All of lore.kernel.org
 help / color / mirror / Atom feed
* FireWire/SBP2 Target mode
@ 2011-08-17 14:51 ` Chris Boot
  0 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2011-08-17 14:51 UTC (permalink / raw)
  To: target-devel, linux1394-devel, linux-scsi, lkml

Hi folks,

Now that we have a nice SCSI target framework in the kernel, and drivers 
either in-tree or being worked on for iSCSI, FC, FCoE, SAS and iSER, I 
was wondering about the possibility of adding FireWire to that list. 
Apple Macs have had a FireWire Target Disk mode for a long time, and 
there is even a program called Endpoint[1] that apparently does this on 
Linux though it looks completely untouched since 2003 and no longer 
works as it depends on the old FireWire stack.

I would very much like to see something like this added to the kernel, 
and would very much like to contribute to writing this feature. However 
my kernel development knowledge is very limited indeed so this would 
require a lot hand-holding and mentoring.

What's the interest in such a feature? Would anyone be able to give some 
(a lot?) of their time to help write this?

Thanks,
Chris

[1] http://oss.oracle.com/projects/endpoint/


^ permalink raw reply	[flat|nested] 104+ messages in thread

* FireWire/SBP2 Target mode
@ 2011-08-17 14:51 ` Chris Boot
  0 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2011-08-17 14:51 UTC (permalink / raw)
  To: target-devel, linux1394-devel, linux-scsi, lkml

Hi folks,

Now that we have a nice SCSI target framework in the kernel, and drivers 
either in-tree or being worked on for iSCSI, FC, FCoE, SAS and iSER, I 
was wondering about the possibility of adding FireWire to that list. 
Apple Macs have had a FireWire Target Disk mode for a long time, and 
there is even a program called Endpoint[1] that apparently does this on 
Linux though it looks completely untouched since 2003 and no longer 
works as it depends on the old FireWire stack.

I would very much like to see something like this added to the kernel, 
and would very much like to contribute to writing this feature. However 
my kernel development knowledge is very limited indeed so this would 
require a lot hand-holding and mentoring.

What's the interest in such a feature? Would anyone be able to give some 
(a lot?) of their time to help write this?

Thanks,
Chris

[1] http://oss.oracle.com/projects/endpoint/


------------------------------------------------------------------------------
Get a FREE DOWNLOAD! and learn more about uberSVN rich system, 
user administration capabilities and model configuration. Take 
the hassle out of deploying and managing Subversion and the 
tools developers use with it. http://p.sf.net/sfu/wandisco-d2d-2

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2011-08-17 14:51 ` Chris Boot
  (?)
@ 2011-08-17 18:57 ` Stefan Richter
  -1 siblings, 0 replies; 104+ messages in thread
From: Stefan Richter @ 2011-08-17 18:57 UTC (permalink / raw)
  To: Chris Boot; +Cc: target-devel, linux1394-devel, linux-scsi, lkml

On Aug 17 Chris Boot wrote:
> Now that we have a nice SCSI target framework in the kernel, and drivers 
> either in-tree or being worked on for iSCSI, FC, FCoE, SAS and iSER, I 
> was wondering about the possibility of adding FireWire to that list. 
> Apple Macs have had a FireWire Target Disk mode for a long time, and 

Side note:  This target mode is a feature of their OpenFirmware and EFI
firmwares, not of the Mac OS and the OS X.  Though both firmware- and
operating-system-implemented SBP-2 targets certainly have their use cases.
Aside from the SBP-2 target in Macs and from Oracle Endpoint, I only know
of SBP-2 targets that are built upon dedicated bus bridge silicon.

> there is even a program called Endpoint[1] that apparently does this on 
> Linux though it looks completely untouched since 2003 and no longer 
> works as it depends on the old FireWire stack.

It can be made to work again if it and libraw1394 are slightly extended to
use a different API for Configuration ROM changes.  Or Endpoint could be
ported from libraw1394 to <linux/firewire-cdev.h>.  But then it would of
course not benefit from the generic SCSI target infrastructure, e.g. WRT
administration, backing storage choices, or command set support.

> I would very much like to see something like this added to the kernel, 
> and would very much like to contribute to writing this feature. However 
> my kernel development knowledge is very limited indeed so this would 
> require a lot hand-holding and mentoring.
> 
> What's the interest in such a feature?

People keep asking for it; very infrequently though.

> Would anyone be able to give some (a lot?) of their time to help write
> this?
> 
> Thanks,
> Chris
> 
> [1] http://oss.oracle.com/projects/endpoint/

I for one can answer questions about firewire-core's driver API but do not
have much spare time for more, for the time being.

BTW, a kernelspace SBP-2 target drivers would use several of the FireWire
features that the firewire-net driver uses too.  So the sources of that
driver may be of help where the firewire-core kerneldoc comments are
missing or are not providing the bigger picture.
-- 
Stefan Richter
-=====-==-== =--- =---=
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2011-08-17 14:51 ` Chris Boot
  (?)
  (?)
@ 2011-08-18 16:19 ` Clemens Ladisch
  2012-02-01 19:50   ` Andy Grover
  -1 siblings, 1 reply; 104+ messages in thread
From: Clemens Ladisch @ 2011-08-18 16:19 UTC (permalink / raw)
  To: Chris Boot, target-devel; +Cc: linux1394-devel, linux-scsi, lkml

Chris Boot wrote:
> Now that we have a nice SCSI target framework in the kernel, and drivers
> either in-tree or being worked on for iSCSI, FC, FCoE, SAS and iSER, I
> was wondering about the possibility of adding FireWire to that list.

As far as I can tell from briefly looking at the framework, this would
require both a fabric module (which is nicely abstracted) and a new
protocol (which doesn't seem to be).

Is there any documentation of how to add a new LIO protocol?

And what is the difference between a protocol and a fabric?


Regards,
Clemens

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2011-08-18 16:19 ` Clemens Ladisch
@ 2012-02-01 19:50   ` Andy Grover
  2012-02-01 21:41       ` Stefan Richter
  0 siblings, 1 reply; 104+ messages in thread
From: Andy Grover @ 2012-02-01 19:50 UTC (permalink / raw)
  To: Clemens Ladisch
  Cc: Chris Boot, target-devel, linux1394-devel, linux-scsi, lkml

Sorry to raise this thread from the dead.

Chris Boot wrote Aug 2011-ish:
> I would very much like to see something like this added to the
> kernel, and would very much like to contribute to writing this
> feature. However my kernel development knowledge is very limited
> indeed so this would require a lot hand-holding and mentoring.

If you're still interested, I'd definitely encourage you to work on this
project. Me and others on target-devel would be happy to help with any
target-related advice.

On 08/18/2011 09:19 AM, Clemens Ladisch wrote:
> Chris Boot wrote:
>> Now that we have a nice SCSI target framework in the kernel, and drivers
>> either in-tree or being worked on for iSCSI, FC, FCoE, SAS and iSER, I
>> was wondering about the possibility of adding FireWire to that list.
> 
> As far as I can tell from briefly looking at the framework, this would
> require both a fabric module (which is nicely abstracted) and a new
> protocol (which doesn't seem to be).
> 
> Is there any documentation of how to add a new LIO protocol?
> 
> And what is the difference between a protocol and a fabric?

Right now the documentation is the other fabric modules, alas.

You're saying the sbp2 protocol can theoretically be used other places
besides firewire? I'd say put it all in the fabric module for now.

You can also join irc.oftc.net #storage and ask more questions there.

Regards -- Andy

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-01 19:50   ` Andy Grover
@ 2012-02-01 21:41       ` Stefan Richter
  0 siblings, 0 replies; 104+ messages in thread
From: Stefan Richter @ 2012-02-01 21:41 UTC (permalink / raw)
  To: Andy Grover
  Cc: Clemens Ladisch, Chris Boot, target-devel, linux1394-devel,
	linux-scsi, lkml

On Feb 01 Andy Grover wrote:
> You're saying the sbp2 protocol can theoretically be used other places
> besides firewire? I'd say put it all in the fabric module for now.

While SBP-2 is explicitly specified for IEEE 1394 a.k.a. FireWire only,
it could be used on any bus architecture which implements IEEE 1212
"Control and Status Registers (CSR) Architecture for Microcomputer
Buses".  But IEEE 1394 a.k.a. FireWire is nowadays the only remaining IEEE
1212 implementation, as far as I know.

On the other hand, the transport protocol SBP-2 can be used to encapsulate
various protocols besides SCSI.  A long time ago I heard that there were
SBP-2 printers that weren't SCSI printers, but I may have confused
something.

The current version of the protocol, SBP-3 which extends SBP-2
in an upwards compatible way, has been developed specifically in
order to transport AV/C command sets.  (AV/C is a set of specifications
from the 1394 Trade Association that build on top of IEC 61883 "Consumer
audio/video equipment - Digital interface" and is used for camcorders,
audio interfaces, studio-grade video equipment, TV set top boxes etc.)
But I am not aware of any existing SBP-3 target or SBP-3 initiator which
actually implements AV/C.

So in short,
  - SBP-2/3 is only used on the FireWire bus.
  - Potentially there could be SBP-2/3 targets or initiators that
    implement something else than SCSI.  But stock SBP-2/3 initiator
    drivers of popular OSs are SCSI initiators, and non-SCSI SBP-2/3
    targets are extremely rare or don't exist actually.
-- 
Stefan Richter
-=====-===-- --=- ----=
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
@ 2012-02-01 21:41       ` Stefan Richter
  0 siblings, 0 replies; 104+ messages in thread
From: Stefan Richter @ 2012-02-01 21:41 UTC (permalink / raw)
  To: Andy Grover; +Cc: linux-scsi, lkml, target-devel, linux1394-devel

On Feb 01 Andy Grover wrote:
> You're saying the sbp2 protocol can theoretically be used other places
> besides firewire? I'd say put it all in the fabric module for now.

While SBP-2 is explicitly specified for IEEE 1394 a.k.a. FireWire only,
it could be used on any bus architecture which implements IEEE 1212
"Control and Status Registers (CSR) Architecture for Microcomputer
Buses".  But IEEE 1394 a.k.a. FireWire is nowadays the only remaining IEEE
1212 implementation, as far as I know.

On the other hand, the transport protocol SBP-2 can be used to encapsulate
various protocols besides SCSI.  A long time ago I heard that there were
SBP-2 printers that weren't SCSI printers, but I may have confused
something.

The current version of the protocol, SBP-3 which extends SBP-2
in an upwards compatible way, has been developed specifically in
order to transport AV/C command sets.  (AV/C is a set of specifications
from the 1394 Trade Association that build on top of IEC 61883 "Consumer
audio/video equipment - Digital interface" and is used for camcorders,
audio interfaces, studio-grade video equipment, TV set top boxes etc.)
But I am not aware of any existing SBP-3 target or SBP-3 initiator which
actually implements AV/C.

So in short,
  - SBP-2/3 is only used on the FireWire bus.
  - Potentially there could be SBP-2/3 targets or initiators that
    implement something else than SCSI.  But stock SBP-2/3 initiator
    drivers of popular OSs are SCSI initiators, and non-SCSI SBP-2/3
    targets are extremely rare or don't exist actually.
-- 
Stefan Richter
-=====-===-- --=- ----=
http://arcgraph.de/sr/

------------------------------------------------------------------------------
Keep Your Developer Skills Current with LearnDevNow!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-d2d

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-01 21:41       ` Stefan Richter
@ 2012-02-02  9:22         ` Boaz Harrosh
  -1 siblings, 0 replies; 104+ messages in thread
From: Boaz Harrosh @ 2012-02-02  9:22 UTC (permalink / raw)
  To: Stefan Richter
  Cc: Andy Grover, Clemens Ladisch, Chris Boot, target-devel,
	linux1394-devel, linux-scsi, lkml

On 02/01/2012 11:41 PM, Stefan Richter wrote:
> On Feb 01 Andy Grover wrote:
>> You're saying the sbp2 protocol can theoretically be used other places
>> besides firewire? I'd say put it all in the fabric module for now.
> 
> While SBP-2 is explicitly specified for IEEE 1394 a.k.a. FireWire only,
> it could be used on any bus architecture which implements IEEE 1212
> "Control and Status Registers (CSR) Architecture for Microcomputer
> Buses".  But IEEE 1394 a.k.a. FireWire is nowadays the only remaining IEEE
> 1212 implementation, as far as I know.
> 
> On the other hand, the transport protocol SBP-2 can be used to encapsulate
> various protocols besides SCSI.  A long time ago I heard that there were
> SBP-2 printers that weren't SCSI printers, but I may have confused
> something.
> 

Hmm Interesting. So what do the other FireWire protocols use, like
networking, DV video, audio? they have yet another encapsulating transport
other than SBP-2? What a mess

> The current version of the protocol, SBP-3 which extends SBP-2
> in an upwards compatible way, has been developed specifically in
> order to transport AV/C command sets.  (AV/C is a set of specifications
> from the 1394 Trade Association that build on top of IEC 61883 "Consumer
> audio/video equipment - Digital interface" and is used for camcorders,
> audio interfaces, studio-grade video equipment, TV set top boxes etc.)
> But I am not aware of any existing SBP-3 target or SBP-3 initiator which
> actually implements AV/C.
> 
> So in short,
>   - SBP-2/3 is only used on the FireWire bus.
>   - Potentially there could be SBP-2/3 targets or initiators that
>     implement something else than SCSI.  But stock SBP-2/3 initiator
>     drivers of popular OSs are SCSI initiators, and non-SCSI SBP-2/3
>     targets are extremely rare or don't exist actually.

Thanks that was informative
I'll have a deeper look

Boaz

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
@ 2012-02-02  9:22         ` Boaz Harrosh
  0 siblings, 0 replies; 104+ messages in thread
From: Boaz Harrosh @ 2012-02-02  9:22 UTC (permalink / raw)
  To: Stefan Richter
  Cc: Andy Grover, linux-scsi, lkml, target-devel, linux1394-devel

On 02/01/2012 11:41 PM, Stefan Richter wrote:
> On Feb 01 Andy Grover wrote:
>> You're saying the sbp2 protocol can theoretically be used other places
>> besides firewire? I'd say put it all in the fabric module for now.
> 
> While SBP-2 is explicitly specified for IEEE 1394 a.k.a. FireWire only,
> it could be used on any bus architecture which implements IEEE 1212
> "Control and Status Registers (CSR) Architecture for Microcomputer
> Buses".  But IEEE 1394 a.k.a. FireWire is nowadays the only remaining IEEE
> 1212 implementation, as far as I know.
> 
> On the other hand, the transport protocol SBP-2 can be used to encapsulate
> various protocols besides SCSI.  A long time ago I heard that there were
> SBP-2 printers that weren't SCSI printers, but I may have confused
> something.
> 

Hmm Interesting. So what do the other FireWire protocols use, like
networking, DV video, audio? they have yet another encapsulating transport
other than SBP-2? What a mess

> The current version of the protocol, SBP-3 which extends SBP-2
> in an upwards compatible way, has been developed specifically in
> order to transport AV/C command sets.  (AV/C is a set of specifications
> from the 1394 Trade Association that build on top of IEC 61883 "Consumer
> audio/video equipment - Digital interface" and is used for camcorders,
> audio interfaces, studio-grade video equipment, TV set top boxes etc.)
> But I am not aware of any existing SBP-3 target or SBP-3 initiator which
> actually implements AV/C.
> 
> So in short,
>   - SBP-2/3 is only used on the FireWire bus.
>   - Potentially there could be SBP-2/3 targets or initiators that
>     implement something else than SCSI.  But stock SBP-2/3 initiator
>     drivers of popular OSs are SCSI initiators, and non-SCSI SBP-2/3
>     targets are extremely rare or don't exist actually.

Thanks that was informative
I'll have a deeper look

Boaz

------------------------------------------------------------------------------
Keep Your Developer Skills Current with LearnDevNow!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-d2d

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-02  9:22         ` Boaz Harrosh
@ 2012-02-02 10:09           ` Clemens Ladisch
  -1 siblings, 0 replies; 104+ messages in thread
From: Clemens Ladisch @ 2012-02-02 10:09 UTC (permalink / raw)
  To: Boaz Harrosh
  Cc: Stefan Richter, Andy Grover, Chris Boot, target-devel,
	linux1394-devel, linux-scsi, lkml

Boaz Harrosh wrote:
> [...] So what do the other FireWire protocols use, like networking,
> DV video, audio?

Their own standard or non-standard mechanism.

> they have yet another encapsulating transport other than SBP-2?

These other devices require isochronous or broadcast transfers, which
SBP-2/3 does not handle well or at all.  It might be possible to use
SBP-3 for control commands (which is exactly what SBP-3's AV/C support
is), but using it would not bring any worthwhile benefits over existing
transports, and would just introduce incompatibilities with all previous
soft- and hardware.


Regards,
Clemens

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
@ 2012-02-02 10:09           ` Clemens Ladisch
  0 siblings, 0 replies; 104+ messages in thread
From: Clemens Ladisch @ 2012-02-02 10:09 UTC (permalink / raw)
  To: Boaz Harrosh
  Cc: linux1394-devel, linux-scsi, lkml, Stefan Richter, Andy Grover,
	target-devel

Boaz Harrosh wrote:
> [...] So what do the other FireWire protocols use, like networking,
> DV video, audio?

Their own standard or non-standard mechanism.

> they have yet another encapsulating transport other than SBP-2?

These other devices require isochronous or broadcast transfers, which
SBP-2/3 does not handle well or at all.  It might be possible to use
SBP-3 for control commands (which is exactly what SBP-3's AV/C support
is), but using it would not bring any worthwhile benefits over existing
transports, and would just introduce incompatibilities with all previous
soft- and hardware.


Regards,
Clemens

------------------------------------------------------------------------------
Keep Your Developer Skills Current with LearnDevNow!
The most comprehensive online learning library for Microsoft developers
is just $99.99! Visual Studio, SharePoint, SQL - plus HTML5, CSS3, MVC3,
Metro Style Apps, more. Free future releases when you subscribe now!
http://p.sf.net/sfu/learndevnow-d2d

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-02 10:09           ` Clemens Ladisch
  (?)
@ 2012-02-06 13:13           ` Chris Boot
  2012-02-06 14:43             ` Clemens Ladisch
  -1 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-06 13:13 UTC (permalink / raw)
  To: target-devel, linux1394-devel
  Cc: Clemens Ladisch, Boaz Harrosh, Stefan Richter, Andy Grover,
	linux-scsi, lkml

Hi folks,

I've been forging ahead in the last few days with my target code and 
have got to a point where it appears to work fairly well and now needs 
some real testing and ideally some initial review.

So far I've tested that I can export LUNs to Linux and Mac OS X machines 
and they can read/write data without issues as you might expect. I've 
even installed Mac OS X onto an exported LUN and booted from it on an 
old PowerBook without issue.

You can pull the code from:
git://github.com/bootc/Linux-SBP-2-Target.git

Or use GitHub to have a look etc...:
https://github.com/bootc/Linux-SBP-2-Target

I used the following script to set up a LUN on the target:

modprobe firewire-sbp-target
mkdir /sys/kernel/config/target/sbp
mkdir /sys/kernel/config/target/sbp/test
mkdir /sys/kernel/config/target/sbp/test/unit_0
mkdir /sys/kernel/config/target/sbp/test/unit_0/lun/lun_0
ln -s /sys/kernel/config/target/core/iblock_0/test 
/sys/kernel/config/target/sbp/test/unit_0/lun/lun_0/test
echo 1 > /sys/kernel/config/target/sbp/test/unit_0/enable

Please note that you can't then disable a unit until all the targets are 
logged-out. For Linux this usually means 'rmmod firewire_sbp2'. This is 
one of the first things I'd like to fix but I'm not entirely sure how to 
go about it yet.

Thanks,
Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-06 13:13           ` Chris Boot
@ 2012-02-06 14:43             ` Clemens Ladisch
  2012-02-06 14:51               ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Clemens Ladisch @ 2012-02-06 14:43 UTC (permalink / raw)
  To: Chris Boot
  Cc: target-devel, linux1394-devel, Boaz Harrosh, Stefan Richter,
	Andy Grover, linux-scsi, lkml

Chris Boot wrote:
> You can pull the code from:
> git://github.com/bootc/Linux-SBP-2-Target.git

The TODO file says:
> * Update Juju so we can get the speed in the fw_address_handler callback

What is the speed needed for?

SBP-2 says:
| The target shall issue data transfer requests with a speed equal to
| that specified by the spd field in the ORB.

SBP-3 says:
| The target shall issue data transfer requests with a speed equal to
| that specified by the controlling spd field, whether in the ORB or in
| a node selector in an associated page table.

> Please note that you can't then disable a unit until all the targets
> are logged-out. For Linux this usually means 'rmmod firewire_sbp2'.

That driver should not, by default, log into targets on its own node.


Regards,
Clemens

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-06 14:43             ` Clemens Ladisch
@ 2012-02-06 14:51               ` Chris Boot
  2012-02-06 20:26                 ` Stefan Richter
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-06 14:51 UTC (permalink / raw)
  To: Clemens Ladisch
  Cc: target-devel, linux1394-devel, Boaz Harrosh, Stefan Richter,
	Andy Grover, linux-scsi, lkml

On 06/02/2012 14:43, Clemens Ladisch wrote:
> Chris Boot wrote:
>> You can pull the code from:
>> git://github.com/bootc/Linux-SBP-2-Target.git
>
> The TODO file says:
>> * Update Juju so we can get the speed in the fw_address_handler callback
>
> What is the speed needed for?

"The speed at which the block write request to the MANAGEMENT_AGENT 
register is received shall determine the speed used by the target for 
all subsequent requests to read the initiator’s configuration ROM, fetch 
ORB’s from initiator memory or store status at the initiator’s 
status_FIFO. Command block ORB’s separately specify the speed for 
requests addressed to the data buffer or page table."

(T10/1155D Revision 4 page 53/54)

> SBP-2 says:
> | The target shall issue data transfer requests with a speed equal to
> | that specified by the spd field in the ORB.
>
> SBP-3 says:
> | The target shall issue data transfer requests with a speed equal to
> | that specified by the controlling spd field, whether in the ORB or in
> | a node selector in an associated page table.

>> Please note that you can't then disable a unit until all the targets
>> are logged-out. For Linux this usually means 'rmmod firewire_sbp2'.
>
> That driver should not, by default, log into targets on its own node.

It still tries to and never appears to give up, so this needs 
blacklisting on the target system until firewire_sbp2 is changed. It's 
harmless other than filling up the kernel log with error messages.

What I meant, however, is if you connect to the target from a separate 
Linux system you will be unable to disable the unit on the target system 
until the _initiator_ logs out. You can do this on the initiator by 
unloading the module, which sends a logout request to the target.

HTH,
Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-06 14:51               ` Chris Boot
@ 2012-02-06 20:26                 ` Stefan Richter
  2012-02-06 22:28                   ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-06 20:26 UTC (permalink / raw)
  To: Chris Boot
  Cc: Clemens Ladisch, target-devel, linux1394-devel, Boaz Harrosh,
	Andy Grover, linux-scsi, lkml

On Feb 06 Chris Boot wrote:
> On 06/02/2012 14:43, Clemens Ladisch wrote:
> > Chris Boot wrote:
> >> You can pull the code from:
> >> git://github.com/bootc/Linux-SBP-2-Target.git
> >
> > The TODO file says:
> >> * Update Juju so we can get the speed in the fw_address_handler callback
> >
> > What is the speed needed for?
> 
> "The speed at which the block write request to the MANAGEMENT_AGENT 
> register is received shall determine the speed used by the target for 
> all subsequent requests to read the initiator’s configuration ROM, fetch 
> ORB’s from initiator memory or store status at the initiator’s 
> status_FIFO. Command block ORB’s separately specify the speed for 
> requests addressed to the data buffer or page table."
> 
> (T10/1155D Revision 4 page 53/54)

I guess it is not too hard to add this to the AR-req handler.  On the
other hand, I see little reason to follow the SBP-2 spec to the letter
here.  The target driver could just use the maximum speed that the core
figured out.  On the other hand, this requires of course
  - the target to wait for core to finish scanning an initiator,
  - the core to offer an API to look up an fw_device by a
    card--generation--nodeID tuple.

The intention of the spec is IMO clearly to enable target implementations
that do not need to implement topology scanning.  I have a hard time to
think of a valid scenario where an initiator needs to be able to steer a
target towards a lower wire speed than what the participating links and
PHYs actually support.

> > SBP-2 says:
> > | The target shall issue data transfer requests with a speed equal to
> > | that specified by the spd field in the ORB.
> >
> > SBP-3 says:
> > | The target shall issue data transfer requests with a speed equal to
> > | that specified by the controlling spd field, whether in the ORB or in
> > | a node selector in an associated page table.

Clemens, the speed used in data transfers can be different from the speed
to be used to read the initiator's Config ROM/ fetch ORBs/ write status,
because data buffers and page tables can reside on a third node.  (In
practice they reside always on the initiator node, but per spec they
don't have to.)

Again, IMO the target driver could ignore this other speed too and just
use the speed which firewire-core figured out.  But on the other hand,
this would require an fw_device lookup, given card--generation--nodeID; so
using the speed code given in the ORB is much simpler.

Side note:  Like with the speed, the max_payload given in the ORB may be
different from that in the initiator's bus information block, simply
because the data buffers and page tables may reside on a third node with a
different packet payload limit.  Again, just using the max_payload given
in the ORB makes for the easiest implementation (and follows the spec to
the letter).

> >> Please note that you can't then disable a unit until all the targets
> >> are logged-out. For Linux this usually means 'rmmod firewire_sbp2'.
> >
> > That driver should not, by default, log into targets on its own node.
> 
> It still tries to and never appears to give up, so this needs 
> blacklisting on the target system until firewire_sbp2 is changed. It's 
> harmless other than filling up the kernel log with error messages.
> 
> What I meant, however, is if you connect to the target from a separate 
> Linux system you will be unable to disable the unit on the target system 
> until the _initiator_ logs out. You can do this on the initiator by 
> unloading the module, which sends a logout request to the target.

Another way to log out is
# echo "fw4.0" > /sys/bus/firewire/drivers/*sbp2/unbind

(I will post a patch soon which renames this directory from sbp2 to
firewire_sbp2, as a side effect of a logging related change.)
-- 
Stefan Richter
-=====-===-- --=- --==-
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-06 20:26                 ` Stefan Richter
@ 2012-02-06 22:28                   ` Chris Boot
  2012-02-06 23:00                     ` Julian Calaby
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-06 22:28 UTC (permalink / raw)
  To: Stefan Richter
  Cc: Clemens Ladisch, target-devel, linux1394-devel, Boaz Harrosh,
	Andy Grover, linux-scsi, lkml

On 6 Feb 2012, at 20:26, Stefan Richter wrote:

> On Feb 06 Chris Boot wrote:
>> On 06/02/2012 14:43, Clemens Ladisch wrote:
>>> Chris Boot wrote:
>>>> You can pull the code from:
>>>> git://github.com/bootc/Linux-SBP-2-Target.git
>>> 
>>> The TODO file says:
>>>> * Update Juju so we can get the speed in the fw_address_handler callback
>>> 
>>> What is the speed needed for?
>> 
>> "The speed at which the block write request to the MANAGEMENT_AGENT 
>> register is received shall determine the speed used by the target for 
>> all subsequent requests to read the initiator’s configuration ROM, fetch 
>> ORB’s from initiator memory or store status at the initiator’s 
>> status_FIFO. Command block ORB’s separately specify the speed for 
>> requests addressed to the data buffer or page table."
>> 
>> (T10/1155D Revision 4 page 53/54)
> 
> I guess it is not too hard to add this to the AR-req handler.  On the
> other hand, I see little reason to follow the SBP-2 spec to the letter
> here.  The target driver could just use the maximum speed that the core
> figured out.  On the other hand, this requires of course
>  - the target to wait for core to finish scanning an initiator,
>  - the core to offer an API to look up an fw_device by a
>    card--generation--nodeID tuple.
> 
> The intention of the spec is IMO clearly to enable target implementations
> that do not need to implement topology scanning.  I have a hard time to
> think of a valid scenario where an initiator needs to be able to steer a
> target towards a lower wire speed than what the participating links and
> PHYs actually support.

The only thing stopping me from getting the speed is the fact that struct fw_request is opaque. The value is easily available from request->response.speed and I kind of do that already in a very hackish way. I've sent a separate patch which adds a function that can be used to access that one value.

Waiting until the bus scan is complete isn't actually that great as I see the first LOGIN requests often before the fw_node is seen at all. I'd have to turn away the requester and hope they try again. I'm fairly sure my little tweak in my patch is a simple enough solution.

>>> SBP-2 says:
>>> | The target shall issue data transfer requests with a speed equal to
>>> | that specified by the spd field in the ORB.
>>> 
>>> SBP-3 says:
>>> | The target shall issue data transfer requests with a speed equal to
>>> | that specified by the controlling spd field, whether in the ORB or in
>>> | a node selector in an associated page table.
> 
> Clemens, the speed used in data transfers can be different from the speed
> to be used to read the initiator's Config ROM/ fetch ORBs/ write status,
> because data buffers and page tables can reside on a third node.  (In
> practice they reside always on the initiator node, but per spec they
> don't have to.)
> 
> Again, IMO the target driver could ignore this other speed too and just
> use the speed which firewire-core figured out.  But on the other hand,
> this would require an fw_device lookup, given card--generation--nodeID; so
> using the speed code given in the ORB is much simpler.
> 
> Side note:  Like with the speed, the max_payload given in the ORB may be
> different from that in the initiator's bus information block, simply
> because the data buffers and page tables may reside on a third node with a
> different packet payload limit.  Again, just using the max_payload given
> in the ORB makes for the easiest implementation (and follows the spec to
> the letter).

Hmm yes so far I've ignored the fact that the data and page tables can be on a different node. I should add that to the TODO fairly low down :-)

>>>> Please note that you can't then disable a unit until all the targets
>>>> are logged-out. For Linux this usually means 'rmmod firewire_sbp2'.
>>> 
>>> That driver should not, by default, log into targets on its own node.
>> 
>> It still tries to and never appears to give up, so this needs 
>> blacklisting on the target system until firewire_sbp2 is changed. It's 
>> harmless other than filling up the kernel log with error messages.
>> 
>> What I meant, however, is if you connect to the target from a separate 
>> Linux system you will be unable to disable the unit on the target system 
>> until the _initiator_ logs out. You can do this on the initiator by 
>> unloading the module, which sends a logout request to the target.
> 
> Another way to log out is
> # echo "fw4.0" > /sys/bus/firewire/drivers/*sbp2/unbind
> 
> (I will post a patch soon which renames this directory from sbp2 to
> firewire_sbp2, as a side effect of a logging related change.)

Good to know, thanks!

HTH,
Chris

-- 
Chris Boot
bootc@bootc.net


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-06 22:28                   ` Chris Boot
@ 2012-02-06 23:00                     ` Julian Calaby
  2012-02-06 23:09                       ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Julian Calaby @ 2012-02-06 23:00 UTC (permalink / raw)
  To: Chris Boot
  Cc: Stefan Richter, Clemens Ladisch, target-devel, linux1394-devel,
	Boaz Harrosh, Andy Grover, linux-scsi, lkml

Hi,

On Tue, Feb 7, 2012 at 09:28, Chris Boot <bootc@bootc.net> wrote:
> On 6 Feb 2012, at 20:26, Stefan Richter wrote:
>
>> On Feb 06 Chris Boot wrote:
>>> On 06/02/2012 14:43, Clemens Ladisch wrote:
>>>> Chris Boot wrote:
>>>>> You can pull the code from:
>>>>> git://github.com/bootc/Linux-SBP-2-Target.git
>>>>
>>>> The TODO file says:
>>>>> * Update Juju so we can get the speed in the fw_address_handler callback
>>>>
>>>> What is the speed needed for?
>>>
>>> "The speed at which the block write request to the MANAGEMENT_AGENT
>>> register is received shall determine the speed used by the target for
>>> all subsequent requests to read the initiator’s configuration ROM, fetch
>>> ORB’s from initiator memory or store status at the initiator’s
>>> status_FIFO. Command block ORB’s separately specify the speed for
>>> requests addressed to the data buffer or page table."
>>>
>>> (T10/1155D Revision 4 page 53/54)
>>
>> I guess it is not too hard to add this to the AR-req handler.  On the
>> other hand, I see little reason to follow the SBP-2 spec to the letter
>> here.  The target driver could just use the maximum speed that the core
>> figured out.  On the other hand, this requires of course
>>  - the target to wait for core to finish scanning an initiator,
>>  - the core to offer an API to look up an fw_device by a
>>    card--generation--nodeID tuple.
>>
>> The intention of the spec is IMO clearly to enable target implementations
>> that do not need to implement topology scanning.  I have a hard time to
>> think of a valid scenario where an initiator needs to be able to steer a
>> target towards a lower wire speed than what the participating links and
>> PHYs actually support.
>
> The only thing stopping me from getting the speed is the fact that struct fw_request is opaque. The value is easily available from request->response.speed and I kind of do that already in a very hackish way. I've sent a separate patch which adds a function that can be used to access that one value.
>
> Waiting until the bus scan is complete isn't actually that great as I see the first LOGIN requests often before the fw_node is seen at all. I'd have to turn away the requester and hope they try again. I'm fairly sure my little tweak in my patch is a simple enough solution.

Stupid question: Could you use a completion queue or something
equivalent to wait until you have seen the fw_node, *then* process the
LOGIN request?

Thanks,

-- 
Julian Calaby

Email: julian.calaby@gmail.com
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-06 23:00                     ` Julian Calaby
@ 2012-02-06 23:09                       ` Chris Boot
  2012-02-07  7:38                         ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-06 23:09 UTC (permalink / raw)
  To: Julian Calaby
  Cc: Stefan Richter, Clemens Ladisch, target-devel, linux1394-devel,
	Boaz Harrosh, Andy Grover, linux-scsi, lkml


On 6 Feb 2012, at 23:00, Julian Calaby wrote:

> Hi,
> 
> On Tue, Feb 7, 2012 at 09:28, Chris Boot <bootc@bootc.net> wrote:
>> On 6 Feb 2012, at 20:26, Stefan Richter wrote:
>> 
>>> On Feb 06 Chris Boot wrote:
>>>> On 06/02/2012 14:43, Clemens Ladisch wrote:
>>>>> Chris Boot wrote:
>>>>>> You can pull the code from:
>>>>>> git://github.com/bootc/Linux-SBP-2-Target.git
>>>>> 
>>>>> The TODO file says:
>>>>>> * Update Juju so we can get the speed in the fw_address_handler callback
>>>>> 
>>>>> What is the speed needed for?
>>>> 
>>>> "The speed at which the block write request to the MANAGEMENT_AGENT
>>>> register is received shall determine the speed used by the target for
>>>> all subsequent requests to read the initiator’s configuration ROM, fetch
>>>> ORB’s from initiator memory or store status at the initiator’s
>>>> status_FIFO. Command block ORB’s separately specify the speed for
>>>> requests addressed to the data buffer or page table."
>>>> 
>>>> (T10/1155D Revision 4 page 53/54)
>>> 
>>> I guess it is not too hard to add this to the AR-req handler.  On the
>>> other hand, I see little reason to follow the SBP-2 spec to the letter
>>> here.  The target driver could just use the maximum speed that the core
>>> figured out.  On the other hand, this requires of course
>>>  - the target to wait for core to finish scanning an initiator,
>>>  - the core to offer an API to look up an fw_device by a
>>>    card--generation--nodeID tuple.
>>> 
>>> The intention of the spec is IMO clearly to enable target implementations
>>> that do not need to implement topology scanning.  I have a hard time to
>>> think of a valid scenario where an initiator needs to be able to steer a
>>> target towards a lower wire speed than what the participating links and
>>> PHYs actually support.
>> 
>> The only thing stopping me from getting the speed is the fact that struct fw_request is opaque. The value is easily available from request->response.speed and I kind of do that already in a very hackish way. I've sent a separate patch which adds a function that can be used to access that one value.
>> 
>> Waiting until the bus scan is complete isn't actually that great as I see the first LOGIN requests often before the fw_node is seen at all. I'd have to turn away the requester and hope they try again. I'm fairly sure my little tweak in my patch is a simple enough solution.
> 
> Stupid question: Could you use a completion queue or something
> equivalent to wait until you have seen the fw_node, *then* process the
> LOGIN request?

The fw_address_handler callback is called in interrupt context, and I can't sleep from within there. As far as I'm aware I must call fw_send_response() from within the callback and can't defer that until I've scheduled something on a work queue. Please correct me if I'm wrong though, as that might be useful anyway.

Chris

-- 
Chris Boot
bootc@bootc.net


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-06 23:09                       ` Chris Boot
@ 2012-02-07  7:38                         ` Chris Boot
  2012-02-07 10:06                           ` Julian Calaby
  2012-02-07 19:17                           ` Stefan Richter
  0 siblings, 2 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-07  7:38 UTC (permalink / raw)
  To: Julian Calaby
  Cc: Stefan Richter, Clemens Ladisch, target-devel, linux1394-devel,
	Boaz Harrosh, Andy Grover, linux-scsi, lkml

On 06/02/2012 23:09, Chris Boot wrote:
>
> On 6 Feb 2012, at 23:00, Julian Calaby wrote:
>
>> Hi,
>>
>> On Tue, Feb 7, 2012 at 09:28, Chris Boot<bootc@bootc.net>  wrote:
>>> On 6 Feb 2012, at 20:26, Stefan Richter wrote:
>>>
>>>> On Feb 06 Chris Boot wrote:
>>>>> On 06/02/2012 14:43, Clemens Ladisch wrote:
>>>>>> Chris Boot wrote:
>>>>>>> You can pull the code from:
>>>>>>> git://github.com/bootc/Linux-SBP-2-Target.git
>>>>>>
>>>>>> The TODO file says:
>>>>>>> * Update Juju so we can get the speed in the fw_address_handler callback
>>>>>>
>>>>>> What is the speed needed for?
>>>>>
>>>>> "The speed at which the block write request to the MANAGEMENT_AGENT
>>>>> register is received shall determine the speed used by the target for
>>>>> all subsequent requests to read the initiator’s configuration ROM, fetch
>>>>> ORB’s from initiator memory or store status at the initiator’s
>>>>> status_FIFO. Command block ORB’s separately specify the speed for
>>>>> requests addressed to the data buffer or page table."
>>>>>
>>>>> (T10/1155D Revision 4 page 53/54)
>>>>
>>>> I guess it is not too hard to add this to the AR-req handler.  On the
>>>> other hand, I see little reason to follow the SBP-2 spec to the letter
>>>> here.  The target driver could just use the maximum speed that the core
>>>> figured out.  On the other hand, this requires of course
>>>>   - the target to wait for core to finish scanning an initiator,
>>>>   - the core to offer an API to look up an fw_device by a
>>>>     card--generation--nodeID tuple.
>>>>
>>>> The intention of the spec is IMO clearly to enable target implementations
>>>> that do not need to implement topology scanning.  I have a hard time to
>>>> think of a valid scenario where an initiator needs to be able to steer a
>>>> target towards a lower wire speed than what the participating links and
>>>> PHYs actually support.
>>>
>>> The only thing stopping me from getting the speed is the fact that struct fw_request is opaque. The value is easily available from request->response.speed and I kind of do that already in a very hackish way. I've sent a separate patch which adds a function that can be used to access that one value.
>>>
>>> Waiting until the bus scan is complete isn't actually that great as I see the first LOGIN requests often before the fw_node is seen at all. I'd have to turn away the requester and hope they try again. I'm fairly sure my little tweak in my patch is a simple enough solution.
>>
>> Stupid question: Could you use a completion queue or something
>> equivalent to wait until you have seen the fw_node, *then* process the
>> LOGIN request?
>
> The fw_address_handler callback is called in interrupt context, and I can't sleep from within there. As far as I'm aware I must call fw_send_response() from within the callback and can't defer that until I've scheduled something on a work queue. Please correct me if I'm wrong though, as that might be useful anyway.

Hmm sorry I've thought about this overnight and clearly I was talking 
rubbish. Yes, I need to reply in the fw_address_handler but all I tend 
to do in there is schedule a task to the the main part of the work 
anyway. As most of the operations require fetching an ORB from the 
initiator I have to do this from user context.

So it's possible I could do this by waiting in my scheduled work 
function until the fw_node is available and get the speed from that - 
but that seems like an inordinate amount of work when I can follow the 
standard and do it really easily by pulling it out of the fw_request.

Chris

-- 
Chris Boot
bootc@bootc.net
Tel: 01271 414100

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-07  7:38                         ` Chris Boot
@ 2012-02-07 10:06                           ` Julian Calaby
  2012-02-07 19:17                           ` Stefan Richter
  1 sibling, 0 replies; 104+ messages in thread
From: Julian Calaby @ 2012-02-07 10:06 UTC (permalink / raw)
  To: Chris Boot
  Cc: Stefan Richter, Clemens Ladisch, target-devel, linux1394-devel,
	Boaz Harrosh, Andy Grover, linux-scsi, lkml

Hi,

On Tue, Feb 7, 2012 at 18:38, Chris Boot <bootc@bootc.net> wrote:
> On 06/02/2012 23:09, Chris Boot wrote:
>>
>>
>> On 6 Feb 2012, at 23:00, Julian Calaby wrote:
>>
>>> Hi,
>>>
>>> On Tue, Feb 7, 2012 at 09:28, Chris Boot<bootc@bootc.net>  wrote:
>>>>
>>>> On 6 Feb 2012, at 20:26, Stefan Richter wrote:
>>>>
>>>>> On Feb 06 Chris Boot wrote:
>>>>>>
>>>>>> On 06/02/2012 14:43, Clemens Ladisch wrote:
>>>>>>>
>>>>>>> Chris Boot wrote:
>>>>>>>>
>>>>>>>> You can pull the code from:
>>>>>>>> git://github.com/bootc/Linux-SBP-2-Target.git
>>>>>>>
>>>>>>>
>>>>>>> The TODO file says:
>>>>>>>>
>>>>>>>> * Update Juju so we can get the speed in the fw_address_handler
>>>>>>>> callback
>>>>>>>
>>>>>>>
>>>>>>> What is the speed needed for?
>>>>>>
>>>>>>
>>>>>> "The speed at which the block write request to the MANAGEMENT_AGENT
>>>>>> register is received shall determine the speed used by the target for
>>>>>> all subsequent requests to read the initiator’s configuration ROM,
>>>>>> fetch
>>>>>> ORB’s from initiator memory or store status at the initiator’s
>>>>>> status_FIFO. Command block ORB’s separately specify the speed for
>>>>>> requests addressed to the data buffer or page table."
>>>>>>
>>>>>> (T10/1155D Revision 4 page 53/54)
>>>>>
>>>>>
>>>>> I guess it is not too hard to add this to the AR-req handler.  On the
>>>>> other hand, I see little reason to follow the SBP-2 spec to the letter
>>>>> here.  The target driver could just use the maximum speed that the core
>>>>> figured out.  On the other hand, this requires of course
>>>>>  - the target to wait for core to finish scanning an initiator,
>>>>>  - the core to offer an API to look up an fw_device by a
>>>>>    card--generation--nodeID tuple.
>>>>>
>>>>> The intention of the spec is IMO clearly to enable target
>>>>> implementations
>>>>> that do not need to implement topology scanning.  I have a hard time to
>>>>> think of a valid scenario where an initiator needs to be able to steer
>>>>> a
>>>>> target towards a lower wire speed than what the participating links and
>>>>> PHYs actually support.
>>>>
>>>>
>>>> The only thing stopping me from getting the speed is the fact that
>>>> struct fw_request is opaque. The value is easily available from
>>>> request->response.speed and I kind of do that already in a very hackish way.
>>>> I've sent a separate patch which adds a function that can be used to access
>>>> that one value.
>>>>
>>>> Waiting until the bus scan is complete isn't actually that great as I
>>>> see the first LOGIN requests often before the fw_node is seen at all. I'd
>>>> have to turn away the requester and hope they try again. I'm fairly sure my
>>>> little tweak in my patch is a simple enough solution.
>>>
>>>
>>> Stupid question: Could you use a completion queue or something
>>> equivalent to wait until you have seen the fw_node, *then* process the
>>> LOGIN request?
>>
>>
>> The fw_address_handler callback is called in interrupt context, and I
>> can't sleep from within there. As far as I'm aware I must call
>> fw_send_response() from within the callback and can't defer that until I've
>> scheduled something on a work queue. Please correct me if I'm wrong though,
>> as that might be useful anyway.
>
>
> Hmm sorry I've thought about this overnight and clearly I was talking
> rubbish. Yes, I need to reply in the fw_address_handler but all I tend to do
> in there is schedule a task to the the main part of the work anyway. As most
> of the operations require fetching an ORB from the initiator I have to do
> this from user context.
>
> So it's possible I could do this by waiting in my scheduled work function
> until the fw_node is available and get the speed from that - but that seems
> like an inordinate amount of work when I can follow the standard and do it
> really easily by pulling it out of the fw_request.

Fair enough, I assumed that there might have been some reason why you
wouldn't have it at that point, not just convention getting in the
way.

Thanks,

-- 
Julian Calaby

Email: julian.calaby@gmail.com
Profile: http://www.google.com/profiles/julian.calaby/
.Plan: http://sites.google.com/site/juliancalaby/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-07  7:38                         ` Chris Boot
  2012-02-07 10:06                           ` Julian Calaby
@ 2012-02-07 19:17                           ` Stefan Richter
  2012-02-07 19:53                             ` Chris Boot
  1 sibling, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-07 19:17 UTC (permalink / raw)
  To: Chris Boot
  Cc: Julian Calaby, Clemens Ladisch, target-devel, linux1394-devel,
	Boaz Harrosh, Andy Grover, linux-scsi, lkml

On Feb 07 Chris Boot wrote:
> On 06/02/2012 23:09, Chris Boot wrote:
> > On 6 Feb 2012, at 23:00, Julian Calaby wrote:
> >> On Tue, Feb 7, 2012 at 09:28, Chris Boot<bootc@bootc.net>  wrote:
> >>> Waiting until the bus scan is complete isn't actually that great
> >>> as I see the first LOGIN requests often before the fw_node is seen
> >>> at all. I'd have to turn away the requester and hope they try again.

An SBP-2 initiator should be prepared to retry its first login attempt if
it sent it shortly after a bus reset.  The target may still hold
reservations for previously loggend in initiators for up to reconnect_hold
+ 2 seconds after bus reset.

> >>> I'm fairly sure my little tweak in my patch is a simple enough
> >>> solution.

Yep.

> >> Stupid question: Could you use a completion queue or something
> >> equivalent to wait until you have seen the fw_node, *then* process the
> >> LOGIN request?
> >
> > The fw_address_handler callback is called in interrupt context, and
> > I can't sleep from within there. As far as I'm aware I must call
> > fw_send_response() from within the callback and can't defer that until
> > I've scheduled something on a work queue. Please correct me if I'm
> > wrong though, as that might be useful anyway.
> 
> Hmm sorry I've thought about this overnight and clearly I was talking 
> rubbish. Yes, I need to reply in the fw_address_handler but all I tend 
> to do in there is schedule a task to the the main part of the work 
> anyway. As most of the operations require fetching an ORB from the 
> initiator I have to do this from user context.

Technically there are two things to perform:

 1. Finish the inbound IEEE 1394 transaction to the management agent
    register by means of fw_send_response().  As far as I can tell, you
    don't have to do that in the address_callback().  But there is little
    reason not to.

    fw_send_response() ends the lifetime of an fw_request, so read the
    speed code before you respond.

 2. Finish the inbound SBP-2 transaction; here the login.  This and
    everything that leads up to it is definitely easiest to implement in
    a process context, e.g. workqueue item.
-- 
Stefan Richter
-=====-===-- --=- --===
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: FireWire/SBP2 Target mode
  2012-02-07 19:17                           ` Stefan Richter
@ 2012-02-07 19:53                             ` Chris Boot
  0 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-07 19:53 UTC (permalink / raw)
  To: Stefan Richter
  Cc: Julian Calaby, Clemens Ladisch, target-devel, linux1394-devel,
	Boaz Harrosh, Andy Grover, linux-scsi, lkml

On 07/02/2012 19:17, Stefan Richter wrote:
> On Feb 07 Chris Boot wrote:
>> On 06/02/2012 23:09, Chris Boot wrote:
>>> On 6 Feb 2012, at 23:00, Julian Calaby wrote:
>>>> Stupid question: Could you use a completion queue or something
>>>> equivalent to wait until you have seen the fw_node, *then* process the
>>>> LOGIN request?
>>>
>>> The fw_address_handler callback is called in interrupt context, and
>>> I can't sleep from within there. As far as I'm aware I must call
>>> fw_send_response() from within the callback and can't defer that until
>>> I've scheduled something on a work queue. Please correct me if I'm
>>> wrong though, as that might be useful anyway.
>>
>> Hmm sorry I've thought about this overnight and clearly I was talking
>> rubbish. Yes, I need to reply in the fw_address_handler but all I tend
>> to do in there is schedule a task to the the main part of the work
>> anyway. As most of the operations require fetching an ORB from the
>> initiator I have to do this from user context.
>
> Technically there are two things to perform:
>
>   1. Finish the inbound IEEE 1394 transaction to the management agent
>      register by means of fw_send_response().  As far as I can tell, you
>      don't have to do that in the address_callback().  But there is little
>      reason not to.
>
>      fw_send_response() ends the lifetime of an fw_request, so read the
>      speed code before you respond.
>
>   2. Finish the inbound SBP-2 transaction; here the login.  This and
>      everything that leads up to it is definitely easiest to implement in
>      a process context, e.g. workqueue item.

Yep I do exactly that - I save the speed then schedule_work() inside the 
address callback, then call fw_send_response() still within the 
callback. The work callback uses fw_run_transaction() to fetch the ORB 
and deal with it.

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target
  2011-08-17 14:51 ` Chris Boot
                   ` (2 preceding siblings ...)
  (?)
@ 2012-02-11 19:43 ` Chris Boot
  2012-02-11 19:44   ` [PATCH 01/13] firewire: Add function to get speed from opaque struct fw_request Chris Boot
                     ` (14 more replies)
  -1 siblings, 15 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:43 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr

Hi folks,

Well after lots of work I have a working and generally (at least I think)
sensible starting point for the FireWire target. It appears to work fine in all
the configurations I've tested it against, including Linux and Mac OS X
initiators.

This is not production ready code, and not ready for merging IMO. I know my
locking (or more the lack of it) leaves something to be desired, and I know my
use of atomics and memory barriers is wrong too. Performance is also a bit
meagre and I'm sure it can be improved substantially - I already have some
ideas for things that can be improved.

For testing, I use:

GUID=5254000b8f01e6f6
DIR_ID=abcdef

modprobe firewire-sbp-target
mkdir /sys/kernel/config/target/sbp
mkdir /sys/kernel/config/target/sbp/$GUID
mkdir /sys/kernel/config/target/sbp/$GUID/tpgt_1
mkdir /sys/kernel/config/target/sbp/$GUID/tpgt_1/lun/lun_0
ln -s /sys/kernel/config/target/core/iblock_0/sbptest /sys/kernel/config/target/sbp/$GUID/tpgt_1/lun/lun_0/sbptest
echo $DIR_ID > /sys/kernel/config/target/sbp/$GUID/tpgt_1/directory_id
echo 1 > /sys/kernel/config/target/sbp/$GUID/tpgt_1/enable

Setting the directory_id is optional and something I have only just added, but
it appears to work as planned.

Any and all comments much appreciated.

Thanks,
Chris

-- 
Chris Boot
bootc@bootc.net


^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH 01/13] firewire: Add function to get speed from opaque struct fw_request
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 02/13] firewire: Add EXPORT_SYMBOL_GPL(fw_card_release) Chris Boot
                     ` (13 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

Sometimes it's useful to know the FireWire speed of the request that has
just come in to a fw_address_handler callback. As struct fw_request is
opaque we can't peek inside to get the speed out of the struct fw_packet
that's just inside. For example, the SBP-2 spec says:

"The speed at which the block write request to the MANAGEMENT_AGENT
register is received shall determine the speed used by the target for
all subsequent requests to read the initiator’s configuration ROM, fetch
ORB’s from initiator memory or store status at the initiator’s
status_FIFO. Command block ORB’s separately specify the speed for
requests addressed to the data buffer or page table."

[ ANSI T10/1155D Revision 4 page 53/54 ]

Signed-off-by: Chris Boot <bootc@bootc.net>
Acked-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: Clemens Ladisch <clemens@ladisch.de>
---
 drivers/firewire/core-transaction.c |   16 ++++++++++++++++
 include/linux/firewire.h            |    1 +
 2 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 855ab3f..614f592 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -820,6 +820,22 @@ void fw_send_response(struct fw_card *card,
 }
 EXPORT_SYMBOL(fw_send_response);
 
+/**
+ * fw_get_request_speed() - Discover bus speed used for this request
+ * @request:	The struct fw_request from which to obtain the speed.
+ *
+ * In certain circumstances it's important to be able to obtain the speed at
+ * which a request was made to an address handler, for example when
+ * implementing an SBP-2 or SBP-3 target. This function inspects the response
+ * object to obtain the speed, which is copied from the request packet in
+ * allocate_request().
+ */
+int fw_get_request_speed(struct fw_request *request)
+{
+	return request->response.speed;
+}
+EXPORT_SYMBOL(fw_get_request_speed);
+
 static void handle_exclusive_region_request(struct fw_card *card,
 					    struct fw_packet *p,
 					    struct fw_request *request,
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 84ccf8e..f010307 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -340,6 +340,7 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
 void fw_core_remove_address_handler(struct fw_address_handler *handler);
 void fw_send_response(struct fw_card *card,
 		      struct fw_request *request, int rcode);
+int fw_get_request_speed(struct fw_request *request);
 void fw_send_request(struct fw_card *card, struct fw_transaction *t,
 		     int tcode, int destination_id, int generation, int speed,
 		     unsigned long long offset, void *payload, size_t length,
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 02/13] firewire: Add EXPORT_SYMBOL_GPL(fw_card_release)
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
  2012-02-11 19:44   ` [PATCH 01/13] firewire: Add function to get speed from opaque struct fw_request Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 03/13] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
                     ` (12 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

The firewire-sbp-target module requires this so it can keep a reference
to the fw_card object in order that it can fetch ORBs to execute and
read/write related data and status information.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/firewire/core-card.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 85661b0..42b180b 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -654,6 +654,7 @@ void fw_card_release(struct kref *kref)
 
 	complete(&card->done);
 }
+EXPORT_SYMBOL_GPL(fw_card_release);
 
 void fw_core_remove_card(struct fw_card *card)
 {
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 03/13] firewire-sbp-target: Add Kconfig, Makefile and TODO
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
  2012-02-11 19:44   ` [PATCH 01/13] firewire: Add function to get speed from opaque struct fw_request Chris Boot
  2012-02-11 19:44   ` [PATCH 02/13] firewire: Add EXPORT_SYMBOL_GPL(fw_card_release) Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-13 12:50     ` Nicholas A. Bellinger
  2012-02-11 19:44   ` [PATCH 04/13] firewire-sbp-target: Add sbp_base.h header Chris Boot
                     ` (11 subsequent siblings)
  14 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

The FireWire SBP-2 Target is a driver for using an IEEE-1394 connection
as a SCSI transport. This module uses the SCSI Target framework to
expose LUNs to other machines attached to a FireWire bus, in effect
acting as a FireWire hard disk similar to FireWire Target Disk mode on
older Apple computers.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/Kconfig  |   14 ++++++++++++++
 drivers/target/sbp/Makefile |   13 +++++++++++++
 drivers/target/sbp/TODO     |    7 +++++++
 3 files changed, 34 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/Kconfig
 create mode 100644 drivers/target/sbp/Makefile
 create mode 100644 drivers/target/sbp/TODO

diff --git a/drivers/target/sbp/Kconfig b/drivers/target/sbp/Kconfig
new file mode 100644
index 0000000..8544010
--- /dev/null
+++ b/drivers/target/sbp/Kconfig
@@ -0,0 +1,14 @@
+
+config FIREWIRE_SBP_TARGET
+	tristate "FireWire SBP-2 fabric module"
+	depends on TARGET_CORE && CONFIGFS_FS && FIREWIRE && EXPERIMENTAL
+	default n
+	help
+	  Say Y or M here to enable SCSI target functionality over FireWire.
+	  This enables you to expose SCSI devices to other nodes on the FireWire
+	  bus, for example hard disks. Similar to FireWire Target Disk mode on
+	  older Apple computers.
+
+	  To compile this driver as a module, say M here: The module will be
+	  called firewire-sbp-target.
+
diff --git a/drivers/target/sbp/Makefile b/drivers/target/sbp/Makefile
new file mode 100644
index 0000000..3a3e155
--- /dev/null
+++ b/drivers/target/sbp/Makefile
@@ -0,0 +1,13 @@
+
+firewire-sbp-target-y += \
+	sbp_configfs.o \
+	sbp_fabric.o \
+	sbp_login.o \
+	sbp_management_agent.o \
+	sbp_proto.o \
+	sbp_scsi_cmnd.o \
+	sbp_target_agent.o \
+	sbp_util.o
+
+obj-$(CONFIG_FIREWIRE_SBP_TARGET) += firewire-sbp-target.o
+
diff --git a/drivers/target/sbp/TODO b/drivers/target/sbp/TODO
new file mode 100644
index 0000000..eaec1c9
--- /dev/null
+++ b/drivers/target/sbp/TODO
@@ -0,0 +1,7 @@
+* Force-terminate sessions when disabling targets
+* Ability to have several SCSI commands in-flight (TCQ?)
+* Retry failed FireWire transactions a few times with exponential backoff
+* Take into account the page_size field for transfers and/or page tables
+* Handle descriptor format sense data
+* Implement QUERY LOGINS management ORB
+* Implement TASK MANAGEMENT functionality
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 04/13] firewire-sbp-target: Add sbp_base.h header
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (2 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 03/13] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 05/13] firewire-sbp-target: Add sbp_configfs.c Chris Boot
                     ` (10 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This header contains defines and structures that are common to many of
the modules of the target code. This includes SBP-2 protocol structures
and constants as well as a few structs for setting up the target, LUN
login information and session setup.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_base.h |  196 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 196 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_base.h

diff --git a/drivers/target/sbp/sbp_base.h b/drivers/target/sbp/sbp_base.h
new file mode 100644
index 0000000..629ae1a
--- /dev/null
+++ b/drivers/target/sbp/sbp_base.h
@@ -0,0 +1,196 @@
+
+#define SBP_VERSION  "v0.1"
+#define SBP_NAMELEN 32
+
+#define SBP_ORB_FETCH_SIZE	8
+
+#define MANAGEMENT_AGENT_STATE_IDLE	0
+#define MANAGEMENT_AGENT_STATE_BUSY	1
+
+#define ORB_NOTIFY(v)			(((v) >> 31) & 0x01)
+#define ORB_REQUEST_FORMAT(v)		(((v) >> 29) & 0x03)
+
+#define MANAGEMENT_ORB_FUNCTION(v)	(((v) >> 16) & 0x0f)
+
+#define MANAGEMENT_ORB_FUNCTION_LOGIN			0x0
+#define MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS		0x1
+#define MANAGEMENT_ORB_FUNCTION_RECONNECT		0x3
+#define MANAGEMENT_ORB_FUNCTION_SET_PASSWORD		0x4
+#define MANAGEMENT_ORB_FUNCTION_LOGOUT			0x7
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK		0xb
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET		0xc
+#define MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET	0xe
+#define MANAGEMENT_ORB_FUNCTION_TARGET_RESET		0xf
+
+#define LOGIN_ORB_EXCLUSIVE(v)		(((v) >> 28) &   0x01)
+#define LOGIN_ORB_RESERVED(v)		(((v) >> 24) &   0x0f)
+#define LOGIN_ORB_RECONNECT(v)		(((v) >> 20) &   0x0f)
+#define LOGIN_ORB_LUN(v)		(((v) >>  0) & 0xffff)
+#define LOGIN_ORB_PASSWORD_LENGTH(v)	(((v) >> 16) & 0xffff)
+#define LOGIN_ORB_RESPONSE_LENGTH(v)	(((v) >>  0) & 0xffff)
+
+#define RECONNECT_ORB_LOGIN_ID(v)	(((v) >>  0) & 0xffff)
+#define LOGOUT_ORB_LOGIN_ID(v)		(((v) >>  0) & 0xffff)
+
+#define CMDBLK_ORB_DIRECTION(v)		(((v) >> 27) &   0x01)
+#define CMDBLK_ORB_SPEED(v)		(((v) >> 24) &   0x07)
+#define CMDBLK_ORB_MAX_PAYLOAD(v)	(((v) >> 20) &   0x0f)
+#define CMDBLK_ORB_PG_TBL_PRESENT(v)	(((v) >> 19) &   0x01)
+#define CMDBLK_ORB_PG_SIZE(v)		(((v) >> 16) &   0x07)
+#define CMDBLK_ORB_DATA_SIZE(v)		(((v) >>  0) & 0xffff)
+
+#define STATUS_BLOCK_SRC(v)		(((v) &   0x03) << 30)
+#define STATUS_BLOCK_RESP(v)		(((v) &   0x03) << 28)
+#define STATUS_BLOCK_DEAD(v)		(((v) ? 1 : 0)  << 27)
+#define STATUS_BLOCK_LEN(v)		(((v) &   0x07) << 24)
+#define STATUS_BLOCK_SBP_STATUS(v)	(((v) &   0xff) << 16)
+#define STATUS_BLOCK_ORB_OFFSET_HIGH(v)	(((v) & 0xffff) <<  0)
+
+#define STATUS_SRC_ORB_CONTINUING	0
+#define STATUS_SRC_ORB_FINISHED		1
+#define STATUS_SRC_UNSOLICITED		2
+
+#define STATUS_RESP_REQUEST_COMPLETE	0
+#define STATUS_RESP_TRANSPORT_FAILURE	1
+#define STATUS_RESP_ILLEGAL_REQUEST	2
+#define STATUS_RESP_VENDOR_DEPENDENT	3
+
+#define SBP_STATUS_OK			0
+#define SBP_STATUS_REQ_TYPE_NOTSUPP	1
+#define SBP_STATUS_SPEED_NOTSUPP	2
+#define SBP_STATUS_PAGE_SIZE_NOTSUPP	3
+#define SBP_STATUS_ACCESS_DENIED	4
+#define SBP_STATUS_LUN_NOTSUPP		5
+#define SBP_STATUS_PAYLOAD_TOO_SMALL	6
+/* 7 is reserved */
+#define SBP_STATUS_RESOURCES_UNAVAIL	8
+#define SBP_STATUS_FUNCTION_REJECTED	9
+#define SBP_STATUS_LOGIN_ID_UNKNOWN	10
+#define SBP_STATUS_DUMMY_ORB_COMPLETE	11
+#define SBP_STATUS_REQUEST_ABORTED	12
+#define SBP_STATUS_UNSPECIFIED_ERROR	0xff
+
+#define AGENT_STATE_RESET	0
+#define AGENT_STATE_ACTIVE	1
+#define AGENT_STATE_SUSPENDED	2
+#define AGENT_STATE_DEAD	3
+
+struct sbp2_pointer {
+	__be32 high;
+	__be32 low;
+};
+
+struct sbp_command_block_orb {
+	struct sbp2_pointer next_orb;
+	struct sbp2_pointer data_descriptor;
+	__be32 misc;
+	u8 command_block[12];
+};
+
+struct sbp_page_table_entry {
+	__be16 segment_length;
+	__be16 segment_base_hi;
+	__be32 segment_base_lo;
+};
+
+struct sbp_management_orb {
+	struct sbp2_pointer ptr1;
+	struct sbp2_pointer ptr2;
+	__be32 misc;
+	__be32 length;
+	struct sbp2_pointer status_fifo;
+};
+
+struct sbp_status_block {
+	__be32 status;
+	__be32 orb_low;
+	u8 data[24];
+};
+
+struct sbp_login_response_block {
+	__be32 misc;
+	struct sbp2_pointer command_block_agent;
+	__be32 reconnect_hold;
+};
+
+struct sbp_login_descriptor {
+	struct sbp_session *sess;
+	struct list_head link;
+
+	struct se_lun *lun;
+
+	u64 status_fifo_addr;
+	int exclusive;
+	u16 login_id;
+	atomic_t unsolicited_status_enable;
+
+	struct sbp_target_agent *tgt_agt;
+};
+
+struct sbp_session {
+	struct se_session *se_sess;
+	struct list_head login_list;
+	struct delayed_work maint_work;
+
+	u64 guid; /* login_owner_EUI_64 */
+	int node_id; /* login_owner_ID */
+
+	struct fw_card *card;
+	int generation;
+	int speed;
+
+	int reconnect_hold;
+	u64 reconnect_expires;
+};
+
+struct sbp_nacl {
+	/* Initiator EUI-64 */
+	u64 guid;
+	/* ASCII formatted GUID for SBP Initiator port */
+	char iport_name[SBP_NAMELEN];
+	/* Returned by sbp_make_nodeacl() */
+	struct se_node_acl se_node_acl;
+};
+
+struct sbp_lun {
+	struct list_head link;
+	struct se_lun *se_lun;
+};
+
+struct sbp_tpg {
+	/* Target portal group tag for TCM */
+	u16 tport_tpgt;
+	/* Pointer back to sbp_tport */
+	struct sbp_tport *tport;
+	/* Returned by sbp_make_tpg() */
+	struct se_portal_group se_tpg;
+
+	struct list_head lun_list;
+};
+
+struct sbp_tport {
+	/* Target Unit Identifier (EUI-64) */
+	u64 guid;
+	/* Target port name */
+	char tport_name[SBP_NAMELEN];
+	/* Returned by sbp_make_tport() */
+	struct se_wwn tport_wwn;
+
+	struct sbp_tpg *tpg;
+
+	/* FireWire unit directory */
+	struct fw_descriptor unit_directory;
+
+	/* SBP Management Agent */
+	struct sbp_management_agent *mgt_agt;
+
+	/* Parameters */
+	int enable;
+	s32 directory_id;
+	int mgt_orb_timeout;
+	int max_reconnect_timeout;
+	int max_logins_per_lun;
+};
+
+extern struct target_fabric_configfs *sbp_fabric_configfs;
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 05/13] firewire-sbp-target: Add sbp_configfs.c
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (3 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 04/13] firewire-sbp-target: Add sbp_base.h header Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 06/13] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
                     ` (9 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This is used to glue the target framework's configfs code to the target
code, and what is used to create targets and link them to LUNs to
export. The code to create the FireWire unit directory to advertise
targets on the FireWire bus is also in here.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_configfs.c |  759 +++++++++++++++++++++++++++++++++++++
 1 files changed, 759 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_configfs.c

diff --git a/drivers/target/sbp/sbp_configfs.c b/drivers/target/sbp/sbp_configfs.c
new file mode 100644
index 0000000..530d1d7
--- /dev/null
+++ b/drivers/target/sbp/sbp_configfs.c
@@ -0,0 +1,759 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/firewire.h>
+
+#include <asm/unaligned.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_configfs.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/configfs_macros.h>
+
+#include "sbp_base.h"
+#include "sbp_fabric.h"
+#include "sbp_management_agent.h"
+#include "sbp_proto.h"
+
+/* Local pointer to allocated TCM configfs fabric module */
+struct target_fabric_configfs *sbp_fabric_configfs;
+
+static const u32 sbp_unit_directory_template[] = {
+	0x1200609e, /* unit_specifier_id: NCITS/T10 */
+	0x13010483, /* unit_sw_version: 1155D Rev 4 */
+	0x3800609e, /* command_set_specifier_id: NCITS/T10 */
+	0x390104d8, /* command_set: SPC-2 */
+	0x3b000000, /* command_set_revision: 0 */
+	0x3c000001, /* firmware_revision: 1 */
+};
+
+static int sbp_update_unit_directory(struct sbp_tport *tport)
+{
+	struct sbp_lun *lun;
+	int num_luns = 0, num_entries, idx = 0, mgt_agt_addr, ret;
+	u32 *data;
+
+	/* unregister existing descriptor */
+	if (tport->unit_directory.data) {
+		fw_core_remove_descriptor(&tport->unit_directory);
+		kfree(tport->unit_directory.data);
+		tport->unit_directory.data = NULL;
+	}
+
+	if (!tport->enable || !tport->tpg)
+		return 0;
+
+	/* count how many LUNs to publish */
+	list_for_each_entry(lun, &tport->tpg->lun_list, link)
+		num_luns++;
+
+	/*
+	 * Number of entries in the final unit directory:
+	 *  - all of those in the template
+	 *  - management_agent
+	 *  - unit_characteristics
+	 *  - reconnect_timeout
+	 *  - unit unique ID
+	 *  - one for each LUN
+	 *
+	 *  MUST NOT include leaf or sub-directory entries
+	 */
+	num_entries = ARRAY_SIZE(sbp_unit_directory_template) + 4 + num_luns;
+
+	if (tport->directory_id != -1)
+		num_entries++;
+
+	/* allocate num_entries + 4 for the header and unique ID leaf */
+	data = kcalloc((num_entries + 4), sizeof(u32), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* directory_length */
+	data[idx++] = num_entries << 16;
+
+	/* directory_id */
+	if (tport->directory_id != -1)
+		data[idx++] = (CSR_DIRECTORY_ID << 24) | tport->directory_id;
+
+	/* directory template */
+	memcpy(&data[idx], sbp_unit_directory_template,
+			sizeof(sbp_unit_directory_template));
+	idx += ARRAY_SIZE(sbp_unit_directory_template);
+
+	/* management_agent */
+	mgt_agt_addr = (tport->mgt_agt->handler.offset - CSR_REGISTER_BASE) / 4;
+	data[idx++] = 0x54000000 | (mgt_agt_addr & 0x00ffffff);
+
+	/* unit_characteristics */
+	data[idx++] = 0x3a000000 |
+		(((tport->mgt_orb_timeout * 2) << 8) & 0xff00) |
+		SBP_ORB_FETCH_SIZE;
+
+	/* reconnect_timeout */
+	data[idx++] = 0x3d000000 | (tport->max_reconnect_timeout & 0xffff);
+
+	/* unit unique ID (leaf is just after LUNs) */
+	data[idx++] = 0x8d000000 | (num_luns + 1);
+
+	/* LUNs */
+	list_for_each_entry(lun, &tport->tpg->lun_list, link) {
+		struct se_lun *se_lun = lun->se_lun;
+		struct se_device *dev = se_lun->lun_se_dev;
+		int type = dev->transport->get_device_type(dev);
+
+		/* logical_unit_number */
+		data[idx++] = 0x14000000 |
+			((type << 16) & 0x1f0000) |
+			(se_lun->unpacked_lun & 0xffff);
+	}
+
+	/* unit unique ID leaf */
+	data[idx++] = 2 << 16;
+	data[idx++] = tport->guid >> 32;
+	data[idx++] = tport->guid;
+
+	tport->unit_directory.length = idx;
+	tport->unit_directory.key = (CSR_DIRECTORY | CSR_UNIT) << 24;
+	tport->unit_directory.data = data;
+
+	ret = fw_core_add_descriptor(&tport->unit_directory);
+	if (ret < 0) {
+		kfree(tport->unit_directory.data);
+		tport->unit_directory.data = NULL;
+	}
+
+	return ret;
+}
+
+static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
+{
+	const char *cp;
+	char c, nibble;
+	int pos = 0, err;
+
+	*wwn = 0;
+	for (cp = name; cp < &name[SBP_NAMELEN - 1]; cp++) {
+		c = *cp;
+		if (c == '\n' && cp[1] == '\0')
+			continue;
+		if (c == '\0') {
+			err = 2;
+			if (pos != 16)
+				goto fail;
+			return cp - name;
+		}
+		err = 3;
+		if (isdigit(c))
+			nibble = c - '0';
+		else if (isxdigit(c) && (islower(c) || !strict))
+			nibble = tolower(c) - 'a' + 10;
+		else
+			goto fail;
+		*wwn = (*wwn << 4) | nibble;
+		pos++;
+	}
+	err = 4;
+fail:
+	printk(KERN_INFO "err %u len %zu pos %u\n",
+			err, cp - name, pos);
+	return -1;
+}
+
+static ssize_t sbp_format_wwn(char *buf, size_t len, u64 wwn)
+{
+	return snprintf(buf, len, "%016llx", wwn);
+}
+
+static struct se_node_acl *sbp_make_nodeacl(
+		struct se_portal_group *se_tpg,
+		struct config_group *group,
+		const char *name)
+{
+	struct se_node_acl *se_nacl, *se_nacl_new;
+	struct sbp_nacl *nacl;
+	u64 guid = 0;
+	u32 nexus_depth = 1;
+
+	pr_info("sbp_make_nodeacl: %s\n", name);
+
+	if (sbp_parse_wwn(name, &guid, 1) < 0)
+		return ERR_PTR(-EINVAL);
+
+	se_nacl_new = sbp_alloc_fabric_acl(se_tpg);
+	if (!se_nacl_new)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+	 * when converting a NodeACL from demo mode -> explict
+	 */
+	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+			name, nexus_depth);
+	if (IS_ERR(se_nacl)) {
+		sbp_release_fabric_acl(se_tpg, se_nacl_new);
+		return se_nacl;
+	}
+
+	/*
+	 * Locate our struct sbp_nacl and set the FC Nport WWPN
+	 */
+	nacl = container_of(se_nacl, struct sbp_nacl, se_node_acl);
+	nacl->guid = guid;
+	sbp_format_wwn(nacl->iport_name, SBP_NAMELEN, guid);
+
+	return se_nacl;
+}
+
+static void sbp_drop_nodeacl(struct se_node_acl *se_acl)
+{
+	struct sbp_nacl *nacl =
+		container_of(se_acl, struct sbp_nacl, se_node_acl);
+
+	core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+	kfree(nacl);
+}
+
+static int sbp_post_link_lun(
+		struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_lun *lun;
+
+	pr_info("sbp_post_link_lun: LUN %d\n", se_lun->unpacked_lun);
+
+	lun = kmalloc(sizeof(*lun), GFP_KERNEL);
+	if (!lun)
+		return -ENOMEM;
+
+	lun->se_lun = se_lun;
+	list_add_tail(&lun->link, &tpg->lun_list);
+
+	return sbp_update_unit_directory(tpg->tport);
+}
+
+static void sbp_pre_unlink_lun(
+		struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	struct sbp_lun *lun;
+	int ret;
+
+	pr_info("sbp_pre_unlink_lun: LUN %d\n", se_lun->unpacked_lun);
+
+	list_for_each_entry(lun, &tpg->lun_list, link) {
+		if (lun->se_lun == se_lun)
+			break;
+	}
+
+	BUG_ON(lun == NULL);
+
+	list_del(&lun->link);
+	kfree(lun);
+
+	if (list_empty(&tpg->lun_list))
+		tport->enable = 0;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		pr_err("unlink LUN: failed to update unit directory\n");
+}
+
+static struct se_portal_group *sbp_make_tpg(
+		struct se_wwn *wwn,
+		struct config_group *group,
+		const char *name)
+{
+	struct sbp_tport *tport =
+		container_of(wwn, struct sbp_tport, tport_wwn);
+
+	struct sbp_tpg *tpg;
+	unsigned long tpgt;
+	int ret;
+
+	if (strstr(name, "tpgt_") != name)
+		return ERR_PTR(-EINVAL);
+	if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+		return ERR_PTR(-EINVAL);
+
+	if (tport->tpg) {
+		pr_err("Only one TPG per Unit is possible.\n");
+		return ERR_PTR(-EBUSY);
+	}
+
+	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+	if (!tpg) {
+		pr_err("Unable to allocate struct sbp_tpg\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	tpg->tport = tport;
+	tpg->tport_tpgt = tpgt;
+	tport->tpg = tpg;
+
+	/* default attribute values */
+	tport->enable = 0;
+	tport->directory_id = -1;
+	tport->mgt_orb_timeout = 15;
+	tport->max_reconnect_timeout = 5;
+	tport->max_logins_per_lun = 1;
+
+	INIT_LIST_HEAD(&tpg->lun_list);
+
+	tport->mgt_agt = sbp_management_agent_register(tport);
+	if (IS_ERR(tport->mgt_agt)) {
+		ret = PTR_ERR(tport->mgt_agt);
+		kfree(tpg);
+		return ERR_PTR(ret);
+	}
+
+	ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
+			&tpg->se_tpg, (void *)tpg,
+			TRANSPORT_TPG_TYPE_NORMAL);
+	if (ret < 0) {
+		sbp_management_agent_unregister(tport->mgt_agt);
+		kfree(tpg);
+		return ERR_PTR(ret);
+	}
+
+	return &tpg->se_tpg;
+}
+
+static void sbp_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	core_tpg_deregister(se_tpg);
+	sbp_management_agent_unregister(tport->mgt_agt);
+	tport->tpg = NULL;
+	kfree(tpg);
+}
+
+static struct se_wwn *sbp_make_tport(
+		struct target_fabric_configfs *tf,
+		struct config_group *group,
+		const char *name)
+{
+	struct sbp_tport *tport;
+	u64 guid = 0;
+
+	pr_info("sbp_make_tport: %s\n", name);
+
+	if (sbp_parse_wwn(name, &guid, 1) < 0)
+		return ERR_PTR(-EINVAL);
+
+	tport = kzalloc(sizeof(*tport), GFP_KERNEL);
+	if (!tport) {
+		pr_err("Unable to allocate struct sbp_tport\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	tport->guid = guid;
+	sbp_format_wwn(tport->tport_name, SBP_NAMELEN, guid);
+
+	return &tport->tport_wwn;
+}
+
+static void sbp_drop_tport(struct se_wwn *wwn)
+{
+	struct sbp_tport *tport =
+		container_of(wwn, struct sbp_tport, tport_wwn);
+
+	kfree(tport);
+}
+
+static ssize_t sbp_wwn_show_attr_version(
+		struct target_fabric_configfs *tf,
+		char *page)
+{
+	return sprintf(page, "FireWire SBP fabric module %s\n", SBP_VERSION);
+}
+
+TF_WWN_ATTR_RO(sbp, version);
+
+static struct configfs_attribute *sbp_wwn_attrs[] = {
+	&sbp_wwn_version.attr,
+	NULL,
+};
+
+
+static ssize_t sbp_tpg_show_directory_id(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	if (tport->directory_id == -1)
+		return sprintf(page, "implicit\n");
+	else
+		return sprintf(page, "%06x\n", tport->directory_id);
+}
+
+static ssize_t sbp_tpg_store_directory_id(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+
+	if (tport->enable) {
+		pr_err("Cannot change the directory_id on an active target.\n");
+		return -EBUSY;
+	}
+
+	if (strstr(page, "implicit") == page) {
+		tport->directory_id = -1;
+	} else {
+		if (kstrtoul(page, 16, &val) < 0)
+			return -EINVAL;
+		if (val > 0xffffff)
+			return -EINVAL;
+
+		tport->directory_id = val;
+	}
+
+	return count;
+}
+
+static ssize_t sbp_tpg_show_enable(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->enable);
+}
+
+static ssize_t sbp_tpg_store_enable(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val != 0) && (val != 1))
+		return -EINVAL;
+
+	if (tport->enable == val)
+		return count;
+
+	if (val) {
+		if (list_empty(&tpg->lun_list)) {
+			pr_err("Cannot enable a target with no LUNs!\n");
+			return -EINVAL;
+		}
+	} else {
+		/* FIXME: force-shutdown sessions instead */
+		if (!list_empty(&se_tpg->tpg_sess_list))
+			return -EBUSY;
+	}
+
+	tport->enable = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0) {
+		pr_err("Could not update Config ROM\n");
+		return ret;
+	}
+
+	return count;
+}
+
+TF_TPG_BASE_ATTR(sbp, directory_id, S_IRUGO | S_IWUSR);
+TF_TPG_BASE_ATTR(sbp, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_base_attrs[] = {
+	&sbp_tpg_directory_id.attr,
+	&sbp_tpg_enable.attr,
+	NULL,
+};
+
+static ssize_t sbp_tpg_attrib_show_mgt_orb_timeout(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->mgt_orb_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 127))
+		return -EINVAL;
+
+	if (tport->mgt_orb_timeout == val)
+		return count;
+
+	tport->mgt_orb_timeout = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_reconnect_timeout(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->max_reconnect_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 32767))
+		return -EINVAL;
+
+	if (tport->max_reconnect_timeout == val)
+		return count;
+
+	tport->max_reconnect_timeout = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_logins_per_lun(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->max_logins_per_lun);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_logins_per_lun(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 127))
+		return -EINVAL;
+
+	/* XXX: also check against current count? */
+
+	tport->max_logins_per_lun = val;
+
+	return count;
+}
+
+TF_TPG_ATTRIB_ATTR(sbp, mgt_orb_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_reconnect_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_logins_per_lun, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
+	&sbp_tpg_attrib_mgt_orb_timeout.attr,
+	&sbp_tpg_attrib_max_reconnect_timeout.attr,
+	&sbp_tpg_attrib_max_logins_per_lun.attr,
+	NULL,
+};
+
+static struct target_core_fabric_ops sbp_ops = {
+	.get_fabric_name		= sbp_get_fabric_name,
+	.get_fabric_proto_ident		= sbp_get_fabric_proto_ident,
+	.tpg_get_wwn			= sbp_get_fabric_wwn,
+	.tpg_get_tag			= sbp_get_tag,
+	.tpg_get_default_depth		= sbp_get_default_depth,
+	.tpg_get_pr_transport_id	= sbp_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= sbp_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= sbp_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= sbp_check_true,
+	.tpg_check_demo_mode_cache	= sbp_check_true,
+	.tpg_check_demo_mode_write_protect = sbp_check_false,
+	.tpg_check_prod_mode_write_protect = sbp_check_false,
+	.tpg_alloc_fabric_acl		= sbp_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= sbp_release_fabric_acl,
+	.tpg_get_inst_index		= sbp_tpg_get_inst_index,
+	.new_cmd_map			= sbp_new_cmd,
+	.release_cmd			= sbp_release_cmd,
+	.shutdown_session		= sbp_shutdown_session,
+	.close_session			= sbp_close_session,
+	.stop_session			= sbp_stop_session,
+	.fall_back_to_erl0		= sbp_reset_nexus,
+	.sess_logged_in			= sbp_sess_logged_in,
+	.sess_get_index			= sbp_sess_get_index,
+	.sess_get_initiator_sid		= NULL,
+	.write_pending			= sbp_write_pending,
+	.write_pending_status		= sbp_write_pending_status,
+	.set_default_node_attributes	= sbp_set_default_node_attrs,
+	.get_task_tag			= sbp_get_task_tag,
+	.get_cmd_state			= sbp_get_cmd_state,
+	.queue_data_in			= sbp_queue_data_in,
+	.queue_status			= sbp_queue_status,
+	.queue_tm_rsp			= sbp_queue_tm_rsp,
+	.get_fabric_sense_len		= sbp_get_fabric_sense_len,
+	.set_fabric_sense_len		= sbp_set_fabric_sense_len,
+	.is_state_remove		= sbp_is_state_remove,
+	.check_stop_free		= sbp_check_stop_free,
+
+	.fabric_make_wwn		= sbp_make_tport,
+	.fabric_drop_wwn		= sbp_drop_tport,
+	.fabric_make_tpg		= sbp_make_tpg,
+	.fabric_drop_tpg		= sbp_drop_tpg,
+	.fabric_post_link		= sbp_post_link_lun,
+	.fabric_pre_unlink		= sbp_pre_unlink_lun,
+	.fabric_make_np			= NULL,
+	.fabric_drop_np			= NULL,
+	.fabric_make_nodeacl		= sbp_make_nodeacl,
+	.fabric_drop_nodeacl		= sbp_drop_nodeacl,
+};
+
+static int sbp_register_configfs(void)
+{
+	struct target_fabric_configfs *fabric;
+	int ret;
+
+	pr_info("FireWire SBP fabric module %s\n", SBP_VERSION);
+
+	/*
+	 * Register the top level struct config_item_type with TCM core
+	 */
+	fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
+	if (!fabric) {
+		pr_err("target_fabric_configfs_init() failed\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * Setup fabric->tf_ops from our local sbp_ops
+	 */
+	fabric->tf_ops = sbp_ops;
+
+	/*
+	 * Setup default attribute lists for various fabric->tf_cit_tmpl
+	 */
+	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = sbp_wwn_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+
+	/*
+	 * Register the fabric for use within TCM
+	 */
+	ret = target_fabric_configfs_register(fabric);
+	if (ret < 0) {
+		pr_err("target_fabric_configfs_register() failed for SBP\n");
+		return ret;
+	}
+
+	/*
+	 * Setup our local pointer to *fabric
+	 */
+	sbp_fabric_configfs = fabric;
+
+	pr_info("SBP[0] - Set fabric -> sbp_fabric_configfs\n");
+	return 0;
+};
+
+static void sbp_deregister_configfs(void)
+{
+	if (!sbp_fabric_configfs)
+		return;
+
+	target_fabric_configfs_deregister(sbp_fabric_configfs);
+	sbp_fabric_configfs = NULL;
+	pr_info("SBP[0] - Cleared sbp_fabric_configfs\n");
+};
+
+static int __init sbp_init(void)
+{
+	int ret;
+
+	ret = sbp_register_configfs();
+	if (ret < 0)
+		return ret;
+
+	return 0;
+};
+
+static void sbp_exit(void)
+{
+	sbp_deregister_configfs();
+};
+
+MODULE_DESCRIPTION("FireWire SBP fabric driver");
+MODULE_LICENSE("GPL");
+module_init(sbp_init);
+module_exit(sbp_exit);
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 06/13] firewire-sbp-target: Add sbp_fabric.{c,h}
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (4 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 05/13] firewire-sbp-target: Add sbp_configfs.c Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-13 13:06     ` Nicholas A. Bellinger
  2012-02-11 19:44   ` [PATCH 07/13] firewire-sbp-target: Add sbp_proto.{c,h} Chris Boot
                     ` (8 subsequent siblings)
  14 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This serves as further glue between the target framework and SBP-2, in
this case dealing with SCSI command submission and data in/out.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_fabric.c |  321 +++++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_fabric.h |   32 ++++
 2 files changed, 353 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_fabric.c
 create mode 100644 drivers/target/sbp/sbp_fabric.h

diff --git a/drivers/target/sbp/sbp_fabric.c b/drivers/target/sbp/sbp_fabric.c
new file mode 100644
index 0000000..edc6fda
--- /dev/null
+++ b/drivers/target/sbp/sbp_fabric.c
@@ -0,0 +1,321 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/firewire.h>
+
+#include <asm/unaligned.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/libfc.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#include "sbp_base.h"
+#include "sbp_fabric.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+
+int sbp_check_true(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+int sbp_check_false(struct se_portal_group *se_tpg)
+{
+	return 0;
+}
+
+char *sbp_get_fabric_name(void)
+{
+	return "sbp";
+}
+
+char *sbp_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	return &tport->tport_name[0];
+}
+
+u16 sbp_get_tag(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	return tpg->tport_tpgt;
+}
+
+u32 sbp_get_default_depth(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+	struct sbp_nacl *nacl;
+
+	nacl = kzalloc(sizeof(struct sbp_nacl), GFP_KERNEL);
+	if (!nacl) {
+		pr_err("Unable to alocate struct sbp_nacl\n");
+		return NULL;
+	}
+
+	return &nacl->se_node_acl;
+}
+
+void sbp_release_fabric_acl(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl)
+{
+	struct sbp_nacl *nacl =
+		container_of(se_nacl, struct sbp_nacl, se_node_acl);
+	kfree(nacl);
+}
+
+u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+int sbp_new_cmd(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+	int ret;
+
+	ret = transport_generic_allocate_tasks(se_cmd, req->cmd_buf);
+	if (ret)
+		return ret;
+
+	return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
+}
+
+void sbp_release_cmd(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	sbp_free_request(req);
+}
+
+int sbp_shutdown_session(struct se_session *se_sess)
+{
+	return 0;
+}
+
+void sbp_close_session(struct se_session *se_sess)
+{
+	return;
+}
+
+void sbp_stop_session(struct se_session *se_sess, int sess_sleep,
+		int conn_sleep)
+{
+	return;
+}
+
+void sbp_reset_nexus(struct se_session *se_sess)
+{
+	return;
+}
+
+int sbp_sess_logged_in(struct se_session *se_sess)
+{
+	return 0;
+}
+
+u32 sbp_sess_get_index(struct se_session *se_sess)
+{
+	return 0;
+}
+
+int sbp_write_pending(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+	int ret;
+
+	if (!req->data_len)
+		return -EINVAL;
+
+	if (req->data_dir != DMA_TO_DEVICE) {
+		pr_err("sbp_write_pending: incorrect data direction\n");
+		return -EINVAL;
+	}
+
+	if (req->data_len != se_cmd->data_length) {
+		pr_warn("sbp_write_pending: dodgy data length (%d != %d)\n",
+			req->data_len, se_cmd->data_length);
+	}
+
+	req->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+	if (!req->data_buf)
+		return -ENOMEM;
+
+	ret = sbp_rw_data(req);
+	if (ret) {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		pr_warn("sbp_write_pending: data write error\n");
+		return ret;
+	}
+
+	sg_copy_from_buffer(se_cmd->t_data_sg,
+			se_cmd->t_data_nents,
+			req->data_buf,
+			se_cmd->data_length);
+
+	transport_generic_process_write(se_cmd);
+
+	return 0;
+}
+
+int sbp_write_pending_status(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+void sbp_set_default_node_attrs(struct se_node_acl *nacl)
+{
+	return;
+}
+
+u32 sbp_get_task_tag(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	/* only used for printk and family? */
+	return (u32)req->orb_pointer;
+}
+
+int sbp_get_cmd_state(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+int sbp_queue_data_in(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+	int ret;
+
+	if (!req->data_len) {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_ILLEGAL_REQUEST) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		pr_err("sbp_queue_data_in: no initiator data buffers\n");
+		return 0;
+	}
+
+	if (req->data_dir != DMA_FROM_DEVICE) {
+		pr_err("sbp_queue_data_in: incorrect data direction\n");
+		return -EINVAL;
+	}
+
+	if (req->data_len != se_cmd->data_length) {
+		pr_warn("sbp_write_pending: dodgy data length (%d != %d)\n",
+			req->data_len, se_cmd->data_length);
+	}
+
+	req->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+	if (!req->data_buf)
+		return -ENOMEM;
+
+	sg_copy_to_buffer(se_cmd->t_data_sg,
+		se_cmd->t_data_nents,
+		req->data_buf,
+		se_cmd->data_length);
+
+	ret = sbp_rw_data(req);
+	if (ret) {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		return ret;
+	}
+
+	return sbp_send_sense(req);
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+int sbp_queue_status(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	return sbp_send_sense(req);
+}
+
+int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+u16 sbp_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+	return 0;
+}
+
+u16 sbp_get_fabric_sense_len(void)
+{
+	return 0;
+}
+
+int sbp_is_state_remove(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+int sbp_check_stop_free(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	transport_generic_free_cmd(&req->se_cmd, 0);
+	return 1;
+}
+
diff --git a/drivers/target/sbp/sbp_fabric.h b/drivers/target/sbp/sbp_fabric.h
new file mode 100644
index 0000000..2a600f1c
--- /dev/null
+++ b/drivers/target/sbp/sbp_fabric.h
@@ -0,0 +1,32 @@
+
+int sbp_check_true(struct se_portal_group *);
+int sbp_check_false(struct se_portal_group *);
+char *sbp_get_fabric_name(void);
+char *sbp_get_fabric_wwn(struct se_portal_group *);
+u16 sbp_get_tag(struct se_portal_group *);
+u32 sbp_get_default_depth(struct se_portal_group *);
+struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *);
+void sbp_release_fabric_acl(struct se_portal_group *,
+		struct se_node_acl *);
+u32 sbp_tpg_get_inst_index(struct se_portal_group *);
+int sbp_new_cmd(struct se_cmd *se_cmd);
+void sbp_release_cmd(struct se_cmd *se_cmd);
+int sbp_shutdown_session(struct se_session *);
+void sbp_close_session(struct se_session *);
+void sbp_stop_session(struct se_session *, int, int);
+void sbp_reset_nexus(struct se_session *);
+int sbp_sess_logged_in(struct se_session *);
+u32 sbp_sess_get_index(struct se_session *);
+int sbp_write_pending(struct se_cmd *);
+int sbp_write_pending_status(struct se_cmd *);
+void sbp_set_default_node_attrs(struct se_node_acl *);
+u32 sbp_get_task_tag(struct se_cmd *);
+int sbp_get_cmd_state(struct se_cmd *);
+int sbp_queue_data_in(struct se_cmd *);
+int sbp_queue_status(struct se_cmd *);
+int sbp_queue_tm_rsp(struct se_cmd *);
+u16 sbp_set_fabric_sense_len(struct se_cmd *, u32);
+u16 sbp_get_fabric_sense_len(void);
+int sbp_is_state_remove(struct se_cmd *);
+int sbp_check_stop_free(struct se_cmd *se_cmd);
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 07/13] firewire-sbp-target: Add sbp_proto.{c,h}
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (5 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 06/13] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 08/13] firewire-sbp-target: add sbp_management_agent.{c,h} Chris Boot
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

These are functions to generate TransportID identifiers as per SPC-4
revision 17.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_proto.c |  113 ++++++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_proto.h |   12 ++++
 2 files changed, 125 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_proto.c
 create mode 100644 drivers/target/sbp/sbp_proto.h

diff --git a/drivers/target/sbp/sbp_proto.c b/drivers/target/sbp/sbp_proto.c
new file mode 100644
index 0000000..5744b5c
--- /dev/null
+++ b/drivers/target/sbp/sbp_proto.c
@@ -0,0 +1,113 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <target/target_core_base.h>
+
+#include "sbp_proto.h"
+
+/*
+ * Handlers for Serial Attached SCSI (SBP)
+ */
+u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+	/*
+	 * Return a IEEE 1394 SCSI Protocol identifier for loopback operations
+	 * This is defined in section 7.5.1 Table 362 in spc4r17
+	 */
+	return SCSI_PROTOCOL_SBP;
+}
+EXPORT_SYMBOL(sbp_get_fabric_proto_ident);
+
+u32 sbp_get_pr_transport_id(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code,
+	unsigned char *buf)
+{
+	int ret;
+
+	/*
+	 * Set PROTOCOL IDENTIFIER to 3h for SBP
+	 */
+	buf[0] = SCSI_PROTOCOL_SBP;
+	/*
+	 * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+	 * over IEEE 1394
+	 */
+	ret = hex2bin(&buf[8], se_nacl->initiatorname, 8);
+	if (ret < 0)
+		pr_debug("sbp transport_id: invalid hex string\n");
+
+	/*
+	 * The IEEE 1394 Transport ID is a hardcoded 24-byte length
+	 */
+	return 24;
+}
+EXPORT_SYMBOL(sbp_get_pr_transport_id);
+
+u32 sbp_get_pr_transport_id_len(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code)
+{
+	*format_code = 0;
+	/*
+	 * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+	 * over IEEE 1394
+	 *
+	 * The SBP Transport ID is a hardcoded 24-byte length
+	 */
+	return 24;
+}
+EXPORT_SYMBOL(sbp_get_pr_transport_id_len);
+
+/*
+ * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
+ * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
+ */
+char *sbp_parse_pr_out_transport_id(
+	struct se_portal_group *se_tpg,
+	const char *buf,
+	u32 *out_tid_len,
+	char **port_nexus_ptr)
+{
+	/*
+	 * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.4 TransportID
+	 * for initiator ports using SCSI over SBP Serial SCSI Protocol
+	 *
+	 * The TransportID for a IEEE 1394 Initiator Port is of fixed size of
+	 * 24 bytes, and IEEE 1394 does not contain a I_T nexus identifier,
+	 * so we return the **port_nexus_ptr set to NULL.
+	 */
+	*port_nexus_ptr = NULL;
+	*out_tid_len = 24;
+
+	return (char *)&buf[8];
+}
+EXPORT_SYMBOL(sbp_parse_pr_out_transport_id);
+
diff --git a/drivers/target/sbp/sbp_proto.h b/drivers/target/sbp/sbp_proto.h
new file mode 100644
index 0000000..1bd3e16
--- /dev/null
+++ b/drivers/target/sbp/sbp_proto.h
@@ -0,0 +1,12 @@
+
+u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg);
+u32 sbp_get_pr_transport_id(struct se_portal_group *se_tpg,
+		struct se_node_acl *se_nacl, struct t10_pr_registration *pr_reg,
+		int *format_code, unsigned char *buf);
+u32 sbp_get_pr_transport_id_len(
+		struct se_portal_group *se_tpg, struct se_node_acl *se_nacl,
+		struct t10_pr_registration *pr_reg, int *format_code);
+char *sbp_parse_pr_out_transport_id(
+		struct se_portal_group *se_tpg, const char *buf,
+		u32 *out_tid_len, char **port_nexus_ptr);
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 08/13] firewire-sbp-target: add sbp_management_agent.{c,h}
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (6 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 07/13] firewire-sbp-target: Add sbp_proto.{c,h} Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 09/13] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This code implements the SBP-2 Management Agent. This is the first of
two firewire address handlers that are used to communicate with the
target. The Management Agent is used to handle login, reconnect and
logout to a SCSI LUN as well as task management functions.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_management_agent.c |  266 +++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_management_agent.h |   23 +++
 2 files changed, 289 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_management_agent.c
 create mode 100644 drivers/target/sbp/sbp_management_agent.h

diff --git a/drivers/target/sbp/sbp_management_agent.c b/drivers/target/sbp/sbp_management_agent.c
new file mode 100644
index 0000000..d9a2124
--- /dev/null
+++ b/drivers/target/sbp/sbp_management_agent.c
@@ -0,0 +1,266 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/kref.h>
+
+#include <target/target_core_base.h>
+
+#include "../../firewire/core.h"
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+#include "sbp_login.h"
+#include "sbp_util.h"
+
+static void sbp_mgt_agent_process(struct work_struct *work)
+{
+	struct sbp_management_agent *agent =
+		container_of(work, struct sbp_management_agent, work);
+	struct sbp_management_request *req = agent->request;
+	int ret;
+	int status_data_len = 0;
+
+	/* fetch the ORB from the initiator */
+	ret = fw_run_transaction(req->card, TCODE_READ_BLOCK_REQUEST,
+		req->node_addr, req->generation, req->speed,
+		agent->orb_offset, &req->orb, sizeof(req->orb));
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("mgt_orb fetch failed: %x\n", ret);
+		goto out;
+	}
+
+	pr_debug("mgt_orb ptr1:0x%llx ptr2:0x%llx misc:0x%x len:0x%x "
+		"status_fifo:0x%llx\n",
+		sbp2_pointer_to_addr(&req->orb.ptr1),
+		sbp2_pointer_to_addr(&req->orb.ptr2),
+		be32_to_cpu(req->orb.misc), be32_to_cpu(req->orb.length),
+		sbp2_pointer_to_addr(&req->orb.status_fifo));
+
+	/* sanity check basic fields */
+	if (!ORB_NOTIFY(be32_to_cpu(req->orb.misc)) ||
+		ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc)) != 0) {
+		pr_err("mgt_orb bad request\n");
+		goto out;
+	}
+
+	switch (MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc))) {
+	case MANAGEMENT_ORB_FUNCTION_LOGIN:
+		sbp_management_request_login(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS:
+		sbp_management_request_query_logins(agent, req,
+				&status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_RECONNECT:
+		sbp_management_request_reconnect(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_SET_PASSWORD:
+		pr_notice("SET PASSWORD not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_LOGOUT:
+		sbp_management_request_logout(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_ABORT_TASK:
+		pr_notice("ABORT TASK not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET:
+		pr_notice("ABORT TASK SET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET:
+		pr_notice("LOGICAL UNIT RESET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_TARGET_RESET:
+		pr_notice("TARGET RESET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	default:
+		pr_notice("unknown management function 0x%x\n",
+			MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc)));
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+	}
+
+	/* set up the status block we'll send to the initiator */
+	req->status.status |= cpu_to_be32(
+		STATUS_BLOCK_SRC(1) | /* Response to ORB, next_ORB absent */
+		STATUS_BLOCK_LEN(DIV_ROUND_UP(status_data_len, 4) + 1) |
+		STATUS_BLOCK_ORB_OFFSET_HIGH(agent->orb_offset >> 32));
+	req->status.orb_low = cpu_to_be32(agent->orb_offset);
+
+	/* write the status block back to the initiator */
+	ret = fw_run_transaction(req->card, TCODE_WRITE_BLOCK_REQUEST,
+		req->node_addr, req->generation, req->speed,
+		sbp2_pointer_to_addr(&req->orb.status_fifo),
+		&req->status, 8 + status_data_len);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("mgt_orb status write failed: %x\n", ret);
+		goto out;
+	}
+
+out:
+	fw_card_put(req->card);
+	kfree(req);
+	atomic_set(&agent->state, MANAGEMENT_AGENT_STATE_IDLE);
+}
+
+static void sbp_mgt_agent_rw(struct fw_card *card,
+	struct fw_request *request, int tcode, int destination, int source,
+	int generation, unsigned long long offset, void *data, size_t length,
+	void *callback_data)
+{
+	struct sbp_management_agent *agent = callback_data;
+	struct sbp2_pointer *ptr = data;
+
+	if (!agent->tport->enable) {
+		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+		return;
+	}
+
+	if ((offset != agent->handler.offset) || (length != 8)) {
+		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+		return;
+	}
+
+	if (tcode == TCODE_WRITE_BLOCK_REQUEST) {
+		struct sbp_management_request *req;
+		int ret;
+
+		smp_wmb();
+		if (atomic_cmpxchg(&agent->state,
+					MANAGEMENT_AGENT_STATE_IDLE,
+					MANAGEMENT_AGENT_STATE_BUSY) !=
+				MANAGEMENT_AGENT_STATE_IDLE) {
+			pr_notice("ignoring management request while busy\n");
+
+			fw_send_response(card, request, RCODE_CONFLICT_ERROR);
+			return;
+		}
+
+		req = kzalloc(sizeof(*req), GFP_ATOMIC);
+		if (!req) {
+			fw_send_response(card, request, RCODE_CONFLICT_ERROR);
+			return;
+		}
+
+		req->card = fw_card_get(card);
+		req->generation = generation;
+		req->node_addr = source;
+		req->speed = fw_get_request_speed(request);
+
+		agent->orb_offset = sbp2_pointer_to_addr(ptr);
+		agent->request = req;
+
+		ret = queue_work(fw_workqueue, &agent->work);
+		if (!ret) {
+			/* pretend we're busy */
+			kfree(req);
+			fw_send_response(card, request, RCODE_CONFLICT_ERROR);
+			return;
+		}
+
+		fw_send_response(card, request, RCODE_COMPLETE);
+	} else if (tcode == TCODE_READ_BLOCK_REQUEST) {
+		addr_to_sbp2_pointer(agent->orb_offset, ptr);
+		fw_send_response(card, request, RCODE_COMPLETE);
+	} else {
+		fw_send_response(card, request, RCODE_TYPE_ERROR);
+	}
+}
+
+struct sbp_management_agent *sbp_management_agent_register(
+		struct sbp_tport *tport)
+{
+	int ret;
+	struct sbp_management_agent *agent;
+
+	agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+	if (!agent)
+		return ERR_PTR(-ENOMEM);
+
+	agent->tport = tport;
+	agent->handler.length = 0x08;
+	agent->handler.address_callback = sbp_mgt_agent_rw;
+	agent->handler.callback_data = agent;
+	atomic_set(&agent->state, MANAGEMENT_AGENT_STATE_IDLE);
+	INIT_WORK(&agent->work, sbp_mgt_agent_process);
+	agent->orb_offset = 0;
+	agent->request = NULL;
+
+	ret = fw_core_add_address_handler(&agent->handler,
+			&sbp_register_region);
+	if (ret < 0) {
+		kfree(agent);
+		return ERR_PTR(ret);
+	}
+
+	return agent;
+}
+
+void sbp_management_agent_unregister(struct sbp_management_agent *agent)
+{
+	if (atomic_read(&agent->state) != MANAGEMENT_AGENT_STATE_IDLE)
+		flush_work_sync(&agent->work);
+
+	fw_core_remove_address_handler(&agent->handler);
+	kfree(agent);
+}
+
diff --git a/drivers/target/sbp/sbp_management_agent.h b/drivers/target/sbp/sbp_management_agent.h
new file mode 100644
index 0000000..615b90e
--- /dev/null
+++ b/drivers/target/sbp/sbp_management_agent.h
@@ -0,0 +1,23 @@
+
+struct sbp_management_agent {
+	struct sbp_tport *tport;
+	struct fw_address_handler handler;
+	atomic_t state;
+	struct work_struct work;
+	u64 orb_offset;
+	struct sbp_management_request *request;
+};
+
+struct sbp_management_request {
+	struct sbp_management_orb orb;
+	struct sbp_status_block status;
+	struct fw_card *card;
+	int generation;
+	int node_addr;
+	int speed;
+};
+
+struct sbp_management_agent *sbp_management_agent_register(
+		struct sbp_tport *tport);
+void sbp_management_agent_unregister(struct sbp_management_agent *agent);
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 09/13] firewire-sbp-target: Add sbp_login.{c,h}
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (7 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 08/13] firewire-sbp-target: add sbp_management_agent.{c,h} Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 10/13] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This file contains the implementation of the login, reconnect and logout
management ORBs in SBP-2.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_login.c |  637 ++++++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_login.h |   14 +
 2 files changed, 651 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_login.c
 create mode 100644 drivers/target/sbp/sbp_login.h

diff --git a/drivers/target/sbp/sbp_login.c b/drivers/target/sbp/sbp_login.c
new file mode 100644
index 0000000..fb1accf
--- /dev/null
+++ b/drivers/target/sbp/sbp_login.c
@@ -0,0 +1,637 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kref.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/slab.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#include "../../firewire/core.h"
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+#include "sbp_login.h"
+#include "sbp_target_agent.h"
+#include "sbp_util.h"
+
+#define SESSION_MAINTENANCE_INTERVAL HZ
+
+static atomic_t login_id = ATOMIC_INIT(0);
+
+static void session_maintenance_work(struct work_struct *work);
+
+static int read_peer_guid(u64 *guid, const struct sbp_management_request *req)
+{
+	int ret;
+	__be32 high, low;
+
+	ret = fw_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+			req->node_addr, req->generation, req->speed,
+			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 3 * 4,
+			&high, sizeof(high));
+	if (ret != RCODE_COMPLETE)
+		return ret;
+
+	ret = fw_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+			req->node_addr, req->generation, req->speed,
+			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 4 * 4,
+			&low, sizeof(low));
+	if (ret != RCODE_COMPLETE)
+		return ret;
+
+	*guid = (u64)be32_to_cpu(high) << 32 | be32_to_cpu(low);
+
+	return RCODE_COMPLETE;
+}
+
+static struct sbp_session *sbp_session_find_by_guid(
+	struct sbp_tpg *tpg, u64 guid)
+{
+	struct se_session *se_sess;
+
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		struct sbp_session *sess = se_sess->fabric_sess_ptr;
+		if (sess->guid == guid)
+			return sess;
+	}
+
+	return NULL;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_lun(
+		struct sbp_session *session, struct se_lun *lun)
+{
+	struct sbp_login_descriptor *login;
+
+	list_for_each_entry(login, &session->login_list, link) {
+		if (login->lun == lun)
+			return login;
+	}
+
+	return NULL;
+}
+
+static int sbp_login_count_all_by_lun(
+		struct sbp_tpg *tpg,
+		struct se_lun *lun,
+		int exclusive)
+{
+	struct se_session *se_sess;
+	int count = 0;
+
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		struct sbp_session *sess = se_sess->fabric_sess_ptr;
+		struct sbp_login_descriptor *login;
+
+		list_for_each_entry(login, &sess->login_list, link) {
+			if (login->lun != lun)
+				continue;
+
+			if (!exclusive) {
+				count++;
+				continue;
+			}
+
+			if (login->exclusive)
+				count++;
+		}
+	}
+
+	return count;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_id(
+	struct sbp_tpg *tpg, int login_id)
+{
+	struct se_session *se_sess;
+
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		struct sbp_session *sess = se_sess->fabric_sess_ptr;
+		struct sbp_login_descriptor *login;
+
+		list_for_each_entry(login, &sess->login_list, link) {
+			if (login->login_id == login_id)
+				return login;
+		}
+	}
+
+	return NULL;
+}
+
+static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun)
+{
+	struct se_portal_group *se_tpg = &tpg->se_tpg;
+	struct se_lun *se_lun;
+
+	if (lun >= TRANSPORT_MAX_LUNS_PER_TPG)
+		return ERR_PTR(-ENODEV);
+
+	spin_lock(&se_tpg->tpg_lun_lock);
+	se_lun = &se_tpg->tpg_lun_list[lun];
+
+	if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
+		se_lun = ERR_PTR(-EINVAL);
+
+	spin_unlock(&se_tpg->tpg_lun_lock);
+
+	return se_lun;
+}
+
+static struct sbp_session *sbp_session_create(
+		struct sbp_tpg *tpg,
+		u64 guid)
+{
+	struct sbp_session *sess;
+	int ret;
+	char guid_str[17];
+	struct se_node_acl *se_nacl;
+
+	sess = kmalloc(sizeof(*sess), GFP_KERNEL);
+	if (!sess) {
+		pr_err("failed to allocate session descriptor\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sess->se_sess = transport_init_session();
+	if (IS_ERR(sess->se_sess)) {
+		pr_err("failed to init se_session\n");
+
+		ret = PTR_ERR(sess->se_sess);
+		kfree(sess);
+		return ERR_PTR(ret);
+	}
+
+	snprintf(guid_str, sizeof(guid_str), "%016llx", guid);
+
+	se_nacl = core_tpg_check_initiator_node_acl(&tpg->se_tpg, guid_str);
+	if (!se_nacl) {
+		pr_warn("Node ACL not found for %s\n", guid_str);
+
+		transport_free_session(sess->se_sess);
+		kfree(sess);
+
+		return ERR_PTR(-EPERM);
+	}
+
+	INIT_LIST_HEAD(&sess->login_list);
+	sess->se_sess->se_node_acl = se_nacl;
+	INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work);
+	sess->guid = guid;
+
+	transport_register_session(&tpg->se_tpg, se_nacl, sess->se_sess, sess);
+
+	return sess;
+}
+
+static void sbp_session_release(struct sbp_session *sess, bool cancel_work)
+{
+	if (!list_empty(&sess->login_list))
+		return;
+
+	transport_deregister_session_configfs(sess->se_sess);
+	transport_deregister_session(sess->se_sess);
+
+	if (sess->card)
+		fw_card_put(sess->card);
+
+	if (cancel_work)
+		cancel_delayed_work_sync(&sess->maint_work);
+
+	kfree(sess);
+}
+
+static void sbp_login_release(struct sbp_login_descriptor *login,
+	bool cancel_work)
+{
+	/* FIXME: abort/wait on tasks */
+
+	list_del(&login->link);
+	sbp_target_agent_unregister(login->tgt_agt);
+	sbp_session_release(login->sess, cancel_work);
+	kfree(login);
+}
+
+void sbp_management_request_login(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	struct se_lun *lun;
+	int ret;
+	u64 guid;
+	struct sbp_session *sess;
+	struct sbp_login_descriptor *login;
+	struct sbp_login_response_block *response;
+	int login_response_len;
+
+	/* find the LUN we want to login to */
+	lun = sbp_get_lun_from_tpg(tpg,
+			LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+	if (IS_ERR(lun)) {
+		pr_notice("login to unknown LUN: %d\n",
+			LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LUN_NOTSUPP));
+		return;
+	}
+
+	/* read the peer's GUID */
+	ret = read_peer_guid(&guid, req);
+	if (ret != RCODE_COMPLETE) {
+		pr_warn("failed to read peer GUID: %d\n", ret);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n",
+		lun->unpacked_lun, guid);
+
+	/* locate an existing session if there is one */
+	sess = sbp_session_find_by_guid(tpg, guid);
+
+	/*
+	 * check for any existing logins by comparing GUIDs
+	 * reject with access_denied if present
+	 */
+	if (sess) {
+		login = sbp_login_find_by_lun(sess, lun);
+		if (login) {
+			pr_notice("initiator already logged-in\n");
+
+			/*
+			 * SBP-2 R4 says we should return access denied, but
+			 * that can confuse initiators. Instead we need to
+			 * treat this like a reconnect, but send the login
+			 * response block like a fresh login.
+			 */
+
+			goto already_logged_in;
+		}
+	}
+
+	/*
+	 * check exclusive bit in login request
+	 * reject with access_denied if any logins present
+	 */
+	if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) &&
+		sbp_login_count_all_by_lun(tpg, lun, 0)) {
+		pr_warn("refusing exclusive login with other active logins\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	/*
+	 * check exclusive bit in any existing login descriptor
+	 * reject with access_denied if any exclusive logins present
+	 */
+	if (sbp_login_count_all_by_lun(tpg, lun, 1)) {
+		pr_warn("refusing login while another exclusive login present\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	/*
+	 * check we haven't exceeded the number of allowed logins
+	 * reject with resources_unavailable if we have
+	 */
+	if (sbp_login_count_all_by_lun(tpg, lun, 0) >=
+			tport->max_logins_per_lun) {
+		pr_warn("max number of logins reached\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	if (!sess) {
+		sess = sbp_session_create(tpg, guid);
+		if (IS_ERR(sess)) {
+			switch (PTR_ERR(sess)) {
+			case -EPERM:
+				ret = SBP_STATUS_ACCESS_DENIED;
+				break;
+			default:
+				ret = SBP_STATUS_RESOURCES_UNAVAIL;
+				break;
+			}
+
+			req->status.status = cpu_to_be32(
+				STATUS_BLOCK_RESP(
+					STATUS_RESP_REQUEST_COMPLETE) |
+				STATUS_BLOCK_SBP_STATUS(ret));
+			return;
+		}
+
+		sess->node_id = req->node_addr;
+		sess->card = fw_card_get(req->card);
+		sess->generation = req->generation;
+		sess->speed = req->speed;
+
+		queue_delayed_work(fw_workqueue, &sess->maint_work,
+			SESSION_MAINTENANCE_INTERVAL);
+	}
+
+	/* only take the latest reconnect_hold into account */
+	sess->reconnect_hold = min(
+		1 << LOGIN_ORB_RECONNECT(be32_to_cpu(req->orb.misc)),
+		tport->max_reconnect_timeout) - 1;
+
+	/* create new login descriptor */
+	login = kmalloc(sizeof(*login), GFP_KERNEL);
+	if (!login) {
+		pr_err("failed to allocate login descriptor\n");
+
+		sbp_session_release(sess, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	login->sess = sess;
+	login->lun = lun;
+	login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo);
+	login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc));
+	login->login_id = atomic_inc_return(&login_id);
+	atomic_set(&login->unsolicited_status_enable, 0);
+
+	/* set up address handler */
+	login->tgt_agt = sbp_target_agent_register(login);
+	if (IS_ERR(login->tgt_agt)) {
+		ret = PTR_ERR(login->tgt_agt);
+		pr_err("failed to map command block handler: %d\n", ret);
+
+		sbp_session_release(sess, true);
+		kfree(login);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	/* add to logins list */
+	list_add_tail(&login->link, &sess->login_list);
+
+already_logged_in:
+	/* send login response */
+	response = kzalloc(sizeof(*response), GFP_KERNEL);
+	if (!response) {
+		pr_err("failed to allocate login response block\n");
+
+		sbp_login_release(login, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	login_response_len = max(12, min((int)sizeof(response),
+		(int)LOGIN_ORB_RESPONSE_LENGTH(be32_to_cpu(req->orb.length))));
+	response->misc = cpu_to_be32(
+		((login_response_len & 0xffff) << 16) |
+		(login->login_id & 0xffff));
+	response->reconnect_hold = cpu_to_be32(sess->reconnect_hold & 0xffff);
+	addr_to_sbp2_pointer(login->tgt_agt->handler.offset,
+		&response->command_block_agent);
+
+	ret = fw_run_transaction(sess->card, TCODE_WRITE_BLOCK_REQUEST,
+		sess->node_id, sess->generation, sess->speed,
+		sbp2_pointer_to_addr(&req->orb.ptr2), response,
+		login_response_len);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("failed to write login response block: %x\n", ret);
+
+		kfree(response);
+		sbp_login_release(login, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	kfree(response);
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+void sbp_management_request_query_logins(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	pr_notice("QUERY LOGINS not implemented\n");
+	/* FIXME: implement */
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+}
+
+void sbp_management_request_reconnect(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	int ret;
+	u64 guid;
+	struct sbp_login_descriptor *login;
+
+	/* read the peer's GUID */
+	ret = read_peer_guid(&guid, req);
+	if (ret != RCODE_COMPLETE) {
+		pr_warn("failed to read peer GUID: %d\n", ret);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	pr_notice("mgt_agent RECONNECT from %016llx\n", guid);
+
+	/* find the login */
+	login = sbp_login_find_by_id(tpg,
+		RECONNECT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc)));
+
+	if (!login) {
+		pr_err("mgt_agent RECONNECT unknown login ID\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	if (login->sess->guid != guid) {
+		pr_err("mgt_agent RECONNECT login GUID doesn't match\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	if (login->sess->card)
+		fw_card_put(login->sess->card);
+
+	/* update the node details */
+	login->sess->generation = req->generation;
+	login->sess->node_id = req->node_addr;
+	login->sess->card = fw_card_get(req->card);
+	login->sess->speed = req->speed;
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+void sbp_management_request_logout(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	int login_id;
+	struct sbp_login_descriptor *login;
+
+	login_id = LOGOUT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc));
+
+	/* Find login by ID */
+	login = sbp_login_find_by_id(tpg, login_id);
+	if (!login) {
+		pr_warn("cannot find login: %d\n", login_id);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LOGIN_ID_UNKNOWN));
+		return;
+	}
+
+	pr_info("mgt_agent LOGOUT from LUN %d session %d\n",
+		login->lun->unpacked_lun, login->login_id);
+
+	/* Check source against login's node_id */
+	if (req->node_addr != login->sess->node_id) {
+		pr_warn("logout from different node ID\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	/* Perform logout */
+	sbp_login_release(login, true);
+
+	pr_info("logout successful!\n");
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void session_check_for_reset(struct sbp_session *sess)
+{
+	bool card_valid = false;
+
+	if (sess->card) {
+		spin_lock_irq(&sess->card->lock);
+		card_valid = (sess->card->local_node != NULL);
+		spin_unlock_irq(&sess->card->lock);
+
+		if (!card_valid) {
+			fw_card_put(sess->card);
+			sess->card = NULL;
+		}
+	}
+
+	if (!card_valid || (sess->generation != sess->card->generation)) {
+		pr_info("Waiting for reconnect from node: %016llx\n",
+			sess->guid);
+
+		sess->node_id = -1;
+		sess->reconnect_expires = get_jiffies_64() +
+			((sess->reconnect_hold + 1) * HZ);
+	}
+}
+
+static void session_reconnect_expired(struct sbp_session *sess)
+{
+	struct sbp_login_descriptor *login, *temp;
+
+	pr_info("Reconnect timer expired for node: %016llx\n", sess->guid);
+
+	list_for_each_entry_safe(login, temp, &sess->login_list, link) {
+		sbp_login_release(login, false);
+	}
+
+	/* sbp_login_release() calls sbp_session_release() */
+}
+
+static void session_maintenance_work(struct work_struct *work)
+{
+	struct sbp_session *sess = container_of(work, struct sbp_session,
+		maint_work.work);
+
+	/* could be called while tearing down the session */
+	if (list_empty(&sess->login_list))
+		return;
+
+	if (sess->node_id != -1) {
+		/* check for bus reset and make node_id invalid */
+		session_check_for_reset(sess);
+
+		queue_delayed_work(fw_workqueue, &sess->maint_work,
+			SESSION_MAINTENANCE_INTERVAL);
+	} else if (!time_after64(get_jiffies_64(), sess->reconnect_expires)) {
+		/* still waiting for reconnect */
+		queue_delayed_work(fw_workqueue, &sess->maint_work,
+			SESSION_MAINTENANCE_INTERVAL);
+	} else {
+		/* reconnect timeout has expired */
+		session_reconnect_expired(sess);
+	}
+}
+
diff --git a/drivers/target/sbp/sbp_login.h b/drivers/target/sbp/sbp_login.h
new file mode 100644
index 0000000..4c86dcb
--- /dev/null
+++ b/drivers/target/sbp/sbp_login.h
@@ -0,0 +1,14 @@
+
+extern void sbp_management_request_login(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+extern void sbp_management_request_query_logins(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+extern void sbp_management_request_reconnect(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+extern void sbp_management_request_logout(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 10/13] firewire-sbp-target: Add sbp_target_agent.{c,h}
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (8 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 09/13] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 11/13] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h} Chris Boot
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This implements the SBP-2 Command Block Agent, or Target Agent. This is
what receives SCSI commands and forwards them to the target framework.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_target_agent.c |  360 +++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_target_agent.h |   30 +++
 2 files changed, 390 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_target_agent.c
 create mode 100644 drivers/target/sbp/sbp_target_agent.h

diff --git a/drivers/target/sbp/sbp_target_agent.c b/drivers/target/sbp/sbp_target_agent.c
new file mode 100644
index 0000000..4ab2000
--- /dev/null
+++ b/drivers/target/sbp/sbp_target_agent.c
@@ -0,0 +1,360 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/slab.h>
+
+#include <target/target_core_base.h>
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+#include "sbp_login.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+#include "sbp_util.h"
+
+static int tgt_agent_rw_agent_state(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	if (tcode == TCODE_READ_QUADLET_REQUEST) {
+		__be32 state;
+
+		pr_debug("tgt_agent AGENT_STATE READ\n");
+
+		state = cpu_to_be32(atomic_read(&agent->state));
+		memcpy(data, &state, sizeof(state));
+
+		return RCODE_COMPLETE;
+	} else if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
+		/* ignored */
+		return RCODE_COMPLETE;
+	} else {
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_agent_reset(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
+		pr_debug("tgt_agent AGENT_RESET\n");
+		atomic_set(&agent->state, AGENT_STATE_RESET);
+		return RCODE_COMPLETE;
+	} else {
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_orb_pointer(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	struct sbp2_pointer *ptr = data;
+
+	if (tcode == TCODE_WRITE_BLOCK_REQUEST) {
+		int ret;
+
+		smp_wmb();
+		atomic_cmpxchg(&agent->state,
+				AGENT_STATE_RESET, AGENT_STATE_SUSPENDED);
+		smp_wmb();
+		if (atomic_cmpxchg(&agent->state,
+					AGENT_STATE_SUSPENDED,
+					AGENT_STATE_ACTIVE)
+				!= AGENT_STATE_SUSPENDED)
+			return RCODE_CONFLICT_ERROR;
+		smp_wmb();
+
+		agent->orb_pointer = sbp2_pointer_to_addr(ptr);
+
+		pr_debug("tgt_agent ORB_POINTER write: %llu\n",
+			agent->orb_pointer);
+
+		ret = queue_work(fw_workqueue, &agent->work);
+		if (!ret)
+			return RCODE_CONFLICT_ERROR;
+
+		return RCODE_COMPLETE;
+	} else if (tcode == TCODE_READ_BLOCK_REQUEST) {
+		pr_debug("tgt_agent ORB_POINTER READ\n");
+		addr_to_sbp2_pointer(agent->orb_pointer, ptr);
+		return RCODE_COMPLETE;
+	} else {
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_doorbell(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
+		int ret;
+
+		smp_wmb();
+		if (atomic_cmpxchg(&agent->state,
+					AGENT_STATE_SUSPENDED,
+					AGENT_STATE_ACTIVE)
+				!= AGENT_STATE_SUSPENDED)
+			return RCODE_CONFLICT_ERROR;
+		smp_wmb();
+
+		pr_debug("tgt_agent DOORBELL\n");
+
+		ret = queue_work(fw_workqueue, &agent->work);
+		if (!ret)
+			return RCODE_CONFLICT_ERROR;
+
+		return RCODE_COMPLETE;
+	} else if (tcode == TCODE_READ_QUADLET_REQUEST) {
+		return RCODE_COMPLETE;
+	} else {
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_unsolicited_status_enable(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	if (tcode == TCODE_WRITE_QUADLET_REQUEST) {
+		pr_debug("tgt_agent UNSOLICITED_STATUS_ENABLE\n");
+		atomic_set(&agent->login->unsolicited_status_enable, 1);
+		return RCODE_COMPLETE;
+	} else if (tcode == TCODE_READ_QUADLET_REQUEST) {
+		return RCODE_COMPLETE;
+	} else {
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static void tgt_agent_rw(struct fw_card *card,
+	struct fw_request *request, int tcode, int destination, int source,
+	int generation, unsigned long long offset, void *data, size_t length,
+	void *callback_data)
+{
+	struct sbp_target_agent *agent = callback_data;
+	int rcode = RCODE_ADDRESS_ERROR;
+
+	/* turn offset into the offset from the start of the block */
+	offset -= agent->handler.offset;
+
+	/* check the source matches the login */
+	if (source != agent->login->sess->node_id) {
+		pr_notice("ignoring request from foreign node (%x != %x)\n",
+			source, agent->login->sess->node_id);
+		fw_send_response(card, request, RCODE_TYPE_ERROR);
+		return;
+	}
+
+	if (offset == 0x00 && length == 4) {
+		/* AGENT_STATE */
+		rcode = tgt_agent_rw_agent_state(card, tcode,
+			generation, data, agent);
+	} else if (offset == 0x04 && length == 4) {
+		/* AGENT_RESET */
+		rcode = tgt_agent_rw_agent_reset(card, tcode,
+			generation, data, agent);
+	} else if (offset == 0x08 && length == 8) {
+		/* ORB_POINTER */
+		rcode = tgt_agent_rw_orb_pointer(card, tcode,
+			generation, data, agent);
+	} else if (offset == 0x10 && length == 4) {
+		/* DOORBELL */
+		rcode = tgt_agent_rw_doorbell(card, tcode,
+			generation, data, agent);
+	} else if (offset == 0x14 && length == 4) {
+		/* UNSOLICITED_STATUS_ENABLE */
+		rcode = tgt_agent_rw_unsolicited_status_enable(card, tcode,
+			generation, data, agent);
+	}
+
+	fw_send_response(card, request, rcode);
+}
+
+static void tgt_agent_process_work(struct work_struct *work)
+{
+	struct sbp_target_request *req =
+		container_of(work, struct sbp_target_request, work);
+
+	switch (ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc))) {
+	case 0:/* Format specified by this standard */
+		sbp_handle_command(req);
+		return;
+	case 1: /* Reserved for future standardization */
+	case 2: /* Vendor-dependent */
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	case 3: /* Dummy ORB */
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_DUMMY_ORB_COMPLETE));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	default:
+		BUG();
+	}
+}
+
+static void tgt_agent_fetch_work(struct work_struct *work)
+{
+	struct sbp_target_agent *agent =
+		container_of(work, struct sbp_target_agent, work);
+	struct sbp_session *sess = agent->login->sess;
+	struct sbp_target_request *req;
+	int ret;
+
+	smp_rmb();
+	if (atomic_read(&agent->state) != AGENT_STATE_ACTIVE)
+		return;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req)
+		goto out;
+
+	smp_rmb();
+	if (atomic_read(&agent->state) != AGENT_STATE_ACTIVE) {
+		sbp_free_request(req);
+		return;
+	}
+
+	/* read in the ORB */
+	ret = fw_run_transaction(sess->card, TCODE_READ_BLOCK_REQUEST,
+		sess->node_id, sess->generation, sess->speed,
+		agent->orb_pointer, &req->orb, sizeof(req->orb));
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("tgt_orb fetch failed: %x\n", ret);
+		sbp_free_request(req);
+		goto out;
+	}
+
+	smp_rmb();
+	if (atomic_read(&agent->state) != AGENT_STATE_ACTIVE) {
+		sbp_free_request(req);
+		return;
+	}
+
+	req->agent = agent;
+	req->orb_pointer = agent->orb_pointer;
+
+	pr_debug("tgt_orb ptr:0x%llx next_orb:0x%llx data_descriptor:0x%llx misc:0x%x\n",
+			req->orb_pointer,
+			sbp2_pointer_to_addr(&req->orb.next_orb),
+			sbp2_pointer_to_addr(&req->orb.data_descriptor),
+			be32_to_cpu(req->orb.misc));
+
+	if (be32_to_cpu(req->orb.next_orb.high) & 0x80000000) {
+		req->status.status = cpu_to_be32(
+				STATUS_BLOCK_SRC(STATUS_SRC_ORB_FINISHED));
+	} else {
+		req->status.status = cpu_to_be32(
+				STATUS_BLOCK_SRC(STATUS_SRC_ORB_CONTINUING));
+	}
+
+	req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_ORB_OFFSET_HIGH(agent->orb_pointer >> 32));
+	req->status.orb_low = cpu_to_be32(agent->orb_pointer & 0xfffffffc);
+	INIT_WORK(&req->work, tgt_agent_process_work);
+
+	ret = queue_work(fw_workqueue, &req->work);
+	if (!ret) {
+		pr_err("tgt_orb queue_work failed\n");
+		sbp_free_request(req);
+		goto out;
+	}
+
+	/* check if we should carry on processing */
+	if (be32_to_cpu(req->orb.next_orb.high) & 0x80000000) {
+		/* null next_orb */
+		goto out;
+	}
+
+	smp_rmb();
+	if (atomic_read(&agent->state) != AGENT_STATE_ACTIVE)
+		return;
+
+	agent->orb_pointer = sbp2_pointer_to_addr(&req->orb.next_orb);
+
+	if (!queue_work(fw_workqueue, &agent->work)) {
+		pr_err("tgt_orb fetch queue_work failed\n");
+		goto out;
+	}
+
+	return;
+
+out:
+	/* finished */
+	atomic_cmpxchg(&agent->state,
+		AGENT_STATE_ACTIVE, AGENT_STATE_SUSPENDED);
+}
+
+struct sbp_target_agent *sbp_target_agent_register(
+		struct sbp_login_descriptor *login)
+{
+	struct sbp_target_agent *agent;
+	int ret;
+
+	agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+	if (!agent)
+		return ERR_PTR(-ENOMEM);
+
+	agent->handler.length = 0x20;
+	agent->handler.address_callback = tgt_agent_rw;
+	agent->handler.callback_data = agent;
+
+	agent->login = login;
+	atomic_set(&agent->state, AGENT_STATE_RESET);
+	INIT_WORK(&agent->work, tgt_agent_fetch_work);
+	agent->orb_pointer = (u64)-1;
+
+	ret = fw_core_add_address_handler(&agent->handler,
+		&sbp_register_region);
+	if (ret < 0) {
+		kfree(agent);
+		return ERR_PTR(ret);
+	}
+
+	return agent;
+}
+
+void sbp_target_agent_unregister(struct sbp_target_agent *agent)
+{
+	if (atomic_read(&agent->state) == AGENT_STATE_ACTIVE)
+		flush_work_sync(&agent->work);
+
+	fw_core_remove_address_handler(&agent->handler);
+	kfree(agent);
+}
+
diff --git a/drivers/target/sbp/sbp_target_agent.h b/drivers/target/sbp/sbp_target_agent.h
new file mode 100644
index 0000000..870b901
--- /dev/null
+++ b/drivers/target/sbp/sbp_target_agent.h
@@ -0,0 +1,30 @@
+
+struct sbp_target_agent {
+	struct fw_address_handler handler;
+	struct sbp_login_descriptor *login;
+	atomic_t state;
+	struct work_struct work;
+	u64 orb_pointer;
+};
+
+struct sbp_target_request {
+	struct sbp_target_agent *agent;
+	u64 orb_pointer;
+	struct sbp_command_block_orb orb;
+	struct sbp_status_block status;
+	struct work_struct work;
+
+	struct se_cmd se_cmd;
+	struct sbp_page_table_entry *pg_tbl;
+	void *cmd_buf;
+	int unpacked_lun;
+	u32 data_len;
+	enum dma_data_direction	data_dir;
+	void *data_buf;
+
+	unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+struct sbp_target_agent *sbp_target_agent_register(
+		struct sbp_login_descriptor *login);
+void sbp_target_agent_unregister(struct sbp_target_agent *agent);
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 11/13] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h}
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (9 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 10/13] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 12/13] firewire-sbp-target: Add sbp_util.{c,h} Chris Boot
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

Miscellaneous functions for dealing with SCSI commands, status, sense
data and data read/write. This is where the real grunt work of pushing
data in and out of the FireWire bus happens.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_scsi_cmnd.c |  357 ++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_scsi_cmnd.h |    6 +
 2 files changed, 363 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_scsi_cmnd.c
 create mode 100644 drivers/target/sbp/sbp_scsi_cmnd.h

diff --git a/drivers/target/sbp/sbp_scsi_cmnd.c b/drivers/target/sbp/sbp_scsi_cmnd.c
new file mode 100644
index 0000000..ca94a28
--- /dev/null
+++ b/drivers/target/sbp/sbp_scsi_cmnd.c
@@ -0,0 +1,357 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+
+#include "sbp_base.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+#include "sbp_util.h"
+
+/*
+ * Wraps fw_run_transaction taking into account page size and max payload, and
+ * retries the transaction if it fails
+ */
+static int sbp_run_transaction(struct sbp_target_request *req, int tcode,
+	unsigned long long offset, void *payload, size_t length)
+{
+	struct sbp_login_descriptor *login = req->agent->login;
+	struct sbp_session *sess = login->sess;
+	int ret, speed, max_payload, pg_size, seg_off = 0, seg_len;
+
+	speed = CMDBLK_ORB_SPEED(be32_to_cpu(req->orb.misc));
+	max_payload = 4 << CMDBLK_ORB_MAX_PAYLOAD(be32_to_cpu(req->orb.misc));
+	pg_size = CMDBLK_ORB_PG_SIZE(be32_to_cpu(req->orb.misc));
+
+	if (pg_size) {
+		pr_err("sbp_run_transaction: page size ignored\n");
+		pg_size = 0x100 << pg_size;
+	}
+
+	while (seg_off < length) {
+		seg_len = length - seg_off;
+		if (seg_len > max_payload)
+			seg_len = max_payload;
+
+		/* FIXME: take page_size into account */
+
+		/* FIXME: retry failed data transfers */
+		ret = fw_run_transaction(sess->card, tcode,
+				sess->node_id, sess->generation, speed,
+				offset + seg_off, payload + seg_off, seg_len);
+		if (ret != RCODE_COMPLETE) {
+			pr_debug("sbp_run_transaction: txn failed: %x\n", ret);
+			return -EIO;
+		}
+
+		seg_off += seg_len;
+	}
+
+	return 0;
+}
+
+static int sbp_fetch_command(struct sbp_target_request *req)
+{
+	int ret, cmd_len, copy_len;
+
+	cmd_len = scsi_command_size(req->orb.command_block);
+
+	req->cmd_buf = kmalloc(cmd_len, GFP_KERNEL);
+	if (!req->cmd_buf)
+		return -ENOMEM;
+
+	memcpy(req->cmd_buf, req->orb.command_block,
+		min_t(int, cmd_len, sizeof(req->orb.command_block)));
+
+	if (cmd_len > sizeof(req->orb.command_block)) {
+		pr_debug("sbp_fetch_command: filling in long command\n");
+		copy_len = cmd_len - sizeof(req->orb.command_block);
+
+		ret = sbp_run_transaction(req, TCODE_READ_BLOCK_REQUEST,
+			req->orb_pointer + sizeof(req->orb),
+			req->cmd_buf + sizeof(req->orb.command_block), cmd_len);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int sbp_fetch_page_table(struct sbp_target_request *req)
+{
+	int pg_tbl_sz, ret;
+	struct sbp_page_table_entry *pg_tbl;
+
+	if (!CMDBLK_ORB_PG_TBL_PRESENT(be32_to_cpu(req->orb.misc)))
+		return 0;
+
+	pg_tbl_sz = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc)) *
+		sizeof(struct sbp_page_table_entry);
+
+	pg_tbl = kmalloc(pg_tbl_sz, GFP_KERNEL);
+	if (!pg_tbl)
+		return -ENOMEM;
+
+	ret = sbp_run_transaction(req, TCODE_READ_BLOCK_REQUEST,
+		sbp2_pointer_to_addr(&req->orb.data_descriptor),
+		pg_tbl, pg_tbl_sz);
+	if (ret) {
+		kfree(pg_tbl);
+		return ret;
+	}
+
+	req->pg_tbl = pg_tbl;
+	return 0;
+}
+
+static void sbp_calc_data_length_direction(struct sbp_target_request *req)
+{
+	int data_size, direction, idx;
+
+	data_size = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+	direction = CMDBLK_ORB_DIRECTION(be32_to_cpu(req->orb.misc));
+
+	if (!data_size) {
+		req->data_len = 0;
+		req->data_dir = DMA_NONE;
+		return;
+	}
+
+	req->data_dir = direction ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+	if (req->pg_tbl) {
+		req->data_len = 0;
+		for (idx = 0; idx < data_size; idx++) {
+			req->data_len += be16_to_cpu(
+					req->pg_tbl[idx].segment_length);
+		}
+	} else {
+		req->data_len = data_size;
+	}
+}
+
+void sbp_handle_command(struct sbp_target_request *req)
+{
+	struct sbp_login_descriptor *login = req->agent->login;
+	struct sbp_session *sess = login->sess;
+	int ret;
+
+	ret = sbp_fetch_command(req);
+	if (ret) {
+		pr_debug("sbp_handle_command: fetch command failed: %d\n", ret);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	}
+
+	ret = sbp_fetch_page_table(req);
+	if (ret) {
+		pr_debug("sbp_handle_command: fetch page table failed: %d\n",
+			ret);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	}
+
+	req->unpacked_lun = req->agent->login->lun->unpacked_lun;
+	sbp_calc_data_length_direction(req);
+
+	pr_debug("sbp_handle_command unpacked_lun:%d data_len:%d "
+		"data_dir:%d\n", req->unpacked_lun, req->data_len,
+		req->data_dir);
+
+	target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf,
+			req->sense_buf, req->unpacked_lun, 0, MSG_SIMPLE_TAG,
+			req->data_dir, TARGET_SCF_UNKNOWN_SIZE);
+}
+
+/*
+ * DMA_TO_DEVICE = read from initiator (SCSI WRITE)
+ * DMA_FROM_DEVICE = write to initiator (SCSI READ)
+ */
+int sbp_rw_data(struct sbp_target_request *req)
+{
+	int ret;
+
+	WARN_ON(!req->data_len);
+
+	if (req->pg_tbl) {
+		int idx, offset = 0, data_size;
+
+		data_size = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+
+		for (idx = 0; idx < data_size; idx++) {
+			int pte_len = be16_to_cpu(
+				req->pg_tbl[idx].segment_length);
+			u64 pte_offset = (u64)be16_to_cpu(
+				req->pg_tbl[idx].segment_base_hi) << 32 |
+				be32_to_cpu(req->pg_tbl[idx].segment_base_lo);
+
+			ret = sbp_run_transaction(req,
+				(req->data_dir == DMA_TO_DEVICE) ?
+				TCODE_READ_BLOCK_REQUEST :
+				TCODE_WRITE_BLOCK_REQUEST,
+				pte_offset, req->data_buf + offset, pte_len);
+			if (ret)
+				break;
+
+			offset += pte_len;
+		}
+	} else {
+		ret = sbp_run_transaction(req,
+			(req->data_dir == DMA_TO_DEVICE) ?
+			TCODE_READ_BLOCK_REQUEST : TCODE_WRITE_BLOCK_REQUEST,
+			sbp2_pointer_to_addr(&req->orb.data_descriptor),
+			req->data_buf, req->data_len);
+	}
+
+	return ret;
+}
+
+int sbp_send_status(struct sbp_target_request *req)
+{
+	int ret, length;
+	struct sbp_login_descriptor *login = req->agent->login;
+
+	/* calculate how much data to send */
+	length = (((be32_to_cpu(req->status.status) >> 24) & 0x07) + 1) * 4;
+
+	ret = sbp_run_transaction(req, TCODE_WRITE_BLOCK_REQUEST,
+		login->status_fifo_addr, &req->status, length);
+	if (ret) {
+		pr_debug("sbp_send_status: write failed: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void sbp_sense_mangle(struct sbp_target_request *req)
+{
+	struct se_cmd *se_cmd = &req->se_cmd;
+	u8 *sense = req->sense_buf;
+	u8 *status = req->status.data;
+
+	WARN_ON(se_cmd->scsi_sense_length < 18);
+
+	switch (sense[0] & 0x7f) {
+	case 0x70:
+		status[0] = 0 << 6;		/* sfmt */
+		break;
+	case 0x71:
+		status[0] = 1 << 6;		/* sfmt */
+		break;
+	default:
+		/*
+		 * TODO: SBP-3 specifies what we should do with descriptor
+		 * format sense data
+		 */
+		pr_err("sbp_send_sense: unknown sense format: 0x%x\n",
+			sense[0]);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQUEST_ABORTED));
+		return;
+	}
+
+	status[0] |= se_cmd->scsi_status & 0x3f;/* status */
+	status[1] =
+		(sense[0] & 0x80) |		/* valid */
+		((sense[2] & 0xe0) >> 1) |	/* mark, eom, ili */
+		(sense[2] & 0x0f);		/* sense_key */
+	status[2] = se_cmd->scsi_asc;		/* sense_code */
+	status[3] = se_cmd->scsi_ascq;		/* sense_qualifier */
+
+	/* information */
+	status[4] = sense[3];
+	status[5] = sense[4];
+	status[6] = sense[5];
+	status[7] = sense[6];
+
+	/* CDB-dependent */
+	status[8] = sense[8];
+	status[9] = sense[9];
+	status[10] = sense[10];
+	status[11] = sense[11];
+
+	/* fru */
+	status[12] = sense[14];
+
+	/* sense_key-dependent */
+	status[13] = sense[15];
+	status[14] = sense[16];
+	status[15] = sense[17];
+
+	req->status.status |= cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_DEAD(0) |
+		STATUS_BLOCK_LEN(5) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+int sbp_send_sense(struct sbp_target_request *req)
+{
+	struct se_cmd *se_cmd = &req->se_cmd;
+
+	if (se_cmd->scsi_sense_length) {
+		sbp_sense_mangle(req);
+	} else {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+	}
+
+	return sbp_send_status(req);
+}
+
+void sbp_free_request(struct sbp_target_request *req)
+{
+	kfree(req->pg_tbl);
+	kfree(req->cmd_buf);
+	kfree(req->data_buf);
+	kfree(req);
+}
diff --git a/drivers/target/sbp/sbp_scsi_cmnd.h b/drivers/target/sbp/sbp_scsi_cmnd.h
new file mode 100644
index 0000000..5e82b25
--- /dev/null
+++ b/drivers/target/sbp/sbp_scsi_cmnd.h
@@ -0,0 +1,6 @@
+
+void sbp_handle_command(struct sbp_target_request *req);
+int sbp_rw_data(struct sbp_target_request *req);
+int sbp_send_status(struct sbp_target_request *req);
+int sbp_send_sense(struct sbp_target_request *req);
+void sbp_free_request(struct sbp_target_request *req);
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 12/13] firewire-sbp-target: Add sbp_util.{c,h}
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (10 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 11/13] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h} Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-11 19:44   ` [PATCH 13/13] firewire-sbp-target: Add to target Kconfig and Makefile Chris Boot
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

Common helper functions and global declarations.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_util.c |   36 ++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_util.h |   15 +++++++++++++++
 2 files changed, 51 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_util.c
 create mode 100644 drivers/target/sbp/sbp_util.h

diff --git a/drivers/target/sbp/sbp_util.c b/drivers/target/sbp/sbp_util.c
new file mode 100644
index 0000000..33073b1
--- /dev/null
+++ b/drivers/target/sbp/sbp_util.c
@@ -0,0 +1,36 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+
+#include <target/target_core_base.h>
+
+#include "sbp_base.h"
+#include "sbp_util.h"
+
+const struct fw_address_region sbp_register_region = {
+	.start = CSR_REGISTER_BASE + 0x10000,
+	.end   = 0x1000000000000ULL,
+};
+
diff --git a/drivers/target/sbp/sbp_util.h b/drivers/target/sbp/sbp_util.h
new file mode 100644
index 0000000..cd3e00d
--- /dev/null
+++ b/drivers/target/sbp/sbp_util.h
@@ -0,0 +1,15 @@
+
+extern const struct fw_address_region sbp_register_region;
+
+static inline u64 sbp2_pointer_to_addr(const struct sbp2_pointer *ptr)
+{
+	return (u64)(be32_to_cpu(ptr->high) & 0x0000ffff) << 32 |
+		(be32_to_cpu(ptr->low) & 0xfffffffc);
+}
+
+static inline void addr_to_sbp2_pointer(u64 addr, struct sbp2_pointer *ptr)
+{
+	ptr->high = cpu_to_be32(addr >> 32);
+	ptr->low = cpu_to_be32(addr);
+}
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 13/13] firewire-sbp-target: Add to target Kconfig and Makefile
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (11 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 12/13] firewire-sbp-target: Add sbp_util.{c,h} Chris Boot
@ 2012-02-11 19:44   ` Chris Boot
  2012-02-12 14:12   ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Stefan Richter
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
  14 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-11 19:44 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This commit also adds an entry to the MAINTAINERS file.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 MAINTAINERS             |    9 +++++++++
 drivers/target/Kconfig  |    1 +
 drivers/target/Makefile |    1 +
 3 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index c0f348d..252aa72 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2695,6 +2695,15 @@ T:	git git://git.alsa-project.org/alsa-kernel.git
 S:	Maintained
 F:	sound/firewire/
 
+FIREWIRE SBP-2 TARGET
+M:  Chris Boot <bootc@bootc.net>
+L:  linux-scsi@vger.kernel.org
+L:  target-devel@vger.kernel.org
+L:  linux1394-devel@lists.sourceforge.net
+T:  git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
+S:  Maintained
+F:  drivers/target/sbp/
+
 FIREWIRE SUBSYSTEM
 M:	Stefan Richter <stefanr@s5r6.in-berlin.de>
 L:	linux1394-devel@lists.sourceforge.net
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
index fc5fa9f..2cfa467 100644
--- a/drivers/target/Kconfig
+++ b/drivers/target/Kconfig
@@ -41,5 +41,6 @@ source "drivers/target/tcm_fc/Kconfig"
 source "drivers/target/iscsi/Kconfig"
 source "drivers/target/tcm_vhost/Kconfig"
 source "drivers/target/usb-gadget/Kconfig"
+source "drivers/target/sbp/Kconfig"
 
 endif
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 6b5f526..1ae8862 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_TCM_FC)		+= tcm_fc/
 obj-$(CONFIG_ISCSI_TARGET)	+= iscsi/
 obj-$(CONFIG_TCM_VHOST)		+= tcm_vhost/
 obj-$(CONFIG_TARGET_USB_GADGET)	+= usb-gadget/
+obj-$(CONFIG_FIREWIRE_SBP_TARGET) += sbp/
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* Re: [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (12 preceding siblings ...)
  2012-02-11 19:44   ` [PATCH 13/13] firewire-sbp-target: Add to target Kconfig and Makefile Chris Boot
@ 2012-02-12 14:12   ` Stefan Richter
  2012-02-12 15:13     ` Chris Boot
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
  14 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-12 14:12 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 11 Chris Boot wrote:
> Well after lots of work I have a working and generally (at least I think)
> sensible starting point for the FireWire target. It appears to work fine in all
> the configurations I've tested it against, including Linux and Mac OS X
> initiators.

I only very quickly scrolled through your patches yet.  Looks all very
readable and well laid out.  Some random thoughts:

Some of the smaller source files could certainly be merged with other
ones without loss of readability.

Some comments about what the code is doing can be removed since the
function names are very well readable on their own.  Example:
+	/* read the peer's GUID */
+	ret = read_peer_guid(&guid, req);

The APIs which you include from "../../firewire/core.h" should eventually
be moved to <linux/firewire.h>.  I think it does not matter whether this
is done before or after mainline merge.  When we do so we should check
whether the affected APIs can be improved for usage in drivers.

Many of the printks should surely be demoted to debug messages with
runtime on-and-off switch.

There are list traversals and list manipulations that make an impression
as if they wanted to be mutex- or lock-protected, but I haven't looked yet
in which contexts these accesses happen.

sbp_proto.c:
+/*
+ * Handlers for Serial Attached SCSI (SBP)
+ */
                 ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ Serial Bus Protocol
Though this is also readily apparent from the top comment in the file.

The four EXPORT_SYMBOLs in sbp_proto.c can be removed, it seems.

sbp_login.c:
+			pr_notice("initiator already logged-in\n");
+
+			/*
+			 * SBP-2 R4 says we should return access denied, but
+			 * that can confuse initiators. Instead we need to
+			 * treat this like a reconnect, but send the login
+			 * response block like a fresh login.
+			 */
Are there initiators which don't bother with reconnect but send relogin
straight away?

Kconfig:
"default n" is redundant.
"*older* Apple computers":  They are still manufactured with this feature.
-- 
Stefan Richter
-=====-===-- --=- -==--
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-02-12 14:12   ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Stefan Richter
@ 2012-02-12 15:13     ` Chris Boot
  2012-02-12 16:16       ` Stefan Richter
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-12 15:13 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 12/02/2012 14:12, Stefan Richter wrote:
> On Feb 11 Chris Boot wrote:
>> Well after lots of work I have a working and generally (at least I think)
>> sensible starting point for the FireWire target. It appears to work fine in all
>> the configurations I've tested it against, including Linux and Mac OS X
>> initiators.
>
> I only very quickly scrolled through your patches yet.  Looks all very
> readable and well laid out.  Some random thoughts:

Thanks for taking a look!

> Some of the smaller source files could certainly be merged with other
> ones without loss of readability.

Yes, definitely.

> Some comments about what the code is doing can be removed since the
> function names are very well readable on their own.  Example:
> +	/* read the peer's GUID */
> +	ret = read_peer_guid(&guid, req);

Guilty as charged. I'll go through and clean this up.

> The APIs which you include from "../../firewire/core.h" should eventually
> be moved to<linux/firewire.h>.  I think it does not matter whether this
> is done before or after mainline merge.  When we do so we should check
> whether the affected APIs can be improved for usage in drivers.

I'm not even sure I use that much from there at all. Possibly only 
fw_card_{get,put,release}(), so that could quite easily be moved into 
<linux/firewire.h>.

> Many of the printks should surely be demoted to debug messages with
> runtime on-and-off switch.

I've moved a lot of them to pr_debug() which doesn't emit anything 
unless you ask it to. Are there others you think should be pr_debug() 
that aren't?

> There are list traversals and list manipulations that make an impression
> as if they wanted to be mutex- or lock-protected, but I haven't looked yet
> in which contexts these accesses happen.

Yes this is what I'm most concerned about but it's an area I know very 
little about. Some hand-holding would be appreciated.

> sbp_proto.c:
> +/*
> + * Handlers for Serial Attached SCSI (SBP)
> + */
>                   ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ Serial Bus Protocol
> Though this is also readily apparent from the top comment in the file.

Hah. Can you tell where I copied and pasted from? :-) Fixed.

> The four EXPORT_SYMBOLs in sbp_proto.c can be removed, it seems.

Another copy & paste leftover. Also fixed.

> sbp_login.c:
> +			pr_notice("initiator already logged-in\n");
> +
> +			/*
> +			 * SBP-2 R4 says we should return access denied, but
> +			 * that can confuse initiators. Instead we need to
> +			 * treat this like a reconnect, but send the login
> +			 * response block like a fresh login.
> +			 */
> Are there initiators which don't bother with reconnect but send relogin
> straight away?

I found my PowerBook did. It looks like when OpenFirmware hands over to 
Darwin, the latter just does a login. I changed this before I had the 
code to expire sessions once the reconnect timeout expires though so 
it's probably unnecessary now but it would slow down the boot by several 
seconds.

> Kconfig:
> "default n" is redundant.
> "*older* Apple computers":  They are still manufactured with this feature.

I thought all the newer ones only did this over Thunderbolt and not 
FireWire? I'm more than happy to change this though.

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-02-12 15:13     ` Chris Boot
@ 2012-02-12 16:16       ` Stefan Richter
  0 siblings, 0 replies; 104+ messages in thread
From: Stefan Richter @ 2012-02-12 16:16 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 12 Chris Boot wrote:
> On 12/02/2012 14:12, Stefan Richter wrote:
> > The APIs which you include from "../../firewire/core.h" should eventually
> > be moved to<linux/firewire.h>.  I think it does not matter whether this
> > is done before or after mainline merge.  When we do so we should check
> > whether the affected APIs can be improved for usage in drivers.
> 
> I'm not even sure I use that much from there at all. Possibly only 
> fw_card_{get,put,release}(), so that could quite easily be moved into 
> <linux/firewire.h>.

Yes, I suppose this is just the card reference counting which we found
is needed for some types of userspace drivers too.  But for them it is
wrapped up in the core-cdev.c glue, thus still core-internal presently.

> > Many of the printks should surely be demoted to debug messages with
> > runtime on-and-off switch.
> 
> I've moved a lot of them to pr_debug() which doesn't emit anything 
> unless you ask it to. Are there others you think should be pr_debug() 
> that aren't?

OK, could have been a wrong impression after superficial reading.

[...]
> > sbp_login.c:
> > +			pr_notice("initiator already logged-in\n");
> > +
> > +			/*
> > +			 * SBP-2 R4 says we should return access denied, but
> > +			 * that can confuse initiators. Instead we need to
> > +			 * treat this like a reconnect, but send the login
> > +			 * response block like a fresh login.
> > +			 */
> > Are there initiators which don't bother with reconnect but send relogin
> > straight away?
> 
> I found my PowerBook did. It looks like when OpenFirmware hands over to 
> Darwin, the latter just does a login. I changed this before I had the 
> code to expire sessions once the reconnect timeout expires though so 
> it's probably unnecessary now but it would slow down the boot by several 
> seconds.

Right, this is a special case.  I remember this as an issue with Linux on
Apple PCs as well, together with a particular harddisk firmware with
somewhat unusual timing characteristics, which rejects firewire-sbp2's
login because it still considers the firmware's login valid.  The former
ieee1394 + sbp2 stack had more luck, but probably just because of slightly
different timing on their part.

You could make this a special case for initiators with Apple's OUI in
the EUI-64.  But I suppose there is no real downside to do this
unconditionally.

Anyway, the case of Apple firmware login -> OS login handover could
certainly be mentioned in the quoted comment, as the one quite common case
where this deviation from the spec is required or at least beneficial.

> > Kconfig:
> > "default n" is redundant.
> > "*older* Apple computers":  They are still manufactured with this feature.
> 
> I thought all the newer ones only did this over Thunderbolt and not 
> FireWire? I'm more than happy to change this though.

Oh, I don't actually know about these ones.
-- 
Stefan Richter
-=====-===-- --=- -==--
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH 03/13] firewire-sbp-target: Add Kconfig, Makefile and TODO
  2012-02-11 19:44   ` [PATCH 03/13] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
@ 2012-02-13 12:50     ` Nicholas A. Bellinger
  0 siblings, 0 replies; 104+ messages in thread
From: Nicholas A. Bellinger @ 2012-02-13 12:50 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, stefanr

On Sat, 2012-02-11 at 19:44 +0000, Chris Boot wrote:
> The FireWire SBP-2 Target is a driver for using an IEEE-1394 connection
> as a SCSI transport. This module uses the SCSI Target framework to
> expose LUNs to other machines attached to a FireWire bus, in effect
> acting as a FireWire hard disk similar to FireWire Target Disk mode on
> older Apple computers.
> 
> Signed-off-by: Chris Boot <bootc@bootc.net>
> Cc: Andy Grover <agrover@redhat.com>
> Cc: Clemens Ladisch <clemens@ladisch.de>
> Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
> Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
> ---
>  drivers/target/sbp/Kconfig  |   14 ++++++++++++++
>  drivers/target/sbp/Makefile |   13 +++++++++++++
>  drivers/target/sbp/TODO     |    7 +++++++
>  3 files changed, 34 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/target/sbp/Kconfig
>  create mode 100644 drivers/target/sbp/Makefile
>  create mode 100644 drivers/target/sbp/TODO
> 
> diff --git a/drivers/target/sbp/Kconfig b/drivers/target/sbp/Kconfig
> new file mode 100644
> index 0000000..8544010
> --- /dev/null
> +++ b/drivers/target/sbp/Kconfig
> @@ -0,0 +1,14 @@
> +
> +config FIREWIRE_SBP_TARGET
> +	tristate "FireWire SBP-2 fabric module"
> +	depends on TARGET_CORE && CONFIGFS_FS && FIREWIRE && EXPERIMENTAL
> +	default n
> +	help
> +	  Say Y or M here to enable SCSI target functionality over FireWire.
> +	  This enables you to expose SCSI devices to other nodes on the FireWire
> +	  bus, for example hard disks. Similar to FireWire Target Disk mode on
> +	  older Apple computers.
> +
> +	  To compile this driver as a module, say M here: The module will be
> +	  called firewire-sbp-target.
> +

Hi Chris,

Just a minor Kconfig related item here.  You can go ahead and drop the
extra depends on TARGET_CORE && CONFIGFS_FS here, as
drivers/target/Kconfig is already handling the dependencies for these
two config options before including drivers/target/sbp/Kconfig.

Thanks!

--nab


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH 06/13] firewire-sbp-target: Add sbp_fabric.{c,h}
  2012-02-11 19:44   ` [PATCH 06/13] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
@ 2012-02-13 13:06     ` Nicholas A. Bellinger
       [not found]       ` <337FFBD7-6B4A-41CA-BB57-6038C935B5BF@bootc.net>
  0 siblings, 1 reply; 104+ messages in thread
From: Nicholas A. Bellinger @ 2012-02-13 13:06 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, stefanr

On Sat, 2012-02-11 at 19:44 +0000, Chris Boot wrote:
> This serves as further glue between the target framework and SBP-2, in
> this case dealing with SCSI command submission and data in/out.
> 
> Signed-off-by: Chris Boot <bootc@bootc.net>
> Cc: Andy Grover <agrover@redhat.com>
> Cc: Clemens Ladisch <clemens@ladisch.de>
> Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
> Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
> ---
>  drivers/target/sbp/sbp_fabric.c |  321 +++++++++++++++++++++++++++++++++++++++
>  drivers/target/sbp/sbp_fabric.h |   32 ++++
>  2 files changed, 353 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/target/sbp/sbp_fabric.c
>  create mode 100644 drivers/target/sbp/sbp_fabric.h
> 
> diff --git a/drivers/target/sbp/sbp_fabric.c b/drivers/target/sbp/sbp_fabric.c
> new file mode 100644
> index 0000000..edc6fda
> --- /dev/null
> +++ b/drivers/target/sbp/sbp_fabric.c
> @@ -0,0 +1,321 @@
> +/*
> + * SBP2 target driver (SCSI over IEEE1394 in target mode)
> + *
> + * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +

<SNIP>

> +int sbp_new_cmd(struct se_cmd *se_cmd)
> +{
> +	struct sbp_target_request *req = container_of(se_cmd,
> +			struct sbp_target_request, se_cmd);
> +	int ret;
> +
> +	ret = transport_generic_allocate_tasks(se_cmd, req->cmd_buf);
> +	if (ret)
> +		return ret;
> +
> +	return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
> +}
> +

Because sbp_scsi_cmnd.c:sbp_handle_command() is using the new
target_submit_cmd() logic, target-core will not be calling
TFO->new_cmd_map() -> sbp_new_cmd() for setup here.

Go ahead and drop this now.

> +
> +u32 sbp_get_task_tag(struct se_cmd *se_cmd)
> +{
> +	struct sbp_target_request *req = container_of(se_cmd,
> +			struct sbp_target_request, se_cmd);
> +
> +	/* only used for printk and family? */
> +	return (u32)req->orb_pointer;
> +}
> +

So an the ABORT_TASK TMR patches use TFO->get_task_tag() to locate a
referenced tag to locate the se_cmd descriptor.  Since we don't
support TMRs yet in sbp, this value will only be used for informational
purposes.

> +
> +int sbp_queue_data_in(struct se_cmd *se_cmd)
> +{
> +	struct sbp_target_request *req = container_of(se_cmd,
> +			struct sbp_target_request, se_cmd);
> +	int ret;
> +
> +	if (!req->data_len) {
> +		req->status.status |= cpu_to_be32(
> +			STATUS_BLOCK_RESP(STATUS_RESP_ILLEGAL_REQUEST) |
> +			STATUS_BLOCK_DEAD(0) |
> +			STATUS_BLOCK_LEN(1) |
> +			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
> +		sbp_send_status(req);
> +		pr_err("sbp_queue_data_in: no initiator data buffers\n");
> +		return 0;
> +	}
> +
> +	if (req->data_dir != DMA_FROM_DEVICE) {
> +		pr_err("sbp_queue_data_in: incorrect data direction\n");
> +		return -EINVAL;
> +	}
> +
> +	if (req->data_len != se_cmd->data_length) {
> +		pr_warn("sbp_write_pending: dodgy data length (%d != %d)\n",
> +			req->data_len, se_cmd->data_length);
> +	}
> +
> +	req->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
> +	if (!req->data_buf)
> +		return -ENOMEM;
> +
> +	sg_copy_to_buffer(se_cmd->t_data_sg,
> +		se_cmd->t_data_nents,
> +		req->data_buf,
> +		se_cmd->data_length);
> +
> +	ret = sbp_rw_data(req);
> +	if (ret) {
> +		req->status.status |= cpu_to_be32(
> +			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
> +			STATUS_BLOCK_DEAD(0) |
> +			STATUS_BLOCK_LEN(1) |
> +			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
> +		sbp_send_status(req);
> +		return ret;
> +	}
> +
> +	return sbp_send_sense(req);
> +}
> +
> +/*
> + * Called after command (no data transfer) or after the write (to device)
> + * operation is completed
> + */
> +int sbp_queue_status(struct se_cmd *se_cmd)
> +{
> +	struct sbp_target_request *req = container_of(se_cmd,
> +			struct sbp_target_request, se_cmd);
> +
> +	return sbp_send_sense(req);
> +}
> +

Thanks!

--nab


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH 06/13] firewire-sbp-target: Add sbp_fabric.{c,h}
       [not found]       ` <337FFBD7-6B4A-41CA-BB57-6038C935B5BF@bootc.net>
@ 2012-02-13 19:53         ` Stefan Richter
  2012-02-13 22:41         ` Nicholas A. Bellinger
  1 sibling, 0 replies; 104+ messages in thread
From: Stefan Richter @ 2012-02-13 19:53 UTC (permalink / raw)
  To: Chris Boot
  Cc: Nicholas A. Bellinger, linux1394-devel, target-devel,
	linux-kernel, agrover, clemens

On Feb 13 Chris Boot wrote:
> I'd like to support ABORT_TASK and friends at some point. The problem
> I see here though is that tags in SBP-2/3 are 48-bits wide (the ORB
> address in the initiator node's memory), and the target framework seems
> to use a u32 for this. SAM-3 Section 4.11 seems to say "A task tag is a
> value that is composed of up to 64 bits" so it might be worth getting
> that changed in the target framework?

In practice, its is quite likely that only 32 bit wide SBP tags are being
used.  But there is no way to guarantee this.
-- 
Stefan Richter
-=====-===-- --=- -==-=
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH 06/13] firewire-sbp-target: Add sbp_fabric.{c,h}
       [not found]       ` <337FFBD7-6B4A-41CA-BB57-6038C935B5BF@bootc.net>
  2012-02-13 19:53         ` Stefan Richter
@ 2012-02-13 22:41         ` Nicholas A. Bellinger
  1 sibling, 0 replies; 104+ messages in thread
From: Nicholas A. Bellinger @ 2012-02-13 22:41 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, stefanr

On Mon, 2012-02-13 at 14:01 +0000, Chris Boot wrote:
> On 13 Feb 2012, at 13:06, Nicholas A. Bellinger wrote:
> 
> > On Sat, 2012-02-11 at 19:44 +0000, Chris Boot wrote:
> >> This serves as further glue between the target framework and SBP-2, in
> >> this case dealing with SCSI command submission and data in/out.
> >> 
> >> Signed-off-by: Chris Boot <bootc@bootc.net>
> >> Cc: Andy Grover <agrover@redhat.com>
> >> Cc: Clemens Ladisch <clemens@ladisch.de>
> >> Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
> >> Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
> >> ---
> >> drivers/target/sbp/sbp_fabric.c |  321 +++++++++++++++++++++++++++++++++++++++
> >> drivers/target/sbp/sbp_fabric.h |   32 ++++
> >> 2 files changed, 353 insertions(+), 0 deletions(-)
> >> create mode 100644 drivers/target/sbp/sbp_fabric.c
> >> create mode 100644 drivers/target/sbp/sbp_fabric.h
> >> 
> >> diff --git a/drivers/target/sbp/sbp_fabric.c b/drivers/target/sbp/sbp_fabric.c
> >> new file mode 100644
> >> index 0000000..edc6fda
> >> --- /dev/null
> >> +++ b/drivers/target/sbp/sbp_fabric.c
> 
> <snip>
> 
> >> +int sbp_new_cmd(struct se_cmd *se_cmd)
> >> +{
> >> +	struct sbp_target_request *req = container_of(se_cmd,
> >> +			struct sbp_target_request, se_cmd);
> >> +	int ret;
> >> +
> >> +	ret = transport_generic_allocate_tasks(se_cmd, req->cmd_buf);
> >> +	if (ret)
> >> +		return ret;
> >> +
> >> +	return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0);
> >> +}
> >> +
> > 
> > Because sbp_scsi_cmnd.c:sbp_handle_command() is using the new
> > target_submit_cmd() logic, target-core will not be calling
> > TFO->new_cmd_map() -> sbp_new_cmd() for setup here.
> > 
> > Go ahead and drop this now.
> 
> So I can just set TFO->new_cmd_map to NULL?
> 

Just drop the sbp_ops->new_cmd_map assignment, no need to explictly set
it to NULL..

> >> +
> >> +u32 sbp_get_task_tag(struct se_cmd *se_cmd)
> >> +{
> >> +	struct sbp_target_request *req = container_of(se_cmd,
> >> +			struct sbp_target_request, se_cmd);
> >> +
> >> +	/* only used for printk and family? */
> >> +	return (u32)req->orb_pointer;
> >> +}
> >> +
> > 
> > So an the ABORT_TASK TMR patches use TFO->get_task_tag() to locate a
> > referenced tag to locate the se_cmd descriptor.  Since we don't
> > support TMRs yet in sbp, this value will only be used for
> informational
> > purposes.
> 
> I'd like to support ABORT_TASK and friends at some point. The problem
> I see here though is that tags in SBP-2/3 are 48-bits wide (the ORB
> address in the initiator node's memory), and the target framework
> seems to use a u32 for this. SAM-3 Section 4.11 seems to say "A task
> tag is a value that is composed of up to 64 bits" so it might be worth
> getting that changed in the target framework?

Bumping TFO->get_task_tag and se_tmr_req->ref_task_tag to u64 is easy
enough, but it would make sense to figure out if this is really required
in practice first..

--nab


^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH v2 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                     ` (13 preceding siblings ...)
  2012-02-12 14:12   ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Stefan Richter
@ 2012-02-15 14:47   ` Chris Boot
  2012-02-15 14:47     ` [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request Chris Boot
                       ` (11 more replies)
  14 siblings, 12 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr

The FireWire SBP-2 Target is a driver for using an IEEE-1394 connection
as a SCSI transport. This module uses the SCSI Target framework to
expose LUNs to other machines attached to a FireWire bus, in effect
acting as a FireWire hard disk similar to FireWire Target Disk mode on
many Apple computers.

Changes since v1:
* Fixed some copy & paste issues
* Updated Kconfig (wording, depends, 'default n')
* Removed some unnecessary EXPORT_SYMBOL()s
* Merged sbp_util.{c,h} into sbp_configfs.c and sbp_base.h
* Merged sbp_proto.{c,h} into sbp_fabric.{c,h}
* Cleaned up comments and several printks
* Fixed a few minor bugs
* Create & use our own workqueue instead of using fw_workqueue
* Dropped the unused TFO->new_cmd_map and sbp_new_cmd()
* Overhauled and simplified tgt_agent_fetch_work()
* Removed some redundant members of struct sbp_target_request
* Removed struct sbp_lun and code to maintain redundant LUN list
* Added spinlock to struct sbp_session and use locking throughout
* Moved fw_card_{get,put,release}() into linux/firewire.h

It didn't feel like a lot of changes but actually that's quite a lot of work,
looking back at it...

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net.


^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 19:09       ` Stefan Richter
  2012-02-15 14:47     ` [PATCH v2 02/11] firewire: Move fw_card kref functions into linux/firewire.h Chris Boot
                       ` (10 subsequent siblings)
  11 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

Sometimes it's useful to know the FireWire speed of the request that has
just come in to a fw_address_handler callback. As struct fw_request is
opaque we can't peek inside to get the speed out of the struct fw_packet
that's just inside. For example, the SBP-2 spec says:

"The speed at which the block write request to the MANAGEMENT_AGENT
register is received shall determine the speed used by the target for
all subsequent requests to read the initiator’s configuration ROM, fetch
ORB’s from initiator memory or store status at the initiator’s
status_FIFO. Command block ORB’s separately specify the speed for
requests addressed to the data buffer or page table."

[ ANSI T10/1155D Revision 4 page 53/54 ]

Signed-off-by: Chris Boot <bootc@bootc.net>
Acked-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: Clemens Ladisch <clemens@ladisch.de>
---
 drivers/firewire/core-transaction.c |   16 ++++++++++++++++
 include/linux/firewire.h            |    1 +
 2 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 855ab3f..614f592 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -820,6 +820,22 @@ void fw_send_response(struct fw_card *card,
 }
 EXPORT_SYMBOL(fw_send_response);
 
+/**
+ * fw_get_request_speed() - Discover bus speed used for this request
+ * @request:	The struct fw_request from which to obtain the speed.
+ *
+ * In certain circumstances it's important to be able to obtain the speed at
+ * which a request was made to an address handler, for example when
+ * implementing an SBP-2 or SBP-3 target. This function inspects the response
+ * object to obtain the speed, which is copied from the request packet in
+ * allocate_request().
+ */
+int fw_get_request_speed(struct fw_request *request)
+{
+	return request->response.speed;
+}
+EXPORT_SYMBOL(fw_get_request_speed);
+
 static void handle_exclusive_region_request(struct fw_card *card,
 					    struct fw_packet *p,
 					    struct fw_request *request,
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 84ccf8e..f010307 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -340,6 +340,7 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
 void fw_core_remove_address_handler(struct fw_address_handler *handler);
 void fw_send_response(struct fw_card *card,
 		      struct fw_request *request, int rcode);
+int fw_get_request_speed(struct fw_request *request);
 void fw_send_request(struct fw_card *card, struct fw_transaction *t,
 		     int tcode, int destination_id, int generation, int speed,
 		     unsigned long long offset, void *payload, size_t length,
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 02/11] firewire: Move fw_card kref functions into linux/firewire.h
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
  2012-02-15 14:47     ` [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 19:10       ` Stefan Richter
  2012-02-15 14:47     ` [PATCH v2 03/11] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
                       ` (9 subsequent siblings)
  11 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

When writing a firewire driver that doesn't deal with struct fw_device
objects (e.g. it only publishes FireWire units and doesn't subscribe to
them), you likely need to keep referenced to struct fw_card objects so
that you can send messages to other nodes. This patch moves
fw_card_put(), fw_card_get() and fw_card_release() into the public
include/linux/firewire.h header instead of drivers/firewire/core.h, and
adds EXPORT_SYMBOL_GPL(fw_card_release).

The firewire-sbp-target module requires these so it can keep a reference
to the fw_card object in order that it can fetch ORBs to execute and
read/write related data and status information.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/firewire/core-card.c |    1 +
 drivers/firewire/core.h      |   15 ---------------
 include/linux/firewire.h     |   14 ++++++++++++++
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 85661b0..42b180b 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -654,6 +654,7 @@ void fw_card_release(struct kref *kref)
 
 	complete(&card->done);
 }
+EXPORT_SYMBOL_GPL(fw_card_release);
 
 void fw_core_remove_card(struct fw_card *card)
 {
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index b45be57..b44657b 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -111,21 +111,6 @@ int fw_compute_block_crc(__be32 *block);
 void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset);
 void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
 
-static inline struct fw_card *fw_card_get(struct fw_card *card)
-{
-	kref_get(&card->kref);
-
-	return card;
-}
-
-void fw_card_release(struct kref *kref);
-
-static inline void fw_card_put(struct fw_card *card)
-{
-	kref_put(&card->kref, fw_card_release);
-}
-
-
 /* -cdev */
 
 extern const struct file_operations fw_device_ops;
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index f010307..341e51c 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -138,6 +138,20 @@ struct fw_card {
 	__be32 maint_utility_register;
 };
 
+static inline struct fw_card *fw_card_get(struct fw_card *card)
+{
+	kref_get(&card->kref);
+
+	return card;
+}
+
+void fw_card_release(struct kref *kref);
+
+static inline void fw_card_put(struct fw_card *card)
+{
+	kref_put(&card->kref, fw_card_release);
+}
+
 struct fw_attribute_group {
 	struct attribute_group *groups[2];
 	struct attribute_group group;
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 03/11] firewire-sbp-target: Add Kconfig, Makefile and TODO
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
  2012-02-15 14:47     ` [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request Chris Boot
  2012-02-15 14:47     ` [PATCH v2 02/11] firewire: Move fw_card kref functions into linux/firewire.h Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 14:47     ` [PATCH v2 04/11] firewire-sbp-target: Add sbp_base.h header Chris Boot
                       ` (8 subsequent siblings)
  11 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

The FireWire SBP-2 Target is a driver for using an IEEE-1394 connection
as a SCSI transport. This module uses the SCSI Target framework to
expose LUNs to other machines attached to a FireWire bus, in effect
acting as a FireWire hard disk similar to FireWire Target Disk mode on
many Apple computers.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/Kconfig  |   13 +++++++++++++
 drivers/target/sbp/Makefile |   11 +++++++++++
 drivers/target/sbp/TODO     |    7 +++++++
 3 files changed, 31 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/Kconfig
 create mode 100644 drivers/target/sbp/Makefile
 create mode 100644 drivers/target/sbp/TODO

diff --git a/drivers/target/sbp/Kconfig b/drivers/target/sbp/Kconfig
new file mode 100644
index 0000000..c9f85e9
--- /dev/null
+++ b/drivers/target/sbp/Kconfig
@@ -0,0 +1,13 @@
+
+config FIREWIRE_SBP_TARGET
+	tristate "FireWire SBP-2 fabric module"
+	depends on FIREWIRE && EXPERIMENTAL
+	help
+	  Say Y or M here to enable SCSI target functionality over FireWire.
+	  This enables you to expose SCSI devices to other nodes on the FireWire
+	  bus, for example hard disks. Similar to FireWire Target Disk mode on
+	  many Apple computers.
+
+	  To compile this driver as a module, say M here: The module will be
+	  called firewire-sbp-target.
+
diff --git a/drivers/target/sbp/Makefile b/drivers/target/sbp/Makefile
new file mode 100644
index 0000000..c8f73f4
--- /dev/null
+++ b/drivers/target/sbp/Makefile
@@ -0,0 +1,11 @@
+
+firewire-sbp-target-y += \
+	sbp_configfs.o \
+	sbp_fabric.o \
+	sbp_login.o \
+	sbp_management_agent.o \
+	sbp_scsi_cmnd.o \
+	sbp_target_agent.o
+
+obj-$(CONFIG_FIREWIRE_SBP_TARGET) += firewire-sbp-target.o
+
diff --git a/drivers/target/sbp/TODO b/drivers/target/sbp/TODO
new file mode 100644
index 0000000..eaec1c9
--- /dev/null
+++ b/drivers/target/sbp/TODO
@@ -0,0 +1,7 @@
+* Force-terminate sessions when disabling targets
+* Ability to have several SCSI commands in-flight (TCQ?)
+* Retry failed FireWire transactions a few times with exponential backoff
+* Take into account the page_size field for transfers and/or page tables
+* Handle descriptor format sense data
+* Implement QUERY LOGINS management ORB
+* Implement TASK MANAGEMENT functionality
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 04/11] firewire-sbp-target: Add sbp_base.h header
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
                       ` (2 preceding siblings ...)
  2012-02-15 14:47     ` [PATCH v2 03/11] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 19:15       ` Stefan Richter
  2012-02-15 14:47     ` [PATCH v2 05/11] firewire-sbp-target: Add sbp_configfs.c Chris Boot
                       ` (7 subsequent siblings)
  11 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This header contains defines and structures that are common to many of
the modules of the target code. This includes SBP-2 protocol structures
and constants as well as a few structs for setting up the target, LUN
login information and session setup.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_base.h |  204 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 204 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_base.h

diff --git a/drivers/target/sbp/sbp_base.h b/drivers/target/sbp/sbp_base.h
new file mode 100644
index 0000000..d39b743
--- /dev/null
+++ b/drivers/target/sbp/sbp_base.h
@@ -0,0 +1,204 @@
+
+#define SBP_VERSION  "v0.1"
+#define SBP_NAMELEN 32
+
+#define SBP_ORB_FETCH_SIZE	8
+
+#define MANAGEMENT_AGENT_STATE_IDLE	0
+#define MANAGEMENT_AGENT_STATE_BUSY	1
+
+#define ORB_NOTIFY(v)			(((v) >> 31) & 0x01)
+#define ORB_REQUEST_FORMAT(v)		(((v) >> 29) & 0x03)
+
+#define MANAGEMENT_ORB_FUNCTION(v)	(((v) >> 16) & 0x0f)
+
+#define MANAGEMENT_ORB_FUNCTION_LOGIN			0x0
+#define MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS		0x1
+#define MANAGEMENT_ORB_FUNCTION_RECONNECT		0x3
+#define MANAGEMENT_ORB_FUNCTION_SET_PASSWORD		0x4
+#define MANAGEMENT_ORB_FUNCTION_LOGOUT			0x7
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK		0xb
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET		0xc
+#define MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET	0xe
+#define MANAGEMENT_ORB_FUNCTION_TARGET_RESET		0xf
+
+#define LOGIN_ORB_EXCLUSIVE(v)		(((v) >> 28) &   0x01)
+#define LOGIN_ORB_RESERVED(v)		(((v) >> 24) &   0x0f)
+#define LOGIN_ORB_RECONNECT(v)		(((v) >> 20) &   0x0f)
+#define LOGIN_ORB_LUN(v)		(((v) >>  0) & 0xffff)
+#define LOGIN_ORB_PASSWORD_LENGTH(v)	(((v) >> 16) & 0xffff)
+#define LOGIN_ORB_RESPONSE_LENGTH(v)	(((v) >>  0) & 0xffff)
+
+#define RECONNECT_ORB_LOGIN_ID(v)	(((v) >>  0) & 0xffff)
+#define LOGOUT_ORB_LOGIN_ID(v)		(((v) >>  0) & 0xffff)
+
+#define CMDBLK_ORB_DIRECTION(v)		(((v) >> 27) &   0x01)
+#define CMDBLK_ORB_SPEED(v)		(((v) >> 24) &   0x07)
+#define CMDBLK_ORB_MAX_PAYLOAD(v)	(((v) >> 20) &   0x0f)
+#define CMDBLK_ORB_PG_TBL_PRESENT(v)	(((v) >> 19) &   0x01)
+#define CMDBLK_ORB_PG_SIZE(v)		(((v) >> 16) &   0x07)
+#define CMDBLK_ORB_DATA_SIZE(v)		(((v) >>  0) & 0xffff)
+
+#define STATUS_BLOCK_SRC(v)		(((v) &   0x03) << 30)
+#define STATUS_BLOCK_RESP(v)		(((v) &   0x03) << 28)
+#define STATUS_BLOCK_DEAD(v)		(((v) ? 1 : 0)  << 27)
+#define STATUS_BLOCK_LEN(v)		(((v) &   0x07) << 24)
+#define STATUS_BLOCK_SBP_STATUS(v)	(((v) &   0xff) << 16)
+#define STATUS_BLOCK_ORB_OFFSET_HIGH(v)	(((v) & 0xffff) <<  0)
+
+#define STATUS_SRC_ORB_CONTINUING	0
+#define STATUS_SRC_ORB_FINISHED		1
+#define STATUS_SRC_UNSOLICITED		2
+
+#define STATUS_RESP_REQUEST_COMPLETE	0
+#define STATUS_RESP_TRANSPORT_FAILURE	1
+#define STATUS_RESP_ILLEGAL_REQUEST	2
+#define STATUS_RESP_VENDOR_DEPENDENT	3
+
+#define SBP_STATUS_OK			0
+#define SBP_STATUS_REQ_TYPE_NOTSUPP	1
+#define SBP_STATUS_SPEED_NOTSUPP	2
+#define SBP_STATUS_PAGE_SIZE_NOTSUPP	3
+#define SBP_STATUS_ACCESS_DENIED	4
+#define SBP_STATUS_LUN_NOTSUPP		5
+#define SBP_STATUS_PAYLOAD_TOO_SMALL	6
+/* 7 is reserved */
+#define SBP_STATUS_RESOURCES_UNAVAIL	8
+#define SBP_STATUS_FUNCTION_REJECTED	9
+#define SBP_STATUS_LOGIN_ID_UNKNOWN	10
+#define SBP_STATUS_DUMMY_ORB_COMPLETE	11
+#define SBP_STATUS_REQUEST_ABORTED	12
+#define SBP_STATUS_UNSPECIFIED_ERROR	0xff
+
+#define AGENT_STATE_RESET	0
+#define AGENT_STATE_ACTIVE	1
+#define AGENT_STATE_SUSPENDED	2
+#define AGENT_STATE_DEAD	3
+
+struct sbp2_pointer {
+	__be32 high;
+	__be32 low;
+};
+
+struct sbp_command_block_orb {
+	struct sbp2_pointer next_orb;
+	struct sbp2_pointer data_descriptor;
+	__be32 misc;
+	u8 command_block[12];
+};
+
+struct sbp_page_table_entry {
+	__be16 segment_length;
+	__be16 segment_base_hi;
+	__be32 segment_base_lo;
+};
+
+struct sbp_management_orb {
+	struct sbp2_pointer ptr1;
+	struct sbp2_pointer ptr2;
+	__be32 misc;
+	__be32 length;
+	struct sbp2_pointer status_fifo;
+};
+
+struct sbp_status_block {
+	__be32 status;
+	__be32 orb_low;
+	u8 data[24];
+};
+
+struct sbp_login_response_block {
+	__be32 misc;
+	struct sbp2_pointer command_block_agent;
+	__be32 reconnect_hold;
+};
+
+struct sbp_login_descriptor {
+	struct sbp_session *sess;
+	struct list_head link;
+
+	struct se_lun *lun;
+
+	u64 status_fifo_addr;
+	int exclusive;
+	u16 login_id;
+	atomic_t unsolicited_status_enable;
+
+	struct sbp_target_agent *tgt_agt;
+};
+
+struct sbp_session {
+	struct se_session *se_sess;
+	struct list_head login_list;
+	spinlock_t login_list_lock;
+	struct delayed_work maint_work;
+
+	u64 guid; /* login_owner_EUI_64 */
+	int node_id; /* login_owner_ID */
+
+	struct fw_card *card;
+	int generation;
+	int speed;
+
+	int reconnect_hold;
+	u64 reconnect_expires;
+};
+
+struct sbp_nacl {
+	/* Initiator EUI-64 */
+	u64 guid;
+	/* ASCII formatted GUID for SBP Initiator port */
+	char iport_name[SBP_NAMELEN];
+	/* Returned by sbp_make_nodeacl() */
+	struct se_node_acl se_node_acl;
+};
+
+struct sbp_tpg {
+	/* Target portal group tag for TCM */
+	u16 tport_tpgt;
+	/* Pointer back to sbp_tport */
+	struct sbp_tport *tport;
+	/* Returned by sbp_make_tpg() */
+	struct se_portal_group se_tpg;
+};
+
+struct sbp_tport {
+	/* Target Unit Identifier (EUI-64) */
+	u64 guid;
+	/* Target port name */
+	char tport_name[SBP_NAMELEN];
+	/* Returned by sbp_make_tport() */
+	struct se_wwn tport_wwn;
+
+	struct sbp_tpg *tpg;
+
+	/* FireWire unit directory */
+	struct fw_descriptor unit_directory;
+
+	/* SBP Management Agent */
+	struct sbp_management_agent *mgt_agt;
+
+	/* Parameters */
+	int enable;
+	s32 directory_id;
+	int mgt_orb_timeout;
+	int max_reconnect_timeout;
+	int max_logins_per_lun;
+};
+
+extern struct target_fabric_configfs *sbp_fabric_configfs;
+extern const struct fw_address_region sbp_register_region;
+extern struct workqueue_struct *sbp_workqueue;
+
+static inline u64 sbp2_pointer_to_addr(const struct sbp2_pointer *ptr)
+{
+	return (u64)(be32_to_cpu(ptr->high) & 0x0000ffff) << 32 |
+		(be32_to_cpu(ptr->low) & 0xfffffffc);
+}
+
+static inline void addr_to_sbp2_pointer(u64 addr, struct sbp2_pointer *ptr)
+{
+	ptr->high = cpu_to_be32(addr >> 32);
+	ptr->low = cpu_to_be32(addr);
+}
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 05/11] firewire-sbp-target: Add sbp_configfs.c
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
                       ` (3 preceding siblings ...)
  2012-02-15 14:47     ` [PATCH v2 04/11] firewire-sbp-target: Add sbp_base.h header Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 19:21       ` Stefan Richter
  2012-02-15 14:47     ` [PATCH v2 06/11] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
                       ` (6 subsequent siblings)
  11 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This is used to glue the target framework's configfs code to the target
code, and what is used to create targets and link them to LUNs to
export. The code to create the FireWire unit directory to advertise
targets on the FireWire bus is also in here.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_configfs.c |  751 +++++++++++++++++++++++++++++++++++++
 1 files changed, 751 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_configfs.c

diff --git a/drivers/target/sbp/sbp_configfs.c b/drivers/target/sbp/sbp_configfs.c
new file mode 100644
index 0000000..f4a6b36
--- /dev/null
+++ b/drivers/target/sbp/sbp_configfs.c
@@ -0,0 +1,751 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/firewire.h>
+
+#include <asm/unaligned.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_configfs.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/configfs_macros.h>
+
+#include "sbp_base.h"
+#include "sbp_fabric.h"
+#include "sbp_management_agent.h"
+
+/* Local pointer to allocated TCM configfs fabric module */
+struct target_fabric_configfs *sbp_fabric_configfs;
+
+struct workqueue_struct *sbp_workqueue;
+
+/* FireWire address region for management and command block address handlers */
+const struct fw_address_region sbp_register_region = {
+	.start = CSR_REGISTER_BASE + 0x10000,
+	.end   = 0x1000000000000ULL,
+};
+
+static const u32 sbp_unit_directory_template[] = {
+	0x1200609e, /* unit_specifier_id: NCITS/T10 */
+	0x13010483, /* unit_sw_version: 1155D Rev 4 */
+	0x3800609e, /* command_set_specifier_id: NCITS/T10 */
+	0x390104d8, /* command_set: SPC-2 */
+	0x3b000000, /* command_set_revision: 0 */
+	0x3c000001, /* firmware_revision: 1 */
+};
+
+static int sbp_count_se_tpg_luns(struct se_portal_group *tpg)
+{
+	int i, count = 0;
+
+	spin_lock(&tpg->tpg_lun_lock);
+	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+		struct se_lun *se_lun = &tpg->tpg_lun_list[i];
+
+		if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+			continue;
+
+		count++;
+	}
+	spin_unlock(&tpg->tpg_lun_lock);
+
+	return count;
+}
+
+static int sbp_update_unit_directory(struct sbp_tport *tport)
+{
+	int num_luns, num_entries, idx = 0, mgt_agt_addr, ret, i;
+	u32 *data;
+
+	if (tport->unit_directory.data) {
+		fw_core_remove_descriptor(&tport->unit_directory);
+		kfree(tport->unit_directory.data);
+		tport->unit_directory.data = NULL;
+	}
+
+	if (!tport->enable || !tport->tpg)
+		return 0;
+
+	num_luns = sbp_count_se_tpg_luns(&tport->tpg->se_tpg);
+
+	/*
+	 * Number of entries in the final unit directory:
+	 *  - all of those in the template
+	 *  - management_agent
+	 *  - unit_characteristics
+	 *  - reconnect_timeout
+	 *  - unit unique ID
+	 *  - one for each LUN
+	 *
+	 *  MUST NOT include leaf or sub-directory entries
+	 */
+	num_entries = ARRAY_SIZE(sbp_unit_directory_template) + 4 + num_luns;
+
+	if (tport->directory_id != -1)
+		num_entries++;
+
+	/* allocate num_entries + 4 for the header and unique ID leaf */
+	data = kcalloc((num_entries + 4), sizeof(u32), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* directory_length */
+	data[idx++] = num_entries << 16;
+
+	/* directory_id */
+	if (tport->directory_id != -1)
+		data[idx++] = (CSR_DIRECTORY_ID << 24) | tport->directory_id;
+
+	/* unit directory template */
+	memcpy(&data[idx], sbp_unit_directory_template,
+			sizeof(sbp_unit_directory_template));
+	idx += ARRAY_SIZE(sbp_unit_directory_template);
+
+	/* management_agent */
+	mgt_agt_addr = (tport->mgt_agt->handler.offset - CSR_REGISTER_BASE) / 4;
+	data[idx++] = 0x54000000 | (mgt_agt_addr & 0x00ffffff);
+
+	/* unit_characteristics */
+	data[idx++] = 0x3a000000 |
+		(((tport->mgt_orb_timeout * 2) << 8) & 0xff00) |
+		SBP_ORB_FETCH_SIZE;
+
+	/* reconnect_timeout */
+	data[idx++] = 0x3d000000 | (tport->max_reconnect_timeout & 0xffff);
+
+	/* unit unique ID (leaf is just after LUNs) */
+	data[idx++] = 0x8d000000 | (num_luns + 1);
+
+	spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+		struct se_lun *se_lun = &tport->tpg->se_tpg.tpg_lun_list[i];
+		struct se_device *dev;
+		int type;
+
+		if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+			continue;
+
+		spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+		dev = se_lun->lun_se_dev;
+		type = dev->transport->get_device_type(dev);
+
+		/* logical_unit_number */
+		data[idx++] = 0x14000000 |
+			((type << 16) & 0x1f0000) |
+			(se_lun->unpacked_lun & 0xffff);
+
+		spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+	}
+	spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+	/* unit unique ID leaf */
+	data[idx++] = 2 << 16;
+	data[idx++] = tport->guid >> 32;
+	data[idx++] = tport->guid;
+
+	tport->unit_directory.length = idx;
+	tport->unit_directory.key = (CSR_DIRECTORY | CSR_UNIT) << 24;
+	tport->unit_directory.data = data;
+
+	ret = fw_core_add_descriptor(&tport->unit_directory);
+	if (ret < 0) {
+		kfree(tport->unit_directory.data);
+		tport->unit_directory.data = NULL;
+	}
+
+	return ret;
+}
+
+static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
+{
+	const char *cp;
+	char c, nibble;
+	int pos = 0, err;
+
+	*wwn = 0;
+	for (cp = name; cp < &name[SBP_NAMELEN - 1]; cp++) {
+		c = *cp;
+		if (c == '\n' && cp[1] == '\0')
+			continue;
+		if (c == '\0') {
+			err = 2;
+			if (pos != 16)
+				goto fail;
+			return cp - name;
+		}
+		err = 3;
+		if (isdigit(c))
+			nibble = c - '0';
+		else if (isxdigit(c) && (islower(c) || !strict))
+			nibble = tolower(c) - 'a' + 10;
+		else
+			goto fail;
+		*wwn = (*wwn << 4) | nibble;
+		pos++;
+	}
+	err = 4;
+fail:
+	printk(KERN_INFO "err %u len %zu pos %u\n",
+			err, cp - name, pos);
+	return -1;
+}
+
+static ssize_t sbp_format_wwn(char *buf, size_t len, u64 wwn)
+{
+	return snprintf(buf, len, "%016llx", wwn);
+}
+
+static struct se_node_acl *sbp_make_nodeacl(
+		struct se_portal_group *se_tpg,
+		struct config_group *group,
+		const char *name)
+{
+	struct se_node_acl *se_nacl, *se_nacl_new;
+	struct sbp_nacl *nacl;
+	u64 guid = 0;
+	u32 nexus_depth = 1;
+
+	if (sbp_parse_wwn(name, &guid, 1) < 0)
+		return ERR_PTR(-EINVAL);
+
+	se_nacl_new = sbp_alloc_fabric_acl(se_tpg);
+	if (!se_nacl_new)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+	 * when converting a NodeACL from demo mode -> explict
+	 */
+	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+			name, nexus_depth);
+	if (IS_ERR(se_nacl)) {
+		sbp_release_fabric_acl(se_tpg, se_nacl_new);
+		return se_nacl;
+	}
+
+	nacl = container_of(se_nacl, struct sbp_nacl, se_node_acl);
+	nacl->guid = guid;
+	sbp_format_wwn(nacl->iport_name, SBP_NAMELEN, guid);
+
+	return se_nacl;
+}
+
+static void sbp_drop_nodeacl(struct se_node_acl *se_acl)
+{
+	struct sbp_nacl *nacl =
+		container_of(se_acl, struct sbp_nacl, se_node_acl);
+
+	core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+	kfree(nacl);
+}
+
+static int sbp_post_link_lun(
+		struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+
+	return sbp_update_unit_directory(tpg->tport);
+}
+
+static void sbp_pre_unlink_lun(
+		struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	int ret;
+
+	if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0)
+		tport->enable = 0;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		pr_err("unlink LUN: failed to update unit directory\n");
+}
+
+static struct se_portal_group *sbp_make_tpg(
+		struct se_wwn *wwn,
+		struct config_group *group,
+		const char *name)
+{
+	struct sbp_tport *tport =
+		container_of(wwn, struct sbp_tport, tport_wwn);
+
+	struct sbp_tpg *tpg;
+	unsigned long tpgt;
+	int ret;
+
+	if (strstr(name, "tpgt_") != name)
+		return ERR_PTR(-EINVAL);
+	if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+		return ERR_PTR(-EINVAL);
+
+	if (tport->tpg) {
+		pr_err("Only one TPG per Unit is possible.\n");
+		return ERR_PTR(-EBUSY);
+	}
+
+	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+	if (!tpg) {
+		pr_err("Unable to allocate struct sbp_tpg\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	tpg->tport = tport;
+	tpg->tport_tpgt = tpgt;
+	tport->tpg = tpg;
+
+	/* default attribute values */
+	tport->enable = 0;
+	tport->directory_id = -1;
+	tport->mgt_orb_timeout = 15;
+	tport->max_reconnect_timeout = 5;
+	tport->max_logins_per_lun = 1;
+
+	tport->mgt_agt = sbp_management_agent_register(tport);
+	if (IS_ERR(tport->mgt_agt)) {
+		ret = PTR_ERR(tport->mgt_agt);
+		kfree(tpg);
+		return ERR_PTR(ret);
+	}
+
+	ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
+			&tpg->se_tpg, (void *)tpg,
+			TRANSPORT_TPG_TYPE_NORMAL);
+	if (ret < 0) {
+		sbp_management_agent_unregister(tport->mgt_agt);
+		kfree(tpg);
+		return ERR_PTR(ret);
+	}
+
+	return &tpg->se_tpg;
+}
+
+static void sbp_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	core_tpg_deregister(se_tpg);
+	sbp_management_agent_unregister(tport->mgt_agt);
+	tport->tpg = NULL;
+	kfree(tpg);
+}
+
+static struct se_wwn *sbp_make_tport(
+		struct target_fabric_configfs *tf,
+		struct config_group *group,
+		const char *name)
+{
+	struct sbp_tport *tport;
+	u64 guid = 0;
+
+	if (sbp_parse_wwn(name, &guid, 1) < 0)
+		return ERR_PTR(-EINVAL);
+
+	tport = kzalloc(sizeof(*tport), GFP_KERNEL);
+	if (!tport) {
+		pr_err("Unable to allocate struct sbp_tport\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	tport->guid = guid;
+	sbp_format_wwn(tport->tport_name, SBP_NAMELEN, guid);
+
+	return &tport->tport_wwn;
+}
+
+static void sbp_drop_tport(struct se_wwn *wwn)
+{
+	struct sbp_tport *tport =
+		container_of(wwn, struct sbp_tport, tport_wwn);
+
+	kfree(tport);
+}
+
+static ssize_t sbp_wwn_show_attr_version(
+		struct target_fabric_configfs *tf,
+		char *page)
+{
+	return sprintf(page, "FireWire SBP fabric module %s\n", SBP_VERSION);
+}
+
+TF_WWN_ATTR_RO(sbp, version);
+
+static struct configfs_attribute *sbp_wwn_attrs[] = {
+	&sbp_wwn_version.attr,
+	NULL,
+};
+
+static ssize_t sbp_tpg_show_directory_id(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	if (tport->directory_id == -1)
+		return sprintf(page, "implicit\n");
+	else
+		return sprintf(page, "%06x\n", tport->directory_id);
+}
+
+static ssize_t sbp_tpg_store_directory_id(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+
+	if (tport->enable) {
+		pr_err("Cannot change the directory_id on an active target.\n");
+		return -EBUSY;
+	}
+
+	if (strstr(page, "implicit") == page) {
+		tport->directory_id = -1;
+	} else {
+		if (kstrtoul(page, 16, &val) < 0)
+			return -EINVAL;
+		if (val > 0xffffff)
+			return -EINVAL;
+
+		tport->directory_id = val;
+	}
+
+	return count;
+}
+
+static ssize_t sbp_tpg_show_enable(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->enable);
+}
+
+static ssize_t sbp_tpg_store_enable(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val != 0) && (val != 1))
+		return -EINVAL;
+
+	if (tport->enable == val)
+		return count;
+
+	if (val) {
+		if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0) {
+			pr_err("Cannot enable a target with no LUNs!\n");
+			return -EINVAL;
+		}
+	} else {
+		/* XXX: force-shutdown sessions instead? */
+		spin_lock(&se_tpg->session_lock);
+		if (!list_empty(&se_tpg->tpg_sess_list)) {
+			spin_unlock(&se_tpg->session_lock);
+			return -EBUSY;
+		}
+		spin_unlock(&se_tpg->session_lock);
+	}
+
+	tport->enable = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0) {
+		pr_err("Could not update Config ROM\n");
+		return ret;
+	}
+
+	return count;
+}
+
+TF_TPG_BASE_ATTR(sbp, directory_id, S_IRUGO | S_IWUSR);
+TF_TPG_BASE_ATTR(sbp, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_base_attrs[] = {
+	&sbp_tpg_directory_id.attr,
+	&sbp_tpg_enable.attr,
+	NULL,
+};
+
+static ssize_t sbp_tpg_attrib_show_mgt_orb_timeout(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->mgt_orb_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 127))
+		return -EINVAL;
+
+	if (tport->mgt_orb_timeout == val)
+		return count;
+
+	tport->mgt_orb_timeout = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_reconnect_timeout(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->max_reconnect_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 32767))
+		return -EINVAL;
+
+	if (tport->max_reconnect_timeout == val)
+		return count;
+
+	tport->max_reconnect_timeout = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_logins_per_lun(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->max_logins_per_lun);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_logins_per_lun(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 127))
+		return -EINVAL;
+
+	/* XXX: also check against current count? */
+
+	tport->max_logins_per_lun = val;
+
+	return count;
+}
+
+TF_TPG_ATTRIB_ATTR(sbp, mgt_orb_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_reconnect_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_logins_per_lun, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
+	&sbp_tpg_attrib_mgt_orb_timeout.attr,
+	&sbp_tpg_attrib_max_reconnect_timeout.attr,
+	&sbp_tpg_attrib_max_logins_per_lun.attr,
+	NULL,
+};
+
+static struct target_core_fabric_ops sbp_ops = {
+	.get_fabric_name		= sbp_get_fabric_name,
+	.get_fabric_proto_ident		= sbp_get_fabric_proto_ident,
+	.tpg_get_wwn			= sbp_get_fabric_wwn,
+	.tpg_get_tag			= sbp_get_tag,
+	.tpg_get_default_depth		= sbp_get_default_depth,
+	.tpg_get_pr_transport_id	= sbp_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= sbp_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= sbp_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= sbp_check_true,
+	.tpg_check_demo_mode_cache	= sbp_check_true,
+	.tpg_check_demo_mode_write_protect = sbp_check_false,
+	.tpg_check_prod_mode_write_protect = sbp_check_false,
+	.tpg_alloc_fabric_acl		= sbp_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= sbp_release_fabric_acl,
+	.tpg_get_inst_index		= sbp_tpg_get_inst_index,
+	.release_cmd			= sbp_release_cmd,
+	.shutdown_session		= sbp_shutdown_session,
+	.close_session			= sbp_close_session,
+	.stop_session			= sbp_stop_session,
+	.fall_back_to_erl0		= sbp_reset_nexus,
+	.sess_logged_in			= sbp_sess_logged_in,
+	.sess_get_index			= sbp_sess_get_index,
+	.write_pending			= sbp_write_pending,
+	.write_pending_status		= sbp_write_pending_status,
+	.set_default_node_attributes	= sbp_set_default_node_attrs,
+	.get_task_tag			= sbp_get_task_tag,
+	.get_cmd_state			= sbp_get_cmd_state,
+	.queue_data_in			= sbp_queue_data_in,
+	.queue_status			= sbp_queue_status,
+	.queue_tm_rsp			= sbp_queue_tm_rsp,
+	.get_fabric_sense_len		= sbp_get_fabric_sense_len,
+	.set_fabric_sense_len		= sbp_set_fabric_sense_len,
+	.is_state_remove		= sbp_is_state_remove,
+	.check_stop_free		= sbp_check_stop_free,
+
+	.fabric_make_wwn		= sbp_make_tport,
+	.fabric_drop_wwn		= sbp_drop_tport,
+	.fabric_make_tpg		= sbp_make_tpg,
+	.fabric_drop_tpg		= sbp_drop_tpg,
+	.fabric_post_link		= sbp_post_link_lun,
+	.fabric_pre_unlink		= sbp_pre_unlink_lun,
+	.fabric_make_np			= NULL,
+	.fabric_drop_np			= NULL,
+	.fabric_make_nodeacl		= sbp_make_nodeacl,
+	.fabric_drop_nodeacl		= sbp_drop_nodeacl,
+};
+
+static int sbp_register_configfs(void)
+{
+	struct target_fabric_configfs *fabric;
+	int ret;
+
+	fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
+	if (!fabric) {
+		pr_err("target_fabric_configfs_init() failed\n");
+		return -ENOMEM;
+	}
+
+	fabric->tf_ops = sbp_ops;
+
+	/*
+	 * Setup default attribute lists for various fabric->tf_cit_tmpl
+	 */
+	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = sbp_wwn_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+
+	ret = target_fabric_configfs_register(fabric);
+	if (ret < 0) {
+		pr_err("target_fabric_configfs_register() failed for SBP\n");
+		return ret;
+	}
+
+	sbp_workqueue = alloc_workqueue("firewire-sbp-target", WQ_UNBOUND, 0);
+	if (!sbp_workqueue) {
+		target_fabric_configfs_deregister(fabric);
+		return -ENOMEM;
+	}
+
+	sbp_fabric_configfs = fabric;
+
+	return 0;
+};
+
+static void sbp_deregister_configfs(void)
+{
+	if (!sbp_fabric_configfs)
+		return;
+
+	target_fabric_configfs_deregister(sbp_fabric_configfs);
+	destroy_workqueue(sbp_workqueue);
+	sbp_fabric_configfs = NULL;
+};
+
+static int __init sbp_init(void)
+{
+	int ret;
+
+	ret = sbp_register_configfs();
+	if (ret < 0)
+		return ret;
+
+	return 0;
+};
+
+static void sbp_exit(void)
+{
+	sbp_deregister_configfs();
+};
+
+MODULE_DESCRIPTION("FireWire SBP fabric driver");
+MODULE_LICENSE("GPL");
+module_init(sbp_init);
+module_exit(sbp_exit);
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 06/11] firewire-sbp-target: Add sbp_fabric.{c,h}
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
                       ` (4 preceding siblings ...)
  2012-02-15 14:47     ` [PATCH v2 05/11] firewire-sbp-target: Add sbp_configfs.c Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 14:47     ` [PATCH v2 07/11] firewire-sbp-target: add sbp_management_agent.{c,h} Chris Boot
                       ` (5 subsequent siblings)
  11 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This serves as further glue between the target framework and SBP-2, in
this case dealing with SCSI command submission and data in/out.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_fabric.c |  353 +++++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_fabric.h |   42 +++++
 2 files changed, 395 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_fabric.c
 create mode 100644 drivers/target/sbp/sbp_fabric.h

diff --git a/drivers/target/sbp/sbp_fabric.c b/drivers/target/sbp/sbp_fabric.c
new file mode 100644
index 0000000..354ef93
--- /dev/null
+++ b/drivers/target/sbp/sbp_fabric.c
@@ -0,0 +1,353 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/firewire.h>
+
+#include <asm/unaligned.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/libfc.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#include "sbp_base.h"
+#include "sbp_fabric.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+
+int sbp_check_true(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+int sbp_check_false(struct se_portal_group *se_tpg)
+{
+	return 0;
+}
+
+char *sbp_get_fabric_name(void)
+{
+	return "sbp";
+}
+
+char *sbp_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	return &tport->tport_name[0];
+}
+
+u16 sbp_get_tag(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	return tpg->tport_tpgt;
+}
+
+u32 sbp_get_default_depth(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+	struct sbp_nacl *nacl;
+
+	nacl = kzalloc(sizeof(struct sbp_nacl), GFP_KERNEL);
+	if (!nacl) {
+		pr_err("Unable to alocate struct sbp_nacl\n");
+		return NULL;
+	}
+
+	return &nacl->se_node_acl;
+}
+
+void sbp_release_fabric_acl(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl)
+{
+	struct sbp_nacl *nacl =
+		container_of(se_nacl, struct sbp_nacl, se_node_acl);
+	kfree(nacl);
+}
+
+u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+void sbp_release_cmd(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	sbp_free_request(req);
+}
+
+int sbp_shutdown_session(struct se_session *se_sess)
+{
+	return 0;
+}
+
+void sbp_close_session(struct se_session *se_sess)
+{
+	return;
+}
+
+void sbp_stop_session(struct se_session *se_sess, int sess_sleep,
+		int conn_sleep)
+{
+	return;
+}
+
+void sbp_reset_nexus(struct se_session *se_sess)
+{
+	return;
+}
+
+int sbp_sess_logged_in(struct se_session *se_sess)
+{
+	return 0;
+}
+
+u32 sbp_sess_get_index(struct se_session *se_sess)
+{
+	return 0;
+}
+
+int sbp_write_pending(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+	int ret;
+
+	req->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+	if (!req->data_buf)
+		return -ENOMEM;
+
+	ret = sbp_rw_data(req);
+	if (ret) {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		pr_warn("sbp_write_pending: data write error\n");
+		return ret;
+	}
+
+	sg_copy_from_buffer(se_cmd->t_data_sg,
+			se_cmd->t_data_nents,
+			req->data_buf,
+			se_cmd->data_length);
+
+	transport_generic_process_write(se_cmd);
+
+	return 0;
+}
+
+int sbp_write_pending_status(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+void sbp_set_default_node_attrs(struct se_node_acl *nacl)
+{
+	return;
+}
+
+u32 sbp_get_task_tag(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	/* only used for printk until we do TMRs */
+	return (u32)req->orb_pointer;
+}
+
+int sbp_get_cmd_state(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+int sbp_queue_data_in(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+	int ret;
+
+	req->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL);
+	if (!req->data_buf)
+		return -ENOMEM;
+
+	sg_copy_to_buffer(se_cmd->t_data_sg,
+		se_cmd->t_data_nents,
+		req->data_buf,
+		se_cmd->data_length);
+
+	ret = sbp_rw_data(req);
+	if (ret) {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		return ret;
+	}
+
+	return sbp_send_sense(req);
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+int sbp_queue_status(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	return sbp_send_sense(req);
+}
+
+int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+u16 sbp_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+	return 0;
+}
+
+u16 sbp_get_fabric_sense_len(void)
+{
+	return 0;
+}
+
+int sbp_is_state_remove(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+int sbp_check_stop_free(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	transport_generic_free_cmd(&req->se_cmd, 0);
+	return 1;
+}
+
+/*
+ * Handlers for Serial Bus Protocol 2/3 (SBP-2 / SBP-3)
+ */
+u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+	/*
+	 * Return a IEEE 1394 SCSI Protocol identifier for loopback operations
+	 * This is defined in section 7.5.1 Table 362 in spc4r17
+	 */
+	return SCSI_PROTOCOL_SBP;
+}
+
+u32 sbp_get_pr_transport_id(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code,
+	unsigned char *buf)
+{
+	int ret;
+
+	/*
+	 * Set PROTOCOL IDENTIFIER to 3h for SBP
+	 */
+	buf[0] = SCSI_PROTOCOL_SBP;
+	/*
+	 * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+	 * over IEEE 1394
+	 */
+	ret = hex2bin(&buf[8], se_nacl->initiatorname, 8);
+	if (ret < 0)
+		pr_debug("sbp transport_id: invalid hex string\n");
+
+	/*
+	 * The IEEE 1394 Transport ID is a hardcoded 24-byte length
+	 */
+	return 24;
+}
+
+u32 sbp_get_pr_transport_id_len(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code)
+{
+	*format_code = 0;
+	/*
+	 * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+	 * over IEEE 1394
+	 *
+	 * The SBP Transport ID is a hardcoded 24-byte length
+	 */
+	return 24;
+}
+
+/*
+ * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
+ * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
+ */
+char *sbp_parse_pr_out_transport_id(
+	struct se_portal_group *se_tpg,
+	const char *buf,
+	u32 *out_tid_len,
+	char **port_nexus_ptr)
+{
+	/*
+	 * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.4 TransportID
+	 * for initiator ports using SCSI over SBP Serial SCSI Protocol
+	 *
+	 * The TransportID for a IEEE 1394 Initiator Port is of fixed size of
+	 * 24 bytes, and IEEE 1394 does not contain a I_T nexus identifier,
+	 * so we return the **port_nexus_ptr set to NULL.
+	 */
+	*port_nexus_ptr = NULL;
+	*out_tid_len = 24;
+
+	return (char *)&buf[8];
+}
+
diff --git a/drivers/target/sbp/sbp_fabric.h b/drivers/target/sbp/sbp_fabric.h
new file mode 100644
index 0000000..eb757a0
--- /dev/null
+++ b/drivers/target/sbp/sbp_fabric.h
@@ -0,0 +1,42 @@
+
+int sbp_check_true(struct se_portal_group *);
+int sbp_check_false(struct se_portal_group *);
+char *sbp_get_fabric_name(void);
+char *sbp_get_fabric_wwn(struct se_portal_group *);
+u16 sbp_get_tag(struct se_portal_group *);
+u32 sbp_get_default_depth(struct se_portal_group *);
+struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *);
+void sbp_release_fabric_acl(struct se_portal_group *,
+		struct se_node_acl *);
+u32 sbp_tpg_get_inst_index(struct se_portal_group *);
+void sbp_release_cmd(struct se_cmd *se_cmd);
+int sbp_shutdown_session(struct se_session *);
+void sbp_close_session(struct se_session *);
+void sbp_stop_session(struct se_session *, int, int);
+void sbp_reset_nexus(struct se_session *);
+int sbp_sess_logged_in(struct se_session *);
+u32 sbp_sess_get_index(struct se_session *);
+int sbp_write_pending(struct se_cmd *);
+int sbp_write_pending_status(struct se_cmd *);
+void sbp_set_default_node_attrs(struct se_node_acl *);
+u32 sbp_get_task_tag(struct se_cmd *);
+int sbp_get_cmd_state(struct se_cmd *);
+int sbp_queue_data_in(struct se_cmd *);
+int sbp_queue_status(struct se_cmd *);
+int sbp_queue_tm_rsp(struct se_cmd *);
+u16 sbp_set_fabric_sense_len(struct se_cmd *, u32);
+u16 sbp_get_fabric_sense_len(void);
+int sbp_is_state_remove(struct se_cmd *);
+int sbp_check_stop_free(struct se_cmd *se_cmd);
+
+u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg);
+u32 sbp_get_pr_transport_id(struct se_portal_group *se_tpg,
+		struct se_node_acl *se_nacl, struct t10_pr_registration *pr_reg,
+		int *format_code, unsigned char *buf);
+u32 sbp_get_pr_transport_id_len(
+		struct se_portal_group *se_tpg, struct se_node_acl *se_nacl,
+		struct t10_pr_registration *pr_reg, int *format_code);
+char *sbp_parse_pr_out_transport_id(
+		struct se_portal_group *se_tpg, const char *buf,
+		u32 *out_tid_len, char **port_nexus_ptr);
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 07/11] firewire-sbp-target: add sbp_management_agent.{c,h}
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
                       ` (5 preceding siblings ...)
  2012-02-15 14:47     ` [PATCH v2 06/11] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 19:48       ` Stefan Richter
  2012-02-15 14:47     ` [PATCH v2 08/11] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
                       ` (4 subsequent siblings)
  11 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This code implements the SBP-2 Management Agent. This is the first of
two firewire address handlers that are used to communicate with the
target. The Management Agent is used to handle login, reconnect and
logout to a SCSI LUN as well as task management functions.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_management_agent.c |  260 +++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_management_agent.h |   23 +++
 2 files changed, 283 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_management_agent.c
 create mode 100644 drivers/target/sbp/sbp_management_agent.h

diff --git a/drivers/target/sbp/sbp_management_agent.c b/drivers/target/sbp/sbp_management_agent.c
new file mode 100644
index 0000000..04e4df8
--- /dev/null
+++ b/drivers/target/sbp/sbp_management_agent.c
@@ -0,0 +1,260 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/kref.h>
+
+#include <target/target_core_base.h>
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+#include "sbp_login.h"
+
+static void sbp_mgt_agent_process(struct work_struct *work)
+{
+	struct sbp_management_agent *agent =
+		container_of(work, struct sbp_management_agent, work);
+	struct sbp_management_request *req = agent->request;
+	int ret;
+	int status_data_len = 0;
+
+	/* fetch the ORB from the initiator */
+	ret = fw_run_transaction(req->card, TCODE_READ_BLOCK_REQUEST,
+		req->node_addr, req->generation, req->speed,
+		agent->orb_offset, &req->orb, sizeof(req->orb));
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("mgt_orb fetch failed: %x\n", ret);
+		goto out;
+	}
+
+	pr_debug("mgt_orb ptr1:0x%llx ptr2:0x%llx misc:0x%x len:0x%x status_fifo:0x%llx\n",
+		sbp2_pointer_to_addr(&req->orb.ptr1),
+		sbp2_pointer_to_addr(&req->orb.ptr2),
+		be32_to_cpu(req->orb.misc), be32_to_cpu(req->orb.length),
+		sbp2_pointer_to_addr(&req->orb.status_fifo));
+
+	if (!ORB_NOTIFY(be32_to_cpu(req->orb.misc)) ||
+		ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc)) != 0) {
+		pr_err("mgt_orb bad request\n");
+		goto out;
+	}
+
+	switch (MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc))) {
+	case MANAGEMENT_ORB_FUNCTION_LOGIN:
+		sbp_management_request_login(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS:
+		sbp_management_request_query_logins(agent, req,
+				&status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_RECONNECT:
+		sbp_management_request_reconnect(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_SET_PASSWORD:
+		pr_notice("SET PASSWORD not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_LOGOUT:
+		sbp_management_request_logout(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_ABORT_TASK:
+		pr_notice("ABORT TASK not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET:
+		pr_notice("ABORT TASK SET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET:
+		pr_notice("LOGICAL UNIT RESET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_TARGET_RESET:
+		pr_notice("TARGET RESET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	default:
+		pr_notice("unknown management function 0x%x\n",
+			MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc)));
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+	}
+
+	req->status.status |= cpu_to_be32(
+		STATUS_BLOCK_SRC(1) | /* Response to ORB, next_ORB absent */
+		STATUS_BLOCK_LEN(DIV_ROUND_UP(status_data_len, 4) + 1) |
+		STATUS_BLOCK_ORB_OFFSET_HIGH(agent->orb_offset >> 32));
+	req->status.orb_low = cpu_to_be32(agent->orb_offset);
+
+	/* write the status block back to the initiator */
+	ret = fw_run_transaction(req->card, TCODE_WRITE_BLOCK_REQUEST,
+		req->node_addr, req->generation, req->speed,
+		sbp2_pointer_to_addr(&req->orb.status_fifo),
+		&req->status, 8 + status_data_len);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("mgt_orb status write failed: %x\n", ret);
+		goto out;
+	}
+
+out:
+	fw_card_put(req->card);
+	kfree(req);
+	atomic_set(&agent->state, MANAGEMENT_AGENT_STATE_IDLE);
+}
+
+static void sbp_mgt_agent_rw(struct fw_card *card,
+	struct fw_request *request, int tcode, int destination, int source,
+	int generation, unsigned long long offset, void *data, size_t length,
+	void *callback_data)
+{
+	struct sbp_management_agent *agent = callback_data;
+	struct sbp2_pointer *ptr = data;
+
+	if (!agent->tport->enable) {
+		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+		return;
+	}
+
+	if ((offset != agent->handler.offset) || (length != 8)) {
+		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+		return;
+	}
+
+	if (tcode == TCODE_WRITE_BLOCK_REQUEST) {
+		struct sbp_management_request *req;
+		int ret;
+
+		smp_wmb();
+		if (atomic_cmpxchg(&agent->state,
+					MANAGEMENT_AGENT_STATE_IDLE,
+					MANAGEMENT_AGENT_STATE_BUSY) !=
+				MANAGEMENT_AGENT_STATE_IDLE) {
+			pr_notice("ignoring management request while busy\n");
+
+			fw_send_response(card, request, RCODE_CONFLICT_ERROR);
+			return;
+		}
+
+		req = kzalloc(sizeof(*req), GFP_ATOMIC);
+		if (!req) {
+			fw_send_response(card, request, RCODE_CONFLICT_ERROR);
+			return;
+		}
+
+		req->card = fw_card_get(card);
+		req->generation = generation;
+		req->node_addr = source;
+		req->speed = fw_get_request_speed(request);
+
+		agent->orb_offset = sbp2_pointer_to_addr(ptr);
+		agent->request = req;
+
+		ret = queue_work(sbp_workqueue, &agent->work);
+		if (!ret) {
+			/* pretend we're busy */
+			kfree(req);
+			fw_send_response(card, request, RCODE_CONFLICT_ERROR);
+			return;
+		}
+
+		fw_send_response(card, request, RCODE_COMPLETE);
+	} else if (tcode == TCODE_READ_BLOCK_REQUEST) {
+		addr_to_sbp2_pointer(agent->orb_offset, ptr);
+		fw_send_response(card, request, RCODE_COMPLETE);
+	} else {
+		fw_send_response(card, request, RCODE_TYPE_ERROR);
+	}
+}
+
+struct sbp_management_agent *sbp_management_agent_register(
+		struct sbp_tport *tport)
+{
+	int ret;
+	struct sbp_management_agent *agent;
+
+	agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+	if (!agent)
+		return ERR_PTR(-ENOMEM);
+
+	agent->tport = tport;
+	agent->handler.length = 0x08;
+	agent->handler.address_callback = sbp_mgt_agent_rw;
+	agent->handler.callback_data = agent;
+	atomic_set(&agent->state, MANAGEMENT_AGENT_STATE_IDLE);
+	INIT_WORK(&agent->work, sbp_mgt_agent_process);
+	agent->orb_offset = 0;
+	agent->request = NULL;
+
+	ret = fw_core_add_address_handler(&agent->handler,
+			&sbp_register_region);
+	if (ret < 0) {
+		kfree(agent);
+		return ERR_PTR(ret);
+	}
+
+	return agent;
+}
+
+void sbp_management_agent_unregister(struct sbp_management_agent *agent)
+{
+	if (atomic_read(&agent->state) != MANAGEMENT_AGENT_STATE_IDLE)
+		flush_work_sync(&agent->work);
+
+	fw_core_remove_address_handler(&agent->handler);
+	kfree(agent);
+}
+
diff --git a/drivers/target/sbp/sbp_management_agent.h b/drivers/target/sbp/sbp_management_agent.h
new file mode 100644
index 0000000..615b90e
--- /dev/null
+++ b/drivers/target/sbp/sbp_management_agent.h
@@ -0,0 +1,23 @@
+
+struct sbp_management_agent {
+	struct sbp_tport *tport;
+	struct fw_address_handler handler;
+	atomic_t state;
+	struct work_struct work;
+	u64 orb_offset;
+	struct sbp_management_request *request;
+};
+
+struct sbp_management_request {
+	struct sbp_management_orb orb;
+	struct sbp_status_block status;
+	struct fw_card *card;
+	int generation;
+	int node_addr;
+	int speed;
+};
+
+struct sbp_management_agent *sbp_management_agent_register(
+		struct sbp_tport *tport);
+void sbp_management_agent_unregister(struct sbp_management_agent *agent);
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 08/11] firewire-sbp-target: Add sbp_login.{c,h}
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
                       ` (6 preceding siblings ...)
  2012-02-15 14:47     ` [PATCH v2 07/11] firewire-sbp-target: add sbp_management_agent.{c,h} Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 21:00       ` Stefan Richter
  2012-02-15 14:47     ` [PATCH v2 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
                       ` (3 subsequent siblings)
  11 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This file contains the implementation of the login, reconnect and logout
management ORBs in SBP-2.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_login.c |  665 ++++++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_login.h |   14 +
 2 files changed, 679 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_login.c
 create mode 100644 drivers/target/sbp/sbp_login.h

diff --git a/drivers/target/sbp/sbp_login.c b/drivers/target/sbp/sbp_login.c
new file mode 100644
index 0000000..74b5eaf
--- /dev/null
+++ b/drivers/target/sbp/sbp_login.c
@@ -0,0 +1,665 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kref.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/slab.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+#include "sbp_login.h"
+#include "sbp_target_agent.h"
+
+#define SESSION_MAINTENANCE_INTERVAL HZ
+
+static atomic_t login_id = ATOMIC_INIT(0);
+
+static void session_maintenance_work(struct work_struct *work);
+
+static int read_peer_guid(u64 *guid, const struct sbp_management_request *req)
+{
+	int ret;
+	__be32 high, low;
+
+	ret = fw_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+			req->node_addr, req->generation, req->speed,
+			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 3 * 4,
+			&high, sizeof(high));
+	if (ret != RCODE_COMPLETE)
+		return ret;
+
+	ret = fw_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+			req->node_addr, req->generation, req->speed,
+			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 4 * 4,
+			&low, sizeof(low));
+	if (ret != RCODE_COMPLETE)
+		return ret;
+
+	*guid = (u64)be32_to_cpu(high) << 32 | be32_to_cpu(low);
+
+	return RCODE_COMPLETE;
+}
+
+static struct sbp_session *sbp_session_find_by_guid(
+	struct sbp_tpg *tpg, u64 guid)
+{
+	struct se_session *se_sess;
+
+	spin_lock(&tpg->se_tpg.session_lock);
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		struct sbp_session *sess = se_sess->fabric_sess_ptr;
+		if (sess->guid == guid) {
+			spin_unlock(&tpg->se_tpg.session_lock);
+			return sess;
+		}
+	}
+	spin_unlock(&tpg->se_tpg.session_lock);
+
+	return NULL;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_lun(
+		struct sbp_session *session, struct se_lun *lun)
+{
+	struct sbp_login_descriptor *login;
+
+	spin_lock(&session->login_list_lock);
+	list_for_each_entry(login, &session->login_list, link) {
+		if (login->lun == lun) {
+			spin_unlock(&session->login_list_lock);
+			return login;
+		}
+	}
+	spin_unlock(&session->login_list_lock);
+
+	return NULL;
+}
+
+static int sbp_login_count_all_by_lun(
+		struct sbp_tpg *tpg,
+		struct se_lun *lun,
+		int exclusive)
+{
+	struct se_session *se_sess;
+	int count = 0;
+
+	spin_lock(&tpg->se_tpg.session_lock);
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		struct sbp_session *sess = se_sess->fabric_sess_ptr;
+		struct sbp_login_descriptor *login;
+
+		spin_lock(&sess->login_list_lock);
+		list_for_each_entry(login, &sess->login_list, link) {
+			if (login->lun != lun)
+				continue;
+
+			if (!exclusive) {
+				count++;
+				continue;
+			}
+
+			if (login->exclusive)
+				count++;
+		}
+		spin_unlock(&sess->login_list_lock);
+	}
+	spin_unlock(&tpg->se_tpg.session_lock);
+
+	return count;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_id(
+	struct sbp_tpg *tpg, int login_id)
+{
+	struct se_session *se_sess;
+
+	spin_lock(&tpg->se_tpg.session_lock);
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		struct sbp_session *sess = se_sess->fabric_sess_ptr;
+		struct sbp_login_descriptor *login;
+
+		spin_lock(&sess->login_list_lock);
+		list_for_each_entry(login, &sess->login_list, link) {
+			if (login->login_id == login_id) {
+				spin_unlock(&sess->login_list_lock);
+				spin_unlock(&tpg->se_tpg.session_lock);
+				return login;
+			}
+		}
+		spin_unlock(&sess->login_list_lock);
+	}
+	spin_unlock(&tpg->se_tpg.session_lock);
+
+	return NULL;
+}
+
+static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun)
+{
+	struct se_portal_group *se_tpg = &tpg->se_tpg;
+	struct se_lun *se_lun;
+
+	if (lun >= TRANSPORT_MAX_LUNS_PER_TPG)
+		return ERR_PTR(-ENODEV);
+
+	spin_lock(&se_tpg->tpg_lun_lock);
+	se_lun = &se_tpg->tpg_lun_list[lun];
+
+	if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
+		se_lun = ERR_PTR(-EINVAL);
+
+	spin_unlock(&se_tpg->tpg_lun_lock);
+
+	return se_lun;
+}
+
+static struct sbp_session *sbp_session_create(
+		struct sbp_tpg *tpg,
+		u64 guid)
+{
+	struct sbp_session *sess;
+	int ret;
+	char guid_str[17];
+	struct se_node_acl *se_nacl;
+
+	sess = kmalloc(sizeof(*sess), GFP_KERNEL);
+	if (!sess) {
+		pr_err("failed to allocate session descriptor\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sess->se_sess = transport_init_session();
+	if (IS_ERR(sess->se_sess)) {
+		pr_err("failed to init se_session\n");
+
+		ret = PTR_ERR(sess->se_sess);
+		kfree(sess);
+		return ERR_PTR(ret);
+	}
+
+	snprintf(guid_str, sizeof(guid_str), "%016llx", guid);
+
+	se_nacl = core_tpg_check_initiator_node_acl(&tpg->se_tpg, guid_str);
+	if (!se_nacl) {
+		pr_warn("Node ACL not found for %s\n", guid_str);
+
+		transport_free_session(sess->se_sess);
+		kfree(sess);
+
+		return ERR_PTR(-EPERM);
+	}
+
+	sess->se_sess->se_node_acl = se_nacl;
+
+	INIT_LIST_HEAD(&sess->login_list);
+	spin_lock_init(&sess->login_list_lock);
+	INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work);
+
+	sess->guid = guid;
+
+	transport_register_session(&tpg->se_tpg, se_nacl, sess->se_sess, sess);
+
+	return sess;
+}
+
+static void sbp_session_release(struct sbp_session *sess, bool cancel_work)
+{
+	spin_lock(&sess->login_list_lock);
+	if (!list_empty(&sess->login_list)) {
+		spin_unlock(&sess->login_list_lock);
+		return;
+	}
+	spin_unlock(&sess->login_list_lock);
+
+	transport_deregister_session_configfs(sess->se_sess);
+	transport_deregister_session(sess->se_sess);
+
+	if (sess->card)
+		fw_card_put(sess->card);
+
+	if (cancel_work)
+		cancel_delayed_work_sync(&sess->maint_work);
+
+	kfree(sess);
+}
+
+static void sbp_login_release(struct sbp_login_descriptor *login,
+	bool cancel_work)
+{
+	struct sbp_session *sess = login->sess;
+
+	/* FIXME: abort/wait on tasks */
+
+	spin_lock(&sess->login_list_lock);
+	list_del(&login->link);
+	spin_unlock(&sess->login_list_lock);
+
+	sbp_target_agent_unregister(login->tgt_agt);
+	sbp_session_release(sess, cancel_work);
+	kfree(login);
+}
+
+void sbp_management_request_login(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	struct se_lun *se_lun;
+	int ret;
+	u64 guid;
+	struct sbp_session *sess;
+	struct sbp_login_descriptor *login;
+	struct sbp_login_response_block *response;
+	int login_response_len;
+
+	se_lun = sbp_get_lun_from_tpg(tpg,
+			LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+	if (IS_ERR(se_lun)) {
+		pr_notice("login to unknown LUN: %d\n",
+			LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LUN_NOTSUPP));
+		return;
+	}
+
+	ret = read_peer_guid(&guid, req);
+	if (ret != RCODE_COMPLETE) {
+		pr_warn("failed to read peer GUID: %d\n", ret);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n",
+		se_lun->unpacked_lun, guid);
+
+	sess = sbp_session_find_by_guid(tpg, guid);
+	if (sess) {
+		login = sbp_login_find_by_lun(sess, se_lun);
+		if (login) {
+			pr_notice("initiator already logged-in\n");
+
+			/*
+			 * SBP-2 R4 says we should return access denied, but
+			 * that can confuse initiators. Instead we need to
+			 * treat this like a reconnect, but send the login
+			 * response block like a fresh login.
+			 *
+			 * This is required particularly in the case of Apple
+			 * devices booting off the FireWire target, where
+			 * the firmware has an active login to the target. When
+			 * the OS takes control of the session it issues its own
+			 * LOGIN rather than a RECONNECT. To avoid the machine
+			 * waiting until the reconnect_hold expires, we can skip
+			 * the ACCESS_DENIED errors to speed things up.
+			 */
+
+			goto already_logged_in;
+		}
+	}
+
+	/*
+	 * check exclusive bit in login request
+	 * reject with access_denied if any logins present
+	 */
+	if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) &&
+			sbp_login_count_all_by_lun(tpg, se_lun, 0)) {
+		pr_warn("refusing exclusive login with other active logins\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	/*
+	 * check exclusive bit in any existing login descriptor
+	 * reject with access_denied if any exclusive logins present
+	 */
+	if (sbp_login_count_all_by_lun(tpg, se_lun, 1)) {
+		pr_warn("refusing login while another exclusive login present\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	/*
+	 * check we haven't exceeded the number of allowed logins
+	 * reject with resources_unavailable if we have
+	 */
+	if (sbp_login_count_all_by_lun(tpg, se_lun, 0) >=
+			tport->max_logins_per_lun) {
+		pr_warn("max number of logins reached\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	if (!sess) {
+		sess = sbp_session_create(tpg, guid);
+		if (IS_ERR(sess)) {
+			switch (PTR_ERR(sess)) {
+			case -EPERM:
+				ret = SBP_STATUS_ACCESS_DENIED;
+				break;
+			default:
+				ret = SBP_STATUS_RESOURCES_UNAVAIL;
+				break;
+			}
+
+			req->status.status = cpu_to_be32(
+				STATUS_BLOCK_RESP(
+					STATUS_RESP_REQUEST_COMPLETE) |
+				STATUS_BLOCK_SBP_STATUS(ret));
+			return;
+		}
+
+		sess->node_id = req->node_addr;
+		sess->card = fw_card_get(req->card);
+		sess->generation = req->generation;
+		sess->speed = req->speed;
+
+		queue_delayed_work(sbp_workqueue, &sess->maint_work,
+			SESSION_MAINTENANCE_INTERVAL);
+	}
+
+	/* only take the latest reconnect_hold into account */
+	sess->reconnect_hold = min(
+		1 << LOGIN_ORB_RECONNECT(be32_to_cpu(req->orb.misc)),
+		tport->max_reconnect_timeout) - 1;
+
+	login = kmalloc(sizeof(*login), GFP_KERNEL);
+	if (!login) {
+		pr_err("failed to allocate login descriptor\n");
+
+		sbp_session_release(sess, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	login->sess = sess;
+	login->lun = se_lun;
+	login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo);
+	login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc));
+	login->login_id = atomic_inc_return(&login_id);
+	atomic_set(&login->unsolicited_status_enable, 0);
+
+	login->tgt_agt = sbp_target_agent_register(login);
+	if (IS_ERR(login->tgt_agt)) {
+		ret = PTR_ERR(login->tgt_agt);
+		pr_err("failed to map command block handler: %d\n", ret);
+
+		sbp_session_release(sess, true);
+		kfree(login);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	spin_lock(&sess->login_list_lock);
+	list_add_tail(&login->link, &sess->login_list);
+	spin_unlock(&sess->login_list_lock);
+
+already_logged_in:
+	response = kzalloc(sizeof(*response), GFP_KERNEL);
+	if (!response) {
+		pr_err("failed to allocate login response block\n");
+
+		sbp_login_release(login, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	login_response_len = clamp_val(
+			LOGIN_ORB_RESPONSE_LENGTH(be32_to_cpu(req->orb.length)),
+			12, sizeof(*response));
+	response->misc = cpu_to_be32(
+		((login_response_len & 0xffff) << 16) |
+		(login->login_id & 0xffff));
+	response->reconnect_hold = cpu_to_be32(sess->reconnect_hold & 0xffff);
+	addr_to_sbp2_pointer(login->tgt_agt->handler.offset,
+		&response->command_block_agent);
+
+	ret = fw_run_transaction(sess->card, TCODE_WRITE_BLOCK_REQUEST,
+		sess->node_id, sess->generation, sess->speed,
+		sbp2_pointer_to_addr(&req->orb.ptr2), response,
+		login_response_len);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("failed to write login response block: %x\n", ret);
+
+		kfree(response);
+		sbp_login_release(login, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	kfree(response);
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+void sbp_management_request_query_logins(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	pr_notice("QUERY LOGINS not implemented\n");
+	/* FIXME: implement */
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+}
+
+void sbp_management_request_reconnect(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	int ret;
+	u64 guid;
+	struct sbp_login_descriptor *login;
+
+	ret = read_peer_guid(&guid, req);
+	if (ret != RCODE_COMPLETE) {
+		pr_warn("failed to read peer GUID: %d\n", ret);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	pr_notice("mgt_agent RECONNECT from %016llx\n", guid);
+
+	login = sbp_login_find_by_id(tpg,
+		RECONNECT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc)));
+
+	if (!login) {
+		pr_err("mgt_agent RECONNECT unknown login ID\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	if (login->sess->guid != guid) {
+		pr_err("mgt_agent RECONNECT login GUID doesn't match\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	if (login->sess->card)
+		fw_card_put(login->sess->card);
+
+	/* update the node details */
+	login->sess->generation = req->generation;
+	login->sess->node_id = req->node_addr;
+	login->sess->card = fw_card_get(req->card);
+	login->sess->speed = req->speed;
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+void sbp_management_request_logout(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	int login_id;
+	struct sbp_login_descriptor *login;
+
+	login_id = LOGOUT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc));
+
+	login = sbp_login_find_by_id(tpg, login_id);
+	if (!login) {
+		pr_warn("cannot find login: %d\n", login_id);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LOGIN_ID_UNKNOWN));
+		return;
+	}
+
+	pr_info("mgt_agent LOGOUT from LUN %d session %d\n",
+		login->lun->unpacked_lun, login->login_id);
+
+	if (req->node_addr != login->sess->node_id) {
+		pr_warn("logout from different node ID\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	sbp_login_release(login, true);
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void session_check_for_reset(struct sbp_session *sess)
+{
+	bool card_valid = false;
+
+	if (sess->card) {
+		spin_lock_irq(&sess->card->lock);
+		card_valid = (sess->card->local_node != NULL);
+		spin_unlock_irq(&sess->card->lock);
+
+		if (!card_valid) {
+			fw_card_put(sess->card);
+			sess->card = NULL;
+		}
+	}
+
+	if (!card_valid || (sess->generation != sess->card->generation)) {
+		pr_info("Waiting for reconnect from node: %016llx\n",
+			sess->guid);
+
+		sess->node_id = -1;
+		sess->reconnect_expires = get_jiffies_64() +
+			((sess->reconnect_hold + 1) * HZ);
+	}
+}
+
+static void session_reconnect_expired(struct sbp_session *sess)
+{
+	struct sbp_login_descriptor *login, *temp;
+
+	pr_info("Reconnect timer expired for node: %016llx\n", sess->guid);
+
+	spin_lock(&sess->login_list_lock);
+	list_for_each_entry_safe(login, temp, &sess->login_list, link) {
+		spin_unlock(&sess->login_list_lock);
+		sbp_login_release(login, false);
+		spin_lock(&sess->login_list_lock);
+	}
+	spin_unlock(&sess->login_list_lock);
+
+	/* sbp_login_release() calls sbp_session_release() */
+}
+
+static void session_maintenance_work(struct work_struct *work)
+{
+	struct sbp_session *sess = container_of(work, struct sbp_session,
+		maint_work.work);
+
+	/* could be called while tearing down the session */
+	spin_lock(&sess->login_list_lock);
+	if (list_empty(&sess->login_list)) {
+		spin_unlock(&sess->login_list_lock);
+		return;
+	}
+	spin_unlock(&sess->login_list_lock);
+
+	if (sess->node_id != -1) {
+		/* check for bus reset and make node_id invalid */
+		session_check_for_reset(sess);
+
+		queue_delayed_work(sbp_workqueue, &sess->maint_work,
+			SESSION_MAINTENANCE_INTERVAL);
+	} else if (!time_after64(get_jiffies_64(), sess->reconnect_expires)) {
+		/* still waiting for reconnect */
+		queue_delayed_work(sbp_workqueue, &sess->maint_work,
+			SESSION_MAINTENANCE_INTERVAL);
+	} else {
+		/* reconnect timeout has expired */
+		session_reconnect_expired(sess);
+	}
+}
+
diff --git a/drivers/target/sbp/sbp_login.h b/drivers/target/sbp/sbp_login.h
new file mode 100644
index 0000000..4c86dcb
--- /dev/null
+++ b/drivers/target/sbp/sbp_login.h
@@ -0,0 +1,14 @@
+
+extern void sbp_management_request_login(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+extern void sbp_management_request_query_logins(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+extern void sbp_management_request_reconnect(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+extern void sbp_management_request_logout(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h}
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
                       ` (7 preceding siblings ...)
  2012-02-15 14:47     ` [PATCH v2 08/11] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 21:27       ` Stefan Richter
  2012-02-15 14:47     ` [PATCH v2 10/11] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h} Chris Boot
                       ` (2 subsequent siblings)
  11 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This implements the SBP-2 Command Block Agent, or Target Agent. This is
what receives SCSI commands and forwards them to the target framework.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_target_agent.c |  356 +++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_target_agent.h |   27 +++
 2 files changed, 383 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_target_agent.c
 create mode 100644 drivers/target/sbp/sbp_target_agent.h

diff --git a/drivers/target/sbp/sbp_target_agent.c b/drivers/target/sbp/sbp_target_agent.c
new file mode 100644
index 0000000..66b0b78
--- /dev/null
+++ b/drivers/target/sbp/sbp_target_agent.c
@@ -0,0 +1,356 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/slab.h>
+
+#include <target/target_core_base.h>
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+#include "sbp_login.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+
+static int tgt_agent_rw_agent_state(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	__be32 state;
+
+	switch (tcode) {
+	case TCODE_READ_QUADLET_REQUEST:
+		pr_debug("tgt_agent AGENT_STATE READ\n");
+
+		state = cpu_to_be32(atomic_read(&agent->state));
+		memcpy(data, &state, sizeof(state));
+
+		return RCODE_COMPLETE;
+	
+	case TCODE_WRITE_QUADLET_REQUEST:
+		/* ignored */
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_agent_reset(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	switch (tcode) {
+	case TCODE_WRITE_QUADLET_REQUEST:
+		pr_debug("tgt_agent AGENT_RESET\n");
+		atomic_set(&agent->state, AGENT_STATE_RESET);
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_orb_pointer(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	struct sbp2_pointer *ptr = data;
+	int ret;
+
+	switch (tcode) {
+	case TCODE_WRITE_BLOCK_REQUEST:
+		smp_wmb();
+		atomic_cmpxchg(&agent->state,
+				AGENT_STATE_RESET, AGENT_STATE_SUSPENDED);
+		smp_wmb();
+		if (atomic_cmpxchg(&agent->state,
+					AGENT_STATE_SUSPENDED,
+					AGENT_STATE_ACTIVE)
+				!= AGENT_STATE_SUSPENDED)
+			return RCODE_CONFLICT_ERROR;
+		smp_wmb();
+
+		agent->orb_pointer = sbp2_pointer_to_addr(ptr);
+
+		pr_debug("tgt_agent ORB_POINTER write: 0x%llx\n",
+			agent->orb_pointer);
+
+		ret = queue_work(sbp_workqueue, &agent->work);
+		if (!ret)
+			return RCODE_CONFLICT_ERROR;
+
+		return RCODE_COMPLETE;
+
+	case TCODE_READ_BLOCK_REQUEST:
+		pr_debug("tgt_agent ORB_POINTER READ\n");
+		addr_to_sbp2_pointer(agent->orb_pointer, ptr);
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_doorbell(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	int ret;
+
+	switch (tcode) {
+	case TCODE_WRITE_QUADLET_REQUEST:
+		smp_wmb();
+		if (atomic_cmpxchg(&agent->state,
+					AGENT_STATE_SUSPENDED,
+					AGENT_STATE_ACTIVE)
+				!= AGENT_STATE_SUSPENDED)
+			return RCODE_CONFLICT_ERROR;
+		smp_wmb();
+
+		pr_debug("tgt_agent DOORBELL\n");
+
+		ret = queue_work(sbp_workqueue, &agent->work);
+		if (!ret)
+			return RCODE_CONFLICT_ERROR;
+
+		return RCODE_COMPLETE;
+
+	case TCODE_READ_QUADLET_REQUEST:
+		return RCODE_COMPLETE;
+	
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_unsolicited_status_enable(struct fw_card *card,
+	int tcode, int generation, void *data,
+	struct sbp_target_agent *agent)
+{
+	switch (tcode) {
+	case TCODE_WRITE_QUADLET_REQUEST:
+		pr_debug("tgt_agent UNSOLICITED_STATUS_ENABLE\n");
+		atomic_set(&agent->login->unsolicited_status_enable, 1);
+		return RCODE_COMPLETE;
+
+	case TCODE_READ_QUADLET_REQUEST:
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static void tgt_agent_rw(struct fw_card *card,
+	struct fw_request *request, int tcode, int destination, int source,
+	int generation, unsigned long long offset, void *data, size_t length,
+	void *callback_data)
+{
+	struct sbp_target_agent *agent = callback_data;
+	int rcode = RCODE_ADDRESS_ERROR;
+
+	/* turn offset into the offset from the start of the block */
+	offset -= agent->handler.offset;
+
+	if (source != agent->login->sess->node_id) {
+		pr_notice("ignoring request from foreign node (%x != %x)\n",
+				source, agent->login->sess->node_id);
+		fw_send_response(card, request, RCODE_TYPE_ERROR);
+		return;
+	}
+
+	if (offset == 0x00 && length == 4) {
+		/* AGENT_STATE */
+		rcode = tgt_agent_rw_agent_state(card, tcode,
+			generation, data, agent);
+	} else if (offset == 0x04 && length == 4) {
+		/* AGENT_RESET */
+		rcode = tgt_agent_rw_agent_reset(card, tcode,
+			generation, data, agent);
+	} else if (offset == 0x08 && length == 8) {
+		/* ORB_POINTER */
+		rcode = tgt_agent_rw_orb_pointer(card, tcode,
+			generation, data, agent);
+	} else if (offset == 0x10 && length == 4) {
+		/* DOORBELL */
+		rcode = tgt_agent_rw_doorbell(card, tcode,
+			generation, data, agent);
+	} else if (offset == 0x14 && length == 4) {
+		/* UNSOLICITED_STATUS_ENABLE */
+		rcode = tgt_agent_rw_unsolicited_status_enable(card, tcode,
+			generation, data, agent);
+	}
+
+	fw_send_response(card, request, rcode);
+}
+
+static void tgt_agent_process_work(struct work_struct *work)
+{
+	struct sbp_target_request *req =
+		container_of(work, struct sbp_target_request, work);
+
+	switch (ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc))) {
+	case 0:/* Format specified by this standard */
+		sbp_handle_command(req);
+		return;
+	case 1: /* Reserved for future standardization */
+	case 2: /* Vendor-dependent */
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	case 3: /* Dummy ORB */
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_DUMMY_ORB_COMPLETE));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	default:
+		BUG();
+	}
+}
+
+static void tgt_agent_fetch_work(struct work_struct *work)
+{
+	struct sbp_target_agent *agent =
+		container_of(work, struct sbp_target_agent, work);
+	struct sbp_session *sess = agent->login->sess;
+	struct sbp_target_request *req;
+	int ret;
+
+	smp_rmb();
+	if (atomic_read(&agent->state) != AGENT_STATE_ACTIVE)
+		return;
+
+	req = kzalloc(sizeof(*req), GFP_KERNEL);
+	if (!req) {
+		atomic_cmpxchg(&agent->state, AGENT_STATE_ACTIVE,
+				AGENT_STATE_DEAD);
+		return;
+	}
+
+	req->agent = agent;
+	req->orb_pointer = agent->orb_pointer;
+	req->status.status = cpu_to_be32(
+			STATUS_BLOCK_ORB_OFFSET_HIGH(req->orb_pointer >> 32));
+	req->status.orb_low = cpu_to_be32(agent->orb_pointer & 0xfffffffc);
+	INIT_WORK(&req->work, tgt_agent_process_work);
+
+	/* read in the ORB */
+	ret = fw_run_transaction(sess->card, TCODE_READ_BLOCK_REQUEST,
+		sess->node_id, sess->generation, sess->speed,
+		req->orb_pointer, &req->orb, sizeof(req->orb));
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("tgt_orb fetch failed: %x\n", ret);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(1) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		atomic_cmpxchg(&agent->state, AGENT_STATE_ACTIVE,
+				AGENT_STATE_DEAD);
+		return;
+	}
+
+	pr_debug("tgt_orb ptr:0x%llx next_orb:0x%llx data_descriptor:0x%llx misc:0x%x\n",
+			req->orb_pointer,
+			sbp2_pointer_to_addr(&req->orb.next_orb),
+			sbp2_pointer_to_addr(&req->orb.data_descriptor),
+			be32_to_cpu(req->orb.misc));
+
+	if (req->orb_pointer >> 32)
+		pr_debug("ORB with high bits set\n");
+
+	if (be32_to_cpu(req->orb.next_orb.high) & 0x80000000) {
+		/* NULL next-ORB */
+		req->status.status |= cpu_to_be32(
+				STATUS_BLOCK_SRC(STATUS_SRC_ORB_FINISHED));
+	} else {
+		/* non-NULL next-ORB */
+		req->status.status |= cpu_to_be32(
+				STATUS_BLOCK_SRC(STATUS_SRC_ORB_CONTINUING));
+	}
+
+	queue_work(sbp_workqueue, &req->work);
+
+	/* check if we should carry on processing */
+	if (be32_to_cpu(req->orb.next_orb.high) & 0x80000000) {
+		/* null next_orb */
+		atomic_cmpxchg(&agent->state, AGENT_STATE_ACTIVE,
+				AGENT_STATE_SUSPENDED);
+	} else {
+		pr_debug("non-NULL next-ORB\n");
+		agent->orb_pointer = sbp2_pointer_to_addr(&req->orb.next_orb);
+		queue_work(sbp_workqueue, &agent->work);
+	}
+}
+
+struct sbp_target_agent *sbp_target_agent_register(
+		struct sbp_login_descriptor *login)
+{
+	struct sbp_target_agent *agent;
+	int ret;
+
+	agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+	if (!agent)
+		return ERR_PTR(-ENOMEM);
+
+	agent->handler.length = 0x20;
+	agent->handler.address_callback = tgt_agent_rw;
+	agent->handler.callback_data = agent;
+
+	agent->login = login;
+	atomic_set(&agent->state, AGENT_STATE_RESET);
+	INIT_WORK(&agent->work, tgt_agent_fetch_work);
+	agent->orb_pointer = (u64)-1;
+
+	ret = fw_core_add_address_handler(&agent->handler,
+		&sbp_register_region);
+	if (ret < 0) {
+		kfree(agent);
+		return ERR_PTR(ret);
+	}
+
+	return agent;
+}
+
+void sbp_target_agent_unregister(struct sbp_target_agent *agent)
+{
+	if (atomic_read(&agent->state) == AGENT_STATE_ACTIVE)
+		flush_work_sync(&agent->work);
+
+	fw_core_remove_address_handler(&agent->handler);
+	kfree(agent);
+}
+
diff --git a/drivers/target/sbp/sbp_target_agent.h b/drivers/target/sbp/sbp_target_agent.h
new file mode 100644
index 0000000..cddcc2f
--- /dev/null
+++ b/drivers/target/sbp/sbp_target_agent.h
@@ -0,0 +1,27 @@
+
+struct sbp_target_agent {
+	struct fw_address_handler handler;
+	struct sbp_login_descriptor *login;
+	atomic_t state;
+	struct work_struct work;
+	u64 orb_pointer;
+};
+
+struct sbp_target_request {
+	struct sbp_target_agent *agent;
+	u64 orb_pointer;
+	struct sbp_command_block_orb orb;
+	struct sbp_status_block status;
+	struct work_struct work;
+
+	struct se_cmd se_cmd;
+	struct sbp_page_table_entry *pg_tbl;
+	void *cmd_buf;
+	void *data_buf;
+
+	unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+struct sbp_target_agent *sbp_target_agent_register(
+		struct sbp_login_descriptor *login);
+void sbp_target_agent_unregister(struct sbp_target_agent *agent);
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 10/11] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h}
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
                       ` (8 preceding siblings ...)
  2012-02-15 14:47     ` [PATCH v2 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-02-15 14:47     ` [PATCH v2 11/11] firewire-sbp-target: Add to target Kconfig and Makefile Chris Boot
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
  11 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

Miscellaneous functions for dealing with SCSI commands, status, sense
data and data read/write. This is where the real grunt work of pushing
data in and out of the FireWire bus happens.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_scsi_cmnd.c |  360 ++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_scsi_cmnd.h |    6 +
 2 files changed, 366 insertions(+), 0 deletions(-)
 create mode 100644 drivers/target/sbp/sbp_scsi_cmnd.c
 create mode 100644 drivers/target/sbp/sbp_scsi_cmnd.h

diff --git a/drivers/target/sbp/sbp_scsi_cmnd.c b/drivers/target/sbp/sbp_scsi_cmnd.c
new file mode 100644
index 0000000..e0b4b71
--- /dev/null
+++ b/drivers/target/sbp/sbp_scsi_cmnd.c
@@ -0,0 +1,360 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+
+#include "sbp_base.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+
+/*
+ * Wraps fw_run_transaction taking into account page size and max payload, and
+ * retries the transaction if it fails
+ */
+static int sbp_run_transaction(struct sbp_target_request *req, int tcode,
+	unsigned long long offset, void *payload, size_t length)
+{
+	struct sbp_login_descriptor *login = req->agent->login;
+	struct sbp_session *sess = login->sess;
+	int ret, speed, max_payload, pg_size, seg_off = 0, seg_len;
+
+	speed = CMDBLK_ORB_SPEED(be32_to_cpu(req->orb.misc));
+	max_payload = 4 << CMDBLK_ORB_MAX_PAYLOAD(be32_to_cpu(req->orb.misc));
+	pg_size = CMDBLK_ORB_PG_SIZE(be32_to_cpu(req->orb.misc));
+
+	if (pg_size) {
+		pr_err("sbp_run_transaction: page size ignored\n");
+		pg_size = 0x100 << pg_size;
+	}
+
+	while (seg_off < length) {
+		seg_len = length - seg_off;
+		if (seg_len > max_payload)
+			seg_len = max_payload;
+
+		/* FIXME: take page_size into account */
+
+		/* FIXME: retry failed data transfers */
+		ret = fw_run_transaction(sess->card, tcode,
+				sess->node_id, sess->generation, speed,
+				offset + seg_off, payload + seg_off, seg_len);
+		if (ret != RCODE_COMPLETE) {
+			pr_debug("sbp_run_transaction: txn failed: %x\n", ret);
+			return -EIO;
+		}
+
+		seg_off += seg_len;
+	}
+
+	return 0;
+}
+
+static int sbp_fetch_command(struct sbp_target_request *req)
+{
+	int ret, cmd_len, copy_len;
+
+	cmd_len = scsi_command_size(req->orb.command_block);
+
+	req->cmd_buf = kmalloc(cmd_len, GFP_KERNEL);
+	if (!req->cmd_buf)
+		return -ENOMEM;
+
+	memcpy(req->cmd_buf, req->orb.command_block,
+		min_t(int, cmd_len, sizeof(req->orb.command_block)));
+
+	if (cmd_len > sizeof(req->orb.command_block)) {
+		pr_debug("sbp_fetch_command: filling in long command\n");
+		copy_len = cmd_len - sizeof(req->orb.command_block);
+
+		ret = sbp_run_transaction(req, TCODE_READ_BLOCK_REQUEST,
+			req->orb_pointer + sizeof(req->orb),
+			req->cmd_buf + sizeof(req->orb.command_block),
+			copy_len);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int sbp_fetch_page_table(struct sbp_target_request *req)
+{
+	int pg_tbl_sz, ret;
+	struct sbp_page_table_entry *pg_tbl;
+
+	if (!CMDBLK_ORB_PG_TBL_PRESENT(be32_to_cpu(req->orb.misc)))
+		return 0;
+
+	pg_tbl_sz = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc)) *
+		sizeof(struct sbp_page_table_entry);
+
+	pg_tbl = kmalloc(pg_tbl_sz, GFP_KERNEL);
+	if (!pg_tbl)
+		return -ENOMEM;
+
+	ret = sbp_run_transaction(req, TCODE_READ_BLOCK_REQUEST,
+		sbp2_pointer_to_addr(&req->orb.data_descriptor),
+		pg_tbl, pg_tbl_sz);
+	if (ret) {
+		kfree(pg_tbl);
+		return ret;
+	}
+
+	req->pg_tbl = pg_tbl;
+	return 0;
+}
+
+static void sbp_calc_data_length_direction(struct sbp_target_request *req,
+	u32 *data_len, enum dma_data_direction *data_dir)
+{
+	int data_size, direction, idx;
+
+	data_size = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+	direction = CMDBLK_ORB_DIRECTION(be32_to_cpu(req->orb.misc));
+
+	if (!data_size) {
+		*data_len = 0;
+		*data_dir = DMA_NONE;
+		return;
+	}
+
+	*data_dir = direction ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+	if (req->pg_tbl) {
+		*data_len = 0;
+		for (idx = 0; idx < data_size; idx++) {
+			*data_len += be16_to_cpu(
+					req->pg_tbl[idx].segment_length);
+		}
+	} else {
+		*data_len = data_size;
+	}
+}
+
+void sbp_handle_command(struct sbp_target_request *req)
+{
+	struct sbp_login_descriptor *login = req->agent->login;
+	struct sbp_session *sess = login->sess;
+	int ret, unpacked_lun;
+	u32 data_length;
+	enum dma_data_direction data_dir;
+
+	ret = sbp_fetch_command(req);
+	if (ret) {
+		pr_debug("sbp_handle_command: fetch command failed: %d\n", ret);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	}
+
+	ret = sbp_fetch_page_table(req);
+	if (ret) {
+		pr_debug("sbp_handle_command: fetch page table failed: %d\n",
+			ret);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	}
+
+	unpacked_lun = req->agent->login->lun->unpacked_lun;
+	sbp_calc_data_length_direction(req, &data_length, &data_dir);
+
+	pr_debug("sbp_handle_command unpacked_lun:%d data_len:%d data_dir:%d\n",
+			unpacked_lun, data_length, data_dir);
+
+	target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf,
+			req->sense_buf, unpacked_lun, data_length,
+			MSG_SIMPLE_TAG, data_dir, 0);
+}
+
+/*
+ * DMA_TO_DEVICE = read from initiator (SCSI WRITE)
+ * DMA_FROM_DEVICE = write to initiator (SCSI READ)
+ */
+int sbp_rw_data(struct sbp_target_request *req)
+{
+	int ret, tcode;
+
+	tcode = (req->se_cmd.data_direction == DMA_TO_DEVICE) ?
+		TCODE_READ_BLOCK_REQUEST :
+		TCODE_WRITE_BLOCK_REQUEST;
+
+	if (req->pg_tbl) {
+		int idx, offset = 0, data_size;
+
+		data_size = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+
+		for (idx = 0; idx < data_size; idx++) {
+			struct sbp_page_table_entry *pte = &req->pg_tbl[idx];
+			int pte_len = be16_to_cpu(pte->segment_length);
+			u64 pte_offset =
+				(u64)be16_to_cpu(pte->segment_base_hi) << 32 |
+				be32_to_cpu(pte->segment_base_lo);
+
+			ret = sbp_run_transaction(req, tcode, pte_offset,
+					req->data_buf + offset, pte_len);
+			if (ret)
+				break;
+
+			offset += pte_len;
+		}
+	} else {
+		ret = sbp_run_transaction(req, tcode,
+				sbp2_pointer_to_addr(&req->orb.data_descriptor),
+				req->data_buf, req->se_cmd.data_length);
+	}
+
+	return ret;
+}
+
+int sbp_send_status(struct sbp_target_request *req)
+{
+	int ret, length;
+	struct sbp_login_descriptor *login = req->agent->login;
+
+	length = (((be32_to_cpu(req->status.status) >> 24) & 0x07) + 1) * 4;
+
+	ret = sbp_run_transaction(req, TCODE_WRITE_BLOCK_REQUEST,
+			login->status_fifo_addr, &req->status, length);
+	if (ret) {
+		pr_debug("sbp_send_status: write failed: %d\n", ret);
+		return ret;
+	}
+
+	pr_debug("sbp_send_status: status write complete for ORB: 0x%llx\n",
+			req->orb_pointer);
+
+	return 0;
+}
+
+static void sbp_sense_mangle(struct sbp_target_request *req)
+{
+	struct se_cmd *se_cmd = &req->se_cmd;
+	u8 *sense = req->sense_buf;
+	u8 *status = req->status.data;
+
+	WARN_ON(se_cmd->scsi_sense_length < 18);
+
+	switch (sense[0] & 0x7f) { 		/* sfmt */
+	case 0x70: /* current, fixed */
+		status[0] = 0 << 6;
+		break;
+	case 0x71: /* deferred, fixed */
+		status[0] = 1 << 6;
+		break;
+	case 0x72: /* current, descriptor */
+	case 0x73: /* deferred, descriptor */
+	default:
+		/*
+		 * TODO: SBP-3 specifies what we should do with descriptor
+		 * format sense data
+		 */
+		pr_err("sbp_send_sense: unknown sense format: 0x%x\n",
+			sense[0]);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQUEST_ABORTED));
+		return;
+	}
+
+	status[0] |= se_cmd->scsi_status & 0x3f;/* status */
+	status[1] =
+		(sense[0] & 0x80) |		/* valid */
+		((sense[2] & 0xe0) >> 1) |	/* mark, eom, ili */
+		(sense[2] & 0x0f);		/* sense_key */
+	status[2] = se_cmd->scsi_asc;		/* sense_code */
+	status[3] = se_cmd->scsi_ascq;		/* sense_qualifier */
+
+	/* information */
+	status[4] = sense[3];
+	status[5] = sense[4];
+	status[6] = sense[5];
+	status[7] = sense[6];
+
+	/* CDB-dependent */
+	status[8] = sense[8];
+	status[9] = sense[9];
+	status[10] = sense[10];
+	status[11] = sense[11];
+
+	/* fru */
+	status[12] = sense[14];
+
+	/* sense_key-dependent */
+	status[13] = sense[15];
+	status[14] = sense[16];
+	status[15] = sense[17];
+
+	req->status.status |= cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_DEAD(0) |
+		STATUS_BLOCK_LEN(5) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+int sbp_send_sense(struct sbp_target_request *req)
+{
+	struct se_cmd *se_cmd = &req->se_cmd;
+
+	if (se_cmd->scsi_sense_length) {
+		sbp_sense_mangle(req);
+	} else {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+	}
+
+	return sbp_send_status(req);
+}
+
+void sbp_free_request(struct sbp_target_request *req)
+{
+	kfree(req->pg_tbl);
+	kfree(req->cmd_buf);
+	kfree(req->data_buf);
+	kfree(req);
+}
diff --git a/drivers/target/sbp/sbp_scsi_cmnd.h b/drivers/target/sbp/sbp_scsi_cmnd.h
new file mode 100644
index 0000000..5e82b25
--- /dev/null
+++ b/drivers/target/sbp/sbp_scsi_cmnd.h
@@ -0,0 +1,6 @@
+
+void sbp_handle_command(struct sbp_target_request *req);
+int sbp_rw_data(struct sbp_target_request *req);
+int sbp_send_status(struct sbp_target_request *req);
+int sbp_send_sense(struct sbp_target_request *req);
+void sbp_free_request(struct sbp_target_request *req);
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH v2 11/11] firewire-sbp-target: Add to target Kconfig and Makefile
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
                       ` (9 preceding siblings ...)
  2012-02-15 14:47     ` [PATCH v2 10/11] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h} Chris Boot
@ 2012-02-15 14:47     ` Chris Boot
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
  11 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-15 14:47 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This commit also adds an entry to the MAINTAINERS file.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 MAINTAINERS             |    9 +++++++++
 drivers/target/Kconfig  |    1 +
 drivers/target/Makefile |    1 +
 3 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index c0f348d..252aa72 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2695,6 +2695,15 @@ T:	git git://git.alsa-project.org/alsa-kernel.git
 S:	Maintained
 F:	sound/firewire/
 
+FIREWIRE SBP-2 TARGET
+M:  Chris Boot <bootc@bootc.net>
+L:  linux-scsi@vger.kernel.org
+L:  target-devel@vger.kernel.org
+L:  linux1394-devel@lists.sourceforge.net
+T:  git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
+S:  Maintained
+F:  drivers/target/sbp/
+
 FIREWIRE SUBSYSTEM
 M:	Stefan Richter <stefanr@s5r6.in-berlin.de>
 L:	linux1394-devel@lists.sourceforge.net
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
index fc5fa9f..2cfa467 100644
--- a/drivers/target/Kconfig
+++ b/drivers/target/Kconfig
@@ -41,5 +41,6 @@ source "drivers/target/tcm_fc/Kconfig"
 source "drivers/target/iscsi/Kconfig"
 source "drivers/target/tcm_vhost/Kconfig"
 source "drivers/target/usb-gadget/Kconfig"
+source "drivers/target/sbp/Kconfig"
 
 endif
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 6b5f526..1ae8862 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_TCM_FC)		+= tcm_fc/
 obj-$(CONFIG_ISCSI_TARGET)	+= iscsi/
 obj-$(CONFIG_TCM_VHOST)		+= tcm_vhost/
 obj-$(CONFIG_TARGET_USB_GADGET)	+= usb-gadget/
+obj-$(CONFIG_FIREWIRE_SBP_TARGET) += sbp/
-- 
1.7.9


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request
  2012-02-15 14:47     ` [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request Chris Boot
@ 2012-02-15 19:09       ` Stefan Richter
  2012-02-15 19:10         ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-15 19:09 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 15 Chris Boot wrote:
> --- a/drivers/firewire/core-transaction.c
> +++ b/drivers/firewire/core-transaction.c
> @@ -820,6 +820,22 @@ void fw_send_response(struct fw_card *card,
>  }
>  EXPORT_SYMBOL(fw_send_response);
>  
> +/**
> + * fw_get_request_speed() - Discover bus speed used for this request
> + * @request:	The struct fw_request from which to obtain the speed.
> + *
> + * In certain circumstances it's important to be able to obtain the speed at
> + * which a request was made to an address handler, for example when
> + * implementing an SBP-2 or SBP-3 target. This function inspects the response
> + * object to obtain the speed, which is copied from the request packet in
> + * allocate_request().
> + */
> +int fw_get_request_speed(struct fw_request *request)
> +{
> +	return request->response.speed;
> +}
> +EXPORT_SYMBOL(fw_get_request_speed);

Uh oh, what have I done by asking for a comment? :-)

Can you tell what's wrong with this API documentation?
-- 
Stefan Richter
-=====-===-- --=- -====
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 02/11] firewire: Move fw_card kref functions into linux/firewire.h
  2012-02-15 14:47     ` [PATCH v2 02/11] firewire: Move fw_card kref functions into linux/firewire.h Chris Boot
@ 2012-02-15 19:10       ` Stefan Richter
  2012-02-16  9:18         ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-15 19:10 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 15 Chris Boot wrote:
> When writing a firewire driver that doesn't deal with struct fw_device
> objects (e.g. it only publishes FireWire units and doesn't subscribe to
> them), you likely need to keep referenced to struct fw_card objects so
> that you can send messages to other nodes. This patch moves
> fw_card_put(), fw_card_get() and fw_card_release() into the public
> include/linux/firewire.h header instead of drivers/firewire/core.h, and
> adds EXPORT_SYMBOL_GPL(fw_card_release).
> 
> The firewire-sbp-target module requires these so it can keep a reference
> to the fw_card object in order that it can fetch ORBs to execute and
> read/write related data and status information.
> 
> Signed-off-by: Chris Boot <bootc@bootc.net>
> Cc: Clemens Ladisch <clemens@ladisch.de>

Acked-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

> ---
>  drivers/firewire/core-card.c |    1 +
>  drivers/firewire/core.h      |   15 ---------------
>  include/linux/firewire.h     |   14 ++++++++++++++
>  3 files changed, 15 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
> index 85661b0..42b180b 100644
> --- a/drivers/firewire/core-card.c
> +++ b/drivers/firewire/core-card.c
> @@ -654,6 +654,7 @@ void fw_card_release(struct kref *kref)
>  
>  	complete(&card->done);
>  }
> +EXPORT_SYMBOL_GPL(fw_card_release);
>  
>  void fw_core_remove_card(struct fw_card *card)
>  {
> diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
> index b45be57..b44657b 100644
> --- a/drivers/firewire/core.h
> +++ b/drivers/firewire/core.h
> @@ -111,21 +111,6 @@ int fw_compute_block_crc(__be32 *block);
>  void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset);
>  void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
>  
> -static inline struct fw_card *fw_card_get(struct fw_card *card)
> -{
> -	kref_get(&card->kref);
> -
> -	return card;
> -}
> -
> -void fw_card_release(struct kref *kref);
> -
> -static inline void fw_card_put(struct fw_card *card)
> -{
> -	kref_put(&card->kref, fw_card_release);
> -}
> -
> -
>  /* -cdev */
>  
>  extern const struct file_operations fw_device_ops;
> diff --git a/include/linux/firewire.h b/include/linux/firewire.h
> index f010307..341e51c 100644
> --- a/include/linux/firewire.h
> +++ b/include/linux/firewire.h
> @@ -138,6 +138,20 @@ struct fw_card {
>  	__be32 maint_utility_register;
>  };
>  
> +static inline struct fw_card *fw_card_get(struct fw_card *card)
> +{
> +	kref_get(&card->kref);
> +
> +	return card;
> +}
> +
> +void fw_card_release(struct kref *kref);
> +
> +static inline void fw_card_put(struct fw_card *card)
> +{
> +	kref_put(&card->kref, fw_card_release);
> +}
> +
>  struct fw_attribute_group {
>  	struct attribute_group *groups[2];
>  	struct attribute_group group;



-- 
Stefan Richter
-=====-===-- --=- -====
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request
  2012-02-15 19:09       ` Stefan Richter
@ 2012-02-15 19:10         ` Chris Boot
  2012-02-15 22:01           ` Stefan Richter
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-15 19:10 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 15/02/2012 19:09, Stefan Richter wrote:
> On Feb 15 Chris Boot wrote:
>> --- a/drivers/firewire/core-transaction.c
>> +++ b/drivers/firewire/core-transaction.c
>> @@ -820,6 +820,22 @@ void fw_send_response(struct fw_card *card,
>>   }
>>   EXPORT_SYMBOL(fw_send_response);
>>
>> +/**
>> + * fw_get_request_speed() - Discover bus speed used for this request
>> + * @request:	The struct fw_request from which to obtain the speed.
>> + *
>> + * In certain circumstances it's important to be able to obtain the speed at
>> + * which a request was made to an address handler, for example when
>> + * implementing an SBP-2 or SBP-3 target. This function inspects the response
>> + * object to obtain the speed, which is copied from the request packet in
>> + * allocate_request().
>> + */
>> +int fw_get_request_speed(struct fw_request *request)
>> +{
>> +	return request->response.speed;
>> +}
>> +EXPORT_SYMBOL(fw_get_request_speed);
>
> Uh oh, what have I done by asking for a comment? :-)
>
> Can you tell what's wrong with this API documentation?

Better to have too much than too little? :-)

Linux 3.4, now with added Enterprise.

Shall I cut it down a bit?

Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 04/11] firewire-sbp-target: Add sbp_base.h header
  2012-02-15 14:47     ` [PATCH v2 04/11] firewire-sbp-target: Add sbp_base.h header Chris Boot
@ 2012-02-15 19:15       ` Stefan Richter
  2012-02-16  9:55         ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-15 19:15 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 15 Chris Boot wrote:
> --- /dev/null
> +++ b/drivers/target/sbp/sbp_base.h
> @@ -0,0 +1,204 @@
[...]
> +struct sbp2_pointer {
> +	__be32 high;
> +	__be32 low;
> +};
[...]
> +struct sbp_tport {
> +	/* Target Unit Identifier (EUI-64) */
> +	u64 guid;
> +	/* Target port name */
> +	char tport_name[SBP_NAMELEN];
> +	/* Returned by sbp_make_tport() */
> +	struct se_wwn tport_wwn;
> +
> +	struct sbp_tpg *tpg;
> +
> +	/* FireWire unit directory */
> +	struct fw_descriptor unit_directory;
> +
> +	/* SBP Management Agent */
> +	struct sbp_management_agent *mgt_agt;
> +
> +	/* Parameters */
> +	int enable;
> +	s32 directory_id;
> +	int mgt_orb_timeout;
> +	int max_reconnect_timeout;
> +	int max_logins_per_lun;
> +};
> +
> +extern struct target_fabric_configfs *sbp_fabric_configfs;
> +extern const struct fw_address_region sbp_register_region;
> +extern struct workqueue_struct *sbp_workqueue;
[...]

Generally, any source file (.c or .h) is meant to be self-contained WRT
type definitions etc., meaning that they should have all required
#include's in themselves rather than rely on indirect includes.

So here you should include the headers which define __be32, u64, struct
se_wwn, struct workqueue and so on.
-- 
Stefan Richter
-=====-===-- --=- -====
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 05/11] firewire-sbp-target: Add sbp_configfs.c
  2012-02-15 14:47     ` [PATCH v2 05/11] firewire-sbp-target: Add sbp_configfs.c Chris Boot
@ 2012-02-15 19:21       ` Stefan Richter
  2012-02-16  9:57         ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-15 19:21 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 15 Chris Boot wrote:
> --- /dev/null
> +++ b/drivers/target/sbp/sbp_configfs.c
> @@ -0,0 +1,751 @@
> +/*
> + * SBP2 target driver (SCSI over IEEE1394 in target mode)
> + *
> + * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +#define KMSG_COMPONENT "sbp_target"
> +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/moduleparam.h>
> +#include <linux/version.h>
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/kthread.h>
> +#include <linux/types.h>
> +#include <linux/string.h>
> +#include <linux/configfs.h>
> +#include <linux/ctype.h>
> +#include <linux/firewire.h>
> +
> +#include <asm/unaligned.h>
> +
> +#include <target/target_core_base.h>
> +#include <target/target_core_backend.h>
> +#include <target/target_core_fabric.h>
> +#include <target/target_core_configfs.h>
> +#include <target/target_core_fabric_configfs.h>
> +#include <target/configfs_macros.h>
> +
> +#include "sbp_base.h"
> +#include "sbp_fabric.h"
> +#include "sbp_management_agent.h"
> +
> +/* Local pointer to allocated TCM configfs fabric module */
> +struct target_fabric_configfs *sbp_fabric_configfs;
> +
> +struct workqueue_struct *sbp_workqueue;

#include <linux/workqueue.h> goes before this.

[...]
> +	sbp_workqueue = alloc_workqueue("firewire-sbp-target", WQ_UNBOUND, 0);
> +	if (!sbp_workqueue) {
> +		target_fabric_configfs_deregister(fabric);
> +		return -ENOMEM;
> +	}

What are your specific requirements that you cannot use one of the
system-wide workqueues?
-- 
Stefan Richter
-=====-===-- --=- -====
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 07/11] firewire-sbp-target: add sbp_management_agent.{c,h}
  2012-02-15 14:47     ` [PATCH v2 07/11] firewire-sbp-target: add sbp_management_agent.{c,h} Chris Boot
@ 2012-02-15 19:48       ` Stefan Richter
  2012-02-16 10:28         ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-15 19:48 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 15 Chris Boot wrote:
> --- /dev/null
> +++ b/drivers/target/sbp/sbp_management_agent.c
[...]
> +static void sbp_mgt_agent_rw(struct fw_card *card,
> +	struct fw_request *request, int tcode, int destination, int source,
> +	int generation, unsigned long long offset, void *data, size_t length,
> +	void *callback_data)
> +{
> +	struct sbp_management_agent *agent = callback_data;
> +	struct sbp2_pointer *ptr = data;
> +
> +	if (!agent->tport->enable) {
> +		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
> +		return;
> +	}
> +
> +	if ((offset != agent->handler.offset) || (length != 8)) {
> +		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
> +		return;
> +	}
> +
> +	if (tcode == TCODE_WRITE_BLOCK_REQUEST) {
> +		struct sbp_management_request *req;
> +		int ret;
> +
> +		smp_wmb();
> +		if (atomic_cmpxchg(&agent->state,
> +					MANAGEMENT_AGENT_STATE_IDLE,
> +					MANAGEMENT_AGENT_STATE_BUSY) !=
> +				MANAGEMENT_AGENT_STATE_IDLE) {
> +			pr_notice("ignoring management request while busy\n");
> +
> +			fw_send_response(card, request, RCODE_CONFLICT_ERROR);
> +			return;
> +		}

There is a rule of thumb which says:  If you add a memory barrier anywhere
in your code, also add a comment saying which accesses this barrier is
meant to bring into order.

So after the write barrier is apparently the agent->state access.  What
access is before the barrier?

And how does the read side look like?

These questions are mostly rhetoric.  It is quite likely that this code is
better off with a plain and simple mutex serialization.

[...]
> +void sbp_management_agent_unregister(struct sbp_management_agent *agent)
> +{
> +	if (atomic_read(&agent->state) != MANAGEMENT_AGENT_STATE_IDLE)
> +		flush_work_sync(&agent->work);
> +
> +	fw_core_remove_address_handler(&agent->handler);
> +	kfree(agent);
> +}

I still have yet to test-apply all your patches, look at the sum of the
code and understand what the execution contexts and critical sections
are.  So I really should not yet ask the next, uninformed question.

Looking at this function, I wonder:  Can the agent->state change after you
read it, and what would happen then?
-- 
Stefan Richter
-=====-===-- --=- -====
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 08/11] firewire-sbp-target: Add sbp_login.{c,h}
  2012-02-15 14:47     ` [PATCH v2 08/11] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
@ 2012-02-15 21:00       ` Stefan Richter
  2012-02-16 11:21         ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-15 21:00 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 15 Chris Boot wrote:
> This file contains the implementation of the login, reconnect and logout
> management ORBs in SBP-2.
> 
> Signed-off-by: Chris Boot <bootc@bootc.net>
> Cc: Andy Grover <agrover@redhat.com>
> Cc: Clemens Ladisch <clemens@ladisch.de>
> Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
> Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
> ---
>  drivers/target/sbp/sbp_login.c |  665 ++++++++++++++++++++++++++++++++++++++++
>  drivers/target/sbp/sbp_login.h |   14 +
>  2 files changed, 679 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/target/sbp/sbp_login.c
>  create mode 100644 drivers/target/sbp/sbp_login.h
> 
> diff --git a/drivers/target/sbp/sbp_login.c b/drivers/target/sbp/sbp_login.c
> new file mode 100644
> index 0000000..74b5eaf
> --- /dev/null
> +++ b/drivers/target/sbp/sbp_login.c
> @@ -0,0 +1,665 @@
> +/*
> + * SBP2 target driver (SCSI over IEEE1394 in target mode)
> + *
> + * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software Foundation,
> + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> + */
> +
> +#define KMSG_COMPONENT "sbp_target"
> +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
> +
> +#include <linux/kref.h>
> +#include <linux/firewire.h>
> +#include <linux/firewire-constants.h>
> +#include <linux/slab.h>
> +
> +#include <target/target_core_base.h>
> +#include <target/target_core_fabric.h>
> +
> +#include "sbp_base.h"
> +#include "sbp_management_agent.h"
> +#include "sbp_login.h"
> +#include "sbp_target_agent.h"
> +
> +#define SESSION_MAINTENANCE_INTERVAL HZ
> +
> +static atomic_t login_id = ATOMIC_INIT(0);
> +
> +static void session_maintenance_work(struct work_struct *work);
> +
> +static int read_peer_guid(u64 *guid, const struct sbp_management_request *req)
> +{
> +	int ret;
> +	__be32 high, low;
> +
> +	ret = fw_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
> +			req->node_addr, req->generation, req->speed,
> +			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 3 * 4,
> +			&high, sizeof(high));
> +	if (ret != RCODE_COMPLETE)
> +		return ret;
> +
> +	ret = fw_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
> +			req->node_addr, req->generation, req->speed,
> +			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 4 * 4,
> +			&low, sizeof(low));
> +	if (ret != RCODE_COMPLETE)
> +		return ret;
> +
> +	*guid = (u64)be32_to_cpu(high) << 32 | be32_to_cpu(low);
> +
> +	return RCODE_COMPLETE;
> +}
> +
> +static struct sbp_session *sbp_session_find_by_guid(
> +	struct sbp_tpg *tpg, u64 guid)
> +{
> +	struct se_session *se_sess;
> +
> +	spin_lock(&tpg->se_tpg.session_lock);
> +	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
> +		struct sbp_session *sess = se_sess->fabric_sess_ptr;
> +		if (sess->guid == guid) {
> +			spin_unlock(&tpg->se_tpg.session_lock);
> +			return sess;
> +		}
> +	}
> +	spin_unlock(&tpg->se_tpg.session_lock);
> +
> +	return NULL;
> +}

Another form to write this would be

static struct sbp_session *sbp_session_find_by_guid(
		struct sbp_tpg *tpg, u64 guid)
{
	struct se_session *se_sess;
	struct sbp_session *s, *session = NULL;

	spin_lock(&tpg->se_tpg.session_lock);
	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
		s = se_sess->fabric_sess_ptr;
		if (s->guid == guid) {
			session = s;
			break;
		}
	}
	spin_unlock(&tpg->se_tpg.session_lock);

	return session;
}

But since your function is very small, the dual unlock-and-exit paths are
not a problem for readability.

As an aside, here is a variation of the theme, though weirdly looking if
one never came across it before:

static struct sbp_session *sbp_session_find_by_guid(
		struct sbp_tpg *tpg, u64 guid)
{
	struct se_session *s;

	spin_lock(&tpg->se_tpg.session_lock);
	list_for_each_entry(s, &tpg->se_tpg.tpg_sess_list, sess_list)
		if (s->fabric_sess_ptr->guid == guid)
			break;
	spin_unlock(&tpg->se_tpg.session_lock);

	if (&s->sess_list != &tpg->se_tpg.tpg_sess_list)
		return s->fabric_sess_ptr;
	else
		return NULL;
}

[...]
> +static struct sbp_login_descriptor *sbp_login_find_by_id(
> +	struct sbp_tpg *tpg, int login_id)
> +{
> +	struct se_session *se_sess;
> +
> +	spin_lock(&tpg->se_tpg.session_lock);
> +	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
> +		struct sbp_session *sess = se_sess->fabric_sess_ptr;
> +		struct sbp_login_descriptor *login;
> +
> +		spin_lock(&sess->login_list_lock);
> +		list_for_each_entry(login, &sess->login_list, link) {
> +			if (login->login_id == login_id) {
> +				spin_unlock(&sess->login_list_lock);
> +				spin_unlock(&tpg->se_tpg.session_lock);
> +				return login;
> +			}
> +		}
> +		spin_unlock(&sess->login_list_lock);
> +	}
> +	spin_unlock(&tpg->se_tpg.session_lock);
> +
> +	return NULL;
> +}

This function on the other hand might indeed benefit from a style
involving a single unlock-and-exit path.

[...]
> +static void sbp_session_release(struct sbp_session *sess, bool cancel_work)
> +{
> +	spin_lock(&sess->login_list_lock);
> +	if (!list_empty(&sess->login_list)) {
> +		spin_unlock(&sess->login_list_lock);
> +		return;
> +	}
> +	spin_unlock(&sess->login_list_lock);
> +
> +	transport_deregister_session_configfs(sess->se_sess);
> +	transport_deregister_session(sess->se_sess);
> +
> +	if (sess->card)
> +		fw_card_put(sess->card);
> +
> +	if (cancel_work)
> +		cancel_delayed_work_sync(&sess->maint_work);
> +
> +	kfree(sess);
> +}

What prevents that an entry is added to sess->login_list right after
you tested for it being empty?

If there is something external which prevents this, then you don't
need to take the lock just for this test.

If there is no such external measure of serialization, then the
spinlock-protected section is too small.

By the way, the use of spin_lock()/spin_unlock() is quite atypical.
This API restricts you
  - not to call a possibly sleeping function within the lock-
    protected section,
  - not to take the lock in tasklet context or IRQ context.

So this locking API is quite rarely used:  Anywhere where a mutex
/could/ be used, but none of the locked sections ever need to sleep.
This is a rather narrow use case.

Maybe you know all this but I thought I mention it anyway.

> +static void session_check_for_reset(struct sbp_session *sess)
> +{
> +	bool card_valid = false;
> +
> +	if (sess->card) {
> +		spin_lock_irq(&sess->card->lock);
> +		card_valid = (sess->card->local_node != NULL);
> +		spin_unlock_irq(&sess->card->lock);
> +
> +		if (!card_valid) {
> +			fw_card_put(sess->card);
> +			sess->card = NULL;
> +		}
> +	}
> +
> +	if (!card_valid || (sess->generation != sess->card->generation)) {
> +		pr_info("Waiting for reconnect from node: %016llx\n",
> +			sess->guid);
> +
> +		sess->node_id = -1;
> +		sess->reconnect_expires = get_jiffies_64() +
> +			((sess->reconnect_hold + 1) * HZ);
> +	}
> +}

[Note to self:  When more awake, carefully review this peeking into
fw_card internals, the generation accesses, and the card refcounting.]

> +static void session_reconnect_expired(struct sbp_session *sess)
> +{
> +	struct sbp_login_descriptor *login, *temp;
> +
> +	pr_info("Reconnect timer expired for node: %016llx\n", sess->guid);
> +
> +	spin_lock(&sess->login_list_lock);
> +	list_for_each_entry_safe(login, temp, &sess->login_list, link) {
> +		spin_unlock(&sess->login_list_lock);
> +		sbp_login_release(login, false);
> +		spin_lock(&sess->login_list_lock);
> +	}
> +	spin_unlock(&sess->login_list_lock);
> +
> +	/* sbp_login_release() calls sbp_session_release() */
> +}

This is wrong.  Either something external protects the
session_reconnect_expired() executing context from concurrent
manipulations of sess->login_list.  Then you don't need to
take the lock here in the first place.

Or there is no such external serialization measure.  Then you
must not drop the list lock in the loop body.

In the latter case, an easy fix would be to move the expired
logins to a local temporary list while holding the lock, then
release each item from the temporary list without holding the
lock.
-- 
Stefan Richter
-=====-===-- --=- -====
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h}
  2012-02-15 14:47     ` [PATCH v2 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
@ 2012-02-15 21:27       ` Stefan Richter
  2012-02-16 11:25         ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-15 21:27 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 15 Chris Boot wrote:
> --- /dev/null
> +++ b/drivers/target/sbp/sbp_target_agent.c
[...]
> +static int tgt_agent_rw_orb_pointer(struct fw_card *card,
> +	int tcode, int generation, void *data,
> +	struct sbp_target_agent *agent)
> +{
> +	struct sbp2_pointer *ptr = data;
> +	int ret;
> +
> +	switch (tcode) {
> +	case TCODE_WRITE_BLOCK_REQUEST:
> +		smp_wmb();
> +		atomic_cmpxchg(&agent->state,
> +				AGENT_STATE_RESET, AGENT_STATE_SUSPENDED);
> +		smp_wmb();
> +		if (atomic_cmpxchg(&agent->state,
> +					AGENT_STATE_SUSPENDED,
> +					AGENT_STATE_ACTIVE)
> +				!= AGENT_STATE_SUSPENDED)
> +			return RCODE_CONFLICT_ERROR;
> +		smp_wmb();

Why the double state change?

And as asked at the patch, which writes are the barriers meant to order,
and how does the corresponding read side look like?  Or are these barriers
not actually needed after all?

[...]
> +void sbp_target_agent_unregister(struct sbp_target_agent *agent)
> +{
> +	if (atomic_read(&agent->state) == AGENT_STATE_ACTIVE)
> +		flush_work_sync(&agent->work);
> +
> +	fw_core_remove_address_handler(&agent->handler);
> +	kfree(agent);
> +}

So, asking once more without having read the code in full yet:  Are you
sure that agent->state is not going to change anymore after you tested it
here?
-- 
Stefan Richter
-=====-===-- --=- -====
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request
  2012-02-15 19:10         ` Chris Boot
@ 2012-02-15 22:01           ` Stefan Richter
  2012-02-16  9:12             ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-15 22:01 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 15 Chris Boot wrote:
> On 15/02/2012 19:09, Stefan Richter wrote:
> > On Feb 15 Chris Boot wrote:
> >> --- a/drivers/firewire/core-transaction.c
> >> +++ b/drivers/firewire/core-transaction.c
> >> @@ -820,6 +820,22 @@ void fw_send_response(struct fw_card *card,
> >>   }
> >>   EXPORT_SYMBOL(fw_send_response);
> >>
> >> +/**
> >> + * fw_get_request_speed() - Discover bus speed used for this request
> >> + * @request:	The struct fw_request from which to obtain the speed.
> >> + *
> >> + * In certain circumstances it's important to be able to obtain the speed at
> >> + * which a request was made to an address handler, for example when
> >> + * implementing an SBP-2 or SBP-3 target. This function inspects the response
> >> + * object to obtain the speed, which is copied from the request packet in
> >> + * allocate_request().
> >> + */
> >> +int fw_get_request_speed(struct fw_request *request)
> >> +{
> >> +	return request->response.speed;
> >> +}
> >> +EXPORT_SYMBOL(fw_get_request_speed);
> >
> > Uh oh, what have I done by asking for a comment? :-)
> >
> > Can you tell what's wrong with this API documentation?
> 
> Better to have too much than too little? :-)
> 
> Linux 3.4, now with added Enterprise.
> 
> Shall I cut it down a bit?

a)  The implementation of the function should not be explained here;
after all it is meant to be opaque to API users.  Besides, if somebody
changes the implementation he will for sure forget to change the comment.

b)  It is fairly self-evident at which occasions an API user would want
to use this function.  (Everytime when he needs to know that speed.)

c)  The function call argument does not really need to be explained
either as soon as the purpose of the function has been made known.

So in my first response where I already acked your patch I should have
simply asked for

/**
 * fw_get_request_speed() - returns speed at which the @request was received
 */

to be added to your patch.  :-)

Patch review could be so easy for everyone involved if the reviewer knew
how to express himself...
-- 
Stefan Richter
-=====-===-- --=- -====
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request
  2012-02-15 22:01           ` Stefan Richter
@ 2012-02-16  9:12             ` Chris Boot
  0 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-16  9:12 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 15/02/2012 22:01, Stefan Richter wrote:
> On Feb 15 Chris Boot wrote:
>> On 15/02/2012 19:09, Stefan Richter wrote:
>>> On Feb 15 Chris Boot wrote:
>>>> --- a/drivers/firewire/core-transaction.c
>>>> +++ b/drivers/firewire/core-transaction.c
>>>> @@ -820,6 +820,22 @@ void fw_send_response(struct fw_card *card,
>>>>    }
>>>>    EXPORT_SYMBOL(fw_send_response);
>>>>
>>>> +/**
>>>> + * fw_get_request_speed() - Discover bus speed used for this request
>>>> + * @request:	The struct fw_request from which to obtain the speed.
>>>> + *
>>>> + * In certain circumstances it's important to be able to obtain the speed at
>>>> + * which a request was made to an address handler, for example when
>>>> + * implementing an SBP-2 or SBP-3 target. This function inspects the response
>>>> + * object to obtain the speed, which is copied from the request packet in
>>>> + * allocate_request().
>>>> + */
>>>> +int fw_get_request_speed(struct fw_request *request)
>>>> +{
>>>> +	return request->response.speed;
>>>> +}
>>>> +EXPORT_SYMBOL(fw_get_request_speed);
>>>
>>> Uh oh, what have I done by asking for a comment? :-)
>>>
>>> Can you tell what's wrong with this API documentation?
>>
>> Better to have too much than too little? :-)
>>
>> Linux 3.4, now with added Enterprise.
>>
>> Shall I cut it down a bit?
>
> a)  The implementation of the function should not be explained here;
> after all it is meant to be opaque to API users.  Besides, if somebody
> changes the implementation he will for sure forget to change the comment.
>
> b)  It is fairly self-evident at which occasions an API user would want
> to use this function.  (Everytime when he needs to know that speed.)
>
> c)  The function call argument does not really need to be explained
> either as soon as the purpose of the function has been made known.
>
> So in my first response where I already acked your patch I should have
> simply asked for
>
> /**
>   * fw_get_request_speed() - returns speed at which the @request was received
>   */
>
> to be added to your patch.  :-)
>
> Patch review could be so easy for everyone involved if the reviewer knew
> how to express himself...

I guess it comes from me just trying too hard... Will fix for v3.

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 02/11] firewire: Move fw_card kref functions into linux/firewire.h
  2012-02-15 19:10       ` Stefan Richter
@ 2012-02-16  9:18         ` Chris Boot
  0 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-16  9:18 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 15/02/2012 19:10, Stefan Richter wrote:
> On Feb 15 Chris Boot wrote:
>> When writing a firewire driver that doesn't deal with struct fw_device
>> objects (e.g. it only publishes FireWire units and doesn't subscribe to
>> them), you likely need to keep referenced to struct fw_card objects so
>> that you can send messages to other nodes. This patch moves
>> fw_card_put(), fw_card_get() and fw_card_release() into the public
>> include/linux/firewire.h header instead of drivers/firewire/core.h, and
>> adds EXPORT_SYMBOL_GPL(fw_card_release).
>>
>> The firewire-sbp-target module requires these so it can keep a reference
>> to the fw_card object in order that it can fetch ORBs to execute and
>> read/write related data and status information.
>>
>> Signed-off-by: Chris Boot<bootc@bootc.net>
>> Cc: Clemens Ladisch<clemens@ladisch.de>
>
> Acked-by: Stefan Richter<stefanr@s5r6.in-berlin.de>

Thanks!

[snip]

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 04/11] firewire-sbp-target: Add sbp_base.h header
  2012-02-15 19:15       ` Stefan Richter
@ 2012-02-16  9:55         ` Chris Boot
  0 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-16  9:55 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 15/02/2012 19:15, Stefan Richter wrote:
> On Feb 15 Chris Boot wrote:
>> --- /dev/null
>> +++ b/drivers/target/sbp/sbp_base.h
>> @@ -0,0 +1,204 @@
> [...]
>> +struct sbp2_pointer {
>> +	__be32 high;
>> +	__be32 low;
>> +};
> [...]
>> +struct sbp_tport {
>> +	/* Target Unit Identifier (EUI-64) */
>> +	u64 guid;
>> +	/* Target port name */
>> +	char tport_name[SBP_NAMELEN];
>> +	/* Returned by sbp_make_tport() */
>> +	struct se_wwn tport_wwn;
>> +
>> +	struct sbp_tpg *tpg;
>> +
>> +	/* FireWire unit directory */
>> +	struct fw_descriptor unit_directory;
>> +
>> +	/* SBP Management Agent */
>> +	struct sbp_management_agent *mgt_agt;
>> +
>> +	/* Parameters */
>> +	int enable;
>> +	s32 directory_id;
>> +	int mgt_orb_timeout;
>> +	int max_reconnect_timeout;
>> +	int max_logins_per_lun;
>> +};
>> +
>> +extern struct target_fabric_configfs *sbp_fabric_configfs;
>> +extern const struct fw_address_region sbp_register_region;
>> +extern struct workqueue_struct *sbp_workqueue;
> [...]
>
> Generally, any source file (.c or .h) is meant to be self-contained WRT
> type definitions etc., meaning that they should have all required
> #include's in themselves rather than rely on indirect includes.
>
> So here you should include the headers which define __be32, u64, struct
> se_wwn, struct workqueue and so on.

Thanks. I'll work on fixing this.

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 05/11] firewire-sbp-target: Add sbp_configfs.c
  2012-02-15 19:21       ` Stefan Richter
@ 2012-02-16  9:57         ` Chris Boot
  2012-02-16 13:48           ` Stefan Richter
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-16  9:57 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 15/02/2012 19:21, Stefan Richter wrote:
> On Feb 15 Chris Boot wrote:
>> --- /dev/null
>> +++ b/drivers/target/sbp/sbp_configfs.c
>> @@ -0,0 +1,751 @@
>> +/*
>> + * SBP2 target driver (SCSI over IEEE1394 in target mode)
>> + *
>> + * Copyright (C) 2011  Chris Boot<bootc@bootc.net>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software Foundation,
>> + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
>> + */
>> +
>> +#define KMSG_COMPONENT "sbp_target"
>> +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
>> +
>> +#include<linux/module.h>
>> +#include<linux/moduleparam.h>
>> +#include<linux/version.h>
>> +#include<linux/init.h>
>> +#include<linux/slab.h>
>> +#include<linux/kthread.h>
>> +#include<linux/types.h>
>> +#include<linux/string.h>
>> +#include<linux/configfs.h>
>> +#include<linux/ctype.h>
>> +#include<linux/firewire.h>
>> +
>> +#include<asm/unaligned.h>
>> +
>> +#include<target/target_core_base.h>
>> +#include<target/target_core_backend.h>
>> +#include<target/target_core_fabric.h>
>> +#include<target/target_core_configfs.h>
>> +#include<target/target_core_fabric_configfs.h>
>> +#include<target/configfs_macros.h>
>> +
>> +#include "sbp_base.h"
>> +#include "sbp_fabric.h"
>> +#include "sbp_management_agent.h"
>> +
>> +/* Local pointer to allocated TCM configfs fabric module */
>> +struct target_fabric_configfs *sbp_fabric_configfs;
>> +
>> +struct workqueue_struct *sbp_workqueue;
>
> #include<linux/workqueue.h>  goes before this.

Yep.

> [...]
>> +	sbp_workqueue = alloc_workqueue("firewire-sbp-target", WQ_UNBOUND, 0);
>> +	if (!sbp_workqueue) {
>> +		target_fabric_configfs_deregister(fabric);
>> +		return -ENOMEM;
>> +	}
>
> What are your specific requirements that you cannot use one of the
> system-wide workqueues?

Nothing specific, I just thought it was sensible to use your own 
workqueue if you put enough work into it. I'll switch to the system queues.

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 07/11] firewire-sbp-target: add sbp_management_agent.{c,h}
  2012-02-15 19:48       ` Stefan Richter
@ 2012-02-16 10:28         ` Chris Boot
  2012-02-16 14:12           ` Stefan Richter
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-16 10:28 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 15/02/2012 19:48, Stefan Richter wrote:
> On Feb 15 Chris Boot wrote:
>> --- /dev/null
>> +++ b/drivers/target/sbp/sbp_management_agent.c
> [...]
>> +static void sbp_mgt_agent_rw(struct fw_card *card,
>> +	struct fw_request *request, int tcode, int destination, int source,
>> +	int generation, unsigned long long offset, void *data, size_t length,
>> +	void *callback_data)
>> +{
>> +	struct sbp_management_agent *agent = callback_data;
>> +	struct sbp2_pointer *ptr = data;
>> +
>> +	if (!agent->tport->enable) {
>> +		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
>> +		return;
>> +	}
>> +
>> +	if ((offset != agent->handler.offset) || (length != 8)) {
>> +		fw_send_response(card, request, RCODE_ADDRESS_ERROR);
>> +		return;
>> +	}
>> +
>> +	if (tcode == TCODE_WRITE_BLOCK_REQUEST) {
>> +		struct sbp_management_request *req;
>> +		int ret;
>> +
>> +		smp_wmb();
>> +		if (atomic_cmpxchg(&agent->state,
>> +					MANAGEMENT_AGENT_STATE_IDLE,
>> +					MANAGEMENT_AGENT_STATE_BUSY) !=
>> +				MANAGEMENT_AGENT_STATE_IDLE) {
>> +			pr_notice("ignoring management request while busy\n");
>> +
>> +			fw_send_response(card, request, RCODE_CONFLICT_ERROR);
>> +			return;
>> +		}
>
> There is a rule of thumb which says:  If you add a memory barrier anywhere
> in your code, also add a comment saying which accesses this barrier is
> meant to bring into order.
>
> So after the write barrier is apparently the agent->state access.  What
> access is before the barrier?
>
> And how does the read side look like?
>
> These questions are mostly rhetoric.  It is quite likely that this code is
> better off with a plain and simple mutex serialization.

Well as I mentioned in my previous messages atomics and locking are 
pretty new ideas to me. Having only really done threading in PERL 
before, the world of doing it in the kernel is rather different! :-) The 
memory barriers are there after I looked in Documentation/atomic_ops.txt 
and clearly misunderstood the entire thing.

Reading about mutexes though I see I can't use them from interrupt 
context, but doesn't the FireWire address handler execute in interrupt 
context? I have to check the state of the management agent in the 
address handler to properly reject requests from the initiator when the 
agent is busy. I guess a spinlock is called for in this situation, 
possibly using spin_trylock() in the address handler to avoid blocking?

> [...]
>> +void sbp_management_agent_unregister(struct sbp_management_agent *agent)
>> +{
>> +	if (atomic_read(&agent->state) != MANAGEMENT_AGENT_STATE_IDLE)
>> +		flush_work_sync(&agent->work);
>> +
>> +	fw_core_remove_address_handler(&agent->handler);
>> +	kfree(agent);
>> +}
>
> I still have yet to test-apply all your patches, look at the sum of the
> code and understand what the execution contexts and critical sections
> are.  So I really should not yet ask the next, uninformed question.
>
> Looking at this function, I wonder:  Can the agent->state change after you
> read it, and what would happen then?

The agent state could change between the read and before the address 
handler is unregistered, this would require an initiator to keep sending 
management requests long after the FW unit descriptor is removed though.

I guess to solve this in a bulletproof manner I need a kref in struct 
sbp_management_agent and a spinlock(?), and a new state to say the agent 
is going away. That way if I happen to receive requests while the agent 
is being removed it can reply with address errors before the address 
handler is fully removed. I'd also need something similar in the target 
agent.

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 08/11] firewire-sbp-target: Add sbp_login.{c,h}
  2012-02-15 21:00       ` Stefan Richter
@ 2012-02-16 11:21         ` Chris Boot
  2012-03-03 17:37           ` Stefan Richter
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-16 11:21 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 15/02/2012 21:00, Stefan Richter wrote:
> On Feb 15 Chris Boot wrote:
>> This file contains the implementation of the login, reconnect and logout
>> management ORBs in SBP-2.
>>
>> Signed-off-by: Chris Boot<bootc@bootc.net>
>> Cc: Andy Grover<agrover@redhat.com>
>> Cc: Clemens Ladisch<clemens@ladisch.de>
>> Cc: Nicholas A. Bellinger<nab@linux-iscsi.org>
>> Cc: Stefan Richter<stefanr@s5r6.in-berlin.de>
>> ---
>>   drivers/target/sbp/sbp_login.c |  665 ++++++++++++++++++++++++++++++++++++++++
>>   drivers/target/sbp/sbp_login.h |   14 +
>>   2 files changed, 679 insertions(+), 0 deletions(-)
>>   create mode 100644 drivers/target/sbp/sbp_login.c
>>   create mode 100644 drivers/target/sbp/sbp_login.h
>>
>> diff --git a/drivers/target/sbp/sbp_login.c b/drivers/target/sbp/sbp_login.c
>> new file mode 100644
>> index 0000000..74b5eaf
>> --- /dev/null
>> +++ b/drivers/target/sbp/sbp_login.c
>> @@ -0,0 +1,665 @@
>> +/*
>> + * SBP2 target driver (SCSI over IEEE1394 in target mode)
>> + *
>> + * Copyright (C) 2011  Chris Boot<bootc@bootc.net>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software Foundation,
>> + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
>> + */
>> +
>> +#define KMSG_COMPONENT "sbp_target"
>> +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
>> +
>> +#include<linux/kref.h>
>> +#include<linux/firewire.h>
>> +#include<linux/firewire-constants.h>
>> +#include<linux/slab.h>
>> +
>> +#include<target/target_core_base.h>
>> +#include<target/target_core_fabric.h>
>> +
>> +#include "sbp_base.h"
>> +#include "sbp_management_agent.h"
>> +#include "sbp_login.h"
>> +#include "sbp_target_agent.h"
>> +
>> +#define SESSION_MAINTENANCE_INTERVAL HZ
>> +
>> +static atomic_t login_id = ATOMIC_INIT(0);
>> +
>> +static void session_maintenance_work(struct work_struct *work);
>> +
>> +static int read_peer_guid(u64 *guid, const struct sbp_management_request *req)
>> +{
>> +	int ret;
>> +	__be32 high, low;
>> +
>> +	ret = fw_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
>> +			req->node_addr, req->generation, req->speed,
>> +			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 3 * 4,
>> +			&high, sizeof(high));
>> +	if (ret != RCODE_COMPLETE)
>> +		return ret;
>> +
>> +	ret = fw_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
>> +			req->node_addr, req->generation, req->speed,
>> +			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 4 * 4,
>> +			&low, sizeof(low));
>> +	if (ret != RCODE_COMPLETE)
>> +		return ret;
>> +
>> +	*guid = (u64)be32_to_cpu(high)<<  32 | be32_to_cpu(low);
>> +
>> +	return RCODE_COMPLETE;
>> +}
>> +
>> +static struct sbp_session *sbp_session_find_by_guid(
>> +	struct sbp_tpg *tpg, u64 guid)
>> +{
>> +	struct se_session *se_sess;
>> +
>> +	spin_lock(&tpg->se_tpg.session_lock);
>> +	list_for_each_entry(se_sess,&tpg->se_tpg.tpg_sess_list, sess_list) {
>> +		struct sbp_session *sess = se_sess->fabric_sess_ptr;
>> +		if (sess->guid == guid) {
>> +			spin_unlock(&tpg->se_tpg.session_lock);
>> +			return sess;
>> +		}
>> +	}
>> +	spin_unlock(&tpg->se_tpg.session_lock);
>> +
>> +	return NULL;
>> +}
>
> Another form to write this would be
>
> static struct sbp_session *sbp_session_find_by_guid(
> 		struct sbp_tpg *tpg, u64 guid)
> {
> 	struct se_session *se_sess;
> 	struct sbp_session *s, *session = NULL;
>
> 	spin_lock(&tpg->se_tpg.session_lock);
> 	list_for_each_entry(se_sess,&tpg->se_tpg.tpg_sess_list, sess_list) {
> 		s = se_sess->fabric_sess_ptr;
> 		if (s->guid == guid) {
> 			session = s;
> 			break;
> 		}
> 	}
> 	spin_unlock(&tpg->se_tpg.session_lock);
>
> 	return session;
> }
>
> But since your function is very small, the dual unlock-and-exit paths are
> not a problem for readability.
>
> As an aside, here is a variation of the theme, though weirdly looking if
> one never came across it before:
>
> static struct sbp_session *sbp_session_find_by_guid(
> 		struct sbp_tpg *tpg, u64 guid)
> {
> 	struct se_session *s;
>
> 	spin_lock(&tpg->se_tpg.session_lock);
> 	list_for_each_entry(s,&tpg->se_tpg.tpg_sess_list, sess_list)
> 		if (s->fabric_sess_ptr->guid == guid)
> 			break;
> 	spin_unlock(&tpg->se_tpg.session_lock);
>
> 	if (&s->sess_list !=&tpg->se_tpg.tpg_sess_list)
> 		return s->fabric_sess_ptr;
> 	else
> 		return NULL;
> }
>
> [...]
>> +static struct sbp_login_descriptor *sbp_login_find_by_id(
>> +	struct sbp_tpg *tpg, int login_id)
>> +{
>> +	struct se_session *se_sess;
>> +
>> +	spin_lock(&tpg->se_tpg.session_lock);
>> +	list_for_each_entry(se_sess,&tpg->se_tpg.tpg_sess_list, sess_list) {
>> +		struct sbp_session *sess = se_sess->fabric_sess_ptr;
>> +		struct sbp_login_descriptor *login;
>> +
>> +		spin_lock(&sess->login_list_lock);
>> +		list_for_each_entry(login,&sess->login_list, link) {
>> +			if (login->login_id == login_id) {
>> +				spin_unlock(&sess->login_list_lock);
>> +				spin_unlock(&tpg->se_tpg.session_lock);
>> +				return login;
>> +			}
>> +		}
>> +		spin_unlock(&sess->login_list_lock);
>> +	}
>> +	spin_unlock(&tpg->se_tpg.session_lock);
>> +
>> +	return NULL;
>> +}
>
> This function on the other hand might indeed benefit from a style
> involving a single unlock-and-exit path.
>
> [...]
>> +static void sbp_session_release(struct sbp_session *sess, bool cancel_work)
>> +{
>> +	spin_lock(&sess->login_list_lock);
>> +	if (!list_empty(&sess->login_list)) {
>> +		spin_unlock(&sess->login_list_lock);
>> +		return;
>> +	}
>> +	spin_unlock(&sess->login_list_lock);
>> +
>> +	transport_deregister_session_configfs(sess->se_sess);
>> +	transport_deregister_session(sess->se_sess);
>> +
>> +	if (sess->card)
>> +		fw_card_put(sess->card);
>> +
>> +	if (cancel_work)
>> +		cancel_delayed_work_sync(&sess->maint_work);
>> +
>> +	kfree(sess);
>> +}
>
> What prevents that an entry is added to sess->login_list right after
> you tested for it being empty?
>
> If there is something external which prevents this, then you don't
> need to take the lock just for this test.
>
> If there is no such external measure of serialization, then the
> spinlock-protected section is too small.

Only two things can manipulate the login list: the management agent, 
which is serialised (e.g. only one management request per target port 
can be ongoing at any point in time), and the session maintenance work 
item. So you're right, the lock-protected section is too small.

> By the way, the use of spin_lock()/spin_unlock() is quite atypical.
> This API restricts you
>    - not to call a possibly sleeping function within the lock-
>      protected section,
>    - not to take the lock in tasklet context or IRQ context.
>
> So this locking API is quite rarely used:  Anywhere where a mutex
> /could/ be used, but none of the locked sections ever need to sleep.
> This is a rather narrow use case.
>
> Maybe you know all this but I thought I mention it anyway.

The session is only really inspected/maniuplated in the context of work 
items, so it's possible I could use mutexes - although in the target 
agent address handler I do check the node_id against the one in the 
session (and I should really check the generation too). Would memory 
barriers be enough for those or would locking be required?

>> +static void session_check_for_reset(struct sbp_session *sess)
>> +{
>> +	bool card_valid = false;
>> +
>> +	if (sess->card) {
>> +		spin_lock_irq(&sess->card->lock);
>> +		card_valid = (sess->card->local_node != NULL);
>> +		spin_unlock_irq(&sess->card->lock);
>> +
>> +		if (!card_valid) {
>> +			fw_card_put(sess->card);
>> +			sess->card = NULL;
>> +		}
>> +	}
>> +
>> +	if (!card_valid || (sess->generation != sess->card->generation)) {
>> +		pr_info("Waiting for reconnect from node: %016llx\n",
>> +			sess->guid);
>> +
>> +		sess->node_id = -1;
>> +		sess->reconnect_expires = get_jiffies_64() +
>> +			((sess->reconnect_hold + 1) * HZ);
>> +	}
>> +}
>
> [Note to self:  When more awake, carefully review this peeking into
> fw_card internals, the generation accesses, and the card refcounting.]
>
>> +static void session_reconnect_expired(struct sbp_session *sess)
>> +{
>> +	struct sbp_login_descriptor *login, *temp;
>> +
>> +	pr_info("Reconnect timer expired for node: %016llx\n", sess->guid);
>> +
>> +	spin_lock(&sess->login_list_lock);
>> +	list_for_each_entry_safe(login, temp,&sess->login_list, link) {
>> +		spin_unlock(&sess->login_list_lock);
>> +		sbp_login_release(login, false);
>> +		spin_lock(&sess->login_list_lock);
>> +	}
>> +	spin_unlock(&sess->login_list_lock);
>> +
>> +	/* sbp_login_release() calls sbp_session_release() */
>> +}
>
> This is wrong.  Either something external protects the
> session_reconnect_expired() executing context from concurrent
> manipulations of sess->login_list.  Then you don't need to
> take the lock here in the first place.
>
> Or there is no such external serialization measure.  Then you
> must not drop the list lock in the loop body.
>
> In the latter case, an easy fix would be to move the expired
> logins to a local temporary list while holding the lock, then
> release each item from the temporary list without holding the
> lock.

Yes deep down I knew it was wrong, and it'll be the latter case of 
needing more locking than it has. I guess I need to protect access to 
the entire session really. Possibly even rwlocks due to only the 
management processes ever changing anything, but lots of reads during 
command handling.

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h}
  2012-02-15 21:27       ` Stefan Richter
@ 2012-02-16 11:25         ` Chris Boot
  2012-02-18 14:59           ` Stefan Richter
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-02-16 11:25 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 15/02/2012 21:27, Stefan Richter wrote:
> On Feb 15 Chris Boot wrote:
>> --- /dev/null
>> +++ b/drivers/target/sbp/sbp_target_agent.c
> [...]
>> +static int tgt_agent_rw_orb_pointer(struct fw_card *card,
>> +	int tcode, int generation, void *data,
>> +	struct sbp_target_agent *agent)
>> +{
>> +	struct sbp2_pointer *ptr = data;
>> +	int ret;
>> +
>> +	switch (tcode) {
>> +	case TCODE_WRITE_BLOCK_REQUEST:
>> +		smp_wmb();
>> +		atomic_cmpxchg(&agent->state,
>> +				AGENT_STATE_RESET, AGENT_STATE_SUSPENDED);
>> +		smp_wmb();
>> +		if (atomic_cmpxchg(&agent->state,
>> +					AGENT_STATE_SUSPENDED,
>> +					AGENT_STATE_ACTIVE)
>> +				!= AGENT_STATE_SUSPENDED)
>> +			return RCODE_CONFLICT_ERROR;
>> +		smp_wmb();
>
> Why the double state change?

Because the SBP spec differentiates between the RESET state, which 
happens after the agent initialises or is sent an explicit reset 
request, and when it's suspended between requests...

> And as asked at the patch, which writes are the barriers meant to order,
> and how does the corresponding read side look like?  Or are these barriers
> not actually needed after all?

...of course this is another time when my use of atomics and memory 
barriers is entirely wrong. I should most likely be using locking here.

> [...]
>> +void sbp_target_agent_unregister(struct sbp_target_agent *agent)
>> +{
>> +	if (atomic_read(&agent->state) == AGENT_STATE_ACTIVE)
>> +		flush_work_sync(&agent->work);
>> +
>> +	fw_core_remove_address_handler(&agent->handler);
>> +	kfree(agent);
>> +}
>
> So, asking once more without having read the code in full yet:  Are you
> sure that agent->state is not going to change anymore after you tested it
> here?

Nope. At least in this case I can unregister the address handler before 
I check if I need to flush the work item.

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 05/11] firewire-sbp-target: Add sbp_configfs.c
  2012-02-16  9:57         ` Chris Boot
@ 2012-02-16 13:48           ` Stefan Richter
  0 siblings, 0 replies; 104+ messages in thread
From: Stefan Richter @ 2012-02-16 13:48 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 16 Chris Boot wrote:
> On 15/02/2012 19:21, Stefan Richter wrote:
> > On Feb 15 Chris Boot wrote:
> >> +	sbp_workqueue = alloc_workqueue("firewire-sbp-target", WQ_UNBOUND, 0);
> >> +	if (!sbp_workqueue) {
> >> +		target_fabric_configfs_deregister(fabric);
> >> +		return -ENOMEM;
> >> +	}
> >
> > What are your specific requirements that you cannot use one of the
> > system-wide workqueues?
> 
> Nothing specific, I just thought it was sensible to use your own 
> workqueue if you put enough work into it. I'll switch to the system queues.

OK, good.  These days you can throw almost any kind of work into the
system workqueues without negative effect on their other users, given you
keep the queue properties in mind which are listed in linux/workqueue.h.
There is also some info in Documentation/workqueue.txt.  If that still
leaves any doubt, you could Cc: Tejun Hejo on questions on the workqueue
infrastructure and he will likely give a helpful hint.

BTW, the drivers/firewire/ subsystem uses an own workqueue instead of the
system-wide ones because of combined requirements of non-reentrance and
memory-reclaim safety, explained in the changelog of commit 6ea9e7bbfc38.
-- 
Stefan Richter
-=====-===-- --=- =----
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 07/11] firewire-sbp-target: add sbp_management_agent.{c,h}
  2012-02-16 10:28         ` Chris Boot
@ 2012-02-16 14:12           ` Stefan Richter
  0 siblings, 0 replies; 104+ messages in thread
From: Stefan Richter @ 2012-02-16 14:12 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 16 Chris Boot wrote:
> Reading about mutexes though I see I can't use them from interrupt 
> context, but doesn't the FireWire address handler execute in interrupt 
> context? I have to check the state of the management agent in the 
> address handler to properly reject requests from the initiator when the 
> agent is busy. I guess a spinlock is called for in this situation, 
> possibly using spin_trylock() in the address handler to avoid blocking?

Yes; the request-receive callback (address handler) is executed in tasklet
context.  All drivers which use this currently use the spin_lock_irqsave
API variant.  I am considering to change the entire subsystem to use
spin_lock_bh only.  IMO you could use spin_lock_bh in your target code, or
spin_lock for locks which are _only_ ever taken in tasklet context.

Plain spin_lock cannot be used, neither in the address handler nor in any
process context which grabs the same lock as the address handler.

The use cases for trylock variants of the locking APIs are somewhat
special.  If in doubt, ignore that trylock APIs exist.

In strict terms, spin_trylock avoids busy-waiting for a contended lock.
mutex_trylock avoids blocking in the sense of sleeping wait for a contended
mutex.  However, to expand on the obvious, the trylock variants are only
useful if whatever action which was meant to be performed can be aborted
without problem, e.g. if upper layers would be able to retry at some later
occasion.

(I am still interested in closer looks at the execution contexts and object
lifetime rules in your code, but spare time vs. mental capacity seem
regularly at odds...)
-- 
Stefan Richter
-=====-===-- --=- =----
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h}
  2012-02-16 11:25         ` Chris Boot
@ 2012-02-18 14:59           ` Stefan Richter
  2012-02-18 15:05             ` Chris Boot
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-02-18 14:59 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 16 Chris Boot wrote:
> On 15/02/2012 21:27, Stefan Richter wrote:
> > On Feb 15 Chris Boot wrote:
> >> --- /dev/null
> >> +++ b/drivers/target/sbp/sbp_target_agent.c
> > [...]
> >> +static int tgt_agent_rw_orb_pointer(struct fw_card *card,
> >> +	int tcode, int generation, void *data,
> >> +	struct sbp_target_agent *agent)
> >> +{
> >> +	struct sbp2_pointer *ptr = data;
> >> +	int ret;
> >> +
> >> +	switch (tcode) {
> >> +	case TCODE_WRITE_BLOCK_REQUEST:
> >> +		smp_wmb();
> >> +		atomic_cmpxchg(&agent->state,
> >> +				AGENT_STATE_RESET, AGENT_STATE_SUSPENDED);
> >> +		smp_wmb();
> >> +		if (atomic_cmpxchg(&agent->state,
> >> +					AGENT_STATE_SUSPENDED,
> >> +					AGENT_STATE_ACTIVE)
> >> +				!= AGENT_STATE_SUSPENDED)
> >> +			return RCODE_CONFLICT_ERROR;
> >> +		smp_wmb();
> >
> > Why the double state change?
> 
> Because the SBP spec differentiates between the RESET state, which 
> happens after the agent initialises or is sent an explicit reset 
> request, and when it's suspended between requests...

OK, right, there are the state transitions Reset-->Active and
Suspended-->Active.  Though you implement the former as a swift
Reset-->Suspended-->Active.  Which does indeed work, provided that there
is no other concurrent context which could transition from Suspended to
Anything-but-Active.

> > And as asked at the patch, which writes are the barriers meant to order,
> > and how does the corresponding read side look like?  Or are these barriers
> > not actually needed after all?
> 
> ...of course this is another time when my use of atomics and memory 
> barriers is entirely wrong. I should most likely be using locking here.
> 
> > [...]
> >> +void sbp_target_agent_unregister(struct sbp_target_agent *agent)
> >> +{
> >> +	if (atomic_read(&agent->state) == AGENT_STATE_ACTIVE)
> >> +		flush_work_sync(&agent->work);
> >> +
> >> +	fw_core_remove_address_handler(&agent->handler);
> >> +	kfree(agent);
> >> +}
> >
> > So, asking once more without having read the code in full yet:  Are you
> > sure that agent->state is not going to change anymore after you tested it
> > here?
> 
> Nope. At least in this case I can unregister the address handler before 
> I check if I need to flush the work item.

Yep, first unregister the handler, then wait for the work to finish, then
free the data.

And as discussed off-list today, firewire-core should be improved to
guarantee you that the handler isn't still running anywhere when
fw_core_remove_address_handler() returns.
-- 
Stefan Richter
-=====-===-- --=- =--=-
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h}
  2012-02-18 14:59           ` Stefan Richter
@ 2012-02-18 15:05             ` Chris Boot
  0 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-02-18 15:05 UTC (permalink / raw)
  To: Stefan Richter
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On 18 Feb 2012, at 14:59, Stefan Richter <stefanr@s5r6.in-berlin.de> wrote:

> On Feb 16 Chris Boot wrote:
>> On 15/02/2012 21:27, Stefan Richter wrote:
>>> On Feb 15 Chris Boot wrote:
>>>> --- /dev/null
>>>> +++ b/drivers/target/sbp/sbp_target_agent.c
>>> [...]
>>>> +static int tgt_agent_rw_orb_pointer(struct fw_card *card,
>>>> +	int tcode, int generation, void *data,
>>>> +	struct sbp_target_agent *agent)
>>>> +{
>>>> +	struct sbp2_pointer *ptr = data;
>>>> +	int ret;
>>>> +
>>>> +	switch (tcode) {
>>>> +	case TCODE_WRITE_BLOCK_REQUEST:
>>>> +		smp_wmb();
>>>> +		atomic_cmpxchg(&agent->state,
>>>> +				AGENT_STATE_RESET, AGENT_STATE_SUSPENDED);
>>>> +		smp_wmb();
>>>> +		if (atomic_cmpxchg(&agent->state,
>>>> +					AGENT_STATE_SUSPENDED,
>>>> +					AGENT_STATE_ACTIVE)
>>>> +				!= AGENT_STATE_SUSPENDED)
>>>> +			return RCODE_CONFLICT_ERROR;
>>>> +		smp_wmb();
>>> 
>>> Why the double state change?
>> 
>> Because the SBP spec differentiates between the RESET state, which 
>> happens after the agent initialises or is sent an explicit reset 
>> request, and when it's suspended between requests...
> 
> OK, right, there are the state transitions Reset-->Active and
> Suspended-->Active.  Though you implement the former as a swift
> Reset-->Suspended-->Active.  Which does indeed work, provided that there
> is no other concurrent context which could transition from Suspended to
> Anything-but-Active.

I'll rewrite this bit to use a lock to protect the state struct member so it isn't so strange. That would also avoid the unusual double state change.

>>> And as asked at the patch, which writes are the barriers meant to order,
>>> and how does the corresponding read side look like?  Or are these barriers
>>> not actually needed after all?
>> 
>> ...of course this is another time when my use of atomics and memory 
>> barriers is entirely wrong. I should most likely be using locking here.
>> 
>>> [...]
>>>> +void sbp_target_agent_unregister(struct sbp_target_agent *agent)
>>>> +{
>>>> +	if (atomic_read(&agent->state) == AGENT_STATE_ACTIVE)
>>>> +		flush_work_sync(&agent->work);
>>>> +
>>>> +	fw_core_remove_address_handler(&agent->handler);
>>>> +	kfree(agent);
>>>> +}
>>> 
>>> So, asking once more without having read the code in full yet:  Are you
>>> sure that agent->state is not going to change anymore after you tested it
>>> here?
>> 
>> Nope. At least in this case I can unregister the address handler before 
>> I check if I need to flush the work item.
> 
> Yep, first unregister the handler, then wait for the work to finish, then
> free the data.
> 
> And as discussed off-list today, firewire-core should be improved to
> guarantee you that the handler isn't still running anywhere when
> fw_core_remove_address_handler() returns.

Great, thanks for clearing that up.

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 08/11] firewire-sbp-target: Add sbp_login.{c,h}
  2012-02-16 11:21         ` Chris Boot
@ 2012-03-03 17:37           ` Stefan Richter
  2012-03-15 17:48             ` Paul E. McKenney
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-03-03 17:37 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Feb 16 Chris Boot wrote:
> The session is only really inspected/maniuplated in the context of work 
> items, so it's possible I could use mutexes - although in the target 
> agent address handler I do check the node_id against the one in the 
> session (and I should really check the generation too). Would memory 
> barriers be enough for those or would locking be required?

A node ID itself is an incomplete datum.  Only a card--generation--node_ID
tuple is complete.

If generation and node ID are written and read concurrently, you have a
couple of choices to do this consistently:  You could atomically write and
read an integer which contains 8 bits of generation and 16 bits of node
ID.  Or you could serialize write and read accesses by a lock or mutex.
Or you could force the write side to write node ID before generation
(with an smp_wmb between to enforce order), and the read side to read
generation before node ID (with an smp_rmb to enforce order).

The latter method leaves a brief window in which a reader could pick up a
current node ID together with an outdated generation.  This is harmless
because the OHCI hardware and respective precautions in firewire-ohci
prevents transaction subactions with outdated generation to go out to the
wire.

It is generally recommended to implement such accesses in drivers with
locks (spinlocks or mutexes).  Among the various means to deal with
concurrency issues, locks seem to be best understood by us simple folk who
hack on drivers. :-)

[...]
> I guess I need to protect access to 
> the entire session really. Possibly even rwlocks due to only the 
> management processes ever changing anything, but lots of reads during 
> command handling.

The use case for rwlocks is not really the case where infrequent write
access meets frequent read access.  Rather, the use case is when it is
important to reduce or prevent contention between readers.

Rwlocks come with their own downsides though.  I guess the somewhat
costlier lock implementation could counter the benefit of allowing
concurrent readers.  Or maybe latency spikes around a write access could be
an issue.

I believe I have read somewhere that one should rather use a simple
spinlock unless exhaustive tests prove that an rwlock really performs
better.  Furthermore, in many if not all use cases of rwlocks, RCU is
available as another alternative.  RCU comes with its own set of downsides
though, for example not being as well and widely understood by programmers
compared to locking, being less easy to debug (may have improved
recently), and posing some challenges to RT-PREEMPT kernels.

AFAIU the above considerations cannot be applied 100 % to able-to-sleep
reader-writer locks, i.e. the kernel's rwsem.  Still, the use case of an
rwsem (in contrast to a mutex) is not particularly where a datum is rarely
written and often read, but where it is desirable to let multiple readers
not block each other.

[Somebody correct me where I'm wrong.]

PS, I cloned your git tree not long ago, but again various distractions
kept me from having a broader look at your code...
-- 
Stefan Richter
-=====-===-- --== ---==
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v2 08/11] firewire-sbp-target: Add sbp_login.{c,h}
  2012-03-03 17:37           ` Stefan Richter
@ 2012-03-15 17:48             ` Paul E. McKenney
  0 siblings, 0 replies; 104+ messages in thread
From: Paul E. McKenney @ 2012-03-15 17:48 UTC (permalink / raw)
  To: Stefan Richter
  Cc: Chris Boot, linux1394-devel, target-devel, linux-kernel, agrover,
	clemens, nab

On Sat, Mar 03, 2012 at 06:37:22PM +0100, Stefan Richter wrote:
> On Feb 16 Chris Boot wrote:

[ . . . ]

> > I guess I need to protect access to 
> > the entire session really. Possibly even rwlocks due to only the 
> > management processes ever changing anything, but lots of reads during 
> > command handling.
> 
> The use case for rwlocks is not really the case where infrequent write
> access meets frequent read access.  Rather, the use case is when it is
> important to reduce or prevent contention between readers.
> 
> Rwlocks come with their own downsides though.  I guess the somewhat
> costlier lock implementation could counter the benefit of allowing
> concurrent readers.  Or maybe latency spikes around a write access could be
> an issue.
> 
> I believe I have read somewhere that one should rather use a simple
> spinlock unless exhaustive tests prove that an rwlock really performs
> better.  Furthermore, in many if not all use cases of rwlocks, RCU is
> available as another alternative.  RCU comes with its own set of downsides
> though, for example not being as well and widely understood by programmers
> compared to locking, being less easy to debug (may have improved
> recently), and posing some challenges to RT-PREEMPT kernels.

The preemptible RCU implementations (TREE_PREEMPT_RCU and TINY_PREEMPT_RCU)
handle the -rt tree.

> AFAIU the above considerations cannot be applied 100 % to able-to-sleep
> reader-writer locks, i.e. the kernel's rwsem.  Still, the use case of an
> rwsem (in contrast to a mutex) is not particularly where a datum is rarely
> written and often read, but where it is desirable to let multiple readers
> not block each other.
> 
> [Somebody correct me where I'm wrong.]

And you can use SRCU if readers need to block.

That said, even I agree that RCU is not always the right tool for the job.

							;-), Paul

> PS, I cloned your git tree not long ago, but again various distractions
> kept me from having a broader look at your code...
> -- 
> Stefan Richter
> -=====-===-- --== ---==
> http://arcgraph.de/sr/
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 


^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
                       ` (10 preceding siblings ...)
  2012-02-15 14:47     ` [PATCH v2 11/11] firewire-sbp-target: Add to target Kconfig and Makefile Chris Boot
@ 2012-04-11 14:20     ` Chris Boot
  2012-04-11 14:20       ` [PATCH 01/11] firewire: Add function to get speed from opaque struct fw_request Chris Boot
                         ` (12 more replies)
  11 siblings, 13 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr

The FireWire SBP-2 Target is a driver for using an IEEE-1394 connection
as a SCSI transport. This module uses the SCSI Target framework to
expose LUNs to other machines attached to a FireWire bus, in effect
acting as a FireWire hard disk similar to FireWire Target Disk mode on
many Apple computers.

Sorry this latest revision has been a long time coming. I was trying to
chase down a crashing bug (but haven't been able to replicate it), changed
my mind about a large portion of the code twice, and life got in the way as
well!

Changes in v3:
* Updates for target framework API changes
* Attempt to make headers self-contained
* Remove bad use of atomics and memory barriers
* Rework use of locking
* Use system workqueues
* Wrap fw_run_transaction() to retry failed transactions
* Coding style fixes
* Fix a few bugs
* Overhaul sbp_rw_data()
* Overhaul target fetch agent

Changes in v2:
* Fixed some copy & paste issues
* Updated Kconfig (wording, depends, 'default n')
* Removed some unnecessary EXPORT_SYMBOL()s
* Merged sbp_util.{c,h} into sbp_configfs.c and sbp_base.h
* Merged sbp_proto.{c,h} into sbp_fabric.{c,h}
* Cleaned up comments and several printks
* Fixed a few minor bugs
* Create & use our own workqueue instead of using fw_workqueue
* Dropped the unused TFO->new_cmd_map and sbp_new_cmd()
* Overhauled and simplified tgt_agent_fetch_work()
* Removed some redundant members of struct sbp_target_request
* Removed struct sbp_lun and code to maintain redundant LUN list
* Added spinlock to struct sbp_session and use locking throughout
* Moved fw_card_{get,put,release}() into linux/firewire.h


^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH 01/11] firewire: Add function to get speed from opaque struct fw_request
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-11 14:20       ` [PATCH 02/11] firewire: Move fw_card kref functions into linux/firewire.h Chris Boot
                         ` (11 subsequent siblings)
  12 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

Sometimes it's useful to know the FireWire speed of the request that has
just come in to a fw_address_handler callback. As struct fw_request is
opaque we can't peek inside to get the speed out of the struct fw_packet
that's just inside. For example, the SBP-2 spec says:

"The speed at which the block write request to the MANAGEMENT_AGENT
register is received shall determine the speed used by the target for
all subsequent requests to read the initiator’s configuration ROM, fetch
ORB’s from initiator memory or store status at the initiator’s
status_FIFO. Command block ORB’s separately specify the speed for
requests addressed to the data buffer or page table."

[ ANSI T10/1155D Revision 4 page 53/54 ]

Signed-off-by: Chris Boot <bootc@bootc.net>
Acked-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: Clemens Ladisch <clemens@ladisch.de>
---
 drivers/firewire/core-transaction.c |    9 +++++++++
 include/linux/firewire.h            |    1 +
 2 files changed, 10 insertions(+)

diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index dea2dcc..db8a965 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -820,6 +820,15 @@ void fw_send_response(struct fw_card *card,
 }
 EXPORT_SYMBOL(fw_send_response);
 
+/**
+ * fw_get_request_speed() - returns speed at which the @request was received
+ */
+int fw_get_request_speed(struct fw_request *request)
+{
+	return request->response.speed;
+}
+EXPORT_SYMBOL(fw_get_request_speed);
+
 static void handle_exclusive_region_request(struct fw_card *card,
 					    struct fw_packet *p,
 					    struct fw_request *request,
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index cdc9b71..4683130 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -325,6 +325,7 @@ int fw_core_add_address_handler(struct fw_address_handler *handler,
 void fw_core_remove_address_handler(struct fw_address_handler *handler);
 void fw_send_response(struct fw_card *card,
 		      struct fw_request *request, int rcode);
+int fw_get_request_speed(struct fw_request *request);
 void fw_send_request(struct fw_card *card, struct fw_transaction *t,
 		     int tcode, int destination_id, int generation, int speed,
 		     unsigned long long offset, void *payload, size_t length,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 02/11] firewire: Move fw_card kref functions into linux/firewire.h
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
  2012-04-11 14:20       ` [PATCH 01/11] firewire: Add function to get speed from opaque struct fw_request Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-11 14:20       ` [PATCH 03/11] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
                         ` (10 subsequent siblings)
  12 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

When writing a firewire driver that doesn't deal with struct fw_device
objects (e.g. it only publishes FireWire units and doesn't subscribe to
them), you likely need to keep referenced to struct fw_card objects so
that you can send messages to other nodes. This patch moves
fw_card_put(), fw_card_get() and fw_card_release() into the public
include/linux/firewire.h header instead of drivers/firewire/core.h, and
adds EXPORT_SYMBOL_GPL(fw_card_release).

The firewire-sbp-target module requires these so it can keep a reference
to the fw_card object in order that it can fetch ORBs to execute and
read/write related data and status information.

Signed-off-by: Chris Boot <bootc@bootc.net>
Acked-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: Clemens Ladisch <clemens@ladisch.de>
---
 drivers/firewire/core-card.c |    1 +
 drivers/firewire/core.h      |   15 ---------------
 include/linux/firewire.h     |   14 ++++++++++++++
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index cc595eb..f5552b3 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -676,6 +676,7 @@ void fw_card_release(struct kref *kref)
 
 	complete(&card->done);
 }
+EXPORT_SYMBOL_GPL(fw_card_release);
 
 void fw_core_remove_card(struct fw_card *card)
 {
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 9047f55..b5a2f61 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -120,21 +120,6 @@ int fw_compute_block_crc(__be32 *block);
 void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset);
 void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
 
-static inline struct fw_card *fw_card_get(struct fw_card *card)
-{
-	kref_get(&card->kref);
-
-	return card;
-}
-
-void fw_card_release(struct kref *kref);
-
-static inline void fw_card_put(struct fw_card *card)
-{
-	kref_put(&card->kref, fw_card_release);
-}
-
-
 /* -cdev */
 
 extern const struct file_operations fw_device_ops;
diff --git a/include/linux/firewire.h b/include/linux/firewire.h
index 4683130..e83c24a 100644
--- a/include/linux/firewire.h
+++ b/include/linux/firewire.h
@@ -135,6 +135,20 @@ struct fw_card {
 	__be32 maint_utility_register;
 };
 
+static inline struct fw_card *fw_card_get(struct fw_card *card)
+{
+	kref_get(&card->kref);
+
+	return card;
+}
+
+void fw_card_release(struct kref *kref);
+
+static inline void fw_card_put(struct fw_card *card)
+{
+	kref_put(&card->kref, fw_card_release);
+}
+
 struct fw_attribute_group {
 	struct attribute_group *groups[2];
 	struct attribute_group group;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 03/11] firewire-sbp-target: Add Kconfig, Makefile and TODO
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
  2012-04-11 14:20       ` [PATCH 01/11] firewire: Add function to get speed from opaque struct fw_request Chris Boot
  2012-04-11 14:20       ` [PATCH 02/11] firewire: Move fw_card kref functions into linux/firewire.h Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-11 14:20       ` [PATCH 04/11] firewire-sbp-target: Add sbp_base.h header Chris Boot
                         ` (9 subsequent siblings)
  12 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

The FireWire SBP-2 Target is a driver for using an IEEE-1394 connection
as a SCSI transport. This module uses the SCSI Target framework to
expose LUNs to other machines attached to a FireWire bus, in effect
acting as a FireWire hard disk similar to FireWire Target Disk mode on
many Apple computers.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/Kconfig  |   13 +++++++++++++
 drivers/target/sbp/Makefile |   11 +++++++++++
 drivers/target/sbp/TODO     |    7 +++++++
 3 files changed, 31 insertions(+)
 create mode 100644 drivers/target/sbp/Kconfig
 create mode 100644 drivers/target/sbp/Makefile
 create mode 100644 drivers/target/sbp/TODO

diff --git a/drivers/target/sbp/Kconfig b/drivers/target/sbp/Kconfig
new file mode 100644
index 0000000..c9f85e9
--- /dev/null
+++ b/drivers/target/sbp/Kconfig
@@ -0,0 +1,13 @@
+
+config FIREWIRE_SBP_TARGET
+	tristate "FireWire SBP-2 fabric module"
+	depends on FIREWIRE && EXPERIMENTAL
+	help
+	  Say Y or M here to enable SCSI target functionality over FireWire.
+	  This enables you to expose SCSI devices to other nodes on the FireWire
+	  bus, for example hard disks. Similar to FireWire Target Disk mode on
+	  many Apple computers.
+
+	  To compile this driver as a module, say M here: The module will be
+	  called firewire-sbp-target.
+
diff --git a/drivers/target/sbp/Makefile b/drivers/target/sbp/Makefile
new file mode 100644
index 0000000..c8f73f4
--- /dev/null
+++ b/drivers/target/sbp/Makefile
@@ -0,0 +1,11 @@
+
+firewire-sbp-target-y += \
+	sbp_configfs.o \
+	sbp_fabric.o \
+	sbp_login.o \
+	sbp_management_agent.o \
+	sbp_scsi_cmnd.o \
+	sbp_target_agent.o
+
+obj-$(CONFIG_FIREWIRE_SBP_TARGET) += firewire-sbp-target.o
+
diff --git a/drivers/target/sbp/TODO b/drivers/target/sbp/TODO
new file mode 100644
index 0000000..eaec1c9
--- /dev/null
+++ b/drivers/target/sbp/TODO
@@ -0,0 +1,7 @@
+* Force-terminate sessions when disabling targets
+* Ability to have several SCSI commands in-flight (TCQ?)
+* Retry failed FireWire transactions a few times with exponential backoff
+* Take into account the page_size field for transfers and/or page tables
+* Handle descriptor format sense data
+* Implement QUERY LOGINS management ORB
+* Implement TASK MANAGEMENT functionality
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 04/11] firewire-sbp-target: Add sbp_base.h header
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (2 preceding siblings ...)
  2012-04-11 14:20       ` [PATCH 03/11] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-11 14:20       ` [PATCH 05/11] firewire-sbp-target: Add sbp_configfs.c Chris Boot
                         ` (8 subsequent siblings)
  12 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This header contains defines and structures that are common to many of
the modules of the target code. This includes SBP-2 protocol structures
and constants as well as a few structs for setting up the target, LUN
login information and session setup.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_base.h |  211 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 211 insertions(+)
 create mode 100644 drivers/target/sbp/sbp_base.h

diff --git a/drivers/target/sbp/sbp_base.h b/drivers/target/sbp/sbp_base.h
new file mode 100644
index 0000000..fa6a39b
--- /dev/null
+++ b/drivers/target/sbp/sbp_base.h
@@ -0,0 +1,211 @@
+#ifndef _SBP_BASE_H
+#define _SBP_BASE_H
+
+#include <linux/firewire.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <target/target_core_base.h>
+
+#define SBP_VERSION  "v0.1"
+#define SBP_NAMELEN 32
+
+#define SBP_ORB_FETCH_SIZE	8
+
+#define MANAGEMENT_AGENT_STATE_IDLE	0
+#define MANAGEMENT_AGENT_STATE_BUSY	1
+
+#define ORB_NOTIFY(v)			(((v) >> 31) & 0x01)
+#define ORB_REQUEST_FORMAT(v)		(((v) >> 29) & 0x03)
+
+#define MANAGEMENT_ORB_FUNCTION(v)	(((v) >> 16) & 0x0f)
+
+#define MANAGEMENT_ORB_FUNCTION_LOGIN			0x0
+#define MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS		0x1
+#define MANAGEMENT_ORB_FUNCTION_RECONNECT		0x3
+#define MANAGEMENT_ORB_FUNCTION_SET_PASSWORD		0x4
+#define MANAGEMENT_ORB_FUNCTION_LOGOUT			0x7
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK		0xb
+#define MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET		0xc
+#define MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET	0xe
+#define MANAGEMENT_ORB_FUNCTION_TARGET_RESET		0xf
+
+#define LOGIN_ORB_EXCLUSIVE(v)		(((v) >> 28) &   0x01)
+#define LOGIN_ORB_RESERVED(v)		(((v) >> 24) &   0x0f)
+#define LOGIN_ORB_RECONNECT(v)		(((v) >> 20) &   0x0f)
+#define LOGIN_ORB_LUN(v)		(((v) >>  0) & 0xffff)
+#define LOGIN_ORB_PASSWORD_LENGTH(v)	(((v) >> 16) & 0xffff)
+#define LOGIN_ORB_RESPONSE_LENGTH(v)	(((v) >>  0) & 0xffff)
+
+#define RECONNECT_ORB_LOGIN_ID(v)	(((v) >>  0) & 0xffff)
+#define LOGOUT_ORB_LOGIN_ID(v)		(((v) >>  0) & 0xffff)
+
+#define CMDBLK_ORB_DIRECTION(v)		(((v) >> 27) &   0x01)
+#define CMDBLK_ORB_SPEED(v)		(((v) >> 24) &   0x07)
+#define CMDBLK_ORB_MAX_PAYLOAD(v)	(((v) >> 20) &   0x0f)
+#define CMDBLK_ORB_PG_TBL_PRESENT(v)	(((v) >> 19) &   0x01)
+#define CMDBLK_ORB_PG_SIZE(v)		(((v) >> 16) &   0x07)
+#define CMDBLK_ORB_DATA_SIZE(v)		(((v) >>  0) & 0xffff)
+
+#define STATUS_BLOCK_SRC(v)		(((v) &   0x03) << 30)
+#define STATUS_BLOCK_RESP(v)		(((v) &   0x03) << 28)
+#define STATUS_BLOCK_DEAD(v)		(((v) ? 1 : 0)  << 27)
+#define STATUS_BLOCK_LEN(v)		(((v) &   0x07) << 24)
+#define STATUS_BLOCK_SBP_STATUS(v)	(((v) &   0xff) << 16)
+#define STATUS_BLOCK_ORB_OFFSET_HIGH(v)	(((v) & 0xffff) <<  0)
+
+#define STATUS_SRC_ORB_CONTINUING	0
+#define STATUS_SRC_ORB_FINISHED		1
+#define STATUS_SRC_UNSOLICITED		2
+
+#define STATUS_RESP_REQUEST_COMPLETE	0
+#define STATUS_RESP_TRANSPORT_FAILURE	1
+#define STATUS_RESP_ILLEGAL_REQUEST	2
+#define STATUS_RESP_VENDOR_DEPENDENT	3
+
+#define SBP_STATUS_OK			0
+#define SBP_STATUS_REQ_TYPE_NOTSUPP	1
+#define SBP_STATUS_SPEED_NOTSUPP	2
+#define SBP_STATUS_PAGE_SIZE_NOTSUPP	3
+#define SBP_STATUS_ACCESS_DENIED	4
+#define SBP_STATUS_LUN_NOTSUPP		5
+#define SBP_STATUS_PAYLOAD_TOO_SMALL	6
+/* 7 is reserved */
+#define SBP_STATUS_RESOURCES_UNAVAIL	8
+#define SBP_STATUS_FUNCTION_REJECTED	9
+#define SBP_STATUS_LOGIN_ID_UNKNOWN	10
+#define SBP_STATUS_DUMMY_ORB_COMPLETE	11
+#define SBP_STATUS_REQUEST_ABORTED	12
+#define SBP_STATUS_UNSPECIFIED_ERROR	0xff
+
+#define AGENT_STATE_RESET	0
+#define AGENT_STATE_ACTIVE	1
+#define AGENT_STATE_SUSPENDED	2
+#define AGENT_STATE_DEAD	3
+
+struct sbp2_pointer {
+	__be32 high;
+	__be32 low;
+};
+
+struct sbp_command_block_orb {
+	struct sbp2_pointer next_orb;
+	struct sbp2_pointer data_descriptor;
+	__be32 misc;
+	u8 command_block[12];
+};
+
+struct sbp_page_table_entry {
+	__be16 segment_length;
+	__be16 segment_base_hi;
+	__be32 segment_base_lo;
+};
+
+struct sbp_management_orb {
+	struct sbp2_pointer ptr1;
+	struct sbp2_pointer ptr2;
+	__be32 misc;
+	__be32 length;
+	struct sbp2_pointer status_fifo;
+};
+
+struct sbp_status_block {
+	__be32 status;
+	__be32 orb_low;
+	u8 data[24];
+};
+
+struct sbp_login_response_block {
+	__be32 misc;
+	struct sbp2_pointer command_block_agent;
+	__be32 reconnect_hold;
+};
+
+struct sbp_login_descriptor {
+	struct sbp_session *sess;
+	struct list_head link;
+
+	struct se_lun *lun;
+
+	u64 status_fifo_addr;
+	int exclusive;
+	u16 login_id;
+
+	struct sbp_target_agent *tgt_agt;
+};
+
+struct sbp_session {
+	spinlock_t lock;
+	struct se_session *se_sess;
+	struct list_head login_list;
+	struct delayed_work maint_work;
+
+	u64 guid; /* login_owner_EUI_64 */
+	int node_id; /* login_owner_ID */
+
+	struct fw_card *card;
+	int generation;
+	int speed;
+
+	int reconnect_hold;
+	u64 reconnect_expires;
+};
+
+struct sbp_nacl {
+	/* Initiator EUI-64 */
+	u64 guid;
+	/* ASCII formatted GUID for SBP Initiator port */
+	char iport_name[SBP_NAMELEN];
+	/* Returned by sbp_make_nodeacl() */
+	struct se_node_acl se_node_acl;
+};
+
+struct sbp_tpg {
+	/* Target portal group tag for TCM */
+	u16 tport_tpgt;
+	/* Pointer back to sbp_tport */
+	struct sbp_tport *tport;
+	/* Returned by sbp_make_tpg() */
+	struct se_portal_group se_tpg;
+};
+
+struct sbp_tport {
+	/* Target Unit Identifier (EUI-64) */
+	u64 guid;
+	/* Target port name */
+	char tport_name[SBP_NAMELEN];
+	/* Returned by sbp_make_tport() */
+	struct se_wwn tport_wwn;
+
+	struct sbp_tpg *tpg;
+
+	/* FireWire unit directory */
+	struct fw_descriptor unit_directory;
+
+	/* SBP Management Agent */
+	struct sbp_management_agent *mgt_agt;
+
+	/* Parameters */
+	int enable;
+	s32 directory_id;
+	int mgt_orb_timeout;
+	int max_reconnect_timeout;
+	int max_logins_per_lun;
+};
+
+extern struct target_fabric_configfs *sbp_fabric_configfs;
+extern const struct fw_address_region sbp_register_region;
+
+static inline u64 sbp2_pointer_to_addr(const struct sbp2_pointer *ptr)
+{
+	return (u64)(be32_to_cpu(ptr->high) & 0x0000ffff) << 32 |
+		(be32_to_cpu(ptr->low) & 0xfffffffc);
+}
+
+static inline void addr_to_sbp2_pointer(u64 addr, struct sbp2_pointer *ptr)
+{
+	ptr->high = cpu_to_be32(addr >> 32);
+	ptr->low = cpu_to_be32(addr);
+}
+
+#endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 05/11] firewire-sbp-target: Add sbp_configfs.c
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (3 preceding siblings ...)
  2012-04-11 14:20       ` [PATCH 04/11] firewire-sbp-target: Add sbp_base.h header Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-11 14:20       ` [PATCH 06/11] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
                         ` (7 subsequent siblings)
  12 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This is used to glue the target framework's configfs code to the target
code, and what is used to create targets and link them to LUNs to
export. The code to create the FireWire unit directory to advertise
targets on the FireWire bus is also in here.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_configfs.c |  737 +++++++++++++++++++++++++++++++++++++
 1 file changed, 737 insertions(+)
 create mode 100644 drivers/target/sbp/sbp_configfs.c

diff --git a/drivers/target/sbp/sbp_configfs.c b/drivers/target/sbp/sbp_configfs.c
new file mode 100644
index 0000000..5399616
--- /dev/null
+++ b/drivers/target/sbp/sbp_configfs.c
@@ -0,0 +1,737 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/configfs.h>
+#include <linux/ctype.h>
+#include <linux/firewire.h>
+
+#include <asm/unaligned.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_configfs.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/configfs_macros.h>
+
+#include "sbp_base.h"
+#include "sbp_fabric.h"
+#include "sbp_management_agent.h"
+
+/* Local pointer to allocated TCM configfs fabric module */
+struct target_fabric_configfs *sbp_fabric_configfs;
+
+/* FireWire address region for management and command block address handlers */
+const struct fw_address_region sbp_register_region = {
+	.start = CSR_REGISTER_BASE + 0x10000,
+	.end   = 0x1000000000000ULL,
+};
+
+static const u32 sbp_unit_directory_template[] = {
+	0x1200609e, /* unit_specifier_id: NCITS/T10 */
+	0x13010483, /* unit_sw_version: 1155D Rev 4 */
+	0x3800609e, /* command_set_specifier_id: NCITS/T10 */
+	0x390104d8, /* command_set: SPC-2 */
+	0x3b000000, /* command_set_revision: 0 */
+	0x3c000001, /* firmware_revision: 1 */
+};
+
+static int sbp_count_se_tpg_luns(struct se_portal_group *tpg)
+{
+	int i, count = 0;
+
+	spin_lock(&tpg->tpg_lun_lock);
+	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+		struct se_lun *se_lun = tpg->tpg_lun_list[i];
+
+		if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+			continue;
+
+		count++;
+	}
+	spin_unlock(&tpg->tpg_lun_lock);
+
+	return count;
+}
+
+static int sbp_update_unit_directory(struct sbp_tport *tport)
+{
+	int num_luns, num_entries, idx = 0, mgt_agt_addr, ret, i;
+	u32 *data;
+
+	if (tport->unit_directory.data) {
+		fw_core_remove_descriptor(&tport->unit_directory);
+		kfree(tport->unit_directory.data);
+		tport->unit_directory.data = NULL;
+	}
+
+	if (!tport->enable || !tport->tpg)
+		return 0;
+
+	num_luns = sbp_count_se_tpg_luns(&tport->tpg->se_tpg);
+
+	/*
+	 * Number of entries in the final unit directory:
+	 *  - all of those in the template
+	 *  - management_agent
+	 *  - unit_characteristics
+	 *  - reconnect_timeout
+	 *  - unit unique ID
+	 *  - one for each LUN
+	 *
+	 *  MUST NOT include leaf or sub-directory entries
+	 */
+	num_entries = ARRAY_SIZE(sbp_unit_directory_template) + 4 + num_luns;
+
+	if (tport->directory_id != -1)
+		num_entries++;
+
+	/* allocate num_entries + 4 for the header and unique ID leaf */
+	data = kcalloc((num_entries + 4), sizeof(u32), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* directory_length */
+	data[idx++] = num_entries << 16;
+
+	/* directory_id */
+	if (tport->directory_id != -1)
+		data[idx++] = (CSR_DIRECTORY_ID << 24) | tport->directory_id;
+
+	/* unit directory template */
+	memcpy(&data[idx], sbp_unit_directory_template,
+			sizeof(sbp_unit_directory_template));
+	idx += ARRAY_SIZE(sbp_unit_directory_template);
+
+	/* management_agent */
+	mgt_agt_addr = (tport->mgt_agt->handler.offset - CSR_REGISTER_BASE) / 4;
+	data[idx++] = 0x54000000 | (mgt_agt_addr & 0x00ffffff);
+
+	/* unit_characteristics */
+	data[idx++] = 0x3a000000 |
+		(((tport->mgt_orb_timeout * 2) << 8) & 0xff00) |
+		SBP_ORB_FETCH_SIZE;
+
+	/* reconnect_timeout */
+	data[idx++] = 0x3d000000 | (tport->max_reconnect_timeout & 0xffff);
+
+	/* unit unique ID (leaf is just after LUNs) */
+	data[idx++] = 0x8d000000 | (num_luns + 1);
+
+	spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+	for (i = 0; i < TRANSPORT_MAX_LUNS_PER_TPG; i++) {
+		struct se_lun *se_lun = tport->tpg->se_tpg.tpg_lun_list[i];
+		struct se_device *dev;
+		int type;
+
+		if (se_lun->lun_status == TRANSPORT_LUN_STATUS_FREE)
+			continue;
+
+		spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+		dev = se_lun->lun_se_dev;
+		type = dev->transport->get_device_type(dev);
+
+		/* logical_unit_number */
+		data[idx++] = 0x14000000 |
+			((type << 16) & 0x1f0000) |
+			(se_lun->unpacked_lun & 0xffff);
+
+		spin_lock(&tport->tpg->se_tpg.tpg_lun_lock);
+	}
+	spin_unlock(&tport->tpg->se_tpg.tpg_lun_lock);
+
+	/* unit unique ID leaf */
+	data[idx++] = 2 << 16;
+	data[idx++] = tport->guid >> 32;
+	data[idx++] = tport->guid;
+
+	tport->unit_directory.length = idx;
+	tport->unit_directory.key = (CSR_DIRECTORY | CSR_UNIT) << 24;
+	tport->unit_directory.data = data;
+
+	ret = fw_core_add_descriptor(&tport->unit_directory);
+	if (ret < 0) {
+		kfree(tport->unit_directory.data);
+		tport->unit_directory.data = NULL;
+	}
+
+	return ret;
+}
+
+static ssize_t sbp_parse_wwn(const char *name, u64 *wwn, int strict)
+{
+	const char *cp;
+	char c, nibble;
+	int pos = 0, err;
+
+	*wwn = 0;
+	for (cp = name; cp < &name[SBP_NAMELEN - 1]; cp++) {
+		c = *cp;
+		if (c == '\n' && cp[1] == '\0')
+			continue;
+		if (c == '\0') {
+			err = 2;
+			if (pos != 16)
+				goto fail;
+			return cp - name;
+		}
+		err = 3;
+		if (isdigit(c))
+			nibble = c - '0';
+		else if (isxdigit(c) && (islower(c) || !strict))
+			nibble = tolower(c) - 'a' + 10;
+		else
+			goto fail;
+		*wwn = (*wwn << 4) | nibble;
+		pos++;
+	}
+	err = 4;
+fail:
+	printk(KERN_INFO "err %u len %zu pos %u\n",
+			err, cp - name, pos);
+	return -1;
+}
+
+static ssize_t sbp_format_wwn(char *buf, size_t len, u64 wwn)
+{
+	return snprintf(buf, len, "%016llx", wwn);
+}
+
+static struct se_node_acl *sbp_make_nodeacl(
+		struct se_portal_group *se_tpg,
+		struct config_group *group,
+		const char *name)
+{
+	struct se_node_acl *se_nacl, *se_nacl_new;
+	struct sbp_nacl *nacl;
+	u64 guid = 0;
+	u32 nexus_depth = 1;
+
+	if (sbp_parse_wwn(name, &guid, 1) < 0)
+		return ERR_PTR(-EINVAL);
+
+	se_nacl_new = sbp_alloc_fabric_acl(se_tpg);
+	if (!se_nacl_new)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * se_nacl_new may be released by core_tpg_add_initiator_node_acl()
+	 * when converting a NodeACL from demo mode -> explict
+	 */
+	se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
+			name, nexus_depth);
+	if (IS_ERR(se_nacl)) {
+		sbp_release_fabric_acl(se_tpg, se_nacl_new);
+		return se_nacl;
+	}
+
+	nacl = container_of(se_nacl, struct sbp_nacl, se_node_acl);
+	nacl->guid = guid;
+	sbp_format_wwn(nacl->iport_name, SBP_NAMELEN, guid);
+
+	return se_nacl;
+}
+
+static void sbp_drop_nodeacl(struct se_node_acl *se_acl)
+{
+	struct sbp_nacl *nacl =
+		container_of(se_acl, struct sbp_nacl, se_node_acl);
+
+	core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
+	kfree(nacl);
+}
+
+static int sbp_post_link_lun(
+		struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+
+	return sbp_update_unit_directory(tpg->tport);
+}
+
+static void sbp_pre_unlink_lun(
+		struct se_portal_group *se_tpg,
+		struct se_lun *se_lun)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	int ret;
+
+	if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0)
+		tport->enable = 0;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		pr_err("unlink LUN: failed to update unit directory\n");
+}
+
+static struct se_portal_group *sbp_make_tpg(
+		struct se_wwn *wwn,
+		struct config_group *group,
+		const char *name)
+{
+	struct sbp_tport *tport =
+		container_of(wwn, struct sbp_tport, tport_wwn);
+
+	struct sbp_tpg *tpg;
+	unsigned long tpgt;
+	int ret;
+
+	if (strstr(name, "tpgt_") != name)
+		return ERR_PTR(-EINVAL);
+	if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+		return ERR_PTR(-EINVAL);
+
+	if (tport->tpg) {
+		pr_err("Only one TPG per Unit is possible.\n");
+		return ERR_PTR(-EBUSY);
+	}
+
+	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
+	if (!tpg) {
+		pr_err("Unable to allocate struct sbp_tpg\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	tpg->tport = tport;
+	tpg->tport_tpgt = tpgt;
+	tport->tpg = tpg;
+
+	/* default attribute values */
+	tport->enable = 0;
+	tport->directory_id = -1;
+	tport->mgt_orb_timeout = 15;
+	tport->max_reconnect_timeout = 5;
+	tport->max_logins_per_lun = 1;
+
+	tport->mgt_agt = sbp_management_agent_register(tport);
+	if (IS_ERR(tport->mgt_agt)) {
+		ret = PTR_ERR(tport->mgt_agt);
+		kfree(tpg);
+		return ERR_PTR(ret);
+	}
+
+	ret = core_tpg_register(&sbp_fabric_configfs->tf_ops, wwn,
+			&tpg->se_tpg, (void *)tpg,
+			TRANSPORT_TPG_TYPE_NORMAL);
+	if (ret < 0) {
+		sbp_management_agent_unregister(tport->mgt_agt);
+		kfree(tpg);
+		return ERR_PTR(ret);
+	}
+
+	return &tpg->se_tpg;
+}
+
+static void sbp_drop_tpg(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	core_tpg_deregister(se_tpg);
+	sbp_management_agent_unregister(tport->mgt_agt);
+	tport->tpg = NULL;
+	kfree(tpg);
+}
+
+static struct se_wwn *sbp_make_tport(
+		struct target_fabric_configfs *tf,
+		struct config_group *group,
+		const char *name)
+{
+	struct sbp_tport *tport;
+	u64 guid = 0;
+
+	if (sbp_parse_wwn(name, &guid, 1) < 0)
+		return ERR_PTR(-EINVAL);
+
+	tport = kzalloc(sizeof(*tport), GFP_KERNEL);
+	if (!tport) {
+		pr_err("Unable to allocate struct sbp_tport\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	tport->guid = guid;
+	sbp_format_wwn(tport->tport_name, SBP_NAMELEN, guid);
+
+	return &tport->tport_wwn;
+}
+
+static void sbp_drop_tport(struct se_wwn *wwn)
+{
+	struct sbp_tport *tport =
+		container_of(wwn, struct sbp_tport, tport_wwn);
+
+	kfree(tport);
+}
+
+static ssize_t sbp_wwn_show_attr_version(
+		struct target_fabric_configfs *tf,
+		char *page)
+{
+	return sprintf(page, "FireWire SBP fabric module %s\n", SBP_VERSION);
+}
+
+TF_WWN_ATTR_RO(sbp, version);
+
+static struct configfs_attribute *sbp_wwn_attrs[] = {
+	&sbp_wwn_version.attr,
+	NULL,
+};
+
+static ssize_t sbp_tpg_show_directory_id(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	if (tport->directory_id == -1)
+		return sprintf(page, "implicit\n");
+	else
+		return sprintf(page, "%06x\n", tport->directory_id);
+}
+
+static ssize_t sbp_tpg_store_directory_id(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+
+	if (tport->enable) {
+		pr_err("Cannot change the directory_id on an active target.\n");
+		return -EBUSY;
+	}
+
+	if (strstr(page, "implicit") == page) {
+		tport->directory_id = -1;
+	} else {
+		if (kstrtoul(page, 16, &val) < 0)
+			return -EINVAL;
+		if (val > 0xffffff)
+			return -EINVAL;
+
+		tport->directory_id = val;
+	}
+
+	return count;
+}
+
+static ssize_t sbp_tpg_show_enable(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->enable);
+}
+
+static ssize_t sbp_tpg_store_enable(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val != 0) && (val != 1))
+		return -EINVAL;
+
+	if (tport->enable == val)
+		return count;
+
+	if (val) {
+		if (sbp_count_se_tpg_luns(&tpg->se_tpg) == 0) {
+			pr_err("Cannot enable a target with no LUNs!\n");
+			return -EINVAL;
+		}
+	} else {
+		/* XXX: force-shutdown sessions instead? */
+		spin_lock_bh(&se_tpg->session_lock);
+		if (!list_empty(&se_tpg->tpg_sess_list)) {
+			spin_unlock_bh(&se_tpg->session_lock);
+			return -EBUSY;
+		}
+		spin_unlock_bh(&se_tpg->session_lock);
+	}
+
+	tport->enable = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0) {
+		pr_err("Could not update Config ROM\n");
+		return ret;
+	}
+
+	return count;
+}
+
+TF_TPG_BASE_ATTR(sbp, directory_id, S_IRUGO | S_IWUSR);
+TF_TPG_BASE_ATTR(sbp, enable, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_base_attrs[] = {
+	&sbp_tpg_directory_id.attr,
+	&sbp_tpg_enable.attr,
+	NULL,
+};
+
+static ssize_t sbp_tpg_attrib_show_mgt_orb_timeout(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->mgt_orb_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 127))
+		return -EINVAL;
+
+	if (tport->mgt_orb_timeout == val)
+		return count;
+
+	tport->mgt_orb_timeout = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_reconnect_timeout(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->max_reconnect_timeout);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+	int ret;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 32767))
+		return -EINVAL;
+
+	if (tport->max_reconnect_timeout == val)
+		return count;
+
+	tport->max_reconnect_timeout = val;
+
+	ret = sbp_update_unit_directory(tport);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sbp_tpg_attrib_show_max_logins_per_lun(
+		struct se_portal_group *se_tpg,
+		char *page)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	return sprintf(page, "%d\n", tport->max_logins_per_lun);
+}
+
+static ssize_t sbp_tpg_attrib_store_max_logins_per_lun(
+		struct se_portal_group *se_tpg,
+		const char *page,
+		size_t count)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+	unsigned long val;
+
+	if (kstrtoul(page, 0, &val) < 0)
+		return -EINVAL;
+	if ((val < 1) || (val > 127))
+		return -EINVAL;
+
+	/* XXX: also check against current count? */
+
+	tport->max_logins_per_lun = val;
+
+	return count;
+}
+
+TF_TPG_ATTRIB_ATTR(sbp, mgt_orb_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_reconnect_timeout, S_IRUGO | S_IWUSR);
+TF_TPG_ATTRIB_ATTR(sbp, max_logins_per_lun, S_IRUGO | S_IWUSR);
+
+static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
+	&sbp_tpg_attrib_mgt_orb_timeout.attr,
+	&sbp_tpg_attrib_max_reconnect_timeout.attr,
+	&sbp_tpg_attrib_max_logins_per_lun.attr,
+	NULL,
+};
+
+static struct target_core_fabric_ops sbp_ops = {
+	.get_fabric_name		= sbp_get_fabric_name,
+	.get_fabric_proto_ident		= sbp_get_fabric_proto_ident,
+	.tpg_get_wwn			= sbp_get_fabric_wwn,
+	.tpg_get_tag			= sbp_get_tag,
+	.tpg_get_default_depth		= sbp_get_default_depth,
+	.tpg_get_pr_transport_id	= sbp_get_pr_transport_id,
+	.tpg_get_pr_transport_id_len	= sbp_get_pr_transport_id_len,
+	.tpg_parse_pr_out_transport_id	= sbp_parse_pr_out_transport_id,
+	.tpg_check_demo_mode		= sbp_check_true,
+	.tpg_check_demo_mode_cache	= sbp_check_true,
+	.tpg_check_demo_mode_write_protect = sbp_check_false,
+	.tpg_check_prod_mode_write_protect = sbp_check_false,
+	.tpg_alloc_fabric_acl		= sbp_alloc_fabric_acl,
+	.tpg_release_fabric_acl		= sbp_release_fabric_acl,
+	.tpg_get_inst_index		= sbp_tpg_get_inst_index,
+	.release_cmd			= sbp_release_cmd,
+	.shutdown_session		= sbp_shutdown_session,
+	.close_session			= sbp_close_session,
+	.sess_get_index			= sbp_sess_get_index,
+	.write_pending			= sbp_write_pending,
+	.write_pending_status		= sbp_write_pending_status,
+	.set_default_node_attributes	= sbp_set_default_node_attrs,
+	.get_task_tag			= sbp_get_task_tag,
+	.get_cmd_state			= sbp_get_cmd_state,
+	.queue_data_in			= sbp_queue_data_in,
+	.queue_status			= sbp_queue_status,
+	.queue_tm_rsp			= sbp_queue_tm_rsp,
+	.get_fabric_sense_len		= sbp_get_fabric_sense_len,
+	.set_fabric_sense_len		= sbp_set_fabric_sense_len,
+	.check_stop_free		= sbp_check_stop_free,
+
+	.fabric_make_wwn		= sbp_make_tport,
+	.fabric_drop_wwn		= sbp_drop_tport,
+	.fabric_make_tpg		= sbp_make_tpg,
+	.fabric_drop_tpg		= sbp_drop_tpg,
+	.fabric_post_link		= sbp_post_link_lun,
+	.fabric_pre_unlink		= sbp_pre_unlink_lun,
+	.fabric_make_np			= NULL,
+	.fabric_drop_np			= NULL,
+	.fabric_make_nodeacl		= sbp_make_nodeacl,
+	.fabric_drop_nodeacl		= sbp_drop_nodeacl,
+};
+
+static int sbp_register_configfs(void)
+{
+	struct target_fabric_configfs *fabric;
+	int ret;
+
+	fabric = target_fabric_configfs_init(THIS_MODULE, "sbp");
+	if (!fabric) {
+		pr_err("target_fabric_configfs_init() failed\n");
+		return -ENOMEM;
+	}
+
+	fabric->tf_ops = sbp_ops;
+
+	/*
+	 * Setup default attribute lists for various fabric->tf_cit_tmpl
+	 */
+	TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = sbp_wwn_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = sbp_tpg_base_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = sbp_tpg_attrib_attrs;
+	TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL;
+	TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL;
+
+	ret = target_fabric_configfs_register(fabric);
+	if (ret < 0) {
+		pr_err("target_fabric_configfs_register() failed for SBP\n");
+		return ret;
+	}
+
+	sbp_fabric_configfs = fabric;
+
+	return 0;
+};
+
+static void sbp_deregister_configfs(void)
+{
+	if (!sbp_fabric_configfs)
+		return;
+
+	target_fabric_configfs_deregister(sbp_fabric_configfs);
+	sbp_fabric_configfs = NULL;
+};
+
+static int __init sbp_init(void)
+{
+	int ret;
+
+	ret = sbp_register_configfs();
+	if (ret < 0)
+		return ret;
+
+	return 0;
+};
+
+static void sbp_exit(void)
+{
+	sbp_deregister_configfs();
+};
+
+MODULE_DESCRIPTION("FireWire SBP fabric driver");
+MODULE_LICENSE("GPL");
+module_init(sbp_init);
+module_exit(sbp_exit);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 06/11] firewire-sbp-target: Add sbp_fabric.{c,h}
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (4 preceding siblings ...)
  2012-04-11 14:20       ` [PATCH 05/11] firewire-sbp-target: Add sbp_configfs.c Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-11 14:20       ` [PATCH 07/11] firewire-sbp-target: Add sbp_management_agent.{c,h} Chris Boot
                         ` (6 subsequent siblings)
  12 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This serves as further glue between the target framework and SBP-2, in
this case dealing with SCSI command submission and data in/out.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_fabric.c |  314 +++++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_fabric.h |   40 +++++
 2 files changed, 354 insertions(+)
 create mode 100644 drivers/target/sbp/sbp_fabric.c
 create mode 100644 drivers/target/sbp/sbp_fabric.h

diff --git a/drivers/target/sbp/sbp_fabric.c b/drivers/target/sbp/sbp_fabric.c
new file mode 100644
index 0000000..5230851
--- /dev/null
+++ b/drivers/target/sbp/sbp_fabric.c
@@ -0,0 +1,314 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/slab.h>
+#include <linux/kthread.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/firewire.h>
+
+#include <asm/unaligned.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/libfc.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#include "sbp_base.h"
+#include "sbp_fabric.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+
+int sbp_check_true(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+int sbp_check_false(struct se_portal_group *se_tpg)
+{
+	return 0;
+}
+
+char *sbp_get_fabric_name(void)
+{
+	return "sbp";
+}
+
+char *sbp_get_fabric_wwn(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	struct sbp_tport *tport = tpg->tport;
+
+	return &tport->tport_name[0];
+}
+
+u16 sbp_get_tag(struct se_portal_group *se_tpg)
+{
+	struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
+	return tpg->tport_tpgt;
+}
+
+u32 sbp_get_default_depth(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *se_tpg)
+{
+	struct sbp_nacl *nacl;
+
+	nacl = kzalloc(sizeof(struct sbp_nacl), GFP_KERNEL);
+	if (!nacl) {
+		pr_err("Unable to alocate struct sbp_nacl\n");
+		return NULL;
+	}
+
+	return &nacl->se_node_acl;
+}
+
+void sbp_release_fabric_acl(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl)
+{
+	struct sbp_nacl *nacl =
+		container_of(se_nacl, struct sbp_nacl, se_node_acl);
+	kfree(nacl);
+}
+
+u32 sbp_tpg_get_inst_index(struct se_portal_group *se_tpg)
+{
+	return 1;
+}
+
+void sbp_release_cmd(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	sbp_free_request(req);
+}
+
+int sbp_shutdown_session(struct se_session *se_sess)
+{
+	return 0;
+}
+
+void sbp_close_session(struct se_session *se_sess)
+{
+	return;
+}
+
+u32 sbp_sess_get_index(struct se_session *se_sess)
+{
+	return 0;
+}
+
+int sbp_write_pending(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+	int ret;
+
+	ret = sbp_rw_data(req);
+	if (ret) {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(
+				STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(
+				SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		return ret;
+	}
+
+	transport_generic_process_write(se_cmd);
+
+	return 0;
+}
+
+int sbp_write_pending_status(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+void sbp_set_default_node_attrs(struct se_node_acl *nacl)
+{
+	return;
+}
+
+u32 sbp_get_task_tag(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	/* only used for printk until we do TMRs */
+	return (u32)req->orb_pointer;
+}
+
+int sbp_get_cmd_state(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+int sbp_queue_data_in(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+	int ret;
+
+	ret = sbp_rw_data(req);
+	if (ret) {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		return ret;
+	}
+
+	return sbp_send_sense(req);
+}
+
+/*
+ * Called after command (no data transfer) or after the write (to device)
+ * operation is completed
+ */
+int sbp_queue_status(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	return sbp_send_sense(req);
+}
+
+int sbp_queue_tm_rsp(struct se_cmd *se_cmd)
+{
+	return 0;
+}
+
+u16 sbp_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length)
+{
+	return 0;
+}
+
+u16 sbp_get_fabric_sense_len(void)
+{
+	return 0;
+}
+
+int sbp_check_stop_free(struct se_cmd *se_cmd)
+{
+	struct sbp_target_request *req = container_of(se_cmd,
+			struct sbp_target_request, se_cmd);
+
+	transport_generic_free_cmd(&req->se_cmd, 0);
+	return 1;
+}
+
+/*
+ * Handlers for Serial Bus Protocol 2/3 (SBP-2 / SBP-3)
+ */
+u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+{
+	/*
+	 * Return a IEEE 1394 SCSI Protocol identifier for loopback operations
+	 * This is defined in section 7.5.1 Table 362 in spc4r17
+	 */
+	return SCSI_PROTOCOL_SBP;
+}
+
+u32 sbp_get_pr_transport_id(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code,
+	unsigned char *buf)
+{
+	int ret;
+
+	/*
+	 * Set PROTOCOL IDENTIFIER to 3h for SBP
+	 */
+	buf[0] = SCSI_PROTOCOL_SBP;
+	/*
+	 * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+	 * over IEEE 1394
+	 */
+	ret = hex2bin(&buf[8], se_nacl->initiatorname, 8);
+	if (ret < 0)
+		pr_debug("sbp transport_id: invalid hex string\n");
+
+	/*
+	 * The IEEE 1394 Transport ID is a hardcoded 24-byte length
+	 */
+	return 24;
+}
+
+u32 sbp_get_pr_transport_id_len(
+	struct se_portal_group *se_tpg,
+	struct se_node_acl *se_nacl,
+	struct t10_pr_registration *pr_reg,
+	int *format_code)
+{
+	*format_code = 0;
+	/*
+	 * From spc4r17, 7.5.4.4 TransportID for initiator ports using SCSI
+	 * over IEEE 1394
+	 *
+	 * The SBP Transport ID is a hardcoded 24-byte length
+	 */
+	return 24;
+}
+
+/*
+ * Used for handling SCSI fabric dependent TransportIDs in SPC-3 and above
+ * Persistent Reservation SPEC_I_PT=1 and PROUT REGISTER_AND_MOVE operations.
+ */
+char *sbp_parse_pr_out_transport_id(
+	struct se_portal_group *se_tpg,
+	const char *buf,
+	u32 *out_tid_len,
+	char **port_nexus_ptr)
+{
+	/*
+	 * Assume the FORMAT CODE 00b from spc4r17, 7.5.4.4 TransportID
+	 * for initiator ports using SCSI over SBP Serial SCSI Protocol
+	 *
+	 * The TransportID for a IEEE 1394 Initiator Port is of fixed size of
+	 * 24 bytes, and IEEE 1394 does not contain a I_T nexus identifier,
+	 * so we return the **port_nexus_ptr set to NULL.
+	 */
+	*port_nexus_ptr = NULL;
+	*out_tid_len = 24;
+
+	return (char *)&buf[8];
+}
diff --git a/drivers/target/sbp/sbp_fabric.h b/drivers/target/sbp/sbp_fabric.h
new file mode 100644
index 0000000..cf66eca
--- /dev/null
+++ b/drivers/target/sbp/sbp_fabric.h
@@ -0,0 +1,40 @@
+
+#include <linux/types.h>
+#include <target/target_core_base.h>
+
+int sbp_check_true(struct se_portal_group *);
+int sbp_check_false(struct se_portal_group *);
+char *sbp_get_fabric_name(void);
+char *sbp_get_fabric_wwn(struct se_portal_group *);
+u16 sbp_get_tag(struct se_portal_group *);
+u32 sbp_get_default_depth(struct se_portal_group *);
+struct se_node_acl *sbp_alloc_fabric_acl(struct se_portal_group *);
+void sbp_release_fabric_acl(struct se_portal_group *,
+		struct se_node_acl *);
+u32 sbp_tpg_get_inst_index(struct se_portal_group *);
+void sbp_release_cmd(struct se_cmd *se_cmd);
+int sbp_shutdown_session(struct se_session *);
+void sbp_close_session(struct se_session *);
+u32 sbp_sess_get_index(struct se_session *);
+int sbp_write_pending(struct se_cmd *);
+int sbp_write_pending_status(struct se_cmd *);
+void sbp_set_default_node_attrs(struct se_node_acl *);
+u32 sbp_get_task_tag(struct se_cmd *);
+int sbp_get_cmd_state(struct se_cmd *);
+int sbp_queue_data_in(struct se_cmd *);
+int sbp_queue_status(struct se_cmd *);
+int sbp_queue_tm_rsp(struct se_cmd *);
+u16 sbp_set_fabric_sense_len(struct se_cmd *, u32);
+u16 sbp_get_fabric_sense_len(void);
+int sbp_check_stop_free(struct se_cmd *se_cmd);
+
+u8 sbp_get_fabric_proto_ident(struct se_portal_group *se_tpg);
+u32 sbp_get_pr_transport_id(struct se_portal_group *se_tpg,
+		struct se_node_acl *se_nacl, struct t10_pr_registration *pr_reg,
+		int *format_code, unsigned char *buf);
+u32 sbp_get_pr_transport_id_len(
+		struct se_portal_group *se_tpg, struct se_node_acl *se_nacl,
+		struct t10_pr_registration *pr_reg, int *format_code);
+char *sbp_parse_pr_out_transport_id(
+		struct se_portal_group *se_tpg, const char *buf,
+		u32 *out_tid_len, char **port_nexus_ptr);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 07/11] firewire-sbp-target: Add sbp_management_agent.{c,h}
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (5 preceding siblings ...)
  2012-04-11 14:20       ` [PATCH 06/11] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-11 14:20       ` [PATCH 08/11] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
                         ` (5 subsequent siblings)
  12 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This code implements the SBP-2 Management Agent. This is the first of
two firewire address handlers that are used to communicate with the
target. The Management Agent is used to handle login, reconnect and
logout to a SCSI LUN as well as task management functions.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_management_agent.c |  255 +++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_management_agent.h |   34 ++++
 2 files changed, 289 insertions(+)
 create mode 100644 drivers/target/sbp/sbp_management_agent.c
 create mode 100644 drivers/target/sbp/sbp_management_agent.h

diff --git a/drivers/target/sbp/sbp_management_agent.c b/drivers/target/sbp/sbp_management_agent.c
new file mode 100644
index 0000000..71f7b2f
--- /dev/null
+++ b/drivers/target/sbp/sbp_management_agent.c
@@ -0,0 +1,255 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/kref.h>
+
+#include <target/target_core_base.h>
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+#include "sbp_login.h"
+#include "sbp_scsi_cmnd.h"
+
+static void sbp_mgt_agent_process(struct work_struct *work)
+{
+	struct sbp_management_agent *agent =
+		container_of(work, struct sbp_management_agent, work);
+	struct sbp_management_request *req = agent->request;
+	int ret;
+	int status_data_len = 0;
+
+	/* fetch the ORB from the initiator */
+	ret = sbp_run_transaction(req->card, TCODE_READ_BLOCK_REQUEST,
+		req->node_addr, req->generation, req->speed,
+		agent->orb_offset, &req->orb, sizeof(req->orb));
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("mgt_orb fetch failed: %x\n", ret);
+		goto out;
+	}
+
+	pr_debug("mgt_orb ptr1:0x%llx ptr2:0x%llx misc:0x%x len:0x%x status_fifo:0x%llx\n",
+		sbp2_pointer_to_addr(&req->orb.ptr1),
+		sbp2_pointer_to_addr(&req->orb.ptr2),
+		be32_to_cpu(req->orb.misc), be32_to_cpu(req->orb.length),
+		sbp2_pointer_to_addr(&req->orb.status_fifo));
+
+	if (!ORB_NOTIFY(be32_to_cpu(req->orb.misc)) ||
+		ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc)) != 0) {
+		pr_err("mgt_orb bad request\n");
+		goto out;
+	}
+
+	switch (MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc))) {
+	case MANAGEMENT_ORB_FUNCTION_LOGIN:
+		sbp_management_request_login(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_QUERY_LOGINS:
+		sbp_management_request_query_logins(agent, req,
+				&status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_RECONNECT:
+		sbp_management_request_reconnect(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_SET_PASSWORD:
+		pr_notice("SET PASSWORD not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_LOGOUT:
+		sbp_management_request_logout(agent, req, &status_data_len);
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_ABORT_TASK:
+		pr_notice("ABORT TASK not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_ABORT_TASK_SET:
+		pr_notice("ABORT TASK SET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_LOGICAL_UNIT_RESET:
+		pr_notice("LOGICAL UNIT RESET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	case MANAGEMENT_ORB_FUNCTION_TARGET_RESET:
+		pr_notice("TARGET RESET not implemented\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+
+	default:
+		pr_notice("unknown management function 0x%x\n",
+			MANAGEMENT_ORB_FUNCTION(be32_to_cpu(req->orb.misc)));
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+
+		break;
+	}
+
+	req->status.status |= cpu_to_be32(
+		STATUS_BLOCK_SRC(1) | /* Response to ORB, next_ORB absent */
+		STATUS_BLOCK_LEN(DIV_ROUND_UP(status_data_len, 4) + 1) |
+		STATUS_BLOCK_ORB_OFFSET_HIGH(agent->orb_offset >> 32));
+	req->status.orb_low = cpu_to_be32(agent->orb_offset);
+
+	/* write the status block back to the initiator */
+	ret = sbp_run_transaction(req->card, TCODE_WRITE_BLOCK_REQUEST,
+		req->node_addr, req->generation, req->speed,
+		sbp2_pointer_to_addr(&req->orb.status_fifo),
+		&req->status, 8 + status_data_len);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("mgt_orb status write failed: %x\n", ret);
+		goto out;
+	}
+
+out:
+	fw_card_put(req->card);
+	kfree(req);
+
+	spin_lock_bh(&agent->lock);
+	agent->state = MANAGEMENT_AGENT_STATE_IDLE;
+	spin_unlock_bh(&agent->lock);
+}
+
+static void sbp_mgt_agent_rw(struct fw_card *card,
+	struct fw_request *request, int tcode, int destination, int source,
+	int generation, unsigned long long offset, void *data, size_t length,
+	void *callback_data)
+{
+	struct sbp_management_agent *agent = callback_data;
+	struct sbp2_pointer *ptr = data;
+	int rcode = RCODE_ADDRESS_ERROR;
+
+	if (!agent->tport->enable)
+		goto out;
+
+	if ((offset != agent->handler.offset) || (length != 8))
+		goto out;
+
+	if (tcode == TCODE_WRITE_BLOCK_REQUEST) {
+		struct sbp_management_request *req;
+		int prev_state;
+
+		spin_lock_bh(&agent->lock);
+		prev_state = agent->state;
+		agent->state = MANAGEMENT_AGENT_STATE_BUSY;
+		spin_unlock_bh(&agent->lock);
+
+		if (prev_state == MANAGEMENT_AGENT_STATE_BUSY) {
+			pr_notice("ignoring management request while busy\n");
+			rcode = RCODE_CONFLICT_ERROR;
+			goto out;
+		}
+
+		req = kzalloc(sizeof(*req), GFP_ATOMIC);
+		if (!req) {
+			rcode = RCODE_CONFLICT_ERROR;
+			goto out;
+		}
+
+		req->card = fw_card_get(card);
+		req->generation = generation;
+		req->node_addr = source;
+		req->speed = fw_get_request_speed(request);
+
+		agent->orb_offset = sbp2_pointer_to_addr(ptr);
+		agent->request = req;
+
+		queue_work(system_unbound_wq, &agent->work);
+		rcode = RCODE_COMPLETE;
+	} else if (tcode == TCODE_READ_BLOCK_REQUEST) {
+		addr_to_sbp2_pointer(agent->orb_offset, ptr);
+		rcode = RCODE_COMPLETE;
+	} else {
+		rcode = RCODE_TYPE_ERROR;
+	}
+
+out:
+	fw_send_response(card, request, rcode);
+}
+
+struct sbp_management_agent *sbp_management_agent_register(
+		struct sbp_tport *tport)
+{
+	int ret;
+	struct sbp_management_agent *agent;
+
+	agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+	if (!agent)
+		return ERR_PTR(-ENOMEM);
+
+	spin_lock_init(&agent->lock);
+	agent->tport = tport;
+	agent->handler.length = 0x08;
+	agent->handler.address_callback = sbp_mgt_agent_rw;
+	agent->handler.callback_data = agent;
+	agent->state = MANAGEMENT_AGENT_STATE_IDLE;
+	INIT_WORK(&agent->work, sbp_mgt_agent_process);
+	agent->orb_offset = 0;
+	agent->request = NULL;
+
+	ret = fw_core_add_address_handler(&agent->handler,
+			&sbp_register_region);
+	if (ret < 0) {
+		kfree(agent);
+		return ERR_PTR(ret);
+	}
+
+	return agent;
+}
+
+void sbp_management_agent_unregister(struct sbp_management_agent *agent)
+{
+	fw_core_remove_address_handler(&agent->handler);
+	cancel_work_sync(&agent->work);
+	kfree(agent);
+}
diff --git a/drivers/target/sbp/sbp_management_agent.h b/drivers/target/sbp/sbp_management_agent.h
new file mode 100644
index 0000000..73237ae
--- /dev/null
+++ b/drivers/target/sbp/sbp_management_agent.h
@@ -0,0 +1,34 @@
+#ifndef _SBP_MANAGEMENT_AGENT_H
+#define _SBP_MANAGEMENT_AGENT_H
+
+#include <linux/types.h>
+#include <linux/firewire.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#include "sbp_base.h"
+
+struct sbp_management_agent {
+	spinlock_t lock;
+	struct sbp_tport *tport;
+	struct fw_address_handler handler;
+	int state;
+	struct work_struct work;
+	u64 orb_offset;
+	struct sbp_management_request *request;
+};
+
+struct sbp_management_request {
+	struct sbp_management_orb orb;
+	struct sbp_status_block status;
+	struct fw_card *card;
+	int generation;
+	int node_addr;
+	int speed;
+};
+
+struct sbp_management_agent *sbp_management_agent_register(
+		struct sbp_tport *tport);
+void sbp_management_agent_unregister(struct sbp_management_agent *agent);
+
+#endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 08/11] firewire-sbp-target: Add sbp_login.{c,h}
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (6 preceding siblings ...)
  2012-04-11 14:20       ` [PATCH 07/11] firewire-sbp-target: Add sbp_management_agent.{c,h} Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-14 10:17         ` Stefan Richter
  2012-04-11 14:20       ` [PATCH 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
                         ` (4 subsequent siblings)
  12 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This file contains the implementation of the login, reconnect and logout
management ORBs in SBP-2.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_login.c |  672 ++++++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_login.h |   17 +
 2 files changed, 689 insertions(+)
 create mode 100644 drivers/target/sbp/sbp_login.c
 create mode 100644 drivers/target/sbp/sbp_login.h

diff --git a/drivers/target/sbp/sbp_login.c b/drivers/target/sbp/sbp_login.c
new file mode 100644
index 0000000..bbcc618
--- /dev/null
+++ b/drivers/target/sbp/sbp_login.c
@@ -0,0 +1,672 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kref.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/slab.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+#include "sbp_login.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+
+#define SESSION_MAINTENANCE_INTERVAL HZ
+
+static atomic_t login_id = ATOMIC_INIT(0);
+
+static void session_maintenance_work(struct work_struct *work);
+
+static int read_peer_guid(u64 *guid, const struct sbp_management_request *req)
+{
+	int ret;
+	__be32 high, low;
+
+	ret = sbp_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+			req->node_addr, req->generation, req->speed,
+			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 3 * 4,
+			&high, sizeof(high));
+	if (ret != RCODE_COMPLETE)
+		return ret;
+
+	ret = sbp_run_transaction(req->card, TCODE_READ_QUADLET_REQUEST,
+			req->node_addr, req->generation, req->speed,
+			(CSR_REGISTER_BASE | CSR_CONFIG_ROM) + 4 * 4,
+			&low, sizeof(low));
+	if (ret != RCODE_COMPLETE)
+		return ret;
+
+	*guid = (u64)be32_to_cpu(high) << 32 | be32_to_cpu(low);
+
+	return RCODE_COMPLETE;
+}
+
+static struct sbp_session *sbp_session_find_by_guid(
+	struct sbp_tpg *tpg, u64 guid)
+{
+	struct se_session *se_sess;
+	struct sbp_session *sess, *found = NULL;
+
+	spin_lock_bh(&tpg->se_tpg.session_lock);
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		sess = se_sess->fabric_sess_ptr;
+		if (sess->guid == guid)
+			found = sess;
+	}
+	spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+	return found;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_lun(
+		struct sbp_session *session, struct se_lun *lun)
+{
+	struct sbp_login_descriptor *login, *found = NULL;
+
+	spin_lock_bh(&session->lock);
+	list_for_each_entry(login, &session->login_list, link) {
+		if (login->lun == lun)
+			found = login;
+	}
+	spin_unlock_bh(&session->lock);
+
+	return found;
+}
+
+static int sbp_login_count_all_by_lun(
+		struct sbp_tpg *tpg,
+		struct se_lun *lun,
+		int exclusive)
+{
+	struct se_session *se_sess;
+	struct sbp_session *sess;
+	struct sbp_login_descriptor *login;
+	int count = 0;
+
+	spin_lock_bh(&tpg->se_tpg.session_lock);
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		sess = se_sess->fabric_sess_ptr;
+
+		spin_lock_bh(&sess->lock);
+		list_for_each_entry(login, &sess->login_list, link) {
+			if (login->lun != lun)
+				continue;
+
+			if (!exclusive || login->exclusive)
+				count++;
+		}
+		spin_unlock_bh(&sess->lock);
+	}
+	spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+	return count;
+}
+
+static struct sbp_login_descriptor *sbp_login_find_by_id(
+	struct sbp_tpg *tpg, int login_id)
+{
+	struct se_session *se_sess;
+	struct sbp_session *sess;
+	struct sbp_login_descriptor *login, *found = NULL;
+
+	spin_lock_bh(&tpg->se_tpg.session_lock);
+	list_for_each_entry(se_sess, &tpg->se_tpg.tpg_sess_list, sess_list) {
+		sess = se_sess->fabric_sess_ptr;
+
+		spin_lock_bh(&sess->lock);
+		list_for_each_entry(login, &sess->login_list, link) {
+			if (login->login_id == login_id)
+				found = login;
+		}
+		spin_unlock_bh(&sess->lock);
+	}
+	spin_unlock_bh(&tpg->se_tpg.session_lock);
+
+	return found;
+}
+
+static struct se_lun *sbp_get_lun_from_tpg(struct sbp_tpg *tpg, int lun)
+{
+	struct se_portal_group *se_tpg = &tpg->se_tpg;
+	struct se_lun *se_lun;
+
+	if (lun >= TRANSPORT_MAX_LUNS_PER_TPG)
+		return ERR_PTR(-EINVAL);
+
+	spin_lock(&se_tpg->tpg_lun_lock);
+	se_lun = se_tpg->tpg_lun_list[lun];
+
+	if (se_lun->lun_status != TRANSPORT_LUN_STATUS_ACTIVE)
+		se_lun = ERR_PTR(-ENODEV);
+
+	spin_unlock(&se_tpg->tpg_lun_lock);
+
+	return se_lun;
+}
+
+static struct sbp_session *sbp_session_create(
+		struct sbp_tpg *tpg,
+		u64 guid)
+{
+	struct sbp_session *sess;
+	int ret;
+	char guid_str[17];
+	struct se_node_acl *se_nacl;
+
+	sess = kmalloc(sizeof(*sess), GFP_KERNEL);
+	if (!sess) {
+		pr_err("failed to allocate session descriptor\n");
+		return ERR_PTR(-ENOMEM);
+	}
+
+	sess->se_sess = transport_init_session();
+	if (IS_ERR(sess->se_sess)) {
+		pr_err("failed to init se_session\n");
+
+		ret = PTR_ERR(sess->se_sess);
+		kfree(sess);
+		return ERR_PTR(ret);
+	}
+
+	snprintf(guid_str, sizeof(guid_str), "%016llx", guid);
+
+	se_nacl = core_tpg_check_initiator_node_acl(&tpg->se_tpg, guid_str);
+	if (!se_nacl) {
+		pr_warn("Node ACL not found for %s\n", guid_str);
+
+		transport_free_session(sess->se_sess);
+		kfree(sess);
+
+		return ERR_PTR(-EPERM);
+	}
+
+	sess->se_sess->se_node_acl = se_nacl;
+
+	spin_lock_init(&sess->lock);
+	INIT_LIST_HEAD(&sess->login_list);
+	INIT_DELAYED_WORK(&sess->maint_work, session_maintenance_work);
+
+	sess->guid = guid;
+
+	transport_register_session(&tpg->se_tpg, se_nacl, sess->se_sess, sess);
+
+	return sess;
+}
+
+static void sbp_session_release(struct sbp_session *sess, bool cancel_work)
+{
+	spin_lock_bh(&sess->lock);
+	if (!list_empty(&sess->login_list)) {
+		spin_unlock_bh(&sess->lock);
+		return;
+	}
+	spin_unlock_bh(&sess->lock);
+
+	if (cancel_work)
+		cancel_delayed_work_sync(&sess->maint_work);
+
+	transport_deregister_session_configfs(sess->se_sess);
+	transport_deregister_session(sess->se_sess);
+
+	if (sess->card)
+		fw_card_put(sess->card);
+
+	kfree(sess);
+}
+
+static void sbp_login_release(struct sbp_login_descriptor *login,
+	bool cancel_work)
+{
+	struct sbp_session *sess = login->sess;
+
+	/* FIXME: abort/wait on tasks */
+
+	sbp_target_agent_unregister(login->tgt_agt);
+
+	if (sess) {
+		spin_lock_bh(&sess->lock);
+		list_del(&login->link);
+		spin_unlock_bh(&sess->lock);
+
+		sbp_session_release(sess, cancel_work);
+	}
+
+	kfree(login);
+}
+
+void sbp_management_request_login(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	struct se_lun *se_lun;
+	int ret;
+	u64 guid;
+	struct sbp_session *sess;
+	struct sbp_login_descriptor *login;
+	struct sbp_login_response_block *response;
+	int login_response_len;
+
+	se_lun = sbp_get_lun_from_tpg(tpg,
+			LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+	if (IS_ERR(se_lun)) {
+		pr_notice("login to unknown LUN: %d\n",
+			LOGIN_ORB_LUN(be32_to_cpu(req->orb.misc)));
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LUN_NOTSUPP));
+		return;
+	}
+
+	ret = read_peer_guid(&guid, req);
+	if (ret != RCODE_COMPLETE) {
+		pr_warn("failed to read peer GUID: %d\n", ret);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	pr_notice("mgt_agent LOGIN to LUN %d from %016llx\n",
+		se_lun->unpacked_lun, guid);
+
+	sess = sbp_session_find_by_guid(tpg, guid);
+	if (sess) {
+		login = sbp_login_find_by_lun(sess, se_lun);
+		if (login) {
+			pr_notice("initiator already logged-in\n");
+
+			/*
+			 * SBP-2 R4 says we should return access denied, but
+			 * that can confuse initiators. Instead we need to
+			 * treat this like a reconnect, but send the login
+			 * response block like a fresh login.
+			 *
+			 * This is required particularly in the case of Apple
+			 * devices booting off the FireWire target, where
+			 * the firmware has an active login to the target. When
+			 * the OS takes control of the session it issues its own
+			 * LOGIN rather than a RECONNECT. To avoid the machine
+			 * waiting until the reconnect_hold expires, we can skip
+			 * the ACCESS_DENIED errors to speed things up.
+			 */
+
+			goto already_logged_in;
+		}
+	}
+
+	/*
+	 * check exclusive bit in login request
+	 * reject with access_denied if any logins present
+	 */
+	if (LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc)) &&
+			sbp_login_count_all_by_lun(tpg, se_lun, 0)) {
+		pr_warn("refusing exclusive login with other active logins\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	/*
+	 * check exclusive bit in any existing login descriptor
+	 * reject with access_denied if any exclusive logins present
+	 */
+	if (sbp_login_count_all_by_lun(tpg, se_lun, 1)) {
+		pr_warn("refusing login while another exclusive login present\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	/*
+	 * check we haven't exceeded the number of allowed logins
+	 * reject with resources_unavailable if we have
+	 */
+	if (sbp_login_count_all_by_lun(tpg, se_lun, 0) >=
+			tport->max_logins_per_lun) {
+		pr_warn("max number of logins reached\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	if (!sess) {
+		sess = sbp_session_create(tpg, guid);
+		if (IS_ERR(sess)) {
+			switch (PTR_ERR(sess)) {
+			case -EPERM:
+				ret = SBP_STATUS_ACCESS_DENIED;
+				break;
+			default:
+				ret = SBP_STATUS_RESOURCES_UNAVAIL;
+				break;
+			}
+
+			req->status.status = cpu_to_be32(
+				STATUS_BLOCK_RESP(
+					STATUS_RESP_REQUEST_COMPLETE) |
+				STATUS_BLOCK_SBP_STATUS(ret));
+			return;
+		}
+
+		sess->node_id = req->node_addr;
+		sess->card = fw_card_get(req->card);
+		sess->generation = req->generation;
+		sess->speed = req->speed;
+
+		schedule_delayed_work(&sess->maint_work,
+				SESSION_MAINTENANCE_INTERVAL);
+	}
+
+	/* only take the latest reconnect_hold into account */
+	sess->reconnect_hold = min(
+		1 << LOGIN_ORB_RECONNECT(be32_to_cpu(req->orb.misc)),
+		tport->max_reconnect_timeout) - 1;
+
+	login = kmalloc(sizeof(*login), GFP_KERNEL);
+	if (!login) {
+		pr_err("failed to allocate login descriptor\n");
+
+		sbp_session_release(sess, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	login->sess = sess;
+	login->lun = se_lun;
+	login->status_fifo_addr = sbp2_pointer_to_addr(&req->orb.status_fifo);
+	login->exclusive = LOGIN_ORB_EXCLUSIVE(be32_to_cpu(req->orb.misc));
+	login->login_id = atomic_inc_return(&login_id);
+
+	login->tgt_agt = sbp_target_agent_register(login);
+	if (IS_ERR(login->tgt_agt)) {
+		ret = PTR_ERR(login->tgt_agt);
+		pr_err("failed to map command block handler: %d\n", ret);
+
+		sbp_session_release(sess, true);
+		kfree(login);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	spin_lock_bh(&sess->lock);
+	list_add_tail(&login->link, &sess->login_list);
+	spin_unlock_bh(&sess->lock);
+
+already_logged_in:
+	response = kzalloc(sizeof(*response), GFP_KERNEL);
+	if (!response) {
+		pr_err("failed to allocate login response block\n");
+
+		sbp_login_release(login, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_RESOURCES_UNAVAIL));
+		return;
+	}
+
+	login_response_len = clamp_val(
+			LOGIN_ORB_RESPONSE_LENGTH(be32_to_cpu(req->orb.length)),
+			12, sizeof(*response));
+	response->misc = cpu_to_be32(
+		((login_response_len & 0xffff) << 16) |
+		(login->login_id & 0xffff));
+	response->reconnect_hold = cpu_to_be32(sess->reconnect_hold & 0xffff);
+	addr_to_sbp2_pointer(login->tgt_agt->handler.offset,
+		&response->command_block_agent);
+
+	ret = sbp_run_transaction(sess->card, TCODE_WRITE_BLOCK_REQUEST,
+		sess->node_id, sess->generation, sess->speed,
+		sbp2_pointer_to_addr(&req->orb.ptr2), response,
+		login_response_len);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("failed to write login response block: %x\n", ret);
+
+		kfree(response);
+		sbp_login_release(login, true);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	kfree(response);
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+void sbp_management_request_query_logins(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	pr_notice("QUERY LOGINS not implemented\n");
+	/* FIXME: implement */
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQ_TYPE_NOTSUPP));
+}
+
+void sbp_management_request_reconnect(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	int ret;
+	u64 guid;
+	struct sbp_login_descriptor *login;
+
+	ret = read_peer_guid(&guid, req);
+	if (ret != RCODE_COMPLETE) {
+		pr_warn("failed to read peer GUID: %d\n", ret);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		return;
+	}
+
+	pr_notice("mgt_agent RECONNECT from %016llx\n", guid);
+
+	login = sbp_login_find_by_id(tpg,
+		RECONNECT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc)));
+
+	if (!login) {
+		pr_err("mgt_agent RECONNECT unknown login ID\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	if (login->sess->guid != guid) {
+		pr_err("mgt_agent RECONNECT login GUID doesn't match\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	spin_lock_bh(&login->sess->lock);
+	if (login->sess->card)
+		fw_card_put(login->sess->card);
+
+	/* update the node details */
+	login->sess->generation = req->generation;
+	login->sess->node_id = req->node_addr;
+	login->sess->card = fw_card_get(req->card);
+	login->sess->speed = req->speed;
+	spin_unlock_bh(&login->sess->lock);
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+void sbp_management_request_logout(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size)
+{
+	struct sbp_tport *tport = agent->tport;
+	struct sbp_tpg *tpg = tport->tpg;
+	int login_id;
+	struct sbp_login_descriptor *login;
+
+	login_id = LOGOUT_ORB_LOGIN_ID(be32_to_cpu(req->orb.misc));
+
+	login = sbp_login_find_by_id(tpg, login_id);
+	if (!login) {
+		pr_warn("cannot find login: %d\n", login_id);
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_LOGIN_ID_UNKNOWN));
+		return;
+	}
+
+	pr_info("mgt_agent LOGOUT from LUN %d session %d\n",
+		login->lun->unpacked_lun, login->login_id);
+
+	if (req->node_addr != login->sess->node_id) {
+		pr_warn("logout from different node ID\n");
+
+		req->status.status = cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_ACCESS_DENIED));
+		return;
+	}
+
+	sbp_login_release(login, true);
+
+	req->status.status = cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+static void session_check_for_reset(struct sbp_session *sess)
+{
+	bool card_valid = false;
+
+	spin_lock_bh(&sess->lock);
+
+	if (sess->card) {
+		spin_lock_irq(&sess->card->lock);
+		card_valid = (sess->card->local_node != NULL);
+		spin_unlock_irq(&sess->card->lock);
+
+		if (!card_valid) {
+			fw_card_put(sess->card);
+			sess->card = NULL;
+		}
+	}
+
+	if (!card_valid || (sess->generation != sess->card->generation)) {
+		pr_info("Waiting for reconnect from node: %016llx\n",
+				sess->guid);
+
+		sess->node_id = -1;
+		sess->reconnect_expires = get_jiffies_64() +
+			((sess->reconnect_hold + 1) * HZ);
+	}
+
+	spin_unlock_bh(&sess->lock);
+}
+
+static void session_reconnect_expired(struct sbp_session *sess)
+{
+	struct sbp_login_descriptor *login, *temp;
+	LIST_HEAD(login_list);
+
+	pr_info("Reconnect timer expired for node: %016llx\n", sess->guid);
+
+	spin_lock_bh(&sess->lock);
+	list_for_each_entry_safe(login, temp, &sess->login_list, link) {
+		login->sess = NULL;
+		list_del(&login->link);
+		list_add_tail(&login->link, &login_list);
+	}
+	spin_unlock_bh(&sess->lock);
+
+	list_for_each_entry_safe(login, temp, &login_list, link) {
+		list_del(&login->link);
+		sbp_login_release(login, false);
+	}
+
+	sbp_session_release(sess, false);
+}
+
+static void session_maintenance_work(struct work_struct *work)
+{
+	struct sbp_session *sess = container_of(work, struct sbp_session,
+			maint_work.work);
+
+	/* could be called while tearing down the session */
+	spin_lock_bh(&sess->lock);
+	if (list_empty(&sess->login_list)) {
+		spin_unlock_bh(&sess->lock);
+		return;
+	}
+	spin_unlock_bh(&sess->lock);
+
+	if (sess->node_id != -1) {
+		/* check for bus reset and make node_id invalid */
+		session_check_for_reset(sess);
+
+		schedule_delayed_work(&sess->maint_work,
+				SESSION_MAINTENANCE_INTERVAL);
+	} else if (!time_after64(get_jiffies_64(), sess->reconnect_expires)) {
+		/* still waiting for reconnect */
+		schedule_delayed_work(&sess->maint_work,
+				SESSION_MAINTENANCE_INTERVAL);
+	} else {
+		/* reconnect timeout has expired */
+		session_reconnect_expired(sess);
+	}
+}
+
diff --git a/drivers/target/sbp/sbp_login.h b/drivers/target/sbp/sbp_login.h
new file mode 100644
index 0000000..3b016f0
--- /dev/null
+++ b/drivers/target/sbp/sbp_login.h
@@ -0,0 +1,17 @@
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+
+extern void sbp_management_request_login(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+extern void sbp_management_request_query_logins(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+extern void sbp_management_request_reconnect(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+extern void sbp_management_request_logout(
+	struct sbp_management_agent *agent, struct sbp_management_request *req,
+	int *status_data_size);
+
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h}
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (7 preceding siblings ...)
  2012-04-11 14:20       ` [PATCH 08/11] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-14 10:49         ` Stefan Richter
  2012-04-11 14:20       ` [PATCH 10/11] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h} Chris Boot
                         ` (3 subsequent siblings)
  12 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This implements the SBP-2 Command Block Agent, or Target Agent. This is
what receives SCSI commands and forwards them to the target framework.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_target_agent.c |  395 +++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_target_agent.h |   40 ++++
 2 files changed, 435 insertions(+)
 create mode 100644 drivers/target/sbp/sbp_target_agent.c
 create mode 100644 drivers/target/sbp/sbp_target_agent.h

diff --git a/drivers/target/sbp/sbp_target_agent.c b/drivers/target/sbp/sbp_target_agent.c
new file mode 100644
index 0000000..5fdd401
--- /dev/null
+++ b/drivers/target/sbp/sbp_target_agent.c
@@ -0,0 +1,395 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/slab.h>
+
+#include <target/target_core_base.h>
+
+#include "sbp_base.h"
+#include "sbp_management_agent.h"
+#include "sbp_login.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+
+static int tgt_agent_rw_agent_state(struct fw_card *card, int tcode, void *data,
+		struct sbp_target_agent *agent)
+{
+	__be32 state;
+
+	switch (tcode) {
+	case TCODE_READ_QUADLET_REQUEST:
+		pr_debug("tgt_agent AGENT_STATE READ\n");
+
+		spin_lock_bh(&agent->lock);
+		state = cpu_to_be32(agent->state);
+		spin_unlock_bh(&agent->lock);
+		memcpy(data, &state, sizeof(state));
+
+		return RCODE_COMPLETE;
+
+	case TCODE_WRITE_QUADLET_REQUEST:
+		/* ignored */
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_agent_reset(struct fw_card *card, int tcode, void *data,
+		struct sbp_target_agent *agent)
+{
+	switch (tcode) {
+	case TCODE_WRITE_QUADLET_REQUEST:
+		pr_debug("tgt_agent AGENT_RESET\n");
+		spin_lock_bh(&agent->lock);
+		agent->state = AGENT_STATE_RESET;
+		spin_unlock_bh(&agent->lock);
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_orb_pointer(struct fw_card *card, int tcode, void *data,
+		struct sbp_target_agent *agent)
+{
+	struct sbp2_pointer *ptr = data;
+
+	switch (tcode) {
+	case TCODE_WRITE_BLOCK_REQUEST:
+		spin_lock_bh(&agent->lock);
+		if (agent->state != AGENT_STATE_SUSPENDED &&
+				agent->state != AGENT_STATE_RESET) {
+			spin_unlock_bh(&agent->lock);
+			pr_notice("Ignoring ORB_POINTER write while active.\n");
+			return RCODE_CONFLICT_ERROR;
+		}
+		agent->state = AGENT_STATE_ACTIVE;
+		spin_unlock_bh(&agent->lock);
+
+		agent->orb_pointer = sbp2_pointer_to_addr(ptr);
+		agent->doorbell = false;
+
+		pr_debug("tgt_agent ORB_POINTER write: 0x%llx\n",
+				agent->orb_pointer);
+
+		queue_work(system_unbound_wq, &agent->work);
+
+		return RCODE_COMPLETE;
+
+	case TCODE_READ_BLOCK_REQUEST:
+		pr_debug("tgt_agent ORB_POINTER READ\n");
+		spin_lock_bh(&agent->lock);
+		addr_to_sbp2_pointer(agent->orb_pointer, ptr);
+		spin_unlock_bh(&agent->lock);
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_doorbell(struct fw_card *card, int tcode, void *data,
+		struct sbp_target_agent *agent)
+{
+	switch (tcode) {
+	case TCODE_WRITE_QUADLET_REQUEST:
+		spin_lock_bh(&agent->lock);
+		if (agent->state != AGENT_STATE_SUSPENDED) {
+			spin_unlock_bh(&agent->lock);
+			pr_debug("Ignoring DOORBELL while active.\n");
+			return RCODE_CONFLICT_ERROR;
+		}
+		agent->state = AGENT_STATE_ACTIVE;
+		spin_unlock_bh(&agent->lock);
+
+		agent->doorbell = true;
+
+		pr_debug("tgt_agent DOORBELL\n");
+
+		queue_work(system_unbound_wq, &agent->work);
+
+		return RCODE_COMPLETE;
+
+	case TCODE_READ_QUADLET_REQUEST:
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static int tgt_agent_rw_unsolicited_status_enable(struct fw_card *card,
+		int tcode, void *data, struct sbp_target_agent *agent)
+{
+	switch (tcode) {
+	case TCODE_WRITE_QUADLET_REQUEST:
+		pr_debug("tgt_agent UNSOLICITED_STATUS_ENABLE\n");
+		/* ignored as we don't send unsolicited status */
+		return RCODE_COMPLETE;
+
+	case TCODE_READ_QUADLET_REQUEST:
+		return RCODE_COMPLETE;
+
+	default:
+		return RCODE_TYPE_ERROR;
+	}
+}
+
+static void tgt_agent_rw(struct fw_card *card, struct fw_request *request,
+		int tcode, int destination, int source, int generation,
+		unsigned long long offset, void *data, size_t length,
+		void *callback_data)
+{
+	struct sbp_target_agent *agent = callback_data;
+	struct sbp_session *sess = agent->login->sess;
+	int sess_gen, sess_node, rcode;
+
+	spin_lock_bh(&sess->lock);
+	sess_gen = sess->generation;
+	sess_node = sess->node_id;
+	spin_unlock_bh(&sess->lock);
+
+	if (generation != sess_gen) {
+		pr_notice("ignoring request with wrong generation\n");
+		rcode = RCODE_TYPE_ERROR;
+		goto out;
+	}
+
+	if (source != sess_node) {
+		pr_notice("ignoring request from foreign node (%x != %x)\n",
+				source, sess_node);
+		rcode = RCODE_TYPE_ERROR;
+		goto out;
+	}
+
+	/* turn offset into the offset from the start of the block */
+	offset -= agent->handler.offset;
+
+	if (offset == 0x00 && length == 4) {
+		/* AGENT_STATE */
+		rcode = tgt_agent_rw_agent_state(card, tcode, data, agent);
+	} else if (offset == 0x04 && length == 4) {
+		/* AGENT_RESET */
+		rcode = tgt_agent_rw_agent_reset(card, tcode, data, agent);
+	} else if (offset == 0x08 && length == 8) {
+		/* ORB_POINTER */
+		rcode = tgt_agent_rw_orb_pointer(card, tcode, data, agent);
+	} else if (offset == 0x10 && length == 4) {
+		/* DOORBELL */
+		rcode = tgt_agent_rw_doorbell(card, tcode, data, agent);
+	} else if (offset == 0x14 && length == 4) {
+		/* UNSOLICITED_STATUS_ENABLE */
+		rcode = tgt_agent_rw_unsolicited_status_enable(card, tcode,
+				data, agent);
+	} else {
+		rcode = RCODE_ADDRESS_ERROR;
+	}
+
+out:
+	fw_send_response(card, request, rcode);
+}
+
+static void tgt_agent_process_work(struct work_struct *work)
+{
+	struct sbp_target_request *req =
+		container_of(work, struct sbp_target_request, work);
+
+	pr_debug("tgt_orb ptr:0x%llx next_ORB:0x%llx data_descriptor:0x%llx misc:0x%x\n",
+			req->orb_pointer,
+			sbp2_pointer_to_addr(&req->orb.next_orb),
+			sbp2_pointer_to_addr(&req->orb.data_descriptor),
+			be32_to_cpu(req->orb.misc));
+
+	if (req->orb_pointer >> 32)
+		pr_debug("ORB with high bits set\n");
+
+	switch (ORB_REQUEST_FORMAT(be32_to_cpu(req->orb.misc))) {
+		case 0:/* Format specified by this standard */
+			sbp_handle_command(req);
+			return;
+		case 1: /* Reserved for future standardization */
+		case 2: /* Vendor-dependent */
+			req->status.status |= cpu_to_be32(
+					STATUS_BLOCK_RESP(
+						STATUS_RESP_REQUEST_COMPLETE) |
+					STATUS_BLOCK_DEAD(0) |
+					STATUS_BLOCK_LEN(1) |
+					STATUS_BLOCK_SBP_STATUS(
+						SBP_STATUS_REQ_TYPE_NOTSUPP));
+			sbp_send_status(req);
+			sbp_free_request(req);
+			return;
+		case 3: /* Dummy ORB */
+			req->status.status |= cpu_to_be32(
+					STATUS_BLOCK_RESP(
+						STATUS_RESP_REQUEST_COMPLETE) |
+					STATUS_BLOCK_DEAD(0) |
+					STATUS_BLOCK_LEN(1) |
+					STATUS_BLOCK_SBP_STATUS(
+						SBP_STATUS_DUMMY_ORB_COMPLETE));
+			sbp_send_status(req);
+			sbp_free_request(req);
+			return;
+		default:
+			BUG();
+	}
+}
+
+/* used to double-check we haven't been issued an AGENT_RESET */
+static inline bool tgt_agent_check_active(struct sbp_target_agent *agent)
+{
+	bool active;
+
+	spin_lock_bh(&agent->lock);
+	active = (agent->state == AGENT_STATE_ACTIVE);
+	spin_unlock_bh(&agent->lock);
+
+	return active;
+}
+
+static void tgt_agent_fetch_work(struct work_struct *work)
+{
+	struct sbp_target_agent *agent =
+		container_of(work, struct sbp_target_agent, work);
+	struct sbp_session *sess = agent->login->sess;
+	struct sbp_target_request *req;
+	int ret;
+	bool doorbell = agent->doorbell;
+	u64 next_orb = agent->orb_pointer;
+
+	while (next_orb && tgt_agent_check_active(agent)) {
+		req = kzalloc(sizeof(*req), GFP_KERNEL);
+		if (!req) {
+			spin_lock_bh(&agent->lock);
+			agent->state = AGENT_STATE_DEAD;
+			spin_unlock_bh(&agent->lock);
+			return;
+		}
+
+		req->login = agent->login;
+		req->orb_pointer = next_orb;
+
+		req->status.status = cpu_to_be32(STATUS_BLOCK_ORB_OFFSET_HIGH(
+					req->orb_pointer >> 32));
+		req->status.orb_low = cpu_to_be32(
+				req->orb_pointer & 0xfffffffc);
+
+		/* read in the ORB */
+		ret = sbp_run_transaction(sess->card, TCODE_READ_BLOCK_REQUEST,
+				sess->node_id, sess->generation, sess->speed,
+				req->orb_pointer, &req->orb, sizeof(req->orb));
+		if (ret != RCODE_COMPLETE) {
+			pr_debug("tgt_orb fetch failed: %x\n", ret);
+			req->status.status |= cpu_to_be32(
+					STATUS_BLOCK_SRC(
+						STATUS_SRC_ORB_FINISHED) |
+					STATUS_BLOCK_RESP(
+						STATUS_RESP_TRANSPORT_FAILURE) |
+					STATUS_BLOCK_DEAD(1) |
+					STATUS_BLOCK_LEN(1) |
+					STATUS_BLOCK_SBP_STATUS(
+						SBP_STATUS_UNSPECIFIED_ERROR));
+			spin_lock_bh(&agent->lock);
+			agent->state = AGENT_STATE_DEAD;
+			spin_unlock_bh(&agent->lock);
+
+			sbp_send_status(req);
+			sbp_free_request(req);
+			return;
+		}
+
+		/* check the next_ORB field */
+		if (be32_to_cpu(req->orb.next_orb.high) & 0x80000000) {
+			next_orb = 0;
+			req->status.status |= cpu_to_be32(STATUS_BLOCK_SRC(
+						STATUS_SRC_ORB_FINISHED));
+		} else {
+			next_orb = sbp2_pointer_to_addr(&req->orb.next_orb);
+			req->status.status |= cpu_to_be32(STATUS_BLOCK_SRC(
+						STATUS_SRC_ORB_CONTINUING));
+		}
+
+		if (tgt_agent_check_active(agent) && !doorbell) {
+			INIT_WORK(&req->work, tgt_agent_process_work);
+			queue_work(system_unbound_wq, &req->work);
+		} else {
+			/* don't process this request, just check next_ORB */
+			sbp_free_request(req);
+		} 
+
+		spin_lock_bh(&agent->lock);
+		doorbell = agent->doorbell = false;
+
+		/* check if we should carry on processing */
+		if (next_orb)
+			agent->orb_pointer = next_orb;
+		else
+			agent->state = AGENT_STATE_SUSPENDED;
+
+		spin_unlock_bh(&agent->lock);
+	};
+}
+
+struct sbp_target_agent *sbp_target_agent_register(
+		struct sbp_login_descriptor *login)
+{
+	struct sbp_target_agent *agent;
+	int ret;
+
+	agent = kmalloc(sizeof(*agent), GFP_KERNEL);
+	if (!agent)
+		return ERR_PTR(-ENOMEM);
+
+	spin_lock_init(&agent->lock);
+
+	agent->handler.length = 0x20;
+	agent->handler.address_callback = tgt_agent_rw;
+	agent->handler.callback_data = agent;
+
+	agent->login = login;
+	agent->state = AGENT_STATE_RESET;
+	INIT_WORK(&agent->work, tgt_agent_fetch_work);
+	agent->orb_pointer = 0;
+	agent->doorbell = false;
+
+	ret = fw_core_add_address_handler(&agent->handler,
+			&sbp_register_region);
+	if (ret < 0) {
+		kfree(agent);
+		return ERR_PTR(ret);
+	}
+
+	return agent;
+}
+
+void sbp_target_agent_unregister(struct sbp_target_agent *agent)
+{
+	fw_core_remove_address_handler(&agent->handler);
+	cancel_work_sync(&agent->work);
+	kfree(agent);
+}
diff --git a/drivers/target/sbp/sbp_target_agent.h b/drivers/target/sbp/sbp_target_agent.h
new file mode 100644
index 0000000..b5d76fd
--- /dev/null
+++ b/drivers/target/sbp/sbp_target_agent.h
@@ -0,0 +1,40 @@
+#ifndef _SBP_TARGET_AGENT_H
+#define _SBP_TARGET_AGENT_H
+
+#include <linux/firewire.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <target/target_core_base.h>
+
+#include "sbp_base.h"
+
+struct sbp_target_agent {
+	spinlock_t lock;
+	struct fw_address_handler handler;
+	struct sbp_login_descriptor *login;
+	int state;
+	struct work_struct work;
+	u64 orb_pointer;
+	bool doorbell;
+};
+
+struct sbp_target_request {
+	struct sbp_login_descriptor *login;
+	u64 orb_pointer;
+	struct sbp_command_block_orb orb;
+	struct sbp_status_block status;
+	struct work_struct work;
+
+	struct se_cmd se_cmd;
+	struct sbp_page_table_entry *pg_tbl;
+	void *cmd_buf;
+
+	unsigned char sense_buf[TRANSPORT_SENSE_BUFFER];
+};
+
+struct sbp_target_agent *sbp_target_agent_register(
+		struct sbp_login_descriptor *login);
+void sbp_target_agent_unregister(struct sbp_target_agent *agent);
+
+#endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 10/11] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h}
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (8 preceding siblings ...)
  2012-04-11 14:20       ` [PATCH 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-11 14:20       ` [PATCH 11/11] firewire-sbp-target: Add to target Kconfig and Makefile Chris Boot
                         ` (2 subsequent siblings)
  12 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

Miscellaneous functions for dealing with SCSI commands, status, sense
data and data read/write. This is where the real grunt work of pushing
data in and out of the FireWire bus happens.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 drivers/target/sbp/sbp_scsi_cmnd.c |  430 ++++++++++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_scsi_cmnd.h |   12 +
 2 files changed, 442 insertions(+)
 create mode 100644 drivers/target/sbp/sbp_scsi_cmnd.c
 create mode 100644 drivers/target/sbp/sbp_scsi_cmnd.h

diff --git a/drivers/target/sbp/sbp_scsi_cmnd.c b/drivers/target/sbp/sbp_scsi_cmnd.c
new file mode 100644
index 0000000..13407cf
--- /dev/null
+++ b/drivers/target/sbp/sbp_scsi_cmnd.c
@@ -0,0 +1,430 @@
+/*
+ * SBP2 target driver (SCSI over IEEE1394 in target mode)
+ *
+ * Copyright (C) 2011  Chris Boot <bootc@bootc.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define KMSG_COMPONENT "sbp_target"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_fabric_configfs.h>
+#include <target/target_core_configfs.h>
+
+#include "sbp_base.h"
+#include "sbp_target_agent.h"
+#include "sbp_scsi_cmnd.h"
+
+/*
+ * Simple wrapper around fw_run_transaction that retries the transaction several
+ * times in case of failure, with an exponential backoff.
+ */
+int sbp_run_transaction(struct fw_card *card, int tcode, int destination_id,
+		int generation, int speed, unsigned long long offset,
+		void *payload, size_t length)
+{
+	int attempt, ret, delay;
+
+	for (attempt = 1; attempt <= 5; attempt++) {
+		ret = fw_run_transaction(card, tcode, destination_id,
+				generation, speed, offset, payload, length);
+
+		switch (ret) {
+		case RCODE_COMPLETE:
+		case RCODE_TYPE_ERROR:
+		case RCODE_ADDRESS_ERROR:
+		case RCODE_GENERATION:
+			return ret;
+
+		default:
+			delay = 5 * attempt * attempt;
+			usleep_range(delay, delay * 2);
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Wrapper around sbp_run_transaction that gets the card, destination,
+ * generation and speed out of the request's session.
+ */
+static int sbp_run_request_transaction(struct sbp_target_request *req,
+		int tcode, unsigned long long offset, void *payload,
+		size_t length)
+{
+	struct sbp_login_descriptor *login = req->login;
+	struct sbp_session *sess = login->sess;
+	struct fw_card *card;
+	int node_id, generation, speed, ret;
+
+	spin_lock_bh(&sess->lock);
+	card = fw_card_get(sess->card);
+	node_id = sess->node_id;
+	generation = sess->generation;
+	speed = sess->speed;
+	spin_unlock_bh(&sess->lock);
+
+	ret = sbp_run_transaction(card, tcode, node_id, generation, speed,
+			offset, payload, length);
+
+	fw_card_put(card);
+
+	return ret;
+}
+
+static int sbp_fetch_command(struct sbp_target_request *req)
+{
+	int ret, cmd_len, copy_len;
+
+	cmd_len = scsi_command_size(req->orb.command_block);
+
+	req->cmd_buf = kmalloc(cmd_len, GFP_KERNEL);
+	if (!req->cmd_buf)
+		return -ENOMEM;
+
+	memcpy(req->cmd_buf, req->orb.command_block,
+		min_t(int, cmd_len, sizeof(req->orb.command_block)));
+
+	if (cmd_len > sizeof(req->orb.command_block)) {
+		pr_debug("sbp_fetch_command: filling in long command\n");
+		copy_len = cmd_len - sizeof(req->orb.command_block);
+
+		ret = sbp_run_request_transaction(req,
+				TCODE_READ_BLOCK_REQUEST,
+				req->orb_pointer + sizeof(req->orb),
+				req->cmd_buf + sizeof(req->orb.command_block),
+				copy_len);
+		if (ret != RCODE_COMPLETE)
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int sbp_fetch_page_table(struct sbp_target_request *req)
+{
+	int pg_tbl_sz, ret;
+	struct sbp_page_table_entry *pg_tbl;
+
+	if (!CMDBLK_ORB_PG_TBL_PRESENT(be32_to_cpu(req->orb.misc)))
+		return 0;
+
+	pg_tbl_sz = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc)) *
+		sizeof(struct sbp_page_table_entry);
+
+	pg_tbl = kmalloc(pg_tbl_sz, GFP_KERNEL);
+	if (!pg_tbl)
+		return -ENOMEM;
+
+	ret = sbp_run_request_transaction(req, TCODE_READ_BLOCK_REQUEST,
+			sbp2_pointer_to_addr(&req->orb.data_descriptor),
+			pg_tbl, pg_tbl_sz);
+	if (ret != RCODE_COMPLETE) {
+		kfree(pg_tbl);
+		return -EIO;
+	}
+
+	req->pg_tbl = pg_tbl;
+	return 0;
+}
+
+static void sbp_calc_data_length_direction(struct sbp_target_request *req,
+	u32 *data_len, enum dma_data_direction *data_dir)
+{
+	int data_size, direction, idx;
+
+	data_size = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+	direction = CMDBLK_ORB_DIRECTION(be32_to_cpu(req->orb.misc));
+
+	if (!data_size) {
+		*data_len = 0;
+		*data_dir = DMA_NONE;
+		return;
+	}
+
+	*data_dir = direction ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+	if (req->pg_tbl) {
+		*data_len = 0;
+		for (idx = 0; idx < data_size; idx++) {
+			*data_len += be16_to_cpu(
+					req->pg_tbl[idx].segment_length);
+		}
+	} else {
+		*data_len = data_size;
+	}
+}
+
+void sbp_handle_command(struct sbp_target_request *req)
+{
+	struct sbp_login_descriptor *login = req->login;
+	struct sbp_session *sess = login->sess;
+	int ret, unpacked_lun;
+	u32 data_length;
+	enum dma_data_direction data_dir;
+
+	ret = sbp_fetch_command(req);
+	if (ret) {
+		pr_debug("sbp_handle_command: fetch command failed: %d\n", ret);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	}
+
+	ret = sbp_fetch_page_table(req);
+	if (ret) {
+		pr_debug("sbp_handle_command: fetch page table failed: %d\n",
+			ret);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_TRANSPORT_FAILURE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_UNSPECIFIED_ERROR));
+		sbp_send_status(req);
+		sbp_free_request(req);
+		return;
+	}
+
+	unpacked_lun = req->login->lun->unpacked_lun;
+	sbp_calc_data_length_direction(req, &data_length, &data_dir);
+
+	pr_debug("sbp_handle_command ORB:0x%llx unpacked_lun:%d data_len:%d data_dir:%d\n",
+			req->orb_pointer, unpacked_lun, data_length, data_dir);
+
+	target_submit_cmd(&req->se_cmd, sess->se_sess, req->cmd_buf,
+			req->sense_buf, unpacked_lun, data_length,
+			MSG_SIMPLE_TAG, data_dir, 0);
+}
+
+/*
+ * DMA_TO_DEVICE = read from initiator (SCSI WRITE)
+ * DMA_FROM_DEVICE = write to initiator (SCSI READ)
+ */
+int sbp_rw_data(struct sbp_target_request *req)
+{
+	struct sbp_session *sess = req->login->sess;
+	int tcode, sg_miter_flags, max_payload, pg_size, speed, node_id,
+		generation, num_pte, length, tfr_length,
+		rcode = RCODE_COMPLETE;
+	struct sbp_page_table_entry *pte;
+	unsigned long long offset;
+	struct fw_card *card;
+	struct sg_mapping_iter iter;
+
+	if (req->se_cmd.data_direction == DMA_FROM_DEVICE) {
+		tcode = TCODE_WRITE_BLOCK_REQUEST;
+		sg_miter_flags = SG_MITER_FROM_SG;
+	} else {
+		tcode = TCODE_READ_BLOCK_REQUEST;
+		sg_miter_flags = SG_MITER_TO_SG;
+	}
+
+	max_payload = 4 << CMDBLK_ORB_MAX_PAYLOAD(be32_to_cpu(req->orb.misc));
+	speed = CMDBLK_ORB_SPEED(be32_to_cpu(req->orb.misc));
+
+	pg_size = CMDBLK_ORB_PG_SIZE(be32_to_cpu(req->orb.misc));
+	if (pg_size) {
+		pr_err("sbp_run_transaction: page size ignored\n");
+		pg_size = 0x100 << pg_size;
+	}
+
+	spin_lock_bh(&sess->lock);
+	card = fw_card_get(sess->card);
+	node_id = sess->node_id;
+	generation = sess->generation;
+	spin_unlock_bh(&sess->lock);
+
+	if (req->pg_tbl) {
+		pte = req->pg_tbl;
+		num_pte = CMDBLK_ORB_DATA_SIZE(be32_to_cpu(req->orb.misc));
+
+		offset = 0;
+		length = 0;
+	} else {
+		pte = NULL;
+		num_pte = 0;
+
+		offset = sbp2_pointer_to_addr(&req->orb.data_descriptor);
+		length = req->se_cmd.data_length;
+	}
+
+	sg_miter_start(&iter, req->se_cmd.t_data_sg, req->se_cmd.t_data_nents,
+		sg_miter_flags);
+
+	while (length || num_pte) {
+		if (!length) {
+			offset = (u64)be16_to_cpu(pte->segment_base_hi) << 32 |
+				be32_to_cpu(pte->segment_base_lo);
+			length = be16_to_cpu(pte->segment_length);
+
+			pte++;
+			num_pte--;
+		}
+
+		sg_miter_next(&iter);
+
+		tfr_length = min3(length, max_payload, (int)iter.length);
+
+		/* FIXME: take page_size into account */
+
+		rcode = sbp_run_transaction(card, tcode, node_id,
+				generation, speed,
+				offset, iter.addr, tfr_length);
+
+		if (rcode != RCODE_COMPLETE)
+			break;
+
+		length -= tfr_length;
+		offset += tfr_length;
+		iter.consumed = tfr_length;
+	}
+
+	sg_miter_stop(&iter);
+	fw_card_put(card);
+
+	if (rcode == RCODE_COMPLETE) {
+		WARN_ON(length != 0);
+		return 0;
+	} else {
+		return -EIO;
+	}
+}
+
+int sbp_send_status(struct sbp_target_request *req)
+{
+	int ret, length;
+	struct sbp_login_descriptor *login = req->login;
+
+	length = (((be32_to_cpu(req->status.status) >> 24) & 0x07) + 1) * 4;
+
+	ret = sbp_run_request_transaction(req, TCODE_WRITE_BLOCK_REQUEST,
+			login->status_fifo_addr, &req->status, length);
+	if (ret != RCODE_COMPLETE) {
+		pr_debug("sbp_send_status: write failed: 0x%x\n", ret);
+		return -EIO;
+	}
+
+	pr_debug("sbp_send_status: status write complete for ORB: 0x%llx\n",
+			req->orb_pointer);
+
+	return 0;
+}
+
+static void sbp_sense_mangle(struct sbp_target_request *req)
+{
+	struct se_cmd *se_cmd = &req->se_cmd;
+	u8 *sense = req->sense_buf;
+	u8 *status = req->status.data;
+
+	WARN_ON(se_cmd->scsi_sense_length < 18);
+
+	switch (sense[0] & 0x7f) { 		/* sfmt */
+	case 0x70: /* current, fixed */
+		status[0] = 0 << 6;
+		break;
+	case 0x71: /* deferred, fixed */
+		status[0] = 1 << 6;
+		break;
+	case 0x72: /* current, descriptor */
+	case 0x73: /* deferred, descriptor */
+	default:
+		/*
+		 * TODO: SBP-3 specifies what we should do with descriptor
+		 * format sense data
+		 */
+		pr_err("sbp_send_sense: unknown sense format: 0x%x\n",
+			sense[0]);
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_REQUEST_ABORTED));
+		return;
+	}
+
+	status[0] |= se_cmd->scsi_status & 0x3f;/* status */
+	status[1] =
+		(sense[0] & 0x80) |		/* valid */
+		((sense[2] & 0xe0) >> 1) |	/* mark, eom, ili */
+		(sense[2] & 0x0f);		/* sense_key */
+	status[2] = se_cmd->scsi_asc;		/* sense_code */
+	status[3] = se_cmd->scsi_ascq;		/* sense_qualifier */
+
+	/* information */
+	status[4] = sense[3];
+	status[5] = sense[4];
+	status[6] = sense[5];
+	status[7] = sense[6];
+
+	/* CDB-dependent */
+	status[8] = sense[8];
+	status[9] = sense[9];
+	status[10] = sense[10];
+	status[11] = sense[11];
+
+	/* fru */
+	status[12] = sense[14];
+
+	/* sense_key-dependent */
+	status[13] = sense[15];
+	status[14] = sense[16];
+	status[15] = sense[17];
+
+	req->status.status |= cpu_to_be32(
+		STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+		STATUS_BLOCK_DEAD(0) |
+		STATUS_BLOCK_LEN(5) |
+		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+}
+
+int sbp_send_sense(struct sbp_target_request *req)
+{
+	struct se_cmd *se_cmd = &req->se_cmd;
+
+	if (se_cmd->scsi_sense_length) {
+		sbp_sense_mangle(req);
+	} else {
+		req->status.status |= cpu_to_be32(
+			STATUS_BLOCK_RESP(STATUS_RESP_REQUEST_COMPLETE) |
+			STATUS_BLOCK_DEAD(0) |
+			STATUS_BLOCK_LEN(1) |
+			STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
+	}
+
+	return sbp_send_status(req);
+}
+
+void sbp_free_request(struct sbp_target_request *req)
+{
+	kfree(req->pg_tbl);
+	kfree(req->cmd_buf);
+	kfree(req);
+}
diff --git a/drivers/target/sbp/sbp_scsi_cmnd.h b/drivers/target/sbp/sbp_scsi_cmnd.h
new file mode 100644
index 0000000..d02f4ca
--- /dev/null
+++ b/drivers/target/sbp/sbp_scsi_cmnd.h
@@ -0,0 +1,12 @@
+
+#include "sbp_target_agent.h"
+
+int sbp_run_transaction(struct fw_card *card, int tcode, int destination_id,
+		int generation, int speed, unsigned long long offset,
+		void *payload, size_t length);
+
+void sbp_handle_command(struct sbp_target_request *req);
+int sbp_rw_data(struct sbp_target_request *req);
+int sbp_send_status(struct sbp_target_request *req);
+int sbp_send_sense(struct sbp_target_request *req);
+void sbp_free_request(struct sbp_target_request *req);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 11/11] firewire-sbp-target: Add to target Kconfig and Makefile
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (9 preceding siblings ...)
  2012-04-11 14:20       ` [PATCH 10/11] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h} Chris Boot
@ 2012-04-11 14:20       ` Chris Boot
  2012-04-12 21:02       ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Andy Grover
  2012-04-13  3:03       ` Nicholas A. Bellinger
  12 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-11 14:20 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

This commit also adds an entry to the MAINTAINERS file.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Nicholas A. Bellinger <nab@linux-iscsi.org>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
---
 MAINTAINERS             |    9 +++++++++
 drivers/target/Kconfig  |    1 +
 drivers/target/Makefile |    1 +
 3 files changed, 11 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index b31bdff..b084020 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2754,6 +2754,15 @@ T:	git git://git.alsa-project.org/alsa-kernel.git
 S:	Maintained
 F:	sound/firewire/
 
+FIREWIRE SBP-2 TARGET
+M:  Chris Boot <bootc@bootc.net>
+L:  linux-scsi@vger.kernel.org
+L:  target-devel@vger.kernel.org
+L:  linux1394-devel@lists.sourceforge.net
+T:  git git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core-2.6.git master
+S:  Maintained
+F:  drivers/target/sbp/
+
 FIREWIRE SUBSYSTEM
 M:	Stefan Richter <stefanr@s5r6.in-berlin.de>
 L:	linux1394-devel@lists.sourceforge.net
diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig
index fc5fa9f..2cfa467 100644
--- a/drivers/target/Kconfig
+++ b/drivers/target/Kconfig
@@ -41,5 +41,6 @@ source "drivers/target/tcm_fc/Kconfig"
 source "drivers/target/iscsi/Kconfig"
 source "drivers/target/tcm_vhost/Kconfig"
 source "drivers/target/usb-gadget/Kconfig"
+source "drivers/target/sbp/Kconfig"
 
 endif
diff --git a/drivers/target/Makefile b/drivers/target/Makefile
index 6b5f526..1ae8862 100644
--- a/drivers/target/Makefile
+++ b/drivers/target/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_TCM_FC)		+= tcm_fc/
 obj-$(CONFIG_ISCSI_TARGET)	+= iscsi/
 obj-$(CONFIG_TCM_VHOST)		+= tcm_vhost/
 obj-$(CONFIG_TARGET_USB_GADGET)	+= usb-gadget/
+obj-$(CONFIG_FIREWIRE_SBP_TARGET) += sbp/
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* Re: [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (10 preceding siblings ...)
  2012-04-11 14:20       ` [PATCH 11/11] firewire-sbp-target: Add to target Kconfig and Makefile Chris Boot
@ 2012-04-12 21:02       ` Andy Grover
  2012-04-13  3:03       ` Nicholas A. Bellinger
  12 siblings, 0 replies; 104+ messages in thread
From: Andy Grover @ 2012-04-12 21:02 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, clemens, nab, stefanr

On 04/11/2012 07:20 AM, Chris Boot wrote:
> The FireWire SBP-2 Target is a driver for using an IEEE-1394 connection
> as a SCSI transport. This module uses the SCSI Target framework to
> expose LUNs to other machines attached to a FireWire bus, in effect
> acting as a FireWire hard disk similar to FireWire Target Disk mode on
> many Apple computers.
> 
> Sorry this latest revision has been a long time coming. I was trying to
> chase down a crashing bug (but haven't been able to replicate it), changed
> my mind about a large portion of the code twice, and life got in the way as
> well!

I just want to say this is awesome and I can't wait to try it!

-- Andy

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
                         ` (11 preceding siblings ...)
  2012-04-12 21:02       ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Andy Grover
@ 2012-04-13  3:03       ` Nicholas A. Bellinger
  2012-04-13 13:16         ` Chris Boot
  12 siblings, 1 reply; 104+ messages in thread
From: Nicholas A. Bellinger @ 2012-04-13  3:03 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens,
	stefanr, Christoph Hellwig

On Wed, 2012-04-11 at 15:20 +0100, Chris Boot wrote:
> The FireWire SBP-2 Target is a driver for using an IEEE-1394 connection
> as a SCSI transport. This module uses the SCSI Target framework to
> expose LUNs to other machines attached to a FireWire bus, in effect
> acting as a FireWire hard disk similar to FireWire Target Disk mode on
> many Apple computers.
> 
> Sorry this latest revision has been a long time coming. I was trying to
> chase down a crashing bug (but haven't been able to replicate it), changed
> my mind about a large portion of the code twice, and life got in the way as
> well!
> 

Some very nice work to make this all go Chris..  8-)

Thanks again btw for your target_core_mod patches along the way to v3!

> Changes in v3:
> * Updates for target framework API changes
> * Attempt to make headers self-contained
> * Remove bad use of atomics and memory barriers
> * Rework use of locking
> * Use system workqueues
> * Wrap fw_run_transaction() to retry failed transactions
> * Coding style fixes
> * Fix a few bugs
> * Overhaul sbp_rw_data()
> * Overhaul target fetch agent
> 

So I've merged a squashed version this series from:

  https://github.com/bootc/Linux-SBP-2-Target.git patch-v3

into lio-core/master, and have now pushed to k.o upstream

This looks to me like a reasonable candidate for a v3.5 mainline merge,
so we need to go ahead and get this into target-pending..  Also, thanks
for getting Stefan's ACK's here on the drivers/firmware/ specific
changes..

So for new fabric drivers (as discused with Sebastian and usb-gadget
recently) that the target team has been enforcing that new fabric
modules convert to use a single source / header file for readability and
maintainability purposes.

It would be great if you can publish one more branch (no need to re-post
the full diff) that takes your patch-v3 down to a single .c/.h file.
Otherwise, I'm fine to take the 15 minutes to do this conversion ahead
of dropping into target-pending for the sunday night linux-next build.

Thanks again Chris!

--nab


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-04-13  3:03       ` Nicholas A. Bellinger
@ 2012-04-13 13:16         ` Chris Boot
  2012-04-14  1:23           ` Nicholas A. Bellinger
  0 siblings, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-04-13 13:16 UTC (permalink / raw)
  To: Nicholas A. Bellinger
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens,
	stefanr, Christoph Hellwig

On 13/04/2012 04:03, Nicholas A. Bellinger wrote:
> On Wed, 2012-04-11 at 15:20 +0100, Chris Boot wrote:
>> The FireWire SBP-2 Target is a driver for using an IEEE-1394 connection
>> as a SCSI transport. This module uses the SCSI Target framework to
>> expose LUNs to other machines attached to a FireWire bus, in effect
>> acting as a FireWire hard disk similar to FireWire Target Disk mode on
>> many Apple computers.
>>
>> Sorry this latest revision has been a long time coming. I was trying to
>> chase down a crashing bug (but haven't been able to replicate it), changed
>> my mind about a large portion of the code twice, and life got in the way as
>> well!
>>
> Some very nice work to make this all go Chris..  8-)
>
> Thanks again btw for your target_core_mod patches along the way to v3!

No problem, it's been a very useful learning experience and I'm really 
glad I did it! :-)

>> Changes in v3:
>> * Updates for target framework API changes
>> * Attempt to make headers self-contained
>> * Remove bad use of atomics and memory barriers
>> * Rework use of locking
>> * Use system workqueues
>> * Wrap fw_run_transaction() to retry failed transactions
>> * Coding style fixes
>> * Fix a few bugs
>> * Overhaul sbp_rw_data()
>> * Overhaul target fetch agent
>>
> So I've merged a squashed version this series from:
>
>    https://github.com/bootc/Linux-SBP-2-Target.git patch-v3
>
> into lio-core/master, and have now pushed to k.o upstream

Thanks!

> This looks to me like a reasonable candidate for a v3.5 mainline merge,
> so we need to go ahead and get this into target-pending..  Also, thanks
> for getting Stefan's ACK's here on the drivers/firmware/ specific
> changes..
>
> So for new fabric drivers (as discused with Sebastian and usb-gadget
> recently) that the target team has been enforcing that new fabric
> modules convert to use a single source / header file for readability and
> maintainability purposes.
>
> It would be great if you can publish one more branch (no need to re-post
> the full diff) that takes your patch-v3 down to a single .c/.h file.
> Otherwise, I'm fine to take the 15 minutes to do this conversion ahead
> of dropping into target-pending for the sunday night linux-next build.

I'll get onto it over the weekend, I hope. I assume in this case I just 
stick it all in drivers/target/ instead of having a sbp/ directory 
underneath that?

Cheers,
Chris


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-04-13 13:16         ` Chris Boot
@ 2012-04-14  1:23           ` Nicholas A. Bellinger
  2012-04-14  9:12             ` [PATCH 0/2] sbp-target: cleanup after merge into single file Chris Boot
  2012-04-17 10:48             ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
  0 siblings, 2 replies; 104+ messages in thread
From: Nicholas A. Bellinger @ 2012-04-14  1:23 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens,
	stefanr, Christoph Hellwig

On Fri, 2012-04-13 at 14:16 +0100, Chris Boot wrote:
> On 13/04/2012 04:03, Nicholas A. Bellinger wrote:

<SNIP>

> > So I've merged a squashed version this series from:
> >
> >    https://github.com/bootc/Linux-SBP-2-Target.git patch-v3
> >
> > into lio-core/master, and have now pushed to k.o upstream
> 
> Thanks!
> 
> > This looks to me like a reasonable candidate for a v3.5 mainline merge,
> > so we need to go ahead and get this into target-pending..  Also, thanks
> > for getting Stefan's ACK's here on the drivers/firmware/ specific
> > changes..
> >
> > So for new fabric drivers (as discused with Sebastian and usb-gadget
> > recently) that the target team has been enforcing that new fabric
> > modules convert to use a single source / header file for readability and
> > maintainability purposes.
> >
> > It would be great if you can publish one more branch (no need to re-post
> > the full diff) that takes your patch-v3 down to a single .c/.h file.
> > Otherwise, I'm fine to take the 15 minutes to do this conversion ahead
> > of dropping into target-pending for the sunday night linux-next build.
> 
> I'll get onto it over the weekend, I hope. I assume in this case I just 
> stick it all in drivers/target/ instead of having a sbp/ directory 
> underneath that?
> 

I was eager to see this change, so I decided to go ahead and do the
mechanical conversion myself in the following branch:

  git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core.git sbp-merge

As mentioned, it converts drivers/target/sbp/ to use a single sbp_target.[c,h]
source/header file following mainline convention for new target fabric
drivers.  Also make as many functions as possible statically defined and
add inline prototypes where necessary.

This patch also renames the sbp-target config entry from:

    FIREWIRE_SBP_TARGET -> SBP_TARGET

and also renames the final generated module name from:

    fireware-sbp-target.ko -> sbp_target.ko

Here is what the diffstat ends up looking like:

 drivers/target/Makefile                   |    2 +-
 drivers/target/sbp/Kconfig                |    6 +-
 drivers/target/sbp/Makefile               |   12 +-
 drivers/target/sbp/sbp_base.h             |  211 ---
 drivers/target/sbp/sbp_configfs.c         |  737 --------
 drivers/target/sbp/sbp_fabric.c           |  314 ----
 drivers/target/sbp/sbp_fabric.h           |   40 -
 drivers/target/sbp/sbp_login.c            |  672 --------
 drivers/target/sbp/sbp_login.h            |   17 -
 drivers/target/sbp/sbp_management_agent.c |  255 ---
 drivers/target/sbp/sbp_management_agent.h |   34 -
 drivers/target/sbp/sbp_scsi_cmnd.c        |  430 -----
 drivers/target/sbp/sbp_scsi_cmnd.h        |   12 -
 drivers/target/sbp/sbp_target.c           | 2621 +++++++++++++++++++++++++++++
 drivers/target/sbp/sbp_target.h           |  254 +++
 drivers/target/sbp/sbp_target_agent.c     |  395 -----
 drivers/target/sbp/sbp_target_agent.h     |   40 -
 17 files changed, 2879 insertions(+), 3173 deletions(-)
 delete mode 100644 drivers/target/sbp/sbp_base.h
 delete mode 100644 drivers/target/sbp/sbp_configfs.c
 delete mode 100644 drivers/target/sbp/sbp_fabric.c
 delete mode 100644 drivers/target/sbp/sbp_fabric.h
 delete mode 100644 drivers/target/sbp/sbp_login.c
 delete mode 100644 drivers/target/sbp/sbp_login.h
 delete mode 100644 drivers/target/sbp/sbp_management_agent.c
 delete mode 100644 drivers/target/sbp/sbp_management_agent.h
 delete mode 100644 drivers/target/sbp/sbp_scsi_cmnd.c
 delete mode 100644 drivers/target/sbp/sbp_scsi_cmnd.h
 create mode 100644 drivers/target/sbp/sbp_target.c
 create mode 100644 drivers/target/sbp/sbp_target.h
 delete mode 100644 drivers/target/sbp/sbp_target_agent.c
 delete mode 100644 drivers/target/sbp/sbp_target_agent.h


Please have a look at this branch over the next days, and if you're OK
with the re-org changes I'll go ahead and merge this into
lio-core/master, and drop into target-pending for sunday night's build.

Thanks Chris!

--nab


^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH 0/2] sbp-target: cleanup after merge into single file
  2012-04-14  1:23           ` Nicholas A. Bellinger
@ 2012-04-14  9:12             ` Chris Boot
  2012-04-14  9:12               ` [PATCH 1/2] sbp-target: minor cleanups after merging " Chris Boot
                                 ` (2 more replies)
  2012-04-17 10:48             ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
  1 sibling, 3 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-14  9:12 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

Thanks to Nick Bellinger for doing the work for me and merging the
sbp-target code into single source/header files. This little series
does a bit of cleanup and updates the TODO file.

I'll also take this opportunity to add my sign-off to Nick's patch that
merges everything together, which this series is on top of:

	Acked-by: Chris Boot <bootc@bootc.net>

Cheers,
Chris

Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: Nicholas Bellinger <nab@linux-iscsi.org>


Chris Boot (2):
  sbp-target: minor cleanups after merging into single file
  sbp-target: update TODO file

 drivers/target/sbp/TODO         |    8 ++++----
 drivers/target/sbp/sbp_target.c |    6 +++---
 drivers/target/sbp/sbp_target.h |    3 ---
 3 files changed, 7 insertions(+), 10 deletions(-)

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 104+ messages in thread

* [PATCH 1/2] sbp-target: minor cleanups after merging into single file
  2012-04-14  9:12             ` [PATCH 0/2] sbp-target: cleanup after merge into single file Chris Boot
@ 2012-04-14  9:12               ` Chris Boot
  2012-04-14  9:12               ` [PATCH 2/2] sbp-target: update TODO file Chris Boot
  2012-04-14 21:44               ` [PATCH 0/2] sbp-target: cleanup after merge into single file Nicholas A. Bellinger
  2 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-14  9:12 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

Just a few minor cleanups to make a couple more elements static and
remove some extern definitions from the header which are not exported.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: Nicholas Bellinger <nab@linux-iscsi.org>
---
 drivers/target/sbp/sbp_target.c |    6 +++---
 drivers/target/sbp/sbp_target.h |    3 ---
 2 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index d7c9ac9..37c6098 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -43,10 +43,10 @@
 #include "sbp_target.h"
 
 /* Local pointer to allocated TCM configfs fabric module */
-struct target_fabric_configfs *sbp_fabric_configfs;
+static struct target_fabric_configfs *sbp_fabric_configfs;
 
 /* FireWire address region for management and command block address handlers */
-const struct fw_address_region sbp_register_region = {
+static const struct fw_address_region sbp_register_region = {
 	.start	= CSR_REGISTER_BASE + 0x10000,
 	.end	= 0x1000000000000ULL,
 };
@@ -1435,7 +1435,7 @@ static void sbp_sense_mangle(struct sbp_target_request *req)
 		STATUS_BLOCK_SBP_STATUS(SBP_STATUS_OK));
 }
 
-int sbp_send_sense(struct sbp_target_request *req)
+static int sbp_send_sense(struct sbp_target_request *req)
 {
 	struct se_cmd *se_cmd = &req->se_cmd;
 
diff --git a/drivers/target/sbp/sbp_target.h b/drivers/target/sbp/sbp_target.h
index 1ec2269..6d0d74a 100644
--- a/drivers/target/sbp/sbp_target.h
+++ b/drivers/target/sbp/sbp_target.h
@@ -193,9 +193,6 @@ struct sbp_tport {
 	int max_logins_per_lun;
 };
 
-extern struct target_fabric_configfs *sbp_fabric_configfs;
-extern const struct fw_address_region sbp_register_region;
-
 static inline u64 sbp2_pointer_to_addr(const struct sbp2_pointer *ptr)
 {
 	return (u64)(be32_to_cpu(ptr->high) & 0x0000ffff) << 32 |
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [PATCH 2/2] sbp-target: update TODO file
  2012-04-14  9:12             ` [PATCH 0/2] sbp-target: cleanup after merge into single file Chris Boot
  2012-04-14  9:12               ` [PATCH 1/2] sbp-target: minor cleanups after merging " Chris Boot
@ 2012-04-14  9:12               ` Chris Boot
  2012-04-14 21:44               ` [PATCH 0/2] sbp-target: cleanup after merge into single file Nicholas A. Bellinger
  2 siblings, 0 replies; 104+ messages in thread
From: Chris Boot @ 2012-04-14  9:12 UTC (permalink / raw)
  To: linux1394-devel, target-devel
  Cc: linux-kernel, agrover, clemens, nab, stefanr, Chris Boot

The TODO wasn't updated after the last batch of changes before the
merge, so remove those items that have been completed. This patch also
re-orders the existing items in priority order and adds a new one.

Signed-off-by: Chris Boot <bootc@bootc.net>
Cc: Andy Grover <agrover@redhat.com>
Cc: Clemens Ladisch <clemens@ladisch.de>
Cc: Stefan Richter <stefanr@s5r6.in-berlin.de>
Cc: Nicholas Bellinger <nab@linux-iscsi.org>
---
 drivers/target/sbp/TODO |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/target/sbp/TODO b/drivers/target/sbp/TODO
index eaec1c9..e800058 100644
--- a/drivers/target/sbp/TODO
+++ b/drivers/target/sbp/TODO
@@ -1,7 +1,7 @@
-* Force-terminate sessions when disabling targets
+1. Improve FireWire data transfer rate by queuing up several simultaneous transfers
+2. Force-terminate sessions when disabling targets
+3. Implement TASK MANAGEMENT functionality
 * Ability to have several SCSI commands in-flight (TCQ?)
-* Retry failed FireWire transactions a few times with exponential backoff
-* Take into account the page_size field for transfers and/or page tables
+* Take into account the page_size field for transfers
 * Handle descriptor format sense data
 * Implement QUERY LOGINS management ORB
-* Implement TASK MANAGEMENT functionality
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 104+ messages in thread

* Re: [PATCH 08/11] firewire-sbp-target: Add sbp_login.{c,h}
  2012-04-11 14:20       ` [PATCH 08/11] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
@ 2012-04-14 10:17         ` Stefan Richter
  0 siblings, 0 replies; 104+ messages in thread
From: Stefan Richter @ 2012-04-14 10:17 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Apr 11 Chris Boot wrote:
> +static void session_check_for_reset(struct sbp_session *sess)
> +{
> +	bool card_valid = false;
> +
> +	spin_lock_bh(&sess->lock);
> +
> +	if (sess->card) {
> +		spin_lock_irq(&sess->card->lock);
> +		card_valid = (sess->card->local_node != NULL);
> +		spin_unlock_irq(&sess->card->lock);
> +
> +		if (!card_valid) {
> +			fw_card_put(sess->card);
> +			sess->card = NULL;
> +		}
> +	}
> +
> +	if (!card_valid || (sess->generation != sess->card->generation)) {
> +		pr_info("Waiting for reconnect from node: %016llx\n",
> +				sess->guid);
> +
> +		sess->node_id = -1;
> +		sess->reconnect_expires = get_jiffies_64() +
> +			((sess->reconnect_hold + 1) * HZ);
> +	}
> +
> +	spin_unlock_bh(&sess->lock);
> +}

The card->local_node != NULL test by itself is atomic, it does not benefit
from being wrapped by card->lock acquisition.

Well, OK, the lock effectively forces the compiler to determine the value
of card_valid only once.  If the lock weren't there I guess the compiler
might feel entitled to reload card->local_node in the second !card_valid
test.  But even if you lose ACCESS_ONCE behavior by removing the card->lock
acquisition, I can't see how that could be detrimental relative to the
current code.

I am wondering on the other hand if there isn't actually a dependency
between this local_node test and something else, e.g. the generation test.
I.e. might the locking be incomplete?  Not sure about that.  I think I
rather want to look at that again when I received the code through
mainline.

BTW "card_valid" sounds rather generic; maybe call it "topology_valid"?
Either way, it can turn valid or invalid any time when firewire-core gets
to handle a self-ID-complete event.
-- 
Stefan Richter
-=====-===-- -=-- -===-
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h}
  2012-04-11 14:20       ` [PATCH 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
@ 2012-04-14 10:49         ` Stefan Richter
  2012-04-14 11:33           ` Stefan Richter
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-04-14 10:49 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Apr 11 Chris Boot wrote:
> +static int tgt_agent_rw_agent_state(struct fw_card *card, int tcode, void *data,
> +		struct sbp_target_agent *agent)
> +{
> +	__be32 state;
> +
> +	switch (tcode) {
> +	case TCODE_READ_QUADLET_REQUEST:
> +		pr_debug("tgt_agent AGENT_STATE READ\n");
> +
> +		spin_lock_bh(&agent->lock);
> +		state = cpu_to_be32(agent->state);
> +		spin_unlock_bh(&agent->lock);
> +		memcpy(data, &state, sizeof(state));
> +
> +		return RCODE_COMPLETE;
> +
> +	case TCODE_WRITE_QUADLET_REQUEST:
> +		/* ignored */
> +		return RCODE_COMPLETE;
> +
> +	default:
> +		return RCODE_TYPE_ERROR;
> +	}
> +}

agent->state is an int; reading an int is atomic.  Hence the access on
its own does not benefit from lock acquisition.

The memcpy can be simplified to

	*(__be32 *)data = cpu_to_be32(agent->state);

if data is always at least quadlet aligned.  Thy type cast is only to tell
code checkers like sparse that we know what we are doing.  If data may be
unaligned, you could use

	put_unaligned_be32(agent->state, data);
-- 
Stefan Richter
-=====-===-- -=-- -===-
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h}
  2012-04-14 10:49         ` Stefan Richter
@ 2012-04-14 11:33           ` Stefan Richter
  0 siblings, 0 replies; 104+ messages in thread
From: Stefan Richter @ 2012-04-14 11:33 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, nab

On Apr 14 Stefan Richter wrote:
> On Apr 11 Chris Boot wrote:
> > +static int tgt_agent_rw_agent_state(struct fw_card *card, int tcode, void *data,
> > +		struct sbp_target_agent *agent)
> > +{
> > +	__be32 state;
> > +
> > +	switch (tcode) {
> > +	case TCODE_READ_QUADLET_REQUEST:
> > +		pr_debug("tgt_agent AGENT_STATE READ\n");
> > +
> > +		spin_lock_bh(&agent->lock);
> > +		state = cpu_to_be32(agent->state);
> > +		spin_unlock_bh(&agent->lock);
> > +		memcpy(data, &state, sizeof(state));
> > +
> > +		return RCODE_COMPLETE;
> > +
> > +	case TCODE_WRITE_QUADLET_REQUEST:
> > +		/* ignored */
> > +		return RCODE_COMPLETE;
> > +
> > +	default:
> > +		return RCODE_TYPE_ERROR;
> > +	}
> > +}
> 
> agent->state is an int; reading an int is atomic.  Hence the access on
> its own does not benefit from lock acquisition.

Actually this is only true because all write accesses to agent->state are
merely assignments (not increments or the like).  And I have to admit that
I don't remember whether this is only how compilers work in practice or it
is actually required by the C language specification.

> The memcpy can be simplified to
> 
> 	*(__be32 *)data = cpu_to_be32(agent->state);
> 
> if data is always at least quadlet aligned.  Thy type cast is only to tell
> code checkers like sparse that we know what we are doing.

So unless there is such an atomicity guarantee, leave the locking as is
and prefer

	int state;

	spin_lock_bh(&agent->lock);
	state = agent->state;
	spin_unlock_bh(&agent->lock);

	*(__be32 *)data = cpu_to_be32(state);

> If data may be
> unaligned, you could use
> 
> 	put_unaligned_be32(agent->state, data);

OK, I read further.  This is part of your handler.address_callback.
data will point to quadlet aligned memory then.  It is no where written as
an API specification, but you may rest assured that firewire-core will
always align quadlet read or block read response buffers at least on
quadlet boundary.  You can safely cast data into an u32 or __be32 pointer.
-- 
Stefan Richter
-=====-===-- -=-- -===-
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH 0/2] sbp-target: cleanup after merge into single file
  2012-04-14  9:12             ` [PATCH 0/2] sbp-target: cleanup after merge into single file Chris Boot
  2012-04-14  9:12               ` [PATCH 1/2] sbp-target: minor cleanups after merging " Chris Boot
  2012-04-14  9:12               ` [PATCH 2/2] sbp-target: update TODO file Chris Boot
@ 2012-04-14 21:44               ` Nicholas A. Bellinger
  2012-04-14 23:11                 ` Stefan Richter
  2 siblings, 1 reply; 104+ messages in thread
From: Nicholas A. Bellinger @ 2012-04-14 21:44 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens, stefanr

On Sat, 2012-04-14 at 10:12 +0100, Chris Boot wrote:
> Thanks to Nick Bellinger for doing the work for me and merging the
> sbp-target code into single source/header files. This little series
> does a bit of cleanup and updates the TODO file.
> 
> I'll also take this opportunity to add my sign-off to Nick's patch that
> merges everything together, which this series is on top of:
> 
> 	Acked-by: Chris Boot <bootc@bootc.net>
> 

Thanks for the Ack.  ;)

I'll go ahead and merge the sbp-merge branch back into lio-core/master
now, and apply this series on top of master.

Also, it looks like Stefan has a few more comments from the last round
of review..  I'll go ahead and get the latest HEAD prepped for
target-pending today, and plan to rebase any forthcoming incremental
patches from you into a single merge commit in target-pending.

Thanks Chris!

--nab


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH 0/2] sbp-target: cleanup after merge into single file
  2012-04-14 21:44               ` [PATCH 0/2] sbp-target: cleanup after merge into single file Nicholas A. Bellinger
@ 2012-04-14 23:11                 ` Stefan Richter
  2012-04-15  1:22                   ` Nicholas A. Bellinger
  0 siblings, 1 reply; 104+ messages in thread
From: Stefan Richter @ 2012-04-14 23:11 UTC (permalink / raw)
  To: Nicholas A. Bellinger
  Cc: Chris Boot, linux1394-devel, target-devel, linux-kernel, agrover,
	clemens

On Apr 14 Nicholas A. Bellinger wrote:
> Also, it looks like Stefan has a few more comments from the last round
> of review..

Don't consider them blocking.  I would welcome it if the code gets merged
soon, it looks very nice and maintainable.  The card state <-> session
state interactions which I was wondering about will be more comfortable for
me to investigate when it is in mainline; I believe there is no urgency
for me to look into that.  Other obscure but simple things like making use
of memory alignment guarantees from firewire-core are more effectively
addressed if I can send patches rather than comments.
-- 
Stefan Richter
-=====-===-- -=-- -====
http://arcgraph.de/sr/

^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH 0/2] sbp-target: cleanup after merge into single file
  2012-04-14 23:11                 ` Stefan Richter
@ 2012-04-15  1:22                   ` Nicholas A. Bellinger
  0 siblings, 0 replies; 104+ messages in thread
From: Nicholas A. Bellinger @ 2012-04-15  1:22 UTC (permalink / raw)
  To: Stefan Richter
  Cc: Chris Boot, linux1394-devel, target-devel, linux-kernel, agrover,
	clemens

On Sun, 2012-04-15 at 01:11 +0200, Stefan Richter wrote:
> On Apr 14 Nicholas A. Bellinger wrote:
> > Also, it looks like Stefan has a few more comments from the last round
> > of review..
> 
> Don't consider them blocking.  I would welcome it if the code gets merged
> soon, it looks very nice and maintainable.  The card state <-> session
> state interactions which I was wondering about will be more comfortable for
> me to investigate when it is in mainline; I believe there is no urgency
> for me to look into that.  Other obscure but simple things like making use
> of memory alignment guarantees from firewire-core are more effectively
> addressed if I can send patches rather than comments.

<nod>  In that case, I'll go ahead and add your Acked-by to the initial
merge commit for sbp-target that will be appearing in
target-pending/for-next-merge shortly.

Thanks Stefan!

--nab




^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-04-14  1:23           ` Nicholas A. Bellinger
  2012-04-14  9:12             ` [PATCH 0/2] sbp-target: cleanup after merge into single file Chris Boot
@ 2012-04-17 10:48             ` Chris Boot
  2012-04-18  7:17               ` Nicholas A. Bellinger
  1 sibling, 1 reply; 104+ messages in thread
From: Chris Boot @ 2012-04-17 10:48 UTC (permalink / raw)
  To: Nicholas A. Bellinger
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens,
	stefanr, Christoph Hellwig

On 14/04/2012 02:23, Nicholas A. Bellinger wrote:
>>> This looks to me like a reasonable candidate for a v3.5 mainline merge,
>>> so we need to go ahead and get this into target-pending..  Also, thanks
>>> for getting Stefan's ACK's here on the drivers/firmware/ specific
>>> changes..
>>>
>>> So for new fabric drivers (as discused with Sebastian and usb-gadget
>>> recently) that the target team has been enforcing that new fabric
>>> modules convert to use a single source / header file for readability and
>>> maintainability purposes.
>>>
>>> It would be great if you can publish one more branch (no need to re-post
>>> the full diff) that takes your patch-v3 down to a single .c/.h file.
>>> Otherwise, I'm fine to take the 15 minutes to do this conversion ahead
>>> of dropping into target-pending for the sunday night linux-next build.
>> I'll get onto it over the weekend, I hope. I assume in this case I just
>> stick it all in drivers/target/ instead of having a sbp/ directory
>> underneath that?
>>
> I was eager to see this change, so I decided to go ahead and do the
> mechanical conversion myself in the following branch:
>
>    git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core.git sbp-merge
>
> As mentioned, it converts drivers/target/sbp/ to use a single sbp_target.[c,h]
> source/header file following mainline convention for new target fabric
> drivers.  Also make as many functions as possible statically defined and
> add inline prototypes where necessary.
>
> This patch also renames the sbp-target config entry from:
>
>      FIREWIRE_SBP_TARGET ->  SBP_TARGET
>
> and also renames the final generated module name from:
>
>      fireware-sbp-target.ko ->  sbp_target.ko

Nick,

I only just noticed this, but it looks like your merge lost my changed 
to the MAINTAINERS file. Want me to send a fixup patch?

Cheers,
Chris

-- 
Chris Boot
bootc@bootc.net


^ permalink raw reply	[flat|nested] 104+ messages in thread

* Re: [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target
  2012-04-17 10:48             ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
@ 2012-04-18  7:17               ` Nicholas A. Bellinger
  0 siblings, 0 replies; 104+ messages in thread
From: Nicholas A. Bellinger @ 2012-04-18  7:17 UTC (permalink / raw)
  To: Chris Boot
  Cc: linux1394-devel, target-devel, linux-kernel, agrover, clemens,
	stefanr, Christoph Hellwig

On Tue, 2012-04-17 at 11:48 +0100, Chris Boot wrote:
> On 14/04/2012 02:23, Nicholas A. Bellinger wrote:

<SNIP>

> > I was eager to see this change, so I decided to go ahead and do the
> > mechanical conversion myself in the following branch:
> >
> >    git://git.kernel.org/pub/scm/linux/kernel/git/nab/lio-core.git sbp-merge
> >
> > As mentioned, it converts drivers/target/sbp/ to use a single sbp_target.[c,h]
> > source/header file following mainline convention for new target fabric
> > drivers.  Also make as many functions as possible statically defined and
> > add inline prototypes where necessary.
> >
> > This patch also renames the sbp-target config entry from:
> >
> >      FIREWIRE_SBP_TARGET ->  SBP_TARGET
> >
> > and also renames the final generated module name from:
> >
> >      fireware-sbp-target.ko ->  sbp_target.ko
> 
> Nick,
> 
> I only just noticed this, but it looks like your merge lost my changed 
> to the MAINTAINERS file. Want me to send a fixup patch?
> 

Whoops, sorry about that Chris.  I'll be sure to get this fixed up in
the next target-pending update.

Thanks!

--nab


^ permalink raw reply	[flat|nested] 104+ messages in thread

end of thread, other threads:[~2012-04-18  7:17 UTC | newest]

Thread overview: 104+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-17 14:51 FireWire/SBP2 Target mode Chris Boot
2011-08-17 14:51 ` Chris Boot
2011-08-17 18:57 ` Stefan Richter
2011-08-18 16:19 ` Clemens Ladisch
2012-02-01 19:50   ` Andy Grover
2012-02-01 21:41     ` Stefan Richter
2012-02-01 21:41       ` Stefan Richter
2012-02-02  9:22       ` Boaz Harrosh
2012-02-02  9:22         ` Boaz Harrosh
2012-02-02 10:09         ` Clemens Ladisch
2012-02-02 10:09           ` Clemens Ladisch
2012-02-06 13:13           ` Chris Boot
2012-02-06 14:43             ` Clemens Ladisch
2012-02-06 14:51               ` Chris Boot
2012-02-06 20:26                 ` Stefan Richter
2012-02-06 22:28                   ` Chris Boot
2012-02-06 23:00                     ` Julian Calaby
2012-02-06 23:09                       ` Chris Boot
2012-02-07  7:38                         ` Chris Boot
2012-02-07 10:06                           ` Julian Calaby
2012-02-07 19:17                           ` Stefan Richter
2012-02-07 19:53                             ` Chris Boot
2012-02-11 19:43 ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
2012-02-11 19:44   ` [PATCH 01/13] firewire: Add function to get speed from opaque struct fw_request Chris Boot
2012-02-11 19:44   ` [PATCH 02/13] firewire: Add EXPORT_SYMBOL_GPL(fw_card_release) Chris Boot
2012-02-11 19:44   ` [PATCH 03/13] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
2012-02-13 12:50     ` Nicholas A. Bellinger
2012-02-11 19:44   ` [PATCH 04/13] firewire-sbp-target: Add sbp_base.h header Chris Boot
2012-02-11 19:44   ` [PATCH 05/13] firewire-sbp-target: Add sbp_configfs.c Chris Boot
2012-02-11 19:44   ` [PATCH 06/13] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
2012-02-13 13:06     ` Nicholas A. Bellinger
     [not found]       ` <337FFBD7-6B4A-41CA-BB57-6038C935B5BF@bootc.net>
2012-02-13 19:53         ` Stefan Richter
2012-02-13 22:41         ` Nicholas A. Bellinger
2012-02-11 19:44   ` [PATCH 07/13] firewire-sbp-target: Add sbp_proto.{c,h} Chris Boot
2012-02-11 19:44   ` [PATCH 08/13] firewire-sbp-target: add sbp_management_agent.{c,h} Chris Boot
2012-02-11 19:44   ` [PATCH 09/13] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
2012-02-11 19:44   ` [PATCH 10/13] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
2012-02-11 19:44   ` [PATCH 11/13] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h} Chris Boot
2012-02-11 19:44   ` [PATCH 12/13] firewire-sbp-target: Add sbp_util.{c,h} Chris Boot
2012-02-11 19:44   ` [PATCH 13/13] firewire-sbp-target: Add to target Kconfig and Makefile Chris Boot
2012-02-12 14:12   ` [RFC][PATCH 00/13] firewire-sbp-target: FireWire SBP-2 SCSI target Stefan Richter
2012-02-12 15:13     ` Chris Boot
2012-02-12 16:16       ` Stefan Richter
2012-02-15 14:47   ` [PATCH v2 00/11] " Chris Boot
2012-02-15 14:47     ` [PATCH v2 01/11] firewire: Add function to get speed from opaque struct fw_request Chris Boot
2012-02-15 19:09       ` Stefan Richter
2012-02-15 19:10         ` Chris Boot
2012-02-15 22:01           ` Stefan Richter
2012-02-16  9:12             ` Chris Boot
2012-02-15 14:47     ` [PATCH v2 02/11] firewire: Move fw_card kref functions into linux/firewire.h Chris Boot
2012-02-15 19:10       ` Stefan Richter
2012-02-16  9:18         ` Chris Boot
2012-02-15 14:47     ` [PATCH v2 03/11] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
2012-02-15 14:47     ` [PATCH v2 04/11] firewire-sbp-target: Add sbp_base.h header Chris Boot
2012-02-15 19:15       ` Stefan Richter
2012-02-16  9:55         ` Chris Boot
2012-02-15 14:47     ` [PATCH v2 05/11] firewire-sbp-target: Add sbp_configfs.c Chris Boot
2012-02-15 19:21       ` Stefan Richter
2012-02-16  9:57         ` Chris Boot
2012-02-16 13:48           ` Stefan Richter
2012-02-15 14:47     ` [PATCH v2 06/11] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
2012-02-15 14:47     ` [PATCH v2 07/11] firewire-sbp-target: add sbp_management_agent.{c,h} Chris Boot
2012-02-15 19:48       ` Stefan Richter
2012-02-16 10:28         ` Chris Boot
2012-02-16 14:12           ` Stefan Richter
2012-02-15 14:47     ` [PATCH v2 08/11] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
2012-02-15 21:00       ` Stefan Richter
2012-02-16 11:21         ` Chris Boot
2012-03-03 17:37           ` Stefan Richter
2012-03-15 17:48             ` Paul E. McKenney
2012-02-15 14:47     ` [PATCH v2 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
2012-02-15 21:27       ` Stefan Richter
2012-02-16 11:25         ` Chris Boot
2012-02-18 14:59           ` Stefan Richter
2012-02-18 15:05             ` Chris Boot
2012-02-15 14:47     ` [PATCH v2 10/11] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h} Chris Boot
2012-02-15 14:47     ` [PATCH v2 11/11] firewire-sbp-target: Add to target Kconfig and Makefile Chris Boot
2012-04-11 14:20     ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
2012-04-11 14:20       ` [PATCH 01/11] firewire: Add function to get speed from opaque struct fw_request Chris Boot
2012-04-11 14:20       ` [PATCH 02/11] firewire: Move fw_card kref functions into linux/firewire.h Chris Boot
2012-04-11 14:20       ` [PATCH 03/11] firewire-sbp-target: Add Kconfig, Makefile and TODO Chris Boot
2012-04-11 14:20       ` [PATCH 04/11] firewire-sbp-target: Add sbp_base.h header Chris Boot
2012-04-11 14:20       ` [PATCH 05/11] firewire-sbp-target: Add sbp_configfs.c Chris Boot
2012-04-11 14:20       ` [PATCH 06/11] firewire-sbp-target: Add sbp_fabric.{c,h} Chris Boot
2012-04-11 14:20       ` [PATCH 07/11] firewire-sbp-target: Add sbp_management_agent.{c,h} Chris Boot
2012-04-11 14:20       ` [PATCH 08/11] firewire-sbp-target: Add sbp_login.{c,h} Chris Boot
2012-04-14 10:17         ` Stefan Richter
2012-04-11 14:20       ` [PATCH 09/11] firewire-sbp-target: Add sbp_target_agent.{c,h} Chris Boot
2012-04-14 10:49         ` Stefan Richter
2012-04-14 11:33           ` Stefan Richter
2012-04-11 14:20       ` [PATCH 10/11] firewire-sbp-target: Add sbp_scsi_cmnd.{c,h} Chris Boot
2012-04-11 14:20       ` [PATCH 11/11] firewire-sbp-target: Add to target Kconfig and Makefile Chris Boot
2012-04-12 21:02       ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Andy Grover
2012-04-13  3:03       ` Nicholas A. Bellinger
2012-04-13 13:16         ` Chris Boot
2012-04-14  1:23           ` Nicholas A. Bellinger
2012-04-14  9:12             ` [PATCH 0/2] sbp-target: cleanup after merge into single file Chris Boot
2012-04-14  9:12               ` [PATCH 1/2] sbp-target: minor cleanups after merging " Chris Boot
2012-04-14  9:12               ` [PATCH 2/2] sbp-target: update TODO file Chris Boot
2012-04-14 21:44               ` [PATCH 0/2] sbp-target: cleanup after merge into single file Nicholas A. Bellinger
2012-04-14 23:11                 ` Stefan Richter
2012-04-15  1:22                   ` Nicholas A. Bellinger
2012-04-17 10:48             ` [PATCH v3 00/11] firewire-sbp-target: FireWire SBP-2 SCSI target Chris Boot
2012-04-18  7:17               ` Nicholas A. Bellinger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.