diff options
Diffstat (limited to 'drivers/scsi/libfc')
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 35 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_fcp.c | 9 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_lport.c | 3 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_rport.c | 28 |
4 files changed, 50 insertions, 25 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 3b8a6451ea2..01ff082dc34 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; @@ -965,8 +963,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)); @@ -2443,8 +2463,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; } /** diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 9cd2149519a..afb63c84314 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -498,7 +498,7 @@ crc_err: stats = per_cpu_ptr(lport->dev_stats, get_cpu()); stats->ErrorFrames++; /* per cpu count, not total count, but OK for limit */ - if (stats->InvalidCRCCount++ < 5) + if (stats->InvalidCRCCount++ < FC_MAX_ERROR_CNT) printk(KERN_WARNING "libfc: CRC error on data " "frame for port (%6.6x)\n", lport->port_id); @@ -690,7 +690,7 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, } /** - * fc_fcp_abts_resp() - Send an ABTS response + * fc_fcp_abts_resp() - Receive an ABTS response * @fsp: The FCP packet that is being aborted * @fp: The response frame */ @@ -730,7 +730,7 @@ static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) } /** - * fc_fcp_recv() - Reveive an FCP frame + * fc_fcp_recv() - Receive an FCP frame * @seq: The sequence the frame is on * @fp: The received frame * @arg: The related FCP packet @@ -1084,6 +1084,7 @@ static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp) rc = lport->tt.fcp_cmd_send(lport, fsp, fc_fcp_recv); if (unlikely(rc)) { spin_lock_irqsave(&si->scsi_queue_lock, flags); + fsp->cmd->SCp.ptr = NULL; list_del(&fsp->list); spin_unlock_irqrestore(&si->scsi_queue_lock, flags); } @@ -1645,12 +1646,10 @@ static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) struct fc_seq *seq; struct fcp_srr *srr; struct fc_frame *fp; - u8 cdb_op; unsigned int rec_tov; rport = fsp->rport; rpriv = rport->dd_data; - cdb_op = fsp->cdb_cmd.fc_cdb[0]; if (!(rpriv->flags & FC_RP_FLAGS_RETRY) || rpriv->rp_state != RPORT_ST_READY) diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 389ab80aef0..e55ed9cf23f 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1025,6 +1025,8 @@ static void fc_lport_enter_reset(struct fc_lport *lport) fc_vport_set_state(lport->vport, FC_VPORT_LINKDOWN); } fc_lport_state_enter(lport, LPORT_ST_RESET); + fc_host_post_event(lport->host, fc_get_event_number(), + FCH_EVT_LIPRESET, 0); fc_vports_linkchange(lport); fc_lport_reset_locked(lport); if (lport->link_up) @@ -1350,7 +1352,6 @@ static void fc_lport_timeout(struct work_struct *work) WARN_ON(1); break; case LPORT_ST_READY: - WARN_ON(1); break; case LPORT_ST_RESET: break; diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c index 49e1ccca09d..760db761944 100644 --- a/drivers/scsi/libfc/fc_rport.c +++ b/drivers/scsi/libfc/fc_rport.c @@ -153,18 +153,6 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, } /** - * 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 */ @@ -173,7 +161,7 @@ static void fc_rport_destroy(struct kref *kref) struct fc_rport_priv *rdata; rdata = container_of(kref, struct fc_rport_priv, kref); - call_rcu(&rdata->rcu, fc_rport_free_rcu); + kfree_rcu(rdata, rcu); } /** @@ -801,6 +789,20 @@ static void fc_rport_recv_flogi_req(struct fc_lport *lport, switch (rdata->rp_state) { case RPORT_ST_INIT: + /* + * If received the FLOGI request on RPORT which is INIT state + * (means not transition to FLOGI either fc_rport timeout + * function didn;t trigger or this end hasn;t received + * beacon yet from other end. In that case only, allow RPORT + * state machine to continue, otherwise fall through which + * causes the code to send reject response. + * NOTE; Not checking for FIP->state such as VNMP_UP or + * VNMP_CLAIM because if FIP state is not one of those, + * RPORT wouldn;t have created and 'rport_lookup' would have + * failed anyway in that case. + */ + if (lport->point_to_multipoint) + break; case RPORT_ST_DELETE: mutex_unlock(&rdata->rp_mutex); rjt_data.reason = ELS_RJT_FIP; |