mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +00:00
ata changes for 6.12
- Convert the qcom AHCI controller DT bindings to DT schema (from Rayyan) - Cleanup of libata core and drivers code handling controller and device quirks to rename "blacklist" to the more neutral "quirk" and to replace the rarely used "horkage" term with the more common "quirk" naming (from me) - Add libata-core message to print the quirks applied to a controller or device (from me) - Remove the not-so-useful function ata_noop_qc_prep() from libata core (from me) - ahci_imx driver cleanup, improvements and DT bindings compatible strings update (from Richard and Dan) - libahci_platform improvements (from Zhang) - Remove obsolete functions declarations from libata header files (from Gaosheng) - Improve teh ahci_brcm driver using managed device resources funetions (from Zhang) - Introduce new helper function to improve libata EH code readability (from Niklas) - Enable module autoloading for the pata_ftide010, pata_ixp4xx and sata_gemini drivers (from Liao) - Move SATA related functions and data declaraions from libata-core to libata-sata (from me) - Rename the function handling the sense data for successful NCQ commands log to better reflect that function actions (from me) - Reduce libata memory usage by moving port resources to struct ata_device and by optimizing the management of resources for CDL capable devices (from me) - Improve libata-eh handling of failed ATA passthrough commands (from Niklas) -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQSRPv8tYSvhwAzJdzjdoc3SxdoYdgUCZuvJ2wAKCRDdoc3SxdoY dhVhAP9Zctzd9Ylb17eO7vVDwA0p7nzqyDxwxWPL8p3FtSm8PQD+PWQaLAPfWmKD X8RqWv9WDGvCGUTEBBSjiZslEp7ccwk= =68kF -----END PGP SIGNATURE----- Merge tag 'ata-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux Pull ata updates from Damien Le Moal: - Convert the qcom AHCI controller DT bindings to DT schema (from Rayyan) - Cleanup of libata core and drivers code handling controller and device quirks to rename "blacklist" to the more neutral "quirk" and to replace the rarely used "horkage" term with the more common "quirk" naming (me) - Add libata-core message to print the quirks applied to a controller or device (me) - Remove the not-so-useful function ata_noop_qc_prep() from libata core (me) - ahci_imx driver cleanup, improvements and DT bindings compatible strings update (Richard and Dan) - libahci_platform improvements (Zhang) - Remove obsolete functions declarations from libata header files (from Gaosheng) - Improve teh ahci_brcm driver using managed device resources funetions (Zhang) - Introduce new helper function to improve libata EH code readability (Niklas) - Enable module autoloading for the pata_ftide010, pata_ixp4xx and sata_gemini drivers (Liao) - Move SATA related functions and data declaraions from libata-core to libata-sata (me) - Rename the function handling the sense data for successful NCQ commands log to better reflect that function actions (me) - Reduce libata memory usage by moving port resources to struct ata_device and by optimizing the management of resources for CDL capable devices (me) - Improve libata-eh handling of failed ATA passthrough commands (Niklas) * tag 'ata-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux: (39 commits) ata: libata: Clear DID_TIME_OUT for ATA PT commands with sense data ata: libata: Fix W=1 compilation warning ata: libata: Improve CDL resource management ata: libata: Introduce ata_dev_free_resources ata: libata: Move sector_buf from struct ata_port to struct ata_device ata: libata: Rename ata_eh_read_sense_success_ncq_log() ata: libata: Move sata_std_hardreset() definition to libata-sata.c ata: libata: Move sata_down_spd_limit() to libata-sata.c ata: libata: Improve __ata_qc_complete() ata: libata-scsi: Improve ata_scsi_handle_link_detach() ata: libata: Cleanup libata-transport ata: sata_gemini: Enable module autoloading ata: pata_ixp4xx: Enable module autoloading ata: pata_ftide010: Enable module autoloading ata: libata: Add helper ata_eh_decide_disposition() ata: ahci_brcm: Use devm_platform_ioremap_resource_byname() helper function ata: libata: Remove obsolete function declarations ata: ahci_imx: Fix error code in probe() ata: libahci_platform: Simplify code with for_each_child_of_node_scoped() ata: ahci_imx: Correct the email address ...
This commit is contained in:
commit
176000734e
@ -30,6 +30,8 @@ select:
|
||||
- marvell,armada-3700-ahci
|
||||
- marvell,armada-8k-ahci
|
||||
- marvell,berlin2q-ahci
|
||||
- qcom,apq8064-ahci
|
||||
- qcom,ipq806x-ahci
|
||||
- socionext,uniphier-pro4-ahci
|
||||
- socionext,uniphier-pxs2-ahci
|
||||
- socionext,uniphier-pxs3-ahci
|
||||
@ -45,6 +47,8 @@ properties:
|
||||
- marvell,armada-8k-ahci
|
||||
- marvell,berlin2-ahci
|
||||
- marvell,berlin2q-ahci
|
||||
- qcom,apq8064-ahci
|
||||
- qcom,ipq806x-ahci
|
||||
- socionext,uniphier-pro4-ahci
|
||||
- socionext,uniphier-pxs2-ahci
|
||||
- socionext,uniphier-pxs3-ahci
|
||||
@ -64,11 +68,11 @@ properties:
|
||||
|
||||
clocks:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
maxItems: 5
|
||||
|
||||
clock-names:
|
||||
minItems: 1
|
||||
maxItems: 3
|
||||
maxItems: 5
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
@ -97,6 +101,31 @@ required:
|
||||
|
||||
allOf:
|
||||
- $ref: ahci-common.yaml#
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,apq8064-ahci
|
||||
- qcom,ipq806x-ahci
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 5
|
||||
clock-names:
|
||||
items:
|
||||
- const: slave_iface
|
||||
- const: iface
|
||||
- const: core
|
||||
- const: rxoob
|
||||
- const: pmalive
|
||||
required:
|
||||
- phys
|
||||
- phy-names
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
@ -19,6 +19,7 @@ properties:
|
||||
- fsl,imx53-ahci
|
||||
- fsl,imx6q-ahci
|
||||
- fsl,imx6qp-ahci
|
||||
- fsl,imx8qm-ahci
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
@ -27,12 +28,14 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
items:
|
||||
- description: sata clock
|
||||
- description: sata reference clock
|
||||
- description: ahb clock
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
items:
|
||||
- const: sata
|
||||
- const: sata_ref
|
||||
@ -58,6 +61,25 @@ properties:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description: if present, disable spread-spectrum clocking on the SATA link.
|
||||
|
||||
phys:
|
||||
items:
|
||||
- description: phandle to SATA PHY.
|
||||
Since "REXT" pin is only present for first lane of i.MX8QM PHY, it's
|
||||
calibration result will be stored, passed through second lane, and
|
||||
shared with all three lanes PHY. The first two lanes PHY are used as
|
||||
calibration PHYs, although only the third lane PHY is used by SATA.
|
||||
- description: phandle to the first lane PHY of i.MX8QM.
|
||||
- description: phandle to the second lane PHY of i.MX8QM.
|
||||
|
||||
phy-names:
|
||||
items:
|
||||
- const: sata-phy
|
||||
- const: cali-phy0
|
||||
- const: cali-phy1
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
@ -65,6 +87,31 @@ required:
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- fsl,imx53-ahci
|
||||
- fsl,imx6q-ahci
|
||||
- fsl,imx6qp-ahci
|
||||
then:
|
||||
properties:
|
||||
clock-names:
|
||||
minItems: 3
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- fsl,imx8qm-ahci
|
||||
then:
|
||||
properties:
|
||||
clock-names:
|
||||
minItems: 2
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
|
@ -1,48 +0,0 @@
|
||||
* Qualcomm AHCI SATA Controller
|
||||
|
||||
SATA nodes are defined to describe on-chip Serial ATA controllers.
|
||||
Each SATA controller should have its own node.
|
||||
|
||||
Required properties:
|
||||
- compatible : compatible list, must contain "generic-ahci"
|
||||
- interrupts : <interrupt mapping for SATA IRQ>
|
||||
- reg : <registers mapping>
|
||||
- phys : Must contain exactly one entry as specified
|
||||
in phy-bindings.txt
|
||||
- phy-names : Must be "sata-phy"
|
||||
|
||||
Required properties for "qcom,ipq806x-ahci" compatible:
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
- clock-names : Shall be:
|
||||
"slave_iface" - Fabric port AHB clock for SATA
|
||||
"iface" - AHB clock
|
||||
"core" - core clock
|
||||
"rxoob" - RX out-of-band clock
|
||||
"pmalive" - Power Module Alive clock
|
||||
- assigned-clocks : Shall be:
|
||||
SATA_RXOOB_CLK
|
||||
SATA_PMALIVE_CLK
|
||||
- assigned-clock-rates : Shall be:
|
||||
100Mhz (100000000) for SATA_RXOOB_CLK
|
||||
100Mhz (100000000) for SATA_PMALIVE_CLK
|
||||
|
||||
Example:
|
||||
sata@29000000 {
|
||||
compatible = "qcom,ipq806x-ahci", "generic-ahci";
|
||||
reg = <0x29000000 0x180>;
|
||||
|
||||
interrupts = <0 209 0x0>;
|
||||
|
||||
clocks = <&gcc SFAB_SATA_S_H_CLK>,
|
||||
<&gcc SATA_H_CLK>,
|
||||
<&gcc SATA_A_CLK>,
|
||||
<&gcc SATA_RXOOB_CLK>,
|
||||
<&gcc SATA_PMALIVE_CLK>;
|
||||
clock-names = "slave_iface", "iface", "core",
|
||||
"rxoob", "pmalive";
|
||||
assigned-clocks = <&gcc SATA_RXOOB_CLK>, <&gcc SATA_PMALIVE_CLK>;
|
||||
assigned-clock-rates = <100000000>, <100000000>;
|
||||
|
||||
phys = <&sata_phy>;
|
||||
phy-names = "sata-phy";
|
||||
};
|
@ -1370,7 +1370,7 @@ static bool ahci_broken_suspend(struct pci_dev *pdev)
|
||||
* V1.03 is known to be broken. V3.04 is known to
|
||||
* work. Between, there are V1.06, V2.06 and V3.03
|
||||
* that we don't have much idea about. For now,
|
||||
* blacklist anything older than V3.04.
|
||||
* assume that anything older than V3.04 is broken.
|
||||
*
|
||||
* http://bugzilla.kernel.org/show_bug.cgi?id=15104
|
||||
*/
|
||||
|
@ -437,7 +437,6 @@ static int brcm_ahci_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct brcm_ahci_priv *priv;
|
||||
struct ahci_host_priv *hpriv;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
@ -451,8 +450,7 @@ static int brcm_ahci_probe(struct platform_device *pdev)
|
||||
priv->version = (unsigned long)of_id->data;
|
||||
priv->dev = dev;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "top-ctrl");
|
||||
priv->top_ctrl = devm_ioremap_resource(dev, res);
|
||||
priv->top_ctrl = devm_platform_ioremap_resource_byname(pdev, "top-ctrl");
|
||||
if (IS_ERR(priv->top_ctrl))
|
||||
return PTR_ERR(priv->top_ctrl);
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/libata.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/thermal.h>
|
||||
#include "ahci.h"
|
||||
|
||||
@ -44,42 +45,10 @@ enum {
|
||||
/* Clock Reset Register */
|
||||
IMX_CLOCK_RESET = 0x7f3f,
|
||||
IMX_CLOCK_RESET_RESET = 1 << 0,
|
||||
/* IMX8QM HSIO AHCI definitions */
|
||||
IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET = 0x03,
|
||||
IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET = 0x09,
|
||||
IMX8QM_SATA_PHY_IMPED_RATIO_85OHM = 0x6c,
|
||||
IMX8QM_LPCG_PHYX2_OFFSET = 0x00000,
|
||||
IMX8QM_CSR_PHYX2_OFFSET = 0x90000,
|
||||
IMX8QM_CSR_PHYX1_OFFSET = 0xa0000,
|
||||
IMX8QM_CSR_PHYX_STTS0_OFFSET = 0x4,
|
||||
IMX8QM_CSR_PCIEA_OFFSET = 0xb0000,
|
||||
IMX8QM_CSR_PCIEB_OFFSET = 0xc0000,
|
||||
IMX8QM_CSR_SATA_OFFSET = 0xd0000,
|
||||
IMX8QM_CSR_PCIE_CTRL2_OFFSET = 0x8,
|
||||
IMX8QM_CSR_MISC_OFFSET = 0xe0000,
|
||||
|
||||
IMX8QM_LPCG_PHYX2_PCLK0_MASK = (0x3 << 16),
|
||||
IMX8QM_LPCG_PHYX2_PCLK1_MASK = (0x3 << 20),
|
||||
IMX8QM_PHY_APB_RSTN_0 = BIT(0),
|
||||
IMX8QM_PHY_MODE_SATA = BIT(19),
|
||||
IMX8QM_PHY_MODE_MASK = (0xf << 17),
|
||||
IMX8QM_PHY_PIPE_RSTN_0 = BIT(24),
|
||||
IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0 = BIT(25),
|
||||
IMX8QM_PHY_PIPE_RSTN_1 = BIT(26),
|
||||
IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1 = BIT(27),
|
||||
IMX8QM_STTS0_LANE0_TX_PLL_LOCK = BIT(4),
|
||||
IMX8QM_MISC_IOB_RXENA = BIT(0),
|
||||
IMX8QM_MISC_IOB_TXENA = BIT(1),
|
||||
IMX8QM_MISC_PHYX1_EPCS_SEL = BIT(12),
|
||||
IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 = BIT(24),
|
||||
IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 = BIT(25),
|
||||
IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 = BIT(28),
|
||||
IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0 = BIT(29),
|
||||
IMX8QM_SATA_CTRL_RESET_N = BIT(12),
|
||||
IMX8QM_SATA_CTRL_EPCS_PHYRESET_N = BIT(7),
|
||||
IMX8QM_CTRL_BUTTON_RST_N = BIT(21),
|
||||
IMX8QM_CTRL_POWER_UP_RST_N = BIT(23),
|
||||
IMX8QM_CTRL_LTSSM_ENABLE = BIT(4),
|
||||
/* IMX8QM SATA specific control registers */
|
||||
IMX8QM_SATA_AHCI_PTC = 0xc8,
|
||||
IMX8QM_SATA_AHCI_PTC_RXWM_MASK = GENMASK(6, 0),
|
||||
IMX8QM_SATA_AHCI_PTC_RXWM = 0x29,
|
||||
};
|
||||
|
||||
enum ahci_imx_type {
|
||||
@ -95,14 +64,10 @@ struct imx_ahci_priv {
|
||||
struct clk *sata_clk;
|
||||
struct clk *sata_ref_clk;
|
||||
struct clk *ahb_clk;
|
||||
struct clk *epcs_tx_clk;
|
||||
struct clk *epcs_rx_clk;
|
||||
struct clk *phy_apbclk;
|
||||
struct clk *phy_pclk0;
|
||||
struct clk *phy_pclk1;
|
||||
void __iomem *phy_base;
|
||||
struct gpio_desc *clkreq_gpiod;
|
||||
struct regmap *gpr;
|
||||
struct phy *sata_phy;
|
||||
struct phy *cali_phy0;
|
||||
struct phy *cali_phy1;
|
||||
bool no_device;
|
||||
bool first_time;
|
||||
u32 phy_params;
|
||||
@ -450,201 +415,79 @@ ATTRIBUTE_GROUPS(fsl_sata_ahci);
|
||||
|
||||
static int imx8_sata_enable(struct ahci_host_priv *hpriv)
|
||||
{
|
||||
u32 val, reg;
|
||||
int i, ret;
|
||||
u32 val;
|
||||
int ret;
|
||||
struct imx_ahci_priv *imxpriv = hpriv->plat_data;
|
||||
struct device *dev = &imxpriv->ahci_pdev->dev;
|
||||
|
||||
/* configure the hsio for sata */
|
||||
ret = clk_prepare_enable(imxpriv->phy_pclk0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't enable phy_pclk0.\n");
|
||||
/*
|
||||
* Since "REXT" pin is only present for first lane of i.MX8QM
|
||||
* PHY, its calibration results will be stored, passed through
|
||||
* to the second lane PHY, and shared with all three lane PHYs.
|
||||
*
|
||||
* Initialize the first two lane PHYs here, although only the
|
||||
* third lane PHY is used by SATA.
|
||||
*/
|
||||
ret = phy_init(imxpriv->cali_phy0);
|
||||
if (ret) {
|
||||
dev_err(dev, "cali PHY init failed\n");
|
||||
return ret;
|
||||
}
|
||||
ret = clk_prepare_enable(imxpriv->phy_pclk1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't enable phy_pclk1.\n");
|
||||
goto disable_phy_pclk0;
|
||||
ret = phy_power_on(imxpriv->cali_phy0);
|
||||
if (ret) {
|
||||
dev_err(dev, "cali PHY power on failed\n");
|
||||
goto err_cali_phy0_exit;
|
||||
}
|
||||
ret = clk_prepare_enable(imxpriv->epcs_tx_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't enable epcs_tx_clk.\n");
|
||||
goto disable_phy_pclk1;
|
||||
ret = phy_init(imxpriv->cali_phy1);
|
||||
if (ret) {
|
||||
dev_err(dev, "cali PHY1 init failed\n");
|
||||
goto err_cali_phy0_off;
|
||||
}
|
||||
ret = clk_prepare_enable(imxpriv->epcs_rx_clk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't enable epcs_rx_clk.\n");
|
||||
goto disable_epcs_tx_clk;
|
||||
ret = phy_power_on(imxpriv->cali_phy1);
|
||||
if (ret) {
|
||||
dev_err(dev, "cali PHY1 power on failed\n");
|
||||
goto err_cali_phy1_exit;
|
||||
}
|
||||
ret = clk_prepare_enable(imxpriv->phy_apbclk);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "can't enable phy_apbclk.\n");
|
||||
goto disable_epcs_rx_clk;
|
||||
ret = phy_init(imxpriv->sata_phy);
|
||||
if (ret) {
|
||||
dev_err(dev, "sata PHY init failed\n");
|
||||
goto err_cali_phy1_off;
|
||||
}
|
||||
/* Configure PHYx2 PIPE_RSTN */
|
||||
regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEA_OFFSET +
|
||||
IMX8QM_CSR_PCIE_CTRL2_OFFSET, &val);
|
||||
if ((val & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
|
||||
/* The link of the PCIEA of HSIO is down */
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_PHYX2_OFFSET,
|
||||
IMX8QM_PHY_PIPE_RSTN_0 |
|
||||
IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0,
|
||||
IMX8QM_PHY_PIPE_RSTN_0 |
|
||||
IMX8QM_PHY_PIPE_RSTN_OVERRIDE_0);
|
||||
ret = phy_set_mode(imxpriv->sata_phy, PHY_MODE_SATA);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to set SATA PHY mode\n");
|
||||
goto err_sata_phy_exit;
|
||||
}
|
||||
regmap_read(imxpriv->gpr, IMX8QM_CSR_PCIEB_OFFSET +
|
||||
IMX8QM_CSR_PCIE_CTRL2_OFFSET, ®);
|
||||
if ((reg & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
|
||||
/* The link of the PCIEB of HSIO is down */
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_PHYX2_OFFSET,
|
||||
IMX8QM_PHY_PIPE_RSTN_1 |
|
||||
IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1,
|
||||
IMX8QM_PHY_PIPE_RSTN_1 |
|
||||
IMX8QM_PHY_PIPE_RSTN_OVERRIDE_1);
|
||||
}
|
||||
if (((reg | val) & IMX8QM_CTRL_LTSSM_ENABLE) == 0) {
|
||||
/* The links of both PCIA and PCIEB of HSIO are down */
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_LPCG_PHYX2_OFFSET,
|
||||
IMX8QM_LPCG_PHYX2_PCLK0_MASK |
|
||||
IMX8QM_LPCG_PHYX2_PCLK1_MASK,
|
||||
0);
|
||||
ret = phy_power_on(imxpriv->sata_phy);
|
||||
if (ret) {
|
||||
dev_err(dev, "sata PHY power up failed\n");
|
||||
goto err_sata_phy_exit;
|
||||
}
|
||||
|
||||
/* set PWR_RST and BT_RST of csr_pciea */
|
||||
val = IMX8QM_CSR_PCIEA_OFFSET + IMX8QM_CSR_PCIE_CTRL2_OFFSET;
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
val,
|
||||
IMX8QM_CTRL_BUTTON_RST_N,
|
||||
IMX8QM_CTRL_BUTTON_RST_N);
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
val,
|
||||
IMX8QM_CTRL_POWER_UP_RST_N,
|
||||
IMX8QM_CTRL_POWER_UP_RST_N);
|
||||
/* The cali_phy# can be turned off after SATA PHY is initialized. */
|
||||
phy_power_off(imxpriv->cali_phy1);
|
||||
phy_exit(imxpriv->cali_phy1);
|
||||
phy_power_off(imxpriv->cali_phy0);
|
||||
phy_exit(imxpriv->cali_phy0);
|
||||
|
||||
/* PHYX1_MODE to SATA */
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_PHYX1_OFFSET,
|
||||
IMX8QM_PHY_MODE_MASK,
|
||||
IMX8QM_PHY_MODE_SATA);
|
||||
/* RxWaterMark setting */
|
||||
val = readl(hpriv->mmio + IMX8QM_SATA_AHCI_PTC);
|
||||
val &= ~IMX8QM_SATA_AHCI_PTC_RXWM_MASK;
|
||||
val |= IMX8QM_SATA_AHCI_PTC_RXWM;
|
||||
writel(val, hpriv->mmio + IMX8QM_SATA_AHCI_PTC);
|
||||
|
||||
/*
|
||||
* BIT0 RXENA 1, BIT1 TXENA 0
|
||||
* BIT12 PHY_X1_EPCS_SEL 1.
|
||||
*/
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_MISC_OFFSET,
|
||||
IMX8QM_MISC_IOB_RXENA,
|
||||
IMX8QM_MISC_IOB_RXENA);
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_MISC_OFFSET,
|
||||
IMX8QM_MISC_IOB_TXENA,
|
||||
0);
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_MISC_OFFSET,
|
||||
IMX8QM_MISC_PHYX1_EPCS_SEL,
|
||||
IMX8QM_MISC_PHYX1_EPCS_SEL);
|
||||
/*
|
||||
* It is possible, for PCIe and SATA are sharing
|
||||
* the same clock source, HPLL or external oscillator.
|
||||
* When PCIe is in low power modes (L1.X or L2 etc),
|
||||
* the clock source can be turned off. In this case,
|
||||
* if this clock source is required to be toggling by
|
||||
* SATA, then SATA functions will be abnormal.
|
||||
* Set the override here to avoid it.
|
||||
*/
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_MISC_OFFSET,
|
||||
IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 |
|
||||
IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 |
|
||||
IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 |
|
||||
IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0,
|
||||
IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_1 |
|
||||
IMX8QM_MISC_CLKREQN_OUT_OVERRIDE_0 |
|
||||
IMX8QM_MISC_CLKREQN_IN_OVERRIDE_1 |
|
||||
IMX8QM_MISC_CLKREQN_IN_OVERRIDE_0);
|
||||
return 0;
|
||||
|
||||
/* clear PHY RST, then set it */
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_SATA_OFFSET,
|
||||
IMX8QM_SATA_CTRL_EPCS_PHYRESET_N,
|
||||
0);
|
||||
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_SATA_OFFSET,
|
||||
IMX8QM_SATA_CTRL_EPCS_PHYRESET_N,
|
||||
IMX8QM_SATA_CTRL_EPCS_PHYRESET_N);
|
||||
|
||||
/* CTRL RST: SET -> delay 1 us -> CLEAR -> SET */
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_SATA_OFFSET,
|
||||
IMX8QM_SATA_CTRL_RESET_N,
|
||||
IMX8QM_SATA_CTRL_RESET_N);
|
||||
udelay(1);
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_SATA_OFFSET,
|
||||
IMX8QM_SATA_CTRL_RESET_N,
|
||||
0);
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_SATA_OFFSET,
|
||||
IMX8QM_SATA_CTRL_RESET_N,
|
||||
IMX8QM_SATA_CTRL_RESET_N);
|
||||
|
||||
/* APB reset */
|
||||
regmap_update_bits(imxpriv->gpr,
|
||||
IMX8QM_CSR_PHYX1_OFFSET,
|
||||
IMX8QM_PHY_APB_RSTN_0,
|
||||
IMX8QM_PHY_APB_RSTN_0);
|
||||
|
||||
for (i = 0; i < 100; i++) {
|
||||
reg = IMX8QM_CSR_PHYX1_OFFSET +
|
||||
IMX8QM_CSR_PHYX_STTS0_OFFSET;
|
||||
regmap_read(imxpriv->gpr, reg, &val);
|
||||
val &= IMX8QM_STTS0_LANE0_TX_PLL_LOCK;
|
||||
if (val == IMX8QM_STTS0_LANE0_TX_PLL_LOCK)
|
||||
break;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
if (val != IMX8QM_STTS0_LANE0_TX_PLL_LOCK) {
|
||||
dev_err(dev, "TX PLL of the PHY is not locked\n");
|
||||
ret = -ENODEV;
|
||||
} else {
|
||||
writeb(imxpriv->imped_ratio, imxpriv->phy_base +
|
||||
IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET);
|
||||
writeb(imxpriv->imped_ratio, imxpriv->phy_base +
|
||||
IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET);
|
||||
reg = readb(imxpriv->phy_base +
|
||||
IMX8QM_SATA_PHY_RX_IMPED_RATIO_OFFSET);
|
||||
if (unlikely(reg != imxpriv->imped_ratio))
|
||||
dev_info(dev, "Can't set PHY RX impedance ratio.\n");
|
||||
reg = readb(imxpriv->phy_base +
|
||||
IMX8QM_SATA_PHY_TX_IMPED_RATIO_OFFSET);
|
||||
if (unlikely(reg != imxpriv->imped_ratio))
|
||||
dev_info(dev, "Can't set PHY TX impedance ratio.\n");
|
||||
usleep_range(50, 100);
|
||||
|
||||
/*
|
||||
* To reduce the power consumption, gate off
|
||||
* the PHY clks
|
||||
*/
|
||||
clk_disable_unprepare(imxpriv->phy_apbclk);
|
||||
clk_disable_unprepare(imxpriv->phy_pclk1);
|
||||
clk_disable_unprepare(imxpriv->phy_pclk0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
clk_disable_unprepare(imxpriv->phy_apbclk);
|
||||
disable_epcs_rx_clk:
|
||||
clk_disable_unprepare(imxpriv->epcs_rx_clk);
|
||||
disable_epcs_tx_clk:
|
||||
clk_disable_unprepare(imxpriv->epcs_tx_clk);
|
||||
disable_phy_pclk1:
|
||||
clk_disable_unprepare(imxpriv->phy_pclk1);
|
||||
disable_phy_pclk0:
|
||||
clk_disable_unprepare(imxpriv->phy_pclk0);
|
||||
err_sata_phy_exit:
|
||||
phy_exit(imxpriv->sata_phy);
|
||||
err_cali_phy1_off:
|
||||
phy_power_off(imxpriv->cali_phy1);
|
||||
err_cali_phy1_exit:
|
||||
phy_exit(imxpriv->cali_phy1);
|
||||
err_cali_phy0_off:
|
||||
phy_power_off(imxpriv->cali_phy0);
|
||||
err_cali_phy0_exit:
|
||||
phy_exit(imxpriv->cali_phy0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -698,6 +541,9 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
|
||||
}
|
||||
} else if (imxpriv->type == AHCI_IMX8QM) {
|
||||
ret = imx8_sata_enable(hpriv);
|
||||
if (ret)
|
||||
goto disable_clk;
|
||||
|
||||
}
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
@ -736,8 +582,10 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv)
|
||||
break;
|
||||
|
||||
case AHCI_IMX8QM:
|
||||
clk_disable_unprepare(imxpriv->epcs_rx_clk);
|
||||
clk_disable_unprepare(imxpriv->epcs_tx_clk);
|
||||
if (imxpriv->sata_phy) {
|
||||
phy_power_off(imxpriv->sata_phy);
|
||||
phy_exit(imxpriv->sata_phy);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -760,6 +608,9 @@ static void ahci_imx_error_handler(struct ata_port *ap)
|
||||
|
||||
ahci_error_handler(ap);
|
||||
|
||||
if (imxpriv->type == AHCI_IMX8QM)
|
||||
return;
|
||||
|
||||
if (!(imxpriv->first_time) || ahci_imx_hotplug)
|
||||
return;
|
||||
|
||||
@ -986,65 +837,19 @@ static const struct scsi_host_template ahci_platform_sht = {
|
||||
|
||||
static int imx8_sata_probe(struct device *dev, struct imx_ahci_priv *imxpriv)
|
||||
{
|
||||
struct resource *phy_res;
|
||||
struct platform_device *pdev = imxpriv->ahci_pdev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
if (of_property_read_u32(np, "fsl,phy-imp", &imxpriv->imped_ratio))
|
||||
imxpriv->imped_ratio = IMX8QM_SATA_PHY_IMPED_RATIO_85OHM;
|
||||
phy_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
|
||||
if (phy_res) {
|
||||
imxpriv->phy_base = devm_ioremap(dev, phy_res->start,
|
||||
resource_size(phy_res));
|
||||
if (!imxpriv->phy_base) {
|
||||
dev_err(dev, "error with ioremap\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
dev_err(dev, "missing *phy* reg region.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
imxpriv->gpr =
|
||||
syscon_regmap_lookup_by_phandle(np, "hsio");
|
||||
if (IS_ERR(imxpriv->gpr)) {
|
||||
dev_err(dev, "unable to find gpr registers\n");
|
||||
return PTR_ERR(imxpriv->gpr);
|
||||
}
|
||||
|
||||
imxpriv->epcs_tx_clk = devm_clk_get(dev, "epcs_tx");
|
||||
if (IS_ERR(imxpriv->epcs_tx_clk)) {
|
||||
dev_err(dev, "can't get epcs_tx_clk clock.\n");
|
||||
return PTR_ERR(imxpriv->epcs_tx_clk);
|
||||
}
|
||||
imxpriv->epcs_rx_clk = devm_clk_get(dev, "epcs_rx");
|
||||
if (IS_ERR(imxpriv->epcs_rx_clk)) {
|
||||
dev_err(dev, "can't get epcs_rx_clk clock.\n");
|
||||
return PTR_ERR(imxpriv->epcs_rx_clk);
|
||||
}
|
||||
imxpriv->phy_pclk0 = devm_clk_get(dev, "phy_pclk0");
|
||||
if (IS_ERR(imxpriv->phy_pclk0)) {
|
||||
dev_err(dev, "can't get phy_pclk0 clock.\n");
|
||||
return PTR_ERR(imxpriv->phy_pclk0);
|
||||
}
|
||||
imxpriv->phy_pclk1 = devm_clk_get(dev, "phy_pclk1");
|
||||
if (IS_ERR(imxpriv->phy_pclk1)) {
|
||||
dev_err(dev, "can't get phy_pclk1 clock.\n");
|
||||
return PTR_ERR(imxpriv->phy_pclk1);
|
||||
}
|
||||
imxpriv->phy_apbclk = devm_clk_get(dev, "phy_apbclk");
|
||||
if (IS_ERR(imxpriv->phy_apbclk)) {
|
||||
dev_err(dev, "can't get phy_apbclk clock.\n");
|
||||
return PTR_ERR(imxpriv->phy_apbclk);
|
||||
}
|
||||
|
||||
/* Fetch GPIO, then enable the external OSC */
|
||||
imxpriv->clkreq_gpiod = devm_gpiod_get_optional(dev, "clkreq",
|
||||
GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE);
|
||||
if (IS_ERR(imxpriv->clkreq_gpiod))
|
||||
return PTR_ERR(imxpriv->clkreq_gpiod);
|
||||
if (imxpriv->clkreq_gpiod)
|
||||
gpiod_set_consumer_name(imxpriv->clkreq_gpiod, "SATA CLKREQ");
|
||||
imxpriv->sata_phy = devm_phy_get(dev, "sata-phy");
|
||||
if (IS_ERR(imxpriv->sata_phy))
|
||||
return dev_err_probe(dev, PTR_ERR(imxpriv->sata_phy),
|
||||
"Failed to get sata_phy\n");
|
||||
|
||||
imxpriv->cali_phy0 = devm_phy_get(dev, "cali-phy0");
|
||||
if (IS_ERR(imxpriv->cali_phy0))
|
||||
return dev_err_probe(dev, PTR_ERR(imxpriv->cali_phy0),
|
||||
"Failed to get cali_phy0\n");
|
||||
imxpriv->cali_phy1 = devm_phy_get(dev, "cali-phy1");
|
||||
if (IS_ERR(imxpriv->cali_phy1))
|
||||
return dev_err_probe(dev, PTR_ERR(imxpriv->cali_phy1),
|
||||
"Failed to get cali_phy1\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1077,12 +882,6 @@ static int imx_ahci_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(imxpriv->sata_ref_clk);
|
||||
}
|
||||
|
||||
imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
|
||||
if (IS_ERR(imxpriv->ahb_clk)) {
|
||||
dev_err(dev, "can't get ahb clock.\n");
|
||||
return PTR_ERR(imxpriv->ahb_clk);
|
||||
}
|
||||
|
||||
if (imxpriv->type == AHCI_IMX6Q || imxpriv->type == AHCI_IMX6QP) {
|
||||
u32 reg_value;
|
||||
|
||||
@ -1142,11 +941,8 @@ static int imx_ahci_probe(struct platform_device *pdev)
|
||||
goto disable_clk;
|
||||
|
||||
/*
|
||||
* Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL,
|
||||
* and IP vendor specific register IMX_TIMER1MS.
|
||||
* Configure CAP_SSS (support stagered spin up).
|
||||
* Implement the port0.
|
||||
* Get the ahb clock rate, and configure the TIMER1MS register.
|
||||
* Configure the HWINIT bits of the HOST_CAP and HOST_PORTS_IMPL.
|
||||
* Set CAP_SSS (support stagered spin up) and Implement the port0.
|
||||
*/
|
||||
reg_val = readl(hpriv->mmio + HOST_CAP);
|
||||
if (!(reg_val & HOST_CAP_SSS)) {
|
||||
@ -1159,8 +955,20 @@ static int imx_ahci_probe(struct platform_device *pdev)
|
||||
writel(reg_val, hpriv->mmio + HOST_PORTS_IMPL);
|
||||
}
|
||||
|
||||
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
|
||||
writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
|
||||
if (imxpriv->type != AHCI_IMX8QM) {
|
||||
/*
|
||||
* Get AHB clock rate and configure the vendor specified
|
||||
* TIMER1MS register on i.MX53, i.MX6Q and i.MX6QP only.
|
||||
*/
|
||||
imxpriv->ahb_clk = devm_clk_get(dev, "ahb");
|
||||
if (IS_ERR(imxpriv->ahb_clk)) {
|
||||
dev_err(dev, "Failed to get ahb clock\n");
|
||||
ret = PTR_ERR(imxpriv->ahb_clk);
|
||||
goto disable_sata;
|
||||
}
|
||||
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
|
||||
writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
|
||||
}
|
||||
|
||||
ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info,
|
||||
&ahci_platform_sht);
|
||||
@ -1229,6 +1037,6 @@ static struct platform_driver imx_ahci_driver = {
|
||||
module_platform_driver(imx_ahci_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Freescale i.MX AHCI SATA platform driver");
|
||||
MODULE_AUTHOR("Richard Zhu <Hong-Xing.Zhu@freescale.com>");
|
||||
MODULE_AUTHOR("Richard Zhu <hongxing.zhu@nxp.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
@ -1446,7 +1446,6 @@ static int piix_init_sidpr(struct ata_host *host)
|
||||
if (hpriv->map[i] == IDE)
|
||||
return 0;
|
||||
|
||||
/* is it blacklisted? */
|
||||
if (piix_no_sidpr(host))
|
||||
return 0;
|
||||
|
||||
|
@ -410,7 +410,6 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
|
||||
static int ahci_platform_get_firmware(struct ahci_host_priv *hpriv,
|
||||
struct device *dev)
|
||||
{
|
||||
struct device_node *child;
|
||||
u32 port;
|
||||
|
||||
if (!of_property_read_u32(dev->of_node, "hba-cap", &hpriv->saved_cap))
|
||||
@ -419,14 +418,12 @@ static int ahci_platform_get_firmware(struct ahci_host_priv *hpriv,
|
||||
of_property_read_u32(dev->of_node,
|
||||
"ports-implemented", &hpriv->saved_port_map);
|
||||
|
||||
for_each_child_of_node(dev->of_node, child) {
|
||||
for_each_child_of_node_scoped(dev->of_node, child) {
|
||||
if (!of_device_is_available(child))
|
||||
continue;
|
||||
|
||||
if (of_property_read_u32(child, "reg", &port)) {
|
||||
of_node_put(child);
|
||||
if (of_property_read_u32(child, "reg", &port))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!of_property_read_u32(child, "hba-port-cap", &hpriv->saved_port_cap[port]))
|
||||
hpriv->saved_port_cap[port] &= PORT_CMD_CAP;
|
||||
@ -460,7 +457,6 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
||||
int child_nodes, rc = -ENOMEM, enabled_ports = 0;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct ahci_host_priv *hpriv;
|
||||
struct device_node *child;
|
||||
u32 mask_port_map = 0;
|
||||
|
||||
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
||||
@ -579,7 +575,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
if (child_nodes) {
|
||||
for_each_child_of_node(dev->of_node, child) {
|
||||
for_each_child_of_node_scoped(dev->of_node, child) {
|
||||
u32 port;
|
||||
struct platform_device *port_dev __maybe_unused;
|
||||
|
||||
@ -588,7 +584,6 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
||||
|
||||
if (of_property_read_u32(child, "reg", &port)) {
|
||||
rc = -EINVAL;
|
||||
of_node_put(child);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
@ -606,18 +601,14 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
||||
if (port_dev) {
|
||||
rc = ahci_platform_get_regulator(hpriv, port,
|
||||
&port_dev->dev);
|
||||
if (rc == -EPROBE_DEFER) {
|
||||
of_node_put(child);
|
||||
if (rc == -EPROBE_DEFER)
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = ahci_platform_get_phy(hpriv, port, dev, child);
|
||||
if (rc) {
|
||||
of_node_put(child);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
enabled_ports++;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -500,10 +500,13 @@ static void ata_eh_dev_disable(struct ata_device *dev)
|
||||
ata_down_xfermask_limit(dev, ATA_DNXFER_FORCE_PIO0 | ATA_DNXFER_QUIET);
|
||||
dev->class++;
|
||||
|
||||
/* From now till the next successful probe, ering is used to
|
||||
/*
|
||||
* From now till the next successful probe, ering is used to
|
||||
* track probe failures. Clear accumulated device error info.
|
||||
*/
|
||||
ata_ering_clear(&dev->ering);
|
||||
|
||||
ata_dev_free_resources(dev);
|
||||
}
|
||||
|
||||
static void ata_eh_unload(struct ata_port *ap)
|
||||
@ -630,6 +633,14 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
|
||||
list_for_each_entry_safe(scmd, tmp, eh_work_q, eh_entry) {
|
||||
struct ata_queued_cmd *qc;
|
||||
|
||||
/*
|
||||
* If the scmd was added to EH, via ata_qc_schedule_eh() ->
|
||||
* scsi_timeout() -> scsi_eh_scmd_add(), scsi_timeout() will
|
||||
* have set DID_TIME_OUT (since libata does not have an abort
|
||||
* handler). Thus, to clear DID_TIME_OUT, clear the host byte.
|
||||
*/
|
||||
set_host_byte(scmd, DID_OK);
|
||||
|
||||
ata_qc_for_each_raw(ap, qc, i) {
|
||||
if (qc->flags & ATA_QCFLAG_ACTIVE &&
|
||||
qc->scsicmd == scmd)
|
||||
@ -1401,6 +1412,43 @@ unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key)
|
||||
return err_mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_eh_decide_disposition - Disposition a qc based on sense data
|
||||
* @qc: qc to examine
|
||||
*
|
||||
* For a regular SCSI command, the SCSI completion callback (scsi_done())
|
||||
* will call scsi_complete(), which will call scsi_decide_disposition(),
|
||||
* which will call scsi_check_sense(). scsi_complete() finally calls
|
||||
* scsi_finish_command(). This is fine for SCSI, since any eventual sense
|
||||
* data is usually returned in the completion itself (without invoking SCSI
|
||||
* EH). However, for a QC, we always need to fetch the sense data
|
||||
* explicitly using SCSI EH.
|
||||
*
|
||||
* A command that is completed via SCSI EH will instead be completed using
|
||||
* scsi_eh_flush_done_q(), which will call scsi_finish_command() directly
|
||||
* (without ever calling scsi_check_sense()).
|
||||
*
|
||||
* For a command that went through SCSI EH, it is the responsibility of the
|
||||
* SCSI EH strategy handler to call scsi_decide_disposition(), see e.g. how
|
||||
* scsi_eh_get_sense() calls scsi_decide_disposition() for SCSI LLDDs that
|
||||
* do not get the sense data as part of the completion.
|
||||
*
|
||||
* Thus, for QC commands that went via SCSI EH, we need to call
|
||||
* scsi_check_sense() ourselves, similar to how scsi_eh_get_sense() calls
|
||||
* scsi_decide_disposition(), which calls scsi_check_sense(), in order to
|
||||
* set the correct SCSI ML byte (if any).
|
||||
*
|
||||
* LOCKING:
|
||||
* EH context.
|
||||
*
|
||||
* RETURNS:
|
||||
* SUCCESS or FAILED or NEEDS_RETRY or ADD_TO_MLQUEUE
|
||||
*/
|
||||
enum scsi_disposition ata_eh_decide_disposition(struct ata_queued_cmd *qc)
|
||||
{
|
||||
return scsi_check_sense(qc->scsicmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_eh_request_sense - perform REQUEST_SENSE_DATA_EXT
|
||||
* @qc: qc to perform REQUEST_SENSE_SENSE_DATA_EXT to
|
||||
@ -1627,7 +1675,8 @@ static unsigned int ata_eh_analyze_tf(struct ata_queued_cmd *qc)
|
||||
}
|
||||
|
||||
if (qc->flags & ATA_QCFLAG_SENSE_VALID) {
|
||||
enum scsi_disposition ret = scsi_check_sense(qc->scsicmd);
|
||||
enum scsi_disposition ret = ata_eh_decide_disposition(qc);
|
||||
|
||||
/*
|
||||
* SUCCESS here means that the sense code could be
|
||||
* evaluated and should be passed to the upper layers
|
||||
@ -1924,7 +1973,7 @@ static inline bool ata_eh_quiet(struct ata_queued_cmd *qc)
|
||||
return qc->flags & ATA_QCFLAG_QUIET;
|
||||
}
|
||||
|
||||
static int ata_eh_read_sense_success_non_ncq(struct ata_link *link)
|
||||
static int ata_eh_get_non_ncq_success_sense(struct ata_link *link)
|
||||
{
|
||||
struct ata_port *ap = link->ap;
|
||||
struct ata_queued_cmd *qc;
|
||||
@ -1942,11 +1991,10 @@ static int ata_eh_read_sense_success_non_ncq(struct ata_link *link)
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* If we have sense data, call scsi_check_sense() in order to set the
|
||||
* correct SCSI ML byte (if any). No point in checking the return value,
|
||||
* since the command has already completed successfully.
|
||||
* No point in checking the return value, since the command has already
|
||||
* completed successfully.
|
||||
*/
|
||||
scsi_check_sense(qc->scsicmd);
|
||||
ata_eh_decide_disposition(qc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1976,9 +2024,9 @@ static void ata_eh_get_success_sense(struct ata_link *link)
|
||||
* request sense ext command to retrieve the sense data.
|
||||
*/
|
||||
if (link->sactive)
|
||||
ret = ata_eh_read_sense_success_ncq_log(link);
|
||||
ret = ata_eh_get_ncq_success_sense(link);
|
||||
else
|
||||
ret = ata_eh_read_sense_success_non_ncq(link);
|
||||
ret = ata_eh_get_non_ncq_success_sense(link);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
@ -3247,7 +3295,7 @@ static int atapi_eh_clear_ua(struct ata_device *dev)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ATA_EH_UA_TRIES; i++) {
|
||||
u8 *sense_buffer = dev->link->ap->sector_buf;
|
||||
u8 *sense_buffer = dev->sector_buf;
|
||||
u8 sense_key = 0;
|
||||
unsigned int err_mask;
|
||||
|
||||
|
@ -648,8 +648,7 @@ static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
|
||||
static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
|
||||
{
|
||||
struct ata_link *link = dev->link;
|
||||
struct ata_port *ap = link->ap;
|
||||
u32 *gscr = (void *)ap->sector_buf;
|
||||
u32 *gscr = (void *)dev->sector_buf;
|
||||
int rc;
|
||||
|
||||
ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE);
|
||||
|
@ -517,6 +517,86 @@ int sata_set_spd(struct ata_link *link)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sata_set_spd);
|
||||
|
||||
/**
|
||||
* sata_down_spd_limit - adjust SATA spd limit downward
|
||||
* @link: Link to adjust SATA spd limit for
|
||||
* @spd_limit: Additional limit
|
||||
*
|
||||
* Adjust SATA spd limit of @link downward. Note that this
|
||||
* function only adjusts the limit. The change must be applied
|
||||
* using sata_set_spd().
|
||||
*
|
||||
* If @spd_limit is non-zero, the speed is limited to equal to or
|
||||
* lower than @spd_limit if such speed is supported. If
|
||||
* @spd_limit is slower than any supported speed, only the lowest
|
||||
* supported speed is allowed.
|
||||
*
|
||||
* LOCKING:
|
||||
* Inherited from caller.
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, negative errno on failure
|
||||
*/
|
||||
int sata_down_spd_limit(struct ata_link *link, u32 spd_limit)
|
||||
{
|
||||
u32 sstatus, spd, mask;
|
||||
int rc, bit;
|
||||
|
||||
if (!sata_scr_valid(link))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* If SCR can be read, use it to determine the current SPD.
|
||||
* If not, use cached value in link->sata_spd.
|
||||
*/
|
||||
rc = sata_scr_read(link, SCR_STATUS, &sstatus);
|
||||
if (rc == 0 && ata_sstatus_online(sstatus))
|
||||
spd = (sstatus >> 4) & 0xf;
|
||||
else
|
||||
spd = link->sata_spd;
|
||||
|
||||
mask = link->sata_spd_limit;
|
||||
if (mask <= 1)
|
||||
return -EINVAL;
|
||||
|
||||
/* unconditionally mask off the highest bit */
|
||||
bit = fls(mask) - 1;
|
||||
mask &= ~(1 << bit);
|
||||
|
||||
/*
|
||||
* Mask off all speeds higher than or equal to the current one. At
|
||||
* this point, if current SPD is not available and we previously
|
||||
* recorded the link speed from SStatus, the driver has already
|
||||
* masked off the highest bit so mask should already be 1 or 0.
|
||||
* Otherwise, we should not force 1.5Gbps on a link where we have
|
||||
* not previously recorded speed from SStatus. Just return in this
|
||||
* case.
|
||||
*/
|
||||
if (spd > 1)
|
||||
mask &= (1 << (spd - 1)) - 1;
|
||||
else if (link->sata_spd)
|
||||
return -EINVAL;
|
||||
|
||||
/* were we already at the bottom? */
|
||||
if (!mask)
|
||||
return -EINVAL;
|
||||
|
||||
if (spd_limit) {
|
||||
if (mask & ((1 << spd_limit) - 1))
|
||||
mask &= (1 << spd_limit) - 1;
|
||||
else {
|
||||
bit = ffs(mask) - 1;
|
||||
mask = 1 << bit;
|
||||
}
|
||||
}
|
||||
|
||||
link->sata_spd_limit = mask;
|
||||
|
||||
ata_link_warn(link, "limiting SATA link speed to %s\n",
|
||||
sata_spd_string(fls(mask)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sata_link_hardreset - reset link via SATA phy reset
|
||||
* @link: link to reset
|
||||
@ -626,6 +706,34 @@ int sata_link_hardreset(struct ata_link *link, const unsigned int *timing,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sata_link_hardreset);
|
||||
|
||||
/**
|
||||
* sata_std_hardreset - COMRESET w/o waiting or classification
|
||||
* @link: link to reset
|
||||
* @class: resulting class of attached device
|
||||
* @deadline: deadline jiffies for the operation
|
||||
*
|
||||
* Standard SATA COMRESET w/o waiting or classification.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep)
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 if link offline, -EAGAIN if link online, -errno on errors.
|
||||
*/
|
||||
int sata_std_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline)
|
||||
{
|
||||
const unsigned int *timing = sata_ehc_deb_timing(&link->eh_context);
|
||||
bool online;
|
||||
int rc;
|
||||
|
||||
rc = sata_link_hardreset(link, timing, deadline, &online, NULL);
|
||||
if (online)
|
||||
return -EAGAIN;
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sata_std_hardreset);
|
||||
|
||||
/**
|
||||
* ata_qc_complete_multiple - Complete multiple qcs successfully
|
||||
* @ap: port in question
|
||||
@ -818,7 +926,7 @@ static ssize_t ata_scsi_lpm_store(struct device *device,
|
||||
|
||||
ata_for_each_link(link, ap, EDGE) {
|
||||
ata_for_each_dev(dev, &ap->link, ENABLED) {
|
||||
if (dev->horkage & ATA_HORKAGE_NOLPM) {
|
||||
if (dev->quirks & ATA_QUIRK_NOLPM) {
|
||||
count = -EOPNOTSUPP;
|
||||
goto out_unlock;
|
||||
}
|
||||
@ -1340,7 +1448,7 @@ EXPORT_SYMBOL_GPL(sata_async_notification);
|
||||
static int ata_eh_read_log_10h(struct ata_device *dev,
|
||||
int *tag, struct ata_taskfile *tf)
|
||||
{
|
||||
u8 *buf = dev->link->ap->sector_buf;
|
||||
u8 *buf = dev->sector_buf;
|
||||
unsigned int err_mask;
|
||||
u8 csum;
|
||||
int i;
|
||||
@ -1379,8 +1487,8 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_eh_read_sense_success_ncq_log - Read the sense data for successful
|
||||
* NCQ commands log
|
||||
* ata_eh_get_ncq_success_sense - Read and process the sense data for
|
||||
* successful NCQ commands log page
|
||||
* @link: ATA link to get sense data for
|
||||
*
|
||||
* Read the sense data for successful NCQ commands log page to obtain
|
||||
@ -1393,11 +1501,11 @@ static int ata_eh_read_log_10h(struct ata_device *dev,
|
||||
* RETURNS:
|
||||
* 0 on success, -errno otherwise.
|
||||
*/
|
||||
int ata_eh_read_sense_success_ncq_log(struct ata_link *link)
|
||||
int ata_eh_get_ncq_success_sense(struct ata_link *link)
|
||||
{
|
||||
struct ata_device *dev = link->device;
|
||||
struct ata_port *ap = dev->link->ap;
|
||||
u8 *buf = ap->ncq_sense_buf;
|
||||
u8 *buf = dev->cdl->ncq_sense_log_buf;
|
||||
struct ata_queued_cmd *qc;
|
||||
unsigned int err_mask, tag;
|
||||
u8 *sense, sk = 0, asc = 0, ascq = 0;
|
||||
@ -1455,17 +1563,14 @@ int ata_eh_read_sense_success_ncq_log(struct ata_link *link)
|
||||
qc->flags |= ATA_QCFLAG_SENSE_VALID;
|
||||
|
||||
/*
|
||||
* If we have sense data, call scsi_check_sense() in order to
|
||||
* set the correct SCSI ML byte (if any). No point in checking
|
||||
* the return value, since the command has already completed
|
||||
* successfully.
|
||||
* No point in checking the return value, since the command has
|
||||
* already completed successfully.
|
||||
*/
|
||||
scsi_check_sense(qc->scsicmd);
|
||||
ata_eh_decide_disposition(qc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_eh_read_sense_success_ncq_log);
|
||||
|
||||
/**
|
||||
* ata_eh_analyze_ncq_error - analyze NCQ error
|
||||
@ -1576,3 +1681,11 @@ void ata_eh_analyze_ncq_error(struct ata_link *link)
|
||||
ehc->i.err_mask &= ~AC_ERR_DEV;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_eh_analyze_ncq_error);
|
||||
|
||||
const struct ata_port_operations sata_port_ops = {
|
||||
.inherits = &ata_base_port_ops,
|
||||
|
||||
.qc_defer = ata_std_qc_defer,
|
||||
.hardreset = sata_std_hardreset,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(sata_port_ops);
|
||||
|
@ -1691,9 +1691,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
||||
set_status_byte(qc->scsicmd, SAM_STAT_CHECK_CONDITION);
|
||||
} else if (is_error && !have_sense) {
|
||||
ata_gen_ata_sense(qc);
|
||||
} else {
|
||||
/* Keep the SCSI ML and status byte, clear host byte. */
|
||||
cmd->result &= 0x0000ffff;
|
||||
}
|
||||
|
||||
ata_qc_done(qc);
|
||||
@ -2094,7 +2091,7 @@ static unsigned int ata_scsiop_inq_b0(struct ata_scsi_args *args, u8 *rbuf)
|
||||
if (ata_id_has_trim(args->id)) {
|
||||
u64 max_blocks = 65535 * ATA_MAX_TRIM_RNUM;
|
||||
|
||||
if (dev->horkage & ATA_HORKAGE_MAX_TRIM_128M)
|
||||
if (dev->quirks & ATA_QUIRK_MAX_TRIM_128M)
|
||||
max_blocks = 128 << (20 - SECTOR_SHIFT);
|
||||
|
||||
put_unaligned_be64(max_blocks, &rbuf[36]);
|
||||
@ -2259,7 +2256,7 @@ static inline u16 ata_xlat_cdl_limit(u8 *buf)
|
||||
static unsigned int ata_msense_control_spgt2(struct ata_device *dev, u8 *buf,
|
||||
u8 spg)
|
||||
{
|
||||
u8 *b, *cdl = dev->cdl, *desc;
|
||||
u8 *b, *cdl = dev->cdl->desc_log_buf, *desc;
|
||||
u32 policy;
|
||||
int i;
|
||||
|
||||
@ -2572,11 +2569,11 @@ static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
|
||||
rbuf[15] = lowest_aligned;
|
||||
|
||||
if (ata_id_has_trim(args->id) &&
|
||||
!(dev->horkage & ATA_HORKAGE_NOTRIM)) {
|
||||
!(dev->quirks & ATA_QUIRK_NOTRIM)) {
|
||||
rbuf[14] |= 0x80; /* LBPME */
|
||||
|
||||
if (ata_id_has_zero_after_trim(args->id) &&
|
||||
dev->horkage & ATA_HORKAGE_ZERO_AFTER_TRIM) {
|
||||
dev->quirks & ATA_QUIRK_ZERO_AFTER_TRIM) {
|
||||
ata_dev_info(dev, "Enabling discard_zeroes_data\n");
|
||||
rbuf[14] |= 0x40; /* LBPRZ */
|
||||
}
|
||||
@ -3240,8 +3237,7 @@ static unsigned int ata_scsi_write_same_xlat(struct ata_queued_cmd *qc)
|
||||
}
|
||||
scsi_16_lba_len(cdb, &block, &n_block);
|
||||
|
||||
if (!unmap ||
|
||||
(dev->horkage & ATA_HORKAGE_NOTRIM) ||
|
||||
if (!unmap || (dev->quirks & ATA_QUIRK_NOTRIM) ||
|
||||
!ata_id_has_trim(dev->id)) {
|
||||
fp = 1;
|
||||
bp = 3;
|
||||
@ -4617,16 +4613,15 @@ static void ata_scsi_handle_link_detach(struct ata_link *link)
|
||||
ata_for_each_dev(dev, link, ALL) {
|
||||
unsigned long flags;
|
||||
|
||||
if (!(dev->flags & ATA_DFLAG_DETACHED))
|
||||
continue;
|
||||
|
||||
spin_lock_irqsave(ap->lock, flags);
|
||||
if (!(dev->flags & ATA_DFLAG_DETACHED)) {
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev->flags &= ~ATA_DFLAG_DETACHED;
|
||||
spin_unlock_irqrestore(ap->lock, flags);
|
||||
|
||||
if (zpodd_dev_enabled(dev))
|
||||
zpodd_exit(dev);
|
||||
|
||||
ata_scsi_remove_dev(dev);
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ static struct workqueue_struct *ata_sff_wq;
|
||||
const struct ata_port_operations ata_sff_port_ops = {
|
||||
.inherits = &ata_base_port_ops,
|
||||
|
||||
.qc_prep = ata_noop_qc_prep,
|
||||
.qc_issue = ata_sff_qc_issue,
|
||||
.qc_fill_rtf = ata_sff_qc_fill_rtf,
|
||||
|
||||
@ -970,7 +969,7 @@ fsm_start:
|
||||
* We ignore ERR here to workaround and proceed sending
|
||||
* the CDB.
|
||||
*/
|
||||
if (!(qc->dev->horkage & ATA_HORKAGE_STUCK_ERR)) {
|
||||
if (!(qc->dev->quirks & ATA_QUIRK_STUCK_ERR)) {
|
||||
ata_ehi_push_desc(ehi, "ST_FIRST: "
|
||||
"DRQ=1 with device error, "
|
||||
"dev_stat 0x%X", status);
|
||||
@ -1045,8 +1044,8 @@ fsm_start:
|
||||
* IDENTIFY, it's likely a phantom
|
||||
* device. Mark hint.
|
||||
*/
|
||||
if (qc->dev->horkage &
|
||||
ATA_HORKAGE_DIAGNOSTIC)
|
||||
if (qc->dev->quirks &
|
||||
ATA_QUIRK_DIAGNOSTIC)
|
||||
qc->err_mask |=
|
||||
AC_ERR_NODEV_HINT;
|
||||
} else {
|
||||
@ -1762,7 +1761,7 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present,
|
||||
/* see if device passed diags: continue and warn later */
|
||||
if (err == 0)
|
||||
/* diagnostic fail : do nothing _YET_ */
|
||||
dev->horkage |= ATA_HORKAGE_DIAGNOSTIC;
|
||||
dev->quirks |= ATA_QUIRK_DIAGNOSTIC;
|
||||
else if (err == 1)
|
||||
/* do nothing */ ;
|
||||
else if ((dev->devno == 0) && (err == 0x81))
|
||||
@ -1781,7 +1780,7 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present,
|
||||
* device signature is invalid with diagnostic
|
||||
* failure.
|
||||
*/
|
||||
if (present && (dev->horkage & ATA_HORKAGE_DIAGNOSTIC))
|
||||
if (present && (dev->quirks & ATA_QUIRK_DIAGNOSTIC))
|
||||
class = ATA_DEV_ATA;
|
||||
else
|
||||
class = ATA_DEV_NONE;
|
||||
|
@ -80,12 +80,6 @@ struct ata_internal {
|
||||
#define transport_class_to_port(dev) \
|
||||
tdev_to_port((dev)->parent)
|
||||
|
||||
|
||||
/* Device objects are always created whit link objects */
|
||||
static int ata_tdev_add(struct ata_device *dev);
|
||||
static void ata_tdev_delete(struct ata_device *dev);
|
||||
|
||||
|
||||
/*
|
||||
* Hack to allow attributes of the same name in different objects.
|
||||
*/
|
||||
@ -364,135 +358,6 @@ unsigned int ata_port_classify(struct ata_port *ap,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_port_classify);
|
||||
|
||||
/*
|
||||
* ATA link attributes
|
||||
*/
|
||||
static int noop(int x) { return x; }
|
||||
|
||||
#define ata_link_show_linkspeed(field, format) \
|
||||
static ssize_t \
|
||||
show_ata_link_##field(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct ata_link *link = transport_class_to_link(dev); \
|
||||
\
|
||||
return sprintf(buf, "%s\n", sata_spd_string(format(link->field))); \
|
||||
}
|
||||
|
||||
#define ata_link_linkspeed_attr(field, format) \
|
||||
ata_link_show_linkspeed(field, format) \
|
||||
static DEVICE_ATTR(field, S_IRUGO, show_ata_link_##field, NULL)
|
||||
|
||||
ata_link_linkspeed_attr(hw_sata_spd_limit, fls);
|
||||
ata_link_linkspeed_attr(sata_spd_limit, fls);
|
||||
ata_link_linkspeed_attr(sata_spd, noop);
|
||||
|
||||
|
||||
static DECLARE_TRANSPORT_CLASS(ata_link_class,
|
||||
"ata_link", NULL, NULL, NULL);
|
||||
|
||||
static void ata_tlink_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_is_link -- check if a struct device represents a ATA link
|
||||
* @dev: device to check
|
||||
*
|
||||
* Returns:
|
||||
* %1 if the device represents a ATA link, %0 else
|
||||
*/
|
||||
static int ata_is_link(const struct device *dev)
|
||||
{
|
||||
return dev->release == ata_tlink_release;
|
||||
}
|
||||
|
||||
static int ata_tlink_match(struct attribute_container *cont,
|
||||
struct device *dev)
|
||||
{
|
||||
struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
|
||||
if (!ata_is_link(dev))
|
||||
return 0;
|
||||
return &i->link_attr_cont.ac == cont;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_tlink_delete -- remove ATA LINK
|
||||
* @link: ATA LINK to remove
|
||||
*
|
||||
* Removes the specified ATA LINK. remove associated ATA device(s) as well.
|
||||
*/
|
||||
void ata_tlink_delete(struct ata_link *link)
|
||||
{
|
||||
struct device *dev = &link->tdev;
|
||||
struct ata_device *ata_dev;
|
||||
|
||||
ata_for_each_dev(ata_dev, link, ALL) {
|
||||
ata_tdev_delete(ata_dev);
|
||||
}
|
||||
|
||||
transport_remove_device(dev);
|
||||
device_del(dev);
|
||||
transport_destroy_device(dev);
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_tlink_add -- initialize a transport ATA link structure
|
||||
* @link: allocated ata_link structure.
|
||||
*
|
||||
* Initialize an ATA LINK structure for sysfs. It will be added in the
|
||||
* device tree below the ATA PORT it belongs to.
|
||||
*
|
||||
* Returns %0 on success
|
||||
*/
|
||||
int ata_tlink_add(struct ata_link *link)
|
||||
{
|
||||
struct device *dev = &link->tdev;
|
||||
struct ata_port *ap = link->ap;
|
||||
struct ata_device *ata_dev;
|
||||
int error;
|
||||
|
||||
device_initialize(dev);
|
||||
dev->parent = &ap->tdev;
|
||||
dev->release = ata_tlink_release;
|
||||
if (ata_is_host_link(link))
|
||||
dev_set_name(dev, "link%d", ap->print_id);
|
||||
else
|
||||
dev_set_name(dev, "link%d.%d", ap->print_id, link->pmp);
|
||||
|
||||
transport_setup_device(dev);
|
||||
|
||||
error = device_add(dev);
|
||||
if (error) {
|
||||
goto tlink_err;
|
||||
}
|
||||
|
||||
error = transport_add_device(dev);
|
||||
if (error)
|
||||
goto tlink_transport_err;
|
||||
transport_configure_device(dev);
|
||||
|
||||
ata_for_each_dev(ata_dev, link, ALL) {
|
||||
error = ata_tdev_add(ata_dev);
|
||||
if (error) {
|
||||
goto tlink_dev_err;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
tlink_dev_err:
|
||||
while (--ata_dev >= link->device) {
|
||||
ata_tdev_delete(ata_dev);
|
||||
}
|
||||
transport_remove_device(dev);
|
||||
tlink_transport_err:
|
||||
device_del(dev);
|
||||
tlink_err:
|
||||
transport_destroy_device(dev);
|
||||
put_device(dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* ATA device attributes
|
||||
*/
|
||||
@ -617,10 +482,10 @@ show_ata_dev_trim(struct device *dev,
|
||||
|
||||
if (!ata_id_has_trim(ata_dev->id))
|
||||
mode = "unsupported";
|
||||
else if (ata_dev->horkage & ATA_HORKAGE_NOTRIM)
|
||||
else if (ata_dev->quirks & ATA_QUIRK_NOTRIM)
|
||||
mode = "forced_unsupported";
|
||||
else if (ata_dev->horkage & ATA_HORKAGE_NO_NCQ_TRIM)
|
||||
mode = "forced_unqueued";
|
||||
else if (ata_dev->quirks & ATA_QUIRK_NO_NCQ_TRIM)
|
||||
mode = "forced_unqueued";
|
||||
else if (ata_fpdma_dsm_supported(ata_dev))
|
||||
mode = "queued";
|
||||
else
|
||||
@ -643,9 +508,9 @@ static void ata_tdev_release(struct device *dev)
|
||||
* @dev: device to check
|
||||
*
|
||||
* Returns:
|
||||
* %1 if the device represents a ATA device, %0 else
|
||||
* true if the device represents a ATA device, false otherwise
|
||||
*/
|
||||
static int ata_is_ata_dev(const struct device *dev)
|
||||
static bool ata_is_ata_dev(const struct device *dev)
|
||||
{
|
||||
return dev->release == ata_tdev_release;
|
||||
}
|
||||
@ -653,21 +518,22 @@ static int ata_is_ata_dev(const struct device *dev)
|
||||
static int ata_tdev_match(struct attribute_container *cont,
|
||||
struct device *dev)
|
||||
{
|
||||
struct ata_internal* i = to_ata_internal(ata_scsi_transport_template);
|
||||
struct ata_internal *i = to_ata_internal(ata_scsi_transport_template);
|
||||
|
||||
if (!ata_is_ata_dev(dev))
|
||||
return 0;
|
||||
return &i->dev_attr_cont.ac == cont;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_tdev_free -- free a ATA LINK
|
||||
* @dev: ATA PHY to free
|
||||
* ata_tdev_free -- free an ATA transport device
|
||||
* @dev: struct ata_device owning the transport device to free
|
||||
*
|
||||
* Frees the specified ATA PHY.
|
||||
* Free the ATA transport device for the specified ATA device.
|
||||
*
|
||||
* Note:
|
||||
* This function must only be called on a PHY that has not
|
||||
* successfully been added using ata_tdev_add().
|
||||
* This function must only be called for a ATA transport device that has not
|
||||
* yet successfully been added using ata_tdev_add().
|
||||
*/
|
||||
static void ata_tdev_free(struct ata_device *dev)
|
||||
{
|
||||
@ -676,10 +542,10 @@ static void ata_tdev_free(struct ata_device *dev)
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_tdev_delete -- remove ATA device
|
||||
* @ata_dev: ATA device to remove
|
||||
* ata_tdev_delete -- remove an ATA transport device
|
||||
* @ata_dev: struct ata_device owning the transport device to delete
|
||||
*
|
||||
* Removes the specified ATA device.
|
||||
* Removes the ATA transport device for the specified ATA device.
|
||||
*/
|
||||
static void ata_tdev_delete(struct ata_device *ata_dev)
|
||||
{
|
||||
@ -690,15 +556,14 @@ static void ata_tdev_delete(struct ata_device *ata_dev)
|
||||
ata_tdev_free(ata_dev);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ata_tdev_add -- initialize a transport ATA device structure.
|
||||
* @ata_dev: ata_dev structure.
|
||||
* ata_tdev_add -- initialize an ATA transport device
|
||||
* @ata_dev: struct ata_device owning the transport device to add
|
||||
*
|
||||
* Initialize an ATA device structure for sysfs. It will be added in the
|
||||
* device tree below the ATA LINK device it belongs to.
|
||||
* Initialize an ATA transport device for sysfs. It will be added in the
|
||||
* device tree below the ATA link device it belongs to.
|
||||
*
|
||||
* Returns %0 on success
|
||||
* Returns %0 on success and a negative error code on error.
|
||||
*/
|
||||
static int ata_tdev_add(struct ata_device *ata_dev)
|
||||
{
|
||||
@ -734,6 +599,136 @@ static int ata_tdev_add(struct ata_device *ata_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ATA link attributes
|
||||
*/
|
||||
static int noop(int x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
#define ata_link_show_linkspeed(field, format) \
|
||||
static ssize_t \
|
||||
show_ata_link_##field(struct device *dev, \
|
||||
struct device_attribute *attr, char *buf) \
|
||||
{ \
|
||||
struct ata_link *link = transport_class_to_link(dev); \
|
||||
\
|
||||
return sprintf(buf, "%s\n", \
|
||||
sata_spd_string(format(link->field))); \
|
||||
}
|
||||
|
||||
#define ata_link_linkspeed_attr(field, format) \
|
||||
ata_link_show_linkspeed(field, format) \
|
||||
static DEVICE_ATTR(field, 0444, show_ata_link_##field, NULL)
|
||||
|
||||
ata_link_linkspeed_attr(hw_sata_spd_limit, fls);
|
||||
ata_link_linkspeed_attr(sata_spd_limit, fls);
|
||||
ata_link_linkspeed_attr(sata_spd, noop);
|
||||
|
||||
static DECLARE_TRANSPORT_CLASS(ata_link_class,
|
||||
"ata_link", NULL, NULL, NULL);
|
||||
|
||||
static void ata_tlink_release(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_is_link -- check if a struct device represents a ATA link
|
||||
* @dev: device to check
|
||||
*
|
||||
* Returns:
|
||||
* true if the device represents a ATA link, false otherwise
|
||||
*/
|
||||
static bool ata_is_link(const struct device *dev)
|
||||
{
|
||||
return dev->release == ata_tlink_release;
|
||||
}
|
||||
|
||||
static int ata_tlink_match(struct attribute_container *cont,
|
||||
struct device *dev)
|
||||
{
|
||||
struct ata_internal *i = to_ata_internal(ata_scsi_transport_template);
|
||||
|
||||
if (!ata_is_link(dev))
|
||||
return 0;
|
||||
return &i->link_attr_cont.ac == cont;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_tlink_delete -- remove an ATA link transport device
|
||||
* @link: struct ata_link owning the link transport device to remove
|
||||
*
|
||||
* Removes the link transport device of the specified ATA link. This also
|
||||
* removes the ATA device(s) associated with the link as well.
|
||||
*/
|
||||
void ata_tlink_delete(struct ata_link *link)
|
||||
{
|
||||
struct device *dev = &link->tdev;
|
||||
struct ata_device *ata_dev;
|
||||
|
||||
ata_for_each_dev(ata_dev, link, ALL) {
|
||||
ata_tdev_delete(ata_dev);
|
||||
}
|
||||
|
||||
transport_remove_device(dev);
|
||||
device_del(dev);
|
||||
transport_destroy_device(dev);
|
||||
put_device(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_tlink_add -- initialize an ATA link transport device
|
||||
* @link: struct ata_link owning the link transport device to initialize
|
||||
*
|
||||
* Initialize an ATA link transport device for sysfs. It will be added in the
|
||||
* device tree below the ATA port it belongs to.
|
||||
*
|
||||
* Returns %0 on success and a negative error code on error.
|
||||
*/
|
||||
int ata_tlink_add(struct ata_link *link)
|
||||
{
|
||||
struct device *dev = &link->tdev;
|
||||
struct ata_port *ap = link->ap;
|
||||
struct ata_device *ata_dev;
|
||||
int error;
|
||||
|
||||
device_initialize(dev);
|
||||
dev->parent = &ap->tdev;
|
||||
dev->release = ata_tlink_release;
|
||||
if (ata_is_host_link(link))
|
||||
dev_set_name(dev, "link%d", ap->print_id);
|
||||
else
|
||||
dev_set_name(dev, "link%d.%d", ap->print_id, link->pmp);
|
||||
|
||||
transport_setup_device(dev);
|
||||
|
||||
error = device_add(dev);
|
||||
if (error)
|
||||
goto tlink_err;
|
||||
|
||||
error = transport_add_device(dev);
|
||||
if (error)
|
||||
goto tlink_transport_err;
|
||||
transport_configure_device(dev);
|
||||
|
||||
ata_for_each_dev(ata_dev, link, ALL) {
|
||||
error = ata_tdev_add(ata_dev);
|
||||
if (error)
|
||||
goto tlink_dev_err;
|
||||
}
|
||||
return 0;
|
||||
tlink_dev_err:
|
||||
while (--ata_dev >= link->device)
|
||||
ata_tdev_delete(ata_dev);
|
||||
transport_remove_device(dev);
|
||||
tlink_transport_err:
|
||||
device_del(dev);
|
||||
tlink_err:
|
||||
transport_destroy_device(dev);
|
||||
put_device(dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup / Teardown code
|
||||
|
@ -112,7 +112,7 @@ static bool zpready(struct ata_device *dev)
|
||||
if (!ret || sense_key != NOT_READY)
|
||||
return false;
|
||||
|
||||
sense_buf = dev->link->ap->sector_buf;
|
||||
sense_buf = dev->sector_buf;
|
||||
ret = atapi_eh_request_sense(dev, sense_buf, sense_key);
|
||||
if (ret)
|
||||
return false;
|
||||
|
@ -38,6 +38,12 @@ extern int libata_noacpi;
|
||||
extern int libata_allow_tpm;
|
||||
extern const struct device_type ata_port_type;
|
||||
extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
|
||||
|
||||
static inline bool ata_sstatus_online(u32 sstatus)
|
||||
{
|
||||
return (sstatus & 0xf) == 0x3;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ATA_FORCE
|
||||
extern void ata_force_cbl(struct ata_port *ap);
|
||||
#else
|
||||
@ -65,7 +71,7 @@ extern bool ata_dev_power_init_tf(struct ata_device *dev,
|
||||
struct ata_taskfile *tf, bool set_active);
|
||||
extern void ata_dev_power_set_standby(struct ata_device *dev);
|
||||
extern void ata_dev_power_set_active(struct ata_device *dev);
|
||||
extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
|
||||
void ata_dev_free_resources(struct ata_device *dev);
|
||||
extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel);
|
||||
extern unsigned int ata_dev_set_feature(struct ata_device *dev,
|
||||
u8 subcmd, u8 action);
|
||||
@ -84,9 +90,25 @@ extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
|
||||
extern const char *sata_spd_string(unsigned int spd);
|
||||
extern unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
|
||||
u8 page, void *buf, unsigned int sectors);
|
||||
void ata_dev_cleanup_cdl_resources(struct ata_device *dev);
|
||||
|
||||
#define to_ata_port(d) container_of(d, struct ata_port, tdev)
|
||||
|
||||
/* libata-sata.c */
|
||||
#ifdef CONFIG_SATA_HOST
|
||||
int sata_down_spd_limit(struct ata_link *link, u32 spd_limit);
|
||||
int ata_eh_get_ncq_success_sense(struct ata_link *link);
|
||||
#else
|
||||
static inline int sata_down_spd_limit(struct ata_link *link, u32 spd_limit)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int ata_eh_get_ncq_success_sense(struct ata_link *link)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* libata-acpi.c */
|
||||
#ifdef CONFIG_ATA_ACPI
|
||||
extern unsigned int ata_acpi_gtf_filter;
|
||||
@ -124,7 +146,6 @@ extern void ata_scsi_set_sense_information(struct ata_device *dev,
|
||||
const struct ata_taskfile *tf);
|
||||
extern void ata_scsi_media_change_notify(struct ata_device *dev);
|
||||
extern void ata_scsi_hotplug(struct work_struct *work);
|
||||
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
|
||||
extern void ata_scsi_dev_rescan(struct work_struct *work);
|
||||
extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
|
||||
unsigned int id, u64 lun);
|
||||
@ -162,6 +183,7 @@ extern void ata_eh_finish(struct ata_port *ap);
|
||||
extern int ata_ering_map(struct ata_ering *ering,
|
||||
int (*map_fn)(struct ata_ering_entry *, void *),
|
||||
void *arg);
|
||||
enum scsi_disposition ata_eh_decide_disposition(struct ata_queued_cmd *qc);
|
||||
extern unsigned int atapi_eh_tur(struct ata_device *dev, u8 *r_sense_key);
|
||||
extern unsigned int atapi_eh_request_sense(struct ata_device *dev,
|
||||
u8 *sense_buf, u8 dfl_sense_key);
|
||||
|
@ -8,9 +8,9 @@
|
||||
* PIO mode and smarter silicon.
|
||||
*
|
||||
* The practical upshot of this is that we must always tune the
|
||||
* drive for the right PIO mode. We must also ignore all the blacklists
|
||||
* and the drive bus mastering DMA information. Also to confuse matters
|
||||
* further we can do DMA on PIO only drives.
|
||||
* drive for the right PIO mode and ignore the drive bus mastering DMA
|
||||
* information. Also to confuse matters further we can do DMA on PIO only
|
||||
* drives.
|
||||
*
|
||||
* DMA on the 5510 also requires we disable_hlt() during DMA on early
|
||||
* revisions.
|
||||
|
@ -884,8 +884,6 @@ static const struct scsi_host_template ep93xx_pata_sht = {
|
||||
static struct ata_port_operations ep93xx_pata_port_ops = {
|
||||
.inherits = &ata_bmdma_port_ops,
|
||||
|
||||
.qc_prep = ata_noop_qc_prep,
|
||||
|
||||
.softreset = ep93xx_pata_softreset,
|
||||
.hardreset = ATA_OP_NULL,
|
||||
|
||||
|
@ -549,6 +549,7 @@ static const struct of_device_id pata_ftide010_of_match[] = {
|
||||
{ .compatible = "faraday,ftide010", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pata_ftide010_of_match);
|
||||
|
||||
static struct platform_driver pata_ftide010_driver = {
|
||||
.driver = {
|
||||
|
@ -170,8 +170,8 @@ static const char * const bad_ata66_3[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
|
||||
const char * const list[])
|
||||
static int hpt_dma_broken(const struct ata_device *dev, char *modestr,
|
||||
const char * const list[])
|
||||
{
|
||||
unsigned char model_num[ATA_ID_PROD_LEN + 1];
|
||||
int i;
|
||||
@ -197,11 +197,11 @@ static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
|
||||
static unsigned int hpt366_filter(struct ata_device *adev, unsigned int mask)
|
||||
{
|
||||
if (adev->class == ATA_DEV_ATA) {
|
||||
if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
|
||||
if (hpt_dma_broken(adev, "UDMA", bad_ata33))
|
||||
mask &= ~ATA_MASK_UDMA;
|
||||
if (hpt_dma_blacklisted(adev, "UDMA3", bad_ata66_3))
|
||||
if (hpt_dma_broken(adev, "UDMA3", bad_ata66_3))
|
||||
mask &= ~(0xF8 << ATA_SHIFT_UDMA);
|
||||
if (hpt_dma_blacklisted(adev, "UDMA4", bad_ata66_4))
|
||||
if (hpt_dma_broken(adev, "UDMA4", bad_ata66_4))
|
||||
mask &= ~(0xF0 << ATA_SHIFT_UDMA);
|
||||
} else if (adev->class == ATA_DEV_ATAPI)
|
||||
mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA);
|
||||
|
@ -218,8 +218,8 @@ static u32 hpt37x_find_mode(struct ata_port *ap, int speed)
|
||||
return 0xffffffffU; /* silence compiler warning */
|
||||
}
|
||||
|
||||
static int hpt_dma_blacklisted(const struct ata_device *dev, char *modestr,
|
||||
const char * const list[])
|
||||
static int hpt_dma_broken(const struct ata_device *dev, char *modestr,
|
||||
const char * const list[])
|
||||
{
|
||||
unsigned char model_num[ATA_ID_PROD_LEN + 1];
|
||||
int i;
|
||||
@ -281,9 +281,9 @@ static const char * const bad_ata100_5[] = {
|
||||
static unsigned int hpt370_filter(struct ata_device *adev, unsigned int mask)
|
||||
{
|
||||
if (adev->class == ATA_DEV_ATA) {
|
||||
if (hpt_dma_blacklisted(adev, "UDMA", bad_ata33))
|
||||
if (hpt_dma_broken(adev, "UDMA", bad_ata33))
|
||||
mask &= ~ATA_MASK_UDMA;
|
||||
if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
|
||||
if (hpt_dma_broken(adev, "UDMA100", bad_ata100_5))
|
||||
mask &= ~(0xE0 << ATA_SHIFT_UDMA);
|
||||
}
|
||||
return mask;
|
||||
@ -300,7 +300,7 @@ static unsigned int hpt370_filter(struct ata_device *adev, unsigned int mask)
|
||||
static unsigned int hpt370a_filter(struct ata_device *adev, unsigned int mask)
|
||||
{
|
||||
if (adev->class == ATA_DEV_ATA) {
|
||||
if (hpt_dma_blacklisted(adev, "UDMA100", bad_ata100_5))
|
||||
if (hpt_dma_broken(adev, "UDMA100", bad_ata100_5))
|
||||
mask &= ~(0xE0 << ATA_SHIFT_UDMA);
|
||||
}
|
||||
return mask;
|
||||
|
@ -328,8 +328,6 @@ static void pata_icside_postreset(struct ata_link *link, unsigned int *classes)
|
||||
|
||||
static struct ata_port_operations pata_icside_port_ops = {
|
||||
.inherits = &ata_bmdma_port_ops,
|
||||
/* no need to build any PRD tables for DMA */
|
||||
.qc_prep = ata_noop_qc_prep,
|
||||
.sff_data_xfer = ata_sff_data_xfer32,
|
||||
.bmdma_setup = pata_icside_bmdma_setup,
|
||||
.bmdma_start = pata_icside_bmdma_start,
|
||||
|
@ -519,9 +519,9 @@ static void it821x_dev_config(struct ata_device *adev)
|
||||
}
|
||||
/* This is a controller firmware triggered funny, don't
|
||||
report the drive faulty! */
|
||||
adev->horkage &= ~ATA_HORKAGE_DIAGNOSTIC;
|
||||
adev->quirks &= ~ATA_QUIRK_DIAGNOSTIC;
|
||||
/* No HPA in 'smart' mode */
|
||||
adev->horkage |= ATA_HORKAGE_BROKEN_HPA;
|
||||
adev->quirks |= ATA_QUIRK_BROKEN_HPA;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -290,6 +290,7 @@ static const struct of_device_id ixp4xx_pata_of_match[] = {
|
||||
{ .compatible = "intel,ixp4xx-compact-flash", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ixp4xx_pata_of_match);
|
||||
|
||||
static struct platform_driver ixp4xx_pata_platform_driver = {
|
||||
.driver = {
|
||||
|
@ -620,7 +620,6 @@ static struct ata_port_operations mpc52xx_ata_port_ops = {
|
||||
.bmdma_start = mpc52xx_bmdma_start,
|
||||
.bmdma_stop = mpc52xx_bmdma_stop,
|
||||
.bmdma_status = mpc52xx_bmdma_status,
|
||||
.qc_prep = ata_noop_qc_prep,
|
||||
};
|
||||
|
||||
static int mpc52xx_ata_init_one(struct device *dev,
|
||||
|
@ -789,7 +789,6 @@ static unsigned int octeon_cf_qc_issue(struct ata_queued_cmd *qc)
|
||||
static struct ata_port_operations octeon_cf_ops = {
|
||||
.inherits = &ata_sff_port_ops,
|
||||
.check_atapi_dma = octeon_cf_check_atapi_dma,
|
||||
.qc_prep = ata_noop_qc_prep,
|
||||
.qc_issue = octeon_cf_qc_issue,
|
||||
.sff_dev_select = octeon_cf_dev_select,
|
||||
.sff_irq_on = octeon_cf_ata_port_noaction,
|
||||
|
@ -46,10 +46,11 @@
|
||||
#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
|
||||
#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
|
||||
|
||||
/* Seagate Barracuda ATA IV Family drives in UDMA mode 5
|
||||
* can overrun their FIFOs when used with the CSB5 */
|
||||
|
||||
static const char *csb_bad_ata100[] = {
|
||||
/*
|
||||
* Seagate Barracuda ATA IV Family drives in UDMA mode 5
|
||||
* can overrun their FIFOs when used with the CSB5.
|
||||
*/
|
||||
static const char * const csb_bad_ata100[] = {
|
||||
"ST320011A",
|
||||
"ST340016A",
|
||||
"ST360021A",
|
||||
@ -163,10 +164,11 @@ static unsigned int serverworks_osb4_filter(struct ata_device *adev, unsigned in
|
||||
* @adev: ATA device
|
||||
* @mask: Mask of proposed modes
|
||||
*
|
||||
* Check the blacklist and disable UDMA5 if matched
|
||||
* Check the list of devices with broken UDMA5 and
|
||||
* disable UDMA5 if matched.
|
||||
*/
|
||||
|
||||
static unsigned int serverworks_csb_filter(struct ata_device *adev, unsigned int mask)
|
||||
static unsigned int serverworks_csb_filter(struct ata_device *adev,
|
||||
unsigned int mask)
|
||||
{
|
||||
const char *p;
|
||||
char model_num[ATA_ID_PROD_LEN + 1];
|
||||
|
@ -417,6 +417,7 @@ static const struct of_device_id gemini_sata_of_match[] = {
|
||||
{ .compatible = "cortina,gemini-sata-bridge", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, gemini_sata_of_match);
|
||||
|
||||
static struct platform_driver gemini_sata_driver = {
|
||||
.driver = {
|
||||
|
@ -128,7 +128,7 @@ static const struct pci_device_id sil_pci_tbl[] = {
|
||||
static const struct sil_drivelist {
|
||||
const char *product;
|
||||
unsigned int quirk;
|
||||
} sil_blacklist [] = {
|
||||
} sil_quirks[] = {
|
||||
{ "ST320012AS", SIL_QUIRK_MOD15WRITE },
|
||||
{ "ST330013AS", SIL_QUIRK_MOD15WRITE },
|
||||
{ "ST340017AS", SIL_QUIRK_MOD15WRITE },
|
||||
@ -600,8 +600,8 @@ static void sil_thaw(struct ata_port *ap)
|
||||
* list, and apply the fixups to only the specific
|
||||
* devices/hosts/firmwares that need it.
|
||||
*
|
||||
* 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
|
||||
* The Maxtor quirk is in the blacklist, but I'm keeping the original
|
||||
* 20040111 - Seagate drives affected by the Mod15Write bug are quirked
|
||||
* The Maxtor quirk is in sil_quirks, but I'm keeping the original
|
||||
* pessimistic fix for the following reasons...
|
||||
* - There seems to be less info on it, only one device gleaned off the
|
||||
* Windows driver, maybe only one is affected. More info would be greatly
|
||||
@ -616,13 +616,13 @@ static void sil_dev_config(struct ata_device *dev)
|
||||
unsigned char model_num[ATA_ID_PROD_LEN + 1];
|
||||
|
||||
/* This controller doesn't support trim */
|
||||
dev->horkage |= ATA_HORKAGE_NOTRIM;
|
||||
dev->quirks |= ATA_QUIRK_NOTRIM;
|
||||
|
||||
ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
|
||||
|
||||
for (n = 0; sil_blacklist[n].product; n++)
|
||||
if (!strcmp(sil_blacklist[n].product, model_num)) {
|
||||
quirks = sil_blacklist[n].quirk;
|
||||
for (n = 0; sil_quirks[n].product; n++)
|
||||
if (!strcmp(sil_quirks[n].product, model_num)) {
|
||||
quirks = sil_quirks[n].quirk;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -564,7 +564,6 @@ static struct ata_port_operations sas_sata_ops = {
|
||||
.error_handler = ata_std_error_handler,
|
||||
.post_internal_cmd = sas_ata_post_internal,
|
||||
.qc_defer = ata_std_qc_defer,
|
||||
.qc_prep = ata_noop_qc_prep,
|
||||
.qc_issue = sas_ata_qc_issue,
|
||||
.qc_fill_rtf = sas_ata_qc_fill_rtf,
|
||||
.set_dmamode = sas_ata_set_dmamode,
|
||||
|
@ -55,6 +55,46 @@
|
||||
/* defines only for the constants which don't work well as enums */
|
||||
#define ATA_TAG_POISON 0xfafbfcfdU
|
||||
|
||||
/*
|
||||
* Quirk flags bits.
|
||||
* ata_device->quirks is an unsigned int, so __ATA_QUIRK_MAX must not exceed 32.
|
||||
*/
|
||||
enum ata_quirks {
|
||||
__ATA_QUIRK_DIAGNOSTIC, /* Failed boot diag */
|
||||
__ATA_QUIRK_NODMA, /* DMA problems */
|
||||
__ATA_QUIRK_NONCQ, /* Don't use NCQ */
|
||||
__ATA_QUIRK_MAX_SEC_128, /* Limit max sects to 128 */
|
||||
__ATA_QUIRK_BROKEN_HPA, /* Broken HPA */
|
||||
__ATA_QUIRK_DISABLE, /* Disable it */
|
||||
__ATA_QUIRK_HPA_SIZE, /* Native size off by one */
|
||||
__ATA_QUIRK_IVB, /* cbl det validity bit bugs */
|
||||
__ATA_QUIRK_STUCK_ERR, /* Stuck ERR on next PACKET */
|
||||
__ATA_QUIRK_BRIDGE_OK, /* No bridge limits */
|
||||
__ATA_QUIRK_ATAPI_MOD16_DMA, /* Use ATAPI DMA for commands that */
|
||||
/* are not a multiple of 16 bytes */
|
||||
__ATA_QUIRK_FIRMWARE_WARN, /* Firmware update warning */
|
||||
__ATA_QUIRK_1_5_GBPS, /* Force 1.5 Gbps */
|
||||
__ATA_QUIRK_NOSETXFER, /* Skip SETXFER, SATA only */
|
||||
__ATA_QUIRK_BROKEN_FPDMA_AA, /* Skip AA */
|
||||
__ATA_QUIRK_DUMP_ID, /* Dump IDENTIFY data */
|
||||
__ATA_QUIRK_MAX_SEC_LBA48, /* Set max sects to 65535 */
|
||||
__ATA_QUIRK_ATAPI_DMADIR, /* Device requires dmadir */
|
||||
__ATA_QUIRK_NO_NCQ_TRIM, /* Do not use queued TRIM */
|
||||
__ATA_QUIRK_NOLPM, /* Do not use LPM */
|
||||
__ATA_QUIRK_WD_BROKEN_LPM, /* Some WDs have broken LPM */
|
||||
__ATA_QUIRK_ZERO_AFTER_TRIM, /* Guarantees zero after trim */
|
||||
__ATA_QUIRK_NO_DMA_LOG, /* Do not use DMA for log read */
|
||||
__ATA_QUIRK_NOTRIM, /* Do not use TRIM */
|
||||
__ATA_QUIRK_MAX_SEC_1024, /* Limit max sects to 1024 */
|
||||
__ATA_QUIRK_MAX_TRIM_128M, /* Limit max trim size to 128M */
|
||||
__ATA_QUIRK_NO_NCQ_ON_ATI, /* Disable NCQ on ATI chipset */
|
||||
__ATA_QUIRK_NO_ID_DEV_LOG, /* Identify device log missing */
|
||||
__ATA_QUIRK_NO_LOG_DIR, /* Do not read log directory */
|
||||
__ATA_QUIRK_NO_FUA, /* Do not use FUA */
|
||||
|
||||
__ATA_QUIRK_MAX,
|
||||
};
|
||||
|
||||
enum {
|
||||
/* various global constants */
|
||||
LIBATA_MAX_PRD = ATA_MAX_PRD / 2,
|
||||
@ -338,6 +378,7 @@ enum {
|
||||
ATA_EHI_PRINTINFO = (1 << 18), /* print configuration info */
|
||||
ATA_EHI_SETMODE = (1 << 19), /* configure transfer mode */
|
||||
ATA_EHI_POST_SETMODE = (1 << 20), /* revalidating after setmode */
|
||||
ATA_EHI_DID_PRINT_QUIRKS = (1 << 21), /* already printed quirks info */
|
||||
|
||||
ATA_EHI_DID_RESET = ATA_EHI_DID_SOFTRESET | ATA_EHI_DID_HARDRESET,
|
||||
|
||||
@ -362,43 +403,42 @@ enum {
|
||||
*/
|
||||
ATA_EH_CMD_TIMEOUT_TABLE_SIZE = 8,
|
||||
|
||||
/* Horkage types. May be set by libata or controller on drives
|
||||
(some horkage may be drive/controller pair dependent */
|
||||
/*
|
||||
* Quirk flags: may be set by libata or controller drivers on drives.
|
||||
* Some quirks may be drive/controller pair dependent.
|
||||
*/
|
||||
ATA_QUIRK_DIAGNOSTIC = (1U << __ATA_QUIRK_DIAGNOSTIC),
|
||||
ATA_QUIRK_NODMA = (1U << __ATA_QUIRK_NODMA),
|
||||
ATA_QUIRK_NONCQ = (1U << __ATA_QUIRK_NONCQ),
|
||||
ATA_QUIRK_MAX_SEC_128 = (1U << __ATA_QUIRK_MAX_SEC_128),
|
||||
ATA_QUIRK_BROKEN_HPA = (1U << __ATA_QUIRK_BROKEN_HPA),
|
||||
ATA_QUIRK_DISABLE = (1U << __ATA_QUIRK_DISABLE),
|
||||
ATA_QUIRK_HPA_SIZE = (1U << __ATA_QUIRK_HPA_SIZE),
|
||||
ATA_QUIRK_IVB = (1U << __ATA_QUIRK_IVB),
|
||||
ATA_QUIRK_STUCK_ERR = (1U << __ATA_QUIRK_STUCK_ERR),
|
||||
ATA_QUIRK_BRIDGE_OK = (1U << __ATA_QUIRK_BRIDGE_OK),
|
||||
ATA_QUIRK_ATAPI_MOD16_DMA = (1U << __ATA_QUIRK_ATAPI_MOD16_DMA),
|
||||
ATA_QUIRK_FIRMWARE_WARN = (1U << __ATA_QUIRK_FIRMWARE_WARN),
|
||||
ATA_QUIRK_1_5_GBPS = (1U << __ATA_QUIRK_1_5_GBPS),
|
||||
ATA_QUIRK_NOSETXFER = (1U << __ATA_QUIRK_NOSETXFER),
|
||||
ATA_QUIRK_BROKEN_FPDMA_AA = (1U << __ATA_QUIRK_BROKEN_FPDMA_AA),
|
||||
ATA_QUIRK_DUMP_ID = (1U << __ATA_QUIRK_DUMP_ID),
|
||||
ATA_QUIRK_MAX_SEC_LBA48 = (1U << __ATA_QUIRK_MAX_SEC_LBA48),
|
||||
ATA_QUIRK_ATAPI_DMADIR = (1U << __ATA_QUIRK_ATAPI_DMADIR),
|
||||
ATA_QUIRK_NO_NCQ_TRIM = (1U << __ATA_QUIRK_NO_NCQ_TRIM),
|
||||
ATA_QUIRK_NOLPM = (1U << __ATA_QUIRK_NOLPM),
|
||||
ATA_QUIRK_WD_BROKEN_LPM = (1U << __ATA_QUIRK_WD_BROKEN_LPM),
|
||||
ATA_QUIRK_ZERO_AFTER_TRIM = (1U << __ATA_QUIRK_ZERO_AFTER_TRIM),
|
||||
ATA_QUIRK_NO_DMA_LOG = (1U << __ATA_QUIRK_NO_DMA_LOG),
|
||||
ATA_QUIRK_NOTRIM = (1U << __ATA_QUIRK_NOTRIM),
|
||||
ATA_QUIRK_MAX_SEC_1024 = (1U << __ATA_QUIRK_MAX_SEC_1024),
|
||||
ATA_QUIRK_MAX_TRIM_128M = (1U << __ATA_QUIRK_MAX_TRIM_128M),
|
||||
ATA_QUIRK_NO_NCQ_ON_ATI = (1U << __ATA_QUIRK_NO_NCQ_ON_ATI),
|
||||
ATA_QUIRK_NO_ID_DEV_LOG = (1U << __ATA_QUIRK_NO_ID_DEV_LOG),
|
||||
ATA_QUIRK_NO_LOG_DIR = (1U << __ATA_QUIRK_NO_LOG_DIR),
|
||||
ATA_QUIRK_NO_FUA = (1U << __ATA_QUIRK_NO_FUA),
|
||||
|
||||
ATA_HORKAGE_DIAGNOSTIC = (1 << 0), /* Failed boot diag */
|
||||
ATA_HORKAGE_NODMA = (1 << 1), /* DMA problems */
|
||||
ATA_HORKAGE_NONCQ = (1 << 2), /* Don't use NCQ */
|
||||
ATA_HORKAGE_MAX_SEC_128 = (1 << 3), /* Limit max sects to 128 */
|
||||
ATA_HORKAGE_BROKEN_HPA = (1 << 4), /* Broken HPA */
|
||||
ATA_HORKAGE_DISABLE = (1 << 5), /* Disable it */
|
||||
ATA_HORKAGE_HPA_SIZE = (1 << 6), /* native size off by one */
|
||||
ATA_HORKAGE_IVB = (1 << 8), /* cbl det validity bit bugs */
|
||||
ATA_HORKAGE_STUCK_ERR = (1 << 9), /* stuck ERR on next PACKET */
|
||||
ATA_HORKAGE_BRIDGE_OK = (1 << 10), /* no bridge limits */
|
||||
ATA_HORKAGE_ATAPI_MOD16_DMA = (1 << 11), /* use ATAPI DMA for commands
|
||||
not multiple of 16 bytes */
|
||||
ATA_HORKAGE_FIRMWARE_WARN = (1 << 12), /* firmware update warning */
|
||||
ATA_HORKAGE_1_5_GBPS = (1 << 13), /* force 1.5 Gbps */
|
||||
ATA_HORKAGE_NOSETXFER = (1 << 14), /* skip SETXFER, SATA only */
|
||||
ATA_HORKAGE_BROKEN_FPDMA_AA = (1 << 15), /* skip AA */
|
||||
ATA_HORKAGE_DUMP_ID = (1 << 16), /* dump IDENTIFY data */
|
||||
ATA_HORKAGE_MAX_SEC_LBA48 = (1 << 17), /* Set max sects to 65535 */
|
||||
ATA_HORKAGE_ATAPI_DMADIR = (1 << 18), /* device requires dmadir */
|
||||
ATA_HORKAGE_NO_NCQ_TRIM = (1 << 19), /* don't use queued TRIM */
|
||||
ATA_HORKAGE_NOLPM = (1 << 20), /* don't use LPM */
|
||||
ATA_HORKAGE_WD_BROKEN_LPM = (1 << 21), /* some WDs have broken LPM */
|
||||
ATA_HORKAGE_ZERO_AFTER_TRIM = (1 << 22),/* guarantees zero after trim */
|
||||
ATA_HORKAGE_NO_DMA_LOG = (1 << 23), /* don't use DMA for log read */
|
||||
ATA_HORKAGE_NOTRIM = (1 << 24), /* don't use TRIM */
|
||||
ATA_HORKAGE_MAX_SEC_1024 = (1 << 25), /* Limit max sects to 1024 */
|
||||
ATA_HORKAGE_MAX_TRIM_128M = (1 << 26), /* Limit max trim size to 128M */
|
||||
ATA_HORKAGE_NO_NCQ_ON_ATI = (1 << 27), /* Disable NCQ on ATI chipset */
|
||||
ATA_HORKAGE_NO_ID_DEV_LOG = (1 << 28), /* Identify device log missing */
|
||||
ATA_HORKAGE_NO_LOG_DIR = (1 << 29), /* Do not read log directory */
|
||||
ATA_HORKAGE_NO_FUA = (1 << 30), /* Do not use FUA */
|
||||
|
||||
/* DMA mask for user DMA control: User visible values; DO NOT
|
||||
renumber */
|
||||
/* User visible DMA mask for DMA control. DO NOT renumber. */
|
||||
ATA_DMA_MASK_ATA = (1 << 0), /* DMA on ATA Disk */
|
||||
ATA_DMA_MASK_ATAPI = (1 << 1), /* DMA on ATAPI */
|
||||
ATA_DMA_MASK_CFA = (1 << 2), /* DMA on CF Card */
|
||||
@ -660,10 +700,25 @@ struct ata_cpr_log {
|
||||
struct ata_cpr cpr[] __counted_by(nr_cpr);
|
||||
};
|
||||
|
||||
struct ata_cdl {
|
||||
/*
|
||||
* Buffer to cache the CDL log page 18h (command duration descriptors)
|
||||
* for SCSI-ATA translation.
|
||||
*/
|
||||
u8 desc_log_buf[ATA_LOG_CDL_SIZE];
|
||||
|
||||
/*
|
||||
* Buffer to handle reading the sense data for successful NCQ Commands
|
||||
* log page for commands using a CDL with one of the limits policy set
|
||||
* to 0xD (successful completion with sense data available bit set).
|
||||
*/
|
||||
u8 ncq_sense_log_buf[ATA_LOG_SENSE_NCQ_SIZE];
|
||||
};
|
||||
|
||||
struct ata_device {
|
||||
struct ata_link *link;
|
||||
unsigned int devno; /* 0 or 1 */
|
||||
unsigned int horkage; /* List of broken features */
|
||||
unsigned int quirks; /* List of broken features */
|
||||
unsigned long flags; /* ATA_DFLAG_xxx */
|
||||
struct scsi_device *sdev; /* attached SCSI device */
|
||||
void *private_data;
|
||||
@ -722,13 +777,16 @@ struct ata_device {
|
||||
/* Concurrent positioning ranges */
|
||||
struct ata_cpr_log *cpr_log;
|
||||
|
||||
/* Command Duration Limits log support */
|
||||
u8 cdl[ATA_LOG_CDL_SIZE];
|
||||
/* Command Duration Limits support */
|
||||
struct ata_cdl *cdl;
|
||||
|
||||
/* error history */
|
||||
int spdn_cnt;
|
||||
/* ering is CLEAR_END, read comment above CLEAR_END */
|
||||
struct ata_ering ering;
|
||||
|
||||
/* For EH */
|
||||
u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
/* Fields between ATA_DEVICE_CLEAR_BEGIN and ATA_DEVICE_CLEAR_END are
|
||||
@ -874,9 +932,6 @@ struct ata_port {
|
||||
#ifdef CONFIG_ATA_ACPI
|
||||
struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */
|
||||
#endif
|
||||
/* owned by EH */
|
||||
u8 *ncq_sense_buf;
|
||||
u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
|
||||
};
|
||||
|
||||
/* The following initializer overrides a method to NULL whether one of
|
||||
@ -1064,8 +1119,6 @@ static inline bool ata_port_is_frozen(const struct ata_port *ap)
|
||||
extern int ata_std_prereset(struct ata_link *link, unsigned long deadline);
|
||||
extern int ata_wait_after_reset(struct ata_link *link, unsigned long deadline,
|
||||
int (*check_ready)(struct ata_link *link));
|
||||
extern int sata_std_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline);
|
||||
extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
|
||||
|
||||
extern struct ata_host *ata_host_alloc(struct device *dev, int n_ports);
|
||||
@ -1129,7 +1182,6 @@ extern int ata_xfer_mode2shift(u8 xfer_mode);
|
||||
extern const char *ata_mode_string(unsigned int xfer_mask);
|
||||
extern unsigned int ata_id_xfermask(const u16 *id);
|
||||
extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
|
||||
extern enum ata_completion_errors ata_noop_qc_prep(struct ata_queued_cmd *qc);
|
||||
extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
|
||||
unsigned int n_elem);
|
||||
extern unsigned int ata_dev_classify(const struct ata_taskfile *tf);
|
||||
@ -1190,12 +1242,13 @@ extern int sata_scr_read(struct ata_link *link, int reg, u32 *val);
|
||||
extern int sata_scr_write(struct ata_link *link, int reg, u32 val);
|
||||
extern int sata_scr_write_flush(struct ata_link *link, int reg, u32 val);
|
||||
extern int sata_set_spd(struct ata_link *link);
|
||||
int sata_std_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline);
|
||||
extern int sata_link_hardreset(struct ata_link *link,
|
||||
const unsigned int *timing, unsigned long deadline,
|
||||
bool *online, int (*check_ready)(struct ata_link *));
|
||||
extern int sata_link_resume(struct ata_link *link, const unsigned int *params,
|
||||
unsigned long deadline);
|
||||
extern int ata_eh_read_sense_success_ncq_log(struct ata_link *link);
|
||||
extern void ata_eh_analyze_ncq_error(struct ata_link *link);
|
||||
#else
|
||||
static inline const unsigned int *
|
||||
@ -1217,6 +1270,11 @@ static inline int sata_scr_write_flush(struct ata_link *link, int reg, u32 val)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int sata_set_spd(struct ata_link *link) { return -EOPNOTSUPP; }
|
||||
static inline int sata_std_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int sata_link_hardreset(struct ata_link *link,
|
||||
const unsigned int *timing,
|
||||
unsigned long deadline,
|
||||
@ -1233,10 +1291,6 @@ static inline int sata_link_resume(struct ata_link *link,
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int ata_eh_read_sense_success_ncq_log(struct ata_link *link)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline void ata_eh_analyze_ncq_error(struct ata_link *link) { }
|
||||
#endif
|
||||
extern int sata_link_debounce(struct ata_link *link,
|
||||
@ -1967,7 +2021,6 @@ extern unsigned int ata_sff_data_xfer(struct ata_queued_cmd *qc,
|
||||
extern unsigned int ata_sff_data_xfer32(struct ata_queued_cmd *qc,
|
||||
unsigned char *buf, unsigned int buflen, int rw);
|
||||
extern void ata_sff_irq_on(struct ata_port *ap);
|
||||
extern void ata_sff_irq_clear(struct ata_port *ap);
|
||||
extern int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc,
|
||||
u8 status, int in_wq);
|
||||
extern void ata_sff_queue_work(struct work_struct *work);
|
||||
|
Loading…
Reference in New Issue
Block a user