Commit 15dd0381 authored by Shivasharan S's avatar Shivasharan S Committed by Martin K. Petersen
Browse files

scsi: megaraid_sas: NVME Interface detection and prop settings



Adding detection logic for NVME device attached behind Ventura
controller.  Driver set HostPageSize in IOC_INIT frame to inform about
page size for NVME devices.  Firmware reports NVME page size to the
driver.  PD INFO DCMD provide new interface type NVME_PD. Driver set
property of NVME device.

Signed-off-by: default avatarShivasharan S <shivasharan.srikanteshwara@broadcom.com>
Signed-off-by: default avatarKashyap Desai <kashyap.desai@broadcom.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.com>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent f4fc2093
Loading
Loading
Loading
Loading
+16 −7
Original line number Diff line number Diff line
@@ -733,7 +733,6 @@ struct megasas_pd_list {
	u16             tid;
	u8             driveType;
	u8             driveState;
	u8             interface;
} __packed;

 /*
@@ -1530,8 +1529,8 @@ struct megasas_register_set {
	u32 	outbound_scratch_pad ;		/*00B0h*/
	u32	outbound_scratch_pad_2;         /*00B4h*/
	u32	outbound_scratch_pad_3;         /*00B8h*/
	u32	outbound_scratch_pad_4;         /*00BCh*/

	u32	reserved_4;			/*00BCh*/

	u32 	inbound_low_queue_port ;	/*00C0h*/

@@ -1864,6 +1863,7 @@ union megasas_frame {
struct MR_PRIV_DEVICE {
	bool is_tm_capable;
	bool tm_busy;
	u8   interface_type;
};
struct megasas_cmd;

@@ -2060,12 +2060,19 @@ enum MR_PD_TYPE {
	SAS_PD = 2,
	SATA_PD = 3,
	FC_PD = 4,
	NVME_PD = 5,
};

/* JBOD Queue depth definitions */
#define MEGASAS_SATA_QD	32
#define MEGASAS_SAS_QD	64
#define MEGASAS_DEFAULT_PD_QD	64
#define MEGASAS_NVME_QD		32

#define MR_DEFAULT_NVME_PAGE_SIZE	4096
#define MR_DEFAULT_NVME_PAGE_SHIFT	12
#define MR_DEFAULT_NVME_MDTS_KB		128
#define MR_NVME_PAGE_SIZE_MASK		0x000000FF

struct megasas_instance {

@@ -2209,6 +2216,7 @@ struct megasas_instance {
	bool is_ventura;
	bool msix_combined;
	u16 max_raid_mapsize;
	u32 nvme_page_size;
};
struct MR_LD_VF_MAP {
	u32 size;
@@ -2428,6 +2436,7 @@ int megasas_get_ctrl_info(struct megasas_instance *instance);
/* PD sequence */
int
megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend);
void megasas_set_dynamic_target_properties(struct scsi_device *sdev);
int megasas_set_crash_dump_params(struct megasas_instance *instance,
	u8 crash_buf_state);
void megasas_free_host_crash_buffer(struct megasas_instance *instance);
+121 −49
Original line number Diff line number Diff line
@@ -116,8 +116,8 @@ static int megasas_ld_list_query(struct megasas_instance *instance,
static int megasas_issue_init_mfi(struct megasas_instance *instance);
static int megasas_register_aen(struct megasas_instance *instance,
				u32 seq_num, u32 class_locale_word);
static int
megasas_get_pd_info(struct megasas_instance *instance, u16 device_id);
static void megasas_get_pd_info(struct megasas_instance *instance,
				struct scsi_device *sdev);
/*
 * PCI ID table for all supported controllers
 */
@@ -1738,16 +1738,21 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no)
}

/*
* megasas_update_sdev_properties - Update sdev structure based on controller's FW capabilities
* megasas_set_dynamic_target_properties -
* Device property set by driver may not be static and it is required to be
* updated after OCR
*
* set tm_capable.
* set dma alignment (only for eedp protection enable vd).
*
* @sdev: OS provided scsi device
*
* Returns void
*/
void megasas_update_sdev_properties(struct scsi_device *sdev)
void megasas_set_dynamic_target_properties(struct scsi_device *sdev)
{
	u16 pd_index = 0;
	u32 device_id, ld;
	u16 pd_index = 0, ld;
	u32 device_id;
	struct megasas_instance *instance;
	struct fusion_context *fusion;
	struct MR_PRIV_DEVICE *mr_device_priv_data;
@@ -1772,8 +1777,7 @@ void megasas_update_sdev_properties(struct scsi_device *sdev)
		raid = MR_LdRaidGet(ld, local_map_ptr);

		if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
			blk_queue_update_dma_alignment(sdev->request_queue,
						       0x7);
		blk_queue_update_dma_alignment(sdev->request_queue, 0x7);

		mr_device_priv_data->is_tm_capable =
			raid->capability.tmCapable;
@@ -1787,42 +1791,88 @@ void megasas_update_sdev_properties(struct scsi_device *sdev)
	}
}

static void megasas_set_device_queue_depth(struct scsi_device *sdev)
/*
 * megasas_set_nvme_device_properties -
 * set nomerges=2
 * set virtual page boundary = 4K (current mr_nvme_pg_size is 4K).
 * set maximum io transfer = MDTS of NVME device provided by MR firmware.
 *
 * MR firmware provides value in KB. Caller of this function converts
 * kb into bytes.
 *
 * e.a MDTS=5 means 2^5 * nvme page size. (In case of 4K page size,
 * MR firmware provides value 128 as (32 * 4K) = 128K.
 *
 * @sdev:				scsi device
 * @max_io_size:				maximum io transfer size
 *
 */
static inline void
megasas_set_nvme_device_properties(struct scsi_device *sdev, u32 max_io_size)
{
	u16				pd_index = 0;
	int		ret = DCMD_FAILED;
	struct megasas_instance *instance;
	u32 mr_nvme_pg_size;

	instance = megasas_lookup_instance(sdev->host->host_no);
	instance = (struct megasas_instance *)sdev->host->hostdata;
	mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
				MR_DEFAULT_NVME_PAGE_SIZE);

	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
		pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
	blk_queue_max_hw_sectors(sdev->request_queue, (max_io_size / 512));

		if (instance->pd_info) {
			mutex_lock(&instance->hba_mutex);
			ret = megasas_get_pd_info(instance, pd_index);
			mutex_unlock(&instance->hba_mutex);
	queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, sdev->request_queue);
	blk_queue_virt_boundary(sdev->request_queue, mr_nvme_pg_size - 1);
}

		if (ret != DCMD_SUCCESS)
			return;

		if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
/*
 * megasas_set_static_target_properties -
 * Device property set by driver are static and it is not required to be
 * updated after OCR.
 *
 * set io timeout
 * set device queue depth
 * set nvme device properties. see - megasas_set_nvme_device_properties
 *
 * @sdev:				scsi device
 *
 */
static void megasas_set_static_target_properties(struct scsi_device *sdev)
{
	u16	target_index = 0;
	u8 interface_type;
	u32 device_qd = MEGASAS_DEFAULT_CMD_PER_LUN;
	u32 max_io_size_kb = MR_DEFAULT_NVME_MDTS_KB;
	struct megasas_instance *instance;
	struct MR_PRIV_DEVICE *mr_device_priv_data;

	instance = megasas_lookup_instance(sdev->host->host_no);
	mr_device_priv_data = sdev->hostdata;
	interface_type  = mr_device_priv_data->interface_type;

	/*
	 * The RAID firmware may require extended timeouts.
	 */
	blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);

	target_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;

			switch (instance->pd_list[pd_index].interface) {
	switch (interface_type) {
	case SAS_PD:
				scsi_change_queue_depth(sdev, MEGASAS_SAS_QD);
		device_qd = MEGASAS_SAS_QD;
		break;

	case SATA_PD:
				scsi_change_queue_depth(sdev, MEGASAS_SATA_QD);
		device_qd = MEGASAS_SATA_QD;
		break;
	case NVME_PD:
		device_qd = MEGASAS_NVME_QD;
		break;

			default:
				scsi_change_queue_depth(sdev, MEGASAS_DEFAULT_PD_QD);
			}
		}
	}

	if (instance->nvme_page_size && max_io_size_kb)
		megasas_set_nvme_device_properties(sdev, (max_io_size_kb << 10));

	scsi_change_queue_depth(sdev, device_qd);

}


@@ -1841,14 +1891,18 @@ static int megasas_slave_configure(struct scsi_device *sdev)
				return -ENXIO;
		}
	}
	megasas_set_device_queue_depth(sdev);
	megasas_update_sdev_properties(sdev);

	/*
	 * The RAID firmware may require extended timeouts.
	 */
	blk_queue_rq_timeout(sdev->request_queue,
		scmd_timeout * HZ);
	mutex_lock(&instance->hba_mutex);
	/* Send DCMD to Firmware and cache the information */
	if ((instance->pd_info) && !MEGASAS_IS_LOGICAL(sdev))
		megasas_get_pd_info(instance, sdev);

	megasas_set_static_target_properties(sdev);

	mutex_unlock(&instance->hba_mutex);

	/* This sdev property may change post OCR */
	megasas_set_dynamic_target_properties(sdev);

	return 0;
}
@@ -3986,18 +4040,22 @@ dcmd_timeout_ocr_possible(struct megasas_instance *instance) {
		return INITIATE_OCR;
}

static int
megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
static void
megasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev)
{
	int ret;
	struct megasas_cmd *cmd;
	struct megasas_dcmd_frame *dcmd;

	struct MR_PRIV_DEVICE *mr_device_priv_data;
	u16 device_id = 0;

	device_id = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
	cmd = megasas_get_cmd(instance);

	if (!cmd) {
		dev_err(&instance->pdev->dev, "Failed to get cmd %s\n", __func__);
		return -ENOMEM;
		return;
	}

	dcmd = &cmd->frame->dcmd;
@@ -4024,7 +4082,9 @@ megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)

	switch (ret) {
	case DCMD_SUCCESS:
		instance->pd_list[device_id].interface =
		mr_device_priv_data = sdev->hostdata;
		le16_to_cpus((u16 *)&instance->pd_info->state.ddf.pdType);
		mr_device_priv_data->interface_type =
				instance->pd_info->state.ddf.pdType.intf;
		break;

@@ -4051,7 +4111,7 @@ megasas_get_pd_info(struct megasas_instance *instance, u16 device_id)
	if (ret != DCMD_TIMEOUT)
		megasas_return_cmd(instance, cmd);

	return ret;
	return;
}
/*
 * megasas_get_pd_list_info -	Returns FW's pd_list structure
@@ -5020,8 +5080,8 @@ skip_alloc:
static int megasas_init_fw(struct megasas_instance *instance)
{
	u32 max_sectors_1;
	u32 max_sectors_2;
	u32 tmp_sectors, msix_enable, scratch_pad_2, scratch_pad_3;
	u32 max_sectors_2, tmp_sectors, msix_enable;
	u32 scratch_pad_2, scratch_pad_3, scratch_pad_4;
	resource_size_t base_addr;
	struct megasas_register_set __iomem *reg_set;
	struct megasas_ctrl_info *ctrl_info = NULL;
@@ -5202,6 +5262,18 @@ static int megasas_init_fw(struct megasas_instance *instance)
	if (instance->instancet->init_adapter(instance))
		goto fail_init_adapter;

	if (instance->is_ventura) {
		scratch_pad_4 =
			readl(&instance->reg_set->outbound_scratch_pad_4);
		if ((scratch_pad_4 & MR_NVME_PAGE_SIZE_MASK) >=
			MR_DEFAULT_NVME_PAGE_SHIFT)
			instance->nvme_page_size =
				(1 << (scratch_pad_4 & MR_NVME_PAGE_SIZE_MASK));

		dev_info(&instance->pdev->dev,
			 "NVME page size\t: (%d)\n", instance->nvme_page_size);
	}

	if (instance->msix_vectors ?
		megasas_setup_irqs_msix(instance, 1) :
		megasas_setup_irqs_ioapic(instance))
+4 −2
Original line number Diff line number Diff line
@@ -376,7 +376,8 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance)

	fusion->sg_dma_pool =
			pci_pool_create("mr_sg", instance->pdev,
				instance->max_chain_frame_sz, 4, 0);
				instance->max_chain_frame_sz,
				MR_DEFAULT_NVME_PAGE_SIZE, 0);
	/* SCSI_SENSE_BUFFERSIZE  = 96 bytes */
	fusion->sense_dma_pool =
			pci_pool_create("mr_sense", instance->pdev,
@@ -823,6 +824,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
			MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0;
	IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
	IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
	IOCInitMessage->HostPageSize = MR_DEFAULT_NVME_PAGE_SHIFT;
	init_frame = (struct megasas_init_frame *)cmd->frame;
	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);

@@ -3935,7 +3937,7 @@ transition_to_ready:
			megasas_setup_jbod_map(instance);

			shost_for_each_device(sdev, shost)
				megasas_update_sdev_properties(sdev);
				megasas_set_dynamic_target_properties(sdev);

			/* reset stream detection array */
			if (instance->is_ventura) {
+1 −1
Original line number Diff line number Diff line
@@ -657,7 +657,7 @@ struct MPI2_IOC_INIT_REQUEST {
	__le16			HeaderVersion;                  /* 0x0E */
	u32                     Reserved5;                      /* 0x10 */
	__le16			Reserved6;                      /* 0x14 */
	u8                      Reserved7;                      /* 0x16 */
	u8                      HostPageSize;                   /* 0x16 */
	u8                      HostMSIxVectors;                /* 0x17 */
	__le16			Reserved8;                      /* 0x18 */
	__le16			SystemRequestFrameSize;         /* 0x1A */