From: Dave Marquardt <davemarq@linux.ibm.com>
To: Tyrel Datwyler <tyreld@linux.ibm.com>
Cc: "James E.J. Bottomley" <James.Bottomley@HansenPartnership.com>,
"Martin K. Petersen" <martin.petersen@oracle.com>,
Madhavan Srinivasan <maddy@linux.ibm.com>,
Michael Ellerman <mpe@ellerman.id.au>,
Nicholas Piggin <npiggin@gmail.com>,
"Christophe Leroy (CS GROUP)" <chleroy@kernel.org>,
linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org,
linuxppc-dev@lists.ozlabs.org, Brian King <brking@linux.ibm.com>,
Greg Joyce <gjoyce@linux.ibm.com>,
Kyle Mahlkuch <kmahlkuc@linux.ibm.com>
Subject: Re: [PATCH v2 6/7] ibmvfc: register and use asynchronous sub-queue
Date: Thu, 25 Jun 2026 16:31:52 -0500 [thread overview]
Message-ID: <87fr2aparb.fsf@linux.ibm.com> (raw)
In-Reply-To: <03239655-0c9a-42af-b6a1-8141f44149f9@linux.ibm.com>
Tyrel Datwyler <tyreld@linux.ibm.com> writes:
> On 6/8/26 11:30 AM, Dave Marquardt via B4 Relay wrote:
>> From: Dave Marquardt <davemarq@linux.ibm.com>
>>
>> Refactor existing code for async events into a common routine,
>> register a channel and interrupt handler for the asynchronous
>> sub-queue, and set capability bits to request that VIOS use the
>> asynchronous sub-queue.
>
> Again, all your patches need Signed-off-by: tags to be accepted.
>
> Also, there is still a lot of different things happening in this patch
>
> You seem to be reworking the fpin_desc helpers which I'm not really seeing any
> reason that you couldn't squash those changes into patch 2. It seems like
> needless churn since, unless I'm missing something, there doesn't seem to be any
> new definitions added since patch 2 just reworking of the input parameters such
> that period goes away and is hardcoded and a new type paramerter is added.
Okay, I'll roll the ibmvfc_common_fpin_to_desc changes into patch 2.
> I would also help reduce the patch size and make it more reviewable if you split
> the the interrupt handler definition and queue registration into separate
> patches as well.
>
>> ---
>> drivers/scsi/ibmvscsi/ibmvfc.c | 376 +++++++++++++++++++++++++++--------
>> drivers/scsi/ibmvscsi/ibmvfc.h | 3 +
>> drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 2 +-
>> 3 files changed, 298 insertions(+), 83 deletions(-)
>>
>> diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
>> index ad1f5636e879..a2252cd2f44b 100644
>> --- a/drivers/scsi/ibmvscsi/ibmvfc.c
>> +++ b/drivers/scsi/ibmvscsi/ibmvfc.c
>> @@ -1514,7 +1514,8 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost)
>> login_info->max_cmds = cpu_to_be32(max_cmds);
>> login_info->capabilities =
>> cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_SEND_VF_WWPN |
>> - IBMVFC_CAN_USE_NOOP_CMD);
>> + IBMVFC_CAN_USE_NOOP_CMD | IBMVFC_YES_SCSI |
>> + IBMVFC_USE_ASYNC_SUBQ | IBMVFC_CAN_HANDLE_FPIN);
>>
>> if (vhost->mq_enabled || vhost->using_channels)
>> login_info->capabilities |= cpu_to_be64(IBMVFC_CAN_USE_CHANNELS);
>> @@ -3240,8 +3241,8 @@ static size_t ibmvfc_fpin_size_helper(u8 fpin_status)
>> * non-NULL - pointer to populated struct fc_els_fpin
>> */
>> static struct fc_els_fpin *
>> -ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 modifier,
>> - __be32 period, __be32 threshold, __be32 event_count)
>> +ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 type, __be16 modifier,
>> + __be32 threshold, __be32 event_count)
>> {
>
> This function signature changes here, and looking at the implemenation below I'm
> struggling to see why this couldn't just be all implmented immediatly in Patch #2.
>
>> struct fc_fn_peer_congn_desc *pdesc;
>> struct fc_fn_congn_desc *cdesc;
>> @@ -3253,7 +3254,7 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 modifier,
>> if (size == 0)
>> return NULL;
>>
>> - fpin = kzalloc(size, GFP_KERNEL);
>> + fpin = kzalloc(size, GFP_ATOMIC);
>
> Why are we changing this to GFP_ATOMIC? Isn't this only ever called from work
> queue context?
I've restored this for my next version of the patch series.
>> if (fpin == NULL)
>> return NULL;
>>
>> @@ -3266,12 +3267,9 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 modifier,
>> cdesc = (struct fc_fn_congn_desc *)fpin->fpin_desc;
>> cdesc->desc_tag = cpu_to_be32(ELS_DTAG_CONGESTION);
>> cdesc->desc_len = cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*cdesc));
>> - if (fpin_status == IBMVFC_AE_FPIN_CONGESTION_CLEARED)
>> - cdesc->event_type = cpu_to_be16(FPIN_CONGN_CLEAR);
>> - else
>> - cdesc->event_type = cpu_to_be16(FPIN_CONGN_DEVICE_SPEC);
>> + cdesc->event_type = type;
>> cdesc->event_modifier = modifier;
>> - cdesc->event_period = period;
>> + cdesc->event_period = cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD);
>> cdesc->severity = FPIN_CONGN_SEVERITY_WARNING;
>> break;
>> case IBMVFC_AE_FPIN_PORT_CONGESTED:
>> @@ -3281,12 +3279,9 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 modifier,
>> pdesc = (struct fc_fn_peer_congn_desc *)fpin->fpin_desc;
>> pdesc->desc_tag = cpu_to_be32(ELS_DTAG_PEER_CONGEST);
>> pdesc->desc_len = cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*pdesc));
>> - if (fpin_status == IBMVFC_AE_FPIN_PORT_CLEARED)
>> - pdesc->event_type = cpu_to_be16(FPIN_CONGN_CLEAR);
>> - else
>> - pdesc->event_type = cpu_to_be16(FPIN_CONGN_DEVICE_SPEC);
>> + pdesc->event_type = type;
>> pdesc->event_modifier = modifier;
>> - pdesc->event_period = period;
>> + pdesc->event_period = cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD);
>> pdesc->detecting_wwpn = cpu_to_be64(0);
>> pdesc->attached_wwpn = wwpn;
>> pdesc->pname_count = cpu_to_be32(1);
>> @@ -3297,7 +3292,7 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 modifier,
>> ldesc = (struct fc_fn_li_desc *)fpin->fpin_desc;
>> ldesc->desc_tag = cpu_to_be32(ELS_DTAG_LNK_INTEGRITY);
>> ldesc->desc_len = cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*ldesc));
>> - ldesc->event_type = cpu_to_be16(FPIN_LI_UNKNOWN);
>> + ldesc->event_type = type;
>> ldesc->event_modifier = modifier;
>> ldesc->event_threshold = threshold;
>> ldesc->event_count = event_count;
>> @@ -3331,9 +3326,47 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 modifier,
>> static struct fc_els_fpin *
>> ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq *crq, u64 wwpn)
>> {
>> + __be16 type;
>> +
>> + switch (crq->fpin_status) {
>> + case IBMVFC_AE_FPIN_LINK_CONGESTED:
>> + case IBMVFC_AE_FPIN_PORT_CONGESTED:
>> + type = cpu_to_be16(FPIN_CONGN_DEVICE_SPEC);
>> + break;
>> + case IBMVFC_AE_FPIN_PORT_CLEARED:
>> + case IBMVFC_AE_FPIN_CONGESTION_CLEARED:
>> + type = cpu_to_be16(FPIN_CONGN_CLEAR);
>> + break;
>> + case IBMVFC_AE_FPIN_PORT_DEGRADED:
>> + type = cpu_to_be16(FPIN_LI_UNKNOWN);
>> + break;
>> + default:
>> + return (NULL);
>> + }
>> +
>> return ibmvfc_common_fpin_to_desc(crq->fpin_status, cpu_to_be64(wwpn),
>> - cpu_to_be16(0),
>> - cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD),
>> + type, cpu_to_be16(0),
>> + cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD),
>> + cpu_to_be32(1));
>> +}
>> +
>> +/**
>> + * ibmvfc_full_fpin_to_desc(): allocate and populate a struct fc_els_fpin struct
>> + * containing a descriptor.
>> + * @ibmvfc_fpin: Pointer to async subq FPIN data
>> + *
>> + * Allocate a struct fc_els_fpin containing a descriptor and populate
>> + * based on data from *ibmvfc_fpin.
>> + *
>> + * Return:
>> + * NULL - unable to allocate structure
>> + * non-NULL - pointer to populated struct fc_els_fpin
>> + */
>> +static struct fc_els_fpin *
>> +ibmvfc_full_fpin_to_desc(struct ibmvfc_async_subq *ibmvfc_fpin)
>> +{
>> + return ibmvfc_common_fpin_to_desc(ibmvfc_fpin->fpin_status, ibmvfc_fpin->wwpn,
>> + cpu_to_be16(0), cpu_to_be16(0),
>> cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD),
>> cpu_to_be32(1));
>> }
>> @@ -3344,67 +3377,99 @@ ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq *crq, u64 wwpn)
>> */
>> static void ibmvfc_process_async_work(struct work_struct *work)
>> {
>> + struct ibmvfc_async_subq_fpin *sqfpin;
>> + struct ibmvfc_target *tgt, *next;
>> + struct ibmvfc_async_subq *subq;
>> struct ibmvfc_async_work *aw;
>> struct ibmvfc_async_crq *crq;
>> - struct ibmvfc_target *tgt;
>> struct ibmvfc_host *vhost;
>> struct fc_els_fpin *fpin;
>> + __be64 node_name;
>> + __be64 scsi_id;
>> + __be64 wwpn;
>>
>> aw = container_of(work, struct ibmvfc_async_work, async_work_s);
>> crq = aw->crq;
>> + subq = aw->subq;
>> vhost = aw->vhost;
>>
>> - if (!crq->scsi_id && !crq->wwpn && !crq->node_name)
>> + if ((!crq && !subq) || (crq && subq)) {
>> + dev_err_ratelimited(vhost->dev,
>> + "FPIN event received, unable to process\n");
>> goto end;
>> - list_for_each_entry(tgt, &vhost->targets, queue) {
>> - if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) != crq->scsi_id)
>> + }
>> +
>> + if (crq) {
>> + wwpn = crq->wwpn;
>> + node_name = crq->node_name;
>> + scsi_id = crq->scsi_id;
>> + } else {
>> + wwpn = subq->wwpn;
>> + node_name = subq->id.node_name;
>> + scsi_id = 0;
>> + }
>> +
>> + if (!scsi_id && !wwpn && !node_name)
>> + goto end;
>> +
>> + list_for_each_entry_safe(tgt, next, &vhost->targets, queue) {
>> + if (scsi_id && cpu_to_be64(tgt->scsi_id) != scsi_id)
>> continue;
>> - if (crq->wwpn && cpu_to_be64(tgt->ids.port_name) != crq->wwpn)
>> + if (wwpn && cpu_to_be64(tgt->ids.port_name) != wwpn)
>> continue;
>> - if (crq->node_name && cpu_to_be64(tgt->ids.node_name) != crq->node_name)
>> + if (node_name && cpu_to_be64(tgt->ids.node_name) != node_name)
>> continue;
>> if (!tgt->rport)
>> continue;
>> - fpin = ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn);
>> + if (crq) {
>> + fpin = ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn);
>> + } else {
>> + sqfpin = (struct ibmvfc_async_subq_fpin *)subq;
>> + fpin = ibmvfc_full_fpin_to_desc(subq);
>> + }
>> if (fpin) {
>> fc_host_fpin_rcv(tgt->vhost->host,
>> sizeof(*fpin) + be32_to_cpu(fpin->desc_len),
>> (char *)fpin, 0);
>> kfree(fpin);
>> } else
>> - dev_err_ratelimited(vhost->dev,
>> - "FPIN event %u received, unable to process\n",
>> - crq->fpin_status);
>> + dev_err_ratelimited(vhost->dev, "FPIN event received, unable to process\n");
>> }
>>
>> end:
>> - crq->valid = 0;
>> + if (crq)
>> + crq->valid = 0;
>> + if (subq)
>> + subq->valid = 0;
>>
>> kfree(aw);
>> }
>>
>> /**
>> - * ibmvfc_handle_async - Handle an async event from the adapter
>> - * @crq: crq to process
>> + * ibmvfc_handle_async_common - Handle an async event from the adapter
>> + * @event: event to process
>> + * @link_state: link state
>> * @vhost: ibmvfc host struct
>> + * @scsi_id: scsi_id (0 if not applicable)
>> + * @wwpn: wwpn
>> + * @node_name: node_name
>> + * @aw_crq: crq pointer for async work (NULL if not needed)
>> + * @aw_subq: subq pointer for async work (NULL if not needed)
>> *
>> **/
>> -VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
>> - struct ibmvfc_host *vhost)
>> +static void ibmvfc_handle_async_common(u64 event, u8 link_state,
>> + struct ibmvfc_host *vhost,
>> + u64 scsi_id, u64 wwpn, u64 node_name,
>> + struct ibmvfc_async_crq *aw_crq,
>> + struct ibmvfc_async_subq *aw_subq)
>
> This is a lot of parameters which could be extracted here in the function if it
> just knew the type of async_crq. Would it be easier to no just take a void
> *async_instance parameter, and an is_subq boolean to determine if you cast the
> void * to ibmvfc_async_crq * or ibmvfc_async_sub_crq *?
Yes, good idea. I've changed this to
VISIBLE_IF_KUNIT void ibmvfc_handle_async(void *crq,
struct ibmvfc_host *vhost,
bool is_subq)
and will extract all of these parameters from crq.
>> +/**
>> + * ibmvfc_handle_async - Handle an async event from the adapter
>> + * @crq: crq to process
>> + * @vhost: ibmvfc host struct
>> + *
>> + **/
>> +VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,
>> + struct ibmvfc_host *vhost)
>
> async and asyncq as in the function name below can be hard to notice the
> difference in name convention. Maybe async_subq would be a better ender, but as
> it might be eaiser to just call ibmvfc_handle_async_common(crq, 0) and
> ibmfvc_handle_async(sub_crq, 1), as I outlined above in each of the interrupt
> handlers.
I agree. I've refactored to a singled ibmvfc_handle_async() with a
boolean parameter indicating whether the CRQ is a subqueue CRQ or not.
>> +{
>> + const struct ibmvfc_async_desc *desc = ibmvfc_get_ae_desc(be64_to_cpu(crq->event));
>> + u64 event = be64_to_cpu(crq->event);
>> +
>> + ibmvfc_log(vhost, desc->log_level,
>> + "%s event received. scsi_id: %llx, wwpn: %llx, node_name: %llx%s\n",
>> + desc->desc, be64_to_cpu(crq->scsi_id),
>> + be64_to_cpu(crq->wwpn), be64_to_cpu(crq->node_name),
>> + ibmvfc_get_link_state(crq->link_state));
>> +
>> + ibmvfc_handle_async_common(event, crq->link_state, vhost,
>> + crq->scsi_id, crq->wwpn, crq->node_name,
>> + crq, NULL);
>> }
>> EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_async);
>>
>> +VISIBLE_IF_KUNIT void ibmvfc_handle_asyncq(struct ibmvfc_crq *crq_instance,
>> + struct ibmvfc_host *vhost)
>> +{
>> + struct ibmvfc_async_subq *crq = (struct ibmvfc_async_subq *)crq_instance;
>> + const struct ibmvfc_async_desc *desc = ibmvfc_get_ae_desc(be16_to_cpu(crq->event));
>> + u64 event = be16_to_cpu(crq->event);
>> +
>> + ibmvfc_log(vhost, desc->log_level,
>> + "%s event received. wwpn: %llx, node_name: %llx%s event 0x%x\n",
>> + desc->desc, be64_to_cpu(crq->wwpn), be64_to_cpu(crq->id.node_name),
>> + ibmvfc_get_link_state(crq->link_state), be16_to_cpu(crq->event));
>> +
>> + ibmvfc_handle_async_common(event, crq->link_state, vhost,
>> + 0, crq->wwpn, crq->id.node_name,
>> + NULL, crq);
>> +}
>> +EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_asyncq);
>> +
>> /**
>> * ibmvfc_handle_crq - Handles and frees received events in the CRQ
>> * @crq: Command/Response queue
>> @@ -4117,6 +4229,13 @@ static void ibmvfc_handle_scrq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost
>> spin_unlock(&evt->queue->l_lock);
>> }
>>
>> +/**
>> + * ibmvfc_next_scrq - Returns the next entry in message subqueue
>> + * @scrq: Pointer to message subqueue
>> + *
>> + * Returns:
>> + * Pointer to next entry in queue / NULL if empty
>> + **/
>> static struct ibmvfc_crq *ibmvfc_next_scrq(struct ibmvfc_queue *scrq)
>> {
>> struct ibmvfc_crq *crq;
>> @@ -4132,6 +4251,57 @@ static struct ibmvfc_crq *ibmvfc_next_scrq(struct ibmvfc_queue *scrq)
>> return crq;
>> }
>>
>> +static void ibmvfc_drain_async_subq(struct ibmvfc_queue *scrq)
>> +{
>> + struct ibmvfc_crq *crq;
>> + unsigned long flags;
>> + int done = 0;
>> +
>> + ENTER;
>> +
>> + spin_lock_irqsave(scrq->q_lock, flags);
>> + while (!done) {
>> + while ((crq = ibmvfc_next_scrq(scrq)) != NULL) {
>> + ibmvfc_handle_asyncq(crq, scrq->vhost);
>> + crq->valid = 0;
>
> Isn't up to the handle_async_common to clear the valid crq bit depending on the
> type of async action?
I've moved clearing the valid bit to ibmvfc_handle_async().
>> + wmb(); /* complete write */
>> + }
>> +
>> + ibmvfc_toggle_scrq_irq(scrq, 1);
>> + crq = ibmvfc_next_scrq(scrq);
>> + if (crq != NULL) {
>> + ibmvfc_toggle_scrq_irq(scrq, 0);
>> + ibmvfc_handle_asyncq(crq, scrq->vhost);
>> + crq->valid = 0;
>
> Same comment as above.
>
>> + wmb(); /* complete write */
>> + } else
>> + done = 1;
>> + }
>> + spin_unlock_irqrestore(scrq->q_lock, flags);
>> +
>> + LEAVE;
>> +}
>> +
>> +/**
>> + * ibmvfc_interrupt_asyncq - Handle an async event from the adapter
>> + * @irq: interrupt request
>> + * @scrq_instance: async subq
>> + *
>> + **/
>> +static irqreturn_t ibmvfc_interrupt_asyncq(int irq, void *scrq_instance)
>> +{
>> + struct ibmvfc_queue *scrq = (struct ibmvfc_queue *)scrq_instance;
>> +
>> + ENTER;
>> +
>> + ibmvfc_toggle_scrq_irq(scrq, 0);
>> + ibmvfc_drain_async_subq(scrq);
>> +
>> + LEAVE;
>> +
>> + return IRQ_HANDLED;
>> +}
>> +
>> static void ibmvfc_drain_sub_crq(struct ibmvfc_queue *scrq)
>> {
>> struct ibmvfc_crq *crq;
>> @@ -5500,6 +5670,8 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
>> unsigned int npiv_max_sectors;
>> int level = IBMVFC_DEFAULT_LOG_LEVEL;
>>
>> + ENTER;
>> +
>> switch (mad_status) {
>> case IBMVFC_MAD_SUCCESS:
>> ibmvfc_free_event(evt);
>> @@ -5578,6 +5750,8 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt)
>> ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
>> wake_up(&vhost->work_wait_q);
>> }
>> +
>> + LEAVE;
>
> Also, please drop the ENTER/LEAVE macros as these look like debug artifacts.
> Especially, in common code paths like the interrupt handlers.
Done.
-Dave
next prev parent reply other threads:[~2026-06-25 21:32 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-08 18:30 [PATCH v2 0/7] ibmvfc: make ibmvfc support FPIN messages Dave Marquardt via B4 Relay
2026-06-08 18:30 ` [PATCH v2 1/7] ibmvfc: add basic FPIN support Dave Marquardt via B4 Relay
2026-06-12 22:35 ` Tyrel Datwyler
2026-06-15 20:37 ` Dave Marquardt
2026-06-15 22:10 ` Tyrel Datwyler
2026-06-15 23:38 ` Tyrel Datwyler
2026-06-08 18:30 ` [PATCH v2 2/7] ibmvfc: Add NOOP command support Dave Marquardt via B4 Relay
2026-06-08 18:30 ` [PATCH v2 3/7] ibmvfc: make ibmvfc login to fabric Dave Marquardt via B4 Relay
2026-06-12 23:11 ` Tyrel Datwyler
2026-06-15 13:42 ` Dave Marquardt
2026-06-08 18:30 ` [PATCH v2 4/7] ibmvfc: define asynchronous sub-queue Dave Marquardt via B4 Relay
2026-06-15 19:27 ` Tyrel Datwyler
2026-06-15 20:15 ` Dave Marquardt
2026-06-08 18:30 ` [PATCH v2 5/7] ibmvfc: allocate " Dave Marquardt via B4 Relay
2026-06-15 19:54 ` Tyrel Datwyler
2026-06-17 19:46 ` Dave Marquardt
2026-06-08 18:30 ` [PATCH v2 6/7] ibmvfc: register and use " Dave Marquardt via B4 Relay
2026-06-15 20:58 ` Tyrel Datwyler
2026-06-25 21:31 ` Dave Marquardt [this message]
2026-06-08 18:30 ` [PATCH v2 7/7] ibmvfc: handle extended FPIN events Dave Marquardt via B4 Relay
2026-06-15 21:52 ` Tyrel Datwyler
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=87fr2aparb.fsf@linux.ibm.com \
--to=davemarq@linux.ibm.com \
--cc=James.Bottomley@HansenPartnership.com \
--cc=brking@linux.ibm.com \
--cc=chleroy@kernel.org \
--cc=gjoyce@linux.ibm.com \
--cc=kmahlkuc@linux.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=maddy@linux.ibm.com \
--cc=martin.petersen@oracle.com \
--cc=mpe@ellerman.id.au \
--cc=npiggin@gmail.com \
--cc=tyreld@linux.ibm.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