Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > media > main-src > by-pkgid > d0a35cd31c1125e2132804d68547073d > files > 3560

kernel-2.6.18-194.26.1.el5.src.rpm

From: Tomas Henzl <thenzl@redhat.com>
Date: Thu, 23 Sep 2010 14:26:56 +0200
Subject: [scsi] megaraid_sas: fix physical disk handling
Message-id: <4C9B4790.2050406@redhat.com>
O-Subject: [RHEL5.5.z PATCH] bz#619365 megaraid_sas: fix physical disk handling
Bugzilla: 619365
RH-Acked-by: Rob Evers <revers@redhat.com>

This is for bz#619365

The patch comes from Bo Yang LSI.
The megaraid_sas driver in RHEL4 has a problem with handling physical disks and
management ioctls; all physical disks are exported to the disk layer allowing
an oops in megasas_complete_cmd_dpc when completing the ioctl command if a
timeout occurs.

This is a backport of a RHEL5.6 patch - "megaraid_sas: update driver to version 4.31"
it is shortened and adapted to 5.5.

I did some basic testing on i686 + x86_64.

Brew build - task_2775409

Tomas



diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 8965842..ad6fc9f 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -1,27 +1,24 @@
 /*
  *
- *		Linux MegaRAID driver for SAS based RAID controllers
+ *Linux MegaRAID driver for SAS based RAID controllers
  *
- * Copyright (c) 2003-2005  LSI Corporation.
+ * Copyright (c) 2009  LSI Corporation.
  *
- *	   This program is free software; you can redistribute it and/or
- *	   modify it under the terms of the GNU General Public License
- *	   as published by the Free Software Foundation; either version
- *	   2 of the License, or (at your option) any later version.
+ *This program is free software; you can redistribute it and/or
+ *modify it under the terms of the GNU General Public License
+ *as published by the Free Software Foundation; either version 2
+ *of the License, or (at your option) any later version.
  *
- * FILE		: megaraid_sas.c
- * Version	: v00.00.04.17-RH1
+ *This program is distributed in the hope that it will be useful,
+ *but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *GNU General Public License for more details.
  *
- * Authors:
- *	(email-id : megaraidlinux@lsi.com)
- * 	Sreenivas Bagalkote
- * 	Sumant Patro
- *	Bo Yang
- *
- * List of supported controllers
- *
- * OEM	Product Name			VID	DID	SSVID	SSID
- * ---	------------			---	---	----	----
+ *You should have received a copy of the GNU General Public License
+ *along with this program; if not, write to the Free Software
+ *Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * 
+ * Send feedback to <Bo.Yang@lsi.com>
  */
 
 #include <linux/kernel.h>
@@ -33,6 +30,7 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
+#include <linux/smp_lock.h>
 #include <linux/uio.h>
 #include <asm/uaccess.h>
 #include <linux/fs.h>
@@ -40,7 +38,6 @@
 #include <linux/blkdev.h>
 #include <linux/mutex.h>
 #include <linux/poll.h>
-#include <linux/smp_lock.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -49,10 +46,6 @@
 #include "megaraid_sas.h"
 
 /*
- * Modules parameters
- */
-
-/*
  * poll_mode_io:1- schedule complete completion from q cmd
  */
 static unsigned int poll_mode_io;
@@ -60,6 +53,16 @@ module_param_named(poll_mode_io, poll_mode_io, int, 0);
 MODULE_PARM_DESC(poll_mode_io,
 	"Complete cmds from IO path, (default=0)");
 
+/*
+ * Number of sectors per IO command
+ * Will be set in megasas_init_mfi if user does not provide
+ */
+static unsigned int max_sectors;
+module_param_named(max_sectors, max_sectors, int, 0);
+MODULE_PARM_DESC(max_sectors,
+	"Maximum number of sectors per IO command");
+
+
 MODULE_LICENSE("GPL");
 MODULE_VERSION(MEGASAS_VERSION);
 MODULE_AUTHOR("megaraidlinux@lsi.com");
@@ -74,6 +77,8 @@ static struct pci_device_id megasas_pci_table[] = {
 	/* xscale IOP */
 	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)},
 	/* ppc IOP */
+	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)},
+	/* ppc IOP */
 	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078GEN2)},
 	/* gen2*/
 	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)},
@@ -82,8 +87,6 @@ static struct pci_device_id megasas_pci_table[] = {
 	/* skinny*/
 	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)},
 	/* skinny*/
-	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)},
-	/* ppc IOP */
 	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)},
 	/* xscale IOP, vega */
 	{PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
@@ -99,13 +102,12 @@ static struct fasync_struct *megasas_async_queue;
 static DEFINE_MUTEX(megasas_async_queue_mutex);
 static DEFINE_MUTEX(megasas_poll_wait_mutex);
 
-
 static int megasas_poll_wait_aen;
-static DECLARE_WAIT_QUEUE_HEAD (megasas_poll_wait);
-extern void
-poll_wait(struct file *filp, wait_queue_head_t *q, poll_table *token);
-
+static DECLARE_WAIT_QUEUE_HEAD ( megasas_poll_wait );
 static u32 support_poll_for_event;
+static u32 support_device_change;
+
+/* define lock for aen poll */
 spinlock_t poll_aen_lock;
 
 static u32 megasas_dbg_lvl;
@@ -113,6 +115,11 @@ static u32 megasas_dbg_lvl;
 static void
 megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 		     u8 alt_status);
+static int megasas_transition_to_ready(struct megasas_instance* instance);
+static int megasas_get_pd_list(struct megasas_instance *instance);
+static int megasas_issue_init_mfi(struct megasas_instance *instance);
+static int megasas_register_aen(struct megasas_instance *instance, u32 seq_num, u32 class_locale_word);
+
 /**
  * megasas_get_cmd -	Get a command from the free pool
  * @instance:		Adapter soft state
@@ -170,7 +177,7 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
 static inline void
 megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
 {
-	writel(1, &(regs)->outbound_intr_mask);
+	writel(0, &(regs)->outbound_intr_mask);
 
 	/* Dummy readl to force pci flush */
 	readl(&regs->outbound_intr_mask);
@@ -206,24 +213,27 @@ static int
 megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
 {
 	u32 status;
+	u32 mfiStatus = 0;
 	/*
 	 * Check if it is our interrupt
 	 */
 	status = readl(&regs->outbound_intr_status);
 
-	if (!(status & MFI_OB_INTR_STATUS_MASK)) {
-		return 1;
-	}
+	if (status & MFI_OB_INTR_STATUS_MASK)
+		mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
+	if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT)
+		mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
 
 	/*
 	 * Clear the interrupt by writing back the same value
 	 */
-	writel(status, &regs->outbound_intr_status);
+	if (mfiStatus)
+		writel(status, &regs->outbound_intr_status);
 
 	/* Dummy readl to force pci flush */
 	readl(&regs->outbound_intr_status);
-
-	return 0;
+	
+	return mfiStatus;
 }
 
 /**
@@ -233,10 +243,69 @@ megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs)
  * @regs :			MFI register set
  */
 static inline void 
-megasas_fire_cmd_xscale(struct megasas_instance *instance, dma_addr_t frame_phys_addr,u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_xscale(struct megasas_instance *instance,
+		dma_addr_t frame_phys_addr,
+		u32 frame_count,
+		struct megasas_register_set __iomem *regs)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&instance->hba_lock, flags);
 	writel((frame_phys_addr >> 3)|(frame_count),
 	       &(regs)->inbound_queue_port);
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
+}
+
+/**
+ * megasas_adp_reset_xscale -	For controller reset
+ * @regs:				MFI register set
+ */
+static int
+megasas_adp_reset_xscale(struct megasas_instance *instance, struct megasas_register_set __iomem * regs)
+{
+	u32 i;
+	u32 pcidata;
+	writel(MFI_ADP_RESET, &regs->inbound_doorbell);
+
+	for (i=0; i < 3; i++)
+		msleep(1000); /* sleep for 3 secs */
+	pcidata =0;
+	pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata);
+	printk("pcidata = %x\n", pcidata);
+	if (pcidata & 0x2) {
+		printk("mfi 1068 offset read=%x\n", pcidata);
+		pcidata &= ~0x2;
+		pci_write_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, pcidata);
+
+		for (i=0; i<2; i++)
+			msleep(1000); /* need to wait 2 secs again */
+
+		pcidata =0;
+		pci_read_config_dword(instance->pdev, MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata);
+		printk("mfi 1068 offset handshake read=%x\n", pcidata);
+		if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) {
+			printk("mfi 1068 offset handshake=%x\n", pcidata);
+			pcidata = 0;
+			pci_write_config_dword(instance->pdev, MFI_1068_FW_HANDSHAKE_OFFSET, pcidata);
+		}
+	}
+	return 0;
+}
+
+/**
+ * megasas_check_reset_xscale -	For controller reset check
+ * @regs:				MFI register set
+ */
+static int 
+megasas_check_reset_xscale(struct megasas_instance *instance, struct megasas_register_set __iomem * regs)
+{
+	u32 consumer;
+	consumer = *instance->consumer;
+
+	if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) && (*instance->consumer == MEGASAS_ADPRESET_INPROG_SIGN)) {
+		return 1;
+	}
+
+	return 0;
 }
 
 static struct megasas_instance_template megasas_instance_template_xscale = {
@@ -246,6 +315,8 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
 	.disable_intr = megasas_disable_intr_xscale,
 	.clear_intr = megasas_clear_intr_xscale,
 	.read_fw_status_reg = megasas_read_fw_status_reg_xscale,
+	.adp_reset = megasas_adp_reset_xscale,
+	.check_reset = megasas_check_reset_xscale,
 };
 
 /**
@@ -267,14 +338,14 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
 {
 	writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
     
-	writel(~0x80000004, &(regs)->outbound_intr_mask);
+	writel(~0x80000000, &(regs)->outbound_intr_mask);
 
 	/* Dummy readl to force pci flush */
 	readl(&regs->outbound_intr_mask);
 }
 
 /**
- * megasas_disable_intr_ppc -	Disables interrupt
+ * megasas_disable_intr_ppc -	Disable interrupt
  * @regs:			MFI register set
  */
 static inline void
@@ -310,7 +381,7 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
 	status = readl(&regs->outbound_intr_status);
 
 	if (!(status & MFI_REPLY_1078_MESSAGE_INTERRUPT)) {
-		return 1;
+		return 0;
 	}
 
 	/*
@@ -321,7 +392,7 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
 	/* Dummy readl to force pci flush */
 	readl(&regs->outbound_doorbell_clear);
 
-	return 0;
+	return 1;
 }
 /**
  * megasas_fire_cmd_ppc -	Sends command to the FW
@@ -330,10 +401,36 @@ megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs)
  * @regs :			MFI register set
  */
 static inline void 
-megasas_fire_cmd_ppc(struct megasas_instance *instance, dma_addr_t frame_phys_addr, u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_ppc(struct megasas_instance *instance,
+		dma_addr_t frame_phys_addr,
+		u32 frame_count,
+		struct megasas_register_set __iomem *regs)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&instance->hba_lock, flags);
 	writel((frame_phys_addr | (frame_count<<1))|1, 
 			&(regs)->inbound_queue_port);
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
+}
+
+/**
+ * megasas_adp_reset_ppc -	For controller reset
+ * @regs:				MFI register set
+ */
+static int 
+megasas_adp_reset_ppc(struct megasas_instance *instance, struct megasas_register_set __iomem * regs)
+{
+	return 0;
+}
+
+/**
+ * megasas_check_reset_ppc -	For controller reset check
+ * @regs:				MFI register set
+ */
+static int 
+megasas_check_reset_ppc(struct megasas_instance *instance, struct megasas_register_set __iomem * regs)
+{
+	return 0;
 }
 
 static struct megasas_instance_template megasas_instance_template_ppc = {
@@ -343,6 +440,8 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
 	.disable_intr = megasas_disable_intr_ppc,
 	.clear_intr = megasas_clear_intr_ppc,
 	.read_fw_status_reg = megasas_read_fw_status_reg_ppc,
+	.adp_reset = megasas_adp_reset_ppc,
+	.check_reset = megasas_check_reset_ppc,
 };
 
 /**
@@ -399,7 +498,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem * regs)
 	status = readl(&regs->outbound_intr_status);
 
 	if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) {
-		return 1;
+		return 0;
 	}
 
 	/*
@@ -412,7 +511,7 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem * regs)
 	*/
 	readl(&regs->outbound_intr_status);
 
-	return 0;
+	return 1;
 }
 /**
  * megasas_fire_cmd_skinny -	Sends command to the FW
@@ -421,17 +520,40 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem * regs)
  * @regs :			MFI register set
  */
 static inline void 
-megasas_fire_cmd_skinny(struct megasas_instance *instance, dma_addr_t frame_phys_addr, u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_skinny(struct megasas_instance *instance,
+			dma_addr_t frame_phys_addr,
+			u32 frame_count,
+			struct megasas_register_set __iomem *regs)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&instance->fire_lock, flags);
+	spin_lock_irqsave(&instance->hba_lock, flags);
 	writel(0, &(regs)->inbound_high_queue_port);
 	writel((frame_phys_addr | (frame_count<<1))|1, 
 			&(regs)->inbound_low_queue_port);
-	spin_unlock_irqrestore(&instance->fire_lock, flags);
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
 	/*msleep(5);*/
 }
 
+/**
+ * megasas_adp_reset_skinny -	For controller reset
+ * @regs:				MFI register set
+ */
+static int 
+megasas_adp_reset_skinny(struct megasas_instance *instance, struct megasas_register_set __iomem * regs)
+{
+	return 0;
+}
+
+/**
+ * megasas_check_reset_skinny -	For controller reset check
+ * @regs:				MFI register set
+ */
+static int 
+megasas_check_reset_skinny(struct megasas_instance *instance, struct megasas_register_set __iomem * regs)
+{
+	return 0;
+}
+
 static struct megasas_instance_template megasas_instance_template_skinny = {
 	
 	.fire_cmd = megasas_fire_cmd_skinny,
@@ -439,16 +561,14 @@ static struct megasas_instance_template megasas_instance_template_skinny = {
 	.disable_intr = megasas_disable_intr_skinny,
 	.clear_intr = megasas_clear_intr_skinny,
 	.read_fw_status_reg = megasas_read_fw_status_reg_skinny,
+	.adp_reset = megasas_adp_reset_skinny,
+	.check_reset = megasas_check_reset_skinny,
 };
 
-/**
-*	This is the end of set of functions & definitions
-* 	specific to ppc (deviceid : 0x60) controllers
-*/
 
 /**
 *	The following functions are defined for gen2 (deviceid : 0x78 0x79)
-* 	controllers
+*	controllers
 */
 
 /**
@@ -456,10 +576,10 @@ static struct megasas_instance_template megasas_instance_template_skinny = {
  * @regs:			MFI register set
  */
 static inline void
-megasas_enable_intr_gen2(struct megasas_register_set __iomem *regs)
+megasas_enable_intr_gen2(struct megasas_register_set __iomem * regs)
 {
 	writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear);
-
+    
 	/* write ~0x00000005 (4 & 1) to the intr mask*/
 	writel(~MFI_GEN2_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask);
 
@@ -485,7 +605,7 @@ megasas_disable_intr_gen2(struct megasas_register_set __iomem * regs)
  * @regs:			MFI register set
  */
 static u32
-megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs)
+megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem * regs)
 {
 	return readl(&(regs)->outbound_scratch_pad);
 }
@@ -495,28 +615,33 @@ megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs)
  * @regs:				MFI register set
  */
 static int
-megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
+megasas_clear_intr_gen2(struct megasas_register_set __iomem * regs)
 {
 	u32 status;
+	u32 mfiStatus = 0;
 	/*
 	 * Check if it is our interrupt
 	 */
 	status = readl(&regs->outbound_intr_status);
 
-	if (!(status & MFI_GEN2_ENABLE_INTERRUPT_MASK)) {
-		return 1;
-	}
+	if (status & MFI_GEN2_ENABLE_INTERRUPT_MASK)
+                mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE;
+
+	if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT)
+                mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE;
 
 	/*
 	 * Clear the interrupt by writing back the same value
 	 */
-	writel(status, &regs->outbound_doorbell_clear);
+	if (mfiStatus)
+		writel(status, &regs->outbound_doorbell_clear);
 
 	/* Dummy readl to force pci flush */
 	readl(&regs->outbound_intr_status);
 
-	return 0;
+	return mfiStatus;
 }
+
 /**
  * megasas_fire_cmd_gen2 -	Sends command to the FW
  * @frame_phys_addr :		Physical address of cmd
@@ -524,31 +649,97 @@ megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
  * @regs :			MFI register set
  */
 static inline void
-megasas_fire_cmd_gen2(struct megasas_instance *instance, dma_addr_t frame_phys_addr,
-			u32 frame_count, struct megasas_register_set __iomem *regs)
+megasas_fire_cmd_gen2(struct megasas_instance *instance,
+			dma_addr_t frame_phys_addr,
+			u32 frame_count,
+			struct megasas_register_set __iomem *regs)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&instance->fire_lock, flags);
-	writel((frame_phys_addr | (frame_count<<1))|1, 
+	spin_lock_irqsave(&instance->hba_lock, flags);
+	writel((frame_phys_addr | (frame_count<<1))|1,
 			&(regs)->inbound_queue_port);
-	spin_unlock_irqrestore(&instance->fire_lock, flags);
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
 }
 
-static struct megasas_instance_template megasas_instance_template_gen2 = {
+/**
+ * megasas_adp_reset_gen2 -     For controller reset
+ * @regs:                               MFI register set
+ */
+static int
+megasas_adp_reset_gen2(struct megasas_instance *instance, struct megasas_register_set __iomem * reg_set)
+{
+	u32 retry = 0, delay = 0;
+	u32 HostDiag;
+
+	writel(0, &reg_set->seq_offset);
+	writel(4, &reg_set->seq_offset);
+ 	writel(0xb, &reg_set->seq_offset);
+	writel(2, &reg_set->seq_offset);
+	writel(7, &reg_set->seq_offset);
+	writel(0xd, &reg_set->seq_offset);
+
+	msleep(1000);
+
+	HostDiag = (u32)readl(&reg_set->host_diag);
+
+	while ( !( HostDiag & DIAG_WRITE_ENABLE) )
+	{
+		msleep(100);
+		HostDiag = (u32)readl(&reg_set->host_diag);
+		printk("ADP_RESET_GEN2: retry time=%x, hostdiag=%x\n", retry, HostDiag);
+
+		if (retry++ >= 100)
+			return 1;
+	}
+
+	printk("ADP_RESET_GEN2: HostDiag=%x\n", HostDiag);
 
+	writel((HostDiag | DIAG_RESET_ADAPTER), &reg_set->host_diag);
+
+	for (delay=0; delay<10; delay++)
+                msleep(1000);
+
+	HostDiag = (u32)readl(&reg_set->host_diag);
+	while ( ( HostDiag & DIAG_RESET_ADAPTER) )
+	{
+		msleep(100);
+		HostDiag = (u32)readl(&reg_set->host_diag);
+		printk("ADP_RESET_GEN2: retry time=%x, hostdiag=%x\n", retry, HostDiag);
+
+		if (retry++ >= 1000)
+			return 1;
+	}
+	return 0;
+}
+
+/**
+ * megasas_check_reset_gen2 -   For controller reset check
+ * @regs:                               MFI register set
+ */
+static int
+megasas_check_reset_gen2(struct megasas_instance *instance, struct megasas_register_set __iomem * regs)
+{
+	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL)
+		return 1;
+
+	return 0;
+}
+
+static struct megasas_instance_template megasas_instance_template_gen2 = {
 	.fire_cmd = megasas_fire_cmd_gen2,
 	.enable_intr = megasas_enable_intr_gen2,
 	.disable_intr = megasas_disable_intr_gen2,
 	.clear_intr = megasas_clear_intr_gen2,
 	.read_fw_status_reg = megasas_read_fw_status_reg_gen2,
+        .adp_reset = megasas_adp_reset_gen2,
+        .check_reset = megasas_check_reset_gen2,
 };
 
 /**
- *      This is the end of set of functions & definitions
+ *	This is the end of set of functions & definitions
  *      specific to gen2 (deviceid : 0x78, 0x79) controllers
  */
 
-
 /**
  * megasas_issue_polled -	Issues a polling command
  * @instance:			Adapter soft state
@@ -570,7 +761,8 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
 	/*
 	 * Issue the frame using inbound queue port
 	 */
-	instance->instancet->fire_cmd(instance, cmd->frame_phys_addr ,0,instance->reg_set);
+	instance->instancet->fire_cmd(instance,
+			cmd->frame_phys_addr, 0, instance->reg_set);
 
 	/*
 	 * Wait for cmd_status to change
@@ -601,10 +793,10 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
 {
 	cmd->cmd_status = ENODATA;
 
-	instance->instancet->fire_cmd(instance, cmd->frame_phys_addr ,0,instance->reg_set);
+	instance->instancet->fire_cmd(instance,
+			cmd->frame_phys_addr, 0, instance->reg_set);
 
-	wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
-		MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
+	wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA);
 
 	return 0;
 }
@@ -646,13 +838,14 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
 	cmd->sync_cmd = 1;
 	cmd->cmd_status = 0xFF;
 
-	instance->instancet->fire_cmd(instance, cmd->frame_phys_addr ,0,instance->reg_set);
+	instance->instancet->fire_cmd(instance,
+			cmd->frame_phys_addr, 0, instance->reg_set);
 
 	/*
 	 * Wait for this cmd to complete
 	 */
-	wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
-		MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
+	wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF);
+	cmd->sync_cmd = 0;
 
 	megasas_return_cmd(instance, cmd);
 	return 0;
@@ -756,7 +949,7 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
 }
 
 /**
- * megasas_make_sgl_kinny -	Prepares 64-bit IEEE SGL
+ * megasas_make_sgl_skinny - Prepares IEEE SGL
  * @instance:		Adapter soft state
  * @scp:		SCSI command from the mid-layer
  * @mfi_sgl:		SGL to be filled in
@@ -799,6 +992,7 @@ megasas_make_sgl_skinny(struct megasas_instance *instance, struct scsi_cmnd *scp
 	for (i = 0; i < sge_count; i++, os_sgl++) {
 		mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
 		mfi_sgl->sge_skinny[i].phys_addr = sg_dma_address(os_sgl);
+		mfi_sgl->sge_skinny[i].flag = 0;
 	}
 
 	return sge_count;
@@ -806,8 +1000,8 @@ megasas_make_sgl_skinny(struct megasas_instance *instance, struct scsi_cmnd *scp
 
  /**
  * megasas_get_frame_count - Computes the number of frames
- * @sge_count		: number of sg elements
  * @frame_type		: type of frame- io or pthru frame
+ * @sge_count		: number of sg elements
  *
  * Returns the number of frames required for numnber of sge's (sge_count)
  */
@@ -915,14 +1109,14 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
 	memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
 
 	/*
-	* If the command is for the tape device, set the
-	* pthru timeout to the os layer timeout value.
-	*/
+	 * If the command is for the tape device, set the
+	 * pthru timeout to the os layer timeout value.
+	 */
 	if(scp->device->type == TYPE_TAPE) {
 		if((scp->timeout_per_command / HZ) > 0xFFFF)
-                    pthru->timeout = 0xFFFF;
-            	else
-                    pthru->timeout = scp->timeout_per_command / HZ;
+			pthru->timeout = 0xFFFF;
+		else
+			pthru->timeout = scp->timeout_per_command / HZ;
 	}
 
 	/*
@@ -965,7 +1159,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
  * megasas_build_ldio -	Prepares IOs to logical devices
  * @instance:		Adapter soft state
  * @scp:		SCSI command
- * @cmd:		Command to to be prepared
+ * @cmd:		Command to be prepared
  *
  * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
  */
@@ -989,7 +1183,6 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
 	if (instance->flag_ieee == 1) {
 		flags |= MFI_FRAME_IEEE;
 	}
-	
 
 	/*
 	 * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
@@ -1073,7 +1266,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
 
         if (ldio->sge_count > instance->max_num_sge) {
         	printk("megasas: build_ld_io  error, sge_count = %x\n", ldio->sge_count);
-	        return 0;
+		return 0;
 	}
 
 	/*
@@ -1087,7 +1280,8 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
 	 * Compute the total number of frames this command consumes. FW uses
 	 * this number to pull sufficient number of frames from host memory.
 	 */
-	cmd->frame_count = megasas_get_frame_count(instance, ldio->sge_count, IO_FRAME);
+	cmd->frame_count = megasas_get_frame_count(instance,
+			ldio->sge_count, IO_FRAME);
 
 	return cmd->frame_count;
 }
@@ -1192,13 +1386,25 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
 	u32 frame_count;
 	struct megasas_cmd *cmd;
 	struct megasas_instance *instance;
+	unsigned long flags;
 
 	instance = (struct megasas_instance *)
 	    scmd->device->host->hostdata;
 
-	/* Don't process if we have already declared adapter dead */
-	if (instance->hw_crit_error)
+        if (instance->issuepend_done == 0)
+                return SCSI_MLQUEUE_HOST_BUSY;
+
+	spin_lock_irqsave(&instance->hba_lock, flags);
+
+	//Don't process if we have already declared adapter dead
+	// If we are in middle of bringing up the HBA, send the busy status to mid-layer
+	// till the process is complete
+	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
 
 	scmd->scsi_done = done;
 	scmd->result = 0;
@@ -1244,8 +1450,8 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
 	 */
 	atomic_inc(&instance->fw_outstanding);
 
-	instance->instancet->fire_cmd(instance, cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
-
+	instance->instancet->fire_cmd(instance, cmd->frame_phys_addr,
+				cmd->frame_count-1, instance->reg_set);
 	/*
 	 * Check if we have pend cmds to be completed
 	 */
@@ -1289,17 +1495,21 @@ static int megasas_slave_configure(struct scsi_device *sdev)
 	 * 	  That will be fixed once LSI engineers have audited the
 	 * 	  firmware for possible issues.
 	 */
-	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && sdev->type == TYPE_DISK) {
-		pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
-		
-		if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
-			sdev->timeout = 90 * HZ;
+	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) {
+		if (sdev->type == TYPE_TAPE) {
+			sdev->timeout = MEGASAS_DEFAULT_CMD_TIMEOUT * HZ;
 			return 0;
+		} else if (sdev->type == TYPE_DISK) {
+			pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
+			if ((instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) &&
+				(instance->pd_list[pd_index].driveType == TYPE_DISK)) {
+				sdev->timeout = MEGASAS_DEFAULT_CMD_TIMEOUT * HZ;
+				return 0;
+			}
 		}
-	
 		return -ENXIO;
 	}
-	
+
 	/*
 	 * The RAID firmware may require extended timeouts.
 	 */
@@ -1307,18 +1517,34 @@ static int megasas_slave_configure(struct scsi_device *sdev)
 	return 0;
 }
 
