|
@@ -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);
|
|
@@ -514,6 +520,9 @@ out:
|
|
|
* @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)
|
|
@@ -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;
|
|
|
}
|
|
|
|
|
@@ -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));
|
|
@@ -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;
|