Sophie

Sophie

distrib > Scientific%20Linux > 5x > i386 > by-pkgid > 351d529f9beeb4e5d936a6d5e3e7813a > files > 2278

kernel-2.6.18-128.29.1.el5.src.rpm

From: Tomas Henzl <thenzl@redhat.com>
Date: Wed, 28 Jul 2010 17:25:27 +0200
Subject: [scsi] megaraid_sas: fix physical disk handling
Message-id: <4C504BE7.5050708@redhat.com>
O-Subject: [RHEL5.3.z PATCH] megaraid_sas: fix physical disk handling
Bugzilla: 619362
RH-Acked-by: Rob Evers <revers@redhat.com>

This is for bz#602714

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.3, because the driver has changed in the past.

The said original patch has some issues, which we hope will be resolved by LSI soon.
A second version of the patch is in sight. The problematic part of the original
patch is not contained in this patch.
I'm posting this now because of time pressure.

Brew build - https://brewweb.devel.redhat.com/taskinfo?taskID=2632785

Tomas


diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 8d1fd9e..115e154 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -97,6 +97,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_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
@@ -154,7 +159,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);
@@ -186,28 +191,31 @@ megasas_read_fw_status_reg_xscale(struct megasas_register_set __iomem * regs)
  * megasas_clear_interrupt_xscale -	Check & clear interrupt
  * @regs:				MFI register set
  */
-static int 
+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;
 }
 
 /**
@@ -223,6 +231,59 @@ megasas_fire_cmd_xscale(dma_addr_t frame_phys_addr,u32 frame_count, struct megas
 	       &(regs)->inbound_queue_port);
 }
 
+/**
+ * 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 = {
 
 	.fire_cmd = megasas_fire_cmd_xscale,
@@ -230,6 +291,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,
 };
 
 /**
@@ -251,7 +314,7 @@ 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);
@@ -294,7 +357,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;
 	}
 
 	/*
@@ -305,7 +368,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
@@ -320,6 +383,26 @@ megasas_fire_cmd_ppc(dma_addr_t frame_phys_addr, u32 frame_count, struct megasas
 			&(regs)->inbound_queue_port);
 }
 
+/**
+ * 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 = {
 	
 	.fire_cmd = megasas_fire_cmd_ppc,
@@ -327,6 +410,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,
 };
 
 /**
@@ -385,25 +470,33 @@ megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs)
 static int
 megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs)
 {
-	u32 status;
-	/*
-	 * Check if it is our interrupt
-	 */
-	status = readl(&regs->outbound_intr_status);
+        u32 status;
+        u32 mfiStatus = 0;
+        /*
+         * Check if it is our interrupt
+         */
+        status = readl(&regs->outbound_intr_status);
+
+        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;
+        }
 
-	if (!(status & MFI_GEN2_ENABLE_INTERRUPT_MASK)) {
-		return 1;
-	}
+        /*
+         * Clear the interrupt by writing back the same value
+         */
+        if (mfiStatus)
+                writel(status, &regs->outbound_doorbell_clear);
 
-	/*
-	 * Clear the interrupt by writing back the same value
-	 */
-	writel(status, &regs->outbound_doorbell_clear);
+        /* Dummy readl to force pci flush */
+        readl(&regs->outbound_intr_status);
 
-	/* Dummy readl to force pci flush */
-	readl(&regs->outbound_intr_status);
+        return mfiStatus;
 
-	return 0;
 }
 /**
  * megasas_fire_cmd_gen2 -	Sends command to the FW
@@ -419,6 +512,75 @@ megasas_fire_cmd_gen2(dma_addr_t frame_phys_addr, u32 frame_count,
 			&(regs)->inbound_queue_port);
 }
 
+/**
+ * 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,
@@ -426,6 +588,8 @@ static struct megasas_instance_template megasas_instance_template_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,
 };
 
 /**
@@ -488,8 +652,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
 
 	instance->instancet->fire_cmd(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;
 }
@@ -536,8 +699,9 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
 	/*
 	 * 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;
@@ -978,13 +1142,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;
@@ -1067,6 +1243,14 @@ 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)
+{
+	writel(MFI_STOP_ADP,
+		&instance->reg_set->inbound_doorbell);
+}
+
 /**
  * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
  * @instance_addr:			Address of adapter soft state
@@ -1084,7 +1268,7 @@ 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);
@@ -1126,6 +1310,26 @@ 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
@@ -1136,9 +1340,84 @@ 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);
+			// Are we there yet?
+			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(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);
@@ -1147,10 +1426,12 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
 			break;
 
 		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
+			 * Call cmd completion routine. Cmd to be 
 			 * be completed directly without depending on isr.
 			 */
 			megasas_complete_cmd_dpc((unsigned long)instance);
@@ -1159,18 +1440,67 @@ 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.
 		*/
 		writel(MFI_STOP_ADP,
-				&instance->reg_set->inbound_doorbell);
+			&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;
 }
 
@@ -1192,7 +1522,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;
@@ -1458,6 +1788,10 @@ 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;
 
@@ -1570,7 +1904,188 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 		break;
 	}
 }
+//
+ /**
+ * 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(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(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);
+		}
+	}
+
+	// Re-register AEN
+	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;
+                }
+
+		// Transition the FW to operational state
+		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
@@ -1581,21 +2096,65 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
 static int
 megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
 {
-	/*
-	 * Check if it is our interrupt
-	 * Clear the interrupt 
-	 */
-	if(instance->instancet->clear_intr(instance->reg_set))
+	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((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
-	 */
+	// 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;
+
 }
 
 /**
@@ -1603,8 +2162,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;
 }
 
 /**
@@ -1864,6 +2435,12 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
 		}
 
 		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;
@@ -1955,6 +2532,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);
@@ -2278,6 +2856,7 @@ static int megasas_init_mfi(struct megasas_instance *instance)
 
 		tmp_sectors = (max_sectors_1 < max_sectors_2)
 		    ? max_sectors_1 : max_sectors_2;
+                instance->disableOnlineCtrlReset = ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
 	}
 
 	instance->max_sectors_per_req = instance->max_num_sge *
@@ -2498,6 +3077,7 @@ 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);
@@ -2651,6 +3231,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);
@@ -2666,6 +3248,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	*instance->producer = 0;
 	*instance->consumer = 0;
 
+ 	instance->issuepend_done = 1;
+	instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
 	instance->evt_detail = pci_alloc_consistent(pdev,
 						    sizeof(struct
 							   megasas_evt_detail),
@@ -2681,6 +3265,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);
 
@@ -2689,6 +3274,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
 	spin_lock_init(&instance->cmd_pool_lock);
 	spin_lock_init(&instance->completion_lock);
+	spin_lock_init(&instance->hba_lock);
 
 	sema_init(&instance->aen_mutex, 1);
 	sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
@@ -2705,6 +3291,9 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
 	instance->flag = 0;
 	instance->last_time = 0;
 
+	instance->disableOnlineCtrlReset = 1;
+
+	INIT_WORK(&instance->work_init, process_fw_state_change_wq, instance);
 	/*
 	 * Initialize MFI Firmware
 	 */
@@ -2794,6 +3383,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)
@@ -2830,6 +3422,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)
@@ -3294,6 +3889,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)
@@ -3317,6 +3915,34 @@ 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);
 
@@ -3330,6 +3956,8 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
 	struct megasas_instance *instance;
 	struct megasas_aen aen;
 	int error;
+	int i;
+	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
 
 	if (file->private_data != file) {
 		printk(KERN_DEBUG "megasas: fasync_helper was not "
@@ -3346,6 +3974,24 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
 		return -ENODEV;
 
 	down(&instance->aen_mutex);
+       for (i = 0; i < wait_time; i++) {
+
+               if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) {
+                       break;
+               }
+
+               if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+                       printk(KERN_NOTICE "megasas: waiting for controller reset to finish\n");
+               }
+
+               msleep(1000);
+        }
+       
+       if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+               printk("megaraid_sas: %s timed out while waiting for HBA to recover.\n", __FUNCTION__);
+               up(&instance->aen_mutex);
+               return -ENODEV;
+        }
 	error = megasas_register_aen(instance, aen.seq_num,
 				     aen.class_locale_word);
 	up(&instance->aen_mutex);
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 4f4ddf1..7db2700 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION				"00.00.04.01-RH1"
-#define MEGASAS_RELDATE				"July 10, 2008"
-#define MEGASAS_EXT_VERSION			"Thu July 10 09:41:51 PST 2008"
+#define MEGASAS_VERSION				"00.00.04.01.27-RH1"
+#define MEGASAS_RELDATE				"Mar. 30, 2010"
+#define MEGASAS_EXT_VERSION			"Tue. Mar. 30 14:13:02 EST 2010"
 
 /*
  * Device IDs
@@ -58,6 +58,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
 
@@ -71,6 +72,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
@@ -280,7 +288,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));
 
@@ -577,6 +617,12 @@ 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)
@@ -584,6 +630,9 @@ struct megasas_ctrl_info {
 #define MFI_REPLY_1078_MESSAGE_INTERRUPT	0x80000000
 #define MFI_REPLY_GEN2_MESSAGE_INTERRUPT       0x00000001
 #define MFI_GEN2_ENABLE_INTERRUPT_MASK         (0x00000001 | 0x00000004)
+#define MFI_1068_PCSR_OFFSET			0x84
+#define MFI_1068_FW_HANDSHAKE_OFFSET		0x64
+#define MFI_1068_FW_READY			0xDDDD0000
 
 /*
 * register set for both 1068 and 1078 controllers
@@ -626,7 +675,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));
 
@@ -1061,17 +1113,6 @@ struct megasas_evt_detail {
 
 } __attribute__ ((packed));
 
- struct megasas_instance_template {
-	void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
-
-	void (*enable_intr)(struct megasas_register_set __iomem *) ;
-	void (*disable_intr)(struct megasas_register_set __iomem *);
-
-	int (*clear_intr)(struct megasas_register_set __iomem *);
-
-	u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *);
- };
-
 struct megasas_instance {
 
 	u32 *producer;
@@ -1096,6 +1137,7 @@ struct megasas_instance {
 	spinlock_t cmd_pool_lock;
 	/* used to synch producer, consumer ptrs */
 	spinlock_t completion_lock;
+	spinlock_t hba_lock;
 	struct dma_pool *frame_dma_pool;
 	struct dma_pool *sense_dma_pool;
 
@@ -1114,17 +1156,46 @@ struct megasas_instance {
 	u32 unique_id;
 
 	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;
+	struct work_struct work_init;
 
 	u8 flag;
+	u8 issuepend_done;
+	u8 disableOnlineCtrlReset;
+	u8 adprecovery;
+	u32 last_seq_num;
 	unsigned long last_time;
 
 	struct timer_list io_completion_timer;
+	struct list_head internal_reset_pending_q;
 };
 
+ struct megasas_instance_template {
+	void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
+
+	void (*enable_intr)(struct megasas_register_set __iomem *) ;
+	void (*disable_intr)(struct megasas_register_set __iomem *);
+
+	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 *);
+ };
+
+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,
+};
+
+
 #define MEGASAS_IS_LOGICAL(scp)						\
 	(scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
 
@@ -1142,7 +1213,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;