mtip32xx: fix crash on surprise removal of the drive
authorAsai Thambi SP <asamymuthupa@micron.com>
Mon, 11 May 2015 22:53:18 +0000 (15:53 -0700)
committerSasha Levin <sasha.levin@oracle.com>
Mon, 18 Apr 2016 12:50:46 +0000 (08:50 -0400)
[ Upstream commit 2132a544727eb17f76bfef8b550a016a41c38821 ]

pci and block layers have changed a lot compared to when SRSI support was added.
Given the current state of pci and block layers, this driver do not have to do
any specific handling.

Signed-off-by: Asai Thambi S P <asamymuthupa@micron.com>
Signed-off-by: Selvan Mani <smani@micron.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
Signed-off-by: Sasha Levin <sasha.levin@oracle.com>
drivers/block/mtip32xx/mtip32xx.c

index 898eb60..4b9a0a4 100644 (file)
@@ -896,6 +896,10 @@ static inline irqreturn_t mtip_handle_irq(struct driver_data *data)
 
                /* Acknowledge the interrupt status on the port.*/
                port_stat = readl(port->mmio + PORT_IRQ_STAT);
+               if (unlikely(port_stat == 0xFFFFFFFF)) {
+                       mtip_check_surprise_removal(dd->pdev);
+                       return IRQ_HANDLED;
+               }
                writel(port_stat, port->mmio + PORT_IRQ_STAT);
 
                /* Demux port status */
@@ -2784,49 +2788,6 @@ static void mtip_hw_debugfs_exit(struct driver_data *dd)
                debugfs_remove_recursive(dd->dfs_node);
 }
 
-static int mtip_free_orphan(struct driver_data *dd)
-{
-       struct kobject *kobj;
-
-       if (dd->bdev) {
-               if (dd->bdev->bd_holders >= 1)
-                       return -2;
-
-               bdput(dd->bdev);
-               dd->bdev = NULL;
-       }
-
-       mtip_hw_debugfs_exit(dd);
-
-       spin_lock(&rssd_index_lock);
-       ida_remove(&rssd_index_ida, dd->index);
-       spin_unlock(&rssd_index_lock);
-
-       if (!test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag) &&
-                       test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag)) {
-               put_disk(dd->disk);
-       } else {
-               if (dd->disk) {
-                       kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
-                       if (kobj) {
-                               mtip_hw_sysfs_exit(dd, kobj);
-                               kobject_put(kobj);
-                       }
-                       del_gendisk(dd->disk);
-                       put_disk(dd->disk);
-                       dd->disk = NULL;
-               }
-               if (dd->queue) {
-                       dd->queue->queuedata = NULL;
-                       blk_cleanup_queue(dd->queue);
-                       blk_mq_free_tag_set(&dd->tags);
-                       dd->queue = NULL;
-               }
-       }
-       kfree(dd);
-       return 0;
-}
-
 /*
  * Perform any init/resume time hardware setup
  *
@@ -2974,7 +2935,6 @@ static int mtip_service_thread(void *data)
        unsigned long slot, slot_start, slot_wrap;
        unsigned int num_cmd_slots = dd->slot_groups * 32;
        struct mtip_port *port = dd->port;
-       int ret;
 
        while (1) {
                if (kthread_should_stop() ||
@@ -3060,18 +3020,6 @@ restart_eh:
                if (kthread_should_stop())
                        goto st_out;
        }
-
-       while (1) {
-               ret = mtip_free_orphan(dd);
-               if (!ret) {
-                       /* NOTE: All data structures are invalid, do not
-                        * access any here */
-                       return 0;
-               }
-               msleep_interruptible(1000);
-               if (kthread_should_stop())
-                       goto st_out;
-       }
 st_out:
        return 0;
 }
@@ -3404,6 +3352,7 @@ static int mtip_hw_exit(struct driver_data *dd)
        /* Release the IRQ. */
        irq_set_affinity_hint(dd->pdev->irq, NULL);
        devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd);
+       msleep(1000);
 
        /* Free dma regions */
        mtip_dma_free(dd);
@@ -4075,52 +4024,51 @@ static int mtip_block_remove(struct driver_data *dd)
 {
        struct kobject *kobj;
 
-       if (!dd->sr) {
-               mtip_hw_debugfs_exit(dd);
+       mtip_hw_debugfs_exit(dd);
 
-               if (dd->mtip_svc_handler) {
-                       set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags);
-                       wake_up_interruptible(&dd->port->svc_wait);
-                       kthread_stop(dd->mtip_svc_handler);
-               }
+       if (dd->mtip_svc_handler) {
+               set_bit(MTIP_PF_SVC_THD_STOP_BIT, &dd->port->flags);
+               wake_up_interruptible(&dd->port->svc_wait);
+               kthread_stop(dd->mtip_svc_handler);
+       }
 
-               /* Clean up the sysfs attributes, if created */
-               if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) {
-                       kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
-                       if (kobj) {
-                               mtip_hw_sysfs_exit(dd, kobj);
-                               kobject_put(kobj);
-                       }
+       /* Clean up the sysfs attributes, if created */
+       if (test_bit(MTIP_DDF_INIT_DONE_BIT, &dd->dd_flag)) {
+               kobj = kobject_get(&disk_to_dev(dd->disk)->kobj);
+               if (kobj) {
+                       mtip_hw_sysfs_exit(dd, kobj);
+                       kobject_put(kobj);
                }
+       }
 
+       if (!dd->sr)
                mtip_standby_drive(dd);
-
-               /*
-                * Delete our gendisk structure. This also removes the device
-                * from /dev
-                */
-               if (dd->bdev) {
-                       bdput(dd->bdev);
-                       dd->bdev = NULL;
-               }
-               if (dd->disk) {
-                       del_gendisk(dd->disk);
-                       if (dd->disk->queue) {
-                               blk_cleanup_queue(dd->queue);
-                               blk_mq_free_tag_set(&dd->tags);
-                               dd->queue = NULL;
-                       }
-                       put_disk(dd->disk);
-               }
-               dd->disk  = NULL;
-
-               spin_lock(&rssd_index_lock);
-               ida_remove(&rssd_index_ida, dd->index);
-               spin_unlock(&rssd_index_lock);
-       } else {
+       else
                dev_info(&dd->pdev->dev, "device %s surprise removal\n",
                                                dd->disk->disk_name);
+
+       /*
+        * Delete our gendisk structure. This also removes the device
+        * from /dev
+        */
+       if (dd->bdev) {
+               bdput(dd->bdev);
+               dd->bdev = NULL;
+       }
+       if (dd->disk) {
+               del_gendisk(dd->disk);
+               if (dd->disk->queue) {
+                       blk_cleanup_queue(dd->queue);
+                       blk_mq_free_tag_set(&dd->tags);
+                       dd->queue = NULL;
+               }
+               put_disk(dd->disk);
        }
+       dd->disk  = NULL;
+
+       spin_lock(&rssd_index_lock);
+       ida_remove(&rssd_index_ida, dd->index);
+       spin_unlock(&rssd_index_lock);
 
        /* De-initialize the protocol layer. */
        mtip_hw_exit(dd);
@@ -4516,6 +4464,7 @@ static void mtip_pci_remove(struct pci_dev *pdev)
                        "Completion workers still active!\n");
        }
 
+       blk_mq_stop_hw_queues(dd->queue);
        /* Clean up the block layer. */
        mtip_block_remove(dd);
 
@@ -4533,10 +4482,8 @@ static void mtip_pci_remove(struct pci_dev *pdev)
        list_del_init(&dd->remove_list);
        spin_unlock_irqrestore(&dev_lock, flags);
 
-       if (!dd->sr)
-               kfree(dd);
-       else
-               set_bit(MTIP_DDF_REMOVE_DONE_BIT, &dd->dd_flag);
+       kfree(dd);
+       set_bit(MTIP_DDF_REMOVE_DONE_BIT, &dd->dd_flag);
 
        pcim_iounmap_regions(pdev, 1 << MTIP_ABAR);
        pci_set_drvdata(pdev, NULL);