Merge branch 'upstream'
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index a6ac616..a748fbf 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -60,6 +60,7 @@
                  Remove un-needed eh_abort handler.
                  Add support for embedded firmware error strings.
    2.26.02.003 - Correctly handle single sgl's with use_sg=1.
+   2.26.02.004 - Add support for 9550SX controllers.
 */
 
 #include <linux/module.h>
@@ -82,7 +83,7 @@
 #include "3w-9xxx.h"
 
 /* Globals */
-#define TW_DRIVER_VERSION "2.26.02.003"
+#define TW_DRIVER_VERSION "2.26.02.004"
 static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
 static unsigned int twa_device_extension_count;
 static int twa_major = -1;
@@ -892,11 +893,6 @@
 		writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
 	}
 
-	if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
-		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing");
-		writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
-	}
-
 	if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
 		if (tw_dev->reset_print == 0) {
 			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
@@ -930,6 +926,36 @@
 	return retval;
 } /* End twa_empty_response_queue() */
 
+/* This function will clear the pchip/response queue on 9550SX */
+static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev)
+{
+	u32 status_reg_value, response_que_value;
+	int count = 0, retval = 1;
+
+	if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9550SX) {
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+		while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
+			response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev));
+			if ((response_que_value & TW_9550SX_DRAIN_COMPLETED) == TW_9550SX_DRAIN_COMPLETED) {
+				/* P-chip settle time */
+				msleep(500);
+				retval = 0;
+				goto out;
+			}
+			status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+			count++;
+		}
+		if (count == TW_MAX_RESPONSE_DRAIN)
+			goto out;
+		
+		retval = 0;
+	} else
+		retval = 0;
+out:
+	return retval;
+} /* End twa_empty_response_queue_large() */
+
 /* This function passes sense keys from firmware to scsi layer */
 static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
 {
@@ -1613,8 +1639,16 @@
 	int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
 
 	while (tries < TW_MAX_RESET_TRIES) {
-		if (do_soft_reset)
+		if (do_soft_reset) {
 			TW_SOFT_RESET(tw_dev);
+			/* Clear pchip/response queue on 9550SX */
+			if (twa_empty_response_queue_large(tw_dev)) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x36, "Response queue (large) empty failed during reset sequence");
+				do_soft_reset = 1;
+				tries++;
+				continue;
+			}
+		}
 
 		/* Make sure controller is in a good state */
 		if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) {
@@ -2034,7 +2068,10 @@
 		goto out_free_device_extension;
 	}
 
-	mem_addr = pci_resource_start(pdev, 1);
+	if (pdev->device == PCI_DEVICE_ID_3WARE_9000)
+		mem_addr = pci_resource_start(pdev, 1);
+	else
+		mem_addr = pci_resource_start(pdev, 2);
 
 	/* Save base address */
 	tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
@@ -2148,6 +2185,8 @@
 static struct pci_device_id twa_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
index 8c8ecbe..46f22cd 100644
--- a/drivers/scsi/3w-9xxx.h
+++ b/drivers/scsi/3w-9xxx.h
@@ -267,7 +267,6 @@
 #define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
 #define TW_CONTROL_CLEAR_QUEUE_ERROR           0x00400000
 #define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
-#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR      0x00000008
 
 /* Status register bit definitions */
 #define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
@@ -285,9 +284,8 @@
 #define TW_STATUS_MICROCONTROLLER_READY	       0x00002000
 #define TW_STATUS_COMMAND_QUEUE_EMPTY	       0x00001000
 #define TW_STATUS_EXPECTED_BITS		       0x00002000
-#define TW_STATUS_UNEXPECTED_BITS	       0x00F00008
-#define TW_STATUS_SBUF_WRITE_ERROR             0x00000008
-#define TW_STATUS_VALID_INTERRUPT              0x00DF0008
+#define TW_STATUS_UNEXPECTED_BITS	       0x00F00000
+#define TW_STATUS_VALID_INTERRUPT              0x00DF0000
 
 /* RESPONSE QUEUE BIT DEFINITIONS */
 #define TW_RESPONSE_ID_MASK		       0x00000FF0
@@ -324,9 +322,9 @@
 
 /* Compatibility defines */
 #define TW_9000_ARCH_ID 0x5
-#define TW_CURRENT_DRIVER_SRL 28
-#define TW_CURRENT_DRIVER_BUILD 9
-#define TW_CURRENT_DRIVER_BRANCH 4
+#define TW_CURRENT_DRIVER_SRL 30
+#define TW_CURRENT_DRIVER_BUILD 80
+#define TW_CURRENT_DRIVER_BRANCH 0
 
 /* Phase defines */
 #define TW_PHASE_INITIAL 0
@@ -334,6 +332,7 @@
 #define TW_PHASE_SGLIST  2
 
 /* Misc defines */
+#define TW_9550SX_DRAIN_COMPLETED	      0xFFFF
 #define TW_SECTOR_SIZE                        512
 #define TW_ALIGNMENT_9000                     4  /* 4 bytes */
 #define TW_ALIGNMENT_9000_SGL                 0x3
@@ -417,6 +416,9 @@
 #ifndef PCI_DEVICE_ID_3WARE_9000
 #define PCI_DEVICE_ID_3WARE_9000 0x1002
 #endif
+#ifndef PCI_DEVICE_ID_3WARE_9550SX
+#define PCI_DEVICE_ID_3WARE_9550SX 0x1003
+#endif
 
 /* Bitmask macros to eliminate bitfields */
 
@@ -443,6 +445,7 @@
 #define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x4)
 #define TW_COMMAND_QUEUE_REG_ADDR(x) (sizeof(dma_addr_t) > 4 ? ((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8))
 #define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0xC)
+#define TW_RESPONSE_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x30)
 #define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
 #define TW_CLEAR_ATTENTION_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
 #define TW_CLEAR_HOST_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1e4edbd..48529d1 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -99,6 +99,7 @@
 obj-$(CONFIG_SCSI_DC390T)	+= tmscsim.o
 obj-$(CONFIG_MEGARAID_LEGACY)	+= megaraid.o
 obj-$(CONFIG_MEGARAID_NEWGEN)	+= megaraid/
+obj-$(CONFIG_MEGARAID_SAS)	+= megaraid/
 obj-$(CONFIG_SCSI_ACARD)	+= atp870u.o
 obj-$(CONFIG_SCSI_SUNESP)	+= esp.o
 obj-$(CONFIG_SCSI_GDTH)		+= gdth.o
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index a8e3dfc..93416f7 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -313,18 +313,37 @@
 		}
 		dresp = (struct aac_mount *)fib_data(fibptr);
 
+		if ((le32_to_cpu(dresp->status) == ST_OK) &&
+		    (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
+			dinfo->command = cpu_to_le32(VM_NameServe64);
+			dinfo->count = cpu_to_le32(index);
+			dinfo->type = cpu_to_le32(FT_FILESYS);
+
+			if (fib_send(ContainerCommand,
+				    fibptr,
+				    sizeof(struct aac_query_mount),
+				    FsaNormal,
+				    1, 1,
+				    NULL, NULL) < 0)
+				continue;
+		} else
+			dresp->mnt[0].capacityhigh = 0;
+
 		dprintk ((KERN_DEBUG
-		  "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%u\n",
+		  "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%llu\n",
 		  (int)index, (int)le32_to_cpu(dresp->status),
 		  (int)le32_to_cpu(dresp->mnt[0].vol),
 		  (int)le32_to_cpu(dresp->mnt[0].state),
-		  (unsigned)le32_to_cpu(dresp->mnt[0].capacity)));
+		  ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+		    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32)));
 		if ((le32_to_cpu(dresp->status) == ST_OK) &&
 		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
 		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
 			fsa_dev_ptr[index].valid = 1;
 			fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol);
-			fsa_dev_ptr[index].size = le32_to_cpu(dresp->mnt[0].capacity);
+			fsa_dev_ptr[index].size
+			  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+			    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
 			if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
 				    fsa_dev_ptr[index].ro = 1;
 		}
@@ -460,7 +479,7 @@
  *	is updated in the struct fsa_dev_info structure rather than returned.
  */
  
-static int probe_container(struct aac_dev *dev, int cid)
+int probe_container(struct aac_dev *dev, int cid)
 {
 	struct fsa_dev_info *fsa_dev_ptr;
 	int status;
@@ -497,11 +516,29 @@
 	dresp = (struct aac_mount *) fib_data(fibptr);
 
 	if ((le32_to_cpu(dresp->status) == ST_OK) &&
+	    (le32_to_cpu(dresp->mnt[0].vol) == CT_NONE)) {
+		dinfo->command = cpu_to_le32(VM_NameServe64);
+		dinfo->count = cpu_to_le32(cid);
+		dinfo->type = cpu_to_le32(FT_FILESYS);
+
+		if (fib_send(ContainerCommand,
+			    fibptr,
+			    sizeof(struct aac_query_mount),
+			    FsaNormal,
+			    1, 1,
+			    NULL, NULL) < 0)
+			goto error;
+	} else
+		dresp->mnt[0].capacityhigh = 0;
+
+	if ((le32_to_cpu(dresp->status) == ST_OK) &&
 	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
 	    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
 		fsa_dev_ptr[cid].valid = 1;
 		fsa_dev_ptr[cid].type = le32_to_cpu(dresp->mnt[0].vol);
-		fsa_dev_ptr[cid].size = le32_to_cpu(dresp->mnt[0].capacity);
+		fsa_dev_ptr[cid].size
+		  = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
+		    (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32);
 		if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
 			fsa_dev_ptr[cid].ro = 1;
 	}
@@ -655,7 +692,7 @@
 			 fibptr, 
 			 sizeof(*info),
 			 FsaNormal, 
-			 1, 1, 
+			 -1, 1, /* First `interrupt' command uses special wait */
 			 NULL, 
 			 NULL);
 
@@ -806,8 +843,8 @@
 	if (!(dev->raw_io_interface)) {
 		dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size -
 			sizeof(struct aac_fibhdr) -
-			sizeof(struct aac_write) + sizeof(struct sgmap)) /
-				sizeof(struct sgmap);
+			sizeof(struct aac_write) + sizeof(struct sgentry)) /
+				sizeof(struct sgentry);
 		if (dev->dac_support) {
 			/* 
 			 * 38 scatter gather elements 
@@ -816,8 +853,8 @@
 				(dev->max_fib_size -
 				sizeof(struct aac_fibhdr) -
 				sizeof(struct aac_write64) +
-				sizeof(struct sgmap64)) /
-					sizeof(struct sgmap64);
+				sizeof(struct sgentry64)) /
+					sizeof(struct sgentry64);
 		}
 		dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
 		if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
@@ -854,7 +891,40 @@
 	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
 	cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
 
-	dprintk((KERN_DEBUG "io_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3], jiffies));
+	if (nblank(dprintk(x))) {
+		u64 lba;
+		switch (scsicmd->cmnd[0]) {
+		case WRITE_6:
+		case READ_6:
+			lba = ((scsicmd->cmnd[1] & 0x1F) << 16) |
+			    (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+			break;
+		case WRITE_16:
+		case READ_16:
+			lba = ((u64)scsicmd->cmnd[2] << 56) |
+			      ((u64)scsicmd->cmnd[3] << 48) |
+			      ((u64)scsicmd->cmnd[4] << 40) |
+			      ((u64)scsicmd->cmnd[5] << 32) |
+			      ((u64)scsicmd->cmnd[6] << 24) |
+			      (scsicmd->cmnd[7] << 16) |
+			      (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+			break;
+		case WRITE_12:
+		case READ_12:
+			lba = ((u64)scsicmd->cmnd[2] << 24) |
+			      (scsicmd->cmnd[3] << 16) |
+			      (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+			break;
+		default:
+			lba = ((u64)scsicmd->cmnd[2] << 24) |
+			       (scsicmd->cmnd[3] << 16) |
+			       (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+			break;
+		}
+		printk(KERN_DEBUG
+		  "io_callback[cpu %d]: lba = %llu, t = %ld.\n",
+		  smp_processor_id(), (unsigned long long)lba, jiffies);
+	}
 
 	if (fibptr == NULL)
 		BUG();
@@ -895,7 +965,7 @@
 
 static int aac_read(struct scsi_cmnd * scsicmd, int cid)
 {
-	u32 lba;
+	u64 lba;
 	u32 count;
 	int status;
 
@@ -907,23 +977,69 @@
 	/*
 	 *	Get block address and transfer length
 	 */
-	if (scsicmd->cmnd[0] == READ_6)	/* 6 byte command */
-	{
+	switch (scsicmd->cmnd[0]) {
+	case READ_6:
 		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", cid));
 
-		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | 
+			(scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
 		count = scsicmd->cmnd[4];
 
 		if (count == 0)
 			count = 256;
-	} else {
+		break;
+	case READ_16:
+		dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", cid));
+
+		lba = 	((u64)scsicmd->cmnd[2] << 56) |
+		 	((u64)scsicmd->cmnd[3] << 48) |
+			((u64)scsicmd->cmnd[4] << 40) |
+			((u64)scsicmd->cmnd[5] << 32) |
+			((u64)scsicmd->cmnd[6] << 24) | 
+			(scsicmd->cmnd[7] << 16) |
+			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+		count = (scsicmd->cmnd[10] << 24) | 
+			(scsicmd->cmnd[11] << 16) |
+			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
+		break;
+	case READ_12:
+		dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", cid));
+
+		lba = ((u64)scsicmd->cmnd[2] << 24) | 
+			(scsicmd->cmnd[3] << 16) |
+		    	(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		count = (scsicmd->cmnd[6] << 24) | 
+			(scsicmd->cmnd[7] << 16) |
+		      	(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+		break;
+	default:
 		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", cid));
 
-		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		lba = ((u64)scsicmd->cmnd[2] << 24) | 
+			(scsicmd->cmnd[3] << 16) | 
+			(scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+		break;
 	}
-	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %u, t = %ld.\n",
+	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n",
 	  smp_processor_id(), (unsigned long long)lba, jiffies));
+	if ((!(dev->raw_io_interface) || !(dev->raw_io_64)) &&
+		(lba & 0xffffffff00000000LL)) {
+		dprintk((KERN_DEBUG "aac_read: Illegal lba\n"));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | 
+			SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+			    HARDWARE_ERROR,
+			    SENCODE_INTERNAL_TARGET_FAILURE,
+			    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+			    0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+		    ? sizeof(scsicmd->sense_buffer)
+		    : sizeof(dev->fsa_dev[cid].sense_data));
+		scsicmd->scsi_done(scsicmd);
+		return 0;
+	}
 	/*
 	 *	Alocate and initialize a Fib
 	 */
@@ -936,8 +1052,8 @@
 	if (dev->raw_io_interface) {
 		struct aac_raw_io *readcmd;
 		readcmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
-		readcmd->block[0] = cpu_to_le32(lba);
-		readcmd->block[1] = 0;
+		readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
+		readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
 		readcmd->count = cpu_to_le32(count<<9);
 		readcmd->cid = cpu_to_le16(cid);
 		readcmd->flags = cpu_to_le16(1);
@@ -964,7 +1080,7 @@
 		readcmd->command = cpu_to_le32(VM_CtHostRead64);
 		readcmd->cid = cpu_to_le16(cid);
 		readcmd->sector_count = cpu_to_le16(count);
-		readcmd->block = cpu_to_le32(lba);
+		readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
 		readcmd->pad   = 0;
 		readcmd->flags = 0; 
 
@@ -989,7 +1105,7 @@
 		readcmd = (struct aac_read *) fib_data(cmd_fibcontext);
 		readcmd->command = cpu_to_le32(VM_CtBlockRead);
 		readcmd->cid = cpu_to_le32(cid);
-		readcmd->block = cpu_to_le32(lba);
+		readcmd->block = cpu_to_le32((u32)(lba&0xffffffff));
 		readcmd->count = cpu_to_le32(count * 512);
 
 		aac_build_sg(scsicmd, &readcmd->sg);
@@ -1031,7 +1147,7 @@
 
 static int aac_write(struct scsi_cmnd * scsicmd, int cid)
 {
-	u32 lba;
+	u64 lba;
 	u32 count;
 	int status;
 	u16 fibsize;
@@ -1048,13 +1164,48 @@
 		count = scsicmd->cmnd[4];
 		if (count == 0)
 			count = 256;
+	} else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */
+		dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", cid));
+
+		lba = 	((u64)scsicmd->cmnd[2] << 56) |
+			((u64)scsicmd->cmnd[3] << 48) |
+			((u64)scsicmd->cmnd[4] << 40) |
+			((u64)scsicmd->cmnd[5] << 32) |
+			((u64)scsicmd->cmnd[6] << 24) | 
+			(scsicmd->cmnd[7] << 16) |
+			(scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
+		count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) |
+			(scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13];
+	} else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */
+		dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", cid));
+
+		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16)
+		    | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16)
+		      | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9];
 	} else {
 		dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", cid));
-		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 	}
-	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %u, t = %ld.\n",
+	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n",
 	  smp_processor_id(), (unsigned long long)lba, jiffies));
+	if ((!(dev->raw_io_interface) || !(dev->raw_io_64))
+	 && (lba & 0xffffffff00000000LL)) {
+		dprintk((KERN_DEBUG "aac_write: Illegal lba\n"));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+			    HARDWARE_ERROR,
+			    SENCODE_INTERNAL_TARGET_FAILURE,
+			    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+			    0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+		    ? sizeof(scsicmd->sense_buffer)
+		    : sizeof(dev->fsa_dev[cid].sense_data));
+		scsicmd->scsi_done(scsicmd);
+		return 0;
+	}
 	/*
 	 *	Allocate and initialize a Fib then setup a BlockWrite command
 	 */
@@ -1068,8 +1219,8 @@
 	if (dev->raw_io_interface) {
 		struct aac_raw_io *writecmd;
 		writecmd = (struct aac_raw_io *) fib_data(cmd_fibcontext);
-		writecmd->block[0] = cpu_to_le32(lba);
-		writecmd->block[1] = 0;
+		writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff));
+		writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32));
 		writecmd->count = cpu_to_le32(count<<9);
 		writecmd->cid = cpu_to_le16(cid);
 		writecmd->flags = 0; 
@@ -1096,7 +1247,7 @@
 		writecmd->command = cpu_to_le32(VM_CtHostWrite64);
 		writecmd->cid = cpu_to_le16(cid);
 		writecmd->sector_count = cpu_to_le16(count); 
-		writecmd->block = cpu_to_le32(lba);
+		writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
 		writecmd->pad	= 0;
 		writecmd->flags	= 0;
 
@@ -1121,7 +1272,7 @@
 		writecmd = (struct aac_write *) fib_data(cmd_fibcontext);
 		writecmd->command = cpu_to_le32(VM_CtBlockWrite);
 		writecmd->cid = cpu_to_le32(cid);
-		writecmd->block = cpu_to_le32(lba);
+		writecmd->block = cpu_to_le32((u32)(lba&0xffffffff));
 		writecmd->count = cpu_to_le32(count * 512);
 		writecmd->sg.count = cpu_to_le32(1);
 		/* ->stable is not used - it did mean which type of write */
@@ -1310,11 +1461,18 @@
 			 */
 			if ((fsa_dev_ptr[cid].valid & 1) == 0) {
 				switch (scsicmd->cmnd[0]) {
+				case SERVICE_ACTION_IN:
+					if (!(dev->raw_io_interface) ||
+					    !(dev->raw_io_64) ||
+					    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+						break;
 				case INQUIRY:
 				case READ_CAPACITY:
 				case TEST_UNIT_READY:
 					spin_unlock_irq(host->host_lock);
 					probe_container(dev, cid);
+					if ((fsa_dev_ptr[cid].valid & 1) == 0)
+						fsa_dev_ptr[cid].valid = 0;
 					spin_lock_irq(host->host_lock);
 					if (fsa_dev_ptr[cid].valid == 0) {
 						scsicmd->result = DID_NO_CONNECT << 16;
@@ -1375,7 +1533,6 @@
 		memset(&inq_data, 0, sizeof (struct inquiry_data));
 
 		inq_data.inqd_ver = 2;	/* claim compliance to SCSI-2 */
-		inq_data.inqd_dtq = 0x80;	/* set RMB bit to one indicating that the medium is removable */
 		inq_data.inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
 		inq_data.inqd_len = 31;
 		/*Format for "pad2" is  RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
@@ -1397,13 +1554,55 @@
 		aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data));
 		return aac_get_container_name(scsicmd, cid);
 	}
+	case SERVICE_ACTION_IN:
+		if (!(dev->raw_io_interface) ||
+		    !(dev->raw_io_64) ||
+		    ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
+			break;
+	{
+		u64 capacity;
+		char cp[12];
+		unsigned int offset = 0;
+
+		dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n"));
+		capacity = fsa_dev_ptr[cid].size - 1;
+		if (scsicmd->cmnd[13] > 12) {
+			offset = scsicmd->cmnd[13] - 12;
+			if (offset > sizeof(cp))
+				break;
+			memset(cp, 0, offset);
+			aac_internal_transfer(scsicmd, cp, 0, offset);
+		}
+		cp[0] = (capacity >> 56) & 0xff;
+		cp[1] = (capacity >> 48) & 0xff;
+		cp[2] = (capacity >> 40) & 0xff;
+		cp[3] = (capacity >> 32) & 0xff;
+		cp[4] = (capacity >> 24) & 0xff;
+		cp[5] = (capacity >> 16) & 0xff;
+		cp[6] = (capacity >> 8) & 0xff;
+		cp[7] = (capacity >> 0) & 0xff;
+		cp[8] = 0;
+		cp[9] = 0;
+		cp[10] = 2;
+		cp[11] = 0;
+		aac_internal_transfer(scsicmd, cp, offset, sizeof(cp));
+
+		/* Do not cache partition table for arrays */
+		scsicmd->device->removable = 1;
+
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+		scsicmd->scsi_done(scsicmd);
+
+		return 0;
+	}
+
 	case READ_CAPACITY:
 	{
 		u32 capacity;
 		char cp[8];
 
 		dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
-		if (fsa_dev_ptr[cid].size <= 0x100000000LL)
+		if (fsa_dev_ptr[cid].size <= 0x100000000ULL)
 			capacity = fsa_dev_ptr[cid].size - 1;
 		else
 			capacity = (u32)-1;
@@ -1417,6 +1616,8 @@
 		cp[6] = 2;
 		cp[7] = 0;
 		aac_internal_transfer(scsicmd, cp, 0, sizeof(cp));
+		/* Do not cache partition table for arrays */
+		scsicmd->device->removable = 1;
 
 		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
 		scsicmd->scsi_done(scsicmd);
@@ -1497,6 +1698,8 @@
 	{
 		case READ_6:
 		case READ_10:
+		case READ_12:
+		case READ_16:
 			/*
 			 *	Hack to keep track of ordinal number of the device that
 			 *	corresponds to a container. Needed to convert
@@ -1504,17 +1707,19 @@
 			 */
 			 
 			spin_unlock_irq(host->host_lock);
-			if  (scsicmd->request->rq_disk)
-				memcpy(fsa_dev_ptr[cid].devname,
-					scsicmd->request->rq_disk->disk_name,
-					8);
-
+			if (scsicmd->request->rq_disk)
+				strlcpy(fsa_dev_ptr[cid].devname,
+				scsicmd->request->rq_disk->disk_name,
+			  	min(sizeof(fsa_dev_ptr[cid].devname),
+				sizeof(scsicmd->request->rq_disk->disk_name) + 1));
 			ret = aac_read(scsicmd, cid);
 			spin_lock_irq(host->host_lock);
 			return ret;
 
 		case WRITE_6:
 		case WRITE_10:
+		case WRITE_12:
+		case WRITE_16:
 			spin_unlock_irq(host->host_lock);
 			ret = aac_write(scsicmd, cid);
 			spin_lock_irq(host->host_lock);
@@ -1745,6 +1950,8 @@
 		case  WRITE_10:
 		case  READ_12:
 		case  WRITE_12:
+		case  READ_16:
+		case  WRITE_16:
 			if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) {
 				printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
 			} else {
@@ -1850,8 +2057,8 @@
 				sizeof(scsicmd->sense_buffer) :
 				le32_to_cpu(srbreply->sense_data_size);
 #ifdef AAC_DETAILED_STATUS_INFO
-		dprintk((KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", 
-					le32_to_cpu(srbreply->status), len));
+		printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
+					le32_to_cpu(srbreply->status), len);
 #endif
 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
 		
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index e405281..4a99d2f 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -1,6 +1,10 @@
 #if (!defined(dprintk))
 # define dprintk(x)
 #endif
+/* eg: if (nblank(dprintk(x))) */
+#define _nblank(x) #x
+#define nblank(x) _nblank(x)[0]
+
 
 /*------------------------------------------------------------------------------
  *              D E F I N E S
@@ -302,7 +306,6 @@
  */
 
 #define		FsaNormal	1
-#define		FsaHigh		2
 
 /*
  * Define the FIB. The FIB is the where all the requested data and
@@ -546,8 +549,6 @@
                   /* This is only valid for adapter to host command queues. */ 
 	spinlock_t	 	*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
 	spinlock_t		lockdata;	/* Actual lock (used only on one side of the lock) */
-	unsigned long		SavedIrql;     	/* Previous IRQL when the spin lock is taken */
-	u32			padding;	/* Padding - FIXME - can remove I believe */
 	struct list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
                                 		/* only valid for command queues which receive entries from the adapter. */
 	struct list_head	pendingq;	/* A queue of outstanding fib's to the adapter. */
@@ -776,7 +777,9 @@
 	u64		last;
 	u64		size;
 	u32		type;
+	u32		config_waiting_on;
 	u16		queue_depth;
+	u8		config_needed;
 	u8		valid;
 	u8		ro;
 	u8		locked;
@@ -1012,6 +1015,7 @@
 	/* macro side-effects BEWARE */
 #	define			raw_io_interface \
 	  init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
+	u8			raw_io_64;
 	u8			printf_enabled;
 };
 
@@ -1362,8 +1366,10 @@
 #define		VM_CtBlockVerify64	18
 #define		VM_CtHostRead64		19
 #define		VM_CtHostWrite64	20
+#define		VM_DrvErrTblLog		21
+#define		VM_NameServe64		22
 
-#define		MAX_VMCOMMAND_NUM	21	/* used for sizing stats array - leave last */
+#define		MAX_VMCOMMAND_NUM	23	/* used for sizing stats array - leave last */
 
 /*
  *	Descriptive information (eg, vital stats)
@@ -1472,6 +1478,7 @@
 						   manager (eg, filesystem) */
 	__le32			altoid;		/* != oid <==> snapshot or 
 						   broken mirror exists */
+	__le32			capacityhigh;
 };
 
 #define FSCS_NOTCLEAN	0x0001  /* fsck is neccessary before mounting */
@@ -1707,6 +1714,7 @@
 #define		AifCmdJobProgress	2	/* Progress report */
 #define			AifJobCtrZero	101	/* Array Zero progress */
 #define			AifJobStsSuccess 1	/* Job completes */
+#define			AifJobStsRunning 102	/* Job running */
 #define		AifCmdAPIReport		3	/* Report from other user of API */
 #define		AifCmdDriverNotify	4	/* Notify host driver of event */
 #define			AifDenMorphComplete 200	/* A morph operation completed */
@@ -1777,6 +1785,7 @@
 struct aac_driver_ident* aac_get_driver_ident(int devtype);
 int aac_get_adapter_info(struct aac_dev* dev);
 int aac_send_shutdown(struct aac_dev *dev);
+int probe_container(struct aac_dev *dev, int cid);
 extern int numacb;
 extern int acbsize;
 extern char aac_driver_version[];
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 75abd04..59a341b 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -195,7 +195,7 @@
 			  fibctx,
 			  sizeof(struct aac_close),
 			  FsaNormal,
-			  1, 1,
+			  -2 /* Timeout silently */, 1,
 			  NULL, NULL);
 
 	if (status == 0)
@@ -313,8 +313,15 @@
 	dev->max_fib_size = sizeof(struct hw_fib);
 	dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size
 		- sizeof(struct aac_fibhdr)
-		- sizeof(struct aac_write) + sizeof(struct sgmap))
-			/ sizeof(struct sgmap);
+		- sizeof(struct aac_write) + sizeof(struct sgentry))
+			/ sizeof(struct sgentry);
+	dev->raw_io_64 = 0;
+	if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
+		0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
+	 		(status[0] == 0x00000001)) {
+		if (status[1] & AAC_OPT_NEW_COMM_64)
+			dev->raw_io_64 = 1;
+	}
 	if ((!aac_adapter_sync_cmd(dev, GET_COMM_PREFERRED_SETTINGS,
 	  0, 0, 0, 0, 0, 0,
 	  status+0, status+1, status+2, status+3, status+4))
@@ -342,8 +349,8 @@
 			dev->max_fib_size = 512;
 			dev->sg_tablesize = host->sg_tablesize
 			  = (512 - sizeof(struct aac_fibhdr)
-			    - sizeof(struct aac_write) + sizeof(struct sgmap))
-			     / sizeof(struct sgmap);
+			    - sizeof(struct aac_write) + sizeof(struct sgentry))
+			     / sizeof(struct sgentry);
 			host->can_queue = AAC_NUM_IO_FIB;
 		} else if (acbsize == 2048) {
 			host->max_sectors = 512;
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index a1d303f0..e4d543a 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -39,7 +39,9 @@
 #include <linux/completion.h>
 #include <linux/blkdev.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
 #include <asm/semaphore.h>
+#include <asm/delay.h>
 
 #include "aacraid.h"
 
@@ -269,40 +271,22 @@
 	/* Interrupt Moderation, only interrupt for first two entries */
 	if (idx != le32_to_cpu(*(q->headers.consumer))) {
 		if (--idx == 0) {
-			if (qid == AdapHighCmdQueue)
-				idx = ADAP_HIGH_CMD_ENTRIES;
-			else if (qid == AdapNormCmdQueue)
+			if (qid == AdapNormCmdQueue)
 				idx = ADAP_NORM_CMD_ENTRIES;
-			else if (qid == AdapHighRespQueue) 
-	        		idx = ADAP_HIGH_RESP_ENTRIES;
-			else if (qid == AdapNormRespQueue) 
+			else
 				idx = ADAP_NORM_RESP_ENTRIES;
 		}
 		if (idx != le32_to_cpu(*(q->headers.consumer)))
 			*nonotify = 1; 
 	}
 
-	if (qid == AdapHighCmdQueue) {
-	        if (*index >= ADAP_HIGH_CMD_ENTRIES)
-        		*index = 0;
-	} else if (qid == AdapNormCmdQueue) {
+	if (qid == AdapNormCmdQueue) {
 	        if (*index >= ADAP_NORM_CMD_ENTRIES) 
 			*index = 0; /* Wrap to front of the Producer Queue. */
-	}
-	else if (qid == AdapHighRespQueue) 
-	{
-	        if (*index >= ADAP_HIGH_RESP_ENTRIES)
-			*index = 0;
-	}
-	else if (qid == AdapNormRespQueue) 
-	{
+	} else {
 		if (*index >= ADAP_NORM_RESP_ENTRIES) 
 			*index = 0; /* Wrap to front of the Producer Queue. */
 	}
-	else {
-		printk("aacraid: invalid qid\n");
-		BUG();
-	}
 
         if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
 		printk(KERN_WARNING "Queue %d full, %u outstanding.\n",
@@ -334,12 +318,8 @@
 {
 	struct aac_entry * entry = NULL;
 	int map = 0;
-	struct aac_queue * q = &dev->queues->queue[qid];
-		
-	spin_lock_irqsave(q->lock, q->SavedIrql);
 	    
-	if (qid == AdapHighCmdQueue || qid == AdapNormCmdQueue) 
-	{
+	if (qid == AdapNormCmdQueue) {
 		/*  if no entries wait for some if caller wants to */
         	while (!aac_get_entry(dev, qid, &entry, index, nonotify)) 
         	{
@@ -350,9 +330,7 @@
 	         */
 	        entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
 	        map = 1;
-	}
-	else if (qid == AdapHighRespQueue || qid == AdapNormRespQueue)
-	{
+	} else {
 	        while(!aac_get_entry(dev, qid, &entry, index, nonotify)) 
 	        {
 			/* if no entries wait for some if caller wants to */
@@ -375,42 +353,6 @@
 	return 0;
 }
 
-
-/**
- *	aac_insert_entry	-	insert a queue entry
- *	@dev: Adapter
- *	@index: Index of entry to insert
- *	@qid: Queue number
- *	@nonotify: Suppress adapter notification
- *
- *	Gets the next free QE off the requested priorty adapter command
- *	queue and associates the Fib with the QE. The QE represented by
- *	index is ready to insert on the queue when this routine returns
- *	success.
- */
- 
-static int aac_insert_entry(struct aac_dev * dev, u32 index, u32 qid, unsigned long nonotify) 
-{
-	struct aac_queue * q = &dev->queues->queue[qid];
-
-	if(q == NULL)
-		BUG();
-	*(q->headers.producer) = cpu_to_le32(index + 1);
-	spin_unlock_irqrestore(q->lock, q->SavedIrql);
-
-	if (qid == AdapHighCmdQueue ||
-	    qid == AdapNormCmdQueue ||
-	    qid == AdapHighRespQueue ||
-	    qid == AdapNormRespQueue)
-	{
-		if (!nonotify)
-			aac_adapter_notify(dev, qid);
-	}
-	else
-		printk("Suprise insert!\n");
-	return 0;
-}
-
 /*
  *	Define the highest level of host to adapter communication routines. 
  *	These routines will support host to adapter FS commuication. These 
@@ -439,12 +381,13 @@
 int fib_send(u16 command, struct fib * fibptr, unsigned long size,  int priority, int wait, int reply, fib_callback callback, void * callback_data)
 {
 	u32 index;
-	u32 qid;
 	struct aac_dev * dev = fibptr->dev;
 	unsigned long nointr = 0;
 	struct hw_fib * hw_fib = fibptr->hw_fib;
 	struct aac_queue * q;
 	unsigned long flags = 0;
+	unsigned long qflags;
+
 	if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
 		return -EBUSY;
 	/*
@@ -497,26 +440,8 @@
 	 *	Get a queue entry connect the FIB to it and send an notify
 	 *	the adapter a command is ready.
 	 */
-	if (priority == FsaHigh) {
-		hw_fib->header.XferState |= cpu_to_le32(HighPriority);
-		qid = AdapHighCmdQueue;
-	} else {
-		hw_fib->header.XferState |= cpu_to_le32(NormalPriority);
-		qid = AdapNormCmdQueue;
-	}
-	q = &dev->queues->queue[qid];
+	hw_fib->header.XferState |= cpu_to_le32(NormalPriority);
 
-	if(wait)
-		spin_lock_irqsave(&fibptr->event_lock, flags);
-	if(aac_queue_get( dev, &index, qid, hw_fib, 1, fibptr, &nointr)<0)
-		return -EWOULDBLOCK;
-	dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index));
-	dprintk((KERN_DEBUG "Fib contents:.\n"));
-	dprintk((KERN_DEBUG "  Command =               %d.\n", hw_fib->header.Command));
-	dprintk((KERN_DEBUG "  XferState  =            %x.\n", hw_fib->header.XferState));
-	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib));
-	dprintk((KERN_DEBUG "  hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
-	dprintk((KERN_DEBUG "  fib being sent=%p\n",fibptr));
 	/*
 	 *	Fill in the Callback and CallbackContext if we are not
 	 *	going to wait.
@@ -525,22 +450,67 @@
 		fibptr->callback = callback;
 		fibptr->callback_data = callback_data;
 	}
-	FIB_COUNTER_INCREMENT(aac_config.FibsSent);
-	list_add_tail(&fibptr->queue, &q->pendingq);
-	q->numpending++;
 
 	fibptr->done = 0;
 	fibptr->flags = 0;
 
-	if(aac_insert_entry(dev, index, qid, (nointr & aac_config.irq_mod)) < 0)
-		return -EWOULDBLOCK;
+	FIB_COUNTER_INCREMENT(aac_config.FibsSent);
+
+	dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index));
+	dprintk((KERN_DEBUG "Fib contents:.\n"));
+	dprintk((KERN_DEBUG "  Command =               %d.\n", hw_fib->header.Command));
+	dprintk((KERN_DEBUG "  XferState  =            %x.\n", hw_fib->header.XferState));
+	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib));
+	dprintk((KERN_DEBUG "  hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
+	dprintk((KERN_DEBUG "  fib being sent=%p\n",fibptr));
+
+	q = &dev->queues->queue[AdapNormCmdQueue];
+
+	if(wait)
+		spin_lock_irqsave(&fibptr->event_lock, flags);
+	spin_lock_irqsave(q->lock, qflags);
+	aac_queue_get( dev, &index, AdapNormCmdQueue, hw_fib, 1, fibptr, &nointr);
+
+	list_add_tail(&fibptr->queue, &q->pendingq);
+	q->numpending++;
+	*(q->headers.producer) = cpu_to_le32(index + 1);
+	spin_unlock_irqrestore(q->lock, qflags);
+	if (!(nointr & aac_config.irq_mod))
+		aac_adapter_notify(dev, AdapNormCmdQueue);
 	/*
 	 *	If the caller wanted us to wait for response wait now. 
 	 */
     
 	if (wait) {
 		spin_unlock_irqrestore(&fibptr->event_lock, flags);
-		down(&fibptr->event_wait);
+		/* Only set for first known interruptable command */
+		if (wait < 0) {
+			/*
+			 * *VERY* Dangerous to time out a command, the
+			 * assumption is made that we have no hope of
+			 * functioning because an interrupt routing or other
+			 * hardware failure has occurred.
+			 */
+			unsigned long count = 36000000L; /* 3 minutes */
+			unsigned long qflags;
+			while (down_trylock(&fibptr->event_wait)) {
+				if (--count == 0) {
+					spin_lock_irqsave(q->lock, qflags);
+					q->numpending--;
+					list_del(&fibptr->queue);
+					spin_unlock_irqrestore(q->lock, qflags);
+					if (wait == -1) {
+	        				printk(KERN_ERR "aacraid: fib_send: first asynchronous command timed out.\n"
+						  "Usually a result of a PCI interrupt routing problem;\n"
+						  "update mother board BIOS or consider utilizing one of\n"
+						  "the SAFE mode kernel options (acpi, apic etc)\n");
+					}
+					return -ETIMEDOUT;
+				}
+				udelay(5);
+			}
+		} else
+			down(&fibptr->event_wait);
 		if(fibptr->done == 0)
 			BUG();
 			
@@ -622,15 +592,9 @@
 		case HostNormCmdQueue:
 			notify = HostNormCmdNotFull;
 			break;
-		case HostHighCmdQueue:
-			notify = HostHighCmdNotFull;
-			break;
 		case HostNormRespQueue:
 			notify = HostNormRespNotFull;
 			break;
-		case HostHighRespQueue:
-			notify = HostHighRespNotFull;
-			break;
 		default:
 			BUG();
 			return;
@@ -652,9 +616,13 @@
 {
 	struct hw_fib * hw_fib = fibptr->hw_fib;
 	struct aac_dev * dev = fibptr->dev;
+	struct aac_queue * q;
 	unsigned long nointr = 0;
-	if (hw_fib->header.XferState == 0)
+	unsigned long qflags;
+
+	if (hw_fib->header.XferState == 0) {
         	return 0;
+	}
 	/*
 	 *	If we plan to do anything check the structure type first.
 	 */ 
@@ -669,37 +637,21 @@
 	 *	send the completed cdb to the adapter.
 	 */
 	if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
+		u32 index;
 	        hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
-	        if (hw_fib->header.XferState & cpu_to_le32(HighPriority)) {
-        		u32 index;
-       			if (size) 
-			{
-				size += sizeof(struct aac_fibhdr);
-				if (size > le16_to_cpu(hw_fib->header.SenderSize))
-					return -EMSGSIZE;
-				hw_fib->header.Size = cpu_to_le16(size);
-			}
-			if(aac_queue_get(dev, &index, AdapHighRespQueue, hw_fib, 1, NULL, &nointr) < 0) {
-				return -EWOULDBLOCK;
-			}
-			if (aac_insert_entry(dev, index, AdapHighRespQueue,  (nointr & (int)aac_config.irq_mod)) != 0) {
-			}
-		} else if (hw_fib->header.XferState & 
-				cpu_to_le32(NormalPriority)) {
-			u32 index;
-
-			if (size) {
-				size += sizeof(struct aac_fibhdr);
-				if (size > le16_to_cpu(hw_fib->header.SenderSize)) 
-					return -EMSGSIZE;
-				hw_fib->header.Size = cpu_to_le16(size);
-			}
-			if (aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr) < 0) 
-				return -EWOULDBLOCK;
-			if (aac_insert_entry(dev, index, AdapNormRespQueue, (nointr & (int)aac_config.irq_mod)) != 0) 
-			{
-			}
+		if (size) {
+			size += sizeof(struct aac_fibhdr);
+			if (size > le16_to_cpu(hw_fib->header.SenderSize)) 
+				return -EMSGSIZE;
+			hw_fib->header.Size = cpu_to_le16(size);
 		}
+		q = &dev->queues->queue[AdapNormRespQueue];
+		spin_lock_irqsave(q->lock, qflags);
+		aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr);
+		*(q->headers.producer) = cpu_to_le32(index + 1);
+		spin_unlock_irqrestore(q->lock, qflags);
+		if (!(nointr & (int)aac_config.irq_mod))
+			aac_adapter_notify(dev, AdapNormRespQueue);
 	}
 	else 
 	{
@@ -791,6 +743,268 @@
 	memset(cp, 0,  256);
 }
 
+
+/**
+ *	aac_handle_aif		-	Handle a message from the firmware
+ *	@dev: Which adapter this fib is from
+ *	@fibptr: Pointer to fibptr from adapter
+ *
+ *	This routine handles a driver notify fib from the adapter and
+ *	dispatches it to the appropriate routine for handling.
+ */
+
+static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
+{
+	struct hw_fib * hw_fib = fibptr->hw_fib;
+	struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data;
+	int busy;
+	u32 container;
+	struct scsi_device *device;
+	enum {
+		NOTHING,
+		DELETE,
+		ADD,
+		CHANGE
+	} device_config_needed;
+
+	/* Sniff for container changes */
+
+	if (!dev)
+		return;
+	container = (u32)-1;
+
+	/*
+	 *	We have set this up to try and minimize the number of
+	 * re-configures that take place. As a result of this when
+	 * certain AIF's come in we will set a flag waiting for another
+	 * type of AIF before setting the re-config flag.
+	 */
+	switch (le32_to_cpu(aifcmd->command)) {
+	case AifCmdDriverNotify:
+		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
+		/*
+		 *	Morph or Expand complete
+		 */
+		case AifDenMorphComplete:
+		case AifDenVolumeExtendComplete:
+			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			if (container >= dev->maximum_num_containers)
+				break;
+
+			/*
+			 *	Find the Scsi_Device associated with the SCSI
+			 * address. Make sure we have the right array, and if
+			 * so set the flag to initiate a new re-config once we
+			 * see an AifEnConfigChange AIF come through.
+			 */
+
+			if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) {
+				device = scsi_device_lookup(dev->scsi_host_ptr, 
+					CONTAINER_TO_CHANNEL(container), 
+					CONTAINER_TO_ID(container), 
+					CONTAINER_TO_LUN(container));
+				if (device) {
+					dev->fsa_dev[container].config_needed = CHANGE;
+					dev->fsa_dev[container].config_waiting_on = AifEnConfigChange;
+					scsi_device_put(device);
+				}
+			}
+		}
+
+		/*
+		 *	If we are waiting on something and this happens to be
+		 * that thing then set the re-configure flag.
+		 */
+		if (container != (u32)-1) {
+			if (container >= dev->maximum_num_containers)
+				break;
+			if (dev->fsa_dev[container].config_waiting_on ==
+			    le32_to_cpu(*(u32 *)aifcmd->data))
+				dev->fsa_dev[container].config_waiting_on = 0;
+		} else for (container = 0;
+		    container < dev->maximum_num_containers; ++container) {
+			if (dev->fsa_dev[container].config_waiting_on ==
+			    le32_to_cpu(*(u32 *)aifcmd->data))
+				dev->fsa_dev[container].config_waiting_on = 0;
+		}
+		break;
+
+	case AifCmdEventNotify:
+		switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) {
+		/*
+		 *	Add an Array.
+		 */
+		case AifEnAddContainer:
+			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			if (container >= dev->maximum_num_containers)
+				break;
+			dev->fsa_dev[container].config_needed = ADD;
+			dev->fsa_dev[container].config_waiting_on =
+				AifEnConfigChange;
+			break;
+
+		/*
+		 *	Delete an Array.
+		 */
+		case AifEnDeleteContainer:
+			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			if (container >= dev->maximum_num_containers)
+				break;
+			dev->fsa_dev[container].config_needed = DELETE;
+			dev->fsa_dev[container].config_waiting_on =
+				AifEnConfigChange;
+			break;
+
+		/*
+		 *	Container change detected. If we currently are not
+		 * waiting on something else, setup to wait on a Config Change.
+		 */
+		case AifEnContainerChange:
+			container = le32_to_cpu(((u32 *)aifcmd->data)[1]);
+			if (container >= dev->maximum_num_containers)
+				break;
+			if (dev->fsa_dev[container].config_waiting_on)
+				break;
+			dev->fsa_dev[container].config_needed = CHANGE;
+			dev->fsa_dev[container].config_waiting_on =
+				AifEnConfigChange;
+			break;
+
+		case AifEnConfigChange:
+			break;
+
+		}
+
+		/*
+		 *	If we are waiting on something and this happens to be
+		 * that thing then set the re-configure flag.
+		 */
+		if (container != (u32)-1) {
+			if (container >= dev->maximum_num_containers)
+				break;
+			if (dev->fsa_dev[container].config_waiting_on ==
+			    le32_to_cpu(*(u32 *)aifcmd->data))
+				dev->fsa_dev[container].config_waiting_on = 0;
+		} else for (container = 0;
+		    container < dev->maximum_num_containers; ++container) {
+			if (dev->fsa_dev[container].config_waiting_on ==
+			    le32_to_cpu(*(u32 *)aifcmd->data))
+				dev->fsa_dev[container].config_waiting_on = 0;
+		}
+		break;
+
+	case AifCmdJobProgress:
+		/*
+		 *	These are job progress AIF's. When a Clear is being
+		 * done on a container it is initially created then hidden from
+		 * the OS. When the clear completes we don't get a config
+		 * change so we monitor the job status complete on a clear then
+		 * wait for a container change.
+		 */
+
+		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
+		 && ((((u32 *)aifcmd->data)[6] == ((u32 *)aifcmd->data)[5])
+		  || (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess)))) {
+			for (container = 0;
+			    container < dev->maximum_num_containers;
+			    ++container) {
+				/*
+				 * Stomp on all config sequencing for all
+				 * containers?
+				 */
+				dev->fsa_dev[container].config_waiting_on =
+					AifEnContainerChange;
+				dev->fsa_dev[container].config_needed = ADD;
+			}
+		}
+		if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero))
+		 && (((u32 *)aifcmd->data)[6] == 0)
+		 && (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning))) {
+			for (container = 0;
+			    container < dev->maximum_num_containers;
+			    ++container) {
+				/*
+				 * Stomp on all config sequencing for all
+				 * containers?
+				 */
+				dev->fsa_dev[container].config_waiting_on =
+					AifEnContainerChange;
+				dev->fsa_dev[container].config_needed = DELETE;
+			}
+		}
+		break;
+	}
+
+	device_config_needed = NOTHING;
+	for (container = 0; container < dev->maximum_num_containers;
+	    ++container) {
+		if ((dev->fsa_dev[container].config_waiting_on == 0)
+		 && (dev->fsa_dev[container].config_needed != NOTHING)) {
+			device_config_needed =
+				dev->fsa_dev[container].config_needed;
+			dev->fsa_dev[container].config_needed = NOTHING;
+			break;
+		}
+	}
+	if (device_config_needed == NOTHING)
+		return;
+
+	/*
+	 *	If we decided that a re-configuration needs to be done,
+	 * schedule it here on the way out the door, please close the door
+	 * behind you.
+	 */
+
+	busy = 0;
+
+
+	/*
+	 *	Find the Scsi_Device associated with the SCSI address,
+	 * and mark it as changed, invalidating the cache. This deals
+	 * with changes to existing device IDs.
+	 */
+
+	if (!dev || !dev->scsi_host_ptr)
+		return;
+	/*
+	 * force reload of disk info via probe_container
+	 */
+	if ((device_config_needed == CHANGE)
+	 && (dev->fsa_dev[container].valid == 1))
+		dev->fsa_dev[container].valid = 2;
+	if ((device_config_needed == CHANGE) ||
+			(device_config_needed == ADD))
+		probe_container(dev, container);
+	device = scsi_device_lookup(dev->scsi_host_ptr, 
+		CONTAINER_TO_CHANNEL(container), 
+		CONTAINER_TO_ID(container), 
+		CONTAINER_TO_LUN(container));
+	if (device) {
+		switch (device_config_needed) {
+		case DELETE:
+			scsi_remove_device(device);
+			break;
+		case CHANGE:
+			if (!dev->fsa_dev[container].valid) {
+				scsi_remove_device(device);
+				break;
+			}
+			scsi_rescan_device(&device->sdev_gendev);
+
+		default:
+			break;
+		}
+		scsi_device_put(device);
+	}
+	if (device_config_needed == ADD) {
+		scsi_add_device(dev->scsi_host_ptr,
+		  CONTAINER_TO_CHANNEL(container),
+		  CONTAINER_TO_ID(container),
+		  CONTAINER_TO_LUN(container));
+	}
+
+}
+
 /**
  *	aac_command_thread	-	command processing thread
  *	@dev: Adapter to monitor
@@ -805,7 +1019,6 @@
 {
 	struct hw_fib *hw_fib, *hw_newfib;
 	struct fib *fib, *newfib;
-	struct aac_queue_block *queues = dev->queues;
 	struct aac_fib_context *fibctx;
 	unsigned long flags;
 	DECLARE_WAITQUEUE(wait, current);
@@ -825,21 +1038,22 @@
 	 *	Let the DPC know it has a place to send the AIF's to.
 	 */
 	dev->aif_thread = 1;
-	add_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
+	add_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
+	dprintk ((KERN_INFO "aac_command_thread start\n"));
 	while(1) 
 	{
-		spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
-		while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) {
+		spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
+		while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) {
 			struct list_head *entry;
 			struct aac_aifcmd * aifcmd;
 
 			set_current_state(TASK_RUNNING);
-		
-			entry = queues->queue[HostNormCmdQueue].cmdq.next;
+	
+			entry = dev->queues->queue[HostNormCmdQueue].cmdq.next;
 			list_del(entry);
-			
-			spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
+		
+			spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
 			fib = list_entry(entry, struct fib, fiblink);
 			/*
 			 *	We will process the FIB here or pass it to a 
@@ -860,6 +1074,7 @@
 			aifcmd = (struct aac_aifcmd *) hw_fib->data;
 			if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) {
 				/* Handle Driver Notify Events */
+				aac_handle_aif(dev, fib);
 				*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
 				fib_adapter_complete(fib, (u16)sizeof(u32));
 			} else {
@@ -869,9 +1084,62 @@
 				   
 				u32 time_now, time_last;
 				unsigned long flagv;
-				
+				unsigned num;
+				struct hw_fib ** hw_fib_pool, ** hw_fib_p;
+				struct fib ** fib_pool, ** fib_p;
+			
+				/* Sniff events */
+				if ((aifcmd->command == 
+				     cpu_to_le32(AifCmdEventNotify)) ||
+				    (aifcmd->command == 
+				     cpu_to_le32(AifCmdJobProgress))) {
+					aac_handle_aif(dev, fib);
+				}
+ 				
 				time_now = jiffies/HZ;
 
+				/*
+				 * Warning: no sleep allowed while
+				 * holding spinlock. We take the estimate
+				 * and pre-allocate a set of fibs outside the
+				 * lock.
+				 */
+				num = le32_to_cpu(dev->init->AdapterFibsSize)
+				    / sizeof(struct hw_fib); /* some extra */
+				spin_lock_irqsave(&dev->fib_lock, flagv);
+				entry = dev->fib_list.next;
+				while (entry != &dev->fib_list) {
+					entry = entry->next;
+					++num;
+				}
+				spin_unlock_irqrestore(&dev->fib_lock, flagv);
+				hw_fib_pool = NULL;
+				fib_pool = NULL;
+				if (num
+				 && ((hw_fib_pool = kmalloc(sizeof(struct hw_fib *) * num, GFP_KERNEL)))
+				 && ((fib_pool = kmalloc(sizeof(struct fib *) * num, GFP_KERNEL)))) {
+					hw_fib_p = hw_fib_pool;
+					fib_p = fib_pool;
+					while (hw_fib_p < &hw_fib_pool[num]) {
+						if (!(*(hw_fib_p++) = kmalloc(sizeof(struct hw_fib), GFP_KERNEL))) {
+							--hw_fib_p;
+							break;
+						}
+						if (!(*(fib_p++) = kmalloc(sizeof(struct fib), GFP_KERNEL))) {
+							kfree(*(--hw_fib_p));
+							break;
+						}
+					}
+					if ((num = hw_fib_p - hw_fib_pool) == 0) {
+						kfree(fib_pool);
+						fib_pool = NULL;
+						kfree(hw_fib_pool);
+						hw_fib_pool = NULL;
+					}
+				} else if (hw_fib_pool) {
+					kfree(hw_fib_pool);
+					hw_fib_pool = NULL;
+				}
 				spin_lock_irqsave(&dev->fib_lock, flagv);
 				entry = dev->fib_list.next;
 				/*
@@ -880,6 +1148,8 @@
 				 * fib, and then set the event to wake up the
 				 * thread that is waiting for it.
 				 */
+				hw_fib_p = hw_fib_pool;
+				fib_p = fib_pool;
 				while (entry != &dev->fib_list) {
 					/*
 					 * Extract the fibctx
@@ -912,9 +1182,11 @@
 					 * Warning: no sleep allowed while
 					 * holding spinlock
 					 */
-					hw_newfib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
-					newfib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
-					if (newfib && hw_newfib) {
+					if (hw_fib_p < &hw_fib_pool[num]) {
+						hw_newfib = *hw_fib_p;
+						*(hw_fib_p++) = NULL;
+						newfib = *fib_p;
+						*(fib_p++) = NULL;
 						/*
 						 * Make the copy of the FIB
 						 */
@@ -929,15 +1201,11 @@
 						fibctx->count++;
 						/* 
 						 * Set the event to wake up the
-						 * thread that will waiting.
+						 * thread that is waiting.
 						 */
 						up(&fibctx->wait_sem);
 					} else {
 						printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
-						if(newfib)
-							kfree(newfib);
-						if(hw_newfib)
-							kfree(hw_newfib);
 					}
 					entry = entry->next;
 				}
@@ -947,21 +1215,38 @@
 				*(__le32 *)hw_fib->data = cpu_to_le32(ST_OK);
 				fib_adapter_complete(fib, sizeof(u32));
 				spin_unlock_irqrestore(&dev->fib_lock, flagv);
+				/* Free up the remaining resources */
+				hw_fib_p = hw_fib_pool;
+				fib_p = fib_pool;
+				while (hw_fib_p < &hw_fib_pool[num]) {
+					if (*hw_fib_p)
+						kfree(*hw_fib_p);
+					if (*fib_p)
+						kfree(*fib_p);
+					++fib_p;
+					++hw_fib_p;
+				}
+				if (hw_fib_pool)
+					kfree(hw_fib_pool);
+				if (fib_pool)
+					kfree(fib_pool);
 			}
-			spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
 			kfree(fib);
+			spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags);
 		}
 		/*
 		 *	There are no more AIF's
 		 */
-		spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
+		spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags);
 		schedule();
 
 		if(signal_pending(current))
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
 	}
-	remove_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
+	if (dev->queues)
+		remove_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait);
 	dev->aif_thread = 0;
 	complete_and_exit(&dev->aif_completion, 0);
+	return 0;
 }
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 4ff29d7..de8490a 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -748,7 +748,8 @@
 		unique_id++;
 	}
 
-	if (pci_enable_device(pdev))
+	error = pci_enable_device(pdev);
+	if (error)
 		goto out;
 
 	if (pci_set_dma_mask(pdev, 0xFFFFFFFFULL) || 
@@ -772,6 +773,7 @@
 	shost->irq = pdev->irq;
 	shost->base = pci_resource_start(pdev, 0);
 	shost->unique_id = unique_id;
+	shost->max_cmd_len = 16;
 
 	aac = (struct aac_dev *)shost->hostdata;
 	aac->scsi_host_ptr = shost;	
@@ -799,7 +801,9 @@
 			goto out_free_fibs;
 
 	aac->maximum_num_channels = aac_drivers[index].channels;
-	aac_get_adapter_info(aac);
+	error = aac_get_adapter_info(aac);
+	if (error < 0)
+		goto out_deinit;
 
 	/*
  	 * Lets override negotiations and drop the maximum SG limit to 34
@@ -927,8 +931,8 @@
 	printk(KERN_INFO "Adaptec %s driver (%s)\n",
 	  AAC_DRIVERNAME, aac_driver_version);
 
-	error = pci_module_init(&aac_pci_driver);
-	if (error)
+	error = pci_register_driver(&aac_pci_driver);
+	if (error < 0)
 		return error;
 
 	aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops);
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index c2c8fa8..5ec866b 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -672,17 +672,36 @@
 
         for (i = 0; i < host_set->n_ports; i++) {
 		struct ata_port *ap;
-		u32 tmp;
 
-		VPRINTK("port %u\n", i);
+		if (!(irq_stat & (1 << i)))
+			continue;
+
 		ap = host_set->ports[i];
-		tmp = irq_stat & (1 << i);
-		if (tmp && ap) {
+		if (ap) {
 			struct ata_queued_cmd *qc;
 			qc = ata_qc_from_tag(ap, ap->active_tag);
-			if (ahci_host_intr(ap, qc))
-				irq_ack |= (1 << i);
+			if (!ahci_host_intr(ap, qc))
+				if (ata_ratelimit()) {
+					struct pci_dev *pdev =
+					  to_pci_dev(ap->host_set->dev);
+					printk(KERN_WARNING
+					  "ahci(%s): unhandled interrupt on port %u\n",
+					  pci_name(pdev), i);
+				}
+
+			VPRINTK("port %u\n", i);
+		} else {
+			VPRINTK("port %u (no irq)\n", i);
+			if (ata_ratelimit()) {
+				struct pci_dev *pdev =
+				  to_pci_dev(ap->host_set->dev);
+				printk(KERN_WARNING
+				  "ahci(%s): interrupt on disabled port %u\n",
+				  pci_name(pdev), i);
+			}
 		}
+
+		irq_ack |= (1 << i);
 	}
 
 	if (irq_ack) {
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
index 70c5fb5..d754b32 100644
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -112,6 +112,9 @@
 	struct ahc_softc *ahc = dev_get_drvdata(dev);
 	u_long s;
 
+	if (ahc->platform_data && ahc->platform_data->host)
+			scsi_remove_host(ahc->platform_data->host);
+
 	ahc_lock(ahc, &s);
 	ahc_intr_enable(ahc, FALSE);
 	ahc_unlock(ahc, &s);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 6b6d4e2..95c285cc8 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -1192,11 +1192,6 @@
 	int i, j;
 
 	if (ahd->platform_data != NULL) {
-		if (ahd->platform_data->host != NULL) {
-			scsi_remove_host(ahd->platform_data->host);
-			scsi_host_put(ahd->platform_data->host);
-		}
-
 		/* destroy all of the device and target objects */
 		for (i = 0; i < AHD_NUM_TARGETS; i++) {
 			starget = ahd->platform_data->starget[i];
@@ -1226,6 +1221,9 @@
 			release_mem_region(ahd->platform_data->mem_busaddr,
 					   0x1000);
 		}
+		if (ahd->platform_data->host)
+			scsi_host_put(ahd->platform_data->host);
+
 		free(ahd->platform_data, M_DEVBUF);
 	}
 }
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index 390b538..bf360ae 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -95,6 +95,9 @@
 	struct ahd_softc *ahd = pci_get_drvdata(pdev);
 	u_long s;
 
+	if (ahd->platform_data && ahd->platform_data->host)
+			scsi_remove_host(ahd->platform_data->host);
+
 	ahd_lock(ahd, &s);
 	ahd_intr_enable(ahd, FALSE);
 	ahd_unlock(ahd, &s);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 876d1de..6ee1435 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -1209,11 +1209,6 @@
 	int i, j;
 
 	if (ahc->platform_data != NULL) {
-		if (ahc->platform_data->host != NULL) {
-			scsi_remove_host(ahc->platform_data->host);
-			scsi_host_put(ahc->platform_data->host);
-		}
-
 		/* destroy all of the device and target objects */
 		for (i = 0; i < AHC_NUM_TARGETS; i++) {
 			starget = ahc->platform_data->starget[i];
@@ -1242,6 +1237,9 @@
 					   0x1000);
 		}
 
+		if (ahc->platform_data->host)
+			scsi_host_put(ahc->platform_data->host);
+
 		free(ahc->platform_data, M_DEVBUF);
 	}
 }
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 3ce77dd..cb30d9c 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -143,6 +143,9 @@
 	struct ahc_softc *ahc = pci_get_drvdata(pdev);
 	u_long s;
 
+	if (ahc->platform_data && ahc->platform_data->host)
+			scsi_remove_host(ahc->platform_data->host);
+
 	ahc_lock(ahc, &s);
 	ahc_intr_enable(ahc, FALSE);
 	ahc_unlock(ahc, &s);
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index f2a72d3..02fe371 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -176,6 +176,7 @@
 	transport_unregister_device(&shost->shost_gendev);
 	class_device_unregister(&shost->shost_classdev);
 	device_del(&shost->shost_gendev);
+	scsi_proc_hostdir_rm(shost->hostt);
 }
 EXPORT_SYMBOL(scsi_remove_host);
 
@@ -262,7 +263,6 @@
 	if (shost->work_q)
 		destroy_workqueue(shost->work_q);
 
-	scsi_proc_hostdir_rm(shost->hostt);
 	scsi_destroy_command_freelist(shost);
 	kfree(shost->shost_data);
 
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index ff291b3..2c9275e 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -48,6 +48,7 @@
 #include <linux/completion.h>
 #include <linux/suspend.h>
 #include <linux/workqueue.h>
+#include <linux/jiffies.h>
 #include <scsi/scsi.h>
 #include "scsi.h"
 #include "scsi_priv.h"
@@ -70,7 +71,6 @@
 static int ata_choose_xfer_mode(struct ata_port *ap,
 				u8 *xfer_mode_out,
 				unsigned int *xfer_shift_out);
-static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
 static void __ata_qc_complete(struct ata_queued_cmd *qc);
 
 static unsigned int ata_unique_id = 1;
@@ -3132,52 +3132,6 @@
 		goto fsm_start;
 }
 
-static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
-				struct scsi_cmnd *cmd)
-{
-	DECLARE_COMPLETION(wait);
-	struct ata_queued_cmd *qc;
-	unsigned long flags;
-	int rc;
-
-	DPRINTK("ATAPI request sense\n");
-
-	qc = ata_qc_new_init(ap, dev);
-	BUG_ON(qc == NULL);
-
-	/* FIXME: is this needed? */
-	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-
-	ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
-	qc->dma_dir = DMA_FROM_DEVICE;
-
-	memset(&qc->cdb, 0, ap->cdb_len);
-	qc->cdb[0] = REQUEST_SENSE;
-	qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
-
-	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
-	qc->tf.command = ATA_CMD_PACKET;
-
-	qc->tf.protocol = ATA_PROT_ATAPI;
-	qc->tf.lbam = (8 * 1024) & 0xff;
-	qc->tf.lbah = (8 * 1024) >> 8;
-	qc->nbytes = SCSI_SENSE_BUFFERSIZE;
-
-	qc->waiting = &wait;
-	qc->complete_fn = ata_qc_complete_noop;
-
-	spin_lock_irqsave(&ap->host_set->lock, flags);
-	rc = ata_qc_issue(qc);
-	spin_unlock_irqrestore(&ap->host_set->lock, flags);
-
-	if (rc)
-		ata_port_disable(ap);
-	else
-		wait_for_completion(&wait);
-
-	DPRINTK("EXIT\n");
-}
-
 /**
  *	ata_qc_timeout - Handle timeout of queued command
  *	@qc: Command that timed out
@@ -3297,14 +3251,14 @@
 	DPRINTK("ENTER\n");
 
 	qc = ata_qc_from_tag(ap, ap->active_tag);
-	if (!qc) {
+	if (qc)
+		ata_qc_timeout(qc);
+	else {
 		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
 		       ap->id);
 		goto out;
 	}
 
-	ata_qc_timeout(qc);
-
 out:
 	DPRINTK("EXIT\n");
 }
@@ -3373,7 +3327,7 @@
 	return qc;
 }
 
-static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
+int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
 {
 	return 0;
 }
@@ -4409,7 +4363,7 @@
 	for (i = 0; i < count; i++) {
 		struct ata_port *ap = host_set->ports[i];
 
-		scsi_scan_host(ap->host);
+		ata_scsi_scan_host(ap);
 	}
 
 	dev_set_drvdata(dev, host_set);
@@ -4569,85 +4523,87 @@
  *	ata_pci_init_native_mode - Initialize native-mode driver
  *	@pdev:  pci device to be initialized
  *	@port:  array[2] of pointers to port info structures.
+ *	@ports: bitmap of ports present
  *
  *	Utility function which allocates and initializes an
  *	ata_probe_ent structure for a standard dual-port
  *	PIO-based IDE controller.  The returned ata_probe_ent
  *	structure can be passed to ata_device_add().  The returned
  *	ata_probe_ent structure should then be freed with kfree().
+ *
+ *	The caller need only pass the address of the primary port, the
+ *	secondary will be deduced automatically. If the device has non
+ *	standard secondary port mappings this function can be called twice,
+ *	once for each interface.
  */
 
 struct ata_probe_ent *
-ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
+ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports)
 {
 	struct ata_probe_ent *probe_ent =
 		ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+	int p = 0;
+
 	if (!probe_ent)
 		return NULL;
 
-	probe_ent->n_ports = 2;
 	probe_ent->irq = pdev->irq;
 	probe_ent->irq_flags = SA_SHIRQ;
 
-	probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
-	probe_ent->port[0].altstatus_addr =
-	probe_ent->port[0].ctl_addr =
-		pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
-	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
+	if (ports & ATA_PORT_PRIMARY) {
+		probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
+		probe_ent->port[p].altstatus_addr =
+		probe_ent->port[p].ctl_addr =
+			pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+		probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4);
+		ata_std_ports(&probe_ent->port[p]);
+		p++;
+	}
 
-	probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
-	probe_ent->port[1].altstatus_addr =
-	probe_ent->port[1].ctl_addr =
-		pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
-	probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+	if (ports & ATA_PORT_SECONDARY) {
+		probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2);
+		probe_ent->port[p].altstatus_addr =
+		probe_ent->port[p].ctl_addr =
+			pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+		probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+		ata_std_ports(&probe_ent->port[p]);
+		p++;
+	}
 
-	ata_std_ports(&probe_ent->port[0]);
-	ata_std_ports(&probe_ent->port[1]);
-
+	probe_ent->n_ports = p;
 	return probe_ent;
 }
 
-static struct ata_probe_ent *
-ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port,
-    struct ata_probe_ent **ppe2)
+static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info **port, int port_num)
 {
-	struct ata_probe_ent *probe_ent, *probe_ent2;
+	struct ata_probe_ent *probe_ent;
 
 	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
 	if (!probe_ent)
 		return NULL;
-	probe_ent2 = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[1]);
-	if (!probe_ent2) {
-		kfree(probe_ent);
-		return NULL;
-	}
 
-	probe_ent->n_ports = 1;
-	probe_ent->irq = 14;
-
-	probe_ent->hard_port_no = 0;
+	
 	probe_ent->legacy_mode = 1;
+	probe_ent->n_ports = 1;
+	probe_ent->hard_port_no = port_num;
 
-	probe_ent2->n_ports = 1;
-	probe_ent2->irq = 15;
-
-	probe_ent2->hard_port_no = 1;
-	probe_ent2->legacy_mode = 1;
-
-	probe_ent->port[0].cmd_addr = 0x1f0;
-	probe_ent->port[0].altstatus_addr =
-	probe_ent->port[0].ctl_addr = 0x3f6;
-	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
-
-	probe_ent2->port[0].cmd_addr = 0x170;
-	probe_ent2->port[0].altstatus_addr =
-	probe_ent2->port[0].ctl_addr = 0x376;
-	probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8;
-
+	switch(port_num)
+	{
+		case 0:
+			probe_ent->irq = 14;
+			probe_ent->port[0].cmd_addr = 0x1f0;
+			probe_ent->port[0].altstatus_addr =
+			probe_ent->port[0].ctl_addr = 0x3f6;
+			break;
+		case 1:
+			probe_ent->irq = 15;
+			probe_ent->port[0].cmd_addr = 0x170;
+			probe_ent->port[0].altstatus_addr =
+			probe_ent->port[0].ctl_addr = 0x376;
+			break;
+	}
+	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4) + 8 * port_num;
 	ata_std_ports(&probe_ent->port[0]);
-	ata_std_ports(&probe_ent2->port[0]);
-
-	*ppe2 = probe_ent2;
 	return probe_ent;
 }
 
@@ -4676,7 +4632,7 @@
 int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
 		      unsigned int n_ports)
 {
-	struct ata_probe_ent *probe_ent, *probe_ent2 = NULL;
+	struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL;
 	struct ata_port_info *port[2];
 	u8 tmp8, mask;
 	unsigned int legacy_mode = 0;
@@ -4693,7 +4649,7 @@
 
 	if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
 	    && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
-		/* TODO: support transitioning to native mode? */
+		/* TODO: What if one channel is in native mode ... */
 		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
 		mask = (1 << 2) | (1 << 0);
 		if ((tmp8 & mask) != mask)
@@ -4701,11 +4657,20 @@
 	}
 
 	/* FIXME... */
-	if ((!legacy_mode) && (n_ports > 1)) {
-		printk(KERN_ERR "ata: BUG: native mode, n_ports > 1\n");
-		return -EINVAL;
+	if ((!legacy_mode) && (n_ports > 2)) {
+		printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
+		n_ports = 2;
+		/* For now */
 	}
 
+	/* FIXME: Really for ATA it isn't safe because the device may be
+	   multi-purpose and we want to leave it alone if it was already
+	   enabled. Secondly for shared use as Arjan says we want refcounting
+	   
+	   Checking dev->is_enabled is insufficient as this is not set at
+	   boot for the primary video which is BIOS enabled
+         */
+         
 	rc = pci_enable_device(pdev);
 	if (rc)
 		return rc;
@@ -4716,6 +4681,7 @@
 		goto err_out;
 	}
 
+	/* FIXME: Should use platform specific mappers for legacy port ranges */
 	if (legacy_mode) {
 		if (!request_region(0x1f0, 8, "libata")) {
 			struct resource *conflict, res;
@@ -4760,10 +4726,17 @@
 		goto err_out_regions;
 
 	if (legacy_mode) {
-		probe_ent = ata_pci_init_legacy_mode(pdev, port, &probe_ent2);
-	} else
-		probe_ent = ata_pci_init_native_mode(pdev, port);
-	if (!probe_ent) {
+		if (legacy_mode & (1 << 0))
+			probe_ent = ata_pci_init_legacy_port(pdev, port, 0);
+		if (legacy_mode & (1 << 1))
+			probe_ent2 = ata_pci_init_legacy_port(pdev, port, 1);
+	} else {
+		if (n_ports == 2)
+			probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
+		else
+			probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY);
+	}
+	if (!probe_ent && !probe_ent2) {
 		rc = -ENOMEM;
 		goto err_out_regions;
 	}
@@ -4875,6 +4848,27 @@
 module_init(ata_init);
 module_exit(ata_exit);
 
+static unsigned long ratelimit_time;
+static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED;
+
+int ata_ratelimit(void)
+{
+	int rc;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ata_ratelimit_lock, flags);
+
+	if (time_after(jiffies, ratelimit_time)) {
+		rc = 1;
+		ratelimit_time = jiffies + (HZ/5);
+	} else
+		rc = 0;
+
+	spin_unlock_irqrestore(&ata_ratelimit_lock, flags);
+
+	return rc;
+}
+
 /*
  * libata is essentially a library of internal helper functions for
  * low-level ATA host controller drivers.  As such, the API/ABI is
@@ -4916,6 +4910,7 @@
 EXPORT_SYMBOL_GPL(__sata_phy_reset);
 EXPORT_SYMBOL_GPL(ata_bus_reset);
 EXPORT_SYMBOL_GPL(ata_port_disable);
+EXPORT_SYMBOL_GPL(ata_ratelimit);
 EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
 EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
 EXPORT_SYMBOL_GPL(ata_scsi_error);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 03b7a6d..c64169c 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -49,6 +49,14 @@
 ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev);
 
 
+static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
+				   void (*done)(struct scsi_cmnd *))
+{
+	ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+	/* "Invalid field in cbd" */
+	done(cmd);
+}
+
 /**
  *	ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd.
  *	@sdev: SCSI device for which BIOS geometry is to be determined
@@ -182,7 +190,6 @@
 {
 	struct scsi_cmnd *cmd = qc->scsicmd;
 	u8 err = 0;
-	unsigned char *sb = cmd->sense_buffer;
 	/* Based on the 3ware driver translation table */
 	static unsigned char sense_table[][4] = {
 		/* BBD|ECC|ID|MAR */
@@ -225,8 +232,6 @@
 	};
 	int i = 0;
 
-	cmd->result = SAM_STAT_CHECK_CONDITION;
-
 	/*
 	 *	Is this an error we can process/parse
 	 */
@@ -281,11 +286,9 @@
 		/* Look for best matches first */
 		if((sense_table[i][0] & err) == sense_table[i][0])
 		{
-			sb[0] = 0x70;
-			sb[2] = sense_table[i][1];
-			sb[7] = 0x0a;
-			sb[12] = sense_table[i][2];
-			sb[13] = sense_table[i][3];
+			ata_scsi_set_sense(cmd, sense_table[i][1] /* sk */,
+					   sense_table[i][2] /* asc */,
+					   sense_table[i][3] /* ascq */ );
 			return;
 		}
 		i++;
@@ -300,11 +303,9 @@
 	{
 		if(stat_table[i][0] & drv_stat)
 		{
-			sb[0] = 0x70;
-			sb[2] = stat_table[i][1];
-			sb[7] = 0x0a;
-			sb[12] = stat_table[i][2];
-			sb[13] = stat_table[i][3];
+			ata_scsi_set_sense(cmd, sense_table[i][1] /* sk */,
+					   sense_table[i][2] /* asc */,
+					   sense_table[i][3] /* ascq */ );
 			return;
 		}
 		i++;
@@ -313,15 +314,12 @@
 	printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat);
 	/* additional-sense-code[-qualifier] */
 
-	sb[0] = 0x70;
-	sb[2] = MEDIUM_ERROR;
-	sb[7] = 0x0A;
 	if (cmd->sc_data_direction == DMA_FROM_DEVICE) {
-		sb[12] = 0x11; /* "unrecovered read error" */
-		sb[13] = 0x04;
+		ata_scsi_set_sense(cmd, MEDIUM_ERROR, 0x11, 0x4);
+		/* "unrecovered read error" */
 	} else {
-		sb[12] = 0x0C; /* "write error -             */
-		sb[13] = 0x02; /*  auto-reallocation failed" */
+		ata_scsi_set_sense(cmd, MEDIUM_ERROR, 0xc, 0x2);
+		/* "write error - auto-reallocation failed" */
 	}
 }
 
@@ -430,15 +428,26 @@
 		;	/* ignore IMMED bit, violates sat-r05 */
 	}
 	if (scsicmd[4] & 0x2)
-		return 1;	/* LOEJ bit set not supported */
+		goto invalid_fld;       /* LOEJ bit set not supported */
 	if (((scsicmd[4] >> 4) & 0xf) != 0)
-		return 1;	/* power conditions not supported */
+		goto invalid_fld;       /* power conditions not supported */
 	if (scsicmd[4] & 0x1) {
 		tf->nsect = 1;	/* 1 sector, lba=0 */
-		tf->lbah = 0x0;
-		tf->lbam = 0x0;
-		tf->lbal = 0x0;
-		tf->device |= ATA_LBA;
+
+		if (qc->dev->flags & ATA_DFLAG_LBA) {
+			qc->tf.flags |= ATA_TFLAG_LBA;
+
+			tf->lbah = 0x0;
+			tf->lbam = 0x0;
+			tf->lbal = 0x0;
+			tf->device |= ATA_LBA;
+		} else {
+			/* CHS */
+			tf->lbal = 0x1; /* sect */
+			tf->lbam = 0x0; /* cyl low */
+			tf->lbah = 0x0; /* cyl high */
+		}
+
 		tf->command = ATA_CMD_VERIFY;	/* READ VERIFY */
 	} else {
 		tf->nsect = 0;	/* time period value (0 implies now) */
@@ -453,6 +462,11 @@
 	 */
 
 	return 0;
+
+invalid_fld:
+	ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+	/* "Invalid field in cbd" */
+	return 1;
 }
 
 
@@ -488,6 +502,99 @@
 }
 
 /**
+ *	scsi_6_lba_len - Get LBA and transfer length
+ *	@scsicmd: SCSI command to translate
+ *
+ *	Calculate LBA and transfer length for 6-byte commands.
+ *
+ *	RETURNS:
+ *	@plba: the LBA
+ *	@plen: the transfer length
+ */
+
+static void scsi_6_lba_len(u8 *scsicmd, u64 *plba, u32 *plen)
+{
+	u64 lba = 0;
+	u32 len = 0;
+
+	VPRINTK("six-byte command\n");
+
+	lba |= ((u64)scsicmd[2]) << 8;
+	lba |= ((u64)scsicmd[3]);
+
+	len |= ((u32)scsicmd[4]);
+
+	*plba = lba;
+	*plen = len;
+}
+
+/**
+ *	scsi_10_lba_len - Get LBA and transfer length
+ *	@scsicmd: SCSI command to translate
+ *
+ *	Calculate LBA and transfer length for 10-byte commands.
+ *
+ *	RETURNS:
+ *	@plba: the LBA
+ *	@plen: the transfer length
+ */
+
+static void scsi_10_lba_len(u8 *scsicmd, u64 *plba, u32 *plen)
+{
+	u64 lba = 0;
+	u32 len = 0;
+
+	VPRINTK("ten-byte command\n");
+
+	lba |= ((u64)scsicmd[2]) << 24;
+	lba |= ((u64)scsicmd[3]) << 16;
+	lba |= ((u64)scsicmd[4]) << 8;
+	lba |= ((u64)scsicmd[5]);
+
+	len |= ((u32)scsicmd[7]) << 8;
+	len |= ((u32)scsicmd[8]);
+
+	*plba = lba;
+	*plen = len;
+}
+
+/**
+ *	scsi_16_lba_len - Get LBA and transfer length
+ *	@scsicmd: SCSI command to translate
+ *
+ *	Calculate LBA and transfer length for 16-byte commands.
+ *
+ *	RETURNS:
+ *	@plba: the LBA
+ *	@plen: the transfer length
+ */
+
+static void scsi_16_lba_len(u8 *scsicmd, u64 *plba, u32 *plen)
+{
+	u64 lba = 0;
+	u32 len = 0;
+
+	VPRINTK("sixteen-byte command\n");
+
+	lba |= ((u64)scsicmd[2]) << 56;
+	lba |= ((u64)scsicmd[3]) << 48;
+	lba |= ((u64)scsicmd[4]) << 40;
+	lba |= ((u64)scsicmd[5]) << 32;
+	lba |= ((u64)scsicmd[6]) << 24;
+	lba |= ((u64)scsicmd[7]) << 16;
+	lba |= ((u64)scsicmd[8]) << 8;
+	lba |= ((u64)scsicmd[9]);
+
+	len |= ((u32)scsicmd[10]) << 24;
+	len |= ((u32)scsicmd[11]) << 16;
+	len |= ((u32)scsicmd[12]) << 8;
+	len |= ((u32)scsicmd[13]);
+
+	*plba = lba;
+	*plen = len;
+}
+
+/**
  *	ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
  *	@qc: Storage for translated ATA taskfile
  *	@scsicmd: SCSI command to translate
@@ -508,53 +615,31 @@
 	unsigned int lba   = tf->flags & ATA_TFLAG_LBA;
 	unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
 	u64 dev_sectors = qc->dev->n_sectors;
-	u64 block = 0;
-	u32 n_block = 0;
+	u64 block;
+	u32 n_block;
 
 	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 	tf->protocol = ATA_PROT_NODATA;
 
-	if (scsicmd[0] == VERIFY) {
-		block |= ((u64)scsicmd[2]) << 24;
-		block |= ((u64)scsicmd[3]) << 16;
-		block |= ((u64)scsicmd[4]) << 8;
-		block |= ((u64)scsicmd[5]);
-
-		n_block |= ((u32)scsicmd[7]) << 8;
-		n_block |= ((u32)scsicmd[8]);
-	}
-
-	else if (scsicmd[0] == VERIFY_16) {
-		block |= ((u64)scsicmd[2]) << 56;
-		block |= ((u64)scsicmd[3]) << 48;
-		block |= ((u64)scsicmd[4]) << 40;
-		block |= ((u64)scsicmd[5]) << 32;
-		block |= ((u64)scsicmd[6]) << 24;
-		block |= ((u64)scsicmd[7]) << 16;
-		block |= ((u64)scsicmd[8]) << 8;
-		block |= ((u64)scsicmd[9]);
-
-		n_block |= ((u32)scsicmd[10]) << 24;
-		n_block |= ((u32)scsicmd[11]) << 16;
-		n_block |= ((u32)scsicmd[12]) << 8;
-		n_block |= ((u32)scsicmd[13]);
-	}
-
+	if (scsicmd[0] == VERIFY)
+		scsi_10_lba_len(scsicmd, &block, &n_block);
+	else if (scsicmd[0] == VERIFY_16)
+		scsi_16_lba_len(scsicmd, &block, &n_block);
 	else
-		return 1;
+		goto invalid_fld;
 
 	if (!n_block)
-		return 1;
+		goto nothing_to_do;
 	if (block >= dev_sectors)
-		return 1;
+		goto out_of_range;
 	if ((block + n_block) > dev_sectors)
-		return 1;
+		goto out_of_range;
 	if (lba48) {
 		if (n_block > (64 * 1024))
-			return 1;
+			goto invalid_fld;
 	} else {
 		if (n_block > 256)
-			return 1;
+			goto invalid_fld;
 	}
 
 	if (lba) {
@@ -589,14 +674,15 @@
 		head  = track % dev->heads;
 		sect  = (u32)block % dev->sectors + 1;
 
-		DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", (u32)block, track, cyl, head, sect);
+		DPRINTK("block %u track %u cyl %u head %u sect %u\n",
+			(u32)block, track, cyl, head, sect);
 		
 		/* Check whether the converted CHS can fit. 
 		   Cylinder: 0-65535 
 		   Head: 0-15
 		   Sector: 1-255*/
 		if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) 
-			return 1;
+			goto out_of_range;
 		
 		tf->command = ATA_CMD_VERIFY;
 		tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
@@ -607,6 +693,20 @@
 	}
 
 	return 0;
+
+invalid_fld:
+	ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+	/* "Invalid field in cbd" */
+	return 1;
+
+out_of_range:
+	ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
+	/* "Logical Block Address out of range" */
+	return 1;
+
+nothing_to_do:
+	qc->scsicmd->result = SAM_STAT_GOOD;
+	return 1;
 }
 
 /**
@@ -635,8 +735,8 @@
 	struct ata_device *dev = qc->dev;
 	unsigned int lba   = tf->flags & ATA_TFLAG_LBA;
 	unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
-	u64 block = 0;
-	u32 n_block = 0;
+	u64 block;
+	u32 n_block;
 
 	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
 	tf->protocol = qc->dev->xfer_protocol;
@@ -650,56 +750,44 @@
 	}
 
 	/* Calculate the SCSI LBA and transfer length. */
-	if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) {
-		block |= ((u64)scsicmd[2]) << 24;
-		block |= ((u64)scsicmd[3]) << 16;
-		block |= ((u64)scsicmd[4]) << 8;
-		block |= ((u64)scsicmd[5]);
+	switch (scsicmd[0]) {
+	case READ_10:
+	case WRITE_10:
+		scsi_10_lba_len(scsicmd, &block, &n_block);
+		break;
+	case READ_6:
+	case WRITE_6:
+		scsi_6_lba_len(scsicmd, &block, &n_block);
 
-		n_block |= ((u32)scsicmd[7]) << 8;
-		n_block |= ((u32)scsicmd[8]);
-
-		VPRINTK("ten-byte command\n");
-	} else if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
-		block |= ((u64)scsicmd[2]) << 8;
-		block |= ((u64)scsicmd[3]);
-
-		n_block |= ((u32)scsicmd[4]);
+		/* for 6-byte r/w commands, transfer length 0
+		 * means 256 blocks of data, not 0 block.
+		 */
 		if (!n_block)
 			n_block = 256;
-	
-		VPRINTK("six-byte command\n");
-	} else if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
-		block |= ((u64)scsicmd[2]) << 56;
-		block |= ((u64)scsicmd[3]) << 48;
-		block |= ((u64)scsicmd[4]) << 40;
-		block |= ((u64)scsicmd[5]) << 32;
-		block |= ((u64)scsicmd[6]) << 24;
-		block |= ((u64)scsicmd[7]) << 16;
-		block |= ((u64)scsicmd[8]) << 8;
-		block |= ((u64)scsicmd[9]);
-
-		n_block |= ((u32)scsicmd[10]) << 24;
-		n_block |= ((u32)scsicmd[11]) << 16;
-		n_block |= ((u32)scsicmd[12]) << 8;
-		n_block |= ((u32)scsicmd[13]);
-
-		VPRINTK("sixteen-byte command\n");
-	} else {
+		break;
+	case READ_16:
+	case WRITE_16:
+		scsi_16_lba_len(scsicmd, &block, &n_block);
+		break;
+	default:
 		DPRINTK("no-byte command\n");
-		return 1;
+		goto invalid_fld;
 	}
 
 	/* Check and compose ATA command */
 	if (!n_block)
-		/* In ATA, sector count 0 means 256 or 65536 sectors, not 0 sectors. */
-		return 1;
+		/* For 10-byte and 16-byte SCSI R/W commands, transfer
+		 * length 0 means transfer 0 block of data.
+		 * However, for ATA R/W commands, sector count 0 means
+		 * 256 or 65536 sectors, not 0 sectors as in SCSI.
+		 */
+		goto nothing_to_do;
 
 	if (lba) {
 		if (lba48) {
 			/* The request -may- be too large for LBA48. */
 			if ((block >> 48) || (n_block > 65536))
-				return 1;
+				goto out_of_range;
 
 			tf->hob_nsect = (n_block >> 8) & 0xff;
 
@@ -711,11 +799,11 @@
 
 			/* The request -may- be too large for LBA28. */
 			if ((block >> 28) || (n_block > 256))
-				return 1;
+				goto out_of_range;
 
 			tf->device |= (block >> 24) & 0xf;
 		}
-	
+
 		qc->nsect = n_block;
 		tf->nsect = n_block & 0xff;
 
@@ -730,24 +818,24 @@
 
 		/* The request -may- be too large for CHS addressing. */
 		if ((block >> 28) || (n_block > 256))
-			return 1;
-			
+			goto out_of_range;
+
 		/* Convert LBA to CHS */
 		track = (u32)block / dev->sectors;
 		cyl   = track / dev->heads;
 		head  = track % dev->heads;
 		sect  = (u32)block % dev->sectors + 1;
 
-		DPRINTK("block[%u] track[%u] cyl[%u] head[%u] sect[%u] \n", 
+		DPRINTK("block %u track %u cyl %u head %u sect %u\n",
 			(u32)block, track, cyl, head, sect);
-		
+
 		/* Check whether the converted CHS can fit. 
 		   Cylinder: 0-65535 
 		   Head: 0-15
 		   Sector: 1-255*/
-		if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) 
-			return 1;
-		
+		if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect))
+			goto out_of_range;
+
 		qc->nsect = n_block;
 		tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */
 		tf->lbal = sect;
@@ -757,6 +845,20 @@
 	}
 
 	return 0;
+
+invalid_fld:
+	ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0);
+	/* "Invalid field in cbd" */
+	return 1;
+
+out_of_range:
+	ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0);
+	/* "Logical Block Address out of range" */
+	return 1;
+
+nothing_to_do:
+	qc->scsicmd->result = SAM_STAT_GOOD;
+	return 1;
 }
 
 static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
@@ -788,6 +890,12 @@
  *	This function sets up an ata_queued_cmd structure for the
  *	SCSI command, and sends that ata_queued_cmd to the hardware.
  *
+ *	The xlat_func argument (actor) returns 0 if ready to execute
+ *	ATA command, else 1 to finish translation. If 1 is returned
+ *	then cmd->result (and possibly cmd->sense_buffer) are assumed
+ *	to be set reflecting an error condition or clean (early)
+ *	termination.
+ *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
  */
@@ -804,7 +912,7 @@
 
 	qc = ata_scsi_qc_new(ap, dev, cmd, done);
 	if (!qc)
-		return;
+		goto err_mem;
 
 	/* data is present; dma-map it */
 	if (cmd->sc_data_direction == DMA_FROM_DEVICE ||
@@ -812,7 +920,7 @@
 		if (unlikely(cmd->request_bufflen < 1)) {
 			printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n",
 			       ap->id, dev->devno);
-			goto err_out;
+			goto err_did;
 		}
 
 		if (cmd->use_sg)
@@ -827,19 +935,28 @@
 	qc->complete_fn = ata_scsi_qc_complete;
 
 	if (xlat_func(qc, scsicmd))
-		goto err_out;
+		goto early_finish;
 
 	/* select device, send command to hardware */
 	if (ata_qc_issue(qc))
-		goto err_out;
+		goto err_did;
 
 	VPRINTK("EXIT\n");
 	return;
 
-err_out:
+early_finish:
+        ata_qc_free(qc);
+	done(cmd);
+	DPRINTK("EXIT - early finish (good or error)\n");
+	return;
+
+err_did:
 	ata_qc_free(qc);
-	ata_bad_cdb(cmd, done);
-	DPRINTK("EXIT - badcmd\n");
+err_mem:
+	cmd->result = (DID_ERROR << 16);
+	done(cmd);
+	DPRINTK("EXIT - internal\n");
+	return;
 }
 
 /**
@@ -906,7 +1023,8 @@
  *	Mapping the response buffer, calling the command's handler,
  *	and handling the handler's return value.  This return value
  *	indicates whether the handler wishes the SCSI command to be
- *	completed successfully, or not.
+ *	completed successfully (0), or not (in which case cmd->result
+ *	and sense buffer are assumed to be set).
  *
  *	LOCKING:
  *	spin_lock_irqsave(host_set lock)
@@ -925,12 +1043,9 @@
 	rc = actor(args, rbuf, buflen);
 	ata_scsi_rbuf_put(cmd, rbuf);
 
-	if (rc)
-		ata_bad_cdb(cmd, args->done);
-	else {
+	if (rc == 0)
 		cmd->result = SAM_STAT_GOOD;
-		args->done(cmd);
-	}
+	args->done(cmd);
 }
 
 /**
@@ -1236,8 +1351,16 @@
 	 * in the same manner)
 	 */
 	page_control = scsicmd[2] >> 6;
-	if ((page_control != 0) && (page_control != 3))
-		return 1;
+	switch (page_control) {
+	case 0: /* current */
+		break;  /* supported */
+	case 3: /* saved */
+		goto saving_not_supp;
+	case 1: /* changeable */
+	case 2: /* defaults */
+	default:
+		goto invalid_fld;
+	}
 
 	if (six_byte)
 		output_len = 4;
@@ -1268,7 +1391,7 @@
 		break;
 
 	default:		/* invalid page code */
-		return 1;
+		goto invalid_fld;
 	}
 
 	if (six_byte) {
@@ -1281,6 +1404,16 @@
 	}
 
 	return 0;
+
+invalid_fld:
+	ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0);
+	/* "Invalid field in cbd" */
+	return 1;
+
+saving_not_supp:
+	ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0);
+	 /* "Saving parameters not supported" */
+	return 1;
 }
 
 /**
@@ -1380,6 +1513,34 @@
 }
 
 /**
+ *	ata_scsi_set_sense - Set SCSI sense data and status
+ *	@cmd: SCSI request to be handled
+ *	@sk: SCSI-defined sense key
+ *	@asc: SCSI-defined additional sense code
+ *	@ascq: SCSI-defined additional sense code qualifier
+ *
+ *	Helper function that builds a valid fixed format, current
+ *	response code and the given sense key (sk), additional sense
+ *	code (asc) and additional sense code qualifier (ascq) with
+ *	a SCSI command status of %SAM_STAT_CHECK_CONDITION and
+ *	DRIVER_SENSE set in the upper bits of scsi_cmnd::result .
+ *
+ *	LOCKING:
+ *	Not required
+ */
+
+void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+{
+	cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+	cmd->sense_buffer[0] = 0x70;	/* fixed format, current */
+	cmd->sense_buffer[2] = sk;
+	cmd->sense_buffer[7] = 18 - 8;	/* additional sense length */
+	cmd->sense_buffer[12] = asc;
+	cmd->sense_buffer[13] = ascq;
+}
+
+/**
  *	ata_scsi_badcmd - End a SCSI request with an error
  *	@cmd: SCSI request to be handled
  *	@done: SCSI command completion function
@@ -1397,30 +1558,84 @@
 void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
 {
 	DPRINTK("ENTER\n");
-	cmd->result = SAM_STAT_CHECK_CONDITION;
-
-	cmd->sense_buffer[0] = 0x70;
-	cmd->sense_buffer[2] = ILLEGAL_REQUEST;
-	cmd->sense_buffer[7] = 14 - 8;	/* addnl. sense len. FIXME: correct? */
-	cmd->sense_buffer[12] = asc;
-	cmd->sense_buffer[13] = ascq;
+	ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);
 
 	done(cmd);
 }
 
+void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
+			 struct scsi_cmnd *cmd)
+{
+	DECLARE_COMPLETION(wait);
+	struct ata_queued_cmd *qc;
+	unsigned long flags;
+	int rc;
+
+	DPRINTK("ATAPI request sense\n");
+
+	qc = ata_qc_new_init(ap, dev);
+	BUG_ON(qc == NULL);
+
+	/* FIXME: is this needed? */
+	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+	ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
+	qc->dma_dir = DMA_FROM_DEVICE;
+
+	memset(&qc->cdb, 0, ap->cdb_len);
+	qc->cdb[0] = REQUEST_SENSE;
+	qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
+
+	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	qc->tf.command = ATA_CMD_PACKET;
+
+	qc->tf.protocol = ATA_PROT_ATAPI;
+	qc->tf.lbam = (8 * 1024) & 0xff;
+	qc->tf.lbah = (8 * 1024) >> 8;
+	qc->nbytes = SCSI_SENSE_BUFFERSIZE;
+
+	qc->waiting = &wait;
+	qc->complete_fn = ata_qc_complete_noop;
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	rc = ata_qc_issue(qc);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	if (rc)
+		ata_port_disable(ap);
+	else
+		wait_for_completion(&wait);
+
+	DPRINTK("EXIT\n");
+}
+
 static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
 {
 	struct scsi_cmnd *cmd = qc->scsicmd;
 
-	if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) {
+	VPRINTK("ENTER, drv_stat == 0x%x\n", drv_stat);
+
+	if (unlikely(drv_stat & (ATA_BUSY | ATA_DRQ)))
+		ata_to_sense_error(qc, drv_stat);
+
+	else if (unlikely(drv_stat & ATA_ERR)) {
 		DPRINTK("request check condition\n");
 
+		/* FIXME: command completion with check condition
+		 * but no sense causes the error handler to run,
+		 * which then issues REQUEST SENSE, fills in the sense 
+		 * buffer, and completes the command (for the second
+		 * time).  We need to issue REQUEST SENSE some other
+		 * way, to avoid completing the command twice.
+		 */
 		cmd->result = SAM_STAT_CHECK_CONDITION;
 
 		qc->scsidone(cmd);
 
 		return 1;
-	} else {
+	}
+
+	else {
 		u8 *scsicmd = cmd->cmnd;
 
 		if (scsicmd[0] == INQUIRY) {
@@ -1428,15 +1643,30 @@
 			unsigned int buflen;
 
 			buflen = ata_scsi_rbuf_get(cmd, &buf);
-			buf[2] = 0x5;
-			buf[3] = (buf[3] & 0xf0) | 2;
+
+	/* ATAPI devices typically report zero for their SCSI version,
+	 * and sometimes deviate from the spec WRT response data
+	 * format.  If SCSI version is reported as zero like normal,
+	 * then we make the following fixups:  1) Fake MMC-5 version,
+	 * to indicate to the Linux scsi midlayer this is a modern
+	 * device.  2) Ensure response data format / ATAPI information
+	 * are always correct.
+	 */
+	/* FIXME: do we ever override EVPD pages and the like, with
+	 * this code?
+	 */
+			if (buf[2] == 0) {
+				buf[2] = 0x5;
+				buf[3] = 0x32;
+			}
+
 			ata_scsi_rbuf_put(cmd, buf);
 		}
+
 		cmd->result = SAM_STAT_GOOD;
 	}
 
 	qc->scsidone(cmd);
-
 	return 0;
 }
 /**
@@ -1697,7 +1927,7 @@
 
 		case INQUIRY:
 			if (scsicmd[1] & 2)	           /* is CmdDt set?  */
-				ata_bad_cdb(cmd, done);
+				ata_scsi_invalid_field(cmd, done);
 			else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
 				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
 			else if (scsicmd[2] == 0x00)
@@ -1707,7 +1937,7 @@
 			else if (scsicmd[2] == 0x83)
 				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
 			else
-				ata_bad_cdb(cmd, done);
+				ata_scsi_invalid_field(cmd, done);
 			break;
 
 		case MODE_SENSE:
@@ -1717,7 +1947,7 @@
 
 		case MODE_SELECT:	/* unconditionally return */
 		case MODE_SELECT_10:	/* bad-field-in-cdb */
-			ata_bad_cdb(cmd, done);
+			ata_scsi_invalid_field(cmd, done);
 			break;
 
 		case READ_CAPACITY:
@@ -1728,7 +1958,7 @@
 			if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
 				ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
 			else
-				ata_bad_cdb(cmd, done);
+				ata_scsi_invalid_field(cmd, done);
 			break;
 
 		case REPORT_LUNS:
@@ -1740,8 +1970,26 @@
 
 		/* all other commands */
 		default:
-			ata_bad_scsiop(cmd, done);
+			ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0);
+			/* "Invalid command operation code" */
+			done(cmd);
 			break;
 	}
 }
 
+void ata_scsi_scan_host(struct ata_port *ap)
+{
+	struct ata_device *dev;
+	unsigned int i;
+
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		return;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		dev = &ap->device[i];
+
+		if (ata_dev_present(dev))
+			scsi_scan_target(&ap->host->shost_gendev, 0, i, 0, 0);
+	}
+}
+
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index d608b3a..a18f2ac 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -39,6 +39,7 @@
 
 /* libata-core.c */
 extern int atapi_enabled;
+extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
 extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
 				      struct ata_device *dev);
 extern void ata_qc_free(struct ata_queued_cmd *qc);
@@ -51,6 +52,9 @@
 
 
 /* libata-scsi.c */
+extern void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
+			 struct scsi_cmnd *cmd);
+extern void ata_scsi_scan_host(struct ata_port *ap);
 extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat);
 extern int ata_scsi_error(struct Scsi_Host *host);
 extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
@@ -76,18 +80,10 @@
 extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
 			    void (*done)(struct scsi_cmnd *),
 			    u8 asc, u8 ascq);
+extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
+			       u8 sk, u8 asc, u8 ascq);
 extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
                         unsigned int (*actor) (struct ata_scsi_args *args,
                                            u8 *rbuf, unsigned int buflen));
 
-static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
-{
-	ata_scsi_badcmd(cmd, done, 0x20, 0x00);
-}
-
-static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
-{
-	ata_scsi_badcmd(cmd, done, 0x24, 0x00);
-}
-
 #endif /* __LIBATA_H__ */
diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c
index 86eaf6d..acae7c4 100644
--- a/drivers/scsi/lpfc/lpfc_attr.c
+++ b/drivers/scsi/lpfc/lpfc_attr.c
@@ -973,10 +973,10 @@
 	if ((phba->fc_flag & FC_FABRIC) ||
 	    ((phba->fc_topology == TOPOLOGY_LOOP) &&
 	     (phba->fc_flag & FC_PUBLIC_LOOP)))
-		node_name = wwn_to_u64(phba->fc_fabparam.nodeName.wwn);
+		node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn);
 	else
 		/* fabric is local port if there is no F/FL_Port */
-		node_name = wwn_to_u64(phba->fc_nodename.wwn);
+		node_name = wwn_to_u64(phba->fc_nodename.u.wwn);
 
 	spin_unlock_irq(shost->host_lock);
 
@@ -1110,7 +1110,7 @@
 	/* Search the mapped list for this target ID */
 	list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
 		if (starget->id == ndlp->nlp_sid) {
-			node_name = wwn_to_u64(ndlp->nlp_nodename.wwn);
+			node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
 			break;
 		}
 	}
@@ -1131,7 +1131,7 @@
 	/* Search the mapped list for this target ID */
 	list_for_each_entry(ndlp, &phba->fc_nlpmap_list, nlp_listp) {
 		if (starget->id == ndlp->nlp_sid) {
-			port_name = wwn_to_u64(ndlp->nlp_portname.wwn);
+			port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn);
 			break;
 		}
 	}
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c
index 4fb8eb0..56052f4 100644
--- a/drivers/scsi/lpfc/lpfc_hbadisc.c
+++ b/drivers/scsi/lpfc/lpfc_hbadisc.c
@@ -1019,8 +1019,8 @@
 	struct fc_rport_identifiers rport_ids;
 
 	/* Remote port has reappeared. Re-register w/ FC transport */
-	rport_ids.node_name = wwn_to_u64(ndlp->nlp_nodename.wwn);
-	rport_ids.port_name = wwn_to_u64(ndlp->nlp_portname.wwn);
+	rport_ids.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn);
+	rport_ids.port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn);
 	rport_ids.port_id = ndlp->nlp_DID;
 	rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
 	if (ndlp->nlp_type & NLP_FCP_TARGET)
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h
index 047a87c..86c4198 100644
--- a/drivers/scsi/lpfc/lpfc_hw.h
+++ b/drivers/scsi/lpfc/lpfc_hw.h
@@ -280,9 +280,9 @@
 #define NAME_CCITT_GR_TYPE  0xE
 			uint8_t IEEEextLsb;	/* FC Word 0, bit 16:23, IEEE extended Lsb */
 			uint8_t IEEE[6];	/* FC IEEE address */
-		};
+		} s;
 		uint8_t wwn[8];
-	};
+	} u;
 };
 
 struct csp {
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 454058f..0856ff7 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -285,7 +285,7 @@
 	if (phba->SerialNumber[0] == 0) {
 		uint8_t *outptr;
 
-		outptr = (uint8_t *) & phba->fc_nodename.IEEE[0];
+		outptr = &phba->fc_nodename.u.s.IEEE[0];
 		for (i = 0; i < 12; i++) {
 			status = *outptr++;
 			j = ((status & 0xf0) >> 4);
@@ -1523,8 +1523,8 @@
 	 * Must done after lpfc_sli_hba_setup()
 	 */
 
-	fc_host_node_name(host) = wwn_to_u64(phba->fc_nodename.wwn);
-	fc_host_port_name(host) = wwn_to_u64(phba->fc_portname.wwn);
+	fc_host_node_name(host) = wwn_to_u64(phba->fc_nodename.u.wwn);
+	fc_host_port_name(host) = wwn_to_u64(phba->fc_portname.u.wwn);
 	fc_host_supported_classes(host) = FC_COS_CLASS3;
 
 	memset(fc_host_supported_fc4s(host), 0,
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 6f308eb..61a6fd8 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -621,8 +621,6 @@
 	if(islogical) {
 		switch (cmd->cmnd[0]) {
 		case TEST_UNIT_READY:
-			memset(cmd->request_buffer, 0, cmd->request_bufflen);
-
 #if MEGA_HAVE_CLUSTERING
 			/*
 			 * Do we support clustering and is the support enabled
@@ -652,11 +650,28 @@
 			return NULL;
 #endif
 
-		case MODE_SENSE:
+		case MODE_SENSE: {
+			char *buf;
+
+			if (cmd->use_sg) {
+				struct scatterlist *sg;
+
+				sg = (struct scatterlist *)cmd->request_buffer;
+				buf = kmap_atomic(sg->page, KM_IRQ0) +
+					sg->offset;
+			} else
+				buf = cmd->request_buffer;
 			memset(cmd->request_buffer, 0, cmd->cmnd[4]);
+			if (cmd->use_sg) {
+				struct scatterlist *sg;
+
+				sg = (struct scatterlist *)cmd->request_buffer;
+				kunmap_atomic(buf - sg->offset, KM_IRQ0);
+			}
 			cmd->result = (DID_OK << 16);
 			cmd->scsi_done(cmd);
 			return NULL;
+		}
 
 		case READ_CAPACITY:
 		case INQUIRY:
@@ -1685,14 +1700,23 @@
 static void
 mega_free_scb(adapter_t *adapter, scb_t *scb)
 {
+	unsigned long length;
+
 	switch( scb->dma_type ) {
 
 	case MEGA_DMA_TYPE_NONE:
 		break;
 
 	case MEGA_BULK_DATA:
+		if (scb->cmd->use_sg == 0)
+			length = scb->cmd->request_bufflen;
+		else {
+			struct scatterlist *sgl =
+				(struct scatterlist *)scb->cmd->request_buffer;
+			length = sgl->length;
+		}
 		pci_unmap_page(adapter->dev, scb->dma_h_bulkdata,
-			scb->cmd->request_bufflen, scb->dma_direction);
+			       length, scb->dma_direction);
 		break;
 
 	case MEGA_SGLIST:
@@ -1741,6 +1765,7 @@
 	struct scatterlist	*sgl;
 	struct page	*page;
 	unsigned long	offset;
+	unsigned int	length;
 	Scsi_Cmnd	*cmd;
 	int	sgcnt;
 	int	idx;
@@ -1748,14 +1773,23 @@
 	cmd = scb->cmd;
 
 	/* Scatter-gather not used */
-	if( !cmd->use_sg ) {
+	if( cmd->use_sg == 0 || (cmd->use_sg == 1 && 
+				 !adapter->has_64bit_addr)) {
 
-		page = virt_to_page(cmd->request_buffer);
-		offset = offset_in_page(cmd->request_buffer);
+		if (cmd->use_sg == 0) {
+			page = virt_to_page(cmd->request_buffer);
+			offset = offset_in_page(cmd->request_buffer);
+			length = cmd->request_bufflen;
+		} else {
+			sgl = (struct scatterlist *)cmd->request_buffer;
+			page = sgl->page;
+			offset = sgl->offset;
+			length = sgl->length;
+		}
 
 		scb->dma_h_bulkdata = pci_map_page(adapter->dev,
 						  page, offset,
-						  cmd->request_bufflen,
+						  length,
 						  scb->dma_direction);
 		scb->dma_type = MEGA_BULK_DATA;
 
@@ -1765,14 +1799,14 @@
 		 */
 		if( adapter->has_64bit_addr ) {
 			scb->sgl64[0].address = scb->dma_h_bulkdata;
-			scb->sgl64[0].length = cmd->request_bufflen;
+			scb->sgl64[0].length = length;
 			*buf = (u32)scb->sgl_dma_addr;
-			*len = (u32)cmd->request_bufflen;
+			*len = (u32)length;
 			return 1;
 		}
 		else {
 			*buf = (u32)scb->dma_h_bulkdata;
-			*len = (u32)cmd->request_bufflen;
+			*len = (u32)length;
 		}
 		return 0;
 	}
@@ -1791,27 +1825,23 @@
 
 	if( sgcnt > adapter->sglen ) BUG();
 
+	*len = 0;
+
 	for( idx = 0; idx < sgcnt; idx++, sgl++ ) {
 
 		if( adapter->has_64bit_addr ) {
 			scb->sgl64[idx].address = sg_dma_address(sgl);
-			scb->sgl64[idx].length = sg_dma_len(sgl);
+			*len += scb->sgl64[idx].length = sg_dma_len(sgl);
 		}
 		else {
 			scb->sgl[idx].address = sg_dma_address(sgl);
-			scb->sgl[idx].length = sg_dma_len(sgl);
+			*len += scb->sgl[idx].length = sg_dma_len(sgl);
 		}
 	}
 
 	/* Reset pointer and length fields */
 	*buf = scb->sgl_dma_addr;
 
-	/*
-	 * For passthru command, dataxferlen must be set, even for commands
-	 * with a sg list
-	 */
-	*len = (u32)cmd->request_bufflen;
-
 	/* Return count of SG requests */
 	return sgcnt;
 }
diff --git a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid
index 917d591..7363e12 100644
--- a/drivers/scsi/megaraid/Kconfig.megaraid
+++ b/drivers/scsi/megaraid/Kconfig.megaraid
@@ -76,3 +76,12 @@
 	To compile this driver as a module, choose M here: the
 	module will be called megaraid
 endif
+
+config MEGARAID_SAS
+	tristate "LSI Logic MegaRAID SAS RAID Module"
+	depends on PCI && SCSI
+	help
+	Module for LSI Logic's SAS based RAID controllers.
+	To compile this driver as a module, choose 'm' here.
+	Module will be called megaraid_sas
+
diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile
index 6dd99f2..f469915 100644
--- a/drivers/scsi/megaraid/Makefile
+++ b/drivers/scsi/megaraid/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_MEGARAID_MM)	+= megaraid_mm.o
 obj-$(CONFIG_MEGARAID_MAILBOX)	+= megaraid_mbox.o
+obj-$(CONFIG_MEGARAID_SAS)	+= megaraid_sas.o
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
new file mode 100644
index 0000000..c3f6373
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -0,0 +1,2806 @@
+/*
+ *
+ *		Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * 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
+ *	   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.02.00-rc4
+ *
+ * Authors:
+ * 	Sreenivas Bagalkote	<Sreenivas.Bagalkote@lsil.com>
+ * 	Sumant Patro		<Sumant.Patro@lsil.com>
+ *
+ * List of supported controllers
+ *
+ * OEM	Product Name			VID	DID	SSVID	SSID
+ * ---	------------			---	---	----	----
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/uio.h>
+#include <asm/uaccess.h>
+#include <linux/fs.h>
+#include <linux/compat.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include "megaraid_sas.h"
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MEGASAS_VERSION);
+MODULE_AUTHOR("sreenivas.bagalkote@lsil.com");
+MODULE_DESCRIPTION("LSI Logic MegaRAID SAS Driver");
+
+/*
+ * PCI ID table for all supported controllers
+ */
+static struct pci_device_id megasas_pci_table[] = {
+
+	{
+	 PCI_VENDOR_ID_LSI_LOGIC,
+	 PCI_DEVICE_ID_LSI_SAS1064R,
+	 PCI_ANY_ID,
+	 PCI_ANY_ID,
+	 },
+	{
+	 PCI_VENDOR_ID_DELL,
+	 PCI_DEVICE_ID_DELL_PERC5,
+	 PCI_ANY_ID,
+	 PCI_ANY_ID,
+	 },
+	{0}			/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(pci, megasas_pci_table);
+
+static int megasas_mgmt_majorno;
+static struct megasas_mgmt_info megasas_mgmt_info;
+static struct fasync_struct *megasas_async_queue;
+static DECLARE_MUTEX(megasas_async_queue_mutex);
+
+/**
+ * megasas_get_cmd -	Get a command from the free pool
+ * @instance:		Adapter soft state
+ *
+ * Returns a free command from the pool
+ */
+static inline struct megasas_cmd *megasas_get_cmd(struct megasas_instance
+						  *instance)
+{
+	unsigned long flags;
+	struct megasas_cmd *cmd = NULL;
+
+	spin_lock_irqsave(&instance->cmd_pool_lock, flags);
+
+	if (!list_empty(&instance->cmd_pool)) {
+		cmd = list_entry((&instance->cmd_pool)->next,
+				 struct megasas_cmd, list);
+		list_del_init(&cmd->list);
+	} else {
+		printk(KERN_ERR "megasas: Command pool empty!\n");
+	}
+
+	spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
+	return cmd;
+}
+
+/**
+ * megasas_return_cmd -	Return a cmd to free command pool
+ * @instance:		Adapter soft state
+ * @cmd:		Command packet to be returned to free command pool
+ */
+static inline void
+megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&instance->cmd_pool_lock, flags);
+
+	cmd->scmd = NULL;
+	list_add_tail(&cmd->list, &instance->cmd_pool);
+
+	spin_unlock_irqrestore(&instance->cmd_pool_lock, flags);
+}
+
+/**
+ * megasas_enable_intr -	Enables interrupts
+ * @regs:			MFI register set
+ */
+static inline void
+megasas_enable_intr(struct megasas_register_set __iomem * regs)
+{
+	writel(1, &(regs)->outbound_intr_mask);
+
+	/* Dummy readl to force pci flush */
+	readl(&regs->outbound_intr_mask);
+}
+
+/**
+ * megasas_disable_intr -	Disables interrupts
+ * @regs:			MFI register set
+ */
+static inline void
+megasas_disable_intr(struct megasas_register_set __iomem * regs)
+{
+	u32 mask = readl(&regs->outbound_intr_mask) & (~0x00000001);
+	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 
+ *
+ * For polling, MFI requires the cmd_status to be set to 0xFF before posting.
+ */
+static int
+megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+	int i;
+	u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000;
+
+	struct megasas_header *frame_hdr = &cmd->frame->hdr;
+
+	frame_hdr->cmd_status = 0xFF;
+	frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+
+	/*
+	 * Issue the frame using inbound queue port
+	 */
+	writel(cmd->frame_phys_addr >> 3,
+	       &instance->reg_set->inbound_queue_port);
+
+	/*
+	 * Wait for cmd_status to change
+	 */
+	for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i++) {
+		rmb();
+		msleep(1);
+	}
+
+	if (frame_hdr->cmd_status == 0xff)
+		return -ETIME;
+
+	return 0;
+}
+
+/**
+ * megasas_issue_blocked_cmd -	Synchronous wrapper around regular FW cmds
+ * @instance:			Adapter soft state
+ * @cmd:			Command to be issued
+ *
+ * This function waits on an event for the command to be returned from ISR.
+ * Used to issue ioctl commands.
+ */
+static int
+megasas_issue_blocked_cmd(struct megasas_instance *instance,
+			  struct megasas_cmd *cmd)
+{
+	cmd->cmd_status = ENODATA;
+
+	writel(cmd->frame_phys_addr >> 3,
+	       &instance->reg_set->inbound_queue_port);
+
+	wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
+
+	return 0;
+}
+
+/**
+ * megasas_issue_blocked_abort_cmd -	Aborts previously issued cmd
+ * @instance:				Adapter soft state
+ * @cmd_to_abort:			Previously issued cmd to be aborted
+ *
+ * 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.
+ */
+static int
+megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
+				struct megasas_cmd *cmd_to_abort)
+{
+	struct megasas_cmd *cmd;
+	struct megasas_abort_frame *abort_fr;
+
+	cmd = megasas_get_cmd(instance);
+
+	if (!cmd)
+		return -1;
+
+	abort_fr = &cmd->frame->abort;
+
+	/*
+	 * Prepare and issue the abort frame
+	 */
+	abort_fr->cmd = MFI_CMD_ABORT;
+	abort_fr->cmd_status = 0xFF;
+	abort_fr->flags = 0;
+	abort_fr->abort_context = cmd_to_abort->index;
+	abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr;
+	abort_fr->abort_mfi_phys_addr_hi = 0;
+
+	cmd->sync_cmd = 1;
+	cmd->cmd_status = 0xFF;
+
+	writel(cmd->frame_phys_addr >> 3,
+	       &instance->reg_set->inbound_queue_port);
+
+	/*
+	 * Wait for this cmd to complete
+	 */
+	wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF));
+
+	megasas_return_cmd(instance, cmd);
+	return 0;
+}
+
+/**
+ * megasas_make_sgl32 -	Prepares 32-bit SGL
+ * @instance:		Adapter soft state
+ * @scp:		SCSI command from the mid-layer
+ * @mfi_sgl:		SGL to be filled in
+ *
+ * If successful, this function returns the number of SG elements. Otherwise,
+ * it returnes -1.
+ */
+static inline int
+megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
+		   union megasas_sgl *mfi_sgl)
+{
+	int i;
+	int sge_count;
+	struct scatterlist *os_sgl;
+
+	/*
+	 * Return 0 if there is no data transfer
+	 */
+	if (!scp->request_buffer || !scp->request_bufflen)
+		return 0;
+
+	if (!scp->use_sg) {
+		mfi_sgl->sge32[0].phys_addr = pci_map_single(instance->pdev,
+							     scp->
+							     request_buffer,
+							     scp->
+							     request_bufflen,
+							     scp->
+							     sc_data_direction);
+		mfi_sgl->sge32[0].length = scp->request_bufflen;
+
+		return 1;
+	}
+
+	os_sgl = (struct scatterlist *)scp->request_buffer;
+	sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,
+			       scp->sc_data_direction);
+
+	for (i = 0; i < sge_count; i++, os_sgl++) {
+		mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
+		mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
+	}
+
+	return sge_count;
+}
+
+/**
+ * megasas_make_sgl64 -	Prepares 64-bit SGL
+ * @instance:		Adapter soft state
+ * @scp:		SCSI command from the mid-layer
+ * @mfi_sgl:		SGL to be filled in
+ *
+ * If successful, this function returns the number of SG elements. Otherwise,
+ * it returnes -1.
+ */
+static inline int
+megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
+		   union megasas_sgl *mfi_sgl)
+{
+	int i;
+	int sge_count;
+	struct scatterlist *os_sgl;
+
+	/*
+	 * Return 0 if there is no data transfer
+	 */
+	if (!scp->request_buffer || !scp->request_bufflen)
+		return 0;
+
+	if (!scp->use_sg) {
+		mfi_sgl->sge64[0].phys_addr = pci_map_single(instance->pdev,
+							     scp->
+							     request_buffer,
+							     scp->
+							     request_bufflen,
+							     scp->
+							     sc_data_direction);
+
+		mfi_sgl->sge64[0].length = scp->request_bufflen;
+
+		return 1;
+	}
+
+	os_sgl = (struct scatterlist *)scp->request_buffer;
+	sge_count = pci_map_sg(instance->pdev, os_sgl, scp->use_sg,
+			       scp->sc_data_direction);
+
+	for (i = 0; i < sge_count; i++, os_sgl++) {
+		mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
+		mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
+	}
+
+	return sge_count;
+}
+
+/**
+ * megasas_build_dcdb -	Prepares a direct cdb (DCDB) command
+ * @instance:		Adapter soft state
+ * @scp:		SCSI command
+ * @cmd:		Command to be prepared in
+ *
+ * This function prepares CDB commands. These are typcially pass-through
+ * commands to the devices.
+ */
+static inline 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;
+	struct megasas_pthru_frame *pthru;
+
+	is_logical = MEGASAS_IS_LOGICAL(scp);
+	device_id = MEGASAS_DEV_INDEX(instance, scp);
+	pthru = (struct megasas_pthru_frame *)cmd->frame;
+
+	if (scp->sc_data_direction == PCI_DMA_TODEVICE)
+		flags = MFI_FRAME_DIR_WRITE;
+	else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+		flags = MFI_FRAME_DIR_READ;
+	else if (scp->sc_data_direction == PCI_DMA_NONE)
+		flags = MFI_FRAME_DIR_NONE;
+
+	/*
+	 * Prepare the DCDB frame
+	 */
+	pthru->cmd = (is_logical) ? MFI_CMD_LD_SCSI_IO : MFI_CMD_PD_SCSI_IO;
+	pthru->cmd_status = 0x0;
+	pthru->scsi_status = 0x0;
+	pthru->target_id = device_id;
+	pthru->lun = scp->device->lun;
+	pthru->cdb_len = scp->cmd_len;
+	pthru->timeout = 0;
+	pthru->flags = flags;
+	pthru->data_xfer_len = scp->request_bufflen;
+
+	memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
+
+	/*
+	 * 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,
+						      &pthru->sgl);
+	} else
+		pthru->sge_count = megasas_make_sgl32(instance, scp,
+						      &pthru->sgl);
+
+	/*
+	 * Sense info specific
+	 */
+	pthru->sense_len = SCSI_SENSE_BUFFERSIZE;
+	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;
+
+	return cmd->frame_count;
+}
+
+/**
+ * megasas_build_ldio -	Prepares IOs to logical devices
+ * @instance:		Adapter soft state
+ * @scp:		SCSI command
+ * @cmd:		Command to to be prepared
+ *
+ * Frames (and accompanying SGLs) for regular SCSI IOs use this function.
+ */
+static inline 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;
+	struct megasas_io_frame *ldio;
+
+	device_id = MEGASAS_DEV_INDEX(instance, scp);
+	ldio = (struct megasas_io_frame *)cmd->frame;
+
+	if (scp->sc_data_direction == PCI_DMA_TODEVICE)
+		flags = MFI_FRAME_DIR_WRITE;
+	else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
+		flags = MFI_FRAME_DIR_READ;
+
+	/*
+	 * Preare 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;
+	ldio->scsi_status = 0x0;
+	ldio->target_id = device_id;
+	ldio->timeout = 0;
+	ldio->reserved_0 = 0;
+	ldio->pad_0 = 0;
+	ldio->flags = flags;
+	ldio->start_lba_hi = 0;
+	ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0;
+
+	/*
+	 * 6-byte READ(0x08) or WRITE(0x0A) cdb
+	 */
+	if (scp->cmd_len == 6) {
+		ldio->lba_count = (u32) scp->cmnd[4];
+		ldio->start_lba_lo = ((u32) scp->cmnd[1] << 16) |
+		    ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];
+
+		ldio->start_lba_lo &= 0x1FFFFF;
+	}
+
+	/*
+	 * 10-byte READ(0x28) or WRITE(0x2A) cdb
+	 */
+	else if (scp->cmd_len == 10) {
+		ldio->lba_count = (u32) scp->cmnd[8] |
+		    ((u32) scp->cmnd[7] << 8);
+		ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |
+		    ((u32) scp->cmnd[3] << 16) |
+		    ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+	}
+
+	/*
+	 * 12-byte READ(0xA8) or WRITE(0xAA) cdb
+	 */
+	else if (scp->cmd_len == 12) {
+		ldio->lba_count = ((u32) scp->cmnd[6] << 24) |
+		    ((u32) scp->cmnd[7] << 16) |
+		    ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+
+		ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |
+		    ((u32) scp->cmnd[3] << 16) |
+		    ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+	}
+
+	/*
+	 * 16-byte READ(0x88) or WRITE(0x8A) cdb
+	 */
+	else if (scp->cmd_len == 16) {
+		ldio->lba_count = ((u32) scp->cmnd[10] << 24) |
+		    ((u32) scp->cmnd[11] << 16) |
+		    ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];
+
+		ldio->start_lba_lo = ((u32) scp->cmnd[6] << 24) |
+		    ((u32) scp->cmnd[7] << 16) |
+		    ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+
+		ldio->start_lba_hi = ((u32) scp->cmnd[2] << 24) |
+		    ((u32) scp->cmnd[3] << 16) |
+		    ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+
+	}
+
+	/*
+	 * 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);
+	} else
+		ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);
+
+	/*
+	 * Sense info specific
+	 */
+	ldio->sense_len = SCSI_SENSE_BUFFERSIZE;
+	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;
+
+	return cmd->frame_count;
+}
+
+/**
+ * megasas_build_cmd -	Prepares a command packet
+ * @instance:		Adapter soft state
+ * @scp:		SCSI command
+ * @frame_count:	[OUT] Number of frames used to prepare this command
+ */
+static inline struct megasas_cmd *megasas_build_cmd(struct megasas_instance
+						    *instance,
+						    struct scsi_cmnd *scp,
+						    int *frame_count)
+{
+	u32 logical_cmd;
+	struct megasas_cmd *cmd;
+
+	/*
+	 * Find out if this is logical or physical drive command.
+	 */
+	logical_cmd = MEGASAS_IS_LOGICAL(scp);
+
+	/*
+	 * Logical drive command
+	 */
+	if (logical_cmd) {
+
+		if (scp->device->id >= MEGASAS_MAX_LD) {
+			scp->result = DID_BAD_TARGET << 16;
+			return NULL;
+		}
+
+		switch (scp->cmnd[0]) {
+
+		case READ_10:
+		case WRITE_10:
+		case READ_12:
+		case WRITE_12:
+		case READ_6:
+		case WRITE_6:
+		case READ_16:
+		case WRITE_16:
+			/*
+			 * Fail for LUN > 0
+			 */
+			if (scp->device->lun) {
+				scp->result = DID_BAD_TARGET << 16;
+				return NULL;
+			}
+
+			cmd = megasas_get_cmd(instance);
+
+			if (!cmd) {
+				scp->result = DID_IMM_RETRY << 16;
+				return NULL;
+			}
+
+			*frame_count = megasas_build_ldio(instance, scp, cmd);
+
+			if (!(*frame_count)) {
+				megasas_return_cmd(instance, cmd);
+				return NULL;
+			}
+
+			return cmd;
+
+		default:
+			/*
+			 * Fail for LUN > 0
+			 */
+			if (scp->device->lun) {
+				scp->result = DID_BAD_TARGET << 16;
+				return NULL;
+			}
+
+			cmd = megasas_get_cmd(instance);
+
+			if (!cmd) {
+				scp->result = DID_IMM_RETRY << 16;
+				return NULL;
+			}
+
+			*frame_count = megasas_build_dcdb(instance, scp, cmd);
+
+			if (!(*frame_count)) {
+				megasas_return_cmd(instance, cmd);
+				return NULL;
+			}
+
+			return cmd;
+		}
+	} else {
+		cmd = megasas_get_cmd(instance);
+
+		if (!cmd) {
+			scp->result = DID_IMM_RETRY << 16;
+			return NULL;
+		}
+
+		*frame_count = megasas_build_dcdb(instance, scp, cmd);
+
+		if (!(*frame_count)) {
+			megasas_return_cmd(instance, cmd);
+			return NULL;
+		}
+
+		return cmd;
+	}
+
+	return NULL;
+}
+
+/**
+ * megasas_queue_command -	Queue entry point
+ * @scmd:			SCSI command to be queued
+ * @done:			Callback entry point
+ */
+static int
+megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+{
+	u32 frame_count;
+	unsigned long flags;
+	struct megasas_cmd *cmd;
+	struct megasas_instance *instance;
+
+	instance = (struct megasas_instance *)
+	    scmd->device->host->hostdata;
+	scmd->scsi_done = done;
+	scmd->result = 0;
+
+	cmd = megasas_build_cmd(instance, scmd, &frame_count);
+
+	if (!cmd) {
+		done(scmd);
+		return 0;
+	}
+
+	cmd->scmd = scmd;
+	scmd->SCp.ptr = (char *)cmd;
+	scmd->SCp.sent_command = jiffies;
+
+	/*
+	 * Issue the command to the FW
+	 */
+	spin_lock_irqsave(&instance->instance_lock, flags);
+	instance->fw_outstanding++;
+	spin_unlock_irqrestore(&instance->instance_lock, flags);
+
+	writel(((cmd->frame_phys_addr >> 3) | (cmd->frame_count - 1)),
+	       &instance->reg_set->inbound_queue_port);
+
+	return 0;
+}
+
+/**
+ * megasas_wait_for_outstanding -	Wait for all outstanding cmds
+ * @instance:				Adapter soft state
+ *
+ * This function waits for upto MEGASAS_RESET_WAIT_TIME seconds for FW to
+ * complete all its outstanding commands. Returns error if one or more IOs
+ * are pending after this time period. It also marks the controller dead.
+ */
+static int megasas_wait_for_outstanding(struct megasas_instance *instance)
+{
+	int i;
+	u32 wait_time = MEGASAS_RESET_WAIT_TIME;
+
+	for (i = 0; i < wait_time; i++) {
+
+		if (!instance->fw_outstanding)
+			break;
+
+		if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) {
+			printk(KERN_NOTICE "megasas: [%2d]waiting for %d "
+			       "commands to complete\n", i,
+			       instance->fw_outstanding);
+		}
+
+		msleep(1000);
+	}
+
+	if (instance->fw_outstanding) {
+		instance->hw_crit_error = 1;
+		return FAILED;
+	}
+
+	return SUCCESS;
+}
+
+/**
+ * megasas_generic_reset -	Generic reset routine
+ * @scmd:			Mid-layer SCSI command
+ *
+ * This routine implements a generic reset handler for device, bus and host
+ * reset requests. Device, bus and host specific reset handlers can use this
+ * function after they do their specific tasks.
+ */
+static int megasas_generic_reset(struct scsi_cmnd *scmd)
+{
+	int ret_val;
+	struct megasas_instance *instance;
+
+	instance = (struct megasas_instance *)scmd->device->host->hostdata;
+
+	printk(KERN_NOTICE "megasas: RESET -%ld cmd=%x <c=%d t=%d l=%d>\n",
+	       scmd->serial_number, scmd->cmnd[0], scmd->device->channel,
+	       scmd->device->id, scmd->device->lun);
+
+	if (instance->hw_crit_error) {
+		printk(KERN_ERR "megasas: cannot recover from previous reset "
+		       "failures\n");
+		return FAILED;
+	}
+
+	spin_unlock(scmd->device->host->host_lock);
+
+	ret_val = megasas_wait_for_outstanding(instance);
+
+	if (ret_val == SUCCESS)
+		printk(KERN_NOTICE "megasas: reset successful \n");
+	else
+		printk(KERN_ERR "megasas: failed to do reset\n");
+
+	spin_lock(scmd->device->host->host_lock);
+
+	return ret_val;
+}
+
+static enum scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd)
+{
+	unsigned long seconds;
+
+	if (scmd->SCp.ptr) {
+		seconds = (jiffies - scmd->SCp.sent_command) / HZ;
+
+		if (seconds < 90) {
+			return EH_RESET_TIMER;
+		} else {
+			return EH_NOT_HANDLED;
+		}
+	}
+
+	return EH_HANDLED;
+}
+
+/**
+ * megasas_reset_device -	Device reset handler entry point
+ */
+static int megasas_reset_device(struct scsi_cmnd *scmd)
+{
+	int ret;
+
+	/*
+	 * First wait for all commands to complete
+	 */
+	ret = megasas_generic_reset(scmd);
+
+	return ret;
+}
+
+/**
+ * megasas_reset_bus_host -	Bus & host reset handler entry point
+ */
+static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
+{
+	int ret;
+
+	/*
+	 * Frist wait for all commands to complete
+	 */
+	ret = megasas_generic_reset(scmd);
+
+	return ret;
+}
+
+/**
+ * megasas_service_aen -	Processes an event notification
+ * @instance:			Adapter soft state
+ * @cmd:			AEN command completed by the ISR
+ *
+ * For AEN, driver sends a command down to FW that is held by the FW till an
+ * event occurs. When an event of interest occurs, FW completes the command
+ * that it was previously holding.
+ *
+ * This routines sends SIGIO signal to processes that have registered with the
+ * driver for AEN.
+ */
+static void
+megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+	/*
+	 * Don't signal app if it is just an aborted previously registered aen
+	 */
+	if (!cmd->abort_aen)
+		kill_fasync(&megasas_async_queue, SIGIO, POLL_IN);
+	else
+		cmd->abort_aen = 0;
+
+	instance->aen_cmd = NULL;
+	megasas_return_cmd(instance, cmd);
+}
+
+/*
+ * Scsi host template for megaraid_sas driver
+ */
+static struct scsi_host_template megasas_template = {
+
+	.module = THIS_MODULE,
+	.name = "LSI Logic SAS based MegaRAID driver",
+	.proc_name = "megaraid_sas",
+	.queuecommand = megasas_queue_command,
+	.eh_device_reset_handler = megasas_reset_device,
+	.eh_bus_reset_handler = megasas_reset_bus_host,
+	.eh_host_reset_handler = megasas_reset_bus_host,
+	.eh_timed_out = megasas_reset_timer,
+	.use_clustering = ENABLE_CLUSTERING,
+};
+
+/**
+ * megasas_complete_int_cmd -	Completes an internal command
+ * @instance:			Adapter soft state
+ * @cmd:			Command to be completed
+ *
+ * The megasas_issue_blocked_cmd() function waits for a command to complete
+ * after it issues a command. This function wakes up that waiting routine by
+ * calling wake_up() on the wait queue.
+ */
+static void
+megasas_complete_int_cmd(struct megasas_instance *instance,
+			 struct megasas_cmd *cmd)
+{
+	cmd->cmd_status = cmd->frame->io.cmd_status;
+
+	if (cmd->cmd_status == ENODATA) {
+		cmd->cmd_status = 0;
+	}
+	wake_up(&instance->int_cmd_wait_q);
+}
+
+/**
+ * megasas_complete_abort -	Completes aborting a command
+ * @instance:			Adapter soft state
+ * @cmd:			Cmd that was issued to abort another cmd
+ *
+ * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q 
+ * after it issues an abort on a previously issued command. This function 
+ * wakes up all functions waiting on the same wait queue.
+ */
+static void
+megasas_complete_abort(struct megasas_instance *instance,
+		       struct megasas_cmd *cmd)
+{
+	if (cmd->sync_cmd) {
+		cmd->sync_cmd = 0;
+		cmd->cmd_status = 0;
+		wake_up(&instance->abort_cmd_wait_q);
+	}
+
+	return;
+}
+
+/**
+ * megasas_unmap_sgbuf -	Unmap SG buffers
+ * @instance:			Adapter soft state
+ * @cmd:			Completed command
+ */
+static inline void
+megasas_unmap_sgbuf(struct megasas_instance *instance, struct megasas_cmd *cmd)
+{
+	dma_addr_t buf_h;
+	u8 opcode;
+
+	if (cmd->scmd->use_sg) {
+		pci_unmap_sg(instance->pdev, cmd->scmd->request_buffer,
+			     cmd->scmd->use_sg, cmd->scmd->sc_data_direction);
+		return;
+	}
+
+	if (!cmd->scmd->request_bufflen)
+		return;
+
+	opcode = cmd->frame->hdr.cmd;
+
+	if ((opcode == MFI_CMD_LD_READ) || (opcode == MFI_CMD_LD_WRITE)) {
+		if (IS_DMA64)
+			buf_h = cmd->frame->io.sgl.sge64[0].phys_addr;
+		else
+			buf_h = cmd->frame->io.sgl.sge32[0].phys_addr;
+	} else {
+		if (IS_DMA64)
+			buf_h = cmd->frame->pthru.sgl.sge64[0].phys_addr;
+		else
+			buf_h = cmd->frame->pthru.sgl.sge32[0].phys_addr;
+	}
+
+	pci_unmap_single(instance->pdev, buf_h, cmd->scmd->request_bufflen,
+			 cmd->scmd->sc_data_direction);
+	return;
+}
+
+/**
+ * megasas_complete_cmd -	Completes a command
+ * @instance:			Adapter soft state
+ * @cmd:			Command to be completed
+ * @alt_status:			If non-zero, use this value as status to 
+ * 				SCSI mid-layer instead of the value returned
+ * 				by the FW. This should be used if caller wants
+ * 				an alternate status (as in the case of aborted
+ * 				commands)
+ */
+static inline void
+megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
+		     u8 alt_status)
+{
+	int exception = 0;
+	struct megasas_header *hdr = &cmd->frame->hdr;
+	unsigned long flags;
+
+	if (cmd->scmd) {
+		cmd->scmd->SCp.ptr = (char *)0;
+	}
+
+	switch (hdr->cmd) {
+
+	case MFI_CMD_PD_SCSI_IO:
+	case MFI_CMD_LD_SCSI_IO:
+
+		/*
+		 * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been
+		 * issued either through an IO path or an IOCTL path. If it
+		 * was via IOCTL, we will send it to internal completion.
+		 */
+		if (cmd->sync_cmd) {
+			cmd->sync_cmd = 0;
+			megasas_complete_int_cmd(instance, cmd);
+			break;
+		}
+
+		/*
+		 * Don't export physical disk devices to mid-layer.
+		 */
+		if (!MEGASAS_IS_LOGICAL(cmd->scmd) &&
+		    (hdr->cmd_status == MFI_STAT_OK) &&
+		    (cmd->scmd->cmnd[0] == INQUIRY)) {
+
+			if (((*(u8 *) cmd->scmd->request_buffer) & 0x1F) ==
+			    TYPE_DISK) {
+				cmd->scmd->result = DID_BAD_TARGET << 16;
+				exception = 1;
+			}
+		}
+
+	case MFI_CMD_LD_READ:
+	case MFI_CMD_LD_WRITE:
+
+		if (alt_status) {
+			cmd->scmd->result = alt_status << 16;
+			exception = 1;
+		}
+
+		if (exception) {
+
+			spin_lock_irqsave(&instance->instance_lock, flags);
+			instance->fw_outstanding--;
+			spin_unlock_irqrestore(&instance->instance_lock, flags);
+
+			megasas_unmap_sgbuf(instance, cmd);
+			cmd->scmd->scsi_done(cmd->scmd);
+			megasas_return_cmd(instance, cmd);
+
+			break;
+		}
+
+		switch (hdr->cmd_status) {
+
+		case MFI_STAT_OK:
+			cmd->scmd->result = DID_OK << 16;
+			break;
+
+		case MFI_STAT_SCSI_IO_FAILED:
+		case MFI_STAT_LD_INIT_IN_PROGRESS:
+			cmd->scmd->result =
+			    (DID_ERROR << 16) | hdr->scsi_status;
+			break;
+
+		case MFI_STAT_SCSI_DONE_WITH_ERROR:
+
+			cmd->scmd->result = (DID_OK << 16) | hdr->scsi_status;
+
+			if (hdr->scsi_status == SAM_STAT_CHECK_CONDITION) {
+				memset(cmd->scmd->sense_buffer, 0,
+				       SCSI_SENSE_BUFFERSIZE);
+				memcpy(cmd->scmd->sense_buffer, cmd->sense,
+				       hdr->sense_len);
+
+				cmd->scmd->result |= DRIVER_SENSE << 24;
+			}
+
+			break;
+
+		case MFI_STAT_LD_OFFLINE:
+		case MFI_STAT_DEVICE_NOT_FOUND:
+			cmd->scmd->result = DID_BAD_TARGET << 16;
+			break;
+
+		default:
+			printk(KERN_DEBUG "megasas: MFI FW status %#x\n",
+			       hdr->cmd_status);
+			cmd->scmd->result = DID_ERROR << 16;
+			break;
+		}
+
+		spin_lock_irqsave(&instance->instance_lock, flags);
+		instance->fw_outstanding--;
+		spin_unlock_irqrestore(&instance->instance_lock, flags);
+
+		megasas_unmap_sgbuf(instance, cmd);
+		cmd->scmd->scsi_done(cmd->scmd);
+		megasas_return_cmd(instance, cmd);
+
+		break;
+
+	case MFI_CMD_SMP:
+	case MFI_CMD_STP:
+	case MFI_CMD_DCMD:
+
+		/*
+		 * See if got an event notification
+		 */
+		if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_WAIT)
+			megasas_service_aen(instance, cmd);
+		else
+			megasas_complete_int_cmd(instance, cmd);
+
+		break;
+
+	case MFI_CMD_ABORT:
+		/*
+		 * Cmd issued to abort another cmd returned
+		 */
+		megasas_complete_abort(instance, cmd);
+		break;
+
+	default:
+		printk("megasas: Unknown command completed! [0x%X]\n",
+		       hdr->cmd);
+		break;
+	}
+}
+
+/**
+ * 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
+ */
+static inline int
+megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
+{
+	u32 status;
+	u32 producer;
+	u32 consumer;
+	u32 context;
+	struct megasas_cmd *cmd;
+
+	/*
+	 * Check if it is our interrupt
+	 */
+	status = readl(&instance->reg_set->outbound_intr_status);
+
+	if (!(status & MFI_OB_INTR_STATUS_MASK)) {
+		return IRQ_NONE;
+	}
+
+	/*
+	 * Clear the interrupt by writing back the same value
+	 */
+	writel(status, &instance->reg_set->outbound_intr_status);
+
+	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;
+
+	return IRQ_HANDLED;
+}
+
+/**
+ * megasas_isr - isr entry point
+ */
+static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
+{
+	return megasas_deplete_reply_queue((struct megasas_instance *)devp,
+					   DID_OK);
+}
+
+/**
+ * megasas_transition_to_ready -	Move the FW to READY state
+ * @reg_set:				MFI register set
+ *
+ * During the initialization, FW passes can potentially be in any one of
+ * several possible states. If the FW in operational, waiting-for-handshake
+ * states, driver must take steps to bring it to ready state. Otherwise, it
+ * has to wait for the ready state.
+ */
+static int
+megasas_transition_to_ready(struct megasas_register_set __iomem * reg_set)
+{
+	int i;
+	u8 max_wait;
+	u32 fw_state;
+	u32 cur_state;
+
+	fw_state = readl(&reg_set->outbound_msg_0) & MFI_STATE_MASK;
+
+	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:
+
+			printk(KERN_DEBUG "megasas: FW in FAULT state!!\n");
+			return -ENODEV;
+
+		case MFI_STATE_WAIT_HANDSHAKE:
+			/*
+			 * Set the CLR bit in inbound doorbell
+			 */
+			writel(MFI_INIT_CLEAR_HANDSHAKE,
+			       &reg_set->inbound_doorbell);
+
+			max_wait = 2;
+			cur_state = MFI_STATE_WAIT_HANDSHAKE;
+			break;
+
+		case MFI_STATE_OPERATIONAL:
+			/*
+			 * Bring it to READY state; assuming max wait 2 secs
+			 */
+			megasas_disable_intr(reg_set);
+			writel(MFI_INIT_READY, &reg_set->inbound_doorbell);
+
+			max_wait = 10;
+			cur_state = MFI_STATE_OPERATIONAL;
+			break;
+
+		case MFI_STATE_UNDEFINED:
+			/*
+			 * This state should not last for more than 2 seconds
+			 */
+			max_wait = 2;
+			cur_state = MFI_STATE_UNDEFINED;
+			break;
+
+		case MFI_STATE_BB_INIT:
+			max_wait = 2;
+			cur_state = MFI_STATE_BB_INIT;
+			break;
+
+		case MFI_STATE_FW_INIT:
+			max_wait = 20;
+			cur_state = MFI_STATE_FW_INIT;
+			break;
+
+		case MFI_STATE_FW_INIT_2:
+			max_wait = 20;
+			cur_state = MFI_STATE_FW_INIT_2;
+			break;
+
+		case MFI_STATE_DEVICE_SCAN:
+			max_wait = 20;
+			cur_state = MFI_STATE_DEVICE_SCAN;
+			break;
+
+		case MFI_STATE_FLUSH_CACHE:
+			max_wait = 20;
+			cur_state = MFI_STATE_FLUSH_CACHE;
+			break;
+
+		default:
+			printk(KERN_DEBUG "megasas: Unknown state 0x%x\n",
+			       fw_state);
+			return -ENODEV;
+		}
+
+		/*
+		 * The cur_state should not last for more than max_wait secs
+		 */
+		for (i = 0; i < (max_wait * 1000); i++) {
+			fw_state = MFI_STATE_MASK &
+			    readl(&reg_set->outbound_msg_0);
+
+			if (fw_state == cur_state) {
+				msleep(1);
+			} else
+				break;
+		}
+
+		/*
+		 * Return error if fw_state hasn't changed after max_wait
+		 */
+		if (fw_state == cur_state) {
+			printk(KERN_DEBUG "FW state [%d] hasn't changed "
+			       "in %d secs\n", fw_state, max_wait);
+			return -ENODEV;
+		}
+	};
+
+	return 0;
+}
+
+/**
+ * megasas_teardown_frame_pool -	Destroy the cmd frame DMA pool
+ * @instance:				Adapter soft state
+ */
+static void megasas_teardown_frame_pool(struct megasas_instance *instance)
+{
+	int i;
+	u32 max_cmd = instance->max_fw_cmds;
+	struct megasas_cmd *cmd;
+
+	if (!instance->frame_dma_pool)
+		return;
+
+	/*
+	 * Return all frames to pool
+	 */
+	for (i = 0; i < max_cmd; i++) {
+
+		cmd = instance->cmd_list[i];
+
+		if (cmd->frame)
+			pci_pool_free(instance->frame_dma_pool, cmd->frame,
+				      cmd->frame_phys_addr);
+
+		if (cmd->sense)
+			pci_pool_free(instance->sense_dma_pool, cmd->frame,
+				      cmd->sense_phys_addr);
+	}
+
+	/*
+	 * Now destroy the pool itself
+	 */
+	pci_pool_destroy(instance->frame_dma_pool);
+	pci_pool_destroy(instance->sense_dma_pool);
+
+	instance->frame_dma_pool = NULL;
+	instance->sense_dma_pool = NULL;
+}
+
+/**
+ * megasas_create_frame_pool -	Creates DMA pool for cmd frames
+ * @instance:			Adapter soft state
+ *
+ * Each command packet has an embedded DMA memory buffer that is used for
+ * filling MFI frame and the SG list that immediately follows the frame. This
+ * function creates those DMA memory buffers for each command packet by using
+ * PCI pool facility.
+ */
+static int megasas_create_frame_pool(struct megasas_instance *instance)
+{
+	int i;
+	u32 max_cmd;
+	u32 sge_sz;
+	u32 sgl_sz;
+	u32 total_sz;
+	u32 frame_count;
+	struct megasas_cmd *cmd;
+
+	max_cmd = instance->max_fw_cmds;
+
+	/*
+	 * Size of our frame is 64 bytes for MFI frame, followed by max SG
+	 * elements and finally SCSI_SENSE_BUFFERSIZE bytes for sense buffer
+	 */
+	sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+	    sizeof(struct megasas_sge32);
+
+	/*
+	 * Calculated the number of 64byte frames required for SGL
+	 */
+	sgl_sz = sge_sz * instance->max_num_sge;
+	frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE;
+
+	/*
+	 * We need one extra frame for the MFI command
+	 */
+	frame_count++;
+
+	total_sz = MEGAMFI_FRAME_SIZE * frame_count;
+	/*
+	 * Use DMA pool facility provided by PCI layer
+	 */
+	instance->frame_dma_pool = pci_pool_create("megasas frame pool",
+						   instance->pdev, total_sz, 64,
+						   0);
+
+	if (!instance->frame_dma_pool) {
+		printk(KERN_DEBUG "megasas: failed to setup frame pool\n");
+		return -ENOMEM;
+	}
+
+	instance->sense_dma_pool = pci_pool_create("megasas sense pool",
+						   instance->pdev, 128, 4, 0);
+
+	if (!instance->sense_dma_pool) {
+		printk(KERN_DEBUG "megasas: failed to setup sense pool\n");
+
+		pci_pool_destroy(instance->frame_dma_pool);
+		instance->frame_dma_pool = NULL;
+
+		return -ENOMEM;
+	}
+
+	/*
+	 * Allocate and attach a frame to each of the commands in cmd_list.
+	 * By making cmd->index as the context instead of the &cmd, we can
+	 * always use 32bit context regardless of the architecture
+	 */
+	for (i = 0; i < max_cmd; i++) {
+
+		cmd = instance->cmd_list[i];
+
+		cmd->frame = pci_pool_alloc(instance->frame_dma_pool,
+					    GFP_KERNEL, &cmd->frame_phys_addr);
+
+		cmd->sense = pci_pool_alloc(instance->sense_dma_pool,
+					    GFP_KERNEL, &cmd->sense_phys_addr);
+
+		/*
+		 * megasas_teardown_frame_pool() takes care of freeing
+		 * whatever has been allocated
+		 */
+		if (!cmd->frame || !cmd->sense) {
+			printk(KERN_DEBUG "megasas: pci_pool_alloc failed \n");
+			megasas_teardown_frame_pool(instance);
+			return -ENOMEM;
+		}
+
+		cmd->frame->io.context = cmd->index;
+	}
+
+	return 0;
+}
+
+/**
+ * megasas_free_cmds -	Free all the cmds in the free cmd pool
+ * @instance:		Adapter soft state
+ */
+static void megasas_free_cmds(struct megasas_instance *instance)
+{
+	int i;
+	/* First free the MFI frame pool */
+	megasas_teardown_frame_pool(instance);
+
+	/* Free all the commands in the cmd_list */
+	for (i = 0; i < instance->max_fw_cmds; i++)
+		kfree(instance->cmd_list[i]);
+
+	/* Free the cmd_list buffer itself */
+	kfree(instance->cmd_list);
+	instance->cmd_list = NULL;
+
+	INIT_LIST_HEAD(&instance->cmd_pool);
+}
+
+/**
+ * megasas_alloc_cmds -	Allocates the command packets
+ * @instance:		Adapter soft state
+ *
+ * Each command that is issued to the FW, whether IO commands from the OS or
+ * internal commands like IOCTLs, are wrapped in local data structure called
+ * megasas_cmd. The frame embedded in this megasas_cmd is actually issued to
+ * the FW.
+ *
+ * Each frame has a 32-bit field called context (tag). This context is used
+ * to get back the megasas_cmd from the frame when a frame gets completed in
+ * the ISR. Typically the address of the megasas_cmd itself would be used as
+ * the context. But we wanted to keep the differences between 32 and 64 bit
+ * systems to the mininum. We always use 32 bit integers for the context. In
+ * this driver, the 32 bit values are the indices into an array cmd_list.
+ * This array is used only to look up the megasas_cmd given the context. The
+ * free commands themselves are maintained in a linked list called cmd_pool.
+ */
+static int megasas_alloc_cmds(struct megasas_instance *instance)
+{
+	int i;
+	int j;
+	u32 max_cmd;
+	struct megasas_cmd *cmd;
+
+	max_cmd = instance->max_fw_cmds;
+
+	/*
+	 * instance->cmd_list is an array of struct megasas_cmd pointers.
+	 * Allocate the dynamic array first and then allocate individual
+	 * commands.
+	 */
+	instance->cmd_list = kmalloc(sizeof(struct megasas_cmd *) * max_cmd,
+				     GFP_KERNEL);
+
+	if (!instance->cmd_list) {
+		printk(KERN_DEBUG "megasas: out of memory\n");
+		return -ENOMEM;
+	}
+
+	memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) * max_cmd);
+
+	for (i = 0; i < max_cmd; i++) {
+		instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd),
+						GFP_KERNEL);
+
+		if (!instance->cmd_list[i]) {
+
+			for (j = 0; j < i; j++)
+				kfree(instance->cmd_list[j]);
+
+			kfree(instance->cmd_list);
+			instance->cmd_list = NULL;
+
+			return -ENOMEM;
+		}
+	}
+
+	/*
+	 * Add all the commands to command pool (instance->cmd_pool)
+	 */
+	for (i = 0; i < max_cmd; i++) {
+		cmd = instance->cmd_list[i];
+		memset(cmd, 0, sizeof(struct megasas_cmd));
+		cmd->index = i;
+		cmd->instance = instance;
+
+		list_add_tail(&cmd->list, &instance->cmd_pool);
+	}
+
+	/*
+	 * Create a frame pool and assign one frame to each cmd
+	 */
+	if (megasas_create_frame_pool(instance)) {
+		printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n");
+		megasas_free_cmds(instance);
+	}
+
+	return 0;
+}
+
+/**
+ * megasas_get_controller_info -	Returns FW's controller structure
+ * @instance:				Adapter soft state
+ * @ctrl_info:				Controller information structure
+ *
+ * Issues an internal command (DCMD) to get the FW's controller structure.
+ * This information is mainly used to find out the maximum IO transfer per
+ * command supported by the FW.
+ */
+static int
+megasas_get_ctrl_info(struct megasas_instance *instance,
+		      struct megasas_ctrl_info *ctrl_info)
+{
+	int ret = 0;
+	struct megasas_cmd *cmd;
+	struct megasas_dcmd_frame *dcmd;
+	struct megasas_ctrl_info *ci;
+	dma_addr_t ci_h = 0;
+
+	cmd = megasas_get_cmd(instance);
+
+	if (!cmd) {
+		printk(KERN_DEBUG "megasas: Failed to get a free cmd\n");
+		return -ENOMEM;
+	}
+
+	dcmd = &cmd->frame->dcmd;
+
+	ci = pci_alloc_consistent(instance->pdev,
+				  sizeof(struct megasas_ctrl_info), &ci_h);
+
+	if (!ci) {
+		printk(KERN_DEBUG "Failed to alloc mem for ctrl info\n");
+		megasas_return_cmd(instance, cmd);
+		return -ENOMEM;
+	}
+
+	memset(ci, 0, sizeof(*ci));
+	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+	dcmd->cmd = MFI_CMD_DCMD;
+	dcmd->cmd_status = 0xFF;
+	dcmd->sge_count = 1;
+	dcmd->flags = MFI_FRAME_DIR_READ;
+	dcmd->timeout = 0;
+	dcmd->data_xfer_len = sizeof(struct megasas_ctrl_info);
+	dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
+	dcmd->sgl.sge32[0].phys_addr = ci_h;
+	dcmd->sgl.sge32[0].length = sizeof(struct megasas_ctrl_info);
+
+	if (!megasas_issue_polled(instance, cmd)) {
+		ret = 0;
+		memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
+	} else {
+		ret = -1;
+	}
+
+	pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
+			    ci, ci_h);
+
+	megasas_return_cmd(instance, cmd);
+	return ret;
+}
+
+/**
+ * megasas_init_mfi -	Initializes the FW
+ * @instance:		Adapter soft state
+ *
+ * This is the main function for initializing MFI firmware.
+ */
+static int megasas_init_mfi(struct megasas_instance *instance)
+{
+	u32 context_sz;
+	u32 reply_q_sz;
+	u32 max_sectors_1;
+	u32 max_sectors_2;
+	struct megasas_register_set __iomem *reg_set;
+
+	struct megasas_cmd *cmd;
+	struct megasas_ctrl_info *ctrl_info;
+
+	struct megasas_init_frame *init_frame;
+	struct megasas_init_queue_info *initq_info;
+	dma_addr_t init_frame_h;
+	dma_addr_t initq_info_h;
+
+	/*
+	 * Map the message registers
+	 */
+	instance->base_addr = pci_resource_start(instance->pdev, 0);
+
+	if (pci_request_regions(instance->pdev, "megasas: LSI Logic")) {
+		printk(KERN_DEBUG "megasas: IO memory region busy!\n");
+		return -EBUSY;
+	}
+
+	instance->reg_set = ioremap_nocache(instance->base_addr, 8192);
+
+	if (!instance->reg_set) {
+		printk(KERN_DEBUG "megasas: Failed to map IO mem\n");
+		goto fail_ioremap;
+	}
+
+	reg_set = instance->reg_set;
+
+	/*
+	 * We expect the FW state to be READY
+	 */
+	if (megasas_transition_to_ready(instance->reg_set))
+		goto fail_ready_state;
+
+	/*
+	 * Get various operational parameters from status register
+	 */
+	instance->max_fw_cmds = readl(&reg_set->outbound_msg_0) & 0x00FFFF;
+	instance->max_num_sge = (readl(&reg_set->outbound_msg_0) & 0xFF0000) >>
+	    0x10;
+	/*
+	 * Create a pool of commands
+	 */
+	if (megasas_alloc_cmds(instance))
+		goto fail_alloc_cmds;
+
+	/*
+	 * Allocate memory for reply queue. Length of reply queue should
+	 * be _one_ more than the maximum commands handled by the firmware.
+	 *
+	 * Note: When FW completes commands, it places corresponding contex
+	 * values in this circular reply queue. This circular queue is a fairly
+	 * typical producer-consumer queue. FW is the producer (of completed
+	 * commands) and the driver is the consumer.
+	 */
+	context_sz = sizeof(u32);
+	reply_q_sz = context_sz * (instance->max_fw_cmds + 1);
+
+	instance->reply_queue = pci_alloc_consistent(instance->pdev,
+						     reply_q_sz,
+						     &instance->reply_queue_h);
+
+	if (!instance->reply_queue) {
+		printk(KERN_DEBUG "megasas: Out of DMA mem for reply queue\n");
+		goto fail_reply_queue;
+	}
+
+	/*
+	 * Prepare a init frame. Note the init frame points to queue info
+	 * structure. Each frame has SGL allocated after first 64 bytes. For
+	 * this frame - since we don't need any SGL - we use SGL's space as
+	 * queue info structure
+	 *
+	 * We will not get a NULL command below. We just created the pool.
+	 */
+	cmd = megasas_get_cmd(instance);
+
+	init_frame = (struct megasas_init_frame *)cmd->frame;
+	initq_info = (struct megasas_init_queue_info *)
+	    ((unsigned long)init_frame + 64);
+
+	init_frame_h = cmd->frame_phys_addr;
+	initq_info_h = init_frame_h + 64;
+
+	memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
+	memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
+
+	initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
+	initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
+
+	initq_info->producer_index_phys_addr_lo = instance->producer_h;
+	initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
+
+	init_frame->cmd = MFI_CMD_INIT;
+	init_frame->cmd_status = 0xFF;
+	init_frame->queue_info_new_phys_addr_lo = initq_info_h;
+
+	init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
+
+	/*
+	 * Issue the init frame in polled mode
+	 */
+	if (megasas_issue_polled(instance, cmd)) {
+		printk(KERN_DEBUG "megasas: Failed to init firmware\n");
+		goto fail_fw_init;
+	}
+
+	megasas_return_cmd(instance, cmd);
+
+	ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
+
+	/*
+	 * Compute the max allowed sectors per IO: The controller info has two
+	 * limits on max sectors. Driver should use the minimum of these two.
+	 *
+	 * 1 << stripe_sz_ops.min = max sectors per strip
+	 *
+	 * Note that older firmwares ( < FW ver 30) didn't report information
+	 * to calculate max_sectors_1. So the number ended up as zero always.
+	 */
+	if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {
+
+		max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
+		    ctrl_info->max_strips_per_io;
+		max_sectors_2 = ctrl_info->max_request_size;
+
+		instance->max_sectors_per_req = (max_sectors_1 < max_sectors_2)
+		    ? max_sectors_1 : max_sectors_2;
+	} else
+		instance->max_sectors_per_req = instance->max_num_sge *
+		    PAGE_SIZE / 512;
+
+	kfree(ctrl_info);
+
+	return 0;
+
+      fail_fw_init:
+	megasas_return_cmd(instance, cmd);
+
+	pci_free_consistent(instance->pdev, reply_q_sz,
+			    instance->reply_queue, instance->reply_queue_h);
+      fail_reply_queue:
+	megasas_free_cmds(instance);
+
+      fail_alloc_cmds:
+      fail_ready_state:
+	iounmap(instance->reg_set);
+
+      fail_ioremap:
+	pci_release_regions(instance->pdev);
+
+	return -EINVAL;
+}
+
+/**
+ * megasas_release_mfi -	Reverses the FW initialization
+ * @intance:			Adapter soft state
+ */
+static void megasas_release_mfi(struct megasas_instance *instance)
+{
+	u32 reply_q_sz = sizeof(u32) * (instance->max_fw_cmds + 1);
+
+	pci_free_consistent(instance->pdev, reply_q_sz,
+			    instance->reply_queue, instance->reply_queue_h);
+
+	megasas_free_cmds(instance);
+
+	iounmap(instance->reg_set);
+
+	pci_release_regions(instance->pdev);
+}
+
+/**
+ * megasas_get_seq_num -	Gets latest event sequence numbers
+ * @instance:			Adapter soft state
+ * @eli:			FW event log sequence numbers information
+ *
+ * FW maintains a log of all events in a non-volatile area. Upper layers would
+ * usually find out the latest sequence number of the events, the seq number at
+ * the boot etc. They would "read" all the events below the latest seq number
+ * by issuing a direct fw cmd (DCMD). For the future events (beyond latest seq
+ * number), they would subsribe to AEN (asynchronous event notification) and
+ * wait for the events to happen.
+ */
+static int
+megasas_get_seq_num(struct megasas_instance *instance,
+		    struct megasas_evt_log_info *eli)
+{
+	struct megasas_cmd *cmd;
+	struct megasas_dcmd_frame *dcmd;
+	struct megasas_evt_log_info *el_info;
+	dma_addr_t el_info_h = 0;
+
+	cmd = megasas_get_cmd(instance);
+
+	if (!cmd) {
+		return -ENOMEM;
+	}
+
+	dcmd = &cmd->frame->dcmd;
+	el_info = pci_alloc_consistent(instance->pdev,
+				       sizeof(struct megasas_evt_log_info),
+				       &el_info_h);
+
+	if (!el_info) {
+		megasas_return_cmd(instance, cmd);
+		return -ENOMEM;
+	}
+
+	memset(el_info, 0, sizeof(*el_info));
+	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+	dcmd->cmd = MFI_CMD_DCMD;
+	dcmd->cmd_status = 0x0;
+	dcmd->sge_count = 1;
+	dcmd->flags = MFI_FRAME_DIR_READ;
+	dcmd->timeout = 0;
+	dcmd->data_xfer_len = sizeof(struct megasas_evt_log_info);
+	dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
+	dcmd->sgl.sge32[0].phys_addr = el_info_h;
+	dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_log_info);
+
+	megasas_issue_blocked_cmd(instance, cmd);
+
+	/*
+	 * Copy the data back into callers buffer
+	 */
+	memcpy(eli, el_info, sizeof(struct megasas_evt_log_info));
+
+	pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
+			    el_info, el_info_h);
+
+	megasas_return_cmd(instance, cmd);
+
+	return 0;
+}
+
+/**
+ * megasas_register_aen -	Registers for asynchronous event notification
+ * @instance:			Adapter soft state
+ * @seq_num:			The starting sequence number
+ * @class_locale:		Class of the event
+ *
+ * This function subscribes for AEN for events beyond the @seq_num. It requests
+ * to be notified if and only if the event is of type @class_locale
+ */
+static int
+megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
+		     u32 class_locale_word)
+{
+	int ret_val;
+	struct megasas_cmd *cmd;
+	struct megasas_dcmd_frame *dcmd;
+	union megasas_evt_class_locale curr_aen;
+	union megasas_evt_class_locale prev_aen;
+
+	/*
+	 * If there an AEN pending already (aen_cmd), check if the
+	 * class_locale of that pending AEN is inclusive of the new
+	 * AEN request we currently have. If it is, then we don't have
+	 * to do anything. In other words, whichever events the current
+	 * AEN request is subscribing to, have already been subscribed
+	 * to.
+	 *
+	 * If the old_cmd is _not_ inclusive, then we have to abort
+	 * that command, form a class_locale that is superset of both
+	 * old and current and re-issue to the FW
+	 */
+
+	curr_aen.word = class_locale_word;
+
+	if (instance->aen_cmd) {
+
+		prev_aen.word = instance->aen_cmd->frame->dcmd.mbox.w[1];
+
+		/*
+		 * A class whose enum value is smaller is inclusive of all
+		 * higher values. If a PROGRESS (= -1) was previously
+		 * registered, then a new registration requests for higher
+		 * classes need not be sent to FW. They are automatically
+		 * included.
+		 *
+		 * Locale numbers don't have such hierarchy. They are bitmap
+		 * values
+		 */
+		if ((prev_aen.members.class <= curr_aen.members.class) &&
+		    !((prev_aen.members.locale & curr_aen.members.locale) ^
+		      curr_aen.members.locale)) {
+			/*
+			 * Previously issued event registration includes
+			 * current request. Nothing to do.
+			 */
+			return 0;
+		} else {
+			curr_aen.members.locale |= prev_aen.members.locale;
+
+			if (prev_aen.members.class < curr_aen.members.class)
+				curr_aen.members.class = prev_aen.members.class;
+
+			instance->aen_cmd->abort_aen = 1;
+			ret_val = megasas_issue_blocked_abort_cmd(instance,
+								  instance->
+								  aen_cmd);
+
+			if (ret_val) {
+				printk(KERN_DEBUG "megasas: Failed to abort "
+				       "previous AEN command\n");
+				return ret_val;
+			}
+		}
+	}
+
+	cmd = megasas_get_cmd(instance);
+
+	if (!cmd)
+		return -ENOMEM;
+
+	dcmd = &cmd->frame->dcmd;
+
+	memset(instance->evt_detail, 0, sizeof(struct megasas_evt_detail));
+
+	/*
+	 * Prepare DCMD for aen registration
+	 */
+	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+	dcmd->cmd = MFI_CMD_DCMD;
+	dcmd->cmd_status = 0x0;
+	dcmd->sge_count = 1;
+	dcmd->flags = MFI_FRAME_DIR_READ;
+	dcmd->timeout = 0;
+	dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
+	dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
+	dcmd->mbox.w[0] = 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);
+
+	/*
+	 * Store reference to the cmd used to register for AEN. When an
+	 * application wants us to register for AEN, we have to abort this
+	 * cmd and re-register with a new EVENT LOCALE supplied by that app
+	 */
+	instance->aen_cmd = cmd;
+
+	/*
+	 * Issue the aen registration frame
+	 */
+	writel(cmd->frame_phys_addr >> 3,
+	       &instance->reg_set->inbound_queue_port);
+
+	return 0;
+}
+
+/**
+ * megasas_start_aen -	Subscribes to AEN during driver load time
+ * @instance:		Adapter soft state
+ */
+static int megasas_start_aen(struct megasas_instance *instance)
+{
+	struct megasas_evt_log_info eli;
+	union megasas_evt_class_locale class_locale;
+
+	/*
+	 * Get the latest sequence number from FW
+	 */
+	memset(&eli, 0, sizeof(eli));
+
+	if (megasas_get_seq_num(instance, &eli))
+		return -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;
+
+	return megasas_register_aen(instance, eli.newest_seq_num + 1,
+				    class_locale.word);
+}
+
+/**
+ * megasas_io_attach -	Attaches this driver to SCSI mid-layer
+ * @instance:		Adapter soft state
+ */
+static int megasas_io_attach(struct megasas_instance *instance)
+{
+	struct Scsi_Host *host = instance->host;
+
+	/*
+	 * Export parameters required by SCSI mid-layer
+	 */
+	host->irq = instance->pdev->irq;
+	host->unique_id = instance->unique_id;
+	host->can_queue = instance->max_fw_cmds - MEGASAS_INT_CMDS;
+	host->this_id = instance->init_id;
+	host->sg_tablesize = instance->max_num_sge;
+	host->max_sectors = instance->max_sectors_per_req;
+	host->cmd_per_lun = 128;
+	host->max_channel = MEGASAS_MAX_CHANNELS - 1;
+	host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL;
+	host->max_lun = MEGASAS_MAX_LUN;
+
+	/*
+	 * Notify the mid-layer about the new controller
+	 */
+	if (scsi_add_host(host, &instance->pdev->dev)) {
+		printk(KERN_DEBUG "megasas: scsi_add_host failed\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * Trigger SCSI to scan our drives
+	 */
+	scsi_scan_host(host);
+	return 0;
+}
+
+/**
+ * megasas_probe_one -	PCI hotplug entry point
+ * @pdev:		PCI device structure
+ * @id:			PCI ids of supported hotplugged adapter	
+ */
+static int __devinit
+megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int rval;
+	struct Scsi_Host *host;
+	struct megasas_instance *instance;
+
+	/*
+	 * Announce PCI information
+	 */
+	printk(KERN_INFO "megasas: %#4.04x:%#4.04x:%#4.04x:%#4.04x: ",
+	       pdev->vendor, pdev->device, pdev->subsystem_vendor,
+	       pdev->subsystem_device);
+
+	printk("bus %d:slot %d:func %d\n",
+	       pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
+
+	/*
+	 * PCI prepping: enable device set bus mastering and dma mask
+	 */
+	rval = pci_enable_device(pdev);
+
+	if (rval) {
+		return rval;
+	}
+
+	pci_set_master(pdev);
+
+	/*
+	 * All our contollers are capable of performing 64-bit DMA
+	 */
+	if (IS_DMA64) {
+		if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
+
+			if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
+				goto fail_set_dma_mask;
+		}
+	} else {
+		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0)
+			goto fail_set_dma_mask;
+	}
+
+	host = scsi_host_alloc(&megasas_template,
+			       sizeof(struct megasas_instance));
+
+	if (!host) {
+		printk(KERN_DEBUG "megasas: scsi_host_alloc failed\n");
+		goto fail_alloc_instance;
+	}
+
+	instance = (struct megasas_instance *)host->hostdata;
+	memset(instance, 0, sizeof(*instance));
+
+	instance->producer = pci_alloc_consistent(pdev, sizeof(u32),
+						  &instance->producer_h);
+	instance->consumer = pci_alloc_consistent(pdev, sizeof(u32),
+						  &instance->consumer_h);
+
+	if (!instance->producer || !instance->consumer) {
+		printk(KERN_DEBUG "megasas: Failed to allocate memory for "
+		       "producer, consumer\n");
+		goto fail_alloc_dma_buf;
+	}
+
+	*instance->producer = 0;
+	*instance->consumer = 0;
+
+	instance->evt_detail = pci_alloc_consistent(pdev,
+						    sizeof(struct
+							   megasas_evt_detail),
+						    &instance->evt_detail_h);
+
+	if (!instance->evt_detail) {
+		printk(KERN_DEBUG "megasas: Failed to allocate memory for "
+		       "event detail structure\n");
+		goto fail_alloc_dma_buf;
+	}
+
+	/*
+	 * Initialize locks and queues
+	 */
+	INIT_LIST_HEAD(&instance->cmd_pool);
+
+	init_waitqueue_head(&instance->int_cmd_wait_q);
+	init_waitqueue_head(&instance->abort_cmd_wait_q);
+
+	spin_lock_init(&instance->cmd_pool_lock);
+	spin_lock_init(&instance->instance_lock);
+
+	sema_init(&instance->aen_mutex, 1);
+	sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS);
+
+	/*
+	 * Initialize PCI related and misc parameters
+	 */
+	instance->pdev = pdev;
+	instance->host = host;
+	instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
+	instance->init_id = MEGASAS_DEFAULT_INIT_ID;
+
+	/*
+	 * Initialize MFI Firmware
+	 */
+	if (megasas_init_mfi(instance))
+		goto fail_init_mfi;
+
+	/*
+	 * Register IRQ
+	 */
+	if (request_irq(pdev->irq, megasas_isr, SA_SHIRQ, "megasas", instance)) {
+		printk(KERN_DEBUG "megasas: Failed to register IRQ\n");
+		goto fail_irq;
+	}
+
+	megasas_enable_intr(instance->reg_set);
+
+	/*
+	 * Store instance in PCI softstate
+	 */
+	pci_set_drvdata(pdev, instance);
+
+	/*
+	 * Add this controller to megasas_mgmt_info structure so that it
+	 * can be exported to management applications
+	 */
+	megasas_mgmt_info.count++;
+	megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance;
+	megasas_mgmt_info.max_index++;
+
+	/*
+	 * Initiate AEN (Asynchronous Event Notification)
+	 */
+	if (megasas_start_aen(instance)) {
+		printk(KERN_DEBUG "megasas: start aen failed\n");
+		goto fail_start_aen;
+	}
+
+	/*
+	 * Register with SCSI mid-layer
+	 */
+	if (megasas_io_attach(instance))
+		goto fail_io_attach;
+
+	return 0;
+
+      fail_start_aen:
+      fail_io_attach:
+	megasas_mgmt_info.count--;
+	megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL;
+	megasas_mgmt_info.max_index--;
+
+	pci_set_drvdata(pdev, NULL);
+	megasas_disable_intr(instance->reg_set);
+	free_irq(instance->pdev->irq, instance);
+
+	megasas_release_mfi(instance);
+
+      fail_irq:
+      fail_init_mfi:
+      fail_alloc_dma_buf:
+	if (instance->evt_detail)
+		pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+				    instance->evt_detail,
+				    instance->evt_detail_h);
+
+	if (instance->producer)
+		pci_free_consistent(pdev, sizeof(u32), instance->producer,
+				    instance->producer_h);
+	if (instance->consumer)
+		pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+				    instance->consumer_h);
+	scsi_host_put(host);
+
+      fail_alloc_instance:
+      fail_set_dma_mask:
+	pci_disable_device(pdev);
+
+	return -ENODEV;
+}
+
+/**
+ * megasas_flush_cache -	Requests FW to flush all its caches
+ * @instance:			Adapter soft state
+ */
+static void megasas_flush_cache(struct megasas_instance *instance)
+{
+	struct megasas_cmd *cmd;
+	struct megasas_dcmd_frame *dcmd;
+
+	cmd = megasas_get_cmd(instance);
+
+	if (!cmd)
+		return;
+
+	dcmd = &cmd->frame->dcmd;
+
+	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+	dcmd->cmd = MFI_CMD_DCMD;
+	dcmd->cmd_status = 0x0;
+	dcmd->sge_count = 0;
+	dcmd->flags = MFI_FRAME_DIR_NONE;
+	dcmd->timeout = 0;
+	dcmd->data_xfer_len = 0;
+	dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
+	dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
+
+	megasas_issue_blocked_cmd(instance, cmd);
+
+	megasas_return_cmd(instance, cmd);
+
+	return;
+}
+
+/**
+ * megasas_shutdown_controller -	Instructs FW to shutdown the controller
+ * @instance:				Adapter soft state
+ */
+static void megasas_shutdown_controller(struct megasas_instance *instance)
+{
+	struct megasas_cmd *cmd;
+	struct megasas_dcmd_frame *dcmd;
+
+	cmd = megasas_get_cmd(instance);
+
+	if (!cmd)
+		return;
+
+	if (instance->aen_cmd)
+		megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd);
+
+	dcmd = &cmd->frame->dcmd;
+
+	memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+	dcmd->cmd = MFI_CMD_DCMD;
+	dcmd->cmd_status = 0x0;
+	dcmd->sge_count = 0;
+	dcmd->flags = MFI_FRAME_DIR_NONE;
+	dcmd->timeout = 0;
+	dcmd->data_xfer_len = 0;
+	dcmd->opcode = MR_DCMD_CTRL_SHUTDOWN;
+
+	megasas_issue_blocked_cmd(instance, cmd);
+
+	megasas_return_cmd(instance, cmd);
+
+	return;
+}
+
+/**
+ * megasas_detach_one -	PCI hot"un"plug entry point
+ * @pdev:		PCI device structure
+ */
+static void megasas_detach_one(struct pci_dev *pdev)
+{
+	int i;
+	struct Scsi_Host *host;
+	struct megasas_instance *instance;
+
+	instance = pci_get_drvdata(pdev);
+	host = instance->host;
+
+	scsi_remove_host(instance->host);
+	megasas_flush_cache(instance);
+	megasas_shutdown_controller(instance);
+
+	/*
+	 * Take the instance off the instance array. Note that we will not
+	 * decrement the max_index. We let this array be sparse array
+	 */
+	for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+		if (megasas_mgmt_info.instance[i] == instance) {
+			megasas_mgmt_info.count--;
+			megasas_mgmt_info.instance[i] = NULL;
+
+			break;
+		}
+	}
+
+	pci_set_drvdata(instance->pdev, NULL);
+
+	megasas_disable_intr(instance->reg_set);
+
+	free_irq(instance->pdev->irq, instance);
+
+	megasas_release_mfi(instance);
+
+	pci_free_consistent(pdev, sizeof(struct megasas_evt_detail),
+			    instance->evt_detail, instance->evt_detail_h);
+
+	pci_free_consistent(pdev, sizeof(u32), instance->producer,
+			    instance->producer_h);
+
+	pci_free_consistent(pdev, sizeof(u32), instance->consumer,
+			    instance->consumer_h);
+
+	scsi_host_put(host);
+
+	pci_set_drvdata(pdev, NULL);
+
+	pci_disable_device(pdev);
+
+	return;
+}
+
+/**
+ * megasas_shutdown -	Shutdown entry point
+ * @device:		Generic device structure
+ */
+static void megasas_shutdown(struct pci_dev *pdev)
+{
+	struct megasas_instance *instance = pci_get_drvdata(pdev);
+	megasas_flush_cache(instance);
+}
+
+/**
+ * megasas_mgmt_open -	char node "open" entry point
+ */
+static int megasas_mgmt_open(struct inode *inode, struct file *filep)
+{
+	/*
+	 * Allow only those users with admin rights
+	 */
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	return 0;
+}
+
+/**
+ * megasas_mgmt_release - char node "release" entry point
+ */
+static int megasas_mgmt_release(struct inode *inode, struct file *filep)
+{
+	filep->private_data = NULL;
+	fasync_helper(-1, filep, 0, &megasas_async_queue);
+
+	return 0;
+}
+
+/**
+ * megasas_mgmt_fasync -	Async notifier registration from applications
+ *
+ * This function adds the calling process to a driver global queue. When an
+ * event occurs, SIGIO will be sent to all processes in this queue.
+ */
+static int megasas_mgmt_fasync(int fd, struct file *filep, int mode)
+{
+	int rc;
+
+	down(&megasas_async_queue_mutex);
+
+	rc = fasync_helper(fd, filep, mode, &megasas_async_queue);
+
+	up(&megasas_async_queue_mutex);
+
+	if (rc >= 0) {
+		/* For sanity check when we get ioctl */
+		filep->private_data = filep;
+		return 0;
+	}
+
+	printk(KERN_DEBUG "megasas: fasync_helper failed [%d]\n", rc);
+
+	return rc;
+}
+
+/**
+ * megasas_mgmt_fw_ioctl -	Issues management ioctls to FW
+ * @instance:			Adapter soft state
+ * @argp:			User's ioctl packet
+ */
+static int
+megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
+		      struct megasas_iocpacket __user * user_ioc,
+		      struct megasas_iocpacket *ioc)
+{
+	struct megasas_sge32 *kern_sge32;
+	struct megasas_cmd *cmd;
+	void *kbuff_arr[MAX_IOCTL_SGE];
+	dma_addr_t buf_handle = 0;
+	int error = 0, i;
+	void *sense = NULL;
+	dma_addr_t sense_handle;
+	u32 *sense_ptr;
+
+	memset(kbuff_arr, 0, sizeof(kbuff_arr));
+
+	if (ioc->sge_count > MAX_IOCTL_SGE) {
+		printk(KERN_DEBUG "megasas: SGE count [%d] >  max limit [%d]\n",
+		       ioc->sge_count, MAX_IOCTL_SGE);
+		return -EINVAL;
+	}
+
+	cmd = megasas_get_cmd(instance);
+	if (!cmd) {
+		printk(KERN_DEBUG "megasas: Failed to get a cmd packet\n");
+		return -ENOMEM;
+	}
+
+	/*
+	 * User's IOCTL packet has 2 frames (maximum). Copy those two
+	 * frames into our cmd's frames. cmd->frame's context will get
+	 * overwritten when we copy from user's frames. So set that value
+	 * alone separately
+	 */
+	memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
+	cmd->frame->hdr.context = cmd->index;
+
+	/*
+	 * The management interface between applications and the fw uses
+	 * MFI frames. E.g, RAID configuration changes, LD property changes
+	 * etc are accomplishes through different kinds of MFI frames. The
+	 * driver needs to care only about substituting user buffers with
+	 * kernel buffers in SGLs. The location of SGL is embedded in the
+	 * struct iocpacket itself.
+	 */
+	kern_sge32 = (struct megasas_sge32 *)
+	    ((unsigned long)cmd->frame + ioc->sgl_off);
+
+	/*
+	 * For each user buffer, create a mirror buffer and copy in
+	 */
+	for (i = 0; i < ioc->sge_count; i++) {
+		kbuff_arr[i] = pci_alloc_consistent(instance->pdev,
+						    ioc->sgl[i].iov_len,
+						    &buf_handle);
+		if (!kbuff_arr[i]) {
+			printk(KERN_DEBUG "megasas: Failed to alloc "
+			       "kernel SGL buffer for IOCTL \n");
+			error = -ENOMEM;
+			goto out;
+		}
+
+		/*
+		 * We don't change the dma_coherent_mask, so
+		 * pci_alloc_consistent only returns 32bit addresses
+		 */
+		kern_sge32[i].phys_addr = (u32) buf_handle;
+		kern_sge32[i].length = ioc->sgl[i].iov_len;
+
+		/*
+		 * We created a kernel buffer corresponding to the
+		 * user buffer. Now copy in from the user buffer
+		 */
+		if (copy_from_user(kbuff_arr[i], ioc->sgl[i].iov_base,
+				   (u32) (ioc->sgl[i].iov_len))) {
+			error = -EFAULT;
+			goto out;
+		}
+	}
+
+	if (ioc->sense_len) {
+		sense = pci_alloc_consistent(instance->pdev, ioc->sense_len,
+					     &sense_handle);
+		if (!sense) {
+			error = -ENOMEM;
+			goto out;
+		}
+
+		sense_ptr =
+		    (u32 *) ((unsigned long)cmd->frame + ioc->sense_off);
+		*sense_ptr = sense_handle;
+	}
+
+	/*
+	 * Set the sync_cmd flag so that the ISR knows not to complete this
+	 * cmd to the SCSI mid-layer
+	 */
+	cmd->sync_cmd = 1;
+	megasas_issue_blocked_cmd(instance, cmd);
+	cmd->sync_cmd = 0;
+
+	/*
+	 * copy out the kernel buffers to user buffers
+	 */
+	for (i = 0; i < ioc->sge_count; i++) {
+		if (copy_to_user(ioc->sgl[i].iov_base, kbuff_arr[i],
+				 ioc->sgl[i].iov_len)) {
+			error = -EFAULT;
+			goto out;
+		}
+	}
+
+	/*
+	 * copy out the sense
+	 */
+	if (ioc->sense_len) {
+		/*
+		 * sense_ptr points to the location that has the user
+		 * sense buffer address
+		 */
+		sense_ptr = (u32 *) ((unsigned long)ioc->frame.raw +
+				     ioc->sense_off);
+
+		if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)),
+				 sense, ioc->sense_len)) {
+			error = -EFAULT;
+			goto out;
+		}
+	}
+
+	/*
+	 * copy the status codes returned by the fw
+	 */
+	if (copy_to_user(&user_ioc->frame.hdr.cmd_status,
+			 &cmd->frame->hdr.cmd_status, sizeof(u8))) {
+		printk(KERN_DEBUG "megasas: Error copying out cmd_status\n");
+		error = -EFAULT;
+	}
+
+      out:
+	if (sense) {
+		pci_free_consistent(instance->pdev, ioc->sense_len,
+				    sense, sense_handle);
+	}
+
+	for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) {
+		pci_free_consistent(instance->pdev,
+				    kern_sge32[i].length,
+				    kbuff_arr[i], kern_sge32[i].phys_addr);
+	}
+
+	megasas_return_cmd(instance, cmd);
+	return error;
+}
+
+static struct megasas_instance *megasas_lookup_instance(u16 host_no)
+{
+	int i;
+
+	for (i = 0; i < megasas_mgmt_info.max_index; i++) {
+
+		if ((megasas_mgmt_info.instance[i]) &&
+		    (megasas_mgmt_info.instance[i]->host->host_no == host_no))
+			return megasas_mgmt_info.instance[i];
+	}
+
+	return NULL;
+}
+
+static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
+{
+	struct megasas_iocpacket __user *user_ioc =
+	    (struct megasas_iocpacket __user *)arg;
+	struct megasas_iocpacket *ioc;
+	struct megasas_instance *instance;
+	int error;
+
+	ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
+	if (!ioc)
+		return -ENOMEM;
+
+	if (copy_from_user(ioc, user_ioc, sizeof(*ioc))) {
+		error = -EFAULT;
+		goto out_kfree_ioc;
+	}
+
+	instance = megasas_lookup_instance(ioc->host_no);
+	if (!instance) {
+		error = -ENODEV;
+		goto out_kfree_ioc;
+	}
+
+	/*
+	 * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds
+	 */
+	if (down_interruptible(&instance->ioctl_sem)) {
+		error = -ERESTARTSYS;
+		goto out_kfree_ioc;
+	}
+	error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc);
+	up(&instance->ioctl_sem);
+
+      out_kfree_ioc:
+	kfree(ioc);
+	return error;
+}
+
+static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg)
+{
+	struct megasas_instance *instance;
+	struct megasas_aen aen;
+	int error;
+
+	if (file->private_data != file) {
+		printk(KERN_DEBUG "megasas: fasync_helper was not "
+		       "called first\n");
+		return -EINVAL;
+	}
+
+	if (copy_from_user(&aen, (void __user *)arg, sizeof(aen)))
+		return -EFAULT;
+
+	instance = megasas_lookup_instance(aen.host_no);
+
+	if (!instance)
+		return -ENODEV;
+
+	down(&instance->aen_mutex);
+	error = megasas_register_aen(instance, aen.seq_num,
+				     aen.class_locale_word);
+	up(&instance->aen_mutex);
+	return error;
+}
+
+/**
+ * megasas_mgmt_ioctl -	char node ioctl entry point
+ */
+static long
+megasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	switch (cmd) {
+	case MEGASAS_IOC_FIRMWARE:
+		return megasas_mgmt_ioctl_fw(file, arg);
+
+	case MEGASAS_IOC_GET_AEN:
+		return megasas_mgmt_ioctl_aen(file, arg);
+	}
+
+	return -ENOTTY;
+}
+
+#ifdef CONFIG_COMPAT
+static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
+{
+	struct compat_megasas_iocpacket __user *cioc =
+	    (struct compat_megasas_iocpacket __user *)arg;
+	struct megasas_iocpacket __user *ioc =
+	    compat_alloc_user_space(sizeof(struct megasas_iocpacket));
+	int i;
+	int error = 0;
+
+	clear_user(ioc, sizeof(*ioc));
+
+	if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
+	    copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
+	    copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) ||
+	    copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) ||
+	    copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) ||
+	    copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32)))
+		return -EFAULT;
+
+	for (i = 0; i < MAX_IOCTL_SGE; i++) {
+		compat_uptr_t ptr;
+
+		if (get_user(ptr, &cioc->sgl[i].iov_base) ||
+		    put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) ||
+		    copy_in_user(&ioc->sgl[i].iov_len,
+				 &cioc->sgl[i].iov_len, sizeof(compat_size_t)))
+			return -EFAULT;
+	}
+
+	error = megasas_mgmt_ioctl_fw(file, (unsigned long)ioc);
+
+	if (copy_in_user(&cioc->frame.hdr.cmd_status,
+			 &ioc->frame.hdr.cmd_status, sizeof(u8))) {
+		printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n");
+		return -EFAULT;
+	}
+	return error;
+}
+
+static long
+megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd,
+			  unsigned long arg)
+{
+	switch (cmd) {
+	case MEGASAS_IOC_FIRMWARE:{
+			return megasas_mgmt_compat_ioctl_fw(file, arg);
+		}
+	case MEGASAS_IOC_GET_AEN:
+		return megasas_mgmt_ioctl_aen(file, arg);
+	}
+
+	return -ENOTTY;
+}
+#endif
+
+/*
+ * File operations structure for management interface
+ */
+static struct file_operations megasas_mgmt_fops = {
+	.owner = THIS_MODULE,
+	.open = megasas_mgmt_open,
+	.release = megasas_mgmt_release,
+	.fasync = megasas_mgmt_fasync,
+	.unlocked_ioctl = megasas_mgmt_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = megasas_mgmt_compat_ioctl,
+#endif
+};
+
+/*
+ * PCI hotplug support registration structure
+ */
+static struct pci_driver megasas_pci_driver = {
+
+	.name = "megaraid_sas",
+	.id_table = megasas_pci_table,
+	.probe = megasas_probe_one,
+	.remove = __devexit_p(megasas_detach_one),
+	.shutdown = megasas_shutdown,
+};
+
+/*
+ * Sysfs driver attributes
+ */
+static ssize_t megasas_sysfs_show_version(struct device_driver *dd, char *buf)
+{
+	return snprintf(buf, strlen(MEGASAS_VERSION) + 2, "%s\n",
+			MEGASAS_VERSION);
+}
+
+static DRIVER_ATTR(version, S_IRUGO, megasas_sysfs_show_version, NULL);
+
+static ssize_t
+megasas_sysfs_show_release_date(struct device_driver *dd, char *buf)
+{
+	return snprintf(buf, strlen(MEGASAS_RELDATE) + 2, "%s\n",
+			MEGASAS_RELDATE);
+}
+
+static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
+		   NULL);
+
+/**
+ * megasas_init - Driver load entry point
+ */
+static int __init megasas_init(void)
+{
+	int rval;
+
+	/*
+	 * Announce driver version and other information
+	 */
+	printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
+	       MEGASAS_EXT_VERSION);
+
+	memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
+
+	/*
+	 * Register character device node
+	 */
+	rval = register_chrdev(0, "megaraid_sas_ioctl", &megasas_mgmt_fops);
+
+	if (rval < 0) {
+		printk(KERN_DEBUG "megasas: failed to open device node\n");
+		return rval;
+	}
+
+	megasas_mgmt_majorno = rval;
+
+	/*
+	 * Register ourselves as PCI hotplug module
+	 */
+	rval = pci_module_init(&megasas_pci_driver);
+
+	if (rval) {
+		printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
+		unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+	}
+
+	driver_create_file(&megasas_pci_driver.driver, &driver_attr_version);
+	driver_create_file(&megasas_pci_driver.driver,
+			   &driver_attr_release_date);
+
+	return rval;
+}
+
+/**
+ * megasas_exit - Driver unload entry point
+ */
+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_release_date);
+
+	pci_unregister_driver(&megasas_pci_driver);
+	unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+}
+
+module_init(megasas_init);
+module_exit(megasas_exit);
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
new file mode 100644
index 0000000..eaec9d5
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -0,0 +1,1142 @@
+/*
+ *
+ *		Linux MegaRAID driver for SAS based RAID controllers
+ *
+ * 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
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * FILE		: megaraid_sas.h
+ */
+
+#ifndef LSI_MEGARAID_SAS_H
+#define LSI_MEGARAID_SAS_H
+
+/**
+ * MegaRAID SAS Driver meta data
+ */
+#define MEGASAS_VERSION				"00.00.02.00-rc4"
+#define MEGASAS_RELDATE				"Sep 16, 2005"
+#define MEGASAS_EXT_VERSION			"Fri Sep 16 12:37:08 EDT 2005"
+
+/*
+ * =====================================
+ * MegaRAID SAS MFI firmware definitions
+ * =====================================
+ */
+
+/*
+ * MFI stands for  MegaRAID SAS FW Interface. This is just a moniker for 
+ * protocol between the software and firmware. Commands are issued using
+ * "message frames"
+ */
+
+/**
+ * FW posts its state in upper 4 bits of outbound_msg_0 register
+ */
+#define MFI_STATE_MASK				0xF0000000
+#define MFI_STATE_UNDEFINED			0x00000000
+#define MFI_STATE_BB_INIT			0x10000000
+#define MFI_STATE_FW_INIT			0x40000000
+#define MFI_STATE_WAIT_HANDSHAKE		0x60000000
+#define MFI_STATE_FW_INIT_2			0x70000000
+#define MFI_STATE_DEVICE_SCAN			0x80000000
+#define MFI_STATE_FLUSH_CACHE			0xA0000000
+#define MFI_STATE_READY				0xB0000000
+#define MFI_STATE_OPERATIONAL			0xC0000000
+#define MFI_STATE_FAULT				0xF0000000
+
+#define MEGAMFI_FRAME_SIZE			64
+
+/**
+ * During FW init, clear pending cmds & reset state using inbound_msg_0
+ *
+ * ABORT	: Abort all pending cmds
+ * 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
+ */
+#define MFI_INIT_ABORT				0x00000000
+#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
+
+/**
+ * MFI frame flags
+ */
+#define MFI_FRAME_POST_IN_REPLY_QUEUE		0x0000
+#define MFI_FRAME_DONT_POST_IN_REPLY_QUEUE	0x0001
+#define MFI_FRAME_SGL32				0x0000
+#define MFI_FRAME_SGL64				0x0002
+#define MFI_FRAME_SENSE32			0x0000
+#define MFI_FRAME_SENSE64			0x0004
+#define MFI_FRAME_DIR_NONE			0x0000
+#define MFI_FRAME_DIR_WRITE			0x0008
+#define MFI_FRAME_DIR_READ			0x0010
+#define MFI_FRAME_DIR_BOTH			0x0018
+
+/**
+ * Definition for cmd_status
+ */
+#define MFI_CMD_STATUS_POLL_MODE		0xFF
+
+/**
+ * MFI command opcodes
+ */
+#define MFI_CMD_INIT				0x00
+#define MFI_CMD_LD_READ				0x01
+#define MFI_CMD_LD_WRITE			0x02
+#define MFI_CMD_LD_SCSI_IO			0x03
+#define MFI_CMD_PD_SCSI_IO			0x04
+#define MFI_CMD_DCMD				0x05
+#define MFI_CMD_ABORT				0x06
+#define MFI_CMD_SMP				0x07
+#define MFI_CMD_STP				0x08
+
+#define MR_DCMD_CTRL_GET_INFO			0x01010000
+
+#define MR_DCMD_CTRL_CACHE_FLUSH		0x01101000
+#define MR_FLUSH_CTRL_CACHE			0x01
+#define MR_FLUSH_DISK_CACHE			0x02
+
+#define MR_DCMD_CTRL_SHUTDOWN			0x01050000
+#define MR_ENABLE_DRIVE_SPINDOWN		0x01
+
+#define MR_DCMD_CTRL_EVENT_GET_INFO		0x01040100
+#define MR_DCMD_CTRL_EVENT_GET			0x01040300
+#define MR_DCMD_CTRL_EVENT_WAIT			0x01040500
+#define MR_DCMD_LD_GET_PROPERTIES		0x03030000
+
+#define MR_DCMD_CLUSTER				0x08000000
+#define MR_DCMD_CLUSTER_RESET_ALL		0x08010100
+#define MR_DCMD_CLUSTER_RESET_LD		0x08010200
+
+/**
+ * MFI command completion codes
+ */
+enum MFI_STAT {
+	MFI_STAT_OK = 0x00,
+	MFI_STAT_INVALID_CMD = 0x01,
+	MFI_STAT_INVALID_DCMD = 0x02,
+	MFI_STAT_INVALID_PARAMETER = 0x03,
+	MFI_STAT_INVALID_SEQUENCE_NUMBER = 0x04,
+	MFI_STAT_ABORT_NOT_POSSIBLE = 0x05,
+	MFI_STAT_APP_HOST_CODE_NOT_FOUND = 0x06,
+	MFI_STAT_APP_IN_USE = 0x07,
+	MFI_STAT_APP_NOT_INITIALIZED = 0x08,
+	MFI_STAT_ARRAY_INDEX_INVALID = 0x09,
+	MFI_STAT_ARRAY_ROW_NOT_EMPTY = 0x0a,
+	MFI_STAT_CONFIG_RESOURCE_CONFLICT = 0x0b,
+	MFI_STAT_DEVICE_NOT_FOUND = 0x0c,
+	MFI_STAT_DRIVE_TOO_SMALL = 0x0d,
+	MFI_STAT_FLASH_ALLOC_FAIL = 0x0e,
+	MFI_STAT_FLASH_BUSY = 0x0f,
+	MFI_STAT_FLASH_ERROR = 0x10,
+	MFI_STAT_FLASH_IMAGE_BAD = 0x11,
+	MFI_STAT_FLASH_IMAGE_INCOMPLETE = 0x12,
+	MFI_STAT_FLASH_NOT_OPEN = 0x13,
+	MFI_STAT_FLASH_NOT_STARTED = 0x14,
+	MFI_STAT_FLUSH_FAILED = 0x15,
+	MFI_STAT_HOST_CODE_NOT_FOUNT = 0x16,
+	MFI_STAT_LD_CC_IN_PROGRESS = 0x17,
+	MFI_STAT_LD_INIT_IN_PROGRESS = 0x18,
+	MFI_STAT_LD_LBA_OUT_OF_RANGE = 0x19,
+	MFI_STAT_LD_MAX_CONFIGURED = 0x1a,
+	MFI_STAT_LD_NOT_OPTIMAL = 0x1b,
+	MFI_STAT_LD_RBLD_IN_PROGRESS = 0x1c,
+	MFI_STAT_LD_RECON_IN_PROGRESS = 0x1d,
+	MFI_STAT_LD_WRONG_RAID_LEVEL = 0x1e,
+	MFI_STAT_MAX_SPARES_EXCEEDED = 0x1f,
+	MFI_STAT_MEMORY_NOT_AVAILABLE = 0x20,
+	MFI_STAT_MFC_HW_ERROR = 0x21,
+	MFI_STAT_NO_HW_PRESENT = 0x22,
+	MFI_STAT_NOT_FOUND = 0x23,
+	MFI_STAT_NOT_IN_ENCL = 0x24,
+	MFI_STAT_PD_CLEAR_IN_PROGRESS = 0x25,
+	MFI_STAT_PD_TYPE_WRONG = 0x26,
+	MFI_STAT_PR_DISABLED = 0x27,
+	MFI_STAT_ROW_INDEX_INVALID = 0x28,
+	MFI_STAT_SAS_CONFIG_INVALID_ACTION = 0x29,
+	MFI_STAT_SAS_CONFIG_INVALID_DATA = 0x2a,
+	MFI_STAT_SAS_CONFIG_INVALID_PAGE = 0x2b,
+	MFI_STAT_SAS_CONFIG_INVALID_TYPE = 0x2c,
+	MFI_STAT_SCSI_DONE_WITH_ERROR = 0x2d,
+	MFI_STAT_SCSI_IO_FAILED = 0x2e,
+	MFI_STAT_SCSI_RESERVATION_CONFLICT = 0x2f,
+	MFI_STAT_SHUTDOWN_FAILED = 0x30,
+	MFI_STAT_TIME_NOT_SET = 0x31,
+	MFI_STAT_WRONG_STATE = 0x32,
+	MFI_STAT_LD_OFFLINE = 0x33,
+	MFI_STAT_PEER_NOTIFICATION_REJECTED = 0x34,
+	MFI_STAT_PEER_NOTIFICATION_FAILED = 0x35,
+	MFI_STAT_RESERVATION_IN_PROGRESS = 0x36,
+	MFI_STAT_I2C_ERRORS_DETECTED = 0x37,
+	MFI_STAT_PCI_ERRORS_DETECTED = 0x38,
+
+	MFI_STAT_INVALID_STATUS = 0xFF
+};
+
+/*
+ * Number of mailbox bytes in DCMD message frame
+ */
+#define MFI_MBOX_SIZE				12
+
+enum MR_EVT_CLASS {
+
+	MR_EVT_CLASS_DEBUG = -2,
+	MR_EVT_CLASS_PROGRESS = -1,
+	MR_EVT_CLASS_INFO = 0,
+	MR_EVT_CLASS_WARNING = 1,
+	MR_EVT_CLASS_CRITICAL = 2,
+	MR_EVT_CLASS_FATAL = 3,
+	MR_EVT_CLASS_DEAD = 4,
+
+};
+
+enum MR_EVT_LOCALE {
+
+	MR_EVT_LOCALE_LD = 0x0001,
+	MR_EVT_LOCALE_PD = 0x0002,
+	MR_EVT_LOCALE_ENCL = 0x0004,
+	MR_EVT_LOCALE_BBU = 0x0008,
+	MR_EVT_LOCALE_SAS = 0x0010,
+	MR_EVT_LOCALE_CTRL = 0x0020,
+	MR_EVT_LOCALE_CONFIG = 0x0040,
+	MR_EVT_LOCALE_CLUSTER = 0x0080,
+	MR_EVT_LOCALE_ALL = 0xffff,
+
+};
+
+enum MR_EVT_ARGS {
+
+	MR_EVT_ARGS_NONE,
+	MR_EVT_ARGS_CDB_SENSE,
+	MR_EVT_ARGS_LD,
+	MR_EVT_ARGS_LD_COUNT,
+	MR_EVT_ARGS_LD_LBA,
+	MR_EVT_ARGS_LD_OWNER,
+	MR_EVT_ARGS_LD_LBA_PD_LBA,
+	MR_EVT_ARGS_LD_PROG,
+	MR_EVT_ARGS_LD_STATE,
+	MR_EVT_ARGS_LD_STRIP,
+	MR_EVT_ARGS_PD,
+	MR_EVT_ARGS_PD_ERR,
+	MR_EVT_ARGS_PD_LBA,
+	MR_EVT_ARGS_PD_LBA_LD,
+	MR_EVT_ARGS_PD_PROG,
+	MR_EVT_ARGS_PD_STATE,
+	MR_EVT_ARGS_PCI,
+	MR_EVT_ARGS_RATE,
+	MR_EVT_ARGS_STR,
+	MR_EVT_ARGS_TIME,
+	MR_EVT_ARGS_ECC,
+
+};
+
+/*
+ * SAS controller properties
+ */
+struct megasas_ctrl_prop {
+
+	u16 seq_num;
+	u16 pred_fail_poll_interval;
+	u16 intr_throttle_count;
+	u16 intr_throttle_timeouts;
+	u8 rebuild_rate;
+	u8 patrol_read_rate;
+	u8 bgi_rate;
+	u8 cc_rate;
+	u8 recon_rate;
+	u8 cache_flush_interval;
+	u8 spinup_drv_count;
+	u8 spinup_delay;
+	u8 cluster_enable;
+	u8 coercion_mode;
+	u8 alarm_enable;
+	u8 disable_auto_rebuild;
+	u8 disable_battery_warn;
+	u8 ecc_bucket_size;
+	u16 ecc_bucket_leak_rate;
+	u8 restore_hotspare_on_insertion;
+	u8 expose_encl_devices;
+	u8 reserved[38];
+
+} __attribute__ ((packed));
+
+/*
+ * SAS controller information
+ */
+struct megasas_ctrl_info {
+
+	/*
+	 * PCI device information
+	 */
+	struct {
+
+		u16 vendor_id;
+		u16 device_id;
+		u16 sub_vendor_id;
+		u16 sub_device_id;
+		u8 reserved[24];
+
+	} __attribute__ ((packed)) pci;
+
+	/*
+	 * Host interface information
+	 */
+	struct {
+
+		u8 PCIX:1;
+		u8 PCIE:1;
+		u8 iSCSI:1;
+		u8 SAS_3G:1;
+		u8 reserved_0:4;
+		u8 reserved_1[6];
+		u8 port_count;
+		u64 port_addr[8];
+
+	} __attribute__ ((packed)) host_interface;
+
+	/*
+	 * Device (backend) interface information
+	 */
+	struct {
+
+		u8 SPI:1;
+		u8 SAS_3G:1;
+		u8 SATA_1_5G:1;
+		u8 SATA_3G:1;
+		u8 reserved_0:4;
+		u8 reserved_1[6];
+		u8 port_count;
+		u64 port_addr[8];
+
+	} __attribute__ ((packed)) device_interface;
+
+	/*
+	 * List of components residing in flash. All str are null terminated
+	 */
+	u32 image_check_word;
+	u32 image_component_count;
+
+	struct {
+
+		char name[8];
+		char version[32];
+		char build_date[16];
+		char built_time[16];
+
+	} __attribute__ ((packed)) image_component[8];
+
+	/*
+	 * List of flash components that have been flashed on the card, but
+	 * are not in use, pending reset of the adapter. This list will be
+	 * empty if a flash operation has not occurred. All stings are null
+	 * terminated
+	 */
+	u32 pending_image_component_count;
+
+	struct {
+
+		char name[8];
+		char version[32];
+		char build_date[16];
+		char build_time[16];
+
+	} __attribute__ ((packed)) pending_image_component[8];
+
+	u8 max_arms;
+	u8 max_spans;
+	u8 max_arrays;
+	u8 max_lds;
+
+	char product_name[80];
+	char serial_no[32];
+
+	/*
+	 * Other physical/controller/operation information. Indicates the
+	 * presence of the hardware
+	 */
+	struct {
+
+		u32 bbu:1;
+		u32 alarm:1;
+		u32 nvram:1;
+		u32 uart:1;
+		u32 reserved:28;
+
+	} __attribute__ ((packed)) hw_present;
+
+	u32 current_fw_time;
+
+	/*
+	 * Maximum data transfer sizes
+	 */
+	u16 max_concurrent_cmds;
+	u16 max_sge_count;
+	u32 max_request_size;
+
+	/*
+	 * Logical and physical device counts
+	 */
+	u16 ld_present_count;
+	u16 ld_degraded_count;
+	u16 ld_offline_count;
+
+	u16 pd_present_count;
+	u16 pd_disk_present_count;
+	u16 pd_disk_pred_failure_count;
+	u16 pd_disk_failed_count;
+
+	/*
+	 * Memory size information
+	 */
+	u16 nvram_size;
+	u16 memory_size;
+	u16 flash_size;
+
+	/*
+	 * Error counters
+	 */
+	u16 mem_correctable_error_count;
+	u16 mem_uncorrectable_error_count;
+
+	/*
+	 * Cluster information
+	 */
+	u8 cluster_permitted;
+	u8 cluster_active;
+
+	/*
+	 * Additional max data transfer sizes
+	 */
+	u16 max_strips_per_io;
+
+	/*
+	 * Controller capabilities structures
+	 */
+	struct {
+
+		u32 raid_level_0:1;
+		u32 raid_level_1:1;
+		u32 raid_level_5:1;
+		u32 raid_level_1E:1;
+		u32 raid_level_6:1;
+		u32 reserved:27;
+
+	} __attribute__ ((packed)) raid_levels;
+
+	struct {
+
+		u32 rbld_rate:1;
+		u32 cc_rate:1;
+		u32 bgi_rate:1;
+		u32 recon_rate:1;
+		u32 patrol_rate:1;
+		u32 alarm_control:1;
+		u32 cluster_supported:1;
+		u32 bbu:1;
+		u32 spanning_allowed:1;
+		u32 dedicated_hotspares:1;
+		u32 revertible_hotspares:1;
+		u32 foreign_config_import:1;
+		u32 self_diagnostic:1;
+		u32 mixed_redundancy_arr:1;
+		u32 global_hot_spares:1;
+		u32 reserved:17;
+
+	} __attribute__ ((packed)) adapter_operations;
+
+	struct {
+
+		u32 read_policy:1;
+		u32 write_policy:1;
+		u32 io_policy:1;
+		u32 access_policy:1;
+		u32 disk_cache_policy:1;
+		u32 reserved:27;
+
+	} __attribute__ ((packed)) ld_operations;
+
+	struct {
+
+		u8 min;
+		u8 max;
+		u8 reserved[2];
+
+	} __attribute__ ((packed)) stripe_sz_ops;
+
+	struct {
+
+		u32 force_online:1;
+		u32 force_offline:1;
+		u32 force_rebuild:1;
+		u32 reserved:29;
+
+	} __attribute__ ((packed)) pd_operations;
+
+	struct {
+
+		u32 ctrl_supports_sas:1;
+		u32 ctrl_supports_sata:1;
+		u32 allow_mix_in_encl:1;
+		u32 allow_mix_in_ld:1;
+		u32 allow_sata_in_cluster:1;
+		u32 reserved:27;
+
+	} __attribute__ ((packed)) pd_mix_support;
+
+	/*
+	 * Define ECC single-bit-error bucket information
+	 */
+	u8 ecc_bucket_count;
+	u8 reserved_2[11];
+
+	/*
+	 * Include the controller properties (changeable items)
+	 */
+	struct megasas_ctrl_prop properties;
+
+	/*
+	 * Define FW pkg version (set in envt v'bles on OEM basis)
+	 */
+	char package_version[0x60];
+
+	u8 pad[0x800 - 0x6a0];
+
+} __attribute__ ((packed));
+
+/*
+ * ===============================
+ * MegaRAID SAS driver definitions
+ * ===============================
+ */
+#define MEGASAS_MAX_PD_CHANNELS			2
+#define MEGASAS_MAX_LD_CHANNELS			2
+#define MEGASAS_MAX_CHANNELS			(MEGASAS_MAX_PD_CHANNELS + \
+						MEGASAS_MAX_LD_CHANNELS)
+#define MEGASAS_MAX_DEV_PER_CHANNEL		128
+#define MEGASAS_DEFAULT_INIT_ID			-1
+#define MEGASAS_MAX_LUN				8
+#define MEGASAS_MAX_LD				64
+
+/*
+ * When SCSI mid-layer calls driver's reset routine, driver waits for
+ * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note
+ * that the driver cannot _actually_ abort or reset pending commands. While
+ * it is waiting for the commands to complete, it prints a diagnostic message
+ * every MEGASAS_RESET_NOTICE_INTERVAL seconds
+ */
+#define MEGASAS_RESET_WAIT_TIME			180
+#define	MEGASAS_RESET_NOTICE_INTERVAL		5
+
+#define MEGASAS_IOCTL_CMD			0
+
+/*
+ * FW reports the maximum of number of commands that it can accept (maximum
+ * commands that can be outstanding) at any time. The driver must report a
+ * lower number to the mid layer because it can issue a few internal commands
+ * itself (E.g, AEN, abort cmd, IOCTLs etc). The number of commands it needs
+ * is shown below
+ */
+#define MEGASAS_INT_CMDS			32
+
+/*
+ * FW can accept both 32 and 64 bit SGLs. We want to allocate 32/64 bit
+ * SGLs based on the size of dma_addr_t
+ */
+#define IS_DMA64				(sizeof(dma_addr_t) == 8)
+
+#define MFI_OB_INTR_STATUS_MASK			0x00000002
+#define MFI_POLL_TIMEOUT_SECS			10
+
+struct megasas_register_set {
+
+	u32 reserved_0[4];	/*0000h */
+
+	u32 inbound_msg_0;	/*0010h */
+	u32 inbound_msg_1;	/*0014h */
+	u32 outbound_msg_0;	/*0018h */
+	u32 outbound_msg_1;	/*001Ch */
+
+	u32 inbound_doorbell;	/*0020h */
+	u32 inbound_intr_status;	/*0024h */
+	u32 inbound_intr_mask;	/*0028h */
+
+	u32 outbound_doorbell;	/*002Ch */
+	u32 outbound_intr_status;	/*0030h */
+	u32 outbound_intr_mask;	/*0034h */
+
+	u32 reserved_1[2];	/*0038h */
+
+	u32 inbound_queue_port;	/*0040h */
+	u32 outbound_queue_port;	/*0044h */
+
+	u32 reserved_2;		/*004Ch */
+
+	u32 index_registers[1004];	/*0050h */
+
+} __attribute__ ((packed));
+
+struct megasas_sge32 {
+
+	u32 phys_addr;
+	u32 length;
+
+} __attribute__ ((packed));
+
+struct megasas_sge64 {
+
+	u64 phys_addr;
+	u32 length;
+
+} __attribute__ ((packed));
+
+union megasas_sgl {
+
+	struct megasas_sge32 sge32[1];
+	struct megasas_sge64 sge64[1];
+
+} __attribute__ ((packed));
+
+struct megasas_header {
+
+	u8 cmd;			/*00h */
+	u8 sense_len;		/*01h */
+	u8 cmd_status;		/*02h */
+	u8 scsi_status;		/*03h */
+
+	u8 target_id;		/*04h */
+	u8 lun;			/*05h */
+	u8 cdb_len;		/*06h */
+	u8 sge_count;		/*07h */
+
+	u32 context;		/*08h */
+	u32 pad_0;		/*0Ch */
+
+	u16 flags;		/*10h */
+	u16 timeout;		/*12h */
+	u32 data_xferlen;	/*14h */
+
+} __attribute__ ((packed));
+
+union megasas_sgl_frame {
+
+	struct megasas_sge32 sge32[8];
+	struct megasas_sge64 sge64[5];
+
+} __attribute__ ((packed));
+
+struct megasas_init_frame {
+
+	u8 cmd;			/*00h */
+	u8 reserved_0;		/*01h */
+	u8 cmd_status;		/*02h */
+
+	u8 reserved_1;		/*03h */
+	u32 reserved_2;		/*04h */
+
+	u32 context;		/*08h */
+	u32 pad_0;		/*0Ch */
+
+	u16 flags;		/*10h */
+	u16 reserved_3;		/*12h */
+	u32 data_xfer_len;	/*14h */
+
+	u32 queue_info_new_phys_addr_lo;	/*18h */
+	u32 queue_info_new_phys_addr_hi;	/*1Ch */
+	u32 queue_info_old_phys_addr_lo;	/*20h */
+	u32 queue_info_old_phys_addr_hi;	/*24h */
+
+	u32 reserved_4[6];	/*28h */
+
+} __attribute__ ((packed));
+
+struct megasas_init_queue_info {
+
+	u32 init_flags;		/*00h */
+	u32 reply_queue_entries;	/*04h */
+
+	u32 reply_queue_start_phys_addr_lo;	/*08h */
+	u32 reply_queue_start_phys_addr_hi;	/*0Ch */
+	u32 producer_index_phys_addr_lo;	/*10h */
+	u32 producer_index_phys_addr_hi;	/*14h */
+	u32 consumer_index_phys_addr_lo;	/*18h */
+	u32 consumer_index_phys_addr_hi;	/*1Ch */
+
+} __attribute__ ((packed));
+
+struct megasas_io_frame {
+
+	u8 cmd;			/*00h */
+	u8 sense_len;		/*01h */
+	u8 cmd_status;		/*02h */
+	u8 scsi_status;		/*03h */
+
+	u8 target_id;		/*04h */
+	u8 access_byte;		/*05h */
+	u8 reserved_0;		/*06h */
+	u8 sge_count;		/*07h */
+
+	u32 context;		/*08h */
+	u32 pad_0;		/*0Ch */
+
+	u16 flags;		/*10h */
+	u16 timeout;		/*12h */
+	u32 lba_count;		/*14h */
+
+	u32 sense_buf_phys_addr_lo;	/*18h */
+	u32 sense_buf_phys_addr_hi;	/*1Ch */
+
+	u32 start_lba_lo;	/*20h */
+	u32 start_lba_hi;	/*24h */
+
+	union megasas_sgl sgl;	/*28h */
+
+} __attribute__ ((packed));
+
+struct megasas_pthru_frame {
+
+	u8 cmd;			/*00h */
+	u8 sense_len;		/*01h */
+	u8 cmd_status;		/*02h */
+	u8 scsi_status;		/*03h */
+
+	u8 target_id;		/*04h */
+	u8 lun;			/*05h */
+	u8 cdb_len;		/*06h */
+	u8 sge_count;		/*07h */
+
+	u32 context;		/*08h */
+	u32 pad_0;		/*0Ch */
+
+	u16 flags;		/*10h */
+	u16 timeout;		/*12h */
+	u32 data_xfer_len;	/*14h */
+
+	u32 sense_buf_phys_addr_lo;	/*18h */
+	u32 sense_buf_phys_addr_hi;	/*1Ch */
+
+	u8 cdb[16];		/*20h */
+	union megasas_sgl sgl;	/*30h */
+
+} __attribute__ ((packed));
+
+struct megasas_dcmd_frame {
+
+	u8 cmd;			/*00h */
+	u8 reserved_0;		/*01h */
+	u8 cmd_status;		/*02h */
+	u8 reserved_1[4];	/*03h */
+	u8 sge_count;		/*07h */
+
+	u32 context;		/*08h */
+	u32 pad_0;		/*0Ch */
+
+	u16 flags;		/*10h */
+	u16 timeout;		/*12h */
+
+	u32 data_xfer_len;	/*14h */
+	u32 opcode;		/*18h */
+
+	union {			/*1Ch */
+		u8 b[12];
+		u16 s[6];
+		u32 w[3];
+	} mbox;
+
+	union megasas_sgl sgl;	/*28h */
+
+} __attribute__ ((packed));
+
+struct megasas_abort_frame {
+
+	u8 cmd;			/*00h */
+	u8 reserved_0;		/*01h */
+	u8 cmd_status;		/*02h */
+
+	u8 reserved_1;		/*03h */
+	u32 reserved_2;		/*04h */
+
+	u32 context;		/*08h */
+	u32 pad_0;		/*0Ch */
+
+	u16 flags;		/*10h */
+	u16 reserved_3;		/*12h */
+	u32 reserved_4;		/*14h */
+
+	u32 abort_context;	/*18h */
+	u32 pad_1;		/*1Ch */
+
+	u32 abort_mfi_phys_addr_lo;	/*20h */
+	u32 abort_mfi_phys_addr_hi;	/*24h */
+
+	u32 reserved_5[6];	/*28h */
+
+} __attribute__ ((packed));
+
+struct megasas_smp_frame {
+
+	u8 cmd;			/*00h */
+	u8 reserved_1;		/*01h */
+	u8 cmd_status;		/*02h */
+	u8 connection_status;	/*03h */
+
+	u8 reserved_2[3];	/*04h */
+	u8 sge_count;		/*07h */
+
+	u32 context;		/*08h */
+	u32 pad_0;		/*0Ch */
+
+	u16 flags;		/*10h */
+	u16 timeout;		/*12h */
+
+	u32 data_xfer_len;	/*14h */
+	u64 sas_addr;		/*18h */
+
+	union {
+		struct megasas_sge32 sge32[2];	/* [0]: resp [1]: req */
+		struct megasas_sge64 sge64[2];	/* [0]: resp [1]: req */
+	} sgl;
+
+} __attribute__ ((packed));
+
+struct megasas_stp_frame {
+
+	u8 cmd;			/*00h */
+	u8 reserved_1;		/*01h */
+	u8 cmd_status;		/*02h */
+	u8 reserved_2;		/*03h */
+
+	u8 target_id;		/*04h */
+	u8 reserved_3[2];	/*05h */
+	u8 sge_count;		/*07h */
+
+	u32 context;		/*08h */
+	u32 pad_0;		/*0Ch */
+
+	u16 flags;		/*10h */
+	u16 timeout;		/*12h */
+
+	u32 data_xfer_len;	/*14h */
+
+	u16 fis[10];		/*18h */
+	u32 stp_flags;
+
+	union {
+		struct megasas_sge32 sge32[2];	/* [0]: resp [1]: data */
+		struct megasas_sge64 sge64[2];	/* [0]: resp [1]: data */
+	} sgl;
+
+} __attribute__ ((packed));
+
+union megasas_frame {
+
+	struct megasas_header hdr;
+	struct megasas_init_frame init;
+	struct megasas_io_frame io;
+	struct megasas_pthru_frame pthru;
+	struct megasas_dcmd_frame dcmd;
+	struct megasas_abort_frame abort;
+	struct megasas_smp_frame smp;
+	struct megasas_stp_frame stp;
+
+	u8 raw_bytes[64];
+};
+
+struct megasas_cmd;
+
+union megasas_evt_class_locale {
+
+	struct {
+		u16 locale;
+		u8 reserved;
+		s8 class;
+	} __attribute__ ((packed)) members;
+
+	u32 word;
+
+} __attribute__ ((packed));
+
+struct megasas_evt_log_info {
+	u32 newest_seq_num;
+	u32 oldest_seq_num;
+	u32 clear_seq_num;
+	u32 shutdown_seq_num;
+	u32 boot_seq_num;
+
+} __attribute__ ((packed));
+
+struct megasas_progress {
+
+	u16 progress;
+	u16 elapsed_seconds;
+
+} __attribute__ ((packed));
+
+struct megasas_evtarg_ld {
+
+	u16 target_id;
+	u8 ld_index;
+	u8 reserved;
+
+} __attribute__ ((packed));
+
+struct megasas_evtarg_pd {
+	u16 device_id;
+	u8 encl_index;
+	u8 slot_number;
+
+} __attribute__ ((packed));
+
+struct megasas_evt_detail {
+
+	u32 seq_num;
+	u32 time_stamp;
+	u32 code;
+	union megasas_evt_class_locale cl;
+	u8 arg_type;
+	u8 reserved1[15];
+
+	union {
+		struct {
+			struct megasas_evtarg_pd pd;
+			u8 cdb_length;
+			u8 sense_length;
+			u8 reserved[2];
+			u8 cdb[16];
+			u8 sense[64];
+		} __attribute__ ((packed)) cdbSense;
+
+		struct megasas_evtarg_ld ld;
+
+		struct {
+			struct megasas_evtarg_ld ld;
+			u64 count;
+		} __attribute__ ((packed)) ld_count;
+
+		struct {
+			u64 lba;
+			struct megasas_evtarg_ld ld;
+		} __attribute__ ((packed)) ld_lba;
+
+		struct {
+			struct megasas_evtarg_ld ld;
+			u32 prevOwner;
+			u32 newOwner;
+		} __attribute__ ((packed)) ld_owner;
+
+		struct {
+			u64 ld_lba;
+			u64 pd_lba;
+			struct megasas_evtarg_ld ld;
+			struct megasas_evtarg_pd pd;
+		} __attribute__ ((packed)) ld_lba_pd_lba;
+
+		struct {
+			struct megasas_evtarg_ld ld;
+			struct megasas_progress prog;
+		} __attribute__ ((packed)) ld_prog;
+
+		struct {
+			struct megasas_evtarg_ld ld;
+			u32 prev_state;
+			u32 new_state;
+		} __attribute__ ((packed)) ld_state;
+
+		struct {
+			u64 strip;
+			struct megasas_evtarg_ld ld;
+		} __attribute__ ((packed)) ld_strip;
+
+		struct megasas_evtarg_pd pd;
+
+		struct {
+			struct megasas_evtarg_pd pd;
+			u32 err;
+		} __attribute__ ((packed)) pd_err;
+
+		struct {
+			u64 lba;
+			struct megasas_evtarg_pd pd;
+		} __attribute__ ((packed)) pd_lba;
+
+		struct {
+			u64 lba;
+			struct megasas_evtarg_pd pd;
+			struct megasas_evtarg_ld ld;
+		} __attribute__ ((packed)) pd_lba_ld;
+
+		struct {
+			struct megasas_evtarg_pd pd;
+			struct megasas_progress prog;
+		} __attribute__ ((packed)) pd_prog;
+
+		struct {
+			struct megasas_evtarg_pd pd;
+			u32 prevState;
+			u32 newState;
+		} __attribute__ ((packed)) pd_state;
+
+		struct {
+			u16 vendorId;
+			u16 deviceId;
+			u16 subVendorId;
+			u16 subDeviceId;
+		} __attribute__ ((packed)) pci;
+
+		u32 rate;
+		char str[96];
+
+		struct {
+			u32 rtc;
+			u32 elapsedSeconds;
+		} __attribute__ ((packed)) time;
+
+		struct {
+			u32 ecar;
+			u32 elog;
+			char str[64];
+		} __attribute__ ((packed)) ecc;
+
+		u8 b[96];
+		u16 s[48];
+		u32 w[24];
+		u64 d[12];
+	} args;
+
+	char description[128];
+
+} __attribute__ ((packed));
+
+struct megasas_instance {
+
+	u32 *producer;
+	dma_addr_t producer_h;
+	u32 *consumer;
+	dma_addr_t consumer_h;
+
+	u32 *reply_queue;
+	dma_addr_t reply_queue_h;
+
+	unsigned long base_addr;
+	struct megasas_register_set __iomem *reg_set;
+
+	s8 init_id;
+	u8 reserved[3];
+
+	u16 max_num_sge;
+	u16 max_fw_cmds;
+	u32 max_sectors_per_req;
+
+	struct megasas_cmd **cmd_list;
+	struct list_head cmd_pool;
+	spinlock_t cmd_pool_lock;
+	struct dma_pool *frame_dma_pool;
+	struct dma_pool *sense_dma_pool;
+
+	struct megasas_evt_detail *evt_detail;
+	dma_addr_t evt_detail_h;
+	struct megasas_cmd *aen_cmd;
+	struct semaphore aen_mutex;
+	struct semaphore ioctl_sem;
+
+	struct Scsi_Host *host;
+
+	wait_queue_head_t int_cmd_wait_q;
+	wait_queue_head_t abort_cmd_wait_q;
+
+	struct pci_dev *pdev;
+	u32 unique_id;
+
+	u32 fw_outstanding;
+	u32 hw_crit_error;
+	spinlock_t instance_lock;
+};
+
+#define MEGASAS_IS_LOGICAL(scp)						\
+	(scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1
+
+#define MEGASAS_DEV_INDEX(inst, scp)					\
+	((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + 	\
+	scp->device->id
+
+struct megasas_cmd {
+
+	union megasas_frame *frame;
+	dma_addr_t frame_phys_addr;
+	u8 *sense;
+	dma_addr_t sense_phys_addr;
+
+	u32 index;
+	u8 sync_cmd;
+	u8 cmd_status;
+	u16 abort_aen;
+
+	struct list_head list;
+	struct scsi_cmnd *scmd;
+	struct megasas_instance *instance;
+	u32 frame_count;
+};
+
+#define MAX_MGMT_ADAPTERS		1024
+#define MAX_IOCTL_SGE			16
+
+struct megasas_iocpacket {
+
+	u16 host_no;
+	u16 __pad1;
+	u32 sgl_off;
+	u32 sge_count;
+	u32 sense_off;
+	u32 sense_len;
+	union {
+		u8 raw[128];
+		struct megasas_header hdr;
+	} frame;
+
+	struct iovec sgl[MAX_IOCTL_SGE];
+
+} __attribute__ ((packed));
+
+struct megasas_aen {
+	u16 host_no;
+	u16 __pad1;
+	u32 seq_num;
+	u32 class_locale_word;
+} __attribute__ ((packed));
+
+#ifdef CONFIG_COMPAT
+struct compat_megasas_iocpacket {
+	u16 host_no;
+	u16 __pad1;
+	u32 sgl_off;
+	u32 sge_count;
+	u32 sense_off;
+	u32 sense_len;
+	union {
+		u8 raw[128];
+		struct megasas_header hdr;
+	} frame;
+	struct compat_iovec sgl[MAX_IOCTL_SGE];
+} __attribute__ ((packed));
+
+#define MEGASAS_IOC_FIRMWARE	_IOWR('M', 1, struct compat_megasas_iocpacket)
+#else
+#define MEGASAS_IOC_FIRMWARE	_IOWR('M', 1, struct megasas_iocpacket)
+#endif
+
+#define MEGASAS_IOC_GET_AEN	_IOW('M', 3, struct megasas_aen)
+
+struct megasas_mgmt_info {
+
+	u16 count;
+	struct megasas_instance *instance[MAX_MGMT_ADAPTERS];
+	int max_index;
+};
+
+#endif				/*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/qla2xxx/qla_rscn.c b/drivers/scsi/qla2xxx/qla_rscn.c
index bdc3bc7..1eba988 100644
--- a/drivers/scsi/qla2xxx/qla_rscn.c
+++ b/drivers/scsi/qla2xxx/qla_rscn.c
@@ -330,6 +330,8 @@
 	fcport->flags &= ~FCF_FAILOVER_NEEDED;
 	fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
 	atomic_set(&fcport->state, FCS_ONLINE);
+	if (fcport->rport)
+		fc_remote_port_unblock(fcport->rport);
 }
 
 
diff --git a/drivers/scsi/sata_mv.c b/drivers/scsi/sata_mv.c
index b8f1f69..e721403 100644
--- a/drivers/scsi/sata_mv.c
+++ b/drivers/scsi/sata_mv.c
@@ -35,7 +35,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME	"sata_mv"
-#define DRV_VERSION	"0.12"
+#define DRV_VERSION	"0.24"
 
 enum {
 	/* BAR's are enumerated in terms of pci_resource_start() terms */
@@ -55,31 +55,62 @@
 	MV_SATAHC_ARBTR_REG_SZ	= MV_MINOR_REG_AREA_SZ,		/* arbiter */
 	MV_PORT_REG_SZ		= MV_MINOR_REG_AREA_SZ,
 
-	MV_Q_CT			= 32,
-	MV_CRQB_SZ		= 32,
-	MV_CRPB_SZ		= 8,
+	MV_USE_Q_DEPTH		= ATA_DEF_QUEUE,
 
-	MV_DMA_BOUNDARY		= 0xffffffffU,
-	SATAHC_MASK		= (~(MV_SATAHC_REG_SZ - 1)),
+	MV_MAX_Q_DEPTH		= 32,
+	MV_MAX_Q_DEPTH_MASK	= MV_MAX_Q_DEPTH - 1,
+
+	/* CRQB needs alignment on a 1KB boundary. Size == 1KB
+	 * CRPB needs alignment on a 256B boundary. Size == 256B
+	 * SG count of 176 leads to MV_PORT_PRIV_DMA_SZ == 4KB
+	 * ePRD (SG) entries need alignment on a 16B boundary. Size == 16B
+	 */
+	MV_CRQB_Q_SZ		= (32 * MV_MAX_Q_DEPTH),
+	MV_CRPB_Q_SZ		= (8 * MV_MAX_Q_DEPTH),
+	MV_MAX_SG_CT		= 176,
+	MV_SG_TBL_SZ		= (16 * MV_MAX_SG_CT),
+	MV_PORT_PRIV_DMA_SZ	= (MV_CRQB_Q_SZ + MV_CRPB_Q_SZ + MV_SG_TBL_SZ),
+
+	/* Our DMA boundary is determined by an ePRD being unable to handle
+	 * anything larger than 64KB
+	 */
+	MV_DMA_BOUNDARY		= 0xffffU,
 
 	MV_PORTS_PER_HC		= 4,
 	/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
 	MV_PORT_HC_SHIFT	= 2,
-	/* == (port % MV_PORTS_PER_HC) to determine port from 0-7 port */
+	/* == (port % MV_PORTS_PER_HC) to determine hard port from 0-7 port */
 	MV_PORT_MASK		= 3,
 
 	/* Host Flags */
 	MV_FLAG_DUAL_HC		= (1 << 30),  /* two SATA Host Controllers */
 	MV_FLAG_IRQ_COALESCE	= (1 << 29),  /* IRQ coalescing capability */
-	MV_FLAG_BDMA		= (1 << 28),  /* Basic DMA */
+	MV_FLAG_GLBL_SFT_RST	= (1 << 28),  /* Global Soft Reset support */
+	MV_COMMON_FLAGS		= (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				   ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+				   ATA_FLAG_PIO_POLLING),
+	MV_6XXX_FLAGS		= (MV_FLAG_IRQ_COALESCE | 
+				   MV_FLAG_GLBL_SFT_RST),
 
 	chip_504x		= 0,
 	chip_508x		= 1,
 	chip_604x		= 2,
 	chip_608x		= 3,
 
+	CRQB_FLAG_READ		= (1 << 0),
+	CRQB_TAG_SHIFT		= 1,
+	CRQB_CMD_ADDR_SHIFT	= 8,
+	CRQB_CMD_CS		= (0x2 << 11),
+	CRQB_CMD_LAST		= (1 << 15),
+
+	CRPB_FLAG_STATUS_SHIFT	= 8,
+
+	EPRD_FLAG_END_OF_TBL	= (1 << 31),
+
 	/* PCI interface registers */
 
+	PCI_COMMAND_OFS		= 0xc00,
+
 	PCI_MAIN_CMD_STS_OFS	= 0xd30,
 	STOP_PCI_MASTER		= (1 << 2),
 	PCI_MASTER_EMPTY	= (1 << 3),
@@ -111,20 +142,13 @@
 	HC_CFG_OFS		= 0,
 
 	HC_IRQ_CAUSE_OFS	= 0x14,
-	CRBP_DMA_DONE		= (1 << 0),	/* shift by port # */
+	CRPB_DMA_DONE		= (1 << 0),	/* shift by port # */
 	HC_IRQ_COAL		= (1 << 4),	/* IRQ coalescing */
 	DEV_IRQ			= (1 << 8),	/* shift by port # */
 
 	/* Shadow block registers */
-	SHD_PIO_DATA_OFS	= 0x100,
-	SHD_FEA_ERR_OFS		= 0x104,
-	SHD_SECT_CNT_OFS	= 0x108,
-	SHD_LBA_L_OFS		= 0x10C,
-	SHD_LBA_M_OFS		= 0x110,
-	SHD_LBA_H_OFS		= 0x114,
-	SHD_DEV_HD_OFS		= 0x118,
-	SHD_CMD_STA_OFS		= 0x11C,
-	SHD_CTL_AST_OFS		= 0x120,
+	SHD_BLK_OFS		= 0x100,
+	SHD_CTL_AST_OFS		= 0x20,		/* ofs from SHD_BLK_OFS */
 
 	/* SATA registers */
 	SATA_STATUS_OFS		= 0x300,  /* ctrl, err regs follow status */
@@ -132,6 +156,11 @@
 
 	/* Port registers */
 	EDMA_CFG_OFS		= 0,
+	EDMA_CFG_Q_DEPTH	= 0,			/* queueing disabled */
+	EDMA_CFG_NCQ		= (1 << 5),
+	EDMA_CFG_NCQ_GO_ON_ERR	= (1 << 14),		/* continue on error */
+	EDMA_CFG_RD_BRST_EXT	= (1 << 11),		/* read burst 512B */
+	EDMA_CFG_WR_BUFF_LEN	= (1 << 13),		/* write buffer 512B */
 
 	EDMA_ERR_IRQ_CAUSE_OFS	= 0x8,
 	EDMA_ERR_IRQ_MASK_OFS	= 0xc,
@@ -161,33 +190,85 @@
 				   EDMA_ERR_LNK_DATA_TX | 
 				   EDMA_ERR_TRANS_PROTO),
 
+	EDMA_REQ_Q_BASE_HI_OFS	= 0x10,
+	EDMA_REQ_Q_IN_PTR_OFS	= 0x14,		/* also contains BASE_LO */
+	EDMA_REQ_Q_BASE_LO_MASK	= 0xfffffc00U,
+
+	EDMA_REQ_Q_OUT_PTR_OFS	= 0x18,
+	EDMA_REQ_Q_PTR_SHIFT	= 5,
+
+	EDMA_RSP_Q_BASE_HI_OFS	= 0x1c,
+	EDMA_RSP_Q_IN_PTR_OFS	= 0x20,
+	EDMA_RSP_Q_OUT_PTR_OFS	= 0x24,		/* also contains BASE_LO */
+	EDMA_RSP_Q_BASE_LO_MASK	= 0xffffff00U,
+	EDMA_RSP_Q_PTR_SHIFT	= 3,
+
 	EDMA_CMD_OFS		= 0x28,
 	EDMA_EN			= (1 << 0),
 	EDMA_DS			= (1 << 1),
 	ATA_RST			= (1 << 2),
 
-	/* BDMA is 6xxx part only */
-	BDMA_CMD_OFS		= 0x224,
-	BDMA_START		= (1 << 0),
+	/* Host private flags (hp_flags) */
+	MV_HP_FLAG_MSI		= (1 << 0),
 
-	MV_UNDEF		= 0,
+	/* Port private flags (pp_flags) */
+	MV_PP_FLAG_EDMA_EN	= (1 << 0),
+	MV_PP_FLAG_EDMA_DS_ACT	= (1 << 1),
+};
+
+/* Command ReQuest Block: 32B */
+struct mv_crqb {
+	u32			sg_addr;
+	u32			sg_addr_hi;
+	u16			ctrl_flags;
+	u16			ata_cmd[11];
+};
+
+/* Command ResPonse Block: 8B */
+struct mv_crpb {
+	u16			id;
+	u16			flags;
+	u32			tmstmp;
+};
+
+/* EDMA Physical Region Descriptor (ePRD); A.K.A. SG */
+struct mv_sg {
+	u32			addr;
+	u32			flags_size;
+	u32			addr_hi;
+	u32			reserved;
 };
 
 struct mv_port_priv {
+	struct mv_crqb		*crqb;
+	dma_addr_t		crqb_dma;
+	struct mv_crpb		*crpb;
+	dma_addr_t		crpb_dma;
+	struct mv_sg		*sg_tbl;
+	dma_addr_t		sg_tbl_dma;
 
+	unsigned		req_producer;		/* cp of req_in_ptr */
+	unsigned		rsp_consumer;		/* cp of rsp_out_ptr */
+	u32			pp_flags;
 };
 
 struct mv_host_priv {
-
+	u32			hp_flags;
 };
 
 static void mv_irq_clear(struct ata_port *ap);
 static u32 mv_scr_read(struct ata_port *ap, unsigned int sc_reg_in);
 static void mv_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
+static u8 mv_check_err(struct ata_port *ap);
 static void mv_phy_reset(struct ata_port *ap);
-static int mv_master_reset(void __iomem *mmio_base);
+static void mv_host_stop(struct ata_host_set *host_set);
+static int mv_port_start(struct ata_port *ap);
+static void mv_port_stop(struct ata_port *ap);
+static void mv_qc_prep(struct ata_queued_cmd *qc);
+static int mv_qc_issue(struct ata_queued_cmd *qc);
 static irqreturn_t mv_interrupt(int irq, void *dev_instance,
 				struct pt_regs *regs);
+static void mv_eng_timeout(struct ata_port *ap);
 static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
 
 static Scsi_Host_Template mv_sht = {
@@ -196,13 +277,13 @@
 	.ioctl			= ata_scsi_ioctl,
 	.queuecommand		= ata_scsi_queuecmd,
 	.eh_strategy_handler	= ata_scsi_error,
-	.can_queue		= ATA_DEF_QUEUE,
+	.can_queue		= MV_USE_Q_DEPTH,
 	.this_id		= ATA_SHT_THIS_ID,
-	.sg_tablesize		= MV_UNDEF,
+	.sg_tablesize		= MV_MAX_SG_CT,
 	.max_sectors		= ATA_MAX_SECTORS,
 	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
 	.emulated		= ATA_SHT_EMULATED,
-	.use_clustering		= MV_UNDEF,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
 	.proc_name		= DRV_NAME,
 	.dma_boundary		= MV_DMA_BOUNDARY,
 	.slave_configure	= ata_scsi_slave_config,
@@ -216,15 +297,16 @@
 	.tf_load		= ata_tf_load,
 	.tf_read		= ata_tf_read,
 	.check_status		= ata_check_status,
+	.check_err		= mv_check_err,
 	.exec_command		= ata_exec_command,
 	.dev_select		= ata_std_dev_select,
 
 	.phy_reset		= mv_phy_reset,
 
-	.qc_prep		= ata_qc_prep,
-	.qc_issue		= ata_qc_issue_prot,
+	.qc_prep		= mv_qc_prep,
+	.qc_issue		= mv_qc_issue,
 
-	.eng_timeout		= ata_eng_timeout,
+	.eng_timeout		= mv_eng_timeout,
 
 	.irq_handler		= mv_interrupt,
 	.irq_clear		= mv_irq_clear,
@@ -232,49 +314,39 @@
 	.scr_read		= mv_scr_read,
 	.scr_write		= mv_scr_write,
 
-	.port_start		= ata_port_start,
-	.port_stop		= ata_port_stop,
-	.host_stop		= ata_host_stop,
+	.port_start		= mv_port_start,
+	.port_stop		= mv_port_stop,
+	.host_stop		= mv_host_stop,
 };
 
 static struct ata_port_info mv_port_info[] = {
 	{  /* chip_504x */
 		.sht		= &mv_sht,
-		.host_flags	= (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				   ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
-				   ATA_FLAG_PIO_POLLING),
-		.pio_mask	= 0x1f,	/* pio4-0 */
-		.udma_mask	= 0,	/* 0x7f (udma6-0 disabled for now) */
+		.host_flags	= MV_COMMON_FLAGS,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.udma_mask	= 0,	/* 0x7f (udma0-6 disabled for now) */
 		.port_ops	= &mv_ops,
 	},
 	{  /* chip_508x */
 		.sht		= &mv_sht,
-		.host_flags	= (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				   ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | 
-				   ATA_FLAG_PIO_POLLING | MV_FLAG_DUAL_HC),
-		.pio_mask	= 0x1f,	/* pio4-0 */
-		.udma_mask	= 0,	/* 0x7f (udma6-0 disabled for now) */
+		.host_flags	= (MV_COMMON_FLAGS | MV_FLAG_DUAL_HC),
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.udma_mask	= 0,	/* 0x7f (udma0-6 disabled for now) */
 		.port_ops	= &mv_ops,
 	},
 	{  /* chip_604x */
 		.sht		= &mv_sht,
-		.host_flags	= (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				   ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | 
-				   ATA_FLAG_PIO_POLLING |
-				   MV_FLAG_IRQ_COALESCE | MV_FLAG_BDMA),
-		.pio_mask	= 0x1f,	/* pio4-0 */
-		.udma_mask	= 0,	/* 0x7f (udma6-0 disabled for now) */
+		.host_flags	= (MV_COMMON_FLAGS | MV_6XXX_FLAGS),
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
 		.port_ops	= &mv_ops,
 	},
 	{  /* chip_608x */
 		.sht		= &mv_sht,
-		.host_flags	= (ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
-				   ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
-				   ATA_FLAG_PIO_POLLING |
-				   MV_FLAG_IRQ_COALESCE | MV_FLAG_DUAL_HC |
-				   MV_FLAG_BDMA),
-		.pio_mask	= 0x1f,	/* pio4-0 */
-		.udma_mask	= 0,	/* 0x7f (udma6-0 disabled for now) */
+		.host_flags	= (MV_COMMON_FLAGS | MV_6XXX_FLAGS | 
+				   MV_FLAG_DUAL_HC),
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
 		.port_ops	= &mv_ops,
 	},
 };
@@ -309,12 +381,6 @@
 	(void) readl(addr);	/* flush to avoid PCI posted write */
 }
 
-static inline void __iomem *mv_port_addr_to_hc_base(void __iomem *port_mmio)
-{
-	return ((void __iomem *)((unsigned long)port_mmio & 
-				 (unsigned long)SATAHC_MASK));
-}
-
 static inline void __iomem *mv_hc_base(void __iomem *base, unsigned int hc)
 {
 	return (base + MV_SATAHC0_REG_BASE + (hc * MV_SATAHC_REG_SZ));
@@ -332,26 +398,152 @@
 	return mv_port_base(ap->host_set->mmio_base, ap->port_no);
 }
 
-static inline int mv_get_hc_count(unsigned long flags)
+static inline int mv_get_hc_count(unsigned long hp_flags)
 {
-	return ((flags & MV_FLAG_DUAL_HC) ? 2 : 1);
-}
-
-static inline int mv_is_edma_active(struct ata_port *ap)
-{
-	void __iomem *port_mmio = mv_ap_base(ap);
-	return (EDMA_EN & readl(port_mmio + EDMA_CMD_OFS));
-}
-
-static inline int mv_port_bdma_capable(struct ata_port *ap)
-{
-	return (ap->flags & MV_FLAG_BDMA);
+	return ((hp_flags & MV_FLAG_DUAL_HC) ? 2 : 1);
 }
 
 static void mv_irq_clear(struct ata_port *ap)
 {
 }
 
+/**
+ *      mv_start_dma - Enable eDMA engine
+ *      @base: port base address
+ *      @pp: port private data
+ *
+ *      Verify the local cache of the eDMA state is accurate with an
+ *      assert.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static void mv_start_dma(void __iomem *base, struct mv_port_priv *pp)
+{
+	if (!(MV_PP_FLAG_EDMA_EN & pp->pp_flags)) {
+		writelfl(EDMA_EN, base + EDMA_CMD_OFS);
+		pp->pp_flags |= MV_PP_FLAG_EDMA_EN;
+	}
+	assert(EDMA_EN & readl(base + EDMA_CMD_OFS));
+}
+
+/**
+ *      mv_stop_dma - Disable eDMA engine
+ *      @ap: ATA channel to manipulate
+ *
+ *      Verify the local cache of the eDMA state is accurate with an
+ *      assert.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static void mv_stop_dma(struct ata_port *ap)
+{
+	void __iomem *port_mmio = mv_ap_base(ap);
+	struct mv_port_priv *pp	= ap->private_data;
+	u32 reg;
+	int i;
+
+	if (MV_PP_FLAG_EDMA_EN & pp->pp_flags) {
+		/* Disable EDMA if active.   The disable bit auto clears.
+		 */
+		writelfl(EDMA_DS, port_mmio + EDMA_CMD_OFS);
+		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+	} else {
+		assert(!(EDMA_EN & readl(port_mmio + EDMA_CMD_OFS)));
+  	}
+	
+	/* now properly wait for the eDMA to stop */
+	for (i = 1000; i > 0; i--) {
+		reg = readl(port_mmio + EDMA_CMD_OFS);
+		if (!(EDMA_EN & reg)) {
+			break;
+		}
+		udelay(100);
+	}
+
+	if (EDMA_EN & reg) {
+		printk(KERN_ERR "ata%u: Unable to stop eDMA\n", ap->id);
+		/* FIXME: Consider doing a reset here to recover */
+	}
+}
+
+#ifdef ATA_DEBUG
+static void mv_dump_mem(void __iomem *start, unsigned bytes)
+{
+	int b, w;
+	for (b = 0; b < bytes; ) {
+		DPRINTK("%p: ", start + b);
+		for (w = 0; b < bytes && w < 4; w++) {
+			printk("%08x ",readl(start + b));
+			b += sizeof(u32);
+		}
+		printk("\n");
+	}
+}
+#endif
+
+static void mv_dump_pci_cfg(struct pci_dev *pdev, unsigned bytes)
+{
+#ifdef ATA_DEBUG
+	int b, w;
+	u32 dw;
+	for (b = 0; b < bytes; ) {
+		DPRINTK("%02x: ", b);
+		for (w = 0; b < bytes && w < 4; w++) {
+			(void) pci_read_config_dword(pdev,b,&dw);
+			printk("%08x ",dw);
+			b += sizeof(u32);
+		}
+		printk("\n");
+	}
+#endif
+}
+static void mv_dump_all_regs(void __iomem *mmio_base, int port,
+			     struct pci_dev *pdev)
+{
+#ifdef ATA_DEBUG
+	void __iomem *hc_base = mv_hc_base(mmio_base, 
+					   port >> MV_PORT_HC_SHIFT);
+	void __iomem *port_base;
+	int start_port, num_ports, p, start_hc, num_hcs, hc;
+
+	if (0 > port) {
+		start_hc = start_port = 0;
+		num_ports = 8;		/* shld be benign for 4 port devs */
+		num_hcs = 2;
+	} else {
+		start_hc = port >> MV_PORT_HC_SHIFT;
+		start_port = port;
+		num_ports = num_hcs = 1;
+	}
+	DPRINTK("All registers for port(s) %u-%u:\n", start_port, 
+		num_ports > 1 ? num_ports - 1 : start_port);
+
+	if (NULL != pdev) {
+		DPRINTK("PCI config space regs:\n");
+		mv_dump_pci_cfg(pdev, 0x68);
+	}
+	DPRINTK("PCI regs:\n");
+	mv_dump_mem(mmio_base+0xc00, 0x3c);
+	mv_dump_mem(mmio_base+0xd00, 0x34);
+	mv_dump_mem(mmio_base+0xf00, 0x4);
+	mv_dump_mem(mmio_base+0x1d00, 0x6c);
+	for (hc = start_hc; hc < start_hc + num_hcs; hc++) {
+		hc_base = mv_hc_base(mmio_base, port >> MV_PORT_HC_SHIFT);
+		DPRINTK("HC regs (HC %i):\n", hc);
+		mv_dump_mem(hc_base, 0x1c);
+	}
+	for (p = start_port; p < start_port + num_ports; p++) {
+		port_base = mv_port_base(mmio_base, p);
+		DPRINTK("EDMA regs (port %i):\n",p);
+		mv_dump_mem(port_base, 0x54);
+		DPRINTK("SATA regs (port %i):\n",p);
+		mv_dump_mem(port_base+0x300, 0x60);
+	}
+#endif
+}
+
 static unsigned int mv_scr_offset(unsigned int sc_reg_in)
 {
 	unsigned int ofs;
@@ -392,30 +584,37 @@
 	}
 }
 
-static int mv_master_reset(void __iomem *mmio_base)
+/**
+ *      mv_global_soft_reset - Perform the 6xxx global soft reset
+ *      @mmio_base: base address of the HBA
+ *
+ *      This routine only applies to 6xxx parts.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static int mv_global_soft_reset(void __iomem *mmio_base)
 {
 	void __iomem *reg = mmio_base + PCI_MAIN_CMD_STS_OFS;
 	int i, rc = 0;
 	u32 t;
 
-	VPRINTK("ENTER\n");
-
 	/* Following procedure defined in PCI "main command and status
 	 * register" table.
 	 */
 	t = readl(reg);
 	writel(t | STOP_PCI_MASTER, reg);
 
-	for (i = 0; i < 100; i++) {
-		msleep(10);
+	for (i = 0; i < 1000; i++) {
+		udelay(1);
 		t = readl(reg);
 		if (PCI_MASTER_EMPTY & t) {
 			break;
 		}
 	}
 	if (!(PCI_MASTER_EMPTY & t)) {
-		printk(KERN_ERR DRV_NAME "PCI master won't flush\n");
-		rc = 1;		/* broken HW? */
+		printk(KERN_ERR DRV_NAME ": PCI master won't flush\n");
+		rc = 1;
 		goto done;
 	}
 
@@ -428,48 +627,411 @@
 	} while (!(GLOB_SFT_RST & t) && (i-- > 0));
 
 	if (!(GLOB_SFT_RST & t)) {
-		printk(KERN_ERR DRV_NAME "can't set global reset\n");
-		rc = 1;		/* broken HW? */
+		printk(KERN_ERR DRV_NAME ": can't set global reset\n");
+		rc = 1;
 		goto done;
 	}
 
-	/* clear reset */
+	/* clear reset and *reenable the PCI master* (not mentioned in spec) */
 	i = 5;
 	do {
-		writel(t & ~GLOB_SFT_RST, reg);
+		writel(t & ~(GLOB_SFT_RST | STOP_PCI_MASTER), reg);
 		t = readl(reg);
 		udelay(1);
 	} while ((GLOB_SFT_RST & t) && (i-- > 0));
 
 	if (GLOB_SFT_RST & t) {
-		printk(KERN_ERR DRV_NAME "can't clear global reset\n");
-		rc = 1;		/* broken HW? */
+		printk(KERN_ERR DRV_NAME ": can't clear global reset\n");
+		rc = 1;
 	}
-
- done:
-	VPRINTK("EXIT, rc = %i\n", rc);
+done:
 	return rc;
 }
 
+/**
+ *      mv_host_stop - Host specific cleanup/stop routine.
+ *      @host_set: host data structure
+ *
+ *      Disable ints, cleanup host memory, call general purpose
+ *      host_stop.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static void mv_host_stop(struct ata_host_set *host_set)
+{
+	struct mv_host_priv *hpriv = host_set->private_data;
+	struct pci_dev *pdev = to_pci_dev(host_set->dev);
+
+	if (hpriv->hp_flags & MV_HP_FLAG_MSI) {
+		pci_disable_msi(pdev);
+	} else {
+		pci_intx(pdev, 0);
+	}
+	kfree(hpriv);
+	ata_host_stop(host_set);
+}
+
+/**
+ *      mv_port_start - Port specific init/start routine.
+ *      @ap: ATA channel to manipulate
+ *
+ *      Allocate and point to DMA memory, init port private memory,
+ *      zero indices.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static int mv_port_start(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct mv_port_priv *pp;
+	void __iomem *port_mmio = mv_ap_base(ap);
+	void *mem;
+	dma_addr_t mem_dma;
+
+	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+	if (!pp) {
+		return -ENOMEM;
+	}
+	memset(pp, 0, sizeof(*pp));
+
+	mem = dma_alloc_coherent(dev, MV_PORT_PRIV_DMA_SZ, &mem_dma, 
+				 GFP_KERNEL);
+	if (!mem) {
+		kfree(pp);
+		return -ENOMEM;
+	}
+	memset(mem, 0, MV_PORT_PRIV_DMA_SZ);
+
+	/* First item in chunk of DMA memory: 
+	 * 32-slot command request table (CRQB), 32 bytes each in size
+	 */
+	pp->crqb = mem;
+	pp->crqb_dma = mem_dma;
+	mem += MV_CRQB_Q_SZ;
+	mem_dma += MV_CRQB_Q_SZ;
+
+	/* Second item: 
+	 * 32-slot command response table (CRPB), 8 bytes each in size
+	 */
+	pp->crpb = mem;
+	pp->crpb_dma = mem_dma;
+	mem += MV_CRPB_Q_SZ;
+	mem_dma += MV_CRPB_Q_SZ;
+
+	/* Third item:
+	 * Table of scatter-gather descriptors (ePRD), 16 bytes each
+	 */
+	pp->sg_tbl = mem;
+	pp->sg_tbl_dma = mem_dma;
+
+	writelfl(EDMA_CFG_Q_DEPTH | EDMA_CFG_RD_BRST_EXT | 
+		 EDMA_CFG_WR_BUFF_LEN, port_mmio + EDMA_CFG_OFS);
+
+	writel((pp->crqb_dma >> 16) >> 16, port_mmio + EDMA_REQ_Q_BASE_HI_OFS);
+	writelfl(pp->crqb_dma & EDMA_REQ_Q_BASE_LO_MASK, 
+		 port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+
+	writelfl(0, port_mmio + EDMA_REQ_Q_OUT_PTR_OFS);
+	writelfl(0, port_mmio + EDMA_RSP_Q_IN_PTR_OFS);
+
+	writel((pp->crpb_dma >> 16) >> 16, port_mmio + EDMA_RSP_Q_BASE_HI_OFS);
+	writelfl(pp->crpb_dma & EDMA_RSP_Q_BASE_LO_MASK, 
+		 port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+
+	pp->req_producer = pp->rsp_consumer = 0;
+
+	/* Don't turn on EDMA here...do it before DMA commands only.  Else
+	 * we'll be unable to send non-data, PIO, etc due to restricted access
+	 * to shadow regs.
+	 */
+	ap->private_data = pp;
+	return 0;
+}
+
+/**
+ *      mv_port_stop - Port specific cleanup/stop routine.
+ *      @ap: ATA channel to manipulate
+ *
+ *      Stop DMA, cleanup port memory.
+ *
+ *      LOCKING:
+ *      This routine uses the host_set lock to protect the DMA stop.
+ */
+static void mv_port_stop(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct mv_port_priv *pp = ap->private_data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	mv_stop_dma(ap);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	ap->private_data = NULL;
+	dma_free_coherent(dev, MV_PORT_PRIV_DMA_SZ, pp->crpb, pp->crpb_dma);
+	kfree(pp);
+}
+
+/**
+ *      mv_fill_sg - Fill out the Marvell ePRD (scatter gather) entries
+ *      @qc: queued command whose SG list to source from
+ *
+ *      Populate the SG list and mark the last entry.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static void mv_fill_sg(struct ata_queued_cmd *qc)
+{
+	struct mv_port_priv *pp = qc->ap->private_data;
+	unsigned int i;
+
+	for (i = 0; i < qc->n_elem; i++) {
+		u32 sg_len;
+		dma_addr_t addr;
+
+		addr = sg_dma_address(&qc->sg[i]);
+		sg_len = sg_dma_len(&qc->sg[i]);
+
+		pp->sg_tbl[i].addr = cpu_to_le32(addr & 0xffffffff);
+		pp->sg_tbl[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+		assert(0 == (sg_len & ~MV_DMA_BOUNDARY));
+		pp->sg_tbl[i].flags_size = cpu_to_le32(sg_len);
+	}
+	if (0 < qc->n_elem) {
+		pp->sg_tbl[qc->n_elem - 1].flags_size |= EPRD_FLAG_END_OF_TBL;
+	}
+}
+
+static inline unsigned mv_inc_q_index(unsigned *index)
+{
+	*index = (*index + 1) & MV_MAX_Q_DEPTH_MASK;
+	return *index;
+}
+
+static inline void mv_crqb_pack_cmd(u16 *cmdw, u8 data, u8 addr, unsigned last)
+{
+	*cmdw = data | (addr << CRQB_CMD_ADDR_SHIFT) | CRQB_CMD_CS |
+		(last ? CRQB_CMD_LAST : 0);
+}
+
+/**
+ *      mv_qc_prep - Host specific command preparation.
+ *      @qc: queued command to prepare
+ *
+ *      This routine simply redirects to the general purpose routine
+ *      if command is not DMA.  Else, it handles prep of the CRQB
+ *      (command request block), does some sanity checking, and calls
+ *      the SG load routine.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static void mv_qc_prep(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct mv_port_priv *pp = ap->private_data;
+	u16 *cw;
+	struct ata_taskfile *tf;
+	u16 flags = 0;
+
+ 	if (ATA_PROT_DMA != qc->tf.protocol) {
+		return;
+	}
+
+	/* the req producer index should be the same as we remember it */
+	assert(((readl(mv_ap_base(qc->ap) + EDMA_REQ_Q_IN_PTR_OFS) >> 
+		 EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
+	       pp->req_producer);
+
+	/* Fill in command request block
+	 */
+	if (!(qc->tf.flags & ATA_TFLAG_WRITE)) {
+		flags |= CRQB_FLAG_READ;
+	}
+	assert(MV_MAX_Q_DEPTH > qc->tag);
+	flags |= qc->tag << CRQB_TAG_SHIFT;
+
+	pp->crqb[pp->req_producer].sg_addr = 
+		cpu_to_le32(pp->sg_tbl_dma & 0xffffffff);
+	pp->crqb[pp->req_producer].sg_addr_hi = 
+		cpu_to_le32((pp->sg_tbl_dma >> 16) >> 16);
+	pp->crqb[pp->req_producer].ctrl_flags = cpu_to_le16(flags);
+
+	cw = &pp->crqb[pp->req_producer].ata_cmd[0];
+	tf = &qc->tf;
+
+	/* Sadly, the CRQB cannot accomodate all registers--there are
+	 * only 11 bytes...so we must pick and choose required
+	 * registers based on the command.  So, we drop feature and
+	 * hob_feature for [RW] DMA commands, but they are needed for
+	 * NCQ.  NCQ will drop hob_nsect.
+	 */
+	switch (tf->command) {
+	case ATA_CMD_READ:
+	case ATA_CMD_READ_EXT:
+	case ATA_CMD_WRITE:
+	case ATA_CMD_WRITE_EXT:
+		mv_crqb_pack_cmd(cw++, tf->hob_nsect, ATA_REG_NSECT, 0);
+		break;
+#ifdef LIBATA_NCQ		/* FIXME: remove this line when NCQ added */
+	case ATA_CMD_FPDMA_READ:
+	case ATA_CMD_FPDMA_WRITE:
+		mv_crqb_pack_cmd(cw++, tf->hob_feature, ATA_REG_FEATURE, 0); 
+		mv_crqb_pack_cmd(cw++, tf->feature, ATA_REG_FEATURE, 0);
+		break;
+#endif				/* FIXME: remove this line when NCQ added */
+	default:
+		/* The only other commands EDMA supports in non-queued and
+		 * non-NCQ mode are: [RW] STREAM DMA and W DMA FUA EXT, none
+		 * of which are defined/used by Linux.  If we get here, this
+		 * driver needs work.
+		 *
+		 * FIXME: modify libata to give qc_prep a return value and
+		 * return error here.
+		 */
+		BUG_ON(tf->command);
+		break;
+	}
+	mv_crqb_pack_cmd(cw++, tf->nsect, ATA_REG_NSECT, 0);
+	mv_crqb_pack_cmd(cw++, tf->hob_lbal, ATA_REG_LBAL, 0);
+	mv_crqb_pack_cmd(cw++, tf->lbal, ATA_REG_LBAL, 0);
+	mv_crqb_pack_cmd(cw++, tf->hob_lbam, ATA_REG_LBAM, 0);
+	mv_crqb_pack_cmd(cw++, tf->lbam, ATA_REG_LBAM, 0);
+	mv_crqb_pack_cmd(cw++, tf->hob_lbah, ATA_REG_LBAH, 0);
+	mv_crqb_pack_cmd(cw++, tf->lbah, ATA_REG_LBAH, 0);
+	mv_crqb_pack_cmd(cw++, tf->device, ATA_REG_DEVICE, 0);
+	mv_crqb_pack_cmd(cw++, tf->command, ATA_REG_CMD, 1);	/* last */
+
+	if (!(qc->flags & ATA_QCFLAG_DMAMAP)) {
+		return;
+	}
+	mv_fill_sg(qc);
+}
+
+/**
+ *      mv_qc_issue - Initiate a command to the host
+ *      @qc: queued command to start
+ *
+ *      This routine simply redirects to the general purpose routine
+ *      if command is not DMA.  Else, it sanity checks our local
+ *      caches of the request producer/consumer indices then enables
+ *      DMA and bumps the request producer index.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static int mv_qc_issue(struct ata_queued_cmd *qc)
+{
+	void __iomem *port_mmio = mv_ap_base(qc->ap);
+	struct mv_port_priv *pp = qc->ap->private_data;
+	u32 in_ptr;
+
+	if (ATA_PROT_DMA != qc->tf.protocol) {
+		/* We're about to send a non-EDMA capable command to the
+		 * port.  Turn off EDMA so there won't be problems accessing
+		 * shadow block, etc registers.
+		 */
+		mv_stop_dma(qc->ap);
+		return ata_qc_issue_prot(qc);
+	}
+
+	in_ptr = readl(port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+
+	/* the req producer index should be the same as we remember it */
+	assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
+	       pp->req_producer);
+	/* until we do queuing, the queue should be empty at this point */
+	assert(((in_ptr >> EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) ==
+	       ((readl(port_mmio + EDMA_REQ_Q_OUT_PTR_OFS) >> 
+		 EDMA_REQ_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK));
+
+	mv_inc_q_index(&pp->req_producer);	/* now incr producer index */
+
+	mv_start_dma(port_mmio, pp);
+
+	/* and write the request in pointer to kick the EDMA to life */
+	in_ptr &= EDMA_REQ_Q_BASE_LO_MASK;
+	in_ptr |= pp->req_producer << EDMA_REQ_Q_PTR_SHIFT;
+	writelfl(in_ptr, port_mmio + EDMA_REQ_Q_IN_PTR_OFS);
+
+	return 0;
+}
+
+/**
+ *      mv_get_crpb_status - get status from most recently completed cmd
+ *      @ap: ATA channel to manipulate
+ *
+ *      This routine is for use when the port is in DMA mode, when it
+ *      will be using the CRPB (command response block) method of
+ *      returning command completion information.  We assert indices
+ *      are good, grab status, and bump the response consumer index to
+ *      prove that we're up to date.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static u8 mv_get_crpb_status(struct ata_port *ap)
+{
+	void __iomem *port_mmio = mv_ap_base(ap);
+	struct mv_port_priv *pp = ap->private_data;
+	u32 out_ptr;
+
+	out_ptr = readl(port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+
+	/* the response consumer index should be the same as we remember it */
+	assert(((out_ptr >> EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == 
+	       pp->rsp_consumer);
+
+	/* increment our consumer index... */
+	pp->rsp_consumer = mv_inc_q_index(&pp->rsp_consumer);
+	
+	/* and, until we do NCQ, there should only be 1 CRPB waiting */
+	assert(((readl(port_mmio + EDMA_RSP_Q_IN_PTR_OFS) >> 
+		 EDMA_RSP_Q_PTR_SHIFT) & MV_MAX_Q_DEPTH_MASK) == 
+	       pp->rsp_consumer);
+
+	/* write out our inc'd consumer index so EDMA knows we're caught up */
+	out_ptr &= EDMA_RSP_Q_BASE_LO_MASK;
+	out_ptr |= pp->rsp_consumer << EDMA_RSP_Q_PTR_SHIFT;
+	writelfl(out_ptr, port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
+
+	/* Return ATA status register for completed CRPB */
+	return (pp->crpb[pp->rsp_consumer].flags >> CRPB_FLAG_STATUS_SHIFT);
+}
+
+/**
+ *      mv_err_intr - Handle error interrupts on the port
+ *      @ap: ATA channel to manipulate
+ *
+ *      In most cases, just clear the interrupt and move on.  However,
+ *      some cases require an eDMA reset, which is done right before
+ *      the COMRESET in mv_phy_reset().  The SERR case requires a
+ *      clear of pending errors in the SATA SERROR register.  Finally,
+ *      if the port disabled DMA, update our cached copy to match.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
 static void mv_err_intr(struct ata_port *ap)
 {
-	void __iomem *port_mmio;
+	void __iomem *port_mmio = mv_ap_base(ap);
 	u32 edma_err_cause, serr = 0;
 
-	/* bug here b/c we got an err int on a port we don't know about,
-	 * so there's no way to clear it
-	 */
-	BUG_ON(NULL == ap);
-	port_mmio = mv_ap_base(ap);
-
 	edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
 
 	if (EDMA_ERR_SERR & edma_err_cause) {
 		serr = scr_read(ap, SCR_ERROR);
 		scr_write_flush(ap, SCR_ERROR, serr);
 	}
-	DPRINTK("port %u error; EDMA err cause: 0x%08x SERR: 0x%08x\n", 
-		ap->port_no, edma_err_cause, serr);
+	if (EDMA_ERR_SELF_DIS & edma_err_cause) {
+		struct mv_port_priv *pp	= ap->private_data;
+		pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+	}
+	DPRINTK(KERN_ERR "ata%u: port error; EDMA err cause: 0x%08x "
+		"SERR: 0x%08x\n", ap->id, edma_err_cause, serr);
 
 	/* Clear EDMA now that SERR cleanup done */
 	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
@@ -480,7 +1042,21 @@
 	}
 }
 
-/* Handle any outstanding interrupts in a single SATAHC 
+/**
+ *      mv_host_intr - Handle all interrupts on the given host controller
+ *      @host_set: host specific structure
+ *      @relevant: port error bits relevant to this host controller
+ *      @hc: which host controller we're to look at
+ *
+ *      Read then write clear the HC interrupt status then walk each
+ *      port connected to the HC and see if it needs servicing.  Port
+ *      success ints are reported in the HC interrupt status reg, the
+ *      port error ints are reported in the higher level main
+ *      interrupt status register and thus are passed in via the
+ *      'relevant' argument.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
  */
 static void mv_host_intr(struct ata_host_set *host_set, u32 relevant,
 			 unsigned int hc)
@@ -490,8 +1066,8 @@
 	struct ata_port *ap;
 	struct ata_queued_cmd *qc;
 	u32 hc_irq_cause;
-	int shift, port, port0, hard_port;
-	u8 ata_status;
+	int shift, port, port0, hard_port, handled;
+	u8 ata_status = 0;
 
 	if (hc == 0) {
 		port0 = 0;
@@ -502,7 +1078,7 @@
 	/* we'll need the HC success int register in most cases */
 	hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
 	if (hc_irq_cause) {
-		writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
+		writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
 	}
 
 	VPRINTK("ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x\n",
@@ -511,35 +1087,38 @@
 	for (port = port0; port < port0 + MV_PORTS_PER_HC; port++) {
 		ap = host_set->ports[port];
 		hard_port = port & MV_PORT_MASK;	/* range 0-3 */
-		ata_status = 0xffU;
+		handled = 0;	/* ensure ata_status is set if handled++ */
 
-		if (((CRBP_DMA_DONE | DEV_IRQ) << hard_port) & hc_irq_cause) {
-			BUG_ON(NULL == ap);
-			/* rcv'd new resp, basic DMA complete, or ATA IRQ */
-			/* This is needed to clear the ATA INTRQ.
-			 * FIXME: don't read the status reg in EDMA mode!
+		if ((CRPB_DMA_DONE << hard_port) & hc_irq_cause) {
+			/* new CRPB on the queue; just one at a time until NCQ
+			 */
+			ata_status = mv_get_crpb_status(ap);
+			handled++;
+		} else if ((DEV_IRQ << hard_port) & hc_irq_cause) {
+			/* received ATA IRQ; read the status reg to clear INTRQ
 			 */
 			ata_status = readb((void __iomem *)
 					   ap->ioaddr.status_addr);
+			handled++;
 		}
 
-		shift = port * 2;
+		shift = port << 1;		/* (port * 2) */
 		if (port >= MV_PORTS_PER_HC) {
 			shift++;	/* skip bit 8 in the HC Main IRQ reg */
 		}
 		if ((PORT0_ERR << shift) & relevant) {
 			mv_err_intr(ap);
-			/* FIXME: smart to OR in ATA_ERR? */
+			/* OR in ATA_ERR to ensure libata knows we took one */
 			ata_status = readb((void __iomem *)
 					   ap->ioaddr.status_addr) | ATA_ERR;
+			handled++;
 		}
 		
-		if (ap) {
+		if (handled && ap) {
 			qc = ata_qc_from_tag(ap, ap->active_tag);
 			if (NULL != qc) {
 				VPRINTK("port %u IRQ found for qc, "
 					"ata_status 0x%x\n", port,ata_status);
-				BUG_ON(0xffU == ata_status);
 				/* mark qc status appropriately */
 				ata_qc_complete(qc, ata_status);
 			}
@@ -548,17 +1127,30 @@
 	VPRINTK("EXIT\n");
 }
 
+/**
+ *      mv_interrupt - 
+ *      @irq: unused
+ *      @dev_instance: private data; in this case the host structure
+ *      @regs: unused
+ *
+ *      Read the read only register to determine if any host
+ *      controllers have pending interrupts.  If so, call lower level
+ *      routine to handle.  Also check for PCI errors which are only
+ *      reported here.
+ *
+ *      LOCKING: 
+ *      This routine holds the host_set lock while processing pending
+ *      interrupts.
+ */
 static irqreturn_t mv_interrupt(int irq, void *dev_instance,
 				struct pt_regs *regs)
 {
 	struct ata_host_set *host_set = dev_instance;
 	unsigned int hc, handled = 0, n_hcs;
-	void __iomem *mmio;
+	void __iomem *mmio = host_set->mmio_base;
 	u32 irq_stat;
 
-	mmio = host_set->mmio_base;
 	irq_stat = readl(mmio + HC_MAIN_IRQ_CAUSE_OFS);
-	n_hcs = mv_get_hc_count(host_set->ports[0]->flags);
 
 	/* check the cases where we either have nothing pending or have read
 	 * a bogus register value which can indicate HW removal or PCI fault
@@ -567,64 +1159,105 @@
 		return IRQ_NONE;
 	}
 
+	n_hcs = mv_get_hc_count(host_set->ports[0]->flags);
 	spin_lock(&host_set->lock);
 
 	for (hc = 0; hc < n_hcs; hc++) {
 		u32 relevant = irq_stat & (HC0_IRQ_PEND << (hc * HC_SHIFT));
 		if (relevant) {
 			mv_host_intr(host_set, relevant, hc);
-			handled = 1;
+			handled++;
 		}
 	}
 	if (PCI_ERR & irq_stat) {
-		/* FIXME: these are all masked by default, but still need
-		 * to recover from them properly.
-		 */
-	}
+		printk(KERN_ERR DRV_NAME ": PCI ERROR; PCI IRQ cause=0x%08x\n",
+		       readl(mmio + PCI_IRQ_CAUSE_OFS));
 
+		DPRINTK("All regs @ PCI error\n");
+		mv_dump_all_regs(mmio, -1, to_pci_dev(host_set->dev));
+
+		writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
+		handled++;
+	}
 	spin_unlock(&host_set->lock);
 
 	return IRQ_RETVAL(handled);
 }
 
+/**
+ *      mv_check_err - Return the error shadow register to caller.
+ *      @ap: ATA channel to manipulate
+ *
+ *      Marvell requires DMA to be stopped before accessing shadow
+ *      registers.  So we do that, then return the needed register.
+ *
+ *      LOCKING:
+ *      Inherited from caller.  FIXME: protect mv_stop_dma with lock?
+ */
+static u8 mv_check_err(struct ata_port *ap)
+{
+	mv_stop_dma(ap);		/* can't read shadow regs if DMA on */
+	return readb((void __iomem *) ap->ioaddr.error_addr);
+}
+
+/**
+ *      mv_phy_reset - Perform eDMA reset followed by COMRESET
+ *      @ap: ATA channel to manipulate
+ *
+ *      Part of this is taken from __sata_phy_reset and modified to
+ *      not sleep since this routine gets called from interrupt level.
+ *
+ *      LOCKING:
+ *      Inherited from caller.  This is coded to safe to call at
+ *      interrupt level, i.e. it does not sleep.
+ */
 static void mv_phy_reset(struct ata_port *ap)
 {
 	void __iomem *port_mmio = mv_ap_base(ap);
 	struct ata_taskfile tf;
 	struct ata_device *dev = &ap->device[0];
-	u32 edma = 0, bdma;
+	unsigned long timeout;
 
 	VPRINTK("ENTER, port %u, mmio 0x%p\n", ap->port_no, port_mmio);
 
-	edma = readl(port_mmio + EDMA_CMD_OFS);
-	if (EDMA_EN & edma) {
-		/* disable EDMA if active */
-		edma &= ~EDMA_EN;
-		writelfl(edma | EDMA_DS, port_mmio + EDMA_CMD_OFS);
-		udelay(1);
-	} else if (mv_port_bdma_capable(ap) &&
-		   (bdma = readl(port_mmio + BDMA_CMD_OFS)) & BDMA_START) {
-		/* disable BDMA if active */
-		writelfl(bdma & ~BDMA_START, port_mmio + BDMA_CMD_OFS);
-	}
+	mv_stop_dma(ap);
 
-	writelfl(edma | ATA_RST, port_mmio + EDMA_CMD_OFS);
+	writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
 	udelay(25);		/* allow reset propagation */
 
 	/* Spec never mentions clearing the bit.  Marvell's driver does
 	 * clear the bit, however.
 	 */
-	writelfl(edma & ~ATA_RST, port_mmio + EDMA_CMD_OFS);
+	writelfl(0, port_mmio + EDMA_CMD_OFS);
 
-	VPRINTK("Done.  Now calling __sata_phy_reset()\n");
+	VPRINTK("S-regs after ATA_RST: SStat 0x%08x SErr 0x%08x "
+		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
+		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
 
 	/* proceed to init communications via the scr_control reg */
-	__sata_phy_reset(ap);
+	scr_write_flush(ap, SCR_CONTROL, 0x301);
+	mdelay(1);
+	scr_write_flush(ap, SCR_CONTROL, 0x300);
+	timeout = jiffies + (HZ * 1);
+	do {
+		mdelay(10);
+		if ((scr_read(ap, SCR_STATUS) & 0xf) != 1)
+			break;
+	} while (time_before(jiffies, timeout));
 
-	if (ap->flags & ATA_FLAG_PORT_DISABLED) {
-		VPRINTK("Port disabled pre-sig.  Exiting.\n");
+	VPRINTK("S-regs after PHY wake: SStat 0x%08x SErr 0x%08x "
+		"SCtrl 0x%08x\n", mv_scr_read(ap, SCR_STATUS),
+		mv_scr_read(ap, SCR_ERROR), mv_scr_read(ap, SCR_CONTROL));
+
+	if (sata_dev_present(ap)) {
+		ata_port_probe(ap);
+	} else {
+		printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n",
+		       ap->id, scr_read(ap, SCR_STATUS));
+		ata_port_disable(ap);
 		return;
 	}
+	ap->cbl = ATA_CBL_SATA;
 
 	tf.lbah = readb((void __iomem *) ap->ioaddr.lbah_addr);
 	tf.lbam = readb((void __iomem *) ap->ioaddr.lbam_addr);
@@ -639,37 +1272,118 @@
 	VPRINTK("EXIT\n");
 }
 
-static void mv_port_init(struct ata_ioports *port, unsigned long base)
+/**
+ *      mv_eng_timeout - Routine called by libata when SCSI times out I/O
+ *      @ap: ATA channel to manipulate
+ *
+ *      Intent is to clear all pending error conditions, reset the
+ *      chip/bus, fail the command, and move on.
+ *
+ *      LOCKING:
+ *      This routine holds the host_set lock while failing the command.
+ */
+static void mv_eng_timeout(struct ata_port *ap)
 {
-	/* PIO related setup */
-	port->data_addr = base + SHD_PIO_DATA_OFS;
-	port->error_addr = port->feature_addr = base + SHD_FEA_ERR_OFS;
-	port->nsect_addr = base + SHD_SECT_CNT_OFS;
-	port->lbal_addr = base + SHD_LBA_L_OFS;
-	port->lbam_addr = base + SHD_LBA_M_OFS;
-	port->lbah_addr = base + SHD_LBA_H_OFS;
-	port->device_addr = base + SHD_DEV_HD_OFS;
-	port->status_addr = port->command_addr = base + SHD_CMD_STA_OFS;
-	port->altstatus_addr = port->ctl_addr = base + SHD_CTL_AST_OFS;
-	/* unused */
-	port->cmd_addr = port->bmdma_addr = port->scr_addr = 0;
+	struct ata_queued_cmd *qc;
+	unsigned long flags;
 
-	/* unmask all EDMA error interrupts */
-	writel(~0, (void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS);
+	printk(KERN_ERR "ata%u: Entering mv_eng_timeout\n",ap->id);
+	DPRINTK("All regs @ start of eng_timeout\n");
+	mv_dump_all_regs(ap->host_set->mmio_base, ap->port_no, 
+			 to_pci_dev(ap->host_set->dev));
 
-	VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", 
-		readl((void __iomem *)base + EDMA_CFG_OFS),
-		readl((void __iomem *)base + EDMA_ERR_IRQ_CAUSE_OFS),
-		readl((void __iomem *)base + EDMA_ERR_IRQ_MASK_OFS));
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+        printk(KERN_ERR "mmio_base %p ap %p qc %p scsi_cmnd %p &cmnd %p\n",
+	       ap->host_set->mmio_base, ap, qc, qc->scsicmd, 
+	       &qc->scsicmd->cmnd);
+
+	mv_err_intr(ap);
+	mv_phy_reset(ap);
+
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+	} else {
+		/* hack alert!  We cannot use the supplied completion
+	 	 * function from inside the ->eh_strategy_handler() thread.
+	 	 * libata is the only user of ->eh_strategy_handler() in
+	 	 * any kernel, so the default scsi_done() assumes it is
+	 	 * not being called from the SCSI EH.
+	 	 */
+		spin_lock_irqsave(&ap->host_set->lock, flags);
+		qc->scsidone = scsi_finish_command;
+		ata_qc_complete(qc, ATA_ERR);
+		spin_unlock_irqrestore(&ap->host_set->lock, flags);
+	}
 }
 
+/**
+ *      mv_port_init - Perform some early initialization on a single port.
+ *      @port: libata data structure storing shadow register addresses
+ *      @port_mmio: base address of the port
+ *
+ *      Initialize shadow register mmio addresses, clear outstanding
+ *      interrupts on the port, and unmask interrupts for the future
+ *      start of the port.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static void mv_port_init(struct ata_ioports *port,  void __iomem *port_mmio)
+{
+	unsigned long shd_base = (unsigned long) port_mmio + SHD_BLK_OFS;
+	unsigned serr_ofs;
+
+	/* PIO related setup 
+	 */
+	port->data_addr = shd_base + (sizeof(u32) * ATA_REG_DATA);
+	port->error_addr = 
+		port->feature_addr = shd_base + (sizeof(u32) * ATA_REG_ERR);
+	port->nsect_addr = shd_base + (sizeof(u32) * ATA_REG_NSECT);
+	port->lbal_addr = shd_base + (sizeof(u32) * ATA_REG_LBAL);
+	port->lbam_addr = shd_base + (sizeof(u32) * ATA_REG_LBAM);
+	port->lbah_addr = shd_base + (sizeof(u32) * ATA_REG_LBAH);
+	port->device_addr = shd_base + (sizeof(u32) * ATA_REG_DEVICE);
+	port->status_addr = 
+		port->command_addr = shd_base + (sizeof(u32) * ATA_REG_STATUS);
+	/* special case: control/altstatus doesn't have ATA_REG_ address */
+	port->altstatus_addr = port->ctl_addr = shd_base + SHD_CTL_AST_OFS;
+
+	/* unused: */
+	port->cmd_addr = port->bmdma_addr = port->scr_addr = 0;
+
+	/* Clear any currently outstanding port interrupt conditions */
+	serr_ofs = mv_scr_offset(SCR_ERROR);
+	writelfl(readl(port_mmio + serr_ofs), port_mmio + serr_ofs);
+	writelfl(0, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
+
+	/* unmask all EDMA error interrupts */
+	writelfl(~0, port_mmio + EDMA_ERR_IRQ_MASK_OFS);
+
+	VPRINTK("EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x\n", 
+		readl(port_mmio + EDMA_CFG_OFS),
+		readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS),
+		readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
+}
+
+/**
+ *      mv_host_init - Perform some early initialization of the host.
+ *      @probe_ent: early data struct representing the host
+ *
+ *      If possible, do an early global reset of the host.  Then do
+ *      our port init and clear/unmask all/relevant host interrupts.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
 static int mv_host_init(struct ata_probe_ent *probe_ent)
 {
 	int rc = 0, n_hc, port, hc;
 	void __iomem *mmio = probe_ent->mmio_base;
 	void __iomem *port_mmio;
 
-	if (mv_master_reset(probe_ent->mmio_base)) {
+	if ((MV_FLAG_GLBL_SFT_RST & probe_ent->host_flags) && 
+	    mv_global_soft_reset(probe_ent->mmio_base)) {
 		rc = 1;
 		goto done;
 	}
@@ -679,17 +1393,27 @@
 
 	for (port = 0; port < probe_ent->n_ports; port++) {
 		port_mmio = mv_port_base(mmio, port);
-		mv_port_init(&probe_ent->port[port], (unsigned long)port_mmio);
+		mv_port_init(&probe_ent->port[port], port_mmio);
 	}
 
 	for (hc = 0; hc < n_hc; hc++) {
-		VPRINTK("HC%i: HC config=0x%08x HC IRQ cause=0x%08x\n", hc,
-			readl(mv_hc_base(mmio, hc) + HC_CFG_OFS),
-			readl(mv_hc_base(mmio, hc) + HC_IRQ_CAUSE_OFS));
+		void __iomem *hc_mmio = mv_hc_base(mmio, hc);
+
+		VPRINTK("HC%i: HC config=0x%08x HC IRQ cause "
+			"(before clear)=0x%08x\n", hc,
+			readl(hc_mmio + HC_CFG_OFS),
+			readl(hc_mmio + HC_IRQ_CAUSE_OFS));
+
+		/* Clear any currently outstanding hc interrupt conditions */
+		writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
 	}
 
-	writel(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
-	writel(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
+	/* Clear any currently outstanding host interrupt conditions */
+	writelfl(0, mmio + PCI_IRQ_CAUSE_OFS);
+
+	/* and unmask interrupt generation for host regs */
+	writelfl(PCI_UNMASK_ALL_IRQS, mmio + PCI_IRQ_MASK_OFS);
+	writelfl(~HC_MAIN_MASKED_IRQS, mmio + HC_MAIN_IRQ_MASK_OFS);
 
 	VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
 		"PCI int cause/mask=0x%08x/0x%08x\n", 
@@ -697,11 +1421,53 @@
 		readl(mmio + HC_MAIN_IRQ_MASK_OFS),
 		readl(mmio + PCI_IRQ_CAUSE_OFS),
 		readl(mmio + PCI_IRQ_MASK_OFS));
-
- done:
+done:
 	return rc;
 }
 
+/**
+ *      mv_print_info - Dump key info to kernel log for perusal.
+ *      @probe_ent: early data struct representing the host
+ *
+ *      FIXME: complete this.
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
+static void mv_print_info(struct ata_probe_ent *probe_ent)
+{
+	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+	struct mv_host_priv *hpriv = probe_ent->private_data;
+	u8 rev_id, scc;
+	const char *scc_s;
+
+	/* Use this to determine the HW stepping of the chip so we know
+	 * what errata to workaround
+	 */
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+
+	pci_read_config_byte(pdev, PCI_CLASS_DEVICE, &scc);
+	if (scc == 0)
+		scc_s = "SCSI";
+	else if (scc == 0x01)
+		scc_s = "RAID";
+	else
+		scc_s = "unknown";
+
+	printk(KERN_INFO DRV_NAME 
+	       "(%s) %u slots %u ports %s mode IRQ via %s\n",
+	       pci_name(pdev), (unsigned)MV_MAX_Q_DEPTH, probe_ent->n_ports, 
+	       scc_s, (MV_HP_FLAG_MSI & hpriv->hp_flags) ? "MSI" : "INTx");
+}
+
+/**
+ *      mv_init_one - handle a positive probe of a Marvell host
+ *      @pdev: PCI device found
+ *      @ent: PCI device ID entry for the matched host
+ *
+ *      LOCKING:
+ *      Inherited from caller.
+ */
 static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 {
 	static int printed_version = 0;
@@ -709,16 +1475,12 @@
 	struct mv_host_priv *hpriv;
 	unsigned int board_idx = (unsigned int)ent->driver_data;
 	void __iomem *mmio_base;
-	int pci_dev_busy = 0;
-	int rc;
+	int pci_dev_busy = 0, rc;
 
 	if (!printed_version++) {
-		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+		printk(KERN_INFO DRV_NAME " version " DRV_VERSION "\n");
 	}
 
-	VPRINTK("ENTER for PCI Bus:Slot.Func=%u:%u.%u\n", pdev->bus->number,
-		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
-
 	rc = pci_enable_device(pdev);
 	if (rc) {
 		return rc;
@@ -730,8 +1492,6 @@
 		goto err_out;
 	}
 
-	pci_intx(pdev, 1);
-
 	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
 	if (probe_ent == NULL) {
 		rc = -ENOMEM;
@@ -742,8 +1502,7 @@
 	probe_ent->dev = pci_dev_to_dev(pdev);
 	INIT_LIST_HEAD(&probe_ent->node);
 
-	mmio_base = ioremap_nocache(pci_resource_start(pdev, MV_PRIMARY_BAR),
-				    pci_resource_len(pdev, MV_PRIMARY_BAR));
+	mmio_base = pci_iomap(pdev, MV_PRIMARY_BAR, 0);
 	if (mmio_base == NULL) {
 		rc = -ENOMEM;
 		goto err_out_free_ent;
@@ -772,37 +1531,40 @@
 	if (rc) {
 		goto err_out_hpriv;
 	}
-/* 	mv_print_info(probe_ent); */
 
-	{
-		int b, w;
-		u32 dw[4];	/* hold a line of 16b */
-		VPRINTK("PCI config space:\n");
-		for (b = 0; b < 0x40; ) {
-			for (w = 0; w < 4; w++) {
-				(void) pci_read_config_dword(pdev,b,&dw[w]);
-				b += sizeof(*dw);
-			}
-			VPRINTK("%08x %08x %08x %08x\n",
-				dw[0],dw[1],dw[2],dw[3]);
-		}
+	/* Enable interrupts */
+	if (pci_enable_msi(pdev) == 0) {
+		hpriv->hp_flags |= MV_HP_FLAG_MSI;
+	} else {
+		pci_intx(pdev, 1);
 	}
 
-	/* FIXME: check ata_device_add return value */
-	ata_device_add(probe_ent);
-	kfree(probe_ent);
+	mv_dump_pci_cfg(pdev, 0x68);
+	mv_print_info(probe_ent);
 
+	if (ata_device_add(probe_ent) == 0) {
+		rc = -ENODEV;		/* No devices discovered */
+		goto err_out_dev_add;
+	}
+
+	kfree(probe_ent);
 	return 0;
 
- err_out_hpriv:
+err_out_dev_add:
+	if (MV_HP_FLAG_MSI & hpriv->hp_flags) {
+		pci_disable_msi(pdev);
+	} else {
+		pci_intx(pdev, 0);
+	}
+err_out_hpriv:
 	kfree(hpriv);
- err_out_iounmap:
-	iounmap(mmio_base);
- err_out_free_ent:
+err_out_iounmap:
+	pci_iounmap(pdev, mmio_base);
+err_out_free_ent:
 	kfree(probe_ent);
- err_out_regions:
+err_out_regions:
 	pci_release_regions(pdev);
- err_out:
+err_out:
 	if (!pci_dev_busy) {
 		pci_disable_device(pdev);
 	}
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 8b7e871..ada45f7 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -29,6 +29,8 @@
  *  NV-specific details such as register offsets, SATA phy location,
  *  hotplug info, etc.
  *
+ *  0.09
+ *     - Fixed bug introduced by 0.08's MCP51 and MCP55 support.
  *
  *  0.08
  *     - Added support for MCP51 and MCP55.
@@ -132,9 +134,7 @@
 	GENERIC,
 	NFORCE2,
 	NFORCE3,
-	CK804,
-	MCP51,
-	MCP55
+	CK804
 };
 
 static struct pci_device_id nv_pci_tbl[] = {
@@ -153,13 +153,13 @@
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
 		PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP51 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
-		PCI_ANY_ID, PCI_ANY_ID, 0, 0, MCP55 },
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
 	{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
 		PCI_ANY_ID, PCI_ANY_ID,
 		PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
@@ -405,7 +405,7 @@
 	rc = -ENOMEM;
 
 	ppi = &nv_port_info;
-	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
 	if (!probe_ent)
 		goto err_out_regions;
 
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
index b227e51..0761a32 100644
--- a/drivers/scsi/sata_sis.c
+++ b/drivers/scsi/sata_sis.c
@@ -263,7 +263,7 @@
 		goto err_out_regions;
 
 	ppi = &sis_port_info;
-	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
 	if (!probe_ent) {
 		rc = -ENOMEM;
 		goto err_out_regions;
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
index 4c9fb8b..9c06f2a 100644
--- a/drivers/scsi/sata_uli.c
+++ b/drivers/scsi/sata_uli.c
@@ -202,7 +202,7 @@
 		goto err_out_regions;
 
 	ppi = &uli_port_info;
-	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
 	if (!probe_ent) {
 		rc = -ENOMEM;
 		goto err_out_regions;
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
index 128b996..5658724 100644
--- a/drivers/scsi/sata_via.c
+++ b/drivers/scsi/sata_via.c
@@ -212,7 +212,7 @@
 	struct ata_probe_ent *probe_ent;
 	struct ata_port_info *ppi = &svia_port_info;
 
-	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
 	if (!probe_ent)
 		return NULL;
 
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index fcf9f6c..327c5d7 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -587,6 +587,7 @@
 	if (sdev->scsi_level >= 2 ||
 	    (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1))
 		sdev->scsi_level++;
+	sdev->sdev_target->scsi_level = sdev->scsi_level;
 
 	return 0;
 }
@@ -771,6 +772,15 @@
 	return SCSI_SCAN_LUN_PRESENT;
 }
 
+static inline void scsi_destroy_sdev(struct scsi_device *sdev)
+{
+	if (sdev->host->hostt->slave_destroy)
+		sdev->host->hostt->slave_destroy(sdev);
+	transport_destroy_device(&sdev->sdev_gendev);
+	put_device(&sdev->sdev_gendev);
+}
+
+
 /**
  * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
  * @starget:	pointer to target device structure
@@ -803,9 +813,9 @@
 	 * The rescan flag is used as an optimization, the first scan of a
 	 * host adapter calls into here with rescan == 0.
 	 */
-	if (rescan) {
-		sdev = scsi_device_lookup_by_target(starget, lun);
-		if (sdev) {
+	sdev = scsi_device_lookup_by_target(starget, lun);
+	if (sdev) {
+		if (rescan || sdev->sdev_state != SDEV_CREATED) {
 			SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
 				"scsi scan: device exists on %s\n",
 				sdev->sdev_gendev.bus_id));
@@ -820,9 +830,9 @@
 								 sdev->model);
 			return SCSI_SCAN_LUN_PRESENT;
 		}
-	}
-
-	sdev = scsi_alloc_sdev(starget, lun, hostdata);
+		scsi_device_put(sdev);
+	} else
+		sdev = scsi_alloc_sdev(starget, lun, hostdata);
 	if (!sdev)
 		goto out;
 
@@ -877,12 +887,8 @@
 				res = SCSI_SCAN_NO_RESPONSE;
 			}
 		}
-	} else {
-		if (sdev->host->hostt->slave_destroy)
-			sdev->host->hostt->slave_destroy(sdev);
-		transport_destroy_device(&sdev->sdev_gendev);
-		put_device(&sdev->sdev_gendev);
-	}
+	} else
+		scsi_destroy_sdev(sdev);
  out:
 	return res;
 }
@@ -1054,7 +1060,7 @@
  *     0: scan completed (or no memory, so further scanning is futile)
  *     1: no report lun scan, or not configured
  **/
-static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
+static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
 				int rescan)
 {
 	char devname[64];
@@ -1067,7 +1073,8 @@
 	struct scsi_lun *lunp, *lun_data;
 	u8 *data;
 	struct scsi_sense_hdr sshdr;
-	struct scsi_target *starget = scsi_target(sdev);
+	struct scsi_device *sdev;
+	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
 
 	/*
 	 * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
@@ -1075,15 +1082,23 @@
 	 * support more than 8 LUNs.
 	 */
 	if ((bflags & BLIST_NOREPORTLUN) || 
-	     sdev->scsi_level < SCSI_2 ||
-	    (sdev->scsi_level < SCSI_3 && 
-	     (!(bflags & BLIST_REPORTLUN2) || sdev->host->max_lun <= 8)) )
+	     starget->scsi_level < SCSI_2 ||
+	    (starget->scsi_level < SCSI_3 && 
+	     (!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8)) )
 		return 1;
 	if (bflags & BLIST_NOLUN)
 		return 0;
 
+	if (!(sdev = scsi_device_lookup_by_target(starget, 0))) {
+		sdev = scsi_alloc_sdev(starget, 0, NULL);
+		if (!sdev)
+			return 0;
+		if (scsi_device_get(sdev))
+			return 0;
+	}
+
 	sprintf(devname, "host %d channel %d id %d",
-		sdev->host->host_no, sdev->channel, sdev->id);
+		shost->host_no, sdev->channel, sdev->id);
 
 	/*
 	 * Allocate enough to hold the header (the same size as one scsi_lun)
@@ -1098,8 +1113,10 @@
 	length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun);
 	lun_data = kmalloc(length, GFP_ATOMIC |
 			   (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
-	if (!lun_data)
+	if (!lun_data) {
+		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
 		goto out;
+	}
 
 	scsi_cmd[0] = REPORT_LUNS;
 
@@ -1201,10 +1218,6 @@
 			for (i = 0; i < sizeof(struct scsi_lun); i++)
 				printk("%02x", data[i]);
 			printk(" has a LUN larger than currently supported.\n");
-		} else if (lun == 0) {
-			/*
-			 * LUN 0 has already been scanned.
-			 */
 		} else if (lun > sdev->host->max_lun) {
 			printk(KERN_WARNING "scsi: %s lun%d has a LUN larger"
 			       " than allowed by the host adapter\n",
@@ -1227,13 +1240,13 @@
 	}
 
 	kfree(lun_data);
-	return 0;
-
  out:
-	/*
-	 * We are out of memory, don't try scanning any further.
-	 */
-	printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+	scsi_device_put(sdev);
+	if (sdev->sdev_state == SDEV_CREATED)
+		/*
+		 * the sdev we used didn't appear in the report luns scan
+		 */
+		scsi_destroy_sdev(sdev);
 	return 0;
 }
 
@@ -1299,7 +1312,6 @@
 	struct Scsi_Host *shost = dev_to_shost(parent);
 	int bflags = 0;
 	int res;
-	struct scsi_device *sdev = NULL;
 	struct scsi_target *starget;
 
 	if (shost->this_id == id)
@@ -1325,27 +1337,16 @@
 	 * Scan LUN 0, if there is some response, scan further. Ideally, we
 	 * would not configure LUN 0 until all LUNs are scanned.
 	 */
-	res = scsi_probe_and_add_lun(starget, 0, &bflags, &sdev, rescan, NULL);
-	if (res == SCSI_SCAN_LUN_PRESENT) {
-		if (scsi_report_lun_scan(sdev, bflags, rescan) != 0)
+	res = scsi_probe_and_add_lun(starget, 0, &bflags, NULL, rescan, NULL);
+	if (res == SCSI_SCAN_LUN_PRESENT || res == SCSI_SCAN_TARGET_PRESENT) {
+		if (scsi_report_lun_scan(starget, bflags, rescan) != 0)
 			/*
 			 * The REPORT LUN did not scan the target,
 			 * do a sequential scan.
 			 */
 			scsi_sequential_lun_scan(starget, bflags,
-				       	res, sdev->scsi_level, rescan);
-	} else if (res == SCSI_SCAN_TARGET_PRESENT) {
-		/*
-		 * There's a target here, but lun 0 is offline so we
-		 * can't use the report_lun scan.  Fall back to a
-		 * sequential lun scan with a bflags of SPARSELUN and
-		 * a default scsi level of SCSI_2
-		 */
-		scsi_sequential_lun_scan(starget, BLIST_SPARSELUN,
-				SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan);
+				       	res, starget->scsi_level, rescan);
 	}
-	if (sdev)
-		scsi_device_put(sdev);
 
  out_reap:
 	/* now determine if the target has any children at all
@@ -1542,10 +1543,7 @@
 {
 	BUG_ON(sdev->id != sdev->host->this_id);
 
-	if (sdev->host->hostt->slave_destroy)
-		sdev->host->hostt->slave_destroy(sdev);
-	transport_destroy_device(&sdev->sdev_gendev);
-	put_device(&sdev->sdev_gendev);
+	scsi_destroy_sdev(sdev);
 }
 EXPORT_SYMBOL(scsi_free_host_dev);
 
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index ff724bbe..1d145d2 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -628,17 +628,16 @@
 	struct Scsi_Host *shost = dev_to_shost(parent->dev.parent);
 	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
 
-	transport_destroy_device(&rphy->dev);
+	scsi_remove_target(dev);
 
-	scsi_remove_target(&rphy->dev);
+	transport_remove_device(dev);
+	device_del(dev);
+	transport_destroy_device(dev);
 
 	spin_lock(&sas_host->lock);
 	list_del(&rphy->list);
 	spin_unlock(&sas_host->lock);
 
-	transport_remove_device(dev);
-	device_del(dev);
-	transport_destroy_device(dev);
 	put_device(&parent->dev);
 }
 EXPORT_SYMBOL(sas_rphy_delete);