+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) Freescale Semiconductor, Inc. 2006.
* Author: Jason Jin<Jason.jin@freescale.com>
* Zhang Wei<wei.zhang@freescale.com>
*
- * SPDX-License-Identifier: GPL-2.0+
- *
* with the reference on libata and ahci drvier in kernel
+ *
+ * This driver provides a SCSI interface to SATA.
*/
#include <common.h>
#include <asm/io.h>
#include <malloc.h>
#include <memalign.h>
+#include <pci.h>
#include <scsi.h>
#include <libata.h>
#include <linux/ctype.h>
#include <ahci.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
-static int ata_io_flush(u8 port);
+static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port);
-struct ahci_probe_ent *probe_ent = NULL;
-u16 *ataid[AHCI_MAX_PORTS];
+#ifndef CONFIG_DM_SCSI
+struct ahci_uc_priv *probe_ent = NULL;
+#endif
#define writel_with_flush(a,b) do { writel(a,b); readl(b); } while (0)
return (i < timeout_msec) ? 0 : -1;
}
-int __weak ahci_link_up(struct ahci_probe_ent *probe_ent, u8 port)
+int __weak ahci_link_up(struct ahci_uc_priv *uc_priv, u8 port)
{
u32 tmp;
int j = 0;
- void __iomem *port_mmio = probe_ent->port[port].port_mmio;
+ void __iomem *port_mmio = uc_priv->port[port].port_mmio;
/*
* Bring up SATA link.
return 0;
}
-static int ahci_host_init(struct ahci_probe_ent *probe_ent)
+static int ahci_host_init(struct ahci_uc_priv *uc_priv)
{
#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
# ifdef CONFIG_DM_PCI
- struct udevice *dev = probe_ent->dev;
+ struct udevice *dev = uc_priv->dev;
struct pci_child_platdata *pplat = dev_get_parent_platdata(dev);
# else
- pci_dev_t pdev = probe_ent->dev;
+ pci_dev_t pdev = uc_priv->dev;
unsigned short vendor;
# endif
u16 tmp16;
#endif
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = uc_priv->mmio_base;
u32 tmp, cap_save, cmd;
int i, j, ret;
void __iomem *port_mmio;
cap_save &= ((1 << 28) | (1 << 17));
cap_save |= (1 << 27); /* Staggered Spin-up. Not needed. */
- ret = ahci_reset(probe_ent->mmio_base);
+ ret = ahci_reset(uc_priv->mmio_base);
if (ret)
return ret;
}
# endif
#endif
- probe_ent->cap = readl(mmio + HOST_CAP);
- probe_ent->port_map = readl(mmio + HOST_PORTS_IMPL);
- port_map = probe_ent->port_map;
- probe_ent->n_ports = (probe_ent->cap & 0x1f) + 1;
+ uc_priv->cap = readl(mmio + HOST_CAP);
+ uc_priv->port_map = readl(mmio + HOST_PORTS_IMPL);
+ port_map = uc_priv->port_map;
+ uc_priv->n_ports = (uc_priv->cap & 0x1f) + 1;
debug("cap 0x%x port_map 0x%x n_ports %d\n",
- probe_ent->cap, probe_ent->port_map, probe_ent->n_ports);
+ uc_priv->cap, uc_priv->port_map, uc_priv->n_ports);
- if (probe_ent->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID)
- probe_ent->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID;
+ if (uc_priv->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID)
+ uc_priv->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID;
- for (i = 0; i < probe_ent->n_ports; i++) {
+ for (i = 0; i < uc_priv->n_ports; i++) {
if (!(port_map & (1 << i)))
continue;
- probe_ent->port[i].port_mmio = ahci_port_base(mmio, i);
- port_mmio = (u8 *) probe_ent->port[i].port_mmio;
- ahci_setup_port(&probe_ent->port[i], mmio, i);
+ uc_priv->port[i].port_mmio = ahci_port_base(mmio, i);
+ port_mmio = (u8 *)uc_priv->port[i].port_mmio;
+ ahci_setup_port(&uc_priv->port[i], mmio, i);
/* make sure port is not active */
tmp = readl(port_mmio + PORT_CMD);
writel_with_flush(cmd, port_mmio + PORT_CMD);
/* Bring up SATA link. */
- ret = ahci_link_up(probe_ent, i);
+ ret = ahci_link_up(uc_priv, i);
if (ret) {
printf("SATA link %d timeout.\n", i);
continue;
tmp = readl(port_mmio + PORT_SCR_STAT);
debug("SATA port %d status: 0x%x\n", i, tmp);
if ((tmp & PORT_SCR_STAT_DET_MASK) == PORT_SCR_STAT_DET_PHYRDY)
- probe_ent->link_port_map |= (0x01 << i);
+ uc_priv->link_port_map |= (0x01 << i);
}
tmp = readl(mmio + HOST_CTL);
}
-static void ahci_print_info(struct ahci_probe_ent *probe_ent)
+static void ahci_print_info(struct ahci_uc_priv *uc_priv)
{
#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI)
# if defined(CONFIG_DM_PCI)
- struct udevice *dev = probe_ent->dev;
+ struct udevice *dev = uc_priv->dev;
# else
- pci_dev_t pdev = probe_ent->dev;
+ pci_dev_t pdev = uc_priv->dev;
# endif
u16 cc;
#endif
- void __iomem *mmio = probe_ent->mmio_base;
+ void __iomem *mmio = uc_priv->mmio_base;
u32 vers, cap, cap2, impl, speed;
const char *speed_s;
const char *scc_s;
vers = readl(mmio + HOST_VERSION);
- cap = probe_ent->cap;
+ cap = uc_priv->cap;
cap2 = readl(mmio + HOST_CAP2);
- impl = probe_ent->port_map;
+ impl = uc_priv->port_map;
speed = (cap >> 20) & 0xf;
if (speed == 1)
cap2 & (1 << 0) ? "boh " : "");
}
-#ifndef CONFIG_SCSI_AHCI_PLAT
+#if defined(CONFIG_DM_SCSI) || !defined(CONFIG_SCSI_AHCI_PLAT)
# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
-static int ahci_init_one(struct udevice *dev)
+static int ahci_init_one(struct ahci_uc_priv *uc_priv, struct udevice *dev)
# else
-static int ahci_init_one(pci_dev_t dev)
+static int ahci_init_one(struct ahci_uc_priv *uc_priv, pci_dev_t dev)
# endif
{
#if !defined(CONFIG_DM_SCSI)
#endif
int rc;
- probe_ent = malloc(sizeof(struct ahci_probe_ent));
- if (!probe_ent) {
- printf("%s: No memory for probe_ent\n", __func__);
- return -ENOMEM;
- }
-
- memset(probe_ent, 0, sizeof(struct ahci_probe_ent));
- probe_ent->dev = dev;
+ uc_priv->dev = dev;
- probe_ent->host_flags = ATA_FLAG_SATA
+ uc_priv->host_flags = ATA_FLAG_SATA
| ATA_FLAG_NO_LEGACY
| ATA_FLAG_MMIO
| ATA_FLAG_PIO_DMA
| ATA_FLAG_NO_ATAPI;
- probe_ent->pio_mask = 0x1f;
- probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
+ uc_priv->pio_mask = 0x1f;
+ uc_priv->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
#if !defined(CONFIG_DM_SCSI)
#ifdef CONFIG_DM_PCI
- probe_ent->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5,
+ uc_priv->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5,
PCI_REGION_MEM);
/* Take from kernel:
if (vendor == 0x197b)
dm_pci_write_config8(dev, 0x41, 0xa1);
#else
- probe_ent->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5,
+ uc_priv->mmio_base = pci_map_bar(dev, PCI_BASE_ADDRESS_5,
PCI_REGION_MEM);
/* Take from kernel:
pci_write_config_byte(dev, 0x41, 0xa1);
#endif
#else
- struct scsi_platdata *plat = dev_get_platdata(dev);
- probe_ent->mmio_base = (void *)plat->base;
+ struct scsi_platdata *plat = dev_get_uclass_platdata(dev);
+ uc_priv->mmio_base = (void *)plat->base;
#endif
- debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base);
+ debug("ahci mmio_base=0x%p\n", uc_priv->mmio_base);
/* initialize adapter */
- rc = ahci_host_init(probe_ent);
+ rc = ahci_host_init(uc_priv);
if (rc)
goto err_out;
- ahci_print_info(probe_ent);
+ ahci_print_info(uc_priv);
return 0;
#define MAX_DATA_BYTE_COUNT (4*1024*1024)
-static int ahci_fill_sg(u8 port, unsigned char *buf, int buf_len)
+static int ahci_fill_sg(struct ahci_uc_priv *uc_priv, u8 port,
+ unsigned char *buf, int buf_len)
{
- struct ahci_ioports *pp = &(probe_ent->port[port]);
+ struct ahci_ioports *pp = &(uc_priv->port[port]);
struct ahci_sg *ahci_sg = pp->cmd_tbl_sg;
u32 sg_count;
int i;
return -ETIMEDOUT;
}
-static int ahci_port_start(u8 port)
+static int ahci_port_start(struct ahci_uc_priv *uc_priv, u8 port)
{
- struct ahci_ioports *pp = &(probe_ent->port[port]);
+ struct ahci_ioports *pp = &(uc_priv->port[port]);
void __iomem *port_mmio = pp->port_mmio;
u32 port_status;
void __iomem *mem;
}
-static int ahci_device_data_io(u8 port, u8 *fis, int fis_len, u8 *buf,
- int buf_len, u8 is_write)
+static int ahci_device_data_io(struct ahci_uc_priv *uc_priv, u8 port, u8 *fis,
+ int fis_len, u8 *buf, int buf_len, u8 is_write)
{
- struct ahci_ioports *pp = &(probe_ent->port[port]);
+ struct ahci_ioports *pp = &(uc_priv->port[port]);
void __iomem *port_mmio = pp->port_mmio;
u32 opts;
u32 port_status;
debug("Enter %s: for port %d\n", __func__, port);
- if (port > probe_ent->n_ports) {
+ if (port > uc_priv->n_ports) {
printf("Invalid port number %d\n", port);
return -1;
}
memcpy((unsigned char *)pp->cmd_tbl, fis, fis_len);
- sg_count = ahci_fill_sg(port, buf, buf_len);
+ sg_count = ahci_fill_sg(uc_priv, port, buf, buf_len);
opts = (fis_len >> 2) | (sg_count << 16) | (is_write << 6);
ahci_fill_cmd_slot(pp, opts);
/*
* SCSI INQUIRY command operation.
*/
-static int ata_scsiop_inquiry(ccb *pccb)
+static int ata_scsiop_inquiry(struct ahci_uc_priv *uc_priv,
+ struct scsi_cmd *pccb)
{
static const u8 hdr[] = {
0,
/* Read id from sata */
port = pccb->target;
- if (ahci_device_data_io(port, (u8 *) &fis, sizeof(fis), (u8 *)tmpid,
- ATA_ID_WORDS * 2, 0)) {
+ if (ahci_device_data_io(uc_priv, port, (u8 *)&fis, sizeof(fis),
+ (u8 *)tmpid, ATA_ID_WORDS * 2, 0)) {
debug("scsi_ahci: SCSI inquiry command failure.\n");
return -EIO;
}
- if (!ataid[port]) {
- ataid[port] = malloc(ATA_ID_WORDS * 2);
- if (!ataid[port]) {
+ if (!uc_priv->ataid[port]) {
+ uc_priv->ataid[port] = malloc(ATA_ID_WORDS * 2);
+ if (!uc_priv->ataid[port]) {
printf("%s: No memory for ataid[port]\n", __func__);
return -ENOMEM;
}
}
- idbuf = ataid[port];
+ idbuf = uc_priv->ataid[port];
memcpy(idbuf, tmpid, ATA_ID_WORDS * 2);
ata_swap_buf_le16(idbuf, ATA_ID_WORDS);
/*
* SCSI READ10/WRITE10 command operation.
*/
-static int ata_scsiop_read_write(ccb *pccb, u8 is_write)
+static int ata_scsiop_read_write(struct ahci_uc_priv *uc_priv,
+ struct scsi_cmd *pccb, u8 is_write)
{
lbaint_t lba = 0;
u16 blocks = 0;
fis[13] = (now_blocks >> 8) & 0xff;
/* Read/Write from ahci */
- if (ahci_device_data_io(pccb->target, (u8 *) &fis, sizeof(fis),
- user_buffer, transfer_size,
+ if (ahci_device_data_io(uc_priv, pccb->target, (u8 *)&fis,
+ sizeof(fis), user_buffer, transfer_size,
is_write)) {
debug("scsi_ahci: SCSI %s10 command failure.\n",
is_write ? "WRITE" : "READ");
* usually, one extra flush when the rare writes do happen.
*/
if (is_write) {
- if (-EIO == ata_io_flush(pccb->target))
+ if (-EIO == ata_io_flush(uc_priv, pccb->target))
return -EIO;
}
user_buffer += transfer_size;
/*
* SCSI READ CAPACITY10 command operation.
*/
-static int ata_scsiop_read_capacity10(ccb *pccb)
+static int ata_scsiop_read_capacity10(struct ahci_uc_priv *uc_priv,
+ struct scsi_cmd *pccb)
{
u32 cap;
u64 cap64;
u32 block_size;
- if (!ataid[pccb->target]) {
+ if (!uc_priv->ataid[pccb->target]) {
printf("scsi_ahci: SCSI READ CAPACITY10 command failure. "
"\tNo ATA info!\n"
"\tPlease run SCSI command INQUIRY first!\n");
return -EPERM;
}
- cap64 = ata_id_n_sectors(ataid[pccb->target]);
+ cap64 = ata_id_n_sectors(uc_priv->ataid[pccb->target]);
if (cap64 > 0x100000000ULL)
cap64 = 0xffffffff;
/*
* SCSI READ CAPACITY16 command operation.
*/
-static int ata_scsiop_read_capacity16(ccb *pccb)
+static int ata_scsiop_read_capacity16(struct ahci_uc_priv *uc_priv,
+ struct scsi_cmd *pccb)
{
u64 cap;
u64 block_size;
- if (!ataid[pccb->target]) {
+ if (!uc_priv->ataid[pccb->target]) {
printf("scsi_ahci: SCSI READ CAPACITY16 command failure. "
"\tNo ATA info!\n"
"\tPlease run SCSI command INQUIRY first!\n");
return -EPERM;
}
- cap = ata_id_n_sectors(ataid[pccb->target]);
+ cap = ata_id_n_sectors(uc_priv->ataid[pccb->target]);
cap = cpu_to_be64(cap);
memcpy(pccb->pdata, &cap, sizeof(cap));
/*
* SCSI TEST UNIT READY command operation.
*/
-static int ata_scsiop_test_unit_ready(ccb *pccb)
+static int ata_scsiop_test_unit_ready(struct ahci_uc_priv *uc_priv,
+ struct scsi_cmd *pccb)
{
- return (ataid[pccb->target]) ? 0 : -EPERM;
+ return (uc_priv->ataid[pccb->target]) ? 0 : -EPERM;
}
-int scsi_exec(ccb *pccb)
+static int ahci_scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
{
+ struct ahci_uc_priv *uc_priv;
+#ifdef CONFIG_DM_SCSI
+ uc_priv = dev_get_uclass_priv(dev->parent);
+#else
+ uc_priv = probe_ent;
+#endif
int ret;
switch (pccb->cmd[0]) {
case SCSI_READ16:
case SCSI_READ10:
- ret = ata_scsiop_read_write(pccb, 0);
+ ret = ata_scsiop_read_write(uc_priv, pccb, 0);
break;
case SCSI_WRITE10:
- ret = ata_scsiop_read_write(pccb, 1);
+ ret = ata_scsiop_read_write(uc_priv, pccb, 1);
break;
case SCSI_RD_CAPAC10:
- ret = ata_scsiop_read_capacity10(pccb);
+ ret = ata_scsiop_read_capacity10(uc_priv, pccb);
break;
case SCSI_RD_CAPAC16:
- ret = ata_scsiop_read_capacity16(pccb);
+ ret = ata_scsiop_read_capacity16(uc_priv, pccb);
break;
case SCSI_TST_U_RDY:
- ret = ata_scsiop_test_unit_ready(pccb);
+ ret = ata_scsiop_test_unit_ready(uc_priv, pccb);
break;
case SCSI_INQUIRY:
- ret = ata_scsiop_inquiry(pccb);
+ ret = ata_scsiop_inquiry(uc_priv, pccb);
break;
default:
printf("Unsupport SCSI command 0x%02x\n", pccb->cmd[0]);
- return false;
+ return -ENOTSUPP;
}
if (ret) {
debug("SCSI command 0x%02x ret errno %d\n", pccb->cmd[0], ret);
- return false;
+ return ret;
}
- return true;
+ return 0;
}
-#if defined(CONFIG_DM_SCSI)
-void scsi_low_level_init(int busdevfunc, struct udevice *dev)
-#else
-void scsi_low_level_init(int busdevfunc)
-#endif
+static int ahci_start_ports(struct ahci_uc_priv *uc_priv)
{
- int i;
u32 linkmap;
+ int i;
+
+ linkmap = uc_priv->link_port_map;
+
+ for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
+ if (((linkmap >> i) & 0x01)) {
+ if (ahci_port_start(uc_priv, (u8) i)) {
+ printf("Can not start port %d\n", i);
+ continue;
+ }
+ }
+ }
+
+ return 0;
+}
+
+#ifndef CONFIG_DM_SCSI
+void scsi_low_level_init(int busdevfunc)
+{
+ struct ahci_uc_priv *uc_priv;
#ifndef CONFIG_SCSI_AHCI_PLAT
+ probe_ent = calloc(1, sizeof(struct ahci_uc_priv));
+ if (!probe_ent) {
+ printf("%s: No memory for uc_priv\n", __func__);
+ return;
+ }
+ uc_priv = probe_ent;
# if defined(CONFIG_DM_PCI)
struct udevice *dev;
int ret;
ret = dm_pci_bus_find_bdf(busdevfunc, &dev);
if (ret)
return;
- ahci_init_one(dev);
-# elif defined(CONFIG_DM_SCSI)
- ahci_init_one(dev);
+ ahci_init_one(uc_priv, dev);
# else
- ahci_init_one(busdevfunc);
+ ahci_init_one(uc_priv, busdevfunc);
# endif
+#else
+ uc_priv = probe_ent;
#endif
- linkmap = probe_ent->link_port_map;
+ ahci_start_ports(uc_priv);
+}
+#endif
- for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
- if (((linkmap >> i) & 0x01)) {
- if (ahci_port_start((u8) i)) {
- printf("Can not start port %d\n", i);
- continue;
- }
- }
- }
+#ifndef CONFIG_SCSI_AHCI_PLAT
+# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI)
+int ahci_init_one_dm(struct udevice *dev)
+{
+ struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ return ahci_init_one(uc_priv, dev);
}
+#endif
+#endif
-#ifdef CONFIG_SCSI_AHCI_PLAT
-int ahci_init(void __iomem *base)
+int ahci_start_ports_dm(struct udevice *dev)
{
- int i, rc = 0;
- u32 linkmap;
+ struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
- probe_ent = malloc(sizeof(struct ahci_probe_ent));
- if (!probe_ent) {
- printf("%s: No memory for probe_ent\n", __func__);
- return -ENOMEM;
- }
+ return ahci_start_ports(uc_priv);
+}
- memset(probe_ent, 0, sizeof(struct ahci_probe_ent));
+#ifdef CONFIG_SCSI_AHCI_PLAT
+static int ahci_init_common(struct ahci_uc_priv *uc_priv, void __iomem *base)
+{
+ int rc;
- probe_ent->host_flags = ATA_FLAG_SATA
+ uc_priv->host_flags = ATA_FLAG_SATA
| ATA_FLAG_NO_LEGACY
| ATA_FLAG_MMIO
| ATA_FLAG_PIO_DMA
| ATA_FLAG_NO_ATAPI;
- probe_ent->pio_mask = 0x1f;
- probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
+ uc_priv->pio_mask = 0x1f;
+ uc_priv->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */
- probe_ent->mmio_base = base;
+ uc_priv->mmio_base = base;
/* initialize adapter */
- rc = ahci_host_init(probe_ent);
+ rc = ahci_host_init(uc_priv);
if (rc)
goto err_out;
- ahci_print_info(probe_ent);
+ ahci_print_info(uc_priv);
- linkmap = probe_ent->link_port_map;
+ rc = ahci_start_ports(uc_priv);
- for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
- if (((linkmap >> i) & 0x01)) {
- if (ahci_port_start((u8) i)) {
- printf("Can not start port %d\n", i);
- continue;
- }
- }
- }
err_out:
return rc;
}
+#ifndef CONFIG_DM_SCSI
+int ahci_init(void __iomem *base)
+{
+ struct ahci_uc_priv *uc_priv;
+
+ probe_ent = malloc(sizeof(struct ahci_uc_priv));
+ if (!probe_ent) {
+ printf("%s: No memory for uc_priv\n", __func__);
+ return -ENOMEM;
+ }
+
+ uc_priv = probe_ent;
+ memset(uc_priv, 0, sizeof(struct ahci_uc_priv));
+
+ return ahci_init_common(uc_priv, base);
+}
+#endif
+
+int ahci_init_dm(struct udevice *dev, void __iomem *base)
+{
+ struct ahci_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+ return ahci_init_common(uc_priv, base);
+}
+
void __weak scsi_init(void)
{
}
-#endif
+#endif /* CONFIG_SCSI_AHCI_PLAT */
/*
* In the general case of generic rotating media it makes sense to have a
* is the last write is difficult. Because writing to the disk in u-boot is
* very rare, this flush command will be invoked after every block write.
*/
-static int ata_io_flush(u8 port)
+static int ata_io_flush(struct ahci_uc_priv *uc_priv, u8 port)
{
u8 fis[20];
- struct ahci_ioports *pp = &(probe_ent->port[port]);
+ struct ahci_ioports *pp = &(uc_priv->port[port]);
void __iomem *port_mmio = pp->port_mmio;
u32 cmd_fis_len = 5; /* five dwords */
return 0;
}
+static int ahci_scsi_bus_reset(struct udevice *dev)
+{
+ /* Not implemented */
+
+ return 0;
+}
-__weak void scsi_bus_reset(void)
+#ifdef CONFIG_DM_SCSI
+int ahci_bind_scsi(struct udevice *ahci_dev, struct udevice **devp)
{
- /*Not implement*/
+ struct udevice *dev;
+ int ret;
+
+ ret = device_bind_driver(ahci_dev, "ahci_scsi", "ahci_scsi", &dev);
+ if (ret)
+ return ret;
+ *devp = dev;
+
+ return 0;
}
+
+int ahci_probe_scsi(struct udevice *ahci_dev, ulong base)
+{
+ struct ahci_uc_priv *uc_priv;
+ struct scsi_platdata *uc_plat;
+ struct udevice *dev;
+ int ret;
+
+ device_find_first_child(ahci_dev, &dev);
+ if (!dev)
+ return -ENODEV;
+ uc_plat = dev_get_uclass_platdata(dev);
+ uc_plat->base = base;
+ uc_plat->max_lun = 1;
+ uc_plat->max_id = 2;
+
+ uc_priv = dev_get_uclass_priv(ahci_dev);
+ ret = ahci_init_one(uc_priv, dev);
+ if (ret)
+ return ret;
+ ret = ahci_start_ports(uc_priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+#ifdef CONFIG_DM_PCI
+int ahci_probe_scsi_pci(struct udevice *ahci_dev)
+{
+ ulong base;
+
+ base = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5,
+ PCI_REGION_MEM);
+
+ return ahci_probe_scsi(ahci_dev, base);
+}
+#endif
+
+struct scsi_ops scsi_ops = {
+ .exec = ahci_scsi_exec,
+ .bus_reset = ahci_scsi_bus_reset,
+};
+
+U_BOOT_DRIVER(ahci_scsi) = {
+ .name = "ahci_scsi",
+ .id = UCLASS_SCSI,
+ .ops = &scsi_ops,
+};
+#else
+int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
+{
+ return ahci_scsi_exec(dev, pccb);
+}
+
+__weak int scsi_bus_reset(struct udevice *dev)
+{
+ return ahci_scsi_bus_reset(dev);
+
+ return 0;
+}
+#endif