[U-Boot] [PATCH 27/29] dm: ahci: Add a driver for SCSI on AHCI
Simon Glass
sjg at chromium.org
Mon Jun 5 19:15:14 UTC 2017
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 at 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
More information about the U-Boot
mailing list