diff mbox series

[v2,1/8] scsi: Add ufs transport class

Message ID 1533469196-300-2-git-send-email-avri.altman@wdc.com (mailing list archive)
State Changes Requested
Headers show
Series scsi: scsi transport for ufs devices | expand

Commit Message

Avri Altman Aug. 5, 2018, 11:39 a.m. UTC
Scsi transport is a framework that allow to send scsi commands to
a non-scsi devices. Still, it is flexible enough to allow
sending non-scsi commands as well. We will use this framework to
manage ufs devices by sending UPIU transactions.

In addition to the basic SCSI core objects this transport class
introduces two additional (currently empty) class objects:
“ufs-host” and “ufs-port”.  There is only one “ufs-host” in the
system, but can be more-than-one “ufs-ports”.

Those classes are left empty for now, as ufs-sysfs already contains
an abundant amount of attributes.

A “ufs-port” is purely a software object. Evidently, the function
template takes no port as an argument, as the driver has no concept
of "port".  We only need it as a hanging point in the bsg device tree,
so maybe a more appropriate term would be: "ufs-bsg-dev-node".

The ufs-port has a pretty lean structure.  This is because we are
using upiu transactions that contains the outmost detailed info,
so we don't really need complex constructs to support it.

The transport will keep track of its  ufs-ports via its scsi host.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/Kconfig              |  13 ++
 drivers/scsi/Makefile             |   1 +
 drivers/scsi/scsi_transport_ufs.c | 354 ++++++++++++++++++++++++++++++++++++++
 include/scsi/scsi_transport_ufs.h |  44 +++++
 4 files changed, 412 insertions(+)
 create mode 100644 drivers/scsi/scsi_transport_ufs.c
 create mode 100644 include/scsi/scsi_transport_ufs.h

Comments

Bart Van Assche Aug. 8, 2018, 4:21 p.m. UTC | #1
On Sun, 2018-08-05 at 14:39 +0300, Avri Altman wrote:
> +config SCSI_UFS_ATTRS
> +	tristate "UFS Transport Attributes"
> +	depends on SCSI
> +	select BLK_DEV_BSGLIB
> +	help
> +	  Scsi transport is a framework that allow to send scsi commands to
> +	  a non-scsi devices. Still, it is flexible enough to allow sending
> +	  non-scsi commands as well. We will use this framework to manage
> +	  ufs devices by sending UPIU transactions.
> +
> +	  If you wish to export transport-specific information about
> +	  each attached UFS device to sysfs, say Y.
> +

The above text is misleading because it suggests that the primary purpose of
SCSI transport drivers is to send SCSI commands to non-SCSI devices. That is
not correct. Please improve that text, e.g. by changing it into something
like the following:

"Universal Flash Storage (UFS) is SCSI transport specification for accessing flash
storage on digital cameras, mobile phones and consumer electronic devices. An UFS
controller communicates with an UFS device by exchanging UFS Protocol Information
Units (UPIUs). UPIUs can not only be used as a transport layer for the SCSI protocol
but are also used by the UFS native command set. This transport driver supports
exchanging UFS protocol information units with an UFS device. See also the ufshcd
driver, which is a SCSI driver that supports UFS devices.

If you wish to exchange UPIU packets that are not SCSI packets with UFS devices,
say Y."

Thanks,

Bart.
Bart Van Assche Aug. 8, 2018, 4:58 p.m. UTC | #2
On Sun, 2018-08-05 at 14:39 +0300, Avri Altman wrote:
> A “ufs-port” is purely a software object. Evidently, the function
> template takes no port as an argument, as the driver has no concept
> of "port".  We only need it as a hanging point in the bsg device tree,
> so maybe a more appropriate term would be: "ufs-bsg-dev-node".
> 
> The ufs-port has a pretty lean structure.  This is because we are
> using upiu transactions that contains the outmost detailed info,
> so we don't really need complex constructs to support it.
> 
> The transport will keep track of its  ufs-ports via its scsi host.

Since no port concept has been defined in the UFS standard, can the port
concept be left out? Have you considered to attach the bsg queue directly
to the UFS SCSI host? There are two struct device instances in each Scsi_Host
structure, namely shost_gendev and shost_dev. I think the former corresponds
to /sys/bus/scsi/devices/host<n> and the latter corresponds to
/sys/class/scsi_host/host<n>. The bsg queue probably can be attached to the
latter. Several SCSI drivers already add additional sysfs attributes to the
/sys/class/scsi_host/host<n>.

Thanks,

Bart.
Avri Altman Aug. 9, 2018, 6:18 a.m. UTC | #3
> -----Original Message-----
> From: Bart Van Assche
> Sent: Wednesday, August 08, 2018 7:21 PM
> To: hch@lst.de; Avri Altman ; linux-scsi@vger.kernel.org;
> jthumshirn@suse.de; hare@suse.com; martin.petersen@oracle.com;
> jejb@linux.vnet.ibm.com
> Cc: Vinayak Holikatti ; Avi Shchislowski ; Alex Lemberg ; Stanislav Nijnikov ;
> subhashj@codeaurora.org
> Subject: Re: [PATCH v2 1/8] scsi: Add ufs transport class
> 
> On Sun, 2018-08-05 at 14:39 +0300, Avri Altman wrote:
> > +config SCSI_UFS_ATTRS
> > +	tristate "UFS Transport Attributes"
> > +	depends on SCSI
> > +	select BLK_DEV_BSGLIB
> > +	help
> > +	  Scsi transport is a framework that allow to send scsi commands to
> > +	  a non-scsi devices. Still, it is flexible enough to allow sending
> > +	  non-scsi commands as well. We will use this framework to manage
> > +	  ufs devices by sending UPIU transactions.
> > +
> > +	  If you wish to export transport-specific information about
> > +	  each attached UFS device to sysfs, say Y.
> > +
> 
> The above text is misleading because it suggests that the primary purpose of
> SCSI transport drivers is to send SCSI commands to non-SCSI devices. That is
> not correct. Please improve that text, e.g. by changing it into something
> like the following:
> 
> "Universal Flash Storage (UFS) is SCSI transport specification for accessing
> flash
> storage on digital cameras, mobile phones and consumer electronic devices.
> An UFS
> controller communicates with an UFS device by exchanging UFS Protocol
> Information
> Units (UPIUs). UPIUs can not only be used as a transport layer for the SCSI
> protocol
> but are also used by the UFS native command set. This transport driver
> supports
> exchanging UFS protocol information units with an UFS device. See also the
> ufshcd
> driver, which is a SCSI driver that supports UFS devices.
> 
> If you wish to exchange UPIU packets that are not SCSI packets with UFS
> devices,
> say Y."
Done.

> 
> Thanks,
> 
> Bart.
Avri Altman Aug. 9, 2018, 4:22 p.m. UTC | #4
> -----Original Message-----
> From: Bart Van Assche
> Sent: Wednesday, August 08, 2018 7:58 PM
> To: hch@lst.de; Avri Altman ; linux-scsi@vger.kernel.org;
> jthumshirn@suse.de; hare@suse.com; martin.petersen@oracle.com;
> jejb@linux.vnet.ibm.com
> Cc: Vinayak Holikatti ; Avi Shchislowski ; Alex Lemberg ; Stanislav Nijnikov ;
> subhashj@codeaurora.org
> Subject: Re: [PATCH v2 1/8] scsi: Add ufs transport class
> 
> On Sun, 2018-08-05 at 14:39 +0300, Avri Altman wrote:
> > A “ufs-port” is purely a software object. Evidently, the function
> > template takes no port as an argument, as the driver has no concept
> > of "port".  We only need it as a hanging point in the bsg device tree,
> > so maybe a more appropriate term would be: "ufs-bsg-dev-node".
> >
> > The ufs-port has a pretty lean structure.  This is because we are
> > using upiu transactions that contains the outmost detailed info,
> > so we don't really need complex constructs to support it.
> >
> > The transport will keep track of its  ufs-ports via its scsi host.
> 
> Since no port concept has been defined in the UFS standard, can the port
> concept be left out? Have you considered to attach the bsg queue directly
> to the UFS SCSI host? There are two struct device instances in each Scsi_Host
> structure, namely shost_gendev and shost_dev. I think the former
> corresponds
> to /sys/bus/scsi/devices/host<n> and the latter corresponds to
> /sys/class/scsi_host/host<n>. The bsg queue probably can be attached to the
> latter. Several SCSI drivers already add additional sysfs attributes to the
> /sys/class/scsi_host/host<n>.
Yeah - so today we are using shost_gendev, and the newly created classes points to /sys/devices/... :

htc_ocnwhl:/sys/class/ufs_host # ls -la
lrwxrwxrwx  1 root root 0 2018-06-17 13:15 host0 -> ../../devices/soc/1da4000.ufshc/host0/ufs_host/host0

htc_ocnwhl:/sys/class/ufs_ports # ls -la
lrwxrwxrwx  1 root root 0 2018-06-17 13:05 ufs-port-0:1 -> ../../devices/soc/1da4000.ufshc/host0/ufs-port-0:1/ufs_ports/ufs-port-0:0

and under /dev/ we get:
htc_ocnwhl:/dev # ls -la | grep ufs
crw-------  1 root      root         246,   3 1970-02-26 03:12 ufs-port-0:0

We didn't add any sysfs attribute to those classes, and I don't expect any to be added,
as I tried to explain in the commit:
"Those classes are left empty for now, as ufs-sysfs already contains
    an abundant amount of attributes."

Practically, this infrastructure provides the bsg device files /dev/<xxx-id>.

Anyway, if you think it's better, I will try to switch it as you suggested.
Can you please refer me to those scsi drivers that you mentioned?

Thanks a lot,
Avri

> 
> Thanks,
> 
> Bart.
Bart Van Assche Aug. 9, 2018, 4:35 p.m. UTC | #5
On Thu, 2018-08-09 at 16:22 +0000, Avri Altman wrote:
> > -----Original Message-----
> > From: Bart Van Assche
> > Sent: Wednesday, August 08, 2018 7:58 PM
> > To: hch@lst.de; Avri Altman ; linux-scsi@vger.kernel.org;
> > jthumshirn@suse.de; hare@suse.com; martin.petersen@oracle.com;
> > jejb@linux.vnet.ibm.com
> > Cc: Vinayak Holikatti ; Avi Shchislowski ; Alex Lemberg ; Stanislav Nijnikov ;
> > subhashj@codeaurora.org
> > Subject: Re: [PATCH v2 1/8] scsi: Add ufs transport class
> > 
> > On Sun, 2018-08-05 at 14:39 +0300, Avri Altman wrote:
> > > A “ufs-port” is purely a software object. Evidently, the function
> > > template takes no port as an argument, as the driver has no concept
> > > of "port".  We only need it as a hanging point in the bsg device tree,
> > > so maybe a more appropriate term would be: "ufs-bsg-dev-node".
> > > 
> > > The ufs-port has a pretty lean structure.  This is because we are
> > > using upiu transactions that contains the outmost detailed info,
> > > so we don't really need complex constructs to support it.
> > > 
> > > The transport will keep track of its  ufs-ports via its scsi host.
> > 
> > Since no port concept has been defined in the UFS standard, can the port
> > concept be left out? Have you considered to attach the bsg queue directly
> > to the UFS SCSI host? There are two struct device instances in each Scsi_Host
> > structure, namely shost_gendev and shost_dev. I think the former
> > corresponds
> > to /sys/bus/scsi/devices/host<n> and the latter corresponds to
> > /sys/class/scsi_host/host<n>. The bsg queue probably can be attached to the
> > latter. Several SCSI drivers already add additional sysfs attributes to the
> > /sys/class/scsi_host/host<n>.
> 
> Yeah - so today we are using shost_gendev, and the newly created classes points to /sys/devices/... :
> 
> htc_ocnwhl:/sys/class/ufs_host # ls -la
> lrwxrwxrwx  1 root root 0 2018-06-17 13:15 host0 -> ../../devices/soc/1da4000.ufshc/host0/ufs_host/host0
> 
> htc_ocnwhl:/sys/class/ufs_ports # ls -la
> lrwxrwxrwx  1 root root 0 2018-06-17 13:05 ufs-port-0:1 -> ../../devices/soc/1da4000.ufshc/host0/ufs-port-0:1/ufs_ports/ufs-port-0:0
> 
> and under /dev/ we get:
> htc_ocnwhl:/dev # ls -la | grep ufs
> crw-------  1 root      root         246,   3 1970-02-26 03:12 ufs-port-0:0
> 
> We didn't add any sysfs attribute to those classes, and I don't expect any to be added,
> as I tried to explain in the commit:
> "Those classes are left empty for now, as ufs-sysfs already contains
>     an abundant amount of attributes."
> 
> Practically, this infrastructure provides the bsg device files /dev/<xxx-id>.
> 
> Anyway, if you think it's better, I will try to switch it as you suggested.

My concern is that no port concept is defined in the UFS standard and hence that users
will be confused if they see a UFS port object in sysfs.

> Can you please refer me to those scsi drivers that you mentioned?

The following command will yield plenty of examples:

git grep -nHE 'device_(create|remove)_file|shost_attrs' drivers/scsi drivers/infiniband

Thanks,

Bart.
Bart Van Assche Aug. 9, 2018, 10:27 p.m. UTC | #6
On Thu, 2018-08-09 at 22:09 +0000, Avri Altman wrote:
> >> We didn't add any sysfs attribute to those classes, and I don't expect any to be added,
> >> as I tried to explain in the commit:
> >> "Those classes are left empty for now, as ufs-sysfs already contains
> >>     an abundant amount of attributes."
> >> 
> >> Practically, this infrastructure provides the bsg device files /dev/<xxx-id>.
> >> 
> >> Anyway, if you think it's better, I will try to switch it as you suggested.
> 
> >My concern is that no port concept is defined in the UFS standard and hence that users
> >will be confused if they see a UFS port object in sysfs.
> I agree.  Its a poor choice.
> One of the reasons for this awkward name, is that I wanted to distinguish between
> a single host object, and a more-than-one bsg device objects - see the snippet from the commit message below.
> So adding an index to host<id> does not serve this purpose.
> An immediate use-case that we had in mind for this infrastructure, aside from provisioning and various management tasks,
> Is that it can serve as a testing and validation environment, where the multiplicity of those devices will show its value.

Hello Avri,

I'm confused. Why do you want to have more than one bsg device node per UFS
SCSI host? According to what I found in the UFS specification each UFS host
communicates with exactly one UFS device. Does a UFS SCSI host correspond to
a UFS host? If so, why is there a need to have more than one bsg device node
per UFS SCSI host?

