From patchwork Thu Oct 19 09:49:05 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shivasharan Srikanteshwara X-Patchwork-Id: 10016301 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 744D860215 for ; Thu, 19 Oct 2017 09:51:02 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 502A628BD0 for ; Thu, 19 Oct 2017 09:51:02 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4492128CB4; Thu, 19 Oct 2017 09:51:02 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_SPAM autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 17A0028BD0 for ; Thu, 19 Oct 2017 09:51:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752619AbdJSJu5 (ORCPT ); Thu, 19 Oct 2017 05:50:57 -0400 Received: from mail-pf0-f193.google.com ([209.85.192.193]:56277 "EHLO mail-pf0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752662AbdJSJur (ORCPT ); Thu, 19 Oct 2017 05:50:47 -0400 Received: by mail-pf0-f193.google.com with SMTP id 17so6190104pfn.12 for ; Thu, 19 Oct 2017 02:50:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=/jEfjn3sEAUE7LINucGQ2IaKiOeX7KVzxtGWpNHL4Mw=; b=Xt8v8iksZdzoqCK7Nfw5ZMYOsizbZzqTyiCxdiLCT7zGO6t2qzV5gR9afxlknbLzZ6 PymakxcrxgXApf0g0LsvKgMcRf2hvX/sA90l+YLXSfcNAshEBK848NYQpE82x/p5/Ku0 lyvIPsGMHyB20duuxBi13ZrQH+uutNcBc5jXY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=/jEfjn3sEAUE7LINucGQ2IaKiOeX7KVzxtGWpNHL4Mw=; b=GD/B6JJmx7pBfy+n30tXA0q4sBXlpCmjC5b/HcO6bE3Q4HkquBvL1uOXHlXj7FWOMf zh+Bclxd39ca8E44S/7DnWC/1tC9OPcfzv0osgwpbgta1igmyBvcZAnNwh+lCAkCT5XT qoEbJZQoe/pZxxWcfUbzPcX71oRUbmx836jkWvDWbZIwvtChfJNvDfMMEnVr4lNzJQ/z zZRc5dJg6aJXtMVZ3SjpwBRypkGHzhO5dVluskchv1GzrvAue5otS/vAccmHqghJ4W/F J5pLmZmGLIV9lSeuZVIM72gzxXA6YVSlbkBLNFg+EMRqtVJgrXw7CusiRpLsm35PFG1x JjQA== X-Gm-Message-State: AMCzsaVFIgs0EEiYMUeu49VPs4gT7h+kbWigwgVsccozo3xqaTJYz+Pe SKsfOTe5DAZhrOpfj+wHiM+jWLZc X-Google-Smtp-Source: ABhQp+SkaToXyfgiOLkfmjZIAuR88AnxKRzAVC1IYDkkQ9yhLpsqr1aBsRHCXMvmsPXFR6Anba55LA== X-Received: by 10.159.211.9 with SMTP id bc9mr1105905plb.192.1508406645717; Thu, 19 Oct 2017 02:50:45 -0700 (PDT) Received: from dhcp-135-24-192-142.localdomain ([192.19.239.250]) by smtp.gmail.com with ESMTPSA id e84sm27202885pfd.1.2017.10.19.02.50.43 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 19 Oct 2017 02:50:44 -0700 (PDT) From: Shivasharan S To: linux-scsi@vger.kernel.org Cc: kashyap.desai@broadcom.com, sumit.saxena@broadcom.com, Shivasharan S Subject: [PATCH 18/19] megaraid_sas: Add support for 64bit consistent DMA Date: Thu, 19 Oct 2017 02:49:05 -0700 Message-Id: <1508406546-25944-19-git-send-email-shivasharan.srikanteshwara@broadcom.com> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1508406546-25944-1-git-send-email-shivasharan.srikanteshwara@broadcom.com> References: <1508406546-25944-1-git-send-email-shivasharan.srikanteshwara@broadcom.com> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The latest MegaRAID Firmware (for Invader series) have support for 64bit DMA for both streaming and consistent DMA buffers. All Ventura series controller FW always support 64 bit consistent DMA. Also on few architectures 32bit DMA is not supported. Current driver always prefers 32bit for consistent DMA and 64bit for streaming DMA. This behavior was unintentional and carried forwarded from legacy controller FW. Need to enhance the driver to support 64bit consistent DMA buffers based on the firmware capability. Below is the DMA setting strategy in driver with this patch. For Ventura series, always try to set 64bit DMA mask. If it fails fall back to 32bit DMA mask. For Invader series and earlier generation controllers, first try to set to 32bit consistent DMA mask irrespective of FW capability. This is needed to ensure firmware downgrades do not break. If 32bit DMA setting fails, check FW capability and try seting to 64bit DMA mask. There are certain restrictions in the hardware for having all sense buffers and all reply descriptors to be in the same 4GB memory region. This limitation is h/w dependent and can not be changed in firmware. This limitation needs to be taken care in driver while allocating the buffers. There was a discussion regarding this - find details at below link. https://www.spinics.net/lists/linux-scsi/msg108251.html Signed-off-by: Kashyap Desai Signed-off-by: Shivasharan S --- drivers/scsi/megaraid/megaraid_sas.h | 12 +- drivers/scsi/megaraid/megaraid_sas_base.c | 245 ++++++++++++------ drivers/scsi/megaraid/megaraid_sas_fusion.c | 384 ++++++++++++++++++++++------ drivers/scsi/megaraid/megaraid_sas_fusion.h | 13 + 4 files changed, 503 insertions(+), 151 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 85ef8415640c..b34fc68c14c9 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1508,6 +1508,8 @@ enum FW_BOOT_CONTEXT { #define MR_CAN_HANDLE_SYNC_CACHE_OFFSET 0X01000000 +#define MR_CAN_HANDLE_64_BIT_DMA_OFFSET (1 << 25) + enum MR_ADAPTER_TYPE { MFI_SERIES = 1, THUNDERBOLT_SERIES = 2, @@ -1628,7 +1630,8 @@ union megasas_sgl_frame { typedef union _MFI_CAPABILITIES { struct { #if defined(__BIG_ENDIAN_BITFIELD) - u32 reserved:19; + u32 reserved:18; + u32 support_64bit_mode:1; u32 support_pd_map_target_id:1; u32 support_qd_throttling:1; u32 support_fp_rlbypass:1; @@ -1656,7 +1659,8 @@ typedef union _MFI_CAPABILITIES { u32 support_fp_rlbypass:1; u32 support_qd_throttling:1; u32 support_pd_map_target_id:1; - u32 reserved:19; + u32 support_64bit_mode:1; + u32 reserved:18; #endif } mfi_capabilities; __le32 reg; @@ -2264,6 +2268,7 @@ struct megasas_instance { u8 r1_ldio_hint_default; u32 nvme_page_size; u8 adapter_type; + bool consistent_mask_64bit; }; struct MR_LD_VF_MAP { u32 size; @@ -2510,4 +2515,7 @@ int megasas_reset_target_fusion(struct scsi_cmnd *scmd); u32 mega_mod64(u64 dividend, u32 divisor); int megasas_alloc_fusion_context(struct megasas_instance *instance); void megasas_free_fusion_context(struct megasas_instance *instance); +void megasas_set_dma_settings(struct megasas_instance *instance, + struct megasas_dcmd_frame *dcmd, + dma_addr_t dma_addr, u32 dma_len); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 995d70a06cb7..3582ed5261dd 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -207,7 +207,7 @@ void megasas_fusion_ocr_wq(struct work_struct *work); static int megasas_get_ld_vf_affiliation(struct megasas_instance *instance, int initial); static int -megasas_set_dma_mask(struct pci_dev *pdev); +megasas_set_dma_mask(struct megasas_instance *instance); static int megasas_alloc_ctrl_mem(struct megasas_instance *instance); static inline void @@ -219,6 +219,31 @@ megasas_free_ctrl_dma_buffers(struct megasas_instance *instance); static inline void megasas_init_ctrl_params(struct megasas_instance *instance); +/** + * megasas_set_dma_settings - Populate DMA address, length and flags for DCMDs + * @instance: Adapter soft state + * @dcmd: DCMD frame inside MFI command + * @dma_addr: DMA address of buffer to be passed to FW + * @dma_len: Length of DMA buffer to be passed to FW + * @return: void + */ +void megasas_set_dma_settings(struct megasas_instance *instance, + struct megasas_dcmd_frame *dcmd, + dma_addr_t dma_addr, u32 dma_len) +{ + if (instance->consistent_mask_64bit) { + dcmd->sgl.sge64[0].phys_addr = cpu_to_le64(dma_addr); + dcmd->sgl.sge64[0].length = cpu_to_le32(dma_len); + dcmd->flags = cpu_to_le16(dcmd->flags | MFI_FRAME_SGL64); + + } else { + dcmd->sgl.sge32[0].phys_addr = + cpu_to_le32(lower_32_bits(dma_addr)); + dcmd->sgl.sge32[0].length = cpu_to_le32(dma_len); + dcmd->flags = cpu_to_le16(dcmd->flags); + } +} + void megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd) { @@ -2501,8 +2526,9 @@ int megasas_sriov_start_heartbeat(struct megasas_instance *instance, dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_CTRL_HB_HOST_MEM)); dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->hb_host_mem_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_CTRL_HB_HOST_MEM)); + + megasas_set_dma_settings(instance, dcmd, instance->hb_host_mem_h, + sizeof(struct MR_CTRL_HB_HOST_MEM)); dev_warn(&instance->pdev->dev, "SR-IOV: Starting heartbeat for scsi%d\n", instance->host->host_no); @@ -4155,13 +4181,14 @@ megasas_get_pd_info(struct megasas_instance *instance, struct scsi_device *sdev) dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_PD_INFO)); dcmd->opcode = cpu_to_le32(MR_DCMD_PD_GET_INFO); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->pd_info_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_PD_INFO)); + + megasas_set_dma_settings(instance, dcmd, instance->pd_info_h, + sizeof(struct MR_PD_INFO)); if ((instance->adapter_type != MFI_SERIES) && !instance->mask_interrupts) @@ -4247,13 +4274,14 @@ megasas_get_pd_list(struct megasas_instance *instance) dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = MFI_STAT_INVALID_STATUS; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST)); dcmd->opcode = cpu_to_le32(MR_DCMD_PD_LIST_QUERY); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST)); + + megasas_set_dma_settings(instance, dcmd, instance->pd_list_buf_h, + (MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST))); if ((instance->adapter_type != MFI_SERIES) && !instance->mask_interrupts) @@ -4369,14 +4397,15 @@ megasas_get_ld_list(struct megasas_instance *instance) dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = MFI_STAT_INVALID_STATUS; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_LIST)); dcmd->opcode = cpu_to_le32(MR_DCMD_LD_GET_LIST); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_LD_LIST)); dcmd->pad_0 = 0; + megasas_set_dma_settings(instance, dcmd, ci_h, + sizeof(struct MR_LD_LIST)); + if ((instance->adapter_type != MFI_SERIES) && !instance->mask_interrupts) ret = megasas_issue_blocked_cmd(instance, cmd, @@ -4480,14 +4509,15 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = MFI_STAT_INVALID_STATUS; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_TARGETID_LIST)); dcmd->opcode = cpu_to_le32(MR_DCMD_LD_LIST_QUERY); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_LD_TARGETID_LIST)); dcmd->pad_0 = 0; + megasas_set_dma_settings(instance, dcmd, ci_h, + sizeof(struct MR_LD_TARGETID_LIST)); + if ((instance->adapter_type != MFI_SERIES) && !instance->mask_interrupts) ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS); @@ -4641,15 +4671,16 @@ megasas_get_ctrl_info(struct megasas_instance *instance) dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = MFI_STAT_INVALID_STATUS; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_ctrl_info)); dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_GET_INFO); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_ctrl_info)); dcmd->mbox.b[0] = 1; + megasas_set_dma_settings(instance, dcmd, ci_h, + sizeof(struct megasas_ctrl_info)); + if ((instance->adapter_type != MFI_SERIES) && !instance->mask_interrupts) ret = megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS); @@ -4758,13 +4789,14 @@ int megasas_set_crash_dump_params(struct megasas_instance *instance, dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = MFI_STAT_INVALID_STATUS; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_NONE); + dcmd->flags = MFI_FRAME_DIR_NONE; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(CRASH_DMA_BUF_SIZE); dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_SET_CRASH_DUMP_PARAMS); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->crash_dump_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(CRASH_DMA_BUF_SIZE); + + megasas_set_dma_settings(instance, dcmd, instance->crash_dump_h, + CRASH_DMA_BUF_SIZE); if ((instance->adapter_type != MFI_SERIES) && !instance->mask_interrupts) @@ -5197,7 +5229,7 @@ static int megasas_init_fw(struct megasas_instance *instance) megasas_init_ctrl_params(instance); - if (megasas_set_dma_mask(instance->pdev)) + if (megasas_set_dma_mask(instance)) goto fail_ready_state; if (megasas_alloc_ctrl_mem(instance)) @@ -5580,13 +5612,14 @@ megasas_get_seq_num(struct megasas_instance *instance, dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = 0x0; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_log_info)); dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_EVENT_GET_INFO); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(el_info_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_log_info)); + + megasas_set_dma_settings(instance, dcmd, el_info_h, + sizeof(struct megasas_evt_log_info)); if (megasas_issue_blocked_cmd(instance, cmd, MFI_IO_TIMEOUT_SECS) == DCMD_SUCCESS) { @@ -5711,7 +5744,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num, dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = 0x0; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_detail)); @@ -5719,8 +5752,9 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num, dcmd->mbox.w[0] = cpu_to_le32(seq_num); instance->last_seq_num = seq_num; dcmd->mbox.w[1] = cpu_to_le32(curr_aen.word); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->evt_detail_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_detail)); + + megasas_set_dma_settings(instance, dcmd, instance->evt_detail_h, + sizeof(struct megasas_evt_detail)); if (instance->aen_cmd != NULL) { megasas_return_cmd(instance, cmd); @@ -5787,16 +5821,15 @@ megasas_get_target_prop(struct megasas_instance *instance, dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_TARGET_PROPERTIES)); dcmd->opcode = cpu_to_le32(MR_DCMD_DRV_GET_TARGET_PROP); - dcmd->sgl.sge32[0].phys_addr = - cpu_to_le32(instance->tgt_prop_h); - dcmd->sgl.sge32[0].length = - cpu_to_le32(sizeof(struct MR_TARGET_PROPERTIES)); + + megasas_set_dma_settings(instance, dcmd, instance->tgt_prop_h, + sizeof(struct MR_TARGET_PROPERTIES)); if ((instance->adapter_type != MFI_SERIES) && !instance->mask_interrupts) @@ -5924,40 +5957,73 @@ static int megasas_io_attach(struct megasas_instance *instance) return 0; } +/** + * megasas_set_dma_mask - Set DMA mask for supported controllers + * + * @instance: Adapter soft state + * Description: + * + * For Ventura, driver/FW will operate in 64bit DMA addresses. + * + * For invader- + * By default, driver/FW will operate in 32bit DMA addresses + * for consistent DMA mapping but if 32 bit consistent + * DMA mask fails, driver will try with 64 bit consistent + * mask provided FW is true 64bit DMA capable + * + * For older controllers(Thunderbolt and MFI based adapters)- + * driver/FW will operate in 32 bit consistent DMA addresses. + */ static int -megasas_set_dma_mask(struct pci_dev *pdev) +megasas_set_dma_mask(struct megasas_instance *instance) { - /* - * All our controllers are capable of performing 64-bit DMA - */ + u64 consistent_mask; + struct pci_dev *pdev; + u32 scratch_pad_2; + + pdev = instance->pdev; + consistent_mask = (instance->adapter_type == VENTURA_SERIES) ? + DMA_BIT_MASK(64) : DMA_BIT_MASK(32); + if (IS_DMA64) { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { + if (dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)) && + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) + goto fail_set_dma_mask; + + if ((*pdev->dev.dma_mask == DMA_BIT_MASK(64)) && + (dma_set_coherent_mask(&pdev->dev, consistent_mask) && + dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)))) { + /* + * If 32 bit DMA mask fails, then try for 64 bit mask + * for FW capable of handling 64 bit DMA. + */ + scratch_pad_2 = readl + (&instance->reg_set->outbound_scratch_pad_2); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) + if (!(scratch_pad_2 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET)) + goto fail_set_dma_mask; + else if (dma_set_mask_and_coherent(&pdev->dev, + DMA_BIT_MASK(64))) goto fail_set_dma_mask; } - } else { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) - goto fail_set_dma_mask; - } - /* - * Ensure that all data structures are allocated in 32-bit - * memory. - */ - if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { - /* Try 32bit DMA mask and 32 bit Consistent dma mask */ - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) - dev_info(&pdev->dev, "set 32bit DMA mask" - "and 32 bit consistent mask\n"); - else - goto fail_set_dma_mask; - } + } else if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) + goto fail_set_dma_mask; + + if (pdev->dev.coherent_dma_mask == DMA_BIT_MASK(32)) + instance->consistent_mask_64bit = false; + else + instance->consistent_mask_64bit = true; + + dev_info(&pdev->dev, "%s bit DMA mask and %s bit consistent mask\n", + ((*pdev->dev.dma_mask == DMA_BIT_MASK(64)) ? "64" : "32"), + (instance->consistent_mask_64bit ? "64" : "32")); return 0; fail_set_dma_mask: - return 1; + dev_err(&pdev->dev, "Failed to set DMA mask\n"); + return -1; + } /* @@ -6632,7 +6698,13 @@ megasas_resume(struct pci_dev *pdev) pci_set_master(pdev); - if (megasas_set_dma_mask(pdev)) + /* + * We expect the FW state to be READY + */ + if (megasas_transition_to_ready(instance, 0)) + goto fail_ready_state; + + if (megasas_set_dma_mask(instance)) goto fail_set_dma_mask; /* @@ -6641,12 +6713,6 @@ megasas_resume(struct pci_dev *pdev) atomic_set(&instance->fw_outstanding, 0); - /* - * We expect the FW state to be READY - */ - if (megasas_transition_to_ready(instance, 0)) - goto fail_ready_state; - /* Now re-enable MSI-X */ if (instance->msix_vectors) { irq_flags = PCI_IRQ_MSIX; @@ -6713,9 +6779,9 @@ megasas_resume(struct pci_dev *pdev) megasas_free_ctrl_mem(instance); scsi_host_put(host); +fail_reenable_msix: fail_set_dma_mask: fail_ready_state: -fail_reenable_msix: pci_disable_device(pdev); @@ -7013,7 +7079,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, struct megasas_iocpacket __user * user_ioc, struct megasas_iocpacket *ioc) { - struct megasas_sge32 *kern_sge32; + struct megasas_sge64 *kern_sge64 = NULL; + struct megasas_sge32 *kern_sge32 = NULL; struct megasas_cmd *cmd; void *kbuff_arr[MAX_IOCTL_SGE]; dma_addr_t buf_handle = 0; @@ -7053,8 +7120,14 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE); cmd->frame->hdr.context = cpu_to_le32(cmd->index); cmd->frame->hdr.pad_0 = 0; - cmd->frame->hdr.flags &= cpu_to_le16(~(MFI_FRAME_IEEE | - MFI_FRAME_SGL64 | + + cmd->frame->hdr.flags &= (~MFI_FRAME_IEEE); + + if (instance->consistent_mask_64bit) + cmd->frame->hdr.flags |= cpu_to_le16((MFI_FRAME_SGL64 | + MFI_FRAME_SENSE64)); + else + cmd->frame->hdr.flags &= cpu_to_le16(~(MFI_FRAME_SGL64 | MFI_FRAME_SENSE64)); if (cmd->frame->hdr.cmd == MFI_CMD_DCMD) @@ -7081,8 +7154,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, * kernel buffers in SGLs. The location of SGL is embedded in the * struct iocpacket itself. */ - kern_sge32 = (struct megasas_sge32 *) - ((unsigned long)cmd->frame + ioc->sgl_off); + if (instance->consistent_mask_64bit) + kern_sge64 = (struct megasas_sge64 *) + ((unsigned long)cmd->frame + ioc->sgl_off); + else + kern_sge32 = (struct megasas_sge32 *) + ((unsigned long)cmd->frame + ioc->sgl_off); /* * For each user buffer, create a mirror buffer and copy in @@ -7105,8 +7182,13 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, * We don't change the dma_coherent_mask, so * pci_alloc_consistent only returns 32bit addresses */ - kern_sge32[i].phys_addr = cpu_to_le32(buf_handle); - kern_sge32[i].length = cpu_to_le32(ioc->sgl[i].iov_len); + if (instance->consistent_mask_64bit) { + kern_sge64[i].phys_addr = cpu_to_le64(buf_handle); + kern_sge64[i].length = cpu_to_le32(ioc->sgl[i].iov_len); + } else { + kern_sge32[i].phys_addr = cpu_to_le32(buf_handle); + kern_sge32[i].length = cpu_to_le32(ioc->sgl[i].iov_len); + } /* * We created a kernel buffer corresponding to the @@ -7129,7 +7211,10 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, sense_ptr = (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off); - *sense_ptr = cpu_to_le32(sense_handle); + if (instance->consistent_mask_64bit) + *sense_ptr = cpu_to_le64(sense_handle); + else + *sense_ptr = cpu_to_le32(sense_handle); } /* @@ -7202,10 +7287,16 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, for (i = 0; i < ioc->sge_count; i++) { if (kbuff_arr[i]) { - dma_free_coherent(&instance->pdev->dev, - le32_to_cpu(kern_sge32[i].length), - kbuff_arr[i], - le32_to_cpu(kern_sge32[i].phys_addr)); + if (instance->consistent_mask_64bit) + dma_free_coherent(&instance->pdev->dev, + le32_to_cpu(kern_sge64[i].length), + kbuff_arr[i], + le64_to_cpu(kern_sge64[i].phys_addr)); + else + dma_free_coherent(&instance->pdev->dev, + le32_to_cpu(kern_sge32[i].length), + kbuff_arr[i], + le32_to_cpu(kern_sge32[i].phys_addr)); kbuff_arr[i] = NULL; } } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 745da54c11aa..fd86ae494fcb 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -99,7 +99,34 @@ static void megasas_free_reply_fusion(struct megasas_instance *instance); static inline void megasas_configure_queue_sizes(struct megasas_instance *instance); +/** + * megasas_check_same_4gb_region - check if allocation + * crosses same 4GB boundary or not + * @instance - adapter's soft instance + * start_addr - start address of DMA allocation + * size - size of allocation in bytes + * return - true : allocation does not cross same + * 4GB boundary + * false: allocation crosses same + * 4GB boundary + */ +static inline bool megasas_check_same_4gb_region + (struct megasas_instance *instance, dma_addr_t start_addr, size_t size) +{ + dma_addr_t end_addr; + + end_addr = start_addr + size; + if (upper_32_bits(start_addr) != upper_32_bits(end_addr)) { + dev_err(&instance->pdev->dev, + "Failed to get same 4GB boundary: start_addr: 0x%llx end_addr: 0x%llx\n", + (unsigned long long)start_addr, + (unsigned long long)end_addr); + return false; + } + + return true; +} /** * megasas_enable_intr_fusion - Enables interrupts @@ -294,17 +321,23 @@ megasas_free_cmds_fusion(struct megasas_instance *instance) struct fusion_context *fusion = instance->ctrl_context; struct megasas_cmd_fusion *cmd; - /* SG, Sense */ - for (i = 0; i < instance->max_mpt_cmds; i++) { - cmd = fusion->cmd_list[i]; - if (cmd) { - if (cmd->sg_frame) - dma_pool_free(fusion->sg_dma_pool, cmd->sg_frame, - cmd->sg_frame_phys_addr); - if (cmd->sense) - dma_pool_free(fusion->sense_dma_pool, cmd->sense, - cmd->sense_phys_addr); + if (fusion->sense) + dma_pool_free(fusion->sense_dma_pool, fusion->sense, + fusion->sense_phys_addr); + + /* SG */ + if (fusion->cmd_list) { + for (i = 0; i < instance->max_mpt_cmds; i++) { + cmd = fusion->cmd_list[i]; + if (cmd) { + if (cmd->sg_frame) + dma_pool_free(fusion->sg_dma_pool, + cmd->sg_frame, + cmd->sg_frame_phys_addr); + } + kfree(cmd); } + kfree(fusion->cmd_list); } if (fusion->sg_dma_pool) { @@ -336,13 +369,6 @@ megasas_free_cmds_fusion(struct megasas_instance *instance) dma_pool_destroy(fusion->io_request_frames_pool); fusion->io_request_frames_pool = NULL; } - - - /* cmd_list */ - for (i = 0; i < instance->max_mpt_cmds; i++) - kfree(fusion->cmd_list[i]); - - kfree(fusion->cmd_list); } /** @@ -356,10 +382,12 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) u16 max_cmd; struct fusion_context *fusion; struct megasas_cmd_fusion *cmd; + int sense_sz; + u32 offset; fusion = instance->ctrl_context; max_cmd = instance->max_fw_cmds; - + sense_sz = instance->max_mpt_cmds * SCSI_SENSE_BUFFERSIZE; fusion->sg_dma_pool = dma_pool_create("mr_sg", &instance->pdev->dev, @@ -368,7 +396,7 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) /* SCSI_SENSE_BUFFERSIZE = 96 bytes */ fusion->sense_dma_pool = dma_pool_create("mr_sense", &instance->pdev->dev, - SCSI_SENSE_BUFFERSIZE, 64, 0); + sense_sz, 64, 0); if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) { dev_err(&instance->pdev->dev, @@ -376,6 +404,51 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) return -ENOMEM; } + fusion->sense = dma_pool_alloc(fusion->sense_dma_pool, + GFP_KERNEL, &fusion->sense_phys_addr); + if (!fusion->sense) { + dev_err(&instance->pdev->dev, + "failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + + /* sense buffer, request frame and reply desc pool requires to be in + * same 4 gb region. Below function will check the same. + * In case of failure, new pci pool will be created with updated + * alignment. + * Older allocation and pool will be destroyed. + * Alignment will be used such a way that next allocation if success, + * will always meet same 4gb region requirement. + * Actual requirement is not alignment, but we need start and end of + * DMA address must have same upper 32 bit address. + */ + + if (!megasas_check_same_4gb_region(instance, fusion->sense_phys_addr, + sense_sz)) { + dma_pool_free(fusion->sense_dma_pool, fusion->sense, + fusion->sense_phys_addr); + fusion->sense = NULL; + dma_pool_destroy(fusion->sense_dma_pool); + + fusion->sense_dma_pool = + dma_pool_create("mr_sense_align", &instance->pdev->dev, + sense_sz, roundup_pow_of_two(sense_sz), + 0); + if (!fusion->sense_dma_pool) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + fusion->sense = dma_pool_alloc(fusion->sense_dma_pool, + GFP_KERNEL, + &fusion->sense_phys_addr); + if (!fusion->sense) { + dev_err(&instance->pdev->dev, + "failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + } + /* * Allocate and attach a frame to each of the commands in cmd_list */ @@ -384,9 +457,11 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) cmd->sg_frame = dma_pool_alloc(fusion->sg_dma_pool, GFP_KERNEL, &cmd->sg_frame_phys_addr); - cmd->sense = dma_pool_alloc(fusion->sense_dma_pool, - GFP_KERNEL, &cmd->sense_phys_addr); - if (!cmd->sg_frame || !cmd->sense) { + offset = SCSI_SENSE_BUFFERSIZE * i; + cmd->sense = (u8 *)fusion->sense + offset; + cmd->sense_phys_addr = fusion->sense_phys_addr + offset; + + if (!cmd->sg_frame) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); return -ENOMEM; @@ -396,13 +471,10 @@ static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) /* create sense buffer for the raid 1/10 fp */ for (i = max_cmd; i < instance->max_mpt_cmds; i++) { cmd = fusion->cmd_list[i]; - cmd->sense = dma_pool_alloc(fusion->sense_dma_pool, - GFP_KERNEL, &cmd->sense_phys_addr); - if (!cmd->sense) { - dev_err(&instance->pdev->dev, - "Failed from %s %d\n", __func__, __LINE__); - return -ENOMEM; - } + offset = SCSI_SENSE_BUFFERSIZE * i; + cmd->sense = (u8 *)fusion->sense + offset; + cmd->sense_phys_addr = fusion->sense_phys_addr + offset; + } return 0; @@ -481,6 +553,40 @@ megasas_alloc_request_fusion(struct megasas_instance *instance) } } + if (!megasas_check_same_4gb_region(instance, + fusion->io_request_frames_phys, + fusion->io_frames_alloc_sz)) { + dma_pool_free(fusion->io_request_frames_pool, + fusion->io_request_frames, + fusion->io_request_frames_phys); + fusion->io_request_frames = NULL; + dma_pool_destroy(fusion->io_request_frames_pool); + + fusion->io_request_frames_pool = + dma_pool_create("mr_ioreq_align", + &instance->pdev->dev, + fusion->io_frames_alloc_sz, + roundup_pow_of_two(fusion->io_frames_alloc_sz), + 0); + + if (!fusion->io_request_frames_pool) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + + fusion->io_request_frames = + dma_pool_alloc(fusion->io_request_frames_pool, + GFP_KERNEL, + &fusion->io_request_frames_phys); + + if (!fusion->io_request_frames) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + } + fusion->req_frames_desc = dma_alloc_coherent(&instance->pdev->dev, fusion->request_alloc_sz, @@ -521,6 +627,41 @@ megasas_alloc_reply_fusion(struct megasas_instance *instance) "Failed from %s %d\n", __func__, __LINE__); return -ENOMEM; } + + if (!megasas_check_same_4gb_region(instance, + fusion->reply_frames_desc_phys[0], + (fusion->reply_alloc_sz * count))) { + dma_pool_free(fusion->reply_frames_desc_pool, + fusion->reply_frames_desc[0], + fusion->reply_frames_desc_phys[0]); + fusion->reply_frames_desc[0] = NULL; + dma_pool_destroy(fusion->reply_frames_desc_pool); + + fusion->reply_frames_desc_pool = + dma_pool_create("mr_reply_align", + &instance->pdev->dev, + fusion->reply_alloc_sz * count, + roundup_pow_of_two(fusion->reply_alloc_sz * count), + 0); + + if (!fusion->reply_frames_desc_pool) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + + fusion->reply_frames_desc[0] = + dma_pool_alloc(fusion->reply_frames_desc_pool, + GFP_KERNEL, + &fusion->reply_frames_desc_phys[0]); + + if (!fusion->reply_frames_desc[0]) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + } + reply_desc = fusion->reply_frames_desc[0]; for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++) reply_desc->Words = cpu_to_le64(ULLONG_MAX); @@ -539,52 +680,124 @@ megasas_alloc_reply_fusion(struct megasas_instance *instance) int megasas_alloc_rdpq_fusion(struct megasas_instance *instance) { - int i, j, count; + int i, j, k, msix_count; struct fusion_context *fusion; union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; + union MPI2_REPLY_DESCRIPTORS_UNION *rdpq_chunk_virt[RDPQ_MAX_CHUNK_COUNT]; + dma_addr_t rdpq_chunk_phys[RDPQ_MAX_CHUNK_COUNT]; + u8 dma_alloc_count, abs_index; + u32 chunk_size, array_size, offset; fusion = instance->ctrl_context; + chunk_size = fusion->reply_alloc_sz * RDPQ_MAX_INDEX_IN_ONE_CHUNK; + array_size = sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * + MAX_MSIX_QUEUES_FUSION; - fusion->rdpq_virt = pci_alloc_consistent(instance->pdev, - sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION, - &fusion->rdpq_phys); + fusion->rdpq_virt = pci_alloc_consistent(instance->pdev, array_size, + &fusion->rdpq_phys); if (!fusion->rdpq_virt) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); return -ENOMEM; } - memset(fusion->rdpq_virt, 0, - sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION); - count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; + memset(fusion->rdpq_virt, 0, array_size); + msix_count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; + fusion->reply_frames_desc_pool = dma_pool_create("mr_rdpq", &instance->pdev->dev, - fusion->reply_alloc_sz, - 16, 0); - - if (!fusion->reply_frames_desc_pool) { + chunk_size, 16, 0); + fusion->reply_frames_desc_pool_align = + dma_pool_create("mr_rdpq_align", + &instance->pdev->dev, + chunk_size, + roundup_pow_of_two(chunk_size), + 0); + + if (!fusion->reply_frames_desc_pool || + !fusion->reply_frames_desc_pool_align) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); return -ENOMEM; } - for (i = 0; i < count; i++) { - fusion->reply_frames_desc[i] = - dma_pool_alloc(fusion->reply_frames_desc_pool, - GFP_KERNEL, &fusion->reply_frames_desc_phys[i]); - if (!fusion->reply_frames_desc[i]) { +/* + * For INVADER_SERIES each set of 8 reply queues(0-7, 8-15, ..) and + * VENTURA_SERIES each set of 16 reply queues(0-15, 16-31, ..) should be + * within 4GB boundary and also reply queues in a set must have same + * upper 32-bits in their memory address. so here driver is allocating the + * DMA'able memory for reply queues according. Driver uses limitation of + * VENTURA_SERIES to manage INVADER_SERIES as well. + */ + dma_alloc_count = DIV_ROUND_UP(msix_count, RDPQ_MAX_INDEX_IN_ONE_CHUNK); + + for (i = 0; i < dma_alloc_count; i++) { + rdpq_chunk_virt[i] = + dma_pool_alloc(fusion->reply_frames_desc_pool, + GFP_KERNEL, &rdpq_chunk_phys[i]); + if (!rdpq_chunk_virt[i]) { dev_err(&instance->pdev->dev, "Failed from %s %d\n", __func__, __LINE__); return -ENOMEM; } + /* reply desc pool requires to be in same 4 gb region. + * Below function will check the same. + * In case of failure, new pci pool will be created with updated + * alignment. + * For RDPQ buffers, driver always allocate two separate pci pool. + * Alignment will be used such a way that next allocation if + * success, will always meet same 4gb region requirement. + * rdpq_tracker keep track of each buffer's physical, + * virtual address and pci pool descriptor. It will help driver + * while freeing the resources. + * + */ + if (!megasas_check_same_4gb_region(instance, rdpq_chunk_phys[i], + chunk_size)) { + dma_pool_free(fusion->reply_frames_desc_pool, + rdpq_chunk_virt[i], + rdpq_chunk_phys[i]); - fusion->rdpq_virt[i].RDPQBaseAddress = - cpu_to_le64(fusion->reply_frames_desc_phys[i]); + rdpq_chunk_virt[i] = + dma_pool_alloc(fusion->reply_frames_desc_pool_align, + GFP_KERNEL, &rdpq_chunk_phys[i]); + if (!rdpq_chunk_virt[i]) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", + __func__, __LINE__); + return -ENOMEM; + } + fusion->rdpq_tracker[i].dma_pool_ptr = + fusion->reply_frames_desc_pool_align; + } else { + fusion->rdpq_tracker[i].dma_pool_ptr = + fusion->reply_frames_desc_pool; + } - reply_desc = fusion->reply_frames_desc[i]; - for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++) - reply_desc->Words = cpu_to_le64(ULLONG_MAX); + fusion->rdpq_tracker[i].pool_entry_phys = rdpq_chunk_phys[i]; + fusion->rdpq_tracker[i].pool_entry_virt = rdpq_chunk_virt[i]; + } + + for (k = 0; k < dma_alloc_count; k++) { + for (i = 0; i < RDPQ_MAX_INDEX_IN_ONE_CHUNK; i++) { + abs_index = (k * RDPQ_MAX_INDEX_IN_ONE_CHUNK) + i; + + if (abs_index == msix_count) + break; + offset = fusion->reply_alloc_sz * i; + fusion->rdpq_virt[abs_index].RDPQBaseAddress = + cpu_to_le64(rdpq_chunk_phys[k] + offset); + fusion->reply_frames_desc_phys[abs_index] = + rdpq_chunk_phys[k] + offset; + fusion->reply_frames_desc[abs_index] = + (union MPI2_REPLY_DESCRIPTORS_UNION *)((u8 *)rdpq_chunk_virt[k] + offset); + + reply_desc = fusion->reply_frames_desc[abs_index]; + for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++) + reply_desc->Words = ULLONG_MAX; + } } + return 0; } @@ -596,15 +809,18 @@ megasas_free_rdpq_fusion(struct megasas_instance *instance) { fusion = instance->ctrl_context; - for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) { - if (fusion->reply_frames_desc[i]) - dma_pool_free(fusion->reply_frames_desc_pool, - fusion->reply_frames_desc[i], - fusion->reply_frames_desc_phys[i]); + for (i = 0; i < RDPQ_MAX_CHUNK_COUNT; i++) { + if (fusion->rdpq_tracker[i].pool_entry_virt) + dma_pool_free(fusion->rdpq_tracker[i].dma_pool_ptr, + fusion->rdpq_tracker[i].pool_entry_virt, + fusion->rdpq_tracker[i].pool_entry_phys); + } if (fusion->reply_frames_desc_pool) dma_pool_destroy(fusion->reply_frames_desc_pool); + if (fusion->reply_frames_desc_pool_align) + dma_pool_destroy(fusion->reply_frames_desc_pool_align); if (fusion->rdpq_virt) pci_free_consistent(instance->pdev, @@ -771,6 +987,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) u32 scratch_pad_2; unsigned long flags; struct timeval tv; + bool cur_fw_64bit_dma_capable; fusion = instance->ctrl_context; @@ -784,6 +1001,19 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0; + if (instance->adapter_type == INVADER_SERIES) { + cur_fw_64bit_dma_capable = + (scratch_pad_2 & MR_CAN_HANDLE_64_BIT_DMA_OFFSET) ? true : false; + + if (instance->consistent_mask_64bit && !cur_fw_64bit_dma_capable) { + dev_err(&instance->pdev->dev, "Driver was operating on 64bit " + "DMA mask, but upcoming FW does not support 64bit DMA mask\n"); + megaraid_sas_kill_hba(instance); + ret = 1; + goto fail_fw_init; + } + } + if (instance->is_rdpq && !cur_rdpq_mode) { dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*" " from RDPQ mode to non RDPQ mode\n"); @@ -811,6 +1041,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) IOCInitMessage->MsgFlags = instance->is_rdpq ? MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0; IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys); + IOCInitMessage->SenseBufferAddressHigh = cpu_to_le32(upper_32_bits(fusion->sense_phys_addr)); IOCInitMessage->HostMSIxVectors = instance->msix_vectors; IOCInitMessage->HostPageSize = MR_DEFAULT_NVME_PAGE_SHIFT; @@ -852,6 +1083,10 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) drv_ops->mfi_capabilities.support_qd_throttling = 1; drv_ops->mfi_capabilities.support_pd_map_target_id = 1; + + if (instance->consistent_mask_64bit) + drv_ops->mfi_capabilities.support_64bit_mode = 1; + /* Convert capability to LE32 */ cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities); @@ -861,8 +1096,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) strlen(sys_info) > 64 ? 64 : strlen(sys_info)); instance->system_info_buf->systemIdLength = strlen(sys_info) > 64 ? 64 : strlen(sys_info); - init_frame->system_info_lo = instance->system_info_h; - init_frame->system_info_hi = 0; + init_frame->system_info_lo = cpu_to_le32(lower_32_bits(instance->system_info_h)); + init_frame->system_info_hi = cpu_to_le32(upper_32_bits(instance->system_info_h)); } init_frame->queue_info_new_phys_addr_hi = @@ -953,6 +1188,15 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) { memset(pd_sync, 0, pd_seq_map_sz); memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); + + if (pend) { + dcmd->mbox.b[0] = MEGASAS_DCMD_MBOX_PEND_FLAG; + dcmd->flags = MFI_FRAME_DIR_WRITE; + instance->jbod_seq_cmd = cmd; + } else { + dcmd->flags = MFI_FRAME_DIR_READ; + } + dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; @@ -960,19 +1204,14 @@ megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) { dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(pd_seq_map_sz); dcmd->opcode = cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(pd_seq_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(pd_seq_map_sz); + + megasas_set_dma_settings(instance, dcmd, pd_seq_h, pd_seq_map_sz); if (pend) { - dcmd->mbox.b[0] = MEGASAS_DCMD_MBOX_PEND_FLAG; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_WRITE); - instance->jbod_seq_cmd = cmd; instance->instancet->issue_dcmd(instance, cmd); return 0; } - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); - /* Below code is only for non pended DCMD */ if (!instance->mask_interrupts) ret = megasas_issue_blocked_cmd(instance, cmd, @@ -1055,13 +1294,13 @@ megasas_get_ld_map_info(struct megasas_instance *instance) dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ); + dcmd->flags = MFI_FRAME_DIR_READ; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(size_map_info); dcmd->opcode = cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(size_map_info); + + megasas_set_dma_settings(instance, dcmd, ci_h, size_map_info); if (!instance->mask_interrupts) ret = megasas_issue_blocked_cmd(instance, cmd, @@ -1159,15 +1398,15 @@ megasas_sync_map_info(struct megasas_instance *instance) dcmd->cmd = MFI_CMD_DCMD; dcmd->cmd_status = 0xFF; dcmd->sge_count = 1; - dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_WRITE); + dcmd->flags = MFI_FRAME_DIR_WRITE; dcmd->timeout = 0; dcmd->pad_0 = 0; dcmd->data_xfer_len = cpu_to_le32(size_map_info); dcmd->mbox.b[0] = num_lds; dcmd->mbox.b[1] = MEGASAS_DCMD_MBOX_PEND_FLAG; dcmd->opcode = cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO); - dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h); - dcmd->sgl.sge32[0].length = cpu_to_le32(size_map_info); + + megasas_set_dma_settings(instance, dcmd, ci_h, size_map_info); instance->map_update_cmd = cmd; @@ -2872,7 +3111,8 @@ megasas_build_io_fusion(struct megasas_instance *instance, io_request->SGLOffset0 = offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL) / 4; - io_request->SenseBufferLowAddress = cpu_to_le32(cmd->sense_phys_addr); + io_request->SenseBufferLowAddress = + cpu_to_le32(lower_32_bits(cmd->sense_phys_addr)); io_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; cmd->scmd = scp; @@ -2913,7 +3153,7 @@ void megasas_prepare_secondRaid1_IO(struct megasas_instance *instance, (fusion->max_sge_in_main_msg * sizeof(union MPI2_SGE_IO_UNION))); /*sense buffer is different for r1 command*/ r1_cmd->io_request->SenseBufferLowAddress = - cpu_to_le32(r1_cmd->sense_phys_addr); + cpu_to_le32(lower_32_bits(r1_cmd->sense_phys_addr)); r1_cmd->scmd = cmd->scmd; req_desc2 = megasas_get_request_descriptor(instance, (r1_cmd->index - 1)); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index 4e229d72dfb0..1814d79cb98d 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -51,6 +51,8 @@ #define HOST_DIAG_RESET_ADAPTER 0x4 #define MEGASAS_FUSION_MAX_RESET_TRIES 3 #define MAX_MSIX_QUEUES_FUSION 128 +#define RDPQ_MAX_INDEX_IN_ONE_CHUNK 16 +#define RDPQ_MAX_CHUNK_COUNT (MAX_MSIX_QUEUES_FUSION / RDPQ_MAX_INDEX_IN_ONE_CHUNK) /* Invader defines */ #define MPI2_TYPE_CUDA 0x2 @@ -1266,6 +1268,12 @@ struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { u32 Reserved2; }; +struct rdpq_alloc_detail { + struct dma_pool *dma_pool_ptr; + dma_addr_t pool_entry_phys; + union MPI2_REPLY_DESCRIPTORS_UNION *pool_entry_virt; +}; + struct fusion_context { struct megasas_cmd_fusion **cmd_list; dma_addr_t req_frames_desc_phys; @@ -1278,9 +1286,14 @@ struct fusion_context { struct dma_pool *sg_dma_pool; struct dma_pool *sense_dma_pool; + u8 *sense; + dma_addr_t sense_phys_addr; + dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION]; union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION]; + struct rdpq_alloc_detail rdpq_tracker[RDPQ_MAX_CHUNK_COUNT]; struct dma_pool *reply_frames_desc_pool; + struct dma_pool *reply_frames_desc_pool_align; u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION];