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: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
Signed-off-by: Kashyap Desai <kashyap.desai@broadcom.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Shivasharan S 2017-02-10 00:59:10 -08:00 committed by Martin K. Petersen
parent f4fc209326
commit 15dd03811d
4 changed files with 145 additions and 62 deletions

View File

@ -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;
@ -2055,17 +2055,24 @@ struct MR_DRV_SYSTEM_INFO {
};
enum MR_PD_TYPE {
UNKNOWN_DRIVE = 0,
PARALLEL_SCSI = 1,
SAS_PD = 2,
SATA_PD = 3,
FC_PD = 4,
UNKNOWN_DRIVE = 0,
PARALLEL_SCSI = 1,
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);

View File

@ -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,57 +1777,102 @@ 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;
} else if (instance->use_seqnum_jbod_fp) {
pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
sdev->id;
sdev->id;
pd_sync = (void *)fusion->pd_seq_sync
[(instance->pd_seq_map_id - 1) & 1];
mr_device_priv_data->is_tm_capable =
pd_sync->seq[pd_index].capability.tmCapable;
pd_sync->seq[pd_index].capability.tmCapable;
}
}
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 = (struct megasas_instance *)sdev->host->hostdata;
mr_nvme_pg_size = max_t(u32, instance->nvme_page_size,
MR_DEFAULT_NVME_PAGE_SIZE);
blk_queue_max_hw_sectors(sdev->request_queue, (max_io_size / 512));
queue_flag_set_unlocked(QUEUE_FLAG_NOMERGES, sdev->request_queue);
blk_queue_virt_boundary(sdev->request_queue, mr_nvme_pg_size - 1);
}
/*
* 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;
if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
/*
* The RAID firmware may require extended timeouts.
*/
blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);
if (instance->pd_info) {
mutex_lock(&instance->hba_mutex);
ret = megasas_get_pd_info(instance, pd_index);
mutex_unlock(&instance->hba_mutex);
}
target_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
if (ret != DCMD_SUCCESS)
return;
if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
switch (instance->pd_list[pd_index].interface) {
case SAS_PD:
scsi_change_queue_depth(sdev, MEGASAS_SAS_QD);
break;
case SATA_PD:
scsi_change_queue_depth(sdev, MEGASAS_SATA_QD);
break;
default:
scsi_change_queue_depth(sdev, MEGASAS_DEFAULT_PD_QD);
}
}
switch (interface_type) {
case SAS_PD:
device_qd = MEGASAS_SAS_QD;
break;
case SATA_PD:
device_qd = MEGASAS_SATA_QD;
break;
case NVME_PD:
device_qd = MEGASAS_NVME_QD;
break;
}
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))

View File

@ -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) {

View File

@ -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 */