diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 9c7b043aa2b4a98bcb755d7c5b70aa45a14fe210..5a20b97c4b8469f23942e2acd8cec994823df567 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1141,6 +1141,12 @@ static int ahci_scsi_bus_reset(struct udevice *dev)
 	return 0;
 }
 
+#ifdef CONFIG_DM_SCSI
+struct scsi_ops scsi_ops = {
+	.exec		= ahci_scsi_exec,
+	.bus_reset	= ahci_scsi_bus_reset,
+};
+#else
 int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
 {
 	return ahci_scsi_exec(dev, pccb);
@@ -1152,3 +1158,4 @@ __weak int scsi_bus_reset(struct udevice *dev)
 
 	return 0;
 }
+#endif
diff --git a/drivers/ata/dwc_ahci.c b/drivers/ata/dwc_ahci.c
index 401201717f885f65799c6ecb725228b1f89c9583..f6147989b1c811b01d474c325d6f735428297bbe 100644
--- a/drivers/ata/dwc_ahci.c
+++ b/drivers/ata/dwc_ahci.c
@@ -98,6 +98,7 @@ U_BOOT_DRIVER(dwc_ahci) = {
 	.id	= UCLASS_SCSI,
 	.of_match = dwc_ahci_ids,
 	.ofdata_to_platdata = dwc_ahci_ofdata_to_platdata,
+	.ops	= &scsi_ops,
 	.probe	= dwc_ahci_probe,
 	.priv_auto_alloc_size = sizeof(struct dwc_ahci_priv),
 	.flags = DM_FLAG_ALLOC_PRIV_DMA,
diff --git a/drivers/ata/sata_ceva.c b/drivers/ata/sata_ceva.c
index 7d61a546d757045d79daaa727e45badb00f4815d..d582e5ba80f0f86e0d65f673335e6003e245ac90 100644
--- a/drivers/ata/sata_ceva.c
+++ b/drivers/ata/sata_ceva.c
@@ -144,6 +144,7 @@ U_BOOT_DRIVER(ceva_host_blk) = {
 	.name = "ceva_sata",
 	.id = UCLASS_SCSI,
 	.of_match = sata_ceva_ids,
+	.ops = &scsi_ops,
 	.probe = sata_ceva_probe,
 	.ofdata_to_platdata = sata_ceva_ofdata_to_platdata,
 };
diff --git a/drivers/scsi/scsi-uclass.c b/drivers/scsi/scsi-uclass.c
index 40c5044f093194f11d9c84e0a76d535c155ada41..31e8999297196cad628d4de381b76e9f59e438fa 100644
--- a/drivers/scsi/scsi-uclass.c
+++ b/drivers/scsi/scsi-uclass.c
@@ -13,6 +13,26 @@
 #include <dm.h>
 #include <scsi.h>
 
+int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb)
+{
+	struct scsi_ops *ops = scsi_get_ops(dev);
+
+	if (!ops->exec)
+		return -ENOSYS;
+
+	return ops->exec(dev, pccb);
+}
+
+int scsi_bus_reset(struct udevice *dev)
+{
+	struct scsi_ops *ops = scsi_get_ops(dev);
+
+	if (!ops->bus_reset)
+		return -ENOSYS;
+
+	return ops->bus_reset(dev);
+}
+
 UCLASS_DRIVER(scsi) = {
 	.id		= UCLASS_SCSI,
 	.name		= "scsi",
diff --git a/include/scsi.h b/include/scsi.h
index 20f6932602bcf9f7cf96fe7d5f9df4a83fdf1f71..9cdd13c795d3aa881320621ae2780ba96ff88b98 100644
--- a/include/scsi.h
+++ b/include/scsi.h
@@ -191,12 +191,25 @@ struct scsi_ops {
 	int (*bus_reset)(struct udevice *dev);
 };
 
-#ifndef CONFIG_DM_SCSI
-void scsi_low_level_init(int busdevfunc);
-void scsi_init(void);
-#endif
+#define scsi_get_ops(dev)        ((struct scsi_ops *)(dev)->driver->ops)
+
+extern struct scsi_ops scsi_ops;
+
+/**
+ * scsi_exec() - execute a command
+ *
+ * @dev:	SCSI bus
+ * @cmd:	Command to execute
+ * @return 0 if OK, -ve on error
+ */
+int scsi_exec(struct udevice *dev, struct scsi_cmd *cmd);
 
-int scsi_exec(struct udevice *dev, struct scsi_cmd *pccb);
+/**
+ * scsi_bus_reset() - reset the bus
+ *
+ * @dev:	SCSI bus to reset
+ * @return 0 if OK, -ve on error
+ */
 int scsi_bus_reset(struct udevice *dev);
 
 /**
@@ -206,6 +219,11 @@ int scsi_bus_reset(struct udevice *dev);
  */
 int scsi_scan(bool verbose);
 
+#ifndef CONFIG_DM_SCSI
+void scsi_low_level_init(int busdevfunc);
+void scsi_init(void);
+#endif
+
 #define SCSI_IDENTIFY					0xC0  /* not used */
 
 /* Hardware errors  */