Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6c8cc1c0 authored by Kiran Patil's avatar Kiran Patil Committed by James Bottomley
Browse files

[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: default avatarKiran Patil <kiran.patil@intel.com>
Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 62bdb645
Loading
Loading
Loading
Loading
+43 −21
Original line number Diff line number Diff line
@@ -2280,6 +2280,36 @@ 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
@@ -2289,8 +2319,7 @@ 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);
	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;
	}
	} else
		ema = list_entry(lport->ema_list.prev, typeof(*ema), ema_list);

	/*
	 * If frame is marked invalid, just drop it.