From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (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 A73DB3A4521; Fri, 11 Sep 2026 05:48:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.163.156.1 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789105737; cv=none; b=NQ8ETpmW2NClW4iOZNgna0mh9zwHEQJDzn03waiisMvyUzgmPTHPuCQM35rJ/ht3v/Wew2Nqs5okaVZ0oYD/fX1Bg2d2Bld89vPiMSKDsKoAZYGXr7foBepyLQcxFO5TEg25TcohyH/0FbcNguac8z4GtgC+7NfzrCuNR5m/oSs= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789105737; c=relaxed/simple; bh=AlpUAzVWXGPH8pKQr+lJetqHE3DRm1z450tG0ZitdNA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W4c/N8QcRvX7hwz2WnIWl8/ibfgkDPtuzLzw5bLAEVC/HC9n2Kak5BU4pDstFGKiWfWRH5ztat1G/aJVQBKLiCRWgeAY9pHgvDRAf/cZ/NcjMRIJhEdFqwtfNNsd4LCP9oLtQCZV4blgnK4HVL9w6Aqc5bBZCV1uxtD54Z8ZtA8= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com; spf=pass smtp.mailfrom=linux.ibm.com; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b=QosNU02l; arc=none smtp.client-ip=148.163.156.1 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.ibm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=ibm.com header.i=@ibm.com header.b="QosNU02l" Received: from pps.filterd (m0353729.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 68B4VT4q3104516; Fri, 11 Sep 2026 05:48:41 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=ibm.com; h=cc :content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=pp1; bh=erJa6tbdZ9iRtaxRC CeehSEpav1G5CFxWCJc9TIvjR4=; b=QosNU02lgyhMzVGS7HRU4A5U9kYcMZYkA f6iyJq2e4pAr11gP9NFbtCsHxvpDvvIisMdnIE3AKg3osPCmJgExGRKfToUpD7wk c/OO0lPK57mzsi6AHJKmt2GSz1bU1ROv1Tg4xEaqh4cF+YW+ibAQvHAZ3kwqeDiG lill8I2n5L2cXRGWyxZtVHg4BzQ3rbKeY4zxftXjJRInCrVA7rhNA+KaMteXUqQE ssZwKYmJfVClReeAE6xs916p5YZVFUTE3DteCf+9QMG7AgK5B4tkGWCfDAkx7Jfu wUdISSit+Hnd6W9KHf8y7ZJ7nLIDG7O25b3P7s4xsOknsqb55rGiA== Received: from ppma12.dal12v.mail.ibm.com (dc.9e.1632.ip4.static.sl-reverse.com [50.22.158.220]) by mx0a-001b2d01.pphosted.com (PPS) with ESMTPS id 4gkd8n9hpp-1 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Fri, 11 Sep 2026 05:48:41 +0000 (GMT) Received: from pps.filterd (ppma12.dal12v.mail.ibm.com [127.0.0.1]) by ppma12.dal12v.mail.ibm.com (8.18.1.11/8.18.1.11) with ESMTP id 68B4K3WG1101917; Fri, 11 Sep 2026 05:48:40 GMT Received: from smtprelay04.dal12v.mail.ibm.com ([172.16.1.6]) by ppma12.dal12v.mail.ibm.com (PPS) with ESMTPS id 4gkvnrmkrv-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 11 Sep 2026 05:48:40 +0000 (GMT) Received: from smtpav02.dal12v.mail.ibm.com (smtpav02.dal12v.mail.ibm.com [10.241.53.101]) by smtprelay04.dal12v.mail.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 68B5mdMj27132576 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 11 Sep 2026 05:48:39 GMT Received: from smtpav02.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B076D5805C; Fri, 11 Sep 2026 05:48:39 +0000 (GMT) Received: from smtpav02.dal12v.mail.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 128275805A; Fri, 11 Sep 2026 05:48:39 +0000 (GMT) Received: from li-4c4c4544-0054-3910-8039-c3c04f423534.ibm.com.com (unknown [9.61.103.123]) by smtpav02.dal12v.mail.ibm.com (Postfix) with ESMTP; Fri, 11 Sep 2026 05:48:38 +0000 (GMT) From: Tyrel Datwyler To: james.bottomley@hansenpartnership.com, martin.petersen@oracle.com Cc: linux-scsi@vger.kernel.org, linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org, brking@linux.ibm.com, davemarq@linux.ibm.com, Tyrel Datwyler Subject: [PATCH v10 4/9] scsi: ibmvfc: extend async event handlers for async sub-CRQ events Date: Thu, 10 Sep 2026 22:48:27 -0700 Message-ID: <20260911054832.1311668-5-tyreld@linux.ibm.com> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260911054832.1311668-1-tyreld@linux.ibm.com> References: <20260911054832.1311668-1-tyreld@linux.ibm.com> Precedence: bulk X-Mailing-List: linux-scsi@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-TM-AS-GCONF: 00 X-Authority-Analysis: v=2.4 cv=NMVAaE6g c=1 sm=1 tr=0 ts=6aa39639 cx=c_pps a=bLidbwmWQ0KltjZqbj+ezA==:117 a=bLidbwmWQ0KltjZqbj+ezA==:17 a=VdqzKS8jKosA:10 a=VkNPw1HP01LnGYTKEx00:22 a=RnoormkPH1_aCDwRdu11:22 a=uAbxVGIbfxUO_5tXvNgY:22 a=VnNF1IyMAAAA:8 a=iW4PeHjXF5vBxW_ITg0A:9 X-Proofpoint-GUID: wossEmEjdPHzicVUrXQ3K5uUqvsmUKoh X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwOTExMDA3NCBTYWx0ZWRfX5CfytU2t9kwh yS4xCaa4Mr5A7MwYK/doQE2VTdx7VVvNh4U7htMyP7tt3e5a7MiLLQ3F5iNvUfqK88YgRLLRvZe 3WBsDX3f+tNdFjOF3xuBS5MPuoVs55GEjn7tQ6MyeRkGTaMZOEXjetxSW4DR3ryijwMw56WVIwg cL8D4qxNBApj8FwX5gjxAXLP/SESH3qvAGKj14n9o5CaP45no5dTXU1ml3aw+Z6k5cse6gL9VAO 3P8K9dVwA4XTXX+8ShI59cTWHYGqx+XAsyRBjXnKIY/jEI4KXgB11fTWM3XFJqScWCWHyXVF7Nu 460IpM8YMRJDCocwX9erL5igJjIHoIcpR02vlPwxE/PpbJMe9Zb6s2yiycuhrBleAJ+VeLJRwy5 oXVh2+fo9e9gf5X4MyRv6cEGb0bOaJpRqzkRy5hXR3bxy+M5skQx0B8n4RRavtQYkXzfxA2KXrt YWHuSoXkMjdq6CNAnyQ== X-Proofpoint-ORIG-GUID: wossEmEjdPHzicVUrXQ3K5uUqvsmUKoh X-Proofpoint-Spam-Info: AW1haW4tMjYwOTExMDA3NCBTYWx0ZWRfX0WgNm6aUjyL+ iwFzmN28UptHH7/lJ1faR6vdBw9odh9ll+FLYieKjeRTYQhUlJWmuVLuAiXD9S8LfnmZYFl8Wft GKrtVmU8jOFCuSzRLkrex0ksZBgdDTY= X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1176,Hydra:6.1.134,FMLib:17.12.100.49 definitions=2026-09-11_02,2026-09-09_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 spamscore=0 bulkscore=0 clxscore=1015 malwarescore=0 lowpriorityscore=0 priorityscore=1501 adultscore=0 suspectscore=0 impostorscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2609040000 definitions=main-2609110074 From: Dave Marquardt Refactor async event handling to support both traditional async CRQs and new asynchronous sub-queue CRQs. Introduce struct ibmvfc_async_crq_event, a tagged union that wraps either an ibmvfc_async_crq (main CRQ) or an ibmvfc_async_sub_crq (async sub-CRQ), with an enum ibmvfc_async_crq_type discriminator. Replace the ibmvfc_async_work bare union and is_subq bool with a single event field of this type. Modify ibmvfc_handle_async() to accept a struct ibmvfc_async_crq_event * instead of a void * plus a bool flag. Update ibmvfc_process_async_work() to dispatch based on event.type. Add ibmvfc_full_fpin_to_desc() to convert full FPIN messages from async sub-queue format to fc_els_fpin structures. Update FPIN processing logic to extract WWPN, node_name, and scsi_id from the appropriate union member based on event type. Update KUnit tests to use struct ibmvfc_async_crq_event arrays at call sites. Signed-off-by: Dave Marquardt [tyreld: added & operator to irqsave/restore calls] [tyreld: updated main crq unit test to use new async event union type] Signed-off-by: Tyrel Datwyler --- drivers/scsi/ibmvscsi/ibmvfc-core.c | 163 +++++++++++++++++++++------ drivers/scsi/ibmvscsi/ibmvfc.h | 18 ++- drivers/scsi/ibmvscsi/ibmvfc_kunit.c | 161 +++++++++++++++++++++++--- 3 files changed, 285 insertions(+), 57 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c b/drivers/scsi/ibmvscsi/ibmvfc-core.c index 7ea64956653e..9b66b45871b1 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc-core.c +++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c @@ -3426,6 +3426,45 @@ ibmvfc_basic_fpin_to_desc(struct ibmvfc_async_crq *crq, u64 wwpn) 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_sub_crq *ibmvfc_fpin) +{ + __be16 type; + + switch (ibmvfc_fpin->fpin_status) { + case IBMVFC_AE_FPIN_LINK_CONGESTED: + case IBMVFC_AE_FPIN_PORT_CONGESTED: + type = cpu_to_be16(FPIN_CONGN_DEVICE_SPEC); + break; + case IBMVFC_AE_FPIN_PORT_CLEARED: + case IBMVFC_AE_FPIN_CONGESTION_CLEARED: + type = cpu_to_be16(FPIN_CONGN_CLEAR); + break; + case IBMVFC_AE_FPIN_PORT_DEGRADED: + type = cpu_to_be16(FPIN_LI_UNKNOWN); + break; + default: + return NULL; + } + + return ibmvfc_common_fpin_to_desc(ibmvfc_fpin->fpin_status, ibmvfc_fpin->wwpn, + type, cpu_to_be16(0), + cpu_to_be32(IBMVFC_FPIN_DEFAULT_EVENT_THRESHOLD), + cpu_to_be32(1)); +} + /** * ibmvfc_find_target - Search for a target in a target list * @target_list: list head of targets to search @@ -3463,28 +3502,40 @@ static struct ibmvfc_target *ibmvfc_find_target(struct list_head *target_list, */ static void ibmvfc_process_async_work(struct work_struct *work) { + struct ibmvfc_async_sub_crq *subq = NULL; struct ibmvfc_async_work *aw; - struct ibmvfc_async_crq *crq; + struct ibmvfc_async_crq *crq = NULL; struct ibmvfc_target *tgt; struct ibmvfc_host *vhost; - struct fc_els_fpin *fpin; + struct fc_els_fpin *fpin = NULL; unsigned long flags; + __be64 node_name; + __be64 scsi_id; + __be64 wwpn; aw = container_of_const(work, struct ibmvfc_async_work, async_work_s); vhost = aw->vhost; - crq = &aw->crq; + if (aw->event.type == IBMVFC_ASYNC_CRQ_SUB) { + subq = &aw->event.subq; + scsi_id = 0; + wwpn = subq->wwpn; + node_name = (subq->flags & IBMVFC_ASYNC_ID_IS_ASSOC_ID) ? 0 : subq->id.node_name; + } else { + crq = &aw->event.async_crq; + scsi_id = crq->scsi_id; + wwpn = crq->wwpn; + node_name = crq->node_name; + } - if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + if (!scsi_id && !wwpn && !node_name) goto free; spin_lock_irqsave(&vhost->host->host_lock, flags); - tgt = ibmvfc_find_target(&vhost->scsi_scrqs.targets, crq->scsi_id, - crq->wwpn, crq->node_name); + tgt = ibmvfc_find_target(&vhost->scsi_scrqs.targets, scsi_id, wwpn, node_name); + if (!tgt) { /* Target not found in scsi_scrqs, search nvme_scrqs */ - tgt = ibmvfc_find_target(&vhost->nvme_scrqs.targets, - crq->scsi_id, crq->wwpn, - crq->node_name); + tgt = ibmvfc_find_target(&vhost->nvme_scrqs.targets, scsi_id, wwpn, node_name); } if (tgt) { @@ -3496,7 +3547,11 @@ static void ibmvfc_process_async_work(struct work_struct *work) goto free; } - fpin = ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn); + if (crq) + fpin = ibmvfc_basic_fpin_to_desc(crq, tgt->wwpn); + else + fpin = ibmvfc_full_fpin_to_desc(subq); + if (fpin) { fc_host_fpin_rcv(tgt->vhost->host, sizeof(*fpin) + be32_to_cpu(fpin->desc_len), @@ -3512,25 +3567,51 @@ static void ibmvfc_process_async_work(struct work_struct *work) /** * ibmvfc_handle_async - Handle an async event from the adapter - * @crq: crq to process + * @ae: tagged union wrapping either an ibmvfc_async_crq (main CRQ) or an + * ibmvfc_async_sub_crq (async sub-CRQ); the type field identifies which * @vhost: ibmvfc host struct * **/ -VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, +VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq_event *ae, struct ibmvfc_host *vhost) { - const struct ibmvfc_async_desc *desc = ibmvfc_get_ae_desc(be64_to_cpu(crq->event)); + struct ibmvfc_async_crq *async_crq = NULL; + struct ibmvfc_async_sub_crq *subq = NULL; + const struct ibmvfc_async_desc *desc; struct ibmvfc_async_work *aw; struct ibmvfc_target *tgt; - - ibmvfc_log(vhost, desc->log_level, "%s event received. scsi_id: %llx, 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)); - - switch (be64_to_cpu(crq->event)) { + __be64 node_name; + __be64 scsi_id; + u8 link_state; + __be64 wwpn; + u64 event; + + if (ae->type == IBMVFC_ASYNC_CRQ_SUB) { + subq = &ae->subq; + event = be16_to_cpu(subq->event); + link_state = subq->link_state; + scsi_id = 0; + wwpn = subq->wwpn; + node_name = subq->flags & IBMVFC_ASYNC_ID_IS_ASSOC_ID ? 0 : subq->id.node_name; + } else { + async_crq = &ae->async_crq; + event = be64_to_cpu(async_crq->event); + link_state = async_crq->link_state; + scsi_id = async_crq->scsi_id; + wwpn = async_crq->wwpn; + node_name = async_crq->node_name; + } + + desc = ibmvfc_get_ae_desc(event); + ibmvfc_log(vhost, desc->log_level, + "%s event received. scsi_id: %llx, wwpn: %llx, node_name: %llx, event %llx%s\n", + desc->desc, be64_to_cpu(scsi_id), + be64_to_cpu(wwpn), be64_to_cpu(node_name), event, + ibmvfc_get_link_state(link_state)); + + switch (event) { case IBMVFC_AE_RESUME: - switch (crq->link_state) { + switch (link_state) { case IBMVFC_AE_LS_LINK_DOWN: ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); break; @@ -3569,33 +3650,33 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, case IBMVFC_AE_ELS_PRLO: case IBMVFC_AE_ELS_PLOGI: list_for_each_entry(tgt, &vhost->scsi_scrqs.targets, queue) { - if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + if (!scsi_id && !wwpn && !node_name) break; - if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) != crq->scsi_id) + if (scsi_id && cpu_to_be64(tgt->scsi_id) != scsi_id) continue; - if (crq->wwpn && cpu_to_be64(tgt->ids.port_name) != crq->wwpn) + if (wwpn && cpu_to_be64(tgt->ids.port_name) != wwpn) continue; - if (crq->node_name && cpu_to_be64(tgt->ids.node_name) != crq->node_name) + if (node_name && cpu_to_be64(tgt->ids.node_name) != node_name) continue; - if (tgt->need_login && be64_to_cpu(crq->event) == IBMVFC_AE_ELS_LOGO) + if (tgt->need_login && event == IBMVFC_AE_ELS_LOGO) tgt->logo_rcvd = 1; - if (!tgt->need_login || be64_to_cpu(crq->event) == IBMVFC_AE_ELS_PLOGI) { + if (!tgt->need_login || event == IBMVFC_AE_ELS_PLOGI) { ibmvfc_del_tgt(tgt); ibmvfc_reinit_host(vhost); } } list_for_each_entry(tgt, &vhost->nvme_scrqs.targets, queue) { - if (!crq->scsi_id && !crq->wwpn && !crq->node_name) + if (!scsi_id && !wwpn && !node_name) break; - if (crq->scsi_id && cpu_to_be64(tgt->scsi_id) != crq->scsi_id) + if (scsi_id && cpu_to_be64(tgt->scsi_id) != scsi_id) continue; - if (crq->wwpn && cpu_to_be64(tgt->ids.port_name) != crq->wwpn) + if (wwpn && cpu_to_be64(tgt->ids.port_name) != wwpn) continue; - if (crq->node_name && cpu_to_be64(tgt->ids.node_name) != crq->node_name) + if (node_name && cpu_to_be64(tgt->ids.node_name) != node_name) continue; - if (tgt->need_login && be64_to_cpu(crq->event) == IBMVFC_AE_ELS_LOGO) + if (tgt->need_login && event == IBMVFC_AE_ELS_LOGO) tgt->logo_rcvd = 1; - if (!tgt->need_login || be64_to_cpu(crq->event) == IBMVFC_AE_ELS_PLOGI) { + if (!tgt->need_login || event == IBMVFC_AE_ELS_PLOGI) { ibmvfc_del_tgt(tgt); ibmvfc_reinit_host(vhost); } @@ -3616,14 +3697,14 @@ VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, if (aw) { INIT_WORK(&aw->async_work_s, ibmvfc_process_async_work); aw->vhost = vhost; - aw->crq = *crq; + aw->event = *ae; queue_work(vhost->fpin_workq, &aw->async_work_s); } else dev_err_ratelimited(vhost->dev, "can't offload async CRQ to work queue\n"); break; default: - dev_err(vhost->dev, "Unknown async event received: %lld\n", crq->event); + dev_err(vhost->dev, "Unknown async event received: %llu\n", event); break; } } @@ -4164,7 +4245,11 @@ static void ibmvfc_tasklet(void *data) while (!done) { /* Pull all the valid messages off the async CRQ */ while ((async = ibmvfc_next_async_crq(vhost)) != NULL) { - ibmvfc_handle_async(async, vhost); + struct ibmvfc_async_crq_event ae = { + .type = IBMVFC_ASYNC_CRQ_MAIN, + .async_crq = *async, + }; + ibmvfc_handle_async(&ae, vhost); async->valid = 0; wmb(); } @@ -4178,8 +4263,12 @@ static void ibmvfc_tasklet(void *data) vio_enable_interrupts(vdev); if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { + struct ibmvfc_async_crq_event ae = { + .type = IBMVFC_ASYNC_CRQ_MAIN, + .async_crq = *async, + }; vio_disable_interrupts(vdev); - ibmvfc_handle_async(async, vhost); + ibmvfc_handle_async(&ae, vhost); async->valid = 0; wmb(); } else if ((crq = ibmvfc_next_crq(vhost)) != NULL) { diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h index a8a063d99564..6fce7a4922bb 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.h +++ b/drivers/scsi/ibmvscsi/ibmvfc.h @@ -786,9 +786,22 @@ struct ibmvfc_async_sub_crq { } id; } __packed __aligned(8); +enum ibmvfc_async_crq_type { + IBMVFC_ASYNC_CRQ_MAIN = 0, + IBMVFC_ASYNC_CRQ_SUB, +}; + +struct ibmvfc_async_crq_event { + enum ibmvfc_async_crq_type type; + union { + struct ibmvfc_async_crq async_crq; + struct ibmvfc_async_sub_crq subq; + }; +}; + struct ibmvfc_async_work { struct ibmvfc_host *vhost; - struct ibmvfc_async_crq crq; + struct ibmvfc_async_crq_event event; struct work_struct async_work_s; }; @@ -1103,7 +1116,8 @@ static inline struct ibmvfc_host *ibmvfc_channels_to_vhost(struct ibmvfc_channel #if IS_ENABLED(CONFIG_KUNIT) #include -VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, struct ibmvfc_host *vhost); +VISIBLE_IF_KUNIT void ibmvfc_handle_async(struct ibmvfc_async_crq_event *event, + struct ibmvfc_host *vhost); VISIBLE_IF_KUNIT struct ibmvfc_host *ibmvfc_get_first_vhost(void); #endif diff --git a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c index 67bd3922a49f..5c67d405dbfc 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c +++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include "ibmvfc.h" @@ -25,7 +24,9 @@ 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]; - struct ibmvfc_async_crq ae[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1]; + struct ibmvfc_async_crq_event ae[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1] = { + [0 ... IBMVFC_AE_FPIN_CONGESTION_CLEARED] = { .type = IBMVFC_ASYNC_CRQ_MAIN }, + }; enum ibmvfc_ae_fpin_status fs; struct fc_host_attrs *fc_host; struct ibmvfc_target *tgt; @@ -63,15 +64,15 @@ static void ibmvfc_async_fpin_test(struct kunit *test) pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] = READ_ONCE(fc_host->fpin_stats.cn_clear); for (fs = IBMVFC_AE_FPIN_LINK_CONGESTED; fs <= IBMVFC_AE_FPIN_CONGESTION_CLEARED; fs++) { - ae[fs].valid = 0x80; - ae[fs].link_state = IBMVFC_AE_LS_LINK_UP; - ae[fs].fpin_status = fs; - ae[fs].event = cpu_to_be64(IBMVFC_AE_FPIN); - ae[fs].scsi_id = cpu_to_be64(tgt->scsi_id); - ae[fs].wwpn = cpu_to_be64(tgt->wwpn); - ae[fs].node_name = cpu_to_be64(tgt->ids.node_name); + ae[fs].async_crq.valid = 0x80; + ae[fs].async_crq.link_state = IBMVFC_AE_LS_LINK_UP; + ae[fs].async_crq.fpin_status = fs; + ae[fs].async_crq.event = cpu_to_be64(IBMVFC_AE_FPIN); + ae[fs].async_crq.scsi_id = cpu_to_be64(tgt->scsi_id); + ae[fs].async_crq.wwpn = cpu_to_be64(tgt->wwpn); + ae[fs].async_crq.node_name = cpu_to_be64(tgt->ids.node_name); ibmvfc_handle_async(&ae[fs], vhost); - ae[fs].valid = 0; + ae[fs].async_crq.valid = 0; wmb(); /* ensure valid bit clear is visible before checking stats */ } flush_workqueue(vhost->fpin_workq); @@ -100,15 +101,15 @@ static void ibmvfc_async_fpin_test(struct kunit *test) pre[IBMVFC_AE_FPIN_PORT_DEGRADED] = READ_ONCE(rport->fpin_stats.li_failure_unknown); pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] = READ_ONCE(fc_host->fpin_stats.cn_clear); - ae[0].valid = 0x80; - ae[0].link_state = IBMVFC_AE_LS_LINK_UP; - ae[0].fpin_status = 0; /* bad value */ - ae[0].event = cpu_to_be64(IBMVFC_AE_FPIN); - ae[0].scsi_id = cpu_to_be64(tgt->scsi_id); - ae[0].wwpn = cpu_to_be64(tgt->wwpn); - ae[0].node_name = cpu_to_be64(tgt->ids.node_name); + ae[0].async_crq.valid = 0x80; + ae[0].async_crq.link_state = IBMVFC_AE_LS_LINK_UP; + ae[0].async_crq.fpin_status = 0; /* bad value */ + ae[0].async_crq.event = cpu_to_be64(IBMVFC_AE_FPIN); + ae[0].async_crq.scsi_id = cpu_to_be64(tgt->scsi_id); + ae[0].async_crq.wwpn = cpu_to_be64(tgt->wwpn); + ae[0].async_crq.node_name = cpu_to_be64(tgt->ids.node_name); ibmvfc_handle_async(&ae[0], vhost); - ae[0].valid = 0; + ae[0].async_crq.valid = 0; wmb(); /* ensure valid bit clear is visible before checking stats */ flush_workqueue(vhost->fpin_workq); @@ -132,8 +133,132 @@ static void ibmvfc_async_fpin_test(struct kunit *test) kref_put(&tgt->kref, ibmvfc_release_tgt); } +/** + * ibmvfc_full_fpin_test - unit test for IBMVFC_AE_FPIN parts of ibmvfc_handle_async + * @test: pointer to kunit structure + * + * Tests + * - error returns from ibmvfc_handle_async + * - statistics updates + * + * Return: void + */ +static void ibmvfc_full_fpin_test(struct kunit *test) +{ + u64 post[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1]; + u64 pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1]; + struct ibmvfc_async_crq_event ae[IBMVFC_AE_FPIN_CONGESTION_CLEARED + 1] = { + [0 ... IBMVFC_AE_FPIN_CONGESTION_CLEARED] = { .type = IBMVFC_ASYNC_CRQ_SUB }, + }; + enum ibmvfc_ae_fpin_status fs; + struct fc_host_attrs *fc_host; + struct ibmvfc_target *tgt; + struct ibmvfc_host *vhost; + struct fc_rport *rport; + unsigned long flags; + + vhost = ibmvfc_get_first_vhost(); + if (!vhost) + kunit_skip(test, "No ibmvfc devices available"); + + spin_lock_irqsave(&vhost->host->host_lock, flags); + if (vhost->scsi_scrqs.num_targets < 1) { + spin_unlock_irqrestore(&vhost->host->host_lock, flags); + scsi_host_put(vhost->host); + kunit_skip(test, "No targets"); + } + tgt = list_first_entry(&vhost->scsi_scrqs.targets, struct ibmvfc_target, queue); + if (!tgt->rport) { + spin_unlock_irqrestore(&vhost->host->host_lock, flags); + scsi_host_put(vhost->host); + kunit_skip(test, "No rport"); + } + rport = tgt->rport; + get_device(&rport->dev); + kref_get(&tgt->kref); + spin_unlock_irqrestore(&vhost->host->host_lock, flags); + + fc_host = shost_to_fc_host(vhost->host); + + pre[IBMVFC_AE_FPIN_LINK_CONGESTED] = READ_ONCE(fc_host->fpin_stats.cn_device_specific); + pre[IBMVFC_AE_FPIN_PORT_CONGESTED] = READ_ONCE(rport->fpin_stats.cn_device_specific); + pre[IBMVFC_AE_FPIN_PORT_CLEARED] = READ_ONCE(rport->fpin_stats.cn_clear); + pre[IBMVFC_AE_FPIN_PORT_DEGRADED] = READ_ONCE(rport->fpin_stats.li_failure_unknown); + pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] = READ_ONCE(fc_host->fpin_stats.cn_clear); + + for (fs = IBMVFC_AE_FPIN_LINK_CONGESTED; fs <= IBMVFC_AE_FPIN_CONGESTION_CLEARED; fs++) { + ae[fs].subq.valid = 0x80; + ae[fs].subq.link_state = IBMVFC_AE_LS_LINK_UP; + ae[fs].subq.fpin_status = fs; + ae[fs].subq.event = cpu_to_be16(IBMVFC_AE_FPIN); + ae[fs].subq.wwpn = cpu_to_be64(tgt->wwpn); + ae[fs].subq.id.node_name = cpu_to_be64(tgt->ids.node_name); + ibmvfc_handle_async(&ae[fs], vhost); + ae[fs].subq.valid = 0; + wmb(); /* ensure valid bit clear is visible before checking stats */ + } + flush_workqueue(vhost->fpin_workq); + + post[IBMVFC_AE_FPIN_LINK_CONGESTED] = READ_ONCE(fc_host->fpin_stats.cn_device_specific); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] = READ_ONCE(rport->fpin_stats.cn_device_specific); + post[IBMVFC_AE_FPIN_PORT_CLEARED] = READ_ONCE(rport->fpin_stats.cn_clear); + post[IBMVFC_AE_FPIN_PORT_DEGRADED] = READ_ONCE(rport->fpin_stats.li_failure_unknown); + post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] = 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); + + /* bad path */ + pre[IBMVFC_AE_FPIN_LINK_CONGESTED] = READ_ONCE(fc_host->fpin_stats.cn_device_specific); + pre[IBMVFC_AE_FPIN_PORT_CONGESTED] = READ_ONCE(rport->fpin_stats.cn_device_specific); + pre[IBMVFC_AE_FPIN_PORT_CLEARED] = READ_ONCE(rport->fpin_stats.cn_clear); + pre[IBMVFC_AE_FPIN_PORT_DEGRADED] = READ_ONCE(rport->fpin_stats.li_failure_unknown); + pre[IBMVFC_AE_FPIN_CONGESTION_CLEARED] = READ_ONCE(fc_host->fpin_stats.cn_clear); + + ae[0].subq.valid = 0x80; + ae[0].subq.link_state = IBMVFC_AE_LS_LINK_UP; + ae[0].subq.fpin_status = 0; /* bad value */ + ae[0].subq.event = cpu_to_be16(IBMVFC_AE_FPIN); + ae[0].subq.wwpn = cpu_to_be64(tgt->wwpn); + ae[0].subq.id.node_name = cpu_to_be64(tgt->ids.node_name); + ibmvfc_handle_async(&ae[0], vhost); + ae[0].subq.valid = 0; + wmb(); /* ensure valid bit clear is visible before checking stats */ + flush_workqueue(vhost->fpin_workq); + + post[IBMVFC_AE_FPIN_LINK_CONGESTED] = READ_ONCE(fc_host->fpin_stats.cn_device_specific); + post[IBMVFC_AE_FPIN_PORT_CONGESTED] = READ_ONCE(rport->fpin_stats.cn_device_specific); + post[IBMVFC_AE_FPIN_PORT_CLEARED] = READ_ONCE(rport->fpin_stats.cn_clear); + post[IBMVFC_AE_FPIN_PORT_DEGRADED] = READ_ONCE(rport->fpin_stats.li_failure_unknown); + post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] = 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]); + + put_device(&rport->dev); + kref_put(&tgt->kref, ibmvfc_release_tgt); + scsi_host_put(vhost->host); +} + static struct kunit_case ibmvfc_fpin_test_cases[] = { KUNIT_CASE(ibmvfc_async_fpin_test), + KUNIT_CASE(ibmvfc_full_fpin_test), {}, }; -- 2.55.0