Skip to contentSkip to conversation

libfc, libfcoe and fcoe updates for scsi-misc

PATCH In review Robert Love 3 participants 34 messages Jul 20, 2010 – Jul 30, 2010

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover libfc, libfcoe and fcoe updates for scsi-misc

The following series implements multiple bug fixes, FCoE VN2VN mode and a VLAN ID patch revert.

VN2VN is a point-to-multipoint FCoE mode. It allows direct connections from the initiator to VN2VN capable FCoE targets.

The VLAN ID revert removes the VLAN ID from the generated WWPN. Adding the VLAN ID to the WWPN is not typical and can cause zoning issues in a variety of scenarios. Note that this change will cause a one time rezone for the new WWPN.

Please apply these patches to scsi-misc.

---

Bart Van Assche (1):
fcoe: make it possible to verify fcoe with sparse

Bhanu Prakash Gollapudi (1):
libfc: Add retry logic to lport state machine when receiving LS_RJT

Joe Eykholt (19):
libfc: convert rport lookup to be RCU safe
libfc: provide space for LLD after remote port structure
libfcoe: convert FIP to lock with mutex instead of spin lock
libfc: add discovery-private pointer for LLD
libfcoe: fcoe: fnic: change fcoe_ctlr_init interface to specify mode
libfc: Add local port point-to-multipoint flag
libfc: add FLOGI state to rport for VN2VN
libfc: track FIP exchanges
libfcoe: add protocol description of FIP VN2VN mode
libfcoe: add state change debugging
libfcoe: fcoe: fnic: add FIP VN2VN point-to-multipoint support
libfcoe: Fix FIP ELS encapsulation details for FLOGI responses fcoe libfcoe: use correct FC-MAP for VN2VN mode
fcoe: config via separate create_vn2vn module parameter
libfc: eliminate rport LOGO state
libfc: add fc_frame_sid() and fc_frame_did() functions
libfc: add fc_fill_reply_hdr() and fc_fill_hdr()
libfc: add interface to allocate a sequence for incoming requests
libfc: don't require a local exchange for incoming requests

Vasu Dev (5):
libfc: IO errors on link down due to cable unplug
fcoe: cleans up fcoe_disable and fcoe_enable
fcoe: adds src and dest mac address checking for fcoe frames Revert "[SCSI] fcoe: Fix using VLAN ID in creating lport's WWWN/WWPN"
fcoe: remove check for zero fabric name

Yi Zou (2):
libfc: fix slowpath error from WARN_ON in fc_fcp_send_data
fcoe: fix offload feature flag change from netdev

 drivers/scsi/fcoe/fcoe.c      |  147 +++--
 drivers/scsi/fcoe/libfcoe.c   | 1306 ++++++++++++++++++++++++++++++++++++-----
 drivers/scsi/fnic/fnic_main.c |   11 
 drivers/scsi/libfc/fc_disc.c  |   39 +
 drivers/scsi/libfc/fc_elsct.c |    2 
 drivers/scsi/libfc/fc_exch.c  |  215 ++++---
 drivers/scsi/libfc/fc_fcp.c   |   13 
 drivers/scsi/libfc/fc_libfc.c |   78 ++
 drivers/scsi/libfc/fc_libfc.h |    2 
 drivers/scsi/libfc/fc_lport.c |  210 +++----
 drivers/scsi/libfc/fc_rport.c |  564 +++++++++++-------
 include/scsi/fc/fc_els.h      |    2 
 include/scsi/fc/fc_fip.h      |   46 +
 include/scsi/fc/fc_ns.h       |    7 
 include/scsi/fc_encode.h      |    7 
 include/scsi/fc_frame.h       |   52 ++
 include/scsi/libfc.h          |   68 +-
 include/scsi/libfcoe.h        |   72 ++
 18 files changed, 2157 insertions(+), 684 deletions(-)
Signature · 1 line
Thanks, //Rob
#1 lore raw

PATCH 1/28 libfc: fix slowpath error from WARN_ON in fc_fcp_send_data

From: Yi Zou <[email protected]>

This is exposed by a mpio test using EMC CLARiiON targets when LUN tresspassing happens, the burst length from the XFER_READY for the MODE SELECT(10) is 19 bytes, much smaller than FC_MIN_MAX_PAYLOAD as 256 bytes. This patch removes the related two WARN_ON()s.

---
 drivers/scsi/libfc/fc_fcp.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)
drivers/scsi/libfc/fc_fcp.c +0 -2
index 8914f1e..a0a3ae7 100644
@@ -580,10 +580,8 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq,
 			   fsp, seq_blen, lport->lso_max, t_blen);
 	}
 
-	WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD);
 	if (t_blen > 512)
 		t_blen &= ~(512 - 1);	/* round down to block size */
-	WARN_ON(t_blen < FC_MIN_MAX_PAYLOAD);	/* won't go below 256 */
 	sc = fsp->cmd;
 
 	remaining = seq_blen;
#2 lore raw

PATCH 2/28 fcoe: make it possible to verify fcoe with sparse

In reply to Robert Love

From: Bart Van Assche <[email protected]>

Analyzing fcoe with sparse currently fails. This is because struct fcoe_rcv_info contains two enum members that have been declared with __attribute__((packed)). Apparently gcc honors this attribute while sparse ignores it. The result is that sizeof(struct fcoe_rcv_info)
== sizeof(struct sk_buff::cb) == 48 on a 64-bit system according to gcc, but not according to sparse. The patch below modifies the definition of struct fcoe_rcv_info such that gcc and sparse interpret this structure definition in the same way. The current sparse output is as follows:

$ cd linux-2.6.34
$ make C=2 M=drivers/scsi/fcoe modules
 CHECK   drivers/scsi/fcoe/fcoe.c

include/scsi/fc_frame.h:81:9: error: invalid bitfield width, -1.
CC [M] drivers/scsi/fcoe/fcoe.o
CHECK drivers/scsi/fcoe/libfcoe.c

include/scsi/fc_frame.h:81:9: error: invalid bitfield width, -1. drivers/scsi/fcoe/libfcoe.c:56:37: error: invalid initializer

---
 include/scsi/fc_frame.h |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)
include/scsi/fc_frame.h +2 -2
index 4d3e9c7..15427fa 100644
@@ -66,8 +66,8 @@ struct fcoe_rcv_info {
 	struct fc_fcp_pkt *fr_fsp;	/* for the corresponding fcp I/O */
 	u32		fr_crc;
 	u16		fr_max_payload;	/* max FC payload */
-	enum fc_sof	fr_sof;		/* start of frame delimiter */
-	enum fc_eof	fr_eof;		/* end of frame delimiter */
+	u8		fr_sof;		/* start of frame delimiter */
+	u8		fr_eof;		/* end of frame delimiter */
 	u8		fr_flags;	/* flags - see below */
 	u8		granted_mac[ETH_ALEN]; /* FCoE MAC address */
 };
#3 lore raw

PATCH 3/28 libfc: IO errors on link down due to cable unplug

In reply to Robert Love

From: Vasu Dev <[email protected]>

In this case, sync IO fails with EIO(5) errors as:-

"Thread:1 System call error:5 - Input/output error (::pwrite() failed)".

This is due to IO time out while libfc doing link down processing to block all rports and if timed out IO was at last retry attempt then it fails to user with EIO error followed by these log messages.

[77848.612169] host2: rport bf0015: Delete port
[77848.612221] host2: rport e10aef: work delete
[77848.612232] host2: rport e10002: work event 3
[77848.612422] sd 2:0:1:1: [sdi] Unhandled error code
[77848.612426] sd 2:0:1:1: [sdi] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[77848.612431] sd 2:0:1:1: [sdi] CDB: Write(10): 2a 00 00 00 11 20 00 00 20 00
[77848.612445] end_request: I/O error, dev sdi, sector 4384
[77848.612553] sd 2:0:1:2: [sdj] Unhandled error code

To fix these EIO errors, such timed out incomplete IOs needs to be re-queued without counting retry attempt and this patch does that using DID_REQUEUE scsi code.

---
 drivers/scsi/libfc/fc_fcp.c |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_fcp.c +5 -0
index a0a3ae7..61a1297 100644
@@ -1971,6 +1971,11 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
 		break;
 	}
 
+	if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE) {
+		sc_cmd->result = (DID_REQUEUE << 16);
+		FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n");
+	}
+
 	spin_lock_irqsave(&si->scsi_queue_lock, flags);
 	list_del(&fsp->list);
 	spin_unlock_irqrestore(&si->scsi_queue_lock, flags);
#4 lore raw

Re: [PATCH 03/28] libfc: IO errors on link down due to cable unplug

Quoted 36 lines · Robert Love

From: Vasu Dev<[email protected]>

In this case, sync IO fails with EIO(5) errors as:-

"Thread:1 System call error:5 - Input/output error (::pwrite() failed)".

This is due to IO time out while libfc doing link down processing to block all rports and if timed out IO was at last retry attempt then it fails to user with EIO error followed by these log messages.

[77848.612169] host2: rport bf0015: Delete port
[77848.612221] host2: rport e10aef: work delete
[77848.612232] host2: rport e10002: work event 3
[77848.612422] sd 2:0:1:1: [sdi] Unhandled error code
[77848.612426] sd 2:0:1:1: [sdi] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[77848.612431] sd 2:0:1:1: [sdi] CDB: Write(10): 2a 00 00 00 11 20 00 00 20 00
[77848.612445] end_request: I/O error, dev sdi, sector 4384
[77848.612553] sd 2:0:1:2: [sdj] Unhandled error code

To fix these EIO errors, such timed out incomplete IOs needs to be re-queued without counting retry attempt and this patch does that using DID_REQUEUE scsi code.

---
  drivers/scsi/libfc/fc_fcp.c |    5 +++++
  1 files changed, 5 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_fcp.c +0 -0
index a0a3ae7..61a1297 100644

drivers/scsi/libfc/fc_fcp.c static void fc_io_compl(struct fc_fcp_pkt *fsp) · line 1978

Quoted 8 lines
drivers/scsi/libfc/fc_fcp.c +5 -0
@@ -1971,6 +1971,11 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
  		break;
  	}
 
+	if (lport->state != LPORT_ST_READY&&  fsp->status_code != FC_COMPLETE) {
+		sc_cmd->result = (DID_REQUEUE<<  16);
+		FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n");
+	}
+

If it is a tape command, you do not want to use DID_REQUEUE do you?

You are using the fc class API to delete the rport in this scenario, right? If so normally I think you would use DID_TRANSPORT_DISRUPTED. This is going to give you an error if it is the last retry like DID_ERROR though.

It seems weird to try and work around the IO erorr in this case because it is the last retry so it should fail. If the port keeps going down and up, then with your patch you could keep retrying the IO forever.

This isn't one of those races where you are blocking the rport, but the IO keeps coming around so the retries are used really quickly right (the driver looks like it has the fc class and internal state checks to prevent this but I wanted to make sure).

#5 lore raw

Re: [PATCH 03/28] libfc: IO errors on link down due to cable unplug

Quoted 40 lines · Mike Christie
Quoted 39 lines · Robert Love

From: Vasu Dev<[email protected]>

In this case, sync IO fails with EIO(5) errors as:-

"Thread:1 System call error:5 - Input/output error (::pwrite() failed)".

This is due to IO time out while libfc doing link down processing to block all rports and if timed out IO was at last retry attempt then it fails to user with EIO error followed by these log messages.

[77848.612169] host2: rport bf0015: Delete port
[77848.612221] host2: rport e10aef: work delete
[77848.612232] host2: rport e10002: work event 3
[77848.612422] sd 2:0:1:1: [sdi] Unhandled error code
[77848.612426] sd 2:0:1:1: [sdi] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[77848.612431] sd 2:0:1:1: [sdi] CDB: Write(10): 2a 00 00 00 11 20 00 00 20 00
[77848.612445] end_request: I/O error, dev sdi, sector 4384
[77848.612553] sd 2:0:1:2: [sdj] Unhandled error code

To fix these EIO errors, such timed out incomplete IOs needs to be re-queued without counting retry attempt and this patch does that using DID_REQUEUE scsi code.

---
  drivers/scsi/libfc/fc_fcp.c |    5 +++++
  1 files changed, 5 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_fcp.c +0 -0
index a0a3ae7..61a1297 100644
@@ -1971,6 +1971,11 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
  		break;
  	}
 
Quoted 8 lines

drivers/scsi/libfc/fc_fcp.c static void fc_io_compl(struct fc_fcp_pkt *fsp) · line 1978

Quoted 5 lines
drivers/scsi/libfc/fc_fcp.c +5 -0
+	if (lport->state != LPORT_ST_READY&&  fsp->status_code != FC_COMPLETE) {
+		sc_cmd->result = (DID_REQUEUE<<  16);
+		FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n");
+	}
+

If it is a tape command, you do not want to use DID_REQUEUE do you?

I wasn't sure of using DID_REQUEUE here and therefore I did RFC first at
http://www.open-fcoe.org/pipermail/devel/2010-June/010360.html. As I understand DID_REQUEUE would block the sdev and would do unconditional retry and now I see that is issue with tapes as you pointed above, so I'll remove its use here but help me understand use of DID_REQUEUE, I mean are LLLD expected to make additional checks before indicating DID_REQUEUE to scsi-ml ?

Quoted 2 lines

You are using the fc class API to delete the rport in this scenario, right?

Yes.

Quoted 4 lines

If so normally I think you would use DID_TRANSPORT_DISRUPTED. This is going to give you an error if it is the last retry like DID_ERROR though.

Effectively both would do same, so changing DID_TRANSPORT_DISRUPTED won't change anything or perhaps I'm missing something here.

Quoted 4 lines

It seems weird to try and work around the IO erorr in this case because it is the last retry so it should fail. If the port keeps going down and up, then with your patch you could keep retrying the IO forever.

I think last try should not fail due to link down if rports comes back before dev_loss_tmo or fast_io_fail_tmo, such IOs should get their last try attempt again once rport are back instead throwing IO error just before port is getting blocked, that is the whole purpose of rport block states.

Quoted 4 lines

This isn't one of those races where you are blocking the rport, but the IO keeps coming around so the retries are used really quickly right (the driver looks like it has the fc class and internal state checks to prevent this but I wanted to make sure).

I'm trying to fix IO error due to failed last attempt on a IO just after link down and its rport yet to move to block state from pending rport event_work. The libfc already has checks once rport or lport no longer ready for new IO try and that is not an issue here. It is very rare case with very tiny time window as rport block, so I can replace DID_REQUEUE here by DID_IMM_RETRY and I verified that works, will that be okay ?

This tiny time windows can be further reduced by use of wmb() on rport state change to block and lport getting out of ready since their states are checked w/o lock in queuecommand path. I can do that as separate patch only if needed and it really helps some corner case.

Sorry for being late on this and I just noticed James just applied this patch, so I'll provide separate patch to remove DID_REQUEUE for tape devices.

Thanks
Vasu

Quoted 4 lines

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#6 lore raw

Re: [PATCH 03/28] libfc: IO errors on link down due to cable unplug

Quoted 50 lines · Vasu Dev
Quoted 40 lines · Mike Christie
Quoted 39 lines · Robert Love

From: Vasu Dev<[email protected]>

In this case, sync IO fails with EIO(5) errors as:-

"Thread:1 System call error:5 - Input/output error (::pwrite() failed)".

This is due to IO time out while libfc doing link down processing to block all rports and if timed out IO was at last retry attempt then it fails to user with EIO error followed by these log messages.

[77848.612169] host2: rport bf0015: Delete port
[77848.612221] host2: rport e10aef: work delete
[77848.612232] host2: rport e10002: work event 3
[77848.612422] sd 2:0:1:1: [sdi] Unhandled error code
[77848.612426] sd 2:0:1:1: [sdi] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[77848.612431] sd 2:0:1:1: [sdi] CDB: Write(10): 2a 00 00 00 11 20 00 00 20 00
[77848.612445] end_request: I/O error, dev sdi, sector 4384
[77848.612553] sd 2:0:1:2: [sdj] Unhandled error code

To fix these EIO errors, such timed out incomplete IOs needs to be re-queued without counting retry attempt and this patch does that using DID_REQUEUE scsi code.

---
   drivers/scsi/libfc/fc_fcp.c |    5 +++++
   1 files changed, 5 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_fcp.c +0 -0
index a0a3ae7..61a1297 100644
@@ -1971,6 +1971,11 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp)
   		break;
   	}
 
Quoted 8 lines

drivers/scsi/libfc/fc_fcp.c static void fc_io_compl(struct fc_fcp_pkt *fsp) · line 1978

Quoted 5 lines
drivers/scsi/libfc/fc_fcp.c +5 -0
+	if (lport->state != LPORT_ST_READY&&   fsp->status_code != FC_COMPLETE) {
+		sc_cmd->result = (DID_REQUEUE<<   16);
+		FC_FCP_DBG(fsp, "Returning DID_REQUEUE to scsi-ml\n");
+	}
+

If it is a tape command, you do not want to use DID_REQUEUE do you?

Quoted 7 lines

I wasn't sure of using DID_REQUEUE here and therefore I did RFC first at
http://www.open-fcoe.org/pipermail/devel/2010-June/010360.html. As I understand DID_REQUEUE would block the sdev and would do unconditional retry and now I see that is issue with tapes as you pointed above, so I'll remove its use here but help me understand use of DID_REQUEUE, I mean are LLLD expected to make additional checks before indicating DID_REQUEUE to scsi-ml ?

I think you would want to use it in case where you want to block the sdev and you know the IO had not started. So some drivers use it if they get an error the indicated the port/target rejected the IO before it even started and there might be a tmp resource issue.

Quoted 6 lines
Quoted 3 lines

You are using the fc class API to delete the rport in this scenario, right?

Yes.

Quoted 7 lines
Quoted 4 lines

If so normally I think you would use DID_TRANSPORT_DISRUPTED. This is going to give you an error if it is the last retry like DID_ERROR though.

