Skip to content

Commit

Permalink
libfc: Avoid that sending after an abort triggers a kernel warning
Browse files Browse the repository at this point in the history
Calling fc_seq_send() after an ABTS message has been received triggers
a kernel warning (WARN_ON(!(ep->esb_stat & ESB_ST_SEQ_INIT))). Avoid
this by returning -ENXIO to the caller if fc_seq_send() is invoked after
an ABTS message has been received.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Cc: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
  • Loading branch information
Bart Van Assche authored and Robert Love committed Sep 4, 2013
1 parent 5d73bea commit cae7b6d
Showing 1 changed file with 37 additions and 22 deletions.
59 changes: 37 additions & 22 deletions drivers/scsi/libfc/fc_exch.c
Original file line number Diff line number Diff line change
Expand Up @@ -463,15 +463,21 @@ static void fc_exch_delete(struct fc_exch *ep)
}

static int fc_seq_send_locked(struct fc_lport *lport, struct fc_seq *sp,
struct fc_frame *fp)
struct fc_frame *fp)
{
struct fc_exch *ep;
struct fc_frame_header *fh = fc_frame_header_get(fp);
int error;
int error = -ENXIO;
u32 f_ctl;
u8 fh_type = fh->fh_type;

ep = fc_seq_exch(sp);

if (ep->esb_stat & (ESB_ST_COMPLETE | ESB_ST_ABNORMAL)) {
fc_frame_free(fp);
goto out;
}

WARN_ON(!(ep->esb_stat & ESB_ST_SEQ_INIT));

f_ctl = ntoh24(fh->fh_f_ctl);
Expand Down Expand Up @@ -514,6 +520,9 @@ static int fc_seq_send_locked(struct fc_lport *lport, struct fc_seq *sp,
* @lport: The local port that the exchange will be sent on
* @sp: The sequence to be sent
* @fp: The frame to be sent on the exchange
*
* Note: The frame will be freed either by a direct call to fc_frame_free(fp)
* or indirectly by calling libfc_function_template.frame_send().
*/
static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
struct fc_frame *fp)
Expand Down Expand Up @@ -621,27 +630,31 @@ static int fc_exch_abort_locked(struct fc_exch *ep,
if (!sp)
return -ENOMEM;

ep->esb_stat |= ESB_ST_SEQ_INIT | ESB_ST_ABNORMAL;
if (timer_msec)
fc_exch_timer_set_locked(ep, timer_msec);

/*
* If not logged into the fabric, don't send ABTS but leave
* sequence active until next timeout.
*/
if (!ep->sid)
return 0;

/*
* Send an abort for the sequence that timed out.
*/
fp = fc_frame_alloc(ep->lp, 0);
if (fp) {
fc_fill_fc_hdr(fp, FC_RCTL_BA_ABTS, ep->did, ep->sid,
FC_TYPE_BLS, FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0);
error = fc_seq_send_locked(ep->lp, sp, fp);
} else
error = -ENOBUFS;
if (ep->sid) {
/*
* Send an abort for the sequence that timed out.
*/
fp = fc_frame_alloc(ep->lp, 0);
if (fp) {
ep->esb_stat |= ESB_ST_SEQ_INIT;
fc_fill_fc_hdr(fp, FC_RCTL_BA_ABTS, ep->did, ep->sid,
FC_TYPE_BLS, FC_FC_END_SEQ |
FC_FC_SEQ_INIT, 0);
error = fc_seq_send_locked(ep->lp, sp, fp);
} else {
error = -ENOBUFS;
}
} else {
/*
* If not logged into the fabric, don't send ABTS but leave
* sequence active until next timeout.
*/
error = 0;
}
ep->esb_stat |= ESB_ST_ABNORMAL;
return error;
}

Expand Down Expand Up @@ -1299,9 +1312,10 @@ static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp)
spin_unlock_bh(&ep->ex_lock);
goto reject;
}
if (!(ep->esb_stat & ESB_ST_REC_QUAL))
if (!(ep->esb_stat & ESB_ST_REC_QUAL)) {
ep->esb_stat |= ESB_ST_REC_QUAL;
fc_exch_hold(ep); /* hold for REC_QUAL */
ep->esb_stat |= ESB_ST_ABNORMAL | ESB_ST_REC_QUAL;
}
fc_exch_timer_set_locked(ep, ep->r_a_tov);

fp = fc_frame_alloc(ep->lp, sizeof(*ap));
Expand All @@ -1322,6 +1336,7 @@ static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp)
}
sp = fc_seq_start_next_locked(sp);
fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS);
ep->esb_stat |= ESB_ST_ABNORMAL;
spin_unlock_bh(&ep->ex_lock);
fc_frame_free(rx_fp);
return;
Expand Down

0 comments on commit cae7b6d

Please sign in to comment.