[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>
This commit is contained in:

committed by
James Bottomley

parent
239e81048b
commit
9226115695
@@ -129,11 +129,11 @@ struct fc_exch_mgr_anchor {
|
||||
};
|
||||
|
||||
static void fc_exch_rrq(struct fc_exch *);
|
||||
static void fc_seq_ls_acc(struct fc_seq *);
|
||||
static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason,
|
||||
static void fc_seq_ls_acc(struct fc_frame *);
|
||||
static void fc_seq_ls_rjt(struct fc_frame *, enum fc_els_rjt_reason,
|
||||
enum fc_els_rjt_explan);
|
||||
static void fc_exch_els_rec(struct fc_seq *, struct fc_frame *);
|
||||
static void fc_exch_els_rrq(struct fc_seq *, struct fc_frame *);
|
||||
static void fc_exch_els_rec(struct fc_frame *);
|
||||
static void fc_exch_els_rrq(struct fc_frame *);
|
||||
|
||||
/*
|
||||
* Internal implementation notes.
|
||||
@@ -1003,28 +1003,30 @@ static void fc_exch_set_addr(struct fc_exch *ep,
|
||||
/**
|
||||
* fc_seq_els_rsp_send() - Send an ELS response using infomation from
|
||||
* the existing sequence/exchange.
|
||||
* @sp: The sequence/exchange to get information from
|
||||
* @fp: The received frame
|
||||
* @els_cmd: The ELS command to be sent
|
||||
* @els_data: The ELS data to be sent
|
||||
*
|
||||
* The received frame is not freed.
|
||||
*/
|
||||
static void fc_seq_els_rsp_send(struct fc_seq *sp, enum fc_els_cmd els_cmd,
|
||||
static void fc_seq_els_rsp_send(struct fc_frame *fp, enum fc_els_cmd els_cmd,
|
||||
struct fc_seq_els_data *els_data)
|
||||
{
|
||||
switch (els_cmd) {
|
||||
case ELS_LS_RJT:
|
||||
fc_seq_ls_rjt(sp, els_data->reason, els_data->explan);
|
||||
fc_seq_ls_rjt(fp, els_data->reason, els_data->explan);
|
||||
break;
|
||||
case ELS_LS_ACC:
|
||||
fc_seq_ls_acc(sp);
|
||||
fc_seq_ls_acc(fp);
|
||||
break;
|
||||
case ELS_RRQ:
|
||||
fc_exch_els_rrq(sp, els_data->fp);
|
||||
fc_exch_els_rrq(fp);
|
||||
break;
|
||||
case ELS_REC:
|
||||
fc_exch_els_rec(sp, els_data->fp);
|
||||
fc_exch_els_rec(fp);
|
||||
break;
|
||||
default:
|
||||
FC_EXCH_DBG(fc_seq_exch(sp), "Invalid ELS CMD:%x\n", els_cmd);
|
||||
FC_LPORT_DBG(fr_dev(fp), "Invalid ELS CMD:%x\n", els_cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1253,11 +1255,13 @@ static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp)
|
||||
}
|
||||
|
||||
/**
|
||||
* fc_exch_recv_req() - Handler for an incoming request where is other
|
||||
* end is originating the sequence
|
||||
* fc_exch_recv_req() - Handler for an incoming request
|
||||
* @lport: The local port that received the request
|
||||
* @mp: The EM that the exchange is on
|
||||
* @fp: The request frame
|
||||
*
|
||||
* This is used when the other end is originating the exchange
|
||||
* and the sequence.
|
||||
*/
|
||||
static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
|
||||
struct fc_frame *fp)
|
||||
@@ -1275,8 +1279,17 @@ static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp,
|
||||
fc_frame_free(fp);
|
||||
return;
|
||||
}
|
||||
fr_dev(fp) = lport;
|
||||
|
||||
BUG_ON(fr_seq(fp)); /* XXX remove later */
|
||||
|
||||
/*
|
||||
* If the RX_ID is 0xffff, don't allocate an exchange.
|
||||
* The upper-level protocol may request one later, if needed.
|
||||
*/
|
||||
if (fh->fh_rx_id == htons(FC_XID_UNKNOWN))
|
||||
return lport->tt.lport_recv(lport, fp);
|
||||
|
||||
fr_seq(fp) = NULL;
|
||||
reject = fc_seq_lookup_recip(lport, mp, fp);
|
||||
if (reject == FC_RJT_NONE) {
|
||||
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,
|
||||
if (ep->resp)
|
||||
ep->resp(sp, fp, ep->arg);
|
||||
else
|
||||
lport->tt.lport_recv(lport, sp, fp);
|
||||
lport->tt.lport_recv(lport, fp);
|
||||
fc_exch_release(ep); /* release from lookup */
|
||||
} else {
|
||||
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)
|
||||
|
||||
/**
|
||||
* fc_seq_ls_acc() - Accept sequence with LS_ACC
|
||||
* @req_sp: The request sequence
|
||||
* @rx_fp: The received frame, not freed here.
|
||||
*
|
||||
* If this fails due to allocation or transmit congestion, assume the
|
||||
* originator will repeat the sequence.
|
||||
*/
|
||||
static void fc_seq_ls_acc(struct fc_seq *req_sp)
|
||||
static void fc_seq_ls_acc(struct fc_frame *rx_fp)
|
||||
{
|
||||
struct fc_seq *sp;
|
||||
struct fc_lport *lport;
|
||||
struct fc_els_ls_acc *acc;
|
||||
struct fc_frame *fp;
|
||||
|
||||
sp = fc_seq_start_next(req_sp);
|
||||
fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc));
|
||||
if (fp) {
|
||||
acc = fc_frame_payload_get(fp, sizeof(*acc));
|
||||
memset(acc, 0, sizeof(*acc));
|
||||
acc->la_cmd = ELS_LS_ACC;
|
||||
fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
|
||||
}
|
||||
lport = fr_dev(rx_fp);
|
||||
fp = fc_frame_alloc(lport, sizeof(*acc));
|
||||
if (!fp)
|
||||
return;
|
||||
acc = fc_frame_payload_get(fp, sizeof(*acc));
|
||||
memset(acc, 0, sizeof(*acc));
|
||||
acc->la_cmd = ELS_LS_ACC;
|
||||
fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
|
||||
lport->tt.frame_send(lport, fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT
|
||||
* @req_sp: The request sequence
|
||||
* @rx_fp: The received frame, not freed here.
|
||||
* @reason: The reason the sequence is being rejected
|
||||
* @explan: The explaination for the rejection
|
||||
* @explan: The explanation for the rejection
|
||||
*
|
||||
* If this fails due to allocation or transmit congestion, assume the
|
||||
* originator will repeat the sequence.
|
||||
*/
|
||||
static void fc_seq_ls_rjt(struct fc_seq *req_sp, enum fc_els_rjt_reason reason,
|
||||
static void fc_seq_ls_rjt(struct fc_frame *rx_fp, enum fc_els_rjt_reason reason,
|
||||
enum fc_els_rjt_explan explan)
|
||||
{
|
||||
struct fc_seq *sp;
|
||||
struct fc_lport *lport;
|
||||
struct fc_els_ls_rjt *rjt;
|
||||
struct fc_frame *fp;
|
||||
|
||||
sp = fc_seq_start_next(req_sp);
|
||||
fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*rjt));
|
||||
if (fp) {
|
||||
rjt = fc_frame_payload_get(fp, sizeof(*rjt));
|
||||
memset(rjt, 0, sizeof(*rjt));
|
||||
rjt->er_cmd = ELS_LS_RJT;
|
||||
rjt->er_reason = reason;
|
||||
rjt->er_explan = explan;
|
||||
fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
|
||||
}
|
||||
lport = fr_dev(rx_fp);
|
||||
fp = fc_frame_alloc(lport, sizeof(*rjt));
|
||||
if (!fp)
|
||||
return;
|
||||
rjt = fc_frame_payload_get(fp, sizeof(*rjt));
|
||||
memset(rjt, 0, sizeof(*rjt));
|
||||
rjt->er_cmd = ELS_LS_RJT;
|
||||
rjt->er_reason = reason;
|
||||
rjt->er_explan = explan;
|
||||
fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0);
|
||||
lport->tt.frame_send(lport, fp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1714,18 +1729,34 @@ void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did)
|
||||
}
|
||||
EXPORT_SYMBOL(fc_exch_mgr_reset);
|
||||
|
||||
/**
|
||||
* fc_exch_lookup() - find an exchange
|
||||
* @lport: The local port
|
||||
* @xid: The exchange ID
|
||||
*
|
||||
* Returns exchange pointer with hold for caller, or NULL if not found.
|
||||
*/
|
||||
static struct fc_exch *fc_exch_lookup(struct fc_lport *lport, u32 xid)
|
||||
{
|
||||
struct fc_exch_mgr_anchor *ema;
|
||||
|
||||
list_for_each_entry(ema, &lport->ema_list, ema_list)
|
||||
if (ema->mp->min_xid <= xid && xid <= ema->mp->max_xid)
|
||||
return fc_exch_find(ema->mp, xid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests
|
||||
* @sp: The sequence the REC is on
|
||||
* @rfp: The REC frame
|
||||
* @rfp: The REC frame, not freed here.
|
||||
*
|
||||
* Note that the requesting port may be different than the S_ID in the request.
|
||||
*/
|
||||
static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
|
||||
static void fc_exch_els_rec(struct fc_frame *rfp)
|
||||
{
|
||||
struct fc_lport *lport;
|
||||
struct fc_frame *fp;
|
||||
struct fc_exch *ep;
|
||||
struct fc_exch_mgr *em;
|
||||
struct fc_els_rec *rp;
|
||||
struct fc_els_rec_acc *acc;
|
||||
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)
|
||||
u16 rxid;
|
||||
u16 oxid;
|
||||
|
||||
lport = fr_dev(rfp);
|
||||
rp = fc_frame_payload_get(rfp, sizeof(*rp));
|
||||
explan = ELS_EXPL_INV_LEN;
|
||||
if (!rp)
|
||||
@@ -1742,35 +1774,19 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
|
||||
rxid = ntohs(rp->rec_rx_id);
|
||||
oxid = ntohs(rp->rec_ox_id);
|
||||
|
||||
/*
|
||||
* Currently it's hard to find the local S_ID from the exchange
|
||||
* manager. This will eventually be fixed, but for now it's easier
|
||||
* to lookup the subject exchange twice, once as if we were
|
||||
* the initiator, and then again if we weren't.
|
||||
*/
|
||||
em = fc_seq_exch(sp)->em;
|
||||
ep = fc_exch_find(em, oxid);
|
||||
ep = fc_exch_lookup(lport,
|
||||
sid == fc_host_port_id(lport->host) ? oxid : rxid);
|
||||
explan = ELS_EXPL_OXID_RXID;
|
||||
if (ep && ep->oid == sid) {
|
||||
if (ep->rxid != FC_XID_UNKNOWN &&
|
||||
rxid != FC_XID_UNKNOWN &&
|
||||
ep->rxid != rxid)
|
||||
goto rel;
|
||||
} else {
|
||||
if (ep)
|
||||
fc_exch_release(ep);
|
||||
ep = NULL;
|
||||
if (rxid != FC_XID_UNKNOWN)
|
||||
ep = fc_exch_find(em, rxid);
|
||||
if (!ep)
|
||||
goto reject;
|
||||
}
|
||||
|
||||
fp = fc_frame_alloc(fc_seq_exch(sp)->lp, sizeof(*acc));
|
||||
if (!fp) {
|
||||
fc_exch_done(sp);
|
||||
if (!ep)
|
||||
goto reject;
|
||||
if (ep->oid != sid || oxid != ep->oxid)
|
||||
goto rel;
|
||||
if (rxid != FC_XID_UNKNOWN && rxid != ep->rxid)
|
||||
goto rel;
|
||||
fp = fc_frame_alloc(lport, sizeof(*acc));
|
||||
if (!fp)
|
||||
goto out;
|
||||
}
|
||||
|
||||
acc = fc_frame_payload_get(fp, sizeof(*acc));
|
||||
memset(acc, 0, sizeof(*acc));
|
||||
acc->reca_cmd = ELS_LS_ACC;
|
||||
@@ -1785,18 +1801,16 @@ static void fc_exch_els_rec(struct fc_seq *sp, struct fc_frame *rfp)
|
||||
acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP |
|
||||
ESB_ST_SEQ_INIT |
|
||||
ESB_ST_COMPLETE));
|
||||
sp = fc_seq_start_next(sp);
|
||||
fc_seq_send_last(sp, fp, FC_RCTL_ELS_REP, FC_TYPE_ELS);
|
||||
fc_fill_reply_hdr(fp, rfp, FC_RCTL_ELS_REP, 0);
|
||||
lport->tt.frame_send(lport, fp);
|
||||
out:
|
||||
fc_exch_release(ep);
|
||||
fc_frame_free(rfp);
|
||||
return;
|
||||
|
||||
rel:
|
||||
fc_exch_release(ep);
|
||||
reject:
|
||||
fc_seq_ls_rjt(sp, reason, explan);
|
||||
fc_frame_free(rfp);
|
||||
fc_seq_ls_rjt(rfp, reason, explan);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1971,20 +1985,20 @@ retry:
|
||||
spin_unlock_bh(&ep->ex_lock);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests
|
||||
* @sp: The sequence that the RRQ is on
|
||||
* @fp: The RRQ frame
|
||||
* @fp: The RRQ frame, not freed here.
|
||||
*/
|
||||
static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
|
||||
static void fc_exch_els_rrq(struct fc_frame *fp)
|
||||
{
|
||||
struct fc_lport *lport;
|
||||
struct fc_exch *ep = NULL; /* request or subject exchange */
|
||||
struct fc_els_rrq *rp;
|
||||
u32 sid;
|
||||
u16 xid;
|
||||
enum fc_els_rjt_explan explan;
|
||||
|
||||
lport = fr_dev(fp);
|
||||
rp = fc_frame_payload_get(fp, sizeof(*rp));
|
||||
explan = ELS_EXPL_INV_LEN;
|
||||
if (!rp)
|
||||
@@ -1993,11 +2007,10 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
|
||||
/*
|
||||
* lookup subject exchange.
|
||||
*/
|
||||
ep = fc_seq_exch(sp);
|
||||
sid = ntoh24(rp->rrq_s_id); /* subject source */
|
||||
xid = ep->did == sid ? ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id);
|
||||
ep = fc_exch_find(ep->em, xid);
|
||||
|
||||
xid = fc_host_port_id(lport->host) == sid ?
|
||||
ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id);
|
||||
ep = fc_exch_lookup(lport, xid);
|
||||
explan = ELS_EXPL_OXID_RXID;
|
||||
if (!ep)
|
||||
goto reject;
|
||||
@@ -2028,15 +2041,14 @@ static void fc_exch_els_rrq(struct fc_seq *sp, struct fc_frame *fp)
|
||||
/*
|
||||
* Send LS_ACC.
|
||||
*/
|
||||
fc_seq_ls_acc(sp);
|
||||
fc_seq_ls_acc(fp);
|
||||
goto out;
|
||||
|
||||
unlock_reject:
|
||||
spin_unlock_bh(&ep->ex_lock);
|
||||
reject:
|
||||
fc_seq_ls_rjt(sp, ELS_RJT_LOGIC, explan);
|
||||
fc_seq_ls_rjt(fp, ELS_RJT_LOGIC, explan);
|
||||
out:
|
||||
fc_frame_free(fp);
|
||||
if (ep)
|
||||
fc_exch_release(ep); /* drop hold from fc_exch_find */
|
||||
}
|
||||
@@ -2267,7 +2279,7 @@ void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp)
|
||||
fc_exch_recv_seq_resp(ema->mp, fp);
|
||||
else if (f_ctl & FC_FC_SEQ_CTX)
|
||||
fc_exch_recv_resp(ema->mp, fp);
|
||||
else
|
||||
else /* no EX_CTX and no SEQ_CTX */
|
||||
fc_exch_recv_req(lport, ema->mp, fp);
|
||||
break;
|
||||
default:
|
||||
|
Reference in New Issue
Block a user