summaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-02 18:23:35 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-02 18:23:35 -0700
commit51562cba98939da0a1d10fe7c25359b77a069033 (patch)
tree9c18b8ac63eab57a87cb19421734ce9843be30e6 /drivers/ata
parent7fe0b14b725d6d09a1d9e1409bd465cb88b587f9 (diff)
parent13b74085d92feda78bad1045516d332a1e9a3407 (diff)
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
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/Kconfig8
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.h16
-rw-r--r--drivers/ata/ahci_platform.c58
-rw-r--r--drivers/ata/libahci.c97
-rw-r--r--drivers/ata/libata-core.c32
-rw-r--r--drivers/ata/libata-eh.c12
-rw-r--r--drivers/ata/libata-scsi.c255
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--drivers/ata/pata_arasan_cf.c14
-rw-r--r--drivers/ata/sata_fsl.c39
-rw-r--r--drivers/ata/sata_highbank.c450
-rw-r--r--drivers/ata/sata_mv.c8
13 files changed, 940 insertions, 52 deletions
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 27cecd313e75..e08d322d01d7 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -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
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index a454a139b1d2..9329dafba91b 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -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
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 57eb1c212a4c..9be471200a07 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -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;
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 09728e09cb31..b1ae48054dc5 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -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", },
{},
};
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 555c07afa05b..4201e535a8c8 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -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 " : ""
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 8e1039c8e159..3492aa73d3a6 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -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
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 7d4535e989bf..26598941e1b3 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -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;
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 8ec81ca8f659..e3bda074fa12 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -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:
@@ -2205,9 +2205,33 @@ static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf)
}
/**
+ * 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 */
@@ -3080,6 +3107,188 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
}
/**
+ * 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
* @cmd: SCSI command opcode to consider
@@ -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;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 50e4dff0604e..7148a58020b9 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -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);
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index bfaa5cb1629a..26201ebef3ca 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -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),
},
};
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index d6577b93bee3..124b2c1d9c0b 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -123,6 +123,7 @@ enum {
ONLINE = (1 << 31),