Commit b3e5838a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-4.1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata

Pull libata fixes from Tejun Heo:
 "Rather big for fixes pull.

   - SCC controllers never lived to see the light of the day.  Both
     libata and ide drivers removed.

   - In some configurations, link power management policy changes
     sometimes cause delayed spurious PHY events which can develop into
     noticeable failures.  This has been reported several times over the
     years.  Gabriele's patches suppress PHY events for a while after
     LPM policy changes which should help most of these failures without
     causing too much problem for hotplug use cases.

   - A few controller specific fixes"

[ Hmm.  I don't think removing SSC support is really a "fix", but hey, it
  removes a lot of lines of code.  Which I like.  So ...  good riddance ]

* 'for-4.1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata:
  ahci: avoton port-disable reset-quirk
  ata: select DW_DMAC in case of SATA_DWC
  libata: Blacklist queued TRIM on all Samsung 800-series
  libata: Ignore spurious PHY event on LPM policy change
  libata: Add helper to determine when PHY events should be ignored
  ata: ahci_st: fixup layering violations / drvdata errors
  Remove celleb-only SCC PATA drivers
parents c91aa67e dbfe8ef5
...@@ -270,6 +270,7 @@ config ATA_PIIX ...@@ -270,6 +270,7 @@ config ATA_PIIX
config SATA_DWC config SATA_DWC
tristate "DesignWare Cores SATA support" tristate "DesignWare Cores SATA support"
depends on 460EX depends on 460EX
select DW_DMAC
help help
This option enables support for the on-chip SATA controller of the This option enables support for the on-chip SATA controller of the
AppliedMicro processor 460EX. AppliedMicro processor 460EX.
...@@ -729,15 +730,6 @@ config PATA_SC1200 ...@@ -729,15 +730,6 @@ config PATA_SC1200
If unsure, say N. If unsure, say N.
config PATA_SCC
tristate "Toshiba's Cell Reference Set IDE support"
depends on PCI && PPC_CELLEB
help
This option enables support for the built-in IDE controller on
Toshiba Cell Reference Board.
If unsure, say N.
config PATA_SCH config PATA_SCH
tristate "Intel SCH PATA support" tristate "Intel SCH PATA support"
depends on PCI depends on PCI
......
...@@ -75,7 +75,6 @@ obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o ...@@ -75,7 +75,6 @@ obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
obj-$(CONFIG_PATA_RDC) += pata_rdc.o obj-$(CONFIG_PATA_RDC) += pata_rdc.o
obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
obj-$(CONFIG_PATA_SCH) += pata_sch.o obj-$(CONFIG_PATA_SCH) += pata_sch.o
obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
obj-$(CONFIG_PATA_SIL680) += pata_sil680.o obj-$(CONFIG_PATA_SIL680) += pata_sil680.o
......
...@@ -66,6 +66,7 @@ enum board_ids { ...@@ -66,6 +66,7 @@ enum board_ids {
board_ahci_yes_fbs, board_ahci_yes_fbs,
/* board IDs for specific chipsets in alphabetical order */ /* board IDs for specific chipsets in alphabetical order */
board_ahci_avn,
board_ahci_mcp65, board_ahci_mcp65,
board_ahci_mcp77, board_ahci_mcp77,
board_ahci_mcp89, board_ahci_mcp89,
...@@ -84,6 +85,8 @@ enum board_ids { ...@@ -84,6 +85,8 @@ enum board_ids {
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class, static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline); unsigned long deadline);
static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static void ahci_mcp89_apple_enable(struct pci_dev *pdev); static void ahci_mcp89_apple_enable(struct pci_dev *pdev);
static bool is_mcp89_apple(struct pci_dev *pdev); static bool is_mcp89_apple(struct pci_dev *pdev);
static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
...@@ -107,6 +110,11 @@ static struct ata_port_operations ahci_p5wdh_ops = { ...@@ -107,6 +110,11 @@ static struct ata_port_operations ahci_p5wdh_ops = {
.hardreset = ahci_p5wdh_hardreset, .hardreset = ahci_p5wdh_hardreset,
}; };
static struct ata_port_operations ahci_avn_ops = {
.inherits = &ahci_ops,
.hardreset = ahci_avn_hardreset,
};
static const struct ata_port_info ahci_port_info[] = { static const struct ata_port_info ahci_port_info[] = {
/* by features */ /* by features */
[board_ahci] = { [board_ahci] = {
...@@ -151,6 +159,12 @@ static const struct ata_port_info ahci_port_info[] = { ...@@ -151,6 +159,12 @@ static const struct ata_port_info ahci_port_info[] = {
.port_ops = &ahci_ops, .port_ops = &ahci_ops,
}, },
/* by chipsets */ /* by chipsets */
[board_ahci_avn] = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_avn_ops,
},
[board_ahci_mcp65] = { [board_ahci_mcp65] = {
AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP | AHCI_HFLAGS (AHCI_HFLAG_NO_FPDMA_AA | AHCI_HFLAG_NO_PMP |
AHCI_HFLAG_YES_NCQ), AHCI_HFLAG_YES_NCQ),
...@@ -290,14 +304,14 @@ static const struct pci_device_id ahci_pci_tbl[] = { ...@@ -290,14 +304,14 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f27), board_ahci }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f2e), board_ahci }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f2f), board_ahci }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f32), board_ahci }, /* Avoton AHCI */ { PCI_VDEVICE(INTEL, 0x1f32), board_ahci_avn }, /* Avoton AHCI */
{ PCI_VDEVICE(INTEL, 0x1f33), board_ahci }, /* Avoton AHCI */ { PCI_VDEVICE(INTEL, 0x1f33), board_ahci_avn }, /* Avoton AHCI */
{ PCI_VDEVICE(INTEL, 0x1f34), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f34), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f35), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f35), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f36), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f36), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f37), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f3e), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f3f), board_ahci }, /* Avoton RAID */ { PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */ { PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */
{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */ { PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */
{ PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */ { PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
...@@ -670,6 +684,79 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class, ...@@ -670,6 +684,79 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
return rc; return rc;
} }
/*
* ahci_avn_hardreset - attempt more aggressive recovery of Avoton ports.
*
* It has been observed with some SSDs that the timing of events in the
* link synchronization phase can leave the port in a state that can not
* be recovered by a SATA-hard-reset alone. The failing signature is
* SStatus.DET stuck at 1 ("Device presence detected but Phy
* communication not established"). It was found that unloading and
* reloading the driver when this problem occurs allows the drive
* connection to be recovered (DET advanced to 0x3). The critical
* component of reloading the driver is that the port state machines are
* reset by bouncing "port enable" in the AHCI PCS configuration
* register. So, reproduce that effect by bouncing a port whenever we
* see DET==1 after a reset.
*/
static int ahci_avn_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline)
{
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
struct ata_port *ap = link->ap;
struct ahci_port_priv *pp = ap->private_data;
struct ahci_host_priv *hpriv = ap->host->private_data;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
unsigned long tmo = deadline - jiffies;
struct ata_taskfile tf;
bool online;
int rc, i;
DPRINTK("ENTER\n");
ahci_stop_engine(ap);
for (i = 0; i < 2; i++) {
u16 val;
u32 sstatus;
int port = ap->port_no;
struct ata_host *host = ap->host;
struct pci_dev *pdev = to_pci_dev(host->dev);
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(link->device, &tf);
tf.command = ATA_BUSY;
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
rc = sata_link_hardreset(link, timing, deadline, &online,
ahci_check_ready);
if (sata_scr_read(link, SCR_STATUS, &sstatus) != 0 ||
(sstatus & 0xf) != 1)
break;
ata_link_printk(link, KERN_INFO, "avn bounce port%d\n",
port);
pci_read_config_word(pdev, 0x92, &val);
val &= ~(1 << port);
pci_write_config_word(pdev, 0x92, val);
ata_msleep(ap, 1000);
val |= 1 << port;
pci_write_config_word(pdev, 0x92, val);
deadline += tmo;
}
hpriv->start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
return rc;
}
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg) static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
{ {
......
...@@ -37,7 +37,6 @@ struct st_ahci_drv_data { ...@@ -37,7 +37,6 @@ struct st_ahci_drv_data {
struct reset_control *pwr; struct reset_control *pwr;
struct reset_control *sw_rst; struct reset_control *sw_rst;
struct reset_control *pwr_rst; struct reset_control *pwr_rst;
struct ahci_host_priv *hpriv;
}; };
static void st_ahci_configure_oob(void __iomem *mmio) static void st_ahci_configure_oob(void __iomem *mmio)
...@@ -55,9 +54,10 @@ static void st_ahci_configure_oob(void __iomem *mmio) ...@@ -55,9 +54,10 @@ static void st_ahci_configure_oob(void __iomem *mmio)
writel(new_val, mmio + ST_AHCI_OOBR); writel(new_val, mmio + ST_AHCI_OOBR);
} }
static int st_ahci_deassert_resets(struct device *dev) static int st_ahci_deassert_resets(struct ahci_host_priv *hpriv,
struct device *dev)
{ {
struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); struct st_ahci_drv_data *drv_data = hpriv->plat_data;
int err; int err;
if (drv_data->pwr) { if (drv_data->pwr) {
...@@ -90,8 +90,8 @@ static int st_ahci_deassert_resets(struct device *dev) ...@@ -90,8 +90,8 @@ static int st_ahci_deassert_resets(struct device *dev)
static void st_ahci_host_stop(struct ata_host *host) static void st_ahci_host_stop(struct ata_host *host)
{ {
struct ahci_host_priv *hpriv = host->private_data; struct ahci_host_priv *hpriv = host->private_data;
struct st_ahci_drv_data *drv_data = hpriv->plat_data;
struct device *dev = host->dev; struct device *dev = host->dev;
struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev);
int err; int err;
if (drv_data->pwr) { if (drv_data->pwr) {
...@@ -103,29 +103,30 @@ static void st_ahci_host_stop(struct ata_host *host) ...@@ -103,29 +103,30 @@ static void st_ahci_host_stop(struct ata_host *host)
ahci_platform_disable_resources(hpriv); ahci_platform_disable_resources(hpriv);
} }
static int st_ahci_probe_resets(struct platform_device *pdev) static int st_ahci_probe_resets(struct ahci_host_priv *hpriv,
struct device *dev)
{ {
struct st_ahci_drv_data *drv_data = platform_get_drvdata(pdev); struct st_ahci_drv_data *drv_data = hpriv->plat_data;
drv_data->pwr = devm_reset_control_get(&pdev->dev, "pwr-dwn"); drv_data->pwr = devm_reset_control_get(dev, "pwr-dwn");
if (IS_ERR(drv_data->pwr)) { if (IS_ERR(drv_data->pwr)) {
dev_info(&pdev->dev, "power reset control not defined\n"); dev_info(dev, "power reset control not defined\n");
drv_data->pwr = NULL; drv_data->pwr = NULL;
} }
drv_data->sw_rst = devm_reset_control_get(&pdev->dev, "sw-rst"); drv_data->sw_rst = devm_reset_control_get(dev, "sw-rst");
if (IS_ERR(drv_data->sw_rst)) { if (IS_ERR(drv_data->sw_rst)) {
dev_info(&pdev->dev, "soft reset control not defined\n"); dev_info(dev, "soft reset control not defined\n");
drv_data->sw_rst = NULL; drv_data->sw_rst = NULL;
} }
drv_data->pwr_rst = devm_reset_control_get(&pdev->dev, "pwr-rst"); drv_data->pwr_rst = devm_reset_control_get(dev, "pwr-rst");
if (IS_ERR(drv_data->pwr_rst)) { if (IS_ERR(drv_data->pwr_rst)) {
dev_dbg(&pdev->dev, "power soft reset control not defined\n"); dev_dbg(dev, "power soft reset control not defined\n");
drv_data->pwr_rst = NULL; drv_data->pwr_rst = NULL;
} }
return st_ahci_deassert_resets(&pdev->dev); return st_ahci_deassert_resets(hpriv, dev);
} }
static struct ata_port_operations st_ahci_port_ops = { static struct ata_port_operations st_ahci_port_ops = {
...@@ -154,15 +155,12 @@ static int st_ahci_probe(struct platform_device *pdev) ...@@ -154,15 +155,12 @@ static int st_ahci_probe(struct platform_device *pdev)
if (!drv_data) if (!drv_data)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, drv_data);
hpriv = ahci_platform_get_resources(pdev); hpriv = ahci_platform_get_resources(pdev);
if (IS_ERR(hpriv)) if (IS_ERR(hpriv))
return PTR_ERR(hpriv); return PTR_ERR(hpriv);
hpriv->plat_data = drv_data;
drv_data->hpriv = hpriv; err = st_ahci_probe_resets(hpriv, &pdev->dev);
err = st_ahci_probe_resets(pdev);
if (err) if (err)
return err; return err;
...@@ -170,7 +168,7 @@ static int st_ahci_probe(struct platform_device *pdev) ...@@ -170,7 +168,7 @@ static int st_ahci_probe(struct platform_device *pdev)
if (err) if (err)
return err; return err;
st_ahci_configure_oob(drv_data->hpriv->mmio); st_ahci_configure_oob(hpriv->mmio);
err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info, err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
&ahci_platform_sht); &ahci_platform_sht);
...@@ -185,8 +183,9 @@ static int st_ahci_probe(struct platform_device *pdev) ...@@ -185,8 +183,9 @@ static int st_ahci_probe(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int st_ahci_suspend(struct device *dev) static int st_ahci_suspend(struct device *dev)
{ {
struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = drv_data->hpriv; struct ahci_host_priv *hpriv = host->private_data;
struct st_ahci_drv_data *drv_data = hpriv->plat_data;
int err; int err;
err = ahci_platform_suspend_host(dev); err = ahci_platform_suspend_host(dev);
...@@ -208,21 +207,21 @@ static int st_ahci_suspend(struct device *dev) ...@@ -208,21 +207,21 @@ static int st_ahci_suspend(struct device *dev)
static int st_ahci_resume(struct device *dev) static int st_ahci_resume(struct device *dev)
{ {
struct st_ahci_drv_data *drv_data = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = drv_data->hpriv; struct ahci_host_priv *hpriv = host->private_data;
int err; int err;
err = ahci_platform_enable_resources(hpriv); err = ahci_platform_enable_resources(hpriv);
if (err) if (err)
return err; return err;
err = st_ahci_deassert_resets(dev); err = st_ahci_deassert_resets(hpriv, dev);
if (err) { if (err) {
ahci_platform_disable_resources(hpriv); ahci_platform_disable_resources(hpriv);
return err; return err;
} }
st_ahci_configure_oob(drv_data->hpriv->mmio); st_ahci_configure_oob(hpriv->mmio);
return ahci_platform_resume_host(dev); return ahci_platform_resume_host(dev);
} }
......
...@@ -1707,8 +1707,7 @@ static void ahci_handle_port_interrupt(struct ata_port *ap, ...@@ -1707,8 +1707,7 @@ static void ahci_handle_port_interrupt(struct ata_port *ap,
if (unlikely(resetting)) if (unlikely(resetting))
status &= ~PORT_IRQ_BAD_PMP; status &= ~PORT_IRQ_BAD_PMP;
/* if LPM is enabled, PHYRDY doesn't mean anything */ if (sata_lpm_ignore_phy_events(&ap->link)) {
if (ap->link.lpm_policy > ATA_LPM_MAX_POWER) {
status &= ~PORT_IRQ_PHYRDY; status &= ~PORT_IRQ_PHYRDY;
ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG); ahci_scr_write(&ap->link, SCR_ERROR, SERR_PHYRDY_CHG);
} }
......
...@@ -4235,7 +4235,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { ...@@ -4235,7 +4235,7 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = {
ATA_HORKAGE_ZERO_AFTER_TRIM, }, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM | { "Crucial_CT*MX100*", "MU01", ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, }, ATA_HORKAGE_ZERO_AFTER_TRIM, },
{ "Samsung SSD 850 PRO*", NULL, ATA_HORKAGE_NO_NCQ_TRIM | { "Samsung SSD 8*", NULL, ATA_HORKAGE_NO_NCQ_TRIM |
ATA_HORKAGE_ZERO_AFTER_TRIM, }, ATA_HORKAGE_ZERO_AFTER_TRIM, },
/* /*
...@@ -6752,6 +6752,38 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val, ...@@ -6752,6 +6752,38 @@ u32 ata_wait_register(struct ata_port *ap, void __iomem *reg, u32 mask, u32 val,
return tmp; return tmp;
} }
/**
* sata_lpm_ignore_phy_events - test if PHY event should be ignored
* @link: Link receiving the event
*
* Test whether the received PHY event has to be ignored or not.
*
* LOCKING:
* None:
*
* RETURNS:
* True if the event has to be ignored.
*/
bool sata_lpm_ignore_phy_events(struct ata_link *link)
{
unsigned long lpm_timeout = link->last_lpm_change +
msecs_to_jiffies(ATA_TMOUT_SPURIOUS_PHY);
/* if LPM is enabled, PHYRDY doesn't mean anything */
if (link->lpm_policy > ATA_LPM_MAX_POWER)
return true;
/* ignore the first PHY event after the LPM policy changed
* as it is might be spurious
*/
if ((link->flags & ATA_LFLAG_CHANGED) &&
time_before(jiffies, lpm_timeout))
return true;
return false;
}
EXPORT_SYMBOL_GPL(sata_lpm_ignore_phy_events);
/* /*
* Dummy port_ops * Dummy port_ops
*/ */
......
...@@ -3597,6 +3597,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, ...@@ -3597,6 +3597,9 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
} }
} }
link->last_lpm_change = jiffies;
link->flags |= ATA_LFLAG_CHANGED;
return 0; return 0;
fail: fail:
......
/*
* Support for IDE interfaces on Celleb platform
*
* (C) Copyright 2006 TOSHIBA CORPORATION
*
* This code is based on drivers/ata/ata_piix.c:
* Copyright 2003-2005 Red Hat Inc
* Copyright 2003-2005 Jeff Garzik
* Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
* Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2003 Red Hat Inc
*
* and drivers/ata/ahci.c:
* Copyright 2004-2005 Red Hat, Inc.
*
* and drivers/ata/libata-core.c:
* Copyright 2003-2004 Red Hat, Inc. All rights reserved.
* Copyright 2003-2004 Jeff Garzik
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#define DRV_NAME "pata_scc"
#define DRV_VERSION "0.3"
#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
/* PCI BARs */
#define SCC_CTRL_BAR 0
#define SCC_BMID_BAR 1
/* offset of CTRL registers */
#define SCC_CTL_PIOSHT 0x000
#define SCC_CTL_PIOCT 0x004
#define SCC_CTL_MDMACT 0x008
#define SCC_CTL_MCRCST 0x00C
#define SCC_CTL_SDMACT 0x010
#define SCC_CTL_SCRCST 0x014
#define SCC_CTL_UDENVT 0x018
#define SCC_CTL_TDVHSEL 0x020
#define SCC_CTL_MODEREG 0x024
#define SCC_CTL_ECMODE 0xF00
#define SCC_CTL_MAEA0 0xF50
#define SCC_CTL_MAEC0 0xF54
#define SCC_CTL_CCKCTRL 0xFF0
/* offset of BMID registers */
#define SCC_DMA_CMD 0x000
#define SCC_DMA_STATUS 0x004
#define SCC_DMA_TABLE_OFS 0x008
#define SCC_DMA_INTMASK 0x010
#define SCC_DMA_INTST 0x014
#define SCC_DMA_PTERADD 0x018
#define SCC_REG_CMD_ADDR 0x020
#define SCC_REG_DATA 0x000
#define SCC_REG_ERR 0x004
#define SCC_REG_FEATURE 0x004
#define SCC_REG_NSECT 0x008
#define SCC_REG_LBAL 0x00C
#define SCC_REG_LBAM 0x010
#define SCC_REG_LBAH 0x014
#define SCC_REG_DEVICE 0x018
#define SCC_REG_STATUS 0x01C
#define SCC_REG_CMD 0x01C
#define SCC_REG_ALTSTATUS 0x020
/* register value */
#define TDVHSEL_MASTER 0x00000001
#define TDVHSEL_SLAVE 0x00000004
#define MODE_JCUSFEN 0x00000080
#define ECMODE_VALUE 0x01
#define CCKCTRL_ATARESET 0x00040000
#define CCKCTRL_BUFCNT 0x00020000
#define CCKCTRL_CRST 0x00010000
#define CCKCTRL_OCLKEN 0x00000100
#define CCKCTRL_ATACLKOEN 0x00000002
#define CCKCTRL_LCLKEN 0x00000001
#define QCHCD_IOS_SS 0x00000001
#define QCHSD_STPDIAG 0x00020000
#define INTMASK_MSK 0xD1000012
#define INTSTS_SERROR 0x80000000
#define INTSTS_PRERR 0x40000000
#define INTSTS_RERR 0x10000000
#define INTSTS_ICERR 0x01000000
#define INTSTS_BMSINT 0x00000010
#define INTSTS_BMHE 0x00000008
#define INTSTS_IOIRQS 0x00000004
#define INTSTS_INTRQ 0x00000002
#define INTSTS_ACTEINT 0x00000001
/* PIO transfer mode table */
/* JCHST */
static const unsigned long JCHSTtbl[2][7] = {
{0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */
{0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */
};
/* JCHHT */
static const unsigned long JCHHTtbl[2][7] = {
{0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */
{0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */
};
/* JCHCT */
static const unsigned long JCHCTtbl[2][7] = {
{0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */
{0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */
};
/* DMA transfer mode table */
/* JCHDCTM/JCHDCTS */
static const unsigned long JCHDCTxtbl[2][7] = {
{0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */
{0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */
};
/* JCSTWTM/JCSTWTS */
static const unsigned long JCSTWTxtbl[2][7] = {
{0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */
{0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
};
/* JCTSS */
static const unsigned long JCTSStbl[2][7] = {
{0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */
{0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */
};
/* JCENVT */
static const unsigned long JCENVTtbl[2][7] = {
{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */
{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
};
/* JCACTSELS/JCACTSELM */
static const unsigned long JCACTSELtbl[2][7] = {
{0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */
};
static const struct pci_device_id scc_pci_tbl[] = {
{ PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0},
{ } /* terminate list */
};
/**
* scc_set_piomode - Initialize host controller PATA PIO timings
* @ap: Port whose timings we are configuring
* @adev: um
*
* Set PIO mode for device.
*
* LOCKING:
* None (inherited from caller).
*/
static void scc_set_piomode (struct ata_port *ap, struct ata_device *adev)
{
unsigned int pio = adev->pio_mode - XFER_PIO_0;
void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];
void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
void __iomem *piosht_port = ctrl_base + SCC_CTL_PIOSHT;
void __iomem *pioct_port = ctrl_base + SCC_CTL_PIOCT;
unsigned long reg;
int offset;
reg = in_be32(cckctrl_port);
if (reg & CCKCTRL_ATACLKOEN)
offset = 1; /* 133MHz */
else
offset = 0; /* 100MHz */
reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio];
out_be32(piosht_port, reg);
reg = JCHCTtbl[offset][pio];
out_be32(pioct_port, reg);
}
/**
* scc_set_dmamode - Initialize host controller PATA DMA timings
* @ap: Port whose timings we are configuring
* @adev: um
*
* Set UDMA mode for device.
*
* LOCKING:
* None (inherited from caller).
*/
static void scc_set_dmamode (struct ata_port *ap, struct ata_device *adev)
{
unsigned int udma = adev->dma_mode;
unsigned int is_slave = (adev->devno != 0);
u8 speed = udma;
void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];
void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
void __iomem *mdmact_port = ctrl_base + SCC_CTL_MDMACT;
void __iomem *mcrcst_port = ctrl_base + SCC_CTL_MCRCST;
void __iomem *sdmact_port = ctrl_base + SCC_CTL_SDMACT;
void __iomem *scrcst_port = ctrl_base + SCC_CTL_SCRCST;
void __iomem *udenvt_port = ctrl_base + SCC_CTL_UDENVT;
void __iomem *tdvhsel_port = ctrl_base + SCC_CTL_TDVHSEL;
int offset, idx;
if (in_be32(cckctrl_port) & CCKCTRL_ATACLKOEN)
offset = 1; /* 133MHz */
else
offset = 0; /* 100MHz */
if (speed >= XFER_UDMA_0)
idx = speed - XFER_UDMA_0;
else
return;
if (is_slave) {
out_be32(sdmact_port, JCHDCTxtbl[offset][idx]);
out_be32(scrcst_port, JCSTWTxtbl[offset][idx]);
out_be32(tdvhsel_port,
(in_be32(tdvhsel_port) & ~TDVHSEL_SLAVE) | (JCACTSELtbl[offset][idx] << 2));
} else {
out_be32(mdmact_port, JCHDCTxtbl[offset][idx]);
out_be32(mcrcst_port, JCSTWTxtbl[offset][idx]);
out_be32(tdvhsel_port,
(in_be32(tdvhsel_port) & ~TDVHSEL_MASTER) | JCACTSELtbl[offset][idx]);
}
out_be32(udenvt_port,
JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]);
}
unsigned long scc_mode_filter(struct ata_device *adev, unsigned long mask)
{
/* errata A308 workaround: limit ATAPI UDMA mode to UDMA4 */
if (adev->class == ATA_DEV_ATAPI &&
(mask & (0xE0 << ATA_SHIFT_UDMA))) {
printk(KERN_INFO "%s: limit ATAPI UDMA to UDMA4\n", DRV_NAME);
mask &= ~(0xE0 << ATA_SHIFT_UDMA);
}
return mask;
}
/**
* scc_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
* Note: Original code is ata_sff_tf_load().
*/
static void scc_tf_load (struct ata_port *ap, const struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
if (tf->ctl != ap->last_ctl) {
out_be32(ioaddr->ctl_addr, tf->ctl);
ap->last_ctl = tf->ctl;
ata_wait_idle(ap);
}
if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
out_be32(ioaddr->feature_addr, tf->hob_feature);
out_be32(ioaddr->nsect_addr, tf->hob_nsect);
out_be32(ioaddr->lbal_addr, tf->hob_lbal);
out_be32(ioaddr->lbam_addr, tf->hob_lbam);
out_be32(ioaddr->lbah_addr, tf->hob_lbah);
VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
tf->hob_feature,
tf->hob_nsect,
tf->hob_lbal,
tf->hob_lbam,
tf->hob_lbah);
}
if (is_addr) {
out_be32(ioaddr->feature_addr, tf->feature);
out_be32(ioaddr->nsect_addr, tf->nsect);
out_be32(ioaddr->lbal_addr, tf->lbal);
out_be32(ioaddr->lbam_addr, tf->lbam);
out_be32(ioaddr->lbah_addr, tf->lbah);
VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
tf->feature,
tf->nsect,
tf->lbal,
tf->lbam,
tf->lbah);
}
if (tf->flags & ATA_TFLAG_DEVICE) {
out_be32(ioaddr->device_addr, tf->device);
VPRINTK("device 0x%X\n", tf->device);
}
ata_wait_idle(ap);
}
/**
* scc_check_status - Read device status reg & clear interrupt
* @ap: port where the device is
*
* Note: Original code is ata_check_status().
*/
static u8 scc_check_status (struct ata_port *ap)
{
return in_be32(ap->ioaddr.status_addr);
}
/**
* scc_tf_read - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
* Note: Original code is ata_sff_tf_read().
*/
static void scc_tf_read (struct ata_port *ap, struct ata_taskfile *tf)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
tf->command = scc_check_status(ap);
tf->feature = in_be32(ioaddr->error_addr);
tf->nsect = in_be32(ioaddr->nsect_addr);
tf->lbal = in_be32(ioaddr->lbal_addr);
tf->lbam = in_be32(ioaddr->lbam_addr);
tf->lbah = in_be32(ioaddr->lbah_addr);
tf->device = in_be32(ioaddr->device_addr);
if (tf->flags & ATA_TFLAG_LBA48) {
out_be32(ioaddr->ctl_addr, tf->ctl | ATA_HOB);
tf->hob_feature = in_be32(ioaddr->error_addr);
tf->hob_nsect = in_be32(ioaddr->nsect_addr);
tf->hob_lbal = in_be32(ioaddr->lbal_addr);
tf->hob_lbam = in_be32(ioaddr->lbam_addr);
tf->hob_lbah = in_be32(ioaddr->lbah_addr);
out_be32(ioaddr->ctl_addr, tf->ctl);
ap->last_ctl = tf->ctl;
}
}
/**
* scc_exec_command - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* Note: Original code is ata_sff_exec_command().
*/
static void scc_exec_command (struct ata_port *ap,
const struct ata_taskfile *tf)
{
DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
out_be32(ap->ioaddr.command_addr, tf->command);
ata_sff_pause(ap);
}
/**
* scc_check_altstatus - Read device alternate status reg
* @ap: port where the device is
*/
static u8 scc_check_altstatus (struct ata_port *ap)
{
return in_be32(ap->ioaddr.altstatus_addr);
}
/**
* scc_dev_select - Select device 0/1 on ATA bus
* @ap: ATA channel to manipulate
* @device: ATA device (numbered from zero) to select
*
* Note: Original code is ata_sff_dev_select().
*/
static void scc_dev_select (struct ata_port *ap, unsigned int device)
{
u8 tmp;
if (device == 0)
tmp = ATA_DEVICE_OBS;
else
tmp = ATA_DEVICE_OBS | ATA_DEV1;
out_be32(ap->ioaddr.device_addr, tmp);
ata_sff_pause(ap);
}
/**
* scc_set_devctl - Write device control reg
* @ap: port where the device is
* @ctl: value to write
*/
static void scc_set_devctl(struct ata_port *ap, u8 ctl)
{
out_be32(ap->ioaddr.ctl_addr, ctl);
}
/**
* scc_bmdma_setup - Set up PCI IDE BMDMA transaction
* @qc: Info associated with this ATA transaction.
*
* Note: Original code is ata_bmdma_setup().
*/
static void scc_bmdma_setup (struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
u8 dmactl;
void __iomem *mmio = ap->ioaddr.bmdma_addr;
/* load PRD table addr */
out_be32(mmio + SCC_DMA_TABLE_OFS, ap->bmdma_prd_dma);
/* specify data direction, triple-check start bit is clear */
dmactl = in_be32(mmio + SCC_DMA_CMD);
dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
if (!rw)
dmactl |= ATA_DMA_WR;
out_be32(mmio + SCC_DMA_CMD, dmactl);
/* issue r/w command */
ap->ops->sff_exec_command(ap, &qc->tf);
}
/**
* scc_bmdma_start - Start a PCI IDE BMDMA transaction
* @qc: Info associated with this ATA transaction.
*
* Note: Original code is ata_bmdma_start().
*/
static void scc_bmdma_start (struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
u8 dmactl;
void __iomem *mmio = ap->ioaddr.bmdma_addr;
/* start host DMA transaction */
dmactl = in_be32(mmio + SCC_DMA_CMD);
out_be32(mmio + SCC_DMA_CMD, dmactl | ATA_DMA_START);
}
/**
* scc_devchk - PATA device presence detection
* @ap: ATA channel to examine
* @device: Device to examine (starting at zero)
*
* Note: Original code is ata_devchk().
*/
static unsigned int scc_devchk (struct ata_port *ap,
unsigned int device)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
u8 nsect, lbal;
ap->ops->sff_dev_select(ap, device);
out_be32(ioaddr->nsect_addr, 0x55);
out_be32(ioaddr->lbal_addr, 0xaa);
out_be32(ioaddr->nsect_addr, 0xaa);
out_be32(ioaddr->lbal_addr, 0x55);
out_be32(ioaddr->nsect_addr, 0x55);
out_be32(ioaddr->lbal_addr, 0xaa);
nsect = in_be32(ioaddr->nsect_addr);
lbal = in_be32(ioaddr->lbal_addr);
if ((nsect == 0x55) && (lbal == 0xaa))
return 1; /* we found a device */
return 0; /* nothing found */
}
/**
* scc_wait_after_reset - wait for devices to become ready after reset
*
* Note: Original code is ata_sff_wait_after_reset
*/
static int scc_wait_after_reset(struct ata_link *link, unsigned int devmask,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
struct ata_ioports *ioaddr = &ap->ioaddr;
unsigned int dev0 = devmask & (1 << 0);
unsigned int dev1 = devmask & (1 << 1);
int rc, ret = 0;
/* Spec mandates ">= 2ms" before checking status. We wait
* 150ms, because that was the magic delay used for ATAPI
* devices in Hale Landis's ATADRVR, for the period of time
* between when the ATA command register is written, and then
* status is checked. Because waiting for "a while" before
* checking status is fine, post SRST, we perform this magic
* delay here as well.
*
* Old drivers/ide uses the 2mS rule and then waits for ready.
*/
ata_msleep(ap, 150);
/* always check readiness of the master device */
rc = ata_sff_wait_ready(link, deadline);
/* -ENODEV means the odd clown forgot the D7 pulldown resistor
* and TF status is 0xff, bail out on it too.
*/
if (rc)
return rc;
/* if device 1 was found in ata_devchk, wait for register
* access briefly, then wait for BSY to clear.
*/
if (dev1) {
int i;
ap->ops->sff_dev_select(ap, 1);
/* Wait for register access. Some ATAPI devices fail
* to set nsect/lbal after reset, so don't waste too
* much time on it. We're gonna wait for !BSY anyway.
*/
for (i = 0; i < 2; i++) {
u8 nsect, lbal;
nsect = in_be32(ioaddr->nsect_addr);
lbal = in_be32(ioaddr->lbal_addr);
if ((nsect == 1) && (lbal == 1))
break;
ata_msleep(ap, 50); /* give drive a breather */
}
rc = ata_sff_wait_ready(link, deadline);
if (rc) {
if (rc != -ENODEV)
return rc;
ret = rc;
}
}
/* is all this really necessary? */
ap->ops->sff_dev_select(ap, 0);
if (dev1)
ap->ops->sff_dev_select(ap, 1);
if (dev0)
ap->ops->sff_dev_select(ap, 0);
return ret;
}
/**
* scc_bus_softreset - PATA device software reset
*
* Note: Original code is ata_bus_softreset().
*/
static int scc_bus_softreset(struct ata_port *ap, unsigned int devmask,
unsigned long deadline)
{
struct ata_ioports *ioaddr = &ap->ioaddr;
DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
/* software reset. causes dev0 to be selected */
out_be32(ioaddr->ctl_addr, ap->ctl);
udelay(20);
out_be32(ioaddr->ctl_addr, ap->ctl | ATA_SRST);
udelay(20);
out_be32(ioaddr->ctl_addr, ap->ctl);
return scc_wait_after_reset(&ap->link, devmask, deadline);
}
/**
* scc_softreset - reset host port via ATA SRST
* @ap: port to reset
* @classes: resulting classes of attached devices
* @deadline: deadline jiffies for the operation
*
* Note: Original code is ata_sff_softreset().
*/
static int scc_softreset(struct ata_link *link, unsigned int *classes,
unsigned long deadline)
{
struct ata_port *ap = link->ap;
unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
unsigned int devmask = 0;
int rc;
u8 err;
DPRINTK("ENTER\n");
/* determine if device 0/1 are present */
if (scc_devchk(ap, 0))
devmask |= (1 << 0);
if (slave_possible && scc_devchk(ap, 1))
devmask |= (1 << 1);
/* select device 0 again */
ap->ops->sff_dev_select(ap, 0);
/* issue bus reset */
DPRINTK("about to softreset, devmask=%x\n", devmask);
rc = scc_bus_softreset(ap, devmask, deadline);
if (rc) {
ata_port_err(ap, "SRST failed (err_mask=0x%x)\n", rc);
return -EIO;
}
/* determine by signature whether we have ATA or ATAPI devices */
classes[0] = ata_sff_dev_classify(&ap->link.device[0],
devmask & (1 << 0), &err);
if (slave_possible && err != 0x81)
classes[1] = ata_sff_dev_classify(&ap->link.device[1],
devmask & (1 << 1), &err);
DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
return 0;
}
/**
* scc_bmdma_stop - Stop PCI IDE BMDMA transfer
* @qc: Command we are ending DMA for
*/
static void scc_bmdma_stop (struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
void __iomem *ctrl_base = ap->host->iomap[SCC_CTRL_BAR];
void __iomem *bmid_base = ap->host->iomap[SCC_BMID_BAR];
u32 reg;
while (1) {
reg = in_be32(bmid_base + SCC_DMA_INTST);
if (reg & INTSTS_SERROR) {
printk(KERN_WARNING "%s: SERROR\n", DRV_NAME);
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_SERROR|INTSTS_BMSINT);
out_be32(bmid_base + SCC_DMA_CMD,
in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
continue;
}
if (reg & INTSTS_PRERR) {
u32 maea0, maec0;
maea0 = in_be32(ctrl_base + SCC_CTL_MAEA0);
maec0 = in_be32(ctrl_base + SCC_CTL_MAEC0);
printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", DRV_NAME, maea0, maec0);
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_PRERR|INTSTS_BMSINT);
out_be32(bmid_base + SCC_DMA_CMD,
in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
continue;
}
if (reg & INTSTS_RERR) {
printk(KERN_WARNING "%s: Response Error\n", DRV_NAME);
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_RERR|INTSTS_BMSINT);
out_be32(bmid_base + SCC_DMA_CMD,
in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
continue;
}
if (reg & INTSTS_ICERR) {
out_be32(bmid_base + SCC_DMA_CMD,
in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
printk(KERN_WARNING "%s: Illegal Configuration\n", DRV_NAME);
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ICERR|INTSTS_BMSINT);
continue;
}
if (reg & INTSTS_BMSINT) {
unsigned int classes;
unsigned long deadline = ata_deadline(jiffies, ATA_TMOUT_BOOT);
printk(KERN_WARNING "%s: Internal Bus Error\n", DRV_NAME);
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMSINT);
/* TBD: SW reset */
scc_softreset(&ap->link, &classes, deadline);
continue;
}
if (reg & INTSTS_BMHE) {
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_BMHE);
continue;
}
if (reg & INTSTS_ACTEINT) {
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_ACTEINT);
continue;
}
if (reg & INTSTS_IOIRQS) {
out_be32(bmid_base + SCC_DMA_INTST, INTSTS_IOIRQS);
continue;
}
break;
}
/* clear start/stop bit */
out_be32(bmid_base + SCC_DMA_CMD,
in_be32(bmid_base + SCC_DMA_CMD) & ~ATA_DMA_START);
/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
ata_sff_dma_pause(ap); /* dummy read */
}
/**
* scc_bmdma_status - Read PCI IDE BMDMA status
* @ap: Port associated with this ATA transaction.
*/
static u8 scc_bmdma_status (struct ata_port *ap)
{
void __iomem *mmio = ap->ioaddr.bmdma_addr;
u8 host_stat = in_be32(mmio + SCC_DMA_STATUS);
u32 int_status = in_be32(mmio + SCC_DMA_INTST);
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
static int retry = 0;
/* return if IOS_SS is cleared */
if (!(in_be32(mmio + SCC_DMA_CMD) & ATA_DMA_START))
return host_stat;
/* errata A252,A308 workaround: Step4 */
if ((scc_check_altstatus(ap) & ATA_ERR)
&& (int_status & INTSTS_INTRQ))
return (host_stat | ATA_DMA_INTR);
/* errata A308 workaround Step5 */
if (int_status & INTSTS_IOIRQS) {
host_stat |= ATA_DMA_INTR;
/* We don't check ATAPI DMA because it is limited to UDMA4 */
if ((qc->tf.protocol == ATA_PROT_DMA &&
qc->dev->xfer_mode > XFER_UDMA_4)) {
if (!(int_status & INTSTS_ACTEINT)) {
printk(KERN_WARNING "ata%u: operation failed (transfer data loss)\n",
ap->print_id);
host_stat |= ATA_DMA_ERR;
if (retry++)
ap->udma_mask &= ~(1 << qc->dev->xfer_mode);
} else
retry = 0;
}
}
return host_stat;
}
/**
* scc_data_xfer - Transfer data by PIO
* @dev: device for this I/O
* @buf: data buffer
* @buflen: buffer length
* @rw: read/write
*
* Note: Original code is ata_sff_data_xfer().
*/
static unsigned int scc_data_xfer (struct ata_device *dev, unsigned char *buf,
unsigned int buflen, int rw)
{
struct ata_port *ap = dev->link->ap;
unsigned int words = buflen >> 1;
unsigned int i;
__le16 *buf16 = (__le16 *) buf;
void __iomem *mmio = ap->ioaddr.data_addr;
/* Transfer multiple of 2 bytes */
if (rw == READ)
for (i = 0; i < words; i++)
buf16[i] = cpu_to_le16(in_be32(mmio));
else
for (i = 0; i < words; i++)
out_be32(mmio, le16_to_cpu(buf16[i]));
/* Transfer trailing 1 byte, if any. */
if (unlikely(buflen & 0x01)) {
__le16 align_buf[1] = { 0 };
unsigned char *trailing_buf = buf + buflen - 1;
if (rw == READ) {
align_buf[0] = cpu_to_le16(in_be32(mmio));
memcpy(trailing_buf, align_buf, 1);
} else {
memcpy(align_buf, trailing_buf, 1);
out_be32(mmio, le16_to_cpu(align_buf[0]));
}
words++;
}
return words << 1;
}
/**
* scc_postreset - standard postreset callback
* @ap: the target ata_port
* @classes: classes of attached devices
*
* Note: Original code is ata_sff_postreset().
*/
static void scc_postreset(struct ata_link *link, unsigned int *classes)
{
struct ata_port *ap = link->ap;
DPRINTK("ENTER\n");
/* is double-select really necessary? */
if (classes[0] != ATA_DEV_NONE)
ap->ops->sff_dev_select(ap, 1);
if (classes[1] != ATA_DEV_NONE)
ap->ops->sff_dev_select(ap, 0);
/* bail out if no device is present */
if (classes[0] == ATA_DEV_NONE && classes[1] == ATA_DEV_NONE) {
DPRINTK("EXIT, no device\n");
return;
}
/* set up device control */
out_be32(ap->ioaddr.ctl_addr, ap->ctl);
DPRINTK("EXIT\n");
}
/**
* scc_irq_clear - Clear PCI IDE BMDMA interrupt.
* @ap: Port associated with this ATA transaction.
*
* Note: Original code is ata_bmdma_irq_clear().
*/
static void scc_irq_clear (struct ata_port *ap)
{
void __iomem *mmio = ap->ioaddr.bmdma_addr;
if (!mmio)
return;
out_be32(mmio + SCC_DMA_STATUS, in_be32(mmio + SCC_DMA_STATUS));
}
/**
* scc_port_start - Set port up for dma.
* @ap: Port to initialize
*
* Allocate space for PRD table using ata_bmdma_port_start().
* Set PRD table address for PTERADD. (PRD Transfer End Read)
*/
static int scc_port_start (struct ata_port *ap)
{
void __iomem *mmio = ap->ioaddr.bmdma_addr;
int rc;
rc = ata_bmdma_port_start(ap);
if (rc)
return rc;
out_be32(mmio + SCC_DMA_PTERADD, ap->bmdma_prd_dma);
return 0;
}
/**
* scc_port_stop - Undo scc_port_start()
* @ap: Port to shut down
*
* Reset PTERADD.
*/
static void scc_port_stop (struct ata_port *ap)
{
void __iomem *mmio = ap->ioaddr.bmdma_addr;
out_be32(mmio + SCC_DMA_PTERADD, 0);
}
static struct scsi_host_template scc_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
static struct ata_port_operations scc_pata_ops = {
.inherits = &ata_bmdma_port_ops,
.set_piomode = scc_set_piomode,
.set_dmamode = scc_set_dmamode,
.mode_filter = scc_mode_filter,
.sff_tf_load = scc_tf_load,
.sff_tf_read = scc_tf_read,
.sff_exec_command = scc_exec_command,
.sff_check_status = scc_check_status,
.sff_check_altstatus = scc_check_altstatus,
.sff_dev_select = scc_dev_select,
.sff_set_devctl = scc_set_devctl,
.bmdma_setup = scc_bmdma_setup,
.bmdma_start = scc_bmdma_start,
.bmdma_stop = scc_bmdma_stop,
.bmdma_status = scc_bmdma_status,
.sff_data_xfer = scc_data_xfer,
.cable_detect = ata_cable_80wire,
.softreset = scc_softreset,
.postreset = scc_postreset,
.sff_irq_clear = scc_irq_clear,
.port_start = scc_port_start,
.port_stop = scc_port_stop,
};
static struct ata_port_info scc_port_info[] = {
{
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
/* No MWDMA */
.udma_mask = ATA_UDMA6,
.port_ops = &scc_pata_ops,
},
};
/**
* scc_reset_controller - initialize SCC PATA controller.
*/
static int scc_reset_controller(struct ata_host *host)
{
void __iomem *ctrl_base = host->iomap[SCC_CTRL_BAR];
void __iomem *bmid_base = host->iomap[SCC_BMID_BAR];
void __iomem *cckctrl_port = ctrl_base + SCC_CTL_CCKCTRL;
void __iomem *mode_port = ctrl_base + SCC_CTL_MODEREG;
void __iomem *ecmode_port = ctrl_base + SCC_CTL_ECMODE;
void __iomem *intmask_port = bmid_base + SCC_DMA_INTMASK;
void __iomem *dmastatus_port = bmid_base + SCC_DMA_STATUS;
u32 reg = 0;
out_be32(cckctrl_port, reg);
reg |= CCKCTRL_ATACLKOEN;
out_be32(cckctrl_port, reg);
reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN;
out_be32(cckctrl_port, reg);
reg |= CCKCTRL_CRST;
out_be32(cckctrl_port, reg);
for (;;) {
reg = in_be32(cckctrl_port);
if (reg & CCKCTRL_CRST)
break;
udelay(5000);
}
reg |= CCKCTRL_ATARESET;
out_be32(cckctrl_port, reg);
out_be32(ecmode_port, ECMODE_VALUE);
out_be32(mode_port, MODE_JCUSFEN);
out_be32(intmask_port, INTMASK_MSK);
if (in_be32(dmastatus_port) & QCHSD_STPDIAG) {
printk(KERN_WARNING "%s: failed to detect 80c cable. (PDIAG# is high)\n", DRV_NAME);
return -EIO;
}
return 0;
}
/**
* scc_setup_ports - initialize ioaddr with SCC PATA port offsets.
* @ioaddr: IO address structure to be initialized
* @base: base address of BMID region
*/
static void scc_setup_ports (struct ata_ioports *ioaddr, void __iomem *base)
{
ioaddr->cmd_addr = base + SCC_REG_CMD_ADDR;
ioaddr->altstatus_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS;
ioaddr->ctl_addr = ioaddr->cmd_addr + SCC_REG_ALTSTATUS;
ioaddr->bmdma_addr = base;
ioaddr->data_addr = ioaddr->cmd_addr + SCC_REG_DATA;
ioaddr->error_addr = ioaddr->cmd_addr + SCC_REG_ERR;
ioaddr->feature_addr = ioaddr->cmd_addr + SCC_REG_FEATURE;
ioaddr->nsect_addr = ioaddr->cmd_addr + SCC_REG_NSECT;
ioaddr->lbal_addr = ioaddr->cmd_addr + SCC_REG_LBAL;
ioaddr->lbam_addr = ioaddr->cmd_addr + SCC_REG_LBAM;
ioaddr->lbah_addr = ioaddr->cmd_addr + SCC_REG_LBAH;
ioaddr->device_addr = ioaddr->cmd_addr + SCC_REG_DEVICE;
ioaddr->status_addr = ioaddr->cmd_addr + SCC_REG_STATUS;
ioaddr->command_addr = ioaddr->cmd_addr + SCC_REG_CMD;
}
static int scc_host_init(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
int rc;
rc = scc_reset_controller(host);
if (rc)
return rc;
rc = dma_set_mask(&pdev->dev, ATA_DMA_MASK);
if (rc)
return rc;
rc = dma_set_coherent_mask(&pdev->dev, ATA_DMA_MASK);
if (rc)
return rc;
scc_setup_ports(&host->ports[0]->ioaddr, host->iomap[SCC_BMID_BAR]);
pci_set_master(pdev);
return 0;
}
/**
* scc_init_one - Register SCC PATA device with kernel services
* @pdev: PCI device to register
* @ent: Entry in scc_pci_tbl matching with @pdev
*
* LOCKING:
* Inherited from PCI layer (may sleep).
*
* RETURNS:
* Zero on success, or -ERRNO value.
*/
static int scc_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
{
unsigned int board_idx = (unsigned int) ent->driver_data;
const struct ata_port_info *ppi[] = { &scc_port_info[board_idx], NULL };
struct ata_host *host;
int rc;
ata_print_version_once(&pdev->dev, DRV_VERSION);
host = ata_host_alloc_pinfo(&pdev->dev, ppi, 1);
if (!host)
return -ENOMEM;
rc = pcim_enable_device(pdev);
if (rc)
return rc;
rc = pcim_iomap_regions(pdev, (1 << SCC_CTRL_BAR) | (1 << SCC_BMID_BAR), DRV_NAME);
if (rc == -EBUSY)
pcim_pin_device(pdev);
if (rc)
return rc;
host->iomap = pcim_iomap_table(pdev);
ata_port_pbar_desc(host->ports[0], SCC_CTRL_BAR, -1, "ctrl");
ata_port_pbar_desc(host->ports[0], SCC_BMID_BAR, -1, "bmid");
rc = scc_host_init(host);
if (rc)
return rc;
return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
IRQF_SHARED, &scc_sht);
}
static struct pci_driver scc_pci_driver = {
.name = DRV_NAME,
.id_table = scc_pci_tbl,
.probe = scc_init_one,
.remove = ata_pci_remove_one,
#ifdef CONFIG_PM_SLEEP
.suspend = ata_pci_device_suspend,
.resume = ata_pci_device_resume,
#endif
};
module_pci_driver(scc_pci_driver);
MODULE_AUTHOR("Toshiba corp");
MODULE_DESCRIPTION("SCSI low-level driver for Toshiba SCC PATA controller");
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
MODULE_VERSION(DRV_VERSION);
...@@ -643,15 +643,6 @@ config BLK_DEV_TC86C001 ...@@ -643,15 +643,6 @@ config BLK_DEV_TC86C001
help help
This driver adds support for Toshiba TC86C001 GOKU-S chip. This driver adds support for Toshiba TC86C001 GOKU-S chip.
config BLK_DEV_CELLEB
tristate "Toshiba's Cell Reference Set IDE support"
depends on PPC_CELLEB
select BLK_DEV_IDEDMA_PCI
help
This driver provides support for the on-board IDE controller on
Toshiba Cell Reference Board.
If unsure, say Y.
endif endif
# TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF # TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF
......
...@@ -38,7 +38,6 @@ obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o ...@@ -38,7 +38,6 @@ obj-$(CONFIG_BLK_DEV_AEC62XX) += aec62xx.o
obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o obj-$(CONFIG_BLK_DEV_ALI15X3) += alim15x3.o
obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o
obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o obj-$(CONFIG_BLK_DEV_ATIIXP) += atiixp.o
obj-$(CONFIG_BLK_DEV_CELLEB) += scc_pata.o
obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o
obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o
obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o
......
/*
* Support for IDE interfaces on Celleb platform
*
* (C) Copyright 2006 TOSHIBA CORPORATION
*
* This code is based on drivers/ide/pci/siimage.c:
* Copyright (C) 2001-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2003 Red Hat
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/types.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
#define SCC_PATA_NAME "scc IDE"
#define TDVHSEL_MASTER 0x00000001
#define TDVHSEL_SLAVE 0x00000004
#define MODE_JCUSFEN 0x00000080
#define CCKCTRL_ATARESET 0x00040000
#define CCKCTRL_BUFCNT 0x00020000
#define CCKCTRL_CRST 0x00010000
#define CCKCTRL_OCLKEN 0x00000100
#define CCKCTRL_ATACLKOEN 0x00000002
#define CCKCTRL_LCLKEN 0x00000001
#define QCHCD_IOS_SS 0x00000001
#define QCHSD_STPDIAG 0x00020000
#define INTMASK_MSK 0xD1000012
#define INTSTS_SERROR 0x80000000
#define INTSTS_PRERR 0x40000000
#define INTSTS_RERR 0x10000000
#define INTSTS_ICERR 0x01000000
#define INTSTS_BMSINT 0x00000010
#define INTSTS_BMHE 0x00000008
#define INTSTS_IOIRQS 0x00000004
#define INTSTS_INTRQ 0x00000002
#define INTSTS_ACTEINT 0x00000001
#define ECMODE_VALUE 0x01
static struct scc_ports {
unsigned long ctl, dma;
struct ide_host *host; /* for removing port from system */
} scc_ports[MAX_HWIFS];
/* PIO transfer mode table */
/* JCHST */
static unsigned long JCHSTtbl[2][7] = {
{0x0E, 0x05, 0x02, 0x03, 0x02, 0x00, 0x00}, /* 100MHz */
{0x13, 0x07, 0x04, 0x04, 0x03, 0x00, 0x00} /* 133MHz */
};
/* JCHHT */
static unsigned long JCHHTtbl[2][7] = {
{0x0E, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00}, /* 100MHz */
{0x13, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00} /* 133MHz */
};
/* JCHCT */
static unsigned long JCHCTtbl[2][7] = {
{0x1D, 0x1D, 0x1C, 0x0B, 0x06, 0x00, 0x00}, /* 100MHz */
{0x27, 0x26, 0x26, 0x0E, 0x09, 0x00, 0x00} /* 133MHz */
};
/* DMA transfer mode table */
/* JCHDCTM/JCHDCTS */
static unsigned long JCHDCTxtbl[2][7] = {
{0x0A, 0x06, 0x04, 0x03, 0x01, 0x00, 0x00}, /* 100MHz */
{0x0E, 0x09, 0x06, 0x04, 0x02, 0x01, 0x00} /* 133MHz */
};
/* JCSTWTM/JCSTWTS */
static unsigned long JCSTWTxtbl[2][7] = {
{0x06, 0x04, 0x03, 0x02, 0x02, 0x02, 0x00}, /* 100MHz */
{0x09, 0x06, 0x04, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
};
/* JCTSS */
static unsigned long JCTSStbl[2][7] = {
{0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x00}, /* 100MHz */
{0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05} /* 133MHz */
};
/* JCENVT */
static unsigned long JCENVTtbl[2][7] = {
{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00}, /* 100MHz */
{0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02} /* 133MHz */
};
/* JCACTSELS/JCACTSELM */
static unsigned long JCACTSELtbl[2][7] = {
{0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00}, /* 100MHz */
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} /* 133MHz */
};
static u8 scc_ide_inb(unsigned long port)
{
u32 data = in_be32((void*)port);
return (u8)data;
}
static void scc_exec_command(ide_hwif_t *hwif, u8 cmd)
{
out_be32((void *)hwif->io_ports.command_addr, cmd);
eieio();
in_be32((void *)(hwif->dma_base + 0x01c));
eieio();
}
static u8 scc_read_status(ide_hwif_t *hwif)
{
return (u8)in_be32((void *)hwif->io_ports.status_addr);
}
static u8 scc_read_altstatus(ide_hwif_t *hwif)
{
return (u8)in_be32((void *)hwif->io_ports.ctl_addr);
}
static u8 scc_dma_sff_read_status(ide_hwif_t *hwif)
{
return (u8)in_be32((void *)(hwif->dma_base + 4));
}
static void scc_write_devctl(ide_hwif_t *hwif, u8 ctl)
{
out_be32((void *)hwif->io_ports.ctl_addr, ctl);
eieio();
in_be32((void *)(hwif->dma_base + 0x01c));
eieio();
}
static void scc_ide_insw(unsigned long port, void *addr, u32 count)
{
u16 *ptr = (u16 *)addr;
while (count--) {
*ptr++ = le16_to_cpu(in_be32((void*)port));
}
}
static void scc_ide_insl(unsigned long port, void *addr, u32 count)
{
u16 *ptr = (u16 *)addr;
while (count--) {
*ptr++ = le16_to_cpu(in_be32((void*)port));
*ptr++ = le16_to_cpu(in_be32((void*)port));
}
}
static void scc_ide_outb(u8 addr, unsigned long port)
{
out_be32((void*)port, addr);
}
static void
scc_ide_outsw(unsigned long port, void *addr, u32 count)
{
u16 *ptr = (u16 *)addr;
while (count--) {
out_be32((void*)port, cpu_to_le16(*ptr++));
}
}
static void
scc_ide_outsl(unsigned long port, void *addr, u32 count)
{
u16 *ptr = (u16 *)addr;
while (count--) {
out_be32((void*)port, cpu_to_le16(*ptr++));
out_be32((void*)port, cpu_to_le16(*ptr++));
}
}
/**
* scc_set_pio_mode - set host controller for PIO mode
* @hwif: port
* @drive: drive
*
* Load the timing settings for this device mode into the
* controller.
*/
static void scc_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
struct scc_ports *ports = ide_get_hwifdata(hwif);
unsigned long ctl_base = ports->ctl;
unsigned long cckctrl_port = ctl_base + 0xff0;
unsigned long piosht_port = ctl_base + 0x000;
unsigned long pioct_port = ctl_base + 0x004;
unsigned long reg;
int offset;
const u8 pio = drive->pio_mode - XFER_PIO_0;
reg = in_be32((void __iomem *)cckctrl_port);
if (reg & CCKCTRL_ATACLKOEN) {
offset = 1; /* 133MHz */
} else {
offset = 0; /* 100MHz */
}
reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio];
out_be32((void __iomem *)piosht_port, reg);
reg = JCHCTtbl[offset][pio];
out_be32((void __iomem *)pioct_port, reg);
}
/**
* scc_set_dma_mode - set host controller for DMA mode
* @hwif: port
* @drive: drive
*
* Load the timing settings for this device mode into the
* controller.
*/
static void scc_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
{
struct scc_ports *ports = ide_get_hwifdata(hwif);
unsigned long ctl_base = ports->ctl;
unsigned long cckctrl_port = ctl_base + 0xff0;
unsigned long mdmact_port = ctl_base + 0x008;
unsigned long mcrcst_port = ctl_base + 0x00c;
unsigned long sdmact_port = ctl_base + 0x010;
unsigned long scrcst_port = ctl_base + 0x014;
unsigned long udenvt_port = ctl_base + 0x018;
unsigned long tdvhsel_port = ctl_base + 0x020;
int is_slave = drive->dn & 1;
int offset, idx;
unsigned long reg;
unsigned long jcactsel;
const u8 speed = drive->dma_mode;
reg = in_be32((void __iomem *)cckctrl_port);
if (reg & CCKCTRL_ATACLKOEN) {
offset = 1; /* 133MHz */
} else {
offset = 0; /* 100MHz */
}
idx = speed - XFER_UDMA_0;
jcactsel = JCACTSELtbl[offset][idx];
if (is_slave) {
out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]);
out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]);
jcactsel = jcactsel << 2;
out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel);
} else {
out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]);
out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]);
out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel);
}
reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx];
out_be32((void __iomem *)udenvt_port, reg);
}
static void scc_dma_host_set(ide_drive_t *drive, int on)
{
ide_hwif_t *hwif = drive->hwif;
u8 unit = drive->dn & 1;
u8 dma_stat = scc_dma_sff_read_status(hwif);
if (on)
dma_stat |= (1 << (5 + unit));
else
dma_stat &= ~(1 << (5 + unit));
scc_ide_outb(dma_stat, hwif->dma_base + 4);
}
/**
* scc_dma_setup - begin a DMA phase
* @drive: target device
* @cmd: command
*
* Build an IDE DMA PRD (IDE speak for scatter gather table)
* and then set up the DMA transfer registers.
*
* Returns 0 on success. If a PIO fallback is required then 1
* is returned.
*/
static int scc_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
{
ide_hwif_t *hwif = drive->hwif;
u32 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
u8 dma_stat;
/* fall back to pio! */
if (ide_build_dmatable(drive, cmd) == 0)
return 1;
/* PRD table */
out_be32((void __iomem *)(hwif->dma_base + 8), hwif->dmatable_dma);
/* specify r/w */
out_be32((void __iomem *)hwif->dma_base, rw);
/* read DMA status for INTR & ERROR flags */
dma_stat = scc_dma_sff_read_status(hwif);
/* clear INTR & ERROR flags */
out_be32((void __iomem *)(hwif->dma_base + 4), dma_stat | 6);
return 0;
}
static void scc_dma_start(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
u8 dma_cmd = scc_ide_inb(hwif->dma_base);
/* start DMA */
scc_ide_outb(dma_cmd | 1, hwif->dma_base);
}
static int __scc_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
u8 dma_stat, dma_cmd;
/* get DMA command mode */
dma_cmd = scc_ide_inb(hwif->dma_base);
/* stop DMA */
scc_ide_outb(dma_cmd & ~1, hwif->dma_base);
/* get DMA status */
dma_stat = scc_dma_sff_read_status(hwif);
/* clear the INTR & ERROR bits */
scc_ide_outb(dma_stat | 6, hwif->dma_base + 4);
/* verify good DMA status */
return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;
}
/**
* scc_dma_end - Stop DMA
* @drive: IDE drive
*
* Check and clear INT Status register.
* Then call __scc_dma_end().
*/
static int scc_dma_end(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
void __iomem *dma_base = (void __iomem *)hwif->dma_base;
unsigned long intsts_port = hwif->dma_base + 0x014;
u32 reg;
int dma_stat, data_loss = 0;
static int retry = 0;
/* errata A308 workaround: Step5 (check data loss) */
/* We don't check non ide_disk because it is limited to UDMA4 */
if (!(in_be32((void __iomem *)hwif->io_ports.ctl_addr)
& ATA_ERR) &&
drive->media == ide_disk && drive->current_speed > XFER_UDMA_4) {
reg = in_be32((void __iomem *)intsts_port);
if (!(reg & INTSTS_ACTEINT)) {
printk(KERN_WARNING "%s: operation failed (transfer data loss)\n",
drive->name);
data_loss = 1;
if (retry++) {
struct request *rq = hwif->rq;
ide_drive_t *drive;
int i;
/* ERROR_RESET and drive->crc_count are needed
* to reduce DMA transfer mode in retry process.
*/
if (rq)
rq->errors |= ERROR_RESET;
ide_port_for_each_dev(i, drive, hwif)
drive->crc_count++;
}
}
}
while (1) {
reg = in_be32((void __iomem *)intsts_port);
if (reg & INTSTS_SERROR) {
printk(KERN_WARNING "%s: SERROR\n", SCC_PATA_NAME);
out_be32((void __iomem *)intsts_port, INTSTS_SERROR|INTSTS_BMSINT);
out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
continue;
}
if (reg & INTSTS_PRERR) {
u32 maea0, maec0;
unsigned long ctl_base = hwif->config_data;
maea0 = in_be32((void __iomem *)(ctl_base + 0xF50));
maec0 = in_be32((void __iomem *)(ctl_base + 0xF54));
printk(KERN_WARNING "%s: PRERR [addr:%x cmd:%x]\n", SCC_PATA_NAME, maea0, maec0);
out_be32((void __iomem *)intsts_port, INTSTS_PRERR|INTSTS_BMSINT);
out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
continue;
}
if (reg & INTSTS_RERR) {
printk(KERN_WARNING "%s: Response Error\n", SCC_PATA_NAME);
out_be32((void __iomem *)intsts_port, INTSTS_RERR|INTSTS_BMSINT);
out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
continue;
}
if (reg & INTSTS_ICERR) {
out_be32(dma_base, in_be32(dma_base) & ~QCHCD_IOS_SS);
printk(KERN_WARNING "%s: Illegal Configuration\n", SCC_PATA_NAME);
out_be32((void __iomem *)intsts_port, INTSTS_ICERR|INTSTS_BMSINT);
continue;
}
if (reg & INTSTS_BMSINT) {
printk(KERN_WARNING "%s: Internal Bus Error\n", SCC_PATA_NAME);
out_be32((void __iomem *)intsts_port, INTSTS_BMSINT);
ide_do_reset(drive);
continue;
}
if (reg & INTSTS_BMHE) {
out_be32((void __iomem *)intsts_port, INTSTS_BMHE);
continue;
}
if (reg & INTSTS_ACTEINT) {
out_be32((void __iomem *)intsts_port, INTSTS_ACTEINT);
continue;
}
if (reg & INTSTS_IOIRQS) {
out_be32((void __iomem *)intsts_port, INTSTS_IOIRQS);
continue;
}
break;
}
dma_stat = __scc_dma_end(drive);
if (data_loss)
dma_stat |= 2; /* emulate DMA error (to retry command) */
return dma_stat;
}
/* returns 1 if dma irq issued, 0 otherwise */
static int scc_dma_test_irq(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
u32 int_stat = in_be32((void __iomem *)hwif->dma_base + 0x014);
/* SCC errata A252,A308 workaround: Step4 */
if ((in_be32((void __iomem *)hwif->io_ports.ctl_addr)
& ATA_ERR) &&
(int_stat & INTSTS_INTRQ))
return 1;
/* SCC errata A308 workaround: Step5 (polling IOIRQS) */
if (int_stat & INTSTS_IOIRQS)
return 1;
return 0;
}
static u8 scc_udma_filter(ide_drive_t *drive)
{
ide_hwif_t *hwif = drive->hwif;
u8 mask = hwif->ultra_mask;
/* errata A308 workaround: limit non ide_disk drive to UDMA4 */
if ((drive->media != ide_disk) && (mask & 0xE0)) {
printk(KERN_INFO "%s: limit %s to UDMA4\n",
SCC_PATA_NAME, drive->name);
mask = ATA_UDMA4;
}
return mask;
}
/**
* setup_mmio_scc - map CTRL/BMID region
* @dev: PCI device we are configuring
* @name: device name
*
*/
static int setup_mmio_scc (struct pci_dev *dev, const char *name)
{
void __iomem *ctl_addr;
void __iomem *dma_addr;
int i, ret;
for (i = 0; i < MAX_HWIFS; i++) {
if (scc_ports[i].ctl == 0)
break;
}
if (i >= MAX_HWIFS)
return -ENOMEM;
ret = pci_request_selected_regions(dev, (1 << 2) - 1, name);
if (ret < 0) {
printk(KERN_ERR "%s: can't reserve resources\n", name);
return ret;
}
ctl_addr = pci_ioremap_bar(dev, 0);
if (!ctl_addr)
goto fail_0;
dma_addr = pci_ioremap_bar(dev, 1);
if (!dma_addr)
goto fail_1;
pci_set_master(dev);
scc_ports[i].ctl = (unsigned long)ctl_addr;
scc_ports[i].dma = (unsigned long)dma_addr;
pci_set_drvdata(dev, (void *) &scc_ports[i]);
return 1;
fail_1:
iounmap(ctl_addr);
fail_0:
return -ENOMEM;
}
static int scc_ide_setup_pci_device(struct pci_dev *dev,
const struct ide_port_info *d)
{
struct scc_ports *ports = pci_get_drvdata(dev);
struct ide_host *host;
struct ide_hw hw, *hws[] = { &hw };
int i, rc;
memset(&hw, 0, sizeof(hw));
for (i = 0; i <= 8; i++)
hw.io_ports_array[i] = ports->dma + 0x20 + i * 4;
hw.irq = dev->irq;
hw.dev = &dev->dev;
rc = ide_host_add(d, hws, 1, &host);
if (rc)
return rc;
ports->host = host;
return 0;
}
/**
* init_setup_scc - set up an SCC PATA Controller
* @dev: PCI device
* @d: IDE port info
*
* Perform the initial set up for this device.
*/
static int init_setup_scc(struct pci_dev *dev, const struct ide_port_info *d)
{
unsigned long ctl_base;
unsigned long dma_base;
unsigned long cckctrl_port;
unsigned long intmask_port;
unsigned long mode_port;
unsigned long ecmode_port;
u32 reg = 0;
struct scc_ports *ports;
int rc;
rc = pci_enable_device(dev);
if (rc)
goto end;
rc = setup_mmio_scc(dev, d->name);
if (rc < 0)
goto end;
ports = pci_get_drvdata(dev);
ctl_base = ports->ctl;
dma_base = ports->dma;
cckctrl_port = ctl_base + 0xff0;
intmask_port = dma_base + 0x010;
mode_port = ctl_base + 0x024;
ecmode_port = ctl_base + 0xf00;
/* controller initialization */
reg = 0;
out_be32((void*)cckctrl_port, reg);
reg |= CCKCTRL_ATACLKOEN;
out_be32((void*)cckctrl_port, reg);
reg |= CCKCTRL_LCLKEN | CCKCTRL_OCLKEN;
out_be32((void*)cckctrl_port, reg);
reg |= CCKCTRL_CRST;
out_be32((void*)cckctrl_port, reg);
for (;;) {
reg = in_be32((void*)cckctrl_port);
if (reg & CCKCTRL_CRST)
break;
udelay(5000);
}
reg |= CCKCTRL_ATARESET;
out_be32((void*)cckctrl_port, reg);
out_be32((void*)ecmode_port, ECMODE_VALUE);
out_be32((void*)mode_port, MODE_JCUSFEN);
out_be32((void*)intmask_port, INTMASK_MSK);
rc = scc_ide_setup_pci_device(dev, d);
end:
return rc;
}
static void scc_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
{
struct ide_io_ports *io_ports = &drive->hwif->io_ports;
if (valid & IDE_VALID_FEATURE)
scc_ide_outb(tf->feature, io_ports->feature_addr);
if (valid & IDE_VALID_NSECT)
scc_ide_outb(tf->nsect, io_ports->nsect_addr);
if (valid & IDE_VALID_LBAL)
scc_ide_outb(tf->lbal, io_ports->lbal_addr);
if (valid & IDE_VALID_LBAM)
scc_ide_outb(tf->lbam, io_ports->lbam_addr);
if (valid & IDE_VALID_LBAH)
scc_ide_outb(tf->lbah, io_ports->lbah_addr);
if (valid & IDE_VALID_DEVICE)
scc_ide_outb(tf->device, io_ports->device_addr);
}
static void scc_tf_read(ide_drive_t *drive, struct ide_taskfile *tf, u8 valid)
{
struct ide_io_ports *io_ports = &drive->hwif->io_ports;
if (valid & IDE_VALID_ERROR)
tf->error = scc_ide_inb(io_ports->feature_addr);
if (valid & IDE_VALID_NSECT)
tf->nsect = scc_ide_inb(io_ports->nsect_addr);
if (valid & IDE_VALID_LBAL)
tf->lbal = scc_ide_inb(io_ports->lbal_addr);
if (valid & IDE_VALID_LBAM)
tf->lbam = scc_ide_inb(io_ports->lbam_addr);
if (valid & IDE_VALID_LBAH)
tf->lbah = scc_ide_inb(io_ports->lbah_addr);
if (valid & IDE_VALID_DEVICE)
tf->device = scc_ide_inb(io_ports->device_addr);
}
static void scc_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
void *buf, unsigned int len)
{
unsigned long data_addr = drive->hwif->io_ports.data_addr;
len++;
if (drive->io_32bit) {
scc_ide_insl(data_addr, buf, len / 4);
if ((len & 3) >= 2)
scc_ide_insw(data_addr, (u8 *)buf + (len & ~3), 1);
} else
scc_ide_insw(data_addr, buf, len / 2);
}
static void scc_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
void *buf, unsigned int len)
{
unsigned long data_addr = drive->hwif->io_ports.data_addr;
len++;
if (drive->io_32bit) {
scc_ide_outsl(data_addr, buf, len / 4);
if ((len & 3) >= 2)
scc_ide_outsw(data_addr, (u8 *)buf + (len & ~3), 1);
} else
scc_ide_outsw(data_addr, buf, len / 2);
}
/**
* init_mmio_iops_scc - set up the iops for MMIO
* @hwif: interface to set up
*
*/
static void init_mmio_iops_scc(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
struct scc_ports *ports = pci_get_drvdata(dev);
unsigned long dma_base = ports->dma;
ide_set_hwifdata(hwif, ports);
hwif->dma_base = dma_base;
hwif->config_data = ports->ctl;
}
/**
* init_iops_scc - set up iops
* @hwif: interface to set up
*
* Do the basic setup for the SCC hardware interface
* and then do the MMIO setup.
*/
static void init_iops_scc(ide_hwif_t *hwif)
{
struct pci_dev *dev = to_pci_dev(hwif->dev);
hwif->hwif_data = NULL;
if (pci_get_drvdata(dev) == NULL)
return;
init_mmio_iops_scc(hwif);
}
static int scc_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
{
return ide_allocate_dma_engine(hwif);
}
static u8 scc_cable_detect(ide_hwif_t *hwif)
{
return ATA_CBL_PATA80;
}
/**
* init_hwif_scc - set up hwif
* @hwif: interface to set up
*
* We do the basic set up of the interface structure. The SCC
* requires several custom handlers so we override the default
* ide DMA handlers appropriately.
*/
static void init_hwif_scc(ide_hwif_t *hwif)
{
/* PTERADD */
out_be32((void __iomem *)(hwif->dma_base + 0x018), hwif->dmatable_dma);
if (in_be32((void __iomem *)(hwif->config_data + 0xff0)) & CCKCTRL_ATACLKOEN)
hwif->ultra_mask = ATA_UDMA6; /* 133MHz */
else
hwif->ultra_mask = ATA_UDMA5; /* 100MHz */
}
static const struct ide_tp_ops scc_tp_ops = {
.exec_command = scc_exec_command,
.read_status = scc_read_status,
.read_altstatus = scc_read_altstatus,
.write_devctl = scc_write_devctl,
.dev_select = ide_dev_select,
.tf_load = scc_tf_load,
.tf_read = scc_tf_read,
.input_data = scc_input_data,
.output_data = scc_output_data,
};
static const struct ide_port_ops scc_port_ops = {
.set_pio_mode = scc_set_pio_mode,
.set_dma_mode = scc_set_dma_mode,
.udma_filter = scc_udma_filter,
.cable_detect = scc_cable_detect,
};
static const struct ide_dma_ops scc_dma_ops = {
.dma_host_set = scc_dma_host_set,
.dma_setup = scc_dma_setup,
.dma_start = scc_dma_start,
.dma_end = scc_dma_end,
.dma_test_irq = scc_dma_test_irq,
.dma_lost_irq = ide_dma_lost_irq,
.dma_timer_expiry = ide_dma_sff_timer_expiry,
.dma_sff_read_status = scc_dma_sff_read_status,
};
static const struct ide_port_info scc_chipset = {
.name = "sccIDE",
.init_iops = init_iops_scc,
.init_dma = scc_init_dma,
.init_hwif = init_hwif_scc,
.tp_ops = &scc_tp_ops,
.port_ops = &scc_port_ops,
.dma_ops = &scc_dma_ops,
.host_flags = IDE_HFLAG_SINGLE,
.irq_flags = IRQF_SHARED,
.pio_mask = ATA_PIO4,
.chipset = ide_pci,
};
/**
* scc_init_one - pci layer discovery entry
* @dev: PCI device
* @id: ident table entry
*
* Called by the PCI code when it finds an SCC PATA controller.
* We then use the IDE PCI generic helper to do most of the work.
*/
static int scc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
{
return init_setup_scc(dev, &scc_chipset);
}
/**
* scc_remove - pci layer remove entry
* @dev: PCI device
*
* Called by the PCI code when it removes an SCC PATA controller.
*/
static void scc_remove(struct pci_dev *dev)
{
struct scc_ports *ports = pci_get_drvdata(dev);
struct ide_host *host = ports->host;
ide_host_remove(host);
iounmap((void*)ports->dma);
iounmap((void*)ports->ctl);
pci_release_selected_regions(dev, (1 << 2) - 1);
memset(ports, 0, sizeof(*ports));
}
static const struct pci_device_id scc_pci_tbl[] = {
{ PCI_VDEVICE(TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_SCC_ATA), 0 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, scc_pci_tbl);
static struct pci_driver scc_pci_driver = {
.name = "SCC IDE",
.id_table = scc_pci_tbl,
.probe = scc_init_one,
.remove = scc_remove,
};
static int __init scc_ide_init(void)
{
return ide_pci_register_driver(&scc_pci_driver);
}
static void __exit scc_ide_exit(void)
{
pci_unregister_driver(&scc_pci_driver);
}
module_init(scc_ide_init);
module_exit(scc_ide_exit);
MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE");
MODULE_LICENSE("GPL");
...@@ -205,6 +205,7 @@ enum { ...@@ -205,6 +205,7 @@ enum {
ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */ ATA_LFLAG_SW_ACTIVITY = (1 << 7), /* keep activity stats */
ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */ ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */
ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */ ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */
ATA_LFLAG_CHANGED = (1 << 10), /* LPM state changed on this link */
/* struct ata_port flags */ /* struct ata_port flags */
ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */ ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
...@@ -309,6 +310,12 @@ enum { ...@@ -309,6 +310,12 @@ enum {
*/ */
ATA_TMOUT_PMP_SRST_WAIT = 5000, ATA_TMOUT_PMP_SRST_WAIT = 5000,
/* When the LPM policy is set to ATA_LPM_MAX_POWER, there might
* be a spurious PHY event, so ignore the first PHY event that
* occurs within 10s after the policy change.
*/
ATA_TMOUT_SPURIOUS_PHY = 10000,
/* ATA bus states */ /* ATA bus states */
BUS_UNKNOWN = 0, BUS_UNKNOWN = 0,
BUS_DMA = 1, BUS_DMA = 1,
...@@ -788,6 +795,8 @@ struct ata_link { ...@@ -788,6 +795,8 @@ struct ata_link {
struct ata_eh_context eh_context; struct ata_eh_context eh_context;
struct ata_device device[ATA_MAX_DEVICES]; struct ata_device device[ATA_MAX_DEVICES];
unsigned long last_lpm_change; /* when last LPM change happened */
}; };
#define ATA_LINK_CLEAR_BEGIN offsetof(struct ata_link, active_tag) #define ATA_LINK_CLEAR_BEGIN offsetof(struct ata_link, active_tag)
#define ATA_LINK_CLEAR_END offsetof(struct ata_link, device[0]) #define ATA_LINK_CLEAR_END offsetof(struct ata_link, device[0])
...@@ -1201,6 +1210,7 @@ extern struct ata_device *ata_dev_pair(struct ata_device *adev); ...@@ -1201,6 +1210,7 @@ extern struct ata_device *ata_dev_pair(struct ata_device *adev);
extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev); extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap); extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap);
extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q); extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q);
extern bool sata_lpm_ignore_phy_events(struct ata_link *link);
extern int ata_cable_40wire(struct ata_port *ap); extern int ata_cable_40wire(struct ata_port *ap);
extern int ata_cable_80wire(struct ata_port *ap); extern int ata_cable_80wire(struct ata_port *ap);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment