diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_bsg.c | 127 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 16 |
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: done: return rval; } + +/* Disable loopback mode */ +static inline int +qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config, + int wait) +{ + int ret = 0; + int rval = 0; + uint16_t new_config[4]; + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) + goto done_reset_internal; + + memset(new_config, 0 , sizeof(new_config)); + if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == + ENABLE_INTERNAL_LOOPBACK || + (config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == + ENABLE_EXTERNAL_LOOPBACK) { + new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK; + ql_dbg(ql_dbg_user, vha, 0x70bf, "new_config[0]=%02x\n", + (new_config[0] & INTERNAL_LOOPBACK_MASK)); + memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; + + ha->notify_dcbx_comp = wait; + ret = qla81xx_set_port_config(vha, new_config); + if (ret != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x7025, + "Set port config failed.\n"); + ha->notify_dcbx_comp = 0; + rval = -EINVAL; + goto done_reset_internal; + } + + /* Wait for DCBX complete event */ + if (wait && !wait_for_completion_timeout(&ha->dcbx_comp, + (20 * HZ))) { + ql_dbg(ql_dbg_user, vha, 0x7026, + "State change notification not received.\n"); + ha->notify_dcbx_comp = 0; + rval = -EINVAL; + goto done_reset_internal; + } else + ql_dbg(ql_dbg_user, vha, 0x7027, + "State change received.\n"); + + ha->notify_dcbx_comp = 0; + } +done_reset_internal: + return rval; +} + /* * Set the port configuration to enable the internal or external loopback * depending on the loopback mode. @@ -569,6 +621,15 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config, if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) { ql_dbg(ql_dbg_user, vha, 0x7022, "State change notification not received.\n"); + ret = qla81xx_reset_loopback_mode(vha, new_config, 0); + /* + * If the reset of the loopback mode doesn't work take a FCoE + * dump and reset the chip. + */ + if (ret) { + ha->isp_ops->fw_dump(vha, 0); + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + } rval = -EINVAL; } else { if (ha->flags.idc_compl_status) { @@ -587,57 +648,6 @@ done_set_internal: return rval; } -/* Disable loopback mode */ -static inline int -qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config, - int wait) -{ - int ret = 0; - int rval = 0; - uint16_t new_config[4]; - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) - goto done_reset_internal; - - memset(new_config, 0 , sizeof(new_config)); - if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == - ENABLE_INTERNAL_LOOPBACK || - (config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == - ENABLE_EXTERNAL_LOOPBACK) { - new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK; - ql_dbg(ql_dbg_user, vha, 0x70bf, "new_config[0]=%02x\n", - (new_config[0] & INTERNAL_LOOPBACK_MASK)); - memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; - - ha->notify_dcbx_comp = wait; - ret = qla81xx_set_port_config(vha, new_config); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7025, - "Set port config failed.\n"); - ha->notify_dcbx_comp = 0; - rval = -EINVAL; - goto done_reset_internal; - } - - /* Wait for DCBX complete event */ - if (wait && !wait_for_completion_timeout(&ha->dcbx_comp, - (20 * HZ))) { - ql_dbg(ql_dbg_user, vha, 0x7026, - "State change notification not received.\n"); - ha->notify_dcbx_comp = 0; - rval = -EINVAL; - goto done_reset_internal; - } else - ql_dbg(ql_dbg_user, vha, 0x7027, - "State change received.\n"); - - ha->notify_dcbx_comp = 0; - } -done_reset_internal: - return rval; -} - static int qla2x00_process_loopback(struct fc_bsg_job *bsg_job) { @@ -781,11 +791,24 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job) rval = qla2x00_loopback_test(vha, &elreq, response); if (new_config[0]) { + int ret; + /* Revert back to original port config * Also clear internal loopback */ - qla81xx_reset_loopback_mode(vha, + ret = qla81xx_reset_loopback_mode(vha, new_config, 0); + if (ret) { + /* + * If the reset of the loopback mode + * doesn't work take FCoE dump and then + * reset the chip. + */ + ha->isp_ops->fw_dump(vha, 0); + set_bit(ISP_ABORT_NEEDED, + &vha->dpc_flags); + } + } 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: mb[1], mb[2], mb[3]); break; case MBA_IDC_NOTIFY: - /* See if we need to quiesce any I/O */ - if (IS_QLA8031(vha->hw)) - if ((mb[2] & 0x7fff) == MBC_PORT_RESET || - (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) { + if (IS_QLA8031(vha->hw)) { + mb[4] = RD_REG_WORD(®24->mailbox4); + if (((mb[2] & 0x7fff) == MBC_PORT_RESET || + (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) && + (mb[4] & INTERNAL_LOOPBACK_MASK) != 0) { set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags); + /* + * Extend loop down timer since port is active. + */ + if (atomic_read(&vha->loop_state) == LOOP_DOWN) + atomic_set(&vha->loop_down_timer, + LOOP_DOWN_TIME); qla2xxx_wake_dpc(vha); } + } case MBA_IDC_COMPLETE: case MBA_IDC_TIME_EXT: if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw)) |