public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 1/3] arcmsr: Support Areca new SATA Raid Adapter ARC1214/1224/1264/1284
@ 2013-08-26  4:14 黃清隆
  2013-08-26 10:18 ` James Bottomley
  2013-08-26 12:20 ` Tomas Henzl
  0 siblings, 2 replies; 4+ messages in thread
From: 黃清隆 @ 2013-08-26  4:14 UTC (permalink / raw)
  To: james.bottomley, linux-scsi, linux-kernel; +Cc: billion

[-- Attachment #1: Type: text/plain, Size: 237 bytes --]

 From: Ching <ching2048@areca.com.tw>

Support Areca new SATA Raid adapter ARC1214/1224/1264/1284.
Modify maximum outstanding command number, notify command complete with auto
request sense
Signed-off-by: Ching  <ching2048@areca.com.tw>

[-- Attachment #2: patch1 --]
[-- Type: application/octet-stream, Size: 261838 bytes --]

diff -uprN a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
--- a/drivers/scsi/arcmsr/arcmsr_attr.c	2013-07-01 06:13:28.000000000 +0800
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c	2012-11-29 19:35:16.000000000 +0800
@@ -59,64 +59,112 @@
 
 struct device_attribute *arcmsr_host_attrs[];
 
-static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp,
-					     struct kobject *kobj,
-					     struct bin_attribute *bin,
-					     char *buf, loff_t off,
-					     size_t count)
+static ssize_t
+arcmsr_sysfs_iop_message_read(struct file *filp,
+				struct kobject *kobj,
+				struct bin_attribute *bin,
+				char *buf, loff_t off,
+				size_t count)
 {
-	struct device *dev = container_of(kobj,struct device,kobj);
+	struct device *dev = container_of(kobj, struct device, kobj);
 	struct Scsi_Host *host = class_to_shost(dev);
-	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+	struct AdapterControlBlock *acb =
+		(struct AdapterControlBlock *)host->hostdata;
 	uint8_t *pQbuffer,*ptmpQbuffer;
 	int32_t allxfer_len = 0;
+	unsigned long flags;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
 
 	/* do message unit read. */
 	ptmpQbuffer = (uint8_t *)buf;
-	while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
-		&& (allxfer_len < 1031)) {
+	spin_lock_irqsave(&acb->rqbuffer_lock, flags);
+	if (acb->rqbuf_firstindex != acb->rqbuf_lastindex) {
 		pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
-		memcpy(ptmpQbuffer, pQbuffer, 1);
-		acb->rqbuf_firstindex++;
-		acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
-		ptmpQbuffer++;
-		allxfer_len++;
+		if (acb->rqbuf_firstindex > acb->rqbuf_lastindex) {
+			if ((ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex) >= 1032) {
+				memcpy(ptmpQbuffer, pQbuffer, 1032);
+				acb->rqbuf_firstindex += 1032;
+				allxfer_len = 1032;
+			} else {
+				if (((ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex) + acb->rqbuf_lastindex) > 1032) {
+					memcpy(ptmpQbuffer, pQbuffer, ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex);
+					ptmpQbuffer += ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex;
+					memcpy(ptmpQbuffer, acb->rqbuffer, 1032 - (ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex));
+					acb->rqbuf_firstindex = 1032 - (ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex);
+					allxfer_len = 1032;
+				} else {
+					memcpy(ptmpQbuffer, pQbuffer, ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex);
+					ptmpQbuffer += ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex;
+					memcpy(ptmpQbuffer, acb->rqbuffer, acb->rqbuf_lastindex);
+					allxfer_len = ARCMSR_MAX_QBUFFER - acb->rqbuf_firstindex + acb->rqbuf_lastindex;
+					acb->rqbuf_firstindex = acb->rqbuf_lastindex;
+				}
+			}
+		} else {
+			if ((acb->rqbuf_lastindex - acb->rqbuf_firstindex) > 1032) {
+				memcpy(ptmpQbuffer, pQbuffer, 1032);
+				acb->rqbuf_firstindex += 1032;
+				allxfer_len = 1032;
+			} else {
+				memcpy(ptmpQbuffer, pQbuffer, acb->rqbuf_lastindex - acb->rqbuf_firstindex);
+				allxfer_len = acb->rqbuf_lastindex - acb->rqbuf_firstindex;
+				acb->rqbuf_firstindex = acb->rqbuf_lastindex;
+			}
+		}
 	}
 	if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 		struct QBUFFER __iomem *prbuffer;
-		uint8_t __iomem *iop_data;
-		int32_t iop_len;
-
-		acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+		uint8_t __iomem *iop_data, *vaddr, *temp;
+			int32_t data_len_residual, data_len, rqbuf_lastindex;
+			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+		rqbuf_lastindex = acb->rqbuf_lastindex;
 		prbuffer = arcmsr_get_iop_rqbuffer(acb);
-		iop_data = prbuffer->data;
-		iop_len = readl(&prbuffer->data_len);
-		while (iop_len > 0) {
-			acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
-			acb->rqbuf_lastindex++;
-			acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-			iop_data++;
-			iop_len--;
+		iop_data = (uint8_t __iomem *)prbuffer->data;
+		data_len_residual = data_len = readl(&prbuffer->data_len);
+		if (data_len > 0) {
+			temp = vaddr = kmalloc(data_len, GFP_ATOMIC);
+			do {
+				memcpy(temp, iop_data, 4);
+				temp += 4;
+				iop_data += 4;
+				data_len_residual -= 4;
+			} while (data_len_residual > 0);
+			pQbuffer = &acb->rqbuffer[acb->rqbuf_lastindex];
+			temp = vaddr;
+			if ((rqbuf_lastindex + data_len) > ARCMSR_MAX_QBUFFER) {
+				memcpy(pQbuffer, temp, ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+				temp += (ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+				rqbuf_lastindex = (rqbuf_lastindex + data_len) % ARCMSR_MAX_QBUFFER;
+				memcpy(&acb->rqbuffer[0], temp, rqbuf_lastindex);
+			} else {
+				memcpy(pQbuffer, temp, data_len);
+				rqbuf_lastindex = (rqbuf_lastindex + data_len) % ARCMSR_MAX_QBUFFER;
+			}
+			kfree(vaddr);
 		}
+		acb->rqbuf_lastindex = rqbuf_lastindex;
 		arcmsr_iop_message_read(acb);
 	}
+	spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
 	return (allxfer_len);
 }
 
-static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp,
-					      struct kobject *kobj,
-					      struct bin_attribute *bin,
-					      char *buf, loff_t off,
-					      size_t count)
+static ssize_t
+arcmsr_sysfs_iop_message_write(struct file *filp,
+				      struct kobject *kobj,
+				      struct bin_attribute *bin,
+				      char *buf, loff_t off,
+				      size_t count)
 {
-	struct device *dev = container_of(kobj,struct device,kobj);
+	struct device *dev = container_of(kobj, struct device, kobj);
 	struct Scsi_Host *host = class_to_shost(dev);
-	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+	struct AdapterControlBlock *acb =
+		(struct AdapterControlBlock *)host->hostdata;
 	int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
 	uint8_t *pQbuffer, *ptmpuserbuffer;
+	unsigned long flags;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -125,10 +173,12 @@ static ssize_t arcmsr_sysfs_iop_message_
 	/* do message unit write. */
 	ptmpuserbuffer = (uint8_t *)buf;
 	user_len = (int32_t)count;
+	spin_lock_irqsave(&acb->wqbuffer_lock, flags);
 	wqbuf_lastindex = acb->wqbuf_lastindex;
 	wqbuf_firstindex = acb->wqbuf_firstindex;
 	if (wqbuf_lastindex != wqbuf_firstindex) {
 		arcmsr_post_ioctldata2iop(acb);
+		spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
 		return 0;	/*need retry*/
 	} else {
 		my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
@@ -139,32 +189,39 @@ static ssize_t arcmsr_sysfs_iop_message_
 				&acb->wqbuffer[acb->wqbuf_lastindex];
 				memcpy(pQbuffer, ptmpuserbuffer, 1);
 				acb->wqbuf_lastindex++;
-				acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
+				acb->wqbuf_lastindex %=
+					ARCMSR_MAX_QBUFFER;
 				ptmpuserbuffer++;
 				user_len--;
 			}
-			if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
+			if (acb->acb_flags &
+				ACB_F_MESSAGE_WQBUFFER_CLEARED) {
 				acb->acb_flags &=
 					~ACB_F_MESSAGE_WQBUFFER_CLEARED;
 				arcmsr_post_ioctldata2iop(acb);
 			}
+			spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
 			return count;
 		} else {
+			spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
 			return 0;	/*need retry*/
 		}
 	}
 }
 
-static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp,
-					      struct kobject *kobj,
-					      struct bin_attribute *bin,
-					      char *buf, loff_t off,
-					      size_t count)
+static ssize_t
+arcmsr_sysfs_iop_message_clear(struct file *filp,
+				      struct kobject *kobj,
+				      struct bin_attribute *bin,
+				      char *buf, loff_t off,
+				      size_t count)
 {
-	struct device *dev = container_of(kobj,struct device,kobj);
+	struct device *dev = container_of(kobj, struct device, kobj);
 	struct Scsi_Host *host = class_to_shost(dev);
-	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+	struct AdapterControlBlock *acb =
+		(struct AdapterControlBlock *)host->hostdata;
 	uint8_t *pQbuffer;
+	unsigned long flags;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EACCES;
@@ -177,10 +234,14 @@ static ssize_t arcmsr_sysfs_iop_message_
 		(ACB_F_MESSAGE_WQBUFFER_CLEARED
 		| ACB_F_MESSAGE_RQBUFFER_CLEARED
 		| ACB_F_MESSAGE_WQBUFFER_READED);
+	spin_lock_irqsave(&acb->rqbuffer_lock, flags);
 	acb->rqbuf_firstindex = 0;
 	acb->rqbuf_lastindex = 0;
+	spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
+	spin_lock_irqsave(&acb->wqbuffer_lock, flags);
 	acb->wqbuf_firstindex = 0;
 	acb->wqbuf_lastindex = 0;
+	spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
 	pQbuffer = acb->rqbuffer;
 	memset(pQbuffer, 0, sizeof (struct QBUFFER));
 	pQbuffer = acb->wqbuffer;
@@ -215,31 +276,37 @@ static struct bin_attribute arcmsr_sysfs
 	.write = arcmsr_sysfs_iop_message_clear,
 };
 
-int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
+int
+arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
 {
 	struct Scsi_Host *host = acb->host;
 	int error;
 
-	error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr);
+	error = sysfs_create_bin_file(&host->shost_dev.kobj,
+		&arcmsr_sysfs_message_read_attr);
 	if (error) {
-		printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
+		pr_err("arcmsr: alloc sysfs mu_read failed\n");
 		goto error_bin_file_message_read;
 	}
-	error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr);
+	error = sysfs_create_bin_file(&host->shost_dev.kobj,
+		&arcmsr_sysfs_message_write_attr);
 	if (error) {
-		printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
+		pr_err("arcmsr: alloc sysfs mu_write failed\n");
 		goto error_bin_file_message_write;
 	}
-	error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_clear_attr);
+	error = sysfs_create_bin_file(&host->shost_dev.kobj,
+		&arcmsr_sysfs_message_clear_attr);
 	if (error) {
-		printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
+		pr_err("arcmsr: alloc sysfs mu_clear failed\n");
 		goto error_bin_file_message_clear;
 	}
 	return 0;
 error_bin_file_message_clear:
-	sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr);
+	sysfs_remove_bin_file(&host->shost_dev.kobj,
+		&arcmsr_sysfs_message_write_attr);
 error_bin_file_message_write:
-	sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr);
+	sysfs_remove_bin_file(&host->shost_dev.kobj,
+		&arcmsr_sysfs_message_read_attr);
 error_bin_file_message_read:
 	return error;
 }
@@ -248,15 +315,17 @@ void arcmsr_free_sysfs_attr(struct Adapt
 {
 	struct Scsi_Host *host = acb->host;
 
-	sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_clear_attr);
-	sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr);
-	sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr);
+	sysfs_remove_bin_file(&host->shost_dev.kobj,
+		&arcmsr_sysfs_message_clear_attr);
+	sysfs_remove_bin_file(&host->shost_dev.kobj,
+		&arcmsr_sysfs_message_write_attr);
+	sysfs_remove_bin_file(&host->shost_dev.kobj,
+		&arcmsr_sysfs_message_read_attr);
 }
 
-
 static ssize_t
 arcmsr_attr_host_driver_version(struct device *dev,
-				struct device_attribute *attr, char *buf)
+			struct device_attribute *attr, char *buf)
 {
 	return snprintf(buf, PAGE_SIZE,
 			"%s\n",
@@ -265,11 +334,11 @@ arcmsr_attr_host_driver_version(struct d
 
 static ssize_t
 arcmsr_attr_host_driver_posted_cmd(struct device *dev,
-				   struct device_attribute *attr, char *buf)
+			struct device_attribute *attr, char *buf)
 {
 	struct Scsi_Host *host = class_to_shost(dev);
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
+		(struct AdapterControlBlock *)host->hostdata;
 	return snprintf(buf, PAGE_SIZE,
 			"%4d\n",
 			atomic_read(&acb->ccboutstandingcount));
@@ -281,7 +350,7 @@ arcmsr_attr_host_driver_reset(struct dev
 {
 	struct Scsi_Host *host = class_to_shost(dev);
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
+		(struct AdapterControlBlock *)host->hostdata;
 	return snprintf(buf, PAGE_SIZE,
 			"%4d\n",
 			acb->num_resets);
@@ -293,19 +362,19 @@ arcmsr_attr_host_driver_abort(struct dev
 {
 	struct Scsi_Host *host = class_to_shost(dev);
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
+		(struct AdapterControlBlock *)host->hostdata;
 	return snprintf(buf, PAGE_SIZE,
 			"%4d\n",
 			acb->num_aborts);
 }
 
 static ssize_t
-arcmsr_attr_host_fw_model(struct device *dev, struct device_attribute *attr,
-			  char *buf)
+arcmsr_attr_host_fw_model(struct device *dev,
+			struct device_attribute *attr, char *buf)
 {
 	struct Scsi_Host *host = class_to_shost(dev);
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
+		(struct AdapterControlBlock *)host->hostdata;
 	return snprintf(buf, PAGE_SIZE,
 			"%s\n",
 			acb->firm_model);
@@ -317,8 +386,7 @@ arcmsr_attr_host_fw_version(struct devic
 {
 	struct Scsi_Host *host = class_to_shost(dev);
 	struct AdapterControlBlock *acb =
-			(struct AdapterControlBlock *) host->hostdata;
-
+			(struct AdapterControlBlock *)host->hostdata;
 	return snprintf(buf, PAGE_SIZE,
 			"%s\n",
 			acb->firm_version);
@@ -330,7 +398,7 @@ arcmsr_attr_host_fw_request_len(struct d
 {
 	struct Scsi_Host *host = class_to_shost(dev);
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
+		(struct AdapterControlBlock *)host->hostdata;
 
 	return snprintf(buf, PAGE_SIZE,
 			"%4d\n",
@@ -343,7 +411,7 @@ arcmsr_attr_host_fw_numbers_queue(struct
 {
 	struct Scsi_Host *host = class_to_shost(dev);
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
+		(struct AdapterControlBlock *)host->hostdata;
 
 	return snprintf(buf, PAGE_SIZE,
 			"%4d\n",
@@ -356,7 +424,7 @@ arcmsr_attr_host_fw_sdram_size(struct de
 {
 	struct Scsi_Host *host = class_to_shost(dev);
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
+		(struct AdapterControlBlock *)host->hostdata;
 
 	return snprintf(buf, PAGE_SIZE,
 			"%4d\n",
@@ -369,23 +437,33 @@ arcmsr_attr_host_fw_hd_channels(struct d
 {
 	struct Scsi_Host *host = class_to_shost(dev);
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
+		(struct AdapterControlBlock *)host->hostdata;
 
 	return snprintf(buf, PAGE_SIZE,
 			"%4d\n",
 			acb->firm_hd_channels);
 }
 
-static DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL);
-static DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO, arcmsr_attr_host_driver_posted_cmd, NULL);
-static DEVICE_ATTR(host_driver_reset, S_IRUGO, arcmsr_attr_host_driver_reset, NULL);
-static DEVICE_ATTR(host_driver_abort, S_IRUGO, arcmsr_attr_host_driver_abort, NULL);
-static DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL);
-static DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL);
-static DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL);
-static DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL);
-static DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL);
-static DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL);
+static DEVICE_ATTR(host_driver_version, S_IRUGO,
+	arcmsr_attr_host_driver_version, NULL);
+static DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO,
+	arcmsr_attr_host_driver_posted_cmd, NULL);
+static DEVICE_ATTR(host_driver_reset, S_IRUGO,
+	arcmsr_attr_host_driver_reset, NULL);
+static DEVICE_ATTR(host_driver_abort, S_IRUGO,
+	arcmsr_attr_host_driver_abort, NULL);
+static DEVICE_ATTR(host_fw_model, S_IRUGO,
+	arcmsr_attr_host_fw_model, NULL);
+static DEVICE_ATTR(host_fw_version, S_IRUGO,
+	arcmsr_attr_host_fw_version, NULL);
+static DEVICE_ATTR(host_fw_request_len, S_IRUGO,
+	arcmsr_attr_host_fw_request_len, NULL);
+static DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO,
+	arcmsr_attr_host_fw_numbers_queue, NULL);
+static DEVICE_ATTR(host_fw_sdram_size, S_IRUGO,
+	arcmsr_attr_host_fw_sdram_size, NULL);
+static DEVICE_ATTR(host_fw_hd_channels, S_IRUGO,
+	arcmsr_attr_host_fw_hd_channels, NULL);
 
 struct device_attribute *arcmsr_host_attrs[] = {
 	&dev_attr_host_driver_version,
diff -uprN a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
--- a/drivers/scsi/arcmsr/arcmsr.h	2013-07-01 06:13:28.000000000 +0800
+++ b/drivers/scsi/arcmsr/arcmsr.h	2013-08-26 19:23:24.000000000 +0800
@@ -45,42 +45,48 @@
 #include <linux/interrupt.h>
 struct device_attribute;
 /*The limit of outstanding scsi command that firmware can handle*/
-#define ARCMSR_MAX_OUTSTANDING_CMD						256
+#define ARCMSR_MAX_OUTSTANDING_CMD		256
 #ifdef CONFIG_XEN
 	#define ARCMSR_MAX_FREECCB_NUM	160
 #else
 	#define ARCMSR_MAX_FREECCB_NUM	320
 #endif
-#define ARCMSR_DRIVER_VERSION		     "Driver Version 1.20.00.15 2010/08/05"
-#define ARCMSR_SCSI_INITIATOR_ID						255
-#define ARCMSR_MAX_XFER_SECTORS							512
-#define ARCMSR_MAX_XFER_SECTORS_B						4096
-#define ARCMSR_MAX_XFER_SECTORS_C						304
-#define ARCMSR_MAX_TARGETID							17
-#define ARCMSR_MAX_TARGETLUN							8
-#define ARCMSR_MAX_CMD_PERLUN		                 ARCMSR_MAX_OUTSTANDING_CMD
-#define ARCMSR_MAX_QBUFFER							4096
-#define ARCMSR_DEFAULT_SG_ENTRIES						38
-#define ARCMSR_MAX_HBB_POSTQUEUE						264
-#define ARCMSR_MAX_XFER_LEN							0x26000 /* 152K */
-#define ARCMSR_CDB_SG_PAGE_LENGTH						256 
+#define ARCMSR_DRIVER_VERSION		"Driver Version 1.30.00.00 2013/05/06"
+#define ARCMSR_SCSI_INITIATOR_ID		255
+#define ARCMSR_MAX_XFER_SECTORS		512
+#define ARCMSR_MAX_XFER_SECTORS_B		4096
+#define ARCMSR_MAX_XFER_SECTORS_C		304
+#define ARCMSR_MAX_TARGETID			17
+#define ARCMSR_MAX_TARGETLUN			8
+#define ARCMSR_MAX_CMD_PERLUN			ARCMSR_MAX_OUTSTANDING_CMD
+#define ARCMSR_MAX_QBUFFER			4096
+#define ARCMSR_DEFAULT_SG_ENTRIES		38
+#define ARCMSR_MAX_HBB_POSTQUEUE		264
+#define ARCMSR_MAX_ARC1214_POSTQUEUE		256
+#define ARCMSR_MAX_ARC1214_DONEQUEUE		257
+#define ARCMSR_MAX_XFER_LEN			0x26000
+#define ARCMSR_CDB_SG_PAGE_LENGTH		256
+#define ARCMST_NUM_MSIX_VECTORS		4
 #ifndef PCI_DEVICE_ID_ARECA_1880
-#define PCI_DEVICE_ID_ARECA_1880 0x1880
- #endif
+	#define PCI_DEVICE_ID_ARECA_1880	0x1880
+#endif
+#ifndef PCI_DEVICE_ID_ARECA_1214
+	#define PCI_DEVICE_ID_ARECA_1214	0x1214
+#endif
 /*
 **********************************************************************************
 **
 **********************************************************************************
 */
-#define ARC_SUCCESS                                                       0
-#define ARC_FAILURE                                                       1
+#define ARC_SUCCESS				0
+#define ARC_FAILURE				1
 /*
 *******************************************************************************
 **        split 64bits dma addressing
 *******************************************************************************
 */
-#define dma_addr_hi32(addr)               (uint32_t) ((addr>>16)>>16)
-#define dma_addr_lo32(addr)               (uint32_t) (addr & 0xffffffff)
+#define dma_addr_hi32(addr)	(uint32_t)((addr >> 16) >> 16)
+#define dma_addr_lo32(addr)	(uint32_t)(addr & 0xffffffff)
 /*
 *******************************************************************************
 **        MESSAGE CONTROL CODE
@@ -88,12 +94,12 @@ struct device_attribute;
 */
 struct CMD_MESSAGE
 {
-      uint32_t HeaderLength;
-      uint8_t  Signature[8];
-      uint32_t Timeout;
-      uint32_t ControlCode;
-      uint32_t ReturnCode;
-      uint32_t Length;
+	uint32_t HeaderLength;
+	uint8_t Signature[8];
+	uint32_t Timeout;
+	uint32_t ControlCode;
+	uint32_t ReturnCode;
+	uint32_t Length;
 };
 /*
 *******************************************************************************
@@ -102,8 +108,8 @@ struct CMD_MESSAGE
 */
 struct CMD_MESSAGE_FIELD
 {
-    struct CMD_MESSAGE			cmdmessage;
-    uint8_t				messagedatabuffer[1032];
+	struct CMD_MESSAGE cmdmessage;
+	uint8_t messagedatabuffer[1032];
 };
 /* IOP message transfer */
 #define ARCMSR_MESSAGE_FAIL			0x0001
@@ -111,57 +117,57 @@ struct CMD_MESSAGE_FIELD
 #define ARECA_SATA_RAID				0x90000000
 /* FunctionCode */
 #define FUNCTION_READ_RQBUFFER			0x0801
-#define FUNCTION_WRITE_WQBUFFER			0x0802
-#define FUNCTION_CLEAR_RQBUFFER			0x0803
-#define FUNCTION_CLEAR_WQBUFFER			0x0804
+#define FUNCTION_WRITE_WQBUFFER		0x0802
+#define FUNCTION_CLEAR_RQBUFFER		0x0803
+#define FUNCTION_CLEAR_WQBUFFER		0x0804
 #define FUNCTION_CLEAR_ALLQBUFFER		0x0805
-#define FUNCTION_RETURN_CODE_3F			0x0806
+#define FUNCTION_RETURN_CODE_3F		0x0806
 #define FUNCTION_SAY_HELLO			0x0807
 #define FUNCTION_SAY_GOODBYE			0x0808
 #define FUNCTION_FLUSH_ADAPTER_CACHE		0x0809
-#define FUNCTION_GET_FIRMWARE_STATUS			0x080A
-#define FUNCTION_HARDWARE_RESET			0x080B
+#define FUNCTION_GET_FIRMWARE_STATUS		0x080A
+#define FUNCTION_HARDWARE_RESET		0x080B
 /* ARECA IO CONTROL CODE*/
-#define ARCMSR_MESSAGE_READ_RQBUFFER       \
-	ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
-#define ARCMSR_MESSAGE_WRITE_WQBUFFER      \
-	ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER
-#define ARCMSR_MESSAGE_CLEAR_RQBUFFER      \
-	ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER
-#define ARCMSR_MESSAGE_CLEAR_WQBUFFER      \
-	ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER
-#define ARCMSR_MESSAGE_CLEAR_ALLQBUFFER    \
-	ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER
-#define ARCMSR_MESSAGE_RETURN_CODE_3F      \
-	ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F
-#define ARCMSR_MESSAGE_SAY_HELLO           \
-	ARECA_SATA_RAID | FUNCTION_SAY_HELLO
-#define ARCMSR_MESSAGE_SAY_GOODBYE         \
-	ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE
-#define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \
-	ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE
+#define ARCMSR_MESSAGE_READ_RQBUFFER		\
+	(ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER)
+#define ARCMSR_MESSAGE_WRITE_WQBUFFER	\
+	(ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER)
+#define ARCMSR_MESSAGE_CLEAR_RQBUFFER	\
+	(ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER)
+#define ARCMSR_MESSAGE_CLEAR_WQBUFFER	\
+	(ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER)
+#define ARCMSR_MESSAGE_CLEAR_ALLQBUFFER	\
+	(ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER)
+#define ARCMSR_MESSAGE_RETURN_CODE_3F	\
+	(ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F)
+#define ARCMSR_MESSAGE_SAY_HELLO		\
+	(ARECA_SATA_RAID | FUNCTION_SAY_HELLO)
+#define ARCMSR_MESSAGE_SAY_GOODBYE		\
+	(ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE)
+#define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE	\
+	(ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE)
 /* ARECA IOCTL ReturnCode */
-#define ARCMSR_MESSAGE_RETURNCODE_OK		0x00000001
+#define ARCMSR_MESSAGE_RETURNCODE_OK			0x00000001
 #define ARCMSR_MESSAGE_RETURNCODE_ERROR		0x00000006
-#define ARCMSR_MESSAGE_RETURNCODE_3F		0x0000003F
+#define ARCMSR_MESSAGE_RETURNCODE_3F			0x0000003F
 #define ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON	0x00000088
 /*
 *************************************************************
 **   structure for holding DMA address data
 *************************************************************
 */
-#define IS_DMA64			(sizeof(dma_addr_t) == 8)
-#define IS_SG64_ADDR                0x01000000 /* bit24 */
+#define IS_DMA64		(sizeof(dma_addr_t) == 8)
+#define IS_SG64_ADDR	0x01000000 /* bit24 */
 struct  SG32ENTRY
 {
-	__le32					length;
-	__le32					address;
+	__le32 length;
+	__le32 address;
 }__attribute__ ((packed));
 struct  SG64ENTRY
 {
-	__le32					length;
-	__le32					address;
-	__le32					addresshigh;
+	__le32 length;
+	__le32 address;
+	__le32 addresshigh;
 }__attribute__ ((packed));
 /*
 ********************************************************************
@@ -170,8 +176,8 @@ struct  SG64ENTRY
 */
 struct QBUFFER
 {
-	uint32_t      data_len;
-	uint8_t       data[124];
+	uint32_t data_len;
+	uint8_t data[124];
 };
 /*
 *******************************************************************************
@@ -180,50 +186,50 @@ struct QBUFFER
 */
 struct FIRMWARE_INFO
 {
-	uint32_t      signature;		/*0, 00-03*/
-	uint32_t      request_len;		/*1, 04-07*/
-	uint32_t      numbers_queue;		/*2, 08-11*/
-	uint32_t      sdram_size;               /*3, 12-15*/
-	uint32_t      ide_channels;		/*4, 16-19*/
-	char          vendor[40];		/*5, 20-59*/
-	char          model[8];			/*15, 60-67*/
-	char          firmware_ver[16];     	/*17, 68-83*/
-	char          device_map[16];		/*21, 84-99*/
-	uint32_t		cfgVersion;               	/*25,100-103 Added for checking of new firmware capability*/
-	uint8_t		cfgSerial[16];           	/*26,104-119*/
-	uint32_t		cfgPicStatus;            	/*30,120-123*/	
+	uint32_t signature;	/*0, 00-03*/
+	uint32_t request_len;	/*1, 04-07*/
+	uint32_t numbers_queue;	/*2, 08-11*/
+	uint32_t sdram_size;	/*3, 12-15*/
+	uint32_t ide_channels;	/*4, 16-19*/
+	char vendor[40];		/*5, 20-59*/
+	char model[8];		/*15, 60-67*/
+	char firmware_ver[16];	/*17, 68-83*/
+	char device_map[16];	/*21, 84-99*/
+	uint32_t cfgVersion;	/*25, 100-103*/
+	uint8_t cfgSerial[16];	/*26, 104-119*/
+	uint32_t cfgPicStatus;	/*30, 120-123*/
 };
 /* signature of set and get firmware config */
-#define ARCMSR_SIGNATURE_GET_CONFIG		      0x87974060
-#define ARCMSR_SIGNATURE_SET_CONFIG		      0x87974063
+#define ARCMSR_SIGNATURE_GET_CONFIG		0x87974060
+#define ARCMSR_SIGNATURE_SET_CONFIG		0x87974063
 /* message code of inbound message register */
-#define ARCMSR_INBOUND_MESG0_NOP		      0x00000000
-#define ARCMSR_INBOUND_MESG0_GET_CONFIG		      0x00000001
-#define ARCMSR_INBOUND_MESG0_SET_CONFIG               0x00000002
-#define ARCMSR_INBOUND_MESG0_ABORT_CMD                0x00000003
-#define ARCMSR_INBOUND_MESG0_STOP_BGRB                0x00000004
-#define ARCMSR_INBOUND_MESG0_FLUSH_CACHE              0x00000005
-#define ARCMSR_INBOUND_MESG0_START_BGRB               0x00000006
-#define ARCMSR_INBOUND_MESG0_CHK331PENDING            0x00000007
-#define ARCMSR_INBOUND_MESG0_SYNC_TIMER               0x00000008
+#define ARCMSR_INBOUND_MESG0_NOP		0x00000000
+#define ARCMSR_INBOUND_MESG0_GET_CONFIG	0x00000001
+#define ARCMSR_INBOUND_MESG0_SET_CONFIG	0x00000002
+#define ARCMSR_INBOUND_MESG0_ABORT_CMD	0x00000003
+#define ARCMSR_INBOUND_MESG0_STOP_BGRB	0x00000004
+#define ARCMSR_INBOUND_MESG0_FLUSH_CACHE	0x00000005
+#define ARCMSR_INBOUND_MESG0_START_BGRB	0x00000006
+#define ARCMSR_INBOUND_MESG0_CHK331PENDING	0x00000007
+#define ARCMSR_INBOUND_MESG0_SYNC_TIMER	0x00000008
 /* doorbell interrupt generator */
-#define ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK           0x00000001
-#define ARCMSR_INBOUND_DRIVER_DATA_READ_OK            0x00000002
-#define ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK          0x00000001
-#define ARCMSR_OUTBOUND_IOP331_DATA_READ_OK           0x00000002
+#define ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK	0x00000001
+#define ARCMSR_INBOUND_DRIVER_DATA_READ_OK	0x00000002
+#define ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK	0x00000001
+#define ARCMSR_OUTBOUND_IOP331_DATA_READ_OK	0x00000002
 /* ccb areca cdb flag */
-#define ARCMSR_CCBPOST_FLAG_SGL_BSIZE                 0x80000000
-#define ARCMSR_CCBPOST_FLAG_IAM_BIOS                  0x40000000
-#define ARCMSR_CCBREPLY_FLAG_IAM_BIOS                 0x40000000
-#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE0              0x10000000
-#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE1              0x00000001
+#define ARCMSR_CCBPOST_FLAG_SGL_BSIZE		0x80000000
+#define ARCMSR_CCBPOST_FLAG_IAM_BIOS		0x40000000
+#define ARCMSR_CCBREPLY_FLAG_IAM_BIOS		0x40000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE0	0x10000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE1	0x00000001
 /* outbound firmware ok */
-#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK             0x80000000
+#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK	0x80000000
 /* ARC-1680 Bus Reset*/
-#define ARCMSR_ARC1680_BUS_RESET				0x00000003
+#define ARCMSR_ARC1680_BUS_RESET		0x00000003
 /* ARC-1880 Bus Reset*/
-#define ARCMSR_ARC1880_RESET_ADAPTER				0x00000024
-#define ARCMSR_ARC1880_DiagWrite_ENABLE			0x00000080
+#define ARCMSR_ARC1880_RESET_ADAPTER		0x00000024
+#define ARCMSR_ARC1880_DiagWrite_ENABLE	0x00000080
 
 /*
 ************************************************************************
@@ -232,98 +238,101 @@ struct FIRMWARE_INFO
 */
 /* ARECA HBB COMMAND for its FIRMWARE */
 /* window of "instruction flags" from driver to iop */
-#define ARCMSR_DRV2IOP_DOORBELL                       0x00020400
-#define ARCMSR_DRV2IOP_DOORBELL_MASK                  0x00020404
+#define ARCMSR_DRV2IOP_DOORBELL		0x00020400
+#define ARCMSR_DRV2IOP_DOORBELL_MASK		0x00020404
 /* window of "instruction flags" from iop to driver */
-#define ARCMSR_IOP2DRV_DOORBELL                       0x00020408
-#define ARCMSR_IOP2DRV_DOORBELL_MASK                  0x0002040C
+#define ARCMSR_IOP2DRV_DOORBELL		0x00020408
+#define ARCMSR_IOP2DRV_DOORBELL_MASK		0x0002040C
 /* ARECA FLAG LANGUAGE */
 /* ioctl transfer */
-#define ARCMSR_IOP2DRV_DATA_WRITE_OK                  0x00000001
+#define ARCMSR_IOP2DRV_DATA_WRITE_OK		0x00000001
 /* ioctl transfer */
-#define ARCMSR_IOP2DRV_DATA_READ_OK                   0x00000002
-#define ARCMSR_IOP2DRV_CDB_DONE                       0x00000004
-#define ARCMSR_IOP2DRV_MESSAGE_CMD_DONE               0x00000008
-
-#define ARCMSR_DOORBELL_HANDLE_INT		      0x0000000F
-#define ARCMSR_DOORBELL_INT_CLEAR_PATTERN   	      0xFF00FFF0
-#define ARCMSR_MESSAGE_INT_CLEAR_PATTERN	      0xFF00FFF7
+#define ARCMSR_IOP2DRV_DATA_READ_OK		0x00000002
+#define ARCMSR_IOP2DRV_CDB_DONE		0x00000004
+#define ARCMSR_IOP2DRV_MESSAGE_CMD_DONE	0x00000008
+
+#define ARCMSR_DOORBELL_HANDLE_INT		0x0000000F
+#define ARCMSR_DOORBELL_INT_CLEAR_PATTERN	0xFF00FFF0
+#define ARCMSR_MESSAGE_INT_CLEAR_PATTERN	0xFF00FFF7
 /* (ARCMSR_INBOUND_MESG0_GET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
-#define ARCMSR_MESSAGE_GET_CONFIG		      0x00010008
+#define ARCMSR_MESSAGE_GET_CONFIG		0x00010008
 /* (ARCMSR_INBOUND_MESG0_SET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
-#define ARCMSR_MESSAGE_SET_CONFIG		      0x00020008
+#define ARCMSR_MESSAGE_SET_CONFIG		0x00020008
 /* (ARCMSR_INBOUND_MESG0_ABORT_CMD<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
-#define ARCMSR_MESSAGE_ABORT_CMD		      0x00030008
+#define ARCMSR_MESSAGE_ABORT_CMD		0x00030008
 /* (ARCMSR_INBOUND_MESG0_STOP_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
-#define ARCMSR_MESSAGE_STOP_BGRB		      0x00040008
+#define ARCMSR_MESSAGE_STOP_BGRB		0x00040008
 /* (ARCMSR_INBOUND_MESG0_FLUSH_CACHE<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
-#define ARCMSR_MESSAGE_FLUSH_CACHE                    0x00050008
+#define ARCMSR_MESSAGE_FLUSH_CACHE		0x00050008
 /* (ARCMSR_INBOUND_MESG0_START_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
-#define ARCMSR_MESSAGE_START_BGRB		      0x00060008
-#define ARCMSR_MESSAGE_START_DRIVER_MODE	      0x000E0008
-#define ARCMSR_MESSAGE_SET_POST_WINDOW		      0x000F0008
-#define ARCMSR_MESSAGE_ACTIVE_EOI_MODE		    0x00100008
+#define ARCMSR_MESSAGE_START_BGRB		0x00060008
+#define ARCMSR_MESSAGE_START_DRIVER_MODE	0x000E0008
+#define ARCMSR_MESSAGE_SET_POST_WINDOW	0x000F0008
+#define ARCMSR_MESSAGE_ACTIVE_EOI_MODE	0x00100008
 /* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */
-#define ARCMSR_MESSAGE_FIRMWARE_OK		      0x80000000
+#define ARCMSR_MESSAGE_FIRMWARE_OK		0x80000000
 /* ioctl transfer */
-#define ARCMSR_DRV2IOP_DATA_WRITE_OK                  0x00000001
+#define ARCMSR_DRV2IOP_DATA_WRITE_OK		0x00000001
 /* ioctl transfer */
-#define ARCMSR_DRV2IOP_DATA_READ_OK                   0x00000002
-#define ARCMSR_DRV2IOP_CDB_POSTED                     0x00000004
-#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED             0x00000008
-#define ARCMSR_DRV2IOP_END_OF_INTERRUPT		0x00000010
+#define ARCMSR_DRV2IOP_DATA_READ_OK		0x00000002
+#define ARCMSR_DRV2IOP_CDB_POSTED		0x00000004
+#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED	0x00000008
+#define ARCMSR_DRV2IOP_END_OF_INTERRUPT	0x00000010
 
 /* data tunnel buffer between user space program and its firmware */
 /* user space data to iop 128bytes */
-#define ARCMSR_MESSAGE_WBUFFER			      0x0000fe00
+#define ARCMSR_MESSAGE_WBUFFER		0x0000fe00
 /* iop data to user space 128bytes */
-#define ARCMSR_MESSAGE_RBUFFER			      0x0000ff00
+#define ARCMSR_MESSAGE_RBUFFER		0x0000ff00
 /* iop message_rwbuffer for message command */
-#define ARCMSR_MESSAGE_RWBUFFER			      0x0000fa00
+#define ARCMSR_MESSAGE_RWBUFFER		0x0000fa00
 /* 
 ************************************************************************
 **                SPEC. for Areca HBC adapter
 ************************************************************************
 */
-#define ARCMSR_HBC_ISR_THROTTLING_LEVEL		12
-#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE		20
+#define ARCMSR_HBC_ISR_THROTTLING_LEVEL	12
+#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE	20
 /* Host Interrupt Mask */
-#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK		0x00000001 /* When clear, the Utility_A interrupt routes to the host.*/
-#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK	0x00000004 /* When clear, the General Outbound Doorbell interrupt routes to the host.*/
-#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK	0x00000008 /* When clear, the Outbound Post List FIFO Not Empty interrupt routes to the host.*/
-#define ARCMSR_HBCMU_ALL_INTMASKENABLE		0x0000000D /* disable all ISR */
+#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK		0x00000001
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK	0x00000004
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK	0x00000008
+#define ARCMSR_HBCMU_ALL_INTMASKENABLE		0x0000000D
 /* Host Interrupt Status */
 #define ARCMSR_HBCMU_UTILITY_A_ISR			0x00000001
-	/*
-	** Set when the Utility_A Interrupt bit is set in the Outbound Doorbell Register.
-	** It clears by writing a 1 to the Utility_A bit in the Outbound Doorbell Clear Register or through automatic clearing (if enabled).
-	*/
+/*
+** Set when the Utility_A Interrupt bit is set
+** in the Outbound Doorbell Register.
+** It clears by writing a 1 to the Utility_A
+** bit in the Outbound Doorbell Clear Register
+** or through automatic clearing (if enabled).
+*/
 #define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR		0x00000004
-	/*
-	** Set if Outbound Doorbell register bits 30:1 have a non-zero
-	** value. This bit clears only when Outbound Doorbell bits
-	** 30:1 are ALL clear. Only a write to the Outbound Doorbell
-	** Clear register clears bits in the Outbound Doorbell register.
-	*/
+/*
+** Set if Outbound Doorbell register bits 30:1 have a non-zero
+** value. This bit clears only when Outbound Doorbell bits
+** 30:1 are ALL clear. Only a write to the Outbound Doorbell
+** Clear register clears bits in the Outbound Doorbell register.
+*/
 #define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR	0x00000008
-	/*
-	** Set whenever the Outbound Post List Producer/Consumer
-	** Register (FIFO) is not empty. It clears when the Outbound
-	** Post List FIFO is empty.
-	*/
+/*
+** Set whenever the Outbound Post List Producer/Consumer
+** Register (FIFO) is not empty. It clears when the Outbound
+** Post List FIFO is empty.
+*/
 #define ARCMSR_HBCMU_SAS_ALL_INT			0x00000010
-	/*
-	** This bit indicates a SAS interrupt from a source external to
-	** the PCIe core. This bit is not maskable.
-	*/
-	/* DoorBell*/
-#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK			0x00000002
-#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK			0x00000004
+/*
+** This bit indicates a SAS interrupt from a source external to
+** the PCIe core. This bit is not maskable.
+*/
+/* DoorBell*/
+#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK		0x00000002
+#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK		0x00000004
 	/*inbound message 0 ready*/
-#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE		0x00000008
+#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE	0x00000008
 	/*more than 12 request completed in a time*/
-#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING		0x00000010
-#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK			0x00000002
+#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING	0x00000010
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK		0x00000002
 	/*outbound DATA WRITE isr door bell clear*/
 #define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR	0x00000002
 #define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK			0x00000004
@@ -337,40 +346,89 @@ struct FIRMWARE_INFO
 #define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK			0x80000000
 /*
 *******************************************************************************
+**                SPEC. for Areca Type D adapter
+*******************************************************************************
+*/
+#define ARCMSR_ARC1214_CHIP_ID					0x00004
+#define ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION		0x00008
+#define ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK		0x00034
+#define ARCMSR_ARC1214_SAMPLE_RESET				0x00100
+#define ARCMSR_ARC1214_RESET_REQUEST				0x00108
+#define ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS			0x00200
+#define ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE		0x0020C
+#define ARCMSR_ARC1214_INBOUND_MESSAGE0			0x00400
+#define ARCMSR_ARC1214_INBOUND_MESSAGE1			0x00404
+#define ARCMSR_ARC1214_OUTBOUND_MESSAGE0			0x00420
+#define ARCMSR_ARC1214_OUTBOUND_MESSAGE1			0x00424
+#define ARCMSR_ARC1214_INBOUND_DOORBELL			0x00460
+#define ARCMSR_ARC1214_OUTBOUND_DOORBELL			0x00480
+#define ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE		0x00484
+#define ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW		0x01000
+#define ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH		0x01004
+#define ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER		0x01018
+#define ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW		0x01060
+#define ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH		0x01064
+#define ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER		0x0106C
+#define ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER		0x01070
+#define ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE		0x01088
+#define ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE		0x0108C
+#define ARCMSR_ARC1214_MESSAGE_WBUFFER			0x02000
+#define ARCMSR_ARC1214_MESSAGE_RBUFFER			0x02100
+#define ARCMSR_ARC1214_MESSAGE_RWBUFFER			0x02200
+/* Host Interrupt Mask */
+#define ARCMSR_ARC1214_ALL_INT_ENABLE				0x00001010
+#define ARCMSR_ARC1214_ALL_INT_DISABLE			0x00000000
+/* Host Interrupt Status */
+#define ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR		0x00001000
+#define ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR		0x00000010
+/* DoorBell*/
+#define ARCMSR_ARC1214_DRV2IOP_DATA_IN_READY			0x00000001
+#define ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ		0x00000002
+/*inbound message 0 ready*/
+#define ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK		0x00000001
+/*outbound DATA WRITE isr door bell clear*/
+#define ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK			0x00000002
+/*outbound message 0 ready*/
+#define ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE		0x02000000
+/*outbound message cmd isr door bell clear*/
+/*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/
+#define ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK			0x80000000
+#define ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR	0x00000001
+/*
+*******************************************************************************
 **    ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
 *******************************************************************************
 */
 struct ARCMSR_CDB
 {
-	uint8_t							Bus;
-	uint8_t							TargetID;
-	uint8_t							LUN;
-	uint8_t							Function;
-	uint8_t							CdbLength;
-	uint8_t							sgcount;
-	uint8_t							Flags;
-#define ARCMSR_CDB_FLAG_SGL_BSIZE          0x01
-#define ARCMSR_CDB_FLAG_BIOS               0x02
-#define ARCMSR_CDB_FLAG_WRITE              0x04
-#define ARCMSR_CDB_FLAG_SIMPLEQ            0x00
-#define ARCMSR_CDB_FLAG_HEADQ              0x08
-#define ARCMSR_CDB_FLAG_ORDEREDQ           0x10
-
-	uint8_t							msgPages;
-	uint32_t						Context;
-	uint32_t						DataLength;
-	uint8_t							Cdb[16];
-	uint8_t							DeviceStatus;
-#define ARCMSR_DEV_CHECK_CONDITION	    0x02
-#define ARCMSR_DEV_SELECT_TIMEOUT	    0xF0
-#define ARCMSR_DEV_ABORTED		    0xF1
-#define ARCMSR_DEV_INIT_FAIL		    0xF2
-
-	uint8_t							SenseData[15];
-	union
-	{
-		struct SG32ENTRY                sg32entry[1];
-		struct SG64ENTRY                sg64entry[1];
+	uint8_t Bus;
+	uint8_t TargetID;
+	uint8_t LUN;
+	uint8_t Function;
+	uint8_t CdbLength;
+	uint8_t sgcount;
+	uint8_t Flags;
+#define ARCMSR_CDB_FLAG_SGL_BSIZE	0x01
+#define ARCMSR_CDB_FLAG_BIOS		0x02
+#define ARCMSR_CDB_FLAG_WRITE		0x04
+#define ARCMSR_CDB_FLAG_SIMPLEQ	0x00
+#define ARCMSR_CDB_FLAG_HEADQ		0x08
+#define ARCMSR_CDB_FLAG_ORDEREDQ	0x10
+
+	uint8_t msgPages;
+	uint32_t msgContext;
+	uint32_t DataLength;
+	uint8_t Cdb[16];
+	uint8_t DeviceStatus;
+#define ARCMSR_DEV_CHECK_CONDITION	0x02
+#define ARCMSR_DEV_SELECT_TIMEOUT	0xF0
+#define ARCMSR_DEV_ABORTED		0xF1
+#define ARCMSR_DEV_INIT_FAIL		0xF2
+
+	uint8_t SenseData[15];
+	union {
+		struct SG32ENTRY sg32entry[1];
+		struct SG64ENTRY sg64entry[1];
 	} u;
 };
 /*
@@ -380,118 +438,162 @@ struct ARCMSR_CDB
 */
 struct MessageUnit_A
 {
-	uint32_t	resrved0[4];			/*0000 000F*/
-	uint32_t	inbound_msgaddr0;		/*0010 0013*/
-	uint32_t	inbound_msgaddr1;		/*0014 0017*/
-	uint32_t	outbound_msgaddr0;		/*0018 001B*/
-	uint32_t	outbound_msgaddr1;		/*001C 001F*/
-	uint32_t	inbound_doorbell;		/*0020 0023*/
-	uint32_t	inbound_intstatus;		/*0024 0027*/
-	uint32_t	inbound_intmask;		/*0028 002B*/
-	uint32_t	outbound_doorbell;		/*002C 002F*/
-	uint32_t	outbound_intstatus;		/*0030 0033*/
-	uint32_t	outbound_intmask;		/*0034 0037*/
-	uint32_t	reserved1[2];			/*0038 003F*/
-	uint32_t	inbound_queueport;		/*0040 0043*/
-	uint32_t	outbound_queueport;     	/*0044 0047*/
-	uint32_t	reserved2[2];			/*0048 004F*/
-	uint32_t	reserved3[492];			/*0050 07FF 492*/
-	uint32_t	reserved4[128];			/*0800 09FF 128*/
-	uint32_t	message_rwbuffer[256];		/*0a00 0DFF 256*/
-	uint32_t	message_wbuffer[32];		/*0E00 0E7F  32*/
-	uint32_t	reserved5[32];			/*0E80 0EFF  32*/
-	uint32_t	message_rbuffer[32];		/*0F00 0F7F  32*/
-	uint32_t	reserved6[32];			/*0F80 0FFF  32*/
+	uint32_t resrved0[4];		/*0000 000F*/
+	uint32_t inbound_msgaddr0;	/*0010 0013*/
+	uint32_t inbound_msgaddr1;	/*0014 0017*/
+	uint32_t outbound_msgaddr0;	/*0018 001B*/
+	uint32_t outbound_msgaddr1;	/*001C 001F*/
+	uint32_t inbound_doorbell;		/*0020 0023*/
+	uint32_t inbound_intstatus;		/*0024 0027*/
+	uint32_t inbound_intmask;		/*0028 002B*/
+	uint32_t outbound_doorbell;	/*002C 002F*/
+	uint32_t outbound_intstatus;	/*0030 0033*/
+	uint32_t outbound_intmask;	/*0034 0037*/
+	uint32_t reserved1[2];		/*0038 003F*/
+	uint32_t inbound_queueport;	/*0040 0043*/
+	uint32_t outbound_queueport;	/*0044 0047*/
+	uint32_t reserved2[2];		/*0048 004F*/
+	uint32_t reserved3[492];		/*0050 07FF 492*/
+	uint32_t reserved4[128];		/*0800 09FF 128*/
+	uint32_t message_rwbuffer[256];	/*0a00 0DFF 256*/
+	uint32_t message_wbuffer[32];	/*0E00 0E7F  32*/
+	uint32_t reserved5[32];		/*0E80 0EFF  32*/
+	uint32_t message_rbuffer[32];	/*0F00 0F7F  32*/
+	uint32_t reserved6[32];		/*0F80 0FFF  32*/
 };
 
 struct MessageUnit_B
 {
-	uint32_t	post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
-	uint32_t	done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
-	uint32_t	postq_index;
-	uint32_t	doneq_index;
-	uint32_t		__iomem *drv2iop_doorbell;
-	uint32_t		__iomem *drv2iop_doorbell_mask;
-	uint32_t		__iomem *iop2drv_doorbell;
-	uint32_t		__iomem *iop2drv_doorbell_mask;
-	uint32_t		__iomem *message_rwbuffer;
-	uint32_t		__iomem *message_wbuffer;
-	uint32_t		__iomem *message_rbuffer;
+	uint32_t post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+	uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+	uint32_t postq_index;
+	uint32_t doneq_index;
+	uint32_t __iomem *drv2iop_doorbell;
+	uint32_t __iomem *drv2iop_doorbell_mask;
+	uint32_t __iomem *iop2drv_doorbell;
+	uint32_t __iomem *iop2drv_doorbell_mask;
+	uint32_t __iomem *message_rwbuffer;
+	uint32_t __iomem *message_wbuffer;
+	uint32_t __iomem *message_rbuffer;
 };
 /*
 *********************************************************************
 ** LSI
 *********************************************************************
 */
-struct MessageUnit_C{
-	uint32_t	message_unit_status;			/*0000 0003*/
-	uint32_t	slave_error_attribute;			/*0004 0007*/
-	uint32_t	slave_error_address;			/*0008 000B*/
-	uint32_t	posted_outbound_doorbell;		/*000C 000F*/
-	uint32_t	master_error_attribute;			/*0010 0013*/
-	uint32_t	master_error_address_low;		/*0014 0017*/
-	uint32_t	master_error_address_high;		/*0018 001B*/
-	uint32_t	hcb_size;				/*001C 001F*/
-	uint32_t	inbound_doorbell;			/*0020 0023*/
-	uint32_t	diagnostic_rw_data;			/*0024 0027*/
-	uint32_t	diagnostic_rw_address_low;		/*0028 002B*/
-	uint32_t	diagnostic_rw_address_high;		/*002C 002F*/
-	uint32_t	host_int_status;				/*0030 0033*/
-	uint32_t	host_int_mask;				/*0034 0037*/
-	uint32_t	dcr_data;				/*0038 003B*/
-	uint32_t	dcr_address;				/*003C 003F*/
-	uint32_t	inbound_queueport;			/*0040 0043*/
-	uint32_t	outbound_queueport;			/*0044 0047*/
-	uint32_t	hcb_pci_address_low;			/*0048 004B*/
-	uint32_t	hcb_pci_address_high;			/*004C 004F*/
-	uint32_t	iop_int_status;				/*0050 0053*/
-	uint32_t	iop_int_mask;				/*0054 0057*/
-	uint32_t	iop_inbound_queue_port;			/*0058 005B*/
-	uint32_t	iop_outbound_queue_port;		/*005C 005F*/
-	uint32_t	inbound_free_list_index;			/*0060 0063*/
-	uint32_t	inbound_post_list_index;			/*0064 0067*/
-	uint32_t	outbound_free_list_index;			/*0068 006B*/
-	uint32_t	outbound_post_list_index;			/*006C 006F*/
-	uint32_t	inbound_doorbell_clear;			/*0070 0073*/
-	uint32_t	i2o_message_unit_control;			/*0074 0077*/
-	uint32_t	last_used_message_source_address_low;	/*0078 007B*/
-	uint32_t	last_used_message_source_address_high;	/*007C 007F*/
-	uint32_t	pull_mode_data_byte_count[4];		/*0080 008F*/
-	uint32_t	message_dest_address_index;		/*0090 0093*/
-	uint32_t	done_queue_not_empty_int_counter_timer;	/*0094 0097*/
-	uint32_t	utility_A_int_counter_timer;		/*0098 009B*/
-	uint32_t	outbound_doorbell;			/*009C 009F*/
-	uint32_t	outbound_doorbell_clear;			/*00A0 00A3*/
-	uint32_t	message_source_address_index;		/*00A4 00A7*/
-	uint32_t	message_done_queue_index;		/*00A8 00AB*/
-	uint32_t	reserved0;				/*00AC 00AF*/
-	uint32_t	inbound_msgaddr0;			/*00B0 00B3*/
-	uint32_t	inbound_msgaddr1;			/*00B4 00B7*/
-	uint32_t	outbound_msgaddr0;			/*00B8 00BB*/
-	uint32_t	outbound_msgaddr1;			/*00BC 00BF*/
-	uint32_t	inbound_queueport_low;			/*00C0 00C3*/
-	uint32_t	inbound_queueport_high;			/*00C4 00C7*/
-	uint32_t	outbound_queueport_low;			/*00C8 00CB*/
-	uint32_t	outbound_queueport_high;		/*00CC 00CF*/
-	uint32_t	iop_inbound_queue_port_low;		/*00D0 00D3*/
-	uint32_t	iop_inbound_queue_port_high;		/*00D4 00D7*/
-	uint32_t	iop_outbound_queue_port_low;		/*00D8 00DB*/
-	uint32_t	iop_outbound_queue_port_high;		/*00DC 00DF*/
-	uint32_t	message_dest_queue_port_low;		/*00E0 00E3*/
-	uint32_t	message_dest_queue_port_high;		/*00E4 00E7*/
-	uint32_t	last_used_message_dest_address_low;	/*00E8 00EB*/
-	uint32_t	last_used_message_dest_address_high;	/*00EC 00EF*/
-	uint32_t	message_done_queue_base_address_low;	/*00F0 00F3*/
-	uint32_t	message_done_queue_base_address_high;	/*00F4 00F7*/
-	uint32_t	host_diagnostic;				/*00F8 00FB*/
-	uint32_t	write_sequence;				/*00FC 00FF*/
-	uint32_t	reserved1[34];				/*0100 0187*/
-	uint32_t	reserved2[1950];				/*0188 1FFF*/
-	uint32_t	message_wbuffer[32];			/*2000 207F*/
-	uint32_t	reserved3[32];				/*2080 20FF*/
-	uint32_t	message_rbuffer[32];			/*2100 217F*/
-	uint32_t	reserved4[32];				/*2180 21FF*/
-	uint32_t	msgcode_rwbuffer[256];			/*2200 23FF*/
+struct MessageUnit_C {
+	uint32_t message_unit_status;			/*0000 0003*/
+	uint32_t slave_error_attribute;			/*0004 0007*/
+	uint32_t slave_error_address;			/*0008 000B*/
+	uint32_t posted_outbound_doorbell;			/*000C 000F*/
+	uint32_t master_error_attribute;			/*0010 0013*/
+	uint32_t master_error_address_low;			/*0014 0017*/
+	uint32_t master_error_address_high;		/*0018 001B*/
+	uint32_t hcb_size;					/*001C 001F*/
+	uint32_t inbound_doorbell;				/*0020 0023*/
+	uint32_t diagnostic_rw_data;			/*0024 0027*/
+	uint32_t diagnostic_rw_address_low;		/*0028 002B*/
+	uint32_t diagnostic_rw_address_high;		/*002C 002F*/
+	uint32_t host_int_status;				/*0030 0033*/
+	uint32_t host_int_mask;				/*0034 0037*/
+	uint32_t dcr_data;					/*0038 003B*/
+	uint32_t dcr_address;				/*003C 003F*/
+	uint32_t inbound_queueport;			/*0040 0043*/
+	uint32_t outbound_queueport;			/*0044 0047*/
+	uint32_t hcb_pci_address_low;			/*0048 004B*/
+	uint32_t hcb_pci_address_high;			/*004C 004F*/
+	uint32_t iop_int_status;				/*0050 0053*/
+	uint32_t iop_int_mask;				/*0054 0057*/
+	uint32_t iop_inbound_queue_port;			/*0058 005B*/
+	uint32_t iop_outbound_queue_port;			/*005C 005F*/
+	uint32_t inbound_free_list_index;			/*0060 0063*/
+	uint32_t inbound_post_list_index;			/*0064 0067*/
+	uint32_t outbound_free_list_index;			/*0068 006B*/
+	uint32_t outbound_post_list_index;			/*006C 006F*/
+	uint32_t inbound_doorbell_clear;			/*0070 0073*/
+	uint32_t i2o_message_unit_control;			/*0074 0077*/
+	uint32_t last_used_message_source_address_low;	/*0078 007B*/
+	uint32_t last_used_message_source_address_high;	/*007C 007F*/
+	uint32_t pull_mode_data_byte_count[4];		/*0080 008F*/
+	uint32_t message_dest_address_index;		/*0090 0093*/
+	uint32_t done_queue_not_empty_int_counter_timer;	/*0094 0097*/
+	uint32_t utility_A_int_counter_timer;		/*0098 009B*/
+	uint32_t outbound_doorbell;			/*009C 009F*/
+	uint32_t outbound_doorbell_clear;			/*00A0 00A3*/
+	uint32_t message_source_address_index;		/*00A4 00A7*/
+	uint32_t message_done_queue_index;		/*00A8 00AB*/
+	uint32_t reserved0;				/*00AC 00AF*/
+	uint32_t inbound_msgaddr0;			/*00B0 00B3*/
+	uint32_t inbound_msgaddr1;			/*00B4 00B7*/
+	uint32_t outbound_msgaddr0;			/*00B8 00BB*/
+	uint32_t outbound_msgaddr1;			/*00BC 00BF*/
+	uint32_t inbound_queueport_low;			/*00C0 00C3*/
+	uint32_t inbound_queueport_high;			/*00C4 00C7*/
+	uint32_t outbound_queueport_low;			/*00C8 00CB*/
+	uint32_t outbound_queueport_high;		/*00CC 00CF*/
+	uint32_t iop_inbound_queue_port_low;		/*00D0 00D3*/
+	uint32_t iop_inbound_queue_port_high;		/*00D4 00D7*/
+	uint32_t iop_outbound_queue_port_low;		/*00D8 00DB*/
+	uint32_t iop_outbound_queue_port_high;		/*00DC 00DF*/
+	uint32_t message_dest_queue_port_low;		/*00E0 00E3*/
+	uint32_t message_dest_queue_port_high;		/*00E4 00E7*/
+	uint32_t last_used_message_dest_address_low;	/*00E8 00EB*/
+	uint32_t last_used_message_dest_address_high;	/*00EC 00EF*/
+	uint32_t message_done_queue_base_address_low;	/*00F0 00F3*/
+	uint32_t message_done_queue_base_address_high;	/*00F4 00F7*/
+	uint32_t host_diagnostic;				/*00F8 00FB*/
+	uint32_t write_sequence;				/*00FC 00FF*/
+	uint32_t reserved1[34];				/*0100 0187*/
+	uint32_t reserved2[1950];				/*0188 1FFF*/
+	uint32_t message_wbuffer[32];			/*2000 207F*/
+	uint32_t reserved3[32];				/*2080 20FF*/
+	uint32_t message_rbuffer[32];			/*2100 217F*/
+	uint32_t reserved4[32];				/*2180 21FF*/
+	uint32_t msgcode_rwbuffer[256];			/*2200 23FF*/
+};
+struct InBound_SRB {
+	uint32_t addressLow;/*pointer to SRB block*/
+	uint32_t addressHigh;
+	uint32_t length;/*in DWORDs*/
+	uint32_t reserved0;
+};
+
+struct OutBound_SRB {
+	uint32_t addressLow;/*pointer to SRB block*/
+	uint32_t addressHigh;
+};
+
+struct MessageUnit_D {
+	struct InBound_SRB post_qbuffer[ARCMSR_MAX_ARC1214_POSTQUEUE];
+	struct OutBound_SRB done_qbuffer[ARCMSR_MAX_ARC1214_DONEQUEUE];
+	u16 postq_index;
+	u16 doneq_index;
+	u32 __iomem *chip_id;			/*0x00004*/
+	u32 __iomem *cpu_mem_config;		/*0x00008*/
+	u32 __iomem *i2o_host_interrupt_mask;	/*0x00034*/
+	u32 __iomem *sample_at_reset;		/*0x00100*/
+	u32 __iomem *reset_request;		/*0x00108*/
+	u32 __iomem *host_int_status;		/*0x00200*/
+	u32 __iomem *pcief0_int_enable;		/*0x0020C*/
+	u32 __iomem *inbound_msgaddr0;		/*0x00400*/
+	u32 __iomem *inbound_msgaddr1;		/*0x00404*/
+	u32 __iomem *outbound_msgaddr0;		/*0x00420*/
+	u32 __iomem *outbound_msgaddr1;		/*0x00424*/
+	u32 __iomem *inbound_doorbell;		/*0x00460*/
+	u32 __iomem *outbound_doorbell;		/*0x00480*/
+	u32 __iomem *outbound_doorbell_enable;	/*0x00484*/
+	u32 __iomem *inboundlist_base_low;	/*0x01000*/
+	u32 __iomem *inboundlist_base_high;	/*0x01004*/
+	u32 __iomem *inboundlist_write_pointer;	/*0x01018*/
+	u32 __iomem *outboundlist_base_low;	/*0x01060*/
+	u32 __iomem *outboundlist_base_high;	/*0x01064*/
+	u32 __iomem *outboundlist_copy_pointer;	/*0x0106C*/
+	u32 __iomem *outboundlist_read_pointer;	/*0x01070 0x01072*/
+	u32 __iomem *outboundlist_interrupt_cause;	/*0x1088*/
+	u32 __iomem *outboundlist_interrupt_enable;	/*0x108C*/
+	u32 __iomem *message_wbuffer;		/*0x2000*/
+	u32 __iomem *message_rbuffer;		/*0x2100*/
+	u32 __iomem *msgcode_rwbuffer;		/*0x2200*/
 };
 /*
 *******************************************************************************
@@ -500,100 +602,110 @@ struct MessageUnit_C{
 */
 struct AdapterControlBlock
 {
-	uint32_t  adapter_type;                /* adapter A,B..... */
-	#define ACB_ADAPTER_TYPE_A            0x00000001	/* hba I IOP */
-	#define ACB_ADAPTER_TYPE_B            0x00000002	/* hbb M IOP */
-	#define ACB_ADAPTER_TYPE_C            0x00000004	/* hbc P IOP */
-	#define ACB_ADAPTER_TYPE_D            0x00000008	/* hbd A IOP */
-	struct pci_dev *		pdev;
-	struct Scsi_Host *		host;
-	unsigned long			vir2phy_offset;
+	uint32_t adapter_type;	/* adapter A,B..... */
+	#define ACB_ADAPTER_TYPE_A	0x00000001	/* hba I IOP */
+	#define ACB_ADAPTER_TYPE_B	0x00000002	/* hbb M IOP */
+	#define ACB_ADAPTER_TYPE_C	0x00000004	/* hbc P IOP */
+	#define ACB_ADAPTER_TYPE_D	0x00000008	/* hbd A IOP */
+	u32 roundup_ccbsize;
+	struct pci_dev *pdev;
+	struct Scsi_Host *host;
+	unsigned long vir2phy_offset;
+	struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS];
 	/* Offset is used in making arc cdb physical to virtual calculations */
-	uint32_t			outbound_int_enable;
-	uint32_t			cdb_phyaddr_hi32;
-	uint32_t			reg_mu_acc_handle0;
-	spinlock_t                      			eh_lock;
-	spinlock_t                      			ccblist_lock;
+	uint32_t outbound_int_enable;
+	uint32_t cdb_phyaddr_hi32;
+	spinlock_t eh_lock;
+	spinlock_t ccblist_lock;
+	spinlock_t postq_lock;
+	spinlock_t doneq_lock;
+	spinlock_t rqbuffer_lock;
+	spinlock_t wqbuffer_lock;
 	union {
 		struct MessageUnit_A __iomem *pmuA;
-		struct MessageUnit_B 	*pmuB;
+		struct MessageUnit_B *pmuB;
 		struct MessageUnit_C __iomem *pmuC;
+		struct MessageUnit_D __iomem *pmuD;
 	};
 	/* message unit ATU inbound base address0 */
 	void __iomem *mem_base0;
 	void __iomem *mem_base1;
-	uint32_t			acb_flags;
-	u16			dev_id;
-	uint8_t                   		adapter_index;
-	#define ACB_F_SCSISTOPADAPTER         	0x0001
-	#define ACB_F_MSG_STOP_BGRB     	0x0002
+	uint32_t acb_flags;
+	u16 dev_id;
+	uint8_t adapter_index;
+	#define ACB_F_SCSISTOPADAPTER			0x0001
+	#define ACB_F_MSG_STOP_BGRB			0x0002
 	/* stop RAID background rebuild */
-	#define ACB_F_MSG_START_BGRB          	0x0004
+	#define ACB_F_MSG_START_BGRB			0x0004
 	/* stop RAID background rebuild */
-	#define ACB_F_IOPDATA_OVERFLOW        	0x0008
+	#define ACB_F_IOPDATA_OVERFLOW		0x0008
 	/* iop message data rqbuffer overflow */
 	#define ACB_F_MESSAGE_WQBUFFER_CLEARED	0x0010
 	/* message clear wqbuffer */
-	#define ACB_F_MESSAGE_RQBUFFER_CLEARED  0x0020
+	#define ACB_F_MESSAGE_RQBUFFER_CLEARED	0x0020
 	/* message clear rqbuffer */
-	#define ACB_F_MESSAGE_WQBUFFER_READED   0x0040
-	#define ACB_F_BUS_RESET               	0x0080
-	#define ACB_F_BUS_HANG_ON		0x0800/* need hardware reset bus */
+	#define ACB_F_MESSAGE_WQBUFFER_READED	0x0040
+	#define ACB_F_BUS_RESET				0x0080
+	#define ACB_F_BUS_HANG_ON			0x0800
 
-	#define ACB_F_IOP_INITED              	0x0100
+	#define ACB_F_IOP_INITED				0x0100
 	/* iop init */
 	#define ACB_F_ABORT				0x0200
-	#define ACB_F_FIRMWARE_TRAP           		0x0400
-	struct CommandControlBlock *			pccb_pool[ARCMSR_MAX_FREECCB_NUM];
+	#define ACB_F_FIRMWARE_TRAP			0x0400
+	#define ACB_F_MSI_ENABLED			0x1000
+	#define ACB_F_MSIX_ENABLED			0x2000
+	struct CommandControlBlock *pccb_pool[ARCMSR_MAX_FREECCB_NUM];
 	/* used for memory free */
-	struct list_head		ccb_free_list;
+	struct list_head ccb_free_list;
 	/* head of free ccb list */
 
-	atomic_t			ccboutstandingcount;
+	atomic_t ccboutstandingcount;
 	/*The present outstanding command number that in the IOP that
 					waiting for being handled by FW*/
 
-	void *				dma_coherent;
+	void *dma_coherent;
 	/* dma_coherent used for memory free */
-	dma_addr_t			dma_coherent_handle;
+	dma_addr_t dma_coherent_handle;
 	/* dma_coherent_handle used for memory free */
-	dma_addr_t				dma_coherent_handle_hbb_mu;
-	unsigned int				uncache_size;
-	uint8_t				rqbuffer[ARCMSR_MAX_QBUFFER];
+	dma_addr_t dma_coherent_handle2;
+	void *dma_coherent2;
+	unsigned int uncache_size;
+	uint8_t rqbuffer[ARCMSR_MAX_QBUFFER];
 	/* data collection buffer for read from 80331 */
-	int32_t				rqbuf_firstindex;
+	uint32_t rqbuf_firstindex;
 	/* first of read buffer  */
-	int32_t				rqbuf_lastindex;
+	uint32_t rqbuf_lastindex;
 	/* last of read buffer   */
-	uint8_t				wqbuffer[ARCMSR_MAX_QBUFFER];
+	uint8_t wqbuffer[ARCMSR_MAX_QBUFFER];
 	/* data collection buffer for write to 80331  */
-	int32_t				wqbuf_firstindex;
+	uint32_t wqbuf_firstindex;
 	/* first of write buffer */
-	int32_t				wqbuf_lastindex;
+	uint32_t wqbuf_lastindex;
 	/* last of write buffer  */
-	uint8_t				devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN];
+	uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN];
 	/* id0 ..... id15, lun0...lun7 */
-#define ARECA_RAID_GONE               0x55
-#define ARECA_RAID_GOOD               0xaa
-	uint32_t			num_resets;
-	uint32_t			num_aborts;
-	uint32_t			signature;
-	uint32_t			firm_request_len;
-	uint32_t			firm_numbers_queue;
-	uint32_t			firm_sdram_size;
-	uint32_t			firm_hd_channels;
-	uint32_t                           	firm_cfg_version;	
-	char			firm_model[12];
-	char			firm_version[20];
-	char			device_map[20];			/*21,84-99*/
-	struct work_struct 		arcmsr_do_message_isr_bh;
-	struct timer_list		eternal_timer;
-	unsigned short		fw_flag;
-				#define	FW_NORMAL	0x0000
-				#define	FW_BOG		0x0001
-				#define	FW_DEADLOCK	0x0010
-	atomic_t 			rq_map_token;
-	atomic_t			ante_token_value;
+#define ARECA_RAID_GONE		0x55
+#define ARECA_RAID_GOOD	0xaa
+	uint32_t num_resets;
+	uint32_t num_aborts;
+	uint32_t signature;
+	uint32_t firm_request_len;
+	uint32_t firm_numbers_queue;
+	uint32_t firm_sdram_size;
+	uint32_t firm_hd_channels;
+	uint32_t firm_cfg_version;
+	char firm_model[12];
+	char firm_version[20];
+	char device_map[20];	/*21,84-99*/
+	struct work_struct arcmsr_do_message_isr_bh;
+	struct timer_list eternal_timer;
+	unsigned short fw_flag;
+	#define FW_NORMAL	0x0000
+	#define FW_BOG		0x0001
+	#define FW_DEADLOCK	0x0010
+	atomic_t rq_map_token;
+	atomic_t ante_token_value;
+	uint32_t maxOutstanding;
 };/* HW_DEVICE_EXTENSION */
 /*
 *******************************************************************************
@@ -601,33 +713,33 @@ struct AdapterControlBlock
 **             this CCB length must be 32 bytes boundary
 *******************************************************************************
 */
-struct CommandControlBlock{
-	/*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/
-	struct list_head		list;				/*x32: 8byte, x64: 16byte*/
-	struct scsi_cmnd		*pcmd;				/*8 bytes pointer of linux scsi command */
-	struct AdapterControlBlock	*acb;				/*x32: 4byte, x64: 8byte*/
-	uint32_t			cdb_phyaddr_pattern;		/*x32: 4byte, x64: 4byte*/
-	uint32_t			arc_cdb_size;			/*x32:4byte,x64:4byte*/
-	uint16_t			ccb_flags;			/*x32: 2byte, x64: 2byte*/
-	#define			CCB_FLAG_READ			0x0000
-	#define			CCB_FLAG_WRITE		0x0001
-	#define			CCB_FLAG_ERROR		0x0002
-	#define			CCB_FLAG_FLUSHCACHE		0x0004
-	#define			CCB_FLAG_MASTER_ABORTED	0x0008	
-	uint16_t                        	startdone;			/*x32:2byte,x32:2byte*/
-	#define			ARCMSR_CCB_DONE   	        	0x0000
-	#define			ARCMSR_CCB_START		0x55AA
-	#define			ARCMSR_CCB_ABORTED		0xAA55
-	#define			ARCMSR_CCB_ILLEGAL		0xFFFF
+struct CommandControlBlock {
+/*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/
+	struct list_head list;
+	struct scsi_cmnd *pcmd;
+	struct AdapterControlBlock *acb;
+	uint32_t cdb_phyaddr;
+	uint32_t arc_cdb_size;
+	uint16_t ccb_flags;
+	#define CCB_FLAG_READ		0x0000
+	#define CCB_FLAG_WRITE		0x0001
+	#define CCB_FLAG_ERROR		0x0002
+	#define CCB_FLAG_FLUSHCACHE	0x0004
+	#define CCB_FLAG_MASTER_ABORTED	0x0008
+	uint16_t startdone;
+	#define ARCMSR_CCB_DONE	0x0000
+	#define ARCMSR_CCB_START	0x55AA
+	#define ARCMSR_CCB_ABORTED	0xAA55
+	#define ARCMSR_CCB_ILLEGAL	0xFFFF
 	#if BITS_PER_LONG == 64
 	/*  ======================512+64 bytes========================  */
-		uint32_t                        	reserved[5];		/*24 byte*/
+		uint32_t reserved[5];	/*24 byte*/
 	#else
-	/*  ======================512+32 bytes========================  */
-		uint32_t                        	reserved;		/*8  byte*/
+	/*======================512+32 bytes========================*/
+		uint32_t reserved;	/*8  byte*/
 	#endif
-	/*  =======================================================   */
-	struct ARCMSR_CDB		arcmsr_cdb;
+	/*=======================================================*/
+	struct ARCMSR_CDB arcmsr_cdb;
 };
 /*
 *******************************************************************************
@@ -636,53 +748,53 @@ struct CommandControlBlock{
 */
 struct SENSE_DATA
 {
-	uint8_t				ErrorCode:7;
+	uint8_t ErrorCode:7;
 #define SCSI_SENSE_CURRENT_ERRORS	0x70
 #define SCSI_SENSE_DEFERRED_ERRORS	0x71
-	uint8_t				Valid:1;
-	uint8_t				SegmentNumber;
-	uint8_t				SenseKey:4;
-	uint8_t				Reserved:1;
-	uint8_t				IncorrectLength:1;
-	uint8_t				EndOfMedia:1;
-	uint8_t				FileMark:1;
-	uint8_t				Information[4];
-	uint8_t				AdditionalSenseLength;
-	uint8_t				CommandSpecificInformation[4];
-	uint8_t				AdditionalSenseCode;
-	uint8_t				AdditionalSenseCodeQualifier;
-	uint8_t				FieldReplaceableUnitCode;
-	uint8_t				SenseKeySpecific[3];
+	uint8_t Valid:1;
+	uint8_t SegmentNumber;
+	uint8_t SenseKey:4;
+	uint8_t Reserved:1;
+	uint8_t IncorrectLength:1;
+	uint8_t EndOfMedia:1;
+	uint8_t FileMark:1;
+	uint8_t Information[4];
+	uint8_t AdditionalSenseLength;
+	uint8_t CommandSpecificInformation[4];
+	uint8_t AdditionalSenseCode;
+	uint8_t AdditionalSenseCodeQualifier;
+	uint8_t FieldReplaceableUnitCode;
+	uint8_t SenseKeySpecific[3];
 };
 /*
 *******************************************************************************
 **  Outbound Interrupt Status Register - OISR
 *******************************************************************************
 */
-#define     ARCMSR_MU_OUTBOUND_INTERRUPT_STATUS_REG                 0x30
-#define     ARCMSR_MU_OUTBOUND_PCI_INT                              0x10
-#define     ARCMSR_MU_OUTBOUND_POSTQUEUE_INT                        0x08
-#define     ARCMSR_MU_OUTBOUND_DOORBELL_INT                         0x04
-#define     ARCMSR_MU_OUTBOUND_MESSAGE1_INT                         0x02
-#define     ARCMSR_MU_OUTBOUND_MESSAGE0_INT                         0x01
-#define     ARCMSR_MU_OUTBOUND_HANDLE_INT                 \
-                    (ARCMSR_MU_OUTBOUND_MESSAGE0_INT      \
-                     |ARCMSR_MU_OUTBOUND_MESSAGE1_INT     \
-                     |ARCMSR_MU_OUTBOUND_DOORBELL_INT     \
-                     |ARCMSR_MU_OUTBOUND_POSTQUEUE_INT    \
-                     |ARCMSR_MU_OUTBOUND_PCI_INT)
+#define ARCMSR_MU_OUTBOUND_INTERRUPT_STATUS_REG	0x30
+#define ARCMSR_MU_OUTBOUND_PCI_INT			0x10
+#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INT		0x08
+#define ARCMSR_MU_OUTBOUND_DOORBELL_INT		0x04
+#define ARCMSR_MU_OUTBOUND_MESSAGE1_INT		0x02
+#define ARCMSR_MU_OUTBOUND_MESSAGE0_INT		0x01
+#define ARCMSR_MU_OUTBOUND_HANDLE_INT	\
+	(ARCMSR_MU_OUTBOUND_MESSAGE0_INT	\
+	|ARCMSR_MU_OUTBOUND_MESSAGE1_INT	\
+	|ARCMSR_MU_OUTBOUND_DOORBELL_INT	\
+	|ARCMSR_MU_OUTBOUND_POSTQUEUE_INT	\
+	|ARCMSR_MU_OUTBOUND_PCI_INT)
 /*
 *******************************************************************************
 **  Outbound Interrupt Mask Register - OIMR
 *******************************************************************************
 */
-#define     ARCMSR_MU_OUTBOUND_INTERRUPT_MASK_REG                   0x34
-#define     ARCMSR_MU_OUTBOUND_PCI_INTMASKENABLE                    0x10
-#define     ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE              0x08
-#define     ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE               0x04
-#define     ARCMSR_MU_OUTBOUND_MESSAGE1_INTMASKENABLE               0x02
-#define     ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE               0x01
-#define     ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE                    0x1F
+#define ARCMSR_MU_OUTBOUND_INTERRUPT_MASK_REG		0x34
+#define ARCMSR_MU_OUTBOUND_PCI_INTMASKENABLE		0x10
+#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE	0x08
+#define ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE	0x04
+#define ARCMSR_MU_OUTBOUND_MESSAGE1_INTMASKENABLE	0x02
+#define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE	0x01
+#define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE		0x1F
 
 extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *);
 extern void arcmsr_iop_message_read(struct AdapterControlBlock *);
diff -uprN a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
--- a/drivers/scsi/arcmsr/arcmsr_hba.c	2013-07-01 06:13:28.000000000 +0800
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c	2013-05-07 19:12:12.000000000 +0800
@@ -2,7 +2,7 @@
 *******************************************************************************
 **        O.S   : Linux
 **   FILE NAME  : arcmsr_hba.c
-**        BY    : Nick Cheng
+**        BY    : Nick Cheng, C.L. Huang
 **   Description: SCSI RAID Device Driver for
 **                ARECA RAID Host adapter
 *******************************************************************************
@@ -71,12 +71,12 @@
 #include <scsi/scsicam.h>
 #include "arcmsr.h"
 MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>");
-MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter");
+MODULE_DESCRIPTION("Areca SAS,SATA RAID Controller Driver");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(ARCMSR_DRIVER_VERSION);
 
-#define	ARCMSR_SLEEPTIME	10
-#define	ARCMSR_RETRYCOUNT	12
+#define ARCMSR_SLEEPTIME	10
+#define ARCMSR_RETRYCOUNT	12
 
 wait_queue_head_t wait_q;
 static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
@@ -89,22 +89,27 @@ static int arcmsr_bios_param(struct scsi
 static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
 static int arcmsr_probe(struct pci_dev *pdev,
 				const struct pci_device_id *id);
+static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state);
+static int arcmsr_resume(struct pci_dev *pdev);
 static void arcmsr_remove(struct pci_dev *pdev);
 static void arcmsr_shutdown(struct pci_dev *pdev);
 static void arcmsr_iop_init(struct AdapterControlBlock *acb);
 static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb);
 static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);
+static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
+	u32 orig_mask);
 static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
-static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);
-static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
+static void arcmsr_hbaA_flush_cache(struct AdapterControlBlock *acb);
+static void arcmsr_hbaB_flush_cache(struct AdapterControlBlock *acb);
 static void arcmsr_request_device_map(unsigned long pacb);
-static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb);
-static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb);
-static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_hbaA_request_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_hbaB_request_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_hbaC_request_device_map(struct AdapterControlBlock *acb);
 static void arcmsr_message_isr_bh_fn(struct work_struct *work);
 static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
 static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
-static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB);
+static void arcmsr_hbaC_message_isr(struct AdapterControlBlock *pACB);
+static void arcmsr_hbaD_message_isr(struct AdapterControlBlock *acb);
 static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
 static const char *arcmsr_info(struct Scsi_Host *);
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
@@ -132,8 +137,6 @@ static struct scsi_host_template arcmsr_
 	.change_queue_depth	= arcmsr_adjust_disk_queue_depth,
 	.can_queue		= ARCMSR_MAX_FREECCB_NUM,
 	.this_id			= ARCMSR_SCSI_INITIATOR_ID,
-	.sg_tablesize	        	= ARCMSR_DEFAULT_SG_ENTRIES, 
-	.max_sectors    	    	= ARCMSR_MAX_XFER_SECTORS_C, 
 	.cmd_per_lun		= ARCMSR_MAX_CMD_PERLUN,
 	.use_clustering		= ENABLE_CLUSTERING,
 	.shost_attrs		= arcmsr_host_attrs,
@@ -148,13 +151,12 @@ static struct pci_device_id arcmsr_devic
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)},
+	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1214)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)},
-	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)},
-	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880)},
@@ -166,23 +168,33 @@ static struct pci_driver arcmsr_pci_driv
 	.id_table			= arcmsr_device_id_table,
 	.probe			= arcmsr_probe,
 	.remove			= arcmsr_remove,
+		.suspend		= arcmsr_suspend,
+		.resume		= arcmsr_resume,
 	.shutdown		= arcmsr_shutdown,
 };
 /*
 ****************************************************************************
 ****************************************************************************
 */
-
-static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb)
+static void arcmsr_free_mu(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A:
 	case ACB_ADAPTER_TYPE_C:
 		break;
-	case ACB_ADAPTER_TYPE_B:{
+	case ACB_ADAPTER_TYPE_B: {
+		struct MessageUnit_B *reg = acb->pmuB;
 		dma_free_coherent(&acb->pdev->dev,
 			sizeof(struct MessageUnit_B),
-			acb->pmuB, acb->dma_coherent_handle_hbb_mu);
+			reg, acb->dma_coherent_handle2);
+		break;
+	}
+	case ACB_ADAPTER_TYPE_D: {
+		dma_free_coherent(&acb->pdev->dev,
+			sizeof(struct MessageUnit_D),
+			acb->dma_coherent,
+			acb->dma_coherent_handle);
+		break;
 	}
 	}
 }
@@ -190,44 +202,73 @@ static void arcmsr_free_hbb_mu(struct Ad
 static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
 {
 	struct pci_dev *pdev = acb->pdev;
-	switch (acb->adapter_type){
-	case ACB_ADAPTER_TYPE_A:{
-		acb->pmuA = ioremap(pci_resource_start(pdev,0), pci_resource_len(pdev,0));
+	switch (acb->adapter_type) {
+	case ACB_ADAPTER_TYPE_A: {
+		acb->pmuA = ioremap(pci_resource_start(pdev, 0),
+			pci_resource_len(pdev, 0));
 		if (!acb->pmuA) {
-			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+			pr_notice("arcmsr%d: memory mapping "
+				"region fail\n", acb->host->host_no);
 			return false;
 		}
 		break;
 	}
-	case ACB_ADAPTER_TYPE_B:{
+	case ACB_ADAPTER_TYPE_B: {
 		void __iomem *mem_base0, *mem_base1;
-		mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+		mem_base0 = ioremap(pci_resource_start(pdev, 0),
+			pci_resource_len(pdev, 0));
 		if (!mem_base0) {
-			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+			pr_notice("arcmsr%d: memory mapping "
+				"region fail\n", acb->host->host_no);
 			return false;
 		}
-		mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
+		mem_base1 = ioremap(pci_resource_start(pdev, 2),
+			pci_resource_len(pdev, 2));
 		if (!mem_base1) {
 			iounmap(mem_base0);
-			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+			pr_notice("arcmsr%d: memory mapping "
+				"region fail\n", acb->host->host_no);
 			return false;
 		}
 		acb->mem_base0 = mem_base0;
 		acb->mem_base1 = mem_base1;
 		break;
 	}
-	case ACB_ADAPTER_TYPE_C:{
-		acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+	case ACB_ADAPTER_TYPE_C: {
+		acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1),
+			pci_resource_len(pdev, 1));
 		if (!acb->pmuC) {
-			printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+			pr_notice("arcmsr%d: memory mapping "
+				"region fail\n", acb->host->host_no);
 			return false;
 		}
-		if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
-			writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/
+		if (readl(&acb->pmuC->outbound_doorbell) &
+			ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+			writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR,
+				&acb->pmuC->outbound_doorbell_clear);
 			return true;
 		}
 		break;
 	}
+	case ACB_ADAPTER_TYPE_D: {
+		void __iomem *mem_base0;
+		unsigned long addr, range, flags;
+
+		addr = (unsigned long)pci_resource_start(pdev, 0);
+		range = pci_resource_len(pdev, 0);
+		flags = pci_resource_flags(pdev, 0);
+		if (flags & IORESOURCE_CACHEABLE)
+			mem_base0 = ioremap(addr, range);
+		else
+			mem_base0 = ioremap_nocache(addr, range);
+		if (!mem_base0) {
+			pr_notice("arcmsr%d: memory mapping region fail\n",
+			acb->host->host_no);
+			return false;
+		}
+		acb->mem_base0 = mem_base0;
+		break;
+	}
 	}
 	return true;
 }
@@ -235,18 +276,21 @@ static bool arcmsr_remap_pciregion(struc
 static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
-	case ACB_ADAPTER_TYPE_A:{
+	case ACB_ADAPTER_TYPE_A: {
 		iounmap(acb->pmuA);
+		break;
 	}
-	break;
-	case ACB_ADAPTER_TYPE_B:{
+	case ACB_ADAPTER_TYPE_B: {
 		iounmap(acb->mem_base0);
 		iounmap(acb->mem_base1);
+		break;
 	}
-
-	break;
-	case ACB_ADAPTER_TYPE_C:{
+	case ACB_ADAPTER_TYPE_C: {
 		iounmap(acb->pmuC);
+		break;
+	}
+	case ACB_ADAPTER_TYPE_D: {
+		iounmap(acb->mem_base0);
 	}
 	}
 }
@@ -264,11 +308,12 @@ static int arcmsr_bios_param(struct scsi
 		struct block_device *bdev, sector_t capacity, int *geom)
 {
 	int ret, heads, sectors, cylinders, total_capacity;
-	unsigned char *buffer;/* return copy of block device's partition table */
+	unsigned char *buffer;
 
 	buffer = scsi_bios_ptable(bdev);
 	if (buffer) {
-		ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]);
+		ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0],
+			&geom[1]);
 		kfree(buffer);
 		if (ret != -1)
 			return ret;
@@ -288,27 +333,53 @@ static int arcmsr_bios_param(struct scsi
 	return 0;
 }
 
-static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
+static bool
+arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
 {
-	struct pci_dev *pdev = acb->pdev;
 	u16 dev_id;
+	struct pci_dev *pdev = acb->pdev;
+
 	pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
 	acb->dev_id = dev_id;
 	switch (dev_id) {
 	case 0x1880: {
 		acb->adapter_type = ACB_ADAPTER_TYPE_C;
-		}
 		break;
-	case 0x1201: {
+	}
+	case 0x1200:
+	case 0x1201:
+	case 0x1202: {
 		acb->adapter_type = ACB_ADAPTER_TYPE_B;
-		}
 		break;
-
-	default: acb->adapter_type = ACB_ADAPTER_TYPE_A;
 	}
+	case 0x1110:
+	case 0x1120:
+	case 0x1130:
+	case 0x1160:
+	case 0x1170:
+	case 0x1210:
+	case 0x1220:
+	case 0x1230:
+	case 0x1260:
+	case 0x1280:
+	case 0x1680: {
+		acb->adapter_type = ACB_ADAPTER_TYPE_A;
+		break;
+	}
+	case 0x1214: {
+		acb->adapter_type = ACB_ADAPTER_TYPE_D;
+		break;
+	}
+	default: {
+		pr_notice("Unknown device ID = 0x%x\n", dev_id);
+		return false;
+	}
+	}
+	return true;
 }
 
-static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
+static bool
+arcmsr_hbaA_wait_msgint_ready(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	int i;
@@ -326,7 +397,8 @@ static uint8_t arcmsr_hba_wait_msgint_re
 	return false;
 }
 
-static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
+static bool
+arcmsr_hbaB_wait_msgint_ready(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 	int i;
@@ -346,282 +418,659 @@ static uint8_t arcmsr_hbb_wait_msgint_re
 	return false;
 }
 
-static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB)
+static bool
+arcmsr_hbaC_wait_msgint_ready(struct AdapterControlBlock *pACB)
 {
 	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
 	int i;
 
 	for (i = 0; i < 2000; i++) {
 		if (readl(&phbcmu->outbound_doorbell)
-				& ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+			& ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
 			writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR,
-				&phbcmu->outbound_doorbell_clear); /*clear interrupt*/
+			&phbcmu->outbound_doorbell_clear);
 			return true;
 		}
 		msleep(10);
-	} /* max 20 seconds */
+	}
+	return false;
+}
 
+static bool
+arcmsr_hbaD_wait_msgint_ready(struct AdapterControlBlock *pACB)
+{
+	int i;
+	struct MessageUnit_D __iomem *reg = (struct MessageUnit_D *)pACB->pmuD;
+	for (i = 0; i < 2000; i++) {
+		if (readl(reg->outbound_doorbell)
+			& ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) {
+			writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE,
+				reg->outbound_doorbell);
+			return true;
+		}
+		msleep(10);
+	} /* max 20 seconds */
 	return false;
 }
 
-static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaA_flush_cache(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	int retry_count = 30;
 	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
 	do {
-		if (arcmsr_hba_wait_msgint_ready(acb))
+		if (arcmsr_hbaA_wait_msgint_ready(acb))
 			break;
 		else {
 			retry_count--;
-			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
-			timeout, retry count down = %d \n", acb->host->host_no, retry_count);
+			pr_notice("arcmsr%d: wait 'flush adapter "
+			"cache' timeout, retry count down = %d\n",
+			acb->host->host_no, retry_count);
 		}
 	} while (retry_count != 0);
 }
 
-static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaB_flush_cache(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 	int retry_count = 30;
 	writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell);
 	do {
-		if (arcmsr_hbb_wait_msgint_ready(acb))
+		if (arcmsr_hbaB_wait_msgint_ready(acb))
 			break;
 		else {
 			retry_count--;
-			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
-			timeout,retry count down = %d \n", acb->host->host_no, retry_count);
+			pr_notice("arcmsr%d: wait 'flush adapter "
+			"cache' timeout, retry count down = %d\n",
+			acb->host->host_no, retry_count);
 		}
 	} while (retry_count != 0);
 }
 
-static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB)
+static void
+arcmsr_hbaC_flush_cache(struct AdapterControlBlock *pACB)
 {
 	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
-	int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
-	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
-	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+	int retry_count = 6;/* enlarge wait flush adapter cache time: 10 minute */
+	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE,
+		&reg->inbound_msgaddr0);
+	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE,
+		&reg->inbound_doorbell);
+	readl(&reg->inbound_doorbell);
+	readl(&reg->inbound_msgaddr0);
+	do {
+		if (arcmsr_hbaC_wait_msgint_ready(pACB)) {
+			break;
+		} else {
+			retry_count--;
+			pr_notice("arcmsr%d: wait 'flush adapter "
+			"cache' timeout, retry count down = %d\n",
+			pACB->host->host_no, retry_count);
+		}
+	} while (retry_count != 0);
+	return;
+}
+
+static void
+arcmsr_hbaD_flush_cache(struct AdapterControlBlock *pACB)
+{
+	int retry_count = 6;
+	struct MessageUnit_D __iomem *reg =
+		(struct MessageUnit_D *)pACB->pmuD;
+
+	writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE,
+		reg->inbound_msgaddr0);
 	do {
-		if (arcmsr_hbc_wait_msgint_ready(pACB)) {
+		if (arcmsr_hbaD_wait_msgint_ready(pACB)) {
 			break;
 		} else {
 			retry_count--;
-			printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \
-			timeout,retry count down = %d \n", pACB->host->host_no, retry_count);
+			pr_notice("arcmsr%d: wait 'flush adapter "
+			"cache' timeout, retry count down = %d\n",
+			pACB->host->host_no,
+			retry_count);
 		}
 	} while (retry_count != 0);
 	return;
 }
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
+
+static void
+arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
 
 	case ACB_ADAPTER_TYPE_A: {
-		arcmsr_flush_hba_cache(acb);
+		arcmsr_hbaA_flush_cache(acb);
 		}
 		break;
 
 	case ACB_ADAPTER_TYPE_B: {
-		arcmsr_flush_hbb_cache(acb);
+		arcmsr_hbaB_flush_cache(acb);
 		}
 		break;
 	case ACB_ADAPTER_TYPE_C: {
-		arcmsr_flush_hbc_cache(acb);
+		arcmsr_hbaC_flush_cache(acb);
 		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		arcmsr_hbaD_flush_cache(acb);
+	}
 	}
 }
 
-static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+static int
+arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 {
 	struct pci_dev *pdev = acb->pdev;
 	void *dma_coherent;
 	dma_addr_t dma_coherent_handle;
-	struct CommandControlBlock *ccb_tmp;
+	struct CommandControlBlock *ccb_tmp = NULL;
 	int i = 0, j = 0;
 	dma_addr_t cdb_phyaddr;
-	unsigned long roundup_ccbsize;
+	unsigned long roundup_ccbsize = 0;
 	unsigned long max_xfer_len;
 	unsigned long max_sg_entrys;
 	uint32_t  firm_config_version;
-
-	for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
-		for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
-			acb->devstate[i][j] = ARECA_RAID_GONE;
-
 	max_xfer_len = ARCMSR_MAX_XFER_LEN;
 	max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
 	firm_config_version = acb->firm_cfg_version;
-	if((firm_config_version & 0xFF) >= 3){
-		max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */
-		max_sg_entrys = (max_xfer_len/4096);
+	if ((firm_config_version & 0xFF) >= 3) {
+		max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH <<
+			((firm_config_version >> 8) & 0xFF)) * 1024;
+		max_sg_entrys = (max_xfer_len / 4096);
 	}
-	acb->host->max_sectors = max_xfer_len/512;
+	acb->host->max_sectors = max_xfer_len / 512;
 	acb->host->sg_tablesize = max_sg_entrys;
-	roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
-	acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
-	dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
-	if(!dma_coherent){
-		printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error\n", acb->host->host_no);
-		return -ENOMEM;
+	switch (acb->adapter_type) {
+	case ACB_ADAPTER_TYPE_A: {
+		roundup_ccbsize =
+		roundup(sizeof(struct CommandControlBlock) +
+		max_sg_entrys * sizeof(struct SG64ENTRY), 32);
+		acb->uncache_size = roundup_ccbsize *
+			ARCMSR_MAX_FREECCB_NUM;
+		dma_coherent = dma_alloc_coherent(&pdev->dev,
+			acb->uncache_size, &dma_coherent_handle,
+			GFP_KERNEL);
+		if (!dma_coherent) {
+			pr_notice("arcmsr%d: dma_alloc_coherent "
+			"got error\n", acb->host->host_no);
+			return -ENOMEM;
+		}
+		memset(dma_coherent, 0, acb->uncache_size);
+		acb->dma_coherent = dma_coherent;
+		acb->dma_coherent_handle = dma_coherent_handle;
+		ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+		acb->vir2phy_offset = (unsigned long)dma_coherent -
+			(unsigned long)dma_coherent_handle;
+		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+			cdb_phyaddr = dma_coherent_handle +
+				offsetof(struct CommandControlBlock,
+				arcmsr_cdb);
+			ccb_tmp->cdb_phyaddr = cdb_phyaddr >> 5;
+			acb->pccb_pool[i] = ccb_tmp;
+			ccb_tmp->acb = acb;
+			INIT_LIST_HEAD(&ccb_tmp->list);
+			list_add_tail(&ccb_tmp->list,
+			&acb->ccb_free_list);
+			ccb_tmp = (struct CommandControlBlock *)
+			((unsigned long)ccb_tmp + roundup_ccbsize);
+			dma_coherent_handle = dma_coherent_handle +
+				roundup_ccbsize;
+		}
+		break;
+	}
+	case ACB_ADAPTER_TYPE_B: {
+		roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) +
+			(max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+		acb->uncache_size = roundup_ccbsize *
+			ARCMSR_MAX_FREECCB_NUM;
+		dma_coherent = dma_alloc_coherent(&pdev->dev,
+			acb->uncache_size, &dma_coherent_handle,
+			GFP_KERNEL);
+		if (!dma_coherent) {
+			pr_notice("DMA allocation failed....\n");
+			return -ENOMEM;
+		}
+		memset(dma_coherent, 0, acb->uncache_size);
+		acb->dma_coherent = dma_coherent;
+		acb->dma_coherent_handle = dma_coherent_handle;
+		ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+		acb->vir2phy_offset = (unsigned long)dma_coherent -
+			(unsigned long)dma_coherent_handle;
+		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+			cdb_phyaddr = dma_coherent_handle +
+			offsetof(struct CommandControlBlock,
+			arcmsr_cdb);
+			ccb_tmp->cdb_phyaddr = cdb_phyaddr >> 5;
+			acb->pccb_pool[i] = ccb_tmp;
+			ccb_tmp->acb = acb;
+			INIT_LIST_HEAD(&ccb_tmp->list);
+			list_add_tail(&ccb_tmp->list,
+			&acb->ccb_free_list);
+			ccb_tmp = (struct CommandControlBlock *)
+			((unsigned long)ccb_tmp + roundup_ccbsize);
+			dma_coherent_handle = dma_coherent_handle +
+			roundup_ccbsize;
+		}
+		break;
+	}
+	case ACB_ADAPTER_TYPE_C: {
+		roundup_ccbsize =
+		roundup(sizeof(struct CommandControlBlock) +
+		(max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+		acb->uncache_size = roundup_ccbsize *
+		ARCMSR_MAX_FREECCB_NUM;
+		dma_coherent = dma_alloc_coherent(&pdev->dev,
+			acb->uncache_size,
+			&dma_coherent_handle,
+			GFP_KERNEL);
+		if (!dma_coherent) {
+			pr_notice("arcmsr%d: dma_alloc_coherent "
+			"got error\n", acb->host->host_no);
+			return -ENOMEM;
+		}
+		memset(dma_coherent, 0, acb->uncache_size);
+		acb->dma_coherent = dma_coherent;
+		acb->dma_coherent_handle = dma_coherent_handle;
+		acb->vir2phy_offset = (unsigned long)dma_coherent -
+		(unsigned long)dma_coherent_handle;
+		ccb_tmp = dma_coherent;
+		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+			cdb_phyaddr = dma_coherent_handle +
+			offsetof(struct CommandControlBlock,
+			arcmsr_cdb);
+			ccb_tmp->cdb_phyaddr = cdb_phyaddr;
+			acb->pccb_pool[i] = ccb_tmp;
+			ccb_tmp->acb = acb;
+			INIT_LIST_HEAD(&ccb_tmp->list);
+			list_add_tail(&ccb_tmp->list,
+				&acb->ccb_free_list);
+			ccb_tmp = (struct CommandControlBlock *)
+				((unsigned long)ccb_tmp +
+				roundup_ccbsize);
+			dma_coherent_handle = dma_coherent_handle +
+				roundup_ccbsize;
+		}
+		break;
+	}
+	case ACB_ADAPTER_TYPE_D: {
+		void *dma_coherent;
+		dma_addr_t dma_coherent_handle;
+
+		roundup_ccbsize = roundup(sizeof(struct CommandControlBlock)
+		+ (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+		dma_coherent = dma_alloc_coherent(&pdev->dev,
+			roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM,
+			&dma_coherent_handle, GFP_KERNEL);
+		if (!dma_coherent) {
+			pr_notice("DMA allocation failed...\n");
+			return -ENOMEM;
+		}
+		acb->roundup_ccbsize = roundup_ccbsize;
+		acb->dma_coherent2 = dma_coherent;
+		acb->dma_coherent_handle2 = dma_coherent_handle;
+		ccb_tmp = dma_coherent;
+		acb->vir2phy_offset = (unsigned long)dma_coherent -
+			(unsigned long)dma_coherent_handle;
+		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+			cdb_phyaddr = dma_coherent_handle +
+			offsetof(struct CommandControlBlock, arcmsr_cdb);
+			ccb_tmp->cdb_phyaddr =
+			cdb_phyaddr;
+			acb->pccb_pool[i] = ccb_tmp;
+			ccb_tmp->acb = acb;
+			INIT_LIST_HEAD(&ccb_tmp->list);
+			list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
+			ccb_tmp = (struct CommandControlBlock *)
+				((unsigned long)ccb_tmp + roundup_ccbsize);
+			dma_coherent_handle = dma_coherent_handle
+				+ roundup_ccbsize;
+		}
 	}
-	acb->dma_coherent = dma_coherent;
-	acb->dma_coherent_handle = dma_coherent_handle;
-	memset(dma_coherent, 0, acb->uncache_size);
-	ccb_tmp = dma_coherent;
-	acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
-	for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
-		cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
-		ccb_tmp->cdb_phyaddr_pattern = ((acb->adapter_type == ACB_ADAPTER_TYPE_C) ? cdb_phyaddr : (cdb_phyaddr >> 5));
-		acb->pccb_pool[i] = ccb_tmp;
-		ccb_tmp->acb = acb;
-		INIT_LIST_HEAD(&ccb_tmp->list);
-		list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
-		ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize);
-		dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
 	}
+	for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
+		for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
+			acb->devstate[i][j] = ARECA_RAID_GONE;
 	return 0;
 }
 
-static void arcmsr_message_isr_bh_fn(struct work_struct *work) 
+static void
+arcmsr_message_isr_bh_fn(struct work_struct *work)
 {
-	struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh);
+	struct AdapterControlBlock *acb = container_of(work,
+		struct AdapterControlBlock, arcmsr_do_message_isr_bh);
 	switch (acb->adapter_type) {
-		case ACB_ADAPTER_TYPE_A: {
-
-			struct MessageUnit_A __iomem *reg  = acb->pmuA;
-			char *acb_dev_map = (char *)acb->device_map;
-			uint32_t __iomem *signature = (uint32_t __iomem*) (&reg->message_rwbuffer[0]);
-			char __iomem *devicemap = (char __iomem*) (&reg->message_rwbuffer[21]);
-			int target, lun;
-			struct scsi_device *psdev;
-			char diff;
-
-			atomic_inc(&acb->rq_map_token);
-			if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
-				for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) {
-					diff = (*acb_dev_map)^readb(devicemap);
-					if (diff != 0) {
-						char temp;
-						*acb_dev_map = readb(devicemap);
-						temp =*acb_dev_map;
-						for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
-							if((temp & 0x01)==1 && (diff & 0x01) == 1) {	
-								scsi_add_device(acb->host, 0, target, lun);
-							}else if((temp & 0x01) == 0 && (diff & 0x01) == 1) {
-								psdev = scsi_device_lookup(acb->host, 0, target, lun);
-								if (psdev != NULL ) {
-									scsi_remove_device(psdev);
-									scsi_device_put(psdev);
-								}
+	case ACB_ADAPTER_TYPE_A: {
+		struct MessageUnit_A __iomem *reg  = acb->pmuA;
+		char *acb_dev_map = (char *)acb->device_map;
+		uint32_t __iomem *signature = (uint32_t __iomem *)
+			(&reg->message_rwbuffer[0]);
+		char __iomem *devicemap = (char __iomem *)
+			(&reg->message_rwbuffer[21]);
+		int target, lun;
+		struct scsi_device *psdev;
+		char diff;
+
+		atomic_inc(&acb->rq_map_token);
+		if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+			for (target = 0; target < ARCMSR_MAX_TARGETID - 1;
+			target++) {
+				diff = (*acb_dev_map) ^ readb(devicemap);
+				if (diff != 0) {
+					char temp;
+					*acb_dev_map = readb(devicemap);
+					temp = *acb_dev_map;
+					for (lun = 0; lun <
+					ARCMSR_MAX_TARGETLUN; lun++) {
+						if ((temp & 0x01) == 1 &&
+						(diff & 0x01) == 1) {
+							scsi_add_device(acb->host,
+							0, target, lun);
+						} else if ((temp & 0x01) == 0
+						&& (diff & 0x01) == 1) {
+							psdev =
+							scsi_device_lookup(acb->host,
+							0, target, lun);
+							if (psdev != NULL) {
+								scsi_remove_device(psdev);
+								scsi_device_put(psdev);
 							}
-							temp >>= 1;
-							diff >>= 1;
 						}
+						temp >>= 1;
+						diff >>= 1;
 					}
-					devicemap++;
-					acb_dev_map++;
 				}
+				devicemap++;
+				acb_dev_map++;
 			}
-			break;
 		}
+		break;
+	}
 
-		case ACB_ADAPTER_TYPE_B: {
-			struct MessageUnit_B *reg  = acb->pmuB;
-			char *acb_dev_map = (char *)acb->device_map;
-			uint32_t __iomem *signature = (uint32_t __iomem*)(&reg->message_rwbuffer[0]);
-			char __iomem *devicemap = (char __iomem*)(&reg->message_rwbuffer[21]);
-			int target, lun;
-			struct scsi_device *psdev;
-			char diff;
-
-			atomic_inc(&acb->rq_map_token);
-			if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
-				for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) {
-					diff = (*acb_dev_map)^readb(devicemap);
-					if (diff != 0) {
-						char temp;
-						*acb_dev_map = readb(devicemap);
-						temp =*acb_dev_map;
-						for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
-							if((temp & 0x01)==1 && (diff & 0x01) == 1) {	
-								scsi_add_device(acb->host, 0, target, lun);
-							}else if((temp & 0x01) == 0 && (diff & 0x01) == 1) {
-								psdev = scsi_device_lookup(acb->host, 0, target, lun);
-								if (psdev != NULL ) {
-									scsi_remove_device(psdev);
-									scsi_device_put(psdev);
-								}
+	case ACB_ADAPTER_TYPE_B: {
+		struct MessageUnit_B *reg  = acb->pmuB;
+		char *acb_dev_map = (char *)acb->device_map;
+		uint32_t __iomem *signature =
+			(uint32_t __iomem *)(&reg->message_rwbuffer[0]);
+		char __iomem *devicemap =
+			(char __iomem *)(&reg->message_rwbuffer[21]);
+		int target, lun;
+		struct scsi_device *psdev;
+		char diff;
+
+		atomic_inc(&acb->rq_map_token);
+		if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+			for (target = 0; target <
+			ARCMSR_MAX_TARGETID - 1; target++) {
+				diff = (*acb_dev_map) ^ readb(devicemap);
+				if (diff != 0) {
+					char temp;
+					*acb_dev_map = readb(devicemap);
+					temp = *acb_dev_map;
+					for (lun = 0;
+					lun < ARCMSR_MAX_TARGETLUN;
+					lun++) {
+						if ((temp & 0x01) == 1 &&
+						(diff & 0x01) == 1) {
+							scsi_add_device(acb->host,
+							0, target, lun);
+						} else if ((temp & 0x01) == 0
+						&& (diff & 0x01) == 1) {
+							psdev = scsi_device_lookup(acb->host,
+							0, target, lun);
+							if (psdev != NULL) {
+								scsi_remove_device(psdev);
+								scsi_device_put(psdev);
 							}
-							temp >>= 1;
-							diff >>= 1;
 						}
+						temp >>= 1;
+						diff >>= 1;
 					}
-					devicemap++;
-					acb_dev_map++;
 				}
+				devicemap++;
+				acb_dev_map++;
 			}
 		}
-		break;
-		case ACB_ADAPTER_TYPE_C: {
-			struct MessageUnit_C *reg  = acb->pmuC;
-			char *acb_dev_map = (char *)acb->device_map;
-			uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer[0]);
-			char __iomem *devicemap = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
-			int target, lun;
-			struct scsi_device *psdev;
-			char diff;
-
-			atomic_inc(&acb->rq_map_token);
-			if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
-				for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
-					diff = (*acb_dev_map)^readb(devicemap);
-					if (diff != 0) {
-						char temp;
-						*acb_dev_map = readb(devicemap);
-						temp = *acb_dev_map;
-						for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
-							if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
-								scsi_add_device(acb->host, 0, target, lun);
-							} else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
-								psdev = scsi_device_lookup(acb->host, 0, target, lun);
-								if (psdev != NULL) {
-									scsi_remove_device(psdev);
-									scsi_device_put(psdev);
-								}
+	}
+	break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *reg  = acb->pmuC;
+		char *acb_dev_map = (char *)acb->device_map;
+		uint32_t __iomem *signature =
+			(uint32_t __iomem *)(&reg->msgcode_rwbuffer[0]);
+		char __iomem *devicemap =
+			(char __iomem *)(&reg->msgcode_rwbuffer[21]);
+		int target, lun;
+		struct scsi_device *psdev;
+		char diff;
+
+		atomic_inc(&acb->rq_map_token);
+		if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+			for (target = 0; target <
+				ARCMSR_MAX_TARGETID - 1; target++) {
+				diff = (*acb_dev_map) ^ readb(devicemap);
+				if (diff != 0) {
+					char temp;
+					*acb_dev_map =
+						readb(devicemap);
+					temp = *acb_dev_map;
+					for (lun = 0; lun <
+					ARCMSR_MAX_TARGETLUN; lun++) {
+						if ((temp & 0x01) == 1 &&
+						(diff & 0x01) == 1) {
+							scsi_add_device(acb->host,
+							0, target, lun);
+						} else if ((temp & 0x01) == 0
+						&& (diff & 0x01) == 1) {
+							psdev = scsi_device_lookup(acb->host,
+							0, target, lun);
+							if (psdev != NULL) {
+								scsi_remove_device(psdev);
+								scsi_device_put(psdev);
+							}
+						}
+						temp >>= 1;
+						diff >>= 1;
+					}
+				}
+				devicemap++;
+				acb_dev_map++;
+			}
+		}
+	}
+	break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *reg  = acb->pmuD;
+		char *acb_dev_map = (char *)acb->device_map;
+		uint32_t __iomem *signature =
+			(uint32_t __iomem *)(&reg->msgcode_rwbuffer[0]);
+		char __iomem *devicemap =
+			(char __iomem *)(&reg->msgcode_rwbuffer[21]);
+		int target, lun;
+		struct scsi_device *psdev;
+		char diff;
+
+		atomic_inc(&acb->rq_map_token);
+		if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+			for (target = 0; target <
+				ARCMSR_MAX_TARGETID - 1; target++) {
+				diff = (*acb_dev_map) ^ readb(devicemap);
+				if (diff != 0) {
+					char temp;
+					*acb_dev_map =
+						readb(devicemap);
+					temp = *acb_dev_map;
+					for (lun = 0; lun <
+					ARCMSR_MAX_TARGETLUN; lun++) {
+						if ((temp & 0x01) == 1 &&
+						(diff & 0x01) == 1) {
+							scsi_add_device(acb->host,
+							0, target, lun);
+						} else if ((temp & 0x01) == 0
+						&& (diff & 0x01) == 1) {
+							psdev = scsi_device_lookup(acb->host,
+							0, target, lun);
+							if (psdev != NULL) {
+								scsi_remove_device(psdev);
+								scsi_device_put(psdev);
 							}
-							temp >>= 1;
-							diff >>= 1;
 						}
+						temp >>= 1;
+						diff >>= 1;
 					}
-					devicemap++;
-					acb_dev_map++;
 				}
+				devicemap++;
+				acb_dev_map++;
 			}
 		}
+		break;
+	}
+	}
+}
+
+static int
+arcmsr_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+	int i;
+	uint32_t intmask_org;
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	struct AdapterControlBlock *acb =
+		(struct AdapterControlBlock *)host->hostdata;
+
+	intmask_org = arcmsr_disable_outbound_ints(acb);
+	if (acb->acb_flags & ACB_F_MSI_ENABLED) {
+		free_irq(pdev->irq, acb);
+		pci_disable_msi(pdev);
+	} else if (acb->acb_flags & ACB_F_MSIX_ENABLED) {
+		for (i = 0; i < ARCMST_NUM_MSIX_VECTORS; i++)
+			free_irq(acb->entries[i].vector, acb);
+		pci_disable_msix(pdev);
+	} else
+		free_irq(pdev->irq, acb);
+	del_timer_sync(&acb->eternal_timer);
+	flush_scheduled_work();
+	arcmsr_stop_adapter_bgrb(acb);
+	arcmsr_flush_adapter_cache(acb);
+	arcmsr_enable_outbound_ints(acb, intmask_org);
+	pci_set_drvdata(pdev, host);
+	pci_save_state(pdev);
+	pci_disable_device(pdev);
+	pci_set_power_state(pdev, pci_choose_state(pdev, state));
+	return 0;
+}
+
+static int
+arcmsr_resume(struct pci_dev *pdev)
+{
+	int error, i, j;
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	struct AdapterControlBlock *acb =
+		(struct AdapterControlBlock *)host->hostdata;
+	struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS];
+	pci_set_power_state(pdev, PCI_D0);
+	pci_enable_wake(pdev, PCI_D0, 0);
+	pci_restore_state(pdev);
+	if (pci_enable_device(pdev)) {
+		pr_warn("%s: pci_enable_device error\n", __func__);
+		return -ENODEV;
+	}
+	error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+	if (error) {
+		error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+		if (error) {
+				pr_warn("scsi%d: No suitable DMA mask available\n",
+			       host->host_no);
+			goto controller_unregister;
+		}
 	}
+	pci_set_master(pdev);
+	if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+		if (!pci_enable_msix(pdev, entries,
+			ARCMST_NUM_MSIX_VECTORS)) {
+			for (i = 0; i < ARCMST_NUM_MSIX_VECTORS;
+			i++) {
+				entries[i].entry = i;
+				if (request_irq(entries[i].vector,
+				arcmsr_do_interrupt, 0,
+				"arcmsr", acb)) {
+					for (j = 0 ; j < i ; j++)
+						free_irq(entries[i].vector,
+						acb);
+					goto controller_stop;
+				}
+				acb->entries[i] = entries[i];
+			}
+			acb->acb_flags |= ACB_F_MSIX_ENABLED;
+		} else {
+			pr_warn("arcmsr%d: MSI-X "
+			"failed to enable\n", acb->host->host_no);
+			if (request_irq(pdev->irq,
+			arcmsr_do_interrupt, IRQF_SHARED,
+			"arcmsr", acb)) {
+				goto controller_stop;
+			}
+		}
+	} else if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
+		if (!pci_enable_msi(pdev))
+			acb->acb_flags |= ACB_F_MSI_ENABLED;
+		if (request_irq(pdev->irq, arcmsr_do_interrupt,
+			IRQF_SHARED, "arcmsr", acb)) {
+			goto controller_stop;
+		}
+	} else {
+		if (request_irq(pdev->irq, arcmsr_do_interrupt,
+			IRQF_SHARED, "arcmsr", acb)) {
+			goto controller_stop;
+		}
+	}
+	arcmsr_iop_init(acb);
+	INIT_WORK(&acb->arcmsr_do_message_isr_bh,
+	arcmsr_message_isr_bh_fn);
+	atomic_set(&acb->rq_map_token, 16);
+	atomic_set(&acb->ante_token_value, 16);
+	acb->fw_flag = FW_NORMAL;
+	init_timer(&acb->eternal_timer);
+	acb->eternal_timer.expires = jiffies +
+		msecs_to_jiffies(6 * HZ);
+	acb->eternal_timer.data = (unsigned long) acb;
+	acb->eternal_timer.function =
+		&arcmsr_request_device_map;
+	add_timer(&acb->eternal_timer);
+	return 0;
+controller_stop:
+		arcmsr_stop_adapter_bgrb(acb);
+		arcmsr_flush_adapter_cache(acb);
+controller_unregister:
+		scsi_remove_host(host);
+		arcmsr_free_ccb_pool(acb);
+		arcmsr_unmap_pciregion(acb);
+		pci_release_regions(pdev);
+		scsi_host_put(host);
+		pci_disable_device(pdev);
+	return -ENODEV;
 }
 
 static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
 	struct Scsi_Host *host;
 	struct AdapterControlBlock *acb;
-	uint8_t bus,dev_fun;
-	int error;
+	uint8_t bus, dev_fun;
+	struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS];
+	int error, i, j;
 	error = pci_enable_device(pdev);
-	if(error){
+	if (error)
 		return -ENODEV;
-	}
-	host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock));
-	if(!host){
+	host = scsi_host_alloc(&arcmsr_scsi_host_template,
+		sizeof(struct AdapterControlBlock));
+	if (!host)
     		goto pci_disable_dev;
-	}
 	error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
-	if(error){
+	if (error) {
 		error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-		if(error){
-			printk(KERN_WARNING
-			       "scsi%d: No suitable DMA mask available\n",
+		if (error) {
+			pr_warn("scsi%d: No suitable DMA mask available\n",
 			       host->host_no);
 			goto scsi_host_release;
 		}
@@ -634,70 +1083,115 @@ static int arcmsr_probe(struct pci_dev *
 	acb->pdev = pdev;
 	acb->host = host;
 	host->max_lun = ARCMSR_MAX_TARGETLUN;
-	host->max_id = ARCMSR_MAX_TARGETID;		/*16:8*/
-	host->max_cmd_len = 16;	 			/*this is issue of 64bit LBA ,over 2T byte*/
-	host->can_queue = ARCMSR_MAX_FREECCB_NUM;	/* max simultaneous cmds */		
-	host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;	    
+	host->max_id = ARCMSR_MAX_TARGETID;
+	host->max_cmd_len = 16;
+	host->can_queue = ARCMSR_MAX_FREECCB_NUM;
+	host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN;
 	host->this_id = ARCMSR_SCSI_INITIATOR_ID;
 	host->unique_id = (bus << 8) | dev_fun;
 	pci_set_drvdata(pdev, host);
 	pci_set_master(pdev);
 	error = pci_request_regions(pdev, "arcmsr");
-	if(error){
+	if (error)
 		goto scsi_host_release;
-	}
 	spin_lock_init(&acb->eh_lock);
 	spin_lock_init(&acb->ccblist_lock);
+	spin_lock_init(&acb->postq_lock);
+	spin_lock_init(&acb->doneq_lock);
+	spin_lock_init(&acb->rqbuffer_lock);
+	spin_lock_init(&acb->wqbuffer_lock);
 	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
 			ACB_F_MESSAGE_RQBUFFER_CLEARED |
 			ACB_F_MESSAGE_WQBUFFER_READED);
 	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
 	INIT_LIST_HEAD(&acb->ccb_free_list);
-	arcmsr_define_adapter_type(acb);
+	error = arcmsr_define_adapter_type(acb);
+	if (!error)
+		goto pci_release_regs;
 	error = arcmsr_remap_pciregion(acb);
-	if(!error){
+	if (!error)
 		goto pci_release_regs;
-	}
 	error = arcmsr_get_firmware_spec(acb);
-	if(!error){
+	if (!error)
 		goto unmap_pci_region;
-	}
 	error = arcmsr_alloc_ccb_pool(acb);
-	if(error){
+	if (error)
 		goto free_hbb_mu;
-	}
-	arcmsr_iop_init(acb);
 	error = scsi_add_host(host, &pdev->dev);
-	if(error){
+	if (error)
 		goto RAID_controller_stop;
-	}
-	error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb);
-	if(error){
-		goto scsi_host_remove;
+	if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) {
+		if (!pci_enable_msix(pdev, entries, ARCMST_NUM_MSIX_VECTORS)) {
+			for (i = 0; i < ARCMST_NUM_MSIX_VECTORS; i++) {
+				entries[i].entry = i;
+				if (request_irq(entries[i].vector,
+					arcmsr_do_interrupt, 0, "arcmsr",
+					acb)) {
+					for (j = 0 ; j < i ; j++)
+						free_irq(entries[i].vector,
+						acb);
+					goto scsi_host_remove;
+				}
+				acb->entries[i] = entries[i];
+			}
+			acb->acb_flags |= ACB_F_MSIX_ENABLED;
+		} else {
+			if (request_irq(pdev->irq, arcmsr_do_interrupt,
+				IRQF_SHARED, "arcmsr", acb)) {
+				printk("arcmsr%d: request_irq = %d failed!\n",
+					acb->host->host_no, pdev->irq);
+				goto scsi_host_remove;
+			}
+		}
+	} else if (pci_find_capability(pdev, PCI_CAP_ID_MSI)) {
+		if (!pci_enable_msi(pdev))
+			acb->acb_flags |= ACB_F_MSI_ENABLED;
+		if (request_irq(pdev->irq, arcmsr_do_interrupt,
+			IRQF_SHARED, "arcmsr", acb)) {
+			pr_warn("arcmsr%d: request_irq =%d failed!\n",
+				acb->host->host_no, pdev->irq);
+			goto scsi_host_remove;
+		}
+	} else {
+		if (request_irq(pdev->irq, arcmsr_do_interrupt,
+			IRQF_SHARED, "arcmsr", acb)) {
+			pr_warn("arcmsr%d: request_irq = %d failed!\n",
+				acb->host->host_no, pdev->irq);
+			goto scsi_host_remove;
+		}
 	}
 	host->irq = pdev->irq;
-    	scsi_scan_host(host);
-	INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
+	arcmsr_iop_init(acb);
+	scsi_scan_host(host);
+	INIT_WORK(&acb->arcmsr_do_message_isr_bh,
+		arcmsr_message_isr_bh_fn);
 	atomic_set(&acb->rq_map_token, 16);
 	atomic_set(&acb->ante_token_value, 16);
 	acb->fw_flag = FW_NORMAL;
 	init_timer(&acb->eternal_timer);
-	acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ);
+	acb->eternal_timer.expires = jiffies +
+		msecs_to_jiffies(6 * HZ);
 	acb->eternal_timer.data = (unsigned long) acb;
-	acb->eternal_timer.function = &arcmsr_request_device_map;
+	acb->eternal_timer.function =
+		&arcmsr_request_device_map;
 	add_timer(&acb->eternal_timer);
-	if(arcmsr_alloc_sysfs_attr(acb))
+	if (arcmsr_alloc_sysfs_attr(acb))
 		goto out_free_sysfs;
 	return 0;
 out_free_sysfs:
 scsi_host_remove:
+	if (acb->acb_flags & ACB_F_MSI_ENABLED) {
+		pci_disable_msi(pdev);
+	} else if (acb->acb_flags & ACB_F_MSIX_ENABLED) {
+		pci_disable_msix(pdev);
+	}
 	scsi_remove_host(host);
 RAID_controller_stop:
 	arcmsr_stop_adapter_bgrb(acb);
 	arcmsr_flush_adapter_cache(acb);
 	arcmsr_free_ccb_pool(acb);
 free_hbb_mu:
-	arcmsr_free_hbb_mu(acb);
+	arcmsr_free_mu(acb);
 unmap_pci_region:
 	arcmsr_unmap_pciregion(acb);
 pci_release_regs:
@@ -709,85 +1203,112 @@ pci_disable_dev:
 	return -ENODEV;
 }
 
-static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
+static uint8_t
+arcmsr_hbaA_abort_allcmd(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
-	writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
-	if (!arcmsr_hba_wait_msgint_ready(acb)) {
-		printk(KERN_NOTICE
-			"arcmsr%d: wait 'abort all outstanding command' timeout \n"
-			, acb->host->host_no);
+	writel(ARCMSR_INBOUND_MESG0_ABORT_CMD,
+		&reg->inbound_msgaddr0);
+	if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
+		pr_notice("arcmsr%d: wait 'abort all outstanding "
+		"command' timeout\n"
+		, acb->host->host_no);
 		return false;
 	}
 	return true;
 }
 
-static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
+static uint8_t
+arcmsr_hbaB_abort_allcmd(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 
-	writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
-	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
-		printk(KERN_NOTICE
-			"arcmsr%d: wait 'abort all outstanding command' timeout \n"
-			, acb->host->host_no);
+	writel(ARCMSR_MESSAGE_ABORT_CMD,
+		reg->drv2iop_doorbell);
+	if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+		pr_notice("arcmsr%d: wait 'abort all outstanding "
+		"command' timeout\n"
+		, acb->host->host_no);
 		return false;
 	}
 	return true;
 }
-static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB)
+static uint8_t
+arcmsr_hbaC_abort_allcmd(struct AdapterControlBlock *pACB)
 {
 	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
 	writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
 	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
-	if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
-		printk(KERN_NOTICE
-			"arcmsr%d: wait 'abort all outstanding command' timeout \n"
-			, pACB->host->host_no);
+	if (!arcmsr_hbaC_wait_msgint_ready(pACB)) {
+		pr_notice("arcmsr%d: wait 'abort all outstanding "
+		"command' timeout\n"
+		, pACB->host->host_no);
+		return false;
+	}
+	return true;
+}
+static uint8_t
+arcmsr_hbaD_abort_allcmd(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit_D __iomem *reg = (struct MessageUnit_D *)pACB->pmuD;
+	writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, reg->inbound_msgaddr0);
+	if (!arcmsr_hbaD_wait_msgint_ready(pACB)) {
+		pr_notice("arcmsr%d: wait 'abort all outstanding "
+		"command' timeout\n"
+		, pACB->host->host_no);
 		return false;
 	}
 	return true;
 }
-static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+static uint8_t
+arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
 {
 	uint8_t rtnval = 0;
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A: {
-		rtnval = arcmsr_abort_hba_allcmd(acb);
+		rtnval = arcmsr_hbaA_abort_allcmd(acb);
 		}
 		break;
 
 	case ACB_ADAPTER_TYPE_B: {
-		rtnval = arcmsr_abort_hbb_allcmd(acb);
+		rtnval = arcmsr_hbaB_abort_allcmd(acb);
 		}
 		break;
 
 	case ACB_ADAPTER_TYPE_C: {
-		rtnval = arcmsr_abort_hbc_allcmd(acb);
+		rtnval = arcmsr_hbaC_abort_allcmd(acb);
 		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		rtnval = arcmsr_hbaD_abort_allcmd(acb);
+	}
 	}
 	return rtnval;
 }
 
-static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb)
+static bool
+arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb)
 {
 	struct MessageUnit_B *reg = pacb->pmuB;
-	writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
-	if (!arcmsr_hbb_wait_msgint_ready(pacb)) {
-		printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no);
+	writel(ARCMSR_MESSAGE_START_DRIVER_MODE,
+		reg->drv2iop_doorbell);
+	if (!arcmsr_hbaB_wait_msgint_ready(pacb)) {
+		pr_err("arcmsr%d: can't set driver mode.\n",
+			pacb->host->host_no);
 		return false;
 	}
     	return true;
 }
 
-static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
+static void
+arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
 {
 	struct scsi_cmnd *pcmd = ccb->pcmd;
-
 	scsi_dma_unmap(pcmd);
 }
 
-static void arcmsr_ccb_complete(struct CommandControlBlock *ccb)
+static void
+arcmsr_ccb_complete(struct CommandControlBlock *ccb)
 {
 	struct AdapterControlBlock *acb = ccb->acb;
 	struct scsi_cmnd *pcmd = ccb->pcmd;
@@ -801,32 +1322,38 @@ static void arcmsr_ccb_complete(struct C
 	pcmd->scsi_done(pcmd);
 }
 
-static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
+static void
+arcmsr_report_sense_info(struct CommandControlBlock *ccb)
 {
 
 	struct scsi_cmnd *pcmd = ccb->pcmd;
-	struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer;
-	pcmd->result = DID_OK << 16;
+	struct SENSE_DATA *sensebuffer =
+		(struct SENSE_DATA *)pcmd->sense_buffer;
+	pcmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1)
+		| (DRIVER_SENSE << 24);
 	if (sensebuffer) {
 		int sense_data_length =
 			sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE
 			? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE;
 		memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE);
-		memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length);
+		memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData,
+			sense_data_length);
 		sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
 		sensebuffer->Valid = 1;
 	}
 }
 
-static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
+static u32
+arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
 {
 	u32 orig_mask = 0;
 	switch (acb->adapter_type) {	
 	case ACB_ADAPTER_TYPE_A : {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 		orig_mask = readl(&reg->outbound_intmask);
-		writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \
-						&reg->outbound_intmask);
+		writel(orig_mask |
+			ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
+			&reg->outbound_intmask);
 		}
 		break;
 	case ACB_ADAPTER_TYPE_B : {
@@ -835,18 +1362,30 @@ static u32 arcmsr_disable_outbound_ints(
 		writel(0, reg->iop2drv_doorbell_mask);
 		}
 		break;
-	case ACB_ADAPTER_TYPE_C:{
-		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C __iomem *reg =
+			(struct MessageUnit_C *)acb->pmuC;
 		/* disable all outbound interrupt */
-		orig_mask = readl(&reg->host_int_mask); /* disable outbound message0 int */
-		writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, &reg->host_int_mask);
+		orig_mask = readl(&reg->host_int_mask);
+		writel(orig_mask | ARCMSR_HBCMU_ALL_INTMASKENABLE,
+			&reg->host_int_mask);
+		readl(&reg->host_int_mask);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *reg =
+			(struct MessageUnit_D *)acb->pmuD;
+		/* disable all outbound interrupt */
+		writel(ARCMSR_ARC1214_ALL_INT_DISABLE,
+		reg->pcief0_int_enable);
+		break;
+	}
 	}
 	return orig_mask;
 }
 
-static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, 
+static void
+arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
 			struct CommandControlBlock *ccb, bool error)
 {
 	uint8_t id, lun;
@@ -857,7 +1396,7 @@ static void arcmsr_report_ccb_state(stru
 			acb->devstate[id][lun] = ARECA_RAID_GOOD;
 		ccb->pcmd->result = DID_OK << 16;
 		arcmsr_ccb_complete(ccb);
-	}else{
+	} else {
 		switch (ccb->arcmsr_cdb.DeviceStatus) {
 		case ARCMSR_DEV_SELECT_TIMEOUT: {
 			acb->devstate[id][lun] = ARECA_RAID_GONE;
@@ -883,53 +1422,47 @@ static void arcmsr_report_ccb_state(stru
 			break;
 
 		default:
-			printk(KERN_NOTICE
-				"arcmsr%d: scsi id = %d lun = %d isr get command error done, \
-				but got unknown DeviceStatus = 0x%x \n"
-				, acb->host->host_no
-				, id
-				, lun
-				, ccb->arcmsr_cdb.DeviceStatus);
-				acb->devstate[id][lun] = ARECA_RAID_GONE;
-				ccb->pcmd->result = DID_NO_CONNECT << 16;
-				arcmsr_ccb_complete(ccb);
+			pr_notice("arcmsr%d: scsi id = %d lun = %d "
+			"isr get command error done, but got unknown "
+			"DeviceStatus = 0x%x\n"
+			, acb->host->host_no
+			, id
+			, lun
+			, ccb->arcmsr_cdb.DeviceStatus);
+			acb->devstate[id][lun] = ARECA_RAID_GONE;
+			ccb->pcmd->result = DID_NO_CONNECT << 16;
+			arcmsr_ccb_complete(ccb);
 			break;
 		}
 	}
 }
 
-static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
+static void
+arcmsr_drain_donequeue(struct AdapterControlBlock *acb,
+	struct CommandControlBlock *pCCB, bool error)
 {
-	int id, lun;
 	if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
-		if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
-			struct scsi_cmnd *abortcmd = pCCB->pcmd;
-			if (abortcmd) {
-				id = abortcmd->device->id;
-				lun = abortcmd->device->lun;				
-				abortcmd->result |= DID_ABORT << 16;
-				arcmsr_ccb_complete(pCCB);
-				printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n",
-				acb->host->host_no, pCCB);
-			}
-			return;
-		}
-		printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
-				done acb = '0x%p'"
-				"ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x"
-				" ccboutstandingcount = %d \n"
-				, acb->host->host_no
-				, acb
-				, pCCB
-				, pCCB->acb
-				, pCCB->startdone
-				, atomic_read(&acb->ccboutstandingcount));
-		  return;
+		pr_notice("arcmsr%d: isr get an illegal ccb "
+		"command done acb = 0x%p, "
+		"ccb = 0x%p, "
+		"ccbacb = 0x%p, "
+		"startdone = 0x%x, "
+		"pscsi_cmd = 0x%p, "
+		"ccboutstandingcount = %d\n"
+		, acb->host->host_no
+		, acb
+		, pCCB
+		, pCCB->acb
+		, pCCB->startdone
+		, pCCB->pcmd
+		, atomic_read(&acb->ccboutstandingcount));
+		return;
 	}
 	arcmsr_report_ccb_state(acb, pCCB, error);
 }
 
-static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
+static void
+arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
 {
 	int i = 0;
 	uint32_t flag_ccb;
@@ -944,12 +1477,16 @@ static void arcmsr_done4abort_postqueue(
 		outbound_intstatus = readl(&reg->outbound_intstatus) &
 					acb->outbound_int_enable;
 		/*clear and abort all outbound posted Q*/
-		writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
-		while(((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF)
-				&& (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
-			pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
-			pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
-			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+		writel(outbound_intstatus, &reg->outbound_intstatus);
+		while (((flag_ccb = readl(&reg->outbound_queueport))
+			!= 0xFFFFFFFF)
+			&& (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+			pARCMSR_CDB = (struct ARCMSR_CDB *)
+				(acb->vir2phy_offset + (flag_ccb << 5));
+			pCCB = container_of(pARCMSR_CDB,
+			struct CommandControlBlock, arcmsr_cdb);
+			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ?
+				true : false;
 			arcmsr_drain_donequeue(acb, pCCB, error);
 		}
 		}
@@ -957,14 +1494,19 @@ static void arcmsr_done4abort_postqueue(
 
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
-		/*clear all outbound posted Q*/
-		writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); /* clear doorbell interrupt */
+		writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN,
+			reg->iop2drv_doorbell);
 		for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
-			if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0) {
+			flag_ccb = readl(&reg->done_qbuffer[i]);
+			if (flag_ccb != 0) {
 				writel(0, &reg->done_qbuffer[i]);
-				pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/
-				pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
-				error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+				pARCMSR_CDB = (struct ARCMSR_CDB *)
+				(acb->vir2phy_offset + (flag_ccb << 5));
+				pCCB = container_of(pARCMSR_CDB,
+				struct CommandControlBlock, arcmsr_cdb);
+				error = (flag_ccb &
+				ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ?
+				true : false;
 				arcmsr_drain_donequeue(acb, pCCB, error);
 			}
 			reg->post_qbuffer[i] = 0;
@@ -979,27 +1521,85 @@ static void arcmsr_done4abort_postqueue(
 		uint32_t flag_ccb, ccb_cdb_phy;
 		bool error;
 		struct CommandControlBlock *pCCB;
-		while ((readl(&reg->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+		while ((readl(&reg->host_int_status) &
+			ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR)
+			&& (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
 			/*need to do*/
 			flag_ccb = readl(&reg->outbound_queueport_low);
 			ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
-			pARCMSR_CDB = (struct  ARCMSR_CDB *)(acb->vir2phy_offset+ccb_cdb_phy);/*frame must be 32 bytes aligned*/
-			pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
-			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+			pARCMSR_CDB = (struct  ARCMSR_CDB *)
+				(acb->vir2phy_offset+ccb_cdb_phy);
+			pCCB = container_of(pARCMSR_CDB,
+				struct CommandControlBlock, arcmsr_cdb);
+			error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
+				? true : false;
 			arcmsr_drain_donequeue(acb, pCCB, error);
 		}
+		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *pmu = acb->pmuD;
+		uint32_t ccb_cdb_phy, outbound_write_pointer;
+		uint32_t doneq_index, index_stripped, addressLow, residual;
+		bool error;
+		struct CommandControlBlock *pCCB;
+		outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
+		doneq_index = pmu->doneq_index;
+		residual = atomic_read(&acb->ccboutstandingcount);
+		for (i = 0; i < residual; i++) {
+			while ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
+				if (doneq_index & 0x4000) {
+					index_stripped = doneq_index & 0xFFF;
+					index_stripped += 1;
+					index_stripped %=
+					ARCMSR_MAX_ARC1214_DONEQUEUE;
+					pmu->doneq_index = index_stripped ?
+					(index_stripped | 0x4000) : (index_stripped + 1);
+				} else {
+					index_stripped = doneq_index;
+					index_stripped += 1;
+					index_stripped %=
+					ARCMSR_MAX_ARC1214_DONEQUEUE;
+					pmu->doneq_index =
+					index_stripped ? index_stripped : ((index_stripped | 0x4000) + 1);
+				}
+				doneq_index = pmu->doneq_index;
+				addressLow =
+				pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
+				ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
+				pARCMSR_CDB = (struct  ARCMSR_CDB *)
+				(acb->vir2phy_offset + ccb_cdb_phy);
+				pCCB = container_of(pARCMSR_CDB,
+				struct CommandControlBlock, arcmsr_cdb);
+				error =
+				(addressLow & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
+				? true : false;
+				arcmsr_drain_donequeue(acb, pCCB, error);
+				writel(doneq_index,
+					pmu->outboundlist_read_pointer);
+			}
+			mdelay(10);
+			outbound_write_pointer =
+				pmu->done_qbuffer[0].addressLow + 1;
+			doneq_index = pmu->doneq_index;
+		}
+		pmu->postq_index = 0;
+		pmu->doneq_index = 0x40FF;
+		break;
 	}
 	}
 }
-static void arcmsr_remove(struct pci_dev *pdev)
+
+static void
+arcmsr_remove(struct pci_dev *pdev)
 {
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
-	int poll_count = 0;
+		(struct AdapterControlBlock *)host->hostdata;
+	int poll_count = 0, i;
 	arcmsr_free_sysfs_attr(acb);
 	scsi_remove_host(host);
-	flush_work(&acb->arcmsr_do_message_isr_bh);
+	flush_work_sync(&acb->arcmsr_do_message_isr_bh);
 	del_timer_sync(&acb->eternal_timer);
 	arcmsr_disable_outbound_ints(acb);
 	arcmsr_stop_adapter_bgrb(acb);
@@ -1007,20 +1607,20 @@ static void arcmsr_remove(struct pci_dev
 	acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
 	acb->acb_flags &= ~ACB_F_IOP_INITED;
 
-	for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++){
+	for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD;
+	poll_count++) {
 		if (!atomic_read(&acb->ccboutstandingcount))
 			break;
-		arcmsr_interrupt(acb);/* FIXME: need spinlock */
+		arcmsr_interrupt(acb);
 		msleep(25);
 	}
 
 	if (atomic_read(&acb->ccboutstandingcount)) {
-		int i;
-
 		arcmsr_abort_allcmd(acb);
 		arcmsr_done4abort_postqueue(acb);
 		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
-			struct CommandControlBlock *ccb = acb->pccb_pool[i];
+			struct CommandControlBlock *ccb =
+				acb->pccb_pool[i];
 			if (ccb->startdone == ARCMSR_CCB_START) {
 				ccb->startdone = ARCMSR_CCB_ABORTED;
 				ccb->pcmd->result = DID_ABORT << 16;
@@ -1028,9 +1628,17 @@ static void arcmsr_remove(struct pci_dev
 			}
 		}
 	}
-	free_irq(pdev->irq, acb);
 	arcmsr_free_ccb_pool(acb);
-	arcmsr_free_hbb_mu(acb);
+	arcmsr_free_mu(acb);
+	if (acb->acb_flags & ACB_F_MSI_ENABLED) {
+		free_irq(pdev->irq, acb);
+		pci_disable_msi(pdev);
+	} else if (acb->acb_flags & ACB_F_MSIX_ENABLED) {
+		for (i = 0; i < ARCMST_NUM_MSIX_VECTORS; i++)
+			free_irq(acb->entries[i].vector, acb);
+		pci_disable_msix(pdev);
+	} else
+		free_irq(pdev->irq, acb);
 	arcmsr_unmap_pciregion(acb);
 	pci_release_regions(pdev);
 	scsi_host_put(host);
@@ -1038,14 +1646,22 @@ static void arcmsr_remove(struct pci_dev
 	pci_set_drvdata(pdev, NULL);
 }
 
-static void arcmsr_shutdown(struct pci_dev *pdev)
+static void
+arcmsr_shutdown(struct pci_dev *pdev)
 {
+	int i;
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 	struct AdapterControlBlock *acb =
 		(struct AdapterControlBlock *)host->hostdata;
 	del_timer_sync(&acb->eternal_timer);
 	arcmsr_disable_outbound_ints(acb);
-	flush_work(&acb->arcmsr_do_message_isr_bh);
+	if (acb->acb_flags & ACB_F_MSIX_ENABLED) {
+		for (i = 0; i < ARCMST_NUM_MSIX_VECTORS; i++)
+			free_irq(acb->entries[i].vector, acb);
+		pci_disable_msix(pdev);
+	} else
+		free_irq(pdev->irq, acb);
+	flush_work_sync(&acb->arcmsr_do_message_isr_bh);
 	arcmsr_stop_adapter_bgrb(acb);
 	arcmsr_flush_adapter_cache(acb);
 }
@@ -1064,7 +1680,8 @@ static void arcmsr_module_exit(void)
 module_init(arcmsr_module_init);
 module_exit(arcmsr_module_exit);
 
-static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
+static void
+arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
 						u32 intmask_org)
 {
 	u32 mask;
@@ -1072,11 +1689,13 @@ static void arcmsr_enable_outbound_ints(
 
 	case ACB_ADAPTER_TYPE_A: {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
-		mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
-			     ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|
-			     ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
+		mask = intmask_org &
+		~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
+		     ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE |
+		     ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
 		writel(mask, &reg->outbound_intmask);
-		acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
+		acb->outbound_int_enable = ~(intmask_org & mask) &
+			0x000000ff;
 		}
 		break;
 
@@ -1087,22 +1706,34 @@ static void arcmsr_enable_outbound_ints(
 			ARCMSR_IOP2DRV_CDB_DONE |
 			ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
 		writel(mask, reg->iop2drv_doorbell_mask);
-		acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
+		acb->outbound_int_enable = (intmask_org | mask) &
+			0x0000000f;
 		}
 		break;
 	case ACB_ADAPTER_TYPE_C: {
-		struct MessageUnit_C *reg = acb->pmuC;
-		mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
+		struct MessageUnit_C __iomem *reg = acb->pmuC;
+		mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK |
+			ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK |
+			ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
 		writel(intmask_org & mask, &reg->host_int_mask);
-		acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
+		acb->outbound_int_enable = ~(intmask_org & mask) &
+			0x0000000f;
 		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *reg = acb->pmuD;
+		mask = ARCMSR_ARC1214_ALL_INT_ENABLE;
+		writel(intmask_org | mask, reg->pcief0_int_enable);
+	}
 	}
 }
 
-static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
+static int
+arcmsr_build_ccb(struct AdapterControlBlock *acb,
 	struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd)
 {
-	struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
+	struct ARCMSR_CDB *arcmsr_cdb =
+		(struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
 	int8_t *psge = (int8_t *)&arcmsr_cdb->u;
 	__le32 address_lo, address_hi;
 	int arccdbsize = 0x30;
@@ -1115,7 +1746,6 @@ static int arcmsr_build_ccb(struct Adapt
 	arcmsr_cdb->TargetID = pcmd->device->id;
 	arcmsr_cdb->LUN = pcmd->device->lun;
 	arcmsr_cdb->Function = 1;
-	arcmsr_cdb->Context = 0;
 	memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
 
 	nseg = scsi_dma_map(pcmd);
@@ -1127,25 +1757,27 @@ static int arcmsr_build_ccb(struct Adapt
 		address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg)));
 		address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg)));
 		if (address_hi == 0) {
-			struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge;
-
+			struct SG32ENTRY *pdma_sg =
+				(struct SG32ENTRY *)psge;
 			pdma_sg->address = address_lo;
 			pdma_sg->length = length;
 			psge += sizeof (struct SG32ENTRY);
 			arccdbsize += sizeof (struct SG32ENTRY);
 		} else {
-			struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge;
-
+			struct SG64ENTRY *pdma_sg =
+			(struct SG64ENTRY *)psge;
 			pdma_sg->addresshigh = address_hi;
 			pdma_sg->address = address_lo;
-			pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
+			pdma_sg->length = length |
+				cpu_to_le32(IS_SG64_ADDR);
 			psge += sizeof (struct SG64ENTRY);
 			arccdbsize += sizeof (struct SG64ENTRY);
 		}
 	}
 	arcmsr_cdb->sgcount = (uint8_t)nseg;
 	arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
-	arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
+	arcmsr_cdb->msgPages = arccdbsize / 0x100 +
+		(arccdbsize % 0x100 ? 1 : 0);
 	if ( arccdbsize > 256)
 		arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
 	if (pcmd->sc_data_direction == DMA_TO_DEVICE)
@@ -1154,10 +1786,14 @@ static int arcmsr_build_ccb(struct Adapt
 	return SUCCESS;
 }
 
-static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
-{
-	uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern;
-	struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
+static void
+arcmsr_post_ccb(struct AdapterControlBlock *acb,
+	struct CommandControlBlock *ccb)
+{
+	uint32_t cdb_phyaddr = ccb->cdb_phyaddr;
+	struct ARCMSR_CDB *arcmsr_cdb =
+		(struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
+	u32 arccdbsize = ccb->arc_cdb_size;
 	atomic_inc(&acb->ccboutstandingcount);
 	ccb->startdone = ARCMSR_CCB_START;
 	switch (acb->adapter_type) {
@@ -1165,10 +1801,11 @@ static void arcmsr_post_ccb(struct Adapt
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 
 		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
-			writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+			writel(cdb_phyaddr |
+			ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
 			&reg->inbound_queueport);
 		else {
-				writel(cdb_phyaddr_pattern, &reg->inbound_queueport);
+			writel(cdb_phyaddr, &reg->inbound_queueport);
 		}
 		}
 		break;
@@ -1177,119 +1814,209 @@ static void arcmsr_post_ccb(struct Adapt
 		struct MessageUnit_B *reg = acb->pmuB;
 		uint32_t ending_index, index = reg->postq_index;
 
-		ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
+		ending_index = ((index + 1) %
+			ARCMSR_MAX_HBB_POSTQUEUE);
 		writel(0, &reg->post_qbuffer[ending_index]);
 		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {
-			writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
-						 &reg->post_qbuffer[index]);
+			writel(cdb_phyaddr |
+			ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+			 &reg->post_qbuffer[index]);
 		} else {
-			writel(cdb_phyaddr_pattern, &reg->post_qbuffer[index]);
+			writel(cdb_phyaddr,
+				&reg->post_qbuffer[index]);
 		}
 		index++;
-		index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
+		index %= ARCMSR_MAX_HBB_POSTQUEUE;
 		reg->postq_index = index;
-		writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
+		writel(ARCMSR_DRV2IOP_CDB_POSTED,
+			reg->drv2iop_doorbell);
 		}
 		break;
 	case ACB_ADAPTER_TYPE_C: {
-		struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+		struct MessageUnit_C *phbcmu =
+			(struct MessageUnit_C *)acb->pmuC;
 		uint32_t ccb_post_stamp, arc_cdb_size;
 
-		arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size;
-		ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1);
+		arc_cdb_size = (ccb->arc_cdb_size > 0x300)
+			? 0x300 : ccb->arc_cdb_size;
+		ccb_post_stamp = (cdb_phyaddr |
+			((arc_cdb_size - 1) >> 6) | 1);
 		if (acb->cdb_phyaddr_hi32) {
-			writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high);
-			writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+			writel(acb->cdb_phyaddr_hi32,
+			&phbcmu->inbound_queueport_high);
+			writel(ccb_post_stamp,
+			&phbcmu->inbound_queueport_low);
 		} else {
-			writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+			writel(ccb_post_stamp,
+			&phbcmu->inbound_queueport_low);
+		}
 		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D *pmu = acb->pmuD;
+		u16 index_stripped;
+		u16 postq_index;
+		unsigned long flags;
+		struct InBound_SRB *pinbound_srb;
+		spin_lock_irqsave(&acb->postq_lock, flags);
+		postq_index = pmu->postq_index;
+		pinbound_srb = (struct InBound_SRB *)&pmu->post_qbuffer[postq_index & 0xFF];
+		pinbound_srb->addressHigh = dma_addr_hi32(cdb_phyaddr);
+		pinbound_srb->addressLow = dma_addr_lo32(cdb_phyaddr);
+		pinbound_srb->length = arccdbsize / 4;
+		arcmsr_cdb->msgContext = dma_addr_lo32(cdb_phyaddr);
+		if (postq_index & 0x4000) {
+			index_stripped = postq_index & 0xFF;
+			index_stripped += 1;
+			index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
+			pmu->postq_index = index_stripped ? (index_stripped | 0x4000) : index_stripped;
+		} else {
+			index_stripped = postq_index;
+			index_stripped += 1;
+			index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
+			pmu->postq_index = index_stripped ? index_stripped : (index_stripped | 0x4000);
 		}
+		writel(postq_index, pmu->inboundlist_write_pointer);
+		spin_unlock_irqrestore(&acb->postq_lock, flags);
+	}
 	}
 }
 
-static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb)
+static void arcmsr_hbaA_stop_bgrb(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
 	writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
-	if (!arcmsr_hba_wait_msgint_ready(acb)) {
-		printk(KERN_NOTICE
-			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
-			, acb->host->host_no);
+	if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
+		pr_notice("arcmsr%d: wait 'stop adapter "
+		"background rebulid' timeout\n"
+		, acb->host->host_no);
 	}
 }
 
-static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaB_stop_bgrb(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
 	writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
 
-	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
-		printk(KERN_NOTICE
-			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
-			, acb->host->host_no);
+	if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+		pr_notice("arcmsr%d: wait 'stop adapter "
+		"background rebulid' timeout\n"
+		, acb->host->host_no);
 	}
 }
 
-static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB)
+static void
+arcmsr_hbaC_stop_bgrb(struct AdapterControlBlock *pACB)
 {
 	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
 	pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
 	writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
-	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
-	if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
-		printk(KERN_NOTICE
-			"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
-			, pACB->host->host_no);
+	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE,
+		&reg->inbound_doorbell);
+	if (!arcmsr_hbaC_wait_msgint_ready(pACB)) {
+		pr_notice("arcmsr%d: wait 'stop adapter "
+		"background rebulid' timeout\n"
+		, pACB->host->host_no);
 	}
 	return;
 }
-static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+
+static void
+arcmsr_hbaD_stop_bgrb(struct AdapterControlBlock *pACB)
 {
-	switch (acb->adapter_type) {
+	struct MessageUnit_D __iomem *reg =
+		(struct MessageUnit_D *)pACB->pmuD;
+
+	pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
+	writel(ARCMSR_INBOUND_MESG0_STOP_BGRB,
+		reg->inbound_msgaddr0);
+	if (!arcmsr_hbaD_wait_msgint_ready(pACB)) {
+		pr_notice("arcmsr%d: wait 'stop adapter background "
+		"rebulid' timeout\n"
+		, pACB->host->host_no);
+	}
+	return;
+}
+
+static void
+arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
+{
+	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A: {
-		arcmsr_stop_hba_bgrb(acb);
-		}
+		arcmsr_hbaA_stop_bgrb(acb);
 		break;
-
+	}
 	case ACB_ADAPTER_TYPE_B: {
-		arcmsr_stop_hbb_bgrb(acb);
-		}
+		arcmsr_hbaB_stop_bgrb(acb);
 		break;
+	}
 	case ACB_ADAPTER_TYPE_C: {
-		arcmsr_stop_hbc_bgrb(acb);
-		}
+		arcmsr_hbaC_stop_bgrb(acb);
+		break;
+	}
+	case ACB_ADAPTER_TYPE_D: {
+		arcmsr_hbaD_stop_bgrb(acb);
+		break;
+	}
 	}
 }
 
-static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
+static void
+arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
 {
-	dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
+	switch (acb->adapter_type) {
+	case ACB_ADAPTER_TYPE_A:
+	case ACB_ADAPTER_TYPE_C:
+	case ACB_ADAPTER_TYPE_B:
+		dma_free_coherent(&acb->pdev->dev, acb->uncache_size,
+			acb->dma_coherent, acb->dma_coherent_handle);
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
+			acb->dma_coherent2, acb->dma_coherent_handle2);
+		break;
+	}
+	}
 }
 
-void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
+void
+arcmsr_iop_message_read(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A: {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
-		writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+		writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+		&reg->inbound_doorbell);
 		}
 		break;
 
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
-		writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
+		writel(ARCMSR_DRV2IOP_DATA_READ_OK,
+		reg->drv2iop_doorbell);
 		}
 		break;
 	case ACB_ADAPTER_TYPE_C: {
 		struct MessageUnit_C __iomem *reg = acb->pmuC;
 		writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+		/*readl(&reg->inbound_doorbell);*/
 		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *reg = acb->pmuD;
+		writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ,
+		reg->inbound_doorbell);
+		/*readl(reg->inbound_doorbell);*/
+		break;
+	}
 	}
 }
 
-static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
+static void
+arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A: {
@@ -1298,7 +2025,8 @@ static void arcmsr_iop_message_wrote(str
 		** push inbound doorbell tell iop, driver data write ok
 		** and wait reply on next hwinterrupt for next Qbuffer post
 		*/
-		writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, &reg->inbound_doorbell);
+		writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK,
+		&reg->inbound_doorbell);
 		}
 		break;
 
@@ -1308,7 +2036,8 @@ static void arcmsr_iop_message_wrote(str
 		** push inbound doorbell tell iop, driver data write ok
 		** and wait reply on next hwinterrupt for next Qbuffer post
 		*/
-		writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
+		writel(ARCMSR_DRV2IOP_DATA_WRITE_OK,
+		reg->drv2iop_doorbell);
 		}
 		break;
 	case ACB_ADAPTER_TYPE_C: {
@@ -1317,13 +2046,21 @@ static void arcmsr_iop_message_wrote(str
 		** push inbound doorbell tell iop, driver data write ok
 		** and wait reply on next hwinterrupt for next Qbuffer post
 		*/
-		writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, &reg->inbound_doorbell);
+		writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK,
+		&reg->inbound_doorbell);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *reg = acb->pmuD;
+		writel(ARCMSR_ARC1214_DRV2IOP_DATA_IN_READY,
+		reg->inbound_doorbell);
+		break;
+	}
 	}
 }
 
-struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
+struct QBUFFER __iomem
+*arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
 {
 	struct QBUFFER __iomem *qbuffer = NULL;
 	switch (acb->adapter_type) {
@@ -1340,21 +2077,30 @@ struct QBUFFER __iomem *arcmsr_get_iop_r
 		}
 		break;
 	case ACB_ADAPTER_TYPE_C: {
-		struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+		struct MessageUnit_C *phbcmu =
+			(struct MessageUnit_C *)acb->pmuC;
 		qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer;
 		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *reg =
+			(struct MessageUnit_D *)acb->pmuD;
+		qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
+		break;
+	}
 	}
 	return qbuffer;
 }
 
-static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
+struct QBUFFER __iomem
+*arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
 {
 	struct QBUFFER __iomem *pqbuffer = NULL;
 	switch (acb->adapter_type) {
 
 	case ACB_ADAPTER_TYPE_A: {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
-		pqbuffer = (struct QBUFFER __iomem *) &reg->message_wbuffer;
+		pqbuffer = (struct QBUFFER __iomem *)&reg->message_wbuffer;
 		}
 		break;
 
@@ -1366,46 +2112,84 @@ static struct QBUFFER __iomem *arcmsr_ge
 	case ACB_ADAPTER_TYPE_C: {
 		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
 		pqbuffer = (struct QBUFFER __iomem *)&reg->message_wbuffer;
+		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *pmu =
+		(struct MessageUnit_D *)acb->pmuD;
+		pqbuffer = (struct QBUFFER __iomem *)pmu->message_wbuffer;
+		break;
 	}
-
 	}
 	return pqbuffer;
 }
 
-static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
+void
+arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
 {
-	struct QBUFFER __iomem *prbuffer;
-	struct QBUFFER *pQbuffer;
-	uint8_t __iomem *iop_data;
-	int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
+	uint8_t __iomem *iop_data, *pQbuffer, *vaddr, *temp;
+	int32_t buf_empty_len, data_len, data_len_residual;
+	uint32_t rqbuf_firstindex, rqbuf_lastindex;
+	unsigned long flags;
+	struct QBUFFER __iomem  *prbuffer;
+	spin_lock_irqsave(&acb->rqbuffer_lock, flags);
 	rqbuf_lastindex = acb->rqbuf_lastindex;
 	rqbuf_firstindex = acb->rqbuf_firstindex;
 	prbuffer = arcmsr_get_iop_rqbuffer(acb);
 	iop_data = (uint8_t __iomem *)prbuffer->data;
-	iop_len = prbuffer->data_len;
-	my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) & (ARCMSR_MAX_QBUFFER - 1);
-
-	if (my_empty_len >= iop_len)
-	{
-		while (iop_len > 0) {
-			pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex];
-			memcpy(pQbuffer, iop_data, 1);
-			rqbuf_lastindex++;
-			rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-			iop_data++;
-			iop_len--;
+	data_len_residual = data_len = readl(&prbuffer->data_len);
+	buf_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) &
+		(ARCMSR_MAX_QBUFFER - 1);
+	if (buf_empty_len >= data_len) {
+		if (data_len > 0) {
+			temp = vaddr = kmalloc(data_len, GFP_ATOMIC);
+			if (!vaddr) {
+				goto leave;
+			}
+			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+			while (data_len_residual >= 4) {
+				memcpy(temp, iop_data, 4);
+				temp += 4;
+				iop_data += 4;
+				data_len_residual -= 4;
+			}
+			if ((data_len_residual > 0) &&
+			(data_len_residual < 4)) {
+				memcpy(temp, iop_data, data_len_residual);
+			}
+			pQbuffer = &acb->rqbuffer[rqbuf_lastindex];
+			temp = vaddr;
+			if ((rqbuf_lastindex + data_len) >
+			ARCMSR_MAX_QBUFFER) {
+				memcpy(pQbuffer, temp,
+				ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+				temp += (ARCMSR_MAX_QBUFFER -
+				rqbuf_lastindex);
+				rqbuf_lastindex = (rqbuf_lastindex + data_len)
+				% ARCMSR_MAX_QBUFFER;
+				memcpy(&acb->rqbuffer[0], temp,
+				rqbuf_lastindex);
+			} else {
+				memcpy(pQbuffer, temp, data_len);
+				rqbuf_lastindex = (rqbuf_lastindex + data_len)
+				% ARCMSR_MAX_QBUFFER;
+			}
+			kfree(vaddr);
+			acb->rqbuf_lastindex = rqbuf_lastindex;
+			arcmsr_iop_message_read(acb);
 		}
-		acb->rqbuf_lastindex = rqbuf_lastindex;
-		arcmsr_iop_message_read(acb);
-	}
-
-	else {
+	} else {
 		acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
 	}
+	leave:
+	spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
 }
 
-static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
+void
+arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb)
 {
+	unsigned long flags;
+	spin_lock_irqsave(&acb->wqbuffer_lock, flags);
 	acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED;
 	if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
 		uint8_t *pQbuffer;
@@ -1416,65 +2200,201 @@ static void arcmsr_iop2drv_data_read_han
 		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
 		pwbuffer = arcmsr_get_iop_wqbuffer(acb);
 		iop_data = (uint8_t __iomem *)pwbuffer->data;
-
-		while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \
-							(allxfer_len < 124)) {
-			pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex];
-			memcpy(iop_data, pQbuffer, 1);
-			acb->wqbuf_firstindex++;
-			acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
-			iop_data++;
-			allxfer_len++;
+		if (acb->wqbuf_firstindex > acb->wqbuf_lastindex) {
+			if ((ARCMSR_MAX_QBUFFER - acb->wqbuf_firstindex) >= 4) {
+				do {
+					pQbuffer =
+					&acb->wqbuffer[acb->wqbuf_firstindex];
+					if (acb->wqbuf_firstindex + 4
+					> ARCMSR_MAX_QBUFFER) {
+						memcpy(iop_data, pQbuffer,
+						ARCMSR_MAX_QBUFFER
+						- acb->wqbuf_firstindex);
+						iop_data += ARCMSR_MAX_QBUFFER
+						- acb->wqbuf_firstindex;
+						acb->wqbuf_firstindex += 4;
+						acb->wqbuf_firstindex %=
+						ARCMSR_MAX_QBUFFER;
+						memcpy(iop_data,
+						&acb->wqbuffer[0],
+						acb->wqbuf_firstindex);
+						iop_data +=
+						acb->wqbuf_firstindex;
+					} else {
+						if ((acb->wqbuf_lastindex
+						- acb->wqbuf_firstindex) > 4) {
+							memcpy(iop_data,
+							pQbuffer, 4);
+							acb->wqbuf_firstindex
+							+= 4;
+							acb->wqbuf_firstindex
+							%= ARCMSR_MAX_QBUFFER;
+							iop_data += 4;
+						} else {
+							memcpy(iop_data, pQbuffer,
+							acb->wqbuf_lastindex
+							- acb->wqbuf_firstindex);
+							allxfer_len +=
+							acb->wqbuf_lastindex -
+							acb->wqbuf_firstindex;
+							acb->wqbuf_firstindex =
+							acb->wqbuf_lastindex;
+							break;
+						}
+					}
+					allxfer_len += 4;
+				} while ((acb->wqbuf_firstindex !=
+				acb->wqbuf_lastindex) && (allxfer_len < 124));
+			} else {
+				pQbuffer =
+				&acb->wqbuffer[acb->wqbuf_firstindex];
+				memcpy(iop_data, pQbuffer, ARCMSR_MAX_QBUFFER
+				- acb->wqbuf_firstindex);
+				iop_data += ARCMSR_MAX_QBUFFER
+				- acb->wqbuf_firstindex;
+				allxfer_len = ARCMSR_MAX_QBUFFER
+				- acb->wqbuf_firstindex;
+				acb->wqbuf_firstindex = 0;
+				do {
+					pQbuffer =
+					&acb->wqbuffer[acb->wqbuf_firstindex];
+					if ((acb->wqbuf_lastindex -
+					acb->wqbuf_firstindex) > 4) {
+						memcpy(iop_data, pQbuffer, 4);
+						acb->wqbuf_firstindex += 4;
+						acb->wqbuf_firstindex %=
+						ARCMSR_MAX_QBUFFER;
+						iop_data += 4;
+					} else {
+						memcpy(iop_data, pQbuffer,
+						acb->wqbuf_lastindex -
+						acb->wqbuf_firstindex);
+						allxfer_len +=
+						acb->wqbuf_lastindex
+						- acb->wqbuf_firstindex;
+						acb->wqbuf_firstindex =
+						acb->wqbuf_lastindex;
+						break;
+					}
+					allxfer_len += 4;
+				} while ((acb->wqbuf_firstindex !=
+				acb->wqbuf_lastindex) && (allxfer_len < 124));
+			}
+		} else {
+			do {
+				pQbuffer =
+				&acb->wqbuffer[acb->wqbuf_firstindex];
+				if ((acb->wqbuf_lastindex -
+				acb->wqbuf_firstindex) > 4) {
+					memcpy(iop_data, pQbuffer, 4);
+					acb->wqbuf_firstindex += 4;
+					acb->wqbuf_firstindex %=
+					ARCMSR_MAX_QBUFFER;
+					iop_data += 4;
+				} else {
+					memcpy(iop_data, pQbuffer,
+					acb->wqbuf_lastindex -
+					acb->wqbuf_firstindex);
+					allxfer_len += acb->wqbuf_lastindex
+					- acb->wqbuf_firstindex;
+					acb->wqbuf_firstindex =
+					acb->wqbuf_lastindex;
+					break;
+				}
+				allxfer_len += 4;
+			} while ((acb->wqbuf_firstindex !=
+			acb->wqbuf_lastindex) && (allxfer_len < 124));
 		}
-		pwbuffer->data_len = allxfer_len;
-
-		arcmsr_iop_message_wrote(acb);
+		writel(allxfer_len, &pwbuffer->data_len);
+		arcmsr_iop_message_wrote(acb);/*notice IOP the message has been written*/
 	}
-
 	if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) {
 		acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED;
 	}
+	spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
 }
 
-static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaA_doorbell_isr(struct AdapterControlBlock *acb)
 {
 	uint32_t outbound_doorbell;
-	struct MessageUnit_A __iomem *reg = acb->pmuA;
+	struct MessageUnit_A __iomem *reg  = acb->pmuA;
 	outbound_doorbell = readl(&reg->outbound_doorbell);
-	writel(outbound_doorbell, &reg->outbound_doorbell);
-	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
-		arcmsr_iop2drv_data_wrote_handle(acb);
-	}
-
-	if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
-		arcmsr_iop2drv_data_read_handle(acb);
-	}
+	do {
+		writel(outbound_doorbell, &reg->outbound_doorbell);
+		if (outbound_doorbell &
+			ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) {
+			arcmsr_iop2drv_data_wrote_handle(acb);
+		}
+		if (outbound_doorbell &
+			ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
+			arcmsr_iop2drv_data_read_handle(acb);
+		}
+		outbound_doorbell = readl(&reg->outbound_doorbell);
+	} while (outbound_doorbell &
+	(ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK
+	| ARCMSR_OUTBOUND_IOP331_DATA_READ_OK));
 }
-static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
+static void
+arcmsr_hbaC_doorbell_isr(struct AdapterControlBlock *pACB)
 {
 	uint32_t outbound_doorbell;
-	struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
-	/*
-	*******************************************************************
-	**  Maybe here we need to check wrqbuffer_lock is lock or not
-	**  DOORBELL: din! don!
-	**  check if there are any mail need to pack from firmware
-	*******************************************************************
-	*/
+	struct MessageUnit_C __iomem *reg =
+		(struct MessageUnit_C *)pACB->pmuC;
 	outbound_doorbell = readl(&reg->outbound_doorbell);
-	writel(outbound_doorbell, &reg->outbound_doorbell_clear);/*clear interrupt*/
-	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) {
-		arcmsr_iop2drv_data_wrote_handle(pACB);
-	}
-	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) {
-		arcmsr_iop2drv_data_read_handle(pACB);
-	}
-	if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
-		arcmsr_hbc_message_isr(pACB);    /* messenger of "driver to iop commands" */
-	}
+	do {
+		if (outbound_doorbell &
+			ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+			arcmsr_hbaC_message_isr(pACB);
+		}
+		writel(outbound_doorbell, &reg->outbound_doorbell_clear);
+		readl(&reg->outbound_doorbell_clear);
+		if (outbound_doorbell &
+			ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) {
+			arcmsr_iop2drv_data_wrote_handle(pACB);
+		}
+		if (outbound_doorbell &
+			ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) {
+			arcmsr_iop2drv_data_read_handle(pACB);
+		}
+		outbound_doorbell = readl(&reg->outbound_doorbell);
+	} while (outbound_doorbell & (ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK
+	| ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK
+	| ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE));
+	return;
+}
+
+static void
+arcmsr_hbaD_doorbell_isr(struct AdapterControlBlock *pACB)
+{
+	uint32_t outbound_doorbell;
+	struct MessageUnit_D __iomem *pmu =
+		(struct MessageUnit_D *)pACB->pmuD;
+
+	outbound_doorbell = readl(pmu->outbound_doorbell);
+	do {
+		writel(outbound_doorbell, pmu->outbound_doorbell);
+		if (outbound_doorbell &
+			ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) {
+			arcmsr_hbaD_message_isr(pACB);
+		}
+		if (outbound_doorbell &
+			ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK) {
+			arcmsr_iop2drv_data_wrote_handle(pACB);
+		}
+		if (outbound_doorbell &
+			ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK) {
+			arcmsr_iop2drv_data_read_handle(pACB);
+		}
+		outbound_doorbell = readl(pmu->outbound_doorbell);
+	} while (outbound_doorbell & (ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK
+	| ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK
+	| ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE));
 	return;
 }
-static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
+
+static void
+arcmsr_hbaA_postqueue_isr(struct AdapterControlBlock *acb)
 {
 	uint32_t flag_ccb;
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
@@ -1482,13 +2402,17 @@ static void arcmsr_hba_postqueue_isr(str
 	struct CommandControlBlock *pCCB;
 	bool error;
 	while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
-		pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/
-		pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
-		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+		pARCMSR_CDB = (struct ARCMSR_CDB *)
+			(acb->vir2phy_offset + (flag_ccb << 5));
+		pCCB = container_of(pARCMSR_CDB,
+			struct CommandControlBlock, arcmsr_cdb);
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0)
+			? true : false;
 		arcmsr_drain_donequeue(acb, pCCB, error);
 	}
 }
-static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaB_postqueue_isr(struct AdapterControlBlock *acb)
 {
 	uint32_t index;
 	uint32_t flag_ccb;
@@ -1499,9 +2423,13 @@ static void arcmsr_hbb_postqueue_isr(str
 	index = reg->doneq_index;
 	while ((flag_ccb = readl(&reg->done_qbuffer[index])) != 0) {
 		writel(0, &reg->done_qbuffer[index]);
-		pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/
-		pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb);
-		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+		pARCMSR_CDB = (struct ARCMSR_CDB *)
+		(acb->vir2phy_offset + (flag_ccb << 5));
+		pCCB = container_of(pARCMSR_CDB,
+		struct CommandControlBlock, arcmsr_cdb);
+		error = (flag_ccb &
+		ARCMSR_CCBREPLY_FLAG_ERROR_MODE0)
+		? true : false;
 		arcmsr_drain_donequeue(acb, pCCB, error);
 		index++;
 		index %= ARCMSR_MAX_HBB_POSTQUEUE;
@@ -1509,51 +2437,102 @@ static void arcmsr_hbb_postqueue_isr(str
 	}
 }
 
-static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaC_postqueue_isr(struct AdapterControlBlock *acb)
 {
-	struct MessageUnit_C *phbcmu;
-	struct ARCMSR_CDB *arcmsr_cdb;
-	struct CommandControlBlock *ccb;
 	uint32_t flag_ccb, ccb_cdb_phy, throttling = 0;
 	int error;
+	struct MessageUnit_C __iomem *phbcmu;
+	struct ARCMSR_CDB *arcmsr_cdb;
+	struct CommandControlBlock *ccb;
 
 	phbcmu = (struct MessageUnit_C *)acb->pmuC;
 	/* areca cdb command done */
 	/* Use correct offset and size for syncing */
+	do {
+		/* check if command done with no error*/
+		flag_ccb = readl(&phbcmu->outbound_queueport_low);
+		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
+		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
+			+ ccb_cdb_phy);
+		ccb = container_of(arcmsr_cdb, struct CommandControlBlock,
+			arcmsr_cdb);
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
+			? true : false;
+		/* check if command done with no error */
+		arcmsr_drain_donequeue(acb, ccb, error);
+		if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
+			writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING,
+				&phbcmu->inbound_doorbell);
+			continue;
+		}
+		throttling++;
+	} while (readl(&phbcmu->host_int_status) &
+	ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR);
+}
 
-	while (readl(&phbcmu->host_int_status) &
-	ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){
-	/* check if command done with no error*/
-	flag_ccb = readl(&phbcmu->outbound_queueport_low);
-	ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/
-	arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);
-	ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
-	error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
-	/* check if command done with no error */
-	arcmsr_drain_donequeue(acb, ccb, error);
-	if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) {
-		writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell);
-		break;
-	}
-	throttling++;
-	}
+static void
+arcmsr_hbaD_postqueue_isr(struct AdapterControlBlock *acb)
+{
+	u32 outbound_write_pointer, doneq_index, index_stripped;
+	uint32_t addressLow, ccb_cdb_phy;
+	int error;
+	struct MessageUnit_D __iomem *pmu;
+	struct ARCMSR_CDB *arcmsr_cdb;
+	struct CommandControlBlock *ccb;
+	unsigned long flags;
+
+	spin_lock_irqsave(&acb->doneq_lock, flags);
+	pmu = (struct MessageUnit_D *)acb->pmuD;
+	outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
+	doneq_index = pmu->doneq_index;
+	if ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
+		do {
+			if (doneq_index & 0x4000) {
+				index_stripped = doneq_index & 0xFFF;
+				index_stripped += 1;
+				index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+				pmu->doneq_index = index_stripped
+				? (index_stripped | 0x4000) : (index_stripped + 1);
+			} else {
+				index_stripped = doneq_index;
+				index_stripped += 1;
+				index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+				pmu->doneq_index = index_stripped
+				? index_stripped : ((index_stripped | 0x4000) + 1);
+			}
+			doneq_index = pmu->doneq_index;
+			addressLow =
+			pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
+			ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
+			arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
+				+ ccb_cdb_phy);
+			ccb = container_of(arcmsr_cdb,
+				struct CommandControlBlock, arcmsr_cdb);
+			error = (addressLow & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
+				? true : false;
+			arcmsr_drain_donequeue(acb, ccb, error);
+			writel(doneq_index,
+				pmu->outboundlist_read_pointer);
+		} while ((doneq_index & 0xFFF) !=
+		(outbound_write_pointer & 0xFFF));
+	}
+	writel(ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR,
+		pmu->outboundlist_interrupt_cause);
+	readl(pmu->outboundlist_interrupt_cause);
+	spin_unlock_irqrestore(&acb->doneq_lock, flags);
 }
-/*
-**********************************************************************************
-** Handle a message interrupt
-**
-** The only message interrupt we expect is in response to a query for the current adapter config.  
-** We want this in order to compare the drivemap so that we can detect newly-attached drives.
-**********************************************************************************
-*/
-static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb)
+
+static void
+arcmsr_hbaA_message_isr(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A *reg  = acb->pmuA;
 	/*clear interrupt and message state*/
 	writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, &reg->outbound_intstatus);
 	schedule_work(&acb->arcmsr_do_message_isr_bh);
 }
-static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaB_message_isr(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg  = acb->pmuB;
 
@@ -1561,126 +2540,161 @@ static void arcmsr_hbb_message_isr(struc
 	writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
 	schedule_work(&acb->arcmsr_do_message_isr_bh);
 }
-/*
-**********************************************************************************
-** Handle a message interrupt
-**
-** The only message interrupt we expect is in response to a query for the
-** current adapter config.
-** We want this in order to compare the drivemap so that we can detect newly-attached drives.
-**********************************************************************************
-*/
-static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb)
+
+static void
+arcmsr_hbaC_message_isr(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_C *reg  = acb->pmuC;
 	/*clear interrupt and message state*/
-	writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &reg->outbound_doorbell_clear);
+	writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR,
+	&reg->outbound_doorbell_clear);
+	schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
+
+static void
+arcmsr_hbaD_message_isr(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_D __iomem *reg  = acb->pmuD;
+	writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE,
+		reg->outbound_doorbell);
+	readl(reg->outbound_doorbell);
 	schedule_work(&acb->arcmsr_do_message_isr_bh);
 }
 
-static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
+static irqreturn_t
+arcmsr_hbaA_handle_isr(struct AdapterControlBlock *acb)
 {
 	uint32_t outbound_intstatus;
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
-	outbound_intstatus = readl(&reg->outbound_intstatus) &
-		acb->outbound_int_enable;
-	if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))	{
-		return 1;
-	}
-	writel(outbound_intstatus, &reg->outbound_intstatus);
-	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)	{
-		arcmsr_hba_doorbell_isr(acb);
+	outbound_intstatus =
+	readl(&reg->outbound_intstatus) & acb->outbound_int_enable;
+	if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) {
+		return IRQ_NONE;
 	}
-	if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
-		arcmsr_hba_postqueue_isr(acb);
-	}
-	if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) 	{
-		/* messenger of "driver to iop commands" */
-		arcmsr_hba_message_isr(acb);
-	}
-	return 0;
+	do {
+		writel(outbound_intstatus, &reg->outbound_intstatus);
+		if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT)
+			arcmsr_hbaA_doorbell_isr(acb);
+		if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT)
+			arcmsr_hbaA_postqueue_isr(acb);
+		if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT)
+			arcmsr_hbaA_message_isr(acb);
+		outbound_intstatus = readl(&reg->outbound_intstatus) &
+			acb->outbound_int_enable;
+	} while (outbound_intstatus & (ARCMSR_MU_OUTBOUND_DOORBELL_INT
+	| ARCMSR_MU_OUTBOUND_POSTQUEUE_INT
+	| ARCMSR_MU_OUTBOUND_MESSAGE0_INT));
+	return IRQ_HANDLED;
 }
 
-static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
+static irqreturn_t
+arcmsr_hbaB_handle_isr(struct AdapterControlBlock *acb)
 {
 	uint32_t outbound_doorbell;
 	struct MessageUnit_B *reg = acb->pmuB;
-	outbound_doorbell = readl(reg->iop2drv_doorbell) &
-				acb->outbound_int_enable;
+	outbound_doorbell = readl(reg->iop2drv_doorbell)
+		& acb->outbound_int_enable;
 	if (!outbound_doorbell)
-		return 1;
-
-	writel(~outbound_doorbell, reg->iop2drv_doorbell);
-	/*in case the last action of doorbell interrupt clearance is cached,
-	this action can push HW to write down the clear bit*/
-	readl(reg->iop2drv_doorbell);
-	writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
-	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
-		arcmsr_iop2drv_data_wrote_handle(acb);
-	}
-	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
-		arcmsr_iop2drv_data_read_handle(acb);
-	}
-	if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
-		arcmsr_hbb_postqueue_isr(acb);
-	}
-	if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
-		/* messenger of "driver to iop commands" */
-		arcmsr_hbb_message_isr(acb);
-	}
-	return 0;
+		return IRQ_NONE;
+	do {
+		writel(~outbound_doorbell, reg->iop2drv_doorbell);
+		readl(reg->iop2drv_doorbell);
+		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT,
+			reg->drv2iop_doorbell);
+		readl(reg->drv2iop_doorbell);
+		if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK)
+			arcmsr_iop2drv_data_wrote_handle(acb);
+		if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK)
+			arcmsr_iop2drv_data_read_handle(acb);
+		if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE)
+			arcmsr_hbaB_postqueue_isr(acb);
+		if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE)
+			arcmsr_hbaB_message_isr(acb);
+		outbound_doorbell = readl(reg->iop2drv_doorbell) &
+			acb->outbound_int_enable;
+	} while (outbound_doorbell & (ARCMSR_IOP2DRV_DATA_WRITE_OK
+	| ARCMSR_IOP2DRV_DATA_READ_OK
+	| ARCMSR_IOP2DRV_CDB_DONE
+	| ARCMSR_IOP2DRV_MESSAGE_CMD_DONE));
+	return IRQ_HANDLED;
 }
 
-static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB)
+static irqreturn_t
+arcmsr_hbaC_handle_isr(struct AdapterControlBlock *pACB)
 {
 	uint32_t host_interrupt_status;
-	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
-	/*
-	*********************************************
-	**   check outbound intstatus
-	*********************************************
-	*/
-	host_interrupt_status = readl(&phbcmu->host_int_status);
-	if (!host_interrupt_status) {
-		/*it must be share irq*/
-		return 1;
-	}
-	/* MU ioctl transfer doorbell interrupts*/
-	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) {
-		arcmsr_hbc_doorbell_isr(pACB);   /* messenger of "ioctl message read write" */
-	}
-	/* MU post queue interrupts*/
-	if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) {
-		arcmsr_hbc_postqueue_isr(pACB);  /* messenger of "scsi commands" */
-	}
-	return 0;
+	struct MessageUnit_C __iomem *phbcmu =
+		(struct MessageUnit_C *)pACB->pmuC;
+	host_interrupt_status =
+		readl(&phbcmu->host_int_status);
+	do {
+		if (host_interrupt_status &
+			ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) {
+			arcmsr_hbaC_doorbell_isr(pACB);
+		}
+		/* MU post queue interrupts*/
+		if (host_interrupt_status &
+			ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) {
+			arcmsr_hbaC_postqueue_isr(pACB);
+		}
+		host_interrupt_status = readl(&phbcmu->host_int_status);
+	} while (host_interrupt_status &
+	(ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR |
+	ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR));
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t
+arcmsr_hbaD_handle_isr(struct AdapterControlBlock *pACB)
+{
+	u32 host_interrupt_status;
+	struct MessageUnit_D __iomem *pmu =
+		(struct MessageUnit_D *)pACB->pmuD;
+	host_interrupt_status = readl(pmu->host_int_status);
+	do {
+		/* MU post queue interrupts*/
+		if (host_interrupt_status &
+			ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR) {
+			arcmsr_hbaD_postqueue_isr(pACB);
+		}
+		if (host_interrupt_status &
+			ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR) {
+			arcmsr_hbaD_doorbell_isr(pACB);
+		}
+		host_interrupt_status = readl(pmu->host_int_status);
+	} while (host_interrupt_status &
+	(ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR |
+	ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR));
+	return IRQ_HANDLED;
 }
-static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
+
+static irqreturn_t
+arcmsr_interrupt(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A: {
-		if (arcmsr_handle_hba_isr(acb)) {
-			return IRQ_NONE;
-		}
-		}
+		return arcmsr_hbaA_handle_isr(acb);
 		break;
-
+	}
 	case ACB_ADAPTER_TYPE_B: {
-		if (arcmsr_handle_hbb_isr(acb)) {
-			return IRQ_NONE;
-		}
-		}
+		return arcmsr_hbaB_handle_isr(acb);
 		break;
-	 case ACB_ADAPTER_TYPE_C: {
-		if (arcmsr_handle_hbc_isr(acb)) {
-			return IRQ_NONE;
-		}
-		}
 	}
-	return IRQ_HANDLED;
+	case ACB_ADAPTER_TYPE_C: {
+		return arcmsr_hbaC_handle_isr(acb);
+		break;
+	}
+	case ACB_ADAPTER_TYPE_D: {
+		return arcmsr_hbaD_handle_isr(acb);
+		break;
+	}
+	default:
+		return IRQ_NONE;
+	}
 }
 
-static void arcmsr_iop_parking(struct AdapterControlBlock *acb)
+static void
+arcmsr_iop_parking(struct AdapterControlBlock *acb)
 {
 	if (acb) {
 		/* stop adapter background rebuild */
@@ -1695,180 +2709,388 @@ static void arcmsr_iop_parking(struct Ad
 	}
 }
 
-void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
+void
+arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
 {
-	int32_t wqbuf_firstindex, wqbuf_lastindex;
-	uint8_t *pQbuffer;
-	struct QBUFFER __iomem *pwbuffer;
-	uint8_t __iomem *iop_data;
-	int32_t allxfer_len = 0;
-	pwbuffer = arcmsr_get_iop_wqbuffer(acb);
-	iop_data = (uint8_t __iomem *)pwbuffer->data;
 	if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) {
-		acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
-		wqbuf_firstindex = acb->wqbuf_firstindex;
-		wqbuf_lastindex = acb->wqbuf_lastindex;
-		while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) {
-			pQbuffer = &acb->wqbuffer[wqbuf_firstindex];
-			memcpy(iop_data, pQbuffer, 1);
-			wqbuf_firstindex++;
-			wqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
-			iop_data++;
-			allxfer_len++;
-		}
-		acb->wqbuf_firstindex = wqbuf_firstindex;
-		pwbuffer->data_len = allxfer_len;
-		arcmsr_iop_message_wrote(acb);
+		if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) {
+			uint8_t *pQbuffer;
+			uint8_t __iomem *iop_data;
+			int32_t allxfer_len = 0;
+			struct QBUFFER __iomem *pwbuffer;
+			acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED);
+			pwbuffer = arcmsr_get_iop_wqbuffer(acb);
+			iop_data = (uint8_t __iomem *)pwbuffer->data;
+			if (acb->wqbuf_firstindex > acb->wqbuf_lastindex) {
+				if ((ARCMSR_MAX_QBUFFER -
+					acb->wqbuf_firstindex) >= 4) {
+					do {
+						pQbuffer =
+						&acb->wqbuffer[acb->wqbuf_firstindex];
+						if (acb->wqbuf_firstindex + 4 >
+						ARCMSR_MAX_QBUFFER) {
+							memcpy(iop_data, pQbuffer,
+							ARCMSR_MAX_QBUFFER - acb->wqbuf_firstindex);
+							iop_data += ARCMSR_MAX_QBUFFER
+							- acb->wqbuf_firstindex;
+							acb->wqbuf_firstindex += 4;
+							acb->wqbuf_firstindex %=
+							ARCMSR_MAX_QBUFFER;
+							memcpy(iop_data,
+							&acb->wqbuffer[0],
+							acb->wqbuf_firstindex);
+							iop_data +=
+							acb->wqbuf_firstindex;
+						} else {
+							if ((acb->wqbuf_lastindex -
+							acb->wqbuf_firstindex) > 4) {
+								memcpy(iop_data,
+								pQbuffer, 4);
+								acb->wqbuf_firstindex
+								+= 4;
+								acb->wqbuf_firstindex
+								%= ARCMSR_MAX_QBUFFER;
+								iop_data += 4;
+							} else {
+								memcpy(iop_data,
+								pQbuffer,
+								acb->wqbuf_lastindex
+								- acb->wqbuf_firstindex);
+								allxfer_len +=
+								acb->wqbuf_lastindex
+								- acb->wqbuf_firstindex;
+								acb->wqbuf_firstindex
+								= acb->wqbuf_lastindex;
+								break;
+							}
+						}
+						allxfer_len += 4;
+					} while ((acb->wqbuf_firstindex !=
+					acb->wqbuf_lastindex) &&
+					(allxfer_len < 124));
+				} else {
+					pQbuffer =
+					&acb->wqbuffer[acb->wqbuf_firstindex];
+					memcpy(iop_data, pQbuffer,
+					ARCMSR_MAX_QBUFFER -
+					acb->wqbuf_firstindex);
+					iop_data += ARCMSR_MAX_QBUFFER
+					- acb->wqbuf_firstindex;
+					allxfer_len = ARCMSR_MAX_QBUFFER
+					- acb->wqbuf_firstindex;
+					acb->wqbuf_firstindex = 0;
+					do {
+						pQbuffer =
+						&acb->wqbuffer[acb->wqbuf_firstindex];
+						if ((acb->wqbuf_lastindex -
+						acb->wqbuf_firstindex) > 4) {
+							memcpy(iop_data,
+							pQbuffer, 4);
+							acb->wqbuf_firstindex
+							+= 4;
+							acb->wqbuf_firstindex
+							%= ARCMSR_MAX_QBUFFER;
+							iop_data += 4;
+						} else {
+							memcpy(iop_data, pQbuffer,
+							acb->wqbuf_lastindex
+							- acb->wqbuf_firstindex);
+							allxfer_len +=
+							acb->wqbuf_lastindex
+							- acb->wqbuf_firstindex;
+							acb->wqbuf_firstindex =
+							acb->wqbuf_lastindex;
+							break;
+						}
+						allxfer_len += 4;
+					} while ((acb->wqbuf_firstindex
+					!= acb->wqbuf_lastindex) &&
+					(allxfer_len < 124));
+				}
+			} else {
+				do {
+					pQbuffer =
+					&acb->wqbuffer[acb->wqbuf_firstindex];
+					if ((acb->wqbuf_lastindex -
+					acb->wqbuf_firstindex) > 4) {
+						memcpy(iop_data,
+						pQbuffer, 4);
+						acb->wqbuf_firstindex
+						+= 4;
+						acb->wqbuf_firstindex
+						%= ARCMSR_MAX_QBUFFER;
+						iop_data += 4;
+					} else {
+						memcpy(iop_data, pQbuffer,
+						acb->wqbuf_lastindex -
+						acb->wqbuf_firstindex);
+						allxfer_len += acb->wqbuf_lastindex
+						- acb->wqbuf_firstindex;
+						acb->wqbuf_firstindex =
+						acb->wqbuf_lastindex;
+						break;
+					}
+					allxfer_len += 4;
+				} while ((acb->wqbuf_firstindex !=
+				acb->wqbuf_lastindex) && (allxfer_len < 124));
+			}
+			writel(allxfer_len, &pwbuffer->data_len);
+			arcmsr_iop_message_wrote(acb);
+		}
 	}
 }
 
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
+static int
+arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
 					struct scsi_cmnd *cmd)
 {
-	struct CMD_MESSAGE_FIELD *pcmdmessagefld;
-	int retvalue = 0, transfer_len = 0;
 	char *buffer;
+	unsigned short use_sg;
+	int retvalue = 0, transfer_len = 0;
+	unsigned long flags;
+	struct CMD_MESSAGE_FIELD *pcmdmessagefld;
+	uint32_t	controlcode = (uint32_t)cmd->cmnd[5] << 24 |
+		(uint32_t)cmd->cmnd[6] << 16 |
+		(uint32_t)cmd->cmnd[7] << 8 |
+		(uint32_t)cmd->cmnd[8];
 	struct scatterlist *sg;
-	uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 |
-						(uint32_t ) cmd->cmnd[6] << 16 |
-						(uint32_t ) cmd->cmnd[7] << 8  |
-						(uint32_t ) cmd->cmnd[8];
-						/* 4 bytes: Areca io control code */
+
+	use_sg = scsi_sg_count(cmd);
 	sg = scsi_sglist(cmd);
 	buffer = kmap_atomic(sg_page(sg)) + sg->offset;
-	if (scsi_sg_count(cmd) > 1) {
+	if (use_sg > 1) {
 		retvalue = ARCMSR_MESSAGE_FAIL;
 		goto message_out;
 	}
 	transfer_len += sg->length;
-
 	if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) {
 		retvalue = ARCMSR_MESSAGE_FAIL;
+		printk("%s: ARCMSR_MESSAGE_FAIL!\n", __func__);
 		goto message_out;
 	}
-	pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer;
-	switch(controlcode) {
-
+	pcmdmessagefld = (struct CMD_MESSAGE_FIELD *)buffer;
+	switch (controlcode) {
 	case ARCMSR_MESSAGE_READ_RQBUFFER: {
 		unsigned char *ver_addr;
 		uint8_t *pQbuffer, *ptmpQbuffer;
-		int32_t allxfer_len = 0;
-
+		uint32_t allxfer_len = 0;
 		ver_addr = kmalloc(1032, GFP_ATOMIC);
 		if (!ver_addr) {
 			retvalue = ARCMSR_MESSAGE_FAIL;
+			printk("%s: memory not enough!\n", __func__);
 			goto message_out;
 		}
-				
 		ptmpQbuffer = ver_addr;
-		while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
-			&& (allxfer_len < 1031)) {
+		spin_lock_irqsave(&acb->rqbuffer_lock, flags);
+		if (acb->rqbuf_firstindex != acb->rqbuf_lastindex) {
 			pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex];
-			memcpy(ptmpQbuffer, pQbuffer, 1);
-			acb->rqbuf_firstindex++;
-			acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER;
-			ptmpQbuffer++;
-			allxfer_len++;
+			if (acb->rqbuf_firstindex > acb->rqbuf_lastindex) {
+				if ((ARCMSR_MAX_QBUFFER -
+					acb->rqbuf_firstindex) >= 1032) {
+					memcpy(ptmpQbuffer, pQbuffer, 1032);
+					acb->rqbuf_firstindex += 1032;
+					allxfer_len = 1032;
+				} else {
+					if (((ARCMSR_MAX_QBUFFER -
+						acb->rqbuf_firstindex) +
+						acb->rqbuf_lastindex) > 1032) {
+						memcpy(ptmpQbuffer,
+						pQbuffer, ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex);
+						ptmpQbuffer +=
+						ARCMSR_MAX_QBUFFER -
+						acb->rqbuf_firstindex;
+						memcpy(ptmpQbuffer,
+						acb->rqbuffer, 1032 -
+						(ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex));
+						acb->rqbuf_firstindex =
+						1032 - (ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex);
+						allxfer_len = 1032;
+					} else {
+						memcpy(ptmpQbuffer,
+						pQbuffer, ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex);
+						ptmpQbuffer +=
+						ARCMSR_MAX_QBUFFER -
+						acb->rqbuf_firstindex;
+						memcpy(ptmpQbuffer,
+						acb->rqbuffer,
+						acb->rqbuf_lastindex);
+						allxfer_len = ARCMSR_MAX_QBUFFER
+						- acb->rqbuf_firstindex +
+						acb->rqbuf_lastindex;
+						acb->rqbuf_firstindex =
+						acb->rqbuf_lastindex;
+					}
+				}
+			} else {
+				if ((acb->rqbuf_lastindex -
+				acb->rqbuf_firstindex) > 1032) {
+					memcpy(ptmpQbuffer, pQbuffer, 1032);
+					acb->rqbuf_firstindex += 1032;
+					allxfer_len = 1032;
+				} else {
+					memcpy(ptmpQbuffer, pQbuffer,
+					acb->rqbuf_lastindex - acb->rqbuf_firstindex);
+					allxfer_len = acb->rqbuf_lastindex
+					- acb->rqbuf_firstindex;
+					acb->rqbuf_firstindex =
+					acb->rqbuf_lastindex;
+				}
+			}
 		}
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
-
 			struct QBUFFER __iomem *prbuffer;
-			uint8_t __iomem *iop_data;
-			int32_t iop_len;
-
-			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+			uint8_t __iomem *iop_data, *vaddr, *temp;
+			uint32_t data_len_residual, data_len, rqbuf_lastindex;
+			rqbuf_lastindex = acb->rqbuf_lastindex;
 			prbuffer = arcmsr_get_iop_rqbuffer(acb);
-			iop_data = prbuffer->data;
-			iop_len = readl(&prbuffer->data_len);
-			while (iop_len > 0) {
-				acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
-				acb->rqbuf_lastindex++;
-				acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-				iop_data++;
-				iop_len--;
+			iop_data = (uint8_t __iomem *)prbuffer->data;
+			data_len_residual = data_len = readl(&prbuffer->data_len);
+			if (data_len > 0) {
+				temp = vaddr = kmalloc(data_len, GFP_ATOMIC);
+				if (!vaddr) {
+					goto leave;
+				}
+				acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+				while (data_len_residual >= 4) {
+					memcpy(temp, iop_data, 4);
+					temp += 4;
+					iop_data += 4;
+					data_len_residual -= 4;
+				}
+				if ((data_len_residual > 0) &&
+				(data_len_residual < 4)) {
+					memcpy(temp, iop_data,
+					data_len_residual);
+				}
+				pQbuffer =
+				&acb->rqbuffer[acb->rqbuf_lastindex];
+				temp = vaddr;
+				if ((rqbuf_lastindex + data_len) >
+				ARCMSR_MAX_QBUFFER) {
+					memcpy(pQbuffer, temp,
+					ARCMSR_MAX_QBUFFER - rqbuf_lastindex);
+					temp += (ARCMSR_MAX_QBUFFER -
+					rqbuf_lastindex);
+					rqbuf_lastindex = (rqbuf_lastindex +
+					data_len) % ARCMSR_MAX_QBUFFER;
+					memcpy(&acb->rqbuffer[0],
+					temp, rqbuf_lastindex);
+				} else {
+					memcpy(pQbuffer, temp, data_len);
+					rqbuf_lastindex =
+					(rqbuf_lastindex + data_len) %
+					ARCMSR_MAX_QBUFFER;
+				}
+				kfree(vaddr);
+				acb->rqbuf_lastindex = rqbuf_lastindex;
+				arcmsr_iop_message_read(acb);
 			}
-			arcmsr_iop_message_read(acb);
 		}
+		leave:
+		spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
 		memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len);
 		pcmdmessagefld->cmdmessage.Length = allxfer_len;
-		if(acb->fw_flag == FW_DEADLOCK) {
-			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-		}else{
-			pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+		if (acb->fw_flag == FW_DEADLOCK) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+		} else {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
 		kfree(ver_addr);
-		}
 		break;
-
+	}
 	case ARCMSR_MESSAGE_WRITE_WQBUFFER: {
 		unsigned char *ver_addr;
-		int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex;
+		int32_t my_empty_len, user_len, wqbuf_firstindex,
+		wqbuf_lastindex;
 		uint8_t *pQbuffer, *ptmpuserbuffer;
-
 		ver_addr = kmalloc(1032, GFP_ATOMIC);
 		if (!ver_addr) {
 			retvalue = ARCMSR_MESSAGE_FAIL;
 			goto message_out;
 		}
-		if(acb->fw_flag == FW_DEADLOCK) {
-			pcmdmessagefld->cmdmessage.ReturnCode = 
+		if (acb->fw_flag == FW_DEADLOCK) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-		}else{
-			pcmdmessagefld->cmdmessage.ReturnCode = 
+		} else {
+			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
 		ptmpuserbuffer = ver_addr;
 		user_len = pcmdmessagefld->cmdmessage.Length;
-		memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
+		memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer,
+		user_len);
+		spin_lock_irqsave(&acb->wqbuffer_lock, flags);
 		wqbuf_lastindex = acb->wqbuf_lastindex;
 		wqbuf_firstindex = acb->wqbuf_firstindex;
 		if (wqbuf_lastindex != wqbuf_firstindex) {
 			struct SENSE_DATA *sensebuffer =
-				(struct SENSE_DATA *)cmd->sense_buffer;
+			(struct SENSE_DATA *)cmd->sense_buffer;
 			arcmsr_post_ioctldata2iop(acb);
 			/* has error report sensedata */
-			sensebuffer->ErrorCode = 0x70;
+			sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS;
 			sensebuffer->SenseKey = ILLEGAL_REQUEST;
 			sensebuffer->AdditionalSenseLength = 0x0A;
 			sensebuffer->AdditionalSenseCode = 0x20;
 			sensebuffer->Valid = 1;
 			retvalue = ARCMSR_MESSAGE_FAIL;
 		} else {
-			my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
-				&(ARCMSR_MAX_QBUFFER - 1);
+			my_empty_len = (wqbuf_firstindex - wqbuf_lastindex - 1)
+			& (ARCMSR_MAX_QBUFFER - 1);
 			if (my_empty_len >= user_len) {
 				while (user_len > 0) {
-					pQbuffer =
-					&acb->wqbuffer[acb->wqbuf_lastindex];
-					memcpy(pQbuffer, ptmpuserbuffer, 1);
-					acb->wqbuf_lastindex++;
-					acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
-					ptmpuserbuffer++;
-					user_len--;
+					pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex];
+					if ((acb->wqbuf_lastindex + user_len)
+						> ARCMSR_MAX_QBUFFER) {
+						memcpy(pQbuffer, ptmpuserbuffer,
+						ARCMSR_MAX_QBUFFER -
+						acb->wqbuf_lastindex);
+						ptmpuserbuffer += (ARCMSR_MAX_QBUFFER
+						- acb->wqbuf_lastindex);
+						user_len -= (ARCMSR_MAX_QBUFFER
+						- acb->wqbuf_lastindex);
+						acb->wqbuf_lastindex = 0;
+					} else {
+						memcpy(pQbuffer, ptmpuserbuffer,
+						user_len);
+						acb->wqbuf_lastindex += user_len;
+						acb->wqbuf_lastindex %=
+						ARCMSR_MAX_QBUFFER;
+						user_len = 0;
+					}
 				}
-				if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
+				if (acb->acb_flags &
+				ACB_F_MESSAGE_WQBUFFER_CLEARED) {
 					acb->acb_flags &=
-						~ACB_F_MESSAGE_WQBUFFER_CLEARED;
+					~ACB_F_MESSAGE_WQBUFFER_CLEARED;
 					arcmsr_post_ioctldata2iop(acb);
 				}
 			} else {
-				/* has error report sensedata */
 				struct SENSE_DATA *sensebuffer =
-					(struct SENSE_DATA *)cmd->sense_buffer;
-				sensebuffer->ErrorCode = 0x70;
+				(struct SENSE_DATA *)cmd->sense_buffer;
+				/* has error report sensedata */
+				sensebuffer->ErrorCode =
+				SCSI_SENSE_CURRENT_ERRORS;
 				sensebuffer->SenseKey = ILLEGAL_REQUEST;
 				sensebuffer->AdditionalSenseLength = 0x0A;
 				sensebuffer->AdditionalSenseCode = 0x20;
 				sensebuffer->Valid = 1;
 				retvalue = ARCMSR_MESSAGE_FAIL;
 			}
-			}
-			kfree(ver_addr);
 		}
+		spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
+		kfree(ver_addr);
 		break;
-
+	}
 	case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
 		uint8_t *pQbuffer = acb->rqbuffer;
+
+		spin_lock_irqsave(&acb->rqbuffer_lock, flags);
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
 			arcmsr_iop_message_read(acb);
@@ -1877,127 +3099,138 @@ static int arcmsr_iop_message_xfer(struc
 		acb->rqbuf_firstindex = 0;
 		acb->rqbuf_lastindex = 0;
 		memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
-		if(acb->fw_flag == FW_DEADLOCK) {
+		spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
+		if (acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-		}else{
+		} else {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
-		}
 		break;
-
+	}
 	case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
 		uint8_t *pQbuffer = acb->wqbuffer;
-		if(acb->fw_flag == FW_DEADLOCK) {
+		if (acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-		}else{
+		} else {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
-
+		spin_lock_irqsave(&acb->wqbuffer_lock, flags);
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
 			arcmsr_iop_message_read(acb);
 		}
-		acb->acb_flags |=
-			(ACB_F_MESSAGE_WQBUFFER_CLEARED |
-				ACB_F_MESSAGE_WQBUFFER_READED);
+		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+		ACB_F_MESSAGE_WQBUFFER_READED);
 		acb->wqbuf_firstindex = 0;
 		acb->wqbuf_lastindex = 0;
 		memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
-		}
+		spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
 		break;
-
+	}
 	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
 		uint8_t *pQbuffer;
-
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
 			arcmsr_iop_message_read(acb);
 		}
-		acb->acb_flags |=
-			(ACB_F_MESSAGE_WQBUFFER_CLEARED
-			| ACB_F_MESSAGE_RQBUFFER_CLEARED
-			| ACB_F_MESSAGE_WQBUFFER_READED);
+		spin_lock_irqsave(&acb->rqbuffer_lock, flags);
+		acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED;
 		acb->rqbuf_firstindex = 0;
 		acb->rqbuf_lastindex = 0;
-		acb->wqbuf_firstindex = 0;
-		acb->wqbuf_lastindex = 0;
 		pQbuffer = acb->rqbuffer;
 		memset(pQbuffer, 0, sizeof(struct QBUFFER));
+		spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
+		spin_lock_irqsave(&acb->wqbuffer_lock, flags);
+		acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
+		ACB_F_MESSAGE_WQBUFFER_READED);
+		acb->wqbuf_firstindex = 0;
+		acb->wqbuf_lastindex = 0;
 		pQbuffer = acb->wqbuffer;
 		memset(pQbuffer, 0, sizeof(struct QBUFFER));
-		if(acb->fw_flag == FW_DEADLOCK) {
+		spin_unlock_irqrestore(&acb->wqbuffer_lock, flags);
+		if (acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-		}else{
+		} else {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
-		}
 		break;
-
+	}
 	case ARCMSR_MESSAGE_RETURN_CODE_3F: {
-		if(acb->fw_flag == FW_DEADLOCK) {
+		if (acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-		}else{
+		} else {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_3F;
 		}
 		break;
-		}
+	}
 	case ARCMSR_MESSAGE_SAY_HELLO: {
 		int8_t *hello_string = "Hello! I am ARCMSR";
-		if(acb->fw_flag == FW_DEADLOCK) {
+		if (acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-		}else{
+		} else {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
-		memcpy(pcmdmessagefld->messagedatabuffer, hello_string
-			, (int16_t)strlen(hello_string));
-		}
+		memcpy(pcmdmessagefld->messagedatabuffer,
+		hello_string, (int16_t)strlen(hello_string));
 		break;
-
-	case ARCMSR_MESSAGE_SAY_GOODBYE:
-		if(acb->fw_flag == FW_DEADLOCK) {
+	}
+	case ARCMSR_MESSAGE_SAY_GOODBYE: {
+		if (acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+		} else {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
 		arcmsr_iop_parking(acb);
 		break;
-
-	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
-		if(acb->fw_flag == FW_DEADLOCK) {
+	}
+	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: {
+		if (acb->fw_flag == FW_DEADLOCK) {
 			pcmdmessagefld->cmdmessage.ReturnCode =
 			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+		} else {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_OK;
 		}
 		arcmsr_flush_adapter_cache(acb);
 		break;
-
+	}
 	default:
 		retvalue = ARCMSR_MESSAGE_FAIL;
+		printk("unknown controlcode(%d)\n", __LINE__);
 	}
 	message_out:
-	sg = scsi_sglist(cmd);
-	kunmap_atomic(buffer - sg->offset);
+	if (use_sg) {
+		struct scatterlist *sg;
+		sg = scsi_sglist(cmd);
+		kunmap_atomic(buffer - sg->offset);
+	}
 	return retvalue;
 }
 
-static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb)
+struct CommandControlBlock
+*arcmsr_get_freeccb(struct AdapterControlBlock *acb)
 {
 	struct list_head *head = &acb->ccb_free_list;
 	struct CommandControlBlock *ccb = NULL;
 	unsigned long flags;
 	spin_lock_irqsave(&acb->ccblist_lock, flags);
 	if (!list_empty(head)) {
-		ccb = list_entry(head->next, struct CommandControlBlock, list);
+		ccb = list_entry(head->next,
+			struct CommandControlBlock, list);
 		list_del_init(&ccb->list);
-	}else{
+	} else {
 		spin_unlock_irqrestore(&acb->ccblist_lock, flags);
 		return 0;
 	}
@@ -2005,7 +3238,8 @@ static struct CommandControlBlock *arcms
 	return ccb;
 }
 
-static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
+void
+arcmsr_handle_virtual_command(struct AdapterControlBlock *acb,
 		struct scsi_cmnd *cmd)
 {
 	switch (cmd->cmnd[0]) {
@@ -2013,7 +3247,6 @@ static void arcmsr_handle_virtual_comman
 		unsigned char inqdata[36];
 		char *buffer;
 		struct scatterlist *sg;
-
 		if (cmd->device->lun) {
 			cmd->result = (DID_TIME_OUT << 16);
 			cmd->scsi_done(cmd);
@@ -2032,14 +3265,11 @@ static void arcmsr_handle_virtual_comman
 		strncpy(&inqdata[16], "RAID controller ", 16);
 		/* Product Identification */
 		strncpy(&inqdata[32], "R001", 4); /* Product Revision */
-
 		sg = scsi_sglist(cmd);
 		buffer = kmap_atomic(sg_page(sg)) + sg->offset;
-
 		memcpy(buffer, inqdata, sizeof(inqdata));
 		sg = scsi_sglist(cmd);
 		kunmap_atomic(buffer - sg->offset);
-
 		cmd->scsi_done(cmd);
 	}
 	break;
@@ -2055,11 +3285,13 @@ static void arcmsr_handle_virtual_comman
 	}
 }
 
-static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
+static int
+arcmsr_queue_command_lck(struct scsi_cmnd *cmd,
 	void (* done)(struct scsi_cmnd *))
 {
 	struct Scsi_Host *host = cmd->device->host;
-	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
+	struct AdapterControlBlock *acb =
+	(struct AdapterControlBlock *)host->hostdata;
 	struct CommandControlBlock *ccb;
 	int target = cmd->device->id;
 	int lun = cmd->device->lun;
@@ -2067,8 +3299,10 @@ static int arcmsr_queue_command_lck(stru
 	cmd->scsi_done = done;
 	cmd->host_scribble = NULL;
 	cmd->result = 0;
-	if ((scsicmd == SYNCHRONIZE_CACHE) ||(scsicmd == SEND_DIAGNOSTIC)){
-		if(acb->devstate[target][lun] == ARECA_RAID_GONE) {
+	if ((scsicmd == SYNCHRONIZE_CACHE) ||
+		(scsicmd == SEND_DIAGNOSTIC)) {
+		if (acb->devstate[target][lun] ==
+			ARECA_RAID_GONE) {
     			cmd->result = (DID_NO_CONNECT << 16);
 		}
 		cmd->scsi_done(cmd);
@@ -2080,13 +3314,14 @@ static int arcmsr_queue_command_lck(stru
 		return 0;
 	}
 	if (atomic_read(&acb->ccboutstandingcount) >=
-			ARCMSR_MAX_OUTSTANDING_CMD)
+	acb->maxOutstanding)
 		return SCSI_MLQUEUE_HOST_BUSY;
 	ccb = arcmsr_get_freeccb(acb);
 	if (!ccb)
 		return SCSI_MLQUEUE_HOST_BUSY;
 	if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) {
-		cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1);
+		cmd->result = (DID_ERROR << 16) |
+			(RESERVATION_CONFLICT << 1);
 		cmd->scsi_done(cmd);
 		return 0;
 	}
@@ -2096,24 +3331,30 @@ static int arcmsr_queue_command_lck(stru
 
 static DEF_SCSI_QCMD(arcmsr_queue_command)
 
-static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
+static bool
+arcmsr_hbaA_get_config(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	char *acb_firm_model = acb->firm_model;
 	char *acb_firm_version = acb->firm_version;
 	char *acb_device_map = acb->device_map;
-	char __iomem *iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);
-	char __iomem *iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);
-	char __iomem *iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]);
+	char __iomem *iop_firm_model =
+		(char __iomem *)(&reg->message_rwbuffer[15]);
+	char __iomem *iop_firm_version =
+		(char __iomem *)(&reg->message_rwbuffer[17]);
+	char __iomem *iop_device_map =
+		(char __iomem *)(&reg->message_rwbuffer[21]);
 	int count;
-	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
-	if (!arcmsr_hba_wait_msgint_ready(acb)) {
-		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
-			miscellaneous data' timeout \n", acb->host->host_no);
+	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG,
+		&reg->inbound_msgaddr0);
+	if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
+		pr_notice("arcmsr%d: wait 'get adapter firmware "
+		"miscellaneous data' timeout\n",
+		acb->host->host_no);
 		return false;
 	}
 	count = 8;
-	while (count){
+	while (count) {
 		*acb_firm_model = readb(iop_firm_model);
 		acb_firm_model++;
 		iop_firm_model++;
@@ -2121,7 +3362,7 @@ static bool arcmsr_get_hba_config(struct
 	}
 
 	count = 16;
-	while (count){
+	while (count) {
 		*acb_firm_version = readb(iop_firm_version);
 		acb_firm_version++;
 		iop_firm_version++;
@@ -2129,13 +3370,14 @@ static bool arcmsr_get_hba_config(struct
 	}
 
 	count=16;
-	while(count){
+	while (count) {
 		*acb_device_map = readb(iop_device_map);
 		acb_device_map++;
 		iop_device_map++;
 		count--;
 	}
-	printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", 
+	pr_notice("Areca RAID Controller%d: F/W %s "
+		"& Model %s\n",
 		acb->host->host_no,
 		acb->firm_version,
 		acb->firm_model);
@@ -2144,10 +3386,12 @@ static bool arcmsr_get_hba_config(struct
 	acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
 	acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
 	acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
-	acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/
+	acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]);
 	return true;
 }
-static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
+
+static bool
+arcmsr_hbaB_get_config(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 	struct pci_dev *pdev = acb->pdev;
@@ -2163,40 +3407,57 @@ static bool arcmsr_get_hbb_config(struct
 	char __iomem *iop_device_map;
 	/*firm_version,21,84-99*/
 	int count;
-	dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL);
-	if (!dma_coherent){
-		printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no);
+	dma_coherent = dma_alloc_coherent(&pdev->dev,
+		sizeof(struct MessageUnit_B), &dma_coherent_handle,
+		GFP_KERNEL);
+	if (!dma_coherent) {
+		pr_notice("arcmsr%d: dma_alloc_coherent "
+		"got error for hbb mu\n", acb->host->host_no);
 		return false;
 	}
-	acb->dma_coherent_handle_hbb_mu = dma_coherent_handle;
+	acb->dma_coherent_handle2 = dma_coherent_handle;
 	reg = (struct MessageUnit_B *)dma_coherent;
 	acb->pmuB = reg;
-	reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL);
-	reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK);
-	reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL);
-	reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK);
-	reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER);
-	reg->message_rbuffer =  (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER);
-	reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER);
-	iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);	/*firm_model,15,60-67*/
-	iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);	/*firm_version,17,68-83*/
-	iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]);	/*firm_version,21,84-99*/
+	reg->drv2iop_doorbell = (uint32_t __iomem *)
+		((unsigned long)acb->mem_base0 +
+		ARCMSR_DRV2IOP_DOORBELL);
+	reg->drv2iop_doorbell_mask = (uint32_t __iomem *)
+		((unsigned long)acb->mem_base0 +
+		ARCMSR_DRV2IOP_DOORBELL_MASK);
+	reg->iop2drv_doorbell = (uint32_t __iomem *)
+		((unsigned long)acb->mem_base0 +
+		ARCMSR_IOP2DRV_DOORBELL);
+	reg->iop2drv_doorbell_mask = (uint32_t __iomem *)
+		((unsigned long)acb->mem_base0 +
+		ARCMSR_IOP2DRV_DOORBELL_MASK);
+	reg->message_wbuffer = (uint32_t __iomem *)
+		((unsigned long)acb->mem_base1 +
+		ARCMSR_MESSAGE_WBUFFER);
+	reg->message_rbuffer = (uint32_t __iomem *)
+		((unsigned long)acb->mem_base1 +
+		ARCMSR_MESSAGE_RBUFFER);
+	reg->message_rwbuffer = (uint32_t __iomem *)
+		((unsigned long)acb->mem_base1 +
+		ARCMSR_MESSAGE_RWBUFFER);
+	iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);
+	iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);
+	iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]);
 
 	writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
-	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
-		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
-			miscellaneous data' timeout \n", acb->host->host_no);
+	if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+		pr_notice("arcmsr%d: wait 'get adapter firmware "
+		"miscellaneous data' timeout\n", acb->host->host_no);
 		return false;
 	}
 	count = 8;
-	while (count){
+	while (count) {
 		*acb_firm_model = readb(iop_firm_model);
 		acb_firm_model++;
 		iop_firm_model++;
 		count--;
 	}
 	count = 16;
-	while (count){
+	while (count) {
 		*acb_firm_version = readb(iop_firm_version);
 		acb_firm_version++;
 		iop_firm_version++;
@@ -2204,14 +3465,15 @@ static bool arcmsr_get_hbb_config(struct
 	}
 
 	count = 16;
-	while(count){
+	while (count) {
 		*acb_device_map = readb(iop_device_map);
 		acb_device_map++;
 		iop_device_map++;
 		count--;
 	}
-	
-	printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
+
+	pr_notice("Areca RAID Controller%d: "
+		"F/W %s & Model %s\n",
 		acb->host->host_no,
 		acb->firm_version,
 		acb->firm_model);
@@ -2226,41 +3488,45 @@ static bool arcmsr_get_hbb_config(struct
 	/*firm_sdram_size,3,12-15*/
 	acb->firm_hd_channels = readl(&reg->message_rwbuffer[5]);
 	/*firm_ide_channels,4,16-19*/
-	acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/
+	acb->firm_cfg_version = readl(&reg->message_rwbuffer[25]);
 	/*firm_ide_channels,4,16-19*/
 	return true;
 }
 
-static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB)
+static bool
+arcmsr_hbaC_get_config(struct AdapterControlBlock *pACB)
 {
 	uint32_t intmask_org, Index, firmware_state = 0;
 	struct MessageUnit_C *reg = pACB->pmuC;
 	char *acb_firm_model = pACB->firm_model;
 	char *acb_firm_version = pACB->firm_version;
-	char *iop_firm_model = (char *)(&reg->msgcode_rwbuffer[15]);    /*firm_model,15,60-67*/
-	char *iop_firm_version = (char *)(&reg->msgcode_rwbuffer[17]);  /*firm_version,17,68-83*/
+	char *iop_firm_model = (char *)(&reg->msgcode_rwbuffer[15]);
+	char *iop_firm_version = (char *)(&reg->msgcode_rwbuffer[17]);
 	int count;
 	/* disable all outbound interrupt */
-	intmask_org = readl(&reg->host_int_mask); /* disable outbound message0 int */
-	writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, &reg->host_int_mask);
-	/* wait firmware ready */
+	intmask_org = readl(&reg->host_int_mask);
+	writel(intmask_org | ARCMSR_HBCMU_ALL_INTMASKENABLE,
+		&reg->host_int_mask);
 	do {
 		firmware_state = readl(&reg->outbound_msgaddr1);
 	} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
 	/* post "get config" instruction */
 	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
-	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
+	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE,
+		&reg->inbound_doorbell);
 	/* wait message ready */
 	for (Index = 0; Index < 2000; Index++) {
-		if (readl(&reg->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
-			writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &reg->outbound_doorbell_clear);/*clear interrupt*/
+		if (readl(&reg->outbound_doorbell) &
+		ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+			writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR,
+				&reg->outbound_doorbell_clear);
 			break;
 		}
 		udelay(10);
 	} /*max 1 seconds*/
 	if (Index >= 2000) {
-		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
-			miscellaneous data' timeout \n", pACB->host->host_no);
+		pr_notice("arcmsr%d: wait 'get adapter firmware "
+		"miscellaneous data' timeout\n", pACB->host->host_no);
 		return false;
 	}
 	count = 8;
@@ -2277,86 +3543,249 @@ static bool arcmsr_get_hbc_config(struct
 		iop_firm_version++;
 		count--;
 	}
-	printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
-		pACB->host->host_no,
-		pACB->firm_version,
-		pACB->firm_model);
-	pACB->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);   /*firm_request_len,1,04-07*/
-	pACB->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/
-	pACB->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);    /*firm_sdram_size,3,12-15*/
-	pACB->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);  /*firm_ide_channels,4,16-19*/
-	pACB->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);  /*firm_cfg_version,25,100-103*/
+	pr_notice("Areca RAID Controller%d: F/W %s & "
+	"Model %s\n",
+	pACB->host->host_no,
+	pACB->firm_version,
+	pACB->firm_model);
+	pACB->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);
+	pACB->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]);
+	pACB->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);
+	pACB->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);
+	pACB->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
 	/*all interrupt service will be enable at arcmsr_iop_init*/
 	return true;
 }
-static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+
+static bool
+arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
+{
+	char *acb_firm_model = acb->firm_model;
+	char *acb_firm_version = acb->firm_version;
+	char *acb_device_map = acb->device_map;
+	char __iomem *iop_firm_model;
+	char __iomem *iop_firm_version;
+	char __iomem *iop_device_map;
+	u32 count;
+	struct MessageUnit_D *reg ;
+	void *dma_coherent;
+	dma_addr_t dma_coherent_handle;
+	struct pci_dev *pdev = acb->pdev;
+
+	acb->uncache_size = roundup(sizeof(struct MessageUnit_D), 32);
+	dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size,
+	&dma_coherent_handle, GFP_KERNEL);
+	if (!dma_coherent) {
+		pr_notice("DMA allocation failed...\n");
+		return -ENOMEM;
+	}
+	memset(dma_coherent, 0, acb->uncache_size);
+	acb->dma_coherent = dma_coherent;
+	acb->dma_coherent_handle = dma_coherent_handle;
+	reg = (struct MessageUnit_D *)dma_coherent;
+	acb->pmuD = reg;
+	reg->chip_id = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_CHIP_ID);
+	reg->cpu_mem_config = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION);
+	reg->i2o_host_interrupt_mask = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK);
+	reg->sample_at_reset = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_SAMPLE_RESET);
+	reg->reset_request = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_RESET_REQUEST);
+	reg->host_int_status = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS);
+	reg->pcief0_int_enable = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE);
+	reg->inbound_msgaddr0 = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_INBOUND_MESSAGE0);
+	reg->inbound_msgaddr1 = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_INBOUND_MESSAGE1);
+	reg->outbound_msgaddr0 = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_MESSAGE0);
+	reg->outbound_msgaddr1 = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_MESSAGE1);
+	reg->inbound_doorbell = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_INBOUND_DOORBELL);
+	reg->outbound_doorbell = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_DOORBELL);
+	reg->outbound_doorbell_enable = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE);
+	reg->inboundlist_base_low = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW);
+	reg->inboundlist_base_high = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH);
+	reg->inboundlist_write_pointer = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER);
+	reg->outboundlist_base_low = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW);
+	reg->outboundlist_base_high = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH);
+	reg->outboundlist_copy_pointer = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER);
+	reg->outboundlist_read_pointer = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER);
+	reg->outboundlist_interrupt_cause = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE);
+	reg->outboundlist_interrupt_enable = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE);
+	reg->message_wbuffer = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_WBUFFER);
+	reg->message_rbuffer = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_RBUFFER);
+	reg->msgcode_rwbuffer = (u32 __iomem *)((unsigned long)
+	acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_RWBUFFER);
+	iop_firm_model = (char __iomem *)(&reg->msgcode_rwbuffer[15]);
+	iop_firm_version = (char __iomem *)(&reg->msgcode_rwbuffer[17]);
+	iop_device_map = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
+	if (readl(acb->pmuD->outbound_doorbell) &
+	ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) {
+		writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE,
+			acb->pmuD->outbound_doorbell);/*clear interrupt*/
+	}
+	/* post "get config" instruction */
+	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, reg->inbound_msgaddr0);
+	/* wait message ready */
+	if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
+		pr_notice("arcmsr%d: wait get adapter firmware "
+		"miscellaneous data timeout\n", acb->host->host_no);
+		dma_free_coherent(&acb->pdev->dev, acb->uncache_size,
+			acb->dma_coherent, acb->dma_coherent_handle);
+		return false;
+	}
+	count = 8;
+	while (count) {
+		*acb_firm_model = readb(iop_firm_model);
+		acb_firm_model++;
+		iop_firm_model++;
+		count--;
+	}
+	count = 16;
+	while (count) {
+		*acb_firm_version = readb(iop_firm_version);
+		acb_firm_version++;
+		iop_firm_version++;
+		count--;
+	}
+	count = 16;
+	while (count) {
+		*acb_device_map = readb(iop_device_map);
+		acb_device_map++;
+		iop_device_map++;
+		count--;
+	}
+	acb->signature = readl(&reg->msgcode_rwbuffer[1]);
+	/*firm_signature,1,00-03*/
+	acb->firm_request_len = readl(&reg->msgcode_rwbuffer[2]);
+	/*firm_request_len,1,04-07*/
+	acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[3]);
+	/*firm_numbers_queue,2,08-11*/
+	acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[4]);
+	/*firm_sdram_size,3,12-15*/
+	acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[5]);
+	/*firm_hd_channels,4,16-19*/
+	acb->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
+	pr_notice("Areca RAID Controller%d: F/W %s & Model %s\n",
+	acb->host->host_no, acb->firm_version, acb->firm_model);
+	return true;
+}
+
+static bool
+arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
 {
-	if (acb->adapter_type == ACB_ADAPTER_TYPE_A)
-		return arcmsr_get_hba_config(acb);
-	else if (acb->adapter_type == ACB_ADAPTER_TYPE_B)
-		return arcmsr_get_hbb_config(acb);
+	bool rtn = false;
+	switch (acb->adapter_type) {
+	case ACB_ADAPTER_TYPE_A:
+		rtn = arcmsr_hbaA_get_config(acb);
+		break;
+	case ACB_ADAPTER_TYPE_B:
+		rtn = arcmsr_hbaB_get_config(acb);
+		break;
+	case ACB_ADAPTER_TYPE_C:
+		rtn = arcmsr_hbaC_get_config(acb);
+		break;
+	case ACB_ADAPTER_TYPE_D:
+		rtn = arcmsr_hbaD_get_config(acb);
+		break;
+	default:
+		break;
+	}
+	if(acb->firm_numbers_queue > ARCMSR_MAX_FREECCB_NUM)
+		acb->maxOutstanding = ARCMSR_MAX_FREECCB_NUM-1;
 	else
-		return arcmsr_get_hbc_config(acb);
+		acb->maxOutstanding = acb->firm_numbers_queue - 1;
+	return rtn;
 }
 
-static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
+static int
+arcmsr_hbaA_polling_ccbdone(struct AdapterControlBlock *acb,
 	struct CommandControlBlock *poll_ccb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	struct CommandControlBlock *ccb;
 	struct ARCMSR_CDB *arcmsr_cdb;
-	uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
+	uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0;
+	uint32_t poll_count = 0;
 	int rtn;
 	bool error;
 	polling_hba_ccb_retry:
 	poll_count++;
-	outbound_intstatus = readl(&reg->outbound_intstatus) & acb->outbound_int_enable;
-	writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
+	outbound_intstatus = readl(&reg->outbound_intstatus) &
+		acb->outbound_int_enable;
+	writel(outbound_intstatus, &reg->outbound_intstatus);
 	while (1) {
-		if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
-			if (poll_ccb_done){
+		flag_ccb = readl(&reg->outbound_queueport);
+		if (flag_ccb == 0xFFFFFFFF) {
+			if (poll_ccb_done) {
 				rtn = SUCCESS;
 				break;
-			}else {
+			} else {
 				msleep(25);
-				if (poll_count > 100){
+				if (poll_count > 100) {
 					rtn = FAILED;
 					break;
 				}
 				goto polling_hba_ccb_retry;
 			}
 		}
-		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
-		ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset +
+			(flag_ccb << 5));
+		ccb = container_of(arcmsr_cdb, struct CommandControlBlock,
+			arcmsr_cdb);
 		poll_ccb_done = (ccb == poll_ccb) ? 1:0;
 		if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
-			if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
-				printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
-					" poll command abort successfully \n"
-					, acb->host->host_no
-					, ccb->pcmd->device->id
-					, ccb->pcmd->device->lun
-					, ccb);
+			if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
+			(ccb == poll_ccb)) {
+				pr_notice("arcmsr%d: scsi id = %d "
+				"lun = %d ccb = '0x%p' poll command "
+				"abort successfully\n"
+				, acb->host->host_no
+				, ccb->pcmd->device->id
+				, ccb->pcmd->device->lun
+				, ccb);
 				ccb->pcmd->result = DID_ABORT << 16;
 				arcmsr_ccb_complete(ccb);
 				continue;
 			}
-			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
-				" command done ccb = '0x%p'"
-				"ccboutstandingcount = %d \n"
-				, acb->host->host_no
-				, ccb
-				, atomic_read(&acb->ccboutstandingcount));
+			pr_notice("arcmsr%d: polling get an illegal "
+			"ccb command done ccb = '0x%p' "
+			"ccboutstandingcount = %d\n"
+			, acb->host->host_no
+			, ccb
+			, atomic_read(&acb->ccboutstandingcount));
 			continue;
 		}
-		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ?
+			true : false;
 		arcmsr_report_ccb_state(acb, ccb, error);
 	}
 	return rtn;
 }
 
-static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
-					struct CommandControlBlock *poll_ccb)
+int
+arcmsr_hbaB_polling_ccbdone(struct AdapterControlBlock *acb,
+				struct CommandControlBlock *poll_ccb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 	struct ARCMSR_CDB *arcmsr_cdb;
@@ -2368,16 +3797,18 @@ static int arcmsr_polling_hbb_ccbdone(st
 
 	poll_count++;
 	/* clear doorbell interrupt */
-	writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
-	while(1){
+	writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN,
+	reg->iop2drv_doorbell);
+	while (1) {
 		index = reg->doneq_index;
-		if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
-			if (poll_ccb_done){
+		flag_ccb = readl(&reg->done_qbuffer[index]);
+		if (flag_ccb == 0) {
+			if (poll_ccb_done) {
 				rtn = SUCCESS;
 				break;
-			}else {
+			} else {
 				msleep(25);
-				if (poll_count > 100){
+				if (poll_count > 100) {
 					rtn = FAILED;
 					break;
 				}
@@ -2390,36 +3821,45 @@ static int arcmsr_polling_hbb_ccbdone(st
 		index %= ARCMSR_MAX_HBB_POSTQUEUE;
 		reg->doneq_index = index;
 		/* check if command done with no error*/
-		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
-		ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
-		poll_ccb_done = (ccb == poll_ccb) ? 1:0;
-		if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
-			if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {
-				printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
-					" poll command abort successfully \n"
-					,acb->host->host_no
-					,ccb->pcmd->device->id
-					,ccb->pcmd->device->lun
-					,ccb);
+		arcmsr_cdb = (struct ARCMSR_CDB *)
+		(acb->vir2phy_offset + (flag_ccb << 5));
+		ccb = container_of(arcmsr_cdb,
+			struct CommandControlBlock,
+			arcmsr_cdb);
+		poll_ccb_done = (ccb == poll_ccb) ? 1 : 0;
+		if ((ccb->acb != acb) ||
+		(ccb->startdone != ARCMSR_CCB_START)) {
+			if ((ccb->startdone == ARCMSR_CCB_ABORTED) ||
+				(ccb == poll_ccb)) {
+				pr_notice("arcmsr%d: "
+				"scsi id = %d lun = %d ccb = '0x%p' poll "
+				"command abort successfully\n"
+				, acb->host->host_no
+				, ccb->pcmd->device->id
+				, ccb->pcmd->device->lun
+				, ccb);
 				ccb->pcmd->result = DID_ABORT << 16;
 				arcmsr_ccb_complete(ccb);
 				continue;
 			}
-			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
-				" command done ccb = '0x%p'"
-				"ccboutstandingcount = %d \n"
+			pr_notice("arcmsr%d: polling get an "
+				"illegal ccb command done ccb = '0x%p' "
+				"ccboutstandingcount = %d\n"
 				, acb->host->host_no
 				, ccb
 				, atomic_read(&acb->ccboutstandingcount));
 			continue;
 		} 
-		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0)
+		? true : false;
 		arcmsr_report_ccb_state(acb, ccb, error);
 	}
 	return rtn;
 }
 
-static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb)
+static int
+arcmsr_hbaC_polling_ccbdone(struct AdapterControlBlock *acb,
+	struct CommandControlBlock *poll_ccb)
 {
 	struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
 	uint32_t flag_ccb, ccb_cdb_phy;
@@ -2431,7 +3871,8 @@ static int arcmsr_polling_hbc_ccbdone(st
 polling_hbc_ccb_retry:
 	poll_count++;
 	while (1) {
-		if ((readl(&reg->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) {
+		if ((readl(&reg->host_int_status) &
+			ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) {
 			if (poll_ccb_done) {
 				rtn = SUCCESS;
 				break;
@@ -2446,60 +3887,154 @@ polling_hbc_ccb_retry:
 		}
 		flag_ccb = readl(&reg->outbound_queueport_low);
 		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
-		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/
-		pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
+			+ ccb_cdb_phy);
+		pCCB = container_of(arcmsr_cdb, struct CommandControlBlock,
+			arcmsr_cdb);
 		poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
 		/* check ifcommand done with no error*/
-		if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+		if ((pCCB->acb != acb) ||
+			(pCCB->startdone != ARCMSR_CCB_START)) {
 			if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
-				printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
-					" poll command abort successfully \n"
-					, acb->host->host_no
-					, pCCB->pcmd->device->id
-					, pCCB->pcmd->device->lun
-					, pCCB);
-					pCCB->pcmd->result = DID_ABORT << 16;
-					arcmsr_ccb_complete(pCCB);
+				pr_notice("arcmsr%d: "
+				"scsi id = %d lun = %d ccb = '0x%p' poll "
+				"command abort successfully\n"
+				, acb->host->host_no
+				, pCCB->pcmd->device->id
+				, pCCB->pcmd->device->lun
+				, pCCB);
+				pCCB->pcmd->result = DID_ABORT << 16;
+				arcmsr_ccb_complete(pCCB);
 				continue;
 			}
-			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
-				" command done ccb = '0x%p'"
-				"ccboutstandingcount = %d \n"
+			pr_notice("arcmsr%d: polling get an illegal "
+			"ccb command done ccb = '0x%p' "
+			"ccboutstandingcount = %d\n"
+			, acb->host->host_no
+			, pCCB
+			, atomic_read(&acb->ccboutstandingcount));
+			continue;
+		}
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
+			? true : false;
+		arcmsr_report_ccb_state(acb, pCCB, error);
+	}
+	return rtn;
+}
+
+static int
+arcmsr_hbaD_polling_ccbdone(struct AdapterControlBlock *acb,
+				struct CommandControlBlock *poll_ccb)
+{
+	bool error;
+	uint32_t poll_ccb_done = 0, poll_count = 0, flag_ccb, ccb_cdb_phy;
+	int rtn, doneq_index, index_stripped, outbound_write_pointer;
+	unsigned long flags;
+	struct ARCMSR_CDB *arcmsr_cdb;
+	struct CommandControlBlock *pCCB;
+	struct MessageUnit_D __iomem *pmu =
+		(struct MessageUnit_D *)acb->pmuD;
+
+	spin_lock_irqsave(&acb->doneq_lock, flags);
+	polling_hbaD_ccb_retry:
+	poll_count++;
+	while (1) {
+		outbound_write_pointer =
+		pmu->done_qbuffer[0].addressLow + 1;
+		doneq_index = pmu->doneq_index;
+		if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) {
+			if (poll_ccb_done) {
+				rtn = SUCCESS;
+				break;
+			} else {
+				msleep(25);
+				if (poll_count > 100) {
+					rtn = FAILED;
+					break;
+				}
+				goto polling_hbaD_ccb_retry;
+			}
+		}
+		if (doneq_index & 0x4000) {
+			index_stripped = doneq_index & 0xFFF;
+			index_stripped += 1;
+			index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+			pmu->doneq_index = index_stripped ? (index_stripped | 0x4000)
+				: (index_stripped + 1);
+		} else {
+			index_stripped = doneq_index;
+			index_stripped += 1;
+			index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+			pmu->doneq_index = index_stripped ? index_stripped :
+				((index_stripped | 0x4000) + 1);
+		}
+		doneq_index = pmu->doneq_index;
+		flag_ccb = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
+		ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
+		arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset +
+			ccb_cdb_phy);
+		pCCB = container_of(arcmsr_cdb,
+			struct CommandControlBlock, arcmsr_cdb);
+		poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
+		if ((pCCB->acb != acb) ||
+		(pCCB->startdone != ARCMSR_CCB_START)) {
+			if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+				pr_notice("arcmsr%d: scsi id = %d "
+				"lun = %d ccb = '0x%p' poll command "
+				"abort successfully\n"
 				, acb->host->host_no
-				, pCCB
-				, atomic_read(&acb->ccboutstandingcount));
+				, pCCB->pcmd->device->id
+				, pCCB->pcmd->device->lun
+				, pCCB);
+				pCCB->pcmd->result = DID_ABORT << 16;
+				arcmsr_ccb_complete(pCCB);
+				continue;
+			}
+			pr_notice("arcmsr%d: polling an illegal "
+			"ccb command done ccb = '0x%p' "
+			"ccboutstandingcount = %d\n"
+			, acb->host->host_no
+			, pCCB
+			, atomic_read(&acb->ccboutstandingcount));
 			continue;
 		}
-		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+		error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
+		? true : false;
 		arcmsr_report_ccb_state(acb, pCCB, error);
 	}
+	spin_unlock_irqrestore(&acb->doneq_lock, flags);
 	return rtn;
 }
-static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
-					struct CommandControlBlock *poll_ccb)
+
+static int
+arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
+				struct CommandControlBlock *poll_ccb)
 {
 	int rtn = 0;
 	switch (acb->adapter_type) {
-
-	case ACB_ADAPTER_TYPE_A: {
-		rtn = arcmsr_polling_hba_ccbdone(acb, poll_ccb);
-		}
+	case ACB_ADAPTER_TYPE_A:{
+		rtn = arcmsr_hbaA_polling_ccbdone(acb, poll_ccb);
 		break;
-
-	case ACB_ADAPTER_TYPE_B: {
-		rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb);
-		}
+	}
+	case ACB_ADAPTER_TYPE_B:{
+		rtn = arcmsr_hbaB_polling_ccbdone(acb, poll_ccb);
 		break;
+	}
 	case ACB_ADAPTER_TYPE_C: {
-		rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb);
-		}
+		rtn = arcmsr_hbaC_polling_ccbdone(acb, poll_ccb);
+		break;
+	}
+	case ACB_ADAPTER_TYPE_D: {
+		rtn = arcmsr_hbaD_polling_ccbdone(acb, poll_ccb);
+	}
 	}
 	return rtn;
 }
 
-static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
+static int
+arcmsr_iop_confirm(struct AdapterControlBlock *acb)
 {
-	uint32_t cdb_phyaddr, cdb_phyaddr_hi32;
+	uint32_t cdb_phyaddr, cdb_phyaddr_hi32, cdb_phyaddr_lo32;
 	dma_addr_t dma_coherent_handle;
 	/*
 	********************************************************************
@@ -2508,7 +4043,7 @@ static int arcmsr_iop_confirm(struct Ada
 	********************************************************************
 	*/
 	dma_coherent_handle = acb->dma_coherent_handle;
-	cdb_phyaddr = (uint32_t)(dma_coherent_handle);
+	cdb_phyaddr_lo32 = (uint32_t)(dma_coherent_handle & 0xffffffff);
 	cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
 	acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
 	/*
@@ -2521,20 +4056,17 @@ static int arcmsr_iop_confirm(struct Ada
 	case ACB_ADAPTER_TYPE_A: {
 		if (cdb_phyaddr_hi32 != 0) {
 			struct MessageUnit_A __iomem *reg = acb->pmuA;
-			uint32_t intmask_org;
-			intmask_org = arcmsr_disable_outbound_ints(acb);
-			writel(ARCMSR_SIGNATURE_SET_CONFIG, \
-						&reg->message_rwbuffer[0]);
+			writel(ARCMSR_SIGNATURE_SET_CONFIG,
+			&reg->message_rwbuffer[0]);
 			writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
-			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
-							&reg->inbound_msgaddr0);
-			if (!arcmsr_hba_wait_msgint_ready(acb)) {
-				printk(KERN_NOTICE "arcmsr%d: ""set ccb high \
-				part physical address timeout\n",
+			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG,
+			&reg->inbound_msgaddr0);
+			if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
+				pr_notice("arcmsr%d: set ccb "
+				"high part physical address timeout\n",
 				acb->host->host_no);
 				return 1;
 			}
-			arcmsr_enable_outbound_ints(acb, intmask_org);
 		}
 		}
 		break;
@@ -2544,17 +4076,16 @@ static int arcmsr_iop_confirm(struct Ada
 		uint32_t __iomem *rwbuffer;
 
 		struct MessageUnit_B *reg = acb->pmuB;
-		uint32_t intmask_org;
-		intmask_org = arcmsr_disable_outbound_ints(acb);
 		reg->postq_index = 0;
 		reg->doneq_index = 0;
-		writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
-		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
-			printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
-				acb->host->host_no);
+		writel(ARCMSR_MESSAGE_SET_POST_WINDOW,
+		reg->drv2iop_doorbell);
+		if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+			pr_notice("arcmsr%d:can not set diver mode\n",
+			acb->host->host_no);
 			return 1;
 		}
-		post_queue_phyaddr = acb->dma_coherent_handle_hbb_mu;
+		post_queue_phyaddr = acb->dma_coherent_handle2;
 		rwbuffer = reg->message_rwbuffer;
 		/* driver "set config" signature */
 		writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
@@ -2566,39 +4097,66 @@ static int arcmsr_iop_confirm(struct Ada
 		writel(post_queue_phyaddr + 1056, rwbuffer++);
 		/* ccb maxQ size must be --> [(256 + 8)*4]*/
 		writel(1056, rwbuffer);
-
 		writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
-		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
-			printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
-			timeout \n",acb->host->host_no);
+		if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+			pr_notice("arcmsr%d: 'set command Q window' "
+			"timeout\n", acb->host->host_no);
 			return 1;
 		}
 		arcmsr_hbb_enable_driver_mode(acb);
-		arcmsr_enable_outbound_ints(acb, intmask_org);
 		}
 		break;
 	case ACB_ADAPTER_TYPE_C: {
 		if (cdb_phyaddr_hi32 != 0) {
-			struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
-
-			printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x\n",
-					acb->adapter_index, cdb_phyaddr_hi32);
-			writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->msgcode_rwbuffer[0]);
-			writel(cdb_phyaddr_hi32, &reg->msgcode_rwbuffer[1]);
-			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
-			writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
-			if (!arcmsr_hbc_wait_msgint_ready(acb)) {
-				printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
-				timeout \n", acb->host->host_no);
+			struct MessageUnit_C *reg =
+			(struct MessageUnit_C *)acb->pmuC;
+			pr_notice("arcmsr%d: cdb_phyaddr_hi32 = 0x%x\n",
+			acb->adapter_index, cdb_phyaddr_hi32);
+			writel(ARCMSR_SIGNATURE_SET_CONFIG,
+				&reg->msgcode_rwbuffer[0]);
+			writel(cdb_phyaddr_hi32,
+				&reg->msgcode_rwbuffer[1]);
+			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG,
+				&reg->inbound_msgaddr0);
+			writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE,
+				&reg->inbound_doorbell);
+			if (!arcmsr_hbaC_wait_msgint_ready(acb)) {
+				pr_notice("arcmsr%d: 'set "
+				"command Q window' timeout\n",
+				acb->host->host_no);
 				return 1;
 			}
 		}
 		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		uint32_t __iomem *rwbuffer;
+
+		struct MessageUnit_D *reg =
+			(struct MessageUnit_D *)acb->pmuD;
+		reg->postq_index = 0;
+		reg->doneq_index = 0;
+		rwbuffer = reg->msgcode_rwbuffer;
+		writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
+		writel(cdb_phyaddr_hi32, rwbuffer++);
+		writel(cdb_phyaddr_lo32, rwbuffer++);
+		writel(cdb_phyaddr_lo32 +
+		(ARCMSR_MAX_ARC1214_POSTQUEUE * sizeof(struct InBound_SRB)),
+		rwbuffer++);
+		writel(0x100, rwbuffer);
+		writel(ARCMSR_INBOUND_MESG0_SET_CONFIG,
+			reg->inbound_msgaddr0);
+		if (!arcmsr_hbaD_wait_msgint_ready(acb))
+			pr_notice("arcmsr%d: 'set command Q "
+			"window' timeout\n", acb->host->host_no);
+		break;
+	}
 	}
 	return 0;
 }
 
-static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
+static void
+arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
 {
 	uint32_t firmware_state = 0;
 	switch (acb->adapter_type) {
@@ -2607,161 +4165,265 @@ static void arcmsr_wait_firmware_ready(s
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 		do {
 			firmware_state = readl(&reg->outbound_msgaddr1);
-		} while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);
+		} while ((firmware_state &
+		ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);
 		}
 		break;
-
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
 		do {
 			firmware_state = readl(reg->iop2drv_doorbell);
 		} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);
-		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
+		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT,
+		reg->drv2iop_doorbell);
 		}
 		break;
 	case ACB_ADAPTER_TYPE_C: {
-		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+		struct MessageUnit_C *reg =
+			(struct MessageUnit_C *)acb->pmuC;
 		do {
 			firmware_state = readl(&reg->outbound_msgaddr1);
-		} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+		} while ((firmware_state &
+		ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
 		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *reg
+			= (struct MessageUnit_D *)acb->pmuD;
+		do {
+			firmware_state = readl(reg->outbound_msgaddr1);
+		} while ((firmware_state &
+		ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK) == 0);
+		break;
+	}
 	}
 }
 
-static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaA_request_device_map(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
-	if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
-		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+	if (unlikely(atomic_read(&acb->rq_map_token) == 0) ||
+		((acb->acb_flags & ACB_F_BUS_RESET) != 0)
+		|| ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+		mod_timer(&acb->eternal_timer,
+			jiffies + msecs_to_jiffies(6 * HZ));
 		return;
 	} else {
 		acb->fw_flag = FW_NORMAL;
-		if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)){
+		if (atomic_read(&acb->ante_token_value) ==
+			atomic_read(&acb->rq_map_token)) {
 			atomic_set(&acb->rq_map_token, 16);
 		}
-		atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+		atomic_set(&acb->ante_token_value,
+			atomic_read(&acb->rq_map_token));
 		if (atomic_dec_and_test(&acb->rq_map_token)) {
-			mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+			mod_timer(&acb->eternal_timer,
+				jiffies + msecs_to_jiffies(6 * HZ));
 			return;
 		}
-		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
-		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG,
+			&reg->inbound_msgaddr0);
+		mod_timer(&acb->eternal_timer, jiffies +
+			msecs_to_jiffies(6 * HZ));
 	}
 	return;
 }
 
-static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaB_request_device_map(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B __iomem *reg = acb->pmuB;
-	if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){
-		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+	if (unlikely(atomic_read(&acb->rq_map_token) == 0) ||
+		((acb->acb_flags & ACB_F_BUS_RESET) != 0) ||
+		((acb->acb_flags & ACB_F_ABORT) != 0)) {
+		mod_timer(&acb->eternal_timer, jiffies +
+			msecs_to_jiffies(6 * HZ));
 		return;
 	} else {
 		acb->fw_flag = FW_NORMAL;
-		if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
+		if (atomic_read(&acb->ante_token_value) ==
+			atomic_read(&acb->rq_map_token)) {
 			atomic_set(&acb->rq_map_token, 16);
 		}
-		atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+		atomic_set(&acb->ante_token_value,
+			atomic_read(&acb->rq_map_token));
 		if (atomic_dec_and_test(&acb->rq_map_token)) {
-			mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+			mod_timer(&acb->eternal_timer,
+				jiffies + msecs_to_jiffies(6 * HZ));
 			return;
 		}
-		writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
-		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+		writel(ARCMSR_MESSAGE_GET_CONFIG,
+			reg->drv2iop_doorbell);
+		mod_timer(&acb->eternal_timer, jiffies +
+			msecs_to_jiffies(6 * HZ));
 	}
 	return;
 }
 
-static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaC_request_device_map(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_C __iomem *reg = acb->pmuC;
-	if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
-		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+	if (unlikely(atomic_read(&acb->rq_map_token) == 0) ||
+		((acb->acb_flags & ACB_F_BUS_RESET) != 0) ||
+		((acb->acb_flags & ACB_F_ABORT) != 0)) {
+		mod_timer(&acb->eternal_timer, jiffies +
+			msecs_to_jiffies(6 * HZ));
 		return;
 	} else {
 		acb->fw_flag = FW_NORMAL;
-		if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
+		if (atomic_read(&acb->ante_token_value) ==
+			atomic_read(&acb->rq_map_token)) {
+			atomic_set(&acb->rq_map_token, 16);
+		}
+		atomic_set(&acb->ante_token_value,
+			atomic_read(&acb->rq_map_token));
+		if (atomic_dec_and_test(&acb->rq_map_token)) {
+			mod_timer(&acb->eternal_timer,
+				jiffies + msecs_to_jiffies(6 * HZ));
+			return;
+		}
+		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG,
+			&reg->inbound_msgaddr0);
+		writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE,
+			&reg->inbound_doorbell);
+		mod_timer(&acb->eternal_timer, jiffies +
+			msecs_to_jiffies(6 * HZ));
+	}
+	return;
+}
+
+static void
+arcmsr_hbaD_request_device_map(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_D __iomem *reg = acb->pmuD;
+	if (unlikely(atomic_read(&acb->rq_map_token) == 0) ||
+		((acb->acb_flags & ACB_F_BUS_RESET) != 0) ||
+		((acb->acb_flags & ACB_F_ABORT) != 0)) {
+		mod_timer(&acb->eternal_timer,
+			jiffies + msecs_to_jiffies(6 * HZ));
+	} else {
+		acb->fw_flag = FW_NORMAL;
+		if (atomic_read(&acb->ante_token_value) ==
+			atomic_read(&acb->rq_map_token)) {
 			atomic_set(&acb->rq_map_token, 16);
 		}
-		atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+		atomic_set(&acb->ante_token_value,
+			atomic_read(&acb->rq_map_token));
 		if (atomic_dec_and_test(&acb->rq_map_token)) {
-			mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+			mod_timer(&acb->eternal_timer, jiffies +
+				msecs_to_jiffies(6 * HZ));
 			return;
 		}
-		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
-		writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &reg->inbound_doorbell);
-		mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG,
+			reg->inbound_msgaddr0);
+		mod_timer(&acb->eternal_timer, jiffies +
+			msecs_to_jiffies(6 * HZ));
 	}
 	return;
 }
 
-static void arcmsr_request_device_map(unsigned long pacb)
+static void
+arcmsr_request_device_map(unsigned long pacb)
 {
-	struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
+	struct AdapterControlBlock *acb =
+		(struct AdapterControlBlock *)pacb;
 	switch (acb->adapter_type) {
 		case ACB_ADAPTER_TYPE_A: {
-			arcmsr_request_hba_device_map(acb);
+			arcmsr_hbaA_request_device_map(acb);
+			break;
 		}
-		break;
 		case ACB_ADAPTER_TYPE_B: {
-			arcmsr_request_hbb_device_map(acb);
+			arcmsr_hbaB_request_device_map(acb);
+			break;
 		}
-		break;
 		case ACB_ADAPTER_TYPE_C: {
-			arcmsr_request_hbc_device_map(acb);
+			arcmsr_hbaC_request_device_map(acb);
+			break;
+		}
+		case ACB_ADAPTER_TYPE_D: {
+			arcmsr_hbaD_request_device_map(acb);
 		}
 	}
 }
 
-static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaA_start_bgrb(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
-	writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);
-	if (!arcmsr_hba_wait_msgint_ready(acb)) {
-		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
-				rebulid' timeout \n", acb->host->host_no);
+	writel(ARCMSR_INBOUND_MESG0_START_BGRB,
+		&reg->inbound_msgaddr0);
+	if (!arcmsr_hbaA_wait_msgint_ready(acb)) {
+		pr_notice("arcmsr%d: wait 'start adapter "
+		"background rebulid' timeout\n", acb->host->host_no);
 	}
 }
 
-static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb)
+static void
+arcmsr_hbaB_start_bgrb(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 	acb->acb_flags |= ACB_F_MSG_START_BGRB;
 	writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
-	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
-		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
-				rebulid' timeout \n",acb->host->host_no);
+	if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+		pr_notice("arcmsr%d: wait 'start adapter "
+		"backgroundrebulid' timeout\n", acb->host->host_no);
 	}
 }
 
-static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB)
+static void
+arcmsr_hbaC_start_bgrb(struct AdapterControlBlock *pACB)
 {
-	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+	struct MessageUnit_C *phbcmu =
+		(struct MessageUnit_C *)pACB->pmuC;
+	pACB->acb_flags |= ACB_F_MSG_START_BGRB;
+	writel(ARCMSR_INBOUND_MESG0_START_BGRB,
+		&phbcmu->inbound_msgaddr0);
+	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE,
+		&phbcmu->inbound_doorbell);
+	if (!arcmsr_hbaC_wait_msgint_ready(pACB)) {
+		pr_notice("arcmsr%d: wait 'start adapter "
+		"background rebulid' timeout\n", pACB->host->host_no);
+	}
+	return;
+}
+
+static void
+arcmsr_hbaD_start_bgrb(struct AdapterControlBlock *pACB)
+{
+	struct MessageUnit_D __iomem *pmu = (struct MessageUnit_D *)pACB->pmuD;
 	pACB->acb_flags |= ACB_F_MSG_START_BGRB;
-	writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0);
-	writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell);
-	if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
-		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
-				rebulid' timeout \n", pACB->host->host_no);
+	writel(ARCMSR_INBOUND_MESG0_START_BGRB, pmu->inbound_msgaddr0);
+	if (!arcmsr_hbaD_wait_msgint_ready(pACB)) {
+		pr_notice("arcmsr%d: wait 'start adapter "
+		"background rebulid' timeout\n", pACB->host->host_no);
 	}
 	return;
 }
-static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
+
+static void
+arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A:
-		arcmsr_start_hba_bgrb(acb);
+		arcmsr_hbaA_start_bgrb(acb);
 		break;
 	case ACB_ADAPTER_TYPE_B:
-		arcmsr_start_hbb_bgrb(acb);
+		arcmsr_hbaB_start_bgrb(acb);
 		break;
 	case ACB_ADAPTER_TYPE_C:
-		arcmsr_start_hbc_bgrb(acb);
+		arcmsr_hbaC_start_bgrb(acb);
+		break;
+	case ACB_ADAPTER_TYPE_D:
+		arcmsr_hbaD_start_bgrb(acb);
+		break;
 	}
 }
 
-static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
+static void
+arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A: {
@@ -2771,65 +4433,87 @@ static void arcmsr_clear_doorbell_queue_
 		outbound_doorbell = readl(&reg->outbound_doorbell);
 		/*clear doorbell interrupt */
 		writel(outbound_doorbell, &reg->outbound_doorbell);
-		writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
+		writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+			&reg->inbound_doorbell);
 		}
 		break;
 
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
 		/*clear interrupt and message state*/
-		writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
-		writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
+		writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN,
+		reg->iop2drv_doorbell);
+		writel(ARCMSR_DRV2IOP_DATA_READ_OK,
+			reg->drv2iop_doorbell);
 		/* let IOP know data has been read */
 		}
 		break;
 	case ACB_ADAPTER_TYPE_C: {
-		struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+		struct MessageUnit_C *reg =
+			(struct MessageUnit_C *)acb->pmuC;
 		uint32_t outbound_doorbell;
 		/* empty doorbell Qbuffer if door bell ringed */
 		outbound_doorbell = readl(&reg->outbound_doorbell);
 		writel(outbound_doorbell, &reg->outbound_doorbell_clear);
-		writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
+		writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK,
+			&reg->inbound_doorbell);
 		}
+		break;
+	case ACB_ADAPTER_TYPE_D: {
+		struct MessageUnit_D __iomem *reg =
+			(struct MessageUnit_D *)acb->pmuD;
+		uint32_t outbound_doorbell;
+		/* empty doorbell Qbuffer if door bell ringed */
+		outbound_doorbell = readl(reg->outbound_doorbell);
+		writel(outbound_doorbell, reg->outbound_doorbell);
+		writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ,
+			reg->inbound_doorbell);
+		break;
+	}
 	}
 }
 
-static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
+static void
+arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A:
+	case ACB_ADAPTER_TYPE_C:
+	case ACB_ADAPTER_TYPE_D:
 		return;
-	case ACB_ADAPTER_TYPE_B:
-		{
-			struct MessageUnit_B *reg = acb->pmuB;
-			writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell);
-			if (!arcmsr_hbb_wait_msgint_ready(acb)) {
-				printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
+	case ACB_ADAPTER_TYPE_B: {
+		struct MessageUnit_B *reg = acb->pmuB;
+			writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE,
+				reg->drv2iop_doorbell);
+			if (!arcmsr_hbaB_wait_msgint_ready(acb)) {
+				pr_notice("ARCMSR IOP "
+				"enables EOI_MODE TIMEOUT");
 				return;
 			}
-		}
-		break;
-	case ACB_ADAPTER_TYPE_C:
-		return;
+	}
+	break;
 	}
 	return;
 }
 
-static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
+static void
+arcmsr_hardware_reset(struct AdapterControlBlock *acb)
 {
 	uint8_t value[64];
 	int i, count = 0;
 	struct MessageUnit_A __iomem *pmuA = acb->pmuA;
 	struct MessageUnit_C __iomem *pmuC = acb->pmuC;
-
+	u32 temp = 0;
 	/* backup pci config data */
-	printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
+	pr_notice("arcmsr%d: executing hw bus reset .....\n",
+	acb->host->host_no);
 	for (i = 0; i < 64; i++) {
 		pci_read_config_byte(acb->pdev, i, &value[i]);
 	}
 	/* hardware reset signal */
 	if ((acb->dev_id == 0x1680)) {
-		writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]);
+		writel(ARCMSR_ARC1680_BUS_RESET,
+			&pmuA->reserved1[0]);
 	} else if ((acb->dev_id == 0x1880)) {
 		do {
 			count++;
@@ -2839,8 +4523,11 @@ static void arcmsr_hardware_reset(struct
 			writel(0x2, &pmuC->write_sequence);
 			writel(0x7, &pmuC->write_sequence);
 			writel(0xD, &pmuC->write_sequence);
-		} while (((readl(&pmuC->host_diagnostic) & ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5));
-		writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic);
+		} while ((((temp = readl(&pmuC->host_diagnostic)) |
+		ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) &&
+		(count < 5));
+		writel(ARCMSR_ARC1880_RESET_ADAPTER,
+			&pmuC->host_diagnostic);
 	} else {
 		pci_write_config_byte(acb->pdev, 0x84, 0x20);
 	}
@@ -2852,7 +4539,9 @@ static void arcmsr_hardware_reset(struct
 	msleep(1000);
 	return;
 }
-static void arcmsr_iop_init(struct AdapterControlBlock *acb)
+
+static void
+arcmsr_iop_init(struct AdapterControlBlock *acb)
 {
 	uint32_t intmask_org;
 	/* disable all outbound interrupt */
@@ -2869,7 +4558,8 @@ static void arcmsr_iop_init(struct Adapt
 	acb->acb_flags |= ACB_F_IOP_INITED;
 }
 
-static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
+static uint8_t
+arcmsr_iop_reset(struct AdapterControlBlock *acb)
 {
 	struct CommandControlBlock *ccb;
 	uint32_t intmask_org;
@@ -2892,7 +4582,8 @@ static uint8_t arcmsr_iop_reset(struct A
 				ccb->ccb_flags = 0;
 				spin_lock_irqsave(&acb->ccblist_lock, flags);
 				list_add_tail(&ccb->list, &acb->ccb_free_list);
-				spin_unlock_irqrestore(&acb->ccblist_lock, flags);
+				spin_unlock_irqrestore(&acb->ccblist_lock,
+					flags);
 			}
 		}
 		atomic_set(&acb->ccboutstandingcount, 0);
@@ -2903,147 +4594,237 @@ static uint8_t arcmsr_iop_reset(struct A
 	return rtnval;
 }
 
-static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
+static int
+arcmsr_bus_reset(struct scsi_cmnd *cmd)
 {
 	struct AdapterControlBlock *acb;
 	uint32_t intmask_org, outbound_doorbell;
 	int retry_count = 0;
 	int rtn = FAILED;
 	acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
-	printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts);
+	pr_err("arcmsr: executing bus reset eh.....num_resets = %d, "
+	"num_aborts = %d\n", acb->num_resets, acb->num_aborts);
 	acb->num_resets++;
 
-	switch(acb->adapter_type){
-		case ACB_ADAPTER_TYPE_A:{
-			if (acb->acb_flags & ACB_F_BUS_RESET){
-				long timeout;
-				printk(KERN_ERR "arcmsr: there is an  bus reset eh proceeding.......\n");
-				timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
-				if (timeout) {
-					return SUCCESS;
-				}
-			}
-			acb->acb_flags |= ACB_F_BUS_RESET;
-			if (!arcmsr_iop_reset(acb)) {
-				struct MessageUnit_A __iomem *reg;
-				reg = acb->pmuA;
-				arcmsr_hardware_reset(acb);
-				acb->acb_flags &= ~ACB_F_IOP_INITED;
+	switch (acb->adapter_type) {
+	case ACB_ADAPTER_TYPE_A: {
+		if (acb->acb_flags & ACB_F_BUS_RESET) {
+			long timeout;
+			pr_err("arcmsr: there is an bus "
+			"reset eh proceeding.......\n");
+			timeout = wait_event_timeout(wait_q,
+			(acb->acb_flags & ACB_F_BUS_RESET)
+			== 0, 220 * HZ);
+			if (timeout) {
+				return SUCCESS;
+			}
+		}
+		acb->acb_flags |= ACB_F_BUS_RESET;
+		if (!arcmsr_iop_reset(acb)) {
+			struct MessageUnit_A __iomem *reg;
+			reg = acb->pmuA;
+			arcmsr_hardware_reset(acb);
+			acb->acb_flags &= ~ACB_F_IOP_INITED;
 sleep_again:
-				ssleep(ARCMSR_SLEEPTIME);
-				if ((readl(&reg->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
-					printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count);
-					if (retry_count > ARCMSR_RETRYCOUNT) {
-						acb->fw_flag = FW_DEADLOCK;
-						printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no);
-						return FAILED;
-					}
-					retry_count++;
-					goto sleep_again;
+			ssleep(ARCMSR_SLEEPTIME);
+			if ((readl(&reg->outbound_msgaddr1) &
+			ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
+				pr_err("arcmsr%d: waiting for "
+				"hw bus reset return, retry = %d\n",
+				acb->host->host_no, retry_count);
+				if (retry_count > ARCMSR_RETRYCOUNT) {
+					acb->fw_flag = FW_DEADLOCK;
+					pr_err("arcmsr%d: waiting "
+					"for hw bus reset return, "
+					"RETRY TERMINATED!!\n",
+					acb->host->host_no);
+					return FAILED;
 				}
-				acb->acb_flags |= ACB_F_IOP_INITED;
-				/* disable all outbound interrupt */
-				intmask_org = arcmsr_disable_outbound_ints(acb);
-				arcmsr_get_firmware_spec(acb);
-				arcmsr_start_adapter_bgrb(acb);
-				/* clear Qbuffer if door bell ringed */
-				outbound_doorbell = readl(&reg->outbound_doorbell);
-				writel(outbound_doorbell, &reg->outbound_doorbell); /*clear interrupt */
-   				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);
-				/* enable outbound Post Queue,outbound doorbell Interrupt */
-				arcmsr_enable_outbound_ints(acb, intmask_org);
-				atomic_set(&acb->rq_map_token, 16);
-				atomic_set(&acb->ante_token_value, 16);
-				acb->fw_flag = FW_NORMAL;
-				mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
-				acb->acb_flags &= ~ACB_F_BUS_RESET;
-				rtn = SUCCESS;
-				printk(KERN_ERR "arcmsr: scsi  bus reset eh returns with success\n");
-			} else {
-				acb->acb_flags &= ~ACB_F_BUS_RESET;
-				atomic_set(&acb->rq_map_token, 16);
-				atomic_set(&acb->ante_token_value, 16);
-				acb->fw_flag = FW_NORMAL;
-				mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
-				rtn = SUCCESS;
+				retry_count++;
+				goto sleep_again;
 			}
-			break;
+			acb->acb_flags |= ACB_F_IOP_INITED;
+			/* disable all outbound interrupt */
+			intmask_org = arcmsr_disable_outbound_ints(acb);
+			arcmsr_get_firmware_spec(acb);
+			arcmsr_start_adapter_bgrb(acb);
+			/* clear Qbuffer if door bell ringed */
+			outbound_doorbell = readl(&reg->outbound_doorbell);
+			writel(outbound_doorbell, &reg->outbound_doorbell);
+			writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+				&reg->inbound_doorbell);
+			arcmsr_enable_outbound_ints(acb, intmask_org);
+			atomic_set(&acb->rq_map_token, 16);
+			atomic_set(&acb->ante_token_value, 16);
+			acb->fw_flag = FW_NORMAL;
+			mod_timer(&acb->eternal_timer, jiffies +
+				msecs_to_jiffies(6 * HZ));
+			acb->acb_flags &= ~ACB_F_BUS_RESET;
+			rtn = SUCCESS;
+			pr_err("arcmsr: scsi bus reset eh "
+			"returns with success\n");
+		} else {
+			acb->acb_flags &= ~ACB_F_BUS_RESET;
+			atomic_set(&acb->rq_map_token, 16);
+			atomic_set(&acb->ante_token_value, 16);
+			acb->fw_flag = FW_NORMAL;
+			mod_timer(&acb->eternal_timer,
+			jiffies + msecs_to_jiffies(6 * HZ));
+			rtn = SUCCESS;
 		}
-		case ACB_ADAPTER_TYPE_B:{
-			acb->acb_flags |= ACB_F_BUS_RESET;
-			if (!arcmsr_iop_reset(acb)) {
-				acb->acb_flags &= ~ACB_F_BUS_RESET;
-				rtn = FAILED;
-			} else {
-				acb->acb_flags &= ~ACB_F_BUS_RESET;
-				atomic_set(&acb->rq_map_token, 16);
-				atomic_set(&acb->ante_token_value, 16);
-				acb->fw_flag = FW_NORMAL;
-				mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
-				rtn = SUCCESS;
+		break;
+	}
+	case ACB_ADAPTER_TYPE_B: {
+		acb->acb_flags |= ACB_F_BUS_RESET;
+		if (!arcmsr_iop_reset(acb)) {
+			acb->acb_flags &= ~ACB_F_BUS_RESET;
+			rtn = FAILED;
+		} else {
+			acb->acb_flags &= ~ACB_F_BUS_RESET;
+			atomic_set(&acb->rq_map_token, 16);
+			atomic_set(&acb->ante_token_value, 16);
+			acb->fw_flag = FW_NORMAL;
+			mod_timer(&acb->eternal_timer,
+				jiffies + msecs_to_jiffies(6 * HZ));
+			rtn = SUCCESS;
+		}
+		break;
+	}
+	case ACB_ADAPTER_TYPE_C: {
+		if (acb->acb_flags & ACB_F_BUS_RESET) {
+			long timeout;
+			pr_err("arcmsr: there is an bus "
+			"reset eh proceeding.......\n");
+			timeout = wait_event_timeout(wait_q,
+			(acb->acb_flags & ACB_F_BUS_RESET) == 0,
+			220 * HZ);
+			if (timeout) {
+				return SUCCESS;
 			}
-			break;
 		}
-		case ACB_ADAPTER_TYPE_C:{
-			if (acb->acb_flags & ACB_F_BUS_RESET) {
-				long timeout;
-				printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n");
-				timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
-				if (timeout) {
-					return SUCCESS;
+		acb->acb_flags |= ACB_F_BUS_RESET;
+		if (!arcmsr_iop_reset(acb)) {
+			struct MessageUnit_C __iomem *reg;
+			reg = acb->pmuC;
+			arcmsr_hardware_reset(acb);
+			acb->acb_flags &= ~ACB_F_IOP_INITED;
+sleep:
+			ssleep(ARCMSR_SLEEPTIME);
+			if ((readl(&reg->host_diagnostic) & 0x04) != 0) {
+				pr_err("arcmsr%d: waiting "
+				"for hw bus reset return, retry = %d\n",
+				acb->host->host_no, retry_count);
+				if (retry_count > ARCMSR_RETRYCOUNT) {
+					acb->fw_flag = FW_DEADLOCK;
+					pr_err("arcmsr%d: "
+					"waiting for hw bus reset return, "
+					"RETRY TERMINATED!!\n",
+					acb->host->host_no);
+					return FAILED;
 				}
+				retry_count++;
+				goto sleep;
 			}
-			acb->acb_flags |= ACB_F_BUS_RESET;
-			if (!arcmsr_iop_reset(acb)) {
-				struct MessageUnit_C __iomem *reg;
-				reg = acb->pmuC;
-				arcmsr_hardware_reset(acb);
-				acb->acb_flags &= ~ACB_F_IOP_INITED;
-sleep:
-				ssleep(ARCMSR_SLEEPTIME);
-				if ((readl(&reg->host_diagnostic) & 0x04) != 0) {
-					printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count);
-					if (retry_count > ARCMSR_RETRYCOUNT) {
-						acb->fw_flag = FW_DEADLOCK;
-						printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no);
-						return FAILED;
-					}
-					retry_count++;
-					goto sleep;
+			acb->acb_flags |= ACB_F_IOP_INITED;
+			/* disable all outbound interrupt */
+			intmask_org =
+			arcmsr_disable_outbound_ints(acb);
+			arcmsr_get_firmware_spec(acb);
+			arcmsr_start_adapter_bgrb(acb);
+			/* clear Qbuffer if door bell ringed */
+			outbound_doorbell =
+			readl(&reg->outbound_doorbell);
+			writel(outbound_doorbell,
+				&reg->outbound_doorbell_clear);
+			writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK,
+				&reg->inbound_doorbell);
+			arcmsr_enable_outbound_ints(acb,
+				intmask_org);
+			atomic_set(&acb->rq_map_token, 16);
+			atomic_set(&acb->ante_token_value, 16);
+			acb->fw_flag = FW_NORMAL;
+			mod_timer(&acb->eternal_timer, jiffies +
+				msecs_to_jiffies(6 * HZ));
+			acb->acb_flags &= ~ACB_F_BUS_RESET;
+			rtn = SUCCESS;
+			pr_err("arcmsr: scsi bus reset "
+			"eh returns with success\n");
+		} else {
+			acb->acb_flags &= ~ACB_F_BUS_RESET;
+			atomic_set(&acb->rq_map_token, 16);
+			atomic_set(&acb->ante_token_value, 16);
+			acb->fw_flag = FW_NORMAL;
+			mod_timer(&acb->eternal_timer, jiffies +
+			msecs_to_jiffies(6 * HZ));
+			rtn = SUCCESS;
+		}
+		break;
+	}
+	case ACB_ADAPTER_TYPE_D: {
+		if (acb->acb_flags & ACB_F_BUS_RESET) {
+			long timeout;
+			pr_notice("arcmsr: there is an bus reset eh proceeding.......\n");
+			timeout = wait_event_timeout(wait_q, (acb->acb_flags
+				& ACB_F_BUS_RESET) == 0, 220 * HZ);
+			if (timeout)
+				return SUCCESS;
+		}
+		acb->acb_flags |= ACB_F_BUS_RESET;
+		if (!arcmsr_iop_reset(acb)) {
+			struct MessageUnit_D __iomem *reg;
+			reg = acb->pmuD;
+			arcmsr_hardware_reset(acb);
+			acb->acb_flags &= ~ACB_F_IOP_INITED;
+			nap:
+			ssleep(ARCMSR_SLEEPTIME);
+			if ((readl(reg->sample_at_reset) & 0x80) != 0) {
+				pr_err("arcmsr%d: waiting for "
+				"hw bus reset return, retry=%d\n",
+				acb->host->host_no, retry_count);
+				if (retry_count > ARCMSR_RETRYCOUNT) {
+					acb->fw_flag = FW_DEADLOCK;
+					pr_err("arcmsr%d: "
+					"waiting for hw bus reset return, "
+					"RETRY TERMINATED!!\n",
+					acb->host->host_no);
+					return FAILED;
 				}
-				acb->acb_flags |= ACB_F_IOP_INITED;
-				/* disable all outbound interrupt */
-				intmask_org = arcmsr_disable_outbound_ints(acb);
-				arcmsr_get_firmware_spec(acb);
-				arcmsr_start_adapter_bgrb(acb);
-				/* clear Qbuffer if door bell ringed */
-				outbound_doorbell = readl(&reg->outbound_doorbell);
-				writel(outbound_doorbell, &reg->outbound_doorbell_clear); /*clear interrupt */
-				writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
-				/* enable outbound Post Queue,outbound doorbell Interrupt */
-				arcmsr_enable_outbound_ints(acb, intmask_org);
-				atomic_set(&acb->rq_map_token, 16);
-				atomic_set(&acb->ante_token_value, 16);
-				acb->fw_flag = FW_NORMAL;
-				mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
-				acb->acb_flags &= ~ACB_F_BUS_RESET;
-				rtn = SUCCESS;
-				printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n");
-			} else {
-				acb->acb_flags &= ~ACB_F_BUS_RESET;
-				atomic_set(&acb->rq_map_token, 16);
-				atomic_set(&acb->ante_token_value, 16);
-				acb->fw_flag = FW_NORMAL;
-				mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
-				rtn = SUCCESS;
+				retry_count++;
+				goto nap;
 			}
-			break;
+			acb->acb_flags |= ACB_F_IOP_INITED;
+			/* disable all outbound interrupt */
+			intmask_org = arcmsr_disable_outbound_ints(acb);
+			arcmsr_get_firmware_spec(acb);
+			arcmsr_start_adapter_bgrb(acb);
+			arcmsr_clear_doorbell_queue_buffer(acb);
+			arcmsr_enable_outbound_ints(acb, intmask_org);
+			atomic_set(&acb->rq_map_token, 16);
+			atomic_set(&acb->ante_token_value, 16);
+			acb->fw_flag = FW_NORMAL;
+			mod_timer(&acb->eternal_timer,
+				jiffies + msecs_to_jiffies(6 * HZ));
+			acb->acb_flags &= ~ACB_F_BUS_RESET;
+			rtn = SUCCESS;
+			pr_err("arcmsr: scsi bus reset "
+			"eh returns with success\n");
+		} else {
+			acb->acb_flags &= ~ACB_F_BUS_RESET;
+			atomic_set(&acb->rq_map_token, 16);
+			atomic_set(&acb->ante_token_value, 16);
+			acb->fw_flag = FW_NORMAL;
+			mod_timer(&acb->eternal_timer,
+				jiffies + msecs_to_jiffies(6 * HZ));
+			rtn = SUCCESS;
 		}
+		break;
+	}
 	}
 	return rtn;
 }
 
-static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
+static int
+arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
 		struct CommandControlBlock *ccb)
 {
 	int rtn;
@@ -3051,15 +4832,17 @@ static int arcmsr_abort_one_cmd(struct A
 	return rtn;
 }
 
-static int arcmsr_abort(struct scsi_cmnd *cmd)
+static int
+arcmsr_abort(struct scsi_cmnd *cmd)
 {
-	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *)cmd->device->host->hostdata;
+	struct AdapterControlBlock *acb = (struct AdapterControlBlock *)
+		cmd->device->host->hostdata;
 	int i = 0;
 	int rtn = FAILED;
-	printk(KERN_NOTICE
-		"arcmsr%d: abort device command of scsi id = %d lun = %d \n",
-		acb->host->host_no, cmd->device->id, cmd->device->lun);
+	pr_notice("arcmsr%d: abort device command of "
+		"scsi id = %d lun = %d\n",
+		acb->host->host_no,
+		cmd->device->id, cmd->device->lun);
 	acb->acb_flags |= ACB_F_ABORT;
 	acb->num_aborts++;
 	/*
@@ -3073,7 +4856,8 @@ static int arcmsr_abort(struct scsi_cmnd
 
 	for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
 		struct CommandControlBlock *ccb = acb->pccb_pool[i];
-		if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {
+		if (ccb->startdone == ARCMSR_CCB_START &&
+			ccb->pcmd == cmd) {
 			ccb->startdone = ARCMSR_CCB_ABORTED;
 			rtn = arcmsr_abort_one_cmd(acb, ccb);
 			break;
@@ -3083,10 +4867,11 @@ static int arcmsr_abort(struct scsi_cmnd
 	return rtn;
 }
 
-static const char *arcmsr_info(struct Scsi_Host *host)
+static const char
+*arcmsr_info(struct Scsi_Host *host)
 {
 	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
+	(struct AdapterControlBlock *)host->hostdata;
 	static char buf[256];
 	char *type;
 	int raid6 = 1;
@@ -3102,6 +4887,7 @@ static const char *arcmsr_info(struct Sc
 	case PCI_DEVICE_ID_ARECA_1160:
 	case PCI_DEVICE_ID_ARECA_1170:
 	case PCI_DEVICE_ID_ARECA_1201:
+	case PCI_DEVICE_ID_ARECA_1214:
 	case PCI_DEVICE_ID_ARECA_1220:
 	case PCI_DEVICE_ID_ARECA_1230:
 	case PCI_DEVICE_ID_ARECA_1260:
@@ -3109,8 +4895,6 @@ static const char *arcmsr_info(struct Sc
 	case PCI_DEVICE_ID_ARECA_1280:
 		type = "SATA";
 		break;
-	case PCI_DEVICE_ID_ARECA_1380:
-	case PCI_DEVICE_ID_ARECA_1381:
 	case PCI_DEVICE_ID_ARECA_1680:
 	case PCI_DEVICE_ID_ARECA_1681:
 	case PCI_DEVICE_ID_ARECA_1880:
@@ -3125,3 +4909,4 @@ static const char *arcmsr_info(struct Sc
 			ARCMSR_DRIVER_VERSION);
 	return buf;
 }
+

^ permalink raw reply	[flat|nested] 4+ messages in thread
* [PATCH 1/3] arcmsr: Support Areca new SATA Raid Adapter ARC1214/1224/1264/1284
@ 2013-08-26  4:12 黃清隆
  0 siblings, 0 replies; 4+ messages in thread
From: 黃清隆 @ 2013-08-26  4:12 UTC (permalink / raw)
  To: james.bottomley, linux-scsi, linux-kernel; +Cc: billion

From: Ching <ching2048@areca.com.tw>


Support Areca new SATA Raid adapter ARC1214/1224/1264/1284.
Modify maximum outstanding command number, notify command complete with auto 
request sense
Signed-off-by: Ching  <ching2048@areca.com.tw>


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2013-08-26 12:21 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-08-26  4:14 [PATCH 1/3] arcmsr: Support Areca new SATA Raid Adapter ARC1214/1224/1264/1284 黃清隆
2013-08-26 10:18 ` James Bottomley
2013-08-26 12:20 ` Tomas Henzl
  -- strict thread matches above, loose matches on Subject: below --
2013-08-26  4:12 黃清隆

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox