Message ID | 1450445228-26571-8-git-send-email-Sumit.Saxena@avagotech.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
Hi Sumit, [auto build test WARNING on scsi/for-next] [also build test WARNING on v4.4-rc5 next-20151218] url: https://github.com/0day-ci/linux/commits/Sumit-Saxena/megaraid_sas-Do-not-allow-PCI-access-during-OCR/20151218-213231 base: https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next coccinelle warnings: (new ones prefixed by >>) >> drivers/scsi/megaraid/megaraid_sas_fusion.c:331:20-27: WARNING: kzalloc should be used for fusion -> cmd_list, instead of kmalloc/memset >> drivers/scsi/megaraid/megaraid_sas_fusion.c:342:24-31: WARNING: kzalloc should be used for fusion -> cmd_list [ i ], instead of kmalloc/memset Please review and possibly fold the followup patch. --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 18.12.2015 14:27, Sumit Saxena wrote: > This patch will create reply queue pool for each MSI-x index and will provide array of all reply queue base address > instead of single base address of legacy mode. Using this new interface Driver can support higher Queue depth allocating > more reply queue as scattered DMA pool. > > If array mode is not supported driver will fall back to legacy method of allocation reply pool. > This method fall back controller queue depth to 1K max. To enable more than 1K QD, driver expect FW to support Array mode > and scratch_pad3 should provide new queue depth value. > > Using this method, Firmware should not allow downgrade (OFU) if latest driver and latest FW report 4K QD and Array mode reply queue. > This type of FW upgrade may cause firmware fault and it should not be supported. Upgrade of FW will work, > but queue depth of the controller will be unchanged until reboot/driver reload. > > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com> > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com> > --- > drivers/scsi/megaraid/megaraid_sas.h | 6 +- > drivers/scsi/megaraid/megaraid_sas_base.c | 9 + > drivers/scsi/megaraid/megaraid_sas_fusion.c | 543 +++++++++++++++------------ > drivers/scsi/megaraid/megaraid_sas_fusion.h | 12 +- > 4 files changed, 330 insertions(+), 240 deletions(-) > > diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h > index 01135be..c539516 100644 > --- a/drivers/scsi/megaraid/megaraid_sas.h > +++ b/drivers/scsi/megaraid/megaraid_sas.h > @@ -152,6 +152,7 @@ > #define MFI_RESET_FLAGS MFI_INIT_READY| \ > MFI_INIT_MFIMODE| \ > MFI_INIT_ABORT > +#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01) > > /* > * MFI frame flags > @@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION { > #define MR_MAX_REPLY_QUEUES_EXT_OFFSET 0X003FC000 > #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14 > #define MR_MAX_MSIX_REG_ARRAY 16 > +#define MR_RDPQ_MODE_OFFSET 0X00800000 > /* > * register set for both 1068 and 1078 controllers > * structure extended for 1078 registers > @@ -1455,8 +1457,9 @@ struct megasas_register_set { > > u32 outbound_scratch_pad ; /*00B0h*/ > u32 outbound_scratch_pad_2; /*00B4h*/ > + u32 outbound_scratch_pad_3; /*00B8h*/ > > - u32 reserved_4[2]; /*00B8h*/ > + u32 reserved_4; /*00BCh*/ > > u32 inbound_low_queue_port ; /*00C0h*/ > > @@ -2117,6 +2120,7 @@ struct megasas_instance { > u8 mask_interrupts; > u16 max_chain_frame_sz; > u8 is_imr; > + u8 is_rdpq; > bool dev_handle; > }; > struct MR_LD_VF_MAP { > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c > index df93fa1..a3b63fa 100644 > --- a/drivers/scsi/megaraid/megaraid_sas_base.c > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c > @@ -92,6 +92,10 @@ int smp_affinity_enable = 1; > module_param(smp_affinity_enable, int, S_IRUGO); > MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)"); > > +int rdpq_enable = 1; > +module_param(rdpq_enable, int, S_IRUGO); > +MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disbale Default: disable(0)"); Is it enabled or disabled by default (-> int rdpq_enable = 1;) ? also fix 'disbale' > + > MODULE_LICENSE("GPL"); > MODULE_VERSION(MEGASAS_VERSION); > MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com"); > @@ -5081,6 +5085,9 @@ static int megasas_init_fw(struct megasas_instance *instance) > instance->msix_vectors = ((scratch_pad_2 > & MR_MAX_REPLY_QUEUES_EXT_OFFSET) > >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; > + if (rdpq_enable) > + instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? > + 1 : 0; > fw_msix_count = instance->msix_vectors; > /* Save 1-15 reply post index address to local memory > * Index 0 is already saved from reg offset > @@ -5117,6 +5124,8 @@ static int megasas_init_fw(struct megasas_instance *instance) > dev_info(&instance->pdev->dev, > "current msix/online cpus\t: (%d/%d)\n", > instance->msix_vectors, (unsigned int)num_online_cpus()); > + dev_info(&instance->pdev->dev, > + "firmware supports rdpq mode\t: (%d)\n", instance->is_rdpq); just a nit, but is_rdpq depends also on rdpq_enable, so the text is not precise > > tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, > (unsigned long)instance); > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c > index e8730ef..aca0cd3 100644 > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c > @@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance *instance, > void *fn, unsigned long interval); > extern struct megasas_mgmt_info megasas_mgmt_info; > extern int resetwaittime; > +static void megasas_free_rdpq_fusion(struct megasas_instance *instance); > +static void megasas_free_reply_fusion(struct megasas_instance *instance); > > > > @@ -205,112 +207,71 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, > #endif > } > > - > /** > - * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool > - * @instance: Adapter soft state > + * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool > + * @instance: Adapter soft state > */ > -static void megasas_teardown_frame_pool_fusion( > - struct megasas_instance *instance) > +void > +megasas_free_cmds_fusion(struct megasas_instance *instance) > { > int i; > struct fusion_context *fusion = instance->ctrl_context; > - > - u16 max_cmd = instance->max_fw_cmds; > - > struct megasas_cmd_fusion *cmd; > > - if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) { > - dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, " > - "sense pool : %p\n", fusion->sg_dma_pool, > - fusion->sense_dma_pool); > - return; > - } > - > - /* > - * Return all frames to pool > - */ > - for (i = 0; i < max_cmd; i++) { > - > + /* SG, Sense */ > + for (i = 0; i < instance->max_fw_cmds; i++) { > cmd = fusion->cmd_list[i]; cmd might be NULL here, add a test please > - > if (cmd->sg_frame) > pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame, > - cmd->sg_frame_phys_addr); > - > + cmd->sg_frame_phys_addr); > if (cmd->sense) > pci_pool_free(fusion->sense_dma_pool, cmd->sense, > - cmd->sense_phys_addr); > + cmd->sense_phys_addr); > } > > - /* > - * Now destroy the pool itself > - */ > - pci_pool_destroy(fusion->sg_dma_pool); > - pci_pool_destroy(fusion->sense_dma_pool); > - > - fusion->sg_dma_pool = NULL; > - fusion->sense_dma_pool = NULL; > -} > - > -/** > - * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool > - * @instance: Adapter soft state > - */ > -void > -megasas_free_cmds_fusion(struct megasas_instance *instance) > -{ > - int i; > - struct fusion_context *fusion = instance->ctrl_context; > - > - u32 max_cmds, req_sz, reply_sz, io_frames_sz; > - > + if (fusion->sg_dma_pool) { > + pci_pool_destroy(fusion->sg_dma_pool); > + fusion->sg_dma_pool = NULL; > + } > + if (fusion->sense_dma_pool) { > + pci_pool_destroy(fusion->sense_dma_pool); > + fusion->sense_dma_pool = NULL; If this is needed (fusion->sense_dma_pool = NULL;), why don't we need it few lines below for example for fusion->io_request_frames_pool ? (there should be some consistency here) > + } > > - req_sz = fusion->request_alloc_sz; > - reply_sz = fusion->reply_alloc_sz; > - io_frames_sz = fusion->io_frames_alloc_sz; > > - max_cmds = instance->max_fw_cmds; > + /* Reply Frame, Desc*/ > + if (instance->is_rdpq) > + megasas_free_rdpq_fusion(instance); > + else > + megasas_free_reply_fusion(instance); > > - /* Free descriptors and request Frames memory */ > + /* Request Frame, Desc*/ > if (fusion->req_frames_desc) > - dma_free_coherent(&instance->pdev->dev, req_sz, > - fusion->req_frames_desc, > - fusion->req_frames_desc_phys); > - > - if (fusion->reply_frames_desc) { > - pci_pool_free(fusion->reply_frames_desc_pool, > - fusion->reply_frames_desc, > - fusion->reply_frames_desc_phys); > - pci_pool_destroy(fusion->reply_frames_desc_pool); > - } > - > - if (fusion->io_request_frames) { > + dma_free_coherent(&instance->pdev->dev, > + fusion->request_alloc_sz, fusion->req_frames_desc, > + fusion->req_frames_desc_phys); > + if (fusion->io_request_frames) > pci_pool_free(fusion->io_request_frames_pool, > - fusion->io_request_frames, > - fusion->io_request_frames_phys); > + fusion->io_request_frames, > + fusion->io_request_frames_phys); > + if (fusion->io_request_frames_pool) > pci_pool_destroy(fusion->io_request_frames_pool); > - } > > - /* Free the Fusion frame pool */ > - megasas_teardown_frame_pool_fusion(instance); > > - /* Free all the commands in the cmd_list */ > - for (i = 0; i < max_cmds; i++) > + /* cmd_list */ > + for (i = 0; i < instance->max_fw_cmds; i++) > kfree(fusion->cmd_list[i]); > > - /* Free the cmd_list buffer itself */ > kfree(fusion->cmd_list); > fusion->cmd_list = NULL; It is a good idea to set (fusion->cmd_list = NULL;), but a test to the kfree should be added > - > } > > /** > - * megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames > + * megasas_create_sg_sense_fusion - Creates DMA pool for cmd frames > * @instance: Adapter soft state > * > */ > -static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) > +static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) > { > int i; > u32 max_cmd; > @@ -321,186 +282,299 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) > max_cmd = instance->max_fw_cmds; > > > - /* > - * Use DMA pool facility provided by PCI layer > - */ > - > - fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev, > - instance->max_chain_frame_sz, > - 4, 0); > - if (!fusion->sg_dma_pool) { > - dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n"); > - return -ENOMEM; > - } > - fusion->sense_dma_pool = pci_pool_create("sense pool fusion", > - instance->pdev, > - SCSI_SENSE_BUFFERSIZE, 64, 0); > + fusion->sg_dma_pool = > + pci_pool_create("mr_sg", instance->pdev, > + instance->max_chain_frame_sz, 4, 0); > + /* SCSI_SENSE_BUFFERSIZE = 96 bytes */ > + fusion->sense_dma_pool = > + pci_pool_create("mr_sense", instance->pdev, > + SCSI_SENSE_BUFFERSIZE, 64, 0); > > - if (!fusion->sense_dma_pool) { > - dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n"); > - pci_pool_destroy(fusion->sg_dma_pool); > - fusion->sg_dma_pool = NULL; > - return -ENOMEM; > - } > + if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); Allocation failed - I don't think we can ignore it. > > /* > * Allocate and attach a frame to each of the commands in cmd_list > */ > for (i = 0; i < max_cmd; i++) { > - > cmd = fusion->cmd_list[i]; > - > cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool, > - GFP_KERNEL, > - &cmd->sg_frame_phys_addr); > + GFP_KERNEL, &cmd->sg_frame_phys_addr); > > cmd->sense = pci_pool_alloc(fusion->sense_dma_pool, > - GFP_KERNEL, &cmd->sense_phys_addr); > - /* > - * megasas_teardown_frame_pool_fusion() takes care of freeing > - * whatever has been allocated > - */ > + GFP_KERNEL, &cmd->sense_phys_addr); > if (!cmd->sg_frame || !cmd->sense) { > - dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n"); > - megasas_teardown_frame_pool_fusion(instance); > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); > return -ENOMEM; > } > } > return 0; > } > > -/** > - * megasas_alloc_cmds_fusion - Allocates the command packets > - * @instance: Adapter soft state > - * > - * > - * Each frame has a 32-bit field called context. This context is used to get > - * back the megasas_cmd_fusion from the frame when a frame gets completed > - * In this driver, the 32 bit values are the indices into an array cmd_list. > - * This array is used only to look up the megasas_cmd_fusion given the context. > - * The free commands themselves are maintained in a linked list called cmd_pool. > - * > - * cmds are formed in the io_request and sg_frame members of the > - * megasas_cmd_fusion. The context field is used to get a request descriptor > - * and is used as SMID of the cmd. > - * SMID value range is from 1 to max_fw_cmds. > - */ > int > -megasas_alloc_cmds_fusion(struct megasas_instance *instance) > +megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) > { > - int i, j, count; > - u32 max_cmd, io_frames_sz; > + u32 max_cmd, i; > struct fusion_context *fusion; > - struct megasas_cmd_fusion *cmd; > - union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; > - u32 offset; > - dma_addr_t io_req_base_phys; > - u8 *io_req_base; > > fusion = instance->ctrl_context; > > max_cmd = instance->max_fw_cmds; > > + /* > + * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. > + * Allocate the dynamic array first and then allocate individual > + * commands. > + */ > + fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd, > + GFP_KERNEL); > + if (!fusion->cmd_list) { > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); > + return -ENOMEM; > + } > + memset(fusion->cmd_list, 0, > + sizeof(struct megasas_cmd_fusion *) * max_cmd); > + > + for (i = 0; i < max_cmd; i++) { > + fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion), > + GFP_KERNEL); kzalloc here and there, as the kbuild script already wrote > + if (!fusion->cmd_list[i]) { > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); > + return -ENOMEM; > + } > + memset(fusion->cmd_list[i], 0, sizeof(struct megasas_cmd_fusion)); > + } > + return 0; > +} > +int > +megasas_alloc_request_fusion(struct megasas_instance *instance) > +{ > + struct fusion_context *fusion; > + > + fusion = instance->ctrl_context; > + > fusion->req_frames_desc = > dma_alloc_coherent(&instance->pdev->dev, > - fusion->request_alloc_sz, > - &fusion->req_frames_desc_phys, GFP_KERNEL); > - > + fusion->request_alloc_sz, > + &fusion->req_frames_desc_phys, GFP_KERNEL); > if (!fusion->req_frames_desc) { > - dev_err(&instance->pdev->dev, "Could not allocate memory for " > - "request_frames\n"); > - goto fail_req_desc; > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); > + return -ENOMEM; > + } > + > + fusion->io_request_frames_pool = > + pci_pool_create("mr_ioreq", instance->pdev, > + fusion->io_frames_alloc_sz, 16, 0); Why do you need a pool, you just allocate once a single region, or not? Please turn it into a dma_alloc_coherent. > + > + if (!fusion->io_request_frames_pool) { > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); > + return -ENOMEM; > + } > + > + fusion->io_request_frames = > + pci_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; > } > + return 0; > +} > + > +int > +megasas_alloc_reply_fusion(struct megasas_instance *instance) > +{ > + int i, count; > + struct fusion_context *fusion; > + union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; > + fusion = instance->ctrl_context; > > count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; > fusion->reply_frames_desc_pool = > - pci_pool_create("reply_frames pool", instance->pdev, > + pci_pool_create("mr_reply", instance->pdev, > fusion->reply_alloc_sz * count, 16, 0); > > if (!fusion->reply_frames_desc_pool) { > - dev_err(&instance->pdev->dev, "Could not allocate memory for " > - "reply_frame pool\n"); > - goto fail_reply_desc; > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); > + return -ENOMEM; > } Same here, I could understand it if the code were merged with megasas_alloc_rdpq_fusion but it is not. Why a pool? > > - fusion->reply_frames_desc = > - pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL, > - &fusion->reply_frames_desc_phys); > - if (!fusion->reply_frames_desc) { > - dev_err(&instance->pdev->dev, "Could not allocate memory for " > - "reply_frame pool\n"); > - pci_pool_destroy(fusion->reply_frames_desc_pool); > - goto fail_reply_desc; > + fusion->reply_frames_desc[0] = > + pci_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; > + 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); > + reply_desc->Words = ULLONG_MAX; The megasas_reset_reply_desc function seems to be used for this kind of resetting, could it be used here ? (and in megasas_alloc_rdpq_fusion) There you also kept the cpu_to_le64(..) that doesn't matter, but again for consistency... > > - io_frames_sz = fusion->io_frames_alloc_sz; > + /* This is not a rdpq mode, but driver still populate > + * reply_frame_desc array to use same msix index in ISR path. > + */ > + for (i = 0; i < (count - 1); i++) > + fusion->reply_frames_desc[i + 1] = > + fusion->reply_frames_desc[i] + > + (fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION); > > - fusion->io_request_frames_pool = > - pci_pool_create("io_request_frames pool", instance->pdev, > - fusion->io_frames_alloc_sz, 16, 0); > + return 0; > +} > > - if (!fusion->io_request_frames_pool) { > - dev_err(&instance->pdev->dev, "Could not allocate memory for " > - "io_request_frame pool\n"); > - goto fail_io_frames; > +int > +megasas_alloc_rdpq_fusion(struct megasas_instance *instance) > +{ > + int i, j, count; > + struct fusion_context *fusion; > + union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; > + > + fusion = instance->ctrl_context; > + > + fusion->rdpq_virt = pci_alloc_consistent(instance->pdev, > + sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION, is dma_alloc_coherent possible here? > + &fusion->rdpq_phys); > + if (!fusion->rdpq_virt) { > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); > + return -ENOMEM; > } > > - fusion->io_request_frames = > - pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL, > - &fusion->io_request_frames_phys); > - if (!fusion->io_request_frames) { > - dev_err(&instance->pdev->dev, "Could not allocate memory for " > - "io_request_frames frames\n"); > - pci_pool_destroy(fusion->io_request_frames_pool); > - goto fail_io_frames; > + 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; > + fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq", > + instance->pdev, fusion->reply_alloc_sz, 16, 0); > + > + if (!fusion->reply_frames_desc_pool) { > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); > + return -ENOMEM; > } > > - /* > - * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. > - * Allocate the dynamic array first and then allocate individual > - * commands. > - */ > - fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) > - * max_cmd, GFP_KERNEL); > + for (i = 0; i < count; i++) { > + fusion->reply_frames_desc[i] = > + pci_pool_alloc(fusion->reply_frames_desc_pool, > + GFP_KERNEL, &fusion->reply_frames_desc_phys[i]); > + if (!fusion->reply_frames_desc[i]) { > + dev_err(&instance->pdev->dev, > + "Failed from %s %d\n", __func__, __LINE__); > + return -ENOMEM; > + } > > - if (!fusion->cmd_list) { > - dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc " > - "memory for cmd_list_fusion\n"); > - goto fail_cmd_list; > + fusion->rdpq_virt[i].RDPQBaseAddress = > + fusion->reply_frames_desc_phys[i]; > + > + reply_desc = fusion->reply_frames_desc[i]; > + for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++) > + reply_desc->Words = ULLONG_MAX; > } > + return 0; > +} > > - max_cmd = instance->max_fw_cmds; > - for (i = 0; i < max_cmd; i++) { > - fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion), > - GFP_KERNEL); > - if (!fusion->cmd_list[i]) { > - dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n"); > +static void > +megasas_free_rdpq_fusion(struct megasas_instance *instance) { > > - for (j = 0; j < i; j++) > - kfree(fusion->cmd_list[j]); > + int i; > + struct fusion_context *fusion; > > - kfree(fusion->cmd_list); > - fusion->cmd_list = NULL; > - goto fail_cmd_list; > - } > + fusion = instance->ctrl_context; > + > + for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) { > + if (fusion->reply_frames_desc[i]) > + pci_pool_free(fusion->reply_frames_desc_pool, > + fusion->reply_frames_desc[i], > + fusion->reply_frames_desc_phys[i]); > } > > - /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */ > - io_req_base = fusion->io_request_frames + > - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; > - io_req_base_phys = fusion->io_request_frames_phys + > - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; > + if (fusion->reply_frames_desc_pool) > + pci_pool_destroy(fusion->reply_frames_desc_pool); > + > + if (fusion->rdpq_virt) > + pci_free_consistent(instance->pdev, > + sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION, > + fusion->rdpq_virt, fusion->rdpq_phys); > +} > + > +static void > +megasas_free_reply_fusion(struct megasas_instance *instance) { > + > + struct fusion_context *fusion; > + > + fusion = instance->ctrl_context; > + > + if (fusion->reply_frames_desc[0]) > + pci_pool_free(fusion->reply_frames_desc_pool, > + fusion->reply_frames_desc[0], > + fusion->reply_frames_desc_phys[0]); > + > + if (fusion->reply_frames_desc_pool) > + pci_pool_destroy(fusion->reply_frames_desc_pool); > + > +} > + > + > +/** > + * megasas_alloc_cmds_fusion - Allocates the command packets > + * @instance: Adapter soft state > + * > + * > + * Each frame has a 32-bit field called context. This context is used to get > + * back the megasas_cmd_fusion from the frame when a frame gets completed > + * In this driver, the 32 bit values are the indices into an array cmd_list. > + * This array is used only to look up the megasas_cmd_fusion given the context. > + * The free commands themselves are maintained in a linked list called cmd_pool. > + * > + * cmds are formed in the io_request and sg_frame members of the > + * megasas_cmd_fusion. The context field is used to get a request descriptor > + * and is used as SMID of the cmd. > + * SMID value range is from 1 to max_fw_cmds. > + */ > +int > +megasas_alloc_cmds_fusion(struct megasas_instance *instance) > +{ > + int i; > + struct fusion_context *fusion; > + struct megasas_cmd_fusion *cmd; > + u32 offset; > + dma_addr_t io_req_base_phys; > + u8 *io_req_base; > + > + > + fusion = instance->ctrl_context; > + > + if (megasas_alloc_cmdlist_fusion(instance)) We may need to call megasas_free_cmds_fusion here too (to free fusion->cmd_list) > + return -ENOMEM; > + > + if (megasas_alloc_request_fusion(instance)) > + goto fail_exit; > + > + if (instance->is_rdpq) { > + if (megasas_alloc_rdpq_fusion(instance)) > + goto fail_exit; > + } else > + if (megasas_alloc_reply_fusion(instance)) > + goto fail_exit; > + > + > + /* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */ > + io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; > + io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; > > /* > * Add all the commands to command pool (fusion->cmd_pool) > */ > > /* SMID 0 is reserved. Set SMID/index from 1 */ > - for (i = 0; i < max_cmd; i++) { > + for (i = 0; i < instance->max_fw_cmds; i++) { > cmd = fusion->cmd_list[i]; > offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; > memset(cmd, 0, sizeof(struct megasas_cmd_fusion)); That memset was already done in megasas_alloc_cmdlist_fusion > @@ -518,35 +592,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) > cmd->io_request_phys_addr = io_req_base_phys + offset; > }/ > > - /* > - * Create a frame pool and assign one frame to each cmd > - */ > - if (megasas_create_frame_pool_fusion(instance)) { > - dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n"); > - megasas_free_cmds_fusion(instance); > - goto fail_req_desc; > - } > + if (megasas_create_sg_sense_fusion(instance)) > + goto fail_exit; > > return 0; > > -fail_cmd_list: > - pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames, > - fusion->io_request_frames_phys); > - pci_pool_destroy(fusion->io_request_frames_pool); > -fail_io_frames: > - dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, > - fusion->reply_frames_desc, > - fusion->reply_frames_desc_phys); > - pci_pool_free(fusion->reply_frames_desc_pool, > - fusion->reply_frames_desc, > - fusion->reply_frames_desc_phys); > - pci_pool_destroy(fusion->reply_frames_desc_pool); > - > -fail_reply_desc: > - dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, > - fusion->req_frames_desc, > - fusion->req_frames_desc_phys); > -fail_req_desc: > +fail_exit: > + megasas_free_cmds_fusion(instance); > return -ENOMEM; > } > > @@ -594,16 +646,17 @@ int > megasas_ioc_init_fusion(struct megasas_instance *instance) > { > struct megasas_init_frame *init_frame; > - struct MPI2_IOC_INIT_REQUEST *IOCInitMessage; > + struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL; > dma_addr_t ioc_init_handle; > struct megasas_cmd *cmd; > - u8 ret; > + u8 ret, cur_rdpq_mode; > struct fusion_context *fusion; > union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc; > int i; > struct megasas_header *frame_hdr; > const char *sys_info; > MFI_CAPABILITIES *drv_ops; > + u32 scratch_pad_2; > > fusion = instance->ctrl_context; > > @@ -615,6 +668,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) > goto fail_get_cmd; > } > > + scratch_pad_2 = readl > + (&instance->reg_set->outbound_scratch_pad_2); > + > + cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0; > + > + if (instance->is_rdpq && !cur_rdpq_mode) { > + dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*" > + " from RDPQ mode to non RDPQ mode\n"); How does this work ? is_rdpq is set in megasas_init_fw only when the fw supports it, why do you test it here again ? I think I'm miss something. Tomas > + ret = 1; > + goto fail_fw_init; > + } > + > IOCInitMessage = > dma_alloc_coherent(&instance->pdev->dev, > sizeof(struct MPI2_IOC_INIT_REQUEST), > @@ -636,7 +701,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) > IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4); > > IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth); > - IOCInitMessage->ReplyDescriptorPostQueueAddress = cpu_to_le64(fusion->reply_frames_desc_phys); > + IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ? > + cpu_to_le64(fusion->rdpq_phys) : > + cpu_to_le64(fusion->reply_frames_desc_phys[0]); > + IOCInitMessage->MsgFlags = instance->is_rdpq ? > + MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0; > IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys); > IOCInitMessage->HostMSIxVectors = instance->msix_vectors; > init_frame = (struct megasas_init_frame *)cmd->frame; > @@ -1087,7 +1156,10 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) > */ > instance->max_fw_cmds = > instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; > - instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008); > + dev_info(&instance->pdev->dev, > + "firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds); > + if (!instance->is_rdpq) > + instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024); > > /* > * Reduce the max supported cmds by 1. This is to ensure that the > @@ -2110,10 +2182,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) > if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) > return IRQ_HANDLED; > > - desc = fusion->reply_frames_desc; > - desc += ((MSIxIndex * fusion->reply_alloc_sz)/ > - sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) + > - fusion->last_reply_idx[MSIxIndex]; > + desc = fusion->reply_frames_desc[MSIxIndex] + > + fusion->last_reply_idx[MSIxIndex]; > > reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; > > @@ -2208,9 +2278,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) > > /* Get the next reply descriptor */ > if (!fusion->last_reply_idx[MSIxIndex]) > - desc = fusion->reply_frames_desc + > - ((MSIxIndex * fusion->reply_alloc_sz)/ > - sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)); > + desc = fusion->reply_frames_desc[MSIxIndex]; > else > desc++; > > @@ -2688,17 +2756,18 @@ out: > > void megasas_reset_reply_desc(struct megasas_instance *instance) > { > - int i, count; > + int i, j, count; > struct fusion_context *fusion; > union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; > > fusion = instance->ctrl_context; > count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; > - for (i = 0 ; i < count ; i++) > + for (i = 0 ; i < count ; i++) { > fusion->last_reply_idx[i] = 0; > - reply_desc = fusion->reply_frames_desc; > - for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++) > - reply_desc->Words = cpu_to_le64(ULLONG_MAX); > + 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); > + } > } > > /* > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h > index db0978d..80eaee2 100644 > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h > @@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC { > struct MR_PD_CFG_SEQ seq[1]; > } __packed; > > +struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { > + u64 RDPQBaseAddress; > + u32 Reserved1; > + u32 Reserved2; > +}; > + > struct fusion_context { > struct megasas_cmd_fusion **cmd_list; > dma_addr_t req_frames_desc_phys; > @@ -940,8 +946,8 @@ struct fusion_context { > struct dma_pool *sg_dma_pool; > struct dma_pool *sense_dma_pool; > > - dma_addr_t reply_frames_desc_phys; > - union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc; > + dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION]; > + union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION]; > struct dma_pool *reply_frames_desc_pool; > > u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION]; > @@ -951,6 +957,8 @@ struct fusion_context { > u32 reply_alloc_sz; > u32 io_frames_alloc_sz; > > + struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt; > + dma_addr_t rdpq_phys; > u16 max_sge_in_main_msg; > u16 max_sge_in_chain; > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Tomas, This reply was stuck in my outbox(was not sent). Just realized now this when reworking on patches to accommodate your feedback. Apologies for late reply. Thanks, Sumit > -----Original Message----- > From: Tomas Henzl [mailto:thenzl@redhat.com] > Sent: Thursday, January 14, 2016 11:09 PM > To: Sumit Saxena; jbottomley@parallels.com; hch@infradead.org; > martin.petersen@oracle.com > Cc: linux-scsi@vger.kernel.org; kashyap.desai@avagotech.com > Subject: Re: [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) > support > > On 18.12.2015 14:27, Sumit Saxena wrote: > > This patch will create reply queue pool for each MSI-x index and will > > provide array of all reply queue base address instead of single base > > address of legacy mode. Using this new interface Driver can support higher > Queue depth allocating more reply queue as scattered DMA pool. > > > > If array mode is not supported driver will fall back to legacy method of > allocation reply pool. > > This method fall back controller queue depth to 1K max. To enable more > > than 1K QD, driver expect FW to support Array mode and scratch_pad3 should > provide new queue depth value. > > > > Using this method, Firmware should not allow downgrade (OFU) if latest driver > and latest FW report 4K QD and Array mode reply queue. > > This type of FW upgrade may cause firmware fault and it should not be > > supported. Upgrade of FW will work, but queue depth of the controller will be > unchanged until reboot/driver reload. > > > > Signed-off-by: Kashyap Desai <kashyap.desai@avagotech.com> > > Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com> > > --- > > drivers/scsi/megaraid/megaraid_sas.h | 6 +- > > drivers/scsi/megaraid/megaraid_sas_base.c | 9 + > > drivers/scsi/megaraid/megaraid_sas_fusion.c | 543 +++++++++++++++-------- > ---- > > drivers/scsi/megaraid/megaraid_sas_fusion.h | 12 +- > > 4 files changed, 330 insertions(+), 240 deletions(-) > > > > diff --git a/drivers/scsi/megaraid/megaraid_sas.h > > b/drivers/scsi/megaraid/megaraid_sas.h > > index 01135be..c539516 100644 > > --- a/drivers/scsi/megaraid/megaraid_sas.h > > +++ b/drivers/scsi/megaraid/megaraid_sas.h > > @@ -152,6 +152,7 @@ > > #define MFI_RESET_FLAGS MFI_INIT_READY| \ > > MFI_INIT_MFIMODE| \ > > MFI_INIT_ABORT > > +#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01) > > > > /* > > * MFI frame flags > > @@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION { > > #define MR_MAX_REPLY_QUEUES_EXT_OFFSET 0X003FC000 > > #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14 > > #define MR_MAX_MSIX_REG_ARRAY 16 > > +#define MR_RDPQ_MODE_OFFSET 0X00800000 > > /* > > * register set for both 1068 and 1078 controllers > > * structure extended for 1078 registers @@ -1455,8 +1457,9 @@ struct > > megasas_register_set { > > > > u32 outbound_scratch_pad ; /*00B0h*/ > > u32 outbound_scratch_pad_2; /*00B4h*/ > > + u32 outbound_scratch_pad_3; /*00B8h*/ > > > > - u32 reserved_4[2]; /*00B8h*/ > > + u32 reserved_4; /*00BCh*/ > > > > u32 inbound_low_queue_port ; /*00C0h*/ > > > > @@ -2117,6 +2120,7 @@ struct megasas_instance { > > u8 mask_interrupts; > > u16 max_chain_frame_sz; > > u8 is_imr; > > + u8 is_rdpq; > > bool dev_handle; > > }; > > struct MR_LD_VF_MAP { > > diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c > > b/drivers/scsi/megaraid/megaraid_sas_base.c > > index df93fa1..a3b63fa 100644 > > --- a/drivers/scsi/megaraid/megaraid_sas_base.c > > +++ b/drivers/scsi/megaraid/megaraid_sas_base.c > > @@ -92,6 +92,10 @@ int smp_affinity_enable = 1; > > module_param(smp_affinity_enable, int, S_IRUGO); > > MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature > > enable/disbale Default: enable(1)"); > > > > +int rdpq_enable = 1; > > +module_param(rdpq_enable, int, S_IRUGO); > > +MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for > > +large queue depth enable/disbale Default: disable(0)"); > > Is it enabled or disabled by default (-> int rdpq_enable = 1;) ? also fix 'disbale' It's enabled by default. I will fix typo. > > > + > > MODULE_LICENSE("GPL"); > > MODULE_VERSION(MEGASAS_VERSION); > > MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com"); > > @@ -5081,6 +5085,9 @@ static int megasas_init_fw(struct megasas_instance > *instance) > > instance->msix_vectors = ((scratch_pad_2 > > & > MR_MAX_REPLY_QUEUES_EXT_OFFSET) > > >> > MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; > > + if (rdpq_enable) > > + instance->is_rdpq = (scratch_pad_2 & > MR_RDPQ_MODE_OFFSET) ? > > + 1 : 0; > > fw_msix_count = instance->msix_vectors; > > /* Save 1-15 reply post index address to local > memory > > * Index 0 is already saved from reg offset @@ > -5117,6 +5124,8 @@ > > static int megasas_init_fw(struct megasas_instance *instance) > > dev_info(&instance->pdev->dev, > > "current msix/online cpus\t: (%d/%d)\n", > > instance->msix_vectors, (unsigned int)num_online_cpus()); > > + dev_info(&instance->pdev->dev, > > + "firmware supports rdpq mode\t: (%d)\n", instance->is_rdpq); > > just a nit, but is_rdpq depends also on rdpq_enable, so the text is not precise I will modify text to reflect the correct information. > > > > > tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, > > (unsigned long)instance); > > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c > > b/drivers/scsi/megaraid/megaraid_sas_fusion.c > > index e8730ef..aca0cd3 100644 > > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c > > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c > > @@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance > *instance, > > void *fn, unsigned long interval); extern struct > > megasas_mgmt_info megasas_mgmt_info; extern int resetwaittime; > > +static void megasas_free_rdpq_fusion(struct megasas_instance > > +*instance); static void megasas_free_reply_fusion(struct > > +megasas_instance *instance); > > > > > > > > @@ -205,112 +207,71 @@ megasas_fire_cmd_fusion(struct > megasas_instance > > *instance, #endif } > > > > - > > /** > > - * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA > pool > > - * @instance: Adapter soft state > > + * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool > > + * @instance: Adapter soft state > > */ > > -static void megasas_teardown_frame_pool_fusion( > > - struct megasas_instance *instance) > > +void > > +megasas_free_cmds_fusion(struct megasas_instance *instance) > > { > > int i; > > struct fusion_context *fusion = instance->ctrl_context; > > - > > - u16 max_cmd = instance->max_fw_cmds; > > - > > struct megasas_cmd_fusion *cmd; > > > > - if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) { > > - dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, " > > - "sense pool : %p\n", fusion->sg_dma_pool, > > - fusion->sense_dma_pool); > > - return; > > - } > > - > > - /* > > - * Return all frames to pool > > - */ > > - for (i = 0; i < max_cmd; i++) { > > - > > + /* SG, Sense */ > > + for (i = 0; i < instance->max_fw_cmds; i++) { > > cmd = fusion->cmd_list[i]; > > cmd might be NULL here, add a test please Cmd cannot be NULL. If I am missing, do you see any instance where cmd might be NULL? > > > - > > if (cmd->sg_frame) > > pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame, > > - cmd->sg_frame_phys_addr); > > - > > + cmd->sg_frame_phys_addr); > > if (cmd->sense) > > pci_pool_free(fusion->sense_dma_pool, cmd->sense, > > - cmd->sense_phys_addr); > > + cmd->sense_phys_addr); > > } > > > > - /* > > - * Now destroy the pool itself > > - */ > > - pci_pool_destroy(fusion->sg_dma_pool); > > - pci_pool_destroy(fusion->sense_dma_pool); > > - > > - fusion->sg_dma_pool = NULL; > > - fusion->sense_dma_pool = NULL; > > -} > > - > > -/** > > - * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool > > - * @instance: Adapter soft state > > - */ > > -void > > -megasas_free_cmds_fusion(struct megasas_instance *instance) -{ > > - int i; > > - struct fusion_context *fusion = instance->ctrl_context; > > - > > - u32 max_cmds, req_sz, reply_sz, io_frames_sz; > > - > > + if (fusion->sg_dma_pool) { > > + pci_pool_destroy(fusion->sg_dma_pool); > > + fusion->sg_dma_pool = NULL; > > + } > > + if (fusion->sense_dma_pool) { > > + pci_pool_destroy(fusion->sense_dma_pool); > > + fusion->sense_dma_pool = NULL; > > If this is needed (fusion->sense_dma_pool = NULL;), why don't we need it few > lines below for example for fusion->io_request_frames_pool ? > (there should be some consistency here) > Agree.. will add (fusion->io_request_frames_pool=NULL). > > > + } > > > > - req_sz = fusion->request_alloc_sz; > > - reply_sz = fusion->reply_alloc_sz; > > - io_frames_sz = fusion->io_frames_alloc_sz; > > > > - max_cmds = instance->max_fw_cmds; > > + /* Reply Frame, Desc*/ > > + if (instance->is_rdpq) > > + megasas_free_rdpq_fusion(instance); > > + else > > + megasas_free_reply_fusion(instance); > > > > - /* Free descriptors and request Frames memory */ > > + /* Request Frame, Desc*/ > > if (fusion->req_frames_desc) > > - dma_free_coherent(&instance->pdev->dev, req_sz, > > - fusion->req_frames_desc, > > - fusion->req_frames_desc_phys); > > - > > - if (fusion->reply_frames_desc) { > > - pci_pool_free(fusion->reply_frames_desc_pool, > > - fusion->reply_frames_desc, > > - fusion->reply_frames_desc_phys); > > - pci_pool_destroy(fusion->reply_frames_desc_pool); > > - } > > - > > - if (fusion->io_request_frames) { > > + dma_free_coherent(&instance->pdev->dev, > > + fusion->request_alloc_sz, fusion->req_frames_desc, > > + fusion->req_frames_desc_phys); > > + if (fusion->io_request_frames) > > pci_pool_free(fusion->io_request_frames_pool, > > - fusion->io_request_frames, > > - fusion->io_request_frames_phys); > > + fusion->io_request_frames, > > + fusion->io_request_frames_phys); > > + if (fusion->io_request_frames_pool) > > pci_pool_destroy(fusion->io_request_frames_pool); > > - } > > > > - /* Free the Fusion frame pool */ > > - megasas_teardown_frame_pool_fusion(instance); > > > > - /* Free all the commands in the cmd_list */ > > - for (i = 0; i < max_cmds; i++) > > + /* cmd_list */ > > + for (i = 0; i < instance->max_fw_cmds; i++) > > kfree(fusion->cmd_list[i]); > > > > - /* Free the cmd_list buffer itself */ > > kfree(fusion->cmd_list); > > fusion->cmd_list = NULL; > > It is a good idea to set (fusion->cmd_list = NULL;), but a test to the kfree should > be added Kfree returns void. What test is needed here? Please clarify if you mean something elase. > > > - > > } > > > > /** > > - * megasas_create_frame_pool_fusion - Creates DMA pool for cmd > frames > > + * megasas_create_sg_sense_fusion - Creates DMA pool for cmd frames > > * @instance: Adapter soft state > > * > > */ > > -static int megasas_create_frame_pool_fusion(struct megasas_instance > > *instance) > > +static int megasas_create_sg_sense_fusion(struct megasas_instance > > +*instance) > > { > > int i; > > u32 max_cmd; > > @@ -321,186 +282,299 @@ static int > megasas_create_frame_pool_fusion(struct megasas_instance *instance) > > max_cmd = instance->max_fw_cmds; > > > > > > - /* > > - * Use DMA pool facility provided by PCI layer > > - */ > > - > > - fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance- > >pdev, > > - instance- > >max_chain_frame_sz, > > - 4, 0); > > - if (!fusion->sg_dma_pool) { > > - dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to > setup request pool fusion\n"); > > - return -ENOMEM; > > - } > > - fusion->sense_dma_pool = pci_pool_create("sense pool fusion", > > - instance->pdev, > > - SCSI_SENSE_BUFFERSIZE, 64, > 0); > > + fusion->sg_dma_pool = > > + pci_pool_create("mr_sg", instance->pdev, > > + instance->max_chain_frame_sz, 4, 0); > > + /* SCSI_SENSE_BUFFERSIZE = 96 bytes */ > > + fusion->sense_dma_pool = > > + pci_pool_create("mr_sense", instance->pdev, > > + SCSI_SENSE_BUFFERSIZE, 64, 0); > > > > - if (!fusion->sense_dma_pool) { > > - dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to > setup sense pool fusion\n"); > > - pci_pool_destroy(fusion->sg_dma_pool); > > - fusion->sg_dma_pool = NULL; > > - return -ENOMEM; > > - } > > + if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > Allocation failed - I don't think we can ignore it. Agreed..Will rectify this. > > > > > /* > > * Allocate and attach a frame to each of the commands in cmd_list > > */ > > for (i = 0; i < max_cmd; i++) { > > - > > cmd = fusion->cmd_list[i]; > > - > > cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool, > > - GFP_KERNEL, > > - &cmd->sg_frame_phys_addr); > > + GFP_KERNEL, &cmd- > >sg_frame_phys_addr); > > > > cmd->sense = pci_pool_alloc(fusion->sense_dma_pool, > > - GFP_KERNEL, &cmd- > >sense_phys_addr); > > - /* > > - * megasas_teardown_frame_pool_fusion() takes care of > freeing > > - * whatever has been allocated > > - */ > > + GFP_KERNEL, &cmd- > >sense_phys_addr); > > if (!cmd->sg_frame || !cmd->sense) { > > - dev_printk(KERN_DEBUG, &instance->pdev->dev, > "pci_pool_alloc failed\n"); > > - megasas_teardown_frame_pool_fusion(instance); > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > return -ENOMEM; > > } > > } > > return 0; > > } > > > > -/** > > - * megasas_alloc_cmds_fusion - Allocates the command packets > > - * @instance: Adapter soft state > > - * > > - * > > - * Each frame has a 32-bit field called context. This context is used > > to get > > - * back the megasas_cmd_fusion from the frame when a frame gets > > completed > > - * In this driver, the 32 bit values are the indices into an array cmd_list. > > - * This array is used only to look up the megasas_cmd_fusion given the > context. > > - * The free commands themselves are maintained in a linked list called > cmd_pool. > > - * > > - * cmds are formed in the io_request and sg_frame members of the > > - * megasas_cmd_fusion. The context field is used to get a request > > descriptor > > - * and is used as SMID of the cmd. > > - * SMID value range is from 1 to max_fw_cmds. > > - */ > > int > > -megasas_alloc_cmds_fusion(struct megasas_instance *instance) > > +megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) > > { > > - int i, j, count; > > - u32 max_cmd, io_frames_sz; > > + u32 max_cmd, i; > > struct fusion_context *fusion; > > - struct megasas_cmd_fusion *cmd; > > - union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; > > - u32 offset; > > - dma_addr_t io_req_base_phys; > > - u8 *io_req_base; > > > > fusion = instance->ctrl_context; > > > > max_cmd = instance->max_fw_cmds; > > > > + /* > > + * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. > > + * Allocate the dynamic array first and then allocate individual > > + * commands. > > + */ > > + fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) * > max_cmd, > > + GFP_KERNEL); > > + if (!fusion->cmd_list) { > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > + return -ENOMEM; > > + } > > + memset(fusion->cmd_list, 0, > > + sizeof(struct megasas_cmd_fusion *) * max_cmd); > > + > > + for (i = 0; i < max_cmd; i++) { > > + fusion->cmd_list[i] = kmalloc(sizeof(struct > megasas_cmd_fusion), > > + GFP_KERNEL); > > kzalloc here and there, as the kbuild script already wrote > > > + if (!fusion->cmd_list[i]) { > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > + return -ENOMEM; > > + } > > + memset(fusion->cmd_list[i], 0, sizeof(struct > megasas_cmd_fusion)); > > + } > > + return 0; > > +} > > +int > > +megasas_alloc_request_fusion(struct megasas_instance *instance) { > > + struct fusion_context *fusion; > > + > > + fusion = instance->ctrl_context; > > + > > fusion->req_frames_desc = > > dma_alloc_coherent(&instance->pdev->dev, > > - fusion->request_alloc_sz, > > - &fusion->req_frames_desc_phys, > GFP_KERNEL); > > - > > + fusion->request_alloc_sz, > > + &fusion->req_frames_desc_phys, GFP_KERNEL); > > if (!fusion->req_frames_desc) { > > - dev_err(&instance->pdev->dev, "Could not allocate memory for > " > > - "request_frames\n"); > > - goto fail_req_desc; > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > + return -ENOMEM; > > + } > > + > > + fusion->io_request_frames_pool = > > + pci_pool_create("mr_ioreq", instance->pdev, > > + fusion->io_frames_alloc_sz, 16, 0); > > Why do you need a pool, you just allocate once a single region, or not? > Please turn it into a dma_alloc_coherent. There are some places where dma_alloc_coherent can be used instead of PCI APIs. If you are OK with ignoring this for now, I will be sending followup patch to address all such issues. > > > + > > + if (!fusion->io_request_frames_pool) { > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > + return -ENOMEM; > > + } > > + > > + fusion->io_request_frames = > > + pci_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; > > } > > + return 0; > > +} > > + > > +int > > +megasas_alloc_reply_fusion(struct megasas_instance *instance) { > > + int i, count; > > + struct fusion_context *fusion; > > + union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; > > + fusion = instance->ctrl_context; > > > > count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; > > fusion->reply_frames_desc_pool = > > - pci_pool_create("reply_frames pool", instance->pdev, > > + pci_pool_create("mr_reply", instance->pdev, > > fusion->reply_alloc_sz * count, 16, 0); > > > > if (!fusion->reply_frames_desc_pool) { > > - dev_err(&instance->pdev->dev, "Could not allocate memory for > " > > - "reply_frame pool\n"); > > - goto fail_reply_desc; > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > + return -ENOMEM; > > } > > Same here, I could understand it if the code were merged with > megasas_alloc_rdpq_fusion but it is not. Why a pool? Same reason for this.. > > > > > - fusion->reply_frames_desc = > > - pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL, > > - &fusion->reply_frames_desc_phys); > > - if (!fusion->reply_frames_desc) { > > - dev_err(&instance->pdev->dev, "Could not allocate memory for > " > > - "reply_frame pool\n"); > > - pci_pool_destroy(fusion->reply_frames_desc_pool); > > - goto fail_reply_desc; > > + fusion->reply_frames_desc[0] = > > + pci_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; > > + 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); > > + reply_desc->Words = ULLONG_MAX; > > The megasas_reset_reply_desc function seems to be used for this kind of > resetting, could it be used here ? (and in megasas_alloc_rdpq_fusion) There you > also kept the cpu_to_le64(..) that doesn't matter, but again for consistency... I will take care of all this in next patchset. > > > > > - io_frames_sz = fusion->io_frames_alloc_sz; > > + /* This is not a rdpq mode, but driver still populate > > + * reply_frame_desc array to use same msix index in ISR path. > > + */ > > + for (i = 0; i < (count - 1); i++) > > + fusion->reply_frames_desc[i + 1] = > > + fusion->reply_frames_desc[i] + > > + (fusion->reply_alloc_sz)/sizeof(union > > +MPI2_REPLY_DESCRIPTORS_UNION); > > > > - fusion->io_request_frames_pool = > > - pci_pool_create("io_request_frames pool", instance->pdev, > > - fusion->io_frames_alloc_sz, 16, 0); > > + return 0; > > +} > > > > - if (!fusion->io_request_frames_pool) { > > - dev_err(&instance->pdev->dev, "Could not allocate memory for > " > > - "io_request_frame pool\n"); > > - goto fail_io_frames; > > +int > > +megasas_alloc_rdpq_fusion(struct megasas_instance *instance) { > > + int i, j, count; > > + struct fusion_context *fusion; > > + union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; > > + > > + fusion = instance->ctrl_context; > > + > > + fusion->rdpq_virt = pci_alloc_consistent(instance->pdev, > > + sizeof(struct > MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * > > +MAX_MSIX_QUEUES_FUSION, > > is dma_alloc_coherent possible here? > > > + &fusion->rdpq_phys); > > + if (!fusion->rdpq_virt) { > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > + return -ENOMEM; > > } > > > > - fusion->io_request_frames = > > - pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL, > > - &fusion->io_request_frames_phys); > > - if (!fusion->io_request_frames) { > > - dev_err(&instance->pdev->dev, "Could not allocate memory for > " > > - "io_request_frames frames\n"); > > - pci_pool_destroy(fusion->io_request_frames_pool); > > - goto fail_io_frames; > > + 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; > > + fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq", > > + instance->pdev, > fusion->reply_alloc_sz, 16, 0); > > + > > + if (!fusion->reply_frames_desc_pool) { > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > + return -ENOMEM; > > } > > > > - /* > > - * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. > > - * Allocate the dynamic array first and then allocate individual > > - * commands. > > - */ > > - fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) > > - * max_cmd, GFP_KERNEL); > > + for (i = 0; i < count; i++) { > > + fusion->reply_frames_desc[i] = > > + pci_pool_alloc(fusion- > >reply_frames_desc_pool, > > + GFP_KERNEL, &fusion- > >reply_frames_desc_phys[i]); > > + if (!fusion->reply_frames_desc[i]) { > > + dev_err(&instance->pdev->dev, > > + "Failed from %s %d\n", __func__, __LINE__); > > + return -ENOMEM; > > + } > > > > - if (!fusion->cmd_list) { > > - dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of > memory. Could not alloc " > > - "memory for cmd_list_fusion\n"); > > - goto fail_cmd_list; > > + fusion->rdpq_virt[i].RDPQBaseAddress = > > + fusion->reply_frames_desc_phys[i]; > > + > > + reply_desc = fusion->reply_frames_desc[i]; > > + for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++) > > + reply_desc->Words = ULLONG_MAX; > > } > > + return 0; > > +} > > > > - max_cmd = instance->max_fw_cmds; > > - for (i = 0; i < max_cmd; i++) { > > - fusion->cmd_list[i] = kmalloc(sizeof(struct > megasas_cmd_fusion), > > - GFP_KERNEL); > > - if (!fusion->cmd_list[i]) { > > - dev_err(&instance->pdev->dev, "Could not alloc cmd > list fusion\n"); > > +static void > > +megasas_free_rdpq_fusion(struct megasas_instance *instance) { > > > > - for (j = 0; j < i; j++) > > - kfree(fusion->cmd_list[j]); > > + int i; > > + struct fusion_context *fusion; > > > > - kfree(fusion->cmd_list); > > - fusion->cmd_list = NULL; > > - goto fail_cmd_list; > > - } > > + fusion = instance->ctrl_context; > > + > > + for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) { > > + if (fusion->reply_frames_desc[i]) > > + pci_pool_free(fusion->reply_frames_desc_pool, > > + fusion->reply_frames_desc[i], > > + fusion->reply_frames_desc_phys[i]); > > } > > > > - /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */ > > - io_req_base = fusion->io_request_frames + > > - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; > > - io_req_base_phys = fusion->io_request_frames_phys + > > - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; > > + if (fusion->reply_frames_desc_pool) > > + pci_pool_destroy(fusion->reply_frames_desc_pool); > > + > > + if (fusion->rdpq_virt) > > + pci_free_consistent(instance->pdev, > > + sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * > MAX_MSIX_QUEUES_FUSION, > > + fusion->rdpq_virt, fusion->rdpq_phys); } > > + > > +static void > > +megasas_free_reply_fusion(struct megasas_instance *instance) { > > + > > + struct fusion_context *fusion; > > + > > + fusion = instance->ctrl_context; > > + > > + if (fusion->reply_frames_desc[0]) > > + pci_pool_free(fusion->reply_frames_desc_pool, > > + fusion->reply_frames_desc[0], > > + fusion->reply_frames_desc_phys[0]); > > + > > + if (fusion->reply_frames_desc_pool) > > + pci_pool_destroy(fusion->reply_frames_desc_pool); > > + > > +} > > + > > + > > +/** > > + * megasas_alloc_cmds_fusion - Allocates the command packets > > + * @instance: Adapter soft state > > + * > > + * > > + * Each frame has a 32-bit field called context. This context is used > > +to get > > + * back the megasas_cmd_fusion from the frame when a frame gets > > +completed > > + * In this driver, the 32 bit values are the indices into an array cmd_list. > > + * This array is used only to look up the megasas_cmd_fusion given the > context. > > + * The free commands themselves are maintained in a linked list called > cmd_pool. > > + * > > + * cmds are formed in the io_request and sg_frame members of the > > + * megasas_cmd_fusion. The context field is used to get a request > > +descriptor > > + * and is used as SMID of the cmd. > > + * SMID value range is from 1 to max_fw_cmds. > > + */ > > +int > > +megasas_alloc_cmds_fusion(struct megasas_instance *instance) { > > + int i; > > + struct fusion_context *fusion; > > + struct megasas_cmd_fusion *cmd; > > + u32 offset; > > + dma_addr_t io_req_base_phys; > > + u8 *io_req_base; > > + > > + > > + fusion = instance->ctrl_context; > > + > > + if (megasas_alloc_cmdlist_fusion(instance)) > > We may need to call megasas_free_cmds_fusion here too (to free fusion- > >cmd_list) I will work on all error condition handling stuff.. > > > + return -ENOMEM; > > + > > + if (megasas_alloc_request_fusion(instance)) > > + goto fail_exit; > > + > > + if (instance->is_rdpq) { > > + if (megasas_alloc_rdpq_fusion(instance)) > > + goto fail_exit; > > + } else > > + if (megasas_alloc_reply_fusion(instance)) > > + goto fail_exit; > > + > > + > > + /* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */ > > + io_req_base = fusion->io_request_frames + > MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; > > + io_req_base_phys = fusion->io_request_frames_phys + > > +MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; > > > > /* > > * Add all the commands to command pool (fusion->cmd_pool) > > */ > > > > /* SMID 0 is reserved. Set SMID/index from 1 */ > > - for (i = 0; i < max_cmd; i++) { > > + for (i = 0; i < instance->max_fw_cmds; i++) { > > cmd = fusion->cmd_list[i]; > > offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; > > memset(cmd, 0, sizeof(struct megasas_cmd_fusion)); > > That memset was already done in megasas_alloc_cmdlist_fusion Will use kzalloc instead of kmalloc to avoid all memset to zero instructions. > > > @@ -518,35 +592,13 @@ megasas_alloc_cmds_fusion(struct > megasas_instance *instance) > > cmd->io_request_phys_addr = io_req_base_phys + offset; > > }/ > > > > - /* > > - * Create a frame pool and assign one frame to each cmd > > - */ > > - if (megasas_create_frame_pool_fusion(instance)) { > > - dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error > creating frame DMA pool\n"); > > - megasas_free_cmds_fusion(instance); > > - goto fail_req_desc; > > - } > > + if (megasas_create_sg_sense_fusion(instance)) > > + goto fail_exit; > > > > return 0; > > > > -fail_cmd_list: > > - pci_pool_free(fusion->io_request_frames_pool, fusion- > >io_request_frames, > > - fusion->io_request_frames_phys); > > - pci_pool_destroy(fusion->io_request_frames_pool); > > -fail_io_frames: > > - dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, > > - fusion->reply_frames_desc, > > - fusion->reply_frames_desc_phys); > > - pci_pool_free(fusion->reply_frames_desc_pool, > > - fusion->reply_frames_desc, > > - fusion->reply_frames_desc_phys); > > - pci_pool_destroy(fusion->reply_frames_desc_pool); > > - > > -fail_reply_desc: > > - dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, > > - fusion->req_frames_desc, > > - fusion->req_frames_desc_phys); > > -fail_req_desc: > > +fail_exit: > > + megasas_free_cmds_fusion(instance); > > return -ENOMEM; > > } > > > > @@ -594,16 +646,17 @@ int > > megasas_ioc_init_fusion(struct megasas_instance *instance) { > > struct megasas_init_frame *init_frame; > > - struct MPI2_IOC_INIT_REQUEST *IOCInitMessage; > > + struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL; > > dma_addr_t ioc_init_handle; > > struct megasas_cmd *cmd; > > - u8 ret; > > + u8 ret, cur_rdpq_mode; > > struct fusion_context *fusion; > > union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc; > > int i; > > struct megasas_header *frame_hdr; > > const char *sys_info; > > MFI_CAPABILITIES *drv_ops; > > + u32 scratch_pad_2; > > > > fusion = instance->ctrl_context; > > > > @@ -615,6 +668,18 @@ megasas_ioc_init_fusion(struct megasas_instance > *instance) > > goto fail_get_cmd; > > } > > > > + scratch_pad_2 = readl > > + (&instance->reg_set->outbound_scratch_pad_2); > > + > > + cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0; > > + > > + if (instance->is_rdpq && !cur_rdpq_mode) { > > + dev_err(&instance->pdev->dev, "Firmware downgrade *NOT > SUPPORTED*" > > + " from RDPQ mode to non RDPQ mode\n"); > > How does this work ? is_rdpq is set in megasas_init_fw only when the fw > supports it, why do you test it here again ? I think I'm miss something. "is_rdpq" stores the capability of firmware flashed during driver load and "cur_rdpq_mode" tells capability of upgraded/downgraded firmware(OFU) without reloading driver. This condition is just to ensure that firmware downgrade from RDPQ mode to non RDPQ mode should not be allowed. > > Tomas > > > + ret = 1; > > + goto fail_fw_init; > > + } > > + > > IOCInitMessage = > > dma_alloc_coherent(&instance->pdev->dev, > > sizeof(struct MPI2_IOC_INIT_REQUEST), @@ -636,7 > +701,11 @@ > > megasas_ioc_init_fusion(struct megasas_instance *instance) > > IOCInitMessage->SystemRequestFrameSize = > > cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4); > > > > IOCInitMessage->ReplyDescriptorPostQueueDepth = > cpu_to_le16(fusion->reply_q_depth); > > - IOCInitMessage->ReplyDescriptorPostQueueAddress = > cpu_to_le64(fusion->reply_frames_desc_phys); > > + IOCInitMessage->ReplyDescriptorPostQueueAddress = instance- > >is_rdpq ? > > + cpu_to_le64(fusion->rdpq_phys) : > > + cpu_to_le64(fusion->reply_frames_desc_phys[0]); > > + IOCInitMessage->MsgFlags = instance->is_rdpq ? > > + MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0; > > IOCInitMessage->SystemRequestFrameBaseAddress = > cpu_to_le64(fusion->io_request_frames_phys); > > IOCInitMessage->HostMSIxVectors = instance->msix_vectors; > > init_frame = (struct megasas_init_frame *)cmd->frame; @@ -1087,7 > > +1156,10 @@ megasas_init_adapter_fusion(struct megasas_instance > *instance) > > */ > > instance->max_fw_cmds = > > instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; > > - instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008); > > + dev_info(&instance->pdev->dev, > > + "firmware support max fw cmd\t: (%d)\n", instance- > >max_fw_cmds); > > + if (!instance->is_rdpq) > > + instance->max_fw_cmds = min_t(u16, instance- > >max_fw_cmds, 1024); > > > > /* > > * Reduce the max supported cmds by 1. This is to ensure that the @@ > > -2110,10 +2182,8 @@ complete_cmd_fusion(struct megasas_instance > *instance, u32 MSIxIndex) > > if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) > > return IRQ_HANDLED; > > > > - desc = fusion->reply_frames_desc; > > - desc += ((MSIxIndex * fusion->reply_alloc_sz)/ > > - sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) + > > - fusion->last_reply_idx[MSIxIndex]; > > + desc = fusion->reply_frames_desc[MSIxIndex] + > > + fusion->last_reply_idx[MSIxIndex]; > > > > reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR > *)desc; > > > > @@ -2208,9 +2278,7 @@ complete_cmd_fusion(struct megasas_instance > > *instance, u32 MSIxIndex) > > > > /* Get the next reply descriptor */ > > if (!fusion->last_reply_idx[MSIxIndex]) > > - desc = fusion->reply_frames_desc + > > - ((MSIxIndex * fusion->reply_alloc_sz)/ > > - sizeof(union > MPI2_REPLY_DESCRIPTORS_UNION)); > > + desc = fusion->reply_frames_desc[MSIxIndex]; > > else > > desc++; > > > > @@ -2688,17 +2756,18 @@ out: > > > > void megasas_reset_reply_desc(struct megasas_instance *instance) { > > - int i, count; > > + int i, j, count; > > struct fusion_context *fusion; > > union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; > > > > fusion = instance->ctrl_context; > > count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; > > - for (i = 0 ; i < count ; i++) > > + for (i = 0 ; i < count ; i++) { > > fusion->last_reply_idx[i] = 0; > > - reply_desc = fusion->reply_frames_desc; > > - for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++) > > - reply_desc->Words = cpu_to_le64(ULLONG_MAX); > > + 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); > > + } > > } > > > > /* > > diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h > > b/drivers/scsi/megaraid/megaraid_sas_fusion.h > > index db0978d..80eaee2 100644 > > --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h > > +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h > > @@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC { > > struct MR_PD_CFG_SEQ seq[1]; > > } __packed; > > > > +struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { > > + u64 RDPQBaseAddress; > > + u32 Reserved1; > > + u32 Reserved2; > > +}; > > + > > struct fusion_context { > > struct megasas_cmd_fusion **cmd_list; > > dma_addr_t req_frames_desc_phys; > > @@ -940,8 +946,8 @@ struct fusion_context { > > struct dma_pool *sg_dma_pool; > > struct dma_pool *sense_dma_pool; > > > > - dma_addr_t reply_frames_desc_phys; > > - union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc; > > + dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION]; > > + union MPI2_REPLY_DESCRIPTORS_UNION > > +*reply_frames_desc[MAX_MSIX_QUEUES_FUSION]; > > struct dma_pool *reply_frames_desc_pool; > > > > u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION]; > > @@ -951,6 +957,8 @@ struct fusion_context { > > u32 reply_alloc_sz; > > u32 io_frames_alloc_sz; > > > > + struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt; > > + dma_addr_t rdpq_phys; > > u16 max_sge_in_main_msg; > > u16 max_sge_in_chain; > > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 01135be..c539516 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -152,6 +152,7 @@ #define MFI_RESET_FLAGS MFI_INIT_READY| \ MFI_INIT_MFIMODE| \ MFI_INIT_ABORT +#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01) /* * MFI frame flags @@ -1416,6 +1417,7 @@ enum DCMD_TIMEOUT_ACTION { #define MR_MAX_REPLY_QUEUES_EXT_OFFSET 0X003FC000 #define MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT 14 #define MR_MAX_MSIX_REG_ARRAY 16 +#define MR_RDPQ_MODE_OFFSET 0X00800000 /* * register set for both 1068 and 1078 controllers * structure extended for 1078 registers @@ -1455,8 +1457,9 @@ struct megasas_register_set { u32 outbound_scratch_pad ; /*00B0h*/ u32 outbound_scratch_pad_2; /*00B4h*/ + u32 outbound_scratch_pad_3; /*00B8h*/ - u32 reserved_4[2]; /*00B8h*/ + u32 reserved_4; /*00BCh*/ u32 inbound_low_queue_port ; /*00C0h*/ @@ -2117,6 +2120,7 @@ struct megasas_instance { u8 mask_interrupts; u16 max_chain_frame_sz; u8 is_imr; + u8 is_rdpq; bool dev_handle; }; struct MR_LD_VF_MAP { diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index df93fa1..a3b63fa 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -92,6 +92,10 @@ int smp_affinity_enable = 1; module_param(smp_affinity_enable, int, S_IRUGO); MODULE_PARM_DESC(smp_affinity_enable, "SMP affinity feature enable/disbale Default: enable(1)"); +int rdpq_enable = 1; +module_param(rdpq_enable, int, S_IRUGO); +MODULE_PARM_DESC(rdpq_enable, " Allocate reply queue in chunks for large queue depth enable/disbale Default: disable(0)"); + MODULE_LICENSE("GPL"); MODULE_VERSION(MEGASAS_VERSION); MODULE_AUTHOR("megaraidlinux.pdl@avagotech.com"); @@ -5081,6 +5085,9 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->msix_vectors = ((scratch_pad_2 & MR_MAX_REPLY_QUEUES_EXT_OFFSET) >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1; + if (rdpq_enable) + instance->is_rdpq = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? + 1 : 0; fw_msix_count = instance->msix_vectors; /* Save 1-15 reply post index address to local memory * Index 0 is already saved from reg offset @@ -5117,6 +5124,8 @@ static int megasas_init_fw(struct megasas_instance *instance) dev_info(&instance->pdev->dev, "current msix/online cpus\t: (%d/%d)\n", instance->msix_vectors, (unsigned int)num_online_cpus()); + dev_info(&instance->pdev->dev, + "firmware supports rdpq mode\t: (%d)\n", instance->is_rdpq); tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, (unsigned long)instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index e8730ef..aca0cd3 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -92,6 +92,8 @@ void megasas_start_timer(struct megasas_instance *instance, void *fn, unsigned long interval); extern struct megasas_mgmt_info megasas_mgmt_info; extern int resetwaittime; +static void megasas_free_rdpq_fusion(struct megasas_instance *instance); +static void megasas_free_reply_fusion(struct megasas_instance *instance); @@ -205,112 +207,71 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance, #endif } - /** - * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool - * @instance: Adapter soft state + * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool + * @instance: Adapter soft state */ -static void megasas_teardown_frame_pool_fusion( - struct megasas_instance *instance) +void +megasas_free_cmds_fusion(struct megasas_instance *instance) { int i; struct fusion_context *fusion = instance->ctrl_context; - - u16 max_cmd = instance->max_fw_cmds; - struct megasas_cmd_fusion *cmd; - if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) { - dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, " - "sense pool : %p\n", fusion->sg_dma_pool, - fusion->sense_dma_pool); - return; - } - - /* - * Return all frames to pool - */ - for (i = 0; i < max_cmd; i++) { - + /* SG, Sense */ + for (i = 0; i < instance->max_fw_cmds; i++) { cmd = fusion->cmd_list[i]; - if (cmd->sg_frame) pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame, - cmd->sg_frame_phys_addr); - + cmd->sg_frame_phys_addr); if (cmd->sense) pci_pool_free(fusion->sense_dma_pool, cmd->sense, - cmd->sense_phys_addr); + cmd->sense_phys_addr); } - /* - * Now destroy the pool itself - */ - pci_pool_destroy(fusion->sg_dma_pool); - pci_pool_destroy(fusion->sense_dma_pool); - - fusion->sg_dma_pool = NULL; - fusion->sense_dma_pool = NULL; -} - -/** - * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool - * @instance: Adapter soft state - */ -void -megasas_free_cmds_fusion(struct megasas_instance *instance) -{ - int i; - struct fusion_context *fusion = instance->ctrl_context; - - u32 max_cmds, req_sz, reply_sz, io_frames_sz; - + if (fusion->sg_dma_pool) { + pci_pool_destroy(fusion->sg_dma_pool); + fusion->sg_dma_pool = NULL; + } + if (fusion->sense_dma_pool) { + pci_pool_destroy(fusion->sense_dma_pool); + fusion->sense_dma_pool = NULL; + } - req_sz = fusion->request_alloc_sz; - reply_sz = fusion->reply_alloc_sz; - io_frames_sz = fusion->io_frames_alloc_sz; - max_cmds = instance->max_fw_cmds; + /* Reply Frame, Desc*/ + if (instance->is_rdpq) + megasas_free_rdpq_fusion(instance); + else + megasas_free_reply_fusion(instance); - /* Free descriptors and request Frames memory */ + /* Request Frame, Desc*/ if (fusion->req_frames_desc) - dma_free_coherent(&instance->pdev->dev, req_sz, - fusion->req_frames_desc, - fusion->req_frames_desc_phys); - - if (fusion->reply_frames_desc) { - pci_pool_free(fusion->reply_frames_desc_pool, - fusion->reply_frames_desc, - fusion->reply_frames_desc_phys); - pci_pool_destroy(fusion->reply_frames_desc_pool); - } - - if (fusion->io_request_frames) { + dma_free_coherent(&instance->pdev->dev, + fusion->request_alloc_sz, fusion->req_frames_desc, + fusion->req_frames_desc_phys); + if (fusion->io_request_frames) pci_pool_free(fusion->io_request_frames_pool, - fusion->io_request_frames, - fusion->io_request_frames_phys); + fusion->io_request_frames, + fusion->io_request_frames_phys); + if (fusion->io_request_frames_pool) pci_pool_destroy(fusion->io_request_frames_pool); - } - /* Free the Fusion frame pool */ - megasas_teardown_frame_pool_fusion(instance); - /* Free all the commands in the cmd_list */ - for (i = 0; i < max_cmds; i++) + /* cmd_list */ + for (i = 0; i < instance->max_fw_cmds; i++) kfree(fusion->cmd_list[i]); - /* Free the cmd_list buffer itself */ kfree(fusion->cmd_list); fusion->cmd_list = NULL; - } /** - * megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames + * megasas_create_sg_sense_fusion - Creates DMA pool for cmd frames * @instance: Adapter soft state * */ -static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) +static int megasas_create_sg_sense_fusion(struct megasas_instance *instance) { int i; u32 max_cmd; @@ -321,186 +282,299 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) max_cmd = instance->max_fw_cmds; - /* - * Use DMA pool facility provided by PCI layer - */ - - fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev, - instance->max_chain_frame_sz, - 4, 0); - if (!fusion->sg_dma_pool) { - dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n"); - return -ENOMEM; - } - fusion->sense_dma_pool = pci_pool_create("sense pool fusion", - instance->pdev, - SCSI_SENSE_BUFFERSIZE, 64, 0); + fusion->sg_dma_pool = + pci_pool_create("mr_sg", instance->pdev, + instance->max_chain_frame_sz, 4, 0); + /* SCSI_SENSE_BUFFERSIZE = 96 bytes */ + fusion->sense_dma_pool = + pci_pool_create("mr_sense", instance->pdev, + SCSI_SENSE_BUFFERSIZE, 64, 0); - if (!fusion->sense_dma_pool) { - dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n"); - pci_pool_destroy(fusion->sg_dma_pool); - fusion->sg_dma_pool = NULL; - return -ENOMEM; - } + if (!fusion->sense_dma_pool || !fusion->sg_dma_pool) + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); /* * Allocate and attach a frame to each of the commands in cmd_list */ for (i = 0; i < max_cmd; i++) { - cmd = fusion->cmd_list[i]; - cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool, - GFP_KERNEL, - &cmd->sg_frame_phys_addr); + GFP_KERNEL, &cmd->sg_frame_phys_addr); cmd->sense = pci_pool_alloc(fusion->sense_dma_pool, - GFP_KERNEL, &cmd->sense_phys_addr); - /* - * megasas_teardown_frame_pool_fusion() takes care of freeing - * whatever has been allocated - */ + GFP_KERNEL, &cmd->sense_phys_addr); if (!cmd->sg_frame || !cmd->sense) { - dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n"); - megasas_teardown_frame_pool_fusion(instance); + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); return -ENOMEM; } } return 0; } -/** - * megasas_alloc_cmds_fusion - Allocates the command packets - * @instance: Adapter soft state - * - * - * Each frame has a 32-bit field called context. This context is used to get - * back the megasas_cmd_fusion from the frame when a frame gets completed - * In this driver, the 32 bit values are the indices into an array cmd_list. - * This array is used only to look up the megasas_cmd_fusion given the context. - * The free commands themselves are maintained in a linked list called cmd_pool. - * - * cmds are formed in the io_request and sg_frame members of the - * megasas_cmd_fusion. The context field is used to get a request descriptor - * and is used as SMID of the cmd. - * SMID value range is from 1 to max_fw_cmds. - */ int -megasas_alloc_cmds_fusion(struct megasas_instance *instance) +megasas_alloc_cmdlist_fusion(struct megasas_instance *instance) { - int i, j, count; - u32 max_cmd, io_frames_sz; + u32 max_cmd, i; struct fusion_context *fusion; - struct megasas_cmd_fusion *cmd; - union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; - u32 offset; - dma_addr_t io_req_base_phys; - u8 *io_req_base; fusion = instance->ctrl_context; max_cmd = instance->max_fw_cmds; + /* + * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. + * Allocate the dynamic array first and then allocate individual + * commands. + */ + fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) * max_cmd, + GFP_KERNEL); + if (!fusion->cmd_list) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + memset(fusion->cmd_list, 0, + sizeof(struct megasas_cmd_fusion *) * max_cmd); + + for (i = 0; i < max_cmd; i++) { + fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion), + GFP_KERNEL); + if (!fusion->cmd_list[i]) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + memset(fusion->cmd_list[i], 0, sizeof(struct megasas_cmd_fusion)); + } + return 0; +} +int +megasas_alloc_request_fusion(struct megasas_instance *instance) +{ + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + fusion->req_frames_desc = dma_alloc_coherent(&instance->pdev->dev, - fusion->request_alloc_sz, - &fusion->req_frames_desc_phys, GFP_KERNEL); - + fusion->request_alloc_sz, + &fusion->req_frames_desc_phys, GFP_KERNEL); if (!fusion->req_frames_desc) { - dev_err(&instance->pdev->dev, "Could not allocate memory for " - "request_frames\n"); - goto fail_req_desc; + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } + + fusion->io_request_frames_pool = + pci_pool_create("mr_ioreq", instance->pdev, + fusion->io_frames_alloc_sz, 16, 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 = + pci_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; } + return 0; +} + +int +megasas_alloc_reply_fusion(struct megasas_instance *instance) +{ + int i, count; + struct fusion_context *fusion; + union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; + fusion = instance->ctrl_context; count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; fusion->reply_frames_desc_pool = - pci_pool_create("reply_frames pool", instance->pdev, + pci_pool_create("mr_reply", instance->pdev, fusion->reply_alloc_sz * count, 16, 0); if (!fusion->reply_frames_desc_pool) { - dev_err(&instance->pdev->dev, "Could not allocate memory for " - "reply_frame pool\n"); - goto fail_reply_desc; + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; } - fusion->reply_frames_desc = - pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL, - &fusion->reply_frames_desc_phys); - if (!fusion->reply_frames_desc) { - dev_err(&instance->pdev->dev, "Could not allocate memory for " - "reply_frame pool\n"); - pci_pool_destroy(fusion->reply_frames_desc_pool); - goto fail_reply_desc; + fusion->reply_frames_desc[0] = + pci_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; + 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); + reply_desc->Words = ULLONG_MAX; - io_frames_sz = fusion->io_frames_alloc_sz; + /* This is not a rdpq mode, but driver still populate + * reply_frame_desc array to use same msix index in ISR path. + */ + for (i = 0; i < (count - 1); i++) + fusion->reply_frames_desc[i + 1] = + fusion->reply_frames_desc[i] + + (fusion->reply_alloc_sz)/sizeof(union MPI2_REPLY_DESCRIPTORS_UNION); - fusion->io_request_frames_pool = - pci_pool_create("io_request_frames pool", instance->pdev, - fusion->io_frames_alloc_sz, 16, 0); + return 0; +} - if (!fusion->io_request_frames_pool) { - dev_err(&instance->pdev->dev, "Could not allocate memory for " - "io_request_frame pool\n"); - goto fail_io_frames; +int +megasas_alloc_rdpq_fusion(struct megasas_instance *instance) +{ + int i, j, count; + struct fusion_context *fusion; + union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; + + fusion = instance->ctrl_context; + + fusion->rdpq_virt = pci_alloc_consistent(instance->pdev, + sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION, + &fusion->rdpq_phys); + if (!fusion->rdpq_virt) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; } - fusion->io_request_frames = - pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL, - &fusion->io_request_frames_phys); - if (!fusion->io_request_frames) { - dev_err(&instance->pdev->dev, "Could not allocate memory for " - "io_request_frames frames\n"); - pci_pool_destroy(fusion->io_request_frames_pool); - goto fail_io_frames; + 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; + fusion->reply_frames_desc_pool = pci_pool_create("mr_rdpq", + instance->pdev, fusion->reply_alloc_sz, 16, 0); + + if (!fusion->reply_frames_desc_pool) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; } - /* - * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. - * Allocate the dynamic array first and then allocate individual - * commands. - */ - fusion->cmd_list = kzalloc(sizeof(struct megasas_cmd_fusion *) - * max_cmd, GFP_KERNEL); + for (i = 0; i < count; i++) { + fusion->reply_frames_desc[i] = + pci_pool_alloc(fusion->reply_frames_desc_pool, + GFP_KERNEL, &fusion->reply_frames_desc_phys[i]); + if (!fusion->reply_frames_desc[i]) { + dev_err(&instance->pdev->dev, + "Failed from %s %d\n", __func__, __LINE__); + return -ENOMEM; + } - if (!fusion->cmd_list) { - dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc " - "memory for cmd_list_fusion\n"); - goto fail_cmd_list; + fusion->rdpq_virt[i].RDPQBaseAddress = + fusion->reply_frames_desc_phys[i]; + + reply_desc = fusion->reply_frames_desc[i]; + for (j = 0; j < fusion->reply_q_depth; j++, reply_desc++) + reply_desc->Words = ULLONG_MAX; } + return 0; +} - max_cmd = instance->max_fw_cmds; - for (i = 0; i < max_cmd; i++) { - fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion), - GFP_KERNEL); - if (!fusion->cmd_list[i]) { - dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n"); +static void +megasas_free_rdpq_fusion(struct megasas_instance *instance) { - for (j = 0; j < i; j++) - kfree(fusion->cmd_list[j]); + int i; + struct fusion_context *fusion; - kfree(fusion->cmd_list); - fusion->cmd_list = NULL; - goto fail_cmd_list; - } + fusion = instance->ctrl_context; + + for (i = 0; i < MAX_MSIX_QUEUES_FUSION; i++) { + if (fusion->reply_frames_desc[i]) + pci_pool_free(fusion->reply_frames_desc_pool, + fusion->reply_frames_desc[i], + fusion->reply_frames_desc_phys[i]); } - /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */ - io_req_base = fusion->io_request_frames + - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; - io_req_base_phys = fusion->io_request_frames_phys + - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; + if (fusion->reply_frames_desc_pool) + pci_pool_destroy(fusion->reply_frames_desc_pool); + + if (fusion->rdpq_virt) + pci_free_consistent(instance->pdev, + sizeof(struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY) * MAX_MSIX_QUEUES_FUSION, + fusion->rdpq_virt, fusion->rdpq_phys); +} + +static void +megasas_free_reply_fusion(struct megasas_instance *instance) { + + struct fusion_context *fusion; + + fusion = instance->ctrl_context; + + if (fusion->reply_frames_desc[0]) + pci_pool_free(fusion->reply_frames_desc_pool, + fusion->reply_frames_desc[0], + fusion->reply_frames_desc_phys[0]); + + if (fusion->reply_frames_desc_pool) + pci_pool_destroy(fusion->reply_frames_desc_pool); + +} + + +/** + * megasas_alloc_cmds_fusion - Allocates the command packets + * @instance: Adapter soft state + * + * + * Each frame has a 32-bit field called context. This context is used to get + * back the megasas_cmd_fusion from the frame when a frame gets completed + * In this driver, the 32 bit values are the indices into an array cmd_list. + * This array is used only to look up the megasas_cmd_fusion given the context. + * The free commands themselves are maintained in a linked list called cmd_pool. + * + * cmds are formed in the io_request and sg_frame members of the + * megasas_cmd_fusion. The context field is used to get a request descriptor + * and is used as SMID of the cmd. + * SMID value range is from 1 to max_fw_cmds. + */ +int +megasas_alloc_cmds_fusion(struct megasas_instance *instance) +{ + int i; + struct fusion_context *fusion; + struct megasas_cmd_fusion *cmd; + u32 offset; + dma_addr_t io_req_base_phys; + u8 *io_req_base; + + + fusion = instance->ctrl_context; + + if (megasas_alloc_cmdlist_fusion(instance)) + return -ENOMEM; + + if (megasas_alloc_request_fusion(instance)) + goto fail_exit; + + if (instance->is_rdpq) { + if (megasas_alloc_rdpq_fusion(instance)) + goto fail_exit; + } else + if (megasas_alloc_reply_fusion(instance)) + goto fail_exit; + + + /* The first 256 bytes (SMID 0) is not used. Don't add to the cmd list */ + io_req_base = fusion->io_request_frames + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; + io_req_base_phys = fusion->io_request_frames_phys + MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; /* * Add all the commands to command pool (fusion->cmd_pool) */ /* SMID 0 is reserved. Set SMID/index from 1 */ - for (i = 0; i < max_cmd; i++) { + for (i = 0; i < instance->max_fw_cmds; i++) { cmd = fusion->cmd_list[i]; offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; memset(cmd, 0, sizeof(struct megasas_cmd_fusion)); @@ -518,35 +592,13 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) cmd->io_request_phys_addr = io_req_base_phys + offset; } - /* - * Create a frame pool and assign one frame to each cmd - */ - if (megasas_create_frame_pool_fusion(instance)) { - dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n"); - megasas_free_cmds_fusion(instance); - goto fail_req_desc; - } + if (megasas_create_sg_sense_fusion(instance)) + goto fail_exit; return 0; -fail_cmd_list: - pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames, - fusion->io_request_frames_phys); - pci_pool_destroy(fusion->io_request_frames_pool); -fail_io_frames: - dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, - fusion->reply_frames_desc, - fusion->reply_frames_desc_phys); - pci_pool_free(fusion->reply_frames_desc_pool, - fusion->reply_frames_desc, - fusion->reply_frames_desc_phys); - pci_pool_destroy(fusion->reply_frames_desc_pool); - -fail_reply_desc: - dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, - fusion->req_frames_desc, - fusion->req_frames_desc_phys); -fail_req_desc: +fail_exit: + megasas_free_cmds_fusion(instance); return -ENOMEM; } @@ -594,16 +646,17 @@ int megasas_ioc_init_fusion(struct megasas_instance *instance) { struct megasas_init_frame *init_frame; - struct MPI2_IOC_INIT_REQUEST *IOCInitMessage; + struct MPI2_IOC_INIT_REQUEST *IOCInitMessage = NULL; dma_addr_t ioc_init_handle; struct megasas_cmd *cmd; - u8 ret; + u8 ret, cur_rdpq_mode; struct fusion_context *fusion; union MEGASAS_REQUEST_DESCRIPTOR_UNION req_desc; int i; struct megasas_header *frame_hdr; const char *sys_info; MFI_CAPABILITIES *drv_ops; + u32 scratch_pad_2; fusion = instance->ctrl_context; @@ -615,6 +668,18 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) goto fail_get_cmd; } + scratch_pad_2 = readl + (&instance->reg_set->outbound_scratch_pad_2); + + cur_rdpq_mode = (scratch_pad_2 & MR_RDPQ_MODE_OFFSET) ? 1 : 0; + + if (instance->is_rdpq && !cur_rdpq_mode) { + dev_err(&instance->pdev->dev, "Firmware downgrade *NOT SUPPORTED*" + " from RDPQ mode to non RDPQ mode\n"); + ret = 1; + goto fail_fw_init; + } + IOCInitMessage = dma_alloc_coherent(&instance->pdev->dev, sizeof(struct MPI2_IOC_INIT_REQUEST), @@ -636,7 +701,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4); IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth); - IOCInitMessage->ReplyDescriptorPostQueueAddress = cpu_to_le64(fusion->reply_frames_desc_phys); + IOCInitMessage->ReplyDescriptorPostQueueAddress = instance->is_rdpq ? + cpu_to_le64(fusion->rdpq_phys) : + cpu_to_le64(fusion->reply_frames_desc_phys[0]); + IOCInitMessage->MsgFlags = instance->is_rdpq ? + MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE : 0; IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys); IOCInitMessage->HostMSIxVectors = instance->msix_vectors; init_frame = (struct megasas_init_frame *)cmd->frame; @@ -1087,7 +1156,10 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) */ instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; - instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008); + dev_info(&instance->pdev->dev, + "firmware support max fw cmd\t: (%d)\n", instance->max_fw_cmds); + if (!instance->is_rdpq) + instance->max_fw_cmds = min_t(u16, instance->max_fw_cmds, 1024); /* * Reduce the max supported cmds by 1. This is to ensure that the @@ -2110,10 +2182,8 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) return IRQ_HANDLED; - desc = fusion->reply_frames_desc; - desc += ((MSIxIndex * fusion->reply_alloc_sz)/ - sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) + - fusion->last_reply_idx[MSIxIndex]; + desc = fusion->reply_frames_desc[MSIxIndex] + + fusion->last_reply_idx[MSIxIndex]; reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; @@ -2208,9 +2278,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) /* Get the next reply descriptor */ if (!fusion->last_reply_idx[MSIxIndex]) - desc = fusion->reply_frames_desc + - ((MSIxIndex * fusion->reply_alloc_sz)/ - sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)); + desc = fusion->reply_frames_desc[MSIxIndex]; else desc++; @@ -2688,17 +2756,18 @@ out: void megasas_reset_reply_desc(struct megasas_instance *instance) { - int i, count; + int i, j, count; struct fusion_context *fusion; union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; fusion = instance->ctrl_context; count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; - for (i = 0 ; i < count ; i++) + for (i = 0 ; i < count ; i++) { fusion->last_reply_idx[i] = 0; - reply_desc = fusion->reply_frames_desc; - for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++) - reply_desc->Words = cpu_to_le64(ULLONG_MAX); + 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); + } } /* diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h index db0978d..80eaee2 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h @@ -928,6 +928,12 @@ struct MR_PD_CFG_SEQ_NUM_SYNC { struct MR_PD_CFG_SEQ seq[1]; } __packed; +struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY { + u64 RDPQBaseAddress; + u32 Reserved1; + u32 Reserved2; +}; + struct fusion_context { struct megasas_cmd_fusion **cmd_list; dma_addr_t req_frames_desc_phys; @@ -940,8 +946,8 @@ struct fusion_context { struct dma_pool *sg_dma_pool; struct dma_pool *sense_dma_pool; - dma_addr_t reply_frames_desc_phys; - union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc; + dma_addr_t reply_frames_desc_phys[MAX_MSIX_QUEUES_FUSION]; + union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc[MAX_MSIX_QUEUES_FUSION]; struct dma_pool *reply_frames_desc_pool; u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION]; @@ -951,6 +957,8 @@ struct fusion_context { u32 reply_alloc_sz; u32 io_frames_alloc_sz; + struct MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY *rdpq_virt; + dma_addr_t rdpq_phys; u16 max_sge_in_main_msg; u16 max_sge_in_chain;