scsi: fnic: Fix missed link-up when critical IRQ targets offline CPU

When CPU Hyper Threading is disabled, sibling CPUs remain present but
are reported offline. Managed MSI-X IRQs can still receive affinity
masks that include those offline CPUs. If a driver-critical vector is
managed, it can be parked on an offline CPU and the driver may miss
critical events such as link-up.

Keep driver-critical vectors unmanaged so they can be migrated by the
IRQ core when their target CPU is offlined.

Since HWQ-0 is unmanaged now, in some queue combinations there can be no
mappings to it in mq_map. So without the blk-mq fix mentioned below,
system may crash during cpu offline/online tests.

Fixes: 8a8449ca5e ("scsi: fnic: Modify ISRs to support multiqueue (MQ)")
Cc: stable@vger.kernel.org
Depends-on: commit 10845a105b ("blk-mq: skip CPU offline notify on unmapped hctx")
Reviewed-by: Sesidhar Baddela <sebaddel@cisco.com>
Reviewed-by: Arulprabhu Ponnusamy <arulponn@cisco.com>
Reviewed-by: Gian Carlo Boffa <gcboffa@cisco.com>
Reviewed-by: Karan Tilak Kumar <kartilak@cisco.com>
Signed-off-by: Arun Easi <aeasi@cisco.com>
Reviewed-by: Laurence Oberman <loberman@redhat.com>
Link: https://patch.msgid.link/20260903175547.57971-1-aeasi@cisco.com
Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
Arun Easi 2026-09-03 10:55:47 -07:00 committed by Martin K. Petersen (Oracle)
parent 1274045b0e
commit 0cb1fd9241
3 changed files with 51 additions and 5 deletions

View File

@ -31,7 +31,7 @@
#define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
#define DRV_VERSION "1.9.0.0"
#define DRV_VERSION "1.9.0.1"
#define PFX DRV_NAME ": "
#define DFX DRV_NAME "%d: "

View File

@ -245,7 +245,14 @@ int fnic_set_intr_mode_msix(struct fnic *fnic)
unsigned int m = ARRAY_SIZE(fnic->wq);
unsigned int o = ARRAY_SIZE(fnic->hw_copy_wq);
unsigned int min_irqs = n + m + 1 + 1; /*rq, raw wq, wq, err*/
/*
* Make driver critical vectors unmanaged, or else it can get tied
* to an offline CPU. This can happen when hyper-threading is off.
*/
struct irq_affinity affd = {
.pre_vectors = n + m + 1, /* rq, raw wq, 1 ioq */
.post_vectors = 1, /* err */
};
/*
* We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs
* (last INTR is used for WQ/RQ errors and notification area)
@ -263,8 +270,8 @@ int fnic_set_intr_mode_msix(struct fnic *fnic)
int vec_count = 0;
int vecs = fnic->rq_count + fnic->raw_wq_count + fnic->wq_copy_count + 1;
vec_count = pci_alloc_irq_vectors(fnic->pdev, min_irqs, vecs,
PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
vec_count = pci_alloc_irq_vectors_affinity(fnic->pdev, min_irqs,
vecs, PCI_IRQ_MSIX|PCI_IRQ_AFFINITY, &affd);
FNIC_ISR_DBG(KERN_INFO, fnic,
"allocated %d MSI-X vectors\n",
vec_count);

View File

@ -744,8 +744,19 @@ static int fnic_nvme_drv_init(struct fnic *fnic)
return ret;
}
static void fnic_mq_init_queue_map(struct fnic *fnic,
struct blk_mq_queue_map *qmap)
{
unsigned int cpu;
for_each_possible_cpu(cpu)
qmap->mq_map[cpu] = 0;
}
void fnic_mq_map_queues_cpus(struct Scsi_Host *host)
{
const struct cpumask *mask;
unsigned int queue, cpu;
struct fnic *fnic = *((struct fnic **) shost_priv(host));
struct pci_dev *l_pdev = fnic->pdev;
int intr_mode = fnic->config.intr_mode;
@ -766,7 +777,35 @@ void fnic_mq_map_queues_cpus(struct Scsi_Host *host)
return;
}
blk_mq_map_hw_queues(qmap, &l_pdev->dev, FNIC_PCI_OFFSET);
fnic_mq_init_queue_map(fnic, qmap);
/*
* Setup CPU to Queue mapping for all managed MSI-X IRQs.
* Q0 is driver critical and non-managed, hence start from Q1.
*/
for (queue = 1; queue < qmap->nr_queues; queue++) {
int irq_num = pci_irq_vector(fnic->pdev,
queue + FNIC_PCI_OFFSET);
if (irq_num < 0)
continue;
mask = pci_irq_get_affinity(fnic->pdev,
queue + FNIC_PCI_OFFSET);
if (!mask) {
shost_printk(KERN_ERR, host,
"failed to get irq_affinity map for queue:%d\n", irq_num);
continue;
}
FNIC_MAIN_DBG(KERN_INFO, fnic,
"got irq_affinity map for %d:\n", irq_num);
for_each_cpu(cpu, mask) {
qmap->mq_map[cpu] = qmap->queue_offset + queue;
FNIC_MAIN_DBG(KERN_INFO, fnic,
"[Q%d] cpu:%d <=> irq:%d\n",
queue, cpu, irq_num);
}
}
}
static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)