[SCSI] qla2xxx: Wait for IDC complete event to finish loopback operation.

Wait for the IDC complete AEN before returning the loopback operation back to
the application to make sure the port is put back into normal operations.

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>
This commit is contained in:
Chad Dupuis 2013-02-08 01:58:04 -05:00 committed by James Bottomley
parent fe52f6e121
commit f356bef134
4 changed files with 39 additions and 10 deletions

View file

@ -535,7 +535,7 @@ done:
/* Disable loopback mode */ /* Disable loopback mode */
static inline int static inline int
qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config, qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
int wait) int wait, int wait2)
{ {
int ret = 0; int ret = 0;
int rval = 0; int rval = 0;
@ -556,28 +556,45 @@ qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
ha->notify_dcbx_comp = wait; ha->notify_dcbx_comp = wait;
ha->notify_lb_portup_comp = wait2;
ret = qla81xx_set_port_config(vha, new_config); ret = qla81xx_set_port_config(vha, new_config);
if (ret != QLA_SUCCESS) { if (ret != QLA_SUCCESS) {
ql_log(ql_log_warn, vha, 0x7025, ql_log(ql_log_warn, vha, 0x7025,
"Set port config failed.\n"); "Set port config failed.\n");
ha->notify_dcbx_comp = 0; ha->notify_dcbx_comp = 0;
ha->notify_lb_portup_comp = 0;
rval = -EINVAL; rval = -EINVAL;
goto done_reset_internal; goto done_reset_internal;
} }
/* Wait for DCBX complete event */ /* Wait for DCBX complete event */
if (wait && !wait_for_completion_timeout(&ha->dcbx_comp, if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
(20 * HZ))) { (DCBX_COMP_TIMEOUT * HZ))) {
ql_dbg(ql_dbg_user, vha, 0x7026, ql_dbg(ql_dbg_user, vha, 0x7026,
"State change notification not received.\n"); "DCBX completion not received.\n");
ha->notify_dcbx_comp = 0; ha->notify_dcbx_comp = 0;
ha->notify_lb_portup_comp = 0;
rval = -EINVAL; rval = -EINVAL;
goto done_reset_internal; goto done_reset_internal;
} else } else
ql_dbg(ql_dbg_user, vha, 0x7027, ql_dbg(ql_dbg_user, vha, 0x7027,
"State change received.\n"); "DCBX completion received.\n");
if (wait2 &&
!wait_for_completion_timeout(&ha->lb_portup_comp,
(LB_PORTUP_COMP_TIMEOUT * HZ))) {
ql_dbg(ql_dbg_user, vha, 0x70c5,
"Port up completion not received.\n");
ha->notify_lb_portup_comp = 0;
rval = -EINVAL;
goto done_reset_internal;
} else
ql_dbg(ql_dbg_user, vha, 0x70c6,
"Port up completion received.\n");
ha->notify_dcbx_comp = 0; ha->notify_dcbx_comp = 0;
ha->notify_lb_portup_comp = 0;
} }
done_reset_internal: done_reset_internal:
return rval; return rval;
@ -618,10 +635,11 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
} }
/* Wait for DCBX complete event */ /* Wait for DCBX complete event */
if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) { if (!wait_for_completion_timeout(&ha->dcbx_comp,
(DCBX_COMP_TIMEOUT * HZ))) {
ql_dbg(ql_dbg_user, vha, 0x7022, ql_dbg(ql_dbg_user, vha, 0x7022,
"State change notification not received.\n"); "DCBX completion not received.\n");
ret = qla81xx_reset_loopback_mode(vha, new_config, 0); ret = qla81xx_reset_loopback_mode(vha, new_config, 0, 0);
/* /*
* If the reset of the loopback mode doesn't work take a FCoE * If the reset of the loopback mode doesn't work take a FCoE
* dump and reset the chip. * dump and reset the chip.
@ -639,7 +657,7 @@ qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
ha->flags.idc_compl_status = 0; ha->flags.idc_compl_status = 0;
} else } else
ql_dbg(ql_dbg_user, vha, 0x7023, ql_dbg(ql_dbg_user, vha, 0x7023,
"State change received.\n"); "DCBX completion received.\n");
} }
ha->notify_dcbx_comp = 0; ha->notify_dcbx_comp = 0;
@ -749,6 +767,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
if (IS_QLA81XX(ha) || IS_QLA8031(ha)) { if (IS_QLA81XX(ha) || IS_QLA8031(ha)) {
memset(config, 0, sizeof(config)); memset(config, 0, sizeof(config));
memset(new_config, 0, sizeof(new_config)); memset(new_config, 0, sizeof(new_config));
if (qla81xx_get_port_config(vha, config)) { if (qla81xx_get_port_config(vha, config)) {
ql_log(ql_log_warn, vha, 0x701f, ql_log(ql_log_warn, vha, 0x701f,
"Get port config failed.\n"); "Get port config failed.\n");
@ -773,7 +792,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
config, new_config, elreq.options); config, new_config, elreq.options);
else else
rval = qla81xx_reset_loopback_mode(vha, rval = qla81xx_reset_loopback_mode(vha,
config, 1); config, 1, 0);
else else
rval = qla81xx_set_loopback_mode(vha, config, rval = qla81xx_set_loopback_mode(vha, config,
new_config, elreq.options); new_config, elreq.options);
@ -817,7 +836,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
* Also clear internal loopback * Also clear internal loopback
*/ */
ret = qla81xx_reset_loopback_mode(vha, ret = qla81xx_reset_loopback_mode(vha,
new_config, 0); new_config, 0, 1);
if (ret) { if (ret) {
/* /*
* If the reset of the loopback mode * If the reset of the loopback mode

View file

@ -2882,7 +2882,13 @@ struct qla_hw_data {
struct completion mbx_cmd_comp; /* Serialize mbx access */ struct completion mbx_cmd_comp; /* Serialize mbx access */
struct completion mbx_intr_comp; /* Used for completion notification */ struct completion mbx_intr_comp; /* Used for completion notification */
struct completion dcbx_comp; /* For set port config notification */ struct completion dcbx_comp; /* For set port config notification */
struct completion lb_portup_comp; /* Used to wait for link up during
* loopback */
#define DCBX_COMP_TIMEOUT 20
#define LB_PORTUP_COMP_TIMEOUT 10
int notify_dcbx_comp; int notify_dcbx_comp;
int notify_lb_portup_comp;
struct mutex selflogin_lock; struct mutex selflogin_lock;
/* Basic firmware related information. */ /* Basic firmware related information. */

View file

@ -1032,6 +1032,9 @@ skip_rio:
} }
} }
case MBA_IDC_COMPLETE: case MBA_IDC_COMPLETE:
if (ha->notify_lb_portup_comp)
complete(&ha->lb_portup_comp);
/* Fallthru */
case MBA_IDC_TIME_EXT: case MBA_IDC_TIME_EXT:
if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw)) if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw))
qla81xx_idc_event(vha, mb[0], mb[1]); qla81xx_idc_event(vha, mb[0], mb[1]);

View file

@ -2465,6 +2465,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
complete(&ha->mbx_cmd_comp); complete(&ha->mbx_cmd_comp);
init_completion(&ha->mbx_intr_comp); init_completion(&ha->mbx_intr_comp);
init_completion(&ha->dcbx_comp); init_completion(&ha->dcbx_comp);
init_completion(&ha->lb_portup_comp);
set_bit(0, (unsigned long *) ha->vp_idx_map); set_bit(0, (unsigned long *) ha->vp_idx_map);