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>
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;
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);
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;
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;
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)) &&
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";
/* Revert back to original port config
* Also clear internal loopback
*/
- qla81xx_reset_internal_loopback(vha,
+ qla81xx_reset_loopback_mode(vha,
new_config, 0);
}
#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
* | 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 | |
* | | | 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 | |
#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 */
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 *);
}
/*
-* 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
* 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,
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)
"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]);
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 */
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");