]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
[SCSI] SCSI: Support Type C RAID controller
authorNick Cheng <nick.cheng@areca.com.tw>
Tue, 13 Jul 2010 12:03:04 +0000 (20:03 +0800)
committerJames Bottomley <James.Bottomley@suse.de>
Tue, 27 Jul 2010 17:03:49 +0000 (12:03 -0500)
1. To support Type C RAID controller, ACB_ADAPTER_TYPE_C, i.e. PCI device
ID: 0x1880.
Signed-off-by: Nick Cheng< nick.cheng@areca.com.tw >
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/arcmsr/arcmsr.h
drivers/scsi/arcmsr/arcmsr_attr.c
drivers/scsi/arcmsr/arcmsr_hba.c

index c0861c05cd4913022c9f2bc4e47061f313a894df..475c31ae985c2cd70c3aa0f2ffd34caa3e645201 100644 (file)
 *******************************************************************************
 */
 #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_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
@@ -60,7 +59,8 @@ struct device_attribute;
 #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_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
@@ -138,9 +138,9 @@ struct CMD_MESSAGE_FIELD
 #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_ERROR           0x00000006
-#define ARCMSR_MESSAGE_RETURNCODE_3F              0x0000003F
+#define ARCMSR_MESSAGE_RETURNCODE_OK           0x00000001
+#define ARCMSR_MESSAGE_RETURNCODE_ERROR                0x00000006
+#define ARCMSR_MESSAGE_RETURNCODE_3F           0x0000003F
 #define ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON  0x00000088
 /*
 *************************************************************
@@ -153,13 +153,13 @@ struct  SG32ENTRY
 {
        __le32                                  length;
        __le32                                  address;
-} __attribute__ ((packed));
+}__attribute__ ((packed));
 struct  SG64ENTRY
 {
        __le32                                  length;
        __le32                                  address;
        __le32                                  addresshigh;
-} __attribute__ ((packed));
+}__attribute__ ((packed));
 /*
 ********************************************************************
 **      Q Buffer of IOP Message Transfer
@@ -186,9 +186,9 @@ struct FIRMWARE_INFO
        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                cfgVersion;                     /*25,100-103 Added for checking of new firmware capability*/
+       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
@@ -212,11 +212,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
 
 /*
 ************************************************************************
@@ -273,6 +277,61 @@ struct FIRMWARE_INFO
 #define ARCMSR_MESSAGE_RBUFFER                       0x0000ff00
 /* 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)
@@ -310,7 +369,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
@@ -356,7 +415,81 @@ 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
@@ -374,11 +507,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_A __iomem *pmuA;
+               struct MessageUnit_B    *pmuB;
+               struct MessageUnit_C __iomem *pmuC;
        };
        /* message unit ATU inbound base address0 */
        void __iomem *mem_base0;
@@ -399,6 +535,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
@@ -441,9 +579,9 @@ struct AdapterControlBlock
        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];
+       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;
@@ -460,31 +598,31 @@ struct AdapterControlBlock
 **             this CCB length must be 32 bytes boundary
 *******************************************************************************
 */
-struct CommandControlBlock
-{
+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                        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
-       #define         CCB_FLAG_ERROR                  0x0002
-       #define         CCB_FLAG_FLUSHCACHE             0x0004
-       #define         CCB_FLAG_MASTER_ABORTED         0x0008
+       #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
+       #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[6];            /*24 byte*/
-#else
+               uint32_t                                reserved[5];            /*24 byte*/
+       #else
        /*  ======================512+32 bytes========================  */
-               uint32_t                                reserved[2];            /*8  byte*/
-#endif
+               uint32_t                                reserved;               /*8  byte*/
+       #endif
        /*  =======================================================   */
        struct ARCMSR_CDB               arcmsr_cdb;
 };
index 07fdfe57e38e07eaf501ddc83a8aba77ed3ca39c..69f8346aa288348a86a8d9885dbfd1759867c5ad 100644 (file)
@@ -59,8 +59,7 @@
 
 struct device_attribute *arcmsr_host_attrs[];
 
-static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp,
-                                            struct kobject *kobj,
+static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj,
                                             struct bin_attribute *bin,
                                             char *buf, loff_t off,
                                             size_t count)
@@ -106,8 +105,7 @@ static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp,
        return (allxfer_len);
 }
 
