[PATCH 3/3 ] SCSI: Support Type C RAID controller

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



1. To support Type C RAID controller, ACB_ADAPTER_TYPE_C, i.e. PCI device
ID: 0x1880.
Signed-off-by: Nick Cheng< nick.cheng@xxxxxxxxxxxx >
---
diff -Naurp --ignore-blank-lines --ignore-all-space --ignore-space-change
arcmsr.1.20.00.15-91209/arcmsr.h arcmsr.1.20.00.15-100202/arcmsr.h
--- arcmsr.1.20.00.15-91209/arcmsr.h	2010-02-01 12:41:34.000000000 +0800
+++ arcmsr.1.20.00.15-100202/arcmsr.h	2010-04-02 12:55:27.000000000 +0800
@@ -48,7 +47,7 @@ struct device_attribute;
 /*The limit of outstanding scsi command that firmware can handle*/
 #define ARCMSR_MAX_OUTSTANDING_CMD
256
 #define ARCMSR_MAX_FREECCB_NUM
320
-#define ARCMSR_DRIVER_VERSION		     "Driver Version 1.20.00.15
2009/12/09"
+#define ARCMSR_DRIVER_VERSION		     "Driver Version 1.20.00.15
2010/02/02"
 #define ARCMSR_SCSI_INITIATOR_ID
255
 #define ARCMSR_MAX_XFER_SECTORS
512
 #define ARCMSR_MAX_XFER_SECTORS_B
4096
@@ -61,6 +60,7 @@ struct device_attribute;
 #define ARCMSR_MAX_HBB_POSTQUEUE
264
 #define ARCMSR_MAX_XFER_LEN
0x26000 /* 152K */
 #define ARCMSR_CDB_SG_PAGE_LENGTH
256 
+#define SCSI_CMD_ARECA_SPECIFIC
0xE1
 #ifndef PCI_DEVICE_ID_ARECA_1880
 #define PCI_DEVICE_ID_ARECA_1880 0x1880
  #endif
@@ -223,11 +223,15 @@ struct FIRMWARE_INFO
 #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                    0x10000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE0              0x10000000
+#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE1              0x00000001
 /* outbound firmware ok */
 #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK             0x80000000
 /* ARC-1680 Bus Reset*/
 #define ARCMSR_ARC1680_BUS_RESET				0x00000003
+/* ARC-1880 Bus Reset*/
+#define ARCMSR_ARC1880_RESET_ADAPTER				0x00000024
+#define ARCMSR_ARC1880_DiagWrite_ENABLE			0x00000080
 
 /*
 ************************************************************************
@@ -285,6 +289,61 @@ struct FIRMWARE_INFO
 /* iop message_rwbuffer for message command */
 #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
+/* 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 */
+/* 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).
+        */
+#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.
+        */
+#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.
+        */
+#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
+/*inbound message 0 ready*/
+#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
+/*outbound DATA WRITE isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR	0x00000002
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK			0x00000004
+/*outbound DATA READ isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_DOORBELL_CLEAR	0x00000004
+/*outbound message 0 ready*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE		0x00000008
+/*outbound message cmd isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR	0x00000008
+/*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/
+#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK			0x80000000
+/*
 
****************************************************************************
***
 **    ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
 
****************************************************************************
***
@@ -321,7 +380,7 @@ struct ARCMSR_CDB
 		struct SG32ENTRY                sg32entry[1];
 		struct SG64ENTRY                sg64entry[1];
 	} u;
-}__attribute__ ((packed));
+};
 /*
 
****************************************************************************
***
 **     Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and
Type B processor
@@ -367,7 +426,82 @@ struct MessageUnit_B
 	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*/
+};
 /*
 
****************************************************************************
***
 **                 Adapter Control Block
@@ -385,11 +519,14 @@ struct AdapterControlBlock
 	unsigned long			vir2phy_offset;
 	/* 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;
 	union {
 		struct MessageUnit_A __iomem *	pmuA;
 		struct MessageUnit_B *		pmuB;
+		struct MessageUnit_C __iomem *pmuC;
 	};
 	/* message unit ATU inbound base address0 */
 	void __iomem *mem_base0;
@@ -410,6 +547,8 @@ struct AdapterControlBlock
 	/* 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_IOP_INITED              	0x0100
 	/* iop init */
 	#define ACB_F_ABORT				0x0200
@@ -476,7 +615,8 @@ struct CommandControlBlock
 	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			shifted_cdb_phyaddr;
/*x32: 4byte, x64: 4byte*/
+	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
@@ -490,10 +630,10 @@ struct CommandControlBlock
 	#define			ARCMSR_CCB_ILLEGAL		0xFFFF
 	#if BITS_PER_LONG == 64
 	/*  ======================512+64 bytes========================  */
-		uint32_t                        	reserved[6];
/*24 byte*/
+		uint32_t                        	reserved[5];
/*24 byte*/
 	#else
 	/*  ======================512+32 bytes========================  */
-		uint32_t                        	reserved[2];
/*8  byte*/
+		uint32_t                        	reserved;
/*8  byte*/
 	#endif
 	/*  =======================================================   */
 	struct ARCMSR_CDB		arcmsr_cdb;
diff -Naurp --ignore-blank-lines --ignore-all-space --ignore-space-change
arcmsr.1.20.00.15-91209/arcmsr_hba.c arcmsr.1.20.00.15-100202/arcmsr_hba.c
--- arcmsr.1.20.00.15-91209/arcmsr_hba.c	2010-03-10
11:52:14.000000000 +0800
+++ arcmsr.1.20.00.15-100202/arcmsr_hba.c	2010-04-02
12:55:22.000000000 +0800
@@ -71,11 +71,12 @@
 #include <scsi/scsicam.h>
 #include "arcmsr.h"
 MODULE_AUTHOR("Nick Cheng <support@xxxxxxxxxxxx>");
-MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx) SATA/SAS RAID Host Bus
Adapter");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus
Adapter");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(ARCMSR_DRIVER_VERSION);
-static int sleeptime = 20;
-static int retrycount = 12;
+static int DEBUG = 1;
+static int sleeptime = 10;
+static int retrycount = 30;
 wait_queue_head_t wait_q;
 static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
 					struct scsi_cmnd *cmd);
@@ -99,10 +100,12 @@ static void arcmsr_flush_hbb_cache(struc
 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_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_hardware_reset(struct AdapterControlBlock *acb);
 static const char *arcmsr_info(struct Scsi_Host *);
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
 static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
@@ -110,13 +113,13 @@ static int arcmsr_adjust_disk_queue_dept
 {
 	if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
 		queue_depth = ARCMSR_MAX_CMD_PERLUN;
-	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), queue_depth);
 	return queue_depth;
 }
 
 static struct scsi_host_template arcmsr_scsi_host_template = {
 	.module			= THIS_MODULE,
-	.name			= "ARCMSR ARECA SATA/SAS RAID Host Bus
Adapter"
+	.name			= "ARCMSR ARECA SATA/SAS RAID Controller"
 				ARCMSR_DRIVER_VERSION,
 	.info			= arcmsr_info,
 	.queuecommand		= arcmsr_queue_command,
@@ -175,17 +178,40 @@ static struct pci_driver arcmsr_pci_driv
 	.err_handler		= &arcmsr_pci_error_handlers,
 	#endif
 };
+/*
+***************************************************************************
*
+***************************************************************************
*
+*/
+int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
+{
+		struct Scsi_Host *shost = NULL;
+		int i, isleep;
+		shost = cmd->device->host;
+		isleep = sleeptime / 10;
+		if (isleep > 0) {
+			for (i = 0; i < isleep; i ++) {
+				msleep(10000);
+			}
+		}
 
-static void arcmsr_free_mu(struct AdapterControlBlock *acb)
+		isleep = sleeptime % 10;
+		if (isleep > 0) {
+			msleep(isleep*1000);
+		}
+		printk("wake-up\n");
+		return 0;
+}
+
+static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
 		case ACB_ADAPTER_TYPE_A:
+		case ACB_ADAPTER_TYPE_C:
 			break;
 		case ACB_ADAPTER_TYPE_B:{
-			struct MessageUnit_B *reg = acb->pmuB;
 			dma_free_coherent(&acb->pdev->dev,
 				sizeof(struct MessageUnit_B),
-				reg, acb->dma_coherent_handle_hbb_mu);
+				acb->pmuB, acb->dma_coherent_handle_hbb_mu);
 		}
 	}
 }
@@ -218,6 +243,19 @@ static bool arcmsr_remap_pciregion(struc
 			}
 			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));
+			if (!acb->pmuC){
+				printk(KERN_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->outb
ound_doorbell_clear);/*clear interrupt*/
+				return TRUE;
+			}
+			break;
 		}
 	}
 	return true;
@@ -229,10 +267,16 @@ static void arcmsr_unmap_pciregion(struc
 		case ACB_ADAPTER_TYPE_A:{
 			iounmap(acb->pmuA);
 		}
+		break;
 		case ACB_ADAPTER_TYPE_B:{
 			iounmap(acb->mem_base0);
 			iounmap(acb->mem_base1);
 		}
+
+		break;
+		case ACB_ADAPTER_TYPE_C:{
+			iounmap(acb->pmuC);
+		}
 	}
 }
 
@@ -280,6 +324,10 @@ static void arcmsr_define_adapter_type(s
 	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 : {
 		acb->adapter_type = ACB_ADAPTER_TYPE_B;
 		}
@@ -301,13 +348,13 @@ static uint8_t arcmsr_hba_wait_msgint_re
 					ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
 				writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
 					&reg->outbound_intstatus);
-				return 0x00;
+				return TRUE;
 			}
 			msleep(10);
 		}/*max 1 seconds*/
 
 	} while (Retries++ < 20);/*max 20 sec*/
-	return 0xff;
+	return FALSE;
 }
 
 static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock
*acb)
@@ -323,15 +369,32 @@ static uint8_t arcmsr_hbb_wait_msgint_re
 				writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
 					, reg->iop2drv_doorbell);
 				writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT,
reg->drv2iop_doorbell);
-				return 0x00;
+				return TRUE;
 			}
 			msleep(10);
 		}/*max 1 seconds*/
 
 	} while (Retries++ < 20);/*max 20 sec*/
-	return 0xff;
+	return FALSE;
 }
 
+static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock
*pACB)
+{
+	struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+	unsigned char Retries = 0x00;
+	uint32_t Index;
+	do{
+		for(Index= 0; Index < 100; Index++){
+			if(readl(&phbcmu->outbound_doorbell) &
ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE){
+
writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR,&phbcmu->outboun
d_doorbell_clear);/*clear interrupt*/
+				return TRUE;
+			}
+			/* one us delay	*/
+			msleep(10);
+		}/*max 1 seconds*/
+	}while(Retries++ < 20);/*max 20 sec*/
+	return FALSE;
+}
 static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
@@ -336,10 +399,9 @@ static void arcmsr_flush_hba_cache(struc
 {
 	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_hba_wait_msgint_ready(acb))
 			break;
 		else {
 			retry_count--;
@@ -353,10 +415,9 @@ static void arcmsr_flush_hbb_cache(struc
 {
 	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_hbb_wait_msgint_ready(acb))
 			break;
 		else {
 			retry_count--;
@@ -366,6 +427,23 @@ static void arcmsr_flush_hbb_cache(struc
 	} while (retry_count != 0);
 }
 
+static void arcmsr_flush_hbc_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);
+	do{
+		if(arcmsr_hbc_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);
+		}
+	}while(retry_count!=0);
+	return;
+}
 static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
@@ -378,21 +456,22 @@ static void arcmsr_flush_adapter_cache(s
 	case ACB_ADAPTER_TYPE_B: {
 		arcmsr_flush_hbb_cache(acb);
 		}
+		break;
+	case ACB_ADAPTER_TYPE_C: {
+		arcmsr_flush_hbc_cache(acb);
+		}
 	}
 }
 
 static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 {
 	struct pci_dev *pdev = acb->pdev;
-	switch (acb->adapter_type) {
-		case ACB_ADAPTER_TYPE_A: {
-
 			void *dma_coherent;
 			dma_addr_t dma_coherent_handle;
 			struct CommandControlBlock *ccb_tmp;
 			int i = 0, j = 0;
 			dma_addr_t cdb_phyaddr;
-			unsigned long roundup_ccbsize = 0;
+	unsigned long roundup_ccbsize = 0, offset;
 			unsigned long max_xfer_len;
 			unsigned long max_sg_entrys;
 			uint32_t  firm_config_version;
@@ -405,26 +483,29 @@ static int arcmsr_alloc_ccb_pool(struct 
 			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 16M byte */
+		max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH <<
((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */
 				max_sg_entrys = (max_xfer_len/4096);	
 			}
 			acb->host->max_sectors = max_xfer_len/512;
 			acb->host->sg_tablesize = max_sg_entrys;
-			roundup_ccbsize = roundup(sizeof(struct
CommandControlBlock) + max_sg_entrys * sizeof(struct SG64ENTRY), 32);
-			acb->uncache_size = roundup_ccbsize *
ARCMSR_MAX_FREECCB_NUM;
+	roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) +
(max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+	acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32;
 			dma_coherent = dma_alloc_coherent(&pdev->dev,
acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
 			if (!dma_coherent) {
 				printk("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;
+	memset(dma_coherent, 0, acb->uncache_size);
+	offset = roundup((unsigned long)dma_coherent, 32) - (unsigned
long)dma_coherent;
+	dma_coherent_handle = dma_coherent_handle + offset;
+	dma_coherent = (struct CommandControlBlock *)dma_coherent + offset;
+	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->shifted_cdb_phyaddr = cdb_phyaddr
>> 5;
+		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);
@@ -432,68 +513,9 @@ static int arcmsr_alloc_ccb_pool(struct 
 				ccb_tmp = (struct CommandControlBlock
*)((unsigned long)ccb_tmp + roundup_ccbsize);
 				dma_coherent_handle = dma_coherent_handle +
roundup_ccbsize;
 			}
-			break;
-		}
-		case ACB_ADAPTER_TYPE_B: {
-
-			void *dma_coherent;
-			dma_addr_t dma_coherent_handle;
-			struct CommandControlBlock *ccb_tmp;
-			uint32_t cdb_phyaddr;
-			unsigned int roundup_ccbsize = 0;
-			unsigned long max_xfer_len;
-			unsigned long max_sg_entrys;
-			unsigned long firm_config_version;
-			unsigned long max_freeccb_num=0;
-			int i = 0, j = 0;
-
-			max_freeccb_num = ARCMSR_MAX_FREECCB_NUM;
-			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 16M byte */
-				max_sg_entrys = (max_xfer_len/4096);/* max
4097 sg entry*/
-			}
-			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 "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->shifted_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;
-		}
-		break;
-	}
 	return 0;
 }
+
 static void arcmsr_message_isr_bh_fn(struct work_struct *work) 
 {
 	struct AdapterControlBlock *acb = container_of(work,struct
AdapterControlBlock, arcmsr_do_message_isr_bh);
@@ -573,6 +595,43 @@ static void arcmsr_message_isr_bh_fn(str
 				}
 			}
 		}
+		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++;
+				}
+			}
+		}
 	}
 }
 
@@ -591,9 +649,9 @@ static int arcmsr_probe(struct pci_dev *
 	if(!host){
     		goto pci_disable_dev;
 	}
-	error = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+	error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
 	if(error){
-		error = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
 		if(error){
 			printk(KERN_WARNING
 			       "scsi%d: No suitable DMA mask available\n",
@@ -675,7 +733,7 @@ static int arcmsr_probe(struct pci_dev *
 		arcmsr_flush_adapter_cache(acb);
 		arcmsr_free_ccb_pool(acb);
 	free_hbb_mu:
-		arcmsr_free_mu(acb);
+		arcmsr_free_hbb_mu(acb);
 	unmap_pci_region:
 		arcmsr_unmap_pciregion(acb);
 	pci_release_regs:
@@ -690,15 +748,14 @@ static int arcmsr_probe(struct pci_dev *
 static uint8_t arcmsr_abort_hba_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)){
+	if (!arcmsr_hba_wait_msgint_ready(acb)){
 		printk(KERN_NOTICE
 			"arcmsr%d: wait 'abort all outstanding command'
timeout \n"
 			, acb->host->host_no);
-		return 0xff;
+		return FALSE;
 	}
-	return 0x00;
+	return TRUE;
 }
 
 static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
@@ -706,15 +763,27 @@ static uint8_t arcmsr_abort_hbb_allcmd(s
 	struct MessageUnit_B *reg = acb->pmuB;
 
 	writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
-	if (arcmsr_hbb_wait_msgint_ready(acb)) {
+	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE
 			"arcmsr%d: wait 'abort all outstanding command'
timeout \n"
 			, acb->host->host_no);
-		return 0xff;
+		return FALSE;
 	}
-	return 0x00;
+	return TRUE;
+}
+static uint8_t arcmsr_abort_hbc_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);
+		return FALSE;
+	}
+	return TRUE;
 }
-
 static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
 {
 	uint8_t rtnval = 0;
@@ -727,6 +796,11 @@ static uint8_t arcmsr_abort_allcmd(struc
 	case ACB_ADAPTER_TYPE_B: {
 		rtnval = arcmsr_abort_hbb_allcmd(acb);
 		}
+		break;
+		
+	case ACB_ADAPTER_TYPE_C: {
+		rtnval = arcmsr_abort_hbc_allcmd(acb);
+		}	
 	}
 	return rtnval;
 }
