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 <s...@chromium.org> --- drivers/ata/ahci.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/ahci.h | 22 ++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 3528a1f3da..c67a144f02 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -23,6 +23,8 @@ #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 +1144,60 @@ 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) +{ + 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; + + 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) { diff --git a/include/ahci.h b/include/ahci.h index 648e56a4cf..746bff083a 100644 --- a/include/ahci.h +++ b/include/ahci.h @@ -203,4 +203,26 @@ int achi_start_ports_dm(struct udevice *dev); */ int ahci_init_dm(struct udevice *dev, void __iomem *base); +/** + * ahci_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 ahci_bind_scsi(struct udevice *ahci_dev, struct udevice **devp); + +/** + * ahci_probe_scsi() - probe and scan the attached SCSI bus + * + * Note that the SCSI device will itself bind block devices for any storage + * devices it finds. + * + * @ahci_dev: AHCI parent device + * @return 0 if OK, -ve on error + */ +int ahci_probe_scsi(struct udevice *ahci_dev); + #endif -- 2.13.0.506.g27d5fe0cd-goog _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot