mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-18 17:54:13 +08:00
[SCSI] qla2xxx: Add internal loopback support for ISP81xx.
Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
parent
3a6478df74
commit
23f2ebd17a
@ -483,6 +483,98 @@ done:
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Set the port configuration to enable the
|
||||
* internal loopback on ISP81XX
|
||||
*/
|
||||
static inline int
|
||||
qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
|
||||
uint16_t *new_config)
|
||||
{
|
||||
int ret = 0;
|
||||
int rval = 0;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha))
|
||||
goto done_set_internal;
|
||||
|
||||
new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1);
|
||||
memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
|
||||
|
||||
ha->notify_dcbx_comp = 1;
|
||||
ret = qla81xx_set_port_config(vha, new_config);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
DEBUG2(printk(KERN_ERR
|
||||
"%s(%lu): Set port config failed\n",
|
||||
__func__, vha->host_no));
|
||||
ha->notify_dcbx_comp = 0;
|
||||
rval = -EINVAL;
|
||||
goto done_set_internal;
|
||||
}
|
||||
|
||||
/* Wait for DCBX complete event */
|
||||
if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) {
|
||||
DEBUG2(qla_printk(KERN_WARNING, ha,
|
||||
"State change notificaition not received.\n"));
|
||||
} else
|
||||
DEBUG2(qla_printk(KERN_INFO, ha,
|
||||
"State change RECEIVED\n"));
|
||||
|
||||
ha->notify_dcbx_comp = 0;
|
||||
|
||||
done_set_internal:
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Set the port configuration to disable the
|
||||
* internal loopback on ISP81XX
|
||||
*/
|
||||
static inline int
|
||||
qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config,
|
||||
int wait)
|
||||
{
|
||||
int ret = 0;
|
||||
int rval = 0;
|
||||
uint16_t new_config[4];
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha))
|
||||
goto done_reset_internal;
|
||||
|
||||
memset(new_config, 0 , sizeof(new_config));
|
||||
if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 ==
|
||||
ENABLE_INTERNAL_LOOPBACK) {
|
||||
new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK;
|
||||
memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ;
|
||||
|
||||
ha->notify_dcbx_comp = wait;
|
||||
ret = qla81xx_set_port_config(vha, new_config);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
DEBUG2(printk(KERN_ERR
|
||||
"%s(%lu): Set port config failed\n",
|
||||
__func__, vha->host_no));
|
||||
ha->notify_dcbx_comp = 0;
|
||||
rval = -EINVAL;
|
||||
goto done_reset_internal;
|
||||
}
|
||||
|
||||
/* Wait for DCBX complete event */
|
||||
if (wait && !wait_for_completion_timeout(&ha->dcbx_comp,
|
||||
(20 * HZ))) {
|
||||
DEBUG2(qla_printk(KERN_WARNING, ha,
|
||||
"State change notificaition not received.\n"));
|
||||
ha->notify_dcbx_comp = 0;
|
||||
rval = -EINVAL;
|
||||
goto done_reset_internal;
|
||||
} else
|
||||
DEBUG2(qla_printk(KERN_INFO, ha,
|
||||
"State change RECEIVED\n"));
|
||||
|
||||
ha->notify_dcbx_comp = 0;
|
||||
}
|
||||
done_reset_internal:
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
{
|
||||
@ -494,6 +586,7 @@ qla2x00_process_loopback(struct fc_bsg_job *bsg_job)
|
||||
char *type;
|
||||
struct msg_echo_lb elreq;
|
||||
uint16_t response[MAILBOX_REGISTER_COUNT];
|
||||
uint16_t config[4], new_config[4];
|
||||
uint8_t *fw_sts_ptr;
|
||||
uint8_t *req_data = NULL;
|
||||
dma_addr_t req_data_dma;
|
||||
@ -568,29 +661,102 @@ 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) {
|
||||
type = "FC_BSG_HST_VENDOR_LOOPBACK";
|
||||
DEBUG2(qla_printk(KERN_INFO, ha,
|
||||
"scsi(%ld) bsg rqst type: %s\n",
|
||||
vha->host_no, type));
|
||||
|
||||
command_sent = INT_DEF_LB_LOOPBACK_CMD;
|
||||
rval = qla2x00_loopback_test(vha, &elreq, response);
|
||||
if (IS_QLA81XX(ha)) {
|
||||
if (response[0] == MBS_COMMAND_ERROR &&
|
||||
response[1] == MBS_LB_RESET) {
|
||||
DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
|
||||
"ISP\n", __func__, vha->host_no));
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
qla2xxx_wake_dpc(vha);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((ha->current_topology == ISP_CFG_F ||
|
||||
(IS_QLA81XX(ha) &&
|
||||
le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE
|
||||
&& req_data_len == MAX_ELS_FRAME_PAYLOAD)) &&
|
||||
elreq.options == EXTERNAL_LOOPBACK) {
|
||||
type = "FC_BSG_HST_VENDOR_ECHO_DIAG";
|
||||
DEBUG2(qla_printk(KERN_INFO, ha,
|
||||
"scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
|
||||
"scsi(%ld) bsg rqst type: %s\n", vha->host_no, type));
|
||||
command_sent = INT_DEF_LB_ECHO_CMD;
|
||||
rval = qla2x00_echo_test(vha, &elreq, response);
|
||||
} else {
|
||||
if (IS_QLA81XX(ha)) {
|
||||
memset(config, 0, sizeof(config));
|
||||
memset(new_config, 0, sizeof(new_config));
|
||||
if (qla81xx_get_port_config(vha, config)) {
|
||||
DEBUG2(printk(KERN_ERR
|
||||
"%s(%lu): Get port config failed\n",
|
||||
__func__, vha->host_no));
|
||||
bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
bsg_job->reply->result = (DID_ERROR << 16);
|
||||
rval = -EPERM;
|
||||
goto done_free_dma_req;
|
||||
}
|
||||
|
||||
if (elreq.options != EXTERNAL_LOOPBACK) {
|
||||
DEBUG2(qla_printk(KERN_INFO, ha,
|
||||
"Internal: current port config = %x\n",
|
||||
config[0]));
|
||||
if (qla81xx_set_internal_loopback(vha, config,
|
||||
new_config)) {
|
||||
bsg_job->reply->reply_payload_rcv_len =
|
||||
0;
|
||||
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->reply_payload_rcv_len =
|
||||
0;
|
||||
bsg_job->reply->result =
|
||||
(DID_ERROR << 16);
|
||||
rval = -EPERM;
|
||||
goto done_free_dma_req;
|
||||
}
|
||||
}
|
||||
|
||||
type = "FC_BSG_HST_VENDOR_LOOPBACK";
|
||||
DEBUG2(qla_printk(KERN_INFO, ha,
|
||||
"scsi(%ld) bsg rqst type: %s\n",
|
||||
vha->host_no, type));
|
||||
|
||||
command_sent = INT_DEF_LB_LOOPBACK_CMD;
|
||||
rval = qla2x00_loopback_test(vha, &elreq, response);
|
||||
|
||||
if (new_config[1]) {
|
||||
/* Revert back to original port config
|
||||
* Also clear internal loopback
|
||||
*/
|
||||
qla81xx_reset_internal_loopback(vha,
|
||||
new_config, 0);
|
||||
}
|
||||
|
||||
if (response[0] == MBS_COMMAND_ERROR &&
|
||||
response[1] == MBS_LB_RESET) {
|
||||
DEBUG2(printk(KERN_ERR "%s(%ld): ABORTing "
|
||||
"ISP\n", __func__, vha->host_no));
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
qla2xxx_wake_dpc(vha);
|
||||
qla2x00_wait_for_chip_reset(vha);
|
||||
/* Also reset the MPI */
|
||||
if (qla81xx_restart_mpi_firmware(vha) !=
|
||||
QLA_SUCCESS) {
|
||||
qla_printk(KERN_INFO, ha,
|
||||
"MPI reset failed for host%ld.\n",
|
||||
vha->host_no);
|
||||
}
|
||||
|
||||
bsg_job->reply->reply_payload_rcv_len = 0;
|
||||
bsg_job->reply->result = (DID_ERROR << 16);
|
||||
rval = -EIO;
|
||||
goto done_free_dma_req;
|
||||
}
|
||||
} else {
|
||||
type = "FC_BSG_HST_VENDOR_LOOPBACK";
|
||||
DEBUG2(qla_printk(KERN_INFO, ha,
|
||||
"scsi(%ld) bsg rqst type: %s\n",
|
||||
vha->host_no, type));
|
||||
command_sent = INT_DEF_LB_LOOPBACK_CMD;
|
||||
rval = qla2x00_loopback_test(vha, &elreq, response);
|
||||
}
|
||||
}
|
||||
|
||||
if (rval) {
|
||||
|
@ -19,6 +19,13 @@
|
||||
#define INT_DEF_LB_LOOPBACK_CMD 0
|
||||
#define INT_DEF_LB_ECHO_CMD 1
|
||||
|
||||
/* Loopback related definations */
|
||||
#define EXTERNAL_LOOPBACK 0xF2
|
||||
#define ENABLE_INTERNAL_LOOPBACK 0x02
|
||||
#define INTERNAL_LOOPBACK_MASK 0x000E
|
||||
#define MAX_ELS_FRAME_PAYLOAD 252
|
||||
#define ELS_OPCODE_BYTE 0x10
|
||||
|
||||
/* BSG Vendor specific definations */
|
||||
#define A84_ISSUE_WRITE_TYPE_CMD 0
|
||||
#define A84_ISSUE_READ_TYPE_CMD 1
|
||||
|
@ -714,6 +714,8 @@ 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_SET_PORT_CONFIG 0x122 /* Set port configuration */
|
||||
#define MBC_GET_PORT_CONFIG 0x123 /* Get port configuration */
|
||||
|
||||
/* Firmware return data sizes */
|
||||
#define FCAL_MAP_SIZE 128
|
||||
@ -2631,6 +2633,8 @@ struct qla_hw_data {
|
||||
struct mutex vport_lock; /* Virtual port synchronization */
|
||||
struct completion mbx_cmd_comp; /* Serialize mbx access */
|
||||
struct completion mbx_intr_comp; /* Used for completion notification */
|
||||
struct completion dcbx_comp; /* For set port config notification */
|
||||
int notify_dcbx_comp;
|
||||
|
||||
/* Basic firmware related information. */
|
||||
uint16_t fw_major_version;
|
||||
|
@ -357,6 +357,11 @@ qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t);
|
||||
extern int qla2x00_get_data_rate(scsi_qla_host_t *);
|
||||
extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t,
|
||||
uint16_t *);
|
||||
extern int
|
||||
qla81xx_get_port_config(scsi_qla_host_t *, uint16_t *);
|
||||
|
||||
extern int
|
||||
qla81xx_set_port_config(scsi_qla_host_t *, uint16_t *);
|
||||
|
||||
/*
|
||||
* Global Function Prototypes in qla_isr.c source file.
|
||||
|
@ -545,10 +545,13 @@ skip_rio:
|
||||
if (IS_QLA2100(ha))
|
||||
break;
|
||||
|
||||
if (IS_QLA8XXX_TYPE(ha))
|
||||
if (IS_QLA8XXX_TYPE(ha)) {
|
||||
DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
|
||||
"%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
|
||||
else
|
||||
if (ha->notify_dcbx_comp)
|
||||
complete(&ha->dcbx_comp);
|
||||
|
||||
} else
|
||||
DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
|
||||
"received.\n", vha->host_no));
|
||||
|
||||
|
@ -3949,6 +3949,72 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
DEBUG11(printk(KERN_INFO
|
||||
"%s(%ld): entered.\n", __func__, vha->host_no));
|
||||
|
||||
if (!IS_QLA81XX(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
mcp->mb[0] = MBC_GET_PORT_CONFIG;
|
||||
mcp->out_mb = MBX_0;
|
||||
mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
DEBUG2_3_11(printk(KERN_WARNING
|
||||
"%s(%ld): failed=%x (%x).\n", __func__,
|
||||
vha->host_no, rval, mcp->mb[0]));
|
||||
} else {
|
||||
/* Copy all bits to preserve original value */
|
||||
memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4);
|
||||
|
||||
DEBUG11(printk(KERN_INFO
|
||||
"%s(%ld): done.\n", __func__, vha->host_no));
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
DEBUG11(printk(KERN_INFO
|
||||
"%s(%ld): entered.\n", __func__, vha->host_no));
|
||||
|
||||
mcp->mb[0] = MBC_SET_PORT_CONFIG;
|
||||
/* Copy all bits to preserve original setting */
|
||||
memcpy(&mcp->mb[1], mb, sizeof(uint16_t) * 4);
|
||||
mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
DEBUG2_3_11(printk(KERN_WARNING
|
||||
"%s(%ld): failed=%x (%x).\n", __func__,
|
||||
vha->host_no, rval, mcp->mb[0]));
|
||||
} else
|
||||
DEBUG11(printk(KERN_INFO
|
||||
"%s(%ld): done.\n", __func__, vha->host_no));
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority,
|
||||
uint16_t *mb)
|
||||
|
@ -2128,6 +2128,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
init_completion(&ha->mbx_cmd_comp);
|
||||
complete(&ha->mbx_cmd_comp);
|
||||
init_completion(&ha->mbx_intr_comp);
|
||||
init_completion(&ha->dcbx_comp);
|
||||
|
||||
set_bit(0, (unsigned long *) ha->vp_idx_map);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user