scsi: arcmsr: Add code for ACB_ADAPTER_TYPE_E

Add code for ACB_ADAPTER_TYPE_E to support new adapter ARC-1884.

Signed-off-by: Ching Huang <ching2048@areca.com.tw>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Ching Huang 2017-12-05 09:35:34 +08:00 committed by Martin K. Petersen
parent 72a7f3130f
commit 235090241c
2 changed files with 649 additions and 3 deletions

View File

@ -65,6 +65,7 @@ struct device_attribute;
#define ARCMSR_MAX_HBB_POSTQUEUE 264
#define ARCMSR_MAX_ARC1214_POSTQUEUE 256
#define ARCMSR_MAX_ARC1214_DONEQUEUE 257
#define ARCMSR_MAX_HBE_DONEQUEUE 512
#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */
#define ARCMSR_CDB_SG_PAGE_LENGTH 256
#define ARCMST_NUM_MSIX_VECTORS 4
@ -77,6 +78,9 @@ struct device_attribute;
#ifndef PCI_DEVICE_ID_ARECA_1203
#define PCI_DEVICE_ID_ARECA_1203 0x1203
#endif
#ifndef PCI_DEVICE_ID_ARECA_1884
#define PCI_DEVICE_ID_ARECA_1884 0x1884
#endif
/*
**********************************************************************************
**
@ -407,6 +411,31 @@ struct FIRMWARE_INFO
#define ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR 0x00000001
/*
*******************************************************************************
** SPEC. for Areca Type E adapter
*******************************************************************************
*/
#define ARCMSR_SIGNATURE_1884 0x188417D3
#define ARCMSR_HBEMU_DRV2IOP_DATA_WRITE_OK 0x00000002
#define ARCMSR_HBEMU_DRV2IOP_DATA_READ_OK 0x00000004
#define ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE 0x00000008
#define ARCMSR_HBEMU_IOP2DRV_DATA_WRITE_OK 0x00000002
#define ARCMSR_HBEMU_IOP2DRV_DATA_READ_OK 0x00000004
#define ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE 0x00000008
#define ARCMSR_HBEMU_MESSAGE_FIRMWARE_OK 0x80000000
#define ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR 0x00000001
#define ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR 0x00000008
#define ARCMSR_HBEMU_ALL_INTMASKENABLE 0x00000009
/* ARC-1884 doorbell sync */
#define ARCMSR_HBEMU_DOORBELL_SYNC 0x100
#define ARCMSR_ARC188X_RESET_ADAPTER 0x00000004
#define ARCMSR_ARC1884_DiagWrite_ENABLE 0x00000080
/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
*******************************************************************************
*/
@ -614,6 +643,88 @@ struct MessageUnit_D {
u32 __iomem *msgcode_rwbuffer; /* 0x2200 */
};
/*
*********************************************************************
** Messaging Unit (MU) of Type E processor(LSI)
*********************************************************************
*/
struct MessageUnit_E{
uint32_t iobound_doorbell; /*0000 0003*/
uint32_t write_sequence_3xxx; /*0004 0007*/
uint32_t host_diagnostic_3xxx; /*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 reply_post_producer_index; /*0068 006B*/
uint32_t reply_post_consumer_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*/
};
typedef struct deliver_completeQ {
uint16_t cmdFlag;
uint16_t cmdSMID;
uint16_t cmdLMID; // reserved (0)
uint16_t cmdFlag2; // reserved (0)
} DeliverQ, CompletionQ, *pDeliver_Q, *pCompletion_Q;
/*
*******************************************************************************
** Adapter Control Block
*******************************************************************************
@ -625,6 +736,7 @@ struct AdapterControlBlock
#define ACB_ADAPTER_TYPE_B 0x00000001 /* hbb M IOP */
#define ACB_ADAPTER_TYPE_C 0x00000002 /* hbc L IOP */
#define ACB_ADAPTER_TYPE_D 0x00000003 /* hbd M IOP */
#define ACB_ADAPTER_TYPE_E 0x00000004 /* hba L IOP */
u32 roundup_ccbsize;
struct pci_dev * pdev;
struct Scsi_Host * host;
@ -644,6 +756,7 @@ struct AdapterControlBlock
struct MessageUnit_B *pmuB;
struct MessageUnit_C __iomem *pmuC;
struct MessageUnit_D *pmuD;
struct MessageUnit_E __iomem *pmuE;
};
/* message unit ATU inbound base address0 */
void __iomem *mem_base0;
@ -723,6 +836,12 @@ struct AdapterControlBlock
atomic_t ante_token_value;
uint32_t maxOutstanding;
int vector_count;
uint32_t doneq_index;
uint32_t ccbsize;
uint32_t in_doorbell;
uint32_t out_doorbell;
uint32_t completionQ_entry;
pCompletion_Q pCompletionQ;
};/* HW_DEVICE_EXTENSION */
/*
*******************************************************************************
@ -748,12 +867,13 @@ struct CommandControlBlock{
#define ARCMSR_CCB_START 0x55AA
#define ARCMSR_CCB_ABORTED 0xAA55
#define ARCMSR_CCB_ILLEGAL 0xFFFF
uint32_t smid;
#if BITS_PER_LONG == 64
/* ======================512+64 bytes======================== */
uint32_t reserved[5]; /*24 byte*/
uint32_t reserved[4]; /*16 byte*/
#else
/* ======================512+32 bytes======================== */
uint32_t reserved; /*8 byte*/
// uint32_t reserved; /*4 byte*/
#endif
/* ======================================================= */
struct ARCMSR_CDB arcmsr_cdb;

View File

@ -110,6 +110,8 @@ static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb);
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb);
static void arcmsr_hbaC_message_isr(struct AdapterControlBlock *pACB);
static void arcmsr_hbaD_message_isr(struct AdapterControlBlock *acb);
static void arcmsr_hbaE_message_isr(struct AdapterControlBlock *acb);
static void arcmsr_hbaE_postqueue_isr(struct AdapterControlBlock *acb);
static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
@ -184,6 +186,8 @@ static struct pci_device_id arcmsr_device_id_table[] = {
.driver_data = ACB_ADAPTER_TYPE_A},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880),
.driver_data = ACB_ADAPTER_TYPE_C},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1884),
.driver_data = ACB_ADAPTER_TYPE_E},
{0, 0}, /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table);
@ -206,7 +210,8 @@ static void arcmsr_free_mu(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_B:
case ACB_ADAPTER_TYPE_D: {
case ACB_ADAPTER_TYPE_D:
case ACB_ADAPTER_TYPE_E: {
dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
acb->dma_coherent2, acb->dma_coherent_handle2);
break;
@ -271,6 +276,20 @@ static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
acb->mem_base0 = mem_base0;
break;
}
case ACB_ADAPTER_TYPE_E: {
acb->pmuE = ioremap(pci_resource_start(pdev, 1),
pci_resource_len(pdev, 1));
if (!acb->pmuE) {
pr_notice("arcmsr%d: memory mapping region fail \n",
acb->host->host_no);
return false;
}
writel(0, &acb->pmuE->host_int_status); /*clear interrupt*/
writel(ARCMSR_HBEMU_DOORBELL_SYNC, &acb->pmuE->iobound_doorbell); /* synchronize doorbell to 0 */
acb->in_doorbell = 0;
acb->out_doorbell = 0;
break;
}
}
return true;
}
@ -295,6 +314,9 @@ static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_D:
iounmap(acb->mem_base0);
break;
case ACB_ADAPTER_TYPE_E:
iounmap(acb->pmuE);
break;
}
}
@ -408,6 +430,24 @@ static bool arcmsr_hbaD_wait_msgint_ready(struct AdapterControlBlock *pACB)
return false;
}
static bool arcmsr_hbaE_wait_msgint_ready(struct AdapterControlBlock *pACB)
{
int i;
uint32_t read_doorbell;
struct MessageUnit_E __iomem *phbcmu = pACB->pmuE;
for (i = 0; i < 2000; i++) {
read_doorbell = readl(&phbcmu->iobound_doorbell);
if ((read_doorbell ^ pACB->in_doorbell) & ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE) {
writel(0, &phbcmu->host_int_status); /*clear interrupt*/
pACB->in_doorbell = read_doorbell;
return true;
}
msleep(10);
} /* max 20 seconds */
return false;
}
static void arcmsr_hbaA_flush_cache(struct AdapterControlBlock *acb)
{
struct MessageUnit_A __iomem *reg = acb->pmuA;
@ -475,6 +515,24 @@ static void arcmsr_hbaD_flush_cache(struct AdapterControlBlock *pACB)
} while (retry_count != 0);
}
static void arcmsr_hbaE_flush_cache(struct AdapterControlBlock *pACB)
{
int retry_count = 30;
struct MessageUnit_E __iomem *reg = pACB->pmuE;
writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, &reg->inbound_msgaddr0);
pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
writel(pACB->out_doorbell, &reg->iobound_doorbell);
do {
if (arcmsr_hbaE_wait_msgint_ready(pACB))
break;
retry_count--;
pr_notice("arcmsr%d: wait 'flush adapter "
"cache' timeout, retry count down = %d\n",
pACB->host->host_no, retry_count);
} while (retry_count != 0);
}
static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@ -495,6 +553,9 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_D:
arcmsr_hbaD_flush_cache(acb);
break;
case ACB_ADAPTER_TYPE_E:
arcmsr_hbaE_flush_cache(acb);
break;
}
}
@ -577,6 +638,23 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb)
reg->msgcode_rwbuffer = MEM_BASE0(ARCMSR_ARC1214_MESSAGE_RWBUFFER);
}
break;
case ACB_ADAPTER_TYPE_E: {
uint32_t completeQ_size;
completeQ_size = sizeof(struct deliver_completeQ) * ARCMSR_MAX_HBE_DONEQUEUE + 128;
acb->roundup_ccbsize = roundup(completeQ_size, 32);
dma_coherent = dma_zalloc_coherent(&pdev->dev, acb->roundup_ccbsize,
&dma_coherent_handle, GFP_KERNEL);
if (!dma_coherent){
pr_notice("arcmsr%d: DMA allocation failed\n", acb->host->host_no);
return false;
}
acb->dma_coherent_handle2 = dma_coherent_handle;
acb->dma_coherent2 = dma_coherent;
acb->pCompletionQ = dma_coherent;
acb->completionQ_entry = acb->roundup_ccbsize / sizeof(struct deliver_completeQ);
acb->doneq_index = 0;
}
break;
default:
break;
}
@ -619,6 +697,7 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
acb->dma_coherent = dma_coherent;
acb->dma_coherent_handle = dma_coherent_handle;
memset(dma_coherent, 0, acb->uncache_size);
acb->ccbsize = roundup_ccbsize;
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++){
@ -630,11 +709,13 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
break;
case ACB_ADAPTER_TYPE_C:
case ACB_ADAPTER_TYPE_D:
case ACB_ADAPTER_TYPE_E:
ccb_tmp->cdb_phyaddr = cdb_phyaddr;
break;
}
acb->pccb_pool[i] = ccb_tmp;
ccb_tmp->acb = acb;
ccb_tmp->smid = (u32)i << 16;
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);
@ -683,6 +764,13 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work)
devicemap = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
break;
}
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
signature = (uint32_t __iomem *)(&reg->msgcode_rwbuffer[0]);
devicemap = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
break;
}
}
atomic_inc(&acb->rq_map_token);
if (readl(signature) != ARCMSR_SIGNATURE_GET_CONFIG)
@ -998,6 +1086,21 @@ static uint8_t arcmsr_hbaD_abort_allcmd(struct AdapterControlBlock *pACB)
return true;
}
static uint8_t arcmsr_hbaE_abort_allcmd(struct AdapterControlBlock *pACB)
{
struct MessageUnit_E __iomem *reg = pACB->pmuE;
writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
writel(pACB->out_doorbell, &reg->iobound_doorbell);
if (!arcmsr_hbaE_wait_msgint_ready(pACB)) {
pr_notice("arcmsr%d: wait 'abort all outstanding "
"command' timeout\n", pACB->host->host_no);
return false;
}
return true;
}
static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
{
uint8_t rtnval = 0;
@ -1020,6 +1123,9 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_D:
rtnval = arcmsr_hbaD_abort_allcmd(acb);
break;
case ACB_ADAPTER_TYPE_E:
rtnval = arcmsr_hbaE_abort_allcmd(acb);
break;
}
return rtnval;
}
@ -1092,6 +1198,13 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
writel(ARCMSR_ARC1214_ALL_INT_DISABLE, reg->pcief0_int_enable);
}
break;
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
orig_mask = readl(&reg->host_int_mask);
writel(orig_mask | ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR | ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR, &reg->host_int_mask);
readl(&reg->host_int_mask); /* Dummy readl to force pci flush */
}
break;
}
return orig_mask;
}
@ -1280,6 +1393,9 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
pmu->doneq_index = 0x40FF;
}
break;
case ACB_ADAPTER_TYPE_E:
arcmsr_hbaE_postqueue_isr(acb);
break;
}
}
@ -1396,6 +1512,13 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
writel(intmask_org | mask, reg->pcief0_int_enable);
break;
}
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
mask = ~(ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR | ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR);
writel(intmask_org & mask, &reg->host_int_mask);
break;
}
}
}
@ -1527,6 +1650,16 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr
spin_unlock_irqrestore(&acb->postq_lock, flags);
break;
}
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *pmu = acb->pmuE;
u32 ccb_post_stamp, arc_cdb_size;
arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size;
ccb_post_stamp = (ccb->smid | ((arc_cdb_size - 1) >> 6));
writel(0, &pmu->inbound_queueport_high);
writel(ccb_post_stamp, &pmu->inbound_queueport_low);
break;
}
}
}
@ -1580,6 +1713,20 @@ static void arcmsr_hbaD_stop_bgrb(struct AdapterControlBlock *pACB)
"timeout\n", pACB->host->host_no);
}
static void arcmsr_hbaE_stop_bgrb(struct AdapterControlBlock *pACB)
{
struct MessageUnit_E __iomem *reg = pACB->pmuE;
pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, &reg->inbound_msgaddr0);
pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
writel(pACB->out_doorbell, &reg->iobound_doorbell);
if (!arcmsr_hbaE_wait_msgint_ready(pACB)) {
pr_notice("arcmsr%d: wait 'stop adapter background rebulid' "
"timeout\n", pACB->host->host_no);
}
}
static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@ -1599,6 +1746,9 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_D:
arcmsr_hbaD_stop_bgrb(acb);
break;
case ACB_ADAPTER_TYPE_E:
arcmsr_hbaE_stop_bgrb(acb);
break;
}
}
@ -1633,6 +1783,12 @@ static void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
reg->inbound_doorbell);
}
break;
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_READ_OK;
writel(acb->out_doorbell, &reg->iobound_doorbell);
}
break;
}
}
@ -1673,6 +1829,12 @@ static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
reg->inbound_doorbell);
}
break;
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_WRITE_OK;
writel(acb->out_doorbell, &reg->iobound_doorbell);
}
break;
}
}
@ -1702,6 +1864,11 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
}
break;
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
qbuffer = (struct QBUFFER __iomem *)&reg->message_rbuffer;
}
break;
}
return qbuffer;
}
@ -1732,6 +1899,11 @@ static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBloc
pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
}
break;
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
pqbuffer = (struct QBUFFER __iomem *)&reg->message_wbuffer;
}
break;
}
return pqbuffer;
}
@ -1968,6 +2140,33 @@ static void arcmsr_hbaD_doorbell_isr(struct AdapterControlBlock *pACB)
| ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE));
}
static void arcmsr_hbaE_doorbell_isr(struct AdapterControlBlock *pACB)
{
uint32_t outbound_doorbell, in_doorbell, tmp;
struct MessageUnit_E __iomem *reg = pACB->pmuE;
in_doorbell = readl(&reg->iobound_doorbell);
outbound_doorbell = in_doorbell ^ pACB->in_doorbell;
do {
writel(0, &reg->host_int_status); /* clear interrupt */
if (outbound_doorbell & ARCMSR_HBEMU_IOP2DRV_DATA_WRITE_OK) {
arcmsr_iop2drv_data_wrote_handle(pACB);
}
if (outbound_doorbell & ARCMSR_HBEMU_IOP2DRV_DATA_READ_OK) {
arcmsr_iop2drv_data_read_handle(pACB);
}
if (outbound_doorbell & ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE) {
arcmsr_hbaE_message_isr(pACB);
}
tmp = in_doorbell;
in_doorbell = readl(&reg->iobound_doorbell);
outbound_doorbell = tmp ^ in_doorbell;
} while (outbound_doorbell & (ARCMSR_HBEMU_IOP2DRV_DATA_WRITE_OK
| ARCMSR_HBEMU_IOP2DRV_DATA_READ_OK
| ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE));
pACB->in_doorbell = in_doorbell;
}
static void arcmsr_hbaA_postqueue_isr(struct AdapterControlBlock *acb)
{
uint32_t flag_ccb;
@ -2077,6 +2276,33 @@ static void arcmsr_hbaD_postqueue_isr(struct AdapterControlBlock *acb)
spin_unlock_irqrestore(&acb->doneq_lock, flags);
}
static void arcmsr_hbaE_postqueue_isr(struct AdapterControlBlock *acb)
{
uint32_t doneq_index;
uint16_t cmdSMID;
int error;
struct MessageUnit_E __iomem *pmu;
struct CommandControlBlock *ccb;
unsigned long flags;
spin_lock_irqsave(&acb->doneq_lock, flags);
doneq_index = acb->doneq_index;
pmu = acb->pmuE;
while ((readl(&pmu->reply_post_producer_index) & 0xFFFF) != doneq_index) {
cmdSMID = acb->pCompletionQ[doneq_index].cmdSMID;
ccb = acb->pccb_pool[cmdSMID];
error = (acb->pCompletionQ[doneq_index].cmdFlag
& ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
arcmsr_drain_donequeue(acb, ccb, error);
doneq_index++;
if (doneq_index >= acb->completionQ_entry)
doneq_index = 0;
}
acb->doneq_index = doneq_index;
writel(doneq_index, &pmu->reply_post_consumer_index);
spin_unlock_irqrestore(&acb->doneq_lock, flags);
}
/*
**********************************************************************************
** Handle a message interrupt
@ -2126,6 +2352,14 @@ static void arcmsr_hbaD_message_isr(struct AdapterControlBlock *acb)
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
static void arcmsr_hbaE_message_isr(struct AdapterControlBlock *acb)
{
struct MessageUnit_E __iomem *reg = acb->pmuE;
writel(0, &reg->host_int_status);
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
static int arcmsr_hbaA_handle_isr(struct AdapterControlBlock *acb)
{
uint32_t outbound_intstatus;
@ -2229,6 +2463,31 @@ static irqreturn_t arcmsr_hbaD_handle_isr(struct AdapterControlBlock *pACB)
return IRQ_HANDLED;
}
static irqreturn_t arcmsr_hbaE_handle_isr(struct AdapterControlBlock *pACB)
{
uint32_t host_interrupt_status;
struct MessageUnit_E __iomem *pmu = pACB->pmuE;
host_interrupt_status = readl(&pmu->host_int_status) &
(ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR |
ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR);
if (!host_interrupt_status)
return IRQ_NONE;
do {
/* MU ioctl transfer doorbell interrupts*/
if (host_interrupt_status & ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR) {
arcmsr_hbaE_doorbell_isr(pACB);
}
/* MU post queue interrupts*/
if (host_interrupt_status & ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR) {
arcmsr_hbaE_postqueue_isr(pACB);
}
host_interrupt_status = readl(&pmu->host_int_status);
} while (host_interrupt_status & (ARCMSR_HBEMU_OUTBOUND_POSTQUEUE_ISR |
ARCMSR_HBEMU_OUTBOUND_DOORBELL_ISR));
return IRQ_HANDLED;
}
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@ -2242,6 +2501,8 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
return arcmsr_hbaC_handle_isr(acb);
case ACB_ADAPTER_TYPE_D:
return arcmsr_hbaD_handle_isr(acb);
case ACB_ADAPTER_TYPE_E:
return arcmsr_hbaE_handle_isr(acb);
default:
return IRQ_NONE;
}
@ -2885,6 +3146,71 @@ static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
return true;
}
static bool arcmsr_hbaE_get_config(struct AdapterControlBlock *pACB)
{
char *acb_firm_model = pACB->firm_model;
char *acb_firm_version = pACB->firm_version;
struct MessageUnit_E __iomem *reg = pACB->pmuE;
char __iomem *iop_firm_model = (char __iomem *)(&reg->msgcode_rwbuffer[15]);
char __iomem *iop_firm_version = (char __iomem *)(&reg->msgcode_rwbuffer[17]);
uint32_t intmask_org, Index, firmware_state = 0, read_doorbell;
int count;
/* disable all outbound interrupt */
intmask_org = readl(&reg->host_int_mask); /* disable outbound message0 int */
writel(intmask_org | ARCMSR_HBEMU_ALL_INTMASKENABLE, &reg->host_int_mask);
/* wait firmware ready */
do {
firmware_state = readl(&reg->outbound_msgaddr1);
} while ((firmware_state & ARCMSR_HBEMU_MESSAGE_FIRMWARE_OK) == 0);
mdelay(20);
/* post "get config" instruction */
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
writel(pACB->out_doorbell, &reg->iobound_doorbell);
/* wait message ready */
for (Index = 0; Index < 2000; Index++) {
read_doorbell = readl(&reg->iobound_doorbell);
if ((read_doorbell ^ pACB->in_doorbell) & ARCMSR_HBEMU_IOP2DRV_MESSAGE_CMD_DONE) {
writel(0, &reg->host_int_status);
pACB->in_doorbell = read_doorbell;
break;
}
mdelay(1);
} /*max 1 seconds*/
if (Index >= 2000) {
pr_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--;
}
pACB->firm_request_len = readl(&reg->msgcode_rwbuffer[1]);
pACB->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[2]);
pACB->firm_sdram_size = readl(&reg->msgcode_rwbuffer[3]);
pACB->firm_hd_channels = readl(&reg->msgcode_rwbuffer[4]);
pACB->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
pACB->host->host_no,
pACB->firm_model,
pACB->firm_version);
return true;
}
static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
{
bool rtn = false;
@ -2902,6 +3228,9 @@ static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_D:
rtn = arcmsr_hbaD_get_config(acb);
break;
case ACB_ADAPTER_TYPE_E:
rtn = arcmsr_hbaE_get_config(acb);
break;
default:
break;
}
@ -3166,6 +3495,75 @@ polling_hbaD_ccb_retry:
return rtn;
}
static int arcmsr_hbaE_polling_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
bool error;
uint32_t poll_ccb_done = 0, poll_count = 0, doneq_index;
uint16_t cmdSMID;
unsigned long flags;
int rtn;
struct CommandControlBlock *pCCB;
struct MessageUnit_E __iomem *reg = acb->pmuE;
polling_hbaC_ccb_retry:
poll_count++;
while (1) {
spin_lock_irqsave(&acb->doneq_lock, flags);
doneq_index = acb->doneq_index;
if ((readl(&reg->reply_post_producer_index) & 0xFFFF) ==
doneq_index) {
spin_unlock_irqrestore(&acb->doneq_lock, flags);
if (poll_ccb_done) {
rtn = SUCCESS;
break;
} else {
msleep(25);
if (poll_count > 40) {
rtn = FAILED;
break;
}
goto polling_hbaC_ccb_retry;
}
}
cmdSMID = acb->pCompletionQ[doneq_index].cmdSMID;
doneq_index++;
if (doneq_index >= acb->completionQ_entry)
doneq_index = 0;
acb->doneq_index = doneq_index;
spin_unlock_irqrestore(&acb->doneq_lock, flags);
pCCB = acb->pccb_pool[cmdSMID];
poll_ccb_done |= (pCCB == poll_ccb) ? 1 : 0;
/* check if command done with no error*/
if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) {
if (pCCB->startdone == ARCMSR_CCB_ABORTED) {
pr_notice("arcmsr%d: scsi id = %d "
"lun = %d ccb = '0x%p' poll command "
"abort successfully\n"
, acb->host->host_no
, pCCB->pcmd->device->id
, (u32)pCCB->pcmd->device->lun
, pCCB);
pCCB->pcmd->result = DID_ABORT << 16;
arcmsr_ccb_complete(pCCB);
continue;
}
pr_notice("arcmsr%d: polling an illegal "
"ccb command done ccb = '0x%p' "
"ccboutstandingcount = %d\n"
, acb->host->host_no
, pCCB
, atomic_read(&acb->ccboutstandingcount));
continue;
}
error = (acb->pCompletionQ[doneq_index].cmdFlag &
ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
arcmsr_report_ccb_state(acb, pCCB, error);
}
writel(doneq_index, &reg->reply_post_consumer_index);
return rtn;
}
static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
@ -3188,6 +3586,9 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
case ACB_ADAPTER_TYPE_D:
rtn = arcmsr_hbaD_polling_ccbdone(acb, poll_ccb);
break;
case ACB_ADAPTER_TYPE_E:
rtn = arcmsr_hbaE_polling_ccbdone(acb, poll_ccb);
break;
}
return rtn;
}
@ -3208,6 +3609,10 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_D:
dma_coherent_handle = acb->dma_coherent_handle2;
break;
case ACB_ADAPTER_TYPE_E:
dma_coherent_handle = acb->dma_coherent_handle +
offsetof(struct CommandControlBlock, arcmsr_cdb);
break;
default:
dma_coherent_handle = acb->dma_coherent_handle;
break;
@ -3316,6 +3721,29 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
}
}
break;
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->msgcode_rwbuffer[0]);
writel(ARCMSR_SIGNATURE_1884, &reg->msgcode_rwbuffer[1]);
writel(cdb_phyaddr, &reg->msgcode_rwbuffer[2]);
writel(cdb_phyaddr_hi32, &reg->msgcode_rwbuffer[3]);
writel(acb->ccbsize, &reg->msgcode_rwbuffer[4]);
dma_coherent_handle = acb->dma_coherent_handle2;
cdb_phyaddr = (uint32_t)(dma_coherent_handle & 0xffffffff);
cdb_phyaddr_hi32 = (uint32_t)((dma_coherent_handle >> 16) >> 16);
writel(cdb_phyaddr, &reg->msgcode_rwbuffer[5]);
writel(cdb_phyaddr_hi32, &reg->msgcode_rwbuffer[6]);
writel(acb->roundup_ccbsize, &reg->msgcode_rwbuffer[7]);
writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
writel(acb->out_doorbell, &reg->iobound_doorbell);
if (!arcmsr_hbaE_wait_msgint_ready(acb)) {
pr_notice("arcmsr%d: 'set command Q window' timeout \n",
acb->host->host_no);
return 1;
}
}
break;
}
return 0;
}
@ -3356,6 +3784,13 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK) == 0);
}
break;
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
do {
firmware_state = readl(&reg->outbound_msgaddr1);
} while ((firmware_state & ARCMSR_HBEMU_MESSAGE_FIRMWARE_OK) == 0);
}
break;
}
}
@ -3455,6 +3890,36 @@ static void arcmsr_hbaD_request_device_map(struct AdapterControlBlock *acb)
}
}
static void arcmsr_hbaE_request_device_map(struct AdapterControlBlock *acb)
{
struct MessageUnit_E __iomem *reg = acb->pmuE;
if (unlikely(atomic_read(&acb->rq_map_token) == 0) ||
((acb->acb_flags & ACB_F_BUS_RESET) != 0) ||
((acb->acb_flags & ACB_F_ABORT) != 0)) {
mod_timer(&acb->eternal_timer,
jiffies + msecs_to_jiffies(6 * HZ));
} else {
acb->fw_flag = FW_NORMAL;
if (atomic_read(&acb->ante_token_value) ==
atomic_read(&acb->rq_map_token)) {
atomic_set(&acb->rq_map_token, 16);
}
atomic_set(&acb->ante_token_value,
atomic_read(&acb->rq_map_token));
if (atomic_dec_and_test(&acb->rq_map_token)) {
mod_timer(&acb->eternal_timer, jiffies +
msecs_to_jiffies(6 * HZ));
return;
}
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->inbound_msgaddr0);
acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
writel(acb->out_doorbell, &reg->iobound_doorbell);
mod_timer(&acb->eternal_timer, jiffies +
msecs_to_jiffies(6 * HZ));
}
}
static void arcmsr_request_device_map(struct timer_list *t)
{
struct AdapterControlBlock *acb = from_timer(acb, t, eternal_timer);
@ -3474,6 +3939,9 @@ static void arcmsr_request_device_map(struct timer_list *t)
case ACB_ADAPTER_TYPE_D:
arcmsr_hbaD_request_device_map(acb);
break;
case ACB_ADAPTER_TYPE_E:
arcmsr_hbaE_request_device_map(acb);
break;
}
}
@ -3524,6 +3992,20 @@ static void arcmsr_hbaD_start_bgrb(struct AdapterControlBlock *pACB)
}
}
static void arcmsr_hbaE_start_bgrb(struct AdapterControlBlock *pACB)
{
struct MessageUnit_E __iomem *pmu = pACB->pmuE;
pACB->acb_flags |= ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_START_BGRB, &pmu->inbound_msgaddr0);
pACB->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
writel(pACB->out_doorbell, &pmu->iobound_doorbell);
if (!arcmsr_hbaE_wait_msgint_ready(pACB)) {
pr_notice("arcmsr%d: wait 'start adapter "
"background rebulid' timeout \n", pACB->host->host_no);
}
}
static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
@ -3539,6 +4021,9 @@ static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_D:
arcmsr_hbaD_start_bgrb(acb);
break;
case ACB_ADAPTER_TYPE_E:
arcmsr_hbaE_start_bgrb(acb);
break;
}
}
@ -3607,6 +4092,27 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
}
}
break;
case ACB_ADAPTER_TYPE_E: {
struct MessageUnit_E __iomem *reg = acb->pmuE;
uint32_t i, tmp;
acb->in_doorbell = readl(&reg->iobound_doorbell);
writel(0, &reg->host_int_status); /*clear interrupt*/
acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_READ_OK;
writel(acb->out_doorbell, &reg->iobound_doorbell);
for(i=0; i < 200; i++) {
msleep(20);
tmp = acb->in_doorbell;
acb->in_doorbell = readl(&reg->iobound_doorbell);
if((tmp ^ acb->in_doorbell) & ARCMSR_HBEMU_IOP2DRV_DATA_WRITE_OK) {
writel(0, &reg->host_int_status); /*clear interrupt*/
acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_DATA_READ_OK;
writel(acb->out_doorbell, &reg->iobound_doorbell);
} else
break;
}
}
break;
}
}
@ -3658,6 +4164,19 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
writel(0xD, &pmuC->write_sequence);
} while (((readl(&pmuC->host_diagnostic) & ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5));
writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic);
} else if (acb->dev_id == 0x1884) {
struct MessageUnit_E __iomem *pmuE = acb->pmuE;
do {
count++;
writel(0x4, &pmuE->write_sequence_3xxx);
writel(0xB, &pmuE->write_sequence_3xxx);
writel(0x2, &pmuE->write_sequence_3xxx);
writel(0x7, &pmuE->write_sequence_3xxx);
writel(0xD, &pmuE->write_sequence_3xxx);
mdelay(10);
} while (((readl(&pmuE->host_diagnostic_3xxx) &
ARCMSR_ARC1884_DiagWrite_ENABLE) == 0) && (count < 5));
writel(ARCMSR_ARC188X_RESET_ADAPTER, &pmuE->host_diagnostic_3xxx);
} else if ((acb->dev_id == 0x1214)) {
writel(0x20, pmuD->reset_request);
} else {
@ -3700,6 +4219,12 @@ static bool arcmsr_reset_in_progress(struct AdapterControlBlock *acb)
true : false;
}
break;
case ACB_ADAPTER_TYPE_E:{
struct MessageUnit_E __iomem *reg = acb->pmuE;
rtn = (readl(&reg->host_diagnostic_3xxx) &
ARCMSR_ARC188X_RESET_ADAPTER) ? true : false;
}
break;
}
return rtn;
}
@ -3890,6 +4415,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
case PCI_DEVICE_ID_ARECA_1680:
case PCI_DEVICE_ID_ARECA_1681:
case PCI_DEVICE_ID_ARECA_1880:
case PCI_DEVICE_ID_ARECA_1884:
type = "SAS/SATA";
break;
default: