From nobody Mon Jun 15 06:29:39 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 01C4F3E00B4; Mon, 8 Jun 2026 18:30:24 +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=1780943425; cv=none; b=XLrvvVwboH/TcEM9439H8NJfxBSGrLtBVQbQUQdijVFoYmlDBZm11fop4rxPPEnF5j1V55GoRzOAsHgs/rMhHwRadCskXZo5iZ9NSB3wFz7EK4WTEX1LA4wbr03VMxIx+uBSzusmNOCXddkGUAZ3O8gWFCsoCVGIz+zG2uuFGsE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780943425; c=relaxed/simple; bh=We7++qIlJ2bDKKYE9D3A4NDw+A++vkMrFgNfJcxgoQQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rjyHcy8nk9g+yasZ487xIP6qLgiuvHvobAdYm9K0bZT0U5QU3s46Uwc6iruHx39xqL3ycph/EM8LX6mXuNabOwK6OZzPIhl51+I+yP3mGW4FTvDgjCJqjcrPWBKaiBZhh5ErfHQ/9M94Adpu0Wfh/aSEK48wHINb61NG6eL9WWY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=U/VPWKyh; 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="U/VPWKyh" Received: by smtp.kernel.org (Postfix) with ESMTPS id 9EED2C4AF0E; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1780943424; bh=We7++qIlJ2bDKKYE9D3A4NDw+A++vkMrFgNfJcxgoQQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=U/VPWKyhe4qzIDFy9AhBONygTYY5Vo999o5LAn+bTfAeSJp7/c6QCooQD7hTQ6XYW Nb+Q80ME71+rkLhhP19+KCL3/l0mVH2tCEVYa5wUHQwEmIcP6AwomZRlhuMjwHd72C JaVdhLZRaxguPUi+8mMVbpagVDyl4onQ0byhwlEhTo4qT9MXClehgFSGqrT9snAcC7 1byNnqVb+bPCBBotLkjPAgNpm1L0QYz16Gr7veow7ClwYKD4WnF7ikFp7h+DehbASn S9bnpmMRUCEMkcTHV/sGC5EUYcXykzQoEkQy6oQCeFe75UhBphCfdtwzbV1NM+LdKE w0i8ivzCggqhA== 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 8F691CD8C9F; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 08 Jun 2026 13:30:16 -0500 Subject: [PATCH v2 1/7] 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: <20260608-ibmvfc-fpin-support-v2-1-d41f540fba5c@linux.ibm.com> References: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@linux.ibm.com> In-Reply-To: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@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=1780943423; l=18791; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=hfU7B2ZSe7sYtc82dqcGd+sEwO/buKXq1Mj8/7vpJlU=; b=OOhwNV1jvLLExBH8Q3z84/fBOprPvOIzau0Kim0S3JMSAgX03TckrLHvSNVfeaJTadyFCyIka eKyYJyWZur3ArZcmxgR9HWMxb2DJa7Ob5lLeeAT2HHSZmNEHR39pu5t 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 basic FPIN messages to the ibmvfc driver. This includes - adding FPIN handling support to the async event handler - offloading processing of FPIN messages to a work queue - converting the VIOS FPIN message to a struct fc_els_fpin as used by the Linux kernel - passing the converted struct fc_els_fpin to fc_host_fpin_rcv for processing The FPIN message conversion routines include a common routine that will also be used in patches 6 and 7, which add full and extended FPIN support. --- drivers/scsi/Kconfig | 10 ++ drivers/scsi/ibmvscsi/Makefile | 1 + drivers/scsi/ibmvscsi/ibmvfc.c | 226 +++++++++++++++++++++++++++++++= +++- drivers/scsi/ibmvscsi/ibmvfc.h | 15 +++ drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 131 ++++++++++++++++++++ 5 files changed, 379 insertions(+), 4 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..9e5f0c0f0369 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,17 +3189,211 @@ 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 modifier, + __be32 period, __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 =3D=3D 0) + return NULL; + + fpin =3D kzalloc(size, GFP_KERNEL); + if (fpin =3D=3D NULL) + 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)); + if (fpin_status =3D=3D IBMVFC_AE_FPIN_CONGESTION_CLEARED) + cdesc->event_type =3D cpu_to_be16(FPIN_CONGN_CLEAR); + else + cdesc->event_type =3D cpu_to_be16(FPIN_CONGN_DEVICE_SPEC); + cdesc->event_modifier =3D modifier; + cdesc->event_period =3D 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(FC_TLV_DESC_LENGTH_FROM_SZ(*pdesc)); + if (fpin_status =3D=3D IBMVFC_AE_FPIN_PORT_CLEARED) + pdesc->event_type =3D cpu_to_be16(FPIN_CONGN_CLEAR); + else + pdesc->event_type =3D cpu_to_be16(FPIN_CONGN_DEVICE_SPEC); + pdesc->event_modifier =3D modifier; + pdesc->event_period =3D period; + pdesc->detecting_wwpn =3D cpu_to_be64(0); + 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(FC_TLV_DESC_LENGTH_FROM_SZ(*ldesc)); + ldesc->event_type =3D cpu_to_be16(FPIN_LI_UNKNOWN); + ldesc->event_modifier =3D modifier; + ldesc->event_threshold =3D threshold; + ldesc->event_count =3D event_count; + ldesc->detecting_wwpn =3D cpu_to_be64(0); + 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) +{ + return ibmvfc_common_fpin_to_desc(crq->fpin_status, cpu_to_be64(wwpn), + cpu_to_be16(0), + cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD), + 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_async_work *aw; + struct ibmvfc_async_crq *crq; + struct ibmvfc_target *tgt; + struct ibmvfc_host *vhost; + struct fc_els_fpin *fpin; + + 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; + list_for_each_entry(tgt, &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; + 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: + crq->valid =3D 0; + + 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; + bool clear_valid =3D true; =20 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), @@ -3269,11 +3467,27 @@ 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) { + clear_valid =3D false; + INIT_WORK(&aw->async_work_s, ibmvfc_process_async_work); + aw->vhost =3D vhost; + aw->crq =3D crq; + schedule_work(&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; } + + if (clear_valid) + crq->valid =3D 0; } +EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_async); =20 /** * ibmvfc_handle_crq - Handles and frees received events in the CRQ @@ -3803,7 +4017,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 @@ -3818,7 +4031,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); @@ -6603,5 +6815,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..8eb1493cbac8 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; @@ -953,4 +963,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..e41e2a49e549 --- /dev/null +++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c @@ -0,0 +1,131 @@ +// 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(); + KUNIT_ASSERT_FALSE_MSG(test, list_empty(headp), "No ibmvfc devices availa= ble\n"); + 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.54.0 From nobody Mon Jun 15 06:29:39 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 01BBE3E00B0; Mon, 8 Jun 2026 18:30:24 +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=1780943425; cv=none; b=iGwIkvnkcOJ/yDYW1JKRx8LkcrssnAWwATjm/zbYJ+1ZWu7uJauX1gMfyxqs4Ibq9N2aQ4j5aTex/2go2LR8IiKJssjrwGyli2ztGxiOhIHFYi1uSZV5kaxQxiA313uQXT85ufq3x3jLyf36w6gGIGXcO2Vp+CNge9Sq7Ue2QDA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780943425; c=relaxed/simple; bh=syQ2Gyfc9rjR++Qbi/B4XF6b6fWOAKQxLqM1f57Ohlw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bKyHzphh5bOnuw52wFudpnxixFQncE8LOl+0Wrn62hV43/aWY2FAwjrrvsCCg8DGnXjplzLvPjG7vzdgWTU/XsG6rQ0g4rOxANomd2ZE3giHD/uFOWsr9seoIA1ZQsDwo9yzqoYWte1FN5p2cma10Q5Jomr9rK9wGwowORkyPkg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jkT/QsPt; 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="jkT/QsPt" Received: by smtp.kernel.org (Postfix) with ESMTPS id B22DEC4AF0F; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1780943424; bh=syQ2Gyfc9rjR++Qbi/B4XF6b6fWOAKQxLqM1f57Ohlw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=jkT/QsPt64fc0GVg3HR+FVFRCf3Jm/T+AlX3p7nnpGtRnkabla6vYZsA65iuzIzu1 wmjySUNAMQjNXaW5Ju9+CPIwoGBO8+pyBCuSwXLjS01xSsb7/6moGIm6R8k/FhQUYs 9kgRxz6JGR9TIsUZ0cQ2WO8jVfj10Tm9NDXRESt8bDxYXr2ZiKUUWyuesv0356Q9qs 11en16v+KFndvm6d+rE5O04SPZ5JbCaGIJvtKciAtOrWf0LiK30ewSTwM22LxoxKl8 pAgSt8Q5coIbdart0BLfRX2t9DqW4QzSiGAvPY+qUPoGBE61vyR8MKuqZLvozKTNml ZHO6UoUrLigUg== 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 A296BCD8CA7; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 08 Jun 2026 13:30:17 -0500 Subject: [PATCH v2 2/7] 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: <20260608-ibmvfc-fpin-support-v2-2-d41f540fba5c@linux.ibm.com> References: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@linux.ibm.com> In-Reply-To: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@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=1780943423; l=2828; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=Yeji3bKeI5rUvEPYFGrDZIoKZAiKRNWAIVzz/y+TjH0=; b=VISqN10F2dbrQ3+yRvqjDLLI5tfZWHem+gzHw4ZulDCgFQqdO7n8bKyUJjNaJT/w2R0JwFRuZ zMo+gv4n7MCDyDj7KGi9yUX0Rp4cpQcXwOux1E1k70ri4LDTb6+kP0z 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 This patch adds support for receiving and recognizing VFC_NOOP messages from VIOS. This is done by - defining the VFC_NOOP CRQ format - recognizing the VFC_NOOP CRQ format in the CRQ handler. If the VIOS has not provided the "support VFC_NOOP" bit in its capabilities on NPIV login, note that the VFC_NOOP is unexpected - setting the "can use VFC_NOOP" bit in the capabilities sent during NPIV login --- drivers/scsi/ibmvscsi/ibmvfc.c | 11 ++++++++++- drivers/scsi/ibmvscsi/ibmvfc.h | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 9e5f0c0f0369..88386d7c9106 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); @@ -3555,6 +3557,13 @@ 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 (!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 diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 8eb1493cbac8..dd26248cac3e 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -180,6 +180,7 @@ struct ibmvfc_npiv_login { #define IBMVFC_CAN_HANDLE_FPIN 0x04 #define IBMVFC_CAN_USE_MAD_VERSION 0x08 #define IBMVFC_CAN_SEND_VF_WWPN 0x10 +#define IBMVFC_CAN_USE_NOOP_CMD 0x200 __be64 node_name; struct srp_direct_buf async; u8 partition_name[IBMVFC_MAX_NAME]; @@ -226,6 +227,7 @@ struct ibmvfc_npiv_login_resp { #define IBMVFC_MAD_VERSION_CAP 0x20 #define IBMVFC_HANDLE_VF_WWPN 0x40 #define IBMVFC_CAN_SUPPORT_CHANNELS 0x80 +#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.54.0 From nobody Mon Jun 15 06:29:39 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 F2AD32C11E6; Mon, 8 Jun 2026 18:30:24 +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=1780943425; cv=none; b=DBJF1al2yhYoHtn/VFrQ7HrN/9M+zNByDH3T4R4MFliEBa8OB9DqxkLpDIwZjVZX5TWdQdwwWpNHyiiFI+/dmlRp/mkC/yymoatbZiVc8GrbdZPAcjg/KoB5pT86NZxUcFYY79CRfYH5wqKSkIroqYkuduZ3MpapDMKBiNVf9Ns= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780943425; c=relaxed/simple; bh=nZPnoI2bjNTs99OsS4ljVmW8rN9gSm70RyOdyJ/2g5c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jksDhY8imyUBpXeD2anDXG4IL3aF1KG0r+FI9EaAEvNC2Iap3lsZEjD6iCyv6xBvIDbh2xMGAGTHQXRkDW0/+IHJkoaNM2yCTZL/uUFKUNNd2tVVqobKs0B1Vj5ldzTzPT8GabVGHZ9QF0A+xS8AwyKLTFud2swPNW0wecwIL8U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=tt3RAubG; 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="tt3RAubG" Received: by smtp.kernel.org (Postfix) with ESMTPS id BC60CC2BCB9; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1780943424; bh=nZPnoI2bjNTs99OsS4ljVmW8rN9gSm70RyOdyJ/2g5c=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=tt3RAubGpy+WekPN8OTQfqZA43olbbsyRM/SZ4O+1kctjxx4JADXRoH3pmX172KX6 cTVuALOzno4ITn4ECRsTkkkDxGhVxLmNjZZXivJDIXh/iFz1Dt+FC5GWEX54cnfzU+ TZ22PgpU7ZqkUfeKigf39jbowZhk09UMtUt0jCwtJFKsXtLkQAtR65b2AvJdFLbevV QTP9BDyQNgKEJaUUM7SrANN7OIaCPk2Cij2lFQM2nr43PafVxku29g5aUwuqMrfXQg Pi4HAZ1aFssL+VXJ2X1e/utPBMFzB34D1u0SoL5Ls+0ACl4gVHEc7IFa3MmO2eXhtB pPrhUCBmWr18A== 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 B41ACCD6E79; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 08 Jun 2026 13:30:18 -0500 Subject: [PATCH v2 3/7] 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: <20260608-ibmvfc-fpin-support-v2-3-d41f540fba5c@linux.ibm.com> References: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@linux.ibm.com> In-Reply-To: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@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=1780943423; l=5878; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=0mN8HnDhMnJNVlV5l4t+QmjOxydG3CBgcYKoM9KofFM=; b=WQIoqOr+bBgsgDM+aspnPNcu/zbwbGDbr9SgBohAsOGyHA0lSuvZCxeBY2dkx9mD96sZNWm+P vAqakpklsv3CjhTRQ8hHofw/jy0TMtstA+SmvCnNAmt6S+DP9oYX0Yr 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 fabric login in order to support the asynchronous event queue with its own interrupt as required by NPIV specification to support the asynchronous sub-queue and interrupt in order to support full and extended FPIN messages. --- drivers/scsi/ibmvscsi/ibmvfc.c | 94 ++++++++++++++++++++++++++++++++++++++= ++-- drivers/scsi/ibmvscsi/ibmvfc.h | 16 +++++++ 2 files changed, 106 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 88386d7c9106..a18861808325 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -5244,6 +5244,86 @@ 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 =3D ibmvfc_get_reserved_event(&vhost->crq); + int level =3D IBMVFC_DEFAULT_LOG_LEVEL; + + 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)); + if (vhost->scsi_scrqs.protocol =3D=3D IBMVFC_PROTO_SCSI) + mad->common.opcode =3D cpu_to_be32(IBMVFC_FABRIC_LOGIN); + else { + ibmvfc_log(vhost, level, "Fabric Login failed: unknown protocol\n"); + return; + } + 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; @@ -5290,8 +5370,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) @@ -5482,9 +5566,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 dd26248cac3e..c996b36d335d 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 { @@ -227,6 +228,7 @@ struct ibmvfc_npiv_login_resp { #define IBMVFC_MAD_VERSION_CAP 0x20 #define IBMVFC_HANDLE_VF_WWPN 0x40 #define IBMVFC_CAN_SUPPORT_CHANNELS 0x80 +#define IBMVFC_SUPPORT_SCSI 0x200 #define IBMVFC_SUPPORT_NOOP_CMD 0x1000 __be32 max_cmds; __be32 scsi_id_sz; @@ -590,6 +592,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 +730,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.54.0 From nobody Mon Jun 15 06:29:39 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 01A0D3D564B; Mon, 8 Jun 2026 18:30:24 +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=1780943425; cv=none; b=UICj2R54mkqnQXNxl8NLWFXIyDgYbUyVBhBJ6lZ6iCXkHRKiVN+Qihx8IX8U3nCMFHDeJ9eryTJ+7l3kjz34YwkZaEKkpZl9BaE96tXSuWXanS9BtB7Bp07h5a7RRa9mRtht3mkvtfkeP5XXlAbZua4DKIJOnsupuxaInCwckTI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780943425; c=relaxed/simple; bh=WN/uN4JdRNJqo5v7zBaxw2Rc3Vdl8fe2Ys3xy2D3LPc=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YJpMvpzJOplVFUiaLGGbcHH/kO47IYXQ0Tn1h2dlayl3sdAgRM+EV5eGrpMXowFayE94xd7Y2ObXf/Fz+lGW+v9HIhQwdCXGKR0dZ3Ecq6i1G4qhXkUpwNJ1hZVeLA1DHPkC7sDKR91me03jxWHNQKaLKp2BMjZD7RErXmuM0kY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=J379PECU; 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="J379PECU" Received: by smtp.kernel.org (Postfix) with ESMTPS id CAA07C4AF13; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1780943424; bh=WN/uN4JdRNJqo5v7zBaxw2Rc3Vdl8fe2Ys3xy2D3LPc=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=J379PECUfuqCe33XlMQCTJscX9efWVmAcjxTnUBdzqbFk0O4ETRy0X0ktHBe3MPFZ HPnhx+vUFAmwhdBjacYKtkQ18jFFyaXGO62Zz9hdlsb0WC25H/Xx56tvKOoGvIiRfH BhGn4dJE8u/CdWvWQ4njJAzCdR4e8fgKca8vIMTuz2maI9mYKC7/bF4HRLK0Nbbmyu LRN4iGnRMuuzCpmaDJ//5e8rGwGN4BBIHZftUq+oS9R+UyWW8oZ0hvihxFUY5+usUS aW+VenLxoRYU6V5/7TpwZvdZ+nV9r7xaQGh7z18Jl2SylIb1pQecF50RMveM5TbZV0 4cZXf379VhbPQ== 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 C7046CD8CAA; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 08 Jun 2026 13:30:19 -0500 Subject: [PATCH v2 4/7] 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: <20260608-ibmvfc-fpin-support-v2-4-d41f540fba5c@linux.ibm.com> References: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@linux.ibm.com> In-Reply-To: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@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=1780943423; l=2517; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=yA6tb5h9yHjsRv3RYlRjKBFZQlRZRIaWtxJ2hzF2GyA=; b=0zrGohOtPsnfaeBPgoDs9nTfdpfFnt/2uEoXKfYHbtytnom9kUeHBoNyfjGEzkpQAB30mVgTd HQfrSUFgk4/B0+KYMqQGg8fth2alskc6gW6XrA6ROFh1/+31hSzAJCM 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 Adds the asynchronous sub-queue structure, modifies the existing channel setup structure, adds the asynchronous sub-queue to the channels structure, and adds flags needed to tell VIOS to use the sub-queue. --- drivers/scsi/ibmvscsi/ibmvfc.h | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index c996b36d335d..f026f30f98d3 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -181,6 +181,8 @@ struct ibmvfc_npiv_login { #define IBMVFC_CAN_HANDLE_FPIN 0x04 #define IBMVFC_CAN_USE_MAD_VERSION 0x08 #define IBMVFC_CAN_SEND_VF_WWPN 0x10 +#define IBMVFC_YES_SCSI 0x40 +#define IBMVFC_USE_ASYNC_SUBQ 0x100 #define IBMVFC_CAN_USE_NOOP_CMD 0x200 __be64 node_name; struct srp_direct_buf async; @@ -229,6 +231,7 @@ struct ibmvfc_npiv_login_resp { #define IBMVFC_HANDLE_VF_WWPN 0x40 #define IBMVFC_CAN_SUPPORT_CHANNELS 0x80 #define IBMVFC_SUPPORT_SCSI 0x200 +#define IBMVFC_SUPPORT_ASYNC_SUBQ 0x800 #define IBMVFC_SUPPORT_NOOP_CMD 0x1000 __be32 max_cmds; __be32 scsi_id_sz; @@ -563,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; @@ -578,6 +581,7 @@ struct ibmvfc_channel_setup { struct srp_direct_buf buffer; __be64 reserved2[5]; __be64 channel_handles[IBMVFC_MAX_CHANNELS]; + __be64 asyncSubqHandle; } __packed __aligned(8); =20 struct ibmvfc_connection_info { @@ -714,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; @@ -853,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.54.0 From nobody Mon Jun 15 06:29:39 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 2D19B3E0C41; Mon, 8 Jun 2026 18:30:25 +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=1780943425; cv=none; b=fwr1GnMuFbzPGv8U2KBUBTQLZhMDuU8PWscxq4jrVClpQjcDen91jXM+40ZB7aHbbd0l9Kmju4cVjclESCHPE7y8Jx0ENsPq2KOO2Xus1Lyd2Tw+EiW5ZkIfsAQfP0f8Giz0rmS5Z3SEBxSxadvL4WfXZs8QuqLGKn/kXknU2yU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780943425; c=relaxed/simple; bh=8/EY0NOHHy8eX+qz/4HA9u/TVExATrYs5NIzD8L0QTg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KCxZlJSYzSpMzO67q+pV893WxHR1MgyCzUI3ZZouc01P+pcLWXgb0R10+kKA/lI4VkjKvSb8JOOH/SF2SpHSevQwx/NWQ9aBShne0h2DgISyqwFw0wrBRpRL2k1M/fB9XJoU+L0IWI09BzfHhbX7Sz7MO1zS+N0tXMF/lCYSNiw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Hta6CqAh; 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="Hta6CqAh" Received: by smtp.kernel.org (Postfix) with ESMTPS id E4063C4AF17; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1780943424; bh=8/EY0NOHHy8eX+qz/4HA9u/TVExATrYs5NIzD8L0QTg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=Hta6CqAhxsPBf4gwMV+sT8kL7RxymxnRgab/ME5l3Pe+NS0s5IAKXTxtsR4r6VvNt IU3GMsL4P7c4xRdgJEnJww3FcbNe76QYxYtlWiyYvIJsyUY8jkkM171o+YVTCKCY6g EsRBBr6tgBYmi3UEPWw2tGqhoGuLHWvkv+l6DRTcTjvsbGuJykMAJ0M3tRWTuABiQH rLZcJFIg6V4IjQHnUfQuSCdIvMO3bJXYfY1VUWslKc2kNnb9LvF/vUiQpHG4/m/ux+ +1QPIFtA5HiwRBFEUrFWL2wI9ZIkeDw3L9+tmngenfslLgFAs/V+hwQEx/WY7XrjBj 5Um4d/jzM9byw== 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 D7AA0CD6E79; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 08 Jun 2026 13:30:20 -0500 Subject: [PATCH v2 5/7] 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: <20260608-ibmvfc-fpin-support-v2-5-d41f540fba5c@linux.ibm.com> References: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@linux.ibm.com> In-Reply-To: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@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=1780943423; l=2552; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=WZU0TiQHIfrATphYf2jr66JLZ5y9tryV6E3XG2zppIE=; b=nWCwY/Gaspg7WA0psfLZHY2NuOMDXWuDl+dLWUWEYYdS4gJkdVPFYe7pUJLHXH5YMoIPkeU8m 5+KyrI5Vlf6C4313XdDy51CcLOyFUrpOw74R6CX3SFEHJqCZ/TDhGjv 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 set up the asynchronous sub-queue for asynchronous events, as required for full and extended FPIN support. --- drivers/scsi/ibmvscsi/ibmvfc.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index a18861808325..ad1f5636e879 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -5352,6 +5352,8 @@ 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]); + scrqs->async_scrq->vios_cookie =3D + be64_to_cpu(setup->asyncSubqHandle); =20 ibmvfc_dbg(vhost, "Using %u channels\n", vhost->scsi_scrqs.active_queues); @@ -5402,6 +5404,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->asyncSubqHandle =3D cpu_to_be64(scrqs->async_scrq->cookie); } =20 ibmvfc_init_event(evt, ibmvfc_channel_setup_done, IBMVFC_MAD_FORMAT); @@ -6369,6 +6372,24 @@ 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) { + kfree(channels->scrqs); + channels->scrqs =3D NULL; + return -ENOMEM; + } + + rc =3D ibmvfc_alloc_queue(vhost, channels->async_scrq, + IBMVFC_SUB_CRQ_FMT); + if (rc) { + kfree(channels->scrqs); + channels->scrqs =3D NULL; + kfree(channels->async_scrq); + channels->async_scrq =3D NULL; + return rc; + } + 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); @@ -6380,6 +6401,9 @@ static int ibmvfc_alloc_channels(struct ibmvfc_host *= vhost, kfree(channels->scrqs); channels->scrqs =3D NULL; channels->active_queues =3D 0; + ibmvfc_free_queue(vhost, channels->async_scrq); + kfree(channels->async_scrq); + channels->async_scrq =3D NULL; return rc; } } @@ -6418,6 +6442,10 @@ static void ibmvfc_release_channels(struct ibmvfc_ho= st *vhost, =20 kfree(channels->scrqs); channels->scrqs =3D NULL; + + ibmvfc_free_queue(vhost, channels->async_scrq); + channels->async_scrq =3D NULL; + channels->active_queues =3D 0; } } --=20 2.54.0 From nobody Mon Jun 15 06:29:39 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 2D0BC3E0758; Mon, 8 Jun 2026 18:30:25 +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=1780943425; cv=none; b=T/GO0NSI6HAQkR2wViKuTSfhw3B8TPoVUbPKgeyUlR2jqiviGlDz3axR1zsy7+gVS1PMCZALkOjwRRUjW+hk8bQx0eNUXhaTsF92mZF5QNKioDQdc4Vw65l1uwYShIp7VZ1ebav8p4hbczC7YRELkk4GCsYx3HYH0841jEkaTB0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780943425; c=relaxed/simple; bh=MTVSF9+SFRTrB2kQtU6UN6T4/OffJ2M/ScNkqmJ7akY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hMno63cPsHjlm4XInGQhOtL+YwiJKo/QDDJzXz9uUPJiQhAzkM5bKvl/V3kgGopUz4wU1rDKP7wSaYH1CeSoopR/+scX7O6rADGXgm8skSEkWJaDOrI+zh1oGxlwdB67SN23PKCWOWW/FGH+8ogga/n6qZ2QnTgvZgZEI0Lo54E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=K94Lg4cF; 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="K94Lg4cF" Received: by smtp.kernel.org (Postfix) with ESMTPS id EB75BC4AF16; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1780943425; bh=MTVSF9+SFRTrB2kQtU6UN6T4/OffJ2M/ScNkqmJ7akY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=K94Lg4cFy1PSwigcv1CeRkhmXO3FHqbzsGn0Ykj+10UKaVtkZq75IigDqdsIArwNK MPmrX81bOnm8KEKLJcK0GP8GspLMDJ3YjZs+cKr5vFaAGtb8g/v/B3kJqWC2ubwXGr I2VTAQAM4ujMa5tZcAYd4lJnE/zW/V0AfLYoGiTvaNfDF6Ojq3C+Bi3IH3SP/xmpse nGU9vaNhL5fxRfcySHod0W4vmwil+jDzNJiENFap4XRyuNh7vtAMo1qsifknjAOmvl l2ohU/zls3zrU6MLuHLKf/pjBoLwRU8OuqOTa713D83S1KteJulM+O9wvVlNxuJyAy iWy+UK8xd2R5Q== 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 E91CACD8CA4; Mon, 8 Jun 2026 18:30:24 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 08 Jun 2026 13:30:21 -0500 Subject: [PATCH v2 6/7] ibmvfc: register and use 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: <20260608-ibmvfc-fpin-support-v2-6-d41f540fba5c@linux.ibm.com> References: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@linux.ibm.com> In-Reply-To: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@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=1780943423; l=23073; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=o5xrvO1OjxGF6dxUj+TXvrDjXpKGaztBflOyX/ZBFvo=; b=rCJ/5khXsAoAhPCE6rP0Erfn3SS8IhVEunUdVLag1ZeV/Gr273O2TP28niuFW6Hx8n6VrUDKr 4uj5AmckNY1Aly93PY5uhGy0bWx+K3wvt7KZY2CFlRxN+fEWmbvrIw/ 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 existing code for async events into a common routine, register a channel and interrupt handler for the asynchronous sub-queue, and set capability bits to request that VIOS use the asynchronous sub-queue. --- drivers/scsi/ibmvscsi/ibmvfc.c | 376 +++++++++++++++++++++++++++----= ---- drivers/scsi/ibmvscsi/ibmvfc.h | 3 + drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 2 +- 3 files changed, 298 insertions(+), 83 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index ad1f5636e879..a2252cd2f44b 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1514,7 +1514,8 @@ static void ibmvfc_set_login_info(struct ibmvfc_host = *vhost) login_info->max_cmds =3D cpu_to_be32(max_cmds); login_info->capabilities =3D cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_SEND_VF_WWPN | - IBMVFC_CAN_USE_NOOP_CMD); + IBMVFC_CAN_USE_NOOP_CMD | IBMVFC_YES_SCSI | + IBMVFC_USE_ASYNC_SUBQ | IBMVFC_CAN_HANDLE_FPIN); =20 if (vhost->mq_enabled || vhost->using_channels) login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_USE_CHANNELS); @@ -3240,8 +3241,8 @@ static size_t ibmvfc_fpin_size_helper(u8 fpin_status) * non-NULL - pointer to populated struct fc_els_fpin */ static struct fc_els_fpin * -ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 modifier, - __be32 period, __be32 threshold, __be32 event_count) +ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 type, __be1= 6 modifier, + __be32 threshold, __be32 event_count) { struct fc_fn_peer_congn_desc *pdesc; struct fc_fn_congn_desc *cdesc; @@ -3253,7 +3254,7 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwp= n, __be16 modifier, if (size =3D=3D 0) return NULL; =20 - fpin =3D kzalloc(size, GFP_KERNEL); + fpin =3D kzalloc(size, GFP_ATOMIC); if (fpin =3D=3D NULL) return NULL; =20 @@ -3266,12 +3267,9 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 ww= pn, __be16 modifier, 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)); - if (fpin_status =3D=3D IBMVFC_AE_FPIN_CONGESTION_CLEARED) - cdesc->event_type =3D cpu_to_be16(FPIN_CONGN_CLEAR); - else - cdesc->event_type =3D cpu_to_be16(FPIN_CONGN_DEVICE_SPEC); + cdesc->event_type =3D type; cdesc->event_modifier =3D modifier; - cdesc->event_period =3D period; + 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: @@ -3281,12 +3279,9 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 ww= pn, __be16 modifier, 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(FC_TLV_DESC_LENGTH_FROM_SZ(*pdesc)); - if (fpin_status =3D=3D IBMVFC_AE_FPIN_PORT_CLEARED) - pdesc->event_type =3D cpu_to_be16(FPIN_CONGN_CLEAR); - else - pdesc->event_type =3D cpu_to_be16(FPIN_CONGN_DEVICE_SPEC); + pdesc->event_type =3D type; pdesc->event_modifier =3D modifier; - pdesc->event_period =3D period; + pdesc->event_period =3D cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD); pdesc->detecting_wwpn =3D cpu_to_be64(0); pdesc->attached_wwpn =3D wwpn; pdesc->pname_count =3D cpu_to_be32(1); @@ -3297,7 +3292,7 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwp= n, __be16 modifier, 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(FC_TLV_DESC_LENGTH_FROM_SZ(*ldesc)); - ldesc->event_type =3D cpu_to_be16(FPIN_LI_UNKNOWN); + ldesc->event_type =3D type; ldesc->event_modifier =3D modifier; ldesc->event_threshold =3D threshold; ldesc->event_count =3D event_count; @@ -3331,9 +3326,47 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 ww= pn, __be16 modifier, static struct fc_els_fpin * ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq *crq, u64 wwpn) { + __be16 type; + + switch (crq->fpin_status) { + case IBMVFC_AE_FPIN_LINK_CONGESTED: + case IBMVFC_AE_FPIN_PORT_CONGESTED: + type =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), - cpu_to_be16(0), - cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD), + type, cpu_to_be16(0), + cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD), + cpu_to_be32(1)); +} + +/** + * ibmvfc_full_fpin_to_desc(): allocate and populate a struct fc_els_fpin = struct + * containing a descriptor. + * @ibmvfc_fpin: Pointer to async subq FPIN data + * + * Allocate a struct fc_els_fpin containing a descriptor and populate + * based on data from *ibmvfc_fpin. + * + * Return: + * NULL - unable to allocate structure + * non-NULL - pointer to populated struct fc_els_fpin + */ +static struct fc_els_fpin * +ibmvfc_full_fpin_to_desc(struct ibmvfc_async_subq *ibmvfc_fpin) +{ + return ibmvfc_common_fpin_to_desc(ibmvfc_fpin->fpin_status, ibmvfc_fpin->= wwpn, + cpu_to_be16(0), cpu_to_be16(0), cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD), cpu_to_be32(1)); } @@ -3344,67 +3377,99 @@ ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq *= crq, u64 wwpn) */ static void ibmvfc_process_async_work(struct work_struct *work) { + struct ibmvfc_async_subq_fpin *sqfpin; + struct ibmvfc_target *tgt, *next; + struct ibmvfc_async_subq *subq; struct ibmvfc_async_work *aw; struct ibmvfc_async_crq *crq; - struct ibmvfc_target *tgt; struct ibmvfc_host *vhost; struct fc_els_fpin *fpin; + __be64 node_name; + __be64 scsi_id; + __be64 wwpn; =20 aw =3D container_of(work, struct ibmvfc_async_work, async_work_s); crq =3D aw->crq; + subq =3D aw->subq; vhost =3D aw->vhost; =20 - if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + if ((!crq && !subq) || (crq && subq)) { + dev_err_ratelimited(vhost->dev, + "FPIN event received, unable to process\n"); goto end; - list_for_each_entry(tgt, &vhost->targets, queue) { - if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) !=3D crq->scsi_id) + } + + 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 end; + + list_for_each_entry_safe(tgt, next, &vhost->targets, queue) { + 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; - fpin =3D ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn); + if (crq) { + fpin =3D ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn); + } else { + sqfpin =3D (struct ibmvfc_async_subq_fpin *)subq; + 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"); } =20 end: - crq->valid =3D 0; + if (crq) + crq->valid =3D 0; + if (subq) + subq->valid =3D 0; =20 kfree(aw); } =20 /** - * ibmvfc_handle_async - Handle an async event from the adapter - * @crq: crq to process + * ibmvfc_handle_async_common - Handle an async event from the adapter + * @event: event to process + * @link_state: link state * @vhost: ibmvfc host struct + * @scsi_id: scsi_id (0 if not applicable) + * @wwpn: wwpn + * @node_name: node_name + * @aw_crq: crq pointer for async work (NULL if not needed) + * @aw_subq: subq pointer for async work (NULL if not needed) * **/ -VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, - struct ibmvfc_host *vhost) +static void ibmvfc_handle_async_common(u64 event, u8 link_state, + struct ibmvfc_host *vhost, + u64 scsi_id, u64 wwpn, u64 node_name, + struct ibmvfc_async_crq *aw_crq, + struct ibmvfc_async_subq *aw_subq) { - const struct ibmvfc_async_desc *desc =3D ibmvfc_get_ae_desc(be64_to_cpu(c= rq->event)); + struct ibmvfc_target *tgt, *next; struct ibmvfc_async_work *aw; - struct ibmvfc_target *tgt; bool clear_valid =3D true; =20 - 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)) { + 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; @@ -3419,7 +3484,6 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmv= fc_async_crq *crq, __ibmvfc_reset_host(vhost); break; } - break; case IBMVFC_AE_LINK_UP: vhost->events_to_log |=3D IBMVFC_AE_LINKUP; @@ -3439,58 +3503,106 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct i= bmvfc_async_crq *crq, vhost->events_to_log |=3D IBMVFC_AE_RSCN; ibmvfc_reinit_host(vhost); break; + case IBMVFC_AE_LINK_DOWN: + case IBMVFC_AE_ADAPTER_FAILED: + ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); + break; + case IBMVFC_AE_LINK_DEAD: + ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); + break; + case IBMVFC_AE_HALT: + ibmvfc_link_down(vhost, IBMVFC_HALTED); + break; 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); } } break; - case IBMVFC_AE_LINK_DOWN: - case IBMVFC_AE_ADAPTER_FAILED: - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); - break; - case IBMVFC_AE_LINK_DEAD: - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - break; - 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) { clear_valid =3D false; INIT_WORK(&aw->async_work_s, ibmvfc_process_async_work); aw->vhost =3D vhost; - aw->crq =3D crq; + if (aw_crq) + aw->crq =3D aw_crq; + if (aw_subq) + aw->subq =3D aw_subq; schedule_work(&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; } =20 - if (clear_valid) - crq->valid =3D 0; + if (clear_valid) { + if (aw_crq) + aw_crq->valid =3D 0; + if (aw_subq) + aw_subq->valid =3D 0; + } +} + +/** + * ibmvfc_handle_async - Handle an async event from the adapter + * @crq: crq to process + * @vhost: ibmvfc host struct + * + **/ +VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, + struct ibmvfc_host *vhost) +{ + const struct ibmvfc_async_desc *desc =3D ibmvfc_get_ae_desc(be64_to_cpu(c= rq->event)); + u64 event =3D be64_to_cpu(crq->event); + + ibmvfc_log(vhost, desc->log_level, + "%s event received. scsi_id: %llx, wwpn: %llx, node_name: %llx%s\n", + desc->desc, be64_to_cpu(crq->scsi_id), + be64_to_cpu(crq->wwpn), be64_to_cpu(crq->node_name), + ibmvfc_get_link_state(crq->link_state)); + + ibmvfc_handle_async_common(event, crq->link_state, vhost, + crq->scsi_id, crq->wwpn, crq->node_name, + crq, NULL); } EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_async); =20 +VISIBLE_IF_KUNIT void ibmvfc_handle_asyncq(struct ibmvfc_crq *crq_instance, + struct ibmvfc_host *vhost) +{ + struct ibmvfc_async_subq *crq =3D (struct ibmvfc_async_subq *)crq_instanc= e; + const struct ibmvfc_async_desc *desc =3D ibmvfc_get_ae_desc(be16_to_cpu(c= rq->event)); + u64 event =3D be16_to_cpu(crq->event); + + ibmvfc_log(vhost, desc->log_level, + "%s event received. wwpn: %llx, node_name: %llx%s event 0x%x\n", + desc->desc, be64_to_cpu(crq->wwpn), be64_to_cpu(crq->id.node_name), + ibmvfc_get_link_state(crq->link_state), be16_to_cpu(crq->event)); + + ibmvfc_handle_async_common(event, crq->link_state, vhost, + 0, crq->wwpn, crq->id.node_name, + NULL, crq); +} +EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_asyncq); + /** * ibmvfc_handle_crq - Handles and frees received events in the CRQ * @crq: Command/Response queue @@ -4117,6 +4229,13 @@ static void ibmvfc_handle_scrq(struct ibmvfc_crq *cr= q, struct ibmvfc_host *vhost spin_unlock(&evt->queue->l_lock); } =20 +/** + * ibmvfc_next_scrq - Returns the next entry in message subqueue + * @scrq: Pointer to message subqueue + * + * Returns: + * Pointer to next entry in queue / NULL if empty + **/ static struct ibmvfc_crq *ibmvfc_next_scrq(struct ibmvfc_queue *scrq) { struct ibmvfc_crq *crq; @@ -4132,6 +4251,57 @@ static struct ibmvfc_crq *ibmvfc_next_scrq(struct ib= mvfc_queue *scrq) return crq; } =20 +static void ibmvfc_drain_async_subq(struct ibmvfc_queue *scrq) +{ + struct ibmvfc_crq *crq; + unsigned long flags; + int done =3D 0; + + ENTER; + + spin_lock_irqsave(scrq->q_lock, flags); + while (!done) { + while ((crq =3D ibmvfc_next_scrq(scrq)) !=3D NULL) { + ibmvfc_handle_asyncq(crq, scrq->vhost); + 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_asyncq(crq, scrq->vhost); + crq->valid =3D 0; + wmb(); /* complete write */ + } else + done =3D 1; + } + spin_unlock_irqrestore(scrq->q_lock, flags); + + LEAVE; +} + +/** + * ibmvfc_interrupt_asyncq - Handle an async event from the adapter + * @irq: interrupt request + * @scrq_instance: async subq + * + **/ +static irqreturn_t ibmvfc_interrupt_asyncq(int irq, void *scrq_instance) +{ + struct ibmvfc_queue *scrq =3D (struct ibmvfc_queue *)scrq_instance; + + ENTER; + + ibmvfc_toggle_scrq_irq(scrq, 0); + ibmvfc_drain_async_subq(scrq); + + LEAVE; + + return IRQ_HANDLED; +} + static void ibmvfc_drain_sub_crq(struct ibmvfc_queue *scrq) { struct ibmvfc_crq *crq; @@ -5500,6 +5670,8 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_even= t *evt) unsigned int npiv_max_sectors; int level =3D IBMVFC_DEFAULT_LOG_LEVEL; =20 + ENTER; + switch (mad_status) { case IBMVFC_MAD_SUCCESS: ibmvfc_free_event(evt); @@ -5578,6 +5750,8 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_even= t *evt) ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); wake_up(&vhost->work_wait_q); } + + LEAVE; } =20 /** @@ -6226,14 +6400,26 @@ 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) +static inline char *ibmvfc_channel_index(struct ibmvfc_channels *channels, + struct ibmvfc_queue *scrq, + char *buf, size_t bufsize) +{ + if (scrq < channels->scrqs || scrq >=3D channels->scrqs + channels->activ= e_queues) + strscpy(buf, "async", 6); + else + snprintf(buf, bufsize, "%ld", scrq - channels->scrqs); + return buf; +} + +static int ibmvfc_register_channel_handler(struct ibmvfc_host *vhost, + struct ibmvfc_channels *channels, + struct ibmvfc_queue *scrq, + 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]; int rc =3D -ENOMEM; + char buf[16]; =20 ENTER; =20 @@ -6252,20 +6438,23 @@ 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); + dev_err(dev, "Error mapping sub-crq[%s] irq\n", + ibmvfc_channel_index(channels, scrq, buf, sizeof(buf))); 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; + snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-scsi%s", + vdev->unit_address, + ibmvfc_channel_index(channels, scrq, buf, sizeof(buf))); + scrq->handler =3D irq; 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; + snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-nvmf%s", + vdev->unit_address, + ibmvfc_channel_index(channels, scrq, buf, sizeof(buf))); + scrq->handler =3D irq; break; default: dev_err(dev, "Unknown channel protocol (%d)\n", @@ -6276,12 +6465,14 @@ static int ibmvfc_register_channel(struct ibmvfc_ho= st *vhost, 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); + dev_err(dev, "Couldn't register sub-crq[%s] irq\n", + ibmvfc_channel_index(channels, scrq, buf, sizeof(buf))); irq_dispose_mapping(scrq->irq); goto irq_failed; } =20 - scrq->hwq_id =3D index; + if (scrq >=3D channels->scrqs && scrq < channels->scrqs + channels->max_q= ueues) + scrq->hwq_id =3D scrq - channels->scrqs; =20 LEAVE; return 0; @@ -6295,13 +6486,21 @@ static int ibmvfc_register_channel(struct ibmvfc_ho= st *vhost, return rc; } =20 +static inline int +ibmvfc_register_channel(struct ibmvfc_host *vhost, + struct ibmvfc_channels *channels, + struct ibmvfc_queue *scrq) +{ + return ibmvfc_register_channel_handler(vhost, channels, scrq, ibmvfc_inte= rrupt_mq); +} + 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]; + char buf[16]; long rc; =20 ENTER; @@ -6316,7 +6515,8 @@ 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", + ibmvfc_channel_index(channels, scrq, buf, sizeof(buf)), rc); =20 /* Clean out the queue */ memset(scrq->msgs.crq, 0, PAGE_SIZE); @@ -6334,10 +6534,21 @@ static void ibmvfc_reg_sub_crqs(struct ibmvfc_host = *vhost, if (!vhost->mq_enabled || !channels->scrqs) return; =20 + if (ibmvfc_register_channel_handler(vhost, channels, + channels->async_scrq, + ibmvfc_interrupt_asyncq)) { + vhost->do_enquiry =3D 0; + return; + } + for (i =3D 0; i < channels->max_queues; i++) { - if (ibmvfc_register_channel(vhost, channels, i)) { + if (ibmvfc_register_channel(vhost, channels, &channels->scrqs[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; } @@ -6356,7 +6567,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; } diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index f026f30f98d3..2e02acde0178 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -715,6 +715,7 @@ struct ibmvfc_async_crq { struct ibmvfc_async_work { struct ibmvfc_host *vhost; struct ibmvfc_async_crq *crq; + struct ibmvfc_async_subq *subq; struct work_struct async_work_s; }; =20 @@ -1008,6 +1009,8 @@ struct ibmvfc_host { =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_asyncq(struct ibmvfc_crq *crq_instance, + struct ibmvfc_host *vhost); 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 e41e2a49e549..c8799eaf4927 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c +++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c @@ -44,7 +44,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); --=20 2.54.0 From nobody Mon Jun 15 06:29:39 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 2CFF53E0732; Mon, 8 Jun 2026 18:30:25 +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=1780943425; cv=none; b=epBGTr0FDduvhPTV4gYXozHa1+nwtsbc3+NpYzzsIXuvNQ5Fvn2cLJUMunOFGWFQ5sEIgX7+pb35JD9mHyPCtAoRd2AdOkyVswLY85PCqdIPkbR4UxgBBHZEH+/5lkUl02VXGYJGSpiK1fo0YYBAVfybYQiixdVyaj3QQp/AliU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780943425; c=relaxed/simple; bh=vI4aSsvmnF4XdV2fqw87RJEP9tt3abWG0rskLfcFsJw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=bywR+Sbqnlz/gQhAYoAZILZD6uEcohCn1xXUNF/xtnS6MiwydQrnYxOp3myjaknUzomW8lVABMNDgscmQHssa914CL/eFjrgKah5aq3coZatqAlleSzG6NeVXCGtkd9yM1ldfndoInMkMFDHcm48RDRQe3YwgWIZTHftkC/EVLg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DuAJ4bsR; 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="DuAJ4bsR" Received: by smtp.kernel.org (Postfix) with ESMTPS id 09295C4AF19; Mon, 8 Jun 2026 18:30:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1780943425; bh=vI4aSsvmnF4XdV2fqw87RJEP9tt3abWG0rskLfcFsJw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From; b=DuAJ4bsRugl52nrc4AHjvofsrwdkSV/lQIZILYE46QqHePb96H0QI9zPF99ljJtdy J2ODcX8z8q6jbtI6F9kbPk+CYmDvK8Ucba71v22l/nNM8/d5EXPqNh5R/zDcXOILzz 2mD4GN5PCvzrjvaH0wLNoUuanhMdlS9oNH/qk1Hw8Enrh73A3t3AM3jswyU77Pa/+6 fLsVYm3Pqve8YCwzBOSCfQCjMUB6Hgqr91wDheigay4DyvssQZHsK01FdHlsRcKsoA aL/F1uPRGcSZf6WegBtd7C5YrRjLDgn08rBwm9GLEvsWZw3Qib96ZQZIBelH+b7O7z ZVqkqLFxjd53Q== 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 062EDCD8CAB; Mon, 8 Jun 2026 18:30:25 +0000 (UTC) From: Dave Marquardt via B4 Relay Date: Mon, 08 Jun 2026 13:30:22 -0500 Subject: [PATCH v2 7/7] 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: <20260608-ibmvfc-fpin-support-v2-7-d41f540fba5c@linux.ibm.com> References: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@linux.ibm.com> In-Reply-To: <20260608-ibmvfc-fpin-support-v2-0-d41f540fba5c@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=1780943423; l=11383; i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id; bh=2RqC+rU2A9gSh64NyYLbxM+SEGYa8ZsXYS3BOiaFMSo=; b=w4G1hFagIYmgT4hvi/1N8dfCxJbcCPexRMzW1ytE6gZV07LmyfYEYRN6E8vlFBmd2MfIhgkw6 lXomtzfWx9zBOwEpBJrUgouN3sYFIsdc0FzJFRAGFuTGLvR/PQ+5yrW 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 extended FPIN handling to ibmvfc driver. Tell VIOS ibmvfc can handle extended FPIN messages, convert any received to struct fc_els descriptors, and call fc_host_fpin_rcv to update statistics and send netlink multicast messages to listeners such as multipathd. --- drivers/scsi/ibmvscsi/ibmvfc.c | 41 +++++++++++- drivers/scsi/ibmvscsi/ibmvfc.h | 31 +++++++++ drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 122 +++++++++++++++++++++++++++++++= ++-- 3 files changed, 186 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index a2252cd2f44b..b034a894e3ec 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1515,7 +1515,8 @@ static void ibmvfc_set_login_info(struct ibmvfc_host = *vhost) login_info->capabilities =3D cpu_to_be64(IBMVFC_CAN_MIGRATE | IBMVFC_CAN_SEND_VF_WWPN | IBMVFC_CAN_USE_NOOP_CMD | 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 if (vhost->mq_enabled || vhost->using_channels) login_info->capabilities |=3D cpu_to_be64(IBMVFC_CAN_USE_CHANNELS); @@ -3254,7 +3255,7 @@ ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwp= n, __be16 type, __be16 modi if (size =3D=3D 0) return NULL; =20 - fpin =3D kzalloc(size, GFP_ATOMIC); + fpin =3D kzalloc(size, GFP_KERNEL); if (fpin =3D=3D NULL) return NULL; =20 @@ -3371,6 +3372,28 @@ ibmvfc_full_fpin_to_desc(struct ibmvfc_async_subq *i= bmvfc_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) +{ + return ibmvfc_common_fpin_to_desc(ibmvfc_fpin->fpin_status, ibmvfc_fpin->= wwpn, + ibmvfc_fpin->fpin_data.event_type, + ibmvfc_fpin->fpin_data.event_type_modifier, + ibmvfc_fpin->fpin_data.event_threshold, + ibmvfc_fpin->fpin_data.event_data.event_count); +} + /** * ibmvfc_process_async_work - Process IBMVFC_AE_FPIN async CRQ from work = queue * @work: pointer to work_struct @@ -3425,7 +3448,19 @@ static void ibmvfc_process_async_work(struct work_st= ruct *work) fpin =3D ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn); } else { sqfpin =3D (struct ibmvfc_async_subq_fpin *)subq; - fpin =3D ibmvfc_full_fpin_to_desc(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"); + fpin =3D NULL; + } else if (!ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_FPIN_EXT)) { + dev_err_ratelimited(vhost->dev, + "Unexpected extended FPIN event received"); + fpin =3D NULL; + } else { + fpin =3D ibmvfc_ext_fpin_to_desc(sqfpin); + } } if (fpin) { fc_host_fpin_rcv(tgt->vhost->host, diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index 2e02acde0178..5c4cf4be4b67 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 0x40 #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 0x200 #define IBMVFC_SUPPORT_ASYNC_SUBQ 0x800 #define IBMVFC_SUPPORT_NOOP_CMD 0x1000 +#define IBMVFC_SUPPORT_FPIN_EXT 0x2000 __be32 max_cmds; __be32 scsi_id_sz; __be64 max_dma_len; @@ -722,6 +724,7 @@ struct ibmvfc_async_work { 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 @@ -738,6 +741,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); + union ibmvfc_iu { struct ibmvfc_mad_common mad_common; struct ibmvfc_npiv_login_mad npiv_login; diff --git a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c b/drivers/scsi/ibmvscsi/i= bmvfc_kunit.c index c8799eaf4927..2e6cbaaebdba 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" @@ -58,10 +59,10 @@ static void ibmvfc_async_fpin_test(struct kunit *test) crq[fs].wwpn =3D cpu_to_be64(tgt->wwpn); crq[fs].node_name =3D cpu_to_be64(tgt->ids.node_name); ibmvfc_handle_async(&crq[fs], vhost); + while (crq[fs].valid) + 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); @@ -94,8 +95,8 @@ static void ibmvfc_async_fpin_test(struct kunit *test) crq[0].wwpn =3D cpu_to_be64(tgt->wwpn); crq[0].node_name =3D cpu_to_be64(tgt->ids.node_name); ibmvfc_handle_async(&crq[0], vhost); - - msleep(500U); + while (crq[0].valid) + 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); @@ -115,8 +116,119 @@ 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_asyncq((struct ibmvfc_crq *)&crq, vhost); \ + while (crq.valid) \ + 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]; + struct ibmvfc_async_subq_fpin + crqcn[IBMVFC_AE_FPIN_PORT_CONGESTED][FPIN_CONGN_DEVICE_SPEC+1]; + struct ibmvfc_async_subq_fpin crqportdg[FPIN_LI_DEVICE_SPEC+1]; + 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_asyncq((struct ibmvfc_crq *)&crq[fs], vhost); + while (crq[fs].valid) + 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.54.0