From: Sumit Saxena <sumit.saxena@avagotech.com>
To: Tomas Henzl <thenzl@redhat.com>,
jbottomley@parallels.com, hch@infradead.org,
martin.petersen@oracle.com
Cc: linux-scsi@vger.kernel.org, Kashyap Desai <kashyap.desai@avagotech.com>
Subject: RE: [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support
Date: Wed, 27 Jan 2016 23:45:23 +0530 [thread overview]
Message-ID: <9a00f103741556312f8699779889c59e@mail.gmail.com> (raw)
In-Reply-To: <5697DD2A.1080601@redhat.com>
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;
> >
next prev parent reply other threads:[~2016-01-27 18:15 UTC|newest]
Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-18 13:26 [PATCH 00/15] megaraid_sas: Updates for scsi-next Sumit Saxena
2015-12-18 13:26 ` [PATCH 01/15] megaraid_sas: Do not allow PCI access during OCR Sumit Saxena
2016-01-11 17:02 ` Tomas Henzl
2015-12-18 13:26 ` [PATCH 02/15] megaraid_sas: MFI IO timeout handling Sumit Saxena
2016-01-11 17:02 ` Tomas Henzl
2015-12-18 13:26 ` [PATCH 03/15] megaraid_sas: Syncing request flags macro names with firmware Sumit Saxena
2016-01-11 17:03 ` Tomas Henzl
2015-12-18 13:26 ` [PATCH 04/15] megaraid_sas: Task management support Sumit Saxena
2016-01-11 17:03 ` Tomas Henzl
2016-01-14 12:04 ` Sumit Saxena
2015-12-18 13:26 ` [PATCH 05/15] megaraid_sas: Update device Queue depth based on interface type Sumit Saxena
2016-01-12 14:16 ` Tomas Henzl
2016-01-14 11:48 ` Sumit Saxena
2015-12-18 13:26 ` [PATCH 06/15] megaraid_sas: Fastpath region lock bypass Sumit Saxena
2016-01-12 14:44 ` Tomas Henzl
2015-12-18 13:27 ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support Sumit Saxena
2015-12-18 14:49 ` [PATCH] megaraid_sas: fix kzalloc-simple.cocci warnings kbuild test robot
2015-12-18 14:49 ` [PATCH 07/15] megaraid_sas: Reply Descriptor Post Queue(RDPQ) support kbuild test robot
2016-01-14 17:38 ` Tomas Henzl
2016-01-27 18:15 ` Sumit Saxena [this message]
2015-12-18 13:27 ` [PATCH 08/15] megaraid_sas: Code optimization build_and_issue_cmd return-type Sumit Saxena
2016-01-14 18:05 ` Tomas Henzl
2015-12-18 13:27 ` [PATCH 09/15] megaraid_sas: Dual Queue depth support Sumit Saxena
2016-01-19 13:34 ` Tomas Henzl
2016-01-19 13:44 ` Sumit Saxena
2016-01-20 13:55 ` Tomas Henzl
2016-01-20 14:09 ` Sumit Saxena
2016-01-20 14:16 ` Tomas Henzl
2016-01-20 15:08 ` Sumit Saxena
2016-01-20 16:00 ` Tomas Henzl
2016-01-27 2:02 ` Martin K. Petersen
2016-01-27 7:09 ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 10/15] megaraid_sas: IO throttling support Sumit Saxena
2016-01-19 13:38 ` Tomas Henzl
2016-01-28 7:18 ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 11/15] megaraid_sas: Make adprecovery variable atomic Sumit Saxena
2016-01-19 13:52 ` Tomas Henzl
2016-01-28 8:30 ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 12/15] megaraid_sas: MFI adapter's OCR changes Sumit Saxena
2016-01-19 14:22 ` Tomas Henzl
2016-01-28 11:12 ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 13/15] megaraid_sas: Introduce module parameter for SCSI command-timeout Sumit Saxena
2016-01-19 14:57 ` Tomas Henzl
2016-01-28 11:17 ` Sumit Saxena
2015-12-18 13:27 ` [PATCH 14/15] megaraid_sas: SPERC OCR changes Sumit Saxena
2016-01-19 15:14 ` Tomas Henzl
2015-12-18 13:27 ` [PATCH 15/15] megaraid_sas: SPERC boot driver reorder Sumit Saxena
2015-12-18 14:05 ` Christoph Hellwig
2016-01-08 7:07 ` Sumit Saxena
2016-01-12 5:26 ` Sumit Saxena
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9a00f103741556312f8699779889c59e@mail.gmail.com \
--to=sumit.saxena@avagotech.com \
--cc=hch@infradead.org \
--cc=jbottomley@parallels.com \
--cc=kashyap.desai@avagotech.com \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.com \
--cc=thenzl@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).