From: Dave Marquardt <[email protected]>

ibmvfc_register_channel() and ibmvfc_deregister_channel() previously only
handled indexed sub-CRQ channels drawn from the channels->scrqs[] array.
The async sub-CRQ (vhost->async_sub_crq) had no registration path through
these helpers, requiring separate handling.

Extend both functions to accept a negative index as a sentinel value
signalling that the async sub-CRQ should be operated on instead of an
indexed scrq entry. When index < 0, the queue pointer is set to
&vhost->async_sub_crq, the IRQ is named "ibmvfc-<addr>-async", and the
handler is set to ibmvfc_interrupt_async_subq rather than the per-protocol
ibmvfc_interrupt_mq handler. hwq_id assignment is skipped for the async
queue since it has no meaningful hardware queue index.

Stopped marking ibmvfc_interrupt_async_subq as __maybe_unused.

Error messages in both paths are updated to distinguish async sub-CRQ
failures from indexed sub-CRQ failures. Kernel-doc headers are added to
both functions documenting the negative-index convention.

Signed-off-by: Dave Marquardt <[email protected]>
---
 drivers/scsi/ibmvscsi/ibmvfc-core.c  | 93 +++++++++++++++++++++++++++---------
 drivers/scsi/ibmvscsi/ibmvfc_kunit.c |  2 +-
 2 files changed, 71 insertions(+), 24 deletions(-)

diff --git a/drivers/scsi/ibmvscsi/ibmvfc-core.c 
b/drivers/scsi/ibmvscsi/ibmvfc-core.c
index a28875c1f983..cc1ef8258060 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc-core.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc-core.c
@@ -4409,7 +4409,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;
 
@@ -6799,13 +6799,29 @@ 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)
 {
        struct device *dev = vhost->dev;
        struct vio_dev *vdev = to_vio_dev(dev);
-       struct ibmvfc_queue *scrq = &channels->scrqs[index];
+       bool is_async = index < 0;
+       struct ibmvfc_queue *scrq = !is_async ? &channels->scrqs[index] : 
&vhost->async_sub_crq;
        int rc = -ENOMEM;
 
        ENTER;
@@ -6825,36 +6841,49 @@ 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);
+               if (!is_async)
+                       dev_err(dev, "Error mapping sub-crq[%d] irq\n", index);
+               else
+                       dev_err(dev, "Error mapping async sub-crq irq\n");
                goto irq_failed;
        }
 
-       switch (channels->protocol) {
-       case IBMVFC_PROTO_SCSI:
-               snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-scsi%d",
-                        vdev->unit_address, index);
-               scrq->handler = ibmvfc_interrupt_mq;
-               break;
-       case IBMVFC_PROTO_NVME:
-               snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-nvmf%d",
-                        vdev->unit_address, index);
-               scrq->handler = ibmvfc_interrupt_mq;
-               break;
-       default:
-               dev_err(dev, "Unknown channel protocol (%d)\n",
-                       channels->protocol);
-               goto irq_failed;
+       if (!is_async) {
+               switch (channels->protocol) {
+               case IBMVFC_PROTO_SCSI:
+                       snprintf(scrq->name, sizeof(scrq->name), 
"ibmvfc-%x-scsi%d",
+                                vdev->unit_address, index);
+                       scrq->handler = ibmvfc_interrupt_mq;
+                       break;
+               case IBMVFC_PROTO_NVME:
+                       snprintf(scrq->name, sizeof(scrq->name), 
"ibmvfc-%x-nvmf%d",
+                                vdev->unit_address, index);
+                       scrq->handler = ibmvfc_interrupt_mq;
+                       break;
+               default:
+                       dev_err(dev, "Unknown channel protocol (%d)\n",
+                               channels->protocol);
+                       goto irq_failed;
+               }
+       } else {
+               snprintf(scrq->name, sizeof(scrq->name), "ibmvfc-%x-async",
+                        vdev->unit_address);
+               scrq->handler = ibmvfc_interrupt_async_subq;
        }
 
        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);
+               if (!is_async)
+                       dev_err(dev, "Couldn't register sub-crq[%d] irq\n", 
index);
+               else
+                       dev_err(dev, "Couldn't register async sub-crq irq\n");
                irq_dispose_mapping(scrq->irq);
                goto irq_failed;
        }
 
-       scrq->hwq_id = index;
+       if (!is_async)
+               scrq->hwq_id = index;
 
        LEAVE;
        return 0;
@@ -6868,13 +6897,26 @@ 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)
 {
        struct device *dev = vhost->dev;
        struct vio_dev *vdev = to_vio_dev(dev);
-       struct ibmvfc_queue *scrq = &channels->scrqs[index];
+       bool is_async = index < 0;
+       struct ibmvfc_queue *scrq = !is_async ? &channels->scrqs[index] : 
&vhost->async_sub_crq;
        long rc;
 
        ENTER;
@@ -6888,8 +6930,13 @@ 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) {
+               if (!is_async)
+                       dev_err(dev, "Failed to free sub-crq[%d]: rc=%ld\n",
+                               index, rc);
+               else
+                       dev_err(dev, "Failed to free async sub-crq: rc=%ld\n", 
rc);
+       }
 
        /* Clean out the queue */
        memset(scrq->msgs.crq, 0, PAGE_SIZE);
diff --git a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c 
b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c
index bc6e542f11ce..47f7c4e79cd8 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc_kunit.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc_kunit.c
@@ -199,7 +199,7 @@ static void ibmvfc_full_fpin_test(struct kunit *test)
        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(tgt->rport->fpin_stats.cn);
+       post[IBMVFC_AE_FPIN_PORT_CONGESTED] = 
READ_ONCE(tgt->rport->fpin_stats.cn_device_specific);
        post[IBMVFC_AE_FPIN_PORT_CLEARED] = 
READ_ONCE(tgt->rport->fpin_stats.cn_clear);
        post[IBMVFC_AE_FPIN_PORT_DEGRADED] = 
READ_ONCE(tgt->rport->fpin_stats.li_failure_unknown);
        post[IBMVFC_AE_FPIN_CONGESTION_CLEARED] = 
READ_ONCE(fc_host->fpin_stats.cn_clear);

-- 
2.55.0



Reply via email to