Commit 9a347ff4 authored by Chad Dupuis's avatar Chad Dupuis Committed by James Bottomley

[SCSI] qla2xxx: Handle interrupt registration failures more gracefully.

If interrupt registration failed we could crash the machine as we were trying
to deference some pointers which weren't allocated yet.  Move the allocation
a little earlier and make some checks to the free resource code to make sure
that we don't try to free a resource that was never allocated.
Signed-off-by: default avatarGiridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: default avatarChad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 01b6585d
...@@ -2564,7 +2564,15 @@ void ...@@ -2564,7 +2564,15 @@ void
qla2x00_free_irqs(scsi_qla_host_t *vha) qla2x00_free_irqs(scsi_qla_host_t *vha)
{ {
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
struct rsp_que *rsp = ha->rsp_q_map[0]; struct rsp_que *rsp;
/*
* We need to check that ha->rsp_q_map is valid in case we are called
* from a probe failure context.
*/
if (!ha->rsp_q_map || !ha->rsp_q_map[0])
return;
rsp = ha->rsp_q_map[0];
if (ha->flags.msix_enabled) if (ha->flags.msix_enabled)
qla24xx_disable_msix(ha); qla24xx_disable_msix(ha);
......
...@@ -306,7 +306,8 @@ static void qla2x00_free_fw_dump(struct qla_hw_data *); ...@@ -306,7 +306,8 @@ static void qla2x00_free_fw_dump(struct qla_hw_data *);
static void qla2x00_mem_free(struct qla_hw_data *); static void qla2x00_mem_free(struct qla_hw_data *);
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
static int qla2x00_alloc_queues(struct qla_hw_data *ha) static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req,
struct rsp_que *rsp)
{ {
scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues, ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues,
...@@ -324,6 +325,12 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha) ...@@ -324,6 +325,12 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha)
"Unable to allocate memory for response queue ptrs.\n"); "Unable to allocate memory for response queue ptrs.\n");
goto fail_rsp_map; goto fail_rsp_map;
} }
/*
* Make sure we record at least the request and response queue zero in
* case we need to free them if part of the probe fails.
*/
ha->rsp_q_map[0] = rsp;
ha->req_q_map[0] = req;
set_bit(0, ha->rsp_qid_map); set_bit(0, ha->rsp_qid_map);
set_bit(0, ha->req_qid_map); set_bit(0, ha->req_qid_map);
return 1; return 1;
...@@ -2417,6 +2424,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -2417,6 +2424,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
host->max_cmd_len, host->max_channel, host->max_lun, host->max_cmd_len, host->max_channel, host->max_lun,
host->transportt, sht->vendor_id); host->transportt, sht->vendor_id);
que_init:
/* Alloc arrays of request and response ring ptrs */
if (!qla2x00_alloc_queues(ha, req, rsp)) {
ql_log(ql_log_fatal, base_vha, 0x003d,
"Failed to allocate memory for queue pointers..."
"aborting.\n");
goto probe_init_failed;
}
/* Set up the irqs */ /* Set up the irqs */
ret = qla2x00_request_irqs(ha, rsp); ret = qla2x00_request_irqs(ha, rsp);
if (ret) if (ret)
...@@ -2424,20 +2441,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -2424,20 +2441,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
pci_save_state(pdev); pci_save_state(pdev);
/* Alloc arrays of request and response ring ptrs */ /* Assign back pointers */
que_init:
if (!qla2x00_alloc_queues(ha)) {
ql_log(ql_log_fatal, base_vha, 0x003d,
"Failed to allocate memory for queue pointers.. aborting.\n");
goto probe_init_failed;
}
ha->rsp_q_map[0] = rsp;
ha->req_q_map[0] = req;
rsp->req = req; rsp->req = req;
req->rsp = rsp; req->rsp = rsp;
set_bit(0, ha->req_qid_map);
set_bit(0, ha->rsp_qid_map);
/* FWI2-capable only. */ /* FWI2-capable only. */
req->req_q_in = &ha->iobase->isp24.req_q_in; req->req_q_in = &ha->iobase->isp24.req_q_in;
req->req_q_out = &ha->iobase->isp24.req_q_out; req->req_q_out = &ha->iobase->isp24.req_q_out;
...@@ -2581,7 +2588,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -2581,7 +2588,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
probe_init_failed: probe_init_failed:
qla2x00_free_req_que(ha, req); qla2x00_free_req_que(ha, req);
ha->req_q_map[0] = NULL;
clear_bit(0, ha->req_qid_map);
qla2x00_free_rsp_que(ha, rsp); qla2x00_free_rsp_que(ha, rsp);
ha->rsp_q_map[0] = NULL;
clear_bit(0, ha->rsp_qid_map);
ha->max_req_queues = ha->max_rsp_queues = 0; ha->max_req_queues = ha->max_rsp_queues = 0;
probe_failed: probe_failed:
...@@ -2663,6 +2674,13 @@ qla2x00_remove_one(struct pci_dev *pdev) ...@@ -2663,6 +2674,13 @@ qla2x00_remove_one(struct pci_dev *pdev)
struct qla_hw_data *ha; struct qla_hw_data *ha;
unsigned long flags; unsigned long flags;
/*
* If the PCI device is disabled that means that probe failed and any
* resources should be have cleaned up on probe exit.
*/
if (!atomic_read(&pdev->enable_cnt))
return;
base_vha = pci_get_drvdata(pdev); base_vha = pci_get_drvdata(pdev);
ha = base_vha->hw; ha = base_vha->hw;
......
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