]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
scsi: megaraid_sas: NVME Interface detection and prop settings
authorShivasharan S <shivasharan.srikanteshwara@broadcom.com>
Fri, 10 Feb 2017 08:59:10 +0000 (00:59 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Mon, 13 Feb 2017 12:26:21 +0000 (07:26 -0500)
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>
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/megaraid/megaraid_sas_fusion.h

index d9049d5054ccf0567adf6c98bf8686966c17ff11..f9efddf32641b59f65ebdca8e8cd7e6326d27be9 100644 (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);
index 23fb78a631f2364604d7879c0b18212f234a49f8..f383bf2cc0a89b5d5a29f1414b8a654790f4921d 100644 (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 = 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;
 
-                       switch (instance->pd_list[pd_index].interface) {
-                       case SAS_PD:
-                               scsi_change_queue_depth(sdev, MEGASAS_SAS_QD);
-                               break;
+       instance = megasas_lookup_instance(sdev->host->host_no);
+       mr_device_priv_data = sdev->hostdata;
+       interface_type  = mr_device_priv_data->interface_type;
 
-                       case SATA_PD:
-                               scsi_change_queue_depth(sdev, MEGASAS_SATA_QD);
-                               break;
+       /*
+        * The RAID firmware may require extended timeouts.
+        */
+       blk_queue_rq_timeout(sdev->request_queue, scmd_timeout * HZ);
 
-                       default:
-                               scsi_change_queue_depth(sdev, MEGASAS_DEFAULT_PD_QD);
-                       }
-               }
+       target_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
+
+       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))
index c38fde0c9a6bb96b9021a73fab108b651a5189be..a481854af0cb927230030466b9aaff608c83d604 100644 (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) {
index 9d9658ea4e6e40936d0fc28d9e4919a9822d9154..9f19f000a4cd28dc96114200ebba481fea7896e1 100644 (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 */