[SCSI] qla2xxx: Changes for ISP83xx loopback support.
Minor changes to support loopback functionality with ISP83xx CNAs. Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Родитель
f9322eeca5
Коммит
8fcd6b8b0f
|
@ -530,13 +530,13 @@ done_unmap_sg:
|
||||||
done:
|
done:
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
/* Set the port configuration to enable the
|
* Set the port configuration to enable the internal or external loopback
|
||||||
* internal loopback on ISP81XX
|
* depending on the loopback mode.
|
||||||
*/
|
*/
|
||||||
static inline int
|
static inline int
|
||||||
qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
|
qla81xx_set_loopback_mode(scsi_qla_host_t *vha, uint16_t *config,
|
||||||
uint16_t *new_config)
|
uint16_t *new_config, uint16_t mode)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int rval = 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))
|
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
|
||||||
goto done_set_internal;
|
goto done_set_internal;
|
||||||
|
|
||||||
new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
|
if (mode == INTERNAL_LOOPBACK)
|
||||||
memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
|
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;
|
ha->notify_dcbx_comp = 1;
|
||||||
ret = qla81xx_set_port_config(vha, new_config);
|
ret = qla81xx_set_port_config(vha, new_config);
|
||||||
|
@ -572,11 +578,9 @@ done_set_internal:
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the port configuration to disable the
|
/* Disable loopback mode */
|
||||||
* internal loopback on ISP81XX
|
|
||||||
*/
|
|
||||||
static inline int
|
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 wait)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
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));
|
memset(new_config, 0 , sizeof(new_config));
|
||||||
if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
|
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;
|
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) ;
|
memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
|
||||||
|
|
||||||
ha->notify_dcbx_comp = wait;
|
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];
|
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)) &&
|
((IS_QLA81XX(ha) || IS_QLA8031(ha)) &&
|
||||||
le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
|
le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
|
||||||
&& req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
|
&& 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;
|
goto done_free_dma_req;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elreq.options != EXTERNAL_LOOPBACK) {
|
ql_dbg(ql_dbg_user, vha, 0x70c0,
|
||||||
ql_dbg(ql_dbg_user, vha, 0x7020,
|
"elreq.options=%04x\n", elreq.options);
|
||||||
"Internal: current port config = %x\n",
|
|
||||||
config[0]);
|
if (elreq.options == EXTERNAL_LOOPBACK)
|
||||||
if (qla81xx_set_internal_loopback(vha, config,
|
if (IS_QLA8031(ha))
|
||||||
new_config)) {
|
rval = qla81xx_set_loopback_mode(vha,
|
||||||
ql_log(ql_log_warn, vha, 0x7024,
|
config, new_config, elreq.options);
|
||||||
"Internal loopback failed.\n");
|
else
|
||||||
bsg_job->reply->result =
|
rval = qla81xx_reset_loopback_mode(vha,
|
||||||
(DID_ERROR << 16);
|
config, 1);
|
||||||
rval = -EPERM;
|
else
|
||||||
goto done_free_dma_req;
|
rval = qla81xx_set_loopback_mode(vha, config,
|
||||||
}
|
new_config, elreq.options);
|
||||||
} else {
|
|
||||||
/* For external loopback to work
|
if (rval) {
|
||||||
* ensure internal loopback is disabled
|
bsg_job->reply->result = (DID_ERROR << 16);
|
||||||
*/
|
rval = -EPERM;
|
||||||
if (qla81xx_reset_internal_loopback(vha,
|
goto done_free_dma_req;
|
||||||
config, 1)) {
|
|
||||||
bsg_job->reply->result =
|
|
||||||
(DID_ERROR << 16);
|
|
||||||
rval = -EPERM;
|
|
||||||
goto done_free_dma_req;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type = "FC_BSG_HST_VENDOR_LOOPBACK";
|
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
|
/* Revert back to original port config
|
||||||
* Also clear internal loopback
|
* Also clear internal loopback
|
||||||
*/
|
*/
|
||||||
qla81xx_reset_internal_loopback(vha,
|
qla81xx_reset_loopback_mode(vha,
|
||||||
new_config, 0);
|
new_config, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,10 @@
|
||||||
#define INT_DEF_LB_ECHO_CMD 1
|
#define INT_DEF_LB_ECHO_CMD 1
|
||||||
|
|
||||||
/* Loopback related definations */
|
/* Loopback related definations */
|
||||||
|
#define INTERNAL_LOOPBACK 0xF1
|
||||||
#define EXTERNAL_LOOPBACK 0xF2
|
#define EXTERNAL_LOOPBACK 0xF2
|
||||||
#define ENABLE_INTERNAL_LOOPBACK 0x02
|
#define ENABLE_INTERNAL_LOOPBACK 0x02
|
||||||
|
#define ENABLE_EXTERNAL_LOOPBACK 0x04
|
||||||
#define INTERNAL_LOOPBACK_MASK 0x000E
|
#define INTERNAL_LOOPBACK_MASK 0x000E
|
||||||
#define MAX_ELS_FRAME_PAYLOAD 252
|
#define MAX_ELS_FRAME_PAYLOAD 252
|
||||||
#define ELS_OPCODE_BYTE 0x10
|
#define ELS_OPCODE_BYTE 0x10
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
* | Device Discovery | 0x2087 | 0x2020-0x2022 |
|
* | Device Discovery | 0x2087 | 0x2020-0x2022 |
|
||||||
* | Queue Command and IO tracing | 0x3030 | 0x3006,0x3008 |
|
* | Queue Command and IO tracing | 0x3030 | 0x3006,0x3008 |
|
||||||
* | | | 0x302d-0x302e |
|
* | | | 0x302d-0x302e |
|
||||||
* | DPC Thread | 0x401c | 0x4002,0x4013 |
|
* | DPC Thread | 0x401d | 0x4002,0x4013 |
|
||||||
* | Async Events | 0x5071 | 0x502b-0x502f |
|
* | Async Events | 0x5071 | 0x502b-0x502f |
|
||||||
* | | | 0x5047,0x5052 |
|
* | | | 0x5047,0x5052 |
|
||||||
* | Timer Routines | 0x6011 | |
|
* | Timer Routines | 0x6011 | |
|
||||||
|
@ -29,12 +29,11 @@
|
||||||
* | | | 0x70a5,0x70a6, |
|
* | | | 0x70a5,0x70a6, |
|
||||||
* | | | 0x70a8,0x70ab, |
|
* | | | 0x70a8,0x70ab, |
|
||||||
* | | | 0x70ad-0x70ae |
|
* | | | 0x70ad-0x70ae |
|
||||||
* | | | 0x70be-70c0 |
|
|
||||||
* | Task Management | 0x803c | 0x8025-0x8026 |
|
* | Task Management | 0x803c | 0x8025-0x8026 |
|
||||||
* | | | 0x800b,0x8039 |
|
* | | | 0x800b,0x8039 |
|
||||||
* | AER/EEH | 0x9011 | |
|
* | AER/EEH | 0x9011 | |
|
||||||
* | Virtual Port | 0xa007 | |
|
* | Virtual Port | 0xa007 | |
|
||||||
* | ISP82XX Specific | 0xb084 | 0xb002 |
|
* | ISP82XX Specific | 0xb084 | 0xb002,0xb024 |
|
||||||
* | | | 0xb082,0xb083 |
|
* | | | 0xb082,0xb083 |
|
||||||
* | MultiQ | 0xc00c | |
|
* | MultiQ | 0xc00c | |
|
||||||
* | Misc | 0xd010 | |
|
* | Misc | 0xd010 | |
|
||||||
|
|
|
@ -799,6 +799,7 @@ typedef struct {
|
||||||
#define MBC_SEND_RNFT_ELS 0x5e /* Send RNFT ELS request */
|
#define MBC_SEND_RNFT_ELS 0x5e /* Send RNFT ELS request */
|
||||||
#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */
|
#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */
|
||||||
#define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */
|
#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_SET_PORT_CONFIG 0x122 /* Set port configuration */
|
||||||
#define MBC_GET_PORT_CONFIG 0x123 /* Get 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 int qla2x00_abort_isp(scsi_qla_host_t *);
|
||||||
extern void qla2x00_abort_isp_cleanup(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 *);
|
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
|
* Description: This function will block the new I/Os
|
||||||
* Its not aborting any I/Os as context
|
* Its not aborting any I/Os as context
|
||||||
* is not destroyed during quiescence
|
* is not destroyed during quiescence
|
||||||
|
@ -4173,20 +4173,20 @@ qla2xxx_mctp_dump(scsi_qla_host_t *vha)
|
||||||
* return : void
|
* return : void
|
||||||
*/
|
*/
|
||||||
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 qla_hw_data *ha = vha->hw;
|
||||||
struct scsi_qla_host *vp;
|
struct scsi_qla_host *vp;
|
||||||
|
|
||||||
ql_dbg(ql_dbg_p3p, vha, 0xb002,
|
ql_dbg(ql_dbg_dpc, vha, 0x401d,
|
||||||
"Performing ISP error recovery - ha=%p.\n", ha);
|
"Quiescing I/O - ha=%p.\n", ha);
|
||||||
|
|
||||||
atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
|
atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
|
||||||
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
||||||
atomic_set(&vha->loop_state, LOOP_DOWN);
|
atomic_set(&vha->loop_state, LOOP_DOWN);
|
||||||
qla2x00_mark_all_devices_lost(vha, 0);
|
qla2x00_mark_all_devices_lost(vha, 0);
|
||||||
list_for_each_entry(vp, &ha->vp_list, list)
|
list_for_each_entry(vp, &ha->vp_list, list)
|
||||||
qla2x00_mark_all_devices_lost(vha, 0);
|
qla2x00_mark_all_devices_lost(vp, 0);
|
||||||
} else {
|
} else {
|
||||||
if (!atomic_read(&vha->loop_down_timer))
|
if (!atomic_read(&vha->loop_down_timer))
|
||||||
atomic_set(&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],
|
event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
|
||||||
mb[4], mb[5], mb[6]);
|
mb[4], mb[5], mb[6]);
|
||||||
|
|
||||||
/* Acknowledgement needed? [Notify && non-zero timeout]. */
|
if (IS_QLA81XX(vha->hw)) {
|
||||||
timeout = (descr >> 8) & 0xf;
|
/* Acknowledgement needed? [Notify && non-zero timeout]. */
|
||||||
if (aen != MBA_IDC_NOTIFY || !timeout)
|
timeout = (descr >> 8) & 0xf;
|
||||||
return;
|
if (aen != MBA_IDC_NOTIFY || !timeout)
|
||||||
|
return;
|
||||||
|
|
||||||
ql_dbg(ql_dbg_async, vha, 0x5022,
|
ql_dbg(ql_dbg_async, vha, 0x5022,
|
||||||
"%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
|
"%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
|
||||||
vha->host_no, event[aen & 0xff], timeout);
|
vha->host_no, event[aen & 0xff], timeout);
|
||||||
|
}
|
||||||
|
|
||||||
rval = qla2x00_post_idc_ack_work(vha, mb);
|
rval = qla2x00_post_idc_ack_work(vha, mb);
|
||||||
if (rval != QLA_SUCCESS)
|
if (rval != QLA_SUCCESS)
|
||||||
|
@ -982,8 +984,17 @@ skip_rio:
|
||||||
"FCF Configuration Error -- %04x %04x %04x.\n",
|
"FCF Configuration Error -- %04x %04x %04x.\n",
|
||||||
mb[1], mb[2], mb[3]);
|
mb[1], mb[2], mb[3]);
|
||||||
break;
|
break;
|
||||||
case MBA_IDC_COMPLETE:
|
|
||||||
case MBA_IDC_NOTIFY:
|
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:
|
case MBA_IDC_TIME_EXT:
|
||||||
if (IS_QLA81XX(vha->hw))
|
if (IS_QLA81XX(vha->hw))
|
||||||
qla81xx_idc_event(vha, mb[0], mb[1]);
|
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) {
|
if (vha->flags.online) {
|
||||||
/*Block any further I/O and wait for pending cmnds to complete*/
|
/*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 */
|
/* Set the quiescence ready bit */
|
||||||
|
|
|
@ -4513,14 +4513,21 @@ qla2x00_do_dpc(void *data)
|
||||||
if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
|
if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
|
||||||
ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
|
ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
|
||||||
"Quiescence mode scheduled.\n");
|
"Quiescence mode scheduled.\n");
|
||||||
qla82xx_device_state_handler(base_vha);
|
if (IS_QLA82XX(ha)) {
|
||||||
clear_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags);
|
qla82xx_device_state_handler(base_vha);
|
||||||
if (!ha->flags.quiesce_owner) {
|
clear_bit(ISP_QUIESCE_NEEDED,
|
||||||
qla2x00_perform_loop_resync(base_vha);
|
&base_vha->dpc_flags);
|
||||||
|
if (!ha->flags.quiesce_owner) {
|
||||||
|
qla2x00_perform_loop_resync(base_vha);
|
||||||
|
|
||||||
qla82xx_idc_lock(ha);
|
qla82xx_idc_lock(ha);
|
||||||
qla82xx_clear_qsnt_ready(base_vha);
|
qla82xx_clear_qsnt_ready(base_vha);
|
||||||
qla82xx_idc_unlock(ha);
|
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,
|
ql_dbg(ql_dbg_dpc, base_vha, 0x400a,
|
||||||
"Quiescence mode end.\n");
|
"Quiescence mode end.\n");
|
||||||
|
|
Загрузка…
Ссылка в новой задаче