Skip to content

Commit

Permalink
[SCSI] qla2xxx: Handle interrupt registration failures more gracefully.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Chad Dupuis <[email protected]>
Signed-off-by: James Bottomley <[email protected]>
  • Loading branch information
Chad Dupuis authored and James Bottomley committed May 22, 2012
1 parent 01b6585 commit 9a347ff
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 14 deletions.
10 changes: 9 additions & 1 deletion drivers/scsi/qla2xxx/qla_isr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
44 changes: 31 additions & 13 deletions drivers/scsi/qla2xxx/qla_os.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down Expand Up @@ -2417,27 +2424,27 @@ 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)
goto probe_init_failed;

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;
Expand Down Expand Up @@ -2581,7 +2588,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)

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:
Expand Down Expand Up @@ -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;

Expand Down

0 comments on commit 9a347ff

Please sign in to comment.