[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:
|
||||
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,7 +545,13 @@ qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
|
|||
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
|
||||
goto done_set_internal;
|
||||
|
||||
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;
|
||||
|
@ -572,11 +578,9 @@ done_set_internal:
|
|||
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,31 +738,25 @@ 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);
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
type = "FC_BSG_HST_VENDOR_LOOPBACK";
|
||||
ql_dbg(ql_dbg_user, vha, 0x7028,
|
||||
|
@ -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,6 +295,7 @@ 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]);
|
||||
|
||||
if (IS_QLA81XX(vha->hw)) {
|
||||
/* Acknowledgement needed? [Notify && non-zero timeout]. */
|
||||
timeout = (descr >> 8) & 0xf;
|
||||
if (aen != MBA_IDC_NOTIFY || !timeout)
|
||||
|
@ -303,6 +304,7 @@ qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
|
|||
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 @@ skip_rio:
|
|||
"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,8 +4513,10 @@ 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");
|
||||
if (IS_QLA82XX(ha)) {
|
||||
qla82xx_device_state_handler(base_vha);
|
||||
clear_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags);
|
||||
clear_bit(ISP_QUIESCE_NEEDED,
|
||||
&base_vha->dpc_flags);
|
||||
if (!ha->flags.quiesce_owner) {
|
||||
qla2x00_perform_loop_resync(base_vha);
|
||||
|
||||
|
@ -4522,6 +4524,11 @@ qla2x00_do_dpc(void *data)
|
|||
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");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче