[PATCH 1/3] scsi: arcmsr: support Areca ARC-1688 Raid controller

From: ching Huang
Date: Mon Sep 18 2023 - 06:33:26 EST


From: ching Huang <ching2048@xxxxxxxxxxxx>

This patch supports Areca new Raid controller ARC-1688

Signed-off-by: ching Huang <ching2048@xxxxxxxxxxxx>
---

diff --git a/drivers/scsi/arcmsr/arcmsr.h
b/drivers/scsi/arcmsr/arcmsr.h
index ed8d931..8c0db11 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -818,6 +818,23 @@ typedef struct deliver_completeQ {
uint16_t cmdLMID; // reserved (0)
uint16_t cmdFlag2; // reserved (0)
} DeliverQ, CompletionQ, *pDeliver_Q, *pCompletion_Q;
+
+#define ARCMSR_XOR_SEG_SIZE (1024 * 1024)
+struct HostRamBuf {
+ uint32_t hrbSignature; // must be "HRBS"
+ uint32_t hrbSize; // total buffer size(must be
multiples of MB)
+ uint32_t hrbRes[2]; // reserved, must be set to 0
+};
+struct Xor_sg {
+ dma_addr_t xorPhys;
+ uint64_t xorBufLen;
+};
+struct XorHandle {
+ dma_addr_t xorPhys;
+ uint64_t xorBufLen;
+ void *xorVirt;
+};
+
/*
**********************************************************************
*********
** Adapter Control Block
@@ -929,6 +946,7 @@ struct AdapterControlBlock
char firm_model[12];
char firm_version[20];
char device_map[20]; /*21,84
-99*/
+ uint32_t firm_PicStatus;
struct work_struct arcmsr_do_message_isr_bh;
struct timer_list eternal_timer;
unsigned short fw_flag;
@@ -937,6 +955,7 @@ struct AdapterControlBlock
#define FW_DEADLOCK 0x0010
uint32_t maxOutstanding;
int vector_count;
+ int xor_mega;
uint32_t maxFreeCCB;
struct timer_list refresh_timer;
uint32_t doneq_index;
@@ -946,6 +965,10 @@ struct AdapterControlBlock
uint32_t completionQ_entry;
pCompletion_Q pCompletionQ;
uint32_t completeQ_size;
+ void *xorVirt;
+ dma_addr_t xorPhys;
+ unsigned int init2cfg_size;
+ unsigned int xorVirtOffset;
};/* HW_DEVICE_EXTENSION */
/*
**********************************************************************
*********
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c
b/drivers/scsi/arcmsr/arcmsr_hba.c
index a66221c..39d3b10 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -747,6 +747,51 @@ static bool arcmsr_alloc_io_queue(struct
AdapterControlBlock *acb)
return rtn;
}

+static int arcmsr_alloc_xor_buffer(struct AdapterControlBlock *acb)
+{
+ int rc = 0;
+ struct pci_dev *pdev = acb->pdev;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle;
+ int i, xor_ram;
+ struct Xor_sg *pXorPhys;
+ void **pXorVirt;
+ struct HostRamBuf *pRamBuf;
+
+ // allocate N times 1 MB physical continuous memory for XOR
engine of Raid 5, 6.
+ xor_ram = (acb->firm_PicStatus >> 24) & 0x0f;
+ acb->xor_mega = (xor_ram - 1) * 32 + 128 + 3;
+ acb->init2cfg_size = sizeof(struct HostRamBuf) + (sizeof(struct
XorHandle) * acb->xor_mega);
+ dma_coherent = dma_alloc_coherent(&pdev->dev, acb-
>init2cfg_size,
+ &dma_coherent_handle, GFP_KERNEL);
+ acb->xorVirt = dma_coherent;
+ acb->xorPhys = dma_coherent_handle;
+ pXorPhys = (struct Xor_sg *)((unsigned long)dma_coherent +
sizeof(struct HostRamBuf));
+ acb->xorVirtOffset = sizeof(struct HostRamBuf) + (sizeof(struct
Xor_sg) * acb->xor_mega);
+ pXorVirt = (void **)((unsigned long)dma_coherent + (unsigned
long)acb->xorVirtOffset);
+ for (i = 0; i < acb->xor_mega; i++) {
+ dma_coherent = dma_alloc_coherent(&pdev->dev,
ARCMSR_XOR_SEG_SIZE,
+ &dma_coherent_handle, GFP_KERNEL);
+ if (dma_coherent) {
+ pXorPhys->xorPhys = dma_coherent_handle;
+ pXorPhys->xorBufLen = ARCMSR_XOR_SEG_SIZE;
+ *pXorVirt = dma_coherent;
+ pXorPhys++;
+ pXorVirt++;
+ } else {
+ printk("arcmsr%d: alloc max XOR buffer = 0x%x
MB\n", acb->host->host_no, i);
+ rc = -ENOMEM;
+ break;
+ }
+ }
+ pRamBuf = (struct HostRamBuf *)acb->xorVirt;
+ pRamBuf->hrbSignature = 0x53425248; //HRBS
+ pRamBuf->hrbSize = i * ARCMSR_XOR_SEG_SIZE;
+ pRamBuf->hrbRes[0] = 0;
+ pRamBuf->hrbRes[1] = 0;
+ return rc;
+}
+
static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
@@ -837,6 +882,10 @@ static int arcmsr_alloc_ccb_pool(struct
AdapterControlBlock *acb)
acb->doneq_index = 0;
break;
}
+ if ((acb->firm_PicStatus >> 24) & 0x0f) {
+ if (arcmsr_alloc_xor_buffer(acb))
+ return -ENOMEM;
+ }
return 0;
}

@@ -2022,6 +2071,26 @@ static void arcmsr_stop_adapter_bgrb(struct
AdapterControlBlock *acb)

static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb)
{
+ if (acb->xor_mega) {
+ struct Xor_sg *pXorPhys;
+ void **pXorVirt;
+ int i;
+
+ pXorPhys = (struct Xor_sg *)(acb->xorVirt +
sizeof(struct HostRamBuf));
+ pXorVirt = (void **)((unsigned long)acb->xorVirt +
(unsigned long)acb->xorVirtOffset);
+ for (i = 0; i < acb->xor_mega; i++) {
+ if (pXorPhys->xorPhys) {
+ dma_free_coherent(&acb->pdev->dev,
ARCMSR_XOR_SEG_SIZE,
+ *pXorVirt, pXorPhys->xorPhys);
+ pXorPhys->xorPhys = (dma_addr_t)NULL;
+ *pXorVirt = NULL;
+ }
+ pXorPhys++;
+ pXorVirt++;
+ }
+ dma_free_coherent(&acb->pdev->dev, acb->init2cfg_size,
+ acb->xorVirt, acb->xorPhys);
+ }
dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb-
>dma_coherent, acb->dma_coherent_handle);
}

@@ -3309,6 +3378,10 @@ static void arcmsr_get_adapter_config(struct
AdapterControlBlock *pACB, uint32_t
pACB->firm_sdram_size = readl(&rwbuffer[3]);
pACB->firm_hd_channels = readl(&rwbuffer[4]);
pACB->firm_cfg_version = readl(&rwbuffer[25]);
+ if (pACB->adapter_type == ACB_ADAPTER_TYPE_F)
+ pACB->firm_PicStatus = readl(&rwbuffer[30]);
+ else
+ pACB->firm_PicStatus = 0;
pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n",
pACB->host->host_no,
pACB->firm_model,
@@ -4096,6 +4169,12 @@ static int arcmsr_iop_confirm(struct
AdapterControlBlock *acb)
acb->msgcode_rwbuffer[5] = lower_32_bits(acb-
>dma_coherent_handle2);
acb->msgcode_rwbuffer[6] = upper_32_bits(acb-
>dma_coherent_handle2);
acb->msgcode_rwbuffer[7] = acb->completeQ_size;
+ if (acb->xor_mega) {
+ acb->msgcode_rwbuffer[8] = 0x455AA; //Linux
init 2
+ acb->msgcode_rwbuffer[9] = 0;
+ acb->msgcode_rwbuffer[10] = lower_32_bits(acb-
>xorPhys);
+ acb->msgcode_rwbuffer[11] = upper_32_bits(acb-
>xorPhys);
+ }
writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg-
>inbound_msgaddr0);
acb->out_doorbell ^=
ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE;
writel(acb->out_doorbell, &reg->iobound_doorbell);