Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / drivers / scsi / cxlflash / main.c
index 1e5bf0c..c86847c 100644 (file)
@@ -289,7 +289,7 @@ static void context_reset(struct afu_cmd *cmd)
                atomic64_set(&afu->room, room);
                if (room)
                        goto write_rrin;
-               udelay(nretry);
+               udelay(1 << nretry);
        } while (nretry++ < MC_ROOM_RETRY_CNT);
 
        pr_err("%s: no cmd_room to send reset\n", __func__);
@@ -303,7 +303,7 @@ write_rrin:
                if (rrin != 0x1)
                        break;
                /* Double delay each time */
-               udelay(2 << nretry);
+               udelay(1 << nretry);
        } while (nretry++ < MC_ROOM_RETRY_CNT);
 }
 
@@ -338,7 +338,7 @@ retry:
                        atomic64_set(&afu->room, room);
                        if (room)
                                goto write_ioarrin;
-                       udelay(nretry);
+                       udelay(1 << nretry);
                } while (nretry++ < MC_ROOM_RETRY_CNT);
 
                dev_err(dev, "%s: no cmd_room to send 0x%X\n",
@@ -352,7 +352,7 @@ retry:
                 * afu->room.
                 */
                if (nretry++ < MC_ROOM_RETRY_CNT) {
-                       udelay(nretry);
+                       udelay(1 << nretry);
                        goto retry;
                }
 
@@ -368,6 +368,7 @@ out:
 
 no_room:
        afu->read_room = true;
+       kref_get(&cfg->afu->mapcount);
        schedule_work(&cfg->work_q);
        rc = SCSI_MLQUEUE_HOST_BUSY;
        goto out;
@@ -473,6 +474,16 @@ out:
        return rc;
 }
 
+static void afu_unmap(struct kref *ref)
+{
+       struct afu *afu = container_of(ref, struct afu, mapcount);
+
+       if (likely(afu->afu_map)) {
+               cxl_psa_unmap((void __iomem *)afu->afu_map);
+               afu->afu_map = NULL;
+       }
+}
+
 /**
  * cxlflash_driver_info() - information handler for this host driver
  * @host:      SCSI host associated with device.
@@ -503,6 +514,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
        ulong lock_flags;
        short lflag = 0;
        int rc = 0;
+       int kref_got = 0;
 
        dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
                            "cdb=(%08X-%08X-%08X-%08X)\n",
@@ -547,6 +559,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
                goto out;
        }
 
+       kref_get(&cfg->afu->mapcount);
+       kref_got = 1;
+
        cmd->rcb.ctx_id = afu->ctx_hndl;
        cmd->rcb.port_sel = port_sel;
        cmd->rcb.lun_id = lun_to_lunid(scp->device->lun);
@@ -587,6 +602,8 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
        }
 
 out:
+       if (kref_got)
+               kref_put(&afu->mapcount, afu_unmap);
        pr_devel("%s: returning rc=%d\n", __func__, rc);
        return rc;
 }
@@ -632,20 +649,36 @@ static void free_mem(struct cxlflash_cfg *cfg)
  * @cfg:       Internal structure associated with the host.
  *
  * Safe to call with AFU in a partially allocated/initialized state.
+ *
+ * Cleans up all state associated with the command queue, and unmaps
+ * the MMIO space.
+ *
+ *  - complete() will take care of commands we initiated (they'll be checked
+ *  in as part of the cleanup that occurs after the completion)
+ *
+ *  - cmd_checkin() will take care of entries that we did not initiate and that
+ *  have not (and will not) complete because they are sitting on a [now stale]
+ *  hardware queue
  */
 static void stop_afu(struct cxlflash_cfg *cfg)
 {
        int i;
        struct afu *afu = cfg->afu;
+       struct afu_cmd *cmd;
 
        if (likely(afu)) {
-               for (i = 0; i < CXLFLASH_NUM_CMDS; i++)
-                       complete(&afu->cmd[i].cevent);
+               for (i = 0; i < CXLFLASH_NUM_CMDS; i++) {
+                       cmd = &afu->cmd[i];
+                       complete(&cmd->cevent);
+                       if (!atomic_read(&cmd->free))
+                               cmd_checkin(cmd);
+               }
 
                if (likely(afu->afu_map)) {
                        cxl_psa_unmap((void __iomem *)afu->afu_map);
                        afu->afu_map = NULL;
                }
+               kref_put(&afu->mapcount, afu_unmap);
        }
 }
 
@@ -731,8 +764,8 @@ static void cxlflash_remove(struct pci_dev *pdev)
                scsi_remove_host(cfg->host);
                /* fall through */
        case INIT_STATE_AFU:
-               term_afu(cfg);
                cancel_work_sync(&cfg->work_q);
+               term_afu(cfg);
        case INIT_STATE_PCI:
                pci_release_regions(cfg->dev);
                pci_disable_device(pdev);
@@ -1108,7 +1141,7 @@ static const struct asyc_intr_info ainfo[] = {
        {SISL_ASTATUS_FC1_OTHER, "other error", 1, CLR_FC_ERROR | LINK_RESET},
        {SISL_ASTATUS_FC1_LOGO, "target initiated LOGO", 1, 0},
        {SISL_ASTATUS_FC1_CRC_T, "CRC threshold exceeded", 1, LINK_RESET},
-       {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, 0},
+       {SISL_ASTATUS_FC1_LOGI_R, "login timed out, retrying", 1, LINK_RESET},
        {SISL_ASTATUS_FC1_LOGI_F, "login failed", 1, CLR_FC_ERROR},
        {SISL_ASTATUS_FC1_LOGI_S, "login succeeded", 1, SCAN_HOST},
        {SISL_ASTATUS_FC1_LINK_DN, "link down", 1, 0},
@@ -1316,6 +1349,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
                                __func__, port);
                        cfg->lr_state = LINK_RESET_REQUIRED;
                        cfg->lr_port = port;
+                       kref_get(&cfg->afu->mapcount);
                        schedule_work(&cfg->work_q);
                }
 
@@ -1336,6 +1370,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
 
                if (info->action & SCAN_HOST) {
                        atomic_inc(&cfg->scan_host_needed);
+                       kref_get(&cfg->afu->mapcount);
                        schedule_work(&cfg->work_q);
                }
        }
@@ -1731,6 +1766,7 @@ static int init_afu(struct cxlflash_cfg *cfg)
                rc = -ENOMEM;
                goto err1;
        }
+       kref_init(&afu->mapcount);
 
        /* No byte reverse on reading afu_version or string will be backwards */
        reg = readq(&afu->afu_map->global.regs.afu_version);
@@ -1765,8 +1801,7 @@ out:
        return rc;
 
 err2:
-       cxl_psa_unmap((void __iomem *)afu->afu_map);
-       afu->afu_map = NULL;
+       kref_put(&afu->mapcount, afu_unmap);
 err1:
        term_mc(cfg, UNDO_START);
        goto out;
@@ -2114,6 +2149,16 @@ static ssize_t lun_mode_store(struct device *dev,
        rc = kstrtouint(buf, 10, &lun_mode);
        if (!rc && (lun_mode < 5) && (lun_mode != afu->internal_lun)) {
                afu->internal_lun = lun_mode;
+
+               /*
+                * When configured for internal LUN, there is only one channel,
+                * channel number 0, else there will be 2 (default).
+                */
+               if (afu->internal_lun)
+                       shost->max_channel = 0;
+               else
+                       shost->max_channel = NUM_FC_PORTS - 1;
+
                afu_reset(cfg);
                scsi_scan_host(cfg->host);
        }
@@ -2274,6 +2319,7 @@ static struct scsi_host_template driver_template = {
  * Device dependent values
  */
 static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
+static struct dev_dependent_vals dev_flash_gt_vals = { CXLFLASH_MAX_SECTORS };
 
 /*
  * PCI device binding table
@@ -2281,6 +2327,8 @@ static struct dev_dependent_vals dev_corsa_vals = { CXLFLASH_MAX_SECTORS };
 static struct pci_device_id cxlflash_pci_table[] = {
        {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CORSA,
         PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_corsa_vals},
+       {PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_FLASH_GT,
+        PCI_ANY_ID, PCI_ANY_ID, 0, 0, (kernel_ulong_t)&dev_flash_gt_vals},
        {}
 };
 
@@ -2339,6 +2387,7 @@ static void cxlflash_worker_thread(struct work_struct *work)
 
        if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
                scsi_scan_host(cfg->host);
+       kref_put(&afu->mapcount, afu_unmap);
 }
 
 /**