Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+9 −1
Original line number Original line Diff line number Diff line
@@ -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);
+31 −13
Original line number Original line Diff line number Diff line
@@ -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)
		    "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)
	    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)


	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)


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)
	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;