Commit 8fcd6b8b authored by Chad Dupuis's avatar Chad Dupuis Committed by James Bottomley

[SCSI] qla2xxx: Changes for ISP83xx loopback support.

Minor changes to support loopback functionality with ISP83xx CNAs.
Signed-off-by: default avatarGiridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: default avatarChad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent f9322eec
......@@ -530,13 +530,13 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
done:
return rval;
}
/* Set the port configuration to enable the
* internal loopback on ISP81XX
/*
* Set the port configuration to enable the internal or external loopback
* depending on the loopback mode.
*/
static inline int
qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
uint16_t *new_config)
qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
uint16_t *new_config, uint16_t mode)
{
int ret = 0;
int rval = 0;
......@@ -545,8 +545,14 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
goto done_set_internal;
new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
if (mode == INTERNAL_LOOPBACK)
new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
else if (mode == EXTERNAL_LOOPBACK)
new_config[0] = config[0] | (ENABLE_EXTERNAL_LOOPBACK << 1);
ql_dbg(ql_dbg_user, vha, 0x70be,
"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 = 1;
ret = qla81xx_set_port_config(vha, new_config);
......@@ -572,11 +578,9 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
return rval;
}
/* Set the port configuration to disable the
* internal loopback on ISP81XX
*/
/* Disable loopback mode */
static inline int
qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
qla81xx_reset_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
int wait)
{
int ret = 0;
......@@ -589,8 +593,12 @@ qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
memset(new_config, 0 , sizeof(new_config));
if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
ENABLE_INTERNAL_LOOPBACK) {
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;
......@@ -707,7 +715,8 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
if ((ha->current_topology == ISP_CFG_F ||
if (atomic_read(&vha->loop_state) == LOOP_READY &&
(ha->current_topology == ISP_CFG_F ||
((IS_QLA81XX(ha) || IS_QLA8031(ha)) &&
le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
&& req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
......@@ -729,30 +738,24 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
goto done_free_dma_req;
}
if (elreq.options != EXTERNAL_LOOPBACK) {
ql_dbg(ql_dbg_user, vha, 0x7020,
"Internal: current port config = %x\n",
config[0]);
if (qla81xx_set_internal_loopback(vha, config,
new_config)) {
ql_log(ql_log_warn, vha, 0x7024,
"Internal loopback failed.\n");
bsg_job->reply->result =
(DID_ERROR << 16);
rval = -EPERM;
goto done_free_dma_req;
}
} else {
/* For external loopback to work
* ensure internal loopback is disabled
*/
if (qla81xx_reset_internal_loopback(vha,
config, 1)) {
bsg_job->reply->result =
(DID_ERROR << 16);
rval = -EPERM;
goto done_free_dma_req;
}
ql_dbg(ql_dbg_user, vha, 0x70c0,
"elreq.options=%04x\n", elreq.options);
if (elreq.options == EXTERNAL_LOOPBACK)
if (IS_QLA8031(ha))
rval = qla81xx_set_loopback_mode(vha,
config, new_config, elreq.options);
else
rval = qla81xx_reset_loopback_mode(vha,
config, 1);
else
rval = qla81xx_set_loopback_mode(vha, config,
new_config, elreq.options);
if (rval) {
bsg_job->reply->result = (DID_ERROR << 16);
rval = -EPERM;
goto done_free_dma_req;
}
type = "FC_BSG_HST_VENDOR_LOOPBACK";
......@@ -766,7 +769,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
/* Revert back to original port config
* Also clear internal loopback
*/
qla81xx_reset_internal_loopback(vha,
qla81xx_reset_loopback_mode(vha,
new_config, 0);
}
......
......@@ -50,8 +50,10 @@
#define INT_DEF_LB_ECHO_CMD 1
/* Loopback related definations */
#define INTERNAL_LOOPBACK 0xF1
#define EXTERNAL_LOOPBACK 0xF2
#define ENABLE_INTERNAL_LOOPBACK 0x02
#define ENABLE_EXTERNAL_LOOPBACK 0x04
#define INTERNAL_LOOPBACK_MASK 0x000E
#define MAX_ELS_FRAME_PAYLOAD 252
#define ELS_OPCODE_BYTE 0x10
......
......@@ -18,7 +18,7 @@
* | Device Discovery | 0x2087 | 0x2020-0x2022 |
* | Queue Command and IO tracing | 0x3030 | 0x3006,0x3008 |
* | | | 0x302d-0x302e |
* | DPC Thread | 0x401c | 0x4002,0x4013 |
* | DPC Thread | 0x401d | 0x4002,0x4013 |
* | Async Events | 0x5071 | 0x502b-0x502f |
* | | | 0x5047,0x5052 |
* | Timer Routines | 0x6011 | |
......@@ -29,12 +29,11 @@
* | | | 0x70a5,0x70a6, |
* | | | 0x70a8,0x70ab, |
* | | | 0x70ad-0x70ae |
* | | | 0x70be-70c0 |
* | Task Management | 0x803c | 0x8025-0x8026 |
* | | | 0x800b,0x8039 |
* | AER/EEH | 0x9011 | |
* | Virtual Port | 0xa007 | |
* | ISP82XX Specific | 0xb084 | 0xb002 |
* | ISP82XX Specific | 0xb084 | 0xb002,0xb024 |
* | | | 0xb082,0xb083 |
* | MultiQ | 0xc00c | |
* | Misc | 0xd010 | |
......
......@@ -799,6 +799,7 @@ typedef struct {
#define MBC_SEND_RNFT_ELS 0x5e /* Send RNFT ELS request */
#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */
#define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */
#define MBC_PORT_RESET 0x120 /* Port Reset */
#define MBC_SET_PORT_CONFIG 0x122 /* Set port configuration */
#define MBC_GET_PORT_CONFIG 0x123 /* Get port configuration */
......
......@@ -48,7 +48,7 @@ extern void qla2x00_update_fcports(scsi_qla_host_t *);
extern int qla2x00_abort_isp(scsi_qla_host_t *);
extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *);
extern void qla82xx_quiescent_state_cleanup(scsi_qla_host_t *);
extern void qla2x00_quiesce_io(scsi_qla_host_t *);
extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
......
......@@ -4165,7 +4165,7 @@ qla2xxx_mctp_dump(scsi_qla_host_t *vha)
}
/*
* qla82xx_quiescent_state_cleanup
* qla2x00_quiesce_io
* Description: This function will block the new I/Os
* Its not aborting any I/Os as context
* is not destroyed during quiescence
......@@ -4173,20 +4173,20 @@ qla2xxx_mctp_dump(scsi_qla_host_t *vha)
* return : void
*/
void
qla82xx_quiescent_state_cleanup(scsi_qla_host_t *vha)
qla2x00_quiesce_io(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
struct scsi_qla_host *vp;
ql_dbg(ql_dbg_p3p, vha, 0xb002,
"Performing ISP error recovery - ha=%p.\n", ha);
ql_dbg(ql_dbg_dpc, vha, 0x401d,
"Quiescing I/O - ha=%p.\n", ha);
atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
atomic_set(&vha->loop_state, LOOP_DOWN);
qla2x00_mark_all_devices_lost(vha, 0);
list_for_each_entry(vp, &ha->vp_list, list)
qla2x00_mark_all_devices_lost(vha, 0);
qla2x00_mark_all_devices_lost(vp, 0);
} else {
if (!atomic_read(&vha->loop_down_timer))
atomic_set(&vha->loop_down_timer,
......
......@@ -295,14 +295,16 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
mb[4], mb[5], mb[6]);
/* Acknowledgement needed? [Notify && non-zero timeout]. */
timeout = (descr >> 8) & 0xf;
if (aen != MBA_IDC_NOTIFY || !timeout)
return;
if (IS_QLA81XX(vha->hw)) {
/* Acknowledgement needed? [Notify && non-zero timeout]. */
timeout = (descr >> 8) & 0xf;
if (aen != MBA_IDC_NOTIFY || !timeout)
return;
ql_dbg(ql_dbg_async, vha, 0x5022,
"%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
vha->host_no, event[aen & 0xff], timeout);
ql_dbg(ql_dbg_async, vha, 0x5022,
"%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
vha->host_no, event[aen & 0xff], timeout);
}
rval = qla2x00_post_idc_ack_work(vha, mb);
if (rval != QLA_SUCCESS)
......@@ -982,8 +984,17 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
"FCF Configuration Error -- %04x %04x %04x.\n",
mb[1], mb[2], mb[3]);
break;
case MBA_IDC_COMPLETE:
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) {
set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
/* Ack that we have quiesced I/O */
qla81xx_idc_event(vha, mb[0], mb[1]);
qla2xxx_wake_dpc(vha);
}
case MBA_IDC_COMPLETE:
case MBA_IDC_TIME_EXT:
if (IS_QLA81XX(vha->hw))
qla81xx_idc_event(vha, mb[0], mb[1]);
......
......@@ -2939,7 +2939,7 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
if (vha->flags.online) {
/*Block any further I/O and wait for pending cmnds to complete*/
qla82xx_quiescent_state_cleanup(vha);
qla2x00_quiesce_io(vha);
}
/* Set the quiescence ready bit */
......
......@@ -4513,14 +4513,21 @@ qla2x00_do_dpc(void *data)
if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
"Quiescence mode scheduled.\n");
qla82xx_device_state_handler(base_vha);
clear_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags);
if (!ha->flags.quiesce_owner) {
qla2x00_perform_loop_resync(base_vha);
qla82xx_idc_lock(ha);
qla82xx_clear_qsnt_ready(base_vha);
qla82xx_idc_unlock(ha);
if (IS_QLA82XX(ha)) {
qla82xx_device_state_handler(base_vha);
clear_bit(ISP_QUIESCE_NEEDED,
&base_vha->dpc_flags);
if (!ha->flags.quiesce_owner) {
qla2x00_perform_loop_resync(base_vha);
qla82xx_idc_lock(ha);
qla82xx_clear_qsnt_ready(base_vha);
qla82xx_idc_unlock(ha);
}
} else {
clear_bit(ISP_QUIESCE_NEEDED,
&base_vha->dpc_flags);
qla2x00_quiesce_io(base_vha);
}
ql_dbg(ql_dbg_dpc, base_vha, 0x400a,
"Quiescence mode end.\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment