[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:
Chad Dupuis 2012-08-22 14:21:06 -04:00 коммит произвёл James Bottomley
Родитель f9322eeca5
Коммит 8fcd6b8b0f
9 изменённых файлов: 86 добавлений и 63 удалений

Просмотреть файл

@ -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");