Commit 6e5c5d24 authored by James Smart's avatar James Smart Committed by Martin K. Petersen
Browse files

scsi: lpfc: Move scsi_host_template outside dynamically allocated/freed phba

On a PCI hotplug capable system, it is possible for scsi_device_put() to
happen after lpfc_pci_remove_one() is called.  As a result, the
sdev->host->hostt->module dereference is for a previously freed memory
location because the phba structure containing the hostt template was
already freed when lpfc_pci_remove_one() returned.

Since the lpfc module is still loaded during power slot disable, all
scsi_host_templates should be declared as part of the global data segment
instead of inside the heap allocated phba structure.  This way the
sdev->host->hostt memory area is always valid as long as the module is
loaded regardless if PCI hotplug dynamically allocates or frees phba
structures.

Move all scsi_host_templates in the phba structure to global variables.
Create a small helper routine to determine appropriate sg_tablesize during
shost allocation.

Link: https://lore.kernel.org/r/20220911221505.117655-7-jsmart2021@gmail.com


Co-developed-by: default avatarDwip N. Banerjee <dnbanerg@us.ibm.com>
Signed-off-by: default avatarDwip N. Banerjee <dnbanerg@us.ibm.com>
Co-developed-by: default avatarDaniel Wagner <dwagner@suse.de>
Signed-off-by: default avatarDaniel Wagner <dwagner@suse.de>
Co-developed-by: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJustin Tee <justin.tee@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 84536351
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -1596,10 +1596,6 @@ struct lpfc_hba {

	char os_host_name[MAXHOSTNAMELEN];

	/* SCSI host template information - for physical port */
	struct scsi_host_template port_template;
	/* SCSI host template information - for all vports */
	struct scsi_host_template vport_template;
	atomic_t dbg_log_idx;
	atomic_t dbg_log_cnt;
	atomic_t dbg_log_dmping;
+1 −0
Original line number Diff line number Diff line
@@ -462,6 +462,7 @@ extern const struct attribute_group *lpfc_hba_groups[];
extern const struct attribute_group *lpfc_vport_groups[];
extern struct scsi_host_template lpfc_template;
extern struct scsi_host_template lpfc_template_nvme;
extern struct scsi_host_template lpfc_vport_template;
extern struct fc_function_template lpfc_transport_functions;
extern struct fc_function_template lpfc_vport_transport_functions;

+20 −30
Original line number Diff line number Diff line
@@ -4614,6 +4614,17 @@ lpfc_get_wwpn(struct lpfc_hba *phba)
		return rol64(wwn, 32);
}

static unsigned short lpfc_get_sg_tablesize(struct lpfc_hba *phba)
{
	if (phba->sli_rev == LPFC_SLI_REV4)
		if (phba->cfg_xpsgl && !phba->nvmet_support)
			return LPFC_MAX_SG_TABLESIZE;
		else
			return phba->cfg_scsi_seg_cnt;
	else
		return phba->cfg_sg_seg_cnt;
}

/**
 * lpfc_vmid_res_alloc - Allocates resources for VMID
 * @phba: pointer to lpfc hba data structure.
@@ -4716,42 +4727,26 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)

	/* Seed template for SCSI host registration */
	if (dev == &phba->pcidev->dev) {
		template = &phba->port_template;

		if (phba->cfg_enable_fc4_type & LPFC_ENABLE_FCP) {
			/* Seed physical port template */
			memcpy(template, &lpfc_template, sizeof(*template));
			template = &lpfc_template;

			if (use_no_reset_hba)
				/* template is for a no reset SCSI Host */
				template->eh_host_reset_handler = NULL;

			/* Template for all vports this physical port creates */
			memcpy(&phba->vport_template, &lpfc_template,
			       sizeof(*template));
			phba->vport_template.shost_groups = lpfc_vport_groups;
			phba->vport_template.eh_bus_reset_handler = NULL;
			phba->vport_template.eh_host_reset_handler = NULL;
			phba->vport_template.vendor_id = 0;

			/* Initialize the host templates with updated value */
			if (phba->sli_rev == LPFC_SLI_REV4) {
				template->sg_tablesize = phba->cfg_scsi_seg_cnt;
				phba->vport_template.sg_tablesize =
					phba->cfg_scsi_seg_cnt;
			} else {
				template->sg_tablesize = phba->cfg_sg_seg_cnt;
				phba->vport_template.sg_tablesize =
					phba->cfg_sg_seg_cnt;
			}

			/* Seed updated value of sg_tablesize */
			template->sg_tablesize = lpfc_get_sg_tablesize(phba);
		} else {
			/* NVMET is for physical port only */
			memcpy(template, &lpfc_template_nvme,
			       sizeof(*template));
			template = &lpfc_template_nvme;
		}
	} else {
		template = &phba->vport_template;
		/* Seed vport template */
		template = &lpfc_vport_template;

		/* Seed updated value of sg_tablesize */
		template->sg_tablesize = lpfc_get_sg_tablesize(phba);
	}

	shost = scsi_host_alloc(template, sizeof(struct lpfc_vport));
@@ -4784,11 +4779,6 @@ lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev)

		shost->dma_boundary =
			phba->sli4_hba.pc_sli4_params.sge_supp_len-1;

		if (phba->cfg_xpsgl && !phba->nvmet_support)
			shost->sg_tablesize = LPFC_MAX_SG_TABLESIZE;
		else
			shost->sg_tablesize = phba->cfg_scsi_seg_cnt;
	} else
		/* SLI-3 has a limited number of hardware queues (3),
		 * thus there is only one for FCP processing.
+27 −0
Original line number Diff line number Diff line
@@ -6794,3 +6794,30 @@ struct scsi_host_template lpfc_template = {
	.change_queue_depth	= scsi_change_queue_depth,
	.track_queue_depth	= 1,
};

struct scsi_host_template lpfc_vport_template = {
	.module			= THIS_MODULE,
	.name			= LPFC_DRIVER_NAME,
	.proc_name		= LPFC_DRIVER_NAME,
	.info			= lpfc_info,
	.queuecommand		= lpfc_queuecommand,
	.eh_timed_out		= fc_eh_timed_out,
	.eh_should_retry_cmd    = fc_eh_should_retry_cmd,
	.eh_abort_handler	= lpfc_abort_handler,
	.eh_device_reset_handler = lpfc_device_reset_handler,
	.eh_target_reset_handler = lpfc_target_reset_handler,
	.eh_bus_reset_handler	= NULL,
	.eh_host_reset_handler	= NULL,
	.slave_alloc		= lpfc_slave_alloc,
	.slave_configure	= lpfc_slave_configure,
	.slave_destroy		= lpfc_slave_destroy,
	.scan_finished		= lpfc_scan_finished,
	.this_id		= -1,
	.sg_tablesize		= LPFC_DEFAULT_SG_SEG_CNT,
	.cmd_per_lun		= LPFC_CMD_PER_LUN,
	.shost_groups		= lpfc_vport_groups,
	.max_sectors		= 0xFFFFFFFF,
	.vendor_id		= 0,
	.change_queue_depth	= scsi_change_queue_depth,
	.track_queue_depth	= 1,
};