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

Pull libata updates from Tejun Heo:

 - Christoph added support for TCG OPAL self encrypting disks

 - Minwoo added support for ATA PASS-THROUGH(32)

 - Linus Walleij removed spurious drvdata assignments in some drivers

 - Support for a few new device and other fixes

* 'for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata: (33 commits)
  sd: add support for TCG OPAL self encrypting disks
  libata: fix build warning from unused goto label
  libata: Support for an ATA PASS-THROUGH(32) command.
  ahci: Add Device ID for ASMedia 1061R and 1062R
  sata_via: Enable optional hotplug on VT6420
  ata: ahci_brcm: Avoid writing to read-only registers
  libata: Add the AHCI_HFLAG_NO_WRITE_TO_RO flag
  libata: Add the AHCI_HFLAG_YES_ALPM flag
  ata: ftide010: fix resource printing
  libata: make the function name in comment match the actual function
  ata: sata_rcar: make of_device_ids const.
  ata: pata_octeon_cf: make of_device_ids const.
  libata: Convert bare printks to pr_cont
  libahci: wrong comments in ahci_do_softreset()
  ata: declare ata_port_info structures as const
  ata: Add driver for Faraday Technology FTIDE010
  ata: Add DT bindings for the Gemini SATA bridge
  ata: Add DT bindings for Faraday Technology FTIDE010
  libata: implement SECURITY PROTOCOL IN/OUT
  libata: factor out a ata_identify_page_supported helper
  ...
This commit is contained in:
Linus Torvalds 2017-07-06 09:41:58 -07:00
commit 109a5db504
36 changed files with 1589 additions and 236 deletions

View File

@ -0,0 +1,55 @@
* Cortina Systems Gemini SATA Bridge
The Gemini SATA bridge in a SoC-internal PATA to SATA bridge that
takes two Faraday Technology FTIDE010 PATA controllers and bridges
them in different configurations to two SATA ports.
Required properties:
- compatible: should be
"cortina,gemini-sata-bridge"
- reg: registers and size for the block
- resets: phandles to the reset lines for both SATA bridges
- reset-names: must be "sata0", "sata1"
- clocks: phandles to the compulsory peripheral clocks
- clock-names: must be "SATA0_PCLK", "SATA1_PCLK"
- syscon: a phandle to the global Gemini system controller
- cortina,gemini-ata-muxmode: tell the desired multiplexing mode for
the ATA controller and SATA bridges. Values 0..3:
Mode 0: ata0 master <-> sata0
ata1 master <-> sata1
ata0 slave interface brought out on IDE pads
Mode 1: ata0 master <-> sata0
ata1 master <-> sata1
ata1 slave interface brought out on IDE pads
Mode 2: ata1 master <-> sata1
ata1 slave <-> sata0
ata0 master and slave interfaces brought out
on IDE pads
Mode 3: ata0 master <-> sata0
ata0 slave <-> sata1
ata1 master and slave interfaces brought out
on IDE pads
Optional boolean properties:
- cortina,gemini-enable-ide-pins: enables the PATA to IDE connection.
The muxmode setting decides whether ATA0 or ATA1 is brought out,
and whether master, slave or both interfaces get brought out.
- cortina,gemini-enable-sata-bridge: enables the PATA to SATA bridge
inside the Gemnini SoC. The Muxmode decides what PATA blocks will
be muxed out and how.
Example:
sata: sata@46000000 {
compatible = "cortina,gemini-sata-bridge";
reg = <0x46000000 0x100>;
resets = <&rcon 26>, <&rcon 27>;
reset-names = "sata0", "sata1";
clocks = <&gcc GEMINI_CLK_GATE_SATA0>,
<&gcc GEMINI_CLK_GATE_SATA1>;
clock-names = "SATA0_PCLK", "SATA1_PCLK";
syscon = <&syscon>;
cortina,gemini-ata-muxmode = <3>;
cortina,gemini-enable-ide-pins;
cortina,gemini-enable-sata-bridge;
};

View File

@ -0,0 +1,38 @@
* Faraday Technology FTIDE010 PATA controller
This controller is the first Faraday IDE interface block, used in the
StorLink SL2312 and SL3516, later known as the Cortina Systems Gemini
platform. The controller can do PIO modes 0 through 4, Multi-word DMA
(MWDM)modes 0 through 2 and Ultra DMA modes 0 through 6.
On the Gemini platform, this PATA block is accompanied by a PATA to
SATA bridge in order to support SATA. This is why a phandle to that
controller is compulsory on that platform.
The timing properties are unique per-SoC, not per-board.
Required properties:
- compatible: should be one of
"cortina,gemini-pata", "faraday,ftide010"
"faraday,ftide010"
- interrupts: interrupt for the block
- reg: registers and size for the block
Optional properties:
- clocks: a SoC clock running the peripheral.
- clock-names: should be set to "PCLK" for the peripheral clock.
Required properties for "cortina,gemini-pata" compatible:
- sata: a phande to the Gemini PATA to SATA bridge, see
cortina,gemini-sata-bridge.txt for details.
Example:
ata@63000000 {
compatible = "cortina,gemini-pata", "faraday,ftide010";
reg = <0x63000000 0x100>;
interrupts = <4 IRQ_TYPE_EDGE_RISING>;
clocks = <&gcc GEMINI_CLK_GATE_IDE>;
clock-names = "PCLK";
sata = <&sata>;
};

View File

@ -7593,6 +7593,15 @@ S: Maintained
F: drivers/ata/pata_*.c F: drivers/ata/pata_*.c
F: drivers/ata/ata_generic.c F: drivers/ata/ata_generic.c
LIBATA PATA FARADAY FTIDE010 AND GEMINI SATA BRIDGE DRIVERS
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-ide@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
S: Maintained
F: drivers/ata/pata_ftide010.c
F: drivers/ata/sata_gemini.c
F: drivers/ata/sata_gemini.h
LIBATA SATA AHCI PLATFORM devices support LIBATA SATA AHCI PLATFORM devices support
M: Hans de Goede <hdegoede@redhat.com> M: Hans de Goede <hdegoede@redhat.com>
M: Tejun Heo <tj@kernel.org> M: Tejun Heo <tj@kernel.org>

View File

@ -213,6 +213,16 @@ config SATA_FSL
If unsure, say N. If unsure, say N.
config SATA_GEMINI
tristate "Gemini SATA bridge support"
depends on PATA_FTIDE010
default ARCH_GEMINI
help
This enabled support for the FTIDE010 to SATA bridge
found in Cortina Systems Gemini platform.
If unsure, say N.
config SATA_AHCI_SEATTLE config SATA_AHCI_SEATTLE
tristate "AMD Seattle 6.0Gbps AHCI SATA host controller support" tristate "AMD Seattle 6.0Gbps AHCI SATA host controller support"
depends on ARCH_SEATTLE depends on ARCH_SEATTLE
@ -599,6 +609,17 @@ config PATA_EP93XX
If unsure, say N. If unsure, say N.
config PATA_FTIDE010
tristate "Faraday Technology FTIDE010 PATA support"
depends on OF
depends on ARM
default ARCH_GEMINI
help
This option enables support for the Faraday FTIDE010
PATA controller found in the Cortina Gemini SoCs.
If unsure, say N.
config PATA_HPT366 config PATA_HPT366
tristate "HPT 366/368 PATA support" tristate "HPT 366/368 PATA support"
depends on PCI depends on PCI

View File

@ -7,6 +7,7 @@ obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
obj-$(CONFIG_SATA_AHCI_SEATTLE) += ahci_seattle.o libahci.o libahci_platform.o obj-$(CONFIG_SATA_AHCI_SEATTLE) += ahci_seattle.o libahci.o libahci_platform.o
obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o
obj-$(CONFIG_SATA_FSL) += sata_fsl.o obj-$(CONFIG_SATA_FSL) += sata_fsl.o
obj-$(CONFIG_SATA_GEMINI) += sata_gemini.o
obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
obj-$(CONFIG_SATA_SIL24) += sata_sil24.o obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
@ -60,6 +61,7 @@ obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o
obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
obj-$(CONFIG_PATA_EFAR) += pata_efar.o obj-$(CONFIG_PATA_EFAR) += pata_efar.o
obj-$(CONFIG_PATA_EP93XX) += pata_ep93xx.o obj-$(CONFIG_PATA_EP93XX) += pata_ep93xx.o
obj-$(CONFIG_PATA_FTIDE010) += pata_ftide010.o
obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o

View File

@ -548,6 +548,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */ { PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */
{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */
{ PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */
{ PCI_VDEVICE(ASMEDIA, 0x0621), board_ahci }, /* ASM1061R */
{ PCI_VDEVICE(ASMEDIA, 0x0622), board_ahci }, /* ASM1062R */
/* /*
* Samsung SSDs found on some macbooks. NCQ times out if MSI is * Samsung SSDs found on some macbooks. NCQ times out if MSI is

View File

@ -248,6 +248,9 @@ enum {
AHCI_HFLAG_MULTI_MSI = 0, AHCI_HFLAG_MULTI_MSI = 0,
#endif #endif
AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */ AHCI_HFLAG_WAKE_BEFORE_STOP = (1 << 22), /* wake before DMA stop */
AHCI_HFLAG_YES_ALPM = (1 << 23), /* force ALPM cap on */
AHCI_HFLAG_NO_WRITE_TO_RO = (1 << 24), /* don't write to read
only registers */
/* ap->flags bits */ /* ap->flags bits */

View File

@ -39,7 +39,6 @@
#define PIODATA_ENDIAN_SHIFT 6 #define PIODATA_ENDIAN_SHIFT 6
#define ENDIAN_SWAP_NONE 0 #define ENDIAN_SWAP_NONE 0
#define ENDIAN_SWAP_FULL 2 #define ENDIAN_SWAP_FULL 2
#define OVERRIDE_HWINIT BIT(16)
#define SATA_TOP_CTRL_TP_CTRL 0x8 #define SATA_TOP_CTRL_TP_CTRL 0x8
#define SATA_TOP_CTRL_PHY_CTRL 0xc #define SATA_TOP_CTRL_PHY_CTRL 0xc
#define SATA_TOP_CTRL_PHY_CTRL_1 0x0 #define SATA_TOP_CTRL_PHY_CTRL_1 0x0
@ -126,17 +125,13 @@ static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv) static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv)
{ {
struct brcm_ahci_priv *priv = hpriv->plat_data; struct brcm_ahci_priv *priv = hpriv->plat_data;
u32 bus_ctrl, port_ctrl, host_caps; u32 port_ctrl, host_caps;
int i; int i;
/* Enable support for ALPM */ /* Enable support for ALPM */
bus_ctrl = brcm_sata_readreg(priv->top_ctrl +
SATA_TOP_CTRL_BUS_CTRL);
brcm_sata_writereg(bus_ctrl | OVERRIDE_HWINIT,
priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
host_caps = readl(hpriv->mmio + HOST_CAP); host_caps = readl(hpriv->mmio + HOST_CAP);
writel(host_caps | HOST_CAP_ALPM, hpriv->mmio); if (!(host_caps & HOST_CAP_ALPM))
brcm_sata_writereg(bus_ctrl, priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL); hpriv->flags |= AHCI_HFLAG_YES_ALPM;
/* /*
* Adjust timeout to allow PLL sufficient time to lock while waking * Adjust timeout to allow PLL sufficient time to lock while waking
@ -360,6 +355,7 @@ static int brcm_ahci_probe(struct platform_device *pdev)
if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ) if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ)
hpriv->flags |= AHCI_HFLAG_NO_NCQ; hpriv->flags |= AHCI_HFLAG_NO_NCQ;
hpriv->flags |= AHCI_HFLAG_NO_WRITE_TO_RO;
ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info, ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
&ahci_platform_sht); &ahci_platform_sht);

View File

@ -47,12 +47,14 @@
#define SATA_ECC_DISABLE 0x00020000 #define SATA_ECC_DISABLE 0x00020000
#define ECC_DIS_ARMV8_CH2 0x80000000 #define ECC_DIS_ARMV8_CH2 0x80000000
#define ECC_DIS_LS1088A 0x40000000
enum ahci_qoriq_type { enum ahci_qoriq_type {
AHCI_LS1021A, AHCI_LS1021A,
AHCI_LS1043A, AHCI_LS1043A,
AHCI_LS2080A, AHCI_LS2080A,
AHCI_LS1046A, AHCI_LS1046A,
AHCI_LS1088A,
AHCI_LS2088A, AHCI_LS2088A,
}; };
@ -68,6 +70,7 @@ static const struct of_device_id ahci_qoriq_of_match[] = {
{ .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A}, { .compatible = "fsl,ls1043a-ahci", .data = (void *)AHCI_LS1043A},
{ .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A}, { .compatible = "fsl,ls2080a-ahci", .data = (void *)AHCI_LS2080A},
{ .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A}, { .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A},
{ .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A},
{ .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A}, { .compatible = "fsl,ls2088a-ahci", .data = (void *)AHCI_LS2088A},
{}, {},
}; };
@ -203,6 +206,17 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC); writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
break; break;
case AHCI_LS1088A:
if (!qpriv->ecc_addr)
return -EINVAL;
writel(readl(qpriv->ecc_addr) | ECC_DIS_LS1088A,
qpriv->ecc_addr);
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
if (qpriv->is_dmacoherent)
writel(AHCI_PORT_AXICC_CFG, reg_base + PORT_AXICC);
break;
case AHCI_LS2088A: case AHCI_LS2088A:
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1); writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS); writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);

View File

@ -504,6 +504,11 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
cap &= ~HOST_CAP_FBS; cap &= ~HOST_CAP_FBS;
} }
if (!(cap & HOST_CAP_ALPM) && (hpriv->flags & AHCI_HFLAG_YES_ALPM)) {
dev_info(dev, "controller can do ALPM, turning on CAP_ALPM\n");
cap |= HOST_CAP_ALPM;
}
if (hpriv->force_port_map && port_map != hpriv->force_port_map) { if (hpriv->force_port_map && port_map != hpriv->force_port_map) {
dev_info(dev, "forcing port_map 0x%x -> 0x%x\n", dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
port_map, hpriv->force_port_map); port_map, hpriv->force_port_map);
@ -940,7 +945,8 @@ int ahci_reset_controller(struct ata_host *host)
/* Some registers might be cleared on reset. Restore /* Some registers might be cleared on reset. Restore
* initial values. * initial values.
*/ */
ahci_restore_initial_config(host); if (!(hpriv->flags & AHCI_HFLAG_NO_WRITE_TO_RO))
ahci_restore_initial_config(host);
} else } else
dev_info(host->dev, "skipping global host reset\n"); dev_info(host->dev, "skipping global host reset\n");
@ -1400,7 +1406,7 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
ata_tf_init(link->device, &tf); ata_tf_init(link->device, &tf);
/* issue the first D2H Register FIS */ /* issue the first H2D Register FIS */
msecs = 0; msecs = 0;
now = jiffies; now = jiffies;
if (time_after(deadline, now)) if (time_after(deadline, now))
@ -1417,7 +1423,7 @@ int ahci_do_softreset(struct ata_link *link, unsigned int *class,
/* spec says at least 5us, but be generous and sleep for 1ms */ /* spec says at least 5us, but be generous and sleep for 1ms */
ata_msleep(ap, 1); ata_msleep(ap, 1);
/* issue the second D2H Register FIS */ /* issue the second H2D Register FIS */
tf.ctl &= ~ATA_SRST; tf.ctl &= ~ATA_SRST;
ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0); ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);

View File

@ -2047,6 +2047,110 @@ retry:
return rc; return rc;
} }
/**
* 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
*
* Read log page using READ_LOG_EXT command.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, AC_ERR_* mask otherwise.
*/
unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
u8 page, void *buf, unsigned int sectors)
{
unsigned long ap_flags = dev->link->ap->flags;
struct ata_taskfile tf;
unsigned int err_mask;
bool dma = false;
DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
/*
* Return error without actually issuing the command on controllers
* which e.g. lockup on a read log page.
*/
if (ap_flags & ATA_FLAG_NO_LOG_PAGE)
return AC_ERR_DEV;
retry:
ata_tf_init(dev, &tf);
if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
!(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) {
tf.command = ATA_CMD_READ_LOG_DMA_EXT;
tf.protocol = ATA_PROT_DMA;
dma = true;
} else {
tf.command = ATA_CMD_READ_LOG_EXT;
tf.protocol = ATA_PROT_PIO;
dma = false;
}
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;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
buf, sectors * ATA_SECT_SIZE, 0);
if (err_mask && dma) {
dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG;
ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n");
goto retry;
}
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
}
static bool ata_log_supported(struct ata_device *dev, u8 log)
{
struct ata_port *ap = dev->link->ap;
if (ata_read_log_page(dev, ATA_LOG_DIRECTORY, 0, ap->sector_buf, 1))
return false;
return get_unaligned_le16(&ap->sector_buf[log * 2]) ? true : false;
}
static bool ata_identify_page_supported(struct ata_device *dev, u8 page)
{
struct ata_port *ap = dev->link->ap;
unsigned int err, i;
if (!ata_log_supported(dev, ATA_LOG_IDENTIFY_DEVICE)) {
ata_dev_warn(dev, "ATA Identify Device Log not supported\n");
return false;
}
/*
* Read IDENTIFY DEVICE data log, page 0, to figure out if the page is
* supported.
*/
err = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, 0, ap->sector_buf,
1);
if (err) {
ata_dev_info(dev,
"failed to get Device Identify Log Emask 0x%x\n",
err);
return false;
}
for (i = 0; i < ap->sector_buf[8]; i++) {
if (ap->sector_buf[9 + i] == page)
return true;
}
return false;
}
static int ata_do_link_spd_horkage(struct ata_device *dev) static int ata_do_link_spd_horkage(struct ata_device *dev)
{ {
struct ata_link *plink = ata_dev_phys_link(dev); struct ata_link *plink = ata_dev_phys_link(dev);
@ -2094,21 +2198,9 @@ static void ata_dev_config_ncq_send_recv(struct ata_device *dev)
{ {
struct ata_port *ap = dev->link->ap; struct ata_port *ap = dev->link->ap;
unsigned int err_mask; unsigned int err_mask;
int log_index = ATA_LOG_NCQ_SEND_RECV * 2;
u16 log_pages;
err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY, if (!ata_log_supported(dev, ATA_LOG_NCQ_SEND_RECV)) {
0, ap->sector_buf, 1); ata_dev_warn(dev, "NCQ Send/Recv Log not supported\n");
if (err_mask) {
ata_dev_dbg(dev,
"failed to get Log Directory Emask 0x%x\n",
err_mask);
return;
}
log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
if (!log_pages) {
ata_dev_warn(dev,
"NCQ Send/Recv Log not supported\n");
return; return;
} }
err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV, err_mask = ata_read_log_page(dev, ATA_LOG_NCQ_SEND_RECV,
@ -2135,19 +2227,8 @@ static void ata_dev_config_ncq_non_data(struct ata_device *dev)
{ {
struct ata_port *ap = dev->link->ap; struct ata_port *ap = dev->link->ap;
unsigned int err_mask; unsigned int err_mask;
int log_index = ATA_LOG_NCQ_NON_DATA * 2;
u16 log_pages;
err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY, if (!ata_log_supported(dev, ATA_LOG_NCQ_NON_DATA)) {
0, ap->sector_buf, 1);
if (err_mask) {
ata_dev_dbg(dev,
"failed to get Log Directory Emask 0x%x\n",
err_mask);
return;
}
log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
if (!log_pages) {
ata_dev_warn(dev, ata_dev_warn(dev,
"NCQ Send/Recv Log not supported\n"); "NCQ Send/Recv Log not supported\n");
return; return;
@ -2176,7 +2257,7 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev)
} }
err_mask = ata_read_log_page(dev, err_mask = ata_read_log_page(dev,
ATA_LOG_SATA_ID_DEV_DATA, ATA_LOG_IDENTIFY_DEVICE,
ATA_LOG_SATA_SETTINGS, ATA_LOG_SATA_SETTINGS,
ap->sector_buf, ap->sector_buf,
1); 1);
@ -2275,8 +2356,6 @@ static void ata_dev_config_zac(struct ata_device *dev)
struct ata_port *ap = dev->link->ap; struct ata_port *ap = dev->link->ap;
unsigned int err_mask; unsigned int err_mask;
u8 *identify_buf = ap->sector_buf; u8 *identify_buf = ap->sector_buf;
int log_index = ATA_LOG_SATA_ID_DEV_DATA * 2, i, found = 0;
u16 log_pages;
dev->zac_zones_optimal_open = U32_MAX; dev->zac_zones_optimal_open = U32_MAX;
dev->zac_zones_optimal_nonseq = U32_MAX; dev->zac_zones_optimal_nonseq = U32_MAX;
@ -2296,44 +2375,7 @@ static void ata_dev_config_zac(struct ata_device *dev)
if (!(dev->flags & ATA_DFLAG_ZAC)) if (!(dev->flags & ATA_DFLAG_ZAC))
return; return;
/* if (!ata_identify_page_supported(dev, ATA_LOG_ZONED_INFORMATION)) {
* Read Log Directory to figure out if IDENTIFY DEVICE log
* is supported.
*/
err_mask = ata_read_log_page(dev, ATA_LOG_DIRECTORY,
0, ap->sector_buf, 1);
if (err_mask) {
ata_dev_info(dev,
"failed to get Log Directory Emask 0x%x\n",
err_mask);
return;
}
log_pages = get_unaligned_le16(&ap->sector_buf[log_index]);
if (log_pages == 0) {
ata_dev_warn(dev,
"ATA Identify Device Log not supported\n");
return;
}
/*
* Read IDENTIFY DEVICE data log, page 0, to figure out
* if page 9 is supported.
*/
err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA, 0,
identify_buf, 1);
if (err_mask) {
ata_dev_info(dev,
"failed to get Device Identify Log Emask 0x%x\n",
err_mask);
return;
}
log_pages = identify_buf[8];
for (i = 0; i < log_pages; i++) {
if (identify_buf[9 + i] == ATA_LOG_ZONED_INFORMATION) {
found++;
break;
}
}
if (!found) {
ata_dev_warn(dev, ata_dev_warn(dev,
"ATA Zoned Information Log not supported\n"); "ATA Zoned Information Log not supported\n");
return; return;
@ -2342,7 +2384,7 @@ static void ata_dev_config_zac(struct ata_device *dev)
/* /*
* Read IDENTIFY DEVICE data log, page 9 (Zoned-device information) * Read IDENTIFY DEVICE data log, page 9 (Zoned-device information)
*/ */
err_mask = ata_read_log_page(dev, ATA_LOG_SATA_ID_DEV_DATA, err_mask = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE,
ATA_LOG_ZONED_INFORMATION, ATA_LOG_ZONED_INFORMATION,
identify_buf, 1); identify_buf, 1);
if (!err_mask) { if (!err_mask) {
@ -2363,6 +2405,37 @@ static void ata_dev_config_zac(struct ata_device *dev)
} }
} }
static void ata_dev_config_trusted(struct ata_device *dev)
{
struct ata_port *ap = dev->link->ap;
u64 trusted_cap;
unsigned int err;
if (!ata_identify_page_supported(dev, ATA_LOG_SECURITY)) {
ata_dev_warn(dev,
"Security Log not supported\n");
return;
}
err = ata_read_log_page(dev, ATA_LOG_IDENTIFY_DEVICE, ATA_LOG_SECURITY,
ap->sector_buf, 1);
if (err) {
ata_dev_dbg(dev,
"failed to read Security Log, Emask 0x%x\n", err);
return;
}
trusted_cap = get_unaligned_le64(&ap->sector_buf[40]);
if (!(trusted_cap & (1ULL << 63))) {
ata_dev_dbg(dev,
"Trusted Computing capability qword not valid!\n");
return;
}
if (trusted_cap & (1 << 0))
dev->flags |= ATA_DFLAG_TRUSTED;
}
/** /**
* ata_dev_configure - Configure the specified ATA/ATAPI device * ata_dev_configure - Configure the specified ATA/ATAPI device
* @dev: Target device to configure * @dev: Target device to configure
@ -2571,7 +2644,7 @@ int ata_dev_configure(struct ata_device *dev)
dev->flags |= ATA_DFLAG_DEVSLP; dev->flags |= ATA_DFLAG_DEVSLP;
err_mask = ata_read_log_page(dev, err_mask = ata_read_log_page(dev,
ATA_LOG_SATA_ID_DEV_DATA, ATA_LOG_IDENTIFY_DEVICE,
ATA_LOG_SATA_SETTINGS, ATA_LOG_SATA_SETTINGS,
sata_setting, sata_setting,
1); 1);
@ -2587,7 +2660,8 @@ int ata_dev_configure(struct ata_device *dev)
} }
ata_dev_config_sense_reporting(dev); ata_dev_config_sense_reporting(dev);
ata_dev_config_zac(dev); ata_dev_config_zac(dev);
dev->cdb_len = 16; ata_dev_config_trusted(dev);
dev->cdb_len = 32;
} }
/* ATAPI-specific feature tests */ /* ATAPI-specific feature tests */

View File

@ -1487,70 +1487,6 @@ static const char *ata_err_string(unsigned int err_mask)
return "unknown error"; return "unknown error";
} }
/**
* 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
*
* Read log page using READ_LOG_EXT command.
*
* LOCKING:
* Kernel thread context (may sleep).
*
* RETURNS:
* 0 on success, AC_ERR_* mask otherwise.
*/
unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
u8 page, void *buf, unsigned int sectors)
{
unsigned long ap_flags = dev->link->ap->flags;
struct ata_taskfile tf;
unsigned int err_mask;
bool dma = false;
DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
/*
* Return error without actually issuing the command on controllers
* which e.g. lockup on a read log page.
*/
if (ap_flags & ATA_FLAG_NO_LOG_PAGE)
return AC_ERR_DEV;
retry:
ata_tf_init(dev, &tf);
if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
!(dev->horkage & ATA_HORKAGE_NO_NCQ_LOG)) {
tf.command = ATA_CMD_READ_LOG_DMA_EXT;
tf.protocol = ATA_PROT_DMA;
dma = true;
} else {
tf.command = ATA_CMD_READ_LOG_EXT;
tf.protocol = ATA_PROT_PIO;
dma = false;
}
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;
err_mask = ata_exec_internal(dev, &tf, NULL, DMA_FROM_DEVICE,
buf, sectors * ATA_SECT_SIZE, 0);
if (err_mask && dma) {
dev->horkage |= ATA_HORKAGE_NO_NCQ_LOG;
ata_dev_warn(dev, "READ LOG DMA EXT failed, trying unqueued\n");
goto retry;
}
DPRINTK("EXIT, err_mask=%x\n", err_mask);
return err_mask;
}
/** /**
* ata_eh_read_log_10h - Read log page 10h for NCQ error details * ata_eh_read_log_10h - Read log page 10h for NCQ error details
* @dev: Device to read log page 10h from * @dev: Device to read log page 10h from

View File

@ -903,32 +903,32 @@ static void ata_dump_status(unsigned id, struct ata_taskfile *tf)
{ {
u8 stat = tf->command, err = tf->feature; u8 stat = tf->command, err = tf->feature;
printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat); pr_warn("ata%u: status=0x%02x { ", id, stat);
if (stat & ATA_BUSY) { if (stat & ATA_BUSY) {
printk("Busy }\n"); /* Data is not valid in this case */ pr_cont("Busy }\n"); /* Data is not valid in this case */
} else { } else {
if (stat & ATA_DRDY) printk("DriveReady "); if (stat & ATA_DRDY) pr_cont("DriveReady ");
if (stat & ATA_DF) printk("DeviceFault "); if (stat & ATA_DF) pr_cont("DeviceFault ");
if (stat & ATA_DSC) printk("SeekComplete "); if (stat & ATA_DSC) pr_cont("SeekComplete ");
if (stat & ATA_DRQ) printk("DataRequest "); if (stat & ATA_DRQ) pr_cont("DataRequest ");
if (stat & ATA_CORR) printk("CorrectedError "); if (stat & ATA_CORR) pr_cont("CorrectedError ");
if (stat & ATA_SENSE) printk("Sense "); if (stat & ATA_SENSE) pr_cont("Sense ");
if (stat & ATA_ERR) printk("Error "); if (stat & ATA_ERR) pr_cont("Error ");
printk("}\n"); pr_cont("}\n");
if (err) { if (err) {
printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err); pr_warn("ata%u: error=0x%02x { ", id, err);
if (err & ATA_ABORTED) printk("DriveStatusError "); if (err & ATA_ABORTED) pr_cont("DriveStatusError ");
if (err & ATA_ICRC) { if (err & ATA_ICRC) {
if (err & ATA_ABORTED) if (err & ATA_ABORTED)
printk("BadCRC "); pr_cont("BadCRC ");
else printk("Sector "); else pr_cont("Sector ");
} }
if (err & ATA_UNC) printk("UncorrectableError "); if (err & ATA_UNC) pr_cont("UncorrectableError ");
if (err & ATA_IDNF) printk("SectorIdNotFound "); if (err & ATA_IDNF) pr_cont("SectorIdNotFound ");
if (err & ATA_TRK0NF) printk("TrackZeroNotFound "); if (err & ATA_TRK0NF) pr_cont("TrackZeroNotFound ");
if (err & ATA_AMNF) printk("AddrMarkNotFound "); if (err & ATA_AMNF) pr_cont("AddrMarkNotFound ");
printk("}\n"); pr_cont("}\n");
} }
} }
} }
@ -1059,8 +1059,7 @@ static void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk,
translate_done: translate_done:
if (verbose) if (verbose)
printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x " pr_err("ata%u: translated ATA stat/err 0x%02x/%02x to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
"to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
id, drv_stat, drv_err, *sk, *asc, *ascq); id, drv_stat, drv_err, *sk, *asc, *ascq);
return; return;
} }
@ -1322,6 +1321,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
blk_queue_flush_queueable(q, false); blk_queue_flush_queueable(q, false);
if (dev->flags & ATA_DFLAG_TRUSTED)
sdev->security_supported = 1;
dev->sdev = sdev; dev->sdev = sdev;
return 0; return 0;
} }
@ -3127,7 +3129,7 @@ ata_scsi_map_proto(u8 byte1)
* ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
* @qc: command structure to be initialized * @qc: command structure to be initialized
* *
* Handles either 12 or 16-byte versions of the CDB. * Handles either 12, 16, or 32-byte versions of the CDB.
* *
* RETURNS: * RETURNS:
* Zero on success, non-zero on failure. * Zero on success, non-zero on failure.
@ -3139,13 +3141,19 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
struct ata_device *dev = qc->dev; struct ata_device *dev = qc->dev;
const u8 *cdb = scmd->cmnd; const u8 *cdb = scmd->cmnd;
u16 fp; u16 fp;
u16 cdb_offset = 0;
if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN) { /* 7Fh variable length cmd means a ata pass-thru(32) */
if (cdb[0] == VARIABLE_LENGTH_CMD)
cdb_offset = 9;
tf->protocol = ata_scsi_map_proto(cdb[1 + cdb_offset]);
if (tf->protocol == ATA_PROT_UNKNOWN) {
fp = 1; fp = 1;
goto invalid_fld; goto invalid_fld;
} }
if (ata_is_ncq(tf->protocol) && (cdb[2] & 0x3) == 0) if (ata_is_ncq(tf->protocol) && (cdb[2 + cdb_offset] & 0x3) == 0)
tf->protocol = ATA_PROT_NCQ_NODATA; tf->protocol = ATA_PROT_NCQ_NODATA;
/* enable LBA */ /* enable LBA */
@ -3181,7 +3189,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
tf->lbah = cdb[12]; tf->lbah = cdb[12];
tf->device = cdb[13]; tf->device = cdb[13];
tf->command = cdb[14]; tf->command = cdb[14];
} else { } else if (cdb[0] == ATA_12) {
/* /*
* 12-byte CDB - incapable of extended commands. * 12-byte CDB - incapable of extended commands.
*/ */
@ -3194,6 +3202,30 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
tf->lbah = cdb[7]; tf->lbah = cdb[7];
tf->device = cdb[8]; tf->device = cdb[8];
tf->command = cdb[9]; tf->command = cdb[9];
} else {
/*
* 32-byte CDB - may contain extended command fields.
*
* If that is the case, copy the upper byte register values.
*/
if (cdb[10] & 0x01) {
tf->hob_feature = cdb[20];
tf->hob_nsect = cdb[22];
tf->hob_lbal = cdb[16];
tf->hob_lbam = cdb[15];
tf->hob_lbah = cdb[14];
tf->flags |= ATA_TFLAG_LBA48;
} else
tf->flags &= ~ATA_TFLAG_LBA48;
tf->feature = cdb[21];
tf->nsect = cdb[23];
tf->lbal = cdb[19];
tf->lbam = cdb[18];
tf->lbah = cdb[17];
tf->device = cdb[24];
tf->command = cdb[25];
tf->auxiliary = get_unaligned_be32(&cdb[28]);
} }
/* For NCQ commands copy the tag value */ /* For NCQ commands copy the tag value */
@ -3564,6 +3596,11 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
dev->class == ATA_DEV_ZAC) dev->class == ATA_DEV_ZAC)
supported = 3; supported = 3;
break; break;
case SECURITY_PROTOCOL_IN:
case SECURITY_PROTOCOL_OUT:
if (dev->flags & ATA_DFLAG_TRUSTED)
supported = 3;
break;
default: default:
break; break;
} }
@ -3910,7 +3947,7 @@ static int ata_mselect_control(struct ata_queued_cmd *qc,
} }
/** /**
* ata_scsiop_mode_select - Simulate MODE SELECT 6, 10 commands * ata_scsi_mode_select_xlat - Simulate MODE SELECT 6, 10 commands
* @qc: Storage for translated ATA taskfile * @qc: Storage for translated ATA taskfile
* *
* Converts a MODE SELECT command to an ATA SET FEATURES taskfile. * Converts a MODE SELECT command to an ATA SET FEATURES taskfile.
@ -4068,6 +4105,99 @@ static unsigned int ata_scsi_mode_select_xlat(struct ata_queued_cmd *qc)
return 1; return 1;
} }
static u8 ata_scsi_trusted_op(u32 len, bool send, bool dma)
{
if (len == 0)
return ATA_CMD_TRUSTED_NONDATA;
else if (send)
return dma ? ATA_CMD_TRUSTED_SND_DMA : ATA_CMD_TRUSTED_SND;
else
return dma ? ATA_CMD_TRUSTED_RCV_DMA : ATA_CMD_TRUSTED_RCV;
}
static unsigned int ata_scsi_security_inout_xlat(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *scmd = qc->scsicmd;
const u8 *cdb = scmd->cmnd;
struct ata_taskfile *tf = &qc->tf;
u8 secp = cdb[1];
bool send = (cdb[0] == SECURITY_PROTOCOL_OUT);
u16 spsp = get_unaligned_be16(&cdb[2]);
u32 len = get_unaligned_be32(&cdb[6]);
bool dma = !(qc->dev->flags & ATA_DFLAG_PIO);
/*
* We don't support the ATA "security" protocol.
*/
if (secp == 0xef) {
ata_scsi_set_invalid_field(qc->dev, scmd, 1, 0);
return 1;
}
if (cdb[4] & 7) { /* INC_512 */
if (len > 0xffff) {
ata_scsi_set_invalid_field(qc->dev, scmd, 6, 0);
return 1;
}
} else {
if (len > 0x01fffe00) {
ata_scsi_set_invalid_field(qc->dev, scmd, 6, 0);
return 1;
}
/* convert to the sector-based ATA addressing */
len = (len + 511) / 512;
}
tf->protocol = dma ? ATA_PROT_DMA : ATA_PROT_PIO;
tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR | ATA_TFLAG_LBA;
if (send)
tf->flags |= ATA_TFLAG_WRITE;
tf->command = ata_scsi_trusted_op(len, send, dma);
tf->feature = secp;
tf->lbam = spsp & 0xff;
tf->lbah = spsp >> 8;
if (len) {
tf->nsect = len & 0xff;
tf->lbal = len >> 8;
} else {
if (!send)
tf->lbah = (1 << 7);
}
ata_qc_set_pc_nbytes(qc);
return 0;
}
/**
* ata_scsi_var_len_cdb_xlat - SATL variable length CDB to Handler
* @qc: Command to be translated
*
* Translate a SCSI variable length CDB to specified commands.
* It checks a service action value in CDB to call corresponding handler.
*
* RETURNS:
* Zero on success, non-zero on failure
*
*/
static unsigned int ata_scsi_var_len_cdb_xlat(struct ata_queued_cmd *qc)
{
struct scsi_cmnd *scmd = qc->scsicmd;
const u8 *cdb = scmd->cmnd;
const u16 sa = get_unaligned_be16(&cdb[8]);
/*
* if service action represents a ata pass-thru(32) command,
* then pass it to ata_scsi_pass_thru handler.
*/
if (sa == ATA_32)
return ata_scsi_pass_thru(qc);
/* unsupported service action */
return 1;
}
/** /**
* ata_get_xlat_func - check if SCSI to ATA translation is possible * ata_get_xlat_func - check if SCSI to ATA translation is possible
* @dev: ATA device * @dev: ATA device
@ -4108,6 +4238,9 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
case ATA_16: case ATA_16:
return ata_scsi_pass_thru; return ata_scsi_pass_thru;
case VARIABLE_LENGTH_CMD:
return ata_scsi_var_len_cdb_xlat;
case MODE_SELECT: case MODE_SELECT:
case MODE_SELECT_10: case MODE_SELECT_10:
return ata_scsi_mode_select_xlat; return ata_scsi_mode_select_xlat;
@ -4119,6 +4252,12 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
case ZBC_OUT: case ZBC_OUT:
return ata_scsi_zbc_out_xlat; return ata_scsi_zbc_out_xlat;
case SECURITY_PROTOCOL_IN:
case SECURITY_PROTOCOL_OUT:
if (!(dev->flags & ATA_DFLAG_TRUSTED))
break;
return ata_scsi_security_inout_xlat;
case START_STOP: case START_STOP:
return ata_scsi_start_stop_xlat; return ata_scsi_start_stop_xlat;
} }
@ -4386,7 +4525,7 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
shost->max_id = 16; shost->max_id = 16;
shost->max_lun = 1; shost->max_lun = 1;
shost->max_channel = 1; shost->max_channel = 1;
shost->max_cmd_len = 16; shost->max_cmd_len = 32;
/* Schedule policy is determined by ->qc_defer() /* Schedule policy is determined by ->qc_defer()
* callback and it needs to see every deferred qc. * callback and it needs to see every deferred qc.

View File

@ -716,24 +716,10 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
if (PageHighMem(page)) { /* do the actual data transfer */
unsigned long flags; buf = kmap_atomic(page);
ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size, do_write);
/* FIXME: use a bounce buffer */ kunmap_atomic(buf);
local_irq_save(flags);
buf = kmap_atomic(page);
/* do the actual data transfer */
ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size,
do_write);
kunmap_atomic(buf);
local_irq_restore(flags);
} else {
buf = page_address(page);
ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size,
do_write);
}
if (!do_write && !PageSlab(page)) if (!do_write && !PageSlab(page))
flush_dcache_page(page); flush_dcache_page(page);
@ -861,24 +847,10 @@ next_sg:
DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read"); DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
if (PageHighMem(page)) { /* do the actual data transfer */
unsigned long flags; buf = kmap_atomic(page);
consumed = ap->ops->sff_data_xfer(qc, buf + offset, count, rw);
/* FIXME: use bounce buffer */ kunmap_atomic(buf);
local_irq_save(flags);
buf = kmap_atomic(page);
/* do the actual data transfer */
consumed = ap->ops->sff_data_xfer(qc, buf + offset,
count, rw);
kunmap_atomic(buf);
local_irq_restore(flags);
} else {
buf = page_address(page);
consumed = ap->ops->sff_data_xfer(qc, buf + offset,
count, rw);
}
bytes -= min(bytes, consumed); bytes -= min(bytes, consumed);
qc->curbytes += count; qc->curbytes += count;

View File

@ -98,6 +98,8 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host);
extern const char *sata_spd_string(unsigned int spd); extern const char *sata_spd_string(unsigned int spd);
extern int ata_port_probe(struct ata_port *ap); extern int ata_port_probe(struct ata_port *ap);
extern void __ata_port_probe(struct ata_port *ap); extern void __ata_port_probe(struct ata_port *ap);
extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
u8 page, void *buf, unsigned int sectors);
#define to_ata_port(d) container_of(d, struct ata_port, tdev) #define to_ata_port(d) container_of(d, struct ata_port, tdev)
@ -160,8 +162,6 @@ extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
unsigned int action); unsigned int action);
extern void ata_eh_done(struct ata_link *link, struct ata_device *dev, extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
unsigned int action); 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); extern void ata_eh_autopsy(struct ata_port *ap);
const char *ata_get_cmd_descript(u8 command); const char *ata_get_cmd_descript(u8 command);
extern void ata_eh_report(struct ata_port *ap); extern void ata_eh_report(struct ata_port *ap);

View File

@ -1597,8 +1597,6 @@ static int bfin_atapi_probe(struct platform_device *pdev)
return -ENODEV; return -ENODEV;
} }
platform_set_drvdata(pdev, host);
return 0; return 0;
} }

View File

@ -944,7 +944,6 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
goto err_rel_gpio; goto err_rel_gpio;
} }
platform_set_drvdata(pdev, drv_data);
drv_data->pdev = pdev; drv_data->pdev = pdev;
drv_data->ide_base = ide_base; drv_data->ide_base = ide_base;
drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN; drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN;

567
drivers/ata/pata_ftide010.c Normal file
View File

@ -0,0 +1,567 @@
/*
* Faraday Technology FTIDE010 driver
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
*
* Includes portions of the SL2312/SL3516/Gemini PATA driver
* Copyright (C) 2003 StorLine, Inc <jason@storlink.com.tw>
* Copyright (C) 2009 Janos Laube <janos.dev@gmail.com>
* Copyright (C) 2010 Frederic Pecourt <opengemini@free.fr>
* Copyright (C) 2011 Tobias Waldvogel <tobias.waldvogel@gmail.com>
*/
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/libata.h>
#include <linux/bitops.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include "sata_gemini.h"
#define DRV_NAME "pata_ftide010"
/**
* struct ftide010 - state container for the Faraday FTIDE010
* @dev: pointer back to the device representing this controller
* @base: remapped I/O space address
* @pclk: peripheral clock for the IDE block
* @host: pointer to the ATA host for this device
* @master_cbl: master cable type
* @slave_cbl: slave cable type
* @sg: Gemini SATA bridge pointer, if running on the Gemini
* @master_to_sata0: Gemini SATA bridge: the ATA master is connected
* to the SATA0 bridge
* @slave_to_sata0: Gemini SATA bridge: the ATA slave is connected
* to the SATA0 bridge
* @master_to_sata1: Gemini SATA bridge: the ATA master is connected
* to the SATA1 bridge
* @slave_to_sata1: Gemini SATA bridge: the ATA slave is connected
* to the SATA1 bridge
*/
struct ftide010 {
struct device *dev;
void __iomem *base;
struct clk *pclk;
struct ata_host *host;
unsigned int master_cbl;
unsigned int slave_cbl;
/* Gemini-specific properties */
struct sata_gemini *sg;
bool master_to_sata0;
bool slave_to_sata0;
bool master_to_sata1;
bool slave_to_sata1;
};
#define FTIDE010_DMA_REG 0x00
#define FTIDE010_DMA_STATUS 0x02
#define FTIDE010_IDE_BMDTPR 0x04
#define FTIDE010_IDE_DEVICE_ID 0x08
#define FTIDE010_PIO_TIMING 0x10
#define FTIDE010_MWDMA_TIMING 0x11
#define FTIDE010_UDMA_TIMING0 0x12 /* Master */
#define FTIDE010_UDMA_TIMING1 0x13 /* Slave */
#define FTIDE010_CLK_MOD 0x14
/* These registers are mapped directly to the IDE registers */
#define FTIDE010_CMD_DATA 0x20
#define FTIDE010_ERROR_FEATURES 0x21
#define FTIDE010_NSECT 0x22
#define FTIDE010_LBAL 0x23
#define FTIDE010_LBAM 0x24
#define FTIDE010_LBAH 0x25
#define FTIDE010_DEVICE 0x26
#define FTIDE010_STATUS_COMMAND 0x27
#define FTIDE010_ALTSTAT_CTRL 0x36
/* Set this bit for UDMA mode 5 and 6 */
#define FTIDE010_UDMA_TIMING_MODE_56 BIT(7)
/* 0 = 50 MHz, 1 = 66 MHz */
#define FTIDE010_CLK_MOD_DEV0_CLK_SEL BIT(0)
#define FTIDE010_CLK_MOD_DEV1_CLK_SEL BIT(1)
/* Enable UDMA on a device */
#define FTIDE010_CLK_MOD_DEV0_UDMA_EN BIT(4)
#define FTIDE010_CLK_MOD_DEV1_UDMA_EN BIT(5)
static struct scsi_host_template pata_ftide010_sht = {
ATA_BMDMA_SHT(DRV_NAME),
};
/*
* Bus timings
*
* The unit of the below required timings is two clock periods of the ATA
* reference clock which is 30 nanoseconds per unit at 66MHz and 20
* nanoseconds per unit at 50 MHz. The PIO timings assume 33MHz speed for
* PIO.
*
* pio_active_time: array of 5 elements for T2 timing for Mode 0,
* 1, 2, 3 and 4. Range 0..15.
* pio_recovery_time: array of 5 elements for T2l timing for Mode 0,
* 1, 2, 3 and 4. Range 0..15.
* mdma_50_active_time: array of 4 elements for Td timing for multi
* word DMA, Mode 0, 1, and 2 at 50 MHz. Range 0..15.
* mdma_50_recovery_time: array of 4 elements for Tk timing for
* multi word DMA, Mode 0, 1 and 2 at 50 MHz. Range 0..15.
* mdma_66_active_time: array of 4 elements for Td timing for multi
* word DMA, Mode 0, 1 and 2 at 66 MHz. Range 0..15.
* mdma_66_recovery_time: array of 4 elements for Tk timing for
* multi word DMA, Mode 0, 1 and 2 at 66 MHz. Range 0..15.
* udma_50_setup_time: array of 4 elements for Tvds timing for ultra
* DMA, Mode 0, 1, 2, 3, 4 and 5 at 50 MHz. Range 0..7.
* udma_50_hold_time: array of 4 elements for Tdvh timing for
* multi word DMA, Mode 0, 1, 2, 3, 4 and 5 at 50 MHz, Range 0..7.
* udma_66_setup_time: array of 4 elements for Tvds timing for multi
* word DMA, Mode 0, 1, 2, 3, 4, 5 and 6 at 66 MHz. Range 0..7.
* udma_66_hold_time: array of 4 elements for Tdvh timing for
* multi word DMA, Mode 0, 1, 2, 3, 4, 5 and 6 at 66 MHz. Range 0..7.
*/
static const u8 pio_active_time[5] = {10, 10, 10, 3, 3};
static const u8 pio_recovery_time[5] = {10, 3, 1, 3, 1};
static const u8 mwdma_50_active_time[3] = {6, 2, 2};
static const u8 mwdma_50_recovery_time[3] = {6, 2, 1};
static const u8 mwdma_66_active_time[3] = {8, 3, 3};
static const u8 mwdma_66_recovery_time[3] = {8, 2, 1};
static const u8 udma_50_setup_time[6] = {3, 3, 2, 2, 1, 1};
static const u8 udma_50_hold_time[6] = {3, 1, 1, 1, 1, 1};
static const u8 udma_66_setup_time[7] = {4, 4, 3, 2, };
static const u8 udma_66_hold_time[7] = {};
/*
* We set 66 MHz for all MWDMA modes
*/
static const bool set_mdma_66_mhz[] = { true, true, true, true };
/*
* We set 66 MHz for UDMA modes 3, 4 and 6 and no others
*/
static const bool set_udma_66_mhz[] = { false, false, false, true, true, false, true };
static void ftide010_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
struct ftide010 *ftide = ap->host->private_data;
u8 speed = adev->dma_mode;
u8 devno = adev->devno & 1;
u8 udma_en_mask;
u8 f66m_en_mask;
u8 clkreg;
u8 timreg;
u8 i;
/* Target device 0 (master) or 1 (slave) */
if (!devno) {
udma_en_mask = FTIDE010_CLK_MOD_DEV0_UDMA_EN;
f66m_en_mask = FTIDE010_CLK_MOD_DEV0_CLK_SEL;
} else {
udma_en_mask = FTIDE010_CLK_MOD_DEV1_UDMA_EN;
f66m_en_mask = FTIDE010_CLK_MOD_DEV1_CLK_SEL;
}
clkreg = readb(ftide->base + FTIDE010_CLK_MOD);
clkreg &= ~udma_en_mask;
clkreg &= ~f66m_en_mask;
if (speed & XFER_UDMA_0) {
i = speed & ~XFER_UDMA_0;
dev_dbg(ftide->dev, "set UDMA mode %02x, index %d\n",
speed, i);
clkreg |= udma_en_mask;
if (set_udma_66_mhz[i]) {
clkreg |= f66m_en_mask;
timreg = udma_66_setup_time[i] << 4 |
udma_66_hold_time[i];
} else {
timreg = udma_50_setup_time[i] << 4 |
udma_50_hold_time[i];
}
/* A special bit needs to be set for modes 5 and 6 */
if (i >= 5)
timreg |= FTIDE010_UDMA_TIMING_MODE_56;
dev_dbg(ftide->dev, "UDMA write clkreg = %02x, timreg = %02x\n",
clkreg, timreg);
writeb(clkreg, ftide->base + FTIDE010_CLK_MOD);
writeb(timreg, ftide->base + FTIDE010_UDMA_TIMING0 + devno);
} else {
i = speed & ~XFER_MW_DMA_0;
dev_dbg(ftide->dev, "set MWDMA mode %02x, index %d\n",
speed, i);
if (set_mdma_66_mhz[i]) {
clkreg |= f66m_en_mask;
timreg = mwdma_66_active_time[i] << 4 |
mwdma_66_recovery_time[i];
} else {
timreg = mwdma_50_active_time[i] << 4 |
mwdma_50_recovery_time[i];
}
dev_dbg(ftide->dev,
"MWDMA write clkreg = %02x, timreg = %02x\n",
clkreg, timreg);
/* This will affect all devices */
writeb(clkreg, ftide->base + FTIDE010_CLK_MOD);
writeb(timreg, ftide->base + FTIDE010_MWDMA_TIMING);
}
/*
* Store the current device (master or slave) in ap->private_data
* so that .qc_issue() can detect if this changes and reprogram
* the DMA settings.
*/
ap->private_data = adev;
return;
}
static void ftide010_set_piomode(struct ata_port *ap, struct ata_device *adev)
{
struct ftide010 *ftide = ap->host->private_data;
u8 pio = adev->pio_mode - XFER_PIO_0;
dev_dbg(ftide->dev, "set PIO mode %02x, index %d\n",
adev->pio_mode, pio);
writeb(pio_active_time[pio] << 4 | pio_recovery_time[pio],
ftide->base + FTIDE010_PIO_TIMING);
}
/*
* We implement our own qc_issue() callback since we may need to set up
* the timings differently for master and slave transfers: the CLK_MOD_REG
* and MWDMA_TIMING_REG is shared between master and slave, so reprogramming
* this may be necessary.
*/
static unsigned int ftide010_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
struct ata_device *adev = qc->dev;
/*
* If the device changed, i.e. slave->master, master->slave,
* then set up the DMA mode again so we are sure the timings
* are correct.
*/
if (adev != ap->private_data && ata_dma_enabled(adev))
ftide010_set_dmamode(ap, adev);
return ata_bmdma_qc_issue(qc);
}
static struct ata_port_operations pata_ftide010_port_ops = {
.inherits = &ata_bmdma_port_ops,
.set_dmamode = ftide010_set_dmamode,
.set_piomode = ftide010_set_piomode,
.qc_issue = ftide010_qc_issue,
};
static struct ata_port_info ftide010_port_info[] = {
{
.flags = ATA_FLAG_SLAVE_POSS,
.mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.pio_mask = ATA_PIO4,
.port_ops = &pata_ftide010_port_ops,
},
};
#if IS_ENABLED(CONFIG_SATA_GEMINI)
static int pata_ftide010_gemini_port_start(struct ata_port *ap)
{
struct ftide010 *ftide = ap->host->private_data;
struct device *dev = ftide->dev;
struct sata_gemini *sg = ftide->sg;
int bridges = 0;
int ret;
ret = ata_bmdma_port_start(ap);
if (ret)
return ret;
if (ftide->master_to_sata0) {
dev_info(dev, "SATA0 (master) start\n");
ret = gemini_sata_start_bridge(sg, 0);
if (!ret)
bridges++;
}
if (ftide->master_to_sata1) {
dev_info(dev, "SATA1 (master) start\n");
ret = gemini_sata_start_bridge(sg, 1);
if (!ret)
bridges++;
}
/* Avoid double-starting */
if (ftide->slave_to_sata0 && !ftide->master_to_sata0) {
dev_info(dev, "SATA0 (slave) start\n");
ret = gemini_sata_start_bridge(sg, 0);
if (!ret)
bridges++;
}
/* Avoid double-starting */
if (ftide->slave_to_sata1 && !ftide->master_to_sata1) {
dev_info(dev, "SATA1 (slave) start\n");
ret = gemini_sata_start_bridge(sg, 1);
if (!ret)
bridges++;
}
dev_info(dev, "brought %d bridges online\n", bridges);
return (bridges > 0) ? 0 : -EINVAL; // -ENODEV;
}
static void pata_ftide010_gemini_port_stop(struct ata_port *ap)
{
struct ftide010 *ftide = ap->host->private_data;
struct device *dev = ftide->dev;
struct sata_gemini *sg = ftide->sg;
if (ftide->master_to_sata0) {
dev_info(dev, "SATA0 (master) stop\n");
gemini_sata_stop_bridge(sg, 0);
}
if (ftide->master_to_sata1) {
dev_info(dev, "SATA1 (master) stop\n");
gemini_sata_stop_bridge(sg, 1);
}
/* Avoid double-stopping */
if (ftide->slave_to_sata0 && !ftide->master_to_sata0) {
dev_info(dev, "SATA0 (slave) stop\n");
gemini_sata_stop_bridge(sg, 0);
}
/* Avoid double-stopping */
if (ftide->slave_to_sata1 && !ftide->master_to_sata1) {
dev_info(dev, "SATA1 (slave) stop\n");
gemini_sata_stop_bridge(sg, 1);
}
}
static int pata_ftide010_gemini_cable_detect(struct ata_port *ap)
{
struct ftide010 *ftide = ap->host->private_data;
/*
* Return the master cable, I have no clue how to return a different
* cable for the slave than for the master.
*/
return ftide->master_cbl;
}
static int pata_ftide010_gemini_init(struct ftide010 *ftide,
bool is_ata1)
{
struct device *dev = ftide->dev;
struct sata_gemini *sg;
enum gemini_muxmode muxmode;
/* Look up SATA bridge */
sg = gemini_sata_bridge_get();
if (IS_ERR(sg))
return PTR_ERR(sg);
ftide->sg = sg;
muxmode = gemini_sata_get_muxmode(sg);
/* Special ops */
pata_ftide010_port_ops.port_start =
pata_ftide010_gemini_port_start;
pata_ftide010_port_ops.port_stop =
pata_ftide010_gemini_port_stop;
pata_ftide010_port_ops.cable_detect =
pata_ftide010_gemini_cable_detect;
/* Flag port as SATA-capable */
if (gemini_sata_bridge_enabled(sg, is_ata1))
ftide010_port_info[0].flags |= ATA_FLAG_SATA;
/*
* We assume that a simple 40-wire cable is used in the PATA mode.
* if you're adding a system using the PATA interface, make sure
* the right cable is set up here, it might be necessary to use
* special hardware detection or encode the cable type in the device
* tree with special properties.
*/
if (!is_ata1) {
switch (muxmode) {
case GEMINI_MUXMODE_0:
ftide->master_cbl = ATA_CBL_SATA;
ftide->slave_cbl = ATA_CBL_PATA40;
ftide->master_to_sata0 = true;
break;
case GEMINI_MUXMODE_1:
ftide->master_cbl = ATA_CBL_SATA;
ftide->slave_cbl = ATA_CBL_NONE;
ftide->master_to_sata0 = true;
break;
case GEMINI_MUXMODE_2:
ftide->master_cbl = ATA_CBL_PATA40;
ftide->slave_cbl = ATA_CBL_PATA40;
break;
case GEMINI_MUXMODE_3:
ftide->master_cbl = ATA_CBL_SATA;
ftide->slave_cbl = ATA_CBL_SATA;
ftide->master_to_sata0 = true;
ftide->slave_to_sata1 = true;
break;
}
} else {
switch (muxmode) {
case GEMINI_MUXMODE_0:
ftide->master_cbl = ATA_CBL_SATA;
ftide->slave_cbl = ATA_CBL_NONE;
ftide->master_to_sata1 = true;
break;
case GEMINI_MUXMODE_1:
ftide->master_cbl = ATA_CBL_SATA;
ftide->slave_cbl = ATA_CBL_PATA40;
ftide->master_to_sata1 = true;
break;
case GEMINI_MUXMODE_2:
ftide->master_cbl = ATA_CBL_SATA;
ftide->slave_cbl = ATA_CBL_SATA;
ftide->slave_to_sata0 = true;
ftide->master_to_sata1 = true;
break;
case GEMINI_MUXMODE_3:
ftide->master_cbl = ATA_CBL_PATA40;
ftide->slave_cbl = ATA_CBL_PATA40;
break;
}
}
dev_info(dev, "set up Gemini PATA%d\n", is_ata1);
return 0;
}
#else
static int pata_ftide010_gemini_init(struct ftide010 *ftide,
bool is_ata1)
{
return -ENOTSUPP;
}
#endif
static int pata_ftide010_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
const struct ata_port_info pi = ftide010_port_info[0];
const struct ata_port_info *ppi[] = { &pi, NULL };
struct ftide010 *ftide;
struct resource *res;
int irq;
int ret;
int i;
ftide = devm_kzalloc(dev, sizeof(*ftide), GFP_KERNEL);
if (!ftide)
return -ENOMEM;
ftide->dev = dev;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
ftide->base = devm_ioremap_resource(dev, res);
if (IS_ERR(ftide->base))
return PTR_ERR(ftide->base);
ftide->pclk = devm_clk_get(dev, "PCLK");
if (!IS_ERR(ftide->pclk)) {
ret = clk_prepare_enable(ftide->pclk);
if (ret) {
dev_err(dev, "failed to enable PCLK\n");
return ret;
}
}
/* Some special Cortina Gemini init, if needed */
if (of_device_is_compatible(np, "cortina,gemini-pata")) {
/*
* We need to know which instance is probing (the
* Gemini has two instances of FTIDE010) and we do
* this simply by looking at the physical base
* address, which is 0x63400000 for ATA1, else we
* are ATA0. This will also set up the cable types.
*/
ret = pata_ftide010_gemini_init(ftide,
(res->start == 0x63400000));
if (ret)
goto err_dis_clk;
} else {
/* Else assume we are connected using PATA40 */
ftide->master_cbl = ATA_CBL_PATA40;
ftide->slave_cbl = ATA_CBL_PATA40;
}
ftide->host = ata_host_alloc_pinfo(dev, ppi, 1);
if (!ftide->host) {
ret = -ENOMEM;
goto err_dis_clk;
}
ftide->host->private_data = ftide;
for (i = 0; i < ftide->host->n_ports; i++) {
struct ata_port *ap = ftide->host->ports[i];
struct ata_ioports *ioaddr = &ap->ioaddr;
ioaddr->bmdma_addr = ftide->base + FTIDE010_DMA_REG;
ioaddr->cmd_addr = ftide->base + FTIDE010_CMD_DATA;
ioaddr->ctl_addr = ftide->base + FTIDE010_ALTSTAT_CTRL;
ioaddr->altstatus_addr = ftide->base + FTIDE010_ALTSTAT_CTRL;
ata_sff_std_ports(ioaddr);
}
dev_info(dev, "device ID %08x, irq %d, reg %pR\n",
readl(ftide->base + FTIDE010_IDE_DEVICE_ID), irq, res);
ret = ata_host_activate(ftide->host, irq, ata_bmdma_interrupt,
0, &pata_ftide010_sht);
if (ret)
goto err_dis_clk;
return 0;
err_dis_clk:
if (!IS_ERR(ftide->pclk))
clk_disable_unprepare(ftide->pclk);
return ret;
}
static int pata_ftide010_remove(struct platform_device *pdev)
{
struct ata_host *host = platform_get_drvdata(pdev);
struct ftide010 *ftide = host->private_data;
ata_host_detach(ftide->host);
if (!IS_ERR(ftide->pclk))
clk_disable_unprepare(ftide->pclk);
return 0;
}
static const struct of_device_id pata_ftide010_of_match[] = {
{
.compatible = "faraday,ftide010",
},
{},
};
static struct platform_driver pata_ftide010_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(pata_ftide010_of_match),
},
.probe = pata_ftide010_probe,
.remove = pata_ftide010_remove,
};
module_platform_driver(pata_ftide010_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);

View File

@ -1038,7 +1038,7 @@ static void octeon_cf_shutdown(struct device *dev)
} }
} }
static struct of_device_id octeon_cf_match[] = { static const struct of_device_id octeon_cf_match[] = {
{ {
.compatible = "cavium,ebt3000-compact-flash", .compatible = "cavium,ebt3000-compact-flash",
}, },

View File

@ -148,8 +148,6 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
if (!ah) if (!ah)
return -ENOMEM; return -ENOMEM;
platform_set_drvdata(pdev, ah);
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;

View File

@ -292,7 +292,7 @@ static struct ata_port_operations rdc_pata_ops = {
.prereset = rdc_pata_prereset, .prereset = rdc_pata_prereset,
}; };
static struct ata_port_info rdc_port_info = { static const struct ata_port_info rdc_port_info = {
.flags = ATA_FLAG_SLAVE_POSS, .flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,

View File

@ -582,8 +582,6 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
/* Set endianness and enable the interface */ /* Set endianness and enable the interface */
pata_s3c_hwinit(info, pdata); pata_s3c_hwinit(info, pdata);
platform_set_drvdata(pdev, host);
ret = ata_host_activate(host, info->irq, ret = ata_host_activate(host, info->irq,
info->irq ? pata_s3c_irq : NULL, info->irq ? pata_s3c_irq : NULL,
0, &pata_s3c_sht); 0, &pata_s3c_sht);

View File

@ -81,7 +81,7 @@ static struct ata_port_operations sch_pata_ops = {
.set_dmamode = sch_set_dmamode, .set_dmamode = sch_set_dmamode,
}; };
static struct ata_port_info sch_port_info = { static const struct ata_port_info sch_port_info = {
.flags = ATA_FLAG_SLAVE_POSS, .flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2, .mwdma_mask = ATA_MWDMA2,

View File

@ -1285,7 +1285,6 @@ static int sata_dwc_probe(struct platform_device *ofdev)
if (err) if (err)
dev_err(&ofdev->dev, "failed to activate host"); dev_err(&ofdev->dev, "failed to activate host");
dev_set_drvdata(&ofdev->dev, host);
return 0; return 0;
error_out: error_out:

View File

@ -1523,8 +1523,6 @@ static int sata_fsl_probe(struct platform_device *ofdev)
ata_host_activate(host, irq, sata_fsl_interrupt, SATA_FSL_IRQ_FLAG, ata_host_activate(host, irq, sata_fsl_interrupt, SATA_FSL_IRQ_FLAG,
&sata_fsl_sht); &sata_fsl_sht);
platform_set_drvdata(ofdev, host);
host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show; host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show;
host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store; host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store;
sysfs_attr_init(&host_priv->intr_coalescing.attr); sysfs_attr_init(&host_priv->intr_coalescing.attr);

438
drivers/ata/sata_gemini.c Normal file
View File

@ -0,0 +1,438 @@
/*
* Cortina Systems Gemini SATA bridge add-on to Faraday FTIDE010
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/bitops.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include <linux/reset.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/clk.h>
#include <linux/io.h>
#include "sata_gemini.h"
#define DRV_NAME "gemini_sata_bridge"
/**
* struct sata_gemini - a state container for a Gemini SATA bridge
* @dev: the containing device
* @base: remapped I/O memory base
* @muxmode: the current muxing mode
* @ide_pins: if the device is using the plain IDE interface pins
* @sata_bridge: if the device enables the SATA bridge
* @sata0_reset: SATA0 reset handler
* @sata1_reset: SATA1 reset handler
* @sata0_pclk: SATA0 PCLK handler
* @sata1_pclk: SATA1 PCLK handler
*/
struct sata_gemini {
struct device *dev;
void __iomem *base;
enum gemini_muxmode muxmode;
bool ide_pins;
bool sata_bridge;
struct reset_control *sata0_reset;
struct reset_control *sata1_reset;
struct clk *sata0_pclk;
struct clk *sata1_pclk;
};
/* Global IDE PAD Skew Control Register */
#define GEMINI_GLOBAL_IDE_SKEW_CTRL 0x18
#define GEMINI_IDE1_HOST_STROBE_DELAY_SHIFT 28
#define GEMINI_IDE1_DEVICE_STROBE_DELAY_SHIFT 24
#define GEMINI_IDE1_OUTPUT_IO_SKEW_SHIFT 20
#define GEMINI_IDE1_INPUT_IO_SKEW_SHIFT 16
#define GEMINI_IDE0_HOST_STROBE_DELAY_SHIFT 12
#define GEMINI_IDE0_DEVICE_STROBE_DELAY_SHIFT 8
#define GEMINI_IDE0_OUTPUT_IO_SKEW_SHIFT 4
#define GEMINI_IDE0_INPUT_IO_SKEW_SHIFT 0
/* Miscellaneous Control Register */
#define GEMINI_GLOBAL_MISC_CTRL 0x30
/*
* Values of IDE IOMUX bits in the misc control register
*
* Bits 26:24 are "IDE IO Select", which decides what SATA
* adapters are connected to which of the two IDE/ATA
* controllers in the Gemini. We can connect the two IDE blocks
* to one SATA adapter each, both acting as master, or one IDE
* blocks to two SATA adapters so the IDE block can act in a
* master/slave configuration.
*
* We also bring out different blocks on the actual IDE
* pins (not SATA pins) if (and only if) these are muxed in.
*
* 111-100 - Reserved
* Mode 0: 000 - ata0 master <-> sata0
* ata1 master <-> sata1
* ata0 slave interface brought out on IDE pads
* Mode 1: 001 - ata0 master <-> sata0
* ata1 master <-> sata1
* ata1 slave interface brought out on IDE pads
* Mode 2: 010 - ata1 master <-> sata1
* ata1 slave <-> sata0
* ata0 master and slave interfaces brought out
* on IDE pads
* Mode 3: 011 - ata0 master <-> sata0
* ata1 slave <-> sata1
* ata1 master and slave interfaces brought out
* on IDE pads
*/
#define GEMINI_IDE_IOMUX_MASK (7 << 24)
#define GEMINI_IDE_IOMUX_MODE0 (0 << 24)
#define GEMINI_IDE_IOMUX_MODE1 (1 << 24)
#define GEMINI_IDE_IOMUX_MODE2 (2 << 24)
#define GEMINI_IDE_IOMUX_MODE3 (3 << 24)
#define GEMINI_IDE_IOMUX_SHIFT (24)
#define GEMINI_IDE_PADS_ENABLE BIT(4)
#define GEMINI_PFLASH_PADS_DISABLE BIT(1)
/*
* Registers directly controlling the PATA<->SATA adapters
*/
#define GEMINI_SATA_ID 0x00
#define GEMINI_SATA_PHY_ID 0x04
#define GEMINI_SATA0_STATUS 0x08
#define GEMINI_SATA1_STATUS 0x0c
#define GEMINI_SATA0_CTRL 0x18
#define GEMINI_SATA1_CTRL 0x1c
#define GEMINI_SATA_STATUS_BIST_DONE BIT(5)
#define GEMINI_SATA_STATUS_BIST_OK BIT(4)
#define GEMINI_SATA_STATUS_PHY_READY BIT(0)
#define GEMINI_SATA_CTRL_PHY_BIST_EN BIT(14)
#define GEMINI_SATA_CTRL_PHY_FORCE_IDLE BIT(13)
#define GEMINI_SATA_CTRL_PHY_FORCE_READY BIT(12)
#define GEMINI_SATA_CTRL_PHY_AFE_LOOP_EN BIT(10)
#define GEMINI_SATA_CTRL_PHY_DIG_LOOP_EN BIT(9)
#define GEMINI_SATA_CTRL_HOTPLUG_DETECT_EN BIT(4)
#define GEMINI_SATA_CTRL_ATAPI_EN BIT(3)
#define GEMINI_SATA_CTRL_BUS_WITH_20 BIT(2)
#define GEMINI_SATA_CTRL_SLAVE_EN BIT(1)
#define GEMINI_SATA_CTRL_EN BIT(0)
/*
* There is only ever one instance of this bridge on a system,
* so create a singleton so that the FTIDE010 instances can grab
* a reference to it.
*/
static struct sata_gemini *sg_singleton;
struct sata_gemini *gemini_sata_bridge_get(void)
{
if (sg_singleton)
return sg_singleton;
return ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL(gemini_sata_bridge_get);
bool gemini_sata_bridge_enabled(struct sata_gemini *sg, bool is_ata1)
{
if (!sg->sata_bridge)
return false;
/*
* In muxmode 2 and 3 one of the ATA controllers is
* actually not connected to any SATA bridge.
*/
if ((sg->muxmode == GEMINI_MUXMODE_2) &&
!is_ata1)
return false;
if ((sg->muxmode == GEMINI_MUXMODE_3) &&
is_ata1)
return false;
return true;
}
EXPORT_SYMBOL(gemini_sata_bridge_enabled);
enum gemini_muxmode gemini_sata_get_muxmode(struct sata_gemini *sg)
{
return sg->muxmode;
}
EXPORT_SYMBOL(gemini_sata_get_muxmode);
static int gemini_sata_setup_bridge(struct sata_gemini *sg,
unsigned int bridge)
{
unsigned long timeout = jiffies + (HZ * 1);
bool bridge_online;
u32 val;
if (bridge == 0) {
val = GEMINI_SATA_CTRL_HOTPLUG_DETECT_EN | GEMINI_SATA_CTRL_EN;
/* SATA0 slave mode is only used in muxmode 2 */
if (sg->muxmode == GEMINI_MUXMODE_2)
val |= GEMINI_SATA_CTRL_SLAVE_EN;
writel(val, sg->base + GEMINI_SATA0_CTRL);
} else {
val = GEMINI_SATA_CTRL_HOTPLUG_DETECT_EN | GEMINI_SATA_CTRL_EN;
/* SATA1 slave mode is only used in muxmode 3 */
if (sg->muxmode == GEMINI_MUXMODE_3)
val |= GEMINI_SATA_CTRL_SLAVE_EN;
writel(val, sg->base + GEMINI_SATA1_CTRL);
}
/* Vendor code waits 10 ms here */
msleep(10);
/* Wait for PHY to become ready */
do {
msleep(100);
if (bridge == 0)
val = readl(sg->base + GEMINI_SATA0_STATUS);
else
val = readl(sg->base + GEMINI_SATA1_STATUS);
if (val & GEMINI_SATA_STATUS_PHY_READY)
break;
} while (time_before(jiffies, timeout));
bridge_online = !!(val & GEMINI_SATA_STATUS_PHY_READY);
dev_info(sg->dev, "SATA%d PHY %s\n", bridge,
bridge_online ? "ready" : "not ready");
return bridge_online ? 0: -ENODEV;
}
int gemini_sata_start_bridge(struct sata_gemini *sg, unsigned int bridge)
{
struct clk *pclk;
int ret;
if (bridge == 0)
pclk = sg->sata0_pclk;
else
pclk = sg->sata1_pclk;
clk_enable(pclk);
msleep(10);
/* Do not keep clocking a bridge that is not online */
ret = gemini_sata_setup_bridge(sg, bridge);
if (ret)
clk_disable(pclk);
return ret;
}
EXPORT_SYMBOL(gemini_sata_start_bridge);
void gemini_sata_stop_bridge(struct sata_gemini *sg, unsigned int bridge)
{
if (bridge == 0)
clk_disable(sg->sata0_pclk);
else if (bridge == 1)
clk_disable(sg->sata1_pclk);
}
EXPORT_SYMBOL(gemini_sata_stop_bridge);
int gemini_sata_reset_bridge(struct sata_gemini *sg,
unsigned int bridge)
{
if (bridge == 0)
reset_control_reset(sg->sata0_reset);
else
reset_control_reset(sg->sata1_reset);
msleep(10);
return gemini_sata_setup_bridge(sg, bridge);
}
EXPORT_SYMBOL(gemini_sata_reset_bridge);
static int gemini_sata_bridge_init(struct sata_gemini *sg)
{
struct device *dev = sg->dev;
u32 sata_id, sata_phy_id;
int ret;
sg->sata0_pclk = devm_clk_get(dev, "SATA0_PCLK");
if (IS_ERR(sg->sata0_pclk)) {
dev_err(dev, "no SATA0 PCLK");
return -ENODEV;
}
sg->sata1_pclk = devm_clk_get(dev, "SATA1_PCLK");
if (IS_ERR(sg->sata1_pclk)) {
dev_err(dev, "no SATA1 PCLK");
return -ENODEV;
}
ret = clk_prepare_enable(sg->sata0_pclk);
if (ret) {
pr_err("failed to enable SATA0 PCLK\n");
return ret;
}
ret = clk_prepare_enable(sg->sata1_pclk);
if (ret) {
pr_err("failed to enable SATA1 PCLK\n");
clk_disable_unprepare(sg->sata0_pclk);
return ret;
}
sg->sata0_reset = devm_reset_control_get(dev, "sata0");
if (IS_ERR(sg->sata0_reset)) {
dev_err(dev, "no SATA0 reset controller\n");
clk_disable_unprepare(sg->sata1_pclk);
clk_disable_unprepare(sg->sata0_pclk);
return PTR_ERR(sg->sata0_reset);
}
sg->sata1_reset = devm_reset_control_get(dev, "sata1");
if (IS_ERR(sg->sata1_reset)) {
dev_err(dev, "no SATA1 reset controller\n");
clk_disable_unprepare(sg->sata1_pclk);
clk_disable_unprepare(sg->sata0_pclk);
return PTR_ERR(sg->sata1_reset);
}
sata_id = readl(sg->base + GEMINI_SATA_ID);
sata_phy_id = readl(sg->base + GEMINI_SATA_PHY_ID);
sg->sata_bridge = true;
clk_disable(sg->sata0_pclk);
clk_disable(sg->sata1_pclk);
dev_info(dev, "SATA ID %08x, PHY ID: %08x\n", sata_id, sata_phy_id);
return 0;
}
static int gemini_sata_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct sata_gemini *sg;
static struct regmap *map;
struct resource *res;
enum gemini_muxmode muxmode;
u32 gmode;
u32 gmask;
u32 val;
int ret;
sg = devm_kzalloc(dev, sizeof(*sg), GFP_KERNEL);
if (!sg)
return -ENOMEM;
sg->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
sg->base = devm_ioremap_resource(dev, res);
if (IS_ERR(sg->base))
return PTR_ERR(sg->base);
map = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(map)) {
dev_err(dev, "no global syscon\n");
return PTR_ERR(map);
}
/* Set up the SATA bridge if need be */
if (of_property_read_bool(np, "cortina,gemini-enable-sata-bridge")) {
ret = gemini_sata_bridge_init(sg);
if (ret)
return ret;
}
if (of_property_read_bool(np, "cortina,gemini-enable-ide-pins"))
sg->ide_pins = true;
if (!sg->sata_bridge && !sg->ide_pins) {
dev_err(dev, "neither SATA bridge or IDE output enabled\n");
ret = -EINVAL;
goto out_unprep_clk;
}
ret = of_property_read_u32(np, "cortina,gemini-ata-muxmode", &muxmode);
if (ret) {
dev_err(dev, "could not parse ATA muxmode\n");
goto out_unprep_clk;
}
if (muxmode > GEMINI_MUXMODE_3) {
dev_err(dev, "illegal muxmode %d\n", muxmode);
ret = -EINVAL;
goto out_unprep_clk;
}
sg->muxmode = muxmode;
gmask = GEMINI_IDE_IOMUX_MASK;
gmode = (muxmode << GEMINI_IDE_IOMUX_SHIFT);
/*
* If we mux out the IDE, parallel flash must be disabled.
* SATA0 and SATA1 have dedicated pins and may coexist with
* parallel flash.
*/
if (sg->ide_pins)
gmode |= GEMINI_IDE_PADS_ENABLE | GEMINI_PFLASH_PADS_DISABLE;
else
gmask |= GEMINI_IDE_PADS_ENABLE;
ret = regmap_update_bits(map, GEMINI_GLOBAL_MISC_CTRL, gmask, gmode);
if (ret) {
dev_err(dev, "unable to set up IDE muxing\n");
ret = -ENODEV;
goto out_unprep_clk;
}
/* FIXME: add more elaborate IDE skew control handling */
if (sg->ide_pins) {
ret = regmap_read(map, GEMINI_GLOBAL_IDE_SKEW_CTRL, &val);
if (ret) {
dev_err(dev, "cannot read IDE skew control register\n");
return ret;
}
dev_info(dev, "IDE skew control: %08x\n", val);
}
dev_info(dev, "set up the Gemini IDE/SATA nexus\n");
platform_set_drvdata(pdev, sg);
sg_singleton = sg;
return 0;
out_unprep_clk:
if (sg->sata_bridge) {
clk_unprepare(sg->sata1_pclk);
clk_unprepare(sg->sata0_pclk);
}
return ret;
}
static int gemini_sata_remove(struct platform_device *pdev)
{
struct sata_gemini *sg = platform_get_drvdata(pdev);
if (sg->sata_bridge) {
clk_unprepare(sg->sata1_pclk);
clk_unprepare(sg->sata0_pclk);
}
sg_singleton = NULL;
return 0;
}
static const struct of_device_id gemini_sata_of_match[] = {
{
.compatible = "cortina,gemini-sata-bridge",
},
{},
};
static struct platform_driver gemini_sata_driver = {
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(gemini_sata_of_match),
},
.probe = gemini_sata_probe,
.remove = gemini_sata_remove,
};
module_platform_driver(gemini_sata_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);

21
drivers/ata/sata_gemini.h Normal file
View File

@ -0,0 +1,21 @@
/* Header for the Gemini SATA bridge */
#ifndef SATA_GEMINI_H
#define SATA_GEMINI_H
struct sata_gemini;
enum gemini_muxmode {
GEMINI_MUXMODE_0 = 0,
GEMINI_MUXMODE_1,
GEMINI_MUXMODE_2,
GEMINI_MUXMODE_3,
};
struct sata_gemini *gemini_sata_bridge_get(void);
bool gemini_sata_bridge_enabled(struct sata_gemini *sg, bool is_ata1);
enum gemini_muxmode gemini_sata_get_muxmode(struct sata_gemini *sg);
int gemini_sata_start_bridge(struct sata_gemini *sg, unsigned int bridge);
void gemini_sata_stop_bridge(struct sata_gemini *sg, unsigned int bridge);
int gemini_sata_reset_bridge(struct sata_gemini *sg, unsigned int bridge);
#endif

View File

@ -737,7 +737,7 @@ static struct ata_port_operations inic_port_ops = {
.port_start = inic_port_start, .port_start = inic_port_start,
}; };
static struct ata_port_info inic_port_info = { static const struct ata_port_info inic_port_info = {
.flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA, .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2, .mwdma_mask = ATA_MWDMA2,

View File

@ -828,7 +828,7 @@ static void sata_rcar_init_controller(struct ata_host *host)
iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG); iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG);
} }
static struct of_device_id sata_rcar_match[] = { static const struct of_device_id sata_rcar_match[] = {
{ {
/* Deprecated by "renesas,sata-r8a7779" */ /* Deprecated by "renesas,sata-r8a7779" */
.compatible = "renesas,rcar-sata", .compatible = "renesas,rcar-sata",

View File

@ -80,6 +80,10 @@ struct svia_priv {
bool wd_workaround; bool wd_workaround;
}; };
static int vt6420_hotplug;
module_param_named(vt6420_hotplug, vt6420_hotplug, int, 0644);
MODULE_PARM_DESC(vt6420_hotplug, "Enable hot-plug support for VT6420 (0=Don't support, 1=support)");
static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static int svia_pci_device_resume(struct pci_dev *pdev); static int svia_pci_device_resume(struct pci_dev *pdev);
@ -166,7 +170,7 @@ static const struct ata_port_info vt6420_port_info = {
.port_ops = &vt6420_sata_ops, .port_ops = &vt6420_sata_ops,
}; };
static struct ata_port_info vt6421_sport_info = { static const struct ata_port_info vt6421_sport_info = {
.flags = ATA_FLAG_SATA, .flags = ATA_FLAG_SATA,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2, .mwdma_mask = ATA_MWDMA2,
@ -174,7 +178,7 @@ static struct ata_port_info vt6421_sport_info = {
.port_ops = &vt6421_sata_ops, .port_ops = &vt6421_sata_ops,
}; };
static struct ata_port_info vt6421_pport_info = { static const struct ata_port_info vt6421_pport_info = {
.flags = ATA_FLAG_SLAVE_POSS, .flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
/* No MWDMA */ /* No MWDMA */
@ -182,7 +186,7 @@ static struct ata_port_info vt6421_pport_info = {
.port_ops = &vt6421_pata_ops, .port_ops = &vt6421_pata_ops,
}; };
static struct ata_port_info vt8251_port_info = { static const struct ata_port_info vt8251_port_info = {
.flags = ATA_FLAG_SATA | ATA_FLAG_SLAVE_POSS, .flags = ATA_FLAG_SATA | ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4, .pio_mask = ATA_PIO4,
.mwdma_mask = ATA_MWDMA2, .mwdma_mask = ATA_MWDMA2,
@ -473,6 +477,11 @@ static int vt6420_prepare_host(struct pci_dev *pdev, struct ata_host **r_host)
struct ata_host *host; struct ata_host *host;
int rc; int rc;
if (vt6420_hotplug) {
ppi[0]->port_ops->scr_read = svia_scr_read;
ppi[0]->port_ops->scr_write = svia_scr_write;
}
rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host); rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host);
if (rc) if (rc)
return rc; return rc;
@ -556,7 +565,7 @@ static void svia_wd_fix(struct pci_dev *pdev)
pci_write_config_byte(pdev, 0x52, tmp8 | BIT(2)); pci_write_config_byte(pdev, 0x52, tmp8 | BIT(2));
} }
static irqreturn_t vt6421_interrupt(int irq, void *dev_instance) static irqreturn_t vt642x_interrupt(int irq, void *dev_instance)
{ {
struct ata_host *host = dev_instance; struct ata_host *host = dev_instance;
irqreturn_t rc = ata_bmdma_interrupt(irq, dev_instance); irqreturn_t rc = ata_bmdma_interrupt(irq, dev_instance);
@ -644,7 +653,7 @@ static void svia_configure(struct pci_dev *pdev, int board_id,
pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
} }
if (board_id == vt6421) { if ((board_id == vt6420 && vt6420_hotplug) || board_id == vt6421) {
/* enable IRQ on hotplug */ /* enable IRQ on hotplug */
pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8); pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8);
if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) { if ((tmp8 & SATA_HOTPLUG) != SATA_HOTPLUG) {
@ -744,8 +753,8 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
svia_configure(pdev, board_id, hpriv); svia_configure(pdev, board_id, hpriv);
pci_set_master(pdev); pci_set_master(pdev);
if (board_id == vt6421) if ((board_id == vt6420 && vt6420_hotplug) || board_id == vt6421)
return ata_host_activate(host, pdev->irq, vt6421_interrupt, return ata_host_activate(host, pdev->irq, vt642x_interrupt,
IRQF_SHARED, &svia_sht); IRQF_SHARED, &svia_sht);
else else
return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt, return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,

View File

@ -50,6 +50,7 @@
#include <linux/string_helpers.h> #include <linux/string_helpers.h>
#include <linux/async.h> #include <linux/async.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sed-opal.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pr.h> #include <linux/pr.h>
#include <linux/t10-pi.h> #include <linux/t10-pi.h>
@ -643,6 +644,26 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
mutex_unlock(&sd_ref_mutex); mutex_unlock(&sd_ref_mutex);
} }
#ifdef CONFIG_BLK_SED_OPAL
static int sd_sec_submit(void *data, u16 spsp, u8 secp, void *buffer,
size_t len, bool send)
{
struct scsi_device *sdev = data;
u8 cdb[12] = { 0, };
int ret;
cdb[0] = send ? SECURITY_PROTOCOL_OUT : SECURITY_PROTOCOL_IN;
cdb[1] = secp;
put_unaligned_be16(spsp, &cdb[2]);
put_unaligned_be32(len, &cdb[6]);
ret = scsi_execute_req(sdev, cdb,
send ? DMA_TO_DEVICE : DMA_FROM_DEVICE,
buffer, len, NULL, SD_TIMEOUT, SD_MAX_RETRIES, NULL);
return ret <= 0 ? ret : -EIO;
}
#endif /* CONFIG_BLK_SED_OPAL */
static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd, static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,
unsigned int dix, unsigned int dif) unsigned int dix, unsigned int dif)
{ {
@ -1454,6 +1475,9 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
if (error) if (error)
goto out; goto out;
if (is_sed_ioctl(cmd))
return sed_ioctl(sdkp->opal_dev, cmd, p);
/* /*
* Send SCSI addressing ioctls directly to mid level, send other * Send SCSI addressing ioctls directly to mid level, send other
* ioctls to block level and then onto mid level if they can't be * ioctls to block level and then onto mid level if they can't be
@ -3014,6 +3038,20 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer)
sdkp->ws10 = 1; sdkp->ws10 = 1;
} }
static void sd_read_security(struct scsi_disk *sdkp, unsigned char *buffer)
{
struct scsi_device *sdev = sdkp->device;
if (!sdev->security_supported)
return;
if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE,
SECURITY_PROTOCOL_IN) == 1 &&
scsi_report_opcode(sdev, buffer, SD_BUF_SIZE,
SECURITY_PROTOCOL_OUT) == 1)
sdkp->security = 1;
}
/** /**
* sd_revalidate_disk - called the first time a new disk is seen, * sd_revalidate_disk - called the first time a new disk is seen,
* performs disk spin up, read_capacity, etc. * performs disk spin up, read_capacity, etc.
@ -3067,6 +3105,7 @@ static int sd_revalidate_disk(struct gendisk *disk)
sd_read_cache_type(sdkp, buffer); sd_read_cache_type(sdkp, buffer);
sd_read_app_tag_own(sdkp, buffer); sd_read_app_tag_own(sdkp, buffer);
sd_read_write_same(sdkp, buffer); sd_read_write_same(sdkp, buffer);
sd_read_security(sdkp, buffer);
} }
sdkp->first_scan = 0; sdkp->first_scan = 0;
@ -3227,6 +3266,12 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
sd_revalidate_disk(gd); sd_revalidate_disk(gd);
if (sdkp->security) {
sdkp->opal_dev = init_opal_dev(sdp, &sd_sec_submit);
if (sdkp->opal_dev)
sd_printk(KERN_NOTICE, sdkp, "supports TCG Opal\n");
}
sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n",
sdp->removable ? "removable " : ""); sdp->removable ? "removable " : "");
scsi_autopm_put_device(sdp); scsi_autopm_put_device(sdp);
@ -3376,6 +3421,8 @@ static int sd_remove(struct device *dev)
sd_zbc_remove(sdkp); sd_zbc_remove(sdkp);
free_opal_dev(sdkp->opal_dev);
blk_register_region(devt, SD_MINORS, NULL, blk_register_region(devt, SD_MINORS, NULL,
sd_default_probe, NULL, NULL); sd_default_probe, NULL, NULL);
@ -3528,6 +3575,7 @@ static int sd_suspend_runtime(struct device *dev)
static int sd_resume(struct device *dev) static int sd_resume(struct device *dev)
{ {
struct scsi_disk *sdkp = dev_get_drvdata(dev); struct scsi_disk *sdkp = dev_get_drvdata(dev);
int ret;
if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */ if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */
return 0; return 0;
@ -3536,7 +3584,10 @@ static int sd_resume(struct device *dev)
return 0; return 0;
sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); sd_printk(KERN_NOTICE, sdkp, "Starting disk\n");
return sd_start_stop_device(sdkp, 1); ret = sd_start_stop_device(sdkp, 1);
if (!ret)
opal_unlock_from_suspend(sdkp->opal_dev);
return ret;
} }
/** /**

View File

@ -71,6 +71,7 @@ struct scsi_disk {
struct scsi_device *device; struct scsi_device *device;
struct device dev; struct device dev;
struct gendisk *disk; struct gendisk *disk;
struct opal_dev *opal_dev;
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
unsigned int nr_zones; unsigned int nr_zones;
unsigned int zone_blocks; unsigned int zone_blocks;
@ -114,6 +115,7 @@ struct scsi_disk {
unsigned rc_basis: 2; unsigned rc_basis: 2;
unsigned zoned: 2; unsigned zoned: 2;
unsigned urswrz : 1; unsigned urswrz : 1;
unsigned security : 1;
unsigned ignore_medium_access_errors : 1; unsigned ignore_medium_access_errors : 1;
}; };
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)

View File

@ -336,11 +336,16 @@ enum {
/* READ_LOG_EXT pages */ /* READ_LOG_EXT pages */
ATA_LOG_DIRECTORY = 0x0, ATA_LOG_DIRECTORY = 0x0,
ATA_LOG_SATA_NCQ = 0x10, ATA_LOG_SATA_NCQ = 0x10,
ATA_LOG_NCQ_NON_DATA = 0x12, ATA_LOG_NCQ_NON_DATA = 0x12,
ATA_LOG_NCQ_SEND_RECV = 0x13, ATA_LOG_NCQ_SEND_RECV = 0x13,
ATA_LOG_SATA_ID_DEV_DATA = 0x30, ATA_LOG_IDENTIFY_DEVICE = 0x30,
/* Identify device log pages: */
ATA_LOG_SECURITY = 0x06,
ATA_LOG_SATA_SETTINGS = 0x08, ATA_LOG_SATA_SETTINGS = 0x08,
ATA_LOG_ZONED_INFORMATION = 0x09, ATA_LOG_ZONED_INFORMATION = 0x09,
/* Identify device SATA settings log:*/
ATA_LOG_DEVSLP_OFFSET = 0x30, ATA_LOG_DEVSLP_OFFSET = 0x30,
ATA_LOG_DEVSLP_SIZE = 0x08, ATA_LOG_DEVSLP_SIZE = 0x08,
ATA_LOG_DEVSLP_MDAT = 0x00, ATA_LOG_DEVSLP_MDAT = 0x00,

View File

@ -156,6 +156,7 @@ enum {
ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */ ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */
ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */ ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */
ATA_DFLAG_AN = (1 << 7), /* AN configured */ ATA_DFLAG_AN = (1 << 7), /* AN configured */
ATA_DFLAG_TRUSTED = (1 << 8), /* device supports trusted send/recv */
ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */ ATA_DFLAG_DMADIR = (1 << 10), /* device requires DMADIR */
ATA_DFLAG_CFG_MASK = (1 << 12) - 1, ATA_DFLAG_CFG_MASK = (1 << 12) - 1,

View File

@ -176,6 +176,7 @@ struct scsi_device {
unsigned no_read_disc_info:1; /* Avoid READ_DISC_INFO cmds */ unsigned no_read_disc_info:1; /* Avoid READ_DISC_INFO cmds */
unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */ unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */
unsigned try_rc_10_first:1; /* Try READ_CAPACACITY_10 first */ unsigned try_rc_10_first:1; /* Try READ_CAPACACITY_10 first */
unsigned security_supported:1; /* Supports Security Protocols */
unsigned is_visible:1; /* is the device visible in sysfs */ unsigned is_visible:1; /* is the device visible in sysfs */
unsigned wce_default_on:1; /* Cache is ON by default */ unsigned wce_default_on:1; /* Cache is ON by default */
unsigned no_dif:1; /* T10 PI (DIF) should be disabled */ unsigned no_dif:1; /* T10 PI (DIF) should be disabled */

View File

@ -162,6 +162,7 @@
#define VERIFY_32 0x0a #define VERIFY_32 0x0a
#define WRITE_32 0x0b #define WRITE_32 0x0b
#define WRITE_SAME_32 0x0d #define WRITE_SAME_32 0x0d
#define ATA_32 0x1ff0
/* Values for T10/04-262r7 */ /* Values for T10/04-262r7 */
#define ATA_16 0x85 /* 16-byte pass-thru */ #define ATA_16 0x85 /* 16-byte pass-thru */