From nobody Sun Jul 26 00:22:09 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 0974D3382E1; Fri, 10 Jul 2026 19:16:57 +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=1783711018; cv=none; b=rMixo4MfQac5GMAIH4jJap5ZMakCf/sCebIQxnkLm5kAQGsXEaLTleUozz6m6MwT3b6jsB8i09xE0xLnAL7bHP91YYHaCU2NF+kAS3P9o/Fej80kIBFWPqCVJs1UYKdnR61OhMKD6XU6GtQq+Gm2Ly9oUKYFDVpUCJwMHfKpXwA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783711018; c=relaxed/simple; bh=3yqe9GX1du6TiCTlJkoiHGqkPxb5/C5fjWZHDCoTY5s=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dWOd5XX+G93eUtueWb5HmXd6WD4Ymyp9lm5PwFQBPKjaKXWQy2Upa83ijUATLFyGJtZhndawY4wLU43PJcqyppxzzJHYP3y30ENOVDPN81Kr2QlUbXl3Ok0brMNXbPjU2kLVvI4sHxuSRzQXmdnZ9pqaZ4fJtZoa1VwE5BYilRw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=okPyzzp5; 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="okPyzzp5" Received: by smtp.kernel.org (Postfix) with ESMTPS id AC9E1C2BCC9; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1783711017; bh=3yqe9GX1du6TiCTlJkoiHGqkPxb5/C5fjWZHDCoTY5s=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=okPyzzp5T0hJwaSvwAvTdgh4v+JuiNY40lwJ3i4EBjG0cHtcOvmARDcJ16Spsky1z o+9s+9BXO5ivEzU8/doWKPTY++9H71iOmDfwKvWT8DL4ohQ8mZM5PMJuaKhx8vjIwj L5oROYo1kEU4L+QAoe6cUsNFw25CDq926pVAeCMcFTfo2FawnpE7KKYz0zNTEH+Cuc /xCDKVGMfCjKc5R/ISl7wFWqJSMM7h6S60BfmdNdDMBUz+oEdc7X+7n5Z++18HrHOp Lw17rMtvzyryfercBVHFr96yC2iEBGqh6drYmwdp5OuNbr0ns/nDCzymcksy7EnNHm R92bQFFgjwhrQ== 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 8DD7FC44501; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Fri, 10 Jul 2026 14:16:41 -0500 Subject: [PATCH v4 1/8] 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: <20260710-ibmvfc-fpin-support-v4-1-ef031ac19520@linux.ibm.com> References: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@linux.ibm.com> In-Reply-To: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@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.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1783711016; l=20898; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=h7uTz/n5LZnGcsqIITUlKoEOKP5bouVsCbK6LtnUe2c=; b=/735JNVEZBOSiCZss9sI2A3gDAX8Ib71Nt42hUlsnKbFK2xnrhtJpKj7VhjynhSrhMFNHoqgU iGOg+RsHNsgBC45LGDINMhMGN/Te5T7L8F3q7njnPC0fJwEKywnvQa4 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.c | 253 +++++++++++++++++++++++++++++++= +++- drivers/scsi/ibmvscsi/ibmvfc.h | 16 +++ drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 132 ++++++++++++++++++ 5 files changed, 405 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index c3042393af23..d5fc7eb2ebb1 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -758,6 +758,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 5eb1cb1a0028..75dc7aee15a0 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0-only 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.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 3dd2adda195e..d3fd1d3437c6 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -30,6 +30,9 @@ #include #include #include +#include +#include +#include #include "ibmvfc.h" =20 static unsigned int init_timeout =3D IBMVFC_INIT_TIMEOUT; @@ -3137,6 +3140,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 { @@ -3185,16 +3189,228 @@ 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_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_target *tgt, *next; + struct ibmvfc_async_work *aw; + struct ibmvfc_async_crq *crq; + struct ibmvfc_host *vhost; + struct fc_els_fpin *fpin; + unsigned long flags; + + aw =3D container_of(work, struct ibmvfc_async_work, async_work_s); + crq =3D &aw->crq; + vhost =3D aw->vhost; + + if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + goto end; + + spin_lock_irqsave(vhost->host->host_lock, flags); + list_for_each_entry_safe(tgt, next, &vhost->targets, queue) { + if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) !=3D crq->scsi_id) + continue; + if (crq->wwpn && cpu_to_be64(tgt->ids.port_name) !=3D crq->wwpn) + continue; + if (crq->node_name && cpu_to_be64(tgt->ids.node_name) !=3D crq->node_nam= e) + continue; + if (!tgt->rport) + continue; + break; + } + spin_unlock_irqrestore(vhost->host->host_lock, flags); + + if (list_entry_is_head(tgt, &vhost->targets, queue) || !tgt->rport) { + dev_err_ratelimited(vhost->dev, "Invalid target for FPIN\n"); + goto end; + } + + 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 %u received, unable to process\n", + crq->fpin_status); + end: + 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," @@ -3269,11 +3485,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 @@ -3803,8 +4031,6 @@ static void ibmvfc_tasklet(void *data) /* Pull all the valid messages off the async CRQ */ while ((async =3D ibmvfc_next_async_crq(vhost)) !=3D NULL) { ibmvfc_handle_async(async, vhost); - async->valid =3D 0; - wmb(); } =20 /* Pull all the valid messages off the CRQ */ @@ -3818,8 +4044,6 @@ static void ibmvfc_tasklet(void *data) if ((async =3D ibmvfc_next_async_crq(vhost)) !=3D NULL) { vio_disable_interrupts(vdev); ibmvfc_handle_async(async, vhost); - async->valid =3D 0; - wmb(); } else if ((crq =3D ibmvfc_next_crq(vhost)) !=3D NULL) { vio_disable_interrupts(vdev); ibmvfc_handle_crq(crq, vhost, &evt_doneq); @@ -6364,9 +6588,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 devm_alloc_workqueue(vhost->dev, "%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 @@ -6412,6 +6642,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: @@ -6603,5 +6836,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 c73ed2314ad0..f69e0605a78d 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -671,8 +671,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; @@ -686,6 +690,12 @@ struct ibmvfc_async_crq { __be64 reserved; } __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; @@ -914,6 +924,7 @@ struct ibmvfc_host { struct work_struct rport_add_work_q; wait_queue_head_t init_wait_q; wait_queue_head_t work_wait_q; + struct workqueue_struct *fpin_workq; }; =20 #define DBG_CMD(CMD) do { if (ibmvfc_debug) CMD; } while (0) @@ -953,4 +964,9 @@ struct ibmvfc_host { #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..1c90318b6811 --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c @@ -0,0 +1,132 @@ +// 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(queue, struct ibmvfc_host, queue); + + KUNIT_ASSERT_GE_MSG(test, vhost->num_targets, 1, "No targets"); + tgt =3D list_first_entry(&vhost->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(500U); + + 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(500U); + + 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 Sun Jul 26 00:22:09 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 0962B1624C5; Fri, 10 Jul 2026 19:16:57 +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=1783711018; cv=none; b=Ja9SeAUI8RX/3BAiauf4fIUkJzFEug6+SPy6a+vwr2sqXLQ96NqOiOs3W7wwjMp1p5CG367vjO5AberzWWtd8HNuyTgV10AmG2jA9bqtkIrx5hM+dk7LWz/8s6Wl4El3dcp7QI9uRa7PfHxSRVaAzU2XUt6mJxZb0SfKpCmODcs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783711018; c=relaxed/simple; bh=1YE5g6HVPLyiV5N1mPToJqURBjxD0Z6Q7YYPMblTBB4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BUWRzjSbr+wkLMruD9/zfO2/Rv4eGE/2WsDgdcNgW3ZrhQNQrxBM+3JHCo8ZA7VZ7IWbTlTiT3iZwyvwM5ZDDkA1yaSfWxnPddXTVtKdrvvY8RGfeIcgjwMm4waUCb/HwIEZl1zBSXpw0bQ72c2eCE1fs9vL8R5zo2J2bbxAQCY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=sBYfisGu; 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="sBYfisGu" Received: by smtp.kernel.org (Postfix) with ESMTPS id B7DBFC2BCC6; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1783711017; bh=1YE5g6HVPLyiV5N1mPToJqURBjxD0Z6Q7YYPMblTBB4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=sBYfisGuXYxCCia8kH2OyHdHw+sYozn/DyESr7ldlvwzIf0qlo9zHuSBvuHIKgXtn sYfD9ZW0g0rmapUZIWXRuzCTilula5hWQibjAUIT3Ac1rKcwiDF+pKvPwPRixI097M vaI//BR5X0LUdNUA5FA24PldkudfopfG3+74WR2Jm04sXyM+qxuJbRwyYeY4u4H+6h wpAmYy5eEHfVR06c0DsI5FA7V9ku7Y4kTY9YsviY98A2SGUXZ8+Zh5QMkPATRiYX0O wYejXPC1jGQdu8ZUHvRkMARSvaQ2lRMZEuBVET+BmxqYW0Vtg8SZkUJX2Fhwwno80T FfDXZnRGXIAbg== 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 9B3AFC44506; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Fri, 10 Jul 2026 14:16:42 -0500 Subject: [PATCH v4 2/8] 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: <20260710-ibmvfc-fpin-support-v4-2-ef031ac19520@linux.ibm.com> References: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@linux.ibm.com> In-Reply-To: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@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.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1783711016; l=4233; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=5KXW4HiPzhI1ypiHMLbjy5Mv9KevT3p+ueI1qaFVPf4=; b=YUG4wqho5z8jkmX/DnPcnCNZuTF+R9Cv0kCY2Wj5Uc0N+NZ1y4XOJ7c7s5TWzfCNjflkJzccb q1P5nxU3U8GB3hDbMcoCQmyPADAspGvab3gBSbfoBat+n5gZ5X5BoE1 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.c | 22 ++++++++++++++++++++-- drivers/scsi/ibmvscsi/ibmvfc.h | 23 +++++++++++++---------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index d3fd1d3437c6..a7e3b7ee0683 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1512,7 +1512,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); @@ -3569,6 +3571,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_VFC_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 @@ -4095,7 +4105,15 @@ static void ibmvfc_handle_scrq(struct ibmvfc_crq *cr= q, struct ibmvfc_host *vhost case IBMVFC_CRQ_XPORT_EVENT: 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 (crq->format =3D=3D IBMVFC_VFC_NOOP) + return; + + if (unlikely(!evt)) { + dev_err(vhost->dev, "Received null event\n"); return; } =20 diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index f69e0605a78d..526632cb7237 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -175,11 +175,12 @@ struct ibmvfc_npiv_login { #define IBMVFC_FLUSH_ON_HALT 0x02 __be32 max_cmds; __be64 capabilities; -#define IBMVFC_CAN_MIGRATE 0x01 -#define IBMVFC_CAN_USE_CHANNELS 0x02 -#define IBMVFC_CAN_HANDLE_FPIN 0x04 -#define IBMVFC_CAN_USE_MAD_VERSION 0x08 -#define IBMVFC_CAN_SEND_VF_WWPN 0x10 +#define IBMVFC_CAN_MIGRATE 0x001 +#define IBMVFC_CAN_USE_CHANNELS 0x002 +#define IBMVFC_CAN_HANDLE_FPIN 0x004 +#define IBMVFC_CAN_USE_MAD_VERSION 0x008 +#define IBMVFC_CAN_SEND_VF_WWPN 0x010 +#define IBMVFC_CAN_USE_NOOP_CMD 0x200 __be64 node_name; struct srp_direct_buf async; u8 partition_name[IBMVFC_MAX_NAME]; @@ -221,11 +222,12 @@ struct ibmvfc_npiv_login_resp { #define IBMVFC_NATIVE_FC 0x01 __be32 reserved; __be64 capabilities; -#define IBMVFC_CAN_FLUSH_ON_HALT 0x08 -#define IBMVFC_CAN_SUPPRESS_ABTS 0x10 -#define IBMVFC_MAD_VERSION_CAP 0x20 -#define IBMVFC_HANDLE_VF_WWPN 0x40 -#define IBMVFC_CAN_SUPPORT_CHANNELS 0x80 +#define IBMVFC_CAN_FLUSH_ON_HALT 0x0008 +#define IBMVFC_CAN_SUPPRESS_ABTS 0x0010 +#define IBMVFC_MAD_VERSION_CAP 0x0020 +#define IBMVFC_HANDLE_VF_WWPN 0x0040 +#define IBMVFC_CAN_SUPPORT_CHANNELS 0x0080 +#define IBMVFC_SUPPORT_NOOP_CMD 0x1000 __be32 max_cmds; __be32 scsi_id_sz; __be64 max_dma_len; @@ -621,6 +623,7 @@ struct ibmvfc_trace_entry { enum ibmvfc_crq_formats { IBMVFC_CMD_FORMAT =3D 0x01, IBMVFC_ASYNC_EVENT =3D 0x02, + IBMVFC_VFC_NOOP =3D 0x03, IBMVFC_MAD_FORMAT =3D 0x04, }; =20 --=20 2.55.0 From nobody Sun Jul 26 00:22:09 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 13D3437C908; Fri, 10 Jul 2026 19:16:58 +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=1783711018; cv=none; b=qw4++jE1edGSvKh4x+hz6sztQC7TUE0bGcDhd1F6HECSP3lmVjc+c/crmbx7wNkMFBZvLlSTAVf9FEIgWTgwXqov1pkT1VdB3tuqurra/J48JYZY/C5w6Blv8u51AqW2N03nZhudcCtRwf7kt7q+bY2DhIBxeByAEe5Gwri7Nmg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783711018; c=relaxed/simple; bh=rMLaqrdfziwuC0RZ1ub4p5UStVN916u5G5CxmEpiCKA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Bs4oIM2PyVWQFrVcKTu0/1djnzm6QB73u6094wrKIErAykgu7D5YcWdeZOARbsa3jArB73lRN1P+1CIc3C8eYlCI5k8fvCP4hcKWiLNcmSiQdsQAKmsQMAPdJKBd5AGJfLxg/dz/YkGnGpIc2Z5NnuROeWSAMsirN724SpbjtIY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UZW/lvkF; 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="UZW/lvkF" Received: by smtp.kernel.org (Postfix) with ESMTPS id C4C4AC2BCF4; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1783711017; bh=rMLaqrdfziwuC0RZ1ub4p5UStVN916u5G5CxmEpiCKA=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=UZW/lvkFeQJ4gTbOnUX2o8RpAwDaMcr0ae81ZKtACmxhP7wG/KIOJHXEaRYUy1fPi RHOQp8AgXWBMGBPuZqz1A74JFsucA5avmNIhdtd/zRUvcz+ZWi1NT2nz2Cmib9gn/N 9XAyI1O1OZTDMlZChQgCJLLPYgLb4j9DxL1rtLV0JEaxZsfHcTJJsra5aF18wT/2Xy lIxRGSNavggB6th56zHJXhMtmMJE4tIVl6IyYSB+nv6LimgjqBw+yN4FWYISctB7AP 4BmjM2RxyR18D+l8ktdduU52+UOp71oy22u7gUwX5bHaYMxZVo7DayHLM4mVV6Xmg2 CKvjb2lQ0pwBw== 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 A87AFC44508; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Fri, 10 Jul 2026 14:16:43 -0500 Subject: [PATCH v4 3/8] ibmvfc: make ibmvfc login to fabric 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: <20260710-ibmvfc-fpin-support-v4-3-ef031ac19520@linux.ibm.com> References: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@linux.ibm.com> In-Reply-To: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@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.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1783711016; l=6602; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=dwpZu8Tf7g3wCB01cs6sTJsbVV1BtGJDXqGvQLlA3Fo=; b=9dSlEYZ7rpdF6wJjDaQ1btFowvC5hZ300PQ/FiwQbZjjqOdnfGfBMMgI/Ufm+ovkA+LekKfo1 aFTexd/DPS7Bw10W2D4JOuDsk41533o2tDfey68pnNrsbEuE85o714d 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 fabric login capability to support asynchronous event queue with dedicated interrupt as required by NPIV specification for async sub-queue and full/extended FPIN message support. Implement ibmvfc_fabric_login() to perform fabric login using MAD (Management Adapter Data) format. Add ibmvfc_fabric_login_done() callback to handle login completion, including error handling and retry logic. On successful fabric login, store the assigned N_Port ID in the FC host structure and transition to IBMVFC_HOST_ACTION_QUERY state to continue initialization. Signed-off-by: Dave Marquardt --- drivers/scsi/ibmvscsi/ibmvfc.c | 96 ++++++++++++++++++++++++++++++++++++++= ++-- drivers/scsi/ibmvscsi/ibmvfc.h | 17 ++++++++ 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index a7e3b7ee0683..c95e78d729ed 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -5265,6 +5265,88 @@ static void ibmvfc_discover_targets(struct ibmvfc_ho= st *vhost) ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); } =20 +static void ibmvfc_fabric_login_done(struct ibmvfc_event *evt) +{ + struct ibmvfc_fabric_login *rsp =3D &evt->xfer_iu->fabric_login; + u32 mad_status =3D be16_to_cpu(rsp->common.status); + struct ibmvfc_host *vhost =3D evt->vhost; + int level =3D IBMVFC_DEFAULT_LOG_LEVEL; + + ENTER; + + switch (mad_status) { + case IBMVFC_MAD_SUCCESS: + fc_host_port_id(vhost->host) =3D be64_to_cpu(rsp->nport_id); + ibmvfc_free_event(evt); + break; + + case IBMVFC_MAD_FAILED: + if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), be16_to_cpu(rsp->error))) + level +=3D ibmvfc_retry_host_init(vhost); + else + ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); + ibmvfc_log(vhost, level, "Fabric Login failed: %s (%x:%x)\n", + ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), be16_to_cpu(rsp->erro= r)), + be16_to_cpu(rsp->status), be16_to_cpu(rsp->error)); + ibmvfc_free_event(evt); + LEAVE; + return; + + case IBMVFC_MAD_CRQ_ERROR: + ibmvfc_retry_host_init(vhost); + fallthrough; + + case IBMVFC_MAD_DRIVER_FAILED: + ibmvfc_free_event(evt); + LEAVE; + return; + + default: + dev_err(vhost->dev, "Invalid fabric Login response: 0x%x\n", mad_status); + ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); + ibmvfc_free_event(evt); + LEAVE; + return; + } + + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); + wake_up(&vhost->work_wait_q); + + LEAVE; +} + +static void ibmvfc_fabric_login(struct ibmvfc_host *vhost) +{ + struct ibmvfc_fabric_login *mad; + struct ibmvfc_event *evt; + int level =3D IBMVFC_DEFAULT_LOG_LEVEL; + + if (vhost->scsi_scrqs.protocol !=3D IBMVFC_PROTO_SCSI) { + ibmvfc_log(vhost, level, "Fabric Login failed: unknown protocol\n"); + ibmvfc_hard_reset_host(vhost); + return; + } + + evt =3D ibmvfc_get_reserved_event(&vhost->crq); + if (!evt) { + ibmvfc_log(vhost, level, "Fabric Login failed: no available events\n"); + ibmvfc_hard_reset_host(vhost); + return; + } + + ibmvfc_init_event(evt, ibmvfc_fabric_login_done, IBMVFC_MAD_FORMAT); + mad =3D &evt->iu.fabric_login; + memset(mad, 0, sizeof(*mad)); + mad->common.opcode =3D cpu_to_be32(IBMVFC_FABRIC_LOGIN); + mad->common.version =3D cpu_to_be32(1); + mad->common.length =3D cpu_to_be16(sizeof(*mad)); + + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); + + if (ibmvfc_send_event(evt, vhost, default_timeout)) + ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); +} + static void ibmvfc_channel_setup_done(struct ibmvfc_event *evt) { struct ibmvfc_host *vhost =3D evt->vhost; @@ -5311,8 +5393,12 @@ static void ibmvfc_channel_setup_done(struct ibmvfc_= event *evt) return; } =20 - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); - wake_up(&vhost->work_wait_q); + if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_SCSI)) { + ibmvfc_fabric_login(vhost); + } else { + ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); + wake_up(&vhost->work_wait_q); + } } =20 static void ibmvfc_channel_setup(struct ibmvfc_host *vhost) @@ -5503,9 +5589,11 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_eve= nt *evt) vhost->host->can_queue =3D be32_to_cpu(rsp->max_cmds) - IBMVFC_NUM_INTERN= AL_REQ; vhost->host->max_sectors =3D npiv_max_sectors; =20 - if (ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPORT_CHANNELS) && vhost->do_en= quiry) { + if (ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPORT_CHANNELS) && vhost->do_en= quiry) ibmvfc_channel_enquiry(vhost); - } else { + else if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_SCSI)) + ibmvfc_fabric_login(vhost); + else { vhost->do_enquiry =3D 0; ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); wake_up(&vhost->work_wait_q); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 526632cb7237..adfd67e85af8 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -138,6 +138,7 @@ enum ibmvfc_mad_types { IBMVFC_CHANNEL_ENQUIRY =3D 0x1000, IBMVFC_CHANNEL_SETUP =3D 0x2000, IBMVFC_CONNECTION_INFO =3D 0x4000, + IBMVFC_FABRIC_LOGIN =3D 0x8000, }; =20 struct ibmvfc_mad_common { @@ -180,6 +181,7 @@ struct ibmvfc_npiv_login { #define IBMVFC_CAN_HANDLE_FPIN 0x004 #define IBMVFC_CAN_USE_MAD_VERSION 0x008 #define IBMVFC_CAN_SEND_VF_WWPN 0x010 +#define IBMVFC_YES_SCSI 0x040 #define IBMVFC_CAN_USE_NOOP_CMD 0x200 __be64 node_name; struct srp_direct_buf async; @@ -227,6 +229,7 @@ struct ibmvfc_npiv_login_resp { #define IBMVFC_MAD_VERSION_CAP 0x0020 #define IBMVFC_HANDLE_VF_WWPN 0x0040 #define IBMVFC_CAN_SUPPORT_CHANNELS 0x0080 +#define IBMVFC_SUPPORT_SCSI 0x0200 #define IBMVFC_SUPPORT_NOOP_CMD 0x1000 __be32 max_cmds; __be32 scsi_id_sz; @@ -590,6 +593,19 @@ struct ibmvfc_connection_info { __be64 reserved[16]; } __packed __aligned(8); =20 +struct ibmvfc_fabric_login { + struct ibmvfc_mad_common common; + __be64 flags; +#define IBMVFC_STRIP_MERGE 0x1 +#define IBMVFC_LINK_COMMANDS 0x2 + __be64 capabilities; + __be64 nport_id; + __be16 status; + __be16 error; + __be32 pad; + __be64 reserved[16]; +} __packed __aligned(8); + struct ibmvfc_trace_start_entry { u32 xfer_len; } __packed; @@ -715,6 +731,7 @@ union ibmvfc_iu { struct ibmvfc_channel_enquiry channel_enquiry; struct ibmvfc_channel_setup_mad channel_setup; struct ibmvfc_connection_info connection_info; + struct ibmvfc_fabric_login fabric_login; } __packed __aligned(8); =20 enum ibmvfc_target_action { --=20 2.55.0 From nobody Sun Jul 26 00:22:09 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 13CA3379C36; Fri, 10 Jul 2026 19:16:58 +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=1783711018; cv=none; b=qM0PRzxlRB4f42NrUKlZAS3gHshgaN9pAxAr5sk8eoy/xHrCDZuV+RPqqvVfjNpENz4UlMehTPV1GermL5AIu27TsgUCUJuRlbYCpDINfpUKaRrwwPlo8rPFYMHEQL1swSZNMPUeBeHoLl6eUZy37F4eaawzW/MCNjCEi2eyyoM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783711018; c=relaxed/simple; bh=VRmoMzw5cFwFEWPHaHM9b3BnH1I17iu1gzzZ2adcQcM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uZ7nlzaRnKYMQ0B4/mWKBPXXhCl4zwiQEVYmNUBXf8XylVutW3w728TtRHRaiQGi+vLhbyYVjNYbVr1KnT4A3LRM+E+lr6xt39X+4Fw98+E6KrAWH+15z3WjhYiupj67q15zF+g5u5htxohNySV/hrG7kjWrbhva2Moaa4jwfc4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ojNnmYvd; 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="ojNnmYvd" Received: by smtp.kernel.org (Postfix) with ESMTPS id CF554C2BCF6; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1783711017; bh=VRmoMzw5cFwFEWPHaHM9b3BnH1I17iu1gzzZ2adcQcM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=ojNnmYvd5g5c6dW4iSlI8QgwPP6I73IEkLShM9tdqJF/K5XsxFH0sz0AdHTZ37ZYI XnOcQuESj9+dRmc1N7FhP3D4gEl17U3HgGL7X/xWnGQDnEICkstcJwJpF+VyZMNpBb W3KjiUbAYVIry/0k5oc/yPous+2HX83aeLUcVLISQr1v0Yo8GKWV+crj4ocv8bN515 i0FQlcy9I07YJNta9MjQCQAW9dW2n2Ixn51ABVcwNXCYD32tNMRAqJkrZGdkuHqvNj L5iXibtibPHQYKZ4L9rMVUYudEHUdDkHVbPJQsFmh/oDaf+vzy25Z1lzapXsSXKGk5 me9TlQj3bVf5Q== 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 B6096C44507; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Fri, 10 Jul 2026 14:16:44 -0500 Subject: [PATCH v4 4/8] 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: <20260710-ibmvfc-fpin-support-v4-4-ef031ac19520@linux.ibm.com> References: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@linux.ibm.com> In-Reply-To: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@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.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1783711016; l=2962; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=kg4QY+7DyAccNJ/5aUxRMv0jVr3wd2+MpIkF1ucpAmU=; b=OqwZB7KS0w5NCNlZ8+LMZKF+NyzQfxoVVfmBJvOBZYUuNP/qCbuFsvK292wcbbblRFvWtHcL+ ecbCZcFXRSBDv/THNx744Yl4K0eBIR2dwXEF00gZL4BJuYSwtqm3tup 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 | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index adfd67e85af8..f38dfae9924c 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -182,6 +182,7 @@ struct ibmvfc_npiv_login { #define IBMVFC_CAN_USE_MAD_VERSION 0x008 #define IBMVFC_CAN_SEND_VF_WWPN 0x010 #define IBMVFC_YES_SCSI 0x040 +#define IBMVFC_USE_ASYNC_SUBQ 0x100 #define IBMVFC_CAN_USE_NOOP_CMD 0x200 __be64 node_name; struct srp_direct_buf async; @@ -230,6 +231,7 @@ struct ibmvfc_npiv_login_resp { #define IBMVFC_HANDLE_VF_WWPN 0x0040 #define IBMVFC_CAN_SUPPORT_CHANNELS 0x0080 #define IBMVFC_SUPPORT_SCSI 0x0200 +#define IBMVFC_SUPPORT_ASYNC_SUBQ 0x0800 #define IBMVFC_SUPPORT_NOOP_CMD 0x1000 __be32 max_cmds; __be32 scsi_id_sz; @@ -564,7 +566,7 @@ struct ibmvfc_channel_setup_mad { struct srp_direct_buf buffer; } __packed __aligned(8); =20 -#define IBMVFC_MAX_CHANNELS 502 +#define IBMVFC_MAX_CHANNELS 501 =20 struct ibmvfc_channel_setup { __be32 flags; @@ -579,6 +581,7 @@ struct ibmvfc_channel_setup { struct srp_direct_buf buffer; __be64 reserved2[5]; __be64 channel_handles[IBMVFC_MAX_CHANNELS]; + __be64 async_subq_handle; } __packed __aligned(8); =20 struct ibmvfc_connection_info { @@ -715,6 +718,25 @@ struct ibmvfc_async_work { struct work_struct async_work_s; }; =20 +struct ibmvfc_async_subq { + volatile u8 valid; +#define IBMVFC_ASYNC_ID_IS_ASSOC_ID 0x01 +#define IBMVFC_FC_EEH 0x04 +#define IBMVFC_FC_FW_UPDATE 0x08 +#define IBMVFC_FC_FW_DUMP 0x10 + u8 flags; + u8 link_state; + u8 fpin_status; + __be16 event; + __be16 pad; + volatile __be64 wwpn; + volatile __be64 nport_id; + union { + __be64 node_name; + __be64 assoc_id; + } id; +} __packed __aligned(8); + union ibmvfc_iu { struct ibmvfc_mad_common mad_common; struct ibmvfc_npiv_login_mad npiv_login; @@ -854,6 +876,7 @@ struct ibmvfc_queue { =20 struct ibmvfc_channels { struct ibmvfc_queue *scrqs; + struct ibmvfc_queue *async_scrq; enum ibmvfc_protocol protocol; unsigned int active_queues; unsigned int desired_queues; --=20 2.55.0 From nobody Sun Jul 26 00:22:09 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 30F24383318; Fri, 10 Jul 2026 19:16:58 +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=1783711018; cv=none; b=OWtdW0EDK17h9SfLehyNmK3CwpgerDhVMMC0Hr71yvPTxctfmMj/QsCVMee19H0MGjGM5eEmMnqv4e11aRrratKKN0bZnzVT+MULnYhucafDWYyKIDa+GFjAgeYeR72Hk4gzv0rjZGMLpBSh/cy/h9NaUmTCaSg+0zpvlA/620g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783711018; c=relaxed/simple; bh=TGyZgCVxY7zCWMJhLl/6htn+DkBY8VNoc8ZMkzpRyBY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IWTK0jeswQqRIwEB4A1fB32BNL4bAN9AZWbuVw8zW7A97uhY5rrh6LV/3h10moqZqAH1CiwllxXWt2dd/UQbiZ612ugyHoWg1OVNNK5h4B5X0Ct8ZWMemb/e1+prY5KhSyks11gHiCM34C2o4qnZjj2tjGX+exlVc5uOLO8XhdM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=bFMnNejA; 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="bFMnNejA" Received: by smtp.kernel.org (Postfix) with ESMTPS id DE802C2BCFB; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1783711017; bh=TGyZgCVxY7zCWMJhLl/6htn+DkBY8VNoc8ZMkzpRyBY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=bFMnNejAJht2t5eyztZygG41CckDK464ZrB2nlSbi5fHfMm+5xWbB0zve0F727KD0 05mSC7fkQXgfKnL4aNTkne0SHmAUEOmNNPhXk9GEMD3wLxEuMllLkOMhpC0R3NhD+r sNf3Xec4P9ER4zaOY946hxWD56WeeJ6+w8MZVgl5yPpnclXqtFXYFWVQ4xn9KZ1xjh cqh6d55SMtSNlMZPavSRVwp9UM/L76GkaaKWeqgNY1P/WFQ3RH1ewAJb4OnY+KOirV 5dS99LItP5YKbNqYqEauXqXlxMDtCcDN+PSB+zXpdEJMIDwfK1RP2HOpc6eFuY7/h4 sUQgg9hi3yS5w== 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 C4D23C43458; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Fri, 10 Jul 2026 14:16:45 -0500 Subject: [PATCH v4 5/8] ibmvfc: allocate 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: <20260710-ibmvfc-fpin-support-v4-5-ef031ac19520@linux.ibm.com> References: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@linux.ibm.com> In-Reply-To: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@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.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1783711016; l=3317; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=rBhgYJ2t1uiM0cxoYETJDBMpf2C9qi2TrIr+jFCPyOo=; b=PTTbtttGusvoi9hV+KxMJoAo6D2KQ9TbW26oq2WCfpA5E5An/pJCL9kAUuhRdQluT30am0Rsb l4dQwNx1snrDsgoIxD4z+TTsgC48OTfjxHv/o6XIRK6qA/EYcCT64R7 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 Allocate and initialize the asynchronous sub-queue required for receiving full and extended FPIN events from VIOS. Modify ibmvfc_alloc_channels() to allocate async_scrq using ibmvfc_alloc_queue() with IBMVFC_SUB_CRQ_FMT format. Update error handling to properly clean up async_scrq on allocation failures. Update ibmvfc_channel_setup() to pass async_subq_handle to VIOS during channel setup, and ibmvfc_channel_setup_done() to store the VIOS cookie for the async sub-queue. Modify ibmvfc_release_channels() to free async_scrq resources during cleanup. Signed-off-by: Dave Marquardt --- drivers/scsi/ibmvscsi/ibmvfc.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index c95e78d729ed..586847ff3336 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -5375,6 +5375,9 @@ static void ibmvfc_channel_setup_done(struct ibmvfc_e= vent *evt) for (i =3D 0; i < active_queues; i++) scrqs->scrqs[i].vios_cookie =3D be64_to_cpu(setup->channel_handles[i]); + if (scrqs->async_scrq) + scrqs->async_scrq->vios_cookie =3D + be64_to_cpu(setup->async_subq_handle); =20 ibmvfc_dbg(vhost, "Using %u channels\n", vhost->scsi_scrqs.active_queues); @@ -5425,6 +5428,7 @@ static void ibmvfc_channel_setup(struct ibmvfc_host *= vhost) setup_buf->num_scsi_subq_channels =3D cpu_to_be32(num_channels); for (i =3D 0; i < num_channels; i++) setup_buf->channel_handles[i] =3D cpu_to_be64(scrqs->scrqs[i].cookie); + setup_buf->async_subq_handle =3D cpu_to_be64(scrqs->async_scrq->cookie); } =20 ibmvfc_init_event(evt, ibmvfc_channel_setup_done, IBMVFC_MAD_FORMAT); @@ -6392,6 +6396,17 @@ static int ibmvfc_alloc_channels(struct ibmvfc_host = *vhost, if (!channels->scrqs) return -ENOMEM; =20 + channels->async_scrq =3D kzalloc_obj(*channels->async_scrq, GFP_KERNEL); + if (!channels->async_scrq) { + rc =3D -ENOMEM; + goto free_scrqs; + } + + rc =3D ibmvfc_alloc_queue(vhost, channels->async_scrq, + IBMVFC_SUB_CRQ_FMT); + if (rc) + goto free_async; + for (i =3D 0; i < channels->max_queues; i++) { scrq =3D &channels->scrqs[i]; rc =3D ibmvfc_alloc_queue(vhost, scrq, IBMVFC_SUB_CRQ_FMT); @@ -6400,13 +6415,21 @@ static int ibmvfc_alloc_channels(struct ibmvfc_host= *vhost, scrq =3D &channels->scrqs[j - 1]; ibmvfc_free_queue(vhost, scrq); } - kfree(channels->scrqs); - channels->scrqs =3D NULL; + ibmvfc_free_queue(vhost, channels->async_scrq); channels->active_queues =3D 0; - return rc; + goto free_async; } } =20 + return rc; + +free_async: + kfree(channels->async_scrq); + channels->async_scrq =3D NULL; +free_scrqs: + kfree(channels->scrqs); + channels->scrqs =3D NULL; + return rc; } =20 @@ -6441,8 +6464,15 @@ static void ibmvfc_release_channels(struct ibmvfc_ho= st *vhost, =20 kfree(channels->scrqs); channels->scrqs =3D NULL; + channels->active_queues =3D 0; } + + if (channels->async_scrq) { + ibmvfc_free_queue(vhost, channels->async_scrq); + kfree(channels->async_scrq); + channels->async_scrq =3D NULL; + } } =20 static void ibmvfc_release_sub_crqs(struct ibmvfc_host *vhost) --=20 2.55.0 From nobody Sun Jul 26 00:22:09 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 30FEB383319; Fri, 10 Jul 2026 19:16:58 +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=1783711018; cv=none; b=s7uEqJkR3KT4m4O373h0XHYDW+mnTPapJ0PmyC7WFfciuiwTWfLlrpJlKXwRWlQT++p0YKbznt0ppD3lMIBK5uu0IEkn2v/oTWQLAruewHL5gDBctYMDZgER8umNVl98HG4cyylqtw26VTX69DrS9SJ4+lb5WsL5HZmxsad6UDE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783711018; c=relaxed/simple; bh=XAFeMHuH/cP5MGLyKIUx/Bv8ucc5pV6sKqasBVE6OY8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=f/zXv1vlTSRGp/ulWsMm8PA139qa5U4it9BbvdtBkqNfBItXSnEA8gbB5yeqTWYaZKkQpkEPmkCnVf9R/Df1o2Bp9gxUbFJxYTa//MScgoz2soj/AZYMxL9NkS5QF9eQdLLyBK7g9yylaoMwx4drCmAaBOc5yEYuhbhYQ0rYpjk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uZ9uq2tQ; 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="uZ9uq2tQ" Received: by smtp.kernel.org (Postfix) with ESMTPS id E3B7EC2BCFD; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1783711017; bh=XAFeMHuH/cP5MGLyKIUx/Bv8ucc5pV6sKqasBVE6OY8=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=uZ9uq2tQ56qjUc1NpXRvp7ODJtfzKdw3qU99mmPxiB6i2xdqitHKH9Q8OwUQj9MTl wplwEH/MWzy99+zrb6jXt4qTHSvLtXcOqSu/4kDLgxzs++vkZJ4KSHyURZdWyW/YOY 6fU35dCRKww4Z9jYErY/KFQFNXthgDJparEClu0xAbmWUfajSGC1YJh3lZvxaZ6UD2 h34ex6hFqeDnkiOz9jdhF3ULDjw8XD1DW2vGamxurYRyHIQoxUElVoIR9EDfkW0va1 SP2j7tNa0UeNCa7IRHYIBzbg7DacWDDFSPYDNbTWa+IeQTQdQs5lGBJt91GEWkGSz5 3zzsmlGxBW0PA== 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 D2855C44501; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Fri, 10 Jul 2026 14:16:46 -0500 Subject: [PATCH v4 6/8] 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: <20260710-ibmvfc-fpin-support-v4-6-ef031ac19520@linux.ibm.com> References: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@linux.ibm.com> In-Reply-To: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@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.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1783711016; l=12961; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=Izn3lAfPSO52fLMO7EJWWL7a8c5B/NSSWpmo6t60F/U=; b=6aYICNC7Yfyp9jBBK4yBoULJsX/wg0IVvte37LxVjudgHwxsREESh8MerKUWQeTnwQtjvVGyd LGyDP88OCVUBLXXy5fIi9Im6TBm0GHJSlFu0Z7qyfw0eFkyv9L1RJrY 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.c | 166 +++++++++++++++++++++++++++----= ---- drivers/scsi/ibmvscsi/ibmvfc.h | 17 ++-- drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 10 +-- 3 files changed, 143 insertions(+), 50 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 586847ff3336..ee56f13f1a97 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -3349,6 +3349,27 @@ 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_subq *ibmvfc_fpin) +{ + return ibmvfc_common_fpin_to_desc(ibmvfc_fpin->fpin_status, ibmvfc_fpin->= wwpn, + cpu_to_be16(0), cpu_to_be16(0), + cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD), + cpu_to_be32(1)); +} + /** * ibmvfc_process_async_work - Process IBMVFC_AE_FPIN async CRQ from work = queue * @work: pointer to work_struct @@ -3356,73 +3377,131 @@ ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq = *crq, u64 wwpn) static void ibmvfc_process_async_work(struct work_struct *work) { struct ibmvfc_target *tgt, *next; + struct ibmvfc_async_subq *subq =3D NULL; struct ibmvfc_async_work *aw; - struct ibmvfc_async_crq *crq; + struct ibmvfc_async_crq *crq =3D NULL; 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(work, struct ibmvfc_async_work, async_work_s); - crq =3D &aw->crq; vhost =3D aw->vhost; + is_subq =3D aw->is_subq; + if (is_subq) + subq =3D &aw->crq.subq; + else + crq =3D &aw->crq.async_crq; =20 - if (!crq->scsi_id && !crq->wwpn && !crq->node_name) - goto end; + if (crq) { + wwpn =3D crq->wwpn; + node_name =3D crq->node_name; + scsi_id =3D crq->scsi_id; + } else { + wwpn =3D subq->wwpn; + node_name =3D subq->id.node_name; + scsi_id =3D 0; + } + + if (!scsi_id && !wwpn && !node_name) + goto free; =20 spin_lock_irqsave(vhost->host->host_lock, flags); list_for_each_entry_safe(tgt, next, &vhost->targets, queue) { - 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_nam= e) + if (node_name && cpu_to_be64(tgt->ids.node_name) !=3D node_name) continue; if (!tgt->rport) continue; break; } - spin_unlock_irqrestore(vhost->host->host_lock, flags); + if (!list_entry_is_head(tgt, &vhost->targets, queue)) { + 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; + } =20 - if (list_entry_is_head(tgt, &vhost->targets, queue) || !tgt->rport) { + if (!tgt->rport) { dev_err_ratelimited(vhost->dev, "Invalid target for FPIN\n"); goto end; } =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), (char *)fpin, 0); kfree(fpin); } else - dev_err_ratelimited(vhost->dev, - "FPIN event %u received, unable to process\n", - crq->fpin_status); + dev_err_ratelimited(vhost->dev, "FPIN event received, unable to process\= n"); + end: + kref_put(&tgt->kref, ibmvfc_release_tgt); + free: kfree(aw); } =20 /** * ibmvfc_handle_async - Handle an async event from the adapter - * @crq: crq to process + * @crq: ibmvfc_async_crq or ibmvfc_async_subq * @vhost: ibmvfc host struct + * @is_subq: indicates whether the crq points to a struct ibmvfc_async_subq * **/ -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_subq) { - 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_subq *subq =3D NULL; + const struct ibmvfc_async_desc *desc; + struct ibmvfc_target *tgt, *next; 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_subq) { + 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; @@ -3460,18 +3539,18 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ib= mvfc_async_crq *crq, case IBMVFC_AE_ELS_LOGO: case IBMVFC_AE_ELS_PRLO: case IBMVFC_AE_ELS_PLOGI: - list_for_each_entry(tgt, &vhost->targets, queue) { - if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + list_for_each_entry_safe(tgt, next, &vhost->targets, queue) { + 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); } @@ -3492,16 +3571,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_subq; + if (is_subq) + 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_subq) + subq->valid =3D 0; + else + async_crq->valid =3D 0; + wmb(); } EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_async); =20 @@ -4040,7 +4130,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); } =20 /* Pull all the valid messages off the CRQ */ @@ -4053,7 +4143,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); } else if ((crq =3D ibmvfc_next_crq(vhost)) !=3D NULL) { vio_disable_interrupts(vdev); ibmvfc_handle_crq(crq, vhost, &evt_doneq); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index f38dfae9924c..bbf19220af70 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -712,12 +712,6 @@ struct ibmvfc_async_crq { __be64 reserved; } __packed __aligned(8); =20 -struct ibmvfc_async_work { - struct ibmvfc_host *vhost; - struct ibmvfc_async_crq crq; - struct work_struct async_work_s; -}; - struct ibmvfc_async_subq { volatile u8 valid; #define IBMVFC_ASYNC_ID_IS_ASSOC_ID 0x01 @@ -737,6 +731,15 @@ struct ibmvfc_async_subq { } id; } __packed __aligned(8); =20 +struct ibmvfc_async_work { + struct ibmvfc_host *vhost; + bool is_subq; + union { + struct ibmvfc_async_crq async_crq; + struct ibmvfc_async_subq subq; + } crq; + struct work_struct async_work_s; +}; union ibmvfc_iu { struct ibmvfc_mad_common mad_common; struct ibmvfc_npiv_login_mad npiv_login; @@ -1008,7 +1011,7 @@ struct ibmvfc_host { #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 1c90318b6811..86c1f6daca58 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,8 @@ 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 msleep(500U); @@ -94,9 +95,8 @@ 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); - - msleep(500U); + ibmvfc_handle_async(&crq[0], vhost, false); + 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); --=20 2.55.0 From nobody Sun Jul 26 00:22:09 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 30E7E383316; Fri, 10 Jul 2026 19:16:58 +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=1783711018; cv=none; b=VqJRcVPIW938dp5ee6TV0edjtHEbWmZXeXZ0F817cb6aoj/uq/0FkqJFP/tp/mUKUYbzjqopFhrzMfVfJmI84DsVLq7saDhRYNy2WSjRBgQcXAFExWAuj6uRYBvNc2ChQMGtoxQWWmiicMqAfPhm7JM60WL/MrHt2L1BMjdwLNE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783711018; c=relaxed/simple; bh=HoTZANVNBhElIy1Js9i7uR3wT0HmjZcPLjtO5In60sU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=uVLGXZdhFxZkpzSg7Te38HpDpwuCa2ryPrTzjMUS6df+oY/+nAiEECdYHlCzEWr94amXF+sQGIRdTcT3tl7elysbAgOWKICiSbjw2r6raaWF1R7w2xhFLJxZI8rMeRXupzoeSM8sZ/cqACNcogh/i5y73QW6GQM4JYcpSaixmMA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=lBwi3tJ8; 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="lBwi3tJ8" Received: by smtp.kernel.org (Postfix) with ESMTPS id F22FCC2BD01; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1783711018; bh=HoTZANVNBhElIy1Js9i7uR3wT0HmjZcPLjtO5In60sU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=lBwi3tJ8VKOQBt/vRNkYqqj2zvl5YWSZ1WhUFbmsne4cvv7NFCI5aeB8NR/AAPWIV EcB6Csetvnsoi75x7yMfoeuovZqqMgfOgq9u6tfWZm4BOoF7Rdg+CAfl1qDppI6zB6 fa2PYJAsBTNO8VGwkBfqBxam7TRaTWk1bO3PngnYBEfOaK2vak4BUtdM6SkRp+wC3/ Zo1/KJ7xWy6InCU84kFvFo/w5eygZLCYJmL0VSqmWw2yGtZ+xJ/Bnck7eLbb/m3xSk eA6KOXGAxQ/gVT5AFLKm3Rw+2SncxiCxC8q9tRnTkUNeaAV64HFwlziwSyKLrDFMRW ckWjpgvr/chSQ== 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 E0EF3C44508; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Fri, 10 Jul 2026 14:16:47 -0500 Subject: [PATCH v4 7/8] ibmvfc: register and use asynchronous sub-queue 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: <20260710-ibmvfc-fpin-support-v4-7-ef031ac19520@linux.ibm.com> References: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@linux.ibm.com> In-Reply-To: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@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.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1783711016; l=8570; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=F+5kh6fFm7s8bT5nsWjaPZ1sWtnj5CE0r34/4rUN4f8=; b=Xcpir/Lzq/zbADFE0sOxxRheC4EDNQ3rbHEDRVi0Bb9ngtI+D3W9HsJFNzf6eX/MDl1kTkzXk fJ4JHFCjJ1WDpdUhQUtYIpb1H041mOgEPkYIgx7e8HBxKaolgiophOp 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 Complete async sub-queue integration by setting up interrupt handling, registering the queue as a channel, and enabling its use during NPIV login. Add ibmvfc_interrupt_async_subq() interrupt handler and ibmvfc_drain_async_subq() to process events from the async sub-queue. Refactor ibmvfc_register_channel() into ibmvfc_register_channel_common() to support both regular sub-CRQs and the async sub-queue with different interrupt handlers. Update ibmvfc_set_login_info() to set IBMVFC_CAN_USE_CHANNELS, IBMVFC_YES_SCSI, IBMVFC_USE_ASYNC_SUBQ, and IBMVFC_CAN_HANDLE_FPIN capability bits when channels are enabled, informing VIOS that the client supports async sub-queue and FPIN handling. Register async_scrq during channel initialization and unregister during cleanup. --- drivers/scsi/ibmvscsi/ibmvfc.c | 146 ++++++++++++++++++++++++++++++++++---= ---- 1 file changed, 124 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index ee56f13f1a97..eb786ac24274 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1517,7 +1517,9 @@ static void ibmvfc_set_login_info(struct ibmvfc_host = *vhost) IBMVFC_CAN_USE_NOOP_CMD); =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_CAN_USE_CHANNELS | IBMVFC_YES_SCSI | + IBMVFC_USE_ASYNC_SUBQ | IBMVFC_CAN_HANDLE_FPIN); =20 login_info->async.va =3D cpu_to_be64(vhost->async_crq.msg_token); login_info->async.len =3D cpu_to_be32(async_crq->size * @@ -4243,6 +4245,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_asyncq - 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; @@ -6340,14 +6388,29 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhos= t) return retrc; } =20 -static int ibmvfc_register_channel(struct ibmvfc_host *vhost, - struct ibmvfc_channels *channels, - int index) +/** + * ibmvfc_register_channel_common - Register a sub-CRQ with the hypervisor + * @vhost: ibmvfc host struct + * @channels: ibmvfc channels struct + * @scrq: sub-CRQ to register + * @index: channel index (negative for async) + * @irq: interrupt handler for the sub-CRQ + * + * Return value: + * 0 on success / non-zero on failure + **/ +static int ibmvfc_register_channel_common(struct ibmvfc_host *vhost, + struct ibmvfc_channels *channels, + struct ibmvfc_queue *scrq, + int index, + irq_handler_t irq) { struct device *dev =3D vhost->dev; struct vio_dev *vdev =3D to_vio_dev(dev); - struct ibmvfc_queue *scrq =3D &channels->scrqs[index]; + long hcall_rc; int rc =3D -ENOMEM; + const char *name_suffix; + bool is_async =3D (index < 0); =20 ENTER; =20 @@ -6366,20 +6429,19 @@ 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[%s] irq\n", "async"); + else + dev_err(dev, "Error mapping sub-crq[%d] irq\n", index); 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; + name_suffix =3D "scsi"; 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; + name_suffix =3D "nvmf"; break; default: dev_err(dev, "Unknown channel protocol (%d)\n", @@ -6387,35 +6449,63 @@ static int ibmvfc_register_channel(struct ibmvfc_ho= st *vhost, goto irq_failed; } =20 + if (is_async) { + snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-%s%s", + vdev->unit_address, name_suffix, "async"); + scrq->handler =3D irq; + } else { + snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-%s%d", + vdev->unit_address, name_suffix, index); + scrq->handler =3D irq ? irq : ibmvfc_interrupt_mq; + scrq->hwq_id =3D index; + } + 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[%s] irq\n", "async"); + else + dev_err(dev, "Couldn't register sub-crq[%d] irq\n", index); irq_dispose_mapping(scrq->irq); goto irq_failed; } =20 - scrq->hwq_id =3D index; - LEAVE; return 0; =20 irq_failed: do { - rc =3D plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address, scrq->cook= ie); - } while (rc =3D=3D H_BUSY || H_IS_LONG_BUSY(rc)); + hcall_rc =3D plpar_hcall_norets(H_FREE_SUB_CRQ, vdev->unit_address, scrq= ->cookie); + } while (hcall_rc =3D=3D H_BUSY || H_IS_LONG_BUSY(hcall_rc)); reg_failed: LEAVE; return rc; } =20 +static int ibmvfc_register_channel_async(struct ibmvfc_host *vhost, + struct ibmvfc_channels *channels, + struct ibmvfc_queue *scrq, + irq_handler_t irq) +{ + return ibmvfc_register_channel_common(vhost, channels, scrq, -1, irq); +} + +static int ibmvfc_register_channel(struct ibmvfc_host *vhost, + struct ibmvfc_channels *channels, + int index) +{ + struct ibmvfc_queue *scrq =3D &channels->scrqs[index]; + + return ibmvfc_register_channel_common(vhost, channels, scrq, index, NULL); +} + static void ibmvfc_deregister_channel(struct ibmvfc_host *vhost, struct ibmvfc_channels *channels, - int index) + struct ibmvfc_queue *scrq) { struct device *dev =3D vhost->dev; struct vio_dev *vdev =3D to_vio_dev(dev); - struct ibmvfc_queue *scrq =3D &channels->scrqs[index]; long rc; =20 ENTER; @@ -6430,7 +6520,7 @@ static void ibmvfc_deregister_channel(struct ibmvfc_h= ost *vhost, } 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); + dev_err(dev, "Failed to free sub-crq[%s]: rc=3D%ld\n", scrq->name, rc); =20 /* Clean out the queue */ memset(scrq->msgs.crq, 0, PAGE_SIZE); @@ -6448,10 +6538,21 @@ static void ibmvfc_reg_sub_crqs(struct ibmvfc_host = *vhost, if (!vhost->mq_enabled || !channels->scrqs) return; =20 + if (ibmvfc_register_channel_async(vhost, channels, + channels->async_scrq, + ibmvfc_interrupt_async_subq)) { + vhost->do_enquiry =3D 0; + return; + } + 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, &channels->scrqs[j - 1]); + ibmvfc_deregister_channel(vhost, channels, + channels->async_scrq); + vhost->do_enquiry =3D 0; return; } @@ -6470,7 +6571,8 @@ static void ibmvfc_dereg_sub_crqs(struct ibmvfc_host = *vhost, return; =20 for (i =3D 0; i < channels->max_queues; i++) - ibmvfc_deregister_channel(vhost, channels, i); + ibmvfc_deregister_channel(vhost, channels, &channels->scrqs[i]); + ibmvfc_deregister_channel(vhost, channels, channels->async_scrq); =20 LEAVE; } --=20 2.55.0 From nobody Sun Jul 26 00:22:09 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 3169238331E; Fri, 10 Jul 2026 19:16:58 +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=1783711018; cv=none; b=gZPz6MbKtbJ99eibfkjeQvnPgJwhF+fvHn/uBLJ6nvSuyPcWKx1GxMKtHnLBO+GTc9e2PJs77+Hf7Cwmx/sGFkqO5cySLEoIwqpmUdpFLAP7kTER+YLwcLWLXZhLEN8wolisDwutBFKXkGmw9CrMGPXgp5fSgqma1rfJIL6cs+0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783711018; c=relaxed/simple; bh=u/SqNHlLtelJIM+sUm7JWGJTBEXONhY5otW+C0d4glE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=oeWwPSEG8+K6Tndno/PMUBEhzJ9GIn1uL7N0g6M2+Q4ncuqzSupI1bbKXjvmclIONO2JhzcnQ2IThuN2EG0LO9oTSfgdaVVMYNKjgyZkvcCAm1u3CQ0VwP/dzCAwQCTElhbFnyfW92a7w7nz59inqcNFzprKkeSoq6hkAuviOgM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MPnRQWr8; 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="MPnRQWr8" Received: by smtp.kernel.org (Postfix) with ESMTPS id 0CD12C2BD04; Fri, 10 Jul 2026 19:16:58 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1783711018; bh=u/SqNHlLtelJIM+sUm7JWGJTBEXONhY5otW+C0d4glE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=MPnRQWr8OCNUVVVTwWE2HGIg9zF4buHUjhE0wEEud90hZKHEdrQx3hcnMEuXA5jBG i7zGgikf4HZC6nPjuZeiV4Si/nGplGB8L47QEQInfSA5hopPFJr4uB/cR6ROJ9DMM5 9lcJdoirHKWDRDQ0xTfZSRqq1Y4lzDzP4cH715jFKOfYGENd5MPTSV8tJsllRLpN3X q/X8z5ZSrS5RRWZmeNvGt62g6TmImXr6iesjVBmoeVkOB9Rh6WJH74UYDeV3i8RWyp rH8ZkB3pQUTh4qT+rE2Iz33EtNwGpvUQQcIleLdDVbZhH4dXCpmQPZ/MjDmyldYDwy 1XoHagHjx0QAA== 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 EE20AC44507; Fri, 10 Jul 2026 19:16:57 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Fri, 10 Jul 2026 14:16:48 -0500 Subject: [PATCH v4 8/8] 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: <20260710-ibmvfc-fpin-support-v4-8-ef031ac19520@linux.ibm.com> References: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@linux.ibm.com> In-Reply-To: <20260710-ibmvfc-fpin-support-v4-0-ef031ac19520@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.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1783711016; l=11738; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=pj4Y25GEYFp93UIxhXkut3uKby4jNRsFyEIqSOdPQgY=; b=WpmjpZ6DXhYV4H23QVt/2vLT4jLpZsmq3WjqP2koFdMjoWGUNEpTORvTDh14UhChIuFQb1fK0 l3gOl50WHMPCGqbta1mU93y0YsUmcIWCEaAR4mEPFAkkRS6ZVdKyDLT 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.c | 55 ++++++++++++++++- drivers/scsi/ibmvscsi/ibmvfc.h | 31 ++++++++++ drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 114 +++++++++++++++++++++++++++++++= +++- 3 files changed, 194 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index eb786ac24274..b131a4a3041b 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1519,7 +1519,8 @@ static void ibmvfc_set_login_info(struct ibmvfc_host = *vhost) if (vhost->mq_enabled || vhost->using_channels) login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_USE_CHANNELS | IBMVFC_YES_SCSI | - IBMVFC_USE_ASYNC_SUBQ | IBMVFC_CAN_HANDLE_FPIN); + IBMVFC_USE_ASYNC_SUBQ | IBMVFC_CAN_HANDLE_FPIN | + IBMVFC_CAN_HANDLE_FPIN_EXT); =20 login_info->async.va =3D cpu_to_be64(vhost->async_crq.msg_token); login_info->async.len =3D cpu_to_be32(async_crq->size * @@ -3372,12 +3373,48 @@ ibmvfc_full_fpin_to_desc(struct ibmvfc_async_subq *= 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_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_subq_fpin *sqfpin; struct ibmvfc_target *tgt, *next; struct ibmvfc_async_subq *subq =3D NULL; struct ibmvfc_async_work *aw; @@ -3439,8 +3476,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 bbf19220af70..d9ee270e0ef9 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -184,6 +184,7 @@ struct ibmvfc_npiv_login { #define IBMVFC_YES_SCSI 0x040 #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]; @@ -233,6 +234,7 @@ struct ibmvfc_npiv_login_resp { #define IBMVFC_SUPPORT_SCSI 0x0200 #define IBMVFC_SUPPORT_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; @@ -715,6 +717,7 @@ struct ibmvfc_async_crq { struct ibmvfc_async_subq { volatile u8 valid; #define IBMVFC_ASYNC_ID_IS_ASSOC_ID 0x01 +#define IBMVFC_ASYNC_IS_FPIN_EXT 0x02 #define IBMVFC_FC_EEH 0x04 #define IBMVFC_FC_FW_UPDATE 0x08 #define IBMVFC_FC_FW_DUMP 0x10 @@ -731,6 +734,34 @@ struct ibmvfc_async_subq { } 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 86c1f6daca58..2f43916b43a5 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" @@ -62,8 +63,6 @@ static void ibmvfc_async_fpin_test(struct kunit *test) msleep(1U); } =20 - msleep(500U); - 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); @@ -116,8 +115,117 @@ static void ibmvfc_async_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->num_targets, 1, "No targets"); + + tgt =3D list_first_entry(&vhost->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_SLOW(ibmvfc_async_fpin_test), + KUNIT_CASE(ibmvfc_async_fpin_test), + KUNIT_CASE(ibmvfc_extended_fpin_test), {}, }; =20 --=20 2.55.0