aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorBart Van Assche <bvanassche@acm.org>2013-08-14 11:37:52 -0400
committerRobert Love <robert.w.love@intel.com>2013-09-04 16:30:43 -0400
commitcae7b6dd6c569f18f5c8e3f33cac60fbaeb58140 (patch)
tree257c25995a259307113f337cc8f569f2604b9363 /drivers/scsi
parent5d73bea2d3a004698d16ba5face89f0bef383e76 (diff)
libfc: Avoid that sending after an abort triggers a kernel warning
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>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/libfc/fc_exch.c59
1 files changed, 37 insertions, 22 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index bc0aba4fabb4..2a7fd5afecca 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -463,15 +463,21 @@ static void fc_exch_delete(struct fc_exch *ep)
463} 463}
464 464
465static int fc_seq_send_locked(struct fc_lport *lport, struct fc_seq *sp, 465static int fc_seq_send_locked(struct fc_lport *lport, struct fc_seq *sp,
466 struct fc_frame *fp) 466 struct fc_frame *fp)
467{ 467{
468 struct fc_exch *ep; 468 struct fc_exch *ep;
469 struct fc_frame_header *fh = fc_frame_header_get(fp); 469 struct fc_frame_header *fh = fc_frame_header_get(fp);
470 int error; 470 int error = -ENXIO;
471 u32 f_ctl; 471 u32 f_ctl;
472 u8 fh_type = fh->fh_type; 472 u8 fh_type = fh->fh_type;
473 473
474 ep = fc_seq_exch(sp); 474 ep = fc_seq_exch(sp);
475
476 if (ep->esb_stat & (ESB_ST_COMPLETE | ESB_ST_ABNORMAL)) {
477 fc_frame_free(fp);
478 goto out;
479 }
480
475 WARN_ON(!(ep->esb_stat & ESB_ST_SEQ_INIT)); 481 WARN_ON(!(ep->esb_stat & ESB_ST_SEQ_INIT));
476 482
477 f_ctl = ntoh24(fh->fh_f_ctl); 483 f_ctl = ntoh24(fh->fh_f_ctl);
@@ -514,6 +520,9 @@ out:
514 * @lport: The local port that the exchange will be sent on 520 * @lport: The local port that the exchange will be sent on
515 * @sp: The sequence to be sent 521 * @sp: The sequence to be sent
516 * @fp: The frame to be sent on the exchange 522 * @fp: The frame to be sent on the exchange
523 *
524 * Note: The frame will be freed either by a direct call to fc_frame_free(fp)
525 * or indirectly by calling libfc_function_template.frame_send().
517 */ 526 */
518static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, 527static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp,
519 struct fc_frame *fp) 528 struct fc_frame *fp)
@@ -621,27 +630,31 @@ static int fc_exch_abort_locked(struct fc_exch *ep,
621 if (!sp) 630 if (!sp)
622 return -ENOMEM; 631 return -ENOMEM;
623 632
624 ep->esb_stat |= ESB_ST_SEQ_INIT | ESB_ST_ABNORMAL;
625 if (timer_msec) 633 if (timer_msec)
626 fc_exch_timer_set_locked(ep, timer_msec); 634 fc_exch_timer_set_locked(ep, timer_msec);
627 635
628 /* 636 if (ep->sid) {
629 * If not logged into the fabric, don't send ABTS but leave 637 /*
630 * sequence active until next timeout. 638 * Send an abort for the sequence that timed out.
631 */ 639 */
632 if (!ep->sid) 640 fp = fc_frame_alloc(ep->lp, 0);
633 return 0; 641 if (fp) {
634 642 ep->esb_stat |= ESB_ST_SEQ_INIT;
635 /* 643 fc_fill_fc_hdr(fp, FC_RCTL_BA_ABTS, ep->did, ep->sid,
636 * Send an abort for the sequence that timed out. 644 FC_TYPE_BLS, FC_FC_END_SEQ |
637 */ 645 FC_FC_SEQ_INIT, 0);
638 fp = fc_frame_alloc(ep->lp, 0); 646 error = fc_seq_send_locked(ep->lp, sp, fp);
639 if (fp) { 647 } else {
640 fc_fill_fc_hdr(fp, FC_RCTL_BA_ABTS, ep->did, ep->sid, 648 error = -ENOBUFS;
641 FC_TYPE_BLS, FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); 649 }
642 error = fc_seq_send_locked(ep->lp, sp, fp); 650 } else {
643 } else 651 /*
644 error = -ENOBUFS; 652 * If not logged into the fabric, don't send ABTS but leave
653 * sequence active until next timeout.
654 */
655 error = 0;
656 }
657 ep->esb_stat |= ESB_ST_ABNORMAL;
645 return error; 658 return error;
646} 659}
647 660
@@ -1299,9 +1312,10 @@ static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp)
1299 spin_unlock_bh(&ep->ex_lock); 1312 spin_unlock_bh(&ep->ex_lock);
1300 goto reject; 1313 goto reject;
1301 } 1314 }
1302 if (!(ep->esb_stat & ESB_ST_REC_QUAL)) 1315 if (!(ep->esb_stat & ESB_ST_REC_QUAL)) {
1316 ep->esb_stat |= ESB_ST_REC_QUAL;
1303 fc_exch_hold(ep); /* hold for REC_QUAL */ 1317 fc_exch_hold(ep); /* hold for REC_QUAL */
1304 ep->esb_stat |= ESB_ST_ABNORMAL | ESB_ST_REC_QUAL; 1318 }
1305 fc_exch_timer_set_locked(ep, ep->r_a_tov); 1319 fc_exch_timer_set_locked(ep, ep->r_a_tov);
1306 1320
1307 fp = fc_frame_alloc(ep->lp, sizeof(*ap)); 1321 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)
1322 } 1336 }
1323 sp = fc_seq_start_next_locked(sp); 1337 sp = fc_seq_start_next_locked(sp);
1324 fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS); 1338 fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS);
1339 ep->esb_stat |= ESB_ST_ABNORMAL;
1325 spin_unlock_bh(&ep->ex_lock); 1340 spin_unlock_bh(&ep->ex_lock);
1326 fc_frame_free(rx_fp); 1341 fc_frame_free(rx_fp);
1327 return; 1342 return;