From e3e65c69c3cfe8e407797c78fd11808aee1a8a81 Mon Sep 17 00:00:00 2001 From: Kiran Patil Date: Mon, 20 Jun 2011 16:59:30 -0700 Subject: [SCSI] libfc:Fix for exchange/seq loopup failure when FCoE stack is used as target and connected to windows initaitor Problem: Linux based SW target (TCM) connected to windows initiator was unable to satisfy write request of size > 2K. Fix: Existing linux implememtation of FCoE stack is expecting sequence number to match w.r.t incoming framme. When DDP is used on target in response to write request from initiator, SW stack is notified only when last data frame arrives and only the pakcket header of last data frame is posted to NetRx queue of storage. When that last packet was processed in libfc:Exchange layer, implementation was expecting sequence number to match, but in this case sequence number which is embedded in FC Header is assigned by windows initaitor, hence due to sequence number mismatch post-processing which shall result into sending RSP is not done. Enhanced the code to utilize the sequence number of incoming last frame and process the packet so that, it will eventually complete the write request by sending write response (RSP) GOOD. Notes/Dependencies: This patch is validated using windows and linux initiator to make sure, it doesn't break anything. Signed-off-by: Kiran Patil Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/libfc/fc_exch.c') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 3b8a6451ea28..f5a0665b6773 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -965,8 +965,30 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, sp = &ep->seq; if (sp->id != fh->fh_seq_id) { atomic_inc(&mp->stats.seq_not_found); - reject = FC_RJT_SEQ_ID; /* sequence/exch should exist */ - goto rel; + if (f_ctl & FC_FC_END_SEQ) { + /* + * Update sequence_id based on incoming last + * frame of sequence exchange. This is needed + * for FCoE target where DDP has been used + * on target where, stack is indicated only + * about last frame's (payload _header) header. + * Whereas "seq_id" which is part of + * frame_header is allocated by initiator + * which is totally different from "seq_id" + * allocated when XFER_RDY was sent by target. + * To avoid false -ve which results into not + * sending RSP, hence write request on other + * end never finishes. + */ + spin_lock_bh(&ep->ex_lock); + sp->ssb_stat |= SSB_ST_RESP; + sp->id = fh->fh_seq_id; + spin_unlock_bh(&ep->ex_lock); + } else { + /* sequence/exch should exist */ + reject = FC_RJT_SEQ_ID; + goto rel; + } } } WARN_ON(ep != fc_seq_exch(sp)); -- cgit v1.2.3 From 6f06e3a7b2f2d840d42a0c2b9906f444e8f2eba6 Mon Sep 17 00:00:00 2001 From: Hillf Danton Date: Wed, 27 Jul 2011 15:10:34 -0700 Subject: [SCSI] libfc: release exchg cache If fail to create workqueue, the newly created cache for exchg has to be released. Signed-off-by: Hillf Danton Reviewed-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/libfc/fc_exch.c') diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index f5a0665b6773..7baf2239ce07 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -2465,8 +2465,11 @@ int fc_setup_exch_mgr(void) fc_exch_workqueue = create_singlethread_workqueue("fc_exch_workqueue"); if (!fc_exch_workqueue) - return -ENOMEM; + goto err; return 0; +err: + kmem_cache_destroy(fc_em_cachep); + return -ENOMEM; } /** -- cgit v1.2.3 From 324f667833d7ddd9501ed8c0e3ec5754ddb1b695 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Wed, 27 Jul 2011 15:10:39 -0700 Subject: [SCSI] libfc, fcoe: ignore rx frame with wrong xid info Drop the rx frame having xid with wrong cpu info or received with xid not matching to our xid. Not dropping such frame is causing panic as that causes accessing data struct beyond their bounds. Signed-off-by: Vasu Dev Tested-by: Ross Brattain Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 4 ++++ drivers/scsi/libfc/fc_exch.c | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/scsi/libfc/fc_exch.c') diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index f7547fb000c0..945df21ac017 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -1373,6 +1373,10 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, } else cpu = smp_processor_id(); } + + if (cpu >= nr_cpu_ids) + goto err; + fps = &per_cpu(fcoe_percpu, cpu); spin_lock_bh(&fps->fcoe_rx_list.lock); if (unlikely(!fps->thread)) { diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 7baf2239ce07..01ff082dc34c 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -802,10 +802,8 @@ static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid) pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask); spin_lock_bh(&pool->lock); ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order); - if (ep) { + if (ep && ep->xid == xid) fc_exch_hold(ep); - WARN_ON(ep->xid != xid); - } spin_unlock_bh(&pool->lock); } return ep; -- cgit v1.2.3