From nobody Mon Sep 28 20:05:56 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA4DF3BE168; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998480; cv=none; b=FIIFJDsQCtp6RaTmXLKunAQj+kF7W7QetsRTSdXq1WvSQ61oIvnyK/CGs1QZdLc/QgvIbpjvt2f885PERbzzZ1K6X02asHzdstSp2IVUCrFiISf6a+q4GLhG3Sr/XFwaMPcXf7XQqdWEqluQ8cnF3A2G5Jy2EGdt4u5qHu8z0zw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998480; c=relaxed/simple; bh=tPrnqFNaNiRlySKjW46ftspHoEvpsW/zyEjE5ADMJ7k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=THkngoVRf7cRxqy0C4m3BXaOIF1lDjCLVtivsE78B1hnVkxCjYg8zxbvRWCyGxs4pS7E9364L+tTb5kwTQBLhKv3uJRL4CvJJNgV1YS6518rnZWD37dJq1Js7ZKIFwR4zzNt+q4rgdVQIJxq8+1wuVIuWX2iVlRaDRX7DhOzqiY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pLga/C3g; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pLga/C3g" Received: by smtp.kernel.org (Postfix) with ESMTPS id 7A7CFC2BCFA; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786998480; bh=tPrnqFNaNiRlySKjW46ftspHoEvpsW/zyEjE5ADMJ7k=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=pLga/C3gRvpQ+scsJ+26rX3TDq48lRk7taqwHsNEOvC3voJHLAlfD8r1Ye1Q3qE+u s/2PsMs5yVSd5nGu0U17fsMCJCdUXtCwZr/15xg2rppYQMrGehJ0w8NBu6Sr3DBrhL 4LEBuMDcsXQdmuG/A/6Dce8wNTSRxeolw+gorpamdH2yKRN+GghxdIFof16bUYxaqd 7cjVnZusrpBvwq3QQ1HNfSf1a5bJksOM/7KvZt88QWnnfb47mP1/xGn+VxUQsaN61E mdVzsQsQJ9Tc3IVnDwdfbRHAFX8e9AayY0s6ld3IKwJt0VpjzByAVi6MzVhWmp2xKc Z3nFIa8lJll3A== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 524A5C5DF7D; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 17 Aug 2026 15:27:54 -0500 Subject: [PATCH v6 1/8] scsi: ibmvfc: add basic FPIN support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260817-ibmvfc-fpin-support-v6-1-62a2d525e70d@linux.ibm.com> References: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> In-Reply-To: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> To: "James E.J. Bottomley" , "Martin K. Petersen" , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , "Christophe Leroy (CS GROUP)" , Tyrel Datwyler Cc: linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, Brian King , Greg Joyce , Kyle Mahlkuch , Dave Marquardt X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786998478; l=21600; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=mAmuuMHW1oOgzlDrGEyLa7J4n5WIkkDLbscFnqXA92g=; b=qPuiLHC1Z90PbtNLCDwjlBygaCR/UjIrDvNw5CDaagrIEaGc34DLOy6Vu7sn84OBgXoc2MPqt DESYuT+liIPDtOS4AHDOnTO4uZjlq4Vsi6QQ3ZHvku5ms9jxZ89GihP X-Developer-Key: i=davemarq@linux.ibm.com; a=ed25519; pk=vy0/nfobrje6EqZxuyw6a3ZstytG8WK2vf5Y3xtGrEg= X-Endpoint-Received: by B4 Relay for davemarq@linux.ibm.com/20260216 with auth_id=689 X-Original-From: Dave Marquardt Reply-To: davemarq@linux.ibm.com From: Dave Marquardt Implement support for a basic level of Fabric Performance Impact Notifications (FPIN) in the ibmvfc driver to enable monitoring of fabric congestion and link integrity events. Add async event handler for IBMVFC_AE_FPIN events that offloads FPIN processing to a dedicated workqueue. Convert VIOS FPIN messages to standard fc_els_fpin structures and pass them to fc_host_fpin_rcv() for processing by the FC transport layer. Introduce common FPIN conversion routines that will be reused for full and extended FPIN support in subsequent patches. Add KUnit test infrastructure to validate FPIN event handling and statistics updates. Changes include: - Add FPIN async event handling in ibmvfc_handle_async() - Create dedicated workqueue for FPIN processing - Implement FPIN message conversion to fc_els_fpin format - Add support for link congestion, port congestion, port cleared, port degraded, and congestion cleared events - Add KUnit test module for FPIN functionality Signed-off-by: Dave Marquardt --- drivers/scsi/Kconfig | 10 ++ drivers/scsi/ibmvscsi/Makefile | 1 + drivers/scsi/ibmvscsi/ibmvfc-core.c | 283 +++++++++++++++++++++++++++++++= +++- drivers/scsi/ibmvscsi/ibmvfc.h | 16 ++ drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 130 ++++++++++++++++ 5 files changed, 437 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 4a2af0f702e1..352abe10da58 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -759,6 +759,16 @@ config SCSI_IBMVFC To compile this driver as a module, choose M here: the module will be called ibmvfc. =20 +config SCSI_IBMVFC_KUNIT_TEST + tristate "KUnit tests for the IBM POWER Virtual FC Client" if !KUNIT_ALL_= TESTS + depends on SCSI_IBMVFC && KUNIT + default KUNIT_ALL_TESTS + help + Compile IBM POWER Virtual FC client KUnit tests. These tests + specifically test FPIN functionality. To compile this driver + as a module, choose M here: the module will be called + ibmvfc_kunit. + config SCSI_IBMVFC_TRACE bool "enable driver internal trace" depends on SCSI_IBMVFC diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile index 9408c7f4cdee..a227bc633f3a 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile @@ -3,3 +3,4 @@ ibmvfc-objs :=3D ibmvfc-core.o ibmvfc-nvme.o =20 obj-$(CONFIG_SCSI_IBMVSCSI) +=3D ibmvscsi.o obj-$(CONFIG_SCSI_IBMVFC) +=3D ibmvfc.o +obj-$(CONFIG_SCSI_IBMVFC_KUNIT_TEST) +=3D ibmvfc_kunit.o diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ib= mvfc-core.c index 45e030566c06..1ac730c0a8a6 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc-core.c +++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c @@ -31,6 +31,9 @@ #include #include #include +#include +#include +#include #include "ibmvfc.h" =20 static unsigned int init_timeout =3D IBMVFC_INIT_TIMEOUT; @@ -3194,6 +3197,7 @@ static const struct ibmvfc_async_desc ae_desc [] =3D { { "Halt", IBMVFC_AE_HALT, IBMVFC_DEFAULT_LOG_LEVEL }, { "Resume", IBMVFC_AE_RESUME, IBMVFC_DEFAULT_LOG_LEVEL }, { "Adapter Failed", IBMVFC_AE_ADAPTER_FAILED, IBMVFC_DEFAULT_LOG_LEVEL }, + { "FPIN", IBMVFC_AE_FPIN, IBMVFC_DEFAULT_LOG_LEVEL }, }; =20 static const struct ibmvfc_async_desc unknown_ae =3D { @@ -3242,16 +3246,259 @@ static const char *ibmvfc_get_link_state(enum ibmv= fc_ae_link_state state) return ""; } =20 +#define IBMVFC_FPIN_CONGN_DESC_SZ (sizeof(struct fc_els_fpin) + sizeof(str= uct fc_fn_congn_desc)) +#define IBMVFC_FPIN_LI_DESC_SZ (sizeof(struct fc_els_fpin) + \ + struct_size_t(struct fc_fn_li_desc, pname_list, 1)) +#define IBMVFC_FPIN_PEER_CONGN_DESC_SZ (sizeof(struct fc_els_fpin) + \ + struct_size_t(struct fc_fn_peer_congn_desc, pname_list, 1)) + +/** + * ibmvfc_fpin_size_helper(): compute fpin structure size based on fpin st= atus + * @fpin_status: status value + * + * Return: + * 0: invalid fpin_status + * other: valid size + */ +static size_t ibmvfc_fpin_size_helper(u8 fpin_status) +{ + size_t size =3D 0; + + switch (fpin_status) { + case IBMVFC_AE_FPIN_LINK_CONGESTED: + case IBMVFC_AE_FPIN_CONGESTION_CLEARED: + size =3D IBMVFC_FPIN_CONGN_DESC_SZ; + break; + case IBMVFC_AE_FPIN_PORT_CONGESTED: + case IBMVFC_AE_FPIN_PORT_CLEARED: + size =3D IBMVFC_FPIN_PEER_CONGN_DESC_SZ; + break; + case IBMVFC_AE_FPIN_PORT_DEGRADED: + size =3D IBMVFC_FPIN_LI_DESC_SZ; + break; + default: + break; + } + + return size; +} + +/** + * ibmvfc_common_fpin_to_desc(): allocate and populate a struct fc_els_fpi= n struct + * containing a descriptor. + * + * 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_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 type, __be1= 6 modifier, + __be32 threshold, __be32 event_count) +{ + struct fc_fn_peer_congn_desc *pdesc; + struct fc_fn_congn_desc *cdesc; + struct fc_fn_li_desc *ldesc; + struct fc_els_fpin *fpin; + size_t size; + + size =3D ibmvfc_fpin_size_helper(fpin_status); + if (!size) + return NULL; + + fpin =3D kzalloc(size, GFP_KERNEL); + if (!fpin) + return NULL; + + fpin->fpin_cmd =3D ELS_FPIN; + + switch (fpin_status) { + case IBMVFC_AE_FPIN_CONGESTION_CLEARED: + case IBMVFC_AE_FPIN_LINK_CONGESTED: + fpin->desc_len =3D cpu_to_be32(sizeof(struct fc_fn_congn_desc)); + cdesc =3D (struct fc_fn_congn_desc *)fpin->fpin_desc; + cdesc->desc_tag =3D cpu_to_be32(ELS_DTAG_CONGESTION); + cdesc->desc_len =3D cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*cdesc)); + cdesc->event_type =3D type; + cdesc->event_modifier =3D modifier; + cdesc->event_period =3D cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD); + cdesc->severity =3D FPIN_CONGN_SEVERITY_WARNING; + break; + case IBMVFC_AE_FPIN_PORT_CONGESTED: + case IBMVFC_AE_FPIN_PORT_CLEARED: + fpin->desc_len =3D + cpu_to_be32(struct_size_t(struct fc_fn_peer_congn_desc, pname_list, 1)); + pdesc =3D (struct fc_fn_peer_congn_desc *)fpin->fpin_desc; + pdesc->desc_tag =3D cpu_to_be32(ELS_DTAG_PEER_CONGEST); + pdesc->desc_len =3D cpu_to_be32(struct_size_t(struct fc_fn_peer_congn_de= sc, + pname_list, 1) - FC_TLV_DESC_HDR_SZ); + pdesc->event_type =3D type; + pdesc->event_modifier =3D modifier; + pdesc->event_period =3D cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD); + pdesc->attached_wwpn =3D wwpn; + pdesc->pname_count =3D cpu_to_be32(1); + pdesc->pname_list[0] =3D wwpn; + break; + case IBMVFC_AE_FPIN_PORT_DEGRADED: + fpin->desc_len =3D cpu_to_be32(struct_size_t(struct fc_fn_li_desc, pname= _list, 1)); + ldesc =3D (struct fc_fn_li_desc *)fpin->fpin_desc; + ldesc->desc_tag =3D cpu_to_be32(ELS_DTAG_LNK_INTEGRITY); + ldesc->desc_len =3D cpu_to_be32(struct_size_t(struct fc_fn_li_desc, + pname_list, 1) - FC_TLV_DESC_HDR_SZ); + ldesc->event_type =3D type; + ldesc->event_modifier =3D modifier; + ldesc->event_threshold =3D threshold; + ldesc->event_count =3D event_count; + ldesc->attached_wwpn =3D wwpn; + ldesc->pname_count =3D cpu_to_be32(1); + ldesc->pname_list[0] =3D wwpn; + break; + default: + /* This should be caught above. */ + kfree(fpin); + fpin =3D NULL; + break; + } + + return fpin; +} + +/** + * ibmvfc_basic_fpin_to_desc(): allocate and populate a struct fc_els_fpin= struct + * containing a descriptor. + * @ibmvfc_fpin: Pointer to async crq + * + * 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_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 =3D cpu_to_be16(FPIN_CONGN_DEVICE_SPEC); + break; + case IBMVFC_AE_FPIN_PORT_CLEARED: + case IBMVFC_AE_FPIN_CONGESTION_CLEARED: + type =3D cpu_to_be16(FPIN_CONGN_CLEAR); + break; + case IBMVFC_AE_FPIN_PORT_DEGRADED: + type =3D cpu_to_be16(FPIN_LI_UNKNOWN); + break; + default: + return NULL; + } + + return ibmvfc_common_fpin_to_desc(crq->fpin_status, cpu_to_be64(wwpn), + type, cpu_to_be16(0), + cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD), + cpu_to_be32(1)); +} + +/** + * ibmvfc_find_target - Search for a target in a target list + * @target_list: list head of targets to search + * @scsi_id: SCSI ID to match (0 to skip this check) + * @wwpn: WWPN to match (0 to skip this check) + * @node_name: Node name to match (0 to skip this check) + * + * Returns: + * Pointer to matching target, or NULL if not found + **/ +static struct ibmvfc_target *ibmvfc_find_target(struct list_head *target_l= ist, + __be64 scsi_id, __be64 wwpn, + __be64 node_name) +{ + struct ibmvfc_target *tgt; + + list_for_each_entry(tgt, target_list, queue) { + if (scsi_id && cpu_to_be64(tgt->scsi_id) !=3D scsi_id) + continue; + if (wwpn && cpu_to_be64(tgt->ids.port_name) !=3D wwpn) + continue; + if (node_name && cpu_to_be64(tgt->ids.node_name) !=3D node_name) + continue; + if (!tgt->rport) + continue; + return tgt; + } + + return NULL; +} + +/** + * ibmvfc_process_async_work - Process IBMVFC_AE_FPIN async CRQ from work = queue + * @work: pointer to work_struct + */ +static void ibmvfc_process_async_work(struct work_struct *work) +{ + struct ibmvfc_async_work *aw; + struct ibmvfc_async_crq *crq; + struct ibmvfc_target *tgt; + struct ibmvfc_host *vhost; + struct fc_els_fpin *fpin; + unsigned long flags; + + aw =3D container_of_const(work, struct ibmvfc_async_work, async_work_s); + vhost =3D aw->vhost; + crq =3D &aw->crq; + + if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + goto free; + + spin_lock_irqsave(vhost->host->host_lock, flags); + tgt =3D ibmvfc_find_target(&vhost->scsi_scrqs.targets, crq->scsi_id, + crq->wwpn, crq->node_name); + if (!tgt) { + /* Target not found in scsi_scrqs, search nvme_scrqs */ + tgt =3D ibmvfc_find_target(&vhost->nvme_scrqs.targets, + crq->scsi_id, crq->wwpn, + crq->node_name); + } + + if (tgt) { + kref_get(&tgt->kref); + spin_unlock_irqrestore(vhost->host->host_lock, flags); + } else { + spin_unlock_irqrestore(vhost->host->host_lock, flags); + dev_err_ratelimited(vhost->dev, "Invalid target for FPIN\n"); + goto free; + } + + fpin =3D ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn); + 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 received, unable to process\= n"); + + kref_put(&tgt->kref, ibmvfc_release_tgt); + free: + kfree(aw); +} + /** * ibmvfc_handle_async - Handle an async event from the adapter * @crq: crq to process * @vhost: ibmvfc host struct * **/ -static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, - struct ibmvfc_host *vhost) +VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, + struct ibmvfc_host *vhost) { const struct ibmvfc_async_desc *desc =3D ibmvfc_get_ae_desc(be64_to_cpu(c= rq->event)); + struct ibmvfc_async_work *aw; struct ibmvfc_target *tgt; =20 ibmvfc_log(vhost, desc->log_level, "%s event received. scsi_id: %llx, wwp= n: %llx," @@ -3326,11 +3573,23 @@ static void ibmvfc_handle_async(struct ibmvfc_async= _crq *crq, case IBMVFC_AE_HALT: ibmvfc_link_down(vhost, IBMVFC_HALTED); break; + case IBMVFC_AE_FPIN: + aw =3D kzalloc(sizeof(struct ibmvfc_async_work), GFP_ATOMIC); + if (aw) { + INIT_WORK(&aw->async_work_s, ibmvfc_process_async_work); + aw->vhost =3D vhost; + aw->crq =3D *crq; + queue_work(vhost->fpin_workq, &aw->async_work_s); + } else + dev_err_ratelimited(vhost->dev, + "can't offload async CRQ to work queue\n"); + break; default: dev_err(vhost->dev, "Unknown async event received: %lld\n", crq->event); break; } } +EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_async); =20 /** * ibmvfc_handle_crq - Handles and frees received events in the CRQ @@ -6803,9 +7062,15 @@ static int ibmvfc_probe(struct vio_dev *vdev, const = struct vio_device_id *id) INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread); mutex_init(&vhost->passthru_mutex); =20 - if ((rc =3D ibmvfc_alloc_mem(vhost))) + vhost->fpin_workq =3D alloc_workqueue("%s-fpin-workq-%u", 0, 0, + IBMVFC_NAME, shost->host_no); + if (vhost->fpin_workq =3D=3D NULL) goto free_scsi_host; =20 + rc =3D ibmvfc_alloc_mem(vhost); + if (rc) + goto free_workq; + vhost->work_thread =3D kthread_run(ibmvfc_work, vhost, "%s_%d", IBMVFC_NA= ME, shost->host_no); =20 @@ -6851,6 +7116,9 @@ static int ibmvfc_probe(struct vio_dev *vdev, const s= truct vio_device_id *id) kthread_stop(vhost->work_thread); free_host_mem: ibmvfc_free_mem(vhost); +free_workq: + destroy_workqueue(vhost->fpin_workq); + vhost->fpin_workq =3D NULL; free_scsi_host: scsi_host_put(shost); out: @@ -6874,6 +7142,9 @@ static void ibmvfc_remove(struct vio_dev *vdev) ENTER; ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr= ); =20 + destroy_workqueue(vhost->fpin_workq); + vhost->fpin_workq =3D NULL; + spin_lock_irqsave(vhost->host->host_lock, flags); ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); spin_unlock_irqrestore(vhost->host->host_lock, flags); @@ -7042,5 +7313,11 @@ static void __exit ibmvfc_module_exit(void) fc_release_transport(ibmvfc_transport_template); } =20 +VISIBLE_IF_KUNIT struct list_head *ibmvfc_get_headp(void) +{ + return &ibmvfc_head; +} +EXPORT_SYMBOL_IF_KUNIT(ibmvfc_get_headp); + module_init(ibmvfc_module_init); module_exit(ibmvfc_module_exit); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index ca80ceffe53a..e8ca0d30f483 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -750,8 +750,12 @@ enum ibmvfc_ae_fpin_status { IBMVFC_AE_FPIN_PORT_CONGESTED =3D 0x2, IBMVFC_AE_FPIN_PORT_CLEARED =3D 0x3, IBMVFC_AE_FPIN_PORT_DEGRADED =3D 0x4, + IBMVFC_AE_FPIN_CONGESTION_CLEARED =3D 0x5, }; =20 +#define IBMVFC_FPIN_DEFAULT_EVENT_PERIOD (5*60*MSEC_PER_SEC) /* 5 minutes = */ +#define IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD (5*60*MSEC_PER_SEC/2) /* 2.5 m= inutes */ + struct ibmvfc_async_crq { volatile u8 valid; u8 link_state; @@ -781,6 +785,12 @@ struct ibmvfc_async_sub_crq { } id; } __packed __aligned(8); =20 +struct ibmvfc_async_work { + struct ibmvfc_host *vhost; + struct ibmvfc_async_crq crq; + struct work_struct async_work_s; +}; + union ibmvfc_iu { struct ibmvfc_mad_common mad_common; struct ibmvfc_npiv_login_mad npiv_login; @@ -1022,6 +1032,7 @@ struct ibmvfc_host { wait_queue_head_t work_wait_q; struct nvme_fc_local_port *nvme_local_port; struct completion nvme_delete_done; + struct workqueue_struct *fpin_workq; }; =20 struct ibmvfc_event *__ibmvfc_get_event(struct ibmvfc_queue *queue, int re= served); @@ -1088,4 +1099,9 @@ static inline struct ibmvfc_host *ibmvfc_channels_to_= vhost(struct ibmvfc_channel #define ibmvfc_remove_trace_file(kobj, attr) do { } while (0) #endif =20 +#ifdef VISIBLE_IF_KUNIT +VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, st= ruct ibmvfc_host *vhost); +VISIBLE_IF_KUNIT struct list_head *ibmvfc_get_headp(void); +#endif + #endif diff --git a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c b/drivers/scsi/ibmvscsi/i= bmvfc_kunit.c new file mode 100644 index 000000000000..64a517a74af8 --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include +#include +#include +#include +#include +#include +#include "ibmvfc.h" + +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); + +/** + * ibmvfc_async_fpin_event_test - unit test for IBMVFC_AE_FPIN parts of + * ibmvfc_handle_async + * @test: pointer to kunit structure + * + * Tests + * - error returns from ibmvfc_handle_async + * - statistics updates + * + * Return: void + */ +static void ibmvfc_async_fpin_test(struct kunit *test) +{ + u64 post[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1]; + u64 pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1]; + enum ibmvfc_ae_fpin_status fs; + struct fc_host_attrs *fc_host; + struct ibmvfc_async_crq crq[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1]; + struct ibmvfc_target *tgt; + struct ibmvfc_host *vhost; + struct list_head *queue; + struct list_head *headp; + + headp =3D ibmvfc_get_headp(); + if (list_empty(headp)) + kunit_skip(test, "No ibmvfc devices available"); + queue =3D headp->next; + vhost =3D container_of_const(queue, struct ibmvfc_host, queue); + + KUNIT_ASSERT_GE_MSG(test, vhost->scsi_scrqs.num_targets, 1, "No targets"); + tgt =3D list_first_entry(&vhost->scsi_scrqs.targets, struct ibmvfc_target= , queue); + KUNIT_EXPECT_NOT_NULL(test, tgt->rport); + + fc_host =3D shost_to_fc_host(vhost->host); + + pre[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_d= evice_specific); + pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n); + pre[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn_= clear); + pre[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.li= _failure_unknown); + pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats.= cn_clear); + + for (fs =3D IBMVFC_AE_FPIN_LINK_CONGESTED; fs <=3D IBMVFC_AE_FPIN_CONGEST= ION_CLEARED; fs++) { + crq[fs].valid =3D 0x80; + crq[fs].link_state =3D IBMVFC_AE_LS_LINK_UP; + crq[fs].fpin_status =3D fs; + crq[fs].event =3D cpu_to_be64(IBMVFC_AE_FPIN); + crq[fs].scsi_id =3D cpu_to_be64(tgt->scsi_id); + crq[fs].wwpn =3D cpu_to_be64(tgt->wwpn); + crq[fs].node_name =3D cpu_to_be64(tgt->ids.node_name); + ibmvfc_handle_async(&crq[fs], vhost); + msleep(1U); + } + + post[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_= device_specific); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn); + post[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn= _clear); + post[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.l= i_failure_unknown); + post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats= .cn_clear); + + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_LINK_CONGESTED], + pre[IBMVFC_AE_FPIN_LINK_CONGESTED]+1); + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_PORT_CONGESTED], + pre[IBMVFC_AE_FPIN_PORT_CONGESTED]+1); + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_PORT_CLEARED], + pre[IBMVFC_AE_FPIN_PORT_CLEARED]+1); + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_PORT_DEGRADED], + pre[IBMVFC_AE_FPIN_PORT_DEGRADED]+1); + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_CONGESTION_CLEARED], + pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED]+1); + + pre[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_d= evice_specific); + pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n); + pre[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn_= clear); + pre[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.li= _failure_unknown); + pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats.= cn_clear); + + /* bad path */ + crq[0].valid =3D 0x80; + crq[0].link_state =3D IBMVFC_AE_LS_LINK_UP; + crq[0].fpin_status =3D 0; /* bad value */ + crq[0].event =3D cpu_to_be64(IBMVFC_AE_FPIN); + crq[0].scsi_id =3D cpu_to_be64(tgt->scsi_id); + crq[0].wwpn =3D cpu_to_be64(tgt->wwpn); + crq[0].node_name =3D cpu_to_be64(tgt->ids.node_name); + ibmvfc_handle_async(&crq[0], vhost); + msleep(1U); + + post[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_= device_specific); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn); + post[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn= _clear); + post[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.l= i_failure_unknown); + post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats= .cn_clear); + + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_LINK_CONGESTED], + post[IBMVFC_AE_FPIN_LINK_CONGESTED]); + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_PORT_CONGESTED], + post[IBMVFC_AE_FPIN_PORT_CONGESTED]); + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_PORT_CLEARED], + post[IBMVFC_AE_FPIN_PORT_CLEARED]); + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_PORT_DEGRADED], + post[IBMVFC_AE_FPIN_PORT_DEGRADED]); + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED], + post[IBMVFC_AE_FPIN_CONGESTION_CLEARED]); +} + +static struct kunit_case ibmvfc_fpin_test_cases[] =3D { + KUNIT_CASE_SLOW(ibmvfc_async_fpin_test), + {}, +}; + +static struct kunit_suite ibmvfc_fpin_test_suite =3D { + .name =3D "ibmvfc-fpin-test", + .test_cases =3D ibmvfc_fpin_test_cases, +}; +kunit_test_init_section_suite(ibmvfc_fpin_test_suite); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Dave Marquardt "); +MODULE_DESCRIPTION("Test module for IBM Virtual Fibre Channel Driver"); --=20 2.55.0 From nobody Mon Sep 28 20:05:56 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA32834D3B9; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998480; cv=none; b=EqU/u0KHA/pjSCWAiySypjZZoWmxV4i3N4cxoO15uNkfKSvy2bLW/d51ZCzNLKZB/X0FzEwcKewNSZ86PqlOW89TpVZNfCkQDqCtxFh8sPQT9KMM967Xm/XFQGn53shCL8m35OvHKXbIuAY1u0FK1GnvGv4BTbK1YVisZsFlocA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998480; c=relaxed/simple; bh=HwmWfEDHvET2VABRqB2+L7uM+jxA3WMPRe4ZJvrflZM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HdornqwkfIZhOCnvnI6gukLnjkAiYXtT2rAH1d9mEXw5zvRFGnA2VfysQL+nPfeT6cm4PDoB1aVEKpPfxO9blEQYDVGtYhI7uY2TOfu37ZS/OWDR0u8tEGfzOhHxtBpY/PBs/05qw9LfnFwwdA5Y+mPiPw33M3EEsvZ484cXfa8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=G8cOjpar; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="G8cOjpar" Received: by smtp.kernel.org (Postfix) with ESMTPS id 87999C2BCF4; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786998480; bh=HwmWfEDHvET2VABRqB2+L7uM+jxA3WMPRe4ZJvrflZM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=G8cOjparchmZQ27bDjr6H6Zpj15G+qi36rgFkVW2gDt6EbRwponnX8JW9i23XwEwb uVKJN71+Q3U+4XSCaavHgcOCcv+qGovVFutQGPW6aQqaWKE11UpfCNzKHMDQx3ApC8 6e+ojpwjJSwZ3qjDPvFIN2rSBvsfdxFqavIZn/XPkEwkKXILVexvXMj0LGumCWqNis 3H+eLofhDEx5kOG2HvSSLY7pz4fhScHk0fqnA5e1yCFG4Iz9/t+EiszNSA0Avh6k8L fbU6EHiPOjK3lbPffQzqXghnrctDXX3iYAFs/cE/7oTmUZck65dn0iUGysjCiMv1f1 VL7jxIXDlc74w== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69976C5DF7E; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 17 Aug 2026 15:27:55 -0500 Subject: [PATCH v6 2/8] scsi: ibmvfc: Add NOOP command support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260817-ibmvfc-fpin-support-v6-2-62a2d525e70d@linux.ibm.com> References: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> In-Reply-To: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> To: "James E.J. Bottomley" , "Martin K. Petersen" , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , "Christophe Leroy (CS GROUP)" , Tyrel Datwyler Cc: linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, Brian King , Greg Joyce , Kyle Mahlkuch , Dave Marquardt X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786998478; l=2488; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=9SEbwhnfSVQdalnJewp+335AWlDv08Etc/f1IY3q92c=; b=1Ll5s9Ouf3E7OwQQH6Lbk036WFAuUT3qfwh8ooBIh/3hD8pJsLjitPA2eihfYKiBqu/EBKYB3 zK0Bzq4ptZTAOqQsIGj61OlM0/WDXVGd8UxpLQUlWiPohFDmxaBZsFT X-Developer-Key: i=davemarq@linux.ibm.com; a=ed25519; pk=vy0/nfobrje6EqZxuyw6a3ZstytG8WK2vf5Y3xtGrEg= X-Endpoint-Received: by B4 Relay for davemarq@linux.ibm.com/20260216 with auth_id=689 X-Original-From: Dave Marquardt Reply-To: davemarq@linux.ibm.com From: Dave Marquardt Add support for VFC_NOOP messages from VIOS to enable keep-alive functionality between the client and server. Define the VFC_NOOP CRQ format and add handling in both the main CRQ handler (ibmvfc_handle_crq) and sub-CRQ handler (ibmvfc_handle_scrq). Log unexpected NOOP messages if received before VIOS advertises support during NPIV login. Set the IBMVFC_CAN_USE_NOOP_CMD capability bit during NPIV login to inform VIOS that the client can handle NOOP commands. Signed-off-by: Dave Marquardt --- drivers/scsi/ibmvscsi/ibmvfc-core.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ib= mvfc-core.c index 1ac730c0a8a6..3aac4fd2c5c3 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc-core.c +++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c @@ -1562,7 +1562,9 @@ static void ibmvfc_set_login_info(struct ibmvfc_host = *vhost) login_info->flags |=3D cpu_to_be16(IBMVFC_CLIENT_MIGRATED); =20 login_info->max_cmds =3D cpu_to_be32(max_cmds); - login_info->capabilities =3D cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_= SEND_VF_WWPN); + login_info->capabilities =3D + cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_SEND_VF_WWPN | + IBMVFC_CAN_USE_NOOP_CMD); =20 if (vhost->mq_enabled || vhost->using_channels) { login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_USE_CHANNELS); @@ -3657,6 +3659,14 @@ static void ibmvfc_handle_crq(struct ibmvfc_crq *crq= , struct ibmvfc_host *vhost, if (crq->format =3D=3D IBMVFC_ASYNC_EVENT) return; =20 + if (crq->format =3D=3D IBMVFC_NOOP) { + if (vhost->state =3D=3D IBMVFC_ACTIVE && + !ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_NOOP_CMD)) + dev_err_ratelimited(vhost->dev, + "Received unexpected NOOP command from partner\n"); + return; + } + /* The only kind of payload CRQs we should get are responses to * things we send. Make sure this response is to something we * actually sent @@ -4185,9 +4195,15 @@ static void ibmvfc_handle_scrq(struct ibmvfc_crq *cr= q, struct ibmvfc_host *vhost case IBMVFC_CRQ_CMD_RSP: break; case IBMVFC_CRQ_XPORT_EVENT: + case IBMVFC_NOOP: return; default: - dev_err(vhost->dev, "Got and invalid message type 0x%02x\n", crq->valid); + dev_err(vhost->dev, "Got an invalid message type 0x%02x\n", crq->valid); + return; + } + + if (unlikely(!evt)) { + dev_err(vhost->dev, "Received null event\n"); return; } =20 --=20 2.55.0 From nobody Mon Sep 28 20:05:56 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA3C03BB69D; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998480; cv=none; b=IVLnmiifPRLgFAEJ72NKXHO0sHQDMARpyHv+eYeMv5R77d+IRhSzDbs5so82iB/TNUMtt1+tIRb8layMm5kHja7lUPmr3HB00/P8odEIlmkcJTfwe/YoOQ62Bn4TKCGk4d7FFd8ml/S2M1rdIILiQFjJgnvQMDgNe7nQDe5ljdc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998480; c=relaxed/simple; bh=ibH6S6bENnAuY6Aa+juHgFRTm4gvytfx9OuJzg8EsIY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=aPnlOFc0xzlfAOW/i0HofWnF3aubms90yIBvWe7WrBYPpPr/nnX32MrQOChedf36rv/FJeo9lQFViRVk7xlHuLrh+Jt184B/nqDOEd8Q2s9F/RRgPtDR4N2mbH/+Xz1gL1Y5bMRWS4udmjIOUxcJ+3vFspXKZJ34M2t1TSdNa+c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=gF10GSGJ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="gF10GSGJ" Received: by smtp.kernel.org (Postfix) with ESMTPS id 9709BC2BCFB; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786998480; bh=ibH6S6bENnAuY6Aa+juHgFRTm4gvytfx9OuJzg8EsIY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=gF10GSGJCzm6/VSnsXkagfLOTPmDgqQ/P/vDV4Et94s58qfdkxWElNBnO4ikpmCE5 zyMbJFxXVDFvrJlAj8TpgVmodRZzfmQaEg1qcAwkvhwifOiZ5l3EFBKnpiu9WHOlu7 IlUqRWxh+TFFtH/dYEeKKWwLNj55meaADEYUEzW3l5PZBd5wEBlHrT7MP+ViJ15xfY SnPdBxuBmfAEKPGxldeCDhhEJ9AyiywQnkd+rtI4clUippC/b9qokb1dvB+bX5chkF aLA2tbinbLHbHCF59a9mWbDAbOT268VU+JsulgQmdzR74lDC3qWcVof4ieK6b2K/vs ZiGgru06KBxPg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7E21EC5DF7A; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 17 Aug 2026 15:27:56 -0500 Subject: [PATCH v6 3/8] scsi: ibmvfc: define asynchronous sub-queue Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260817-ibmvfc-fpin-support-v6-3-62a2d525e70d@linux.ibm.com> References: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> In-Reply-To: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> To: "James E.J. Bottomley" , "Martin K. Petersen" , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , "Christophe Leroy (CS GROUP)" , Tyrel Datwyler Cc: linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, Brian King , Greg Joyce , Kyle Mahlkuch , Dave Marquardt X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786998478; l=1724; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=/KuclEPljx50OTgTOexb3g3OjrWOPH3RuTwtYAu4ZCA=; b=+1629IP57o+J51b+3ITeltUAP+OLqWdGeAZJHhZ90rI7MHuCuzRXht3bgo2YPc7JdegRHvPQg OJb/Ew+AxR3B0ZuppdltVOt7zVVrsY1iGhr+1qq82o7EImQS8yqL1zI X-Developer-Key: i=davemarq@linux.ibm.com; a=ed25519; pk=vy0/nfobrje6EqZxuyw6a3ZstytG8WK2vf5Y3xtGrEg= X-Endpoint-Received: by B4 Relay for davemarq@linux.ibm.com/20260216 with auth_id=689 X-Original-From: Dave Marquardt Reply-To: davemarq@linux.ibm.com From: Dave Marquardt Define data structures for asynchronous sub-queue support required for full and extended FPIN functionality. Add ibmvfc_async_subq structure to represent async events received via the sub-queue, including FPIN status, link state, event type, and WWPN information. Update ibmvfc_channel_setup structure to include async_subq_handle field and reduce IBMVFC_MAX_CHANNELS from 502 to 501 to accommodate the async sub-queue. Add async_scrq pointer to ibmvfc_channels structure. Add capability flags IBMVFC_USE_ASYNC_SUBQ and IBMVFC_SUPPORT_ASYNC_SUBQ for negotiating async sub-queue support with VIOS during login. Signed-off-by: Dave Marquardt --- drivers/scsi/ibmvscsi/ibmvfc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index e8ca0d30f483..d8880d02685b 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -773,6 +773,7 @@ struct ibmvfc_async_sub_crq { volatile u8 valid; u8 flags; #define IBMVFC_ASYNC_ID_IS_ASSOC_ID 0x01 +#define IBMVFC_ASYNC_IS_FPIN_EXT 0x02 u8 link_state; u8 fpin_status; __be16 event; @@ -790,7 +791,6 @@ struct ibmvfc_async_work { struct ibmvfc_async_crq crq; struct work_struct async_work_s; }; - union ibmvfc_iu { struct ibmvfc_mad_common mad_common; struct ibmvfc_npiv_login_mad npiv_login; @@ -990,6 +990,7 @@ struct ibmvfc_host { mempool_t *tgt_pool; struct ibmvfc_queue crq; struct ibmvfc_queue async_crq; + struct ibmvfc_queue async_sub_crq; struct ibmvfc_channels scsi_scrqs; struct ibmvfc_channels nvme_scrqs; struct ibmvfc_npiv_login login_info; --=20 2.55.0 From nobody Mon Sep 28 20:05:56 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA45B3BD64B; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998480; cv=none; b=STHvcq553+vngfLF/GRccD5ZNbdpqzuXnGLJ5uVWjUtA9WFRqtTxOahknimTJsHvLZ4NBErcrGeDXW7aGXGNdeSkZLV8RDp8wEEqdiVYHTlqrvAWZniTTUlVnNTWERrNNu6UelTK/cRZ37KNhn+T9wRbU7AzcAtKCvDkKVOcovw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998480; c=relaxed/simple; bh=NFvkWy/nmatWKUvYU5eOqWZyh2ppPT2bJ/73cNDxkCQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=VoR+KllmJykRgmEGP41/PvXA1KqNbX9KwF2aAqbKjcs2f9T8/0NVt2shs1nrFNsCsfi/evs+CyI/KPA+aab4sPejcm+ZaQyAOVw2ZCaYdqaIJPDfYnZ0oJZavUFkTHTGo08lJVOgpK6vyn9i1EpKL8oWw+RSEPhY7Un7l9mNDAw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=g9LhdrXI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="g9LhdrXI" Received: by smtp.kernel.org (Postfix) with ESMTPS id A6C49C2BCFF; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786998480; bh=NFvkWy/nmatWKUvYU5eOqWZyh2ppPT2bJ/73cNDxkCQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=g9LhdrXIAv5Qkn2fr8JORBgAs3inzZnKBp6DiDZzgbTYKZlE6SbYtqJz4OwHgLXGD V9daCOVHDtJYM+dkCEMwnuU5j4NFCdA8qp3AIu2jNSxMJ+ZRo6LFQu7mECF7muxl5I FD59r58jNyEbX8ZQ/3uiLkqGAnv8SyXH4wl/Ky/QLXLgFq1VZD32br42kla6ssSqV2 E7u0b+bDiAWykx+QcRGOQ3UfW3qquyn/lxSgjsZk8s0IuPs5FzLDGuCJfcVbqumRiv tdG74eFoZAmtvBL/gyrAGzltHLoNTx3cfJnbe+5kFhg367k04XdPt/1yfucRoPWL/1 FmlAotAG7msJg== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 93630C5DF80; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 17 Aug 2026 15:27:57 -0500 Subject: [PATCH v6 4/8] scsi: ibmvfc: extend async event handlers to handle async sub queue events Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260817-ibmvfc-fpin-support-v6-4-62a2d525e70d@linux.ibm.com> References: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> In-Reply-To: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> To: "James E.J. Bottomley" , "Martin K. Petersen" , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , "Christophe Leroy (CS GROUP)" , Tyrel Datwyler Cc: linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, Brian King , Greg Joyce , Kyle Mahlkuch , Dave Marquardt X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786998478; l=17142; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=ZwExv6GnPXFZ+qLUEclcBVMFGNhhYQVRTl7Woj2vmWE=; b=QKbR1Hf03ZhXYJxe97+v1UN6ZBx7E00cnDXo51D/I0qvb2lo+KxQykfGYz2qxme++XHUXZsPr CtPbGbmca6wAUwlTqlANdCDLJs6VLsO5tJekpPvBW46QNf6sMsky64k X-Developer-Key: i=davemarq@linux.ibm.com; a=ed25519; pk=vy0/nfobrje6EqZxuyw6a3ZstytG8WK2vf5Y3xtGrEg= X-Endpoint-Received: by B4 Relay for davemarq@linux.ibm.com/20260216 with auth_id=689 X-Original-From: Dave Marquardt Reply-To: davemarq@linux.ibm.com From: Dave Marquardt Refactor async event handling to support both traditional async CRQs and new asynchronous sub-queue CRQs. Modify ibmvfc_handle_async() to accept events from either source and update ibmvfc_process_async_work() to handle both ibmvfc_async_crq and ibmvfc_async_subq structures. Add is_subq flag to ibmvfc_async_work to distinguish between event sources. Add ibmvfc_full_fpin_to_desc() to convert full FPIN messages from async sub-queue format to fc_els_fpin structures. Update FPIN processing logic to extract WWPN, node_name, and scsi_id from the appropriate structure based on event source. Update KUnit tests to reflect the new async event handling interface. Signed-off-by: Dave Marquardt --- drivers/scsi/ibmvscsi/ibmvfc-core.c | 158 ++++++++++++++++++++++++++++---= ---- drivers/scsi/ibmvscsi/ibmvfc.h | 9 +- drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 112 ++++++++++++++++++++++++- 3 files changed, 241 insertions(+), 38 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ib= mvfc-core.c index 3aac4fd2c5c3..37ee8f00322a 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc-core.c +++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c @@ -3406,6 +3406,45 @@ ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq *c= rq, u64 wwpn) cpu_to_be32(1)); } =20 +/** + * 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_sub_crq *ibmvfc_fpin) +{ + __be16 type; + + switch (ibmvfc_fpin->fpin_status) { + case IBMVFC_AE_FPIN_LINK_CONGESTED: + case IBMVFC_AE_FPIN_PORT_CONGESTED: + type =3D cpu_to_be16(FPIN_CONGN_DEVICE_SPEC); + break; + case IBMVFC_AE_FPIN_PORT_CLEARED: + case IBMVFC_AE_FPIN_CONGESTION_CLEARED: + type =3D cpu_to_be16(FPIN_CONGN_CLEAR); + break; + case IBMVFC_AE_FPIN_PORT_DEGRADED: + type =3D cpu_to_be16(FPIN_LI_UNKNOWN); + break; + default: + return NULL; + } + + return ibmvfc_common_fpin_to_desc(ibmvfc_fpin->fpin_status, ibmvfc_fpin->= wwpn, + type, cpu_to_be16(0), + cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD), + cpu_to_be32(1)); +} + /** * ibmvfc_find_target - Search for a target in a target list * @target_list: list head of targets to search @@ -3443,28 +3482,41 @@ static struct ibmvfc_target *ibmvfc_find_target(str= uct list_head *target_list, */ static void ibmvfc_process_async_work(struct work_struct *work) { + struct ibmvfc_async_sub_crq *subq =3D NULL; struct ibmvfc_async_work *aw; - struct ibmvfc_async_crq *crq; + struct ibmvfc_async_crq *crq =3D NULL; struct ibmvfc_target *tgt; struct ibmvfc_host *vhost; - struct fc_els_fpin *fpin; + struct fc_els_fpin *fpin =3D NULL; unsigned long flags; + __be64 node_name; + __be64 scsi_id; + bool is_subq; + __be64 wwpn; =20 aw =3D container_of_const(work, struct ibmvfc_async_work, async_work_s); vhost =3D aw->vhost; - crq =3D &aw->crq; + is_subq =3D aw->is_subq; + if (is_subq) { + subq =3D &aw->crq.subq; + scsi_id =3D 0; + wwpn =3D subq->wwpn; + node_name =3D subq->id.node_name; + } else { + crq =3D &aw->crq.async_crq; + scsi_id =3D crq->scsi_id; + wwpn =3D crq->wwpn; + node_name =3D crq->node_name; + } =20 - if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + if (!scsi_id && !wwpn && !node_name) goto free; =20 spin_lock_irqsave(vhost->host->host_lock, flags); - tgt =3D ibmvfc_find_target(&vhost->scsi_scrqs.targets, crq->scsi_id, - crq->wwpn, crq->node_name); + tgt =3D ibmvfc_find_target(&vhost->scsi_scrqs.targets, scsi_id, wwpn, nod= e_name); if (!tgt) { /* Target not found in scsi_scrqs, search nvme_scrqs */ - tgt =3D ibmvfc_find_target(&vhost->nvme_scrqs.targets, - crq->scsi_id, crq->wwpn, - crq->node_name); + tgt =3D ibmvfc_find_target(&vhost->nvme_scrqs.targets, scsi_id, wwpn, no= de_name); } =20 if (tgt) { @@ -3476,7 +3528,11 @@ static void ibmvfc_process_async_work(struct work_st= ruct *work) goto free; } =20 - fpin =3D ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn); + if (crq) + fpin =3D ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn); + else + fpin =3D ibmvfc_full_fpin_to_desc(subq); + if (fpin) { fc_host_fpin_rcv(tgt->vhost->host, sizeof(*fpin) + be32_to_cpu(fpin->desc_len), @@ -3492,25 +3548,52 @@ static void ibmvfc_process_async_work(struct work_s= truct *work) =20 /** * ibmvfc_handle_async - Handle an async event from the adapter - * @crq: crq to process + * @crq: ibmvfc_async_crq or ibmvfc_async_sub_crq * @vhost: ibmvfc host struct + * @is_sub_crq: indicates whether the crq points to a struct ibmvfc_async_= sub_crq * **/ -VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, - struct ibmvfc_host *vhost) +VISIBLE_IF_KUNIT void ibmvfc_handle_async(void *crq, + struct ibmvfc_host *vhost, + bool is_sub_crq) { - const struct ibmvfc_async_desc *desc =3D ibmvfc_get_ae_desc(be64_to_cpu(c= rq->event)); + struct ibmvfc_async_crq *async_crq =3D NULL; + struct ibmvfc_async_sub_crq *subq =3D NULL; + const struct ibmvfc_async_desc *desc; struct ibmvfc_async_work *aw; struct ibmvfc_target *tgt; - - ibmvfc_log(vhost, desc->log_level, "%s event received. scsi_id: %llx, wwp= n: %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)); - - switch (be64_to_cpu(crq->event)) { + __be64 node_name; + __be64 scsi_id; + u8 link_state; + __be64 wwpn; + u64 event; + + if (is_sub_crq) { + subq =3D crq; + event =3D be16_to_cpu(subq->event); + link_state =3D subq->link_state; + scsi_id =3D 0; + wwpn =3D subq->wwpn; + node_name =3D subq->id.node_name; + } else { + async_crq =3D crq; + event =3D be64_to_cpu(async_crq->event); + link_state =3D async_crq->link_state; + scsi_id =3D async_crq->scsi_id; + wwpn =3D async_crq->wwpn; + node_name =3D async_crq->node_name; + } + + desc =3D ibmvfc_get_ae_desc(event); + ibmvfc_log(vhost, desc->log_level, + "%s event received. scsi_id: %llx, wwpn: %llx, node_name: %llx, event= %llx%s\n", + desc->desc, be64_to_cpu(scsi_id), + be64_to_cpu(wwpn), be64_to_cpu(node_name), event, + ibmvfc_get_link_state(link_state)); + + switch (event) { case IBMVFC_AE_RESUME: - switch (crq->link_state) { + switch (link_state) { case IBMVFC_AE_LS_LINK_DOWN: ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); break; @@ -3549,17 +3632,17 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ib= mvfc_async_crq *crq, case IBMVFC_AE_ELS_PRLO: case IBMVFC_AE_ELS_PLOGI: list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) { - if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + if (!scsi_id && !wwpn && !node_name) break; - if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) !=3D crq->scsi_id) + if (scsi_id && cpu_to_be64(tgt->scsi_id) !=3D scsi_id) continue; - if (crq->wwpn && cpu_to_be64(tgt->ids.port_name) !=3D crq->wwpn) + if (wwpn && cpu_to_be64(tgt->ids.port_name) !=3D wwpn) continue; - if (crq->node_name && cpu_to_be64(tgt->ids.node_name) !=3D crq->node_na= me) + if (node_name && cpu_to_be64(tgt->ids.node_name) !=3D node_name) continue; - if (tgt->need_login && be64_to_cpu(crq->event) =3D=3D IBMVFC_AE_ELS_LOG= O) + if (tgt->need_login && event =3D=3D IBMVFC_AE_ELS_LOGO) tgt->logo_rcvd =3D 1; - if (!tgt->need_login || be64_to_cpu(crq->event) =3D=3D IBMVFC_AE_ELS_PL= OGI) { + if (!tgt->need_login || event =3D=3D IBMVFC_AE_ELS_PLOGI) { ibmvfc_del_tgt(tgt); ibmvfc_reinit_host(vhost); } @@ -3580,16 +3663,27 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ib= mvfc_async_crq *crq, if (aw) { INIT_WORK(&aw->async_work_s, ibmvfc_process_async_work); aw->vhost =3D vhost; - aw->crq =3D *crq; + aw->is_subq =3D is_sub_crq; + if (is_sub_crq) + aw->crq.subq =3D *subq; + else + aw->crq.async_crq =3D *async_crq; queue_work(vhost->fpin_workq, &aw->async_work_s); } else dev_err_ratelimited(vhost->dev, "can't offload async CRQ to work queue\n"); break; default: - dev_err(vhost->dev, "Unknown async event received: %lld\n", crq->event); + dev_err(vhost->dev, "Unknown async event received: %llu\n", event); break; } + + rmb(); + if (is_sub_crq) + subq->valid =3D 0; + else + async_crq->valid =3D 0; + wmb(); } EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_async); =20 @@ -4128,7 +4222,7 @@ static void ibmvfc_tasklet(void *data) while (!done) { /* Pull all the valid messages off the async CRQ */ while ((async =3D ibmvfc_next_async_crq(vhost)) !=3D NULL) { - ibmvfc_handle_async(async, vhost); + ibmvfc_handle_async(async, vhost, false); async->valid =3D 0; wmb(); } @@ -4143,7 +4237,7 @@ static void ibmvfc_tasklet(void *data) vio_enable_interrupts(vdev); if ((async =3D ibmvfc_next_async_crq(vhost)) !=3D NULL) { vio_disable_interrupts(vdev); - ibmvfc_handle_async(async, vhost); + ibmvfc_handle_async(async, vhost, false); async->valid =3D 0; wmb(); } else if ((crq =3D ibmvfc_next_crq(vhost)) !=3D NULL) { diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index d8880d02685b..26a2be9354e9 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -788,9 +788,14 @@ struct ibmvfc_async_sub_crq { =20 struct ibmvfc_async_work { struct ibmvfc_host *vhost; - struct ibmvfc_async_crq crq; + bool is_subq; + union { + struct ibmvfc_async_crq async_crq; + struct ibmvfc_async_sub_crq subq; + } crq; struct work_struct async_work_s; }; + union ibmvfc_iu { struct ibmvfc_mad_common mad_common; struct ibmvfc_npiv_login_mad npiv_login; @@ -1101,7 +1106,7 @@ static inline struct ibmvfc_host *ibmvfc_channels_to_= vhost(struct ibmvfc_channel #endif =20 #ifdef VISIBLE_IF_KUNIT -VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, st= ruct ibmvfc_host *vhost); +VISIBLE_IF_KUNIT void ibmvfc_handle_async(void *crq, struct ibmvfc_host *v= host, bool is_subq); VISIBLE_IF_KUNIT struct list_head *ibmvfc_get_headp(void); #endif =20 diff --git a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c b/drivers/scsi/ibmvscsi/i= bmvfc_kunit.c index 64a517a74af8..0b29c1e6478b 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c +++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c @@ -45,7 +45,7 @@ static void ibmvfc_async_fpin_test(struct kunit *test) fc_host =3D shost_to_fc_host(vhost->host); =20 pre[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_d= evice_specific); - pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n); + pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n_device_specific); pre[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn_= clear); pre[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.li= _failure_unknown); pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats.= cn_clear); @@ -58,7 +58,7 @@ static void ibmvfc_async_fpin_test(struct kunit *test) crq[fs].scsi_id =3D cpu_to_be64(tgt->scsi_id); crq[fs].wwpn =3D cpu_to_be64(tgt->wwpn); crq[fs].node_name =3D cpu_to_be64(tgt->ids.node_name); - ibmvfc_handle_async(&crq[fs], vhost); + ibmvfc_handle_async(&crq[fs], vhost, false); msleep(1U); } =20 @@ -93,7 +93,110 @@ static void ibmvfc_async_fpin_test(struct kunit *test) crq[0].scsi_id =3D cpu_to_be64(tgt->scsi_id); crq[0].wwpn =3D cpu_to_be64(tgt->wwpn); crq[0].node_name =3D cpu_to_be64(tgt->ids.node_name); - ibmvfc_handle_async(&crq[0], vhost); + ibmvfc_handle_async(&crq[0], vhost, false); + msleep(1U); + + post[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_= device_specific); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn); + post[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn= _clear); + post[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.l= i_failure_unknown); + post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats= .cn_clear); + + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_LINK_CONGESTED], + post[IBMVFC_AE_FPIN_LINK_CONGESTED]); + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_PORT_CONGESTED], + post[IBMVFC_AE_FPIN_PORT_CONGESTED]); + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_PORT_CLEARED], + post[IBMVFC_AE_FPIN_PORT_CLEARED]); + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_PORT_DEGRADED], + post[IBMVFC_AE_FPIN_PORT_DEGRADED]); + KUNIT_EXPECT_EQ(test, pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED], + post[IBMVFC_AE_FPIN_CONGESTION_CLEARED]); +} + +/** + * ibmvfc_async_fpin_event_test - unit test for IBMVFC_AE_FPIN parts of + * ibmvfc_handle_async + * @test: pointer to kunit structure + * + * Tests + * - error returns from ibmvfc_handle_async + * - statistics updates + * + * Return: void + */ +static void ibmvfc_full_fpin_test(struct kunit *test) +{ + u64 post[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1]; + u64 pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1]; + enum ibmvfc_ae_fpin_status fs; + struct fc_host_attrs *fc_host; + struct ibmvfc_async_sub_crq crq[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1] = =3D {}; + struct ibmvfc_target *tgt; + struct ibmvfc_host *vhost; + struct list_head *queue; + struct list_head *headp; + + headp =3D ibmvfc_get_headp(); + if (list_empty(headp)) + kunit_skip(test, "No ibmvfc devices available"); + queue =3D headp->next; + vhost =3D container_of_const(queue, struct ibmvfc_host, queue); + + KUNIT_ASSERT_GE_MSG(test, vhost->scsi_scrqs.num_targets, 1, "No targets"); + tgt =3D list_first_entry(&vhost->scsi_scrqs.targets, struct ibmvfc_target= , queue); + KUNIT_EXPECT_NOT_NULL(test, tgt->rport); + + fc_host =3D shost_to_fc_host(vhost->host); + + pre[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_d= evice_specific); + pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n_device_specific); + pre[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn_= clear); + pre[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.li= _failure_unknown); + pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats.= cn_clear); + + for (fs =3D IBMVFC_AE_FPIN_LINK_CONGESTED; fs <=3D IBMVFC_AE_FPIN_CONGEST= ION_CLEARED; fs++) { + crq[fs].valid =3D 0x80; + crq[fs].link_state =3D IBMVFC_AE_LS_LINK_UP; + crq[fs].fpin_status =3D fs; + crq[fs].event =3D cpu_to_be16(IBMVFC_AE_FPIN); + crq[fs].wwpn =3D cpu_to_be64(tgt->wwpn); + crq[fs].id.node_name =3D cpu_to_be64(tgt->ids.node_name); + ibmvfc_handle_async(&crq[fs], vhost, true); + msleep(1U); + } + + post[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_= device_specific); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn); + post[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn= _clear); + post[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.l= i_failure_unknown); + post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats= .cn_clear); + + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_LINK_CONGESTED], + pre[IBMVFC_AE_FPIN_LINK_CONGESTED]+1); + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_PORT_CONGESTED], + pre[IBMVFC_AE_FPIN_PORT_CONGESTED]+1); + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_PORT_CLEARED], + pre[IBMVFC_AE_FPIN_PORT_CLEARED]+1); + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_PORT_DEGRADED], + pre[IBMVFC_AE_FPIN_PORT_DEGRADED]+1); + KUNIT_EXPECT_GE(test, post[IBMVFC_AE_FPIN_CONGESTION_CLEARED], + pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED]+1); + + pre[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_d= evice_specific); + pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n); + pre[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn_= clear); + pre[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.li= _failure_unknown); + pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats.= cn_clear); + + /* bad path */ + crq[0].valid =3D 0x80; + crq[0].link_state =3D IBMVFC_AE_LS_LINK_UP; + crq[0].fpin_status =3D 0; /* bad value */ + crq[0].event =3D cpu_to_be16(IBMVFC_AE_FPIN); + crq[0].wwpn =3D cpu_to_be64(tgt->wwpn); + crq[0].id.node_name =3D cpu_to_be64(tgt->ids.node_name); + ibmvfc_handle_async(&crq[0], vhost, true); msleep(1U); =20 post[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_= device_specific); @@ -115,7 +218,8 @@ static void ibmvfc_async_fpin_test(struct kunit *test) } =20 static struct kunit_case ibmvfc_fpin_test_cases[] =3D { - KUNIT_CASE_SLOW(ibmvfc_async_fpin_test), + KUNIT_CASE(ibmvfc_async_fpin_test), + KUNIT_CASE(ibmvfc_full_fpin_test), {}, }; =20 --=20 2.55.0 From nobody Mon Sep 28 20:05:56 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 327713BED38; Mon, 17 Aug 2026 20:28:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998481; cv=none; b=NVVEqB0rCB82vu5MLtWVETNbcRXASKhlourQo4LsYsyYi3NSMlxpnihRiReyYCZXaeRPH3SVdi69ypn0/U6Fatmtgh+vc1er+VTYkVVkoLp9jleb5E+pOt/Z7NEhh+loGUMlvzt6t5kAgXC4Kn+ASMI7Elq9NHYyWboJLZ+HW84= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998481; c=relaxed/simple; bh=npfH/SvYzT/0JdIG65b9lFjBjFK6IAPbJe3MeAJoVkI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rBrhpepaHeWLMfWifFZvYIUW0/ieO6sr30nD7OPHCll+BlHVv4NAe3jGJU2ZJ6MqsKG2aavrmLI/nUOmDpcz4CWhml+0d3sUrIFv5YWaYAyQK1odNuDsdzlGjhU75jPAH0cWCWPD9QL55+YL9aipCP3YIMzI38dZbXS57J/DFY8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OvXUKDdc; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OvXUKDdc" Received: by smtp.kernel.org (Postfix) with ESMTPS id B9EBDC2BD04; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786998480; bh=npfH/SvYzT/0JdIG65b9lFjBjFK6IAPbJe3MeAJoVkI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=OvXUKDdc4IZdoFW+onc2JbE4lT9pHmqLKQhjBidbqcHMbfskxJYBXJWoKw1Lg+cgE 1zv9e0EjvIqXHaSLyAKL6CHryRfhHfmp7xPbrCtdkRBffgSroSp9Rjo+f/1I8Iv+EX 05y2I1/cCRTPuVNupUjhYkUHVWesZf+7HJnk21UEKX6h833/JQNNZhCbNZTxCYch+s nqFIyc2PQ1gjZLwcn4K2TDPXEx6bvTuoWjGf+89Qo+ewtkt6UPf7Hw/GtMnnnd1ev4 2QIALx9svjgcTXihzBEe+36Iy45t1UpawsodiOVodro5IzQC9UBMBYk499UWHDd2ph j1bB7/w1+4odw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id A7AA9C5DF7E; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 17 Aug 2026 15:27:58 -0500 Subject: [PATCH v6 5/8] scsi: ibmvfc: add interrupt routine for asynchronous sub CRQ Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260817-ibmvfc-fpin-support-v6-5-62a2d525e70d@linux.ibm.com> References: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> In-Reply-To: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> To: "James E.J. Bottomley" , "Martin K. Petersen" , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , "Christophe Leroy (CS GROUP)" , Tyrel Datwyler Cc: linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, Brian King , Greg Joyce , Kyle Mahlkuch , Dave Marquardt X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786998478; l=2520; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=7/pOhL66oIfhC+c2Ky/GKig1QdGkJ5gXNjXvwPpOstQ=; b=UyyqRGb9DG8+vFzmNzkA2zxmpe1CTUHrMMk1sRPRTql3em5WjOKEfZNye/BW9tc1of7kawlnC SyKGiDhEPrzDFJk5OCJWQatUnB3llD2a4nZH1Pf2QIN0Ey54K7/oI3z X-Developer-Key: i=davemarq@linux.ibm.com; a=ed25519; pk=vy0/nfobrje6EqZxuyw6a3ZstytG8WK2vf5Y3xtGrEg= X-Endpoint-Received: by B4 Relay for davemarq@linux.ibm.com/20260216 with auth_id=689 X-Original-From: Dave Marquardt Reply-To: davemarq@linux.ibm.com From: Dave Marquardt Add ibmvfc_interrupt_async_subq(), an IRQ handler dedicated to asynchronous sub-CRQ events from the adapter. The handler disables the sub-CRQ IRQ and then calls ibmvfc_drain_async_subq() to consume all pending entries before re-enabling interrupts. ibmvfc_drain_async_subq() holds both the host lock and the per-queue q_lock while processing. It loops over available CRQ entries via ibmvfc_next_scrq(), dispatching each to ibmvfc_handle_async() with the async flag set, then clears the valid bit and issues a write barrier. After draining, it re-enables the sub-CRQ IRQ and performs one final check for a newly arrived entry to close the IRQ-enable race; if one is found it is processed before exiting the loop. --- drivers/scsi/ibmvscsi/ibmvfc-core.c | 46 +++++++++++++++++++++++++++++++++= ++++ 1 file changed, 46 insertions(+) diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ib= mvfc-core.c index 37ee8f00322a..23c1a4cb40d9 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc-core.c +++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c @@ -4337,6 +4337,52 @@ static struct ibmvfc_crq *ibmvfc_next_scrq(struct ib= mvfc_queue *scrq) return crq; } =20 +static void ibmvfc_drain_async_subq(struct ibmvfc_queue *scrq) +{ + struct ibmvfc_host *vhost =3D scrq->vhost; + struct ibmvfc_crq *crq; + unsigned long flags; + int done =3D 0; + + spin_lock_irqsave(vhost->host->host_lock, flags); + spin_lock(scrq->q_lock); + while (!done) { + while ((crq =3D ibmvfc_next_scrq(scrq)) !=3D NULL) { + ibmvfc_handle_async(crq, scrq->vhost, true); + crq->valid =3D 0; + wmb(); /* complete write */ + } + + ibmvfc_toggle_scrq_irq(scrq, 1); + crq =3D ibmvfc_next_scrq(scrq); + if (crq !=3D NULL) { + ibmvfc_toggle_scrq_irq(scrq, 0); + ibmvfc_handle_async(crq, scrq->vhost, true); + crq->valid =3D 0; + wmb(); /* complete write */ + } else + done =3D 1; + } + spin_unlock(scrq->q_lock); + spin_unlock_irqrestore(vhost->host->host_lock, flags); +} + +/** + * ibmvfc_interrupt_async_subq - Handle an async event from the adapter + * @irq: interrupt request + * @scrq_instance: async subq + * + **/ +static irqreturn_t ibmvfc_interrupt_async_subq(int irq, void *scrq_instanc= e) +{ + struct ibmvfc_queue *scrq =3D (struct ibmvfc_queue *)scrq_instance; + + ibmvfc_toggle_scrq_irq(scrq, 0); + ibmvfc_drain_async_subq(scrq); + + return IRQ_HANDLED; +} + static void ibmvfc_drain_sub_crq(struct ibmvfc_queue *scrq) { struct ibmvfc_crq *crq; --=20 2.55.0 From nobody Mon Sep 28 20:05:56 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 328563BED44; Mon, 17 Aug 2026 20:28:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998481; cv=none; b=OgHMLD5Uso8cYlqr04eEAGkgYJSuxM5B0ibH4K8DaaY3iODce/JMQ2kAbGOv8g1xF87bkkZRoXWNJI9XkkENwPXk/ZO+s6dSBpCLqcF6i2Ouf1OPeSljesM3sOPQGhEib41fDhv7Al5yWYr23obMEzTQMUGD3Q7CvVBOKAlEHZs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998481; c=relaxed/simple; bh=rBgZ5VK40aEMwxtbCY8cctcwTHfingKNS2cXMW/FnxY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sDROzudtyv+qpzceYIdgbUFpyskqzvXuDOA2wq1T8y6nzIqKpkrwGdkuDF7yU8DjxOdW6gghHNS1w8b48H/qKZrXcnXTrRRmALKPDvOo2OauHKTKk3h/P6/AmLo7idFXCkACYje2J7ipLUsJ+OmjzkwmY+JE+y4/oL0rr6mmbWk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TkR7mbhI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TkR7mbhI" Received: by smtp.kernel.org (Postfix) with ESMTPS id D0F71C2BCFC; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786998480; bh=rBgZ5VK40aEMwxtbCY8cctcwTHfingKNS2cXMW/FnxY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=TkR7mbhIu87e04gmqq/AaEETh6Lz2lUzNhieNgZNa55GMHlzEXW1Tc8eYs/ue7aOf K0+sik3CLqGqwNap9qW+jDN+76ZaYyXH0HRJPrHXri2Dq/Vqf1l8S/JR3e5bewaHeL Dk5Lt+RLMilSWmzMeGKU0JQEI5UxMiahgLwyQ7K7DlChWxrelMwo8GoWoiq2/FdX3S pIfF8+SmQwhckxgl2ST6XMMLfxEcV9KAqyUM+HEoUlqaz/rD/Q5jxDK+eCLP+uI+h0 3w/2vhzu2mVCnFwE5s+5no76Z/xRZMfENgVIuuALn4vQs+P2lPGWPRPcLE1R5b8BtN ZWygfDSY+YLVA== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id BD3CEC5DF7D; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 17 Aug 2026 15:27:59 -0500 Subject: [PATCH v6 6/8] scsi: ibmvfc: extend channel registration and deregistration for async subq Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260817-ibmvfc-fpin-support-v6-6-62a2d525e70d@linux.ibm.com> References: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> In-Reply-To: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> To: "James E.J. Bottomley" , "Martin K. Petersen" , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , "Christophe Leroy (CS GROUP)" , Tyrel Datwyler Cc: linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, Brian King , Greg Joyce , Kyle Mahlkuch , Dave Marquardt X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786998478; l=12073; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=eM/8MBGktPM7uSpS5NtgX4c9oHTmEq/tUy21KvC60sg=; b=VJ4dh2WXXVUEx/+J6axHGUGWNoSllzuFwXuaoF4au4SMFID4suym2n6jbj+qLL5nDSz/ayT3m RI/jE8BbtfeBxzV5pHm/9NjlmG0EnDC/M0egm32kr7+40kixLfMeJn9 X-Developer-Key: i=davemarq@linux.ibm.com; a=ed25519; pk=vy0/nfobrje6EqZxuyw6a3ZstytG8WK2vf5Y3xtGrEg= X-Endpoint-Received: by B4 Relay for davemarq@linux.ibm.com/20260216 with auth_id=689 X-Original-From: Dave Marquardt Reply-To: davemarq@linux.ibm.com From: Dave Marquardt ibmvfc_register_channel() and ibmvfc_deregister_channel() previously only handled indexed sub-CRQ channels drawn from the channels->scrqs[] array. The async sub-CRQ (vhost->async_sub_crq) had no registration path through these helpers, requiring separate handling. Extend both functions to accept a negative index as a sentinel value signalling that the async sub-CRQ should be operated on instead of an indexed scrq entry. When index < 0, the queue pointer is set to &vhost->async_sub_crq, the IRQ is named "ibmvfc--async", and the handler is set to ibmvfc_interrupt_async_subq rather than the per-protocol ibmvfc_interrupt_mq handler. hwq_id assignment is skipped for the async queue since it has no meaningful hardware queue index. Error messages in both paths are updated to distinguish async sub-CRQ failures from indexed sub-CRQ failures. Kernel-doc headers are added to both functions documenting the negative-index convention. Signed-off-by: Dave Marquardt --- drivers/scsi/ibmvscsi/ibmvfc-core.c | 102 ++++++++++++++++++++++++-------= ---- drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 20 ++++--- 2 files changed, 85 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ib= mvfc-core.c index 23c1a4cb40d9..da34b572518a 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc-core.c +++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c @@ -3501,7 +3501,7 @@ static void ibmvfc_process_async_work(struct work_str= uct *work) subq =3D &aw->crq.subq; scsi_id =3D 0; wwpn =3D subq->wwpn; - node_name =3D subq->id.node_name; + node_name =3D (subq->flags & IBMVFC_ASYNC_ID_IS_ASSOC_ID) ? 0 : subq->id= .node_name; } else { crq =3D &aw->crq.async_crq; scsi_id =3D crq->scsi_id; @@ -3574,7 +3574,7 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(void *crq, link_state =3D subq->link_state; scsi_id =3D 0; wwpn =3D subq->wwpn; - node_name =3D subq->id.node_name; + node_name =3D subq->flags & IBMVFC_ASYNC_ID_IS_ASSOC_ID ? 0 : subq->id.n= ode_name; } else { async_crq =3D crq; event =3D be64_to_cpu(async_crq->event); @@ -3677,13 +3677,6 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(void *crq, dev_err(vhost->dev, "Unknown async event received: %llu\n", event); break; } - - rmb(); - if (is_sub_crq) - subq->valid =3D 0; - else - async_crq->valid =3D 0; - wmb(); } EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_async); =20 @@ -6728,13 +6721,29 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhos= t) return retrc; } =20 +/** + * ibmvfc_register_channel - Register a sub-CRQ channel with the hypervisor + * @vhost: ibmvfc host struct + * @channels: ibmvfc channels struct containing the channel array and prot= ocol + * @index: index into the channels array for the queue to register, or + * a negative value to register the async sub-CRQ + * + * Register a sub-CRQ with the hypervisor via h_reg_sub_crq, map its hardw= are + * IRQ to a Linux IRQ, and bind an interrupt handler to it. The handler is + * selected based on the channel protocol (SCSI or NVMe) for normal queues= , or + * set to the async sub-CRQ handler when @index is negative. + * + * Return value: + * 0 on success / non-zero on failure + **/ static int ibmvfc_register_channel(struct ibmvfc_host *vhost, struct ibmvfc_channels *channels, int index) { struct device *dev =3D vhost->dev; struct vio_dev *vdev =3D to_vio_dev(dev); - struct ibmvfc_queue *scrq =3D &channels->scrqs[index]; + bool is_async =3D index < 0; + struct ibmvfc_queue *scrq =3D !is_async ? &channels->scrqs[index] : &vhos= t->async_sub_crq; int rc =3D -ENOMEM; =20 ENTER; @@ -6754,36 +6763,49 @@ static int ibmvfc_register_channel(struct ibmvfc_ho= st *vhost, =20 if (!scrq->irq) { rc =3D -EINVAL; - dev_err(dev, "Error mapping sub-crq[%d] irq\n", index); + if (!is_async) + dev_err(dev, "Error mapping sub-crq[%d] irq\n", index); + else + dev_err(dev, "Error mapping async sub-crq irq\n"); goto irq_failed; } =20 - switch (channels->protocol) { - case IBMVFC_PROTO_SCSI: - snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-scsi%d", - vdev->unit_address, index); - scrq->handler =3D ibmvfc_interrupt_mq; - break; - case IBMVFC_PROTO_NVME: - snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-nvmf%d", - vdev->unit_address, index); - scrq->handler =3D ibmvfc_interrupt_mq; - break; - default: - dev_err(dev, "Unknown channel protocol (%d)\n", - channels->protocol); - goto irq_failed; + if (!is_async) { + switch (channels->protocol) { + case IBMVFC_PROTO_SCSI: + snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-scsi%d", + vdev->unit_address, index); + scrq->handler =3D ibmvfc_interrupt_mq; + break; + case IBMVFC_PROTO_NVME: + snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-nvmf%d", + vdev->unit_address, index); + scrq->handler =3D ibmvfc_interrupt_mq; + break; + default: + dev_err(dev, "Unknown channel protocol (%d)\n", + channels->protocol); + goto irq_failed; + } + } else { + snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-async", + vdev->unit_address); + scrq->handler =3D ibmvfc_interrupt_async_subq; } =20 rc =3D request_irq(scrq->irq, scrq->handler, 0, scrq->name, scrq); =20 if (rc) { - dev_err(dev, "Couldn't register sub-crq[%d] irq\n", index); + if (!is_async) + dev_err(dev, "Couldn't register sub-crq[%d] irq\n", index); + else + dev_err(dev, "Couldn't register async sub-crq irq\n"); irq_dispose_mapping(scrq->irq); goto irq_failed; } =20 - scrq->hwq_id =3D index; + if (!is_async) + scrq->hwq_id =3D index; =20 LEAVE; return 0; @@ -6797,13 +6819,26 @@ static int ibmvfc_register_channel(struct ibmvfc_ho= st *vhost, return rc; } =20 +/** + * ibmvfc_deregister_channel - Deregister a sub-CRQ channel with the hyper= visor + * @vhost: ibmvfc host struct + * @channels: ibmvfc channels struct containing the sub-CRQ array + * @index: index into the sub-CRQ array, or -1 to deregister the + * asynchronous sub-CRQ + * + * Frees the IRQ, disposes of the IRQ mapping, and calls H_FREE_SUB_CRQ to + * release the sub-CRQ with the hypervisor. On success the queue message + * buffer is zeroed and the current index is reset. If H_FREE_SUB_CRQ fail= s, + * an error is logged but the channel resources are cleaned up regardless. + */ static void ibmvfc_deregister_channel(struct ibmvfc_host *vhost, struct ibmvfc_channels *channels, int index) { struct device *dev =3D vhost->dev; struct vio_dev *vdev =3D to_vio_dev(dev); - struct ibmvfc_queue *scrq =3D &channels->scrqs[index]; + bool is_async =3D index < 0; + struct ibmvfc_queue *scrq =3D !is_async ? &channels->scrqs[index] : &vhos= t->async_sub_crq; long rc; =20 ENTER; @@ -6817,8 +6852,13 @@ static void ibmvfc_deregister_channel(struct ibmvfc_= host *vhost, scrq->cookie); } while (rc =3D=3D H_BUSY || H_IS_LONG_BUSY(rc)); =20 - if (rc) - dev_err(dev, "Failed to free sub-crq[%d]: rc=3D%ld\n", index, rc); + if (rc) { + if (!is_async) + dev_err(dev, "Failed to free sub-crq[%d]: rc=3D%ld\n", + index, rc); + else + dev_err(dev, "Failed to free async sub-crq: rc=3D%ld\n", rc); + } =20 /* Clean out the queue */ memset(scrq->msgs.crq, 0, PAGE_SIZE); diff --git a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c b/drivers/scsi/ibmvscsi/i= bmvfc_kunit.c index 0b29c1e6478b..444e6e6e1c39 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c +++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c @@ -59,11 +59,13 @@ static void ibmvfc_async_fpin_test(struct kunit *test) crq[fs].wwpn =3D cpu_to_be64(tgt->wwpn); crq[fs].node_name =3D cpu_to_be64(tgt->ids.node_name); ibmvfc_handle_async(&crq[fs], vhost, false); + crq[fs].valid =3D 0; + wmb(); msleep(1U); } =20 post[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_= device_specific); - post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn_device_specific); post[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn= _clear); post[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.l= i_failure_unknown); post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats= .cn_clear); @@ -80,7 +82,7 @@ static void ibmvfc_async_fpin_test(struct kunit *test) pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED]+1); =20 pre[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_d= evice_specific); - pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n); + pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n_device_specific); pre[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn_= clear); pre[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.li= _failure_unknown); pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats.= cn_clear); @@ -94,10 +96,12 @@ static void ibmvfc_async_fpin_test(struct kunit *test) crq[0].wwpn =3D cpu_to_be64(tgt->wwpn); crq[0].node_name =3D cpu_to_be64(tgt->ids.node_name); ibmvfc_handle_async(&crq[0], vhost, false); + crq[0].valid =3D 0; + wmb(); msleep(1U); =20 post[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_= device_specific); - post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn_device_specific); post[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn= _clear); post[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.l= i_failure_unknown); post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats= .cn_clear); @@ -163,11 +167,13 @@ static void ibmvfc_full_fpin_test(struct kunit *test) crq[fs].wwpn =3D cpu_to_be64(tgt->wwpn); crq[fs].id.node_name =3D cpu_to_be64(tgt->ids.node_name); ibmvfc_handle_async(&crq[fs], vhost, true); + crq[fs].valid =3D 0; + wmb(); msleep(1U); } =20 post[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_= device_specific); - post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn_device_specific); post[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn= _clear); post[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.l= i_failure_unknown); post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats= .cn_clear); @@ -184,7 +190,7 @@ static void ibmvfc_full_fpin_test(struct kunit *test) pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED]+1); =20 pre[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_d= evice_specific); - pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n); + pre[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.c= n_device_specific); pre[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn_= clear); pre[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.li= _failure_unknown); pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats.= cn_clear); @@ -197,10 +203,12 @@ static void ibmvfc_full_fpin_test(struct kunit *test) crq[0].wwpn =3D cpu_to_be64(tgt->wwpn); crq[0].id.node_name =3D cpu_to_be64(tgt->ids.node_name); ibmvfc_handle_async(&crq[0], vhost, true); + crq[0].valid =3D 0; + wmb(); msleep(1U); =20 post[IBMVFC_AE_FPIN_LINK_CONGESTED] =3D READ_ONCE(fc_host->fpin_stats.cn_= device_specific); - post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] =3D READ_ONCE(tgt->rport->fpin_stats.= cn_device_specific); post[IBMVFC_AE_FPIN_PORT_CLEARED] =3D READ_ONCE(tgt->rport->fpin_stats.cn= _clear); post[IBMVFC_AE_FPIN_PORT_DEGRADED] =3D READ_ONCE(tgt->rport->fpin_stats.l= i_failure_unknown); post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] =3D READ_ONCE(fc_host->fpin_stats= .cn_clear); --=20 2.55.0 From nobody Mon Sep 28 20:05:56 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 28B533BE644; Mon, 17 Aug 2026 20:28:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998481; cv=none; b=EJ3Ng4qlVrhKkAcy+gkE3tmTstlG7MKSll95VpJ1VfmBXTdhtkM6TZ07GKGqtV9zyiCMex1XI+LNICRfPCOyIywrKFNJgCUAS1zYQf3l/v08wQJJaxaKqFsqw8PnCJWTmJ9k7L8vSHRtmz4z1G4k5RO8rKRvx5WO6AOwUQryNr8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998481; c=relaxed/simple; bh=0xav3ZG2vwafFbyRgSfB4B8YteusTxcTD4O99qBOm9I=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=SXT3ySAHYN11P2OKwUn2e8rzHUhl+TrMhmEakNIkAPJ0f60VeAV/2y1UGY47zzwrZLSNhDo9iowDCPzkhUuLaR58gIdtVr9amt7rynX+4FpvzpmDKJhC2CMoU2jWNEPMwpVYLBwCxygjGvNVAFrR5Mf80zNfopqcA5wjUQU8+tY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LJ0rEFLx; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LJ0rEFLx" Received: by smtp.kernel.org (Postfix) with ESMTPS id E307FC2BCFD; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786998480; bh=0xav3ZG2vwafFbyRgSfB4B8YteusTxcTD4O99qBOm9I=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=LJ0rEFLxSD8Sd6xWr4m5FieJpyoxlOWD4LdvUJqz+HyKZ1KKfpMIRqHNkuoyYMEnu CeAPBg6L4hj/1TF2s3n0fhcs2Y+DD6IPOw1/nf4NmrHLOjf14iF3mzxQsIi8fvN4bC BRFlaiIwVeor2JSrnSpzgttHPUgLYfhxxRnhnhtTPO5X5Ph6Gpo9A+YKPb7HQM/tHl 7sW9/2tXGKM3xNPL6M+DZ0P6LvabHWp2iNP8DxxR8i3OZEeQB8DRA/Snlido5V1ZGe GyNt97C6ryYXrSLbf7cGQAVgCGGxZqLUGpxwM9lTGMFzJjzt0DqTMioPzi/k6ItcNv gtvni6FJ5gqMQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D1A5DC5B572; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 17 Aug 2026 15:28:00 -0500 Subject: [PATCH v6 7/8] scsi: ibmvfc: register and use asynchronous sub CRQ for events Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260817-ibmvfc-fpin-support-v6-7-62a2d525e70d@linux.ibm.com> References: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> In-Reply-To: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> To: "James E.J. Bottomley" , "Martin K. Petersen" , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , "Christophe Leroy (CS GROUP)" , Tyrel Datwyler Cc: linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, Brian King , Greg Joyce , Kyle Mahlkuch , Dave Marquardt X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786998478; l=4793; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=j22BIxygRjLa4p+iYGPOotTe0EA7iaqbwa3Kd3tyrQ0=; b=bmM1vQX/hlqZescK8GyIzDVs13rycnVQ8XYyh2XPfyATmUqG9Yqb5T4roaPkoGnU19d30Y1gj daUXzc6XyV9BhsxITyxziYnDvV/NpasYpGwbNwYJP8ho59+tARxt7Ye X-Developer-Key: i=davemarq@linux.ibm.com; a=ed25519; pk=vy0/nfobrje6EqZxuyw6a3ZstytG8WK2vf5Y3xtGrEg= X-Endpoint-Received: by B4 Relay for davemarq@linux.ibm.com/20260216 with auth_id=689 X-Original-From: Dave Marquardt Reply-To: davemarq@linux.ibm.com From: Dave Marquardt Wire the async sub-CRQ into the sub-CRQ lifecycle so it is allocated, registered, and freed alongside the SCSI channel queues. In ibmvfc_init_sub_crqs(), allocate the async sub-CRQ queue buffer via ibmvfc_alloc_queue() before allocating the SCSI channels. Register it with the VIOS by calling ibmvfc_register_channel() with index -1 (the negative-index sentinel introduced in the previous commit). Either failure disables multi-queue and aborts init. In ibmvfc_release_sub_crqs(), deregister and free the async sub-CRQ before tearing down the SCSI channels. In ibmvfc_channel_setup_done(), capture the async sub-CRQ handle returned by the VIOS in the channel setup response and store it in vhost->async_sub_crq.vios_cookie. In ibmvfc_set_login_info(), advertise IBMVFC_USE_ASYNC_SUBQ, IBMVFC_CAN_HANDLE_FPIN, and IBMVFC_YES_SCSI capabilities whenever multi-queue channels are enabled. IBMVFC_YES_SCSI was previously only set for NVMe-enabled configurations; move it to the common multi-queue path so it is always advertised when channels are in use. --- drivers/scsi/ibmvscsi/ibmvfc-core.c | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ib= mvfc-core.c index da34b572518a..686142761863 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc-core.c +++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c @@ -1568,9 +1568,11 @@ static void ibmvfc_set_login_info(struct ibmvfc_host= *vhost) =20 if (vhost->mq_enabled || vhost->using_channels) { login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_USE_CHANNELS); + login_info->capabilities |=3D cpu_to_be64(IBMVFC_USE_ASYNC_SUBQ); + login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_HANDLE_FPIN); + login_info->capabilities |=3D cpu_to_be64(IBMVFC_YES_SCSI); if (vhost->nvme_enabled) { login_info->capabilities |=3D cpu_to_be64(IBMVFC_YES_NVMEOF); - login_info->capabilities |=3D cpu_to_be64(IBMVFC_YES_SCSI); login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_USE_WWPN_ALL); } } @@ -5749,6 +5751,7 @@ static void ibmvfc_channel_setup_done(struct ibmvfc_e= vent *evt) for (i =3D 0; i < nvme->active_queues; i++) nvme->scrqs[i].vios_cookie =3D be64_to_cpu(setup->channel_handles[scsi->active_queues + i]); + vhost->async_sub_crq.vios_cookie =3D be64_to_cpu(setup->async_sub_crq_ha= ndle); =20 ibmvfc_dbg(vhost, "Using %u SCSI channels\n", scsi->active_queues); @@ -5808,6 +5811,7 @@ static void ibmvfc_channel_setup(struct ibmvfc_host *= vhost) for (i =3D 0; i < nvme_channels; i++) setup_buf->channel_handles[scsi_channels + i] =3D cpu_to_be64(nvme->scrqs[i].cookie); + setup_buf->async_sub_crq_handle =3D cpu_to_be64(vhost->async_sub_crq.coo= kie); } =20 ibmvfc_init_event(evt, ibmvfc_channel_setup_done, IBMVFC_MAD_FORMAT); @@ -6879,7 +6883,9 @@ static void ibmvfc_reg_sub_crqs(struct ibmvfc_host *v= host, for (i =3D 0; i < channels->max_queues; i++) { if (ibmvfc_register_channel(vhost, channels, i)) { for (j =3D i; j > 0; j--) - ibmvfc_deregister_channel(vhost, channels, j - 1); + ibmvfc_deregister_channel( + vhost, channels, j - 1); + vhost->do_enquiry =3D 0; return; } @@ -6934,10 +6940,27 @@ static int ibmvfc_alloc_channels(struct ibmvfc_host= *vhost, =20 static void ibmvfc_init_sub_crqs(struct ibmvfc_host *vhost) { + int rc =3D 0; + ENTER; if (!vhost->mq_enabled) return; =20 + rc =3D ibmvfc_alloc_queue(vhost, &vhost->async_sub_crq, IBMVFC_SUB_CRQ_FM= T); + if (rc) { + vhost->do_enquiry =3D 0; + vhost->mq_enabled =3D 0; + return; + } + + /* register async_sub_crq channel */ + if (ibmvfc_register_channel(vhost, &vhost->scsi_scrqs, -1)) { + ibmvfc_free_queue(vhost, &vhost->async_sub_crq); + vhost->do_enquiry =3D 0; + vhost->mq_enabled =3D 0; + return; + } + if (ibmvfc_alloc_channels(vhost, &vhost->scsi_scrqs)) { vhost->do_enquiry =3D 0; vhost->mq_enabled =3D 0; @@ -6980,6 +7003,9 @@ static void ibmvfc_release_sub_crqs(struct ibmvfc_hos= t *vhost) if (!vhost->scsi_scrqs.scrqs) return; =20 + ibmvfc_deregister_channel(vhost, &vhost->scsi_scrqs, -1); + ibmvfc_free_queue(vhost, &vhost->async_sub_crq); + ibmvfc_dereg_sub_crqs(vhost, &vhost->scsi_scrqs); ibmvfc_release_channels(vhost, &vhost->scsi_scrqs); =20 @@ -7258,7 +7284,7 @@ static int ibmvfc_probe(struct vio_dev *vdev, const s= truct vio_device_id *id) INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread); mutex_init(&vhost->passthru_mutex); =20 - vhost->fpin_workq =3D alloc_workqueue("%s-fpin-workq-%u", 0, 0, + vhost->fpin_workq =3D alloc_workqueue("%s-fpin-workq-%u", WQ_PERCPU, 0, IBMVFC_NAME, shost->host_no); if (vhost->fpin_workq =3D=3D NULL) goto free_scsi_host; --=20 2.55.0 From nobody Mon Sep 28 20:05:56 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3294A3BED4F; Mon, 17 Aug 2026 20:28:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998481; cv=none; b=VETbWdzB+cAVE/z/ez/0zGZ/aQHcOGMjNnOXTufMViIplylFUFSn/TO4+7CTDTN3fe8EOIWrrg5LDMmTiLwlNOEq79I26y9fCG3880+wZyA62G+SF30FNCYorJBDU2fsvLXqHBJfdXbQF/AKMPx01ZGNnxZym9LweBzeaNg6H1o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786998481; c=relaxed/simple; bh=amL52l/okHbYKiCDMsCPi5kgeo/yQt3zDter/qTs5oQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=WKdA/h+xqYLz1r4WJXkoPej+uu3Dxtwk01UWkzegASYFuZIzx+SJM7JXKfaqBwMG9pbTCytAtfeg6bwFqA/beTpz/Pw/b0ZhtefZZxLzIdB1fPIFZcOc2wOpNp41ww00rYsJmyEieHj46HNMKkBKnrckUnUbSjQmv09x3RTlolA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OfK/peEs; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OfK/peEs" Received: by smtp.kernel.org (Postfix) with ESMTPS id 02EC4C2BD00; Mon, 17 Aug 2026 20:28:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1786998481; bh=amL52l/okHbYKiCDMsCPi5kgeo/yQt3zDter/qTs5oQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=OfK/peEsDfqN8RN4wR1cQAXjmsv8sHDr6O/XYz/QVEHXnI2zF7B1dIbEyNnJ8qS3S 6rpwWqo+Gg/E8de/Kc7SJ7sfOY631CZj3fQCjtc6uWPT6FpZM6lUbSw/5wyx5I+CCS jMfwCm7P4gPph5jL3/iVTkuf0Owu7kX9v13IRoB2Wkb7UNcEkAKVCuvoTdtJy0kuIO bf7XR3kO3NVwJPuZPepmQW+RCWVQ9xf3+KDbV6/fYRGSWL8bnDAAzCaercB5KTOxKI X3d9gS68yAP+CHErV2vdaxBvz/3OanHdD6wENyPAJQxHQJg/+ptXjaH69idhHcgiYR Swf0loL/kEgGw== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id E561EC5DF7F; Mon, 17 Aug 2026 20:28:00 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 17 Aug 2026 15:28:01 -0500 Subject: [PATCH v6 8/8] scsi: ibmvfc: handle extended FPIN events Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260817-ibmvfc-fpin-support-v6-8-62a2d525e70d@linux.ibm.com> References: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> In-Reply-To: <20260817-ibmvfc-fpin-support-v6-0-62a2d525e70d@linux.ibm.com> To: "James E.J. Bottomley" , "Martin K. Petersen" , Madhavan Srinivasan , Michael Ellerman , Nicholas Piggin , "Christophe Leroy (CS GROUP)" , Tyrel Datwyler Cc: linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, Brian King , Greg Joyce , Kyle Mahlkuch , Dave Marquardt X-Mailer: b4 0.16.0 X-Developer-Signature: v=1; a=ed25519-sha256; t=1786998478; l=11267; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=wtV6dTnhWVvMmvGiELngpnyuuTDST/nEYZo8U676ADI=; b=qCLma0aWa0xnXBV46Nc5J63YruNDz2hnIGavBEGx3rmFD/VIeQ2u00EFAkKPFfhonYWXDw/2z AYQdyEjN/fQB915i2/hEeXE0D8GUZrH/ZkSFuqpeVQq/kLP490Jgg2O X-Developer-Key: i=davemarq@linux.ibm.com; a=ed25519; pk=vy0/nfobrje6EqZxuyw6a3ZstytG8WK2vf5Y3xtGrEg= X-Endpoint-Received: by B4 Relay for davemarq@linux.ibm.com/20260216 with auth_id=689 X-Original-From: Dave Marquardt Reply-To: davemarq@linux.ibm.com From: Dave Marquardt Implement support for extended FPIN messages received via the asynchronous sub-queue, completing full FPIN functionality. Extended FPIN messages provide more detailed information about fabric events compared to basic FPIN messages, including specific event types, modifiers, thresholds, and event counts. Add ibmvfc_extended_fpin_to_desc() to convert extended FPIN messages from async sub-queue format to fc_els_fpin structures with complete descriptor information. Update ibmvfc_process_async_work() to handle extended FPIN events from the async sub-queue. Set IBMVFC_CAN_HANDLE_FPIN capability during login to inform VIOS that the client can process extended FPIN messages. Add comprehensive KUnit tests to validate extended FPIN event handling and verify proper statistics updates for all FPIN event types. Signed-off-by: Dave Marquardt --- drivers/scsi/ibmvscsi/ibmvfc-core.c | 53 ++++++++++++++++- drivers/scsi/ibmvscsi/ibmvfc.h | 30 ++++++++++ drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 110 +++++++++++++++++++++++++++++++= ++++ 3 files changed, 191 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ib= mvfc-core.c index 686142761863..5c711447ac6d 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc-core.c +++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c @@ -1571,6 +1571,7 @@ static void ibmvfc_set_login_info(struct ibmvfc_host = *vhost) login_info->capabilities |=3D cpu_to_be64(IBMVFC_USE_ASYNC_SUBQ); login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_HANDLE_FPIN); login_info->capabilities |=3D cpu_to_be64(IBMVFC_YES_SCSI); + login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_HANDLE_FPIN_EXT); if (vhost->nvme_enabled) { login_info->capabilities |=3D cpu_to_be64(IBMVFC_YES_NVMEOF); login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_USE_WWPN_ALL); @@ -3447,6 +3448,41 @@ ibmvfc_full_fpin_to_desc(struct ibmvfc_async_sub_crq= *ibmvfc_fpin) cpu_to_be32(1)); } =20 +/** + * ibmvfc_ext_fpin_to_desc(): allocate and populate a struct fc_els_fpin s= truct + * 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_ext_fpin_to_desc(struct ibmvfc_async_subq_fpin *ibmvfc_fpin) +{ + u8 flags =3D ibmvfc_fpin->fpin_data.flags; + __be32 threshold =3D cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD); + __be16 modifier =3D 0; + __be32 count =3D cpu_to_be32(1); + __be16 type =3D 0; + + if (flags & IBMVFC_FPIN_EVENT_TYPE_VALID) + type =3D ibmvfc_fpin->fpin_data.event_type; + if (flags & IBMVFC_FPIN_MODIFIER_VALID) + modifier =3D ibmvfc_fpin->fpin_data.event_type_modifier; + if (flags & IBMVFC_FPIN_THRESHOLD_VALID) + threshold =3D ibmvfc_fpin->fpin_data.event_threshold; + if (flags & IBMVFC_FPIN_EVENT_COUNT_VALID) + count =3D ibmvfc_fpin->fpin_data.event_data.event_count; + + return ibmvfc_common_fpin_to_desc(ibmvfc_fpin->fpin_status, + ibmvfc_fpin->wwpn, type, + modifier, threshold, count); +} + /** * ibmvfc_find_target - Search for a target in a target list * @target_list: list head of targets to search @@ -3485,6 +3521,7 @@ static struct ibmvfc_target *ibmvfc_find_target(struc= t list_head *target_list, static void ibmvfc_process_async_work(struct work_struct *work) { struct ibmvfc_async_sub_crq *subq =3D NULL; + struct ibmvfc_async_subq_fpin *sqfpin; struct ibmvfc_async_work *aw; struct ibmvfc_async_crq *crq =3D NULL; struct ibmvfc_target *tgt; @@ -3532,8 +3569,20 @@ static void ibmvfc_process_async_work(struct work_st= ruct *work) =20 if (crq) fpin =3D ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn); - else - fpin =3D ibmvfc_full_fpin_to_desc(subq); + else { + sqfpin =3D (struct ibmvfc_async_subq_fpin *)subq; + if ((subq->flags & IBMVFC_ASYNC_IS_FPIN_EXT) =3D=3D 0) { + fpin =3D ibmvfc_full_fpin_to_desc(subq); + } else if (!(sqfpin->fpin_data.flags & IBMVFC_FPIN_EVENT_TYPE_VALID)) { + dev_err_ratelimited(vhost->dev, + "Invalid extended FPIN event received\n"); + } else if (!ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_FPIN_EXT)) { + dev_err_ratelimited(vhost->dev, + "Unexpected extended FPIN event received\n"); + } else { + fpin =3D ibmvfc_ext_fpin_to_desc(sqfpin); + } + } =20 if (fpin) { fc_host_fpin_rcv(tgt->vhost->host, diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 26a2be9354e9..e1b9884ea27e 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -210,6 +210,7 @@ struct ibmvfc_npiv_login { #define IBMVFC_CAN_USE_WWPN_ALL 0x080 #define IBMVFC_USE_ASYNC_SUBQ 0x100 #define IBMVFC_CAN_USE_NOOP_CMD 0x200 +#define IBMVFC_CAN_HANDLE_FPIN_EXT 0x800 __be64 node_name; struct srp_direct_buf async; u8 partition_name[IBMVFC_MAX_NAME]; @@ -261,6 +262,7 @@ struct ibmvfc_npiv_login_resp { #define IBMVFC_SUPPORT_WWPN_ALL 0x0400 #define IBMVFC_ASYNC_SUBQ 0x0800 #define IBMVFC_SUPPORT_NOOP_CMD 0x1000 +#define IBMVFC_SUPPORT_FPIN_EXT 0x2000 __be32 max_cmds; __be32 scsi_id_sz; __be64 max_dma_len; @@ -786,6 +788,34 @@ struct ibmvfc_async_sub_crq { } id; } __packed __aligned(8); =20 +struct ibmvfc_fpin_data { +#define IBMVFC_FPIN_EVENT_TYPE_VALID 0x01 +#define IBMVFC_FPIN_MODIFIER_VALID 0x02 +#define IBMVFC_FPIN_THRESHOLD_VALID 0x04 +#define IBMVFC_FPIN_SEVERITY_VALID 0x08 +#define IBMVFC_FPIN_EVENT_COUNT_VALID 0x10 + u8 flags; + u8 reserved[3]; + __be16 event_type; + __be16 event_type_modifier; + __be32 event_threshold; + union { + u8 severity; + __be32 event_count; + } event_data; +} __packed __aligned(8); + +struct ibmvfc_async_subq_fpin { + volatile u8 valid; + u8 flags; + u8 link_state; + u8 fpin_status; + __be16 event; + __be16 pad; + volatile __be64 wwpn; + struct ibmvfc_fpin_data fpin_data; +} __packed __aligned(8); + struct ibmvfc_async_work { struct ibmvfc_host *vhost; bool is_subq; diff --git a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c b/drivers/scsi/ibmvscsi/i= bmvfc_kunit.c index 444e6e6e1c39..ce938b93ecb4 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c +++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include "ibmvfc.h" @@ -225,9 +226,118 @@ static void ibmvfc_full_fpin_test(struct kunit *test) post[IBMVFC_AE_FPIN_CONGESTION_CLEARED]); } =20 +#define IBMVFC_TEST_FPIN_EXT(fs, ev, stat, crq) { \ + crq.valid =3D 0x80; \ + crq.flags =3D IBMVFC_ASYNC_IS_FPIN_EXT; \ + crq.link_state =3D IBMVFC_AE_LS_LINK_UP; \ + crq.fpin_status =3D (fs); \ + crq.event =3D cpu_to_be16(IBMVFC_AE_FPIN); \ + crq.wwpn =3D cpu_to_be64(tgt->wwpn); \ + crq.fpin_data.flags =3D IBMVFC_FPIN_EVENT_TYPE_VALID; \ + crq.fpin_data.event_type =3D cpu_to_be16((ev)); \ + pre =3D READ_ONCE(tgt->rport->fpin_stats.stat); \ + ibmvfc_handle_async((struct ibmvfc_crq *)&crq, vhost, true); \ + msleep(1U); \ + post =3D READ_ONCE(tgt->rport->fpin_stats.stat); \ +} + +/** + * ibmvfc_extended_fpin_test - unit test for extended FPIN events + * @test: pointer to kunit structure + * + * Tests + * + * Return: void + */ +static void ibmvfc_extended_fpin_test(struct kunit *test) +{ + enum ibmvfc_ae_fpin_status fs; + struct ibmvfc_async_subq_fpin crq[IBMVFC_AE_FPIN_CONGESTION_CLEARED+1] = =3D {}; + struct ibmvfc_async_subq_fpin + crqcn[IBMVFC_AE_FPIN_PORT_CONGESTED][FPIN_CONGN_DEVICE_SPEC+1] =3D {}; + struct ibmvfc_async_subq_fpin crqportdg[FPIN_LI_DEVICE_SPEC+1] =3D {}; + struct ibmvfc_target *tgt; + struct ibmvfc_host *vhost; + struct list_head *headp; + LIST_HEAD(evt_doneq); + u64 pre, post; + + headp =3D ibmvfc_get_headp(); + KUNIT_ASSERT_FALSE_MSG(test, list_empty(headp), "No ibmvfc devices availa= ble\n"); + vhost =3D list_first_entry(headp, struct ibmvfc_host, queue); + KUNIT_ASSERT_GE_MSG(test, vhost->scsi_scrqs.num_targets, 1, "No targets"); + + tgt =3D list_first_entry(&vhost->scsi_scrqs.targets, struct ibmvfc_target= , queue); + KUNIT_ASSERT_NOT_NULL(test, tgt->rport); + + for (fs =3D IBMVFC_AE_FPIN_LINK_CONGESTED; fs <=3D IBMVFC_AE_FPIN_CONGEST= ION_CLEARED; fs++) { + switch (fs) { + case IBMVFC_AE_FPIN_PORT_CLEARED: + case IBMVFC_AE_FPIN_CONGESTION_CLEARED: + crq[fs].valid =3D 0x80; + crq[fs].flags =3D IBMVFC_ASYNC_IS_FPIN_EXT; + crq[fs].link_state =3D IBMVFC_AE_LS_LINK_UP; + crq[fs].fpin_status =3D fs; + crq[fs].event =3D cpu_to_be16(IBMVFC_AE_FPIN); + crq[fs].wwpn =3D cpu_to_be64(tgt->wwpn); + crq[fs].fpin_data.flags =3D IBMVFC_FPIN_EVENT_TYPE_VALID; + crq[fs].fpin_data.event_type =3D cpu_to_be16(FPIN_CONGN_CLEAR); + pre =3D READ_ONCE(tgt->rport->fpin_stats.cn_clear); + ibmvfc_handle_async((struct ibmvfc_crq *)&crq[fs], vhost, true); + msleep(1U); + post =3D READ_ONCE(tgt->rport->fpin_stats.cn_clear); + break; + case IBMVFC_AE_FPIN_LINK_CONGESTED: + case IBMVFC_AE_FPIN_PORT_CONGESTED: + IBMVFC_TEST_FPIN_EXT(fs, FPIN_CONGN_CLEAR, cn_clear, + crqcn[fs-1][FPIN_CONGN_CLEAR]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_CONGN_LOST_CREDIT, + cn_lost_credit, + crqcn[fs-1][FPIN_CONGN_LOST_CREDIT]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_CONGN_CREDIT_STALL, + cn_credit_stall, + crqcn[fs-1][FPIN_CONGN_CREDIT_STALL]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_CONGN_OVERSUBSCRIPTION, + cn_oversubscription, + crqcn[fs-1][FPIN_CONGN_OVERSUBSCRIPTION]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_CONGN_DEVICE_SPEC, + cn_device_specific, + crqcn[fs-1][FPIN_CONGN_DEVICE_SPEC]); + break; + case IBMVFC_AE_FPIN_PORT_DEGRADED: + IBMVFC_TEST_FPIN_EXT(fs, FPIN_LI_UNKNOWN, + li_failure_unknown, + crqportdg[FPIN_LI_UNKNOWN]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_LI_LINK_FAILURE, + li_link_failure_count, + crqportdg[FPIN_LI_LINK_FAILURE]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_LI_LOSS_OF_SYNC, + li_loss_of_sync_count, + crqportdg[FPIN_LI_LOSS_OF_SYNC]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_LI_LOSS_OF_SIG, + li_loss_of_signals_count, + crqportdg[FPIN_LI_LOSS_OF_SIG]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_LI_PRIM_SEQ_ERR, + li_prim_seq_err_count, + crqportdg[FPIN_LI_PRIM_SEQ_ERR]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_LI_INVALID_TX_WD, + li_invalid_tx_word_count, + crqportdg[FPIN_LI_INVALID_TX_WD]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_LI_INVALID_CRC, + li_invalid_crc_count, + crqportdg[FPIN_LI_INVALID_CRC]); + IBMVFC_TEST_FPIN_EXT(fs, FPIN_LI_DEVICE_SPEC, + li_device_specific, + crqportdg[FPIN_LI_DEVICE_SPEC]); + break; + } + } +} + static struct kunit_case ibmvfc_fpin_test_cases[] =3D { KUNIT_CASE(ibmvfc_async_fpin_test), KUNIT_CASE(ibmvfc_full_fpin_test), + KUNIT_CASE(ibmvfc_extended_fpin_test), {}, }; =20 --=20 2.55.0