mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
Merge tag 'ata-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux
Pull ata updates from Niklas Cassel: - Misc code cleanups related to tag checking and tag command completion (Damien) - Remove Baikal bt1-ahci DT binding since the upstreaming for this SoC is not going to be finalized (Andy) - Only call the libata port error handler from the SCSI error handler if there were command timeouts or if EH was scheduled for the port (Damien) - Refactor ata_scsiop_maint_in() to more clearly show that there is only one service action implemented for the MAINTENANCE IN command (me) - Clean up the handling of sysfs attributes exposed by libata (Heiner) - Let libahci_platform use a flexible array member for platform PHYs to avoid multiple allocations (Rosen) - Do not retry reset if the device has been removed/hot-unplugged (Igor) - Add missing newlines to error prints in pata_arasan_cf driver (Haoyu) - Use the correct SCSI host byte when completing deferred ATA PASS-THROUGH commands, to avoid the SCSI mid-layer from failing the commands instead of requeuing (Igor) * tag 'ata-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/libata/linux: ata: libata-scsi: fix requeue of deferred ATA PASS-THROUGH commands ata: pata_arasan_cf: fix missing newline in dev_err() messages ata: libata-transport: remove static variable ata_scsi_transport_template ata: libata-transport: split struct ata_internal ata: libata-transport: use static struct ata_transport_internal to simplify match functions ata: libata-transport: inline ata_attach|release_transport ata: libata-transport: instantiate struct ata_internal statically ata: libata-eh: Do not retry reset if the device is gone ata: libahci_platform: use flex array for platform PHYs ata: libata-transport: remove redundant dynamic sysfs attributes ata: libata-scsi: refactor ata_scsiop_maint_in() ata: libata-eh: avoid unnecessary calls to ata_scsi_port_error_handler() ata: ahci-dwc: Remove not-going-to-be-supported code for Baikal SoC ata: libata-scsi: rename and improve ata_qc_done() ata: libata-scsi: make ata_scsi_simulate() static ata: libata-scsi: simplify ata_scsi_requeue_deferred_qc() ata: libata-sata: simplify ata_sas_queuecmd() ata: libata-core: improve tag checks in ata_qc_issue()
This commit is contained in:
@@ -1,115 +0,0 @@
|
|||||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
|
||||||
%YAML 1.2
|
|
||||||
---
|
|
||||||
$id: http://devicetree.org/schemas/ata/baikal,bt1-ahci.yaml#
|
|
||||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
|
||||||
|
|
||||||
title: Baikal-T1 SoC AHCI SATA controller
|
|
||||||
|
|
||||||
maintainers:
|
|
||||||
- Serge Semin <fancer.lancer@gmail.com>
|
|
||||||
|
|
||||||
description:
|
|
||||||
AHCI SATA controller embedded into the Baikal-T1 SoC is based on the
|
|
||||||
DWC AHCI SATA v4.10a IP-core.
|
|
||||||
|
|
||||||
allOf:
|
|
||||||
- $ref: snps,dwc-ahci-common.yaml#
|
|
||||||
|
|
||||||
properties:
|
|
||||||
compatible:
|
|
||||||
const: baikal,bt1-ahci
|
|
||||||
|
|
||||||
clocks:
|
|
||||||
items:
|
|
||||||
- description: Peripheral APB bus clock
|
|
||||||
- description: Application AXI BIU clock
|
|
||||||
- description: SATA Ports reference clock
|
|
||||||
|
|
||||||
clock-names:
|
|
||||||
items:
|
|
||||||
- const: pclk
|
|
||||||
- const: aclk
|
|
||||||
- const: ref
|
|
||||||
|
|
||||||
resets:
|
|
||||||
items:
|
|
||||||
- description: Application AXI BIU domain reset
|
|
||||||
- description: SATA Ports clock domain reset
|
|
||||||
|
|
||||||
reset-names:
|
|
||||||
items:
|
|
||||||
- const: arst
|
|
||||||
- const: ref
|
|
||||||
|
|
||||||
ports-implemented:
|
|
||||||
maximum: 0x3
|
|
||||||
|
|
||||||
patternProperties:
|
|
||||||
"^sata-port@[0-1]$":
|
|
||||||
$ref: /schemas/ata/snps,dwc-ahci-common.yaml#/$defs/dwc-ahci-port
|
|
||||||
|
|
||||||
properties:
|
|
||||||
reg:
|
|
||||||
minimum: 0
|
|
||||||
maximum: 1
|
|
||||||
|
|
||||||
snps,tx-ts-max:
|
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
|
||||||
description:
|
|
||||||
Due to having AXI3 bus interface utilized the maximum Tx DMA
|
|
||||||
transaction size can't exceed 16 beats (AxLEN[3:0]).
|
|
||||||
enum: [ 1, 2, 4, 8, 16 ]
|
|
||||||
|
|
||||||
snps,rx-ts-max:
|
|
||||||
$ref: /schemas/types.yaml#/definitions/uint32
|
|
||||||
description:
|
|
||||||
Due to having AXI3 bus interface utilized the maximum Rx DMA
|
|
||||||
transaction size can't exceed 16 beats (AxLEN[3:0]).
|
|
||||||
enum: [ 1, 2, 4, 8, 16 ]
|
|
||||||
|
|
||||||
unevaluatedProperties: false
|
|
||||||
|
|
||||||
required:
|
|
||||||
- compatible
|
|
||||||
- reg
|
|
||||||
- interrupts
|
|
||||||
- clocks
|
|
||||||
- clock-names
|
|
||||||
- resets
|
|
||||||
|
|
||||||
unevaluatedProperties: false
|
|
||||||
|
|
||||||
examples:
|
|
||||||
- |
|
|
||||||
sata@1f050000 {
|
|
||||||
compatible = "baikal,bt1-ahci";
|
|
||||||
reg = <0x1f050000 0x2000>;
|
|
||||||
#address-cells = <1>;
|
|
||||||
#size-cells = <0>;
|
|
||||||
|
|
||||||
interrupts = <0 64 4>;
|
|
||||||
|
|
||||||
clocks = <&ccu_sys 1>, <&ccu_axi 2>, <&sata_ref_clk>;
|
|
||||||
clock-names = "pclk", "aclk", "ref";
|
|
||||||
|
|
||||||
resets = <&ccu_axi 2>, <&ccu_sys 0>;
|
|
||||||
reset-names = "arst", "ref";
|
|
||||||
|
|
||||||
ports-implemented = <0x3>;
|
|
||||||
|
|
||||||
sata-port@0 {
|
|
||||||
reg = <0>;
|
|
||||||
|
|
||||||
snps,tx-ts-max = <4>;
|
|
||||||
snps,rx-ts-max = <4>;
|
|
||||||
};
|
|
||||||
|
|
||||||
sata-port@1 {
|
|
||||||
reg = <1>;
|
|
||||||
|
|
||||||
snps,tx-ts-max = <4>;
|
|
||||||
snps,rx-ts-max = <4>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
...
|
|
||||||
@@ -194,7 +194,6 @@ config AHCI_DM816
|
|||||||
config AHCI_DWC
|
config AHCI_DWC
|
||||||
tristate "Synopsys DWC AHCI SATA support"
|
tristate "Synopsys DWC AHCI SATA support"
|
||||||
select SATA_HOST
|
select SATA_HOST
|
||||||
select MFD_SYSCON if (MIPS_BAIKAL_T1 || COMPILE_TEST)
|
|
||||||
help
|
help
|
||||||
This option enables support for the Synopsys DWC AHCI SATA
|
This option enables support for the Synopsys DWC AHCI SATA
|
||||||
controller implementation.
|
controller implementation.
|
||||||
|
|||||||
@@ -357,7 +357,6 @@ struct ahci_host_priv {
|
|||||||
* If platform uses PHYs. There is a 1:1 relation between the port number and
|
* If platform uses PHYs. There is a 1:1 relation between the port number and
|
||||||
* the PHY position in this array.
|
* the PHY position in this array.
|
||||||
*/
|
*/
|
||||||
struct phy **phys;
|
|
||||||
unsigned nports; /* Number of ports */
|
unsigned nports; /* Number of ports */
|
||||||
void *plat_data; /* Other platform data */
|
void *plat_data; /* Other platform data */
|
||||||
unsigned int irq; /* interrupt line */
|
unsigned int irq; /* interrupt line */
|
||||||
@@ -379,6 +378,8 @@ struct ahci_host_priv {
|
|||||||
/* only required for per-port MSI(-X) support */
|
/* only required for per-port MSI(-X) support */
|
||||||
int (*get_irq_vector)(struct ata_host *host,
|
int (*get_irq_vector)(struct ata_host *host,
|
||||||
int port);
|
int port);
|
||||||
|
|
||||||
|
struct phy *phys[] __counted_by(nports);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -13,12 +13,10 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/libata.h>
|
#include <linux/libata.h>
|
||||||
#include <linux/log2.h>
|
#include <linux/log2.h>
|
||||||
#include <linux/mfd/syscon.h>
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/regmap.h>
|
|
||||||
|
|
||||||
#include "ahci.h"
|
#include "ahci.h"
|
||||||
|
|
||||||
@@ -92,20 +90,6 @@
|
|||||||
#define AHCI_DWC_PORT_PHYCR 0x74
|
#define AHCI_DWC_PORT_PHYCR 0x74
|
||||||
#define AHCI_DWC_PORT_PHYSR 0x78
|
#define AHCI_DWC_PORT_PHYSR 0x78
|
||||||
|
|
||||||
/* Baikal-T1 AHCI SATA specific registers */
|
|
||||||
#define AHCI_BT1_HOST_PHYCR AHCI_DWC_HOST_GPCR
|
|
||||||
#define AHCI_BT1_HOST_MPLM_MASK GENMASK(29, 23)
|
|
||||||
#define AHCI_BT1_HOST_LOSDT_MASK GENMASK(22, 20)
|
|
||||||
#define AHCI_BT1_HOST_CRR BIT(19)
|
|
||||||
#define AHCI_BT1_HOST_CRW BIT(18)
|
|
||||||
#define AHCI_BT1_HOST_CRCD BIT(17)
|
|
||||||
#define AHCI_BT1_HOST_CRCA BIT(16)
|
|
||||||
#define AHCI_BT1_HOST_CRDI_MASK GENMASK(15, 0)
|
|
||||||
|
|
||||||
#define AHCI_BT1_HOST_PHYSR AHCI_DWC_HOST_GPSR
|
|
||||||
#define AHCI_BT1_HOST_CRA BIT(16)
|
|
||||||
#define AHCI_BT1_HOST_CRDO_MASK GENMASK(15, 0)
|
|
||||||
|
|
||||||
struct ahci_dwc_plat_data {
|
struct ahci_dwc_plat_data {
|
||||||
unsigned int pflags;
|
unsigned int pflags;
|
||||||
unsigned int hflags;
|
unsigned int hflags;
|
||||||
@@ -122,39 +106,6 @@ struct ahci_dwc_host_priv {
|
|||||||
u32 dmacr[AHCI_MAX_PORTS];
|
u32 dmacr[AHCI_MAX_PORTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ahci_bt1_init(struct ahci_host_priv *hpriv)
|
|
||||||
{
|
|
||||||
struct ahci_dwc_host_priv *dpriv = hpriv->plat_data;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* APB, application and reference clocks are required */
|
|
||||||
if (!ahci_platform_find_clk(hpriv, "pclk") ||
|
|
||||||
!ahci_platform_find_clk(hpriv, "aclk") ||
|
|
||||||
!ahci_platform_find_clk(hpriv, "ref")) {
|
|
||||||
dev_err(&dpriv->pdev->dev, "No system clocks specified\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fully reset the SATA AXI and ref clocks domain to ensure the state
|
|
||||||
* machine is working from scratch especially if the reference clocks
|
|
||||||
* source has been changed.
|
|
||||||
*/
|
|
||||||
ret = ahci_platform_assert_rsts(hpriv);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&dpriv->pdev->dev, "Couldn't assert the resets\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = ahci_platform_deassert_rsts(hpriv);
|
|
||||||
if (ret) {
|
|
||||||
dev_err(&dpriv->pdev->dev, "Couldn't de-assert the resets\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct ahci_host_priv *ahci_dwc_get_resources(struct platform_device *pdev)
|
static struct ahci_host_priv *ahci_dwc_get_resources(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct ahci_dwc_host_priv *dpriv;
|
struct ahci_dwc_host_priv *dpriv;
|
||||||
@@ -457,15 +408,9 @@ static struct ahci_dwc_plat_data ahci_dwc_plat = {
|
|||||||
.pflags = AHCI_PLATFORM_GET_RESETS,
|
.pflags = AHCI_PLATFORM_GET_RESETS,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ahci_dwc_plat_data ahci_bt1_plat = {
|
|
||||||
.pflags = AHCI_PLATFORM_GET_RESETS | AHCI_PLATFORM_RST_TRIGGER,
|
|
||||||
.init = ahci_bt1_init,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct of_device_id ahci_dwc_of_match[] = {
|
static const struct of_device_id ahci_dwc_of_match[] = {
|
||||||
{ .compatible = "snps,dwc-ahci", &ahci_dwc_plat },
|
{ .compatible = "snps,dwc-ahci", &ahci_dwc_plat },
|
||||||
{ .compatible = "snps,spear-ahci", &ahci_dwc_plat },
|
{ .compatible = "snps,spear-ahci", &ahci_dwc_plat },
|
||||||
{ .compatible = "baikal,bt1-ahci", &ahci_bt1_plat },
|
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, ahci_dwc_of_match);
|
MODULE_DEVICE_TABLE(of, ahci_dwc_of_match);
|
||||||
|
|||||||
@@ -482,15 +482,29 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
|||||||
struct ahci_host_priv *hpriv;
|
struct ahci_host_priv *hpriv;
|
||||||
u32 mask_port_map = 0;
|
u32 mask_port_map = 0;
|
||||||
u32 max_port;
|
u32 max_port;
|
||||||
|
int nports;
|
||||||
|
|
||||||
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
if (!devres_open_group(dev, NULL, GFP_KERNEL))
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
|
/* find maximum port id for allocating structures */
|
||||||
|
max_port = ahci_platform_find_max_port_id(dev);
|
||||||
|
/*
|
||||||
|
* Set nports according to maximum port id. Clamp at
|
||||||
|
* AHCI_MAX_PORTS, warning message for invalid port id
|
||||||
|
* is generated later.
|
||||||
|
* When DT has no sub-nodes max_port is 0, nports is 1,
|
||||||
|
* in order to be able to use the
|
||||||
|
* ahci_platform_[en|dis]able_[phys|regulators] functions.
|
||||||
|
*/
|
||||||
|
nports = min(AHCI_MAX_PORTS, max_port + 1);
|
||||||
|
hpriv = devres_alloc(ahci_platform_put_resources, struct_size(hpriv, phys, nports),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!hpriv)
|
if (!hpriv)
|
||||||
goto err_out;
|
goto err_out;
|
||||||
|
|
||||||
|
hpriv->nports = nports;
|
||||||
|
|
||||||
devres_add(dev, hpriv);
|
devres_add(dev, hpriv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -573,23 +587,6 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
|
|||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find maximum port id for allocating structures */
|
|
||||||
max_port = ahci_platform_find_max_port_id(dev);
|
|
||||||
/*
|
|
||||||
* Set nports according to maximum port id. Clamp at
|
|
||||||
* AHCI_MAX_PORTS, warning message for invalid port id
|
|
||||||
* is generated later.
|
|
||||||
* When DT has no sub-nodes max_port is 0, nports is 1,
|
|
||||||
* in order to be able to use the
|
|
||||||
* ahci_platform_[en|dis]able_[phys|regulators] functions.
|
|
||||||
*/
|
|
||||||
hpriv->nports = min(AHCI_MAX_PORTS, max_port + 1);
|
|
||||||
|
|
||||||
hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL);
|
|
||||||
if (!hpriv->phys) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* We cannot use devm_ here, since ahci_platform_put_resources() uses
|
* We cannot use devm_ here, since ahci_platform_put_resources() uses
|
||||||
* target_pwrs after devm_ have freed memory
|
* target_pwrs after devm_ have freed memory
|
||||||
|
|||||||
@@ -5151,8 +5151,13 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
|
|||||||
struct ata_link *link = qc->dev->link;
|
struct ata_link *link = qc->dev->link;
|
||||||
u8 prot = qc->tf.protocol;
|
u8 prot = qc->tf.protocol;
|
||||||
|
|
||||||
/* Make sure only one non-NCQ command is outstanding. */
|
/*
|
||||||
WARN_ON_ONCE(ata_tag_valid(link->active_tag));
|
* Make sure we have a valid tag and that only one non-NCQ command is
|
||||||
|
* outstanding.
|
||||||
|
*/
|
||||||
|
if (WARN_ON_ONCE(!ata_tag_valid(qc->tag)) ||
|
||||||
|
WARN_ON_ONCE(ata_tag_valid(link->active_tag)))
|
||||||
|
goto sys_err;
|
||||||
|
|
||||||
if (ata_is_ncq(prot)) {
|
if (ata_is_ncq(prot)) {
|
||||||
WARN_ON_ONCE(link->sactive & (1 << qc->hw_tag));
|
WARN_ON_ONCE(link->sactive & (1 << qc->hw_tag));
|
||||||
@@ -6773,23 +6778,14 @@ static int __init ata_init(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
libata_transport_init();
|
libata_transport_init();
|
||||||
ata_scsi_transport_template = ata_attach_transport();
|
|
||||||
if (!ata_scsi_transport_template) {
|
|
||||||
ata_sff_exit();
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
|
printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_out:
|
return 0;
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __exit ata_exit(void)
|
static void __exit ata_exit(void)
|
||||||
{
|
{
|
||||||
ata_release_transport(ata_scsi_transport_template);
|
|
||||||
libata_transport_exit();
|
libata_transport_exit();
|
||||||
ata_sff_exit();
|
ata_sff_exit();
|
||||||
ata_free_force_param();
|
ata_free_force_param();
|
||||||
|
|||||||
@@ -560,21 +560,27 @@ void ata_scsi_error(struct Scsi_Host *host)
|
|||||||
{
|
{
|
||||||
struct ata_port *ap = ata_shost_to_port(host);
|
struct ata_port *ap = ata_shost_to_port(host);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
int nr_timedout;
|
||||||
LIST_HEAD(eh_work_q);
|
LIST_HEAD(eh_work_q);
|
||||||
|
|
||||||
spin_lock_irqsave(host->host_lock, flags);
|
spin_lock_irqsave(host->host_lock, flags);
|
||||||
list_splice_init(&host->eh_cmd_q, &eh_work_q);
|
list_splice_init(&host->eh_cmd_q, &eh_work_q);
|
||||||
spin_unlock_irqrestore(host->host_lock, flags);
|
spin_unlock_irqrestore(host->host_lock, flags);
|
||||||
|
|
||||||
ata_scsi_cmd_error_handler(host, ap, &eh_work_q);
|
/*
|
||||||
|
* First check what errors we got with ata_scsi_cmd_error_handler().
|
||||||
|
* If we had no command timeouts and EH is not scheduled for this port,
|
||||||
|
* meaning that we do not have any failed command, then there is no
|
||||||
|
* need to go through the full port error handling. We only need to
|
||||||
|
* flush the completed commands we have.
|
||||||
|
*/
|
||||||
|
nr_timedout = ata_scsi_cmd_error_handler(host, ap, &eh_work_q);
|
||||||
|
if (nr_timedout || ata_port_eh_scheduled(ap))
|
||||||
|
ata_scsi_port_error_handler(host, ap);
|
||||||
|
else
|
||||||
|
scsi_eh_flush_done_q(&ap->eh_done_q);
|
||||||
|
|
||||||
/* If we timed raced normal completion and there is nothing to
|
|
||||||
recover nr_timedout == 0 why exactly are we doing error recovery ? */
|
|
||||||
ata_scsi_port_error_handler(host, ap);
|
|
||||||
|
|
||||||
/* finish or retry handled scmd's and clean up */
|
|
||||||
WARN_ON(!list_empty(&eh_work_q));
|
WARN_ON(!list_empty(&eh_work_q));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -586,9 +592,11 @@ void ata_scsi_error(struct Scsi_Host *host)
|
|||||||
* process the given list of commands and return those finished to the
|
* process the given list of commands and return those finished to the
|
||||||
* ap->eh_done_q. This function is the first part of the libata error
|
* ap->eh_done_q. This function is the first part of the libata error
|
||||||
* handler which processes a given list of failed commands.
|
* handler which processes a given list of failed commands.
|
||||||
|
*
|
||||||
|
* Return the number of commands that timed out.
|
||||||
*/
|
*/
|
||||||
void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
|
int ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
|
||||||
struct list_head *eh_work_q)
|
struct list_head *eh_work_q)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@@ -695,6 +703,8 @@ void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
|
|||||||
ap->eh_tries = ATA_EH_MAX_TRIES;
|
ap->eh_tries = ATA_EH_MAX_TRIES;
|
||||||
|
|
||||||
spin_unlock_irqrestore(ap->lock, flags);
|
spin_unlock_irqrestore(ap->lock, flags);
|
||||||
|
|
||||||
|
return nr_timedout;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
|
EXPORT_SYMBOL(ata_scsi_cmd_error_handler);
|
||||||
|
|
||||||
@@ -3171,7 +3181,7 @@ int ata_eh_reset(struct ata_link *link, int classify,
|
|||||||
sata_scr_read(link, SCR_STATUS, &sstatus))
|
sata_scr_read(link, SCR_STATUS, &sstatus))
|
||||||
rc = -ERESTART;
|
rc = -ERESTART;
|
||||||
|
|
||||||
if (try >= max_tries) {
|
if (try >= max_tries || rc == -ENODEV) {
|
||||||
/*
|
/*
|
||||||
* Thaw host port even if reset failed, so that the port
|
* Thaw host port even if reset failed, so that the port
|
||||||
* can be retried on the next phy event. This risks
|
* can be retried on the next phy event. This risks
|
||||||
|
|||||||
@@ -1378,15 +1378,13 @@ EXPORT_SYMBOL_GPL(ata_sas_sdev_configure);
|
|||||||
|
|
||||||
int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
|
int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
|
||||||
|
|
||||||
if (likely(ata_dev_enabled(ap->link.device)))
|
if (likely(ata_dev_enabled(ap->link.device)))
|
||||||
rc = __ata_scsi_queuecmd(cmd, ap->link.device);
|
return __ata_scsi_queuecmd(cmd, ap->link.device);
|
||||||
else {
|
|
||||||
cmd->result = (DID_BAD_TARGET << 16);
|
cmd->result = (DID_BAD_TARGET << 16);
|
||||||
scsi_done(cmd);
|
scsi_done(cmd);
|
||||||
}
|
|
||||||
return rc;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
|
EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
|
||||||
|
|
||||||
|
|||||||
@@ -1649,12 +1649,16 @@ nothing_to_do:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ata_qc_done(struct ata_queued_cmd *qc)
|
static void ata_scsi_qc_done(struct ata_queued_cmd *qc, bool set_result,
|
||||||
|
u32 scmd_result)
|
||||||
{
|
{
|
||||||
struct scsi_cmnd *cmd = qc->scsicmd;
|
struct scsi_cmnd *cmd = qc->scsicmd;
|
||||||
void (*done)(struct scsi_cmnd *) = qc->scsidone;
|
void (*done)(struct scsi_cmnd *) = qc->scsidone;
|
||||||
|
|
||||||
ata_qc_free(qc);
|
ata_qc_free(qc);
|
||||||
|
|
||||||
|
if (set_result)
|
||||||
|
cmd->result = scmd_result;
|
||||||
done(cmd);
|
done(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1685,24 +1689,19 @@ void ata_scsi_deferred_qc_work(struct work_struct *work)
|
|||||||
void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
|
void ata_scsi_requeue_deferred_qc(struct ata_port *ap)
|
||||||
{
|
{
|
||||||
struct ata_queued_cmd *qc = ap->deferred_qc;
|
struct ata_queued_cmd *qc = ap->deferred_qc;
|
||||||
struct scsi_cmnd *scmd;
|
|
||||||
|
|
||||||
lockdep_assert_held(ap->lock);
|
lockdep_assert_held(ap->lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have a deferred qc when a reset occurs or NCQ commands fail,
|
* If we have a deferred qc when a reset occurs or NCQ commands fail,
|
||||||
* do not try to be smart about what to do with this deferred command
|
* do not try to be smart about what to do with this deferred command
|
||||||
* and simply retry it by completing it with DID_SOFT_ERROR.
|
* and simply requeue it by completing it with DID_REQUEUE.
|
||||||
*/
|
*/
|
||||||
if (!qc)
|
if (qc) {
|
||||||
return;
|
ap->deferred_qc = NULL;
|
||||||
|
cancel_work(&ap->deferred_qc_work);
|
||||||
scmd = qc->scsicmd;
|
ata_scsi_qc_done(qc, true, DID_REQUEUE << 16);
|
||||||
ap->deferred_qc = NULL;
|
}
|
||||||
cancel_work(&ap->deferred_qc_work);
|
|
||||||
ata_qc_free(qc);
|
|
||||||
scmd->result = (DID_SOFT_ERROR << 16);
|
|
||||||
scsi_done(scmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ata_scsi_schedule_deferred_qc(struct ata_port *ap)
|
static void ata_scsi_schedule_deferred_qc(struct ata_port *ap)
|
||||||
@@ -1758,7 +1757,7 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc)
|
|||||||
ata_scsi_set_sense_information(qc);
|
ata_scsi_set_sense_information(qc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ata_qc_done(qc);
|
ata_scsi_qc_done(qc, false, 0);
|
||||||
|
|
||||||
ata_scsi_schedule_deferred_qc(ap);
|
ata_scsi_schedule_deferred_qc(ap);
|
||||||
}
|
}
|
||||||
@@ -2917,17 +2916,15 @@ static void atapi_qc_complete(struct ata_queued_cmd *qc)
|
|||||||
if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
|
if (qc->cdb[0] == ALLOW_MEDIUM_REMOVAL && qc->dev->sdev)
|
||||||
qc->dev->sdev->locked = 0;
|
qc->dev->sdev->locked = 0;
|
||||||
|
|
||||||
qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
|
ata_scsi_qc_done(qc, true, SAM_STAT_CHECK_CONDITION);
|
||||||
ata_qc_done(qc);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* successful completion path */
|
/* successful completion path */
|
||||||
if (cmd->cmnd[0] == INQUIRY && (cmd->cmnd[1] & 0x03) == 0)
|
if (cmd->cmnd[0] == INQUIRY && (cmd->cmnd[1] & 0x03) == 0)
|
||||||
atapi_fixup_inquiry(cmd);
|
atapi_fixup_inquiry(cmd);
|
||||||
cmd->result = SAM_STAT_GOOD;
|
|
||||||
|
|
||||||
ata_qc_done(qc);
|
ata_scsi_qc_done(qc, true, SAM_STAT_GOOD);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* atapi_xlat - Initialize PACKET taskfile
|
* atapi_xlat - Initialize PACKET taskfile
|
||||||
@@ -3576,28 +3573,13 @@ invalid_opcode:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static unsigned int ata_scsi_report_supported_opcodes(struct ata_device *dev,
|
||||||
* ata_scsiop_maint_in - Simulate a subset of MAINTENANCE_IN
|
struct scsi_cmnd *cmd,
|
||||||
* @dev: Target device.
|
u8 *rbuf)
|
||||||
* @cmd: SCSI command of interest.
|
|
||||||
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
|
|
||||||
*
|
|
||||||
* Yields a subset to satisfy scsi_report_opcode()
|
|
||||||
*
|
|
||||||
* LOCKING:
|
|
||||||
* spin_lock_irqsave(host lock)
|
|
||||||
*/
|
|
||||||
static unsigned int ata_scsiop_maint_in(struct ata_device *dev,
|
|
||||||
struct scsi_cmnd *cmd, u8 *rbuf)
|
|
||||||
{
|
{
|
||||||
u8 *cdb = cmd->cmnd;
|
u8 *cdb = cmd->cmnd;
|
||||||
u8 supported = 0, cdlp = 0, rwcdlp = 0;
|
u8 supported = 0, cdlp = 0, rwcdlp = 0;
|
||||||
|
|
||||||
if ((cdb[1] & 0x1f) != MI_REPORT_SUPPORTED_OPERATION_CODES) {
|
|
||||||
ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cdb[2] != 1 && cdb[2] != 3) {
|
if (cdb[2] != 1 && cdb[2] != 3) {
|
||||||
ata_dev_warn(dev, "invalid command format %d\n", cdb[2]);
|
ata_dev_warn(dev, "invalid command format %d\n", cdb[2]);
|
||||||
ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
|
ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
|
||||||
@@ -3677,6 +3659,32 @@ static unsigned int ata_scsiop_maint_in(struct ata_device *dev,
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ata_scsiop_maint_in - Simulate a subset of MAINTENANCE_IN
|
||||||
|
* @dev: Target device.
|
||||||
|
* @cmd: SCSI command of interest.
|
||||||
|
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
|
||||||
|
*
|
||||||
|
* Yields a subset to satisfy scsi_report_opcode()
|
||||||
|
*
|
||||||
|
* LOCKING:
|
||||||
|
* spin_lock_irqsave(host lock)
|
||||||
|
*/
|
||||||
|
static unsigned int ata_scsiop_maint_in(struct ata_device *dev,
|
||||||
|
struct scsi_cmnd *cmd, u8 *rbuf)
|
||||||
|
{
|
||||||
|
u8 *cdb = cmd->cmnd;
|
||||||
|
u8 service_action = cdb[1] & 0x1f;
|
||||||
|
|
||||||
|
switch (service_action) {
|
||||||
|
case MI_REPORT_SUPPORTED_OPERATION_CODES:
|
||||||
|
return ata_scsi_report_supported_opcodes(dev, cmd, rbuf);
|
||||||
|
default:
|
||||||
|
ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ata_scsi_report_zones_complete - convert ATA output
|
* ata_scsi_report_zones_complete - convert ATA output
|
||||||
* @qc: command structure returning the data
|
* @qc: command structure returning the data
|
||||||
@@ -4424,6 +4432,79 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ata_scsi_simulate - simulate SCSI command on ATA device
|
||||||
|
* @dev: the target device
|
||||||
|
* @cmd: SCSI command being sent to device.
|
||||||
|
*
|
||||||
|
* Interprets and directly executes a select list of SCSI commands
|
||||||
|
* that can be handled internally.
|
||||||
|
*
|
||||||
|
* LOCKING:
|
||||||
|
* spin_lock_irqsave(host lock)
|
||||||
|
*/
|
||||||
|
static void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
|
||||||
|
{
|
||||||
|
const u8 *scsicmd = cmd->cmnd;
|
||||||
|
u8 tmp8;
|
||||||
|
|
||||||
|
switch (scsicmd[0]) {
|
||||||
|
case INQUIRY:
|
||||||
|
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_inquiry);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_SENSE:
|
||||||
|
case MODE_SENSE_10:
|
||||||
|
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_mode_sense);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case READ_CAPACITY:
|
||||||
|
case SERVICE_ACTION_IN_16:
|
||||||
|
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_read_cap);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REPORT_LUNS:
|
||||||
|
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_report_luns);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REQUEST_SENSE:
|
||||||
|
ata_scsi_set_sense(dev, cmd, 0, 0, 0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* if we reach this, then writeback caching is disabled,
|
||||||
|
* turning this into a no-op.
|
||||||
|
*/
|
||||||
|
case SYNCHRONIZE_CACHE:
|
||||||
|
case SYNCHRONIZE_CACHE_16:
|
||||||
|
fallthrough;
|
||||||
|
|
||||||
|
/* no-op's, complete with success */
|
||||||
|
case REZERO_UNIT:
|
||||||
|
case SEEK_6:
|
||||||
|
case SEEK_10:
|
||||||
|
case TEST_UNIT_READY:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEND_DIAGNOSTIC:
|
||||||
|
tmp8 = scsicmd[1] & ~(1 << 3);
|
||||||
|
if (tmp8 != 0x4 || scsicmd[3] || scsicmd[4])
|
||||||
|
ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MAINTENANCE_IN:
|
||||||
|
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_maint_in);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* all other commands */
|
||||||
|
default:
|
||||||
|
ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0);
|
||||||
|
/* "Invalid command operation code" */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
scsi_done(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
enum scsi_qc_status __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
|
enum scsi_qc_status __ata_scsi_queuecmd(struct scsi_cmnd *scmd,
|
||||||
struct ata_device *dev)
|
struct ata_device *dev)
|
||||||
{
|
{
|
||||||
@@ -4526,80 +4607,6 @@ enum scsi_qc_status ata_scsi_queuecmd(struct Scsi_Host *shost,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
|
EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
|
||||||
|
|
||||||
/**
|
|
||||||
* ata_scsi_simulate - simulate SCSI command on ATA device
|
|
||||||
* @dev: the target device
|
|
||||||
* @cmd: SCSI command being sent to device.
|
|
||||||
*
|
|
||||||
* Interprets and directly executes a select list of SCSI commands
|
|
||||||
* that can be handled internally.
|
|
||||||
*
|
|
||||||
* LOCKING:
|
|
||||||
* spin_lock_irqsave(host lock)
|
|
||||||
*/
|
|
||||||
|
|
||||||
void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
|
|
||||||
{
|
|
||||||
const u8 *scsicmd = cmd->cmnd;
|
|
||||||
u8 tmp8;
|
|
||||||
|
|
||||||
switch(scsicmd[0]) {
|
|
||||||
case INQUIRY:
|
|
||||||
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_inquiry);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MODE_SENSE:
|
|
||||||
case MODE_SENSE_10:
|
|
||||||
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_mode_sense);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case READ_CAPACITY:
|
|
||||||
case SERVICE_ACTION_IN_16:
|
|
||||||
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_read_cap);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REPORT_LUNS:
|
|
||||||
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_report_luns);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REQUEST_SENSE:
|
|
||||||
ata_scsi_set_sense(dev, cmd, 0, 0, 0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* if we reach this, then writeback caching is disabled,
|
|
||||||
* turning this into a no-op.
|
|
||||||
*/
|
|
||||||
case SYNCHRONIZE_CACHE:
|
|
||||||
case SYNCHRONIZE_CACHE_16:
|
|
||||||
fallthrough;
|
|
||||||
|
|
||||||
/* no-op's, complete with success */
|
|
||||||
case REZERO_UNIT:
|
|
||||||
case SEEK_6:
|
|
||||||
case SEEK_10:
|
|
||||||
case TEST_UNIT_READY:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SEND_DIAGNOSTIC:
|
|
||||||
tmp8 = scsicmd[1] & ~(1 << 3);
|
|
||||||
if (tmp8 != 0x4 || scsicmd[3] || scsicmd[4])
|
|
||||||
ata_scsi_set_invalid_field(dev, cmd, 1, 0xff);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MAINTENANCE_IN:
|
|
||||||
ata_scsi_rbuf_fill(dev, cmd, ata_scsiop_maint_in);
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* all other commands */
|
|
||||||
default:
|
|
||||||
ata_scsi_set_sense(dev, cmd, ILLEGAL_REQUEST, 0x20, 0x0);
|
|
||||||
/* "Invalid command operation code" */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
scsi_done(cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ata_scsi_add_hosts(struct ata_host *host, const struct scsi_host_template *sht)
|
int ata_scsi_add_hosts(struct ata_host *host, const struct scsi_host_template *sht)
|
||||||
{
|
{
|
||||||
int i, rc;
|
int i, rc;
|
||||||
@@ -4617,7 +4624,7 @@ int ata_scsi_add_hosts(struct ata_host *host, const struct scsi_host_template *s
|
|||||||
*(struct ata_port **)&shost->hostdata[0] = ap;
|
*(struct ata_port **)&shost->hostdata[0] = ap;
|
||||||
ap->scsi_host = shost;
|
ap->scsi_host = shost;
|
||||||
|
|
||||||
shost->transportt = ata_scsi_transport_template;
|
shost->transportt = &ata_scsi_transportt;
|
||||||
shost->unique_id = ap->print_id;
|
shost->unique_id = ap->print_id;
|
||||||
shost->max_id = 16;
|
shost->max_id = 16;
|
||||||
shost->max_lun = 1;
|
shost->max_lun = 1;
|
||||||
|
|||||||
@@ -37,33 +37,10 @@
|
|||||||
#include "libata.h"
|
#include "libata.h"
|
||||||
#include "libata-transport.h"
|
#include "libata-transport.h"
|
||||||
|
|
||||||
#define ATA_PORT_ATTRS 3
|
static int ata_tlink_match(struct attribute_container *cont,
|
||||||
#define ATA_LINK_ATTRS 3
|
struct device *dev);
|
||||||
#define ATA_DEV_ATTRS 9
|
static int ata_tdev_match(struct attribute_container *cont,
|
||||||
|
struct device *dev);
|
||||||
struct scsi_transport_template;
|
|
||||||
struct scsi_transport_template *ata_scsi_transport_template;
|
|
||||||
|
|
||||||
struct ata_internal {
|
|
||||||
struct scsi_transport_template t;
|
|
||||||
|
|
||||||
struct device_attribute private_port_attrs[ATA_PORT_ATTRS];
|
|
||||||
struct device_attribute private_link_attrs[ATA_LINK_ATTRS];
|
|
||||||
struct device_attribute private_dev_attrs[ATA_DEV_ATTRS];
|
|
||||||
|
|
||||||
struct transport_container link_attr_cont;
|
|
||||||
struct transport_container dev_attr_cont;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The array of null terminated pointers to attributes
|
|
||||||
* needed by scsi_sysfs.c
|
|
||||||
*/
|
|
||||||
struct device_attribute *link_attrs[ATA_LINK_ATTRS + 1];
|
|
||||||
struct device_attribute *port_attrs[ATA_PORT_ATTRS + 1];
|
|
||||||
struct device_attribute *dev_attrs[ATA_DEV_ATTRS + 1];
|
|
||||||
};
|
|
||||||
#define to_ata_internal(tmpl) container_of(tmpl, struct ata_internal, t)
|
|
||||||
|
|
||||||
|
|
||||||
#define tdev_to_device(d) \
|
#define tdev_to_device(d) \
|
||||||
container_of((d), struct ata_device, tdev)
|
container_of((d), struct ata_device, tdev)
|
||||||
@@ -80,13 +57,6 @@ struct ata_internal {
|
|||||||
#define transport_class_to_port(dev) \
|
#define transport_class_to_port(dev) \
|
||||||
tdev_to_port((dev)->parent)
|
tdev_to_port((dev)->parent)
|
||||||
|
|
||||||
/*
|
|
||||||
* Hack to allow attributes of the same name in different objects.
|
|
||||||
*/
|
|
||||||
#define ATA_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \
|
|
||||||
struct device_attribute device_attr_##_prefix##_##_name = \
|
|
||||||
__ATTR(_name,_mode,_show,_store)
|
|
||||||
|
|
||||||
#define ata_bitfield_name_match(title, table) \
|
#define ata_bitfield_name_match(title, table) \
|
||||||
static ssize_t \
|
static ssize_t \
|
||||||
get_ata_##title##_names(u32 table_key, char *buf) \
|
get_ata_##title##_names(u32 table_key, char *buf) \
|
||||||
@@ -214,6 +184,17 @@ ata_port_simple_attr(stats.idle_irq, idle_irq, "%ld\n", unsigned long);
|
|||||||
/* We want the port_no sysfs attibute to start at 1 (ap->port_no starts at 0) */
|
/* We want the port_no sysfs attibute to start at 1 (ap->port_no starts at 0) */
|
||||||
ata_port_simple_attr(port_no + 1, port_no, "%u\n", unsigned int);
|
ata_port_simple_attr(port_no + 1, port_no, "%u\n", unsigned int);
|
||||||
|
|
||||||
|
static const struct attribute *const ata_port_attr_attrs[] = {
|
||||||
|
&dev_attr_nr_pmp_links.attr,
|
||||||
|
&dev_attr_idle_irq.attr,
|
||||||
|
&dev_attr_port_no.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group ata_port_attr_group = {
|
||||||
|
.attrs_const = ata_port_attr_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
static DECLARE_TRANSPORT_CLASS(ata_port_class,
|
static DECLARE_TRANSPORT_CLASS(ata_port_class,
|
||||||
"ata_port", NULL, NULL, NULL);
|
"ata_port", NULL, NULL, NULL);
|
||||||
|
|
||||||
@@ -240,7 +221,7 @@ static int ata_tport_match(struct attribute_container *cont,
|
|||||||
{
|
{
|
||||||
if (!ata_is_port(dev))
|
if (!ata_is_port(dev))
|
||||||
return 0;
|
return 0;
|
||||||
return &ata_scsi_transport_template->host_attrs.ac == cont;
|
return &ata_scsi_transportt.host_attrs.ac == cont;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -496,6 +477,23 @@ show_ata_dev_trim(struct device *dev,
|
|||||||
|
|
||||||
static DEVICE_ATTR(trim, S_IRUGO, show_ata_dev_trim, NULL);
|
static DEVICE_ATTR(trim, S_IRUGO, show_ata_dev_trim, NULL);
|
||||||
|
|
||||||
|
static const struct attribute *const ata_device_attr_attrs[] = {
|
||||||
|
&dev_attr_class.attr,
|
||||||
|
&dev_attr_pio_mode.attr,
|
||||||
|
&dev_attr_dma_mode.attr,
|
||||||
|
&dev_attr_xfer_mode.attr,
|
||||||
|
&dev_attr_spdn_cnt.attr,
|
||||||
|
&dev_attr_ering.attr,
|
||||||
|
&dev_attr_id.attr,
|
||||||
|
&dev_attr_gscr.attr,
|
||||||
|
&dev_attr_trim.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group ata_device_attr_group = {
|
||||||
|
.attrs_const = ata_device_attr_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
static DECLARE_TRANSPORT_CLASS(ata_dev_class,
|
static DECLARE_TRANSPORT_CLASS(ata_dev_class,
|
||||||
"ata_device", NULL, NULL, NULL);
|
"ata_device", NULL, NULL, NULL);
|
||||||
|
|
||||||
@@ -515,16 +513,6 @@ static bool ata_is_ata_dev(const struct device *dev)
|
|||||||
return dev->release == ata_tdev_release;
|
return dev->release == ata_tdev_release;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ata_tdev_match(struct attribute_container *cont,
|
|
||||||
struct device *dev)
|
|
||||||
{
|
|
||||||
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 an ATA transport device
|
* ata_tdev_free -- free an ATA transport device
|
||||||
* @dev: struct ata_device owning the transport device to free
|
* @dev: struct ata_device owning the transport device to free
|
||||||
@@ -626,6 +614,17 @@ ata_link_linkspeed_attr(hw_sata_spd_limit, fls);
|
|||||||
ata_link_linkspeed_attr(sata_spd_limit, fls);
|
ata_link_linkspeed_attr(sata_spd_limit, fls);
|
||||||
ata_link_linkspeed_attr(sata_spd, noop);
|
ata_link_linkspeed_attr(sata_spd, noop);
|
||||||
|
|
||||||
|
static const struct attribute *const ata_link_attr_attrs[] = {
|
||||||
|
&dev_attr_hw_sata_spd_limit.attr,
|
||||||
|
&dev_attr_sata_spd_limit.attr,
|
||||||
|
&dev_attr_sata_spd.attr,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct attribute_group ata_link_attr_group = {
|
||||||
|
.attrs_const = ata_link_attr_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
static DECLARE_TRANSPORT_CLASS(ata_link_class,
|
static DECLARE_TRANSPORT_CLASS(ata_link_class,
|
||||||
"ata_link", NULL, NULL, NULL);
|
"ata_link", NULL, NULL, NULL);
|
||||||
|
|
||||||
@@ -645,16 +644,6 @@ static bool ata_is_link(const struct device *dev)
|
|||||||
return dev->release == ata_tlink_release;
|
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
|
* ata_tlink_delete -- remove an ATA link transport device
|
||||||
* @link: struct ata_link owning the link transport device to remove
|
* @link: struct ata_link owning the link transport device to remove
|
||||||
@@ -730,101 +719,49 @@ int ata_tlink_add(struct ata_link *link)
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct scsi_transport_template ata_scsi_transportt = {
|
||||||
|
.eh_strategy_handler = ata_scsi_error,
|
||||||
|
.user_scan = ata_scsi_user_scan,
|
||||||
|
|
||||||
|
.host_attrs.ac.class = &ata_port_class.class,
|
||||||
|
.host_attrs.ac.grp = &ata_port_attr_group,
|
||||||
|
.host_attrs.ac.match = ata_tport_match,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct transport_container ata_link_attr_cont = {
|
||||||
|
.ac.class = &ata_link_class.class,
|
||||||
|
.ac.grp = &ata_link_attr_group,
|
||||||
|
.ac.match = ata_tlink_match,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct transport_container ata_dev_attr_cont = {
|
||||||
|
.ac.class = &ata_dev_class.class,
|
||||||
|
.ac.grp = &ata_device_attr_group,
|
||||||
|
.ac.match = ata_tdev_match,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ata_tlink_match(struct attribute_container *cont,
|
||||||
|
struct device *dev)
|
||||||
|
{
|
||||||
|
if (!ata_is_link(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return &ata_link_attr_cont.ac == cont;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ata_tdev_match(struct attribute_container *cont,
|
||||||
|
struct device *dev)
|
||||||
|
{
|
||||||
|
if (!ata_is_ata_dev(dev))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return &ata_dev_attr_cont.ac == cont;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup / Teardown code
|
* Setup / Teardown code
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SETUP_TEMPLATE(attrb, field, perm, test) \
|
|
||||||
i->private_##attrb[count] = dev_attr_##field; \
|
|
||||||
i->private_##attrb[count].attr.mode = perm; \
|
|
||||||
i->attrb[count] = &i->private_##attrb[count]; \
|
|
||||||
if (test) \
|
|
||||||
count++
|
|
||||||
|
|
||||||
#define SETUP_LINK_ATTRIBUTE(field) \
|
|
||||||
SETUP_TEMPLATE(link_attrs, field, S_IRUGO, 1)
|
|
||||||
|
|
||||||
#define SETUP_PORT_ATTRIBUTE(field) \
|
|
||||||
SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
|
|
||||||
|
|
||||||
#define SETUP_DEV_ATTRIBUTE(field) \
|
|
||||||
SETUP_TEMPLATE(dev_attrs, field, S_IRUGO, 1)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ata_attach_transport -- instantiate ATA transport template
|
|
||||||
*/
|
|
||||||
struct scsi_transport_template *ata_attach_transport(void)
|
|
||||||
{
|
|
||||||
struct ata_internal *i;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
i = kzalloc_obj(struct ata_internal);
|
|
||||||
if (!i)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
i->t.eh_strategy_handler = ata_scsi_error;
|
|
||||||
i->t.user_scan = ata_scsi_user_scan;
|
|
||||||
|
|
||||||
i->t.host_attrs.ac.attrs = &i->port_attrs[0];
|
|
||||||
i->t.host_attrs.ac.class = &ata_port_class.class;
|
|
||||||
i->t.host_attrs.ac.match = ata_tport_match;
|
|
||||||
transport_container_register(&i->t.host_attrs);
|
|
||||||
|
|
||||||
i->link_attr_cont.ac.class = &ata_link_class.class;
|
|
||||||
i->link_attr_cont.ac.attrs = &i->link_attrs[0];
|
|
||||||
i->link_attr_cont.ac.match = ata_tlink_match;
|
|
||||||
transport_container_register(&i->link_attr_cont);
|
|
||||||
|
|
||||||
i->dev_attr_cont.ac.class = &ata_dev_class.class;
|
|
||||||
i->dev_attr_cont.ac.attrs = &i->dev_attrs[0];
|
|
||||||
i->dev_attr_cont.ac.match = ata_tdev_match;
|
|
||||||
transport_container_register(&i->dev_attr_cont);
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
SETUP_PORT_ATTRIBUTE(nr_pmp_links);
|
|
||||||
SETUP_PORT_ATTRIBUTE(idle_irq);
|
|
||||||
SETUP_PORT_ATTRIBUTE(port_no);
|
|
||||||
BUG_ON(count > ATA_PORT_ATTRS);
|
|
||||||
i->port_attrs[count] = NULL;
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
SETUP_LINK_ATTRIBUTE(hw_sata_spd_limit);
|
|
||||||
SETUP_LINK_ATTRIBUTE(sata_spd_limit);
|
|
||||||
SETUP_LINK_ATTRIBUTE(sata_spd);
|
|
||||||
BUG_ON(count > ATA_LINK_ATTRS);
|
|
||||||
i->link_attrs[count] = NULL;
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
SETUP_DEV_ATTRIBUTE(class);
|
|
||||||
SETUP_DEV_ATTRIBUTE(pio_mode);
|
|
||||||
SETUP_DEV_ATTRIBUTE(dma_mode);
|
|
||||||
SETUP_DEV_ATTRIBUTE(xfer_mode);
|
|
||||||
SETUP_DEV_ATTRIBUTE(spdn_cnt);
|
|
||||||
SETUP_DEV_ATTRIBUTE(ering);
|
|
||||||
SETUP_DEV_ATTRIBUTE(id);
|
|
||||||
SETUP_DEV_ATTRIBUTE(gscr);
|
|
||||||
SETUP_DEV_ATTRIBUTE(trim);
|
|
||||||
BUG_ON(count > ATA_DEV_ATTRS);
|
|
||||||
i->dev_attrs[count] = NULL;
|
|
||||||
|
|
||||||
return &i->t;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ata_release_transport -- release ATA transport template instance
|
|
||||||
* @t: transport template instance
|
|
||||||
*/
|
|
||||||
void ata_release_transport(struct scsi_transport_template *t)
|
|
||||||
{
|
|
||||||
struct ata_internal *i = to_ata_internal(t);
|
|
||||||
|
|
||||||
transport_container_unregister(&i->t.host_attrs);
|
|
||||||
transport_container_unregister(&i->link_attr_cont);
|
|
||||||
transport_container_unregister(&i->dev_attr_cont);
|
|
||||||
|
|
||||||
kfree(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
__init int libata_transport_init(void)
|
__init int libata_transport_init(void)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
@@ -838,6 +775,11 @@ __init int libata_transport_init(void)
|
|||||||
error = transport_class_register(&ata_dev_class);
|
error = transport_class_register(&ata_dev_class);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_unregister_port;
|
goto out_unregister_port;
|
||||||
|
|
||||||
|
transport_container_register(&ata_scsi_transportt.host_attrs);
|
||||||
|
transport_container_register(&ata_link_attr_cont);
|
||||||
|
transport_container_register(&ata_dev_attr_cont);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_unregister_port:
|
out_unregister_port:
|
||||||
@@ -851,6 +793,10 @@ __init int libata_transport_init(void)
|
|||||||
|
|
||||||
void __exit libata_transport_exit(void)
|
void __exit libata_transport_exit(void)
|
||||||
{
|
{
|
||||||
|
transport_container_unregister(&ata_scsi_transportt.host_attrs);
|
||||||
|
transport_container_unregister(&ata_link_attr_cont);
|
||||||
|
transport_container_unregister(&ata_dev_attr_cont);
|
||||||
|
|
||||||
transport_class_unregister(&ata_link_class);
|
transport_class_unregister(&ata_link_class);
|
||||||
transport_class_unregister(&ata_port_class);
|
transport_class_unregister(&ata_port_class);
|
||||||
transport_class_unregister(&ata_dev_class);
|
transport_class_unregister(&ata_dev_class);
|
||||||
|
|||||||
@@ -3,14 +3,11 @@
|
|||||||
#define _LIBATA_TRANSPORT_H
|
#define _LIBATA_TRANSPORT_H
|
||||||
|
|
||||||
|
|
||||||
extern struct scsi_transport_template *ata_scsi_transport_template;
|
extern struct scsi_transport_template ata_scsi_transportt;
|
||||||
|
|
||||||
int ata_tlink_add(struct ata_link *link);
|
int ata_tlink_add(struct ata_link *link);
|
||||||
void ata_tlink_delete(struct ata_link *link);
|
void ata_tlink_delete(struct ata_link *link);
|
||||||
|
|
||||||
struct scsi_transport_template *ata_attach_transport(void);
|
|
||||||
void ata_release_transport(struct scsi_transport_template *t);
|
|
||||||
|
|
||||||
__init int libata_transport_init(void);
|
__init int libata_transport_init(void);
|
||||||
void __exit libata_transport_exit(void);
|
void __exit libata_transport_exit(void);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ static inline int wait4buf(struct arasan_cf_dev *acdev)
|
|||||||
if (!wait_for_completion_timeout(&acdev->cf_completion, TIMEOUT)) {
|
if (!wait_for_completion_timeout(&acdev->cf_completion, TIMEOUT)) {
|
||||||
u32 rw = acdev->qc->tf.flags & ATA_TFLAG_WRITE;
|
u32 rw = acdev->qc->tf.flags & ATA_TFLAG_WRITE;
|
||||||
|
|
||||||
dev_err(acdev->host->dev, "%s TimeOut", rw ? "write" : "read");
|
dev_err(acdev->host->dev, "%s TimeOut\n", rw ? "write" : "read");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +474,7 @@ static int sg_xfer(struct arasan_cf_dev *acdev, struct scatterlist *sg)
|
|||||||
dma_len = min(xfer_cnt, FIFO_SIZE);
|
dma_len = min(xfer_cnt, FIFO_SIZE);
|
||||||
ret = dma_xfer(acdev, src, dest, dma_len);
|
ret = dma_xfer(acdev, src, dest, dma_len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(acdev->host->dev, "dma failed");
|
dev_err(acdev->host->dev, "dma failed\n");
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1205,7 +1205,6 @@ extern unsigned int ata_do_dev_read_id(struct ata_device *dev,
|
|||||||
struct ata_taskfile *tf, __le16 *id);
|
struct ata_taskfile *tf, __le16 *id);
|
||||||
extern void ata_qc_complete(struct ata_queued_cmd *qc);
|
extern void ata_qc_complete(struct ata_queued_cmd *qc);
|
||||||
extern u64 ata_qc_get_active(struct ata_port *ap);
|
extern u64 ata_qc_get_active(struct ata_port *ap);
|
||||||
extern void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd);
|
|
||||||
extern int ata_std_bios_param(struct scsi_device *sdev,
|
extern int ata_std_bios_param(struct scsi_device *sdev,
|
||||||
struct gendisk *unused,
|
struct gendisk *unused,
|
||||||
sector_t capacity, int geom[]);
|
sector_t capacity, int geom[]);
|
||||||
@@ -1226,7 +1225,8 @@ extern int ata_ncq_prio_enable(struct ata_port *ap, struct scsi_device *sdev,
|
|||||||
extern struct ata_device *ata_dev_pair(struct ata_device *adev);
|
extern struct ata_device *ata_dev_pair(struct ata_device *adev);
|
||||||
int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
|
int ata_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
|
||||||
extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap);
|
extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap);
|
||||||
extern void ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap, struct list_head *eh_q);
|
int ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
|
||||||
|
struct list_head *eh_q);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SATA specific code - drivers/ata/libata-sata.c
|
* SATA specific code - drivers/ata/libata-sata.c
|
||||||
|
|||||||
Reference in New Issue
Block a user