scsi: arcmsr: Support new RAID controller ARC-1688
authorching Huang <ching2048@areca.com.tw>
Mon, 2 Oct 2023 09:42:19 +0000 (17:42 +0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Sat, 25 Nov 2023 02:20:49 +0000 (21:20 -0500)
Add support for new Areca RAID controller ARC-1688

Signed-off-by: ching Huang <ching2048@areca.com.tw>
Link: https://lore.kernel.org/r/110bdc873497d3d5e090b908fb159b6155bb3a2b.camel@areca.com.tw
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/arcmsr/arcmsr.h
drivers/scsi/arcmsr/arcmsr_hba.c

index ed8d9319862a5a05f19ed4fe90ec779acbcaae05..8f20d9cc5377401caf92510649d553fb55606892 100644 (file)
@@ -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 sg size, 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 */
 /*
 *******************************************************************************
index a66221c3b72f82501b5a1cc70f291fd45fbae546..092c704aa7352718ae2e28530d4dc5ff2a515e15 100644 (file)
@@ -747,6 +747,57 @@ 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 1 MB * N physically continuous memory for XOR engine.
+       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 {
+                       pr_info("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;
@@ -836,7 +887,11 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
                acb->completionQ_entry = acb->ioqueue_size / sizeof(struct deliver_completeQ);
                acb->doneq_index = 0;
                break;
-       }       
+       }
+       if ((acb->firm_PicStatus >> 24) & 0x0f) {
+               if (arcmsr_alloc_xor_buffer(acb))
+                       return -ENOMEM;
+       }
        return 0;
 }
 
@@ -2022,6 +2077,29 @@ 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 = 0;
+                               *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 +3387,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 +4178,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);