+static void process_fw_state_change_wq(void *instance);
+
+static void megaraid_sas_kill_hba(struct megasas_instance *instance)
+{
+       if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY))
+       {
+               writel(MFI_STOP_ADP,
+                       &instance->reg_set->reserved_0[0]);
+       } else {
+               writel(MFI_STOP_ADP,
+                       &instance->reg_set->inbound_doorbell);
+       }
+}
+
 static int megasas_slave_alloc(struct scsi_device *sdev)
 {
 	u16		pd_index = 0;
 	struct megasas_instance *instance ;
 	instance = megasas_lookup_instance(sdev->host->host_no);
-
-	if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && sdev->type == TYPE_DISK) {
+	if ((sdev->channel < MEGASAS_MAX_PD_CHANNELS) &&
+				(sdev->type == TYPE_DISK)) {
 		/*
 		 * Open the OS scan to the SYSTEM PD
 		 */
 		pd_index =
-		    (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + sdev->id;
+			(sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+			sdev->id;
 		if ((instance->pd_list[pd_index].driveState ==
 			MR_PD_STATE_SYSTEM) &&
 			(instance->pd_list[pd_index].driveType ==
@@ -1331,7 +1557,6 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
 	return 0;
 }
 
-
 /**
  * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
  * @instance_addr:			Address of adapter soft state
@@ -1349,8 +1574,9 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
 	unsigned long flags;
 
 	/* If we have already declared adapter dead, donot complete cmds */
-	if (instance->hw_crit_error)
+	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR ) { 
 		return;
+	}
 
 	spin_lock_irqsave(&instance->completion_lock, flags);
 
@@ -1360,6 +1586,10 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
 	while (consumer != producer) {
 		context = instance->reply_queue[consumer];
 
+		if (context >= instance->max_fw_cmds) {
+			printk("ERROR ERROR: unexpected context value %x\n", context);
+			BUG();
+		}
 		cmd = instance->cmd_list[context];
 
 		megasas_complete_cmd(instance, cmd, DID_OK);
@@ -1371,7 +1601,6 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
 	}
 
 	*instance->consumer = producer;
-
 	spin_unlock_irqrestore(&instance->completion_lock, flags);
 
 	/*
@@ -1383,11 +1612,12 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
 
 		spin_lock_irqsave(instance->host->host_lock, flags);
 		instance->flag &= ~MEGASAS_FW_BUSY;
-		if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-			(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+		if ((instance->pdev->device ==
+			PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+			(instance->pdev->device ==
+			PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
 			instance->host->can_queue =
 				instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
-			
 		} else 
 			instance->host->can_queue =
 				instance->max_fw_cmds - MEGASAS_INT_CMDS;
@@ -1397,6 +1627,25 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
 
 }
 
+static void megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
+
+void megasas_do_ocr(struct megasas_instance *instance)
+{
+	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
+		(instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
+		(instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR))
+	{
+		*instance->consumer     = MEGASAS_ADPRESET_INPROG_SIGN;
+	}
+
+	instance->instancet->disable_intr(instance->reg_set);
+	instance->adprecovery   = MEGASAS_ADPRESET_SM_INFAULT;
+	instance->issuepend_done = 0;
+	atomic_set(&instance->fw_outstanding, 0);
+	megasas_internal_reset_defer_cmds(instance);
+	process_fw_state_change_wq(instance);
+}
+
 /**
  * megasas_wait_for_outstanding -	Wait for all outstanding cmds
  * @instance:				Adapter soft state
@@ -1407,9 +1656,86 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
  */
 static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 {
-	int i;
+	int i, sl;
+	u32 reset_index;
 	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
+	u8 adprecovery;
+	unsigned long flags;
+	struct list_head clist_local;
+	struct megasas_cmd *reset_cmd;
+	u32 fw_state;
+	u8 kill_adapter_flag;
+
 
+	/* If we are in-process if internal reset, we should wait for that process to complete */
+	spin_lock_irqsave(&instance->hba_lock, flags);
+	adprecovery = instance->adprecovery;
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
+
+	if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+
+		/**
+		 *  We take the ownership of all the pending commands. These would be failed to the OS
+		 *  after a successful recovery from adapter internal reset condition.
+		 */
+
+		INIT_LIST_HEAD(&clist_local);
+		spin_lock_irqsave(&instance->hba_lock, flags);
+		list_splice_init(&instance->internal_reset_pending_q, &clist_local);
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
+
+		printk("megasas: HBA reset handler invoked while adapter internal reset in progress, wait till that's over...\n");
+		for (i = 0; i < wait_time; i++) {
+			msleep(1000);
+			spin_lock_irqsave(&instance->hba_lock, flags);
+			adprecovery = instance->adprecovery;
+			spin_unlock_irqrestore(&instance->hba_lock, flags);
+			if (adprecovery == MEGASAS_HBA_OPERATIONAL)
+				break;
+		}
+
+		/* Are we out of reset yet? If not, HBA is toasted :-( */
+		if (adprecovery != MEGASAS_HBA_OPERATIONAL) {
+			printk("megasas: HBA reset handler timedout for internal reset. Stopping the HBA.\n");
+			spin_lock_irqsave(&instance->hba_lock, flags);
+			instance->adprecovery	= MEGASAS_HW_CRITICAL_ERROR;
+			spin_unlock_irqrestore(&instance->hba_lock, flags);
+			return FAILED;
+		}
+
+		printk("megasas: HBA internal reset condition discovered to be cleared.\n");
+
+		/* Send the pending commands back to the OS with reset condition */
+		reset_index	= 0;
+		while (!list_empty(&clist_local)) {
+			reset_cmd	= list_entry((&clist_local)->next, struct megasas_cmd, list);
+			list_del_init(&reset_cmd->list);
+			if (reset_cmd->scmd) {
+				reset_cmd->scmd->result = DID_RESET << 16;
+				printk("megasas: %d:%p reset scsi command [%02x], %#lx\n",
+					reset_index, reset_cmd, reset_cmd->scmd->cmnd[0], reset_cmd->scmd->serial_number);
+				reset_cmd->scmd->scsi_done(reset_cmd->scmd);
+				megasas_return_cmd(instance, reset_cmd);
+			}
+			else if (reset_cmd->sync_cmd) {
+				// Such commands have no timeout, we re-issue this guy again.
+				printk("megasas: %p synchronous command detected on the internal reset queue, re-issuing it.\n", reset_cmd);
+				reset_cmd->cmd_status = ENODATA;
+				instance->instancet->fire_cmd(instance, reset_cmd->frame_phys_addr ,0,instance->reg_set);
+			}
+			else {
+				printk("megasas: %p unexpected command on the internal reset defer list.\n", reset_cmd);
+			}
+			reset_index++;
+		}
+
+		printk("megaraid_sas: All pending commands have been cleared for reset condition.\n");
+
+		return SUCCESS;
+	}
+
+	/* Kernel reset without internal reset in progress */
+	printk("megaraid_sas: HBA reset handler invoked without an internal reset condition.\n");
 	for (i = 0; i < wait_time; i++) {
 
 		int outstanding = atomic_read(&instance->fw_outstanding);
@@ -1420,6 +1746,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
 			printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
 			       "commands to complete\n",i,outstanding);
+
 			/*
 			 * Call cmd completion routine. Cmd to be
 			 * be completed directly without depending on isr.
@@ -1430,14 +1757,60 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 		msleep(1000);
 	}
 
-	if (atomic_read(&instance->fw_outstanding)) {
+        /**
+        for the fw state fault case, driver need to reset three times before kill adapter.
+        */
+        i = 0;
+        kill_adapter_flag = 0;
+        do {
+                fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+                if ((fw_state == MFI_STATE_FAULT) && (instance->disableOnlineCtrlReset == 0)) {
+                        printk("megasas: waiting_for_outstanding: before issue OCR. FW state = %x\n", fw_state);
+                        if (i == 3) {
+                                kill_adapter_flag = 2;
+                                break;
+                        }
+                        megasas_do_ocr(instance);
+                       kill_adapter_flag = 1;
+                        printk("megasas: waiting_for_outstanding: after issue OCR. \n");
+
+                        /* wait for 5 secs to let the FW finish all the pending cmds*/
+                        for (sl=0; sl<10; sl++)
+                                msleep(500);
+                }
+                       i++;
+        } while (i <= 3);
+
+        /**
+        for the fw state not fault case, it is maybe fw hang, driver need to reset the controller before kill the adapter.
+        */
+        if (atomic_read(&instance->fw_outstanding) && !kill_adapter_flag) {
+                if (instance->disableOnlineCtrlReset == 0) {
+                        printk("megasas: waiting_for_outstanding: before issue OCR. FW state = %x\n", fw_state);
+                        megasas_do_ocr(instance);
+                        printk("megasas: waiting_for_outstanding: after issue OCR. \n");
+
+                        /* wait for 5 secs to let the FW finish all the pending cmds*/
+                        for (i = 0; i < wait_time; i++) {
+                                int outstanding = atomic_read(&instance->fw_outstanding);
+
+                                if (!outstanding)
+                                        return SUCCESS;
+                                msleep(1000);
+                        }
+                }
+        }
+
+        if (atomic_read(&instance->fw_outstanding) || (kill_adapter_flag == 2)) {
+		printk("megaraid_sas: pending commands remain even after reset handling.\n");
 		/*
 		* Send signal to FW to stop processing any pending cmds.
 		* The controller will be taken offline by the OS now.
 		*/
-		if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-			(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY))
-		{
+		if ((instance->pdev->device ==
+			PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+			(instance->pdev->device ==
+			PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
 			writel(MFI_STOP_ADP,
 				&instance->reg_set->reserved_0[0]);
 		} else {
@@ -1445,10 +1818,14 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 				&instance->reg_set->inbound_doorbell);
 		}
 		megasas_dump_pending_frames(instance);
-		instance->hw_crit_error = 1;
+		spin_lock_irqsave(&instance->hba_lock, flags);
+		instance->adprecovery	= MEGASAS_HW_CRITICAL_ERROR;
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
 		return FAILED;
 	}
 
+	printk("megaraid_sas: no more pending commands remain after reset handling.\n");
+
 	return SUCCESS;
 }
 
@@ -1470,7 +1847,7 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
 	scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n",
 		 scmd->serial_number, scmd->cmnd[0], scmd->retries);
 
-	if (instance->hw_crit_error) {
+	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR ) {
 		printk(KERN_ERR "megasas: cannot recover from previous reset "
 		       "failures\n");
 		return FAILED;
@@ -1625,11 +2002,11 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
 
 	instance->aen_cmd = NULL;
 	megasas_return_cmd(instance, cmd);
-	if (instance->unload == 0) {
+	if ((instance->unload == 0) && ((instance->issuepend_done == 1))) {
 		struct megasas_aen_event *ev;
 		ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
 		if (!ev) {
-			printk(KERN_ERR "%s: out of memory\n", __FUNCTION__);
+			printk(KERN_ERR "megasas_service_aen: out of memory\n");
 		} else {
 			ev->instance = instance;
 			INIT_WORK(&ev->hotplug_work, megasas_aen_polling, ev);
@@ -1638,6 +2015,30 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
 	}
 }
 
+static ssize_t
+sysfs_max_sectors_read(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(class_dev);
+
+	struct megasas_instance *instance =
+				(struct megasas_instance *)host->hostdata;
+
+	return sprintf(buf,"%u\n", instance->max_sectors_per_req);
+}
+
+static struct class_device_attribute dev_attr_max_sector = {
+	.attr = {
+		.name = "max_sectors",
+		.mode = S_IRUGO,
+	},
+	.show = sysfs_max_sectors_read
+};
+
+static struct class_device_attribute *megasas_shost_sysfs_attr[] = {
+	&dev_attr_max_sector,
+	NULL,
+};
+
 /*
  * Scsi host template for megaraid_sas driver
  */
@@ -1656,6 +2057,7 @@ static struct scsi_host_template megasas_template = {
 	.eh_timed_out = megasas_reset_timer,
 	.bios_param = megasas_bios_param,
 	.use_clustering = ENABLE_CLUSTERING,
+	.shost_attrs	= megasas_shost_sysfs_attr,
 };
 
 /**
@@ -1724,8 +2126,7 @@ megasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd)
 	opcode = cmd->frame->hdr.cmd;
 
 	if ((opcode == MFI_CMD_LD_READ) || (opcode == MFI_CMD_LD_WRITE)) {
-		if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-		(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+		if (instance->flag_ieee) {
 			buf_h = cmd->frame->io.sgl.sge_skinny[0].phys_addr;
 
 		} else if (IS_DMA64)
@@ -1733,8 +2134,7 @@ megasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd)
 		else
 			buf_h = cmd->frame->io.sgl.sge32[0].phys_addr;
 	} else {
-		if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-		(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+		if (instance->flag_ieee) {
 			buf_h = cmd->frame->pthru.sgl.sge_skinny[0].phys_addr;
 
 		} else if (IS_DMA64)
@@ -1766,6 +2166,12 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 	int exception = 0;
 	struct megasas_header *hdr = &cmd->frame->hdr;
 
+       /** 
+	* If the commands complete successfully, the retry counter
+	* should also be reset for future re-tries.
+	**/
+        cmd->retry_for_fw_reset = 0;
+
 	if (cmd->scmd)
 		cmd->scmd->SCp.ptr = NULL;
 
@@ -1854,13 +2260,13 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 	case MFI_CMD_SMP:
 	case MFI_CMD_STP:
 	case MFI_CMD_DCMD:
+
 		if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO || 
 			cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
 			spin_lock_irqsave(&poll_aen_lock, flags);
 			megasas_poll_wait_aen = 0;
 			spin_unlock_irqrestore(&poll_aen_lock, flags);
 		}
-
 		/*
 		 * See if got an event notification
 		 */
@@ -1885,30 +2291,273 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 	}
 }
 
+ /**
+ * megasas_issue_pending_cmds_again -	issue all pending cmds
+ *                              	in FW again because of the fw reset
+ * @instance:				Adapter soft state
+ */
+static inline void
+megasas_issue_pending_cmds_again(struct megasas_instance *instance)
+{
+	struct megasas_cmd *cmd;
+	struct list_head clist_local;
+	union megasas_evt_class_locale class_locale;
+	unsigned long flags;
+	u32 seq_num;
+
+	INIT_LIST_HEAD(&clist_local);
+	spin_lock_irqsave(&instance->hba_lock, flags);
+	list_splice_init(&instance->internal_reset_pending_q, &clist_local);
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
+
+	while (!list_empty(&clist_local)) {
+		cmd	= list_entry((&clist_local)->next, struct megasas_cmd, list);
+		list_del_init(&cmd->list);
+
+               if (cmd->sync_cmd || cmd->scmd) {
+                       printk("megaraid_sas: command %p, %p:%d detected to be pending while HBA reset.\n", cmd, cmd->scmd, cmd->sync_cmd);
+
+                       cmd->retry_for_fw_reset++;
+
+                       /** 
+			* If a command has continuously been tried multiple times and causing
+			* a FW reset condition, no further recoveries should be performed on
+                        * the controller
+			*/
+
+                       if (cmd->retry_for_fw_reset == 3) {
+                               printk("megaraid_sas: command %p, %p:%d was tried multiple times during adapter reset. Shutting down the HBA\n", cmd, cmd->scmd, cmd->sync_cmd);
+                               megaraid_sas_kill_hba(instance);
+
+				instance->adprecovery	= MEGASAS_HW_CRITICAL_ERROR;
+                               return;
+                       }
+               }
+
+		if (cmd->sync_cmd == 1) {
+			if (cmd->scmd) {
+				printk("megaraid_sas: unexpected SCSI command attached to internal command!\n");
+			}
+			printk("megasas: %p synchronous command detected on the internal reset queue, issue it again.\n", cmd);
+			cmd->cmd_status = ENODATA;
+			instance->instancet->fire_cmd(instance,cmd->frame_phys_addr ,0,instance->reg_set);
+		} else if (cmd->scmd) {
+			printk("megasas: %p scsi command [%02x], %#lx detected on the internal reset queue, issue it again.\n", cmd, cmd->scmd->cmnd[0], cmd->scmd->serial_number);
+			atomic_inc(&instance->fw_outstanding);
+			instance->instancet->fire_cmd(instance, cmd->frame_phys_addr ,cmd->frame_count-1,instance->reg_set);
+		}
+		else {
+			printk("megasas: %p unexpected command on the internal reset defer list while re-issue!!\n", cmd);
+		}
+	}
+
+	if (instance->aen_cmd) {
+		printk("megaraid_sas: existing aen_cmd discovered in deferred processing, freeing...\n");
+		megasas_return_cmd(instance, instance->aen_cmd);
+		instance->aen_cmd	= NULL;
+	}
+
+	/*
+	* Initiate AEN (Asynchronous Event Notification)
+	*/
+	seq_num = instance->last_seq_num;
+	class_locale.members.reserved = 0;
+	class_locale.members.locale = MR_EVT_LOCALE_ALL;
+	class_locale.members.class = MR_EVT_CLASS_DEBUG;
+
+	megasas_register_aen(instance, seq_num, class_locale.word);
+}
+
+
+/**
+ * Move the internal reset pending commands to a deferred queue.
+ *
+ * We move the commands pending at internal reset time to a pending queue. This queue would
+ * be flushed after successful completion of the internal reset sequence.
+ * if the internal reset did not complete in time, the kernel reset handler would flush these
+ * commands.
+ **/
+static void megasas_internal_reset_defer_cmds(struct megasas_instance *instance)
+{
+	struct megasas_cmd *cmd;
+	int i;
+	u32 max_cmd = instance->max_fw_cmds;
+	u32 defer_index;
+	unsigned long flags;
+
+	defer_index	= 0;
+	spin_lock_irqsave(&instance->cmd_pool_lock, flags);
+	for (i = 0; i < max_cmd; i++) {
+		cmd = instance->cmd_list[i];
+		if (cmd->sync_cmd == 1 || cmd->scmd) {
+			printk("megasas: moving cmd[%d]:%p:%d:%p on the defer queue as internal reset in progress.\n",
+				defer_index, cmd, cmd->sync_cmd, cmd->scmd);
+			if (!list_empty(&cmd->list)) {
+				printk("megaraid_sas: ERROR while moving this cmd:%p, %d %p, it was discovered on some list?\n", cmd, cmd->sync_cmd, cmd->scmd);
+				list_del_init(&cmd->list);
+			}
+			defer_index++;
+			list_add_tail(&cmd->list, &instance->internal_reset_pending_q);
+		}
+	}
+	spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
+}
+
+static void process_fw_state_change_wq(void *arg)
+{
+	u32 wait;
+	unsigned long flags;
+
+	struct megasas_instance *instance = arg;
+        
+	if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) {
+                printk("megaraid_sas: error, unexpected adapter recovery state %x in %s\n", instance->adprecovery, __FUNCTION__);
+                return;
+        }
+
+	if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) {
+		printk("megaraid_sas: FW detected to be in fault state, restarting it...\n");
+
+		instance->instancet->disable_intr(instance->reg_set);
+                atomic_set(&instance->fw_outstanding, 0);
+
+                atomic_set(&instance->fw_reset_no_pci_access, 1);
+                instance->instancet->adp_reset(instance, instance->reg_set);
+                atomic_set(&instance->fw_reset_no_pci_access, 0 );
+
+		printk("megaraid_sas: FW was restarted successfully, initiating next stage...\n");
+
+		printk("megaraid_sas: HBA recovery state machine, state 2 starting...\n");
+
+                /*waitting for about 20 second before start the second init*/
+                for(wait = 0; wait < 30; wait++)
+                        msleep(1000);
+
+                if (megasas_transition_to_ready(instance))
+                {
+                        printk("megaraid_sas: out: controller is not in ready state\n");
+
+                        megaraid_sas_kill_hba(instance);
+			instance->adprecovery	= MEGASAS_HW_CRITICAL_ERROR;
+                        return ;
+                }
+
+                if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
+                        (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
+                        (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR))
+                {
+                        *instance->consumer = *instance->producer;
+                } else {
+                        *instance->consumer = 0;
+                        *instance->producer = 0;
+                }
+
+		megasas_issue_init_mfi(instance);
+
+		/**
+		 *  Setting the adapter to OPERATIONAL at this point is very important. This would
+		 * prevent other subsystems (reset, aen, and ioctls) to block till the recovery
+		 * logic has run it's course.
+		 */
+
+		spin_lock_irqsave(&instance->hba_lock, flags);
+		instance->adprecovery	= MEGASAS_HBA_OPERATIONAL;
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
+		instance->instancet->enable_intr(instance->reg_set);
+
+		printk("megaraid_sas: second stage of reset complete, FW is ready now.\n");
+
+		megasas_issue_pending_cmds_again(instance);
+		instance->issuepend_done = 1;
+
+
+	}
+	return ;
+}
+
 /**
  * megasas_deplete_reply_queue -	Processes all completed commands
  * @instance:				Adapter soft state
  * @alt_status:				Alternate status to be returned to
  * 					SCSI mid-layer instead of the status
  * 					returned by the FW
+ * Note: this must be called with hba lock held
  */
 static int
 megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
 {
-	/*
-	 * Check if it is our interrupt
-	 * Clear the interrupt 
+	u32 mfiStatus;
+	u32 fw_state;
+
+	/**
+	 * If the adapter is under a reset recovery, all interrupts coming from it must be acknowledged
+	 * if the consumer pointer value indicates so.
 	 */
-	if(instance->instancet->clear_intr(instance->reg_set))
+
+        if((mfiStatus = instance->instancet->check_reset(instance, instance->reg_set)) == 1) {
+                return IRQ_HANDLED;
+        }
+
+	/* Clear the interrupt on the HBA */
+	if((mfiStatus = instance->instancet->clear_intr(instance->reg_set)) == 0) {
 		return IRQ_NONE;
+	}
 
-	if (instance->hw_crit_error)
-		goto out_done;
-        /*
-	 * Schedule the tasklet for cmd completion
+	instance->mfiStatus = mfiStatus;
+
+	/**
+	 *  If the current soft state indicates an OPERATIONAL state _and_ now we have
+	 * detected state change, this should be FW FAULT case.
 	 */
+
+	if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) {
+		fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+
+                if (fw_state != MFI_STATE_FAULT) {
+                        printk("megaraid_sas: fw state while internal state change operational, state:%x\n", fw_state);
+                }
+
+               	if ((fw_state == MFI_STATE_FAULT) && (instance->disableOnlineCtrlReset == 0)){
+			printk("megaraid_sas: adapter reset condition is detected, waiting for it to restart...\n");
+
+                       	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
+                               	(instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
+                               	(instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR))
+                               	{
+					*instance->consumer	= MEGASAS_ADPRESET_INPROG_SIGN;
+                       	}
+
+
+			instance->instancet->disable_intr(instance->reg_set);
+			instance->adprecovery	= MEGASAS_ADPRESET_SM_INFAULT;    // indicates adapter restart stage 1 is in progress
+			instance->issuepend_done = 0;
+
+			/** 
+			 * The pending commands are moved to a deferred list. We would pick commands up and
+			 * re-issue once the reset processing is over.
+			 */
+
+			atomic_set(&instance->fw_outstanding, 0);
+			megasas_internal_reset_defer_cmds(instance);
+
+			/** 
+			 * Schedule a low-priorty thread to perform the function for current stage of
+			 * adapter reset state machine.
+			 */
+
+                       	printk("megaraid_sas: FW state detected, current:%x, reset stage:%d\n", fw_state, instance->adprecovery);
+			schedule_work(&instance->work_init);
+			return IRQ_HANDLED;
+		}
+		else {
+			printk("megaraid_sas: fw state while internal state changes, state:%x, disableOCR=%x\n",
+				fw_state, instance->disableOnlineCtrlReset);
+		}
+	}
+
+	/* Schedule the tasklet for cmd completion */
+
 	tasklet_schedule(&instance->isr_tasklet);
-out_done:
 	return IRQ_HANDLED;
 }
 
@@ -1917,8 +2566,20 @@ out_done:
  */
 static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
 {
-	return megasas_deplete_reply_queue((struct megasas_instance *)devp,
-					   DID_OK);
+	struct megasas_instance *instance;
+	unsigned long flags;
+	irqreturn_t	rc;
+      
+	if ( atomic_read( &(( (struct megasas_instance *)devp)->fw_reset_no_pci_access )) )
+                return IRQ_HANDLED;
+
+	instance = (struct megasas_instance *)devp;
+
+	spin_lock_irqsave(&instance->hba_lock, flags);
+	rc =  megasas_deplete_reply_queue(instance, DID_OK);
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
+
+	return rc;
 }
 
 /**
@@ -1946,7 +2607,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
  		       " state\n");
 
 	while (fw_state != MFI_STATE_READY) {
-	
+
 		abs_state = instance->instancet->read_fw_status_reg(instance->reg_set);
 
 		switch (fw_state) {
@@ -1960,13 +2621,17 @@ megasas_transition_to_ready(struct megasas_instance* instance)
 			/*
 			 * Set the CLR bit in inbound doorbell
 			 */
-			if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-				(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY))
-			{
-				writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+			if ((instance->pdev->device ==
+				PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+				(instance->pdev->device ==
+				PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+
+				writel(
+				  MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
 					&instance->reg_set->reserved_0[0]);
 			} else {
-				writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
+				writel(
+				    MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
 					&instance->reg_set->inbound_doorbell);
 			}
 
@@ -1975,12 +2640,13 @@ megasas_transition_to_ready(struct megasas_instance* instance)
 			break;
 
 		case MFI_STATE_BOOT_MESSAGE_PENDING:
-			if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-				(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY))
-			{
+			if ((instance->pdev->device ==
+				PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+			(instance->pdev->device ==
+				PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
 				writel(MFI_INIT_HOTPLUG,
 					&instance->reg_set->reserved_0[0]);
-			} else 
+			} else
 				writel(MFI_INIT_HOTPLUG,
 					&instance->reg_set->inbound_doorbell);
 
@@ -1993,12 +2659,15 @@ megasas_transition_to_ready(struct megasas_instance* instance)
 			 * Bring it to READY state; assuming max wait 10 secs
 			 */
 			instance->instancet->disable_intr(instance->reg_set);
-			if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-				(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY))
-			{
-				writel(MFI_RESET_FLAGS, &instance->reg_set->reserved_0[0]);
-			} else 
-				writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
+			if ((instance->pdev->device ==
+				PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+				(instance->pdev->device ==
+				PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+				writel(MFI_RESET_FLAGS,
+					&instance->reg_set->reserved_0[0]);
+			} else
+				writel(MFI_RESET_FLAGS,
+					&instance->reg_set->inbound_doorbell);
 
 			max_wait = MEGASAS_RESET_WAIT_TIME;
 			cur_state = MFI_STATE_OPERATIONAL;
@@ -2047,9 +2716,10 @@ megasas_transition_to_ready(struct megasas_instance* instance)
 		 * The cur_state should not last for more than max_wait secs
 		 */
 		for (i = 0; i < (max_wait * 1000); i++) {
-			fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &  
+			fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) &
 					MFI_STATE_MASK ;
-			curr_abs_state = instance->instancet->read_fw_status_reg(instance->reg_set);
+		curr_abs_state =
+		instance->instancet->read_fw_status_reg(instance->reg_set);
 
 			if (abs_state == curr_abs_state) {
 				msleep(1);
@@ -2065,7 +2735,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
 			       "in %d secs\n", fw_state, max_wait);
 			return -ENODEV;
 		}
-	};
+	}
  	printk(KERN_INFO "megasas: FW now in Ready state\n");
 
 	return 0;
@@ -2137,7 +2807,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
 	 */
 	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
 	    sizeof(struct megasas_sge32);
-		
+
 	if (instance->flag_ieee) {
 		sge_sz = sizeof(struct megasas_sge_skinny);
 	}
@@ -2147,6 +2817,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
 	 */
 	sgl_sz = sge_sz * instance->max_num_sge;
 	frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE;
+	frame_count = 15;
 
 	/*
 	 * We need one extra frame for the MFI command
@@ -2203,7 +2874,15 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
 			return -ENOMEM;
 		}
 
+		memset(cmd->frame, 0, total_sz);
+
 		cmd->frame->io.context = cmd->index;
+
+		/*
+		 * Initialize pad_0 to 0, otherwise it could corrupt
+		 * the value of context and cause FW crash
+		 */
+		cmd->frame->io.pad_0 = 0;
 	}
 
 	return 0;
@@ -2295,6 +2974,7 @@ static int megasas_alloc_cmds(struct megasas_instance *instance)
 		cmd = instance->cmd_list[i];
 		memset(cmd, 0, sizeof(struct megasas_cmd));
 		cmd->index = i;
+		cmd->scmd = NULL;
 		cmd->instance = instance;
 
 		list_add_tail(&cmd->list, &instance->cmd_pool);
@@ -2620,8 +3300,8 @@ megasas_issue_init_mfi(struct megasas_instance *instance)
 
 	return 0;
 
-fail_fw_init:
-	return -EINVAL;
+	fail_fw_init:
+		return -EINVAL;
 }
 
 /**
@@ -2630,7 +3310,6 @@ fail_fw_init:
  * @timer:		timer object to be initialized
  * @fn:			timer function
  * @interval:		time interval between timer function call
- *
  */
 static inline void
 megasas_start_timer(struct megasas_instance *instance,
@@ -2690,9 +3369,13 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 		(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
 		(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
 		(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0079GEN2)) {
-		instance->base_addr = pci_resource_start(instance->pdev, 1);
+			instance->base_addr = pci_resource_start(instance->pdev, 1);
+			printk("\n gen2: instance->base_addr = %x",
+				(unsigned int)instance->base_addr);
 	} else {
-		instance->base_addr = pci_resource_start(instance->pdev, 0);
+			instance->base_addr = pci_resource_start(instance->pdev, 0);
+			printk("\n ppc: instance->base_addr = %x",
+				(unsigned int)instance->base_addr);
 	}
 
 	if (pci_request_selected_regions(instance->pdev,
@@ -2742,14 +3425,13 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 	 * Get various operational parameters from status register
 	 */
 	instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
-	
 	/*
 	 * Reduce the max supported cmds by 1. This is to ensure that the
 	 * reply_q_sz (1 more than the max cmd that driver may send)
 	 * does not exceed max cmds that the FW can support
 	 */
 	instance->max_fw_cmds = instance->max_fw_cmds-1;
-	instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >> 
+	instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
 					0x10;
 	/*
 	 * Create a pool of commands
@@ -2781,6 +3463,13 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 	if (megasas_issue_init_mfi(instance))
 		goto fail_fw_init;
 
+	instance->fw_support_ieee = 0; 
+	instance->fw_support_ieee = (instance->instancet->read_fw_status_reg(reg_set) & 0x04000000); 
+
+	printk("megasas_init_mfi: fw_support_ieee=%d", instance->fw_support_ieee);
+	if (instance->fw_support_ieee)
+		instance->flag_ieee = 1;
+	
 	/** for passthrough
 	* the following function will get the PD LIST.
 	*/
@@ -2809,12 +3498,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 		    ctrl_info->max_strips_per_io;
 		max_sectors_2 = ctrl_info->max_request_size;
 
-		tmp_sectors = (max_sectors_1 < max_sectors_2)
-		    ? max_sectors_1 : max_sectors_2;
+		tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
+                instance->disableOnlineCtrlReset = ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
 	}
 
 	instance->max_sectors_per_req = instance->max_num_sge *
-						PAGE_SIZE / 512;
+					PAGE_SIZE / 512;
 	if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
 		instance->max_sectors_per_req = tmp_sectors;
 
@@ -2992,6 +3681,8 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
 			 * Previously issued event registration includes
 			 * current request. Nothing to do.
 			 */
+			printk(KERN_INFO "%s[%d]: already registered\n",
+				__FUNCTION__, instance->host->host_no);
 			return 0;
 		} else {
 			curr_aen.members.locale |= prev_aen.members.locale;
@@ -3035,13 +3726,14 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
 	dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
 	dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
 	dcmd->mbox.w[0] = seq_num;
+	instance->last_seq_num = seq_num;
 	dcmd->mbox.w[1] = curr_aen.word;
 	dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h;
 	dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail);
-	
+
 	if ( instance->aen_cmd != NULL ) {
-               megasas_return_cmd(instance, cmd);
-               return 0; 
+		megasas_return_cmd(instance, cmd);
+		return 0;
 	}
 
 	/*
@@ -3054,7 +3746,8 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
 	/*
 	 * Issue the aen registration frame
 	 */
-	instance->instancet->fire_cmd(instance, cmd->frame_phys_addr ,0,instance->reg_set);
+	instance->instancet->fire_cmd(instance,
+			cmd->frame_phys_addr, 0, instance->reg_set);
 
 	return 0;
 }
@@ -3103,10 +3796,32 @@ static int megasas_io_attach(struct megasas_instance *instance)
 	if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
 		(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
 		host->can_queue = instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
-	} else 
+	} else
 		host->can_queue = instance->max_fw_cmds - MEGASAS_INT_CMDS;
 	host->this_id = instance->init_id;
 	host->sg_tablesize = instance->max_num_sge;
+
+	/*
+	 * Check if the module parameter value for max_sectors can be used
+	 */
+	if (max_sectors && max_sectors < instance->max_sectors_per_req)
+		instance->max_sectors_per_req = max_sectors;
+	else {
+		if (max_sectors) {
+			if (((instance->pdev->device ==
+				PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
+				(instance->pdev->device ==
+				PCI_DEVICE_ID_LSI_SAS0079GEN2)) &&
+				(max_sectors <= MEGASAS_MAX_SECTORS)) {
+				instance->max_sectors_per_req = max_sectors;
+			} else {
+			printk(KERN_INFO "megasas: max_sectors should be > 0"
+				"and <= %d (or < 1MB for GEN2 controller)\n",
+				instance->max_sectors_per_req);
+			}
+		}
+	}
+
 	host->max_sectors = instance->max_sectors_per_req;
 	host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN;
 	host->max_channel = MEGASAS_MAX_CHANNELS - 1;
@@ -3127,6 +3842,7 @@ static int megasas_io_attach(struct megasas_instance *instance)
 	 */
 	scsi_scan_host(host);
 	return 0;
+
 }
 
 static int
@@ -3198,6 +3914,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	instance = (struct megasas_instance *)host->hostdata;
 	memset(instance, 0, sizeof(*instance));
 
+	atomic_set( &instance->fw_reset_no_pci_access, 0 );
+
 	instance->producer = pci_alloc_consistent(pdev, sizeof(u32),
 						  &instance->producer_h);
 	instance->consumer = pci_alloc_consistent(pdev, sizeof(u32),
@@ -3212,7 +3930,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	*instance->producer = 0;
 	*instance->consumer = 0;
 	instance->flag_ieee = 0;
-	megasas_poll_wait_aen = 0;	
+ 	instance->issuepend_done = 1;
+	instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+	megasas_poll_wait_aen = 0;
 
 	instance->evt_detail = pci_alloc_consistent(pdev,
 						    sizeof(struct
@@ -3229,6 +3949,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	 * Initialize locks and queues
 	 */
 	INIT_LIST_HEAD(&instance->cmd_pool);
+	INIT_LIST_HEAD(&instance->internal_reset_pending_q);
 
 	atomic_set(&instance->fw_outstanding,0);
 
@@ -3236,12 +3957,12 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	init_waitqueue_head(&instance->abort_cmd_wait_q);
 
 	spin_lock_init(&instance->cmd_pool_lock);
-	spin_lock_init(&instance->fire_lock);
+	spin_lock_init(&instance->hba_lock);
 	spin_lock_init(&instance->completion_lock);
-
-	sema_init(&instance->aen_mutex, 1);
 	spin_lock_init(&poll_aen_lock);
 
+	sema_init(&instance->aen_mutex, 1);
+	
 	/*
 	 * Initialize PCI related and misc parameters
 	 */
@@ -3254,7 +3975,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 		(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
 		instance->flag_ieee = 1;
 		sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
-	
 	} else 
 		sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
 	
@@ -3262,6 +3982,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	instance->flag = 0;
 	instance->unload = 1;
 	instance->last_time = 0;
+	instance->disableOnlineCtrlReset = 1;
+
+	INIT_WORK(&instance->work_init, process_fw_state_change_wq, instance);
 
 	/*
 	 * Initialize MFI Firmware
@@ -3307,7 +4030,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto fail_io_attach;
 
 	instance->unload = 0;
-	
+
 	return 0;
 
       fail_start_aen:
@@ -3354,6 +4077,9 @@ static void megasas_flush_cache(struct megasas_instance *instance)
 	struct megasas_cmd *cmd;
 	struct megasas_dcmd_frame *dcmd;
 
+	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+		return;
+
 	cmd = megasas_get_cmd(instance);
 
 	if (!cmd)
@@ -3391,6 +4117,9 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
 	struct megasas_cmd *cmd;
 	struct megasas_dcmd_frame *dcmd;
 
+	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR)
+		return;
+
 	cmd = megasas_get_cmd(instance);
 
 	if (!cmd)
@@ -3423,7 +4152,7 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
 /**
  * megasas_suspend -	driver suspend entry point
  * @pdev:		PCI device structure
- * @state:		state
+ * @state:		PCI power state to suspend routine
  */
 static int __devinit
 megasas_suspend(struct pci_dev *pdev, pm_message_t state)
@@ -3432,14 +4161,15 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state)
 	struct megasas_instance *instance;
 
 	instance = pci_get_drvdata(pdev);
-	instance->unload = 1;
 	host = instance->host;
+	instance->unload = 1;
 
 	if (poll_mode_io)
 		del_timer_sync(&instance->io_completion_timer);
 
 	megasas_flush_cache(instance);
 	megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN);
+
 	tasklet_kill(&instance->isr_tasklet);
 
 	pci_set_drvdata(instance->pdev, instance);
@@ -3477,7 +4207,7 @@ megasas_resume(struct pci_dev *pdev)
 	rval = pci_enable_device_mem(pdev);
 
 	if (rval) {
-		printk(KERN_INFO "megasas: Enable device failed\n");
+		printk(KERN_ERR "megasas: Enable device failed\n");
 		return rval;
 	}
 
@@ -3511,7 +4241,7 @@ megasas_resume(struct pci_dev *pdev)
 	 */
 	if (request_irq(pdev->irq, megasas_isr, IRQF_SHARED,
 		"megasas", instance)) {
-		printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
+		printk(KERN_ERR "megasas: Failed to register IRQ\n");
 		goto fail_irq;
 	}
 
@@ -3558,7 +4288,6 @@ fail_ready_state:
 #define megasas_suspend	NULL
 #define megasas_resume	NULL
 #endif
-
 /**
  * megasas_detach_one -	PCI hot"un"plug entry point
  * @pdev:		PCI device structure
@@ -3571,7 +4300,6 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
 
 	instance = pci_get_drvdata(pdev);
 	instance->unload = 1;
-		
 	host = instance->host;
 
 	if (poll_mode_io)
@@ -3580,6 +4308,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev)
 	scsi_remove_host(instance->host);
 	megasas_flush_cache(instance);
 	megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
+
 	tasklet_kill(&instance->isr_tasklet);
 
 	/*
@@ -3631,7 +4360,6 @@ static void megasas_shutdown(struct pci_dev *pdev)
 	instance->unload = 1;
 	megasas_flush_cache(instance);
 	megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN);
-
 }
 
 /**
@@ -3678,7 +4406,7 @@ static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
  /**
  * megasas_mgmt_poll -  char node "poll" entry point
  * */
-static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait)
+static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait) 
 {
  	unsigned int mask;
 	unsigned long flags;
@@ -3816,16 +4544,16 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
 	 */
 	if (ioc->sense_len) {
 		/*
-		 * sense_ptr points to the location that has the user
+		 * sense_buff points to the location that has the user
 		 * sense buffer address
 		 */
+
 		sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw +
 				ioc->sense_off);
-
 		if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
-				 sense, ioc->sense_len)) {
-			printk(KERN_ERR "megasas: Failed to copy out to user "
-					"sense data\n");
+				sense, ioc->sense_len)) {
+			printk(KERN_ERR "megasas: Failed to copy out to user"
+				"sense data\n");
 			error = -EFAULT;
 			goto out;
 		}
@@ -3863,6 +4591,9 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
 	struct megasas_iocpacket *ioc;
 	struct megasas_instance *instance;
 	int error;
+	int i;
+	unsigned long flags;
+	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
 
 	ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
 	if (!ioc)
@@ -3878,8 +4609,8 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
 		error = -ENODEV;
 		goto out_kfree_ioc;
 	}
-		
-	if (instance->hw_crit_error == 1) {
+
+	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
 		printk("Controller in crit error\n");
 		error = -ENODEV;
 		goto out_kfree_ioc;
@@ -3897,10 +4628,38 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
 		error = -ERESTARTSYS;
 		goto out_kfree_ioc;
 	}
+
+	// If HBA is undergoing a reset recovery, wait for that to complete
+	// before issuing this command
+	for (i = 0; i < wait_time; i++) {
+
+		spin_lock_irqsave(&instance->hba_lock, flags);
+		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+			spin_unlock_irqrestore(&instance->hba_lock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
+
+		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+			printk(KERN_NOTICE "megasas: waiting for controller reset to finish\n");
+		}
+
+		msleep(1000);
+	}
+
+	spin_lock_irqsave(&instance->hba_lock, flags);
+	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
+		printk("megaraid_sas: %s timed out while waiting for HBA to recover.\n", __FUNCTION__);
+		error = -ENODEV;
+		goto out_kfree_ioc;
+	}
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
+
 	error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc);
 	up(&instance->ioctl_sem);
 
-      out_kfree_ioc:
+out_kfree_ioc:
 	kfree(ioc);
 	return error;
 }
@@ -3910,6 +4669,9 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
 	struct megasas_instance *instance;
 	struct megasas_aen aen;
 	int error;
+	int i;
+	unsigned long flags;
+	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
 
 	if (file->private_data != file) {
 		printk(KERN_DEBUG "megasas: fasync_helper was not "
@@ -3925,15 +4687,39 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
 	if (!instance)
 		return -ENODEV;
 
-	if (instance->hw_crit_error == 1) {
-		error = -ENODEV;
+	if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) {
+		return -ENODEV;
+       }
+
+	if (instance->unload == 1)
+		return -ENODEV;
+
+	down(&instance->aen_mutex);
+	for (i = 0; i < wait_time; i++) {
+
+		spin_lock_irqsave(&instance->hba_lock, flags);
+		if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+			spin_unlock_irqrestore(&instance->hba_lock, flags);
+			break;
+		}
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
+
+		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+			printk(KERN_NOTICE "megasas: waiting for controller reset to finish\n");
+		}
+
+		msleep(1000);
 	}
 
-	if (instance->unload == 1) {
+	spin_lock_irqsave(&instance->hba_lock, flags);
+	if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+		spin_unlock_irqrestore(&instance->hba_lock, flags);
+		printk("megaraid_sas: %s timed out while waiting for HBA to recover.\n", __FUNCTION__);
+		up(&instance->aen_mutex);
 		return -ENODEV;
 	}
+	spin_unlock_irqrestore(&instance->hba_lock, flags);
 
-	down(&instance->aen_mutex);
 	error = megasas_register_aen(instance, aen.seq_num,
 				     aen.class_locale_word);
 	up(&instance->aen_mutex);
@@ -4079,6 +4865,15 @@ static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
 			megasas_sysfs_show_support_poll_for_event, NULL);
 
 static ssize_t
+megasas_sysfs_show_support_device_change(struct device_driver *dd, char *buf)
+{
+	return sprintf(buf, "%u\n", support_device_change);
+}
+
+static DRIVER_ATTR(support_device_change, S_IRUGO,
+			megasas_sysfs_show_support_device_change, NULL);
+
+static ssize_t
 megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
 {
 	return sprintf(buf, "%u\n", megasas_dbg_lvl);
@@ -4105,8 +4900,8 @@ megasas_sysfs_show_poll_mode_io(struct device_driver *dd, char *buf)
 }
 
 static ssize_t
-megasas_sysfs_set_poll_mode_io(struct device_driver *dd, const char *buf,
-				size_t count)
+megasas_sysfs_set_poll_mode_io(struct device_driver *dd,
+				const char *buf, size_t count)
 {
 	int retval = count;
 	int tmp = poll_mode_io;
@@ -4152,10 +4947,6 @@ out:
 	return retval;
 }
 
-static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR,
-			megasas_sysfs_show_poll_mode_io,
-			megasas_sysfs_set_poll_mode_io);
-
 static void 
 megasas_aen_polling(void *arg)
 {
@@ -4172,7 +4963,7 @@ megasas_aen_polling(void *arg)
 	int error;
 
 	if (!instance) {
-		printk(KERN_ERR "%s: invalid instance!\n", __FUNCTION__);
+		printk(KERN_ERR "invalid instance!\n");
 		kfree(ev);
 		return;
 	}
@@ -4181,7 +4972,6 @@ megasas_aen_polling(void *arg)
 	if (instance->evt_detail) {
 
 		switch (instance->evt_detail->code) {
-		printk("EVENT received: event_code=%x!\n", instance->evt_detail->code);
 
 		case MR_EVT_PD_INSERTED:
 			if(megasas_get_pd_list(instance) == 0) {
@@ -4195,8 +4985,9 @@ megasas_aen_polling(void *arg)
 							scsi_add_device(host, i, j, 0);
 						}
 					} 
-					if (sdev1)
+					if (sdev1) {
 						scsi_device_put(sdev1);
+					}
 							
 				}
 			}
@@ -4228,8 +5019,8 @@ megasas_aen_polling(void *arg)
 			doscan = 0;
 			break;
 
-		case MR_EVT_CFG_CLEARED:
 		case MR_EVT_LD_OFFLINE:
+		case MR_EVT_CFG_CLEARED:
 		case MR_EVT_LD_DELETED:
 			megasas_get_ld_list(instance);
 			for (i=0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
@@ -4279,25 +5070,23 @@ megasas_aen_polling(void *arg)
 			break;
 		}
 	} else {
-		printk(KERN_ERR "%s[%d]: invalid evt_detail!\n",
-			__FUNCTION__, instance->host->host_no);
+		printk(KERN_ERR "invalid evt_detail!\n");
 		kfree(ev);
 		return;
 	}
 
-	if (doscan) { /*keep this incase we need to use*/
-		printk(KERN_INFO "%s[%d]: scanning ...\n",
-			__FUNCTION__, instance->host->host_no);
+	if (doscan) {
+		printk(KERN_INFO "scanning ...\n");
 		megasas_get_pd_list(instance);
 		for (i=0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
 			for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
-				pd_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
+				pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j;
 				sdev1 = scsi_device_lookup(host, i, j, 0);
-				if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
+				if (instance->pd_list[pd_index].driveState ==
+							MR_PD_STATE_SYSTEM) {
 					if (!sdev1) {
 						scsi_add_device(host, i, j, 0);
-					}
-					if (sdev1) {
+					} else {
 						scsi_device_put(sdev1);
 					}
 				} else {
@@ -4317,8 +5106,7 @@ megasas_aen_polling(void *arg)
 				if (instance->ld_ids[ld_index] != 0xff) {
 					if (!sdev1) {
 						scsi_add_device(host, i+2, j, 0);
-					}
-					if (sdev1) {
+					} else {
 						scsi_device_put(sdev1);
 					}
 				} else {
@@ -4334,9 +5122,7 @@ megasas_aen_polling(void *arg)
 
 	seq_num = instance->evt_detail->seq_num + 1; 
 
-	/*
-	 * Register AEN with FW for latest sequence number plus 1
-	 */
+	/* Register AEN with FW for latest sequence number plus 1 */
 	class_locale.members.reserved = 0;
 	class_locale.members.locale = MR_EVT_LOCALE_ALL;
 	class_locale.members.class = MR_EVT_CLASS_DEBUG;
@@ -4351,12 +5137,16 @@ megasas_aen_polling(void *arg)
 	up(&instance->aen_mutex);
 
 	if(error)
-		printk(KERN_ERR "%s[%d]: register aen failed error %x\n",
-			__FUNCTION__, instance->host->host_no, error);
-	kfree(ev);
+		printk(KERN_ERR "register aen failed error %x\n", error);
 
+	kfree(ev);
 }
 
+
+static DRIVER_ATTR(poll_mode_io, S_IRUGO|S_IWUSR,
+		megasas_sysfs_show_poll_mode_io,
+		megasas_sysfs_set_poll_mode_io);
+
 /**
  * megasas_init - Driver load entry point
  */
@@ -4371,8 +5161,8 @@ static int __init megasas_init(void)
 	       MEGASAS_EXT_VERSION);
 
 	support_poll_for_event = 2;
-
-
+	support_device_change = 1;
+	
 	memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
 
 	/*
@@ -4407,7 +5197,7 @@ static int __init megasas_init(void)
 		goto err_dcf_rel_date;
 
 	rval = driver_create_file(&megasas_pci_driver.driver,
-				&driver_attr_support_poll_for_event);
+				  &driver_attr_support_poll_for_event);
 	if (rval)
 		goto err_dcf_support_poll_for_event;
 
@@ -4420,17 +5210,26 @@ static int __init megasas_init(void)
 				  &driver_attr_poll_mode_io);
 	if (rval)
 		goto err_dcf_poll_mode_io;
+	rval = driver_create_file(&megasas_pci_driver.driver,
+				&driver_attr_support_device_change);
+	if (rval)
+		goto err_dcf_support_device_change;
 
 	return rval;
+err_dcf_support_device_change:
+	driver_remove_file(&megasas_pci_driver.driver,
+			  &driver_attr_poll_mode_io);
 err_dcf_poll_mode_io:
 	driver_remove_file(&megasas_pci_driver.driver,
 			   &driver_attr_dbg_lvl);
 err_dcf_dbg_lvl:
 	driver_remove_file(&megasas_pci_driver.driver,
 			&driver_attr_support_poll_for_event);
+
 err_dcf_support_poll_for_event:
 	driver_remove_file(&megasas_pci_driver.driver,
-			   &driver_attr_release_date);
+		  &driver_attr_release_date);
+
 err_dcf_rel_date:
 	driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
 err_dcf_attr_ver:
@@ -4446,15 +5245,16 @@ err_pcidrv:
 static void __exit megasas_exit(void)
 {
 	driver_remove_file(&megasas_pci_driver.driver,
-			&driver_attr_poll_mode_io);
+			   &driver_attr_poll_mode_io);
 	driver_remove_file(&megasas_pci_driver.driver,
-			&driver_attr_dbg_lvl);
+			   &driver_attr_dbg_lvl);
 	driver_remove_file(&megasas_pci_driver.driver,
-			&driver_attr_support_poll_for_event);
+			   &driver_attr_support_poll_for_event);
 	driver_remove_file(&megasas_pci_driver.driver,
-			&driver_attr_release_date);
+			&driver_attr_support_device_change);
 	driver_remove_file(&megasas_pci_driver.driver,
-			&driver_attr_version);
+			   &driver_attr_release_date);
+	driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
 
 	pci_unregister_driver(&megasas_pci_driver);
 	unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 966a1cd..40e0d8e 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -2,7 +2,7 @@
  *
  *		Linux MegaRAID driver for SAS based RAID controllers
  *
- * Copyright (c) 2003-2005  LSI Corporation.
+ * Copyright (c) 2003-2005  LSI Logic Corporation.
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -18,18 +18,18 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION				"00.00.04.17-RH1"
-#define MEGASAS_RELDATE				"Nov. 25, 2009"
-#define MEGASAS_EXT_VERSION			"Wed. Nov. 25, 11:41:51 PST 2009"
+#define MEGASAS_VERSION				"00.00.04.17-4.31.z-RH1"
+#define MEGASAS_RELDATE				"June. 15, 2010"
+#define MEGASAS_EXT_VERSION			"Tues. June. 15 14:13:02 EST 2010"
 
 /*
  * Device IDs
  */
 #define	PCI_DEVICE_ID_LSI_SAS1078R		0x0060
 #define	PCI_DEVICE_ID_LSI_SAS1078DE		0x007C
+#define	PCI_DEVICE_ID_LSI_VERDE_ZCR		0x0413
 #define	PCI_DEVICE_ID_LSI_SAS1078GEN2		0x0078
 #define	PCI_DEVICE_ID_LSI_SAS0079GEN2		0x0079
-#define	PCI_DEVICE_ID_LSI_VERDE_ZCR		0x0413
 #define	PCI_DEVICE_ID_LSI_SAS0073SKINNY		0x0073
 #define	PCI_DEVICE_ID_LSI_SAS0071SKINNY		0x0071
 
@@ -60,6 +60,7 @@
 #define MFI_STATE_READY				0xB0000000
 #define MFI_STATE_OPERATIONAL			0xC0000000
 #define MFI_STATE_FAULT				0xF0000000
+#define  MFI_RESET_REQUIRED			0x00000001
 
 #define MEGAMFI_FRAME_SIZE			64
 
@@ -73,6 +74,13 @@
  * HOTPLUG	: Resume from Hotplug
  * MFI_STOP_ADP	: Send signal to FW to stop processing
  */
+
+#define WRITE_SEQUENCE_OFFSET		(0x0000000FC) // I20
+#define HOST_DIAGNOSTIC_OFFSET		(0x000000F8)  // I20
+#define DIAG_WRITE_ENABLE			(0x00000080)
+#define DIAG_RESET_ADAPTER			(0x00000004)
+
+#define MFI_ADP_RESET				0x00000040
 #define MFI_INIT_ABORT				0x00000001
 #define MFI_INIT_READY				0x00000002
 #define MFI_INIT_MFIMODE			0x00000004
@@ -96,7 +104,7 @@
 #define MFI_FRAME_DIR_WRITE			0x0008
 #define MFI_FRAME_DIR_READ			0x0010
 #define MFI_FRAME_DIR_BOTH			0x0018
-#define MFI_FRAME_IEEE                         	0x0020
+#define MFI_FRAME_IEEE				0x0020
 
 /*
  * Definition for cmd_status
@@ -285,6 +293,7 @@ enum MR_EVT_ARGS {
 	MR_EVT_ARGS_PD_PATHINFO,
 	MR_EVT_ARGS_PD_POWER_STATE,
 	MR_EVT_ARGS_GENERIC,
+
 };
 
 /*
@@ -319,8 +328,8 @@ enum MR_PD_STATE {
     MR_PD_STATE_ONLINE              = 0x18,
     MR_PD_STATE_COPYBACK            = 0x20,
     MR_PD_STATE_SYSTEM              = 0x40,
- };
-
+};
+ 
  /*
  * defines the physical drive address structure
  */
@@ -348,6 +357,22 @@ struct MR_PD_ADDRESS {
     u64     sasAddr[2];
 } __attribute__ ((packed));
 
+/*
+ * defines the physical drive list structure
+ */
+struct MR_PD_LIST {
+    u32             size;
+    u32             count;
+    struct MR_PD_ADDRESS   addr[1];
+} __attribute__ ((packed));
+
+
+struct megasas_pd_list {
+    u16             tid;
+    u8             driveType;
+    u8             driveState;
+} __attribute__ ((packed));
+
  /*
  * defines the logical drive reference structure
  */
@@ -376,22 +401,6 @@ struct MR_LD_LIST {
 } __attribute__ ((packed));
 
 /*
- * defines the physical drive list structure
- */
-struct MR_PD_LIST {
-    u32             size;
-    u32             count;
-    struct MR_PD_ADDRESS   addr[1];
-} __attribute__ ((packed));
-
-
-struct megasas_pd_list {
-    u16             tid;
-    u8             driveType;
-    u8             driveState;
-} __attribute__ ((packed));
-
-/*
  * SAS controller properties
  */
 struct megasas_ctrl_prop {
@@ -417,7 +426,39 @@ struct megasas_ctrl_prop {
 	u16 ecc_bucket_leak_rate;
 	u8 restore_hotspare_on_insertion;
 	u8 expose_encl_devices;
-	u8 reserved[38];
+        u8      maintainPdFailHistory;
+    	u8      disallowHostRequestReordering;
+    	u8      abortCCOnError;                 
+    	u8      loadBalanceMode;                
+    	u8      disableAutoDetectBackplane;    
+    	u8      snapVDSpace;                    
+    /*
+     * Add properties that can be controlled by a bit in the following structure.
+     */
+    struct {
+        u32     copyBackDisabled            : 1;
+        u32     SMARTerEnabled              : 1;
+        u32     prCorrectUnconfiguredAreas  : 1;
+        u32     useFdeOnly                  : 1;
+        u32     disableNCQ                  : 1;
+       u32     SSDSMARTerEnabled           : 1;
+        u32     SSDPatrolReadEnabled        : 1;
+        u32     enableSpinDownUnconfigured  : 1;
+        u32     autoEnhancedImport          : 1;
+        u32     enableSecretKeyControl      : 1;
+        u32     disableOnlineCtrlReset      : 1;
+        u32     allowBootWithPinnedCache    : 1;
+        u32     disableSpinDownHS           : 1;
+        u32     enableJBOD                  : 1;
+        u32     reserved                    :18;
+    } OnOffProperties;
+    u8      autoSnapVDSpace;                
+                                            
+    u8      viewSpace;                      
+                                            
+    u16     spinDownTime;                 
+
+    u8      reserved[24];
 
 } __attribute__ ((packed));
 
@@ -680,14 +721,16 @@ struct megasas_ctrl_info {
 #define MEGASAS_DEFAULT_CMD_PER_LUN		128
 #define MEGASAS_MAX_PD				(MEGASAS_MAX_PD_CHANNELS * \
 							MEGASAS_MAX_DEV_PER_CHANNEL)
-
 #define MEGASAS_MAX_LD_IDS			(MEGASAS_MAX_LD_CHANNELS * \
 							MEGASAS_MAX_DEV_PER_CHANNEL)
+
+
+#define MEGASAS_MAX_SECTORS                    (2*1024)
 #define MEGASAS_DBG_LVL				1
 #define MEGASAS_FW_BUSY				1
 /* Frame Type */
-#define IO_FRAME					0
-#define PTHRU_FRAME					1
+#define IO_FRAME				0
+#define PTHRU_FRAME				1
 
 /*
  * When SCSI mid-layer calls driver's reset routine, driver waits for
@@ -699,7 +742,9 @@ struct megasas_ctrl_info {
 #define MEGASAS_RESET_WAIT_TIME			180
 #define MEGASAS_INTERNAL_CMD_WAIT_TIME		180
 #define	MEGASAS_RESET_NOTICE_INTERVAL		5
+
 #define MEGASAS_IOCTL_CMD			0
+
 #define MEGASAS_DEFAULT_CMD_TIMEOUT		90
 
 /*
@@ -718,15 +763,24 @@ struct megasas_ctrl_info {
  */
 #define IS_DMA64				(sizeof(dma_addr_t) == 8)
 
+#define MFI_XSCALE_OMR0_CHANGE_INTERRUPT            0x00000001  /* MFI state change interrupt */
+
+#define MFI_INTR_FLAG_REPLY_MESSAGE                 0x00000001
+#define MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE         0x00000002
+#define MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT 0x00000004  /* MFI state change interrrupt */
+
 #define MFI_OB_INTR_STATUS_MASK			0x00000002
 #define MFI_POLL_TIMEOUT_SECS			60
 #define MEGASAS_COMPLETION_TIMER_INTERVAL	(HZ/10)
 
 #define MFI_REPLY_1078_MESSAGE_INTERRUPT	0x80000000
-#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT       0x00000001
-#define MFI_GEN2_ENABLE_INTERRUPT_MASK         (0x00000001 | 0x00000004)
+#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT	0x00000001
+#define MFI_GEN2_ENABLE_INTERRUPT_MASK		0x00000001 
 #define MFI_REPLY_SKINNY_MESSAGE_INTERRUPT	0x40000000
-#define MFI_SKINNY_ENABLE_INTERRUPT_MASK	(0x00000001 | 0x00000008)
+#define MFI_SKINNY_ENABLE_INTERRUPT_MASK	(0x00000001)
+#define MFI_1068_PCSR_OFFSET			0x84
+#define MFI_1068_FW_HANDSHAKE_OFFSET		0x64
+#define MFI_1068_FW_READY			0xDDDD0000
 
 
 /*
@@ -770,7 +824,10 @@ struct megasas_register_set {
 	u32 	inbound_high_queue_port ;	/*00C4h*/
 
 	u32 	reserved_5;			/*00C8h*/
-	u32 	index_registers[820];		/*00CCh*/
+	u32		res_6[11];			/*CCh*/
+	u32		host_diag;
+	u32		seq_offset;
+	u32 	index_registers[807];		/*00CCh*/
 
 } __attribute__ ((packed));
 
@@ -787,7 +844,7 @@ struct megasas_sge64 {
 	u32 length;
 
 } __attribute__ ((packed));
-
+ 
 struct megasas_sge_skinny {
 
 	u64 phys_addr;
@@ -1233,19 +1290,22 @@ struct megasas_instance {
 	struct megasas_register_set __iomem *reg_set;
 
 	struct megasas_pd_list		pd_list[MEGASAS_MAX_PD];
+	u8     ld_ids[MEGASAS_MAX_LD_IDS];
 
 	s8 init_id;
 
 	u16 max_num_sge;
 	u16 max_fw_cmds;
 	u32 max_sectors_per_req;
+	struct megasas_aen_event *ev;
+	u32 cmd_per_lun;
 
 	struct megasas_cmd **cmd_list;
 	struct list_head cmd_pool;
 	spinlock_t cmd_pool_lock;
-	/* used to synch producer, consumer ptrs */
+	spinlock_t hba_lock;
 	spinlock_t completion_lock;
-	spinlock_t fire_lock;
+
 	struct dma_pool *frame_dma_pool;
 	struct dma_pool *sense_dma_pool;
 
@@ -1262,23 +1322,40 @@ struct megasas_instance {
 
 	struct pci_dev *pdev;
 	u32 unique_id;
+	u32 fw_support_ieee;
 
 	atomic_t fw_outstanding;
-	u32 hw_crit_error;
+	atomic_t fw_reset_no_pci_access;
 
+	
 	struct megasas_instance_template *instancet;
 	struct tasklet_struct isr_tasklet;
-	u8     ld_ids[MEGASAS_MAX_LD_IDS];
+	struct work_struct work_init;
 
 	u8 flag;
 	u8 unload;
 	u8 flag_ieee;
+	u8 issuepend_done;
+	u8 disableOnlineCtrlReset;
+	u8 adprecovery;
 	unsigned long last_time;
-	struct work_struct hotplug_work;
+	u32 mfiStatus;
+	u32 last_seq_num;
 
 	struct timer_list io_completion_timer;
+	struct list_head internal_reset_pending_q;
 };
 
+enum {
+	MEGASAS_HBA_OPERATIONAL			= 0,
+	MEGASAS_ADPRESET_SM_INFAULT		= 1,
+	MEGASAS_ADPRESET_SM_FW_RESET_SUCCESS	= 2,
+	MEGASAS_ADPRESET_SM_OPERATIONAL		= 3,
+	MEGASAS_HW_CRITICAL_ERROR		= 4,
+	MEGASAS_ADPRESET_INPROG_SIGN		= 0xDEADDEAD,
+};
+
+
  struct megasas_instance_template {
 	void (*fire_cmd)(struct megasas_instance *, dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
 
@@ -1288,6 +1365,8 @@ struct megasas_instance {
 	int (*clear_intr)(struct megasas_register_set __iomem *);
 
 	u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
+	int (*adp_reset)(struct megasas_instance *, struct megasas_register_set __iomem *);
+	int (*check_reset)(struct megasas_instance *, struct megasas_register_set __iomem *);
  };
 
 #define MEGASAS_IS_LOGICAL(scp)						\
@@ -1307,7 +1386,9 @@ struct megasas_cmd {
 	u32 index;
 	u8 sync_cmd;
 	u8 cmd_status;
-	u16 abort_aen;
+	u8 abort_aen;
+        u8 retry_for_fw_reset;
+
 
 	struct list_head list;
 	struct scsi_cmnd *scmd;