>
> > >
> > > Signed-off-by: Can Guo <cang@xxxxxxxxxxxxxx>
> > > ---
> > > drivers/scsi/ufs/Kconfig | 3 ++-
> > > drivers/scsi/ufs/Makefile | 2 +- drivers/scsi/ufs/ufs_bsg.c |
> > > 49
> > > +++++++++++++++++++++++++++++++++++++++++++---
> > > drivers/scsi/ufs/ufs_bsg.h | 8 --------
> > > drivers/scsi/ufs/ufshcd.c | 36 ++++++++++++++++++++++++++++++----
> > > drivers/scsi/ufs/ufshcd.h | 7 ++++++-
> > > 6 files changed, 87 insertions(+), 18 deletions(-)
> > >
> > > diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
> > > index d14c224..72620ce 100644
> > > --- a/drivers/scsi/ufs/Kconfig
> > > +++ b/drivers/scsi/ufs/Kconfig
> > > @@ -38,6 +38,7 @@ config SCSI_UFSHCD
> > > select PM_DEVFREQ
> > > select DEVFREQ_GOV_SIMPLE_ONDEMAND
> > > select NLS
> > > + select BLK_DEV_BSGLIB
> >
> > Why is this needed?
> >
>
> Because ufshcd.c needs to call some funcs defined in bsg lib.
>
> > > ---help---
> > > This selects the support for UFS devices in Linux, say Y and make
> > > sure that you know the name of your UFS host adapter (the card
> > > @@ -143,7 +144,7 @@ config SCSI_UFS_TI_J721E
> > > If unsure, say N.
> > >
> > > config SCSI_UFS_BSG
> > > - bool "Universal Flash Storage BSG device node"
> > > + tristate "Universal Flash Storage BSG device node"
> > > depends on SCSI_UFSHCD
> > > select BLK_DEV_BSGLIB
> > > help
> > > diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
> > > index 94c6c5d..904eff1 100644
> > > --- a/drivers/scsi/ufs/Makefile
> > > +++ b/drivers/scsi/ufs/Makefile
> > > @@ -6,7 +6,7 @@ obj-$(CONFIG_SCSI_UFS_CDNS_PLATFORM) +=
> > > cdns-pltfrm.o
> > > obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
> > > obj-$(CONFIG_SCSI_UFSHCD) += ufshcd-core.o
> > > ufshcd-core-y += ufshcd.o ufs-sysfs.o
> > > -ufshcd-core-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
> > > +obj-$(CONFIG_SCSI_UFS_BSG) += ufs_bsg.o
> > > obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
> > > obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
> > > obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o diff --git
> > > a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c index
> > > 3a2e68f..302222f 100644
> > > --- a/drivers/scsi/ufs/ufs_bsg.c
> > > +++ b/drivers/scsi/ufs/ufs_bsg.c
> > > @@ -164,13 +164,15 @@ static int ufs_bsg_request(struct bsg_job *job)
> > > */
> > > void ufs_bsg_remove(struct ufs_hba *hba) {
> > > - struct device *bsg_dev = &hba->bsg_dev;
> > > + struct device *bsg_dev = hba->bsg_dev;
> > >
> > > if (!hba->bsg_queue)
> > > return;
> > >
> > > bsg_remove_queue(hba->bsg_queue);
> > >
> > > + hba->bsg_dev = NULL;
> > > + hba->bsg_queue = NULL;
> > > device_del(bsg_dev);
> > > put_device(bsg_dev);
> > > }
> > > @@ -178,6 +180,7 @@ void ufs_bsg_remove(struct ufs_hba *hba)
> > > static inline void ufs_bsg_node_release(struct device *dev)
> > > {
> > > put_device(dev->parent);
> > > + kfree(dev);
> > > }
> > >
> > > /**
> > > @@ -186,14 +189,19 @@ static inline void ufs_bsg_node_release(struct
> > > device *dev)
> > > *
> > > * Called during initial loading of the driver, and before
> > > scsi_scan_host.
> > > */
> > > -int ufs_bsg_probe(struct ufs_hba *hba)
> > > +static int ufs_bsg_probe(struct ufs_hba *hba)
> > > {
> > > - struct device *bsg_dev = &hba->bsg_dev;
> > > + struct device *bsg_dev;
> > > struct Scsi_Host *shost = hba->host;
> > > struct device *parent = &shost->shost_gendev;
> > > struct request_queue *q;
> > > int ret;
> > >
> > > + bsg_dev = kzalloc(sizeof(*bsg_dev), GFP_KERNEL);
> > > + if (!bsg_dev)
> > > + return -ENOMEM;
> > > +
> > > + hba->bsg_dev = bsg_dev;
> > > device_initialize(bsg_dev);
> > >
> > > bsg_dev->parent = get_device(parent);
> > > @@ -217,6 +225,41 @@ int ufs_bsg_probe(struct ufs_hba *hba)
> > >
> > > out:
> > > dev_err(bsg_dev, "fail to initialize a bsg dev %d\n",
> > > shost->host_no);
> > > + hba->bsg_dev = NULL;
> > > put_device(bsg_dev);
> > > return ret;
> > > }
> > > +
> > > +static int __init ufs_bsg_init(void)
> > > +{
> > > + struct list_head *hba_list = NULL;
> > > + struct ufs_hba *hba;
> > > + int ret = 0;
> > > +
> > > + ufshcd_get_hba_list_lock(&hba_list);
> > > + list_for_each_entry(hba, hba_list, list) {
> > > + ret = ufs_bsg_probe(hba);
> > > + if (ret)
> > > + break;
> > > + }
> >
> > So what happens if I go CONFIG_SCSI_UFS_BSG=y and
> > CONFIG_SCSI_UFS_QCOM=y?
> >
> > Wouldn't that mean that ufs_bsg_init() is called before ufshcd_init()
> > has added the controller to the list? And even in the even that they are
> > both =m, what happens if they are invoked in the "wrong" order?
> >
>
> In the case that CONFIG_SCSI_UFS_BSG=y and CONFIG_SCSI_UFS_QCOM=y,
> I give late_initcall_sync(ufs_bsg_init) to make sure ufs_bsg_init
> is invoked only after platform driver is probed. I tested this combination.
>
> In the case that both of them are "m", installing ufs-bsg before ufs-qcom
> is installed would have no effect as ufs_hba_list is empty, which is
> expected.
Why is it the expected behavior that bsg may or may not probe
depending
on the driver load order and potentially timing of the initialization.
> And in real cases, as the UFS is the boot device, UFS driver will always
> be probed during bootup.
>
The UFS driver will load and probe because it's mentioned in the
devicetree, but if either the ufs drivers or any of its dependencies
(phy, resets, clocks, etc) are built as modules it might very well
finish probing after lateinitcall.
So in the even that the bsg is =y and any of these drivers are =m, or
if
you're having bad luck with your timing, the list will be empty.
As described below, if bsg=m, then there's nothing that will load the
module and the bsg will not probe...