@@ -734,9 +808,8 @@ static uint8_t arcmsr_abort_allcmd(struc
 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)){
+	if(!arcmsr_hbb_wait_msgint_ready(pacb)){
 		printk(KERN_ERR "arcmsr%d: can't set driver mode. \n",
pacb->host->host_no);
 		return false;
 	}
@@ -759,7 +831,6 @@ static void arcmsr_ccb_complete(struct C
 	atomic_dec(&acb->ccboutstandingcount);
 	arcmsr_pci_unmap_dma(ccb);
 	ccb->startdone = ARCMSR_CCB_DONE;
-	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);
@@ -803,14 +871,20 @@ 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;
+		/* 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);
+		}
+		break;
 	}
 	return orig_mask;
 }
 
 static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, 
-			struct CommandControlBlock *ccb, uint32_t flag_ccb)
+			struct CommandControlBlock *ccb, bool error)
 {
-
 	uint8_t id, lun;
 	id = ccb->pcmd->device->id;
 	lun = ccb->pcmd->device->lun;
@@ -814,7 +888,7 @@ static void arcmsr_report_ccb_state(stru
 	uint8_t id, lun;
 	id = ccb->pcmd->device->id;
 	lun = ccb->pcmd->device->lun;
-	if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+	if (!error) {
 		if (acb->devstate[id][lun] == ARECA_RAID_GONE)
 			acb->devstate[id][lun] = ARECA_RAID_GOOD;
 			ccb->pcmd->result = DID_OK << 16;
@@ -846,9 +920,8 @@ static void arcmsr_report_ccb_state(stru
 
 		default:
 				printk(KERN_NOTICE
-					"arcmsr%d: scsi id = %d lun = %d"
-					" isr get command error done, "
-					"but got unknown DeviceStatus = 0x%x
\n"
+				"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
@@ -861,25 +934,20 @@ static void arcmsr_report_ccb_state(stru
 	}
 }
 
-static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb,
uint32_t flag_ccb)
+static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct
CommandControlBlock *pCCB, bool error)
 
 {
-	struct CommandControlBlock *ccb;
-	struct ARCMSR_CDB *arcmsr_cdb;
 	int id, lun;
-
-	arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb
<< 5));
-	ccb = container_of(arcmsr_cdb, struct CommandControlBlock,
arcmsr_cdb);
-	if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
-		if (ccb->startdone == ARCMSR_CCB_ABORTED) {
-			struct scsi_cmnd *abortcmd = ccb->pcmd;
+	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(ccb);
-				printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
-				isr got aborted command \n",
acb->host->host_no, ccb);
+				arcmsr_ccb_complete(pCCB);
+				printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p'
isr got aborted command \n",
+				acb->host->host_no, pCCB);
 			}
 		}
 		printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command
\
@@ -888,20 +956,21 @@ static void arcmsr_drain_donequeue(struc
 				" ccboutstandingcount = %d \n"
 				, acb->host->host_no
 				, acb
-				, ccb
-				, ccb->acb
-				, ccb->startdone
+				, pCCB
+				, pCCB->acb
+				, pCCB->startdone
 				, atomic_read(&acb->ccboutstandingcount));
 		}
-	else
-	arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+	arcmsr_report_ccb_state(acb, pCCB, error);
 }
 
 static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
 {
 	int i = 0;
 	uint32_t flag_ccb;
-
+	struct ARCMSR_CDB *pARCMSR_CDB;
+	bool error;
+	struct CommandControlBlock *pCCB;
 	switch (acb->adapter_type) {
 
 	case ACB_ADAPTER_TYPE_A: {
@@ -913,7 +982,10 @@ static void arcmsr_done4abort_postqueue(
 		writel(outbound_intstatus, &reg->outbound_intstatus);/*clear
interrupt*/
 		while (((flag_ccb = readl(&reg->outbound_queueport)) !=
0xFFFFFFFF)
 				&& (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
-			arcmsr_drain_donequeue(acb, flag_ccb);
+			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;
+			arcmsr_drain_donequeue(acb, pCCB, error);
 		}
 		}
 		break;
@@ -921,17 +993,37 @@ 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 */
 		for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
 			if ((flag_ccb = readl(&reg->done_qbuffer[i])) != 0)
{
 				writel(0, &reg->done_qbuffer[i]);
-				arcmsr_drain_donequeue(acb, flag_ccb);
+				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;
+				arcmsr_drain_donequeue(acb, pCCB, error);
 			}
-			writel(0, &reg->post_qbuffer[i]);
+			reg->post_qbuffer[i]=0;
 		}
 		reg->doneq_index = 0;
 		reg->postq_index = 0;
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *reg = acb->pmuC;
+		struct  ARCMSR_CDB *pARCMSR_CDB;
+		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)){
+			/*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;
+			arcmsr_drain_donequeue(acb, pCCB, error);
+		}		
+	}
 	}
 }
 static void arcmsr_remove(struct pci_dev *pdev)
@@ -942,7 +1034,6 @@ static void arcmsr_remove(struct pci_dev
 	int poll_count = 0;
 	arcmsr_free_sysfs_attr(acb);
 	scsi_remove_host(host);
-	scsi_host_put(host);
 	flush_scheduled_work();
 	del_timer_sync(&acb->eternal_timer);
 	arcmsr_disable_outbound_ints(acb);
@@ -974,8 +1065,10 @@ static void arcmsr_remove(struct pci_dev
 	}
 	free_irq(pdev->irq, acb);
 	arcmsr_free_ccb_pool(acb);
-	arcmsr_free_mu(acb);
+	arcmsr_free_hbb_mu(acb);
+	arcmsr_unmap_pciregion(acb);
 	pci_release_regions(pdev);
+	scsi_host_put(host);
 	pci_disable_device(pdev);
 	pci_set_drvdata(pdev, NULL);
 }
@@ -1033,6 +1124,13 @@ static void arcmsr_enable_outbound_ints(
 		writel(mask, reg->iop2drv_doorbell_mask);
 		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);
+		writel(intmask_org & mask, &reg->host_int_mask);
+		acb->outbound_int_enable = ~(intmask_org & mask) &
0x0000000f;
+		}	
 	}
 }
 
@@ -1044,24 +1142,20 @@ static int arcmsr_build_ccb(struct Adapt
 	__le32 address_lo, address_hi;
 	int arccdbsize = 0x30;
 	__le32 length = 0;
-	int i, cdb_sgcount = 0;
+	int i;
 	struct scatterlist *sg;
 	int nseg;
-
 	ccb->pcmd = pcmd;
 	memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
-	arcmsr_cdb->Bus = 0;
 	arcmsr_cdb->TargetID = pcmd->device->id;
 	arcmsr_cdb->LUN = pcmd->device->lun;
 	arcmsr_cdb->Function = 1;
-	arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
 	arcmsr_cdb->Context = 0;
 	memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
 
 	nseg = scsi_dma_map(pcmd);
-	if(nseg > acb->host->sg_tablesize || nseg < 0)
+	if(unlikely(nseg > acb->host->sg_tablesize || nseg < 0))
 		return FAILED;
-	/* map stor port SG list to our iop SG List. */
 	scsi_for_each_sg(pcmd, sg, nseg, i) {
 		/* Get the physical address of the current data pointer */
 		length = cpu_to_le32(sg_dma_len(sg));
@@ -1083,23 +1177,22 @@ static int arcmsr_build_ccb(struct Adapt
 			psge += sizeof (struct SG64ENTRY);
 			arccdbsize += sizeof (struct SG64ENTRY);
 		}
-		cdb_sgcount++;
 	}
-	arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
+	arcmsr_cdb->sgcount = (uint8_t)nseg;
 	arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
 	arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 :
0);
 	if ( arccdbsize > 256)
 		arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
 	if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0]|WRITE_10 ||
pcmd->cmnd[0]|WRITE_12 ){
 		arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
-		ccb->ccb_flags |= CCB_FLAG_WRITE;
 	}
+	ccb->arc_cdb_size = arccdbsize;
 	return SUCCESS;
 }
 
 static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct
CommandControlBlock *ccb)
 {
-	uint32_t shifted_cdb_phyaddr = ccb->shifted_cdb_phyaddr;
+	uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern;
 	struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB
*)&ccb->arcmsr_cdb;
 	atomic_inc(&acb->ccboutstandingcount);
 	ccb->startdone = ARCMSR_CCB_START;
@@ -1109,10 +1201,10 @@ static void arcmsr_post_ccb(struct Adapt
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 
 		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
-			writel(shifted_cdb_phyaddr |
ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+			writel(cdb_phyaddr_pattern |
ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
 			&reg->inbound_queueport);
 		else {
-				writel(shifted_cdb_phyaddr,
&reg->inbound_queueport);
+				writel(cdb_phyaddr_pattern,
&reg->inbound_queueport);
 		}
 		}
 		break;
@@ -1124,11 +1216,10 @@ static void arcmsr_post_ccb(struct Adapt
 		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(shifted_cdb_phyaddr |
ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
+			writel(cdb_phyaddr_pattern |
ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\
 						 &reg->post_qbuffer[index]);
-		}
-		else {
-			writel(shifted_cdb_phyaddr,
&reg->post_qbuffer[index]);
+		}else{
+			writel(cdb_phyaddr_pattern,
&reg->post_qbuffer[index]);
 		}
 		index++;
 		index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set
it to 0 */
@@ -1136,6 +1227,19 @@ static void arcmsr_post_ccb(struct Adapt
 		writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		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);
+		if(acb->cdb_phyaddr_hi32){
+			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);
+		}
+		}
 	}
 }
 
@@ -1144,8 +1248,7 @@ static void arcmsr_stop_hba_bgrb(struct 
 	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)) {
+	if (!arcmsr_hba_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE
 			"arcmsr%d: wait 'stop adapter background rebulid'
timeout \n"
 			, acb->host->host_no);
@@ -1158,13 +1261,26 @@ static void arcmsr_stop_hbb_bgrb(struct 
 	acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
 	writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
 
-	if (arcmsr_hbb_wait_msgint_ready(acb)) {
+	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE
 			"arcmsr%d: wait 'stop adapter background rebulid'
timeout \n"
 			, acb->host->host_no);
 	}
 }
 
+static void arcmsr_stop_hbc_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);
+	}
+	return;
+}
 static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
@@ -1177,22 +1293,16 @@ static void arcmsr_stop_adapter_bgrb(str
 		arcmsr_stop_hbb_bgrb(acb);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		arcmsr_stop_hbc_bgrb(acb);
+		}		
 	}
 }
 
 static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
 {
-	switch (acb->adapter_type) {
-	case ACB_ADAPTER_TYPE_A: {
-		dma_free_coherent(&acb->pdev->dev, acb->uncache_size,
acb->dma_coherent, acb->dma_coherent_handle);
-		iounmap(acb->pmuA);
-	}
-		break;
-	case ACB_ADAPTER_TYPE_B: {
 		dma_free_coherent(&acb->pdev->dev, acb->uncache_size,
acb->dma_coherent, acb->dma_coherent_handle);
 	}
-	}
-}
 
 void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
 {
@@ -1208,6 +1318,10 @@ void arcmsr_iop_message_read(struct Adap
 		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);
+		}
 	}
 }
 
@@ -1233,6 +1347,15 @@ static void arcmsr_iop_message_wrote(str
 		writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C __iomem *reg = acb->pmuC;
+		/*
+		** 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);
+		}
+		break;		
 	}
 }
 
@@ -1253,6 +1375,10 @@ struct QBUFFER __iomem *arcmsr_get_iop_r
 		qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *phbcmu=(struct MessageUnit_C
*)acb->pmuC;
+		qbuffer = (struct QBUFFER __iomem
*)&phbcmu->message_rbuffer;
+		}	
 	}
 	return qbuffer;
 }
@@ -1274,6 +1399,11 @@ static struct QBUFFER __iomem *arcmsr_ge
 		pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		struct MessageUnit_C *reg=(struct MessageUnit_C *)acb->pmuC;
+		pqbuffer = (struct QBUFFER __iomem *)&reg->message_wbuffer;
+        }
+
 	}
 	return pqbuffer;
 }
@@ -1358,14 +1486,42 @@ static void arcmsr_hba_doorbell_isr(stru
 		arcmsr_iop2drv_data_read_handle(acb);
 	}
 }
-
+static void arcmsr_hbc_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
+	*******************************************************************
+	*/
+	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" */
+	}
+	return;
+}
 static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb)
 {
 	uint32_t flag_ccb;
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
-
+	struct ARCMSR_CDB *pARCMSR_CDB;
+	struct CommandControlBlock *pCCB;
+	bool error;
 	while ((flag_ccb = readl(&reg->outbound_queueport)) != 0xFFFFFFFF) {
-		arcmsr_drain_donequeue(acb, flag_ccb);
+		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;
+		arcmsr_drain_donequeue(acb, pCCB, error);
 	}
 }
 
@@ -1374,17 +1530,51 @@ static void arcmsr_hbb_postqueue_isr(str
 	uint32_t index;
 	uint32_t flag_ccb;
 	struct MessageUnit_B *reg = acb->pmuB;
-
+	struct ARCMSR_CDB *pARCMSR_CDB;
+	struct CommandControlBlock *pCCB;
+	bool error;
 	index = reg->doneq_index;
-
 	while ((flag_ccb = readl(&reg->done_qbuffer[index])) != 0) {
 		writel(0, &reg->done_qbuffer[index]);
-		arcmsr_drain_donequeue(acb, flag_ccb);
+		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;		
+		arcmsr_drain_donequeue(acb, pCCB, error);
 		index++;
 		index %= ARCMSR_MAX_HBB_POSTQUEUE;
 		reg->doneq_index = index;
 	}
 }
+
+static void arcmsr_hbc_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;
+
+	phbcmu = (struct MessageUnit_C *)acb->pmuC;
+	/* areca cdb command done */
+	/* Use correct offset and size for syncing */
+
+	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++;
+	}
+}
 /*
 
****************************************************************************
******
 ** Handle a message interrupt
@@ -1408,6 +1598,23 @@ 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)
+{
+	struct MessageUnit_C *reg  = acb->pmuC;
+	/*clear interrupt and message state*/
+	writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR,
&reg->outbound_doorbell_clear);
+	schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
+
 static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
 {
 	uint32_t outbound_intstatus;
@@ -1463,6 +1668,31 @@ static int arcmsr_handle_hbb_isr(struct 
 
 	return 0;
 }
+
+static int arcmsr_handle_hbc_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 FALSE;
+	}
+	/* 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 TRUE;
+}
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
@@ -1479,6 +1709,11 @@ static irqreturn_t arcmsr_interrupt(stru
 		}
 		}
 		break;
+	 case ACB_ADAPTER_TYPE_C: {
+		if(arcmsr_handle_hbc_isr(acb)) {
+			return IRQ_NONE;
+		}
+        		}
 	}
 	return IRQ_HANDLED;
 }
@@ -1890,7 +2120,10 @@ static int arcmsr_queue_command(struct s
 	if (atomic_read(&acb->ccboutstandingcount) >=
 			ARCMSR_MAX_OUTSTANDING_CMD)
 		return SCSI_MLQUEUE_HOST_BUSY;
-
+	if((scsicmd == SCSI_CMD_ARECA_SPECIFIC)){
+		printk("Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n");
+		return 0;
+	}
 	ccb = arcmsr_get_freeccb(acb);
 	if (!ccb)
 		return SCSI_MLQUEUE_HOST_BUSY;
@@ -1912,9 +2145,8 @@ static bool arcmsr_get_hba_config(struct
 	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)) {
+	if (!arcmsr_hba_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
 			miscellaneous data' timeout \n",
acb->host->host_no);
 		return false;
@@ -1990,7 +2222,7 @@ static bool arcmsr_get_hbb_config(struct
 	iop_device_map = (char __iomem *)(&reg->message_rwbuffer[21]);
/*firm_version,21,84-99*/
 
 	writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
-	if (arcmsr_hbb_wait_msgint_ready(acb)){
+	if (!arcmsr_hbb_wait_msgint_ready(acb)){
 		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
 			miscellaneous data' timeout \n",
acb->host->host_no);
 		return false;
@@ -2037,12 +2269,73 @@ static bool arcmsr_get_hbb_config(struct
 	/*firm_ide_channels,4,16-19*/
 	return true;
 }
+
+static bool arcmsr_get_hbc_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*/
+	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 */
+	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);
+	/* 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*/
+			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);
+		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--;
+	}
+	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*/
+	/*all interrupt service will be enable at arcmsr_iop_init*/
+	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
+	else if(acb->adapter_type == ACB_ADAPTER_TYPE_B)
 		return arcmsr_get_hbb_config(acb);
+	else
+		return arcmsr_get_hbc_config(acb);	
 }
 
 static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
@@ -2053,7 +2346,7 @@ static int arcmsr_polling_hba_ccbdone(st
 	struct ARCMSR_CDB *arcmsr_cdb;
 	uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count
= 0;
 	int rtn;
-
+	bool error;
 	polling_hba_ccb_retry:
 	poll_count++;
 	outbound_intstatus = readl(&reg->outbound_intstatus) &
acb->outbound_int_enable;
@@ -2064,6 +2357,7 @@ static int arcmsr_polling_hba_ccbdone(st
 				rtn = SUCCESS;
 				break;
 			}else {
+				msleep(25);
 				if (poll_count > 100){
 					rtn = FAILED;
 					break;
@@ -2093,9 +2387,9 @@ static int arcmsr_polling_hba_ccbdone(st
 				, ccb
 				, atomic_read(&acb->ccboutstandingcount));
 			continue;
-		}else{
-			arcmsr_report_ccb_state(acb, ccb, flag_ccb);
 		}
+		error=(flag_ccb &
ARCMSR_CCBREPLY_FLAG_ERROR_MODE0)?TRUE:FALSE;
+		arcmsr_report_ccb_state(acb, ccb, error);
 	}
 	return rtn;
 }
@@ -2108,7 +2402,7 @@ static int arcmsr_polling_hbb_ccbdone(st
 	struct CommandControlBlock *ccb;
 	uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
 	int index, rtn;
-	
+	bool error;
 	polling_hbb_ccb_retry:
 	poll_count++;
 	/* clear doorbell interrupt */
@@ -2156,13 +2450,69 @@ static int arcmsr_polling_hbb_ccbdone(st
 				, ccb
 				, atomic_read(&acb->ccboutstandingcount));
 			continue;
-		}else{
-			arcmsr_report_ccb_state(acb, ccb, flag_ccb);
 		}
-	}	/*drain reply FIFO*/
+		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)
+{
+	struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+	uint32_t flag_ccb, ccb_cdb_phy;
+	struct ARCMSR_CDB *arcmsr_cdb;
+	bool error;
+	struct CommandControlBlock *pCCB;
+	uint32_t poll_ccb_done = 0, poll_count = 0;
+	int rtn;
+	polling_hbc_ccb_retry:
+	poll_count++;
+	while(1){
+		if((readl(&reg->host_int_status) &
ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0){
+			if (poll_ccb_done){
+				rtn = SUCCESS;
+				break;
+			}else {
+				msleep(25);
+				if (poll_count > 100){
+					rtn = FAILED;
+					break;
+				}
+				goto 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);
+		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->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);
+				continue;
+			}
+			printk(KERN_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_polling_ccbdone(struct AdapterControlBlock *acb,
 					struct CommandControlBlock
*poll_ccb)
 {
@@ -2177,6 +2527,10 @@ static int arcmsr_polling_ccbdone(struct
 	case ACB_ADAPTER_TYPE_B: {
 		rtn = arcmsr_polling_hbb_ccbdone(acb,poll_ccb);
 		}
+		break;
+	case ACB_ADAPTER_TYPE_C: {
+		rtn = arcmsr_polling_hbc_ccbdone(acb,poll_ccb);
+		}
 	}
 	return rtn;
 }
@@ -2194,6 +2548,7 @@ static int arcmsr_iop_confirm(struct Ada
 	dma_coherent_handle = acb->dma_coherent_handle;
 	cdb_phyaddr = (uint32_t)(dma_coherent_handle);
 	cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+	acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
 	/*
 
***********************************************************************
 	**    if adapter type B, set window of "post command Q"
@@ -2211,7 +2566,7 @@ static int arcmsr_iop_confirm(struct Ada
 			writel(cdb_phyaddr_hi32, &reg->message_rwbuffer[1]);
 			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
 
&reg->inbound_msgaddr0);
-			if (arcmsr_hba_wait_msgint_ready(acb)) {
+			if (!arcmsr_hba_wait_msgint_ready(acb)) {
 				printk(KERN_NOTICE "arcmsr%d: ""set ccb high
\
 				part physical address timeout\n",
 				acb->host->host_no);
@@ -2232,7 +2587,7 @@ static int arcmsr_iop_confirm(struct Ada
 		reg->postq_index = 0;
 		reg->doneq_index = 0;
 		writel(ARCMSR_MESSAGE_SET_POST_WINDOW,
reg->drv2iop_doorbell);
-		if (arcmsr_hbb_wait_msgint_ready(acb)) {
+		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 			printk(KERN_NOTICE "arcmsr%d:can not set diver
mode\n", \
 				acb->host->host_no);
 			return 1;
@@ -2251,7 +2606,7 @@ static int arcmsr_iop_confirm(struct Ada
 		writel(1056, rwbuffer);
 
 		writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
-		if (arcmsr_hbb_wait_msgint_ready(acb)) {
+		if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 			printk(KERN_NOTICE "arcmsr%d: 'set command Q window'
\
 			timeout \n",acb->host->host_no);
 			return 1;
@@ -2260,6 +2615,27 @@ static int arcmsr_iop_confirm(struct Ada
 		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;
+
+		                if(cdb_phyaddr_hi32!=0){
+				unsigned char Retries=0x00;
+				do{
+					printk(KERN_NOTICE "arcmsr%d:
cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32);
+				} while(Retries++ < 100);
+			}
+			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);
+				return 1;
+			}
+		}
+		}		
 	}
 	return 0;
 }
@@ -2286,6 +2661,12 @@ static void arcmsr_wait_firmware_ready(s
 		writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT,
reg->drv2iop_doorbell);
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		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);
+		}
 	}
 }
 
@@ -2328,6 +2708,26 @@ static void arcmsr_request_hbb_device_ma
 	return;
 }
 
+static void arcmsr_request_hbc_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 )){
+		return;
+	}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));
+		if(atomic_dec_and_test(&acb->rq_map_token))
+			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_request_device_map(unsigned long pacb)
 {
 	struct AdapterControlBlock *acb = (struct AdapterControlBlock
*)pacb;
@@ -2341,6 +2740,9 @@ static void arcmsr_request_device_map(un
 			arcmsr_request_hbb_device_map(acb);
 		}
 		break;
+		case ACB_ADAPTER_TYPE_C: {
+			arcmsr_request_hbc_device_map(acb);
+		}
 	}
 }
 
@@ -2349,7 +2751,7 @@ static void arcmsr_start_hba_bgrb(struct
 	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)) {
+	if (!arcmsr_hba_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background
\
 				rebulid' timeout \n", acb->host->host_no);
 	}
@@ -2360,12 +2762,24 @@ static void arcmsr_start_hbb_bgrb(struct
 	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)) {
+	if (!arcmsr_hbb_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background
\
 				rebulid' timeout \n",acb->host->host_no);
 	}
 }
 
+static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+	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_hbc_wait_msgint_ready(pACB)){
+		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background
\
+				rebulid' timeout \n",pACB->host->host_no);
+	}
+	return;
+}
 static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
 {
 	switch (acb->adapter_type) {
@@ -2375,6 +2789,8 @@ static void arcmsr_start_adapter_bgrb(st
 	case ACB_ADAPTER_TYPE_B:
 		arcmsr_start_hbb_bgrb(acb);
 		break;
+	case ACB_ADAPTER_TYPE_C:
+		arcmsr_start_hbc_bgrb(acb);
 	}
 }
 
@@ -2400,6 +2816,14 @@ static void arcmsr_clear_doorbell_queue_
 		/* let IOP know data has been read */
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C: {
+		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);
+		}
 	}
 }
 
@@ -2412,12 +2836,14 @@ static void arcmsr_enable_eoi_mode(struc
 		{
 			struct MessageUnit_B *reg = acb->pmuB;
 			writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE,
reg->drv2iop_doorbell);
-			if(arcmsr_hbb_wait_msgint_ready(acb)) {
+			if(!arcmsr_hbb_wait_msgint_ready(acb)) {
 				printk(KERN_NOTICE "ARCMSR IOP enables
EOI_MODE TIMEOUT");
 				return;
 			}
 		}
 		break;
+	case ACB_ADAPTER_TYPE_C:
+		return;
 	}
 	return;
 }
@@ -2425,21 +2851,33 @@ static void arcmsr_enable_eoi_mode(struc
 static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
 {
 	uint8_t value[64];
-	int i;	
-	struct MessageUnit_A __iomem *reg = acb->pmuA;
-
+	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_ERR "arcmsr%d: executing hw bus reset .....\n",
acb->host->host_no);
+	printk("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, &reg->reserved1[0]);
+		writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]);
+	}else if((acb->dev_id == 0x1880)){
+		do{
+			count++;
+			writel(0xF, &pmuC->write_sequence);
+			writel(0x4, &pmuC->write_sequence);
+			writel(0xB, &pmuC->write_sequence);
+			writel(0x2, &pmuC->write_sequence);
+			writel(0x7, &pmuC->write_sequence);
+			writel(0xD, &pmuC->write_sequence);
+		}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);
 	}
-	msleep(1000);
+	msleep(2000);
 	/* write back pci config data */
 	for (i=0;i<64;i++) {
 		pci_write_config_byte(acb->pdev, i, value[i]);
@@ -2447,29 +2885,6 @@ static void arcmsr_hardware_reset(struct
 	msleep(1000);
 	return;
 }
-/*
-***************************************************************************
*
-***************************************************************************
*
-*/
-int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
-{
-		struct Scsi_Host *shost = NULL;
-		int i, isleep;
-
-		shost = cmd->device->host;
-		isleep = sleeptime / 10;
-		if (isleep > 0) {
-			for (i = 0; i < isleep; i ++) {
-				msleep(10000);
-			}
-		}
-
-		isleep = sleeptime % 10;
-		if (isleep > 0) {
-			msleep(isleep*1000);
-		}
-		return 0;
-}
 static void arcmsr_iop_init(struct AdapterControlBlock *acb)
 {
 	uint32_t intmask_org;
@@ -2494,6 +2908,7 @@ static uint8_t arcmsr_iop_reset(struct A
 	uint32_t intmask_org;
 	uint8_t rtnval = 0x00;
 	int i = 0;
+	//spin_unlock_irq(acb->host->host_lock);
 	if (atomic_read(&acb->ccboutstandingcount) != 0) {
 		/* disable all outbound interrupt */
 		intmask_org = arcmsr_disable_outbound_ints(acb);
@@ -2510,8 +2925,10 @@ static uint8_t arcmsr_iop_reset(struct A
 		atomic_set(&acb->ccboutstandingcount, 0);
 		/* enable all outbound interrupt */
 		arcmsr_enable_outbound_ints(acb, intmask_org);
+		//spin_lock_irq(acb->host->host_lock);
 		return rtnval;
 	}
+	//spin_lock_irq(acb->host->host_lock);	
 	return rtnval;
 }
 
@@ -2522,37 +2939,35 @@ static int arcmsr_bus_reset(struct scsi_
 	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 eh bus reset .....num_resets =
%d, 
-		num_aborts = %d \n", acb->num_resets, acb->num_aborts);
+	printk(KERN_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;
-				timeout = wait_event_timeout(wait_q, 
-					(acb->acb_flags & ACB_F_BUS_RESET)
== 0, 220*HZ);
+				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)){
+			if(!arcmsr_iop_reset(acb)){
 				struct MessageUnit_A __iomem *reg;
 				reg = acb->pmuA;
+				spin_unlock_irq(acb->host->host_lock);
 				arcmsr_hardware_reset(acb);
 				acb->acb_flags &= ~ACB_F_IOP_INITED;
 				sleep_again:
 				arcmsr_sleep_for_bus_reset(cmd);
 				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);
+					printk(KERN_ERR "arcmsr%d: waiting
for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count);
 					if(retry_count > retrycount){
 						acb->fw_flag = FW_DEADLOCK;
-						printk(KERN_ERR "arcmsr%d:
waiting for hw bus reset return, 
-							RETRY TERMINATED!!
\n", acb->host->host_no);
+						printk(KERN_ERR "arcmsr%d:
waiting for hw bus reset return, RETRY TERMINATED!! \n",
acb->host->host_no);
+
spin_lock_irq(acb->host->host_lock);
 						return FAILED;
 					}
 					retry_count++;
@@ -2562,6 +2977,7 @@ static int arcmsr_bus_reset(struct scsi_
 				/* disable all outbound interrupt */
 				intmask_org =
arcmsr_disable_outbound_ints(acb);
 				arcmsr_get_firmware_spec(acb);
+				//arcmsr_iop_confirm(acb);
 				arcmsr_start_adapter_bgrb(acb);
 				/* clear Qbuffer if door bell ringed */
 				outbound_doorbell =
readl(&reg->outbound_doorbell);
@@ -2579,7 +2995,8 @@ static int arcmsr_bus_reset(struct scsi_
 				add_timer(&acb->eternal_timer);
 				acb->acb_flags &= ~ACB_F_BUS_RESET;
 				rtn = SUCCESS;
-				printk(KERN_ERR "arcmsr: scsi eh bus reset
succeeds\n");
+				printk(KERN_ERR "arcmsr: scsi  bus reset eh
returns with success\n");
+				spin_lock_irq(acb->host->host_lock);
 			}else{
 				acb->acb_flags &= ~ACB_F_BUS_RESET;
 				if(atomic_read(&acb->rq_map_token) == 0){
@@ -2603,7 +3020,7 @@ static int arcmsr_bus_reset(struct scsi_
 		}
 		case ACB_ADAPTER_TYPE_B:{
 			acb->acb_flags |= ACB_F_BUS_RESET;
-			if(arcmsr_iop_reset(acb)){
+			if(!arcmsr_iop_reset(acb)){
 				acb->acb_flags &= ~ACB_F_BUS_RESET;
 				rtn = FAILED;
 			}else{
@@ -2626,6 +3043,79 @@ static int arcmsr_bus_reset(struct scsi_
 				rtn = SUCCESS;
 			}
 		}
+		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;
+				//spin_unlock_irq(acb->host->host_lock);
+				arcmsr_hardware_reset(acb);
+				acb->acb_flags &= ~ACB_F_IOP_INITED;
+				sleep:
+				arcmsr_sleep_for_bus_reset(cmd);
+				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 > retrycount){
+						acb->fw_flag = FW_DEADLOCK;
+						printk(KERN_ERR "arcmsr%d:
waiting for hw bus reset return, RETRY TERMINATED!! \n",
acb->host->host_no);
+
//spin_lock_irq(acb->host->host_lock);
+						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); /*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;
+				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);
+				acb->acb_flags &= ~ACB_F_BUS_RESET;
+				rtn = SUCCESS;
+				printk(KERN_ERR "arcmsr: scsi bus reset eh
returns with success\n");
+				//spin_lock_irq(acb->host->host_lock);
+			}else{
+				acb->acb_flags &= ~ACB_F_BUS_RESET;
+				if(atomic_read(&acb->rq_map_token) == 0){
+					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);
+				}else{
+					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;
 }
@@ -2634,9 +3124,7 @@ static int arcmsr_abort_one_cmd(struct A
 		struct CommandControlBlock *ccb)
 {
 	int rtn;
-	spin_lock_irq(&acb->eh_lock);
 	rtn = arcmsr_polling_ccbdone(acb, ccb);
-	spin_unlock_irq(&acb->eh_lock);
 	return rtn;
 }
 
@@ -2662,7 +3149,6 @@ static int arcmsr_abort(struct scsi_cmnd
 		return rtn;
 
 	for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
-		printk("%s: loop %d\n", __FUNCTION__, i);
 		struct CommandControlBlock *ccb = acb->pccb_pool[i];
 		if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd)
{
 			ccb->startdone = ARCMSR_CCB_ABORTED;
@@ -2671,7 +3157,6 @@ static int arcmsr_abort(struct scsi_cmnd
 		}
 	}
 	acb->acb_flags &= ~ACB_F_ABORT;
-	printk("%s: leaving\n", __FUNCTION__);
 	return rtn;
 }
 
@@ -2706,6 +3190,7 @@ static const char *arcmsr_info(struct Sc
 	case PCI_DEVICE_ID_ARECA_1381:
 	case PCI_DEVICE_ID_ARECA_1680:
 	case PCI_DEVICE_ID_ARECA_1681:
+	case PCI_DEVICE_ID_ARECA_1880:	
 		type = "SAS";
 		break;
 	default:

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux