[SCSI] libfc: Enhanced exchange ID selection mechanism and fix related EMA selection logic.

Problem:

In case of exchange responder case, EMA selection was defaulted to the
last EMA from EMA list (lport.ema_list).  If exchange ID is selected
from offload pool and not setup DDP, resulting into incorrect
selection of EMA, and eventually dropping the packet because unable to
find exchange.

Fix:

Enhanced the exchange ID selection (depending upon request type and
exchange responder) Made necessary enhancement in EMA selection
algorithm.

Signed-off-by: Kiran Patil <kiran.patil@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
Kiran Patil 2011-01-28 16:04:39 -08:00 committed by James Bottomley
parent 62bdb6455e
commit 6c8cc1c003

View file

@ -2280,17 +2280,46 @@ void fc_exch_mgr_free(struct fc_lport *lport)
}
EXPORT_SYMBOL(fc_exch_mgr_free);
/**
* fc_find_ema() - Lookup and return appropriate Exchange Manager Anchor depending
* upon 'xid'.
* @f_ctl: f_ctl
* @lport: The local port the frame was received on
* @fh: The received frame header
*/
static struct fc_exch_mgr_anchor *fc_find_ema(u32 f_ctl,
struct fc_lport *lport,
struct fc_frame_header *fh)
{
struct fc_exch_mgr_anchor *ema;
u16 xid;
if (f_ctl & FC_FC_EX_CTX)
xid = ntohs(fh->fh_ox_id);
else {
xid = ntohs(fh->fh_rx_id);
if (xid == FC_XID_UNKNOWN)
return list_entry(lport->ema_list.prev,
typeof(*ema), ema_list);
}
list_for_each_entry(ema, &lport->ema_list, ema_list) {
if ((xid >= ema->mp->min_xid) &&
(xid <= ema->mp->max_xid))
return ema;
}
return NULL;
}
/**
* fc_exch_recv() - Handler for received frames
* @lport: The local port the frame was received on
* @fp: The received frame
* @fp: The received frame
*/
void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
{
struct fc_frame_header *fh = fc_frame_header_get(fp);
struct fc_exch_mgr_anchor *ema;
u32 f_ctl, found = 0;
u16 oxid;
u32 f_ctl;
/* lport lock ? */
if (!lport || lport->state == LPORT_ST_DISABLED) {
@ -2301,24 +2330,17 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
}
f_ctl = ntoh24(fh->fh_f_ctl);
oxid = ntohs(fh->fh_ox_id);
if (f_ctl & FC_FC_EX_CTX) {
list_for_each_entry(ema, &lport->ema_list, ema_list) {
if ((oxid >= ema->mp->min_xid) &&
(oxid <= ema->mp->max_xid)) {
found = 1;
break;
}
}
if (!found) {
FC_LPORT_DBG(lport, "Received response for out "
"of range oxid:%hx\n", oxid);
fc_frame_free(fp);
return;
}
} else
ema = list_entry(lport->ema_list.prev, typeof(*ema), ema_list);
ema = fc_find_ema(f_ctl, lport, fh);
if (!ema) {
FC_LPORT_DBG(lport, "Unable to find Exchange Manager Anchor,"
"fc_ctl <0x%x>, xid <0x%x>\n",
f_ctl,
(f_ctl & FC_FC_EX_CTX) ?
ntohs(fh->fh_ox_id) :
ntohs(fh->fh_rx_id));
fc_frame_free(fp);
return;
}
/*
* If frame is marked invalid, just drop it.