From: Dave Marquardt <[email protected]>

ibmvfc_register_channel() and ibmvfc_deregister_channel() previously only
handled SCSI and NVMe sub-CRQ channels identified by the channel protocol
(IBMVFC_PROTO_SCSI, IBMVFC_PROTO_NVME). The async sub-CRQ had no
registration path through these helpers, requiring separate handling.

Add a new IBMVFC_PROTO_ASYNC protocol value to enum ibmvfc_protocol.
Extend both functions to handle IBMVFC_PROTO_ASYNC channels: the IRQ is
named "ibmvfc-<addr>-async<index>" and the handler is set to
ibmvfc_interrupt_async_subq rather than the per-protocol
ibmvfc_interrupt_mq handler.

Remove the __maybe_unused annotation from ibmvfc_interrupt_async_subq
now that it is referenced in ibmvfc_register_channel().

Error messages in both paths are updated to include the channel protocol
to distinguish async sub-CRQ failures from SCSI/NVMe sub-CRQ failures.
Kernel-doc headers are added to both functions.

Signed-off-by: Dave Marquardt <[email protected]>
Signed-off-by: Tyrel Datwyler <[email protected]>
---
 drivers/scsi/ibmvscsi/ibmvfc-core.c | 46 +++++++++++++++++++++++++----
 drivers/scsi/ibmvscsi/ibmvfc.h      |  1 +
 2 files changed, 42 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c 
b/drivers/scsi/ibmvscsi/ibmvfc-core.c
index b354bfb1a9b6..b967c82e9943 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc-core.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c
@@ -4421,7 +4421,7 @@ static void ibmvfc_drain_async_subq(struct ibmvfc_queue 
*scrq)
  * @scrq_instance: async subq
  *
  **/
-static irqreturn_t __maybe_unused ibmvfc_interrupt_async_subq(int irq, void 
*scrq_instance)
+static irqreturn_t ibmvfc_interrupt_async_subq(int irq, void *scrq_instance)
 {
        struct ibmvfc_queue *scrq = (struct ibmvfc_queue *)scrq_instance;
 
@@ -6812,6 +6812,21 @@ static int ibmvfc_init_crq(struct ibmvfc_host *vhost)
        return retrc;
 }
 
+/**
+ * ibmvfc_register_channel - Register a sub-CRQ channel with the hypervisor
+ * @vhost:     ibmvfc host struct
+ * @channels:  ibmvfc channels struct containing the channel array and protocol
+ * @index:     index into the channels array for the queue to register, or
+ *             a negative value to register the async sub-CRQ
+ *
+ * Register a sub-CRQ with the hypervisor via h_reg_sub_crq, map its hardware
+ * IRQ to a Linux IRQ, and bind an interrupt handler to it. The handler is
+ * selected based on the channel protocol (SCSI or NVMe) for normal queues, or
+ * set to the async sub-CRQ handler when @index is negative.
+ *
+ * Return value:
+ *     0 on success / non-zero on failure
+ **/
 static int ibmvfc_register_channel(struct ibmvfc_host *vhost,
                                   struct ibmvfc_channels *channels,
                                   int index)
@@ -6839,7 +6854,8 @@ static int ibmvfc_register_channel(struct ibmvfc_host 
*vhost,
 
        if (!scrq->irq) {
                rc = -EINVAL;
-               dev_err(dev, "Error mapping sub-crq[%d] irq\n", index);
+               dev_err(dev, "Error mapping protocol (%d) sub-crq[%d] irq\n",
+                       channels->protocol, index);
                goto irq_failed;
        }
 
@@ -6854,6 +6870,11 @@ static int ibmvfc_register_channel(struct ibmvfc_host 
*vhost,
                         vdev->unit_address, index);
                scrq->handler = ibmvfc_interrupt_mq;
                break;
+       case IBMVFC_PROTO_ASYNC:
+               snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-async%d",
+                        vdev->unit_address, index);
+               scrq->handler = ibmvfc_interrupt_async_subq;
+               break;
        default:
                dev_err(dev, "Unknown channel protocol (%d)\n",
                        channels->protocol);
@@ -6863,7 +6884,8 @@ static int ibmvfc_register_channel(struct ibmvfc_host 
*vhost,
        rc = request_irq(scrq->irq, scrq->handler, 0, scrq->name, scrq);
 
        if (rc) {
-               dev_err(dev, "Couldn't register sub-crq[%d] irq\n", index);
+               dev_err(dev, "Couldn't register protocol (%d) sub-crq[%d] 
irq\n",
+                       channels->protocol, index);
                irq_dispose_mapping(scrq->irq);
                scrq->irq = 0;
                goto irq_failed;
@@ -6883,6 +6905,18 @@ static int ibmvfc_register_channel(struct ibmvfc_host 
*vhost,
        return rc;
 }
 
+/**
+ * ibmvfc_deregister_channel - Deregister a sub-CRQ channel with the hypervisor
+ * @vhost:     ibmvfc host struct
+ * @channels:  ibmvfc channels struct containing the sub-CRQ array
+ * @index:     index into the sub-CRQ array, or -1 to deregister the
+ *             asynchronous sub-CRQ
+ *
+ * Frees the IRQ, disposes of the IRQ mapping, and calls H_FREE_SUB_CRQ to
+ * release the sub-CRQ with the hypervisor. On success the queue message
+ * buffer is zeroed and the current index is reset. If H_FREE_SUB_CRQ fails,
+ * an error is logged but the channel resources are cleaned up regardless.
+ */
 static void ibmvfc_deregister_channel(struct ibmvfc_host *vhost,
                                      struct ibmvfc_channels *channels,
                                      int index)
@@ -6905,8 +6939,10 @@ static void ibmvfc_deregister_channel(struct ibmvfc_host 
*vhost,
                                        scrq->cookie);
        } while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
 
-       if (rc)
-               dev_err(dev, "Failed to free sub-crq[%d]: rc=%ld\n", index, rc);
+       if (rc) {
+               dev_err(dev, "Failed to free protocol (%d) sub-crq[%d]: 
rc=%ld\n",
+                       channels->protocol, index, rc);
+       }
 
        /* Clean out the queue */
        if (scrq->msgs.handle) {
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index ebbcb911f639..1cb6f20b0626 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -839,6 +839,7 @@ enum ibmvfc_target_action {
 enum ibmvfc_protocol {
        IBMVFC_PROTO_SCSI = 0,
        IBMVFC_PROTO_NVME = 1,
+       IBMVFC_PROTO_ASYNC = 2,
 };
 
 struct ibmvfc_target {
-- 
2.55.0


Reply via email to