diff options
author | Simon Glass <sjg@chromium.org> | 2017-06-15 03:28:46 (GMT) |
---|---|---|
committer | Simon Glass <sjg@chromium.org> | 2017-07-11 16:08:19 (GMT) |
commit | 681357ffd9fe4528d020a878ef6ee61f519d8d85 (patch) | |
tree | 271008f521aad643de4c1fa9909920698ba13a81 /drivers | |
parent | 5c56176318c8a602fa78813ac273f16a10278a2d (diff) | |
download | u-boot-681357ffd9fe4528d020a878ef6ee61f519d8d85.tar.xz |
dm: ahci: Add a driver for SCSI on AHCI
Some AHCI drivers use SCSI under the hood. Rather than making the AHCI
driver be in the SCSI uclass it makes sense to have the AHCI device create
a SCSI device as a child. That way we can handle any AHCI-specific
operations rather than trying to pretend tha the device is just SCSI.
To handle this we need to provide a way for AHCI drivers to bind a SCSI
device as its child, and probe it. Add functions for this.
Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/ahci.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 3528a1f..6da412d 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -19,10 +19,13 @@ #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(struct ahci_uc_priv *uc_priv, u8 port); @@ -1142,10 +1145,64 @@ static int ahci_scsi_bus_reset(struct udevice *dev) } #ifdef CONFIG_DM_SCSI +int ahci_bind_scsi(struct udevice *ahci_dev, struct udevice **devp) +{ + 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) +{ +#ifdef CONFIG_SCSI_AHCI_PLAT + return -ENOSYS; /* TODO(sjg@chromium.org): Support non-PCI AHCI */ +#else + 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 = (ulong)dm_pci_map_bar(ahci_dev, PCI_BASE_ADDRESS_5, + PCI_REGION_MEM); + uc_plat->max_lun = 1; + uc_plat->max_id = 2; + uc_priv = dev_get_uclass_priv(dev); + ret = ahci_init_one(uc_priv, dev); + if (ret) + return ret; + ret = ahci_start_ports(uc_priv); + if (ret) + return ret; + + debug("Scanning %s\n", dev->name); + ret = scsi_scan_dev(dev, true); + if (ret) + return ret; +#endif + + return 0; +} + 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) { |