diff options
author | Bart Van Assche <bvanassche@acm.org> | 2013-08-14 11:37:52 -0400 |
---|---|---|
committer | Robert Love <robert.w.love@intel.com> | 2013-09-04 16:30:43 -0400 |
commit | cae7b6dd6c569f18f5c8e3f33cac60fbaeb58140 (patch) | |
tree | 257c25995a259307113f337cc8f569f2604b9363 /drivers/scsi | |
parent | 5d73bea2d3a004698d16ba5face89f0bef383e76 (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.c | 59 |
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 | ||
465 | static int fc_seq_send_locked(struct fc_lport *lport, struct fc_seq *sp, | 465 | static 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 | */ |
518 | static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, | 527 | static 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; |