summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-04-16 01:03:01 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2026-04-16 01:03:01 +0300
commit5a69195686d5b874ac5a4c7f809ecb75fbc535ef (patch)
treea6346912a217bba63e90759ef93f1e43aa0e68fe
parent40286d6379aacfcc053253ef78dc78b09addffda (diff)
parent8ebf408e7d463eee02c348a3c8277b95587b710d (diff)
downloadlinux-5a69195686d5b874ac5a4c7f809ecb75fbc535ef.tar.xz
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()
-rw-r--r--Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml115
-rw-r--r--drivers/ata/Kconfig1
-rw-r--r--drivers/ata/ahci.h3
-rw-r--r--drivers/ata/ahci_dwc.c55
-rw-r--r--drivers/ata/libahci_platform.c33
-rw-r--r--drivers/ata/libata-core.c20
-rw-r--r--drivers/ata/libata-eh.c30
-rw-r--r--drivers/ata/libata-sata.c14
-rw-r--r--drivers/ata/libata-scsi.c227
-rw-r--r--drivers/ata/libata-transport.c224
-rw-r--r--drivers/ata/libata-transport.h5
-rw-r--r--drivers/ata/pata_arasan_cf.c4
-rw-r--r--include/linux/libata.h4
13 files changed, 258 insertions, 477 deletions
diff --git a/Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml b/Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
deleted file mode 100644
index 9b7ca4759bd7..000000000000
--- a/Documentation/devicetree/bindings/ata/baikal,bt1-ahci.yaml
+++ /dev/null
@@ -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>;
- };
- };
-...
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 2349bca136e0..fff305ec1e78 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -194,7 +194,6 @@ config AHCI_DM816
config AHCI_DWC
tristate "Synopsys DWC AHCI SATA support"
select SATA_HOST
- select MFD_SYSCON if (MIPS_BAIKAL_T1 || COMPILE_TEST)
help
This option enables support for the Synopsys DWC AHCI SATA
controller implementation.
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 293b7fb216b5..9e8b6319025c 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -357,7 +357,6 @@ struct ahci_host_priv {
* If platform uses PHYs. There is a 1:1 relation between the port number and
* the PHY position in this array.
*/
- struct phy **phys;
unsigned nports; /* Number of ports */
void *plat_data; /* Other platform data */
unsigned int irq; /* interrupt line */
@@ -379,6 +378,8 @@ struct ahci_host_priv {
/* only required for per-port MSI(-X) support */
int (*get_irq_vector)(struct ata_host *host,
int port);
+
+ struct phy *phys[] __counted_by(nports);
};
/*
diff --git a/drivers/ata/ahci_dwc.c b/drivers/ata/ahci_dwc.c
index 64abf865bb67..feb8a8539b8e 100644
--- a/drivers/ata/ahci_dwc.c
+++ b/drivers/ata/ahci_dwc.c
@@ -13,12 +13,10 @@
#include <linux/kernel.h>
#include <linux/libata.h>
#include <linux/log2.h>
-#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
-#include <linux/regmap.h>
#include "ahci.h"
@@ -92,20 +90,6 @@
#define AHCI_DWC_PORT_PHYCR 0x74
#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 {
unsigned int pflags;
unsigned int hflags;
@@ -122,39 +106,6 @@ struct ahci_dwc_host_priv {
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)
{
struct ahci_dwc_host_priv *dpriv;
@@ -457,15 +408,9 @@ static struct ahci_dwc_plat_data ahci_dwc_plat = {
.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[] = {
{ .compatible = "snps,dwc-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);
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index f37247e7a5cb..6e072d681341 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -482,15 +482,29 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
struct ahci_host_priv *hpriv;
u32 mask_port_map = 0;
u32 max_port;
+ int nports;
if (!devres_open_group(dev, NULL, GFP_KERNEL))
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);
if (!hpriv)
goto err_out;
+ hpriv->nports = nports;
+
devres_add(dev, hpriv);
/*
@@ -573,23 +587,6 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev,
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
* target_pwrs after devm_ have freed memory
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 374993031895..e76d15411e2a 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5151,8 +5151,13 @@ void ata_qc_issue(struct ata_queued_cmd *qc)
struct ata_link *link = qc->dev->link;
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)) {
WARN_ON_ONCE(link->sactive & (1 << qc->hw_tag));
@@ -6773,23 +6778,14 @@ static int __init ata_init(void)
}
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");
- return 0;
-err_out:
- return rc;
+ return 0;
}
static void __exit ata_exit(void)
{
- ata_release_transport(ata_scsi_transport_template);
libata_transport_exit();
ata_sff_exit();
ata_free_force_param();
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 23be85418b3b..9a4b67b90b17 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -560,21 +560,27 @@ void ata_scsi_error(struct Scsi_Host *host)
{
struct ata_port *ap = ata_shost_to_port(host);
unsigned long flags;
+ int nr_timedout;
LIST_HEAD(eh_work_q);
spin_lock_irqsave(host->host_lock, flags);
list_splice_init(&host->eh_cmd_q, &eh_work_q);
spin_unlock_irqrestore(host->host_lock, flags);
- ata_scsi_cmd_error_handler(host, ap, &eh_work_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);
+ /*
+ * 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);
- /* finish or retry handled scmd's and clean up */
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
* ap->eh_done_q. This function is the first part of the libata error
* 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,
- struct list_head *eh_work_q)
+int ata_scsi_cmd_error_handler(struct Scsi_Host *host, struct ata_port *ap,
+ struct list_head *eh_work_q)
{
int i;
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;
spin_unlock_irqrestore(ap->lock, flags);
+
+ return nr_timedout;
}
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))
rc = -ERESTART;
- if (try >= max_tries) {
+ if (try >= max_tries || rc == -ENODEV) {
/*
* Thaw host port even if reset failed, so that the port
* can be retried on the next phy event. This risks
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c
index b9d635088f5f..2ee54d60ea4b 100644
--- a/drivers/ata/libata-sata.c
+++ b/drivers/ata/libata-sata.c
@@ -1378,15 +1378,13 @@ EXPORT_SYMBOL_GPL(ata_sas_sdev_configure);
int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
{
- int rc = 0;
-
if (likely(ata_dev_enabled(ap->link.device)))
- rc = __ata_scsi_queuecmd(cmd, ap->link.device);
- else {
- cmd->result = (DID_BAD_TARGET << 16);
- scsi_done(cmd);
- }
- return rc;
+ return __ata_scsi_queuecmd(cmd, ap->link.device);
+
+ cmd->result = (DID_BAD_TARGET << 16);
+ scsi_done(cmd);
+
+ return 0;
}
EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3b65df914ebb..f44612e269a4 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1649,12 +1649,16 @@ nothing_to_do:
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;
void (*done)(struct scsi_cmnd *) = qc->scsidone;
ata_qc_free(qc);
+
+ if (set_result)
+ cmd->result = scmd_result;
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)
{
struct ata_queued_cmd *qc = ap->deferred_qc;
- struct scsi_cmnd *scmd;
lockdep_assert_held(ap->lock);
/*
* 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
- * and simply retry it by completing it with DID_SOFT_ERROR.
+ * and simply requeue it by completing it with DID_REQUEUE.
*/
- if (!qc)
- return;
-
- scmd = qc->scsicmd;
- ap->deferred_qc = NULL;
- cancel_work(&ap->deferred_qc_work);
- ata_qc_free(qc);
- scmd->result = (DID_SOFT_ERROR << 16);
- scsi_done(scmd);
+ if (qc) {
+ ap->deferred_qc = NULL;
+ cancel_work(&ap->deferred_qc_work);
+ ata_scsi_qc_done(qc, true, DID_REQUEUE << 16);
+ }
}
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_qc_done(qc);
+ ata_scsi_qc_done(qc, false, 0);
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)
qc->dev->sdev->locked = 0;
- qc->scsicmd->result = SAM_STAT_CHECK_CONDITION;
- ata_qc_done(qc);
+ ata_scsi_qc_done(qc, true, SAM_STAT_CHECK_CONDITION);
return;
}
/* successful completion path */
if (cmd->cmnd[0] == INQUIRY && (cmd->cmnd[1] & 0x03) == 0)
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
@@ -3576,28 +3573,13 @@ invalid_opcode:
return 1;
}
-/**
- * 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)
+static unsigned int ata_scsi_report_supported_opcodes(struct ata_device *dev,
+ struct scsi_cmnd *cmd,
+ u8 *rbuf)
{
u8 *cdb = cmd->cmnd;
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) {
ata_dev_warn(dev, "invalid command format %d\n", cdb[2]);
ata_scsi_set_invalid_field(dev, cmd, 2, 0xff);
@@ -3678,6 +3660,32 @@ static unsigned int ata_scsiop_maint_in(struct ata_device *dev,
}
/**
+ * 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
* @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;
}
+/**
+ * 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,
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);
-/**
- * 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 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;
ap->scsi_host = shost;
- shost->transportt = ata_scsi_transport_template;
+ shost->transportt = &ata_scsi_transportt;
shost->unique_id = ap->print_id;
shost->max_id = 16;
shost->max_lun = 1;
diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c
index 2099d94c4f68..95862dc34419 100644
--- a/drivers/ata/libata-transport.c
+++ b/drivers/ata/libata-transport.c
@@ -37,33 +37,10 @@
#include "libata.h"
#include "libata-transport.h"
-#define ATA_PORT_ATTRS 3
-#define ATA_LINK_ATTRS 3
-#define ATA_DEV_ATTRS 9
-
-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)
-
+static int ata_tlink_match(struct attribute_container *cont,
+ struct device *dev);
+static int ata_tdev_match(struct attribute_container *cont,
+ struct device *dev);
#define tdev_to_device(d) \
container_of((d), struct ata_device, tdev)
@@ -80,13 +57,6 @@ struct ata_internal {
#define transport_class_to_port(dev) \
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) \
static ssize_t \
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) */
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,
"ata_port", NULL, NULL, NULL);
@@ -240,7 +221,7 @@ static int ata_tport_match(struct attribute_container *cont,
{
if (!ata_is_port(dev))
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 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,
"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;
}
-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
* @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, 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,
"ata_link", NULL, NULL, NULL);
@@ -645,16 +644,6 @@ 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
@@ -730,101 +719,49 @@ int ata_tlink_add(struct ata_link *link)
return error;
}
-/*
- * 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++
+struct scsi_transport_template ata_scsi_transportt = {
+ .eh_strategy_handler = ata_scsi_error,
+ .user_scan = ata_scsi_user_scan,
-#define SETUP_LINK_ATTRIBUTE(field) \
- SETUP_TEMPLATE(link_attrs, field, S_IRUGO, 1)
+ .host_attrs.ac.class = &ata_port_class.class,
+ .host_attrs.ac.grp = &ata_port_attr_group,
+ .host_attrs.ac.match = ata_tport_match,
+};
-#define SETUP_PORT_ATTRIBUTE(field) \
- SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1)
+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,
+};
-#define SETUP_DEV_ATTRIBUTE(field) \
- SETUP_TEMPLATE(dev_attrs, field, S_IRUGO, 1)
+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,
+};
-/**
- * ata_attach_transport -- instantiate ATA transport template
- */
-struct scsi_transport_template *ata_attach_transport(void)
+static int ata_tlink_match(struct attribute_container *cont,
+ struct device *dev)
{
- 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;
+ if (!ata_is_link(dev))
+ return 0;
+
+ return &ata_link_attr_cont.ac == cont;
}
-/**
- * ata_release_transport -- release ATA transport template instance
- * @t: transport template instance
- */
-void ata_release_transport(struct scsi_transport_template *t)
+static int ata_tdev_match(struct attribute_container *cont,
+ struct device *dev)
{
- 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);
+ if (!ata_is_ata_dev(dev))
+ return 0;
- kfree(i);
+ return &ata_dev_attr_cont.ac == cont;
}
+/*
+ * Setup / Teardown code
+ */
+
__init int libata_transport_init(void)
{
int error;
@@ -838,6 +775,11 @@ __init int libata_transport_init(void)
error = transport_class_register(&ata_dev_class);
if (error)
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;
out_unregister_port:
@@ -851,6 +793,10 @@ __init int libata_transport_init(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_port_class);
transport_class_unregister(&ata_dev_class);
diff --git a/drivers/ata/libata-transport.h b/drivers/ata/libata-transport.h
index 50cd2cbe8eea..629ac843a873 100644
--- a/drivers/ata/libata-transport.h
+++ b/drivers/ata/libata-transport.h
@@ -3,14 +3,11 @@
#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);
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);
void __exit libata_transport_exit(void);
#endif
diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c
index 514d549286b5..b1e281b64f57 100644
--- a/drivers/ata/pata_arasan_cf.c
+++ b/drivers/ata/pata_arasan_cf.c
@@ -380,7 +380,7 @@ static inline int wait4buf(struct arasan_cf_dev *acdev)
if (!wait_for_completion_timeout(&acdev->cf_completion, TIMEOUT)) {
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;
}
@@ -474,7 +474,7 @@ static int sg_xfer(struct arasan_cf_dev *acdev, struct scatterlist *sg)
dma_len = min(xfer_cnt, FIFO_SIZE);
ret = dma_xfer(acdev, src, dest, dma_len);
if (ret) {
- dev_err(acdev->host->dev, "dma failed");
+ dev_err(acdev->host->dev, "dma failed\n");
goto fail;
}
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 00346ce3af5e..5c085ef4eda7 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1205,7 +1205,6 @@ extern unsigned int ata_do_dev_read_id(struct ata_device *dev,
struct ata_taskfile *tf, __le16 *id);
extern void ata_qc_complete(struct ata_queued_cmd *qc);
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,
struct gendisk *unused,
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);
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_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