-static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp,
-                                             struct kobject *kobj,
+static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj,
                                              struct bin_attribute *bin,
                                              char *buf, loff_t off,
                                              size_t count)
@@ -155,8 +153,7 @@ static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp,
        }
 }
 
-static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp,
-                                             struct kobject *kobj,
+static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
                                              struct bin_attribute *bin,
                                              char *buf, loff_t off,
                                              size_t count)
index ba33473b27a1bc7b715dfc3c4f2aaf2505ffb241..95a895dd4f132883aa7dc8c379332aa917863aa0 100644 (file)
 #include <scsi/scsicam.h>
 #include "arcmsr.h"
 MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>");
-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 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 +99,12 @@ static void arcmsr_flush_hbb_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_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,
@@ -119,18 +121,18 @@ static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
 
 static struct scsi_host_template arcmsr_scsi_host_template = {
        .module                 = THIS_MODULE,
-       .name                   = "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter"
-                                                       ARCMSR_DRIVER_VERSION,
+       .name                   = "ARCMSR ARECA SATA/SAS RAID Controller"
+                               ARCMSR_DRIVER_VERSION,
        .info                   = arcmsr_info,
        .queuecommand           = arcmsr_queue_command,
-       .eh_abort_handler       = arcmsr_abort,
+       .eh_abort_handler               = arcmsr_abort,
        .eh_bus_reset_handler   = arcmsr_bus_reset,
        .bios_param             = arcmsr_bios_param,
        .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,
+       .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,
@@ -160,22 +162,45 @@ static struct pci_device_id arcmsr_device_id_table[] = {
 MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
 static struct pci_driver arcmsr_pci_driver = {
        .name                   = "arcmsr",
-       .id_table               = arcmsr_device_id_table,
+       .id_table                       = arcmsr_device_id_table,
        .probe                  = arcmsr_probe,
        .remove                 = arcmsr_remove,
        .shutdown               = arcmsr_shutdown,
 };
+/*
+****************************************************************************
+****************************************************************************
+*/
+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);
+               }
+               printk(KERN_NOTICE "wake-up\n");
+               return 0;
+}
 
-static void arcmsr_free_mu(struct AdapterControlBlock *acb)
+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);
+               dma_free_coherent(&acb->pdev->dev,
+                       sizeof(struct MessageUnit_B),
+                       acb->pmuB, acb->dma_coherent_handle_hbb_mu);
        }
        }
 }
@@ -183,10 +208,9 @@ static void arcmsr_free_mu(struct AdapterControlBlock *acb)
 static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
 {
        struct pci_dev *pdev = acb->pdev;
-
-       switch (acb->adapter_type) {
+       switch (acb->adapter_type){
        case ACB_ADAPTER_TYPE_A:{
-               acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+               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);
                        return false;
@@ -208,6 +232,19 @@ static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
                }
                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->outbound_doorbell_clear);/*clear interrupt*/
+                       return true;
+               }
+               break;
        }
        }
        return true;
@@ -216,13 +253,19 @@ static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
 static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb)
 {
        switch (acb->adapter_type) {
-               case ACB_ADAPTER_TYPE_A:{
-                       iounmap(acb->pmuA);
-               }
-               case ACB_ADAPTER_TYPE_B:{
-                       iounmap(acb->mem_base0);
-                       iounmap(acb->mem_base1);
-               }
+       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);
+       }
        }
 }
 
@@ -270,34 +313,37 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
        pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
        acb->dev_id = dev_id;
        switch (dev_id) {
-       case 0x1201 : {
+       case 0x1880: {
+               acb->adapter_type = ACB_ADAPTER_TYPE_C;
+               }
+               break;
+       case 0x1201: {
                acb->adapter_type = ACB_ADAPTER_TYPE_B;
                }
                break;
 
-       default : acb->adapter_type = ACB_ADAPTER_TYPE_A;
+       default: acb->adapter_type = ACB_ADAPTER_TYPE_A;
        }
-}
+}      
 
 static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
 {
        struct MessageUnit_A __iomem *reg = acb->pmuA;
        uint32_t Index;
        uint8_t Retries = 0x00;
-
        do {
                for (Index = 0; Index < 100; Index++) {
                        if (readl(&reg->outbound_intstatus) &
                                        ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
                                writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
                                        &reg->outbound_intstatus);
-                               return 0x00;
+                               return true;
                        }
                        msleep(10);
-               } /*max 1 seconds*/
+               }/*max 1 seconds*/
 
        } while (Retries++ < 20);/*max 20 sec*/
-       return 0xff;
+       return false;
 }
 
 static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
@@ -305,7 +351,6 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
        struct MessageUnit_B *reg = acb->pmuB;
        uint32_t Index;
        uint8_t Retries = 0x00;
-
        do {
                for (Index = 0; Index < 100; Index++) {
                        if (readl(reg->iop2drv_doorbell)
@@ -313,23 +358,39 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
                                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*/
+               }/*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->outbound_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;
        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--;
@@ -343,10 +404,9 @@ static void arcmsr_flush_hbb_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_hbb_wait_msgint_ready(acb))
                        break;
                else {
                        retry_count--;
@@ -356,6 +416,23 @@ static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb)
        } 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) {
@@ -368,151 +445,94 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
        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 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 16M 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;
-                       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;
-               }
-                       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;
-               }
-               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;
+       struct pci_dev *pdev = acb->pdev;
+       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, offset;
+       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);    
+       }
+       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 + 32;
+       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;
+       }
+       acb->dma_coherent = dma_coherent;
+       acb->dma_coherent_handle = dma_coherent_handle;
+       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->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;
        }
        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);
 
+static void arcmsr_message_isr_bh_fn(struct work_struct *work) 
+{
+       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]);
+                       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++) {
+                               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) {
+                                               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) {
+                                                       }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) {
                                                                psdev = scsi_device_lookup(acb->host, 0, target, lun);
-                                                               if (psdev != NULL) {
+                                                               if (psdev != NULL ) {
                                                                        scsi_remove_device(psdev);
                                                                        scsi_device_put(psdev);
                                                                }
@@ -531,8 +551,45 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work)
                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]);
+                       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;
+                                               }
+                                       }
+                                       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;
@@ -571,21 +628,20 @@ 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;
+       uint8_t bus,dev_fun;
        int error;
-
        error = pci_enable_device(pdev);
-       if (error) {
+       if(error){
                return -ENODEV;
        }
        host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock));
-       if (!host) {
-               goto pci_disable_dev;
+       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) {
+               if(error){
                        printk(KERN_WARNING
                               "scsi%d: No suitable DMA mask available\n",
                               host->host_no);
@@ -596,53 +652,53 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        bus = pdev->bus->number;
        dev_fun = pdev->devfn;
        acb = (struct AdapterControlBlock *) host->hostdata;
-       memset(acb, 0, sizeof(struct AdapterControlBlock));
+       memset(acb,0,sizeof(struct AdapterControlBlock));
        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;             /*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->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);
        acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
-                          ACB_F_MESSAGE_RQBUFFER_CLEARED |
-                          ACB_F_MESSAGE_WQBUFFER_READED);
+                       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_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) {
+       if(error){
                goto scsi_host_remove;
        }
        host->irq = pdev->irq;
-       scsi_scan_host(host);
+       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);
@@ -652,10 +708,10 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        acb->eternal_timer.data = (unsigned long) acb;
        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:
+out_free_sysfs:
 scsi_host_remove:
        scsi_remove_host(host);
 RAID_controller_stop:
@@ -663,7 +719,7 @@ RAID_controller_stop:
        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:
@@ -678,15 +734,14 @@ pci_disable_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)
@@ -694,15 +749,27 @@ static uint8_t arcmsr_abort_hbb_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)) {
+       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;
@@ -715,6 +782,11 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
        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;
 }
@@ -722,13 +794,12 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
 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;
-}
-       return true;
+       }
+       return true;
 }
 
 static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
@@ -736,18 +807,16 @@ 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)
 {
        struct AdapterControlBlock *acb = ccb->acb;
        struct scsi_cmnd *pcmd = ccb->pcmd;
        unsigned long flags;
-
        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);
@@ -759,7 +828,6 @@ 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;
        if (sensebuffer) {
                int sense_data_length =
@@ -775,8 +843,7 @@ static void arcmsr_report_sense_info(struct CommandControlBlock *ccb)
 static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
 {
        u32 orig_mask = 0;
-       switch (acb->adapter_type) {
-
+       switch (acb->adapter_type) {    
        case ACB_ADAPTER_TYPE_A : {
                struct MessageUnit_A __iomem *reg = acb->pmuA;
                orig_mask = readl(&reg->outbound_intmask);
@@ -784,30 +851,35 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
                                                &reg->outbound_intmask);
                }
                break;
-
        case ACB_ADAPTER_TYPE_B : {
                struct MessageUnit_B *reg = acb->pmuB;
                orig_mask = readl(reg->iop2drv_doorbell_mask);
                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)
+static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, 
+                       struct CommandControlBlock *ccb, bool error)
 {
-
        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;
                        arcmsr_ccb_complete(ccb);
-       } else {
+       }else{
                switch (ccb->arcmsr_cdb.DeviceStatus) {
                case ARCMSR_DEV_SELECT_TIMEOUT: {
                        acb->devstate[id][lun] = ARECA_RAID_GONE;
@@ -833,42 +905,37 @@ static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
                        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);
+                       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);
                        break;
                }
        }
 }
 
-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;
+                               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);
                        }
+                       return;
                }
                printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
                                done acb = '0x%p'"
@@ -876,20 +943,22 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t fla
                                " ccboutstandingcount = %d \n"
                                , acb->host->host_no
                                , acb
-                               , ccb
-                               , ccb->acb
-                               , ccb->startdone
+                               , pCCB
+                               , pCCB->acb
+                               , pCCB->startdone
                                , atomic_read(&acb->ccboutstandingcount));
+                 return;
                }
-       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: {
@@ -899,9 +968,12 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
                                        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)
+               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;
@@ -909,17 +981,37 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
        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)
@@ -930,16 +1022,15 @@ static void arcmsr_remove(struct pci_dev *pdev)
        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);
        arcmsr_stop_adapter_bgrb(acb);
-       arcmsr_flush_adapter_cache(acb);
+       arcmsr_flush_adapter_cache(acb);        
        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 */
@@ -962,8 +1053,10 @@ static void arcmsr_remove(struct pci_dev *pdev)
        }
        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);
 }
@@ -983,7 +1076,6 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
 static int arcmsr_module_init(void)
 {
        int error = 0;
-
        error = pci_register_driver(&arcmsr_pci_driver);
        return error;
 }
@@ -999,10 +1091,9 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
                                                u32 intmask_org)
 {
        u32 mask;
-
        switch (acb->adapter_type) {
 
-       case ACB_ADAPTER_TYPE_A : {
+       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|
@@ -1012,7 +1103,7 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
                }
                break;
 
-       case ACB_ADAPTER_TYPE_B : {
+       case ACB_ADAPTER_TYPE_B: {
                struct MessageUnit_B *reg = acb->pmuB;
                mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK |
                        ARCMSR_IOP2DRV_DATA_READ_OK |
@@ -1021,6 +1112,13 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
                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;
+               }
        }
 }
 
@@ -1032,75 +1130,69 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb,
        __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));
-                       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;
-
-                               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;
+       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));
+               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;
+
+                       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;
 
-                               pdma_sg->addresshigh = address_hi;
-                               pdma_sg->address = address_lo;
-                               pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
-                               psge += sizeof (struct SG64ENTRY);
-                               arccdbsize += sizeof (struct SG64ENTRY);
-                       }
-                       cdb_sgcount++;
+                       pdma_sg->addresshigh = address_hi;
+                       pdma_sg->address = address_lo;
+                       pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR);
+                       psge += sizeof (struct SG64ENTRY);
+                       arccdbsize += sizeof (struct SG64ENTRY);
                }
-               arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
-               arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
+       }
+       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) {
+       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;
-
        switch (acb->adapter_type) {
        case ACB_ADAPTER_TYPE_A: {
                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;
@@ -1112,11 +1204,10 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr
                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 */
@@ -1124,6 +1215,19 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr
                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);
+               }
+               }
        }
 }
 
@@ -1132,8 +1236,7 @@ static void arcmsr_stop_hba_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)) {
+       if (!arcmsr_hba_wait_msgint_ready(acb)) {
                printk(KERN_NOTICE
                        "arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
                        , acb->host->host_no);
@@ -1146,13 +1249,26 @@ static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb)
        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) {
@@ -1165,21 +1281,15 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
                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);
-       }
-       }
+       dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
 }
 
 void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
@@ -1196,6 +1306,10 @@ void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
                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);
+               }
        }
 }
 
@@ -1221,13 +1335,21 @@ static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
                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;
        }
 }
 
 struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
 {
        struct QBUFFER __iomem *qbuffer = NULL;
-
        switch (acb->adapter_type) {
 
        case ACB_ADAPTER_TYPE_A: {
@@ -1241,6 +1363,10 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
                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;
 }
@@ -1248,7 +1374,6 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
 static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb)
 {
        struct QBUFFER __iomem *pqbuffer = NULL;
-
        switch (acb->adapter_type) {
 
        case ACB_ADAPTER_TYPE_A: {
@@ -1262,6 +1387,11 @@ static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBloc
                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;
 }
@@ -1272,19 +1402,18 @@ static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb)
        struct QBUFFER *pQbuffer;
        uint8_t __iomem *iop_data;
        int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex;
-
        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);
+       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);
+                       memcpy(pQbuffer, iop_data, 1);
                        rqbuf_lastindex++;
                        rqbuf_lastindex %= ARCMSR_MAX_QBUFFER;
                        iop_data++;
@@ -1335,25 +1464,52 @@ static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb)
 {
        uint32_t outbound_doorbell;
        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)    {
+       if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) {
                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);
        }
 }
 
@@ -1362,29 +1518,62 @@ static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
        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
 **
-** The only message interrupt we expect is in response to a query for the current adapter config.
+** 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)
 {
        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);
@@ -1397,13 +1586,29 @@ static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb)
        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;
        struct MessageUnit_A __iomem *reg = acb->pmuA;
-
        outbound_intstatus = readl(&reg->outbound_intstatus) &
-                                                       acb->outbound_int_enable;
+               acb->outbound_int_enable;
        if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))      {
                return 1;
        }
@@ -1414,7 +1619,7 @@ static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
        if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) {
                arcmsr_hba_postqueue_isr(acb);
        }
-       if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT)       {
+       if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT)        {
                /* messenger of "driver to iop commands" */
                arcmsr_hba_message_isr(acb);
        }
@@ -1425,9 +1630,8 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
 {
        uint32_t outbound_doorbell;
        struct MessageUnit_B *reg = acb->pmuB;
-
        outbound_doorbell = readl(reg->iop2drv_doorbell) &
-                                                       acb->outbound_int_enable;
+                               acb->outbound_int_enable;
        if (!outbound_doorbell)
                return 1;
 
@@ -1436,7 +1640,7 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
        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)   {
+       if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) {
                arcmsr_iop2drv_data_wrote_handle(acb);
        }
        if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) {
@@ -1445,14 +1649,37 @@ static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb)
        if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) {
                arcmsr_hbb_postqueue_isr(acb);
        }
-       if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
+       if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) {
                /* messenger of "driver to iop commands" */
                arcmsr_hbb_message_isr(acb);
        }
-
        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 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;
+}
 static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
 {
        switch (acb->adapter_type) {
@@ -1469,6 +1696,11 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
                }
                }
                break;
+        case ACB_ADAPTER_TYPE_C: {
+               if (arcmsr_handle_hbc_isr(acb)) {
+                       return IRQ_NONE;
+               }
+               }
        }
        return IRQ_HANDLED;
 }
@@ -1495,7 +1727,6 @@ void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
        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) {
@@ -1528,7 +1759,6 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                                                (uint32_t ) cmd->cmnd[7] << 8  |
                                                (uint32_t ) cmd->cmnd[8];
                                                /* 4 bytes: Areca io control code */
-
        sg = scsi_sglist(cmd);
        buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
        if (scsi_sg_count(cmd) > 1) {
@@ -1554,7 +1784,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                        retvalue = ARCMSR_MESSAGE_FAIL;
                        goto message_out;
                }
-
+                               
                ptmpQbuffer = ver_addr;
                while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
                        && (allxfer_len < 1031)) {
@@ -1586,10 +1816,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                }
                memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len);
                pcmdmessagefld->cmdmessage.Length = allxfer_len;
-               if (acb->fw_flag == FW_DEADLOCK) {
+               if(acb->fw_flag == FW_DEADLOCK) {
                        pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
-               } else {
-               pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
+               }else{
+                       pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
                }
                kfree(ver_addr);
                }
