aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManoj Kumar <manoj@linux.vnet.ibm.com>2015-12-14 16:07:23 -0500
committerMartin K. Petersen <martin.petersen@oracle.com>2016-01-06 20:55:01 -0500
commitb45cdbaf9f7f0486847c52f60747fb108724652a (patch)
treec59b83e2a7384f2f9ab2a74a8e11223a114e85a5
parentee91e332a6e6e9b939f60f6e1bd72fb2def5290d (diff)
cxlflash: Resolve oops in wait_port_offline
If an async error interrupt is generated, and the error requires the FC link to be reset, it cannot be performed in the interrupt context. So a work element is scheduled to complete the link reset in a process context. If either an EEH event or an escalation occurs in between when the interrupt is generated and the scheduled work is started, the MMIO space may no longer be available. This will cause an oops in the worker thread. [ 606.806583] NIP kthread_data+0x28/0x40 [ 606.806633] LR wq_worker_sleeping+0x30/0x100 [ 606.806694] Call Trace: [ 606.806721] 0x50 (unreliable) [ 606.806796] wq_worker_sleeping+0x30/0x100 [ 606.806884] __schedule+0x69c/0x8a0 [ 606.806959] schedule+0x44/0xc0 [ 606.807034] do_exit+0x770/0xb90 [ 606.807109] die+0x300/0x460 [ 606.807185] bad_page_fault+0xd8/0x150 [ 606.807259] handle_page_fault+0x2c/0x30 [ 606.807338] wait_port_offline.constprop.12+0x60/0x130 [cxlflash] To prevent the problem space area from being unmapped, when there is pending work, a mapcount (using the kref mechanism) is held. The mapcount is released only when the work is completed. The last reference release is tied to the unmapping service. Signed-off-by: Manoj N. Kumar <manoj@linux.vnet.ibm.com> Acked-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com> Reviewed-by: Uma Krishnan <ukrishn@linux.vnet.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/cxlflash/common.h2
-rw-r--r--drivers/scsi/cxlflash/main.c27
2 files changed, 26 insertions, 3 deletions
diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h
index c11cd193f896..5ada9268a450 100644
--- a/drivers/scsi/cxlflash/common.h
+++ b/drivers/scsi/cxlflash/common.h
@@ -165,6 +165,8 @@ struct afu {
165 struct sisl_host_map __iomem *host_map; /* MC host map */ 165 struct sisl_host_map __iomem *host_map; /* MC host map */
166 struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */ 166 struct sisl_ctrl_map __iomem *ctrl_map; /* MC control map */
167 167
168 struct kref mapcount;
169
168 ctx_hndl_t ctx_hndl; /* master's context handle */ 170 ctx_hndl_t ctx_hndl; /* master's context handle */
169 u64 *hrrq_start; 171 u64 *hrrq_start;
170 u64 *hrrq_end; 172 u64 *hrrq_end;
diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c
index ac39856a74b4..30542ca9415b 100644
--- a/drivers/scsi/cxlflash/main.c
+++ b/drivers/scsi/cxlflash/main.c
@@ -368,6 +368,7 @@ out:
368 368
369no_room: 369no_room:
370 afu->read_room = true; 370 afu->read_room = true;
371 kref_get(&cfg->afu->mapcount);
371 schedule_work(&cfg->work_q); 372 schedule_work(&cfg->work_q);
372 rc = SCSI_MLQUEUE_HOST_BUSY; 373 rc = SCSI_MLQUEUE_HOST_BUSY;
373 goto out; 374 goto out;
@@ -473,6 +474,16 @@ out:
473 return rc; 474 return rc;
474} 475}
475 476
477static void afu_unmap(struct kref *ref)
478{
479 struct afu *afu = container_of(ref, struct afu, mapcount);
480
481 if (likely(afu->afu_map)) {
482 cxl_psa_unmap((void __iomem *)afu->afu_map);
483 afu->afu_map = NULL;
484 }
485}
486
476/** 487/**
477 * cxlflash_driver_info() - information handler for this host driver 488 * cxlflash_driver_info() - information handler for this host driver
478 * @host: SCSI host associated with device. 489 * @host: SCSI host associated with device.
@@ -503,6 +514,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
503 ulong lock_flags; 514 ulong lock_flags;
504 short lflag = 0; 515 short lflag = 0;
505 int rc = 0; 516 int rc = 0;
517 int kref_got = 0;
506 518
507 dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu " 519 dev_dbg_ratelimited(dev, "%s: (scp=%p) %d/%d/%d/%llu "
508 "cdb=(%08X-%08X-%08X-%08X)\n", 520 "cdb=(%08X-%08X-%08X-%08X)\n",
@@ -547,6 +559,9 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp)
547 goto out; 559 goto out;
548 } 560 }
549 561
562 kref_get(&cfg->afu->mapcount);
563 kref_got = 1;
564
550 cmd->rcb.ctx_id = afu->ctx_hndl; 565 cmd->rcb.ctx_id = afu->ctx_hndl;
551 cmd->rcb.port_sel = port_sel; 566 cmd->rcb.port_sel = port_sel;
552 cmd->rcb.lun_id = lun_to_lunid(scp->device->lun); 567 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)
587 } 602 }
588 603
589out: 604out:
605 if (kref_got)
606 kref_put(&afu->mapcount, afu_unmap);
590 pr_devel("%s: returning rc=%d\n", __func__, rc); 607 pr_devel("%s: returning rc=%d\n", __func__, rc);
591 return rc; 608 return rc;
592} 609}
@@ -661,6 +678,7 @@ static void stop_afu(struct cxlflash_cfg *cfg)
661 cxl_psa_unmap((void __iomem *)afu->afu_map); 678 cxl_psa_unmap((void __iomem *)afu->afu_map);
662 afu->afu_map = NULL; 679 afu->afu_map = NULL;
663 } 680 }
681 kref_put(&afu->mapcount, afu_unmap);
664 } 682 }
665} 683}
666 684
@@ -746,8 +764,8 @@ static void cxlflash_remove(struct pci_dev *pdev)
746 scsi_remove_host(cfg->host); 764 scsi_remove_host(cfg->host);
747 /* fall through */ 765 /* fall through */
748 case INIT_STATE_AFU: 766 case INIT_STATE_AFU:
749 term_afu(cfg);
750 cancel_work_sync(&cfg->work_q); 767 cancel_work_sync(&cfg->work_q);
768 term_afu(cfg);
751 case INIT_STATE_PCI: 769 case INIT_STATE_PCI:
752 pci_release_regions(cfg->dev); 770 pci_release_regions(cfg->dev);
753 pci_disable_device(pdev); 771 pci_disable_device(pdev);
@@ -1331,6 +1349,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
1331 __func__, port); 1349 __func__, port);
1332 cfg->lr_state = LINK_RESET_REQUIRED; 1350 cfg->lr_state = LINK_RESET_REQUIRED;
1333 cfg->lr_port = port; 1351 cfg->lr_port = port;
1352 kref_get(&cfg->afu->mapcount);
1334 schedule_work(&cfg->work_q); 1353 schedule_work(&cfg->work_q);
1335 } 1354 }
1336 1355
@@ -1351,6 +1370,7 @@ static irqreturn_t cxlflash_async_err_irq(int irq, void *data)
1351 1370
1352 if (info->action & SCAN_HOST) { 1371 if (info->action & SCAN_HOST) {
1353 atomic_inc(&cfg->scan_host_needed); 1372 atomic_inc(&cfg->scan_host_needed);
1373 kref_get(&cfg->afu->mapcount);
1354 schedule_work(&cfg->work_q); 1374 schedule_work(&cfg->work_q);
1355 } 1375 }
1356 } 1376 }
@@ -1746,6 +1766,7 @@ static int init_afu(struct cxlflash_cfg *cfg)
1746 rc = -ENOMEM; 1766 rc = -ENOMEM;
1747 goto err1; 1767 goto err1;
1748 } 1768 }
1769 kref_init(&afu->mapcount);
1749 1770
1750 /* No byte reverse on reading afu_version or string will be backwards */ 1771 /* No byte reverse on reading afu_version or string will be backwards */
1751 reg = readq(&afu->afu_map->global.regs.afu_version); 1772 reg = readq(&afu->afu_map->global.regs.afu_version);
@@ -1780,8 +1801,7 @@ out:
1780 return rc; 1801 return rc;
1781 1802
1782err2: 1803err2:
1783 cxl_psa_unmap((void __iomem *)afu->afu_map); 1804 kref_put(&afu->mapcount, afu_unmap);
1784 afu->afu_map = NULL;
1785err1: 1805err1:
1786 term_mc(cfg, UNDO_START); 1806 term_mc(cfg, UNDO_START);
1787 goto out; 1807 goto out;
@@ -2354,6 +2374,7 @@ static void cxlflash_worker_thread(struct work_struct *work)
2354 2374
2355 if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0) 2375 if (atomic_dec_if_positive(&cfg->scan_host_needed) >= 0)
2356 scsi_scan_host(cfg->host); 2376 scsi_scan_host(cfg->host);
2377 kref_put(&afu->mapcount, afu_unmap);
2357} 2378}
2358 2379
2359/** 2380/**