diff options
author | Nick Cheng <nick.cheng@areca.com.tw> | 2010-07-13 20:03:04 +0800 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 12:03:49 -0500 |
commit | cdd3cb156f190edb37d7066ddbf879354da2b634 (patch) | |
tree | 8633100619eb382a49f79c7003d59ae048368abe /drivers | |
parent | a91c1be21704113b023919826c6d531da46656ef (diff) |
[SCSI] SCSI: Support Type C RAID controller
1. To support Type C RAID controller, ACB_ADAPTER_TYPE_C, i.e. PCI device
ID: 0x1880.
Signed-off-by: Nick Cheng< nick.cheng@areca.com.tw >
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr.h | 208 | ||||
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_attr.c | 9 | ||||
-rw-r--r-- | drivers/scsi/arcmsr/arcmsr_hba.c | 1538 |
3 files changed, 1182 insertions, 573 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index c0861c05cd4..475c31ae985 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -43,12 +43,11 @@ ******************************************************************************* */ #include <linux/interrupt.h> - 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 2009/12/09" +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/02/02" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -60,7 +59,8 @@ struct device_attribute; #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 +#define ARCMSR_CDB_SG_PAGE_LENGTH 256 +#define SCSI_CMD_ARECA_SPECIFIC 0xE1 #ifndef PCI_DEVICE_ID_ARECA_1880 #define PCI_DEVICE_ID_ARECA_1880 0x1880 #endif @@ -138,9 +138,9 @@ struct CMD_MESSAGE_FIELD #define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \ ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE /* ARECA IOCTL ReturnCode */ -#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001 -#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006 -#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F +#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001 +#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006 +#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F #define ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON 0x00000088 /* ************************************************************* @@ -153,13 +153,13 @@ struct SG32ENTRY { __le32 length; __le32 address; -} __attribute__ ((packed)); +}__attribute__ ((packed)); struct SG64ENTRY { __le32 length; __le32 address; __le32 addresshigh; -} __attribute__ ((packed)); +}__attribute__ ((packed)); /* ******************************************************************** ** Q Buffer of IOP Message Transfer @@ -186,9 +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*/ + 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 @@ -212,11 +212,15 @@ struct FIRMWARE_INFO #define ARCMSR_CCBPOST_FLAG_SGL_BSIZE 0x80000000 #define ARCMSR_CCBPOST_FLAG_IAM_BIOS 0x40000000 #define ARCMSR_CCBREPLY_FLAG_IAM_BIOS 0x40000000 -#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000 +#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE0 0x10000000 +#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE1 0x00000001 /* outbound firmware ok */ #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000 /* ARC-1680 Bus Reset*/ #define ARCMSR_ARC1680_BUS_RESET 0x00000003 +/* ARC-1880 Bus Reset*/ +#define ARCMSR_ARC1880_RESET_ADAPTER 0x00000024 +#define ARCMSR_ARC1880_DiagWrite_ENABLE 0x00000080 /* ************************************************************************ @@ -273,6 +277,61 @@ struct FIRMWARE_INFO #define ARCMSR_MESSAGE_RBUFFER 0x0000ff00 /* iop message_rwbuffer for message command */ #define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00 +/* +************************************************************************ +** SPEC. for Areca HBC adapter +************************************************************************ +*/ +#define ARCMSR_HBC_ISR_THROTTLING_LEVEL 12 +#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE 20 +/* Host Interrupt Mask */ +#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK 0x00000001 /* When clear, the Utility_A interrupt routes to the host.*/ +#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK 0x00000004 /* When clear, the General Outbound Doorbell interrupt routes to the host.*/ +#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK 0x00000008 /* When clear, the Outbound Post List FIFO Not Empty interrupt routes to the host.*/ +#define ARCMSR_HBCMU_ALL_INTMASKENABLE 0x0000000D /* disable all ISR */ +/* Host Interrupt Status */ +#define ARCMSR_HBCMU_UTILITY_A_ISR 0x00000001 + /* + ** Set when the Utility_A Interrupt bit is set in the Outbound Doorbell Register. + ** It clears by writing a 1 to the Utility_A bit in the Outbound Doorbell Clear Register or through automatic clearing (if enabled). + */ +#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR 0x00000004 + /* + ** Set if Outbound Doorbell register bits 30:1 have a non-zero + ** value. This bit clears only when Outbound Doorbell bits + ** 30:1 are ALL clear. Only a write to the Outbound Doorbell + ** Clear register clears bits in the Outbound Doorbell register. + */ +#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR 0x00000008 + /* + ** Set whenever the Outbound Post List Producer/Consumer + ** Register (FIFO) is not empty. It clears when the Outbound + ** Post List FIFO is empty. + */ +#define ARCMSR_HBCMU_SAS_ALL_INT 0x00000010 + /* + ** This bit indicates a SAS interrupt from a source external to + ** the PCIe core. This bit is not maskable. + */ + /* DoorBell*/ +#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK 0x00000002 +#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK 0x00000004 + /*inbound message 0 ready*/ +#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE 0x00000008 + /*more than 12 request completed in a time*/ +#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING 0x00000010 +#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK 0x00000002 + /*outbound DATA WRITE isr door bell clear*/ +#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR 0x00000002 +#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK 0x00000004 + /*outbound DATA READ isr door bell clear*/ +#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_DOORBELL_CLEAR 0x00000004 + /*outbound message 0 ready*/ +#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE 0x00000008 + /*outbound message cmd isr door bell clear*/ +#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR 0x00000008 + /*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/ +#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK 0x80000000 /* ******************************************************************************* ** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504) @@ -310,7 +369,7 @@ struct ARCMSR_CDB 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 @@ -356,7 +415,81 @@ struct MessageUnit_B uint32_t __iomem *message_wbuffer; uint32_t __iomem *message_rbuffer; }; - +/* +********************************************************************* +** LSI +********************************************************************* +*/ +struct MessageUnit_C{ + uint32_t message_unit_status; /*0000 0003*/ + uint32_t slave_error_attribute; /*0004 0007*/ + uint32_t slave_error_address; /*0008 000B*/ + uint32_t posted_outbound_doorbell; /*000C 000F*/ + uint32_t master_error_attribute; /*0010 0013*/ + uint32_t master_error_address_low; /*0014 0017*/ + uint32_t master_error_address_high; /*0018 001B*/ + uint32_t hcb_size; /*001C 001F*/ + uint32_t inbound_doorbell; /*0020 0023*/ + uint32_t diagnostic_rw_data; /*0024 0027*/ + uint32_t diagnostic_rw_address_low; /*0028 002B*/ + uint32_t diagnostic_rw_address_high; /*002C 002F*/ + uint32_t host_int_status; /*0030 0033*/ + uint32_t host_int_mask; /*0034 0037*/ + uint32_t dcr_data; /*0038 003B*/ + uint32_t dcr_address; /*003C 003F*/ + uint32_t inbound_queueport; /*0040 0043*/ + uint32_t outbound_queueport; /*0044 0047*/ + uint32_t hcb_pci_address_low; /*0048 004B*/ + uint32_t hcb_pci_address_high; /*004C 004F*/ + uint32_t iop_int_status; /*0050 0053*/ + uint32_t iop_int_mask; /*0054 0057*/ + uint32_t iop_inbound_queue_port; /*0058 005B*/ + uint32_t iop_outbound_queue_port; /*005C 005F*/ + uint32_t inbound_free_list_index; /*0060 0063*/ + uint32_t inbound_post_list_index; /*0064 0067*/ + uint32_t outbound_free_list_index; /*0068 006B*/ + uint32_t outbound_post_list_index; /*006C 006F*/ + uint32_t inbound_doorbell_clear; /*0070 0073*/ + uint32_t i2o_message_unit_control; /*0074 0077*/ + uint32_t last_used_message_source_address_low; /*0078 007B*/ + uint32_t last_used_message_source_address_high; /*007C 007F*/ + uint32_t pull_mode_data_byte_count[4]; /*0080 008F*/ + uint32_t message_dest_address_index; /*0090 0093*/ + uint32_t done_queue_not_empty_int_counter_timer; /*0094 0097*/ + uint32_t utility_A_int_counter_timer; /*0098 009B*/ + uint32_t outbound_doorbell; /*009C 009F*/ + uint32_t outbound_doorbell_clear; /*00A0 00A3*/ + uint32_t message_source_address_index; /*00A4 00A7*/ + uint32_t message_done_queue_index; /*00A8 00AB*/ + uint32_t reserved0; /*00AC 00AF*/ + uint32_t inbound_msgaddr0; /*00B0 00B3*/ + uint32_t inbound_msgaddr1; /*00B4 00B7*/ + uint32_t outbound_msgaddr0; /*00B8 00BB*/ + uint32_t outbound_msgaddr1; /*00BC 00BF*/ + uint32_t inbound_queueport_low; /*00C0 00C3*/ + uint32_t inbound_queueport_high; /*00C4 00C7*/ + uint32_t outbound_queueport_low; /*00C8 00CB*/ + uint32_t outbound_queueport_high; /*00CC 00CF*/ + uint32_t iop_inbound_queue_port_low; /*00D0 00D3*/ + uint32_t iop_inbound_queue_port_high; /*00D4 00D7*/ + uint32_t iop_outbound_queue_port_low; /*00D8 00DB*/ + uint32_t iop_outbound_queue_port_high; /*00DC 00DF*/ + uint32_t message_dest_queue_port_low; /*00E0 00E3*/ + uint32_t message_dest_queue_port_high; /*00E4 00E7*/ + uint32_t last_used_message_dest_address_low; /*00E8 00EB*/ + uint32_t last_used_message_dest_address_high; /*00EC 00EF*/ + uint32_t message_done_queue_base_address_low; /*00F0 00F3*/ + uint32_t message_done_queue_base_address_high; /*00F4 00F7*/ + uint32_t host_diagnostic; /*00F8 00FB*/ + uint32_t write_sequence; /*00FC 00FF*/ + uint32_t reserved1[34]; /*0100 0187*/ + uint32_t reserved2[1950]; /*0188 1FFF*/ + uint32_t message_wbuffer[32]; /*2000 207F*/ + uint32_t reserved3[32]; /*2080 20FF*/ + uint32_t message_rbuffer[32]; /*2100 217F*/ + uint32_t reserved4[32]; /*2180 21FF*/ + uint32_t msgcode_rwbuffer[256]; /*2200 23FF*/ +}; /* ******************************************************************************* ** Adapter Control Block @@ -374,11 +507,14 @@ struct AdapterControlBlock unsigned long vir2phy_offset; /* 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; union { - struct MessageUnit_A __iomem * pmuA; - struct MessageUnit_B * pmuB; + struct MessageUnit_A __iomem *pmuA; + struct MessageUnit_B *pmuB; + struct MessageUnit_C __iomem *pmuC; }; /* message unit ATU inbound base address0 */ void __iomem *mem_base0; @@ -399,6 +535,8 @@ struct AdapterControlBlock /* message clear rqbuffer */ #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040 #define ACB_F_BUS_RESET 0x0080 + #define ACB_F_BUS_HANG_ON 0x0800/* need hardware reset bus */ + #define ACB_F_IOP_INITED 0x0100 /* iop init */ #define ACB_F_ABORT 0x0200 @@ -441,9 +579,9 @@ 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]; + 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; @@ -460,31 +598,31 @@ struct AdapterControlBlock ** this CCB length must be 32 bytes boundary ******************************************************************************* */ -struct CommandControlBlock -{ +struct CommandControlBlock{ /*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*/ + uint32_t cdb_phyaddr_pattern; /*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 - #define CCB_FLAG_WRITE 0x0001 - #define CCB_FLAG_ERROR 0x0002 - #define CCB_FLAG_FLUSHCACHE 0x0004 - #define CCB_FLAG_MASTER_ABORTED 0x0008 + #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; /*x32:2byte,x32:2byte*/ - #define ARCMSR_CCB_DONE 0x0000 - #define ARCMSR_CCB_START 0x55AA - #define ARCMSR_CCB_ABORTED 0xAA55 - #define ARCMSR_CCB_ILLEGAL 0xFFFF + #define ARCMSR_CCB_DONE 0x0000 + #define ARCMSR_CCB_START 0x55AA + #define ARCMSR_CCB_ABORTED 0xAA55 + #define ARCMSR_CCB_ILLEGAL 0xFFFF #if BITS_PER_LONG == 64 /* ======================512+64 bytes======================== */ - uint32_t reserved[6]; /*24 byte*/ -#else + uint32_t reserved[5]; /*24 byte*/ + #else /* ======================512+32 bytes======================== */ - uint32_t reserved[2]; /*8 byte*/ -#endif + uint32_t reserved; /*8 byte*/ + #endif /* ======================================================= */ struct ARCMSR_CDB arcmsr_cdb; }; diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index 07fdfe57e38..69f8346aa28 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -59,8 +59,7 @@ struct device_attribute *arcmsr_host_attrs[]; -static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp, - struct kobject *kobj, +static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj, struct bin_attribute *bin, char *buf, loff_t off, size_t count) @@ -106,8 +105,7 @@ static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp, return (allxfer_len); } -static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, - struct kobject *kobj, +static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj, struct bin_attribute *bin, char *buf, loff_t off, size_t count) @@ -155,8 +153,7 @@ static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, } } -static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp, - struct kobject *kobj, +static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj, struct bin_attribute *bin, char *buf, loff_t off, size_t count) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index ba33473b27a..95a895dd4f1 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -71,11 +71,11 @@ #include <scsi/scsicam.h> #include "arcmsr.h" MODULE_AUTHOR("Nick Cheng <support@areca.com.tw>"); -MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx) SATA/SAS RAID Host Bus Adapter"); +MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); -static int sleeptime = 20; -static int retrycount = 12; +static int sleeptime = 10; +static int retrycount = 30; wait_queue_head_t wait_q; static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); @@ -99,10 +99,12 @@ static void arcmsr_flush_hbb_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_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_hardware_reset(struct AdapterControlBlock *acb); static const char *arcmsr_info(struct Scsi_Host *); static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, @@ -119,18 +121,18 @@ 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 Host Bus Adapter" - ARCMSR_DRIVER_VERSION, + .name = "ARCMSR ARECA SATA/SAS RAID Controller" + ARCMSR_DRIVER_VERSION, .info = arcmsr_info, .queuecommand = arcmsr_queue_command, - .eh_abort_handler = arcmsr_abort, + .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, - .this_id = ARCMSR_SCSI_INITIATOR_ID, - .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES, - .max_sectors = ARCMSR_MAX_XFER_SECTORS_C, + .this_id = ARCMSR_SCSI_INITIATOR_ID, + .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, @@ -160,22 +162,45 @@ static struct pci_device_id arcmsr_device_id_table[] = { MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); static struct pci_driver arcmsr_pci_driver = { .name = "arcmsr", - .id_table = arcmsr_device_id_table, + .id_table = arcmsr_device_id_table, .probe = arcmsr_probe, .remove = arcmsr_remove, .shutdown = arcmsr_shutdown, }; +/* +**************************************************************************** +**************************************************************************** +*/ +int arcmsr_sleep_for_bus_reset(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *shost = NULL; + int i, isleep; + shost = cmd->device->host; + isleep = sleeptime / 10; + if (isleep > 0) { + for (i = 0; i < isleep; i++) { + msleep(10000); + } + } -static void arcmsr_free_mu(struct AdapterControlBlock *acb) + isleep = sleeptime % 10; + if (isleep > 0) { + msleep(isleep*1000); + } + printk(KERN_NOTICE "wake-up\n"); + return 0; +} + +static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: + case ACB_ADAPTER_TYPE_C: 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); + dma_free_coherent(&acb->pdev->dev, + sizeof(struct MessageUnit_B), + acb->pmuB, acb->dma_coherent_handle_hbb_mu); } } } @@ -183,10 +208,9 @@ static void arcmsr_free_mu(struct AdapterControlBlock *acb) static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) { struct pci_dev *pdev = acb->pdev; - - switch (acb->adapter_type) { + switch (acb->adapter_type){ case ACB_ADAPTER_TYPE_A:{ - acb->pmuA = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + 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; @@ -208,6 +232,19 @@ static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) } acb->mem_base0 = mem_base0; acb->mem_base1 = mem_base1; + break; + } + case ACB_ADAPTER_TYPE_C:{ + acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); + if (!acb->pmuC) { + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); + return false; + } + if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/ + return true; + } + break; } } return true; @@ -216,13 +253,19 @@ static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) 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); - } + case ACB_ADAPTER_TYPE_A:{ + iounmap(acb->pmuA); + } + break; + case ACB_ADAPTER_TYPE_B:{ + iounmap(acb->mem_base0); + iounmap(acb->mem_base1); + } + + break; + case ACB_ADAPTER_TYPE_C:{ + iounmap(acb->pmuC); + } } } @@ -270,34 +313,37 @@ static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); acb->dev_id = dev_id; switch (dev_id) { - case 0x1201 : { + 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; + default: acb->adapter_type = ACB_ADAPTER_TYPE_A; } -} +} 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; + return true; } msleep(10); - } /*max 1 seconds*/ + }/*max 1 seconds*/ } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; + return false; } static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) @@ -305,7 +351,6 @@ 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) @@ -313,23 +358,39 @@ static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN , reg->iop2drv_doorbell); writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); - return 0x00; + return true; } msleep(10); - } /*max 1 seconds*/ + }/*max 1 seconds*/ } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; + return false; } +static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB) +{ + struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; + unsigned char Retries = 0x00; + uint32_t Index; + do { + for (Index = 0; Index < 100; Index++) { + if (readl(&phbcmu->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &phbcmu->outbound_doorbell_clear);/*clear interrupt*/ + return true; + } + /* one us delay */ + msleep(10); + } /*max 1 seconds*/ + } while (Retries++ < 20); /*max 20 sec*/ + return false; +} 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)) + if (arcmsr_hba_wait_msgint_ready(acb)) break; else { retry_count--; @@ -343,10 +404,9 @@ 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)) + if (arcmsr_hbb_wait_msgint_ready(acb)) break; else { retry_count--; @@ -356,6 +416,23 @@ static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) } while (retry_count != 0); } +static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB) +{ + struct MessageUnit_C *reg = (struct MessageUnit_C *)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)) { + break; + } else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout,retry count down = %d \n", pACB->host->host_no, retry_count); + } + } while (retry_count != 0); + return; +} static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) { switch (acb->adapter_type) { @@ -368,151 +445,94 @@ static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) case ACB_ADAPTER_TYPE_B: { arcmsr_flush_hbb_cache(acb); } + break; + case ACB_ADAPTER_TYPE_C: { + arcmsr_flush_hbc_cache(acb); + } } } 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) { - 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; - 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++) { - 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); - ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); - dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; - } - break; - } - case ACB_ADAPTER_TYPE_B: { - - void *dma_coherent; - dma_addr_t dma_coherent_handle; - struct CommandControlBlock *ccb_tmp; - 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) { - 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; - 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++) { - 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); - ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + - roundup_ccbsize); - dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; - } - for (i = 0; i < ARCMSR_MAX_TARGETID; i++) - for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GONE; - } - break; + struct pci_dev *pdev = acb->pdev; + 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, offset; + 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 4M 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 - 1) * sizeof(struct SG64ENTRY), 32); + acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM + 32; + dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); + if(!dma_coherent){ + printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error \n", acb->host->host_no); + return -ENOMEM; + } + acb->dma_coherent = dma_coherent; + acb->dma_coherent_handle = dma_coherent_handle; + memset(dma_coherent, 0, acb->uncache_size); + offset = roundup((unsigned long)dma_coherent, 32) - (unsigned long)dma_coherent; + dma_coherent_handle = dma_coherent_handle + offset; + dma_coherent = (struct CommandControlBlock *)dma_coherent + offset; + ccb_tmp = dma_coherent; + 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)); + 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); + ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); + dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; } return 0; } -static void arcmsr_message_isr_bh_fn(struct work_struct *work) -{ - struct AdapterControlBlock *acb = container_of(work, struct AdapterControlBlock, arcmsr_do_message_isr_bh); +static void arcmsr_message_isr_bh_fn(struct work_struct *work) +{ + struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh); switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { 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]); + 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++) { + 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) { + 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) { + }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) { psdev = scsi_device_lookup(acb->host, 0, target, lun); - if (psdev != NULL) { + if (psdev != NULL ) { scsi_remove_device(psdev); scsi_device_put(psdev); } @@ -531,8 +551,45 @@ 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 *)(®->message_rwbuffer[0]); - char __iomem *devicemap = (char __iomem *)(®->message_rwbuffer[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; + + 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; + case ACB_ADAPTER_TYPE_C: { + struct MessageUnit_C *reg = acb->pmuC; + char *acb_dev_map = (char *)acb-> |