]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - drivers/scsi/cxlflash/main.c
scsi: cxlflash: Serialize RRQ access and support offlevel processing
[mirror_ubuntu-zesty-kernel.git] / drivers / scsi / cxlflash / main.c
index 30c09593c12223fbc588438b9742e334d6f6d04e..8c207ba8474bc431bd7fee0460cea8e3fbc62c4f 100644 (file)
@@ -1157,10 +1157,13 @@ cxlflash_sync_err_irq_exit:
 /**
  * process_hrrq() - process the read-response queue
  * @afu:       AFU associated with the host.
+ * @doneq:     Queue of commands harvested from the RRQ.
+ *
+ * This routine must be called holding the disabled RRQ spin lock.
  *
  * Return: The number of entries processed.
  */
-static int process_hrrq(struct afu *afu)
+static int process_hrrq(struct afu *afu, struct list_head *doneq)
 {
        struct afu_cmd *cmd;
        struct sisl_ioasa *ioasa;
@@ -1189,7 +1192,7 @@ static int process_hrrq(struct afu *afu)
                        cmd = container_of(ioarcb, struct afu_cmd, rcb);
                }
 
-               cmd_complete(cmd);
+               list_add_tail(&cmd->queue, doneq);
 
                /* Advance to next entry or wrap and flip the toggle bit */
                if (hrrq_curr < hrrq_end)
@@ -1209,18 +1212,44 @@ static int process_hrrq(struct afu *afu)
        return num_hrrq;
 }
 
+/**
+ * process_cmd_doneq() - process a queue of harvested RRQ commands
+ * @doneq:     Queue of completed commands.
+ *
+ * Note that upon return the queue can no longer be trusted.
+ */
+static void process_cmd_doneq(struct list_head *doneq)
+{
+       struct afu_cmd *cmd, *tmp;
+
+       WARN_ON(list_empty(doneq));
+
+       list_for_each_entry_safe(cmd, tmp, doneq, queue)
+               cmd_complete(cmd);
+}
+
 /**
  * cxlflash_rrq_irq() - interrupt handler for read-response queue (normal path)
  * @irq:       Interrupt number.
  * @data:      Private data provided at interrupt registration, the AFU.
  *
- * Return: Always return IRQ_HANDLED.
+ * Return: IRQ_HANDLED or IRQ_NONE when no ready entries found.
  */
 static irqreturn_t cxlflash_rrq_irq(int irq, void *data)
 {
        struct afu *afu = (struct afu *)data;
+       unsigned long hrrq_flags;
+       LIST_HEAD(doneq);
+       int num_entries = 0;
 
-       process_hrrq(afu);
+       spin_lock_irqsave(&afu->hrrq_slock, hrrq_flags);
+       num_entries = process_hrrq(afu, &doneq);
+       spin_unlock_irqrestore(&afu->hrrq_slock, hrrq_flags);
+
+       if (num_entries == 0)
+               return IRQ_NONE;
+
+       process_cmd_doneq(&doneq);
        return IRQ_HANDLED;
 }
 
@@ -1540,14 +1569,13 @@ static int start_afu(struct cxlflash_cfg *cfg)
 
        init_pcr(cfg);
 
-       /* After an AFU reset, RRQ entries are stale, clear them */
+       /* Initialize RRQ */
        memset(&afu->rrq_entry, 0, sizeof(afu->rrq_entry));
-
-       /* Initialize RRQ pointers */
        afu->hrrq_start = &afu->rrq_entry[0];
        afu->hrrq_end = &afu->rrq_entry[NUM_RRQ_ENTRY - 1];
        afu->hrrq_curr = afu->hrrq_start;
        afu->toggle = 1;
+       spin_lock_init(&afu->hrrq_slock);
 
        /* Initialize SQ */
        if (afu_is_sq_cmd_mode(afu)) {