
Hi Stefan,
Thanks for your opinion.
-----Original Message----- From: Stefan Roese sr@denx.de Sent: 2019年9月29日 19:46 To: Peng Ma peng.ma@nxp.com; sjg@chromium.org; Prabhakar X prabhakar.kushwaha@nxp.com; jagan@openedev.com; bmeng.cn@gmail.com; Andy Tang andy.tang@nxp.com Cc: michal.simek@xilinx.com; andre.przywara@arm.com; smoch@web.de; u-boot@lists.denx.de; Robert Hancock hancock@sedsystems.ca Subject: [EXT] Re: [RFC 1/3] scsi: ata: Add DM SCSI interface to support None AHCI sata driver
Caution: EXT Email
Hi Peng,
On 25.09.19 11:54, Peng Ma wrote:
In driver/ata. If the sata driver support AHCI mode, there will provides a complete set of SCSI interface. If the sata is not support AHCI mode(NONE_AHCI) there will not provides the SCSI interface.
This patch is to support SCSI interface for None AHCI sata such as fsl_sata.c sil_sata.c etc.
Signed-off-by: Peng Ma peng.ma@nxp.com
drivers/ata/Kconfig | 17 +++- drivers/ata/Makefile | 2 + drivers/ata/ata-uclass.c | 16 ++++ drivers/ata/ata.c | 244
+++++++++++++++++++++++++++++++++++++++++++++++
drivers/ata/sata.c | 2 +- drivers/ata/scsi_ata.h | 43 +++++++++ include/dm/uclass-id.h | 1 + 7 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 drivers/ata/ata-uclass.c create mode 100644 drivers/ata/ata.c create mode 100644 drivers/ata/scsi_ata.h
Please take a look at commit 0506620f4f49 ("sata: sata_mv: Add DM support to enable CONFIG_BLK usage"). Perhaps this is a way to migrate these drivers to DM / BLK as well.
[Peng Ma] I saw This changed is not support SCSI command.
BTW: I agree with Robert, that SCSI is a bit misleading here. We are not using the SCSI commands on the boards with this Marvell (non-AHCI) SATA driver. The SATA command is more appropriate in this case in my eyes.
[Peng Ma] OK, you mean There is no need to support SCSI command for Non-AHCI driver? We still use SATA command for Non-AHCI driver here?
Best Regards, Peng
Thanks, Stefan
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 87636ae..3d6db2e 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -7,6 +7,13 @@ config AHCI operations at present. The block device interface has not been
converted
to driver model.
+config NONE_AHCI
bool "Support None AHCI SATA controllers with driver model"
depends on DM
help
This enables a uclass for disk controllers in U-Boot. such as AHCI. It
support None AHCI sata with DM mode
- config SATA bool "Support SATA controllers" select HAVE_BLOCK_DEVICE
@@ -32,6 +39,15 @@ config SCSI_AHCI help Enable this to allow interfacing SATA devices via the SCSI layer.
+config SCSI_NONE_AHCI
bool "Enable SCSI interface to None AHCI SATA devices"
select LIBATA
select SCSI
select DM_SCSI
help
Enable this to allow interfacing None AHCI SATA devices via the DM
SCSI layer.
menu "SATA/SCSI device support"
config AHCI_PCI
@@ -49,7 +65,6 @@ config SATA_CEVA ZynqMP. Support up to 2 external devices. Complient with SATA
3.1 and
AHCI 1.3 specifications with hot-plug detect feature.
- config DWC_AHCI bool "Enable Synopsys DWC AHCI driver support" select SCSI_AHCI
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 6e03384..cddbdc8 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -6,8 +6,10 @@ obj-$(CONFIG_DWC_AHCI) += dwc_ahci.o obj-$(CONFIG_FSL_AHCI) += fsl_ahci.o obj-$(CONFIG_AHCI) += ahci-uclass.o +obj-$(CONFIG_NONE_AHCI) += ata-uclass.o obj-$(CONFIG_AHCI_PCI) += ahci-pci.o obj-$(CONFIG_SCSI_AHCI) += ahci.o +obj-$(CONFIG_SCSI_NONE_AHCI) += ata.o obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o obj-$(CONFIG_FSL_SATA) += fsl_sata.o obj-$(CONFIG_LIBATA) += libata.o diff --git a/drivers/ata/ata-uclass.c b/drivers/ata/ata-uclass.c new file mode 100644 index 0000000..e2cc499 --- /dev/null +++ b/drivers/ata/ata-uclass.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (c) 2019 NXP, Inc
- Written by Peng Mapeng.ma@nxp.com */
+#include <common.h> +#include <dm.h> +#include <scsi.h> +#include "scsi_ata.h"
+UCLASS_DRIVER(ata) = {
.id = UCLASS_NONE_AHCI,
.name = "ata",
.per_device_auto_alloc_size = sizeof(struct ata_uc_priv), };
diff --git a/drivers/ata/ata.c b/drivers/ata/ata.c new file mode 100644 index 0000000..bdb7403 --- /dev/null +++ b/drivers/ata/ata.c @@ -0,0 +1,244 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Copyright (C) NXP, Inc. 2019.
- Author: Peng Mapeng.ma@nxp.com
- with the reference on libata and none ahci drvier in kernel
- This driver provides a DM SCSI interface to None AHCI SATA.
- */
+#include <common.h> +#include <dm/lists.h> +#include <dm.h> +#include <scsi.h> +#include <libata.h> +#include <sata.h> +#include <malloc.h> +#include <memalign.h> +#include <fis.h>
+#include "scsi_ata.h"
+int ata_bind_scsi(struct udevice *ata_dev, struct udevice **devp) {
int ret;
struct udevice *dev;
ret = device_bind_driver(ata_dev, "ata_scsi", "ata_scsi", &dev);
if (ret)
return ret;
*devp = dev;
return 0;
+}
+static int scsi_exec_internal(struct udevice *dev, struct scsi_cmd *pccb,
bool is_write) {
u32 temp;
u16 blocks = 0;
int ret = -ENODEV;
lbaint_t start = 0;
u8 port = pccb->target;
u8 *buffer = pccb->pdata;
struct ata_uc_priv *uc_priv = dev_get_uclass_priv(dev);
/* Retrieve the base LBA number from the ccb structure. */
if (pccb->cmd[0] == SCSI_READ16) {
memcpy(&start, pccb->cmd + 2, 8);
start = be64_to_cpu(start);
} else {
memcpy(&temp, pccb->cmd + 2, 4);
start = be32_to_cpu(temp);
}
if (pccb->cmd[0] == SCSI_READ16)
blocks = (((u16)pccb->cmd[13]) << 8) |
((u16)pccb->cmd[14]);
else
blocks = (((u16)pccb->cmd[7]) << 8) |
- ((u16)pccb->cmd[8]);
debug("scsi_ata: %s %u blocks starting from lba 0x" LBAFU "\n",
is_write ? "write" : "read", blocks, start);
if (is_write)
if (uc_priv->write)
ret = uc_priv->write(dev, start, blocks, buffer,
port);
else
pr_err("scsi_ata: write ptr is NULL\n");
else
if (uc_priv->read)
ret = uc_priv->read(dev, start, blocks, buffer,
port);
else
pr_err("scsi_ata: read ptr is NULL\n");
return ret;
+}
+static char *fsl_ata_id_strcpy(u16 *target, u16 *src, int len) {
int i;
for (i = 0; i < len / 2; i++)
target[i] = src[i];
return (char *)target;
+}
+static int ata_scsiop_inquiry(struct udevice *dev, struct scsi_cmd +*pccb) {
u8 port;
u16 *idbuf;
struct ata_uc_priv *uc_priv = dev_get_uclass_priv(dev);
ALLOC_CACHE_ALIGN_BUFFER(u16, tmpid, ATA_ID_WORDS);
/* Clean ccb data buffer */
memset(pccb->pdata, 0, pccb->datalen);
if (pccb->datalen <= 35)
return 0;
/* Read id from sata */
port = pccb->target;
if (uc_priv->ata_inquiry) {
uc_priv->ata_inquiry(dev, (u16 *)tmpid, port);
} else {
pr_err("scsi_ata: ata_inquiry ptr is NULL\n");
return -ENODEV;
}
if (!uc_priv->ataid[port]) {
uc_priv->ataid[port] = malloc(ATA_ID_WORDS * 2);
if (!uc_priv->ataid[port]) {
pr_err("%s: No memory for ataid[port]\n",
__func__);
return -ENOMEM;
}
}
idbuf = uc_priv->ataid[port];
memcpy(idbuf, tmpid, ATA_ID_WORDS * 2);
memcpy(&pccb->pdata[8], "ATA ", 8);
fsl_ata_id_strcpy((u16 *)&pccb->pdata[16], &idbuf[ATA_ID_PROD],
16);
fsl_ata_id_strcpy((u16 *)&pccb->pdata[32],
- &idbuf[ATA_ID_FW_REV], 4);
+#ifdef DEBUG
ata_dump_id(idbuf);
+#endif
return 0;
+}
+/*
- SCSI READ CAPACITY10 command operation.
- */
+static int ata_scsiop_read_capacity10(struct ata_uc_priv *uc_priv,
struct scsi_cmd *pccb) {
u32 cap;
u64 cap64;
u32 block_size;
if (!uc_priv->ataid[pccb->target]) {
pr_err("scsi_ata: SCSI READ CAPACITY10 command
failure.");
pr_err("\tNo ATA info!\n");
pr_err("\tPlease run SCSI command INQUIRY first!\n");
return -EPERM;
}
cap64 = ata_id_n_sectors(uc_priv->ataid[pccb->target]);
if (cap64 > 0x100000000ULL)
cap64 = 0xffffffff;
cap = cpu_to_be32(cap64);
memcpy(pccb->pdata, &cap, sizeof(cap));
block_size = cpu_to_be32((u32)512);
memcpy(&pccb->pdata[4], &block_size, 4);
return 0;
+}
+/*
- SCSI READ CAPACITY16 command operation.
- */
+static int ata_scsiop_read_capacity16(struct ata_uc_priv *uc_priv,
struct scsi_cmd *pccb) {
u64 cap;
u64 block_size;
if (!uc_priv->ataid[pccb->target]) {
pr_err("scsi_ata: SCSI READ CAPACITY16 command
failure.");
pr_err("\tNo ATA info!\n");
pr_err("\tPlease run SCSI command INQUIRY first!\n");
return -EPERM;
}
cap = ata_id_n_sectors(uc_priv->ataid[pccb->target]);
cap = cpu_to_be64(cap);
memcpy(pccb->pdata, &cap, sizeof(cap));
block_size = cpu_to_be64((u64)512);
memcpy(&pccb->pdata[8], &block_size, 8);
return 0;
+}
+/*
- SCSI TEST UNIT READY command operation.
- */
+static int ata_scsiop_test_unit_ready(struct ata_uc_priv *uc_priv,
struct scsi_cmd *pccb) {
return (uc_priv->ataid[pccb->target]) ? 0 : -EPERM; }
+static int ata_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb) +{
struct ata_uc_priv *uc_priv = dev_get_uclass_priv(dev->parent);
int ret;
switch (pccb->cmd[0]) {
case SCSI_READ16:
case SCSI_READ10:
ret = scsi_exec_internal(dev->parent, pccb, 0);
break;
case SCSI_WRITE10:
ret = scsi_exec_internal(dev->parent, pccb, 1);
break;
case SCSI_RD_CAPAC10:
ret = ata_scsiop_read_capacity10(uc_priv, pccb);
break;
case SCSI_RD_CAPAC16:
ret = ata_scsiop_read_capacity16(uc_priv, pccb);
break;
case SCSI_TST_U_RDY:
ret = ata_scsiop_test_unit_ready(uc_priv, pccb);
break;
case SCSI_INQUIRY:
ret = ata_scsiop_inquiry(dev->parent, pccb);
break;
default:
pr_err("Unsupport SCSI command 0x%02x\n",
pccb->cmd[0]);
return -ENOTSUPP;
}
if (ret) {
debug("SCSI command 0x%02x ret errno %d\n",
pccb->cmd[0], ret);
return ret;
}
return 0;
+}
+struct scsi_ops ata_scsi_ops = {
.exec = ata_scsi_exec,
+};
+U_BOOT_DRIVER(ata_scsi) = {
.name = "ata_scsi",
.id = UCLASS_SCSI,
.ops = &ata_scsi_ops,
+}; diff --git a/drivers/ata/sata.c b/drivers/ata/sata.c index e384b80..1fee375 100644 --- a/drivers/ata/sata.c +++ b/drivers/ata/sata.c @@ -83,7 +83,7 @@ static unsigned long sata_bwrite(struct blk_desc
*block_dev, lbaint_t start,
} #endif
-#ifndef CONFIG_AHCI +#ifndef CONFIG_SCSI int __sata_initialize(void) { int rc, ret = -1; diff --git a/drivers/ata/scsi_ata.h b/drivers/ata/scsi_ata.h new file mode 100644 index 0000000..472a562 --- /dev/null +++ b/drivers/ata/scsi_ata.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/*
- Copyright (C) NXP Inc. 2019.
- Author: Peng Mapeng.ma@nxp.com
- */
+#ifndef _AHCI_H_ +#define _AHCI_H_
+#include <pci.h>
+#define ATA_MAX_PORTS 32 +/**
- struct ata_uc_priv - information about an ATA controller
- When driver model is used, this is accessible using
+dev_get_uclass_priv(dev)
- where dev is the controller (although at present it sometimes stands
alone).
- */
+struct ata_uc_priv { +#if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
struct udevice *dev;
+#else
pci_dev_t dev;
+#endif
u16 *ataid[ATA_MAX_PORTS];
ulong (*read)(struct udevice *dev, lbaint_t start, u16 blkcnt,
void *buffer, u8 port);
ulong (*write)(struct udevice *dev, lbaint_t start, u16 blkcnt,
const void *buffer, u8 port);
int (*ata_inquiry)(struct udevice *dev, u16 *buffer, u8 port);
+};
+/**
- ata_bind_scsi() - bind a new SCSI bus as a child
- Note that the SCSI bus device will itself bind block devices
- @ahci_dev: AHCI parent device
- @devp: Returns new SCSI bus device
- @return 0 if OK, -ve on error
- */
+int ata_bind_scsi(struct udevice *ahci_dev, struct udevice **devp); +#endif diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index d4d9610..087cd2d 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -29,6 +29,7 @@ enum uclass_id { /* U-Boot uclasses start here - in alphabetical order */ UCLASS_ADC, /* Analog-to-digital converter */ UCLASS_AHCI, /* SATA disk controller */
UCLASS_NONE_AHCI, /* SATA disk controller of None AHCI */ UCLASS_AUDIO_CODEC, /* Audio codec with control and data
path */
UCLASS_AXI, /* AXI bus */ UCLASS_BLK, /* Block device */
Viele Grüße, Stefan
-- DENX Software Engineering GmbH, Managing Director: Wolfgang Denk HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr@denx.de