aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorBhanu Prakash Gollapudi <bprakash@broadcom.com>2011-07-27 14:32:07 -0400
committerJames Bottomley <JBottomley@Parallels.com>2011-07-28 03:47:12 -0400
commit7b594769120b43b8da1ff8f7b4c31a47fabd6ac0 (patch)
tree792d229f0e4a029cdba8c0eeddb2997ead7e9d45 /drivers/scsi
parent744469542951d32979a8dcb1dbed560bfed1745e (diff)
[SCSI] bnx2fc: Handle REC_TOV error code from firmware
Driver decides to initiate REC on REC_TOV timer pop. The firmware maintains the REC timer and informs the driver as a firmware error message, which is an unsolicited event to the driver. Driver also issues REC on other unsolicited events from firmware that indicate data loss. Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h1
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c140
2 files changed, 112 insertions, 29 deletions
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index cd506c0ee2f6..b1b0b3e89a84 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -143,6 +143,7 @@
143 143
144#define SRR_RETRY_COUNT 5 144#define SRR_RETRY_COUNT 5
145#define REC_RETRY_COUNT 1 145#define REC_RETRY_COUNT 1
146#define BNX2FC_NUM_ERR_BITS 63
146 147
147/* bnx2fc driver uses only one instance of fcoe_percpu_s */ 148/* bnx2fc driver uses only one instance of fcoe_percpu_s */
148extern struct fcoe_percpu_s bnx2fc_global; 149extern struct fcoe_percpu_s bnx2fc_global;
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index 03ae003d3b85..764c45254dc6 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -629,6 +629,8 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
629 struct bnx2fc_hba *hba = interface->hba; 629 struct bnx2fc_hba *hba = interface->hba;
630 int task_idx, index; 630 int task_idx, index;
631 int rc = 0; 631 int rc = 0;
632 u64 err_warn_bit_map;
633 u8 err_warn = 0xff;
632 634
633 635
634 BNX2FC_TGT_DBG(tgt, "Entered UNSOL COMPLETION wqe = 0x%x\n", wqe); 636 BNX2FC_TGT_DBG(tgt, "Entered UNSOL COMPLETION wqe = 0x%x\n", wqe);
@@ -691,13 +693,11 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
691 BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n", 693 BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n",
692 err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); 694 err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
693 695
694 bnx2fc_return_rqe(tgt, 1);
695 696
696 if (xid > BNX2FC_MAX_XID) { 697 if (xid > BNX2FC_MAX_XID) {
697 BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", 698 BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n",
698 xid); 699 xid);
699 spin_unlock_bh(&tgt->tgt_lock); 700 goto ret_err_rqe;
700 break;
701 } 701 }
702 702
703 task_idx = xid / BNX2FC_TASKS_PER_PAGE; 703 task_idx = xid / BNX2FC_TASKS_PER_PAGE;
@@ -707,23 +707,29 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
707 task = &(task_page[index]); 707 task = &(task_page[index]);
708 708
709 io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; 709 io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
710 if (!io_req) { 710 if (!io_req)
711 spin_unlock_bh(&tgt->tgt_lock); 711 goto ret_err_rqe;
712 break;
713 }
714 712
715 if (io_req->cmd_type != BNX2FC_SCSI_CMD) { 713 if (io_req->cmd_type != BNX2FC_SCSI_CMD) {
716 printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n"); 714 printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n");
717 spin_unlock_bh(&tgt->tgt_lock); 715 goto ret_err_rqe;
718 break;
719 } 716 }
720 717
721 if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP, 718 if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP,
722 &io_req->req_flags)) { 719 &io_req->req_flags)) {
723 BNX2FC_IO_DBG(io_req, "unsol_err: cleanup in " 720 BNX2FC_IO_DBG(io_req, "unsol_err: cleanup in "
724 "progress.. ignore unsol err\n"); 721 "progress.. ignore unsol err\n");
725 spin_unlock_bh(&tgt->tgt_lock); 722 goto ret_err_rqe;
726 break; 723 }
724
725 err_warn_bit_map = (u64)
726 ((u64)err_entry->data.err_warn_bitmap_hi << 32) |
727 (u64)err_entry->data.err_warn_bitmap_lo;
728 for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) {
729 if (err_warn_bit_map & (u64)((u64)1 << i)) {
730 err_warn = i;
731 break;
732 }
727 } 733 }
728 734
729 /* 735 /*
@@ -733,26 +739,61 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
733 * logging out the target, when the ABTS eventually 739 * logging out the target, when the ABTS eventually
734 * times out. 740 * times out.
735 */ 741 */
736 if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, 742 if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) {
737 &io_req->req_flags)) {
738 /*
739 * Cancel the timeout_work, as we received IO
740 * completion with FW error.
741 */
742 if (cancel_delayed_work(&io_req->timeout_work))
743 kref_put(&io_req->refcount,
744 bnx2fc_cmd_release); /* timer hold */
745
746 rc = bnx2fc_initiate_abts(io_req);
747 if (rc != SUCCESS) {
748 BNX2FC_IO_DBG(io_req, "err_warn: initiate_abts "
749 "failed. issue cleanup\n");
750 rc = bnx2fc_initiate_cleanup(io_req);
751 BUG_ON(rc);
752 }
753 } else
754 printk(KERN_ERR PFX "err_warn: io_req (0x%x) already " 743 printk(KERN_ERR PFX "err_warn: io_req (0x%x) already "
755 "in ABTS processing\n", xid); 744 "in ABTS processing\n", xid);
745 goto ret_err_rqe;
746 }
747 BNX2FC_TGT_DBG(tgt, "err = 0x%x\n", err_warn);
748 if (tgt->dev_type != TYPE_TAPE)
749 goto skip_rec;
750 switch (err_warn) {
751 case FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION:
752 case FCOE_ERROR_CODE_DATA_OOO_RO:
753 case FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT:
754 case FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET:
755 case FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ:
756 case FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET:
757 BNX2FC_TGT_DBG(tgt, "REC TOV popped for xid - 0x%x\n",
758 xid);
759 memset(&io_req->err_entry, 0,
760 sizeof(struct fcoe_err_report_entry));
761 memcpy(&io_req->err_entry, err_entry,
762 sizeof(struct fcoe_err_report_entry));
763 if (!test_bit(BNX2FC_FLAG_SRR_SENT,
764 &io_req->req_flags)) {
765 spin_unlock_bh(&tgt->tgt_lock);
766 rc = bnx2fc_send_rec(io_req);
767 spin_lock_bh(&tgt->tgt_lock);
768
769 if (rc)
770 goto skip_rec;
771 } else
772 printk(KERN_ERR PFX "SRR in progress\n");
773 goto ret_err_rqe;
774 break;
775 default:
776 break;
777 }
778
779skip_rec:
780 set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags);
781 /*
782 * Cancel the timeout_work, as we received IO
783 * completion with FW error.
784 */
785 if (cancel_delayed_work(&io_req->timeout_work))
786 kref_put(&io_req->refcount, bnx2fc_cmd_release);
787
788 rc = bnx2fc_initiate_abts(io_req);
789 if (rc != SUCCESS) {
790 printk(KERN_ERR PFX "err_warn: initiate_abts "
791 "failed xid = 0x%x. issue cleanup\n",
792 io_req->xid);
793 bnx2fc_initiate_cleanup(io_req);
794 }
795ret_err_rqe:
796 bnx2fc_return_rqe(tgt, 1);
756 spin_unlock_bh(&tgt->tgt_lock); 797 spin_unlock_bh(&tgt->tgt_lock);
757 break; 798 break;
758 799
@@ -773,6 +814,47 @@ static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe)
773 BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x", 814 BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x",
774 err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); 815 err_entry->data.tx_buf_off, err_entry->data.rx_buf_off);
775 816
817 if (xid > BNX2FC_MAX_XID) {
818 BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid);
819 goto ret_warn_rqe;
820 }
821
822 err_warn_bit_map = (u64)
823 ((u64)err_entry->data.err_warn_bitmap_hi << 32) |
824 (u64)err_entry->data.err_warn_bitmap_lo;
825 for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) {
826 if (err_warn_bit_map & (u64) (1 << i)) {
827 err_warn = i;
828 break;
829 }
830 }
831 BNX2FC_TGT_DBG(tgt, "warn = 0x%x\n", err_warn);
832
833 task_idx = xid / BNX2FC_TASKS_PER_PAGE;
834 index = xid % BNX2FC_TASKS_PER_PAGE;
835 task_page = (struct fcoe_task_ctx_entry *)
836 interface->hba->task_ctx[task_idx];
837 task = &(task_page[index]);
838 io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid];
839 if (!io_req)
840 goto ret_warn_rqe;
841
842 if (io_req->cmd_type != BNX2FC_SCSI_CMD) {
843 printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n");
844 goto ret_warn_rqe;
845 }
846
847 memset(&io_req->err_entry, 0,
848 sizeof(struct fcoe_err_report_entry));
849 memcpy(&io_req->err_entry, err_entry,
850 sizeof(struct fcoe_err_report_entry));
851
852 if (err_warn == FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION)
853 /* REC_TOV is not a warning code */
854 BUG_ON(1);
855 else
856 BNX2FC_TGT_DBG(tgt, "Unsolicited warning\n");
857ret_warn_rqe:
776 bnx2fc_return_rqe(tgt, 1); 858 bnx2fc_return_rqe(tgt, 1);
777 spin_unlock_bh(&tgt->tgt_lock); 859 spin_unlock_bh(&tgt->tgt_lock);
778 break; 860 break;