diff mbox

[v2,1/2] scsi:stex.c Support Pegasus 3 product

Message ID 1465885263-8553-1-git-send-email-ch1102chiou@gmail.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Charles Chiou June 14, 2016, 6:21 a.m. UTC
From: Charles <charles.chiou@tw.promise.com>

Pegasus series is a RAID support product by using Thunderbolt technology.

The newest product, Pegasus 3 is support Thunderbolt 3 technology with another chip.

1.Change driver version.

2.Add Pegasus 3 VID, DID and define it's device address.

3.Pegasus 3 use msi interrupt, so stex_request_irq P3 type enable msi.

4.For hibernation, use msi_lock in stex_ss_handshake to prevent msi register write again when handshaking.

5.Pegasus 3 don't need read() as flush.

6.In stex_ss_intr & stex_abort, P3 only clear interrupt register when getting vendor defined interrupt.

Signed-off-by: Charles <charles.chiou@tw.promise.com>
Signed-off-by: Paul <paul.lyu@tw.promise.com>
---
 drivers/scsi/stex.c | 242 ++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 177 insertions(+), 65 deletions(-)

Comments

kernel test robot June 14, 2016, 6:49 a.m. UTC | #1
Hi,

[auto build test WARNING on scsi/for-next]
[also build test WARNING on v4.7-rc3 next-20160609]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Charles-Chiou/scsi-stex-c-Support-Pegasus-3-product/20160614-142621
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
config: sparc64-allmodconfig (attached as .config)
compiler: sparc64-linux-gnu-gcc (Debian 5.3.1-8) 5.3.1 20160205
reproduce:
        wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=sparc64 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   In file included from arch/sparc/include/asm/string.h:4:0,
                    from include/linux/string.h:18,
                    from include/linux/bitmap.h:8,
                    from include/linux/nodemask.h:94,
                    from include/linux/mmzone.h:16,
                    from include/linux/gfp.h:5,
                    from include/linux/slab.h:14,
                    from drivers/scsi/stex.c:20:
   drivers/scsi/stex.c: In function 'stex_handshake':
>> arch/sparc/include/asm/string_64.h:28:29: warning: 'scratch' may be used uninitialized in this function [-Wmaybe-uninitialized]
    #define memset(s, c, count) __builtin_memset(s, c, count)
                                ^
   drivers/scsi/stex.c:1111:10: note: 'scratch' was declared here
     __le32 *scratch;
             ^

vim +/scratch +28 arch/sparc/include/asm/string_64.h

f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  12  /* Really, userland/ksyms should not see any of this stuff. */
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  13  
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  14  #ifdef __KERNEL__
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  15  
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  16  #include <asm/asi.h>
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  17  
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  18  #ifndef EXPORT_SYMTAB_STROPS
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  19  
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  20  /* First the mem*() things. */
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  21  #define __HAVE_ARCH_MEMMOVE
f05a6865 arch/sparc/include/asm/string_64.h Sam Ravnborg    2014-05-16  22  void *memmove(void *, const void *, __kernel_size_t);
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  23  
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  24  #define __HAVE_ARCH_MEMCPY
4d14a459 arch/sparc/include/asm/string_64.h David S. Miller 2009-12-10  25  #define memcpy(t, f, n) __builtin_memcpy(t, f, n)
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  26  
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  27  #define __HAVE_ARCH_MEMSET
4d14a459 arch/sparc/include/asm/string_64.h David S. Miller 2009-12-10 @28  #define memset(s, c, count) __builtin_memset(s, c, count)
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  29  
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  30  #define __HAVE_ARCH_MEMSCAN
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  31  
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  32  #undef memscan
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  33  #define memscan(__arg0, __char, __arg2)					\
f5e706ad include/asm-sparc/string_64.h      Sam Ravnborg    2008-07-17  34  ({									\
f05a6865 arch/sparc/include/asm/string_64.h Sam Ravnborg    2014-05-16  35  	void *__memscan_zero(void *, size_t);				\
f05a6865 arch/sparc/include/asm/string_64.h Sam Ravnborg    2014-05-16  36  	void *__memscan_generic(void *, int, size_t);			\

:::::: The code at line 28 was first introduced by commit
:::::: 4d14a459857bd151ecbd14bcd37b4628da00792b sparc: Stop trying to be so fancy and use __builtin_{memcpy,memset}()

:::::: TO: David S. Miller <davem@davemloft.net>
:::::: CC: David S. Miller <davem@davemloft.net>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot June 14, 2016, 7:24 a.m. UTC | #2
Hi,

[auto build test WARNING on scsi/for-next]
[also build test WARNING on v4.7-rc3 next-20160609]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Charles-Chiou/scsi-stex-c-Support-Pegasus-3-product/20160614-142621
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.1.1-1) 6.1.1 20160430
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   drivers/scsi/stex.c: In function 'stex_handshake':
>> drivers/scsi/stex.c:1208:2: warning: 'scratch' may be used uninitialized in this function [-Wmaybe-uninitialized]
     memset(scratch, 0, scratch_size);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   drivers/scsi/stex.c:1111:10: note: 'scratch' was declared here
     __le32 *scratch;
             ^~~~~~~

vim +/scratch +1208 drivers/scsi/stex.c

0f3f6ee6 Ed Lin  2009-03-31  1192  			msleep(1);
0f3f6ee6 Ed Lin  2009-03-31  1193  		}
2a48e931 Charles 2016-06-14  1194  	} else {
2a48e931 Charles 2016-06-14  1195  		while ((readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS)
2a48e931 Charles 2016-06-14  1196  		 & SS_STS_HANDSHAKE) == 0) {
2a48e931 Charles 2016-06-14  1197  			if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
2a48e931 Charles 2016-06-14  1198  				printk(KERN_ERR DRV_NAME
2a48e931 Charles 2016-06-14  1199  					"(%s): no signature after handshake frame\n",
2a48e931 Charles 2016-06-14  1200  					pci_name(hba->pdev));
2a48e931 Charles 2016-06-14  1201  				ret = -1;
2a48e931 Charles 2016-06-14  1202  				break;
2a48e931 Charles 2016-06-14  1203  			}
2a48e931 Charles 2016-06-14  1204  			rmb();
2a48e931 Charles 2016-06-14  1205  			msleep(1);
2a48e931 Charles 2016-06-14  1206  		}
2a48e931 Charles 2016-06-14  1207  	}
9eb46d2a Ed Lin  2009-09-28 @1208  	memset(scratch, 0, scratch_size);
0f3f6ee6 Ed Lin  2009-03-31  1209  	msg_h->flag = 0;
2a48e931 Charles 2016-06-14  1210  
0f3f6ee6 Ed Lin  2009-03-31  1211  	return ret;
0f3f6ee6 Ed Lin  2009-03-31  1212  }
0f3f6ee6 Ed Lin  2009-03-31  1213  
0f3f6ee6 Ed Lin  2009-03-31  1214  static int stex_handshake(struct st_hba *hba)
0f3f6ee6 Ed Lin  2009-03-31  1215  {
0f3f6ee6 Ed Lin  2009-03-31  1216  	int err;

:::::: The code at line 1208 was first introduced by commit
:::::: 9eb46d2a08de537e14e92216bf18e7cb541d2f67 [SCSI] stex: add support for reset request from firmware

:::::: TO: Ed Lin <ed.lin@promise.com>
:::::: CC: James Bottomley <James.Bottomley@suse.de>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
kernel test robot June 14, 2016, 7:25 a.m. UTC | #3
Hi,

[auto build test WARNING on scsi/for-next]
[also build test WARNING on v4.7-rc3 next-20160614]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Charles-Chiou/scsi-stex-c-Support-Pegasus-3-product/20160614-142621
base:   https://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git for-next
config: i386-allmodconfig (attached as .config)
compiler: gcc-6 (Debian 6.1.1-1) 6.1.1 20160430
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   In file included from arch/x86/include/asm/string.h:2:0,
                    from include/linux/string.h:18,
                    from arch/x86/include/asm/page_32.h:34,
                    from arch/x86/include/asm/page.h:13,
                    from arch/x86/include/asm/thread_info.h:11,
                    from include/linux/thread_info.h:54,
                    from arch/x86/include/asm/preempt.h:6,
                    from include/linux/preempt.h:59,
                    from include/linux/spinlock.h:50,
                    from include/linux/mmzone.h:7,
                    from include/linux/gfp.h:5,
                    from include/linux/slab.h:14,
                    from drivers/scsi/stex.c:20:
   drivers/scsi/stex.c: In function 'stex_handshake':
>> arch/x86/include/asm/string_32.h:325:29: warning: 'scratch' may be used uninitialized in this function [-Wmaybe-uninitialized]
    #define memset(s, c, count) __builtin_memset(s, c, count)
                                ^~~~~~~~~~~~~~~~
   drivers/scsi/stex.c:1111:10: note: 'scratch' was declared here
     __le32 *scratch;
             ^~~~~~~

vim +/scratch +325 arch/x86/include/asm/string_32.h

^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  309  
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  310  #undef COMMON
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  311  }
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  312  
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  313  #define __constant_c_x_memset(s, c, count)			\
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  314  	(__builtin_constant_p(count)				\
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  315  	 ? __constant_c_and_count_memset((s), (c), (count))	\
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  316  	 : __constant_c_memset((s), (c), (count)))
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  317  
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  318  #define __memset(s, c, count)				\
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  319  	(__builtin_constant_p(count)			\
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  320  	 ? __constant_count_memset((s), (c), (count))	\
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  321  	 : __memset_generic((s), (c), (count)))
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  322  
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  323  #define __HAVE_ARCH_MEMSET
ff60fab7 arch/x86/include/asm/string_32.h Arjan van de Ven 2009-09-28  324  #if (__GNUC__ >= 4)
ff60fab7 arch/x86/include/asm/string_32.h Arjan van de Ven 2009-09-28 @325  #define memset(s, c, count) __builtin_memset(s, c, count)
ff60fab7 arch/x86/include/asm/string_32.h Arjan van de Ven 2009-09-28  326  #else
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  327  #define memset(s, c, count)						\
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  328  	(__builtin_constant_p(c)					\
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  329  	 ? __constant_c_x_memset((s), (0x01010101UL * (unsigned char)(c)), \
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  330  				 (count))				\
78d64fc2 include/asm-x86/string_32.h      Joe Perches      2008-05-12  331  	 : __memset((s), (c), (count)))
ff60fab7 arch/x86/include/asm/string_32.h Arjan van de Ven 2009-09-28  332  #endif
^1da177e include/asm-i386/string.h        Linus Torvalds   2005-04-16  333  

:::::: The code at line 325 was first introduced by commit
:::::: ff60fab71bb3b4fdbf8caf57ff3739ffd0887396 x86: Use __builtin_memset and __builtin_memcpy for memset/memcpy

:::::: TO: Arjan van de Ven <arjan@infradead.org>
:::::: CC: H. Peter Anvin <hpa@zytor.com>

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 5b23175..817e895 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -38,8 +38,8 @@ 
 #include <scsi/scsi_eh.h>
 
 #define DRV_NAME "stex"
-#define ST_DRIVER_VERSION	"5.00.0000.01"
-#define ST_VER_MAJOR		5
+#define ST_DRIVER_VERSION	"6.00.0000.01"
+#define ST_VER_MAJOR		6
 #define ST_VER_MINOR		00
 #define ST_OEM				0000
 #define ST_BUILD_VER		01
@@ -64,6 +64,13 @@  enum {
 	YI2H_INT_C				= 0xa0,
 	YH2I_REQ				= 0xc0,
 	YH2I_REQ_HI				= 0xc4,
+	PSCRATCH0				= 0xb0,
+	PSCRATCH1				= 0xb4,
+	PSCRATCH2				= 0xb8,
+	PSCRATCH3				= 0xbc,
+	PSCRATCH4				= 0xc8,
+	MAILBOX_BASE			= 0x1000,
+	MAILBOX_HNDSHK_STS		= 0x0,
 
 	/* MU register value */
 	MU_INBOUND_DOORBELL_HANDSHAKE		= (1 << 0),
@@ -87,7 +94,7 @@  enum {
 	MU_STATE_STOP				= 5,
 	MU_STATE_NOCONNECT			= 6,
 
-	MU_MAX_DELAY				= 120,
+	MU_MAX_DELAY				= 50,
 	MU_HANDSHAKE_SIGNATURE			= 0x55aaaa55,
 	MU_HANDSHAKE_SIGNATURE_HALF		= 0x5a5a0000,
 	MU_HARD_RESET_WAIT			= 30000,
@@ -135,6 +142,7 @@  enum {
 	st_yosemite				= 2,
 	st_seq					= 3,
 	st_yel					= 4,
+	st_P3					= 5,
 
 	PASSTHRU_REQ_TYPE			= 0x00000001,
 	PASSTHRU_REQ_NO_WAKEUP			= 0x00000100,
@@ -339,6 +347,7 @@  struct st_hba {
 	u16 rq_size;
 	u16 sts_count;
 	u8  supports_pm;
+	int msi_lock;
 };
 
 struct st_card_info {
@@ -540,11 +549,15 @@  stex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
 
 	++hba->req_head;
 	hba->req_head %= hba->rq_count+1;
-
-	writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI);
-	readl(hba->mmio_base + YH2I_REQ_HI); /* flush */
-	writel(addr, hba->mmio_base + YH2I_REQ);
-	readl(hba->mmio_base + YH2I_REQ); /* flush */
+	if (hba->cardtype == st_P3) {
+		writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI);
+		writel(addr, hba->mmio_base + YH2I_REQ);
+	} else {
+		writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI);
+		readl(hba->mmio_base + YH2I_REQ_HI); /* flush */
+		writel(addr, hba->mmio_base + YH2I_REQ);
+		readl(hba->mmio_base + YH2I_REQ); /* flush */
+	}
 }
 
 static void return_abnormal_state(struct st_hba *hba, int status)
@@ -974,15 +987,31 @@  static irqreturn_t stex_ss_intr(int irq, void *__hba)
 
 	spin_lock_irqsave(hba->host->host_lock, flags);
 
-	data = readl(base + YI2H_INT);
-	if (data && data != 0xffffffff) {
-		/* clear the interrupt */
-		writel(data, base + YI2H_INT_C);
-		stex_ss_mu_intr(hba);
-		spin_unlock_irqrestore(hba->host->host_lock, flags);
-		if (unlikely(data & SS_I2H_REQUEST_RESET))
-			queue_work(hba->work_q, &hba->reset_work);
-		return IRQ_HANDLED;
+	if (hba->cardtype == st_yel) {
+		data = readl(base + YI2H_INT);
+		if (data && data != 0xffffffff) {
+			/* clear the interrupt */
+			writel(data, base + YI2H_INT_C);
+			stex_ss_mu_intr(hba);
+			spin_unlock_irqrestore(hba->host->host_lock, flags);
+			if (unlikely(data & SS_I2H_REQUEST_RESET))
+				queue_work(hba->work_q, &hba->reset_work);
+			return IRQ_HANDLED;
+		}
+	} else {
+		data = readl(base + PSCRATCH4);
+		if (data != 0xffffffff) {
+			if (data != 0) {
+				/* clear the interrupt */
+				writel(data, base + PSCRATCH1);
+				writel((1 << 22), base + YH2I_INT);
+			}
+			stex_ss_mu_intr(hba);
+			spin_unlock_irqrestore(hba->host->host_lock, flags);
+			if (unlikely(data & SS_I2H_REQUEST_RESET))
+				queue_work(hba->work_q, &hba->reset_work);
+			return IRQ_HANDLED;
+		}
 	}
 
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
@@ -1085,14 +1114,27 @@  static int stex_ss_handshake(struct st_hba *hba)
 	int ret = 0;
 
 	before = jiffies;
-	while ((readl(base + YIOA_STATUS) & SS_MU_OPERATIONAL) == 0) {
-		if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
-			printk(KERN_ERR DRV_NAME
-				"(%s): firmware not operational\n",
-				pci_name(hba->pdev));
-			return -1;
+
+	if (hba->cardtype == st_yel) {
+		while ((readl(base + YIOA_STATUS) & SS_MU_OPERATIONAL) == 0) {
+			if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+				printk(KERN_ERR DRV_NAME
+					"(%s): firmware not operational\n",
+					pci_name(hba->pdev));
+				return -1;
+			}
+			msleep(1);
+		}
+	} else {
+		while ((readl(base + PSCRATCH3) & SS_MU_OPERATIONAL) == 0) {
+			if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+				printk(KERN_ERR DRV_NAME
+					"(%s): firmware not operational\n",
+					pci_name(hba->pdev));
+				return -1;
+			}
+			msleep(1);
 		}
-		msleep(1);
 	}
 
 	msg_h = (struct st_msg_header *)hba->dma_mem;
@@ -1111,30 +1153,61 @@  static int stex_ss_handshake(struct st_hba *hba)
 	scratch_size = (hba->sts_count+1)*sizeof(u32);
 	h->scratch_size = cpu_to_le32(scratch_size);
 
-	data = readl(base + YINT_EN);
-	data &= ~4;
-	writel(data, base + YINT_EN);
-	writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI);
-	readl(base + YH2I_REQ_HI);
-	writel(hba->dma_handle, base + YH2I_REQ);
-	readl(base + YH2I_REQ); /* flush */
+	if (hba->cardtype == st_yel) {
+		data = readl(base + YINT_EN);
+		data &= ~4;
+		writel(data, base + YINT_EN);
+		writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI);
+		readl(base + YH2I_REQ_HI);
+		writel(hba->dma_handle, base + YH2I_REQ);
+		readl(base + YH2I_REQ); /* flush */
+	} else {
+		data = readl(base + YINT_EN);
+		data &= ~(1 << 0);
+		data &= ~(1 << 2);
+		writel(data, base + YINT_EN);
+		if (hba->msi_lock == 0) {
+			/* P3 MSI Register cannot access twice */
+			writel((1 << 6), base + YH2I_INT);
+			hba->msi_lock  = 1;
+		}
+		writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI);
+		writel(hba->dma_handle, base + YH2I_REQ);
+	}
 
-	scratch = hba->scratch;
 	before = jiffies;
-	while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) {
-		if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
-			printk(KERN_ERR DRV_NAME
-				"(%s): no signature after handshake frame\n",
-				pci_name(hba->pdev));
-			ret = -1;
-			break;
+
+	if (hba->cardtype == st_yel) {
+		scratch = hba->scratch;
+
+		while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) {
+			if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+				printk(KERN_ERR DRV_NAME
+					"(%s): no signature after handshake frame\n",
+					pci_name(hba->pdev));
+				ret = -1;
+				break;
+			}
+			rmb();
+			msleep(1);
+		}
+	} else {
+		while ((readl(base + MAILBOX_BASE + MAILBOX_HNDSHK_STS)
+		 & SS_STS_HANDSHAKE) == 0) {
+			if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) {
+				printk(KERN_ERR DRV_NAME
+					"(%s): no signature after handshake frame\n",
+					pci_name(hba->pdev));
+				ret = -1;
+				break;
+			}
+			rmb();
+			msleep(1);
 		}
-		rmb();
-		msleep(1);
 	}
-
 	memset(scratch, 0, scratch_size);
 	msg_h->flag = 0;
+
 	return ret;
 }
 
@@ -1144,8 +1217,10 @@  static int stex_handshake(struct st_hba *hba)
 	unsigned long flags;
 	unsigned int mu_status;
 
-	err = (hba->cardtype == st_yel) ?
-		stex_ss_handshake(hba) : stex_common_handshake(hba);
+	if (hba->cardtype == st_yel || hba->cardtype == st_P3)
+		err = stex_ss_handshake(hba);
+	else
+		err = stex_common_handshake(hba);
 	spin_lock_irqsave(hba->host->host_lock, flags);
 	mu_status = hba->mu_status;
 	if (err == 0) {
@@ -1190,6 +1265,15 @@  static int stex_abort(struct scsi_cmnd *cmd)
 
 		writel(data, base + YI2H_INT_C);
 		stex_ss_mu_intr(hba);
+	} else if (hba->cardtype == st_P3) {
+		data = readl(base + PSCRATCH4);
+		if (data == 0xffffffff)
+			goto fail_out;
+		if (data != 0) {
+			writel(data, base + PSCRATCH1);
+			writel((1 << 22), base + YH2I_INT);
+		}
+		stex_ss_mu_intr(hba);
 	} else {
 		data = readl(base + ODBL);
 		if (data == 0 || data == 0xffffffff)
@@ -1197,7 +1281,6 @@  static int stex_abort(struct scsi_cmnd *cmd)
 
 		writel(data, base + ODBL);
 		readl(base + ODBL); /* flush */
-
 		stex_mu_intr(hba, data);
 	}
 	if (hba->wait_ccb == NULL) {
@@ -1293,6 +1376,12 @@  static void stex_ss_reset(struct st_hba *hba)
 	ssleep(5);
 }
 
+static void stex_p3_reset(struct st_hba *hba)
+{
+	writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT);
+	ssleep(5);
+}
+
 static int stex_do_reset(struct st_hba *hba)
 {
 	unsigned long flags;
@@ -1329,7 +1418,8 @@  static int stex_do_reset(struct st_hba *hba)
 		stex_hard_reset(hba);
 	else if (hba->cardtype == st_yel)
 		stex_ss_reset(hba);
-
+	else if (hba->cardtype == st_P3)
+		stex_p3_reset(hba);
 
 	return_abnormal_state(hba, DID_RESET);
 
@@ -1414,6 +1504,13 @@  static struct pci_device_id stex_pci_tbl[] = {
 	/* st_yel */
 	{ 0x105a, 0x8650, 0x1033, PCI_ANY_ID, 0, 0, st_yel },
 	{ 0x105a, 0x8760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yel },
+
+	/* st_P3, pluto */
+	{ PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE,
+		0x8870, 0, 0, st_P3 },
+	/* st_P3, p3 */
+	{ PCI_VENDOR_ID_PROMISE, 0x8870, PCI_VENDOR_ID_PROMISE,
+		0x4300, 0, 0, st_P3 },
 	{ }	/* terminate list */
 };
 
@@ -1482,6 +1579,19 @@  static struct st_card_info stex_card_info[] = {
 		.map_sg		= stex_ss_map_sg,
 		.send		= stex_ss_send_cmd,
 	},
+
+	/* st_P3 */
+	{
+		.max_id		= 129,
+		.max_lun	= 256,
+		.max_channel	= 0,
+		.rq_count	= 801,
+		.rq_size	= 512,
+		.sts_count	= 801,
+		.alloc_rq	= stex_ss_alloc_req,
+		.map_sg		= stex_ss_map_sg,
+		.send		= stex_ss_send_cmd,
+	},
 };
 
 static int stex_set_dma_mask(struct pci_dev * pdev)
@@ -1502,7 +1612,7 @@  static int stex_request_irq(struct st_hba *hba)
 	struct pci_dev *pdev = hba->pdev;
 	int status;
 
-	if (msi) {
+	if (msi || hba->cardtype == st_P3) {
 		status = pci_enable_msi(pdev);
 		if (status != 0)
 			printk(KERN_ERR DRV_NAME
@@ -1513,7 +1623,8 @@  static int stex_request_irq(struct st_hba *hba)
 	} else
 		hba->msi_enabled = 0;
 
-	status = request_irq(pdev->irq, hba->cardtype == st_yel ?
+	status = request_irq(pdev->irq,
+		(hba->cardtype == st_yel || hba->cardtype == st_P3) ?
 		stex_ss_intr : stex_intr, IRQF_SHARED, DRV_NAME, hba);
 
 	if (status != 0) {
@@ -1597,12 +1708,12 @@  static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	case 0x4265:
 		break;
 	default:
-		if (hba->cardtype == st_yel)
+		if (hba->cardtype == st_yel || hba->cardtype == st_P3)
 			hba->supports_pm = 1;
 	}
 
 	sts_offset = scratch_offset = (ci->rq_count+1) * ci->rq_size;
-	if (hba->cardtype == st_yel)
+	if (hba->cardtype == st_yel || hba->cardtype == st_P3)
 		sts_offset += (ci->sts_count+1) * sizeof(u32);
 	cp_offset = sts_offset + (ci->sts_count+1) * sizeof(struct status_msg);
 	hba->dma_size = cp_offset + sizeof(struct st_frame);
@@ -1642,7 +1753,7 @@  static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto out_pci_free;
 	}
 
-	if (hba->cardtype == st_yel)
+	if (hba->cardtype == st_yel || hba->cardtype == st_P3)
 		hba->scratch = (__le32 *)(hba->dma_mem + scratch_offset);
 	hba->status_buffer = (struct status_msg *)(hba->dma_mem + sts_offset);
 	hba->copy_buffer = hba->dma_mem + cp_offset;
@@ -1653,8 +1764,9 @@  static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	hba->map_sg = ci->map_sg;
 	hba->send = ci->send;
 	hba->mu_status = MU_STATE_STARTING;
+	hba->msi_lock = 0;
 
-	if (hba->cardtype == st_yel)
+	if (hba->cardtype == st_yel || hba->cardtype == st_P3)
 		host->sg_tablesize = 38;
 	else
 		host->sg_tablesize = 32;
@@ -1736,28 +1848,29 @@  static void stex_hba_stop(struct st_hba *hba, int st_sleep_mic)
 
 	spin_lock_irqsave(hba->host->host_lock, flags);
 
-	if (hba->cardtype == st_yel && hba->supports_pm == 1)
-	{
-		if(st_sleep_mic == ST_NOTHANDLED)
-		{
+	if ((hba->cardtype == st_yel || hba->cardtype == st_P3) &&
+		hba->supports_pm == 1) {
+		if (st_sleep_mic == ST_NOTHANDLED) {
 			spin_unlock_irqrestore(hba->host->host_lock, flags);
 			return;
 		}
 	}
 	req = hba->alloc_rq(hba);
-	if (hba->cardtype == st_yel) {
+	if (hba->cardtype == st_yel || hba->cardtype == st_P3) {
 		msg_h = (struct st_msg_header *)req - 1;
 		memset(msg_h, 0, hba->rq_size);
 	} else
 		memset(req, 0, hba->rq_size);
 
-	if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel)
+	if ((hba->cardtype == st_yosemite || hba->cardtype == st_yel
+		|| hba->cardtype == st_P3)
 		&& st_sleep_mic == ST_IGNORED) {
 		req->cdb[0] = MGT_CMD;
 		req->cdb[1] = MGT_CMD_SIGNATURE;
 		req->cdb[2] = CTLR_CONFIG_CMD;
 		req->cdb[3] = CTLR_SHUTDOWN;
-	} else if (hba->cardtype == st_yel && st_sleep_mic != ST_IGNORED) {
+	} else if ((hba->cardtype == st_yel || hba->cardtype == st_P3)
+		&& st_sleep_mic != ST_IGNORED) {
 		req->cdb[0] = MGT_CMD;
 		req->cdb[1] = MGT_CMD_SIGNATURE;
 		req->cdb[2] = CTLR_CONFIG_CMD;
@@ -1768,16 +1881,13 @@  static void stex_hba_stop(struct st_hba *hba, int st_sleep_mic)
 		req->cdb[1] = CTLR_POWER_STATE_CHANGE;
 		req->cdb[2] = CTLR_POWER_SAVING;
 	}
-
 	hba->ccb[tag].cmd = NULL;
 	hba->ccb[tag].sg_count = 0;
 	hba->ccb[tag].sense_bufflen = 0;
 	hba->ccb[tag].sense_buffer = NULL;
 	hba->ccb[tag].req_type = PASSTHRU_REQ_TYPE;
-
 	hba->send(hba, req, tag);
 	spin_unlock_irqrestore(hba->host->host_lock, flags);
-
 	before = jiffies;
 	while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) {
 		if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
@@ -1833,12 +1943,13 @@  static void stex_shutdown(struct pci_dev *pdev)
 		stex_hba_stop(hba, ST_S5);
 }
 
-static int stex_choice_sleep_mic(pm_message_t state)
+static int stex_choice_sleep_mic(struct st_hba *hba, pm_message_t state)
 {
 	switch (state.event) {
 	case PM_EVENT_SUSPEND:
 		return ST_S3;
 	case PM_EVENT_HIBERNATE:
+		hba->msi_lock = 0;
 		return ST_S4;
 	default:
 		return ST_NOTHANDLED;
@@ -1849,8 +1960,9 @@  static int stex_suspend(struct pci_dev *pdev, pm_message_t state)
 {
 	struct st_hba *hba = pci_get_drvdata(pdev);
 
-	if (hba->cardtype == st_yel && hba->supports_pm == 1)
-		stex_hba_stop(hba, stex_choice_sleep_mic(state));
+	if ((hba->cardtype == st_yel || hba->cardtype == st_P3)
+		&& hba->supports_pm == 1)
+		stex_hba_stop(hba, stex_choice_sleep_mic(hba, state));
 	else
 		stex_hba_stop(hba, ST_IGNORED);
 	return 0;