@@ -1605,11 +1835,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                        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;
@@ -1672,10 +1902,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                acb->rqbuf_firstindex = 0;
                acb->rqbuf_lastindex = 0;
                memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER);
-               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;
                }
@@ -1684,10 +1914,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
 
        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;
                }
@@ -1724,10 +1954,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                memset(pQbuffer, 0, sizeof(struct QBUFFER));
                pQbuffer = acb->wqbuffer;
                memset(pQbuffer, 0, sizeof(struct QBUFFER));
-               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;
                }
@@ -1735,10 +1965,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                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;
                }
@@ -1746,10 +1976,10 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                }
        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;
                }
@@ -1759,7 +1989,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                break;
 
        case ARCMSR_MESSAGE_SAY_GOODBYE:
-               if (acb->fw_flag == FW_DEADLOCK) {
+               if(acb->fw_flag == FW_DEADLOCK) {
                        pcmdmessagefld->cmdmessage.ReturnCode =
                        ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
                }
@@ -1767,7 +1997,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
                break;
 
        case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
-               if (acb->fw_flag == FW_DEADLOCK) {
+               if(acb->fw_flag == FW_DEADLOCK) {
                        pcmdmessagefld->cmdmessage.ReturnCode =
                        ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
                }
@@ -1792,7 +2022,7 @@ static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock
        if (!list_empty(head)) {
                ccb = list_entry(head->next, struct CommandControlBlock, list);
                list_del_init(&ccb->list);
-       } else {
+       }else{
                spin_unlock_irqrestore(&acb->ccblist_lock, flags);
                return 0;
        }
@@ -1862,29 +2092,29 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
        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) {
-                       cmd->result = (DID_NO_CONNECT << 16);
+       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);
                return 0;
        }
-
        if (target == 16) {
                /* virtual device for iop message transfer */
                arcmsr_handle_virtual_command(acb, cmd);
                return 0;
        }
-
        if (atomic_read(&acb->ccboutstandingcount) >=
                        ARCMSR_MAX_OUTSTANDING_CMD)
                return SCSI_MLQUEUE_HOST_BUSY;
-
+       if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) {
+               printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n");
+               return 0;
+       }
        ccb = arcmsr_get_freeccb(acb);
        if (!ccb)
                return SCSI_MLQUEUE_HOST_BUSY;
-       if ( arcmsr_build_ccb( acb, ccb, cmd ) == FAILED ) {
+       if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) {
                cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1);
                cmd->scsi_done(cmd);
                return 0;
@@ -1901,17 +2131,16 @@ static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
        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_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;
        }
        count = 8;
-       while (count) {
+       while (count){
                *acb_firm_model = readb(iop_firm_model);
                acb_firm_model++;
                iop_firm_model++;
@@ -1919,25 +2148,25 @@ static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb)
        }
 
        count = 16;
-       while (count) {
+       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--;
-               }
-       printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n",
+       count=16;
+       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", 
                acb->host->host_no,
                acb->firm_version,
                acb->firm_model);
-               acb->signature = readl(&reg->message_rwbuffer[0]);
+       acb->signature = readl(&reg->message_rwbuffer[0]);
        acb->firm_request_len = readl(&reg->message_rwbuffer[1]);
        acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);
        acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);
@@ -1962,14 +2191,14 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
        /*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) {
+       if (!dma_coherent){
                printk(KERN_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;
        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= (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);
@@ -1981,41 +2210,41 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
        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;
        }
        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++;
                count--;
        }
 
-               count = 16;
-               while (count) {
-                       *acb_device_map = readb(iop_device_map);
-                       acb_device_map++;
-                       iop_device_map++;
-                       count--;
-               }
-
+       count = 16;
+       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",
-                       acb->host->host_no,
+               acb->host->host_no,
                acb->firm_version,
                acb->firm_model);
 
        acb->signature = readl(&reg->message_rwbuffer[1]);
-               /*firm_signature,1,00-03*/
+       /*firm_signature,1,00-03*/
        acb->firm_request_len = readl(&reg->message_rwbuffer[2]);
        /*firm_request_len,1,04-07*/
        acb->firm_numbers_queue = readl(&reg->message_rwbuffer[3]);
@@ -2028,12 +2257,73 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
        /*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,
@@ -2044,18 +2334,19 @@ static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
        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;
        writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/
        while (1) {
                if ((flag_ccb = readl(&reg->outbound_queueport)) == 0xFFFFFFFF) {
-                       if (poll_ccb_done) {
+                       if (poll_ccb_done){
                                rtn = SUCCESS;
                                break;
-                       } else {
-                               if (poll_count > 100) {
+                       }else {
+                               msleep(25);
+                               if (poll_count > 100){
                                        rtn = FAILED;
                                        break;
                                }
@@ -2084,76 +2375,132 @@ static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
                                , 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;
 }
 
 static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb,
                                        struct CommandControlBlock *poll_ccb)
 {
-               struct MessageUnit_B *reg = acb->pmuB;
+       struct MessageUnit_B *reg = acb->pmuB;
        struct ARCMSR_CDB *arcmsr_cdb;
-               struct CommandControlBlock *ccb;
-               uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
+       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 */
+       poll_count++;
+       /* clear doorbell interrupt */
        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) {
+       while(1){
+               index = reg->doneq_index;
+               if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {
+                       if (poll_ccb_done){
                                rtn = SUCCESS;
-                                       break;
-                       } else {
-                                       msleep(25);
-                               if (poll_count > 100) {
+                               break;
+                       }else {
+                               msleep(25);
+                               if (poll_count > 100){
                                        rtn = FAILED;
-                                               break;
-                               }
-                                       goto polling_hbb_ccb_retry;
+                                       break;
                                }
+                               goto polling_hbb_ccb_retry;
                        }
-                       writel(0, &reg->done_qbuffer[index]);
-                       index++;
-                       /*if last index number set it to 0 */
-                       index %= ARCMSR_MAX_HBB_POSTQUEUE;
-                       reg->doneq_index = index;
-                       /* check ifcommand done with no error*/
+               }
+               writel(0, &reg->done_qbuffer[index]);
+               index++;
+               /*if last index number set it to 0 */
+               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)) {
+               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);
-                                       ccb->pcmd->result = DID_ABORT << 16;
+                                       ,acb->host->host_no
+                                       ,ccb->pcmd->device->id
+                                       ,ccb->pcmd->device->lun
+                                       ,ccb);
+                               ccb->pcmd->result = DID_ABORT << 16;
                                arcmsr_ccb_complete(ccb);
-                                       continue;
+                               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));
+                       continue;
+               } 
+               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;
                                }
-                               printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
-                                       " command done ccb = '0x%p'"
-                                       "ccboutstandingcount = %d \n"
+                               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
-                                       , ccb
-                                       , atomic_read(&acb->ccboutstandingcount));
+                                       , pCCB->pcmd->device->id
+                                       , pCCB->pcmd->device->lun
+                                       , pCCB);
+                                       pCCB->pcmd->result = DID_ABORT << 16;
+                                       arcmsr_ccb_complete(pCCB);
                                continue;
-               } else {
-                       arcmsr_report_ccb_state(acb, ccb, flag_ccb);
+                       }
+                       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;
                }
-               }       /*drain reply FIFO*/
+               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)
 {
@@ -2168,6 +2515,10 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
        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;
 }
@@ -2185,6 +2536,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
        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"
@@ -2202,7 +2554,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
                        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);
@@ -2223,7 +2575,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *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)) {
+               if (!arcmsr_hbb_wait_msgint_ready(acb)) {
                        printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
                                acb->host->host_no);
                        return 1;
@@ -2242,7 +2594,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
                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;
@@ -2251,6 +2603,27 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *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;
+
+                       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;
 }
@@ -2258,7 +2631,6 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
 static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
 {
        uint32_t firmware_state = 0;
-
        switch (acb->adapter_type) {
 
        case ACB_ADAPTER_TYPE_A: {
@@ -2277,24 +2649,30 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
                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);
+               }
        }
 }
 
 static void arcmsr_request_hba_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)) {
+       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)) {
+               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);
-               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
+               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
        }
        return;
 }
@@ -2302,7 +2680,25 @@ static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb)
 static void arcmsr_request_hbb_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 )){
+               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_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)
+{
+       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 {
@@ -2313,8 +2709,9 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
                atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
                if (atomic_dec_and_test(&acb->rq_map_token))
                        return;
-               writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell);
-               mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ));
+               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;
 }
