Minor libata updates, nothing notable.

1) Apply -- and then revert -- the FUA feature.  Caused
    disk corruption in linux-next, proving it cannot be turned on by
    default.
 
    Net effect to upstream tree:  zero
 
 2) New AHCI platform driver sata_highbank
 
 3) Improve SCSI MODE SENSE handling; support MODE SELECT
 
 4) AHCI: support aggressive device sleep (power mgmt)
 
 5) sata_fsl: minor fix
 
 6) pata_arasan: clk support
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIVAwUAUGtCHCWzCDIBeCsvAQLHFA//X6IM8ymHasCzEXvB2IusarPZYqfrGOUX
 DVHPPeBdNbuNtX1iIp9NEvx5PONEvBgylrzbH0jOW9f+8GZM7sgT0NFlUWAfg7hO
 HF3RN3EsQMMcSK+BoOLzo+vzSEAIbPB7zqKAGqh9QBBpfKAYbAy2WHr7P5OMuy9J
 IjKoknc8jaOWavg8oavx3dU5PCFU7BoPQzrPSNB/MY5L1Ia3H29zyCmoW1Ha05wa
 LRZzJes4X3H+tStNhtrNmItaRfxJNW7xPluNOn4FIyQmK+Nh3NDk6IBuwPdFpltn
 m6azzOfHreaP9J9xcIiU1NX7Gu+IBYZpOyL61B+WUmCRLXMdnhDTZE6mkKe10ReZ
 o9oBn636swDVMXG+zS0hjv+nQgV0l+sHX/0GsTCxDapZal7icCUsLzW9flaCh0n+
 zkwoxjvGZOkFf6ZsAgFVo8h2YMe7Ph2I5JIiN12rqee4grV7cHStKQn076Kyb9zo
 5LsR1/+YuuWz9G2dEmirDA8xBtydIZ4thvblwXipnqyZWkAwLue+opIWxau7BlPZ
 qz6KjNp2L1hS8QgQnYHYmk/EDPDg5SNP4RTCCO9TKUBcu9fcke2c+R8V7ebKCI02
 AaaccV4N6t7c1rdQUH6bnizi9aZ+tRoBAheLEDrrkOx72f71hE6JgueqhI+EaTw6
 LyrSiiVITxA=
 =i3EH
 -----END PGP SIGNATURE-----

Merge tag 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev

Pull libata changes from Jeff Garzik:
 "Minor libata updates, nothing notable.

   1) Apply -- and then revert -- the FUA feature.  Caused disk
      corruption in linux-next, proving it cannot be turned on by
      default.

      Net effect to upstream tree:  zero

   2) New AHCI platform driver sata_highbank

   3) Improve SCSI MODE SENSE handling; support MODE SELECT

   4) AHCI: support aggressive device sleep (power mgmt)

   5) sata_fsl: minor fix

   6) pata_arasan: clk support"

* tag 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/libata-dev:
  sata_mv: Fix warnings when no PCI
  [libata] Makefile: Fix build error in sata_highbank
  [libata] export ata_dev_set_feature()
  libata-core: use ATA_LBA in ata_build_rw_tf()
  ata/ahci_platform: Add clock framework support
  pata_arasan: add Device Tree probing capability
  pata_arasan: Add clk_{un}prepare() support
  ata: add platform driver for Calxeda AHCI controller
  sata_fsl: add workaround for data length mismatch on freescale V2 controller
  ahci: implement aggressive SATA device sleep support
  ata: define enum constants for IDENTIFY DEVICE
  Revert "libata: enable SATA disk fua detection on default"
  [libata] scsi: implement MODE SELECT command
  [libata] scsi: support MODE SENSE request for changeable and default parameters
  [libata] scsi: Remove unlikely() from FUA check
  libata: enable SATA disk fua detection on default
This commit is contained in:
Linus Torvalds 2012-10-02 18:23:35 -07:00
commit 51562cba98
19 changed files with 1025 additions and 60 deletions

View file

@ -0,0 +1,17 @@
Calxeda Highbank Combination Phys for SATA
Properties:
- compatible : Should be "calxeda,hb-combophy"
- #phy-cells: Should be 1.
- reg : Address and size for Combination Phy registers.
- phydev: device ID for programming the combophy.
Example:
combophy5: combo-phy@fff5d000 {
compatible = "calxeda,hb-combophy";
#phy-cells = <1>;
reg = <0xfff5d000 0x1000>;
phydev = <31>;
};

View file

@ -8,9 +8,17 @@ Required properties:
- interrupts : <interrupt mapping for SATA IRQ>
- reg : <registers mapping>
Optional properties:
- calxeda,port-phys: phandle-combophy and lane assignment, which maps each
SATA port to a combophy and a lane within that
combophy
Example:
sata@ffe08000 {
compatible = "calxeda,hb-ahci";
reg = <0xffe08000 0x1000>;
interrupts = <115>;
calxeda,port-phys = <&combophy5 0 &combophy0 0 &combophy0 1
&combophy0 2 &combophy0 3>;
};

View file

@ -0,0 +1,17 @@
* ARASAN PATA COMPACT FLASH CONTROLLER
Required properties:
- compatible: "arasan,cf-spear1340"
- reg: Address range of the CF registers
- interrupt-parent: Should be the phandle for the interrupt controller
that services interrupts for this device
- interrupt: Should contain the CF interrupt number
Example:
cf@fc000000 {
compatible = "arasan,cf-spear1340";
reg = <0xfc000000 0x1000>;
interrupt-parent = <&vic1>;
interrupts = <12>;
};

View file

@ -121,6 +121,9 @@
compatible = "calxeda,hb-ahci";
reg = <0xffe08000 0x10000>;
interrupts = <0 83 4>;
calxeda,port-phys = <&combophy5 0 &combophy0 0
&combophy0 1 &combophy0 2
&combophy0 3>;
};
sdhci@ffe0e000 {
@ -306,5 +309,19 @@
reg = <0xfff51000 0x1000>;
interrupts = <0 80 4 0 81 4 0 82 4>;
};
combophy0: combo-phy@fff58000 {
compatible = "calxeda,hb-combophy";
#phy-cells = <1>;
reg = <0xfff58000 0x1000>;
phydev = <5>;
};
combophy5: combo-phy@fff5d000 {
compatible = "calxeda,hb-combophy";
#phy-cells = <1>;
reg = <0xfff5d000 0x1000>;
phydev = <31>;
};
};
};

View file

@ -214,6 +214,14 @@ config SATA_DWC_VDEBUG
help
This option enables the taskfile dumping and NCQ debugging.
config SATA_HIGHBANK
tristate "Calxeda Highbank SATA support"
help
This option enables support for the Calxeda Highbank SoC's
onboard SATA.
If unsure, say N.
config SATA_MV
tristate "Marvell SATA support"
help

View file

@ -9,6 +9,7 @@ obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
# SFF w/ custom DMA
obj-$(CONFIG_PDC_ADMA) += pdc_adma.o

View file

@ -35,6 +35,7 @@
#ifndef _AHCI_H
#define _AHCI_H
#include <linux/clk.h>
#include <linux/libata.h>
/* Enclosure Management Control */
@ -115,6 +116,9 @@ enum {
HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */
HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */
HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */
HOST_CAP2_SDS = (1 << 3), /* Support device sleep */
HOST_CAP2_SADM = (1 << 4), /* Support aggressive DevSlp */
HOST_CAP2_DESO = (1 << 5), /* DevSlp from slumber only */
/* registers for each SATA port */
PORT_LST_ADDR = 0x00, /* command list DMA addr */
@ -133,6 +137,7 @@ enum {
PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */
PORT_SCR_NTF = 0x3c, /* SATA phy register: SNotification */
PORT_FBS = 0x40, /* FIS-based Switching */
PORT_DEVSLP = 0x44, /* device sleep */
/* PORT_IRQ_{STAT,MASK} bits */
PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */
@ -186,6 +191,7 @@ enum {
PORT_CMD_ICC_PARTIAL = (0x2 << 28), /* Put i/f in partial state */
PORT_CMD_ICC_SLUMBER = (0x6 << 28), /* Put i/f in slumber state */
/* PORT_FBS bits */
PORT_FBS_DWE_OFFSET = 16, /* FBS device with error offset */
PORT_FBS_ADO_OFFSET = 12, /* FBS active dev optimization offset */
PORT_FBS_DEV_OFFSET = 8, /* FBS device to issue offset */
@ -194,6 +200,15 @@ enum {
PORT_FBS_DEC = (1 << 1), /* FBS device error clear */
PORT_FBS_EN = (1 << 0), /* Enable FBS */
/* PORT_DEVSLP bits */
PORT_DEVSLP_DM_OFFSET = 25, /* DITO multiplier offset */
PORT_DEVSLP_DM_MASK = (0xf << 25), /* DITO multiplier mask */
PORT_DEVSLP_DITO_OFFSET = 15, /* DITO offset */
PORT_DEVSLP_MDAT_OFFSET = 10, /* Minimum assertion time */
PORT_DEVSLP_DETO_OFFSET = 2, /* DevSlp exit timeout */
PORT_DEVSLP_DSP = (1 << 1), /* DevSlp present */
PORT_DEVSLP_ADSE = (1 << 0), /* Aggressive DevSlp enable */
/* hpriv->flags bits */
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
@ -302,6 +317,7 @@ struct ahci_host_priv {
u32 em_loc; /* enclosure management location */
u32 em_buf_sz; /* EM buffer size in byte */
u32 em_msg_type; /* EM message type */
struct clk *clk; /* Only for platforms supporting clk */
};
extern int ahci_ignore_sss;

View file

@ -12,6 +12,7 @@
* any later version.
*/
#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
@ -118,6 +119,17 @@ static int __init ahci_probe(struct platform_device *pdev)
return -ENOMEM;
}
hpriv->clk = clk_get(dev, NULL);
if (IS_ERR(hpriv->clk)) {
dev_err(dev, "can't get clock\n");
} else {
rc = clk_prepare_enable(hpriv->clk);
if (rc) {
dev_err(dev, "clock prepare enable failed");
goto free_clk;
}
}
/*
* Some platforms might need to prepare for mmio region access,
* which could be done in the following init call. So, the mmio
@ -127,7 +139,7 @@ static int __init ahci_probe(struct platform_device *pdev)
if (pdata && pdata->init) {
rc = pdata->init(dev, hpriv->mmio);
if (rc)
return rc;
goto disable_unprepare_clk;
}
ahci_save_initial_config(dev, hpriv,
@ -153,7 +165,7 @@ static int __init ahci_probe(struct platform_device *pdev)
host = ata_host_alloc_pinfo(dev, ppi, n_ports);
if (!host) {
rc = -ENOMEM;
goto err0;
goto pdata_exit;
}
host->private_data = hpriv;
@ -183,7 +195,7 @@ static int __init ahci_probe(struct platform_device *pdev)
rc = ahci_reset_controller(host);
if (rc)
goto err0;
goto pdata_exit;
ahci_init_controller(host);
ahci_print_info(host, "platform");
@ -191,12 +203,18 @@ static int __init ahci_probe(struct platform_device *pdev)
rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
&ahci_platform_sht);
if (rc)
goto err0;
goto pdata_exit;
return 0;
err0:
pdata_exit:
if (pdata && pdata->exit)
pdata->exit(dev);
disable_unprepare_clk:
if (!IS_ERR(hpriv->clk))
clk_disable_unprepare(hpriv->clk);
free_clk:
if (!IS_ERR(hpriv->clk))
clk_put(hpriv->clk);
return rc;
}
@ -205,12 +223,18 @@ static int __devexit ahci_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
ata_host_detach(host);
if (pdata && pdata->exit)
pdata->exit(dev);
if (!IS_ERR(hpriv->clk)) {
clk_disable_unprepare(hpriv->clk);
clk_put(hpriv->clk);
}
return 0;
}
@ -245,6 +269,10 @@ static int ahci_suspend(struct device *dev)
if (pdata && pdata->suspend)
return pdata->suspend(dev);
if (!IS_ERR(hpriv->clk))
clk_disable_unprepare(hpriv->clk);
return 0;
}
@ -252,18 +280,27 @@ static int ahci_resume(struct device *dev)
{
struct ahci_platform_data *pdata = dev_get_platdata(dev);
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
int rc;
if (!IS_ERR(hpriv->clk)) {
rc = clk_prepare_enable(hpriv->clk);
if (rc) {
dev_err(dev, "clock prepare enable failed");
return rc;
}
}
if (pdata && pdata->resume) {
rc = pdata->resume(dev);
if (rc)
return rc;
goto disable_unprepare_clk;
}
if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(host);
if (rc)
return rc;
goto disable_unprepare_clk;
ahci_init_controller(host);
}
@ -271,13 +308,18 @@ static int ahci_resume(struct device *dev)
ata_host_resume(host);
return 0;
disable_unprepare_clk:
if (!IS_ERR(hpriv->clk))
clk_disable_unprepare(hpriv->clk);
return rc;
}
#endif
SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
static const struct of_device_id ahci_of_match[] = {
{ .compatible = "calxeda,hb-ahci", },
{ .compatible = "snps,spear-ahci", },
{},
};

View file

@ -45,6 +45,7 @@
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
#include "ahci.h"
#include "libata.h"
static int ahci_skip_host_reset;
int ahci_ignore_sss;
@ -76,6 +77,7 @@ static void ahci_qc_prep(struct ata_queued_cmd *qc);
static int ahci_pmp_qc_defer(struct ata_queued_cmd *qc);
static void ahci_freeze(struct ata_port *ap);
static void ahci_thaw(struct ata_port *ap);
static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep);
static void ahci_enable_fbs(struct ata_port *ap);
static void ahci_disable_fbs(struct ata_port *ap);
static void ahci_pmp_attach(struct ata_port *ap);
@ -193,6 +195,10 @@ module_param(ahci_em_messages, int, 0444);
MODULE_PARM_DESC(ahci_em_messages,
"AHCI Enclosure Management Message control (0 = off, 1 = on)");
int devslp_idle_timeout = 1000; /* device sleep idle timeout in ms */
module_param(devslp_idle_timeout, int, 0644);
MODULE_PARM_DESC(devslp_idle_timeout, "device sleep idle timeout");
static void ahci_enable_ahci(void __iomem *mmio)
{
int i;
@ -702,6 +708,16 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
}
}
/* set aggressive device sleep */
if ((hpriv->cap2 & HOST_CAP2_SDS) &&
(hpriv->cap2 & HOST_CAP2_SADM) &&
(link->device->flags & ATA_DFLAG_DEVSLP)) {
if (policy == ATA_LPM_MIN_POWER)
ahci_set_aggressive_devslp(ap, true);
else
ahci_set_aggressive_devslp(ap, false);
}
if (policy == ATA_LPM_MAX_POWER) {
sata_link_scr_lpm(link, policy, false);
@ -1890,6 +1906,81 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
ahci_kick_engine(ap);
}
static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
{
void __iomem *port_mmio = ahci_port_base(ap);
struct ata_device *dev = ap->link.device;
u32 devslp, dm, dito, mdat, deto;
int rc;
unsigned int err_mask;
devslp = readl(port_mmio + PORT_DEVSLP);
if (!(devslp & PORT_DEVSLP_DSP)) {
dev_err(ap->host->dev, "port does not support device sleep\n");
return;
}
/* disable device sleep */
if (!sleep) {
if (devslp & PORT_DEVSLP_ADSE) {
writel(devslp & ~PORT_DEVSLP_ADSE,
port_mmio + PORT_DEVSLP);
err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_DISABLE,
SATA_DEVSLP);
if (err_mask && err_mask != AC_ERR_DEV)
ata_dev_warn(dev, "failed to disable DEVSLP\n");
}
return;
}
/* device sleep was already enabled */
if (devslp & PORT_DEVSLP_ADSE)
return;
/* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */
rc = ahci_stop_engine(ap);
if (rc)
return;
dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET;
dito = devslp_idle_timeout / (dm + 1);
if (dito > 0x3ff)
dito = 0x3ff;
/* Use the nominal value 10 ms if the read MDAT is zero,
* the nominal value of DETO is 20 ms.
*/
if (dev->sata_settings[ATA_LOG_DEVSLP_VALID] &
ATA_LOG_DEVSLP_VALID_MASK) {
mdat = dev->sata_settings[ATA_LOG_DEVSLP_MDAT] &
ATA_LOG_DEVSLP_MDAT_MASK;
if (!mdat)
mdat = 10;
deto = dev->sata_settings[ATA_LOG_DEVSLP_DETO];
if (!deto)
deto = 20;
} else {
mdat = 10;
deto = 20;
}
devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) |
(mdat << PORT_DEVSLP_MDAT_OFFSET) |
(deto << PORT_DEVSLP_DETO_OFFSET) |
PORT_DEVSLP_ADSE);
writel(devslp, port_mmio + PORT_DEVSLP);
ahci_start_engine(ap);
/* enable device sleep feature for the drive */
err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_ENABLE,
SATA_DEVSLP);
if (err_mask && err_mask != AC_ERR_DEV)
ata_dev_warn(dev, "failed to enable DEVSLP\n");
}
static void ahci_enable_fbs(struct ata_port *ap)
{
struct ahci_port_priv *pp = ap->private_data;
@ -2164,7 +2255,8 @@ void ahci_print_info(struct ata_host *host, const char *scc_s)
"flags: "
"%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s"
"%s%s%s%s%s%s\n"
"%s%s%s%s%s%s%s"
"%s%s\n"
,
cap & HOST_CAP_64 ? "64bit " : "",
@ -2184,6 +2276,9 @@ void ahci_print_info(struct ata_host *host, const char *scc_s)
cap & HOST_CAP_CCC ? "ccc " : "",
cap & HOST_CAP_EMS ? "ems " : "",
cap & HOST_CAP_SXS ? "sxs " : "",
cap2 & HOST_CAP2_DESO ? "deso " : "",
cap2 & HOST_CAP2_SADM ? "sadm " : "",
cap2 & HOST_CAP2_SDS ? "sds " : "",
cap2 & HOST_CAP2_APST ? "apst " : "",
cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",
cap2 & HOST_CAP2_BOH ? "boh " : ""

View file

@ -774,7 +774,7 @@ int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
tf->lbam = (block >> 8) & 0xff;
tf->lbal = block & 0xff;
tf->device = 1 << 6;
tf->device = ATA_LBA;
if (tf->flags & ATA_TFLAG_FUA)
tf->device |= 1 << 7;
} else if (dev->flags & ATA_DFLAG_LBA) {
@ -2155,6 +2155,7 @@ int ata_dev_configure(struct ata_device *dev)
int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
const u16 *id = dev->id;
unsigned long xfer_mask;
unsigned int err_mask;
char revbuf[7]; /* XYZ-99\0 */
char fwrevbuf[ATA_ID_FW_REV_LEN+1];
char modelbuf[ATA_ID_PROD_LEN+1];
@ -2323,6 +2324,26 @@ int ata_dev_configure(struct ata_device *dev)
}
}
/* check and mark DevSlp capability */
if (ata_id_has_devslp(dev->id))
dev->flags |= ATA_DFLAG_DEVSLP;
/* Obtain SATA Settings page from Identify Device Data Log,
* which contains DevSlp timing variables etc.
* Exclude old devices with ata_id_has_ncq()
*/
if (ata_id_has_ncq(dev->id)) {
err_mask = ata_read_log_page(dev,
ATA_LOG_SATA_ID_DEV_DATA,
ATA_LOG_SATA_SETTINGS,
dev->sata_settings,
1);
if (err_mask)
ata_dev_dbg(dev,
"failed to get Identify Device Data, Emask 0x%x\n",
err_mask);
}
dev->cdb_len = 16;
}
@ -2351,8 +2372,6 @@ int ata_dev_configure(struct ata_device *dev)
(ap->flags & ATA_FLAG_AN) && ata_id_has_atapi_AN(id) &&
(!sata_pmp_attached(ap) ||
sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf) == 0)) {
unsigned int err_mask;
/* issue SET feature command to turn this on */
err_mask = ata_dev_set_feature(dev,
SETFEATURES_SATA_ENABLE, SATA_AN);
@ -3598,7 +3617,7 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
switch (policy) {
case ATA_LPM_MAX_POWER:
/* disable all LPM transitions */
scontrol |= (0x3 << 8);
scontrol |= (0x7 << 8);
/* initiate transition to active state */
if (spm_wakeup) {
scontrol |= (0x4 << 12);
@ -3608,12 +3627,12 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy,
case ATA_LPM_MED_POWER:
/* allow LPM to PARTIAL */
scontrol &= ~(0x1 << 8);
scontrol |= (0x2 << 8);
scontrol |= (0x6 << 8);
break;
case ATA_LPM_MIN_POWER:
if (ata_link_nr_enabled(link) > 0)
/* no restrictions on LPM transitions */
scontrol &= ~(0x3 << 8);
scontrol &= ~(0x7 << 8);
else {
/* empty port, power off */
scontrol &= ~0xf;
@ -4472,6 +4491,7 @@ unsigned int ata_dev_set_feature(struct ata_device *dev, u8 enable, u8 feature)
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
}
EXPORT_SYMBOL_GPL(ata_dev_set_feature);
/**
* ata_dev_init_params - Issue INIT DEV PARAMS command

View file

@ -1487,6 +1487,7 @@ static const char *ata_err_string(unsigned int err_mask)
/**
* ata_read_log_page - read a specific log page
* @dev: target device
* @log: log to read
* @page: page to read
* @buf: buffer to store read page
* @sectors: number of sectors to read
@ -1499,17 +1500,18 @@ static const char *ata_err_string(unsigned int err_mask)
* RETURNS:
* 0 on success, AC_ERR_* mask otherwise.
*/
static unsigned int ata_read_log_page(struct ata_device *dev,
u8 page, void *buf, unsigned int sectors)
unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
u8 page, void *buf, unsigned int sectors)
{
struct ata_taskfile tf;
unsigned int err_mask;
DPRINTK("read log page - page %d\n", page);
DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
ata_tf_init(dev, &tf);
tf.command = ATA_CMD_READ_LOG_EXT;
tf.lbal = page;
tf.lbal = log;
tf.lbam = page;
tf.nsect = sectors;
tf.hob_nsect = sectors >> 8;
tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_LBA48 | ATA_TFLAG_DEVICE;
@ -1545,7 +1547,7 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
u8 csum;
int i;
err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, buf, 1);
err_mask = ata_read_log_page(dev, ATA_LOG_SATA_NCQ, 0, buf, 1);
if (err_mask)
return -EIO;

View file

@ -1655,7 +1655,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
if (unlikely(scmd->cmd_len < 10))
goto invalid_fld;
scsi_10_lba_len(cdb, &block, &n_block);
if (unlikely(cdb[1] & (1 << 3)))
if (cdb[1] & (1 << 3))
tf_flags |= ATA_TFLAG_FUA;
break;
case READ_6:
@ -1675,7 +1675,7 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc)
if (unlikely(scmd->cmd_len < 16))
goto invalid_fld;
scsi_16_lba_len(cdb, &block, &n_block);
if (unlikely(cdb[1] & (1 << 3)))
if (cdb[1] & (1 << 3))
tf_flags |= ATA_TFLAG_FUA;
break;
default:
@ -2204,10 +2204,34 @@ static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf)
return 0;
}
/**
* modecpy - Prepare response for MODE SENSE
* @dest: output buffer
* @src: data being copied
* @n: length of mode page
* @changeable: whether changeable parameters are requested
*
* Generate a generic MODE SENSE page for either current or changeable
* parameters.
*
* LOCKING:
* None.
*/
static void modecpy(u8 *dest, const u8 *src, int n, bool changeable)
{
if (changeable) {
memcpy(dest, src, 2);
memset(dest + 2, 0, n - 2);
} else {
memcpy(dest, src, n);
}
}
/**
* ata_msense_caching - Simulate MODE SENSE caching info page
* @id: device IDENTIFY data
* @buf: output buffer
* @changeable: whether changeable parameters are requested
*
* Generate a caching info page, which conditionally indicates
* write caching to the SCSI layer, depending on device
@ -2216,12 +2240,12 @@ static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf)
* LOCKING:
* None.
*/
static unsigned int ata_msense_caching(u16 *id, u8 *buf)
static unsigned int ata_msense_caching(u16 *id, u8 *buf, bool changeable)
{
memcpy(buf, def_cache_mpage, sizeof(def_cache_mpage));
if (ata_id_wcache_enabled(id))
modecpy(buf, def_cache_mpage, sizeof(def_cache_mpage), changeable);
if (changeable || ata_id_wcache_enabled(id))
buf[2] |= (1 << 2); /* write cache enable */
if (!ata_id_rahead_enabled(id))
if (!changeable && !ata_id_rahead_enabled(id))
buf[12] |= (1 << 5); /* disable read ahead */
return sizeof(def_cache_mpage);
}
@ -2229,30 +2253,33 @@ static unsigned int ata_msense_caching(u16 *id, u8 *buf)
/**
* ata_msense_ctl_mode - Simulate MODE SENSE control mode page
* @buf: output buffer
* @changeable: whether changeable parameters are requested
*
* Generate a generic MODE SENSE control mode page.
*
* LOCKING:
* None.
*/
static unsigned int ata_msense_ctl_mode(u8 *buf)
static unsigned int ata_msense_ctl_mode(u8 *buf, bool changeable)
{
memcpy(buf, def_control_mpage, sizeof(def_control_mpage));
modecpy(buf, def_control_mpage, sizeof(def_control_mpage), changeable);
return sizeof(def_control_mpage);
}
/**
* ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
* @buf: output buffer
* @changeable: whether changeable parameters are requested
*
* Generate a generic MODE SENSE r/w error recovery page.
*
* LOCKING:
* None.
*/
static unsigned int ata_msense_rw_recovery(u8 *buf)
static unsigned int ata_msense_rw_recovery(u8 *buf, bool changeable)
{
memcpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage));
modecpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage),
changeable);
return sizeof(def_rw_recovery_mpage);
}
@ -2316,11 +2343,11 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
page_control = scsicmd[2] >> 6;
switch (page_control) {
case 0: /* current */
case 1: /* changeable */
case 2: /* defaults */
break; /* supported */
case 3: /* saved */
goto saving_not_supp;
case 1: /* changeable */
case 2: /* defaults */
default:
goto invalid_fld;
}
@ -2341,21 +2368,21 @@ static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
switch(pg) {
case RW_RECOVERY_MPAGE:
p += ata_msense_rw_recovery(p);
p += ata_msense_rw_recovery(p, page_control == 1);
break;
case CACHE_MPAGE:
p += ata_msense_caching(args->id, p);
p += ata_msense_caching(args->id, p, page_control == 1);
break;
case CONTROL_MPAGE:
p += ata_msense_ctl_mode(p);
p += ata_msense_ctl_mode(p, page_control == 1);
break;
case ALL_MPAGES:
p += ata_msense_rw_recovery(p);
p += ata_msense_caching(args->id, p);
p += ata_msense_ctl_mode(p);
p += ata_msense_rw_recovery(p, page_control == 1);
p += ata_msense_caching(args->id, p, page_control == 1);
p += ata_msense_ctl_mode(p, page_control == 1);
break;
default: /* invalid page code */
@ -3079,6 +3106,188 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
return 1;
}
/**
* ata_mselect_caching - Simulate MODE SELECT for caching info page
* @qc: Storage for translated ATA taskfile
* @buf: input buffer
* @len: number of valid bytes in the input buffer
*
* Prepare a taskfile to modify caching information for the device.
*
* LOCKING:
* None.
*/
static int ata_mselect_caching(struct ata_queued_cmd *qc,
const u8 *buf, int len)
{
struct ata_taskfile *tf = &qc->tf;
struct ata_device *dev = qc->dev;
char mpage[CACHE_MPAGE_LEN];
u8 wce;
/*
* The first two bytes of def_cache_mpage are a header, so offsets
* in mpage are off by 2 compared to buf. Same for len.
*/
if (len != CACHE_MPAGE_LEN - 2)
return -EINVAL;
wce = buf[0] & (1 << 2);
/*
* Check that read-only bits are not modified.
*/
ata_msense_caching(dev->id, mpage, false);
mpage[2] &= ~(1 << 2);
mpage[2] |= wce;
if (memcmp(mpage + 2, buf, CACHE_MPAGE_LEN - 2) != 0)
return -EINVAL;
tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR;
tf->protocol = ATA_PROT_NODATA;
tf->nsect = 0;
tf->command = ATA_CMD_SET_FEATURES;
tf->feature = wce ? SETFEATURES_WC_ON : SETFEATURES_WC_OFF;
return 0;
}
/**
* ata_scsiop_mode_select - Simulate MODE SELECT 6, 10 commands
* @qc: Storage for translated ATA taskfile
*
* Converts a MODE SELECT command to an ATA SET FEATURES taskfile.
* Assume this is invoked for direct access devices (e.g. disks) only.
* There should be no block descriptor for other device types.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *scmd = qc->scsicmd;
const u8 *cdb = scmd->cmnd;
const u8 *p;
u8 pg, spg;
unsigned six_byte, pg_len, hdr_len, bd_len;
int len;
VPRINTK("ENTER\n");
six_byte = (cdb[0] == MODE_SELECT);
if (six_byte) {
if (scmd->cmd_len < 5)
goto invalid_fld;
len = cdb[4];
hdr_len = 4;
} else {
if (scmd->cmd_len < 9)
goto invalid_fld;
len = (cdb[7] << 8) + cdb[8];
hdr_len = 8;
}
/* We only support PF=1, SP=0. */
if ((cdb[1] & 0x11) != 0x10)
goto invalid_fld;
/* Test early for possible overrun. */
if (!scsi_sg_count(scmd) || scsi_sglist(scmd)->length < len)
goto invalid_param_len;
p = page_address(sg_page(scsi_sglist(scmd)));
/* Move past header and block descriptors. */
if (len < hdr_len)
goto invalid_param_len;
if (six_byte)
bd_len = p[3];
else
bd_len = (p[6] << 8) + p[7];
len -= hdr_len;
p += hdr_len;
if (len < bd_len)
goto invalid_param_len;
if (bd_len != 0 && bd_len != 8)
goto invalid_param;
len -= bd_len;
p += bd_len;
if (len == 0)
goto skip;
/* Parse both possible formats for the mode page headers. */
pg = p[0] & 0x3f;
if (p[0] & 0x40) {
if (len < 4)
goto invalid_param_len;
spg = p[1];
pg_len = (p[2] << 8) | p[3];
p += 4;
len -= 4;
} else {
if (len < 2)
goto invalid_param_len;
spg = 0;
pg_len = p[1];
p += 2;
len -= 2;
}
/*
* No mode subpages supported (yet) but asking for _all_
* subpages may be valid
*/
if (spg && (spg != ALL_SUB_MPAGES))
goto invalid_param;
if (pg_len > len)
goto invalid_param_len;
switch (pg) {
case CACHE_MPAGE:
if (ata_mselect_caching(qc, p, pg_len) < 0)
goto invalid_param;
break;
default: /* invalid page code */
goto invalid_param;
}
/*
* Only one page has changeable data, so we only support setting one
* page at a time.
*/
if (len > pg_len)
goto invalid_param;
return 0;
invalid_fld:
/* "Invalid field in CDB" */
ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x24, 0x0);
return 1;
invalid_param:
/* "Invalid field in parameter list" */
ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x26, 0x0);
return 1;
invalid_param_len:
/* "Parameter list length error" */
ata_scsi_set_sense(scmd, ILLEGAL_REQUEST, 0x1a, 0x0);
return 1;
skip:
scmd->result = SAM_STAT_GOOD;
return 1;
}
/**
* ata_get_xlat_func - check if SCSI to ATA translation is possible
* @dev: ATA device
@ -3119,6 +3328,11 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
case ATA_16:
return ata_scsi_pass_thru;
case MODE_SELECT:
case MODE_SELECT_10:
return ata_scsi_mode_select_xlat;
break;
case START_STOP:
return ata_scsi_start_stop_xlat;
}
@ -3311,11 +3525,6 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
break;
case MODE_SELECT: /* unconditionally return */
case MODE_SELECT_10: /* bad-field-in-cdb */
ata_scsi_invalid_field(cmd);
break;
case READ_CAPACITY:
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
break;

View file

@ -165,6 +165,8 @@ extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
unsigned int action);
extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
unsigned int action);
extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
u8 page, void *buf, unsigned int sectors);
extern void ata_eh_autopsy(struct ata_port *ap);
const char *ata_get_cmd_descript(u8 command);
extern void ata_eh_report(struct ata_port *ap);

View file

@ -31,6 +31,7 @@
#include <linux/kernel.h>
#include <linux/libata.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pata_arasan_cf_data.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
@ -310,7 +311,7 @@ static int cf_init(struct arasan_cf_dev *acdev)
unsigned long flags;
int ret = 0;
ret = clk_enable(acdev->clk);
ret = clk_prepare_enable(acdev->clk);
if (ret) {
dev_dbg(acdev->host->dev, "clock enable failed");
return ret;
@ -340,7 +341,7 @@ static void cf_exit(struct arasan_cf_dev *acdev)
writel(readl(acdev->vbase + OP_MODE) & ~CFHOST_ENB,
acdev->vbase + OP_MODE);
spin_unlock_irqrestore(&acdev->host->lock, flags);
clk_disable(acdev->clk);
clk_disable_unprepare(acdev->clk);
}
static void dma_callback(void *dev)
@ -935,6 +936,14 @@ static int arasan_cf_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(arasan_cf_pm_ops, arasan_cf_suspend, arasan_cf_resume);
#ifdef CONFIG_OF
static const struct of_device_id arasan_cf_id_table[] = {
{ .compatible = "arasan,cf-spear1340" },
{}
};
MODULE_DEVICE_TABLE(of, arasan_cf_id_table);
#endif
static struct platform_driver arasan_cf_driver = {
.probe = arasan_cf_probe,
.remove = __devexit_p(arasan_cf_remove),
@ -942,6 +951,7 @@ static struct platform_driver arasan_cf_driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.pm = &arasan_cf_pm_ops,
.of_match_table = of_match_ptr(arasan_cf_id_table),
},
};

View file

@ -123,6 +123,7 @@ enum {
ONLINE = (1 << 31),
GOING_OFFLINE = (1 << 30),
BIST_ERR = (1 << 29),
CLEAR_ERROR = (1 << 27),
FATAL_ERR_HC_MASTER_ERR = (1 << 18),
FATAL_ERR_PARITY_ERR_TX = (1 << 17),
@ -143,6 +144,7 @@ enum {
FATAL_ERR_CRC_ERR_RX |
FATAL_ERR_FIFO_OVRFL_TX | FATAL_ERR_FIFO_OVRFL_RX,
INT_ON_DATA_LENGTH_MISMATCH = (1 << 12),
INT_ON_FATAL_ERR = (1 << 5),
INT_ON_PHYRDY_CHG = (1 << 4),
@ -1181,25 +1183,54 @@ static void sata_fsl_host_intr(struct ata_port *ap)
u32 hstatus, done_mask = 0;
struct ata_queued_cmd *qc;
u32 SError;
u32 tag;
u32 status_mask = INT_ON_ERROR;
hstatus = ioread32(hcr_base + HSTATUS);
sata_fsl_scr_read(&ap->link, SCR_ERROR, &SError);
/* Read command completed register */
done_mask = ioread32(hcr_base + CC);
/* Workaround for data length mismatch errata */
if (unlikely(hstatus & INT_ON_DATA_LENGTH_MISMATCH)) {
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
qc = ata_qc_from_tag(ap, tag);
if (qc && ata_is_atapi(qc->tf.protocol)) {
u32 hcontrol;
/* Set HControl[27] to clear error registers */
hcontrol = ioread32(hcr_base + HCONTROL);
iowrite32(hcontrol | CLEAR_ERROR,
hcr_base + HCONTROL);
/* Clear HControl[27] */
iowrite32(hcontrol & ~CLEAR_ERROR,
hcr_base + HCONTROL);
/* Clear SError[E] bit */
sata_fsl_scr_write(&ap->link, SCR_ERROR,
SError);
/* Ignore fatal error and device error */
status_mask &= ~(INT_ON_SINGL_DEVICE_ERR
| INT_ON_FATAL_ERR);
break;
}
}
}
if (unlikely(SError & 0xFFFF0000)) {
DPRINTK("serror @host_intr : 0x%x\n", SError);
sata_fsl_error_intr(ap);
}
if (unlikely(hstatus & INT_ON_ERROR)) {
if (unlikely(hstatus & status_mask)) {
DPRINTK("error interrupt!!\n");
sata_fsl_error_intr(ap);
return;
}
/* Read command completed register */
done_mask = ioread32(hcr_base + CC);
VPRINTK("Status of all queues :\n");
VPRINTK("done_mask/CC = 0x%x, CA = 0x%x, CE=0x%x,CQ=0x%x,apqa=0x%x\n",
done_mask,

450
drivers/ata/sata_highbank.c Normal file
View file

@ -0,0 +1,450 @@
/*
* Calxeda Highbank AHCI SATA platform driver
* Copyright 2012 Calxeda, Inc.
*
* based on the AHCI SATA platform driver by Jeff Garzik and Anton Vorontsov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
*/
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/libata.h>
#include <linux/ahci_platform.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/export.h>
#include "ahci.h"
#define CPHY_MAP(dev, addr) ((((dev) & 0x1f) << 7) | (((addr) >> 9) & 0x7f))
#define CPHY_ADDR(addr) (((addr) & 0x1ff) << 2)
#define SERDES_CR_CTL 0x80a0
#define SERDES_CR_ADDR 0x80a1
#define SERDES_CR_DATA 0x80a2
#define CR_BUSY 0x0001
#define CR_START 0x0001
#define CR_WR_RDN 0x0002
#define CPHY_RX_INPUT_STS 0x2002
#define CPHY_SATA_OVERRIDE 0x4000
#define CPHY_OVERRIDE 0x2005
#define SPHY_LANE 0x100
#define SPHY_HALF_RATE 0x0001
#define CPHY_SATA_DPLL_MODE 0x0700
#define CPHY_SATA_DPLL_SHIFT 8
#define CPHY_SATA_DPLL_RESET (1 << 11)
#define CPHY_PHY_COUNT 6
#define CPHY_LANE_COUNT 4
#define CPHY_PORT_COUNT (CPHY_PHY_COUNT * CPHY_LANE_COUNT)
static DEFINE_SPINLOCK(cphy_lock);
/* Each of the 6 phys can have up to 4 sata ports attached to i. Map 0-based
* sata ports to their phys and then to their lanes within the phys
*/
struct phy_lane_info {
void __iomem *phy_base;
u8 lane_mapping;
u8 phy_devs;
};
static struct phy_lane_info port_data[CPHY_PORT_COUNT];
static u32 __combo_phy_reg_read(u8 sata_port, u32 addr)
{
u32 data;
u8 dev = port_data[sata_port].phy_devs;
spin_lock(&cphy_lock);
writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
data = readl(port_data[sata_port].phy_base + CPHY_ADDR(addr));
spin_unlock(&cphy_lock);
return data;
}
static void __combo_phy_reg_write(u8 sata_port, u32 addr, u32 data)
{
u8 dev = port_data[sata_port].phy_devs;
spin_lock(&cphy_lock);
writel(CPHY_MAP(dev, addr), port_data[sata_port].phy_base + 0x800);
writel(data, port_data[sata_port].phy_base + CPHY_ADDR(addr));
spin_unlock(&cphy_lock);
}
static void combo_phy_wait_for_ready(u8 sata_port)
{
while (__combo_phy_reg_read(sata_port, SERDES_CR_CTL) & CR_BUSY)
udelay(5);
}
static u32 combo_phy_read(u8 sata_port, u32 addr)
{
combo_phy_wait_for_ready(sata_port);
__combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
__combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_START);
combo_phy_wait_for_ready(sata_port);
return __combo_phy_reg_read(sata_port, SERDES_CR_DATA);
}
static void combo_phy_write(u8 sata_port, u32 addr, u32 data)
{
combo_phy_wait_for_ready(sata_port);
__combo_phy_reg_write(sata_port, SERDES_CR_ADDR, addr);
__combo_phy_reg_write(sata_port, SERDES_CR_DATA, data);
__combo_phy_reg_write(sata_port, SERDES_CR_CTL, CR_WR_RDN | CR_START);
}
static void highbank_cphy_disable_overrides(u8 sata_port)
{
u8 lane = port_data[sata_port].lane_mapping;
u32 tmp;
if (unlikely(port_data[sata_port].phy_base == NULL))
return;
tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
tmp &= ~CPHY_SATA_OVERRIDE;
combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
}
static void cphy_override_rx_mode(u8 sata_port, u32 val)
{
u8 lane = port_data[sata_port].lane_mapping;
u32 tmp;
tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS + lane * SPHY_LANE);
tmp &= ~CPHY_SATA_OVERRIDE;
combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
tmp |= CPHY_SATA_OVERRIDE;
combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
tmp &= ~CPHY_SATA_DPLL_MODE;
tmp |= val << CPHY_SATA_DPLL_SHIFT;
combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
tmp |= CPHY_SATA_DPLL_RESET;
combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
tmp &= ~CPHY_SATA_DPLL_RESET;
combo_phy_write(sata_port, CPHY_OVERRIDE + lane * SPHY_LANE, tmp);
msleep(15);
}
static void highbank_cphy_override_lane(u8 sata_port)
{
u8 lane = port_data[sata_port].lane_mapping;
u32 tmp, k = 0;
if (unlikely(port_data[sata_port].phy_base == NULL))
return;
do {
tmp = combo_phy_read(sata_port, CPHY_RX_INPUT_STS +
lane * SPHY_LANE);
} while ((tmp & SPHY_HALF_RATE) && (k++ < 1000));
cphy_override_rx_mode(sata_port, 3);
}
static int highbank_initialize_phys(struct device *dev, void __iomem *addr)
{
struct device_node *sata_node = dev->of_node;
int phy_count = 0, phy, port = 0;
void __iomem *cphy_base[CPHY_PHY_COUNT];
struct device_node *phy_nodes[CPHY_PHY_COUNT];
memset(port_data, 0, sizeof(struct phy_lane_info) * CPHY_PORT_COUNT);
memset(phy_nodes, 0, sizeof(struct device_node*) * CPHY_PHY_COUNT);
do {
u32 tmp;
struct of_phandle_args phy_data;
if (of_parse_phandle_with_args(sata_node,
"calxeda,port-phys", "#phy-cells",
port, &phy_data))
break;
for (phy = 0; phy < phy_count; phy++) {
if (phy_nodes[phy] == phy_data.np)
break;
}
if (phy_nodes[phy] == NULL) {
phy_nodes[phy] = phy_data.np;
cphy_base[phy] = of_iomap(phy_nodes[phy], 0);
if (cphy_base[phy] == NULL) {
return 0;
}
phy_count += 1;
}
port_data[port].lane_mapping = phy_data.args[0];
of_property_read_u32(phy_nodes[phy], "phydev", &tmp);
port_data[port].phy_devs = tmp;
port_data[port].phy_base = cphy_base[phy];
of_node_put(phy_data.np);
port += 1;
} while (port < CPHY_PORT_COUNT);
return 0;
}
static int ahci_highbank_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;
u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
struct ata_taskfile tf;
bool online;
u32 sstatus;
int rc;
int retry = 10;
ahci_stop_engine(ap);
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(link->device, &tf);
tf.command = 0x80;
ata_tf_to_fis(&tf, 0, 0, d2h_fis);
do {
highbank_cphy_disable_overrides(link->ap->port_no);
rc = sata_link_hardreset(link, timing, deadline, &online, NULL);
highbank_cphy_override_lane(link->ap->port_no);
/* If the status is 1, we are connected, but the link did not
* come up. So retry resetting the link again.
*/
if (sata_scr_read(link, SCR_STATUS, &sstatus))
break;
if (!(sstatus & 0x3))
break;
} while (!online && retry--);
ahci_start_engine(ap);
if (online)
*class = ahci_dev_classify(ap);
return rc;
}
static struct ata_port_operations ahci_highbank_ops = {
.inherits = &ahci_ops,
.hardreset = ahci_highbank_hardreset,
};
static const struct ata_port_info ahci_highbank_port_info = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_highbank_ops,
};
static struct scsi_host_template ahci_highbank_platform_sht = {
AHCI_SHT("highbank-ahci"),
};
static const struct of_device_id ahci_of_match[] = {
{ .compatible = "calxeda,hb-ahci" },
{},
};
MODULE_DEVICE_TABLE(of, ahci_of_match);
static int __init ahci_highbank_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ahci_host_priv *hpriv;
struct ata_host *host;
struct resource *mem;
int irq;
int n_ports;
int i;
int rc;
struct ata_port_info pi = ahci_highbank_port_info;
const struct ata_port_info *ppi[] = { &pi, NULL };
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(dev, "no mmio space\n");
return -EINVAL;
}
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(dev, "no irq\n");
return -EINVAL;
}
hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
if (!hpriv) {
dev_err(dev, "can't alloc ahci_host_priv\n");
return -ENOMEM;
}
hpriv->flags |= (unsigned long)pi.private_data;
hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
if (!hpriv->mmio) {
dev_err(dev, "can't map %pR\n", mem);
return -ENOMEM;
}
rc = highbank_initialize_phys(dev, hpriv->mmio);
if (rc)
return rc;
ahci_save_initial_config(dev, hpriv, 0, 0);
/* prepare host */
if (hpriv->cap & HOST_CAP_NCQ)
pi.flags |= ATA_FLAG_NCQ;
if (hpriv->cap & HOST_CAP_PMP)
pi.flags |= ATA_FLAG_PMP;
ahci_set_em_messages(hpriv, &pi);
/* CAP.NP sometimes indicate the index of the last enabled
* port, at other times, that of the last possible port, so
* determining the maximum port number requires looking at
* both CAP.NP and port_map.
*/
n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
host = ata_host_alloc_pinfo(dev, ppi, n_ports);
if (!host) {
rc = -ENOMEM;
goto err0;
}
host->private_data = hpriv;
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
host->flags |= ATA_HOST_PARALLEL_SCAN;
if (pi.flags & ATA_FLAG_EM)
ahci_reset_em(host);
for (i = 0; i < host->n_ports; i++) {
struct ata_port *ap = host->ports[i];
ata_port_desc(ap, "mmio %pR", mem);
ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
/* set enclosure management message type */
if (ap->flags & ATA_FLAG_EM)
ap->em_message_type = hpriv->em_msg_type;
/* disabled/not-implemented port */
if (!(hpriv->port_map & (1 << i)))
ap->ops = &ata_dummy_port_ops;
}
rc = ahci_reset_controller(host);
if (rc)
goto err0;
ahci_init_controller(host);
ahci_print_info(host, "platform");
rc = ata_host_activate(host, irq, ahci_interrupt, 0,
&ahci_highbank_platform_sht);
if (rc)
goto err0;
return 0;
err0:
return rc;
}
static int __devexit ahci_highbank_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct ata_host *host = dev_get_drvdata(dev);
ata_host_detach(host);
return 0;
}
#ifdef CONFIG_PM
static int ahci_highbank_suspend(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
struct ahci_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->mmio;
u32 ctl;
int rc;
if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
dev_err(dev, "firmware update required for suspend/resume\n");
return -EIO;
}
/*
* AHCI spec rev1.1 section 8.3.3:
* Software must disable interrupts prior to requesting a
* transition of the HBA to D3 state.
*/
ctl = readl(mmio + HOST_CTL);
ctl &= ~HOST_IRQ_EN;
writel(ctl, mmio + HOST_CTL);
readl(mmio + HOST_CTL); /* flush */
rc = ata_host_suspend(host, PMSG_SUSPEND);
if (rc)
return rc;
return 0;
}
static int ahci_highbank_resume(struct device *dev)
{
struct ata_host *host = dev_get_drvdata(dev);
int rc;
if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
rc = ahci_reset_controller(host);
if (rc)
return rc;
ahci_init_controller(host);
}
ata_host_resume(host);
return 0;
}
#endif
SIMPLE_DEV_PM_OPS(ahci_highbank_pm_ops,
ahci_highbank_suspend, ahci_highbank_resume);
static struct platform_driver ahci_highbank_driver = {
.remove = __devexit_p(ahci_highbank_remove),
.driver = {
.name = "highbank-ahci",
.owner = THIS_MODULE,
.of_match_table = ahci_of_match,
.pm = &ahci_highbank_pm_ops,
},
.probe = ahci_highbank_probe,
};
module_platform_driver(ahci_highbank_driver);
MODULE_DESCRIPTION("Calxeda Highbank AHCI SATA platform driver");
MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@calxeda.com>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("sata:highbank");

View file

@ -79,8 +79,8 @@
* module options
*/
static int msi;
#ifdef CONFIG_PCI
static int msi;
module_param(msi, int, S_IRUGO);
MODULE_PARM_DESC(msi, "Enable use of PCI MSI (0=off, 1=on)");
#endif
@ -652,12 +652,13 @@ static u8 mv_sff_check_status(struct ata_port *ap);
* because we have to allow room for worst case splitting of
* PRDs for 64K boundaries in mv_fill_sg().
*/
#ifdef CONFIG_PCI
static struct scsi_host_template mv5_sht = {
ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = MV_MAX_SG_CT / 2,
.dma_boundary = MV_DMA_BOUNDARY,
};
#endif
static struct scsi_host_template mv6_sht = {
ATA_NCQ_SHT(DRV_NAME),
.can_queue = MV_MAX_Q_DEPTH - 1,
@ -1252,7 +1253,7 @@ static void mv_dump_mem(void __iomem *start, unsigned bytes)
}
}
#endif
#if defined(ATA_DEBUG) || defined(CONFIG_PCI)
static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
{
#ifdef ATA_DEBUG
@ -1269,6 +1270,7 @@ static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
}
#endif
}
#endif
static void mv_dump_all_regs(void __iomem *mmio_base, int port,
struct pci_dev *pdev)
{

View file

@ -77,6 +77,9 @@ enum {
ATA_ID_EIDE_PIO_IORDY = 68,
ATA_ID_ADDITIONAL_SUPP = 69,
ATA_ID_QUEUE_DEPTH = 75,
ATA_ID_SATA_CAPABILITY = 76,
ATA_ID_SATA_CAPABILITY_2 = 77,
ATA_ID_FEATURE_SUPP = 78,
ATA_ID_MAJOR_VER = 80,
ATA_ID_COMMAND_SET_1 = 82,
ATA_ID_COMMAND_SET_2 = 83,
@ -292,6 +295,13 @@ enum {
/* READ_LOG_EXT pages */
ATA_LOG_SATA_NCQ = 0x10,
ATA_LOG_SATA_ID_DEV_DATA = 0x30,
ATA_LOG_SATA_SETTINGS = 0x08,
ATA_LOG_DEVSLP_MDAT = 0x30,
ATA_LOG_DEVSLP_MDAT_MASK = 0x1F,
ATA_LOG_DEVSLP_DETO = 0x31,
ATA_LOG_DEVSLP_VALID = 0x37,
ATA_LOG_DEVSLP_VALID_MASK = 0x80,
/* READ/WRITE LONG (obsolete) */
ATA_CMD_READ_LONG = 0x22,
@ -345,6 +355,7 @@ enum {
SATA_FPDMA_IN_ORDER = 0x04, /* FPDMA in-order data delivery */
SATA_AN = 0x05, /* Asynchronous Notification */
SATA_SSP = 0x06, /* Software Settings Preservation */
SATA_DEVSLP = 0x09, /* Device Sleep */
/* feature values for SET_MAX */
ATA_SET_MAX_ADDR = 0x00,
@ -558,15 +569,17 @@ static inline int ata_is_data(u8 prot)
#define ata_id_is_ata(id) (((id)[ATA_ID_CONFIG] & (1 << 15)) == 0)
#define ata_id_has_lba(id) ((id)[ATA_ID_CAPABILITY] & (1 << 9))
#define ata_id_has_dma(id) ((id)[ATA_ID_CAPABILITY] & (1 << 8))
#define ata_id_has_ncq(id) ((id)[76] & (1 << 8))
#define ata_id_has_ncq(id) ((id)[ATA_ID_SATA_CAPABILITY] & (1 << 8))
#define ata_id_queue_depth(id) (((id)[ATA_ID_QUEUE_DEPTH] & 0x1f) + 1)
#define ata_id_removeable(id) ((id)[ATA_ID_CONFIG] & (1 << 7))
#define ata_id_has_atapi_AN(id) \
( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
((id)[78] & (1 << 5)) )
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
((id)[ATA_ID_FEATURE_SUPP] & (1 << 5)))
#define ata_id_has_fpdma_aa(id) \
( (((id)[76] != 0x0000) && ((id)[76] != 0xffff)) && \
((id)[78] & (1 << 2)) )
((((id)[ATA_ID_SATA_CAPABILITY] != 0x0000) && \
((id)[ATA_ID_SATA_CAPABILITY] != 0xffff)) && \
((id)[ATA_ID_FEATURE_SUPP] & (1 << 2)))
#define ata_id_iordy_disable(id) ((id)[ATA_ID_CAPABILITY] & (1 << 10))
#define ata_id_has_iordy(id) ((id)[ATA_ID_CAPABILITY] & (1 << 11))
#define ata_id_u32(id,n) \
@ -578,11 +591,12 @@ static inline int ata_is_data(u8 prot)
((u64) (id)[(n) + 0]) )
#define ata_id_cdb_intr(id) (((id)[ATA_ID_CONFIG] & 0x60) == 0x20)
#define ata_id_has_da(id) ((id)[77] & (1 << 4))
#define ata_id_has_da(id) ((id)[ATA_ID_SATA_CAPABILITY_2] & (1 << 4))
#define ata_id_has_devslp(id) ((id)[ATA_ID_FEATURE_SUPP] & (1 << 8))
static inline bool ata_id_has_hipm(const u16 *id)
{
u16 val = id[76];
u16 val = id[ATA_ID_SATA_CAPABILITY];
if (val == 0 || val == 0xffff)
return false;
@ -592,7 +606,7 @@ static inline bool ata_id_has_hipm(const u16 *id)
static inline bool ata_id_has_dipm(const u16 *id)
{
u16 val = id[78];
u16 val = id[ATA_ID_FEATURE_SUPP];
if (val == 0 || val == 0xffff)
return false;

View file

@ -162,6 +162,7 @@ enum {
ATA_DFLAG_DETACHED = (1 << 25),
ATA_DFLAG_DA = (1 << 26), /* device supports Device Attention */
ATA_DFLAG_DEVSLP = (1 << 27), /* device supports Device Sleep */
ATA_DEV_UNKNOWN = 0, /* unknown device */
ATA_DEV_ATA = 1, /* ATA device */
@ -649,6 +650,9 @@ struct ata_device {
u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
};
/* Identify Device Data Log (30h), SATA Settings (page 08h) */
u8 sata_settings[ATA_SECT_SIZE];
/* error history */
int spdn_cnt;
/* ering is CLEAR_END, read comment above CLEAR_END */