Linux SCSI subsystem development
 help / color / mirror / Atom feed
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

  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