summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h29
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c3
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c684
3 files changed, 525 insertions, 191 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index ab646e580d64..ce5371b3cdd5 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -48,7 +48,7 @@ struct device_attribute;
 /*The limit of outstanding scsi command that firmware can handle*/
 #define ARCMSR_MAX_OUTSTANDING_CMD						256
 #define ARCMSR_MAX_FREECCB_NUM							320
-#define ARCMSR_DRIVER_VERSION		     "Driver Version 1.20.00.15 2008/02/27"
+#define ARCMSR_DRIVER_VERSION		     "Driver Version 1.20.00.15 2008/11/03"
 #define ARCMSR_SCSI_INITIATOR_ID						255
 #define ARCMSR_MAX_XFER_SECTORS							512
 #define ARCMSR_MAX_XFER_SECTORS_B						4096
@@ -110,6 +110,8 @@ struct CMD_MESSAGE_FIELD
 #define FUNCTION_SAY_HELLO			0x0807
 #define FUNCTION_SAY_GOODBYE			0x0808
 #define FUNCTION_FLUSH_ADAPTER_CACHE		0x0809
+#define FUNCTION_GET_FIRMWARE_STATUS			0x080A
+#define FUNCTION_HARDWARE_RESET			0x080B
 /* ARECA IO CONTROL CODE*/
 #define ARCMSR_MESSAGE_READ_RQBUFFER       \
 	ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER
@@ -133,6 +135,7 @@ struct CMD_MESSAGE_FIELD
 #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
 /*
 *************************************************************
 **   structure for holding DMA address data
@@ -341,13 +344,13 @@ struct MessageUnit_B
 	uint32_t	done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
 	uint32_t	postq_index;
 	uint32_t	doneq_index;
-	void		__iomem *drv2iop_doorbell_reg;
-	void		__iomem *drv2iop_doorbell_mask_reg;
-	void		__iomem *iop2drv_doorbell_reg;
-	void		__iomem *iop2drv_doorbell_mask_reg;
-	void		__iomem *msgcode_rwbuffer_reg;
-	void		__iomem *ioctl_wbuffer_reg;
-	void		__iomem *ioctl_rbuffer_reg;
+	uint32_t		__iomem *drv2iop_doorbell_reg;
+	uint32_t		__iomem *drv2iop_doorbell_mask_reg;
+	uint32_t		__iomem *iop2drv_doorbell_reg;
+	uint32_t		__iomem *iop2drv_doorbell_mask_reg;
+	uint32_t		__iomem *msgcode_rwbuffer_reg;
+	uint32_t		__iomem *ioctl_wbuffer_reg;
+	uint32_t		__iomem *ioctl_rbuffer_reg;
 };
 
 /*
@@ -375,6 +378,7 @@ struct AdapterControlBlock
 	/* message unit ATU inbound base address0 */
 
 	uint32_t			acb_flags;
+	uint8_t                   		adapter_index;
 	#define ACB_F_SCSISTOPADAPTER         	0x0001
 	#define ACB_F_MSG_STOP_BGRB     	0x0002
 	/* stop RAID background rebuild */
@@ -390,7 +394,7 @@ struct AdapterControlBlock
 	#define ACB_F_BUS_RESET               	0x0080
 	#define ACB_F_IOP_INITED              	0x0100
 	/* iop init */
-
+	#define ACB_F_FIRMWARE_TRAP           		0x0400
 	struct CommandControlBlock *			pccb_pool[ARCMSR_MAX_FREECCB_NUM];
 	/* used for memory free */
 	struct list_head		ccb_free_list;
@@ -423,12 +427,19 @@ struct AdapterControlBlock
 #define ARECA_RAID_GOOD               0xaa
 	uint32_t			num_resets;
 	uint32_t			num_aborts;
+	uint32_t			signature;
 	uint32_t			firm_request_len;
 	uint32_t			firm_numbers_queue;
 	uint32_t			firm_sdram_size;
 	uint32_t			firm_hd_channels;
 	char				firm_model[12];
 	char				firm_version[20];
+	char			device_map[20];			/*21,84-99*/
+	struct work_struct 		arcmsr_do_message_isr_bh;
+	struct timer_list		eternal_timer;
+	unsigned short		fw_state;
+	atomic_t 			rq_map_token;
+	int			ante_token_value;
 };/* HW_DEVICE_EXTENSION */
 /*
 *******************************************************************************
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index a4e04c50c436..07fdfe57e38e 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -192,6 +192,7 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = {
 	.attr = {
 		.name = "mu_read",
 		.mode = S_IRUSR ,
+		.owner = THIS_MODULE,
 	},
 	.size = 1032,
 	.read = arcmsr_sysfs_iop_message_read,
@@ -201,6 +202,7 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = {
 	.attr = {
 		.name = "mu_write",
 		.mode = S_IWUSR,
+		.owner = THIS_MODULE,
 	},
 	.size = 1032,
 	.write = arcmsr_sysfs_iop_message_write,
@@ -210,6 +212,7 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
 	.attr = {
 		.name = "mu_clear",
 		.mode = S_IWUSR,
+		.owner = THIS_MODULE,
 	},
 	.size = 1,
 	.write = arcmsr_sysfs_iop_message_clear,
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index ffbe2192da3c..ffa54792bb33 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -72,8 +72,16 @@
 #include <scsi/scsicam.h>
 #include "arcmsr.h"
 
+#ifdef CONFIG_SCSI_ARCMSR_RESET
+	static int sleeptime = 20;
+	static int retrycount = 12;
+	module_param(sleeptime, int, S_IRUGO|S_IWUSR);
+	MODULE_PARM_DESC(sleeptime, "The waiting period for FW ready while bus reset");
+	module_param(retrycount, int, S_IRUGO|S_IWUSR);
+	MODULE_PARM_DESC(retrycount, "The retry count for FW ready while bus reset");
+#endif
 MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");
-MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");
+MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Bus Adapter");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(ARCMSR_DRIVER_VERSION);
 
@@ -96,6 +104,13 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb);
 static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb);
 static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);
 static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
+static void arcmsr_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_message_isr_bh_fn(struct work_struct *work);
+static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode);
+static void arcmsr_start_adapter_bgrb(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,
@@ -112,7 +127,7 @@ 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 Adapter"
+	.name			= "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter"
 							ARCMSR_DRIVER_VERSION,
 	.info			= arcmsr_info,
 	.queuecommand		= arcmsr_queue_command,
@@ -128,16 +143,6 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
 	.use_clustering		= ENABLE_CLUSTERING,
 	.shost_attrs		= arcmsr_host_attrs,
 };
-#ifdef CONFIG_SCSI_ARCMSR_AER
-static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
-static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
-						pci_channel_state_t state);
-
-static struct pci_error_handlers arcmsr_pci_error_handlers = {
-	.error_detected		= arcmsr_pci_error_detected,
-	.slot_reset		= arcmsr_pci_slot_reset,
-};
-#endif
 static struct pci_device_id arcmsr_device_id_table[] = {
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)},
 	{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)},
@@ -166,9 +171,6 @@ static struct pci_driver arcmsr_pci_driver = {
 	.probe			= arcmsr_probe,
 	.remove			= arcmsr_remove,
 	.shutdown		= arcmsr_shutdown,
-	#ifdef CONFIG_SCSI_ARCMSR_AER
-	.err_handler		= &arcmsr_pci_error_handlers,
-	#endif
 };
 
 static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
@@ -236,10 +238,9 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 		void *dma_coherent;
 		dma_addr_t dma_coherent_handle, dma_addr;
 		struct CommandControlBlock *ccb_tmp;
-		uint32_t intmask_org;
 		int i, j;
 
-		acb->pmuA = pci_ioremap_bar(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);
@@ -281,12 +282,6 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 		for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
 			for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
 				acb->devstate[i][j] = ARECA_RAID_GONE;
-
-		/*
-		** here we need to tell iop 331 our ccb_tmp.HighPart
-		** if ccb_tmp.HighPart is not zero
-		*/
-		intmask_org = arcmsr_disable_outbound_ints(acb);
 		}
 		break;
 
@@ -297,7 +292,6 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 		void __iomem *mem_base0, *mem_base1;
 		void *dma_coherent;
 		dma_addr_t dma_coherent_handle, dma_addr;
-		uint32_t intmask_org;
 		struct CommandControlBlock *ccb_tmp;
 		int i, j;
 
@@ -333,11 +327,13 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 		reg = (struct MessageUnit_B *)(dma_coherent +
 		ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
 		acb->pmuB = reg;
-		mem_base0 = pci_ioremap_bar(pdev, 0);
+		mem_base0 = ioremap(pci_resource_start(pdev, 0),
+					pci_resource_len(pdev, 0));
 		if (!mem_base0)
 			goto out;
 
-		mem_base1 = pci_ioremap_bar(pdev, 2);
+		mem_base1 = ioremap(pci_resource_start(pdev, 2),
+					pci_resource_len(pdev, 2));
 		if (!mem_base1) {
 			iounmap(mem_base0);
 			goto out;
@@ -357,12 +353,6 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
 		for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
 			for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
 				acb->devstate[i][j] = ARECA_RAID_GOOD;
-
-		/*
-		** here we need to tell iop 331 our ccb_tmp.HighPart
-		** if ccb_tmp.HighPart is not zero
-		*/
-		intmask_org = arcmsr_disable_outbound_ints(acb);
 		}
 		break;
 	}
@@ -374,6 +364,88 @@ out:
 		sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
 	return -ENOMEM;
 }
+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]);
+			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_B: {
+			struct MessageUnit_B *reg  = acb->pmuB;
+			char *acb_dev_map = (char *)acb->device_map;
+			uint32_t __iomem *signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer_reg[0]);
+			char __iomem *devicemap = (char __iomem *)(&reg->msgcode_rwbuffer_reg[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++;
+				}
+			}
+		}
+	}
+}
 
 static int arcmsr_probe(struct pci_dev *pdev,
 	const struct pci_device_id *id)
@@ -432,17 +504,17 @@ static int arcmsr_probe(struct pci_dev *pdev,
 			   ACB_F_MESSAGE_WQBUFFER_READED);
 	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
 	INIT_LIST_HEAD(&acb->ccb_free_list);
-
+	INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn);
 	error = arcmsr_alloc_ccb_pool(acb);
 	if (error)
 		goto out_release_regions;
 
+	arcmsr_iop_init(acb);
 	error = request_irq(pdev->irq, arcmsr_do_interrupt,
 			    IRQF_SHARED, "arcmsr", acb);
 	if (error)
 		goto out_free_ccb_pool;
 
-	arcmsr_iop_init(acb);
 	pci_set_drvdata(pdev, host);
 	if (strncmp(acb->firm_version, "V1.42", 5) >= 0)
 		host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B;
@@ -459,6 +531,14 @@ static int arcmsr_probe(struct pci_dev *pdev,
 	#ifdef CONFIG_SCSI_ARCMSR_AER
 	pci_enable_pcie_error_reporting(pdev);
 	#endif
+	atomic_set(&acb->rq_map_token, 16);
+	acb->fw_state = true;
+	init_timer(&acb->eternal_timer);
+	acb->eternal_timer.expires = jiffies + msecs_to_jiffies(10*HZ);
+	acb->eternal_timer.data = (unsigned long) acb;
+	acb->eternal_timer.function = &arcmsr_request_device_map;
+	add_timer(&acb->eternal_timer);
+
 	return 0;
  out_free_sysfs:
  out_free_irq:
@@ -518,40 +598,48 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
 	return 0xff;
 }
 
-static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
+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 0x00;
 }
 
-static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 
 	writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg);
-	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 0x00;
 }
 
-static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
 {
+	uint8_t rtnval = 0;
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A: {
-		arcmsr_abort_hba_allcmd(acb);
+		rtnval = arcmsr_abort_hba_allcmd(acb);
 		}
 		break;
 
 	case ACB_ADAPTER_TYPE_B: {
-		arcmsr_abort_hbb_allcmd(acb);
+		rtnval = arcmsr_abort_hbb_allcmd(acb);
 		}
 	}
+	return rtnval;
 }
 
 static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb)
@@ -649,8 +737,7 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
 
 	case ACB_ADAPTER_TYPE_A : {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
-		orig_mask = readl(&reg->outbound_intmask)|\
-				ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE;
+		orig_mask = readl(&reg->outbound_intmask);
 		writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \
 						&reg->outbound_intmask);
 		}
@@ -658,8 +745,7 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
 
 	case ACB_ADAPTER_TYPE_B : {
 		struct MessageUnit_B *reg = acb->pmuB;
-		orig_mask = readl(reg->iop2drv_doorbell_mask_reg) & \
-					(~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
+		orig_mask = readl(reg->iop2drv_doorbell_mask_reg);
 		writel(0, reg->iop2drv_doorbell_mask_reg);
 		}
 		break;
@@ -795,12 +881,13 @@ static void arcmsr_remove(struct pci_dev *pdev)
 	struct AdapterControlBlock *acb =
 		(struct AdapterControlBlock *) host->hostdata;
 	int poll_count = 0;
-
 	arcmsr_free_sysfs_attr(acb);
 	scsi_remove_host(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_disable_outbound_ints(acb);
 	acb->acb_flags |= ACB_F_SCSISTOPADAPTER;
 	acb->acb_flags &= ~ACB_F_IOP_INITED;
 
@@ -841,7 +928,9 @@ static void arcmsr_shutdown(struct pci_dev *pdev)
 	struct Scsi_Host *host = pci_get_drvdata(pdev);
 	struct AdapterControlBlock *acb =
 		(struct AdapterControlBlock *)host->hostdata;
-
+	del_timer_sync(&acb->eternal_timer);
+	arcmsr_disable_outbound_ints(acb);
+	flush_scheduled_work();
 	arcmsr_stop_adapter_bgrb(acb);
 	arcmsr_flush_adapter_cache(acb);
 }
@@ -861,7 +950,7 @@ static void arcmsr_module_exit(void)
 module_init(arcmsr_module_init);
 module_exit(arcmsr_module_exit);
 
-static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
+static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
 						u32 intmask_org)
 {
 	u32 mask;
@@ -871,7 +960,8 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
 	case ACB_ADAPTER_TYPE_A : {
 		struct MessageUnit_A __iomem *reg = acb->pmuA;
 		mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE |
-			     ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE);
+			     ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE|
+			     ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE);
 		writel(mask, &reg->outbound_intmask);
 		acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff;
 		}
@@ -879,8 +969,10 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \
 
 	case ACB_ADAPTER_TYPE_B : {
 		struct MessageUnit_B *reg = acb->pmuB;
-		mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | \
-			ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE);
+		mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK |
+			ARCMSR_IOP2DRV_DATA_READ_OK |
+			ARCMSR_IOP2DRV_CDB_DONE |
+			ARCMSR_IOP2DRV_MESSAGE_CMD_DONE);
 		writel(mask, reg->iop2drv_doorbell_mask_reg);
 		acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
 		}
@@ -1048,8 +1140,8 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
 	}
 	case ACB_ADAPTER_TYPE_B: {
 		struct MessageUnit_B *reg = acb->pmuB;
-		iounmap(reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL);
-		iounmap(reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER);
+		iounmap((u8 *)reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL);
+		iounmap((u8 *)reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER);
 		dma_free_coherent(&acb->pdev->dev,
 		(ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 +
 		sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle);
@@ -1249,13 +1341,36 @@ static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb)
 		reg->doneq_index = index;
 	}
 }
+/*
+**********************************************************************************
+** Handle a message interrupt
+**
+** The only message interrupt we expect is in response to a query for the current adapter config.
+** We want this in order to compare the drivemap so that we can detect newly-attached drives.
+**********************************************************************************
+*/
+static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_A *reg  = acb->pmuA;
+
+	/*clear interrupt and message state*/
+	writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, &reg->outbound_intstatus);
+	schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
+static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb)
+{
+	struct MessageUnit_B *reg  = acb->pmuB;
 
+	/*clear interrupt and message state*/
+	writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);
+	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) & \
+	outbound_intstatus = readl(&reg->outbound_intstatus) &
 							acb->outbound_int_enable;
 	if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))	{
 		return 1;
@@ -1267,6 +1382,10 @@ 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) 	{
+		/* messenger of "driver to iop commands" */
+		arcmsr_hba_message_isr(acb);
+	}
 	return 0;
 }
 
@@ -1275,13 +1394,14 @@ 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_reg) & \
+	outbound_doorbell = readl(reg->iop2drv_doorbell_reg) &
 							acb->outbound_int_enable;
 	if (!outbound_doorbell)
 		return 1;
 
 	writel(~outbound_doorbell, reg->iop2drv_doorbell_reg);
-	/*in case the last action of doorbell interrupt clearance is cached, this action can push HW to write down the clear bit*/
+	/*in case the last action of doorbell interrupt clearance is cached,
+	this action can push HW to write down the clear bit*/
 	readl(reg->iop2drv_doorbell_reg);
 	writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg);
 	if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) 	{
@@ -1293,6 +1413,10 @@ 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) {
+		/* messenger of "driver to iop commands" */
+		arcmsr_hbb_message_isr(acb);
+	}
 
 	return 0;
 }
@@ -1360,7 +1484,7 @@ void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb)
 	}
 }
 
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
 					struct scsi_cmnd *cmd)
 {
 	struct CMD_MESSAGE_FIELD *pcmdmessagefld;
@@ -1398,6 +1522,13 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 			retvalue = ARCMSR_MESSAGE_FAIL;
 			goto message_out;
 		}
+
+		if (!acb->fw_state) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+			goto message_out;
+		}
+
 		ptmpQbuffer = ver_addr;
 		while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex)
 			&& (allxfer_len < 1031)) {
@@ -1444,6 +1575,12 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 			retvalue = ARCMSR_MESSAGE_FAIL;
 			goto message_out;
 		}
+		if (!acb->fw_state) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+			goto message_out;
+		}
+
 		ptmpuserbuffer = ver_addr;
 		user_len = pcmdmessagefld->cmdmessage.Length;
 		memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len);
@@ -1496,6 +1633,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 
 	case ARCMSR_MESSAGE_CLEAR_RQBUFFER: {
 		uint8_t *pQbuffer = acb->rqbuffer;
+		if (!acb->fw_state) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+			goto message_out;
+		}
 
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
@@ -1511,6 +1653,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 
 	case ARCMSR_MESSAGE_CLEAR_WQBUFFER: {
 		uint8_t *pQbuffer = acb->wqbuffer;
+		if (!acb->fw_state) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+			goto message_out;
+		}
 
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
@@ -1529,6 +1676,11 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 
 	case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: {
 		uint8_t *pQbuffer;
+		if (!acb->fw_state) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+			goto message_out;
+		}
 
 		if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
 			acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
@@ -1551,13 +1703,22 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 		break;
 
 	case ARCMSR_MESSAGE_RETURN_CODE_3F: {
+		if (!acb->fw_state) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+			goto message_out;
+		}
 		pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F;
 		}
 		break;
 
 	case ARCMSR_MESSAGE_SAY_HELLO: {
 		int8_t *hello_string = "Hello! I am ARCMSR";
-
+		if (!acb->fw_state) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+			goto message_out;
+		}
 		memcpy(pcmdmessagefld->messagedatabuffer, hello_string
 			, (int16_t)strlen(hello_string));
 		pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK;
@@ -1565,10 +1726,20 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \
 		break;
 
 	case ARCMSR_MESSAGE_SAY_GOODBYE:
+		if (!acb->fw_state) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+			goto message_out;
+		}
 		arcmsr_iop_parking(acb);
 		break;
 
 	case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE:
+		if (!acb->fw_state) {
+			pcmdmessagefld->cmdmessage.ReturnCode =
+			ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON;
+			goto message_out;
+		}
 		arcmsr_flush_adapter_cache(acb);
 		break;
 
@@ -1651,16 +1822,57 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
 	struct CommandControlBlock *ccb;
 	int target = cmd->device->id;
 	int lun = cmd->device->lun;
-
+	uint8_t scsicmd = cmd->cmnd[0];
 	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);
+		}
+		cmd->scsi_done(cmd);
+		return 0;
+	}
+
 	if (acb->acb_flags & ACB_F_BUS_RESET) {
-		printk(KERN_NOTICE "arcmsr%d: bus reset"
-			" and return busy \n"
-			, acb->host->host_no);
+		switch (acb->adapter_type) {
+			case ACB_ADAPTER_TYPE_A: {
+				struct MessageUnit_A __iomem *reg = acb->pmuA;
+				uint32_t intmask_org, outbound_doorbell;
+
+				if ((readl(&reg->outbound_msgaddr1) &
+					ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
+					printk(KERN_NOTICE "arcmsr%d: bus reset and return busy\n",
+						acb->host->host_no);
 		return SCSI_MLQUEUE_HOST_BUSY;
 	}
+
+				acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
+				printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok\n",
+					acb->host->host_no);
+				/* disable all outbound interrupt */
+				intmask_org = arcmsr_disable_outbound_ints(acb);
+				arcmsr_get_firmware_spec(acb, 1);
+				/*start background rebuild*/
+				arcmsr_start_adapter_bgrb(acb);
+				/* clear Qbuffer if door bell ringed */
+				outbound_doorbell = readl(&reg->outbound_doorbell);
+				/*clear interrupt */
+				writel(outbound_doorbell, &reg->outbound_doorbell);
+				writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
+					&reg->inbound_doorbell);
+				/* enable outbound Post Queue,outbound doorbell Interrupt */
+				arcmsr_enable_outbound_ints(acb, intmask_org);
+				acb->acb_flags |= ACB_F_IOP_INITED;
+				acb->acb_flags &= ~ACB_F_BUS_RESET;
+			}
+			break;
+			case ACB_ADAPTER_TYPE_B: {
+			}
+		}
+	}
+
 	if (target == 16) {
 		/* virtual device for iop message transfer */
 		arcmsr_handle_virtual_command(acb, cmd);
@@ -1699,21 +1911,25 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd,
 	return 0;
 }
 
-static void arcmsr_get_hba_config(struct AdapterControlBlock *acb)
+static void *arcmsr_get_hba_config(struct AdapterControlBlock *acb, int mode)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
 	char *acb_firm_model = acb->firm_model;
 	char *acb_firm_version = acb->firm_version;
+	char *acb_device_map = acb->device_map;
 	char __iomem *iop_firm_model = (char __iomem *)(&reg->message_rwbuffer[15]);
 	char __iomem *iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);
+	char __iomem *iop_device_map = (char __iomem *) (&reg->message_rwbuffer[21]);
 	int count;
 
 	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
 	if (arcmsr_hba_wait_msgint_ready(acb)) {
 		printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \
 			miscellaneous data' timeout \n", acb->host->host_no);
+		return NULL;
 	}
 
+	if (mode == 1) {
 	count = 8;
 	while (count) {
 		*acb_firm_model = readb(iop_firm_model);
@@ -1730,34 +1946,48 @@ static void arcmsr_get_hba_config(struct AdapterControlBlock *acb)
 		count--;
 	}
 
+		count = 16;
+		while (count) {
+			*acb_device_map = readb(iop_device_map);
+			acb_device_map++;
+			iop_device_map++;
+			count--;
+		}
+
 	printk(KERN_INFO 	"ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n"
 		, acb->host->host_no
 		, acb->firm_version);
-
+		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]);
 	acb->firm_hd_channels = readl(&reg->message_rwbuffer[4]);
 }
-
-static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
+	return reg->message_rwbuffer;
+}
+static void __iomem *arcmsr_get_hbb_config(struct AdapterControlBlock *acb, int mode)
 {
 	struct MessageUnit_B *reg = acb->pmuB;
 	uint32_t __iomem *lrwbuffer = reg->msgcode_rwbuffer_reg;
 	char *acb_firm_model = acb->firm_model;
 	char *acb_firm_version = acb->firm_version;
+	char *acb_device_map = acb->device_map;
 	char __iomem *iop_firm_model = (char __iomem *)(&lrwbuffer[15]);
 	/*firm_model,15,60-67*/
 	char __iomem *iop_firm_version = (char __iomem *)(&lrwbuffer[17]);
 	/*firm_version,17,68-83*/
+	char __iomem *iop_device_map = (char __iomem *) (&lrwbuffer[21]);
+	/*firm_version,21,84-99*/
 	int count;
 
 	writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
 	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 NULL;
 	}
 
+	if (mode == 1) {
 	count = 8;
 	while (count)
 	{
@@ -1776,11 +2006,20 @@ static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
 		count--;
 	}
 
+		count = 16;
+		while (count) {
+			*acb_device_map = readb(iop_device_map);
+			acb_device_map++;
+			iop_device_map++;
+			count--;
+		}
+
 	printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n",
 			acb->host->host_no,
 			acb->firm_version);
 
-	lrwbuffer++;
+		acb->signature = readl(lrwbuffer++);
+		/*firm_signature,1,00-03*/
 	acb->firm_request_len = readl(lrwbuffer++);
 	/*firm_request_len,1,04-07*/
 	acb->firm_numbers_queue = readl(lrwbuffer++);
@@ -1790,20 +2029,23 @@ static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb)
 	acb->firm_hd_channels = readl(lrwbuffer);
 	/*firm_ide_channels,4,16-19*/
 }
-
-static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
+	return reg->msgcode_rwbuffer_reg;
+}
+static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode)
 {
+	void *rtnval = 0;
 	switch (acb->adapter_type) {
 	case ACB_ADAPTER_TYPE_A: {
-		arcmsr_get_hba_config(acb);
+		rtnval = arcmsr_get_hba_config(acb, mode);
 		}
 		break;
 
 	case ACB_ADAPTER_TYPE_B: {
-		arcmsr_get_hbb_config(acb);
+		rtnval = arcmsr_get_hbb_config(acb, mode);
 		}
 		break;
 	}
+	return rtnval;
 }
 
 static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb,
@@ -2043,6 +2285,66 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
 	}
 }
 
+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->fw_state = false;
+	} else {
+	/*to prevent rq_map_token from changing by other interrupt, then
+	avoid the dead-lock*/
+		acb->fw_state = true;
+		atomic_dec(&acb->rq_map_token);
+		if (!(acb->fw_state) ||
+			(acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+			atomic_set(&acb->rq_map_token, 16);
+		}
+		acb->ante_token_value = atomic_read(&acb->rq_map_token);
+		writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
+	}
+	mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
+	return;
+}
+
+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->fw_state = false;
+	} else {
+	/*to prevent rq_map_token from changing by other interrupt, then
+	avoid the dead-lock*/
+		acb->fw_state = true;
+		atomic_dec(&acb->rq_map_token);
+		if (!(acb->fw_state) ||
+			(acb->ante_token_value == atomic_read(&acb->rq_map_token))) {
+			atomic_set(&acb->rq_map_token, 16);
+		}
+		acb->ante_token_value = atomic_read(&acb->rq_map_token);
+		writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg);
+	}
+	mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6000));
+	return;
+}
+
+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);
+		}
+		break;
+		case ACB_ADAPTER_TYPE_B: {
+			arcmsr_request_hbb_device_map(acb);
+		}
+		break;
+	}
+}
+
 static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb)
 {
 	struct MessageUnit_A __iomem *reg = acb->pmuA;
@@ -2121,6 +2423,60 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb)
 	return;
 }
 
+static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
+{
+	uint8_t value[64];
+	int i;
+
+	/* backup pci config data */
+	for (i = 0; i < 64; i++) {
+		pci_read_config_byte(acb->pdev, i, &value[i]);
+	}
+	/* hardware reset signal */
+	pci_write_config_byte(acb->pdev, 0x84, 0x20);
+	msleep(1000);
+	/* write back pci config data */
+	for (i = 0; i < 64; i++) {
+		pci_write_config_byte(acb->pdev, i, value[i]);
+	}
+	msleep(1000);
+	return;
+}
+/*
+****************************************************************************
+****************************************************************************
+*/
+#ifdef CONFIG_SCSI_ARCMSR_RESET
+	int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
+	{
+			struct Scsi_Host *shost = NULL;
+			spinlock_t *host_lock = NULL;
+			int i, isleep;
+
+			shost = cmd->device->host;
+			host_lock = shost->host_lock;
+
+			printk(KERN_NOTICE "Host %d bus reset over, sleep %d seconds (busy %d, can queue %d) ...........\n",
+					shost->host_no, sleeptime, shost->host_busy, shost->can_queue);
+			isleep = sleeptime / 10;
+			spin_unlock_irq(host_lock);
+			if (isleep > 0) {
+				for (i = 0; i < isleep; i++) {
+					msleep(10000);
+					printk(KERN_NOTICE "^%d^\n", i);
+				}
+			}
+
+			isleep = sleeptime % 10;
+			if (isleep > 0) {
+				msleep(isleep * 1000);
+				printk(KERN_NOTICE "^v^\n");
+			}
+			spin_lock_irq(host_lock);
+			printk(KERN_NOTICE "***** wake up *****\n");
+			return 0;
+	}
+#endif
 static void arcmsr_iop_init(struct AdapterControlBlock *acb)
 {
 	uint32_t intmask_org;
@@ -2129,7 +2485,7 @@ static void arcmsr_iop_init(struct AdapterControlBlock *acb)
        intmask_org = arcmsr_disable_outbound_ints(acb);
 	arcmsr_wait_firmware_ready(acb);
 	arcmsr_iop_confirm(acb);
-	arcmsr_get_firmware_spec(acb);
+	arcmsr_get_firmware_spec(acb, 1);
 	/*start background rebuild*/
 	arcmsr_start_adapter_bgrb(acb);
 	/* empty doorbell Qbuffer if door bell ringed */
@@ -2140,51 +2496,110 @@ static void arcmsr_iop_init(struct AdapterControlBlock *acb)
 	acb->acb_flags |= ACB_F_IOP_INITED;
 }
 
-static void arcmsr_iop_reset(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb)
 {
 	struct CommandControlBlock *ccb;
 	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);
 		/* talk to iop 331 outstanding command aborted */
-		arcmsr_abort_allcmd(acb);
-
+		rtnval = arcmsr_abort_allcmd(acb);
 		/* wait for 3 sec for all command aborted*/
 		ssleep(3);
-
-		/* disable all outbound interrupt */
-		intmask_org = arcmsr_disable_outbound_ints(acb);
 		/* clear all outbound posted Q */
 		arcmsr_done4abort_postqueue(acb);
 		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
 			ccb = acb->pccb_pool[i];
 			if (ccb->startdone == ARCMSR_CCB_START) {
-				ccb->startdone = ARCMSR_CCB_ABORTED;
 				arcmsr_ccb_complete(ccb, 1);
 			}
 		}
+		atomic_set(&acb->ccboutstandingcount, 0);
 		/* enable all outbound interrupt */
 		arcmsr_enable_outbound_ints(acb, intmask_org);
+		return rtnval;
 	}
+	return rtnval;
 }
 
 static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
 {
 	struct AdapterControlBlock *acb =
 		(struct AdapterControlBlock *)cmd->device->host->hostdata;
-	int i;
+	int retry = 0;
 
-	acb->num_resets++;
+	if (acb->acb_flags & ACB_F_BUS_RESET)
+		return SUCCESS;
+
+	printk(KERN_NOTICE "arcmsr%d: bus reset ..... \n", acb->adapter_index);
 	acb->acb_flags |= ACB_F_BUS_RESET;
-	for (i = 0; i < 400; i++) {
-		if (!atomic_read(&acb->ccboutstandingcount))
+	acb->num_resets++;
+	while (atomic_read(&acb->ccboutstandingcount) != 0 && retry < 4) {
+		arcmsr_interrupt(acb);
+		retry++;
+	}
+
+	if (arcmsr_iop_reset(acb)) {
+		switch (acb->adapter_type) {
+		case ACB_ADAPTER_TYPE_A: {
+			printk(KERN_NOTICE "arcmsr%d: do hardware bus reset, num_resets = %d num_aborts = %d \n",
+				acb->adapter_index, acb->num_resets, acb->num_aborts);
+			arcmsr_hardware_reset(acb);
+			acb->acb_flags |= ACB_F_FIRMWARE_TRAP;
+			acb->acb_flags &= ~ACB_F_IOP_INITED;
+			#ifdef CONFIG_SCSI_ARCMSR_RESET
+			struct MessageUnit_A __iomem *reg = acb->pmuA;
+			uint32_t intmask_org, outbound_doorbell;
+			int retry_count = 0;
+sleep_again:
+			arcmsr_sleep_for_bus_reset(cmd);
+			if ((readl(&reg->outbound_msgaddr1) &
+			ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
+			printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry=%d \n",
+			acb->host->host_no, retry_count);
+			if (retry_count > retrycount) {
+				printk(KERN_NOTICE "arcmsr%d: hardware bus reset and return busy, retry aborted \n",
+				acb->host->host_no);
+			return SUCCESS;
+			}
+			retry_count++;
+			goto sleep_again;
+			}
+			acb->acb_flags &= ~ACB_F_FIRMWARE_TRAP;
+			acb->acb_flags |= ACB_F_IOP_INITED;
+			acb->acb_flags &= ~ACB_F_BUS_RESET;
+			printk(KERN_NOTICE "arcmsr%d: hardware bus reset and reset ok \n",
+				acb->host->host_no);
+			/* disable all outbound interrupt */
+			intmask_org = arcmsr_disable_outbound_ints(acb);
+			arcmsr_get_firmware_spec(acb, 1);
+			/*start	background rebuild*/
+			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);
+			init_timer(&acb->eternal_timer);
+			acb->eternal_timer.expires = jiffies + msecs_to_jiffies(20*HZ);
+			acb->eternal_timer.data = (unsigned long) acb;
+			acb->eternal_timer.function = &arcmsr_request_device_map;
+			add_timer(&acb->eternal_timer);
+			#endif
+		}
 			break;
-		arcmsr_interrupt(acb);/* FIXME: need spinlock */
-		msleep(25);
+		case ACB_ADAPTER_TYPE_B: {
 	}
-	arcmsr_iop_reset(acb);
+		}
+	} else {
 	acb->acb_flags &= ~ACB_F_BUS_RESET;
+	}
 	return SUCCESS;
 }
 
@@ -2277,98 +2692,3 @@ static const char *arcmsr_info(struct Scsi_Host *host)
 			ARCMSR_DRIVER_VERSION);
 	return buf;
 }
-#ifdef CONFIG_SCSI_ARCMSR_AER
-static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev)
-{
-	struct Scsi_Host *host = pci_get_drvdata(pdev);
-	struct AdapterControlBlock *acb =
-		(struct AdapterControlBlock *) host->hostdata;
-	uint32_t intmask_org;
-	int i, j;
-
-	if (pci_enable_device(pdev)) {
-		return PCI_ERS_RESULT_DISCONNECT;
-	}
-	pci_set_master(pdev);
-	intmask_org = arcmsr_disable_outbound_ints(acb);
-	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
-			   ACB_F_MESSAGE_RQBUFFER_CLEARED |
-			   ACB_F_MESSAGE_WQBUFFER_READED);
-	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;
-	for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
-		for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
-			acb->devstate[i][j] = ARECA_RAID_GONE;
-
-	arcmsr_wait_firmware_ready(acb);
-	arcmsr_iop_confirm(acb);
-       /* disable all outbound interrupt */
-	arcmsr_get_firmware_spec(acb);
-	/*start background rebuild*/
-	arcmsr_start_adapter_bgrb(acb);
-	/* empty doorbell Qbuffer if door bell ringed */
-	arcmsr_clear_doorbell_queue_buffer(acb);
-	arcmsr_enable_eoi_mode(acb);
-	/* enable outbound Post Queue,outbound doorbell Interrupt */
-	arcmsr_enable_outbound_ints(acb, intmask_org);
-	acb->acb_flags |= ACB_F_IOP_INITED;
-
-	pci_enable_pcie_error_reporting(pdev);
-	return PCI_ERS_RESULT_RECOVERED;
-}
-
-static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev)
-{
-	struct Scsi_Host *host = pci_get_drvdata(pdev);
-	struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata;
-	struct CommandControlBlock *ccb;
-	uint32_t intmask_org;
-	int i = 0;
-
-	if (atomic_read(&acb->ccboutstandingcount) != 0) {
-		/* talk to iop 331 outstanding command aborted */
-		arcmsr_abort_allcmd(acb);
-		/* wait for 3 sec for all command aborted*/
-		ssleep(3);
-		/* disable all outbound interrupt */
-		intmask_org = arcmsr_disable_outbound_ints(acb);
-		/* clear all outbound posted Q */
-		arcmsr_done4abort_postqueue(acb);
-		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
-			ccb = acb->pccb_pool[i];
-			if (ccb->startdone == ARCMSR_CCB_START) {
-				ccb->startdone = ARCMSR_CCB_ABORTED;
-				arcmsr_ccb_complete(ccb, 1);
-			}
-		}
-		/* enable all outbound interrupt */
-		arcmsr_enable_outbound_ints(acb, intmask_org);
-	}
-	pci_disable_device(pdev);
-}
-
-static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev)
-{
-			struct Scsi_Host *host = pci_get_drvdata(pdev);
-			struct AdapterControlBlock *acb	= \
-				(struct AdapterControlBlock *)host->hostdata;
-
-			arcmsr_stop_adapter_bgrb(acb);
-			arcmsr_flush_adapter_cache(acb);
-}
-
-static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
-						pci_channel_state_t state)
-{
-	switch (state) {
-	case pci_channel_io_frozen:
-			arcmsr_pci_ers_need_reset_forepart(pdev);
-			return PCI_ERS_RESULT_NEED_RESET;
-	case pci_channel_io_perm_failure:
-			arcmsr_pci_ers_disconnect_forepart(pdev);
-			return PCI_ERS_RESULT_DISCONNECT;
-			break;
-	default:
-			return PCI_ERS_RESULT_NEED_RESET;
-	  }
-}
-#endif