]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge branch 'for-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 6 Jul 2017 16:41:58 +0000 (09:41 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 6 Jul 2017 16:41:58 +0000 (09:41 -0700)
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
  ...

36 files changed:
Documentation/devicetree/bindings/ata/cortina,gemini-sata-bridge.txt [new file with mode: 0644]
Documentation/devicetree/bindings/ata/faraday,ftide010.txt [new file with mode: 0644]
MAINTAINERS
drivers/ata/Kconfig
drivers/ata/Makefile
drivers/ata/ahci.c
drivers/ata/ahci.h
drivers/ata/ahci_brcm.c
drivers/ata/ahci_qoriq.c
drivers/ata/libahci.c
drivers/ata/libata-core.c
drivers/ata/libata-eh.c
drivers/ata/libata-scsi.c
drivers/ata/libata-sff.c
drivers/ata/libata.h
drivers/ata/pata_bf54x.c
drivers/ata/pata_ep93xx.c
drivers/ata/pata_ftide010.c [new file with mode: 0644]
drivers/ata/pata_octeon_cf.c
drivers/ata/pata_rb532_cf.c
drivers/ata/pata_rdc.c
drivers/ata/pata_samsung_cf.c
drivers/ata/pata_sch.c
drivers/ata/sata_dwc_460ex.c
drivers/ata/sata_fsl.c
drivers/ata/sata_gemini.c [new file with mode: 0644]
drivers/ata/sata_gemini.h [new file with mode: 0644]
drivers/ata/sata_inic162x.c
drivers/ata/sata_rcar.c
drivers/ata/sata_via.c
drivers/scsi/sd.c
drivers/scsi/sd.h
include/linux/ata.h
include/linux/libata.h
include/scsi/scsi_device.h
include/scsi/scsi_proto.h

diff --git a/Documentation/devicetree/bindings/ata/cortina,gemini-sata-bridge.txt b/Documentation/devicetree/bindings/ata/cortina,gemini-sata-bridge.txt
new file mode 100644 (file)
index 0000000..1c3d3cc
--- /dev/null
@@ -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;
+};
diff --git a/Documentation/devicetree/bindings/ata/faraday,ftide010.txt b/Documentation/devicetree/bindings/ata/faraday,ftide010.txt
new file mode 100644 (file)
index 0000000..a0c64a2
--- /dev/null
@@ -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>;
+};
index b73dddde6455aa794f6641434db4f9ed0f12af48..6ff7aa45151329cf881986e290c807fd82fa0fcf 100644 (file)
@@ -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>
index de3eaf051697601a641440d12687e88258ebc394..948fc86980a1b75d1b9f99e9588bf894e024a88c 100644 (file)
@@ -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
index cd931a5eba922267e0307a833f0b4e1f9f8cec17..a26ef5a939198879e15880cbe1f63bf111d05b9b 100644 (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_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
index 1e1c355121e4aad0e7bdaefdd77bb2a7d8ba72ff..5a5fd0b404eb8467b1b83bf04d9d6768cc9536c9 100644 (file)
@@ -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
index 30f67a1a4f54c42d499dfeb038c24fdaef147ff3..8b61123d2c3c1cd55489feb389b68735077219d5 100644 (file)
@@ -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 */
 
index 6f8a7341fa08a701af61226fab156206b506be20..5936d1679bf3af0e529d36df820e3b8736bfce17 100644 (file)
@@ -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);
index 4c96f3ac4976d9bbc306010ca4fd76bb7d33015e..b6b0bf76dfc7bb7fe90f45418aab974bf73b6f87 100644 (file)
 
 #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);
index 6154f0e2b81a9e88716781b556e88f8cfd40e02c..3e286d86ab42acbc54c84488e74ffc37f13dff65 100644 (file)
@@ -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);
 
index b82d6bb88d275dceef1c8166ef4126e73bfd12dd..8453f9a4682f855e910f59d1d78860f639d4bf59 100644 (file)
@@ -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 */
index 7e33e200aae55ba928ad2a29dcc568b115f6d11d..b70bcf6d2914b6a82967fee346f5865b5c3b66b8 100644 (file)
@@ -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
index b0866f040d1fcd6c935868998e9db637aac4c1ef..d462c5a3a7efd8b3c4933df845c0f3f1d8637bac 100644 (file)
@@ -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;
+
+       /* 7Fh variable length cmd means a ata pass-thru(32) */
+       if (cdb[0] == VARIABLE_LENGTH_CMD)
+               cdb_offset = 9;
 
-       if ((tf->protocol = ata_scsi_map_proto(cdb[1])) == ATA_PROT_UNKNOWN) {
+       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.
index 052921352f31c0c14a4b4ff43a6753a96efeecd4..cc2f2e35f4c2e4ee49a67ef8df5da34cfb182a4e 100644 (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");
 
-       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;
index 5afe35baf61b78139fb1fd7af41727f3da92a8e1..839d487394b7be5ed8966c25571f75fe5b16a8b5 100644 (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 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);
index 9c5780a7e1b925dc668b6bade617d07c0bb0a2a2..0e55a8da274878e89f6f75d573570c77ac238e01 100644 (file)
@@ -1597,8 +1597,6 @@ static int bfin_atapi_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       platform_set_drvdata(pdev, host);
-
        return 0;
 }
 
index bf1b910c5d691b7032b7f1751b62237547f58570..0a550190955ad26915842aff139bd9e09588257b 100644 (file)
@@ -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;
diff --git a/drivers/ata/pata_ftide010.c b/drivers/ata/pata_ftide010.c
new file mode 100644 (file)
index 0000000..5d4b72e
--- /dev/null
@@ -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);
index f524a9099d012017fc068206081d90b59d12b808..1ba03d6df9513bc16a5c3d11f3479b7136a8d34d 100644 (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",
        },
index c8b6a780a29050775f66ec60bc89773d71677683..653b9a0bf7274571c8c7d199956c5e98869fdf02 100644 (file)
@@ -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;
index 9ce5952216bc6e661da18bbba9b7db6730febd6e..959bb54fd80341eab450d8a017e8adf34d8ee9b0 100644 (file)
@@ -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,
index 431c7de30ce64ebd431ddaf01ca87c2127debfad..50801c40b0295229ecc82d7ce52b849f9ac513f1 100644 (file)
@@ -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);
index b920c3407f8b26c8c10f73d9b7c58fc9fd056a2f..1b80a66caa542f12f5c24dd556a53a57a9d355a3 100644 (file)
@@ -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,
index e0939bd5ea73526f7dcc643d4202434bf1f796a1..ce128d5a6ded21b7603d737be439fa89e9050d56 100644 (file)
@@ -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:
index 01734d54c69cdcde06908e89f5e16576348f863d..95bf3abda6f656292be4998d7a28e55c1052065f 100644 (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,
                          &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);
diff --git a/drivers/ata/sata_gemini.c b/drivers/ata/sata_gemini.c
new file mode 100644 (file)
index 0000000..8c70452
--- /dev/null
@@ -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);
diff --git a/drivers/ata/sata_gemini.h b/drivers/ata/sata_gemini.h
new file mode 100644 (file)
index 0000000..ca1837a
--- /dev/null
@@ -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
index e81a8217f1ff7be37ea2c3d61d6d1326f9f55a5e..9b6d7930d1c7940025877657e9062723b40921d4 100644 (file)
@@ -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,
index b7939a2c1fab53ff2a94799a261d401c1c440f2e..ee98447587366f240a580e56a49e0983f58727e2 100644 (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);
 }
 
-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",
index 22e96fc77d09baaf23e1fb56015f55bf6c9ca692..93b8d783936ad01a145dafa5775a44b677a8355c 100644 (file)
@@ -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,
index b6bb4e0ce0e3288f321ef1319621063f02d6c868..8796d908fcddb18c05edea309fbbb19a67878cfd 100644 (file)
@@ -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;
 }
 
 /**
index 61d02efd366c362bee8c6cc49df77bcba67357b7..99c4dde9b6bf83fc2c00d0a8797f38ccaac57542 100644 (file)
@@ -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)
index 73fe18edfdaf962532c60f8ba85340ae9a9cef2a..e65ae4b2ed485a67a26d7c45d542a76d70ab9d97 100644 (file)
@@ -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,
index 9e6633235ad76f928ced2ff8163f44d05ab1e1f5..55de3da58b1c4f5582f95e09a868f6ffb1de852a 100644 (file)
@@ -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,
 
index 05641aebd1811f5141b2bdf63a0f1d82cdace9c1..310c86a892e95e9113a9cbf2e9d0d9ade615df05 100644 (file)
@@ -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 */
index ce78ec8e367da1a34d75136339d9b7e2a088abdf..06076b88d375bc7407939ccd7d9482438812b356 100644 (file)
 #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 */