Commit 5b37479a authored by Ching Huang's avatar Ching Huang Committed by Christoph Hellwig

arcmsr: add support new adapter ARC12x4 series

Add code to support the new Areca Raid ARC12x4 series adapters.
Signed-off-by: default avatarChing Huang <ching2048@areca.com.tw>
Reviewed-by: default avatarTomas Henzl <thenzl@redhat.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent aaa64f69
......@@ -63,12 +63,17 @@ struct device_attribute;
#define ARCMSR_MAX_QBUFFER 4096
#define ARCMSR_DEFAULT_SG_ENTRIES 38
#define ARCMSR_MAX_HBB_POSTQUEUE 264
#define ARCMSR_MAX_ARC1214_POSTQUEUE 256
#define ARCMSR_MAX_ARC1214_DONEQUEUE 257
#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */
#define ARCMSR_CDB_SG_PAGE_LENGTH 256
#define ARCMST_NUM_MSIX_VECTORS 4
#ifndef PCI_DEVICE_ID_ARECA_1880
#define PCI_DEVICE_ID_ARECA_1880 0x1880
#endif
#ifndef PCI_DEVICE_ID_ARECA_1214
#define PCI_DEVICE_ID_ARECA_1214 0x1214
#endif
/*
**********************************************************************************
**
......@@ -339,6 +344,56 @@ struct FIRMWARE_INFO
#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK 0x80000000
/*
*******************************************************************************
** SPEC. for Areca Type D adapter
*******************************************************************************
*/
#define ARCMSR_ARC1214_CHIP_ID 0x00004
#define ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION 0x00008
#define ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK 0x00034
#define ARCMSR_ARC1214_SAMPLE_RESET 0x00100
#define ARCMSR_ARC1214_RESET_REQUEST 0x00108
#define ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS 0x00200
#define ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE 0x0020C
#define ARCMSR_ARC1214_INBOUND_MESSAGE0 0x00400
#define ARCMSR_ARC1214_INBOUND_MESSAGE1 0x00404
#define ARCMSR_ARC1214_OUTBOUND_MESSAGE0 0x00420
#define ARCMSR_ARC1214_OUTBOUND_MESSAGE1 0x00424
#define ARCMSR_ARC1214_INBOUND_DOORBELL 0x00460
#define ARCMSR_ARC1214_OUTBOUND_DOORBELL 0x00480
#define ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE 0x00484
#define ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW 0x01000
#define ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH 0x01004
#define ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER 0x01018
#define ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW 0x01060
#define ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH 0x01064
#define ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER 0x0106C
#define ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER 0x01070
#define ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE 0x01088
#define ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE 0x0108C
#define ARCMSR_ARC1214_MESSAGE_WBUFFER 0x02000
#define ARCMSR_ARC1214_MESSAGE_RBUFFER 0x02100
#define ARCMSR_ARC1214_MESSAGE_RWBUFFER 0x02200
/* Host Interrupt Mask */
#define ARCMSR_ARC1214_ALL_INT_ENABLE 0x00001010
#define ARCMSR_ARC1214_ALL_INT_DISABLE 0x00000000
/* Host Interrupt Status */
#define ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR 0x00001000
#define ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR 0x00000010
/* DoorBell*/
#define ARCMSR_ARC1214_DRV2IOP_DATA_IN_READY 0x00000001
#define ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ 0x00000002
/*inbound message 0 ready*/
#define ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK 0x00000001
/*outbound DATA WRITE isr door bell clear*/
#define ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK 0x00000002
/*outbound message 0 ready*/
#define ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE 0x02000000
/*outbound message cmd isr door bell clear*/
/*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/
#define ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK 0x80000000
#define ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR 0x00000001
/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
*******************************************************************************
*/
......@@ -496,6 +551,56 @@ struct MessageUnit_C{
uint32_t msgcode_rwbuffer[256]; /*2200 23FF*/
};
/*
*********************************************************************
** Messaging Unit (MU) of Type D processor
*********************************************************************
*/
struct InBound_SRB {
uint32_t addressLow; /* pointer to SRB block */
uint32_t addressHigh;
uint32_t length; /* in DWORDs */
uint32_t reserved0;
};
struct OutBound_SRB {
uint32_t addressLow; /* pointer to SRB block */
uint32_t addressHigh;
};
struct MessageUnit_D {
struct InBound_SRB post_qbuffer[ARCMSR_MAX_ARC1214_POSTQUEUE];
volatile struct OutBound_SRB
done_qbuffer[ARCMSR_MAX_ARC1214_DONEQUEUE];
u16 postq_index;
volatile u16 doneq_index;
u32 __iomem *chip_id; /* 0x00004 */
u32 __iomem *cpu_mem_config; /* 0x00008 */
u32 __iomem *i2o_host_interrupt_mask; /* 0x00034 */
u32 __iomem *sample_at_reset; /* 0x00100 */
u32 __iomem *reset_request; /* 0x00108 */
u32 __iomem *host_int_status; /* 0x00200 */
u32 __iomem *pcief0_int_enable; /* 0x0020C */
u32 __iomem *inbound_msgaddr0; /* 0x00400 */
u32 __iomem *inbound_msgaddr1; /* 0x00404 */
u32 __iomem *outbound_msgaddr0; /* 0x00420 */
u32 __iomem *outbound_msgaddr1; /* 0x00424 */
u32 __iomem *inbound_doorbell; /* 0x00460 */
u32 __iomem *outbound_doorbell; /* 0x00480 */
u32 __iomem *outbound_doorbell_enable; /* 0x00484 */
u32 __iomem *inboundlist_base_low; /* 0x01000 */
u32 __iomem *inboundlist_base_high; /* 0x01004 */
u32 __iomem *inboundlist_write_pointer; /* 0x01018 */
u32 __iomem *outboundlist_base_low; /* 0x01060 */
u32 __iomem *outboundlist_base_high; /* 0x01064 */
u32 __iomem *outboundlist_copy_pointer; /* 0x0106C */
u32 __iomem *outboundlist_read_pointer; /* 0x01070 0x01072 */
u32 __iomem *outboundlist_interrupt_cause; /* 0x1088 */
u32 __iomem *outboundlist_interrupt_enable; /* 0x108C */
u32 __iomem *message_wbuffer; /* 0x2000 */
u32 __iomem *message_rbuffer; /* 0x2100 */
u32 __iomem *msgcode_rwbuffer; /* 0x2200 */
};
/*
*******************************************************************************
** Adapter Control Block
*******************************************************************************
......@@ -518,12 +623,15 @@ struct AdapterControlBlock
uint32_t reg_mu_acc_handle0;
spinlock_t eh_lock;
spinlock_t ccblist_lock;
spinlock_t postq_lock;
spinlock_t doneq_lock;
spinlock_t rqbuffer_lock;
spinlock_t wqbuffer_lock;
union {
struct MessageUnit_A __iomem *pmuA;
struct MessageUnit_B *pmuB;
struct MessageUnit_C __iomem *pmuC;
struct MessageUnit_D *pmuD;
};
/* message unit ATU inbound base address0 */
void __iomem *mem_base0;
......
......@@ -108,6 +108,7 @@ 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_hbaC_message_isr(struct AdapterControlBlock *pACB);
static void arcmsr_hbaD_message_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);
......@@ -161,6 +162,8 @@ static struct pci_device_id arcmsr_device_id_table[] = {
.driver_data = ACB_ADAPTER_TYPE_B},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210),
.driver_data = ACB_ADAPTER_TYPE_A},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1214),
.driver_data = ACB_ADAPTER_TYPE_D},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220),
.driver_data = ACB_ADAPTER_TYPE_A},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230),
......@@ -202,7 +205,8 @@ static struct pci_driver arcmsr_pci_driver = {
static void arcmsr_free_mu(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_B:{
case ACB_ADAPTER_TYPE_B:
case ACB_ADAPTER_TYPE_D: {
dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
acb->dma_coherent2, acb->dma_coherent_handle2);
break;
......@@ -251,6 +255,25 @@ static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb)
}
break;
}
case ACB_ADAPTER_TYPE_D: {
void __iomem *mem_base0;
unsigned long addr, range, flags;
addr = (unsigned long)pci_resource_start(pdev, 0);
range = pci_resource_len(pdev, 0);
flags = pci_resource_flags(pdev, 0);
if (flags & IORESOURCE_CACHEABLE)
mem_base0 = ioremap(addr, range);
else
mem_base0 = ioremap_nocache(addr, range);
if (!mem_base0) {
pr_notice("arcmsr%d: memory mapping region fail\n",
acb->host->host_no);
return false;
}
acb->mem_base0 = mem_base0;
break;
}
}
return true;
}
......@@ -271,6 +294,10 @@ static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_C:{
iounmap(acb->pmuC);
}
break;
case ACB_ADAPTER_TYPE_D:
iounmap(acb->mem_base0);
break;
}
}
......@@ -367,6 +394,23 @@ static uint8_t arcmsr_hbaC_wait_msgint_ready(struct AdapterControlBlock *pACB)
return false;
}
static bool arcmsr_hbaD_wait_msgint_ready(struct AdapterControlBlock *pACB)
{
struct MessageUnit_D *reg = pACB->pmuD;
int i;
for (i = 0; i < 2000; i++) {
if (readl(reg->outbound_doorbell)
& ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) {
writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE,
reg->outbound_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;
......@@ -416,6 +460,24 @@ static void arcmsr_hbaC_flush_cache(struct AdapterControlBlock *pACB)
} while (retry_count != 0);
return;
}
static void arcmsr_hbaD_flush_cache(struct AdapterControlBlock *pACB)
{
int retry_count = 15;
struct MessageUnit_D *reg = pACB->pmuD;
writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, reg->inbound_msgaddr0);
do {
if (arcmsr_hbaD_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) {
......@@ -432,6 +494,10 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_C: {
arcmsr_hbaC_flush_cache(acb);
}
break;
case ACB_ADAPTER_TYPE_D:
arcmsr_hbaD_flush_cache(acb);
break;
}
}
......@@ -475,9 +541,16 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle;
for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){
cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb);
ccb_tmp->cdb_phyaddr =
((acb->adapter_type == ACB_ADAPTER_TYPE_C) ?
cdb_phyaddr : (cdb_phyaddr >> 5));
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_A:
case ACB_ADAPTER_TYPE_B:
ccb_tmp->cdb_phyaddr = cdb_phyaddr >> 5;
break;
case ACB_ADAPTER_TYPE_C:
case ACB_ADAPTER_TYPE_D:
ccb_tmp->cdb_phyaddr = cdb_phyaddr;
break;
}
acb->pccb_pool[i] = ccb_tmp;
ccb_tmp->acb = acb;
INIT_LIST_HEAD(&ccb_tmp->list);
......@@ -521,6 +594,13 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work)
devicemap = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
break;
}
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *reg = acb->pmuD;
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)
......@@ -651,6 +731,8 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id)
}
spin_lock_init(&acb->eh_lock);
spin_lock_init(&acb->ccblist_lock);
spin_lock_init(&acb->postq_lock);
spin_lock_init(&acb->doneq_lock);
spin_lock_init(&acb->rqbuffer_lock);
spin_lock_init(&acb->wqbuffer_lock);
acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
......@@ -836,6 +918,20 @@ static uint8_t arcmsr_hbaC_abort_allcmd(struct AdapterControlBlock *pACB)
}
return true;
}
static uint8_t arcmsr_hbaD_abort_allcmd(struct AdapterControlBlock *pACB)
{
struct MessageUnit_D *reg = pACB->pmuD;
writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, reg->inbound_msgaddr0);
if (!arcmsr_hbaD_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;
......@@ -853,6 +949,11 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_C: {
rtnval = arcmsr_hbaC_abort_allcmd(acb);
}
break;
case ACB_ADAPTER_TYPE_D:
rtnval = arcmsr_hbaD_abort_allcmd(acb);
break;
}
return rtnval;
}
......@@ -919,6 +1020,12 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb)
writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, &reg->host_int_mask);
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *reg = acb->pmuD;
/* disable all outbound interrupt */
writel(ARCMSR_ARC1214_ALL_INT_DISABLE, reg->pcief0_int_enable);
}
break;
}
return orig_mask;
}
......@@ -1066,7 +1173,62 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb)
error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false;
arcmsr_drain_donequeue(acb, pCCB, error);
}
}
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *pmu = acb->pmuD;
uint32_t ccb_cdb_phy, outbound_write_pointer;
uint32_t doneq_index, index_stripped, addressLow, residual;
bool error;
struct CommandControlBlock *pCCB;
outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
residual = atomic_read(&acb->ccboutstandingcount);
for (i = 0; i < residual; i++) {
while ((doneq_index & 0xFFF) !=
(outbound_write_pointer & 0xFFF)) {
if (doneq_index & 0x4000) {
index_stripped = doneq_index & 0xFFF;
index_stripped += 1;
index_stripped %=
ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped ?
(index_stripped | 0x4000) :
(index_stripped + 1);
} else {
index_stripped = doneq_index;
index_stripped += 1;
index_stripped %=
ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped ?
index_stripped :
((index_stripped | 0x4000) + 1);
}
doneq_index = pmu->doneq_index;
addressLow = pmu->done_qbuffer[doneq_index &
0xFFF].addressLow;
ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
pARCMSR_CDB = (struct ARCMSR_CDB *)
(acb->vir2phy_offset + ccb_cdb_phy);
pCCB = container_of(pARCMSR_CDB,
struct CommandControlBlock, arcmsr_cdb);
error = (addressLow &
ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ?
true : false;
arcmsr_drain_donequeue(acb, pCCB, error);
writel(doneq_index,
pmu->outboundlist_read_pointer);
}
mdelay(10);
outbound_write_pointer =
pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
}
pmu->postq_index = 0;
pmu->doneq_index = 0x40FF;
}
break;
}
}
......@@ -1175,6 +1337,14 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb,
writel(intmask_org & mask, &reg->host_int_mask);
acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f;
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *reg = acb->pmuD;
mask = ARCMSR_ARC1214_ALL_INT_ENABLE;
writel(intmask_org | mask, reg->pcief0_int_enable);
break;
}
}
}
......@@ -1282,6 +1452,38 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr
writel(ccb_post_stamp, &phbcmu->inbound_queueport_low);
}
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *pmu = acb->pmuD;
u16 index_stripped;
u16 postq_index;
unsigned long flags;
struct InBound_SRB *pinbound_srb;
spin_lock_irqsave(&acb->postq_lock, flags);
postq_index = pmu->postq_index;
pinbound_srb = (struct InBound_SRB *)&(pmu->post_qbuffer[postq_index & 0xFF]);
pinbound_srb->addressHigh = dma_addr_hi32(cdb_phyaddr);
pinbound_srb->addressLow = dma_addr_lo32(cdb_phyaddr);
pinbound_srb->length = ccb->arc_cdb_size >> 2;
arcmsr_cdb->msgContext = dma_addr_lo32(cdb_phyaddr);
if (postq_index & 0x4000) {
index_stripped = postq_index & 0xFF;
index_stripped += 1;
index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
pmu->postq_index = index_stripped ?
(index_stripped | 0x4000) : index_stripped;
} else {
index_stripped = postq_index;
index_stripped += 1;
index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
pmu->postq_index = index_stripped ? index_stripped :
(index_stripped | 0x4000);
}
writel(postq_index, pmu->inboundlist_write_pointer);
spin_unlock_irqrestore(&acb->postq_lock, flags);
break;
}
}
}
......@@ -1323,6 +1525,18 @@ static void arcmsr_hbaC_stop_bgrb(struct AdapterControlBlock *pACB)
}
return;
}
static void arcmsr_hbaD_stop_bgrb(struct AdapterControlBlock *pACB)
{
struct MessageUnit_D *reg = pACB->pmuD;
pACB->acb_flags &= ~ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, reg->inbound_msgaddr0);
if (!arcmsr_hbaD_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) {
......@@ -1338,6 +1552,10 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_C: {
arcmsr_hbaC_stop_bgrb(acb);
}
break;
case ACB_ADAPTER_TYPE_D:
arcmsr_hbaD_stop_bgrb(acb);
break;
}
}
......@@ -1362,8 +1580,16 @@ static void arcmsr_iop_message_read(struct AdapterControlBlock *acb)
break;
case ACB_ADAPTER_TYPE_C: {
struct MessageUnit_C __iomem *reg = acb->pmuC;
writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, &reg->inbound_doorbell);
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *reg = acb->pmuD;
writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ,
reg->inbound_doorbell);
}
break;
}
}
......@@ -1398,6 +1624,12 @@ static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb)
writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, &reg->inbound_doorbell);
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *reg = acb->pmuD;
writel(ARCMSR_ARC1214_DRV2IOP_DATA_IN_READY,
reg->inbound_doorbell);
}
break;
}
}
......@@ -1421,6 +1653,12 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb)
struct MessageUnit_C __iomem *phbcmu = acb->pmuC;
qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer;
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *reg = acb->pmuD;
qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer;
}
break;
}
return qbuffer;
}
......@@ -1444,8 +1682,13 @@ static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBloc
case ACB_ADAPTER_TYPE_C: {
struct MessageUnit_C __iomem *reg = acb->pmuC;
pqbuffer = (struct QBUFFER __iomem *)&reg->message_wbuffer;
}
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *reg = acb->pmuD;
pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer;
}
break;
}
return pqbuffer;
}
......@@ -1500,7 +1743,7 @@ arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb,
uint8_t __iomem *iop_data;
uint32_t iop_len;
if (acb->adapter_type & ACB_ADAPTER_TYPE_C)
if (acb->adapter_type & (ACB_ADAPTER_TYPE_C | ACB_ADAPTER_TYPE_D))
return arcmsr_Read_iop_rqbuffer_in_DWORD(acb, prbuffer);
iop_data = (uint8_t __iomem *)prbuffer->data;
iop_len = readl(&prbuffer->data_len);
......@@ -1586,7 +1829,7 @@ arcmsr_write_ioctldata2iop(struct AdapterControlBlock *acb)
uint8_t __iomem *iop_data;
int32_t allxfer_len = 0;
if (acb->adapter_type & ACB_ADAPTER_TYPE_C) {
if (acb->adapter_type & (ACB_ADAPTER_TYPE_C | ACB_ADAPTER_TYPE_D)) {
arcmsr_write_ioctldata2iop_in_DWORD(acb);
return;
}
......@@ -1662,6 +1905,27 @@ static void arcmsr_hbaC_doorbell_isr(struct AdapterControlBlock *pACB)
| ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK
| ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE));
}
static void arcmsr_hbaD_doorbell_isr(struct AdapterControlBlock *pACB)
{
uint32_t outbound_doorbell;
struct MessageUnit_D *pmu = pACB->pmuD;
outbound_doorbell = readl(pmu->outbound_doorbell);
do {
writel(outbound_doorbell, pmu->outbound_doorbell);
if (outbound_doorbell & ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE)
arcmsr_hbaD_message_isr(pACB);
if (outbound_doorbell & ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK)
arcmsr_iop2drv_data_wrote_handle(pACB);
if (outbound_doorbell & ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK)
arcmsr_iop2drv_data_read_handle(pACB);
outbound_doorbell = readl(pmu->outbound_doorbell);
} while (outbound_doorbell & (ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK
| ARCMSR_ARC1214_IOP2DRV_DATA_READ_OK
| ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE));
}
static void arcmsr_hbaA_postqueue_isr(struct AdapterControlBlock *acb)
{
uint32_t flag_ccb;
......@@ -1728,6 +1992,59 @@ static void arcmsr_hbaC_postqueue_isr(struct AdapterControlBlock *acb)
}
}
}
static void arcmsr_hbaD_postqueue_isr(struct AdapterControlBlock *acb)
{
u32 outbound_write_pointer, doneq_index, index_stripped;
uint32_t addressLow, ccb_cdb_phy;
int error;
struct MessageUnit_D *pmu;
struct ARCMSR_CDB *arcmsr_cdb;
struct CommandControlBlock *ccb;
unsigned long flags;
spin_lock_irqsave(&acb->doneq_lock, flags);
pmu = acb->pmuD;
outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
if ((doneq_index & 0xFFF) != (outbound_write_pointer & 0xFFF)) {
do {
if (doneq_index & 0x4000) {
index_stripped = doneq_index & 0xFFF;
index_stripped += 1;
index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped
? (index_stripped | 0x4000) :
(index_stripped + 1);
} else {
index_stripped = doneq_index;
index_stripped += 1;
index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped
? index_stripped :
((index_stripped | 0x4000) + 1);
}
doneq_index = pmu->doneq_index;
addressLow = pmu->done_qbuffer[doneq_index &
0xFFF].addressLow;
ccb_cdb_phy = (addressLow & 0xFFFFFFF0);
arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset
+ ccb_cdb_phy);
ccb = container_of(arcmsr_cdb,
struct CommandControlBlock, arcmsr_cdb);
error = (addressLow & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1)
? true : false;
arcmsr_drain_donequeue(acb, ccb, error);
writel(doneq_index, pmu->outboundlist_read_pointer);
} while ((doneq_index & 0xFFF) !=
(outbound_write_pointer & 0xFFF));
}
writel(ARCMSR_ARC1214_OUTBOUND_LIST_INTERRUPT_CLEAR,
pmu->outboundlist_interrupt_cause);
readl(pmu->outboundlist_interrupt_cause);
spin_unlock_irqrestore(&acb->doneq_lock, flags);
}
/*
**********************************************************************************
** Handle a message interrupt
......@@ -1768,6 +2085,15 @@ static void arcmsr_hbaC_message_isr(struct AdapterControlBlock *acb)
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
static void arcmsr_hbaD_message_isr(struct AdapterControlBlock *acb)
{
struct MessageUnit_D *reg = acb->pmuD;
writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE, reg->outbound_doorbell);
readl(reg->outbound_doorbell);
schedule_work(&acb->arcmsr_do_message_isr_bh);
}
static int arcmsr_hbaA_handle_isr(struct AdapterControlBlock *acb)
{
uint32_t outbound_intstatus;
......@@ -1845,6 +2171,32 @@ static int arcmsr_hbaC_handle_isr(struct AdapterControlBlock *pACB)
ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR));
return IRQ_HANDLED;
}
static irqreturn_t arcmsr_hbaD_handle_isr(struct AdapterControlBlock *pACB)
{
u32 host_interrupt_status;
struct MessageUnit_D *pmu = pACB->pmuD;
host_interrupt_status = readl(pmu->host_int_status) &
(ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR |
ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR);
if (!host_interrupt_status)
return IRQ_NONE;
do {
/* MU post queue interrupts*/
if (host_interrupt_status &
ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR)
arcmsr_hbaD_postqueue_isr(pACB);
if (host_interrupt_status &
ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR)
arcmsr_hbaD_doorbell_isr(pACB);
host_interrupt_status = readl(pmu->host_int_status);
} while (host_interrupt_status &
(ARCMSR_ARC1214_OUTBOUND_POSTQUEUE_ISR |
ARCMSR_ARC1214_OUTBOUND_DOORBELL_ISR));
return IRQ_HANDLED;
}
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
{
switch (acb->adapter_type) {
......@@ -1856,6 +2208,8 @@ static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb)
break;
case ACB_ADAPTER_TYPE_C:
return arcmsr_hbaC_handle_isr(acb);
case ACB_ADAPTER_TYPE_D:
return arcmsr_hbaD_handle_isr(acb);
default:
return IRQ_NONE;
}
......@@ -2522,6 +2876,137 @@ static bool arcmsr_hbaC_get_config(struct AdapterControlBlock *pACB)
/*all interrupt service will be enable at arcmsr_iop_init*/
return true;
}
static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb)
{
char *acb_firm_model = acb->firm_model;
char *acb_firm_version = acb->firm_version;
char *acb_device_map = acb->device_map;
char __iomem *iop_firm_model;
char __iomem *iop_firm_version;
char __iomem *iop_device_map;
u32 count;
struct MessageUnit_D *reg ;
void *dma_coherent2;
dma_addr_t dma_coherent_handle2;
struct pci_dev *pdev = acb->pdev;
acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32);
dma_coherent2 = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize,
&dma_coherent_handle2, GFP_KERNEL);
if (!dma_coherent2) {
pr_notice("DMA allocation failed...\n");
return false;
}
memset(dma_coherent2, 0, acb->roundup_ccbsize);
acb->dma_coherent_handle2 = dma_coherent_handle2;
acb->dma_coherent2 = dma_coherent2;
reg = (struct MessageUnit_D *)dma_coherent2;
acb->pmuD = reg;
reg->chip_id = acb->mem_base0 + ARCMSR_ARC1214_CHIP_ID;
reg->cpu_mem_config = acb->mem_base0 +
ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION;
reg->i2o_host_interrupt_mask = acb->mem_base0 +
ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK;
reg->sample_at_reset = acb->mem_base0 + ARCMSR_ARC1214_SAMPLE_RESET;
reg->reset_request = acb->mem_base0 + ARCMSR_ARC1214_RESET_REQUEST;
reg->host_int_status = acb->mem_base0 +
ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS;
reg->pcief0_int_enable = acb->mem_base0 +
ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE;
reg->inbound_msgaddr0 = acb->mem_base0 +
ARCMSR_ARC1214_INBOUND_MESSAGE0;
reg->inbound_msgaddr1 = acb->mem_base0 +
ARCMSR_ARC1214_INBOUND_MESSAGE1;
reg->outbound_msgaddr0 = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_MESSAGE0;
reg->outbound_msgaddr1 = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_MESSAGE1;
reg->inbound_doorbell = acb->mem_base0 +
ARCMSR_ARC1214_INBOUND_DOORBELL;
reg->outbound_doorbell = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_DOORBELL;
reg->outbound_doorbell_enable = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE;
reg->inboundlist_base_low = acb->mem_base0 +
ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW;
reg->inboundlist_base_high = acb->mem_base0 +
ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH;
reg->inboundlist_write_pointer = acb->mem_base0 +
ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER;
reg->outboundlist_base_low = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW;
reg->outboundlist_base_high = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH;
reg->outboundlist_copy_pointer = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER;
reg->outboundlist_read_pointer = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER;
reg->outboundlist_interrupt_cause = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE;
reg->outboundlist_interrupt_enable = acb->mem_base0 +
ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE;
reg->message_wbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_WBUFFER;
reg->message_rbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_RBUFFER;
reg->msgcode_rwbuffer = acb->mem_base0 +
ARCMSR_ARC1214_MESSAGE_RWBUFFER;
iop_firm_model = (char __iomem *)(&reg->msgcode_rwbuffer[15]);
iop_firm_version = (char __iomem *)(&reg->msgcode_rwbuffer[17]);
iop_device_map = (char __iomem *)(&reg->msgcode_rwbuffer[21]);
if (readl(acb->pmuD->outbound_doorbell) &
ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE) {
writel(ARCMSR_ARC1214_IOP2DRV_MESSAGE_CMD_DONE,
acb->pmuD->outbound_doorbell);/*clear interrupt*/
}
/* post "get config" instruction */
writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, reg->inbound_msgaddr0);
/* wait message ready */
if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
pr_notice("arcmsr%d: wait get adapter firmware "
"miscellaneous data timeout\n", acb->host->host_no);
dma_free_coherent(&acb->pdev->dev, acb->roundup_ccbsize,
acb->dma_coherent2, acb->dma_coherent_handle2);
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--;
}
count = 16;
while (count) {
*acb_device_map = readb(iop_device_map);
acb_device_map++;
iop_device_map++;
count--;
}
acb->signature = readl(&reg->msgcode_rwbuffer[1]);
/*firm_signature,1,00-03*/
acb->firm_request_len = readl(&reg->msgcode_rwbuffer[2]);
/*firm_request_len,1,04-07*/
acb->firm_numbers_queue = readl(&reg->msgcode_rwbuffer[3]);
/*firm_numbers_queue,2,08-11*/
acb->firm_sdram_size = readl(&reg->msgcode_rwbuffer[4]);
/*firm_sdram_size,3,12-15*/
acb->firm_hd_channels = readl(&reg->msgcode_rwbuffer[5]);
/*firm_hd_channels,4,16-19*/
acb->firm_cfg_version = readl(&reg->msgcode_rwbuffer[25]);
pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
acb->host->host_no,
acb->firm_model,
acb->firm_version);
return true;
}
static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
{
bool rtn = false;
......@@ -2536,6 +3021,9 @@ static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb)
case ACB_ADAPTER_TYPE_C:
rtn = arcmsr_hbaC_get_config(acb);
break;
case ACB_ADAPTER_TYPE_D:
rtn = arcmsr_hbaD_get_config(acb);
break;
default:
break;
}
......@@ -2725,6 +3213,89 @@ static int arcmsr_hbaC_polling_ccbdone(struct AdapterControlBlock *acb,
}
return rtn;
}
static int arcmsr_hbaD_polling_ccbdone(struct AdapterControlBlock *acb,
struct CommandControlBlock *poll_ccb)
{
bool error;
uint32_t poll_ccb_done = 0, poll_count = 0, flag_ccb, ccb_cdb_phy;
int rtn, doneq_index, index_stripped, outbound_write_pointer;
unsigned long flags;
struct ARCMSR_CDB *arcmsr_cdb;
struct CommandControlBlock *pCCB;
struct MessageUnit_D *pmu = acb->pmuD;
polling_hbaD_ccb_retry:
poll_count++;
while (1) {
outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) {
if (poll_ccb_done) {
rtn = SUCCESS;
break;
} else {
msleep(25);
if (poll_count > 40) {
rtn = FAILED;
break;
}
goto polling_hbaD_ccb_retry;
}
}
spin_lock_irqsave(&acb->doneq_lock, flags);
if (doneq_index & 0x4000) {
index_stripped = doneq_index & 0xFFF;
index_stripped += 1;
index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped ?
(index_stripped | 0x4000) :
(index_stripped + 1);
} else {
index_stripped = doneq_index;
index_stripped += 1;
index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped ? index_stripped :
((index_stripped | 0x4000) + 1);
}
spin_unlock_irqrestore(&acb->doneq_lock, flags);
doneq_index = pmu->doneq_index;
flag_ccb = pmu->done_qbuffer[doneq_index & 0xFFF].addressLow;
ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);
arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset +
ccb_cdb_phy);
pCCB = container_of(arcmsr_cdb, struct CommandControlBlock,
arcmsr_cdb);
poll_ccb_done |= (pCCB == poll_ccb) ? 1 : 0;
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 = (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)
{
......@@ -2743,6 +3314,10 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb,
case ACB_ADAPTER_TYPE_C: {
rtn = arcmsr_hbaC_polling_ccbdone(acb, poll_ccb);
}
break;
case ACB_ADAPTER_TYPE_D:
rtn = arcmsr_hbaD_polling_ccbdone(acb, poll_ccb);
break;
}
return rtn;
}
......@@ -2760,6 +3335,7 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
*/
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_B:
case ACB_ADAPTER_TYPE_D:
dma_coherent_handle = acb->dma_coherent_handle2;
break;
default:
......@@ -2849,6 +3425,27 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb)
}
}
}
break;
case ACB_ADAPTER_TYPE_D: {
uint32_t __iomem *rwbuffer;
struct MessageUnit_D *reg = acb->pmuD;
reg->postq_index = 0;
reg->doneq_index = 0;
rwbuffer = reg->msgcode_rwbuffer;
writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);
writel(cdb_phyaddr_hi32, rwbuffer++);
writel(cdb_phyaddr, rwbuffer++);
writel(cdb_phyaddr + (ARCMSR_MAX_ARC1214_POSTQUEUE *
sizeof(struct InBound_SRB)), rwbuffer++);
writel(0x100, rwbuffer);
writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, reg->inbound_msgaddr0);
if (!arcmsr_hbaD_wait_msgint_ready(acb)) {
pr_notice("arcmsr%d: 'set command Q window' timeout\n",
acb->host->host_no);
return 1;
}
}
break;
}
return 0;
}
......@@ -2880,6 +3477,15 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb)
firmware_state = readl(&reg->outbound_msgaddr1);
} while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0);
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *reg = acb->pmuD;
do {
firmware_state = readl(reg->outbound_msgaddr1);
} while ((firmware_state &
ARCMSR_ARC1214_MESSAGE_FIRMWARE_OK) == 0);
}
break;
}
}
......@@ -2950,6 +3556,35 @@ static void arcmsr_hbaC_request_device_map(struct AdapterControlBlock *acb)
return;
}
static void arcmsr_hbaD_request_device_map(struct AdapterControlBlock *acb)
{
struct MessageUnit_D *reg = acb->pmuD;
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);
mod_timer(&acb->eternal_timer, jiffies +
msecs_to_jiffies(6 * HZ));
}
}
static void arcmsr_request_device_map(unsigned long pacb)
{
struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb;
......@@ -2965,6 +3600,10 @@ static void arcmsr_request_device_map(unsigned long pacb)
case ACB_ADAPTER_TYPE_C: {
arcmsr_hbaC_request_device_map(acb);
}
break;
case ACB_ADAPTER_TYPE_D:
arcmsr_hbaD_request_device_map(acb);
break;
}
}
......@@ -3002,6 +3641,19 @@ static void arcmsr_hbaC_start_bgrb(struct AdapterControlBlock *pACB)
}
return;
}
static void arcmsr_hbaD_start_bgrb(struct AdapterControlBlock *pACB)
{
struct MessageUnit_D *pmu = pACB->pmuD;
pACB->acb_flags |= ACB_F_MSG_START_BGRB;
writel(ARCMSR_INBOUND_MESG0_START_BGRB, pmu->inbound_msgaddr0);
if (!arcmsr_hbaD_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) {
......@@ -3013,6 +3665,10 @@ static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb)
break;
case ACB_ADAPTER_TYPE_C:
arcmsr_hbaC_start_bgrb(acb);
break;
case ACB_ADAPTER_TYPE_D:
arcmsr_hbaD_start_bgrb(acb);
break;
}
}
......@@ -3058,6 +3714,29 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb)
break;
}
}
break;
case ACB_ADAPTER_TYPE_D: {
struct MessageUnit_D *reg = acb->pmuD;
uint32_t outbound_doorbell, i;
/* empty doorbell Qbuffer if door bell ringed */
outbound_doorbell = readl(reg->outbound_doorbell);
writel(outbound_doorbell, reg->outbound_doorbell);
writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ,
reg->inbound_doorbell);
for (i = 0; i < 200; i++) {
msleep(20);
outbound_doorbell = readl(reg->outbound_doorbell);
if (outbound_doorbell &
ARCMSR_ARC1214_IOP2DRV_DATA_WRITE_OK) {
writel(outbound_doorbell,
reg->outbound_doorbell);
writel(ARCMSR_ARC1214_DRV2IOP_DATA_OUT_READ,
reg->inbound_doorbell);
} else
break;
}
}
break;
}
}
......@@ -3088,6 +3767,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb)
int i, count = 0;
struct MessageUnit_A __iomem *pmuA = acb->pmuA;
struct MessageUnit_C __iomem *pmuC = acb->pmuC;
struct MessageUnit_D *pmuD = acb->pmuD;
/* backup pci config data */
printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no);
......@@ -3108,6 +3788,8 @@ 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 == 0x1214)) {
writel(0x20, pmuD->reset_request);
} else {
pci_write_config_byte(acb->pdev, 0x84, 0x20);
}
......@@ -3304,6 +3986,66 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd)
}
break;
}
case ACB_ADAPTER_TYPE_D: {
if (acb->acb_flags & ACB_F_BUS_RESET) {
long timeout;
pr_notice("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_D *reg;
reg = acb->pmuD;
arcmsr_hardware_reset(acb);
acb->acb_flags &= ~ACB_F_IOP_INITED;
nap:
ssleep(ARCMSR_SLEEPTIME);
if ((readl(reg->sample_at_reset) & 0x80) != 0) {
pr_err("arcmsr%d: waiting for "
"hw bus reset return, retry=%d\n",
acb->host->host_no, retry_count);
if (retry_count > ARCMSR_RETRYCOUNT) {
acb->fw_flag = FW_DEADLOCK;
pr_err("arcmsr%d: waiting for hw bus"
" reset return, "
"RETRY TERMINATED!!\n",
acb->host->host_no);
return FAILED;
}
retry_count++;
goto nap;
}
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);
arcmsr_clear_doorbell_queue_buffer(acb);
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;
mod_timer(&acb->eternal_timer,
jiffies + msecs_to_jiffies(6 * HZ));
acb->acb_flags &= ~ACB_F_BUS_RESET;
rtn = SUCCESS;
pr_err("arcmsr: scsi bus reset "
"eh returns with success\n");
} else {
acb->acb_flags &= ~ACB_F_BUS_RESET;
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;
}
......@@ -3380,6 +4122,7 @@ static const char *arcmsr_info(struct Scsi_Host *host)
case PCI_DEVICE_ID_ARECA_1280:
type = "SATA";
break;
case PCI_DEVICE_ID_ARECA_1214:
case PCI_DEVICE_ID_ARECA_1380:
case PCI_DEVICE_ID_ARECA_1381:
case PCI_DEVICE_ID_ARECA_1680:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment