Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 89877e42827f16fa5f86b1df0c2860b1 > files > 2269

kernel-2.6.18-128.1.10.el5.src.rpm

Date: Thu, 12 Oct 2006 17:16:27 -0400 (EDT)
From: Chip Coldwell <coldwell@redhat.com>
Subject: [RHEL5.0 PATCH]: BZ#209463: megaraid_sas: possible data corruptor
 3.01->3.05


Hi Fellas,

Sorry for the late post.  This patch from LSI Logic comes with the
following changelog:

- sets ioctl timeout and updates version,changelog
- adds tasklet for cmd completion
- prints pending cmds before setting hw_crit_error
- function pointer for disable interrupt
- frame count optimization
- FW transition (includes Soft reset)and q size changes
- handle clear_user() error
- handle and properly unwind from sysfs errors thrown during mod init

>From our perspective, the important change is the sixth one above,
quoting Sumant Patro at LSI:

    The 'Queue size change' bug fix is a critical one.  Driver was
    sending one more cmd than the FW could handle.  This is a
    potential Data corruption issue.  The buggy code for the queue
    size was there for a long time in the driver, where it was sending
    number of responseQueueEntries as 0x3f1. FW expects the
    responseQueueEntries to have a maximum value of 0x3f0.

    The test team has been able to duplicate it consistently under
    heavy IO. Two symptoms are seen because of the bug :

    1. IO programs became sluggish and seemed to be hung/data
       corruption message from the test tools.

    2. System is unresponsive if it is boot controller

We could restrict ourselves to just the fix for the potential data
corruptor; however, I think there are pretty compelling reasons for
taking the whole thing even at this late date.  Most importantly, it
has all been accepted in James Bottomley's scsi-misc git repository,
so this is an opportunity to start off the RHEL5 driver closer to
upstream.

More generally, accepting this patch will put RHEL5 in sync with LSI
and their customers, and save us the trouble of larger backports for
5.1.

Your ACKs are humbly solicited.

Chip

-- 
Charles M. "Chip" Coldwell
Senior Software Engineer
Red Hat, Inc
978-392-2426

diff -uprN linux-2.6.18-orig/Documentation/scsi/ChangeLog.megaraid_sas linux-2.6.18/Documentation/scsi/ChangeLog.megaraid_sas
--- linux-2.6.18-orig/Documentation/scsi/ChangeLog.megaraid_sas	2006-10-04 13:10:35.000000000 -0700
+++ linux-2.6.18/Documentation/scsi/ChangeLog.megaraid_sas	2006-10-04 13:13:33.000000000 -0700
@@ -1,4 +1,49 @@
 
+1 Release Date    : Mon Oct 02 11:21:32 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.03.05
+3 Older Version   : 00.00.03.04
+
+i.	PCI_DEVICE macro used
+
+	Convert the pci_device_id-table of the megaraid_sas-driver to the PCI_DEVICE-macro, to safe some lines.
+
+		- Henrik Kretzschmar <henne@nachtwindheim.de>
+ii.	All compiler warnings removed
+iii.	megasas_ctrl_info struct reverted to 3.02 release
+iv.	Default value of megasas_dbg_lvl set to 0
+v.	Removing in megasas_exit the sysfs entry created for megasas_dbg_lvl
+vi.	In megasas_teardown_frame_pool(), cmd->frame was passed instead of
+	cmd->sense to pci_pool_free. Fixed. Bug was pointed out by
+	Eric Sesterhenn
+
+1 Release Date    : Wed Sep 13 14:22:51 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.03.04
+3 Older Version   : 00.00.03.03
+
+i.	Added Reboot notify
+ii.	Reduced by 1 max cmds sent to FW from Driver to make the reply_q_sz same
+	as Max Cmds FW can support
+
+1 Release Date    : Tue Aug 22 16:33:14 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.03.03
+3 Older Version   : 00.00.03.02
+
+i.	Send stop adapter to FW & Dump pending FW cmds before declaring adapter dead.
+	New varible added to set dbg level.
+ii.	Disable interrupt made as fn pointer as they are different for 1068 / 1078
+iii.	Frame count optimization. Main frame can contain 2 SGE for 64 bit SGLs and
+	3 SGE for 32 bit SGL
+iv.	Tasklet added for cmd completion
+v.	If FW in operational state before firing INIT, now we send RESET Flag to FW instead of just READY. This is used to do soft reset.
+vi.	megasas_ctrl_prop structure updated (based on FW struct)
+vii.	Added print : FW now in Ready State during initialization
+
+1 Release Date    : Sun Aug 06 22:49:52 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.03.02
+3 Older Version   : 00.00.03.01
+
+i.	Added FW tranistion state for Hotplug scenario
+
 1 Release Date    : Sun May 14 22:49:52 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
 2 Current Version : 00.00.03.01
 3 Older Version   : 00.00.02.04
diff -uprN linux-2.6.18-orig/drivers/scsi/megaraid/megaraid_sas.c linux-2.6.18/drivers/scsi/megaraid/megaraid_sas.c
--- linux-2.6.18-orig/drivers/scsi/megaraid/megaraid_sas.c	2006-10-04 13:10:19.000000000 -0700
+++ linux-2.6.18/drivers/scsi/megaraid/megaraid_sas.c	2006-10-04 13:12:44.000000000 -0700
@@ -10,7 +10,7 @@
  *	   2 of the License, or (at your option) any later version.
  *
  * FILE		: megaraid_sas.c
- * Version	: v00.00.03.01
+ * Version	: v00.00.03.05
  *
  * Authors:
  * 	Sreenivas Bagalkote	<Sreenivas.Bagalkote@lsil.com>
@@ -53,31 +53,15 @@ MODULE_DESCRIPTION("LSI Logic MegaRAID S
  */
 static struct pci_device_id megasas_pci_table[] = {
 
-	{
-	 PCI_VENDOR_ID_LSI_LOGIC,
-	 PCI_DEVICE_ID_LSI_SAS1064R, /* xscale IOP */
-	 PCI_ANY_ID,
-	 PCI_ANY_ID,
-	 },
-	{
-	 PCI_VENDOR_ID_LSI_LOGIC,
-	 PCI_DEVICE_ID_LSI_SAS1078R, /* ppc IOP */
-	 PCI_ANY_ID,
-	 PCI_ANY_ID,
-	},
-	{
-	 PCI_VENDOR_ID_LSI_LOGIC,
-	 PCI_DEVICE_ID_LSI_VERDE_ZCR,	/* xscale IOP, vega */
-	 PCI_ANY_ID,
-	 PCI_ANY_ID,
-	 },
-	{
-	 PCI_VENDOR_ID_DELL,
-	 PCI_DEVICE_ID_DELL_PERC5, /* xscale IOP */
-	 PCI_ANY_ID,
-	 PCI_ANY_ID,
-	 },
-	{0}			/* Terminating entry */
+	{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)},
+	/* 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_VERDE_ZCR)},
+	/* xscale IOP, vega */
+	{PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)},
+	/* xscale IOP */
+	{}
 };
 
 MODULE_DEVICE_TABLE(pci, megasas_pci_table);
@@ -87,6 +71,8 @@ static struct megasas_mgmt_info megasas_
 static struct fasync_struct *megasas_async_queue;
 static DEFINE_MUTEX(megasas_async_queue_mutex);
 
+static u32 megasas_dbg_lvl;
+
 /**
  * megasas_get_cmd -	Get a command from the free pool
  * @instance:		Adapter soft state
@@ -151,6 +137,19 @@ megasas_enable_intr_xscale(struct megasa
 }
 
 /**
+ * megasas_disable_intr_xscale -Disables interrupt
+ * @regs:			MFI register set
+ */
+static inline void
+megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs)
+{
+	u32 mask = 0x1f;
+	writel(mask, &regs->outbound_intr_mask);
+	/* Dummy readl to force pci flush */
+	readl(&regs->outbound_intr_mask);
+}
+
+/**
  * megasas_read_fw_status_reg_xscale - returns the current FW status value
  * @regs:			MFI register set
  */
@@ -201,6 +200,7 @@ static struct megasas_instance_template 
 
 	.fire_cmd = megasas_fire_cmd_xscale,
 	.enable_intr = megasas_enable_intr_xscale,
+	.disable_intr = megasas_disable_intr_xscale,
 	.clear_intr = megasas_clear_intr_xscale,
 	.read_fw_status_reg = megasas_read_fw_status_reg_xscale,
 };
@@ -231,6 +231,19 @@ megasas_enable_intr_ppc(struct megasas_r
 }
 
 /**
+ * megasas_disable_intr_ppc -	Disable interrupt
+ * @regs:			MFI register set
+ */
+static inline void
+megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs)
+{
+	u32 mask = 0xFFFFFFFF;
+	writel(mask, &regs->outbound_intr_mask);
+	/* Dummy readl to force pci flush */
+	readl(&regs->outbound_intr_mask);
+}
+
+/**
  * megasas_read_fw_status_reg_ppc - returns the current FW status value
  * @regs:			MFI register set
  */
@@ -281,6 +294,7 @@ static struct megasas_instance_template 
 	
 	.fire_cmd = megasas_fire_cmd_ppc,
 	.enable_intr = megasas_enable_intr_ppc,
+	.disable_intr = megasas_disable_intr_ppc,
 	.clear_intr = megasas_clear_intr_ppc,
 	.read_fw_status_reg = megasas_read_fw_status_reg_ppc,
 };
@@ -291,25 +305,6 @@ static struct megasas_instance_template 
 */
 
 /**
- * megasas_disable_intr -	Disables interrupts
- * @regs:			MFI register set
- */
-static inline void
-megasas_disable_intr(struct megasas_instance *instance)
-{
-	u32 mask = 0x1f; 
-	struct megasas_register_set __iomem *regs = instance->reg_set;
-
-	if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R)
-		mask = 0xffffffff;
-
-	writel(mask, &regs->outbound_intr_mask);
-
-	/* Dummy readl to force pci flush */
-	readl(&regs->outbound_intr_mask);
-}
-
-/**
  * megasas_issue_polled -	Issues a polling command
  * @instance:			Adapter soft state
  * @cmd:			Command packet to be issued 
@@ -352,6 +347,7 @@ megasas_issue_polled(struct megasas_inst
  * @cmd:			Command to be issued
  *
  * This function waits on an event for the command to be returned from ISR.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
  * Used to issue ioctl commands.
  */
 static int
@@ -362,7 +358,8 @@ megasas_issue_blocked_cmd(struct megasas
 
 	instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
 
-	wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
+	wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
+		MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
 
 	return 0;
 }
@@ -374,7 +371,8 @@ megasas_issue_blocked_cmd(struct megasas
  *
  * MFI firmware can abort previously issued AEN comamnd (automatic event
  * notification). The megasas_issue_blocked_abort_cmd() issues such abort
- * cmd and blocks till it is completed.
+ * cmd and waits for return status.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
  */
 static int
 megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
@@ -408,7 +406,8 @@ megasas_issue_blocked_abort_cmd(struct m
 	/*
 	 * Wait for this cmd to complete
 	 */
-	wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF));
+	wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
+		MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
 
 	megasas_return_cmd(instance, cmd);
 	return 0;
@@ -511,6 +510,46 @@ megasas_make_sgl64(struct megasas_instan
 	return sge_count;
 }
 
+ /**
+ * megasas_get_frame_count - Computes the number of frames
+ * @sge_count		: number of sg elements
+ *
+ * Returns the number of frames required for numnber of sge's (sge_count)
+ */
+
+u32 megasas_get_frame_count(u8 sge_count)
+{
+	int num_cnt;
+	int sge_bytes;
+	u32 sge_sz;
+	u32 frame_count=0;
+
+	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+	    sizeof(struct megasas_sge32);
+
+	/*
+	* Main frame can contain 2 SGEs for 64-bit SGLs and
+	* 3 SGEs for 32-bit SGLs
+	*/
+	if (IS_DMA64)
+		num_cnt = sge_count - 2;
+	else
+		num_cnt = sge_count - 3;
+
+	if(num_cnt>0){
+		sge_bytes = sge_sz * num_cnt;
+
+		frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
+		    ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
+	}
+	/* Main frame */
+	frame_count +=1;
+
+	if (frame_count > 7)
+		frame_count = 8;
+	return frame_count;
+}
+
 /**
  * megasas_build_dcdb -	Prepares a direct cdb (DCDB) command
  * @instance:		Adapter soft state
@@ -524,8 +563,6 @@ static int
 megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
 		   struct megasas_cmd *cmd)
 {
-	u32 sge_sz;
-	int sge_bytes;
 	u32 is_logical;
 	u32 device_id;
 	u16 flags = 0;
@@ -560,9 +597,6 @@ megasas_build_dcdb(struct megasas_instan
 	/*
 	 * Construct SGL
 	 */
-	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
-	    sizeof(struct megasas_sge32);
-
 	if (IS_DMA64) {
 		pthru->flags |= MFI_FRAME_SGL64;
 		pthru->sge_count = megasas_make_sgl64(instance, scp,
@@ -578,17 +612,11 @@ megasas_build_dcdb(struct megasas_instan
 	pthru->sense_buf_phys_addr_hi = 0;
 	pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
 
-	sge_bytes = sge_sz * pthru->sge_count;
-
 	/*
 	 * 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 = (sge_bytes / MEGAMFI_FRAME_SIZE) +
-	    ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
-	if (cmd->frame_count > 7)
-		cmd->frame_count = 8;
+	cmd->frame_count = megasas_get_frame_count(pthru->sge_count);
 
 	return cmd->frame_count;
 }
@@ -605,8 +633,6 @@ static int
 megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
 		   struct megasas_cmd *cmd)
 {
-	u32 sge_sz;
-	int sge_bytes;
 	u32 device_id;
 	u8 sc = scp->cmnd[0];
 	u16 flags = 0;
@@ -621,7 +647,7 @@ megasas_build_ldio(struct megasas_instan
 		flags = MFI_FRAME_DIR_READ;
 
 	/*
-	 * Preare the Logical IO frame: 2nd bit is zero for all read cmds
+	 * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
 	 */
 	ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
 	ldio->cmd_status = 0x0;
@@ -690,9 +716,6 @@ megasas_build_ldio(struct megasas_instan
 	/*
 	 * Construct SGL
 	 */
-	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
-	    sizeof(struct megasas_sge32);
-
 	if (IS_DMA64) {
 		ldio->flags |= MFI_FRAME_SGL64;
 		ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
@@ -706,13 +729,11 @@ megasas_build_ldio(struct megasas_instan
 	ldio->sense_buf_phys_addr_hi = 0;
 	ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
 
-	sge_bytes = sge_sz * ldio->sge_count;
-
-	cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
-	    ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
-	if (cmd->frame_count > 7)
-		cmd->frame_count = 8;
+	/*
+	 * 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(ldio->sge_count);
 
 	return cmd->frame_count;
 }
@@ -743,6 +764,69 @@ static inline int megasas_is_ldio(struct
 	}
 }
 
+ /**
+ * megasas_dump_pending_frames -	Dumps the frame address of all pending cmds
+ *                              	in FW
+ * @instance:				Adapter soft state
+ */
+static inline void
+megasas_dump_pending_frames(struct megasas_instance *instance)
+{
+	struct megasas_cmd *cmd;
+	int i,n;
+	union megasas_sgl *mfi_sgl;
+	struct megasas_io_frame *ldio;
+	struct megasas_pthru_frame *pthru;
+	u32 sgcount;
+	u32 max_cmd = instance->max_fw_cmds;
+
+	printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
+	printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
+	if (IS_DMA64)
+		printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
+	else
+		printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
+
+	printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
+	for (i = 0; i < max_cmd; i++) {
+		cmd = instance->cmd_list[i];
+		if(!cmd->scmd)
+			continue;
+		printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
+		if (megasas_is_ldio(cmd->scmd)){
+			ldio = (struct megasas_io_frame *)cmd->frame;
+			mfi_sgl = &ldio->sgl;
+			sgcount = ldio->sge_count;
+			printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
+		}
+		else {
+			pthru = (struct megasas_pthru_frame *) cmd->frame;
+			mfi_sgl = &pthru->sgl;
+			sgcount = pthru->sge_count;
+			printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
+		}
+	if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
+		for (n = 0; n < sgcount; n++){
+			if (IS_DMA64)
+				printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
+			else
+				printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
+			}
+		}
+		printk(KERN_ERR "\n");
+	} /*for max_cmd*/
+	printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
+	for (i = 0; i < max_cmd; i++) {
+
+		cmd = instance->cmd_list[i];
+
+		if(cmd->sync_cmd == 1){
+			printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
+		}
+	}
+	printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
+}
+
 /**
  * megasas_queue_command -	Queue entry point
  * @scmd:			SCSI command to be queued
@@ -848,6 +932,13 @@ static int megasas_wait_for_outstanding(
 	}
 
 	if (atomic_read(&instance->fw_outstanding)) {
+		/*
+		* 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);
+		megasas_dump_pending_frames(instance);
 		instance->hw_crit_error = 1;
 		return FAILED;
 	}
@@ -1184,11 +1275,6 @@ megasas_complete_cmd(struct megasas_inst
 static int
 megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
 {
-	u32 producer;
-	u32 consumer;
-	u32 context;
-	struct megasas_cmd *cmd;
-
 	/*
 	 * Check if it is our interrupt
 	 * Clear the interrupt 
@@ -1196,23 +1282,10 @@ megasas_deplete_reply_queue(struct megas
 	if(instance->instancet->clear_intr(instance->reg_set))
 		return IRQ_NONE;
 
-	producer = *instance->producer;
-	consumer = *instance->consumer;
-
-	while (consumer != producer) {
-		context = instance->reply_queue[consumer];
-
-		cmd = instance->cmd_list[context];
-
-		megasas_complete_cmd(instance, cmd, alt_status);
-
-		consumer++;
-		if (consumer == (instance->max_fw_cmds + 1)) {
-			consumer = 0;
-		}
-	}
-
-	*instance->consumer = producer;
+        /*
+	 * Schedule the tasklet for cmd completion
+	 */
+	tasklet_schedule(&instance->isr_tasklet);
 
 	return IRQ_HANDLED;
 }
@@ -1245,10 +1318,12 @@ megasas_transition_to_ready(struct megas
 
 	fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
 
+	if (fw_state != MFI_STATE_READY)
+ 		printk(KERN_INFO "megasas: Waiting for FW to come to ready"
+ 		       " state\n");
+
 	while (fw_state != MFI_STATE_READY) {
 
-		printk(KERN_INFO "megasas: Waiting for FW to come to ready"
-		       " state\n");
 		switch (fw_state) {
 
 		case MFI_STATE_FAULT:
@@ -1260,19 +1335,27 @@ megasas_transition_to_ready(struct megas
 			/*
 			 * Set the CLR bit in inbound doorbell
 			 */
-			writel(MFI_INIT_CLEAR_HANDSHAKE,
+			writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
 				&instance->reg_set->inbound_doorbell);
 
 			max_wait = 2;
 			cur_state = MFI_STATE_WAIT_HANDSHAKE;
 			break;
 
+		case MFI_STATE_BOOT_MESSAGE_PENDING:
+			writel(MFI_INIT_HOTPLUG,
+				&instance->reg_set->inbound_doorbell);
+
+			max_wait = 10;
+			cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
+			break;
+
 		case MFI_STATE_OPERATIONAL:
 			/*
-			 * Bring it to READY state; assuming max wait 2 secs
+			 * Bring it to READY state; assuming max wait 10 secs
 			 */
-			megasas_disable_intr(instance);
-			writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
+			instance->instancet->disable_intr(instance->reg_set);
+			writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
 
 			max_wait = 10;
 			cur_state = MFI_STATE_OPERATIONAL;
@@ -1339,6 +1422,7 @@ megasas_transition_to_ready(struct megas
 			return -ENODEV;
 		}
 	};
+ 	printk(KERN_INFO "megasas: FW now in Ready state\n");
 
 	return 0;
 }
@@ -1368,7 +1452,7 @@ static void megasas_teardown_frame_pool(
 				      cmd->frame_phys_addr);
 
 		if (cmd->sense)
-			pci_pool_free(instance->sense_dma_pool, cmd->frame,
+			pci_pool_free(instance->sense_dma_pool, cmd->sense,
 				      cmd->sense_phys_addr);
 	}
 
@@ -1644,6 +1728,39 @@ megasas_get_ctrl_info(struct megasas_ins
 }
 
 /**
+ * megasas_complete_cmd_dpc	 -	Returns FW's controller structure
+ * @instance_addr:			Address of adapter soft state
+ *
+ * Tasklet to complete cmds
+ */
+void megasas_complete_cmd_dpc(unsigned long instance_addr)
+{
+	u32 producer;
+	u32 consumer;
+	u32 context;
+	struct megasas_cmd *cmd;
+	struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
+
+	producer = *instance->producer;
+	consumer = *instance->consumer;
+
+	while (consumer != producer) {
+		context = instance->reply_queue[consumer];
+
+		cmd = instance->cmd_list[context];
+
+		megasas_complete_cmd(instance, cmd, DID_OK);
+
+		consumer++;
+		if (consumer == (instance->max_fw_cmds + 1)) {
+			consumer = 0;
+		}
+	}
+
+	*instance->consumer = producer;
+}
+
+/**
  * megasas_init_mfi -	Initializes the FW
  * @instance:		Adapter soft state
  *
@@ -1706,6 +1823,12 @@ static int megasas_init_mfi(struct megas
 	 * 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) >> 
 					0x10;
 	/*
@@ -1770,7 +1893,7 @@ static int megasas_init_mfi(struct megas
 	/*
 	 * disable the intr before firing the init frame to FW
 	 */
-	megasas_disable_intr(instance);
+	instance->instancet->disable_intr(instance->reg_set);
 
 	/*
 	 * Issue the init frame in polled mode
@@ -1807,6 +1930,12 @@ static int megasas_init_mfi(struct megas
 
 	kfree(ctrl_info);
 
+        /*
+	* Setup tasklet for cmd completion
+	*/
+
+        tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+                        (unsigned long)instance);
 	return 0;
 
       fail_fw_init:
@@ -2198,6 +2327,8 @@ megasas_probe_one(struct pci_dev *pdev, 
 	instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
 	instance->init_id = MEGASAS_DEFAULT_INIT_ID;
 
+	megasas_dbg_lvl = 0;
+
 	/*
 	 * Initialize MFI Firmware
 	 */
@@ -2250,7 +2381,7 @@ megasas_probe_one(struct pci_dev *pdev, 
 	megasas_mgmt_info.max_index--;
 
 	pci_set_drvdata(pdev, NULL);
-	megasas_disable_intr(instance);
+	instance->instancet->disable_intr(instance->reg_set);
 	free_irq(instance->pdev->irq, instance);
 
 	megasas_release_mfi(instance);
@@ -2364,6 +2495,7 @@ static void megasas_detach_one(struct pc
 	scsi_remove_host(instance->host);
 	megasas_flush_cache(instance);
 	megasas_shutdown_controller(instance);
+	tasklet_kill(&instance->isr_tasklet);
 
 	/*
 	 * Take the instance off the instance array. Note that we will not
@@ -2380,7 +2512,7 @@ static void megasas_detach_one(struct pc
 
 	pci_set_drvdata(instance->pdev, NULL);
 
-	megasas_disable_intr(instance);
+	instance->instancet->disable_intr(instance->reg_set);
 
 	free_irq(instance->pdev->irq, instance);
 
@@ -2732,7 +2864,8 @@ static int megasas_mgmt_compat_ioctl_fw(
 	int i;
 	int error = 0;
 
-	clear_user(ioc, sizeof(*ioc));
+	if (clear_user(ioc, sizeof(*ioc)))
+		return -EFAULT;
 
 	if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
 	    copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
@@ -2824,6 +2957,26 @@ megasas_sysfs_show_release_date(struct d
 static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
 		   NULL);
 
+static ssize_t
+megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
+{
+	return sprintf(buf,"%u",megasas_dbg_lvl);
+}
+
+static ssize_t
+megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count)
+{
+	int retval = count;
+	if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){
+		printk(KERN_ERR "megasas: could not set dbg_lvl\n");
+		retval = -EINVAL;
+	}
+	return retval;
+}
+
+static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
+		   megasas_sysfs_set_dbg_lvl);
+
 /**
  * megasas_init - Driver load entry point
  */
@@ -2854,18 +3007,37 @@ static int __init megasas_init(void)
 	/*
 	 * Register ourselves as PCI hotplug module
 	 */
-	rval = pci_module_init(&megasas_pci_driver);
+	rval = pci_register_driver(&megasas_pci_driver);
 
 	if (rval) {
 		printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
-		unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+		goto err_pcidrv;
 	}
 
-	driver_create_file(&megasas_pci_driver.driver, &driver_attr_version);
-	driver_create_file(&megasas_pci_driver.driver,
-			   &driver_attr_release_date);
+	rval = driver_create_file(&megasas_pci_driver.driver,
+				  &driver_attr_version);
+	if (rval)
+		goto err_dcf_attr_ver;
+	rval = driver_create_file(&megasas_pci_driver.driver,
+				  &driver_attr_release_date);
+	if (rval)
+		goto err_dcf_rel_date;
+	rval = driver_create_file(&megasas_pci_driver.driver,
+				  &driver_attr_dbg_lvl);
+	if (rval)
+		goto err_dcf_dbg_lvl;
 
 	return rval;
+err_dcf_dbg_lvl:
+	driver_remove_file(&megasas_pci_driver.driver,
+			   &driver_attr_release_date);
+err_dcf_rel_date:
+	driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+err_dcf_attr_ver:
+	pci_unregister_driver(&megasas_pci_driver);
+err_pcidrv:
+	unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+  	return rval;
 }
 
 /**
@@ -2873,9 +3045,11 @@ static int __init megasas_init(void)
  */
 static void __exit megasas_exit(void)
 {
-	driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+	driver_remove_file(&megasas_pci_driver.driver,
+			   &driver_attr_dbg_lvl);
 	driver_remove_file(&megasas_pci_driver.driver,
 			   &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 -uprN linux-2.6.18-orig/drivers/scsi/megaraid/megaraid_sas.h linux-2.6.18/drivers/scsi/megaraid/megaraid_sas.h
--- linux-2.6.18-orig/drivers/scsi/megaraid/megaraid_sas.h	2006-10-04 13:10:19.000000000 -0700
+++ linux-2.6.18/drivers/scsi/megaraid/megaraid_sas.h	2006-10-04 13:12:50.000000000 -0700
@@ -18,9 +18,9 @@
 /**
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION				"00.00.03.01"
-#define MEGASAS_RELDATE				"May 14, 2006"
-#define MEGASAS_EXT_VERSION			"Sun May 14 22:49:52 PDT 2006"
+#define MEGASAS_VERSION				"00.00.03.05"
+#define MEGASAS_RELDATE				"Oct 02, 2006"
+#define MEGASAS_EXT_VERSION			"Mon Oct 02 11:21:32 PDT 2006"
 
 /*
  * Device IDs
@@ -50,6 +50,7 @@
 #define MFI_STATE_WAIT_HANDSHAKE		0x60000000
 #define MFI_STATE_FW_INIT_2			0x70000000
 #define MFI_STATE_DEVICE_SCAN			0x80000000
+#define MFI_STATE_BOOT_MESSAGE_PENDING		0x90000000
 #define MFI_STATE_FLUSH_CACHE			0xA0000000
 #define MFI_STATE_READY				0xB0000000
 #define MFI_STATE_OPERATIONAL			0xC0000000
@@ -64,12 +65,18 @@
  * READY	: Move from OPERATIONAL to READY state; discard queue info
  * MFIMODE	: Discard (possible) low MFA posted in 64-bit mode (??)
  * CLR_HANDSHAKE: FW is waiting for HANDSHAKE from BIOS or Driver
+ * HOTPLUG	: Resume from Hotplug
+ * MFI_STOP_ADP	: Send signal to FW to stop processing
  */
-#define MFI_INIT_ABORT				0x00000000
+#define MFI_INIT_ABORT				0x00000001
 #define MFI_INIT_READY				0x00000002
 #define MFI_INIT_MFIMODE			0x00000004
 #define MFI_INIT_CLEAR_HANDSHAKE		0x00000008
-#define MFI_RESET_FLAGS				MFI_INIT_READY|MFI_INIT_MFIMODE
+#define MFI_INIT_HOTPLUG			0x00000010
+#define MFI_STOP_ADP				0x00000020
+#define MFI_RESET_FLAGS				MFI_INIT_READY| \
+						MFI_INIT_MFIMODE| \
+						MFI_INIT_ABORT
 
 /**
  * MFI frame flags
@@ -530,6 +537,8 @@ struct megasas_ctrl_info {
 #define MEGASAS_MAX_LUN				8
 #define MEGASAS_MAX_LD				64
 
+#define MEGASAS_DBG_LVL				1
+
 /*
  * When SCSI mid-layer calls driver's reset routine, driver waits for
  * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note
@@ -538,6 +547,7 @@ struct megasas_ctrl_info {
  * every MEGASAS_RESET_NOTICE_INTERVAL seconds
  */
 #define MEGASAS_RESET_WAIT_TIME			180
+#define MEGASAS_INTERNAL_CMD_WAIT_TIME		180
 #define	MEGASAS_RESET_NOTICE_INTERVAL		5
 
 #define MEGASAS_IOCTL_CMD			0
@@ -1042,6 +1052,7 @@ struct megasas_evt_detail {
 	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 *);
 
@@ -1092,6 +1103,7 @@ struct megasas_instance {
 	u32 hw_crit_error;
 
 	struct megasas_instance_template *instancet;
+	struct tasklet_struct isr_tasklet;
 };
 
 #define MEGASAS_IS_LOGICAL(scp)						\