Merge branch 'akpm' (fixes from Andrew Morton)
[firefly-linux-kernel-4.4.55.git] / drivers / scsi / hpsa.c
index 6b35d0dfe64c943a5a9caac8564fdfa8fc5c9a83..cef5d49b59cd248d124e81bb568f0e3c198cc1df 100644 (file)
@@ -5971,10 +5971,6 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
 
        /* Save the PCI command register */
        pci_read_config_word(pdev, 4, &command_register);
-       /* Turn the board off.  This is so that later pci_restore_state()
-        * won't turn the board on before the rest of config space is ready.
-        */
-       pci_disable_device(pdev);
        pci_save_state(pdev);
 
        /* find the first memory BAR, so we can find the cfg table */
@@ -6022,11 +6018,6 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
                goto unmap_cfgtable;
 
        pci_restore_state(pdev);
-       rc = pci_enable_device(pdev);
-       if (rc) {
-               dev_warn(&pdev->dev, "failed to enable device.\n");
-               goto unmap_cfgtable;
-       }
        pci_write_config_word(pdev, 4, command_register);
 
        /* Some devices (notably the HP Smart Array 5i Controller)
@@ -6159,26 +6150,22 @@ static void hpsa_interrupt_mode(struct ctlr_info *h)
                h->msix_vector = MAX_REPLY_QUEUES;
                if (h->msix_vector > num_online_cpus())
                        h->msix_vector = num_online_cpus();
-               err = pci_enable_msix(h->pdev, hpsa_msix_entries,
-                                     h->msix_vector);
-               if (err > 0) {
+               err = pci_enable_msix_range(h->pdev, hpsa_msix_entries,
+                                           1, h->msix_vector);
+               if (err < 0) {
+                       dev_warn(&h->pdev->dev, "MSI-X init failed %d\n", err);
+                       h->msix_vector = 0;
+                       goto single_msi_mode;
+               } else if (err < h->msix_vector) {
                        dev_warn(&h->pdev->dev, "only %d MSI-X vectors "
                               "available\n", err);
-                       h->msix_vector = err;
-                       err = pci_enable_msix(h->pdev, hpsa_msix_entries,
-                                             h->msix_vector);
-               }
-               if (!err) {
-                       for (i = 0; i < h->msix_vector; i++)
-                               h->intr[i] = hpsa_msix_entries[i].vector;
-                       return;
-               } else {
-                       dev_warn(&h->pdev->dev, "MSI-X init failed %d\n",
-                              err);
-                       h->msix_vector = 0;
-                       goto default_int_mode;
                }
+               h->msix_vector = err;
+               for (i = 0; i < h->msix_vector; i++)
+                       h->intr[i] = hpsa_msix_entries[i].vector;
+               return;
        }
+single_msi_mode:
        if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
                dev_info(&h->pdev->dev, "MSI\n");
                if (!pci_enable_msi(h->pdev))
@@ -6541,6 +6528,23 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev)
        if (!reset_devices)
                return 0;
 
+       /* kdump kernel is loading, we don't know in which state is
+        * the pci interface. The dev->enable_cnt is equal zero
+        * so we call enable+disable, wait a while and switch it on.
+        */
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_warn(&pdev->dev, "Failed to enable PCI device\n");
+               return -ENODEV;
+       }
+       pci_disable_device(pdev);
+       msleep(260);                    /* a randomly chosen number */
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               dev_warn(&pdev->dev, "failed to enable device.\n");
+               return -ENODEV;
+       }
+       pci_set_master(pdev);
        /* Reset the controller with a PCI power-cycle or via doorbell */
        rc = hpsa_kdump_hard_reset_controller(pdev);
 
@@ -6549,10 +6553,11 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev)
         * "performant mode".  Or, it might be 640x, which can't reset
         * due to concerns about shared bbwc between 6402/6404 pair.
         */
-       if (rc == -ENOTSUPP)
-               return rc; /* just try to do the kdump anyhow. */
-       if (rc)
-               return -ENODEV;
+       if (rc) {
+               if (rc != -ENOTSUPP) /* just try to do the kdump anyhow. */
+                       rc = -ENODEV;
+               goto out_disable;
+       }
 
        /* Now try to get the controller to respond to a no-op */
        dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n");
@@ -6563,7 +6568,11 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev)
                        dev_warn(&pdev->dev, "no-op failed%s\n",
                                        (i < 11 ? "; re-trying" : ""));
        }
-       return 0;
+
+out_disable:
+
+       pci_disable_device(pdev);
+       return rc;
 }
 
 static int hpsa_allocate_cmd_pool(struct ctlr_info *h)
@@ -6743,6 +6752,7 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
                iounmap(h->transtable);
        if (h->cfgtable)
                iounmap(h->cfgtable);
+       pci_disable_device(h->pdev);
        pci_release_regions(h->pdev);
        kfree(h);
 }