@@ -2322,7 +2719,6 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb)
 static void arcmsr_request_device_map(unsigned long pacb)
 {
        struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
-
        switch (acb->adapter_type) {
                case ACB_ADAPTER_TYPE_A: {
                        arcmsr_request_hba_device_map(acb);
@@ -2332,6 +2728,9 @@ static void arcmsr_request_device_map(unsigned long pacb)
                        arcmsr_request_hbb_device_map(acb);
                }
                break;
+               case ACB_ADAPTER_TYPE_C: {
+                       arcmsr_request_hbc_device_map(acb);
+               }
        }
 }
 
@@ -2340,7 +2739,7 @@ static void arcmsr_start_hba_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)) {
+       if (!arcmsr_hba_wait_msgint_ready(acb)) {
                printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
                                rebulid' timeout \n", acb->host->host_no);
        }
@@ -2351,12 +2750,24 @@ static void arcmsr_start_hbb_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)) {
+       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) {
@@ -2366,6 +2777,8 @@ static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
        case ACB_ADAPTER_TYPE_B:
                arcmsr_start_hbb_bgrb(acb);
                break;
+       case ACB_ADAPTER_TYPE_C:
+               arcmsr_start_hbc_bgrb(acb);
        }
 }
 
@@ -2391,6 +2804,14 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
                /* 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);
+               }
        }
 }
 
@@ -2403,12 +2824,14 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
                {
                        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;
 }
@@ -2416,21 +2839,33 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
 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(KERN_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, &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);
+               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]);
@@ -2438,35 +2873,11 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
        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;
-
-       /* disable all outbound interrupt */
-       intmask_org = arcmsr_disable_outbound_ints(acb);
+       /* disable all outbound interrupt */
+       intmask_org = arcmsr_disable_outbound_ints(acb);
        arcmsr_wait_firmware_ready(acb);
        arcmsr_iop_confirm(acb);
        /*start background rebuild*/
@@ -2485,7 +2896,6 @@ static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
        uint32_t intmask_org;
        uint8_t rtnval = 0x00;
        int i = 0;
-
        if (atomic_read(&acb->ccboutstandingcount) != 0) {
                /* disable all outbound interrupt */
                intmask_org = arcmsr_disable_outbound_ints(acb);
@@ -2514,54 +2924,50 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
        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) {
+       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;
-                       arcmsr_hardware_reset(acb);
-                       acb->acb_flags &= ~ACB_F_IOP_INITED;
+                               arcmsr_hardware_reset(acb);
+                               acb->acb_flags &= ~ACB_F_IOP_INITED;
 sleep_again:
-                       arcmsr_sleep_for_bus_reset(cmd);
+                               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);
-                       if (retry_count > retrycount) {
+                                       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);
                                                return FAILED;
-                       }
-                       retry_count++;
-                       goto sleep_again;
-                       }
-                       acb->acb_flags |= ACB_F_IOP_INITED;
-                       /* disable all outbound interrupt */
-                       intmask_org = arcmsr_disable_outbound_ints(acb);
+                                       }
+                                       retry_count++;
+                                       goto sleep_again;
+                               }
+                               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);
+                               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;
                                init_timer(&acb->eternal_timer);
@@ -2571,35 +2977,35 @@ sleep_again:
                                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");
                        } 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);
+                                       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->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;
                }
                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 {
-       acb->acb_flags &= ~ACB_F_BUS_RESET;
+                       } 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);
@@ -2616,7 +3022,78 @@ sleep_again:
                                        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;
+                               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:
+                               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);
+                                               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");
+                       } 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;
@@ -2626,9 +3103,7 @@ static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,
                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;
 }
 
@@ -2638,7 +3113,6 @@ static int arcmsr_abort(struct scsi_cmnd *cmd)
                (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);
@@ -2672,7 +3146,6 @@ static const char *arcmsr_info(struct Scsi_Host *host)
        static char buf[256];
        char *type;
        int raid6 = 1;
-
        switch (acb->pdev->device) {
        case PCI_DEVICE_ID_ARECA_1110:
        case PCI_DEVICE_ID_ARECA_1200:
@@ -2696,6 +3169,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
        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: