Commit ad40f525 authored by Chad Dupuis's avatar Chad Dupuis Committed by Martin K. Petersen

scsi: qedf: Fix crash when MFW calls for protocol stats while function is still probing

The MFW may make a call to qed and then to qedf for protocol statistics
while the function is still probing.  If this happens it's possible that
some members of the struct qedf_ctx may not be fully initialized which can
result in a NULL pointer dereference or general protection fault.

To prevent this, add a new flag call QEDF_PROBING and set it when the
__qedf_probe() function is active. Then in the qedf_get_protocol_tlv_data()
function we can check if the function is still probing and return
immediantely before any uninitialized structures can be touched.

Link: https://lore.kernel.org/r/20200416084314.18851-9-skashyap@marvell.comSigned-off-by: default avatarChad Dupuis <cdupuis@marvell.com>
Signed-off-by: default avatarSaurav Kashyap <skashyap@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent f6b172f2
...@@ -355,6 +355,7 @@ struct qedf_ctx { ...@@ -355,6 +355,7 @@ struct qedf_ctx {
#define QEDF_GRCDUMP_CAPTURE 4 #define QEDF_GRCDUMP_CAPTURE 4
#define QEDF_IN_RECOVERY 5 #define QEDF_IN_RECOVERY 5
#define QEDF_DBG_STOP_IO 6 #define QEDF_DBG_STOP_IO 6
#define QEDF_PROBING 8
unsigned long flags; /* Miscellaneous state flags */ unsigned long flags; /* Miscellaneous state flags */
int fipvlan_retries; int fipvlan_retries;
u8 num_queues; u8 num_queues;
......
...@@ -3190,7 +3190,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) ...@@ -3190,7 +3190,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
{ {
int rc = -EINVAL; int rc = -EINVAL;
struct fc_lport *lport; struct fc_lport *lport;
struct qedf_ctx *qedf; struct qedf_ctx *qedf = NULL;
struct Scsi_Host *host; struct Scsi_Host *host;
bool is_vf = false; bool is_vf = false;
struct qed_ll2_params params; struct qed_ll2_params params;
...@@ -3220,6 +3220,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) ...@@ -3220,6 +3220,7 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
/* Initialize qedf_ctx */ /* Initialize qedf_ctx */
qedf = lport_priv(lport); qedf = lport_priv(lport);
set_bit(QEDF_PROBING, &qedf->flags);
qedf->lport = lport; qedf->lport = lport;
qedf->ctlr.lp = lport; qedf->ctlr.lp = lport;
qedf->pdev = pdev; qedf->pdev = pdev;
...@@ -3244,9 +3245,12 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) ...@@ -3244,9 +3245,12 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
} else { } else {
/* Init pointers during recovery */ /* Init pointers during recovery */
qedf = pci_get_drvdata(pdev); qedf = pci_get_drvdata(pdev);
set_bit(QEDF_PROBING, &qedf->flags);
lport = qedf->lport; lport = qedf->lport;
} }
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe started.\n");
host = lport->host; host = lport->host;
/* Allocate mempool for qedf_io_work structs */ /* Allocate mempool for qedf_io_work structs */
...@@ -3553,6 +3557,10 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) ...@@ -3553,6 +3557,10 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
else else
fc_fabric_login(lport); fc_fabric_login(lport);
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe done.\n");
clear_bit(QEDF_PROBING, &qedf->flags);
/* All good */ /* All good */
return 0; return 0;
...@@ -3578,6 +3586,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode) ...@@ -3578,6 +3586,11 @@ static int __qedf_probe(struct pci_dev *pdev, int mode)
err1: err1:
scsi_host_put(lport->host); scsi_host_put(lport->host);
err0: err0:
if (qedf) {
QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC, "Probe done.\n");
clear_bit(QEDF_PROBING, &qedf->flags);
}
return rc; return rc;
} }
...@@ -3727,11 +3740,25 @@ void qedf_get_protocol_tlv_data(void *dev, void *data) ...@@ -3727,11 +3740,25 @@ void qedf_get_protocol_tlv_data(void *dev, void *data)
{ {
struct qedf_ctx *qedf = dev; struct qedf_ctx *qedf = dev;
struct qed_mfw_tlv_fcoe *fcoe = data; struct qed_mfw_tlv_fcoe *fcoe = data;
struct fc_lport *lport = qedf->lport; struct fc_lport *lport;
struct Scsi_Host *host = lport->host; struct Scsi_Host *host;
struct fc_host_attrs *fc_host = shost_to_fc_host(host); struct fc_host_attrs *fc_host;
struct fc_host_statistics *hst; struct fc_host_statistics *hst;
if (!qedf) {
QEDF_ERR(NULL, "qedf is null.\n");
return;
}
if (test_bit(QEDF_PROBING, &qedf->flags)) {
QEDF_ERR(&qedf->dbg_ctx, "Function is still probing.\n");
return;
}
lport = qedf->lport;
host = lport->host;
fc_host = shost_to_fc_host(host);
/* Force a refresh of the fc_host stats including offload stats */ /* Force a refresh of the fc_host stats including offload stats */
hst = qedf_fc_get_host_stats(host); hst = qedf_fc_get_host_stats(host);
......
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