[U-Boot] [RFC 1/3] scsi: ata: Add DM SCSI interface to support None AHCI sata driver

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
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 */

This sata is a None AHCI sata device. It belongs to PCI sata. To support DM mode with SCSI interface we use the SCSI_NONE_AHCI.
This patch is an example(pci sata) to fit "support SCSI interface for None AHCI sata"
Signed-off-by: Peng Ma peng.ma@nxp.com --- drivers/ata/sata_sil.c | 515 +++++++++++++++++++++++++++++++------------------ drivers/ata/sata_sil.h | 12 +- 2 files changed, 332 insertions(+), 195 deletions(-)
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index a8598d9..c4ac640 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -14,18 +14,22 @@ #include <sata.h> #include <libata.h> #include <sata.h> +#if CONFIG_IS_ENABLED(SCSI_NONE_AHCI) +#include "scsi_ata.h" +#include <scsi.h> +#include <dm.h> +#endif #include "sata_sil.h"
/* Convert sectorsize to wordsize */ -#define ATA_SECTOR_WORDS (ATA_SECT_SIZE/2) #define virt_to_bus(devno, v) pci_virt_to_mem(devno, (void *) (v))
static struct sata_info sata_info;
static struct pci_device_id supported[] = { - {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131}, - {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132}, - {PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124}, + { PCI_DEVICE(PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3131) }, + { PCI_DEVICE(PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3132) }, + { PCI_DEVICE(PCI_VENDOR_ID_SILICONIMAGE, PCI_DEVICE_ID_SIL3124) }, {} };
@@ -113,9 +117,9 @@ static int sil_init_port(void *port) return 0; }
-static void sil_read_fis(int dev, int tag, struct sata_fis_d2h *fis) +static void sil_read_fis(struct sil_sata *sata, int tag, + struct sata_fis_d2h *fis) { - struct sil_sata *sata = sata_dev_desc[dev].priv; void *port = sata->port; struct sil_prb *prb; int i; @@ -128,9 +132,9 @@ static void sil_read_fis(int dev, int tag, struct sata_fis_d2h *fis) *dst++ = readl(src++); }
-static int sil_exec_cmd(int dev, struct sil_cmd_block *pcmd, int tag) +static int sil_exec_cmd(struct sil_sata *sata, struct sil_cmd_block *pcmd, + int tag) { - struct sil_sata *sata = sata_dev_desc[dev].priv; void *port = sata->port; u64 paddr = virt_to_bus(sata->devno, pcmd); u32 irq_mask, irq_stat; @@ -164,9 +168,8 @@ static int sil_exec_cmd(int dev, struct sil_cmd_block *pcmd, int tag) return rc; }
-static int sil_cmd_set_feature(int dev) +static int sil_cmd_set_feature(struct sil_sata *sata) { - struct sil_sata *sata = sata_dev_desc[dev].priv; struct sil_cmd_block cmdb, *pcmd = &cmdb; struct sata_fis_d2h fis; u8 udma_cap; @@ -191,9 +194,9 @@ static int sil_cmd_set_feature(int dev) if (udma_cap == ATA_UDMA3) pcmd->prb.fis.sector_count = XFER_UDMA_3;
- ret = sil_exec_cmd(dev, pcmd, 0); + ret = sil_exec_cmd(sata, pcmd, 0); if (ret) { - sil_read_fis(dev, 0, &fis); + sil_read_fis(sata, 0, &fis); printf("Err: exe cmd(0x%x).\n", readl(sata->port + PORT_SERROR)); sil_sata_dump_fis(&fis); @@ -203,9 +206,44 @@ static int sil_cmd_set_feature(int dev) return 0; }
-static int sil_cmd_identify_device(int dev, u16 *id) +static void sil_sata_init_wcache(struct sil_sata *sata, u16 *id) +{ + if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) + sata->wcache = 1; + if (ata_id_has_flush(id)) + sata->flush = 1; + if (ata_id_has_flush_ext(id)) + sata->flush_ext = 1; +} + +static void sil_sata_set_feature_by_id(struct sil_sata *sata, u16 *id) +{ +#ifdef CONFIG_LBA48 + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) + sata_dev_desc[sata->id].lba48 = 1; +#endif + sata->lba48 = 1; + debug("Device supports LBA48\n"); + } else { + debug("Device supports LBA28\n"); + } +#endif + + sil_sata_init_wcache(sata, id); + sil_cmd_set_feature(sata); +} + +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) +static int sil_cmd_identify_device(struct sil_sata *sata, u16 *id) { - struct sil_sata *sata = sata_dev_desc[dev].priv; +#else +static int sil_cmd_identify_device(struct udevice *dev, u16 *id, u8 port) +{ + struct sil_sata_priv *priv = dev_get_priv(dev); + sil_sata_t *sata = priv->sil_sata_desc[port]; +#endif struct sil_cmd_block cmdb, *pcmd = &cmdb; struct sata_fis_d2h fis; int ret; @@ -220,29 +258,29 @@ static int sil_cmd_identify_device(int dev, u16 *id) pcmd->sge.cnt = cpu_to_le32(sizeof(id[0]) * ATA_ID_WORDS); pcmd->sge.flags = cpu_to_le32(SGE_TRM);
- ret = sil_exec_cmd(dev, pcmd, 0); + ret = sil_exec_cmd(sata, pcmd, 0); if (ret) { - sil_read_fis(dev, 0, &fis); + sil_read_fis(sata, 0, &fis); printf("Err: id cmd(0x%x).\n", readl(sata->port + PORT_SERROR)); sil_sata_dump_fis(&fis); return 1; } ata_swap_buf_le16(id, ATA_ID_WORDS);
+ sil_sata_set_feature_by_id(sata, id); return 0; }
-static int sil_cmd_soft_reset(int dev) +static int sil_cmd_soft_reset(struct sil_sata *sata) { struct sil_cmd_block cmdb, *pcmd = &cmdb; - struct sil_sata *sata = sata_dev_desc[dev].priv; struct sata_fis_d2h fis; void *port = sata->port; int ret;
/* put the port into known state */ if (sil_init_port(port)) { - printf("SRST: port %d not ready\n", dev); + printf("SRST: port %d not ready\n", sata->id); return 1; }
@@ -252,9 +290,9 @@ static int sil_cmd_soft_reset(int dev) pcmd->prb.fis.fis_type = SATA_FIS_TYPE_REGISTER_H2D; pcmd->prb.fis.pm_port_c = 0xf;
- ret = sil_exec_cmd(dev, &cmdb, 0); + ret = sil_exec_cmd(sata, &cmdb, 0); if (ret) { - sil_read_fis(dev, 0, &fis); + sil_read_fis(sata, 0, &fis); printf("SRST cmd error.\n"); sil_sata_dump_fis(&fis); return 1; @@ -263,10 +301,9 @@ static int sil_cmd_soft_reset(int dev) return 0; }
-static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt, - u8 *buffer, int is_write) +static ulong sil_sata_rw_cmd(struct sil_sata *sata, ulong start, ulong blkcnt, + u8 *buffer, int is_write) { - struct sil_sata *sata = sata_dev_desc[dev].priv; struct sil_cmd_block cmdb, *pcmd = &cmdb; struct sata_fis_d2h fis; u64 block; @@ -296,9 +333,9 @@ static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt, pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); pcmd->sge.flags = cpu_to_le32(SGE_TRM);
- ret = sil_exec_cmd(dev, pcmd, 0); + ret = sil_exec_cmd(sata, pcmd, 0); if (ret) { - sil_read_fis(dev, 0, &fis); + sil_read_fis(sata, 0, &fis); printf("Err: rw cmd(0x%08x).\n", readl(sata->port + PORT_SERROR)); sil_sata_dump_fis(&fis); @@ -308,10 +345,9 @@ static ulong sil_sata_rw_cmd(int dev, ulong start, ulong blkcnt, return blkcnt; }
-static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt, - u8 *buffer, int is_write) +static ulong sil_sata_rw_cmd_ext(struct sil_sata *sata, ulong start, + ulong blkcnt, u8 *buffer, int is_write) { - struct sil_sata *sata = sata_dev_desc[dev].priv; struct sil_cmd_block cmdb, *pcmd = &cmdb; struct sata_fis_d2h fis; u64 block; @@ -344,9 +380,9 @@ static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt, pcmd->sge.cnt = cpu_to_le32(blkcnt * ATA_SECT_SIZE); pcmd->sge.flags = cpu_to_le32(SGE_TRM);
- ret = sil_exec_cmd(dev, pcmd, 0); + ret = sil_exec_cmd(sata, pcmd, 0); if (ret) { - sil_read_fis(dev, 0, &fis); + sil_read_fis(sata, 0, &fis); printf("Err: rw ext cmd(0x%08x).\n", readl(sata->port + PORT_SERROR)); sil_sata_dump_fis(&fis); @@ -356,8 +392,9 @@ static ulong sil_sata_rw_cmd_ext(int dev, ulong start, ulong blkcnt, return blkcnt; }
-static ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt, - const void *buffer, int is_write) +static ulong sil_sata_rw_lba28(struct sil_sata *sata, ulong blknr, + lbaint_t blkcnt, const void *buffer, + int is_write) { ulong start, blks, max_blks; u8 *addr; @@ -369,23 +406,28 @@ static ulong sil_sata_rw_lba28(int dev, ulong blknr, lbaint_t blkcnt, max_blks = ATA_MAX_SECTORS; do { if (blks > max_blks) { - sil_sata_rw_cmd(dev, start, max_blks, addr, is_write); + sil_sata_rw_cmd(sata, start, max_blks, addr, is_write); start += max_blks; blks -= max_blks; addr += ATA_SECT_SIZE * max_blks; } else { - sil_sata_rw_cmd(dev, start, blks, addr, is_write); + sil_sata_rw_cmd(sata, start, blks, addr, is_write); start += blks; blks = 0; addr += ATA_SECT_SIZE * blks; } } while (blks != 0);
+#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) return blkcnt; +#else + return blks; +#endif }
-static ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt, - const void *buffer, int is_write) +static ulong sil_sata_rw_lba48(struct sil_sata *sata, ulong blknr, + lbaint_t blkcnt, const void *buffer, + int is_write) { ulong start, blks, max_blks; u8 *addr; @@ -397,24 +439,28 @@ static ulong sil_sata_rw_lba48(int dev, ulong blknr, lbaint_t blkcnt, max_blks = ATA_MAX_SECTORS_LBA48; do { if (blks > max_blks) { - sil_sata_rw_cmd_ext(dev, start, max_blks, - addr, is_write); + sil_sata_rw_cmd_ext(sata, start, max_blks, + addr, is_write); start += max_blks; blks -= max_blks; addr += ATA_SECT_SIZE * max_blks; } else { - sil_sata_rw_cmd_ext(dev, start, blks, - addr, is_write); + sil_sata_rw_cmd_ext(sata, start, blks, + addr, is_write); start += blks; blks = 0; addr += ATA_SECT_SIZE * blks; } } while (blks != 0);
+#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) return blkcnt; +#else + return blks; +#endif }
-static void sil_sata_cmd_flush_cache(int dev) +static void sil_sata_cmd_flush_cache(struct sil_sata *sata) { struct sil_cmd_block cmdb, *pcmd = &cmdb;
@@ -423,10 +469,10 @@ static void sil_sata_cmd_flush_cache(int dev) pcmd->prb.fis.pm_port_c = (1 << 7); pcmd->prb.fis.command = ATA_CMD_FLUSH;
- sil_exec_cmd(dev, pcmd, 0); + sil_exec_cmd(sata, pcmd, 0); }
-static void sil_sata_cmd_flush_cache_ext(int dev) +static void sil_sata_cmd_flush_cache_ext(struct sil_sata *sata) { struct sil_cmd_block cmdb, *pcmd = &cmdb;
@@ -435,54 +481,29 @@ static void sil_sata_cmd_flush_cache_ext(int dev) pcmd->prb.fis.pm_port_c = (1 << 7); pcmd->prb.fis.command = ATA_CMD_FLUSH_EXT;
- sil_exec_cmd(dev, pcmd, 0); -} - -static void sil_sata_init_wcache(int dev, u16 *id) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) - sata->wcache = 1; - if (ata_id_has_flush(id)) - sata->flush = 1; - if (ata_id_has_flush_ext(id)) - sata->flush_ext = 1; -} - -static int sil_sata_get_wcache(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - return sata->wcache; -} - -static int sil_sata_get_flush(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - return sata->flush; -} - -static int sil_sata_get_flush_ext(int dev) -{ - struct sil_sata *sata = sata_dev_desc[dev].priv; - - return sata->flush_ext; + sil_exec_cmd(sata, pcmd, 0); }
/* * SATA interface between low level driver and command layer */ +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) { - struct sil_sata *sata = sata_dev_desc[dev].priv; + sil_sata_t *sata = (sil_sata_t *)sata_dev_desc[dev].priv; +#else +ulong sata_read(struct udevice *dev, lbaint_t blknr, u16 blkcnt, + void *buffer, u8 port) +{ + struct sil_sata_priv *priv = dev_get_priv(dev); + sil_sata_t *sata = priv->sil_sata_desc[port]; +#endif ulong rc;
if (sata->lba48) - rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); + rc = sil_sata_rw_lba48(sata, blknr, blkcnt, buffer, READ_CMD); else - rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); + rc = sil_sata_rw_lba28(sata, blknr, blkcnt, buffer, READ_CMD);
return rc; } @@ -490,111 +511,47 @@ ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) /* * SATA interface between low level driver and command layer */ +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) { - struct sil_sata *sata = sata_dev_desc[dev].priv; + sil_sata_t *sata = (sil_sata_t *)sata_dev_desc[dev].priv; +#else +ulong sata_write(struct udevice *dev, lbaint_t blknr, u16 blkcnt, + const void *buffer, u8 port) +{ + struct sil_sata_priv *priv = dev_get_priv(dev); + sil_sata_t *sata = priv->sil_sata_desc[port]; +#endif ulong rc;
if (sata->lba48) { - rc = sil_sata_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (sil_sata_get_wcache(dev) && sil_sata_get_flush_ext(dev)) - sil_sata_cmd_flush_cache_ext(dev); + rc = sil_sata_rw_lba48(sata, blknr, blkcnt, buffer, WRITE_CMD); + if (sata->wcache && sata->flush_ext) + sil_sata_cmd_flush_cache_ext(sata); } else { - rc = sil_sata_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (sil_sata_get_wcache(dev) && sil_sata_get_flush(dev)) - sil_sata_cmd_flush_cache(dev); + rc = sil_sata_rw_lba28(sata, blknr, blkcnt, buffer, WRITE_CMD); + if (sata->wcache && sata->flush) + sil_sata_cmd_flush_cache(sata); }
return rc; }
-/* - * SATA interface between low level driver and command layer - */ -int init_sata(int dev) -{ - static int init_done, idx; - pci_dev_t devno; - u16 word; - - if (init_done == 1 && dev < sata_info.maxport) - return 0; - - init_done = 1; - - /* Find PCI device(s) */ - devno = pci_find_devices(supported, idx++); - if (devno == -1) - return 1; - - pci_read_config_word(devno, PCI_DEVICE_ID, &word); - - /* get the port count */ - word &= 0xf; - - sata_info.portbase = sata_info.maxport; - sata_info.maxport = sata_info.portbase + word; - sata_info.devno = devno; - - /* Read out all BARs */ - sata_info.iobase[0] = (ulong)pci_map_bar(devno, - PCI_BASE_ADDRESS_0, PCI_REGION_MEM); - sata_info.iobase[1] = (ulong)pci_map_bar(devno, - PCI_BASE_ADDRESS_2, PCI_REGION_MEM); - sata_info.iobase[2] = (ulong)pci_map_bar(devno, - PCI_BASE_ADDRESS_4, PCI_REGION_MEM); - - /* mask out the unused bits */ - sata_info.iobase[0] &= 0xffffff80; - sata_info.iobase[1] &= 0xfffffc00; - sata_info.iobase[2] &= 0xffffff80; - - /* Enable Bus Mastering and memory region */ - pci_write_config_word(devno, PCI_COMMAND, - PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); - - /* Check if mem accesses and Bus Mastering are enabled. */ - pci_read_config_word(devno, PCI_COMMAND, &word); - if (!(word & PCI_COMMAND_MEMORY) || - (!(word & PCI_COMMAND_MASTER))) { - printf("Error: Can not enable MEM access or Bus Mastering.\n"); - debug("PCI command: %04x\n", word); - return 1; - } - - /* GPIO off */ - writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD)); - /* clear global reset & mask interrupts during initialization */ - writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL)); - - return 0; -} - -int reset_sata(int dev) +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) +static int sil_init_sata(int dev) { - return 0; -} - -/* - * SATA interface between low level driver and command layer - */ -int scan_sata(int dev) +#else +static int sil_init_sata(struct udevice *uc_dev, int dev) { - unsigned char serial[ATA_ID_SERNO_LEN + 1]; - unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; - unsigned char product[ATA_ID_PROD_LEN + 1]; - struct sil_sata *sata; + struct sil_sata_priv *priv = dev_get_priv(uc_dev); +#endif + sil_sata_t *sata; void *port; - int cnt; - u16 *id; u32 tmp; + int cnt;
- if (dev >= sata_info.maxport) { - printf("SATA#%d is not present\n", dev); - return 1; - } + printf("SATA#%d:\n", dev);
- printf("SATA#%d\n", dev); port = (void *)sata_info.iobase[1] + PORT_REGS_SIZE * (dev - sata_info.portbase);
@@ -622,7 +579,7 @@ int scan_sata(int dev) tmp = readl(port + PORT_SSTATUS); if ((tmp & 0xf) != 0x3) { printf(" (No RDY)\n"); - return 1; + return 0; }
/* Wait for port ready */ @@ -646,45 +603,115 @@ int scan_sata(int dev) return 1; }
- sata = (struct sil_sata *)malloc(sizeof(struct sil_sata)); + sata = (sil_sata_t *)malloc(sizeof(struct sil_sata)); if (!sata) { printf("%d no memory.\n", dev); return 1; } memset((void *)sata, 0, sizeof(struct sil_sata));
- /* turn on port interrupt */ - tmp = readl((void *)(sata_info.iobase[0] + HOST_CTRL)); - tmp |= (1 << (dev - sata_info.portbase)); - writel(tmp, (void *)(sata_info.iobase[0] + HOST_CTRL)); - /* Save the private struct to block device struct */ +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) sata_dev_desc[dev].priv = (void *)sata; +#else + priv->sil_sata_desc[dev] = sata; + priv->base = (ulong)port; +#endif + sata->id = dev; sata->port = port; sata->devno = sata_info.devno; sprintf(sata->name, "SATA#%d", dev); - sil_cmd_soft_reset(dev); + sil_cmd_soft_reset(sata); tmp = readl(port + PORT_SSTATUS); tmp = (tmp >> 4) & 0xf; printf(" (%s)\n", sata_spd_string(tmp));
+ return 0; +} + +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) +/* + * SATA interface between low level driver and command layer + */ +int init_sata(int dev) +{ + static int init_done, idx; + pci_dev_t devno; + u16 word; + + if (init_done == 1 && dev < sata_info.maxport) + goto init_start; + + init_done = 1; + + /* Find PCI device(s) */ + devno = pci_find_devices(supported, idx++); + if (devno == -1) + return 1; + + pci_read_config_word(devno, PCI_DEVICE_ID, &word); + + /* get the port count */ + word &= 0xf; + + sata_info.portbase = 0; + sata_info.maxport = sata_info.portbase + word; + sata_info.devno = devno; + + /* Read out all BARs */ + sata_info.iobase[0] = (ulong)pci_map_bar(devno, + PCI_BASE_ADDRESS_0, PCI_REGION_MEM); + sata_info.iobase[1] = (ulong)pci_map_bar(devno, + PCI_BASE_ADDRESS_2, PCI_REGION_MEM); + + /* mask out the unused bits */ + sata_info.iobase[0] &= 0xffffff80; + sata_info.iobase[1] &= 0xfffffc00; + + /* Enable Bus Mastering and memory region */ + pci_write_config_word(devno, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + /* Check if mem accesses and Bus Mastering are enabled. */ + pci_read_config_word(devno, PCI_COMMAND, &word); + if (!(word & PCI_COMMAND_MEMORY) || + (!(word & PCI_COMMAND_MASTER))) { + printf("Error: Can not enable MEM access or Bus Mastering.\n"); + debug("PCI command: %04x\n", word); + return 1; + } + + /* GPIO off */ + writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD)); + /* clear global reset & mask interrupts during initialization */ + writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL)); + +init_start: + return sil_init_sata(dev); +} + +int reset_sata(int dev) +{ + return 0; +} + +/* + * SATA interface between low level driver and command layer + */ +int scan_sata(int dev) +{ + sil_sata_t *sata = (sil_sata_t *)sata_dev_desc[dev].priv; + unsigned char serial[ATA_ID_SERNO_LEN + 1]; + unsigned char firmware[ATA_ID_FW_REV_LEN + 1]; + unsigned char product[ATA_ID_PROD_LEN + 1]; + u16 *id; + id = (u16 *)malloc(ATA_ID_WORDS * 2); if (!id) { printf("Id malloc failed\n"); - free((void *)sata); return 1; } - sil_cmd_identify_device(dev, id); - -#ifdef CONFIG_LBA48 - /* Check if support LBA48 */ - if (ata_id_has_lba48(id)) { - sata_dev_desc[dev].lba48 = 1; - sata->lba48 = 1; - debug("Device supports LBA48\n"); - } else - debug("Device supports LBA28\n"); -#endif + sil_cmd_identify_device(sata, id);
/* Serial number */ ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); @@ -701,14 +728,116 @@ int scan_sata(int dev) /* Totoal sectors */ sata_dev_desc[dev].lba = ata_id_n_sectors(id);
- sil_sata_init_wcache(dev, id); - sil_cmd_set_feature(dev); - #ifdef DEBUG - sil_cmd_identify_device(dev, id); ata_dump_id(id); #endif free((void *)id);
return 0; } +#else +static int sil_pci_bind(struct udevice *dev) +{ + struct udevice *scsi_dev; + + return ata_bind_scsi(dev, &scsi_dev); +} + +static int sil_priv_init(struct udevice *dev, ulong devnum) +{ + struct ata_uc_priv *uc_priv = dev_get_uclass_priv(dev); + struct sil_sata_priv *priv = dev_get_priv(dev); + struct scsi_platdata *uc_plat; + struct udevice *child_dev; + + device_find_first_child(dev, &child_dev); + if (!child_dev) + return -ENODEV; + + uc_plat = dev_get_uclass_platdata(child_dev); + uc_plat->base = priv->base; + uc_plat->max_id = devnum; + uc_plat->max_lun = 1; + + uc_priv->dev = dev; + uc_priv->read = sata_read; + uc_priv->write = sata_write; + uc_priv->ata_inquiry = sil_cmd_identify_device; + + return 0; +} + +static int sil_pci_probe(struct udevice *dev) +{ + int i; + u16 word; + pci_dev_t devno; + + /* Get PCI device number */ + devno = dm_pci_get_bdf(dev); + if (devno == -1) + return 1; + + dm_pci_read_config16(dev, PCI_DEVICE_ID, &word); + + /* get the port count */ + word &= 0xf; + + sata_info.portbase = 0; + sata_info.maxport = sata_info.portbase + word; + sata_info.devno = devno; + + /* Read out all BARs */ + sata_info.iobase[0] = (ulong)dm_pci_map_bar(dev, + PCI_BASE_ADDRESS_0, PCI_REGION_MEM); + sata_info.iobase[1] = (ulong)dm_pci_map_bar(dev, + PCI_BASE_ADDRESS_2, PCI_REGION_MEM); + + /* mask out the unused bits */ + sata_info.iobase[0] &= 0xffffff80; + sata_info.iobase[1] &= 0xfffffc00; + + /* Enable Bus Mastering and memory region */ + dm_pci_write_config16(dev, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + /* Check if mem accesses and Bus Mastering are enabled. */ + dm_pci_read_config16(dev, PCI_COMMAND, &word); + if (!(word & PCI_COMMAND_MEMORY) || + (!(word & PCI_COMMAND_MASTER))) { + printf("Error: Can not enable MEM access or Bus Mastering.\n"); + debug("PCI command: %04x\n", word); + return 1; + } + + /* GPIO off */ + writel(0, (void *)(sata_info.iobase[0] + HOST_FLASH_CMD)); + /* clear global reset & mask interrupts during initialization */ + writel(0, (void *)(sata_info.iobase[0] + HOST_CTRL)); + + for (i = sata_info.portbase; i < sata_info.maxport; i++) + if (sil_init_sata(dev, i)) + return -ENODEV; + + if (sil_priv_init(dev, i)) + return -ENODEV; + + return 0; +} + +static const struct udevice_id sil_pci_ids[] = { + { .compatible = "sil-pci-sample" }, + { } +}; + +U_BOOT_DRIVER(sil_pci) = { + .name = "sil_pci", + .id = UCLASS_NONE_AHCI, + .of_match = sil_pci_ids, + .bind = sil_pci_bind, + .probe = sil_pci_probe, + .priv_auto_alloc_size = sizeof(struct sil_sata_priv), +}; + +U_BOOT_PCI_DEVICE(sil_pci, supported); +#endif diff --git a/drivers/ata/sata_sil.h b/drivers/ata/sata_sil.h index 8b7cbdf..d21fd34 100644 --- a/drivers/ata/sata_sil.h +++ b/drivers/ata/sata_sil.h @@ -13,7 +13,7 @@ /* * SATA device driver struct for each dev */ -struct sil_sata { +typedef struct sil_sata { char name[12]; void *port; /* the port base address */ int lba48; @@ -24,7 +24,8 @@ struct sil_sata { int wcache; int flush; int flush_ext; -}; + int id; +} sil_sata_t;
/* sata info for each controller */ struct sata_info { @@ -210,4 +211,11 @@ enum { CMD_ERR = 0x21, };
+#if CONFIG_IS_ENABLED(SCSI_NONE_AHCI) +struct sil_sata_priv { + ulong base; + sil_sata_t *sil_sata_desc[ATA_MAX_PORTS]; +}; +#endif + #endif

This sata is a None AHCI sata device. To support DM mode with SCSI interface we use the SCSI_NONE_AHCI.
This patch is an example(normal sata) to fit "support SCSI interface for None AHCI sata"
Signed-off-by: Peng Ma peng.ma@nxp.com --- drivers/ata/fsl_sata.c | 300 +++++++++++++++++++++++++++++++++---------------- drivers/ata/fsl_sata.h | 9 ++ 2 files changed, 211 insertions(+), 98 deletions(-)
diff --git a/drivers/ata/fsl_sata.c b/drivers/ata/fsl_sata.c index e70a515..7bfeb9b 100644 --- a/drivers/ata/fsl_sata.c +++ b/drivers/ata/fsl_sata.c @@ -15,7 +15,11 @@ #include <fis.h> #include <sata.h> #include "fsl_sata.h" - +#if CONFIG_IS_ENABLED(SCSI_NONE_AHCI) +#include "scsi_ata.h" +#include <scsi.h> +#include <dm.h> +#else #ifndef CONFIG_SYS_SATA1_FLAGS #define CONFIG_SYS_SATA1_FLAGS FLAGS_DMA #endif @@ -35,6 +39,7 @@ static struct fsl_sata_info fsl_sata_info[] = { {0, 0}, #endif }; +#endif
static inline void sdelay(unsigned long sec) { @@ -74,7 +79,11 @@ static int ata_wait_register(unsigned __iomem *addr, u32 mask, return (i < timeout_msec) ? 0 : -1; }
+#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) int init_sata(int dev) +#else +static int init_sata(struct fsl_ata_priv *priv) +#endif { u32 length, align; cmd_hdr_tbl_t *cmd_hdr; @@ -85,6 +94,10 @@ int init_sata(int dev) int i; fsl_sata_t *sata;
+#if CONFIG_IS_ENABLED(SCSI_NONE_AHCI) + int dev = priv->number; +#endif + if (dev < 0 || dev > (CONFIG_SYS_SATA_MAX_DEVICE - 1)) { printf("the sata index %d is out of ranges\n\r", dev); return -1; @@ -110,13 +123,17 @@ int init_sata(int dev) /* Zero all of the device driver struct */ memset((void *)sata, 0, sizeof(fsl_sata_t));
- /* Save the private struct to block device struct */ - sata_dev_desc[dev].priv = (void *)sata; - snprintf(sata->name, 12, "SATA%d", dev);
/* Set the controller register base address to device struct */ +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) + sata_dev_desc[dev].priv = (void *)sata; reg = (fsl_sata_reg_t *)(fsl_sata_info[dev].sata_reg_base); + sata->dma_flag = fsl_sata_info[dev].flags; +#else + reg = (fsl_sata_reg_t *)priv->base; + sata->dma_flag = priv->flag; +#endif sata->reg_base = reg;
/* Allocate the command header table, 4 bytes aligned */ @@ -252,6 +269,9 @@ int init_sata(int dev) else if ((val32 & SSTATUS_SPD_MASK) == SSTATUS_SPD_GEN2) printf("(3 Gbps)\n\r");
+#if CONFIG_IS_ENABLED(SCSI_NONE_AHCI) + priv->fsl_sata = sata; +#endif return 0; }
@@ -479,34 +499,16 @@ static int fsl_sata_exec_cmd(struct fsl_sata *sata, struct sata_fis_h2d *cfis, return -1; }
-static void fsl_sata_identify(int dev, u16 *id) +static void fsl_sata_xfer_mode(fsl_sata_t *sata, u16 *id) { - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - struct sata_fis_h2d h2d, *cfis = &h2d; - - memset(cfis, 0, sizeof(struct sata_fis_h2d)); - - cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; - cfis->pm_port_c = 0x80; /* is command */ - cfis->command = ATA_CMD_ID_ATA; - - fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2); - ata_swap_buf_le16(id, ATA_ID_WORDS); -} - -static void fsl_sata_xfer_mode(int dev, u16 *id) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - sata->pio = id[ATA_ID_PIO_MODES]; sata->mwdma = id[ATA_ID_MWDMA_MODES]; sata->udma = id[ATA_ID_UDMA_MODES]; debug("pio %04x, mwdma %04x, udma %04x\n\r", sata->pio, sata->mwdma, sata->udma); }
-static void fsl_sata_set_features(int dev) +static void fsl_sata_set_features(fsl_sata_t *sata) { - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d, *cfis = &h2d; u8 udma_cap;
@@ -533,9 +535,9 @@ static void fsl_sata_set_features(int dev) fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); }
-static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) +static u32 fsl_sata_rw_cmd(fsl_sata_t *sata, u32 start, u32 blkcnt, u8 *buffer, + int is_write) { - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d, *cfis = &h2d; u32 block;
@@ -558,9 +560,8 @@ static u32 fsl_sata_rw_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_wr return blkcnt; }
-static void fsl_sata_flush_cache(int dev) +static void fsl_sata_flush_cache(fsl_sata_t *sata) { - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d, *cfis = &h2d;
memset(cfis, 0, sizeof(struct sata_fis_h2d)); @@ -572,9 +573,9 @@ static void fsl_sata_flush_cache(int dev) fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); }
-static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int is_write) +static u32 fsl_sata_rw_cmd_ext(fsl_sata_t *sata, u32 start, u32 blkcnt, + u8 *buffer, int is_write) { - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d, *cfis = &h2d; u64 block;
@@ -602,10 +603,9 @@ static u32 fsl_sata_rw_cmd_ext(int dev, u32 start, u32 blkcnt, u8 *buffer, int i return blkcnt; }
-static u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, - int is_write) +static u32 fsl_sata_rw_ncq_cmd(fsl_sata_t *sata, u32 start, u32 blkcnt, + u8 *buffer, int is_write) { - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d, *cfis = &h2d; int ncq_channel; u64 block; @@ -646,9 +646,8 @@ static u32 fsl_sata_rw_ncq_cmd(int dev, u32 start, u32 blkcnt, u8 *buffer, return blkcnt; }
-static void fsl_sata_flush_cache_ext(int dev) +static void fsl_sata_flush_cache_ext(fsl_sata_t *sata) { - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; struct sata_fis_h2d h2d, *cfis = &h2d;
memset(cfis, 0, sizeof(struct sata_fis_h2d)); @@ -660,10 +659,8 @@ static void fsl_sata_flush_cache_ext(int dev) fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, NULL, 0); }
-static void fsl_sata_init_wcache(int dev, u16 *id) +static void fsl_sata_init_wcache(fsl_sata_t *sata, u16 *id) { - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - if (ata_id_has_wcache(id) && ata_id_wcache_enabled(id)) sata->wcache = 1; if (ata_id_has_flush(id)) @@ -672,26 +669,8 @@ static void fsl_sata_init_wcache(int dev, u16 *id) sata->flush_ext = 1; }
-static int fsl_sata_get_wcache(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - return sata->wcache; -} - -static int fsl_sata_get_flush(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - return sata->flush; -} - -static int fsl_sata_get_flush_ext(int dev) -{ - fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; - return sata->flush_ext; -} - -static u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt, - const void *buffer, int is_write) +static u32 ata_low_level_rw_lba48(fsl_sata_t *sata, u32 blknr, lbaint_t blkcnt, + const void *buffer, int is_write) { u32 start, blks; u8 *addr; @@ -704,28 +683,36 @@ static u32 ata_low_level_rw_lba48(int dev, u32 blknr, lbaint_t blkcnt, max_blks = ATA_MAX_SECTORS_LBA48; do { if (blks > max_blks) { - if (fsl_sata_info[dev].flags != FLAGS_FPDMA) - fsl_sata_rw_cmd_ext(dev, start, max_blks, addr, is_write); + if (sata->dma_flag != FLAGS_FPDMA) + fsl_sata_rw_cmd_ext(sata, start, max_blks, addr, + is_write); else - fsl_sata_rw_ncq_cmd(dev, start, max_blks, addr, is_write); + fsl_sata_rw_ncq_cmd(sata, start, max_blks, addr, + is_write); start += max_blks; blks -= max_blks; addr += ATA_SECT_SIZE * max_blks; } else { - if (fsl_sata_info[dev].flags != FLAGS_FPDMA) - fsl_sata_rw_cmd_ext(dev, start, blks, addr, is_write); + if (sata->dma_flag != FLAGS_FPDMA) + fsl_sata_rw_cmd_ext(sata, start, blks, addr, + is_write); else - fsl_sata_rw_ncq_cmd(dev, start, blks, addr, is_write); + fsl_sata_rw_ncq_cmd(sata, start, blks, addr, + is_write); start += blks; blks = 0; addr += ATA_SECT_SIZE * blks; } } while (blks != 0);
+#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) return blkcnt; +#else + return blks; +#endif }
-static u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, +static u32 ata_low_level_rw_lba28(fsl_sata_t *sata, u32 blknr, u32 blkcnt, const void *buffer, int is_write) { u32 start, blks; @@ -739,53 +726,132 @@ static u32 ata_low_level_rw_lba28(int dev, u32 blknr, u32 blkcnt, max_blks = ATA_MAX_SECTORS; do { if (blks > max_blks) { - fsl_sata_rw_cmd(dev, start, max_blks, addr, is_write); + fsl_sata_rw_cmd(sata, start, max_blks, addr, is_write); start += max_blks; blks -= max_blks; addr += ATA_SECT_SIZE * max_blks; } else { - fsl_sata_rw_cmd(dev, start, blks, addr, is_write); + fsl_sata_rw_cmd(sata, start, blks, addr, is_write); start += blks; blks = 0; addr += ATA_SECT_SIZE * blks; } } while (blks != 0);
+#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) return blkcnt; +#else + return blks; +#endif }
/* * SATA interface between low level driver and command layer */ +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer) { - u32 rc; fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; +#else +ulong sata_read(struct udevice *dev, lbaint_t blknr, u16 blkcnt, + void *buffer, u8 port) +{ + struct fsl_ata_priv *priv = dev_get_priv(dev); + fsl_sata_t *sata = priv->fsl_sata; +#endif + u32 rc;
if (sata->lba48) - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, READ_CMD); + rc = ata_low_level_rw_lba48(sata, blknr, blkcnt, buffer, + READ_CMD); else - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, READ_CMD); + rc = ata_low_level_rw_lba28(sata, blknr, blkcnt, buffer, + READ_CMD); return rc; }
+#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer) { - u32 rc; fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; +#else +ulong sata_write(struct udevice *dev, lbaint_t blknr, u16 blkcnt, + const void *buffer, u8 port) +{ + struct fsl_ata_priv *priv = dev_get_priv(dev); + fsl_sata_t *sata = priv->fsl_sata; +#endif + u32 rc;
if (sata->lba48) { - rc = ata_low_level_rw_lba48(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush_ext(dev)) - fsl_sata_flush_cache_ext(dev); + rc = ata_low_level_rw_lba48(sata, blknr, blkcnt, buffer, + WRITE_CMD); + if (sata->wcache && sata->flush_ext) + fsl_sata_flush_cache_ext(sata); } else { - rc = ata_low_level_rw_lba28(dev, blknr, blkcnt, buffer, WRITE_CMD); - if (fsl_sata_get_wcache(dev) && fsl_sata_get_flush(dev)) - fsl_sata_flush_cache(dev); + rc = ata_low_level_rw_lba28(sata, blknr, blkcnt, buffer, + WRITE_CMD); + if (sata->wcache && sata->flush) + fsl_sata_flush_cache(sata); } return rc; }
+static int sata_getinfo(fsl_sata_t *sata, u16 *id) +{ + /* if no detected link */ + if (!sata->link) + return -EINVAL; + +#ifdef CONFIG_LBA48 + /* Check if support LBA48 */ + if (ata_id_has_lba48(id)) { + sata->lba48 = 1; + debug("Device support LBA48\n\r"); + } else { + debug("Device supports LBA28\n\r"); + } +#endif + + /* Get the NCQ queue depth from device */ + sata->queue_depth = ata_id_queue_depth(id); + + /* Get the xfer mode from device */ + fsl_sata_xfer_mode(sata, id); + + /* Get the write cache status from device */ + fsl_sata_init_wcache(sata, id); + + /* Set the xfer mode to highest speed */ + fsl_sata_set_features(sata); + + return 0; +} + +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) +static int fsl_sata_identify(fsl_sata_t *sata, u16 *id) +{ +#else +static int fsl_sata_identify(struct udevice *dev, u16 *id, u8 port) +{ + struct fsl_ata_priv *priv = dev_get_priv(dev); + fsl_sata_t *sata = priv->fsl_sata; +#endif + struct sata_fis_h2d h2d, *cfis = &h2d; + + memset(cfis, 0, sizeof(struct sata_fis_h2d)); + + cfis->fis_type = SATA_FIS_TYPE_REGISTER_H2D; + cfis->pm_port_c = 0x80; /* is command */ + cfis->command = ATA_CMD_ID_ATA; + + fsl_sata_exec_cmd(sata, cfis, CMD_ATA, 0, (u8 *)id, ATA_ID_WORDS * 2); + ata_swap_buf_le16(id, ATA_ID_WORDS); + + return sata_getinfo(sata, (u16 *)id); +} + +#if !CONFIG_IS_ENABLED(SCSI_NONE_AHCI) int scan_sata(int dev) { fsl_sata_t *sata = (fsl_sata_t *)sata_dev_desc[dev].priv; @@ -806,7 +872,7 @@ int scan_sata(int dev) }
/* Identify device to get information */ - fsl_sata_identify(dev, id); + fsl_sata_identify(sata, id);
/* Serial number */ ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial)); @@ -824,30 +890,68 @@ int scan_sata(int dev) n_sectors = ata_id_n_sectors(id); sata_dev_desc[dev].lba = (u32)n_sectors;
-#ifdef CONFIG_LBA48 - /* Check if support LBA48 */ - if (ata_id_has_lba48(id)) { - sata->lba48 = 1; - debug("Device support LBA48\n\r"); - } else - debug("Device supports LBA28\n\r"); +#ifdef DEBUG + ata_dump_id(id); #endif + free((void *)id); + return 0; +} +#else +static int fsl_bind_ata(struct udevice *dev) +{ + struct udevice *scsi_dev;
- /* Get the NCQ queue depth from device */ - sata->queue_depth = ata_id_queue_depth(id); + return ata_bind_scsi(dev, &scsi_dev); +}
- /* Get the xfer mode from device */ - fsl_sata_xfer_mode(dev, id); +static int fsl_ata_ofdata_to_platdata(struct udevice *dev) +{ + struct fsl_ata_priv *priv = dev_get_priv(dev);
- /* Get the write cache status from device */ - fsl_sata_init_wcache(dev, id); + priv->number = dev_read_u32_default(dev, "sata-number", -1); + priv->flag = dev_read_u32_default(dev, "sata-fpdma", -1); + + priv->base = dev_read_addr(dev); + if (priv->base == FDT_ADDR_T_NONE) + return -EINVAL;
- /* Set the xfer mode to highest speed */ - fsl_sata_set_features(dev); -#ifdef DEBUG - fsl_sata_identify(dev, id); - ata_dump_id(id); -#endif - free((void *)id); return 0; } + +static int fsl_ata_probe(struct udevice *dev) +{ + struct udevice *child_dev; + struct scsi_platdata *uc_plat; + struct fsl_ata_priv *priv = dev_get_priv(dev); + struct ata_uc_priv *uc_priv = dev_get_uclass_priv(dev); + + device_find_first_child(dev, &child_dev); + if (!child_dev) + return -ENODEV; + + uc_plat = dev_get_uclass_platdata(child_dev); + uc_plat->base = priv->base; + uc_plat->max_lun = 1; + uc_plat->max_id = 1; + + uc_priv->read = sata_read; + uc_priv->write = sata_write; + uc_priv->ata_inquiry = fsl_sata_identify; + return init_sata(priv); +} + +static const struct udevice_id fsl_ata_ids[] = { + { .compatible = "fsl,pq-sata-v2" }, + { } +}; + +U_BOOT_DRIVER(fsl_ahci) = { + .name = "fsl_ata", + .id = UCLASS_NONE_AHCI, + .of_match = fsl_ata_ids, + .bind = fsl_bind_ata, + .ofdata_to_platdata = fsl_ata_ofdata_to_platdata, + .probe = fsl_ata_probe, + .priv_auto_alloc_size = sizeof(struct fsl_ata_priv), +}; +#endif diff --git a/drivers/ata/fsl_sata.h b/drivers/ata/fsl_sata.h index a4ee83d..1a0165e 100644 --- a/drivers/ata/fsl_sata.h +++ b/drivers/ata/fsl_sata.h @@ -318,4 +318,13 @@ typedef struct fsl_sata { #define READ_CMD 0 #define WRITE_CMD 1
+#if CONFIG_IS_ENABLED(SCSI_NONE_AHCI) +struct fsl_ata_priv { + u32 base; + u32 flag; + u32 number; + fsl_sata_t *fsl_sata; +}; +#endif + #endif /* __FSL_SATA_H__ */

On 2019-09-25 3:54 a.m., 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.
The patch rationale seems strange - SATA controllers don't inherently provide a SCSI interface regardless of whether they are AHCI or not. In the Linux kernel, SATA devices are supported using the SCSI layer via SCSI to ATA translation, which is a standardized mapping, largely in order to reuse a bunch of code - and U-Boot could choose to do the same - but AHCI controllers are handled the same way as all other SATA controllers in that regard by Linux, so I'm not sure why that distinction is being made here.
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
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 */

Hi Robert,
Thanks very much for your comments, please see my comments inline.
-----Original Message----- From: Robert Hancock hancock@sedsystems.ca Sent: 2019年9月25日 23:50 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: andre.przywara@arm.com; michal.simek@xilinx.com; u-boot@lists.denx.de; smoch@web.de; sr@denx.de Subject: [EXT] Re: [U-Boot] [RFC 1/3] scsi: ata: Add DM SCSI interface to support None AHCI sata driver
Caution: EXT Email
On 2019-09-25 3:54 a.m., 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.
The patch rationale seems strange - SATA controllers don't inherently provide a SCSI interface regardless of whether they are AHCI or not. In the Linux kernel, SATA devices are supported using the SCSI layer via SCSI to ATA translation, which is a standardized mapping, largely in order to reuse a bunch of code - and U-Boot could choose to do the same
- but AHCI controllers are handled the same way as all other SATA controllers in
that regard by Linux, so I'm not sure why that distinction is being made here.
[Peng Ma] For Linux: If the sata controller fallow AHCI: Vendor_init ----> ahci_platform_init_host(struct ata_port_operations ahci_ops) ---> ata_host_register ----> ata_scsi_add_hosts ...... If the sata controller not fallow AHCI: Vendor_init(struct ata_port_operations sata_xxx _ops) ----> ata_host_register ----> ata_scsi_add_hosts ......
For U-boot: If the sata controller fallow AHCI: The devices: UCLASS_BLK---->UCLASS_SCSI---->UCLASS_AHCI(just call ata interface) The drivers: Vendor_init ----> ahci_probe_scsi(struct scsi_ops scsi_ops) then the devices will bind(ahci_bind_scsi) the driver during uboot init. If the sata controller not fallow AHCI: Not Support: We shold support for None AHCI sata with scsi interface like as follows: The devices: UCLASS_BLK---->UCLASS_SCSI---->UCLASS_NONE_AHCI The drivers: Vendor_init (struct scsi_ops scsi_ops) then the devices will bind(ata_bind_scsi) the driver during uboot init.
Note: On U-boot the The ATA lib just provide some common interface. Best Regards, Peng
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
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 */
-- Robert Hancock Senior Software Developer SED Systems, a division of Calian Ltd. Email: hancock@sedsystems.ca

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.
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.
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

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

Hi Peng,
On 30.09.19 04:42, Peng Ma wrote:
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?
There is no need for the "scsi" command for (S)ATA drivers (AHCI or non-AHCI). The only reason to support the "scsi" command that I can think of, is compatibility. So if you need to support old env scripts that use the "scsi" cmd. As mentioned before, we are not using the "scsi" command at all with this non-AHCI driver.
Thanks, Stefan
participants (3)
-
Peng Ma
-
Robert Hancock
-
Stefan Roese