Commit d1d5ca88 authored by Jitendra Bhivare's avatar Jitendra Bhivare Committed by Martin K. Petersen

scsi: be2iscsi: Add TPE recovery feature

After UE is detected, check for recoverable error by reading
SLIPORT SEMAPHORE register. If transient parity error i.e. 0xExxx
then schedule recovery work on driver wq.

FLag this error to prevent any transactions for the duration of ue2rp to
restart polling. After that, if FW becomes ready then recover port.

Wake up processes in wq before going offline.
Wait for process to execute before cleaning up.
Signed-off-by: default avatarJitendra Bhivare <jitendra.bhivare@broadcom.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent f79929de
...@@ -21,6 +21,78 @@ ...@@ -21,6 +21,78 @@
#include "be.h" #include "be.h"
#include "be_mgmt.h" #include "be_mgmt.h"
/* UE Status Low CSR */
static const char * const desc_ue_status_low[] = {
"CEV",
"CTX",
"DBUF",
"ERX",
"Host",
"MPU",
"NDMA",
"PTC ",
"RDMA ",
"RXF ",
"RXIPS ",
"RXULP0 ",
"RXULP1 ",
"RXULP2 ",
"TIM ",
"TPOST ",
"TPRE ",
"TXIPS ",
"TXULP0 ",
"TXULP1 ",
"UC ",
"WDMA ",
"TXULP2 ",
"HOST1 ",
"P0_OB_LINK ",
"P1_OB_LINK ",
"HOST_GPIO ",
"MBOX ",
"AXGMAC0",
"AXGMAC1",
"JTAG",
"MPU_INTPEND"
};
/* UE Status High CSR */
static const char * const desc_ue_status_hi[] = {
"LPCMEMHOST",
"MGMT_MAC",
"PCS0ONLINE",
"MPU_IRAM",
"PCS1ONLINE",
"PCTL0",
"PCTL1",
"PMEM",
"RR",
"TXPB",
"RXPP",
"XAUI",
"TXP",
"ARM",
"IPC",
"HOST2",
"HOST3",
"HOST4",
"HOST5",
"HOST6",
"HOST7",
"HOST8",
"HOST9",
"NETC",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown"
};
struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba, struct be_mcc_wrb *alloc_mcc_wrb(struct beiscsi_hba *phba,
unsigned int *ref_tag) unsigned int *ref_tag)
{ {
...@@ -185,6 +257,16 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba, ...@@ -185,6 +257,16 @@ int beiscsi_mccq_compl_wait(struct beiscsi_hba *phba,
phba->ctrl.mcc_tag_status[tag], phba->ctrl.mcc_tag_status[tag],
msecs_to_jiffies( msecs_to_jiffies(
BEISCSI_HOST_MBX_TIMEOUT)); BEISCSI_HOST_MBX_TIMEOUT));
/**
* Return EIO if port is being disabled. Associated DMA memory, if any,
* is freed by the caller. When port goes offline, MCCQ is cleaned up
* so does WRB.
*/
if (!test_bit(BEISCSI_HBA_ONLINE, &phba->state)) {
clear_bit(MCC_TAG_STATE_RUNNING,
&phba->ctrl.ptag_state[tag].tag_state);
return -EIO;
}
/** /**
* If MBOX cmd timeout expired, tag and resource allocated * If MBOX cmd timeout expired, tag and resource allocated
...@@ -538,7 +620,6 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl) ...@@ -538,7 +620,6 @@ static int be_mbox_db_ready_poll(struct be_ctrl_info *ctrl)
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX, BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BC_%d : FW Timed Out\n"); "BC_%d : FW Timed Out\n");
set_bit(BEISCSI_HBA_FW_TIMEOUT, &phba->state); set_bit(BEISCSI_HBA_FW_TIMEOUT, &phba->state);
beiscsi_ue_detect(phba);
return -EBUSY; return -EBUSY;
} }
...@@ -1584,6 +1665,12 @@ int beiscsi_init_sliport(struct beiscsi_hba *phba) ...@@ -1584,6 +1665,12 @@ int beiscsi_init_sliport(struct beiscsi_hba *phba)
if (!status) if (!status)
return -EIO; return -EIO;
/* clear all error states after checking FW rdy */
phba->state &= ~BEISCSI_HBA_IN_ERR;
/* check again UER support */
phba->state &= ~BEISCSI_HBA_UER_SUPP;
/* /*
* SLI COMMON_FUNCTION_RESET completion is indicated by BMBX RDY bit. * SLI COMMON_FUNCTION_RESET completion is indicated by BMBX RDY bit.
* It should clean up any stale info in FW for this fn. * It should clean up any stale info in FW for this fn.
...@@ -1647,3 +1734,87 @@ int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp) ...@@ -1647,3 +1734,87 @@ int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp)
mutex_unlock(&ctrl->mbox_lock); mutex_unlock(&ctrl->mbox_lock);
return status; return status;
} }
/*
* beiscsi_detect_ue()- Detect Unrecoverable Error on adapter
* @phba: Driver priv structure
*
* Read registers linked to UE and check for the UE status
**/
int beiscsi_detect_ue(struct beiscsi_hba *phba)
{
uint32_t ue_mask_hi = 0, ue_mask_lo = 0;
uint32_t ue_hi = 0, ue_lo = 0;
uint8_t i = 0;
int ret = 0;
pci_read_config_dword(phba->pcidev,
PCICFG_UE_STATUS_LOW, &ue_lo);
pci_read_config_dword(phba->pcidev,
PCICFG_UE_STATUS_MASK_LOW,
&ue_mask_lo);
pci_read_config_dword(phba->pcidev,
PCICFG_UE_STATUS_HIGH,
&ue_hi);
pci_read_config_dword(phba->pcidev,
PCICFG_UE_STATUS_MASK_HI,
&ue_mask_hi);
ue_lo = (ue_lo & ~ue_mask_lo);
ue_hi = (ue_hi & ~ue_mask_hi);
if (ue_lo || ue_hi) {
set_bit(BEISCSI_HBA_IN_UE, &phba->state);
__beiscsi_log(phba, KERN_ERR,
"BC_%d : HBA error detected\n");
ret = 1;
}
if (ue_lo) {
for (i = 0; ue_lo; ue_lo >>= 1, i++) {
if (ue_lo & 1)
__beiscsi_log(phba, KERN_ERR,
"BC_%d : UE_LOW %s bit set\n",
desc_ue_status_low[i]);
}
}
if (ue_hi) {
for (i = 0; ue_hi; ue_hi >>= 1, i++) {
if (ue_hi & 1)
__beiscsi_log(phba, KERN_ERR,
"BC_%d : UE_HIGH %s bit set\n",
desc_ue_status_hi[i]);
}
}
return ret;
}
/*
* beiscsi_detect_tpe()- Detect Transient Parity Error on adapter
* @phba: Driver priv structure
*
* Read SLIPORT SEMAPHORE register to check for UER
*
**/
int beiscsi_detect_tpe(struct beiscsi_hba *phba)
{
u32 post, status;
int ret = 0;
post = beiscsi_get_post_stage(phba);
status = post & POST_STAGE_MASK;
if ((status & POST_ERR_RECOVERY_CODE_MASK) ==
POST_STAGE_RECOVERABLE_ERR) {
set_bit(BEISCSI_HBA_IN_TPE, &phba->state);
__beiscsi_log(phba, KERN_INFO,
"BC_%d : HBA error recoverable: 0x%x\n", post);
ret = 1;
} else {
__beiscsi_log(phba, KERN_INFO,
"BC_%d : HBA in UE: 0x%x\n", post);
}
return ret;
}
...@@ -770,6 +770,10 @@ int beiscsi_init_sliport(struct beiscsi_hba *phba); ...@@ -770,6 +770,10 @@ int beiscsi_init_sliport(struct beiscsi_hba *phba);
int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num); int beiscsi_cmd_iscsi_cleanup(struct beiscsi_hba *phba, unsigned short ulp_num);
int beiscsi_detect_ue(struct beiscsi_hba *phba);
int beiscsi_detect_tpe(struct beiscsi_hba *phba);
int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl, int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
struct be_queue_info *eq, int eq_delay); struct be_queue_info *eq, int eq_delay);
......
...@@ -58,7 +58,7 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, ...@@ -58,7 +58,7 @@ struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
beiscsi_ep = ep->dd_data; beiscsi_ep = ep->dd_data;
phba = beiscsi_ep->phba; phba = beiscsi_ep->phba;
if (beiscsi_hba_in_error(phba)) { if (!beiscsi_hba_is_online(phba)) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BS_%d : HBA in error 0x%lx\n", phba->state); "BS_%d : HBA in error 0x%lx\n", phba->state);
return NULL; return NULL;
...@@ -444,7 +444,7 @@ int beiscsi_iface_set_param(struct Scsi_Host *shost, ...@@ -444,7 +444,7 @@ int beiscsi_iface_set_param(struct Scsi_Host *shost,
uint32_t rm_len = dt_len; uint32_t rm_len = dt_len;
int ret; int ret;
if (beiscsi_hba_in_error(phba)) { if (!beiscsi_hba_is_online(phba)) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BS_%d : HBA in error 0x%lx\n", phba->state); "BS_%d : HBA in error 0x%lx\n", phba->state);
return -EBUSY; return -EBUSY;
...@@ -587,7 +587,7 @@ int beiscsi_iface_get_param(struct iscsi_iface *iface, ...@@ -587,7 +587,7 @@ int beiscsi_iface_get_param(struct iscsi_iface *iface,
if (param_type != ISCSI_NET_PARAM) if (param_type != ISCSI_NET_PARAM)
return 0; return 0;
if (beiscsi_hba_in_error(phba)) { if (!beiscsi_hba_is_online(phba)) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BS_%d : HBA in error 0x%lx\n", phba->state); "BS_%d : HBA in error 0x%lx\n", phba->state);
return -EBUSY; return -EBUSY;
...@@ -797,7 +797,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost, ...@@ -797,7 +797,7 @@ int beiscsi_get_host_param(struct Scsi_Host *shost,
struct beiscsi_hba *phba = iscsi_host_priv(shost); struct beiscsi_hba *phba = iscsi_host_priv(shost);
int status = 0; int status = 0;
if (beiscsi_hba_in_error(phba)) { if (!beiscsi_hba_is_online(phba)) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BS_%d : HBA in error 0x%lx\n", phba->state); "BS_%d : HBA in error 0x%lx\n", phba->state);
return -EBUSY; return -EBUSY;
...@@ -945,7 +945,7 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) ...@@ -945,7 +945,7 @@ int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
phba = ((struct beiscsi_conn *)conn->dd_data)->phba; phba = ((struct beiscsi_conn *)conn->dd_data)->phba;
if (beiscsi_hba_in_error(phba)) { if (!beiscsi_hba_is_online(phba)) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BS_%d : HBA in error 0x%lx\n", phba->state); "BS_%d : HBA in error 0x%lx\n", phba->state);
return -EBUSY; return -EBUSY;
...@@ -1175,7 +1175,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, ...@@ -1175,7 +1175,7 @@ beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
} }
phba = iscsi_host_priv(shost); phba = iscsi_host_priv(shost);
if (beiscsi_hba_in_error(phba)) { if (!beiscsi_hba_is_online(phba)) {
ret = -EIO; ret = -EIO;
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BS_%d : HBA in error 0x%lx\n", phba->state); "BS_%d : HBA in error 0x%lx\n", phba->state);
...@@ -1335,7 +1335,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) ...@@ -1335,7 +1335,7 @@ void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
tcp_upload_flag = CONNECTION_UPLOAD_ABORT; tcp_upload_flag = CONNECTION_UPLOAD_ABORT;
} }
if (beiscsi_hba_in_error(phba)) { if (!beiscsi_hba_is_online(phba)) {
beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG, beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
"BS_%d : HBA in error 0x%lx\n", phba->state); "BS_%d : HBA in error 0x%lx\n", phba->state);
goto free_ep; goto free_ep;
......
This diff is collapsed.
...@@ -393,7 +393,7 @@ struct beiscsi_hba { ...@@ -393,7 +393,7 @@ struct beiscsi_hba {
} fw_config; } fw_config;
unsigned long state; unsigned long state;
#define BEISCSI_HBA_RUNNING 0 #define BEISCSI_HBA_ONLINE 0
#define BEISCSI_HBA_LINK_UP 1 #define BEISCSI_HBA_LINK_UP 1
#define BEISCSI_HBA_BOOT_FOUND 2 #define BEISCSI_HBA_BOOT_FOUND 2
#define BEISCSI_HBA_BOOT_WORK 3 #define BEISCSI_HBA_BOOT_WORK 3
...@@ -417,6 +417,7 @@ struct beiscsi_hba { ...@@ -417,6 +417,7 @@ struct beiscsi_hba {
/* check for UE every 1000ms */ /* check for UE every 1000ms */
#define BEISCSI_UE_DETECT_INTERVAL 1000 #define BEISCSI_UE_DETECT_INTERVAL 1000
u32 ue2rp; u32 ue2rp;
struct delayed_work recover_port;
bool mac_addr_set; bool mac_addr_set;
u8 mac_address[ETH_ALEN]; u8 mac_address[ETH_ALEN];
...@@ -455,6 +456,9 @@ struct beiscsi_hba { ...@@ -455,6 +456,9 @@ struct beiscsi_hba {
}; };
#define beiscsi_hba_in_error(phba) ((phba)->state & BEISCSI_HBA_IN_ERR) #define beiscsi_hba_in_error(phba) ((phba)->state & BEISCSI_HBA_IN_ERR)
#define beiscsi_hba_is_online(phba) \
(!beiscsi_hba_in_error((phba)) && \
test_bit(BEISCSI_HBA_ONLINE, &phba->state))
struct beiscsi_session { struct beiscsi_session {
struct pci_pool *bhs_pool; struct pci_pool *bhs_pool;
......
...@@ -24,134 +24,6 @@ ...@@ -24,134 +24,6 @@
#include "be_iscsi.h" #include "be_iscsi.h"
#include "be_main.h" #include "be_main.h"
/* UE Status Low CSR */
static const char * const desc_ue_status_low[] = {
"CEV",
"CTX",
"DBUF",
"ERX",
"Host",
"MPU",
"NDMA",
"PTC ",
"RDMA ",
"RXF ",
"RXIPS ",
"RXULP0 ",
"RXULP1 ",
"RXULP2 ",
"TIM ",
"TPOST ",
"TPRE ",
"TXIPS ",
"TXULP0 ",
"TXULP1 ",
"UC ",
"WDMA ",
"TXULP2 ",
"HOST1 ",
"P0_OB_LINK ",
"P1_OB_LINK ",
"HOST_GPIO ",
"MBOX ",
"AXGMAC0",
"AXGMAC1",
"JTAG",
"MPU_INTPEND"
};
/* UE Status High CSR */
static const char * const desc_ue_status_hi[] = {
"LPCMEMHOST",
"MGMT_MAC",
"PCS0ONLINE",
"MPU_IRAM",
"PCS1ONLINE",
"PCTL0",
"PCTL1",
"PMEM",
"RR",
"TXPB",
"RXPP",
"XAUI",
"TXP",
"ARM",
"IPC",
"HOST2",
"HOST3",
"HOST4",
"HOST5",
"HOST6",
"HOST7",
"HOST8",
"HOST9",
"NETC",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown"
};
/*
* beiscsi_ue_detect()- Detect Unrecoverable Error on adapter
* @phba: Driver priv structure
*
* Read registers linked to UE and check for the UE status
**/
void beiscsi_ue_detect(struct beiscsi_hba *phba)
{
uint32_t ue_hi = 0, ue_lo = 0;
uint32_t ue_mask_hi = 0, ue_mask_lo = 0;
uint8_t i = 0;
pci_read_config_dword(phba->pcidev,
PCICFG_UE_STATUS_LOW, &ue_lo);
pci_read_config_dword(phba->pcidev,
PCICFG_UE_STATUS_MASK_LOW,
&ue_mask_lo);
pci_read_config_dword(phba->pcidev,
PCICFG_UE_STATUS_HIGH,
&ue_hi);
pci_read_config_dword(phba->pcidev,
PCICFG_UE_STATUS_MASK_HI,
&ue_mask_hi);
ue_lo = (ue_lo & ~ue_mask_lo);
ue_hi = (ue_hi & ~ue_mask_hi);
if (ue_lo || ue_hi) {
set_bit(BEISCSI_HBA_IN_UE, &phba->state);
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG | BEISCSI_LOG_MBOX,
"BG_%d : HBA error detected\n");
}
if (ue_lo) {
for (i = 0; ue_lo; ue_lo >>= 1, i++) {
if (ue_lo & 1)
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG,
"BG_%d : UE_LOW %s bit set\n",
desc_ue_status_low[i]);
}
}
if (ue_hi) {
for (i = 0; ue_hi; ue_hi >>= 1, i++) {
if (ue_hi & 1)
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_CONFIG,
"BG_%d : UE_HIGH %s bit set\n",
desc_ue_status_hi[i]);
}
}
}
int beiscsi_modify_eq_delay(struct beiscsi_hba *phba, int beiscsi_modify_eq_delay(struct beiscsi_hba *phba,
struct be_set_eqd *set_eqd, struct be_set_eqd *set_eqd,
int num) int num)
......
...@@ -329,7 +329,6 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params, ...@@ -329,7 +329,6 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
struct wrb_handle *pwrb_handle, struct wrb_handle *pwrb_handle,
struct hwi_wrb_context *pwrb_context); struct hwi_wrb_context *pwrb_context);
void beiscsi_ue_detect(struct beiscsi_hba *phba);
int be_cmd_modify_eq_delay(struct beiscsi_hba *phba, int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
struct be_set_eqd *, int num); struct be_set_eqd *, int num);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment