Skip to content

Commit 4b1068f

Browse files
mrangankarmartinkpetersen
authored andcommitted
scsi: qedi: Add MFW error recovery process
This patch adds the mfw error recovery process in the qedi driver. The process includes a partial/customized driver unload and load to reset context by preserving active iSCSI session kernel state. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Manish Rangankar <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent fb276f7 commit 4b1068f

File tree

2 files changed

+66
-22
lines changed

2 files changed

+66
-22
lines changed

drivers/scsi/qedi/qedi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ struct qedi_ctx {
331331
u16 ll2_mtu;
332332

333333
struct workqueue_struct *dpc_wq;
334+
struct delayed_work recovery_work;
334335

335336
spinlock_t task_idx_lock; /* To protect gbl context */
336337
s32 last_tidx_alloc;

drivers/scsi/qedi/qedi_main.c

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ static struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid);
5858
static void qedi_reset_uio_rings(struct qedi_uio_dev *udev);
5959
static void qedi_ll2_free_skbs(struct qedi_ctx *qedi);
6060
static struct nvm_iscsi_block *qedi_get_nvram_block(struct qedi_ctx *qedi);
61+
static void qedi_recovery_handler(struct work_struct *work);
6162

6263
static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle)
6364
{
@@ -1113,6 +1114,20 @@ static void qedi_get_protocol_tlv_data(void *dev, void *data)
11131114
return;
11141115
}
11151116

1117+
static void qedi_schedule_recovery_handler(void *dev)
1118+
{
1119+
struct qedi_ctx *qedi = dev;
1120+
1121+
QEDI_ERR(&qedi->dbg_ctx, "Recovery handler scheduled.\n");
1122+
1123+
if (test_and_set_bit(QEDI_IN_RECOVERY, &qedi->flags))
1124+
return;
1125+
1126+
atomic_set(&qedi->link_state, QEDI_LINK_DOWN);
1127+
1128+
schedule_delayed_work(&qedi->recovery_work, 0);
1129+
}
1130+
11161131
static void qedi_link_update(void *dev, struct qed_link_output *link)
11171132
{
11181133
struct qedi_ctx *qedi = (struct qedi_ctx *)dev;
@@ -1130,6 +1145,7 @@ static void qedi_link_update(void *dev, struct qed_link_output *link)
11301145
static struct qed_iscsi_cb_ops qedi_cb_ops = {
11311146
{
11321147
.link_update = qedi_link_update,
1148+
.schedule_recovery_handler = qedi_schedule_recovery_handler,
11331149
.get_protocol_tlv_data = qedi_get_protocol_tlv_data,
11341150
.get_generic_tlv_data = qedi_get_generic_tlv_data,
11351151
}
@@ -2328,16 +2344,18 @@ static void __qedi_remove(struct pci_dev *pdev, int mode)
23282344
struct qedi_ctx *qedi = pci_get_drvdata(pdev);
23292345
int rval;
23302346

2331-
if (qedi->tmf_thread) {
2332-
flush_workqueue(qedi->tmf_thread);
2333-
destroy_workqueue(qedi->tmf_thread);
2334-
qedi->tmf_thread = NULL;
2335-
}
2347+
if (mode == QEDI_MODE_NORMAL) {
2348+
if (qedi->tmf_thread) {
2349+
flush_workqueue(qedi->tmf_thread);
2350+
destroy_workqueue(qedi->tmf_thread);
2351+
qedi->tmf_thread = NULL;
2352+
}
23362353

2337-
if (qedi->offload_thread) {
2338-
flush_workqueue(qedi->offload_thread);
2339-
destroy_workqueue(qedi->offload_thread);
2340-
qedi->offload_thread = NULL;
2354+
if (qedi->offload_thread) {
2355+
flush_workqueue(qedi->offload_thread);
2356+
destroy_workqueue(qedi->offload_thread);
2357+
qedi->offload_thread = NULL;
2358+
}
23412359
}
23422360

23432361
#ifdef CONFIG_DEBUG_FS
@@ -2353,8 +2371,7 @@ static void __qedi_remove(struct pci_dev *pdev, int mode)
23532371
qedi_ops->ll2->stop(qedi->cdev);
23542372
}
23552373

2356-
if (mode == QEDI_MODE_NORMAL)
2357-
qedi_free_iscsi_pf_param(qedi);
2374+
qedi_free_iscsi_pf_param(qedi);
23582375

23592376
rval = qedi_ops->common->update_drv_state(qedi->cdev, false);
23602377
if (rval)
@@ -2373,9 +2390,6 @@ static void __qedi_remove(struct pci_dev *pdev, int mode)
23732390
qedi_free_uio(qedi->udev);
23742391
qedi_free_itt(qedi);
23752392

2376-
iscsi_host_remove(qedi->shost);
2377-
iscsi_host_free(qedi->shost);
2378-
23792393
if (qedi->ll2_recv_thread) {
23802394
kthread_stop(qedi->ll2_recv_thread);
23812395
qedi->ll2_recv_thread = NULL;
@@ -2384,6 +2398,9 @@ static void __qedi_remove(struct pci_dev *pdev, int mode)
23842398

23852399
if (qedi->boot_kset)
23862400
iscsi_boot_destroy_kset(qedi->boot_kset);
2401+
2402+
iscsi_host_remove(qedi->shost);
2403+
iscsi_host_free(qedi->shost);
23872404
}
23882405
}
23892406

@@ -2435,14 +2452,12 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
24352452
qedi->dev_info.common.num_hwfns,
24362453
qedi_ops->common->get_affin_hwfn_idx(qedi->cdev));
24372454

2438-
if (mode != QEDI_MODE_RECOVERY) {
2439-
rc = qedi_set_iscsi_pf_param(qedi);
2440-
if (rc) {
2441-
rc = -ENOMEM;
2442-
QEDI_ERR(&qedi->dbg_ctx,
2443-
"Set iSCSI pf param fail\n");
2444-
goto free_host;
2445-
}
2455+
rc = qedi_set_iscsi_pf_param(qedi);
2456+
if (rc) {
2457+
rc = -ENOMEM;
2458+
QEDI_ERR(&qedi->dbg_ctx,
2459+
"Set iSCSI pf param fail\n");
2460+
goto free_host;
24462461
}
24472462

24482463
qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params);
@@ -2633,6 +2648,8 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
26332648
goto free_cid_que;
26342649
}
26352650

2651+
INIT_DELAYED_WORK(&qedi->recovery_work, qedi_recovery_handler);
2652+
26362653
/* F/w needs 1st task context memory entry for performance */
26372654
set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map);
26382655
atomic_set(&qedi->num_offloads, 0);
@@ -2673,6 +2690,32 @@ static int __qedi_probe(struct pci_dev *pdev, int mode)
26732690
return rc;
26742691
}
26752692

2693+
static void qedi_mark_conn_recovery(struct iscsi_cls_session *cls_session)
2694+
{
2695+
struct iscsi_session *session = cls_session->dd_data;
2696+
struct iscsi_conn *conn = session->leadconn;
2697+
struct qedi_conn *qedi_conn = conn->dd_data;
2698+
2699+
iscsi_conn_failure(qedi_conn->cls_conn->dd_data, ISCSI_ERR_CONN_FAILED);
2700+
}
2701+
2702+
static void qedi_recovery_handler(struct work_struct *work)
2703+
{
2704+
struct qedi_ctx *qedi =
2705+
container_of(work, struct qedi_ctx, recovery_work.work);
2706+
2707+
iscsi_host_for_each_session(qedi->shost, qedi_mark_conn_recovery);
2708+
2709+
/* Call common_ops->recovery_prolog to allow the MFW to quiesce
2710+
* any PCI transactions.
2711+
*/
2712+
qedi_ops->common->recovery_prolog(qedi->cdev);
2713+
2714+
__qedi_remove(qedi->pdev, QEDI_MODE_RECOVERY);
2715+
__qedi_probe(qedi->pdev, QEDI_MODE_RECOVERY);
2716+
clear_bit(QEDI_IN_RECOVERY, &qedi->flags);
2717+
}
2718+
26762719
static int qedi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
26772720
{
26782721
return __qedi_probe(pdev, QEDI_MODE_NORMAL);

0 commit comments

Comments
 (0)