forked from Minki/linux
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:
commit
109a5db504
@ -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;
|
||||
};
|
38
Documentation/devicetree/bindings/ata/faraday,ftide010.txt
Normal file
38
Documentation/devicetree/bindings/ata/faraday,ftide010.txt
Normal 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>;
|
||||
};
|
@ -7593,6 +7593,15 @@ S: Maintained
|
||||
F: drivers/ata/pata_*.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
|
||||
M: Hans de Goede <hdegoede@redhat.com>
|
||||
M: Tejun Heo <tj@kernel.org>
|
||||
|
@ -213,6 +213,16 @@ config SATA_FSL
|
||||
|
||||
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
|
||||
tristate "AMD Seattle 6.0Gbps AHCI SATA host controller support"
|
||||
depends on ARCH_SEATTLE
|
||||
@ -599,6 +609,17 @@ config PATA_EP93XX
|
||||
|
||||
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
|
||||
tristate "HPT 366/368 PATA support"
|
||||
depends on PCI
|
||||
|
@ -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_PLATFORM) += ahci_platform.o libahci.o libahci_platform.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_SIL24) += sata_sil24.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_EFAR) += pata_efar.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_HPT37X) += pata_hpt37x.o
|
||||
obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
|
||||
|
@ -548,6 +548,8 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
||||
{ PCI_VDEVICE(ASMEDIA, 0x0602), board_ahci }, /* ASM1060 */
|
||||
{ PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */
|
||||
{ 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
|
||||
|
@ -248,6 +248,9 @@ enum {
|
||||
AHCI_HFLAG_MULTI_MSI = 0,
|
||||
#endif
|
||||
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 */
|
||||
|
||||
|
@ -39,7 +39,6 @@
|
||||
#define PIODATA_ENDIAN_SHIFT 6
|
||||
#define ENDIAN_SWAP_NONE 0
|
||||
#define ENDIAN_SWAP_FULL 2
|
||||
#define OVERRIDE_HWINIT BIT(16)
|
||||
#define SATA_TOP_CTRL_TP_CTRL 0x8
|
||||
#define SATA_TOP_CTRL_PHY_CTRL 0xc
|
||||
#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)
|
||||
{
|
||||
struct brcm_ahci_priv *priv = hpriv->plat_data;
|
||||
u32 bus_ctrl, port_ctrl, host_caps;
|
||||
u32 port_ctrl, host_caps;
|
||||
int i;
|
||||
|
||||
/* 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);
|
||||
writel(host_caps | HOST_CAP_ALPM, hpriv->mmio);
|
||||
brcm_sata_writereg(bus_ctrl, priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
|
||||
if (!(host_caps & HOST_CAP_ALPM))
|
||||
hpriv->flags |= AHCI_HFLAG_YES_ALPM;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
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,
|
||||
&ahci_platform_sht);
|
||||
|
@ -47,12 +47,14 @@
|
||||
|
||||
#define SATA_ECC_DISABLE 0x00020000
|
||||
#define ECC_DIS_ARMV8_CH2 0x80000000
|
||||
#define ECC_DIS_LS1088A 0x40000000
|
||||
|
||||
enum ahci_qoriq_type {
|
||||
AHCI_LS1021A,
|
||||
AHCI_LS1043A,
|
||||
AHCI_LS2080A,
|
||||
AHCI_LS1046A,
|
||||
AHCI_LS1088A,
|
||||
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,ls2080a-ahci", .data = (void *)AHCI_LS2080A},
|
||||
{ .compatible = "fsl,ls1046a-ahci", .data = (void *)AHCI_LS1046A},
|
||||
{ .compatible = "fsl,ls1088a-ahci", .data = (void *)AHCI_LS1088A},
|
||||
{ .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);
|
||||
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:
|
||||
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
|
||||
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
|
||||
|
@ -504,6 +504,11 @@ void ahci_save_initial_config(struct device *dev, struct ahci_host_priv *hpriv)
|
||||
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) {
|
||||
dev_info(dev, "forcing port_map 0x%x -> 0x%x\n",
|
||||
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
|
||||
* initial values.
|
||||
*/
|
||||
ahci_restore_initial_config(host);
|
||||
if (!(hpriv->flags & AHCI_HFLAG_NO_WRITE_TO_RO))
|
||||
ahci_restore_initial_config(host);
|
||||
} else
|
||||
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);
|
||||
|
||||
/* issue the first D2H Register FIS */
|
||||
/* issue the first H2D Register FIS */
|
||||
msecs = 0;
|
||||
now = jiffies;
|
||||
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 */
|
||||
ata_msleep(ap, 1);
|
||||
|
||||
/* issue the second D2H Register FIS */
|
||||
/* issue the second H2D Register FIS */
|
||||
tf.ctl &= ~ATA_SRST;
|
||||
ahci_exec_polled_cmd(ap, pmp, &tf, 0, 0, 0);
|
||||
|
||||
|
@ -2047,6 +2047,110 @@ retry:
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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,
|
||||
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,
|
||||
"NCQ Send/Recv Log not supported\n");
|
||||
if (!ata_log_supported(dev, ATA_LOG_NCQ_SEND_RECV)) {
|
||||
ata_dev_warn(dev, "NCQ Send/Recv Log not supported\n");
|
||||
return;
|
||||
}
|
||||
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;
|
||||
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,
|
||||
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) {
|
||||
if (!ata_log_supported(dev, ATA_LOG_NCQ_NON_DATA)) {
|
||||
ata_dev_warn(dev,
|
||||
"NCQ Send/Recv Log not supported\n");
|
||||
return;
|
||||
@ -2176,7 +2257,7 @@ static void ata_dev_config_ncq_prio(struct ata_device *dev)
|
||||
}
|
||||
|
||||
err_mask = ata_read_log_page(dev,
|
||||
ATA_LOG_SATA_ID_DEV_DATA,
|
||||
ATA_LOG_IDENTIFY_DEVICE,
|
||||
ATA_LOG_SATA_SETTINGS,
|
||||
ap->sector_buf,
|
||||
1);
|
||||
@ -2275,8 +2356,6 @@ static void ata_dev_config_zac(struct ata_device *dev)
|
||||
struct ata_port *ap = dev->link->ap;
|
||||
unsigned int err_mask;
|
||||
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_nonseq = U32_MAX;
|
||||
@ -2296,44 +2375,7 @@ static void ata_dev_config_zac(struct ata_device *dev)
|
||||
if (!(dev->flags & ATA_DFLAG_ZAC))
|
||||
return;
|
||||
|
||||
/*
|
||||
* 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) {
|
||||
if (!ata_identify_page_supported(dev, ATA_LOG_ZONED_INFORMATION)) {
|
||||
ata_dev_warn(dev,
|
||||
"ATA Zoned Information Log not supported\n");
|
||||
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)
|
||||
*/
|
||||
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,
|
||||
identify_buf, 1);
|
||||
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
|
||||
* @dev: Target device to configure
|
||||
@ -2571,7 +2644,7 @@ int ata_dev_configure(struct ata_device *dev)
|
||||
|
||||
dev->flags |= ATA_DFLAG_DEVSLP;
|
||||
err_mask = ata_read_log_page(dev,
|
||||
ATA_LOG_SATA_ID_DEV_DATA,
|
||||
ATA_LOG_IDENTIFY_DEVICE,
|
||||
ATA_LOG_SATA_SETTINGS,
|
||||
sata_setting,
|
||||
1);
|
||||
@ -2587,7 +2660,8 @@ int ata_dev_configure(struct ata_device *dev)
|
||||
}
|
||||
ata_dev_config_sense_reporting(dev);
|
||||
ata_dev_config_zac(dev);
|
||||
dev->cdb_len = 16;
|
||||
ata_dev_config_trusted(dev);
|
||||
dev->cdb_len = 32;
|
||||
}
|
||||
|
||||
/* ATAPI-specific feature tests */
|
||||
|
@ -1487,70 +1487,6 @@ static const char *ata_err_string(unsigned int err_mask)
|
||||
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
|
||||
* @dev: Device to read log page 10h from
|
||||
|
@ -903,32 +903,32 @@ static void ata_dump_status(unsigned id, struct ata_taskfile *tf)
|
||||
{
|
||||
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) {
|
||||
printk("Busy }\n"); /* Data is not valid in this case */
|
||||
pr_cont("Busy }\n"); /* Data is not valid in this case */
|
||||
} else {
|
||||
if (stat & ATA_DRDY) printk("DriveReady ");
|
||||
if (stat & ATA_DF) printk("DeviceFault ");
|
||||
if (stat & ATA_DSC) printk("SeekComplete ");
|
||||
if (stat & ATA_DRQ) printk("DataRequest ");
|
||||
if (stat & ATA_CORR) printk("CorrectedError ");
|
||||
if (stat & ATA_SENSE) printk("Sense ");
|
||||
if (stat & ATA_ERR) printk("Error ");
|
||||
printk("}\n");
|
||||
if (stat & ATA_DRDY) pr_cont("DriveReady ");
|
||||
if (stat & ATA_DF) pr_cont("DeviceFault ");
|
||||
if (stat & ATA_DSC) pr_cont("SeekComplete ");
|
||||
if (stat & ATA_DRQ) pr_cont("DataRequest ");
|
||||
if (stat & ATA_CORR) pr_cont("CorrectedError ");
|
||||
if (stat & ATA_SENSE) pr_cont("Sense ");
|
||||
if (stat & ATA_ERR) pr_cont("Error ");
|
||||
pr_cont("}\n");
|
||||
|
||||
if (err) {
|
||||
printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err);
|
||||
if (err & ATA_ABORTED) printk("DriveStatusError ");
|
||||
pr_warn("ata%u: error=0x%02x { ", id, err);
|
||||
if (err & ATA_ABORTED) pr_cont("DriveStatusError ");
|
||||
if (err & ATA_ICRC) {
|
||||
if (err & ATA_ABORTED)
|
||||
printk("BadCRC ");
|
||||
else printk("Sector ");
|
||||
pr_cont("BadCRC ");
|
||||
else pr_cont("Sector ");
|
||||
}
|
||||
if (err & ATA_UNC) printk("UncorrectableError ");
|
||||
if (err & ATA_IDNF) printk("SectorIdNotFound ");
|
||||
if (err & ATA_TRK0NF) printk("TrackZeroNotFound ");
|
||||
if (err & ATA_AMNF) printk("AddrMarkNotFound ");
|
||||
printk("}\n");
|
||||
if (err & ATA_UNC) pr_cont("UncorrectableError ");
|
||||
if (err & ATA_IDNF) pr_cont("SectorIdNotFound ");
|
||||
if (err & ATA_TRK0NF) pr_cont("TrackZeroNotFound ");
|
||||
if (err & ATA_AMNF) pr_cont("AddrMarkNotFound ");
|
||||
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:
|
||||
if (verbose)
|
||||
printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x "
|
||||
"to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
|
||||
pr_err("ata%u: translated ATA stat/err 0x%02x/%02x to SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n",
|
||||
id, drv_stat, drv_err, *sk, *asc, *ascq);
|
||||
return;
|
||||
}
|
||||
@ -1322,6 +1321,9 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
|
||||
|
||||
blk_queue_flush_queueable(q, false);
|
||||
|
||||
if (dev->flags & ATA_DFLAG_TRUSTED)
|
||||
sdev->security_supported = 1;
|
||||
|
||||
dev->sdev = sdev;
|
||||
return 0;
|
||||
}
|
||||
@ -3127,7 +3129,7 @@ ata_scsi_map_proto(u8 byte1)
|
||||
* ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile
|
||||
* @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:
|
||||
* 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;
|
||||
const u8 *cdb = scmd->cmnd;
|
||||
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;
|
||||
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;
|
||||
|
||||
/* enable LBA */
|
||||
@ -3181,7 +3189,7 @@ static unsigned int ata_scsi_pass_thru(struct ata_queued_cmd *qc)
|
||||
tf->lbah = cdb[12];
|
||||
tf->device = cdb[13];
|
||||
tf->command = cdb[14];
|
||||
} else {
|
||||
} else if (cdb[0] == ATA_12) {
|
||||
/*
|
||||
* 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->device = cdb[8];
|
||||
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 */
|
||||
@ -3564,6 +3596,11 @@ static unsigned int ata_scsiop_maint_in(struct ata_scsi_args *args, u8 *rbuf)
|
||||
dev->class == ATA_DEV_ZAC)
|
||||
supported = 3;
|
||||
break;
|
||||
case SECURITY_PROTOCOL_IN:
|
||||
case SECURITY_PROTOCOL_OUT:
|
||||
if (dev->flags & ATA_DFLAG_TRUSTED)
|
||||
supported = 3;
|
||||
break;
|
||||
default:
|
||||
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
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
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
|
||||
* @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:
|
||||
return ata_scsi_pass_thru;
|
||||
|
||||
case VARIABLE_LENGTH_CMD:
|
||||
return ata_scsi_var_len_cdb_xlat;
|
||||
|
||||
case MODE_SELECT:
|
||||
case MODE_SELECT_10:
|
||||
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:
|
||||
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:
|
||||
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_lun = 1;
|
||||
shost->max_channel = 1;
|
||||
shost->max_cmd_len = 16;
|
||||
shost->max_cmd_len = 32;
|
||||
|
||||
/* Schedule policy is determined by ->qc_defer()
|
||||
* callback and it needs to see every deferred qc.
|
||||
|
@ -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");
|
||||
|
||||
if (PageHighMem(page)) {
|
||||
unsigned long flags;
|
||||
|
||||
/* FIXME: use a bounce buffer */
|
||||
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);
|
||||
}
|
||||
/* do the actual data transfer */
|
||||
buf = kmap_atomic(page);
|
||||
ap->ops->sff_data_xfer(qc, buf + offset, qc->sect_size, do_write);
|
||||
kunmap_atomic(buf);
|
||||
|
||||
if (!do_write && !PageSlab(page))
|
||||
flush_dcache_page(page);
|
||||
@ -861,24 +847,10 @@ next_sg:
|
||||
|
||||
DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
|
||||
|
||||
if (PageHighMem(page)) {
|
||||
unsigned long flags;
|
||||
|
||||
/* FIXME: use bounce buffer */
|
||||
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);
|
||||
}
|
||||
/* do the actual data transfer */
|
||||
buf = kmap_atomic(page);
|
||||
consumed = ap->ops->sff_data_xfer(qc, buf + offset, count, rw);
|
||||
kunmap_atomic(buf);
|
||||
|
||||
bytes -= min(bytes, consumed);
|
||||
qc->curbytes += count;
|
||||
|
@ -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 int 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)
|
||||
|
||||
@ -160,8 +162,6 @@ 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);
|
||||
|
@ -1597,8 +1597,6 @@ static int bfin_atapi_probe(struct platform_device *pdev)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -944,7 +944,6 @@ static int ep93xx_pata_probe(struct platform_device *pdev)
|
||||
goto err_rel_gpio;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, drv_data);
|
||||
drv_data->pdev = pdev;
|
||||
drv_data->ide_base = ide_base;
|
||||
drv_data->udma_in_phys = mem_res->start + IDEUDMADATAIN;
|
||||
|
567
drivers/ata/pata_ftide010.c
Normal file
567
drivers/ata/pata_ftide010.c
Normal 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);
|
@ -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",
|
||||
},
|
||||
|
@ -148,8 +148,6 @@ static int rb532_pata_driver_probe(struct platform_device *pdev)
|
||||
if (!ah)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ah);
|
||||
|
||||
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
@ -292,7 +292,7 @@ static struct ata_port_operations rdc_pata_ops = {
|
||||
.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,
|
||||
.pio_mask = ATA_PIO4,
|
||||
|
@ -582,8 +582,6 @@ static int __init pata_s3c_probe(struct platform_device *pdev)
|
||||
/* Set endianness and enable the interface */
|
||||
pata_s3c_hwinit(info, pdata);
|
||||
|
||||
platform_set_drvdata(pdev, host);
|
||||
|
||||
ret = ata_host_activate(host, info->irq,
|
||||
info->irq ? pata_s3c_irq : NULL,
|
||||
0, &pata_s3c_sht);
|
||||
|
@ -81,7 +81,7 @@ static struct ata_port_operations sch_pata_ops = {
|
||||
.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,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
|
@ -1285,7 +1285,6 @@ static int sata_dwc_probe(struct platform_device *ofdev)
|
||||
if (err)
|
||||
dev_err(&ofdev->dev, "failed to activate host");
|
||||
|
||||
dev_set_drvdata(&ofdev->dev, host);
|
||||
return 0;
|
||||
|
||||
error_out:
|
||||
|
@ -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,
|
||||
&sata_fsl_sht);
|
||||
|
||||
platform_set_drvdata(ofdev, host);
|
||||
|
||||
host_priv->intr_coalescing.show = fsl_sata_intr_coalescing_show;
|
||||
host_priv->intr_coalescing.store = fsl_sata_intr_coalescing_store;
|
||||
sysfs_attr_init(&host_priv->intr_coalescing.attr);
|
||||
|
438
drivers/ata/sata_gemini.c
Normal file
438
drivers/ata/sata_gemini.c
Normal 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
21
drivers/ata/sata_gemini.h
Normal 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
|
@ -737,7 +737,7 @@ static struct ata_port_operations inic_port_ops = {
|
||||
.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,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
|
@ -828,7 +828,7 @@ static void sata_rcar_init_controller(struct ata_host *host)
|
||||
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" */
|
||||
.compatible = "renesas,rcar-sata",
|
||||
|
@ -80,6 +80,10 @@ struct svia_priv {
|
||||
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);
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
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,
|
||||
};
|
||||
|
||||
static struct ata_port_info vt6421_sport_info = {
|
||||
static const struct ata_port_info vt6421_sport_info = {
|
||||
.flags = ATA_FLAG_SATA,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
@ -174,7 +178,7 @@ static struct ata_port_info vt6421_sport_info = {
|
||||
.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,
|
||||
.pio_mask = ATA_PIO4,
|
||||
/* No MWDMA */
|
||||
@ -182,7 +186,7 @@ static struct ata_port_info vt6421_pport_info = {
|
||||
.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,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.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;
|
||||
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);
|
||||
if (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));
|
||||
}
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
if (board_id == vt6421) {
|
||||
if ((board_id == vt6420 && vt6420_hotplug) || board_id == vt6421) {
|
||||
/* enable IRQ on hotplug */
|
||||
pci_read_config_byte(pdev, SVIA_MISC_3, &tmp8);
|
||||
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);
|
||||
|
||||
pci_set_master(pdev);
|
||||
if (board_id == vt6421)
|
||||
return ata_host_activate(host, pdev->irq, vt6421_interrupt,
|
||||
if ((board_id == vt6420 && vt6420_hotplug) || board_id == vt6421)
|
||||
return ata_host_activate(host, pdev->irq, vt642x_interrupt,
|
||||
IRQF_SHARED, &svia_sht);
|
||||
else
|
||||
return ata_host_activate(host, pdev->irq, ata_bmdma_interrupt,
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include <linux/string_helpers.h>
|
||||
#include <linux/async.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sed-opal.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/pr.h>
|
||||
#include <linux/t10-pi.h>
|
||||
@ -643,6 +644,26 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
|
||||
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,
|
||||
unsigned int dix, unsigned int dif)
|
||||
{
|
||||
@ -1454,6 +1475,9 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
if (error)
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
|
||||
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,
|
||||
* 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_app_tag_own(sdkp, buffer);
|
||||
sd_read_write_same(sdkp, buffer);
|
||||
sd_read_security(sdkp, buffer);
|
||||
}
|
||||
|
||||
sdkp->first_scan = 0;
|
||||
@ -3227,6 +3266,12 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
|
||||
|
||||
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",
|
||||
sdp->removable ? "removable " : "");
|
||||
scsi_autopm_put_device(sdp);
|
||||
@ -3376,6 +3421,8 @@ static int sd_remove(struct device *dev)
|
||||
|
||||
sd_zbc_remove(sdkp);
|
||||
|
||||
free_opal_dev(sdkp->opal_dev);
|
||||
|
||||
blk_register_region(devt, SD_MINORS, 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)
|
||||
{
|
||||
struct scsi_disk *sdkp = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */
|
||||
return 0;
|
||||
@ -3536,7 +3584,10 @@ static int sd_resume(struct device *dev)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,6 +71,7 @@ struct scsi_disk {
|
||||
struct scsi_device *device;
|
||||
struct device dev;
|
||||
struct gendisk *disk;
|
||||
struct opal_dev *opal_dev;
|
||||
#ifdef CONFIG_BLK_DEV_ZONED
|
||||
unsigned int nr_zones;
|
||||
unsigned int zone_blocks;
|
||||
@ -114,6 +115,7 @@ struct scsi_disk {
|
||||
unsigned rc_basis: 2;
|
||||
unsigned zoned: 2;
|
||||
unsigned urswrz : 1;
|
||||
unsigned security : 1;
|
||||
unsigned ignore_medium_access_errors : 1;
|
||||
};
|
||||
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev)
|
||||
|
@ -336,11 +336,16 @@ enum {
|
||||
/* READ_LOG_EXT pages */
|
||||
ATA_LOG_DIRECTORY = 0x0,
|
||||
ATA_LOG_SATA_NCQ = 0x10,
|
||||
ATA_LOG_NCQ_NON_DATA = 0x12,
|
||||
ATA_LOG_NCQ_SEND_RECV = 0x13,
|
||||
ATA_LOG_SATA_ID_DEV_DATA = 0x30,
|
||||
ATA_LOG_NCQ_NON_DATA = 0x12,
|
||||
ATA_LOG_NCQ_SEND_RECV = 0x13,
|
||||
ATA_LOG_IDENTIFY_DEVICE = 0x30,
|
||||
|
||||
/* Identify device log pages: */
|
||||
ATA_LOG_SECURITY = 0x06,
|
||||
ATA_LOG_SATA_SETTINGS = 0x08,
|
||||
ATA_LOG_ZONED_INFORMATION = 0x09,
|
||||
|
||||
/* Identify device SATA settings log:*/
|
||||
ATA_LOG_DEVSLP_OFFSET = 0x30,
|
||||
ATA_LOG_DEVSLP_SIZE = 0x08,
|
||||
ATA_LOG_DEVSLP_MDAT = 0x00,
|
||||
|
@ -156,6 +156,7 @@ enum {
|
||||
ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */
|
||||
ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */
|
||||
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_CFG_MASK = (1 << 12) - 1,
|
||||
|
||||
|
@ -176,6 +176,7 @@ struct scsi_device {
|
||||
unsigned no_read_disc_info:1; /* Avoid READ_DISC_INFO cmds */
|
||||
unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */
|
||||
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 wce_default_on:1; /* Cache is ON by default */
|
||||
unsigned no_dif:1; /* T10 PI (DIF) should be disabled */
|
||||
|
@ -162,6 +162,7 @@
|
||||
#define VERIFY_32 0x0a
|
||||
#define WRITE_32 0x0b
|
||||
#define WRITE_SAME_32 0x0d
|
||||
#define ATA_32 0x1ff0
|
||||
|
||||
/* Values for T10/04-262r7 */
|
||||
#define ATA_16 0x85 /* 16-byte pass-thru */
|
||||
|
Loading…
Reference in New Issue
Block a user