aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc/fc_exch.c
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2010-07-20 18:21:12 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-28 10:06:02 -0400
commit922611569572d3c1aa0ed6491d21583fb3fcca22 (patch)
treef7cb42bf5519d1c42853808f2f784188afe1bc2e /drivers/scsi/libfc/fc_exch.c
parent239e81048b7dcd27448db40c845f88ac7c68424e (diff)
[SCSI] libfc: don't require a local exchange for incoming requests
Incoming requests shouldn't require a local exchange if we're just going to reply with one or two frames and don't expect anything further. Don't allocate exchanges for such requests until requested by the upper-layer protocol. The sequence is always NULL for new requests, so remove that as an argument to request handlers. Also change the first argument to lport->tt.seq_els_rsp_send from the sequence pointer to the received frame pointer, to supply the exchange IDs and destination ID info. Signed-off-by: Joe Eykholt <jeykholt@cisco.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/libfc/fc_exch.c')
-rw-r--r--drivers/scsi/libfc/fc_exch.c188
1 files changed, 100 insertions, 88 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 027042a6de3b..b8560ad8cf66 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -129,11 +129,11 @@ struct fc_exch_mgr_anchor {
129}; 129};
130 130
131static void fc_exch_rrq(struct fc_exch *); 131static void fc_exch_rrq(struct fc_exch *);
132static void fc_seq_ls_acc(struct fc_seq *); 132static void fc_seq_ls_acc(struct fc_frame *);
133static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason, 133static void fc_seq_ls_rjt(struct fc_frame *, enum fc_els_rjt_reason,
134 enum fc_els_rjt_explan); 134 enum fc_els_rjt_explan);
135static void fc_exch_els_rec(struct fc_seq *, struct fc_frame *); 135static void fc_exch_els_rec(struct fc_frame *);
136static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *); 136static void fc_exch_els_rrq(struct fc_frame *);
137 137
138/* 138/*
139 * Internal implementation notes. 139 * Internal implementation notes.
@@ -1003,28 +1003,30 @@ static void fc_exch_set_addr(struct fc_exch *ep,
1003/** 1003/**
1004 * fc_seq_els_rsp_send() - Send an ELS response using infomation from 1004 * fc_seq_els_rsp_send() - Send an ELS response using infomation from
1005 * the existing sequence/exchange. 1005 * the existing sequence/exchange.
1006 * @sp: The sequence/exchange to get information from 1006 * @fp: The received frame
1007 * @els_cmd: The ELS command to be sent 1007 * @els_cmd: The ELS command to be sent
1008 * @els_data: The ELS data to be sent 1008 * @els_data: The ELS data to be sent
1009 *
1010 * The received frame is not freed.
1009 */ 1011 */
1010static void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd, 1012static void fc_seq_els_rsp_send(struct fc_frame *fp, enum fc_els_cmd els_cmd,
1011 struct fc_seq_els_data *els_data) 1013 struct fc_seq_els_data *els_data)
1012{ 1014{
1013 switch (els_cmd) { 1015 switch (els_cmd) {
1014 case ELS_LS_RJT: 1016 case ELS_LS_RJT:
1015 fc_seq_ls_rjt(sp, els_data->reason, els_data->explan); 1017 fc_seq_ls_rjt(fp, els_data->reason, els_data->explan);
1016 break; 1018 break;
1017 case ELS_LS_ACC: 1019 case ELS_LS_ACC:
1018 fc_seq_ls_acc(sp); 1020 fc_seq_ls_acc(fp);
1019 break; 1021 break;
1020 case ELS_RRQ: 1022 case ELS_RRQ:
1021 fc_exch_els_rrq(sp, els_data->fp); 1023 fc_exch_els_rrq(fp);
1022 break; 1024 break;
1023 case ELS_REC: 1025 case ELS_REC:
1024 fc_exch_els_rec(sp, els_data->fp); 1026 fc_exch_els_rec(fp);
1025 break; 1027 break;
1026 default: 1028 default:
1027 FC_EXCH_DBG(fc_seq_exch(sp), "Invalid ELS CMD:%x\n", els_cmd); 1029 FC_LPORT_DBG(fr_dev(fp), "Invalid ELS CMD:%x\n", els_cmd);
1028 } 1030 }
1029} 1031}
1030 1032
@@ -1253,11 +1255,13 @@ static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
1253} 1255}
1254 1256
1255/** 1257/**
1256 * fc_exch_recv_req() - Handler for an incoming request where is other 1258 * fc_exch_recv_req() - Handler for an incoming request
1257 * end is originating the sequence
1258 * @lport: The local port that received the request 1259 * @lport: The local port that received the request
1259 * @mp: The EM that the exchange is on 1260 * @mp: The EM that the exchange is on
1260 * @fp: The request frame 1261 * @fp: The request frame
1262 *
1263 * This is used when the other end is originating the exchange
1264 * and the sequence.
1261 */ 1265 */
1262static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, 1266static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
1263 struct fc_frame *fp) 1267 struct fc_frame *fp)
@@ -1275,8 +1279,17 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
1275 fc_frame_free(fp); 1279 fc_frame_free(fp);
1276 return; 1280 return;
1277 } 1281 }
1282 fr_dev(fp) = lport;
1283
1284 BUG_ON(fr_seq(fp)); /* XXX remove later */
1285
1286 /*
1287 * If the RX_ID is 0xffff, don't allocate an exchange.
1288 * The upper-level protocol may request one later, if needed.
1289 */
1290 if (fh->fh_rx_id == htons(FC_XID_UNKNOWN))
1291 return lport->tt.lport_recv(lport, fp);
1278 1292
1279 fr_seq(fp) = NULL;
1280 reject = fc_seq_lookup_recip(lport, mp, fp); 1293 reject = fc_seq_lookup_recip(lport, mp, fp);
1281 if (reject == FC_RJT_NONE) { 1294 if (reject == FC_RJT_NONE) {
1282 sp = fr_seq(fp); /* sequence will be held */ 1295 sp = fr_seq(fp); /* sequence will be held */
@@ -1298,7 +1311,7 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
1298 if (ep->resp) 1311 if (ep->resp)
1299 ep->resp(sp, fp, ep->arg); 1312 ep->resp(sp, fp, ep->arg);
1300 else 1313 else
1301 lport->tt.lport_recv(lport, sp, fp); 1314 lport->tt.lport_recv(lport, fp);
1302 fc_exch_release(ep); /* release from lookup */ 1315 fc_exch_release(ep); /* release from lookup */
1303 } else { 1316 } else {
1304 FC_LPORT_DBG(lport, "exch/seq lookup failed: reject %x\n", 1317 FC_LPORT_DBG(lport, "exch/seq lookup failed: reject %x\n",
@@ -1566,53 +1579,55 @@ static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp)
1566 1579
1567/** 1580/**
1568 * fc_seq_ls_acc() - Accept sequence with LS_ACC 1581 * fc_seq_ls_acc() - Accept sequence with LS_ACC
1569 * @req_sp: The request sequence 1582 * @rx_fp: The received frame, not freed here.
1570 * 1583 *
1571 * If this fails due to allocation or transmit congestion, assume the 1584 * If this fails due to allocation or transmit congestion, assume the
1572 * originator will repeat the sequence. 1585 * originator will repeat the sequence.
1573 */ 1586 */
1574static void fc_seq_ls_acc(struct fc_seq *req_sp) 1587static void fc_seq_ls_acc(struct fc_frame *rx_fp)
1575{ 1588{
1576 struct fc_seq *sp; 1589 struct fc_lport *lport;
1577 struct fc_els_ls_acc *acc; 1590 struct fc_els_ls_acc *acc;
1578 struct fc_frame *fp; 1591 struct fc_frame *fp;
1579 1592
1580 sp = fc_seq_start_next(req_sp); 1593 lport = fr_dev(rx_fp);
1581 fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc)); 1594 fp = fc_frame_alloc(lport, sizeof(*acc));
1582 if (fp) { 1595 if (!fp)
1583 acc = fc_frame_payload_get(fp, sizeof(*acc)); 1596 return;
1584 memset(acc, 0, sizeof(*acc)); 1597 acc = fc_frame_payload_get(fp, sizeof(*acc));
1585 acc->la_cmd = ELS_LS_ACC; 1598 memset(acc, 0, sizeof(*acc));
1586 fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); 1599 acc->la_cmd = ELS_LS_ACC;
1587 } 1600 fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
1601 lport->tt.frame_send(lport, fp);
1588} 1602}
1589 1603
1590/** 1604/**
1591 * fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT 1605 * fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT
1592 * @req_sp: The request sequence 1606 * @rx_fp: The received frame, not freed here.
1593 * @reason: The reason the sequence is being rejected 1607 * @reason: The reason the sequence is being rejected
1594 * @explan: The explaination for the rejection 1608 * @explan: The explanation for the rejection
1595 * 1609 *
1596 * If this fails due to allocation or transmit congestion, assume the 1610 * If this fails due to allocation or transmit congestion, assume the
1597 * originator will repeat the sequence. 1611 * originator will repeat the sequence.
1598 */ 1612 */
1599static void fc_seq_ls_rjt(struct fc_seq *req_sp, enum fc_els_rjt_reason reason, 1613static void fc_seq_ls_rjt(struct fc_frame *rx_fp, enum fc_els_rjt_reason reason,
1600 enum fc_els_rjt_explan explan) 1614 enum fc_els_rjt_explan explan)
1601{ 1615{
1602 struct fc_seq *sp; 1616 struct fc_lport *lport;
1603 struct fc_els_ls_rjt *rjt; 1617 struct fc_els_ls_rjt *rjt;
1604 struct fc_frame *fp; 1618 struct fc_frame *fp;
1605 1619
1606 sp = fc_seq_start_next(req_sp); 1620 lport = fr_dev(rx_fp);
1607 fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*rjt)); 1621 fp = fc_frame_alloc(lport, sizeof(*rjt));
1608 if (fp) { 1622 if (!fp)
1609 rjt = fc_frame_payload_get(fp, sizeof(*rjt)); 1623 return;
1610 memset(rjt, 0, sizeof(*rjt)); 1624 rjt = fc_frame_payload_get(fp, sizeof(*rjt));
1611 rjt->er_cmd = ELS_LS_RJT; 1625 memset(rjt, 0, sizeof(*rjt));
1612 rjt->er_reason = reason; 1626 rjt->er_cmd = ELS_LS_RJT;
1613 rjt->er_explan = explan; 1627 rjt->er_reason = reason;
1614 fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); 1628 rjt->er_explan = explan;
1615 } 1629 fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
1630 lport->tt.frame_send(lport, fp);
1616} 1631}
1617 1632
1618/** 1633/**
@@ -1715,17 +1730,33 @@ void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did)
1715EXPORT_SYMBOL(fc_exch_mgr_reset); 1730EXPORT_SYMBOL(fc_exch_mgr_reset);
1716 1731
1717/** 1732/**
1733 * fc_exch_lookup() - find an exchange
1734 * @lport: The local port
1735 * @xid: The exchange ID
1736 *
1737 * Returns exchange pointer with hold for caller, or NULL if not found.
1738 */
1739static struct fc_exch *fc_exch_lookup(struct fc_lport *lport, u32 xid)
1740{
1741 struct fc_exch_mgr_anchor *ema;
1742
1743 list_for_each_entry(ema, &lport->ema_list, ema_list)
1744 if (ema->mp->min_xid <= xid && xid <= ema->mp->max_xid)
1745 return fc_exch_find(ema->mp, xid);
1746 return NULL;
1747}
1748
1749/**
1718 * fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests 1750 * fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests
1719 * @sp: The sequence the REC is on 1751 * @rfp: The REC frame, not freed here.
1720 * @rfp: The REC frame
1721 * 1752 *
1722 * Note that the requesting port may be different than the S_ID in the request. 1753 * Note that the requesting port may be different than the S_ID in the request.
1723 */ 1754 */
1724static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp) 1755static void fc_exch_els_rec(struct fc_frame *rfp)
1725{ 1756{
1757 struct fc_lport *lport;
1726 struct fc_frame *fp; 1758 struct fc_frame *fp;
1727 struct fc_exch *ep; 1759 struct fc_exch *ep;
1728 struct fc_exch_mgr *em;
1729 struct fc_els_rec *rp; 1760 struct fc_els_rec *rp;
1730 struct fc_els_rec_acc *acc; 1761 struct fc_els_rec_acc *acc;
1731 enum fc_els_rjt_reason reason = ELS_RJT_LOGIC; 1762 enum fc_els_rjt_reason reason = ELS_RJT_LOGIC;
@@ -1734,6 +1765,7 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
1734 u16 rxid; 1765 u16 rxid;
1735 u16 oxid; 1766 u16 oxid;
1736 1767
1768 lport = fr_dev(rfp);
1737 rp = fc_frame_payload_get(rfp, sizeof(*rp)); 1769 rp = fc_frame_payload_get(rfp, sizeof(*rp));
1738 explan = ELS_EXPL_INV_LEN; 1770 explan = ELS_EXPL_INV_LEN;
1739 if (!rp) 1771 if (!rp)
@@ -1742,35 +1774,19 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
1742 rxid = ntohs(rp->rec_rx_id); 1774 rxid = ntohs(rp->rec_rx_id);
1743 oxid = ntohs(rp->rec_ox_id); 1775 oxid = ntohs(rp->rec_ox_id);
1744 1776
1745 /* 1777 ep = fc_exch_lookup(lport,
1746 * Currently it's hard to find the local S_ID from the exchange 1778 sid == fc_host_port_id(lport->host) ? oxid : rxid);
1747 * manager. This will eventually be fixed, but for now it's easier
1748 * to lookup the subject exchange twice, once as if we were
1749 * the initiator, and then again if we weren't.
1750 */
1751 em = fc_seq_exch(sp)->em;
1752 ep = fc_exch_find(em, oxid);
1753 explan = ELS_EXPL_OXID_RXID; 1779 explan = ELS_EXPL_OXID_RXID;
1754 if (ep && ep->oid == sid) { 1780 if (!ep)
1755 if (ep->rxid != FC_XID_UNKNOWN && 1781 goto reject;
1756 rxid != FC_XID_UNKNOWN && 1782 if (ep->oid != sid || oxid != ep->oxid)
1757 ep->rxid != rxid) 1783 goto rel;
1758 goto rel; 1784 if (rxid != FC_XID_UNKNOWN && rxid != ep->rxid)
1759 } else { 1785 goto rel;
1760 if (ep) 1786 fp = fc_frame_alloc(lport, sizeof(*acc));
1761 fc_exch_release(ep); 1787 if (!fp)
1762 ep = NULL;
1763 if (rxid != FC_XID_UNKNOWN)
1764 ep = fc_exch_find(em, rxid);
1765 if (!ep)
1766 goto reject;
1767 }
1768
1769 fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc));
1770 if (!fp) {
1771 fc_exch_done(sp);
1772 goto out; 1788 goto out;
1773 } 1789
1774 acc = fc_frame_payload_get(fp, sizeof(*acc)); 1790 acc = fc_frame_payload_get(fp, sizeof(*acc));
1775 memset(acc, 0, sizeof(*acc)); 1791 memset(acc, 0, sizeof(*acc));
1776 acc->reca_cmd = ELS_LS_ACC; 1792 acc->reca_cmd = ELS_LS_ACC;
@@ -1785,18 +1801,16 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
1785 acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP | 1801 acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP |
1786 ESB_ST_SEQ_INIT | 1802 ESB_ST_SEQ_INIT |
1787 ESB_ST_COMPLETE)); 1803 ESB_ST_COMPLETE));
1788 sp = fc_seq_start_next(sp); 1804 fc_fill_reply_hdr(fp, rfp, FC_RCTL_ELS_REP, 0);
1789 fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS); 1805 lport->tt.frame_send(lport, fp);
1790out: 1806out:
1791 fc_exch_release(ep); 1807 fc_exch_release(ep);
1792 fc_frame_free(rfp);
1793 return; 1808 return;
1794 1809
1795rel: 1810rel:
1796 fc_exch_release(ep); 1811 fc_exch_release(ep);
1797reject: 1812reject:
1798 fc_seq_ls_rjt(sp, reason, explan); 1813 fc_seq_ls_rjt(rfp, reason, explan);
1799 fc_frame_free(rfp);
1800} 1814}
1801 1815
1802/** 1816/**
@@ -1971,20 +1985,20 @@ retry:
1971 spin_unlock_bh(&ep->ex_lock); 1985 spin_unlock_bh(&ep->ex_lock);
1972} 1986}
1973 1987
1974
1975/** 1988/**
1976 * fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests 1989 * fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests
1977 * @sp: The sequence that the RRQ is on 1990 * @fp: The RRQ frame, not freed here.
1978 * @fp: The RRQ frame
1979 */ 1991 */
1980static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp) 1992static void fc_exch_els_rrq(struct fc_frame *fp)
1981{ 1993{
1994 struct fc_lport *lport;
1982 struct fc_exch *ep = NULL; /* request or subject exchange */ 1995 struct fc_exch *ep = NULL; /* request or subject exchange */
1983 struct fc_els_rrq *rp; 1996 struct fc_els_rrq *rp;
1984 u32 sid; 1997 u32 sid;
1985 u16 xid; 1998 u16 xid;
1986 enum fc_els_rjt_explan explan; 1999 enum fc_els_rjt_explan explan;
1987 2000
2001 lport = fr_dev(fp);
1988 rp = fc_frame_payload_get(fp, sizeof(*rp)); 2002 rp = fc_frame_payload_get(fp, sizeof(*rp));
1989 explan = ELS_EXPL_INV_LEN; 2003 explan = ELS_EXPL_INV_LEN;
1990 if (!rp) 2004 if (!rp)
@@ -1993,11 +2007,10 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
1993 /* 2007 /*
1994 * lookup subject exchange. 2008 * lookup subject exchange.
1995 */ 2009 */
1996 ep = fc_seq_exch(sp);
1997 sid = ntoh24(rp->rrq_s_id); /* subject source */ 2010 sid = ntoh24(rp->rrq_s_id); /* subject source */
1998 xid = ep->did == sid ? ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id); 2011 xid = fc_host_port_id(lport->host) == sid ?
1999 ep = fc_exch_find(ep->em, xid); 2012 ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id);
2000 2013 ep = fc_exch_lookup(lport, xid);
2001 explan = ELS_EXPL_OXID_RXID; 2014 explan = ELS_EXPL_OXID_RXID;
2002 if (!ep) 2015 if (!ep)
2003 goto reject; 2016 goto reject;
@@ -2028,15 +2041,14 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
2028 /* 2041 /*
2029 * Send LS_ACC. 2042 * Send LS_ACC.
2030 */ 2043 */
2031 fc_seq_ls_acc(sp); 2044 fc_seq_ls_acc(fp);
2032 goto out; 2045 goto out;
2033 2046
2034unlock_reject: 2047unlock_reject:
2035 spin_unlock_bh(&ep->ex_lock); 2048 spin_unlock_bh(&ep->ex_lock);
2036reject: 2049reject:
2037 fc_seq_ls_rjt(sp, ELS_RJT_LOGIC, explan); 2050 fc_seq_ls_rjt(fp, ELS_RJT_LOGIC, explan);
2038out: 2051out:
2039 fc_frame_free(fp);
2040 if (ep) 2052 if (ep)
2041 fc_exch_release(ep); /* drop hold from fc_exch_find */ 2053 fc_exch_release(ep); /* drop hold from fc_exch_find */
2042} 2054}
@@ -2267,7 +2279,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
2267 fc_exch_recv_seq_resp(ema->mp, fp); 2279 fc_exch_recv_seq_resp(ema->mp, fp);
2268 else if (f_ctl & FC_FC_SEQ_CTX) 2280 else if (f_ctl & FC_FC_SEQ_CTX)
2269 fc_exch_recv_resp(ema->mp, fp); 2281 fc_exch_recv_resp(ema->mp, fp);
2270 else 2282 else /* no EX_CTX and no SEQ_CTX */
2271 fc_exch_recv_req(lport, ema->mp, fp); 2283 fc_exch_recv_req(lport, ema->mp, fp);
2272 break; 2284 break;
2273 default: 2285 default: