|
@@ -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 &&
|