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>
master
Simon Glass 7 years ago
parent 5c56176318
commit 681357ffd9
  1. 57
      drivers/ata/ahci.c
  2. 22
      include/ahci.h

@ -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)
{

@ -200,4 +200,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

Loading…
Cancel
Save