From 6c8cc1c003cee1c4290f5d8c684912d60354056a Mon Sep 17 00:00:00 2001 From: Kiran Patil Date: Fri, 28 Jan 2011 16:04:39 -0800 Subject: [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 Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_exch.c | 64 +++++++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index a3d640289dc..08bf5fa6afd 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -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. -- cgit v1.2.3-18-g5258