* [PATCH 2/3] SCSI: Support Type C RAID controller
@ 2010-06-21 3:02 Nick Cheng
2010-06-21 14:16 ` James Bottomley
0 siblings, 1 reply; 5+ messages in thread
From: Nick Cheng @ 2010-06-21 3:02 UTC (permalink / raw)
To: linux-scsi; +Cc: James.Bottomley, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 143 bytes --]
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 >
---
[-- Attachment #2: patch1_2 --]
[-- Type: application/octet-stream, Size: 74004 bytes --]
diff -Naurp --ignore-blank-lines --ignore-all-space --ignore-space-change a/linux//drivers/scsi/arcmsr/arcmsr.h b/linux/drivers/scsi/arcmsr/arcmsr.h
--- a/linux//drivers/scsi/arcmsr/arcmsr.h 2010-06-21 18:02:52.000000000 +0800
+++ b/linux/drivers/scsi/arcmsr/arcmsr.h 2010-06-21 18:05:16.000000000 +0800
@@ -48,7 +47,7 @@ struct device_attribute;
/*The limit of outstanding scsi command that firmware can handle*/
#define ARCMSR_MAX_OUTSTANDING_CMD 256
#define ARCMSR_MAX_FREECCB_NUM 320
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2009/12/09"
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/02/02"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
@@ -61,6 +60,7 @@ struct device_attribute;
#define ARCMSR_MAX_HBB_POSTQUEUE 264
#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */
#define ARCMSR_CDB_SG_PAGE_LENGTH 256
+#define SCSI_CMD_ARECA_SPECIFIC 0xE1
#ifndef PCI_DEVICE_ID_ARECA_1880
#define PCI_DEVICE_ID_ARECA_1880 0x1880
#endif
@@ -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
/*
************************************************************************
@@ -274,6 +278,61 @@ struct FIRMWARE_INFO
/* iop message_rwbuffer for message command */
#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00
/*
+************************************************************************
+** SPEC. for Areca HBC adapter
+************************************************************************
+*/
+#define ARCMSR_HBC_ISR_THROTTLING_LEVEL 12
+#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE 20
+/* Host Interrupt Mask */
+#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK 0x00000001 /* When clear, the Utility_A interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK 0x00000004 /* When clear, the General Outbound Doorbell interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK 0x00000008 /* When clear, the Outbound Post List FIFO Not Empty interrupt routes to the host.*/
+#define ARCMSR_HBCMU_ALL_INTMASKENABLE 0x0000000D /* disable all ISR */
+/* Host Interrupt Status */
+#define ARCMSR_HBCMU_UTILITY_A_ISR 0x00000001
+ /*
+ ** Set when the Utility_A Interrupt bit is set in the Outbound Doorbell Register.
+ ** It clears by writing a 1 to the Utility_A bit in the Outbound Doorbell Clear Register or through automatic clearing (if enabled).
+ */
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR 0x00000004
+ /*
+ ** Set if Outbound Doorbell register bits 30:1 have a non-zero
+ ** value. This bit clears only when Outbound Doorbell bits
+ ** 30:1 are ALL clear. Only a write to the Outbound Doorbell
+ ** Clear register clears bits in the Outbound Doorbell register.
+ */
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR 0x00000008
+ /*
+ ** Set whenever the Outbound Post List Producer/Consumer
+ ** Register (FIFO) is not empty. It clears when the Outbound
+ ** Post List FIFO is empty.
+ */
+#define ARCMSR_HBCMU_SAS_ALL_INT 0x00000010
+ /*
+ ** This bit indicates a SAS interrupt from a source external to
+ ** the PCIe core. This bit is not maskable.
+ */
+ /* DoorBell*/
+#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK 0x00000002
+#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK 0x00000004
+ /*inbound message 0 ready*/
+#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE 0x00000008
+ /*more than 12 request completed in a time*/
+#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING 0x00000010
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK 0x00000002
+ /*outbound DATA WRITE isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR 0x00000002
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK 0x00000004
+ /*outbound DATA READ isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_DOORBELL_CLEAR 0x00000004
+ /*outbound message 0 ready*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE 0x00000008
+ /*outbound message cmd isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR 0x00000008
+ /*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/
+#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK 0x80000000
+/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
*******************************************************************************
@@ -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_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
@@ -460,13 +598,13 @@ 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
@@ -480,10 +618,10 @@ struct CommandControlBlock
#define ARCMSR_CCB_ILLEGAL 0xFFFF
#if BITS_PER_LONG == 64
/* ======================512+64 bytes======================== */
- uint32_t reserved[6]; /*24 byte*/
+ uint32_t reserved[5]; /*24 byte*/
#else
/* ======================512+32 bytes======================== */
- uint32_t reserved[2]; /*8 byte*/
+ uint32_t reserved; /*8 byte*/
#endif
/* ======================================================= */
struct ARCMSR_CDB arcmsr_cdb;
diff -Naurp --ignore-blank-lines --ignore-all-space --ignore-space-change a/linux//drivers/scsi/arcmsr/arcmsr_hba.c b/linux/drivers/scsi/arcmsr/arcmsr_hba.c
--- a/linux//drivers/scsi/arcmsr/arcmsr_hba.c 2010-06-21 18:02:41.000000000 +0800
+++ b/linux/drivers/scsi/arcmsr/arcmsr_hba.c 2010-06-21 18:05:10.000000000 +0800
@@ -71,11 +71,11 @@
#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(struc
static void arcmsr_request_device_map(unsigned long pacb);
static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb);
static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb);
static void arcmsr_message_isr_bh_fn(struct work_struct *work);
static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
-
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB);
+static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
@@ -119,7 +121,7 @@ static int arcmsr_adjust_disk_queue_dept
static struct scsi_host_template arcmsr_scsi_host_template = {
.module = THIS_MODULE,
- .name = "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter"
+ .name = "ARCMSR ARECA SATA/SAS RAID Controller"
ARCMSR_DRIVER_VERSION,
.info = arcmsr_info,
.queuecommand = arcmsr_queue_command,
@@ -165,17 +167,40 @@ static struct pci_driver arcmsr_pci_driv
.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);
+ }
+ }
-static void arcmsr_free_mu(struct AdapterControlBlock *acb)
+ isleep = sleeptime % 10;
+ if (isleep > 0) {
+ msleep(isleep*1000);
+ }
+ printk(KERN_NOTICE "wake-up\n");
+ return 0;
+}
+
+static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A:
+ case ACB_ADAPTER_TYPE_C:
break;
case ACB_ADAPTER_TYPE_B:{
- struct MessageUnit_B *reg = acb->pmuB;
dma_free_coherent(&acb->pdev->dev,
sizeof(struct MessageUnit_B),
- reg, acb->dma_coherent_handle_hbb_mu);
+ acb->pmuB, acb->dma_coherent_handle_hbb_mu);
}
}
}
@@ -208,6 +232,19 @@ static bool arcmsr_remap_pciregion(struc
}
acb->mem_base0 = mem_base0;
acb->mem_base1 = mem_base1;
+ break;
+ }
+ case ACB_ADAPTER_TYPE_C:{
+ acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+ if (!acb->pmuC) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/
+ return true;
+ }
+ break;
}
}
return true;
@@ -219,10 +256,16 @@ static void arcmsr_unmap_pciregion(struc
case ACB_ADAPTER_TYPE_A:{
iounmap(acb->pmuA);
}
+ break;
case ACB_ADAPTER_TYPE_B:{
iounmap(acb->mem_base0);
iounmap(acb->mem_base1);
}
+
+ break;
+ case ACB_ADAPTER_TYPE_C:{
+ iounmap(acb->pmuC);
+ }
}
}
@@ -270,6 +313,10 @@ static void arcmsr_define_adapter_type(s
pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
acb->dev_id = dev_id;
switch (dev_id) {
+ case 0x1880: {
+ acb->adapter_type = ACB_ADAPTER_TYPE_C;
+ }
+ break;
case 0x1201 : {
acb->adapter_type = ACB_ADAPTER_TYPE_B;
}
@@ -291,13 +337,13 @@ static uint8_t arcmsr_hba_wait_msgint_re
ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
®->outbound_intstatus);
- return 0x00;
+ return true;
}
msleep(10);
} /*max 1 seconds*/
} while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
+ return false;
}
static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
@@ -313,15 +358,32 @@ static uint8_t arcmsr_hbb_wait_msgint_re
writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
, reg->iop2drv_doorbell);
writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
- return 0x00;
+ return true;
}
msleep(10);
} /*max 1 seconds*/
} while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
+ return false;
}
+static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+ unsigned char Retries = 0x00;
+ uint32_t Index;
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->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;
@@ -326,10 +388,9 @@ static void arcmsr_flush_hba_cache(struc
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
int retry_count = 30;
-
writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->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(struc
{
struct MessageUnit_B *reg = acb->pmuB;
int retry_count = 30;
-
writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell);
do {
- if (!arcmsr_hbb_wait_msgint_ready(acb))
+ if (arcmsr_hbb_wait_msgint_ready(acb))
break;
else {
retry_count--;
@@ -356,6 +416,23 @@ static void arcmsr_flush_hbb_cache(struc
} while (retry_count != 0);
}
+static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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,21 +445,22 @@ static void arcmsr_flush_adapter_cache(s
case ACB_ADAPTER_TYPE_B: {
arcmsr_flush_hbb_cache(acb);
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_flush_hbc_cache(acb);
+ }
}
}
static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
-
void *dma_coherent;
dma_addr_t dma_coherent_handle;
struct CommandControlBlock *ccb_tmp;
int i = 0, j = 0;
dma_addr_t cdb_phyaddr;
- unsigned long roundup_ccbsize = 0;
+ unsigned long roundup_ccbsize = 0, offset;
unsigned long max_xfer_len;
unsigned long max_sg_entrys;
uint32_t firm_config_version;
@@ -395,26 +472,29 @@ static int arcmsr_alloc_ccb_pool(struct
max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
firm_config_version = acb->firm_cfg_version;
if ((firm_config_version & 0xFF) >= 3) {
- max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
+ max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */
max_sg_entrys = (max_xfer_len/4096);
}
acb->host->max_sectors = max_xfer_len/512;
acb->host->sg_tablesize = max_sg_entrys;
- roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + max_sg_entrys * sizeof(struct SG64ENTRY), 32);
- acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
+ roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+ acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32;
dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
if (!dma_coherent) {
printk(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;
+ memset(dma_coherent, 0, acb->uncache_size);
+ offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent;
+ dma_coherent_handle = dma_coherent_handle + offset;
+ dma_coherent = (struct CommandControlBlock *)dma_coherent + offset;
+ ccb_tmp = dma_coherent;
acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
- ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
+ ccb_tmp->cdb_phyaddr_pattern = ((acb->adapter_type == ACB_ADAPTER_TYPE_C) ? cdb_phyaddr : (cdb_phyaddr >> 5));
acb->pccb_pool[i] = ccb_tmp;
ccb_tmp->acb = acb;
INIT_LIST_HEAD(&ccb_tmp->list);
@@ -422,68 +502,9 @@ static int arcmsr_alloc_ccb_pool(struct
ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize);
dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
}
- break;
- }
- case ACB_ADAPTER_TYPE_B: {
-
- void *dma_coherent;
- dma_addr_t dma_coherent_handle;
- struct CommandControlBlock *ccb_tmp;
- uint32_t cdb_phyaddr;
- unsigned int roundup_ccbsize = 0;
- unsigned long max_xfer_len;
- unsigned long max_sg_entrys;
- unsigned long firm_config_version;
- unsigned long max_freeccb_num = 0;
- int i = 0, j = 0;
-
- max_freeccb_num = ARCMSR_MAX_FREECCB_NUM;
- max_xfer_len = ARCMSR_MAX_XFER_LEN;
- max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
- firm_config_version = acb->firm_cfg_version;
- if ((firm_config_version & 0xFF) >= 3) {
- max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH <<
- ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
- max_sg_entrys = (max_xfer_len/4096);/* max 4097 sg entry*/
- }
- acb->host->max_sectors = max_xfer_len / 512;
- acb->host->sg_tablesize = max_sg_entrys;
- roundup_ccbsize = roundup(sizeof(struct CommandControlBlock)+
- (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
- acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
- dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size,
- &dma_coherent_handle, GFP_KERNEL);
-
- if (!dma_coherent) {
- printk(KERN_NOTICE "DMA allocation failed...........................\n");
- return -ENOMEM;
- }
- memset(dma_coherent, 0, acb->uncache_size);
- acb->dma_coherent = dma_coherent;
- acb->dma_coherent_handle = dma_coherent_handle;
- ccb_tmp = (struct CommandControlBlock *)dma_coherent;
- acb->vir2phy_offset = (unsigned long)dma_coherent -
- (unsigned long)dma_coherent_handle;
- for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
- cdb_phyaddr = dma_coherent_handle +
- offsetof(struct CommandControlBlock, arcmsr_cdb);
- ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
- acb->pccb_pool[i] = ccb_tmp;
- ccb_tmp->acb = acb;
- INIT_LIST_HEAD(&ccb_tmp->list);
- list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp +
- roundup_ccbsize);
- dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
- }
- for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
- for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
- acb->devstate[i][j] = ARECA_RAID_GONE;
- }
- break;
- }
return 0;
}
+
static void arcmsr_message_isr_bh_fn(struct work_struct *work)
{
struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh);
@@ -563,6 +584,43 @@ static void arcmsr_message_isr_bh_fn(str
}
}
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = acb->pmuC;
+ char *acb_dev_map = (char *)acb->device_map;
+ uint32_t __iomem *signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]);
+ char __iomem *devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]);
+ int target, lun;
+ struct scsi_device *psdev;
+ char diff;
+
+ atomic_inc(&acb->rq_map_token);
+ if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+ for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
+ diff = (*acb_dev_map)^readb(devicemap);
+ if (diff != 0) {
+ char temp;
+ *acb_dev_map = readb(devicemap);
+ temp = *acb_dev_map;
+ for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+ if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
+ scsi_add_device(acb->host, 0, target, lun);
+ } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
+ psdev = scsi_device_lookup(acb->host, 0, target, lun);
+ if (psdev != NULL) {
+ scsi_remove_device(psdev);
+ scsi_device_put(psdev);
+ }
+ }
+ temp >>= 1;
+ diff >>= 1;
+ }
+ }
+ devicemap++;
+ acb_dev_map++;
+ }
+ }
+ }
}
}
@@ -662,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:
@@ -677,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, ®->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)
@@ -693,15 +749,27 @@ static uint8_t arcmsr_abort_hbb_allcmd(s
struct MessageUnit_B *reg = acb->pmuB;
writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'abort all outstanding command' timeout \n"
, acb->host->host_no);
- return 0xff;
+ return false;
}
- return 0x00;
+ return true;
+}
+static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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;
@@ -714,6 +782,11 @@ static uint8_t arcmsr_abort_allcmd(struc
case ACB_ADAPTER_TYPE_B: {
rtnval = arcmsr_abort_hbb_allcmd(acb);
}
+ break;
+
+ case ACB_ADAPTER_TYPE_C: {
+ rtnval = arcmsr_abort_hbc_allcmd(acb);
+ }
}
return rtnval;
}
@@ -721,9 +794,8 @@ static uint8_t arcmsr_abort_allcmd(struc
static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb)
{
struct MessageUnit_B *reg = pacb->pmuB;
-
writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(pacb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(pacb)) {
printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no);
return false;
}
@@ -746,7 +817,6 @@ static void arcmsr_ccb_complete(struct C
atomic_dec(&acb->ccboutstandingcount);
arcmsr_pci_unmap_dma(ccb);
ccb->startdone = ARCMSR_CCB_DONE;
- ccb->ccb_flags = 0;
spin_lock_irqsave(&acb->ccblist_lock, flags);
list_add_tail(&ccb->list, &acb->ccb_free_list);
spin_unlock_irqrestore(&acb->ccblist_lock, flags);
@@ -790,14 +857,20 @@ static u32 arcmsr_disable_outbound_ints(
writel(0, reg->iop2drv_doorbell_mask);
}
break;
+ case ACB_ADAPTER_TYPE_C:{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ /* disable all outbound interrupt */
+ orig_mask = readl(®->host_int_mask); /* disable outbound message0 int */
+ writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask);
+ }
+ break;
}
return orig_mask;
}
static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
- struct CommandControlBlock *ccb, uint32_t flag_ccb)
+ struct CommandControlBlock *ccb, bool error)
{
-
uint8_t id, lun;
id = ccb->pcmd->device->id;
lun = ccb->pcmd->device->lun;
@@ -801,7 +874,7 @@ static void arcmsr_report_ccb_state(stru
uint8_t id, lun;
id = ccb->pcmd->device->id;
lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (!error) {
if (acb->devstate[id][lun] == ARECA_RAID_GONE)
acb->devstate[id][lun] = ARECA_RAID_GOOD;
ccb->pcmd->result = DID_OK << 16;
@@ -833,9 +906,8 @@ static void arcmsr_report_ccb_state(stru
default:
printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d"
- " isr get command error done, "
- "but got unknown DeviceStatus = 0x%x \n"
+ "arcmsr%d: scsi id = %d lun = %d isr get command error done, \
+ but got unknown DeviceStatus = 0x%x \n"
, acb->host->host_no
, id
, lun
@@ -848,26 +920,22 @@ static void arcmsr_report_ccb_state(stru
}
}
-static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb)
+static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
{
- struct CommandControlBlock *ccb;
- struct ARCMSR_CDB *arcmsr_cdb;
int id, lun;
-
- arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
- ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
- if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
- if (ccb->startdone == ARCMSR_CCB_ABORTED) {
- struct scsi_cmnd *abortcmd = ccb->pcmd;
+ if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+ if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+ struct scsi_cmnd *abortcmd = pCCB->pcmd;
if (abortcmd) {
id = abortcmd->device->id;
lun = abortcmd->device->lun;
abortcmd->result |= DID_ABORT << 16;
- arcmsr_ccb_complete(ccb);
- printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
- isr got aborted command \n", acb->host->host_no, ccb);
+ arcmsr_ccb_complete(pCCB);
+ printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n",
+ acb->host->host_no, pCCB);
}
+ return;
}
printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
done acb = '0x%p'"
@@ -875,20 +943,22 @@ static void arcmsr_drain_donequeue(struc
" ccboutstandingcount = %d \n"
, acb->host->host_no
, acb
- , ccb
- , ccb->acb
- , ccb->startdone
+ , pCCB
+ , pCCB->acb
+ , pCCB->startdone
, atomic_read(&acb->ccboutstandingcount));
+ 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: {
@@ -900,7 +970,10 @@ static void arcmsr_done4abort_postqueue(
writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/
while (((flag_ccb = readl(®->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;
@@ -908,17 +981,37 @@ static void arcmsr_done4abort_postqueue(
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
/*clear all outbound posted Q*/
+ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, ®->iop2drv_doorbell); /* clear doorbell interrupt */
for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) {
writel(0, ®->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, ®->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(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+ /*need to do*/
+ flag_ccb = readl(®->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)
@@ -929,7 +1022,6 @@ static void arcmsr_remove(struct pci_dev
int poll_count = 0;
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
- scsi_host_put(host);
flush_scheduled_work();
del_timer_sync(&acb->eternal_timer);
arcmsr_disable_outbound_ints(acb);
@@ -961,8 +1053,10 @@ static void arcmsr_remove(struct pci_dev
}
free_irq(pdev->irq, acb);
arcmsr_free_ccb_pool(acb);
- arcmsr_free_mu(acb);
+ arcmsr_free_hbb_mu(acb);
+ arcmsr_unmap_pciregion(acb);
pci_release_regions(pdev);
+ scsi_host_put(host);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -1020,6 +1112,13 @@ static void arcmsr_enable_outbound_ints(
writel(mask, reg->iop2drv_doorbell_mask);
acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = acb->pmuC;
+ mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
+ writel(intmask_org & mask, ®->host_int_mask);
+ acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
+ }
}
}
@@ -1031,24 +1130,20 @@ static int arcmsr_build_ccb(struct Adapt
__le32 address_lo, address_hi;
int arccdbsize = 0x30;
__le32 length = 0;
- int i, cdb_sgcount = 0;
+ int i;
struct scatterlist *sg;
int nseg;
-
ccb->pcmd = pcmd;
memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
- arcmsr_cdb->Bus = 0;
arcmsr_cdb->TargetID = pcmd->device->id;
arcmsr_cdb->LUN = pcmd->device->lun;
arcmsr_cdb->Function = 1;
- arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
arcmsr_cdb->Context = 0;
memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
nseg = scsi_dma_map(pcmd);
- if (nseg > acb->host->sg_tablesize || nseg < 0)
+ if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0))
return FAILED;
- /* map stor port SG list to our iop SG List. */
scsi_for_each_sg(pcmd, sg, nseg, i) {
/* Get the physical address of the current data pointer */
length = cpu_to_le32(sg_dma_len(sg));
@@ -1070,23 +1165,22 @@ static int arcmsr_build_ccb(struct Adapt
psge += sizeof (struct SG64ENTRY);
arccdbsize += sizeof (struct SG64ENTRY);
}
- cdb_sgcount++;
}
- arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
+ arcmsr_cdb->sgcount = (uint8_t)nseg;
arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
if ( arccdbsize > 256)
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0] | WRITE_10 || pcmd->cmnd[0]|WRITE_12) {
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
- ccb->ccb_flags |= CCB_FLAG_WRITE;
}
+ ccb->arc_cdb_size = arccdbsize;
return SUCCESS;
}
static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
{
- uint32_t shifted_cdb_phyaddr = ccb->shifted_cdb_phyaddr;
+ uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern;
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
atomic_inc(&acb->ccboutstandingcount);
ccb->startdone = ARCMSR_CCB_START;
@@ -1096,10 +1189,10 @@ static void arcmsr_post_ccb(struct Adapt
struct MessageUnit_A __iomem *reg = acb->pmuA;
if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
- writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+ writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
®->inbound_queueport);
else {
- writel(shifted_cdb_phyaddr, ®->inbound_queueport);
+ writel(cdb_phyaddr_pattern, ®->inbound_queueport);
}
}
break;
@@ -1111,11 +1204,10 @@ static void arcmsr_post_ccb(struct Adapt
ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
writel(0, ®->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,\
®->post_qbuffer[index]);
- }
- else {
- writel(shifted_cdb_phyaddr, ®->post_qbuffer[index]);
+ } else {
+ writel(cdb_phyaddr_pattern, ®->post_qbuffer[index]);
}
index++;
index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
@@ -1123,6 +1215,19 @@ static void arcmsr_post_ccb(struct Adapt
writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t ccb_post_stamp, arc_cdb_size;
+
+ arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size;
+ ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1);
+ if (acb->cdb_phyaddr_hi32) {
+ writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high);
+ writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+ } else {
+ writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+ }
+ }
}
}
@@ -1131,8 +1236,7 @@ static void arcmsr_stop_hba_bgrb(struct
struct MessageUnit_A __iomem *reg = acb->pmuA;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->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);
@@ -1145,13 +1249,26 @@ static void arcmsr_stop_hbb_bgrb(struct
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
, acb->host->host_no);
}
}
+static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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) {
@@ -1164,22 +1281,16 @@ static void arcmsr_stop_adapter_bgrb(str
arcmsr_stop_hbb_bgrb(acb);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_stop_hbc_bgrb(acb);
+ }
}
}
static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
{
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
- dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
- iounmap(acb->pmuA);
- }
- break;
- case ACB_ADAPTER_TYPE_B: {
dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
}
- }
-}
void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
{
@@ -1195,6 +1306,10 @@ void arcmsr_iop_message_read(struct Adap
writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell);
+ }
}
}
@@ -1220,6 +1335,15 @@ static void arcmsr_iop_message_wrote(str
writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ /*
+ ** push inbound doorbell tell iop, driver data write ok
+ ** and wait reply on next hwinterrupt for next Qbuffer post
+ */
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, ®->inbound_doorbell);
+ }
+ break;
}
}
@@ -1240,6 +1363,10 @@ struct QBUFFER __iomem *arcmsr_get_iop_r
qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+ qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer;
+ }
}
return qbuffer;
}
@@ -1261,6 +1387,11 @@ static struct QBUFFER __iomem *arcmsr_ge
pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ pqbuffer = (struct QBUFFER __iomem *)®->message_wbuffer;
+ }
+
}
return pqbuffer;
}
@@ -1345,14 +1474,42 @@ static void arcmsr_hba_doorbell_isr(stru
arcmsr_iop2drv_data_read_handle(acb);
}
}
-
+static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
+{
+ uint32_t outbound_doorbell;
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ /*
+ *******************************************************************
+ ** Maybe here we need to check wrqbuffer_lock is lock or not
+ ** DOORBELL: din! don!
+ ** check if there are any mail need to pack from firmware
+ *******************************************************************
+ */
+ outbound_doorbell = readl(®->outbound_doorbell);
+ writel(outbound_doorbell, ®->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(®->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);
}
}
@@ -1361,17 +1518,51 @@ static void arcmsr_hbb_postqueue_isr(str
uint32_t index;
uint32_t flag_ccb;
struct MessageUnit_B *reg = acb->pmuB;
-
+ struct ARCMSR_CDB *pARCMSR_CDB;
+ struct CommandControlBlock *pCCB;
+ bool error;
index = reg->doneq_index;
-
while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) {
writel(0, ®->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
@@ -1395,6 +1586,23 @@ static void arcmsr_hbb_message_isr(struc
writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
+/*
+**********************************************************************************
+** Handle a message interrupt
+**
+** The only message interrupt we expect is in response to a query for the
+** current adapter config.
+** We want this in order to compare the drivemap so that we can detect newly-attached drives.
+**********************************************************************************
+*/
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_C *reg = acb->pmuC;
+ /*clear interrupt and message state*/
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear);
+ schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
+
static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
{
uint32_t outbound_intstatus;
@@ -1447,7 +1653,31 @@ static int arcmsr_handle_hbb_isr(struct
/* 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)
@@ -1466,6 +1696,11 @@ static irqreturn_t arcmsr_interrupt(stru
}
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ if (arcmsr_handle_hbc_isr(acb)) {
+ return IRQ_NONE;
+ }
+ }
}
return IRQ_HANDLED;
}
@@ -1877,7 +2107,10 @@ static int arcmsr_queue_command(struct s
if (atomic_read(&acb->ccboutstandingcount) >=
ARCMSR_MAX_OUTSTANDING_CMD)
return SCSI_MLQUEUE_HOST_BUSY;
-
+ if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) {
+ printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n");
+ return 0;
+ }
ccb = arcmsr_get_freeccb(acb);
if (!ccb)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1900,9 +2133,8 @@ static bool arcmsr_get_hba_config(struct
char __iomem *iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]);
char __iomem *iop_device_map = (char __iomem *) (®->message_rwbuffer[21]);
int count;
-
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->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;
@@ -1978,7 +2210,7 @@ static bool arcmsr_get_hbb_config(struct
iop_device_map = (char __iomem *)(®->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;
@@ -2025,12 +2257,73 @@ static bool arcmsr_get_hbb_config(struct
/*firm_ide_channels,4,16-19*/
return true;
}
+
+static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB)
+{
+ uint32_t intmask_org, Index, firmware_state = 0;
+ struct MessageUnit_C *reg = pACB->pmuC;
+ char *acb_firm_model = pACB->firm_model;
+ char *acb_firm_version = pACB->firm_version;
+ char *iop_firm_model = (char *)(®->msgcode_rwbuffer[15]); /*firm_model,15,60-67*/
+ char *iop_firm_version = (char *)(®->msgcode_rwbuffer[17]); /*firm_version,17,68-83*/
+ int count;
+ /* disable all outbound interrupt */
+ intmask_org = readl(®->host_int_mask); /* disable outbound message0 int */
+ writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask);
+ /* wait firmware ready */
+ do {
+ firmware_state = readl(®->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+ /* post "get config" instruction */
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell);
+ /* wait message ready */
+ for (Index = 0; Index < 2000; Index++) {
+ if (readl(®->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->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(®->msgcode_rwbuffer[1]); /*firm_request_len,1,04-07*/
+ pACB->firm_numbers_queue = readl(®->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/
+ pACB->firm_sdram_size = readl(®->msgcode_rwbuffer[3]); /*firm_sdram_size,3,12-15*/
+ pACB->firm_hd_channels = readl(®->msgcode_rwbuffer[4]); /*firm_ide_channels,4,16-19*/
+ pACB->firm_cfg_version = readl(®->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,
@@ -2041,7 +2334,7 @@ static int arcmsr_polling_hba_ccbdone(st
struct ARCMSR_CDB *arcmsr_cdb;
uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
int rtn;
-
+ bool error;
polling_hba_ccb_retry:
poll_count++;
outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable;
@@ -2052,6 +2345,7 @@ static int arcmsr_polling_hba_ccbdone(st
rtn = SUCCESS;
break;
} else {
+ msleep(25);
if (poll_count > 100) {
rtn = FAILED;
break;
@@ -2081,9 +2375,9 @@ static int arcmsr_polling_hba_ccbdone(st
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
- } else {
- arcmsr_report_ccb_state(acb, ccb, flag_ccb);
}
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_report_ccb_state(acb, ccb, error);
}
return rtn;
}
@@ -2096,7 +2390,7 @@ static int arcmsr_polling_hbb_ccbdone(st
struct CommandControlBlock *ccb;
uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
int index, rtn;
-
+ bool error;
polling_hbb_ccb_retry:
poll_count++;
/* clear doorbell interrupt */
@@ -2144,13 +2438,69 @@ static int arcmsr_polling_hbb_ccbdone(st
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
- } else {
- arcmsr_report_ccb_state(acb, ccb, flag_ccb);
}
- } /*drain reply FIFO*/
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_report_ccb_state(acb, ccb, error);
+ }
return rtn;
}
+static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t flag_ccb, ccb_cdb_phy;
+ struct ARCMSR_CDB *arcmsr_cdb;
+ bool error;
+ struct CommandControlBlock *pCCB;
+ uint32_t poll_ccb_done = 0, poll_count = 0;
+ int rtn;
+polling_hbc_ccb_retry:
+ poll_count++;
+ while (1) {
+ if ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) {
+ if (poll_ccb_done) {
+ rtn = SUCCESS;
+ break;
+ } else {
+ msleep(25);
+ if (poll_count > 100) {
+ rtn = FAILED;
+ break;
+ }
+ goto polling_hbc_ccb_retry;
+ }
+ }
+ flag_ccb = readl(®->outbound_queueport_low);
+ ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/
+ pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+ poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
+ /* check ifcommand done with no error*/
+ if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+ if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+ printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+ " poll command abort successfully \n"
+ , acb->host->host_no
+ , pCCB->pcmd->device->id
+ , pCCB->pcmd->device->lun
+ , pCCB);
+ pCCB->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(pCCB);
+ continue;
+ }
+ printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n"
+ , acb->host->host_no
+ , pCCB
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+ arcmsr_report_ccb_state(acb, pCCB, error);
+ }
+ return rtn;
+}
static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
@@ -2165,6 +2515,10 @@ static int arcmsr_polling_ccbdone(struct
case ACB_ADAPTER_TYPE_B: {
rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb);
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb);
+ }
}
return rtn;
}
@@ -2182,6 +2536,7 @@ static int arcmsr_iop_confirm(struct Ada
dma_coherent_handle = acb->dma_coherent_handle;
cdb_phyaddr = (uint32_t)(dma_coherent_handle);
cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
/*
***********************************************************************
** if adapter type B, set window of "post command Q"
@@ -2199,7 +2554,7 @@ static int arcmsr_iop_confirm(struct Ada
writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]);
writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
®->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);
@@ -2220,7 +2575,7 @@ static int arcmsr_iop_confirm(struct Ada
reg->postq_index = 0;
reg->doneq_index = 0;
writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
acb->host->host_no);
return 1;
@@ -2239,7 +2594,7 @@ static int arcmsr_iop_confirm(struct Ada
writel(1056, rwbuffer);
writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
timeout \n",acb->host->host_no);
return 1;
@@ -2248,6 +2603,27 @@ static int arcmsr_iop_confirm(struct Ada
arcmsr_enable_outbound_ints(acb, intmask_org);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ if (cdb_phyaddr_hi32 != 0) {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+
+ if (cdb_phyaddr_hi32 != 0) {
+ unsigned char Retries = 0x00;
+ do {
+ printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32);
+ } while (Retries++ < 100);
+ }
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->msgcode_rwbuffer[0]);
+ writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]);
+ writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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;
}
@@ -2274,6 +2649,12 @@ static void arcmsr_wait_firmware_ready(s
writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ do {
+ firmware_state = readl(®->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+ }
}
}
@@ -2316,6 +2696,26 @@ static void arcmsr_request_hbb_device_ma
return;
}
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+ return;
+ } else {
+ acb->fw_flag = FW_NORMAL;
+ if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
+ atomic_set(&acb->rq_map_token, 16);
+ }
+ atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+ if (atomic_dec_and_test(&acb->rq_map_token))
+ return;
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell);
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+ }
+ return;
+}
+
static void arcmsr_request_device_map(unsigned long pacb)
{
struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
@@ -2329,6 +2728,9 @@ static void arcmsr_request_device_map(un
arcmsr_request_hbb_device_map(acb);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_request_hbc_device_map(acb);
+ }
}
}
@@ -2337,7 +2739,7 @@ static void arcmsr_start_hba_bgrb(struct
struct MessageUnit_A __iomem *reg = acb->pmuA;
acb->acb_flags |= ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->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);
}
@@ -2348,12 +2750,24 @@ static void arcmsr_start_hbb_bgrb(struct
struct MessageUnit_B *reg = acb->pmuB;
acb->acb_flags |= ACB_F_MSG_START_BGRB;
writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
rebulid' timeout \n",acb->host->host_no);
}
}
+static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+ pACB->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell);
+ if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+ rebulid' timeout \n", pACB->host->host_no);
+ }
+ return;
+}
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@@ -2363,6 +2777,8 @@ static void arcmsr_start_adapter_bgrb(st
case ACB_ADAPTER_TYPE_B:
arcmsr_start_hbb_bgrb(acb);
break;
+ case ACB_ADAPTER_TYPE_C:
+ arcmsr_start_hbc_bgrb(acb);
}
}
@@ -2388,6 +2804,14 @@ static void arcmsr_clear_doorbell_queue_
/* let IOP know data has been read */
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t outbound_doorbell;
+ /* empty doorbell Qbuffer if door bell ringed */
+ outbound_doorbell = readl(®->outbound_doorbell);
+ writel(outbound_doorbell, ®->outbound_doorbell_clear);
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell);
+ }
}
}
@@ -2400,12 +2824,14 @@ static void arcmsr_enable_eoi_mode(struc
{
struct MessageUnit_B *reg = acb->pmuB;
writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell);
- if(arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
return;
}
}
break;
+ case ACB_ADAPTER_TYPE_C:
+ return;
}
return;
}
@@ -2413,21 +2839,33 @@ static void arcmsr_enable_eoi_mode(struc
static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
{
uint8_t value[64];
- int i;
- struct MessageUnit_A __iomem *reg = acb->pmuA;
-
+ int i, count = 0;
+ struct MessageUnit_A __iomem *pmuA = acb->pmuA;
+ struct MessageUnit_C __iomem *pmuC = acb->pmuC;
+ u32 temp = 0;
/* backup pci config data */
- printk(KERN_ERR "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
+ printk(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, ®->reserved1[0]);
+ writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]);
+ } else if ((acb->dev_id == 0x1880)) {
+ do {
+ count++;
+ writel(0xF, &pmuC->write_sequence);
+ writel(0x4, &pmuC->write_sequence);
+ writel(0xB, &pmuC->write_sequence);
+ writel(0x2, &pmuC->write_sequence);
+ writel(0x7, &pmuC->write_sequence);
+ writel(0xD, &pmuC->write_sequence);
+ } while ((((temp = readl(&pmuC->host_diagnostic)) | ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5));
+ writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic);
} else {
pci_write_config_byte(acb->pdev, 0x84, 0x20);
}
- msleep(1000);
+ msleep(2000);
/* write back pci config data */
for (i=0;i<64;i++) {
pci_write_config_byte(acb->pdev, i, value[i]);
@@ -2435,29 +2873,6 @@ static void arcmsr_hardware_reset(struct
msleep(1000);
return;
}
-/*
-****************************************************************************
-****************************************************************************
-*/
-int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
-{
- struct Scsi_Host *shost = NULL;
- int i, isleep;
-
- shost = cmd->device->host;
- isleep = sleeptime / 10;
- if (isleep > 0) {
- for (i = 0; i < isleep; i ++) {
- msleep(10000);
- }
- }
-
- isleep = sleeptime % 10;
- if (isleep > 0) {
- msleep(isleep*1000);
- }
- return 0;
-}
static void arcmsr_iop_init(struct AdapterControlBlock *acb)
{
uint32_t intmask_org;
@@ -2510,24 +2924,22 @@ static int arcmsr_bus_reset(struct scsi_
uint32_t intmask_org, outbound_doorbell;
int retry_count = 0;
int rtn = FAILED;
-
acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
- printk(KERN_ERR "arcmsr: executing eh bus reset .....num_resets = %d, \
- num_aborts = %d \n", acb->num_resets, acb->num_aborts);
+ printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts);
acb->num_resets++;
switch(acb->adapter_type){
case ACB_ADAPTER_TYPE_A:{
if (acb->acb_flags & ACB_F_BUS_RESET) {
long timeout;
- timeout = wait_event_timeout(wait_q,
- (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
+ printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n");
+ timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
if (timeout) {
return SUCCESS;
}
}
acb->acb_flags |= ACB_F_BUS_RESET;
- if (arcmsr_iop_reset(acb)) {
+ if (!arcmsr_iop_reset(acb)) {
struct MessageUnit_A __iomem *reg;
reg = acb->pmuA;
arcmsr_hardware_reset(acb);
@@ -2535,12 +2947,10 @@ static int arcmsr_bus_reset(struct scsi_
sleep_again:
arcmsr_sleep_for_bus_reset(cmd);
if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
- printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
- retry=%d \n", acb->host->host_no, retry_count);
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count);
if (retry_count > retrycount) {
acb->fw_flag = FW_DEADLOCK;
- printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
- RETRY TERMINATED!! \n", acb->host->host_no);
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no);
return FAILED;
}
retry_count++;
@@ -2567,7 +2977,7 @@ 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) {
@@ -2591,7 +3001,7 @@ sleep_again:
}
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 {
@@ -2613,6 +3023,77 @@ sleep_again:
}
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(®->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(®->outbound_doorbell);
+ writel(outbound_doorbell, ®->outbound_doorbell_clear); /*clear interrupt */
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->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;
@@ -2622,9 +3103,7 @@ static int arcmsr_abort_one_cmd(struct A
struct CommandControlBlock *ccb)
{
int rtn;
- spin_lock_irq(&acb->eh_lock);
rtn = arcmsr_polling_ccbdone(acb, ccb);
- spin_unlock_irq(&acb->eh_lock);
return rtn;
}
@@ -2692,6 +3169,7 @@ static const char *arcmsr_info(struct Sc
case PCI_DEVICE_ID_ARECA_1381:
case PCI_DEVICE_ID_ARECA_1680:
case PCI_DEVICE_ID_ARECA_1681:
+ case PCI_DEVICE_ID_ARECA_1880:
type = "SAS";
break;
default:
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH 2/3] SCSI: Support Type C RAID controller
@ 2010-06-18 7:39 Nick Cheng
2010-06-20 14:18 ` James Bottomley
0 siblings, 1 reply; 5+ messages in thread
From: Nick Cheng @ 2010-06-18 7:39 UTC (permalink / raw)
To: linux-scsi; +Cc: James.Bottomley, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 143 bytes --]
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 >
---
[-- Attachment #2: patch2_3 --]
[-- Type: application/octet-stream, Size: 74000 bytes --]
diff -Naurp --ignore-blank-lines --ignore-all-space --ignore-space-change a/linux/drivers/scsi/arcmsr/arcmsr.h b/linux/drivers/scsi/arcmsr/arcmsr.h
--- a/linux/drivers/scsi/arcmsr/arcmsr.h 2010-06-18 23:06:38.000000000 +0800
+++ b/linux/drivers/scsi/arcmsr/arcmsr.h 2010-06-18 23:07:46.000000000 +0800
@@ -48,7 +47,7 @@ struct device_attribute;
/*The limit of outstanding scsi command that firmware can handle*/
#define ARCMSR_MAX_OUTSTANDING_CMD 256
#define ARCMSR_MAX_FREECCB_NUM 320
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2009/12/09"
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/02/02"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
@@ -61,6 +60,7 @@ struct device_attribute;
#define ARCMSR_MAX_HBB_POSTQUEUE 264
#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */
#define ARCMSR_CDB_SG_PAGE_LENGTH 256
+#define SCSI_CMD_ARECA_SPECIFIC 0xE1
#ifndef PCI_DEVICE_ID_ARECA_1880
#define PCI_DEVICE_ID_ARECA_1880 0x1880
#endif
@@ -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
/*
************************************************************************
@@ -274,6 +278,61 @@ struct FIRMWARE_INFO
/* iop message_rwbuffer for message command */
#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00
/*
+************************************************************************
+** SPEC. for Areca HBC adapter
+************************************************************************
+*/
+#define ARCMSR_HBC_ISR_THROTTLING_LEVEL 12
+#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE 20
+/* Host Interrupt Mask */
+#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK 0x00000001 /* When clear, the Utility_A interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK 0x00000004 /* When clear, the General Outbound Doorbell interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK 0x00000008 /* When clear, the Outbound Post List FIFO Not Empty interrupt routes to the host.*/
+#define ARCMSR_HBCMU_ALL_INTMASKENABLE 0x0000000D /* disable all ISR */
+/* Host Interrupt Status */
+#define ARCMSR_HBCMU_UTILITY_A_ISR 0x00000001
+ /*
+ ** Set when the Utility_A Interrupt bit is set in the Outbound Doorbell Register.
+ ** It clears by writing a 1 to the Utility_A bit in the Outbound Doorbell Clear Register or through automatic clearing (if enabled).
+ */
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR 0x00000004
+ /*
+ ** Set if Outbound Doorbell register bits 30:1 have a non-zero
+ ** value. This bit clears only when Outbound Doorbell bits
+ ** 30:1 are ALL clear. Only a write to the Outbound Doorbell
+ ** Clear register clears bits in the Outbound Doorbell register.
+ */
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR 0x00000008
+ /*
+ ** Set whenever the Outbound Post List Producer/Consumer
+ ** Register (FIFO) is not empty. It clears when the Outbound
+ ** Post List FIFO is empty.
+ */
+#define ARCMSR_HBCMU_SAS_ALL_INT 0x00000010
+ /*
+ ** This bit indicates a SAS interrupt from a source external to
+ ** the PCIe core. This bit is not maskable.
+ */
+ /* DoorBell*/
+#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK 0x00000002
+#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK 0x00000004
+ /*inbound message 0 ready*/
+#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE 0x00000008
+ /*more than 12 request completed in a time*/
+#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING 0x00000010
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK 0x00000002
+ /*outbound DATA WRITE isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR 0x00000002
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK 0x00000004
+ /*outbound DATA READ isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_DOORBELL_CLEAR 0x00000004
+ /*outbound message 0 ready*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE 0x00000008
+ /*outbound message cmd isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR 0x00000008
+ /*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/
+#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK 0x80000000
+/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
*******************************************************************************
@@ -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_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
@@ -460,13 +598,13 @@ 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
@@ -480,10 +618,10 @@ struct CommandControlBlock
#define ARCMSR_CCB_ILLEGAL 0xFFFF
#if BITS_PER_LONG == 64
/* ======================512+64 bytes======================== */
- uint32_t reserved[6]; /*24 byte*/
+ uint32_t reserved[5]; /*24 byte*/
#else
/* ======================512+32 bytes======================== */
- uint32_t reserved[2]; /*8 byte*/
+ uint32_t reserved; /*8 byte*/
#endif
/* ======================================================= */
struct ARCMSR_CDB arcmsr_cdb;
diff -Naurp --ignore-blank-lines --ignore-all-space --ignore-space-change a/linux/drivers/scsi/arcmsr/arcmsr_hba.c b/linux/drivers/scsi/arcmsr/arcmsr_hba.c
--- a/linux/drivers/scsi/arcmsr/arcmsr_hba.c 2010-06-18 23:06:48.000000000 +0800
+++ b/linux/drivers/scsi/arcmsr/arcmsr_hba.c 2010-06-18 23:07:54.000000000 +0800
@@ -71,11 +71,11 @@
#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(struc
static void arcmsr_request_device_map(unsigned long pacb);
static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb);
static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb);
static void arcmsr_message_isr_bh_fn(struct work_struct *work);
static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
-
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB);
+static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
@@ -119,7 +121,7 @@ static int arcmsr_adjust_disk_queue_dept
static struct scsi_host_template arcmsr_scsi_host_template = {
.module = THIS_MODULE,
- .name = "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter"
+ .name = "ARCMSR ARECA SATA/SAS RAID Controller"
ARCMSR_DRIVER_VERSION,
.info = arcmsr_info,
.queuecommand = arcmsr_queue_command,
@@ -165,17 +167,40 @@ static struct pci_driver arcmsr_pci_driv
.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);
+ }
+ }
-static void arcmsr_free_mu(struct AdapterControlBlock *acb)
+ isleep = sleeptime % 10;
+ if (isleep > 0) {
+ msleep(isleep*1000);
+ }
+ printk(KERN_NOTICE "wake-up\n");
+ return 0;
+}
+
+static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A:
+ case ACB_ADAPTER_TYPE_C:
break;
case ACB_ADAPTER_TYPE_B:{
- struct MessageUnit_B *reg = acb->pmuB;
dma_free_coherent(&acb->pdev->dev,
sizeof(struct MessageUnit_B),
- reg, acb->dma_coherent_handle_hbb_mu);
+ acb->pmuB, acb->dma_coherent_handle_hbb_mu);
}
}
}
@@ -208,6 +232,19 @@ static bool arcmsr_remap_pciregion(struc
}
acb->mem_base0 = mem_base0;
acb->mem_base1 = mem_base1;
+ break;
+ }
+ case ACB_ADAPTER_TYPE_C:{
+ acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+ if (!acb->pmuC) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/
+ return true;
+ }
+ break;
}
}
return true;
@@ -219,10 +256,16 @@ static void arcmsr_unmap_pciregion(struc
case ACB_ADAPTER_TYPE_A:{
iounmap(acb->pmuA);
}
+ break;
case ACB_ADAPTER_TYPE_B:{
iounmap(acb->mem_base0);
iounmap(acb->mem_base1);
}
+
+ break;
+ case ACB_ADAPTER_TYPE_C:{
+ iounmap(acb->pmuC);
+ }
}
}
@@ -270,6 +313,10 @@ static void arcmsr_define_adapter_type(s
pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
acb->dev_id = dev_id;
switch (dev_id) {
+ case 0x1880: {
+ acb->adapter_type = ACB_ADAPTER_TYPE_C;
+ }
+ break;
case 0x1201 : {
acb->adapter_type = ACB_ADAPTER_TYPE_B;
}
@@ -291,13 +337,13 @@ static uint8_t arcmsr_hba_wait_msgint_re
ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
®->outbound_intstatus);
- return 0x00;
+ return true;
}
msleep(10);
} /*max 1 seconds*/
} while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
+ return false;
}
static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
@@ -313,15 +358,32 @@ static uint8_t arcmsr_hbb_wait_msgint_re
writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
, reg->iop2drv_doorbell);
writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
- return 0x00;
+ return true;
}
msleep(10);
} /*max 1 seconds*/
} while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
+ return false;
}
+static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+ unsigned char Retries = 0x00;
+ uint32_t Index;
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->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;
@@ -326,10 +388,9 @@ static void arcmsr_flush_hba_cache(struc
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
int retry_count = 30;
-
writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->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(struc
{
struct MessageUnit_B *reg = acb->pmuB;
int retry_count = 30;
-
writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell);
do {
- if (!arcmsr_hbb_wait_msgint_ready(acb))
+ if (arcmsr_hbb_wait_msgint_ready(acb))
break;
else {
retry_count--;
@@ -356,6 +416,23 @@ static void arcmsr_flush_hbb_cache(struc
} while (retry_count != 0);
}
+static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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,21 +445,22 @@ static void arcmsr_flush_adapter_cache(s
case ACB_ADAPTER_TYPE_B: {
arcmsr_flush_hbb_cache(acb);
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_flush_hbc_cache(acb);
+ }
}
}
static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
-
void *dma_coherent;
dma_addr_t dma_coherent_handle;
struct CommandControlBlock *ccb_tmp;
int i = 0, j = 0;
dma_addr_t cdb_phyaddr;
- unsigned long roundup_ccbsize = 0;
+ unsigned long roundup_ccbsize = 0, offset;
unsigned long max_xfer_len;
unsigned long max_sg_entrys;
uint32_t firm_config_version;
@@ -395,26 +472,29 @@ static int arcmsr_alloc_ccb_pool(struct
max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
firm_config_version = acb->firm_cfg_version;
if ((firm_config_version & 0xFF) >= 3) {
- max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
+ max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */
max_sg_entrys = (max_xfer_len/4096);
}
acb->host->max_sectors = max_xfer_len/512;
acb->host->sg_tablesize = max_sg_entrys;
- roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + max_sg_entrys * sizeof(struct SG64ENTRY), 32);
- acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
+ roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+ acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32;
dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
if (!dma_coherent) {
printk(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;
+ memset(dma_coherent, 0, acb->uncache_size);
+ offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent;
+ dma_coherent_handle = dma_coherent_handle + offset;
+ dma_coherent = (struct CommandControlBlock *)dma_coherent + offset;
+ ccb_tmp = dma_coherent;
acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
- ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
+ ccb_tmp->cdb_phyaddr_pattern = ((acb->adapter_type == ACB_ADAPTER_TYPE_C) ? cdb_phyaddr : (cdb_phyaddr >> 5));
acb->pccb_pool[i] = ccb_tmp;
ccb_tmp->acb = acb;
INIT_LIST_HEAD(&ccb_tmp->list);
@@ -422,68 +502,9 @@ static int arcmsr_alloc_ccb_pool(struct
ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize);
dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
}
- break;
- }
- case ACB_ADAPTER_TYPE_B: {
-
- void *dma_coherent;
- dma_addr_t dma_coherent_handle;
- struct CommandControlBlock *ccb_tmp;
- uint32_t cdb_phyaddr;
- unsigned int roundup_ccbsize = 0;
- unsigned long max_xfer_len;
- unsigned long max_sg_entrys;
- unsigned long firm_config_version;
- unsigned long max_freeccb_num = 0;
- int i = 0, j = 0;
-
- max_freeccb_num = ARCMSR_MAX_FREECCB_NUM;
- max_xfer_len = ARCMSR_MAX_XFER_LEN;
- max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
- firm_config_version = acb->firm_cfg_version;
- if ((firm_config_version & 0xFF) >= 3) {
- max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH <<
- ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
- max_sg_entrys = (max_xfer_len/4096);/* max 4097 sg entry*/
- }
- acb->host->max_sectors = max_xfer_len / 512;
- acb->host->sg_tablesize = max_sg_entrys;
- roundup_ccbsize = roundup(sizeof(struct CommandControlBlock)+
- (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
- acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
- dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size,
- &dma_coherent_handle, GFP_KERNEL);
-
- if (!dma_coherent) {
- printk(KERN_NOTICE "DMA allocation failed...........................\n");
- return -ENOMEM;
- }
- memset(dma_coherent, 0, acb->uncache_size);
- acb->dma_coherent = dma_coherent;
- acb->dma_coherent_handle = dma_coherent_handle;
- ccb_tmp = (struct CommandControlBlock *)dma_coherent;
- acb->vir2phy_offset = (unsigned long)dma_coherent -
- (unsigned long)dma_coherent_handle;
- for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
- cdb_phyaddr = dma_coherent_handle +
- offsetof(struct CommandControlBlock, arcmsr_cdb);
- ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
- acb->pccb_pool[i] = ccb_tmp;
- ccb_tmp->acb = acb;
- INIT_LIST_HEAD(&ccb_tmp->list);
- list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp +
- roundup_ccbsize);
- dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
- }
- for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
- for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
- acb->devstate[i][j] = ARECA_RAID_GONE;
- }
- break;
- }
return 0;
}
+
static void arcmsr_message_isr_bh_fn(struct work_struct *work)
{
struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh);
@@ -563,6 +584,43 @@ static void arcmsr_message_isr_bh_fn(str
}
}
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = acb->pmuC;
+ char *acb_dev_map = (char *)acb->device_map;
+ uint32_t __iomem *signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]);
+ char __iomem *devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]);
+ int target, lun;
+ struct scsi_device *psdev;
+ char diff;
+
+ atomic_inc(&acb->rq_map_token);
+ if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+ for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
+ diff = (*acb_dev_map)^readb(devicemap);
+ if (diff != 0) {
+ char temp;
+ *acb_dev_map = readb(devicemap);
+ temp = *acb_dev_map;
+ for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+ if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
+ scsi_add_device(acb->host, 0, target, lun);
+ } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
+ psdev = scsi_device_lookup(acb->host, 0, target, lun);
+ if (psdev != NULL) {
+ scsi_remove_device(psdev);
+ scsi_device_put(psdev);
+ }
+ }
+ temp >>= 1;
+ diff >>= 1;
+ }
+ }
+ devicemap++;
+ acb_dev_map++;
+ }
+ }
+ }
}
}
@@ -662,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:
@@ -677,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, ®->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)
@@ -693,15 +749,27 @@ static uint8_t arcmsr_abort_hbb_allcmd(s
struct MessageUnit_B *reg = acb->pmuB;
writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'abort all outstanding command' timeout \n"
, acb->host->host_no);
- return 0xff;
+ return false;
}
- return 0x00;
+ return true;
+}
+static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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;
@@ -714,6 +782,11 @@ static uint8_t arcmsr_abort_allcmd(struc
case ACB_ADAPTER_TYPE_B: {
rtnval = arcmsr_abort_hbb_allcmd(acb);
}
+ break;
+
+ case ACB_ADAPTER_TYPE_C: {
+ rtnval = arcmsr_abort_hbc_allcmd(acb);
+ }
}
return rtnval;
}
@@ -721,9 +794,8 @@ static uint8_t arcmsr_abort_allcmd(struc
static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb)
{
struct MessageUnit_B *reg = pacb->pmuB;
-
writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(pacb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(pacb)) {
printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no);
return false;
}
@@ -746,7 +817,6 @@ static void arcmsr_ccb_complete(struct C
atomic_dec(&acb->ccboutstandingcount);
arcmsr_pci_unmap_dma(ccb);
ccb->startdone = ARCMSR_CCB_DONE;
- ccb->ccb_flags = 0;
spin_lock_irqsave(&acb->ccblist_lock, flags);
list_add_tail(&ccb->list, &acb->ccb_free_list);
spin_unlock_irqrestore(&acb->ccblist_lock, flags);
@@ -790,14 +857,20 @@ static u32 arcmsr_disable_outbound_ints(
writel(0, reg->iop2drv_doorbell_mask);
}
break;
+ case ACB_ADAPTER_TYPE_C:{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ /* disable all outbound interrupt */
+ orig_mask = readl(®->host_int_mask); /* disable outbound message0 int */
+ writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask);
+ }
+ break;
}
return orig_mask;
}
static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
- struct CommandControlBlock *ccb, uint32_t flag_ccb)
+ struct CommandControlBlock *ccb, bool error)
{
-
uint8_t id, lun;
id = ccb->pcmd->device->id;
lun = ccb->pcmd->device->lun;
@@ -801,7 +874,7 @@ static void arcmsr_report_ccb_state(stru
uint8_t id, lun;
id = ccb->pcmd->device->id;
lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (!error) {
if (acb->devstate[id][lun] == ARECA_RAID_GONE)
acb->devstate[id][lun] = ARECA_RAID_GOOD;
ccb->pcmd->result = DID_OK << 16;
@@ -833,9 +906,8 @@ static void arcmsr_report_ccb_state(stru
default:
printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d"
- " isr get command error done, "
- "but got unknown DeviceStatus = 0x%x \n"
+ "arcmsr%d: scsi id = %d lun = %d isr get command error done, \
+ but got unknown DeviceStatus = 0x%x \n"
, acb->host->host_no
, id
, lun
@@ -848,26 +920,22 @@ static void arcmsr_report_ccb_state(stru
}
}
-static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb)
+static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
{
- struct CommandControlBlock *ccb;
- struct ARCMSR_CDB *arcmsr_cdb;
int id, lun;
-
- arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
- ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
- if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
- if (ccb->startdone == ARCMSR_CCB_ABORTED) {
- struct scsi_cmnd *abortcmd = ccb->pcmd;
+ if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+ if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+ struct scsi_cmnd *abortcmd = pCCB->pcmd;
if (abortcmd) {
id = abortcmd->device->id;
lun = abortcmd->device->lun;
abortcmd->result |= DID_ABORT << 16;
- arcmsr_ccb_complete(ccb);
- printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
- isr got aborted command \n", acb->host->host_no, ccb);
+ arcmsr_ccb_complete(pCCB);
+ printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n",
+ acb->host->host_no, pCCB);
}
+ return;
}
printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
done acb = '0x%p'"
@@ -875,20 +943,22 @@ static void arcmsr_drain_donequeue(struc
" ccboutstandingcount = %d \n"
, acb->host->host_no
, acb
- , ccb
- , ccb->acb
- , ccb->startdone
+ , pCCB
+ , pCCB->acb
+ , pCCB->startdone
, atomic_read(&acb->ccboutstandingcount));
+ 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: {
@@ -900,7 +970,10 @@ static void arcmsr_done4abort_postqueue(
writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/
while (((flag_ccb = readl(®->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;
@@ -908,17 +981,37 @@ static void arcmsr_done4abort_postqueue(
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
/*clear all outbound posted Q*/
+ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, ®->iop2drv_doorbell); /* clear doorbell interrupt */
for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) {
writel(0, ®->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, ®->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(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+ /*need to do*/
+ flag_ccb = readl(®->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)
@@ -929,7 +1022,6 @@ static void arcmsr_remove(struct pci_dev
int poll_count = 0;
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
- scsi_host_put(host);
flush_scheduled_work();
del_timer_sync(&acb->eternal_timer);
arcmsr_disable_outbound_ints(acb);
@@ -961,8 +1053,10 @@ static void arcmsr_remove(struct pci_dev
}
free_irq(pdev->irq, acb);
arcmsr_free_ccb_pool(acb);
- arcmsr_free_mu(acb);
+ arcmsr_free_hbb_mu(acb);
+ arcmsr_unmap_pciregion(acb);
pci_release_regions(pdev);
+ scsi_host_put(host);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -1020,6 +1112,13 @@ static void arcmsr_enable_outbound_ints(
writel(mask, reg->iop2drv_doorbell_mask);
acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = acb->pmuC;
+ mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
+ writel(intmask_org & mask, ®->host_int_mask);
+ acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
+ }
}
}
@@ -1031,24 +1130,20 @@ static int arcmsr_build_ccb(struct Adapt
__le32 address_lo, address_hi;
int arccdbsize = 0x30;
__le32 length = 0;
- int i, cdb_sgcount = 0;
+ int i;
struct scatterlist *sg;
int nseg;
-
ccb->pcmd = pcmd;
memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
- arcmsr_cdb->Bus = 0;
arcmsr_cdb->TargetID = pcmd->device->id;
arcmsr_cdb->LUN = pcmd->device->lun;
arcmsr_cdb->Function = 1;
- arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
arcmsr_cdb->Context = 0;
memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
nseg = scsi_dma_map(pcmd);
- if (nseg > acb->host->sg_tablesize || nseg < 0)
+ if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0))
return FAILED;
- /* map stor port SG list to our iop SG List. */
scsi_for_each_sg(pcmd, sg, nseg, i) {
/* Get the physical address of the current data pointer */
length = cpu_to_le32(sg_dma_len(sg));
@@ -1070,23 +1165,22 @@ static int arcmsr_build_ccb(struct Adapt
psge += sizeof (struct SG64ENTRY);
arccdbsize += sizeof (struct SG64ENTRY);
}
- cdb_sgcount++;
}
- arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
+ arcmsr_cdb->sgcount = (uint8_t)nseg;
arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
if ( arccdbsize > 256)
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0] | WRITE_10 || pcmd->cmnd[0]|WRITE_12) {
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
- ccb->ccb_flags |= CCB_FLAG_WRITE;
}
+ ccb->arc_cdb_size = arccdbsize;
return SUCCESS;
}
static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
{
- uint32_t shifted_cdb_phyaddr = ccb->shifted_cdb_phyaddr;
+ uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern;
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
atomic_inc(&acb->ccboutstandingcount);
ccb->startdone = ARCMSR_CCB_START;
@@ -1096,10 +1189,10 @@ static void arcmsr_post_ccb(struct Adapt
struct MessageUnit_A __iomem *reg = acb->pmuA;
if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
- writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+ writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
®->inbound_queueport);
else {
- writel(shifted_cdb_phyaddr, ®->inbound_queueport);
+ writel(cdb_phyaddr_pattern, ®->inbound_queueport);
}
}
break;
@@ -1111,11 +1204,10 @@ static void arcmsr_post_ccb(struct Adapt
ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
writel(0, ®->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,\
®->post_qbuffer[index]);
- }
- else {
- writel(shifted_cdb_phyaddr, ®->post_qbuffer[index]);
+ } else {
+ writel(cdb_phyaddr_pattern, ®->post_qbuffer[index]);
}
index++;
index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
@@ -1123,6 +1215,19 @@ static void arcmsr_post_ccb(struct Adapt
writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t ccb_post_stamp, arc_cdb_size;
+
+ arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size;
+ ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1);
+ if (acb->cdb_phyaddr_hi32) {
+ writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high);
+ writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+ } else {
+ writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+ }
+ }
}
}
@@ -1131,8 +1236,7 @@ static void arcmsr_stop_hba_bgrb(struct
struct MessageUnit_A __iomem *reg = acb->pmuA;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->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);
@@ -1145,13 +1249,26 @@ static void arcmsr_stop_hbb_bgrb(struct
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
, acb->host->host_no);
}
}
+static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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) {
@@ -1164,22 +1281,16 @@ static void arcmsr_stop_adapter_bgrb(str
arcmsr_stop_hbb_bgrb(acb);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_stop_hbc_bgrb(acb);
+ }
}
}
static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
{
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
- dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
- iounmap(acb->pmuA);
- }
- break;
- case ACB_ADAPTER_TYPE_B: {
dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
}
- }
-}
void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
{
@@ -1195,6 +1306,10 @@ void arcmsr_iop_message_read(struct Adap
writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell);
+ }
}
}
@@ -1220,6 +1335,15 @@ static void arcmsr_iop_message_wrote(str
writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ /*
+ ** push inbound doorbell tell iop, driver data write ok
+ ** and wait reply on next hwinterrupt for next Qbuffer post
+ */
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, ®->inbound_doorbell);
+ }
+ break;
}
}
@@ -1240,6 +1363,10 @@ struct QBUFFER __iomem *arcmsr_get_iop_r
qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+ qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer;
+ }
}
return qbuffer;
}
@@ -1261,6 +1387,11 @@ static struct QBUFFER __iomem *arcmsr_ge
pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ pqbuffer = (struct QBUFFER __iomem *)®->message_wbuffer;
+ }
+
}
return pqbuffer;
}
@@ -1345,14 +1474,42 @@ static void arcmsr_hba_doorbell_isr(stru
arcmsr_iop2drv_data_read_handle(acb);
}
}
-
+static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
+{
+ uint32_t outbound_doorbell;
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ /*
+ *******************************************************************
+ ** Maybe here we need to check wrqbuffer_lock is lock or not
+ ** DOORBELL: din! don!
+ ** check if there are any mail need to pack from firmware
+ *******************************************************************
+ */
+ outbound_doorbell = readl(®->outbound_doorbell);
+ writel(outbound_doorbell, ®->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(®->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);
}
}
@@ -1361,17 +1518,51 @@ static void arcmsr_hbb_postqueue_isr(str
uint32_t index;
uint32_t flag_ccb;
struct MessageUnit_B *reg = acb->pmuB;
-
+ struct ARCMSR_CDB *pARCMSR_CDB;
+ struct CommandControlBlock *pCCB;
+ bool error;
index = reg->doneq_index;
-
while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) {
writel(0, ®->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
@@ -1395,6 +1586,23 @@ static void arcmsr_hbb_message_isr(struc
writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
+/*
+**********************************************************************************
+** Handle a message interrupt
+**
+** The only message interrupt we expect is in response to a query for the
+** current adapter config.
+** We want this in order to compare the drivemap so that we can detect newly-attached drives.
+**********************************************************************************
+*/
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_C *reg = acb->pmuC;
+ /*clear interrupt and message state*/
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear);
+ schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
+
static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
{
uint32_t outbound_intstatus;
@@ -1447,7 +1653,31 @@ static int arcmsr_handle_hbb_isr(struct
/* 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)
@@ -1466,6 +1696,11 @@ static irqreturn_t arcmsr_interrupt(stru
}
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ if (arcmsr_handle_hbc_isr(acb)) {
+ return IRQ_NONE;
+ }
+ }
}
return IRQ_HANDLED;
}
@@ -1877,7 +2107,10 @@ static int arcmsr_queue_command(struct s
if (atomic_read(&acb->ccboutstandingcount) >=
ARCMSR_MAX_OUTSTANDING_CMD)
return SCSI_MLQUEUE_HOST_BUSY;
-
+ if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) {
+ printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n");
+ return 0;
+ }
ccb = arcmsr_get_freeccb(acb);
if (!ccb)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1900,9 +2133,8 @@ static bool arcmsr_get_hba_config(struct
char __iomem *iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]);
char __iomem *iop_device_map = (char __iomem *) (®->message_rwbuffer[21]);
int count;
-
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->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;
@@ -1978,7 +2210,7 @@ static bool arcmsr_get_hbb_config(struct
iop_device_map = (char __iomem *)(®->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;
@@ -2025,12 +2257,73 @@ static bool arcmsr_get_hbb_config(struct
/*firm_ide_channels,4,16-19*/
return true;
}
+
+static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB)
+{
+ uint32_t intmask_org, Index, firmware_state = 0;
+ struct MessageUnit_C *reg = pACB->pmuC;
+ char *acb_firm_model = pACB->firm_model;
+ char *acb_firm_version = pACB->firm_version;
+ char *iop_firm_model = (char *)(®->msgcode_rwbuffer[15]); /*firm_model,15,60-67*/
+ char *iop_firm_version = (char *)(®->msgcode_rwbuffer[17]); /*firm_version,17,68-83*/
+ int count;
+ /* disable all outbound interrupt */
+ intmask_org = readl(®->host_int_mask); /* disable outbound message0 int */
+ writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask);
+ /* wait firmware ready */
+ do {
+ firmware_state = readl(®->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+ /* post "get config" instruction */
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell);
+ /* wait message ready */
+ for (Index = 0; Index < 2000; Index++) {
+ if (readl(®->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->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(®->msgcode_rwbuffer[1]); /*firm_request_len,1,04-07*/
+ pACB->firm_numbers_queue = readl(®->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/
+ pACB->firm_sdram_size = readl(®->msgcode_rwbuffer[3]); /*firm_sdram_size,3,12-15*/
+ pACB->firm_hd_channels = readl(®->msgcode_rwbuffer[4]); /*firm_ide_channels,4,16-19*/
+ pACB->firm_cfg_version = readl(®->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,
@@ -2041,7 +2334,7 @@ static int arcmsr_polling_hba_ccbdone(st
struct ARCMSR_CDB *arcmsr_cdb;
uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
int rtn;
-
+ bool error;
polling_hba_ccb_retry:
poll_count++;
outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable;
@@ -2052,6 +2345,7 @@ static int arcmsr_polling_hba_ccbdone(st
rtn = SUCCESS;
break;
} else {
+ msleep(25);
if (poll_count > 100) {
rtn = FAILED;
break;
@@ -2081,9 +2375,9 @@ static int arcmsr_polling_hba_ccbdone(st
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
- } else {
- arcmsr_report_ccb_state(acb, ccb, flag_ccb);
}
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_report_ccb_state(acb, ccb, error);
}
return rtn;
}
@@ -2096,7 +2390,7 @@ static int arcmsr_polling_hbb_ccbdone(st
struct CommandControlBlock *ccb;
uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
int index, rtn;
-
+ bool error;
polling_hbb_ccb_retry:
poll_count++;
/* clear doorbell interrupt */
@@ -2144,13 +2438,69 @@ static int arcmsr_polling_hbb_ccbdone(st
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
- } else {
- arcmsr_report_ccb_state(acb, ccb, flag_ccb);
}
- } /*drain reply FIFO*/
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_report_ccb_state(acb, ccb, error);
+ }
return rtn;
}
+static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t flag_ccb, ccb_cdb_phy;
+ struct ARCMSR_CDB *arcmsr_cdb;
+ bool error;
+ struct CommandControlBlock *pCCB;
+ uint32_t poll_ccb_done = 0, poll_count = 0;
+ int rtn;
+polling_hbc_ccb_retry:
+ poll_count++;
+ while (1) {
+ if ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) {
+ if (poll_ccb_done) {
+ rtn = SUCCESS;
+ break;
+ } else {
+ msleep(25);
+ if (poll_count > 100) {
+ rtn = FAILED;
+ break;
+ }
+ goto polling_hbc_ccb_retry;
+ }
+ }
+ flag_ccb = readl(®->outbound_queueport_low);
+ ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/
+ pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+ poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
+ /* check ifcommand done with no error*/
+ if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+ if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+ printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+ " poll command abort successfully \n"
+ , acb->host->host_no
+ , pCCB->pcmd->device->id
+ , pCCB->pcmd->device->lun
+ , pCCB);
+ pCCB->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(pCCB);
+ continue;
+ }
+ printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n"
+ , acb->host->host_no
+ , pCCB
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+ arcmsr_report_ccb_state(acb, pCCB, error);
+ }
+ return rtn;
+}
static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
@@ -2165,6 +2515,10 @@ static int arcmsr_polling_ccbdone(struct
case ACB_ADAPTER_TYPE_B: {
rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb);
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb);
+ }
}
return rtn;
}
@@ -2182,6 +2536,7 @@ static int arcmsr_iop_confirm(struct Ada
dma_coherent_handle = acb->dma_coherent_handle;
cdb_phyaddr = (uint32_t)(dma_coherent_handle);
cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
/*
***********************************************************************
** if adapter type B, set window of "post command Q"
@@ -2199,7 +2554,7 @@ static int arcmsr_iop_confirm(struct Ada
writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]);
writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
®->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);
@@ -2220,7 +2575,7 @@ static int arcmsr_iop_confirm(struct Ada
reg->postq_index = 0;
reg->doneq_index = 0;
writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
acb->host->host_no);
return 1;
@@ -2239,7 +2594,7 @@ static int arcmsr_iop_confirm(struct Ada
writel(1056, rwbuffer);
writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
timeout \n",acb->host->host_no);
return 1;
@@ -2248,6 +2603,27 @@ static int arcmsr_iop_confirm(struct Ada
arcmsr_enable_outbound_ints(acb, intmask_org);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ if (cdb_phyaddr_hi32 != 0) {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+
+ if (cdb_phyaddr_hi32 != 0) {
+ unsigned char Retries = 0x00;
+ do {
+ printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32);
+ } while (Retries++ < 100);
+ }
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->msgcode_rwbuffer[0]);
+ writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]);
+ writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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;
}
@@ -2274,6 +2649,12 @@ static void arcmsr_wait_firmware_ready(s
writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ do {
+ firmware_state = readl(®->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+ }
}
}
@@ -2316,6 +2696,26 @@ static void arcmsr_request_hbb_device_ma
return;
}
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+ return;
+ } else {
+ acb->fw_flag = FW_NORMAL;
+ if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
+ atomic_set(&acb->rq_map_token, 16);
+ }
+ atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+ if (atomic_dec_and_test(&acb->rq_map_token))
+ return;
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell);
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+ }
+ return;
+}
+
static void arcmsr_request_device_map(unsigned long pacb)
{
struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
@@ -2329,6 +2728,9 @@ static void arcmsr_request_device_map(un
arcmsr_request_hbb_device_map(acb);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_request_hbc_device_map(acb);
+ }
}
}
@@ -2337,7 +2739,7 @@ static void arcmsr_start_hba_bgrb(struct
struct MessageUnit_A __iomem *reg = acb->pmuA;
acb->acb_flags |= ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->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);
}
@@ -2348,12 +2750,24 @@ static void arcmsr_start_hbb_bgrb(struct
struct MessageUnit_B *reg = acb->pmuB;
acb->acb_flags |= ACB_F_MSG_START_BGRB;
writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
rebulid' timeout \n",acb->host->host_no);
}
}
+static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+ pACB->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell);
+ if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+ rebulid' timeout \n", pACB->host->host_no);
+ }
+ return;
+}
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@@ -2363,6 +2777,8 @@ static void arcmsr_start_adapter_bgrb(st
case ACB_ADAPTER_TYPE_B:
arcmsr_start_hbb_bgrb(acb);
break;
+ case ACB_ADAPTER_TYPE_C:
+ arcmsr_start_hbc_bgrb(acb);
}
}
@@ -2388,6 +2804,14 @@ static void arcmsr_clear_doorbell_queue_
/* let IOP know data has been read */
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t outbound_doorbell;
+ /* empty doorbell Qbuffer if door bell ringed */
+ outbound_doorbell = readl(®->outbound_doorbell);
+ writel(outbound_doorbell, ®->outbound_doorbell_clear);
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell);
+ }
}
}
@@ -2400,12 +2824,14 @@ static void arcmsr_enable_eoi_mode(struc
{
struct MessageUnit_B *reg = acb->pmuB;
writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell);
- if(arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
return;
}
}
break;
+ case ACB_ADAPTER_TYPE_C:
+ return;
}
return;
}
@@ -2413,21 +2839,33 @@ static void arcmsr_enable_eoi_mode(struc
static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
{
uint8_t value[64];
- int i;
- struct MessageUnit_A __iomem *reg = acb->pmuA;
-
+ int i, count = 0;
+ struct MessageUnit_A __iomem *pmuA = acb->pmuA;
+ struct MessageUnit_C __iomem *pmuC = acb->pmuC;
+ u32 temp = 0;
/* backup pci config data */
- printk(KERN_ERR "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
+ printk(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, ®->reserved1[0]);
+ writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]);
+ } else if ((acb->dev_id == 0x1880)) {
+ do {
+ count++;
+ writel(0xF, &pmuC->write_sequence);
+ writel(0x4, &pmuC->write_sequence);
+ writel(0xB, &pmuC->write_sequence);
+ writel(0x2, &pmuC->write_sequence);
+ writel(0x7, &pmuC->write_sequence);
+ writel(0xD, &pmuC->write_sequence);
+ } while ((((temp = readl(&pmuC->host_diagnostic)) | ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5));
+ writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic);
} else {
pci_write_config_byte(acb->pdev, 0x84, 0x20);
}
- msleep(1000);
+ msleep(2000);
/* write back pci config data */
for (i=0;i<64;i++) {
pci_write_config_byte(acb->pdev, i, value[i]);
@@ -2435,29 +2873,6 @@ static void arcmsr_hardware_reset(struct
msleep(1000);
return;
}
-/*
-****************************************************************************
-****************************************************************************
-*/
-int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
-{
- struct Scsi_Host *shost = NULL;
- int i, isleep;
-
- shost = cmd->device->host;
- isleep = sleeptime / 10;
- if (isleep > 0) {
- for (i = 0; i < isleep; i ++) {
- msleep(10000);
- }
- }
-
- isleep = sleeptime % 10;
- if (isleep > 0) {
- msleep(isleep*1000);
- }
- return 0;
-}
static void arcmsr_iop_init(struct AdapterControlBlock *acb)
{
uint32_t intmask_org;
@@ -2510,24 +2924,22 @@ static int arcmsr_bus_reset(struct scsi_
uint32_t intmask_org, outbound_doorbell;
int retry_count = 0;
int rtn = FAILED;
-
acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
- printk(KERN_ERR "arcmsr: executing eh bus reset .....num_resets = %d, \
- num_aborts = %d \n", acb->num_resets, acb->num_aborts);
+ printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts);
acb->num_resets++;
switch(acb->adapter_type){
case ACB_ADAPTER_TYPE_A:{
if (acb->acb_flags & ACB_F_BUS_RESET) {
long timeout;
- timeout = wait_event_timeout(wait_q,
- (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
+ printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n");
+ timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
if (timeout) {
return SUCCESS;
}
}
acb->acb_flags |= ACB_F_BUS_RESET;
- if (arcmsr_iop_reset(acb)) {
+ if (!arcmsr_iop_reset(acb)) {
struct MessageUnit_A __iomem *reg;
reg = acb->pmuA;
arcmsr_hardware_reset(acb);
@@ -2535,12 +2947,10 @@ static int arcmsr_bus_reset(struct scsi_
sleep_again:
arcmsr_sleep_for_bus_reset(cmd);
if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
- printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
- retry=%d \n", acb->host->host_no, retry_count);
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count);
if (retry_count > retrycount) {
acb->fw_flag = FW_DEADLOCK;
- printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
- RETRY TERMINATED!! \n", acb->host->host_no);
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no);
return FAILED;
}
retry_count++;
@@ -2567,7 +2977,7 @@ 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) {
@@ -2591,7 +3001,7 @@ sleep_again:
}
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 {
@@ -2613,6 +3023,77 @@ sleep_again:
}
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(®->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(®->outbound_doorbell);
+ writel(outbound_doorbell, ®->outbound_doorbell_clear); /*clear interrupt */
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->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;
@@ -2622,9 +3103,7 @@ static int arcmsr_abort_one_cmd(struct A
struct CommandControlBlock *ccb)
{
int rtn;
- spin_lock_irq(&acb->eh_lock);
rtn = arcmsr_polling_ccbdone(acb, ccb);
- spin_unlock_irq(&acb->eh_lock);
return rtn;
}
@@ -2692,6 +3169,7 @@ static const char *arcmsr_info(struct Sc
case PCI_DEVICE_ID_ARECA_1381:
case PCI_DEVICE_ID_ARECA_1680:
case PCI_DEVICE_ID_ARECA_1681:
+ case PCI_DEVICE_ID_ARECA_1880:
type = "SAS";
break;
default:
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH 2/3] SCSI: Support Type C RAID controller
2010-06-18 7:39 Nick Cheng
@ 2010-06-20 14:18 ` James Bottomley
0 siblings, 0 replies; 5+ messages in thread
From: James Bottomley @ 2010-06-20 14:18 UTC (permalink / raw)
To: nick.cheng; +Cc: linux-scsi, linux-kernel
On Fri, 2010-06-18 at 15:39 +0800, Nick Cheng wrote:
> 1. To support Type C RAID controller, ACB_ADAPTER_TYPE_C, i.e. PCI device
> ID: 0x1880.
OK, got patch 1/3 successfully, but after I apply it, this one doesn't
apply:
jejb@mulgrave:~/git/scsi-misc-2.6> patch -p2 < ~/tmp.diff
patching file drivers/scsi/arcmsr/arcmsr.h
Hunk #9 succeeded at 599 with fuzz 2.
Hunk #10 FAILED at 619.
This rejection, for instance is because there's an indent before the
#else and #endif in the patch which isn't in the file ... that lack of
indent dates back to the time the driver was first imported, so you
can't be patching from the current kernel to this.
1 out of 10 hunks FAILED -- saving rejects to file
drivers/scsi/arcmsr/arcmsr.h.rej
patching file drivers/scsi/arcmsr/arcmsr_hba.c
Hunk #3 FAILED at 121.
Hunk #13 FAILED at 448.
Hunk #14 FAILED at 475.
Hunk #15 FAILED at 502.
Hunk #16 succeeded at 644 (offset 1 line).
Hunk #17 succeeded at 780 (offset 1 line).
Hunk #18 FAILED at 794.
Hunk #19 succeeded at 811 (offset 1 line).
Hunk #20 succeeded at 844 (offset 1 line).
Hunk #21 succeeded at 856 with fuzz 1 (offset 1 line).
Hunk #22 succeeded at 880 (offset 1 line).
Hunk #23 succeeded at 923 (offset 1 line).
Hunk #24 succeeded at 940 (offset 1 line).
Hunk #25 succeeded at 972 (offset 1 line).
Hunk #26 succeeded at 986 (offset 1 line).
Hunk #27 succeeded at 1009 (offset 1 line).
Hunk #28 succeeded at 1036 (offset 1 line).
Hunk #29 succeeded at 1047 (offset 1 line).
Hunk #30 succeeded at 1088 (offset 1 line).
Hunk #31 succeeded at 1119 (offset 1 line).
Hunk #32 succeeded at 1180 (offset 1 line).
Hunk #33 FAILED at 1197.
Hunk #34 FAILED at 1236.
Hunk #35 succeeded at 1263 (offset 1 line).
Hunk #36 succeeded at 1278 (offset 1 line).
Hunk #37 succeeded at 1289 (offset 1 line).
Hunk #38 succeeded at 1310 (offset 1 line).
Hunk #39 succeeded at 1323 (offset 1 line).
Hunk #40 succeeded at 1355 (offset 1 line).
Hunk #41 succeeded at 1380 (offset 1 line).
Hunk #42 succeeded at 1409 (offset 1 line).
Hunk #43 succeeded at 1438 (offset 1 line).
Hunk #44 succeeded at 1463 (offset 1 line).
Hunk #45 succeeded at 1552 (offset 1 line).
Hunk #46 succeeded at 1596 (offset 1 line).
Hunk #47 succeeded at 1665 (offset 2 lines).
Hunk #48 succeeded at 1734 with fuzz 1 (offset 2 lines).
Hunk #49 succeeded at 1778 (offset 3 lines).
Hunk #50 succeeded at 2194 (offset 3 lines).
Hunk #51 succeeded at 2220 (offset 3 lines).
Hunk #52 FAILED at 2294.
Hunk #53 succeeded at 2344 (offset 3 lines).
Hunk #54 succeeded at 2421 (offset 3 lines).
Hunk #55 succeeded at 2432 (offset 3 lines).
Hunk #56 FAILED at 2459.
Hunk #57 FAILED at 2474.
Hunk #58 FAILED at 2522.
Hunk #59 succeeded at 2546 (offset 3 lines).
Hunk #60 succeeded at 2567 (offset 3 lines).
Hunk #61 succeeded at 2585 (offset 3 lines).
Hunk #62 succeeded at 2606 (offset 3 lines).
Hunk #63 succeeded at 2625 (offset 3 lines).
Hunk #64 succeeded at 2634 (offset 3 lines).
Hunk #65 succeeded at 2681 (offset 3 lines).
Hunk #66 succeeded at 2729 (offset 3 lines).
Hunk #67 succeeded at 2762 (offset 3 lines).
Hunk #68 succeeded at 2773 (offset 3 lines).
Hunk #69 succeeded at 2784 (offset 3 lines).
Hunk #70 succeeded at 2811 (offset 3 lines).
Hunk #71 succeeded at 2838 (offset 3 lines).
Hunk #72 succeeded at 2858 (offset 3 lines).
Hunk #73 FAILED at 2870.
Hunk #74 FAILED at 2892.
Hunk #75 FAILED at 2967.
Hunk #76 FAILED at 2992.
Hunk #77 succeeded at 3028 (offset 4 lines).
Hunk #78 succeeded at 3052 with fuzz 1 (offset 4 lines).
Hunk #79 FAILED at 3070.
Hunk #80 succeeded at 3083 (offset 4 lines).
Hunk #81 succeeded at 3151 (offset 4 lines).
16 out of 81 hunks FAILED -- saving rejects to file
drivers/scsi/arcmsr/arcmsr_hba.c.rej
Can you redo 2/3 and 3/3 so they apply in sequence on 2.6.35-rc3 with
1/3 already applied?
Thanks,
James
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/3] SCSI: Support Type C RAID controller
@ 2010-05-26 4:55 Nick Cheng
0 siblings, 0 replies; 5+ messages in thread
From: Nick Cheng @ 2010-05-26 4:55 UTC (permalink / raw)
To: linux-scsi; +Cc: James.Bottomley, linux-kernel
[-- Attachment #1: Type: text/plain, Size: 143 bytes --]
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 >
---
[-- Attachment #2: patch2_3 --]
[-- Type: application/octet-stream, Size: 74000 bytes --]
diff -Naurp --ignore-blank-lines --ignore-all-space --ignore-space-change a/linux/drivers/scsi/arcmsr/arcmsr.h b/linux/drivers/scsi/arcmsr/arcmsr.h
--- a/linux/drivers/scsi/arcmsr/arcmsr.h 2010-05-26 19:47:46.000000000 +0800
+++ b/linux/drivers/scsi/arcmsr/arcmsr.h 2010-05-26 20:43:13.000000000 +0800
@@ -48,7 +47,7 @@ struct device_attribute;
/*The limit of outstanding scsi command that firmware can handle*/
#define ARCMSR_MAX_OUTSTANDING_CMD 256
#define ARCMSR_MAX_FREECCB_NUM 320
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2009/12/09"
+#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/02/02"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
#define ARCMSR_MAX_XFER_SECTORS_B 4096
@@ -61,6 +60,7 @@ struct device_attribute;
#define ARCMSR_MAX_HBB_POSTQUEUE 264
#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */
#define ARCMSR_CDB_SG_PAGE_LENGTH 256
+#define SCSI_CMD_ARECA_SPECIFIC 0xE1
#ifndef PCI_DEVICE_ID_ARECA_1880
#define PCI_DEVICE_ID_ARECA_1880 0x1880
#endif
@@ -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
/*
************************************************************************
@@ -274,6 +278,61 @@ struct FIRMWARE_INFO
/* iop message_rwbuffer for message command */
#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00
/*
+************************************************************************
+** SPEC. for Areca HBC adapter
+************************************************************************
+*/
+#define ARCMSR_HBC_ISR_THROTTLING_LEVEL 12
+#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE 20
+/* Host Interrupt Mask */
+#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK 0x00000001 /* When clear, the Utility_A interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK 0x00000004 /* When clear, the General Outbound Doorbell interrupt routes to the host.*/
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK 0x00000008 /* When clear, the Outbound Post List FIFO Not Empty interrupt routes to the host.*/
+#define ARCMSR_HBCMU_ALL_INTMASKENABLE 0x0000000D /* disable all ISR */
+/* Host Interrupt Status */
+#define ARCMSR_HBCMU_UTILITY_A_ISR 0x00000001
+ /*
+ ** Set when the Utility_A Interrupt bit is set in the Outbound Doorbell Register.
+ ** It clears by writing a 1 to the Utility_A bit in the Outbound Doorbell Clear Register or through automatic clearing (if enabled).
+ */
+#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR 0x00000004
+ /*
+ ** Set if Outbound Doorbell register bits 30:1 have a non-zero
+ ** value. This bit clears only when Outbound Doorbell bits
+ ** 30:1 are ALL clear. Only a write to the Outbound Doorbell
+ ** Clear register clears bits in the Outbound Doorbell register.
+ */
+#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR 0x00000008
+ /*
+ ** Set whenever the Outbound Post List Producer/Consumer
+ ** Register (FIFO) is not empty. It clears when the Outbound
+ ** Post List FIFO is empty.
+ */
+#define ARCMSR_HBCMU_SAS_ALL_INT 0x00000010
+ /*
+ ** This bit indicates a SAS interrupt from a source external to
+ ** the PCIe core. This bit is not maskable.
+ */
+ /* DoorBell*/
+#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK 0x00000002
+#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK 0x00000004
+ /*inbound message 0 ready*/
+#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE 0x00000008
+ /*more than 12 request completed in a time*/
+#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING 0x00000010
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK 0x00000002
+ /*outbound DATA WRITE isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR 0x00000002
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK 0x00000004
+ /*outbound DATA READ isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_DOORBELL_CLEAR 0x00000004
+ /*outbound message 0 ready*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE 0x00000008
+ /*outbound message cmd isr door bell clear*/
+#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR 0x00000008
+ /*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/
+#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK 0x80000000
+/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
*******************************************************************************
@@ -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_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
@@ -460,13 +598,13 @@ 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
@@ -480,10 +618,10 @@ struct CommandControlBlock
#define ARCMSR_CCB_ILLEGAL 0xFFFF
#if BITS_PER_LONG == 64
/* ======================512+64 bytes======================== */
- uint32_t reserved[6]; /*24 byte*/
+ uint32_t reserved[5]; /*24 byte*/
#else
/* ======================512+32 bytes======================== */
- uint32_t reserved[2]; /*8 byte*/
+ uint32_t reserved; /*8 byte*/
#endif
/* ======================================================= */
struct ARCMSR_CDB arcmsr_cdb;
diff -Naurp --ignore-blank-lines --ignore-all-space --ignore-space-change a/linux/drivers/scsi/arcmsr/arcmsr_hba.c b/linux/drivers/scsi/arcmsr/arcmsr_hba.c
--- a/linux/drivers/scsi/arcmsr/arcmsr_hba.c 2010-05-26 20:38:55.000000000 +0800
+++ b/linux/drivers/scsi/arcmsr/arcmsr_hba.c 2010-05-26 20:43:07.000000000 +0800
@@ -71,11 +71,11 @@
#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(struc
static void arcmsr_request_device_map(unsigned long pacb);
static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb);
static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb);
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb);
static void arcmsr_message_isr_bh_fn(struct work_struct *work);
static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
-
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB);
+static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
@@ -119,7 +121,7 @@ static int arcmsr_adjust_disk_queue_dept
static struct scsi_host_template arcmsr_scsi_host_template = {
.module = THIS_MODULE,
- .name = "ARCMSR ARECA SATA/SAS RAID Host Bus Adapter"
+ .name = "ARCMSR ARECA SATA/SAS RAID Controller"
ARCMSR_DRIVER_VERSION,
.info = arcmsr_info,
.queuecommand = arcmsr_queue_command,
@@ -165,17 +167,40 @@ static struct pci_driver arcmsr_pci_driv
.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);
+ }
+ }
-static void arcmsr_free_mu(struct AdapterControlBlock *acb)
+ isleep = sleeptime % 10;
+ if (isleep > 0) {
+ msleep(isleep*1000);
+ }
+ printk(KERN_NOTICE "wake-up\n");
+ return 0;
+}
+
+static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A:
+ case ACB_ADAPTER_TYPE_C:
break;
case ACB_ADAPTER_TYPE_B:{
- struct MessageUnit_B *reg = acb->pmuB;
dma_free_coherent(&acb->pdev->dev,
sizeof(struct MessageUnit_B),
- reg, acb->dma_coherent_handle_hbb_mu);
+ acb->pmuB, acb->dma_coherent_handle_hbb_mu);
}
}
}
@@ -208,6 +232,19 @@ static bool arcmsr_remap_pciregion(struc
}
acb->mem_base0 = mem_base0;
acb->mem_base1 = mem_base1;
+ break;
+ }
+ case ACB_ADAPTER_TYPE_C:{
+ acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1));
+ if (!acb->pmuC) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no);
+ return false;
+ }
+ if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/
+ return true;
+ }
+ break;
}
}
return true;
@@ -219,10 +256,16 @@ static void arcmsr_unmap_pciregion(struc
case ACB_ADAPTER_TYPE_A:{
iounmap(acb->pmuA);
}
+ break;
case ACB_ADAPTER_TYPE_B:{
iounmap(acb->mem_base0);
iounmap(acb->mem_base1);
}
+
+ break;
+ case ACB_ADAPTER_TYPE_C:{
+ iounmap(acb->pmuC);
+ }
}
}
@@ -270,6 +313,10 @@ static void arcmsr_define_adapter_type(s
pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
acb->dev_id = dev_id;
switch (dev_id) {
+ case 0x1880: {
+ acb->adapter_type = ACB_ADAPTER_TYPE_C;
+ }
+ break;
case 0x1201 : {
acb->adapter_type = ACB_ADAPTER_TYPE_B;
}
@@ -291,13 +337,13 @@ static uint8_t arcmsr_hba_wait_msgint_re
ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
®->outbound_intstatus);
- return 0x00;
+ return true;
}
msleep(10);
} /*max 1 seconds*/
} while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
+ return false;
}
static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb)
@@ -313,15 +358,32 @@ static uint8_t arcmsr_hbb_wait_msgint_re
writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN
, reg->iop2drv_doorbell);
writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
- return 0x00;
+ return true;
}
msleep(10);
} /*max 1 seconds*/
} while (Retries++ < 20);/*max 20 sec*/
- return 0xff;
+ return false;
}
+static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+ unsigned char Retries = 0x00;
+ uint32_t Index;
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->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;
@@ -326,10 +388,9 @@ static void arcmsr_flush_hba_cache(struc
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
int retry_count = 30;
-
writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->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(struc
{
struct MessageUnit_B *reg = acb->pmuB;
int retry_count = 30;
-
writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell);
do {
- if (!arcmsr_hbb_wait_msgint_ready(acb))
+ if (arcmsr_hbb_wait_msgint_ready(acb))
break;
else {
retry_count--;
@@ -356,6 +416,23 @@ static void arcmsr_flush_hbb_cache(struc
} while (retry_count != 0);
}
+static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */
+ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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,21 +445,22 @@ static void arcmsr_flush_adapter_cache(s
case ACB_ADAPTER_TYPE_B: {
arcmsr_flush_hbb_cache(acb);
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_flush_hbc_cache(acb);
+ }
}
}
static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
-
void *dma_coherent;
dma_addr_t dma_coherent_handle;
struct CommandControlBlock *ccb_tmp;
int i = 0, j = 0;
dma_addr_t cdb_phyaddr;
- unsigned long roundup_ccbsize = 0;
+ unsigned long roundup_ccbsize = 0, offset;
unsigned long max_xfer_len;
unsigned long max_sg_entrys;
uint32_t firm_config_version;
@@ -395,26 +472,29 @@ static int arcmsr_alloc_ccb_pool(struct
max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
firm_config_version = acb->firm_cfg_version;
if ((firm_config_version & 0xFF) >= 3) {
- max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
+ max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */
max_sg_entrys = (max_xfer_len/4096);
}
acb->host->max_sectors = max_xfer_len/512;
acb->host->sg_tablesize = max_sg_entrys;
- roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + max_sg_entrys * sizeof(struct SG64ENTRY), 32);
- acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
+ roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
+ acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32;
dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL);
if (!dma_coherent) {
printk(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;
+ memset(dma_coherent, 0, acb->uncache_size);
+ offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent;
+ dma_coherent_handle = dma_coherent_handle + offset;
+ dma_coherent = (struct CommandControlBlock *)dma_coherent + offset;
+ ccb_tmp = dma_coherent;
acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
- ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
+ ccb_tmp->cdb_phyaddr_pattern = ((acb->adapter_type == ACB_ADAPTER_TYPE_C) ? cdb_phyaddr : (cdb_phyaddr >> 5));
acb->pccb_pool[i] = ccb_tmp;
ccb_tmp->acb = acb;
INIT_LIST_HEAD(&ccb_tmp->list);
@@ -422,68 +502,9 @@ static int arcmsr_alloc_ccb_pool(struct
ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize);
dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
}
- break;
- }
- case ACB_ADAPTER_TYPE_B: {
-
- void *dma_coherent;
- dma_addr_t dma_coherent_handle;
- struct CommandControlBlock *ccb_tmp;
- uint32_t cdb_phyaddr;
- unsigned int roundup_ccbsize = 0;
- unsigned long max_xfer_len;
- unsigned long max_sg_entrys;
- unsigned long firm_config_version;
- unsigned long max_freeccb_num = 0;
- int i = 0, j = 0;
-
- max_freeccb_num = ARCMSR_MAX_FREECCB_NUM;
- max_xfer_len = ARCMSR_MAX_XFER_LEN;
- max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES;
- firm_config_version = acb->firm_cfg_version;
- if ((firm_config_version & 0xFF) >= 3) {
- max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH <<
- ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */
- max_sg_entrys = (max_xfer_len/4096);/* max 4097 sg entry*/
- }
- acb->host->max_sectors = max_xfer_len / 512;
- acb->host->sg_tablesize = max_sg_entrys;
- roundup_ccbsize = roundup(sizeof(struct CommandControlBlock)+
- (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32);
- acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM;
- dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size,
- &dma_coherent_handle, GFP_KERNEL);
-
- if (!dma_coherent) {
- printk(KERN_NOTICE "DMA allocation failed...........................\n");
- return -ENOMEM;
- }
- memset(dma_coherent, 0, acb->uncache_size);
- acb->dma_coherent = dma_coherent;
- acb->dma_coherent_handle = dma_coherent_handle;
- ccb_tmp = (struct CommandControlBlock *)dma_coherent;
- acb->vir2phy_offset = (unsigned long)dma_coherent -
- (unsigned long)dma_coherent_handle;
- for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
- cdb_phyaddr = dma_coherent_handle +
- offsetof(struct CommandControlBlock, arcmsr_cdb);
- ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5;
- acb->pccb_pool[i] = ccb_tmp;
- ccb_tmp->acb = acb;
- INIT_LIST_HEAD(&ccb_tmp->list);
- list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp +
- roundup_ccbsize);
- dma_coherent_handle = dma_coherent_handle + roundup_ccbsize;
- }
- for (i = 0; i < ARCMSR_MAX_TARGETID; i++)
- for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)
- acb->devstate[i][j] = ARECA_RAID_GONE;
- }
- break;
- }
return 0;
}
+
static void arcmsr_message_isr_bh_fn(struct work_struct *work)
{
struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh);
@@ -563,6 +584,43 @@ static void arcmsr_message_isr_bh_fn(str
}
}
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = acb->pmuC;
+ char *acb_dev_map = (char *)acb->device_map;
+ uint32_t __iomem *signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]);
+ char __iomem *devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]);
+ int target, lun;
+ struct scsi_device *psdev;
+ char diff;
+
+ atomic_inc(&acb->rq_map_token);
+ if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) {
+ for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) {
+ diff = (*acb_dev_map)^readb(devicemap);
+ if (diff != 0) {
+ char temp;
+ *acb_dev_map = readb(devicemap);
+ temp = *acb_dev_map;
+ for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) {
+ if ((temp & 0x01) == 1 && (diff & 0x01) == 1) {
+ scsi_add_device(acb->host, 0, target, lun);
+ } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) {
+ psdev = scsi_device_lookup(acb->host, 0, target, lun);
+ if (psdev != NULL) {
+ scsi_remove_device(psdev);
+ scsi_device_put(psdev);
+ }
+ }
+ temp >>= 1;
+ diff >>= 1;
+ }
+ }
+ devicemap++;
+ acb_dev_map++;
+ }
+ }
+ }
}
}
@@ -662,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:
@@ -677,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, ®->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)
@@ -693,15 +749,27 @@ static uint8_t arcmsr_abort_hbb_allcmd(s
struct MessageUnit_B *reg = acb->pmuB;
writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'abort all outstanding command' timeout \n"
, acb->host->host_no);
- return 0xff;
+ return false;
}
- return 0x00;
+ return true;
+}
+static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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;
@@ -714,6 +782,11 @@ static uint8_t arcmsr_abort_allcmd(struc
case ACB_ADAPTER_TYPE_B: {
rtnval = arcmsr_abort_hbb_allcmd(acb);
}
+ break;
+
+ case ACB_ADAPTER_TYPE_C: {
+ rtnval = arcmsr_abort_hbc_allcmd(acb);
+ }
}
return rtnval;
}
@@ -721,9 +794,8 @@ static uint8_t arcmsr_abort_allcmd(struc
static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb)
{
struct MessageUnit_B *reg = pacb->pmuB;
-
writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(pacb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(pacb)) {
printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no);
return false;
}
@@ -746,7 +817,6 @@ static void arcmsr_ccb_complete(struct C
atomic_dec(&acb->ccboutstandingcount);
arcmsr_pci_unmap_dma(ccb);
ccb->startdone = ARCMSR_CCB_DONE;
- ccb->ccb_flags = 0;
spin_lock_irqsave(&acb->ccblist_lock, flags);
list_add_tail(&ccb->list, &acb->ccb_free_list);
spin_unlock_irqrestore(&acb->ccblist_lock, flags);
@@ -790,14 +857,20 @@ static u32 arcmsr_disable_outbound_ints(
writel(0, reg->iop2drv_doorbell_mask);
}
break;
+ case ACB_ADAPTER_TYPE_C:{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ /* disable all outbound interrupt */
+ orig_mask = readl(®->host_int_mask); /* disable outbound message0 int */
+ writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask);
+ }
+ break;
}
return orig_mask;
}
static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb,
- struct CommandControlBlock *ccb, uint32_t flag_ccb)
+ struct CommandControlBlock *ccb, bool error)
{
-
uint8_t id, lun;
id = ccb->pcmd->device->id;
lun = ccb->pcmd->device->lun;
@@ -801,7 +874,7 @@ static void arcmsr_report_ccb_state(stru
uint8_t id, lun;
id = ccb->pcmd->device->id;
lun = ccb->pcmd->device->lun;
- if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) {
+ if (!error) {
if (acb->devstate[id][lun] == ARECA_RAID_GONE)
acb->devstate[id][lun] = ARECA_RAID_GOOD;
ccb->pcmd->result = DID_OK << 16;
@@ -833,9 +906,8 @@ static void arcmsr_report_ccb_state(stru
default:
printk(KERN_NOTICE
- "arcmsr%d: scsi id = %d lun = %d"
- " isr get command error done, "
- "but got unknown DeviceStatus = 0x%x \n"
+ "arcmsr%d: scsi id = %d lun = %d isr get command error done, \
+ but got unknown DeviceStatus = 0x%x \n"
, acb->host->host_no
, id
, lun
@@ -848,26 +920,22 @@ static void arcmsr_report_ccb_state(stru
}
}
-static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb)
+static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error)
{
- struct CommandControlBlock *ccb;
- struct ARCMSR_CDB *arcmsr_cdb;
int id, lun;
-
- arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));
- ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
- if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {
- if (ccb->startdone == ARCMSR_CCB_ABORTED) {
- struct scsi_cmnd *abortcmd = ccb->pcmd;
+ if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+ if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+ struct scsi_cmnd *abortcmd = pCCB->pcmd;
if (abortcmd) {
id = abortcmd->device->id;
lun = abortcmd->device->lun;
abortcmd->result |= DID_ABORT << 16;
- arcmsr_ccb_complete(ccb);
- printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \
- isr got aborted command \n", acb->host->host_no, ccb);
+ arcmsr_ccb_complete(pCCB);
+ printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n",
+ acb->host->host_no, pCCB);
}
+ return;
}
printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \
done acb = '0x%p'"
@@ -875,20 +943,22 @@ static void arcmsr_drain_donequeue(struc
" ccboutstandingcount = %d \n"
, acb->host->host_no
, acb
- , ccb
- , ccb->acb
- , ccb->startdone
+ , pCCB
+ , pCCB->acb
+ , pCCB->startdone
, atomic_read(&acb->ccboutstandingcount));
+ 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: {
@@ -900,7 +970,10 @@ static void arcmsr_done4abort_postqueue(
writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/
while (((flag_ccb = readl(®->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;
@@ -908,17 +981,37 @@ static void arcmsr_done4abort_postqueue(
case ACB_ADAPTER_TYPE_B: {
struct MessageUnit_B *reg = acb->pmuB;
/*clear all outbound posted Q*/
+ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, ®->iop2drv_doorbell); /* clear doorbell interrupt */
for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) {
if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) {
writel(0, ®->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, ®->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(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) {
+ /*need to do*/
+ flag_ccb = readl(®->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)
@@ -929,7 +1022,6 @@ static void arcmsr_remove(struct pci_dev
int poll_count = 0;
arcmsr_free_sysfs_attr(acb);
scsi_remove_host(host);
- scsi_host_put(host);
flush_scheduled_work();
del_timer_sync(&acb->eternal_timer);
arcmsr_disable_outbound_ints(acb);
@@ -961,8 +1053,10 @@ static void arcmsr_remove(struct pci_dev
}
free_irq(pdev->irq, acb);
arcmsr_free_ccb_pool(acb);
- arcmsr_free_mu(acb);
+ arcmsr_free_hbb_mu(acb);
+ arcmsr_unmap_pciregion(acb);
pci_release_regions(pdev);
+ scsi_host_put(host);
pci_disable_device(pdev);
pci_set_drvdata(pdev, NULL);
}
@@ -1020,6 +1112,13 @@ static void arcmsr_enable_outbound_ints(
writel(mask, reg->iop2drv_doorbell_mask);
acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f;
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = acb->pmuC;
+ mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK);
+ writel(intmask_org & mask, ®->host_int_mask);
+ acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
+ }
}
}
@@ -1031,24 +1130,20 @@ static int arcmsr_build_ccb(struct Adapt
__le32 address_lo, address_hi;
int arccdbsize = 0x30;
__le32 length = 0;
- int i, cdb_sgcount = 0;
+ int i;
struct scatterlist *sg;
int nseg;
-
ccb->pcmd = pcmd;
memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB));
- arcmsr_cdb->Bus = 0;
arcmsr_cdb->TargetID = pcmd->device->id;
arcmsr_cdb->LUN = pcmd->device->lun;
arcmsr_cdb->Function = 1;
- arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len;
arcmsr_cdb->Context = 0;
memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len);
nseg = scsi_dma_map(pcmd);
- if (nseg > acb->host->sg_tablesize || nseg < 0)
+ if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0))
return FAILED;
- /* map stor port SG list to our iop SG List. */
scsi_for_each_sg(pcmd, sg, nseg, i) {
/* Get the physical address of the current data pointer */
length = cpu_to_le32(sg_dma_len(sg));
@@ -1070,23 +1165,22 @@ static int arcmsr_build_ccb(struct Adapt
psge += sizeof (struct SG64ENTRY);
arccdbsize += sizeof (struct SG64ENTRY);
}
- cdb_sgcount++;
}
- arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount;
+ arcmsr_cdb->sgcount = (uint8_t)nseg;
arcmsr_cdb->DataLength = scsi_bufflen(pcmd);
arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0);
if ( arccdbsize > 256)
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE;
if (pcmd->cmnd[0]|WRITE_6 || pcmd->cmnd[0] | WRITE_10 || pcmd->cmnd[0]|WRITE_12) {
arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE;
- ccb->ccb_flags |= CCB_FLAG_WRITE;
}
+ ccb->arc_cdb_size = arccdbsize;
return SUCCESS;
}
static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb)
{
- uint32_t shifted_cdb_phyaddr = ccb->shifted_cdb_phyaddr;
+ uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern;
struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb;
atomic_inc(&acb->ccboutstandingcount);
ccb->startdone = ARCMSR_CCB_START;
@@ -1096,10 +1189,10 @@ static void arcmsr_post_ccb(struct Adapt
struct MessageUnit_A __iomem *reg = acb->pmuA;
if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE)
- writel(shifted_cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
+ writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,
®->inbound_queueport);
else {
- writel(shifted_cdb_phyaddr, ®->inbound_queueport);
+ writel(cdb_phyaddr_pattern, ®->inbound_queueport);
}
}
break;
@@ -1111,11 +1204,10 @@ static void arcmsr_post_ccb(struct Adapt
ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE);
writel(0, ®->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,\
®->post_qbuffer[index]);
- }
- else {
- writel(shifted_cdb_phyaddr, ®->post_qbuffer[index]);
+ } else {
+ writel(cdb_phyaddr_pattern, ®->post_qbuffer[index]);
}
index++;
index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */
@@ -1123,6 +1215,19 @@ static void arcmsr_post_ccb(struct Adapt
writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t ccb_post_stamp, arc_cdb_size;
+
+ arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size;
+ ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1);
+ if (acb->cdb_phyaddr_hi32) {
+ writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high);
+ writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+ } else {
+ writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
+ }
+ }
}
}
@@ -1131,8 +1236,7 @@ static void arcmsr_stop_hba_bgrb(struct
struct MessageUnit_A __iomem *reg = acb->pmuA;
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->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);
@@ -1145,13 +1249,26 @@ static void arcmsr_stop_hbb_bgrb(struct
acb->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE
"arcmsr%d: wait 'stop adapter background rebulid' timeout \n"
, acb->host->host_no);
}
}
+static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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) {
@@ -1164,22 +1281,16 @@ static void arcmsr_stop_adapter_bgrb(str
arcmsr_stop_hbb_bgrb(acb);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_stop_hbc_bgrb(acb);
+ }
}
}
static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
{
- switch (acb->adapter_type) {
- case ACB_ADAPTER_TYPE_A: {
- dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
- iounmap(acb->pmuA);
- }
- break;
- case ACB_ADAPTER_TYPE_B: {
dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle);
}
- }
-}
void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
{
@@ -1195,6 +1306,10 @@ void arcmsr_iop_message_read(struct Adap
writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell);
+ }
}
}
@@ -1220,6 +1335,15 @@ static void arcmsr_iop_message_wrote(str
writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ /*
+ ** push inbound doorbell tell iop, driver data write ok
+ ** and wait reply on next hwinterrupt for next Qbuffer post
+ */
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, ®->inbound_doorbell);
+ }
+ break;
}
}
@@ -1240,6 +1363,10 @@ struct QBUFFER __iomem *arcmsr_get_iop_r
qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC;
+ qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer;
+ }
}
return qbuffer;
}
@@ -1261,6 +1387,11 @@ static struct QBUFFER __iomem *arcmsr_ge
pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ pqbuffer = (struct QBUFFER __iomem *)®->message_wbuffer;
+ }
+
}
return pqbuffer;
}
@@ -1345,14 +1474,42 @@ static void arcmsr_hba_doorbell_isr(stru
arcmsr_iop2drv_data_read_handle(acb);
}
}
-
+static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB)
+{
+ uint32_t outbound_doorbell;
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC;
+ /*
+ *******************************************************************
+ ** Maybe here we need to check wrqbuffer_lock is lock or not
+ ** DOORBELL: din! don!
+ ** check if there are any mail need to pack from firmware
+ *******************************************************************
+ */
+ outbound_doorbell = readl(®->outbound_doorbell);
+ writel(outbound_doorbell, ®->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(®->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);
}
}
@@ -1361,17 +1518,51 @@ static void arcmsr_hbb_postqueue_isr(str
uint32_t index;
uint32_t flag_ccb;
struct MessageUnit_B *reg = acb->pmuB;
-
+ struct ARCMSR_CDB *pARCMSR_CDB;
+ struct CommandControlBlock *pCCB;
+ bool error;
index = reg->doneq_index;
-
while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) {
writel(0, ®->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
@@ -1395,6 +1586,23 @@ static void arcmsr_hbb_message_isr(struc
writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell);
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
+/*
+**********************************************************************************
+** Handle a message interrupt
+**
+** The only message interrupt we expect is in response to a query for the
+** current adapter config.
+** We want this in order to compare the drivemap so that we can detect newly-attached drives.
+**********************************************************************************
+*/
+static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_C *reg = acb->pmuC;
+ /*clear interrupt and message state*/
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear);
+ schedule_work(&acb->arcmsr_do_message_isr_bh);
+}
+
static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb)
{
uint32_t outbound_intstatus;
@@ -1447,7 +1653,31 @@ static int arcmsr_handle_hbb_isr(struct
/* 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)
@@ -1466,6 +1696,11 @@ static irqreturn_t arcmsr_interrupt(stru
}
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ if (arcmsr_handle_hbc_isr(acb)) {
+ return IRQ_NONE;
+ }
+ }
}
return IRQ_HANDLED;
}
@@ -1877,7 +2107,10 @@ static int arcmsr_queue_command(struct s
if (atomic_read(&acb->ccboutstandingcount) >=
ARCMSR_MAX_OUTSTANDING_CMD)
return SCSI_MLQUEUE_HOST_BUSY;
-
+ if ((scsicmd == SCSI_CMD_ARECA_SPECIFIC)) {
+ printk(KERN_NOTICE "Receiveing SCSI_CMD_ARECA_SPECIFIC command..\n");
+ return 0;
+ }
ccb = arcmsr_get_freeccb(acb);
if (!ccb)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -1900,9 +2133,8 @@ static bool arcmsr_get_hba_config(struct
char __iomem *iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]);
char __iomem *iop_device_map = (char __iomem *) (®->message_rwbuffer[21]);
int count;
-
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->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;
@@ -1978,7 +2210,7 @@ static bool arcmsr_get_hbb_config(struct
iop_device_map = (char __iomem *)(®->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;
@@ -2025,12 +2257,73 @@ static bool arcmsr_get_hbb_config(struct
/*firm_ide_channels,4,16-19*/
return true;
}
+
+static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB)
+{
+ uint32_t intmask_org, Index, firmware_state = 0;
+ struct MessageUnit_C *reg = pACB->pmuC;
+ char *acb_firm_model = pACB->firm_model;
+ char *acb_firm_version = pACB->firm_version;
+ char *iop_firm_model = (char *)(®->msgcode_rwbuffer[15]); /*firm_model,15,60-67*/
+ char *iop_firm_version = (char *)(®->msgcode_rwbuffer[17]); /*firm_version,17,68-83*/
+ int count;
+ /* disable all outbound interrupt */
+ intmask_org = readl(®->host_int_mask); /* disable outbound message0 int */
+ writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask);
+ /* wait firmware ready */
+ do {
+ firmware_state = readl(®->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+ /* post "get config" instruction */
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell);
+ /* wait message ready */
+ for (Index = 0; Index < 2000; Index++) {
+ if (readl(®->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) {
+ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->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(®->msgcode_rwbuffer[1]); /*firm_request_len,1,04-07*/
+ pACB->firm_numbers_queue = readl(®->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/
+ pACB->firm_sdram_size = readl(®->msgcode_rwbuffer[3]); /*firm_sdram_size,3,12-15*/
+ pACB->firm_hd_channels = readl(®->msgcode_rwbuffer[4]); /*firm_ide_channels,4,16-19*/
+ pACB->firm_cfg_version = readl(®->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,
@@ -2041,7 +2334,7 @@ static int arcmsr_polling_hba_ccbdone(st
struct ARCMSR_CDB *arcmsr_cdb;
uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0;
int rtn;
-
+ bool error;
polling_hba_ccb_retry:
poll_count++;
outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable;
@@ -2052,6 +2345,7 @@ static int arcmsr_polling_hba_ccbdone(st
rtn = SUCCESS;
break;
} else {
+ msleep(25);
if (poll_count > 100) {
rtn = FAILED;
break;
@@ -2081,9 +2375,9 @@ static int arcmsr_polling_hba_ccbdone(st
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
- } else {
- arcmsr_report_ccb_state(acb, ccb, flag_ccb);
}
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_report_ccb_state(acb, ccb, error);
}
return rtn;
}
@@ -2096,7 +2390,7 @@ static int arcmsr_polling_hbb_ccbdone(st
struct CommandControlBlock *ccb;
uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;
int index, rtn;
-
+ bool error;
polling_hbb_ccb_retry:
poll_count++;
/* clear doorbell interrupt */
@@ -2144,13 +2438,69 @@ static int arcmsr_polling_hbb_ccbdone(st
, ccb
, atomic_read(&acb->ccboutstandingcount));
continue;
- } else {
- arcmsr_report_ccb_state(acb, ccb, flag_ccb);
}
- } /*drain reply FIFO*/
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false;
+ arcmsr_report_ccb_state(acb, ccb, error);
+ }
return rtn;
}
+static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb)
+{
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t flag_ccb, ccb_cdb_phy;
+ struct ARCMSR_CDB *arcmsr_cdb;
+ bool error;
+ struct CommandControlBlock *pCCB;
+ uint32_t poll_ccb_done = 0, poll_count = 0;
+ int rtn;
+polling_hbc_ccb_retry:
+ poll_count++;
+ while (1) {
+ if ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) {
+ if (poll_ccb_done) {
+ rtn = SUCCESS;
+ break;
+ } else {
+ msleep(25);
+ if (poll_count > 100) {
+ rtn = FAILED;
+ break;
+ }
+ goto polling_hbc_ccb_retry;
+ }
+ }
+ flag_ccb = readl(®->outbound_queueport_low);
+ ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
+ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/
+ pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb);
+ poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0;
+ /* check ifcommand done with no error*/
+ if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
+ if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
+ printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"
+ " poll command abort successfully \n"
+ , acb->host->host_no
+ , pCCB->pcmd->device->id
+ , pCCB->pcmd->device->lun
+ , pCCB);
+ pCCB->pcmd->result = DID_ABORT << 16;
+ arcmsr_ccb_complete(pCCB);
+ continue;
+ }
+ printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"
+ " command done ccb = '0x%p'"
+ "ccboutstandingcount = %d \n"
+ , acb->host->host_no
+ , pCCB
+ , atomic_read(&acb->ccboutstandingcount));
+ continue;
+ }
+ error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
+ arcmsr_report_ccb_state(acb, pCCB, error);
+ }
+ return rtn;
+}
static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
@@ -2165,6 +2515,10 @@ static int arcmsr_polling_ccbdone(struct
case ACB_ADAPTER_TYPE_B: {
rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb);
}
+ break;
+ case ACB_ADAPTER_TYPE_C: {
+ rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb);
+ }
}
return rtn;
}
@@ -2182,6 +2536,7 @@ static int arcmsr_iop_confirm(struct Ada
dma_coherent_handle = acb->dma_coherent_handle;
cdb_phyaddr = (uint32_t)(dma_coherent_handle);
cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);
+ acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32;
/*
***********************************************************************
** if adapter type B, set window of "post command Q"
@@ -2199,7 +2554,7 @@ static int arcmsr_iop_confirm(struct Ada
writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]);
writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \
®->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);
@@ -2220,7 +2575,7 @@ static int arcmsr_iop_confirm(struct Ada
reg->postq_index = 0;
reg->doneq_index = 0;
writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \
acb->host->host_no);
return 1;
@@ -2239,7 +2594,7 @@ static int arcmsr_iop_confirm(struct Ada
writel(1056, rwbuffer);
writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \
timeout \n",acb->host->host_no);
return 1;
@@ -2248,6 +2603,27 @@ static int arcmsr_iop_confirm(struct Ada
arcmsr_enable_outbound_ints(acb, intmask_org);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ if (cdb_phyaddr_hi32 != 0) {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+
+ if (cdb_phyaddr_hi32 != 0) {
+ unsigned char Retries = 0x00;
+ do {
+ printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x \n", acb->adapter_index, cdb_phyaddr_hi32);
+ } while (Retries++ < 100);
+ }
+ writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->msgcode_rwbuffer[0]);
+ writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]);
+ writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->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;
}
@@ -2274,6 +2649,12 @@ static void arcmsr_wait_firmware_ready(s
writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ do {
+ firmware_state = readl(®->outbound_msgaddr1);
+ } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
+ }
}
}
@@ -2316,6 +2696,26 @@ static void arcmsr_request_hbb_device_ma
return;
}
+static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_C __iomem *reg = acb->pmuC;
+ if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) {
+ return;
+ } else {
+ acb->fw_flag = FW_NORMAL;
+ if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) {
+ atomic_set(&acb->rq_map_token, 16);
+ }
+ atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token));
+ if (atomic_dec_and_test(&acb->rq_map_token))
+ return;
+ writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell);
+ mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ));
+ }
+ return;
+}
+
static void arcmsr_request_device_map(unsigned long pacb)
{
struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
@@ -2329,6 +2728,9 @@ static void arcmsr_request_device_map(un
arcmsr_request_hbb_device_map(acb);
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ arcmsr_request_hbc_device_map(acb);
+ }
}
}
@@ -2337,7 +2739,7 @@ static void arcmsr_start_hba_bgrb(struct
struct MessageUnit_A __iomem *reg = acb->pmuA;
acb->acb_flags |= ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->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);
}
@@ -2348,12 +2750,24 @@ static void arcmsr_start_hbb_bgrb(struct
struct MessageUnit_B *reg = acb->pmuB;
acb->acb_flags |= ACB_F_MSG_START_BGRB;
writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell);
- if (arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
rebulid' timeout \n",acb->host->host_no);
}
}
+static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB)
+{
+ struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC;
+ pACB->acb_flags |= ACB_F_MSG_START_BGRB;
+ writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0);
+ writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell);
+ if (!arcmsr_hbc_wait_msgint_ready(pACB)) {
+ printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \
+ rebulid' timeout \n", pACB->host->host_no);
+ }
+ return;
+}
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@@ -2363,6 +2777,8 @@ static void arcmsr_start_adapter_bgrb(st
case ACB_ADAPTER_TYPE_B:
arcmsr_start_hbb_bgrb(acb);
break;
+ case ACB_ADAPTER_TYPE_C:
+ arcmsr_start_hbc_bgrb(acb);
}
}
@@ -2388,6 +2804,14 @@ static void arcmsr_clear_doorbell_queue_
/* let IOP know data has been read */
}
break;
+ case ACB_ADAPTER_TYPE_C: {
+ struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC;
+ uint32_t outbound_doorbell;
+ /* empty doorbell Qbuffer if door bell ringed */
+ outbound_doorbell = readl(®->outbound_doorbell);
+ writel(outbound_doorbell, ®->outbound_doorbell_clear);
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell);
+ }
}
}
@@ -2400,12 +2824,14 @@ static void arcmsr_enable_eoi_mode(struc
{
struct MessageUnit_B *reg = acb->pmuB;
writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell);
- if(arcmsr_hbb_wait_msgint_ready(acb)) {
+ if (!arcmsr_hbb_wait_msgint_ready(acb)) {
printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT");
return;
}
}
break;
+ case ACB_ADAPTER_TYPE_C:
+ return;
}
return;
}
@@ -2413,21 +2839,33 @@ static void arcmsr_enable_eoi_mode(struc
static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
{
uint8_t value[64];
- int i;
- struct MessageUnit_A __iomem *reg = acb->pmuA;
-
+ int i, count = 0;
+ struct MessageUnit_A __iomem *pmuA = acb->pmuA;
+ struct MessageUnit_C __iomem *pmuC = acb->pmuC;
+ u32 temp = 0;
/* backup pci config data */
- printk(KERN_ERR "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
+ printk(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, ®->reserved1[0]);
+ writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]);
+ } else if ((acb->dev_id == 0x1880)) {
+ do {
+ count++;
+ writel(0xF, &pmuC->write_sequence);
+ writel(0x4, &pmuC->write_sequence);
+ writel(0xB, &pmuC->write_sequence);
+ writel(0x2, &pmuC->write_sequence);
+ writel(0x7, &pmuC->write_sequence);
+ writel(0xD, &pmuC->write_sequence);
+ } while ((((temp = readl(&pmuC->host_diagnostic)) | ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5));
+ writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic);
} else {
pci_write_config_byte(acb->pdev, 0x84, 0x20);
}
- msleep(1000);
+ msleep(2000);
/* write back pci config data */
for (i=0;i<64;i++) {
pci_write_config_byte(acb->pdev, i, value[i]);
@@ -2435,29 +2873,6 @@ static void arcmsr_hardware_reset(struct
msleep(1000);
return;
}
-/*
-****************************************************************************
-****************************************************************************
-*/
-int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd)
-{
- struct Scsi_Host *shost = NULL;
- int i, isleep;
-
- shost = cmd->device->host;
- isleep = sleeptime / 10;
- if (isleep > 0) {
- for (i = 0; i < isleep; i ++) {
- msleep(10000);
- }
- }
-
- isleep = sleeptime % 10;
- if (isleep > 0) {
- msleep(isleep*1000);
- }
- return 0;
-}
static void arcmsr_iop_init(struct AdapterControlBlock *acb)
{
uint32_t intmask_org;
@@ -2510,24 +2924,22 @@ static int arcmsr_bus_reset(struct scsi_
uint32_t intmask_org, outbound_doorbell;
int retry_count = 0;
int rtn = FAILED;
-
acb = (struct AdapterControlBlock *) cmd->device->host->hostdata;
- printk(KERN_ERR "arcmsr: executing eh bus reset .....num_resets = %d, \
- num_aborts = %d \n", acb->num_resets, acb->num_aborts);
+ printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts);
acb->num_resets++;
switch(acb->adapter_type){
case ACB_ADAPTER_TYPE_A:{
if (acb->acb_flags & ACB_F_BUS_RESET) {
long timeout;
- timeout = wait_event_timeout(wait_q,
- (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
+ printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n");
+ timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ);
if (timeout) {
return SUCCESS;
}
}
acb->acb_flags |= ACB_F_BUS_RESET;
- if (arcmsr_iop_reset(acb)) {
+ if (!arcmsr_iop_reset(acb)) {
struct MessageUnit_A __iomem *reg;
reg = acb->pmuA;
arcmsr_hardware_reset(acb);
@@ -2535,12 +2947,10 @@ static int arcmsr_bus_reset(struct scsi_
sleep_again:
arcmsr_sleep_for_bus_reset(cmd);
if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) {
- printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
- retry=%d \n", acb->host->host_no, retry_count);
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d \n", acb->host->host_no, retry_count);
if (retry_count > retrycount) {
acb->fw_flag = FW_DEADLOCK;
- printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, \
- RETRY TERMINATED!! \n", acb->host->host_no);
+ printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!! \n", acb->host->host_no);
return FAILED;
}
retry_count++;
@@ -2567,7 +2977,7 @@ 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) {
@@ -2591,7 +3001,7 @@ sleep_again:
}
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 {
@@ -2613,6 +3023,77 @@ sleep_again:
}
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(®->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(®->outbound_doorbell);
+ writel(outbound_doorbell, ®->outbound_doorbell_clear); /*clear interrupt */
+ writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->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;
@@ -2622,9 +3103,7 @@ static int arcmsr_abort_one_cmd(struct A
struct CommandControlBlock *ccb)
{
int rtn;
- spin_lock_irq(&acb->eh_lock);
rtn = arcmsr_polling_ccbdone(acb, ccb);
- spin_unlock_irq(&acb->eh_lock);
return rtn;
}
@@ -2692,6 +3169,7 @@ static const char *arcmsr_info(struct Sc
case PCI_DEVICE_ID_ARECA_1381:
case PCI_DEVICE_ID_ARECA_1680:
case PCI_DEVICE_ID_ARECA_1681:
+ case PCI_DEVICE_ID_ARECA_1880:
type = "SAS";
break;
default:
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2010-06-21 14:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-06-21 3:02 [PATCH 2/3] SCSI: Support Type C RAID controller Nick Cheng
2010-06-21 14:16 ` James Bottomley
-- strict thread matches above, loose matches on Subject: below --
2010-06-18 7:39 Nick Cheng
2010-06-20 14:18 ` James Bottomley
2010-05-26 4:55 Nick Cheng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox