aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChad Dupuis <chad.dupuis@qlogic.com>2013-02-08 01:57:51 -0500
committerJames Bottomley <JBottomley@Parallels.com>2013-02-22 07:39:56 -0500
commit67b2a31f517a43631af218d146e39f4e502b3e83 (patch)
tree03f9e03ce629a9eb896b285260d7baaa447e383b
parentb00ee7d770abbe1e63df74eada0376c75ceb2daf (diff)
[SCSI] qla2xxx: Extra loopback error handling for ISP83xx.
Add the following error handling for loopback diagnostic mode with ISP83xx: 1. If we do not receive an MBA_DCBX_COMPLETE after our initial set port configuration command, try to reset the port back into normal operation. If that fails, take a FCoE dump and then reset the chip. 2. After completing the loopback diagnostic operation, if the reset of the port back into normal operation fails then reset the port so we take a FCoE dump and then reset the chip. 3. When we receive an IDC notification and the requested operation is loopback extend the loop down timer so the link does not appear to down for an extended period of time. [jejb: fix checkpatch issue] Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r--drivers/scsi/qla2xxx/qla_bsg.c127
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c16
2 files changed, 87 insertions, 56 deletions
diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c
index 79babab8353f..be299c83e07e 100644
--- a/drivers/scsi/qla2xxx/qla_bsg.c
+++ b/drivers/scsi/qla2xxx/qla_bsg.c
@@ -531,6 +531,58 @@ done_unmap_sg:
531done: 531done:
532 return rval; 532 return rval;
533} 533}
534
535/* Disable loopback mode */
536static inline int
537qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
538 int wait)
539{
540 int ret = 0;
541 int rval = 0;
542 uint16_t new_config[4];
543 struct qla_hw_data *ha = vha->hw;
544
545 if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
546 goto done_reset_internal;
547
548 memset(new_config, 0 , sizeof(new_config));
549 if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
550 ENABLE_INTERNAL_LOOPBACK ||
551 (config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
552 ENABLE_EXTERNAL_LOOPBACK) {
553 new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK;
554 ql_dbg(ql_dbg_user, vha, 0x70bf, "new_config[0]=%02x\n",
555 (new_config[0] & INTERNAL_LOOPBACK_MASK));
556 memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
557
558 ha->notify_dcbx_comp = wait;
559 ret = qla81xx_set_port_config(vha, new_config);
560 if (ret != QLA_SUCCESS) {
561 ql_log(ql_log_warn, vha, 0x7025,
562 "Set port config failed.\n");
563 ha->notify_dcbx_comp = 0;
564 rval = -EINVAL;
565 goto done_reset_internal;
566 }
567
568 /* Wait for DCBX complete event */
569 if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
570 (20 * HZ))) {
571 ql_dbg(ql_dbg_user, vha, 0x7026,
572 "State change notification not received.\n");
573 ha->notify_dcbx_comp = 0;
574 rval = -EINVAL;
575 goto done_reset_internal;
576 } else
577 ql_dbg(ql_dbg_user, vha, 0x7027,
578 "State change received.\n");
579
580 ha->notify_dcbx_comp = 0;
581 }
582done_reset_internal:
583 return rval;
584}
585
534/* 586/*
535 * Set the port configuration to enable the internal or external loopback 587 * Set the port configuration to enable the internal or external loopback
536 * depending on the loopback mode. 588 * depending on the loopback mode.
@@ -569,6 +621,15 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
569 if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) { 621 if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) {
570 ql_dbg(ql_dbg_user, vha, 0x7022, 622 ql_dbg(ql_dbg_user, vha, 0x7022,
571 "State change notification not received.\n"); 623 "State change notification not received.\n");
624 ret = qla81xx_reset_loopback_mode(vha, new_config, 0);
625 /*
626 * If the reset of the loopback mode doesn't work take a FCoE
627 * dump and reset the chip.
628 */
629 if (ret) {
630 ha->isp_ops->fw_dump(vha, 0);
631 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
632 }
572 rval = -EINVAL; 633 rval = -EINVAL;
573 } else { 634 } else {
574 if (ha->flags.idc_compl_status) { 635 if (ha->flags.idc_compl_status) {
@@ -587,57 +648,6 @@ done_set_internal:
587 return rval; 648 return rval;
588} 649}
589 650
590/* Disable loopback mode */
591static inline int
592qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
593 int wait)
594{
595 int ret = 0;
596 int rval = 0;
597 uint16_t new_config[4];
598 struct qla_hw_data *ha = vha->hw;
599
600 if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
601 goto done_reset_internal;
602
603 memset(new_config, 0 , sizeof(new_config));
604 if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
605 ENABLE_INTERNAL_LOOPBACK ||
606 (config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
607 ENABLE_EXTERNAL_LOOPBACK) {
608 new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK;
609 ql_dbg(ql_dbg_user, vha, 0x70bf, "new_config[0]=%02x\n",
610 (new_config[0] & INTERNAL_LOOPBACK_MASK));
611 memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
612
613 ha->notify_dcbx_comp = wait;
614 ret = qla81xx_set_port_config(vha, new_config);
615 if (ret != QLA_SUCCESS) {
616 ql_log(ql_log_warn, vha, 0x7025,
617 "Set port config failed.\n");
618 ha->notify_dcbx_comp = 0;
619 rval = -EINVAL;
620 goto done_reset_internal;
621 }
622
623 /* Wait for DCBX complete event */
624 if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
625 (20 * HZ))) {
626 ql_dbg(ql_dbg_user, vha, 0x7026,
627 "State change notification not received.\n");
628 ha->notify_dcbx_comp = 0;
629 rval = -EINVAL;
630 goto done_reset_internal;
631 } else
632 ql_dbg(ql_dbg_user, vha, 0x7027,
633 "State change received.\n");
634
635 ha->notify_dcbx_comp = 0;
636 }
637done_reset_internal:
638 return rval;
639}
640
641static int 651static int
642qla2x00_process_loopback(struct fc_bsg_job *bsg_job) 652qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
643{ 653{
@@ -781,11 +791,24 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
781 rval = qla2x00_loopback_test(vha, &elreq, response); 791 rval = qla2x00_loopback_test(vha, &elreq, response);
782 792
783 if (new_config[0]) { 793 if (new_config[0]) {
794 int ret;
795
784 /* Revert back to original port config 796 /* Revert back to original port config
785 * Also clear internal loopback 797 * Also clear internal loopback
786 */ 798 */
787 qla81xx_reset_loopback_mode(vha, 799 ret = qla81xx_reset_loopback_mode(vha,
788 new_config, 0); 800 new_config, 0);
801 if (ret) {
802 /*
803 * If the reset of the loopback mode
804 * doesn't work take FCoE dump and then
805 * reset the chip.
806 */
807 ha->isp_ops->fw_dump(vha, 0);
808 set_bit(ISP_ABORT_NEEDED,
809 &vha->dpc_flags);
810 }
811
789 } 812 }
790 813
791 if (response[0] == MBS_COMMAND_ERROR && 814 if (response[0] == MBS_COMMAND_ERROR &&
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index 26a3086a7e3a..9380d961616c 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -985,13 +985,21 @@ skip_rio:
985 mb[1], mb[2], mb[3]); 985 mb[1], mb[2], mb[3]);
986 break; 986 break;
987 case MBA_IDC_NOTIFY: 987 case MBA_IDC_NOTIFY:
988 /* See if we need to quiesce any I/O */ 988 if (IS_QLA8031(vha->hw)) {
989 if (IS_QLA8031(vha->hw)) 989 mb[4] = RD_REG_WORD(&reg24->mailbox4);
990 if ((mb[2] & 0x7fff) == MBC_PORT_RESET || 990 if (((mb[2] & 0x7fff) == MBC_PORT_RESET ||
991 (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) { 991 (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) &&
992 (mb[4] & INTERNAL_LOOPBACK_MASK) != 0) {
992 set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags); 993 set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
994 /*
995 * Extend loop down timer since port is active.
996 */
997 if (atomic_read(&vha->loop_state) == LOOP_DOWN)
998 atomic_set(&vha->loop_down_timer,
999 LOOP_DOWN_TIME);
993 qla2xxx_wake_dpc(vha); 1000 qla2xxx_wake_dpc(vha);
994 } 1001 }
1002 }
995 case MBA_IDC_COMPLETE: 1003 case MBA_IDC_COMPLETE:
996 case MBA_IDC_TIME_EXT: 1004 case MBA_IDC_TIME_EXT:
997 if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw)) 1005 if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw))