diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index cfec2ec..f8db2ad 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -4517,12 +4517,16 @@ LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support");
 # For [0], FCP commands are issued to Work Queues ina round robin fashion.
 # For [1], FCP commands are issued to a Work Queue associated with the
 #          current CPU.
+# For [2], FCP commands are issued to a Work Queue associated with the
+#          current CPU core (same Work Queue for all CPUs of a core).
 # It would be set to 1 by the driver if it's able to set up cpu affinity
 # for FCP I/Os through Work Queue associated with the current CPU. Otherwise,
 # roundrobin scheduling of FCP I/Os through WQs will be used.
+# It would remain set to 2 by the driver, likewise, if 2 was requested.
 */
-LPFC_ATTR_RW(fcp_io_sched, 0, 0, 1, "Determine scheduling algorithm for "
-		"issuing commands [0] - Round Robin, [1] - Current CPU");
+LPFC_ATTR_RW(fcp_io_sched, 0, 0, 2, "Determine scheduling algorithm for "
+		"issuing commands [0] - Round Robin, [1] - Current CPU, "
+		"[2] - Current CPU core");
 
 /*
 # lpfc_fcp2_no_tgt_reset: Determine bus reset behavior
diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h
index 0c7070b..3c63063 100644
--- a/drivers/scsi/lpfc/lpfc_hw4.h
+++ b/drivers/scsi/lpfc/lpfc_hw4.h
@@ -191,6 +191,7 @@ struct lpfc_sli_intf {
 /* Algrithmns for scheduling FCP commands to WQs */
 #define	LPFC_FCP_SCHED_ROUND_ROBIN	0
 #define	LPFC_FCP_SCHED_BY_CPU		1
+#define	LPFC_FCP_SCHED_BY_CPU_CORE	2
 
 /* Delay Multiplier constant */
 #define LPFC_DMULT_CONST       651042
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 03d1946..917351c 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -8703,6 +8703,7 @@ lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors)
 {
 	int i, idx, saved_chann, used_chann, cpu, phys_id;
 	int max_phys_id, min_phys_id;
+	int max_core_id, min_core_id, core_id, prev_core_id;
 	int num_io_channel, first_cpu, chan;
 	struct lpfc_vector_map_info *cpup;
 #ifdef CONFIG_X86
@@ -8722,6 +8723,9 @@ lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors)
 	max_phys_id = 0;
 	min_phys_id = INT_MAX;
 	phys_id = 0;
+	max_core_id = 0;
+	min_core_id = INT_MAX;
+	core_id = 0;
 	num_io_channel = 0;
 	first_cpu = LPFC_VECTOR_MAP_EMPTY;
 
@@ -8749,6 +8753,12 @@ lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors)
 			max_phys_id = cpup->phys_id;
 		if (cpup->phys_id < min_phys_id)
 			min_phys_id = cpup->phys_id;
+
+		if (cpup->core_id > max_core_id)
+			max_core_id = cpup->core_id;
+		if (cpup->core_id < min_core_id)
+			min_core_id = cpup->core_id;
+
 		cpup++;
 	}
 
@@ -8820,6 +8830,46 @@ found:
 	}
 
 	/*
+	 * With lpfc_fcp_io_sched per core, associate IO channels with CPUs
+	 * based only on the core numbers instead of individual CPU numbers,
+	 * and ignore/overwrite already assigned values (from MSI-x vectors).
+	 */
+	if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU_CORE) {
+
+		/* The IO channel used by a core */
+		chan = -1;
+
+		/* For each core, assign its (sequential) CPUs the same IO channel */
+		prev_core_id = -1;
+		for (core_id = min_core_id; core_id <= max_core_id; core_id++) {
+
+			cpup = phba->sli4_hba.cpu_map;
+			for (cpu = 0; cpu < phba->sli4_hba.num_present_cpu; cpu++, cpup++) {
+
+				if (cpup->core_id != core_id)
+					continue;
+
+				/* Round-robin on different cores */
+				if (core_id != prev_core_id) {
+					prev_core_id = core_id;
+					chan = (chan + 1) % phba->cfg_fcp_io_channel;
+				}
+
+				cpup->channel_id = chan;
+
+				/* Don't count CPUs w/ IRQ affinity hint (already counted) */
+				if (cpup->irq == LPFC_VECTOR_MAP_EMPTY)
+					num_io_channel++;
+
+				lpfc_printf_log(phba, KERN_INFO, LOG_INIT,
+						"3336 Set IO_CHANN CPU %d channel %d coreid %d\n",
+						cpu, cpup->channel_id, cpup->core_id);
+			}
+		}
+		goto out_fcp_io_sched_per_core;
+	}
+
+	/*
 	 * Finally fill in the IO channel for any remaining CPUs.
 	 * At this point, all IO channels have been assigned to a specific
 	 * MSIx vector, mapped to a specific CPU.
@@ -8891,6 +8941,7 @@ out:
 		}
 	}
 
+out_fcp_io_sched_per_core:
 	if (phba->sli4_hba.num_online_cpu != phba->sli4_hba.num_present_cpu) {
 		cpup = phba->sli4_hba.cpu_map;
 		for (idx = 0; idx < phba->sli4_hba.num_present_cpu; idx++) {
@@ -8916,7 +8967,8 @@ out:
 				vectors);
 
 	/* Enable using cpu affinity for scheduling */
-	phba->cfg_fcp_io_sched = LPFC_FCP_SCHED_BY_CPU;
+	if (phba->cfg_fcp_io_sched != LPFC_FCP_SCHED_BY_CPU_CORE)
+		phba->cfg_fcp_io_sched = LPFC_FCP_SCHED_BY_CPU;
 	return 1;
 }
 
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 3bd0be6..b34276e 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -3881,7 +3881,8 @@ int lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba,
 		return hwq;
 	}
 
-	if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU
+	if ((phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU ||
+	     phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_CPU_CORE)
 	    && phba->cfg_fcp_io_channel > 1) {
 		cpu = smp_processor_id();
 		if (cpu < phba->sli4_hba.num_present_cpu) {
