summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/arcmsr
diff options
context:
space:
mode:
authorNick Cheng <nick.cheng@areca.com.tw>2007-09-13 17:26:40 +0800
committerJames Bottomley <jejb@mulgrave.localdomain>2007-10-12 14:48:27 -0400
commit1a4f550a09f89e3a15eff1971bc9db977571b9f6 (patch)
tree3ba5dea468391701664d4ca4c0b0e2a569521d89 /drivers/scsi/arcmsr
parentbfd129445f23c037d9a440ebfa4109e11c220301 (diff)
[SCSI] arcmsr: 1.20.00.15: add SATA RAID plus other fixes
Description: ** support ARC1200/1201/1202 SATA RAID adapter, which is named ACB_ADAPTER_TYPE_B ** modify the arcmsr_pci_slot_reset function ** modify the arcmsr_pci_ers_disconnect_forepart function ** modify the arcmsr_pci_ers_need_reset_forepart function  Signed-off-by: Nick Cheng <nick.cheng@areca.com.tw> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/arcmsr')
-rw-r--r--drivers/scsi/arcmsr/arcmsr.h192
-rw-r--r--drivers/scsi/arcmsr/arcmsr_attr.c64
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c2249
3 files changed, 1527 insertions, 978 deletions
diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h
index f0b8bf4534f0..ace7a15b413e 100644
--- a/drivers/scsi/arcmsr/arcmsr.h
+++ b/drivers/scsi/arcmsr/arcmsr.h
@@ -9,7 +9,7 @@
** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved.
**
** Web site: www.areca.com.tw
-** E-mail: erich@areca.com.tw
+** E-mail: support@areca.com.tw
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 2 as
@@ -45,19 +45,26 @@
#include <linux/interrupt.h>
struct class_device_attribute;
-
-#define ARCMSR_MAX_OUTSTANDING_CMD 256
-#define ARCMSR_MAX_FREECCB_NUM 288
-#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.14"
+/*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 2007/08/30"
#define ARCMSR_SCSI_INITIATOR_ID 255
#define ARCMSR_MAX_XFER_SECTORS 512
-#define ARCMSR_MAX_XFER_SECTORS_B 4096
-#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_MAX_XFER_SECTORS_B 4096
+#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_MAX_HBB_POSTQUEUE 264
+/*
+**********************************************************************************
+**
+**********************************************************************************
+*/
+#define ARC_SUCCESS 0
+#define ARC_FAILURE 1
/*
*******************************************************************************
** split 64bits dma addressing
@@ -90,7 +97,7 @@ struct CMD_MESSAGE_FIELD
uint8_t messagedatabuffer[1032];
};
/* IOP message transfer */
-#define ARCMSR_MESSAGE_FAIL 0x0001
+#define ARCMSR_MESSAGE_FAIL 0x0001
/* DeviceType */
#define ARECA_SATA_RAID 0x90000000
/* FunctionCode */
@@ -163,27 +170,27 @@ struct QBUFFER
};
/*
*******************************************************************************
-** FIRMWARE INFO
+** FIRMWARE INFO for Intel IOP R 80331 processor (Type A)
*******************************************************************************
*/
struct FIRMWARE_INFO
{
- uint32_t signature; /*0, 00-03*/
- uint32_t request_len; /*1, 04-07*/
- uint32_t numbers_queue; /*2, 08-11*/
+ uint32_t signature; /*0, 00-03*/
+ uint32_t request_len; /*1, 04-07*/
+ uint32_t numbers_queue; /*2, 08-11*/
uint32_t sdram_size; /*3, 12-15*/
- uint32_t ide_channels; /*4, 16-19*/
- char vendor[40]; /*5, 20-59*/
- char model[8]; /*15, 60-67*/
- char firmware_ver[16]; /*17, 68-83*/
- char device_map[16]; /*21, 84-99*/
+ uint32_t ide_channels; /*4, 16-19*/
+ char vendor[40]; /*5, 20-59*/
+ char model[8]; /*15, 60-67*/
+ char firmware_ver[16]; /*17, 68-83*/
+ char device_map[16]; /*21, 84-99*/
};
/* signature of set and get firmware config */
-#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
-#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063
+#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060
+#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063
/* message code of inbound message register */
-#define ARCMSR_INBOUND_MESG0_NOP 0x00000000
-#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001
+#define ARCMSR_INBOUND_MESG0_NOP 0x00000000
+#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001
#define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002
#define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003
#define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004
@@ -203,6 +210,60 @@ struct FIRMWARE_INFO
#define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000
/* outbound firmware ok */
#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000
+
+/*
+************************************************************************
+** SPEC. for Areca Type B adapter
+************************************************************************
+*/
+/* ARECA HBB COMMAND for its FIRMWARE */
+/* window of "instruction flags" from driver to iop */
+#define ARCMSR_DRV2IOP_DOORBELL 0x00020400
+#define ARCMSR_DRV2IOP_DOORBELL_MASK 0x00020404
+/* window of "instruction flags" from iop to driver */
+#define ARCMSR_IOP2DRV_DOORBELL 0x00020408
+#define ARCMSR_IOP2DRV_DOORBELL_MASK 0x0002040C
+/* ARECA FLAG LANGUAGE */
+/* ioctl transfer */
+#define ARCMSR_IOP2DRV_DATA_WRITE_OK 0x00000001
+/* ioctl transfer */
+#define ARCMSR_IOP2DRV_DATA_READ_OK 0x00000002
+#define ARCMSR_IOP2DRV_CDB_DONE 0x00000004
+#define ARCMSR_IOP2DRV_MESSAGE_CMD_DONE 0x00000008
+
+#define ARCMSR_DOORBELL_HANDLE_INT 0x0000000F
+#define ARCMSR_DOORBELL_INT_CLEAR_PATTERN 0xFF00FFF0
+#define ARCMSR_MESSAGE_INT_CLEAR_PATTERN 0xFF00FFF7
+/* (ARCMSR_INBOUND_MESG0_GET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_GET_CONFIG 0x00010008
+/* (ARCMSR_INBOUND_MESG0_SET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_SET_CONFIG 0x00020008
+/* (ARCMSR_INBOUND_MESG0_ABORT_CMD<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_ABORT_CMD 0x00030008
+/* (ARCMSR_INBOUND_MESG0_STOP_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_STOP_BGRB 0x00040008
+/* (ARCMSR_INBOUND_MESG0_FLUSH_CACHE<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_FLUSH_CACHE 0x00050008
+/* (ARCMSR_INBOUND_MESG0_START_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */
+#define ARCMSR_MESSAGE_START_BGRB 0x00060008
+#define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008
+#define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008
+/* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */
+#define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000
+/* ioctl transfer */
+#define ARCMSR_DRV2IOP_DATA_WRITE_OK 0x00000001
+/* ioctl transfer */
+#define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002
+#define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004
+#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008
+
+/* data tunnel buffer between user space program and its firmware */
+/* user space data to iop 128bytes */
+#define ARCMSR_IOCTL_WBUFFER 0x0000fe00
+/* iop data to user space 128bytes */
+#define ARCMSR_IOCTL_RBUFFER 0x0000ff00
+/* iop message_rwbuffer for message command */
+#define ARCMSR_MSGCODE_RWBUFFER 0x0000fa00
/*
*******************************************************************************
** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504)
@@ -214,7 +275,6 @@ struct ARCMSR_CDB
uint8_t TargetID;
uint8_t LUN;
uint8_t Function;
-
uint8_t CdbLength;
uint8_t sgcount;
uint8_t Flags;
@@ -224,20 +284,18 @@ struct ARCMSR_CDB
#define ARCMSR_CDB_FLAG_SIMPLEQ 0x00
#define ARCMSR_CDB_FLAG_HEADQ 0x08
#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10
- uint8_t Reserved1;
+ uint8_t Reserved1;
uint32_t Context;
uint32_t DataLength;
-
uint8_t Cdb[16];
-
uint8_t DeviceStatus;
-#define ARCMSR_DEV_CHECK_CONDITION 0x02
-#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0
-#define ARCMSR_DEV_ABORTED 0xF1
-#define ARCMSR_DEV_INIT_FAIL 0xF2
- uint8_t SenseData[15];
+#define ARCMSR_DEV_CHECK_CONDITION 0x02
+#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0
+#define ARCMSR_DEV_ABORTED 0xF1
+#define ARCMSR_DEV_INIT_FAIL 0xF2
+ uint8_t SenseData[15];
union
{
struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES];
@@ -246,10 +304,10 @@ struct ARCMSR_CDB
};
/*
*******************************************************************************
-** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331)
+** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor
*******************************************************************************
*/
-struct MessageUnit
+struct MessageUnit_A
{
uint32_t resrved0[4]; /*0000 000F*/
uint32_t inbound_msgaddr0; /*0010 0013*/
@@ -274,6 +332,30 @@ struct MessageUnit
uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/
uint32_t reserved6[32]; /*0F80 0FFF 32*/
};
+
+struct MessageUnit_B
+{
+ uint32_t post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+ uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE];
+ uint32_t postq_index;
+ uint32_t doneq_index;
+ uint32_t *drv2iop_doorbell_reg;
+ uint32_t *drv2iop_doorbell_mask_reg;
+ uint32_t *iop2drv_doorbell_reg;
+ uint32_t *iop2drv_doorbell_mask_reg;
+ uint32_t *msgcode_rwbuffer_reg;
+ uint32_t *ioctl_wbuffer_reg;
+ uint32_t *ioctl_rbuffer_reg;
+};
+
+struct MessageUnit
+{
+ union
+ {
+ struct MessageUnit_A pmu_A;
+ struct MessageUnit_B pmu_B;
+ } u;
+};
/*
*******************************************************************************
** Adapter Control Block
@@ -281,37 +363,45 @@ struct MessageUnit
*/
struct AdapterControlBlock
{
+ uint32_t adapter_type; /* adapter A,B..... */
+ #define ACB_ADAPTER_TYPE_A 0x00000001 /* hba I IOP */
+ #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 */
struct pci_dev * pdev;
struct Scsi_Host * host;
unsigned long vir2phy_offset;
/* Offset is used in making arc cdb physical to virtual calculations */
uint32_t outbound_int_enable;
- struct MessageUnit __iomem * pmu;
+ struct MessageUnit * pmu;
/* message unit ATU inbound base address0 */
uint32_t acb_flags;
-#define ACB_F_SCSISTOPADAPTER 0x0001
-#define ACB_F_MSG_STOP_BGRB 0x0002
+ #define ACB_F_SCSISTOPADAPTER 0x0001
+ #define ACB_F_MSG_STOP_BGRB 0x0002
/* stop RAID background rebuild */
-#define ACB_F_MSG_START_BGRB 0x0004
+ #define ACB_F_MSG_START_BGRB 0x0004
/* stop RAID background rebuild */
-#define ACB_F_IOPDATA_OVERFLOW 0x0008
+ #define ACB_F_IOPDATA_OVERFLOW 0x0008
/* iop message data rqbuffer overflow */
-#define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010
+ #define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010
/* message clear wqbuffer */
-#define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020
+ #define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020
/* message clear rqbuffer */
-#define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
-#define ACB_F_BUS_RESET 0x0080
-#define ACB_F_IOP_INITED 0x0100
+ #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040
+ #define ACB_F_BUS_RESET 0x0080
+ #define ACB_F_IOP_INITED 0x0100
/* iop init */
struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM];
/* used for memory free */
struct list_head ccb_free_list;
/* head of free ccb list */
+
atomic_t ccboutstandingcount;
+ /*The present outstanding command number that in the IOP that
+ waiting for being handled by FW*/
void * dma_coherent;
/* dma_coherent used for memory free */
@@ -353,7 +443,7 @@ struct CommandControlBlock
{
struct ARCMSR_CDB arcmsr_cdb;
/*
- ** 0-503 (size of CDB=504):
+ ** 0-503 (size of CDB = 504):
** arcmsr messenger scsi command descriptor size 504 bytes
*/
uint32_t cdb_shifted_phyaddr;
@@ -466,7 +556,9 @@ struct SENSE_DATA
#define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01
#define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F
-extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb);
+extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *);
+extern void arcmsr_iop_message_read(struct AdapterControlBlock *);
+extern struct QBUFFER *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *);
extern struct class_device_attribute *arcmsr_host_attrs[];
-extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb);
+extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *);
void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb);
diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c
index 06c0dce3b839..0f0a1ae99434 100644
--- a/drivers/scsi/arcmsr/arcmsr_attr.c
+++ b/drivers/scsi/arcmsr/arcmsr_attr.c
@@ -8,7 +8,7 @@
** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
**
** Web site: www.areca.com.tw
-** E-mail: erich@areca.com.tw
+** E-mail: support@areca.com.tw
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 2 as
@@ -49,6 +49,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/delay.h>
+#include <linux/pci.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -58,15 +59,11 @@
struct class_device_attribute *arcmsr_host_attrs[];
-static ssize_t
-arcmsr_sysfs_iop_message_read(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
uint8_t *pQbuffer,*ptmpQbuffer;
int32_t allxfer_len = 0;
@@ -85,12 +82,13 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj,
allxfer_len++;
}
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
- struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *)
- &reg->message_rbuffer;
- uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data;
+ struct QBUFFER *prbuffer;
+ uint8_t *iop_data;
int32_t iop_len;
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
+ prbuffer = arcmsr_get_iop_rqbuffer(acb);
+ iop_data = (uint8_t *)prbuffer->data;
iop_len = readl(&prbuffer->data_len);
while (iop_len > 0) {
acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data);
@@ -99,16 +97,12 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj,
iop_data++;
iop_len--;
}
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK,
- &reg->inbound_doorbell);
+ arcmsr_iop_message_read(acb);
}
return (allxfer_len);
}
-static ssize_t
-arcmsr_sysfs_iop_message_write(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
@@ -126,7 +120,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
wqbuf_lastindex = acb->wqbuf_lastindex;
wqbuf_firstindex = acb->wqbuf_firstindex;
if (wqbuf_lastindex != wqbuf_firstindex) {
- arcmsr_post_Qbuffer(acb);
+ arcmsr_post_ioctldata2iop(acb);
return 0; /*need retry*/
} else {
my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1)
@@ -144,7 +138,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) {
acb->acb_flags &=
~ACB_F_MESSAGE_WQBUFFER_CLEARED;
- arcmsr_post_Qbuffer(acb);
+ arcmsr_post_ioctldata2iop(acb);
}
return count;
} else {
@@ -153,15 +147,11 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj,
}
}
-static ssize_t
-arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj, char *buf, loff_t off, size_t count)
{
struct class_device *cdev = container_of(kobj,struct class_device,kobj);
struct Scsi_Host *host = class_to_shost(cdev);
struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
- struct MessageUnit __iomem *reg = acb->pmu;
uint8_t *pQbuffer;
if (!capable(CAP_SYS_ADMIN))
@@ -169,8 +159,7 @@ arcmsr_sysfs_iop_message_clear(struct kobject *kobj,
if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
- writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK
- , &reg->inbound_doorbell);
+ arcmsr_iop_message_read(acb);
}
acb->acb_flags |=
(ACB_F_MESSAGE_WQBUFFER_CLEARED
@@ -191,6 +180,7 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = {
.attr = {
.name = "mu_read",
.mode = S_IRUSR ,
+ .owner = THIS_MODULE,
},
.size = 1032,
.read = arcmsr_sysfs_iop_message_read,
@@ -200,6 +190,7 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = {
.attr = {
.name = "mu_write",
.mode = S_IWUSR,
+ .owner = THIS_MODULE,
},
.size = 1032,
.write = arcmsr_sysfs_iop_message_write,
@@ -209,6 +200,7 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = {
.attr = {
.name = "mu_clear",
.mode = S_IWUSR,
+ .owner = THIS_MODULE,
},
.size = 1,
.write = arcmsr_sysfs_iop_message_clear,
@@ -219,31 +211,26 @@ int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb)
struct Scsi_Host *host = acb->host;
int error;
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_read_attr);
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
if (error) {
printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n");
goto error_bin_file_message_read;
}
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_write_attr);
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
if (error) {
printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n");
goto error_bin_file_message_write;
}
- error = sysfs_create_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_clear_attr);
+ error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
if (error) {
printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n");
goto error_bin_file_message_clear;
}
return 0;
error_bin_file_message_clear:
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_write_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
error_bin_file_message_write:
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_read_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
error_bin_file_message_read:
return error;
}
@@ -252,12 +239,9 @@ void
arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) {
struct Scsi_Host *host = acb->host;
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_clear_attr);
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_write_attr);
- sysfs_remove_bin_file(&host->shost_classdev.kobj,
- &arcmsr_sysfs_message_read_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr);
+ sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr);
}
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 0ddfc21e9f7d..d70398ac64db 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -9,7 +9,7 @@
** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved
**
** Web site: www.areca.com.tw
-** E-mail: erich@areca.com.tw
+** E-mail: support@areca.com.tw
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License version 2 as
@@ -71,33 +71,37 @@
#include <scsi/scsicam.h>
#include "arcmsr.h"
-MODULE_AUTHOR("Erich Chen <erich@areca.com.tw>");
+MODULE_AUTHOR("Erich Chen <support@areca.com.tw>");
MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_VERSION(ARCMSR_DRIVER_VERSION);
-static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd);
+static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb,
+ struct scsi_cmnd *cmd);
+static int arcmsr_iop_confirm(struct AdapterControlBlock *acb);
static int arcmsr_abort(struct scsi_cmnd *);
static int arcmsr_bus_reset(struct scsi_cmnd *);
static int arcmsr_bios_param(struct scsi_device *sdev,
- struct block_device *bdev, sector_t capacity, int *info);
-static int arcmsr_queue_command(struct scsi_cmnd * cmd,
- void (*done) (struct scsi_cmnd *));
+ struct block_device *bdev, sector_t capacity, int *info);
+static int arcmsr_queue_command(struct scsi_cmnd *cmd,
+ void (*done) (struct scsi_cmnd *));
static int arcmsr_probe(struct pci_dev *pdev,
const struct pci_device_id *id);
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_stop_adapter_bgrb(struct AdapterControlBlock *acb);
-static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb);
-static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb);
+static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb);
+static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev,
pci_channel_state_t state);
static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev);
-static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
+static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
+ int queue_depth)
{
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
queue_depth = ARCMSR_MAX_CMD_PERLUN;
@@ -123,17 +127,21 @@ static struct scsi_host_template arcmsr_scsi_host_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = arcmsr_host_attrs,
};
+#ifdef CONFIG_SCSI_ARCMSR_AER
static struct pci_error_handlers arcmsr_pci_error_handlers = {
.error_detected = arcmsr_pci_error_detected,
.slot_reset = arcmsr_pci_slot_reset,
};
-
+#endif
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)},
@@ -153,20 +161,20 @@ static struct pci_driver arcmsr_pci_driver = {
.probe = arcmsr_probe,
.remove = arcmsr_remove,
.shutdown = arcmsr_shutdown,
+ #ifdef CONFIG_SCSI_ARCMSR_AER
.err_handler = &arcmsr_pci_error_handlers,
+ #endif
};
static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
{
irqreturn_t handle_state;
- struct AdapterControlBlock *acb;
- unsigned long flags;
-
- acb = (struct AdapterControlBlock *)dev_id;
+ struct AdapterControlBlock *acb = dev_id;
- spin_lock_irqsave(acb->host->host_lock, flags);
+ spin_lock(acb->host->host_lock);
handle_state = arcmsr_interrupt(acb);
- spin_unlock_irqrestore(acb->host->host_lock, flags);
+ spin_unlock(acb->host->host_lock);
+
return handle_state;
}
@@ -198,68 +206,159 @@ static int arcmsr_bios_param(struct scsi_device *sdev,
return 0;
}
-static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb)
+static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb)
{
struct pci_dev *pdev = acb->pdev;
- struct MessageUnit __iomem *reg = acb->pmu;
- u32 ccb_phyaddr_hi32;
- void *dma_coherent;
- dma_addr_t dma_coherent_handle, dma_addr;
- struct CommandControlBlock *ccb_tmp;
- int i, j;
+ u16 dev_id;
+ pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id);
+ switch (dev_id) {
+ case 0x1201 : {
+ acb->adapter_type = ACB_ADAPTER_TYPE_B;
+ }
+ break;
+
+ default : acb->adapter_type = ACB_ADAPTER_TYPE_A;
+ }
+}
- dma_coherent = dma_alloc_coherent(&pdev->dev,
+static int arcmsr_alloc_ccb_pool(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;
+ uint32_t intmask_org;
+ int i, j;
+
+ acb->pmu = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+ if (!acb->pmu) {
+ printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n",
+ acb->host->host_no);
+ }
+
+ dma_coherent = dma_alloc_coherent(&pdev->dev,
ARCMSR_MAX_FREECCB_NUM *
sizeof (struct CommandControlBlock) + 0x20,
&dma_coherent_handle, GFP_KERNEL);
- if (!dma_coherent)
- return -ENOMEM;
+ if (!dma_coherent)
+ return -ENOMEM;
- acb->dma_coherent = dma_coherent;
- acb->dma_coherent_handle = dma_coherent_handle;
+ 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));
- }
+ 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;
- for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
- ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
- ccb_tmp->acb = acb;
- acb->pccb_pool[i] = ccb_tmp;
- list_add_tail(&ccb_tmp->list, &acb->ccb_free_list);
- dma_addr = dma_addr + sizeof (struct CommandControlBlock);
- ccb_tmp++;
- }
+ dma_addr = dma_coherent_handle;
+ ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+ ccb_tmp->acb = acb;
+ acb->pccb_pool[i] = ccb_tmp;
+ 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_GOOD;
+ 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;
- /*
- ** here we need to tell iop 331 our ccb_tmp.HighPart
- ** if ccb_tmp.HighPart is not zero
- */
- ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16);
- if (ccb_phyaddr_hi32 != 0) {
- writel(ARCMSR_SIGNATURE_SET_CONFIG, &reg->message_rwbuffer[0]);
- writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);
- writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
- printk(KERN_NOTICE "arcmsr%d: "
- "'set ccb high part physical address' timeout\n",
- acb->host->host_no);
- }
+ /*
+ ** here we need to tell iop 331 our ccb_tmp.HighPart
+ ** if ccb_tmp.HighPart is not zero
+ */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ }
+ break;
+
+ case ACB_ADAPTER_TYPE_B: {
+
+ struct pci_dev *pdev = acb->pdev;
+ struct MessageUnit_B *reg;
+ void *mem_base0, *mem_base1;
+ void *dma_coherent;
+ dma_addr_t dma_coherent_handle, dma_addr;
+ uint32_t intmask_org;
+ 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)),
+ &dma_coherent_handle, GFP_KERNEL);
+ if (!dma_coherent)
+ return -ENOMEM;
- writel(readl(&reg->outbound_intmask) |
- ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE,
- &reg->outbound_intmask);
+ 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));
+ }
+
+ reg = (struct MessageUnit_B *)(dma_coherent +
+ ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock));
+
+ dma_addr = dma_coherent_handle;
+ ccb_tmp = (struct CommandControlBlock *)dma_coherent;
+ for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {
+ ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5;
+ ccb_tmp->acb = acb;
+ acb->pccb_pool[i] = ccb_tmp;
+ 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->pmu = (struct MessageUnit_B *)reg;
+ mem_base0 = ioremap(pci_resource_start(pdev, 0),
+ pci_resource_len(pdev, 0));
+ mem_base1 = ioremap(pci_resource_start(pdev, 2),
+ pci_resource_len(pdev, 2));
+ reg->drv2iop_doorbell_reg = (uint32_t *)((char *)mem_base0 +
+ ARCMSR_DRV2IOP_DOORBELL);
+ reg->drv2iop_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 +
+ ARCMSR_DRV2IOP_DOORBELL_MASK);
+ reg->iop2drv_doorbell_reg = (uint32_t *)((char *)mem_base0 +
+ ARCMSR_IOP2DRV_DOORBELL);
+ reg->iop2drv_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 +
+ ARCMSR_IOP2DRV_DOORBELL_MASK);
+ reg->ioctl_wbuffer_reg = (uint32_t *)((char *)mem_base1 +
+ ARCMSR_IOCTL_WBUFFER);
+ reg->ioctl_rbuffer_reg = (uint32_t *)((char *)mem_base1 +
+ ARCMSR_IOCTL_RBUFFER);
+ reg->msgcode_rwbuffer_reg = (uint32_t *)((char *)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;
+
+ /*
+ ** here we need to tell iop 331 our ccb_tmp.HighPart
+ ** if ccb_tmp.HighPart is not zero
+ */
+ intmask_org = arcmsr_disable_outbound_ints(acb);
+ }
+ break;
+ }
return 0;
}
@@ -310,16 +409,11 @@ static int arcmsr_probe(struct pci_dev *pdev,
host->unique_id = (bus << 8) | dev_fun;
host->irq = pdev->irq;
error = pci_request_regions(pdev, "arcmsr");
- if (error)
+ if (error) {
goto out_host_put;
-
- acb->pmu = ioremap(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0));
- if (!acb->pmu) {
- printk(KERN_NOTICE "arcmsr%d: memory"
- " mapping region fail \n", acb->host->host_no);
- goto out_release_regions;
}
+ arcmsr_define_adapter_type(acb);
+
acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |
ACB_F_MESSAGE_RQBUFFER_CLEARED |
ACB_F_MESSAGE_WQBUFFER_READED);
@@ -328,10 +422,10 @@ static int arcmsr_probe(struct pci_dev *pdev,
error = arcmsr_alloc_ccb_pool(acb);
if (error)
- goto out_iounmap;
+ goto out_release_regions;
error = request_irq(pdev->irq, arcmsr_do_interrupt,
- IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb);
+ IRQF_SHARED, "arcmsr", acb);
if (error)
goto out_free_ccb_pool;
@@ -349,14 +443,15 @@ static int arcmsr_probe(struct pci_dev *pdev,
goto out_free_sysfs;
scsi_scan_host(host);
+ #ifdef CONFIG_SCSI_ARCMSR_AER
pci_enable_pcie_error_reporting(pdev);
+ #endif
return 0;
out_free_sysfs:
out_free_irq:
free_irq(pdev->irq, acb);
out_free_ccb_pool:
arcmsr_free_ccb_pool(acb);
- out_iounmap:
iounmap(acb->pmu);
out_release_regions:
pci_release_regions(pdev);
@@ -368,17 +463,84 @@ static int arcmsr_probe(struct pci_dev *pdev,
return error;
}
-static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb)
+static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
+ uint32_t Index;
+ uint8_t Retries = 0x00;
+
+ do {
+ for (Index = 0; Index < 100; Index++) {
+ if (readl(&reg->outbound_intstatus) &
+ ARCMSR_MU_OUTBOUND_MESSAGE0_INT) {
+ writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT,
+ &reg->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 = (struct MessageUnit_B *)acb->pmu;
+ 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);
+ return 0x00;
+ }
+ msleep(10);
+ }/*max 1 seconds*/
+
+ } while (Retries++ < 20);/*max 20 sec*/
+ return 0xff;
+}
+
+static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb)
{
- struct MessageUnit __iomem *reg = acb->pmu;
+ struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu;
writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, &reg->inbound_msgaddr0);
- if (arcmsr_wait_msgint_ready(acb))
+ if (arcmsr_hba_wait_msgint_ready(acb))
printk(KERN_NOTICE
"arcmsr%d: wait 'abort all outstanding command' timeout \n"
, acb->host->host_no);
}
+static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb)
+{
+ struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu;
+
+ writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg);
+ if (arcmsr_hbb_wait_msgint_ready(acb))
+ printk(KERN_NOTICE
+ "arcmsr%d: wait 'abort all outstanding command' timeout \n"