diff options
author | Chad Dupuis <chad.dupuis@qlogic.com> | 2012-05-15 14:34:14 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-05-22 11:25:50 +0100 |
commit | 9a347ff404d786d044ed09a4ec9a38ca70e8c803 (patch) | |
tree | 699ff5a897129337de90f7439948b7b54f441195 | |
parent | 01b6585d8af737a82b45ca22a938f2a930659775 (diff) |
[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: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 10 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 44 |
2 files changed, 40 insertions, 14 deletions
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ce42288049b..f4b8a5f7840 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2564,7 +2564,15 @@ void qla2x00_free_irqs(scsi_qla_host_t *vha) { 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) qla24xx_disable_msix(ha); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 7db803377c6..2e6dd88fbf5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -306,7 +306,8 @@ static void qla2x00_free_fw_dump(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); 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) "Unable to allocate memory for response queue ptrs.\n"); 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->req_qid_map); return 1; @@ -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->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 */ ret = qla2x00_request_irqs(ha, rsp); if (ret) @@ -2424,20 +2441,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pci_save_state(pdev); - /* Alloc arrays of request and response ring ptrs */ -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; + /* Assign back pointers */ rsp->req = req; req->rsp = rsp; - set_bit(0, ha->req_qid_map); - set_bit(0, ha->rsp_qid_map); + /* FWI2-capable only. */ req->req_q_in = &ha->iobase->isp24.req_q_in; req->req_q_out = &ha->iobase->isp24.req_q_out; @@ -2581,7 +2588,11 @@ skip_dpc: probe_init_failed: 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); + ha->rsp_q_map[0] = NULL; + clear_bit(0, ha->rsp_qid_map); ha->max_req_queues = ha->max_rsp_queues = 0; probe_failed: @@ -2663,6 +2674,13 @@ qla2x00_remove_one(struct pci_dev *pdev) struct qla_hw_data *ha; 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); ha = base_vha->hw; |