Effectively both would do same, so changing DID_TRANSPORT_DISRUPTED won't change anything or perhaps I'm missing something here.

The behavior is the same, but the error code that gets logged is more clear I think.

Quoted 11 lines
Quoted 5 lines

It seems weird to try and work around the IO erorr in this case because it is the last retry so it should fail. If the port keeps going down and up, then with your patch you could keep retrying the IO forever.

I think last try should not fail due to link down if rports comes back before dev_loss_tmo or fast_io_fail_tmo, such IOs should get their last try attempt again once rport are back instead throwing IO error just before port is getting blocked, that is the whole purpose of rport block states.

Just to make sure we are on the same page. Didn't the command get a chance to run on its last retry, but the port came down while it was executing. I am just saying that should count as a try, but with your patch you are giving it another retry. So instead of 5 it gets 6. And actually you are throwing out retries for this case so it runs until it times out (times out in scsi_softirq_done).

If you want that behavior and people argee it is the right think to do then I think we should apply it to all drivers, so users can expect the same behavior. Use DID_TRANSPORT_DISRUPTED in the driver, but then in scsi_error.c change that to check for tape devices. In the non tape case then just always retry until the command times out (time out in scsi_softirq_done. I do not mean timeout like when the scsi eh runs).

If the command never got a chance to start, then forget all this. I am wrong and DID_REQUEUE is fine.

Quoted 6 lines
Quoted 5 lines

This isn't one of those races where you are blocking the rport, but the IO keeps coming around so the retries are used really quickly right (the driver looks like it has the fc class and internal state checks to prevent this but I wanted to make sure).

Quoted 6 lines

I'm trying to fix IO error due to failed last attempt on a IO just after link down and its rport yet to move to block state from pending rport event_work. The libfc already has checks once rport or lport no longer ready for new IO try and that is not an issue here. It is very rare case with very tiny time window as rport block, so I can replace DID_REQUEUE here by DID_IMM_RETRY and I verified that works, will that be okay ?

DID_IMM_RETRY has the exact same issues.

Quoted 6 lines

This tiny time windows can be further reduced by use of wmb() on rport state change to block and lport getting out of ready since their states are checked w/o lock in queuecommand path. I can do that as separate patch only if needed and it really helps some corner case.

That is not really the issue.

#7 lore raw

Re: [PATCH 03/28] libfc: IO errors on link down due to cable unplug

In reply to Vasu Dev
Quoted 5 lines · Vasu Dev
Quoted 4 lines

This isn't one of those races where you are blocking the rport, but the IO keeps coming around so the retries are used really quickly right (the driver looks like it has the fc class and internal state checks to prevent this but I wanted to make sure).

I think I am hitting the above problem.

Quoted 4 lines

This tiny time windows can be further reduced by use of wmb() on rport state change to block and lport getting out of ready since their states are checked w/o lock in queuecommand path.

I think you need something like this for the lport queue ready check. It looks like the initial failure from __fc_linkdown->fc_fcp_cleanup burned a timeout. Then because it missed the lport ready check, it will use an extra retry just sitting there timing out.

For the rport state check, I think you are supposed to call the fc chkready function under the host lock. The port state and flags are set under it. I did the attached patch for that.

libfc: call fc_remote_port_chkready under the host lock.

The rport port state and flags are set under the host lock, so this patch calls fc_remote_port_chkready with the host lock held like is also done in the other fc drivers.

drivers/scsi/libfc/fc_fcp.c +2 -2
index eac4d09..a116846 100644
@@ -1765,14 +1768,14 @@ int fc_queuecommand(struct scsi_cmnd *sc_cmd, void (*done)(struct scsi_cmnd *))
 	struct fcoe_dev_stats *stats;
 
 	lport = shost_priv(sc_cmd->device->host);
-	spin_unlock_irq(lport->host->host_lock);
 
 	rval = fc_remote_port_chkready(rport);
 	if (rval) {
 		sc_cmd->result = rval;
 		done(sc_cmd);
-		goto out;
+		return 0;
 	}
+	spin_unlock_irq(lport->host->host_lock);
 
 	if (!*(struct fc_remote_port **)rport->dd_data) {
 		/*
#8 lore raw

Re: [PATCH 03/28] libfc: IO errors on link down due to cable unplug

Quoted 14 lines · Mike Christie
Quoted 5 lines · Vasu Dev
Quoted 4 lines

This isn't one of those races where you are blocking the rport, but the IO keeps coming around so the retries are used really quickly right (the driver looks like it has the fc class and internal state checks to prevent this but I wanted to make sure).

I think I am hitting the above problem.

Quoted 4 lines

This tiny time windows can be further reduced by use of wmb() on rport state change to block and lport getting out of ready since their states are checked w/o lock in queuecommand path.

Quoted 8 lines

I think you need something like this for the lport queue ready check. It looks like the initial failure from __fc_linkdown->fc_fcp_cleanup burned a timeout. Then because it missed the lport ready check, it will use an extra retry just sitting there timing out.

For the rport state check, I think you are supposed to call the fc chkready function under the host lock. The port state and flags are set under it. I did the attached patch for that.

I tried attached patch w/o this series and that didn't work and I got same IO errors on link down. However once I included my next patch 4/28 related to IO error fix then attached patch worked w/o having this patch under discussion, so attached patch works w/o this patch and I agree rport needs to be checked under lock to get up-to-date correct rport state checking in fc_queueucommand, so can you submit this patch ?

I'll submit another patch to replace added DID_REQUEUE here as this series already applied to scsi-misc, I'll replace this by DID_TRANSPORT_DISRUPTED since added DID_REQUEUE could be returned for attempted tape IO as you pointed in other response and having DID_TRANSPORT_DISRUPTED would be more meaningful code as lport is not ready in this case to complete IOs.

Below is IO error log with attached patch w/o this series just after ixgbe link goes down :-

[  452.168644] ixgbe: eth3 NIC Link is Down
[  452.180427] sd 5:0:0:2: [sdd] Done:
[  452.180436] sd 5:0:0:3: [sde] Done: RETRY
[  452.180441] sd 5:0:0:3: [sde] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.180445] sd 5:0:0:3: [sde] CDB: Write(10): 2a 00 00 07 91 80 00 00
80 00
[  452.180464] sd 5:0:0:1: [sdc] Done: RETRY
[  452.180467] sd 5:0:0:1: [sdc] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.180469] sd 5:0:0:1: [sdc] CDB: Write(10): 2a 00 00 07 cf 00 00 00
80 00
[  452.181792] RETRY
[  452.181963] sd 5:0:0:2: [sdd] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.182241] sd 5:0:0:2: [sdd] CDB: Write(10): 2a 00 00 07 ac 00 00 00
80 00
[  452.183294] sd 5:0:0:2: [sdd] Done:
[  452.183326] sd 5:0:0:0: [sdb] Done: RETRY
[  452.183329] sd 5:0:0:0: [sdb] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.183332] sd 5:0:0:0: [sdb] CDB: Write(10): 2a 00 00 07 99 00 00 00
80 00
[  452.184089] RETRY
[  452.184262] sd 5:0:0:2: [sdd] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.184514] sd 5:0:0:2: [sdd] CDB: Write(10): 2a 00 00 07 ac 00 00 00
80 00
[  452.185557] sd 5:0:0:2: [sdd] Done: RETRY
[  452.185798] sd 5:0:0:2: [sdd] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.186050] sd 5:0:0:2: [sdd] CDB: Write(10): 2a 00 00 07 ac 00 00 00
80 00
[  452.187101] sd 5:0:0:2: [sdd] Done: RETRY
[  452.187373] sd 5:0:0:2: [sdd] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.187633] sd 5:0:0:2: [sdd] CDB: Write(10): 2a 00 00 07 ac 00 00 00
80 00
[  452.188691] sd 5:0:0:2: [sdd] Done: RETRY
[  452.188932] sd 5:0:0:2: [sdd] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK[  452.189184] sd 5:0:0:2: [sdd] CDB: Write(10): 2a
00 00 07 ac 00 00 00 80 00
[  452.190499] sd 5:0:0:2: [sdd] Done: SUCCESS
[  452.190748] sd 5:0:0:2: [sdd] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.190999] sd 5:0:0:2: [sdd] CDB: Write(10): 2a 00 00 07 ac 00 00 00
80 00
[  452.192033] sd 5:0:0:2: [sdd] Unhandled error code
[  452.192244] sd 5:0:0:2: [sdd] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.192495] sd 5:0:0:2: [sdd] CDB: Write(10): 2a 00 00 07 ac 00 00 00
80 00
[  452.193526] end_request: I/O error, dev sdd, sector 502784
[  452.193820] host5: libfc: Link down on port (050b01)
[  452.194006] sd 5:0:0:3: [sde] Done: RETRY
[  452.194262] sd 5:0:0:3: [sde] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.194507] sd 5:0:0:3: [sde] CDB: Write(10): 2a 00 00 07 91 80 00 00
80 00
[  452.195525] sd 5:0:0:1: [sdc] Done: RETRY
[  452.195790] sd 5:0:0:1: [sdc] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.196033] sd 5:0:0:1: [sdc] CDB: Write(10): 2a 00 00 07 cf 00 00 00
80 00
[  452.197076] sd 5:0:0:0: [sdb] Done: RETRY
[  452.197354] sd 5:0:0:0: [sdb] Result: hostbyte=DID_ERROR
driverbyte=DRIVER_OK
[  452.197620] sd 5:0:0:0: [sdb] CDB: Write(10): 2a 00 00 07 99 00 00 00
80 00
[  459.476688] ixgbe: eth3 NIC Link is Up 10 Gbps, Flow Control: None
[  464.287400] host5: libfc: Link up on port (050b01)
[  466.304340] libfcoe: host5: FIP selected Fibre-Channel Forwarder MAC

00:05:1e:d8:2f:03

In above log, IO error occurred even before libfc could start acting on
link down at [452.193820] to block rports but once rport blocked your attached patch helps as I said above.

Thanks
Vasu

#9 lore raw

PATCH 4/28 fcoe: cleans up fcoe_disable and fcoe_enable

In reply to Robert Love

From: Vasu Dev <[email protected]>

The fc_fabric_logoff and fc_fabric_login are redundant here after recently added fcoe_ctlr_link_down/up to these functions, therefore this patch removes logoff and login to only use link down and up here. This works best for their current usages with fcoe DCB link down or up.

This also works well to avoid EIO errors when fcoe DCB link goes down as lport state moves out of ready quickly from fcoe_ctlr_link_down and that allows re-queuing timed out IOs for this case also.

---
 drivers/scsi/fcoe/fcoe.c |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)
drivers/scsi/fcoe/fcoe.c +4 -6
index 44a0759..d340cf2 100644
@@ -1918,8 +1918,8 @@ static int fcoe_disable(const char *buffer, struct kernel_param *kp)
 	rtnl_unlock();
 
 	if (fcoe) {
-		fc_fabric_logoff(fcoe->ctlr.lp);
 		fcoe_ctlr_link_down(&fcoe->ctlr);
+		fcoe_clean_pending_queue(fcoe->ctlr.lp);
 	} else
 		rc = -ENODEV;
 
@@ -1972,12 +1972,10 @@ static int fcoe_enable(const char *buffer, struct kernel_param *kp)
 	fcoe = fcoe_hostlist_lookup_port(netdev);
 	rtnl_unlock();
 
-	if (fcoe) {
-		if (!fcoe_link_ok(fcoe->ctlr.lp))
-			fcoe_ctlr_link_up(&fcoe->ctlr);
-		rc = fc_fabric_login(fcoe->ctlr.lp);
-	} else
+	if (!fcoe)
 		rc = -ENODEV;
+	else if (!fcoe_link_ok(fcoe->ctlr.lp))
+		fcoe_ctlr_link_up(&fcoe->ctlr);
 
 	dev_put(netdev);
 out_nodev:
#10 lore raw

PATCH 5/28 fcoe: adds src and dest mac address checking for fcoe frames

In reply to Robert Love

From: Vasu Dev <[email protected]>

This is per FC-BB-5 Annex-D recommendation and per that if address checking fails then drop the frame.

FIP code paths are already doing this so only needed for fcoe frames.

The src address checking is limited to only fip mode since this might break non-fip mode used in p2p due to used OUI based addressing in some p2p code paths, going forward FIP will be the only mode, therefore limited this to only FIP mode so that it won't break non-fip p2p mode for now.

-v2
Removes FCOE packet type checking since fcoe_rcv is registered to receive only FCoE type packets from netdev and it is already checked by netdev.

---
 drivers/scsi/fcoe/fcoe.c |   20 +++++++++++++++++---
 include/scsi/libfcoe.h   |   10 ++++++++++
 2 files changed, 27 insertions(+), 3 deletions(-)
drivers/scsi/fcoe/fcoe.c +17 -3
index d340cf2..a120962 100644
@@ -1210,6 +1210,8 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
 	struct fcoe_interface *fcoe;
 	struct fc_frame_header *fh;
 	struct fcoe_percpu_s *fps;
+	struct fcoe_port *port;
+	struct ethhdr *eh;
 	unsigned int cpu;
 
 	fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type);
@@ -1227,9 +1229,21 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev,
 			skb_tail_pointer(skb), skb_end_pointer(skb),
 			skb->csum, skb->dev ? skb->dev->name : "<NULL>");
 
-	/* check for FCOE packet type */
-	if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) {
-		FCOE_NETDEV_DBG(netdev, "Wrong FC type frame");
+	/* check for mac addresses */
+	eh = eth_hdr(skb);
+	port = lport_priv(lport);
+	if (compare_ether_addr(eh->h_dest, port->data_src_addr) &&
+	    compare_ether_addr(eh->h_dest, fcoe->ctlr.ctl_src_addr) &&
+	    compare_ether_addr(eh->h_dest, (u8[6])FC_FCOE_FLOGI_MAC)) {
+		FCOE_NETDEV_DBG(netdev, "wrong destination mac address:%pM\n",
+				eh->h_dest);
+		goto err;
+	}
+
+	if (is_fip_mode(&fcoe->ctlr) &&
+	    compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) {
+		FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n",
+				eh->h_source);
 		goto err;
 	}
 
include/scsi/libfcoe.h +10 -0
index ec13f51..81aee1c 100644
@@ -170,4 +170,14 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *, struct fc_lport *,
 u64 fcoe_wwn_from_mac(unsigned char mac[], unsigned int, unsigned int);
 int fcoe_libfc_config(struct fc_lport *, struct libfc_function_template *);
 
+/**
+ * is_fip_mode() - returns true if FIP mode selected.
+ * @fip:	FCoE controller.
+ */
+static inline bool is_fip_mode(struct fcoe_ctlr *fip)
+{
+	return fip->state == FIP_ST_ENABLED;
+}
+
+
 #endif /* _LIBFCOE_H */
#11 lore raw

PATCH 6/28 libfc: convert rport lookup to be RCU safe

In reply to Robert Love

From: Joe Eykholt <[email protected]>

To allow LLD to do lookups on rports without grabbing a mutex, make them RCU-safe. The caller of lport->tt.rport_lookup will have the choice of holding disc_mutex or the rcu_read_lock().

---
 drivers/scsi/libfc/fc_disc.c  |    6 +++---
 drivers/scsi/libfc/fc_rport.c |   22 ++++++++++++++++++----
 include/scsi/libfc.h          |    2 ++
 3 files changed, 23 insertions(+), 7 deletions(-)
drivers/scsi/libfc/fc_disc.c +3 -3
index c7985da..d0fa9a0 100644
@@ -63,12 +63,12 @@ static void fc_disc_restart(struct fc_disc *);
 void fc_disc_stop_rports(struct fc_disc *disc)
 {
 	struct fc_lport *lport;
-	struct fc_rport_priv *rdata, *next;
+	struct fc_rport_priv *rdata;
 
 	lport = disc->lport;
 
 	mutex_lock(&disc->disc_mutex);
-	list_for_each_entry_safe(rdata, next, &disc->rports, peers)
+	list_for_each_entry_rcu(rdata, &disc->rports, peers)
 		lport->tt.rport_logoff(rdata);
 	mutex_unlock(&disc->disc_mutex);
 }
@@ -292,7 +292,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
 	 * Skip ports which were never discovered.  These are the dNS port
 	 * and ports which were created by PLOGI.
 	 */
-	list_for_each_entry(rdata, &disc->rports, peers) {
+	list_for_each_entry_rcu(rdata, &disc->rports, peers) {
 		if (!rdata->disc_id)
 			continue;
 		if (rdata->disc_id == disc->disc_id)
drivers/scsi/libfc/fc_rport.c +18 -4
index 363cde3..6b56973 100644
@@ -95,13 +95,15 @@ static const char *fc_rport_state_names[] = {
  * fc_rport_lookup() - Lookup a remote port by port_id
  * @lport:   The local port to lookup the remote port on
  * @port_id: The remote port ID to look up
+ *
+ * The caller must hold either disc_mutex or rcu_read_lock().
  */
 static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport,
 					     u32 port_id)
 {
 	struct fc_rport_priv *rdata;
 
-	list_for_each_entry(rdata, &lport->disc.rports, peers)
+	list_for_each_entry_rcu(rdata, &lport->disc.rports, peers)
 		if (rdata->ids.port_id == port_id)
 			return rdata;
 	return NULL;
@@ -146,11 +148,23 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
 	INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout);
 	INIT_WORK(&rdata->event_work, fc_rport_work);
 	if (port_id != FC_FID_DIR_SERV)
-		list_add(&rdata->peers, &lport->disc.rports);
+		list_add_rcu(&rdata->peers, &lport->disc.rports);
 	return rdata;
 }
 
 /**
+ * fc_rport_free_rcu() - Free a remote port
+ * @rcu: The rcu_head structure inside the remote port
+ */
+static void fc_rport_free_rcu(struct rcu_head *rcu)
+{
+	struct fc_rport_priv *rdata;
+
+	rdata = container_of(rcu, struct fc_rport_priv, rcu);
+	kfree(rdata);
+}
+
+/**
  * fc_rport_destroy() - Free a remote port after last reference is released
  * @kref: The remote port's kref
  */
@@ -159,7 +173,7 @@ static void fc_rport_destroy(struct kref *kref)
 	struct fc_rport_priv *rdata;
 
 	rdata = container_of(kref, struct fc_rport_priv, kref);
-	kfree(rdata);
+	call_rcu(&rdata->rcu, fc_rport_free_rcu);
 }
 
 /**
@@ -334,7 +348,7 @@ static void fc_rport_work(struct work_struct *work)
 				mutex_unlock(&rdata->rp_mutex);
 			} else {
 				FC_RPORT_DBG(rdata, "work delete\n");
-				list_del(&rdata->peers);
+				list_del_rcu(&rdata->peers);
 				mutex_unlock(&rdata->rp_mutex);
 				kref_put(&rdata->kref, lport->tt.rport_destroy);
 			}
include/scsi/libfc.h +2 -0
index 6d78df7..b0310b9 100644
@@ -195,6 +195,7 @@ struct fc_rport_libfc_priv {
  * @rp_mutex:       The mutex that protects the remote port
  * @retry_work:     Handle for retries
  * @event_callback: Callback when READY, FAILED or LOGO states complete
+ * @rcu:	    Structure used for freeing in an RCU-safe manner
  */
 struct fc_rport_priv {
 	struct fc_lport		    *local_port;
@@ -217,6 +218,7 @@ struct fc_rport_priv {
 	struct list_head            peers;
 	struct work_struct          event_work;
 	u32			    supported_classes;
+	struct rcu_head		    rcu;
 };
 
 /**
#12 lore raw

PATCH 7/28 libfc: provide space for LLD after remote port structure

In reply to Robert Love

From: Joe Eykholt <[email protected]>

Add pre-zeroed space after the allocation for fc_rport_priv for use by the lower-level driver.

This is primarily for VN2VN FIP mode, but could be used in other ways someday.

The space required is specified in lport->rport_priv_size.

---
 drivers/scsi/libfc/fc_rport.c |    2 +-
 include/scsi/libfc.h          |    2 ++
 2 files changed, 3 insertions(+), 1 deletions(-)
drivers/scsi/libfc/fc_rport.c +1 -1
index 6b56973..6d68482 100644
@@ -127,7 +127,7 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,
 	if (rdata)
 		return rdata;
 
-	rdata = kzalloc(sizeof(*rdata), GFP_KERNEL);
+	rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL);
 	if (!rdata)
 		return NULL;
 
include/scsi/libfc.h +2 -0
index b0310b9..fcbee8c 100644
@@ -799,6 +799,7 @@ struct fc_disc {
  * @mfs:                   The maximum Fibre Channel payload size
  * @max_retry_count:       The maximum retry attempts
  * @max_rport_retry_count: The maximum remote port retry attempts
+ * @rport_priv_size:       Size needed by driver after struct fc_rport_priv
  * @lro_xid:               The maximum XID for LRO
  * @lso_max:               The maximum large offload send size
  * @fcts:                  FC-4 type mask
@@ -848,6 +849,7 @@ struct fc_lport {
 	u32			       mfs;
 	u8			       max_retry_count;
 	u8			       max_rport_retry_count;
+	u16			       rport_priv_size;
 	u16			       link_speed;
 	u16			       link_supported_speeds;
 	u16			       lro_xid;
#13 lore raw

PATCH 8/28 libfcoe: convert FIP to lock with mutex instead of spin lock

In reply to Robert Love

From: Joe Eykholt <[email protected]>

It turns out most of the FIP work is now done from worker threads or process context now, so there's no need to use a spin lock.

Change to use mutex instead of spin lock and delayed_work instead of a timer.

This will make it nicer for the VN_port to VN_port feature that will interact more with the libfc layers requiring that spinlocks not be held.

---
 drivers/scsi/fcoe/libfcoe.c |  116 ++++++++++++++++++++-----------------------
 include/scsi/libfcoe.h      |    9 +--
 2 files changed, 57 insertions(+), 68 deletions(-)
drivers/scsi/fcoe/libfcoe.c +55 -61
index f009191..e510888 100644
@@ -113,7 +113,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip)
 	fip->state = FIP_ST_LINK_WAIT;
 	fip->mode = FIP_ST_AUTO;
 	INIT_LIST_HEAD(&fip->fcfs);
-	spin_lock_init(&fip->lock);
+	mutex_init(&fip->ctlr_mutex);
 	fip->flogi_oxid = FC_XID_UNKNOWN;
 	setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
 	INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
@@ -159,10 +159,10 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
 	cancel_work_sync(&fip->recv_work);
 	skb_queue_purge(&fip->fip_recv_list);
 
-	spin_lock_bh(&fip->lock);
+	mutex_lock(&fip->ctlr_mutex);
 	fip->state = FIP_ST_DISABLED;
 	fcoe_ctlr_reset_fcfs(fip);
-	spin_unlock_bh(&fip->lock);
+	mutex_unlock(&fip->ctlr_mutex);
 	del_timer_sync(&fip->timer);
 	cancel_work_sync(&fip->timer_work);
 }
@@ -255,19 +255,19 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf)
  */
 void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
 {
-	spin_lock_bh(&fip->lock);
+	mutex_lock(&fip->ctlr_mutex);
 	if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) {
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 		fc_linkup(fip->lp);
 	} else if (fip->state == FIP_ST_LINK_WAIT) {
 		fip->state = fip->mode;
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 		if (fip->state == FIP_ST_AUTO)
 			LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
 		fc_linkup(fip->lp);
 		fcoe_ctlr_solicit(fip, NULL);
 	} else
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 }
 EXPORT_SYMBOL(fcoe_ctlr_link_up);
 
@@ -300,11 +300,11 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
 	int link_dropped;
 
 	LIBFCOE_FIP_DBG(fip, "link down.\n");
-	spin_lock_bh(&fip->lock);
+	mutex_lock(&fip->ctlr_mutex);
 	fcoe_ctlr_reset(fip);
 	link_dropped = fip->state != FIP_ST_LINK_WAIT;
 	fip->state = FIP_ST_LINK_WAIT;
-	spin_unlock_bh(&fip->lock);
+	mutex_unlock(&fip->ctlr_mutex);
 
 	if (link_dropped)
 		fc_linkdown(fip->lp);
@@ -577,12 +577,12 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 	unsigned long sel_time = 0;
 	struct fcoe_dev_stats *stats;
 
+	stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu());
+
 	list_for_each_entry_safe(fcf, next, &fip->fcfs, list) {
 		deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2;
 		if (fip->sel_fcf == fcf) {
 			if (time_after(jiffies, deadline)) {
-				stats = per_cpu_ptr(fip->lp->dev_stats,
-						    smp_processor_id());
 				stats->MissDiscAdvCount++;
 				printk(KERN_INFO "libfcoe: host%d: "
 				       "Missing Discovery Advertisement "
@@ -601,8 +601,6 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 			WARN_ON(!fip->fcf_count);
 			fip->fcf_count--;
 			kfree(fcf);
-			stats = per_cpu_ptr(fip->lp->dev_stats,
-					    smp_processor_id());
 			stats->VLinkFailureCount++;
 		} else {
 			if (time_after(next_timer, deadline))
@@ -612,6 +610,7 @@ static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip)
 				sel_time = fcf->time;
 		}
 	}
+	put_cpu();
 	if (sel_time && !fip->sel_fcf && !fip->sel_time) {
 		sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY);
 		fip->sel_time = sel_time;
@@ -768,7 +767,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
 	if (fcoe_ctlr_parse_adv(fip, skb, &new))
 		return;
 
-	spin_lock_bh(&fip->lock);
+	mutex_lock(&fip->ctlr_mutex);
 	first = list_empty(&fip->fcfs);
 	found = NULL;
 	list_for_each_entry(fcf, &fip->fcfs, list) {
@@ -847,7 +846,7 @@ static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb)
 			mod_timer(&fip->timer, fip->sel_time);
 	}
 out:
-	spin_unlock_bh(&fip->lock);
+	mutex_unlock(&fip->ctlr_mutex);
 }
 
 /**
@@ -1108,11 +1107,12 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
 		if (is_vn_port)
 			fc_lport_reset(vn_port);
 		else {
-			spin_lock_bh(&fip->lock);
+			mutex_lock(&fip->ctlr_mutex);
 			per_cpu_ptr(lport->dev_stats,
-				    smp_processor_id())->VLinkFailureCount++;
+				    get_cpu())->VLinkFailureCount++;
+			put_cpu();
 			fcoe_ctlr_reset(fip);
-			spin_unlock_bh(&fip->lock);
+			mutex_unlock(&fip->ctlr_mutex);
 
 			fc_lport_reset(fip->lp);
 			fcoe_ctlr_solicit(fip, NULL);
@@ -1166,7 +1166,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
 	if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len)
 		goto drop;
 
-	spin_lock_bh(&fip->lock);
+	mutex_lock(&fip->ctlr_mutex);
 	state = fip->state;
 	if (state == FIP_ST_AUTO) {
 		fip->map_dest = 0;
@@ -1174,7 +1174,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
 		state = FIP_ST_ENABLED;
 		LIBFCOE_FIP_DBG(fip, "Using FIP mode\n");
 	}
-	spin_unlock_bh(&fip->lock);
+	mutex_unlock(&fip->ctlr_mutex);
 	if (state != FIP_ST_ENABLED)
 		goto drop;
 
@@ -1240,19 +1240,38 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
 /**
  * fcoe_ctlr_timeout() - FIP timeout handler
  * @arg: The FCoE controller that timed out
- *
- * Ages FCFs.  Triggers FCF selection if possible.  Sends keep-alives.
  */
 static void fcoe_ctlr_timeout(unsigned long arg)
 {
 	struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg;
+
+	schedule_work(&fip->timer_work);
+}
+
+/**
+ * fcoe_ctlr_timer_work() - Worker thread function for timer work
+ * @work: Handle to a FCoE controller
+ *
+ * Ages FCFs.  Triggers FCF selection if possible.
+ * Sends keep-alives and resets.
+ */
+static void fcoe_ctlr_timer_work(struct work_struct *work)
+{
+	struct fcoe_ctlr *fip;
+	struct fc_lport *vport;
+	u8 *mac;
+	u8 reset = 0;
+	u8 send_ctlr_ka = 0;
+	u8 send_port_ka = 0;
 	struct fcoe_fcf *sel;
 	struct fcoe_fcf *fcf;
 	unsigned long next_timer;
 
-	spin_lock_bh(&fip->lock);
+	fip = container_of(work, struct fcoe_ctlr, timer_work);
+
+	mutex_lock(&fip->ctlr_mutex);
 	if (fip->state == FIP_ST_DISABLED) {
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 		return;
 	}
 
@@ -1286,7 +1305,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
 			       "FIP Fibre-Channel Forwarder timed out.	"
 			       "Starting FCF discovery.\n",
 			       fip->lp->host->host_no);
-			fip->reset_req = 1;
+			reset = 1;
 			schedule_work(&fip->timer_work);
 		}
 	}
@@ -1294,7 +1313,7 @@ static void fcoe_ctlr_timeout(unsigned long arg)
 	if (sel && !sel->fd_flags) {
 		if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
 			fip->ctlr_ka_time = jiffies + sel->fka_period;
-			fip->send_ctlr_ka = 1;
+			send_ctlr_ka = 1;
 		}
 		if (time_after(next_timer, fip->ctlr_ka_time))
 			next_timer = fip->ctlr_ka_time;
@@ -1302,37 +1321,14 @@ static void fcoe_ctlr_timeout(unsigned long arg)
 		if (time_after_eq(jiffies, fip->port_ka_time)) {
 			fip->port_ka_time = jiffies +
 				msecs_to_jiffies(FIP_VN_KA_PERIOD);
-			fip->send_port_ka = 1;
+			send_port_ka = 1;
 		}
 		if (time_after(next_timer, fip->port_ka_time))
 			next_timer = fip->port_ka_time;
 	}
 	if (!list_empty(&fip->fcfs))
 		mod_timer(&fip->timer, next_timer);
-	if (fip->send_ctlr_ka || fip->send_port_ka)
-		schedule_work(&fip->timer_work);
-	spin_unlock_bh(&fip->lock);
-}
-
-/**
- * fcoe_ctlr_timer_work() - Worker thread function for timer work
- * @work: Handle to a FCoE controller
- *
- * Sends keep-alives and resets which must not
- * be called from the timer directly, since they use a mutex.
- */
-static void fcoe_ctlr_timer_work(struct work_struct *work)
-{
-	struct fcoe_ctlr *fip;
-	struct fc_lport *vport;
-	u8 *mac;
-	int reset;
-
-	fip = container_of(work, struct fcoe_ctlr, timer_work);
-	spin_lock_bh(&fip->lock);
-	reset = fip->reset_req;
-	fip->reset_req = 0;
-	spin_unlock_bh(&fip->lock);
+	mutex_unlock(&fip->ctlr_mutex);
 
 	if (reset) {
 		fc_lport_reset(fip->lp);
@@ -1340,12 +1336,10 @@ static void fcoe_ctlr_timer_work(struct work_struct *work)
 		fcoe_ctlr_solicit(fip, NULL);
 	}
 
-	if (fip->send_ctlr_ka) {
-		fip->send_ctlr_ka = 0;
+	if (send_ctlr_ka)
 		fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr);
-	}
-	if (fip->send_port_ka) {
-		fip->send_port_ka = 0;
+
+	if (send_port_ka) {
 		mutex_lock(&fip->lp->lp_mutex);
 		mac = fip->get_src_addr(fip->lp);
 		fcoe_ctlr_send_keep_alive(fip, fip->lp, 1, mac);
@@ -1402,9 +1396,9 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
 	if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP &&
 	    fip->flogi_oxid == ntohs(fh->fh_ox_id)) {
 
-		spin_lock_bh(&fip->lock);
+		mutex_lock(&fip->ctlr_mutex);
 		if (fip->state != FIP_ST_AUTO && fip->state != FIP_ST_NON_FIP) {
-			spin_unlock_bh(&fip->lock);
+			mutex_unlock(&fip->ctlr_mutex);
 			return -EINVAL;
 		}
 		fip->state = FIP_ST_NON_FIP;
@@ -1424,13 +1418,13 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
 			fip->map_dest = 0;
 		}
 		fip->flogi_oxid = FC_XID_UNKNOWN;
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 		fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id);
 	} else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) {
 		/*
 		 * Save source MAC for point-to-point responses.
 		 */
-		spin_lock_bh(&fip->lock);
+		mutex_lock(&fip->ctlr_mutex);
 		if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) {
 			memcpy(fip->dest_addr, sa, ETH_ALEN);
 			fip->map_dest = 0;
@@ -1439,7 +1433,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
 						"Setting non-FIP mode\n");
 			fip->state = FIP_ST_NON_FIP;
 		}
-		spin_unlock_bh(&fip->lock);
+		mutex_unlock(&fip->ctlr_mutex);
 	}
 	return 0;
 }
include/scsi/libfcoe.h +2 -7
index 81aee1c..7d18b50 100644
@@ -75,14 +75,12 @@ enum fip_state {
  * @flogi_count:   number of FLOGI attempts in AUTO mode.
  * @map_dest:	   use the FC_MAP mode for destination MAC addresses.
  * @spma:	   supports SPMA server-provided MACs mode
- * @send_ctlr_ka:  need to send controller keep alive
- * @send_port_ka:  need to send port keep alives
  * @dest_addr:	   MAC address of the selected FC forwarder.
  * @ctl_src_addr:  the native MAC address of our local port.
  * @send:	   LLD-supplied function to handle sending FIP Ethernet frames
  * @update_mac:    LLD-supplied function to handle changes to MAC addresses.
  * @get_src_addr:  LLD-supplied function to supply a source MAC address.
- * @lock:	   lock protecting this structure.
+ * @ctlr_mutex:	   lock protecting this structure.
  *
  * This structure is used by all FCoE drivers.  It contains information
  * needed by all FCoE low-level drivers (LLDs) as well as internal state
@@ -106,18 +104,15 @@ struct fcoe_ctlr {
 	u16 user_mfs;
 	u16 flogi_oxid;
 	u8 flogi_count;
-	u8 reset_req;
 	u8 map_dest;
 	u8 spma;
-	u8 send_ctlr_ka;
-	u8 send_port_ka;
 	u8 dest_addr[ETH_ALEN];
 	u8 ctl_src_addr[ETH_ALEN];
 
 	void (*send)(struct fcoe_ctlr *, struct sk_buff *);
 	void (*update_mac)(struct fc_lport *, u8 *addr);
 	u8 * (*get_src_addr)(struct fc_lport *);
-	spinlock_t lock;
+	struct mutex ctlr_mutex;
 };
 
 /**
#14 lore raw

PATCH 9/28 libfc: add discovery-private pointer for LLD

In reply to Robert Love

From: Joe Eykholt <[email protected]>

For VN_port to VN_port mode, FIP will do discovery and needs a way to find its state from the local port or discovery structure. It seems that any other LLD that implements its own discovery would also need something like this.

Replace disc->lport with disc->priv, and use container_of to find the lport. We could use disc->priv for that, but container_of is smaller and faster.

---
 drivers/scsi/libfc/fc_disc.c  |   14 +++++++-------
 drivers/scsi/libfc/fc_libfc.h |    2 +-
 include/scsi/libfc.h          |    9 +++++++--
 3 files changed, 15 insertions(+), 10 deletions(-)
drivers/scsi/libfc/fc_disc.c +7 -7
index d0fa9a0..0447455 100644
@@ -65,7 +65,7 @@ void fc_disc_stop_rports(struct fc_disc *disc)
 	struct fc_lport *lport;
 	struct fc_rport_priv *rdata;
 
-	lport = disc->lport;
+	lport = fc_disc_lport(disc);
 
 	mutex_lock(&disc->disc_mutex);
 	list_for_each_entry_rcu(rdata, &disc->rports, peers)
@@ -96,7 +96,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
 	LIST_HEAD(disc_ports);
 	struct fc_disc_port *dp, *next;
 
-	lport = disc->lport;
+	lport = fc_disc_lport(disc);
 
 	FC_DISC_DBG(disc, "Received an RSCN event\n");
 
@@ -275,7 +275,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,
  */
 static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
 {
-	struct fc_lport *lport = disc->lport;
+	struct fc_lport *lport = fc_disc_lport(disc);
 	struct fc_rport_priv *rdata;
 
 	FC_DISC_DBG(disc, "Discovery complete\n");
@@ -313,7 +313,7 @@ static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event)
  */
 static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
 {
-	struct fc_lport *lport = disc->lport;
+	struct fc_lport *lport = fc_disc_lport(disc);
 	unsigned long delay = 0;
 
 	FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n",
@@ -353,7 +353,7 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp)
 static void fc_disc_gpn_ft_req(struct fc_disc *disc)
 {
 	struct fc_frame *fp;
-	struct fc_lport *lport = disc->lport;
+	struct fc_lport *lport = fc_disc_lport(disc);
 
 	WARN_ON(!fc_lport_test_ready(lport));
 
@@ -396,7 +396,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)
 	struct fc_rport_identifiers ids;
 	struct fc_rport_priv *rdata;
 
-	lport = disc->lport;
+	lport = fc_disc_lport(disc);
 	disc->seq_count++;
 
 	/*
@@ -733,7 +733,7 @@ int fc_disc_init(struct fc_lport *lport)
 	mutex_init(&disc->disc_mutex);
 	INIT_LIST_HEAD(&disc->rports);
 
-	disc->lport = lport;
+	disc->priv = lport;
 
 	return 0;
 }
drivers/scsi/libfc/fc_libfc.h +1 -1
index f5c0ca4..16d2162 100644
@@ -52,7 +52,7 @@ extern unsigned int fc_debug_logging;
 #define FC_DISC_DBG(disc, fmt, args...)				\
 	FC_CHECK_LOGGING(FC_DISC_LOGGING,			\
 			 printk(KERN_INFO "host%u: disc: " fmt,	\
-				(disc)->lport->host->host_no,	\
+				fc_disc_lport(disc)->host->host_no,	\
 				##args))
 
 #define FC_RPORT_ID_DBG(lport, port_id, fmt, args...)			\
include/scsi/libfc.h +7 -2
index fcbee8c..5f64e59 100644
@@ -739,7 +739,7 @@ struct libfc_function_template {
  * @buf_len:       Length of the discovery buffer
  * @disc_id:       Discovery ID
  * @rports:        List of discovered remote ports
- * @lport:         The local port that discovery is for
+ * @priv:          Private pointer for use by discovery code
  * @disc_mutex:    Mutex that protects the discovery context
  * @partial_buf:   Partial name buffer (if names are returned
  *                 in multiple frames)
@@ -755,7 +755,7 @@ struct fc_disc {
 	u16                   disc_id;
 
 	struct list_head      rports;
-	struct fc_lport	      *lport;
+	void		      *priv;
 	struct mutex	      disc_mutex;
 	struct fc_gpn_ft_resp partial_buf;
 	struct delayed_work   disc_work;
@@ -1003,6 +1003,11 @@ void fc_rport_terminate_io(struct fc_rport *);
  *****************************/
 int fc_disc_init(struct fc_lport *);
 
+static inline struct fc_lport *fc_disc_lport(struct fc_disc *disc)
+{
+	return container_of(disc, struct fc_lport, disc);
+}
+
 /*
  * FCP LAYER
  *****************************/
#15 lore raw

PATCH 10/28 libfcoe: fcoe: fnic: change fcoe_ctlr_init interface to specify mode

In reply to Robert Love

From: Joe Eykholt <[email protected]>

There are three modes that libfcoe currently supports, and a new one is coming. Change the fcoe_ctlr_init() interface to add the mode desired. This should not change any functionality.

---
 drivers/scsi/fcoe/fcoe.c      |    2 +-
 drivers/scsi/fcoe/libfcoe.c   |    4 ++--
 drivers/scsi/fnic/fnic_main.c |    4 ++--
 include/scsi/libfcoe.h        |   11 ++++++++++-
 4 files changed, 15 insertions(+), 6 deletions(-)
drivers/scsi/fcoe/fcoe.c +1 -1
index a120962..9d64e08 100644
@@ -357,7 +357,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)
 	/*
 	 * Initialize FIP.
 	 */
-	fcoe_ctlr_init(&fcoe->ctlr);
+	fcoe_ctlr_init(&fcoe->ctlr, FIP_MODE_AUTO);
 	fcoe->ctlr.send = fcoe_fip_send;
 	fcoe->ctlr.update_mac = fcoe_update_src_mac;
 	fcoe->ctlr.get_src_addr = fcoe_get_src_mac;
drivers/scsi/fcoe/libfcoe.c +2 -2
index e510888..76056e4 100644
@@ -108,10 +108,10 @@ static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf)
  * fcoe_ctlr_init() - Initialize the FCoE Controller instance
  * @fip: The FCoE controller to initialize
  */
-void fcoe_ctlr_init(struct fcoe_ctlr *fip)
+void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
 {
 	fip->state = FIP_ST_LINK_WAIT;
-	fip->mode = FIP_ST_AUTO;
+	fip->mode = mode;
 	INIT_LIST_HEAD(&fip->fcfs);
 	mutex_init(&fip->ctlr_mutex);
 	fip->flogi_oxid = FC_XID_UNKNOWN;
drivers/scsi/fnic/fnic_main.c +2 -2
index 265e73d..d0fe1c3 100644
@@ -617,7 +617,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
 	fnic->ctlr.send = fnic_eth_send;
 	fnic->ctlr.update_mac = fnic_update_mac;
 	fnic->ctlr.get_src_addr = fnic_get_mac;
-	fcoe_ctlr_init(&fnic->ctlr);
 	if (fnic->config.flags & VFCF_FIP_CAPABLE) {
 		shost_printk(KERN_INFO, fnic->lport->host,
 			     "firmware supports FIP\n");
@@ -625,10 +624,11 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
 		vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0);
 		vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS);
 		vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr);
+		fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_AUTO);
 	} else {
 		shost_printk(KERN_INFO, fnic->lport->host,
 			     "firmware uses non-FIP mode\n");
-		fnic->ctlr.mode = FIP_ST_NON_FIP;
+		fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_NON_FIP);
 	}
 	fnic->state = FNIC_IN_FC_MODE;
 
include/scsi/libfcoe.h +10 -1
index 7d18b50..1a84a31 100644
@@ -54,6 +54,15 @@ enum fip_state {
 	FIP_ST_ENABLED,
 };
 
+/*
+ * Modes:
+ * The mode is the state that is to be entered after link up.
+ * It must not change after fcoe_ctlr_init() sets it.
+ */
+#define FIP_MODE_AUTO		FIP_ST_AUTO
+#define FIP_MODE_NON_FIP	FIP_ST_NON_FIP
+#define FIP_MODE_FABRIC		FIP_ST_ENABLED
+
 /**
  * struct fcoe_ctlr - FCoE Controller and FIP state
  * @state:	   internal FIP state for network link and FIP or non-FIP mode.
@@ -152,7 +161,7 @@ struct fcoe_fcf {
 };
 
 /* FIP API functions */
-void fcoe_ctlr_init(struct fcoe_ctlr *);
+void fcoe_ctlr_init(struct fcoe_ctlr *, enum fip_state);
 void fcoe_ctlr_destroy(struct fcoe_ctlr *);
 void fcoe_ctlr_link_up(struct fcoe_ctlr *);
 int fcoe_ctlr_link_down(struct fcoe_ctlr *);
#16 lore raw

PATCH 11/28 libfc: Add local port point-to-multipoint flag

In reply to Robert Love

From: Joe Eykholt <[email protected]>

For VN_port to VN_port mode, the transport sets the port_id and there's no lport FLOGI. This is similar to FC loop mode.

Add a point_to_multipoint flag that indicates the local port is in point-to-multipoint mode. This skips FLOGI and discovery. It also skips resetting the port_id on resets other than link down.

Add function fc_lport_set_local_id() that sets the local port_id. This is called by libfcoe on behalf of the low-level driver to set the port_id when the link comes up.

---
 drivers/scsi/libfc/fc_lport.c |   36 +++++++++++++++++++++++++++++++++++-
 include/scsi/libfc.h          |    2 ++
 2 files changed, 37 insertions(+), 1 deletions(-)
drivers/scsi/libfc/fc_lport.c +35 -1
index 79c9e3c..f7bff2c 100644
@@ -755,6 +755,34 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id,
 }
 
 /**
+ * fc_lport_set_port_id() - set the local port Port ID for point-to-multipoint
+ * @lport: The local port which will have its Port ID set.
+ * @port_id: The new port ID.
+ *
+ * Called by the lower-level driver when transport sets the local port_id.
+ * This is used in VN_port to VN_port mode for FCoE, and causes FLOGI and
+ * discovery to be skipped.
+ */
+void fc_lport_set_local_id(struct fc_lport *lport, u32 port_id)
+{
+	mutex_lock(&lport->lp_mutex);
+
+	fc_lport_set_port_id(lport, port_id, NULL);
+
+	switch (lport->state) {
+	case LPORT_ST_RESET:
+	case LPORT_ST_FLOGI:
+		if (port_id)
+			fc_lport_enter_ready(lport);
+		break;
+	default:
+		break;
+	}
+	mutex_unlock(&lport->lp_mutex);
+}
+EXPORT_SYMBOL(fc_lport_set_local_id);
+
+/**
  * fc_lport_recv_flogi_req() - Receive a FLOGI request
  * @sp_in: The sequence the FLOGI is on
  * @rx_fp: The FLOGI frame
@@ -954,7 +982,7 @@ static void fc_lport_reset_locked(struct fc_lport *lport)
 	lport->tt.exch_mgr_reset(lport, 0, 0);
 	fc_host_fabric_name(lport->host) = 0;
 
-	if (lport->port_id)
+	if (lport->port_id && (!lport->point_to_multipoint || !lport->link_up))
 		fc_lport_set_port_id(lport, 0, NULL);
 }
 
@@ -1536,6 +1564,12 @@ void fc_lport_enter_flogi(struct fc_lport *lport)
 
 	fc_lport_state_enter(lport, LPORT_ST_FLOGI);
 
+	if (lport->point_to_multipoint) {
+		if (lport->port_id)
+			fc_lport_enter_ready(lport);
+		return;
+	}
+
 	fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
 	if (!fp)
 		return fc_lport_error(lport, fp);
include/scsi/libfc.h +2 -0
index 5f64e59..bd05605 100644
@@ -846,6 +846,7 @@ struct fc_lport {
 	u32			       lro_enabled:1;
 	u32			       does_npiv:1;
 	u32			       npiv_enabled:1;
+	u32			       point_to_multipoint:1;
 	u32			       mfs;
 	u8			       max_retry_count;
 	u8			       max_rport_retry_count;
@@ -991,6 +992,7 @@ int fc_set_mfs(struct fc_lport *, u32 mfs);
 struct fc_lport *libfc_vport_create(struct fc_vport *, int privsize);
 struct fc_lport *fc_vport_id_lookup(struct fc_lport *, u32 port_id);
 int fc_lport_bsg_request(struct fc_bsg_job *);
+void fc_lport_set_local_id(struct fc_lport *, u32 port_id);
 
 /*
  * REMOTE PORT LAYER
#17 lore raw

PATCH 12/28 libfc: add FLOGI state to rport for VN2VN

In reply to Robert Love

From: Joe Eykholt <[email protected]>

The FIP proposal for VN_port to VN_port point-to-multipoint operation requires a FLOGI be sent to each remote port. The FLOGI is sent with the assigned S_ID and D_IDs of the local and remote ports. This and the response get FIP-encapsulated for Ethernet.

Add FLOGI state to the remote port state machine. This will be skipped if not in point-to-multipoint mode.

To reduce a little duplication between PLOGI and FLOGI response handling, added fc_rport_login_complete(), which handles the parameters for the rdata struct.

---
 drivers/scsi/libfc/fc_lport.c |    4 -
 drivers/scsi/libfc/fc_rport.c |  290 +++++++++++++++++++++++++++++++++++++++--
 include/scsi/fc/fc_els.h      |    2 
 include/scsi/libfc.h          |    4 +
 4 files changed, 286 insertions(+), 14 deletions(-)
drivers/scsi/libfc/fc_lport.c +2 -2
index f7bff2c..ec9850c 100644
@@ -906,10 +906,10 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
 		recv = lport->tt.rport_recv_req;
 		switch (fc_frame_payload_op(fp)) {
 		case ELS_FLOGI:
-			recv = fc_lport_recv_flogi_req;
+			if (!lport->point_to_multipoint)
+				recv = fc_lport_recv_flogi_req;
 			break;
 		case ELS_LOGO:
-			fh = fc_frame_header_get(fp);
 			if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI)
 				recv = fc_lport_recv_logo_req;
 			break;
drivers/scsi/libfc/fc_rport.c +278 -12

397 lines not on this page · raw message

include/scsi/fc/fc_els.h +2 -0
index 70a7e92..481abbd 100644
@@ -191,6 +191,7 @@ enum fc_els_rjt_reason {
 	ELS_RJT_UNAB =		0x09,	/* unable to perform command request */
 	ELS_RJT_UNSUP =		0x0b,	/* command not supported */
 	ELS_RJT_INPROG =	0x0e,	/* command already in progress */
+	ELS_RJT_FIP =		0x20,	/* FIP error */
 	ELS_RJT_VENDOR =	0xff,	/* vendor specific error */
 };
 
@@ -212,6 +213,7 @@ enum fc_els_rjt_explan {
 	ELS_EXPL_UNAB_DATA =	0x2a,	/* unable to supply requested data */
 	ELS_EXPL_UNSUPR =	0x2c,	/* Request not supported */
 	ELS_EXPL_INV_LEN =	0x2d,	/* Invalid payload length */
+	ELS_EXPL_NOT_NEIGHBOR = 0x62,	/* VN2VN_Port not in neighbor set */
 	/* TBD - above definitions incomplete */
 };
 
include/scsi/libfc.h +4 -0
index bd05605..24b91c9 100644
@@ -97,6 +97,8 @@ enum fc_disc_event {
 /**
  * enum fc_rport_state - Remote port states
  * @RPORT_ST_INIT:    Initialized
+ * @RPORT_ST_FLOGI:   Waiting for FLOGI completion for point-to-multipoint
+ * @RPORT_ST_PLOGI_WAIT:   Waiting for peer to login for point-to-multipoint
  * @RPORT_ST_PLOGI:   Waiting for PLOGI completion
  * @RPORT_ST_PRLI:    Waiting for PRLI completion
  * @RPORT_ST_RTV:     Waiting for RTV completion
@@ -107,6 +109,8 @@ enum fc_disc_event {
 */
 enum fc_rport_state {
 	RPORT_ST_INIT,
+	RPORT_ST_FLOGI,
+	RPORT_ST_PLOGI_WAIT,
 	RPORT_ST_PLOGI,
 	RPORT_ST_PRLI,
 	RPORT_ST_RTV,
#18 lore raw

PATCH 13/28 libfc: track FIP exchanges

In reply to Robert Love

From: Joe Eykholt <[email protected]>

When an exchange is received with a FIP encapsulation, we need to know that the response must be sent via FIP and what the original ELS opcode was. This becomes important for VN2VN mode, where we may receive FLOGI or LOGO from several peer VN_ports, and the LS_ACC or LS_RJT must be sent FIP-encapsulated with the correct sub-type.

Add a field to the struct fc_frame, fr_encaps, to indicate the encapsulation values. That term is chosen to be neutral and LLD-agnostic in case non-FCoE/FIP LLDs might find it useful.

The frame fr_encaps is transferred from the ingress frame to the exchange by fc_exch_recv_req(), and back to the outgoing frame by fc_seq_send().

This is taking the last byte in the skb->cb array. If needed, we could combine the info in sof, eof, flags, and encaps together into one field, but it'd be better to do that if and when its needed.

---
 drivers/scsi/libfc/fc_exch.c |    2 ++
 include/scsi/fc_frame.h      |    3 +++
 include/scsi/libfc.h         |    2 ++
 3 files changed, 7 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_exch.c +2 -0
index 104e0fb..61eabd3 100644
@@ -464,6 +464,7 @@ static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
 
 	f_ctl = ntoh24(fh->fh_f_ctl);
 	fc_exch_setup_hdr(ep, fp, f_ctl);
+	fr_encaps(fp) = ep->encaps;
 
 	/*
 	 * update sequence count if this frame is carrying
@@ -1259,6 +1260,7 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
 		sp = fr_seq(fp);	/* sequence will be held */
 		ep = fc_seq_exch(sp);
 		fc_seq_send_ack(sp, fp);
+		ep->encaps = fr_encaps(fp);
 
 		/*
 		 * Call the receive function.
include/scsi/fc_frame.h +3 -0
index 15427fa..29dd97d 100644
@@ -51,6 +51,7 @@
 #define fr_sof(fp)	(fr_cb(fp)->fr_sof)
 #define fr_eof(fp)	(fr_cb(fp)->fr_eof)
 #define fr_flags(fp)	(fr_cb(fp)->fr_flags)
+#define fr_encaps(fp)	(fr_cb(fp)->fr_encaps)
 #define fr_max_payload(fp)	(fr_cb(fp)->fr_max_payload)
 #define fr_fsp(fp)	(fr_cb(fp)->fr_fsp)
 #define fr_crc(fp)	(fr_cb(fp)->fr_crc)
@@ -69,6 +70,7 @@ struct fcoe_rcv_info {
 	u8		fr_sof;		/* start of frame delimiter */
 	u8		fr_eof;		/* end of frame delimiter */
 	u8		fr_flags;	/* flags - see below */
+	u8		fr_encaps;	/* LLD encapsulation info (e.g. FIP) */
 	u8		granted_mac[ETH_ALEN]; /* FCoE MAC address */
 };
 
@@ -97,6 +99,7 @@ static inline void fc_frame_init(struct fc_frame *fp)
 	fr_dev(fp) = NULL;
 	fr_seq(fp) = NULL;
 	fr_flags(fp) = 0;
+	fr_encaps(fp) = 0;
 }
 
 struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len);
include/scsi/libfc.h +2 -0
index 24b91c9..8d297f9 100644
@@ -412,6 +412,7 @@ struct fc_seq {
  * @esb_stat:     ESB exchange status
  * @r_a_tov:      Resouce allocation time out value (in msecs)
  * @seq_id:       The next sequence ID to use
+ * @encaps:       encapsulation information for lower-level driver
  * @f_ctl:        F_CTL flags for the sequence
  * @fh_type:      The frame type
  * @class:        The class of service
@@ -443,6 +444,7 @@ struct fc_exch {
 	u32		    esb_stat;
 	u32		    r_a_tov;
 	u8		    seq_id;
+	u8		    encaps;
 	u32		    f_ctl;
 	u8		    fh_type;
 	enum fc_class	    class;
#19 lore raw

PATCH 14/28 libfcoe: add protocol description of FIP VN2VN mode

In reply to Robert Love

From: Joe Eykholt <[email protected]>

The FC-BB-6 committee is proposing a new FIP usage model called VN_port to VN_port mode. It allows VN_ports to discover each other over a loss-free L2 Ethernet without any FCF or Fibre-channel fabric services. This is point-to-multipoint. There is also a variant of this called point-to-point which provides for making sure there is just one pair of ports operating over the Ethernet fabric.

This patch defines the new message type and subtypes as well as one new descriptor type used by VN2VN mode.

These are all still at the proposed stage and subject to change.

---
 include/scsi/fc/fc_fip.h |   46 +++++++++++++++++++++++++++++++++++++++++++---
 include/scsi/fc/fc_ns.h  |    7 +++++++
 2 files changed, 50 insertions(+), 3 deletions(-)
include/scsi/fc/fc_fip.h +43 -3
index 17baa19..ae25d4a 100644
@@ -17,9 +17,12 @@
 #ifndef _FC_FIP_H_
 #define _FC_FIP_H_
 
+#include <scsi/fc/fc_ns.h>
+
 /*
  * This version is based on:
  * http://www.t11.org/ftp/t11/pub/fc/bb-5/08-543v1.pdf
+ * and T11 FC-BB-6 10-019v4.pdf (June 2010 VN2VN proposal)
  */
 
 #define FIP_DEF_PRI	128	/* default selection priority */
@@ -29,11 +32,24 @@
 #define FIP_FCF_FUZZ	100	/* random time added by FCF (mS) */
 
 /*
+ * VN2VN proposed-standard values.
+ */
+#define FIP_VN_FC_MAP	0x0efd00 /* MAC OUI for VN2VN use */
+#define FIP_VN_PROBE_WAIT 100	/* interval between VN2VN probes (ms) */
+#define FIP_VN_ANN_WAIT 400	/* interval between VN2VN announcements (ms) */
+#define FIP_VN_RLIM_INT 10000	/* interval between probes when rate limited */
+#define FIP_VN_RLIM_COUNT 10	/* number of probes before rate limiting */
+#define FIP_VN_BEACON_INT 8000	/* interval between VN2VN beacons */
+#define FIP_VN_BEACON_FUZZ 100	/* random time to add to beacon period (ms) */
+
+/*
  * Multicast MAC addresses.  T11-adopted.
  */
-#define FIP_ALL_FCOE_MACS	((u8[6]) { 1, 0x10, 0x18, 1, 0, 0 })
-#define FIP_ALL_ENODE_MACS	((u8[6]) { 1, 0x10, 0x18, 1, 0, 1 })
-#define FIP_ALL_FCF_MACS	((u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
+#define FIP_ALL_FCOE_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 0 })
+#define FIP_ALL_ENODE_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 1 })
+#define FIP_ALL_FCF_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
+#define FIP_ALL_VN2VN_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 4 })
+#define FIP_ALL_P2P_MACS	((__u8[6]) { 1, 0x10, 0x18, 1, 0, 5 })
 
 #define FIP_VER		1		/* version for fip_header */
 
@@ -60,6 +76,7 @@ enum fip_opcode {
 	FIP_OP_LS =	2,		/* Link Service request or reply */
 	FIP_OP_CTRL =	3,		/* Keep Alive / Link Reset */
 	FIP_OP_VLAN =	4,		/* VLAN discovery */
+	FIP_OP_VN2VN =	5,		/* VN2VN operation */
 	FIP_OP_VENDOR_MIN = 0xfff8,	/* min vendor-specific opcode */
 	FIP_OP_VENDOR_MAX = 0xfffe,	/* max vendor-specific opcode */
 };
@@ -97,11 +114,23 @@ enum fip_vlan_subcode {
 };
 
 /*
+ * Subcodes for FIP_OP_VN2VN.
+ */
+enum fip_vn2vn_subcode {
+	FIP_SC_VN_PROBE_REQ = 1,	/* probe request */
+	FIP_SC_VN_PROBE_REP = 2,	/* probe reply */
+	FIP_SC_VN_CLAIM_NOTIFY = 3,	/* claim notification */
+	FIP_SC_VN_CLAIM_REP = 4,	/* claim response */
+	FIP_SC_VN_BEACON = 5,		/* beacon */
+};
+
+/*
  * flags in header fip_flags.
  */
 enum fip_flag {
 	FIP_FL_FPMA =	0x8000,		/* supports FPMA fabric-provided MACs */
 	FIP_FL_SPMA =	0x4000,		/* supports SPMA server-provided MACs */
+	FIP_FL_REC_OR_P2P = 0x0008,	/* configured addr or point-to-point */
 	FIP_FL_AVAIL =	0x0004,		/* available for FLOGI/ELP */
 	FIP_FL_SOL =	0x0002,		/* this is a solicited message */
 	FIP_FL_FPORT =	0x0001,		/* sent from an F port */
@@ -130,6 +159,7 @@ enum fip_desc_type {
 	FIP_DT_FKA =	12,		/* advertisement keep-alive period */
 	FIP_DT_VENDOR =	13,		/* vendor ID */
 	FIP_DT_VLAN =	14,		/* vlan number */
+	FIP_DT_FC4F =	15,		/* FC-4 features */
 	FIP_DT_LIMIT,			/* max defined desc_type + 1 */
 	FIP_DT_VENDOR_BASE = 128,	/* first vendor-specific desc_type */
 };
@@ -229,6 +259,16 @@ enum fip_fka_flags {
 /* FIP_DT_FKA flags */
 
 /*
+ * FIP_DT_FC4F - FC-4 features.
+ */
+struct fip_fc4_feat {
+	struct fip_desc fd_desc;
+	__u8		fd_resvd[2];
+	struct fc_ns_fts fd_fts;
+	struct fc_ns_ff	fd_ff;
+} __attribute__((packed));
+
+/*
  * FIP_DT_VENDOR descriptor.
  */
 struct fip_vendor_desc {
include/scsi/fc/fc_ns.h +7 -0
index e7d3ac4..185015d 100644
@@ -100,6 +100,13 @@ struct fc_ns_fts {
 };
 
 /*
+ * FC4-features object.
+ */
+struct fc_ns_ff	{
+	__be32	fd_feat[FC_NS_TYPES * 4 / FC_NS_BPW]; /* 4-bits per FC-type */
+};
+
+/*
  * GID_PT request.
  */
 struct fc_ns_gid_pt {
#20 lore raw

PATCH 15/28 libfcoe: add state change debugging

In reply to Robert Love

From: Joe Eykholt <[email protected]>

Enhancement: add debug messages at all state transitions.

---
 drivers/scsi/fcoe/libfcoe.c |   48 +++++++++++++++++++++++++++++++++++++------
 1 files changed, 41 insertions(+), 7 deletions(-)
drivers/scsi/fcoe/libfcoe.c +41 -7
index 76056e4..11f3db5 100644
@@ -80,6 +80,40 @@ do {							\
 			      printk(KERN_INFO "host%d: fip: " fmt, 	\
 				     (fip)->lp->host->host_no, ##args);)
 
+static const char *fcoe_ctlr_states[] = {
+	[FIP_ST_DISABLED] =	"DISABLED",
+	[FIP_ST_LINK_WAIT] =	"LINK_WAIT",
+	[FIP_ST_AUTO] =		"AUTO",
+	[FIP_ST_NON_FIP] =	"NON_FIP",
+	[FIP_ST_ENABLED] =	"ENABLED",
+};
+
+static const char *fcoe_ctlr_state(enum fip_state state)
+{
+	const char *cp = "unknown";
+
+	if (state < ARRAY_SIZE(fcoe_ctlr_states))
+		cp = fcoe_ctlr_states[state];
+	if (!cp)
+		cp = "unknown";
+	return cp;
+}
+
+/**
+ * fcoe_ctlr_set_state() - Set and do debug printing for the new FIP state.
+ * @fip: The FCoE controller
+ * @state: The new state
+ */
+static void fcoe_ctlr_set_state(struct fcoe_ctlr *fip, enum fip_state state)
+{
+	if (state == fip->state)
+		return;
+	if (fip->lp)
+		LIBFCOE_FIP_DBG(fip, "state %s -> %s\n",
+			fcoe_ctlr_state(fip->state), fcoe_ctlr_state(state));
+	fip->state = state;
+}
+
 /**
  * fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid
  * @fcf: The FCF to check
@@ -110,7 +144,7 @@ static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf)
  */
 void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
 {
-	fip->state = FIP_ST_LINK_WAIT;
+	fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
 	fip->mode = mode;
 	INIT_LIST_HEAD(&fip->fcfs);
 	mutex_init(&fip->ctlr_mutex);
@@ -160,7 +194,7 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
 	skb_queue_purge(&fip->fip_recv_list);
 
 	mutex_lock(&fip->ctlr_mutex);
-	fip->state = FIP_ST_DISABLED;
+	fcoe_ctlr_set_state(fip, FIP_ST_DISABLED);
 	fcoe_ctlr_reset_fcfs(fip);
 	mutex_unlock(&fip->ctlr_mutex);
 	del_timer_sync(&fip->timer);
@@ -260,7 +294,7 @@ void fcoe_ctlr_link_up(struct fcoe_ctlr *fip)
 		mutex_unlock(&fip->ctlr_mutex);
 		fc_linkup(fip->lp);
 	} else if (fip->state == FIP_ST_LINK_WAIT) {
-		fip->state = fip->mode;
+		fcoe_ctlr_set_state(fip, fip->mode);
 		mutex_unlock(&fip->ctlr_mutex);
 		if (fip->state == FIP_ST_AUTO)
 			LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n");
@@ -303,7 +337,7 @@ int fcoe_ctlr_link_down(struct fcoe_ctlr *fip)
 	mutex_lock(&fip->ctlr_mutex);
 	fcoe_ctlr_reset(fip);
 	link_dropped = fip->state != FIP_ST_LINK_WAIT;
-	fip->state = FIP_ST_LINK_WAIT;
+	fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT);
 	mutex_unlock(&fip->ctlr_mutex);
 
 	if (link_dropped)
@@ -1170,7 +1204,7 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
 	state = fip->state;
 	if (state == FIP_ST_AUTO) {
 		fip->map_dest = 0;
-		fip->state = FIP_ST_ENABLED;
+		fcoe_ctlr_set_state(fip, FIP_ST_ENABLED);
 		state = FIP_ST_ENABLED;
 		LIBFCOE_FIP_DBG(fip, "Using FIP mode\n");
 	}
@@ -1401,7 +1435,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
 			mutex_unlock(&fip->ctlr_mutex);
 			return -EINVAL;
 		}
-		fip->state = FIP_ST_NON_FIP;
+		fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
 		LIBFCOE_FIP_DBG(fip,
 				"received FLOGI LS_ACC using non-FIP mode\n");
 
@@ -1431,7 +1465,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
 			if (fip->state == FIP_ST_AUTO)
 				LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. "
 						"Setting non-FIP mode\n");
-			fip->state = FIP_ST_NON_FIP;
+			fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP);
 		}
 		mutex_unlock(&fip->ctlr_mutex);
 	}
#21 lore raw

PATCH 16/28 libfcoe: fcoe: fnic: add FIP VN2VN point-to-multipoint support

In reply to Robert Love

From: Joe Eykholt <[email protected]>

The FC-BB-6 committee is proposing a new FIP usage model called VN_port to VN_port mode. It allows VN_ports to discover each other over a loss-free L2 Ethernet without any FCF or Fibre-channel fabric services. This is point-to-multipoint. There is also a variant of this called point-to-point which provides for making sure there is just one pair of ports operating over the Ethernet fabric.

We add these new states: VNMP_START, _PROBE1, _PROBE2, _CLAIM, and _UP. These usually go quickly in that sequence. After waiting a random amount of time up to 100 ms in START, we select a pseudo-random proposed locally-unique port ID and send out probes in states PROBE1 and PROBE2, 100 ms apart. If no probe responses are heard, we proceed to CLAIM state 400 ms later and send a claim notification. We wait another 400 ms to receive claim responses, which give us a list of the other nodes on the network, including their FC-4 capabilities. After another 400 ms we go to VNMP_UP state and should start interoperating with any of the nodes for whic we receivec claim responses. More details are in the spec.j

Add the new mode as FIP_MODE_VN2VN. The driver must specify explicitly that it wants to operate in this mode. There is no automatic detection between point-to-multipoint and fabric mode, and the local port initialization is affected, so it isn't anticipated that there will ever be any such automatic switchover.

It may eventually be possible to have both fabric and VN2VN modes on the same L2 network, which may be done by two separate local VN_ports (lports).

When in VN2VN mode, FIP replaces libfc's fabric-oriented discovery module with its own simple code that adds remote ports as they are discovered from incoming claim notifications and responses. These hooks are placed by fcoe_disc_init().

A linear list of discovered vn_ports is maintained under the fcoe_ctlr struct. It is expected to be short for now, and accessed infrequently. It is kept under RCU for lock-ordering reasons. The lport and/or rport mutexes may be held when we need to lookup a fcoe_vnport during an ELS send.

Change fcoe_ctlr_encaps() to lookup the destination vn_port in the list of peers for the destination MAC address of the FIP-encapsulated frame.

Add a new function fcoe_disc_init() to initialize just the discovery portion of libfcoe for VN2VN mode.

---
 drivers/scsi/fcoe/fcoe.c      |   16 -
 drivers/scsi/fcoe/libfcoe.c   | 1075 +++++++++++++++++++++++++++++++++++++++--
 drivers/scsi/fnic/fnic_main.c |    7 
 include/scsi/libfcoe.h        |   42 ++
 4 files changed, 1071 insertions(+), 69 deletions(-)
drivers/scsi/fcoe/fcoe.c +13 -3
index 9d64e08..216aba3 100644
@@ -315,7 +315,11 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
 	dev_uc_add(netdev, flogi_maddr);
 	if (fip->spma)
 		dev_uc_add(netdev, fip->ctl_src_addr);
-	dev_mc_add(netdev, FIP_ALL_ENODE_MACS);
+	if (fip->mode == FIP_MODE_VN2VN) {
+		dev_mc_add(netdev, FIP_ALL_VN2VN_MACS);
+		dev_mc_add(netdev, FIP_ALL_P2P_MACS);
+	} else
+		dev_mc_add(netdev, FIP_ALL_ENODE_MACS);
 
 	/*
 	 * setup the receive function from ethernet driver
@@ -401,7 +405,11 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)
 	dev_uc_del(netdev, flogi_maddr);
 	if (fip->spma)
 		dev_uc_del(netdev, fip->ctl_src_addr);
-	dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
+	if (fip->mode == FIP_MODE_VN2VN) {
+		dev_mc_del(netdev, FIP_ALL_VN2VN_MACS);
+		dev_mc_del(netdev, FIP_ALL_P2P_MACS);
+	} else
+		dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
 
 	/* Tell the LLD we are done w/ FCoE */
 	ops = netdev->netdev_ops;
@@ -967,7 +975,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
 	}
 
 	/* Initialize the library */
-	rc = fcoe_libfc_config(lport, &fcoe_libfc_fcn_templ);
+	rc = fcoe_libfc_config(lport, &fcoe->ctlr, &fcoe_libfc_fcn_templ, 1);
 	if (rc) {
 		FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the "
 				"interface\n");
@@ -2533,6 +2541,8 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did,
 	switch (op) {
 	case ELS_FLOGI:
 	case ELS_FDISC:
+		if (lport->point_to_multipoint)
+			break;
 		return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp,
 				     fip, timeout);
 	case ELS_LOGO:
drivers/scsi/fcoe/libfcoe.c +1016 -59

1,241 lines not on this page · raw message

drivers/scsi/fnic/fnic_main.c +1 -6
index d0fe1c3..9eb7a9e 100644
@@ -673,7 +673,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
 	/* Start local port initiatialization */
 
 	lp->link_up = 0;
-	lp->tt = fnic_transport_template;
 
 	lp->max_retry_count = fnic->config.flogi_retries;
 	lp->max_rport_retry_count = fnic->config.plogi_retries;
@@ -689,11 +688,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,
 	fc_set_wwnn(lp, fnic->config.node_wwn);
 	fc_set_wwpn(lp, fnic->config.port_wwn);
 
-	fc_lport_init(lp);
-	fc_exch_init(lp);
-	fc_elsct_init(lp);
-	fc_rport_init(lp);
-	fc_disc_init(lp);
+	fcoe_libfc_config(lp, &fnic->ctlr, &fnic_transport_template, 0);
 
 	if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START,
 			       FCPIO_HOST_EXCH_RANGE_END, NULL)) {
include/scsi/libfcoe.h +41 -1

106 lines not on this page · raw message

#22 lore raw

PATCH 17/28 libfcoe: Fix FIP ELS encapsulation details for FLOGI responses

In reply to Robert Love

From: Joe Eykholt <[email protected]>

When sending a FLOGI LS_ACC, which we only do in point-to-multipoint mode, the MAC descriptor should have the granted MAC set to 0x0efd00 || D_ID.

When sending an LS_RJT, there should be no MAC descriptor.

When sending either an LS_ACC or LS_RJT, the subcode should indicate an reply, not a request.

---
 drivers/scsi/fcoe/libfcoe.c |   42 ++++++++++++++++++++++++++++--------------
 1 files changed, 28 insertions(+), 14 deletions(-)
drivers/scsi/fcoe/libfcoe.c +28 -14
index 79df78f..4865e81 100644
@@ -469,11 +469,15 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
 		struct fip_header fip;
 		struct fip_encaps encaps;
 	} __attribute__((packed)) *cap;
+	struct fc_frame_header *fh;
 	struct fip_mac_desc *mac;
 	struct fcoe_fcf *fcf;
 	size_t dlen;
 	u16 fip_flags;
+	u8 op;
 
+	fh = (struct fc_frame_header *)skb->data;
+	op = *(u8 *)(fh + 1);
 	dlen = sizeof(struct fip_encaps) + skb->len;	/* len before push */
 	cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap));
 	memset(cap, 0, sizeof(*cap));
@@ -481,6 +485,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
 	if (lport->point_to_multipoint) {
 		if (fcoe_ctlr_vn_lookup(fip, d_id, cap->eth.h_dest))
 			return -ENODEV;
+		fip_flags = 0;
 	} else {
 		fcf = fip->sel_fcf;
 		if (!fcf)
@@ -497,26 +502,35 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
 
 	cap->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER);
 	cap->fip.fip_op = htons(FIP_OP_LS);
-	cap->fip.fip_subcode = FIP_SC_REQ;
-	cap->fip.fip_dl_len = htons((dlen + sizeof(*mac)) / FIP_BPW);
+	if (op == ELS_LS_ACC || op == ELS_LS_RJT)
+		cap->fip.fip_subcode = FIP_SC_REP;
+	else
+		cap->fip.fip_subcode = FIP_SC_REQ;
 	cap->fip.fip_flags = htons(fip_flags);
 
 	cap->encaps.fd_desc.fip_dtype = dtype;
 	cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW;
 
-	mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
-	memset(mac, 0, sizeof(*mac));
-	mac->fd_desc.fip_dtype = FIP_DT_MAC;
-	mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
-	if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
-		memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
-	} else if (fip_flags & FIP_FL_SPMA) {
-		LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
-		memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
-	} else {
-		LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
-		/* FPMA only FLOGI must leave the MAC desc set to all 0s */
+	if (op != ELS_LS_RJT) {
+		dlen += sizeof(*mac);
+		mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac));
+		memset(mac, 0, sizeof(*mac));
+		mac->fd_desc.fip_dtype = FIP_DT_MAC;
+		mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW;
+		if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) {
+			memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN);
+		} else if (fip->mode == FIP_MODE_VN2VN) {
+			hton24(mac->fd_mac, FIP_VN_FC_MAP);
+			hton24(mac->fd_mac + 3, fip->port_id);
+		} else if (fip_flags & FIP_FL_SPMA) {
+			LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n");
+			memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN);
+		} else {
+			LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n");
+			/* FPMA only FLOGI.  Must leave the MAC desc zeroed. */
+		}
 	}
+	cap->fip.fip_dl_len = htons(dlen / FIP_BPW);
 
 	skb->protocol = htons(ETH_P_FIP);
 	skb_reset_mac_header(skb);
#23 lore raw

PATCH 18/28 fcoe libfcoe: use correct FC-MAP for VN2VN mode

In reply to Robert Love

From: Joe Eykholt <[email protected]>

In VN2VN mode, map_dest means to use the default VN2VN OUI. Change code that uses the default FCoE OUI to use the one set in the fcoe_ctlr struct.

---
 drivers/scsi/fcoe/fcoe.c    |    6 ++----
 drivers/scsi/fcoe/libfcoe.c |   24 ++++++++++++++++++++----
 2 files changed, 22 insertions(+), 8 deletions(-)
drivers/scsi/fcoe/fcoe.c +2 -4
index 216aba3..4d3e70a 100644
@@ -1534,11 +1534,9 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp)
 	/* fill up mac and fcoe headers */
 	eh = eth_hdr(skb);
 	eh->h_proto = htons(ETH_P_FCOE);
+	memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN);
 	if (fcoe->ctlr.map_dest)
-		fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id);
-	else
-		/* insert GW address */
-		memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN);
+		memcpy(eh->h_dest + 3, fh->fh_d_id, 3);
 
 	if (unlikely(fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN))
 		memcpy(eh->h_source, fcoe->ctlr.ctl_src_addr, ETH_ALEN);
drivers/scsi/fcoe/libfcoe.c +20 -4
index 4865e81..4de8ced 100644
@@ -153,6 +153,20 @@ static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf)
 }
 
 /**
+ * fcoe_ctlr_map_dest() - Set flag and OUI for mapping destination addresses
+ * @fip: The FCoE controller
+ */
+static void fcoe_ctlr_map_dest(struct fcoe_ctlr *fip)
+{
+	if (fip->mode == FIP_MODE_VN2VN)
+		hton24(fip->dest_addr, FIP_VN_FC_MAP);
+	else
+		hton24(fip->dest_addr, FIP_DEF_FC_MAP);
+	hton24(fip->dest_addr + 3, 0);
+	fip->map_dest = 1;
+}
+
+/**
  * fcoe_ctlr_init() - Initialize the FCoE Controller instance
  * @fip: The FCoE controller to initialize
  */
@@ -345,7 +359,7 @@ static void fcoe_ctlr_reset(struct fcoe_ctlr *fip)
 	fip->port_ka_time = 0;
 	fip->sol_time = 0;
 	fip->flogi_oxid = FC_XID_UNKNOWN;
-	fip->map_dest = 0;
+	fcoe_ctlr_map_dest(fip);
 }
 
 /**
@@ -573,11 +587,11 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
 			fip->flogi_count++;
 			if (fip->flogi_count < 3)
 				goto drop;
-			fip->map_dest = 1;
+			fcoe_ctlr_map_dest(fip);
 			return 0;
 		}
 		if (fip->state == FIP_ST_NON_FIP)
-			fip->map_dest = 1;
+			fcoe_ctlr_map_dest(fip);
 	}
 
 	if (fip->state == FIP_ST_NON_FIP)
@@ -1411,6 +1425,7 @@ static void fcoe_ctlr_timer_work(struct work_struct *work)
 			       "Fibre-Channel Forwarder MAC %pM\n",
 			       fip->lp->host->host_no, sel->fcf_mac);
 			memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
+			fip->map_dest = 0;
 			fip->port_ka_time = jiffies +
 				msecs_to_jiffies(FIP_VN_KA_PERIOD);
 			fip->ctlr_ka_time = jiffies + sel->fka_period;
@@ -1527,7 +1542,7 @@ int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport,
 		 * Otherwise we use the FCoE gateway addr
 		 */
 		if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) {
-			fip->map_dest = 1;
+			fcoe_ctlr_map_dest(fip);
 		} else {
 			memcpy(fip->dest_addr, sa, ETH_ALEN);
 			fip->map_dest = 0;
@@ -2426,6 +2441,7 @@ static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip)
 		new_port_id = fip->port_id;
 		hton24(mac, FIP_VN_FC_MAP);
 		hton24(mac + 3, new_port_id);
+		fcoe_ctlr_map_dest(fip);
 		fip->update_mac(fip->lp, mac);
 		fcoe_ctlr_vn_send_claim(fip);
 		next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT);
#24 lore raw

PATCH 19/28 fcoe: config via separate create_vn2vn module parameter

In reply to Robert Love

From: Joe Eykholt <[email protected]>

Add module parameter create_vn2vn that behaves like the create parameter except that the new instance is created in FIP vn2vn mode.

This can be replaced once we change create to allow modifying per-instance attributes before starting the instance.

---
 drivers/scsi/fcoe/fcoe.c |   16 ++++++++++++----
 1 files changed, 12 insertions(+), 4 deletions(-)
drivers/scsi/fcoe/fcoe.c +12 -4
index 4d3e70a..ab6ea60 100644
@@ -117,9 +117,14 @@ static void fcoe_recv_frame(struct sk_buff *skb);
 
 static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
 
-module_param_call(create, fcoe_create, NULL, NULL, S_IWUSR);
+module_param_call(create, fcoe_create, NULL, (void *)FIP_MODE_AUTO, S_IWUSR);
 __MODULE_PARM_TYPE(create, "string");
 MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface");
+module_param_call(create_vn2vn, fcoe_create, NULL,
+		  (void *)FIP_MODE_VN2VN, S_IWUSR);
+__MODULE_PARM_TYPE(create_vn2vn, "string");
+MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance "
+		 "on an Ethernet interface");
 module_param_call(destroy, fcoe_destroy, NULL, NULL, S_IWUSR);
 __MODULE_PARM_TYPE(destroy, "string");
 MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface");
@@ -341,10 +346,12 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,
 /**
  * fcoe_interface_create() - Create a FCoE interface on a net device
  * @netdev: The net device to create the FCoE interface on
+ * @fip_mode: The mode to use for FIP
  *
  * Returns: pointer to a struct fcoe_interface or NULL on error
  */
-static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)
+static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev,
+						    enum fip_state fip_mode)
 {
 	struct fcoe_interface *fcoe;
 	int err;
@@ -361,7 +368,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)
 	/*
 	 * Initialize FIP.
 	 */
-	fcoe_ctlr_init(&fcoe->ctlr, FIP_MODE_AUTO);
+	fcoe_ctlr_init(&fcoe->ctlr, fip_mode);
 	fcoe->ctlr.send = fcoe_fip_send;
 	fcoe->ctlr.update_mac = fcoe_update_src_mac;
 	fcoe->ctlr.get_src_addr = fcoe_get_src_mac;
@@ -2088,6 +2095,7 @@ static void fcoe_destroy_work(struct work_struct *work)
  */
 static int fcoe_create(const char *buffer, struct kernel_param *kp)
 {
+	enum fip_state fip_mode = (enum fip_state)(long)kp->arg;
 	int rc;
 	struct fcoe_interface *fcoe;
 	struct fc_lport *lport;
@@ -2129,7 +2137,7 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)
 		goto out_putdev;
 	}
 
-	fcoe = fcoe_interface_create(netdev);
+	fcoe = fcoe_interface_create(netdev, fip_mode);
 	if (!fcoe) {
 		rc = -ENOMEM;
 		goto out_putdev;
#25 lore raw

PATCH 20/28 libfc: eliminate rport LOGO state

In reply to Robert Love

From: Joe Eykholt <[email protected]>

The LOGO state hasn't been used in a while, except in a brief transition to DELETE state while holding the rport mutex. All port LOGO responses have been ignored as well as any timeout if we don't get a response.

So this patch just removes LOGO state and simplifies the response handler.

---
 drivers/scsi/libfc/fc_rport.c |   88 ++++++++++-------------------------------
 include/scsi/libfc.h          |    2 -
 2 files changed, 22 insertions(+), 68 deletions(-)
drivers/scsi/libfc/fc_rport.c +22 -66
index 4d6adf2..c06d63e 100644
@@ -89,7 +89,6 @@ static const char *fc_rport_state_names[] = {
 	[RPORT_ST_PRLI] = "PRLI",
 	[RPORT_ST_RTV] = "RTV",
 	[RPORT_ST_READY] = "Ready",
-	[RPORT_ST_LOGO] = "LOGO",
 	[RPORT_ST_ADISC] = "ADISC",
 	[RPORT_ST_DELETE] = "Delete",
 };
@@ -514,9 +513,6 @@ static void fc_rport_timeout(struct work_struct *work)
 	case RPORT_ST_RTV:
 		fc_rport_enter_rtv(rdata);
 		break;
-	case RPORT_ST_LOGO:
-		fc_rport_enter_logo(rdata);
-		break;
 	case RPORT_ST_ADISC:
 		fc_rport_enter_adisc(rdata);
 		break;
@@ -547,7 +543,6 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)
 	switch (rdata->rp_state) {
 	case RPORT_ST_FLOGI:
 	case RPORT_ST_PLOGI:
-	case RPORT_ST_LOGO:
 		rdata->flags &= ~FC_RP_STARTED;
 		fc_rport_enter_delete(rdata, RPORT_EV_FAILED);
 		break;
@@ -791,7 +786,6 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport,
 
 	switch (rdata->rp_state) {
 	case RPORT_ST_INIT:
-	case RPORT_ST_LOGO:
 	case RPORT_ST_DELETE:
 		mutex_unlock(&rdata->rp_mutex);
 		rjt_data.reason = ELS_RJT_FIP;
@@ -1037,52 +1031,6 @@ err:
 }
 
 /**
- * fc_rport_logo_resp() - Handler for logout (LOGO) responses
- * @sp:	       The sequence the LOGO was on
- * @fp:	       The LOGO response frame
- * @rdata_arg: The remote port that sent the LOGO response
- *
- * Locking Note: This function will be called without the rport lock
- * held, but it will lock, call an _enter_* function or fc_rport_error
- * and then unlock the rport.
- */
-static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
-			       void *rdata_arg)
-{
-	struct fc_rport_priv *rdata = rdata_arg;
-	u8 op;
-
-	mutex_lock(&rdata->rp_mutex);
-
-	FC_RPORT_DBG(rdata, "Received a LOGO %s\n", fc_els_resp_type(fp));
-
-	if (rdata->rp_state != RPORT_ST_LOGO) {
-		FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
-			     "%s\n", fc_rport_state(rdata));
-		if (IS_ERR(fp))
-			goto err;
-		goto out;
-	}
-
-	if (IS_ERR(fp)) {
-		fc_rport_error_retry(rdata, fp);
-		goto err;
-	}
-
-	op = fc_frame_payload_op(fp);
-	if (op != ELS_LS_ACC)
-		FC_RPORT_DBG(rdata, "Bad ELS response op %x for LOGO command\n",
-			     op);
-	fc_rport_enter_delete(rdata, RPORT_EV_LOGO);
-
-out:
-	fc_frame_free(fp);
-err:
-	mutex_unlock(&rdata->rp_mutex);
-	kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy);
-}
-
-/**
  * fc_rport_enter_prli() - Send Process Login (PRLI) request
  * @rdata: The remote port to send the PRLI request to
  *
@@ -1224,6 +1172,24 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)
 }
 
 /**
+ * fc_rport_logo_resp() - Handler for logout (LOGO) responses
+ * @sp:	       The sequence the LOGO was on
+ * @fp:	       The LOGO response frame
+ * @lport_arg: The local port
+ */
+static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
+			       void *lport_arg)
+{
+	struct fc_lport *lport = lport_arg;
+
+	FC_RPORT_ID_DBG(lport, fc_seq_exch(sp)->did,
+			"Received a LOGO %s\n", fc_els_resp_type(fp));
+	if (IS_ERR(fp))
+		return;
+	fc_frame_free(fp);
+}
+
+/**
  * fc_rport_enter_logo() - Send a logout (LOGO) request
  * @rdata: The remote port to send the LOGO request to
  *
@@ -1235,23 +1201,14 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata)
 	struct fc_lport *lport = rdata->local_port;
 	struct fc_frame *fp;
 
-	FC_RPORT_DBG(rdata, "Port entered LOGO state from %s state\n",
+	FC_RPORT_DBG(rdata, "Port sending LOGO from %s state\n",
 		     fc_rport_state(rdata));
 
-	fc_rport_state_enter(rdata, RPORT_ST_LOGO);
-
 	fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
-	if (!fp) {
-		fc_rport_error_retry(rdata, fp);
+	if (!fp)
 		return;
-	}
-
-	if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
-				  fc_rport_logo_resp, rdata,
-				  2 * lport->r_a_tov))
-		fc_rport_error_retry(rdata, NULL);
-	else
-		kref_get(&rdata->kref);
+	(void)lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO,
+				   fc_rport_logo_resp, lport, 0);
 }
 
 /**
@@ -1670,7 +1627,6 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
 		break;
 	case RPORT_ST_FLOGI:
 	case RPORT_ST_DELETE:
-	case RPORT_ST_LOGO:
 		FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n",
 			     fc_rport_state(rdata));
 		mutex_unlock(&rdata->rp_mutex);
include/scsi/libfc.h +0 -2
index 8d297f9..e6f07fb 100644
@@ -103,7 +103,6 @@ enum fc_disc_event {
  * @RPORT_ST_PRLI:    Waiting for PRLI completion
  * @RPORT_ST_RTV:     Waiting for RTV completion
  * @RPORT_ST_READY:   Ready for use
- * @RPORT_ST_LOGO:    Remote port logout (LOGO) sent
  * @RPORT_ST_ADISC:   Discover Address sent
  * @RPORT_ST_DELETE:  Remote port being deleted
 */
@@ -115,7 +114,6 @@ enum fc_rport_state {
 	RPORT_ST_PRLI,
 	RPORT_ST_RTV,
 	RPORT_ST_READY,
-	RPORT_ST_LOGO,
 	RPORT_ST_ADISC,
 	RPORT_ST_DELETE,
 };
#26 lore raw

PATCH 21/28 libfc: add fc_frame_sid() and fc_frame_did() functions

In reply to Robert Love

From: Joe Eykholt <[email protected]>

To pave the way for eliminating exchanges from incoming requests, add simple inline fc_frame_sid() and fc_frame_did() functions which get the FC_IDs from the frame header. This can be almost as efficient as getting them from the sequence/exchange.

Move ntohll, htonll, ntoh24 and hton24 to <scsi/fc_frame.h> since we need them there and that's included by <scsi/libfc.h>

---
 drivers/scsi/libfc/fc_lport.c |   12 ++++-------
 drivers/scsi/libfc/fc_rport.c |   26 +++++-------------------
 include/scsi/fc_frame.h       |   45 ++++++++++++++++++++++++++++++++++++++++-
 include/scsi/libfc.h          |   18 ----------------
 4 files changed, 54 insertions(+), 47 deletions(-)
drivers/scsi/libfc/fc_lport.c +4 -8
index ec9850c..be3c2ce 100644
@@ -800,7 +800,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 				    struct fc_lport *lport)
 {
 	struct fc_frame *fp;
-	struct fc_frame_header *fh;
 	struct fc_seq *sp;
 	struct fc_exch *ep;
 	struct fc_els_flogi *flp;
@@ -813,8 +812,7 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 	FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n",
 		     fc_lport_state(lport));
 
-	fh = fc_frame_header_get(rx_fp);
-	remote_fid = ntoh24(fh->fh_s_id);
+	remote_fid = fc_frame_sid(rx_fp);
 	flp = fc_frame_payload_get(rx_fp, sizeof(*flp));
 	if (!flp)
 		goto out;
@@ -910,7 +908,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
 				recv = fc_lport_recv_flogi_req;
 			break;
 		case ELS_LOGO:
-			if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI)
+			if (fc_frame_sid(fp) == FC_FID_FLOGI)
 				recv = fc_lport_recv_logo_req;
 			break;
 		case ELS_RSCN:
@@ -1468,7 +1466,6 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 			 void *lp_arg)
 {
 	struct fc_lport *lport = lp_arg;
-	struct fc_frame_header *fh;
 	struct fc_els_flogi *flp;
 	u32 did;
 	u16 csp_flags;
@@ -1496,8 +1493,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 		goto err;
 	}
 
-	fh = fc_frame_header_get(fp);
-	did = ntoh24(fh->fh_d_id);
+	did = fc_frame_did(fp);
 	if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) {
 		flp = fc_frame_payload_get(fp, sizeof(*flp));
 		if (flp) {
@@ -1523,7 +1519,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 				       "Port (%6.6x) entered "
 				       "point-to-point mode\n",
 				       lport->host->host_no, did);
-				fc_lport_ptp_setup(lport, ntoh24(fh->fh_s_id),
+				fc_lport_ptp_setup(lport, fc_frame_sid(fp),
 						   get_unaligned_be64(
 							   &flp->fl_wwpn),
 						   get_unaligned_be64(
drivers/scsi/libfc/fc_rport.c +6 -20
index c06d63e..1234931 100644
@@ -747,13 +747,11 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport,
 	struct fc_rport_priv *rdata;
 	struct fc_frame *fp = rx_fp;
 	struct fc_exch *ep;
-	struct fc_frame_header *fh;
 	struct fc_seq_els_data rjt_data;
 	u32 sid, f_ctl;
 
 	rjt_data.fp = NULL;
-	fh = fc_frame_header_get(fp);
-	sid = ntoh24(fh->fh_s_id);
+	sid = fc_frame_sid(fp);
 
 	FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n");
 
@@ -1430,17 +1428,14 @@ static void fc_rport_recv_els_req(struct fc_lport *lport,
 				  struct fc_seq *sp, struct fc_frame *fp)
 {
 	struct fc_rport_priv *rdata;
-	struct fc_frame_header *fh;
 	struct fc_seq_els_data els_data;
 
 	els_data.fp = NULL;
 	els_data.reason = ELS_RJT_UNAB;
 	els_data.explan = ELS_EXPL_PLOGI_REQD;
 
-	fh = fc_frame_header_get(fp);
-
 	mutex_lock(&lport->disc.disc_mutex);
-	rdata = lport->tt.rport_lookup(lport, ntoh24(fh->fh_s_id));
+	rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp));
 	if (!rdata) {
 		mutex_unlock(&lport->disc.disc_mutex);
 		goto reject;
@@ -1555,14 +1550,12 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,
 	struct fc_rport_priv *rdata;
 	struct fc_frame *fp = rx_fp;
 	struct fc_exch *ep;
-	struct fc_frame_header *fh;
 	struct fc_els_flogi *pl;
 	struct fc_seq_els_data rjt_data;
 	u32 sid, f_ctl;
 
 	rjt_data.fp = NULL;
-	fh = fc_frame_header_get(fp);
-	sid = ntoh24(fh->fh_s_id);
+	sid = fc_frame_sid(fp);
 
 	FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n");
 
@@ -1682,7 +1675,6 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
 	struct fc_lport *lport = rdata->local_port;
 	struct fc_exch *ep;
 	struct fc_frame *fp;
-	struct fc_frame_header *fh;
 	struct {
 		struct fc_els_prli prli;
 		struct fc_els_spp spp;
@@ -1698,12 +1690,10 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
 	u32 roles = FC_RPORT_ROLE_UNKNOWN;
 
 	rjt_data.fp = NULL;
-	fh = fc_frame_header_get(rx_fp);
-
 	FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
 		     fc_rport_state(rdata));
 
-	len = fr_len(rx_fp) - sizeof(*fh);
+	len = fr_len(rx_fp) - sizeof(struct fc_frame_header);
 	pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
 	if (!pp)
 		goto reject_len;
@@ -1817,7 +1807,6 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
 				   struct fc_frame *rx_fp)
 {
 	struct fc_lport *lport = rdata->local_port;
-	struct fc_frame_header *fh;
 	struct fc_exch *ep;
 	struct fc_frame *fp;
 	struct {
@@ -1832,12 +1821,11 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,
 	struct fc_seq_els_data rjt_data;
 
 	rjt_data.fp = NULL;
-	fh = fc_frame_header_get(rx_fp);
 
 	FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n",
 		     fc_rport_state(rdata));
 
-	len = fr_len(rx_fp) - sizeof(*fh);
+	len = fr_len(rx_fp) - sizeof(struct fc_frame_header);
 	pp = fc_frame_payload_get(rx_fp, sizeof(*pp));
 	if (!pp)
 		goto reject_len;
@@ -1901,14 +1889,12 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,
 				   struct fc_seq *sp,
 				   struct fc_frame *fp)
 {
-	struct fc_frame_header *fh;
 	struct fc_rport_priv *rdata;
 	u32 sid;
 
 	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
 
-	fh = fc_frame_header_get(fp);
-	sid = ntoh24(fh->fh_s_id);
+	sid = fc_frame_sid(fp);
 
 	mutex_lock(&lport->disc.disc_mutex);
 	rdata = lport->tt.rport_lookup(lport, sid);
include/scsi/fc_frame.h +44 -1

63 lines not on this page · raw message

include/scsi/libfc.h +0 -18
index e6f07fb..f1ce793 100644
@@ -42,24 +42,6 @@
 #define	FC_EX_TIMEOUT	1	/* Exchange timeout */
 #define	FC_EX_CLOSED	2	/* Exchange closed */
 
-/* some helpful macros */
-
-#define ntohll(x) be64_to_cpu(x)
-#define htonll(x) cpu_to_be64(x)
-
-
-static inline u32 ntoh24(const u8 *p)
-{
-	return (p[0] << 16) | (p[1] << 8) | p[2];
-}
-
-static inline void hton24(u8 *p, u32 v)
-{
-	p[0] = (v >> 16) & 0xff;
-	p[1] = (v >> 8) & 0xff;
-	p[2] = v & 0xff;
-}
-
 /**
  * enum fc_lport_state - Local port states
  * @LPORT_ST_DISABLED: Disabled
#27 lore raw

PATCH 22/28 libfc: add fc_fill_reply_hdr() and fc_fill_hdr()

In reply to Robert Love

From: Joe Eykholt <[email protected]>

Add functions to fill in an FC header given a request header. These reduces code lines in fc_lport and fc_rport and works without an exchange/sequence assigned.

fc_fill_reply_hdr() fills a header for a final reply frame.

fc_fill_hdr() which is similar but allows specifying the f_ctl parameter.

Add defines for F_CTL values FC_FCTL_REQ and FC_FCTL_RESP. These can be used for most request and response sequences.

v2 of patch adds a line to copy the frame encapsulation info from the received frame.

---
 drivers/scsi/libfc/fc_elsct.c |    2 +
 drivers/scsi/libfc/fc_fcp.c   |    6 ++-
 drivers/scsi/libfc/fc_libfc.c |   78 +++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/libfc/fc_lport.c |   39 ++++++---------------
 drivers/scsi/libfc/fc_rport.c |   64 ++++++++--------------------------
 include/scsi/fc_encode.h      |    7 ++++
 include/scsi/libfc.h          |    4 ++
 7 files changed, 121 insertions(+), 79 deletions(-)
drivers/scsi/libfc/fc_elsct.c +1 -1
index e9412b7..9b25969 100644
@@ -64,7 +64,7 @@ struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did,
 	}
 
 	fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type,
-		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+		       FC_FCTL_REQ, 0);
 
 	return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec);
 }
drivers/scsi/libfc/fc_fcp.c +3 -3
index 61a1297..eac4d09 100644
@@ -1108,7 +1108,7 @@ static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp,
 
 	fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id,
 		       rpriv->local_port->port_id, FC_TYPE_FCP,
-		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+		       FC_FCTL_REQ, 0);
 
 	seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy,
 				      fsp, 0);
@@ -1381,7 +1381,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)
 	fr_seq(fp) = fsp->seq_ptr;
 	fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id,
 		       rpriv->local_port->port_id, FC_TYPE_ELS,
-		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+		       FC_FCTL_REQ, 0);
 	if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC,
 				 fc_fcp_rec_resp, fsp,
 				 jiffies_to_msecs(FC_SCSI_REC_TOV))) {
@@ -1639,7 +1639,7 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset)
 
 	fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id,
 		       rpriv->local_port->port_id, FC_TYPE_FCP,
-		       FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
+		       FC_FCTL_REQ, 0);
 
 	seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, NULL,
 				      fsp, jiffies_to_msecs(FC_SCSI_REC_TOV));
drivers/scsi/libfc/fc_libfc.c +78 -0

87 lines not on this page · raw message

drivers/scsi/libfc/fc_lport.c +12 -27
index be3c2ce..e50a660 100644
@@ -405,11 +405,9 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
 				   struct fc_lport *lport)
 {
 	struct fc_frame *fp;
-	struct fc_exch *ep = fc_seq_exch(sp);
 	unsigned int len;
 	void *pp;
 	void *dp;
-	u32 f_ctl;
 
 	FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n",
 		     fc_lport_state(lport));
@@ -425,11 +423,8 @@ static void fc_lport_recv_echo_req(struct fc_seq *sp, struct fc_frame *in_fp,
 		dp = fc_frame_payload_get(fp, len);
 		memcpy(dp, pp, len);
 		*((__be32 *)dp) = htonl(ELS_LS_ACC << 24);
-		sp = lport->tt.seq_start_next(sp);
-		f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
-		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-			       FC_TYPE_ELS, f_ctl, 0);
-		lport->tt.seq_send(lport, sp, fp);
+		fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);
+		lport->tt.frame_send(lport, fp);
 	}
 	fc_frame_free(in_fp);
 }
@@ -447,7 +442,6 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
 				   struct fc_lport *lport)
 {
 	struct fc_frame *fp;
-	struct fc_exch *ep = fc_seq_exch(sp);
 	struct fc_els_rnid *req;
 	struct {
 		struct fc_els_rnid_resp rnid;
@@ -457,7 +451,6 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
 	struct fc_seq_els_data rjt_data;
 	u8 fmt;
 	size_t len;
-	u32 f_ctl;
 
 	FC_LPORT_DBG(lport, "Received RNID request while in state %s\n",
 		     fc_lport_state(lport));
@@ -490,12 +483,8 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp,
 				memcpy(&rp->gen, &lport->rnid_gen,
 				       sizeof(rp->gen));
 			}
-			sp = lport->tt.seq_start_next(sp);
-			f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ;
-			f_ctl |= FC_FC_END_SEQ | FC_FC_SEQ_INIT;
-			fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, ep->did, ep->sid,
-				       FC_TYPE_ELS, f_ctl, 0);
-			lport->tt.seq_send(lport, sp, fp);
+			fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0);
+			lport->tt.frame_send(lport, fp);
 		}
 	}
 	fc_frame_free(in_fp);
@@ -800,14 +789,13 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 				    struct fc_lport *lport)
 {
 	struct fc_frame *fp;
+	struct fc_frame_header *fh;
 	struct fc_seq *sp;
-	struct fc_exch *ep;
 	struct fc_els_flogi *flp;
 	struct fc_els_flogi *new_flp;
 	u64 remote_wwpn;
 	u32 remote_fid;
 	u32 local_fid;
-	u32 f_ctl;
 
 	FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n",
 		     fc_lport_state(lport));
@@ -843,7 +831,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 
 	fp = fc_frame_alloc(lport, sizeof(*flp));
 	if (fp) {
-		sp = lport->tt.seq_start_next(fr_seq(rx_fp));
 		new_flp = fc_frame_payload_get(fp, sizeof(*flp));
 		fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI);
 		new_flp->fl_cmd = (u8) ELS_LS_ACC;
@@ -852,11 +839,11 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,
 		 * Send the response.  If this fails, the originator should
 		 * repeat the sequence.
 		 */
-		f_ctl = FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ;
-		ep = fc_seq_exch(sp);
-		fc_fill_fc_hdr(fp, FC_RCTL_ELS_REP, remote_fid, local_fid,
-			       FC_TYPE_ELS, f_ctl, 0);
-		lport->tt.seq_send(lport, sp, fp);
+		fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
+		fh = fc_frame_header_get(fp);
+		hton24(fh->fh_s_id, local_fid);
+		hton24(fh->fh_d_id, remote_fid);
+		lport->tt.frame_send(lport, fp);
 
 	} else {
 		fc_lport_error(lport, fp);
@@ -1731,8 +1718,7 @@ static int fc_lport_els_request(struct fc_bsg_job *job,
 	hton24(fh->fh_d_id, did);
 	hton24(fh->fh_s_id, lport->port_id);
 	fh->fh_type = FC_TYPE_ELS;
-	hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
-	       FC_FC_END_SEQ | FC_FC_SEQ_INIT);
+	hton24(fh->fh_f_ctl, FC_FCTL_REQ);
 	fh->fh_cs_ctl = 0;
 	fh->fh_df_ctl = 0;
 	fh->fh_parm_offset = 0;
@@ -1791,8 +1777,7 @@ static int fc_lport_ct_request(struct fc_bsg_job *job,
 	hton24(fh->fh_d_id, did);
 	hton24(fh->fh_s_id, lport->port_id);
 	fh->fh_type = FC_TYPE_CT;
-	hton24(fh->fh_f_ctl, FC_FC_FIRST_SEQ |
-	       FC_FC_END_SEQ | FC_FC_SEQ_INIT);
+	hton24(fh->fh_f_ctl, FC_FCTL_REQ);
 	fh->fh_cs_ctl = 0;
 	fh->fh_df_ctl = 0;
 	fh->fh_parm_offset = 0;
drivers/scsi/libfc/fc_rport.c +16 -48

189 lines not on this page · raw message

include/scsi/fc_encode.h +7 -0
index 9b4867c..6d293c8 100644
@@ -21,6 +21,13 @@
 #define _FC_ENCODE_H_
 #include <asm/unaligned.h>
 
+/*
+ * F_CTL values for simple requests and responses.
+ */
+#define FC_FCTL_REQ	(FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)
+#define FC_FCTL_RESP	(FC_FC_EX_CTX | FC_FC_LAST_SEQ | \
+			FC_FC_END_SEQ | FC_FC_SEQ_INIT)
+
 struct fc_ns_rft {
 	struct fc_ns_fid fid;	/* port ID object */
 	struct fc_ns_fts fts;	/* FC4-types object */
include/scsi/libfc.h +4 -0
index f1ce793..a6414ec 100644
@@ -1027,6 +1027,10 @@ struct fc_seq *fc_elsct_send(struct fc_lport *, u32 did,
 				    void *arg, u32 timer_msec);
 void fc_lport_flogi_resp(struct fc_seq *, struct fc_frame *, void *);
 void fc_lport_logo_resp(struct fc_seq *, struct fc_frame *, void *);
+void fc_fill_reply_hdr(struct fc_frame *, const struct fc_frame *,
+		       enum fc_rctl, u32 parm_offset);
+void fc_fill_hdr(struct fc_frame *, const struct fc_frame *,
+		 enum fc_rctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset);
 
 
 /*
#28 lore raw

PATCH 23/28 libfc: add interface to allocate a sequence for incoming requests

In reply to Robert Love

From: Joe Eykholt <[email protected]>

For incoming ELS and FCP requests, we often don't require an exchange and sequence, however, sometimes we do. For those cases, (primarily FCP requests for targets) add a function to set up the exchange and sequence.

---
 drivers/scsi/libfc/fc_exch.c |   25 +++++++++++++++++++++++++
 include/scsi/libfc.h         |    7 +++++++
 2 files changed, 32 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_exch.c +25 -0
index 61eabd3..027042a 100644
@@ -1231,6 +1231,28 @@ free:
 }
 
 /**
+ * fc_seq_assign() - Assign exchange and sequence for incoming request
+ * @lport: The local port that received the request
+ * @fp:    The request frame
+ *
+ * On success, the sequence pointer will be returned and also in fr_seq(@fp).
+ */
+static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
+{
+	struct fc_exch_mgr_anchor *ema;
+
+	WARN_ON(lport != fr_dev(fp));
+	WARN_ON(fr_seq(fp));
+	fr_seq(fp) = NULL;
+
+	list_for_each_entry(ema, &lport->ema_list, ema_list)
+		if ((!ema->match || ema->match(fp)) &&
+		    fc_seq_lookup_recip(lport, ema->mp, fp) != FC_RJT_NONE)
+			break;
+	return fr_seq(fp);
+}
+
+/**
  * fc_exch_recv_req() - Handler for an incoming request where is other
  *			end is originating the sequence
  * @lport: The local port that received the request
@@ -2283,6 +2305,9 @@ int fc_exch_init(struct fc_lport *lport)
 	if (!lport->tt.seq_exch_abort)
 		lport->tt.seq_exch_abort = fc_seq_exch_abort;
 
+	if (!lport->tt.seq_assign)
+		lport->tt.seq_assign = fc_seq_assign;
+
 	return 0;
 }
 EXPORT_SYMBOL(fc_exch_init);
include/scsi/libfc.h +7 -0
index a6414ec..605f1d7 100644
@@ -556,6 +556,13 @@ struct libfc_function_template {
 	struct fc_seq *(*seq_start_next)(struct fc_seq *);
 
 	/*
+	 * Assign a sequence for an incoming request frame.
+	 *
+	 * STATUS: OPTIONAL
+	 */
+	struct fc_seq *(*seq_assign)(struct fc_lport *, struct fc_frame *);
+
+	/*
 	 * Reset an exchange manager, completing all sequences and exchanges.
 	 * If s_id is non-zero, reset only exchanges originating from that FID.
 	 * If d_id is non-zero, reset only exchanges sending to that FID.
#29 lore raw

PATCH 24/28 libfc: don't require a local exchange for incoming requests

In reply to Robert Love

From: Joe Eykholt <[email protected]>

Incoming requests shouldn't require a local exchange if we're just going to reply with one or two frames and don't expect anything further. Don't allocate exchanges for such requests until requested by the upper-layer protocol.

The sequence is always NULL for new requests, so remove that as an argument to request handlers.

Also change the first argument to lport->tt.seq_els_rsp_send from the sequence pointer to the received frame pointer, to supply the exchange IDs and destination ID info.

---
 drivers/scsi/fcoe/libfcoe.c   |    9 +-
 drivers/scsi/libfc/fc_disc.c  |   19 ++--
 drivers/scsi/libfc/fc_exch.c  |  188 ++++++++++++++++++++++-------------------
 drivers/scsi/libfc/fc_lport.c |   58 ++++---------
 drivers/scsi/libfc/fc_rport.c |  112 +++++++++---------------
 include/scsi/libfc.h          |   16 +--
 6 files changed, 174 insertions(+), 228 deletions(-)
drivers/scsi/fcoe/libfcoe.c +4 -5
index 4de8ced..2c265fe 100644
@@ -2341,20 +2341,19 @@ drop:
 
 /**
  * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode.
- * @fip: The FCoE controller
+ * @lport: The local port
+ * @fp: The received frame
  *
  * This should never be called since we don't see RSCNs or other
  * fabric-generated ELSes.
  */
-static void fcoe_ctlr_disc_recv(struct fc_seq *seq, struct fc_frame *fp,
-				struct fc_lport *lport)
+static void fcoe_ctlr_disc_recv(struct fc_lport *lport, struct fc_frame *fp)
 {
 	struct fc_seq_els_data rjt_data;
 
-	rjt_data.fp = NULL;
 	rjt_data.reason = ELS_RJT_UNSUP;
 	rjt_data.explan = ELS_EXPL_NONE;
-	lport->tt.seq_els_rsp_send(seq, ELS_LS_RJT, &rjt_data);
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
 	fc_frame_free(fp);
 }
 
drivers/scsi/libfc/fc_disc.c +7 -12
index 0447455..32f67c4 100644
@@ -75,15 +75,13 @@ void fc_disc_stop_rports(struct fc_disc *disc)
 
 /**
  * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN)
- * @sp:	   The sequence of the RSCN exchange
+ * @disc:  The discovery object to which the RSCN applies
  * @fp:	   The RSCN frame
- * @lport: The local port that the request will be sent on
  *
  * Locking Note: This function expects that the disc_mutex is locked
  *		 before it is called.
  */
-static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
-				  struct fc_disc *disc)
+static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp)
 {
 	struct fc_lport *lport;
 	struct fc_els_rscn *rp;
@@ -151,7 +149,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
 			break;
 		}
 	}
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_ACC, NULL);
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL);
 
 	/*
 	 * If not doing a complete rediscovery, do GPN_ID on
@@ -177,25 +175,22 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,
 	return;
 reject:
 	FC_DISC_DBG(disc, "Received a bad RSCN frame\n");
-	rjt_data.fp = NULL;
 	rjt_data.reason = ELS_RJT_LOGIC;
 	rjt_data.explan = ELS_EXPL_NONE;
-	lport->tt.seq_els_rsp_send(sp, ELS_LS_RJT, &rjt_data);
+	lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data);
 	fc_frame_free(fp);
 }
 
 /**
  * fc_disc_recv_req() - Handle incoming requests
- * @sp:	   The sequence of the request exchange
- * @fp:	   The request frame
  * @lport: The local port receiving the request
+ * @fp:	   The request frame
  *
  * Locking Note: This function is called from the EM and will lock
  *		 the disc_mutex before calling the handler for the
  *		 request.
  */
-static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,
-			     struct fc_lport *lport)
+static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp)
 {
 	u8 op;
 	struct fc_disc *disc = &lport->disc;
@@ -204,7 +199,7 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,
 	switch (op) {
 	case ELS_RSCN:
 		mutex_lock(&disc->disc_mutex);
-		fc_disc_recv_rscn_req(sp, fp, disc);
+		fc_disc_recv_rscn_req(disc, fp);
 		mutex_unlock(&disc->disc_mutex);
 		break;
 	default:
drivers/scsi/libfc/fc_exch.c +100 -88

347 lines not on this page · raw message

drivers/scsi/libfc/fc_lport.c +19 -39

163 lines not on this page · raw message

drivers/scsi/libfc/fc_rport.c +39 -73

350 lines not on this page · raw message

include/scsi/libfc.h +5 -11
index 605f1d7..14be49b 100644
@@ -249,14 +249,12 @@ struct fcoe_dev_stats {
 
 /**
  * struct fc_seq_els_data - ELS data used for passing ELS specific responses
- * @fp:     The ELS frame
  * @reason: The reason for rejection
  * @explan: The explaination of the rejection
  *
  * Mainly used by the exchange manager layer.
  */
 struct fc_seq_els_data {
-	struct fc_frame *fp;
 	enum fc_els_rjt_reason reason;
 	enum fc_els_rjt_explan explan;
 };
@@ -519,12 +517,11 @@ struct libfc_function_template {
 			struct fc_frame *);
 
 	/*
-	 * Send an ELS response using infomation from a previous
-	 * exchange and sequence.
+	 * Send an ELS response using infomation from the received frame.
 	 *
 	 * STATUS: OPTIONAL
 	 */
-	void (*seq_els_rsp_send)(struct fc_seq *, enum fc_els_cmd,
+	void (*seq_els_rsp_send)(struct fc_frame *, enum fc_els_cmd,
 				 struct fc_seq_els_data *);
 
 	/*
@@ -583,8 +580,7 @@ struct libfc_function_template {
 	 *
 	 * STATUS: OPTIONAL
 	 */
-	void (*lport_recv)(struct fc_lport *, struct fc_seq *,
-			   struct fc_frame *);
+	void (*lport_recv)(struct fc_lport *, struct fc_frame *);
 
 	/*
 	 * Reset the local port.
@@ -646,8 +642,7 @@ struct libfc_function_template {
 	 *
 	 * STATUS: OPTIONAL
 	 */
-	void (*rport_recv_req)(struct fc_seq *, struct fc_frame *,
-			       struct fc_lport *);
+	void (*rport_recv_req)(struct fc_lport *, struct fc_frame *);
 
 	/*
 	 * lookup an rport by it's port ID.
@@ -693,8 +688,7 @@ struct libfc_function_template {
 	 *
 	 * STATUS: OPTIONAL
 	 */
-	void (*disc_recv_req)(struct fc_seq *, struct fc_frame *,
-			      struct fc_lport *);
+	void (*disc_recv_req)(struct fc_lport *, struct fc_frame *);
 
 	/*
 	 * Start discovery for a local port.
#30 lore raw

PATCH 25/28 fcoe: fix offload feature flag change from netdev

In reply to Robert Love

From: Yi Zou <[email protected]>

Currently, when FCoE netdev feature flags are toggled by the LLD, lport's corresponding flags are not updated. This causes the fc_fcp to still try to offload the I/O. This patch adds support of NETDEV_FEAT_CHANGE event in fcoe netdev device notification callback so we can update the lport offload flags appropriately.

---
 drivers/scsi/fcoe/fcoe.c |   68 +++++++++++++++++++++++++++++++++-------------
 1 files changed, 49 insertions(+), 19 deletions(-)
drivers/scsi/fcoe/fcoe.c +49 -19
index ab6ea60..cf9d718 100644
@@ -589,6 +589,50 @@ static int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type)
 }
 
 /**
+ * fcoe_netdev_features_change - Updates the lport's offload flags based
+ * on the LLD netdev's FCoE feature flags
+ */
+static void fcoe_netdev_features_change(struct fc_lport *lport,
+					struct net_device *netdev)
+{
+	mutex_lock(&lport->lp_mutex);
+
+	if (netdev->features & NETIF_F_SG)
+		lport->sg_supp = 1;
+	else
+		lport->sg_supp = 0;
+
+	if (netdev->features & NETIF_F_FCOE_CRC) {
+		lport->crc_offload = 1;
+		FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
+	} else {
+		lport->crc_offload = 0;
+	}
+
+	if (netdev->features & NETIF_F_FSO) {
+		lport->seq_offload = 1;
+		lport->lso_max = netdev->gso_max_size;
+		FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
+				lport->lso_max);
+	} else {
+		lport->seq_offload = 0;
+		lport->lso_max = 0;
+	}
+
+	if (netdev->fcoe_ddp_xid) {
+		lport->lro_enabled = 1;
+		lport->lro_xid = netdev->fcoe_ddp_xid;
+		FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n",
+				lport->lro_xid);
+	} else {
+		lport->lro_enabled = 0;
+		lport->lro_xid = 0;
+	}
+
+	mutex_unlock(&lport->lp_mutex);
+}
+
+/**
  * fcoe_netdev_config() - Set up net devive for SW FCoE
  * @lport:  The local port that is associated with the net device
  * @netdev: The associated net device
@@ -624,25 +668,8 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
 		return -EINVAL;
 
 	/* offload features support */
-	if (netdev->features & NETIF_F_SG)
-		lport->sg_supp = 1;
+	fcoe_netdev_features_change(lport, netdev);
 
-	if (netdev->features & NETIF_F_FCOE_CRC) {
-		lport->crc_offload = 1;
-		FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n");
-	}
-	if (netdev->features & NETIF_F_FSO) {
-		lport->seq_offload = 1;
-		lport->lso_max = netdev->gso_max_size;
-		FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n",
-				lport->lso_max);
-	}
-	if (netdev->fcoe_ddp_xid) {
-		lport->lro_enabled = 1;
-		lport->lro_xid = netdev->fcoe_ddp_xid;
-		FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n",
-				lport->lro_xid);
-	}
 	skb_queue_head_init(&port->fcoe_pending_queue);
 	port->fcoe_pending_queue_active = 0;
 	setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport);
@@ -1861,6 +1888,9 @@ static int fcoe_device_notification(struct notifier_block *notifier,
 		schedule_work(&port->destroy_work);
 		goto out;
 		break;
+	case NETDEV_FEAT_CHANGE:
+		fcoe_netdev_features_change(lport, netdev);
+		break;
 	default:
 		FCOE_NETDEV_DBG(netdev, "Unknown event %ld "
 				"from netdev netlink\n", event);
@@ -2056,8 +2086,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)
 		rc = -ENODEV;
 		goto out_putdev;
 	}
-	list_del(&fcoe->list);
 	fcoe_interface_cleanup(fcoe);
+	list_del(&fcoe->list);
 	/* RTNL mutex is dropped by fcoe_if_destroy */
 	fcoe_if_destroy(fcoe->ctlr.lp);
 
#31 lore raw

PATCH 26/28 Revert "[SCSI] fcoe: Fix using VLAN ID in creating lport's WWWN/WWPN"

In reply to Robert Love

From: Vasu Dev <[email protected]>

This reverts commit cc0136c2e9c10e889cb36e39710c0eb10707b396.

That commit introduced vlan id info to WWPN but WWPN needs to remain static as an unique port identifier in the fabric, therefore variable fabric vlan id info doesn't need to be coded inside WWPN.

After this revert, port arg to fcoe_wwn_from_mac is always zero but still leaving it as-is okay to later allow users to use NAA 2 scheme with this additional port arg.

Note with this patch, existing zoning using WWPN would require re-zoning this time only and later no more re-zoning due to any vlan id changes.

---
 drivers/scsi/fcoe/fcoe.c |   11 +----------
 1 files changed, 1 insertions(+), 10 deletions(-)
drivers/scsi/fcoe/fcoe.c +1 -10
index cf9d718..ddd2ca2 100644
@@ -647,7 +647,6 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
 	u64 wwnn, wwpn;
 	struct fcoe_interface *fcoe;
 	struct fcoe_port *port;
-	int vid = 0;
 
 	/* Setup lport private data to point to fcoe softc */
 	port = lport_priv(lport);
@@ -677,20 +676,12 @@ static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev)
 	fcoe_link_speed_update(lport);
 
 	if (!lport->vport) {
-		/*
-		 * Use NAA 1&2 (FC-FS Rev. 2.0, Sec. 15) to generate WWNN/WWPN:
-		 * For WWNN, we use NAA 1 w/ bit 27-16 of word 0 as 0.
-		 * For WWPN, we use NAA 2 w/ bit 27-16 of word 0 from VLAN ID
-		 */
-		if (netdev->priv_flags & IFF_802_1Q_VLAN)
-			vid = vlan_dev_vlan_id(netdev);
-
 		if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN))
 			wwnn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 1, 0);
 		fc_set_wwnn(lport, wwnn);
 		if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN))
 			wwpn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr,
-						 2, vid);
+						 2, 0);
 		fc_set_wwpn(lport, wwpn);
 	}
 
#32 lore raw

PATCH 27/28 libfc: Add retry logic to lport state machine when receiving LS_RJT

In reply to Robert Love

From: Bhanu Prakash Gollapudi <[email protected]>

Call fc_lport_error to retry upto max retry count when FLOGI/SCR/NS gets rejected.

---
 drivers/scsi/libfc/fc_lport.c |   63 ++++++++++++++++++-----------------------
 1 files changed, 27 insertions(+), 36 deletions(-)
drivers/scsi/libfc/fc_lport.c +27 -36
index 1998c03..6eb334a 100644
@@ -1012,38 +1012,24 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)
 		     PTR_ERR(fp), fc_lport_state(lport),
 		     lport->retry_count);
 
-	if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
-		/*
-		 * Memory allocation failure, or the exchange timed out.
-		 *  Retry after delay
-		 */
-		if (lport->retry_count < lport->max_retry_count) {
-			lport->retry_count++;
-			if (!fp)
-				delay = msecs_to_jiffies(500);
-			else
-				delay =	msecs_to_jiffies(lport->e_d_tov);
-
-			schedule_delayed_work(&lport->retry_work, delay);
-		} else {
-			switch (lport->state) {
-			case LPORT_ST_DISABLED:
-			case LPORT_ST_READY:
-			case LPORT_ST_RESET:
-			case LPORT_ST_RNN_ID:
-			case LPORT_ST_RSNN_NN:
-			case LPORT_ST_RSPN_ID:
-			case LPORT_ST_RFT_ID:
-			case LPORT_ST_RFF_ID:
-			case LPORT_ST_SCR:
-			case LPORT_ST_DNS:
-			case LPORT_ST_FLOGI:
-			case LPORT_ST_LOGO:
-				fc_lport_enter_reset(lport);
-				break;
-			}
-		}
-	}
+	if (PTR_ERR(fp) == -FC_EX_CLOSED)
+		return;
+
+	/*
+	 * Memory allocation failure, or the exchange timed out
+	 * or we received LS_RJT.
+	 * Retry after delay
+	 */
+	if (lport->retry_count < lport->max_retry_count) {
+		lport->retry_count++;
+		if (!fp)
+			delay = msecs_to_jiffies(500);
+		else
+			delay =	msecs_to_jiffies(lport->e_d_tov);
+
+		schedule_delayed_work(&lport->retry_work, delay);
+	} else
+		fc_lport_enter_reset(lport);
 }
 
 /**
@@ -1461,7 +1447,13 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 	}
 
 	did = fc_frame_did(fp);
-	if (fc_frame_payload_op(fp) == ELS_LS_ACC && did != 0) {
+
+	if (!did) {
+		FC_LPORT_DBG(lport, "Bad FLOGI response\n");
+		goto out;
+	}
+
+	if (fc_frame_payload_op(fp) == ELS_LS_ACC) {
 		flp = fc_frame_payload_get(fp, sizeof(*flp));
 		if (flp) {
 			mfs = ntohs(flp->fl_csp.sp_bb_data) &
@@ -1500,9 +1492,8 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,
 				fc_lport_enter_dns(lport);
 			}
 		}
-	} else {
-		FC_LPORT_DBG(lport, "Bad FLOGI response\n");
-	}
+	} else
+		fc_lport_error(lport, fp);
 
 out:
 	fc_frame_free(fp);
#33 lore raw

PATCH 28/28 fcoe: remove check for zero fabric name

In reply to Robert Love

From: Vasu Dev <[email protected]>

This check prevents FCF selection in NPV mode due to zero fabric name in that case and in turn flogi fails. Though NPV mode should not have this zero and should be fixed there also but spec also does not require initiator to ensure that fabric name must be non-zero, therefore dropping this check to get flogi working in NPV mode.

---
 drivers/scsi/fcoe/libfcoe.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/fcoe/libfcoe.c +1 -1
index 2c265fe..aa503d8 100644
@@ -845,7 +845,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
 	}
 	if (!fcf->fc_map || (fcf->fc_map & 0x10000))
 		return -EINVAL;
-	if (!fcf->switch_name || !fcf->fabric_name)
+	if (!fcf->switch_name)
 		return -EINVAL;
 	if (desc_mask) {
 		LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n",