diff options
author | Nick Cheng <nick.cheng@areca.com.tw> | 2010-06-18 15:39:12 +0800 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 12:01:53 -0500 |
commit | ae52e7f09ff509df11cd408eabe90132b6be1231 (patch) | |
tree | 601dd812c670fe1c586a514a6785324855fdc098 /drivers/scsi/arcmsr | |
parent | f034260db330bb3ffc815fcb682b1c84aca09591 (diff) |
[SCSI] arcmsr: Support 1024 scatter-gather list entries and improve AP while FW trapped and behaviors of EHs
1. To support 4M/1024 scatter-gather list entry, reorganize struct
ARCMSR_CDB and struct CommandControlBlock
2. To modify arcmsr_probe
3. In order to help fix F/W issue, add the driver mode for type B card
4. To improve AP's behavior while F/W resets
5. To unify struct MessageUnit_B's members' naming in all OS drivers'
6. To improve error handlers, arcmsr_bus_reset(), arcmsr_abort()
7. To fix the arcmsr_queue_command() in bus reset stage, just let the
commands pass down to FW, don't block
Signed-off-by: Nick Cheng <nick.cheng@areca.com.tw>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/arcmsr')
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr.h | 135 | ||||
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_hba.c | 1225 |
2 files changed, 677 insertions, 683 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index ce5371b3cdd5..c0861c05cd49 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -48,16 +48,22 @@ struct device_attribute; /*The limit of outstanding scsi command that firmware can handle*/ #define ARCMSR_MAX_OUTSTANDING_CMD 256 #define ARCMSR_MAX_FREECCB_NUM 320 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2008/11/03" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2009/12/09" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 +#define ARCMSR_MAX_XFER_SECTORS_C 304 #define ARCMSR_MAX_TARGETID 17 #define ARCMSR_MAX_TARGETLUN 8 #define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD #define ARCMSR_MAX_QBUFFER 4096 -#define ARCMSR_MAX_SG_ENTRIES 38 +#define ARCMSR_DEFAULT_SG_ENTRIES 38 #define ARCMSR_MAX_HBB_POSTQUEUE 264 +#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */ +#define ARCMSR_CDB_SG_PAGE_LENGTH 256 +#ifndef PCI_DEVICE_ID_ARECA_1880 +#define PCI_DEVICE_ID_ARECA_1880 0x1880 + #endif /* ********************************************************************************** ** @@ -141,26 +147,19 @@ struct CMD_MESSAGE_FIELD ** structure for holding DMA address data ************************************************************* */ +#define IS_DMA64 (sizeof(dma_addr_t) == 8) #define IS_SG64_ADDR 0x01000000 /* bit24 */ struct SG32ENTRY { __le32 length; __le32 address; -}; +} __attribute__ ((packed)); struct SG64ENTRY { __le32 length; __le32 address; __le32 addresshigh; -}; -struct SGENTRY_UNION -{ - union - { - struct SG32ENTRY sg32entry; - struct SG64ENTRY sg64entry; - }u; -}; +} __attribute__ ((packed)); /* ******************************************************************** ** Q Buffer of IOP Message Transfer @@ -187,6 +186,9 @@ struct FIRMWARE_INFO char model[8]; /*15, 60-67*/ char firmware_ver[16]; /*17, 68-83*/ char device_map[16]; /*21, 84-99*/ + uint32_t cfgVersion; /*25,100-103 Added for checking of new firmware capability*/ + uint8_t cfgSerial[16]; /*26,104-119*/ + uint32_t cfgPicStatus; /*30,120-123*/ }; /* signature of set and get firmware config */ #define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 @@ -213,6 +215,8 @@ struct FIRMWARE_INFO #define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000 /* outbound firmware ok */ #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000 +/* ARC-1680 Bus Reset*/ +#define ARCMSR_ARC1680_BUS_RESET 0x00000003 /* ************************************************************************ @@ -264,11 +268,11 @@ struct FIRMWARE_INFO /* data tunnel buffer between user space program and its firmware */ /* user space data to iop 128bytes */ -#define ARCMSR_IOCTL_WBUFFER 0x0000fe00 +#define ARCMSR_MESSAGE_WBUFFER 0x0000fe00 /* iop data to user space 128bytes */ -#define ARCMSR_IOCTL_RBUFFER 0x0000ff00 +#define ARCMSR_MESSAGE_RBUFFER 0x0000ff00 /* iop message_rwbuffer for message command */ -#define ARCMSR_MSGCODE_RWBUFFER 0x0000fa00 +#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00 /* ******************************************************************************* ** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504) @@ -290,7 +294,7 @@ struct ARCMSR_CDB #define ARCMSR_CDB_FLAG_HEADQ 0x08 #define ARCMSR_CDB_FLAG_ORDEREDQ 0x10 - uint8_t Reserved1; + uint8_t msgPages; uint32_t Context; uint32_t DataLength; uint8_t Cdb[16]; @@ -303,10 +307,10 @@ struct ARCMSR_CDB uint8_t SenseData[15]; union { - struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES]; - struct SG64ENTRY sg64entry[ARCMSR_MAX_SG_ENTRIES]; + struct SG32ENTRY sg32entry[1]; + struct SG64ENTRY sg64entry[1]; } u; -}; +} __attribute__ ((packed)); /* ******************************************************************************* ** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor @@ -344,13 +348,13 @@ struct MessageUnit_B uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; uint32_t postq_index; uint32_t doneq_index; - uint32_t __iomem *drv2iop_doorbell_reg; - uint32_t __iomem *drv2iop_doorbell_mask_reg; - uint32_t __iomem *iop2drv_doorbell_reg; - uint32_t __iomem *iop2drv_doorbell_mask_reg; - uint32_t __iomem *msgcode_rwbuffer_reg; - uint32_t __iomem *ioctl_wbuffer_reg; - uint32_t __iomem *ioctl_rbuffer_reg; + uint32_t __iomem *drv2iop_doorbell; + uint32_t __iomem *drv2iop_doorbell_mask; + uint32_t __iomem *iop2drv_doorbell; + uint32_t __iomem *iop2drv_doorbell_mask; + uint32_t __iomem *message_rwbuffer; + uint32_t __iomem *message_wbuffer; + uint32_t __iomem *message_rbuffer; }; /* @@ -370,14 +374,17 @@ struct AdapterControlBlock unsigned long vir2phy_offset; /* Offset is used in making arc cdb physical to virtual calculations */ uint32_t outbound_int_enable; - + spinlock_t eh_lock; + spinlock_t ccblist_lock; union { struct MessageUnit_A __iomem * pmuA; struct MessageUnit_B * pmuB; }; /* message unit ATU inbound base address0 */ - + void __iomem *mem_base0; + void __iomem *mem_base1; uint32_t acb_flags; + u16 dev_id; uint8_t adapter_index; #define ACB_F_SCSISTOPADAPTER 0x0001 #define ACB_F_MSG_STOP_BGRB 0x0002 @@ -394,6 +401,7 @@ struct AdapterControlBlock #define ACB_F_BUS_RESET 0x0080 #define ACB_F_IOP_INITED 0x0100 /* iop init */ + #define ACB_F_ABORT 0x0200 #define ACB_F_FIRMWARE_TRAP 0x0400 struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; /* used for memory free */ @@ -408,7 +416,8 @@ 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; + unsigned int uncache_size; uint8_t rqbuffer[ARCMSR_MAX_QBUFFER]; /* data collection buffer for read from 80331 */ int32_t rqbuf_firstindex; @@ -432,14 +441,18 @@ struct AdapterControlBlock uint32_t firm_numbers_queue; uint32_t firm_sdram_size; uint32_t firm_hd_channels; + uint32_t firm_cfg_version; char firm_model[12]; char firm_version[20]; char device_map[20]; /*21,84-99*/ struct work_struct arcmsr_do_message_isr_bh; struct timer_list eternal_timer; - unsigned short fw_state; + unsigned short fw_flag; + #define FW_NORMAL 0x0000 + #define FW_BOG 0x0001 + #define FW_DEADLOCK 0x0010 atomic_t rq_map_token; - int ante_token_value; + atomic_t ante_token_value; };/* HW_DEVICE_EXTENSION */ /* ******************************************************************************* @@ -449,65 +462,31 @@ struct AdapterControlBlock */ struct CommandControlBlock { - struct ARCMSR_CDB arcmsr_cdb; - /* - ** 0-503 (size of CDB = 504): - ** arcmsr messenger scsi command descriptor size 504 bytes - */ - uint32_t cdb_shifted_phyaddr; - /* 504-507 */ - uint32_t reserved1; - /* 508-511 */ -#if BITS_PER_LONG == 64 - /* ======================512+64 bytes======================== */ - struct list_head list; - /* 512-527 16 bytes next/prev ptrs for ccb lists */ - struct scsi_cmnd * pcmd; - /* 528-535 8 bytes pointer of linux scsi command */ - struct AdapterControlBlock * acb; - /* 536-543 8 bytes pointer of acb */ - - uint16_t ccb_flags; - /* 544-545 */ + /*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/ + 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 shifted_cdb_phyaddr; /*x32: 4byte, x64: 4byte*/ + uint16_t ccb_flags; /*x32: 2byte, x64: 2byte*/ #define CCB_FLAG_READ 0x0000 #define CCB_FLAG_WRITE 0x0001 #define CCB_FLAG_ERROR 0x0002 #define CCB_FLAG_FLUSHCACHE 0x0004 #define CCB_FLAG_MASTER_ABORTED 0x0008 - uint16_t startdone; - /* 546-547 */ + uint16_t startdone; /*x32:2byte,x32:2byte*/ #define ARCMSR_CCB_DONE 0x0000 #define ARCMSR_CCB_START 0x55AA #define ARCMSR_CCB_ABORTED 0xAA55 #define ARCMSR_CCB_ILLEGAL 0xFFFF - uint32_t reserved2[7]; - /* 548-551 552-555 556-559 560-563 564-567 568-571 572-575 */ + #if BITS_PER_LONG == 64 + /* ======================512+64 bytes======================== */ + uint32_t reserved[6]; /*24 byte*/ #else /* ======================512+32 bytes======================== */ - struct list_head list; - /* 512-519 8 bytes next/prev ptrs for ccb lists */ - struct scsi_cmnd * pcmd; - /* 520-523 4 bytes pointer of linux scsi command */ - struct AdapterControlBlock * acb; - /* 524-527 4 bytes pointer of acb */ - - uint16_t ccb_flags; - /* 528-529 */ - #define CCB_FLAG_READ 0x0000 - #define CCB_FLAG_WRITE 0x0001 - #define CCB_FLAG_ERROR 0x0002 - #define CCB_FLAG_FLUSHCACHE 0x0004 - #define CCB_FLAG_MASTER_ABORTED 0x0008 - uint16_t startdone; - /* 530-531 */ - #define ARCMSR_CCB_DONE 0x0000 - #define ARCMSR_CCB_START 0x55AA - #define ARCMSR_CCB_ABORTED 0xAA55 - #define ARCMSR_CCB_ILLEGAL 0xFFFF - uint32_t reserved2[3]; - /* 532-535 536-539 540-543 */ + uint32_t reserved[2]; /*8 byte*/ #endif - /* ========================================================== */ + /* ======================================================= */ + struct ARCMSR_CDB arcmsr_cdb; }; /* ******************************************************************************* diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index ffa54792bb33..ba33473b27a1 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -58,7 +58,6 @@ #include <linux/timer.h> #include <linux/pci.h> #include <linux/aer.h> -#include <linux/slab.h> #include <asm/dma.h> #include <asm/io.h> #include <asm/system.h> @@ -71,20 +70,13 @@ #include <scsi/scsi_transport.h> #include <scsi/scsicam.h> #include "arcmsr.h" - -#ifdef CONFIG_SCSI_ARCMSR_RESET - static int sleeptime = 20; - static int retrycount = 12; - module_param(sleeptime, int, S_IRUGO|S_IWUSR); - MODULE_PARM_DESC(sleeptime, "The waiting period for FW ready while bus reset"); - module_param(retrycount, int, S_IRUGO|S_IWUSR); - MODULE_PARM_DESC(retrycount, "The retry count for FW ready while bus reset"); -#endif -MODULE_AUTHOR("Erich Chen <support@areca.com.tw>"); -MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Bus Adapter"); +MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>"); +MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx) SATA/SAS RAID Host Bus Adapter"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); - +static int sleeptime = 20; +static int retrycount = 12; +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); @@ -108,7 +100,7 @@ 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_message_isr_bh_fn(struct work_struct *work); -static void *arcmsr_get_firmware_spec(struct AdapterControlBlock *acb, int mode); +static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb); static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); static const char *arcmsr_info(struct Scsi_Host *); @@ -135,10 +127,10 @@ static struct scsi_host_template arcmsr_scsi_host_template = { .eh_bus_reset_handler = arcmsr_bus_reset, .bios_param = arcmsr_bios_param, .change_queue_depth = arcmsr_adjust_disk_queue_depth, - .can_queue = ARCMSR_MAX_OUTSTANDING_CMD, + .can_queue = ARCMSR_MAX_FREECCB_NUM, .this_id = ARCMSR_SCSI_INITIATOR_ID, - .sg_tablesize = ARCMSR_MAX_SG_ENTRIES, - .max_sectors = ARCMSR_MAX_XFER_SECTORS, + .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES, + .max_sectors = ARCMSR_MAX_XFER_SECTORS_C, .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = arcmsr_host_attrs, @@ -162,6 +154,7 @@ static struct pci_device_id arcmsr_device_id_table[] = { {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)}, {0, 0}, /* Terminating entry */ }; MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); @@ -173,15 +166,72 @@ static struct pci_driver arcmsr_pci_driver = { .shutdown = arcmsr_shutdown, }; +static void arcmsr_free_mu(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: + break; + case ACB_ADAPTER_TYPE_B:{ + struct MessageUnit_B *reg = acb->pmuB; + dma_free_coherent(&acb->pdev->dev, + sizeof(struct MessageUnit_B), + reg, acb->dma_coherent_handle_hbb_mu); + } + } +} + +static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) +{ + struct pci_dev *pdev = acb->pdev; + + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A:{ + acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!acb->pmuA) { + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); + return false; + } + break; + } + case ACB_ADAPTER_TYPE_B:{ + void __iomem *mem_base0, *mem_base1; + mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!mem_base0) { + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); + return false; + } + mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); + if (!mem_base1) { + iounmap(mem_base0); + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); + return false; + } + acb->mem_base0 = mem_base0; + acb->mem_base1 = mem_base1; + } + } + return true; +} + +static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A:{ + iounmap(acb->pmuA); + } + case ACB_ADAPTER_TYPE_B:{ + iounmap(acb->mem_base0); + iounmap(acb->mem_base1); + } + } +} + static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) { irqreturn_t handle_state; struct AdapterControlBlock *acb = dev_id; - spin_lock(acb->host->host_lock); handle_state = arcmsr_interrupt(acb); - spin_unlock(acb->host->host_lock); - return handle_state; } @@ -218,6 +268,7 @@ 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 0x1201 : { acb->adapter_type = ACB_ADAPTER_TYPE_B; @@ -228,141 +279,210 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) } } -static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) +static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = acb->pmuA; + uint32_t Index; + uint8_t Retries = 0x00; + + do { + for (Index = 0; Index < 100; Index++) { + if (readl(®->outbound_intstatus) & + ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, + ®->outbound_intstatus); + return 0x00; + } + msleep(10); + } /*max 1 seconds*/ + + } while (Retries++ < 20);/*max 20 sec*/ + return 0xff; +} + +static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) { + struct MessageUnit_B *reg = acb->pmuB; + uint32_t Index; + uint8_t Retries = 0x00; + do { + for (Index = 0; Index < 100; Index++) { + if (readl(reg->iop2drv_doorbell) + & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN + , reg->iop2drv_doorbell); + writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); + return 0x00; + } + msleep(10); + } /*max 1 seconds*/ + + } while (Retries++ < 20);/*max 20 sec*/ + return 0xff; +} + +static void arcmsr_flush_hba_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)) + break; + else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout, retry count down = %d \n", acb->host->host_no, retry_count); + } + } while (retry_count != 0); +} + +static void arcmsr_flush_hbb_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)) + break; + else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout,retry count down = %d \n", acb->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: { - struct pci_dev *pdev = acb->pdev; - void *dma_coherent; - dma_addr_t dma_coherent_handle, dma_addr; - struct CommandControlBlock *ccb_tmp; - int i, j; + arcmsr_flush_hba_cache(acb); + } + break; - acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); - if (!acb->pmuA) { - printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", - acb->host->host_no); - return -ENOMEM; + case ACB_ADAPTER_TYPE_B: { + arcmsr_flush_hbb_cache(acb); } + } +} - dma_coherent = dma_alloc_coherent(&pdev->dev, - ARCMSR_MAX_FREECCB_NUM * - sizeof (struct CommandControlBlock) + 0x20, - &dma_coherent_handle, GFP_KERNEL); +static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) +{ + struct pci_dev *pdev = acb->pdev; + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + void *dma_coherent; + dma_addr_t dma_coherent_handle; + struct CommandControlBlock *ccb_tmp; + int i = 0, j = 0; + dma_addr_t cdb_phyaddr; + unsigned long roundup_ccbsize = 0; + unsigned long max_xfer_len; + unsigned long max_sg_entrys; + uint32_t firm_config_version; + + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) + for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + acb->devstate[i][j] = ARECA_RAID_GONE; + + max_xfer_len = ARCMSR_MAX_XFER_LEN; + max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; + firm_config_version = acb->firm_cfg_version; + if ((firm_config_version & 0xFF) >= 3) { + max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */ + max_sg_entrys = (max_xfer_len/4096); + } + acb->host->max_sectors = max_xfer_len/512; + acb->host->sg_tablesize = max_sg_entrys; + roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + max_sg_entrys * sizeof(struct SG64ENTRY), 32); + acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; + dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); if (!dma_coherent) { - iounmap(acb->pmuA); + printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no); return -ENOMEM; } - + memset(dma_coherent, 0, acb->uncache_size); acb->dma_coherent = dma_coherent; acb->dma_coherent_handle = dma_coherent_handle; - - if (((unsigned long)dma_coherent & 0x1F)) { - dma_coherent = dma_coherent + - (0x20 - ((unsigned long)dma_coherent & 0x1F)); - dma_coherent_handle = dma_coherent_handle + - (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); - } - - dma_addr = dma_coherent_handle; ccb_tmp = (struct CommandControlBlock *)dma_coherent; + acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; - ccb_tmp->acb = acb; + cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); + ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5; acb->pccb_pool[i] = ccb_tmp; + ccb_tmp->acb = acb; + INIT_LIST_HEAD(&ccb_tmp->list); list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); - dma_addr = dma_addr + sizeof(struct CommandControlBlock); - ccb_tmp++; - } - - acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; - for (i = 0; i < ARCMSR_MAX_TARGETID; i++) - for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GONE; + ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); + dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; } break; - + } case ACB_ADAPTER_TYPE_B: { - struct pci_dev *pdev = acb->pdev; - struct MessageUnit_B *reg; - void __iomem *mem_base0, *mem_base1; void *dma_coherent; - dma_addr_t dma_coherent_handle, dma_addr; + dma_addr_t dma_coherent_handle; struct CommandControlBlock *ccb_tmp; - int i, j; - - dma_coherent = dma_alloc_coherent(&pdev->dev, - ((ARCMSR_MAX_FREECCB_NUM * - sizeof(struct CommandControlBlock) + 0x20) + - sizeof(struct MessageUnit_B)), + uint32_t cdb_phyaddr; + unsigned int roundup_ccbsize = 0; + unsigned long max_xfer_len; + unsigned long max_sg_entrys; + unsigned long firm_config_version; + unsigned long max_freeccb_num = 0; + int i = 0, j = 0; + + max_freeccb_num = ARCMSR_MAX_FREECCB_NUM; + max_xfer_len = ARCMSR_MAX_XFER_LEN; + max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; + firm_config_version = acb->firm_cfg_version; + if ((firm_config_version & 0xFF) >= 3) { + max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << + ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 16M byte */ + max_sg_entrys = (max_xfer_len/4096);/* max 4097 sg entry*/ + } + acb->host->max_sectors = max_xfer_len / 512; + acb->host->sg_tablesize = max_sg_entrys; + roundup_ccbsize = roundup(sizeof(struct CommandControlBlock)+ + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); + acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; + dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); - if (!dma_coherent) - return -ENOMEM; + if (!dma_coherent) { + printk(KERN_NOTICE "DMA allocation failed...........................\n"); + return -ENOMEM; + } + memset(dma_coherent, 0, acb->uncache_size); acb->dma_coherent = dma_coherent; acb->dma_coherent_handle = dma_coherent_handle; - - if (((unsigned long)dma_coherent & 0x1F)) { - dma_coherent = dma_coherent + - (0x20 - ((unsigned long)dma_coherent & 0x1F)); - dma_coherent_handle = dma_coherent_handle + - (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); - } - - dma_addr = dma_coherent_handle; ccb_tmp = (struct CommandControlBlock *)dma_coherent; + acb->vir2phy_offset = (unsigned long)dma_coherent - + (unsigned long)dma_coherent_handle; for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; - ccb_tmp->acb = acb; + cdb_phyaddr = dma_coherent_handle + + offsetof(struct CommandControlBlock, arcmsr_cdb); + ccb_tmp->shifted_cdb_phyaddr = cdb_phyaddr >> 5; acb->pccb_pool[i] = ccb_tmp; + ccb_tmp->acb = acb; + INIT_LIST_HEAD(&ccb_tmp->list); list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); - dma_addr = dma_addr + sizeof(struct CommandControlBlock); - ccb_tmp++; - } - - reg = (struct MessageUnit_B *)(dma_coherent + - ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); - acb->pmuB = reg; - mem_base0 = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (!mem_base0) - goto out; - - mem_base1 = ioremap(pci_resource_start(pdev, 2), - pci_resource_len(pdev, 2)); - if (!mem_base1) { - iounmap(mem_base0); - goto out; + ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + + roundup_ccbsize); + dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; } - - reg->drv2iop_doorbell_reg = mem_base0 + ARCMSR_DRV2IOP_DOORBELL; - reg->drv2iop_doorbell_mask_reg = mem_base0 + - ARCMSR_DRV2IOP_DOORBELL_MASK; - reg->iop2drv_doorbell_reg = mem_base0 + ARCMSR_IOP2DRV_DOORBELL; - reg->iop2drv_doorbell_mask_reg = mem_base0 + - ARCMSR_IOP2DRV_DOORBELL_MASK; - reg->ioctl_wbuffer_reg = mem_base1 + ARCMSR_IOCTL_WBUFFER; - reg->ioctl_rbuffer_reg = mem_base1 + ARCMSR_IOCTL_RBUFFER; - reg->msgcode_rwbuffer_reg = mem_base1 + ARCMSR_MSGCODE_RWBUFFER; - - acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; for (i = 0; i < ARCMSR_MAX_TARGETID; i++) for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GOOD; + acb->devstate[i][j] = ARECA_RAID_GONE; } break; } return 0; - -out: - dma_free_coherent(&acb->pdev->dev, - (ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock) + 0x20 + - sizeof(struct MessageUnit_B)), acb->dma_coherent, acb->dma_coherent_handle); - return -ENOMEM; } static void arcmsr_message_isr_bh_fn(struct work_struct *work) { @@ -411,8 +531,8 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work) 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 *)(®->msgcode_rwbuffer_reg[0]); - char __iomem *devicemap = (char __iomem *)(®->msgcode_rwbuffer_reg[21]); + 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; @@ -447,8 +567,7 @@ static void arcmsr_message_isr_bh_fn(struct work_struct *work) } } -static int arcmsr_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct Scsi_Host *host; struct AdapterControlBlock *acb; @@ -456,19 +575,13 @@ static int arcmsr_probe(struct pci_dev *pdev, int error; error = pci_enable_device(pdev); - if (error) - goto out; - pci_set_master(pdev); - - host = scsi_host_alloc(&arcmsr_scsi_host_template, - sizeof(struct AdapterControlBlock)); + if (error) { + return -ENODEV; + } + host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock)); if (!host) { - error = -ENOMEM; - goto out_disable_device; + goto pci_disable_dev; } - acb = (struct AdapterControlBlock *)host->hostdata; - memset(acb, 0, sizeof (struct AdapterControlBlock)); - error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); if (error) { error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); @@ -476,126 +589,90 @@ static int arcmsr_probe(struct pci_dev *pdev, printk(KERN_WARNING "scsi%d: No suitable DMA mask available\n", host->host_no); - goto out_host_put; + goto scsi_host_release; } } + init_waitqueue_head(&wait_q); bus = pdev->bus->number; dev_fun = pdev->devfn; - acb->host = host; + acb = (struct AdapterControlBlock *) host->hostdata; + memset(acb, 0, sizeof(struct AdapterControlBlock)); acb->pdev = pdev; - host->max_sectors = ARCMSR_MAX_XFER_SECTORS; + acb->host = host; 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->sg_tablesize = ARCMSR_MAX_SG_ENTRIES; host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; host->this_id = ARCMSR_SCSI_INITIATOR_ID; host->unique_id = (bus << 8) | dev_fun; - host->irq = pdev->irq; + pci_set_drvdata(pdev, host); + pci_set_master(pdev); error = pci_request_regions(pdev, "arcmsr"); if (error) { - goto out_host_put; + goto scsi_host_release; } - arcmsr_define_adapter_type(acb); - + spin_lock_init(&acb->eh_lock); + spin_lock_init(&acb->ccblist_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); - INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); + arcmsr_define_adapter_type(acb); + error = arcmsr_remap_pciregion(acb); + if (!error) { + goto pci_release_regs; + } + error = arcmsr_get_firmware_spec(acb); + if (!error) { + goto unmap_pci_region; + } error = arcmsr_alloc_ccb_pool(acb); - if (error) - goto out_release_regions; - + if (error) { + goto free_hbb_mu; + } arcmsr_iop_init(acb); - error = request_irq(pdev->irq, arcmsr_do_interrupt, - IRQF_SHARED, "arcmsr", acb); - if (error) - goto out_free_ccb_pool; - - pci_set_drvdata(pdev, host); - if (strncmp(acb->firm_version, "V1.42", 5) >= 0) - host->max_sectors= ARCMSR_MAX_XFER_SECTORS_B; - error = scsi_add_host(host, &pdev->dev); - if (error) - goto out_free_irq; - - error = arcmsr_alloc_sysfs_attr(acb); - if (error) - goto out_free_sysfs; - + if (error) { + goto RAID_controller_stop; + } + error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb); + if (error) { + goto scsi_host_remove; + } + host->irq = pdev->irq; scsi_scan_host(host); - #ifdef CONFIG_SCSI_ARCMSR_AER - pci_enable_pcie_error_reporting(pdev); - #endif + INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); atomic_set(&acb->rq_map_token, 16); - acb->fw_state = true; + 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(10*HZ); + 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); - + if (arcmsr_alloc_sysfs_attr(acb)) + goto out_free_sysfs; return 0; out_free_sysfs: - out_free_irq: - free_irq(pdev->irq, acb); - out_free_ccb_pool: +scsi_host_remove: + scsi_remove_host(host); +RAID_controller_stop: + arcmsr_stop_adapter_bgrb(acb); + arcmsr_flush_adapter_cache(acb); arcmsr_free_ccb_pool(acb); - out_release_regions: +free_hbb_mu: + arcmsr_free_mu(acb); +unmap_pci_region: + arcmsr_unmap_pciregion(acb); +pci_release_regs: pci_release_regions(pdev); - out_host_put: +scsi_host_release: scsi_host_put(host); - out_disable_device: +pci_disable_dev: pci_disable_device(pdev); - out: - return error; -} - -static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t Index; - uint8_t Retries = 0x00; - - do { - for (Index = 0; Index < 100; Index++) { - if (readl(®->outbound_intstatus) & - ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, - ®->outbound_intstatus); - return 0x00; - } - msleep(10); - }/*max 1 seconds*/ - - } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; -} - -static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - uint32_t Index; - uint8_t Retries = 0x00; - - do { - for (Index = 0; Index < 100; Index++) { - if (readl(reg->iop2drv_doorbell_reg) - & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN - , reg->iop2drv_doorbell_reg); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell_reg); - return 0x00; - } - msleep(10); - }/*max 1 seconds*/ - - } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; + return -ENODEV; } static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) @@ -616,7 +693,7 @@ static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) { struct MessageUnit_B *reg = acb->pmuB; - writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg); + writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell); if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'abort all outstanding command' timeout \n" @@ -642,76 +719,41 @@ static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb) return rtnval; } +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; +} + return true; +} + static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) { struct scsi_cmnd *pcmd = ccb->pcmd; scsi_dma_unmap(pcmd); -} + } -static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag) +static void arcmsr_ccb_complete(struct CommandControlBlock *ccb) { struct AdapterControlBlock *acb = ccb->acb; struct scsi_cmnd *pcmd = ccb->pcmd; + unsigned long flags; + atomic_dec(&acb->ccboutstandingcount); arcmsr_pci_unmap_dma(ccb); - if (stand_flag == 1) - atomic_dec(&acb->ccboutstandingcount); ccb->startdone = ARCMSR_CCB_DONE; ccb->ccb_flags = 0; + spin_lock_irqsave(&acb->ccblist_lock, flags); list_add_tail(&ccb->list, &acb->ccb_free_list); + spin_unlock_irqrestore(&acb->ccblist_lock, flags); pcmd->scsi_done(pcmd); } -static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - int retry_count = 30; - - writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); - do { |