All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] pm80xx: Spinlock fix
@ 2013-12-18 11:28 Viswas G
  2013-12-23 13:07 ` Tomas Henzl
  0 siblings, 1 reply; 33+ messages in thread
From: Viswas G @ 2013-12-18 11:28 UTC (permalink / raw)
  To: linux-scsi
  Cc: xjtuwjp, jason.seba42, JBottomley, Vasanthalakshmi.Tharmarajan,
	Suresh.Thiagarajan, Viswas.G

>From 9338d4bc92b23b4c283f9bd6812646ab74866a40 Mon Sep 17 00:00:00 2001
From: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
Date: Mon, 16 Dec 2013 21:15:20 +0530
Subject: [PATCH] pm80xx: Spinlock fix

spin_unlock was used instead of spin_unlock_irqrestore. To fix this 
lock_flags per-adapter is added and used across all the places where pm8001_ha->lock is used.

Reported-by: Jason Seba <jason.seba42@gmail.com>
Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
Signed-off-by: Viswas G <Viswas.G@pmcs.com>
---
 drivers/scsi/pm8001/pm8001_hwi.c |  158 ++++++++++++++++++++++----------------
 drivers/scsi/pm8001/pm8001_sas.c |   50 ++++++------
 drivers/scsi/pm8001/pm8001_sas.h |    1 +
 drivers/scsi/pm8001/pm80xx_hwi.c |   69 ++++++++++-------
 4 files changed, 160 insertions(+), 118 deletions(-)

diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
index 0a1296a..3901c40 100644
--- a/drivers/scsi/pm8001/pm8001_hwi.c
+++ b/drivers/scsi/pm8001/pm8001_hwi.c
@@ -411,7 +411,6 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
 				     u32 SSCbit)
 {
 	u32 value, offset, i;
-	unsigned long flags;
 
 #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
 #define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
@@ -425,10 +424,10 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
     * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
     * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
     */
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	if (-1 == pm8001_bar4_shift(pm8001_ha,
 				SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		return;
 	}
 
@@ -439,7 +438,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
 	/* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
 	if (-1 == pm8001_bar4_shift(pm8001_ha,
 				SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		return;
 	}
 	for (i = 4; i < 8; i++) {
@@ -466,7 +465,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
 
 	/*set the shifted destination address to 0x0 to avoid error operation */
 	pm8001_bar4_shift(pm8001_ha, 0x0);
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	return;
 }
 
@@ -481,7 +480,6 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
 	u32 offset;
 	u32 value;
 	u32 i;
-	unsigned long flags;
 
 #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000
 #define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000
@@ -490,11 +488,11 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
 #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
 
 	value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	/* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
 	if (-1 == pm8001_bar4_shift(pm8001_ha,
 			     OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		return;
 	}
 	for (i = 0; i < 4; i++) {
@@ -504,7 +502,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
 
 	if (-1 == pm8001_bar4_shift(pm8001_ha,
 			     OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		return;
 	}
 	for (i = 4; i < 8; i++) {
@@ -513,7 +511,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
 	}
 	/*set the shifted destination address to 0x0 to avoid error operation */
 	pm8001_bar4_shift(pm8001_ha, 0x0);
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	return;
 }
 
@@ -768,11 +766,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
 		PM8001_INIT_DBG(pm8001_ha,
 			pm8001_printk("Firmware is ready for reset .\n"));
 	} else {
-		unsigned long flags;
 		/* Trigger NMI twice via RB6 */
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			PM8001_FAIL_DBG(pm8001_ha,
 				pm8001_printk("Shift Bar4 to 0x%x failed\n",
 					RB6_ACCESS_REG));
@@ -798,10 +796,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
 			PM8001_FAIL_DBG(pm8001_ha,
 				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
 				pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return -1;
 		}
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	}
 	return 0;
 }
@@ -818,7 +817,6 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 	u32	max_wait_count;
 	u32	regVal1, regVal2, regVal3;
 	u32	signature = 0x252acbcd; /* for host scratch pad0 */
-	unsigned long flags;
 
 	/* step1: Check FW is ready for soft reset */
 	if (soft_reset_ready_check(pm8001_ha) != 0) {
@@ -829,9 +827,9 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 	/* step 2: clear NMI status register on AAP1 and IOP, write the same
 	value to clear */
 	/* map 0x60000 to BAR4(0x20), BAR2(win) */
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("Shift Bar4 to 0x%x failed\n",
 			MBIC_AAP1_ADDR_BASE));
@@ -843,7 +841,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 	pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
 	/* map 0x70000 to BAR4(0x20), BAR2(win) */
 	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("Shift Bar4 to 0x%x failed\n",
 			MBIC_IOP_ADDR_BASE));
@@ -886,7 +884,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 	/* read required registers for confirmming */
 	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
 	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("Shift Bar4 to 0x%x failed\n",
 			GSM_ADDR_BASE));
@@ -953,7 +951,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 	udelay(10);
 	/* step 5-b: set GPIO-0 output control to tristate anyway */
 	if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		PM8001_INIT_DBG(pm8001_ha,
 				pm8001_printk("Shift Bar4 to 0x%x failed\n",
 				GPIO_ADDR_BASE));
@@ -970,7 +968,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 	/* Step 6: Reset the IOP and AAP1 */
 	/* map 0x00000 to BAR4(0x20), BAR2(win) */
 	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
 			SPC_TOP_LEVEL_ADDR_BASE));
@@ -1008,7 +1006,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 	/* step 11: reads and sets the GSM Configuration and Reset Register */
 	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
 	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
 			GSM_ADDR_BASE));
@@ -1062,7 +1060,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 	/* step 13: bring the IOP and AAP1 out of reset */
 	/* map 0x00000 to BAR4(0x20), BAR2(win) */
 	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("Shift Bar4 to 0x%x failed\n",
 			SPC_TOP_LEVEL_ADDR_BASE));
@@ -1104,7 +1102,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
 				pm8001_cr32(pm8001_ha, 0,
 				MSGU_SCRATCH_PAD_3)));
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return -1;
 		}
 
@@ -1134,12 +1133,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
 				pm8001_cr32(pm8001_ha, 0,
 				MSGU_SCRATCH_PAD_3)));
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return -1;
 		}
 	}
 	pm8001_bar4_shift(pm8001_ha, 0);
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 
 	PM8001_INIT_DBG(pm8001_ha,
 		pm8001_printk("SPC soft reset Complete\n"));
@@ -1517,18 +1517,19 @@ void pm8001_work_fn(struct work_struct *work)
 		u32 tag;
 		struct pm8001_ccb_info *ccb;
 		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
-		unsigned long flags, flags1;
+		unsigned long flags1;
 		struct task_status_struct *ts;
 		int i;
 
 		if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
 			break; /* Task still on lu */
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 
 		spin_lock_irqsave(&t->task_state_lock, flags1);
 		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
 			spin_unlock_irqrestore(&t->task_state_lock, flags1);
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			break; /* Task got completed by another */
 		}
 		spin_unlock_irqrestore(&t->task_state_lock, flags1);
@@ -1541,7 +1542,8 @@ void pm8001_work_fn(struct work_struct *work)
 				break;
 		}
 		if (!ccb) {
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			break; /* Task got freed by another */
 		}
 		ts = &t->task_status;
@@ -1562,12 +1564,14 @@ void pm8001_work_fn(struct work_struct *work)
 				" aborted by upper layer!\n",
 				t, pw->handler, ts->resp, ts->stat));
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 		} else {
 			spin_unlock_irqrestore(&t->task_state_lock, flags1);
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/* in order to force CPU ordering */
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
 		}
 	}	break;
@@ -1577,7 +1581,7 @@ void pm8001_work_fn(struct work_struct *work)
 		u32 tag;
 		struct pm8001_ccb_info *ccb;
 		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
-		unsigned long flags, flags1;
+		unsigned long flags1;
 		int i, ret = 0;
 
 		PM8001_IO_DBG(pm8001_ha,
@@ -1600,13 +1604,14 @@ void pm8001_work_fn(struct work_struct *work)
 				break;
 			});
 
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 
 		spin_lock_irqsave(&t->task_state_lock, flags1);
 
 		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
 			spin_unlock_irqrestore(&t->task_state_lock, flags1);
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
 				(void)pm8001_abort_task(t);
 			break; /* Task got completed by another */
@@ -1622,7 +1627,8 @@ void pm8001_work_fn(struct work_struct *work)
 				break;
 		}
 		if (!ccb) {
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
 				(void)pm8001_abort_task(t);
 			break; /* Task got freed by another */
@@ -1634,7 +1640,8 @@ void pm8001_work_fn(struct work_struct *work)
 		switch (ret) {
 		case TMF_RESP_FUNC_SUCC: /* task on lu */
 			ccb->open_retry = 1; /* Snub completion */
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			ret = pm8001_abort_task(t);
 			ccb->open_retry = 0;
 			switch (ret) {
@@ -1651,12 +1658,14 @@ void pm8001_work_fn(struct work_struct *work)
 			break;
 
 		case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			/* Do we need to abort the task locally? */
 			break;
 
 		default: /* device misbehavior */
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			ret = TMF_RESP_FUNC_FAILED;
 			PM8001_IO_DBG(pm8001_ha,
 				pm8001_printk("...Reset phy\n"));
@@ -2504,9 +2513,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*in order to force CPU ordering*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2524,9 +2535,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2552,9 +2565,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/* ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2619,9 +2634,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2643,9 +2660,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2678,16 +2697,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	} else if (!t->uldd_task) {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	}
 }
 
@@ -2798,9 +2817,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2913,16 +2934,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	} else if (!t->uldd_task) {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	}
 }
 
@@ -4194,9 +4215,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
 	void *pMsg1 = NULL;
 	u8 uninitialized_var(bc);
 	u32 ret = MPI_IO_STATUS_FAIL;
-	unsigned long flags;
 
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
 	do {
 		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
@@ -4217,7 +4237,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
 				break;
 		}
 	} while (1);
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	return ret;
 }
 
@@ -4472,18 +4492,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
 							flags);
 				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
 				mb();/* ditto */
-				spin_unlock_irq(&pm8001_ha->lock);
+				spin_unlock_irqrestore(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
+				spin_lock_irqsave(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				return 0;
 			} else if (!task->uldd_task) {
 				spin_unlock_irqrestore(&task->task_state_lock,
 							flags);
 				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
 				mb();/*ditto*/
-				spin_unlock_irq(&pm8001_ha->lock);
+				spin_unlock_irqrestore(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
+				spin_lock_irqsave(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				return 0;
 			}
 		}
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index f50ac44..eac1b81 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -166,7 +166,6 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
 	struct pm8001_hba_info *pm8001_ha = NULL;
 	struct sas_phy_linkrates *rates;
 	DECLARE_COMPLETION_ONSTACK(completion);
-	unsigned long flags;
 	pm8001_ha = sas_phy->ha->lldd_ha;
 	pm8001_ha->phy[phy_id].enable_completion = &completion;
 	switch (func) {
@@ -211,11 +210,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
 		PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
 		break;
 	case PHY_FUNC_GET_EVENTS:
-		spin_lock_irqsave(&pm8001_ha->lock, flags);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		if (pm8001_ha->chip_id == chip_8001) {
 			if (-1 == pm8001_bar4_shift(pm8001_ha,
 					(phy_id < 4) ? 0x30000 : 0x40000)) {
-				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+				spin_unlock_irqrestore(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				return -EINVAL;
 			}
 		}
@@ -232,7 +232,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
 		}
 		if (pm8001_ha->chip_id == chip_8001)
 			pm8001_bar4_shift(pm8001_ha, 0);
-		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		return 0;
 	default:
 		rc = -EOPNOTSUPP;
@@ -369,7 +369,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
 	struct pm8001_ccb_info *ccb;
 	u32 tag = 0xdeadbeef, rc, n_elem = 0;
 	u32 n = num;
-	unsigned long flags = 0;
 
 	if (!dev->port) {
 		struct task_status_struct *tsm = &t->task_status;
@@ -380,8 +379,8 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
 		return 0;
 	}
 	pm8001_ha = pm8001_find_ha_by_dev(task->dev);
-	PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device\n"));
+	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	do {
 		dev = t->dev;
 		pm8001_dev = dev->lldd_dev;
@@ -392,9 +391,11 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
 				ts->resp = SAS_TASK_UNDELIVERED;
 				ts->stat = SAS_PHY_DOWN;
 
-				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+				spin_unlock_irqrestore(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				t->task_done(t);
-				spin_lock_irqsave(&pm8001_ha->lock, flags);
+				spin_lock_irqsave(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				if (n > 1)
 					t = list_entry(t->list.next,
 							struct sas_task, list);
@@ -482,7 +483,7 @@ err_out:
 			dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
 				t->data_dir);
 out_done:
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	return rc;
 }
 
@@ -607,7 +608,6 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
   */
 static int pm8001_dev_found_notify(struct domain_device *dev)
 {
-	unsigned long flags = 0;
 	int res = 0;
 	struct pm8001_hba_info *pm8001_ha = NULL;
 	struct domain_device *parent_dev = dev->parent;
@@ -615,7 +615,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
 	DECLARE_COMPLETION_ONSTACK(completion);
 	u32 flag = 0;
 	pm8001_ha = pm8001_find_ha_by_dev(dev);
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 
 	pm8001_device = pm8001_alloc_dev(pm8001_ha);
 	if (!pm8001_device) {
@@ -654,14 +654,14 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
 	} /*register this device to HBA*/
 	PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
 	PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	wait_for_completion(&completion);
 	if (dev->dev_type == SAS_END_DEVICE)
 		msleep(50);
 	pm8001_ha->flags = PM8001F_RUN_TIME;
 	return 0;
 found_out:
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	return res;
 }
 
@@ -864,13 +864,12 @@ ex_err:
   */
 static void pm8001_dev_gone_notify(struct domain_device *dev)
 {
-	unsigned long flags = 0;
 	u32 tag;
 	struct pm8001_hba_info *pm8001_ha;
 	struct pm8001_device *pm8001_dev = dev->lldd_dev;
 
 	pm8001_ha = pm8001_find_ha_by_dev(dev);
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	pm8001_tag_alloc(pm8001_ha, &tag);
 	if (pm8001_dev) {
 		u32 device_id = pm8001_dev->device_id;
@@ -879,10 +878,12 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
 			pm8001_printk("found dev[%d:%x] is gone.\n",
 			pm8001_dev->device_id, pm8001_dev->dev_type));
 		if (pm8001_dev->running_req) {
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
 				dev, 1, 0);
-			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 		}
 		PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
 		pm8001_free_dev(pm8001_dev);
@@ -891,7 +892,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
 			pm8001_printk("Found dev has gone.\n"));
 	}
 	dev->lldd_dev = NULL;
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 }
 
 void pm8001_dev_gone(struct domain_device *dev)
@@ -918,12 +919,11 @@ void pm8001_open_reject_retry(
 	struct pm8001_device *device_to_close)
 {
 	int i;
-	unsigned long flags;
 
 	if (pm8001_ha == NULL)
 		return;
 
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 
 	for (i = 0; i < PM8001_MAX_CCB; i++) {
 		struct sas_task *task;
@@ -973,13 +973,15 @@ void pm8001_open_reject_retry(
 				flags1);
 			pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
 			mb();/* in order to force CPU ordering */
-			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			task->task_done(task);
-			spin_lock_irqsave(&pm8001_ha->lock, flags);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 		}
 	}
 
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 }
 
 /**
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index 6c5fd5e..2b8065c 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -475,6 +475,7 @@ struct pm8001_hba_info {
 	struct list_head	list;
 	unsigned long		flags;
 	spinlock_t		lock;/* host-wide lock */
+	unsigned long		lock_flags;
 	struct pci_dev		*pdev;/* our device */
 	struct device		*dev;
 	struct pm8001_hba_memspace io_mem[6];
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index c950dc5..3ac024a 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -2177,9 +2177,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*in order to force CPU ordering*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2197,9 +2199,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2223,9 +2227,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/* ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2290,9 +2296,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2314,9 +2322,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2349,16 +2359,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	} else if (!t->uldd_task) {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	}
 }
 
@@ -2472,9 +2482,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
 			ts->stat = SAS_QUEUE_FULL;
 			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
+			spin_unlock_irqrestore(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			spin_lock_irqsave(&pm8001_ha->lock,
+						pm8001_ha->lock_flags);
 			return;
 		}
 		break;
@@ -2600,16 +2612,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	} else if (!t->uldd_task) {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
 		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
+		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	}
 }
 
@@ -3705,9 +3717,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
 	void *pMsg1 = NULL;
 	u8 uninitialized_var(bc);
 	u32 ret = MPI_IO_STATUS_FAIL;
-	unsigned long flags;
 
-	spin_lock_irqsave(&pm8001_ha->lock, flags);
+	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
 	do {
 		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
@@ -3728,7 +3739,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
 				break;
 		}
 	} while (1);
-	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
+	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
 	return ret;
 }
 
@@ -4309,18 +4320,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
 							flags);
 				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
 				mb();/* ditto */
-				spin_unlock_irq(&pm8001_ha->lock);
+				spin_unlock_irqrestore(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
+				spin_lock_irqsave(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				return 0;
 			} else if (!task->uldd_task) {
 				spin_unlock_irqrestore(&task->task_state_lock,
 							flags);
 				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
 				mb();/*ditto*/
-				spin_unlock_irq(&pm8001_ha->lock);
+				spin_unlock_irqrestore(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
+				spin_lock_irqsave(&pm8001_ha->lock,
+							pm8001_ha->lock_flags);
 				return 0;
 			}
 		}
-- 
1.7.6


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [PATCH] pm80xx: Spinlock fix
  2013-12-18 11:28 [PATCH] pm80xx: Spinlock fix Viswas G
@ 2013-12-23 13:07 ` Tomas Henzl
  2013-12-23 13:32   ` Jack Wang
  0 siblings, 1 reply; 33+ messages in thread
From: Tomas Henzl @ 2013-12-23 13:07 UTC (permalink / raw)
  To: Viswas G, linux-scsi
  Cc: xjtuwjp, jason.seba42, JBottomley, Vasanthalakshmi.Tharmarajan,
	Suresh.Thiagarajan

On 12/18/2013 12:28 PM, Viswas G wrote:
> From 9338d4bc92b23b4c283f9bd6812646ab74866a40 Mon Sep 17 00:00:00 2001
> From: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
> Date: Mon, 16 Dec 2013 21:15:20 +0530
> Subject: [PATCH] pm80xx: Spinlock fix
>
> spin_unlock was used instead of spin_unlock_irqrestore. To fix this 
> lock_flags per-adapter is added and used across all the places where pm8001_ha->lock is used.

I think this could have been fixed but just using spin_unlock_irqsave instead of spin_unlock_irq
why the change to global lock_flags?  I'm not a spinlock expert, but is this safe?

>
> Reported-by: Jason Seba <jason.seba42@gmail.com>
> Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
> Signed-off-by: Viswas G <Viswas.G@pmcs.com>
> ---
>  drivers/scsi/pm8001/pm8001_hwi.c |  158 ++++++++++++++++++++++----------------
>  drivers/scsi/pm8001/pm8001_sas.c |   50 ++++++------
>  drivers/scsi/pm8001/pm8001_sas.h |    1 +
>  drivers/scsi/pm8001/pm80xx_hwi.c |   69 ++++++++++-------
>  4 files changed, 160 insertions(+), 118 deletions(-)
>
> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
> index 0a1296a..3901c40 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.c
> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
> @@ -411,7 +411,6 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>  				     u32 SSCbit)
>  {
>  	u32 value, offset, i;
> -	unsigned long flags;
>  
>  #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
>  #define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
> @@ -425,10 +424,10 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>      * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
>      * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
>      */
> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>  				SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		return;
>  	}
>  
> @@ -439,7 +438,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>  	/* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>  				SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		return;
>  	}
>  	for (i = 4; i < 8; i++) {
> @@ -466,7 +465,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>  
>  	/*set the shifted destination address to 0x0 to avoid error operation */
>  	pm8001_bar4_shift(pm8001_ha, 0x0);
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	return;
>  }
>  
> @@ -481,7 +480,6 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>  	u32 offset;
>  	u32 value;
>  	u32 i;
> -	unsigned long flags;
>  
>  #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000
>  #define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000
> @@ -490,11 +488,11 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>  #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
>  
>  	value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	/* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>  			     OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		return;
>  	}
>  	for (i = 0; i < 4; i++) {
> @@ -504,7 +502,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>  
>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>  			     OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		return;
>  	}
>  	for (i = 4; i < 8; i++) {
> @@ -513,7 +511,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>  	}
>  	/*set the shifted destination address to 0x0 to avoid error operation */
>  	pm8001_bar4_shift(pm8001_ha, 0x0);
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	return;
>  }
>  
> @@ -768,11 +766,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>  		PM8001_INIT_DBG(pm8001_ha,
>  			pm8001_printk("Firmware is ready for reset .\n"));
>  	} else {
> -		unsigned long flags;
>  		/* Trigger NMI twice via RB6 */
> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			PM8001_FAIL_DBG(pm8001_ha,
>  				pm8001_printk("Shift Bar4 to 0x%x failed\n",
>  					RB6_ACCESS_REG));
> @@ -798,10 +796,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>  			PM8001_FAIL_DBG(pm8001_ha,
>  				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>  				pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return -1;
>  		}
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	}
>  	return 0;
>  }
> @@ -818,7 +817,6 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  	u32	max_wait_count;
>  	u32	regVal1, regVal2, regVal3;
>  	u32	signature = 0x252acbcd; /* for host scratch pad0 */
> -	unsigned long flags;
>  
>  	/* step1: Check FW is ready for soft reset */
>  	if (soft_reset_ready_check(pm8001_ha) != 0) {
> @@ -829,9 +827,9 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  	/* step 2: clear NMI status register on AAP1 and IOP, write the same
>  	value to clear */
>  	/* map 0x60000 to BAR4(0x20), BAR2(win) */
> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		PM8001_FAIL_DBG(pm8001_ha,
>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>  			MBIC_AAP1_ADDR_BASE));
> @@ -843,7 +841,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  	pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
>  	/* map 0x70000 to BAR4(0x20), BAR2(win) */
>  	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		PM8001_FAIL_DBG(pm8001_ha,
>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>  			MBIC_IOP_ADDR_BASE));
> @@ -886,7 +884,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  	/* read required registers for confirmming */
>  	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
>  	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		PM8001_FAIL_DBG(pm8001_ha,
>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>  			GSM_ADDR_BASE));
> @@ -953,7 +951,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  	udelay(10);
>  	/* step 5-b: set GPIO-0 output control to tristate anyway */
>  	if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		PM8001_INIT_DBG(pm8001_ha,
>  				pm8001_printk("Shift Bar4 to 0x%x failed\n",
>  				GPIO_ADDR_BASE));
> @@ -970,7 +968,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  	/* Step 6: Reset the IOP and AAP1 */
>  	/* map 0x00000 to BAR4(0x20), BAR2(win) */
>  	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		PM8001_FAIL_DBG(pm8001_ha,
>  			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>  			SPC_TOP_LEVEL_ADDR_BASE));
> @@ -1008,7 +1006,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  	/* step 11: reads and sets the GSM Configuration and Reset Register */
>  	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
>  	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		PM8001_FAIL_DBG(pm8001_ha,
>  			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>  			GSM_ADDR_BASE));
> @@ -1062,7 +1060,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  	/* step 13: bring the IOP and AAP1 out of reset */
>  	/* map 0x00000 to BAR4(0x20), BAR2(win) */
>  	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		PM8001_FAIL_DBG(pm8001_ha,
>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>  			SPC_TOP_LEVEL_ADDR_BASE));
> @@ -1104,7 +1102,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>  				pm8001_cr32(pm8001_ha, 0,
>  				MSGU_SCRATCH_PAD_3)));
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return -1;
>  		}
>  
> @@ -1134,12 +1133,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>  				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>  				pm8001_cr32(pm8001_ha, 0,
>  				MSGU_SCRATCH_PAD_3)));
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return -1;
>  		}
>  	}
>  	pm8001_bar4_shift(pm8001_ha, 0);
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  
>  	PM8001_INIT_DBG(pm8001_ha,
>  		pm8001_printk("SPC soft reset Complete\n"));
> @@ -1517,18 +1517,19 @@ void pm8001_work_fn(struct work_struct *work)
>  		u32 tag;
>  		struct pm8001_ccb_info *ccb;
>  		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
> -		unsigned long flags, flags1;
> +		unsigned long flags1;
>  		struct task_status_struct *ts;
>  		int i;
>  
>  		if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
>  			break; /* Task still on lu */
> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  
>  		spin_lock_irqsave(&t->task_state_lock, flags1);
>  		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>  			spin_unlock_irqrestore(&t->task_state_lock, flags1);
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			break; /* Task got completed by another */
>  		}
>  		spin_unlock_irqrestore(&t->task_state_lock, flags1);
> @@ -1541,7 +1542,8 @@ void pm8001_work_fn(struct work_struct *work)
>  				break;
>  		}
>  		if (!ccb) {
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			break; /* Task got freed by another */
>  		}
>  		ts = &t->task_status;
> @@ -1562,12 +1564,14 @@ void pm8001_work_fn(struct work_struct *work)
>  				" aborted by upper layer!\n",
>  				t, pw->handler, ts->resp, ts->stat));
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  		} else {
>  			spin_unlock_irqrestore(&t->task_state_lock, flags1);
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/* in order to force CPU ordering */
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
>  		}
>  	}	break;
> @@ -1577,7 +1581,7 @@ void pm8001_work_fn(struct work_struct *work)
>  		u32 tag;
>  		struct pm8001_ccb_info *ccb;
>  		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
> -		unsigned long flags, flags1;
> +		unsigned long flags1;
>  		int i, ret = 0;
>  
>  		PM8001_IO_DBG(pm8001_ha,
> @@ -1600,13 +1604,14 @@ void pm8001_work_fn(struct work_struct *work)
>  				break;
>  			});
>  
> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  
>  		spin_lock_irqsave(&t->task_state_lock, flags1);
>  
>  		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>  			spin_unlock_irqrestore(&t->task_state_lock, flags1);
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>  				(void)pm8001_abort_task(t);
>  			break; /* Task got completed by another */
> @@ -1622,7 +1627,8 @@ void pm8001_work_fn(struct work_struct *work)
>  				break;
>  		}
>  		if (!ccb) {
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>  				(void)pm8001_abort_task(t);
>  			break; /* Task got freed by another */
> @@ -1634,7 +1640,8 @@ void pm8001_work_fn(struct work_struct *work)
>  		switch (ret) {
>  		case TMF_RESP_FUNC_SUCC: /* task on lu */
>  			ccb->open_retry = 1; /* Snub completion */
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			ret = pm8001_abort_task(t);
>  			ccb->open_retry = 0;
>  			switch (ret) {
> @@ -1651,12 +1658,14 @@ void pm8001_work_fn(struct work_struct *work)
>  			break;
>  
>  		case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			/* Do we need to abort the task locally? */
>  			break;
>  
>  		default: /* device misbehavior */
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			ret = TMF_RESP_FUNC_FAILED;
>  			PM8001_IO_DBG(pm8001_ha,
>  				pm8001_printk("...Reset phy\n"));
> @@ -2504,9 +2513,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*in order to force CPU ordering*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2524,9 +2535,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2552,9 +2565,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/* ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2619,9 +2634,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2643,9 +2660,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2678,16 +2697,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  		mb();/* ditto */
> -		spin_unlock_irq(&pm8001_ha->lock);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		t->task_done(t);
> -		spin_lock_irq(&pm8001_ha->lock);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	} else if (!t->uldd_task) {
>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  		mb();/*ditto*/
> -		spin_unlock_irq(&pm8001_ha->lock);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		t->task_done(t);
> -		spin_lock_irq(&pm8001_ha->lock);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	}
>  }
>  
> @@ -2798,9 +2817,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2913,16 +2934,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  		mb();/* ditto */
> -		spin_unlock_irq(&pm8001_ha->lock);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		t->task_done(t);
> -		spin_lock_irq(&pm8001_ha->lock);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	} else if (!t->uldd_task) {
>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  		mb();/*ditto*/
> -		spin_unlock_irq(&pm8001_ha->lock);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		t->task_done(t);
> -		spin_lock_irq(&pm8001_ha->lock);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	}
>  }
>  
> @@ -4194,9 +4215,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>  	void *pMsg1 = NULL;
>  	u8 uninitialized_var(bc);
>  	u32 ret = MPI_IO_STATUS_FAIL;
> -	unsigned long flags;
>  
> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>  	do {
>  		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
> @@ -4217,7 +4237,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>  				break;
>  		}
>  	} while (1);
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	return ret;
>  }
>  
> @@ -4472,18 +4492,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>  							flags);
>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>  				mb();/* ditto */
> -				spin_unlock_irq(&pm8001_ha->lock);
> +				spin_unlock_irqrestore(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				task->task_done(task);
> -				spin_lock_irq(&pm8001_ha->lock);
> +				spin_lock_irqsave(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				return 0;
>  			} else if (!task->uldd_task) {
>  				spin_unlock_irqrestore(&task->task_state_lock,
>  							flags);
>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>  				mb();/*ditto*/
> -				spin_unlock_irq(&pm8001_ha->lock);
> +				spin_unlock_irqrestore(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				task->task_done(task);
> -				spin_lock_irq(&pm8001_ha->lock);
> +				spin_lock_irqsave(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				return 0;
>  			}
>  		}
> diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
> index f50ac44..eac1b81 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.c
> +++ b/drivers/scsi/pm8001/pm8001_sas.c
> @@ -166,7 +166,6 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>  	struct pm8001_hba_info *pm8001_ha = NULL;
>  	struct sas_phy_linkrates *rates;
>  	DECLARE_COMPLETION_ONSTACK(completion);
> -	unsigned long flags;
>  	pm8001_ha = sas_phy->ha->lldd_ha;
>  	pm8001_ha->phy[phy_id].enable_completion = &completion;
>  	switch (func) {
> @@ -211,11 +210,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>  		PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
>  		break;
>  	case PHY_FUNC_GET_EVENTS:
> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		if (pm8001_ha->chip_id == chip_8001) {
>  			if (-1 == pm8001_bar4_shift(pm8001_ha,
>  					(phy_id < 4) ? 0x30000 : 0x40000)) {
> -				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +				spin_unlock_irqrestore(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				return -EINVAL;
>  			}
>  		}
> @@ -232,7 +232,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>  		}
>  		if (pm8001_ha->chip_id == chip_8001)
>  			pm8001_bar4_shift(pm8001_ha, 0);
> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		return 0;
>  	default:
>  		rc = -EOPNOTSUPP;
> @@ -369,7 +369,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>  	struct pm8001_ccb_info *ccb;
>  	u32 tag = 0xdeadbeef, rc, n_elem = 0;
>  	u32 n = num;
> -	unsigned long flags = 0;
>  
>  	if (!dev->port) {
>  		struct task_status_struct *tsm = &t->task_status;
> @@ -380,8 +379,8 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>  		return 0;
>  	}
>  	pm8001_ha = pm8001_find_ha_by_dev(task->dev);
> -	PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
> +	PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device\n"));
> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	do {
>  		dev = t->dev;
>  		pm8001_dev = dev->lldd_dev;
> @@ -392,9 +391,11 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>  				ts->resp = SAS_TASK_UNDELIVERED;
>  				ts->stat = SAS_PHY_DOWN;
>  
> -				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +				spin_unlock_irqrestore(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				t->task_done(t);
> -				spin_lock_irqsave(&pm8001_ha->lock, flags);
> +				spin_lock_irqsave(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				if (n > 1)
>  					t = list_entry(t->list.next,
>  							struct sas_task, list);
> @@ -482,7 +483,7 @@ err_out:
>  			dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
>  				t->data_dir);
>  out_done:
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	return rc;
>  }
>  
> @@ -607,7 +608,6 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
>    */
>  static int pm8001_dev_found_notify(struct domain_device *dev)
>  {
> -	unsigned long flags = 0;
>  	int res = 0;
>  	struct pm8001_hba_info *pm8001_ha = NULL;
>  	struct domain_device *parent_dev = dev->parent;
> @@ -615,7 +615,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>  	DECLARE_COMPLETION_ONSTACK(completion);
>  	u32 flag = 0;
>  	pm8001_ha = pm8001_find_ha_by_dev(dev);
> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  
>  	pm8001_device = pm8001_alloc_dev(pm8001_ha);
>  	if (!pm8001_device) {
> @@ -654,14 +654,14 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>  	} /*register this device to HBA*/
>  	PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
>  	PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	wait_for_completion(&completion);
>  	if (dev->dev_type == SAS_END_DEVICE)
>  		msleep(50);
>  	pm8001_ha->flags = PM8001F_RUN_TIME;
>  	return 0;
>  found_out:
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	return res;
>  }
>  
> @@ -864,13 +864,12 @@ ex_err:
>    */
>  static void pm8001_dev_gone_notify(struct domain_device *dev)
>  {
> -	unsigned long flags = 0;
>  	u32 tag;
>  	struct pm8001_hba_info *pm8001_ha;
>  	struct pm8001_device *pm8001_dev = dev->lldd_dev;
>  
>  	pm8001_ha = pm8001_find_ha_by_dev(dev);
> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	pm8001_tag_alloc(pm8001_ha, &tag);
>  	if (pm8001_dev) {
>  		u32 device_id = pm8001_dev->device_id;
> @@ -879,10 +878,12 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>  			pm8001_printk("found dev[%d:%x] is gone.\n",
>  			pm8001_dev->device_id, pm8001_dev->dev_type));
>  		if (pm8001_dev->running_req) {
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
>  				dev, 1, 0);
> -			spin_lock_irqsave(&pm8001_ha->lock, flags);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  		}
>  		PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
>  		pm8001_free_dev(pm8001_dev);
> @@ -891,7 +892,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>  			pm8001_printk("Found dev has gone.\n"));
>  	}
>  	dev->lldd_dev = NULL;
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  }
>  
>  void pm8001_dev_gone(struct domain_device *dev)
> @@ -918,12 +919,11 @@ void pm8001_open_reject_retry(
>  	struct pm8001_device *device_to_close)
>  {
>  	int i;
> -	unsigned long flags;
>  
>  	if (pm8001_ha == NULL)
>  		return;
>  
> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  
>  	for (i = 0; i < PM8001_MAX_CCB; i++) {
>  		struct sas_task *task;
> @@ -973,13 +973,15 @@ void pm8001_open_reject_retry(
>  				flags1);
>  			pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>  			mb();/* in order to force CPU ordering */
> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			task->task_done(task);
> -			spin_lock_irqsave(&pm8001_ha->lock, flags);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  		}
>  	}
>  
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  }
>  
>  /**
> diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
> index 6c5fd5e..2b8065c 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.h
> +++ b/drivers/scsi/pm8001/pm8001_sas.h
> @@ -475,6 +475,7 @@ struct pm8001_hba_info {
>  	struct list_head	list;
>  	unsigned long		flags;
>  	spinlock_t		lock;/* host-wide lock */
> +	unsigned long		lock_flags;
>  	struct pci_dev		*pdev;/* our device */
>  	struct device		*dev;
>  	struct pm8001_hba_memspace io_mem[6];
> diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
> index c950dc5..3ac024a 100644
> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
> @@ -2177,9 +2177,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*in order to force CPU ordering*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2197,9 +2199,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2223,9 +2227,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/* ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2290,9 +2296,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2314,9 +2322,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2349,16 +2359,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  		mb();/* ditto */
> -		spin_unlock_irq(&pm8001_ha->lock);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		t->task_done(t);
> -		spin_lock_irq(&pm8001_ha->lock);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	} else if (!t->uldd_task) {
>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  		mb();/*ditto*/
> -		spin_unlock_irq(&pm8001_ha->lock);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		t->task_done(t);
> -		spin_lock_irq(&pm8001_ha->lock);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	}
>  }
>  
> @@ -2472,9 +2482,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>  			ts->stat = SAS_QUEUE_FULL;
>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  			mb();/*ditto*/
> -			spin_unlock_irq(&pm8001_ha->lock);
> +			spin_unlock_irqrestore(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			t->task_done(t);
> -			spin_lock_irq(&pm8001_ha->lock);
> +			spin_lock_irqsave(&pm8001_ha->lock,
> +						pm8001_ha->lock_flags);
>  			return;
>  		}
>  		break;
> @@ -2600,16 +2612,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  		mb();/* ditto */
> -		spin_unlock_irq(&pm8001_ha->lock);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		t->task_done(t);
> -		spin_lock_irq(&pm8001_ha->lock);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	} else if (!t->uldd_task) {
>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>  		mb();/*ditto*/
> -		spin_unlock_irq(&pm8001_ha->lock);
> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  		t->task_done(t);
> -		spin_lock_irq(&pm8001_ha->lock);
> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	}
>  }
>  
> @@ -3705,9 +3717,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>  	void *pMsg1 = NULL;
>  	u8 uninitialized_var(bc);
>  	u32 ret = MPI_IO_STATUS_FAIL;
> -	unsigned long flags;
>  
> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>  	do {
>  		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
> @@ -3728,7 +3739,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>  				break;
>  		}
>  	} while (1);
> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>  	return ret;
>  }
>  
> @@ -4309,18 +4320,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>  							flags);
>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>  				mb();/* ditto */
> -				spin_unlock_irq(&pm8001_ha->lock);
> +				spin_unlock_irqrestore(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				task->task_done(task);
> -				spin_lock_irq(&pm8001_ha->lock);
> +				spin_lock_irqsave(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				return 0;
>  			} else if (!task->uldd_task) {
>  				spin_unlock_irqrestore(&task->task_state_lock,
>  							flags);
>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>  				mb();/*ditto*/
> -				spin_unlock_irq(&pm8001_ha->lock);
> +				spin_unlock_irqrestore(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				task->task_done(task);
> -				spin_lock_irq(&pm8001_ha->lock);
> +				spin_lock_irqsave(&pm8001_ha->lock,
> +							pm8001_ha->lock_flags);
>  				return 0;
>  			}
>  		}


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] pm80xx: Spinlock fix
  2013-12-23 13:07 ` Tomas Henzl
@ 2013-12-23 13:32   ` Jack Wang
  2013-12-23 13:45     ` Suresh Thiagarajan
  0 siblings, 1 reply; 33+ messages in thread
From: Jack Wang @ 2013-12-23 13:32 UTC (permalink / raw)
  To: Tomas Henzl, Viswas G
  Cc: linux-scsi, jason.seba42, JBottomley,
	Vasanthalakshmi.Tharmarajan, Suresh.Thiagarajan

On 12/23/2013 02:07 PM, Tomas Henzl wrote:
> On 12/18/2013 12:28 PM, Viswas G wrote:
>> From 9338d4bc92b23b4c283f9bd6812646ab74866a40 Mon Sep 17 00:00:00 2001
>> From: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>> Date: Mon, 16 Dec 2013 21:15:20 +0530
>> Subject: [PATCH] pm80xx: Spinlock fix
>>
>> spin_unlock was used instead of spin_unlock_irqrestore. To fix this 
>> lock_flags per-adapter is added and used across all the places where pm8001_ha->lock is used.
> 
> I think this could have been fixed but just using spin_unlock_irqsave instead of spin_unlock_irq
> why the change to global lock_flags?  I'm not a spinlock expert, but is this safe?
> 
Agree with Tomas, it's dangerous to change to global lock_flags.

Have you reproduce the bug reported from Jason, and verify the patch?
I think better just to change the spin_lock_irq to spin_lock_irqsave if
that is the cause.

Jack
>>
>> Reported-by: Jason Seba <jason.seba42@gmail.com>
>> Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>> Signed-off-by: Viswas G <Viswas.G@pmcs.com>
>> ---
>>  drivers/scsi/pm8001/pm8001_hwi.c |  158 ++++++++++++++++++++++----------------
>>  drivers/scsi/pm8001/pm8001_sas.c |   50 ++++++------
>>  drivers/scsi/pm8001/pm8001_sas.h |    1 +
>>  drivers/scsi/pm8001/pm80xx_hwi.c |   69 ++++++++++-------
>>  4 files changed, 160 insertions(+), 118 deletions(-)
>>
>> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c
>> index 0a1296a..3901c40 100644
>> --- a/drivers/scsi/pm8001/pm8001_hwi.c
>> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
>> @@ -411,7 +411,6 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>  				     u32 SSCbit)
>>  {
>>  	u32 value, offset, i;
>> -	unsigned long flags;
>>  
>>  #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
>>  #define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
>> @@ -425,10 +424,10 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>      * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
>>      * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
>>      */
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  				SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return;
>>  	}
>>  
>> @@ -439,7 +438,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>  	/* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  				SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return;
>>  	}
>>  	for (i = 4; i < 8; i++) {
>> @@ -466,7 +465,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>  
>>  	/*set the shifted destination address to 0x0 to avoid error operation */
>>  	pm8001_bar4_shift(pm8001_ha, 0x0);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return;
>>  }
>>  
>> @@ -481,7 +480,6 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>  	u32 offset;
>>  	u32 value;
>>  	u32 i;
>> -	unsigned long flags;
>>  
>>  #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000
>>  #define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000
>> @@ -490,11 +488,11 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>  #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
>>  
>>  	value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	/* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  			     OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return;
>>  	}
>>  	for (i = 0; i < 4; i++) {
>> @@ -504,7 +502,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>  
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  			     OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return;
>>  	}
>>  	for (i = 4; i < 8; i++) {
>> @@ -513,7 +511,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>  	}
>>  	/*set the shifted destination address to 0x0 to avoid error operation */
>>  	pm8001_bar4_shift(pm8001_ha, 0x0);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return;
>>  }
>>  
>> @@ -768,11 +766,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>  		PM8001_INIT_DBG(pm8001_ha,
>>  			pm8001_printk("Firmware is ready for reset .\n"));
>>  	} else {
>> -		unsigned long flags;
>>  		/* Trigger NMI twice via RB6 */
>> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			PM8001_FAIL_DBG(pm8001_ha,
>>  				pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  					RB6_ACCESS_REG));
>> @@ -798,10 +796,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>  			PM8001_FAIL_DBG(pm8001_ha,
>>  				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>  				pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return -1;
>>  		}
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  	return 0;
>>  }
>> @@ -818,7 +817,6 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	u32	max_wait_count;
>>  	u32	regVal1, regVal2, regVal3;
>>  	u32	signature = 0x252acbcd; /* for host scratch pad0 */
>> -	unsigned long flags;
>>  
>>  	/* step1: Check FW is ready for soft reset */
>>  	if (soft_reset_ready_check(pm8001_ha) != 0) {
>> @@ -829,9 +827,9 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* step 2: clear NMI status register on AAP1 and IOP, write the same
>>  	value to clear */
>>  	/* map 0x60000 to BAR4(0x20), BAR2(win) */
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  			MBIC_AAP1_ADDR_BASE));
>> @@ -843,7 +841,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
>>  	/* map 0x70000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  			MBIC_IOP_ADDR_BASE));
>> @@ -886,7 +884,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* read required registers for confirmming */
>>  	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  			GSM_ADDR_BASE));
>> @@ -953,7 +951,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	udelay(10);
>>  	/* step 5-b: set GPIO-0 output control to tristate anyway */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_INIT_DBG(pm8001_ha,
>>  				pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  				GPIO_ADDR_BASE));
>> @@ -970,7 +968,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* Step 6: Reset the IOP and AAP1 */
>>  	/* map 0x00000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>  			SPC_TOP_LEVEL_ADDR_BASE));
>> @@ -1008,7 +1006,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* step 11: reads and sets the GSM Configuration and Reset Register */
>>  	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>  			GSM_ADDR_BASE));
>> @@ -1062,7 +1060,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* step 13: bring the IOP and AAP1 out of reset */
>>  	/* map 0x00000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  			SPC_TOP_LEVEL_ADDR_BASE));
>> @@ -1104,7 +1102,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>  				pm8001_cr32(pm8001_ha, 0,
>>  				MSGU_SCRATCH_PAD_3)));
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return -1;
>>  		}
>>  
>> @@ -1134,12 +1133,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>  				pm8001_cr32(pm8001_ha, 0,
>>  				MSGU_SCRATCH_PAD_3)));
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return -1;
>>  		}
>>  	}
>>  	pm8001_bar4_shift(pm8001_ha, 0);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  	PM8001_INIT_DBG(pm8001_ha,
>>  		pm8001_printk("SPC soft reset Complete\n"));
>> @@ -1517,18 +1517,19 @@ void pm8001_work_fn(struct work_struct *work)
>>  		u32 tag;
>>  		struct pm8001_ccb_info *ccb;
>>  		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>> -		unsigned long flags, flags1;
>> +		unsigned long flags1;
>>  		struct task_status_struct *ts;
>>  		int i;
>>  
>>  		if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
>>  			break; /* Task still on lu */
>> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  		spin_lock_irqsave(&t->task_state_lock, flags1);
>>  		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>  			spin_unlock_irqrestore(&t->task_state_lock, flags1);
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			break; /* Task got completed by another */
>>  		}
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags1);
>> @@ -1541,7 +1542,8 @@ void pm8001_work_fn(struct work_struct *work)
>>  				break;
>>  		}
>>  		if (!ccb) {
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			break; /* Task got freed by another */
>>  		}
>>  		ts = &t->task_status;
>> @@ -1562,12 +1564,14 @@ void pm8001_work_fn(struct work_struct *work)
>>  				" aborted by upper layer!\n",
>>  				t, pw->handler, ts->resp, ts->stat));
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  		} else {
>>  			spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/* in order to force CPU ordering */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>>  		}
>>  	}	break;
>> @@ -1577,7 +1581,7 @@ void pm8001_work_fn(struct work_struct *work)
>>  		u32 tag;
>>  		struct pm8001_ccb_info *ccb;
>>  		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>> -		unsigned long flags, flags1;
>> +		unsigned long flags1;
>>  		int i, ret = 0;
>>  
>>  		PM8001_IO_DBG(pm8001_ha,
>> @@ -1600,13 +1604,14 @@ void pm8001_work_fn(struct work_struct *work)
>>  				break;
>>  			});
>>  
>> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  		spin_lock_irqsave(&t->task_state_lock, flags1);
>>  
>>  		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>  			spin_unlock_irqrestore(&t->task_state_lock, flags1);
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>  				(void)pm8001_abort_task(t);
>>  			break; /* Task got completed by another */
>> @@ -1622,7 +1627,8 @@ void pm8001_work_fn(struct work_struct *work)
>>  				break;
>>  		}
>>  		if (!ccb) {
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>  				(void)pm8001_abort_task(t);
>>  			break; /* Task got freed by another */
>> @@ -1634,7 +1640,8 @@ void pm8001_work_fn(struct work_struct *work)
>>  		switch (ret) {
>>  		case TMF_RESP_FUNC_SUCC: /* task on lu */
>>  			ccb->open_retry = 1; /* Snub completion */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			ret = pm8001_abort_task(t);
>>  			ccb->open_retry = 0;
>>  			switch (ret) {
>> @@ -1651,12 +1658,14 @@ void pm8001_work_fn(struct work_struct *work)
>>  			break;
>>  
>>  		case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			/* Do we need to abort the task locally? */
>>  			break;
>>  
>>  		default: /* device misbehavior */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			ret = TMF_RESP_FUNC_FAILED;
>>  			PM8001_IO_DBG(pm8001_ha,
>>  				pm8001_printk("...Reset phy\n"));
>> @@ -2504,9 +2513,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*in order to force CPU ordering*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2524,9 +2535,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2552,9 +2565,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/* ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2619,9 +2634,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2643,9 +2660,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2678,16 +2697,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/* ditto */
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	} else if (!t->uldd_task) {
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/*ditto*/
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  }
>>  
>> @@ -2798,9 +2817,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2913,16 +2934,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/* ditto */
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	} else if (!t->uldd_task) {
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/*ditto*/
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  }
>>  
>> @@ -4194,9 +4215,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>  	void *pMsg1 = NULL;
>>  	u8 uninitialized_var(bc);
>>  	u32 ret = MPI_IO_STATUS_FAIL;
>> -	unsigned long flags;
>>  
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>  	do {
>>  		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>> @@ -4217,7 +4237,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>  				break;
>>  		}
>>  	} while (1);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return ret;
>>  }
>>  
>> @@ -4472,18 +4492,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>  							flags);
>>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  				mb();/* ditto */
>> -				spin_unlock_irq(&pm8001_ha->lock);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				task->task_done(task);
>> -				spin_lock_irq(&pm8001_ha->lock);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return 0;
>>  			} else if (!task->uldd_task) {
>>  				spin_unlock_irqrestore(&task->task_state_lock,
>>  							flags);
>>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  				mb();/*ditto*/
>> -				spin_unlock_irq(&pm8001_ha->lock);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				task->task_done(task);
>> -				spin_lock_irq(&pm8001_ha->lock);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return 0;
>>  			}
>>  		}
>> diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
>> index f50ac44..eac1b81 100644
>> --- a/drivers/scsi/pm8001/pm8001_sas.c
>> +++ b/drivers/scsi/pm8001/pm8001_sas.c
>> @@ -166,7 +166,6 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>  	struct pm8001_hba_info *pm8001_ha = NULL;
>>  	struct sas_phy_linkrates *rates;
>>  	DECLARE_COMPLETION_ONSTACK(completion);
>> -	unsigned long flags;
>>  	pm8001_ha = sas_phy->ha->lldd_ha;
>>  	pm8001_ha->phy[phy_id].enable_completion = &completion;
>>  	switch (func) {
>> @@ -211,11 +210,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>  		PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
>>  		break;
>>  	case PHY_FUNC_GET_EVENTS:
>> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		if (pm8001_ha->chip_id == chip_8001) {
>>  			if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  					(phy_id < 4) ? 0x30000 : 0x40000)) {
>> -				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return -EINVAL;
>>  			}
>>  		}
>> @@ -232,7 +232,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>  		}
>>  		if (pm8001_ha->chip_id == chip_8001)
>>  			pm8001_bar4_shift(pm8001_ha, 0);
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return 0;
>>  	default:
>>  		rc = -EOPNOTSUPP;
>> @@ -369,7 +369,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>  	struct pm8001_ccb_info *ccb;
>>  	u32 tag = 0xdeadbeef, rc, n_elem = 0;
>>  	u32 n = num;
>> -	unsigned long flags = 0;
>>  
>>  	if (!dev->port) {
>>  		struct task_status_struct *tsm = &t->task_status;
>> @@ -380,8 +379,8 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>  		return 0;
>>  	}
>>  	pm8001_ha = pm8001_find_ha_by_dev(task->dev);
>> -	PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device\n"));
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	do {
>>  		dev = t->dev;
>>  		pm8001_dev = dev->lldd_dev;
>> @@ -392,9 +391,11 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>  				ts->resp = SAS_TASK_UNDELIVERED;
>>  				ts->stat = SAS_PHY_DOWN;
>>  
>> -				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				t->task_done(t);
>> -				spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				if (n > 1)
>>  					t = list_entry(t->list.next,
>>  							struct sas_task, list);
>> @@ -482,7 +483,7 @@ err_out:
>>  			dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
>>  				t->data_dir);
>>  out_done:
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return rc;
>>  }
>>  
>> @@ -607,7 +608,6 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
>>    */
>>  static int pm8001_dev_found_notify(struct domain_device *dev)
>>  {
>> -	unsigned long flags = 0;
>>  	int res = 0;
>>  	struct pm8001_hba_info *pm8001_ha = NULL;
>>  	struct domain_device *parent_dev = dev->parent;
>> @@ -615,7 +615,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>>  	DECLARE_COMPLETION_ONSTACK(completion);
>>  	u32 flag = 0;
>>  	pm8001_ha = pm8001_find_ha_by_dev(dev);
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  	pm8001_device = pm8001_alloc_dev(pm8001_ha);
>>  	if (!pm8001_device) {
>> @@ -654,14 +654,14 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>>  	} /*register this device to HBA*/
>>  	PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
>>  	PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	wait_for_completion(&completion);
>>  	if (dev->dev_type == SAS_END_DEVICE)
>>  		msleep(50);
>>  	pm8001_ha->flags = PM8001F_RUN_TIME;
>>  	return 0;
>>  found_out:
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return res;
>>  }
>>  
>> @@ -864,13 +864,12 @@ ex_err:
>>    */
>>  static void pm8001_dev_gone_notify(struct domain_device *dev)
>>  {
>> -	unsigned long flags = 0;
>>  	u32 tag;
>>  	struct pm8001_hba_info *pm8001_ha;
>>  	struct pm8001_device *pm8001_dev = dev->lldd_dev;
>>  
>>  	pm8001_ha = pm8001_find_ha_by_dev(dev);
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	pm8001_tag_alloc(pm8001_ha, &tag);
>>  	if (pm8001_dev) {
>>  		u32 device_id = pm8001_dev->device_id;
>> @@ -879,10 +878,12 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>>  			pm8001_printk("found dev[%d:%x] is gone.\n",
>>  			pm8001_dev->device_id, pm8001_dev->dev_type));
>>  		if (pm8001_dev->running_req) {
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
>>  				dev, 1, 0);
>> -			spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  		}
>>  		PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
>>  		pm8001_free_dev(pm8001_dev);
>> @@ -891,7 +892,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>>  			pm8001_printk("Found dev has gone.\n"));
>>  	}
>>  	dev->lldd_dev = NULL;
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  }
>>  
>>  void pm8001_dev_gone(struct domain_device *dev)
>> @@ -918,12 +919,11 @@ void pm8001_open_reject_retry(
>>  	struct pm8001_device *device_to_close)
>>  {
>>  	int i;
>> -	unsigned long flags;
>>  
>>  	if (pm8001_ha == NULL)
>>  		return;
>>  
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  	for (i = 0; i < PM8001_MAX_CCB; i++) {
>>  		struct sas_task *task;
>> @@ -973,13 +973,15 @@ void pm8001_open_reject_retry(
>>  				flags1);
>>  			pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  			mb();/* in order to force CPU ordering */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			task->task_done(task);
>> -			spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  		}
>>  	}
>>  
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  }
>>  
>>  /**
>> diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
>> index 6c5fd5e..2b8065c 100644
>> --- a/drivers/scsi/pm8001/pm8001_sas.h
>> +++ b/drivers/scsi/pm8001/pm8001_sas.h
>> @@ -475,6 +475,7 @@ struct pm8001_hba_info {
>>  	struct list_head	list;
>>  	unsigned long		flags;
>>  	spinlock_t		lock;/* host-wide lock */
>> +	unsigned long		lock_flags;
>>  	struct pci_dev		*pdev;/* our device */
>>  	struct device		*dev;
>>  	struct pm8001_hba_memspace io_mem[6];
>> diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
>> index c950dc5..3ac024a 100644
>> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
>> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
>> @@ -2177,9 +2177,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*in order to force CPU ordering*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2197,9 +2199,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2223,9 +2227,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/* ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2290,9 +2296,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2314,9 +2322,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2349,16 +2359,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/* ditto */
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	} else if (!t->uldd_task) {
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/*ditto*/
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  }
>>  
>> @@ -2472,9 +2482,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2600,16 +2612,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/* ditto */
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	} else if (!t->uldd_task) {
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/*ditto*/
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  }
>>  
>> @@ -3705,9 +3717,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>  	void *pMsg1 = NULL;
>>  	u8 uninitialized_var(bc);
>>  	u32 ret = MPI_IO_STATUS_FAIL;
>> -	unsigned long flags;
>>  
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>  	do {
>>  		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>> @@ -3728,7 +3739,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>  				break;
>>  		}
>>  	} while (1);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return ret;
>>  }
>>  
>> @@ -4309,18 +4320,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>  							flags);
>>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  				mb();/* ditto */
>> -				spin_unlock_irq(&pm8001_ha->lock);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				task->task_done(task);
>> -				spin_lock_irq(&pm8001_ha->lock);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return 0;
>>  			} else if (!task->uldd_task) {
>>  				spin_unlock_irqrestore(&task->task_state_lock,
>>  							flags);
>>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  				mb();/*ditto*/
>> -				spin_unlock_irq(&pm8001_ha->lock);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				task->task_done(task);
>> -				spin_lock_irq(&pm8001_ha->lock);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return 0;
>>  			}
>>  		}
> 


^ permalink raw reply	[flat|nested] 33+ messages in thread

* RE: [PATCH] pm80xx: Spinlock fix
  2013-12-23 13:32   ` Jack Wang
@ 2013-12-23 13:45     ` Suresh Thiagarajan
  2013-12-23 14:55       ` Jason Seba
  0 siblings, 1 reply; 33+ messages in thread
From: Suresh Thiagarajan @ 2013-12-23 13:45 UTC (permalink / raw)
  To: Jack Wang, Tomas Henzl, Viswas G
  Cc: linux-scsi, jason.seba42, JBottomley, Vasanthalakshmi Tharmarajan



-----Original Message-----
From: Jack Wang [mailto:xjtuwjp@gmail.com] 
Sent: Monday, December 23, 2013 7:03 PM
To: Tomas Henzl; Viswas G
Cc: linux-scsi@vger.kernel.org; jason.seba42@gmail.com; JBottomley@parallels.com; Vasanthalakshmi Tharmarajan; Suresh Thiagarajan
Subject: Re: [PATCH] pm80xx: Spinlock fix

On 12/23/2013 02:07 PM, Tomas Henzl wrote:
> On 12/18/2013 12:28 PM, Viswas G wrote:
>> From 9338d4bc92b23b4c283f9bd6812646ab74866a40 Mon Sep 17 00:00:00 
>> 2001
>> From: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>> Date: Mon, 16 Dec 2013 21:15:20 +0530
>> Subject: [PATCH] pm80xx: Spinlock fix
>>
>> spin_unlock was used instead of spin_unlock_irqrestore. To fix this 
>> lock_flags per-adapter is added and used across all the places where pm8001_ha->lock is used.
> 
> I think this could have been fixed but just using spin_unlock_irqsave 
> instead of spin_unlock_irq why the change to global lock_flags?  I'm not a spinlock expert, but is this safe?
> 
Agree with Tomas, it's dangerous to change to global lock_flags.

Have you reproduce the bug reported from Jason, and verify the patch?
I think better just to change the spin_lock_irq to spin_lock_irqsave if that is the cause.

Suresh: We could not reproduce this issue and Jason(in CC) also could not reproduce it for now. spin_lock_irqsave and spin_unlock_irqrestore were called from multiple functions. Earlier flags was declared as a local variable wherever spinlock was used. This was not correct since irq information was saved in one function's flag which is a local to that function and restored in other function where again flags was declared as local variable to that function. So the data stored in flags while irq save was not used while restoring. Since we have lock per card, we are associating flag also per card for that lock.
-Suresh

Jack
>>
>> Reported-by: Jason Seba <jason.seba42@gmail.com>
>> Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>> Signed-off-by: Viswas G <Viswas.G@pmcs.com>
>> ---
>>  drivers/scsi/pm8001/pm8001_hwi.c |  158 ++++++++++++++++++++++----------------
>>  drivers/scsi/pm8001/pm8001_sas.c |   50 ++++++------
>>  drivers/scsi/pm8001/pm8001_sas.h |    1 +
>>  drivers/scsi/pm8001/pm80xx_hwi.c |   69 ++++++++++-------
>>  4 files changed, 160 insertions(+), 118 deletions(-)
>>
>> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c 
>> b/drivers/scsi/pm8001/pm8001_hwi.c
>> index 0a1296a..3901c40 100644
>> --- a/drivers/scsi/pm8001/pm8001_hwi.c
>> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
>> @@ -411,7 +411,6 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>  				     u32 SSCbit)
>>  {
>>  	u32 value, offset, i;
>> -	unsigned long flags;
>>  
>>  #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define 
>> SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -425,10 +424,10 
>> @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>      * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
>>      * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
>>      */
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  				SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return;
>>  	}
>>  
>> @@ -439,7 +438,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>  	/* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  				SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return;
>>  	}
>>  	for (i = 4; i < 8; i++) {
>> @@ -466,7 +465,7 @@ static void mpi_set_phys_g3_with_ssc(struct 
>> pm8001_hba_info *pm8001_ha,
>>  
>>  	/*set the shifted destination address to 0x0 to avoid error operation */
>>  	pm8001_bar4_shift(pm8001_ha, 0x0);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return;
>>  }
>>  
>> @@ -481,7 +480,6 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>  	u32 offset;
>>  	u32 value;
>>  	u32 i;
>> -	unsigned long flags;
>>  
>>  #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define 
>> OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -490,11 +488,11 
>> @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info 
>> *pm8001_ha,  #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
>>  
>>  	value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	/* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  			     OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return;
>>  	}
>>  	for (i = 0; i < 4; i++) {
>> @@ -504,7 +502,7 @@ static void 
>> mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>  
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  			     OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return;
>>  	}
>>  	for (i = 4; i < 8; i++) {
>> @@ -513,7 +511,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>  	}
>>  	/*set the shifted destination address to 0x0 to avoid error operation */
>>  	pm8001_bar4_shift(pm8001_ha, 0x0);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return;
>>  }
>>  
>> @@ -768,11 +766,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>  		PM8001_INIT_DBG(pm8001_ha,
>>  			pm8001_printk("Firmware is ready for reset .\n"));
>>  	} else {
>> -		unsigned long flags;
>>  		/* Trigger NMI twice via RB6 */
>> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			PM8001_FAIL_DBG(pm8001_ha,
>>  				pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  					RB6_ACCESS_REG));
>> @@ -798,10 +796,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>  			PM8001_FAIL_DBG(pm8001_ha,
>>  				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>  				pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return -1;
>>  		}
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  	return 0;
>>  }
>> @@ -818,7 +817,6 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	u32	max_wait_count;
>>  	u32	regVal1, regVal2, regVal3;
>>  	u32	signature = 0x252acbcd; /* for host scratch pad0 */
>> -	unsigned long flags;
>>  
>>  	/* step1: Check FW is ready for soft reset */
>>  	if (soft_reset_ready_check(pm8001_ha) != 0) { @@ -829,9 +827,9 @@ 
>> pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* step 2: clear NMI status register on AAP1 and IOP, write the same
>>  	value to clear */
>>  	/* map 0x60000 to BAR4(0x20), BAR2(win) */
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  			MBIC_AAP1_ADDR_BASE));
>> @@ -843,7 +841,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
>>  	/* map 0x70000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  			MBIC_IOP_ADDR_BASE));
>> @@ -886,7 +884,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* read required registers for confirmming */
>>  	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  			GSM_ADDR_BASE));
>> @@ -953,7 +951,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	udelay(10);
>>  	/* step 5-b: set GPIO-0 output control to tristate anyway */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_INIT_DBG(pm8001_ha,
>>  				pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  				GPIO_ADDR_BASE));
>> @@ -970,7 +968,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* Step 6: Reset the IOP and AAP1 */
>>  	/* map 0x00000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>  			SPC_TOP_LEVEL_ADDR_BASE));
>> @@ -1008,7 +1006,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* step 11: reads and sets the GSM Configuration and Reset Register */
>>  	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>  			GSM_ADDR_BASE));
>> @@ -1062,7 +1060,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  	/* step 13: bring the IOP and AAP1 out of reset */
>>  	/* map 0x00000 to BAR4(0x20), BAR2(win) */
>>  	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		PM8001_FAIL_DBG(pm8001_ha,
>>  			pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>  			SPC_TOP_LEVEL_ADDR_BASE));
>> @@ -1104,7 +1102,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>  				pm8001_cr32(pm8001_ha, 0,
>>  				MSGU_SCRATCH_PAD_3)));
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return -1;
>>  		}
>>  
>> @@ -1134,12 +1133,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>  				pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>  				pm8001_cr32(pm8001_ha, 0,
>>  				MSGU_SCRATCH_PAD_3)));
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return -1;
>>  		}
>>  	}
>>  	pm8001_bar4_shift(pm8001_ha, 0);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  	PM8001_INIT_DBG(pm8001_ha,
>>  		pm8001_printk("SPC soft reset Complete\n")); @@ -1517,18 +1517,19 
>> @@ void pm8001_work_fn(struct work_struct *work)
>>  		u32 tag;
>>  		struct pm8001_ccb_info *ccb;
>>  		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>> -		unsigned long flags, flags1;
>> +		unsigned long flags1;
>>  		struct task_status_struct *ts;
>>  		int i;
>>  
>>  		if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
>>  			break; /* Task still on lu */
>> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  		spin_lock_irqsave(&t->task_state_lock, flags1);
>>  		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>  			spin_unlock_irqrestore(&t->task_state_lock, flags1);
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			break; /* Task got completed by another */
>>  		}
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags1); @@ -1541,7 
>> +1542,8 @@ void pm8001_work_fn(struct work_struct *work)
>>  				break;
>>  		}
>>  		if (!ccb) {
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			break; /* Task got freed by another */
>>  		}
>>  		ts = &t->task_status;
>> @@ -1562,12 +1564,14 @@ void pm8001_work_fn(struct work_struct *work)
>>  				" aborted by upper layer!\n",
>>  				t, pw->handler, ts->resp, ts->stat));
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  		} else {
>>  			spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/* in order to force CPU ordering */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>>  		}
>>  	}	break;
>> @@ -1577,7 +1581,7 @@ void pm8001_work_fn(struct work_struct *work)
>>  		u32 tag;
>>  		struct pm8001_ccb_info *ccb;
>>  		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>> -		unsigned long flags, flags1;
>> +		unsigned long flags1;
>>  		int i, ret = 0;
>>  
>>  		PM8001_IO_DBG(pm8001_ha,
>> @@ -1600,13 +1604,14 @@ void pm8001_work_fn(struct work_struct *work)
>>  				break;
>>  			});
>>  
>> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  		spin_lock_irqsave(&t->task_state_lock, flags1);
>>  
>>  		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>  			spin_unlock_irqrestore(&t->task_state_lock, flags1);
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>  				(void)pm8001_abort_task(t);
>>  			break; /* Task got completed by another */ @@ -1622,7 +1627,8 @@ 
>> void pm8001_work_fn(struct work_struct *work)
>>  				break;
>>  		}
>>  		if (!ccb) {
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>  				(void)pm8001_abort_task(t);
>>  			break; /* Task got freed by another */ @@ -1634,7 +1640,8 @@ void 
>> pm8001_work_fn(struct work_struct *work)
>>  		switch (ret) {
>>  		case TMF_RESP_FUNC_SUCC: /* task on lu */
>>  			ccb->open_retry = 1; /* Snub completion */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			ret = pm8001_abort_task(t);
>>  			ccb->open_retry = 0;
>>  			switch (ret) {
>> @@ -1651,12 +1658,14 @@ void pm8001_work_fn(struct work_struct *work)
>>  			break;
>>  
>>  		case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			/* Do we need to abort the task locally? */
>>  			break;
>>  
>>  		default: /* device misbehavior */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			ret = TMF_RESP_FUNC_FAILED;
>>  			PM8001_IO_DBG(pm8001_ha,
>>  				pm8001_printk("...Reset phy\n")); @@ -2504,9 +2513,11 @@ 
>> mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*in order to force CPU ordering*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2524,9 +2535,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2552,9 +2565,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/* ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2619,9 +2634,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2643,9 +2660,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2678,16 +2697,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/* ditto */
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	} else if (!t->uldd_task) {
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/*ditto*/
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  }
>>  
>> @@ -2798,9 +2817,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2913,16 +2934,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/* ditto */
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	} else if (!t->uldd_task) {
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/*ditto*/
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  }
>>  
>> @@ -4194,9 +4215,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>  	void *pMsg1 = NULL;
>>  	u8 uninitialized_var(bc);
>>  	u32 ret = MPI_IO_STATUS_FAIL;
>> -	unsigned long flags;
>>  
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>  	do {
>>  		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc); 
>> @@ -4217,7 +4237,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>  				break;
>>  		}
>>  	} while (1);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return ret;
>>  }
>>  
>> @@ -4472,18 +4492,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>  							flags);
>>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  				mb();/* ditto */
>> -				spin_unlock_irq(&pm8001_ha->lock);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				task->task_done(task);
>> -				spin_lock_irq(&pm8001_ha->lock);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return 0;
>>  			} else if (!task->uldd_task) {
>>  				spin_unlock_irqrestore(&task->task_state_lock,
>>  							flags);
>>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  				mb();/*ditto*/
>> -				spin_unlock_irq(&pm8001_ha->lock);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				task->task_done(task);
>> -				spin_lock_irq(&pm8001_ha->lock);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return 0;
>>  			}
>>  		}
>> diff --git a/drivers/scsi/pm8001/pm8001_sas.c 
>> b/drivers/scsi/pm8001/pm8001_sas.c
>> index f50ac44..eac1b81 100644
>> --- a/drivers/scsi/pm8001/pm8001_sas.c
>> +++ b/drivers/scsi/pm8001/pm8001_sas.c
>> @@ -166,7 +166,6 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>  	struct pm8001_hba_info *pm8001_ha = NULL;
>>  	struct sas_phy_linkrates *rates;
>>  	DECLARE_COMPLETION_ONSTACK(completion);
>> -	unsigned long flags;
>>  	pm8001_ha = sas_phy->ha->lldd_ha;
>>  	pm8001_ha->phy[phy_id].enable_completion = &completion;
>>  	switch (func) {
>> @@ -211,11 +210,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>  		PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
>>  		break;
>>  	case PHY_FUNC_GET_EVENTS:
>> -		spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		if (pm8001_ha->chip_id == chip_8001) {
>>  			if (-1 == pm8001_bar4_shift(pm8001_ha,
>>  					(phy_id < 4) ? 0x30000 : 0x40000)) {
>> -				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return -EINVAL;
>>  			}
>>  		}
>> @@ -232,7 +232,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>  		}
>>  		if (pm8001_ha->chip_id == chip_8001)
>>  			pm8001_bar4_shift(pm8001_ha, 0);
>> -		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		return 0;
>>  	default:
>>  		rc = -EOPNOTSUPP;
>> @@ -369,7 +369,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>  	struct pm8001_ccb_info *ccb;
>>  	u32 tag = 0xdeadbeef, rc, n_elem = 0;
>>  	u32 n = num;
>> -	unsigned long flags = 0;
>>  
>>  	if (!dev->port) {
>>  		struct task_status_struct *tsm = &t->task_status; @@ -380,8 +379,8 
>> @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>  		return 0;
>>  	}
>>  	pm8001_ha = pm8001_find_ha_by_dev(task->dev);
>> -	PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device\n"));
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	do {
>>  		dev = t->dev;
>>  		pm8001_dev = dev->lldd_dev;
>> @@ -392,9 +391,11 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>  				ts->resp = SAS_TASK_UNDELIVERED;
>>  				ts->stat = SAS_PHY_DOWN;
>>  
>> -				spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				t->task_done(t);
>> -				spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				if (n > 1)
>>  					t = list_entry(t->list.next,
>>  							struct sas_task, list);
>> @@ -482,7 +483,7 @@ err_out:
>>  			dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
>>  				t->data_dir);
>>  out_done:
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return rc;
>>  }
>>  
>> @@ -607,7 +608,6 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
>>    */
>>  static int pm8001_dev_found_notify(struct domain_device *dev)  {
>> -	unsigned long flags = 0;
>>  	int res = 0;
>>  	struct pm8001_hba_info *pm8001_ha = NULL;
>>  	struct domain_device *parent_dev = dev->parent; @@ -615,7 +615,7 @@ 
>> static int pm8001_dev_found_notify(struct domain_device *dev)
>>  	DECLARE_COMPLETION_ONSTACK(completion);
>>  	u32 flag = 0;
>>  	pm8001_ha = pm8001_find_ha_by_dev(dev);
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  	pm8001_device = pm8001_alloc_dev(pm8001_ha);
>>  	if (!pm8001_device) {
>> @@ -654,14 +654,14 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>>  	} /*register this device to HBA*/
>>  	PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
>>  	PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	wait_for_completion(&completion);
>>  	if (dev->dev_type == SAS_END_DEVICE)
>>  		msleep(50);
>>  	pm8001_ha->flags = PM8001F_RUN_TIME;
>>  	return 0;
>>  found_out:
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return res;
>>  }
>>  
>> @@ -864,13 +864,12 @@ ex_err:
>>    */
>>  static void pm8001_dev_gone_notify(struct domain_device *dev)  {
>> -	unsigned long flags = 0;
>>  	u32 tag;
>>  	struct pm8001_hba_info *pm8001_ha;
>>  	struct pm8001_device *pm8001_dev = dev->lldd_dev;
>>  
>>  	pm8001_ha = pm8001_find_ha_by_dev(dev);
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	pm8001_tag_alloc(pm8001_ha, &tag);
>>  	if (pm8001_dev) {
>>  		u32 device_id = pm8001_dev->device_id; @@ -879,10 +878,12 @@ 
>> static void pm8001_dev_gone_notify(struct domain_device *dev)
>>  			pm8001_printk("found dev[%d:%x] is gone.\n",
>>  			pm8001_dev->device_id, pm8001_dev->dev_type));
>>  		if (pm8001_dev->running_req) {
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
>>  				dev, 1, 0);
>> -			spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  		}
>>  		PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
>>  		pm8001_free_dev(pm8001_dev);
>> @@ -891,7 +892,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>>  			pm8001_printk("Found dev has gone.\n"));
>>  	}
>>  	dev->lldd_dev = NULL;
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  }
>>  
>>  void pm8001_dev_gone(struct domain_device *dev) @@ -918,12 +919,11 
>> @@ void pm8001_open_reject_retry(
>>  	struct pm8001_device *device_to_close)  {
>>  	int i;
>> -	unsigned long flags;
>>  
>>  	if (pm8001_ha == NULL)
>>  		return;
>>  
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  
>>  	for (i = 0; i < PM8001_MAX_CCB; i++) {
>>  		struct sas_task *task;
>> @@ -973,13 +973,15 @@ void pm8001_open_reject_retry(
>>  				flags1);
>>  			pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  			mb();/* in order to force CPU ordering */
>> -			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			task->task_done(task);
>> -			spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  		}
>>  	}
>>  
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  }
>>  
>>  /**
>> diff --git a/drivers/scsi/pm8001/pm8001_sas.h 
>> b/drivers/scsi/pm8001/pm8001_sas.h
>> index 6c5fd5e..2b8065c 100644
>> --- a/drivers/scsi/pm8001/pm8001_sas.h
>> +++ b/drivers/scsi/pm8001/pm8001_sas.h
>> @@ -475,6 +475,7 @@ struct pm8001_hba_info {
>>  	struct list_head	list;
>>  	unsigned long		flags;
>>  	spinlock_t		lock;/* host-wide lock */
>> +	unsigned long		lock_flags;
>>  	struct pci_dev		*pdev;/* our device */
>>  	struct device		*dev;
>>  	struct pm8001_hba_memspace io_mem[6]; diff --git 
>> a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
>> index c950dc5..3ac024a 100644
>> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
>> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
>> @@ -2177,9 +2177,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*in order to force CPU ordering*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2197,9 +2199,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2223,9 +2227,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/* ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2290,9 +2296,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2314,9 +2322,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2349,16 +2359,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/* ditto */
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	} else if (!t->uldd_task) {
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/*ditto*/
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  }
>>  
>> @@ -2472,9 +2482,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>  			ts->stat = SAS_QUEUE_FULL;
>>  			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  			mb();/*ditto*/
>> -			spin_unlock_irq(&pm8001_ha->lock);
>> +			spin_unlock_irqrestore(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			t->task_done(t);
>> -			spin_lock_irq(&pm8001_ha->lock);
>> +			spin_lock_irqsave(&pm8001_ha->lock,
>> +						pm8001_ha->lock_flags);
>>  			return;
>>  		}
>>  		break;
>> @@ -2600,16 +2612,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/* ditto */
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	} else if (!t->uldd_task) {
>>  		spin_unlock_irqrestore(&t->task_state_lock, flags);
>>  		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>  		mb();/*ditto*/
>> -		spin_unlock_irq(&pm8001_ha->lock);
>> +		spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  		t->task_done(t);
>> -		spin_lock_irq(&pm8001_ha->lock);
>> +		spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	}
>>  }
>>  
>> @@ -3705,9 +3717,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>  	void *pMsg1 = NULL;
>>  	u8 uninitialized_var(bc);
>>  	u32 ret = MPI_IO_STATUS_FAIL;
>> -	unsigned long flags;
>>  
>> -	spin_lock_irqsave(&pm8001_ha->lock, flags);
>> +	spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>  	do {
>>  		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc); 
>> @@ -3728,7 +3739,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>  				break;
>>  		}
>>  	} while (1);
>> -	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>> +	spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>  	return ret;
>>  }
>>  
>> @@ -4309,18 +4320,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>  							flags);
>>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  				mb();/* ditto */
>> -				spin_unlock_irq(&pm8001_ha->lock);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				task->task_done(task);
>> -				spin_lock_irq(&pm8001_ha->lock);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return 0;
>>  			} else if (!task->uldd_task) {
>>  				spin_unlock_irqrestore(&task->task_state_lock,
>>  							flags);
>>  				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>  				mb();/*ditto*/
>> -				spin_unlock_irq(&pm8001_ha->lock);
>> +				spin_unlock_irqrestore(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				task->task_done(task);
>> -				spin_lock_irq(&pm8001_ha->lock);
>> +				spin_lock_irqsave(&pm8001_ha->lock,
>> +							pm8001_ha->lock_flags);
>>  				return 0;
>>  			}
>>  		}
> 


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] pm80xx: Spinlock fix
  2013-12-23 13:45     ` Suresh Thiagarajan
@ 2013-12-23 14:55       ` Jason Seba
  2013-12-23 15:06         ` Jack Wang
  0 siblings, 1 reply; 33+ messages in thread
From: Jason Seba @ 2013-12-23 14:55 UTC (permalink / raw)
  To: Suresh Thiagarajan
  Cc: Jack Wang, Tomas Henzl, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan

Why is this considered dangerous?  I put some thought into it and
couldn't find any obvious reason why it wouldn't work, but I also
couldn't find any other drivers that work this way.  Is there a
particular reason to avoid doing it this way?

On Mon, Dec 23, 2013 at 8:45 AM, Suresh Thiagarajan
<Suresh.Thiagarajan@pmcs.com> wrote:
>
>
> -----Original Message-----
> From: Jack Wang [mailto:xjtuwjp@gmail.com]
> Sent: Monday, December 23, 2013 7:03 PM
> To: Tomas Henzl; Viswas G
> Cc: linux-scsi@vger.kernel.org; jason.seba42@gmail.com; JBottomley@parallels.com; Vasanthalakshmi Tharmarajan; Suresh Thiagarajan
> Subject: Re: [PATCH] pm80xx: Spinlock fix
>
> On 12/23/2013 02:07 PM, Tomas Henzl wrote:
>> On 12/18/2013 12:28 PM, Viswas G wrote:
>>> From 9338d4bc92b23b4c283f9bd6812646ab74866a40 Mon Sep 17 00:00:00
>>> 2001
>>> From: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>> Date: Mon, 16 Dec 2013 21:15:20 +0530
>>> Subject: [PATCH] pm80xx: Spinlock fix
>>>
>>> spin_unlock was used instead of spin_unlock_irqrestore. To fix this
>>> lock_flags per-adapter is added and used across all the places where pm8001_ha->lock is used.
>>
>> I think this could have been fixed but just using spin_unlock_irqsave
>> instead of spin_unlock_irq why the change to global lock_flags?  I'm not a spinlock expert, but is this safe?
>>
> Agree with Tomas, it's dangerous to change to global lock_flags.
>
> Have you reproduce the bug reported from Jason, and verify the patch?
> I think better just to change the spin_lock_irq to spin_lock_irqsave if that is the cause.
>
> Suresh: We could not reproduce this issue and Jason(in CC) also could not reproduce it for now. spin_lock_irqsave and spin_unlock_irqrestore were called from multiple functions. Earlier flags was declared as a local variable wherever spinlock was used. This was not correct since irq information was saved in one function's flag which is a local to that function and restored in other function where again flags was declared as local variable to that function. So the data stored in flags while irq save was not used while restoring. Since we have lock per card, we are associating flag also per card for that lock.
> -Suresh
>
> Jack
>>>
>>> Reported-by: Jason Seba <jason.seba42@gmail.com>
>>> Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>> Signed-off-by: Viswas G <Viswas.G@pmcs.com>
>>> ---
>>>  drivers/scsi/pm8001/pm8001_hwi.c |  158 ++++++++++++++++++++++----------------
>>>  drivers/scsi/pm8001/pm8001_sas.c |   50 ++++++------
>>>  drivers/scsi/pm8001/pm8001_sas.h |    1 +
>>>  drivers/scsi/pm8001/pm80xx_hwi.c |   69 ++++++++++-------
>>>  4 files changed, 160 insertions(+), 118 deletions(-)
>>>
>>> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c
>>> b/drivers/scsi/pm8001/pm8001_hwi.c
>>> index 0a1296a..3901c40 100644
>>> --- a/drivers/scsi/pm8001/pm8001_hwi.c
>>> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
>>> @@ -411,7 +411,6 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>                                   u32 SSCbit)
>>>  {
>>>      u32 value, offset, i;
>>> -    unsigned long flags;
>>>
>>>  #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>> SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -425,10 +424,10
>>> @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>      * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
>>>      * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
>>>      */
>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>                              SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              return;
>>>      }
>>>
>>> @@ -439,7 +438,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>      /* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>                              SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              return;
>>>      }
>>>      for (i = 4; i < 8; i++) {
>>> @@ -466,7 +465,7 @@ static void mpi_set_phys_g3_with_ssc(struct
>>> pm8001_hba_info *pm8001_ha,
>>>
>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      return;
>>>  }
>>>
>>> @@ -481,7 +480,6 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>      u32 offset;
>>>      u32 value;
>>>      u32 i;
>>> -    unsigned long flags;
>>>
>>>  #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>> OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -490,11 +488,11
>>> @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info
>>> *pm8001_ha,  #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
>>>
>>>      value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      /* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>                           OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              return;
>>>      }
>>>      for (i = 0; i < 4; i++) {
>>> @@ -504,7 +502,7 @@ static void
>>> mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>                           OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              return;
>>>      }
>>>      for (i = 4; i < 8; i++) {
>>> @@ -513,7 +511,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>      }
>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      return;
>>>  }
>>>
>>> @@ -768,11 +766,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>              PM8001_INIT_DBG(pm8001_ha,
>>>                      pm8001_printk("Firmware is ready for reset .\n"));
>>>      } else {
>>> -            unsigned long flags;
>>>              /* Trigger NMI twice via RB6 */
>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>                                      RB6_ACCESS_REG));
>>> @@ -798,10 +796,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>                              pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return -1;
>>>              }
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      }
>>>      return 0;
>>>  }
>>> @@ -818,7 +817,6 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>      u32     max_wait_count;
>>>      u32     regVal1, regVal2, regVal3;
>>>      u32     signature = 0x252acbcd; /* for host scratch pad0 */
>>> -    unsigned long flags;
>>>
>>>      /* step1: Check FW is ready for soft reset */
>>>      if (soft_reset_ready_check(pm8001_ha) != 0) { @@ -829,9 +827,9 @@
>>> pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>      /* step 2: clear NMI status register on AAP1 and IOP, write the same
>>>      value to clear */
>>>      /* map 0x60000 to BAR4(0x20), BAR2(win) */
>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>                      MBIC_AAP1_ADDR_BASE));
>>> @@ -843,7 +841,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>      pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
>>>      /* map 0x70000 to BAR4(0x20), BAR2(win) */
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>                      MBIC_IOP_ADDR_BASE));
>>> @@ -886,7 +884,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>      /* read required registers for confirmming */
>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>                      GSM_ADDR_BASE));
>>> @@ -953,7 +951,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>      udelay(10);
>>>      /* step 5-b: set GPIO-0 output control to tristate anyway */
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              PM8001_INIT_DBG(pm8001_ha,
>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>                              GPIO_ADDR_BASE));
>>> @@ -970,7 +968,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>      /* Step 6: Reset the IOP and AAP1 */
>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>> @@ -1008,7 +1006,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>      /* step 11: reads and sets the GSM Configuration and Reset Register */
>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>                      GSM_ADDR_BASE));
>>> @@ -1062,7 +1060,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>      /* step 13: bring the IOP and AAP1 out of reset */
>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>> @@ -1104,7 +1102,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>                              pm8001_cr32(pm8001_ha, 0,
>>>                              MSGU_SCRATCH_PAD_3)));
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return -1;
>>>              }
>>>
>>> @@ -1134,12 +1133,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>                              pm8001_cr32(pm8001_ha, 0,
>>>                              MSGU_SCRATCH_PAD_3)));
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return -1;
>>>              }
>>>      }
>>>      pm8001_bar4_shift(pm8001_ha, 0);
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>
>>>      PM8001_INIT_DBG(pm8001_ha,
>>>              pm8001_printk("SPC soft reset Complete\n")); @@ -1517,18 +1517,19
>>> @@ void pm8001_work_fn(struct work_struct *work)
>>>              u32 tag;
>>>              struct pm8001_ccb_info *ccb;
>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>> -            unsigned long flags, flags1;
>>> +            unsigned long flags1;
>>>              struct task_status_struct *ts;
>>>              int i;
>>>
>>>              if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
>>>                      break; /* Task still on lu */
>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>
>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      break; /* Task got completed by another */
>>>              }
>>>              spin_unlock_irqrestore(&t->task_state_lock, flags1); @@ -1541,7
>>> +1542,8 @@ void pm8001_work_fn(struct work_struct *work)
>>>                              break;
>>>              }
>>>              if (!ccb) {
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      break; /* Task got freed by another */
>>>              }
>>>              ts = &t->task_status;
>>> @@ -1562,12 +1564,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>                              " aborted by upper layer!\n",
>>>                              t, pw->handler, ts->resp, ts->stat));
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>              } else {
>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/* in order to force CPU ordering */
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>>              }
>>>      }       break;
>>> @@ -1577,7 +1581,7 @@ void pm8001_work_fn(struct work_struct *work)
>>>              u32 tag;
>>>              struct pm8001_ccb_info *ccb;
>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>> -            unsigned long flags, flags1;
>>> +            unsigned long flags1;
>>>              int i, ret = 0;
>>>
>>>              PM8001_IO_DBG(pm8001_ha,
>>> @@ -1600,13 +1604,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>                              break;
>>>                      });
>>>
>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>
>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>
>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>                              (void)pm8001_abort_task(t);
>>>                      break; /* Task got completed by another */ @@ -1622,7 +1627,8 @@
>>> void pm8001_work_fn(struct work_struct *work)
>>>                              break;
>>>              }
>>>              if (!ccb) {
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>                              (void)pm8001_abort_task(t);
>>>                      break; /* Task got freed by another */ @@ -1634,7 +1640,8 @@ void
>>> pm8001_work_fn(struct work_struct *work)
>>>              switch (ret) {
>>>              case TMF_RESP_FUNC_SUCC: /* task on lu */
>>>                      ccb->open_retry = 1; /* Snub completion */
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      ret = pm8001_abort_task(t);
>>>                      ccb->open_retry = 0;
>>>                      switch (ret) {
>>> @@ -1651,12 +1658,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>                      break;
>>>
>>>              case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      /* Do we need to abort the task locally? */
>>>                      break;
>>>
>>>              default: /* device misbehavior */
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      ret = TMF_RESP_FUNC_FAILED;
>>>                      PM8001_IO_DBG(pm8001_ha,
>>>                              pm8001_printk("...Reset phy\n")); @@ -2504,9 +2513,11 @@
>>> mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*in order to force CPU ordering*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2524,9 +2535,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2552,9 +2565,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/* ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2619,9 +2634,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2643,9 +2660,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2678,16 +2697,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>              mb();/* ditto */
>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              t->task_done(t);
>>> -            spin_lock_irq(&pm8001_ha->lock);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      } else if (!t->uldd_task) {
>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>              mb();/*ditto*/
>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              t->task_done(t);
>>> -            spin_lock_irq(&pm8001_ha->lock);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      }
>>>  }
>>>
>>> @@ -2798,9 +2817,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2913,16 +2934,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>              mb();/* ditto */
>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              t->task_done(t);
>>> -            spin_lock_irq(&pm8001_ha->lock);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      } else if (!t->uldd_task) {
>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>              mb();/*ditto*/
>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              t->task_done(t);
>>> -            spin_lock_irq(&pm8001_ha->lock);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      }
>>>  }
>>>
>>> @@ -4194,9 +4215,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>      void *pMsg1 = NULL;
>>>      u8 uninitialized_var(bc);
>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>> -    unsigned long flags;
>>>
>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>      do {
>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>> @@ -4217,7 +4237,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>                              break;
>>>              }
>>>      } while (1);
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      return ret;
>>>  }
>>>
>>> @@ -4472,18 +4492,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>                                                      flags);
>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>                              mb();/* ditto */
>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              task->task_done(task);
>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              return 0;
>>>                      } else if (!task->uldd_task) {
>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>                                                      flags);
>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>                              mb();/*ditto*/
>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              task->task_done(task);
>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              return 0;
>>>                      }
>>>              }
>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.c
>>> b/drivers/scsi/pm8001/pm8001_sas.c
>>> index f50ac44..eac1b81 100644
>>> --- a/drivers/scsi/pm8001/pm8001_sas.c
>>> +++ b/drivers/scsi/pm8001/pm8001_sas.c
>>> @@ -166,7 +166,6 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>      struct sas_phy_linkrates *rates;
>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>> -    unsigned long flags;
>>>      pm8001_ha = sas_phy->ha->lldd_ha;
>>>      pm8001_ha->phy[phy_id].enable_completion = &completion;
>>>      switch (func) {
>>> @@ -211,11 +210,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>              PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
>>>              break;
>>>      case PHY_FUNC_GET_EVENTS:
>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              if (pm8001_ha->chip_id == chip_8001) {
>>>                      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>                                      (phy_id < 4) ? 0x30000 : 0x40000)) {
>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              return -EINVAL;
>>>                      }
>>>              }
>>> @@ -232,7 +232,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>              }
>>>              if (pm8001_ha->chip_id == chip_8001)
>>>                      pm8001_bar4_shift(pm8001_ha, 0);
>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              return 0;
>>>      default:
>>>              rc = -EOPNOTSUPP;
>>> @@ -369,7 +369,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>      struct pm8001_ccb_info *ccb;
>>>      u32 tag = 0xdeadbeef, rc, n_elem = 0;
>>>      u32 n = num;
>>> -    unsigned long flags = 0;
>>>
>>>      if (!dev->port) {
>>>              struct task_status_struct *tsm = &t->task_status; @@ -380,8 +379,8
>>> @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>              return 0;
>>>      }
>>>      pm8001_ha = pm8001_find_ha_by_dev(task->dev);
>>> -    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device\n"));
>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      do {
>>>              dev = t->dev;
>>>              pm8001_dev = dev->lldd_dev;
>>> @@ -392,9 +391,11 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>                              ts->resp = SAS_TASK_UNDELIVERED;
>>>                              ts->stat = SAS_PHY_DOWN;
>>>
>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              t->task_done(t);
>>> -                            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              if (n > 1)
>>>                                      t = list_entry(t->list.next,
>>>                                                      struct sas_task, list);
>>> @@ -482,7 +483,7 @@ err_out:
>>>                      dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
>>>                              t->data_dir);
>>>  out_done:
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      return rc;
>>>  }
>>>
>>> @@ -607,7 +608,6 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
>>>    */
>>>  static int pm8001_dev_found_notify(struct domain_device *dev)  {
>>> -    unsigned long flags = 0;
>>>      int res = 0;
>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>      struct domain_device *parent_dev = dev->parent; @@ -615,7 +615,7 @@
>>> static int pm8001_dev_found_notify(struct domain_device *dev)
>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>>      u32 flag = 0;
>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>
>>>      pm8001_device = pm8001_alloc_dev(pm8001_ha);
>>>      if (!pm8001_device) {
>>> @@ -654,14 +654,14 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>>>      } /*register this device to HBA*/
>>>      PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
>>>      PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      wait_for_completion(&completion);
>>>      if (dev->dev_type == SAS_END_DEVICE)
>>>              msleep(50);
>>>      pm8001_ha->flags = PM8001F_RUN_TIME;
>>>      return 0;
>>>  found_out:
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      return res;
>>>  }
>>>
>>> @@ -864,13 +864,12 @@ ex_err:
>>>    */
>>>  static void pm8001_dev_gone_notify(struct domain_device *dev)  {
>>> -    unsigned long flags = 0;
>>>      u32 tag;
>>>      struct pm8001_hba_info *pm8001_ha;
>>>      struct pm8001_device *pm8001_dev = dev->lldd_dev;
>>>
>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      pm8001_tag_alloc(pm8001_ha, &tag);
>>>      if (pm8001_dev) {
>>>              u32 device_id = pm8001_dev->device_id; @@ -879,10 +878,12 @@
>>> static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>                      pm8001_printk("found dev[%d:%x] is gone.\n",
>>>                      pm8001_dev->device_id, pm8001_dev->dev_type));
>>>              if (pm8001_dev->running_req) {
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
>>>                              dev, 1, 0);
>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>              }
>>>              PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
>>>              pm8001_free_dev(pm8001_dev);
>>> @@ -891,7 +892,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>                      pm8001_printk("Found dev has gone.\n"));
>>>      }
>>>      dev->lldd_dev = NULL;
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>  }
>>>
>>>  void pm8001_dev_gone(struct domain_device *dev) @@ -918,12 +919,11
>>> @@ void pm8001_open_reject_retry(
>>>      struct pm8001_device *device_to_close)  {
>>>      int i;
>>> -    unsigned long flags;
>>>
>>>      if (pm8001_ha == NULL)
>>>              return;
>>>
>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>
>>>      for (i = 0; i < PM8001_MAX_CCB; i++) {
>>>              struct sas_task *task;
>>> @@ -973,13 +973,15 @@ void pm8001_open_reject_retry(
>>>                              flags1);
>>>                      pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>                      mb();/* in order to force CPU ordering */
>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      task->task_done(task);
>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>              }
>>>      }
>>>
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>  }
>>>
>>>  /**
>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.h
>>> b/drivers/scsi/pm8001/pm8001_sas.h
>>> index 6c5fd5e..2b8065c 100644
>>> --- a/drivers/scsi/pm8001/pm8001_sas.h
>>> +++ b/drivers/scsi/pm8001/pm8001_sas.h
>>> @@ -475,6 +475,7 @@ struct pm8001_hba_info {
>>>      struct list_head        list;
>>>      unsigned long           flags;
>>>      spinlock_t              lock;/* host-wide lock */
>>> +    unsigned long           lock_flags;
>>>      struct pci_dev          *pdev;/* our device */
>>>      struct device           *dev;
>>>      struct pm8001_hba_memspace io_mem[6]; diff --git
>>> a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
>>> index c950dc5..3ac024a 100644
>>> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
>>> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
>>> @@ -2177,9 +2177,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*in order to force CPU ordering*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2197,9 +2199,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2223,9 +2227,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/* ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2290,9 +2296,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2314,9 +2322,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2349,16 +2359,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>              mb();/* ditto */
>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              t->task_done(t);
>>> -            spin_lock_irq(&pm8001_ha->lock);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      } else if (!t->uldd_task) {
>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>              mb();/*ditto*/
>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              t->task_done(t);
>>> -            spin_lock_irq(&pm8001_ha->lock);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      }
>>>  }
>>>
>>> @@ -2472,9 +2482,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>                      ts->stat = SAS_QUEUE_FULL;
>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>                      mb();/*ditto*/
>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      t->task_done(t);
>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                            pm8001_ha->lock_flags);
>>>                      return;
>>>              }
>>>              break;
>>> @@ -2600,16 +2612,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>              mb();/* ditto */
>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              t->task_done(t);
>>> -            spin_lock_irq(&pm8001_ha->lock);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      } else if (!t->uldd_task) {
>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>              mb();/*ditto*/
>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>              t->task_done(t);
>>> -            spin_lock_irq(&pm8001_ha->lock);
>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      }
>>>  }
>>>
>>> @@ -3705,9 +3717,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>      void *pMsg1 = NULL;
>>>      u8 uninitialized_var(bc);
>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>> -    unsigned long flags;
>>>
>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>      do {
>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>> @@ -3728,7 +3739,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>                              break;
>>>              }
>>>      } while (1);
>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>      return ret;
>>>  }
>>>
>>> @@ -4309,18 +4320,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>                                                      flags);
>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>                              mb();/* ditto */
>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              task->task_done(task);
>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              return 0;
>>>                      } else if (!task->uldd_task) {
>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>                                                      flags);
>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>                              mb();/*ditto*/
>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              task->task_done(task);
>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>> +                                                    pm8001_ha->lock_flags);
>>>                              return 0;
>>>                      }
>>>              }
>>
>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] pm80xx: Spinlock fix
  2013-12-23 14:55       ` Jason Seba
@ 2013-12-23 15:06         ` Jack Wang
  2013-12-23 15:28           ` Tomas Henzl
  0 siblings, 1 reply; 33+ messages in thread
From: Jack Wang @ 2013-12-23 15:06 UTC (permalink / raw)
  To: Jason Seba
  Cc: Suresh Thiagarajan, Tomas Henzl, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan

On 12/23/2013 03:55 PM, Jason Seba wrote:
> Why is this considered dangerous?  I put some thought into it and
> couldn't find any obvious reason why it wouldn't work, but I also
> couldn't find any other drivers that work this way.  Is there a
> particular reason to avoid doing it this way?
> 
If you use global flags, you may change interrupt state depends on context.

> On Mon, Dec 23, 2013 at 8:45 AM, Suresh Thiagarajan
> <Suresh.Thiagarajan@pmcs.com> wrote:
>>
>>
>> -----Original Message-----
>> From: Jack Wang [mailto:xjtuwjp@gmail.com]
>> Sent: Monday, December 23, 2013 7:03 PM
>> To: Tomas Henzl; Viswas G
>> Cc: linux-scsi@vger.kernel.org; jason.seba42@gmail.com; JBottomley@parallels.com; Vasanthalakshmi Tharmarajan; Suresh Thiagarajan
>> Subject: Re: [PATCH] pm80xx: Spinlock fix
>>
>> On 12/23/2013 02:07 PM, Tomas Henzl wrote:
>>> On 12/18/2013 12:28 PM, Viswas G wrote:
>>>> From 9338d4bc92b23b4c283f9bd6812646ab74866a40 Mon Sep 17 00:00:00
>>>> 2001
>>>> From: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>>> Date: Mon, 16 Dec 2013 21:15:20 +0530
>>>> Subject: [PATCH] pm80xx: Spinlock fix
>>>>
>>>> spin_unlock was used instead of spin_unlock_irqrestore. To fix this
>>>> lock_flags per-adapter is added and used across all the places where pm8001_ha->lock is used.
>>>
>>> I think this could have been fixed but just using spin_unlock_irqsave
>>> instead of spin_unlock_irq why the change to global lock_flags?  I'm not a spinlock expert, but is this safe?
>>>
>> Agree with Tomas, it's dangerous to change to global lock_flags.
>>
>> Have you reproduce the bug reported from Jason, and verify the patch?
>> I think better just to change the spin_lock_irq to spin_lock_irqsave if that is the cause.
>>
>> Suresh: We could not reproduce this issue and Jason(in CC) also could not reproduce it for now. spin_lock_irqsave and spin_unlock_irqrestore were called from multiple functions. Earlier flags was declared as a local variable wherever spinlock was used. This was not correct since irq information was saved in one function's flag which is a local to that function and restored in other function where again flags was declared as local variable to that function. So the data stored in flags while irq save was not used while restoring. Since we have lock per card, we are associating flag also per card for that lock.
>> -Suresh
>>
>> Jack
>>>>
>>>> Reported-by: Jason Seba <jason.seba42@gmail.com>
>>>> Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>>> Signed-off-by: Viswas G <Viswas.G@pmcs.com>
>>>> ---
>>>>  drivers/scsi/pm8001/pm8001_hwi.c |  158 ++++++++++++++++++++++----------------
>>>>  drivers/scsi/pm8001/pm8001_sas.c |   50 ++++++------
>>>>  drivers/scsi/pm8001/pm8001_sas.h |    1 +
>>>>  drivers/scsi/pm8001/pm80xx_hwi.c |   69 ++++++++++-------
>>>>  4 files changed, 160 insertions(+), 118 deletions(-)
>>>>
>>>> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c
>>>> b/drivers/scsi/pm8001/pm8001_hwi.c
>>>> index 0a1296a..3901c40 100644
>>>> --- a/drivers/scsi/pm8001/pm8001_hwi.c
>>>> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
>>>> @@ -411,7 +411,6 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>                                   u32 SSCbit)
>>>>  {
>>>>      u32 value, offset, i;
>>>> -    unsigned long flags;
>>>>
>>>>  #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>>> SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -425,10 +424,10
>>>> @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>      * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
>>>>      * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
>>>>      */
>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>                              SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              return;
>>>>      }
>>>>
>>>> @@ -439,7 +438,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>      /* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>                              SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              return;
>>>>      }
>>>>      for (i = 4; i < 8; i++) {
>>>> @@ -466,7 +465,7 @@ static void mpi_set_phys_g3_with_ssc(struct
>>>> pm8001_hba_info *pm8001_ha,
>>>>
>>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      return;
>>>>  }
>>>>
>>>> @@ -481,7 +480,6 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>      u32 offset;
>>>>      u32 value;
>>>>      u32 i;
>>>> -    unsigned long flags;
>>>>
>>>>  #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>>> OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -490,11 +488,11
>>>> @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info
>>>> *pm8001_ha,  #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
>>>>
>>>>      value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      /* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>                           OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              return;
>>>>      }
>>>>      for (i = 0; i < 4; i++) {
>>>> @@ -504,7 +502,7 @@ static void
>>>> mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>                           OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              return;
>>>>      }
>>>>      for (i = 4; i < 8; i++) {
>>>> @@ -513,7 +511,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>      }
>>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      return;
>>>>  }
>>>>
>>>> @@ -768,11 +766,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>>              PM8001_INIT_DBG(pm8001_ha,
>>>>                      pm8001_printk("Firmware is ready for reset .\n"));
>>>>      } else {
>>>> -            unsigned long flags;
>>>>              /* Trigger NMI twice via RB6 */
>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>                                      RB6_ACCESS_REG));
>>>> @@ -798,10 +796,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>                              pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return -1;
>>>>              }
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      }
>>>>      return 0;
>>>>  }
>>>> @@ -818,7 +817,6 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>      u32     max_wait_count;
>>>>      u32     regVal1, regVal2, regVal3;
>>>>      u32     signature = 0x252acbcd; /* for host scratch pad0 */
>>>> -    unsigned long flags;
>>>>
>>>>      /* step1: Check FW is ready for soft reset */
>>>>      if (soft_reset_ready_check(pm8001_ha) != 0) { @@ -829,9 +827,9 @@
>>>> pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>      /* step 2: clear NMI status register on AAP1 and IOP, write the same
>>>>      value to clear */
>>>>      /* map 0x60000 to BAR4(0x20), BAR2(win) */
>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>                      MBIC_AAP1_ADDR_BASE));
>>>> @@ -843,7 +841,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>      pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
>>>>      /* map 0x70000 to BAR4(0x20), BAR2(win) */
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>                      MBIC_IOP_ADDR_BASE));
>>>> @@ -886,7 +884,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>      /* read required registers for confirmming */
>>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>                      GSM_ADDR_BASE));
>>>> @@ -953,7 +951,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>      udelay(10);
>>>>      /* step 5-b: set GPIO-0 output control to tristate anyway */
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              PM8001_INIT_DBG(pm8001_ha,
>>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>                              GPIO_ADDR_BASE));
>>>> @@ -970,7 +968,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>      /* Step 6: Reset the IOP and AAP1 */
>>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>>> @@ -1008,7 +1006,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>      /* step 11: reads and sets the GSM Configuration and Reset Register */
>>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>>                      GSM_ADDR_BASE));
>>>> @@ -1062,7 +1060,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>      /* step 13: bring the IOP and AAP1 out of reset */
>>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>>> @@ -1104,7 +1102,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>                              pm8001_cr32(pm8001_ha, 0,
>>>>                              MSGU_SCRATCH_PAD_3)));
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return -1;
>>>>              }
>>>>
>>>> @@ -1134,12 +1133,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>                              pm8001_cr32(pm8001_ha, 0,
>>>>                              MSGU_SCRATCH_PAD_3)));
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return -1;
>>>>              }
>>>>      }
>>>>      pm8001_bar4_shift(pm8001_ha, 0);
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>
>>>>      PM8001_INIT_DBG(pm8001_ha,
>>>>              pm8001_printk("SPC soft reset Complete\n")); @@ -1517,18 +1517,19
>>>> @@ void pm8001_work_fn(struct work_struct *work)
>>>>              u32 tag;
>>>>              struct pm8001_ccb_info *ccb;
>>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>>> -            unsigned long flags, flags1;
>>>> +            unsigned long flags1;
>>>>              struct task_status_struct *ts;
>>>>              int i;
>>>>
>>>>              if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
>>>>                      break; /* Task still on lu */
>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>
>>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      break; /* Task got completed by another */
>>>>              }
>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags1); @@ -1541,7
>>>> +1542,8 @@ void pm8001_work_fn(struct work_struct *work)
>>>>                              break;
>>>>              }
>>>>              if (!ccb) {
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      break; /* Task got freed by another */
>>>>              }
>>>>              ts = &t->task_status;
>>>> @@ -1562,12 +1564,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>                              " aborted by upper layer!\n",
>>>>                              t, pw->handler, ts->resp, ts->stat));
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>              } else {
>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/* in order to force CPU ordering */
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>>              }
>>>>      }       break;
>>>> @@ -1577,7 +1581,7 @@ void pm8001_work_fn(struct work_struct *work)
>>>>              u32 tag;
>>>>              struct pm8001_ccb_info *ccb;
>>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>>> -            unsigned long flags, flags1;
>>>> +            unsigned long flags1;
>>>>              int i, ret = 0;
>>>>
>>>>              PM8001_IO_DBG(pm8001_ha,
>>>> @@ -1600,13 +1604,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>                              break;
>>>>                      });
>>>>
>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>
>>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>>
>>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>>                              (void)pm8001_abort_task(t);
>>>>                      break; /* Task got completed by another */ @@ -1622,7 +1627,8 @@
>>>> void pm8001_work_fn(struct work_struct *work)
>>>>                              break;
>>>>              }
>>>>              if (!ccb) {
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>>                              (void)pm8001_abort_task(t);
>>>>                      break; /* Task got freed by another */ @@ -1634,7 +1640,8 @@ void
>>>> pm8001_work_fn(struct work_struct *work)
>>>>              switch (ret) {
>>>>              case TMF_RESP_FUNC_SUCC: /* task on lu */
>>>>                      ccb->open_retry = 1; /* Snub completion */
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      ret = pm8001_abort_task(t);
>>>>                      ccb->open_retry = 0;
>>>>                      switch (ret) {
>>>> @@ -1651,12 +1658,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>                      break;
>>>>
>>>>              case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      /* Do we need to abort the task locally? */
>>>>                      break;
>>>>
>>>>              default: /* device misbehavior */
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      ret = TMF_RESP_FUNC_FAILED;
>>>>                      PM8001_IO_DBG(pm8001_ha,
>>>>                              pm8001_printk("...Reset phy\n")); @@ -2504,9 +2513,11 @@
>>>> mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*in order to force CPU ordering*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2524,9 +2535,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2552,9 +2565,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/* ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2619,9 +2634,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2643,9 +2660,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2678,16 +2697,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>              mb();/* ditto */
>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              t->task_done(t);
>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      } else if (!t->uldd_task) {
>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>              mb();/*ditto*/
>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              t->task_done(t);
>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      }
>>>>  }
>>>>
>>>> @@ -2798,9 +2817,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2913,16 +2934,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>              mb();/* ditto */
>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              t->task_done(t);
>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      } else if (!t->uldd_task) {
>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>              mb();/*ditto*/
>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              t->task_done(t);
>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      }
>>>>  }
>>>>
>>>> @@ -4194,9 +4215,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>      void *pMsg1 = NULL;
>>>>      u8 uninitialized_var(bc);
>>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>>> -    unsigned long flags;
>>>>
>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>>      do {
>>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>>> @@ -4217,7 +4237,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>                              break;
>>>>              }
>>>>      } while (1);
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      return ret;
>>>>  }
>>>>
>>>> @@ -4472,18 +4492,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>>                                                      flags);
>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>                              mb();/* ditto */
>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              task->task_done(task);
>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              return 0;
>>>>                      } else if (!task->uldd_task) {
>>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>>                                                      flags);
>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>                              mb();/*ditto*/
>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              task->task_done(task);
>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              return 0;
>>>>                      }
>>>>              }
>>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.c
>>>> b/drivers/scsi/pm8001/pm8001_sas.c
>>>> index f50ac44..eac1b81 100644
>>>> --- a/drivers/scsi/pm8001/pm8001_sas.c
>>>> +++ b/drivers/scsi/pm8001/pm8001_sas.c
>>>> @@ -166,7 +166,6 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>>      struct sas_phy_linkrates *rates;
>>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>>> -    unsigned long flags;
>>>>      pm8001_ha = sas_phy->ha->lldd_ha;
>>>>      pm8001_ha->phy[phy_id].enable_completion = &completion;
>>>>      switch (func) {
>>>> @@ -211,11 +210,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>              PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
>>>>              break;
>>>>      case PHY_FUNC_GET_EVENTS:
>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              if (pm8001_ha->chip_id == chip_8001) {
>>>>                      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>                                      (phy_id < 4) ? 0x30000 : 0x40000)) {
>>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              return -EINVAL;
>>>>                      }
>>>>              }
>>>> @@ -232,7 +232,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>              }
>>>>              if (pm8001_ha->chip_id == chip_8001)
>>>>                      pm8001_bar4_shift(pm8001_ha, 0);
>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              return 0;
>>>>      default:
>>>>              rc = -EOPNOTSUPP;
>>>> @@ -369,7 +369,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>      struct pm8001_ccb_info *ccb;
>>>>      u32 tag = 0xdeadbeef, rc, n_elem = 0;
>>>>      u32 n = num;
>>>> -    unsigned long flags = 0;
>>>>
>>>>      if (!dev->port) {
>>>>              struct task_status_struct *tsm = &t->task_status; @@ -380,8 +379,8
>>>> @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>              return 0;
>>>>      }
>>>>      pm8001_ha = pm8001_find_ha_by_dev(task->dev);
>>>> -    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device\n"));
>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      do {
>>>>              dev = t->dev;
>>>>              pm8001_dev = dev->lldd_dev;
>>>> @@ -392,9 +391,11 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>                              ts->resp = SAS_TASK_UNDELIVERED;
>>>>                              ts->stat = SAS_PHY_DOWN;
>>>>
>>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              t->task_done(t);
>>>> -                            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              if (n > 1)
>>>>                                      t = list_entry(t->list.next,
>>>>                                                      struct sas_task, list);
>>>> @@ -482,7 +483,7 @@ err_out:
>>>>                      dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
>>>>                              t->data_dir);
>>>>  out_done:
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      return rc;
>>>>  }
>>>>
>>>> @@ -607,7 +608,6 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
>>>>    */
>>>>  static int pm8001_dev_found_notify(struct domain_device *dev)  {
>>>> -    unsigned long flags = 0;
>>>>      int res = 0;
>>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>>      struct domain_device *parent_dev = dev->parent; @@ -615,7 +615,7 @@
>>>> static int pm8001_dev_found_notify(struct domain_device *dev)
>>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>>>      u32 flag = 0;
>>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>
>>>>      pm8001_device = pm8001_alloc_dev(pm8001_ha);
>>>>      if (!pm8001_device) {
>>>> @@ -654,14 +654,14 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>>>>      } /*register this device to HBA*/
>>>>      PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
>>>>      PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      wait_for_completion(&completion);
>>>>      if (dev->dev_type == SAS_END_DEVICE)
>>>>              msleep(50);
>>>>      pm8001_ha->flags = PM8001F_RUN_TIME;
>>>>      return 0;
>>>>  found_out:
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      return res;
>>>>  }
>>>>
>>>> @@ -864,13 +864,12 @@ ex_err:
>>>>    */
>>>>  static void pm8001_dev_gone_notify(struct domain_device *dev)  {
>>>> -    unsigned long flags = 0;
>>>>      u32 tag;
>>>>      struct pm8001_hba_info *pm8001_ha;
>>>>      struct pm8001_device *pm8001_dev = dev->lldd_dev;
>>>>
>>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      pm8001_tag_alloc(pm8001_ha, &tag);
>>>>      if (pm8001_dev) {
>>>>              u32 device_id = pm8001_dev->device_id; @@ -879,10 +878,12 @@
>>>> static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>>                      pm8001_printk("found dev[%d:%x] is gone.\n",
>>>>                      pm8001_dev->device_id, pm8001_dev->dev_type));
>>>>              if (pm8001_dev->running_req) {
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
>>>>                              dev, 1, 0);
>>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>              }
>>>>              PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
>>>>              pm8001_free_dev(pm8001_dev);
>>>> @@ -891,7 +892,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>>                      pm8001_printk("Found dev has gone.\n"));
>>>>      }
>>>>      dev->lldd_dev = NULL;
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>  }
>>>>
>>>>  void pm8001_dev_gone(struct domain_device *dev) @@ -918,12 +919,11
>>>> @@ void pm8001_open_reject_retry(
>>>>      struct pm8001_device *device_to_close)  {
>>>>      int i;
>>>> -    unsigned long flags;
>>>>
>>>>      if (pm8001_ha == NULL)
>>>>              return;
>>>>
>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>
>>>>      for (i = 0; i < PM8001_MAX_CCB; i++) {
>>>>              struct sas_task *task;
>>>> @@ -973,13 +973,15 @@ void pm8001_open_reject_retry(
>>>>                              flags1);
>>>>                      pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>                      mb();/* in order to force CPU ordering */
>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      task->task_done(task);
>>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>              }
>>>>      }
>>>>
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>  }
>>>>
>>>>  /**
>>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.h
>>>> b/drivers/scsi/pm8001/pm8001_sas.h
>>>> index 6c5fd5e..2b8065c 100644
>>>> --- a/drivers/scsi/pm8001/pm8001_sas.h
>>>> +++ b/drivers/scsi/pm8001/pm8001_sas.h
>>>> @@ -475,6 +475,7 @@ struct pm8001_hba_info {
>>>>      struct list_head        list;
>>>>      unsigned long           flags;
>>>>      spinlock_t              lock;/* host-wide lock */
>>>> +    unsigned long           lock_flags;
>>>>      struct pci_dev          *pdev;/* our device */
>>>>      struct device           *dev;
>>>>      struct pm8001_hba_memspace io_mem[6]; diff --git
>>>> a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
>>>> index c950dc5..3ac024a 100644
>>>> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
>>>> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
>>>> @@ -2177,9 +2177,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*in order to force CPU ordering*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2197,9 +2199,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2223,9 +2227,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/* ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2290,9 +2296,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2314,9 +2322,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2349,16 +2359,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>              mb();/* ditto */
>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              t->task_done(t);
>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      } else if (!t->uldd_task) {
>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>              mb();/*ditto*/
>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              t->task_done(t);
>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      }
>>>>  }
>>>>
>>>> @@ -2472,9 +2482,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>                      mb();/*ditto*/
>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      t->task_done(t);
>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                            pm8001_ha->lock_flags);
>>>>                      return;
>>>>              }
>>>>              break;
>>>> @@ -2600,16 +2612,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>              mb();/* ditto */
>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              t->task_done(t);
>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      } else if (!t->uldd_task) {
>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>              mb();/*ditto*/
>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>              t->task_done(t);
>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      }
>>>>  }
>>>>
>>>> @@ -3705,9 +3717,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>      void *pMsg1 = NULL;
>>>>      u8 uninitialized_var(bc);
>>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>>> -    unsigned long flags;
>>>>
>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>>      do {
>>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>>> @@ -3728,7 +3739,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>                              break;
>>>>              }
>>>>      } while (1);
>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>      return ret;
>>>>  }
>>>>
>>>> @@ -4309,18 +4320,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>>                                                      flags);
>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>                              mb();/* ditto */
>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              task->task_done(task);
>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              return 0;
>>>>                      } else if (!task->uldd_task) {
>>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>>                                                      flags);
>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>                              mb();/*ditto*/
>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              task->task_done(task);
>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>> +                                                    pm8001_ha->lock_flags);
>>>>                              return 0;
>>>>                      }
>>>>              }
>>>
>>


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] pm80xx: Spinlock fix
  2013-12-23 15:06         ` Jack Wang
@ 2013-12-23 15:28           ` Tomas Henzl
  2013-12-23 15:33             ` Jason Seba
  2013-12-23 15:38             ` [PATCH] pm80xx: Spinlock fix Oleg Nesterov
  0 siblings, 2 replies; 33+ messages in thread
From: Tomas Henzl @ 2013-12-23 15:28 UTC (permalink / raw)
  To: Jack Wang, Jason Seba
  Cc: Suresh Thiagarajan, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, Oleg Nesterov

On 12/23/2013 04:06 PM, Jack Wang wrote:
> On 12/23/2013 03:55 PM, Jason Seba wrote:
>> Why is this considered dangerous?  I put some thought into it and
>> couldn't find any obvious reason why it wouldn't work, but I also
>> couldn't find any other drivers that work this way.  Is there a
>> particular reason to avoid doing it this way?
>>
> If you use global flags, you may change interrupt state depends on context.

The problem could show up when different threads try to store different content to the flags.

>
>> On Mon, Dec 23, 2013 at 8:45 AM, Suresh Thiagarajan
>> <Suresh.Thiagarajan@pmcs.com> wrote:
>>>
>>> -----Original Message-----
>>> From: Jack Wang [mailto:xjtuwjp@gmail.com]
>>> Sent: Monday, December 23, 2013 7:03 PM
>>> To: Tomas Henzl; Viswas G
>>> Cc: linux-scsi@vger.kernel.org; jason.seba42@gmail.com; JBottomley@parallels.com; Vasanthalakshmi Tharmarajan; Suresh Thiagarajan
>>> Subject: Re: [PATCH] pm80xx: Spinlock fix
>>>
>>> On 12/23/2013 02:07 PM, Tomas Henzl wrote:
>>>> On 12/18/2013 12:28 PM, Viswas G wrote:
>>>>> From 9338d4bc92b23b4c283f9bd6812646ab74866a40 Mon Sep 17 00:00:00
>>>>> 2001
>>>>> From: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>>>> Date: Mon, 16 Dec 2013 21:15:20 +0530
>>>>> Subject: [PATCH] pm80xx: Spinlock fix
>>>>>
>>>>> spin_unlock was used instead of spin_unlock_irqrestore. To fix this
>>>>> lock_flags per-adapter is added and used across all the places where pm8001_ha->lock is used.
>>>> I think this could have been fixed but just using spin_unlock_irqsave
>>>> instead of spin_unlock_irq why the change to global lock_flags?  I'm not a spinlock expert, but is this safe?
>>>>
>>> Agree with Tomas, it's dangerous to change to global lock_flags.
>>>
>>> Have you reproduce the bug reported from Jason, and verify the patch?
>>> I think better just to change the spin_lock_irq to spin_lock_irqsave if that is the cause.
>>>
>>> Suresh: We could not reproduce this issue and Jason(in CC) also could not reproduce it for now. spin_lock_irqsave and spin_unlock_irqrestore were called from multiple functions. Earlier flags was declared as a local variable wherever spinlock was used. This was not correct since irq information was saved in one function's flag which is a local to that function and restored in other function where again flags was declared as local variable to that function. So the data stored in flags while irq save was not used while restoring. Since we have lock per card, we are associating flag also per card for that lock.

Thanks, it took me a while until I have found an example - you need to unlock
mpi_ssp_event and the lock was taken elsewhere, so I understand it better now.
You know your code much better - are you sure that no other thread will be started
which could change the value of lock_flags?

Tomas

>>> -Suresh
>>>
>>> Jack
>>>>> Reported-by: Jason Seba <jason.seba42@gmail.com>
>>>>> Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>>>> Signed-off-by: Viswas G <Viswas.G@pmcs.com>
>>>>> ---
>>>>>  drivers/scsi/pm8001/pm8001_hwi.c |  158 ++++++++++++++++++++++----------------
>>>>>  drivers/scsi/pm8001/pm8001_sas.c |   50 ++++++------
>>>>>  drivers/scsi/pm8001/pm8001_sas.h |    1 +
>>>>>  drivers/scsi/pm8001/pm80xx_hwi.c |   69 ++++++++++-------
>>>>>  4 files changed, 160 insertions(+), 118 deletions(-)
>>>>>
>>>>> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c
>>>>> b/drivers/scsi/pm8001/pm8001_hwi.c
>>>>> index 0a1296a..3901c40 100644
>>>>> --- a/drivers/scsi/pm8001/pm8001_hwi.c
>>>>> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
>>>>> @@ -411,7 +411,6 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>>                                   u32 SSCbit)
>>>>>  {
>>>>>      u32 value, offset, i;
>>>>> -    unsigned long flags;
>>>>>
>>>>>  #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>>>> SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -425,10 +424,10
>>>>> @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>>      * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
>>>>>      * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
>>>>>      */
>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>                              SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              return;
>>>>>      }
>>>>>
>>>>> @@ -439,7 +438,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>>      /* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>                              SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              return;
>>>>>      }
>>>>>      for (i = 4; i < 8; i++) {
>>>>> @@ -466,7 +465,7 @@ static void mpi_set_phys_g3_with_ssc(struct
>>>>> pm8001_hba_info *pm8001_ha,
>>>>>
>>>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      return;
>>>>>  }
>>>>>
>>>>> @@ -481,7 +480,6 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>>      u32 offset;
>>>>>      u32 value;
>>>>>      u32 i;
>>>>> -    unsigned long flags;
>>>>>
>>>>>  #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>>>> OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -490,11 +488,11
>>>>> @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info
>>>>> *pm8001_ha,  #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
>>>>>
>>>>>      value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      /* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>                           OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              return;
>>>>>      }
>>>>>      for (i = 0; i < 4; i++) {
>>>>> @@ -504,7 +502,7 @@ static void
>>>>> mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>>
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>                           OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              return;
>>>>>      }
>>>>>      for (i = 4; i < 8; i++) {
>>>>> @@ -513,7 +511,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>>      }
>>>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      return;
>>>>>  }
>>>>>
>>>>> @@ -768,11 +766,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>>>              PM8001_INIT_DBG(pm8001_ha,
>>>>>                      pm8001_printk("Firmware is ready for reset .\n"));
>>>>>      } else {
>>>>> -            unsigned long flags;
>>>>>              /* Trigger NMI twice via RB6 */
>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>                                      RB6_ACCESS_REG));
>>>>> @@ -798,10 +796,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>>                              pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return -1;
>>>>>              }
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      }
>>>>>      return 0;
>>>>>  }
>>>>> @@ -818,7 +817,6 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>      u32     max_wait_count;
>>>>>      u32     regVal1, regVal2, regVal3;
>>>>>      u32     signature = 0x252acbcd; /* for host scratch pad0 */
>>>>> -    unsigned long flags;
>>>>>
>>>>>      /* step1: Check FW is ready for soft reset */
>>>>>      if (soft_reset_ready_check(pm8001_ha) != 0) { @@ -829,9 +827,9 @@
>>>>> pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>      /* step 2: clear NMI status register on AAP1 and IOP, write the same
>>>>>      value to clear */
>>>>>      /* map 0x60000 to BAR4(0x20), BAR2(win) */
>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>                      MBIC_AAP1_ADDR_BASE));
>>>>> @@ -843,7 +841,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>      pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
>>>>>      /* map 0x70000 to BAR4(0x20), BAR2(win) */
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>                      MBIC_IOP_ADDR_BASE));
>>>>> @@ -886,7 +884,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>      /* read required registers for confirmming */
>>>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>                      GSM_ADDR_BASE));
>>>>> @@ -953,7 +951,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>      udelay(10);
>>>>>      /* step 5-b: set GPIO-0 output control to tristate anyway */
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              PM8001_INIT_DBG(pm8001_ha,
>>>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>                              GPIO_ADDR_BASE));
>>>>> @@ -970,7 +968,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>      /* Step 6: Reset the IOP and AAP1 */
>>>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>>>> @@ -1008,7 +1006,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>      /* step 11: reads and sets the GSM Configuration and Reset Register */
>>>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>>>                      GSM_ADDR_BASE));
>>>>> @@ -1062,7 +1060,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>      /* step 13: bring the IOP and AAP1 out of reset */
>>>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>>>> @@ -1104,7 +1102,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>>                              pm8001_cr32(pm8001_ha, 0,
>>>>>                              MSGU_SCRATCH_PAD_3)));
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return -1;
>>>>>              }
>>>>>
>>>>> @@ -1134,12 +1133,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>>                              pm8001_cr32(pm8001_ha, 0,
>>>>>                              MSGU_SCRATCH_PAD_3)));
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return -1;
>>>>>              }
>>>>>      }
>>>>>      pm8001_bar4_shift(pm8001_ha, 0);
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>
>>>>>      PM8001_INIT_DBG(pm8001_ha,
>>>>>              pm8001_printk("SPC soft reset Complete\n")); @@ -1517,18 +1517,19
>>>>> @@ void pm8001_work_fn(struct work_struct *work)
>>>>>              u32 tag;
>>>>>              struct pm8001_ccb_info *ccb;
>>>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>>>> -            unsigned long flags, flags1;
>>>>> +            unsigned long flags1;
>>>>>              struct task_status_struct *ts;
>>>>>              int i;
>>>>>
>>>>>              if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
>>>>>                      break; /* Task still on lu */
>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>
>>>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      break; /* Task got completed by another */
>>>>>              }
>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags1); @@ -1541,7
>>>>> +1542,8 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>                              break;
>>>>>              }
>>>>>              if (!ccb) {
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      break; /* Task got freed by another */
>>>>>              }
>>>>>              ts = &t->task_status;
>>>>> @@ -1562,12 +1564,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>                              " aborted by upper layer!\n",
>>>>>                              t, pw->handler, ts->resp, ts->stat));
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>              } else {
>>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/* in order to force CPU ordering */
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>>              }
>>>>>      }       break;
>>>>> @@ -1577,7 +1581,7 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>              u32 tag;
>>>>>              struct pm8001_ccb_info *ccb;
>>>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>>>> -            unsigned long flags, flags1;
>>>>> +            unsigned long flags1;
>>>>>              int i, ret = 0;
>>>>>
>>>>>              PM8001_IO_DBG(pm8001_ha,
>>>>> @@ -1600,13 +1604,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>                              break;
>>>>>                      });
>>>>>
>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>
>>>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>>>
>>>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>>>                              (void)pm8001_abort_task(t);
>>>>>                      break; /* Task got completed by another */ @@ -1622,7 +1627,8 @@
>>>>> void pm8001_work_fn(struct work_struct *work)
>>>>>                              break;
>>>>>              }
>>>>>              if (!ccb) {
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>>>                              (void)pm8001_abort_task(t);
>>>>>                      break; /* Task got freed by another */ @@ -1634,7 +1640,8 @@ void
>>>>> pm8001_work_fn(struct work_struct *work)
>>>>>              switch (ret) {
>>>>>              case TMF_RESP_FUNC_SUCC: /* task on lu */
>>>>>                      ccb->open_retry = 1; /* Snub completion */
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      ret = pm8001_abort_task(t);
>>>>>                      ccb->open_retry = 0;
>>>>>                      switch (ret) {
>>>>> @@ -1651,12 +1658,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>                      break;
>>>>>
>>>>>              case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      /* Do we need to abort the task locally? */
>>>>>                      break;
>>>>>
>>>>>              default: /* device misbehavior */
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      ret = TMF_RESP_FUNC_FAILED;
>>>>>                      PM8001_IO_DBG(pm8001_ha,
>>>>>                              pm8001_printk("...Reset phy\n")); @@ -2504,9 +2513,11 @@
>>>>> mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*in order to force CPU ordering*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2524,9 +2535,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2552,9 +2565,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/* ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2619,9 +2634,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2643,9 +2660,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2678,16 +2697,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>              mb();/* ditto */
>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              t->task_done(t);
>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      } else if (!t->uldd_task) {
>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>              mb();/*ditto*/
>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              t->task_done(t);
>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      }
>>>>>  }
>>>>>
>>>>> @@ -2798,9 +2817,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2913,16 +2934,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>              mb();/* ditto */
>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              t->task_done(t);
>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      } else if (!t->uldd_task) {
>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>              mb();/*ditto*/
>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              t->task_done(t);
>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      }
>>>>>  }
>>>>>
>>>>> @@ -4194,9 +4215,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>      void *pMsg1 = NULL;
>>>>>      u8 uninitialized_var(bc);
>>>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>>>> -    unsigned long flags;
>>>>>
>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>>>      do {
>>>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>>>> @@ -4217,7 +4237,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>                              break;
>>>>>              }
>>>>>      } while (1);
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      return ret;
>>>>>  }
>>>>>
>>>>> @@ -4472,18 +4492,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>>>                                                      flags);
>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>                              mb();/* ditto */
>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              task->task_done(task);
>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              return 0;
>>>>>                      } else if (!task->uldd_task) {
>>>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>>>                                                      flags);
>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>                              mb();/*ditto*/
>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              task->task_done(task);
>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              return 0;
>>>>>                      }
>>>>>              }
>>>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.c
>>>>> b/drivers/scsi/pm8001/pm8001_sas.c
>>>>> index f50ac44..eac1b81 100644
>>>>> --- a/drivers/scsi/pm8001/pm8001_sas.c
>>>>> +++ b/drivers/scsi/pm8001/pm8001_sas.c
>>>>> @@ -166,7 +166,6 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>>>      struct sas_phy_linkrates *rates;
>>>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>>>> -    unsigned long flags;
>>>>>      pm8001_ha = sas_phy->ha->lldd_ha;
>>>>>      pm8001_ha->phy[phy_id].enable_completion = &completion;
>>>>>      switch (func) {
>>>>> @@ -211,11 +210,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>>              PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
>>>>>              break;
>>>>>      case PHY_FUNC_GET_EVENTS:
>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              if (pm8001_ha->chip_id == chip_8001) {
>>>>>                      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>                                      (phy_id < 4) ? 0x30000 : 0x40000)) {
>>>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              return -EINVAL;
>>>>>                      }
>>>>>              }
>>>>> @@ -232,7 +232,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>>              }
>>>>>              if (pm8001_ha->chip_id == chip_8001)
>>>>>                      pm8001_bar4_shift(pm8001_ha, 0);
>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              return 0;
>>>>>      default:
>>>>>              rc = -EOPNOTSUPP;
>>>>> @@ -369,7 +369,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>>      struct pm8001_ccb_info *ccb;
>>>>>      u32 tag = 0xdeadbeef, rc, n_elem = 0;
>>>>>      u32 n = num;
>>>>> -    unsigned long flags = 0;
>>>>>
>>>>>      if (!dev->port) {
>>>>>              struct task_status_struct *tsm = &t->task_status; @@ -380,8 +379,8
>>>>> @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>>              return 0;
>>>>>      }
>>>>>      pm8001_ha = pm8001_find_ha_by_dev(task->dev);
>>>>> -    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device\n"));
>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      do {
>>>>>              dev = t->dev;
>>>>>              pm8001_dev = dev->lldd_dev;
>>>>> @@ -392,9 +391,11 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>>                              ts->resp = SAS_TASK_UNDELIVERED;
>>>>>                              ts->stat = SAS_PHY_DOWN;
>>>>>
>>>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              t->task_done(t);
>>>>> -                            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              if (n > 1)
>>>>>                                      t = list_entry(t->list.next,
>>>>>                                                      struct sas_task, list);
>>>>> @@ -482,7 +483,7 @@ err_out:
>>>>>                      dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
>>>>>                              t->data_dir);
>>>>>  out_done:
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      return rc;
>>>>>  }
>>>>>
>>>>> @@ -607,7 +608,6 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
>>>>>    */
>>>>>  static int pm8001_dev_found_notify(struct domain_device *dev)  {
>>>>> -    unsigned long flags = 0;
>>>>>      int res = 0;
>>>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>>>      struct domain_device *parent_dev = dev->parent; @@ -615,7 +615,7 @@
>>>>> static int pm8001_dev_found_notify(struct domain_device *dev)
>>>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>>>>      u32 flag = 0;
>>>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>
>>>>>      pm8001_device = pm8001_alloc_dev(pm8001_ha);
>>>>>      if (!pm8001_device) {
>>>>> @@ -654,14 +654,14 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>>>>>      } /*register this device to HBA*/
>>>>>      PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
>>>>>      PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      wait_for_completion(&completion);
>>>>>      if (dev->dev_type == SAS_END_DEVICE)
>>>>>              msleep(50);
>>>>>      pm8001_ha->flags = PM8001F_RUN_TIME;
>>>>>      return 0;
>>>>>  found_out:
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      return res;
>>>>>  }
>>>>>
>>>>> @@ -864,13 +864,12 @@ ex_err:
>>>>>    */
>>>>>  static void pm8001_dev_gone_notify(struct domain_device *dev)  {
>>>>> -    unsigned long flags = 0;
>>>>>      u32 tag;
>>>>>      struct pm8001_hba_info *pm8001_ha;
>>>>>      struct pm8001_device *pm8001_dev = dev->lldd_dev;
>>>>>
>>>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      pm8001_tag_alloc(pm8001_ha, &tag);
>>>>>      if (pm8001_dev) {
>>>>>              u32 device_id = pm8001_dev->device_id; @@ -879,10 +878,12 @@
>>>>> static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>>>                      pm8001_printk("found dev[%d:%x] is gone.\n",
>>>>>                      pm8001_dev->device_id, pm8001_dev->dev_type));
>>>>>              if (pm8001_dev->running_req) {
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
>>>>>                              dev, 1, 0);
>>>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>              }
>>>>>              PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
>>>>>              pm8001_free_dev(pm8001_dev);
>>>>> @@ -891,7 +892,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>>>                      pm8001_printk("Found dev has gone.\n"));
>>>>>      }
>>>>>      dev->lldd_dev = NULL;
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>  }
>>>>>
>>>>>  void pm8001_dev_gone(struct domain_device *dev) @@ -918,12 +919,11
>>>>> @@ void pm8001_open_reject_retry(
>>>>>      struct pm8001_device *device_to_close)  {
>>>>>      int i;
>>>>> -    unsigned long flags;
>>>>>
>>>>>      if (pm8001_ha == NULL)
>>>>>              return;
>>>>>
>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>
>>>>>      for (i = 0; i < PM8001_MAX_CCB; i++) {
>>>>>              struct sas_task *task;
>>>>> @@ -973,13 +973,15 @@ void pm8001_open_reject_retry(
>>>>>                              flags1);
>>>>>                      pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>                      mb();/* in order to force CPU ordering */
>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      task->task_done(task);
>>>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>              }
>>>>>      }
>>>>>
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>  }
>>>>>
>>>>>  /**
>>>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.h
>>>>> b/drivers/scsi/pm8001/pm8001_sas.h
>>>>> index 6c5fd5e..2b8065c 100644
>>>>> --- a/drivers/scsi/pm8001/pm8001_sas.h
>>>>> +++ b/drivers/scsi/pm8001/pm8001_sas.h
>>>>> @@ -475,6 +475,7 @@ struct pm8001_hba_info {
>>>>>      struct list_head        list;
>>>>>      unsigned long           flags;
>>>>>      spinlock_t              lock;/* host-wide lock */
>>>>> +    unsigned long           lock_flags;
>>>>>      struct pci_dev          *pdev;/* our device */
>>>>>      struct device           *dev;
>>>>>      struct pm8001_hba_memspace io_mem[6]; diff --git
>>>>> a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
>>>>> index c950dc5..3ac024a 100644
>>>>> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
>>>>> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
>>>>> @@ -2177,9 +2177,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*in order to force CPU ordering*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2197,9 +2199,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2223,9 +2227,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/* ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2290,9 +2296,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2314,9 +2322,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2349,16 +2359,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>              mb();/* ditto */
>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              t->task_done(t);
>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      } else if (!t->uldd_task) {
>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>              mb();/*ditto*/
>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              t->task_done(t);
>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      }
>>>>>  }
>>>>>
>>>>> @@ -2472,9 +2482,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>                      mb();/*ditto*/
>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      t->task_done(t);
>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                            pm8001_ha->lock_flags);
>>>>>                      return;
>>>>>              }
>>>>>              break;
>>>>> @@ -2600,16 +2612,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>              mb();/* ditto */
>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              t->task_done(t);
>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      } else if (!t->uldd_task) {
>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>              mb();/*ditto*/
>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>              t->task_done(t);
>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      }
>>>>>  }
>>>>>
>>>>> @@ -3705,9 +3717,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>      void *pMsg1 = NULL;
>>>>>      u8 uninitialized_var(bc);
>>>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>>>> -    unsigned long flags;
>>>>>
>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>>>      do {
>>>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>>>> @@ -3728,7 +3739,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>                              break;
>>>>>              }
>>>>>      } while (1);
>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>      return ret;
>>>>>  }
>>>>>
>>>>> @@ -4309,18 +4320,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>>>                                                      flags);
>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>                              mb();/* ditto */
>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              task->task_done(task);
>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              return 0;
>>>>>                      } else if (!task->uldd_task) {
>>>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>>>                                                      flags);
>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>                              mb();/*ditto*/
>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              task->task_done(task);
>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>                              return 0;
>>>>>                      }
>>>>>              }
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] pm80xx: Spinlock fix
  2013-12-23 15:28           ` Tomas Henzl
@ 2013-12-23 15:33             ` Jason Seba
  2013-12-23 15:36               ` Tomas Henzl
  2013-12-23 16:34               ` Oleg Nesterov
  2013-12-23 15:38             ` [PATCH] pm80xx: Spinlock fix Oleg Nesterov
  1 sibling, 2 replies; 33+ messages in thread
From: Jason Seba @ 2013-12-23 15:33 UTC (permalink / raw)
  To: Tomas Henzl
  Cc: Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, Oleg Nesterov

 Wouldn't the contents of the global flags value be protected by the
spinlock itself?  Or is that making a dangerous assumption about the
particulars of how spinlocks work on various platforms?

On Mon, Dec 23, 2013 at 10:28 AM, Tomas Henzl <thenzl@redhat.com> wrote:
> On 12/23/2013 04:06 PM, Jack Wang wrote:
>> On 12/23/2013 03:55 PM, Jason Seba wrote:
>>> Why is this considered dangerous?  I put some thought into it and
>>> couldn't find any obvious reason why it wouldn't work, but I also
>>> couldn't find any other drivers that work this way.  Is there a
>>> particular reason to avoid doing it this way?
>>>
>> If you use global flags, you may change interrupt state depends on context.
>
> The problem could show up when different threads try to store different content to the flags.
>
>>
>>> On Mon, Dec 23, 2013 at 8:45 AM, Suresh Thiagarajan
>>> <Suresh.Thiagarajan@pmcs.com> wrote:
>>>>
>>>> -----Original Message-----
>>>> From: Jack Wang [mailto:xjtuwjp@gmail.com]
>>>> Sent: Monday, December 23, 2013 7:03 PM
>>>> To: Tomas Henzl; Viswas G
>>>> Cc: linux-scsi@vger.kernel.org; jason.seba42@gmail.com; JBottomley@parallels.com; Vasanthalakshmi Tharmarajan; Suresh Thiagarajan
>>>> Subject: Re: [PATCH] pm80xx: Spinlock fix
>>>>
>>>> On 12/23/2013 02:07 PM, Tomas Henzl wrote:
>>>>> On 12/18/2013 12:28 PM, Viswas G wrote:
>>>>>> From 9338d4bc92b23b4c283f9bd6812646ab74866a40 Mon Sep 17 00:00:00
>>>>>> 2001
>>>>>> From: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>>>>> Date: Mon, 16 Dec 2013 21:15:20 +0530
>>>>>> Subject: [PATCH] pm80xx: Spinlock fix
>>>>>>
>>>>>> spin_unlock was used instead of spin_unlock_irqrestore. To fix this
>>>>>> lock_flags per-adapter is added and used across all the places where pm8001_ha->lock is used.
>>>>> I think this could have been fixed but just using spin_unlock_irqsave
>>>>> instead of spin_unlock_irq why the change to global lock_flags?  I'm not a spinlock expert, but is this safe?
>>>>>
>>>> Agree with Tomas, it's dangerous to change to global lock_flags.
>>>>
>>>> Have you reproduce the bug reported from Jason, and verify the patch?
>>>> I think better just to change the spin_lock_irq to spin_lock_irqsave if that is the cause.
>>>>
>>>> Suresh: We could not reproduce this issue and Jason(in CC) also could not reproduce it for now. spin_lock_irqsave and spin_unlock_irqrestore were called from multiple functions. Earlier flags was declared as a local variable wherever spinlock was used. This was not correct since irq information was saved in one function's flag which is a local to that function and restored in other function where again flags was declared as local variable to that function. So the data stored in flags while irq save was not used while restoring. Since we have lock per card, we are associating flag also per card for that lock.
>
> Thanks, it took me a while until I have found an example - you need to unlock
> mpi_ssp_event and the lock was taken elsewhere, so I understand it better now.
> You know your code much better - are you sure that no other thread will be started
> which could change the value of lock_flags?
>
> Tomas
>
>>>> -Suresh
>>>>
>>>> Jack
>>>>>> Reported-by: Jason Seba <jason.seba42@gmail.com>
>>>>>> Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>>>>> Signed-off-by: Viswas G <Viswas.G@pmcs.com>
>>>>>> ---
>>>>>>  drivers/scsi/pm8001/pm8001_hwi.c |  158 ++++++++++++++++++++++----------------
>>>>>>  drivers/scsi/pm8001/pm8001_sas.c |   50 ++++++------
>>>>>>  drivers/scsi/pm8001/pm8001_sas.h |    1 +
>>>>>>  drivers/scsi/pm8001/pm80xx_hwi.c |   69 ++++++++++-------
>>>>>>  4 files changed, 160 insertions(+), 118 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c
>>>>>> b/drivers/scsi/pm8001/pm8001_hwi.c
>>>>>> index 0a1296a..3901c40 100644
>>>>>> --- a/drivers/scsi/pm8001/pm8001_hwi.c
>>>>>> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
>>>>>> @@ -411,7 +411,6 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>>>                                   u32 SSCbit)
>>>>>>  {
>>>>>>      u32 value, offset, i;
>>>>>> -    unsigned long flags;
>>>>>>
>>>>>>  #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>>>>> SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -425,10 +424,10
>>>>>> @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>>>      * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
>>>>>>      * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
>>>>>>      */
>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>                              SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              return;
>>>>>>      }
>>>>>>
>>>>>> @@ -439,7 +438,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>>>      /* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>                              SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              return;
>>>>>>      }
>>>>>>      for (i = 4; i < 8; i++) {
>>>>>> @@ -466,7 +465,7 @@ static void mpi_set_phys_g3_with_ssc(struct
>>>>>> pm8001_hba_info *pm8001_ha,
>>>>>>
>>>>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      return;
>>>>>>  }
>>>>>>
>>>>>> @@ -481,7 +480,6 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>>>      u32 offset;
>>>>>>      u32 value;
>>>>>>      u32 i;
>>>>>> -    unsigned long flags;
>>>>>>
>>>>>>  #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>>>>> OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -490,11 +488,11
>>>>>> @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info
>>>>>> *pm8001_ha,  #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
>>>>>>
>>>>>>      value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      /* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>                           OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              return;
>>>>>>      }
>>>>>>      for (i = 0; i < 4; i++) {
>>>>>> @@ -504,7 +502,7 @@ static void
>>>>>> mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>>>
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>                           OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              return;
>>>>>>      }
>>>>>>      for (i = 4; i < 8; i++) {
>>>>>> @@ -513,7 +511,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>>>      }
>>>>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      return;
>>>>>>  }
>>>>>>
>>>>>> @@ -768,11 +766,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>>>>              PM8001_INIT_DBG(pm8001_ha,
>>>>>>                      pm8001_printk("Firmware is ready for reset .\n"));
>>>>>>      } else {
>>>>>> -            unsigned long flags;
>>>>>>              /* Trigger NMI twice via RB6 */
>>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>                                      RB6_ACCESS_REG));
>>>>>> @@ -798,10 +796,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>>>                              pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return -1;
>>>>>>              }
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      }
>>>>>>      return 0;
>>>>>>  }
>>>>>> @@ -818,7 +817,6 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>      u32     max_wait_count;
>>>>>>      u32     regVal1, regVal2, regVal3;
>>>>>>      u32     signature = 0x252acbcd; /* for host scratch pad0 */
>>>>>> -    unsigned long flags;
>>>>>>
>>>>>>      /* step1: Check FW is ready for soft reset */
>>>>>>      if (soft_reset_ready_check(pm8001_ha) != 0) { @@ -829,9 +827,9 @@
>>>>>> pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>      /* step 2: clear NMI status register on AAP1 and IOP, write the same
>>>>>>      value to clear */
>>>>>>      /* map 0x60000 to BAR4(0x20), BAR2(win) */
>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>                      MBIC_AAP1_ADDR_BASE));
>>>>>> @@ -843,7 +841,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>      pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
>>>>>>      /* map 0x70000 to BAR4(0x20), BAR2(win) */
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>                      MBIC_IOP_ADDR_BASE));
>>>>>> @@ -886,7 +884,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>      /* read required registers for confirmming */
>>>>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>                      GSM_ADDR_BASE));
>>>>>> @@ -953,7 +951,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>      udelay(10);
>>>>>>      /* step 5-b: set GPIO-0 output control to tristate anyway */
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              PM8001_INIT_DBG(pm8001_ha,
>>>>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>                              GPIO_ADDR_BASE));
>>>>>> @@ -970,7 +968,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>      /* Step 6: Reset the IOP and AAP1 */
>>>>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>>>>> @@ -1008,7 +1006,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>      /* step 11: reads and sets the GSM Configuration and Reset Register */
>>>>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>>>>                      GSM_ADDR_BASE));
>>>>>> @@ -1062,7 +1060,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>      /* step 13: bring the IOP and AAP1 out of reset */
>>>>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>>>>> @@ -1104,7 +1102,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>>>                              pm8001_cr32(pm8001_ha, 0,
>>>>>>                              MSGU_SCRATCH_PAD_3)));
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return -1;
>>>>>>              }
>>>>>>
>>>>>> @@ -1134,12 +1133,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>>>                              pm8001_cr32(pm8001_ha, 0,
>>>>>>                              MSGU_SCRATCH_PAD_3)));
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return -1;
>>>>>>              }
>>>>>>      }
>>>>>>      pm8001_bar4_shift(pm8001_ha, 0);
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>
>>>>>>      PM8001_INIT_DBG(pm8001_ha,
>>>>>>              pm8001_printk("SPC soft reset Complete\n")); @@ -1517,18 +1517,19
>>>>>> @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>              u32 tag;
>>>>>>              struct pm8001_ccb_info *ccb;
>>>>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>>>>> -            unsigned long flags, flags1;
>>>>>> +            unsigned long flags1;
>>>>>>              struct task_status_struct *ts;
>>>>>>              int i;
>>>>>>
>>>>>>              if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
>>>>>>                      break; /* Task still on lu */
>>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>
>>>>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      break; /* Task got completed by another */
>>>>>>              }
>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags1); @@ -1541,7
>>>>>> +1542,8 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>                              break;
>>>>>>              }
>>>>>>              if (!ccb) {
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      break; /* Task got freed by another */
>>>>>>              }
>>>>>>              ts = &t->task_status;
>>>>>> @@ -1562,12 +1564,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>                              " aborted by upper layer!\n",
>>>>>>                              t, pw->handler, ts->resp, ts->stat));
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>              } else {
>>>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/* in order to force CPU ordering */
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>>              }
>>>>>>      }       break;
>>>>>> @@ -1577,7 +1581,7 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>              u32 tag;
>>>>>>              struct pm8001_ccb_info *ccb;
>>>>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>>>>> -            unsigned long flags, flags1;
>>>>>> +            unsigned long flags1;
>>>>>>              int i, ret = 0;
>>>>>>
>>>>>>              PM8001_IO_DBG(pm8001_ha,
>>>>>> @@ -1600,13 +1604,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>                              break;
>>>>>>                      });
>>>>>>
>>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>
>>>>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>>>>
>>>>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>>>>                              (void)pm8001_abort_task(t);
>>>>>>                      break; /* Task got completed by another */ @@ -1622,7 +1627,8 @@
>>>>>> void pm8001_work_fn(struct work_struct *work)
>>>>>>                              break;
>>>>>>              }
>>>>>>              if (!ccb) {
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>>>>                              (void)pm8001_abort_task(t);
>>>>>>                      break; /* Task got freed by another */ @@ -1634,7 +1640,8 @@ void
>>>>>> pm8001_work_fn(struct work_struct *work)
>>>>>>              switch (ret) {
>>>>>>              case TMF_RESP_FUNC_SUCC: /* task on lu */
>>>>>>                      ccb->open_retry = 1; /* Snub completion */
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      ret = pm8001_abort_task(t);
>>>>>>                      ccb->open_retry = 0;
>>>>>>                      switch (ret) {
>>>>>> @@ -1651,12 +1658,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>                      break;
>>>>>>
>>>>>>              case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      /* Do we need to abort the task locally? */
>>>>>>                      break;
>>>>>>
>>>>>>              default: /* device misbehavior */
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      ret = TMF_RESP_FUNC_FAILED;
>>>>>>                      PM8001_IO_DBG(pm8001_ha,
>>>>>>                              pm8001_printk("...Reset phy\n")); @@ -2504,9 +2513,11 @@
>>>>>> mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*in order to force CPU ordering*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2524,9 +2535,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2552,9 +2565,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/* ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2619,9 +2634,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2643,9 +2660,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2678,16 +2697,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>              mb();/* ditto */
>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              t->task_done(t);
>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      } else if (!t->uldd_task) {
>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>              mb();/*ditto*/
>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              t->task_done(t);
>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      }
>>>>>>  }
>>>>>>
>>>>>> @@ -2798,9 +2817,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2913,16 +2934,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>              mb();/* ditto */
>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              t->task_done(t);
>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      } else if (!t->uldd_task) {
>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>              mb();/*ditto*/
>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              t->task_done(t);
>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      }
>>>>>>  }
>>>>>>
>>>>>> @@ -4194,9 +4215,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>>      void *pMsg1 = NULL;
>>>>>>      u8 uninitialized_var(bc);
>>>>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>>>>> -    unsigned long flags;
>>>>>>
>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>>>>      do {
>>>>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>>>>> @@ -4217,7 +4237,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>>                              break;
>>>>>>              }
>>>>>>      } while (1);
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      return ret;
>>>>>>  }
>>>>>>
>>>>>> @@ -4472,18 +4492,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>>>>                                                      flags);
>>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>                              mb();/* ditto */
>>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              task->task_done(task);
>>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              return 0;
>>>>>>                      } else if (!task->uldd_task) {
>>>>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>>>>                                                      flags);
>>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>                              mb();/*ditto*/
>>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              task->task_done(task);
>>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              return 0;
>>>>>>                      }
>>>>>>              }
>>>>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.c
>>>>>> b/drivers/scsi/pm8001/pm8001_sas.c
>>>>>> index f50ac44..eac1b81 100644
>>>>>> --- a/drivers/scsi/pm8001/pm8001_sas.c
>>>>>> +++ b/drivers/scsi/pm8001/pm8001_sas.c
>>>>>> @@ -166,7 +166,6 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>>>>      struct sas_phy_linkrates *rates;
>>>>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>>>>> -    unsigned long flags;
>>>>>>      pm8001_ha = sas_phy->ha->lldd_ha;
>>>>>>      pm8001_ha->phy[phy_id].enable_completion = &completion;
>>>>>>      switch (func) {
>>>>>> @@ -211,11 +210,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>>>              PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
>>>>>>              break;
>>>>>>      case PHY_FUNC_GET_EVENTS:
>>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              if (pm8001_ha->chip_id == chip_8001) {
>>>>>>                      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>                                      (phy_id < 4) ? 0x30000 : 0x40000)) {
>>>>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              return -EINVAL;
>>>>>>                      }
>>>>>>              }
>>>>>> @@ -232,7 +232,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>>>              }
>>>>>>              if (pm8001_ha->chip_id == chip_8001)
>>>>>>                      pm8001_bar4_shift(pm8001_ha, 0);
>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              return 0;
>>>>>>      default:
>>>>>>              rc = -EOPNOTSUPP;
>>>>>> @@ -369,7 +369,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>>>      struct pm8001_ccb_info *ccb;
>>>>>>      u32 tag = 0xdeadbeef, rc, n_elem = 0;
>>>>>>      u32 n = num;
>>>>>> -    unsigned long flags = 0;
>>>>>>
>>>>>>      if (!dev->port) {
>>>>>>              struct task_status_struct *tsm = &t->task_status; @@ -380,8 +379,8
>>>>>> @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>>>              return 0;
>>>>>>      }
>>>>>>      pm8001_ha = pm8001_find_ha_by_dev(task->dev);
>>>>>> -    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device\n"));
>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      do {
>>>>>>              dev = t->dev;
>>>>>>              pm8001_dev = dev->lldd_dev;
>>>>>> @@ -392,9 +391,11 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>>>                              ts->resp = SAS_TASK_UNDELIVERED;
>>>>>>                              ts->stat = SAS_PHY_DOWN;
>>>>>>
>>>>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              t->task_done(t);
>>>>>> -                            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              if (n > 1)
>>>>>>                                      t = list_entry(t->list.next,
>>>>>>                                                      struct sas_task, list);
>>>>>> @@ -482,7 +483,7 @@ err_out:
>>>>>>                      dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
>>>>>>                              t->data_dir);
>>>>>>  out_done:
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      return rc;
>>>>>>  }
>>>>>>
>>>>>> @@ -607,7 +608,6 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
>>>>>>    */
>>>>>>  static int pm8001_dev_found_notify(struct domain_device *dev)  {
>>>>>> -    unsigned long flags = 0;
>>>>>>      int res = 0;
>>>>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>>>>      struct domain_device *parent_dev = dev->parent; @@ -615,7 +615,7 @@
>>>>>> static int pm8001_dev_found_notify(struct domain_device *dev)
>>>>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>>>>>      u32 flag = 0;
>>>>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>
>>>>>>      pm8001_device = pm8001_alloc_dev(pm8001_ha);
>>>>>>      if (!pm8001_device) {
>>>>>> @@ -654,14 +654,14 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>>>>>>      } /*register this device to HBA*/
>>>>>>      PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
>>>>>>      PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      wait_for_completion(&completion);
>>>>>>      if (dev->dev_type == SAS_END_DEVICE)
>>>>>>              msleep(50);
>>>>>>      pm8001_ha->flags = PM8001F_RUN_TIME;
>>>>>>      return 0;
>>>>>>  found_out:
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      return res;
>>>>>>  }
>>>>>>
>>>>>> @@ -864,13 +864,12 @@ ex_err:
>>>>>>    */
>>>>>>  static void pm8001_dev_gone_notify(struct domain_device *dev)  {
>>>>>> -    unsigned long flags = 0;
>>>>>>      u32 tag;
>>>>>>      struct pm8001_hba_info *pm8001_ha;
>>>>>>      struct pm8001_device *pm8001_dev = dev->lldd_dev;
>>>>>>
>>>>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      pm8001_tag_alloc(pm8001_ha, &tag);
>>>>>>      if (pm8001_dev) {
>>>>>>              u32 device_id = pm8001_dev->device_id; @@ -879,10 +878,12 @@
>>>>>> static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>>>>                      pm8001_printk("found dev[%d:%x] is gone.\n",
>>>>>>                      pm8001_dev->device_id, pm8001_dev->dev_type));
>>>>>>              if (pm8001_dev->running_req) {
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
>>>>>>                              dev, 1, 0);
>>>>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>              }
>>>>>>              PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
>>>>>>              pm8001_free_dev(pm8001_dev);
>>>>>> @@ -891,7 +892,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>>>>                      pm8001_printk("Found dev has gone.\n"));
>>>>>>      }
>>>>>>      dev->lldd_dev = NULL;
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>  }
>>>>>>
>>>>>>  void pm8001_dev_gone(struct domain_device *dev) @@ -918,12 +919,11
>>>>>> @@ void pm8001_open_reject_retry(
>>>>>>      struct pm8001_device *device_to_close)  {
>>>>>>      int i;
>>>>>> -    unsigned long flags;
>>>>>>
>>>>>>      if (pm8001_ha == NULL)
>>>>>>              return;
>>>>>>
>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>
>>>>>>      for (i = 0; i < PM8001_MAX_CCB; i++) {
>>>>>>              struct sas_task *task;
>>>>>> @@ -973,13 +973,15 @@ void pm8001_open_reject_retry(
>>>>>>                              flags1);
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>                      mb();/* in order to force CPU ordering */
>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      task->task_done(task);
>>>>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>              }
>>>>>>      }
>>>>>>
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>  }
>>>>>>
>>>>>>  /**
>>>>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.h
>>>>>> b/drivers/scsi/pm8001/pm8001_sas.h
>>>>>> index 6c5fd5e..2b8065c 100644
>>>>>> --- a/drivers/scsi/pm8001/pm8001_sas.h
>>>>>> +++ b/drivers/scsi/pm8001/pm8001_sas.h
>>>>>> @@ -475,6 +475,7 @@ struct pm8001_hba_info {
>>>>>>      struct list_head        list;
>>>>>>      unsigned long           flags;
>>>>>>      spinlock_t              lock;/* host-wide lock */
>>>>>> +    unsigned long           lock_flags;
>>>>>>      struct pci_dev          *pdev;/* our device */
>>>>>>      struct device           *dev;
>>>>>>      struct pm8001_hba_memspace io_mem[6]; diff --git
>>>>>> a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
>>>>>> index c950dc5..3ac024a 100644
>>>>>> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
>>>>>> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
>>>>>> @@ -2177,9 +2177,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*in order to force CPU ordering*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2197,9 +2199,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2223,9 +2227,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/* ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2290,9 +2296,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2314,9 +2322,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2349,16 +2359,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>              mb();/* ditto */
>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              t->task_done(t);
>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      } else if (!t->uldd_task) {
>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>              mb();/*ditto*/
>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              t->task_done(t);
>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      }
>>>>>>  }
>>>>>>
>>>>>> @@ -2472,9 +2482,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>                      mb();/*ditto*/
>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      t->task_done(t);
>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>                      return;
>>>>>>              }
>>>>>>              break;
>>>>>> @@ -2600,16 +2612,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>              mb();/* ditto */
>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              t->task_done(t);
>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      } else if (!t->uldd_task) {
>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>              mb();/*ditto*/
>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>              t->task_done(t);
>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      }
>>>>>>  }
>>>>>>
>>>>>> @@ -3705,9 +3717,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>>      void *pMsg1 = NULL;
>>>>>>      u8 uninitialized_var(bc);
>>>>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>>>>> -    unsigned long flags;
>>>>>>
>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>>>>      do {
>>>>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>>>>> @@ -3728,7 +3739,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>>                              break;
>>>>>>              }
>>>>>>      } while (1);
>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>      return ret;
>>>>>>  }
>>>>>>
>>>>>> @@ -4309,18 +4320,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>>>>                                                      flags);
>>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>                              mb();/* ditto */
>>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              task->task_done(task);
>>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              return 0;
>>>>>>                      } else if (!task->uldd_task) {
>>>>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>>>>                                                      flags);
>>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>                              mb();/*ditto*/
>>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              task->task_done(task);
>>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>                              return 0;
>>>>>>                      }
>>>>>>              }
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] pm80xx: Spinlock fix
  2013-12-23 15:33             ` Jason Seba
@ 2013-12-23 15:36               ` Tomas Henzl
  2013-12-23 16:34               ` Oleg Nesterov
  1 sibling, 0 replies; 33+ messages in thread
From: Tomas Henzl @ 2013-12-23 15:36 UTC (permalink / raw)
  To: Jason Seba
  Cc: Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, Oleg Nesterov

On 12/23/2013 04:33 PM, Jason Seba wrote:
>  Wouldn't the contents of the global flags value be protected by the
> spinlock itself?  Or is that making a dangerous assumption about the
> particulars of how spinlocks work on various platforms?

I'm not an expert but I think, that the spinlock starts by storing the 'flags'
and continues with acquiring that actual spin

>
> On Mon, Dec 23, 2013 at 10:28 AM, Tomas Henzl <thenzl@redhat.com> wrote:
>> On 12/23/2013 04:06 PM, Jack Wang wrote:
>>> On 12/23/2013 03:55 PM, Jason Seba wrote:
>>>> Why is this considered dangerous?  I put some thought into it and
>>>> couldn't find any obvious reason why it wouldn't work, but I also
>>>> couldn't find any other drivers that work this way.  Is there a
>>>> particular reason to avoid doing it this way?
>>>>
>>> If you use global flags, you may change interrupt state depends on context.
>> The problem could show up when different threads try to store different content to the flags.
>>
>>>> On Mon, Dec 23, 2013 at 8:45 AM, Suresh Thiagarajan
>>>> <Suresh.Thiagarajan@pmcs.com> wrote:
>>>>> -----Original Message-----
>>>>> From: Jack Wang [mailto:xjtuwjp@gmail.com]
>>>>> Sent: Monday, December 23, 2013 7:03 PM
>>>>> To: Tomas Henzl; Viswas G
>>>>> Cc: linux-scsi@vger.kernel.org; jason.seba42@gmail.com; JBottomley@parallels.com; Vasanthalakshmi Tharmarajan; Suresh Thiagarajan
>>>>> Subject: Re: [PATCH] pm80xx: Spinlock fix
>>>>>
>>>>> On 12/23/2013 02:07 PM, Tomas Henzl wrote:
>>>>>> On 12/18/2013 12:28 PM, Viswas G wrote:
>>>>>>> From 9338d4bc92b23b4c283f9bd6812646ab74866a40 Mon Sep 17 00:00:00
>>>>>>> 2001
>>>>>>> From: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>>>>>> Date: Mon, 16 Dec 2013 21:15:20 +0530
>>>>>>> Subject: [PATCH] pm80xx: Spinlock fix
>>>>>>>
>>>>>>> spin_unlock was used instead of spin_unlock_irqrestore. To fix this
>>>>>>> lock_flags per-adapter is added and used across all the places where pm8001_ha->lock is used.
>>>>>> I think this could have been fixed but just using spin_unlock_irqsave
>>>>>> instead of spin_unlock_irq why the change to global lock_flags?  I'm not a spinlock expert, but is this safe?
>>>>>>
>>>>> Agree with Tomas, it's dangerous to change to global lock_flags.
>>>>>
>>>>> Have you reproduce the bug reported from Jason, and verify the patch?
>>>>> I think better just to change the spin_lock_irq to spin_lock_irqsave if that is the cause.
>>>>>
>>>>> Suresh: We could not reproduce this issue and Jason(in CC) also could not reproduce it for now. spin_lock_irqsave and spin_unlock_irqrestore were called from multiple functions. Earlier flags was declared as a local variable wherever spinlock was used. This was not correct since irq information was saved in one function's flag which is a local to that function and restored in other function where again flags was declared as local variable to that function. So the data stored in flags while irq save was not used while restoring. Since we have lock per card, we are associating flag also per card for that lock.
>> Thanks, it took me a while until I have found an example - you need to unlock
>> mpi_ssp_event and the lock was taken elsewhere, so I understand it better now.
>> You know your code much better - are you sure that no other thread will be started
>> which could change the value of lock_flags?
>>
>> Tomas
>>
>>>>> -Suresh
>>>>>
>>>>> Jack
>>>>>>> Reported-by: Jason Seba <jason.seba42@gmail.com>
>>>>>>> Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
>>>>>>> Signed-off-by: Viswas G <Viswas.G@pmcs.com>
>>>>>>> ---
>>>>>>>  drivers/scsi/pm8001/pm8001_hwi.c |  158 ++++++++++++++++++++++----------------
>>>>>>>  drivers/scsi/pm8001/pm8001_sas.c |   50 ++++++------
>>>>>>>  drivers/scsi/pm8001/pm8001_sas.h |    1 +
>>>>>>>  drivers/scsi/pm8001/pm80xx_hwi.c |   69 ++++++++++-------
>>>>>>>  4 files changed, 160 insertions(+), 118 deletions(-)
>>>>>>>
>>>>>>> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c
>>>>>>> b/drivers/scsi/pm8001/pm8001_hwi.c
>>>>>>> index 0a1296a..3901c40 100644
>>>>>>> --- a/drivers/scsi/pm8001/pm8001_hwi.c
>>>>>>> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
>>>>>>> @@ -411,7 +411,6 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>>>>                                   u32 SSCbit)
>>>>>>>  {
>>>>>>>      u32 value, offset, i;
>>>>>>> -    unsigned long flags;
>>>>>>>
>>>>>>>  #define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>>>>>> SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -425,10 +424,10
>>>>>>> @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>>>>      * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
>>>>>>>      * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
>>>>>>>      */
>>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>>                              SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              return;
>>>>>>>      }
>>>>>>>
>>>>>>> @@ -439,7 +438,7 @@ static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
>>>>>>>      /* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>>                              SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              return;
>>>>>>>      }
>>>>>>>      for (i = 4; i < 8; i++) {
>>>>>>> @@ -466,7 +465,7 @@ static void mpi_set_phys_g3_with_ssc(struct
>>>>>>> pm8001_hba_info *pm8001_ha,
>>>>>>>
>>>>>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>>>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      return;
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -481,7 +480,6 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>>>>      u32 offset;
>>>>>>>      u32 value;
>>>>>>>      u32 i;
>>>>>>> -    unsigned long flags;
>>>>>>>
>>>>>>>  #define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000  #define
>>>>>>> OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000 @@ -490,11 +488,11
>>>>>>> @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info
>>>>>>> *pm8001_ha,  #define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
>>>>>>>
>>>>>>>      value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
>>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      /* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>>                           OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              return;
>>>>>>>      }
>>>>>>>      for (i = 0; i < 4; i++) {
>>>>>>> @@ -504,7 +502,7 @@ static void
>>>>>>> mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>>>>
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>>                           OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              return;
>>>>>>>      }
>>>>>>>      for (i = 4; i < 8; i++) {
>>>>>>> @@ -513,7 +511,7 @@ static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
>>>>>>>      }
>>>>>>>      /*set the shifted destination address to 0x0 to avoid error operation */
>>>>>>>      pm8001_bar4_shift(pm8001_ha, 0x0);
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      return;
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -768,11 +766,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>>>>>              PM8001_INIT_DBG(pm8001_ha,
>>>>>>>                      pm8001_printk("Firmware is ready for reset .\n"));
>>>>>>>      } else {
>>>>>>> -            unsigned long flags;
>>>>>>>              /* Trigger NMI twice via RB6 */
>>>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>>>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>>                                      RB6_ACCESS_REG));
>>>>>>> @@ -798,10 +796,11 @@ static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
>>>>>>>                      PM8001_FAIL_DBG(pm8001_ha,
>>>>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>>>>                              pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)));
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return -1;
>>>>>>>              }
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      }
>>>>>>>      return 0;
>>>>>>>  }
>>>>>>> @@ -818,7 +817,6 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>      u32     max_wait_count;
>>>>>>>      u32     regVal1, regVal2, regVal3;
>>>>>>>      u32     signature = 0x252acbcd; /* for host scratch pad0 */
>>>>>>> -    unsigned long flags;
>>>>>>>
>>>>>>>      /* step1: Check FW is ready for soft reset */
>>>>>>>      if (soft_reset_ready_check(pm8001_ha) != 0) { @@ -829,9 +827,9 @@
>>>>>>> pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>      /* step 2: clear NMI status register on AAP1 and IOP, write the same
>>>>>>>      value to clear */
>>>>>>>      /* map 0x60000 to BAR4(0x20), BAR2(win) */
>>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>>                      MBIC_AAP1_ADDR_BASE));
>>>>>>> @@ -843,7 +841,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>      pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
>>>>>>>      /* map 0x70000 to BAR4(0x20), BAR2(win) */
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>>                      MBIC_IOP_ADDR_BASE));
>>>>>>> @@ -886,7 +884,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>      /* read required registers for confirmming */
>>>>>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>>                      GSM_ADDR_BASE));
>>>>>>> @@ -953,7 +951,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>      udelay(10);
>>>>>>>      /* step 5-b: set GPIO-0 output control to tristate anyway */
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              PM8001_INIT_DBG(pm8001_ha,
>>>>>>>                              pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>>                              GPIO_ADDR_BASE));
>>>>>>> @@ -970,7 +968,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>      /* Step 6: Reset the IOP and AAP1 */
>>>>>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>>>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>>>>>> @@ -1008,7 +1006,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>      /* step 11: reads and sets the GSM Configuration and Reset Register */
>>>>>>>      /* map 0x0700000 to BAR4(0x20), BAR2(win) */
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>>                      pm8001_printk("SPC Shift Bar4 to 0x%x failed\n",
>>>>>>>                      GSM_ADDR_BASE));
>>>>>>> @@ -1062,7 +1060,7 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>      /* step 13: bring the IOP and AAP1 out of reset */
>>>>>>>      /* map 0x00000 to BAR4(0x20), BAR2(win) */
>>>>>>>      if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              PM8001_FAIL_DBG(pm8001_ha,
>>>>>>>                      pm8001_printk("Shift Bar4 to 0x%x failed\n",
>>>>>>>                      SPC_TOP_LEVEL_ADDR_BASE));
>>>>>>> @@ -1104,7 +1102,8 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>>>>                              pm8001_cr32(pm8001_ha, 0,
>>>>>>>                              MSGU_SCRATCH_PAD_3)));
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return -1;
>>>>>>>              }
>>>>>>>
>>>>>>> @@ -1134,12 +1133,13 @@ pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
>>>>>>>                              pm8001_printk("SCRATCH_PAD3 value = 0x%x\n",
>>>>>>>                              pm8001_cr32(pm8001_ha, 0,
>>>>>>>                              MSGU_SCRATCH_PAD_3)));
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return -1;
>>>>>>>              }
>>>>>>>      }
>>>>>>>      pm8001_bar4_shift(pm8001_ha, 0);
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>
>>>>>>>      PM8001_INIT_DBG(pm8001_ha,
>>>>>>>              pm8001_printk("SPC soft reset Complete\n")); @@ -1517,18 +1517,19
>>>>>>> @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>>              u32 tag;
>>>>>>>              struct pm8001_ccb_info *ccb;
>>>>>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>>>>>> -            unsigned long flags, flags1;
>>>>>>> +            unsigned long flags1;
>>>>>>>              struct task_status_struct *ts;
>>>>>>>              int i;
>>>>>>>
>>>>>>>              if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
>>>>>>>                      break; /* Task still on lu */
>>>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>
>>>>>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>>>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      break; /* Task got completed by another */
>>>>>>>              }
>>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags1); @@ -1541,7
>>>>>>> +1542,8 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>>                              break;
>>>>>>>              }
>>>>>>>              if (!ccb) {
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      break; /* Task got freed by another */
>>>>>>>              }
>>>>>>>              ts = &t->task_status;
>>>>>>> @@ -1562,12 +1564,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>>                              " aborted by upper layer!\n",
>>>>>>>                              t, pw->handler, ts->resp, ts->stat));
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>              } else {
>>>>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/* in order to force CPU ordering */
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>>              }
>>>>>>>      }       break;
>>>>>>> @@ -1577,7 +1581,7 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>>              u32 tag;
>>>>>>>              struct pm8001_ccb_info *ccb;
>>>>>>>              struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
>>>>>>> -            unsigned long flags, flags1;
>>>>>>> +            unsigned long flags1;
>>>>>>>              int i, ret = 0;
>>>>>>>
>>>>>>>              PM8001_IO_DBG(pm8001_ha,
>>>>>>> @@ -1600,13 +1604,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>>                              break;
>>>>>>>                      });
>>>>>>>
>>>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>
>>>>>>>              spin_lock_irqsave(&t->task_state_lock, flags1);
>>>>>>>
>>>>>>>              if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
>>>>>>>                      spin_unlock_irqrestore(&t->task_state_lock, flags1);
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>>>>>                              (void)pm8001_abort_task(t);
>>>>>>>                      break; /* Task got completed by another */ @@ -1622,7 +1627,8 @@
>>>>>>> void pm8001_work_fn(struct work_struct *work)
>>>>>>>                              break;
>>>>>>>              }
>>>>>>>              if (!ccb) {
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
>>>>>>>                              (void)pm8001_abort_task(t);
>>>>>>>                      break; /* Task got freed by another */ @@ -1634,7 +1640,8 @@ void
>>>>>>> pm8001_work_fn(struct work_struct *work)
>>>>>>>              switch (ret) {
>>>>>>>              case TMF_RESP_FUNC_SUCC: /* task on lu */
>>>>>>>                      ccb->open_retry = 1; /* Snub completion */
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      ret = pm8001_abort_task(t);
>>>>>>>                      ccb->open_retry = 0;
>>>>>>>                      switch (ret) {
>>>>>>> @@ -1651,12 +1658,14 @@ void pm8001_work_fn(struct work_struct *work)
>>>>>>>                      break;
>>>>>>>
>>>>>>>              case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      /* Do we need to abort the task locally? */
>>>>>>>                      break;
>>>>>>>
>>>>>>>              default: /* device misbehavior */
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      ret = TMF_RESP_FUNC_FAILED;
>>>>>>>                      PM8001_IO_DBG(pm8001_ha,
>>>>>>>                              pm8001_printk("...Reset phy\n")); @@ -2504,9 +2513,11 @@
>>>>>>> mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*in order to force CPU ordering*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2524,9 +2535,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2552,9 +2565,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/* ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2619,9 +2634,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2643,9 +2660,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2678,16 +2697,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>              mb();/* ditto */
>>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              t->task_done(t);
>>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      } else if (!t->uldd_task) {
>>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>              mb();/*ditto*/
>>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              t->task_done(t);
>>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      }
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -2798,9 +2817,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2913,16 +2934,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>              mb();/* ditto */
>>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              t->task_done(t);
>>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      } else if (!t->uldd_task) {
>>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>              mb();/*ditto*/
>>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              t->task_done(t);
>>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      }
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -4194,9 +4215,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>>>      void *pMsg1 = NULL;
>>>>>>>      u8 uninitialized_var(bc);
>>>>>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>>>>>> -    unsigned long flags;
>>>>>>>
>>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>>>>>      do {
>>>>>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>>>>>> @@ -4217,7 +4237,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>>>                              break;
>>>>>>>              }
>>>>>>>      } while (1);
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      return ret;
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -4472,18 +4492,22 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>>>>>                                                      flags);
>>>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>>                              mb();/* ditto */
>>>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              task->task_done(task);
>>>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              return 0;
>>>>>>>                      } else if (!task->uldd_task) {
>>>>>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>>>>>                                                      flags);
>>>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>>                              mb();/*ditto*/
>>>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              task->task_done(task);
>>>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              return 0;
>>>>>>>                      }
>>>>>>>              }
>>>>>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.c
>>>>>>> b/drivers/scsi/pm8001/pm8001_sas.c
>>>>>>> index f50ac44..eac1b81 100644
>>>>>>> --- a/drivers/scsi/pm8001/pm8001_sas.c
>>>>>>> +++ b/drivers/scsi/pm8001/pm8001_sas.c
>>>>>>> @@ -166,7 +166,6 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>>>>>      struct sas_phy_linkrates *rates;
>>>>>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>>>>>> -    unsigned long flags;
>>>>>>>      pm8001_ha = sas_phy->ha->lldd_ha;
>>>>>>>      pm8001_ha->phy[phy_id].enable_completion = &completion;
>>>>>>>      switch (func) {
>>>>>>> @@ -211,11 +210,12 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>>>>              PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id);
>>>>>>>              break;
>>>>>>>      case PHY_FUNC_GET_EVENTS:
>>>>>>> -            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              if (pm8001_ha->chip_id == chip_8001) {
>>>>>>>                      if (-1 == pm8001_bar4_shift(pm8001_ha,
>>>>>>>                                      (phy_id < 4) ? 0x30000 : 0x40000)) {
>>>>>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              return -EINVAL;
>>>>>>>                      }
>>>>>>>              }
>>>>>>> @@ -232,7 +232,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>>>>>>>              }
>>>>>>>              if (pm8001_ha->chip_id == chip_8001)
>>>>>>>                      pm8001_bar4_shift(pm8001_ha, 0);
>>>>>>> -            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              return 0;
>>>>>>>      default:
>>>>>>>              rc = -EOPNOTSUPP;
>>>>>>> @@ -369,7 +369,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>>>>      struct pm8001_ccb_info *ccb;
>>>>>>>      u32 tag = 0xdeadbeef, rc, n_elem = 0;
>>>>>>>      u32 n = num;
>>>>>>> -    unsigned long flags = 0;
>>>>>>>
>>>>>>>      if (!dev->port) {
>>>>>>>              struct task_status_struct *tsm = &t->task_status; @@ -380,8 +379,8
>>>>>>> @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>>>>              return 0;
>>>>>>>      }
>>>>>>>      pm8001_ha = pm8001_find_ha_by_dev(task->dev);
>>>>>>> -    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n "));
>>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +    PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device\n"));
>>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      do {
>>>>>>>              dev = t->dev;
>>>>>>>              pm8001_dev = dev->lldd_dev;
>>>>>>> @@ -392,9 +391,11 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
>>>>>>>                              ts->resp = SAS_TASK_UNDELIVERED;
>>>>>>>                              ts->stat = SAS_PHY_DOWN;
>>>>>>>
>>>>>>> -                            spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              t->task_done(t);
>>>>>>> -                            spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              if (n > 1)
>>>>>>>                                      t = list_entry(t->list.next,
>>>>>>>                                                      struct sas_task, list);
>>>>>>> @@ -482,7 +483,7 @@ err_out:
>>>>>>>                      dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem,
>>>>>>>                              t->data_dir);
>>>>>>>  out_done:
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      return rc;
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -607,7 +608,6 @@ static void pm8001_free_dev(struct pm8001_device *pm8001_dev)
>>>>>>>    */
>>>>>>>  static int pm8001_dev_found_notify(struct domain_device *dev)  {
>>>>>>> -    unsigned long flags = 0;
>>>>>>>      int res = 0;
>>>>>>>      struct pm8001_hba_info *pm8001_ha = NULL;
>>>>>>>      struct domain_device *parent_dev = dev->parent; @@ -615,7 +615,7 @@
>>>>>>> static int pm8001_dev_found_notify(struct domain_device *dev)
>>>>>>>      DECLARE_COMPLETION_ONSTACK(completion);
>>>>>>>      u32 flag = 0;
>>>>>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>
>>>>>>>      pm8001_device = pm8001_alloc_dev(pm8001_ha);
>>>>>>>      if (!pm8001_device) {
>>>>>>> @@ -654,14 +654,14 @@ static int pm8001_dev_found_notify(struct domain_device *dev)
>>>>>>>      } /*register this device to HBA*/
>>>>>>>      PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n"));
>>>>>>>      PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag);
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      wait_for_completion(&completion);
>>>>>>>      if (dev->dev_type == SAS_END_DEVICE)
>>>>>>>              msleep(50);
>>>>>>>      pm8001_ha->flags = PM8001F_RUN_TIME;
>>>>>>>      return 0;
>>>>>>>  found_out:
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      return res;
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -864,13 +864,12 @@ ex_err:
>>>>>>>    */
>>>>>>>  static void pm8001_dev_gone_notify(struct domain_device *dev)  {
>>>>>>> -    unsigned long flags = 0;
>>>>>>>      u32 tag;
>>>>>>>      struct pm8001_hba_info *pm8001_ha;
>>>>>>>      struct pm8001_device *pm8001_dev = dev->lldd_dev;
>>>>>>>
>>>>>>>      pm8001_ha = pm8001_find_ha_by_dev(dev);
>>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      pm8001_tag_alloc(pm8001_ha, &tag);
>>>>>>>      if (pm8001_dev) {
>>>>>>>              u32 device_id = pm8001_dev->device_id; @@ -879,10 +878,12 @@
>>>>>>> static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>>>>>                      pm8001_printk("found dev[%d:%x] is gone.\n",
>>>>>>>                      pm8001_dev->device_id, pm8001_dev->dev_type));
>>>>>>>              if (pm8001_dev->running_req) {
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev ,
>>>>>>>                              dev, 1, 0);
>>>>>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>              }
>>>>>>>              PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
>>>>>>>              pm8001_free_dev(pm8001_dev);
>>>>>>> @@ -891,7 +892,7 @@ static void pm8001_dev_gone_notify(struct domain_device *dev)
>>>>>>>                      pm8001_printk("Found dev has gone.\n"));
>>>>>>>      }
>>>>>>>      dev->lldd_dev = NULL;
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>  }
>>>>>>>
>>>>>>>  void pm8001_dev_gone(struct domain_device *dev) @@ -918,12 +919,11
>>>>>>> @@ void pm8001_open_reject_retry(
>>>>>>>      struct pm8001_device *device_to_close)  {
>>>>>>>      int i;
>>>>>>> -    unsigned long flags;
>>>>>>>
>>>>>>>      if (pm8001_ha == NULL)
>>>>>>>              return;
>>>>>>>
>>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>
>>>>>>>      for (i = 0; i < PM8001_MAX_CCB; i++) {
>>>>>>>              struct sas_task *task;
>>>>>>> @@ -973,13 +973,15 @@ void pm8001_open_reject_retry(
>>>>>>>                              flags1);
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>>                      mb();/* in order to force CPU ordering */
>>>>>>> -                    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      task->task_done(task);
>>>>>>> -                    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>              }
>>>>>>>      }
>>>>>>>
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>  }
>>>>>>>
>>>>>>>  /**
>>>>>>> diff --git a/drivers/scsi/pm8001/pm8001_sas.h
>>>>>>> b/drivers/scsi/pm8001/pm8001_sas.h
>>>>>>> index 6c5fd5e..2b8065c 100644
>>>>>>> --- a/drivers/scsi/pm8001/pm8001_sas.h
>>>>>>> +++ b/drivers/scsi/pm8001/pm8001_sas.h
>>>>>>> @@ -475,6 +475,7 @@ struct pm8001_hba_info {
>>>>>>>      struct list_head        list;
>>>>>>>      unsigned long           flags;
>>>>>>>      spinlock_t              lock;/* host-wide lock */
>>>>>>> +    unsigned long           lock_flags;
>>>>>>>      struct pci_dev          *pdev;/* our device */
>>>>>>>      struct device           *dev;
>>>>>>>      struct pm8001_hba_memspace io_mem[6]; diff --git
>>>>>>> a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
>>>>>>> index c950dc5..3ac024a 100644
>>>>>>> --- a/drivers/scsi/pm8001/pm80xx_hwi.c
>>>>>>> +++ b/drivers/scsi/pm8001/pm80xx_hwi.c
>>>>>>> @@ -2177,9 +2177,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*in order to force CPU ordering*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2197,9 +2199,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2223,9 +2227,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/* ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2290,9 +2296,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2314,9 +2322,11 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2349,16 +2359,16 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
>>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>              mb();/* ditto */
>>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              t->task_done(t);
>>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      } else if (!t->uldd_task) {
>>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>              mb();/*ditto*/
>>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              t->task_done(t);
>>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      }
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -2472,9 +2482,11 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>>>                      ts->stat = SAS_QUEUE_FULL;
>>>>>>>                      pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>                      mb();/*ditto*/
>>>>>>> -                    spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      t->task_done(t);
>>>>>>> -                    spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                    spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                            pm8001_ha->lock_flags);
>>>>>>>                      return;
>>>>>>>              }
>>>>>>>              break;
>>>>>>> @@ -2600,16 +2612,16 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb)
>>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>              mb();/* ditto */
>>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              t->task_done(t);
>>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      } else if (!t->uldd_task) {
>>>>>>>              spin_unlock_irqrestore(&t->task_state_lock, flags);
>>>>>>>              pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>>>>>>>              mb();/*ditto*/
>>>>>>> -            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>              t->task_done(t);
>>>>>>> -            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +            spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      }
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -3705,9 +3717,8 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>>>      void *pMsg1 = NULL;
>>>>>>>      u8 uninitialized_var(bc);
>>>>>>>      u32 ret = MPI_IO_STATUS_FAIL;
>>>>>>> -    unsigned long flags;
>>>>>>>
>>>>>>> -    spin_lock_irqsave(&pm8001_ha->lock, flags);
>>>>>>> +    spin_lock_irqsave(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      circularQ = &pm8001_ha->outbnd_q_tbl[vec];
>>>>>>>      do {
>>>>>>>              ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
>>>>>>> @@ -3728,7 +3739,7 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
>>>>>>>                              break;
>>>>>>>              }
>>>>>>>      } while (1);
>>>>>>> -    spin_unlock_irqrestore(&pm8001_ha->lock, flags);
>>>>>>> +    spin_unlock_irqrestore(&pm8001_ha->lock, pm8001_ha->lock_flags);
>>>>>>>      return ret;
>>>>>>>  }
>>>>>>>
>>>>>>> @@ -4309,18 +4320,22 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
>>>>>>>                                                      flags);
>>>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>>                              mb();/* ditto */
>>>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              task->task_done(task);
>>>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              return 0;
>>>>>>>                      } else if (!task->uldd_task) {
>>>>>>>                              spin_unlock_irqrestore(&task->task_state_lock,
>>>>>>>                                                      flags);
>>>>>>>                              pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>>>>>>>                              mb();/*ditto*/
>>>>>>> -                            spin_unlock_irq(&pm8001_ha->lock);
>>>>>>> +                            spin_unlock_irqrestore(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              task->task_done(task);
>>>>>>> -                            spin_lock_irq(&pm8001_ha->lock);
>>>>>>> +                            spin_lock_irqsave(&pm8001_ha->lock,
>>>>>>> +                                                    pm8001_ha->lock_flags);
>>>>>>>                              return 0;
>>>>>>>                      }
>>>>>>>              }
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] pm80xx: Spinlock fix
  2013-12-23 15:28           ` Tomas Henzl
  2013-12-23 15:33             ` Jason Seba
@ 2013-12-23 15:38             ` Oleg Nesterov
  1 sibling, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-23 15:38 UTC (permalink / raw)
  To: Tomas Henzl
  Cc: Jack Wang, Jason Seba, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan

On 12/23, Tomas Henzl wrote:
>
> On 12/23/2013 04:06 PM, Jack Wang wrote:
> > On 12/23/2013 03:55 PM, Jason Seba wrote:
> >> Why is this considered dangerous?  I put some thought into it and
> >> couldn't find any obvious reason why it wouldn't work, but I also
> >> couldn't find any other drivers that work this way.  Is there a
> >> particular reason to avoid doing it this way?
> >>
> > If you use global flags, you may change interrupt state depends on context.
>
> The problem could show up when different threads try to store different content to the flags.

Agreed. I have no idea if the patch is right or not, but at least
the changelog should clearly explain that only one thread can do
spin_lock_irqsave(&x->lock, x->lock_flags) at any time, otherwise
the patch (and the code) _looks_ wrong even if it is correct.

And if we can't use a local "unsigned long flags" because _unlock
can happen in another function, imho this should be mentioned in
the changelog as well.

Oleg.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [PATCH] pm80xx: Spinlock fix
  2013-12-23 15:33             ` Jason Seba
  2013-12-23 15:36               ` Tomas Henzl
@ 2013-12-23 16:34               ` Oleg Nesterov
  2013-12-23 17:27                   ` Oleg Nesterov
  1 sibling, 1 reply; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-23 16:34 UTC (permalink / raw)
  To: Jason Seba
  Cc: Tomas Henzl, Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan

On 12/23, Jason Seba wrote:
>
>  Wouldn't the contents of the global flags value be protected by the
> spinlock itself?

This can be even true because nowadays spin_lock_irqsave() writes to
"flags" after it takes the lock, and _irqrestore works gets the copy
of "flags" before it releases the lock.

Still this doesn't look safe and afaik this is not documented. Although
I have to admit that after I actually looked at the current implementation
I think this should work.

Perhaps we should ask the maintainers upstream? Even if this works, I am
not sure this is _supposed_ to work. I mean, in theory spin_lock_irqave()
can be changed as, say

	#define spin_lock_irqsave(lock, flags)		\
		do {    				\
			local_irq_save(flags);		\
			spin_lock(lock);		\
		} while (0)

(and iirc it was defined this way a long ago). In this case "flags" is
obviously not protected.

Oleg.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-23 16:34               ` Oleg Nesterov
@ 2013-12-23 17:27                   ` Oleg Nesterov
  0 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-23 17:27 UTC (permalink / raw)
  To: Jason Seba, Peter Zijlstra, Ingo Molnar, Linus Torvalds
  Cc: Tomas Henzl, Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel

On 12/23, Oleg Nesterov wrote:
>
> Perhaps we should ask the maintainers upstream? Even if this works, I am
> not sure this is _supposed_ to work. I mean, in theory spin_lock_irqave()
> can be changed as, say
>
> 	#define spin_lock_irqsave(lock, flags)		\
> 		do {    				\
> 			local_irq_save(flags);		\
> 			spin_lock(lock);		\
> 		} while (0)
>
> (and iirc it was defined this way a long ago). In this case "flags" is
> obviously not protected.

Yes, lets ask the maintainers.

In short, is this code

	spinlock_t LOCK;
	unsigned long FLAGS;

	void my_lock(void)
	{
		spin_lock_irqsave(&LOCK, FLAGS);
	}

	void my_unlock(void)
	{
		spin_unlock_irqrestore(&LOCK, FLAGS);
	}

correct or not?

Initially I thought that this is obviously wrong, irqsave/irqrestore
assume that "flags" is owned by the caller, not by the lock. And iirc
this was certainly wrong in the past.

But when I look at spinlock.c it seems that this code can actually work.
_irqsave() writes to FLAGS after it takes the lock, and _irqrestore()
has a copy of FLAGS before it drops this lock.

And it turns out, some users assume this should work, for example

	arch/arm/mach-omap2/powerdomain.c:
		pwrdm_lock() and pwrdm_unlock()

	drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c:
		brcmf_fws_lock() and brcmf_fws_unlock()

seem to do exactly this. Plus the pending patch for drivers/scsi/pm8001/.

So is it documented somewhere that this sequence is correct, or the code
above should be changed even if it happens to work?

Oleg.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2013-12-23 17:27                   ` Oleg Nesterov
  0 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-23 17:27 UTC (permalink / raw)
  To: Jason Seba, Peter Zijlstra, Ingo Molnar, Linus Torvalds
  Cc: Tomas Henzl, Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel

On 12/23, Oleg Nesterov wrote:
>
> Perhaps we should ask the maintainers upstream? Even if this works, I am
> not sure this is _supposed_ to work. I mean, in theory spin_lock_irqave()
> can be changed as, say
>
> 	#define spin_lock_irqsave(lock, flags)		\
> 		do {    				\
> 			local_irq_save(flags);		\
> 			spin_lock(lock);		\
> 		} while (0)
>
> (and iirc it was defined this way a long ago). In this case "flags" is
> obviously not protected.

Yes, lets ask the maintainers.

In short, is this code

	spinlock_t LOCK;
	unsigned long FLAGS;

	void my_lock(void)
	{
		spin_lock_irqsave(&LOCK, FLAGS);
	}

	void my_unlock(void)
	{
		spin_unlock_irqrestore(&LOCK, FLAGS);
	}

correct or not?

Initially I thought that this is obviously wrong, irqsave/irqrestore
assume that "flags" is owned by the caller, not by the lock. And iirc
this was certainly wrong in the past.

But when I look at spinlock.c it seems that this code can actually work.
_irqsave() writes to FLAGS after it takes the lock, and _irqrestore()
has a copy of FLAGS before it drops this lock.

And it turns out, some users assume this should work, for example

	arch/arm/mach-omap2/powerdomain.c:
		pwrdm_lock() and pwrdm_unlock()

	drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c:
		brcmf_fws_lock() and brcmf_fws_unlock()

seem to do exactly this. Plus the pending patch for drivers/scsi/pm8001/.

So is it documented somewhere that this sequence is correct, or the code
above should be changed even if it happens to work?

Oleg.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-23 17:27                   ` Oleg Nesterov
@ 2013-12-23 18:12                     ` Linus Torvalds
  -1 siblings, 0 replies; 33+ messages in thread
From: Linus Torvalds @ 2013-12-23 18:12 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Tomas Henzl, Jack Wang,
	Suresh Thiagarajan, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, Linux Kernel Mailing List

On Mon, Dec 23, 2013 at 9:27 AM, Oleg Nesterov <oleg@redhat.com> wrote:
>
> In short, is this code
>
>         spinlock_t LOCK;
>         unsigned long FLAGS;
>
>         void my_lock(void)
>         {
>                 spin_lock_irqsave(&LOCK, FLAGS);
>         }
>
>         void my_unlock(void)
>         {
>                 spin_unlock_irqrestore(&LOCK, FLAGS);
>         }
>
> correct or not?

Hell no. "flags" needs to be a thread-private variable, or at least
protected some way (ie the above could work if everything is inside a
bigger lock, to serialize access to FLAGS).

                    Linus

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2013-12-23 18:12                     ` Linus Torvalds
  0 siblings, 0 replies; 33+ messages in thread
From: Linus Torvalds @ 2013-12-23 18:12 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Tomas Henzl, Jack Wang,
	Suresh Thiagarajan, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, Linux Kernel Mailing List

On Mon, Dec 23, 2013 at 9:27 AM, Oleg Nesterov <oleg@redhat.com> wrote:
>
> In short, is this code
>
>         spinlock_t LOCK;
>         unsigned long FLAGS;
>
>         void my_lock(void)
>         {
>                 spin_lock_irqsave(&LOCK, FLAGS);
>         }
>
>         void my_unlock(void)
>         {
>                 spin_unlock_irqrestore(&LOCK, FLAGS);
>         }
>
> correct or not?

Hell no. "flags" needs to be a thread-private variable, or at least
protected some way (ie the above could work if everything is inside a
bigger lock, to serialize access to FLAGS).

                    Linus

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-23 17:27                   ` Oleg Nesterov
@ 2013-12-23 18:23                     ` Ingo Molnar
  -1 siblings, 0 replies; 33+ messages in thread
From: Ingo Molnar @ 2013-12-23 18:23 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Linus Torvalds,
	Tomas Henzl, Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel


* Oleg Nesterov <oleg@redhat.com> wrote:

> On 12/23, Oleg Nesterov wrote:
> >
> > Perhaps we should ask the maintainers upstream? Even if this works, I am
> > not sure this is _supposed_ to work. I mean, in theory spin_lock_irqave()
> > can be changed as, say
> >
> > 	#define spin_lock_irqsave(lock, flags)		\
> > 		do {    				\
> > 			local_irq_save(flags);		\
> > 			spin_lock(lock);		\
> > 		} while (0)
> >
> > (and iirc it was defined this way a long ago). In this case "flags" is
> > obviously not protected.
> 
> Yes, lets ask the maintainers.
> 
> In short, is this code
> 
> 	spinlock_t LOCK;
> 	unsigned long FLAGS;
> 
> 	void my_lock(void)
> 	{
> 		spin_lock_irqsave(&LOCK, FLAGS);
> 	}
> 
> 	void my_unlock(void)
> 	{
> 		spin_unlock_irqrestore(&LOCK, FLAGS);
> 	}
> 
> correct or not?
> 
> Initially I thought that this is obviously wrong, irqsave/irqrestore 
> assume that "flags" is owned by the caller, not by the lock. And 
> iirc this was certainly wrong in the past.
> 
> But when I look at spinlock.c it seems that this code can actually 
> work. _irqsave() writes to FLAGS after it takes the lock, and 
> _irqrestore() has a copy of FLAGS before it drops this lock.

I don't think that's true: if it was then the lock would not be 
irqsave, a hardware-irq could come in after the lock has been taken 
and before flags are saved+disabled.

So AFAICS this is an unsafe pattern, beyond being ugly as hell.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2013-12-23 18:23                     ` Ingo Molnar
  0 siblings, 0 replies; 33+ messages in thread
From: Ingo Molnar @ 2013-12-23 18:23 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Linus Torvalds,
	Tomas Henzl, Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel


* Oleg Nesterov <oleg@redhat.com> wrote:

> On 12/23, Oleg Nesterov wrote:
> >
> > Perhaps we should ask the maintainers upstream? Even if this works, I am
> > not sure this is _supposed_ to work. I mean, in theory spin_lock_irqave()
> > can be changed as, say
> >
> > 	#define spin_lock_irqsave(lock, flags)		\
> > 		do {    				\
> > 			local_irq_save(flags);		\
> > 			spin_lock(lock);		\
> > 		} while (0)
> >
> > (and iirc it was defined this way a long ago). In this case "flags" is
> > obviously not protected.
> 
> Yes, lets ask the maintainers.
> 
> In short, is this code
> 
> 	spinlock_t LOCK;
> 	unsigned long FLAGS;
> 
> 	void my_lock(void)
> 	{
> 		spin_lock_irqsave(&LOCK, FLAGS);
> 	}
> 
> 	void my_unlock(void)
> 	{
> 		spin_unlock_irqrestore(&LOCK, FLAGS);
> 	}
> 
> correct or not?
> 
> Initially I thought that this is obviously wrong, irqsave/irqrestore 
> assume that "flags" is owned by the caller, not by the lock. And 
> iirc this was certainly wrong in the past.
> 
> But when I look at spinlock.c it seems that this code can actually 
> work. _irqsave() writes to FLAGS after it takes the lock, and 
> _irqrestore() has a copy of FLAGS before it drops this lock.

I don't think that's true: if it was then the lock would not be 
irqsave, a hardware-irq could come in after the lock has been taken 
and before flags are saved+disabled.

So AFAICS this is an unsafe pattern, beyond being ugly as hell.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-23 18:12                     ` Linus Torvalds
@ 2013-12-23 18:24                       ` Oleg Nesterov
  -1 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-23 18:24 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Tomas Henzl, Jack Wang,
	Suresh Thiagarajan, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, Linux Kernel Mailing List

On 12/23, Linus Torvalds wrote:
>
> On Mon, Dec 23, 2013 at 9:27 AM, Oleg Nesterov <oleg@redhat.com> wrote:
> >
> > In short, is this code
> >
> >         spinlock_t LOCK;
> >         unsigned long FLAGS;
> >
> >         void my_lock(void)
> >         {
> >                 spin_lock_irqsave(&LOCK, FLAGS);
> >         }
> >
> >         void my_unlock(void)
> >         {
> >                 spin_unlock_irqrestore(&LOCK, FLAGS);
> >         }
> >
> > correct or not?
>
> Hell no. "flags" needs to be a thread-private variable, or at least
> protected some way (ie the above could work if everything is inside a
> bigger lock, to serialize access to FLAGS).

This was my understanding (although, once again, it seems to me this can
suprisingly work with the current implementation).

However, the code above already has the users. Do you think it makes
sense to add something like

	void spinlock_irqsave_careful(spinlock_t *lock, unsigned long *flags)
	{
		unsigned long _flags;
		spinlock_irqsave(lock, _flags);
		*flags = flags;
	}

	void spinlock_irqrestore_careful(spinlock_t *lock, unsigned long *flags)
	{
		unsigned long _flags = *flags;
		spinlock_irqrestore(lock, _flags);
	}

into include/linux/spinlock.h ?

Oleg.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2013-12-23 18:24                       ` Oleg Nesterov
  0 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-23 18:24 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Tomas Henzl, Jack Wang,
	Suresh Thiagarajan, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, Linux Kernel Mailing List

On 12/23, Linus Torvalds wrote:
>
> On Mon, Dec 23, 2013 at 9:27 AM, Oleg Nesterov <oleg@redhat.com> wrote:
> >
> > In short, is this code
> >
> >         spinlock_t LOCK;
> >         unsigned long FLAGS;
> >
> >         void my_lock(void)
> >         {
> >                 spin_lock_irqsave(&LOCK, FLAGS);
> >         }
> >
> >         void my_unlock(void)
> >         {
> >                 spin_unlock_irqrestore(&LOCK, FLAGS);
> >         }
> >
> > correct or not?
>
> Hell no. "flags" needs to be a thread-private variable, or at least
> protected some way (ie the above could work if everything is inside a
> bigger lock, to serialize access to FLAGS).

This was my understanding (although, once again, it seems to me this can
suprisingly work with the current implementation).

However, the code above already has the users. Do you think it makes
sense to add something like

	void spinlock_irqsave_careful(spinlock_t *lock, unsigned long *flags)
	{
		unsigned long _flags;
		spinlock_irqsave(lock, _flags);
		*flags = flags;
	}

	void spinlock_irqrestore_careful(spinlock_t *lock, unsigned long *flags)
	{
		unsigned long _flags = *flags;
		spinlock_irqrestore(lock, _flags);
	}

into include/linux/spinlock.h ?

Oleg.

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-23 18:23                     ` Ingo Molnar
@ 2013-12-23 18:33                       ` Oleg Nesterov
  -1 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-23 18:33 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Linus Torvalds,
	Tomas Henzl, Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel

On 12/23, Ingo Molnar wrote:
>
> * Oleg Nesterov <oleg@redhat.com> wrote:
>
> > Initially I thought that this is obviously wrong, irqsave/irqrestore
> > assume that "flags" is owned by the caller, not by the lock. And
> > iirc this was certainly wrong in the past.
> >
> > But when I look at spinlock.c it seems that this code can actually
> > work. _irqsave() writes to FLAGS after it takes the lock, and
> > _irqrestore() has a copy of FLAGS before it drops this lock.
>
> I don't think that's true: if it was then the lock would not be
> irqsave, a hardware-irq could come in after the lock has been taken
> and before flags are saved+disabled.

I do agree that this pattern is not safe, that is why I decided to ask.

But, unless I missed something, with the current implementation
spin_lock_irqsave(lock, global_flags) does:

	unsigned long local_flags;

	local_irq_save(local_flags);
	spin_lock(lock);

	global_flags = local_flags;

so the access to global_flags is actually serialized by lock.

> So AFAICS this is an unsafe pattern, beyond being ugly as hell.

Yes, I think the same.

Oleg.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2013-12-23 18:33                       ` Oleg Nesterov
  0 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-23 18:33 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Linus Torvalds,
	Tomas Henzl, Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel

On 12/23, Ingo Molnar wrote:
>
> * Oleg Nesterov <oleg@redhat.com> wrote:
>
> > Initially I thought that this is obviously wrong, irqsave/irqrestore
> > assume that "flags" is owned by the caller, not by the lock. And
> > iirc this was certainly wrong in the past.
> >
> > But when I look at spinlock.c it seems that this code can actually
> > work. _irqsave() writes to FLAGS after it takes the lock, and
> > _irqrestore() has a copy of FLAGS before it drops this lock.
>
> I don't think that's true: if it was then the lock would not be
> irqsave, a hardware-irq could come in after the lock has been taken
> and before flags are saved+disabled.

I do agree that this pattern is not safe, that is why I decided to ask.

But, unless I missed something, with the current implementation
spin_lock_irqsave(lock, global_flags) does:

	unsigned long local_flags;

	local_irq_save(local_flags);
	spin_lock(lock);

	global_flags = local_flags;

so the access to global_flags is actually serialized by lock.

> So AFAICS this is an unsafe pattern, beyond being ugly as hell.

Yes, I think the same.

Oleg.


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-23 18:24                       ` Oleg Nesterov
@ 2013-12-23 18:43                         ` Linus Torvalds
  -1 siblings, 0 replies; 33+ messages in thread
From: Linus Torvalds @ 2013-12-23 18:43 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Tomas Henzl, Jack Wang,
	Suresh Thiagarajan, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, Linux Kernel Mailing List

On Mon, Dec 23, 2013 at 10:24 AM, Oleg Nesterov <oleg@redhat.com> wrote:
>
> However, the code above already has the users. Do you think it makes
> sense to add something like

No. I think it makes sense to put a big warning on any users you find,
and fart in the general direction of any developer who did that broken
pattern.

Because code like that is obviously crap.

                Linus

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2013-12-23 18:43                         ` Linus Torvalds
  0 siblings, 0 replies; 33+ messages in thread
From: Linus Torvalds @ 2013-12-23 18:43 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Tomas Henzl, Jack Wang,
	Suresh Thiagarajan, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, Linux Kernel Mailing List

On Mon, Dec 23, 2013 at 10:24 AM, Oleg Nesterov <oleg@redhat.com> wrote:
>
> However, the code above already has the users. Do you think it makes
> sense to add something like

No. I think it makes sense to put a big warning on any users you find,
and fart in the general direction of any developer who did that broken
pattern.

Because code like that is obviously crap.

                Linus

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-23 18:33                       ` Oleg Nesterov
@ 2013-12-24  8:29                         ` Ingo Molnar
  -1 siblings, 0 replies; 33+ messages in thread
From: Ingo Molnar @ 2013-12-24  8:29 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Linus Torvalds,
	Tomas Henzl, Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel


* Oleg Nesterov <oleg@redhat.com> wrote:

> On 12/23, Ingo Molnar wrote:
> >
> > * Oleg Nesterov <oleg@redhat.com> wrote:
> >
> > > Initially I thought that this is obviously wrong, irqsave/irqrestore
> > > assume that "flags" is owned by the caller, not by the lock. And
> > > iirc this was certainly wrong in the past.
> > >
> > > But when I look at spinlock.c it seems that this code can actually
> > > work. _irqsave() writes to FLAGS after it takes the lock, and
> > > _irqrestore() has a copy of FLAGS before it drops this lock.
> >
> > I don't think that's true: if it was then the lock would not be
> > irqsave, a hardware-irq could come in after the lock has been taken
> > and before flags are saved+disabled.
> 
> I do agree that this pattern is not safe, that is why I decided to ask.
> 
> But, unless I missed something, with the current implementation
> spin_lock_irqsave(lock, global_flags) does:
> 
> 	unsigned long local_flags;
> 
> 	local_irq_save(local_flags);
> 	spin_lock(lock);
> 
> 	global_flags = local_flags;
> 
> so the access to global_flags is actually serialized by lock.

You are right, today that's true technically because IIRC due to Sparc 
quirks we happen to return 'flags' as a return value - still it's very 
ugly and it could break anytime if we decide to do more aggressive 
optimizations and actually directly save into 'flags'.

Note that even today there's a narrow exception: on UP we happen to 
build it the other way around, so that we do:

	local_irq_save(global_flags);
	__acquire(lock);

This does not matter for any real code because on UP there is no 
physical lock and __acquire() is empty code-wise, but any compiler 
driven locking analysis tool using __attribute__ __context__(), if 
built on UP, would see the unsafe locking pattern.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2013-12-24  8:29                         ` Ingo Molnar
  0 siblings, 0 replies; 33+ messages in thread
From: Ingo Molnar @ 2013-12-24  8:29 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Linus Torvalds,
	Tomas Henzl, Jack Wang, Suresh Thiagarajan, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel


* Oleg Nesterov <oleg@redhat.com> wrote:

> On 12/23, Ingo Molnar wrote:
> >
> > * Oleg Nesterov <oleg@redhat.com> wrote:
> >
> > > Initially I thought that this is obviously wrong, irqsave/irqrestore
> > > assume that "flags" is owned by the caller, not by the lock. And
> > > iirc this was certainly wrong in the past.
> > >
> > > But when I look at spinlock.c it seems that this code can actually
> > > work. _irqsave() writes to FLAGS after it takes the lock, and
> > > _irqrestore() has a copy of FLAGS before it drops this lock.
> >
> > I don't think that's true: if it was then the lock would not be
> > irqsave, a hardware-irq could come in after the lock has been taken
> > and before flags are saved+disabled.
> 
> I do agree that this pattern is not safe, that is why I decided to ask.
> 
> But, unless I missed something, with the current implementation
> spin_lock_irqsave(lock, global_flags) does:
> 
> 	unsigned long local_flags;
> 
> 	local_irq_save(local_flags);
> 	spin_lock(lock);
> 
> 	global_flags = local_flags;
> 
> so the access to global_flags is actually serialized by lock.

You are right, today that's true technically because IIRC due to Sparc 
quirks we happen to return 'flags' as a return value - still it's very 
ugly and it could break anytime if we decide to do more aggressive 
optimizations and actually directly save into 'flags'.

Note that even today there's a narrow exception: on UP we happen to 
build it the other way around, so that we do:

	local_irq_save(global_flags);
	__acquire(lock);

This does not matter for any real code because on UP there is no 
physical lock and __acquire() is empty code-wise, but any compiler 
driven locking analysis tool using __attribute__ __context__(), if 
built on UP, would see the unsafe locking pattern.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 33+ messages in thread

* RE: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-24  8:29                         ` Ingo Molnar
  (?)
@ 2013-12-24  9:13                         ` Suresh Thiagarajan
  2013-12-24 17:29                             ` James Bottomley
  2013-12-27 16:18                             ` Oleg Nesterov
  -1 siblings, 2 replies; 33+ messages in thread
From: Suresh Thiagarajan @ 2013-12-24  9:13 UTC (permalink / raw)
  To: Ingo Molnar, Oleg Nesterov
  Cc: Jason Seba, Peter Zijlstra, Ingo Molnar, Linus Torvalds,
	Tomas Henzl, Jack Wang, Viswas G, linux-scsi, JBottomley,
	Vasanthalakshmi Tharmarajan, linux-kernel



On Tue, Dec 24, 2013 at 1:59 PM, Ingo Molnar <mingo@kernel.org> wrote:
>
> * Oleg Nesterov <oleg@redhat.com> wrote:
>
>> On 12/23, Ingo Molnar wrote:
>> >
>> > * Oleg Nesterov <oleg@redhat.com> wrote:
>> >
>> > > Initially I thought that this is obviously wrong, irqsave/irqrestore
>> > > assume that "flags" is owned by the caller, not by the lock. And
>> > > iirc this was certainly wrong in the past.
>> > >
>> > > But when I look at spinlock.c it seems that this code can actually
>> > > work. _irqsave() writes to FLAGS after it takes the lock, and
>> > > _irqrestore() has a copy of FLAGS before it drops this lock.
>> >
>> > I don't think that's true: if it was then the lock would not be
>> > irqsave, a hardware-irq could come in after the lock has been taken
>> > and before flags are saved+disabled.
>>
>> I do agree that this pattern is not safe, that is why I decided to ask.
>>
>> But, unless I missed something, with the current implementation
>> spin_lock_irqsave(lock, global_flags) does:
>>
>>       unsigned long local_flags;
>>
>>       local_irq_save(local_flags);
>>       spin_lock(lock);
>>
>>       global_flags = local_flags;
>>
>> so the access to global_flags is actually serialized by lock.

Below is a small pseudo code on protecting/serializing the flag for global access.
struct temp
{
	...
	spinlock_t lock;
	unsigned long lock_flags;
};
void my_lock(struct temp *t)
{
               unsigned long flag; // thread-private variable as suggested
               spin_lock_irqsave(&t->lock, flag);
               t->lock_flags = flag; //updating inside critical section now to serialize the access to flag
}

void my_unlock(struct temp *t)
{
               unsigned long flag = t->lock_flags;
               t->lock_flags = 0;  //clearing it before getting out of critical section
               spin_unlock_irqrestore(&t->lock, flag);
}

Here for unlocking, I could even use spin_unlock_irqrestore(&t->lock, t->lock_flags) directly instead of my_unlock() since t->lock_flags is updated only in my_lock and so there is no need to explicitly clear t->lock_flags. Please let me know if I miss anything here in serializing the global lock flag.

Thanks,
Suresh
>
> You are right, today that's true technically because IIRC due to Sparc
> quirks we happen to return 'flags' as a return value - still it's very
> ugly and it could break anytime if we decide to do more aggressive
> optimizations and actually directly save into 'flags'.
>
> Note that even today there's a narrow exception: on UP we happen to
> build it the other way around, so that we do:
>
>         local_irq_save(global_flags);
>         __acquire(lock);
>
> This does not matter for any real code because on UP there is no
> physical lock and __acquire() is empty code-wise, but any compiler
> driven locking analysis tool using __attribute__ __context__(), if
> built on UP, would see the unsafe locking pattern.
>
> Thanks,
>
>         Ingo
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-24  9:13                         ` Suresh Thiagarajan
@ 2013-12-24 17:29                             ` James Bottomley
  2013-12-27 16:18                             ` Oleg Nesterov
  1 sibling, 0 replies; 33+ messages in thread
From: James Bottomley @ 2013-12-24 17:29 UTC (permalink / raw)
  To: Suresh Thiagarajan
  Cc: Ingo Molnar, Oleg Nesterov, Jason Seba, Peter Zijlstra,
	Ingo Molnar, Linus Torvalds, Tomas Henzl, Jack Wang, Viswas G,
	linux-scsi, Vasanthalakshmi Tharmarajan, linux-kernel

On Tue, 2013-12-24 at 09:13 +0000, Suresh Thiagarajan wrote:
> 
> On Tue, Dec 24, 2013 at 1:59 PM, Ingo Molnar <mingo@kernel.org> wrote:
> >
> > * Oleg Nesterov <oleg@redhat.com> wrote:
> >
> >> On 12/23, Ingo Molnar wrote:
> >> >
> >> > * Oleg Nesterov <oleg@redhat.com> wrote:
> >> >
> >> > > Initially I thought that this is obviously wrong, irqsave/irqrestore
> >> > > assume that "flags" is owned by the caller, not by the lock. And
> >> > > iirc this was certainly wrong in the past.
> >> > >
> >> > > But when I look at spinlock.c it seems that this code can actually
> >> > > work. _irqsave() writes to FLAGS after it takes the lock, and
> >> > > _irqrestore() has a copy of FLAGS before it drops this lock.
> >> >
> >> > I don't think that's true: if it was then the lock would not be
> >> > irqsave, a hardware-irq could come in after the lock has been taken
> >> > and before flags are saved+disabled.
> >>
> >> I do agree that this pattern is not safe, that is why I decided to ask.
> >>
> >> But, unless I missed something, with the current implementation
> >> spin_lock_irqsave(lock, global_flags) does:
> >>
> >>       unsigned long local_flags;
> >>
> >>       local_irq_save(local_flags);
> >>       spin_lock(lock);
> >>
> >>       global_flags = local_flags;
> >>
> >> so the access to global_flags is actually serialized by lock.
> 
> Below is a small pseudo code on protecting/serializing the flag for global access.
> struct temp
> {
> 	...
> 	spinlock_t lock;
> 	unsigned long lock_flags;
> };
> void my_lock(struct temp *t)
> {
>                unsigned long flag; // thread-private variable as suggested
>                spin_lock_irqsave(&t->lock, flag);
>                t->lock_flags = flag; //updating inside critical section now to serialize the access to flag
> }
> 
> void my_unlock(struct temp *t)
> {
>                unsigned long flag = t->lock_flags;
>                t->lock_flags = 0;  //clearing it before getting out of critical section
>                spin_unlock_irqrestore(&t->lock, flag);
> }
> 
> Here for unlocking, I could even use spin_unlock_irqrestore(&t->lock,
> t->lock_flags) directly instead of my_unlock() since t->lock_flags is
> updated only in my_lock and so there is no need to explicitly clear
> t->lock_flags. Please let me know if I miss anything here in
> serializing the global lock flag.

I don't think anyone's arguing that you can't do this.  The argument is
more you shouldn't: Lock contention is one of the biggest killers of
performance and getting locking right (avoiding inversions, or even
nested locks at all) is hard.  Therefore you need to keep the shortest
and clearest critical sections in Linux that you can, so the pattern for
locking is to lock and unlock in the same routine with a local flags
variable.

So, rather than develop a primitive that supports and encourages uses of
locking that violate the pattern and is far more likely to cause
performance and other problems, could you just audit the code to see if
the need to carry a lock across a routine could be eliminated (either by
shortening the critical section or by better nesting the calls).

Thanks,

James



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2013-12-24 17:29                             ` James Bottomley
  0 siblings, 0 replies; 33+ messages in thread
From: James Bottomley @ 2013-12-24 17:29 UTC (permalink / raw)
  To: Suresh Thiagarajan
  Cc: Ingo Molnar, Oleg Nesterov, Jason Seba, Peter Zijlstra,
	Ingo Molnar, Linus Torvalds, Tomas Henzl, Jack Wang, Viswas G,
	linux-scsi, Vasanthalakshmi Tharmarajan, linux-kernel

On Tue, 2013-12-24 at 09:13 +0000, Suresh Thiagarajan wrote:
> 
> On Tue, Dec 24, 2013 at 1:59 PM, Ingo Molnar <mingo@kernel.org> wrote:
> >
> > * Oleg Nesterov <oleg@redhat.com> wrote:
> >
> >> On 12/23, Ingo Molnar wrote:
> >> >
> >> > * Oleg Nesterov <oleg@redhat.com> wrote:
> >> >
> >> > > Initially I thought that this is obviously wrong, irqsave/irqrestore
> >> > > assume that "flags" is owned by the caller, not by the lock. And
> >> > > iirc this was certainly wrong in the past.
> >> > >
> >> > > But when I look at spinlock.c it seems that this code can actually
> >> > > work. _irqsave() writes to FLAGS after it takes the lock, and
> >> > > _irqrestore() has a copy of FLAGS before it drops this lock.
> >> >
> >> > I don't think that's true: if it was then the lock would not be
> >> > irqsave, a hardware-irq could come in after the lock has been taken
> >> > and before flags are saved+disabled.
> >>
> >> I do agree that this pattern is not safe, that is why I decided to ask.
> >>
> >> But, unless I missed something, with the current implementation
> >> spin_lock_irqsave(lock, global_flags) does:
> >>
> >>       unsigned long local_flags;
> >>
> >>       local_irq_save(local_flags);
> >>       spin_lock(lock);
> >>
> >>       global_flags = local_flags;
> >>
> >> so the access to global_flags is actually serialized by lock.
> 
> Below is a small pseudo code on protecting/serializing the flag for global access.
> struct temp
> {
> 	...
> 	spinlock_t lock;
> 	unsigned long lock_flags;
> };
> void my_lock(struct temp *t)
> {
>                unsigned long flag; // thread-private variable as suggested
>                spin_lock_irqsave(&t->lock, flag);
>                t->lock_flags = flag; //updating inside critical section now to serialize the access to flag
> }
> 
> void my_unlock(struct temp *t)
> {
>                unsigned long flag = t->lock_flags;
>                t->lock_flags = 0;  //clearing it before getting out of critical section
>                spin_unlock_irqrestore(&t->lock, flag);
> }
> 
> Here for unlocking, I could even use spin_unlock_irqrestore(&t->lock,
> t->lock_flags) directly instead of my_unlock() since t->lock_flags is
> updated only in my_lock and so there is no need to explicitly clear
> t->lock_flags. Please let me know if I miss anything here in
> serializing the global lock flag.

I don't think anyone's arguing that you can't do this.  The argument is
more you shouldn't: Lock contention is one of the biggest killers of
performance and getting locking right (avoiding inversions, or even
nested locks at all) is hard.  Therefore you need to keep the shortest
and clearest critical sections in Linux that you can, so the pattern for
locking is to lock and unlock in the same routine with a local flags
variable.

So, rather than develop a primitive that supports and encourages uses of
locking that violate the pattern and is far more likely to cause
performance and other problems, could you just audit the code to see if
the need to carry a lock across a routine could be eliminated (either by
shortening the critical section or by better nesting the calls).

Thanks,

James

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-24  9:13                         ` Suresh Thiagarajan
@ 2013-12-27 16:18                             ` Oleg Nesterov
  2013-12-27 16:18                             ` Oleg Nesterov
  1 sibling, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-27 16:18 UTC (permalink / raw)
  To: Suresh Thiagarajan
  Cc: Ingo Molnar, Jason Seba, Peter Zijlstra, Ingo Molnar,
	Linus Torvalds, Tomas Henzl, Jack Wang, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel

On 12/24, Suresh Thiagarajan wrote:
>
> Below is a small pseudo code on protecting/serializing the flag for global access.
> struct temp
> {
> 	...
> 	spinlock_t lock;
> 	unsigned long lock_flags;
> };
> void my_lock(struct temp *t)
> {
>                unsigned long flag; // thread-private variable as suggested
>                spin_lock_irqsave(&t->lock, flag);
>                t->lock_flags = flag; //updating inside critical section now to serialize the access to flag
> }
>
> void my_unlock(struct temp *t)
> {
>                unsigned long flag = t->lock_flags;
>                t->lock_flags = 0;  //clearing it before getting out of critical section
>                spin_unlock_irqrestore(&t->lock, flag);
> }

Yes, this should work as a quick fix. And you do not need to clear ->lock_flags
in my_unlock().

But when I look at original patch again, I no longer understand why do
you need pm8001_ha->lock_flags at all. Of course I do not understand this
code, I am sure I missed something, but at first glance it seems that only
this sequence

	spin_unlock_irq(&pm8001_ha->lock);
	t->task_done(t);
	spin_lock_irq(&pm8001_ha->lock);

should be fixed?

If yes, why you can't simply do spin_unlock() + spin_lock() around
t->task_done() ? This won't enable irqs, but spin_unlock_irqrestore()
doesn't necessarily enables irqs too, so ->task_done() can run with
irqs disabled?

And note that the pattern above has a lot of users, perhaps it makes
sense to start with something like the patch below?

Hmm. there is another oddity in this code, for example mpi_sata_completion()
does

	} else if (t->uldd_task) {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
		mb();/* ditto */
		spin_unlock_irq(&pm8001_ha->lock);
		t->task_done(t);
		spin_lock_irq(&pm8001_ha->lock);
	} else if (!t->uldd_task) {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
		mb();/*ditto*/
		spin_unlock_irq(&pm8001_ha->lock);
		t->task_done(t);
		spin_lock_irq(&pm8001_ha->lock);
	}

and both branches do the same code? mpi_sata_event(), pm8001_chip_sata_req()
too.

Imho, whatever you do, the changelog should tell more.

Oleg.


--- x/drivers/scsi/pm8001/pm8001_sas.h
+++ x/drivers/scsi/pm8001/pm8001_sas.h
@@ -619,6 +619,20 @@ u32 pm8001_get_ncq_tag(struct sas_task *
 void pm8001_ccb_free(struct pm8001_hba_info *pm8001_ha, u32 ccb_idx);
 void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
 	struct sas_task *task, struct pm8001_ccb_info *ccb, u32 ccb_idx);
+
+static inline void
+pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
+			struct sas_task *task, struct pm8001_ccb_info *ccb,
+			u32 ccb_idx)
+{
+	pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb_idx);
+	smp_mb(); /* comment */
+	spin_unlock(&pm8001_ha->lock);
+	task->task_done(task);
+	spin_lock(&pm8001_ha->lock);
+}
+
+
 int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
 	void *funcdata);
 void pm8001_scan_start(struct Scsi_Host *shost);
--- x/drivers/scsi/pm8001/pm8001_hwi.c
+++ x/drivers/scsi/pm8001/pm8001_hwi.c
@@ -2502,11 +2502,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*in order to force CPU ordering*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2522,11 +2518,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2550,11 +2542,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/* ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2617,11 +2605,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				    IO_DS_NON_OPERATIONAL);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2641,11 +2625,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				    IO_DS_IN_ERROR);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2674,20 +2654,9 @@ mpi_sata_completion(struct pm8001_hba_in
 			" resp 0x%x stat 0x%x but aborted by upper layer!\n",
 			t, status, ts->resp, ts->stat));
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-	} else if (t->uldd_task) {
-		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
-	} else if (!t->uldd_task) {
+	} else {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 	}
 }
 
@@ -2796,11 +2765,7 @@ static void mpi_sata_event(struct pm8001
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_COMPLETE;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2909,20 +2874,9 @@ static void mpi_sata_event(struct pm8001
 			" resp 0x%x stat 0x%x but aborted by upper layer!\n",
 			t, event, ts->resp, ts->stat));
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-	} else if (t->uldd_task) {
-		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
-	} else if (!t->uldd_task) {
+	} else {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 	}
 }
 
@@ -4467,23 +4421,10 @@ static int pm8001_chip_sata_req(struct p
 					" stat 0x%x but aborted by upper layer "
 					"\n", task, ts->resp, ts->stat));
 				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-			} else if (task->uldd_task) {
-				spin_unlock_irqrestore(&task->task_state_lock,
-							flags);
-				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-				mb();/* ditto */
-				spin_unlock_irq(&pm8001_ha->lock);
-				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
-				return 0;
-			} else if (!task->uldd_task) {
+			} else {
 				spin_unlock_irqrestore(&task->task_state_lock,
 							flags);
-				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-				mb();/*ditto*/
-				spin_unlock_irq(&pm8001_ha->lock);
-				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
+				pm8001_ccb_task_free_done(pm8001_ha, task, ccb, tag);
 				return 0;
 			}
 		}
--- x/drivers/scsi/pm8001/pm80xx_hwi.c
+++ x/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -2175,11 +2175,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*in order to force CPU ordering*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2195,11 +2191,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2221,11 +2213,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/* ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2288,11 +2276,7 @@ mpi_sata_completion(struct pm8001_hba_in
 					IO_DS_NON_OPERATIONAL);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2312,11 +2296,7 @@ mpi_sata_completion(struct pm8001_hba_in
 					IO_DS_IN_ERROR);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2345,20 +2325,9 @@ mpi_sata_completion(struct pm8001_hba_in
 			" resp 0x%x stat 0x%x but aborted by upper layer!\n",
 			t, status, ts->resp, ts->stat));
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-	} else if (t->uldd_task) {
-		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
-	} else if (!t->uldd_task) {
+	} else {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 	}
 }
 
@@ -2470,11 +2439,7 @@ static void mpi_sata_event(struct pm8001
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_COMPLETE;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2596,20 +2561,9 @@ static void mpi_sata_event(struct pm8001
 			" resp 0x%x stat 0x%x but aborted by upper layer!\n",
 			t, event, ts->resp, ts->stat));
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-	} else if (t->uldd_task) {
-		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
-	} else if (!t->uldd_task) {
+	} else {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 	}
 }
 
@@ -4304,23 +4258,10 @@ static int pm80xx_chip_sata_req(struct p
 					"\n", task, ts->resp, ts->stat));
 				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
 				return 0;
-			} else if (task->uldd_task) {
-				spin_unlock_irqrestore(&task->task_state_lock,
-							flags);
-				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-				mb();/* ditto */
-				spin_unlock_irq(&pm8001_ha->lock);
-				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
-				return 0;
-			} else if (!task->uldd_task) {
+			} else {
 				spin_unlock_irqrestore(&task->task_state_lock,
 							flags);
-				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-				mb();/*ditto*/
-				spin_unlock_irq(&pm8001_ha->lock);
-				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
+				pm8001_ccb_task_free_done(pm8001_ha, task, ccb, tag);
 				return 0;
 			}
 		}


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2013-12-27 16:18                             ` Oleg Nesterov
  0 siblings, 0 replies; 33+ messages in thread
From: Oleg Nesterov @ 2013-12-27 16:18 UTC (permalink / raw)
  To: Suresh Thiagarajan
  Cc: Ingo Molnar, Jason Seba, Peter Zijlstra, Ingo Molnar,
	Linus Torvalds, Tomas Henzl, Jack Wang, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel

On 12/24, Suresh Thiagarajan wrote:
>
> Below is a small pseudo code on protecting/serializing the flag for global access.
> struct temp
> {
> 	...
> 	spinlock_t lock;
> 	unsigned long lock_flags;
> };
> void my_lock(struct temp *t)
> {
>                unsigned long flag; // thread-private variable as suggested
>                spin_lock_irqsave(&t->lock, flag);
>                t->lock_flags = flag; //updating inside critical section now to serialize the access to flag
> }
>
> void my_unlock(struct temp *t)
> {
>                unsigned long flag = t->lock_flags;
>                t->lock_flags = 0;  //clearing it before getting out of critical section
>                spin_unlock_irqrestore(&t->lock, flag);
> }

Yes, this should work as a quick fix. And you do not need to clear ->lock_flags
in my_unlock().

But when I look at original patch again, I no longer understand why do
you need pm8001_ha->lock_flags at all. Of course I do not understand this
code, I am sure I missed something, but at first glance it seems that only
this sequence

	spin_unlock_irq(&pm8001_ha->lock);
	t->task_done(t);
	spin_lock_irq(&pm8001_ha->lock);

should be fixed?

If yes, why you can't simply do spin_unlock() + spin_lock() around
t->task_done() ? This won't enable irqs, but spin_unlock_irqrestore()
doesn't necessarily enables irqs too, so ->task_done() can run with
irqs disabled?

And note that the pattern above has a lot of users, perhaps it makes
sense to start with something like the patch below?

Hmm. there is another oddity in this code, for example mpi_sata_completion()
does

	} else if (t->uldd_task) {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
		mb();/* ditto */
		spin_unlock_irq(&pm8001_ha->lock);
		t->task_done(t);
		spin_lock_irq(&pm8001_ha->lock);
	} else if (!t->uldd_task) {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
		mb();/*ditto*/
		spin_unlock_irq(&pm8001_ha->lock);
		t->task_done(t);
		spin_lock_irq(&pm8001_ha->lock);
	}

and both branches do the same code? mpi_sata_event(), pm8001_chip_sata_req()
too.

Imho, whatever you do, the changelog should tell more.

Oleg.


--- x/drivers/scsi/pm8001/pm8001_sas.h
+++ x/drivers/scsi/pm8001/pm8001_sas.h
@@ -619,6 +619,20 @@ u32 pm8001_get_ncq_tag(struct sas_task *
 void pm8001_ccb_free(struct pm8001_hba_info *pm8001_ha, u32 ccb_idx);
 void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
 	struct sas_task *task, struct pm8001_ccb_info *ccb, u32 ccb_idx);
+
+static inline void
+pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
+			struct sas_task *task, struct pm8001_ccb_info *ccb,
+			u32 ccb_idx)
+{
+	pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb_idx);
+	smp_mb(); /* comment */
+	spin_unlock(&pm8001_ha->lock);
+	task->task_done(task);
+	spin_lock(&pm8001_ha->lock);
+}
+
+
 int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
 	void *funcdata);
 void pm8001_scan_start(struct Scsi_Host *shost);
--- x/drivers/scsi/pm8001/pm8001_hwi.c
+++ x/drivers/scsi/pm8001/pm8001_hwi.c
@@ -2502,11 +2502,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*in order to force CPU ordering*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2522,11 +2518,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2550,11 +2542,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/* ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2617,11 +2605,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				    IO_DS_NON_OPERATIONAL);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2641,11 +2625,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				    IO_DS_IN_ERROR);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2674,20 +2654,9 @@ mpi_sata_completion(struct pm8001_hba_in
 			" resp 0x%x stat 0x%x but aborted by upper layer!\n",
 			t, status, ts->resp, ts->stat));
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-	} else if (t->uldd_task) {
-		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
-	} else if (!t->uldd_task) {
+	} else {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 	}
 }
 
@@ -2796,11 +2765,7 @@ static void mpi_sata_event(struct pm8001
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_COMPLETE;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2909,20 +2874,9 @@ static void mpi_sata_event(struct pm8001
 			" resp 0x%x stat 0x%x but aborted by upper layer!\n",
 			t, event, ts->resp, ts->stat));
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-	} else if (t->uldd_task) {
-		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
-	} else if (!t->uldd_task) {
+	} else {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 	}
 }
 
@@ -4467,23 +4421,10 @@ static int pm8001_chip_sata_req(struct p
 					" stat 0x%x but aborted by upper layer "
 					"\n", task, ts->resp, ts->stat));
 				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-			} else if (task->uldd_task) {
-				spin_unlock_irqrestore(&task->task_state_lock,
-							flags);
-				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-				mb();/* ditto */
-				spin_unlock_irq(&pm8001_ha->lock);
-				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
-				return 0;
-			} else if (!task->uldd_task) {
+			} else {
 				spin_unlock_irqrestore(&task->task_state_lock,
 							flags);
-				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-				mb();/*ditto*/
-				spin_unlock_irq(&pm8001_ha->lock);
-				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
+				pm8001_ccb_task_free_done(pm8001_ha, task, ccb, tag);
 				return 0;
 			}
 		}
--- x/drivers/scsi/pm8001/pm80xx_hwi.c
+++ x/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -2175,11 +2175,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*in order to force CPU ordering*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2195,11 +2191,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2221,11 +2213,7 @@ mpi_sata_completion(struct pm8001_hba_in
 				IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/* ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2288,11 +2276,7 @@ mpi_sata_completion(struct pm8001_hba_in
 					IO_DS_NON_OPERATIONAL);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2312,11 +2296,7 @@ mpi_sata_completion(struct pm8001_hba_in
 					IO_DS_IN_ERROR);
 			ts->resp = SAS_TASK_UNDELIVERED;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2345,20 +2325,9 @@ mpi_sata_completion(struct pm8001_hba_in
 			" resp 0x%x stat 0x%x but aborted by upper layer!\n",
 			t, status, ts->resp, ts->stat));
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-	} else if (t->uldd_task) {
-		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
-	} else if (!t->uldd_task) {
+	} else {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 	}
 }
 
@@ -2470,11 +2439,7 @@ static void mpi_sata_event(struct pm8001
 				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
 			ts->resp = SAS_TASK_COMPLETE;
 			ts->stat = SAS_QUEUE_FULL;
-			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-			mb();/*ditto*/
-			spin_unlock_irq(&pm8001_ha->lock);
-			t->task_done(t);
-			spin_lock_irq(&pm8001_ha->lock);
+			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 			return;
 		}
 		break;
@@ -2596,20 +2561,9 @@ static void mpi_sata_event(struct pm8001
 			" resp 0x%x stat 0x%x but aborted by upper layer!\n",
 			t, event, ts->resp, ts->stat));
 		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-	} else if (t->uldd_task) {
-		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/* ditto */
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
-	} else if (!t->uldd_task) {
+	} else {
 		spin_unlock_irqrestore(&t->task_state_lock, flags);
-		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
-		mb();/*ditto*/
-		spin_unlock_irq(&pm8001_ha->lock);
-		t->task_done(t);
-		spin_lock_irq(&pm8001_ha->lock);
+		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
 	}
 }
 
@@ -4304,23 +4258,10 @@ static int pm80xx_chip_sata_req(struct p
 					"\n", task, ts->resp, ts->stat));
 				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
 				return 0;
-			} else if (task->uldd_task) {
-				spin_unlock_irqrestore(&task->task_state_lock,
-							flags);
-				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-				mb();/* ditto */
-				spin_unlock_irq(&pm8001_ha->lock);
-				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
-				return 0;
-			} else if (!task->uldd_task) {
+			} else {
 				spin_unlock_irqrestore(&task->task_state_lock,
 							flags);
-				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
-				mb();/*ditto*/
-				spin_unlock_irq(&pm8001_ha->lock);
-				task->task_done(task);
-				spin_lock_irq(&pm8001_ha->lock);
+				pm8001_ccb_task_free_done(pm8001_ha, task, ccb, tag);
 				return 0;
 			}
 		}

^ permalink raw reply	[flat|nested] 33+ messages in thread

* RE: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2013-12-27 16:18                             ` Oleg Nesterov
  (?)
@ 2014-01-02 10:31                             ` Suresh Thiagarajan
  2014-01-03 20:02                                 ` Dan Williams
  -1 siblings, 1 reply; 33+ messages in thread
From: Suresh Thiagarajan @ 2014-01-02 10:31 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Ingo Molnar, Jason Seba, Peter Zijlstra, Ingo Molnar,
	Linus Torvalds, Tomas Henzl, Jack Wang, Viswas G, linux-scsi,
	JBottomley, Vasanthalakshmi Tharmarajan, linux-kernel



On Fri, Dec 27, 2013 at 9:48 PM, Oleg Nesterov <oleg@redhat.com> wrote:
> On 12/24, Suresh Thiagarajan wrote:
>>
>> Below is a small pseudo code on protecting/serializing the flag for global access.
>> struct temp
>> {
>>       ...
>>       spinlock_t lock;
>>       unsigned long lock_flags;
>> };
>> void my_lock(struct temp *t)
>> {
>>                unsigned long flag; // thread-private variable as suggested
>>                spin_lock_irqsave(&t->lock, flag);
>>                t->lock_flags = flag; //updating inside critical section now to serialize the access to flag
>> }
>>
>> void my_unlock(struct temp *t)
>> {
>>                unsigned long flag = t->lock_flags;
>>                t->lock_flags = 0;  //clearing it before getting out of critical section
>>                spin_unlock_irqrestore(&t->lock, flag);
>> }
>
> Yes, this should work as a quick fix. And you do not need to clear ->lock_flags
> in my_unlock().
>
> But when I look at original patch again, I no longer understand why do
> you need pm8001_ha->lock_flags at all. Of course I do not understand this
> code, I am sure I missed something, but at first glance it seems that only
> this sequence
>
>         spin_unlock_irq(&pm8001_ha->lock);
>         t->task_done(t);
>         spin_lock_irq(&pm8001_ha->lock);
>
> should be fixed?
>
> If yes, why you can't simply do spin_unlock() + spin_lock() around
> t->task_done() ? This won't enable irqs, but spin_unlock_irqrestore()
> doesn't necessarily enables irqs too, so ->task_done() can run with
> irqs disabled?
>
> And note that the pattern above has a lot of users, perhaps it makes
> sense to start with something like the patch below?

Thanks James, Oleg and all for your inputs.
Will start with review and testing this patch and then work/investigate to keep shortest and clearest critical 
section so that we can have the lock and unlock within the same routine.

Regards,
Suresh
>
> Hmm. there is another oddity in this code, for example mpi_sata_completion()
> does
>
>         } else if (t->uldd_task) {
>                 spin_unlock_irqrestore(&t->task_state_lock, flags);
>                 pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>                 mb();/* ditto */
>                 spin_unlock_irq(&pm8001_ha->lock);
>                 t->task_done(t);
>                 spin_lock_irq(&pm8001_ha->lock);
>         } else if (!t->uldd_task) {
>                 spin_unlock_irqrestore(&t->task_state_lock, flags);
>                 pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
>                 mb();/*ditto*/
>                 spin_unlock_irq(&pm8001_ha->lock);
>                 t->task_done(t);
>                 spin_lock_irq(&pm8001_ha->lock);
>         }
>
> and both branches do the same code? mpi_sata_event(), pm8001_chip_sata_req()
> too.
>
> Imho, whatever you do, the changelog should tell more.
>
> Oleg.
>
>
> --- x/drivers/scsi/pm8001/pm8001_sas.h
> +++ x/drivers/scsi/pm8001/pm8001_sas.h
> @@ -619,6 +619,20 @@ u32 pm8001_get_ncq_tag(struct sas_task *
>  void pm8001_ccb_free(struct pm8001_hba_info *pm8001_ha, u32 ccb_idx);
>  void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha,
>         struct sas_task *task, struct pm8001_ccb_info *ccb, u32 ccb_idx);
> +
> +static inline void
> +pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
> +                       struct sas_task *task, struct pm8001_ccb_info *ccb,
> +                       u32 ccb_idx)
> +{
> +       pm8001_ccb_task_free(pm8001_ha, task, ccb, ccb_idx);
> +       smp_mb(); /* comment */
> +       spin_unlock(&pm8001_ha->lock);
> +       task->task_done(task);
> +       spin_lock(&pm8001_ha->lock);
> +}
> +
> +
>  int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
>         void *funcdata);
>  void pm8001_scan_start(struct Scsi_Host *shost);
> --- x/drivers/scsi/pm8001/pm8001_hwi.c
> +++ x/drivers/scsi/pm8001/pm8001_hwi.c
> @@ -2502,11 +2502,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                 IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*in order to force CPU ordering*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2522,11 +2518,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                 IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2550,11 +2542,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                 IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/* ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2617,11 +2605,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                     IO_DS_NON_OPERATIONAL);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2641,11 +2625,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                     IO_DS_IN_ERROR);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2674,20 +2654,9 @@ mpi_sata_completion(struct pm8001_hba_in
>                         " resp 0x%x stat 0x%x but aborted by upper layer!\n",
>                         t, status, ts->resp, ts->stat));
>                 pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -       } else if (t->uldd_task) {
> -               spin_unlock_irqrestore(&t->task_state_lock, flags);
> -               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -               mb();/* ditto */
> -               spin_unlock_irq(&pm8001_ha->lock);
> -               t->task_done(t);
> -               spin_lock_irq(&pm8001_ha->lock);
> -       } else if (!t->uldd_task) {
> +       } else {
>                 spin_unlock_irqrestore(&t->task_state_lock, flags);
> -               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -               mb();/*ditto*/
> -               spin_unlock_irq(&pm8001_ha->lock);
> -               t->task_done(t);
> -               spin_lock_irq(&pm8001_ha->lock);
> +               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>         }
>  }
>
> @@ -2796,11 +2765,7 @@ static void mpi_sata_event(struct pm8001
>                                 IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
>                         ts->resp = SAS_TASK_COMPLETE;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2909,20 +2874,9 @@ static void mpi_sata_event(struct pm8001
>                         " resp 0x%x stat 0x%x but aborted by upper layer!\n",
>                         t, event, ts->resp, ts->stat));
>                 pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -       } else if (t->uldd_task) {
> -               spin_unlock_irqrestore(&t->task_state_lock, flags);
> -               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -               mb();/* ditto */
> -               spin_unlock_irq(&pm8001_ha->lock);
> -               t->task_done(t);
> -               spin_lock_irq(&pm8001_ha->lock);
> -       } else if (!t->uldd_task) {
> +       } else {
>                 spin_unlock_irqrestore(&t->task_state_lock, flags);
> -               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -               mb();/*ditto*/
> -               spin_unlock_irq(&pm8001_ha->lock);
> -               t->task_done(t);
> -               spin_lock_irq(&pm8001_ha->lock);
> +               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>         }
>  }
>
> @@ -4467,23 +4421,10 @@ static int pm8001_chip_sata_req(struct p
>                                         " stat 0x%x but aborted by upper layer "
>                                         "\n", task, ts->resp, ts->stat));
>                                 pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
> -                       } else if (task->uldd_task) {
> -                               spin_unlock_irqrestore(&task->task_state_lock,
> -                                                       flags);
> -                               pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
> -                               mb();/* ditto */
> -                               spin_unlock_irq(&pm8001_ha->lock);
> -                               task->task_done(task);
> -                               spin_lock_irq(&pm8001_ha->lock);
> -                               return 0;
> -                       } else if (!task->uldd_task) {
> +                       } else {
>                                 spin_unlock_irqrestore(&task->task_state_lock,
>                                                         flags);
> -                               pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
> -                               mb();/*ditto*/
> -                               spin_unlock_irq(&pm8001_ha->lock);
> -                               task->task_done(task);
> -                               spin_lock_irq(&pm8001_ha->lock);
> +                               pm8001_ccb_task_free_done(pm8001_ha, task, ccb, tag);
>                                 return 0;
>                         }
>                 }
> --- x/drivers/scsi/pm8001/pm80xx_hwi.c
> +++ x/drivers/scsi/pm8001/pm80xx_hwi.c
> @@ -2175,11 +2175,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                 IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*in order to force CPU ordering*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2195,11 +2191,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                 IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2221,11 +2213,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                 IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/* ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2288,11 +2276,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                         IO_DS_NON_OPERATIONAL);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2312,11 +2296,7 @@ mpi_sata_completion(struct pm8001_hba_in
>                                         IO_DS_IN_ERROR);
>                         ts->resp = SAS_TASK_UNDELIVERED;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2345,20 +2325,9 @@ mpi_sata_completion(struct pm8001_hba_in
>                         " resp 0x%x stat 0x%x but aborted by upper layer!\n",
>                         t, status, ts->resp, ts->stat));
>                 pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -       } else if (t->uldd_task) {
> -               spin_unlock_irqrestore(&t->task_state_lock, flags);
> -               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -               mb();/* ditto */
> -               spin_unlock_irq(&pm8001_ha->lock);
> -               t->task_done(t);
> -               spin_lock_irq(&pm8001_ha->lock);
> -       } else if (!t->uldd_task) {
> +       } else {
>                 spin_unlock_irqrestore(&t->task_state_lock, flags);
> -               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -               mb();/*ditto*/
> -               spin_unlock_irq(&pm8001_ha->lock);
> -               t->task_done(t);
> -               spin_lock_irq(&pm8001_ha->lock);
> +               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>         }
>  }
>
> @@ -2470,11 +2439,7 @@ static void mpi_sata_event(struct pm8001
>                                 IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
>                         ts->resp = SAS_TASK_COMPLETE;
>                         ts->stat = SAS_QUEUE_FULL;
> -                       pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -                       mb();/*ditto*/
> -                       spin_unlock_irq(&pm8001_ha->lock);
> -                       t->task_done(t);
> -                       spin_lock_irq(&pm8001_ha->lock);
> +                       pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>                         return;
>                 }
>                 break;
> @@ -2596,20 +2561,9 @@ static void mpi_sata_event(struct pm8001
>                         " resp 0x%x stat 0x%x but aborted by upper layer!\n",
>                         t, event, ts->resp, ts->stat));
>                 pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -       } else if (t->uldd_task) {
> -               spin_unlock_irqrestore(&t->task_state_lock, flags);
> -               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -               mb();/* ditto */
> -               spin_unlock_irq(&pm8001_ha->lock);
> -               t->task_done(t);
> -               spin_lock_irq(&pm8001_ha->lock);
> -       } else if (!t->uldd_task) {
> +       } else {
>                 spin_unlock_irqrestore(&t->task_state_lock, flags);
> -               pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
> -               mb();/*ditto*/
> -               spin_unlock_irq(&pm8001_ha->lock);
> -               t->task_done(t);
> -               spin_lock_irq(&pm8001_ha->lock);
> +               pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
>         }
>  }
>
> @@ -4304,23 +4258,10 @@ static int pm80xx_chip_sata_req(struct p
>                                         "\n", task, ts->resp, ts->stat));
>                                 pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
>                                 return 0;
> -                       } else if (task->uldd_task) {
> -                               spin_unlock_irqrestore(&task->task_state_lock,
> -                                                       flags);
> -                               pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
> -                               mb();/* ditto */
> -                               spin_unlock_irq(&pm8001_ha->lock);
> -                               task->task_done(task);
> -                               spin_lock_irq(&pm8001_ha->lock);
> -                               return 0;
> -                       } else if (!task->uldd_task) {
> +                       } else {
>                                 spin_unlock_irqrestore(&task->task_state_lock,
>                                                         flags);
> -                               pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
> -                               mb();/*ditto*/
> -                               spin_unlock_irq(&pm8001_ha->lock);
> -                               task->task_done(task);
> -                               spin_lock_irq(&pm8001_ha->lock);
> +                               pm8001_ccb_task_free_done(pm8001_ha, task, ccb, tag);
>                                 return 0;
>                         }
>                 }
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
  2014-01-02 10:31                             ` Suresh Thiagarajan
@ 2014-01-03 20:02                                 ` Dan Williams
  0 siblings, 0 replies; 33+ messages in thread
From: Dan Williams @ 2014-01-03 20:02 UTC (permalink / raw)
  To: Suresh Thiagarajan
  Cc: Oleg Nesterov, Ingo Molnar, Jason Seba, Peter Zijlstra,
	Ingo Molnar, Linus Torvalds, Tomas Henzl, Jack Wang, Viswas G,
	linux-scsi, JBottomley, Vasanthalakshmi Tharmarajan,
	linux-kernel

On Thu, Jan 2, 2014 at 2:31 AM, Suresh Thiagarajan
<Suresh.Thiagarajan@pmcs.com> wrote:
>
>
> On Fri, Dec 27, 2013 at 9:48 PM, Oleg Nesterov <oleg@redhat.com> wrote:
>> On 12/24, Suresh Thiagarajan wrote:
>>>
>>> Below is a small pseudo code on protecting/serializing the flag for global access.
>>> struct temp
>>> {
>>>       ...
>>>       spinlock_t lock;
>>>       unsigned long lock_flags;
>>> };
>>> void my_lock(struct temp *t)
>>> {
>>>                unsigned long flag; // thread-private variable as suggested
>>>                spin_lock_irqsave(&t->lock, flag);
>>>                t->lock_flags = flag; //updating inside critical section now to serialize the access to flag
>>> }
>>>
>>> void my_unlock(struct temp *t)
>>> {
>>>                unsigned long flag = t->lock_flags;
>>>                t->lock_flags = 0;  //clearing it before getting out of critical section
>>>                spin_unlock_irqrestore(&t->lock, flag);
>>> }
>>
>> Yes, this should work as a quick fix. And you do not need to clear ->lock_flags
>> in my_unlock().
>>
>> But when I look at original patch again, I no longer understand why do
>> you need pm8001_ha->lock_flags at all. Of course I do not understand this
>> code, I am sure I missed something, but at first glance it seems that only
>> this sequence
>>
>>         spin_unlock_irq(&pm8001_ha->lock);
>>         t->task_done(t);
>>         spin_lock_irq(&pm8001_ha->lock);
>>
>> should be fixed?
>>
>> If yes, why you can't simply do spin_unlock() + spin_lock() around
>> t->task_done() ? This won't enable irqs, but spin_unlock_irqrestore()
>> doesn't necessarily enables irqs too, so ->task_done() can run with
>> irqs disabled?
>>
>> And note that the pattern above has a lot of users, perhaps it makes
>> sense to start with something like the patch below?
>
> Thanks James, Oleg and all for your inputs.
> Will start with review and testing this patch and then work/investigate to keep shortest and clearest critical
> section so that we can have the lock and unlock within the same routine.
>

Fwiw we solved this in libsas a while back with a similar pattern
proposed by Oleg:

unsigned long flags;

local_irq_save(flags);
spin_unlock(lock);
...
spin_lock_lock(lock);
local_irq_restore(flags);

See commit 312d3e56119a "[SCSI] libsas: remove ata_port.lock
management duties from lldds"

--
Dan

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix)
@ 2014-01-03 20:02                                 ` Dan Williams
  0 siblings, 0 replies; 33+ messages in thread
From: Dan Williams @ 2014-01-03 20:02 UTC (permalink / raw)
  To: Suresh Thiagarajan
  Cc: Oleg Nesterov, Ingo Molnar, Jason Seba, Peter Zijlstra,
	Ingo Molnar, Linus Torvalds, Tomas Henzl, Jack Wang, Viswas G,
	linux-scsi, JBottomley, Vasanthalakshmi Tharmarajan,
	linux-kernel

On Thu, Jan 2, 2014 at 2:31 AM, Suresh Thiagarajan
<Suresh.Thiagarajan@pmcs.com> wrote:
>
>
> On Fri, Dec 27, 2013 at 9:48 PM, Oleg Nesterov <oleg@redhat.com> wrote:
>> On 12/24, Suresh Thiagarajan wrote:
>>>
>>> Below is a small pseudo code on protecting/serializing the flag for global access.
>>> struct temp
>>> {
>>>       ...
>>>       spinlock_t lock;
>>>       unsigned long lock_flags;
>>> };
>>> void my_lock(struct temp *t)
>>> {
>>>                unsigned long flag; // thread-private variable as suggested
>>>                spin_lock_irqsave(&t->lock, flag);
>>>                t->lock_flags = flag; //updating inside critical section now to serialize the access to flag
>>> }
>>>
>>> void my_unlock(struct temp *t)
>>> {
>>>                unsigned long flag = t->lock_flags;
>>>                t->lock_flags = 0;  //clearing it before getting out of critical section
>>>                spin_unlock_irqrestore(&t->lock, flag);
>>> }
>>
>> Yes, this should work as a quick fix. And you do not need to clear ->lock_flags
>> in my_unlock().
>>
>> But when I look at original patch again, I no longer understand why do
>> you need pm8001_ha->lock_flags at all. Of course I do not understand this
>> code, I am sure I missed something, but at first glance it seems that only
>> this sequence
>>
>>         spin_unlock_irq(&pm8001_ha->lock);
>>         t->task_done(t);
>>         spin_lock_irq(&pm8001_ha->lock);
>>
>> should be fixed?
>>
>> If yes, why you can't simply do spin_unlock() + spin_lock() around
>> t->task_done() ? This won't enable irqs, but spin_unlock_irqrestore()
>> doesn't necessarily enables irqs too, so ->task_done() can run with
>> irqs disabled?
>>
>> And note that the pattern above has a lot of users, perhaps it makes
>> sense to start with something like the patch below?
>
> Thanks James, Oleg and all for your inputs.
> Will start with review and testing this patch and then work/investigate to keep shortest and clearest critical
> section so that we can have the lock and unlock within the same routine.
>

Fwiw we solved this in libsas a while back with a similar pattern
proposed by Oleg:

unsigned long flags;

local_irq_save(flags);
spin_unlock(lock);
...
spin_lock_lock(lock);
local_irq_restore(flags);

See commit 312d3e56119a "[SCSI] libsas: remove ata_port.lock
management duties from lldds"

--
Dan

^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2014-01-03 20:02 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-18 11:28 [PATCH] pm80xx: Spinlock fix Viswas G
2013-12-23 13:07 ` Tomas Henzl
2013-12-23 13:32   ` Jack Wang
2013-12-23 13:45     ` Suresh Thiagarajan
2013-12-23 14:55       ` Jason Seba
2013-12-23 15:06         ` Jack Wang
2013-12-23 15:28           ` Tomas Henzl
2013-12-23 15:33             ` Jason Seba
2013-12-23 15:36               ` Tomas Henzl
2013-12-23 16:34               ` Oleg Nesterov
2013-12-23 17:27                 ` spinlock_irqsave() && flags (Was: pm80xx: Spinlock fix) Oleg Nesterov
2013-12-23 17:27                   ` Oleg Nesterov
2013-12-23 18:12                   ` Linus Torvalds
2013-12-23 18:12                     ` Linus Torvalds
2013-12-23 18:24                     ` Oleg Nesterov
2013-12-23 18:24                       ` Oleg Nesterov
2013-12-23 18:43                       ` Linus Torvalds
2013-12-23 18:43                         ` Linus Torvalds
2013-12-23 18:23                   ` Ingo Molnar
2013-12-23 18:23                     ` Ingo Molnar
2013-12-23 18:33                     ` Oleg Nesterov
2013-12-23 18:33                       ` Oleg Nesterov
2013-12-24  8:29                       ` Ingo Molnar
2013-12-24  8:29                         ` Ingo Molnar
2013-12-24  9:13                         ` Suresh Thiagarajan
2013-12-24 17:29                           ` James Bottomley
2013-12-24 17:29                             ` James Bottomley
2013-12-27 16:18                           ` Oleg Nesterov
2013-12-27 16:18                             ` Oleg Nesterov
2014-01-02 10:31                             ` Suresh Thiagarajan
2014-01-03 20:02                               ` Dan Williams
2014-01-03 20:02                                 ` Dan Williams
2013-12-23 15:38             ` [PATCH] pm80xx: Spinlock fix Oleg Nesterov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.