[SCSI] qla2xxx: IDC implementation for ISP83xx.
Signed-off-by: Santosh Vernekar <santosh.vernekar@qlogic.com> Signed-off-by: Saurav Kashyap <saurav.kashyap@qlogic.com> Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
parent
40129a4c6e
commit
7d613ac6ac
@ -564,6 +564,7 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
|
||||
int type;
|
||||
uint32_t idc_control;
|
||||
|
||||
if (off != 0)
|
||||
return -EINVAL;
|
||||
@ -587,22 +588,36 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
|
||||
scsi_unblock_requests(vha->host);
|
||||
break;
|
||||
case 0x2025d:
|
||||
if (!IS_QLA81XX(ha) || !IS_QLA8031(ha))
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
ql_log(ql_log_info, vha, 0x706f,
|
||||
"Issuing MPI reset.\n");
|
||||
|
||||
/* Make sure FC side is not in reset */
|
||||
qla2x00_wait_for_hba_online(vha);
|
||||
if (IS_QLA83XX(ha)) {
|
||||
uint32_t idc_control;
|
||||
|
||||
/* Issue MPI reset */
|
||||
scsi_block_requests(vha->host);
|
||||
if (qla81xx_restart_mpi_firmware(vha) != QLA_SUCCESS)
|
||||
ql_log(ql_log_warn, vha, 0x7070,
|
||||
"MPI reset failed.\n");
|
||||
scsi_unblock_requests(vha->host);
|
||||
break;
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
__qla83xx_get_idc_control(vha, &idc_control);
|
||||
idc_control |= QLA83XX_IDC_GRACEFUL_RESET;
|
||||
__qla83xx_set_idc_control(vha, idc_control);
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE,
|
||||
QLA8XXX_DEV_NEED_RESET);
|
||||
qla83xx_idc_audit(vha, IDC_AUDIT_TIMESTAMP);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
break;
|
||||
} else {
|
||||
/* Make sure FC side is not in reset */
|
||||
qla2x00_wait_for_hba_online(vha);
|
||||
|
||||
/* Issue MPI reset */
|
||||
scsi_block_requests(vha->host);
|
||||
if (qla81xx_restart_mpi_firmware(vha) != QLA_SUCCESS)
|
||||
ql_log(ql_log_warn, vha, 0x7070,
|
||||
"MPI reset failed.\n");
|
||||
scsi_unblock_requests(vha->host);
|
||||
break;
|
||||
}
|
||||
case 0x2025e:
|
||||
if (!IS_QLA82XX(ha) || vha != base_vha) {
|
||||
ql_log(ql_log_info, vha, 0x7071,
|
||||
@ -616,6 +631,29 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
|
||||
qla2xxx_wake_dpc(vha);
|
||||
qla2x00_wait_for_fcoe_ctx_reset(vha);
|
||||
break;
|
||||
case 0x2025f:
|
||||
if (!IS_QLA8031(ha))
|
||||
return -EPERM;
|
||||
ql_log(ql_log_info, vha, 0x70bc,
|
||||
"Disabling Reset by IDC control\n");
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
__qla83xx_get_idc_control(vha, &idc_control);
|
||||
idc_control |= QLA83XX_IDC_RESET_DISABLED;
|
||||
__qla83xx_set_idc_control(vha, idc_control);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
break;
|
||||
case 0x20260:
|
||||
if (!IS_QLA8031(ha))
|
||||
return -EPERM;
|
||||
ql_log(ql_log_info, vha, 0x70bd,
|
||||
"Enabling Reset by IDC control\n");
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
__qla83xx_get_idc_control(vha, &idc_control);
|
||||
idc_control &= ~QLA83XX_IDC_RESET_DISABLED;
|
||||
__qla83xx_set_idc_control(vha, idc_control);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
break;
|
||||
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -1364,7 +1364,7 @@ qla2x00_read_optrom(struct fc_bsg_job *bsg_job)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
int rval = 0;
|
||||
|
||||
if (ha->flags.isp82xx_reset_hdlr_active)
|
||||
if (ha->flags.nic_core_reset_hdlr_active)
|
||||
return -EBUSY;
|
||||
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, 0);
|
||||
|
@ -11,18 +11,18 @@
|
||||
* ----------------------------------------------------------------------
|
||||
* | Level | Last Value Used | Holes |
|
||||
* ----------------------------------------------------------------------
|
||||
* | Module Init and Probe | 0x0123 | 0x4b,0xba,0xfa |
|
||||
* | Mailbox commands | 0x1140 | 0x111a-0x111b |
|
||||
* | Module Init and Probe | 0x0124 | 0x4b,0xba,0xfa |
|
||||
* | Mailbox commands | 0x114c | 0x111a-0x111b |
|
||||
* | | | 0x112c-0x112e |
|
||||
* | | | 0x113a |
|
||||
* | Device Discovery | 0x2087 | 0x2020-0x2022 |
|
||||
* | Queue Command and IO tracing | 0x3030 | 0x3006,0x3008 |
|
||||
* | | | 0x302d-0x302e |
|
||||
* | DPC Thread | 0x401c | 0x4002,0x4013 |
|
||||
* | Async Events | 0x505f | 0x502b-0x502f |
|
||||
* | Async Events | 0x506c | 0x502b-0x502f |
|
||||
* | | | 0x5047,0x5052 |
|
||||
* | Timer Routines | 0x6011 | |
|
||||
* | User Space Interactions | 0x70bb | 0x7018,0x702e, |
|
||||
* | User Space Interactions | 0x70bd | 0x7018,0x702e, |
|
||||
* | | | 0x7039,0x7045, |
|
||||
* | | | 0x7073-0x7075, |
|
||||
* | | | 0x708c, |
|
||||
@ -33,7 +33,7 @@
|
||||
* | | | 0x800b,0x8039 |
|
||||
* | AER/EEH | 0x9011 | |
|
||||
* | Virtual Port | 0xa007 | |
|
||||
* | ISP82XX Specific | 0xb055 | 0xb024 |
|
||||
* | ISP82XX Specific | 0xb080 | 0xb024 |
|
||||
* | MultiQ | 0xc00c | |
|
||||
* | Misc | 0xd010 | |
|
||||
* | Target Mode | 0xe06f | |
|
||||
|
@ -114,6 +114,82 @@
|
||||
#define WRT_REG_WORD(addr, data) writew(data,addr)
|
||||
#define WRT_REG_DWORD(addr, data) writel(data,addr)
|
||||
|
||||
/*
|
||||
* ISP83XX specific remote register addresses
|
||||
*/
|
||||
#define QLA83XX_LED_PORT0 0x00201320
|
||||
#define QLA83XX_LED_PORT1 0x00201328
|
||||
#define QLA83XX_IDC_DEV_STATE 0x22102384
|
||||
#define QLA83XX_IDC_MAJOR_VERSION 0x22102380
|
||||
#define QLA83XX_IDC_MINOR_VERSION 0x22102398
|
||||
#define QLA83XX_IDC_DRV_PRESENCE 0x22102388
|
||||
#define QLA83XX_IDC_DRIVER_ACK 0x2210238c
|
||||
#define QLA83XX_IDC_CONTROL 0x22102390
|
||||
#define QLA83XX_IDC_AUDIT 0x22102394
|
||||
#define QLA83XX_IDC_LOCK_RECOVERY 0x2210239c
|
||||
#define QLA83XX_DRIVER_LOCKID 0x22102104
|
||||
#define QLA83XX_DRIVER_LOCK 0x8111c028
|
||||
#define QLA83XX_DRIVER_UNLOCK 0x8111c02c
|
||||
#define QLA83XX_FLASH_LOCKID 0x22102100
|
||||
#define QLA83XX_FLASH_LOCK 0x8111c010
|
||||
#define QLA83XX_FLASH_UNLOCK 0x8111c014
|
||||
#define QLA83XX_DEV_PARTINFO1 0x221023e0
|
||||
#define QLA83XX_DEV_PARTINFO2 0x221023e4
|
||||
#define QLA83XX_FW_HEARTBEAT 0x221020b0
|
||||
#define QLA83XX_PEG_HALT_STATUS1 0x221020a8
|
||||
#define QLA83XX_PEG_HALT_STATUS2 0x221020ac
|
||||
|
||||
/* 83XX: Macros defining 8200 AEN Reason codes */
|
||||
#define IDC_DEVICE_STATE_CHANGE BIT_0
|
||||
#define IDC_PEG_HALT_STATUS_CHANGE BIT_1
|
||||
#define IDC_NIC_FW_REPORTED_FAILURE BIT_2
|
||||
#define IDC_HEARTBEAT_FAILURE BIT_3
|
||||
|
||||
/* 83XX: Macros defining 8200 AEN Error-levels */
|
||||
#define ERR_LEVEL_NON_FATAL 0x1
|
||||
#define ERR_LEVEL_RECOVERABLE_FATAL 0x2
|
||||
#define ERR_LEVEL_UNRECOVERABLE_FATAL 0x4
|
||||
|
||||
/* 83XX: Macros for IDC Version */
|
||||
#define QLA83XX_SUPP_IDC_MAJOR_VERSION 0x01
|
||||
#define QLA83XX_SUPP_IDC_MINOR_VERSION 0x0
|
||||
|
||||
/* 83XX: Macros for scheduling dpc tasks */
|
||||
#define QLA83XX_NIC_CORE_RESET 0x1
|
||||
#define QLA83XX_IDC_STATE_HANDLER 0x2
|
||||
#define QLA83XX_NIC_CORE_UNRECOVERABLE 0x3
|
||||
|
||||
/* 83XX: Macros for defining IDC-Control bits */
|
||||
#define QLA83XX_IDC_RESET_DISABLED BIT_0
|
||||
#define QLA83XX_IDC_GRACEFUL_RESET BIT_1
|
||||
|
||||
/* 83XX: Macros for different timeouts */
|
||||
#define QLA83XX_IDC_INITIALIZATION_TIMEOUT 30
|
||||
#define QLA83XX_IDC_RESET_ACK_TIMEOUT 10
|
||||
#define QLA83XX_MAX_LOCK_RECOVERY_WAIT (2 * HZ)
|
||||
|
||||
/* 83XX: Macros for defining class in DEV-Partition Info register */
|
||||
#define QLA83XX_CLASS_TYPE_NONE 0x0
|
||||
#define QLA83XX_CLASS_TYPE_NIC 0x1
|
||||
#define QLA83XX_CLASS_TYPE_FCOE 0x2
|
||||
#define QLA83XX_CLASS_TYPE_ISCSI 0x3
|
||||
|
||||
/* 83XX: Macros for IDC Lock-Recovery stages */
|
||||
#define IDC_LOCK_RECOVERY_STAGE1 0x1 /* Stage1: Intent for
|
||||
* lock-recovery
|
||||
*/
|
||||
#define IDC_LOCK_RECOVERY_STAGE2 0x2 /* Stage2: Perform lock-recovery */
|
||||
|
||||
/* 83XX: Macros for IDC Audit type */
|
||||
#define IDC_AUDIT_TIMESTAMP 0x0 /* IDC-AUDIT: Record timestamp of
|
||||
* dev-state change to NEED-RESET
|
||||
* or NEED-QUIESCENT
|
||||
*/
|
||||
#define IDC_AUDIT_COMPLETION 0x1 /* IDC-AUDIT: Record duration of
|
||||
* reset-recovery completion is
|
||||
* second
|
||||
*/
|
||||
|
||||
/*
|
||||
* The ISP2312 v2 chip cannot access the FLASH/GPIO registers via MMIO in an
|
||||
* 133Mhz slot.
|
||||
@ -596,6 +672,9 @@ typedef struct {
|
||||
#define MBA_DISCARD_RND_FRAME 0x8048 /* discard RND frame due to error. */
|
||||
#define MBA_REJECTED_FCP_CMD 0x8049 /* rejected FCP_CMD. */
|
||||
|
||||
/* 83XX FCoE specific */
|
||||
#define MBA_IDC_AEN 0x8200 /* FCoE: NIC Core state change AEN */
|
||||
|
||||
/* ISP mailbox loopback echo diagnostic error code */
|
||||
#define MBS_LB_RESET 0x17
|
||||
/*
|
||||
@ -2523,11 +2602,12 @@ struct qla_hw_data {
|
||||
uint32_t disable_msix_handshake :1;
|
||||
uint32_t fcp_prio_enabled :1;
|
||||
uint32_t isp82xx_fw_hung:1;
|
||||
uint32_t nic_core_hung:1;
|
||||
|
||||
uint32_t quiesce_owner:1;
|
||||
uint32_t thermal_supported:1;
|
||||
uint32_t isp82xx_reset_hdlr_active:1;
|
||||
uint32_t isp82xx_reset_owner:1;
|
||||
uint32_t nic_core_reset_hdlr_active:1;
|
||||
uint32_t nic_core_reset_owner:1;
|
||||
uint32_t isp82xx_no_md_cap:1;
|
||||
uint32_t host_shutting_down:1;
|
||||
/* 30 bits */
|
||||
@ -2912,8 +2992,8 @@ struct qla_hw_data {
|
||||
unsigned long mn_win_crb;
|
||||
unsigned long ms_win_crb;
|
||||
int qdr_sn_window;
|
||||
uint32_t nx_dev_init_timeout;
|
||||
uint32_t nx_reset_timeout;
|
||||
uint32_t fcoe_dev_init_timeout;
|
||||
uint32_t fcoe_reset_timeout;
|
||||
rwlock_t hw_lock;
|
||||
uint16_t portnum; /* port number */
|
||||
int link_width;
|
||||
@ -2935,6 +3015,19 @@ struct qla_hw_data {
|
||||
uint32_t md_dump_size;
|
||||
|
||||
void *loop_id_map;
|
||||
|
||||
/* QLA83XX IDC specific fields */
|
||||
uint32_t idc_audit_ts;
|
||||
|
||||
/* DPC low-priority workqueue */
|
||||
struct workqueue_struct *dpc_lp_wq;
|
||||
struct work_struct idc_aen;
|
||||
/* DPC high-priority workqueue */
|
||||
struct workqueue_struct *dpc_hp_wq;
|
||||
struct work_struct nic_core_reset;
|
||||
struct work_struct idc_state_handler;
|
||||
struct work_struct nic_core_unrecoverable;
|
||||
|
||||
struct qlt_hw_data tgt;
|
||||
};
|
||||
|
||||
|
@ -1540,7 +1540,10 @@ struct access_chip_rsp_84xx {
|
||||
/*
|
||||
* ISP83xx mailbox commands
|
||||
*/
|
||||
#define MBC_WRITE_REMOTE_REG 0x0001 /* Write remote register */
|
||||
#define MBC_WRITE_REMOTE_REG 0x0001 /* Write remote register */
|
||||
#define MBC_READ_REMOTE_REG 0x0009 /* Read remote register */
|
||||
#define MBC_RESTART_NIC_FIRMWARE 0x003d /* Restart NIC firmware */
|
||||
#define MBC_SET_ACCESS_CONTROL 0x003e /* Access control command */
|
||||
|
||||
/* Flash access control option field bit definitions */
|
||||
#define FAC_OPT_FORCE_SEMAPHORE BIT_15
|
||||
|
@ -76,6 +76,13 @@ extern int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *, fc_port_t *);
|
||||
|
||||
extern fc_port_t *
|
||||
qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
|
||||
|
||||
extern int __qla83xx_set_idc_control(scsi_qla_host_t *, uint32_t);
|
||||
extern int __qla83xx_get_idc_control(scsi_qla_host_t *, uint32_t *);
|
||||
extern void qla83xx_idc_audit(scsi_qla_host_t *, int);
|
||||
extern int qla83xx_nic_core_reset(scsi_qla_host_t *);
|
||||
extern void qla83xx_reset_ownership(scsi_qla_host_t *);
|
||||
|
||||
/*
|
||||
* Global Data in qla_os.c source file.
|
||||
*/
|
||||
@ -133,6 +140,20 @@ extern void qla2x00_relogin(struct scsi_qla_host *);
|
||||
extern void qla2x00_do_work(struct scsi_qla_host *);
|
||||
extern void qla2x00_free_fcports(struct scsi_qla_host *);
|
||||
|
||||
extern void qla83xx_schedule_work(scsi_qla_host_t *, int);
|
||||
extern void qla83xx_service_idc_aen(struct work_struct *);
|
||||
extern void qla83xx_nic_core_unrecoverable_work(struct work_struct *);
|
||||
extern void qla83xx_idc_state_handler_work(struct work_struct *);
|
||||
extern void qla83xx_nic_core_reset_work(struct work_struct *);
|
||||
|
||||
extern void qla83xx_idc_lock(scsi_qla_host_t *, uint16_t);
|
||||
extern void qla83xx_idc_unlock(scsi_qla_host_t *, uint16_t);
|
||||
extern int qla83xx_idc_state_handler(scsi_qla_host_t *);
|
||||
extern int qla83xx_set_drv_presence(scsi_qla_host_t *vha);
|
||||
extern int __qla83xx_set_drv_presence(scsi_qla_host_t *vha);
|
||||
extern int qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
|
||||
extern int __qla83xx_clear_drv_presence(scsi_qla_host_t *vha);
|
||||
|
||||
/*
|
||||
* Global Functions in qla_mid.c source file.
|
||||
*/
|
||||
@ -421,7 +442,11 @@ extern void qla24xx_beacon_blink(struct scsi_qla_host *);
|
||||
extern void qla83xx_beacon_blink(struct scsi_qla_host *);
|
||||
extern int qla82xx_beacon_on(struct scsi_qla_host *);
|
||||
extern int qla82xx_beacon_off(struct scsi_qla_host *);
|
||||
extern int qla83xx_write_remote_reg(struct scsi_qla_host *, uint32_t, uint32_t);
|
||||
extern int qla83xx_wr_reg(scsi_qla_host_t *, uint32_t, uint32_t);
|
||||
extern int qla83xx_rd_reg(scsi_qla_host_t *, uint32_t, uint32_t *);
|
||||
extern int qla83xx_restart_nic_firmware(scsi_qla_host_t *);
|
||||
extern int qla83xx_access_control(scsi_qla_host_t *, uint16_t, uint32_t,
|
||||
uint32_t, uint16_t *);
|
||||
|
||||
extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *,
|
||||
uint32_t, uint32_t);
|
||||
@ -582,6 +607,7 @@ extern uint32_t qla82xx_wait_for_state_change(scsi_qla_host_t *, uint32_t);
|
||||
extern int qla82xx_idc_lock(struct qla_hw_data *);
|
||||
extern void qla82xx_idc_unlock(struct qla_hw_data *);
|
||||
extern int qla82xx_device_state_handler(scsi_qla_host_t *);
|
||||
extern void qla8xxx_dev_failed_handler(scsi_qla_host_t *);
|
||||
extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *);
|
||||
|
||||
extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *,
|
||||
|
@ -429,6 +429,71 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
|
||||
/* QLogic ISP2x00 Hardware Support Functions. */
|
||||
/****************************************************************************/
|
||||
|
||||
int
|
||||
qla83xx_nic_core_fw_load(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t idc_major_ver, idc_minor_ver;
|
||||
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
|
||||
/* SV: TODO: Assign initialization timeout from
|
||||
* flash-info / other param
|
||||
*/
|
||||
ha->fcoe_dev_init_timeout = QLA83XX_IDC_INITIALIZATION_TIMEOUT;
|
||||
ha->fcoe_reset_timeout = QLA83XX_IDC_RESET_ACK_TIMEOUT;
|
||||
|
||||
/* Set our fcoe function presence */
|
||||
if (__qla83xx_set_drv_presence(vha) != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb077,
|
||||
"Error while setting DRV-Presence.\n");
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Decide the reset ownership */
|
||||
qla83xx_reset_ownership(vha);
|
||||
|
||||
/*
|
||||
* On first protocol driver load:
|
||||
* Init-Owner: Set IDC-Major-Version and Clear IDC-Lock-Recovery
|
||||
* register.
|
||||
* Others: Check compatibility with current IDC Major version.
|
||||
*/
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_MAJOR_VERSION, &idc_major_ver);
|
||||
if (ha->flags.nic_core_reset_owner) {
|
||||
/* Set IDC Major version */
|
||||
idc_major_ver = QLA83XX_SUPP_IDC_MAJOR_VERSION;
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_MAJOR_VERSION, idc_major_ver);
|
||||
|
||||
/* Clearing IDC-Lock-Recovery register */
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_LOCK_RECOVERY, 0);
|
||||
} else if (idc_major_ver != QLA83XX_SUPP_IDC_MAJOR_VERSION) {
|
||||
/*
|
||||
* Clear further IDC participation if we are not compatible with
|
||||
* the current IDC Major Version.
|
||||
*/
|
||||
ql_log(ql_log_warn, vha, 0xb07d,
|
||||
"Failing load, idc_major_ver=%d, expected_major_ver=%d.\n",
|
||||
idc_major_ver, QLA83XX_SUPP_IDC_MAJOR_VERSION);
|
||||
__qla83xx_clear_drv_presence(vha);
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
/* Each function sets its supported Minor version. */
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_MINOR_VERSION, &idc_minor_ver);
|
||||
idc_minor_ver |= (QLA83XX_SUPP_IDC_MINOR_VERSION << (ha->portnum * 2));
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_MINOR_VERSION, idc_minor_ver);
|
||||
|
||||
rval = qla83xx_idc_state_handler(vha);
|
||||
|
||||
exit:
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* qla2x00_initialize_adapter
|
||||
* Initialize board.
|
||||
@ -537,6 +602,14 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
|
||||
}
|
||||
}
|
||||
|
||||
/* Load the NIC Core f/w if we are the first protocol driver. */
|
||||
if (IS_QLA8031(ha)) {
|
||||
rval = qla83xx_nic_core_fw_load(vha);
|
||||
if (rval)
|
||||
ql_log(ql_log_warn, vha, 0x0124,
|
||||
"Error in initializing NIC Core f/w.\n");
|
||||
}
|
||||
|
||||
if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
|
||||
qla24xx_read_fcp_prio_cfg(vha);
|
||||
|
||||
@ -3736,6 +3809,307 @@ qla2x00_update_fcports(scsi_qla_host_t *base_vha)
|
||||
spin_unlock_irqrestore(&ha->vport_slock, flags);
|
||||
}
|
||||
|
||||
/* Assumes idc_lock always held on entry */
|
||||
void
|
||||
qla83xx_reset_ownership(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t drv_presence, drv_presence_mask;
|
||||
uint32_t dev_part_info1, dev_part_info2, class_type;
|
||||
uint32_t class_type_mask = 0x3;
|
||||
uint16_t fcoe_other_function = 0xffff, i;
|
||||
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
|
||||
|
||||
qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO1, &dev_part_info1);
|
||||
qla83xx_rd_reg(vha, QLA83XX_DEV_PARTINFO2, &dev_part_info2);
|
||||
for (i = 0; i < 8; i++) {
|
||||
class_type = ((dev_part_info1 >> (i * 4)) & class_type_mask);
|
||||
if ((class_type == QLA83XX_CLASS_TYPE_FCOE) &&
|
||||
(i != ha->portnum)) {
|
||||
fcoe_other_function = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (fcoe_other_function == 0xffff) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
class_type = ((dev_part_info2 >> (i * 4)) &
|
||||
class_type_mask);
|
||||
if ((class_type == QLA83XX_CLASS_TYPE_FCOE) &&
|
||||
((i + 8) != ha->portnum)) {
|
||||
fcoe_other_function = i + 8;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Prepare drv-presence mask based on fcoe functions present.
|
||||
* However consider only valid physical fcoe function numbers (0-15).
|
||||
*/
|
||||
drv_presence_mask = ~((1 << (ha->portnum)) |
|
||||
((fcoe_other_function == 0xffff) ?
|
||||
0 : (1 << (fcoe_other_function))));
|
||||
|
||||
/* We are the reset owner iff:
|
||||
* - No other protocol drivers present.
|
||||
* - This is the lowest among fcoe functions. */
|
||||
if (!(drv_presence & drv_presence_mask) &&
|
||||
(ha->portnum < fcoe_other_function)) {
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb07f,
|
||||
"This host is Reset owner.\n");
|
||||
ha->flags.nic_core_reset_owner = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
__qla83xx_set_drv_ack(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t drv_ack;
|
||||
|
||||
rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRIVER_ACK, &drv_ack);
|
||||
if (rval == QLA_SUCCESS) {
|
||||
drv_ack |= (1 << ha->portnum);
|
||||
rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRIVER_ACK, drv_ack);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_set_drv_ack(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
rval = __qla83xx_set_drv_ack(vha);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
__qla83xx_clear_drv_ack(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t drv_ack;
|
||||
|
||||
rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRIVER_ACK, &drv_ack);
|
||||
if (rval == QLA_SUCCESS) {
|
||||
drv_ack &= ~(1 << ha->portnum);
|
||||
rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRIVER_ACK, drv_ack);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_clear_drv_ack(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
rval = __qla83xx_clear_drv_ack(vha);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
const char *
|
||||
qla83xx_dev_state_to_string(uint32_t dev_state)
|
||||
{
|
||||
switch (dev_state) {
|
||||
case QLA8XXX_DEV_COLD:
|
||||
return "COLD/RE-INIT";
|
||||
case QLA8XXX_DEV_INITIALIZING:
|
||||
return "INITIALIZING";
|
||||
case QLA8XXX_DEV_READY:
|
||||
return "READY";
|
||||
case QLA8XXX_DEV_NEED_RESET:
|
||||
return "NEED RESET";
|
||||
case QLA8XXX_DEV_NEED_QUIESCENT:
|
||||
return "NEED QUIESCENT";
|
||||
case QLA8XXX_DEV_FAILED:
|
||||
return "FAILED";
|
||||
case QLA8XXX_DEV_QUIESCENT:
|
||||
return "QUIESCENT";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* Assumes idc-lock always held on entry */
|
||||
void
|
||||
qla83xx_idc_audit(scsi_qla_host_t *vha, int audit_type)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t idc_audit_reg = 0, duration_secs = 0;
|
||||
|
||||
switch (audit_type) {
|
||||
case IDC_AUDIT_TIMESTAMP:
|
||||
ha->idc_audit_ts = (jiffies_to_msecs(jiffies) / 1000);
|
||||
idc_audit_reg = (ha->portnum) |
|
||||
(IDC_AUDIT_TIMESTAMP << 7) | (ha->idc_audit_ts << 8);
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_AUDIT, idc_audit_reg);
|
||||
break;
|
||||
|
||||
case IDC_AUDIT_COMPLETION:
|
||||
duration_secs = ((jiffies_to_msecs(jiffies) -
|
||||
jiffies_to_msecs(ha->idc_audit_ts)) / 1000);
|
||||
idc_audit_reg = (ha->portnum) |
|
||||
(IDC_AUDIT_COMPLETION << 7) | (duration_secs << 8);
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_AUDIT, idc_audit_reg);
|
||||
break;
|
||||
|
||||
default:
|
||||
ql_log(ql_log_warn, vha, 0xb078,
|
||||
"Invalid audit type specified.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Assumes idc_lock always held on entry */
|
||||
int
|
||||
qla83xx_initiating_reset(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t idc_control, dev_state;
|
||||
|
||||
__qla83xx_get_idc_control(vha, &idc_control);
|
||||
if ((idc_control & QLA83XX_IDC_RESET_DISABLED)) {
|
||||
ql_log(ql_log_info, vha, 0xb080,
|
||||
"NIC Core reset has been disabled. idc-control=0x%x\n",
|
||||
idc_control);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
/* Set NEED-RESET iff in READY state and we are the reset-owner */
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_DEV_STATE, &dev_state);
|
||||
if (ha->flags.nic_core_reset_owner && dev_state == QLA8XXX_DEV_READY) {
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE,
|
||||
QLA8XXX_DEV_NEED_RESET);
|
||||
ql_log(ql_log_info, vha, 0xb056, "HW State: NEED RESET.\n");
|
||||
qla83xx_idc_audit(vha, IDC_AUDIT_TIMESTAMP);
|
||||
} else {
|
||||
const char *state = qla83xx_dev_state_to_string(dev_state);
|
||||
ql_log(ql_log_info, vha, 0xb057, "HW State: %s.\n", state);
|
||||
|
||||
/* SV: XXX: Is timeout required here? */
|
||||
/* Wait for IDC state change READY -> NEED_RESET */
|
||||
while (dev_state == QLA8XXX_DEV_READY) {
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
msleep(200);
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_DEV_STATE, &dev_state);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send IDC ack by writing to drv-ack register */
|
||||
__qla83xx_set_drv_ack(vha);
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
__qla83xx_set_idc_control(scsi_qla_host_t *vha, uint32_t idc_control)
|
||||
{
|
||||
return qla83xx_wr_reg(vha, QLA83XX_IDC_CONTROL, idc_control);
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_set_idc_control(scsi_qla_host_t *vha, uint32_t idc_control)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
rval = __qla83xx_set_idc_control(vha, idc_control);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
__qla83xx_get_idc_control(scsi_qla_host_t *vha, uint32_t *idc_control)
|
||||
{
|
||||
return qla83xx_rd_reg(vha, QLA83XX_IDC_CONTROL, idc_control);
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_get_idc_control(scsi_qla_host_t *vha, uint32_t *idc_control)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
rval = __qla83xx_get_idc_control(vha, idc_control);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_check_driver_presence(scsi_qla_host_t *vha)
|
||||
{
|
||||
uint32_t drv_presence = 0;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
|
||||
if (drv_presence & (1 << ha->portnum))
|
||||
return QLA_SUCCESS;
|
||||
else
|
||||
return QLA_TEST_FAILED;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_nic_core_reset(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb058,
|
||||
"Entered %s().\n", __func__);
|
||||
|
||||
if (vha->device_flags & DFLG_DEV_FAILED) {
|
||||
ql_log(ql_log_warn, vha, 0xb059,
|
||||
"Device in unrecoverable FAILED state.\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
|
||||
if (qla83xx_check_driver_presence(vha) != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0xb05a,
|
||||
"Function=0x%x has been removed from IDC participation.\n",
|
||||
ha->portnum);
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
qla83xx_reset_ownership(vha);
|
||||
|
||||
rval = qla83xx_initiating_reset(vha);
|
||||
|
||||
/*
|
||||
* Perform reset if we are the reset-owner,
|
||||
* else wait till IDC state changes to READY/FAILED.
|
||||
*/
|
||||
if (rval == QLA_SUCCESS) {
|
||||
rval = qla83xx_idc_state_handler(vha);
|
||||
|
||||
if (rval == QLA_SUCCESS)
|
||||
ha->flags.nic_core_hung = 0;
|
||||
__qla83xx_clear_drv_ack(vha);
|
||||
}
|
||||
|
||||
exit:
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb05b, "Exiting %s.\n", __func__);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* qla82xx_quiescent_state_cleanup
|
||||
* Description: This function will block the new I/Os
|
||||
@ -3871,6 +4245,14 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
|
||||
struct req_que *req = ha->req_q_map[0];
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_QLA8031(ha)) {
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb05c,
|
||||
"Clearing fcoe driver presence.\n");
|
||||
if (qla83xx_clear_drv_presence(vha) != QLA_SUCCESS)
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb073,
|
||||
"Erro while clearing DRV-Presence.\n");
|
||||
}
|
||||
|
||||
if (vha->flags.online) {
|
||||
qla2x00_abort_isp_cleanup(vha);
|
||||
|
||||
@ -3982,6 +4364,13 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
|
||||
}
|
||||
spin_unlock_irqrestore(&ha->vport_slock, flags);
|
||||
|
||||
if (IS_QLA8031(ha)) {
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb05d,
|
||||
"Setting back fcoe driver presence.\n");
|
||||
if (qla83xx_set_drv_presence(vha) != QLA_SUCCESS)
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb074,
|
||||
"Error while setting DRV-Presence.\n");
|
||||
}
|
||||
} else {
|
||||
ql_log(ql_log_warn, vha, 0x8023, "%s **** FAILED ****.\n",
|
||||
__func__);
|
||||
|
@ -332,6 +332,166 @@ qla2x00_get_link_speed_str(struct qla_hw_data *ha)
|
||||
return link_speed;
|
||||
}
|
||||
|
||||
void
|
||||
qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
/*
|
||||
* 8200 AEN Interpretation:
|
||||
* mb[0] = AEN code
|
||||
* mb[1] = AEN Reason code
|
||||
* mb[2] = LSW of Peg-Halt Status-1 Register
|
||||
* mb[6] = MSW of Peg-Halt Status-1 Register
|
||||
* mb[3] = LSW of Peg-Halt Status-2 register
|
||||
* mb[7] = MSW of Peg-Halt Status-2 register
|
||||
* mb[4] = IDC Device-State Register value
|
||||
* mb[5] = IDC Driver-Presence Register value
|
||||
*/
|
||||
ql_dbg(ql_dbg_async, vha, 0x506b, "AEN Code: mb[0] = 0x%x AEN reason: "
|
||||
"mb[1] = 0x%x PH-status1: mb[2] = 0x%x PH-status1: mb[6] = 0x%x.\n",
|
||||
mb[0], mb[1], mb[2], mb[6]);
|
||||
ql_dbg(ql_dbg_async, vha, 0x506c, "PH-status2: mb[3] = 0x%x "
|
||||
"PH-status2: mb[7] = 0x%x Device-State: mb[4] = 0x%x "
|
||||
"Drv-Presence: mb[5] = 0x%x.\n", mb[3], mb[7], mb[4], mb[5]);
|
||||
|
||||
if (mb[1] & (IDC_PEG_HALT_STATUS_CHANGE | IDC_NIC_FW_REPORTED_FAILURE |
|
||||
IDC_HEARTBEAT_FAILURE)) {
|
||||
ha->flags.nic_core_hung = 1;
|
||||
ql_log(ql_log_warn, vha, 0x5060,
|
||||
"83XX: F/W Error Reported: Check if reset required.\n");
|
||||
|
||||
if (mb[1] & IDC_PEG_HALT_STATUS_CHANGE) {
|
||||
uint32_t protocol_engine_id, fw_err_code, err_level;
|
||||
|
||||
/*
|
||||
* IDC_PEG_HALT_STATUS_CHANGE interpretation:
|
||||
* - PEG-Halt Status-1 Register:
|
||||
* (LSW = mb[2], MSW = mb[6])
|
||||
* Bits 0-7 = protocol-engine ID
|
||||
* Bits 8-28 = f/w error code
|
||||
* Bits 29-31 = Error-level
|
||||
* Error-level 0x1 = Non-Fatal error
|
||||
* Error-level 0x2 = Recoverable Fatal error
|
||||
* Error-level 0x4 = UnRecoverable Fatal error
|
||||
* - PEG-Halt Status-2 Register:
|
||||
* (LSW = mb[3], MSW = mb[7])
|
||||
*/
|
||||
protocol_engine_id = (mb[2] & 0xff);
|
||||
fw_err_code = (((mb[2] & 0xff00) >> 8) |
|
||||
((mb[6] & 0x1fff) << 8));
|
||||
err_level = ((mb[6] & 0xe000) >> 13);
|
||||
ql_log(ql_log_warn, vha, 0x5061, "PegHalt Status-1 "
|
||||
"Register: protocol_engine_id=0x%x "
|
||||
"fw_err_code=0x%x err_level=0x%x.\n",
|
||||
protocol_engine_id, fw_err_code, err_level);
|
||||
ql_log(ql_log_warn, vha, 0x5062, "PegHalt Status-2 "
|
||||
"Register: 0x%x%x.\n", mb[7], mb[3]);
|
||||
if (err_level == ERR_LEVEL_NON_FATAL) {
|
||||
ql_log(ql_log_warn, vha, 0x5063,
|
||||
"Not a fatal error, f/w has recovered "
|
||||
"iteself.\n");
|
||||
} else if (err_level == ERR_LEVEL_RECOVERABLE_FATAL) {
|
||||
ql_log(ql_log_fatal, vha, 0x5064,
|
||||
"Recoverable Fatal error: Chip reset "
|
||||
"required.\n");
|
||||
qla83xx_schedule_work(vha,
|
||||
QLA83XX_NIC_CORE_RESET);
|
||||
} else if (err_level == ERR_LEVEL_UNRECOVERABLE_FATAL) {
|
||||
ql_log(ql_log_fatal, vha, 0x5065,
|
||||
"Unrecoverable Fatal error: Set FAILED "
|
||||
"state, reboot required.\n");
|
||||
qla83xx_schedule_work(vha,
|
||||
QLA83XX_NIC_CORE_UNRECOVERABLE);
|
||||
}
|
||||
}
|
||||
|
||||
if (mb[1] & IDC_NIC_FW_REPORTED_FAILURE) {
|
||||
uint16_t peg_fw_state, nw_interface_link_up;
|
||||
uint16_t nw_interface_signal_detect, sfp_status;
|
||||
uint16_t htbt_counter, htbt_monitor_enable;
|
||||
uint16_t sfp_additonal_info, sfp_multirate;
|
||||
uint16_t sfp_tx_fault, link_speed, dcbx_status;
|
||||
|
||||
/*
|
||||
* IDC_NIC_FW_REPORTED_FAILURE interpretation:
|
||||
* - PEG-to-FC Status Register:
|
||||
* (LSW = mb[2], MSW = mb[6])
|
||||
* Bits 0-7 = Peg-Firmware state
|
||||
* Bit 8 = N/W Interface Link-up
|
||||
* Bit 9 = N/W Interface signal detected
|
||||
* Bits 10-11 = SFP Status
|
||||
* SFP Status 0x0 = SFP+ transceiver not expected
|
||||
* SFP Status 0x1 = SFP+ transceiver not present
|
||||
* SFP Status 0x2 = SFP+ transceiver invalid
|
||||
* SFP Status 0x3 = SFP+ transceiver present and
|
||||
* valid
|
||||
* Bits 12-14 = Heartbeat Counter
|
||||
* Bit 15 = Heartbeat Monitor Enable
|
||||
* Bits 16-17 = SFP Additional Info
|
||||
* SFP info 0x0 = Unregocnized transceiver for
|
||||
* Ethernet
|
||||
* SFP info 0x1 = SFP+ brand validation failed
|
||||
* SFP info 0x2 = SFP+ speed validation failed
|
||||
* SFP info 0x3 = SFP+ access error
|
||||
* Bit 18 = SFP Multirate
|
||||
* Bit 19 = SFP Tx Fault
|
||||
* Bits 20-22 = Link Speed
|
||||
* Bits 23-27 = Reserved
|
||||
* Bits 28-30 = DCBX Status
|
||||
* DCBX Status 0x0 = DCBX Disabled
|
||||
* DCBX Status 0x1 = DCBX Enabled
|
||||
* DCBX Status 0x2 = DCBX Exchange error
|
||||
* Bit 31 = Reserved
|
||||
*/
|
||||
peg_fw_state = (mb[2] & 0x00ff);
|
||||
nw_interface_link_up = ((mb[2] & 0x0100) >> 8);
|
||||
nw_interface_signal_detect = ((mb[2] & 0x0200) >> 9);
|
||||
sfp_status = ((mb[2] & 0x0c00) >> 10);
|
||||
htbt_counter = ((mb[2] & 0x7000) >> 12);
|
||||
htbt_monitor_enable = ((mb[2] & 0x8000) >> 15);
|
||||
sfp_additonal_info = (mb[6] & 0x0003);
|
||||
sfp_multirate = ((mb[6] & 0x0004) >> 2);
|
||||
sfp_tx_fault = ((mb[6] & 0x0008) >> 3);
|
||||
link_speed = ((mb[6] & 0x0070) >> 4);
|
||||
dcbx_status = ((mb[6] & 0x7000) >> 12);
|
||||
|
||||
ql_log(ql_log_warn, vha, 0x5066,
|
||||
"Peg-to-Fc Status Register:\n"
|
||||
"peg_fw_state=0x%x, nw_interface_link_up=0x%x, "
|
||||
"nw_interface_signal_detect=0x%x"
|
||||
"\nsfp_statis=0x%x.\n ", peg_fw_state,
|
||||
nw_interface_link_up, nw_interface_signal_detect,
|
||||
sfp_status);
|
||||
ql_log(ql_log_warn, vha, 0x5067,
|
||||
"htbt_counter=0x%x, htbt_monitor_enable=0x%x, "
|
||||
"sfp_additonal_info=0x%x, sfp_multirate=0x%x.\n ",
|
||||
htbt_counter, htbt_monitor_enable,
|
||||
sfp_additonal_info, sfp_multirate);
|
||||
ql_log(ql_log_warn, vha, 0x5068,
|
||||
"sfp_tx_fault=0x%x, link_state=0x%x, "
|
||||
"dcbx_status=0x%x.\n", sfp_tx_fault, link_speed,
|
||||
dcbx_status);
|
||||
|
||||
qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
|
||||
}
|
||||
|
||||
if (mb[1] & IDC_HEARTBEAT_FAILURE) {
|
||||
ql_log(ql_log_warn, vha, 0x5069,
|
||||
"Heartbeat Failure encountered, chip reset "
|
||||
"required.\n");
|
||||
|
||||
qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
|
||||
}
|
||||
}
|
||||
|
||||
if (mb[1] & IDC_DEVICE_STATE_CHANGE) {
|
||||
ql_log(ql_log_info, vha, 0x506a,
|
||||
"IDC Device-State changed = 0x%x.\n", mb[4]);
|
||||
qla83xx_schedule_work(vha, MBA_IDC_AEN);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qla2x00_async_event() - Process aynchronous events.
|
||||
* @ha: SCSI driver HA context
|
||||
@ -825,8 +985,18 @@ skip_rio:
|
||||
case MBA_IDC_COMPLETE:
|
||||
case MBA_IDC_NOTIFY:
|
||||
case MBA_IDC_TIME_EXT:
|
||||
qla81xx_idc_event(vha, mb[0], mb[1]);
|
||||
if (IS_QLA81XX(vha->hw))
|
||||
qla81xx_idc_event(vha, mb[0], mb[1]);
|
||||
break;
|
||||
|
||||
case MBA_IDC_AEN:
|
||||
mb[4] = RD_REG_WORD(®24->mailbox4);
|
||||
mb[5] = RD_REG_WORD(®24->mailbox5);
|
||||
mb[6] = RD_REG_WORD(®24->mailbox6);
|
||||
mb[7] = RD_REG_WORD(®24->mailbox7);
|
||||
qla83xx_handle_8200_aen(vha, mb);
|
||||
break;
|
||||
|
||||
default:
|
||||
ql_dbg(ql_dbg_async, vha, 0x5057,
|
||||
"Unknown AEN:%04x %04x %04x %04x\n",
|
||||
@ -2301,7 +2471,7 @@ qla24xx_intr_handler(int irq, void *dev_id)
|
||||
unsigned long iter;
|
||||
uint32_t stat;
|
||||
uint32_t hccr;
|
||||
uint16_t mb[4];
|
||||
uint16_t mb[8];
|
||||
struct rsp_que *rsp;
|
||||
unsigned long flags;
|
||||
|
||||
@ -2457,7 +2627,7 @@ qla24xx_msix_default(int irq, void *dev_id)
|
||||
int status;
|
||||
uint32_t stat;
|
||||
uint32_t hccr;
|
||||
uint16_t mb[4];
|
||||
uint16_t mb[8];
|
||||
unsigned long flags;
|
||||
|
||||
rsp = (struct rsp_que *) dev_id;
|
||||
|
@ -75,7 +75,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
return QLA_FUNCTION_TIMEOUT;
|
||||
}
|
||||
|
||||
if (ha->flags.isp82xx_fw_hung) {
|
||||
if (IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung) {
|
||||
/* Setting Link-Down error */
|
||||
mcp->mb[0] = MBS_LINK_DOWN_ERROR;
|
||||
ql_log(ql_log_warn, vha, 0x1004,
|
||||
@ -232,7 +232,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
ha->flags.mbox_int = 0;
|
||||
clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
|
||||
|
||||
if (ha->flags.isp82xx_fw_hung) {
|
||||
if ((IS_QLA82XX(ha) && ha->flags.isp82xx_fw_hung)) {
|
||||
ha->flags.mbox_busy = 0;
|
||||
/* Setting Link-Down error */
|
||||
mcp->mb[0] = MBS_LINK_DOWN_ERROR;
|
||||
@ -4741,7 +4741,7 @@ qla82xx_mbx_beacon_ctl(scsi_qla_host_t *vha, int enable)
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_write_remote_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data)
|
||||
qla83xx_wr_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data)
|
||||
{
|
||||
int rval;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
@ -4814,3 +4814,139 @@ qla2x00_port_logout(scsi_qla_host_t *vha, struct fc_port *fcport)
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_rd_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t *data)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
unsigned long retry_max_time = jiffies + (2 * HZ);
|
||||
|
||||
if (!IS_QLA83XX(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x114b, "Entered %s.\n", __func__);
|
||||
|
||||
retry_rd_reg:
|
||||
mcp->mb[0] = MBC_READ_REMOTE_REG;
|
||||
mcp->mb[1] = LSW(reg);
|
||||
mcp->mb[2] = MSW(reg);
|
||||
mcp->out_mb = MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_4|MBX_3|MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x114c,
|
||||
"Failed=%x mb[0]=%x mb[1]=%x.\n",
|
||||
rval, mcp->mb[0], mcp->mb[1]);
|
||||
} else {
|
||||
*data = (mcp->mb[3] | (mcp->mb[4] << 16));
|
||||
if (*data == QLA8XXX_BAD_VALUE) {
|
||||
/*
|
||||
* During soft-reset CAMRAM register reads might
|
||||
* return 0xbad0bad0. So retry for MAX of 2 sec
|
||||
* while reading camram registers.
|
||||
*/
|
||||
if (time_after(jiffies, retry_max_time)) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1141,
|
||||
"Failure to read CAMRAM register. "
|
||||
"data=0x%x.\n", *data);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
msleep(100);
|
||||
goto retry_rd_reg;
|
||||
}
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1142, "Done %s.\n", __func__);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_restart_nic_firmware(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA83XX(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1143, "Entered %s.\n", __func__);
|
||||
|
||||
mcp->mb[0] = MBC_RESTART_NIC_FIRMWARE;
|
||||
mcp->out_mb = MBX_0;
|
||||
mcp->in_mb = MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1144,
|
||||
"Failed=%x mb[0]=%x mb[1]=%x.\n",
|
||||
rval, mcp->mb[0], mcp->mb[1]);
|
||||
ha->isp_ops->fw_dump(vha, 0);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1145, "Done %s.\n", __func__);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_access_control(scsi_qla_host_t *vha, uint16_t options,
|
||||
uint32_t start_addr, uint32_t end_addr, uint16_t *sector_size)
|
||||
{
|
||||
int rval;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
uint8_t subcode = (uint8_t)options;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA8031(ha))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1146, "Entered %s.\n", __func__);
|
||||
|
||||
mcp->mb[0] = MBC_SET_ACCESS_CONTROL;
|
||||
mcp->mb[1] = options;
|
||||
mcp->out_mb = MBX_1|MBX_0;
|
||||
if (subcode & BIT_2) {
|
||||
mcp->mb[2] = LSW(start_addr);
|
||||
mcp->mb[3] = MSW(start_addr);
|
||||
mcp->mb[4] = LSW(end_addr);
|
||||
mcp->mb[5] = MSW(end_addr);
|
||||
mcp->out_mb |= MBX_5|MBX_4|MBX_3|MBX_2;
|
||||
}
|
||||
mcp->in_mb = MBX_2|MBX_1|MBX_0;
|
||||
if (!(subcode & (BIT_2 | BIT_5)))
|
||||
mcp->in_mb |= MBX_4|MBX_3;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1147,
|
||||
"Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[3]=%x mb[4]=%x.\n",
|
||||
rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3],
|
||||
mcp->mb[4]);
|
||||
ha->isp_ops->fw_dump(vha, 0);
|
||||
} else {
|
||||
if (subcode & BIT_5)
|
||||
*sector_size = mcp->mb[1];
|
||||
else if (subcode & (BIT_6 | BIT_7)) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1148,
|
||||
"Driver-lock id=%x%x", mcp->mb[4], mcp->mb[3]);
|
||||
} else if (subcode & (BIT_3 | BIT_4)) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1149,
|
||||
"Flash-lock id=%x%x", mcp->mb[4], mcp->mb[3]);
|
||||
}
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x114a, "Done %s.\n", __func__);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
@ -2355,7 +2355,7 @@ qla82xx_need_reset(struct qla_hw_data *ha)
|
||||
uint32_t drv_state;
|
||||
int rval;
|
||||
|
||||
if (ha->flags.isp82xx_reset_owner)
|
||||
if (ha->flags.nic_core_reset_owner)
|
||||
return 1;
|
||||
else {
|
||||
drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
|
||||
@ -2864,7 +2864,7 @@ qla82xx_device_bootstrap(scsi_qla_host_t *vha)
|
||||
timeout = msleep_interruptible(200);
|
||||
if (timeout) {
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA82XX_DEV_FAILED);
|
||||
QLA8XXX_DEV_FAILED);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
@ -2895,7 +2895,7 @@ dev_initialize:
|
||||
/* set to DEV_INITIALIZING */
|
||||
ql_log(ql_log_info, vha, 0x009e,
|
||||
"HW State: INITIALIZING.\n");
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_INITIALIZING);
|
||||
|
||||
/* Driver that sets device state to initializating sets IDC version */
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION);
|
||||
@ -2908,14 +2908,14 @@ dev_initialize:
|
||||
ql_log(ql_log_fatal, vha, 0x00ad,
|
||||
"HW State: FAILED.\n");
|
||||
qla82xx_clear_drv_active(ha);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_FAILED);
|
||||
return rval;
|
||||
}
|
||||
|
||||
dev_ready:
|
||||
ql_log(ql_log_info, vha, 0x00ae,
|
||||
"HW State: READY.\n");
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_READY);
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
@ -2964,7 +2964,7 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
|
||||
"DRV_STATE:%d.\n", QLA2XXX_DRIVER_NAME,
|
||||
drv_active, drv_state);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA82XX_DEV_READY);
|
||||
QLA8XXX_DEV_READY);
|
||||
ql_log(ql_log_info, vha, 0xb025,
|
||||
"HW State: DEV_READY.\n");
|
||||
qla82xx_idc_unlock(ha);
|
||||
@ -2985,10 +2985,10 @@ qla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
|
||||
}
|
||||
dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
|
||||
/* everyone acked so set the state to DEV_QUIESCENCE */
|
||||
if (dev_state == QLA82XX_DEV_NEED_QUIESCENT) {
|
||||
if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT) {
|
||||
ql_log(ql_log_info, vha, 0xb026,
|
||||
"HW State: DEV_QUIESCENT.\n");
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_QUIESCENT);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_QUIESCENT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3018,8 +3018,8 @@ qla82xx_wait_for_state_change(scsi_qla_host_t *vha, uint32_t curr_state)
|
||||
return dev_state;
|
||||
}
|
||||
|
||||
static void
|
||||
qla82xx_dev_failed_handler(scsi_qla_host_t *vha)
|
||||
void
|
||||
qla8xxx_dev_failed_handler(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
@ -3067,7 +3067,7 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
|
||||
}
|
||||
|
||||
drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
|
||||
if (!ha->flags.isp82xx_reset_owner) {
|
||||
if (!ha->flags.nic_core_reset_owner) {
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb028,
|
||||
"reset_acknowledged by 0x%x\n", ha->portnum);
|
||||
qla82xx_set_rst_ready(ha);
|
||||
@ -3079,7 +3079,7 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
|
||||
}
|
||||
|
||||
/* wait for 10 seconds for reset ack from all functions */
|
||||
reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
|
||||
reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
|
||||
|
||||
drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
|
||||
drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
|
||||
@ -3091,7 +3091,7 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
|
||||
drv_state, drv_active, dev_state, active_mask);
|
||||
|
||||
while (drv_state != drv_active &&
|
||||
dev_state != QLA82XX_DEV_INITIALIZING) {
|
||||
dev_state != QLA8XXX_DEV_INITIALIZING) {
|
||||
if (time_after_eq(jiffies, reset_timeout)) {
|
||||
ql_log(ql_log_warn, vha, 0x00b5,
|
||||
"Reset timeout.\n");
|
||||
@ -3102,7 +3102,7 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
|
||||
qla82xx_idc_lock(ha);
|
||||
drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
|
||||
drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
|
||||
if (ha->flags.isp82xx_reset_owner)
|
||||
if (ha->flags.nic_core_reset_owner)
|
||||
drv_active &= active_mask;
|
||||
dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
|
||||
}
|
||||
@ -3118,11 +3118,11 @@ qla82xx_need_reset_handler(scsi_qla_host_t *vha)
|
||||
dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown");
|
||||
|
||||
/* Force to DEV_COLD unless someone else is starting a reset */
|
||||
if (dev_state != QLA82XX_DEV_INITIALIZING &&
|
||||
dev_state != QLA82XX_DEV_COLD) {
|
||||
if (dev_state != QLA8XXX_DEV_INITIALIZING &&
|
||||
dev_state != QLA8XXX_DEV_COLD) {
|
||||
ql_log(ql_log_info, vha, 0x00b7,
|
||||
"HW State: COLD/RE-INIT.\n");
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_COLD);
|
||||
qla82xx_set_rst_ready(ha);
|
||||
if (ql2xmdenable) {
|
||||
if (qla82xx_md_collect(vha))
|
||||
@ -3240,7 +3240,7 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
|
||||
dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown");
|
||||
|
||||
/* wait for 30 seconds for device to go ready */
|
||||
dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
|
||||
dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ);
|
||||
|
||||
while (1) {
|
||||
|
||||
@ -3264,18 +3264,18 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
|
||||
}
|
||||
|
||||
switch (dev_state) {
|
||||
case QLA82XX_DEV_READY:
|
||||
ha->flags.isp82xx_reset_owner = 0;
|
||||
case QLA8XXX_DEV_READY:
|
||||
ha->flags.nic_core_reset_owner = 0;
|
||||
goto rel_lock;
|
||||
case QLA82XX_DEV_COLD:
|
||||
case QLA8XXX_DEV_COLD:
|
||||
rval = qla82xx_device_bootstrap(vha);
|
||||
break;
|
||||
case QLA82XX_DEV_INITIALIZING:
|
||||
case QLA8XXX_DEV_INITIALIZING:
|
||||
qla82xx_idc_unlock(ha);
|
||||
msleep(1000);
|
||||
qla82xx_idc_lock(ha);
|
||||
break;
|
||||
case QLA82XX_DEV_NEED_RESET:
|
||||
case QLA8XXX_DEV_NEED_RESET:
|
||||
if (!ql2xdontresethba)
|
||||
qla82xx_need_reset_handler(vha);
|
||||
else {
|
||||
@ -3284,15 +3284,15 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
|
||||
qla82xx_idc_lock(ha);
|
||||
}
|
||||
dev_init_timeout = jiffies +
|
||||
(ha->nx_dev_init_timeout * HZ);
|
||||
(ha->fcoe_dev_init_timeout * HZ);
|
||||
break;
|
||||
case QLA82XX_DEV_NEED_QUIESCENT:
|
||||
case QLA8XXX_DEV_NEED_QUIESCENT:
|
||||
qla82xx_need_qsnt_handler(vha);
|
||||
/* Reset timeout value after quiescence handler */
|
||||
dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
|
||||
dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout\
|
||||
* HZ);
|
||||
break;
|
||||
case QLA82XX_DEV_QUIESCENT:
|
||||
case QLA8XXX_DEV_QUIESCENT:
|
||||
/* Owner will exit and other will wait for the state
|
||||
* to get changed
|
||||
*/
|
||||
@ -3304,11 +3304,11 @@ qla82xx_device_state_handler(scsi_qla_host_t *vha)
|
||||
qla82xx_idc_lock(ha);
|
||||
|
||||
/* Reset timeout value after quiescence handler */
|
||||
dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\
|
||||
dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout\
|
||||
* HZ);
|
||||
break;
|
||||
case QLA82XX_DEV_FAILED:
|
||||
qla82xx_dev_failed_handler(vha);
|
||||
case QLA8XXX_DEV_FAILED:
|
||||
qla8xxx_dev_failed_handler(vha);
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
goto exit;
|
||||
default:
|
||||
@ -3368,23 +3368,23 @@ void qla82xx_watchdog(scsi_qla_host_t *vha)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
/* don't poll if reset is going on */
|
||||
if (!ha->flags.isp82xx_reset_hdlr_active) {
|
||||
if (!ha->flags.nic_core_reset_hdlr_active) {
|
||||
dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
|
||||
if (qla82xx_check_temp(vha)) {
|
||||
set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
|
||||
ha->flags.isp82xx_fw_hung = 1;
|
||||
qla82xx_clear_pending_mbx(vha);
|
||||
} else if (dev_state == QLA82XX_DEV_NEED_RESET &&
|
||||
} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
|
||||
!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
|
||||
ql_log(ql_log_warn, vha, 0x6001,
|
||||
"Adapter reset needed.\n");
|
||||
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
||||
} else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT &&
|
||||
} else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
|
||||
!test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
|
||||
ql_log(ql_log_warn, vha, 0x6002,
|
||||
"Quiescent needed.\n");
|
||||
set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
|
||||
} else if (dev_state == QLA82XX_DEV_FAILED &&
|
||||
} else if (dev_state == QLA8XXX_DEV_FAILED &&
|
||||
!test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) &&
|
||||
vha->flags.online == 1) {
|
||||
ql_log(ql_log_warn, vha, 0xb055,
|
||||
@ -3453,12 +3453,12 @@ qla82xx_set_reset_owner(scsi_qla_host_t *vha)
|
||||
uint32_t dev_state;
|
||||
|
||||
dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
|
||||
if (dev_state == QLA82XX_DEV_READY) {
|
||||
if (dev_state == QLA8XXX_DEV_READY) {
|
||||
ql_log(ql_log_info, vha, 0xb02f,
|
||||
"HW State: NEED RESET\n");
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA82XX_DEV_NEED_RESET);
|
||||
ha->flags.isp82xx_reset_owner = 1;
|
||||
QLA8XXX_DEV_NEED_RESET);
|
||||
ha->flags.nic_core_reset_owner = 1;
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb030,
|
||||
"reset_owner is 0x%x\n", ha->portnum);
|
||||
} else
|
||||
@ -3489,7 +3489,7 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
|
||||
"Device in failed state, exiting.\n");
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
ha->flags.isp82xx_reset_hdlr_active = 1;
|
||||
ha->flags.nic_core_reset_hdlr_active = 1;
|
||||
|
||||
qla82xx_idc_lock(ha);
|
||||
qla82xx_set_reset_owner(vha);
|
||||
@ -3503,7 +3503,7 @@ qla82xx_abort_isp(scsi_qla_host_t *vha)
|
||||
|
||||
if (rval == QLA_SUCCESS) {
|
||||
ha->flags.isp82xx_fw_hung = 0;
|
||||
ha->flags.isp82xx_reset_hdlr_active = 0;
|
||||
ha->flags.nic_core_reset_hdlr_active = 0;
|
||||
qla82xx_restart_isp(vha);
|
||||
}
|
||||
|
||||
|
@ -542,14 +542,15 @@
|
||||
#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174))
|
||||
|
||||
/* Every driver should use these Device State */
|
||||
#define QLA82XX_DEV_COLD 1
|
||||
#define QLA82XX_DEV_INITIALIZING 2
|
||||
#define QLA82XX_DEV_READY 3
|
||||
#define QLA82XX_DEV_NEED_RESET 4
|
||||
#define QLA82XX_DEV_NEED_QUIESCENT 5
|
||||
#define QLA82XX_DEV_FAILED 6
|
||||
#define QLA82XX_DEV_QUIESCENT 7
|
||||
#define QLA8XXX_DEV_COLD 1
|
||||
#define QLA8XXX_DEV_INITIALIZING 2
|
||||
#define QLA8XXX_DEV_READY 3
|
||||
#define QLA8XXX_DEV_NEED_RESET 4
|
||||
#define QLA8XXX_DEV_NEED_QUIESCENT 5
|
||||
#define QLA8XXX_DEV_FAILED 6
|
||||
#define QLA8XXX_DEV_QUIESCENT 7
|
||||
#define MAX_STATES 8 /* Increment if new state added */
|
||||
#define QLA8XXX_BAD_VALUE 0xbad0bad0
|
||||
|
||||
#define QLA82XX_IDC_VERSION 1
|
||||
#define QLA82XX_ROM_DEV_INIT_TIMEOUT 30
|
||||
|
@ -2149,7 +2149,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
scsi_qla_host_t *base_vha = NULL;
|
||||
struct qla_hw_data *ha;
|
||||
char pci_info[30];
|
||||
char fw_str[30];
|
||||
char fw_str[30], wq_name[30];
|
||||
struct scsi_host_template *sht;
|
||||
int bars, mem_only = 0;
|
||||
uint16_t req_length = 0, rsp_length = 0;
|
||||
@ -2319,6 +2319,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF;
|
||||
ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA;
|
||||
} else if (IS_QLA83XX(ha)) {
|
||||
ha->portnum = PCI_FUNC(ha->pdev->devfn);
|
||||
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
|
||||
ha->mbx_count = MAILBOX_REGISTER_COUNT;
|
||||
req_length = REQUEST_ENTRY_CNT_24XX;
|
||||
@ -2403,6 +2404,20 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER +
|
||||
base_vha->vp_idx;
|
||||
|
||||
if (IS_QLA8031(ha)) {
|
||||
sprintf(wq_name, "qla2xxx_%lu_dpc_lp_wq", base_vha->host_no);
|
||||
ha->dpc_lp_wq = create_singlethread_workqueue(wq_name);
|
||||
INIT_WORK(&ha->idc_aen, qla83xx_service_idc_aen);
|
||||
|
||||
sprintf(wq_name, "qla2xxx_%lu_dpc_hp_wq", base_vha->host_no);
|
||||
ha->dpc_hp_wq = create_singlethread_workqueue(wq_name);
|
||||
INIT_WORK(&ha->nic_core_reset, qla83xx_nic_core_reset_work);
|
||||
INIT_WORK(&ha->idc_state_handler,
|
||||
qla83xx_idc_state_handler_work);
|
||||
INIT_WORK(&ha->nic_core_unrecoverable,
|
||||
qla83xx_nic_core_unrecoverable_work);
|
||||
}
|
||||
|
||||
/* Set the SG table size based on ISP type */
|
||||
if (!IS_FWI2_CAPABLE(ha)) {
|
||||
if (IS_QLA2100(ha))
|
||||
@ -2500,7 +2515,7 @@ que_init:
|
||||
if (IS_QLA82XX(ha)) {
|
||||
qla82xx_idc_lock(ha);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA82XX_DEV_FAILED);
|
||||
QLA8XXX_DEV_FAILED);
|
||||
qla82xx_idc_unlock(ha);
|
||||
ql_log(ql_log_fatal, base_vha, 0x00d7,
|
||||
"HW State: FAILED.\n");
|
||||
@ -2751,6 +2766,14 @@ qla2x00_remove_one(struct pci_dev *pdev)
|
||||
}
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
|
||||
if (IS_QLA8031(ha)) {
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb07e,
|
||||
"Clearing fcoe driver presence.\n");
|
||||
if (qla83xx_clear_drv_presence(base_vha) != QLA_SUCCESS)
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb079,
|
||||
"Error while clearing DRV-Presence.\n");
|
||||
}
|
||||
|
||||
set_bit(UNLOADING, &base_vha->dpc_flags);
|
||||
|
||||
qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
|
||||
@ -2772,6 +2795,21 @@ qla2x00_remove_one(struct pci_dev *pdev)
|
||||
ha->wq = NULL;
|
||||
}
|
||||
|
||||
/* Cancel all work and destroy DPC workqueues */
|
||||
if (ha->dpc_lp_wq) {
|
||||
cancel_work_sync(&ha->idc_aen);
|
||||
destroy_workqueue(ha->dpc_lp_wq);
|
||||
ha->dpc_lp_wq = NULL;
|
||||
}
|
||||
|
||||
if (ha->dpc_hp_wq) {
|
||||
cancel_work_sync(&ha->nic_core_reset);
|
||||
cancel_work_sync(&ha->idc_state_handler);
|
||||
cancel_work_sync(&ha->nic_core_unrecoverable);
|
||||
destroy_workqueue(ha->dpc_hp_wq);
|
||||
ha->dpc_hp_wq = NULL;
|
||||
}
|
||||
|
||||
/* Kill the kernel thread for this host */
|
||||
if (ha->dpc_thread) {
|
||||
struct task_struct *t = ha->dpc_thread;
|
||||
@ -2838,7 +2876,6 @@ qla2x00_free_device(scsi_qla_host_t *vha)
|
||||
qla2x00_stop_dpc_thread(vha);
|
||||
|
||||
qla25xx_delete_queues(vha);
|
||||
|
||||
if (ha->flags.fce_enabled)
|
||||
qla2x00_disable_fce_trace(vha, NULL, NULL);
|
||||
|
||||
@ -3709,6 +3746,637 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
|
||||
}
|
||||
}
|
||||
|
||||
/* Schedule work on any of the dpc-workqueues */
|
||||
void
|
||||
qla83xx_schedule_work(scsi_qla_host_t *base_vha, int work_code)
|
||||
{
|
||||
struct qla_hw_data *ha = base_vha->hw;
|
||||
|
||||
switch (work_code) {
|
||||
case MBA_IDC_AEN: /* 0x8200 */
|
||||
if (ha->dpc_lp_wq)
|
||||
queue_work(ha->dpc_lp_wq, &ha->idc_aen);
|
||||
break;
|
||||
|
||||
case QLA83XX_NIC_CORE_RESET: /* 0x1 */
|
||||
if (!ha->flags.nic_core_reset_hdlr_active) {
|
||||
if (ha->dpc_hp_wq)
|
||||
queue_work(ha->dpc_hp_wq, &ha->nic_core_reset);
|
||||
} else
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb05e,
|
||||
"NIC Core reset is already active. Skip "
|
||||
"scheduling it again.\n");
|
||||
break;
|
||||
case QLA83XX_IDC_STATE_HANDLER: /* 0x2 */
|
||||
if (ha->dpc_hp_wq)
|
||||
queue_work(ha->dpc_hp_wq, &ha->idc_state_handler);
|
||||
break;
|
||||
case QLA83XX_NIC_CORE_UNRECOVERABLE: /* 0x3 */
|
||||
if (ha->dpc_hp_wq)
|
||||
queue_work(ha->dpc_hp_wq, &ha->nic_core_unrecoverable);
|
||||
break;
|
||||
default:
|
||||
ql_log(ql_log_warn, base_vha, 0xb05f,
|
||||
"Unknow work-code=0x%x.\n", work_code);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Work: Perform NIC Core Unrecoverable state handling */
|
||||
void
|
||||
qla83xx_nic_core_unrecoverable_work(struct work_struct *work)
|
||||
{
|
||||
struct qla_hw_data *ha =
|
||||
container_of(work, struct qla_hw_data, nic_core_reset);
|
||||
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
|
||||
uint32_t dev_state = 0;
|
||||
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state);
|
||||
qla83xx_reset_ownership(base_vha);
|
||||
if (ha->flags.nic_core_reset_owner) {
|
||||
ha->flags.nic_core_reset_owner = 0;
|
||||
qla83xx_wr_reg(base_vha, QLA83XX_IDC_DEV_STATE,
|
||||
QLA8XXX_DEV_FAILED);
|
||||
ql_log(ql_log_info, base_vha, 0xb060, "HW State: FAILED.\n");
|
||||
qla83xx_schedule_work(base_vha, QLA83XX_IDC_STATE_HANDLER);
|
||||
}
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
}
|
||||
|
||||
/* Work: Execute IDC state handler */
|
||||
void
|
||||
qla83xx_idc_state_handler_work(struct work_struct *work)
|
||||
{
|
||||
struct qla_hw_data *ha =
|
||||
container_of(work, struct qla_hw_data, nic_core_reset);
|
||||
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
|
||||
uint32_t dev_state = 0;
|
||||
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state);
|
||||
if (dev_state == QLA8XXX_DEV_FAILED ||
|
||||
dev_state == QLA8XXX_DEV_NEED_QUIESCENT)
|
||||
qla83xx_idc_state_handler(base_vha);
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_check_nic_core_fw_alive(scsi_qla_host_t *base_vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
unsigned long heart_beat_wait = jiffies + (1 * HZ);
|
||||
uint32_t heart_beat_counter1, heart_beat_counter2;
|
||||
|
||||
do {
|
||||
if (time_after(jiffies, heart_beat_wait)) {
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb07c,
|
||||
"Nic Core f/w is not alive.\n");
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
qla83xx_rd_reg(base_vha, QLA83XX_FW_HEARTBEAT,
|
||||
&heart_beat_counter1);
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
msleep(100);
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
qla83xx_rd_reg(base_vha, QLA83XX_FW_HEARTBEAT,
|
||||
&heart_beat_counter2);
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
} while (heart_beat_counter1 == heart_beat_counter2);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Work: Perform NIC Core Reset handling */
|
||||
void
|
||||
qla83xx_nic_core_reset_work(struct work_struct *work)
|
||||
{
|
||||
struct qla_hw_data *ha =
|
||||
container_of(work, struct qla_hw_data, nic_core_reset);
|
||||
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
|
||||
uint32_t dev_state = 0;
|
||||
|
||||
if (!ha->flags.nic_core_reset_hdlr_active) {
|
||||
if (qla83xx_check_nic_core_fw_alive(base_vha) == QLA_SUCCESS) {
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE,
|
||||
&dev_state);
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
if (dev_state != QLA8XXX_DEV_NEED_RESET) {
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb07a,
|
||||
"Nic Core f/w is alive.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ha->flags.nic_core_reset_hdlr_active = 1;
|
||||
if (qla83xx_nic_core_reset(base_vha)) {
|
||||
/* NIC Core reset failed. */
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb061,
|
||||
"NIC Core reset failed.\n");
|
||||
}
|
||||
ha->flags.nic_core_reset_hdlr_active = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Work: Handle 8200 IDC aens */
|
||||
void
|
||||
qla83xx_service_idc_aen(struct work_struct *work)
|
||||
{
|
||||
struct qla_hw_data *ha =
|
||||
container_of(work, struct qla_hw_data, idc_aen);
|
||||
scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
|
||||
uint32_t dev_state, idc_control;
|
||||
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state);
|
||||
qla83xx_rd_reg(base_vha, QLA83XX_IDC_CONTROL, &idc_control);
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
if (dev_state == QLA8XXX_DEV_NEED_RESET) {
|
||||
if (idc_control & QLA83XX_IDC_GRACEFUL_RESET) {
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb062,
|
||||
"Application requested NIC Core Reset.\n");
|
||||
qla83xx_schedule_work(base_vha, QLA83XX_NIC_CORE_RESET);
|
||||
} else if (qla83xx_check_nic_core_fw_alive(base_vha) ==
|
||||
QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb07b,
|
||||
"Other protocol driver requested NIC Core Reset.\n");
|
||||
qla83xx_schedule_work(base_vha, QLA83XX_NIC_CORE_RESET);
|
||||
}
|
||||
} else if (dev_state == QLA8XXX_DEV_FAILED ||
|
||||
dev_state == QLA8XXX_DEV_NEED_QUIESCENT) {
|
||||
qla83xx_schedule_work(base_vha, QLA83XX_IDC_STATE_HANDLER);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qla83xx_wait_logic(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Yield CPU */
|
||||
if (!in_interrupt()) {
|
||||
/*
|
||||
* Wait about 200ms before retrying again.
|
||||
* This controls the number of retries for single
|
||||
* lock operation.
|
||||
*/
|
||||
msleep(100);
|
||||
schedule();
|
||||
} else {
|
||||
for (i = 0; i < 20; i++)
|
||||
cpu_relax(); /* This a nop instr on i386 */
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_force_lock_recovery(scsi_qla_host_t *base_vha)
|
||||
{
|
||||
int rval;
|
||||
uint32_t data;
|
||||
uint32_t idc_lck_rcvry_stage_mask = 0x3;
|
||||
uint32_t idc_lck_rcvry_owner_mask = 0x3c;
|
||||
struct qla_hw_data *ha = base_vha->hw;
|
||||
|
||||
rval = qla83xx_rd_reg(base_vha, QLA83XX_IDC_LOCK_RECOVERY, &data);
|
||||
if (rval)
|
||||
return rval;
|
||||
|
||||
if ((data & idc_lck_rcvry_stage_mask) > 0) {
|
||||
return QLA_SUCCESS;
|
||||
} else {
|
||||
data = (IDC_LOCK_RECOVERY_STAGE1) | (ha->portnum << 2);
|
||||
rval = qla83xx_wr_reg(base_vha, QLA83XX_IDC_LOCK_RECOVERY,
|
||||
data);
|
||||
if (rval)
|
||||
return rval;
|
||||
|
||||
msleep(200);
|
||||
|
||||
rval = qla83xx_rd_reg(base_vha, QLA83XX_IDC_LOCK_RECOVERY,
|
||||
&data);
|
||||
if (rval)
|
||||
return rval;
|
||||
|
||||
if (((data & idc_lck_rcvry_owner_mask) >> 2) == ha->portnum) {
|
||||
data &= (IDC_LOCK_RECOVERY_STAGE2 |
|
||||
~(idc_lck_rcvry_stage_mask));
|
||||
rval = qla83xx_wr_reg(base_vha,
|
||||
QLA83XX_IDC_LOCK_RECOVERY, data);
|
||||
if (rval)
|
||||
return rval;
|
||||
|
||||
/* Forcefully perform IDC UnLock */
|
||||
rval = qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_UNLOCK,
|
||||
&data);
|
||||
if (rval)
|
||||
return rval;
|
||||
/* Clear lock-id by setting 0xff */
|
||||
rval = qla83xx_wr_reg(base_vha, QLA83XX_DRIVER_LOCKID,
|
||||
0xff);
|
||||
if (rval)
|
||||
return rval;
|
||||
/* Clear lock-recovery by setting 0x0 */
|
||||
rval = qla83xx_wr_reg(base_vha,
|
||||
QLA83XX_IDC_LOCK_RECOVERY, 0x0);
|
||||
if (rval)
|
||||
return rval;
|
||||
} else
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_idc_lock_recovery(scsi_qla_host_t *base_vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
uint32_t o_drv_lockid, n_drv_lockid;
|
||||
unsigned long lock_recovery_timeout;
|
||||
|
||||
lock_recovery_timeout = jiffies + QLA83XX_MAX_LOCK_RECOVERY_WAIT;
|
||||
retry_lockid:
|
||||
rval = qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, &o_drv_lockid);
|
||||
if (rval)
|
||||
goto exit;
|
||||
|
||||
/* MAX wait time before forcing IDC Lock recovery = 2 secs */
|
||||
if (time_after_eq(jiffies, lock_recovery_timeout)) {
|
||||
if (qla83xx_force_lock_recovery(base_vha) == QLA_SUCCESS)
|
||||
return QLA_SUCCESS;
|
||||
else
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
rval = qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, &n_drv_lockid);
|
||||
if (rval)
|
||||
goto exit;
|
||||
|
||||
if (o_drv_lockid == n_drv_lockid) {
|
||||
qla83xx_wait_logic();
|
||||
goto retry_lockid;
|
||||
} else
|
||||
return QLA_SUCCESS;
|
||||
|
||||
exit:
|
||||
return rval;
|
||||
}
|
||||
|
||||
void
|
||||
qla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id)
|
||||
{
|
||||
uint16_t options = (requester_id << 15) | BIT_6;
|
||||
uint32_t data;
|
||||
struct qla_hw_data *ha = base_vha->hw;
|
||||
|
||||
/* IDC-lock implementation using driver-lock/lock-id remote registers */
|
||||
retry_lock:
|
||||
if (qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCK, &data)
|
||||
== QLA_SUCCESS) {
|
||||
if (data) {
|
||||
/* Setting lock-id to our function-number */
|
||||
qla83xx_wr_reg(base_vha, QLA83XX_DRIVER_LOCKID,
|
||||
ha->portnum);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb063,
|
||||
"Failed to acquire IDC lock. retrying...\n");
|
||||
|
||||
/* Retry/Perform IDC-Lock recovery */
|
||||
if (qla83xx_idc_lock_recovery(base_vha)
|
||||
== QLA_SUCCESS) {
|
||||
qla83xx_wait_logic();
|
||||
goto retry_lock;
|
||||
} else
|
||||
ql_log(ql_log_warn, base_vha, 0xb075,
|
||||
"IDC Lock recovery FAILED.\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
/* XXX: IDC-lock implementation using access-control mbx */
|
||||
retry_lock2:
|
||||
if (qla83xx_access_control(base_vha, options, 0, 0, NULL)) {
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb072,
|
||||
"Failed to acquire IDC lock. retrying...\n");
|
||||
/* Retry/Perform IDC-Lock recovery */
|
||||
if (qla83xx_idc_lock_recovery(base_vha) == QLA_SUCCESS) {
|
||||
qla83xx_wait_logic();
|
||||
goto retry_lock2;
|
||||
} else
|
||||
ql_log(ql_log_warn, base_vha, 0xb076,
|
||||
"IDC Lock recovery FAILED.\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
qla83xx_idc_unlock(scsi_qla_host_t *base_vha, uint16_t requester_id)
|
||||
{
|
||||
uint16_t options = (requester_id << 15) | BIT_7, retry;
|
||||
uint32_t data;
|
||||
struct qla_hw_data *ha = base_vha->hw;
|
||||
|
||||
/* IDC-unlock implementation using driver-unlock/lock-id
|
||||
* remote registers
|
||||
*/
|
||||
retry = 0;
|
||||
retry_unlock:
|
||||
if (qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_LOCKID, &data)
|
||||
== QLA_SUCCESS) {
|
||||
if (data == ha->portnum) {
|
||||
qla83xx_rd_reg(base_vha, QLA83XX_DRIVER_UNLOCK, &data);
|
||||
/* Clearing lock-id by setting 0xff */
|
||||
qla83xx_wr_reg(base_vha, QLA83XX_DRIVER_LOCKID, 0xff);
|
||||
} else if (retry < 10) {
|
||||
/* SV: XXX: IDC unlock retrying needed here? */
|
||||
|
||||
/* Retry for IDC-unlock */
|
||||
qla83xx_wait_logic();
|
||||
retry++;
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb064,
|
||||
"Failed to release IDC lock, retyring=%d\n", retry);
|
||||
goto retry_unlock;
|
||||
}
|
||||
} else if (retry < 10) {
|
||||
/* Retry for IDC-unlock */
|
||||
qla83xx_wait_logic();
|
||||
retry++;
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb065,
|
||||
"Failed to read drv-lockid, retyring=%d\n", retry);
|
||||
goto retry_unlock;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
/* XXX: IDC-unlock implementation using access-control mbx */
|
||||
retry = 0;
|
||||
retry_unlock2:
|
||||
if (qla83xx_access_control(base_vha, options, 0, 0, NULL)) {
|
||||
if (retry < 10) {
|
||||
/* Retry for IDC-unlock */
|
||||
qla83xx_wait_logic();
|
||||
retry++;
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb066,
|
||||
"Failed to release IDC lock, retyring=%d\n", retry);
|
||||
goto retry_unlock2;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int
|
||||
__qla83xx_set_drv_presence(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t drv_presence;
|
||||
|
||||
rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
|
||||
if (rval == QLA_SUCCESS) {
|
||||
drv_presence |= (1 << ha->portnum);
|
||||
rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRV_PRESENCE,
|
||||
drv_presence);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_set_drv_presence(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
rval = __qla83xx_set_drv_presence(vha);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
__qla83xx_clear_drv_presence(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t drv_presence;
|
||||
|
||||
rval = qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
|
||||
if (rval == QLA_SUCCESS) {
|
||||
drv_presence &= ~(1 << ha->portnum);
|
||||
rval = qla83xx_wr_reg(vha, QLA83XX_IDC_DRV_PRESENCE,
|
||||
drv_presence);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_clear_drv_presence(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
rval = __qla83xx_clear_drv_presence(vha);
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
void
|
||||
qla83xx_need_reset_handler(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t drv_ack, drv_presence;
|
||||
unsigned long ack_timeout;
|
||||
|
||||
/* Wait for IDC ACK from all functions (DRV-ACK == DRV-PRESENCE) */
|
||||
ack_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
|
||||
while (1) {
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_DRIVER_ACK, &drv_ack);
|
||||
qla83xx_rd_reg(vha, QLA83XX_IDC_DRV_PRESENCE, &drv_presence);
|
||||
if (drv_ack == drv_presence)
|
||||
break;
|
||||
|
||||
if (time_after_eq(jiffies, ack_timeout)) {
|
||||
ql_log(ql_log_warn, vha, 0xb067,
|
||||
"RESET ACK TIMEOUT! drv_presence=0x%x "
|
||||
"drv_ack=0x%x\n", drv_presence, drv_ack);
|
||||
/*
|
||||
* The function(s) which did not ack in time are forced
|
||||
* to withdraw any further participation in the IDC
|
||||
* reset.
|
||||
*/
|
||||
if (drv_ack != drv_presence)
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_DRV_PRESENCE,
|
||||
drv_ack);
|
||||
break;
|
||||
}
|
||||
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
msleep(1000);
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
}
|
||||
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_COLD);
|
||||
ql_log(ql_log_info, vha, 0xb068, "HW State: COLD/RE-INIT.\n");
|
||||
}
|
||||
|
||||
int
|
||||
qla83xx_device_bootstrap(scsi_qla_host_t *vha)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
uint32_t idc_control;
|
||||
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_INITIALIZING);
|
||||
ql_log(ql_log_info, vha, 0xb069, "HW State: INITIALIZING.\n");
|
||||
|
||||
/* Clearing IDC-Control Graceful-Reset Bit before resetting f/w */
|
||||
__qla83xx_get_idc_control(vha, &idc_control);
|
||||
idc_control &= ~QLA83XX_IDC_GRACEFUL_RESET;
|
||||
__qla83xx_set_idc_control(vha, 0);
|
||||
|
||||
qla83xx_idc_unlock(vha, 0);
|
||||
rval = qla83xx_restart_nic_firmware(vha);
|
||||
qla83xx_idc_lock(vha, 0);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_fatal, vha, 0xb06a,
|
||||
"Failed to restart NIC f/w.\n");
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_FAILED);
|
||||
ql_log(ql_log_info, vha, 0xb06b, "HW State: FAILED.\n");
|
||||
} else {
|
||||
ql_dbg(ql_dbg_p3p, vha, 0xb06c,
|
||||
"Success in restarting nic f/w.\n");
|
||||
qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE, QLA8XXX_DEV_READY);
|
||||
ql_log(ql_log_info, vha, 0xb06d, "HW State: READY.\n");
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* Assumes idc_lock always held on entry */
|
||||
int
|
||||
qla83xx_idc_state_handler(scsi_qla_host_t *base_vha)
|
||||
{
|
||||
struct qla_hw_data *ha = base_vha->hw;
|
||||
int rval = QLA_SUCCESS;
|
||||
unsigned long dev_init_timeout;
|
||||
uint32_t dev_state;
|
||||
|
||||
/* Wait for MAX-INIT-TIMEOUT for the device to go ready */
|
||||
dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ);
|
||||
|
||||
while (1) {
|
||||
|
||||
if (time_after_eq(jiffies, dev_init_timeout)) {
|
||||
ql_log(ql_log_warn, base_vha, 0xb06e,
|
||||
"Initialization TIMEOUT!\n");
|
||||
/* Init timeout. Disable further NIC Core
|
||||
* communication.
|
||||
*/
|
||||
qla83xx_wr_reg(base_vha, QLA83XX_IDC_DEV_STATE,
|
||||
QLA8XXX_DEV_FAILED);
|
||||
ql_log(ql_log_info, base_vha, 0xb06f,
|
||||
"HW State: FAILED.\n");
|
||||
}
|
||||
|
||||
qla83xx_rd_reg(base_vha, QLA83XX_IDC_DEV_STATE, &dev_state);
|
||||
switch (dev_state) {
|
||||
case QLA8XXX_DEV_READY:
|
||||
if (ha->flags.nic_core_reset_owner)
|
||||
qla83xx_idc_audit(base_vha,
|
||||
IDC_AUDIT_COMPLETION);
|
||||
ha->flags.nic_core_reset_owner = 0;
|
||||
ql_dbg(ql_dbg_p3p, base_vha, 0xb070,
|
||||
"Reset_owner reset by 0x%x.\n",
|
||||
ha->portnum);
|
||||
goto exit;
|
||||
case QLA8XXX_DEV_COLD:
|
||||
if (ha->flags.nic_core_reset_owner)
|
||||
rval = qla83xx_device_bootstrap(base_vha);
|
||||
else {
|
||||
/* Wait for AEN to change device-state */
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
msleep(1000);
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
}
|
||||
break;
|
||||
case QLA8XXX_DEV_INITIALIZING:
|
||||
/* Wait for AEN to change device-state */
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
msleep(1000);
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
break;
|
||||
case QLA8XXX_DEV_NEED_RESET:
|
||||
if (!ql2xdontresethba && ha->flags.nic_core_reset_owner)
|
||||
qla83xx_need_reset_handler(base_vha);
|
||||
else {
|
||||
/* Wait for AEN to change device-state */
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
msleep(1000);
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
}
|
||||
/* reset timeout value after need reset handler */
|
||||
dev_init_timeout = jiffies +
|
||||
(ha->fcoe_dev_init_timeout * HZ);
|
||||
break;
|
||||
case QLA8XXX_DEV_NEED_QUIESCENT:
|
||||
/* XXX: DEBUG for now */
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
msleep(1000);
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
break;
|
||||
case QLA8XXX_DEV_QUIESCENT:
|
||||
/* XXX: DEBUG for now */
|
||||
if (ha->flags.quiesce_owner)
|
||||
goto exit;
|
||||
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
msleep(1000);
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
dev_init_timeout = jiffies +
|
||||
(ha->fcoe_dev_init_timeout * HZ);
|
||||
break;
|
||||
case QLA8XXX_DEV_FAILED:
|
||||
if (ha->flags.nic_core_reset_owner)
|
||||
qla83xx_idc_audit(base_vha,
|
||||
IDC_AUDIT_COMPLETION);
|
||||
ha->flags.nic_core_reset_owner = 0;
|
||||
__qla83xx_clear_drv_presence(base_vha);
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
qla8xxx_dev_failed_handler(base_vha);
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
goto exit;
|
||||
case QLA8XXX_BAD_VALUE:
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
msleep(1000);
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
break;
|
||||
default:
|
||||
ql_log(ql_log_warn, base_vha, 0xb071,
|
||||
"Unknow Device State: %x.\n", dev_state);
|
||||
qla83xx_idc_unlock(base_vha, 0);
|
||||
qla8xxx_dev_failed_handler(base_vha);
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
qla83xx_idc_lock(base_vha, 0);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* qla2x00_do_dpc
|
||||
* This kernel thread is a task that is schedule by the interrupt handler
|
||||
@ -3764,7 +4432,7 @@ qla2x00_do_dpc(void *data)
|
||||
&base_vha->dpc_flags)) {
|
||||
qla82xx_idc_lock(ha);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA82XX_DEV_FAILED);
|
||||
QLA8XXX_DEV_FAILED);
|
||||
qla82xx_idc_unlock(ha);
|
||||
ql_log(ql_log_info, base_vha, 0x4004,
|
||||
"HW State: FAILED.\n");
|
||||
@ -4341,7 +5009,7 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
|
||||
qla82xx_idc_lock(ha);
|
||||
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA82XX_DEV_INITIALIZING);
|
||||
QLA8XXX_DEV_INITIALIZING);
|
||||
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION,
|
||||
QLA82XX_IDC_VERSION);
|
||||
@ -4365,12 +5033,12 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
|
||||
"HW State: FAILED.\n");
|
||||
qla82xx_clear_drv_active(ha);
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA82XX_DEV_FAILED);
|
||||
QLA8XXX_DEV_FAILED);
|
||||
} else {
|
||||
ql_log(ql_log_info, base_vha, 0x900c,
|
||||
"HW State: READY.\n");
|
||||
qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
|
||||
QLA82XX_DEV_READY);
|
||||
QLA8XXX_DEV_READY);
|
||||
qla82xx_idc_unlock(ha);
|
||||
ha->flags.isp82xx_fw_hung = 0;
|
||||
rval = qla82xx_restart_isp(base_vha);
|
||||
@ -4385,7 +5053,7 @@ uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha)
|
||||
"This devfn is not reset owner = 0x%x.\n",
|
||||
ha->pdev->devfn);
|
||||
if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) ==
|
||||
QLA82XX_DEV_READY)) {
|
||||
QLA8XXX_DEV_READY)) {
|
||||
ha->flags.isp82xx_fw_hung = 0;
|
||||
rval = qla82xx_restart_isp(base_vha);
|
||||
qla82xx_idc_lock(ha);
|
||||
|
@ -966,16 +966,16 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha)
|
||||
QLA82XX_IDC_PARAM_ADDR , 8);
|
||||
|
||||
if (*wptr == __constant_cpu_to_le32(0xffffffff)) {
|
||||
ha->nx_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT;
|
||||
ha->nx_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT;
|
||||
ha->fcoe_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT;
|
||||
ha->fcoe_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT;
|
||||
} else {
|
||||
ha->nx_dev_init_timeout = le32_to_cpu(*wptr++);
|
||||
ha->nx_reset_timeout = le32_to_cpu(*wptr);
|
||||
ha->fcoe_dev_init_timeout = le32_to_cpu(*wptr++);
|
||||
ha->fcoe_reset_timeout = le32_to_cpu(*wptr);
|
||||
}
|
||||
ql_dbg(ql_dbg_init, vha, 0x004e,
|
||||
"nx_dev_init_timeout=%d "
|
||||
"nx_reset_timeout=%d.\n", ha->nx_dev_init_timeout,
|
||||
ha->nx_reset_timeout);
|
||||
"fcoe_dev_init_timeout=%d "
|
||||
"fcoe_reset_timeout=%d.\n", ha->fcoe_dev_init_timeout,
|
||||
ha->fcoe_reset_timeout);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1017,7 +1017,7 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
|
||||
!IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
|
||||
return;
|
||||
|
||||
if (ha->flags.isp82xx_reset_hdlr_active)
|
||||
if (ha->flags.nic_core_reset_hdlr_active)
|
||||
return;
|
||||
|
||||
ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr,
|
||||
@ -1675,15 +1675,15 @@ qla83xx_beacon_blink(struct scsi_qla_host *vha)
|
||||
|
||||
if (IS_QLA2031(ha) && ha->beacon_blink_led) {
|
||||
if (ha->flags.port0)
|
||||
led_select_value = 0x00201320;
|
||||
led_select_value = QLA83XX_LED_PORT0;
|
||||
else
|
||||
led_select_value = 0x00201328;
|
||||
led_select_value = QLA83XX_LED_PORT1;
|
||||
|
||||
qla83xx_write_remote_reg(vha, led_select_value, 0x40002000);
|
||||
qla83xx_write_remote_reg(vha, led_select_value + 4, 0x40002000);
|
||||
qla83xx_wr_reg(vha, led_select_value, 0x40002000);
|
||||
qla83xx_wr_reg(vha, led_select_value + 4, 0x40002000);
|
||||
msleep(1000);
|
||||
qla83xx_write_remote_reg(vha, led_select_value, 0x40004000);
|
||||
qla83xx_write_remote_reg(vha, led_select_value + 4, 0x40004000);
|
||||
qla83xx_wr_reg(vha, led_select_value, 0x40004000);
|
||||
qla83xx_wr_reg(vha, led_select_value + 4, 0x40004000);
|
||||
} else if ((IS_QLA8031(ha) || IS_QLA81XX(ha)) && ha->beacon_blink_led) {
|
||||
int rval;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user