get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.1/patches/2221020/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2221020,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2221020/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/20260408-ibmvfc-fpin-support-v1-1-52b06c464e03@linux.ibm.com/",
    "project": {
        "id": 2,
        "url": "http://patchwork.ozlabs.org/api/1.1/projects/2/?format=api",
        "name": "Linux PPC development",
        "link_name": "linuxppc-dev",
        "list_id": "linuxppc-dev.lists.ozlabs.org",
        "list_email": "linuxppc-dev@lists.ozlabs.org",
        "web_url": "https://github.com/linuxppc/wiki/wiki",
        "scm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git",
        "webscm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/"
    },
    "msgid": "<20260408-ibmvfc-fpin-support-v1-1-52b06c464e03@linux.ibm.com>",
    "date": "2026-04-08T17:07:42",
    "name": "[1/5] ibmvfc: add basic FPIN support",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "57eab2f568a01d8e164d2f5f687f5d002cf78d32",
    "submitter": {
        "id": 93089,
        "url": "http://patchwork.ozlabs.org/api/1.1/people/93089/?format=api",
        "name": "Dave Marquardt via B4 Relay",
        "email": "devnull+davemarq.linux.ibm.com@kernel.org"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/20260408-ibmvfc-fpin-support-v1-1-52b06c464e03@linux.ibm.com/mbox/",
    "series": [
        {
            "id": 499164,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/499164/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/list/?series=499164",
            "date": "2026-04-08T17:07:44",
            "name": "ibmvfc: make ibmvfc support FPIN messages",
            "version": 1,
            "mbox": "http://patchwork.ozlabs.org/series/499164/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2221020/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2221020/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "\n <linuxppc-dev+bounces-19520-incoming=patchwork.ozlabs.org@lists.ozlabs.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "linuxppc-dev@lists.ozlabs.org"
        ],
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=JC4sKN7V;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.ozlabs.org\n (client-ip=2404:9400:21b9:f100::1; helo=lists.ozlabs.org;\n envelope-from=linuxppc-dev+bounces-19520-incoming=patchwork.ozlabs.org@lists.ozlabs.org;\n receiver=patchwork.ozlabs.org)",
            "lists.ozlabs.org;\n arc=none smtp.remote-ip=172.234.252.31",
            "lists.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org",
            "lists.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=JC4sKN7V;\n\tdkim-atps=neutral",
            "lists.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=kernel.org\n (client-ip=172.234.252.31; helo=sea.source.kernel.org;\n envelope-from=devnull+davemarq.linux.ibm.com@kernel.org;\n receiver=lists.ozlabs.org)"
        ],
        "Received": [
            "from lists.ozlabs.org (lists.ozlabs.org\n [IPv6:2404:9400:21b9:f100::1])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4frTzR2kqXz1xv0\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 09 Apr 2026 03:08:19 +1000 (AEST)",
            "from boromir.ozlabs.org (localhost [127.0.0.1])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 4frTz26YmSz2yrt;\n\tThu, 09 Apr 2026 03:07:58 +1000 (AEST)",
            "from sea.source.kernel.org (sea.source.kernel.org [172.234.252.31])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby lists.ozlabs.org (Postfix) with ESMTPS id 4frTyw5sP4z2yj1\n\tfor <linuxppc-dev@lists.ozlabs.org>; Thu, 09 Apr 2026 03:07:52 +1000 (AEST)",
            "from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58])\n\tby sea.source.kernel.org (Postfix) with ESMTP id 686874416C;\n\tWed,  8 Apr 2026 17:07:49 +0000 (UTC)",
            "by smtp.kernel.org (Postfix) with ESMTPS id 42798C2BC87;\n\tWed,  8 Apr 2026 17:07:49 +0000 (UTC)",
            "from aws-us-west-2-korg-lkml-1.web.codeaurora.org\n (localhost.localdomain [127.0.0.1])\n\tby smtp.lore.kernel.org (Postfix) with ESMTP id 34DF810F9960;\n\tWed,  8 Apr 2026 17:07:49 +0000 (UTC)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707; t=1775668078;\n\tcv=none;\n b=IJPfiDpW/HYgq+ea7c9Guyp6PAnvvh4+gRnDYV0yIT/7x1G4l6y74D8IOvv96/doOni7XBryXdcJxZfo9kJmWGvi+iw4CWkV08cWZw0uPbZkHpRTP22Cfnuuh1vJ3KJ/OIbZWR/sTSq/VHW8lx8un6++V0/dxppXdTwTmgfTfLgm7XZiXq0XHaZAEwXvJBZ/OSXq1BX1V//YAfOwL2cZwYlBiPlm8oUD38v+uwC9j9m+iYBQIq4/m9uJQNuRpA78DEpHKNv7z5CGvOA48oel1pOmoMfxx14tIpFBbD8DgrxpcVfqoASA4LfOOE6HwX/njRmDw+sywrz99e7UwaEB6Q==",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=lists.ozlabs.org; s=201707;\n\tt=1775668078; c=relaxed/relaxed;\n\tbh=TrNaXl0olRLwtAg7b8ZBTOMnAKFaS4XbKBmR6Ol9GD4=;\n\th=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References:\n\t In-Reply-To:To:Cc;\n b=kuBVx65lZCA9IHtp7GrSW2efesfEDJf+jVWDXiN0omGIJbwXJXHTDXn0WJdcFioxmVp47Rr/UaSeOfEWNL4zbCEtOq1GhLTOxbckZ74Hwfg+Mbr2Nlapi6Pc69/HDcRMDCm0UeevncS5/4MXdOIgMsdjEonRqiPk2+E84clFJKY5sUHNNSSuem34+KM/k5ysmzxvcoWW0xM3Pq25ltXKTXdvoUOxOjXEsgpsQld2WUPZTQz1QBoz6/LkHBO1CaHUFwE9eAJB9enuqoSxoBIFGPRcJm23Pwy8BNG1QjhdP9786N82tQV57TpysKGugXCwvsn549BVHpfDe5nI8OSJyg==",
        "ARC-Authentication-Results": "i=1; lists.ozlabs.org;\n dmarc=pass (p=quarantine dis=none) header.from=kernel.org;\n dkim=pass (2048-bit key;\n unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256\n header.s=k20201202 header.b=JC4sKN7V; dkim-atps=neutral;\n spf=pass (client-ip=172.234.252.31; helo=sea.source.kernel.org;\n envelope-from=devnull+davemarq.linux.ibm.com@kernel.org;\n receiver=lists.ozlabs.org) smtp.mailfrom=kernel.org",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org;\n\ts=k20201202; t=1775668069;\n\tbh=JDw6Ae7HX/HrNqj4fG10qrqI2pkNxGhfMVSa7ABOjac=;\n\th=From:Date:Subject:References:In-Reply-To:To:Cc:Reply-To:From;\n\tb=JC4sKN7V813di4AZMXfU6Iq3zIQXNIvw1dvwUzpRT4E2ze9AUFI+Rr1YLs8VABj7S\n\t ss2oXcru4/K9JGrPXLUS3brwr3RE87mpsUvzIDHjh/pVFWq2V2nsqQ+ovqytn/yy8R\n\t dGn+Eo5cvn/audp3/z/945w+EBhcSGEkMuUdyWP4qvxuM4oBkp7AudS6jHfK+BxpxZ\n\t DFUEec6ZP556m4XhVjr/Sm3mD5lal6EksJbESc2zoHRCmuQSJv3NJj6Hqbf5g1+F9p\n\t nLTNlY0QSqYDXEAcmNQ98e13e+j6C8EDzl1ZDtZycj8mh9hdFYSTvzhFGpusp043vl\n\t 8klpA1u5+Lbtg==",
        "From": "Dave Marquardt via B4 Relay <devnull+davemarq.linux.ibm.com@kernel.org>",
        "Date": "Wed, 08 Apr 2026 12:07:42 -0500",
        "Subject": "[PATCH 1/5] ibmvfc: add basic FPIN support",
        "X-Mailing-List": "linuxppc-dev@lists.ozlabs.org",
        "List-Id": "<linuxppc-dev.lists.ozlabs.org>",
        "List-Help": "<mailto:linuxppc-dev+help@lists.ozlabs.org>",
        "List-Owner": "<mailto:linuxppc-dev+owner@lists.ozlabs.org>",
        "List-Post": "<mailto:linuxppc-dev@lists.ozlabs.org>",
        "List-Archive": "<https://lore.kernel.org/linuxppc-dev/>,\n  <https://lists.ozlabs.org/pipermail/linuxppc-dev/>",
        "List-Subscribe": "<mailto:linuxppc-dev+subscribe@lists.ozlabs.org>,\n  <mailto:linuxppc-dev+subscribe-digest@lists.ozlabs.org>,\n  <mailto:linuxppc-dev+subscribe-nomail@lists.ozlabs.org>",
        "List-Unsubscribe": "<mailto:linuxppc-dev+unsubscribe@lists.ozlabs.org>",
        "Precedence": "list",
        "MIME-Version": "1.0",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "7bit",
        "Message-Id": "<20260408-ibmvfc-fpin-support-v1-1-52b06c464e03@linux.ibm.com>",
        "References": "<20260408-ibmvfc-fpin-support-v1-0-52b06c464e03@linux.ibm.com>",
        "In-Reply-To": "<20260408-ibmvfc-fpin-support-v1-0-52b06c464e03@linux.ibm.com>",
        "To": "\"James E.J. Bottomley\" <James.Bottomley@HansenPartnership.com>,\n \"Martin K. Petersen\" <martin.petersen@oracle.com>,\n Madhavan Srinivasan <maddy@linux.ibm.com>,\n Michael Ellerman <mpe@ellerman.id.au>, Nicholas Piggin <npiggin@gmail.com>,\n \"Christophe Leroy (CS GROUP)\" <chleroy@kernel.org>,\n Tyrel Datwyler <tyreld@linux.ibm.com>",
        "Cc": "linux-kernel@vger.kernel.org, linux-scsi@vger.kernel.org,\n linuxppc-dev@lists.ozlabs.org, Brian King <brking@linux.ibm.com>,\n Greg Joyce <gjoyce@linux.ibm.com>, Kyle Mahlkuch <kmahlkuc@linux.ibm.com>,\n Dave Marquardt <davemarq@linux.ibm.com>",
        "X-Mailer": "b4 0.15.1",
        "X-Developer-Signature": "v=1; a=ed25519-sha256; t=1775668068; l=14243;\n i=davemarq@linux.ibm.com; s=20260216; h=from:subject:message-id;\n bh=Dl00hOQbbC4RypcktadD3eAH088sQG3T5G/LZ4uD1gw=;\n b=S1I7+xP1l1nWPy8gVi7/26B6OD+IWNadA8id5ws1319dCjiZT/Kmu3TGxtwI0QBYCt9KZkQ21\n OFjT7iP4e8ICz9YQuvAuYXSO1YalYbbeNTcdWGwHcHJdhW2np9nuBdK",
        "X-Developer-Key": "i=davemarq@linux.ibm.com; a=ed25519;\n pk=vy0/nfobrje6EqZxuyw6a3ZstytG8WK2vf5Y3xtGrEg=",
        "X-Endpoint-Received": "by B4 Relay for davemarq@linux.ibm.com/20260216 with\n auth_id=689",
        "X-Original-From": "Dave Marquardt <davemarq@linux.ibm.com>",
        "Reply-To": "davemarq@linux.ibm.com",
        "X-Spam-Status": "No, score=-0.2 required=3.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED,\n\tDKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS\n\tautolearn=disabled version=4.0.1 OzLabs 8",
        "X-Spam-Checker-Version": "SpamAssassin 4.0.1 (2024-03-25) on lists.ozlabs.org"
    },
    "content": "From: Dave Marquardt <davemarq@linux.ibm.com>\n\n- Add FPIN event descriptor\n- Add congestion cleared status\n- Add code to handle basic FPIN async event\n- Add KUnit tests\n---\n drivers/scsi/Kconfig                 |  10 ++\n drivers/scsi/ibmvscsi/Makefile       |   1 +\n drivers/scsi/ibmvscsi/ibmvfc.c       | 189 ++++++++++++++++++++++++++++++++++-\n drivers/scsi/ibmvscsi/ibmvfc.h       |   9 ++\n drivers/scsi/ibmvscsi/ibmvfc_kunit.c |  95 ++++++++++++++++++\n 5 files changed, 302 insertions(+), 2 deletions(-)",
    "diff": "diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig\nindex f811ce473c2a..9a4b18cde834 100644\n--- a/drivers/scsi/Kconfig\n+++ b/drivers/scsi/Kconfig\n@@ -761,6 +761,16 @@ config SCSI_IBMVFC\n \t  To compile this driver as a module, choose M here: the\n \t  module will be called ibmvfc.\n \n+config SCSI_IBMVFC_KUNIT_TEST\n+\ttristate \"KUnit tests for the IBM POWER Virtual FC Client\" if !KUNIT_ALL_TESTS\n+\tdepends on SCSI_IBMVFC && KUNIT\n+\tdefault KUNIT_ALL_TESTS\n+\thelp\n+\t  Compile IBM POWER Virtual FC client KUnit tests.\n+\n+\t  To compile this driver as a module, choose M here: the\n+\t  module will be called ibmvfc_kunit.\n+\n config SCSI_IBMVFC_TRACE\n \tbool \"enable driver internal trace\"\n \tdepends on SCSI_IBMVFC\ndiff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile\nindex 5eb1cb1a0028..75dc7aee15a0 100644\n--- a/drivers/scsi/ibmvscsi/Makefile\n+++ b/drivers/scsi/ibmvscsi/Makefile\n@@ -1,3 +1,4 @@\n # SPDX-License-Identifier: GPL-2.0-only\n obj-$(CONFIG_SCSI_IBMVSCSI)\t+= ibmvscsi.o\n obj-$(CONFIG_SCSI_IBMVFC)\t+= ibmvfc.o\n+obj-$(CONFIG_SCSI_IBMVFC_KUNIT_TEST)\t+= ibmvfc_kunit.o\ndiff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c\nindex 3dd2adda195e..3ac376ba2c62 100644\n--- a/drivers/scsi/ibmvscsi/ibmvfc.c\n+++ b/drivers/scsi/ibmvscsi/ibmvfc.c\n@@ -30,6 +30,9 @@\n #include <scsi/scsi_tcq.h>\n #include <scsi/scsi_transport_fc.h>\n #include <scsi/scsi_bsg_fc.h>\n+#include <kunit/visibility.h>\n+#include <scsi/fc/fc_els.h>\n+#include <linux/overflow.h>\n #include \"ibmvfc.h\"\n \n static unsigned int init_timeout = IBMVFC_INIT_TIMEOUT;\n@@ -3137,6 +3140,7 @@ static const struct ibmvfc_async_desc ae_desc [] = {\n \t{ \"Halt\",\tIBMVFC_AE_HALT,\t\tIBMVFC_DEFAULT_LOG_LEVEL },\n \t{ \"Resume\",\tIBMVFC_AE_RESUME,\tIBMVFC_DEFAULT_LOG_LEVEL },\n \t{ \"Adapter Failed\", IBMVFC_AE_ADAPTER_FAILED, IBMVFC_DEFAULT_LOG_LEVEL },\n+\t{ \"FPIN\",\tIBMVFC_AE_FPIN,\t\tIBMVFC_DEFAULT_LOG_LEVEL },\n };\n \n static const struct ibmvfc_async_desc unknown_ae = {\n@@ -3185,17 +3189,166 @@ static const char *ibmvfc_get_link_state(enum ibmvfc_ae_link_state state)\n \treturn \"\";\n }\n \n+#define IBMVFC_FPIN_CONGN_DESC_SZ (sizeof(struct fc_els_fpin) + sizeof(struct fc_fn_congn_desc))\n+#define IBMVFC_FPIN_LI_DESC_SZ (sizeof(struct fc_els_fpin) + \\\n+\t\t\t\tstruct_size_t(struct fc_fn_li_desc, pname_list, 1))\n+#define IBMVFC_FPIN_PEER_CONGN_DESC_SZ (sizeof(struct fc_els_fpin) + \\\n+\t\t\t\t\tstruct_size_t(struct fc_fn_peer_congn_desc, pname_list, 1))\n+\n+/**\n+ * ibmvfc_fpin_size_helper(): compute fpin structure size based on fpin status\n+ * @fpin_status: status value\n+ *\n+ * Return:\n+ * 0: invalid fpin_status\n+ * other: valid size\n+ */\n+static size_t ibmvfc_fpin_size_helper(u8 fpin_status)\n+{\n+\tsize_t size = 0;\n+\n+\tswitch (fpin_status) {\n+\tcase IBMVFC_AE_FPIN_LINK_CONGESTED:\n+\tcase IBMVFC_AE_FPIN_CONGESTION_CLEARED:\n+\t\tsize = IBMVFC_FPIN_CONGN_DESC_SZ;\n+\t\tbreak;\n+\tcase IBMVFC_AE_FPIN_PORT_CONGESTED:\n+\tcase IBMVFC_AE_FPIN_PORT_CLEARED:\n+\t\tsize = IBMVFC_FPIN_PEER_CONGN_DESC_SZ;\n+\t\tbreak;\n+\tcase IBMVFC_AE_FPIN_PORT_DEGRADED:\n+\t\tsize = IBMVFC_FPIN_LI_DESC_SZ;\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\treturn size;\n+}\n+\n+/**\n+ * ibmvfc_common_fpin_to_desc(): allocate and populate a struct fc_els_fpin struct\n+ * containing a descriptor.\n+ * @fpin_status: status value\n+ * @wwpn: attached wwpn\n+ *\n+ * Allocate a struct fc_els_fpin containing a descriptor and populate\n+ * based on data from *ibmvfc_fpin.\n+ *\n+ * Return:\n+ * NULL     - unable to allocate structure\n+ * non-NULL - pointer to populated struct fc_els_fpin\n+ */\n+static struct fc_els_fpin *\n+ibmvfc_common_fpin_to_desc(u8 fpin_status, __be64 wwpn, __be16 modifier,\n+\t\t\t   __be32 period, __be32 threshold, __be32 event_count)\n+{\n+\tstruct fc_fn_peer_congn_desc *pdesc;\n+\tstruct fc_fn_congn_desc *cdesc;\n+\tstruct fc_fn_li_desc *ldesc;\n+\tstruct fc_els_fpin *fpin;\n+\tsize_t size;\n+\n+\tsize = ibmvfc_fpin_size_helper(fpin_status);\n+\tif (size == 0)\n+\t\treturn NULL;\n+\n+\tfpin = kzalloc(size, GFP_KERNEL);\n+\tif (fpin == NULL)\n+\t\treturn NULL;\n+\n+\tfpin->fpin_cmd = ELS_FPIN;\n+\n+\tswitch (fpin_status) {\n+\tcase IBMVFC_AE_FPIN_CONGESTION_CLEARED:\n+\tcase IBMVFC_AE_FPIN_LINK_CONGESTED:\n+\t\tfpin->desc_len = cpu_to_be32(sizeof(struct fc_fn_congn_desc));\n+\t\tcdesc = (struct fc_fn_congn_desc *)fpin->fpin_desc;\n+\t\tcdesc->desc_tag = cpu_to_be32(ELS_DTAG_CONGESTION);\n+\t\tcdesc->desc_len = cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*cdesc));\n+\t\tif (fpin_status == IBMVFC_AE_FPIN_CONGESTION_CLEARED)\n+\t\t\tcdesc->event_type = cpu_to_be16(FPIN_CONGN_CLEAR);\n+\t\telse\n+\t\t\tcdesc->event_type = cpu_to_be16(FPIN_CONGN_DEVICE_SPEC);\n+\t\tcdesc->event_modifier = modifier;\n+\t\tcdesc->event_period = period;\n+\t\tcdesc->severity = FPIN_CONGN_SEVERITY_WARNING;\n+\t\tbreak;\n+\tcase IBMVFC_AE_FPIN_PORT_CONGESTED:\n+\tcase IBMVFC_AE_FPIN_PORT_CLEARED:\n+\t\tfpin->desc_len = cpu_to_be32(sizeof(struct fc_fn_peer_congn_desc));\n+\t\tpdesc = (struct fc_fn_peer_congn_desc *)fpin->fpin_desc;\n+\t\tpdesc->desc_tag = cpu_to_be32(ELS_DTAG_PEER_CONGEST);\n+\t\tpdesc->desc_len = cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*pdesc));\n+\t\tif (fpin_status == IBMVFC_AE_FPIN_PORT_CLEARED)\n+\t\t\tpdesc->event_type = cpu_to_be16(FPIN_CONGN_CLEAR);\n+\t\telse\n+\t\t\tpdesc->event_type = cpu_to_be16(FPIN_CONGN_DEVICE_SPEC);\n+\t\tpdesc->event_modifier = modifier;\n+\t\tpdesc->event_period = period;\n+\t\tpdesc->detecting_wwpn = cpu_to_be64(0);\n+\t\tpdesc->attached_wwpn = wwpn;\n+\t\tpdesc->pname_count = cpu_to_be32(1);\n+\t\tpdesc->pname_list[0] = wwpn;\n+\t\tbreak;\n+\tcase IBMVFC_AE_FPIN_PORT_DEGRADED:\n+\t\tfpin->desc_len = cpu_to_be32(sizeof(struct fc_fn_li_desc));\n+\t\tldesc = (struct fc_fn_li_desc *)fpin->fpin_desc;\n+\t\tldesc->desc_tag = cpu_to_be32(ELS_DTAG_LNK_INTEGRITY);\n+\t\tldesc->desc_len = cpu_to_be32(FC_TLV_DESC_LENGTH_FROM_SZ(*ldesc));\n+\t\tldesc->event_type = cpu_to_be16(FPIN_LI_UNKNOWN);\n+\t\tldesc->event_modifier = modifier;\n+\t\tldesc->event_threshold = threshold;\n+\t\tldesc->event_count = event_count;\n+\t\tldesc->detecting_wwpn = cpu_to_be64(0);\n+\t\tldesc->attached_wwpn = wwpn;\n+\t\tldesc->pname_count = cpu_to_be32(1);\n+\t\tldesc->pname_list[0] = wwpn;\n+\t\tbreak;\n+\tdefault:\n+\t\t/* This should be caught above. */\n+\t\tkfree(fpin);\n+\t\tfpin = NULL;\n+\t\tbreak;\n+\t}\n+\n+\treturn fpin;\n+}\n+\n+/**\n+ * ibmvfc_basic_fpin_to_desc(): allocate and populate a struct fc_els_fpin struct\n+ * containing a descriptor.\n+ * @ibmvfc_fpin: Pointer to async crq\n+ *\n+ * Allocate a struct fc_els_fpin containing a descriptor and populate\n+ * based on data from *ibmvfc_fpin.\n+ *\n+ * Return:\n+ * NULL     - unable to allocate structure\n+ * non-NULL - pointer to populated struct fc_els_fpin\n+ */\n+static struct fc_els_fpin *\n+/*XXX*/ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq *crq)\n+{\n+\treturn ibmvfc_common_fpin_to_desc(crq->fpin_status, crq->wwpn,\n+\t\t\t\t\t  cpu_to_be16(0),\n+\t\t\t\t\t  cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_PERIOD),\n+\t\t\t\t\t  cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD),\n+\t\t\t\t\t  cpu_to_be32(1));\n+}\n+\n /**\n  * ibmvfc_handle_async - Handle an async event from the adapter\n  * @crq:\tcrq to process\n  * @vhost:\tibmvfc host struct\n  *\n  **/\n-static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,\n-\t\t\t\tstruct ibmvfc_host *vhost)\n+VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,\n+\t\t\t\t\t  struct ibmvfc_host *vhost)\n {\n \tconst struct ibmvfc_async_desc *desc = ibmvfc_get_ae_desc(be64_to_cpu(crq->event));\n \tstruct ibmvfc_target *tgt;\n+\tstruct fc_els_fpin *fpin;\n \n \tibmvfc_log(vhost, desc->log_level, \"%s event received. scsi_id: %llx, wwpn: %llx,\"\n \t\t   \" node_name: %llx%s\\n\", desc->desc, be64_to_cpu(crq->scsi_id),\n@@ -3269,11 +3422,37 @@ static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq,\n \tcase IBMVFC_AE_HALT:\n \t\tibmvfc_link_down(vhost, IBMVFC_HALTED);\n \t\tbreak;\n+\tcase IBMVFC_AE_FPIN:\n+\t\tif (!crq->scsi_id && !crq->wwpn && !crq->node_name)\n+\t\t\tbreak;\n+\t\tlist_for_each_entry(tgt, &vhost->targets, queue) {\n+\t\t\tif (crq->scsi_id && cpu_to_be64(tgt->scsi_id) != crq->scsi_id)\n+\t\t\t\tcontinue;\n+\t\t\tif (crq->wwpn && cpu_to_be64(tgt->ids.port_name) != crq->wwpn)\n+\t\t\t\tcontinue;\n+\t\t\tif (crq->node_name && cpu_to_be64(tgt->ids.node_name) != crq->node_name)\n+\t\t\t\tcontinue;\n+\t\t\tif (!tgt->rport)\n+\t\t\t\tcontinue;\n+\t\t\tfpin = ibmvfc_basic_fpin_to_desc(crq);\n+\t\t\tif (fpin) {\n+\t\t\t\tfc_host_fpin_rcv(tgt->vhost->host,\n+\t\t\t\t\t\t sizeof(*fpin) +\n+\t\t\t\t\t\t       be32_to_cpu(fpin->desc_len),\n+\t\t\t\t\t\t (char *)fpin, 0);\n+\t\t\t\tkfree(fpin);\n+\t\t\t} else\n+\t\t\t\tdev_err(vhost->dev,\n+\t\t\t\t\t\"FPIN event %u received, unable to process\\n\",\n+\t\t\t\t\tcrq->fpin_status);\n+\t\t}\n+\t\tbreak;\n \tdefault:\n \t\tdev_err(vhost->dev, \"Unknown async event received: %lld\\n\", crq->event);\n \t\tbreak;\n \t}\n }\n+EXPORT_SYMBOL_IF_KUNIT(ibmvfc_handle_async);\n \n /**\n  * ibmvfc_handle_crq - Handles and frees received events in the CRQ\n@@ -6603,5 +6782,11 @@ static void __exit ibmvfc_module_exit(void)\n \tfc_release_transport(ibmvfc_transport_template);\n }\n \n+VISIBLE_IF_KUNIT struct list_head *ibmvfc_get_headp(void)\n+{\n+\treturn &ibmvfc_head;\n+}\n+EXPORT_SYMBOL_IF_KUNIT(ibmvfc_get_headp);\n+\n module_init(ibmvfc_module_init);\n module_exit(ibmvfc_module_exit);\ndiff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h\nindex c73ed2314ad0..29932284a4c9 100644\n--- a/drivers/scsi/ibmvscsi/ibmvfc.h\n+++ b/drivers/scsi/ibmvscsi/ibmvfc.h\n@@ -671,8 +671,12 @@ enum ibmvfc_ae_fpin_status {\n \tIBMVFC_AE_FPIN_PORT_CONGESTED\t= 0x2,\n \tIBMVFC_AE_FPIN_PORT_CLEARED\t= 0x3,\n \tIBMVFC_AE_FPIN_PORT_DEGRADED\t= 0x4,\n+\tIBMVFC_AE_FPIN_CONGESTION_CLEARED\t= 0x5,\n };\n \n+#define IBMVFC_FPIN_DEFAULT_EVENT_PERIOD\t(5*60*MSEC_PER_SEC) /* 5 minutes */\n+#define IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD\t(5*60*MSEC_PER_SEC/2) /* 2.5 minutes */\n+\n struct ibmvfc_async_crq {\n \tvolatile u8 valid;\n \tu8 link_state;\n@@ -953,4 +957,9 @@ struct ibmvfc_host {\n #define ibmvfc_remove_trace_file(kobj, attr) do { } while (0)\n #endif\n \n+#ifdef VISIBLE_IF_KUNIT\n+VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, struct ibmvfc_host *vhost);\n+VISIBLE_IF_KUNIT struct list_head *ibmvfc_get_headp(void);\n+#endif\n+\n #endif\ndiff --git a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c\nnew file mode 100644\nindex 000000000000..1c238896049f\n--- /dev/null\n+++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c\n@@ -0,0 +1,95 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+#include <kunit/test.h>\n+#include <kunit/visibility.h>\n+#include <scsi/scsi_device.h>\n+#include <scsi/scsi_transport_fc.h>\n+#include <linux/list.h>\n+#include \"ibmvfc.h\"\n+\n+MODULE_IMPORT_NS(\"EXPORTED_FOR_KUNIT_TESTING\");\n+\n+/**\n+ * ibmvfc_handle_fpin_event_test - unit test for IBMVFC_AE_FPIN parts of\n+ * ibmvfc_handle_async\n+ * @test: pointer to kunit structure\n+ *\n+ * Tests\n+ * - error returns from ibmvfc_handle_async\n+ * - statistics updates\n+ *\n+ * Return: void\n+ */\n+static void ibmvfc_handle_fpin_event_test(struct kunit *test)\n+{\n+\tu64 *stats[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1] = { NULL };\n+\tu64 post[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1];\n+\tu64 pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1];\n+\tenum ibmvfc_ae_fpin_status fs;\n+\tstruct ibmvfc_async_crq crq;\n+\tstruct ibmvfc_target *tgt;\n+\tstruct ibmvfc_host *vhost;\n+\tstruct list_head *queue;\n+\tstruct list_head *headp;\n+\n+\n+\theadp = ibmvfc_get_headp();\n+\tKUNIT_ASSERT_NOT_NULL(test, headp);\n+\tqueue = headp->next;\n+\tKUNIT_ASSERT_PTR_NE(test, queue, headp);\n+\tvhost = container_of(queue, struct ibmvfc_host, queue);\n+\n+\tKUNIT_EXPECT_GE(test, vhost->num_targets, 1);\n+\ttgt = list_first_entry(&vhost->targets, struct ibmvfc_target, queue);\n+\tKUNIT_EXPECT_NOT_NULL(test, tgt->rport);\n+\n+\tstats[IBMVFC_AE_FPIN_LINK_CONGESTED] = &tgt->rport->fpin_stats.cn;\n+\tstats[IBMVFC_AE_FPIN_PORT_CONGESTED] = &tgt->rport->fpin_stats.cn;\n+\tstats[IBMVFC_AE_FPIN_PORT_CLEARED] = &tgt->rport->fpin_stats.cn_clear;\n+\tstats[IBMVFC_AE_FPIN_CONGESTION_CLEARED] = &tgt->rport->fpin_stats.cn_clear;\n+\tstats[IBMVFC_AE_FPIN_PORT_DEGRADED] = &tgt->rport->fpin_stats.li;\n+\n+\tfor (fs = IBMVFC_AE_FPIN_LINK_CONGESTED; fs <= IBMVFC_AE_FPIN_CONGESTION_CLEARED; fs++) {\n+\t\tcrq.valid = 0x80;\n+\t\tcrq.link_state = IBMVFC_AE_LS_LINK_UP;\n+\t\tcrq.fpin_status = fs;\n+\t\tcrq.event = cpu_to_be64(IBMVFC_AE_FPIN);\n+\t\tcrq.scsi_id = cpu_to_be64(tgt->scsi_id);\n+\t\tcrq.wwpn = cpu_to_be64(tgt->wwpn);\n+\t\tcrq.node_name = cpu_to_be64(tgt->ids.node_name);\n+\t\tpre[fs] = *stats[fs];\n+\t\tibmvfc_handle_async(&crq, vhost);\n+\t\tpost[fs] = *stats[fs];\n+\t\tKUNIT_EXPECT_EQ(test, post[fs], pre[fs]+1);\n+\t}\n+\n+\t/* bad path */\n+\tfor (fs = IBMVFC_AE_FPIN_LINK_CONGESTED; fs <= IBMVFC_AE_FPIN_CONGESTION_CLEARED; fs++)\n+\t\tpre[fs] = *stats[fs];\n+\tcrq.valid = 0x80;\n+\tcrq.link_state = IBMVFC_AE_LS_LINK_UP;\n+\tcrq.fpin_status = 0; /* bad value */\n+\tcrq.event = cpu_to_be64(IBMVFC_AE_FPIN);\n+\tcrq.scsi_id = cpu_to_be64(tgt->scsi_id);\n+\tcrq.wwpn = cpu_to_be64(tgt->wwpn);\n+\tcrq.node_name = cpu_to_be64(tgt->ids.node_name);\n+\tibmvfc_handle_async(&crq, vhost);\n+\tfor (fs = IBMVFC_AE_FPIN_LINK_CONGESTED; fs <= IBMVFC_AE_FPIN_CONGESTION_CLEARED; fs++) {\n+\t\tpost[fs] = *stats[fs];\n+\t\tKUNIT_EXPECT_EQ(test, pre[fs], post[fs]);\n+\t}\n+}\n+\n+static struct kunit_case ibmvfc_fpin_test_cases[] = {\n+\tKUNIT_CASE(ibmvfc_handle_fpin_event_test),\n+\t{},\n+};\n+\n+static struct kunit_suite ibmvfc_fpin_test_suite = {\n+\t.name = \"ibmvfc-fpin-test\",\n+\t.test_cases = ibmvfc_fpin_test_cases,\n+};\n+kunit_test_init_section_suite(ibmvfc_fpin_test_suite);\n+\n+MODULE_LICENSE(\"GPL\");\n+MODULE_AUTHOR(\"Dave Marquardt <davemarq@linux.ibm.com>\");\n+MODULE_DESCRIPTION(\"Test module for IBM Virtual Fibre Channel Driver\");\n",
    "prefixes": [
        "1/5"
    ]
}