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

Commit 093df737 authored by Quinn Tran's avatar Quinn Tran Committed by Martin K. Petersen
Browse files

scsi: qla2xxx: Fix Target mode handling with Multiqueue changes.



- Fix race condition between dpc_thread accessing Multiqueue resources
  and qla2x00_remove_one thread trying to free resource.
- Fix out of order free for Multiqueue resources. Also, Multiqueue
  interrupts needs a workqueue. Interrupt needed to stop before
  the wq can be destroyed.

Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Signed-off-by: default avatarQuinn Tran <quinn.tran@cavium.com>
Signed-off-by: default avatarHimanshu Madhani <himanshu.madhani@cavium.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 5601236b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -2734,7 +2734,8 @@ struct isp_operations {

#define QLA_MSIX_DEFAULT		0x00
#define QLA_MSIX_RSP_Q			0x01
#define QLA_MSIX_QPAIR_MULTIQ_RSP_Q	0x02
#define QLA_ATIO_VECTOR		0x02
#define QLA_MSIX_QPAIR_MULTIQ_RSP_Q	0x03

#define QLA_MIDX_DEFAULT	0
#define QLA_MIDX_RSP_Q		1
+1 −1
Original line number Diff line number Diff line
@@ -6764,7 +6764,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int v
		qpair->vp_idx = vp_idx;

		for (i = 0; i < ha->msix_count; i++) {
			msix = &ha->msix_entries[i + 2];
			msix = &ha->msix_entries[i];
			if (msix->in_use)
				continue;
			qpair->msix = msix;
+8 −12
Original line number Diff line number Diff line
@@ -3005,6 +3005,7 @@ struct qla_init_msix_entry {
static struct qla_init_msix_entry msix_entries[] = {
	{ "qla2xxx (default)", qla24xx_msix_default },
	{ "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
	{ "qla2xxx (atio_q)", qla83xx_msix_atio_q },
	{ "qla2xxx (qpair_multiq)", qla2xxx_msix_rsp_q },
};

@@ -3013,17 +3014,10 @@ static struct qla_init_msix_entry qla82xx_msix_entries[] = {
	{ "qla2xxx (rsp_q)", qla82xx_msix_rsp_q },
};

static struct qla_init_msix_entry qla83xx_msix_entries[] = {
	{ "qla2xxx (default)", qla24xx_msix_default },
	{ "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
	{ "qla2xxx (atio_q)", qla83xx_msix_atio_q },
};

static int
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
{
#define MIN_MSIX_COUNT	2
#define ATIO_VECTOR	2
	int i, ret;
	struct qla_msix_entry *qentry;
	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
@@ -3080,7 +3074,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
	}

	/* Enable MSI-X vectors for the base queue */
	for (i = 0; i < 2; i++) {
	for (i = 0; i < (QLA_MSIX_RSP_Q + 1); i++) {
		qentry = &ha->msix_entries[i];
		qentry->handle = rsp;
		rsp->msix = qentry;
@@ -3097,6 +3091,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
		if (ret)
			goto msix_register_fail;
		qentry->have_irq = 1;
		qentry->in_use = 1;

		/* Register for CPU affinity notification. */
		irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify);
@@ -3116,14 +3111,15 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
	 * queue.
	 */
	if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
		qentry = &ha->msix_entries[ATIO_VECTOR];
		qentry = &ha->msix_entries[QLA_ATIO_VECTOR];
		rsp->msix = qentry;
		qentry->handle = rsp;
		scnprintf(qentry->name, sizeof(qentry->name),
		    qla83xx_msix_entries[ATIO_VECTOR].name);
		    msix_entries[QLA_ATIO_VECTOR].name);
		qentry->in_use = 1;
		ret = request_irq(qentry->vector,
			qla83xx_msix_entries[ATIO_VECTOR].handler,
			0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp);
			msix_entries[QLA_ATIO_VECTOR].handler,
			0, msix_entries[QLA_ATIO_VECTOR].name, rsp);
		qentry->have_irq = 1;
	}

+39 −14
Original line number Diff line number Diff line
@@ -439,24 +439,41 @@ static void qla2x00_free_queues(struct qla_hw_data *ha)
	struct req_que *req;
	struct rsp_que *rsp;
	int cnt;
	unsigned long flags;

	spin_lock_irqsave(&ha->hardware_lock, flags);
	for (cnt = 0; cnt < ha->max_req_queues; cnt++) {
		if (!test_bit(cnt, ha->req_qid_map))
			continue;

		req = ha->req_q_map[cnt];
		clear_bit(cnt, ha->req_qid_map);
		ha->req_q_map[cnt] = NULL;

		spin_unlock_irqrestore(&ha->hardware_lock, flags);
		qla2x00_free_req_que(ha, req);
		spin_lock_irqsave(&ha->hardware_lock, flags);
	}
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	kfree(ha->req_q_map);
	ha->req_q_map = NULL;


	spin_lock_irqsave(&ha->hardware_lock, flags);
	for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) {
		if (!test_bit(cnt, ha->rsp_qid_map))
			continue;

		rsp = ha->rsp_q_map[cnt];
		clear_bit(cnt, ha->req_qid_map);
		ha->rsp_q_map[cnt] =  NULL;
		spin_unlock_irqrestore(&ha->hardware_lock, flags);
		qla2x00_free_rsp_que(ha, rsp);
		spin_lock_irqsave(&ha->hardware_lock, flags);
	}
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	kfree(ha->rsp_q_map);
	ha->rsp_q_map = NULL;
}
@@ -1890,17 +1907,22 @@ qla83xx_iospace_config(struct qla_hw_data *ha)
		pci_read_config_word(ha->pdev,
		    QLA_83XX_PCI_MSIX_CONTROL, &msix);
		ha->msix_count = msix + 1;
		/* Max queues are bounded by available msix vectors */
		/* queue 0 uses two msix vectors */
		/*
		 * By default, driver uses at least two msix vectors
		 * (default & rspq)
		 */
		if (ql2xmqsupport) {
			/* MB interrupt uses 1 vector */
			ha->max_req_queues = ha->msix_count - 1;
			ha->max_rsp_queues = ha->max_req_queues;

			/* ATIOQ needs 1 vector. That's 1 less QPair */
			if (QLA_TGT_MODE_ENABLED())
				ha->max_req_queues--;

			/* Queue pairs is the max value minus
			 * the base queue pair */
			ha->max_qpairs = ha->max_req_queues - 1;
			ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc010,
			    "Max no of queues pairs: %d.\n", ha->max_qpairs);
			ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190,
			    "Max no of queues pairs: %d.\n", ha->max_qpairs);
		}
@@ -1912,6 +1934,8 @@ qla83xx_iospace_config(struct qla_hw_data *ha)

mqiobase_exit:
	ha->msix_count = ha->max_rsp_queues + 1;
	if (QLA_TGT_MODE_ENABLED())
		ha->msix_count++;

	qlt_83xx_iospace_config(ha);

@@ -2989,7 +3013,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
	    host->can_queue, base_vha->req,
	    base_vha->mgmt_svr_loop_id, host->sg_tablesize);

	if (ha->mqenable) {
	if (ha->mqenable && qla_ini_mode_enabled(base_vha)) {
		ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1);
		/* Create start of day qpairs for Block MQ */
		if (shost_use_blk_mq(host)) {
@@ -3263,13 +3287,6 @@ qla2x00_delete_all_vps(struct qla_hw_data *ha, scsi_qla_host_t *base_vha)
static void
qla2x00_destroy_deferred_work(struct qla_hw_data *ha)
{
	/* Flush the work queue and remove it */
	if (ha->wq) {
		flush_workqueue(ha->wq);
		destroy_workqueue(ha->wq);
		ha->wq = NULL;
	}

	/* Cancel all work and destroy DPC workqueues */
	if (ha->dpc_lp_wq) {
		cancel_work_sync(&ha->idc_aen);
@@ -3465,9 +3482,17 @@ qla2x00_free_device(scsi_qla_host_t *vha)
		ha->isp_ops->disable_intrs(ha);
	}

	qla2x00_free_fcports(vha);

	qla2x00_free_irqs(vha);

	qla2x00_free_fcports(vha);
	/* Flush the work queue and remove it */
	if (ha->wq) {
		flush_workqueue(ha->wq);
		destroy_workqueue(ha->wq);
		ha->wq = NULL;
	}


	qla2x00_mem_free(ha);

@@ -5187,8 +5212,8 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)

	base_vha->flags.init_done = 0;
	qla25xx_delete_queues(base_vha);
	qla2x00_free_irqs(base_vha);
	qla2x00_free_fcports(base_vha);
	qla2x00_free_irqs(base_vha);
	qla2x00_mem_free(ha);
	qla82xx_md_free(base_vha);
	qla2x00_free_queues(ha);