diff options
Diffstat (limited to 'drivers/scsi/arcmsr')
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr.h | 146 | ||||
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_attr.c | 120 | ||||
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_hba.c | 2326 |
3 files changed, 1811 insertions, 781 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index 77b26f5b9c33..3bcaaac0ae4b 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -45,13 +45,14 @@ #include <linux/interrupt.h> struct device_attribute; /*The limit of outstanding scsi command that firmware can handle*/ -#define ARCMSR_MAX_OUTSTANDING_CMD 256 #ifdef CONFIG_XEN #define ARCMSR_MAX_FREECCB_NUM 160 +#define ARCMSR_MAX_OUTSTANDING_CMD 155 #else #define ARCMSR_MAX_FREECCB_NUM 320 +#define ARCMSR_MAX_OUTSTANDING_CMD 255 #endif -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/08/05" +#define ARCMSR_DRIVER_VERSION "v1.30.00.04-20140919" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -62,11 +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 /* ********************************************************************************** ** @@ -100,10 +107,11 @@ struct CMD_MESSAGE ** IOP Message Transfer Data for user space ******************************************************************************* */ +#define ARCMSR_API_DATA_BUFLEN 1032 struct CMD_MESSAGE_FIELD { struct CMD_MESSAGE cmdmessage; - uint8_t messagedatabuffer[1032]; + uint8_t messagedatabuffer[ARCMSR_API_DATA_BUFLEN]; }; /* IOP message transfer */ #define ARCMSR_MESSAGE_FAIL 0x0001 @@ -337,6 +345,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) ******************************************************************************* */ @@ -357,7 +415,7 @@ struct ARCMSR_CDB #define ARCMSR_CDB_FLAG_ORDEREDQ 0x10 uint8_t msgPages; - uint32_t Context; + uint32_t msgContext; uint32_t DataLength; uint8_t Cdb[16]; uint8_t DeviceStatus; @@ -494,6 +552,56 @@ struct MessageUnit_C{ uint32_t msgcode_rwbuffer[256]; /*2200 23FF*/ }; /* +********************************************************************* +** Messaging Unit (MU) of Type D processor +********************************************************************* +*/ +struct InBound_SRB { + uint32_t addressLow; /* pointer to SRB block */ + uint32_t addressHigh; + uint32_t length; /* in DWORDs */ + uint32_t reserved0; +}; + +struct OutBound_SRB { + uint32_t addressLow; /* pointer to SRB block */ + uint32_t addressHigh; +}; + +struct MessageUnit_D { + struct InBound_SRB post_qbuffer[ARCMSR_MAX_ARC1214_POSTQUEUE]; + volatile struct OutBound_SRB + done_qbuffer[ARCMSR_MAX_ARC1214_DONEQUEUE]; + u16 postq_index; + volatile u16 doneq_index; + u32 __iomem *chip_id; /* 0x00004 */ + u32 __iomem *cpu_mem_config; /* 0x00008 */ + u32 __iomem *i2o_host_interrupt_mask; /* 0x00034 */ + u32 __iomem *sample_at_reset; /* 0x00100 */ + u32 __iomem *reset_request; /* 0x00108 */ + u32 __iomem *host_int_status; /* 0x00200 */ + u32 __iomem *pcief0_int_enable; /* 0x0020C */ + u32 __iomem *inbound_msgaddr0; /* 0x00400 */ + u32 __iomem *inbound_msgaddr1; /* 0x00404 */ + u32 __iomem *outbound_msgaddr0; /* 0x00420 */ + u32 __iomem *outbound_msgaddr1; /* 0x00424 */ + u32 __iomem *inbound_doorbell; /* 0x00460 */ + u32 __iomem *outbound_doorbell; /* 0x00480 */ + u32 __iomem *outbound_doorbell_enable; /* 0x00484 */ + u32 __iomem *inboundlist_base_low; /* 0x01000 */ + u32 __iomem *inboundlist_base_high; /* 0x01004 */ + u32 __iomem *inboundlist_write_pointer; /* 0x01018 */ + u32 __iomem *outboundlist_base_low; /* 0x01060 */ + u32 __iomem *outboundlist_base_high; /* 0x01064 */ + u32 __iomem *outboundlist_copy_pointer; /* 0x0106C */ + u32 __iomem *outboundlist_read_pointer; /* 0x01070 0x01072 */ + u32 __iomem *outboundlist_interrupt_cause; /* 0x1088 */ + u32 __iomem *outboundlist_interrupt_enable; /* 0x108C */ + u32 __iomem *message_wbuffer; /* 0x2000 */ + u32 __iomem *message_rbuffer; /* 0x2100 */ + u32 __iomem *msgcode_rwbuffer; /* 0x2200 */ +}; +/* ******************************************************************************* ** Adapter Control Block ******************************************************************************* @@ -505,19 +613,26 @@ struct AdapterControlBlock #define ACB_ADAPTER_TYPE_B 0x00000002 /* hbb M IOP */ #define ACB_ADAPTER_TYPE_C 0x00000004 /* hbc P IOP */ #define ACB_ADAPTER_TYPE_D 0x00000008 /* hbd A IOP */ + u32 roundup_ccbsize; struct pci_dev * pdev; struct Scsi_Host * host; unsigned long vir2phy_offset; + struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS]; /* Offset is used in making arc cdb physical to virtual calculations */ uint32_t outbound_int_enable; uint32_t cdb_phyaddr_hi32; 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; @@ -544,6 +659,8 @@ struct AdapterControlBlock /* iop init */ #define ACB_F_ABORT 0x0200 #define ACB_F_FIRMWARE_TRAP 0x0400 + #define ACB_F_MSI_ENABLED 0x1000 + #define ACB_F_MSIX_ENABLED 0x2000 struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; /* used for memory free */ struct list_head ccb_free_list; @@ -557,19 +674,20 @@ struct AdapterControlBlock /* dma_coherent used for memory free */ dma_addr_t dma_coherent_handle; /* dma_coherent_handle used for memory free */ - dma_addr_t dma_coherent_handle_hbb_mu; + dma_addr_t dma_coherent_handle2; + void *dma_coherent2; unsigned int uncache_size; uint8_t rqbuffer[ARCMSR_MAX_QBUFFER]; /* data collection buffer for read from 80331 */ - int32_t rqbuf_firstindex; + int32_t rqbuf_getIndex; /* first of read buffer */ - int32_t rqbuf_lastindex; + int32_t rqbuf_putIndex; /* last of read buffer */ uint8_t wqbuffer[ARCMSR_MAX_QBUFFER]; /* data collection buffer for write to 80331 */ - int32_t wqbuf_firstindex; + int32_t wqbuf_getIndex; /* first of write buffer */ - int32_t wqbuf_lastindex; + int32_t wqbuf_putIndex; /* last of write buffer */ uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN]; /* id0 ..... id15, lun0...lun7 */ @@ -594,6 +712,8 @@ struct AdapterControlBlock #define FW_DEADLOCK 0x0010 atomic_t rq_map_token; atomic_t ante_token_value; + uint32_t maxOutstanding; + int msix_vector_count; };/* HW_DEVICE_EXTENSION */ /* ******************************************************************************* @@ -606,7 +726,7 @@ struct CommandControlBlock{ struct list_head list; /*x32: 8byte, x64: 16byte*/ struct scsi_cmnd *pcmd; /*8 bytes pointer of linux scsi command */ struct AdapterControlBlock *acb; /*x32: 4byte, x64: 8byte*/ - uint32_t cdb_phyaddr_pattern; /*x32: 4byte, x64: 4byte*/ + uint32_t cdb_phyaddr; /*x32: 4byte, x64: 4byte*/ uint32_t arc_cdb_size; /*x32:4byte,x64:4byte*/ uint16_t ccb_flags; /*x32: 2byte, x64: 2byte*/ #define CCB_FLAG_READ 0x0000 @@ -684,8 +804,10 @@ struct SENSE_DATA #define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01 #define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F -extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *); -extern void arcmsr_iop_message_read(struct AdapterControlBlock *); +extern void arcmsr_write_ioctldata2iop(struct AdapterControlBlock *); +extern uint32_t arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *, + struct QBUFFER __iomem *); +extern void arcmsr_clear_iop2drv_rqueue_buffer(struct AdapterControlBlock *); extern struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *); extern struct device_attribute *arcmsr_host_attrs[]; extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *); diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index acdae33de521..9c86481f779f 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -50,6 +50,7 @@ #include <linux/errno.h> #include <linux/delay.h> #include <linux/pci.h> +#include <linux/circ_buf.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> @@ -68,42 +69,42 @@ static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp, struct device *dev = container_of(kobj,struct device,kobj); struct Scsi_Host *host = class_to_shost(dev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - uint8_t *pQbuffer,*ptmpQbuffer; + uint8_t *ptmpQbuffer; int32_t allxfer_len = 0; + unsigned long flags; if (!capable(CAP_SYS_ADMIN)) return -EACCES; /* do message unit read. */ ptmpQbuffer = (uint8_t *)buf; - while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) - && (allxfer_len < 1031)) { - pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; - memcpy(ptmpQbuffer, pQbuffer, 1); - acb->rqbuf_firstindex++; - acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - ptmpQbuffer++; - allxfer_len++; + spin_lock_irqsave(&acb->rqbuffer_lock, flags); + if (acb->rqbuf_getIndex != acb->rqbuf_putIndex) { + unsigned int tail = acb->rqbuf_getIndex; + unsigned int head = acb->rqbuf_putIndex; + unsigned int cnt_to_end = CIRC_CNT_TO_END(head, tail, ARCMSR_MAX_QBUFFER); + + allxfer_len = CIRC_CNT(head, tail, ARCMSR_MAX_QBUFFER); + if (allxfer_len > ARCMSR_API_DATA_BUFLEN) + allxfer_len = ARCMSR_API_DATA_BUFLEN; + + if (allxfer_len <= cnt_to_end) + memcpy(ptmpQbuffer, acb->rqbuffer + tail, allxfer_len); + else { + memcpy(ptmpQbuffer, acb->rqbuffer + tail, cnt_to_end); + memcpy(ptmpQbuffer + cnt_to_end, acb->rqbuffer, allxfer_len - cnt_to_end); + } + acb->rqbuf_getIndex = (acb->rqbuf_getIndex + allxfer_len) % ARCMSR_MAX_QBUFFER; } if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { struct QBUFFER __iomem *prbuffer; - uint8_t __iomem *iop_data; - int32_t iop_len; - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; prbuffer = arcmsr_get_iop_rqbuffer(acb); - iop_data = prbuffer->data; - iop_len = readl(&prbuffer->data_len); - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; - } - arcmsr_iop_message_read(acb); + if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; } - return (allxfer_len); + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); + return allxfer_len; } static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, @@ -115,43 +116,42 @@ static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, struct device *dev = container_of(kobj,struct device,kobj); struct Scsi_Host *host = class_to_shost(dev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; + int32_t user_len, cnt2end; uint8_t *pQbuffer, *ptmpuserbuffer; + unsigned long flags; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (count > 1032) + if (count > ARCMSR_API_DATA_BUFLEN) return -EINVAL; /* do message unit write. */ ptmpuserbuffer = (uint8_t *)buf; user_len = (int32_t)count; - wqbuf_lastindex = acb->wqbuf_lastindex; - wqbuf_firstindex = acb->wqbuf_firstindex; - if (wqbuf_lastindex != wqbuf_firstindex) { - arcmsr_post_ioctldata2iop(acb); + spin_lock_irqsave(&acb->wqbuffer_lock, flags); + if (acb->wqbuf_putIndex != acb->wqbuf_getIndex) { + arcmsr_write_ioctldata2iop(acb); + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); return 0; /*need retry*/ } else { - my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) - &(ARCMSR_MAX_QBUFFER - 1); - if (my_empty_len >= user_len) { - while (user_len > 0) { - pQbuffer = - &acb->wqbuffer[acb->wqbuf_lastindex]; - memcpy(pQbuffer, ptmpuserbuffer, 1); - acb->wqbuf_lastindex++; - acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - ptmpuserbuffer++; - user_len--; - } - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { - acb->acb_flags &= - ~ACB_F_MESSAGE_WQBUFFER_CLEARED; - arcmsr_post_ioctldata2iop(acb); - } - return count; - } else { - return 0; /*need retry*/ + pQbuffer = &acb->wqbuffer[acb->wqbuf_putIndex]; + cnt2end = ARCMSR_MAX_QBUFFER - acb->wqbuf_putIndex; + if (user_len > cnt2end) { + memcpy(pQbuffer, ptmpuserbuffer, cnt2end); + ptmpuserbuffer += cnt2end; + user_len -= cnt2end; + acb->wqbuf_putIndex = 0; + pQbuffer = acb->wqbuffer; + } + memcpy(pQbuffer, ptmpuserbuffer, user_len); + acb->wqbuf_putIndex += user_len; + acb->wqbuf_putIndex %= ARCMSR_MAX_QBUFFER; + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { + acb->acb_flags &= + ~ACB_F_MESSAGE_WQBUFFER_CLEARED; + arcmsr_write_ioctldata2iop(acb); } + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); + return count; } } @@ -165,22 +165,24 @@ static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp, struct Scsi_Host *host = class_to_shost(dev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; uint8_t *pQbuffer; + unsigned long flags; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - arcmsr_iop_message_read(acb); - } + arcmsr_clear_iop2drv_rqueue_buffer(acb); acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; + spin_lock_irqsave(&acb->rqbuffer_lock, flags); + acb->rqbuf_getIndex = 0; + acb->rqbuf_putIndex = 0; + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); + spin_lock_irqsave(&acb->wqbuffer_lock, flags); + acb->wqbuf_getIndex = 0; + acb->wqbuf_putIndex = 0; + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); pQbuffer = acb->rqbuffer; memset(pQbuffer, 0, sizeof (struct QBUFFER)); pQbuffer = acb->wqbuffer; @@ -193,7 +195,7 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = { .name = "mu_read", .mode = S_IRUSR , }, - .size = 1032, + .size = ARCMSR_API_DATA_BUFLEN, .read = arcmsr_sysfs_iop_message_read, }; @@ -202,7 +204,7 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = { .name = "mu_write", .mode = S_IWUSR, }, - .size = 1032, + .size = ARCMSR_API_DATA_BUFLEN, .write = arcmsr_sysfs_iop_message_write, }; diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index b13764ca23fd..0b44fb5ee485 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -2,11 +2,10 @@ ******************************************************************************* ** O.S : Linux ** FILE NAME : arcmsr_hba.c -** BY : Nick Cheng -** Description: SCSI RAID Device Driver for -** ARECA RAID Host adapter +** BY : Nick Cheng, C.L. Huang +** Description: SCSI RAID Device Driver for Areca RAID Controller ******************************************************************************* -** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved +** Copyright (C) 2002 - 2014, Areca Technology Corporation All rights reserved ** ** Web site: www.areca.com.tw ** E-mail: support@areca.com.tw @@ -59,6 +58,7 @@ #include <linux/slab.h> #include <linux/pci.h> #include <linux/aer.h> +#include <linux/circ_buf.h> #include <asm/dma.h> #include <asm/io.h> #include <asm/uaccess.h> @@ -70,15 +70,15 @@ #include <scsi/scsi_transport.h> #include <scsi/scsicam.h> #include "arcmsr.h" -MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>"); -MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter"); +MODULE_AUTHOR("Nick Cheng, C.L. Huang <support@areca.com.tw>"); +MODULE_DESCRIPTION("Areca ARC11xx/12xx/16xx/188x SAS/SATA RAID Controller Driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); #define ARCMSR_SLEEPTIME 10 #define ARCMSR_RETRYCOUNT 12 -wait_queue_head_t wait_q; +static wait_queue_head_t wait_q; static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); static int arcmsr_iop_confirm(struct AdapterControlBlock *acb); @@ -89,25 +89,31 @@ static int arcmsr_bios_param(struct scsi_device *sdev, static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id); +static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state); +static int arcmsr_resume(struct pci_dev *pdev); static void arcmsr_remove(struct pci_dev *pdev); static void arcmsr_shutdown(struct pci_dev *pdev); static void arcmsr_iop_init(struct AdapterControlBlock *acb); static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb); static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb); +static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, + u32 intmask_org); static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); -static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb); -static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb); +static void arcmsr_hbaA_flush_cache(struct AdapterControlBlock *acb); +static void arcmsr_hbaB_flush_cache(struct AdapterControlBlock *acb); static void arcmsr_request_device_map(unsigned long pacb); -static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb); -static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb); -static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb); +static void arcmsr_hbaA_request_device_map(struct AdapterControlBlock *acb); +static void arcmsr_hbaB_request_device_map(struct AdapterControlBlock *acb); +static void arcmsr_hbaC_request_device_map(struct AdapterControlBlock *acb); static void arcmsr_message_isr_bh_fn(struct work_struct *work); static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb); static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); -static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB); +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); +static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *); static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth, int reason) { @@ -122,15 +128,14 @@ static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, static struct scsi_host_template arcmsr_scsi_host_template = { .module = THIS_MODULE, - .name = "ARCMSR ARECA SATA/SAS RAID Controller" - ARCMSR_DRIVER_VERSION, + .name = "Areca SAS/SATA RAID driver", .info = arcmsr_info, .queuecommand = arcmsr_queue_command, .eh_abort_handler = arcmsr_abort, .eh_bus_reset_handler = arcmsr_bus_reset, .bios_param = arcmsr_bios_param, .change_queue_depth = arcmsr_adjust_disk_queue_depth, - .can_queue = ARCMSR_MAX_FREECCB_NUM, + .can_queue = ARCMSR_MAX_OUTSTANDING_CMD, .this_id = ARCMSR_SCSI_INITIATOR_ID, .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES, .max_sectors = ARCMSR_MAX_XFER_SECTORS_C, @@ -139,34 +144,59 @@ static struct scsi_host_template arcmsr_scsi_host_template = { .shost_attrs = arcmsr_host_attrs, .no_write_same = 1, }; + static struct pci_device_id arcmsr_device_id_table[] = { - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880)}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200), + .driver_data = ACB_ADAPTER_TYPE_B}, + {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}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681), + .driver_data = ACB_ADAPTER_TYPE_A}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880), + .driver_data = ACB_ADAPTER_TYPE_C}, {0, 0}, /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); + static struct pci_driver arcmsr_pci_driver = { .name = "arcmsr", .id_table = arcmsr_device_id_table, .probe = arcmsr_probe, .remove = arcmsr_remove, + .suspend = arcmsr_suspend, + .resume = arcmsr_resume, .shutdown = arcmsr_shutdown, }; /* @@ -174,16 +204,14 @@ static struct pci_driver arcmsr_pci_driver = { **************************************************************************** */ -static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb) +static void arcmsr_free_mu(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: - case ACB_ADAPTER_TYPE_C: + 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; - case ACB_ADAPTER_TYPE_B:{ - dma_free_coherent(&acb->pdev->dev, - sizeof(struct MessageUnit_B), - acb->pmuB, acb->dma_coherent_handle_hbb_mu); } } } @@ -229,6 +257,25 @@ static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) } break; } + case ACB_ADAPTER_TYPE_D: { + void __iomem *mem_base0; + unsigned long addr, range, flags; + + addr = (unsigned long)pci_resource_start(pdev, 0); + range = pci_resource_len(pdev, 0); + flags = pci_resource_flags(pdev, 0); + if (flags & IORESOURCE_CACHEABLE) + mem_base0 = ioremap(addr, range); + else + mem_base0 = ioremap_nocache(addr, range); + if (!mem_base0) { + pr_notice("arcmsr%d: memory mapping region fail\n", + acb->host->host_no); + return false; + } + acb->mem_base0 = mem_base0; + break; + } } return true; } @@ -249,6 +296,10 @@ static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_C:{ iounmap(acb->pmuC); } + break; + case ACB_ADAPTER_TYPE_D: + iounmap(acb->mem_base0); + break; } } @@ -289,27 +340,7 @@ static int arcmsr_bios_param(struct scsi_device *sdev, return 0; } -static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) -{ - struct pci_dev *pdev = acb->pdev; - u16 dev_id; - pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); - acb->dev_id = dev_id; - switch (dev_id) { - case 0x1880: { - acb->adapter_type = ACB_ADAPTER_TYPE_C; - } - break; - case 0x1201: { - acb->adapter_type = ACB_ADAPTER_TYPE_B; - } - break; - - default: acb->adapter_type = ACB_ADAPTER_TYPE_A; - } -} - -static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) +static uint8_t arcmsr_hbaA_wait_msgint_ready(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; int i; @@ -327,7 +358,7 @@ static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) return false; } -static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) +static uint8_t arcmsr_hbaB_wait_msgint_ready(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; int i; @@ -347,9 +378,9 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) return false; } -static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB) +static uint8_t arcmsr_hbaC_wait_msgint_ready(struct AdapterControlBlock *pACB) { - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; + struct MessageUnit_C __iomem *phbcmu = pACB->pmuC; int i; for (i = 0; i < 2000; i++) { @@ -365,13 +396,30 @@ static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB) return false; } -static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) +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; int retry_count = 30; writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); do { - if (arcmsr_hba_wait_msgint_ready(acb)) + if (arcmsr_hbaA_wait_msgint_ready(acb)) break; else { retry_count--; @@ -381,13 +429,13 @@ static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) } while (retry_count != 0); } -static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) +static void arcmsr_hbaB_flush_cache(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; int retry_count = 30; writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell); do { - if (arcmsr_hbb_wait_msgint_ready(acb)) + if (arcmsr_hbaB_wait_msgint_ready(acb)) break; else { retry_count--; @@ -397,14 +445,14 @@ static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) } while (retry_count != 0); } -static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB) +static void arcmsr_hbaC_flush_cache(struct AdapterControlBlock *pACB) { - struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; + struct MessageUnit_C __iomem *reg = pACB->pmuC; int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */ writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); do { - if (arcmsr_hbc_wait_msgint_ready(pACB)) { + if (arcmsr_hbaC_wait_msgint_ready(pACB)) { break; } else { retry_count--; @@ -414,22 +462,44 @@ static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB) } while (retry_count != 0); return; } + +static void arcmsr_hbaD_flush_cache(struct AdapterControlBlock *pACB) +{ + int retry_count = 15; + struct MessageUnit_D *reg = pACB->pmuD; + + writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, reg->inbound_msgaddr0); + do { + if (arcmsr_hbaD_wait_msgint_ready(pACB)) + break; + + retry_count--; + pr_notice("arcmsr%d: wait 'flush adapter " + "cache' timeout, retry count down = %d\n", + pACB->host->host_no, retry_count); + } while (retry_count != 0); +} + static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { - arcmsr_flush_hba_cache(acb); + arcmsr_hbaA_flush_cache(acb); } break; case ACB_ADAPTER_TYPE_B: { - arcmsr_flush_hbb_cache(acb); + arcmsr_hbaB_flush_cache(acb); } break; case ACB_ADAPTER_TYPE_C: { - arcmsr_flush_hbc_cache(acb); + arcmsr_hbaC_flush_cache(acb); } + break; + case ACB_ADAPTER_TYPE_D: + arcmsr_hbaD_flush_cache(acb); + break; } } @@ -473,7 +543,16 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){ cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); - ccb_tmp->cdb_phyaddr_pattern = ((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); @@ -486,121 +565,126 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) static void arcmsr_message_isr_bh_fn(struct work_struct *work) { - struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh); + struct AdapterControlBlock *acb = container_of(work, + struct AdapterControlBlock, arcmsr_do_message_isr_bh); + char *acb_dev_map = (char *)acb->device_map; + uint32_t __iomem *signature = NULL; + char __iomem *devicemap = NULL; + int target, lun; + struct scsi_device *psdev; + char diff, temp; + switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = acb->pmuA; - struct MessageUnit_A __iomem *reg = acb->pmuA; - char *acb_dev_map = (char *)acb->device_map; - uint32_t __iomem *signature = (uint32_t __iomem*) (®->message_rwbuffer[0]); - char __iomem *devicemap = (char __iomem*) (®->message_rwbuffer[21]); - int target, lun; - struct scsi_device *psdev; - char diff; - - atomic_inc(&acb->rq_map_token); - if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { - for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) { - diff = (*acb_dev_map)^readb(devicemap); - if (diff != 0) { - char temp; - *acb_dev_map = readb(devicemap); - temp =*acb_dev_map; - for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { - if((temp & 0x01)==1 && (diff & 0x01) == 1) { - scsi_add_device(acb->host, 0, target, lun); - }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) { - psdev = scsi_device_lookup(acb->host, 0, target, lun); - if (psdev != NULL ) { - scsi_remove_device(psdev); - scsi_device_put(psdev); - } - } - temp >>= 1; - diff >>= 1; - } - } - devicemap++; - acb_dev_map++; - } - } - break; - } + signature = (uint32_t __iomem *)(®->message_rwbuffer[0]); + devicemap = (char __iomem *)(®->message_rwbuffer[21]); + break; + } + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = acb->pmuB; - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - char *acb_dev_map = (char *)acb->device_map; - uint32_t __iomem *signature = (uint32_t __iomem*)(®->message_rwbuffer[0]); - char __iomem *devicemap = (char __iomem*)(®->message_rwbuffer[21]); - int target, lun; - struct scsi_device *psdev; - char diff; - - atomic_inc(&acb->rq_map_token); - if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { - for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) { - diff = (*acb_dev_map)^readb(devicemap); - if (diff != 0) { - char temp; - *acb_dev_map = readb(devicemap); - temp =*acb_dev_map; - for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { - if((temp & 0x01)==1 && (diff & 0x01) == 1) { - scsi_add_device(acb->host, 0, target, lun); - }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) { - psdev = scsi_device_lookup(acb->host, 0, target, lun); - if (psdev != NULL ) { - scsi_remove_device(psdev); - scsi_device_put(psdev); - } - } - temp >>= 1; - diff >>= 1; - } - } - devicemap++; - acb_dev_map++; - } - } - } + signature = (uint32_t __iomem *)(®->message_rwbuffer[0]); + devicemap = (char __iomem *)(®->message_rwbuffer[21]); break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = acb->pmuC; - char *acb_dev_map = (char *)acb->device_map; - uint32_t __iomem *signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]); - char __iomem *devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]); - int target, lun; - struct scsi_device *psdev; - char diff; - - atomic_inc(&acb->rq_map_token); - if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { - for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) { - diff = (*acb_dev_map)^readb(devicemap); - if (diff != 0) { - char temp; - *acb_dev_map = readb(devicemap); - temp = *acb_dev_map; - for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { - if ((temp & 0x01) == 1 && (diff & 0x01) == 1) { - scsi_add_device(acb->host, 0, target, lun); - } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) { - psdev = scsi_device_lookup(acb->host, 0, target, lun); - if (psdev != NULL) { - scsi_remove_device(psdev); - scsi_device_put(psdev); - } - } - temp >>= 1; - diff >>= 1; - } + } + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C __iomem *reg = acb->pmuC; + + signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]); + devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]); + break; + } + case ACB_ADAPTER_TYPE_D: { + struct MessageUnit_D *reg = acb->pmuD; + + signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]); + devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]); + break; + } + } + atomic_inc(&acb->rq_map_token); + if (readl(signature) != ARCMSR_SIGNATURE_GET_CONFIG) + return; + for (target = 0; target < ARCMSR_MAX_TARGETID - 1; + target++) { + temp = readb(devicemap); + diff = (*acb_dev_map) ^ temp; + if (diff != 0) { + *acb_dev_map = temp; + for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; + lun++) { + if ((diff & 0x01) == 1 && + (temp & 0x01) == 1) { + scsi_add_device(acb->host, + 0, target, lun); + } else if ((diff & 0x01) == 1 + && (temp & 0x01) == 0) { + psdev = scsi_device_lookup(acb->host, + 0, target, lun); + if (psdev != NULL) { + scsi_remove_device(psdev); + scsi_device_put(psdev); } - devicemap++; - acb_dev_map++; } + temp >>= 1; + diff >>= 1; } } + devicemap++; + acb_dev_map++; + } +} + +static int +arcmsr_request_irq(struct pci_dev *pdev, struct AdapterControlBlock *acb) +{ + int i, j, r; + struct msix_entry entries[ARCMST_NUM_MSIX_VECTORS]; + + for (i = 0; i < ARCMST_NUM_MSIX_VECTORS; i++) + entries[i].entry = i; + r = pci_enable_msix_range(pdev, entries, 1, ARCMST_NUM_MSIX_VECTORS); + if (r < 0) + goto msi_int; + acb->msix_vector_count = r; + for (i = 0; i < r; i++) { + if (request_irq(entries[i].vector, + arcmsr_do_interrupt, 0, "arcmsr", acb)) { + pr_warn("arcmsr%d: request_irq =%d failed!\n", + acb->host->host_no, entries[i].vector); + for (j = 0 ; j < i ; j++) + free_irq(entries[j].vector, acb); + pci_disable_msix(pdev); + goto msi_int; + } + acb->entries[i] = entries[i]; + } + acb->acb_flags |= ACB_F_MSIX_ENABLED; + pr_info("arcmsr%d: msi-x enabled\n", acb->host->host_no); + return SUCCESS; +msi_int: + if (pci_enable_msi_exact(pdev, 1) < 0) + goto legacy_int; + if (request_irq(pdev->irq, arcmsr_do_interrupt, + IRQF_SHARED, "arcmsr", acb)) { + pr_warn("arcmsr%d: request_irq =%d failed!\n", + acb->host->host_no, pdev->irq); + pci_disable_msi(pdev); + goto legacy_int; + } + acb->acb_flags |= ACB_F_MSI_ENABLED; + pr_info("arcmsr%d: msi enabled\n", acb->host->host_no); + return SUCCESS; +legacy_int: + if (request_irq(pdev->irq, arcmsr_do_interrupt, + IRQF_SHARED, "arcmsr", acb)) { + pr_warn("arcmsr%d: request_irq = %d failed!\n", + acb->host->host_no, pdev->irq); + return FAILED; } + return SUCCESS; } static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) @@ -637,7 +721,7 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) host->max_lun = ARCMSR_MAX_TARGETLUN; host->max_id = ARCMSR_MAX_TARGETID; /*16:8*/ host->max_cmd_len = 16; /*this is issue of 64bit LBA ,over 2T byte*/ - host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ + host->can_queue = ARCMSR_MAX_OUTSTANDING_CMD; host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; host->this_id = ARCMSR_SCSI_INITIATOR_ID; host->unique_id = (bus << 8) | dev_fun; @@ -649,12 +733,16 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) } spin_lock_init(&acb->eh_lock); spin_lock_init(&acb->ccblist_lock); + spin_lock_init(&acb->postq_lock); + spin_lock_init(&acb->doneq_lock); + spin_lock_init(&acb->rqbuffer_lock); + spin_lock_init(&acb->wqbuffer_lock); acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; INIT_LIST_HEAD(&acb->ccb_free_list); - arcmsr_define_adapter_type(acb); + acb->adapter_type = id->driver_data; error = arcmsr_remap_pciregion(acb); if(!error){ goto pci_release_regs; @@ -667,17 +755,13 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) if(error){ goto free_hbb_mu; } - arcmsr_iop_init(acb); error = scsi_add_host(host, &pdev->dev); if(error){ - goto RAID_controller_stop; + goto free_ccb_pool; } - error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb); - if(error){ + if (arcmsr_request_irq(pdev, acb) == FAILED) goto scsi_host_remove; - } - host->irq = pdev->irq; - scsi_scan_host(host); + arcmsr_iop_init(acb); INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); atomic_set(&acb->rq_map_token, 16); atomic_set(&acb->ante_token_value, 16); @@ -689,16 +773,20 @@ static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) add_timer(&acb->eternal_timer); if(arcmsr_alloc_sysfs_attr(acb)) goto out_free_sysfs; + scsi_scan_host(host); return 0; out_free_sysfs: -scsi_host_remove: - scsi_remove_host(host); -RAID_controller_stop: + del_timer_sync(&acb->eternal_timer); + flush_work(&acb->arcmsr_do_message_isr_bh); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); + arcmsr_free_irq(pdev, acb); +scsi_host_remove: + scsi_remove_host(host); +free_ccb_pool: arcmsr_free_ccb_pool(acb); free_hbb_mu: - arcmsr_free_hbb_mu(acb); + arcmsr_free_mu(acb); unmap_pci_region: arcmsr_unmap_pciregion(acb); pci_release_regs: @@ -710,75 +798,169 @@ pci_disable_dev: return -ENODEV; } -static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) +static void arcmsr_free_irq(struct pci_dev *pdev, + struct AdapterControlBlock *acb) +{ + int i; + + if (acb->acb_flags & ACB_F_MSI_ENABLED) { + free_irq(pdev->irq, acb); + pci_disable_msi(pdev); + } else if (acb->acb_flags & ACB_F_MSIX_ENABLED) { + for (i = 0; i < acb->msix_vector_count; i++) + free_irq(acb->entries[i].vector, acb); + pci_disable_msix(pdev); + } else + free_irq(pdev->irq, acb); +} + +static int arcmsr_suspend(struct pci_dev *pdev, pm_message_t state) +{ + uint32_t intmask_org; + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct AdapterControlBlock *acb = + (struct AdapterControlBlock *)host->hostdata; + + intmask_org = arcmsr_disable_outbound_ints(acb); + arcmsr_free_irq(pdev, acb); + del_timer_sync(&acb->eternal_timer); + flush_work(&acb->arcmsr_do_message_isr_bh); + arcmsr_stop_adapter_bgrb(acb); + arcmsr_flush_adapter_cache(acb); + pci_set_drvdata(pdev, host); + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + return 0; +} + +static int arcmsr_resume(struct pci_dev *pdev) +{ + int error; + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct AdapterControlBlock *acb = + (struct AdapterControlBlock *)host->hostdata; + + pci_set_power_state(pdev, PCI_D0); + pci_enable_wake(pdev, PCI_D0, 0); + pci_restore_state(pdev); + if (pci_enable_device(pdev)) { + pr_warn("%s: pci_enable_device error\n", __func__); + return -ENODEV; + } + error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (error) { + error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (error) { + pr_warn("scsi%d: No suitable DMA mask available\n", + host->host_no); + goto controller_unregister; + } + } + pci_set_master(pdev); + if (arcmsr_request_irq(pdev, acb) == FAILED) + goto controller_stop; + arcmsr_iop_init(acb); + INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); + atomic_set(&acb->rq_map_token, 16); + atomic_set(&acb->ante_token_value, 16); + acb->fw_flag = FW_NORMAL; + init_timer(&acb->eternal_timer); + acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ); + acb->eternal_timer.data = (unsigned long) acb; + acb->eternal_timer.function = &arcmsr_request_device_map; + add_timer(&acb->eternal_timer); + return 0; +controller_stop: + arcmsr_stop_adapter_bgrb(acb); + arcmsr_flush_adapter_cache(acb); +controller_unregister: + scsi_remove_host(host); + arcmsr_free_ccb_pool(acb); + arcmsr_unmap_pciregion(acb); + pci_release_regions(pdev); + scsi_host_put(host); + pci_disable_device(pdev); + return -ENODEV; +} + +static uint8_t arcmsr_hbaA_abort_allcmd(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hbaA_wait_msgint_ready(acb)) { printk(KERN_NOTICE - "arcmsr%d: wait 'abort all outstanding command' timeout \n" + "arcmsr%d: wait 'abort all outstanding command' timeout\n" , acb->host->host_no); return false; } return true; } -static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) +static uint8_t arcmsr_hbaB_abort_allcmd(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbaB_wait_msgint_ready(acb)) { printk(KERN_NOTICE - "arcmsr%d: wait 'abort all outstanding command' timeout \n" + "arcmsr%d: wait 'abort all outstanding command' timeout\n" , acb->host->host_no); return false; } return true; } -static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB) +static uint8_t arcmsr_hbaC_abort_allcmd(struct AdapterControlBlock *pACB) { - struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; + struct MessageUnit_C __iomem *reg = pACB->pmuC; writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); - if (!arcmsr_hbc_wait_msgint_ready(pACB)) { + if (!arcmsr_hbaC_wait_msgint_ready(pACB)) { printk(KERN_NOTICE - "arcmsr%d: wait 'abort all outstanding command' timeout \n" + "arcmsr%d: wait 'abort all outstanding command' timeout\n" , pACB->host->host_no); return false; } 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; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { - rtnval = arcmsr_abort_hba_allcmd(acb); + rtnval = arcmsr_hbaA_abort_allcmd(acb); } break; case ACB_ADAPTER_TYPE_B: { - rtnval = arcmsr_abort_hbb_allcmd(acb); + rtnval = arcmsr_hbaB_abort_allcmd(acb); } break; case ACB_ADAPTER_TYPE_C: { - rtnval = arcmsr_abort_hbc_allcmd(acb); + rtnval = arcmsr_hbaC_abort_allcmd(acb); } - } - return rtnval; -} + break; -static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb) -{ - struct MessageUnit_B *reg = pacb->pmuB; - writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(pacb)) { - printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no); - return false; + case ACB_ADAPTER_TYPE_D: + rtnval = arcmsr_hbaD_abort_allcmd(acb); + break; } - return true; + return rtnval; } static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) @@ -837,12 +1019,18 @@ static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) } break; case ACB_ADAPTER_TYPE_C:{ - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + struct MessageUnit_C __iomem *reg = acb->pmuC; /* disable all outbound interrupt */ orig_mask = readl(®->host_int_mask); /* disable outbound message0 int */ writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->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; } @@ -933,7 +1121,7 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct Comma static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) { int i = 0; - uint32_t flag_ccb; + uint32_t flag_ccb, ccb_cdb_phy; struct ARCMSR_CDB *pARCMSR_CDB; bool error; struct CommandControlBlock *pCCB; @@ -961,8 +1149,9 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) /*clear all outbound posted Q*/ writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); /* clear doorbell interrupt */ for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { - if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) { - writel(0, ®->done_qbuffer[i]); + flag_ccb = reg->done_qbuffer[i]; + if (flag_ccb != 0) { + reg->done_qbuffer[i] = 0; pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; @@ -975,11 +1164,7 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) } break; case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = acb->pmuC; - struct ARCMSR_CDB *pARCMSR_CDB; - uint32_t flag_ccb, ccb_cdb_phy; - bool error; - struct CommandControlBlock *pCCB; + struct MessageUnit_C __iomem *reg = acb->pmuC; while ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { /*need to do*/ flag_ccb = readl(®->outbound_queueport_low); @@ -989,9 +1174,54 @@ static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; arcmsr_drain_donequeue(acb, pCCB, error); } - } + } + break; + case ACB_ADAPTER_TYPE_D: { + struct MessageUnit_D *pmu = acb->pmuD; + uint32_t outbound_write_pointer; + uint32_t doneq_index, index_stripped, addressLow, residual, toggle; + unsigned long flags; + + residual = atomic_read(&acb->ccboutstandingcount); + for (i = 0; i < residual; i++) { + spin_lock_irqsave(&acb->doneq_lock, flags); + outbound_write_pointer = + pmu->done_qbuffer[0].addressLow + 1; + doneq_index = pmu->doneq_index; + if ((doneq_index & 0xFFF) != + (outbound_write_pointer & 0xFFF)) { + toggle = doneq_index & 0x4000; + index_stripped = (doneq_index & 0xFFF) + 1; + index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE; + pmu->doneq_index = index_stripped ? (index_stripped | toggle) : + ((toggle ^ 0x4000) + 1); + doneq_index = pmu->doneq_index; + spin_unlock_irqrestore(&acb->doneq_lock, flags); + 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); + } else { + spin_unlock_irqrestore(&acb->doneq_lock, flags); + mdelay(10); + } + } + pmu->postq_index = 0; + pmu->doneq_index = 0x40FF; + } + break; } } + static void arcmsr_remove(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); @@ -1029,9 +1259,9 @@ static void arcmsr_remove(struct pci_dev *pdev) } } } - free_irq(pdev->irq, acb); + arcmsr_free_irq(pdev, acb); arcmsr_free_ccb_pool(acb); - arcmsr_free_hbb_mu(acb); + arcmsr_free_mu(acb); arcmsr_unmap_pciregion(acb); pci_release_regions(pdev); scsi_host_put(host); @@ -1045,6 +1275,7 @@ static void arcmsr_shutdown(struct pci_dev *pdev) (struct AdapterControlBlock *)host->hostdata; del_timer_sync(&acb->eternal_timer); arcmsr_disable_outbound_ints(acb); + arcmsr_free_irq(pdev, acb); flush_work(&acb->arcmsr_do_message_isr_bh); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); @@ -1091,11 +1322,19 @@ static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, } break; case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = acb->pmuC; + struct MessageUnit_C __iomem *reg = acb->pmuC; mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK); writel(intmask_org & mask, ®->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; + } } } @@ -1115,7 +1354,7 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, arcmsr_cdb->TargetID = pcmd->device->id; arcmsr_cdb->LUN = pcmd->device->lun; arcmsr_cdb->Function = 1; - arcmsr_cdb->Context = 0; + arcmsr_cdb->msgContext = 0; memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); nseg = scsi_dma_map(pcmd); @@ -1156,7 +1395,7 @@ static int arcmsr_build_ccb(struct AdapterControlBlock *acb, static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) { - uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern; + uint32_t cdb_phyaddr = ccb->cdb_phyaddr; struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; atomic_inc(&acb->ccboutstandingcount); ccb->startdone = ARCMSR_CCB_START; @@ -1165,25 +1404,24 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr struct MessageUnit_A __iomem *reg = acb->pmuA; if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) - writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, + writel(cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, ®->inbound_queueport); - else { - writel(cdb_phyaddr_pattern, ®->inbound_queueport); - } - } + else + writel(cdb_phyaddr, ®->inbound_queueport); break; + } case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; uint32_t ending_index, index = reg->postq_index; ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); - writel(0, ®->post_qbuffer[ending_index]); + reg->post_qbuffer[ending_index] = 0; if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { - writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ - ®->post_qbuffer[index]); + reg->post_qbuffer[index] = + cdb_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE; } else { - writel(cdb_phyaddr_pattern, ®->post_qbuffer[index]); + reg->post_qbuffer[index] = cdb_phyaddr; } index++; index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */ @@ -1192,11 +1430,11 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr } break; case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC; + struct MessageUnit_C __iomem *phbcmu = acb->pmuC; uint32_t ccb_post_stamp, arc_cdb_size; arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size; - ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1); + ccb_post_stamp = (cdb_phyaddr | ((arc_cdb_size - 1) >> 6) | 1); if (acb->cdb_phyaddr_hi32) { writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high); writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); @@ -1204,62 +1442,102 @@ static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandContr writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); } } + break; + case ACB_ADAPTER_TYPE_D: { + struct MessageUnit_D *pmu = acb->pmuD; + u16 index_stripped; + u16 postq_index, toggle; + 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); + toggle = postq_index & 0x4000; + index_stripped = postq_index + 1; + index_stripped &= (ARCMSR_MAX_ARC1214_POSTQUEUE - 1); + pmu->postq_index = index_stripped ? (index_stripped | toggle) : + (toggle ^ 0x4000); + writel(postq_index, pmu->inboundlist_write_pointer); + spin_unlock_irqrestore(&acb->postq_lock, flags); + break; + } } } -static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb) +static void arcmsr_hbaA_stop_bgrb(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hbaA_wait_msgint_ready(acb)) { printk(KERN_NOTICE - "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" + "arcmsr%d: wait 'stop adapter background rebulid' timeout\n" , acb->host->host_no); } } -static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb) +static void arcmsr_hbaB_stop_bgrb(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbaB_wait_msgint_ready(acb)) { printk(KERN_NOTICE - "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" + "arcmsr%d: wait 'stop adapter background rebulid' timeout\n" , acb->host->host_no); } } -static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB) +static void arcmsr_hbaC_stop_bgrb(struct AdapterControlBlock *pACB) { - struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; + struct MessageUnit_C __iomem *reg = pACB->pmuC; pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); - if (!arcmsr_hbc_wait_msgint_ready(pACB)) { + if (!arcmsr_hbaC_wait_msgint_ready(pACB)) { printk(KERN_NOTICE - "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" + "arcmsr%d: wait 'stop adapter background rebulid' timeout\n" , pACB->host->host_no); } 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) { case ACB_ADAPTER_TYPE_A: { - arcmsr_stop_hba_bgrb(acb); + arcmsr_hbaA_stop_bgrb(acb); } break; case ACB_ADAPTER_TYPE_B: { - arcmsr_stop_hbb_bgrb(acb); + arcmsr_hbaB_stop_bgrb(acb); } break; case ACB_ADAPTER_TYPE_C: { - arcmsr_stop_hbc_bgrb(acb); + arcmsr_hbaC_stop_bgrb(acb); } + break; + case ACB_ADAPTER_TYPE_D: + arcmsr_hbaD_stop_bgrb(acb); + break; } } @@ -1268,7 +1546,7 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); } -void arcmsr_iop_message_read(struct AdapterControlBlock *acb) +static void arcmsr_iop_message_read(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { @@ -1284,8 +1562,16 @@ void arcmsr_iop_message_read(struct AdapterControlBlock *acb) break; case ACB_ADAPTER_TYPE_C: { struct MessageUnit_C __iomem *reg = acb->pmuC; + writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->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; } } @@ -1320,6 +1606,12 @@ static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, ®->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; } } @@ -1340,9 +1632,15 @@ struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) } break; case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC; + 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; } @@ -1364,96 +1662,208 @@ static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBloc } break; case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + struct MessageUnit_C __iomem *reg = acb->pmuC; pqbuffer = (struct QBUFFER __iomem *)®->message_wbuffer; - } - + } + break; + case ACB_ADAPTER_TYPE_D: { + struct MessageUnit_D *reg = acb->pmuD; + pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer; + } + break; } return pqbuffer; } -static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) +static uint32_t +arcmsr_Read_iop_rqbuffer_in_DWORD(struct AdapterControlBlock *acb, + struct QBUFFER __iomem *prbuffer) { - struct QBUFFER __iomem *prbuffer; - struct QBUFFER *pQbuffer; - uint8_t __iomem *iop_data; - int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; - rqbuf_lastindex = acb->rqbuf_lastindex; - rqbuf_firstindex = acb->rqbuf_firstindex; - prbuffer = arcmsr_get_iop_rqbuffer(acb); - iop_data = (uint8_t __iomem *)prbuffer->data; - iop_len = prbuffer->data_len; - my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) & (ARCMSR_MAX_QBUFFER - 1); - - if (my_empty_len >= iop_len) - { - while (iop_len > 0) { - pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex]; - memcpy(pQbuffer, iop_data, 1); - rqbuf_lastindex++; - rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + uint8_t *pQbuffer; + uint8_t *buf1 = NULL; + uint32_t __iomem *iop_data; + uint32_t iop_len, data_len, *buf2 = NULL; + + iop_data = (uint32_t __iomem *)prbuffer->data; + iop_len = readl(&prbuffer->data_len); + if (iop_len > 0) { + buf1 = kmalloc(128, GFP_ATOMIC); + buf2 = (uint32_t *)buf1; + if (buf1 == NULL) + return 0; + data_len = iop_len; + while (data_len >= 4) { + *buf2++ = readl(iop_data); iop_data++; - iop_len--; + data_len -= 4; } - acb->rqbuf_lastindex = rqbuf_lastindex; - arcmsr_iop_message_read(acb); + if (data_len) + *buf2 = readl(iop_data); + buf2 = (uint32_t *)buf1; + } + while (iop_len > 0) { + pQbuffer = &acb->rqbuffer[acb->rqbuf_putIndex]; + *pQbuffer = *buf1; + acb->rqbuf_putIndex++; + /* if last, index number set it to 0 */ + acb->rqbuf_putIndex %= ARCMSR_MAX_QBUFFER; + buf1++; + iop_len--; } + kfree(buf2); + /* let IOP know data has been read */ + arcmsr_iop_message_read(acb); + return 1; +} + +uint32_t +arcmsr_Read_iop_rqbuffer_data(struct AdapterControlBlock *acb, + struct QBUFFER __iomem *prbuffer) { - else { + uint8_t *pQbuffer; + uint8_t __iomem *iop_data; + uint32_t iop_len; + + 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); + while (iop_len > 0) { + pQbuffer = &acb->rqbuffer[acb->rqbuf_putIndex]; + *pQbuffer = readb(iop_data); + acb->rqbuf_putIndex++; + acb->rqbuf_putIndex %= ARCMSR_MAX_QBUFFER; + iop_data++; + iop_len--; + } + arcmsr_iop_message_read(acb); + return 1; +} + +static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) +{ + unsigned long flags; + struct QBUFFER __iomem *prbuffer; + int32_t buf_empty_len; + + spin_lock_irqsave(&acb->rqbuffer_lock, flags); + prbuffer = arcmsr_get_iop_rqbuffer(acb); + buf_empty_len = (acb->rqbuf_putIndex - acb->rqbuf_getIndex - 1) & + (ARCMSR_MAX_QBUFFER - 1); + if (buf_empty_len >= readl(&prbuffer->data_len)) { + if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; + } else acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); +} + +static void arcmsr_write_ioctldata2iop_in_DWORD(struct AdapterControlBlock *acb) +{ + uint8_t *pQbuffer; + struct QBUFFER __iomem *pwbuffer; + uint8_t *buf1 = NULL; + uint32_t __iomem *iop_data; + uint32_t allxfer_len = 0, data_len, *buf2 = NULL, data; + + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { + buf1 = kmalloc(128, GFP_ATOMIC); + buf2 = (uint32_t *)buf1; + if (buf1 == NULL) + return; + + acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); + pwbuffer = arcmsr_get_iop_wqbuffer(acb); + iop_data = (uint32_t __iomem *)pwbuffer->data; + while ((acb->wqbuf_getIndex != acb->wqbuf_putIndex) + && (allxfer_len < 124)) { + pQbuffer = &acb->wqbuffer[acb->wqbuf_getIndex]; + *buf1 = *pQbuffer; + acb->wqbuf_getIndex++; + acb->wqbuf_getIndex %= ARCMSR_MAX_QBUFFER; + buf1++; + allxfer_len++; + } + data_len = allxfer_len; + buf1 = (uint8_t *)buf2; + while (data_len >= 4) { + data = *buf2++; + writel(data, iop_data); + iop_data++; + data_len -= 4; + } + if (data_len) { + data = *buf2; + writel(data, iop_data); + } + writel(allxfer_len, &pwbuffer->data_len); + kfree(buf1); + arcmsr_iop_message_wrote(acb); } } -static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) +void +arcmsr_write_ioctldata2iop(struct AdapterControlBlock *acb) { - acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; - if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { - uint8_t *pQbuffer; - struct QBUFFER __iomem *pwbuffer; - uint8_t __iomem *iop_data; - int32_t allxfer_len = 0; + uint8_t *pQbuffer; + struct QBUFFER __iomem *pwbuffer; + uint8_t __iomem *iop_data; + int32_t allxfer_len = 0; + if (acb->adapter_type & (ACB_ADAPTER_TYPE_C | ACB_ADAPTER_TYPE_D)) { + arcmsr_write_ioctldata2iop_in_DWORD(acb); + return; + } + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); pwbuffer = arcmsr_get_iop_wqbuffer(acb); iop_data = (uint8_t __iomem *)pwbuffer->data; - - while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \ - (allxfer_len < 124)) { - pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex]; - memcpy(iop_data, pQbuffer, 1); - acb->wqbuf_firstindex++; - acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + while ((acb->wqbuf_getIndex != acb->wqbuf_putIndex) + && (allxfer_len < 124)) { + pQbuffer = &acb->wqbuffer[acb->wqbuf_getIndex]; + writeb(*pQbuffer, iop_data); + acb->wqbuf_getIndex++; + acb->wqbuf_getIndex %= ARCMSR_MAX_QBUFFER; iop_data++; allxfer_len++; } - pwbuffer->data_len = allxfer_len; - + writel(allxfer_len, &pwbuffer->data_len); arcmsr_iop_message_wrote(acb); } +} - if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) { +static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) +{ + unsigned long flags; + + spin_lock_irqsave(&acb->wqbuffer_lock, flags); + acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; + if (acb->wqbuf_getIndex != acb->wqbuf_putIndex) + arcmsr_write_ioctldata2iop(acb); + if (acb->wqbuf_getIndex == acb->wqbuf_putIndex) acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; - } + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); } -static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb) +static void arcmsr_hbaA_doorbell_isr(struct AdapterControlBlock *acb) { uint32_t outbound_doorbell; struct MessageUnit_A __iomem *reg = acb->pmuA; outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell); - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { - arcmsr_iop2drv_data_wrote_handle(acb); - } - - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { - arcmsr_iop2drv_data_read_handle(acb); - } + do { + writel(outbound_doorbell, ®->outbound_doorbell); + if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) + arcmsr_iop2drv_data_wrote_handle(acb); + if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) + arcmsr_iop2drv_data_read_handle(acb); + outbound_doorbell = readl(®->outbound_doorbell); + } while (outbound_doorbell & (ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK + | ARCMSR_OUTBOUND_IOP331_DATA_READ_OK)); } -static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB) +static void arcmsr_hbaC_doorbell_isr(struct AdapterControlBlock *pACB) { uint32_t outbound_doorbell; - struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; + struct MessageUnit_C __iomem *reg = pACB->pmuC; /* ******************************************************************* ** Maybe here we need to check wrqbuffer_lock is lock or not @@ -1462,19 +1872,42 @@ static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB) ******************************************************************* */ outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell_clear);/*clear interrupt*/ - if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { - arcmsr_iop2drv_data_wrote_handle(pACB); - } - if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) { - arcmsr_iop2drv_data_read_handle(pACB); - } - if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { - arcmsr_hbc_message_isr(pACB); /* messenger of "driver to iop commands" */ - } - return; + do { + writel(outbound_doorbell, ®->outbound_doorbell_clear); + readl(®->outbound_doorbell_clear); + if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) + arcmsr_iop2drv_data_wrote_handle(pACB); + if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) + arcmsr_iop2drv_data_read_handle(pACB); + if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) + arcmsr_hbaC_message_isr(pACB); + outbound_doorbell = readl(®->outbound_doorbell); + } while (outbound_doorbell & (ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK + | ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK + | ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE)); } -static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) + +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; struct MessageUnit_A __iomem *reg = acb->pmuA; @@ -1488,7 +1921,7 @@ static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) arcmsr_drain_donequeue(acb, pCCB, error); } } -static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) +static void arcmsr_hbaB_postqueue_isr(struct AdapterControlBlock *acb) { uint32_t index; uint32_t flag_ccb; @@ -1497,8 +1930,8 @@ static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) struct CommandControlBlock *pCCB; bool error; index = reg->doneq_index; - while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) { - writel(0, ®->done_qbuffer[index]); + while ((flag_ccb = reg->done_qbuffer[index]) != 0) { + reg->done_qbuffer[index] = 0; pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; @@ -1509,35 +1942,80 @@ static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) } } -static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb) +static void arcmsr_hbaC_postqueue_isr(struct AdapterControlBlock *acb) { - struct MessageUnit_C *phbcmu; + struct MessageUnit_C __iomem *phbcmu; struct ARCMSR_CDB *arcmsr_cdb; struct CommandControlBlock *ccb; uint32_t flag_ccb, ccb_cdb_phy, throttling = 0; int error; - phbcmu = (struct MessageUnit_C *)acb->pmuC; + phbcmu = acb->pmuC; /* areca cdb command done */ /* Use correct offset and size for syncing */ - while (readl(&phbcmu->host_int_status) & - ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){ - /* check if command done with no error*/ - flag_ccb = readl(&phbcmu->outbound_queueport_low); - ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/ - arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); - ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; - /* check if command done with no error */ - arcmsr_drain_donequeue(acb, ccb, error); - if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) { - writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell); - break; - } - throttling++; + while ((flag_ccb = readl(&phbcmu->outbound_queueport_low)) != + 0xFFFFFFFF) { + ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); + arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + + ccb_cdb_phy); + ccb = container_of(arcmsr_cdb, struct CommandControlBlock, + arcmsr_cdb); + error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) + ? true : false; + /* check if command done with no error */ + arcmsr_drain_donequeue(acb, ccb, error); + throttling++; + if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) { + writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, + &phbcmu->inbound_doorbell); + throttling = 0; + } } } + +static void arcmsr_hbaD_postqueue_isr(struct AdapterControlBlock *acb) +{ + u32 outbound_write_pointer, doneq_index, index_stripped, toggle; + 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 { + toggle = doneq_index & 0x4000; + index_stripped = (doneq_index & 0xFFF) + 1; + index_stripped %= ARCMSR_MAX_ARC1214_DONEQUEUE; + pmu->doneq_index = index_stripped ? (index_stripped | toggle) : + ((toggle ^ 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 @@ -1546,14 +2024,14 @@ static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb) ** We want this in order to compare the drivemap so that we can detect newly-attached drives. ********************************************************************************** */ -static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb) +static void arcmsr_hbaA_message_isr(struct AdapterControlBlock *acb) { - struct MessageUnit_A *reg = acb->pmuA; + struct MessageUnit_A __iomem *reg = acb->pmuA; /*clear interrupt and message state*/ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, ®->outbound_intstatus); schedule_work(&acb->arcmsr_do_message_isr_bh); } -static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb) +static void arcmsr_hbaB_message_isr(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; @@ -1570,114 +2048,142 @@ static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb) ** We want this in order to compare the drivemap so that we can detect newly-attached drives. ********************************************************************************** */ -static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb) +static void arcmsr_hbaC_message_isr(struct AdapterControlBlock *acb) { - struct MessageUnit_C *reg = acb->pmuC; + struct MessageUnit_C __iomem *reg = acb->pmuC; /*clear interrupt and message state*/ writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear); schedule_work(&acb->arcmsr_do_message_isr_bh); } -static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb) +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; struct MessageUnit_A __iomem *reg = acb->pmuA; outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; - if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) { - return 1; - } - writel(outbound_intstatus, ®->outbound_intstatus); - if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { - arcmsr_hba_doorbell_isr(acb); - } - if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { - arcmsr_hba_postqueue_isr(acb); - } - if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - /* messenger of "driver to iop commands" */ - arcmsr_hba_message_isr(acb); - } - return 0; + if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) + return IRQ_NONE; + do { + writel(outbound_intstatus, ®->outbound_intstatus); + if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) + arcmsr_hbaA_doorbell_isr(acb); + if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) + arcmsr_hbaA_postqueue_isr(acb); + if (outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) + arcmsr_hbaA_message_isr(acb); + outbound_intstatus = readl(®->outbound_intstatus) & + acb->outbound_int_enable; + } while (outbound_intstatus & (ARCMSR_MU_OUTBOUND_DOORBELL_INT + | ARCMSR_MU_OUTBOUND_POSTQUEUE_INT + | ARCMSR_MU_OUTBOUND_MESSAGE0_INT)); + return IRQ_HANDLED; } -static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) +static int arcmsr_hbaB_handle_isr(struct AdapterControlBlock *acb) { uint32_t outbound_doorbell; struct MessageUnit_B *reg = acb->pmuB; outbound_doorbell = readl(reg->iop2drv_doorbell) & acb->outbound_int_enable; if (!outbound_doorbell) - return 1; - - writel(~outbound_doorbell, reg->iop2drv_doorbell); - /*in case the last action of doorbell interrupt clearance is cached, - this action can push HW to write down the clear bit*/ - readl(reg->iop2drv_doorbell); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); - if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { - arcmsr_iop2drv_data_wrote_handle(acb); - } - if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { - arcmsr_iop2drv_data_read_handle(acb); - } - if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { - arcmsr_hbb_postqueue_isr(acb); - } - if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { - /* messenger of "driver to iop commands" */ - arcmsr_hbb_message_isr(acb); - } - return 0; + return IRQ_NONE; + do { + writel(~outbound_doorbell, reg->iop2drv_doorbell); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); + if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) + arcmsr_iop2drv_data_wrote_handle(acb); + if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) + arcmsr_iop2drv_data_read_handle(acb); + if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) + arcmsr_hbaB_postqueue_isr(acb); + if (outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) + arcmsr_hbaB_message_isr(acb); + outbound_doorbell = readl(reg->iop2drv_doorbell) & + acb->outbound_int_enable; + } while (outbound_doorbell & (ARCMSR_IOP2DRV_DATA_WRITE_OK + | ARCMSR_IOP2DRV_DATA_READ_OK + | ARCMSR_IOP2DRV_CDB_DONE + | ARCMSR_IOP2DRV_MESSAGE_CMD_DONE)); + return IRQ_HANDLED; } -static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB) +static int arcmsr_hbaC_handle_isr(struct AdapterControlBlock *pACB) { uint32_t host_interrupt_status; - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; + struct MessageUnit_C __iomem *phbcmu = pACB->pmuC; /* ********************************************* ** check outbound intstatus ********************************************* */ - host_interrupt_status = readl(&phbcmu->host_int_status); - if (!host_interrupt_status) { - /*it must be share irq*/ - return 1; - } - /* MU ioctl transfer doorbell interrupts*/ - if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) { - arcmsr_hbc_doorbell_isr(pACB); /* messenger of "ioctl message read write" */ - } - /* MU post queue interrupts*/ - if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) { - arcmsr_hbc_postqueue_isr(pACB); /* messenger of "scsi commands" */ - } - return 0; + host_interrupt_status = readl(&phbcmu->host_int_status) & + (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR | + ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR); + if (!host_interrupt_status) + return IRQ_NONE; + do { + if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) + arcmsr_hbaC_doorbell_isr(pACB); + /* MU post queue interrupts*/ + if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) + arcmsr_hbaC_postqueue_isr(pACB); + host_interrupt_status = readl(&phbcmu->host_int_status); + } while (host_interrupt_status & (ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR | + 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) { - case ACB_ADAPTER_TYPE_A: { - if (arcmsr_handle_hba_isr(acb)) { - return IRQ_NONE; - } - } + case ACB_ADAPTER_TYPE_A: + return arcmsr_hbaA_handle_isr(acb); break; - - case ACB_ADAPTER_TYPE_B: { - if (arcmsr_handle_hbb_isr(acb)) { - return IRQ_NONE; - } - } + case ACB_ADAPTER_TYPE_B: + return arcmsr_hbaB_handle_isr(acb); break; - case ACB_ADAPTER_TYPE_C: { - if (arcmsr_handle_hbc_isr(acb)) { - return IRQ_NONE; - } - } + case ACB_ADAPTER_TYPE_C: + return arcmsr_hbaC_handle_isr(acb); + case ACB_ADAPTER_TYPE_D: + return arcmsr_hbaD_handle_isr(acb); + default: + return IRQ_NONE; } - return IRQ_HANDLED; } static void arcmsr_iop_parking(struct AdapterControlBlock *acb) @@ -1695,296 +2201,273 @@ static void arcmsr_iop_parking(struct AdapterControlBlock *acb) } } -void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb) + +void arcmsr_clear_iop2drv_rqueue_buffer(struct AdapterControlBlock *acb) { - int32_t wqbuf_firstindex, wqbuf_lastindex; - uint8_t *pQbuffer; - struct QBUFFER __iomem *pwbuffer; - uint8_t __iomem *iop_data; - int32_t allxfer_len = 0; - pwbuffer = arcmsr_get_iop_wqbuffer(acb); - iop_data = (uint8_t __iomem *)pwbuffer->data; - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { - acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); - wqbuf_firstindex = acb->wqbuf_firstindex; - wqbuf_lastindex = acb->wqbuf_lastindex; - while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) { - pQbuffer = &acb->wqbuffer[wqbuf_firstindex]; - memcpy(iop_data, pQbuffer, 1); - wqbuf_firstindex++; - wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - allxfer_len++; + uint32_t i; + + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + for (i = 0; i < 15; i++) { + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + acb->rqbuf_getIndex = 0; + acb->rqbuf_putIndex = 0; + arcmsr_iop_message_read(acb); + mdelay(30); + } else if (acb->rqbuf_getIndex != + acb->rqbuf_putIndex) { + acb->rqbuf_getIndex = 0; + acb->rqbuf_putIndex = 0; + mdelay(30); + } else + break; } - acb->wqbuf_firstindex = wqbuf_firstindex; - pwbuffer->data_len = allxfer_len; - arcmsr_iop_message_wrote(acb); } } static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, - struct scsi_cmnd *cmd) + struct scsi_cmnd *cmd) { - struct CMD_MESSAGE_FIELD *pcmdmessagefld; - int retvalue = 0, transfer_len = 0; char *buffer; + unsigned short use_sg; + int retvalue = 0, transfer_len = 0; + unsigned long flags; + struct CMD_MESSAGE_FIELD *pcmdmessagefld; + uint32_t controlcode = (uint32_t)cmd->cmnd[5] << 24 | + (uint32_t)cmd->cmnd[6] << 16 | + (uint32_t)cmd->cmnd[7] << 8 | + (uint32_t)cmd->cmnd[8]; struct scatterlist *sg; - uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 | - (uint32_t ) cmd->cmnd[6] << 16 | - (uint32_t ) cmd->cmnd[7] << 8 | - (uint32_t ) cmd->cmnd[8]; - /* 4 bytes: Areca io control code */ + + use_sg = scsi_sg_count(cmd); sg = scsi_sglist(cmd); buffer = kmap_atomic(sg_page(sg)) + sg->offset; - if (scsi_sg_count(cmd) > 1) { + if (use_sg > 1) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } transfer_len += sg->length; - if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) { retvalue = ARCMSR_MESSAGE_FAIL; + pr_info("%s: ARCMSR_MESSAGE_FAIL!\n", __func__); goto message_out; } - pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer; - switch(controlcode) { - + pcmdmessagefld = (struct CMD_MESSAGE_FIELD *)buffer; + switch (controlcode) { case ARCMSR_MESSAGE_READ_RQBUFFER: { unsigned char *ver_addr; - uint8_t *pQbuffer, *ptmpQbuffer; - int32_t allxfer_len = 0; - - ver_addr = kmalloc(1032, GFP_ATOMIC); + uint8_t *ptmpQbuffer; + uint32_t allxfer_len = 0; + ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC); if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; + pr_info("%s: memory not enough!\n", __func__); goto message_out; } - ptmpQbuffer = ver_addr; - while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) - && (allxfer_len < 1031)) { - pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; - memcpy(ptmpQbuffer, pQbuffer, 1); - acb->rqbuf_firstindex++; - acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - ptmpQbuffer++; - allxfer_len++; + spin_lock_irqsave(&acb->rqbuffer_lock, flags); + if (acb->rqbuf_getIndex != acb->rqbuf_putIndex) { + unsigned int tail = acb->rqbuf_getIndex; + unsigned int head = acb->rqbuf_putIndex; + unsigned int cnt_to_end = CIRC_CNT_TO_END(head, tail, ARCMSR_MAX_QBUFFER); + + allxfer_len = CIRC_CNT(head, tail, ARCMSR_MAX_QBUFFER); + if (allxfer_len > ARCMSR_API_DATA_BUFLEN) + allxfer_len = ARCMSR_API_DATA_BUFLEN; + + if (allxfer_len <= cnt_to_end) + memcpy(ptmpQbuffer, acb->rqbuffer + tail, allxfer_len); + else { + memcpy(ptmpQbuffer, acb->rqbuffer + tail, cnt_to_end); + memcpy(ptmpQbuffer + cnt_to_end, acb->rqbuffer, allxfer_len - cnt_to_end); + } + acb->rqbuf_getIndex = (acb->rqbuf_getIndex + allxfer_len) % ARCMSR_MAX_QBUFFER; } + memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, + allxfer_len); if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - struct QBUFFER __iomem *prbuffer; - uint8_t __iomem *iop_data; - int32_t iop_len; - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; prbuffer = arcmsr_get_iop_rqbuffer(acb); - iop_data = prbuffer->data; - iop_len = readl(&prbuffer->data_len); - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; - } - arcmsr_iop_message_read(acb); - } - memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len); - pcmdmessagefld->cmdmessage.Length = allxfer_len; - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0) + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; } + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); kfree(ver_addr); - } + pcmdmessagefld->cmdmessage.Length = allxfer_len; + if (acb->fw_flag == FW_DEADLOCK) + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + else + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; break; - + } case ARCMSR_MESSAGE_WRITE_WQBUFFER: { unsigned char *ver_addr; - int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; + int32_t user_len, cnt2end; uint8_t *pQbuffer, *ptmpuserbuffer; - - ver_addr = kmalloc(1032, GFP_ATOMIC); + ver_addr = kmalloc(ARCMSR_API_DATA_BUFLEN, GFP_ATOMIC); if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } ptmpuserbuffer = ver_addr; user_len = pcmdmessagefld->cmdmessage.Length; - memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); - wqbuf_lastindex = acb->wqbuf_lastindex; - wqbuf_firstindex = acb->wqbuf_firstindex; - if (wqbuf_lastindex != wqbuf_firstindex) { + memcpy(ptmpuserbuffer, + pcmdmessagefld->messagedatabuffer, user_len); + spin_lock_irqsave(&acb->wqbuffer_lock, flags); + if (acb->wqbuf_putIndex != acb->wqbuf_getIndex) { struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)cmd->sense_buffer; - arcmsr_post_ioctldata2iop(acb); + arcmsr_write_ioctldata2iop(acb); /* has error report sensedata */ - sensebuffer->ErrorCode = 0x70; + sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; sensebuffer->SenseKey = ILLEGAL_REQUEST; sensebuffer->AdditionalSenseLength = 0x0A; sensebuffer->AdditionalSenseCode = 0x20; sensebuffer->Valid = 1; retvalue = ARCMSR_MESSAGE_FAIL; } else { - my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) - &(ARCMSR_MAX_QBUFFER - 1); - if (my_empty_len >= user_len) { - while (user_len > 0) { - pQbuffer = - &acb->wqbuffer[acb->wqbuf_lastindex]; - memcpy(pQbuffer, ptmpuserbuffer, 1); - acb->wqbuf_lastindex++; - acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - ptmpuserbuffer++; - user_len--; - } - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { - acb->acb_flags &= - ~ACB_F_MESSAGE_WQBUFFER_CLEARED; - arcmsr_post_ioctldata2iop(acb); - } - } else { - /* has error report sensedata */ - struct SENSE_DATA *sensebuffer = - (struct SENSE_DATA *)cmd->sense_buffer; - sensebuffer->ErrorCode = 0x70; - sensebuffer->SenseKey = ILLEGAL_REQUEST; - sensebuffer->AdditionalSenseLength = 0x0A; - sensebuffer->AdditionalSenseCode = 0x20; - sensebuffer->Valid = 1; - retvalue = ARCMSR_MESSAGE_FAIL; + pQbuffer = &acb->wqbuffer[acb->wqbuf_putIndex]; + cnt2end = ARCMSR_MAX_QBUFFER - acb->wqbuf_putIndex; + if (user_len > cnt2end) { + memcpy(pQbuffer, ptmpuserbuffer, cnt2end); + ptmpuserbuffer += cnt2end; + user_len -= cnt2end; + acb->wqbuf_putIndex = 0; + pQbuffer = acb->wqbuffer; } + memcpy(pQbuffer, ptmpuserbuffer, user_len); + acb->wqbuf_putIndex += user_len; + acb->wqbuf_putIndex %= ARCMSR_MAX_QBUFFER; + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { + acb->acb_flags &= + ~ACB_F_MESSAGE_WQBUFFER_CLEARED; + arcmsr_write_ioctldata2iop(acb); } - kfree(ver_addr); } + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); + kfree(ver_addr); + if (acb->fw_flag == FW_DEADLOCK) + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + else + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; break; - + } case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { uint8_t *pQbuffer = acb->rqbuffer; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - arcmsr_iop_message_read(acb); - } + + arcmsr_clear_iop2drv_rqueue_buffer(acb); + spin_lock_irqsave(&acb->rqbuffer_lock, flags); acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; + acb->rqbuf_getIndex = 0; + acb->rqbuf_putIndex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - if(acb->fw_flag == FW_DEADLOCK) { + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); + if (acb->fw_flag == FW_DEADLOCK) pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + else pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } - } + ARCMSR_MESSAGE_RETURNCODE_OK; break; - + } case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { uint8_t *pQbuffer = acb->wqbuffer; - if(acb->fw_flag == FW_DEADLOCK) { + spin_lock_irqsave(&acb->wqbuffer_lock, flags); + acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | + ACB_F_MESSAGE_WQBUFFER_READED); + acb->wqbuf_getIndex = 0; + acb->wqbuf_putIndex = 0; + memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); + if (acb->fw_flag == FW_DEADLOCK) pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + else pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } - - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - arcmsr_iop_message_read(acb); - } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED | - ACB_F_MESSAGE_WQBUFFER_READED); - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; - memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - } + ARCMSR_MESSAGE_RETURNCODE_OK; break; - + } case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { uint8_t *pQbuffer; - - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - arcmsr_iop_message_read(acb); - } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED - | ACB_F_MESSAGE_RQBUFFER_CLEARED - | ACB_F_MESSAGE_WQBUFFER_READED); - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; + arcmsr_clear_iop2drv_rqueue_buffer(acb); + spin_lock_irqsave(&acb->rqbuffer_lock, flags); + acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; + acb->rqbuf_getIndex = 0; + acb->rqbuf_putIndex = 0; pQbuffer = acb->rqbuffer; memset(pQbuffer, 0, sizeof(struct QBUFFER)); + spin_unlock_irqrestore(&acb->rqbuffer_lock, flags); + spin_lock_irqsave(&acb->wqbuffer_lock, flags); + acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | + ACB_F_MESSAGE_WQBUFFER_READED); + acb->wqbuf_getIndex = 0; + acb->wqbuf_putIndex = 0; pQbuffer = acb->wqbuffer; memset(pQbuffer, 0, sizeof(struct QBUFFER)); - if(acb->fw_flag == FW_DEADLOCK) { + spin_unlock_irqrestore(&acb->wqbuffer_lock, flags); + if (acb->fw_flag == FW_DEADLOCK) pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + else pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } - } + ARCMSR_MESSAGE_RETURNCODE_OK; break; - + } case ARCMSR_MESSAGE_RETURN_CODE_3F: { - if(acb->fw_flag == FW_DEADLOCK) { + if (acb->fw_flag == FW_DEADLOCK) pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + else pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_3F; - } + ARCMSR_MESSAGE_RETURNCODE_3F; break; - } + } case ARCMSR_MESSAGE_SAY_HELLO: { int8_t *hello_string = "Hello! I am ARCMSR"; - if(acb->fw_flag == FW_DEADLOCK) { + if (acb->fw_flag == FW_DEADLOCK) pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + else pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } - memcpy(pcmdmessagefld->messagedatabuffer, hello_string - , (int16_t)strlen(hello_string)); - } + ARCMSR_MESSAGE_RETURNCODE_OK; + memcpy(pcmdmessagefld->messagedatabuffer, + hello_string, (int16_t)strlen(hello_string)); break; - - case ARCMSR_MESSAGE_SAY_GOODBYE: - if(acb->fw_flag == FW_DEADLOCK) { + } + case ARCMSR_MESSAGE_SAY_GOODBYE: { + if (acb->fw_flag == FW_DEADLOCK) pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + else + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; arcmsr_iop_parking(acb); break; - - case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: - if(acb->fw_flag == FW_DEADLOCK) { + } + case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: { + if (acb->fw_flag == FW_DEADLOCK) pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } + ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; + else + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; arcmsr_flush_adapter_cache(acb); break; - + } default: retvalue = ARCMSR_MESSAGE_FAIL; + pr_info("%s: unknown controlcode!\n", __func__); + } +message_out: + if (use_sg) { + struct scatterlist *sg = scsi_sglist(cmd); + kunmap_atomic(buffer - sg->offset); } - message_out: - sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset); return retvalue; } @@ -1999,7 +2482,7 @@ static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock list_del_init(&ccb->list); }else{ spin_unlock_irqrestore(&acb->ccblist_lock, flags); - return 0; + return NULL; } spin_unlock_irqrestore(&acb->ccblist_lock, flags); return ccb; @@ -2079,9 +2562,6 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd, arcmsr_handle_virtual_command(acb, cmd); return 0; } - if (atomic_read(&acb->ccboutstandingcount) >= - ARCMSR_MAX_OUTSTANDING_CMD) - return SCSI_MLQUEUE_HOST_BUSY; ccb = arcmsr_get_freeccb(acb); if (!ccb) return SCSI_MLQUEUE_HOST_BUSY; @@ -2096,7 +2576,7 @@ static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd, static DEF_SCSI_QCMD(arcmsr_queue_command) -static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb) +static bool arcmsr_hbaA_get_config(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; char *acb_firm_model = acb->firm_model; @@ -2107,7 +2587,7 @@ static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb) char __iomem *iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); int count; writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hbaA_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ miscellaneous data' timeout \n", acb->host->host_no); return false; @@ -2135,10 +2615,10 @@ static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb) iop_device_map++; count--; } - printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", + pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n", acb->host->host_no, - acb->firm_version, - acb->firm_model); + acb->firm_model, + acb->firm_version); acb->signature = readl(®->message_rwbuffer[0]); acb->firm_request_len = readl(®->message_rwbuffer[1]); acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); @@ -2147,7 +2627,7 @@ static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb) acb->firm_cfg_version = readl(®->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ return true; } -static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) +static bool arcmsr_hbaB_get_config(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; struct pci_dev *pdev = acb->pdev; @@ -2163,12 +2643,18 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) char __iomem *iop_device_map; /*firm_version,21,84-99*/ int count; - dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL); + + acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_B), 32); + dma_coherent = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize, + &dma_coherent_handle, GFP_KERNEL); if (!dma_coherent){ - printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no); + printk(KERN_NOTICE + "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", + acb->host->host_no); return false; } - acb->dma_coherent_handle_hbb_mu = dma_coherent_handle; + acb->dma_coherent_handle2 = dma_coherent_handle; + acb->dma_coherent2 = dma_coherent; reg = (struct MessageUnit_B *)dma_coherent; acb->pmuB = reg; reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL); @@ -2183,7 +2669,7 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); /*firm_version,21,84-99*/ writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbaB_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ miscellaneous data' timeout \n", acb->host->host_no); return false; @@ -2211,10 +2697,10 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) count--; } - printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", + pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n", acb->host->host_no, - acb->firm_version, - acb->firm_model); + acb->firm_model, + acb->firm_version); acb->signature = readl(®->message_rwbuffer[1]); /*firm_signature,1,00-03*/ @@ -2231,14 +2717,14 @@ static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) return true; } -static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB) +static bool arcmsr_hbaC_get_config(struct AdapterControlBlock *pACB) { uint32_t intmask_org, Index, firmware_state = 0; - struct MessageUnit_C *reg = pACB->pmuC; + struct MessageUnit_C __iomem *reg = pACB->pmuC; char *acb_firm_model = pACB->firm_model; char *acb_firm_version = pACB->firm_version; - char *iop_firm_model = (char *)(®->msgcode_rwbuffer[15]); /*firm_model,15,60-67*/ - char *iop_firm_version = (char *)(®->msgcode_rwbuffer[17]); /*firm_version,17,68-83*/ + char __iomem *iop_firm_model = (char __iomem *)(®->msgcode_rwbuffer[15]); /*firm_model,15,60-67*/ + char __iomem *iop_firm_version = (char __iomem *)(®->msgcode_rwbuffer[17]); /*firm_version,17,68-83*/ int count; /* disable all outbound interrupt */ intmask_org = readl(®->host_int_mask); /* disable outbound message0 int */ @@ -2277,10 +2763,10 @@ static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB) iop_firm_version++; count--; } - printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", + pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n", pACB->host->host_no, - pACB->firm_version, - pACB->firm_model); + pACB->firm_model, + pACB->firm_version); pACB->firm_request_len = readl(®->msgcode_rwbuffer[1]); /*firm_request_len,1,04-07*/ pACB->firm_numbers_queue = readl(®->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/ pACB->firm_sdram_size = readl(®->msgcode_rwbuffer[3]); /*firm_sdram_size,3,12-15*/ @@ -2289,17 +2775,166 @@ static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB) /*all interrupt service will be enable at arcmsr_iop_init*/ return true; } + +static bool arcmsr_hbaD_get_config(struct AdapterControlBlock *acb) +{ + char *acb_firm_model = acb->firm_model; + char *acb_firm_version = acb->firm_version; + char *acb_device_map = acb->device_map; + char __iomem *iop_firm_model; + char __iomem *iop_firm_version; + char __iomem *iop_device_map; + u32 count; + struct MessageUnit_D *reg; + void *dma_coherent2; + dma_addr_t dma_coherent_handle2; + struct pci_dev *pdev = acb->pdev; + + acb->roundup_ccbsize = roundup(sizeof(struct MessageUnit_D), 32); + dma_coherent2 = dma_alloc_coherent(&pdev->dev, acb->roundup_ccbsize, + &dma_coherent_handle2, GFP_KERNEL); + if (!dma_coherent2) { + pr_notice("DMA allocation failed...\n"); + return false; + } + memset(dma_coherent2, 0, acb->roundup_ccbsize); + acb->dma_coherent_handle2 = dma_coherent_handle2; + acb->dma_coherent2 = dma_coherent2; + reg = (struct MessageUnit_D *)dma_coherent2; + acb->pmuD = reg; + reg->chip_id = acb->mem_base0 + ARCMSR_ARC1214_CHIP_ID; + reg->cpu_mem_config = acb->mem_base0 + + ARCMSR_ARC1214_CPU_MEMORY_CONFIGURATION; + reg->i2o_host_interrupt_mask = acb->mem_base0 + + ARCMSR_ARC1214_I2_HOST_INTERRUPT_MASK; + reg->sample_at_reset = acb->mem_base0 + ARCMSR_ARC1214_SAMPLE_RESET; + reg->reset_request = acb->mem_base0 + ARCMSR_ARC1214_RESET_REQUEST; + reg->host_int_status = acb->mem_base0 + + ARCMSR_ARC1214_MAIN_INTERRUPT_STATUS; + reg->pcief0_int_enable = acb->mem_base0 + + ARCMSR_ARC1214_PCIE_F0_INTERRUPT_ENABLE; + reg->inbound_msgaddr0 = acb->mem_base0 + + ARCMSR_ARC1214_INBOUND_MESSAGE0; + reg->inbound_msgaddr1 = acb->mem_base0 + + ARCMSR_ARC1214_INBOUND_MESSAGE1; + reg->outbound_msgaddr0 = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_MESSAGE0; + reg->outbound_msgaddr1 = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_MESSAGE1; + reg->inbound_doorbell = acb->mem_base0 + + ARCMSR_ARC1214_INBOUND_DOORBELL; + reg->outbound_doorbell = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_DOORBELL; + reg->outbound_doorbell_enable = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_DOORBELL_ENABLE; + reg->inboundlist_base_low = acb->mem_base0 + + ARCMSR_ARC1214_INBOUND_LIST_BASE_LOW; + reg->inboundlist_base_high = acb->mem_base0 + + ARCMSR_ARC1214_INBOUND_LIST_BASE_HIGH; + reg->inboundlist_write_pointer = acb->mem_base0 + + ARCMSR_ARC1214_INBOUND_LIST_WRITE_POINTER; + reg->outboundlist_base_low = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_LIST_BASE_LOW; + reg->outboundlist_base_high = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_LIST_BASE_HIGH; + reg->outboundlist_copy_pointer = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_LIST_COPY_POINTER; + reg->outboundlist_read_pointer = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_LIST_READ_POINTER; + reg->outboundlist_interrupt_cause = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_INTERRUPT_CAUSE; + reg->outboundlist_interrupt_enable = acb->mem_base0 + + ARCMSR_ARC1214_OUTBOUND_INTERRUPT_ENABLE; + reg->message_wbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_WBUFFER; + reg->message_rbuffer = acb->mem_base0 + ARCMSR_ARC1214_MESSAGE_RBUFFER; + reg->msgcode_rwbuffer = acb->mem_base0 + + ARCMSR_ARC1214_MESSAGE_RWBUFFER; + iop_firm_model = (char __iomem *)(®->msgcode_rwbuffer[15]); + iop_firm_version = (char __iomem *)(®->msgcode_rwbuffer[17]); + iop_device_map = (char __iomem *)(®->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(®->msgcode_rwbuffer[1]); + /*firm_signature,1,00-03*/ + acb->firm_request_len = readl(®->msgcode_rwbuffer[2]); + /*firm_request_len,1,04-07*/ + acb->firm_numbers_queue = readl(®->msgcode_rwbuffer[3]); + /*firm_numbers_queue,2,08-11*/ + acb->firm_sdram_size = readl(®->msgcode_rwbuffer[4]); + /*firm_sdram_size,3,12-15*/ + acb->firm_hd_channels = readl(®->msgcode_rwbuffer[5]); + /*firm_hd_channels,4,16-19*/ + acb->firm_cfg_version = readl(®->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) { - if (acb->adapter_type == ACB_ADAPTER_TYPE_A) - return arcmsr_get_hba_config(acb); - else if (acb->adapter_type == ACB_ADAPTER_TYPE_B) - return arcmsr_get_hbb_config(acb); + bool rtn = false; + + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: + rtn = arcmsr_hbaA_get_config(acb); + break; + case ACB_ADAPTER_TYPE_B: + rtn = arcmsr_hbaB_get_config(acb); + break; + 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; + } + if (acb->firm_numbers_queue > ARCMSR_MAX_OUTSTANDING_CMD) + acb->maxOutstanding = ARCMSR_MAX_OUTSTANDING_CMD; else - return arcmsr_get_hbc_config(acb); + acb->maxOutstanding = acb->firm_numbers_queue - 1; + acb->host->can_queue = acb->maxOutstanding; + return rtn; } -static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, +static int arcmsr_hbaA_polling_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { struct MessageUnit_A __iomem *reg = acb->pmuA; @@ -2328,7 +2963,7 @@ static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, } arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - poll_ccb_done = (ccb == poll_ccb) ? 1:0; + poll_ccb_done |= (ccb == poll_ccb) ? 1 : 0; if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" @@ -2355,7 +2990,7 @@ static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, return rtn; } -static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, +static int arcmsr_hbaB_polling_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { struct MessageUnit_B *reg = acb->pmuB; @@ -2371,7 +3006,8 @@ static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); while(1){ index = reg->doneq_index; - if ((flag_ccb = readl(®->done_qbuffer[index])) == 0) { + flag_ccb = reg->done_qbuffer[index]; + if (flag_ccb == 0) { if (poll_ccb_done){ rtn = SUCCESS; break; @@ -2384,7 +3020,7 @@ static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, goto polling_hbb_ccb_retry; } } - writel(0, ®->done_qbuffer[index]); + reg->done_qbuffer[index] = 0; index++; /*if last index number set it to 0 */ index %= ARCMSR_MAX_HBB_POSTQUEUE; @@ -2392,7 +3028,7 @@ static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, /* check if command done with no error*/ arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - poll_ccb_done = (ccb == poll_ccb) ? 1:0; + poll_ccb_done |= (ccb == poll_ccb) ? 1 : 0; if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" @@ -2419,9 +3055,10 @@ static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, return rtn; } -static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) +static int arcmsr_hbaC_polling_ccbdone(struct AdapterControlBlock *acb, + struct CommandControlBlock *poll_ccb) { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + struct MessageUnit_C __iomem *reg = acb->pmuC; uint32_t flag_ccb, ccb_cdb_phy; struct ARCMSR_CDB *arcmsr_cdb; bool error; @@ -2448,7 +3085,7 @@ polling_hbc_ccb_retry: ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/ pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0; + poll_ccb_done |= (pCCB == poll_ccb) ? 1 : 0; /* check ifcommand done with no error*/ if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { if (pCCB->startdone == ARCMSR_CCB_ABORTED) { @@ -2475,6 +3112,81 @@ 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, 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) : + ((toggle ^ 0x4000) + 1); + doneq_index = pmu->doneq_index; + spin_unlock_irqrestore(&acb->doneq_lock, flags); + 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) { @@ -2482,17 +3194,21 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { - rtn = arcmsr_polling_hba_ccbdone(acb, poll_ccb); + rtn = arcmsr_hbaA_polling_ccbdone(acb, poll_ccb); } break; case ACB_ADAPTER_TYPE_B: { - rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb); + rtn = arcmsr_hbaB_polling_ccbdone(acb, poll_ccb); } break; case ACB_ADAPTER_TYPE_C: { - rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb); + 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; } @@ -2500,6 +3216,7 @@ static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) { uint32_t cdb_phyaddr, cdb_phyaddr_hi32; + dma_addr_t dma_coherent_handle; /* ******************************************************************** @@ -2507,8 +3224,17 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) ** if freeccb.HighPart is not zero ******************************************************************** */ - cdb_phyaddr = lower_32_bits(acb->dma_coherent_handle); - cdb_phyaddr_hi32 = upper_32_bits(acb->dma_coherent_handle); + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_B: + case ACB_ADAPTER_TYPE_D: + dma_coherent_handle = acb->dma_coherent_handle2; + break; + default: + dma_coherent_handle = acb->dma_coherent_handle; + break; + } + cdb_phyaddr = lower_32_bits(dma_coherent_handle); + cdb_phyaddr_hi32 = upper_32_bits(dma_coherent_handle); acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32; /* *********************************************************************** @@ -2520,65 +3246,62 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_A: { if (cdb_phyaddr_hi32 != 0) { struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t intmask_org; - intmask_org = arcmsr_disable_outbound_ints(acb); writel(ARCMSR_SIGNATURE_SET_CONFIG, \ ®->message_rwbuffer[0]); writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]); writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \ ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hbaA_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: ""set ccb high \ part physical address timeout\n", acb->host->host_no); return 1; } - arcmsr_enable_outbound_ints(acb, intmask_org); } } break; case ACB_ADAPTER_TYPE_B: { - unsigned long post_queue_phyaddr; uint32_t __iomem *rwbuffer; struct MessageUnit_B *reg = acb->pmuB; - uint32_t intmask_org; - intmask_org = arcmsr_disable_outbound_ints(acb); reg->postq_index = 0; reg->doneq_index = 0; writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbaB_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \ acb->host->host_no); return 1; } - post_queue_phyaddr = acb->dma_coherent_handle_hbb_mu; rwbuffer = reg->message_rwbuffer; /* driver "set config" signature */ writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++); /* normal should be zero */ writel(cdb_phyaddr_hi32, rwbuffer++); /* postQ size (256 + 8)*4 */ - writel(post_queue_phyaddr, rwbuffer++); + writel(cdb_phyaddr, rwbuffer++); /* doneQ size (256 + 8)*4 */ - writel(post_queue_phyaddr + 1056, rwbuffer++); + writel(cdb_phyaddr + 1056, rwbuffer++); /* ccb maxQ size must be --> [(256 + 8)*4]*/ writel(1056, rwbuffer); writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbaB_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ timeout \n",acb->host->host_no); return 1; } - arcmsr_hbb_enable_driver_mode(acb); - arcmsr_enable_outbound_ints(acb, intmask_org); + writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell); + if (!arcmsr_hbaB_wait_msgint_ready(acb)) { + pr_err("arcmsr%d: can't set driver mode.\n", + acb->host->host_no); + return 1; + } } break; case ACB_ADAPTER_TYPE_C: { if (cdb_phyaddr_hi32 != 0) { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + struct MessageUnit_C __iomem *reg = acb->pmuC; printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x\n", acb->adapter_index, cdb_phyaddr_hi32); @@ -2586,13 +3309,34 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]); writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); - if (!arcmsr_hbc_wait_msgint_ready(acb)) { + if (!arcmsr_hbaC_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ timeout \n", acb->host->host_no); return 1; } } } + 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; } @@ -2619,15 +3363,24 @@ static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) } break; case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; + struct MessageUnit_C __iomem *reg = acb->pmuC; do { firmware_state = readl(®->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; } } -static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb) +static void arcmsr_hbaA_request_device_map(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ @@ -2649,9 +3402,9 @@ static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb) return; } -static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb) +static void arcmsr_hbaB_request_device_map(struct AdapterControlBlock *acb) { - struct MessageUnit_B __iomem *reg = acb->pmuB; + struct MessageUnit_B *reg = acb->pmuB; 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)); return; @@ -2671,7 +3424,7 @@ static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb) return; } -static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb) +static void arcmsr_hbaC_request_device_map(struct AdapterControlBlock *acb) { struct MessageUnit_C __iomem *reg = acb->pmuC; if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) { @@ -2694,69 +3447,119 @@ static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb) return; } +static void arcmsr_hbaD_request_device_map(struct AdapterControlBlock *acb) +{ + struct MessageUnit_D *reg = acb->pmuD; + + if (unlikely(atomic_read(&acb->rq_map_token) == 0) || + ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || + ((acb->acb_flags & ACB_F_ABORT) != 0)) { + mod_timer(&acb->eternal_timer, + jiffies + msecs_to_jiffies(6 * HZ)); + } else { + acb->fw_flag = FW_NORMAL; + if (atomic_read(&acb->ante_token_value) == + atomic_read(&acb->rq_map_token)) { + atomic_set(&acb->rq_map_token, 16); + } + atomic_set(&acb->ante_token_value, + atomic_read(&acb->rq_map_token)); + if (atomic_dec_and_test(&acb->rq_map_token)) { + mod_timer(&acb->eternal_timer, jiffies + + msecs_to_jiffies(6 * HZ)); + return; + } + writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, + reg->inbound_msgaddr0); + mod_timer(&acb->eternal_timer, jiffies + + msecs_to_jiffies(6 * HZ)); + } +} + static void arcmsr_request_device_map(unsigned long pacb) { struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { - arcmsr_request_hba_device_map(acb); + arcmsr_hbaA_request_device_map(acb); } break; case ACB_ADAPTER_TYPE_B: { - arcmsr_request_hbb_device_map(acb); + arcmsr_hbaB_request_device_map(acb); } break; case ACB_ADAPTER_TYPE_C: { - arcmsr_request_hbc_device_map(acb); + arcmsr_hbaC_request_device_map(acb); } + break; + case ACB_ADAPTER_TYPE_D: + arcmsr_hbaD_request_device_map(acb); + break; } } -static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb) +static void arcmsr_hbaA_start_bgrb(struct AdapterControlBlock *acb) { struct MessageUnit_A __iomem *reg = acb->pmuA; acb->acb_flags |= ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { + if (!arcmsr_hbaA_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ rebulid' timeout \n", acb->host->host_no); } } -static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb) +static void arcmsr_hbaB_start_bgrb(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; acb->acb_flags |= ACB_F_MSG_START_BGRB; writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbaB_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ rebulid' timeout \n",acb->host->host_no); } } -static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB) +static void arcmsr_hbaC_start_bgrb(struct AdapterControlBlock *pACB) { - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; + struct MessageUnit_C __iomem *phbcmu = pACB->pmuC; pACB->acb_flags |= ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0); writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell); - if (!arcmsr_hbc_wait_msgint_ready(pACB)) { + if (!arcmsr_hbaC_wait_msgint_ready(pACB)) { printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ rebulid' timeout \n", pACB->host->host_no); } 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) { case ACB_ADAPTER_TYPE_A: - arcmsr_start_hba_bgrb(acb); + arcmsr_hbaA_start_bgrb(acb); break; case ACB_ADAPTER_TYPE_B: - arcmsr_start_hbb_bgrb(acb); + arcmsr_hbaB_start_bgrb(acb); break; case ACB_ADAPTER_TYPE_C: - arcmsr_start_hbc_bgrb(acb); + arcmsr_hbaC_start_bgrb(acb); + break; + case ACB_ADAPTER_TYPE_D: + arcmsr_hbaD_start_bgrb(acb); + break; } } @@ -2783,13 +3586,48 @@ static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) } break; case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; - uint32_t outbound_doorbell; + struct MessageUnit_C __iomem *reg = acb->pmuC; + uint32_t outbound_doorbell, i; /* empty doorbell Qbuffer if door bell ringed */ outbound_doorbell = readl(®->outbound_doorbell); writel(outbound_doorbell, ®->outbound_doorbell_clear); writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); + for (i = 0; i < 200; i++) { + msleep(20); + outbound_doorbell = readl(®->outbound_doorbell); + if (outbound_doorbell & + ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { + writel(outbound_doorbell, + ®->outbound_doorbell_clear); + writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, + ®->inbound_doorbell); + } else + 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; } } @@ -2802,7 +3640,7 @@ static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { + if (!arcmsr_hbaB_wait_msgint_ready(acb)) { printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT"); return; } @@ -2820,6 +3658,7 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) int i, count = 0; struct MessageUnit_A __iomem *pmuA = acb->pmuA; struct MessageUnit_C __iomem *pmuC = acb->pmuC; + struct MessageUnit_D *pmuD = acb->pmuD; /* backup pci config data */ printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no); @@ -2840,6 +3679,8 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) writel(0xD, &pmuC->write_sequence); } while (((readl(&pmuC->host_diagnostic) & ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5)); writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic); + } else if ((acb->dev_id == 0x1214)) { + writel(0x20, pmuD->reset_request); } else { pci_write_config_byte(acb->pdev, 0x84, 0x20); } @@ -3016,9 +3857,7 @@ sleep: arcmsr_get_firmware_spec(acb); arcmsr_start_adapter_bgrb(acb); /* clear Qbuffer if door bell ringed */ - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell_clear); /*clear interrupt */ - writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); + arcmsr_clear_doorbell_queue_buffer(acb); /* enable outbound Post Queue,outbound doorbell Interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); atomic_set(&acb->rq_map_token, 16); @@ -3038,6 +3877,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; } @@ -3056,8 +3955,10 @@ static int arcmsr_abort(struct scsi_cmnd *cmd) (struct AdapterControlBlock *)cmd->device->host->hostdata; int i = 0; int rtn = FAILED; + uint32_t intmask_org; + printk(KERN_NOTICE - "arcmsr%d: abort device command of scsi id = %d lun = %d \n", + "arcmsr%d: abort device command of scsi id = %d lun = %d\n", acb->host->host_no, cmd->device->id, (u32)cmd->device->lun); acb->acb_flags |= ACB_F_ABORT; acb->num_aborts++; @@ -3067,9 +3968,12 @@ static int arcmsr_abort(struct scsi_cmnd *cmd) ** we need to handle it as soon as possible and exit ************************************************ */ - if (!atomic_read(&acb->ccboutstandingcount)) + if (!atomic_read(&acb->ccboutstandingcount)) { + acb->acb_flags &= ~ACB_F_ABORT; return rtn; + } + intmask_org = arcmsr_disable_outbound_ints(acb); for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { struct CommandControlBlock *ccb = acb->pccb_pool[i]; if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) { @@ -3079,6 +3983,7 @@ static int arcmsr_abort(struct scsi_cmnd *cmd) } } acb->acb_flags &= ~ACB_F_ABORT; + arcmsr_enable_outbound_ints(acb, intmask_org); return rtn; } @@ -3108,19 +4013,20 @@ static const char *arcmsr_info(struct Scsi_Host *host) case PCI_DEVICE_ID_ARECA_1280: type = "SATA"; break; + case PCI_DEVICE_ID_ARECA_1214: case PCI_DEVICE_ID_ARECA_1380: case PCI_DEVICE_ID_ARECA_1381: case PCI_DEVICE_ID_ARECA_1680: case PCI_DEVICE_ID_ARECA_1681: case PCI_DEVICE_ID_ARECA_1880: - type = "SAS"; + type = "SAS/SATA"; break; default: - type = "X-TYPE"; + type = "unknown"; + raid6 = 0; break; } - sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s", - type, raid6 ? "( RAID6 capable)" : "", - ARCMSR_DRIVER_VERSION); + sprintf(buf, "Areca %s RAID Controller %s\narcmsr version %s\n", + type, raid6 ? "(RAID6 capable)" : "", ARCMSR_DRIVER_VERSION); return buf; } |