> "...
>  In addition to the basic SCSI core objects this transport class
>     introduces two additional (currently empty) class objects:
>     “ufs-host” and “ufs-port”.  There is only one “ufs-host” in the
>     system, but can be more-than-one “ufs-ports”.
> 
> ..."

Since both the ufs-host and ufs-port objects are empty, can both be left out?

Thanks,

Bart.
Bart Van Assche Aug. 9, 2018, 11:51 p.m. UTC | #7
On Thu, 2018-08-09 at 23:32 +0000, Avri Altman wrote:
> And as I said before, we think that maintaining the flexibility to have more-than-one
> bsg device nodes, will be useful serving as a testing and validation environment.

That is a very vague statement. Please clarify.

> >> "...
> >>  In addition to the basic SCSI core objects this transport class
> >>     introduces two additional (currently empty) class objects:
> >>     “ufs-host” and “ufs-port”.  There is only one “ufs-host” in the
> >>     system, but can be more-than-one “ufs-ports”.
> >> 
> >> ..."
> 
> >Since both the ufs-host and ufs-port objects are empty, can both be left out?
> But mustn't I declare those classes for the various components of the scsi transport to work?

Are you perhaps referring to the transport_class_register() calls in SCSI
transport drivers? From what I see in existing SCSI transport drivers the
transport_class_register() function is used to register link, port, host,
vport, rport and other objects. I don't think that a SCSI transport driver
is required to register host and port objects.

Maybe we should take a step back and discuss first why the new bsg queues
are registered by a transport driver? Since in case of UFS as far as I can
see there is no real need to introduce a transport driver other than for
creating the bsg device nodes, have you considered to add the code for
creating bsg device nodes to the UFS driver instead of in a UFS transport
driver? I think transport drivers were introduced as a way to share code
between multiple SCSI LLDs that use the same transport mechanism. In the
case of UFS there is only one SCSI LLD. Hence I'm wondering whether we
really need an UFS transport driver.

Thanks,

Bart.
Douglas Gilbert Aug. 10, 2018, 12:33 a.m. UTC | #8
On 2018-08-09 07:51 PM, Bart Van Assche wrote:
> On Thu, 2018-08-09 at 23:32 +0000, Avri Altman wrote:
>> And as I said before, we think that maintaining the flexibility to have more-than-one
>> bsg device nodes, will be useful serving as a testing and validation environment.
> 
> That is a very vague statement. Please clarify.
> 
>>>> "...
>>>>   In addition to the basic SCSI core objects this transport class
>>>>      introduces two additional (currently empty) class objects:
>>>>      “ufs-host” and “ufs-port”.  There is only one “ufs-host” in the
>>>>      system, but can be more-than-one “ufs-ports”.
>>>>
>>>> ..."
>>
>>> Since both the ufs-host and ufs-port objects are empty, can both be left out?
>> But mustn't I declare those classes for the various components of the scsi transport to work?
> 
> Are you perhaps referring to the transport_class_register() calls in SCSI
> transport drivers? From what I see in existing SCSI transport drivers the
> transport_class_register() function is used to register link, port, host,
> vport, rport and other objects. I don't think that a SCSI transport driver
> is required to register host and port objects.
> 
> Maybe we should take a step back and discuss first why the new bsg queues
> are registered by a transport driver? Since in case of UFS as far as I can
> see there is no real need to introduce a transport driver other than for
> creating the bsg device nodes, have you considered to add the code for
> creating bsg device nodes to the UFS driver instead of in a UFS transport
> driver? I think transport drivers were introduced as a way to share code
> between multiple SCSI LLDs that use the same transport mechanism. In the
> case of UFS there is only one SCSI LLD. Hence I'm wondering whether we
> really need an UFS transport driver.

If there is a one-to-one relationship between a UFS initiator, target and
logical unit then you could communicate with the driver using SCSI READ BUFFER
and WRITE BUFFER commands. Both have a vendor specific MODE value (0x1).
Also pick a non-default MODE SPECIFIC value (e.g. 110b) to lessen the chances
of clashing with a LU that is using the same technique.

Then you can read and write data to the ufs driver (initiator) as much as you
like via the ioctl(SG_IO) via its storage logical unit.


Another slightly more structured way would be to use the SCSI MANAGEMENT IN/OUT
commands with A MANAGEMENT PROTOCOL value of F0h to FFh (vendor specific).
Then if you need to configure the ufs driver to make the storage available
then driver could present a MANAGEMENT PROTOCOL "well-known logical unit"
(which is not so well known).

Doug Gilbert
Stanislav Nijnikov Aug. 14, 2018, 11:42 a.m. UTC | #9
Hi Bart,

> -----Original Message-----
> From: Bart Van Assche
> Sent: Friday, August 10, 2018 2:51 AM
> To: hch@lst.de; Avri Altman ; linux-scsi@vger.kernel.org; hare@suse.com; jthumshirn@suse.de; martin.petersen@oracle.com;
> jejb@linux.vnet.ibm.com
> Cc: Vinayak Holikatti ; Avi Shchislowski ; Alex Lemberg ; Stanislav Nijnikov ; subhashj@codeaurora.org
> Subject: Re: [PATCH v2 1/8] scsi: Add ufs transport class
> 
> On Thu, 2018-08-09 at 23:32 +0000, Avri Altman wrote:
> > And as I said before, we think that maintaining the flexibility to have more-than-one
> > bsg device nodes, will be useful serving as a testing and validation environment.
> 
> That is a very vague statement. Please clarify.
> 
> > >> "...
> > >>  In addition to the basic SCSI core objects this transport class
> > >>     introduces two additional (currently empty) class objects:
> > >>     “ufs-host” and “ufs-port”.  There is only one “ufs-host” in the
> > >>     system, but can be more-than-one “ufs-ports”.
> > >>
> > >> ..."
> >
> > >Since both the ufs-host and ufs-port objects are empty, can both be left out?
> > But mustn't I declare those classes for the various components of the scsi transport to work?
> 
> Are you perhaps referring to the transport_class_register() calls in SCSI
> transport drivers? From what I see in existing SCSI transport drivers the
> transport_class_register() function is used to register link, port, host,
> vport, rport and other objects. I don't think that a SCSI transport driver
> is required to register host and port objects.
> 
> Maybe we should take a step back and discuss first why the new bsg queues
> are registered by a transport driver? Since in case of UFS as far as I can
> see there is no real need to introduce a transport driver other than for
> creating the bsg device nodes, have you considered to add the code for
> creating bsg device nodes to the UFS driver instead of in a UFS transport
> driver? I think transport drivers were introduced as a way to share code
> between multiple SCSI LLDs that use the same transport mechanism. In the
> case of UFS there is only one SCSI LLD. Hence I'm wondering whether we
> really need an UFS transport driver.
> 

At the moment, the SCSI transport related code could be found at driver/scsi/scsi_transport_* files.
What is a point of hiding the UFS transport code inside the UFS driver?  

Regards.
Stanislav
Bart Van Assche Aug. 21, 2018, 1:54 a.m. UTC | #10
On Tue, 2018-08-14 at 11:42 +0000, Stanislav Nijnikov wrote:
> From: Bart Van Assche
> > Are you perhaps referring to the transport_class_register() calls in SCSI
> > transport drivers? From what I see in existing SCSI transport drivers the
> > transport_class_register() function is used to register link, port, host,
> > vport, rport and other objects. I don't think that a SCSI transport driver
> > is required to register host and port objects.
> > 
> > Maybe we should take a step back and discuss first why the new bsg queues
> > are registered by a transport driver? Since in case of UFS as far as I can
> > see there is no real need to introduce a transport driver other than for
> > creating the bsg device nodes, have you considered to add the code for
> > creating bsg device nodes to the UFS driver instead of in a UFS transport
> > driver? I think transport drivers were introduced as a way to share code
> > between multiple SCSI LLDs that use the same transport mechanism. In the
> > case of UFS there is only one SCSI LLD. Hence I'm wondering whether we
> > really need an UFS transport driver.
> 
> At the moment, the SCSI transport related code could be found at driver/scsi/scsi_transport_* files.
> What is a point of hiding the UFS transport code inside the UFS driver?  

Have you tried to implement the approach I proposed? If so, did you encounter
any issues that made it impossible to implement that approach? If you have
not yet tried to implement the above proposal, what are you waiting for?

Bart.
Avri Altman Aug. 21, 2018, 5:09 a.m. UTC | #11
Hi Bart,

> -----Original Message-----
> From: Bart Van Assche
> Sent: Tuesday, August 21, 2018 4:54 AM
> To: jthumshirn@suse.de; hch@lst.de; Avri Altman ;
> martin.petersen@oracle.com; linux-scsi@vger.kernel.org; hare@suse.com;
> jejb@linux.vnet.ibm.com; Stanislav Nijnikov
> Cc: Vinayak Holikatti ; Avi Shchislowski ; Alex Lemberg ;
> subhashj@codeaurora.org
> Subject: Re: [PATCH v2 1/8] scsi: Add ufs transport class
> 
> On Tue, 2018-08-14 at 11:42 +0000, Stanislav Nijnikov wrote:
> > From: Bart Van Assche
> > > Are you perhaps referring to the transport_class_register() calls in SCSI
> > > transport drivers? From what I see in existing SCSI transport drivers the
> > > transport_class_register() function is used to register link, port, host,
> > > vport, rport and other objects. I don't think that a SCSI transport driver
> > > is required to register host and port objects.
> > >
> > > Maybe we should take a step back and discuss first why the new bsg
> queues
> > > are registered by a transport driver? Since in case of UFS as far as I can
> > > see there is no real need to introduce a transport driver other than for
> > > creating the bsg device nodes, have you considered to add the code for
> > > creating bsg device nodes to the UFS driver instead of in a UFS transport
> > > driver? I think transport drivers were introduced as a way to share code
> > > between multiple SCSI LLDs that use the same transport mechanism. In
> the
> > > case of UFS there is only one SCSI LLD. Hence I'm wondering whether we
> > > really need an UFS transport driver.
> >
> > At the moment, the SCSI transport related code could be found at
> driver/scsi/scsi_transport_* files.
> > What is a point of hiding the UFS transport code inside the UFS driver?
> 
> Have you tried to implement the approach I proposed? If so, did you
> encounter
> any issues that made it impossible to implement that approach? If you have
> not yet tried to implement the above proposal, what are you waiting for?
Your proposal makes a perfect sense, and it is certainly a feasible path.
I also accept your point and withdraw from my intension to create multiple bsg dev nodes.

It is just that I couldn't find any other lld that creates its own bsg queue - 
Currently this is only done within scsi transport and scsi sysfs.
So before sending a new RFC, I was hoping to get additional support for your proposal.
Will send it in the coming days.

Thanks a lot,
Avri
diff mbox series

Patch

diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 8fc851a..9e99275 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -290,6 +290,19 @@  config SCSI_SAS_ATTRS
 	  If you wish to export transport-specific information about
 	  each attached SAS device to sysfs, say Y.
 
+config SCSI_UFS_ATTRS
+	tristate "UFS Transport Attributes"
+	depends on SCSI
+	select BLK_DEV_BSGLIB
+	help
+	  Scsi transport is a framework that allow to send scsi commands to
+	  a non-scsi devices. Still, it is flexible enough to allow sending
+	  non-scsi commands as well. We will use this framework to manage
+	  ufs devices by sending UPIU transactions.
+
+	  If you wish to export transport-specific information about
+	  each attached UFS device to sysfs, say Y.
+
 source "drivers/scsi/libsas/Kconfig"
 
 config SCSI_SRP_ATTRS
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index d1bad43..e0efc06 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -34,6 +34,7 @@  obj-$(CONFIG_SCSI_ISCSI_ATTRS)	+= scsi_transport_iscsi.o
 obj-$(CONFIG_SCSI_SAS_ATTRS)	+= scsi_transport_sas.o
 obj-$(CONFIG_SCSI_SAS_LIBSAS)	+= libsas/
 obj-$(CONFIG_SCSI_SRP_ATTRS)	+= scsi_transport_srp.o
+obj-$(CONFIG_SCSI_UFS_ATTRS)	+= scsi_transport_ufs.o
 obj-$(CONFIG_SCSI_DH)		+= device_handler/
 
 obj-$(CONFIG_LIBFC)		+= libfc/
diff --git a/drivers/scsi/scsi_transport_ufs.c b/drivers/scsi/scsi_transport_ufs.c
new file mode 100644
index 0000000..06349c6
--- /dev/null
+++ b/drivers/scsi/scsi_transport_ufs.c
@@ -0,0 +1,354 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SCSI UFS transport class
+ *
+ * Copyright (C) 2018 Western Digital Corporation
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/blkdev.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_ufs.h>
+
+
+#define UFS_HOST_ATTRS 0
+#define UFS_PORT_ATTRS 0
+
+#define MAX_PORTS 256
+static DEFINE_IDA(ufs_ida);
+
+struct ufs_internal {
+	struct scsi_transport_template t;
+	struct ufs_function_template *f;
+
+	struct device_attribute *host_attrs[UFS_HOST_ATTRS + 1];
+	struct device_attribute *port_attrs[UFS_PORT_ATTRS + 1];
+	struct transport_container port_attr_cont;
+};
+
+static inline struct ufs_internal *
+to_ufs_internal(struct scsi_transport_template *tmpl)
+{
+	return container_of(tmpl, struct ufs_internal, t);
+}
+
+struct ufs_host_attrs {
+	atomic_t active_ports;
+};
+
+static inline struct ufs_host_attrs *
+to_ufs_host_attrs(struct Scsi_Host *shost)
+{
+	return (struct ufs_host_attrs *)shost->shost_data;
+}
+
+static int ufs_bsg_dispatch(struct bsg_job *job)
+{
+	struct Scsi_Host *shost = dev_to_shost(job->dev);
+	struct ufs_internal *i = to_ufs_internal(shost->transportt);
+
+	/* check for payload_len when we'll support data transfer upiu */
+
+	return i->f->bsg_request(job);
+}
+
+static int ufs_bsg_initialize(struct Scsi_Host *shost, struct ufs_port *port)
+{
+	struct request_queue *q;
+	struct ufs_internal *i = to_ufs_internal(shost->transportt);
+
+	if (!i->f->bsg_request) {
+		pr_info("%s can't handle ufs requests\n", shost->hostt->name);
+		return 0;
+	}
+
+	q = bsg_setup_queue(&port->dev, dev_name(&port->dev),
+			    ufs_bsg_dispatch, 0);
+	if (IS_ERR(q))
+		return PTR_ERR(q);
+	port->q = q;
+
+	return 0;
+}
+
+static int ufs_host_setup(struct transport_container *tc, struct device *dev,
+			  struct device *cdev)
+{
+	struct Scsi_Host *shost = dev_to_shost(dev);
+	struct ufs_host_attrs *ufs_host = to_ufs_host_attrs(shost);
+
+	atomic_set(&ufs_host->active_ports, 0);
+
+	return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(ufs_host_class, "ufs_host", ufs_host_setup,
+			       NULL, NULL);
+
+static DECLARE_TRANSPORT_CLASS(ufs_port_class, "ufs_ports",
+			       NULL, NULL, NULL);
+
+static int ufs_host_match(struct attribute_container *cont,
+			  struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct ufs_internal *i;
+
+	if (!scsi_is_host_device(dev))
+		return 0;
+
+	shost = dev_to_shost(dev);
+	if (!shost->transportt)
+		return 0;
+
+	if (shost->transportt->host_attrs.ac.class != &ufs_host_class.class)
+		return 0;
+
+	i = to_ufs_internal(shost->transportt);
+
+	return &i->t.host_attrs.ac == cont;
+}
+
+static void ufs_port_release(struct device *dev)
+{
+	struct ufs_port *port = dev_to_ufs_port(dev);
+	struct Scsi_Host *shost = dev_to_shost(dev->parent);
+	struct ufs_host_attrs *ufs_host = to_ufs_host_attrs(shost);
+
+	ida_simple_remove(&ufs_ida, port->id);
+	atomic_dec(&ufs_host->active_ports);
+	put_device(dev->parent);
+	kfree(port);
+}
+
+static inline int scsi_is_ufs_port(const struct device *dev)
+{
+	return dev->release == ufs_port_release;
+}
+
+static int ufs_port_match(struct attribute_container *cont, struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct ufs_internal *i;
+
+	if (!scsi_is_ufs_port(dev))
+		return 0;
+
+	shost = dev_to_shost(dev->parent);
+
+	if (!shost->transportt)
+		return 0;
+
+	if (shost->transportt->host_attrs.ac.class != &ufs_host_class.class)
+		return 0;
+
+	i = to_ufs_internal(shost->transportt);
+	return &i->port_attr_cont.ac == cont;
+}
+
+/**
+ * ufs_attach_transport - instantiate UFS transport template
+ * @ft:		UFS transport class function template
+ */
+struct scsi_transport_template *
+ufs_attach_transport(struct ufs_function_template *ft)
+{
+	struct ufs_internal *i = kzalloc(sizeof(struct ufs_internal),
+					GFP_KERNEL);
+
+	if (unlikely(!i))
+		return NULL;
+
+	i->f = ft;
+	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+	i->t.host_attrs.ac.class = &ufs_host_class.class;
+	i->t.host_attrs.ac.match = ufs_host_match;
+	i->t.host_size = sizeof(struct ufs_host_attrs);
+	i->host_attrs[0] = NULL;
+	transport_container_register(&i->t.host_attrs);
+
+	i->port_attr_cont.ac.class = &ufs_port_class.class;
+	i->port_attr_cont.ac.attrs = &i->port_attrs[0];
+	i->port_attr_cont.ac.match = ufs_port_match;
+	i->port_attrs[0] = NULL;
+	transport_container_register(&i->port_attr_cont);
+
+	return &i->t;
+}
+EXPORT_SYMBOL(ufs_attach_transport);
+
+/**
+ * ufs_release_transport  -  release UFS transport template instance
+ * @t:		transport template instance
+ */
+void ufs_release_transport(struct scsi_transport_template *t)
+{
+	struct ufs_internal *i = to_ufs_internal(t);
+
+	transport_container_unregister(&i->t.host_attrs);
+	transport_container_unregister(&i->port_attr_cont);
+	kfree(i);
+}
+EXPORT_SYMBOL(ufs_release_transport);
+
+/** ufs_port_alloc - allocate and initialize a UFS port structure
+ * @shost:	scsi host that the port is attached to
+ *
+ * Allocates a UFS port structure.  It will be added to the device tree
+ * below the device specified by its Scsi_Host parent.
+ * Returns %NULL on error
+ */
+struct ufs_port *ufs_port_alloc(struct Scsi_Host *shost)
+{
+	struct ufs_port *port;
+	struct device *parent = &shost->shost_gendev;
+	struct ufs_host_attrs *ufs_host = to_ufs_host_attrs(shost);
+
+	port = kzalloc(sizeof(*port), GFP_KERNEL);
+	if (!port)
+		return NULL;
+
+	port->id = ida_simple_get(&ufs_ida, 0, MAX_PORTS, GFP_KERNEL);
+	if (port->id < 0)
+		return NULL;
+	atomic_inc(&ufs_host->active_ports);
+
+	device_initialize(&port->dev);
+
+	port->dev.parent = get_device(parent);
+	port->dev.release = ufs_port_release;
+
+	dev_set_name(&port->dev, "ufs-port-%d:%d", shost->host_no, port->id);
+
+	transport_setup_device(&port->dev);
+
+	return port;
+}
+EXPORT_SYMBOL(ufs_port_alloc);
+
+/**
+ * ufs_port_add - add a UFS port to the device hierarchy
+ * @port:	port to be added
+ *
+ * publishes a port to the rest of the system
+ */
+int ufs_port_add(struct ufs_port *port)
+{
+	struct device *dev = &port->dev;
+	struct Scsi_Host *shost = dev_to_shost(dev->parent);
+	int error;
+
+	if (!port) {
+		pr_err("%s failed with null port\n", __func__);
+		return -EINVAL;
+	}
+
+	error = device_add(dev);
+
+	if (error)
+		return error;
+
+	transport_add_device(dev);
+	transport_configure_device(dev);
+
+	if (ufs_bsg_initialize(shost, port))
+		dev_err(dev, "fail to initialize a bsg dev %d\n",
+			shost->host_no);
+
+	return 0;
+}
+EXPORT_SYMBOL(ufs_port_add);
+
+/**
+ * ufs_port_free  -  free a ufs port
+ * @port:	ufs port to free
+ *
+ * Frees the specified ufs port. Should be called on ufs_port_add() failure.
+ */
+void ufs_port_free(struct ufs_port *port)
+{
+	transport_destroy_device(&port->dev);
+	put_device(&port->dev);
+}
+EXPORT_SYMBOL(ufs_port_free);
+
+/**
+ * ufs_port_delete  -  remove a ufs port
+ * @port:	ufs port to remove
+ *
+ */
+void ufs_port_delete(struct ufs_port *port)
+{
+	struct device *dev = &port->dev;
+
+	if (port->q)
+		bsg_unregister_queue(port->q);
+
+	transport_remove_device(dev);
+	device_del(dev);
+	transport_destroy_device(dev);
+
+	put_device(dev);
+}
+EXPORT_SYMBOL(ufs_port_delete);
+
+static int do_ufs_port_del(struct device *dev, void *data)
+{
+	if (scsi_is_ufs_port(dev))
+		ufs_port_delete(dev_to_ufs_port(dev));
+
+	return 0;
+}
+
+/**
+ * ufs_remove_host  -  tear down a ufs port devices
+ * @shost:	the scsi host which is parenting the ufs port objects
+ *
+ * Removes all ufs port devices.
+ * Unharm Other devices that are attached to that host.
+ */
+void ufs_remove_host(struct Scsi_Host *shost)
+{
+	device_for_each_child(&shost->shost_gendev, NULL, do_ufs_port_del);
+}
+EXPORT_SYMBOL_GPL(ufs_remove_host);
+
+static __init int ufs_transport_init(void)
+{
+	int error;
+
+	error = transport_class_register(&ufs_host_class);
+	if (error)
+		goto out;
+
+	error = transport_class_register(&ufs_port_class);
+	if (error)
+		goto out_unregister_transport;
+
+	return 0;
+
+out_unregister_transport:
+	transport_class_unregister(&ufs_host_class);
+out:
+	return error;
+}
+
+static void __exit ufs_transport_exit(void)
+{
+	transport_class_unregister(&ufs_host_class);
+	transport_class_unregister(&ufs_port_class);
+}
+
+MODULE_AUTHOR("WDC");
+MODULE_DESCRIPTION("UFS Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(ufs_transport_init);
+module_exit(ufs_transport_exit);
diff --git a/include/scsi/scsi_transport_ufs.h b/include/scsi/scsi_transport_ufs.h
new file mode 100644
index 0000000..c45dfb8
--- /dev/null
+++ b/include/scsi/scsi_transport_ufs.h
@@ -0,0 +1,44 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018 Western Digital Corporation
+ */
+
+#ifndef SCSI_TRANSPORT_UFS_H
+#define SCSI_TRANSPORT_UFS_H
+
+#include <linux/bsg-lib.h>
+#include <linux/bsg.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+
+struct ufs_function_template {
+	int	(*bsg_request)(struct bsg_job *job);
+};
+
+/* One might expect a more complex structure –
+ * some representation of a list containing all the luns of the systems,
+ * including the w-luns.  However, as we are using upiu transactions that
+ * contains the lun index in its header, we need not to have its representation
+ * in the device tree.
+ */
+struct ufs_port {
+	struct device		dev;
+	int			id;
+	struct request_queue	*q;
+};
+
+static inline struct ufs_port *dev_to_ufs_port(struct device *d)
+{
+	return container_of(d, struct ufs_port, dev);
+}
+
+struct scsi_transport_template *
+ufs_attach_transport(struct ufs_function_template *ft);
+void ufs_release_transport(struct scsi_transport_template *t);
+struct ufs_port *ufs_port_alloc(struct Scsi_Host *shost);
+int ufs_port_add(struct ufs_port *port);
+void ufs_port_free(struct ufs_port *port);
+void ufs_port_delete(struct ufs_port *port);
+void ufs_remove_host(struct Scsi_Host *shost);
+#endif