summaryrefslogtreecommitdiff
path: root/drivers/scsi/be2iscsi/be_main.c
diff options
context:
space:
mode:
authorJitendra Bhivare <jitendra.bhivare@broadcom.com>2016-08-19 09:50:11 (GMT)
committerMartin K. Petersen <martin.petersen@oracle.com>2016-08-24 02:42:43 (GMT)
commit9122e991cebb90a7225109ed7627950f485c5f58 (patch)
tree9e4037cf4b5eaa4a4336d3e8b74d36ffa45b021c /drivers/scsi/be2iscsi/be_main.c
parenta30950161954a046421b26fbf55a873ae27b1e25 (diff)
downloadlinux-9122e991cebb90a7225109ed7627950f485c5f58.tar.xz
scsi: be2iscsi: Fix checks for HBA in error state
Save ue_detected and fw_timeout errors in state field of beiscsi_hba. BEISCSI_HBA_RUNNING BEISCSI_HBA_LINK_UP BEISCSI_HBA_BOOT_FOUND BEISCSI_HBA_PCI_ERR BEISCSI_HBA_FW_TIMEOUT BEISCSI_HBA_IN_UE Make sure no PCI transaction happens once in error state. Add checks in IO path to detect HBA in error. Skip hwi_purge_eq step which can't be done in error state. Signed-off-by: Jitendra Bhivare <jitendra.bhivare@broadcom.com> Reviewed-by: Hannes Reinecke <hare@suse.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/be2iscsi/be_main.c')
-rw-r--r--drivers/scsi/be2iscsi/be_main.c97
1 files changed, 67 insertions, 30 deletions
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 6179c4e..22fcbea 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -2017,6 +2017,9 @@ void beiscsi_process_mcc_cq(struct beiscsi_hba *phba)
mcc_compl = queue_tail_node(mcc_cq);
mcc_compl->flags = le32_to_cpu(mcc_compl->flags);
while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) {
+ if (beiscsi_hba_in_error(phba))
+ return;
+
if (num_processed >= 32) {
hwi_ring_cq_db(phba, mcc_cq->id,
num_processed, 0);
@@ -2048,7 +2051,8 @@ static void beiscsi_mcc_work(struct work_struct *work)
phba = pbe_eq->phba;
beiscsi_process_mcc_cq(phba);
/* rearm EQ for further interrupts */
- hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
+ if (!beiscsi_hba_in_error(phba))
+ hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
}
/**
@@ -2079,6 +2083,9 @@ unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq, int budget)
while (sol->dw[offsetof(struct amap_sol_cqe, valid) / 32] &
CQE_VALID_MASK) {
+ if (beiscsi_hba_in_error(phba))
+ return 0;
+
be_dws_le_to_cpu(sol, sizeof(struct sol_cqe));
code = (sol->dw[offsetof(struct amap_sol_cqe, code) /
@@ -2248,12 +2255,16 @@ static int be_iopoll(struct irq_poll *iop, int budget)
struct be_eq_entry *eqe = NULL;
struct be_queue_info *eq;
- io_events = 0;
pbe_eq = container_of(iop, struct be_eq_obj, iopoll);
phba = pbe_eq->phba;
+ if (beiscsi_hba_in_error(phba)) {
+ irq_poll_complete(iop);
+ return 0;
+ }
+
+ io_events = 0;
eq = &pbe_eq->q;
eqe = queue_tail_node(eq);
-
while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] &
EQE_VALID_MASK) {
AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
@@ -2261,7 +2272,6 @@ static int be_iopoll(struct irq_poll *iop, int budget)
eqe = queue_tail_node(eq);
io_events++;
}
-
hwi_ring_eq_db(phba, eq->id, 1, io_events, 0, 1);
ret = beiscsi_process_cq(pbe_eq, budget);
@@ -2272,7 +2282,8 @@ static int be_iopoll(struct irq_poll *iop, int budget)
BEISCSI_LOG_CONFIG | BEISCSI_LOG_IO,
"BM_%d : rearm pbe_eq->q.id =%d ret %d\n",
pbe_eq->q.id, ret);
- hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
+ if (!beiscsi_hba_in_error(phba))
+ hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1);
}
return ret;
}
@@ -4633,7 +4644,8 @@ static void beiscsi_cleanup_task(struct iscsi_task *task)
}
if (io_task->scsi_cmnd) {
- scsi_dma_unmap(io_task->scsi_cmnd);
+ if (io_task->num_sg)
+ scsi_dma_unmap(io_task->scsi_cmnd);
io_task->scsi_cmnd = NULL;
}
} else {
@@ -5112,6 +5124,15 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
int num_sg;
unsigned int writedir = 0, xferlen = 0;
+ phba = io_task->conn->phba;
+ /**
+ * HBA in error includes BEISCSI_HBA_FW_TIMEOUT. IO path might be
+ * operational if FW still gets heartbeat from EP FW. Is management
+ * path really needed to continue further?
+ */
+ if (beiscsi_hba_in_error(phba))
+ return -EIO;
+
if (!io_task->conn->login_in_progress)
task->hdr->exp_statsn = 0;
@@ -5119,8 +5140,8 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
return beiscsi_mtask(task);
io_task->scsi_cmnd = sc;
+ io_task->num_sg = 0;
num_sg = scsi_dma_map(sc);
- phba = io_task->conn->phba;
if (num_sg < 0) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_ISCSI,
@@ -5131,6 +5152,11 @@ static int beiscsi_task_xmit(struct iscsi_task *task)
return num_sg;
}
+ /**
+ * For scsi cmd task, check num_sg before unmapping in cleanup_task.
+ * For management task, cleanup_task checks mtask_addr before unmapping.
+ */
+ io_task->num_sg = num_sg;
xferlen = scsi_bufflen(sc);
sg = scsi_sglist(sc);
if (sc->sc_data_direction == DMA_TO_DEVICE)
@@ -5160,6 +5186,12 @@ static int beiscsi_bsg_request(struct bsg_job *job)
shost = iscsi_job_to_shost(job);
phba = iscsi_host_priv(shost);
+ if (beiscsi_hba_in_error(phba)) {
+ beiscsi_log(phba, KERN_INFO, BEISCSI_LOG_CONFIG,
+ "BM_%d : HBA in error 0x%lx\n", phba->state);
+ return -ENXIO;
+ }
+
switch (bsg_req->msgcode) {
case ISCSI_BSG_HST_VENDOR:
nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev,
@@ -5233,12 +5265,10 @@ void beiscsi_hba_attrs_init(struct beiscsi_hba *phba)
/*
* beiscsi_quiesce()- Cleanup Driver resources
* @phba: Instance Priv structure
- * @unload_state:i Clean or EEH unload state
*
* Free the OS and HW resources held by the driver
**/
-static void beiscsi_quiesce(struct beiscsi_hba *phba,
- uint32_t unload_state)
+static void beiscsi_quiesce(struct beiscsi_hba *phba)
{
struct hwi_controller *phwi_ctrlr;
struct hwi_context_memory *phwi_context;
@@ -5265,21 +5295,22 @@ static void beiscsi_quiesce(struct beiscsi_hba *phba,
irq_poll_disable(&pbe_eq->iopoll);
}
- if (unload_state == BEISCSI_CLEAN_UNLOAD) {
- destroy_workqueue(phba->wq);
- beiscsi_clean_port(phba);
- beiscsi_free_mem(phba);
-
- beiscsi_unmap_pci_function(phba);
- pci_free_consistent(phba->pcidev,
- phba->ctrl.mbox_mem_alloced.size,
- phba->ctrl.mbox_mem_alloced.va,
- phba->ctrl.mbox_mem_alloced.dma);
- } else {
- hwi_purge_eq(phba);
+ /* PCI_ERR is set then check if driver is not unloading */
+ if (test_bit(BEISCSI_HBA_RUNNING, &phba->state) &&
+ test_bit(BEISCSI_HBA_PCI_ERR, &phba->state)) {
hwi_cleanup(phba);
+ return;
}
+ destroy_workqueue(phba->wq);
+ beiscsi_clean_port(phba);
+ beiscsi_free_mem(phba);
+
+ beiscsi_unmap_pci_function(phba);
+ pci_free_consistent(phba->pcidev,
+ phba->ctrl.mbox_mem_alloced.size,
+ phba->ctrl.mbox_mem_alloced.va,
+ phba->ctrl.mbox_mem_alloced.dma);
}
static void beiscsi_remove(struct pci_dev *pcidev)
@@ -5292,10 +5323,11 @@ static void beiscsi_remove(struct pci_dev *pcidev)
return;
}
+ clear_bit(BEISCSI_HBA_RUNNING, &phba->state);
beiscsi_iface_destroy_default(phba);
iscsi_boot_destroy_kset(phba->boot_kset);
iscsi_host_remove(phba->shost);
- beiscsi_quiesce(phba, BEISCSI_CLEAN_UNLOAD);
+ beiscsi_quiesce(phba);
pci_dev_put(phba->pcidev);
iscsi_host_free(phba->shost);
pci_disable_pcie_error_reporting(pcidev);
@@ -5331,6 +5363,9 @@ static void be_eqd_update(struct beiscsi_hba *phba)
u32 pps, delta;
unsigned int tag;
+ if (beiscsi_hba_in_error(phba))
+ return;
+
phwi_ctrlr = phba->phwi_ctrlr;
phwi_context = phwi_ctrlr->phwi_ctxt;
@@ -5372,6 +5407,9 @@ static void be_eqd_update(struct beiscsi_hba *phba)
static void be_check_boot_session(struct beiscsi_hba *phba)
{
+ if (beiscsi_hba_in_error(phba))
+ return;
+
if (beiscsi_setup_boot_info(phba))
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BM_%d : Could not set up "
@@ -5393,13 +5431,13 @@ beiscsi_hw_health_check(struct work_struct *work)
be_eqd_update(phba);
- if (phba->state & BE_ADAPTER_CHECK_BOOT) {
+ if (test_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state)) {
if ((phba->get_boot > 0) && (!phba->boot_kset)) {
phba->get_boot--;
if (!(phba->get_boot % BE_GET_BOOT_TO))
be_check_boot_session(phba);
} else {
- phba->state &= ~BE_ADAPTER_CHECK_BOOT;
+ clear_bit(BEISCSI_HBA_BOOT_FOUND, &phba->state);
phba->get_boot = 0;
}
}
@@ -5417,12 +5455,12 @@ static pci_ers_result_t beiscsi_eeh_err_detected(struct pci_dev *pdev,
struct beiscsi_hba *phba = NULL;
phba = (struct beiscsi_hba *)pci_get_drvdata(pdev);
- phba->state |= BE_ADAPTER_PCI_ERR;
+ set_bit(BEISCSI_HBA_PCI_ERR, &phba->state);
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
"BM_%d : EEH error detected\n");
- beiscsi_quiesce(phba, BEISCSI_EEH_UNLOAD);
+ beiscsi_quiesce(phba);
if (state == pci_channel_io_perm_failure) {
beiscsi_log(phba, KERN_ERR, BEISCSI_LOG_INIT,
@@ -5554,7 +5592,7 @@ static void beiscsi_eeh_resume(struct pci_dev *pdev)
}
hwi_enable_intr(phba);
- phba->state &= ~BE_ADAPTER_PCI_ERR;
+ clear_bit(BEISCSI_HBA_PCI_ERR, &phba->state);
return;
ret_err:
@@ -5597,10 +5635,8 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
/* Initialize Driver configuration Paramters */
beiscsi_hba_attrs_init(phba);
- phba->fw_timeout = false;
phba->mac_addr_set = false;
-
switch (pcidev->device) {
case BE_DEVICE_ID1:
case OC_DEVICE_ID1:
@@ -5629,6 +5665,7 @@ static int beiscsi_dev_probe(struct pci_dev *pcidev,
goto hba_free;
}
+ set_bit(BEISCSI_HBA_RUNNING, &phba->state);
/*
* FUNCTION_RESET should clean up any stale info in FW for this fn
*/