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 06:25:50 -0400 |
commit | 9a347ff404d786d044ed09a4ec9a38ca70e8c803 (patch) | |
tree | 699ff5a897129337de90f7439948b7b54f441195 /drivers/scsi/qla2xxx | |
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>
Diffstat (limited to 'drivers/scsi/qla2xxx')
-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 ce42288049b5..f4b8a5f7840a 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c | |||
@@ -2564,7 +2564,15 @@ void | |||
2564 | qla2x00_free_irqs(scsi_qla_host_t *vha) | 2564 | qla2x00_free_irqs(scsi_qla_host_t *vha) |
2565 | { | 2565 | { |
2566 | struct qla_hw_data *ha = vha->hw; | 2566 | struct qla_hw_data *ha = vha->hw; |
2567 | struct rsp_que *rsp = ha->rsp_q_map[0]; | 2567 | struct rsp_que *rsp; |
2568 | |||
2569 | /* | ||
2570 | * We need to check that ha->rsp_q_map is valid in case we are called | ||
2571 | * from a probe failure context. | ||
2572 | */ | ||
2573 | if (!ha->rsp_q_map || !ha->rsp_q_map[0]) | ||
2574 | return; | ||
2575 | rsp = ha->rsp_q_map[0]; | ||
2568 | 2576 | ||
2569 | if (ha->flags.msix_enabled) | 2577 | if (ha->flags.msix_enabled) |
2570 | qla24xx_disable_msix(ha); | 2578 | qla24xx_disable_msix(ha); |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 7db803377c64..2e6dd88fbf50 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 *); | |||
306 | static void qla2x00_mem_free(struct qla_hw_data *); | 306 | static void qla2x00_mem_free(struct qla_hw_data *); |
307 | 307 | ||
308 | /* -------------------------------------------------------------------------- */ | 308 | /* -------------------------------------------------------------------------- */ |
309 | static int qla2x00_alloc_queues(struct qla_hw_data *ha) | 309 | static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, |
310 | struct rsp_que *rsp) | ||
310 | { | 311 | { |
311 | scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); | 312 | scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); |
312 | ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues, | 313 | 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 | "Unable to allocate memory for response queue ptrs.\n"); | 325 | "Unable to allocate memory for response queue ptrs.\n"); |
325 | goto fail_rsp_map; | 326 | goto fail_rsp_map; |
326 | } | 327 | } |
328 | /* | ||
329 | * Make sure we record at least the request and response queue zero in | ||
330 | * case we need to free them if part of the probe fails. | ||
331 | */ | ||
332 | ha->rsp_q_map[0] = rsp; | ||
333 | ha->req_q_map[0] = req; | ||
327 | set_bit(0, ha->rsp_qid_map); | 334 | set_bit(0, ha->rsp_qid_map); |
328 | set_bit(0, ha->req_qid_map); | 335 | set_bit(0, ha->req_qid_map); |
329 | return 1; | 336 | return 1; |
@@ -2417,6 +2424,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2417 | host->max_cmd_len, host->max_channel, host->max_lun, | 2424 | host->max_cmd_len, host->max_channel, host->max_lun, |
2418 | host->transportt, sht->vendor_id); | 2425 | host->transportt, sht->vendor_id); |
2419 | 2426 | ||
2427 | que_init: | ||
2428 | /* Alloc arrays of request and response ring ptrs */ | ||
2429 | if (!qla2x00_alloc_queues(ha, req, rsp)) { | ||
2430 | ql_log(ql_log_fatal, base_vha, 0x003d, | ||
2431 | "Failed to allocate memory for queue pointers..." | ||
2432 | "aborting.\n"); | ||
2433 | goto probe_init_failed; | ||
2434 | } | ||
2435 | |||
2436 | |||
2420 | /* Set up the irqs */ | 2437 | /* Set up the irqs */ |
2421 | ret = qla2x00_request_irqs(ha, rsp); | 2438 | ret = qla2x00_request_irqs(ha, rsp); |
2422 | if (ret) | 2439 | if (ret) |
@@ -2424,20 +2441,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2424 | 2441 | ||
2425 | pci_save_state(pdev); | 2442 | pci_save_state(pdev); |
2426 | 2443 | ||
2427 | /* Alloc arrays of request and response ring ptrs */ | 2444 | /* Assign back pointers */ |
2428 | que_init: | ||
2429 | if (!qla2x00_alloc_queues(ha)) { | ||
2430 | ql_log(ql_log_fatal, base_vha, 0x003d, | ||
2431 | "Failed to allocate memory for queue pointers.. aborting.\n"); | ||
2432 | goto probe_init_failed; | ||
2433 | } | ||
2434 | |||
2435 | ha->rsp_q_map[0] = rsp; | ||
2436 | ha->req_q_map[0] = req; | ||
2437 | rsp->req = req; | 2445 | rsp->req = req; |
2438 | req->rsp = rsp; | 2446 | req->rsp = rsp; |
2439 | set_bit(0, ha->req_qid_map); | 2447 | |
2440 | set_bit(0, ha->rsp_qid_map); | ||
2441 | /* FWI2-capable only. */ | 2448 | /* FWI2-capable only. */ |
2442 | req->req_q_in = &ha->iobase->isp24.req_q_in; | 2449 | req->req_q_in = &ha->iobase->isp24.req_q_in; |
2443 | req->req_q_out = &ha->iobase->isp24.req_q_out; | 2450 | req->req_q_out = &ha->iobase->isp24.req_q_out; |
@@ -2581,7 +2588,11 @@ skip_dpc: | |||
2581 | 2588 | ||
2582 | probe_init_failed: | 2589 | probe_init_failed: |
2583 | qla2x00_free_req_que(ha, req); | 2590 | qla2x00_free_req_que(ha, req); |
2591 | ha->req_q_map[0] = NULL; | ||
2592 | clear_bit(0, ha->req_qid_map); | ||
2584 | qla2x00_free_rsp_que(ha, rsp); | 2593 | qla2x00_free_rsp_que(ha, rsp); |
2594 | ha->rsp_q_map[0] = NULL; | ||
2595 | clear_bit(0, ha->rsp_qid_map); | ||
2585 | ha->max_req_queues = ha->max_rsp_queues = 0; | 2596 | ha->max_req_queues = ha->max_rsp_queues = 0; |
2586 | 2597 | ||
2587 | probe_failed: | 2598 | probe_failed: |
@@ -2663,6 +2674,13 @@ qla2x00_remove_one(struct pci_dev *pdev) | |||
2663 | struct qla_hw_data *ha; | 2674 | struct qla_hw_data *ha; |
2664 | unsigned long flags; | 2675 | unsigned long flags; |
2665 | 2676 | ||
2677 | /* | ||
2678 | * If the PCI device is disabled that means that probe failed and any | ||
2679 | * resources should be have cleaned up on probe exit. | ||
2680 | */ | ||
2681 | if (!atomic_read(&pdev->enable_cnt)) | ||
2682 | return; | ||
2683 | |||
2666 | base_vha = pci_get_drvdata(pdev); | 2684 | base_vha = pci_get_drvdata(pdev); |
2667 | ha = base_vha->hw; | 2685 | ha = base_vha->hw; |
2668 | 2686 | ||