Discussion:
[PATCH v3 16/17] arcmsr: support new adapter ARC12x4 series
Ching Huang
2014-08-19 07:25:22 UTC
Permalink
From: Ching Huang <***@areca.com.tw>

Add code for supporting Areca new Raid adapter ARC12x4 series.

Signed-off-by: Ching Huang <***@areca.com.tw>
---

diff -uprN a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
--- a/drivers/scsi/arcmsr/arcmsr.h 2014-05-06 15:29:54.000000000 +0800
+++ b/drivers/scsi/arcmsr/arcmsr.h 2014-05-06 15:06:04.000000000 +0800
@@ -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,55 @@ 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 +622,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;
diff -uprN a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
--- a/drivers/scsi/arcmsr/arcmsr_hba.c 2014-08-14 18:41:12.000000000 +0800
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c 2014-08-14 18:38:46.000000000 +0800
@@ -108,6 +108,7 @@ static void arcmsr_message_isr_bh_fn(str
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);
@@ -151,6 +152,7 @@ static struct pci_device_id arcmsr_devic
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201), .driver_data = ACB_ADAPTER_TYPE_B,},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202), .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), .driver_data = ACB_ADAPTER_TYPE_A,},
{PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260), .driver_data = ACB_ADAPTER_TYPE_A,},
@@ -181,7 +183,8 @@ static struct pci_driver arcmsr_pci_driv
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;
@@ -230,6 +233,25 @@ static bool arcmsr_remap_pciregion(struc
}
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;
}
@@ -250,6 +272,10 @@ static void arcmsr_unmap_pciregion(struc
case ACB_ADAPTER_TYPE_C:{
iounmap(acb->pmuC);
}
+ break;
+ case ACB_ADAPTER_TYPE_D:
+ iounmap(acb->mem_base0);
+ break;
}
}

@@ -346,6 +372,23 @@ static uint8_t arcmsr_hbaC_wait_msgint_r
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;
@@ -395,6 +438,25 @@ static void arcmsr_hbaC_flush_cache(stru
} 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;
+ else {
+ 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) {
@@ -411,6 +473,10 @@ static void arcmsr_flush_adapter_cache(s
case ACB_ADAPTER_TYPE_C: {
arcmsr_hbaC_flush_cache(acb);
}
+ break;
+ case ACB_ADAPTER_TYPE_D:
+ arcmsr_hbaD_flush_cache(acb);
+ break;
}
}

@@ -454,7 +520,16 @@ static int arcmsr_alloc_ccb_pool(struct
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);
@@ -495,6 +570,12 @@ static void arcmsr_message_isr_bh_fn(str
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)
@@ -625,6 +706,8 @@ static int arcmsr_probe(struct pci_dev *
}
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 |
@@ -809,6 +892,20 @@ static uint8_t arcmsr_hbaC_abort_allcmd(
}
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;
@@ -826,6 +923,11 @@ static uint8_t arcmsr_abort_allcmd(struc
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;
}
@@ -892,6 +994,12 @@ static u32 arcmsr_disable_outbound_ints(
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;
}
@@ -1039,7 +1147,60 @@ static void arcmsr_done4abort_postqueue(
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;
}
}

@@ -1148,6 +1309,13 @@ static void arcmsr_enable_outbound_ints(
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;
+ }
}
}

@@ -1256,6 +1424,38 @@ static void arcmsr_post_ccb(struct Adapt
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;
+ }
}
}

@@ -1297,6 +1497,18 @@ static void arcmsr_hbaC_stop_bgrb(struct
}
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) {
@@ -1312,6 +1524,10 @@ static void arcmsr_stop_adapter_bgrb(str
case ACB_ADAPTER_TYPE_C: {
arcmsr_hbaC_stop_bgrb(acb);
}
+ break;
+ case ACB_ADAPTER_TYPE_D:
+ arcmsr_hbaD_stop_bgrb(acb);
+ break;
}
}

@@ -1338,6 +1554,13 @@ static void arcmsr_iop_message_read(stru
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;
}
}

@@ -1372,6 +1595,12 @@ static void arcmsr_iop_message_wrote(str
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;
}
}

@@ -1395,6 +1624,12 @@ struct QBUFFER __iomem *arcmsr_get_iop_r
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;
}
@@ -1418,8 +1653,13 @@ static struct QBUFFER __iomem *arcmsr_ge
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;
}
@@ -1473,7 +1713,7 @@ arcmsr_Read_iop_rqbuffer_data(struct Ada
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);
@@ -1559,7 +1799,7 @@ arcmsr_write_ioctldata2iop(struct Adapte
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;
}
@@ -1635,6 +1875,27 @@ static void arcmsr_hbaC_doorbell_isr(str
| 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;
@@ -1700,6 +1961,59 @@ static void arcmsr_hbaC_postqueue_isr(st
}
}
}
+
+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
@@ -1740,6 +2054,15 @@ static void arcmsr_hbaC_message_isr(stru
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;
@@ -1817,6 +2140,32 @@ static int arcmsr_hbaC_handle_isr(struct
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) {
@@ -1829,6 +2178,9 @@ static irqreturn_t arcmsr_interrupt(stru
case ACB_ADAPTER_TYPE_C:
return arcmsr_hbaC_handle_isr(acb);
break;
+ case ACB_ADAPTER_TYPE_D:
+ return arcmsr_hbaD_handle_isr(acb);
+ break;
default:
return IRQ_NONE;
}
@@ -2491,6 +2843,137 @@ static bool arcmsr_hbaC_get_config(struc
/*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;
@@ -2505,6 +2988,9 @@ static bool arcmsr_get_firmware_spec(str
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;
}
@@ -2693,6 +3179,89 @@ polling_hbc_ccb_retry:
}
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)
{
@@ -2711,6 +3280,10 @@ static int arcmsr_polling_ccbdone(struct
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;
}
@@ -2728,6 +3301,7 @@ static int arcmsr_iop_confirm(struct Ada
*/
switch (acb->adapter_type) {
case ACB_ADAPTER_TYPE_B:
+ case ACB_ADAPTER_TYPE_D:
dma_coherent_handle = acb->dma_coherent_handle2;
break;
default:
@@ -2817,6 +3391,27 @@ static int arcmsr_iop_confirm(struct Ada
}
}
}
+ 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;
}
@@ -2848,6 +3443,15 @@ static void arcmsr_wait_firmware_ready(s
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;
}
}

@@ -2918,6 +3522,35 @@ static void arcmsr_hbaC_request_device_m
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;
@@ -2933,6 +3566,10 @@ static void arcmsr_request_device_map(un
case ACB_ADAPTER_TYPE_C: {
arcmsr_hbaC_request_device_map(acb);
}
+ break;
+ case ACB_ADAPTER_TYPE_D:
+ arcmsr_hbaD_request_device_map(acb);
+ break;
}
}

@@ -2970,6 +3607,19 @@ static void arcmsr_hbaC_start_bgrb(struc
}
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) {
@@ -2981,6 +3631,10 @@ static void arcmsr_start_adapter_bgrb(st
break;
case ACB_ADAPTER_TYPE_C:
arcmsr_hbaC_start_bgrb(acb);
+ break;
+ case ACB_ADAPTER_TYPE_D:
+ arcmsr_hbaD_start_bgrb(acb);
+ break;
}
}

@@ -3026,6 +3680,29 @@ static void arcmsr_clear_doorbell_queue_
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;
}
}

@@ -3056,6 +3733,7 @@ static void arcmsr_hardware_reset(struct
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);
@@ -3076,6 +3754,8 @@ static void arcmsr_hardware_reset(struct
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);
}
@@ -3272,6 +3952,66 @@ sleep:
}
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;
}
@@ -3348,6 +4088,7 @@ static const char *arcmsr_info(struct Sc
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:


--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Tomas Henzl
2014-08-27 14:00:48 UTC
Permalink
Post by Ching Huang
Add code for supporting Areca new Raid adapter ARC12x4 series.
---
Hi Ching,
please look at the comments below -
Post by Ching Huang
}
@@ -1039,7 +1147,60 @@ static void arcmsr_done4abort_postqueue(
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;
I have noticed this^ in this driver already before. Sometimes it makes sense
when a variable is declared in a 'case' block but often it is just
a waste of space. In this function this is the third 'bool error' declared.
Is there a reason for this style (this function is not the worst case) ?
Post by Ching Huang
+ 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 + 1);
+ } else {
+ index_stripped = doneq_index;
+ index_stripped += 1;
+ index_stripped %=
+ ARCMSR_MAX_ARC1214_DONEQUEUE;
+ pmu->doneq_index = 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;
}
}
...
Post by Ching Huang
@@ -1256,6 +1424,38 @@ static void arcmsr_post_ccb(struct Adapt
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;
+ (index_stripped | 0x4000);
+ }
The code above could be a bit easier -

arcmsr_cdb->msgContext = dma_addr_lo32(cdb_phyaddr);
index_stripped = postq_index + 1;
index_stripped &= (ARCMSR_MAX_ARC1214_POSTQUEUE - 1);

if (postq_index & 0x4000)
pmu->postq_index = index_stripped ?
(index_stripped | 0x4000) : index_stripped;
else
pmu->postq_index = index_stripped ?
index_stripped : (index_stripped | 0x4000);
or am I wrong? This is repeated in the code many times
Post by Ching Huang
+ writel(postq_index, pmu->inboundlist_write_pointer);
+ spin_unlock_irqrestore(&acb->postq_lock, flags);
+ break;
+ }
}
}
...
Post by Ching Huang
+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;
+
+ poll_count++;
+ while (1) {
+ outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
+ doneq_index = pmu->doneq_index;
You seem to protect the doneq with a spinlock on some other places, arcmsr_hbaD_postqueue_isr
and below in this function. Why not here, is it intentional?
Post by Ching Huang
+ 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 + 1);
+ } else {
+ index_stripped = doneq_index;
+ index_stripped += 1;
+ index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+ ((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)
{
@@ -2711,6 +3280,10 @@ static int arcmsr_polling_ccbdone(struct
case ACB_ADAPTER_TYPE_C: {
rtn = arcmsr_hbaC_polling_ccbdone(acb, poll_ccb);
}
+ break;
+ rtn = arcmsr_hbaD_polling_ccbdone(acb, poll_ccb);
+ break;
}
return rtn;
}
@@ -2728,6 +3301,7 @@ static int arcmsr_iop_confirm(struct Ada
*/
switch (acb->adapter_type) {
dma_coherent_handle = acb->dma_coherent_handle2;
break;
@@ -2817,6 +3391,27 @@ static int arcmsr_iop_confirm(struct Ada
}
}
}
+ 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;
}
@@ -2848,6 +3443,15 @@ static void arcmsr_wait_firmware_ready(s
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;
}
}
@@ -2918,6 +3522,35 @@ static void arcmsr_hbaC_request_device_m
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;
@@ -2933,6 +3566,10 @@ static void arcmsr_request_device_map(un
case ACB_ADAPTER_TYPE_C: {
arcmsr_hbaC_request_device_map(acb);
}
+ break;
+ arcmsr_hbaD_request_device_map(acb);
+ break;
}
}
@@ -2970,6 +3607,19 @@ static void arcmsr_hbaC_start_bgrb(struc
}
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) {
@@ -2981,6 +3631,10 @@ static void arcmsr_start_adapter_bgrb(st
break;
arcmsr_hbaC_start_bgrb(acb);
+ break;
+ arcmsr_hbaD_start_bgrb(acb);
+ break;
}
}
@@ -3026,6 +3680,29 @@ static void arcmsr_clear_doorbell_queue_
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;
}
}
@@ -3056,6 +3733,7 @@ static void arcmsr_hardware_reset(struct
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);
@@ -3076,6 +3754,8 @@ static void arcmsr_hardware_reset(struct
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);
}
}
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;
+ 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;
}
@@ -3348,6 +4088,7 @@ static const char *arcmsr_info(struct Sc
type = "SATA";
break;
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
Ching Huang
2014-08-28 15:46:49 UTC
Permalink
Post by Tomas Henzl
Post by Ching Huang
Add code for supporting Areca new Raid adapter ARC12x4 series.
---
Hi Ching,
please look at the comments below -
Post by Ching Huang
}
@@ -1039,7 +1147,60 @@ static void arcmsr_done4abort_postqueue(
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;
I have noticed this^ in this driver already before. Sometimes it makes sense
when a variable is declared in a 'case' block but often it is just
a waste of space. In this function this is the third 'bool error' declared.
Is there a reason for this style (this function is not the worst case) ?
Yea, there is many variable are duplicate declaration, I will clean it up.
Post by Tomas Henzl
Post by Ching Huang
+ 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 + 1);
+ } else {
+ index_stripped = doneq_index;
+ index_stripped += 1;
+ index_stripped %=
+ ARCMSR_MAX_ARC1214_DONEQUEUE;
+ pmu->doneq_index = 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;
}
}
...
Post by Ching Huang
@@ -1256,6 +1424,38 @@ static void arcmsr_post_ccb(struct Adapt
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;
u16 postq_index, toggle;
Post by Tomas Henzl
Post by Ching Huang
+ 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;
+ (index_stripped | 0x4000);
+ }
The code above could be a bit easier -
Yea. I simplify it to following.
toggle = postq_index & 0x4000;
index_stripped = (postq_index & 0xFF) + 1;
index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
pmu->postq_index = index_stripped ? (index_stripped | toggle) :
(index_stripped | (toggle ^ 0x4000));
Post by Tomas Henzl
arcmsr_cdb->msgContext = dma_addr_lo32(cdb_phyaddr);
index_stripped = postq_index + 1;
index_stripped &= (ARCMSR_MAX_ARC1214_POSTQUEUE - 1);
if (postq_index & 0x4000)
pmu->postq_index = index_stripped ?
(index_stripped | 0x4000) : index_stripped;
else
pmu->postq_index = index_stripped ?
index_stripped : (index_stripped | 0x4000);
or am I wrong? This is repeated in the code many times
Yea. one for postQueue and 3 times for doneQueue. They all can be simplified as above.
Post by Tomas Henzl
Post by Ching Huang
+ writel(postq_index, pmu->inboundlist_write_pointer);
+ spin_unlock_irqrestore(&acb->postq_lock, flags);
+ break;
+ }
}
}
...
Post by Ching Huang
+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;
+
+ poll_count++;
+ while (1) {
+ outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
+ doneq_index = pmu->doneq_index;
You seem to protect the doneq with a spinlock on some other places, arcmsr_hbaD_postqueue_isr
and below in this function. Why not here, is it intentional?
Before came here, the h/w interrupt was disabled. Hence, don't worry about other thread
to change doneq_index.
Post by Tomas Henzl
Post by Ching Huang
+ 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 + 1);
+ } else {
+ index_stripped = doneq_index;
+ index_stripped += 1;
+ index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+ ((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)
{
@@ -2711,6 +3280,10 @@ static int arcmsr_polling_ccbdone(struct
case ACB_ADAPTER_TYPE_C: {
rtn = arcmsr_hbaC_polling_ccbdone(acb, poll_ccb);
}
+ break;
+ rtn = arcmsr_hbaD_polling_ccbdone(acb, poll_ccb);
+ break;
}
return rtn;
}
@@ -2728,6 +3301,7 @@ static int arcmsr_iop_confirm(struct Ada
*/
switch (acb->adapter_type) {
dma_coherent_handle = acb->dma_coherent_handle2;
break;
@@ -2817,6 +3391,27 @@ static int arcmsr_iop_confirm(struct Ada
}
}
}
+ 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;
}
@@ -2848,6 +3443,15 @@ static void arcmsr_wait_firmware_ready(s
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;
}
}
@@ -2918,6 +3522,35 @@ static void arcmsr_hbaC_request_device_m
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;
@@ -2933,6 +3566,10 @@ static void arcmsr_request_device_map(un
case ACB_ADAPTER_TYPE_C: {
arcmsr_hbaC_request_device_map(acb);
}
+ break;
+ arcmsr_hbaD_request_device_map(acb);
+ break;
}
}
@@ -2970,6 +3607,19 @@ static void arcmsr_hbaC_start_bgrb(struc
}
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) {
@@ -2981,6 +3631,10 @@ static void arcmsr_start_adapter_bgrb(st
break;
arcmsr_hbaC_start_bgrb(acb);
+ break;
+ arcmsr_hbaD_start_bgrb(acb);
+ break;
}
}
@@ -3026,6 +3680,29 @@ static void arcmsr_clear_doorbell_queue_
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;
}
}
@@ -3056,6 +3733,7 @@ static void arcmsr_hardware_reset(struct
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);
@@ -3076,6 +3754,8 @@ static void arcmsr_hardware_reset(struct
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);
}
}
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;
+ 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;
}
@@ -3348,6 +4088,7 @@ static const char *arcmsr_info(struct Sc
type = "SATA";
break;
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
Tomas Henzl
2014-08-28 12:49:08 UTC
Permalink
Post by Ching Huang
Post by Tomas Henzl
Post by Ching Huang
Add code for supporting Areca new Raid adapter ARC12x4 series.
---
Hi Ching,
please look at the comments below -
Post by Ching Huang
}
@@ -1039,7 +1147,60 @@ static void arcmsr_done4abort_postqueue(
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;
I have noticed this^ in this driver already before. Sometimes it makes sense
when a variable is declared in a 'case' block but often it is just
a waste of space. In this function this is the third 'bool error' declared.
Is there a reason for this style (this function is not the worst case) ?
Yea, there is many variable are duplicate declaration, I will clean it up.
Post by Tomas Henzl
Post by Ching Huang
+ 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 + 1);
+ } else {
+ index_stripped = doneq_index;
+ index_stripped += 1;
+ index_stripped %=
+ ARCMSR_MAX_ARC1214_DONEQUEUE;
+ pmu->doneq_index = 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;
}
}
...
Post by Ching Huang
@@ -1256,6 +1424,38 @@ static void arcmsr_post_ccb(struct Adapt
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;
u16 postq_index, toggle;
Post by Tomas Henzl
Post by Ching Huang
+ 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;
+ (index_stripped | 0x4000);
+ }
The code above could be a bit easier -
Yea. I simplify it to following.
toggle = postq_index & 0x4000;
index_stripped = (postq_index & 0xFF) + 1;
the first '&' is not needed, because we use a modulo in a next step
Post by Ching Huang
index_stripped %= ARCMSR_MAX_ARC1214_POSTQUEUE;
and module is for certain binary numbers equivalent to '&', so this
could be changed into
index_stripped = postq_index + 1;
index_stripped &= (ARCMSR_MAX_ARC1214_POSTQUEUE - 1);
( ARCMSR_MAX_ARC1214_POSTQUEUE is equal 0x100)

and this
Post by Ching Huang
(index_stripped | (toggle ^ 0x4000));
into
pmu->postq_index = index_stripped ? (index_stripped | toggle) :
(toggle ^ 0x4000);

Let us stop this discussion, it's not a bug, you may or may not include it in your next series,
we can discuss it there.
For another question, please look below.
Post by Ching Huang
Post by Tomas Henzl
arcmsr_cdb->msgContext = dma_addr_lo32(cdb_phyaddr);
index_stripped = postq_index + 1;
index_stripped &= (ARCMSR_MAX_ARC1214_POSTQUEUE - 1);
if (postq_index & 0x4000)
pmu->postq_index = index_stripped ?
(index_stripped | 0x4000) : index_stripped;
else
pmu->postq_index = index_stripped ?
index_stripped : (index_stripped | 0x4000);
or am I wrong? This is repeated in the code many times
Yea. one for postQueue and 3 times for doneQueue. They all can be simplified as above.
Post by Tomas Henzl
Post by Ching Huang
+ writel(postq_index, pmu->inboundlist_write_pointer);
+ spin_unlock_irqrestore(&acb->postq_lock, flags);
+ break;
+ }
}
}
...
Post by Ching Huang
+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;
+
+ poll_count++;
+ while (1) {
+ outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
+ doneq_index = pmu->doneq_index;
You seem to protect the doneq with a spinlock on some other places, arcmsr_hbaD_postqueue_isr
and below in this function. Why not here, is it intentional?
Before came here, the h/w interrupt was disabled. Hence, don't worry about other thread
to change doneq_index.
I guess you mean the hw interrupts from your card. If so and if you know that no other thread on another
processor can access the doneq_index - why do you use the spinlock just few lines below?
Post by Ching Huang
Post by Tomas Henzl
Post by Ching Huang
+ 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 + 1);
+ } else {
+ index_stripped = doneq_index;
+ index_stripped += 1;
+ index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
+ ((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)
{
@@ -2711,6 +3280,10 @@ static int arcmsr_polling_ccbdone(struct
case ACB_ADAPTER_TYPE_C: {
rtn = arcmsr_hbaC_polling_ccbdone(acb, poll_ccb);
}
+ break;
+ rtn = arcmsr_hbaD_polling_ccbdone(acb, poll_ccb);
+ break;
}
return rtn;
}
@@ -2728,6 +3301,7 @@ static int arcmsr_iop_confirm(struct Ada
*/
switch (acb->adapter_type) {
dma_coherent_handle = acb->dma_coherent_handle2;
break;
@@ -2817,6 +3391,27 @@ static int arcmsr_iop_confirm(struct Ada
}
}
}
+ 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;
}
@@ -2848,6 +3443,15 @@ static void arcmsr_wait_firmware_ready(s
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;
}
}
@@ -2918,6 +3522,35 @@ static void arcmsr_hbaC_request_device_m
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;
@@ -2933,6 +3566,10 @@ static void arcmsr_request_device_map(un
case ACB_ADAPTER_TYPE_C: {
arcmsr_hbaC_request_device_map(acb);
}
+ break;
+ arcmsr_hbaD_request_device_map(acb);
+ break;
}
}
@@ -2970,6 +3607,19 @@ static void arcmsr_hbaC_start_bgrb(struc
}
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) {
@@ -2981,6 +3631,10 @@ static void arcmsr_start_adapter_bgrb(st
break;
arcmsr_hbaC_start_bgrb(acb);
+ break;
+ arcmsr_hbaD_start_bgrb(acb);
+ break;
}
}
@@ -3026,6 +3680,29 @@ static void arcmsr_clear_doorbell_queue_
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;
}
}
@@ -3056,6 +3733,7 @@ static void arcmsr_hardware_reset(struct
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);
@@ -3076,6 +3754,8 @@ static void arcmsr_hardware_reset(struct
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);
}
}
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;
+ 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;
}
@@ -3348,6 +4088,7 @@ static const char *arcmsr_info(struct Sc
type = "SATA";
break;
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
Christoph Hellwig
2014-09-09 16:30:57 UTC
Permalink
Ching,

do you have a chance to address Thomas second concern below? As
far as I can tell (Thomas, please correct me) that's the last
outstanding concern, and I'd really like to merge the arcmsr updates
for the Linux 3.18 merge window.
Tomas Henzl
2014-09-10 09:58:35 UTC
Permalink
Post by Tomas Henzl
Ching,
do you have a chance to address Thomas second concern below? As
far as I can tell (Thomas, please correct me) that's the last
outstanding concern, and I'd really like to merge the arcmsr updates
for the Linux 3.18 merge window.
Correct, still awaiting a response.
Post by Tomas Henzl
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Ching Huang
2014-09-11 03:59:10 UTC
Permalink
Post by Tomas Henzl
Post by Tomas Henzl
Ching,
do you have a chance to address Thomas second concern below? As
far as I can tell (Thomas, please correct me) that's the last
outstanding concern, and I'd really like to merge the arcmsr updates
for the Linux 3.18 merge window.
Correct, still awaiting a response.
Christoph, Tomas,

Sorry for the late reply.

I think I misunderstand Tomas' meaning.
The spin lock in arcmsr_hbaD_polling_ccbdone() is necessary to protect doneq_index and have to be modified as following.

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, toggle;
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) {
spin_lock_irqsave(&acb->doneq_lock, flags);
outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) {
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_hbaD_ccb_retry;
}
}
toggle = doneq_index & 0x4000;
index_stripped = (doneq_index & 0xFFF) + 1;
index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
pmu->doneq_index = index_stripped ? (index_stripped | toggle) :
((index_stripped + 1) | (toggle ^ 0x4000));
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;
}
Post by Tomas Henzl
Post by Tomas Henzl
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
Tomas Henzl
2014-09-11 14:21:39 UTC
Permalink
Post by Ching Huang
Post by Tomas Henzl
Post by Tomas Henzl
Ching,
do you have a chance to address Thomas second concern below? As
far as I can tell (Thomas, please correct me) that's the last
outstanding concern, and I'd really like to merge the arcmsr updates
for the Linux 3.18 merge window.
Correct, still awaiting a response.
Christoph, Tomas,
Sorry for the late reply.
I think I misunderstand Tomas' meaning.
The spin lock in arcmsr_hbaD_polling_ccbdone() is necessary to protect doneq_index and have to be modified as following.
OK, so you are going to repost 16/17 ? If so, please describe all changes you'll do, in that new post.
Post by Ching Huang
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, toggle;
unsigned long flags;
struct ARCMSR_CDB *arcmsr_cdb;
struct CommandControlBlock *pCCB;
struct MessageUnit_D *pmu = acb->pmuD;
poll_count++;
while (1) {
spin_lock_irqsave(&acb->doneq_lock, flags);
outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) {
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_hbaD_ccb_retry;
}
}
toggle = doneq_index & 0x4000;
index_stripped = (doneq_index & 0xFFF) + 1;
index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
((index_stripped + 1) | (toggle ^ 0x4000));
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;
}
Post by Tomas Henzl
Post by Tomas Henzl
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Ching Huang
2014-09-12 03:31:00 UTC
Permalink
Post by Tomas Henzl
Post by Ching Huang
Post by Tomas Henzl
Post by Tomas Henzl
Ching,
do you have a chance to address Thomas second concern below? As
far as I can tell (Thomas, please correct me) that's the last
outstanding concern, and I'd really like to merge the arcmsr updates
for the Linux 3.18 merge window.
Correct, still awaiting a response.
Christoph, Tomas,
Sorry for the late reply.
I think I misunderstand Tomas' meaning.
The spin lock in arcmsr_hbaD_polling_ccbdone() is necessary to protect doneq_index and have to be modified as following.
OK, so you are going to repost 16/17 ? If so, please describe all changes you'll do, in that new post.
By previous review, I will post two patches.
One for 13/17 and another for 16/17.
These patches are relative to http://git.infradead.org/users/hch/scsi-queue.git/tree/arcmsr-for-3.18:/drivers/scsi/arcmsr
Post by Tomas Henzl
Post by Ching Huang
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, toggle;
unsigned long flags;
struct ARCMSR_CDB *arcmsr_cdb;
struct CommandControlBlock *pCCB;
struct MessageUnit_D *pmu = acb->pmuD;
poll_count++;
while (1) {
spin_lock_irqsave(&acb->doneq_lock, flags);
outbound_write_pointer = pmu->done_qbuffer[0].addressLow + 1;
doneq_index = pmu->doneq_index;
if ((outbound_write_pointer & 0xFFF) == (doneq_index & 0xFFF)) {
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_hbaD_ccb_retry;
}
}
toggle = doneq_index & 0x4000;
index_stripped = (doneq_index & 0xFFF) + 1;
index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE;
((index_stripped + 1) | (toggle ^ 0x4000));
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;
}
Post by Tomas Henzl
Post by Tomas Henzl
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Tomas Henzl
2014-09-15 13:23:36 UTC
Permalink
Post by Tomas Henzl
Post by Tomas Henzl
Ching,
do you have a chance to address Thomas second concern below? As
far as I can tell (Thomas, please correct me) that's the last
outstanding concern, and I'd really like to merge the arcmsr updates
for the Linux 3.18 merge window.
Correct, still awaiting a response.
Christoph,

you may add my 'reviewed-by' to the arcmsr series
http://git.infradead.org/users/hch/scsi-queue.git/tree/arcmsr-for-3.18:/drivers/scsi/arcmsr
with the '[PATCH v5 2/2] arcmsr: simplify of updating doneq_index and postq_index'
( https://lkml.org/lkml/2014/9/15/177 ) on top of the series
that last patch fixes the 16/17 from your git.
I hope the series is an iteration in the right direction.
Skip the the '[PATCH v4 1/2] arcmsr: simplify ioctl data read/write', Ching will repost it later.

Tomas
Post by Tomas Henzl
Post by Tomas Henzl
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to ***@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Christoph Hellwig
2014-09-15 17:05:19 UTC
Permalink
Post by Ching Huang
Christoph,
you may add my 'reviewed-by' to the arcmsr series
http://git.infradead.org/users/hch/scsi-queue.git/tree/arcmsr-for-3.18:/drivers/scsi/arcmsr
with the '[PATCH v5 2/2] arcmsr: simplify of updating doneq_index and postq_index'
( https://lkml.org/lkml/2014/9/15/177 ) on top of the series
that last patch fixes the 16/17 from your git.
I hope the series is an iteration in the right direction.
Skip the the '[PATCH v4 1/2] arcmsr: simplify ioctl data read/write', Ching will repost it later.
Thanks a lot Tomas for all the review, and thanks Ching for the patches
and updates. I'll merge the branch and the additional patch today.
Ching Huang
2014-09-16 02:42:08 UTC
Permalink
Post by Christoph Hellwig
Post by Ching Huang
Christoph,
you may add my 'reviewed-by' to the arcmsr series
http://git.infradead.org/users/hch/scsi-queue.git/tree/arcmsr-for-3.18:/drivers/scsi/arcmsr
with the '[PATCH v5 2/2] arcmsr: simplify of updating doneq_index and postq_index'
( https://lkml.org/lkml/2014/9/15/177 ) on top of the series
that last patch fixes the 16/17 from your git.
I hope the series is an iteration in the right direction.
Skip the the '[PATCH v4 1/2] arcmsr: simplify ioctl data read/write', Ching will repost it later.
Thanks a lot Tomas for all the review, and thanks Ching for the patches
and updates. I'll merge the branch and the additional patch today.
Christoph,

The [PATCH v5 2/2] was depend on [PATCH v4 1/2].
If you skip patch 1/2, then patch 2/2 may cause line number mismatch.
How should I do? Please advise.
Christoph Hellwig
2014-09-16 22:40:19 UTC
Permalink
Post by Ching Huang
The [PATCH v5 2/2] was depend on [PATCH v4 1/2].
If you skip patch 1/2, then patch 2/2 may cause line number mismatch.
How should I do? Please advise.
Hi Ching,

[PATCH v5 2/2] applied without a problem. Please look at my
drivers-for-3.18 branch and send any additional patches relative to
that.

Loading...