aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJan Kiszka <jan.kiszka@siemens.com>2011-11-04 04:45:59 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2012-01-06 15:10:33 -0500
commitfb51ccbf217c1c994607b6519c7d85250928553d (patch)
treed08ba9a0278da0e75b6c6714e9453e46068e27b4 /drivers/scsi
parentae5cd86455381282ece162966183d3f208c6fad7 (diff)
PCI: Rework config space blocking services
pci_block_user_cfg_access was designed for the use case that a single context, the IPR driver, temporarily delays user space accesses to the config space via sysfs. This assumption became invalid by the time pci_dev_reset was added as locking instance. Today, if you run two loops in parallel that reset the same device via sysfs, you end up with a kernel BUG as pci_block_user_cfg_access detect the broken assumption. This reworks the pci_block_user_cfg_access to a sleeping service pci_cfg_access_lock and an atomic-compatible variant called pci_cfg_access_trylock. The former not only blocks user space access as before but also waits if access was already locked. The latter service just returns false in this case, allowing the caller to resolve the conflict instead of raising a BUG. Adaptions of the ipr driver were originally written by Brian King. Acked-by: Brian King <brking@linux.vnet.ibm.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/ipr.c67
-rw-r--r--drivers/scsi/ipr.h1
2 files changed, 61 insertions, 7 deletions
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index fd860d952b28..67b169b7a5be 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -7638,8 +7638,12 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
7638 **/ 7638 **/
7639static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd) 7639static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd)
7640{ 7640{
7641 struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
7642
7641 ENTER; 7643 ENTER;
7642 pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); 7644 if (ioa_cfg->cfg_locked)
7645 pci_cfg_access_unlock(ioa_cfg->pdev);
7646 ioa_cfg->cfg_locked = 0;
7643 ipr_cmd->job_step = ipr_reset_restore_cfg_space; 7647 ipr_cmd->job_step = ipr_reset_restore_cfg_space;
7644 LEAVE; 7648 LEAVE;
7645 return IPR_RC_JOB_CONTINUE; 7649 return IPR_RC_JOB_CONTINUE;
@@ -7660,8 +7664,6 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
7660 int rc = PCIBIOS_SUCCESSFUL; 7664 int rc = PCIBIOS_SUCCESSFUL;
7661 7665
7662 ENTER; 7666 ENTER;
7663 pci_block_user_cfg_access(ioa_cfg->pdev);
7664
7665 if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO) 7667 if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO)
7666 writel(IPR_UPROCI_SIS64_START_BIST, 7668 writel(IPR_UPROCI_SIS64_START_BIST,
7667 ioa_cfg->regs.set_uproc_interrupt_reg32); 7669 ioa_cfg->regs.set_uproc_interrupt_reg32);
@@ -7673,7 +7675,9 @@ static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
7673 ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); 7675 ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
7674 rc = IPR_RC_JOB_RETURN; 7676 rc = IPR_RC_JOB_RETURN;
7675 } else { 7677 } else {
7676 pci_unblock_user_cfg_access(ipr_cmd->ioa_cfg->pdev); 7678 if (ioa_cfg->cfg_locked)
7679 pci_cfg_access_unlock(ipr_cmd->ioa_cfg->pdev);
7680 ioa_cfg->cfg_locked = 0;
7677 ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); 7681 ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
7678 rc = IPR_RC_JOB_CONTINUE; 7682 rc = IPR_RC_JOB_CONTINUE;
7679 } 7683 }
@@ -7716,7 +7720,6 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
7716 struct pci_dev *pdev = ioa_cfg->pdev; 7720 struct pci_dev *pdev = ioa_cfg->pdev;
7717 7721
7718 ENTER; 7722 ENTER;
7719 pci_block_user_cfg_access(pdev);
7720 pci_set_pcie_reset_state(pdev, pcie_warm_reset); 7723 pci_set_pcie_reset_state(pdev, pcie_warm_reset);
7721 ipr_cmd->job_step = ipr_reset_slot_reset_done; 7724 ipr_cmd->job_step = ipr_reset_slot_reset_done;
7722 ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT); 7725 ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT);
@@ -7725,6 +7728,56 @@ static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd)
7725} 7728}
7726 7729
7727/** 7730/**
7731 * ipr_reset_block_config_access_wait - Wait for permission to block config access
7732 * @ipr_cmd: ipr command struct
7733 *
7734 * Description: This attempts to block config access to the IOA.
7735 *
7736 * Return value:
7737 * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
7738 **/
7739static int ipr_reset_block_config_access_wait(struct ipr_cmnd *ipr_cmd)
7740{
7741 struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
7742 int rc = IPR_RC_JOB_CONTINUE;
7743
7744 if (pci_cfg_access_trylock(ioa_cfg->pdev)) {
7745 ioa_cfg->cfg_locked = 1;
7746 ipr_cmd->job_step = ioa_cfg->reset;
7747 } else {
7748 if (ipr_cmd->u.time_left) {
7749 rc = IPR_RC_JOB_RETURN;
7750 ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
7751 ipr_reset_start_timer(ipr_cmd,
7752 IPR_CHECK_FOR_RESET_TIMEOUT);
7753 } else {
7754 ipr_cmd->job_step = ioa_cfg->reset;
7755 dev_err(&ioa_cfg->pdev->dev,
7756 "Timed out waiting to lock config access. Resetting anyway.\n");
7757 }
7758 }
7759
7760 return rc;
7761}
7762
7763/**
7764 * ipr_reset_block_config_access - Block config access to the IOA
7765 * @ipr_cmd: ipr command struct
7766 *
7767 * Description: This attempts to block config access to the IOA
7768 *
7769 * Return value:
7770 * IPR_RC_JOB_CONTINUE
7771 **/
7772static int ipr_reset_block_config_access(struct ipr_cmnd *ipr_cmd)
7773{
7774 ipr_cmd->ioa_cfg->cfg_locked = 0;
7775 ipr_cmd->job_step = ipr_reset_block_config_access_wait;
7776 ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
7777 return IPR_RC_JOB_CONTINUE;
7778}
7779
7780/**
7728 * ipr_reset_allowed - Query whether or not IOA can be reset 7781 * ipr_reset_allowed - Query whether or not IOA can be reset
7729 * @ioa_cfg: ioa config struct 7782 * @ioa_cfg: ioa config struct
7730 * 7783 *
@@ -7763,7 +7816,7 @@ static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd)
7763 ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; 7816 ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
7764 ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); 7817 ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
7765 } else { 7818 } else {
7766 ipr_cmd->job_step = ioa_cfg->reset; 7819 ipr_cmd->job_step = ipr_reset_block_config_access;
7767 rc = IPR_RC_JOB_CONTINUE; 7820 rc = IPR_RC_JOB_CONTINUE;
7768 } 7821 }
7769 7822
@@ -7796,7 +7849,7 @@ static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd)
7796 writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg32); 7849 writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg32);
7797 ipr_cmd->job_step = ipr_reset_wait_to_start_bist; 7850 ipr_cmd->job_step = ipr_reset_wait_to_start_bist;
7798 } else { 7851 } else {
7799 ipr_cmd->job_step = ioa_cfg->reset; 7852 ipr_cmd->job_step = ipr_reset_block_config_access;
7800 } 7853 }
7801 7854
7802 ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; 7855 ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index ac84736c1b9c..b13f9cc12279 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -1387,6 +1387,7 @@ struct ipr_ioa_cfg {
1387 u8 msi_received:1; 1387 u8 msi_received:1;
1388 u8 sis64:1; 1388 u8 sis64:1;
1389 u8 dump_timeout:1; 1389 u8 dump_timeout:1;
1390 u8 cfg_locked:1;
1390 1391
1391 u8 revid; 1392 u8 revid;
1392 1393