* [PATCH] Marvell 6440 SAS/SATA driver
[not found] <20080122151857.GA8680@ubuntu.domain>
@ 2008-01-22 15:24 ` Ke Wei
2008-01-23 3:58 ` Jeff Garzik
0 siblings, 1 reply; 22+ messages in thread
From: Ke Wei @ 2008-01-22 15:24 UTC (permalink / raw)
To: linux-scsi; +Cc: kewei, qswang, jfeng, qzhao, jeff
This is Marvell 88SE6440 SAS/SATA HBA support for kernel version 2.6.24-rc8
which is 'sas' branch of
git://git.kernel.org/pub/scm/linux/kernel/git/jgarzik/misc-2.6.git .
Marvell 6440 SAS/SATA non-raid driver supports SAS HDD , SATA Devices(ATA/ATAPI)
.
No support for Wide Port , SATA PM , Expander and Hot plug.
I disabled PCI MSI at the kernel boot prompt , so the driver will work failed
for this version if using MSI .
Signed-off-by: Ke Wei <kewei@marvell.com>
---
drivers/scsi/mvsas.c | 1241 ++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 998 insertions(+), 243 deletions(-)
mode change 100644 => 100755 drivers/scsi/mvsas.c
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
old mode 100644
new mode 100755
index e31ed5a..fb376a7
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -2,6 +2,7 @@
mvsas.c - Marvell 88SE6440 SAS/SATA support
Copyright 2007 Red Hat, Inc.
+ Copyright 2008 Marvell. <kewei@marvell.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -37,8 +38,13 @@
#include <scsi/libsas.h>
#include <asm/io.h>
-#define DRV_NAME "mvsas"
-#define DRV_VERSION "0.1"
+#define DRV_NAME "mvsas"
+#define DRV_VERSION "0.3"
+#define _MV_DUMP 0
+#define MVS_DISABLE_NVRAM
+#define MVS_QUEUE_SIZE (30)
+#define MVS_PRINTK(_x_, ...) \
+ printk(KERN_NOTICE DRV_NAME ": " _x_ , ## __VA_ARGS__)
#define mr32(reg) readl(regs + MVS_##reg)
#define mw32(reg,val) writel((val), regs + MVS_##reg)
@@ -47,6 +53,65 @@
readl(regs + MVS_##reg); \
} while (0)
+#define MVS_BIT(x) (1L << (x))
+
+#define PORT_TYPE_SATA MVS_BIT(0)
+#define PORT_TYPE_SAS MVS_BIT(1)
+
+#define MVS_ID_NOT_MAPPED 0xff
+#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
+
+/* offset for D2H FIS in the Received FIS List Structure */
+#define SATA_RECEIVED_D2H_FIS(reg_set) \
+ (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
+#define SATA_RECEIVED_PIO_FIS(reg_set) \
+ (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
+#define UNASSOC_D2H_FIS(id) \
+ (mvi->rx_fis + 0x100 * id)
+
+
+#define READ_PORT_CONFIG_DATA(i) \
+ ((i > 3)?mr32(P4_CFG_DATA + (i - 4) * 8):mr32(P0_CFG_DATA + i * 8))
+#define WRITE_PORT_CONFIG_DATA(i,tmp) \
+ {if (i > 3)mw32(P4_CFG_DATA + (i - 4) * 8, tmp); \
+ else \
+ mw32(P0_CFG_DATA + i * 8, tmp); }
+#define WRITE_PORT_CONFIG_ADDR(i,tmp) \
+ {if (i > 3)mw32(P4_CFG_ADDR + (i - 4) * 8, tmp); \
+ else \
+ mw32(P0_CFG_ADDR + i * 8, tmp); }
+
+#define READ_PORT_PHY_CONTROL(i) \
+ ((i > 3)?mr32(P4_SER_CTLSTAT + (i - 4) * 4):mr32(P0_SER_CTLSTAT+i * 4))
+#define WRITE_PORT_PHY_CONTROL(i,tmp) \
+ {if (i > 3)mw32(P4_SER_CTLSTAT + (i - 4) * 4, tmp); \
+ else \
+ mw32(P0_SER_CTLSTAT + i * 4, tmp); }
+
+#define READ_PORT_VSR_DATA(i) \
+ ((i > 3)?mr32(P4_VSR_DATA + (i - 4) * 8):mr32(P0_VSR_DATA+i*8))
+#define WRITE_PORT_VSR_DATA(i,tmp) \
+ {if (i > 3)mw32(P4_VSR_DATA + (i - 4) * 8, tmp); \
+ else \
+ mw32(P0_VSR_DATA + i*8, tmp); }
+#define WRITE_PORT_VSR_ADDR(i,tmp) \
+ {if (i > 3)mw32(P4_VSR_ADDR + (i - 4) * 8, tmp); \
+ else \
+ mw32(P0_VSR_ADDR + i * 8, tmp); }
+
+#define READ_PORT_IRQ_STAT(i) \
+ ((i > 3)?mr32(P4_INT_STAT + (i - 4) * 8):mr32(P0_INT_STAT + i * 8))
+#define WRITE_PORT_IRQ_STAT(i,tmp) \
+ {if (i > 3)mw32(P4_INT_STAT + (i-4) * 8, tmp); \
+ else \
+ mw32(P0_INT_STAT + i * 8, tmp); }
+#define READ_PORT_IRQ_MASK(i) \
+ ((i > 3)?mr32(P4_INT_MASK + (i-4) * 8):mr32(P0_INT_MASK+i*8))
+#define WRITE_PORT_IRQ_MASK(i,tmp) \
+ {if (i > 3)mw32(P4_INT_MASK + (i-4) * 8, tmp); \
+ else \
+ mw32(P0_INT_MASK + i * 8, tmp); }
+
/* driver compile-time configuration */
enum driver_configuration {
MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */
@@ -57,7 +122,7 @@ enum driver_configuration {
MVS_SLOTS = 512, /* command slots */
MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */
MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */
- MVS_ATA_CMD_SZ = 128, /* SATA command table buffer size */
+ MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */
MVS_OAF_SZ = 64, /* Open address frame buffer size */
MVS_RX_FIS_COUNT = 17, /* Optional rx'd FISs (max 17) */
@@ -89,7 +154,7 @@ enum hw_registers {
MVS_GBL_CTL = 0x04, /* global control */
MVS_GBL_INT_STAT = 0x08, /* global irq status */
MVS_GBL_PI = 0x0C, /* ports implemented bitmask */
- MVS_GBL_PORT_TYPE = 0x00, /* port type */
+ MVS_GBL_PORT_TYPE = 0xa0, /* port type */
MVS_CTL = 0x100, /* SAS/SATA port configuration */
MVS_PCS = 0x104, /* SAS/SATA port control/status */
@@ -102,11 +167,12 @@ enum hw_registers {
MVS_TX_LO = 0x124, /* TX (delivery) ring addr */
MVS_TX_HI = 0x128,
- MVS_RX_PROD_IDX = 0x12C, /* RX producer pointer */
- MVS_RX_CONS_IDX = 0x130, /* RX consumer pointer (RO) */
+ MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */
+ MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */
MVS_RX_CFG = 0x134, /* RX configuration */
MVS_RX_LO = 0x138, /* RX (completion) ring addr */
MVS_RX_HI = 0x13C,
+ MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */
MVS_INT_COAL = 0x148, /* Int coalescing config */
MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */
@@ -117,9 +183,12 @@ enum hw_registers {
/* ports 1-3 follow after this */
MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */
MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */
+ MVS_P4_INT_STAT = 0x200, /* Port 4 interrupt status */
+ MVS_P4_INT_MASK = 0x204, /* Port 4 interrupt enable mask */
/* ports 1-3 follow after this */
MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */
+ MVS_P4_SER_CTLSTAT = 0x220, /* port4 serial control/status */
MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */
MVS_CMD_DATA = 0x1BC, /* Command register port (data) */
@@ -127,6 +196,14 @@ enum hw_registers {
/* ports 1-3 follow after this */
MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */
MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */
+ MVS_P4_CFG_ADDR = 0x230, /* Port 4 config address */
+ MVS_P4_CFG_DATA = 0x234, /* Port 4 config data */
+
+ /* ports 1-3 follow after this */
+ MVS_P0_VSR_ADDR = 0x1E0, /* port0 VSR address */
+ MVS_P0_VSR_DATA = 0x1E4, /* port0 VSR data */
+ MVS_P4_VSR_ADDR = 0x250, /* port 4 VSR addr */
+ MVS_P4_VSR_DATA = 0x254, /* port 4 VSR data */
};
enum hw_register_bits {
@@ -140,12 +217,35 @@ enum hw_register_bits {
/* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */
SATA_TARGET = (1U << 16), /* port0 SATA target enable */
- AUTO_DET = (1U << 8), /* port0 SAS/SATA autodetect */
- SAS_MODE = (1U << 0), /* port0 SAS(1), SATA(0) mode */
- /* SAS_MODE value may be
- * dictated (in hw) by values
- * of SATA_TARGET & AUTO_DET
- */
+ MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */
+ MODE_AUTO_DET_PORT6 = (1U << 14),
+ MODE_AUTO_DET_PORT5 = (1U << 13),
+ MODE_AUTO_DET_PORT4 = (1U << 12),
+ MODE_AUTO_DET_PORT3 = (1U << 11),
+ MODE_AUTO_DET_PORT2 = (1U << 10),
+ MODE_AUTO_DET_PORT1 = (1U << 9),
+ MODE_AUTO_DET_PORT0 = (1U << 8),
+ MODE_AUTO_DET_EN = MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
+ MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
+ MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
+ MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
+ MODE_SAS_PORT7_MASK = (1U << 7), /* port0 SAS(1), SATA(0) mode */
+ MODE_SAS_PORT6_MASK = (1U << 6),
+ MODE_SAS_PORT5_MASK = (1U << 5),
+ MODE_SAS_PORT4_MASK = (1U << 4),
+ MODE_SAS_PORT3_MASK = (1U << 3),
+ MODE_SAS_PORT2_MASK = (1U << 2),
+ MODE_SAS_PORT1_MASK = (1U << 1),
+ MODE_SAS_PORT0_MASK = (1U << 0),
+ MODE_SAS_SATA = MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
+ MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
+ MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
+ MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
+
+ /* SAS_MODE value may be
+ * dictated (in hw) by values
+ * of SATA_TARGET & AUTO_DET
+ */
/* MVS_TX_CFG */
TX_EN = (1U << 16), /* Enable TX */
@@ -167,12 +267,14 @@ enum hw_register_bits {
CINT_MEM = (1U << 26), /* int mem parity err */
CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */
CINT_SRS = (1U << 3), /* SRS event */
- CINT_CI_STOP = (1U << 10), /* cmd issue stopped */
+ CINT_CI_STOP = (1U << 1), /* cmd issue stopped */
CINT_DONE = (1U << 0), /* cmd completion */
/* shl for ports 1-3 */
CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */
- CINT_PORT = (1U << 8), /* port0 event */
+ CINT_PORT = (1U << 8), /* port0 event */
+ CINT_PORT_MASK_OFFSET = 8,
+ CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET),
/* TX (delivery) ring bits */
TXQ_CMD_SHIFT = 29,
@@ -239,6 +341,12 @@ enum hw_register_bits {
PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */
PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */
PHY_RST = (1U << 0), /* phy reset */
+ PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
+ PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
+ (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
+ PHY_READY_MASK = (1U << 20),
/* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */
@@ -260,13 +368,33 @@ enum hw_register_bits {
PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */
/* MVS_PCS */
+ PCS_EN_SATA_REG = (16), /* Enable SATA Register Set*/
+ PCS_EN_PORT_XMT_START = (12), /* Enable Port Transmit*/
+ PCS_EN_PORT_XMT_START2 = (8), /* For 6480*/
PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */
PCS_RSP_RX_EN = (1U << 7), /* raw response rx */
PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */
PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */
PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */
- PCS_CMD_RST = (1U << 2), /* reset cmd issue */
+ PCS_CMD_RST = (1U << 1), /* reset cmd issue */
PCS_CMD_EN = (1U << 0), /* enable cmd issue */
+
+ /*Port n Attached Device Info*/
+ PORT_DEV_SSP_TRGT = (1U << 19),
+ PORT_DEV_SMP_TRGT = (1U << 18),
+ PORT_DEV_STP_TRGT = (1U << 17),
+ PORT_DEV_SSP_INIT = (1U << 11),
+ PORT_DEV_SMP_INIT = (1U << 10),
+ PORT_DEV_STP_INIT = (1U << 9),
+ PORT_PHY_ID_MASK = (0xFFU << 24),
+ PORT_DEV_TRGT_MASK = (0x7U << 17),
+ PORT_DEV_INIT_MASK = (0x7U << 9),
+ PORT_DEV_TYPE_MASK = (0x7U << 0),
+
+ /*Port n PHY Status*/
+ PHY_RDY = (1U << 2),
+ PHY_DW_SYNC = (1U << 1),
+ PHY_OOB_DTCTD = (1U << 0),
};
enum mvs_info_flags {
@@ -329,14 +457,20 @@ enum sas_cmd_port_registers {
/* SAS/SATA configuration port registers, aka phy registers */
enum sas_sata_config_port_regs {
- PHYR_IDENTIFY = 0x0, /* info for IDENTIFY frame */
- PHYR_ADDR_LO = 0x4, /* my SAS address (low) */
- PHYR_ADDR_HI = 0x8, /* my SAS address (high) */
- PHYR_ATT_DEV_INFO = 0xC, /* attached device info */
+ PHYR_IDENTIFY = 0x00, /* info for IDENTIFY frame */
+ PHYR_ADDR_LO = 0x04, /* my SAS address (low) */
+ PHYR_ADDR_HI = 0x08, /* my SAS address (high) */
+ PHYR_ATT_DEV_INFO = 0x0C, /* attached device info */
PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */
PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */
PHYR_SATA_CTL = 0x18, /* SATA control */
PHYR_PHY_STAT = 0x1C, /* PHY status */
+ PHYR_SATA_SIG0 = 0x20, /*port SATA signature FIS(Byte 0-3) */
+ PHYR_SATA_SIG1 = 0x24, /*port SATA signature FIS(Byte 4-7) */
+ PHYR_SATA_SIG2 = 0x28, /*port SATA signature FIS(Byte 8-11) */
+ PHYR_SATA_SIG3 = 0x2c, /*port SATA signature FIS(Byte 12-15) */
+ PHYR_R_ERR_COUNT = 0x30, /* port R_ERR count register */
+ PHYR_CRC_ERR_COUNT = 0x34, /* port CRC error count register */
PHYR_WIDE_PORT = 0x38, /* wide port participating */
PHYR_CURRENT0 = 0x80, /* current connection info 0 */
PHYR_CURRENT1 = 0x84, /* current connection info 1 */
@@ -344,18 +478,21 @@ enum sas_sata_config_port_regs {
};
enum pci_cfg_registers {
- PCR_PHY_CTL = 0x40,
- PCR_PHY_CTL2 = 0x90,
+ PCR_PHY_CTL = 0x40,
+ PCR_PHY_CTL2 = 0x90,
+ PCR_DEV_CTRL = 0xE8,
};
enum pci_cfg_register_bits {
- PCTL_PWR_ON = (0xFU << 24),
- PCTL_OFF = (0xFU << 12),
+ PCTL_PWR_ON = (0xFU << 24),
+ PCTL_OFF = (0xFU << 12),
+ PRD_REQ_SIZE = (0x4000),
+ PRD_REQ_MASK = (0x00007000),
};
enum nvram_layout_offsets {
- NVR_SIG = 0x00, /* 0xAA, 0x55 */
- NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */
+ NVR_SIG = 0x00, /* 0xAA, 0x55 */
+ NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */
};
enum chip_flavors {
@@ -365,9 +502,9 @@ enum chip_flavors {
};
struct mvs_chip_info {
- unsigned int n_phy;
- unsigned int srs_sz;
- unsigned int slot_width;
+ u32 n_phy;
+ u32 srs_sz;
+ u32 slot_width;
};
struct mvs_err_info {
@@ -408,13 +545,24 @@ struct mvs_slot_info {
struct mvs_port {
struct asd_sas_port sas_port;
+ u8 taskfileset;
};
struct mvs_phy {
struct mvs_port *port;
struct asd_sas_phy sas_phy;
+ struct sas_identify identify;
+ __le32 devinfo;
+ __le64 devsasaddr;
+ __le32 attdevinfo;
+ __le64 attdevsasaddr;
+ u32 type;
+ __le32 phystatus;
+ __le32 irqstatus;
+ u8 wideportphymap;
+ u32 frame_rcvd_size;
+ u8 frame_rcvd[32];
- u8 frame_rcvd[24 + 1024];
};
struct mvs_info {
@@ -437,27 +585,39 @@ struct mvs_info {
dma_addr_t rx_dma;
u32 rx_cons; /* RX consumer idx */
- __le32 *rx_fis; /* RX'd FIS area */
+ void *rx_fis; /* RX'd FIS area */
dma_addr_t rx_fis_dma;
- struct mvs_cmd_hdr *slot; /* DMA command header slots */
+ struct mvs_cmd_hdr *slot; /* DMA command header slots */
dma_addr_t slot_dma;
const struct mvs_chip_info *chip;
- /* further per-slot information */
+ unsigned long tags[MVS_SLOTS];
struct mvs_slot_info slot_info[MVS_SLOTS];
- unsigned long tags[(MVS_SLOTS / sizeof(unsigned long)) + 1];
-
+ /* further per-slot information */
struct mvs_phy phy[MVS_MAX_PHYS];
struct mvs_port port[MVS_MAX_PHYS];
+
+ u32 can_queue; /* per adapter */
+ u32 tag_out; /*Get*/
+ u32 tag_in; /*Give*/
+};
+
+struct mvs_queue_task {
+ struct list_head list;
+
+ void *uldd_task;
};
+static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
+static void mvs_scan_start(struct Scsi_Host *);
+
static struct scsi_transport_template *mvs_stt;
static const struct mvs_chip_info mvs_chips[] = {
- [chip_6320] = { 2, 16, 9 },
- [chip_6440] = { 4, 16, 9 },
+ [chip_6320] = { 2, 16, 9 },
+ [chip_6440] = { 4, 16, 9 },
[chip_6480] = { 8, 32, 10 },
};
@@ -468,6 +628,8 @@ static struct scsi_host_template mvs_sht = {
.target_alloc = sas_target_alloc,
.slave_configure = sas_slave_configure,
.slave_destroy = sas_slave_destroy,
+ .scan_finished = mvs_scan_finished,
+ .scan_start = mvs_scan_start,
.change_queue_depth = sas_change_queue_depth,
.change_queue_type = sas_change_queue_type,
.bios_param = sas_bios_param,
@@ -477,14 +639,154 @@ static struct scsi_host_template mvs_sht = {
.sg_tablesize = SG_ALL,
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING,
- .eh_device_reset_handler= sas_eh_device_reset_handler,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
};
-static void mvs_int_rx(struct mvs_info *mvi, bool self_clear);
+static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
+{
+ u32 i;
+ u32 run;
+ u32 offset;
+
+ offset = 0;
+ while (size) {
+ printk("%08X : ", baseaddr + offset);
+ if (size >= 16)
+ run = 16;
+ else
+ run = size;
+ size -= run;
+ for (i = 0; i < 16; i++) {
+ if (i < run)
+ printk("%02X ", (unsigned int)data[i]);
+ else
+ printk(" ");
+ }
+ printk(": ");
+ for (i = 0; i < run; i++)
+ printk("%c", isalnum(data[i]) ? data[i] : '.');
+ printk("\n");
+ data = &data[16];
+ offset += run;
+ }
+ printk("\n");
+}
+
+static inline void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
+ enum sas_proto proto)
+{
+ u32 offset;
+ u32 len_ct;
+
+ if (sas_protocol_ata(proto))
+ len_ct = MVS_ATA_CMD_SZ;
+ else
+ len_ct = MVS_SSP_CMD_SZ;
+
+ offset =
+ len_ct + MVS_OAF_SZ +
+ sizeof(struct mvs_prd) * mvi->slot_info[tag].n_elem;
+ MVS_PRINTK("+---->Status buffer :\n");
+ mvs_hexdump(32, (u8 *) mvi->slot_info[tag].response,
+ (u32) mvi->slot_info[tag].buf_dma + offset);
+}
+
+static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
+ enum sas_proto proto)
+{
+#if _MV_DUMP
+ u32 sz, w_ptr, r_ptr;
+ u64 addr;
+ void __iomem *regs = mvi->regs;
+ u32 len_ct;
+
+ if (sas_protocol_ata(proto))
+ len_ct = MVS_ATA_CMD_SZ;
+ else
+ len_ct = MVS_SSP_CMD_SZ;
+
+ /*Delivery Queue */
+ sz = mr32(TX_CFG) & TX_RING_SZ_MASK;
+ w_ptr = mr32(TX_PROD_IDX) & TX_RING_SZ_MASK;
+ r_ptr = mr32(TX_CONS_IDX) & TX_RING_SZ_MASK;
+ addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO);
+ MVS_PRINTK("Delivery Queue Size=%04d , WRT_PTR=%04X , RD_PTR=%04X\n",
+ sz, w_ptr, r_ptr);
+ MVS_PRINTK
+ ("Delivery Queue Base Address=0x%llX (PA)"
+ "(tx_dma=0x%llX), Entry=%04d\n",
+ addr, mvi->tx_dma, w_ptr);
+ mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
+ (u32) mvi->tx_dma + sizeof(u32) * w_ptr);
+ /*Command List */
+ addr = mr32(CMD_LIST_HI) << 16 << 16 | mr32(CMD_LIST_LO);
+ MVS_PRINTK
+ ("Command List Base Address=0x%llX (PA)"
+ "(slot_dma=0x%llX), Header=%03d\n",
+ addr, mvi->slot_dma, tag);
+ MVS_PRINTK("Command Header[%03d]:\n", tag);
+ /*mvs_cmd_hdr */
+ mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
+ (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
+ /*1.command table area */
+ MVS_PRINTK("+---->Command Table :\n");
+ mvs_hexdump(len_ct, (u8 *) mvi->slot_info[tag].buf,
+ (u32) mvi->slot_info[tag].buf_dma);
+ /*2.open address frame area */
+ MVS_PRINTK("+---->Open Address Frame :\n");
+ mvs_hexdump(MVS_OAF_SZ, (u8 *) mvi->slot_info[tag].buf + len_ct,
+ (u32) mvi->slot_info[tag].buf_dma + len_ct);
+ /*3.status buffer */
+ mvs_hba_sb_dump(mvi, tag, proto);
+ /*4.PRD table */
+ MVS_PRINTK("+---->PRD table :\n");
+ mvs_hexdump(sizeof(struct mvs_prd) * mvi->slot_info[tag].n_elem,
+ (u8 *) mvi->slot_info[tag].buf + len_ct + MVS_OAF_SZ,
+ (u32) mvi->slot_info[tag].buf_dma + len_ct + MVS_OAF_SZ);
+#endif
+}
+
+static void mvs_hba_cq_dump(struct mvs_info *mvi)
+{
+#if _MV_DUMP
+ u64 addr;
+ void __iomem *regs = mvi->regs;
+ u32 entry = mvi->rx_cons + 1;
+ u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
+ /*Completion Queue */
+ addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
+ MVS_PRINTK("Completion Task = 0x%08X\n",
+ (u32) mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
+ MVS_PRINTK
+ ("Completion List Base Address=0x%llX (PA), "
+ "CQ_Entry=%04d, CQ_WP=0x%08X\n",
+ addr, entry - 1, mvi->rx[0]);
+ mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
+ mvi->rx_dma + sizeof(u32) * entry);
+#endif
+}
+
+static void mvs_hba_interrupt_enable(struct mvs_info *mvi, int enable)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mvi->lock, flags);
+ tmp = mr32(GBL_CTL);
+
+ if (enable)
+ mw32(GBL_CTL, tmp | INT_EN);
+ else
+ mw32(GBL_CTL, tmp & ~INT_EN);
+ spin_unlock_irqrestore(&mvi->lock, flags);
+}
+
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
/* move to PCI layer or libata core? */
static int pci_go_64(struct pci_dev *pdev)
@@ -519,38 +821,37 @@ static int pci_go_64(struct pci_dev *pdev)
return rc;
}
-static void mvs_tag_clear(struct mvs_info *mvi, unsigned int tag)
+static inline void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
{
- mvi->tags[tag / sizeof(unsigned long)] &=
- ~(1UL << (tag % sizeof(unsigned long)));
+ mvi->tag_in = (mvi->tag_in + 1) & (MVS_SLOTS - 1);
+ mvi->tags[mvi->tag_in] = tag;
}
-static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
+static inline void mvs_tag_free(struct mvs_info *mvi, u32 tag)
{
- mvi->tags[tag / sizeof(unsigned long)] |=
- (1UL << (tag % sizeof(unsigned long)));
+ mvi->tag_out = (mvi->tag_out - 1) & (MVS_SLOTS - 1);
}
-static bool mvs_tag_test(struct mvs_info *mvi, unsigned int tag)
+static inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
{
- return mvi->tags[tag / sizeof(unsigned long)] &
- (1UL << (tag % sizeof(unsigned long)));
+ if (mvi->tag_out != mvi->tag_in) {
+ *tag_out = mvi->tags[mvi->tag_out];
+ mvi->tag_out = (mvi->tag_out + 1) & (MVS_SLOTS - 1);
+ return 0;
+ }
+ return -EBUSY;
}
-static int mvs_tag_alloc(struct mvs_info *mvi, unsigned int *tag_out)
+static void mvs_tag_init(struct mvs_info *mvi)
{
- unsigned int i;
-
- for (i = 0; i < MVS_SLOTS; i++)
- if (!mvs_tag_test(mvi, i)) {
- mvs_tag_set(mvi, i);
- *tag_out = i;
- return 0;
- }
-
- return -EBUSY;
+ int i;
+ for (i = 0; i < MVS_SLOTS; ++i)
+ mvi->tags[i] = i;
+ mvi->tag_out = 0;
+ mvi->tag_in = MVS_SLOTS - 1;
}
+#ifndef MVS_DISABLE_NVRAM
static int mvs_eep_read(void __iomem *regs, unsigned int addr, u32 *data)
{
int timeout = 1000;
@@ -592,7 +893,7 @@ static int mvs_eep_read_buf(void __iomem *regs, unsigned int
addr,
if (rc)
return rc;
- tmp8 = (u8 *) &tmp;
+ tmp8 = (u8 *)&tmp;
for (i = j; i < 4; i++)
*buf8++ = tmp8[i];
@@ -613,7 +914,7 @@ static int mvs_eep_read_buf(void __iomem *regs, unsigned int
addr,
if (rc)
return rc;
- tmp8 = (u8 *) &tmp;
+ tmp8 = (u8 *)&tmp;
j = addr_end - tmp_addr;
for (i = 0; i < j; i++)
*buf8++ = tmp8[i];
@@ -623,10 +924,12 @@ static int mvs_eep_read_buf(void __iomem *regs, unsigned
int addr,
return 0;
}
+#endif
static int mvs_nvram_read(struct mvs_info *mvi, unsigned int addr,
void *buf, unsigned int buflen)
{
+#ifndef MVS_DISABLE_NVRAM
void __iomem *regs = mvi->regs;
int rc, i;
unsigned int sum;
@@ -644,7 +947,8 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned int
addr,
goto err_out;
}
- if (hdr[0] != 0x5A) { /* entry id */
+ if (hdr[0] != 0x5A) {
+ /* entry id */
msg = "invalid nvram entry id";
rc = -ENOENT;
goto err_out;
@@ -666,11 +970,53 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned
int addr,
err_out:
dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
return rc;
+#else
+ memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
+ return 0;
+#endif
+}
+
+static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ /* give the phy enabling interrupt event time to come in (1s
+ * is empirically about all it takes) */
+ if (time < HZ)
+ return 0;
+ /* Wait for discovery to finish */
+ scsi_flush_work(shost);
+ return 1;
+}
+
+static void mvs_scan_start(struct Scsi_Host *shost)
+{
+ int i;
+ struct sas_identify_frame *id;
+ struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
+
+ for (i = 0; i < mvi->chip->n_phy; ++i) {
+ struct mvs_phy *phy = &mvi->phy[i];
+ id = (struct sas_identify_frame *)phy->frame_rcvd;
+ if (phy->type & PORT_TYPE_SAS) {
+ id->dev_type = phy->identify.device_type;
+ id->initiator_bits = SAS_PROTO_ALL;
+ id->target_bits = phy->identify.target_port_protocols;
+ } else if (phy->type & PORT_TYPE_SATA) {
+ }
+ mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
+ mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
+ PORTE_BYTES_DMAED);
+ }
+
}
static void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events)
{
- /* FIXME */
+ void __iomem *regs = mvi->regs;
+ /*
+ events is port event.now ,
+ we need check the interrupt status which belongs to per port.
+ */
+ MVS_PRINTK("Port0 = %d", READ_PORT_IRQ_STAT(0));
}
static void mvs_int_sata(struct mvs_info *mvi)
@@ -681,9 +1027,10 @@ static void mvs_int_sata(struct mvs_info *mvi)
static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
struct mvs_slot_info *slot, unsigned int slot_idx)
{
- if (slot->n_elem)
- pci_unmap_sg(mvi->pdev, task->scatter,
- slot->n_elem, task->data_dir);
+ if (!sas_protocol_ata(task->task_proto))
+ if (slot->n_elem)
+ pci_unmap_sg(mvi->pdev, task->scatter,
+ slot->n_elem, task->data_dir);
switch (task->task_proto) {
case SAS_PROTO_SMP:
@@ -708,9 +1055,34 @@ static void mvs_slot_err(struct mvs_info *mvi, struct
sas_task *task,
unsigned int slot_idx)
{
/* FIXME */
+ mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
}
-static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
+static inline int mvs_can_queue(struct mvs_info *mvi, int num)
+{
+ int res = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mvi->lock, flags);
+ if ((mvi->can_queue - num) < 0)
+ res = -EBUSY;
+ else
+ mvi->can_queue -= num;
+ spin_unlock_irqrestore(&mvi->lock, flags);
+
+ return res;
+}
+
+static inline void mvs_can_dequeue(struct mvs_info *mvi, int num)
+{
+ /*unsigned long flags;*/
+
+ /*spin_lock_irqsave(&mvi->lock, flags);*/
+ mvi->can_queue += num;
+ /*spin_unlock_irqrestore(&mvi->lock, flags);*/
+}
+
+static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
{
unsigned int slot_idx = rx_desc & RXQ_SLOT_MASK;
struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
@@ -722,19 +1094,19 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32
rx_desc)
aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
if (!aborted) {
task->task_state_flags &=
- ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
task->task_state_flags |= SAS_TASK_STATE_DONE;
}
spin_unlock(&task->task_state_lock);
if (aborted)
- return;
+ return -1;
memset(tstat, 0, sizeof(*tstat));
tstat->resp = SAS_TASK_COMPLETE;
/* error info record present */
- if (rx_desc & RXQ_ERR) {
+ if ((rx_desc & RXQ_ERR) && (*(u64 *) slot->response)) {
tstat->stat = SAM_CHECK_COND;
mvs_slot_err(mvi, task, slot_idx);
goto out;
@@ -743,13 +1115,14 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32
rx_desc)
switch (task->task_proto) {
case SAS_PROTO_SSP:
/* hw says status == 0, datapres == 0 */
- if (rx_desc & RXQ_GOOD)
+ if (rx_desc & RXQ_GOOD) {
tstat->stat = SAM_GOOD;
-
+ tstat->resp = SAS_TASK_COMPLETE;
+ }
/* response frame present */
else if (rx_desc & RXQ_RSP) {
struct ssp_response_iu *iu =
- slot->response + sizeof(struct mvs_err_info);
+ slot->response + sizeof(struct mvs_err_info);
ssp_task_response(&mvi->pdev->dev, task, iu);
}
@@ -763,15 +1136,26 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32
rx_desc)
break;
case SATA_PROTO:
- case SAS_PROTO_STP:
- if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) == RXQ_DONE)
- tstat->stat = SAM_GOOD;
- else
- tstat->stat = SAM_CHECK_COND;
- /* FIXME: read taskfile data from SATA register set
- * associated with SATA target
- */
- break;
+ case SAS_PROTO_STP:{
+ struct ata_task_resp *resp =
+ (struct ata_task_resp *)tstat->buf;
+ struct domain_device *dev = task->dev;
+ struct mvs_port *port =
+ (struct mvs_port *)dev->port->lldd_port;
+
+ if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) ==
+ RXQ_DONE)
+ tstat->stat = SAM_GOOD;
+ else
+ tstat->stat = SAM_CHECK_COND;
+
+ resp->frame_len = sizeof(struct dev_to_host_fis);
+ memcpy(&resp->ending_fis[0],
+ SATA_RECEIVED_D2H_FIS(port->taskfileset),
+ sizeof(struct dev_to_host_fis));
+ /*mvs_hexdump(16,resp->ending_fis,0);*/
+ break;
+ }
default:
tstat->stat = SAM_CHECK_COND;
@@ -781,6 +1165,7 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32
rx_desc)
out:
mvs_slot_free(mvi, task, slot, slot_idx);
task->task_done(task);
+ return tstat->stat;
}
static void mvs_int_full(struct mvs_info *mvi)
@@ -791,6 +1176,8 @@ static void mvs_int_full(struct mvs_info *mvi)
stat = mr32(INT_STAT);
+ mvs_int_rx(mvi, false);
+
for (i = 0; i < MVS_MAX_PORTS; i++) {
tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
if (tmp)
@@ -800,14 +1187,12 @@ static void mvs_int_full(struct mvs_info *mvi)
if (stat & CINT_SRS)
mvs_int_sata(mvi);
- if (stat & (CINT_CI_STOP | CINT_DONE))
- mvs_int_rx(mvi, false);
-
mw32(INT_STAT, stat);
}
-static void mvs_int_rx(struct mvs_info *mvi, bool self_clear)
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
{
+ void __iomem *regs = mvi->regs;
u32 rx_prod_idx, rx_desc;
bool attn = false;
@@ -816,32 +1201,45 @@ static void mvs_int_rx(struct mvs_info *mvi, bool
self_clear)
* we don't have to stall the CPU reading that register.
* The actual RX ring is offset by one dword, due to this.
*/
- rx_prod_idx = le32_to_cpu(mvi->rx[0]) & 0xfff;
+ rx_prod_idx = le32_to_cpu(mr32(RX_CONS_IDX)) & RX_RING_SZ_MASK;
if (rx_prod_idx == 0xfff) { /* h/w hasn't touched RX ring yet */
mvi->rx_cons = 0xfff;
- return;
+ return 0;
}
+
+ /* The CMPL_Q may come late, read from register and try again
+ * note: if coalescing is enabled,
+ * it will need to read from register every time for sure
+ */
+ if (mvi->rx_cons == rx_prod_idx)
+ return 0;
+
if (mvi->rx_cons == 0xfff)
mvi->rx_cons = MVS_RX_RING_SZ - 1;
while (mvi->rx_cons != rx_prod_idx) {
+
/* increment our internal RX consumer pointer */
mvi->rx_cons = (mvi->rx_cons + 1) & (MVS_RX_RING_SZ - 1);
- /* Read RX descriptor at offset+1, due to above */
rx_desc = le32_to_cpu(mvi->rx[mvi->rx_cons + 1]);
- if (rx_desc & RXQ_DONE)
- /* we had a completion, error or no */
- mvs_slot_complete(mvi, rx_desc);
+ mvs_hba_cq_dump(mvi);
- if (rx_desc & RXQ_ATTN)
+ if (unlikely(rx_desc & RXQ_DONE))
+ mvs_slot_complete(mvi, rx_desc);
+ else if (rx_desc & RXQ_ATTN) {
attn = true;
+ MVS_PRINTK("ATTN\n");
+ } else if (rx_desc & RXQ_ERR) {
+ MVS_PRINTK("RXQ_ERR\n");
+ }
}
if (attn && self_clear)
mvs_int_full(mvi);
+ return 0;
}
static irqreturn_t mvs_interrupt(int irq, void *opaque)
@@ -851,6 +1249,10 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
u32 stat;
stat = mr32(GBL_INT_STAT);
+
+ /* clear CMD_CMPLT ASAP */
+ mw32_f(INT_STAT, CINT_DONE);
+
if (stat == 0 || stat == 0xffffffff)
return IRQ_NONE;
@@ -877,13 +1279,14 @@ static irqreturn_t mvs_msi_interrupt(int irq, void
*opaque)
}
struct mvs_task_exec_info {
- struct sas_task *task;
- struct mvs_cmd_hdr *hdr;
- unsigned int tag;
- int n_elem;
+ struct sas_task *task;
+ struct mvs_cmd_hdr *hdr;
+ unsigned int tag;
+ int n_elem;
};
-static int mvs_task_prep_smp(struct mvs_info *mvi, struct mvs_task_exec_info
*tei)
+static int mvs_task_prep_smp(struct mvs_info *mvi,
+ struct mvs_task_exec_info *tei)
{
int elem, rc;
struct mvs_cmd_hdr *hdr = tei->hdr;
@@ -918,8 +1321,8 @@ static int mvs_task_prep_smp(struct mvs_info *mvi, struct
mvs_task_exec_info *te
* Fill in TX ring and command slot header
*/
- mvi->tx[tag] = cpu_to_le32(
- (TXQ_CMD_SMP << TXQ_CMD_SHIFT) | TXQ_MODE_I | tag);
+ mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
+ TXQ_MODE_I | tag);
hdr->flags = 0;
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
@@ -941,6 +1344,65 @@ err_out:
return rc;
}
+static inline void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port
*port)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp, offs;
+
+ if (port->taskfileset == MVS_ID_NOT_MAPPED)
+ return;
+
+ offs = 1U << ((port->taskfileset & 0x0f) + PCS_EN_SATA_REG);
+ if (port->taskfileset < 16) {
+ tmp = mr32(PCS);
+ mw32(PCS, tmp | ~offs);
+ } else {
+ tmp = mr32(CTL);
+ mw32(CTL, tmp | ~offs);
+ }
+
+ port->taskfileset = MVS_ID_NOT_MAPPED;
+}
+
+static inline u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port
*port)
+{
+ int i;
+ u32 tmp, offs;
+ void __iomem *regs = mvi->regs;
+
+ if (port->taskfileset != MVS_ID_NOT_MAPPED)
+ return 0;
+
+ tmp = mr32(PCS);
+
+ for (i = 0; i < mvi->chip->srs_sz; i++) {
+ if (i == 16)
+ tmp = mr32(CTL);
+ offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG);
+ if (!(tmp & offs)) {
+ port->taskfileset = i;
+
+ if (i < 16)
+ mw32(PCS, tmp | offs);
+ else
+ mw32(CTL, tmp | offs);
+ return 0;
+ }
+ }
+ return MVS_ID_NOT_MAPPED;
+}
+
+static inline u32 mvs_get_ncq_tag(struct sas_task *task)
+{
+ u32 tag = 0;
+ struct ata_queued_cmd *qc = task->uldd_task;
+
+ if (qc)
+ tag = qc->tag;
+
+ return tag;
+}
+
static int mvs_task_prep_ata(struct mvs_info *mvi,
struct mvs_task_exec_info *tei)
{
@@ -949,7 +1411,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
struct mvs_cmd_hdr *hdr = tei->hdr;
struct asd_sas_port *sas_port = dev->port;
unsigned int tag = tei->tag;
- struct mvs_slot_info *slot = &mvi->slot_info[tag];
+ struct mvs_slot_info *slot;
u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
struct scatterlist *sg;
struct mvs_prd *buf_prd;
@@ -957,20 +1419,38 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
u8 *buf_cmd, *buf_oaf;
dma_addr_t buf_tmp_dma;
unsigned int i, req_len, resp_len;
+ struct mvs_port *port = (struct mvs_port *)sas_port->lldd_port;
+
+ if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED)
+ return -EBUSY;
+
+ slot = &mvi->slot_info[tag];
- /* FIXME: fill in SATA register set */
- mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag |
- (TXQ_CMD_STP << TXQ_CMD_SHIFT) |
- (sas_port->phy_mask << TXQ_PHY_SHIFT));
+ mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+ (TXQ_CMD_STP << TXQ_CMD_SHIFT) |
+ (sas_port->
+ phy_mask << TXQ_PHY_SHIFT) |
+ (port->
+ taskfileset << TXQ_SRS_SHIFT));
if (task->ata_task.use_ncq)
flags |= MCH_FPDMA;
- if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
- flags |= MCH_ATAPI;
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
+ if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
+ flags |= MCH_ATAPI;
+ }
+
/* FIXME: fill in port multiplier number */
hdr->flags = cpu_to_le32(flags);
- hdr->tags = cpu_to_le32(tag);
+
+ /* FIXME: the low order order 5 bits for the TAG if enable NCQ */
+ if (task->ata_task.use_ncq) {
+ hdr->tags = cpu_to_le32(mvs_get_ncq_tag(task));
+ /*Fill in task file */
+ task->ata_task.fis.sector_count = hdr->tags << 3;
+ } else
+ hdr->tags = cpu_to_le32(tag);
hdr->data_len = cpu_to_le32(task->total_xfer_len);
/*
@@ -978,9 +1458,8 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
*/
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
- /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ***************/
- buf_cmd =
- buf_tmp = slot->buf;
+ /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
+ buf_cmd = buf_tmp = slot->buf;
buf_tmp_dma = slot->buf_dma;
hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
@@ -988,7 +1467,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
buf_tmp += MVS_ATA_CMD_SZ;
buf_tmp_dma += MVS_ATA_CMD_SZ;
- /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
+ /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
/* used for STP. unused for SATA? */
buf_oaf = buf_tmp;
hdr->open_frame = cpu_to_le64(buf_tmp_dma);
@@ -996,32 +1475,37 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
buf_tmp += MVS_OAF_SZ;
buf_tmp_dma += MVS_OAF_SZ;
- /* region 3: PRD table ***********************************************/
+ /* region 3: PRD table ********************************************** */
buf_prd = buf_tmp;
- hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ if (tei->n_elem)
+ hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ else
+ hdr->prd_tbl = 0;
i = sizeof(struct mvs_prd) * tei->n_elem;
buf_tmp += i;
buf_tmp_dma += i;
- /* region 4: status buffer (larger the PRD, smaller this buf) ********/
+ /* region 4: status buffer (larger the PRD, smaller this buf) ******* */
/* FIXME: probably unused, for SATA. kept here just in case
* we get a STP/SATA error information record
*/
slot->response = buf_tmp;
hdr->status_buf = cpu_to_le64(buf_tmp_dma);
- req_len = sizeof(struct ssp_frame_hdr) + 28;
+ req_len = sizeof(struct host_to_dev_fis);
resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
- sizeof(struct mvs_err_info) - i;
+ sizeof(struct mvs_err_info) - i;
/* request, response lengths */
+ resp_len = min(resp_len, (u32) 0x400);
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
/* fill in command FIS and ATAPI CDB */
- memcpy(buf_cmd, &task->ata_task.fis,
- sizeof(struct host_to_dev_fis));
- memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
+ task->ata_task.fis.flags |= 0x80;
+ memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
+ memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
/* fill in PRD (scatter/gather) table, if any */
sg = task->scatter;
@@ -1044,7 +1528,7 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
struct mvs_cmd_hdr *hdr = tei->hdr;
struct mvs_slot_info *slot;
struct scatterlist *sg;
- unsigned int resp_len, req_len, i, tag = tei->tag;
+ u32 resp_len, req_len, i, tag = tei->tag;
struct mvs_prd *buf_prd;
struct ssp_frame_hdr *ssp_hdr;
void *buf_tmp;
@@ -1054,9 +1538,10 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
slot = &mvi->slot_info[tag];
- mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag |
- (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
- (sas_port->phy_mask << TXQ_PHY_SHIFT));
+ mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+ (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
+ (sas_port->
+ phy_mask << TXQ_PHY_SHIFT));
flags = MCH_RETRY;
if (task->ssp_task.enable_first_burst) {
@@ -1064,8 +1549,8 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
fburst = (1 << 7);
}
hdr->flags = cpu_to_le32(flags |
- (tei->n_elem << MCH_PRD_LEN_SHIFT) |
- (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
+ (tei->n_elem << MCH_PRD_LEN_SHIFT) |
+ (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
hdr->tags = cpu_to_le32(tag);
hdr->data_len = cpu_to_le32(task->total_xfer_len);
@@ -1075,9 +1560,8 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
*/
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
- /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***************/
- buf_cmd =
- buf_tmp = slot->buf;
+ /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
+ buf_cmd = buf_tmp = slot->buf;
buf_tmp_dma = slot->buf_dma;
hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
@@ -1085,28 +1569,33 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
buf_tmp += MVS_SSP_CMD_SZ;
buf_tmp_dma += MVS_SSP_CMD_SZ;
- /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
+ /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
buf_oaf = buf_tmp;
hdr->open_frame = cpu_to_le64(buf_tmp_dma);
buf_tmp += MVS_OAF_SZ;
buf_tmp_dma += MVS_OAF_SZ;
- /* region 3: PRD table ***********************************************/
+ /* region 3: PRD table ********************************************** */
buf_prd = buf_tmp;
- hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ if (tei->n_elem)
+ hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ else
+ hdr->prd_tbl = 0;
i = sizeof(struct mvs_prd) * tei->n_elem;
buf_tmp += i;
buf_tmp_dma += i;
- /* region 4: status buffer (larger the PRD, smaller this buf) ********/
+ /* region 4: status buffer (larger the PRD, smaller this buf) ******* */
slot->response = buf_tmp;
hdr->status_buf = cpu_to_le64(buf_tmp_dma);
- req_len = sizeof(struct ssp_frame_hdr) + 28;
resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
- sizeof(struct mvs_err_info) - i;
+ sizeof(struct mvs_err_info) - i;
+ resp_len = min(resp_len, (u32) 0x400);
+
+ req_len = sizeof(struct ssp_frame_hdr) + 28;
/* request, response lengths */
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
@@ -1118,8 +1607,8 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
buf_oaf[3] = tag;
memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
- /* fill in SSP frame header */
- ssp_hdr = (struct ssp_frame_hdr *) buf_cmd;
+ /* fill in SSP frame header (Command Table.SSP frame header) */
+ ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
ssp_hdr->frame_type = SSP_COMMAND;
memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr,
HASHED_SAS_ADDR_SIZE);
@@ -1131,12 +1620,11 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
buf_cmd += sizeof(*ssp_hdr);
memcpy(buf_cmd, &task->ssp_task.LUN, 8);
buf_cmd[9] = fburst |
- task->ssp_task.task_attr |
- (task->ssp_task.task_prio << 3);
+ task->ssp_task.task_attr | (task->ssp_task.task_prio << 3);
memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
-
- /* fill in PRD (scatter/gather) table, if any */
- sg = task->scatter;
+ /*CDB*/
+ /* fill in PRD (scatter/gather) table, if any */
+ sg = task->scatter;
for (i = 0; i < tei->n_elem; i++) {
buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
buf_prd->len = cpu_to_le32(sg_dma_len(sg));
@@ -1155,72 +1643,106 @@ static int mvs_task_exec(struct sas_task *task, const
int num, gfp_t gfp_flags)
void __iomem *regs = mvi->regs;
unsigned long flags;
struct mvs_task_exec_info tei;
+ struct sas_task *t = task;
+ u32 n = num, pass = 0;
+
+ mvs_hba_interrupt_enable(mvi, 0);
+
+ do {
+ if (!sas_protocol_ata(t->task_proto)) {
+ if (t->num_scatter) {
+ n_elem = pci_map_sg(mvi->pdev, t->scatter,
+ t->num_scatter,
+ t->data_dir);
+ if (!n_elem) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ }
+ } else {
+ n_elem = t->num_scatter;
+ }
- /* FIXME: STP/SATA support not complete yet */
- if (task->task_proto == SATA_PROTO || task->task_proto == SAS_PROTO_STP)
- return -SAS_DEV_NO_RESPONSE;
+ rc = mvs_tag_alloc(mvi, &tag);
+ if (rc)
+ goto err_out;
- if (task->num_scatter) {
- n_elem = pci_map_sg(mvi->pdev, task->scatter,
- task->num_scatter, task->data_dir);
- if (!n_elem)
- return -ENOMEM;
- }
+ mvi->slot_info[tag].task = t;
+ mvi->slot_info[tag].n_elem = n_elem;
+ tei.task = t;
+ tei.hdr = &mvi->slot[tag];
+ tei.tag = tag;
+ tei.n_elem = n_elem;
- spin_lock_irqsave(&mvi->lock, flags);
+ switch (t->task_proto) {
+ case SAS_PROTO_SMP:
+ rc = mvs_task_prep_smp(mvi, &tei);
+ break;
+ case SAS_PROTO_SSP:
+ rc = mvs_task_prep_ssp(mvi, &tei);
+ break;
+ case SATA_PROTO:
+ case SAS_PROTO_STP:
+ rc = mvs_task_prep_ata(mvi, &tei);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
- rc = mvs_tag_alloc(mvi, &tag);
- if (rc)
- goto err_out;
+ if (rc)
+ goto err_out_tag;
- mvi->slot_info[tag].task = task;
- mvi->slot_info[tag].n_elem = n_elem;
- tei.task = task;
- tei.hdr = &mvi->slot[tag];
- tei.tag = tag;
- tei.n_elem = n_elem;
+ /* TODO: select normal or high priority */
- switch (task->task_proto) {
- case SAS_PROTO_SMP:
- rc = mvs_task_prep_smp(mvi, &tei);
- break;
- case SAS_PROTO_SSP:
- rc = mvs_task_prep_ssp(mvi, &tei);
- break;
- case SATA_PROTO:
- case SAS_PROTO_STP:
- rc = mvs_task_prep_ata(mvi, &tei);
- break;
- default:
- rc = -EINVAL;
- break;
- }
-
- if (rc)
- goto err_out_tag;
+ spin_lock_irqsave(&t->task_state_lock, flags);
+ t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock_irqrestore(&t->task_state_lock, flags);
- /* TODO: select normal or high priority */
+ if (n == 1) {
+ mvs_hba_interrupt_enable(mvi, 1);
+ mw32(TX_PROD_IDX, mvi->tx_prod);
+ }
+ /*
+ MVS_PRINTK("task=0x%08X,proto=%d,tag=%d,"
+ "num=%d,mvi->tx_prod=%d\n",
+ (u32)t,t->task_proto,tag,n,mvi->tx_prod);
+ */
+ mvs_hba_memory_dump(mvi, tag, t->task_proto);
- mw32(RX_PROD_IDX, mvi->tx_prod);
+ ++pass;
+ mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
- mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_TX_RING_SZ - 1);
+ if (n == 1)
+ break;
- spin_lock(&task->task_state_lock);
- task->task_state_flags |= SAS_TASK_AT_INITIATOR;
- spin_unlock(&task->task_state_lock);
+ t = list_entry(t->list.next, struct sas_task, list);
+ } while (--n);
- spin_unlock_irqrestore(&mvi->lock, flags);
return 0;
err_out_tag:
- mvs_tag_clear(mvi, tag);
+ mvs_tag_free(mvi, tag);
+ MVS_PRINTK("Error : free tag %d\n", tag);
err_out:
- if (n_elem)
- pci_unmap_sg(mvi->pdev, task->scatter, n_elem, task->data_dir);
- spin_unlock_irqrestore(&mvi->lock, flags);
+ MVS_PRINTK("mvsas exec failed[%d]!\n", pass);
+ if (!sas_protocol_ata(t->task_proto))
+ if (n_elem)
+ pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
+ t->data_dir);
+ if (pass)
+ mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
+ mvs_hba_interrupt_enable(mvi, 1);
return rc;
}
+static int mvs_abort_task(struct sas_task *task)
+{
+ /*FIXME*/
+ MVS_PRINTK("mvs abort task\n");
+ return TMF_RESP_FUNC_COMPLETE;
+}
+
static void mvs_free(struct mvs_info *mvi)
{
int i;
@@ -1238,7 +1760,7 @@ static void mvs_free(struct mvs_info *mvi)
if (mvi->tx)
dma_free_coherent(&mvi->pdev->dev,
- sizeof(*mvi->tx) * MVS_TX_RING_SZ,
+ sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
mvi->tx, mvi->tx_dma);
if (mvi->rx_fis)
dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
@@ -1249,10 +1771,12 @@ static void mvs_free(struct mvs_info *mvi)
mvi->rx, mvi->rx_dma);
if (mvi->slot)
dma_free_coherent(&mvi->pdev->dev,
- sizeof(*mvi->slot) * MVS_RX_RING_SZ,
+ sizeof(*mvi->slot) * MVS_SLOTS,
mvi->slot, mvi->slot_dma);
+#if 0
if (mvi->peri_regs)
iounmap(mvi->peri_regs);
+#endif
if (mvi->regs)
iounmap(mvi->regs);
if (mvi->shost)
@@ -1274,25 +1798,25 @@ static int mvs_phy_control(struct asd_sas_phy *sas_phy,
enum phy_func func,
reg = mvi->regs + MVS_P0_SER_CTLSTAT + (phy_id * 4);
switch (func) {
- case PHY_FUNC_SET_LINK_RATE: {
- struct sas_phy_linkrates *rates = funcdata;
- u32 lrmin = 0, lrmax = 0;
+ case PHY_FUNC_SET_LINK_RATE:{
+ struct sas_phy_linkrates *rates = funcdata;
+ u32 lrmin = 0, lrmax = 0;
- lrmin = (rates->minimum_linkrate << 8);
- lrmax = (rates->maximum_linkrate << 12);
+ lrmin = (rates->minimum_linkrate << 8);
+ lrmax = (rates->maximum_linkrate << 12);
- tmp = readl(reg);
- if (lrmin) {
- tmp &= ~(0xf << 8);
- tmp |= lrmin;
- }
- if (lrmax) {
- tmp &= ~(0xf << 12);
- tmp |= lrmax;
+ tmp = readl(reg);
+ if (lrmin) {
+ tmp &= ~(0xf << 8);
+ tmp |= lrmin;
+ }
+ if (lrmax) {
+ tmp &= ~(0xf << 12);
+ tmp |= lrmax;
+ }
+ writel(tmp, reg);
+ break;
}
- writel(tmp, reg);
- break;
- }
case PHY_FUNC_HARD_RESET:
tmp = readl(reg);
@@ -1335,11 +1859,11 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi,
int phy_id)
sas_phy->lldd_phy = phy;
}
-static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct mvs_info *mvi;
- unsigned long res_start, res_len;
+ unsigned long res_start, res_len, res_flag;
struct asd_sas_phy **arr_phy;
struct asd_sas_port **arr_port;
const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
@@ -1381,9 +1905,10 @@ static struct mvs_info * __devinit mvs_alloc(struct
pci_dev *pdev,
SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
mvi->shost->transportt = mvs_stt;
- mvi->shost->max_id = ~0;
- mvi->shost->max_lun = ~0;
- mvi->shost->max_cmd_len = ~0;
+ mvi->shost->max_id = 21;
+ mvi->shost->max_lun = 2;
+ mvi->shost->max_channel = 0;
+ mvi->shost->max_cmd_len = 16;
mvi->sas.sas_ha_name = DRV_NAME;
mvi->sas.dev = &pdev->dev;
@@ -1392,12 +1917,13 @@ static struct mvs_info * __devinit mvs_alloc(struct
pci_dev *pdev,
mvi->sas.sas_phy = arr_phy;
mvi->sas.sas_port = arr_port;
mvi->sas.num_phys = chip->n_phy;
- mvi->sas.lldd_max_execute_num = MVS_TX_RING_SZ - 1;/* FIXME: correct? */
- mvi->sas.lldd_queue_size = MVS_TX_RING_SZ - 1; /* FIXME: correct? */
+ mvi->sas.lldd_max_execute_num = MVS_CHIP_SLOT_SZ - 1;
+ mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
+ mvi->can_queue = (MVS_CHIP_SLOT_SZ >> 1) - 1;
mvi->sas.lldd_ha = mvi;
mvi->sas.core.shost = mvi->shost;
- mvs_tag_set(mvi, MVS_TX_RING_SZ - 1);
+ mvs_tag_init(mvi);
/*
* ioremap main and peripheral registers
@@ -1408,16 +1934,23 @@ static struct mvs_info * __devinit mvs_alloc(struct
pci_dev *pdev,
if (!res_start || !res_len)
goto err_out;
+#if 0
mvi->peri_regs = ioremap_nocache(res_start, res_len);
- if (!mvi->regs)
+ if (!mvi->peri_regs)
goto err_out;
+#endif
res_start = pci_resource_start(pdev, 4);
res_len = pci_resource_len(pdev, 4);
if (!res_start || !res_len)
goto err_out;
- mvi->regs = ioremap_nocache(res_start, res_len);
+ res_flag = pci_resource_flags(pdev, 4);
+ if (res_flag & IORESOURCE_CACHEABLE)
+ mvi->regs = ioremap(res_start, res_len);
+ else
+ mvi->regs = ioremap_nocache(res_start, res_len);
+
if (!mvi->regs)
goto err_out;
@@ -1426,14 +1959,14 @@ static struct mvs_info * __devinit mvs_alloc(struct
pci_dev *pdev,
*/
mvi->tx = dma_alloc_coherent(&pdev->dev,
- sizeof(*mvi->tx) * MVS_TX_RING_SZ,
+ sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
&mvi->tx_dma, GFP_KERNEL);
if (!mvi->tx)
goto err_out;
- memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_TX_RING_SZ);
+ memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
- &mvi->rx_fis_dma, GFP_KERNEL);
+ &mvi->rx_fis_dma, GFP_KERNEL);
if (!mvi->rx_fis)
goto err_out;
memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
@@ -1459,7 +1992,7 @@ static struct mvs_info * __devinit mvs_alloc(struct
pci_dev *pdev,
struct mvs_slot_info *slot = &mvi->slot_info[i];
slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
- &slot->buf_dma, GFP_KERNEL);
+ &slot->buf_dma, GFP_KERNEL);
if (!slot->buf)
goto err_out;
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
@@ -1468,7 +2001,6 @@ static struct mvs_info * __devinit mvs_alloc(struct
pci_dev *pdev,
/* finally, read NVRAM to get our SAS address */
if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
goto err_out;
-
return mvi;
err_out:
@@ -1476,13 +2008,13 @@ err_out:
return NULL;
}
-static u32 mvs_cr32(void __iomem *regs, u32 addr)
+static inline u32 mvs_cr32(void __iomem *regs, u32 addr)
{
mw32(CMD_ADDR, addr);
return mr32(CMD_DATA);
}
-static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
+static inline void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
{
mw32(CMD_ADDR, addr);
mw32(CMD_DATA, val);
@@ -1497,7 +2029,6 @@ static u32 mvs_phy_read(struct mvs_info *mvi, unsigned int
phy_id, u32 addr)
writel(addr, phy_regs);
return readl(phy_regs + 4);
}
-#endif
static void mvs_phy_write(struct mvs_info *mvi, unsigned int phy_id,
u32 addr, u32 val)
@@ -1509,6 +2040,7 @@ static void mvs_phy_write(struct mvs_info *mvi, unsigned
int phy_id,
writel(val, phy_regs + 4);
readl(phy_regs); /* flush */
}
+#endif
static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
{
@@ -1547,6 +2079,174 @@ static void __devinit mvs_phy_hacks(struct mvs_info
*mvi)
tmp &= 0x1fffffff;
tmp |= (2U << 29); /* 8 ms retry */
mvs_cw32(regs, CMD_PHY_TIMER, tmp);
+
+ /* TEST - for phy decoding error, adjust voltage levels */
+ mw32(P0_VSR_ADDR + 0, 0x8);
+ mw32(P0_VSR_DATA + 0, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 8, 0x8);
+ mw32(P0_VSR_DATA + 8, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 16, 0x8);
+ mw32(P0_VSR_DATA + 16, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 24, 0x8);
+ mw32(P0_VSR_DATA + 24, 0x2F0);
+
+}
+
+static inline void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ tmp = mr32(PCS);
+ if (mvi->chip->n_phy <= 4)
+ tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_START);
+ else
+ tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_START2);
+ mw32(PCS, tmp);
+}
+
+static void mvs_detect_porttype(struct mvs_info *mvi, int i)
+{
+ void __iomem *regs = mvi->regs;
+ u32 reg;
+ struct mvs_phy *phy = &mvi->phy[i];
+
+ /* enable auto port detection */
+ mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
+ msleep(100);
+
+ /* TODO check & save device type */
+ reg = mr32(GBL_PORT_TYPE);
+
+ if (reg & MODE_SAS_SATA & (1 << i)) {
+ phy->type = PORT_TYPE_SAS;
+ phy->identify.target_port_protocols = SAS_PROTO_SSP;
+ } else {
+ phy->type = PORT_TYPE_SATA;
+ phy->identify.target_port_protocols = SAS_PROTO_STP;
+ }
+
+}
+
+static inline void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
+{
+ u32 *s = (u32 *) buf;
+ void __iomem *regs = mvi->regs;
+
+ if (!s)
+ return NULL;
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_SATA_SIG3);
+ s[3] = READ_PORT_CONFIG_DATA(i);
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_SATA_SIG2);
+ s[2] = READ_PORT_CONFIG_DATA(i);
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_SATA_SIG1);
+ s[1] = READ_PORT_CONFIG_DATA(i);
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_SATA_SIG0);
+ s[0] = READ_PORT_CONFIG_DATA(i);
+
+ return (void *)s;
+}
+
+static inline u32 mvs_is_sig_fis_received(struct mvs_info *mvi, int i)
+{
+ u32 tmp;
+ void __iomem *regs = mvi->regs;
+
+ tmp = (READ_PORT_IRQ_STAT(i) & PHYEV_SIG_FIS);
+ if (tmp)
+ WRITE_PORT_IRQ_STAT(i, PHYEV_SIG_FIS);
+
+ return tmp;
+}
+
+static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
+{
+ void __iomem *regs = mvi->regs;
+ struct mvs_phy *phy = &mvi->phy[i];
+ u32 tmp;
+ __le64 tmp64;
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_IDENTIFY);
+ phy->devinfo = READ_PORT_CONFIG_DATA(i);
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_ADDR_HI);
+ phy->devsasaddr = (__le64) READ_PORT_CONFIG_DATA(i) << 32;
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_ADDR_LO);
+ phy->devsasaddr |= READ_PORT_CONFIG_DATA(i); /*le */
+
+ phy->phystatus = READ_PORT_PHY_CONTROL(i);
+ /*MVS_PRINTK("PhyStatus=%X\n",phy->phystatus);*/
+
+ /*FIXME Update Wide Port info */
+ phy->port = &mvi->port[i];
+ phy->port->sas_port.lldd_port = phy->port;
+ phy->port->taskfileset = MVS_ID_NOT_MAPPED;
+
+ if (phy->phystatus & PHY_READY_MASK) {
+ u32 phy_st;
+ struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_PHY_STAT);
+ phy_st = READ_PORT_CONFIG_DATA(i);
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_ATT_ADDR_HI);
+ phy->attdevsasaddr = (__le64) READ_PORT_CONFIG_DATA(i) << 32;
+
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_ATT_ADDR_LO);
+ phy->attdevsasaddr |= READ_PORT_CONFIG_DATA(i);
+
+ /*Updated attached_sas_addr */
+ tmp64 = phy->attdevsasaddr;
+ MVS_PRINTK("phy[%d] Get Attached Address 0x%llX \n", i, tmp64);
+ tmp64 = cpu_to_be64(tmp64);
+ memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
+
+ if (phy->type & PORT_TYPE_SAS) {
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_ATT_DEV_INFO);
+ phy->attdevinfo = READ_PORT_CONFIG_DATA(i);
+ phy->identify.device_type =
+ phy->attdevinfo & PORT_DEV_TYPE_MASK;
+ MVS_PRINTK("device_type = %d\n",
+ phy->identify.device_type);
+
+ sas_phy->linkrate =
+ (phy->phystatus & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+ if (phy_st & PHY_OOB_DTCTD)
+ sas_phy->oob_mode = SAS_OOB_MODE;
+ phy->frame_rcvd_size =
+ sizeof(struct sas_identify_frame);
+ } else if (phy->type & PORT_TYPE_SATA) {
+ if (mvs_is_sig_fis_received(mvi, i)) {
+ if (phy_st & PHY_OOB_DTCTD)
+ sas_phy->oob_mode = SATA_OOB_MODE;
+ phy->frame_rcvd_size =
+ sizeof(struct dev_to_host_fis);
+ mvs_get_d2h_reg(mvi, i,
+ (void *)sas_phy->frame_rcvd);
+ }
+ }
+ /* workaround for HW phy decoding error on 1.5g disk drive */
+ WRITE_PORT_VSR_ADDR(i, 0x06);
+ tmp = READ_PORT_VSR_DATA(i);
+ if (((phy->phystatus & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
+ SAS_LINK_RATE_1_5_GBPS)
+ tmp &= ~0x20000000;
+ else
+ tmp |= 0x20000000;
+ WRITE_PORT_VSR_DATA(i, tmp);
+
+ }
+ phy->irqstatus = READ_PORT_IRQ_STAT(i);
}
static int __devinit mvs_hw_init(struct mvs_info *mvi)
@@ -1559,6 +2259,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32(GBL_CTL, 0);
tmp = mr32(GBL_CTL);
+ /*ResetController */
if (!(tmp & HBA_RST)) {
if (mvi->flags & MVF_PHY_PWR_FIX) {
pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
@@ -1576,7 +2277,6 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32_f(GBL_CTL, HBA_RST);
}
-
/* wait for reset to finish; timeout is just a guess */
i = 1000;
while (i-- > 0) {
@@ -1590,13 +2290,24 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
return -EBUSY;
}
+ /*InitChip */
/* make sure RST is set; HBA_RST /should/ have done that for us */
- cctl = mr32(CTL);
+ cctl = mr32(CTL); /*MVS_CTL */
if (cctl & CCTL_RST)
cctl &= ~CCTL_RST;
else
mw32_f(CTL, cctl | CCTL_RST);
+ pci_read_config_dword(mvi->pdev, PCI_COMMAND, &tmp);
+ /*MV_PCI_DEV_EN */
+ tmp |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_dword(mvi->pdev, PCI_COMMAND, tmp);
+ /* write to device control _AND_ device status register? - A.C. */
+ pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
+ tmp &= ~PRD_REQ_MASK;
+ tmp |= PRD_REQ_SIZE;
+ pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
+
pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
tmp |= PCTL_PWR_ON;
tmp &= ~PCTL_OFF;
@@ -1609,6 +2320,9 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32_f(CTL, cctl);
+ /* reset control */
+ mw32(PCS, 0); /*MVS_PCS */
+
mvs_phy_hacks(mvi);
mw32(CMD_LIST_LO, mvi->slot_dma);
@@ -1617,7 +2331,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32(RX_FIS_LO, mvi->rx_fis_dma);
mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
- mw32(TX_CFG, MVS_TX_RING_SZ);
+ mw32(TX_CFG, MVS_CHIP_SLOT_SZ);
mw32(TX_LO, mvi->tx_dma);
mw32(TX_HI, (mvi->tx_dma >> 16) >> 16);
@@ -1628,42 +2342,82 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
/* init and reset phys */
for (i = 0; i < mvi->chip->n_phy; i++) {
/* FIXME: is this the correct dword order? */
- u32 lo = *((u32 *) &mvi->sas_addr[0]);
- u32 hi = *((u32 *) &mvi->sas_addr[4]);
+ u32 lo = *((u32 *)&mvi->sas_addr[0]);
+ u32 hi = *((u32 *)&mvi->sas_addr[4]);
+
+ mvs_detect_porttype(mvi, i);
/* set phy local SAS address */
- mvs_phy_write(mvi, i, PHYR_ADDR_LO, lo);
- mvs_phy_write(mvi, i, PHYR_ADDR_HI, hi);
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_ADDR_LO);
+ WRITE_PORT_CONFIG_DATA(i, lo);
+ WRITE_PORT_CONFIG_ADDR(i, PHYR_ADDR_HI);
+ WRITE_PORT_CONFIG_DATA(i, hi);
/* reset phy */
- tmp = readl(regs + MVS_P0_SER_CTLSTAT + (i * 4));
+ tmp = READ_PORT_PHY_CONTROL(i);
tmp |= PHY_RST;
- writel(tmp, regs + MVS_P0_SER_CTLSTAT + (i * 4));
+ WRITE_PORT_PHY_CONTROL(i, tmp);
}
msleep(100);
for (i = 0; i < mvi->chip->n_phy; i++) {
+ /* clear phy int status */
+ tmp = READ_PORT_IRQ_STAT(i);
+ tmp &= ~PHYEV_SIG_FIS;
+ WRITE_PORT_IRQ_STAT(i, tmp);
+
/* set phy int mask */
- writel(PHYEV_BROAD_CH | PHYEV_RDY_CH,
- regs + MVS_P0_INT_MASK + (i * 8));
+ tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS;
+ WRITE_PORT_IRQ_MASK(i, tmp);
- /* clear phy int status */
- tmp = readl(regs + MVS_P0_INT_STAT + (i * 8));
- writel(tmp, regs + MVS_P0_INT_STAT + (i * 8));
+ mvs_update_phyinfo(mvi, i);
+ mvs_enable_xmt(mvi, i);
}
/* FIXME: update wide port bitmaps */
+ /* little endian for open address and command table, etc. */
+ /* A.C.
+ * it seems that ( from the spec ) turning on big-endian won't
+ * do us any good on big-endian machines, need further confirmation
+ */
+ cctl = mr32(CTL);
+ cctl |= CCTL_ENDIAN_CMD;
+ cctl |= CCTL_ENDIAN_DATA;
+ cctl &= ~CCTL_ENDIAN_OPEN;
+ cctl |= CCTL_ENDIAN_RSP;
+ mw32_f(CTL, cctl);
+
+ /* reset CMD queue */
+ tmp = mr32(PCS);
+ tmp |= PCS_CMD_RST;
+ mw32(PCS, tmp);
+ /* interrupt coalescing may cause missing HW interrput in some case,
+ * and the max count is 0x1ff, while our max slot is 0x200,
+ * it will make count 0.
+ */
+ tmp = 0;
+ mw32(INT_COAL, tmp);
+
+ tmp = 0x100;
+ mw32(INT_COAL_TMOUT, tmp);
+
/* ladies and gentlemen, start your engines */
- mw32(TX_CFG, MVS_TX_RING_SZ | TX_EN);
+ mw32(TX_CFG, 0);
+ mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
+ /* enable CMD/CMPL_Q/RESP mode */
mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN |
((mvi->flags & MVF_MSI) ? PCS_SELF_CLEAR : 0));
/* re-enable interrupts globally */
mw32(GBL_CTL, INT_EN);
+ /* enable completion queue interrupt */
+ tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM);
+ mw32(INT_MASK, tmp);
+
return 0;
}
@@ -1680,7 +2434,7 @@ static void __devinit mvs_print_info(struct mvs_info *mvi)
}
static int __devinit mvs_pci_init(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
int rc;
struct mvs_info *mvi;
@@ -1732,6 +2486,7 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
mvs_print_info(mvi);
scsi_scan_host(mvi->shost);
+
return 0;
err_out_shost:
@@ -1771,6 +2526,7 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
static struct sas_domain_function_template mvs_transport_ops = {
.lldd_execute_task = mvs_task_exec,
.lldd_control_phy = mvs_phy_control,
+ .lldd_abort_task = mvs_abort_task,
};
static struct pci_device_id __devinitdata mvs_pci_table[] = {
@@ -1822,4 +2578,3 @@ MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller
driver");
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, mvs_pci_table);
-
--
1.5.3.7
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-22 15:24 ` [PATCH] Marvell 6440 SAS/SATA driver Ke Wei
@ 2008-01-23 3:58 ` Jeff Garzik
2008-01-23 10:54 ` Ke Wei
2008-01-23 19:23 ` Grant Grundler
0 siblings, 2 replies; 22+ messages in thread
From: Jeff Garzik @ 2008-01-23 3:58 UTC (permalink / raw)
To: Ke Wei; +Cc: linux-scsi, kewei, qswang, jfeng, qzhao
Comments inline, mostly minor stuff cleaning up the source.
Major problem though: your mailer converted tabs to spaces, so our
automated patch tools won't work on your submission. It usually takes a
few attempts to get your email setup working, such that all the
automated tools used in the Linux community work.
Ke Wei wrote:
> +#define MVS_QUEUE_SIZE (30)
to be consistent with the rest of the driver, make this an enum
> +#define MVS_PRINTK(_x_, ...) \
> + printk(KERN_NOTICE DRV_NAME ": " _x_ , ## __VA_ARGS__)
>
> #define mr32(reg) readl(regs + MVS_##reg)
> #define mw32(reg,val) writel((val), regs + MVS_##reg)
> @@ -47,6 +53,65 @@
> readl(regs + MVS_##reg); \
> } while (0)
>
> +#define MVS_BIT(x) (1L << (x))
> +
> +#define PORT_TYPE_SATA MVS_BIT(0)
> +#define PORT_TYPE_SAS MVS_BIT(1)
to be consistent with the rest of the driver, just open-code "1 << n".
This also makes it easier to get the C type correct.
> +#define MVS_ID_NOT_MAPPED 0xff
> +#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
> +
> +/* offset for D2H FIS in the Received FIS List Structure */
> +#define SATA_RECEIVED_D2H_FIS(reg_set) \
> + (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
> +#define SATA_RECEIVED_PIO_FIS(reg_set) \
> + (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
> +#define UNASSOC_D2H_FIS(id) \
> + (mvi->rx_fis + 0x100 * id)
> +
> +
> +#define READ_PORT_CONFIG_DATA(i) \
> + ((i > 3)?mr32(P4_CFG_DATA + (i - 4) * 8):mr32(P0_CFG_DATA + i * 8))
> +#define WRITE_PORT_CONFIG_DATA(i,tmp) \
> + {if (i > 3)mw32(P4_CFG_DATA + (i - 4) * 8, tmp); \
> + else \
> + mw32(P0_CFG_DATA + i * 8, tmp); }
> +#define WRITE_PORT_CONFIG_ADDR(i,tmp) \
> + {if (i > 3)mw32(P4_CFG_ADDR + (i - 4) * 8, tmp); \
> + else \
> + mw32(P0_CFG_ADDR + i * 8, tmp); }
> +
> +#define READ_PORT_PHY_CONTROL(i) \
> + ((i > 3)?mr32(P4_SER_CTLSTAT + (i - 4) * 4):mr32(P0_SER_CTLSTAT+i * 4))
> +#define WRITE_PORT_PHY_CONTROL(i,tmp) \
> + {if (i > 3)mw32(P4_SER_CTLSTAT + (i - 4) * 4, tmp); \
> + else \
> + mw32(P0_SER_CTLSTAT + i * 4, tmp); }
> +
> +#define READ_PORT_VSR_DATA(i) \
> + ((i > 3)?mr32(P4_VSR_DATA + (i - 4) * 8):mr32(P0_VSR_DATA+i*8))
> +#define WRITE_PORT_VSR_DATA(i,tmp) \
> + {if (i > 3)mw32(P4_VSR_DATA + (i - 4) * 8, tmp); \
> + else \
> + mw32(P0_VSR_DATA + i*8, tmp); }
> +#define WRITE_PORT_VSR_ADDR(i,tmp) \
> + {if (i > 3)mw32(P4_VSR_ADDR + (i - 4) * 8, tmp); \
> + else \
> + mw32(P0_VSR_ADDR + i * 8, tmp); }
> +
> +#define READ_PORT_IRQ_STAT(i) \
> + ((i > 3)?mr32(P4_INT_STAT + (i - 4) * 8):mr32(P0_INT_STAT + i * 8))
> +#define WRITE_PORT_IRQ_STAT(i,tmp) \
> + {if (i > 3)mw32(P4_INT_STAT + (i-4) * 8, tmp); \
> + else \
> + mw32(P0_INT_STAT + i * 8, tmp); }
> +#define READ_PORT_IRQ_MASK(i) \
> + ((i > 3)?mr32(P4_INT_MASK + (i-4) * 8):mr32(P0_INT_MASK+i*8))
> +#define WRITE_PORT_IRQ_MASK(i,tmp) \
> + {if (i > 3)mw32(P4_INT_MASK + (i-4) * 8, tmp); \
> + else \
> + mw32(P0_INT_MASK + i * 8, tmp); }
make these macros readable, by breaking each C statement into a separate
line
> @@ -260,13 +368,33 @@ enum hw_register_bits {
> PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */
>
> /* MVS_PCS */
> + PCS_EN_SATA_REG = (16), /* Enable SATA Register Set*/
> + PCS_EN_PORT_XMT_START = (12), /* Enable Port Transmit*/
> + PCS_EN_PORT_XMT_START2 = (8), /* For 6480*/
> PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */
> PCS_RSP_RX_EN = (1U << 7), /* raw response rx */
> PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */
> PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */
> PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */
> - PCS_CMD_RST = (1U << 2), /* reset cmd issue */
> + PCS_CMD_RST = (1U << 1), /* reset cmd issue */
> PCS_CMD_EN = (1U << 0), /* enable cmd issue */
> +
> + /*Port n Attached Device Info*/
> + PORT_DEV_SSP_TRGT = (1U << 19),
> + PORT_DEV_SMP_TRGT = (1U << 18),
> + PORT_DEV_STP_TRGT = (1U << 17),
> + PORT_DEV_SSP_INIT = (1U << 11),
> + PORT_DEV_SMP_INIT = (1U << 10),
> + PORT_DEV_STP_INIT = (1U << 9),
> + PORT_PHY_ID_MASK = (0xFFU << 24),
> + PORT_DEV_TRGT_MASK = (0x7U << 17),
> + PORT_DEV_INIT_MASK = (0x7U << 9),
> + PORT_DEV_TYPE_MASK = (0x7U << 0),
> +
> + /*Port n PHY Status*/
> + PHY_RDY = (1U << 2),
> + PHY_DW_SYNC = (1U << 1),
> + PHY_OOB_DTCTD = (1U << 0),
to be consistent, add spaces after /* and before */
>
> struct mvs_port {
> struct asd_sas_port sas_port;
> + u8 taskfileset;
> };
>
> struct mvs_phy {
> struct mvs_port *port;
> struct asd_sas_phy sas_phy;
> + struct sas_identify identify;
> + __le32 devinfo;
> + __le64 devsasaddr;
> + __le32 attdevinfo;
> + __le64 attdevsasaddr;
> + u32 type;
> + __le32 phystatus;
> + __le32 irqstatus;
> + u8 wideportphymap;
> + u32 frame_rcvd_size;
> + u8 frame_rcvd[32];
following linux style (and style used in my original driver), consider
adding some '_' underscores, to separate out words.
dev_info
phy_stat
irq_stat
etc.
also, following the style in this driver, please add comments describing
what the fields do
> - u8 frame_rcvd[24 + 1024];
> };
>
> struct mvs_info {
> @@ -437,27 +585,39 @@ struct mvs_info {
> dma_addr_t rx_dma;
> u32 rx_cons; /* RX consumer idx */
>
> - __le32 *rx_fis; /* RX'd FIS area */
> + void *rx_fis; /* RX'd FIS area */
> dma_addr_t rx_fis_dma;
>
> - struct mvs_cmd_hdr *slot; /* DMA command header slots */
> + struct mvs_cmd_hdr *slot; /* DMA command header slots */
> dma_addr_t slot_dma;
>
> const struct mvs_chip_info *chip;
>
> - /* further per-slot information */
> + unsigned long tags[MVS_SLOTS];
> struct mvs_slot_info slot_info[MVS_SLOTS];
> - unsigned long tags[(MVS_SLOTS / sizeof(unsigned long)) + 1];
> -
> + /* further per-slot information */
> struct mvs_phy phy[MVS_MAX_PHYS];
> struct mvs_port port[MVS_MAX_PHYS];
> +
> + u32 can_queue; /* per adapter */
> + u32 tag_out; /*Get*/
> + u32 tag_in; /*Give*/
> +};
> +
> +struct mvs_queue_task {
> + struct list_head list;
> +
> + void *uldd_task;
> };
>
> +static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
> +static void mvs_scan_start(struct Scsi_Host *);
> +
> static struct scsi_transport_template *mvs_stt;
>
> static const struct mvs_chip_info mvs_chips[] = {
> - [chip_6320] = { 2, 16, 9 },
> - [chip_6440] = { 4, 16, 9 },
> + [chip_6320] = { 2, 16, 9 },
> + [chip_6440] = { 4, 16, 9 },
> [chip_6480] = { 8, 32, 10 },
> };
>
> @@ -468,6 +628,8 @@ static struct scsi_host_template mvs_sht = {
> .target_alloc = sas_target_alloc,
> .slave_configure = sas_slave_configure,
> .slave_destroy = sas_slave_destroy,
> + .scan_finished = mvs_scan_finished,
> + .scan_start = mvs_scan_start,
> .change_queue_depth = sas_change_queue_depth,
> .change_queue_type = sas_change_queue_type,
> .bios_param = sas_bios_param,
> @@ -477,14 +639,154 @@ static struct scsi_host_template mvs_sht = {
> .sg_tablesize = SG_ALL,
> .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
> .use_clustering = ENABLE_CLUSTERING,
> - .eh_device_reset_handler= sas_eh_device_reset_handler,
> + .eh_device_reset_handler = sas_eh_device_reset_handler,
> .eh_bus_reset_handler = sas_eh_bus_reset_handler,
> .slave_alloc = sas_slave_alloc,
> .target_destroy = sas_target_destroy,
> .ioctl = sas_ioctl,
> };
>
> -static void mvs_int_rx(struct mvs_info *mvi, bool self_clear);
> +static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
> +{
> + u32 i;
> + u32 run;
> + u32 offset;
> +
> + offset = 0;
> + while (size) {
> + printk("%08X : ", baseaddr + offset);
> + if (size >= 16)
> + run = 16;
> + else
> + run = size;
> + size -= run;
> + for (i = 0; i < 16; i++) {
> + if (i < run)
> + printk("%02X ", (unsigned int)data[i]);
> + else
> + printk(" ");
> + }
> + printk(": ");
> + for (i = 0; i < run; i++)
> + printk("%c", isalnum(data[i]) ? data[i] : '.');
> + printk("\n");
> + data = &data[16];
> + offset += run;
> + }
> + printk("\n");
> +}
lib/hexdump.c should already provide most of this functionality?
> @@ -666,11 +970,53 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned
> int addr,
> err_out:
> dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
> return rc;
> +#else
> + memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
> + return 0;
> +#endif
what happens if two adapters are used, with the same SAS address? That
causes problems...
> static void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events)
> {
> - /* FIXME */
> + void __iomem *regs = mvi->regs;
> + /*
> + events is port event.now ,
> + we need check the interrupt status which belongs to per port.
> + */
> + MVS_PRINTK("Port0 = %d", READ_PORT_IRQ_STAT(0));
> }
>
> static void mvs_int_sata(struct mvs_info *mvi)
> @@ -681,9 +1027,10 @@ static void mvs_int_sata(struct mvs_info *mvi)
> static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
> struct mvs_slot_info *slot, unsigned int slot_idx)
> {
> - if (slot->n_elem)
> - pci_unmap_sg(mvi->pdev, task->scatter,
> - slot->n_elem, task->data_dir);
> + if (!sas_protocol_ata(task->task_proto))
> + if (slot->n_elem)
> + pci_unmap_sg(mvi->pdev, task->scatter,
> + slot->n_elem, task->data_dir);
>
> switch (task->task_proto) {
> case SAS_PROTO_SMP:
> @@ -708,9 +1055,34 @@ static void mvs_slot_err(struct mvs_info *mvi, struct
> sas_task *task,
> unsigned int slot_idx)
> {
> /* FIXME */
> + mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
> }
>
> -static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
> +static inline int mvs_can_queue(struct mvs_info *mvi, int num)
> +{
> + int res = 0;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&mvi->lock, flags);
> + if ((mvi->can_queue - num) < 0)
> + res = -EBUSY;
> + else
> + mvi->can_queue -= num;
> + spin_unlock_irqrestore(&mvi->lock, flags);
> +
> + return res;
> +}
> +
> +static inline void mvs_can_dequeue(struct mvs_info *mvi, int num)
> +{
> + /*unsigned long flags;*/
> +
> + /*spin_lock_irqsave(&mvi->lock, flags);*/
> + mvi->can_queue += num;
> + /*spin_unlock_irqrestore(&mvi->lock, flags);*/
these functions are dead code and can be removed, AFAICS
> @@ -816,32 +1201,45 @@ static void mvs_int_rx(struct mvs_info *mvi, bool
> self_clear)
> * we don't have to stall the CPU reading that register.
> * The actual RX ring is offset by one dword, due to this.
> */
> - rx_prod_idx = le32_to_cpu(mvi->rx[0]) & 0xfff;
> + rx_prod_idx = le32_to_cpu(mr32(RX_CONS_IDX)) & RX_RING_SZ_MASK;
This appears to add a new bug... the le32_to_cpu() is not longer
needed, once you started using mr32() macro
The PCI MMIO read/write functions handle that for you (since PCI is
defined to be a little endian bus).
> @@ -978,9 +1458,8 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
> */
> memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
>
> - /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ***************/
> - buf_cmd =
> - buf_tmp = slot->buf;
> + /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
> + buf_cmd = buf_tmp = slot->buf;
> buf_tmp_dma = slot->buf_dma;
>
> hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
> @@ -988,7 +1467,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
> buf_tmp += MVS_ATA_CMD_SZ;
> buf_tmp_dma += MVS_ATA_CMD_SZ;
>
> - /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
> + /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
> /* used for STP. unused for SATA? */
> buf_oaf = buf_tmp;
> hdr->open_frame = cpu_to_le64(buf_tmp_dma);
> @@ -996,32 +1475,37 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
> buf_tmp += MVS_OAF_SZ;
> buf_tmp_dma += MVS_OAF_SZ;
>
> - /* region 3: PRD table ***********************************************/
> + /* region 3: PRD table ********************************************** */
adding this space before "*/" is strange
> /* fill in command FIS and ATAPI CDB */
> - memcpy(buf_cmd, &task->ata_task.fis,
> - sizeof(struct host_to_dev_fis));
> - memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
> + task->ata_task.fis.flags |= 0x80;
> + memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
> + if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
> + memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
prefer that you use named constants rather than 0x40 and 0x80
We call such numeric constants "magic numbers", because open source
reviewers are not given any hint as to what that number represents, its
purpose, its meaning.
> - /* region 4: status buffer (larger the PRD, smaller this buf) ********/
> + /* region 4: status buffer (larger the PRD, smaller this buf) ******* */
> slot->response = buf_tmp;
> hdr->status_buf = cpu_to_le64(buf_tmp_dma);
>
> - req_len = sizeof(struct ssp_frame_hdr) + 28;
> resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
> - sizeof(struct mvs_err_info) - i;
> + sizeof(struct mvs_err_info) - i;
> + resp_len = min(resp_len, (u32) 0x400);
> +
> + req_len = sizeof(struct ssp_frame_hdr) + 28;
same comment here -- use a numeric constant rather than 0x400
> @@ -1131,12 +1620,11 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
> buf_cmd += sizeof(*ssp_hdr);
> memcpy(buf_cmd, &task->ssp_task.LUN, 8);
> buf_cmd[9] = fburst |
> - task->ssp_task.task_attr |
> - (task->ssp_task.task_prio << 3);
> + task->ssp_task.task_attr | (task->ssp_task.task_prio << 3);
> memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
> -
> - /* fill in PRD (scatter/gather) table, if any */
> - sg = task->scatter;
> + /*CDB*/
> + /* fill in PRD (scatter/gather) table, if any */
> + sg = task->scatter;
strange C code indentation (but maybe that's just the patch
tabs-to-spaces corruption mentioned at the top of this email)
> for (i = 0; i < tei->n_elem; i++) {
> buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
> buf_prd->len = cpu_to_le32(sg_dma_len(sg));
> @@ -1155,72 +1643,106 @@ static int mvs_task_exec(struct sas_task *task, const
> int num, gfp_t gfp_flags)
> void __iomem *regs = mvi->regs;
> unsigned long flags;
> struct mvs_task_exec_info tei;
> + struct sas_task *t = task;
> + u32 n = num, pass = 0;
> +
> + mvs_hba_interrupt_enable(mvi, 0);
this is most likely a bug, or remnant of another driver.
should not not need to disable and then re-enable the HBA interrupt on
every task_exec call.
if it's an interrupt mitigation strategy, it needs a large comment block
somewhere, describing what's going on.
> + do {
> + if (!sas_protocol_ata(t->task_proto)) {
> + if (t->num_scatter) {
> + n_elem = pci_map_sg(mvi->pdev, t->scatter,
> + t->num_scatter,
> + t->data_dir);
> + if (!n_elem) {
> + rc = -ENOMEM;
> + goto err_out;
> + }
> + }
> + } else {
> + n_elem = t->num_scatter;
> + }
>
> - /* FIXME: STP/SATA support not complete yet */
> - if (task->task_proto == SATA_PROTO || task->task_proto == SAS_PROTO_STP)
> - return -SAS_DEV_NO_RESPONSE;
> + rc = mvs_tag_alloc(mvi, &tag);
> + if (rc)
> + goto err_out;
>
> - if (task->num_scatter) {
> - n_elem = pci_map_sg(mvi->pdev, task->scatter,
> - task->num_scatter, task->data_dir);
> - if (!n_elem)
> - return -ENOMEM;
> - }
> + mvi->slot_info[tag].task = t;
> + mvi->slot_info[tag].n_elem = n_elem;
> + tei.task = t;
> + tei.hdr = &mvi->slot[tag];
> + tei.tag = tag;
> + tei.n_elem = n_elem;
>
> - spin_lock_irqsave(&mvi->lock, flags);
> + switch (t->task_proto) {
> + case SAS_PROTO_SMP:
> + rc = mvs_task_prep_smp(mvi, &tei);
> + break;
> + case SAS_PROTO_SSP:
> + rc = mvs_task_prep_ssp(mvi, &tei);
> + break;
> + case SATA_PROTO:
> + case SAS_PROTO_STP:
> + rc = mvs_task_prep_ata(mvi, &tei);
> + break;
> + default:
> + rc = -EINVAL;
> + break;
> + }
>
> - rc = mvs_tag_alloc(mvi, &tag);
> - if (rc)
> - goto err_out;
> + if (rc)
> + goto err_out_tag;
>
> - mvi->slot_info[tag].task = task;
> - mvi->slot_info[tag].n_elem = n_elem;
> - tei.task = task;
> - tei.hdr = &mvi->slot[tag];
> - tei.tag = tag;
> - tei.n_elem = n_elem;
> + /* TODO: select normal or high priority */
>
> - switch (task->task_proto) {
> - case SAS_PROTO_SMP:
> - rc = mvs_task_prep_smp(mvi, &tei);
> - break;
> - case SAS_PROTO_SSP:
> - rc = mvs_task_prep_ssp(mvi, &tei);
> - break;
> - case SATA_PROTO:
> - case SAS_PROTO_STP:
> - rc = mvs_task_prep_ata(mvi, &tei);
> - break;
> - default:
> - rc = -EINVAL;
> - break;
> - }
> -
> - if (rc)
> - goto err_out_tag;
> + spin_lock_irqsave(&t->task_state_lock, flags);
> + t->task_state_flags |= SAS_TASK_AT_INITIATOR;
> + spin_unlock_irqrestore(&t->task_state_lock, flags);
>
> - /* TODO: select normal or high priority */
> + if (n == 1) {
> + mvs_hba_interrupt_enable(mvi, 1);
> + mw32(TX_PROD_IDX, mvi->tx_prod);
> + }
> + /*
ditto. this is highly irregular (enabling/disabling HBA interrupt for
each task exec -- lotsa of overhead for questionable gain)
> +static int mvs_abort_task(struct sas_task *task)
> +{
> + /*FIXME*/
> + MVS_PRINTK("mvs abort task\n");
> + return TMF_RESP_FUNC_COMPLETE;
> +}
should make an attempt to do something sane here
> @@ -1249,10 +1771,12 @@ static void mvs_free(struct mvs_info *mvi)
> mvi->rx, mvi->rx_dma);
> if (mvi->slot)
> dma_free_coherent(&mvi->pdev->dev,
> - sizeof(*mvi->slot) * MVS_RX_RING_SZ,
> + sizeof(*mvi->slot) * MVS_SLOTS,
> mvi->slot, mvi->slot_dma);
> +#if 0
> if (mvi->peri_regs)
> iounmap(mvi->peri_regs);
> +#endif
> if (mvi->regs)
> iounmap(mvi->regs);
> if (mvi->shost)
maybe change this #if, and related #ifs, to
#ifdef MVS_ENABLE_PERI
?
> @@ -1274,25 +1798,25 @@ static int mvs_phy_control(struct asd_sas_phy *sas_phy,
> enum phy_func func,
> reg = mvi->regs + MVS_P0_SER_CTLSTAT + (phy_id * 4);
>
> switch (func) {
> - case PHY_FUNC_SET_LINK_RATE: {
> - struct sas_phy_linkrates *rates = funcdata;
> - u32 lrmin = 0, lrmax = 0;
> + case PHY_FUNC_SET_LINK_RATE:{
> + struct sas_phy_linkrates *rates = funcdata;
> + u32 lrmin = 0, lrmax = 0;
>
> - lrmin = (rates->minimum_linkrate << 8);
> - lrmax = (rates->maximum_linkrate << 12);
> + lrmin = (rates->minimum_linkrate << 8);
> + lrmax = (rates->maximum_linkrate << 12);
>
> - tmp = readl(reg);
> - if (lrmin) {
> - tmp &= ~(0xf << 8);
> - tmp |= lrmin;
> - }
> - if (lrmax) {
> - tmp &= ~(0xf << 12);
> - tmp |= lrmax;
> + tmp = readl(reg);
> + if (lrmin) {
> + tmp &= ~(0xf << 8);
> + tmp |= lrmin;
> + }
> + if (lrmax) {
> + tmp &= ~(0xf << 12);
> + tmp |= lrmax;
> + }
> + writel(tmp, reg);
> + break;
the C code indentation appears wrong (but again, maybe that's the email
problem)
> @@ -1381,9 +1905,10 @@ static struct mvs_info * __devinit mvs_alloc(struct
> pci_dev *pdev,
>
> SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
> mvi->shost->transportt = mvs_stt;
> - mvi->shost->max_id = ~0;
> - mvi->shost->max_lun = ~0;
> - mvi->shost->max_cmd_len = ~0;
> + mvi->shost->max_id = 21;
> + mvi->shost->max_lun = 2;
> + mvi->shost->max_channel = 0;
> + mvi->shost->max_cmd_len = 16;
max_lun of 2? that seems quite incorrect. your hardware does not have
that limit, AFAICS.
> @@ -1476,13 +2008,13 @@ err_out:
> return NULL;
> }
>
> -static u32 mvs_cr32(void __iomem *regs, u32 addr)
> +static inline u32 mvs_cr32(void __iomem *regs, u32 addr)
> {
> mw32(CMD_ADDR, addr);
> return mr32(CMD_DATA);
> }
>
> -static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
> +static inline void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
> {
> mw32(CMD_ADDR, addr);
> mw32(CMD_DATA, val);
there is no need for explicit inlining here. if its useful to inline,
let the compiler make that decision.
it's marked 'static', which is sufficient to enable the compiler to do
module-scoped optimizations.
> @@ -1547,6 +2079,174 @@ static void __devinit mvs_phy_hacks(struct mvs_info
> *mvi)
> tmp &= 0x1fffffff;
> tmp |= (2U << 29); /* 8 ms retry */
> mvs_cw32(regs, CMD_PHY_TIMER, tmp);
> +
> + /* TEST - for phy decoding error, adjust voltage levels */
> + mw32(P0_VSR_ADDR + 0, 0x8);
> + mw32(P0_VSR_DATA + 0, 0x2F0);
> +
> + mw32(P0_VSR_ADDR + 8, 0x8);
> + mw32(P0_VSR_DATA + 8, 0x2F0);
> +
> + mw32(P0_VSR_ADDR + 16, 0x8);
> + mw32(P0_VSR_DATA + 16, 0x2F0);
> +
> + mw32(P0_VSR_ADDR + 24, 0x8);
> + mw32(P0_VSR_DATA + 24, 0x2F0);
> +
> +}
is this test code needed in the submitted driver?
> + /* workaround for HW phy decoding error on 1.5g disk drive */
> + WRITE_PORT_VSR_ADDR(i, 0x06);
> + tmp = READ_PORT_VSR_DATA(i);
> + if (((phy->phystatus & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
> + PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
> + SAS_LINK_RATE_1_5_GBPS)
> + tmp &= ~0x20000000;
> + else
> + tmp |= 0x20000000;
> + WRITE_PORT_VSR_DATA(i, tmp);
> +
> + }
> + phy->irqstatus = READ_PORT_IRQ_STAT(i);
replace 0x20000000 with a named constant
> static int __devinit mvs_hw_init(struct mvs_info *mvi)
> @@ -1559,6 +2259,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
> mw32(GBL_CTL, 0);
> tmp = mr32(GBL_CTL);
>
> + /*ResetController */
/* reset controller */
it's not a function, and whitespace makes things more readable :)
> @@ -1590,13 +2290,24 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
> return -EBUSY;
> }
>
> + /*InitChip */
ditto
> /* make sure RST is set; HBA_RST /should/ have done that for us */
> - cctl = mr32(CTL);
> + cctl = mr32(CTL); /*MVS_CTL */
> if (cctl & CCTL_RST)
> cctl &= ~CCTL_RST;
> else
> mw32_f(CTL, cctl | CCTL_RST);
>
> + pci_read_config_dword(mvi->pdev, PCI_COMMAND, &tmp);
> + /*MV_PCI_DEV_EN */
> + tmp |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
> + pci_write_config_dword(mvi->pdev, PCI_COMMAND, tmp);
are you sure this wasn't just copied from another driver?
pci_enable_device() turns on PCI_COMMAND_IO and PCI_COMMAND_MEMORY, and
pci_set_master() turns on PCI_COMMAND_MASTER.
In general, you should not need to twiddle PCI_COMMAND register this
way, it has already been done for you.
> @@ -1609,6 +2320,9 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
>
> mw32_f(CTL, cctl);
>
> + /* reset control */
> + mw32(PCS, 0); /*MVS_PCS */
> +
> mvs_phy_hacks(mvi);
>
request improved comment :) or simply delete, if it is redundant to
"reset control" comment
Overall: no major complaints or objections, only minor stuff. After
fixing all the minor stuff, the main issue is getting your email set up
correctly to send patches.
Jeff
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-23 3:58 ` Jeff Garzik
@ 2008-01-23 10:54 ` Ke Wei
2008-01-23 11:41 ` Jeff Garzik
2008-01-25 21:27 ` James Bottomley
2008-01-23 19:23 ` Grant Grundler
1 sibling, 2 replies; 22+ messages in thread
From: Ke Wei @ 2008-01-23 10:54 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linux-scsi, kewei, qswang, jfeng, qzhao
[-- Attachment #1: Type: text/plain, Size: 30424 bytes --]
Attachment is a patch file for 6440 driver. I will have to spend more
time on setting my mail client. Yesterday I used mutt tool. But Look
like the problem still exists.
I fixed all issues which you mentioned , but
> > @@ -666,11 +970,53 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned
> > int addr,
> > err_out:
> > dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
> > return rc;
> > +#else
> > + memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
> > + return 0;
> > +#endif
>
>
> what happens if two adapters are used, with the same SAS address? That
> causes problems...
>
>
Our bios can write SAS Address per port when system boot , so I think
we don't need read or configure address.
And I reserved hexdump funciton if you don't care. Only debugging.
> > +static int mvs_abort_task(struct sas_task *task)
> > +{
> > + /*FIXME*/
> > + MVS_PRINTK("mvs abort task\n");
> > + return TMF_RESP_FUNC_COMPLETE;
> > +}
>
> should make an attempt to do something sane here
>
if entering this abort function , I think I must fix the unknown
issues instead of here. But I also will implement next.
On Jan 23, 2008 11:58 AM, Jeff Garzik <jeff@garzik.org> wrote:
>
> Comments inline, mostly minor stuff cleaning up the source.
>
> Major problem though: your mailer converted tabs to spaces, so our
> automated patch tools won't work on your submission. It usually takes a
> few attempts to get your email setup working, such that all the
> automated tools used in the Linux community work.
>
>
> Ke Wei wrote:
> > +#define MVS_QUEUE_SIZE (30)
>
> to be consistent with the rest of the driver, make this an enum
>
>
> > +#define MVS_PRINTK(_x_, ...) \
> > + printk(KERN_NOTICE DRV_NAME ": " _x_ , ## __VA_ARGS__)
> >
> > #define mr32(reg) readl(regs + MVS_##reg)
> > #define mw32(reg,val) writel((val), regs + MVS_##reg)
> > @@ -47,6 +53,65 @@
> > readl(regs + MVS_##reg); \
> > } while (0)
> >
> > +#define MVS_BIT(x) (1L << (x))
> > +
> > +#define PORT_TYPE_SATA MVS_BIT(0)
> > +#define PORT_TYPE_SAS MVS_BIT(1)
>
> to be consistent with the rest of the driver, just open-code "1 << n".
> This also makes it easier to get the C type correct.
>
>
>
> > +#define MVS_ID_NOT_MAPPED 0xff
> > +#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
> > +
> > +/* offset for D2H FIS in the Received FIS List Structure */
> > +#define SATA_RECEIVED_D2H_FIS(reg_set) \
> > + (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
> > +#define SATA_RECEIVED_PIO_FIS(reg_set) \
> > + (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
> > +#define UNASSOC_D2H_FIS(id) \
> > + (mvi->rx_fis + 0x100 * id)
> > +
> > +
> > +#define READ_PORT_CONFIG_DATA(i) \
> > + ((i > 3)?mr32(P4_CFG_DATA + (i - 4) * 8):mr32(P0_CFG_DATA + i * 8))
> > +#define WRITE_PORT_CONFIG_DATA(i,tmp) \
> > + {if (i > 3)mw32(P4_CFG_DATA + (i - 4) * 8, tmp); \
> > + else \
> > + mw32(P0_CFG_DATA + i * 8, tmp); }
> > +#define WRITE_PORT_CONFIG_ADDR(i,tmp) \
> > + {if (i > 3)mw32(P4_CFG_ADDR + (i - 4) * 8, tmp); \
> > + else \
> > + mw32(P0_CFG_ADDR + i * 8, tmp); }
> > +
> > +#define READ_PORT_PHY_CONTROL(i) \
> > + ((i > 3)?mr32(P4_SER_CTLSTAT + (i - 4) * 4):mr32(P0_SER_CTLSTAT+i * 4))
> > +#define WRITE_PORT_PHY_CONTROL(i,tmp) \
> > + {if (i > 3)mw32(P4_SER_CTLSTAT + (i - 4) * 4, tmp); \
> > + else \
> > + mw32(P0_SER_CTLSTAT + i * 4, tmp); }
> > +
> > +#define READ_PORT_VSR_DATA(i) \
> > + ((i > 3)?mr32(P4_VSR_DATA + (i - 4) * 8):mr32(P0_VSR_DATA+i*8))
> > +#define WRITE_PORT_VSR_DATA(i,tmp) \
> > + {if (i > 3)mw32(P4_VSR_DATA + (i - 4) * 8, tmp); \
> > + else \
> > + mw32(P0_VSR_DATA + i*8, tmp); }
> > +#define WRITE_PORT_VSR_ADDR(i,tmp) \
> > + {if (i > 3)mw32(P4_VSR_ADDR + (i - 4) * 8, tmp); \
> > + else \
> > + mw32(P0_VSR_ADDR + i * 8, tmp); }
> > +
> > +#define READ_PORT_IRQ_STAT(i) \
> > + ((i > 3)?mr32(P4_INT_STAT + (i - 4) * 8):mr32(P0_INT_STAT + i * 8))
> > +#define WRITE_PORT_IRQ_STAT(i,tmp) \
> > + {if (i > 3)mw32(P4_INT_STAT + (i-4) * 8, tmp); \
> > + else \
> > + mw32(P0_INT_STAT + i * 8, tmp); }
> > +#define READ_PORT_IRQ_MASK(i) \
> > + ((i > 3)?mr32(P4_INT_MASK + (i-4) * 8):mr32(P0_INT_MASK+i*8))
> > +#define WRITE_PORT_IRQ_MASK(i,tmp) \
> > + {if (i > 3)mw32(P4_INT_MASK + (i-4) * 8, tmp); \
> > + else \
> > + mw32(P0_INT_MASK + i * 8, tmp); }
>
>
> make these macros readable, by breaking each C statement into a separate
> line
>
>
>
>
> > @@ -260,13 +368,33 @@ enum hw_register_bits {
> > PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */
> >
> > /* MVS_PCS */
> > + PCS_EN_SATA_REG = (16), /* Enable SATA Register Set*/
> > + PCS_EN_PORT_XMT_START = (12), /* Enable Port Transmit*/
> > + PCS_EN_PORT_XMT_START2 = (8), /* For 6480*/
> > PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */
> > PCS_RSP_RX_EN = (1U << 7), /* raw response rx */
> > PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */
> > PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */
> > PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */
> > - PCS_CMD_RST = (1U << 2), /* reset cmd issue */
> > + PCS_CMD_RST = (1U << 1), /* reset cmd issue */
> > PCS_CMD_EN = (1U << 0), /* enable cmd issue */
> > +
> > + /*Port n Attached Device Info*/
> > + PORT_DEV_SSP_TRGT = (1U << 19),
> > + PORT_DEV_SMP_TRGT = (1U << 18),
> > + PORT_DEV_STP_TRGT = (1U << 17),
> > + PORT_DEV_SSP_INIT = (1U << 11),
> > + PORT_DEV_SMP_INIT = (1U << 10),
> > + PORT_DEV_STP_INIT = (1U << 9),
> > + PORT_PHY_ID_MASK = (0xFFU << 24),
> > + PORT_DEV_TRGT_MASK = (0x7U << 17),
> > + PORT_DEV_INIT_MASK = (0x7U << 9),
> > + PORT_DEV_TYPE_MASK = (0x7U << 0),
> > +
> > + /*Port n PHY Status*/
> > + PHY_RDY = (1U << 2),
> > + PHY_DW_SYNC = (1U << 1),
> > + PHY_OOB_DTCTD = (1U << 0),
>
> to be consistent, add spaces after /* and before */
>
>
> >
> > struct mvs_port {
> > struct asd_sas_port sas_port;
> > + u8 taskfileset;
> > };
> >
> > struct mvs_phy {
> > struct mvs_port *port;
> > struct asd_sas_phy sas_phy;
> > + struct sas_identify identify;
> > + __le32 devinfo;
> > + __le64 devsasaddr;
> > + __le32 attdevinfo;
> > + __le64 attdevsasaddr;
> > + u32 type;
> > + __le32 phystatus;
> > + __le32 irqstatus;
> > + u8 wideportphymap;
> > + u32 frame_rcvd_size;
> > + u8 frame_rcvd[32];
>
> following linux style (and style used in my original driver), consider
> adding some '_' underscores, to separate out words.
>
> dev_info
> phy_stat
> irq_stat
> etc.
>
> also, following the style in this driver, please add comments describing
> what the fields do
>
>
>
> > - u8 frame_rcvd[24 + 1024];
> > };
> >
> > struct mvs_info {
> > @@ -437,27 +585,39 @@ struct mvs_info {
> > dma_addr_t rx_dma;
> > u32 rx_cons; /* RX consumer idx */
> >
> > - __le32 *rx_fis; /* RX'd FIS area */
> > + void *rx_fis; /* RX'd FIS area */
> > dma_addr_t rx_fis_dma;
> >
> > - struct mvs_cmd_hdr *slot; /* DMA command header slots */
> > + struct mvs_cmd_hdr *slot; /* DMA command header slots */
> > dma_addr_t slot_dma;
> >
> > const struct mvs_chip_info *chip;
> >
> > - /* further per-slot information */
> > + unsigned long tags[MVS_SLOTS];
> > struct mvs_slot_info slot_info[MVS_SLOTS];
> > - unsigned long tags[(MVS_SLOTS / sizeof(unsigned long)) + 1];
> > -
> > + /* further per-slot information */
> > struct mvs_phy phy[MVS_MAX_PHYS];
> > struct mvs_port port[MVS_MAX_PHYS];
> > +
> > + u32 can_queue; /* per adapter */
> > + u32 tag_out; /*Get*/
> > + u32 tag_in; /*Give*/
> > +};
> > +
> > +struct mvs_queue_task {
> > + struct list_head list;
> > +
> > + void *uldd_task;
> > };
> >
> > +static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
> > +static void mvs_scan_start(struct Scsi_Host *);
> > +
> > static struct scsi_transport_template *mvs_stt;
> >
> > static const struct mvs_chip_info mvs_chips[] = {
> > - [chip_6320] = { 2, 16, 9 },
> > - [chip_6440] = { 4, 16, 9 },
> > + [chip_6320] = { 2, 16, 9 },
> > + [chip_6440] = { 4, 16, 9 },
> > [chip_6480] = { 8, 32, 10 },
> > };
> >
> > @@ -468,6 +628,8 @@ static struct scsi_host_template mvs_sht = {
> > .target_alloc = sas_target_alloc,
> > .slave_configure = sas_slave_configure,
> > .slave_destroy = sas_slave_destroy,
> > + .scan_finished = mvs_scan_finished,
> > + .scan_start = mvs_scan_start,
> > .change_queue_depth = sas_change_queue_depth,
> > .change_queue_type = sas_change_queue_type,
> > .bios_param = sas_bios_param,
> > @@ -477,14 +639,154 @@ static struct scsi_host_template mvs_sht = {
> > .sg_tablesize = SG_ALL,
> > .max_sectors = SCSI_DEFAULT_MAX_SECTORS,
> > .use_clustering = ENABLE_CLUSTERING,
> > - .eh_device_reset_handler= sas_eh_device_reset_handler,
> > + .eh_device_reset_handler = sas_eh_device_reset_handler,
> > .eh_bus_reset_handler = sas_eh_bus_reset_handler,
> > .slave_alloc = sas_slave_alloc,
> > .target_destroy = sas_target_destroy,
> > .ioctl = sas_ioctl,
> > };
> >
> > -static void mvs_int_rx(struct mvs_info *mvi, bool self_clear);
> > +static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
> > +{
> > + u32 i;
> > + u32 run;
> > + u32 offset;
> > +
> > + offset = 0;
> > + while (size) {
> > + printk("%08X : ", baseaddr + offset);
> > + if (size >= 16)
> > + run = 16;
> > + else
> > + run = size;
> > + size -= run;
> > + for (i = 0; i < 16; i++) {
> > + if (i < run)
> > + printk("%02X ", (unsigned int)data[i]);
> > + else
> > + printk(" ");
> > + }
> > + printk(": ");
> > + for (i = 0; i < run; i++)
> > + printk("%c", isalnum(data[i]) ? data[i] : '.');
> > + printk("\n");
> > + data = &data[16];
> > + offset += run;
> > + }
> > + printk("\n");
> > +}
>
> lib/hexdump.c should already provide most of this functionality?
>
>
> > @@ -666,11 +970,53 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned
> > int addr,
> > err_out:
> > dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
> > return rc;
> > +#else
> > + memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
> > + return 0;
> > +#endif
>
>
> what happens if two adapters are used, with the same SAS address? That
> causes problems...
>
>
>
> > static void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events)
> > {
> > - /* FIXME */
> > + void __iomem *regs = mvi->regs;
> > + /*
> > + events is port event.now ,
> > + we need check the interrupt status which belongs to per port.
> > + */
> > + MVS_PRINTK("Port0 = %d", READ_PORT_IRQ_STAT(0));
> > }
> >
> > static void mvs_int_sata(struct mvs_info *mvi)
> > @@ -681,9 +1027,10 @@ static void mvs_int_sata(struct mvs_info *mvi)
> > static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
> > struct mvs_slot_info *slot, unsigned int slot_idx)
> > {
> > - if (slot->n_elem)
> > - pci_unmap_sg(mvi->pdev, task->scatter,
> > - slot->n_elem, task->data_dir);
> > + if (!sas_protocol_ata(task->task_proto))
> > + if (slot->n_elem)
> > + pci_unmap_sg(mvi->pdev, task->scatter,
> > + slot->n_elem, task->data_dir);
> >
> > switch (task->task_proto) {
> > case SAS_PROTO_SMP:
> > @@ -708,9 +1055,34 @@ static void mvs_slot_err(struct mvs_info *mvi, struct
> > sas_task *task,
> > unsigned int slot_idx)
> > {
> > /* FIXME */
> > + mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
> > }
> >
> > -static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
> > +static inline int mvs_can_queue(struct mvs_info *mvi, int num)
> > +{
> > + int res = 0;
> > + unsigned long flags;
> > +
> > + spin_lock_irqsave(&mvi->lock, flags);
> > + if ((mvi->can_queue - num) < 0)
> > + res = -EBUSY;
> > + else
> > + mvi->can_queue -= num;
> > + spin_unlock_irqrestore(&mvi->lock, flags);
> > +
> > + return res;
> > +}
> > +
> > +static inline void mvs_can_dequeue(struct mvs_info *mvi, int num)
> > +{
> > + /*unsigned long flags;*/
> > +
> > + /*spin_lock_irqsave(&mvi->lock, flags);*/
> > + mvi->can_queue += num;
> > + /*spin_unlock_irqrestore(&mvi->lock, flags);*/
>
> these functions are dead code and can be removed, AFAICS
>
>
>
> > @@ -816,32 +1201,45 @@ static void mvs_int_rx(struct mvs_info *mvi, bool
> > self_clear)
> > * we don't have to stall the CPU reading that register.
> > * The actual RX ring is offset by one dword, due to this.
> > */
> > - rx_prod_idx = le32_to_cpu(mvi->rx[0]) & 0xfff;
> > + rx_prod_idx = le32_to_cpu(mr32(RX_CONS_IDX)) & RX_RING_SZ_MASK;
>
> This appears to add a new bug... the le32_to_cpu() is not longer
> needed, once you started using mr32() macro
>
> The PCI MMIO read/write functions handle that for you (since PCI is
> defined to be a little endian bus).
>
>
> > @@ -978,9 +1458,8 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
> > */
> > memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
> >
> > - /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ***************/
> > - buf_cmd =
> > - buf_tmp = slot->buf;
> > + /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
> > + buf_cmd = buf_tmp = slot->buf;
> > buf_tmp_dma = slot->buf_dma;
> >
> > hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
> > @@ -988,7 +1467,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
> > buf_tmp += MVS_ATA_CMD_SZ;
> > buf_tmp_dma += MVS_ATA_CMD_SZ;
> >
> > - /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
> > + /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
> > /* used for STP. unused for SATA? */
> > buf_oaf = buf_tmp;
> > hdr->open_frame = cpu_to_le64(buf_tmp_dma);
>
> > @@ -996,32 +1475,37 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
> > buf_tmp += MVS_OAF_SZ;
> > buf_tmp_dma += MVS_OAF_SZ;
> >
> > - /* region 3: PRD table ***********************************************/
> > + /* region 3: PRD table ********************************************** */
>
>
> adding this space before "*/" is strange
>
>
>
> > /* fill in command FIS and ATAPI CDB */
> > - memcpy(buf_cmd, &task->ata_task.fis,
> > - sizeof(struct host_to_dev_fis));
> > - memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
> > + task->ata_task.fis.flags |= 0x80;
> > + memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
> > + if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
> > + memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
>
> prefer that you use named constants rather than 0x40 and 0x80
>
> We call such numeric constants "magic numbers", because open source
> reviewers are not given any hint as to what that number represents, its
> purpose, its meaning.
>
>
>
> > - /* region 4: status buffer (larger the PRD, smaller this buf) ********/
> > + /* region 4: status buffer (larger the PRD, smaller this buf) ******* */
> > slot->response = buf_tmp;
> > hdr->status_buf = cpu_to_le64(buf_tmp_dma);
> >
> > - req_len = sizeof(struct ssp_frame_hdr) + 28;
> > resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
> > - sizeof(struct mvs_err_info) - i;
> > + sizeof(struct mvs_err_info) - i;
> > + resp_len = min(resp_len, (u32) 0x400);
> > +
> > + req_len = sizeof(struct ssp_frame_hdr) + 28;
>
> same comment here -- use a numeric constant rather than 0x400
>
>
>
> > @@ -1131,12 +1620,11 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
> > buf_cmd += sizeof(*ssp_hdr);
> > memcpy(buf_cmd, &task->ssp_task.LUN, 8);
> > buf_cmd[9] = fburst |
> > - task->ssp_task.task_attr |
> > - (task->ssp_task.task_prio << 3);
> > + task->ssp_task.task_attr | (task->ssp_task.task_prio << 3);
> > memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
> > -
> > - /* fill in PRD (scatter/gather) table, if any */
> > - sg = task->scatter;
> > + /*CDB*/
> > + /* fill in PRD (scatter/gather) table, if any */
> > + sg = task->scatter;
>
> strange C code indentation (but maybe that's just the patch
> tabs-to-spaces corruption mentioned at the top of this email)
>
>
> > for (i = 0; i < tei->n_elem; i++) {
> > buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
> > buf_prd->len = cpu_to_le32(sg_dma_len(sg));
> > @@ -1155,72 +1643,106 @@ static int mvs_task_exec(struct sas_task *task, const
> > int num, gfp_t gfp_flags)
> > void __iomem *regs = mvi->regs;
> > unsigned long flags;
> > struct mvs_task_exec_info tei;
> > + struct sas_task *t = task;
> > + u32 n = num, pass = 0;
> > +
> > + mvs_hba_interrupt_enable(mvi, 0);
>
>
> this is most likely a bug, or remnant of another driver.
>
> should not not need to disable and then re-enable the HBA interrupt on
> every task_exec call.
>
> if it's an interrupt mitigation strategy, it needs a large comment block
> somewhere, describing what's going on.
>
>
>
> > + do {
> > + if (!sas_protocol_ata(t->task_proto)) {
> > + if (t->num_scatter) {
> > + n_elem = pci_map_sg(mvi->pdev, t->scatter,
> > + t->num_scatter,
> > + t->data_dir);
> > + if (!n_elem) {
> > + rc = -ENOMEM;
> > + goto err_out;
> > + }
> > + }
> > + } else {
> > + n_elem = t->num_scatter;
> > + }
> >
> > - /* FIXME: STP/SATA support not complete yet */
> > - if (task->task_proto == SATA_PROTO || task->task_proto == SAS_PROTO_STP)
> > - return -SAS_DEV_NO_RESPONSE;
> > + rc = mvs_tag_alloc(mvi, &tag);
> > + if (rc)
> > + goto err_out;
> >
> > - if (task->num_scatter) {
> > - n_elem = pci_map_sg(mvi->pdev, task->scatter,
> > - task->num_scatter, task->data_dir);
> > - if (!n_elem)
> > - return -ENOMEM;
> > - }
> > + mvi->slot_info[tag].task = t;
> > + mvi->slot_info[tag].n_elem = n_elem;
> > + tei.task = t;
> > + tei.hdr = &mvi->slot[tag];
> > + tei.tag = tag;
> > + tei.n_elem = n_elem;
> >
> > - spin_lock_irqsave(&mvi->lock, flags);
> > + switch (t->task_proto) {
> > + case SAS_PROTO_SMP:
> > + rc = mvs_task_prep_smp(mvi, &tei);
> > + break;
> > + case SAS_PROTO_SSP:
> > + rc = mvs_task_prep_ssp(mvi, &tei);
> > + break;
> > + case SATA_PROTO:
> > + case SAS_PROTO_STP:
> > + rc = mvs_task_prep_ata(mvi, &tei);
> > + break;
> > + default:
> > + rc = -EINVAL;
> > + break;
> > + }
> >
> > - rc = mvs_tag_alloc(mvi, &tag);
> > - if (rc)
> > - goto err_out;
> > + if (rc)
> > + goto err_out_tag;
> >
> > - mvi->slot_info[tag].task = task;
> > - mvi->slot_info[tag].n_elem = n_elem;
> > - tei.task = task;
> > - tei.hdr = &mvi->slot[tag];
> > - tei.tag = tag;
> > - tei.n_elem = n_elem;
> > + /* TODO: select normal or high priority */
> >
> > - switch (task->task_proto) {
> > - case SAS_PROTO_SMP:
> > - rc = mvs_task_prep_smp(mvi, &tei);
> > - break;
> > - case SAS_PROTO_SSP:
> > - rc = mvs_task_prep_ssp(mvi, &tei);
> > - break;
> > - case SATA_PROTO:
> > - case SAS_PROTO_STP:
> > - rc = mvs_task_prep_ata(mvi, &tei);
> > - break;
> > - default:
> > - rc = -EINVAL;
> > - break;
> > - }
> > -
> > - if (rc)
> > - goto err_out_tag;
> > + spin_lock_irqsave(&t->task_state_lock, flags);
> > + t->task_state_flags |= SAS_TASK_AT_INITIATOR;
> > + spin_unlock_irqrestore(&t->task_state_lock, flags);
> >
> > - /* TODO: select normal or high priority */
> > + if (n == 1) {
> > + mvs_hba_interrupt_enable(mvi, 1);
> > + mw32(TX_PROD_IDX, mvi->tx_prod);
> > + }
> > + /*
>
> ditto. this is highly irregular (enabling/disabling HBA interrupt for
> each task exec -- lotsa of overhead for questionable gain)
>
>
>
> > +static int mvs_abort_task(struct sas_task *task)
> > +{
> > + /*FIXME*/
> > + MVS_PRINTK("mvs abort task\n");
> > + return TMF_RESP_FUNC_COMPLETE;
> > +}
>
> should make an attempt to do something sane here
>
>
> > @@ -1249,10 +1771,12 @@ static void mvs_free(struct mvs_info *mvi)
> > mvi->rx, mvi->rx_dma);
> > if (mvi->slot)
> > dma_free_coherent(&mvi->pdev->dev,
> > - sizeof(*mvi->slot) * MVS_RX_RING_SZ,
> > + sizeof(*mvi->slot) * MVS_SLOTS,
> > mvi->slot, mvi->slot_dma);
> > +#if 0
> > if (mvi->peri_regs)
> > iounmap(mvi->peri_regs);
> > +#endif
> > if (mvi->regs)
> > iounmap(mvi->regs);
> > if (mvi->shost)
>
> maybe change this #if, and related #ifs, to
>
> #ifdef MVS_ENABLE_PERI
>
>
> ?
>
>
> > @@ -1274,25 +1798,25 @@ static int mvs_phy_control(struct asd_sas_phy *sas_phy,
> > enum phy_func func,
> > reg = mvi->regs + MVS_P0_SER_CTLSTAT + (phy_id * 4);
> >
> > switch (func) {
> > - case PHY_FUNC_SET_LINK_RATE: {
> > - struct sas_phy_linkrates *rates = funcdata;
> > - u32 lrmin = 0, lrmax = 0;
> > + case PHY_FUNC_SET_LINK_RATE:{
> > + struct sas_phy_linkrates *rates = funcdata;
> > + u32 lrmin = 0, lrmax = 0;
> >
> > - lrmin = (rates->minimum_linkrate << 8);
> > - lrmax = (rates->maximum_linkrate << 12);
> > + lrmin = (rates->minimum_linkrate << 8);
> > + lrmax = (rates->maximum_linkrate << 12);
> >
> > - tmp = readl(reg);
> > - if (lrmin) {
> > - tmp &= ~(0xf << 8);
> > - tmp |= lrmin;
> > - }
> > - if (lrmax) {
> > - tmp &= ~(0xf << 12);
> > - tmp |= lrmax;
> > + tmp = readl(reg);
> > + if (lrmin) {
> > + tmp &= ~(0xf << 8);
> > + tmp |= lrmin;
> > + }
> > + if (lrmax) {
> > + tmp &= ~(0xf << 12);
> > + tmp |= lrmax;
> > + }
> > + writel(tmp, reg);
> > + break;
>
> the C code indentation appears wrong (but again, maybe that's the email
> problem)
>
>
> > @@ -1381,9 +1905,10 @@ static struct mvs_info * __devinit mvs_alloc(struct
> > pci_dev *pdev,
> >
> > SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
> > mvi->shost->transportt = mvs_stt;
> > - mvi->shost->max_id = ~0;
> > - mvi->shost->max_lun = ~0;
> > - mvi->shost->max_cmd_len = ~0;
> > + mvi->shost->max_id = 21;
> > + mvi->shost->max_lun = 2;
> > + mvi->shost->max_channel = 0;
> > + mvi->shost->max_cmd_len = 16;
>
> max_lun of 2? that seems quite incorrect. your hardware does not have
> that limit, AFAICS.
>
>
>
> > @@ -1476,13 +2008,13 @@ err_out:
> > return NULL;
> > }
> >
> > -static u32 mvs_cr32(void __iomem *regs, u32 addr)
> > +static inline u32 mvs_cr32(void __iomem *regs, u32 addr)
> > {
> > mw32(CMD_ADDR, addr);
> > return mr32(CMD_DATA);
> > }
> >
> > -static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
> > +static inline void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
> > {
> > mw32(CMD_ADDR, addr);
> > mw32(CMD_DATA, val);
>
> there is no need for explicit inlining here. if its useful to inline,
> let the compiler make that decision.
>
> it's marked 'static', which is sufficient to enable the compiler to do
> module-scoped optimizations.
>
>
> > @@ -1547,6 +2079,174 @@ static void __devinit mvs_phy_hacks(struct mvs_info
> > *mvi)
> > tmp &= 0x1fffffff;
> > tmp |= (2U << 29); /* 8 ms retry */
> > mvs_cw32(regs, CMD_PHY_TIMER, tmp);
> > +
> > + /* TEST - for phy decoding error, adjust voltage levels */
> > + mw32(P0_VSR_ADDR + 0, 0x8);
> > + mw32(P0_VSR_DATA + 0, 0x2F0);
> > +
> > + mw32(P0_VSR_ADDR + 8, 0x8);
> > + mw32(P0_VSR_DATA + 8, 0x2F0);
> > +
> > + mw32(P0_VSR_ADDR + 16, 0x8);
> > + mw32(P0_VSR_DATA + 16, 0x2F0);
> > +
> > + mw32(P0_VSR_ADDR + 24, 0x8);
> > + mw32(P0_VSR_DATA + 24, 0x2F0);
> > +
> > +}
>
> is this test code needed in the submitted driver?
>
>
>
> > + /* workaround for HW phy decoding error on 1.5g disk drive */
> > + WRITE_PORT_VSR_ADDR(i, 0x06);
> > + tmp = READ_PORT_VSR_DATA(i);
> > + if (((phy->phystatus & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
> > + PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
> > + SAS_LINK_RATE_1_5_GBPS)
> > + tmp &= ~0x20000000;
> > + else
> > + tmp |= 0x20000000;
> > + WRITE_PORT_VSR_DATA(i, tmp);
> > +
> > + }
> > + phy->irqstatus = READ_PORT_IRQ_STAT(i);
>
> replace 0x20000000 with a named constant
>
>
>
> > static int __devinit mvs_hw_init(struct mvs_info *mvi)
> > @@ -1559,6 +2259,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
> > mw32(GBL_CTL, 0);
> > tmp = mr32(GBL_CTL);
> >
> > + /*ResetController */
>
>
> /* reset controller */
>
> it's not a function, and whitespace makes things more readable :)
>
>
> > @@ -1590,13 +2290,24 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
> > return -EBUSY;
> > }
> >
> > + /*InitChip */
>
> ditto
>
>
>
> > /* make sure RST is set; HBA_RST /should/ have done that for us */
> > - cctl = mr32(CTL);
> > + cctl = mr32(CTL); /*MVS_CTL */
> > if (cctl & CCTL_RST)
> > cctl &= ~CCTL_RST;
> > else
> > mw32_f(CTL, cctl | CCTL_RST);
> >
> > + pci_read_config_dword(mvi->pdev, PCI_COMMAND, &tmp);
> > + /*MV_PCI_DEV_EN */
> > + tmp |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
> > + pci_write_config_dword(mvi->pdev, PCI_COMMAND, tmp);
>
> are you sure this wasn't just copied from another driver?
>
> pci_enable_device() turns on PCI_COMMAND_IO and PCI_COMMAND_MEMORY, and
> pci_set_master() turns on PCI_COMMAND_MASTER.
>
> In general, you should not need to twiddle PCI_COMMAND register this
> way, it has already been done for you.
>
>
> > @@ -1609,6 +2320,9 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
> >
> > mw32_f(CTL, cctl);
> >
> > + /* reset control */
> > + mw32(PCS, 0); /*MVS_PCS */
> > +
> > mvs_phy_hacks(mvi);
> >
>
> request improved comment :) or simply delete, if it is redundant to
> "reset control" comment
>
>
>
> Overall: no major complaints or objections, only minor stuff. After
> fixing all the minor stuff, the main issue is getting your email set up
> correctly to send patches.
>
> Jeff
>
>
>
>
>
--
Best Regards,
Ke Wei
[-- Attachment #2: mvsas.patch --]
[-- Type: text/plain, Size: 21547 bytes --]
Signed-off-by: Ke Wei <kewei@marvell.com>
---
drivers/scsi/mvsas.c | 304 ++++++++++++++++++++++++++------------------------
1 files changed, 159 insertions(+), 145 deletions(-)
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
index fb376a7..0637a2b 100755
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -42,7 +42,7 @@
#define DRV_VERSION "0.3"
#define _MV_DUMP 0
#define MVS_DISABLE_NVRAM
-#define MVS_QUEUE_SIZE (30)
+
#define MVS_PRINTK(_x_, ...) \
printk(KERN_NOTICE DRV_NAME ": " _x_ , ## __VA_ARGS__)
@@ -53,11 +53,6 @@
readl(regs + MVS_##reg); \
} while (0)
-#define MVS_BIT(x) (1L << (x))
-
-#define PORT_TYPE_SATA MVS_BIT(0)
-#define PORT_TYPE_SAS MVS_BIT(1)
-
#define MVS_ID_NOT_MAPPED 0xff
#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
@@ -72,45 +67,59 @@
#define READ_PORT_CONFIG_DATA(i) \
((i > 3)?mr32(P4_CFG_DATA + (i - 4) * 8):mr32(P0_CFG_DATA + i * 8))
-#define WRITE_PORT_CONFIG_DATA(i,tmp) \
- {if (i > 3)mw32(P4_CFG_DATA + (i - 4) * 8, tmp); \
+#define WRITE_PORT_CONFIG_DATA(i,tmp) { \
+ if (i > 3) \
+ mw32(P4_CFG_DATA + (i - 4) * 8, tmp); \
else \
- mw32(P0_CFG_DATA + i * 8, tmp); }
-#define WRITE_PORT_CONFIG_ADDR(i,tmp) \
- {if (i > 3)mw32(P4_CFG_ADDR + (i - 4) * 8, tmp); \
+ mw32(P0_CFG_DATA + i * 8, tmp); \
+ }
+#define WRITE_PORT_CONFIG_ADDR(i,tmp) { \
+ if (i > 3) \
+ mw32(P4_CFG_ADDR + (i - 4) * 8, tmp); \
else \
- mw32(P0_CFG_ADDR + i * 8, tmp); }
+ mw32(P0_CFG_ADDR + i * 8, tmp); \
+ }
#define READ_PORT_PHY_CONTROL(i) \
((i > 3)?mr32(P4_SER_CTLSTAT + (i - 4) * 4):mr32(P0_SER_CTLSTAT+i * 4))
-#define WRITE_PORT_PHY_CONTROL(i,tmp) \
- {if (i > 3)mw32(P4_SER_CTLSTAT + (i - 4) * 4, tmp); \
+#define WRITE_PORT_PHY_CONTROL(i,tmp) { \
+ if (i > 3) \
+ mw32(P4_SER_CTLSTAT + (i - 4) * 4, tmp); \
else \
- mw32(P0_SER_CTLSTAT + i * 4, tmp); }
+ mw32(P0_SER_CTLSTAT + i * 4, tmp); \
+ }
#define READ_PORT_VSR_DATA(i) \
((i > 3)?mr32(P4_VSR_DATA + (i - 4) * 8):mr32(P0_VSR_DATA+i*8))
-#define WRITE_PORT_VSR_DATA(i,tmp) \
- {if (i > 3)mw32(P4_VSR_DATA + (i - 4) * 8, tmp); \
+#define WRITE_PORT_VSR_DATA(i,tmp) { \
+ if (i > 3) \
+ mw32(P4_VSR_DATA + (i - 4) * 8, tmp); \
else \
- mw32(P0_VSR_DATA + i*8, tmp); }
-#define WRITE_PORT_VSR_ADDR(i,tmp) \
- {if (i > 3)mw32(P4_VSR_ADDR + (i - 4) * 8, tmp); \
+ mw32(P0_VSR_DATA + i*8, tmp); \
+ }
+#define WRITE_PORT_VSR_ADDR(i,tmp) { \
+ if (i > 3) \
+ mw32(P4_VSR_ADDR + (i - 4) * 8, tmp); \
else \
- mw32(P0_VSR_ADDR + i * 8, tmp); }
+ mw32(P0_VSR_ADDR + i * 8, tmp); \
+ }
#define READ_PORT_IRQ_STAT(i) \
((i > 3)?mr32(P4_INT_STAT + (i - 4) * 8):mr32(P0_INT_STAT + i * 8))
-#define WRITE_PORT_IRQ_STAT(i,tmp) \
- {if (i > 3)mw32(P4_INT_STAT + (i-4) * 8, tmp); \
+#define WRITE_PORT_IRQ_STAT(i,tmp) { \
+ if (i > 3) \
+ mw32(P4_INT_STAT + (i-4) * 8, tmp); \
else \
- mw32(P0_INT_STAT + i * 8, tmp); }
+ mw32(P0_INT_STAT + i * 8, tmp); \
+ }
#define READ_PORT_IRQ_MASK(i) \
((i > 3)?mr32(P4_INT_MASK + (i-4) * 8):mr32(P0_INT_MASK+i*8))
-#define WRITE_PORT_IRQ_MASK(i,tmp) \
- {if (i > 3)mw32(P4_INT_MASK + (i-4) * 8, tmp); \
+#define WRITE_PORT_IRQ_MASK(i,tmp) { \
+ if (i > 3) \
+ mw32(P4_INT_MASK + (i-4) * 8, tmp); \
else \
- mw32(P0_INT_MASK + i * 8, tmp); }
+ mw32(P0_INT_MASK + i * 8, tmp); \
+ }
/* driver compile-time configuration */
enum driver_configuration {
@@ -126,6 +135,8 @@ enum driver_configuration {
MVS_OAF_SZ = 64, /* Open address frame buffer size */
MVS_RX_FIS_COUNT = 17, /* Optional rx'd FISs (max 17) */
+
+ MVS_QUEUE_SIZE = 30, /* Support Queue depth */
};
/* unchangeable hardware details */
@@ -368,9 +379,9 @@ enum hw_register_bits {
PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */
/* MVS_PCS */
- PCS_EN_SATA_REG = (16), /* Enable SATA Register Set*/
- PCS_EN_PORT_XMT_START = (12), /* Enable Port Transmit*/
- PCS_EN_PORT_XMT_START2 = (8), /* For 6480*/
+ PCS_EN_SATA_REG = (16), /* Enable SATA Register Set */
+ PCS_EN_PORT_XMT_START = (12), /* Enable Port Transmit */
+ PCS_EN_PORT_XMT_START2 = (8), /* For 6480 */
PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */
PCS_RSP_RX_EN = (1U << 7), /* raw response rx */
PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */
@@ -379,7 +390,7 @@ enum hw_register_bits {
PCS_CMD_RST = (1U << 1), /* reset cmd issue */
PCS_CMD_EN = (1U << 0), /* enable cmd issue */
- /*Port n Attached Device Info*/
+ /* Port n Attached Device Info */
PORT_DEV_SSP_TRGT = (1U << 19),
PORT_DEV_SMP_TRGT = (1U << 18),
PORT_DEV_STP_TRGT = (1U << 17),
@@ -391,10 +402,14 @@ enum hw_register_bits {
PORT_DEV_INIT_MASK = (0x7U << 9),
PORT_DEV_TYPE_MASK = (0x7U << 0),
- /*Port n PHY Status*/
+ /* Port n PHY Status */
PHY_RDY = (1U << 2),
PHY_DW_SYNC = (1U << 1),
PHY_OOB_DTCTD = (1U << 0),
+
+ /* VSR */
+ /* PHYMODE 6 (CDB) */
+ PHY_MODE6_DTL_SPEED = (1U << 27),
};
enum mvs_info_flags {
@@ -477,6 +492,24 @@ enum sas_sata_config_port_regs {
PHYR_CURRENT2 = 0x88, /* current connection info 2 */
};
+/* SAS/SATA Vendor Specific Port Registers */
+enum sas_sata_vsp_regs {
+ VSR_PHY_STAT = 0x00, /* Phy Status */
+ VSR_PHY_MODE1 = 0x01, /* phy tx */
+ VSR_PHY_MODE2 = 0x02, /* tx scc */
+ VSR_PHY_MODE3 = 0x03, /* pll */
+ VSR_PHY_MODE4 = 0x04, /* VCO */
+ VSR_PHY_MODE5 = 0x05, /* Rx */
+ VSR_PHY_MODE6 = 0x06, /* CDR */
+ VSR_PHY_MODE7 = 0x07, /* Impedance */
+ VSR_PHY_MODE8 = 0x08, /* Voltage */
+ VSR_PHY_MODE9 = 0x09, /* Test */
+ VSR_PHY_MODE10 = 0x0A, /* Power */
+ VSR_PHY_MODE11 = 0x0B, /* Phy Mode */
+ VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */
+ VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */
+};
+
enum pci_cfg_registers {
PCR_PHY_CTL = 0x40,
PCR_PHY_CTL2 = 0x90,
@@ -501,6 +534,34 @@ enum chip_flavors {
chip_6480,
};
+enum port_type {
+ PORT_TYPE_SAS = (1L << 1),
+ PORT_TYPE_SATA = (1L << 0),
+};
+
+/* Command Table Format */
+enum ct_format {
+ /* SSP */
+ SSP_F_H = 0x00,
+ SSP_F_IU = 0x18,
+ SSP_F_MAX = 0x4D,
+ /* STP */
+ STP_CMD_FIS = 0x00,
+ STP_ATAPI_CMD = 0x40,
+ STP_F_MAX = 0x10,
+ /* SMP */
+ SMP_F_T = 0x00,
+ SMP_F_DEP = 0x01,
+ SMP_F_MAX = 0x101,
+};
+
+enum status_buffer {
+ SB_EIR_OFF = 0x00, /* Error Information Record */
+ SB_RFB_OFF = 0x08, /* Response Frame Buffer */
+ SB_RFB_MAX = 0x400, /* RFB size*/
+};
+
+
struct mvs_chip_info {
u32 n_phy;
u32 srs_sz;
@@ -552,14 +613,14 @@ struct mvs_phy {
struct mvs_port *port;
struct asd_sas_phy sas_phy;
struct sas_identify identify;
- __le32 devinfo;
- __le64 devsasaddr;
- __le32 attdevinfo;
- __le64 attdevsasaddr;
+ __le32 dev_info;
+ __le64 dev_sas_addr;
+ __le32 att_dev_info;
+ __le64 att_dev_sas_addr;
u32 type;
- __le32 phystatus;
- __le32 irqstatus;
- u8 wideportphymap;
+ __le32 phy_status;
+ __le32 irq_status;
+ u8 wide_port_phymap;
u32 frame_rcvd_size;
u8 frame_rcvd[32];
@@ -676,7 +737,7 @@ static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
printk("\n");
}
-static inline void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
+static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
enum sas_proto proto)
{
u32 offset;
@@ -821,18 +882,18 @@ static int pci_go_64(struct pci_dev *pdev)
return rc;
}
-static inline void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
+static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
{
mvi->tag_in = (mvi->tag_in + 1) & (MVS_SLOTS - 1);
mvi->tags[mvi->tag_in] = tag;
}
-static inline void mvs_tag_free(struct mvs_info *mvi, u32 tag)
+static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
{
mvi->tag_out = (mvi->tag_out - 1) & (MVS_SLOTS - 1);
}
-static inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
+static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
{
if (mvi->tag_out != mvi->tag_in) {
*tag_out = mvi->tags[mvi->tag_out];
@@ -971,7 +1032,6 @@ err_out:
dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
return rc;
#else
- memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
return 0;
#endif
}
@@ -1058,30 +1118,6 @@ static void mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
}
-static inline int mvs_can_queue(struct mvs_info *mvi, int num)
-{
- int res = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&mvi->lock, flags);
- if ((mvi->can_queue - num) < 0)
- res = -EBUSY;
- else
- mvi->can_queue -= num;
- spin_unlock_irqrestore(&mvi->lock, flags);
-
- return res;
-}
-
-static inline void mvs_can_dequeue(struct mvs_info *mvi, int num)
-{
- /*unsigned long flags;*/
-
- /*spin_lock_irqsave(&mvi->lock, flags);*/
- mvi->can_queue += num;
- /*spin_unlock_irqrestore(&mvi->lock, flags);*/
-}
-
static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
{
unsigned int slot_idx = rx_desc & RXQ_SLOT_MASK;
@@ -1201,7 +1237,7 @@ static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
* we don't have to stall the CPU reading that register.
* The actual RX ring is offset by one dword, due to this.
*/
- rx_prod_idx = le32_to_cpu(mr32(RX_CONS_IDX)) & RX_RING_SZ_MASK;
+ rx_prod_idx = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
if (rx_prod_idx == 0xfff) { /* h/w hasn't touched RX ring yet */
mvi->rx_cons = 0xfff;
return 0;
@@ -1344,7 +1380,7 @@ err_out:
return rc;
}
-static inline void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
{
void __iomem *regs = mvi->regs;
u32 tmp, offs;
@@ -1364,7 +1400,7 @@ static inline void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
port->taskfileset = MVS_ID_NOT_MAPPED;
}
-static inline u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
{
int i;
u32 tmp, offs;
@@ -1392,7 +1428,7 @@ static inline u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
return MVS_ID_NOT_MAPPED;
}
-static inline u32 mvs_get_ncq_tag(struct sas_task *task)
+static u32 mvs_get_ncq_tag(struct sas_task *task)
{
u32 tag = 0;
struct ata_queued_cmd *qc = task->uldd_task;
@@ -1418,7 +1454,8 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
void *buf_tmp;
u8 *buf_cmd, *buf_oaf;
dma_addr_t buf_tmp_dma;
- unsigned int i, req_len, resp_len;
+ u32 i, req_len, resp_len;
+ const u32 max_resp_len = SB_RFB_MAX;
struct mvs_port *port = (struct mvs_port *)sas_port->lldd_port;
if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED)
@@ -1498,14 +1535,15 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
sizeof(struct mvs_err_info) - i;
/* request, response lengths */
- resp_len = min(resp_len, (u32) 0x400);
+ resp_len = min(resp_len, max_resp_len);
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
+ task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
/* fill in command FIS and ATAPI CDB */
- task->ata_task.fis.flags |= 0x80;
memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
- memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
+ memcpy(buf_cmd + STP_ATAPI_CMD,
+ task->ata_task.atapi_packet, 16);
/* fill in PRD (scatter/gather) table, if any */
sg = task->scatter;
@@ -1528,13 +1566,14 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
struct mvs_cmd_hdr *hdr = tei->hdr;
struct mvs_slot_info *slot;
struct scatterlist *sg;
- u32 resp_len, req_len, i, tag = tei->tag;
struct mvs_prd *buf_prd;
struct ssp_frame_hdr *ssp_hdr;
void *buf_tmp;
u8 *buf_cmd, *buf_oaf, fburst = 0;
dma_addr_t buf_tmp_dma;
u32 flags;
+ u32 resp_len, req_len, i, tag = tei->tag;
+ const u32 max_resp_len = SB_RFB_MAX;
slot = &mvi->slot_info[tag];
@@ -1593,7 +1632,7 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
sizeof(struct mvs_err_info) - i;
- resp_len = min(resp_len, (u32) 0x400);
+ resp_len = min(resp_len, max_resp_len);
req_len = sizeof(struct ssp_frame_hdr) + 28;
@@ -1619,12 +1658,11 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
/* fill in command frame IU */
buf_cmd += sizeof(*ssp_hdr);
memcpy(buf_cmd, &task->ssp_task.LUN, 8);
- buf_cmd[9] = fburst |
- task->ssp_task.task_attr | (task->ssp_task.task_prio << 3);
+ buf_cmd[9] = fburst | task->ssp_task.task_attr |
+ (task->ssp_task.task_prio << 3);
memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
- /*CDB*/
- /* fill in PRD (scatter/gather) table, if any */
- sg = task->scatter;
+ /* fill in PRD (scatter/gather) table, if any */
+ sg = task->scatter;
for (i = 0; i < tei->n_elem; i++) {
buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
buf_prd->len = cpu_to_le32(sg_dma_len(sg));
@@ -1646,7 +1684,7 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
struct sas_task *t = task;
u32 n = num, pass = 0;
- mvs_hba_interrupt_enable(mvi, 0);
+ spin_lock_irqsave(&mvi->lock, flags);
do {
if (!sas_protocol_ata(t->task_proto)) {
@@ -1695,12 +1733,12 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
/* TODO: select normal or high priority */
- spin_lock_irqsave(&t->task_state_lock, flags);
+ spin_lock(&t->task_state_lock);
t->task_state_flags |= SAS_TASK_AT_INITIATOR;
- spin_unlock_irqrestore(&t->task_state_lock, flags);
+ spin_unlock(&t->task_state_lock);
if (n == 1) {
- mvs_hba_interrupt_enable(mvi, 1);
+ spin_unlock_irqrestore(&mvi->lock, flags);
mw32(TX_PROD_IDX, mvi->tx_prod);
}
/*
@@ -1732,7 +1770,7 @@ err_out:
t->data_dir);
if (pass)
mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
- mvs_hba_interrupt_enable(mvi, 1);
+ spin_unlock_irqrestore(&mvi->lock, flags);
return rc;
}
@@ -1773,7 +1811,7 @@ static void mvs_free(struct mvs_info *mvi)
dma_free_coherent(&mvi->pdev->dev,
sizeof(*mvi->slot) * MVS_SLOTS,
mvi->slot, mvi->slot_dma);
-#if 0
+#ifdef MVS_ENABLE_PERI
if (mvi->peri_regs)
iounmap(mvi->peri_regs);
#endif
@@ -1906,7 +1944,7 @@ static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
mvi->shost->transportt = mvs_stt;
mvi->shost->max_id = 21;
- mvi->shost->max_lun = 2;
+ mvi->shost->max_lun = ~0;
mvi->shost->max_channel = 0;
mvi->shost->max_cmd_len = 16;
@@ -1934,7 +1972,7 @@ static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
if (!res_start || !res_len)
goto err_out;
-#if 0
+#ifdef MVS_ENABLE_PERI
mvi->peri_regs = ioremap_nocache(res_start, res_len);
if (!mvi->peri_regs)
goto err_out;
@@ -2008,40 +2046,18 @@ err_out:
return NULL;
}
-static inline u32 mvs_cr32(void __iomem *regs, u32 addr)
+static u32 mvs_cr32(void __iomem *regs, u32 addr)
{
mw32(CMD_ADDR, addr);
return mr32(CMD_DATA);
}
-static inline void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
+static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
{
mw32(CMD_ADDR, addr);
mw32(CMD_DATA, val);
}
-#if 0
-static u32 mvs_phy_read(struct mvs_info *mvi, unsigned int phy_id, u32 addr)
-{
- void __iomem *regs = mvi->regs;
- void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8);
-
- writel(addr, phy_regs);
- return readl(phy_regs + 4);
-}
-
-static void mvs_phy_write(struct mvs_info *mvi, unsigned int phy_id,
- u32 addr, u32 val)
-{
- void __iomem *regs = mvi->regs;
- void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8);
-
- writel(addr, phy_regs);
- writel(val, phy_regs + 4);
- readl(phy_regs); /* flush */
-}
-#endif
-
static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
@@ -2095,7 +2111,7 @@ static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
}
-static inline void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
+static void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
{
void __iomem *regs = mvi->regs;
u32 tmp;
@@ -2131,7 +2147,7 @@ static void mvs_detect_porttype(struct mvs_info *mvi, int i)
}
-static inline void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
+static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
{
u32 *s = (u32 *) buf;
void __iomem *regs = mvi->regs;
@@ -2154,7 +2170,7 @@ static inline void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
return (void *)s;
}
-static inline u32 mvs_is_sig_fis_received(struct mvs_info *mvi, int i)
+static u32 mvs_is_sig_fis_received(struct mvs_info *mvi, int i)
{
u32 tmp;
void __iomem *regs = mvi->regs;
@@ -2174,23 +2190,22 @@ static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
__le64 tmp64;
WRITE_PORT_CONFIG_ADDR(i, PHYR_IDENTIFY);
- phy->devinfo = READ_PORT_CONFIG_DATA(i);
+ phy->dev_info = READ_PORT_CONFIG_DATA(i);
WRITE_PORT_CONFIG_ADDR(i, PHYR_ADDR_HI);
- phy->devsasaddr = (__le64) READ_PORT_CONFIG_DATA(i) << 32;
+ phy->dev_sas_addr = (__le64) READ_PORT_CONFIG_DATA(i) << 32;
WRITE_PORT_CONFIG_ADDR(i, PHYR_ADDR_LO);
- phy->devsasaddr |= READ_PORT_CONFIG_DATA(i); /*le */
+ phy->dev_sas_addr |= READ_PORT_CONFIG_DATA(i); /* le */
- phy->phystatus = READ_PORT_PHY_CONTROL(i);
- /*MVS_PRINTK("PhyStatus=%X\n",phy->phystatus);*/
+ phy->phy_status = READ_PORT_PHY_CONTROL(i);
- /*FIXME Update Wide Port info */
+ /* FIXME Update Wide Port info */
phy->port = &mvi->port[i];
phy->port->sas_port.lldd_port = phy->port;
phy->port->taskfileset = MVS_ID_NOT_MAPPED;
- if (phy->phystatus & PHY_READY_MASK) {
+ if (phy->phy_status & PHY_READY_MASK) {
u32 phy_st;
struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
@@ -2198,27 +2213,29 @@ static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
phy_st = READ_PORT_CONFIG_DATA(i);
WRITE_PORT_CONFIG_ADDR(i, PHYR_ATT_ADDR_HI);
- phy->attdevsasaddr = (__le64) READ_PORT_CONFIG_DATA(i) << 32;
+ phy->att_dev_sas_addr = (__le64) READ_PORT_CONFIG_DATA(i) << 32;
WRITE_PORT_CONFIG_ADDR(i, PHYR_ATT_ADDR_LO);
- phy->attdevsasaddr |= READ_PORT_CONFIG_DATA(i);
+ phy->att_dev_sas_addr |= READ_PORT_CONFIG_DATA(i);
/*Updated attached_sas_addr */
- tmp64 = phy->attdevsasaddr;
- MVS_PRINTK("phy[%d] Get Attached Address 0x%llX \n", i, tmp64);
+ tmp64 = phy->att_dev_sas_addr;
+ MVS_PRINTK("phy[%d] Get Attached Address 0x%llX ,"
+ " SAS Address 0x%llX\n",
+ i, tmp64, phy->dev_sas_addr);
tmp64 = cpu_to_be64(tmp64);
memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
if (phy->type & PORT_TYPE_SAS) {
WRITE_PORT_CONFIG_ADDR(i, PHYR_ATT_DEV_INFO);
- phy->attdevinfo = READ_PORT_CONFIG_DATA(i);
+ phy->att_dev_info = READ_PORT_CONFIG_DATA(i);
phy->identify.device_type =
- phy->attdevinfo & PORT_DEV_TYPE_MASK;
+ phy->att_dev_info & PORT_DEV_TYPE_MASK;
MVS_PRINTK("device_type = %d\n",
phy->identify.device_type);
sas_phy->linkrate =
- (phy->phystatus & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
if (phy_st & PHY_OOB_DTCTD)
sas_phy->oob_mode = SAS_OOB_MODE;
@@ -2235,18 +2252,18 @@ static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
}
}
/* workaround for HW phy decoding error on 1.5g disk drive */
- WRITE_PORT_VSR_ADDR(i, 0x06);
+ WRITE_PORT_VSR_ADDR(i, VSR_PHY_MODE6);
tmp = READ_PORT_VSR_DATA(i);
- if (((phy->phystatus & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
SAS_LINK_RATE_1_5_GBPS)
- tmp &= ~0x20000000;
+ tmp &= ~PHY_MODE6_DTL_SPEED;
else
- tmp |= 0x20000000;
+ tmp |= PHY_MODE6_DTL_SPEED;
WRITE_PORT_VSR_DATA(i, tmp);
}
- phy->irqstatus = READ_PORT_IRQ_STAT(i);
+ phy->irq_status = READ_PORT_IRQ_STAT(i);
}
static int __devinit mvs_hw_init(struct mvs_info *mvi)
@@ -2259,7 +2276,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32(GBL_CTL, 0);
tmp = mr32(GBL_CTL);
- /*ResetController */
+ /* Reset Controller */
if (!(tmp & HBA_RST)) {
if (mvi->flags & MVF_PHY_PWR_FIX) {
pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
@@ -2290,18 +2307,14 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
return -EBUSY;
}
- /*InitChip */
+ /* Init Chip */
/* make sure RST is set; HBA_RST /should/ have done that for us */
- cctl = mr32(CTL); /*MVS_CTL */
+ cctl = mr32(CTL);
if (cctl & CCTL_RST)
cctl &= ~CCTL_RST;
else
mw32_f(CTL, cctl | CCTL_RST);
- pci_read_config_dword(mvi->pdev, PCI_COMMAND, &tmp);
- /*MV_PCI_DEV_EN */
- tmp |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
- pci_write_config_dword(mvi->pdev, PCI_COMMAND, tmp);
/* write to device control _AND_ device status register? - A.C. */
pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
tmp &= ~PRD_REQ_MASK;
@@ -2342,6 +2355,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
/* init and reset phys */
for (i = 0; i < mvi->chip->n_phy; i++) {
/* FIXME: is this the correct dword order? */
+#ifdef MVS_DISABLE_NVRAM
u32 lo = *((u32 *)&mvi->sas_addr[0]);
u32 hi = *((u32 *)&mvi->sas_addr[4]);
@@ -2352,7 +2366,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
WRITE_PORT_CONFIG_DATA(i, lo);
WRITE_PORT_CONFIG_ADDR(i, PHYR_ADDR_HI);
WRITE_PORT_CONFIG_DATA(i, hi);
-
+#endif
/* reset phy */
tmp = READ_PORT_PHY_CONTROL(i);
tmp |= PHY_RST;
--
1.5.3.7
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-23 10:54 ` Ke Wei
@ 2008-01-23 11:41 ` Jeff Garzik
2008-01-25 16:43 ` Ke Wei
2008-01-25 21:27 ` James Bottomley
1 sibling, 1 reply; 22+ messages in thread
From: Jeff Garzik @ 2008-01-23 11:41 UTC (permalink / raw)
To: Ke Wei; +Cc: linux-scsi, kewei, qswang, jfeng, qzhao
Ke Wei wrote:
> Attachment is a patch file for 6440 driver. I will have to spend more
> time on setting my mail client. Yesterday I used mutt tool. But Look
> like the problem still exists.
> I fixed all issues which you mentioned , but
The changes look good, thanks!
In terms of engineering process, I should have been more clear: when
revising your submission, you should make the revisions and then
regenerate your original patch.
To use a silly example, if you needed to fix a 1-character typo in a
1,000-line patch, you would need to make your revision, re-generate the
1,000-line patch, and email that new patch.
So, to move forward, please create one single patch with the latest
mvsas, diff'd against the 'mvsas' branch of
git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
I will "ack" that patch (indicate my approval), and unless other
objections surface, James will merge your patch into the 'mvsas' branch.
That will get the driver on the road to be included in 2.6.25.
>>> @@ -666,11 +970,53 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned
>>> int addr,
>>> err_out:
>>> dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
>>> return rc;
>>> +#else
>>> + memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
>>> + return 0;
>>> +#endif
>>
>> what happens if two adapters are used, with the same SAS address? That
>> causes problems...
>>
>>
> Our bios can write SAS Address per port when system boot , so I think
> we don't need read or configure address.
It is standard Linux policy to reduce or eliminate BIOS dependencies as
much as possible.
This is because there are several common scenarios where BIOS may not
run, or otherwise not be available:
* suspend/resume
* controller hotplug
* non-x86 PCI platforms such as POWER
Thus, we need the driver to obtain these addresses -- hopefully reading
them from a BIOS data table somewhere, if NVRAM is not available.
This is a highly common scenario -- obtaining unique identifying
information in the absence of BIOS.
Similarly, we cannot rely on BIOS to perform any global reset or errata
workaround duties for us. That must be coded into the driver also.
> And I reserved hexdump funciton if you don't care. Only debugging.
It is not an important matter, but it would be nice to clean that up
eventually.
Also, FWIW, we have a standard method of debug output:
struct pci_dev *pdev;
dev_dbg(&pdev->dev, KERN_INFO,
"this is debug message number %d", 2);
which will only be compiled into the driver when DEBUG is defined.
>>> +static int mvs_abort_task(struct sas_task *task)
>>> +{
>>> + /*FIXME*/
>>> + MVS_PRINTK("mvs abort task\n");
>>> + return TMF_RESP_FUNC_COMPLETE;
>>> +}
>> should make an attempt to do something sane here
>>
> if entering this abort function , I think I must fix the unknown
> issues instead of here. But I also will implement next.
Ok, thanks.
Jeff
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-23 3:58 ` Jeff Garzik
2008-01-23 10:54 ` Ke Wei
@ 2008-01-23 19:23 ` Grant Grundler
1 sibling, 0 replies; 22+ messages in thread
From: Grant Grundler @ 2008-01-23 19:23 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Ke Wei, linux-scsi, kewei, qswang, jfeng, qzhao
On Jan 22, 2008 7:58 PM, Jeff Garzik <jeff@garzik.org> wrote:
> > +#define READ_PORT_CONFIG_DATA(i) \
> > + ((i > 3)?mr32(P4_CFG_DATA + (i - 4) * 8):mr32(P0_CFG_DATA + i * 8))
> > +#define WRITE_PORT_CONFIG_DATA(i,tmp) \
> > + {if (i > 3)mw32(P4_CFG_DATA + (i - 4) * 8, tmp); \
> > + else \
> > + mw32(P0_CFG_DATA + i * 8, tmp); }
> > +#define WRITE_PORT_CONFIG_ADDR(i,tmp) \
> > + {if (i > 3)mw32(P4_CFG_ADDR + (i - 4) * 8, tmp); \
> > + else \
> > + mw32(P0_CFG_ADDR + i * 8, tmp); }
> > +
> > +#define READ_PORT_PHY_CONTROL(i) \
> > + ((i > 3)?mr32(P4_SER_CTLSTAT + (i - 4) * 4):mr32(P0_SER_CTLSTAT+i * 4))
> > +#define WRITE_PORT_PHY_CONTROL(i,tmp) \
> > + {if (i > 3)mw32(P4_SER_CTLSTAT + (i - 4) * 4, tmp); \
> > + else \
> > + mw32(P0_SER_CTLSTAT + i * 4, tmp); }
> > +
> > +#define READ_PORT_VSR_DATA(i) \
> > + ((i > 3)?mr32(P4_VSR_DATA + (i - 4) * 8):mr32(P0_VSR_DATA+i*8))
> > +#define WRITE_PORT_VSR_DATA(i,tmp) \
> > + {if (i > 3)mw32(P4_VSR_DATA + (i - 4) * 8, tmp); \
> > + else \
> > + mw32(P0_VSR_DATA + i*8, tmp); }
> > +#define WRITE_PORT_VSR_ADDR(i,tmp) \
> > + {if (i > 3)mw32(P4_VSR_ADDR + (i - 4) * 8, tmp); \
> > + else \
> > + mw32(P0_VSR_ADDR + i * 8, tmp); }
> > +
> > +#define READ_PORT_IRQ_STAT(i) \
> > + ((i > 3)?mr32(P4_INT_STAT + (i - 4) * 8):mr32(P0_INT_STAT + i * 8))
> > +#define WRITE_PORT_IRQ_STAT(i,tmp) \
> > + {if (i > 3)mw32(P4_INT_STAT + (i-4) * 8, tmp); \
> > + else \
> > + mw32(P0_INT_STAT + i * 8, tmp); }
> > +#define READ_PORT_IRQ_MASK(i) \
> > + ((i > 3)?mr32(P4_INT_MASK + (i-4) * 8):mr32(P0_INT_MASK+i*8))
> > +#define WRITE_PORT_IRQ_MASK(i,tmp) \
> > + {if (i > 3)mw32(P4_INT_MASK + (i-4) * 8, tmp); \
> > + else \
> > + mw32(P0_INT_MASK + i * 8, tmp); }
>
>
> make these macros readable, by breaking each C statement into a separate
> line
I'd prefer these all be written as static functions. Let the compiler do
the type checking instead of assuming we've got it right. There is no
performance difference AFAIK.
>
>
>
>
> > @@ -260,13 +368,33 @@ enum hw_register_bits {
> > PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */
> >
> > /* MVS_PCS */
> > + PCS_EN_SATA_REG = (16), /* Enable SATA Register Set*/
> > + PCS_EN_PORT_XMT_START = (12), /* Enable Port Transmit*/
> > + PCS_EN_PORT_XMT_START2 = (8), /* For 6480*/
> > PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */
> > PCS_RSP_RX_EN = (1U << 7), /* raw response rx */
> > PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */
> > PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */
What's the difference between PCS_FIS_RX_EN and PCS_EN_SATA_REG?
Grouping them together implies they define bits/commands for the same register.
The three new entries collide with the existing definitions and it's
not obvious what
the intended usage is.
Later, jeff pointed out drivers should be using dev_dbg() instead of splattering
"MVS_PRINTK" alll over the place. I'd like to strongly encourage that.
hth,
grant
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-23 11:41 ` Jeff Garzik
@ 2008-01-25 16:43 ` Ke Wei
2008-01-25 17:24 ` Grant Grundler
` (3 more replies)
0 siblings, 4 replies; 22+ messages in thread
From: Ke Wei @ 2008-01-25 16:43 UTC (permalink / raw)
To: Jeff Garzik; +Cc: linux-scsi, kewei, qswang, jfeng, qzhao
[-- Attachment #1: Type: text/plain, Size: 3426 bytes --]
The attached is Marvell 6440 SAS/SATA driver. I will try to send email
by git-send-email.
Changelog :
Merged from Jeff's branch to James's branch.
Signed-off-by: Ke Wei <kewei@marvell.com>
On Jan 23, 2008 7:41 PM, Jeff Garzik <jeff@garzik.org> wrote:
> Ke Wei wrote:
> > Attachment is a patch file for 6440 driver. I will have to spend more
> > time on setting my mail client. Yesterday I used mutt tool. But Look
> > like the problem still exists.
> > I fixed all issues which you mentioned , but
>
> The changes look good, thanks!
>
> In terms of engineering process, I should have been more clear: when
> revising your submission, you should make the revisions and then
> regenerate your original patch.
>
> To use a silly example, if you needed to fix a 1-character typo in a
> 1,000-line patch, you would need to make your revision, re-generate the
> 1,000-line patch, and email that new patch.
>
> So, to move forward, please create one single patch with the latest
> mvsas, diff'd against the 'mvsas' branch of
> git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
>
> I will "ack" that patch (indicate my approval), and unless other
> objections surface, James will merge your patch into the 'mvsas' branch.
> That will get the driver on the road to be included in 2.6.25.
>
>
> >>> @@ -666,11 +970,53 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned
> >>> int addr,
> >>> err_out:
> >>> dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
> >>> return rc;
> >>> +#else
> >>> + memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
> >>> + return 0;
> >>> +#endif
> >>
> >> what happens if two adapters are used, with the same SAS address? That
> >> causes problems...
> >>
> >>
> > Our bios can write SAS Address per port when system boot , so I think
> > we don't need read or configure address.
>
> It is standard Linux policy to reduce or eliminate BIOS dependencies as
> much as possible.
>
> This is because there are several common scenarios where BIOS may not
> run, or otherwise not be available:
>
> * suspend/resume
> * controller hotplug
> * non-x86 PCI platforms such as POWER
>
> Thus, we need the driver to obtain these addresses -- hopefully reading
> them from a BIOS data table somewhere, if NVRAM is not available.
>
> This is a highly common scenario -- obtaining unique identifying
> information in the absence of BIOS.
>
>
>
> Similarly, we cannot rely on BIOS to perform any global reset or errata
> workaround duties for us. That must be coded into the driver also.
>
>
> > And I reserved hexdump funciton if you don't care. Only debugging.
>
> It is not an important matter, but it would be nice to clean that up
> eventually.
>
> Also, FWIW, we have a standard method of debug output:
>
> struct pci_dev *pdev;
>
> dev_dbg(&pdev->dev, KERN_INFO,
> "this is debug message number %d", 2);
>
> which will only be compiled into the driver when DEBUG is defined.
>
>
> >>> +static int mvs_abort_task(struct sas_task *task)
> >>> +{
> >>> + /*FIXME*/
> >>> + MVS_PRINTK("mvs abort task\n");
> >>> + return TMF_RESP_FUNC_COMPLETE;
> >>> +}
> >> should make an attempt to do something sane here
> >>
> > if entering this abort function , I think I must fix the unknown
> > issues instead of here. But I also will implement next.
>
> Ok, thanks.
>
> Jeff
>
>
>
>
--
Best Regards,
Ke Wei
[-- Attachment #2: 0042-Marvell-6440-SAS-SATA-driver.patch --]
[-- Type: text/plain, Size: 66456 bytes --]
From c08fa2ad97be03ecf1ff27eb761ba06e38211611 Mon Sep 17 00:00:00 2001
From: root <root@ubuntu.domain>
Date: Sat, 26 Jan 2008 00:27:48 +0800
Subject: [PATCH] Marvell 6440 SAS/SATA driver
Changelog :
Merged from Jeff's branch to James's branch.
Signed-off-by: Ke Wei <kewei@marvell.com>
---
drivers/scsi/mvsas.c | 1376 ++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 1108 insertions(+), 268 deletions(-)
mode change 100644 => 100755 drivers/scsi/mvsas.c
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
old mode 100644
new mode 100755
index 03638b9..321be21
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -2,6 +2,7 @@
mvsas.c - Marvell 88SE6440 SAS/SATA support
Copyright 2007 Red Hat, Inc.
+ Copyright 2008 Marvell. <kewei@marvell.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -37,8 +38,10 @@
#include <scsi/libsas.h>
#include <asm/io.h>
-#define DRV_NAME "mvsas"
-#define DRV_VERSION "0.1"
+#define DRV_NAME "mvsas"
+#define DRV_VERSION "0.3"
+#define _MV_DUMP 0
+#define MVS_DISABLE_NVRAM
#define mr32(reg) readl(regs + MVS_##reg)
#define mw32(reg,val) writel((val), regs + MVS_##reg)
@@ -47,6 +50,17 @@
readl(regs + MVS_##reg); \
} while (0)
+#define MVS_ID_NOT_MAPPED 0xff
+#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
+
+/* offset for D2H FIS in the Received FIS List Structure */
+#define SATA_RECEIVED_D2H_FIS(reg_set) \
+ (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
+#define SATA_RECEIVED_PIO_FIS(reg_set) \
+ (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
+#define UNASSOC_D2H_FIS(id) \
+ (mvi->rx_fis + 0x100 * id)
+
/* driver compile-time configuration */
enum driver_configuration {
MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */
@@ -57,10 +71,12 @@ enum driver_configuration {
MVS_SLOTS = 512, /* command slots */
MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */
MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */
- MVS_ATA_CMD_SZ = 128, /* SATA command table buffer size */
+ MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */
MVS_OAF_SZ = 64, /* Open address frame buffer size */
MVS_RX_FIS_COUNT = 17, /* Optional rx'd FISs (max 17) */
+
+ MVS_QUEUE_SIZE = 30, /* Support Queue depth */
};
/* unchangeable hardware details */
@@ -89,7 +105,7 @@ enum hw_registers {
MVS_GBL_CTL = 0x04, /* global control */
MVS_GBL_INT_STAT = 0x08, /* global irq status */
MVS_GBL_PI = 0x0C, /* ports implemented bitmask */
- MVS_GBL_PORT_TYPE = 0x00, /* port type */
+ MVS_GBL_PORT_TYPE = 0xa0, /* port type */
MVS_CTL = 0x100, /* SAS/SATA port configuration */
MVS_PCS = 0x104, /* SAS/SATA port control/status */
@@ -102,11 +118,12 @@ enum hw_registers {
MVS_TX_LO = 0x124, /* TX (delivery) ring addr */
MVS_TX_HI = 0x128,
- MVS_RX_PROD_IDX = 0x12C, /* RX producer pointer */
- MVS_RX_CONS_IDX = 0x130, /* RX consumer pointer (RO) */
+ MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */
+ MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */
MVS_RX_CFG = 0x134, /* RX configuration */
MVS_RX_LO = 0x138, /* RX (completion) ring addr */
MVS_RX_HI = 0x13C,
+ MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */
MVS_INT_COAL = 0x148, /* Int coalescing config */
MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */
@@ -117,9 +134,12 @@ enum hw_registers {
/* ports 1-3 follow after this */
MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */
MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */
+ MVS_P4_INT_STAT = 0x200, /* Port 4 interrupt status */
+ MVS_P4_INT_MASK = 0x204, /* Port 4 interrupt enable mask */
/* ports 1-3 follow after this */
MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */
+ MVS_P4_SER_CTLSTAT = 0x220, /* port4 serial control/status */
MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */
MVS_CMD_DATA = 0x1BC, /* Command register port (data) */
@@ -127,6 +147,14 @@ enum hw_registers {
/* ports 1-3 follow after this */
MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */
MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */
+ MVS_P4_CFG_ADDR = 0x230, /* Port 4 config address */
+ MVS_P4_CFG_DATA = 0x234, /* Port 4 config data */
+
+ /* ports 1-3 follow after this */
+ MVS_P0_VSR_ADDR = 0x1E0, /* port0 VSR address */
+ MVS_P0_VSR_DATA = 0x1E4, /* port0 VSR data */
+ MVS_P4_VSR_ADDR = 0x250, /* port 4 VSR addr */
+ MVS_P4_VSR_DATA = 0x254, /* port 4 VSR data */
};
enum hw_register_bits {
@@ -140,12 +168,35 @@ enum hw_register_bits {
/* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */
SATA_TARGET = (1U << 16), /* port0 SATA target enable */
- AUTO_DET = (1U << 8), /* port0 SAS/SATA autodetect */
- SAS_MODE = (1U << 0), /* port0 SAS(1), SATA(0) mode */
- /* SAS_MODE value may be
- * dictated (in hw) by values
- * of SATA_TARGET & AUTO_DET
- */
+ MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */
+ MODE_AUTO_DET_PORT6 = (1U << 14),
+ MODE_AUTO_DET_PORT5 = (1U << 13),
+ MODE_AUTO_DET_PORT4 = (1U << 12),
+ MODE_AUTO_DET_PORT3 = (1U << 11),
+ MODE_AUTO_DET_PORT2 = (1U << 10),
+ MODE_AUTO_DET_PORT1 = (1U << 9),
+ MODE_AUTO_DET_PORT0 = (1U << 8),
+ MODE_AUTO_DET_EN = MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
+ MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
+ MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
+ MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
+ MODE_SAS_PORT7_MASK = (1U << 7), /* port0 SAS(1), SATA(0) mode */
+ MODE_SAS_PORT6_MASK = (1U << 6),
+ MODE_SAS_PORT5_MASK = (1U << 5),
+ MODE_SAS_PORT4_MASK = (1U << 4),
+ MODE_SAS_PORT3_MASK = (1U << 3),
+ MODE_SAS_PORT2_MASK = (1U << 2),
+ MODE_SAS_PORT1_MASK = (1U << 1),
+ MODE_SAS_PORT0_MASK = (1U << 0),
+ MODE_SAS_SATA = MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
+ MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
+ MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
+ MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
+
+ /* SAS_MODE value may be
+ * dictated (in hw) by values
+ * of SATA_TARGET & AUTO_DET
+ */
/* MVS_TX_CFG */
TX_EN = (1U << 16), /* Enable TX */
@@ -167,12 +218,14 @@ enum hw_register_bits {
CINT_MEM = (1U << 26), /* int mem parity err */
CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */
CINT_SRS = (1U << 3), /* SRS event */
- CINT_CI_STOP = (1U << 10), /* cmd issue stopped */
+ CINT_CI_STOP = (1U << 1), /* cmd issue stopped */
CINT_DONE = (1U << 0), /* cmd completion */
/* shl for ports 1-3 */
CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */
- CINT_PORT = (1U << 8), /* port0 event */
+ CINT_PORT = (1U << 8), /* port0 event */
+ CINT_PORT_MASK_OFFSET = 8,
+ CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET),
/* TX (delivery) ring bits */
TXQ_CMD_SHIFT = 29,
@@ -239,6 +292,12 @@ enum hw_register_bits {
PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */
PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */
PHY_RST = (1U << 0), /* phy reset */
+ PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
+ PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
+ (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
+ PHY_READY_MASK = (1U << 20),
/* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */
@@ -260,13 +319,37 @@ enum hw_register_bits {
PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */
/* MVS_PCS */
+ PCS_EN_SATA_REG_SHIFT = (16), /* Enable SATA Register Set */
+ PCS_EN_PORT_XMT_SHIFT = (12), /* Enable Port Transmit */
+ PCS_EN_PORT_XMT_SHIFT2 = (8), /* For 6480 */
PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */
PCS_RSP_RX_EN = (1U << 7), /* raw response rx */
PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */
PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */
PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */
- PCS_CMD_RST = (1U << 2), /* reset cmd issue */
+ PCS_CMD_RST = (1U << 1), /* reset cmd issue */
PCS_CMD_EN = (1U << 0), /* enable cmd issue */
+
+ /* Port n Attached Device Info */
+ PORT_DEV_SSP_TRGT = (1U << 19),
+ PORT_DEV_SMP_TRGT = (1U << 18),
+ PORT_DEV_STP_TRGT = (1U << 17),
+ PORT_DEV_SSP_INIT = (1U << 11),
+ PORT_DEV_SMP_INIT = (1U << 10),
+ PORT_DEV_STP_INIT = (1U << 9),
+ PORT_PHY_ID_MASK = (0xFFU << 24),
+ PORT_DEV_TRGT_MASK = (0x7U << 17),
+ PORT_DEV_INIT_MASK = (0x7U << 9),
+ PORT_DEV_TYPE_MASK = (0x7U << 0),
+
+ /* Port n PHY Status */
+ PHY_RDY = (1U << 2),
+ PHY_DW_SYNC = (1U << 1),
+ PHY_OOB_DTCTD = (1U << 0),
+
+ /* VSR */
+ /* PHYMODE 6 (CDB) */
+ PHY_MODE6_DTL_SPEED = (1U << 27),
};
enum mvs_info_flags {
@@ -329,33 +412,60 @@ enum sas_cmd_port_registers {
/* SAS/SATA configuration port registers, aka phy registers */
enum sas_sata_config_port_regs {
- PHYR_IDENTIFY = 0x0, /* info for IDENTIFY frame */
- PHYR_ADDR_LO = 0x4, /* my SAS address (low) */
- PHYR_ADDR_HI = 0x8, /* my SAS address (high) */
- PHYR_ATT_DEV_INFO = 0xC, /* attached device info */
+ PHYR_IDENTIFY = 0x00, /* info for IDENTIFY frame */
+ PHYR_ADDR_LO = 0x04, /* my SAS address (low) */
+ PHYR_ADDR_HI = 0x08, /* my SAS address (high) */
+ PHYR_ATT_DEV_INFO = 0x0C, /* attached device info */
PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */
PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */
PHYR_SATA_CTL = 0x18, /* SATA control */
PHYR_PHY_STAT = 0x1C, /* PHY status */
+ PHYR_SATA_SIG0 = 0x20, /*port SATA signature FIS(Byte 0-3) */
+ PHYR_SATA_SIG1 = 0x24, /*port SATA signature FIS(Byte 4-7) */
+ PHYR_SATA_SIG2 = 0x28, /*port SATA signature FIS(Byte 8-11) */
+ PHYR_SATA_SIG3 = 0x2c, /*port SATA signature FIS(Byte 12-15) */
+ PHYR_R_ERR_COUNT = 0x30, /* port R_ERR count register */
+ PHYR_CRC_ERR_COUNT = 0x34, /* port CRC error count register */
PHYR_WIDE_PORT = 0x38, /* wide port participating */
PHYR_CURRENT0 = 0x80, /* current connection info 0 */
PHYR_CURRENT1 = 0x84, /* current connection info 1 */
PHYR_CURRENT2 = 0x88, /* current connection info 2 */
};
+/* SAS/SATA Vendor Specific Port Registers */
+enum sas_sata_vsp_regs {
+ VSR_PHY_STAT = 0x00, /* Phy Status */
+ VSR_PHY_MODE1 = 0x01, /* phy tx */
+ VSR_PHY_MODE2 = 0x02, /* tx scc */
+ VSR_PHY_MODE3 = 0x03, /* pll */
+ VSR_PHY_MODE4 = 0x04, /* VCO */
+ VSR_PHY_MODE5 = 0x05, /* Rx */
+ VSR_PHY_MODE6 = 0x06, /* CDR */
+ VSR_PHY_MODE7 = 0x07, /* Impedance */
+ VSR_PHY_MODE8 = 0x08, /* Voltage */
+ VSR_PHY_MODE9 = 0x09, /* Test */
+ VSR_PHY_MODE10 = 0x0A, /* Power */
+ VSR_PHY_MODE11 = 0x0B, /* Phy Mode */
+ VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */
+ VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */
+};
+
enum pci_cfg_registers {
- PCR_PHY_CTL = 0x40,
- PCR_PHY_CTL2 = 0x90,
+ PCR_PHY_CTL = 0x40,
+ PCR_PHY_CTL2 = 0x90,
+ PCR_DEV_CTRL = 0xE8,
};
enum pci_cfg_register_bits {
- PCTL_PWR_ON = (0xFU << 24),
- PCTL_OFF = (0xFU << 12),
+ PCTL_PWR_ON = (0xFU << 24),
+ PCTL_OFF = (0xFU << 12),
+ PRD_REQ_SIZE = (0x4000),
+ PRD_REQ_MASK = (0x00007000),
};
enum nvram_layout_offsets {
- NVR_SIG = 0x00, /* 0xAA, 0x55 */
- NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */
+ NVR_SIG = 0x00, /* 0xAA, 0x55 */
+ NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */
};
enum chip_flavors {
@@ -364,10 +474,38 @@ enum chip_flavors {
chip_6480,
};
+enum port_type {
+ PORT_TYPE_SAS = (1L << 1),
+ PORT_TYPE_SATA = (1L << 0),
+};
+
+/* Command Table Format */
+enum ct_format {
+ /* SSP */
+ SSP_F_H = 0x00,
+ SSP_F_IU = 0x18,
+ SSP_F_MAX = 0x4D,
+ /* STP */
+ STP_CMD_FIS = 0x00,
+ STP_ATAPI_CMD = 0x40,
+ STP_F_MAX = 0x10,
+ /* SMP */
+ SMP_F_T = 0x00,
+ SMP_F_DEP = 0x01,
+ SMP_F_MAX = 0x101,
+};
+
+enum status_buffer {
+ SB_EIR_OFF = 0x00, /* Error Information Record */
+ SB_RFB_OFF = 0x08, /* Response Frame Buffer */
+ SB_RFB_MAX = 0x400, /* RFB size*/
+};
+
+
struct mvs_chip_info {
- unsigned int n_phy;
- unsigned int srs_sz;
- unsigned int slot_width;
+ u32 n_phy;
+ u32 srs_sz;
+ u32 slot_width;
};
struct mvs_err_info {
@@ -395,7 +533,7 @@ struct mvs_cmd_hdr {
struct mvs_slot_info {
struct sas_task *task;
- unsigned int n_elem;
+ u32 n_elem;
/* DMA buffer for storing cmd tbl, open addr frame, status buffer,
* and PRD table
@@ -408,13 +546,24 @@ struct mvs_slot_info {
struct mvs_port {
struct asd_sas_port sas_port;
+ u8 taskfileset;
};
struct mvs_phy {
struct mvs_port *port;
struct asd_sas_phy sas_phy;
+ struct sas_identify identify;
+ __le32 dev_info;
+ __le64 dev_sas_addr;
+ __le32 att_dev_info;
+ __le64 att_dev_sas_addr;
+ u32 type;
+ __le32 phy_status;
+ __le32 irq_status;
+ u8 wide_port_phymap;
+ u32 frame_rcvd_size;
+ u8 frame_rcvd[32];
- u8 frame_rcvd[24 + 1024];
};
struct mvs_info {
@@ -437,27 +586,55 @@ struct mvs_info {
dma_addr_t rx_dma;
u32 rx_cons; /* RX consumer idx */
- __le32 *rx_fis; /* RX'd FIS area */
+ void *rx_fis; /* RX'd FIS area */
dma_addr_t rx_fis_dma;
- struct mvs_cmd_hdr *slot; /* DMA command header slots */
+ struct mvs_cmd_hdr *slot; /* DMA command header slots */
dma_addr_t slot_dma;
const struct mvs_chip_info *chip;
- /* further per-slot information */
+ unsigned long tags[MVS_SLOTS];
struct mvs_slot_info slot_info[MVS_SLOTS];
- unsigned long tags[(MVS_SLOTS / sizeof(unsigned long)) + 1];
-
+ /* further per-slot information */
struct mvs_phy phy[MVS_MAX_PHYS];
struct mvs_port port[MVS_MAX_PHYS];
+
+ u32 can_queue; /* per adapter */
+ u32 tag_out; /*Get*/
+ u32 tag_in; /*Give*/
};
+struct mvs_queue_task {
+ struct list_head list;
+
+ void *uldd_task;
+};
+
+static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port);
+static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val);
+static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port);
+static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
+ u32 port, u32 val);
+static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port);
+static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val);
+static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr);
+static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port);
+static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val);
+static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr);
+static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port);
+static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val);
+static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port);
+static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val);
+
+static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
+static void mvs_scan_start(struct Scsi_Host *);
+
static struct scsi_transport_template *mvs_stt;
static const struct mvs_chip_info mvs_chips[] = {
- [chip_6320] = { 2, 16, 9 },
- [chip_6440] = { 4, 16, 9 },
+ [chip_6320] = { 2, 16, 9 },
+ [chip_6440] = { 4, 16, 9 },
[chip_6480] = { 8, 32, 10 },
};
@@ -468,6 +645,8 @@ static struct scsi_host_template mvs_sht = {
.target_alloc = sas_target_alloc,
.slave_configure = sas_slave_configure,
.slave_destroy = sas_slave_destroy,
+ .scan_finished = mvs_scan_finished,
+ .scan_start = mvs_scan_start,
.change_queue_depth = sas_change_queue_depth,
.change_queue_type = sas_change_queue_type,
.bios_param = sas_bios_param,
@@ -477,14 +656,159 @@ static struct scsi_host_template mvs_sht = {
.sg_tablesize = SG_ALL,
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING,
- .eh_device_reset_handler= sas_eh_device_reset_handler,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
};
-static void mvs_int_rx(struct mvs_info *mvi, bool self_clear);
+static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
+{
+ u32 i;
+ u32 run;
+ u32 offset;
+
+ offset = 0;
+ while (size) {
+ printk("%08X : ", baseaddr + offset);
+ if (size >= 16)
+ run = 16;
+ else
+ run = size;
+ size -= run;
+ for (i = 0; i < 16; i++) {
+ if (i < run)
+ printk("%02X ", (u32)data[i]);
+ else
+ printk(" ");
+ }
+ printk(": ");
+ for (i = 0; i < run; i++)
+ printk("%c", isalnum(data[i]) ? data[i] : '.');
+ printk("\n");
+ data = &data[16];
+ offset += run;
+ }
+ printk("\n");
+}
+
+static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
+ enum sas_protocol proto)
+{
+ u32 offset;
+ u32 len_ct;
+ struct pci_dev *pdev = mvi->pdev;
+
+ if (sas_protocol_ata(proto))
+ len_ct = MVS_ATA_CMD_SZ;
+ else
+ len_ct = MVS_SSP_CMD_SZ;
+
+ offset =
+ len_ct + MVS_OAF_SZ +
+ sizeof(struct mvs_prd) * mvi->slot_info[tag].n_elem;
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer :\n");
+ mvs_hexdump(32, (u8 *) mvi->slot_info[tag].response,
+ (u32) mvi->slot_info[tag].buf_dma + offset);
+}
+
+static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
+ enum sas_protocol proto)
+{
+#if _MV_DUMP
+ u32 sz, w_ptr, r_ptr;
+ u64 addr;
+ u32 len_ct;
+ void __iomem *regs = mvi->regs;
+ struct pci_dev *pdev = mvi->pdev;
+
+ if (sas_protocol_ata(proto))
+ len_ct = MVS_ATA_CMD_SZ;
+ else
+ len_ct = MVS_SSP_CMD_SZ;
+
+ /*Delivery Queue */
+ sz = mr32(TX_CFG) & TX_RING_SZ_MASK;
+ w_ptr = mr32(TX_PROD_IDX) & TX_RING_SZ_MASK;
+ r_ptr = mr32(TX_CONS_IDX) & TX_RING_SZ_MASK;
+ addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Delivery Queue Size=%04d , WRT_PTR=%04X , RD_PTR=%04X\n",
+ sz, w_ptr, r_ptr);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Delivery Queue Base Address=0x%llX (PA)"
+ "(tx_dma=0x%llX), Entry=%04d\n",
+ addr, mvi->tx_dma, w_ptr);
+ mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
+ (u32) mvi->tx_dma + sizeof(u32) * w_ptr);
+ /*Command List */
+ addr = mr32(CMD_LIST_HI) << 16 << 16 | mr32(CMD_LIST_LO);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Command List Base Address=0x%llX (PA)"
+ "(slot_dma=0x%llX), Header=%03d\n",
+ addr, mvi->slot_dma, tag);
+ dev_printk(KERN_DEBUG, &pdev->dev, "Command Header[%03d]:\n", tag);
+ /*mvs_cmd_hdr */
+ mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
+ (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
+ /*1.command table area */
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Command Table :\n");
+ mvs_hexdump(len_ct, (u8 *) mvi->slot_info[tag].buf,
+ (u32) mvi->slot_info[tag].buf_dma);
+ /*2.open address frame area */
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Open Address Frame :\n");
+ mvs_hexdump(MVS_OAF_SZ, (u8 *) mvi->slot_info[tag].buf + len_ct,
+ (u32) mvi->slot_info[tag].buf_dma + len_ct);
+ /*3.status buffer */
+ mvs_hba_sb_dump(mvi, tag, proto);
+ /*4.PRD table */
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->PRD table :\n");
+ mvs_hexdump(sizeof(struct mvs_prd) * mvi->slot_info[tag].n_elem,
+ (u8 *) mvi->slot_info[tag].buf + len_ct + MVS_OAF_SZ,
+ (u32) mvi->slot_info[tag].buf_dma + len_ct + MVS_OAF_SZ);
+#endif
+}
+
+static void mvs_hba_cq_dump(struct mvs_info *mvi)
+{
+#if _MV_DUMP
+ u64 addr;
+ void __iomem *regs = mvi->regs;
+ struct pci_dev *pdev = mvi->pdev;
+ u32 entry = mvi->rx_cons + 1;
+ u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
+
+ /*Completion Queue */
+ addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
+ dev_printk(KERN_DEBUG, &pdev->dev, "Completion Task = 0x%08X\n",
+ (u32) mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Completion List Base Address=0x%llX (PA), "
+ "CQ_Entry=%04d, CQ_WP=0x%08X\n",
+ addr, entry - 1, mvi->rx[0]);
+ mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
+ mvi->rx_dma + sizeof(u32) * entry);
+#endif
+}
+
+static void mvs_hba_interrupt_enable(struct mvs_info *mvi, int enable)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mvi->lock, flags);
+ tmp = mr32(GBL_CTL);
+
+ if (enable)
+ mw32(GBL_CTL, tmp | INT_EN);
+ else
+ mw32(GBL_CTL, tmp & ~INT_EN);
+ spin_unlock_irqrestore(&mvi->lock, flags);
+}
+
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
/* move to PCI layer or libata core? */
static int pci_go_64(struct pci_dev *pdev)
@@ -519,39 +843,38 @@ static int pci_go_64(struct pci_dev *pdev)
return rc;
}
-static void mvs_tag_clear(struct mvs_info *mvi, unsigned int tag)
+static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
{
- mvi->tags[tag / sizeof(unsigned long)] &=
- ~(1UL << (tag % sizeof(unsigned long)));
+ mvi->tag_in = (mvi->tag_in + 1) & (MVS_SLOTS - 1);
+ mvi->tags[mvi->tag_in] = tag;
}
-static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
+static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
{
- mvi->tags[tag / sizeof(unsigned long)] |=
- (1UL << (tag % sizeof(unsigned long)));
+ mvi->tag_out = (mvi->tag_out - 1) & (MVS_SLOTS - 1);
}
-static bool mvs_tag_test(struct mvs_info *mvi, unsigned int tag)
+static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
{
- return mvi->tags[tag / sizeof(unsigned long)] &
- (1UL << (tag % sizeof(unsigned long)));
+ if (mvi->tag_out != mvi->tag_in) {
+ *tag_out = mvi->tags[mvi->tag_out];
+ mvi->tag_out = (mvi->tag_out + 1) & (MVS_SLOTS - 1);
+ return 0;
+ }
+ return -EBUSY;
}
-static int mvs_tag_alloc(struct mvs_info *mvi, unsigned int *tag_out)
+static void mvs_tag_init(struct mvs_info *mvi)
{
- unsigned int i;
-
- for (i = 0; i < MVS_SLOTS; i++)
- if (!mvs_tag_test(mvi, i)) {
- mvs_tag_set(mvi, i);
- *tag_out = i;
- return 0;
- }
-
- return -EBUSY;
+ int i;
+ for (i = 0; i < MVS_SLOTS; ++i)
+ mvi->tags[i] = i;
+ mvi->tag_out = 0;
+ mvi->tag_in = MVS_SLOTS - 1;
}
-static int mvs_eep_read(void __iomem *regs, unsigned int addr, u32 *data)
+#ifndef MVS_DISABLE_NVRAM
+static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data)
{
int timeout = 1000;
@@ -573,10 +896,10 @@ static int mvs_eep_read(void __iomem *regs, unsigned int addr, u32 *data)
return -EBUSY;
}
-static int mvs_eep_read_buf(void __iomem *regs, unsigned int addr,
- void *buf, unsigned int buflen)
+static int mvs_eep_read_buf(void __iomem *regs, u32 addr,
+ void *buf, u32 buflen)
{
- unsigned int addr_end, tmp_addr, i, j;
+ u32 addr_end, tmp_addr, i, j;
u32 tmp = 0;
int rc;
u8 *tmp8, *buf8 = buf;
@@ -592,7 +915,7 @@ static int mvs_eep_read_buf(void __iomem *regs, unsigned int addr,
if (rc)
return rc;
- tmp8 = (u8 *) &tmp;
+ tmp8 = (u8 *)&tmp;
for (i = j; i < 4; i++)
*buf8++ = tmp8[i];
@@ -613,7 +936,7 @@ static int mvs_eep_read_buf(void __iomem *regs, unsigned int addr,
if (rc)
return rc;
- tmp8 = (u8 *) &tmp;
+ tmp8 = (u8 *)&tmp;
j = addr_end - tmp_addr;
for (i = 0; i < j; i++)
*buf8++ = tmp8[i];
@@ -623,13 +946,15 @@ static int mvs_eep_read_buf(void __iomem *regs, unsigned int addr,
return 0;
}
+#endif
-static int mvs_nvram_read(struct mvs_info *mvi, unsigned int addr,
- void *buf, unsigned int buflen)
+static int mvs_nvram_read(struct mvs_info *mvi, u32 addr,
+ void *buf, u32 buflen)
{
+#ifndef MVS_DISABLE_NVRAM
void __iomem *regs = mvi->regs;
int rc, i;
- unsigned int sum;
+ u32 sum;
u8 hdr[2], *tmp;
const char *msg;
@@ -644,16 +969,17 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned int addr,
goto err_out;
}
- if (hdr[0] != 0x5A) { /* entry id */
+ if (hdr[0] != 0x5A) {
+ /* entry id */
msg = "invalid nvram entry id";
rc = -ENOENT;
goto err_out;
}
tmp = buf;
- sum = ((unsigned int)hdr[0]) + ((unsigned int)hdr[1]);
+ sum = ((u32)hdr[0]) + ((u32)hdr[1]);
for (i = 0; i < buflen; i++)
- sum += ((unsigned int)tmp[i]);
+ sum += ((u32)tmp[i]);
if (sum) {
msg = "nvram checksum failure";
@@ -666,11 +992,55 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned int addr,
err_out:
dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
return rc;
+#else
+ /* FIXME , For SAS target mode */
+ memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
+ return 0;
+#endif
+}
+
+static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ /* give the phy enabling interrupt event time to come in (1s
+ * is empirically about all it takes) */
+ if (time < HZ)
+ return 0;
+ /* Wait for discovery to finish */
+ scsi_flush_work(shost);
+ return 1;
+}
+
+static void mvs_scan_start(struct Scsi_Host *shost)
+{
+ int i;
+ struct sas_identify_frame *id;
+ struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
+
+ for (i = 0; i < mvi->chip->n_phy; ++i) {
+ struct mvs_phy *phy = &mvi->phy[i];
+ id = (struct sas_identify_frame *)phy->frame_rcvd;
+ if (phy->type & PORT_TYPE_SAS) {
+ id->dev_type = phy->identify.device_type;
+ id->initiator_bits = SAS_PROTOCOL_ALL;
+ id->target_bits = phy->identify.target_port_protocols;
+ } else if (phy->type & PORT_TYPE_SATA) {
+ }
+ mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
+ mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
+ PORTE_BYTES_DMAED);
+ }
+
}
static void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events)
{
- /* FIXME */
+ struct pci_dev *pdev = mvi->pdev;
+ /*
+ * events is port event now ,
+ * we need check the interrupt status which belongs to per port.
+ */
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Port0 = %d", mvs_read_port_irq_stat(mvi, 0));
}
static void mvs_int_sata(struct mvs_info *mvi)
@@ -679,11 +1049,12 @@ static void mvs_int_sata(struct mvs_info *mvi)
}
static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
- struct mvs_slot_info *slot, unsigned int slot_idx)
+ struct mvs_slot_info *slot, u32 slot_idx)
{
- if (slot->n_elem)
- pci_unmap_sg(mvi->pdev, task->scatter,
- slot->n_elem, task->data_dir);
+ if (!sas_protocol_ata(task->task_proto))
+ if (slot->n_elem)
+ pci_unmap_sg(mvi->pdev, task->scatter,
+ slot->n_elem, task->data_dir);
switch (task->task_proto) {
case SAS_PROTOCOL_SMP:
@@ -705,14 +1076,15 @@ static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
}
static void mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
- unsigned int slot_idx)
+ u32 slot_idx)
{
/* FIXME */
+ mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
}
-static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
+static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
{
- unsigned int slot_idx = rx_desc & RXQ_SLOT_MASK;
+ u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
struct sas_task *task = slot->task;
struct task_status_struct *tstat = &task->task_status;
@@ -722,19 +1094,19 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
if (!aborted) {
task->task_state_flags &=
- ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
task->task_state_flags |= SAS_TASK_STATE_DONE;
}
spin_unlock(&task->task_state_lock);
if (aborted)
- return;
+ return -1;
memset(tstat, 0, sizeof(*tstat));
tstat->resp = SAS_TASK_COMPLETE;
/* error info record present */
- if (rx_desc & RXQ_ERR) {
+ if ((rx_desc & RXQ_ERR) && (*(u64 *) slot->response)) {
tstat->stat = SAM_CHECK_COND;
mvs_slot_err(mvi, task, slot_idx);
goto out;
@@ -743,13 +1115,14 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
switch (task->task_proto) {
case SAS_PROTOCOL_SSP:
/* hw says status == 0, datapres == 0 */
- if (rx_desc & RXQ_GOOD)
+ if (rx_desc & RXQ_GOOD) {
tstat->stat = SAM_GOOD;
-
+ tstat->resp = SAS_TASK_COMPLETE;
+ }
/* response frame present */
else if (rx_desc & RXQ_RSP) {
struct ssp_response_iu *iu =
- slot->response + sizeof(struct mvs_err_info);
+ slot->response + sizeof(struct mvs_err_info);
sas_ssp_task_response(&mvi->pdev->dev, task, iu);
}
@@ -763,15 +1136,26 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
break;
case SAS_PROTOCOL_SATA:
- case SAS_PROTOCOL_STP:
- if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) == RXQ_DONE)
- tstat->stat = SAM_GOOD;
- else
- tstat->stat = SAM_CHECK_COND;
- /* FIXME: read taskfile data from SATA register set
- * associated with SATA target
- */
- break;
+ case SAS_PROTOCOL_STP: {
+ struct ata_task_resp *resp =
+ (struct ata_task_resp *)tstat->buf;
+ struct domain_device *dev = task->dev;
+ struct mvs_port *port =
+ (struct mvs_port *)dev->port->lldd_port;
+
+ if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) ==
+ RXQ_DONE)
+ tstat->stat = SAM_GOOD;
+ else
+ tstat->stat = SAM_CHECK_COND;
+
+ resp->frame_len = sizeof(struct dev_to_host_fis);
+ memcpy(&resp->ending_fis[0],
+ SATA_RECEIVED_D2H_FIS(port->taskfileset),
+ sizeof(struct dev_to_host_fis));
+ /*mvs_hexdump(16,resp->ending_fis,0);*/
+ break;
+ }
default:
tstat->stat = SAM_CHECK_COND;
@@ -781,6 +1165,7 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
out:
mvs_slot_free(mvi, task, slot, slot_idx);
task->task_done(task);
+ return tstat->stat;
}
static void mvs_int_full(struct mvs_info *mvi)
@@ -791,6 +1176,8 @@ static void mvs_int_full(struct mvs_info *mvi)
stat = mr32(INT_STAT);
+ mvs_int_rx(mvi, false);
+
for (i = 0; i < MVS_MAX_PORTS; i++) {
tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
if (tmp)
@@ -800,48 +1187,60 @@ static void mvs_int_full(struct mvs_info *mvi)
if (stat & CINT_SRS)
mvs_int_sata(mvi);
- if (stat & (CINT_CI_STOP | CINT_DONE))
- mvs_int_rx(mvi, false);
-
mw32(INT_STAT, stat);
}
-static void mvs_int_rx(struct mvs_info *mvi, bool self_clear)
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
{
+ void __iomem *regs = mvi->regs;
u32 rx_prod_idx, rx_desc;
bool attn = false;
+ struct pci_dev *pdev = mvi->pdev;
/* the first dword in the RX ring is special: it contains
* a mirror of the hardware's RX producer index, so that
* we don't have to stall the CPU reading that register.
* The actual RX ring is offset by one dword, due to this.
*/
- rx_prod_idx = le32_to_cpu(mvi->rx[0]) & 0xfff;
+ rx_prod_idx = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
if (rx_prod_idx == 0xfff) { /* h/w hasn't touched RX ring yet */
mvi->rx_cons = 0xfff;
- return;
+ return 0;
}
+
+ /* The CMPL_Q may come late, read from register and try again
+ * note: if coalescing is enabled,
+ * it will need to read from register every time for sure
+ */
+ if (mvi->rx_cons == rx_prod_idx)
+ return 0;
+
if (mvi->rx_cons == 0xfff)
mvi->rx_cons = MVS_RX_RING_SZ - 1;
while (mvi->rx_cons != rx_prod_idx) {
+
/* increment our internal RX consumer pointer */
mvi->rx_cons = (mvi->rx_cons + 1) & (MVS_RX_RING_SZ - 1);
- /* Read RX descriptor at offset+1, due to above */
rx_desc = le32_to_cpu(mvi->rx[mvi->rx_cons + 1]);
- if (rx_desc & RXQ_DONE)
- /* we had a completion, error or no */
- mvs_slot_complete(mvi, rx_desc);
+ mvs_hba_cq_dump(mvi);
- if (rx_desc & RXQ_ATTN)
+ if (unlikely(rx_desc & RXQ_DONE))
+ mvs_slot_complete(mvi, rx_desc);
+ else if (rx_desc & RXQ_ATTN) {
attn = true;
+ dev_printk(KERN_DEBUG, &pdev->dev, "ATTN\n");
+ } else if (rx_desc & RXQ_ERR) {
+ dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR\n");
+ }
}
if (attn && self_clear)
mvs_int_full(mvi);
+ return 0;
}
static irqreturn_t mvs_interrupt(int irq, void *opaque)
@@ -851,6 +1250,10 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
u32 stat;
stat = mr32(GBL_INT_STAT);
+
+ /* clear CMD_CMPLT ASAP */
+ mw32_f(INT_STAT, CINT_DONE);
+
if (stat == 0 || stat == 0xffffffff)
return IRQ_NONE;
@@ -877,18 +1280,19 @@ static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
}
struct mvs_task_exec_info {
- struct sas_task *task;
- struct mvs_cmd_hdr *hdr;
- unsigned int tag;
- int n_elem;
+ struct sas_task *task;
+ struct mvs_cmd_hdr *hdr;
+ u32 tag;
+ int n_elem;
};
-static int mvs_task_prep_smp(struct mvs_info *mvi, struct mvs_task_exec_info *tei)
+static int mvs_task_prep_smp(struct mvs_info *mvi,
+ struct mvs_task_exec_info *tei)
{
int elem, rc;
struct mvs_cmd_hdr *hdr = tei->hdr;
struct scatterlist *sg_req, *sg_resp;
- unsigned int req_len, resp_len, tag = tei->tag;
+ u32 req_len, resp_len, tag = tei->tag;
/*
* DMA-map SMP request, response buffers
@@ -918,8 +1322,8 @@ static int mvs_task_prep_smp(struct mvs_info *mvi, struct mvs_task_exec_info *te
* Fill in TX ring and command slot header
*/
- mvi->tx[tag] = cpu_to_le32(
- (TXQ_CMD_SMP << TXQ_CMD_SHIFT) | TXQ_MODE_I | tag);
+ mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
+ TXQ_MODE_I | tag);
hdr->flags = 0;
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
@@ -941,6 +1345,65 @@ err_out:
return rc;
}
+static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp, offs;
+
+ if (port->taskfileset == MVS_ID_NOT_MAPPED)
+ return;
+
+ offs = 1U << ((port->taskfileset & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+ if (port->taskfileset < 16) {
+ tmp = mr32(PCS);
+ mw32(PCS, tmp | ~offs);
+ } else {
+ tmp = mr32(CTL);
+ mw32(CTL, tmp | ~offs);
+ }
+
+ port->taskfileset = MVS_ID_NOT_MAPPED;
+}
+
+static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+{
+ int i;
+ u32 tmp, offs;
+ void __iomem *regs = mvi->regs;
+
+ if (port->taskfileset != MVS_ID_NOT_MAPPED)
+ return 0;
+
+ tmp = mr32(PCS);
+
+ for (i = 0; i < mvi->chip->srs_sz; i++) {
+ if (i == 16)
+ tmp = mr32(CTL);
+ offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+ if (!(tmp & offs)) {
+ port->taskfileset = i;
+
+ if (i < 16)
+ mw32(PCS, tmp | offs);
+ else
+ mw32(CTL, tmp | offs);
+ return 0;
+ }
+ }
+ return MVS_ID_NOT_MAPPED;
+}
+
+static u32 mvs_get_ncq_tag(struct sas_task *task)
+{
+ u32 tag = 0;
+ struct ata_queued_cmd *qc = task->uldd_task;
+
+ if (qc)
+ tag = qc->tag;
+
+ return tag;
+}
+
static int mvs_task_prep_ata(struct mvs_info *mvi,
struct mvs_task_exec_info *tei)
{
@@ -948,29 +1411,46 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
struct domain_device *dev = task->dev;
struct mvs_cmd_hdr *hdr = tei->hdr;
struct asd_sas_port *sas_port = dev->port;
- unsigned int tag = tei->tag;
- struct mvs_slot_info *slot = &mvi->slot_info[tag];
- u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+ struct mvs_slot_info *slot;
struct scatterlist *sg;
struct mvs_prd *buf_prd;
+ struct mvs_port *port = (struct mvs_port *)sas_port->lldd_port;
+ u32 tag = tei->tag;
+ u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
void *buf_tmp;
u8 *buf_cmd, *buf_oaf;
dma_addr_t buf_tmp_dma;
- unsigned int i, req_len, resp_len;
+ u32 i, req_len, resp_len;
+ const u32 max_resp_len = SB_RFB_MAX;
+
+ if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED)
+ return -EBUSY;
+
+ slot = &mvi->slot_info[tag];
- /* FIXME: fill in SATA register set */
- mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag |
- (TXQ_CMD_STP << TXQ_CMD_SHIFT) |
- (sas_port->phy_mask << TXQ_PHY_SHIFT));
+ mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+ (TXQ_CMD_STP << TXQ_CMD_SHIFT) |
+ (sas_port->phy_mask << TXQ_PHY_SHIFT) |
+ (port->taskfileset << TXQ_SRS_SHIFT));
if (task->ata_task.use_ncq)
flags |= MCH_FPDMA;
- if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
- flags |= MCH_ATAPI;
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
+ if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
+ flags |= MCH_ATAPI;
+ }
+
/* FIXME: fill in port multiplier number */
hdr->flags = cpu_to_le32(flags);
- hdr->tags = cpu_to_le32(tag);
+
+ /* FIXME: the low order order 5 bits for the TAG if enable NCQ */
+ if (task->ata_task.use_ncq) {
+ hdr->tags = cpu_to_le32(mvs_get_ncq_tag(task));
+ /*Fill in task file */
+ task->ata_task.fis.sector_count = hdr->tags << 3;
+ } else
+ hdr->tags = cpu_to_le32(tag);
hdr->data_len = cpu_to_le32(task->total_xfer_len);
/*
@@ -978,9 +1458,8 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
*/
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
- /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ***************/
- buf_cmd =
- buf_tmp = slot->buf;
+ /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
+ buf_cmd = buf_tmp = slot->buf;
buf_tmp_dma = slot->buf_dma;
hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
@@ -988,7 +1467,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
buf_tmp += MVS_ATA_CMD_SZ;
buf_tmp_dma += MVS_ATA_CMD_SZ;
- /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
+ /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
/* used for STP. unused for SATA? */
buf_oaf = buf_tmp;
hdr->open_frame = cpu_to_le64(buf_tmp_dma);
@@ -996,32 +1475,38 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
buf_tmp += MVS_OAF_SZ;
buf_tmp_dma += MVS_OAF_SZ;
- /* region 3: PRD table ***********************************************/
+ /* region 3: PRD table ********************************************** */
buf_prd = buf_tmp;
- hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ if (tei->n_elem)
+ hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ else
+ hdr->prd_tbl = 0;
i = sizeof(struct mvs_prd) * tei->n_elem;
buf_tmp += i;
buf_tmp_dma += i;
- /* region 4: status buffer (larger the PRD, smaller this buf) ********/
+ /* region 4: status buffer (larger the PRD, smaller this buf) ******* */
/* FIXME: probably unused, for SATA. kept here just in case
* we get a STP/SATA error information record
*/
slot->response = buf_tmp;
hdr->status_buf = cpu_to_le64(buf_tmp_dma);
- req_len = sizeof(struct ssp_frame_hdr) + 28;
+ req_len = sizeof(struct host_to_dev_fis);
resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
- sizeof(struct mvs_err_info) - i;
+ sizeof(struct mvs_err_info) - i;
/* request, response lengths */
+ resp_len = min(resp_len, max_resp_len);
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
+ task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
/* fill in command FIS and ATAPI CDB */
- memcpy(buf_cmd, &task->ata_task.fis,
- sizeof(struct host_to_dev_fis));
- memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
+ memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
+ memcpy(buf_cmd + STP_ATAPI_CMD,
+ task->ata_task.atapi_packet, 16);
/* fill in PRD (scatter/gather) table, if any */
sg = task->scatter;
@@ -1044,28 +1529,28 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
struct mvs_cmd_hdr *hdr = tei->hdr;
struct mvs_slot_info *slot;
struct scatterlist *sg;
- unsigned int resp_len, req_len, i, tag = tei->tag;
struct mvs_prd *buf_prd;
struct ssp_frame_hdr *ssp_hdr;
void *buf_tmp;
u8 *buf_cmd, *buf_oaf, fburst = 0;
dma_addr_t buf_tmp_dma;
u32 flags;
+ u32 resp_len, req_len, i, tag = tei->tag;
+ const u32 max_resp_len = SB_RFB_MAX;
slot = &mvi->slot_info[tag];
- mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag |
- (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
- (sas_port->phy_mask << TXQ_PHY_SHIFT));
-
+ mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+ (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
+ (sas_port->phy_mask << TXQ_PHY_SHIFT));
flags = MCH_RETRY;
if (task->ssp_task.enable_first_burst) {
flags |= MCH_FBURST;
fburst = (1 << 7);
}
hdr->flags = cpu_to_le32(flags |
- (tei->n_elem << MCH_PRD_LEN_SHIFT) |
- (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
+ (tei->n_elem << MCH_PRD_LEN_SHIFT) |
+ (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
hdr->tags = cpu_to_le32(tag);
hdr->data_len = cpu_to_le32(task->total_xfer_len);
@@ -1075,9 +1560,8 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
*/
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
- /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***************/
- buf_cmd =
- buf_tmp = slot->buf;
+ /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
+ buf_cmd = buf_tmp = slot->buf;
buf_tmp_dma = slot->buf_dma;
hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
@@ -1085,28 +1569,33 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
buf_tmp += MVS_SSP_CMD_SZ;
buf_tmp_dma += MVS_SSP_CMD_SZ;
- /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
+ /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
buf_oaf = buf_tmp;
hdr->open_frame = cpu_to_le64(buf_tmp_dma);
buf_tmp += MVS_OAF_SZ;
buf_tmp_dma += MVS_OAF_SZ;
- /* region 3: PRD table ***********************************************/
+ /* region 3: PRD table ********************************************** */
buf_prd = buf_tmp;
- hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ if (tei->n_elem)
+ hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ else
+ hdr->prd_tbl = 0;
i = sizeof(struct mvs_prd) * tei->n_elem;
buf_tmp += i;
buf_tmp_dma += i;
- /* region 4: status buffer (larger the PRD, smaller this buf) ********/
+ /* region 4: status buffer (larger the PRD, smaller this buf) ******* */
slot->response = buf_tmp;
hdr->status_buf = cpu_to_le64(buf_tmp_dma);
- req_len = sizeof(struct ssp_frame_hdr) + 28;
resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
- sizeof(struct mvs_err_info) - i;
+ sizeof(struct mvs_err_info) - i;
+ resp_len = min(resp_len, max_resp_len);
+
+ req_len = sizeof(struct ssp_frame_hdr) + 28;
/* request, response lengths */
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
@@ -1118,8 +1607,8 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
buf_oaf[3] = tag;
memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
- /* fill in SSP frame header */
- ssp_hdr = (struct ssp_frame_hdr *) buf_cmd;
+ /* fill in SSP frame header (Command Table.SSP frame header) */
+ ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
ssp_hdr->frame_type = SSP_COMMAND;
memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr,
HASHED_SAS_ADDR_SIZE);
@@ -1130,11 +1619,9 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
/* fill in command frame IU */
buf_cmd += sizeof(*ssp_hdr);
memcpy(buf_cmd, &task->ssp_task.LUN, 8);
- buf_cmd[9] = fburst |
- task->ssp_task.task_attr |
- (task->ssp_task.task_prio << 3);
+ buf_cmd[9] = fburst | task->ssp_task.task_attr |
+ (task->ssp_task.task_prio << 3);
memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
-
/* fill in PRD (scatter/gather) table, if any */
sg = task->scatter;
for (i = 0; i < tei->n_elem; i++) {
@@ -1151,76 +1638,138 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
{
struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
- unsigned int tag = 0xdeadbeef, rc, n_elem = 0;
+ struct pci_dev *pdev = mvi->pdev;
+ struct mvs_task_exec_info tei;
+ struct sas_task *t = task;
void __iomem *regs = mvi->regs;
+ u32 tag = 0xdeadbeef, rc, n_elem = 0;
unsigned long flags;
- struct mvs_task_exec_info tei;
+ u32 n = num, pass = 0;
- /* FIXME: STP/SATA support not complete yet */
- if (task->task_proto == SAS_PROTOCOL_SATA || task->task_proto == SAS_PROTOCOL_STP)
- return -SAS_DEV_NO_RESPONSE;
+ spin_lock_irqsave(&mvi->lock, flags);
- if (task->num_scatter) {
- n_elem = pci_map_sg(mvi->pdev, task->scatter,
- task->num_scatter, task->data_dir);
- if (!n_elem)
- return -ENOMEM;
- }
+ do {
+ if (!sas_protocol_ata(t->task_proto)) {
+ if (t->num_scatter) {
+ n_elem = pci_map_sg(mvi->pdev, t->scatter,
+ t->num_scatter,
+ t->data_dir);
+ if (!n_elem) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ }
+ } else {
+ n_elem = t->num_scatter;
+ }
- spin_lock_irqsave(&mvi->lock, flags);
+ rc = mvs_tag_alloc(mvi, &tag);
+ if (rc)
+ goto err_out;
- rc = mvs_tag_alloc(mvi, &tag);
- if (rc)
- goto err_out;
+ mvi->slot_info[tag].task = t;
+ mvi->slot_info[tag].n_elem = n_elem;
+ tei.task = t;
+ tei.hdr = &mvi->slot[tag];
+ tei.tag = tag;
+ tei.n_elem = n_elem;
- mvi->slot_info[tag].task = task;
- mvi->slot_info[tag].n_elem = n_elem;
- tei.task = task;
- tei.hdr = &mvi->slot[tag];
- tei.tag = tag;
- tei.n_elem = n_elem;
+ switch (t->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ rc = mvs_task_prep_smp(mvi, &tei);
+ break;
+ case SAS_PROTOCOL_SSP:
+ rc = mvs_task_prep_ssp(mvi, &tei);
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ rc = mvs_task_prep_ata(mvi, &tei);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
- switch (task->task_proto) {
- case SAS_PROTOCOL_SMP:
- rc = mvs_task_prep_smp(mvi, &tei);
- break;
- case SAS_PROTOCOL_SSP:
- rc = mvs_task_prep_ssp(mvi, &tei);
- break;
- case SAS_PROTOCOL_SATA:
- case SAS_PROTOCOL_STP:
- rc = mvs_task_prep_ata(mvi, &tei);
- break;
- default:
- rc = -EINVAL;
- break;
- }
+ if (rc)
+ goto err_out_tag;
- if (rc)
- goto err_out_tag;
+ /* TODO: select normal or high priority */
- /* TODO: select normal or high priority */
+ spin_lock(&t->task_state_lock);
+ t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock(&t->task_state_lock);
- mw32(RX_PROD_IDX, mvi->tx_prod);
+ if (n == 1) {
+ spin_unlock_irqrestore(&mvi->lock, flags);
+ mw32(TX_PROD_IDX, mvi->tx_prod);
+ }
+ mvs_hba_memory_dump(mvi, tag, t->task_proto);
- mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_TX_RING_SZ - 1);
+ ++pass;
+ mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
- spin_lock(&task->task_state_lock);
- task->task_state_flags |= SAS_TASK_AT_INITIATOR;
- spin_unlock(&task->task_state_lock);
+ if (n == 1)
+ break;
+
+ t = list_entry(t->list.next, struct sas_task, list);
+ } while (--n);
- spin_unlock_irqrestore(&mvi->lock, flags);
return 0;
err_out_tag:
- mvs_tag_clear(mvi, tag);
+ mvs_tag_free(mvi, tag);
err_out:
- if (n_elem)
- pci_unmap_sg(mvi->pdev, task->scatter, n_elem, task->data_dir);
+ dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", pass);
+ if (!sas_protocol_ata(t->task_proto))
+ if (n_elem)
+ pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
+ t->data_dir);
+ if (pass)
+ mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
spin_unlock_irqrestore(&mvi->lock, flags);
return rc;
}
+static int mvs_task_abort(struct sas_task *task)
+{
+ int rc = 1;
+ unsigned long flags;
+ struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
+ struct pci_dev *pdev = mvi->pdev;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out_done;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ /*FIXME*/
+ rc = TMF_RESP_FUNC_COMPLETE;
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! ");
+ break;
+ case SAS_PROTOCOL_SSP:
+ dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! ");
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:{
+ dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! "
+ "Dump D2H FIS: \n");
+ mvs_hexdump(sizeof(struct host_to_dev_fis),
+ (void *)&task->ata_task.fis, 0);
+ dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
+ mvs_hexdump(16, task->ata_task.atapi_packet, 0);
+ break;
+ }
+ default:
+ break;
+ }
+out_done:
+ return rc;
+}
+
static void mvs_free(struct mvs_info *mvi)
{
int i;
@@ -1238,7 +1787,7 @@ static void mvs_free(struct mvs_info *mvi)
if (mvi->tx)
dma_free_coherent(&mvi->pdev->dev,
- sizeof(*mvi->tx) * MVS_TX_RING_SZ,
+ sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
mvi->tx, mvi->tx_dma);
if (mvi->rx_fis)
dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
@@ -1249,10 +1798,12 @@ static void mvs_free(struct mvs_info *mvi)
mvi->rx, mvi->rx_dma);
if (mvi->slot)
dma_free_coherent(&mvi->pdev->dev,
- sizeof(*mvi->slot) * MVS_RX_RING_SZ,
+ sizeof(*mvi->slot) * MVS_SLOTS,
mvi->slot, mvi->slot_dma);
+#ifdef MVS_ENABLE_PERI
if (mvi->peri_regs)
iounmap(mvi->peri_regs);
+#endif
if (mvi->regs)
iounmap(mvi->regs);
if (mvi->shost)
@@ -1274,25 +1825,25 @@ static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
reg = mvi->regs + MVS_P0_SER_CTLSTAT + (phy_id * 4);
switch (func) {
- case PHY_FUNC_SET_LINK_RATE: {
- struct sas_phy_linkrates *rates = funcdata;
- u32 lrmin = 0, lrmax = 0;
+ case PHY_FUNC_SET_LINK_RATE:{
+ struct sas_phy_linkrates *rates = funcdata;
+ u32 lrmin = 0, lrmax = 0;
- lrmin = (rates->minimum_linkrate << 8);
- lrmax = (rates->maximum_linkrate << 12);
+ lrmin = (rates->minimum_linkrate << 8);
+ lrmax = (rates->maximum_linkrate << 12);
- tmp = readl(reg);
- if (lrmin) {
- tmp &= ~(0xf << 8);
- tmp |= lrmin;
- }
- if (lrmax) {
- tmp &= ~(0xf << 12);
- tmp |= lrmax;
+ tmp = readl(reg);
+ if (lrmin) {
+ tmp &= ~(0xf << 8);
+ tmp |= lrmin;
+ }
+ if (lrmax) {
+ tmp &= ~(0xf << 12);
+ tmp |= lrmax;
+ }
+ writel(tmp, reg);
+ break;
}
- writel(tmp, reg);
- break;
- }
case PHY_FUNC_HARD_RESET:
tmp = readl(reg);
@@ -1335,11 +1886,11 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
sas_phy->lldd_phy = phy;
}
-static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct mvs_info *mvi;
- unsigned long res_start, res_len;
+ unsigned long res_start, res_len, res_flag;
struct asd_sas_phy **arr_phy;
struct asd_sas_port **arr_port;
const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
@@ -1381,9 +1932,10 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
mvi->shost->transportt = mvs_stt;
- mvi->shost->max_id = ~0;
+ mvi->shost->max_id = 21;
mvi->shost->max_lun = ~0;
- mvi->shost->max_cmd_len = ~0;
+ mvi->shost->max_channel = 0;
+ mvi->shost->max_cmd_len = 16;
mvi->sas.sas_ha_name = DRV_NAME;
mvi->sas.dev = &pdev->dev;
@@ -1392,12 +1944,13 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
mvi->sas.sas_phy = arr_phy;
mvi->sas.sas_port = arr_port;
mvi->sas.num_phys = chip->n_phy;
- mvi->sas.lldd_max_execute_num = MVS_TX_RING_SZ - 1;/* FIXME: correct? */
- mvi->sas.lldd_queue_size = MVS_TX_RING_SZ - 1; /* FIXME: correct? */
+ mvi->sas.lldd_max_execute_num = MVS_CHIP_SLOT_SZ - 1;
+ mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
+ mvi->can_queue = (MVS_CHIP_SLOT_SZ >> 1) - 1;
mvi->sas.lldd_ha = mvi;
mvi->sas.core.shost = mvi->shost;
- mvs_tag_set(mvi, MVS_TX_RING_SZ - 1);
+ mvs_tag_init(mvi);
/*
* ioremap main and peripheral registers
@@ -1408,16 +1961,23 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
if (!res_start || !res_len)
goto err_out;
+#ifdef MVS_ENABLE_PERI
mvi->peri_regs = ioremap_nocache(res_start, res_len);
- if (!mvi->regs)
+ if (!mvi->peri_regs)
goto err_out;
+#endif
res_start = pci_resource_start(pdev, 4);
res_len = pci_resource_len(pdev, 4);
if (!res_start || !res_len)
goto err_out;
- mvi->regs = ioremap_nocache(res_start, res_len);
+ res_flag = pci_resource_flags(pdev, 4);
+ if (res_flag & IORESOURCE_CACHEABLE)
+ mvi->regs = ioremap(res_start, res_len);
+ else
+ mvi->regs = ioremap_nocache(res_start, res_len);
+
if (!mvi->regs)
goto err_out;
@@ -1426,14 +1986,14 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
*/
mvi->tx = dma_alloc_coherent(&pdev->dev,
- sizeof(*mvi->tx) * MVS_TX_RING_SZ,
+ sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
&mvi->tx_dma, GFP_KERNEL);
if (!mvi->tx)
goto err_out;
- memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_TX_RING_SZ);
+ memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
- &mvi->rx_fis_dma, GFP_KERNEL);
+ &mvi->rx_fis_dma, GFP_KERNEL);
if (!mvi->rx_fis)
goto err_out;
memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
@@ -1459,7 +2019,7 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
struct mvs_slot_info *slot = &mvi->slot_info[i];
slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
- &slot->buf_dma, GFP_KERNEL);
+ &slot->buf_dma, GFP_KERNEL);
if (!slot->buf)
goto err_out;
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
@@ -1468,7 +2028,6 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
/* finally, read NVRAM to get our SAS address */
if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
goto err_out;
-
return mvi;
err_out:
@@ -1488,26 +2047,89 @@ static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
mw32(CMD_DATA, val);
}
-#if 0
-static u32 mvs_phy_read(struct mvs_info *mvi, unsigned int phy_id, u32 addr)
+static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
{
void __iomem *regs = mvi->regs;
- void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8);
-
- writel(addr, phy_regs);
- return readl(phy_regs + 4);
+ return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4):
+ mr32(P4_SER_CTLSTAT + (port - 4) * 4);
}
-#endif
-static void mvs_phy_write(struct mvs_info *mvi, unsigned int phy_id,
- u32 addr, u32 val)
+static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
{
void __iomem *regs = mvi->regs;
- void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8);
+ if (port < 4)
+ mw32(P0_SER_CTLSTAT + port * 4, val);
+ else
+ mw32(P4_SER_CTLSTAT + (port - 4) * 4, val);
+}
- writel(addr, phy_regs);
- writel(val, phy_regs + 4);
- readl(phy_regs); /* flush */
+static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port)
+{
+ void __iomem *regs = mvi->regs + off;
+ void __iomem *regs2 = mvi->regs + off2;
+ return (port < 4)?readl(regs + port * 8):
+ readl(regs2 + (port - 4) * 8);
+}
+
+static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
+ u32 port, u32 val)
+{
+ void __iomem *regs = mvi->regs + off;
+ void __iomem *regs2 = mvi->regs + off2;
+ if (port < 4)
+ writel(val, regs + port * 8);
+ else
+ writel(val, regs2 + (port - 4) * 8);
+}
+
+static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port);
+}
+
+static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port, val);
+}
+
+static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr)
+{
+ mvs_write_port(mvi, MVS_P0_CFG_ADDR, MVS_P4_CFG_ADDR, port, addr);
+}
+
+static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port);
+}
+
+static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port, val);
+}
+
+static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr)
+{
+ mvs_write_port(mvi, MVS_P0_VSR_ADDR, MVS_P4_VSR_ADDR, port, addr);
+}
+
+static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port);
+}
+
+static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val);
+}
+
+static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port);
+}
+
+static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port, val);
}
static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
@@ -1547,6 +2169,173 @@ static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
tmp &= 0x1fffffff;
tmp |= (2U << 29); /* 8 ms retry */
mvs_cw32(regs, CMD_PHY_TIMER, tmp);
+
+ /* TEST - for phy decoding error, adjust voltage levels */
+ mw32(P0_VSR_ADDR + 0, 0x8);
+ mw32(P0_VSR_DATA + 0, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 8, 0x8);
+ mw32(P0_VSR_DATA + 8, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 16, 0x8);
+ mw32(P0_VSR_DATA + 16, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 24, 0x8);
+ mw32(P0_VSR_DATA + 24, 0x2F0);
+
+}
+
+static void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ tmp = mr32(PCS);
+ if (mvi->chip->n_phy <= 4)
+ tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
+ else
+ tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
+ mw32(PCS, tmp);
+}
+
+static void mvs_detect_porttype(struct mvs_info *mvi, int i)
+{
+ void __iomem *regs = mvi->regs;
+ u32 reg;
+ struct mvs_phy *phy = &mvi->phy[i];
+
+ /* enable auto port detection */
+ mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
+ msleep(100);
+
+ /* TODO check & save device type */
+ reg = mr32(GBL_PORT_TYPE);
+
+ if (reg & MODE_SAS_SATA & (1 << i)) {
+ phy->type = PORT_TYPE_SAS;
+ phy->identify.target_port_protocols = SAS_PROTOCOL_SSP;
+ } else {
+ phy->type = PORT_TYPE_SATA;
+ phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
+ }
+
+}
+
+static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
+{
+ u32 *s = (u32 *) buf;
+
+ if (!s)
+ return NULL;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
+ s[3] = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
+ s[2] = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
+ s[1] = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
+ s[0] = mvs_read_port_cfg_data(mvi, i);
+
+ return (void *)s;
+}
+
+static u32 mvs_is_sig_fis_received(struct mvs_info *mvi, int i)
+{
+ u32 tmp;
+
+ tmp = mvs_read_port_irq_stat(mvi, i) & PHYEV_SIG_FIS;
+ if (tmp)
+ mvs_write_port_irq_stat(mvi, i, PHYEV_SIG_FIS);
+
+ return tmp;
+}
+
+static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
+{
+ struct mvs_phy *phy = &mvi->phy[i];
+ u32 tmp;
+ __le64 tmp64;
+ struct pci_dev *pdev = mvi->pdev;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
+ phy->dev_info = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
+ phy->dev_sas_addr = (__le64) mvs_read_port_cfg_data(mvi, i) << 32;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
+ phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); /* le */
+
+ phy->phy_status = mvs_read_phy_ctl(mvi, i);
+
+ /* FIXME Update Wide Port info */
+ phy->port = &mvi->port[i];
+ phy->port->sas_port.lldd_port = phy->port;
+ phy->port->taskfileset = MVS_ID_NOT_MAPPED;
+
+ if (phy->phy_status & PHY_READY_MASK) {
+ u32 phy_st;
+ struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
+ phy_st = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
+ phy->att_dev_sas_addr =
+ (__le64) mvs_read_port_cfg_data(mvi, i) << 32;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
+ phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
+
+ /*Updated attached_sas_addr */
+ tmp64 = phy->att_dev_sas_addr;
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "phy[%d] Get Attached Address 0x%llX ,"
+ " SAS Address 0x%llX\n",
+ i, tmp64, phy->dev_sas_addr);
+ tmp64 = cpu_to_be64(tmp64);
+ memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
+
+ if (phy->type & PORT_TYPE_SAS) {
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
+ phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
+ phy->identify.device_type =
+ phy->att_dev_info & PORT_DEV_TYPE_MASK;
+
+ sas_phy->linkrate =
+ (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+ if (phy_st & PHY_OOB_DTCTD)
+ sas_phy->oob_mode = SAS_OOB_MODE;
+ phy->frame_rcvd_size =
+ sizeof(struct sas_identify_frame);
+ } else if (phy->type & PORT_TYPE_SATA) {
+ if (mvs_is_sig_fis_received(mvi, i)) {
+ if (phy_st & PHY_OOB_DTCTD)
+ sas_phy->oob_mode = SATA_OOB_MODE;
+ phy->frame_rcvd_size =
+ sizeof(struct dev_to_host_fis);
+ mvs_get_d2h_reg(mvi, i,
+ (void *)sas_phy->frame_rcvd);
+ }
+ }
+ /* workaround for HW phy decoding error on 1.5g disk drive */
+ mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
+ tmp = mvs_read_port_vsr_data(mvi, i);
+ if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
+ SAS_LINK_RATE_1_5_GBPS)
+ tmp &= ~PHY_MODE6_DTL_SPEED;
+ else
+ tmp |= PHY_MODE6_DTL_SPEED;
+ mvs_write_port_vsr_data(mvi, i, tmp);
+
+ }
+ phy->irq_status = mvs_read_port_irq_stat(mvi, i);
}
static int __devinit mvs_hw_init(struct mvs_info *mvi)
@@ -1559,6 +2348,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32(GBL_CTL, 0);
tmp = mr32(GBL_CTL);
+ /* Reset Controller */
if (!(tmp & HBA_RST)) {
if (mvi->flags & MVF_PHY_PWR_FIX) {
pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
@@ -1576,7 +2366,6 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32_f(GBL_CTL, HBA_RST);
}
-
/* wait for reset to finish; timeout is just a guess */
i = 1000;
while (i-- > 0) {
@@ -1590,6 +2379,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
return -EBUSY;
}
+ /* Init Chip */
/* make sure RST is set; HBA_RST /should/ have done that for us */
cctl = mr32(CTL);
if (cctl & CCTL_RST)
@@ -1597,6 +2387,12 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
else
mw32_f(CTL, cctl | CCTL_RST);
+ /* write to device control _AND_ device status register? - A.C. */
+ pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
+ tmp &= ~PRD_REQ_MASK;
+ tmp |= PRD_REQ_SIZE;
+ pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
+
pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
tmp |= PCTL_PWR_ON;
tmp &= ~PCTL_OFF;
@@ -1609,6 +2405,9 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32_f(CTL, cctl);
+ /* reset control */
+ mw32(PCS, 0); /*MVS_PCS */
+
mvs_phy_hacks(mvi);
mw32(CMD_LIST_LO, mvi->slot_dma);
@@ -1617,7 +2416,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32(RX_FIS_LO, mvi->rx_fis_dma);
mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
- mw32(TX_CFG, MVS_TX_RING_SZ);
+ mw32(TX_CFG, MVS_CHIP_SLOT_SZ);
mw32(TX_LO, mvi->tx_dma);
mw32(TX_HI, (mvi->tx_dma >> 16) >> 16);
@@ -1628,42 +2427,82 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
/* init and reset phys */
for (i = 0; i < mvi->chip->n_phy; i++) {
/* FIXME: is this the correct dword order? */
- u32 lo = *((u32 *) &mvi->sas_addr[0]);
- u32 hi = *((u32 *) &mvi->sas_addr[4]);
+ u32 lo = *((u32 *)&mvi->sas_addr[0]);
+ u32 hi = *((u32 *)&mvi->sas_addr[4]);
+
+ mvs_detect_porttype(mvi, i);
/* set phy local SAS address */
- mvs_phy_write(mvi, i, PHYR_ADDR_LO, lo);
- mvs_phy_write(mvi, i, PHYR_ADDR_HI, hi);
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
+ mvs_write_port_cfg_data(mvi, i, lo);
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
+ mvs_write_port_cfg_data(mvi, i, hi);
/* reset phy */
- tmp = readl(regs + MVS_P0_SER_CTLSTAT + (i * 4));
+ tmp = mvs_read_phy_ctl(mvi, i);
tmp |= PHY_RST;
- writel(tmp, regs + MVS_P0_SER_CTLSTAT + (i * 4));
+ mvs_write_phy_ctl(mvi, i, tmp);
}
msleep(100);
for (i = 0; i < mvi->chip->n_phy; i++) {
+ /* clear phy int status */
+ tmp = mvs_read_port_irq_stat(mvi, i);
+ tmp &= ~PHYEV_SIG_FIS;
+ mvs_write_port_irq_stat(mvi, i, tmp);
+
/* set phy int mask */
- writel(PHYEV_BROAD_CH | PHYEV_RDY_CH,
- regs + MVS_P0_INT_MASK + (i * 8));
+ tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS;
+ mvs_write_port_irq_mask(mvi, i, tmp);
- /* clear phy int status */
- tmp = readl(regs + MVS_P0_INT_STAT + (i * 8));
- writel(tmp, regs + MVS_P0_INT_STAT + (i * 8));
+ mvs_update_phyinfo(mvi, i);
+ mvs_enable_xmt(mvi, i);
}
/* FIXME: update wide port bitmaps */
+ /* little endian for open address and command table, etc. */
+ /* A.C.
+ * it seems that ( from the spec ) turning on big-endian won't
+ * do us any good on big-endian machines, need further confirmation
+ */
+ cctl = mr32(CTL);
+ cctl |= CCTL_ENDIAN_CMD;
+ cctl |= CCTL_ENDIAN_DATA;
+ cctl &= ~CCTL_ENDIAN_OPEN;
+ cctl |= CCTL_ENDIAN_RSP;
+ mw32_f(CTL, cctl);
+
+ /* reset CMD queue */
+ tmp = mr32(PCS);
+ tmp |= PCS_CMD_RST;
+ mw32(PCS, tmp);
+ /* interrupt coalescing may cause missing HW interrput in some case,
+ * and the max count is 0x1ff, while our max slot is 0x200,
+ * it will make count 0.
+ */
+ tmp = 0;
+ mw32(INT_COAL, tmp);
+
+ tmp = 0x100;
+ mw32(INT_COAL_TMOUT, tmp);
+
/* ladies and gentlemen, start your engines */
- mw32(TX_CFG, MVS_TX_RING_SZ | TX_EN);
+ mw32(TX_CFG, 0);
+ mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
+ /* enable CMD/CMPL_Q/RESP mode */
mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN |
((mvi->flags & MVF_MSI) ? PCS_SELF_CLEAR : 0));
/* re-enable interrupts globally */
mw32(GBL_CTL, INT_EN);
+ /* enable completion queue interrupt */
+ tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM);
+ mw32(INT_MASK, tmp);
+
return 0;
}
@@ -1680,7 +2519,7 @@ static void __devinit mvs_print_info(struct mvs_info *mvi)
}
static int __devinit mvs_pci_init(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
int rc;
struct mvs_info *mvi;
@@ -1732,6 +2571,7 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
mvs_print_info(mvi);
scsi_scan_host(mvi->shost);
+
return 0;
err_out_shost:
@@ -1771,6 +2611,7 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
static struct sas_domain_function_template mvs_transport_ops = {
.lldd_execute_task = mvs_task_exec,
.lldd_control_phy = mvs_phy_control,
+ .lldd_abort_task = mvs_task_abort,
};
static struct pci_device_id __devinitdata mvs_pci_table[] = {
@@ -1822,4 +2663,3 @@ MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, mvs_pci_table);
-
--
1.5.4.rc4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-25 16:43 ` Ke Wei
@ 2008-01-25 17:24 ` Grant Grundler
2008-01-25 17:38 ` James Bottomley
2008-01-25 22:12 ` Jeff Garzik
2008-01-25 17:38 ` Grant Grundler
` (2 subsequent siblings)
3 siblings, 2 replies; 22+ messages in thread
From: Grant Grundler @ 2008-01-25 17:24 UTC (permalink / raw)
To: Ke Wei; +Cc: Jeff Garzik, linux-scsi, kewei, qswang, jfeng, qzhao
On Jan 25, 2008 8:43 AM, Ke Wei <kewei.mv@gmail.com> wrote:
> The attached is Marvell 6440 SAS/SATA driver. I will try to send email
> by git-send-email.
I know this isn't part of this patch:
#define mr32(reg) readl(regs + MVS_##reg)
#define mw32(reg,val) writel((val), regs + MVS_##reg)
But can "regs" be declared a parameter to the macro?
And the one letter difference in the name is just asking for trouble.
Better to call it "mmio_base" or something a bit longer that won't
likely collide with other stuff.
+/* offset for D2H FIS in the Received FIS List Structure */
+#define SATA_RECEIVED_D2H_FIS(reg_set) \
+ (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
Ditto.
+ MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */
+ MODE_AUTO_DET_PORT6 = (1U << 14),
+ MODE_AUTO_DET_PORT5 = (1U << 13),
+ MODE_AUTO_DET_PORT4 = (1U << 12),
+ MODE_AUTO_DET_PORT3 = (1U << 11),
+ MODE_AUTO_DET_PORT2 = (1U << 10),
+ MODE_AUTO_DET_PORT1 = (1U << 9),
+ MODE_AUTO_DET_PORT0 = (1U << 8),
These really aren't needed.
#define MODE_AUTO_DET_EN (0xff << 8) /* enable auto detect on all
8 ports */
Ditto for MODE_SAS_SATA.
+ /* Port n Attached Device Info */
Groups bits defined have a comment preceeding a group of bits (which
is a good thing). If multiple registers are being defined in one enum
declaration, can you please add either the register offset
to the comment or include the constant that defines the
offset (e.g. MVS_P0_CFG_ADDR)?
Have to stop for now...but I'm wonder how this driver ever worked
given the number of HW register bits that were changed (assuming
they were wrong before this patch). And this driver looks _alot_
better than the previous Marvell drivers I've looked at. Please keep
up the good work! :)
hth,
grant
> Changelog :
> Merged from Jeff's branch to James's branch.
>
> Signed-off-by: Ke Wei <kewei@marvell.com>
>
>
>
> On Jan 23, 2008 7:41 PM, Jeff Garzik <jeff@garzik.org> wrote:
> > Ke Wei wrote:
> > > Attachment is a patch file for 6440 driver. I will have to spend more
> > > time on setting my mail client. Yesterday I used mutt tool. But Look
> > > like the problem still exists.
> > > I fixed all issues which you mentioned , but
> >
> > The changes look good, thanks!
> >
> > In terms of engineering process, I should have been more clear: when
> > revising your submission, you should make the revisions and then
> > regenerate your original patch.
> >
> > To use a silly example, if you needed to fix a 1-character typo in a
> > 1,000-line patch, you would need to make your revision, re-generate the
> > 1,000-line patch, and email that new patch.
> >
> > So, to move forward, please create one single patch with the latest
> > mvsas, diff'd against the 'mvsas' branch of
> > git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
> >
> > I will "ack" that patch (indicate my approval), and unless other
> > objections surface, James will merge your patch into the 'mvsas' branch.
> > That will get the driver on the road to be included in 2.6.25.
> >
> >
> > >>> @@ -666,11 +970,53 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned
> > >>> int addr,
> > >>> err_out:
> > >>> dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
> > >>> return rc;
> > >>> +#else
> > >>> + memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
> > >>> + return 0;
> > >>> +#endif
> > >>
> > >> what happens if two adapters are used, with the same SAS address? That
> > >> causes problems...
> > >>
> > >>
> > > Our bios can write SAS Address per port when system boot , so I think
> > > we don't need read or configure address.
> >
> > It is standard Linux policy to reduce or eliminate BIOS dependencies as
> > much as possible.
> >
> > This is because there are several common scenarios where BIOS may not
> > run, or otherwise not be available:
> >
> > * suspend/resume
> > * controller hotplug
> > * non-x86 PCI platforms such as POWER
> >
> > Thus, we need the driver to obtain these addresses -- hopefully reading
> > them from a BIOS data table somewhere, if NVRAM is not available.
> >
> > This is a highly common scenario -- obtaining unique identifying
> > information in the absence of BIOS.
> >
> >
> >
> > Similarly, we cannot rely on BIOS to perform any global reset or errata
> > workaround duties for us. That must be coded into the driver also.
> >
> >
> > > And I reserved hexdump funciton if you don't care. Only debugging.
> >
> > It is not an important matter, but it would be nice to clean that up
> > eventually.
> >
> > Also, FWIW, we have a standard method of debug output:
> >
> > struct pci_dev *pdev;
> >
> > dev_dbg(&pdev->dev, KERN_INFO,
> > "this is debug message number %d", 2);
> >
> > which will only be compiled into the driver when DEBUG is defined.
> >
> >
> > >>> +static int mvs_abort_task(struct sas_task *task)
> > >>> +{
> > >>> + /*FIXME*/
> > >>> + MVS_PRINTK("mvs abort task\n");
> > >>> + return TMF_RESP_FUNC_COMPLETE;
> > >>> +}
> > >> should make an attempt to do something sane here
> > >>
> > > if entering this abort function , I think I must fix the unknown
> > > issues instead of here. But I also will implement next.
> >
> > Ok, thanks.
> >
> > Jeff
> >
> >
> >
> >
>
>
>
> --
> Best Regards,
> Ke Wei
>
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-25 16:43 ` Ke Wei
2008-01-25 17:24 ` Grant Grundler
@ 2008-01-25 17:38 ` Grant Grundler
2008-01-25 22:39 ` James Bottomley
2008-01-25 23:00 ` James Bottomley
3 siblings, 0 replies; 22+ messages in thread
From: Grant Grundler @ 2008-01-25 17:38 UTC (permalink / raw)
To: Ke Wei; +Cc: Jeff Garzik, linux-scsi, kewei, qswang, jfeng, qzhao
On Jan 25, 2008 8:43 AM, Ke Wei <kewei.mv@gmail.com> wrote:
> The attached is Marvell 6440 SAS/SATA driver. I will try to send email
> by git-send-email.
>
Sorry, just saw some more issues in
+static void mvs_hba_interrupt_enable(struct mvs_info *mvi, int enable)
Three comments here:
1) This routine is slightly misnamed since it can both enable and disable
the interrupt. I _suggest_ to not pass in "enable" parameter and add a
mvs_hba_interrupt_disable() to deal with (2) and (3) below.
2) On interrupt disable, MMIO write posting _could_ be a problem here.
ie interrupts could be generated after calling this routine since it doesn't
force the MMIO write to the PCI device with an MMIO read.
(For more info on this see chapter 4 of
http://iou.parisc-linux.org/ols_2002/ )
3) Even after fixing (2), interrupts can already be in-flight and not
yet delivered.
Higher level code needs to make sure it can tolerate a "late arriving" IRQ.
One MMIO read should mostly solve this for MSI but not for Line-based IRQ.
(MMIO Read-return will flush inflight MSI).
hth,
grant
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-25 17:24 ` Grant Grundler
@ 2008-01-25 17:38 ` James Bottomley
2008-01-25 22:12 ` Jeff Garzik
1 sibling, 0 replies; 22+ messages in thread
From: James Bottomley @ 2008-01-25 17:38 UTC (permalink / raw)
To: Grant Grundler
Cc: Ke Wei, Jeff Garzik, linux-scsi, kewei, qswang, jfeng, qzhao
On Fri, 2008-01-25 at 09:24 -0800, Grant Grundler wrote:
> On Jan 25, 2008 8:43 AM, Ke Wei <kewei.mv@gmail.com> wrote:
> > The attached is Marvell 6440 SAS/SATA driver. I will try to send email
> > by git-send-email.
>
> I know this isn't part of this patch:
> #define mr32(reg) readl(regs + MVS_##reg)
> #define mw32(reg,val) writel((val), regs + MVS_##reg)
>
> But can "regs" be declared a parameter to the macro?
> And the one letter difference in the name is just asking for trouble.
> Better to call it "mmio_base" or something a bit longer that won't
> likely collide with other stuff.
>
> +/* offset for D2H FIS in the Received FIS List Structure */
> +#define SATA_RECEIVED_D2H_FIS(reg_set) \
> + (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
>
> Ditto.
>
> + MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */
> + MODE_AUTO_DET_PORT6 = (1U << 14),
> + MODE_AUTO_DET_PORT5 = (1U << 13),
> + MODE_AUTO_DET_PORT4 = (1U << 12),
> + MODE_AUTO_DET_PORT3 = (1U << 11),
> + MODE_AUTO_DET_PORT2 = (1U << 10),
> + MODE_AUTO_DET_PORT1 = (1U << 9),
> + MODE_AUTO_DET_PORT0 = (1U << 8),
>
> These really aren't needed.
>
> #define MODE_AUTO_DET_EN (0xff << 8) /* enable auto detect on all
> 8 ports */
>
>
> Ditto for MODE_SAS_SATA.
Given that we don't have public docs for this driver, having register
bit definitions in the driver, even if they aren't used anywhere can be
incredibly helpful, so please don't remove them. Even more useful would
be additional comments saying what they actually do ...
James
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-23 10:54 ` Ke Wei
2008-01-23 11:41 ` Jeff Garzik
@ 2008-01-25 21:27 ` James Bottomley
1 sibling, 0 replies; 22+ messages in thread
From: James Bottomley @ 2008-01-25 21:27 UTC (permalink / raw)
To: Ke Wei; +Cc: Jeff Garzik, linux-scsi, kewei, qswang, jfeng, qzhao
On Wed, 2008-01-23 at 18:54 +0800, Ke Wei wrote:
> Attachment is a patch file for 6440 driver. I will have to spend more
> time on setting my mail client. Yesterday I used mutt tool. But Look
> like the problem still exists.
By default, unfortunately, I think no email tool nowadays inserts plain
text ... they all assume you want it nicely formatted with proper line
breaks.
There's a guide to inserting plain text patches inline with some email
tools in the kernel Documentation directory:
Documentation/email-clients.txt
The current attachment is fine for a patch application, Thanks.
James
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-25 17:24 ` Grant Grundler
2008-01-25 17:38 ` James Bottomley
@ 2008-01-25 22:12 ` Jeff Garzik
1 sibling, 0 replies; 22+ messages in thread
From: Jeff Garzik @ 2008-01-25 22:12 UTC (permalink / raw)
To: Grant Grundler; +Cc: Ke Wei, linux-scsi, kewei, qswang, jfeng, qzhao
Grant Grundler wrote:
> On Jan 25, 2008 8:43 AM, Ke Wei <kewei.mv@gmail.com> wrote:
>> The attached is Marvell 6440 SAS/SATA driver. I will try to send email
>> by git-send-email.
>
> I know this isn't part of this patch:
> #define mr32(reg) readl(regs + MVS_##reg)
> #define mw32(reg,val) writel((val), regs + MVS_##reg)
>
> But can "regs" be declared a parameter to the macro?
This is a common technique in drivers (especially net drivers),
eliminating the redundant-across-the-entire-driver argument passed to
each register read or write. The result is infinitely more readable and
compact.
val = mr32(IRQ_STAT);
immediately communicates all the necessary information you need.
> + MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */
> + MODE_AUTO_DET_PORT6 = (1U << 14),
> + MODE_AUTO_DET_PORT5 = (1U << 13),
> + MODE_AUTO_DET_PORT4 = (1U << 12),
> + MODE_AUTO_DET_PORT3 = (1U << 11),
> + MODE_AUTO_DET_PORT2 = (1U << 10),
> + MODE_AUTO_DET_PORT1 = (1U << 9),
> + MODE_AUTO_DET_PORT0 = (1U << 8),
>
> These really aren't needed.
Like James noted, without public docs, we don't want to be removing any
hardware definitions.
> Have to stop for now...but I'm wonder how this driver ever worked
> given the number of HW register bits that were changed (assuming
> they were wrong before this patch). And this driver looks _alot_
> better than the previous Marvell drivers I've looked at. Please keep
> up the good work! :)
Before this patch, the driver did not work. As I do with all other
drivers I write, I write the entire driver from the datasheet before
testing anything.
Jeff
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-25 16:43 ` Ke Wei
2008-01-25 17:24 ` Grant Grundler
2008-01-25 17:38 ` Grant Grundler
@ 2008-01-25 22:39 ` James Bottomley
2008-01-27 15:10 ` Ke Wei
2008-01-27 15:27 ` Ke Wei
2008-01-25 23:00 ` James Bottomley
3 siblings, 2 replies; 22+ messages in thread
From: James Bottomley @ 2008-01-25 22:39 UTC (permalink / raw)
To: Ke Wei; +Cc: Jeff Garzik, linux-scsi, kewei, qswang, jfeng, qzhao
On Sat, 2008-01-26 at 00:43 +0800, Ke Wei wrote:
> struct mvs_phy {
> struct mvs_port *port;
> struct asd_sas_phy sas_phy;
> + struct sas_identify identify;
> + __le32 dev_info;
> + __le64 dev_sas_addr;
> + __le32 att_dev_info;
> + __le64 att_dev_sas_addr;
> + u32 type;
> + __le32 phy_status;
> + __le32 irq_status;
> + u8 wide_port_phymap;
> + u32 frame_rcvd_size;
> + u8 frame_rcvd[32];
>
> - u8 frame_rcvd[24 + 1024];
> };
These __le quantites don't look right ... they're all read in by readl,
which will convert little endian to CPU anyway.
> @@ -437,27 +586,55 @@ struct mvs_info {
> dma_addr_t rx_dma;
> u32 rx_cons; /* RX consumer idx */
>
> - __le32 *rx_fis; /* RX'd FIS area */
> + void *rx_fis; /* RX'd FIS area */
Now the received FIS, on the other hand, provided you're storing it in
wire format (which you look to be) *is* little endian data by definition
in the ATA spec.
> -static void mvs_tag_clear(struct mvs_info *mvi, unsigned int tag)
> +static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
> {
> - mvi->tags[tag / sizeof(unsigned long)] &=
> - ~(1UL << (tag % sizeof(unsigned long)));
> + mvi->tag_in = (mvi->tag_in + 1) & (MVS_SLOTS - 1);
> + mvi->tags[mvi->tag_in] = tag;
> }
>
> -static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
> +static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
> {
> - mvi->tags[tag / sizeof(unsigned long)] |=
> - (1UL << (tag % sizeof(unsigned long)));
> + mvi->tag_out = (mvi->tag_out - 1) & (MVS_SLOTS - 1);
> }
>
> -static bool mvs_tag_test(struct mvs_info *mvi, unsigned int tag)
> +static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
> {
> - return mvi->tags[tag / sizeof(unsigned long)] &
> - (1UL << (tag % sizeof(unsigned long)));
> + if (mvi->tag_out != mvi->tag_in) {
> + *tag_out = mvi->tags[mvi->tag_out];
> + mvi->tag_out = (mvi->tag_out + 1) & (MVS_SLOTS - 1);
> + return 0;
> + }
> + return -EBUSY;
I really don't think you should be doing this. That single ring governs
all the potential tag slots for everything in this device. If you do a
simple head tail allocation, what can happen is that you get a slow tag
(attached to a format command, or a tape command) and then the ring head
will hit the slow tag and the entire device will halt. I think you need
a bitmap based allocation algorithm to ensure that if you have a free
tag anywhere, you'll use it.
If you look at the aic94xx index functions in aic94xx_hwi.h you'll see
asd_tc_index_get() and asd_tc_index_release() doing exactly what you
want with the native linux bitmap functions (the aic also uses a single
issue queue with indexes into it).
James
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-25 16:43 ` Ke Wei
` (2 preceding siblings ...)
2008-01-25 22:39 ` James Bottomley
@ 2008-01-25 23:00 ` James Bottomley
2008-01-25 23:05 ` Jeff Garzik
3 siblings, 1 reply; 22+ messages in thread
From: James Bottomley @ 2008-01-25 23:00 UTC (permalink / raw)
To: Ke Wei; +Cc: Jeff Garzik, linux-scsi, kewei, qswang, jfeng, qzhao
On Sat, 2008-01-26 at 00:43 +0800, Ke Wei wrote:
> The attached is Marvell 6440 SAS/SATA driver. I will try to send email
> by git-send-email.
>
> Changelog :
> Merged from Jeff's branch to James's branch.
>
> Signed-off-by: Ke Wei <kewei@marvell.com>
A compile test of this seems to show some problems:
drivers/scsi/mvsas.c:2126: warning: 'mvs_read_port_irq_mask' defined but not used
drivers/scsi/mvsas.c:796: warning: 'mvs_hba_interrupt_enable' defined but not used
drivers/scsi/mvsas.c:1349: warning: 'mvs_free_reg_set' defined but not used
The lack of interrupt enable looks potentially fatal...except that you
have an open coded interrupt enable in mvs_hw_init().
James
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-25 23:00 ` James Bottomley
@ 2008-01-25 23:05 ` Jeff Garzik
0 siblings, 0 replies; 22+ messages in thread
From: Jeff Garzik @ 2008-01-25 23:05 UTC (permalink / raw)
To: James Bottomley; +Cc: Ke Wei, linux-scsi, kewei, qswang, jfeng, qzhao
James Bottomley wrote:
> The lack of interrupt enable looks potentially fatal...
See my comments on this specific issue, in this thread, for the reason
why that function isn't used...
Jeff
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-25 22:39 ` James Bottomley
@ 2008-01-27 15:10 ` Ke Wei
2008-01-27 15:27 ` Ke Wei
1 sibling, 0 replies; 22+ messages in thread
From: Ke Wei @ 2008-01-27 15:10 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi, kewei.mv, jeff, qswang, jfeng, qzhao, kewei
resend mail, include the driver patch inline in this email.
Changelog :
Merged from Jeff's branch to James's branch.
Signed-off-by: Ke Wei <kewei@marvell.com>
---
drivers/scsi/mvsas.c | 1376 ++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 1108 insertions(+), 268 deletions(-)
mode change 100644 => 100755 drivers/scsi/mvsas.c
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
old mode 100644
new mode 100755
index 03638b9..321be21
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -2,6 +2,7 @@
mvsas.c - Marvell 88SE6440 SAS/SATA support
Copyright 2007 Red Hat, Inc.
+ Copyright 2008 Marvell. <kewei@marvell.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -37,8 +38,10 @@
#include <scsi/libsas.h>
#include <asm/io.h>
-#define DRV_NAME "mvsas"
-#define DRV_VERSION "0.1"
+#define DRV_NAME "mvsas"
+#define DRV_VERSION "0.3"
+#define _MV_DUMP 0
+#define MVS_DISABLE_NVRAM
#define mr32(reg) readl(regs + MVS_##reg)
#define mw32(reg,val) writel((val), regs + MVS_##reg)
@@ -47,6 +50,17 @@
readl(regs + MVS_##reg); \
} while (0)
+#define MVS_ID_NOT_MAPPED 0xff
+#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
+
+/* offset for D2H FIS in the Received FIS List Structure */
+#define SATA_RECEIVED_D2H_FIS(reg_set) \
+ (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
+#define SATA_RECEIVED_PIO_FIS(reg_set) \
+ (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
+#define UNASSOC_D2H_FIS(id) \
+ (mvi->rx_fis + 0x100 * id)
+
/* driver compile-time configuration */
enum driver_configuration {
MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */
@@ -57,10 +71,12 @@ enum driver_configuration {
MVS_SLOTS = 512, /* command slots */
MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */
MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */
- MVS_ATA_CMD_SZ = 128, /* SATA command table buffer size */
+ MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */
MVS_OAF_SZ = 64, /* Open address frame buffer size */
MVS_RX_FIS_COUNT = 17, /* Optional rx'd FISs (max 17) */
+
+ MVS_QUEUE_SIZE = 30, /* Support Queue depth */
};
/* unchangeable hardware details */
@@ -89,7 +105,7 @@ enum hw_registers {
MVS_GBL_CTL = 0x04, /* global control */
MVS_GBL_INT_STAT = 0x08, /* global irq status */
MVS_GBL_PI = 0x0C, /* ports implemented bitmask */
- MVS_GBL_PORT_TYPE = 0x00, /* port type */
+ MVS_GBL_PORT_TYPE = 0xa0, /* port type */
MVS_CTL = 0x100, /* SAS/SATA port configuration */
MVS_PCS = 0x104, /* SAS/SATA port control/status */
@@ -102,11 +118,12 @@ enum hw_registers {
MVS_TX_LO = 0x124, /* TX (delivery) ring addr */
MVS_TX_HI = 0x128,
- MVS_RX_PROD_IDX = 0x12C, /* RX producer pointer */
- MVS_RX_CONS_IDX = 0x130, /* RX consumer pointer (RO) */
+ MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */
+ MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */
MVS_RX_CFG = 0x134, /* RX configuration */
MVS_RX_LO = 0x138, /* RX (completion) ring addr */
MVS_RX_HI = 0x13C,
+ MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */
MVS_INT_COAL = 0x148, /* Int coalescing config */
MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */
@@ -117,9 +134,12 @@ enum hw_registers {
/* ports 1-3 follow after this */
MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */
MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */
+ MVS_P4_INT_STAT = 0x200, /* Port 4 interrupt status */
+ MVS_P4_INT_MASK = 0x204, /* Port 4 interrupt enable mask */
/* ports 1-3 follow after this */
MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */
+ MVS_P4_SER_CTLSTAT = 0x220, /* port4 serial control/status */
MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */
MVS_CMD_DATA = 0x1BC, /* Command register port (data) */
@@ -127,6 +147,14 @@ enum hw_registers {
/* ports 1-3 follow after this */
MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */
MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */
+ MVS_P4_CFG_ADDR = 0x230, /* Port 4 config address */
+ MVS_P4_CFG_DATA = 0x234, /* Port 4 config data */
+
+ /* ports 1-3 follow after this */
+ MVS_P0_VSR_ADDR = 0x1E0, /* port0 VSR address */
+ MVS_P0_VSR_DATA = 0x1E4, /* port0 VSR data */
+ MVS_P4_VSR_ADDR = 0x250, /* port 4 VSR addr */
+ MVS_P4_VSR_DATA = 0x254, /* port 4 VSR data */
};
enum hw_register_bits {
@@ -140,12 +168,35 @@ enum hw_register_bits {
/* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */
SATA_TARGET = (1U << 16), /* port0 SATA target enable */
- AUTO_DET = (1U << 8), /* port0 SAS/SATA autodetect */
- SAS_MODE = (1U << 0), /* port0 SAS(1), SATA(0) mode */
- /* SAS_MODE value may be
- * dictated (in hw) by values
- * of SATA_TARGET & AUTO_DET
- */
+ MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */
+ MODE_AUTO_DET_PORT6 = (1U << 14),
+ MODE_AUTO_DET_PORT5 = (1U << 13),
+ MODE_AUTO_DET_PORT4 = (1U << 12),
+ MODE_AUTO_DET_PORT3 = (1U << 11),
+ MODE_AUTO_DET_PORT2 = (1U << 10),
+ MODE_AUTO_DET_PORT1 = (1U << 9),
+ MODE_AUTO_DET_PORT0 = (1U << 8),
+ MODE_AUTO_DET_EN = MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 |
+ MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 |
+ MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 |
+ MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7,
+ MODE_SAS_PORT7_MASK = (1U << 7), /* port0 SAS(1), SATA(0) mode */
+ MODE_SAS_PORT6_MASK = (1U << 6),
+ MODE_SAS_PORT5_MASK = (1U << 5),
+ MODE_SAS_PORT4_MASK = (1U << 4),
+ MODE_SAS_PORT3_MASK = (1U << 3),
+ MODE_SAS_PORT2_MASK = (1U << 2),
+ MODE_SAS_PORT1_MASK = (1U << 1),
+ MODE_SAS_PORT0_MASK = (1U << 0),
+ MODE_SAS_SATA = MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK |
+ MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK |
+ MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK |
+ MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK,
+
+ /* SAS_MODE value may be
+ * dictated (in hw) by values
+ * of SATA_TARGET & AUTO_DET
+ */
/* MVS_TX_CFG */
TX_EN = (1U << 16), /* Enable TX */
@@ -167,12 +218,14 @@ enum hw_register_bits {
CINT_MEM = (1U << 26), /* int mem parity err */
CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */
CINT_SRS = (1U << 3), /* SRS event */
- CINT_CI_STOP = (1U << 10), /* cmd issue stopped */
+ CINT_CI_STOP = (1U << 1), /* cmd issue stopped */
CINT_DONE = (1U << 0), /* cmd completion */
/* shl for ports 1-3 */
CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */
- CINT_PORT = (1U << 8), /* port0 event */
+ CINT_PORT = (1U << 8), /* port0 event */
+ CINT_PORT_MASK_OFFSET = 8,
+ CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET),
/* TX (delivery) ring bits */
TXQ_CMD_SHIFT = 29,
@@ -239,6 +292,12 @@ enum hw_register_bits {
PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */
PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */
PHY_RST = (1U << 0), /* phy reset */
+ PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8),
+ PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12),
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16),
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK =
+ (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET),
+ PHY_READY_MASK = (1U << 20),
/* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */
@@ -260,13 +319,37 @@ enum hw_register_bits {
PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */
/* MVS_PCS */
+ PCS_EN_SATA_REG_SHIFT = (16), /* Enable SATA Register Set */
+ PCS_EN_PORT_XMT_SHIFT = (12), /* Enable Port Transmit */
+ PCS_EN_PORT_XMT_SHIFT2 = (8), /* For 6480 */
PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */
PCS_RSP_RX_EN = (1U << 7), /* raw response rx */
PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */
PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */
PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */
- PCS_CMD_RST = (1U << 2), /* reset cmd issue */
+ PCS_CMD_RST = (1U << 1), /* reset cmd issue */
PCS_CMD_EN = (1U << 0), /* enable cmd issue */
+
+ /* Port n Attached Device Info */
+ PORT_DEV_SSP_TRGT = (1U << 19),
+ PORT_DEV_SMP_TRGT = (1U << 18),
+ PORT_DEV_STP_TRGT = (1U << 17),
+ PORT_DEV_SSP_INIT = (1U << 11),
+ PORT_DEV_SMP_INIT = (1U << 10),
+ PORT_DEV_STP_INIT = (1U << 9),
+ PORT_PHY_ID_MASK = (0xFFU << 24),
+ PORT_DEV_TRGT_MASK = (0x7U << 17),
+ PORT_DEV_INIT_MASK = (0x7U << 9),
+ PORT_DEV_TYPE_MASK = (0x7U << 0),
+
+ /* Port n PHY Status */
+ PHY_RDY = (1U << 2),
+ PHY_DW_SYNC = (1U << 1),
+ PHY_OOB_DTCTD = (1U << 0),
+
+ /* VSR */
+ /* PHYMODE 6 (CDB) */
+ PHY_MODE6_DTL_SPEED = (1U << 27),
};
enum mvs_info_flags {
@@ -329,33 +412,60 @@ enum sas_cmd_port_registers {
/* SAS/SATA configuration port registers, aka phy registers */
enum sas_sata_config_port_regs {
- PHYR_IDENTIFY = 0x0, /* info for IDENTIFY frame */
- PHYR_ADDR_LO = 0x4, /* my SAS address (low) */
- PHYR_ADDR_HI = 0x8, /* my SAS address (high) */
- PHYR_ATT_DEV_INFO = 0xC, /* attached device info */
+ PHYR_IDENTIFY = 0x00, /* info for IDENTIFY frame */
+ PHYR_ADDR_LO = 0x04, /* my SAS address (low) */
+ PHYR_ADDR_HI = 0x08, /* my SAS address (high) */
+ PHYR_ATT_DEV_INFO = 0x0C, /* attached device info */
PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */
PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */
PHYR_SATA_CTL = 0x18, /* SATA control */
PHYR_PHY_STAT = 0x1C, /* PHY status */
+ PHYR_SATA_SIG0 = 0x20, /*port SATA signature FIS(Byte 0-3) */
+ PHYR_SATA_SIG1 = 0x24, /*port SATA signature FIS(Byte 4-7) */
+ PHYR_SATA_SIG2 = 0x28, /*port SATA signature FIS(Byte 8-11) */
+ PHYR_SATA_SIG3 = 0x2c, /*port SATA signature FIS(Byte 12-15) */
+ PHYR_R_ERR_COUNT = 0x30, /* port R_ERR count register */
+ PHYR_CRC_ERR_COUNT = 0x34, /* port CRC error count register */
PHYR_WIDE_PORT = 0x38, /* wide port participating */
PHYR_CURRENT0 = 0x80, /* current connection info 0 */
PHYR_CURRENT1 = 0x84, /* current connection info 1 */
PHYR_CURRENT2 = 0x88, /* current connection info 2 */
};
+/* SAS/SATA Vendor Specific Port Registers */
+enum sas_sata_vsp_regs {
+ VSR_PHY_STAT = 0x00, /* Phy Status */
+ VSR_PHY_MODE1 = 0x01, /* phy tx */
+ VSR_PHY_MODE2 = 0x02, /* tx scc */
+ VSR_PHY_MODE3 = 0x03, /* pll */
+ VSR_PHY_MODE4 = 0x04, /* VCO */
+ VSR_PHY_MODE5 = 0x05, /* Rx */
+ VSR_PHY_MODE6 = 0x06, /* CDR */
+ VSR_PHY_MODE7 = 0x07, /* Impedance */
+ VSR_PHY_MODE8 = 0x08, /* Voltage */
+ VSR_PHY_MODE9 = 0x09, /* Test */
+ VSR_PHY_MODE10 = 0x0A, /* Power */
+ VSR_PHY_MODE11 = 0x0B, /* Phy Mode */
+ VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */
+ VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */
+};
+
enum pci_cfg_registers {
- PCR_PHY_CTL = 0x40,
- PCR_PHY_CTL2 = 0x90,
+ PCR_PHY_CTL = 0x40,
+ PCR_PHY_CTL2 = 0x90,
+ PCR_DEV_CTRL = 0xE8,
};
enum pci_cfg_register_bits {
- PCTL_PWR_ON = (0xFU << 24),
- PCTL_OFF = (0xFU << 12),
+ PCTL_PWR_ON = (0xFU << 24),
+ PCTL_OFF = (0xFU << 12),
+ PRD_REQ_SIZE = (0x4000),
+ PRD_REQ_MASK = (0x00007000),
};
enum nvram_layout_offsets {
- NVR_SIG = 0x00, /* 0xAA, 0x55 */
- NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */
+ NVR_SIG = 0x00, /* 0xAA, 0x55 */
+ NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */
};
enum chip_flavors {
@@ -364,10 +474,38 @@ enum chip_flavors {
chip_6480,
};
+enum port_type {
+ PORT_TYPE_SAS = (1L << 1),
+ PORT_TYPE_SATA = (1L << 0),
+};
+
+/* Command Table Format */
+enum ct_format {
+ /* SSP */
+ SSP_F_H = 0x00,
+ SSP_F_IU = 0x18,
+ SSP_F_MAX = 0x4D,
+ /* STP */
+ STP_CMD_FIS = 0x00,
+ STP_ATAPI_CMD = 0x40,
+ STP_F_MAX = 0x10,
+ /* SMP */
+ SMP_F_T = 0x00,
+ SMP_F_DEP = 0x01,
+ SMP_F_MAX = 0x101,
+};
+
+enum status_buffer {
+ SB_EIR_OFF = 0x00, /* Error Information Record */
+ SB_RFB_OFF = 0x08, /* Response Frame Buffer */
+ SB_RFB_MAX = 0x400, /* RFB size*/
+};
+
+
struct mvs_chip_info {
- unsigned int n_phy;
- unsigned int srs_sz;
- unsigned int slot_width;
+ u32 n_phy;
+ u32 srs_sz;
+ u32 slot_width;
};
struct mvs_err_info {
@@ -395,7 +533,7 @@ struct mvs_cmd_hdr {
struct mvs_slot_info {
struct sas_task *task;
- unsigned int n_elem;
+ u32 n_elem;
/* DMA buffer for storing cmd tbl, open addr frame, status buffer,
* and PRD table
@@ -408,13 +546,24 @@ struct mvs_slot_info {
struct mvs_port {
struct asd_sas_port sas_port;
+ u8 taskfileset;
};
struct mvs_phy {
struct mvs_port *port;
struct asd_sas_phy sas_phy;
+ struct sas_identify identify;
+ __le32 dev_info;
+ __le64 dev_sas_addr;
+ __le32 att_dev_info;
+ __le64 att_dev_sas_addr;
+ u32 type;
+ __le32 phy_status;
+ __le32 irq_status;
+ u8 wide_port_phymap;
+ u32 frame_rcvd_size;
+ u8 frame_rcvd[32];
- u8 frame_rcvd[24 + 1024];
};
struct mvs_info {
@@ -437,27 +586,55 @@ struct mvs_info {
dma_addr_t rx_dma;
u32 rx_cons; /* RX consumer idx */
- __le32 *rx_fis; /* RX'd FIS area */
+ void *rx_fis; /* RX'd FIS area */
dma_addr_t rx_fis_dma;
- struct mvs_cmd_hdr *slot; /* DMA command header slots */
+ struct mvs_cmd_hdr *slot; /* DMA command header slots */
dma_addr_t slot_dma;
const struct mvs_chip_info *chip;
- /* further per-slot information */
+ unsigned long tags[MVS_SLOTS];
struct mvs_slot_info slot_info[MVS_SLOTS];
- unsigned long tags[(MVS_SLOTS / sizeof(unsigned long)) + 1];
-
+ /* further per-slot information */
struct mvs_phy phy[MVS_MAX_PHYS];
struct mvs_port port[MVS_MAX_PHYS];
+
+ u32 can_queue; /* per adapter */
+ u32 tag_out; /*Get*/
+ u32 tag_in; /*Give*/
};
+struct mvs_queue_task {
+ struct list_head list;
+
+ void *uldd_task;
+};
+
+static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port);
+static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val);
+static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port);
+static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
+ u32 port, u32 val);
+static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port);
+static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val);
+static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr);
+static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port);
+static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val);
+static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr);
+static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port);
+static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val);
+static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port);
+static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val);
+
+static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
+static void mvs_scan_start(struct Scsi_Host *);
+
static struct scsi_transport_template *mvs_stt;
static const struct mvs_chip_info mvs_chips[] = {
- [chip_6320] = { 2, 16, 9 },
- [chip_6440] = { 4, 16, 9 },
+ [chip_6320] = { 2, 16, 9 },
+ [chip_6440] = { 4, 16, 9 },
[chip_6480] = { 8, 32, 10 },
};
@@ -468,6 +645,8 @@ static struct scsi_host_template mvs_sht = {
.target_alloc = sas_target_alloc,
.slave_configure = sas_slave_configure,
.slave_destroy = sas_slave_destroy,
+ .scan_finished = mvs_scan_finished,
+ .scan_start = mvs_scan_start,
.change_queue_depth = sas_change_queue_depth,
.change_queue_type = sas_change_queue_type,
.bios_param = sas_bios_param,
@@ -477,14 +656,159 @@ static struct scsi_host_template mvs_sht = {
.sg_tablesize = SG_ALL,
.max_sectors = SCSI_DEFAULT_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING,
- .eh_device_reset_handler= sas_eh_device_reset_handler,
+ .eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
.slave_alloc = sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
};
-static void mvs_int_rx(struct mvs_info *mvi, bool self_clear);
+static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr)
+{
+ u32 i;
+ u32 run;
+ u32 offset;
+
+ offset = 0;
+ while (size) {
+ printk("%08X : ", baseaddr + offset);
+ if (size >= 16)
+ run = 16;
+ else
+ run = size;
+ size -= run;
+ for (i = 0; i < 16; i++) {
+ if (i < run)
+ printk("%02X ", (u32)data[i]);
+ else
+ printk(" ");
+ }
+ printk(": ");
+ for (i = 0; i < run; i++)
+ printk("%c", isalnum(data[i]) ? data[i] : '.');
+ printk("\n");
+ data = &data[16];
+ offset += run;
+ }
+ printk("\n");
+}
+
+static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
+ enum sas_protocol proto)
+{
+ u32 offset;
+ u32 len_ct;
+ struct pci_dev *pdev = mvi->pdev;
+
+ if (sas_protocol_ata(proto))
+ len_ct = MVS_ATA_CMD_SZ;
+ else
+ len_ct = MVS_SSP_CMD_SZ;
+
+ offset =
+ len_ct + MVS_OAF_SZ +
+ sizeof(struct mvs_prd) * mvi->slot_info[tag].n_elem;
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer :\n");
+ mvs_hexdump(32, (u8 *) mvi->slot_info[tag].response,
+ (u32) mvi->slot_info[tag].buf_dma + offset);
+}
+
+static void mvs_hba_memory_dump(struct mvs_info *mvi, u32 tag,
+ enum sas_protocol proto)
+{
+#if _MV_DUMP
+ u32 sz, w_ptr, r_ptr;
+ u64 addr;
+ u32 len_ct;
+ void __iomem *regs = mvi->regs;
+ struct pci_dev *pdev = mvi->pdev;
+
+ if (sas_protocol_ata(proto))
+ len_ct = MVS_ATA_CMD_SZ;
+ else
+ len_ct = MVS_SSP_CMD_SZ;
+
+ /*Delivery Queue */
+ sz = mr32(TX_CFG) & TX_RING_SZ_MASK;
+ w_ptr = mr32(TX_PROD_IDX) & TX_RING_SZ_MASK;
+ r_ptr = mr32(TX_CONS_IDX) & TX_RING_SZ_MASK;
+ addr = mr32(TX_HI) << 16 << 16 | mr32(TX_LO);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Delivery Queue Size=%04d , WRT_PTR=%04X , RD_PTR=%04X\n",
+ sz, w_ptr, r_ptr);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Delivery Queue Base Address=0x%llX (PA)"
+ "(tx_dma=0x%llX), Entry=%04d\n",
+ addr, mvi->tx_dma, w_ptr);
+ mvs_hexdump(sizeof(u32), (u8 *)(&mvi->tx[mvi->tx_prod]),
+ (u32) mvi->tx_dma + sizeof(u32) * w_ptr);
+ /*Command List */
+ addr = mr32(CMD_LIST_HI) << 16 << 16 | mr32(CMD_LIST_LO);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Command List Base Address=0x%llX (PA)"
+ "(slot_dma=0x%llX), Header=%03d\n",
+ addr, mvi->slot_dma, tag);
+ dev_printk(KERN_DEBUG, &pdev->dev, "Command Header[%03d]:\n", tag);
+ /*mvs_cmd_hdr */
+ mvs_hexdump(sizeof(struct mvs_cmd_hdr), (u8 *)(&mvi->slot[tag]),
+ (u32) mvi->slot_dma + tag * sizeof(struct mvs_cmd_hdr));
+ /*1.command table area */
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Command Table :\n");
+ mvs_hexdump(len_ct, (u8 *) mvi->slot_info[tag].buf,
+ (u32) mvi->slot_info[tag].buf_dma);
+ /*2.open address frame area */
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Open Address Frame :\n");
+ mvs_hexdump(MVS_OAF_SZ, (u8 *) mvi->slot_info[tag].buf + len_ct,
+ (u32) mvi->slot_info[tag].buf_dma + len_ct);
+ /*3.status buffer */
+ mvs_hba_sb_dump(mvi, tag, proto);
+ /*4.PRD table */
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->PRD table :\n");
+ mvs_hexdump(sizeof(struct mvs_prd) * mvi->slot_info[tag].n_elem,
+ (u8 *) mvi->slot_info[tag].buf + len_ct + MVS_OAF_SZ,
+ (u32) mvi->slot_info[tag].buf_dma + len_ct + MVS_OAF_SZ);
+#endif
+}
+
+static void mvs_hba_cq_dump(struct mvs_info *mvi)
+{
+#if _MV_DUMP
+ u64 addr;
+ void __iomem *regs = mvi->regs;
+ struct pci_dev *pdev = mvi->pdev;
+ u32 entry = mvi->rx_cons + 1;
+ u32 rx_desc = le32_to_cpu(mvi->rx[entry]);
+
+ /*Completion Queue */
+ addr = mr32(RX_HI) << 16 << 16 | mr32(RX_LO);
+ dev_printk(KERN_DEBUG, &pdev->dev, "Completion Task = 0x%08X\n",
+ (u32) mvi->slot_info[rx_desc & RXQ_SLOT_MASK].task);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Completion List Base Address=0x%llX (PA), "
+ "CQ_Entry=%04d, CQ_WP=0x%08X\n",
+ addr, entry - 1, mvi->rx[0]);
+ mvs_hexdump(sizeof(u32), (u8 *)(&rx_desc),
+ mvi->rx_dma + sizeof(u32) * entry);
+#endif
+}
+
+static void mvs_hba_interrupt_enable(struct mvs_info *mvi, int enable)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&mvi->lock, flags);
+ tmp = mr32(GBL_CTL);
+
+ if (enable)
+ mw32(GBL_CTL, tmp | INT_EN);
+ else
+ mw32(GBL_CTL, tmp & ~INT_EN);
+ spin_unlock_irqrestore(&mvi->lock, flags);
+}
+
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
/* move to PCI layer or libata core? */
static int pci_go_64(struct pci_dev *pdev)
@@ -519,39 +843,38 @@ static int pci_go_64(struct pci_dev *pdev)
return rc;
}
-static void mvs_tag_clear(struct mvs_info *mvi, unsigned int tag)
+static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
{
- mvi->tags[tag / sizeof(unsigned long)] &=
- ~(1UL << (tag % sizeof(unsigned long)));
+ mvi->tag_in = (mvi->tag_in + 1) & (MVS_SLOTS - 1);
+ mvi->tags[mvi->tag_in] = tag;
}
-static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
+static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
{
- mvi->tags[tag / sizeof(unsigned long)] |=
- (1UL << (tag % sizeof(unsigned long)));
+ mvi->tag_out = (mvi->tag_out - 1) & (MVS_SLOTS - 1);
}
-static bool mvs_tag_test(struct mvs_info *mvi, unsigned int tag)
+static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
{
- return mvi->tags[tag / sizeof(unsigned long)] &
- (1UL << (tag % sizeof(unsigned long)));
+ if (mvi->tag_out != mvi->tag_in) {
+ *tag_out = mvi->tags[mvi->tag_out];
+ mvi->tag_out = (mvi->tag_out + 1) & (MVS_SLOTS - 1);
+ return 0;
+ }
+ return -EBUSY;
}
-static int mvs_tag_alloc(struct mvs_info *mvi, unsigned int *tag_out)
+static void mvs_tag_init(struct mvs_info *mvi)
{
- unsigned int i;
-
- for (i = 0; i < MVS_SLOTS; i++)
- if (!mvs_tag_test(mvi, i)) {
- mvs_tag_set(mvi, i);
- *tag_out = i;
- return 0;
- }
-
- return -EBUSY;
+ int i;
+ for (i = 0; i < MVS_SLOTS; ++i)
+ mvi->tags[i] = i;
+ mvi->tag_out = 0;
+ mvi->tag_in = MVS_SLOTS - 1;
}
-static int mvs_eep_read(void __iomem *regs, unsigned int addr, u32 *data)
+#ifndef MVS_DISABLE_NVRAM
+static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data)
{
int timeout = 1000;
@@ -573,10 +896,10 @@ static int mvs_eep_read(void __iomem *regs, unsigned int addr, u32 *data)
return -EBUSY;
}
-static int mvs_eep_read_buf(void __iomem *regs, unsigned int addr,
- void *buf, unsigned int buflen)
+static int mvs_eep_read_buf(void __iomem *regs, u32 addr,
+ void *buf, u32 buflen)
{
- unsigned int addr_end, tmp_addr, i, j;
+ u32 addr_end, tmp_addr, i, j;
u32 tmp = 0;
int rc;
u8 *tmp8, *buf8 = buf;
@@ -592,7 +915,7 @@ static int mvs_eep_read_buf(void __iomem *regs, unsigned int addr,
if (rc)
return rc;
- tmp8 = (u8 *) &tmp;
+ tmp8 = (u8 *)&tmp;
for (i = j; i < 4; i++)
*buf8++ = tmp8[i];
@@ -613,7 +936,7 @@ static int mvs_eep_read_buf(void __iomem *regs, unsigned int addr,
if (rc)
return rc;
- tmp8 = (u8 *) &tmp;
+ tmp8 = (u8 *)&tmp;
j = addr_end - tmp_addr;
for (i = 0; i < j; i++)
*buf8++ = tmp8[i];
@@ -623,13 +946,15 @@ static int mvs_eep_read_buf(void __iomem *regs, unsigned int addr,
return 0;
}
+#endif
-static int mvs_nvram_read(struct mvs_info *mvi, unsigned int addr,
- void *buf, unsigned int buflen)
+static int mvs_nvram_read(struct mvs_info *mvi, u32 addr,
+ void *buf, u32 buflen)
{
+#ifndef MVS_DISABLE_NVRAM
void __iomem *regs = mvi->regs;
int rc, i;
- unsigned int sum;
+ u32 sum;
u8 hdr[2], *tmp;
const char *msg;
@@ -644,16 +969,17 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned int addr,
goto err_out;
}
- if (hdr[0] != 0x5A) { /* entry id */
+ if (hdr[0] != 0x5A) {
+ /* entry id */
msg = "invalid nvram entry id";
rc = -ENOENT;
goto err_out;
}
tmp = buf;
- sum = ((unsigned int)hdr[0]) + ((unsigned int)hdr[1]);
+ sum = ((u32)hdr[0]) + ((u32)hdr[1]);
for (i = 0; i < buflen; i++)
- sum += ((unsigned int)tmp[i]);
+ sum += ((u32)tmp[i]);
if (sum) {
msg = "nvram checksum failure";
@@ -666,11 +992,55 @@ static int mvs_nvram_read(struct mvs_info *mvi, unsigned int addr,
err_out:
dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg);
return rc;
+#else
+ /* FIXME , For SAS target mode */
+ memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8);
+ return 0;
+#endif
+}
+
+static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
+{
+ /* give the phy enabling interrupt event time to come in (1s
+ * is empirically about all it takes) */
+ if (time < HZ)
+ return 0;
+ /* Wait for discovery to finish */
+ scsi_flush_work(shost);
+ return 1;
+}
+
+static void mvs_scan_start(struct Scsi_Host *shost)
+{
+ int i;
+ struct sas_identify_frame *id;
+ struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
+
+ for (i = 0; i < mvi->chip->n_phy; ++i) {
+ struct mvs_phy *phy = &mvi->phy[i];
+ id = (struct sas_identify_frame *)phy->frame_rcvd;
+ if (phy->type & PORT_TYPE_SAS) {
+ id->dev_type = phy->identify.device_type;
+ id->initiator_bits = SAS_PROTOCOL_ALL;
+ id->target_bits = phy->identify.target_port_protocols;
+ } else if (phy->type & PORT_TYPE_SATA) {
+ }
+ mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
+ mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
+ PORTE_BYTES_DMAED);
+ }
+
}
static void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events)
{
- /* FIXME */
+ struct pci_dev *pdev = mvi->pdev;
+ /*
+ * events is port event now ,
+ * we need check the interrupt status which belongs to per port.
+ */
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Port0 = %d", mvs_read_port_irq_stat(mvi, 0));
}
static void mvs_int_sata(struct mvs_info *mvi)
@@ -679,11 +1049,12 @@ static void mvs_int_sata(struct mvs_info *mvi)
}
static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
- struct mvs_slot_info *slot, unsigned int slot_idx)
+ struct mvs_slot_info *slot, u32 slot_idx)
{
- if (slot->n_elem)
- pci_unmap_sg(mvi->pdev, task->scatter,
- slot->n_elem, task->data_dir);
+ if (!sas_protocol_ata(task->task_proto))
+ if (slot->n_elem)
+ pci_unmap_sg(mvi->pdev, task->scatter,
+ slot->n_elem, task->data_dir);
switch (task->task_proto) {
case SAS_PROTOCOL_SMP:
@@ -705,14 +1076,15 @@ static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
}
static void mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
- unsigned int slot_idx)
+ u32 slot_idx)
{
/* FIXME */
+ mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
}
-static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
+static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
{
- unsigned int slot_idx = rx_desc & RXQ_SLOT_MASK;
+ u32 slot_idx = rx_desc & RXQ_SLOT_MASK;
struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
struct sas_task *task = slot->task;
struct task_status_struct *tstat = &task->task_status;
@@ -722,19 +1094,19 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED;
if (!aborted) {
task->task_state_flags &=
- ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
+ ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
task->task_state_flags |= SAS_TASK_STATE_DONE;
}
spin_unlock(&task->task_state_lock);
if (aborted)
- return;
+ return -1;
memset(tstat, 0, sizeof(*tstat));
tstat->resp = SAS_TASK_COMPLETE;
/* error info record present */
- if (rx_desc & RXQ_ERR) {
+ if ((rx_desc & RXQ_ERR) && (*(u64 *) slot->response)) {
tstat->stat = SAM_CHECK_COND;
mvs_slot_err(mvi, task, slot_idx);
goto out;
@@ -743,13 +1115,14 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
switch (task->task_proto) {
case SAS_PROTOCOL_SSP:
/* hw says status == 0, datapres == 0 */
- if (rx_desc & RXQ_GOOD)
+ if (rx_desc & RXQ_GOOD) {
tstat->stat = SAM_GOOD;
-
+ tstat->resp = SAS_TASK_COMPLETE;
+ }
/* response frame present */
else if (rx_desc & RXQ_RSP) {
struct ssp_response_iu *iu =
- slot->response + sizeof(struct mvs_err_info);
+ slot->response + sizeof(struct mvs_err_info);
sas_ssp_task_response(&mvi->pdev->dev, task, iu);
}
@@ -763,15 +1136,26 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
break;
case SAS_PROTOCOL_SATA:
- case SAS_PROTOCOL_STP:
- if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) == RXQ_DONE)
- tstat->stat = SAM_GOOD;
- else
- tstat->stat = SAM_CHECK_COND;
- /* FIXME: read taskfile data from SATA register set
- * associated with SATA target
- */
- break;
+ case SAS_PROTOCOL_STP: {
+ struct ata_task_resp *resp =
+ (struct ata_task_resp *)tstat->buf;
+ struct domain_device *dev = task->dev;
+ struct mvs_port *port =
+ (struct mvs_port *)dev->port->lldd_port;
+
+ if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) ==
+ RXQ_DONE)
+ tstat->stat = SAM_GOOD;
+ else
+ tstat->stat = SAM_CHECK_COND;
+
+ resp->frame_len = sizeof(struct dev_to_host_fis);
+ memcpy(&resp->ending_fis[0],
+ SATA_RECEIVED_D2H_FIS(port->taskfileset),
+ sizeof(struct dev_to_host_fis));
+ /*mvs_hexdump(16,resp->ending_fis,0);*/
+ break;
+ }
default:
tstat->stat = SAM_CHECK_COND;
@@ -781,6 +1165,7 @@ static void mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
out:
mvs_slot_free(mvi, task, slot, slot_idx);
task->task_done(task);
+ return tstat->stat;
}
static void mvs_int_full(struct mvs_info *mvi)
@@ -791,6 +1176,8 @@ static void mvs_int_full(struct mvs_info *mvi)
stat = mr32(INT_STAT);
+ mvs_int_rx(mvi, false);
+
for (i = 0; i < MVS_MAX_PORTS; i++) {
tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED);
if (tmp)
@@ -800,48 +1187,60 @@ static void mvs_int_full(struct mvs_info *mvi)
if (stat & CINT_SRS)
mvs_int_sata(mvi);
- if (stat & (CINT_CI_STOP | CINT_DONE))
- mvs_int_rx(mvi, false);
-
mw32(INT_STAT, stat);
}
-static void mvs_int_rx(struct mvs_info *mvi, bool self_clear)
+static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
{
+ void __iomem *regs = mvi->regs;
u32 rx_prod_idx, rx_desc;
bool attn = false;
+ struct pci_dev *pdev = mvi->pdev;
/* the first dword in the RX ring is special: it contains
* a mirror of the hardware's RX producer index, so that
* we don't have to stall the CPU reading that register.
* The actual RX ring is offset by one dword, due to this.
*/
- rx_prod_idx = le32_to_cpu(mvi->rx[0]) & 0xfff;
+ rx_prod_idx = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK;
if (rx_prod_idx == 0xfff) { /* h/w hasn't touched RX ring yet */
mvi->rx_cons = 0xfff;
- return;
+ return 0;
}
+
+ /* The CMPL_Q may come late, read from register and try again
+ * note: if coalescing is enabled,
+ * it will need to read from register every time for sure
+ */
+ if (mvi->rx_cons == rx_prod_idx)
+ return 0;
+
if (mvi->rx_cons == 0xfff)
mvi->rx_cons = MVS_RX_RING_SZ - 1;
while (mvi->rx_cons != rx_prod_idx) {
+
/* increment our internal RX consumer pointer */
mvi->rx_cons = (mvi->rx_cons + 1) & (MVS_RX_RING_SZ - 1);
- /* Read RX descriptor at offset+1, due to above */
rx_desc = le32_to_cpu(mvi->rx[mvi->rx_cons + 1]);
- if (rx_desc & RXQ_DONE)
- /* we had a completion, error or no */
- mvs_slot_complete(mvi, rx_desc);
+ mvs_hba_cq_dump(mvi);
- if (rx_desc & RXQ_ATTN)
+ if (unlikely(rx_desc & RXQ_DONE))
+ mvs_slot_complete(mvi, rx_desc);
+ else if (rx_desc & RXQ_ATTN) {
attn = true;
+ dev_printk(KERN_DEBUG, &pdev->dev, "ATTN\n");
+ } else if (rx_desc & RXQ_ERR) {
+ dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR\n");
+ }
}
if (attn && self_clear)
mvs_int_full(mvi);
+ return 0;
}
static irqreturn_t mvs_interrupt(int irq, void *opaque)
@@ -851,6 +1250,10 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
u32 stat;
stat = mr32(GBL_INT_STAT);
+
+ /* clear CMD_CMPLT ASAP */
+ mw32_f(INT_STAT, CINT_DONE);
+
if (stat == 0 || stat == 0xffffffff)
return IRQ_NONE;
@@ -877,18 +1280,19 @@ static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
}
struct mvs_task_exec_info {
- struct sas_task *task;
- struct mvs_cmd_hdr *hdr;
- unsigned int tag;
- int n_elem;
+ struct sas_task *task;
+ struct mvs_cmd_hdr *hdr;
+ u32 tag;
+ int n_elem;
};
-static int mvs_task_prep_smp(struct mvs_info *mvi, struct mvs_task_exec_info *tei)
+static int mvs_task_prep_smp(struct mvs_info *mvi,
+ struct mvs_task_exec_info *tei)
{
int elem, rc;
struct mvs_cmd_hdr *hdr = tei->hdr;
struct scatterlist *sg_req, *sg_resp;
- unsigned int req_len, resp_len, tag = tei->tag;
+ u32 req_len, resp_len, tag = tei->tag;
/*
* DMA-map SMP request, response buffers
@@ -918,8 +1322,8 @@ static int mvs_task_prep_smp(struct mvs_info *mvi, struct mvs_task_exec_info *te
* Fill in TX ring and command slot header
*/
- mvi->tx[tag] = cpu_to_le32(
- (TXQ_CMD_SMP << TXQ_CMD_SHIFT) | TXQ_MODE_I | tag);
+ mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) |
+ TXQ_MODE_I | tag);
hdr->flags = 0;
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
@@ -941,6 +1345,65 @@ err_out:
return rc;
}
+static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp, offs;
+
+ if (port->taskfileset == MVS_ID_NOT_MAPPED)
+ return;
+
+ offs = 1U << ((port->taskfileset & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+ if (port->taskfileset < 16) {
+ tmp = mr32(PCS);
+ mw32(PCS, tmp | ~offs);
+ } else {
+ tmp = mr32(CTL);
+ mw32(CTL, tmp | ~offs);
+ }
+
+ port->taskfileset = MVS_ID_NOT_MAPPED;
+}
+
+static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
+{
+ int i;
+ u32 tmp, offs;
+ void __iomem *regs = mvi->regs;
+
+ if (port->taskfileset != MVS_ID_NOT_MAPPED)
+ return 0;
+
+ tmp = mr32(PCS);
+
+ for (i = 0; i < mvi->chip->srs_sz; i++) {
+ if (i == 16)
+ tmp = mr32(CTL);
+ offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+ if (!(tmp & offs)) {
+ port->taskfileset = i;
+
+ if (i < 16)
+ mw32(PCS, tmp | offs);
+ else
+ mw32(CTL, tmp | offs);
+ return 0;
+ }
+ }
+ return MVS_ID_NOT_MAPPED;
+}
+
+static u32 mvs_get_ncq_tag(struct sas_task *task)
+{
+ u32 tag = 0;
+ struct ata_queued_cmd *qc = task->uldd_task;
+
+ if (qc)
+ tag = qc->tag;
+
+ return tag;
+}
+
static int mvs_task_prep_ata(struct mvs_info *mvi,
struct mvs_task_exec_info *tei)
{
@@ -948,29 +1411,46 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
struct domain_device *dev = task->dev;
struct mvs_cmd_hdr *hdr = tei->hdr;
struct asd_sas_port *sas_port = dev->port;
- unsigned int tag = tei->tag;
- struct mvs_slot_info *slot = &mvi->slot_info[tag];
- u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
+ struct mvs_slot_info *slot;
struct scatterlist *sg;
struct mvs_prd *buf_prd;
+ struct mvs_port *port = (struct mvs_port *)sas_port->lldd_port;
+ u32 tag = tei->tag;
+ u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
void *buf_tmp;
u8 *buf_cmd, *buf_oaf;
dma_addr_t buf_tmp_dma;
- unsigned int i, req_len, resp_len;
+ u32 i, req_len, resp_len;
+ const u32 max_resp_len = SB_RFB_MAX;
+
+ if (mvs_assign_reg_set(mvi, port) == MVS_ID_NOT_MAPPED)
+ return -EBUSY;
+
+ slot = &mvi->slot_info[tag];
- /* FIXME: fill in SATA register set */
- mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag |
- (TXQ_CMD_STP << TXQ_CMD_SHIFT) |
- (sas_port->phy_mask << TXQ_PHY_SHIFT));
+ mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+ (TXQ_CMD_STP << TXQ_CMD_SHIFT) |
+ (sas_port->phy_mask << TXQ_PHY_SHIFT) |
+ (port->taskfileset << TXQ_SRS_SHIFT));
if (task->ata_task.use_ncq)
flags |= MCH_FPDMA;
- if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
- flags |= MCH_ATAPI;
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) {
+ if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI)
+ flags |= MCH_ATAPI;
+ }
+
/* FIXME: fill in port multiplier number */
hdr->flags = cpu_to_le32(flags);
- hdr->tags = cpu_to_le32(tag);
+
+ /* FIXME: the low order order 5 bits for the TAG if enable NCQ */
+ if (task->ata_task.use_ncq) {
+ hdr->tags = cpu_to_le32(mvs_get_ncq_tag(task));
+ /*Fill in task file */
+ task->ata_task.fis.sector_count = hdr->tags << 3;
+ } else
+ hdr->tags = cpu_to_le32(tag);
hdr->data_len = cpu_to_le32(task->total_xfer_len);
/*
@@ -978,9 +1458,8 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
*/
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
- /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ***************/
- buf_cmd =
- buf_tmp = slot->buf;
+ /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */
+ buf_cmd = buf_tmp = slot->buf;
buf_tmp_dma = slot->buf_dma;
hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
@@ -988,7 +1467,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
buf_tmp += MVS_ATA_CMD_SZ;
buf_tmp_dma += MVS_ATA_CMD_SZ;
- /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
+ /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
/* used for STP. unused for SATA? */
buf_oaf = buf_tmp;
hdr->open_frame = cpu_to_le64(buf_tmp_dma);
@@ -996,32 +1475,38 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
buf_tmp += MVS_OAF_SZ;
buf_tmp_dma += MVS_OAF_SZ;
- /* region 3: PRD table ***********************************************/
+ /* region 3: PRD table ********************************************** */
buf_prd = buf_tmp;
- hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ if (tei->n_elem)
+ hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ else
+ hdr->prd_tbl = 0;
i = sizeof(struct mvs_prd) * tei->n_elem;
buf_tmp += i;
buf_tmp_dma += i;
- /* region 4: status buffer (larger the PRD, smaller this buf) ********/
+ /* region 4: status buffer (larger the PRD, smaller this buf) ******* */
/* FIXME: probably unused, for SATA. kept here just in case
* we get a STP/SATA error information record
*/
slot->response = buf_tmp;
hdr->status_buf = cpu_to_le64(buf_tmp_dma);
- req_len = sizeof(struct ssp_frame_hdr) + 28;
+ req_len = sizeof(struct host_to_dev_fis);
resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ -
- sizeof(struct mvs_err_info) - i;
+ sizeof(struct mvs_err_info) - i;
/* request, response lengths */
+ resp_len = min(resp_len, max_resp_len);
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
+ task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */
/* fill in command FIS and ATAPI CDB */
- memcpy(buf_cmd, &task->ata_task.fis,
- sizeof(struct host_to_dev_fis));
- memcpy(buf_cmd + 0x40, task->ata_task.atapi_packet, 16);
+ memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis));
+ if (dev->sata_dev.command_set == ATAPI_COMMAND_SET)
+ memcpy(buf_cmd + STP_ATAPI_CMD,
+ task->ata_task.atapi_packet, 16);
/* fill in PRD (scatter/gather) table, if any */
sg = task->scatter;
@@ -1044,28 +1529,28 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
struct mvs_cmd_hdr *hdr = tei->hdr;
struct mvs_slot_info *slot;
struct scatterlist *sg;
- unsigned int resp_len, req_len, i, tag = tei->tag;
struct mvs_prd *buf_prd;
struct ssp_frame_hdr *ssp_hdr;
void *buf_tmp;
u8 *buf_cmd, *buf_oaf, fburst = 0;
dma_addr_t buf_tmp_dma;
u32 flags;
+ u32 resp_len, req_len, i, tag = tei->tag;
+ const u32 max_resp_len = SB_RFB_MAX;
slot = &mvi->slot_info[tag];
- mvi->tx[tag] = cpu_to_le32(TXQ_MODE_I | tag |
- (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
- (sas_port->phy_mask << TXQ_PHY_SHIFT));
-
+ mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
+ (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
+ (sas_port->phy_mask << TXQ_PHY_SHIFT));
flags = MCH_RETRY;
if (task->ssp_task.enable_first_burst) {
flags |= MCH_FBURST;
fburst = (1 << 7);
}
hdr->flags = cpu_to_le32(flags |
- (tei->n_elem << MCH_PRD_LEN_SHIFT) |
- (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
+ (tei->n_elem << MCH_PRD_LEN_SHIFT) |
+ (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT));
hdr->tags = cpu_to_le32(tag);
hdr->data_len = cpu_to_le32(task->total_xfer_len);
@@ -1075,9 +1560,8 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
*/
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
- /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***************/
- buf_cmd =
- buf_tmp = slot->buf;
+ /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */
+ buf_cmd = buf_tmp = slot->buf;
buf_tmp_dma = slot->buf_dma;
hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma);
@@ -1085,28 +1569,33 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
buf_tmp += MVS_SSP_CMD_SZ;
buf_tmp_dma += MVS_SSP_CMD_SZ;
- /* region 2: open address frame area (MVS_OAF_SZ bytes) **********/
+ /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */
buf_oaf = buf_tmp;
hdr->open_frame = cpu_to_le64(buf_tmp_dma);
buf_tmp += MVS_OAF_SZ;
buf_tmp_dma += MVS_OAF_SZ;
- /* region 3: PRD table ***********************************************/
+ /* region 3: PRD table ********************************************** */
buf_prd = buf_tmp;
- hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ if (tei->n_elem)
+ hdr->prd_tbl = cpu_to_le64(buf_tmp_dma);
+ else
+ hdr->prd_tbl = 0;
i = sizeof(struct mvs_prd) * tei->n_elem;
buf_tmp += i;
buf_tmp_dma += i;
- /* region 4: status buffer (larger the PRD, smaller this buf) ********/
+ /* region 4: status buffer (larger the PRD, smaller this buf) ******* */
slot->response = buf_tmp;
hdr->status_buf = cpu_to_le64(buf_tmp_dma);
- req_len = sizeof(struct ssp_frame_hdr) + 28;
resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ -
- sizeof(struct mvs_err_info) - i;
+ sizeof(struct mvs_err_info) - i;
+ resp_len = min(resp_len, max_resp_len);
+
+ req_len = sizeof(struct ssp_frame_hdr) + 28;
/* request, response lengths */
hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4));
@@ -1118,8 +1607,8 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
buf_oaf[3] = tag;
memcpy(buf_oaf + 4, task->dev->sas_addr, SAS_ADDR_SIZE);
- /* fill in SSP frame header */
- ssp_hdr = (struct ssp_frame_hdr *) buf_cmd;
+ /* fill in SSP frame header (Command Table.SSP frame header) */
+ ssp_hdr = (struct ssp_frame_hdr *)buf_cmd;
ssp_hdr->frame_type = SSP_COMMAND;
memcpy(ssp_hdr->hashed_dest_addr, task->dev->hashed_sas_addr,
HASHED_SAS_ADDR_SIZE);
@@ -1130,11 +1619,9 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
/* fill in command frame IU */
buf_cmd += sizeof(*ssp_hdr);
memcpy(buf_cmd, &task->ssp_task.LUN, 8);
- buf_cmd[9] = fburst |
- task->ssp_task.task_attr |
- (task->ssp_task.task_prio << 3);
+ buf_cmd[9] = fburst | task->ssp_task.task_attr |
+ (task->ssp_task.task_prio << 3);
memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16);
-
/* fill in PRD (scatter/gather) table, if any */
sg = task->scatter;
for (i = 0; i < tei->n_elem; i++) {
@@ -1151,76 +1638,138 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
{
struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
- unsigned int tag = 0xdeadbeef, rc, n_elem = 0;
+ struct pci_dev *pdev = mvi->pdev;
+ struct mvs_task_exec_info tei;
+ struct sas_task *t = task;
void __iomem *regs = mvi->regs;
+ u32 tag = 0xdeadbeef, rc, n_elem = 0;
unsigned long flags;
- struct mvs_task_exec_info tei;
+ u32 n = num, pass = 0;
- /* FIXME: STP/SATA support not complete yet */
- if (task->task_proto == SAS_PROTOCOL_SATA || task->task_proto == SAS_PROTOCOL_STP)
- return -SAS_DEV_NO_RESPONSE;
+ spin_lock_irqsave(&mvi->lock, flags);
- if (task->num_scatter) {
- n_elem = pci_map_sg(mvi->pdev, task->scatter,
- task->num_scatter, task->data_dir);
- if (!n_elem)
- return -ENOMEM;
- }
+ do {
+ if (!sas_protocol_ata(t->task_proto)) {
+ if (t->num_scatter) {
+ n_elem = pci_map_sg(mvi->pdev, t->scatter,
+ t->num_scatter,
+ t->data_dir);
+ if (!n_elem) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ }
+ } else {
+ n_elem = t->num_scatter;
+ }
- spin_lock_irqsave(&mvi->lock, flags);
+ rc = mvs_tag_alloc(mvi, &tag);
+ if (rc)
+ goto err_out;
- rc = mvs_tag_alloc(mvi, &tag);
- if (rc)
- goto err_out;
+ mvi->slot_info[tag].task = t;
+ mvi->slot_info[tag].n_elem = n_elem;
+ tei.task = t;
+ tei.hdr = &mvi->slot[tag];
+ tei.tag = tag;
+ tei.n_elem = n_elem;
- mvi->slot_info[tag].task = task;
- mvi->slot_info[tag].n_elem = n_elem;
- tei.task = task;
- tei.hdr = &mvi->slot[tag];
- tei.tag = tag;
- tei.n_elem = n_elem;
+ switch (t->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ rc = mvs_task_prep_smp(mvi, &tei);
+ break;
+ case SAS_PROTOCOL_SSP:
+ rc = mvs_task_prep_ssp(mvi, &tei);
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:
+ rc = mvs_task_prep_ata(mvi, &tei);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
- switch (task->task_proto) {
- case SAS_PROTOCOL_SMP:
- rc = mvs_task_prep_smp(mvi, &tei);
- break;
- case SAS_PROTOCOL_SSP:
- rc = mvs_task_prep_ssp(mvi, &tei);
- break;
- case SAS_PROTOCOL_SATA:
- case SAS_PROTOCOL_STP:
- rc = mvs_task_prep_ata(mvi, &tei);
- break;
- default:
- rc = -EINVAL;
- break;
- }
+ if (rc)
+ goto err_out_tag;
- if (rc)
- goto err_out_tag;
+ /* TODO: select normal or high priority */
- /* TODO: select normal or high priority */
+ spin_lock(&t->task_state_lock);
+ t->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock(&t->task_state_lock);
- mw32(RX_PROD_IDX, mvi->tx_prod);
+ if (n == 1) {
+ spin_unlock_irqrestore(&mvi->lock, flags);
+ mw32(TX_PROD_IDX, mvi->tx_prod);
+ }
+ mvs_hba_memory_dump(mvi, tag, t->task_proto);
- mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_TX_RING_SZ - 1);
+ ++pass;
+ mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1);
- spin_lock(&task->task_state_lock);
- task->task_state_flags |= SAS_TASK_AT_INITIATOR;
- spin_unlock(&task->task_state_lock);
+ if (n == 1)
+ break;
+
+ t = list_entry(t->list.next, struct sas_task, list);
+ } while (--n);
- spin_unlock_irqrestore(&mvi->lock, flags);
return 0;
err_out_tag:
- mvs_tag_clear(mvi, tag);
+ mvs_tag_free(mvi, tag);
err_out:
- if (n_elem)
- pci_unmap_sg(mvi->pdev, task->scatter, n_elem, task->data_dir);
+ dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", pass);
+ if (!sas_protocol_ata(t->task_proto))
+ if (n_elem)
+ pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
+ t->data_dir);
+ if (pass)
+ mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
spin_unlock_irqrestore(&mvi->lock, flags);
return rc;
}
+static int mvs_task_abort(struct sas_task *task)
+{
+ int rc = 1;
+ unsigned long flags;
+ struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
+ struct pci_dev *pdev = mvi->pdev;
+
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ if (task->task_state_flags & SAS_TASK_STATE_DONE) {
+ rc = TMF_RESP_FUNC_COMPLETE;
+ goto out_done;
+ }
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ /*FIXME*/
+ rc = TMF_RESP_FUNC_COMPLETE;
+ switch (task->task_proto) {
+ case SAS_PROTOCOL_SMP:
+ dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! ");
+ break;
+ case SAS_PROTOCOL_SSP:
+ dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! ");
+ break;
+ case SAS_PROTOCOL_SATA:
+ case SAS_PROTOCOL_STP:{
+ dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! "
+ "Dump D2H FIS: \n");
+ mvs_hexdump(sizeof(struct host_to_dev_fis),
+ (void *)&task->ata_task.fis, 0);
+ dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n");
+ mvs_hexdump(16, task->ata_task.atapi_packet, 0);
+ break;
+ }
+ default:
+ break;
+ }
+out_done:
+ return rc;
+}
+
static void mvs_free(struct mvs_info *mvi)
{
int i;
@@ -1238,7 +1787,7 @@ static void mvs_free(struct mvs_info *mvi)
if (mvi->tx)
dma_free_coherent(&mvi->pdev->dev,
- sizeof(*mvi->tx) * MVS_TX_RING_SZ,
+ sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
mvi->tx, mvi->tx_dma);
if (mvi->rx_fis)
dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ,
@@ -1249,10 +1798,12 @@ static void mvs_free(struct mvs_info *mvi)
mvi->rx, mvi->rx_dma);
if (mvi->slot)
dma_free_coherent(&mvi->pdev->dev,
- sizeof(*mvi->slot) * MVS_RX_RING_SZ,
+ sizeof(*mvi->slot) * MVS_SLOTS,
mvi->slot, mvi->slot_dma);
+#ifdef MVS_ENABLE_PERI
if (mvi->peri_regs)
iounmap(mvi->peri_regs);
+#endif
if (mvi->regs)
iounmap(mvi->regs);
if (mvi->shost)
@@ -1274,25 +1825,25 @@ static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
reg = mvi->regs + MVS_P0_SER_CTLSTAT + (phy_id * 4);
switch (func) {
- case PHY_FUNC_SET_LINK_RATE: {
- struct sas_phy_linkrates *rates = funcdata;
- u32 lrmin = 0, lrmax = 0;
+ case PHY_FUNC_SET_LINK_RATE:{
+ struct sas_phy_linkrates *rates = funcdata;
+ u32 lrmin = 0, lrmax = 0;
- lrmin = (rates->minimum_linkrate << 8);
- lrmax = (rates->maximum_linkrate << 12);
+ lrmin = (rates->minimum_linkrate << 8);
+ lrmax = (rates->maximum_linkrate << 12);
- tmp = readl(reg);
- if (lrmin) {
- tmp &= ~(0xf << 8);
- tmp |= lrmin;
- }
- if (lrmax) {
- tmp &= ~(0xf << 12);
- tmp |= lrmax;
+ tmp = readl(reg);
+ if (lrmin) {
+ tmp &= ~(0xf << 8);
+ tmp |= lrmin;
+ }
+ if (lrmax) {
+ tmp &= ~(0xf << 12);
+ tmp |= lrmax;
+ }
+ writel(tmp, reg);
+ break;
}
- writel(tmp, reg);
- break;
- }
case PHY_FUNC_HARD_RESET:
tmp = readl(reg);
@@ -1335,11 +1886,11 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id)
sas_phy->lldd_phy = phy;
}
-static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct mvs_info *mvi;
- unsigned long res_start, res_len;
+ unsigned long res_start, res_len, res_flag;
struct asd_sas_phy **arr_phy;
struct asd_sas_port **arr_port;
const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data];
@@ -1381,9 +1932,10 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas;
mvi->shost->transportt = mvs_stt;
- mvi->shost->max_id = ~0;
+ mvi->shost->max_id = 21;
mvi->shost->max_lun = ~0;
- mvi->shost->max_cmd_len = ~0;
+ mvi->shost->max_channel = 0;
+ mvi->shost->max_cmd_len = 16;
mvi->sas.sas_ha_name = DRV_NAME;
mvi->sas.dev = &pdev->dev;
@@ -1392,12 +1944,13 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
mvi->sas.sas_phy = arr_phy;
mvi->sas.sas_port = arr_port;
mvi->sas.num_phys = chip->n_phy;
- mvi->sas.lldd_max_execute_num = MVS_TX_RING_SZ - 1;/* FIXME: correct? */
- mvi->sas.lldd_queue_size = MVS_TX_RING_SZ - 1; /* FIXME: correct? */
+ mvi->sas.lldd_max_execute_num = MVS_CHIP_SLOT_SZ - 1;
+ mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE;
+ mvi->can_queue = (MVS_CHIP_SLOT_SZ >> 1) - 1;
mvi->sas.lldd_ha = mvi;
mvi->sas.core.shost = mvi->shost;
- mvs_tag_set(mvi, MVS_TX_RING_SZ - 1);
+ mvs_tag_init(mvi);
/*
* ioremap main and peripheral registers
@@ -1408,16 +1961,23 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
if (!res_start || !res_len)
goto err_out;
+#ifdef MVS_ENABLE_PERI
mvi->peri_regs = ioremap_nocache(res_start, res_len);
- if (!mvi->regs)
+ if (!mvi->peri_regs)
goto err_out;
+#endif
res_start = pci_resource_start(pdev, 4);
res_len = pci_resource_len(pdev, 4);
if (!res_start || !res_len)
goto err_out;
- mvi->regs = ioremap_nocache(res_start, res_len);
+ res_flag = pci_resource_flags(pdev, 4);
+ if (res_flag & IORESOURCE_CACHEABLE)
+ mvi->regs = ioremap(res_start, res_len);
+ else
+ mvi->regs = ioremap_nocache(res_start, res_len);
+
if (!mvi->regs)
goto err_out;
@@ -1426,14 +1986,14 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
*/
mvi->tx = dma_alloc_coherent(&pdev->dev,
- sizeof(*mvi->tx) * MVS_TX_RING_SZ,
+ sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ,
&mvi->tx_dma, GFP_KERNEL);
if (!mvi->tx)
goto err_out;
- memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_TX_RING_SZ);
+ memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ);
mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ,
- &mvi->rx_fis_dma, GFP_KERNEL);
+ &mvi->rx_fis_dma, GFP_KERNEL);
if (!mvi->rx_fis)
goto err_out;
memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ);
@@ -1459,7 +2019,7 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
struct mvs_slot_info *slot = &mvi->slot_info[i];
slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ,
- &slot->buf_dma, GFP_KERNEL);
+ &slot->buf_dma, GFP_KERNEL);
if (!slot->buf)
goto err_out;
memset(slot->buf, 0, MVS_SLOT_BUF_SZ);
@@ -1468,7 +2028,6 @@ static struct mvs_info * __devinit mvs_alloc(struct pci_dev *pdev,
/* finally, read NVRAM to get our SAS address */
if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8))
goto err_out;
-
return mvi;
err_out:
@@ -1488,26 +2047,89 @@ static void mvs_cw32(void __iomem *regs, u32 addr, u32 val)
mw32(CMD_DATA, val);
}
-#if 0
-static u32 mvs_phy_read(struct mvs_info *mvi, unsigned int phy_id, u32 addr)
+static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
{
void __iomem *regs = mvi->regs;
- void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8);
-
- writel(addr, phy_regs);
- return readl(phy_regs + 4);
+ return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4):
+ mr32(P4_SER_CTLSTAT + (port - 4) * 4);
}
-#endif
-static void mvs_phy_write(struct mvs_info *mvi, unsigned int phy_id,
- u32 addr, u32 val)
+static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
{
void __iomem *regs = mvi->regs;
- void __iomem *phy_regs = regs + MVS_P0_CFG_ADDR + (phy_id * 8);
+ if (port < 4)
+ mw32(P0_SER_CTLSTAT + port * 4, val);
+ else
+ mw32(P4_SER_CTLSTAT + (port - 4) * 4, val);
+}
- writel(addr, phy_regs);
- writel(val, phy_regs + 4);
- readl(phy_regs); /* flush */
+static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port)
+{
+ void __iomem *regs = mvi->regs + off;
+ void __iomem *regs2 = mvi->regs + off2;
+ return (port < 4)?readl(regs + port * 8):
+ readl(regs2 + (port - 4) * 8);
+}
+
+static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2,
+ u32 port, u32 val)
+{
+ void __iomem *regs = mvi->regs + off;
+ void __iomem *regs2 = mvi->regs + off2;
+ if (port < 4)
+ writel(val, regs + port * 8);
+ else
+ writel(val, regs2 + (port - 4) * 8);
+}
+
+static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port);
+}
+
+static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port, val);
+}
+
+static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr)
+{
+ mvs_write_port(mvi, MVS_P0_CFG_ADDR, MVS_P4_CFG_ADDR, port, addr);
+}
+
+static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port);
+}
+
+static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port, val);
+}
+
+static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr)
+{
+ mvs_write_port(mvi, MVS_P0_VSR_ADDR, MVS_P4_VSR_ADDR, port, addr);
+}
+
+static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port);
+}
+
+static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val);
+}
+
+static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
+{
+ return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port);
+}
+
+static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
+{
+ mvs_write_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port, val);
}
static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
@@ -1547,6 +2169,173 @@ static void __devinit mvs_phy_hacks(struct mvs_info *mvi)
tmp &= 0x1fffffff;
tmp |= (2U << 29); /* 8 ms retry */
mvs_cw32(regs, CMD_PHY_TIMER, tmp);
+
+ /* TEST - for phy decoding error, adjust voltage levels */
+ mw32(P0_VSR_ADDR + 0, 0x8);
+ mw32(P0_VSR_DATA + 0, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 8, 0x8);
+ mw32(P0_VSR_DATA + 8, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 16, 0x8);
+ mw32(P0_VSR_DATA + 16, 0x2F0);
+
+ mw32(P0_VSR_ADDR + 24, 0x8);
+ mw32(P0_VSR_DATA + 24, 0x2F0);
+
+}
+
+static void mvs_enable_xmt(struct mvs_info *mvi, int PhyId)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ tmp = mr32(PCS);
+ if (mvi->chip->n_phy <= 4)
+ tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT);
+ else
+ tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2);
+ mw32(PCS, tmp);
+}
+
+static void mvs_detect_porttype(struct mvs_info *mvi, int i)
+{
+ void __iomem *regs = mvi->regs;
+ u32 reg;
+ struct mvs_phy *phy = &mvi->phy[i];
+
+ /* enable auto port detection */
+ mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
+ msleep(100);
+
+ /* TODO check & save device type */
+ reg = mr32(GBL_PORT_TYPE);
+
+ if (reg & MODE_SAS_SATA & (1 << i)) {
+ phy->type = PORT_TYPE_SAS;
+ phy->identify.target_port_protocols = SAS_PROTOCOL_SSP;
+ } else {
+ phy->type = PORT_TYPE_SATA;
+ phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
+ }
+
+}
+
+static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
+{
+ u32 *s = (u32 *) buf;
+
+ if (!s)
+ return NULL;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3);
+ s[3] = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2);
+ s[2] = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1);
+ s[1] = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
+ s[0] = mvs_read_port_cfg_data(mvi, i);
+
+ return (void *)s;
+}
+
+static u32 mvs_is_sig_fis_received(struct mvs_info *mvi, int i)
+{
+ u32 tmp;
+
+ tmp = mvs_read_port_irq_stat(mvi, i) & PHYEV_SIG_FIS;
+ if (tmp)
+ mvs_write_port_irq_stat(mvi, i, PHYEV_SIG_FIS);
+
+ return tmp;
+}
+
+static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
+{
+ struct mvs_phy *phy = &mvi->phy[i];
+ u32 tmp;
+ __le64 tmp64;
+ struct pci_dev *pdev = mvi->pdev;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
+ phy->dev_info = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
+ phy->dev_sas_addr = (__le64) mvs_read_port_cfg_data(mvi, i) << 32;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
+ phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); /* le */
+
+ phy->phy_status = mvs_read_phy_ctl(mvi, i);
+
+ /* FIXME Update Wide Port info */
+ phy->port = &mvi->port[i];
+ phy->port->sas_port.lldd_port = phy->port;
+ phy->port->taskfileset = MVS_ID_NOT_MAPPED;
+
+ if (phy->phy_status & PHY_READY_MASK) {
+ u32 phy_st;
+ struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
+ phy_st = mvs_read_port_cfg_data(mvi, i);
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
+ phy->att_dev_sas_addr =
+ (__le64) mvs_read_port_cfg_data(mvi, i) << 32;
+
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
+ phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
+
+ /*Updated attached_sas_addr */
+ tmp64 = phy->att_dev_sas_addr;
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "phy[%d] Get Attached Address 0x%llX ,"
+ " SAS Address 0x%llX\n",
+ i, tmp64, phy->dev_sas_addr);
+ tmp64 = cpu_to_be64(tmp64);
+ memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
+
+ if (phy->type & PORT_TYPE_SAS) {
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
+ phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
+ phy->identify.device_type =
+ phy->att_dev_info & PORT_DEV_TYPE_MASK;
+
+ sas_phy->linkrate =
+ (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+ if (phy_st & PHY_OOB_DTCTD)
+ sas_phy->oob_mode = SAS_OOB_MODE;
+ phy->frame_rcvd_size =
+ sizeof(struct sas_identify_frame);
+ } else if (phy->type & PORT_TYPE_SATA) {
+ if (mvs_is_sig_fis_received(mvi, i)) {
+ if (phy_st & PHY_OOB_DTCTD)
+ sas_phy->oob_mode = SATA_OOB_MODE;
+ phy->frame_rcvd_size =
+ sizeof(struct dev_to_host_fis);
+ mvs_get_d2h_reg(mvi, i,
+ (void *)sas_phy->frame_rcvd);
+ }
+ }
+ /* workaround for HW phy decoding error on 1.5g disk drive */
+ mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6);
+ tmp = mvs_read_port_vsr_data(mvi, i);
+ if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) ==
+ SAS_LINK_RATE_1_5_GBPS)
+ tmp &= ~PHY_MODE6_DTL_SPEED;
+ else
+ tmp |= PHY_MODE6_DTL_SPEED;
+ mvs_write_port_vsr_data(mvi, i, tmp);
+
+ }
+ phy->irq_status = mvs_read_port_irq_stat(mvi, i);
}
static int __devinit mvs_hw_init(struct mvs_info *mvi)
@@ -1559,6 +2348,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32(GBL_CTL, 0);
tmp = mr32(GBL_CTL);
+ /* Reset Controller */
if (!(tmp & HBA_RST)) {
if (mvi->flags & MVF_PHY_PWR_FIX) {
pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
@@ -1576,7 +2366,6 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32_f(GBL_CTL, HBA_RST);
}
-
/* wait for reset to finish; timeout is just a guess */
i = 1000;
while (i-- > 0) {
@@ -1590,6 +2379,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
return -EBUSY;
}
+ /* Init Chip */
/* make sure RST is set; HBA_RST /should/ have done that for us */
cctl = mr32(CTL);
if (cctl & CCTL_RST)
@@ -1597,6 +2387,12 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
else
mw32_f(CTL, cctl | CCTL_RST);
+ /* write to device control _AND_ device status register? - A.C. */
+ pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp);
+ tmp &= ~PRD_REQ_MASK;
+ tmp |= PRD_REQ_SIZE;
+ pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp);
+
pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp);
tmp |= PCTL_PWR_ON;
tmp &= ~PCTL_OFF;
@@ -1609,6 +2405,9 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32_f(CTL, cctl);
+ /* reset control */
+ mw32(PCS, 0); /*MVS_PCS */
+
mvs_phy_hacks(mvi);
mw32(CMD_LIST_LO, mvi->slot_dma);
@@ -1617,7 +2416,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32(RX_FIS_LO, mvi->rx_fis_dma);
mw32(RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16);
- mw32(TX_CFG, MVS_TX_RING_SZ);
+ mw32(TX_CFG, MVS_CHIP_SLOT_SZ);
mw32(TX_LO, mvi->tx_dma);
mw32(TX_HI, (mvi->tx_dma >> 16) >> 16);
@@ -1628,42 +2427,82 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
/* init and reset phys */
for (i = 0; i < mvi->chip->n_phy; i++) {
/* FIXME: is this the correct dword order? */
- u32 lo = *((u32 *) &mvi->sas_addr[0]);
- u32 hi = *((u32 *) &mvi->sas_addr[4]);
+ u32 lo = *((u32 *)&mvi->sas_addr[0]);
+ u32 hi = *((u32 *)&mvi->sas_addr[4]);
+
+ mvs_detect_porttype(mvi, i);
/* set phy local SAS address */
- mvs_phy_write(mvi, i, PHYR_ADDR_LO, lo);
- mvs_phy_write(mvi, i, PHYR_ADDR_HI, hi);
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
+ mvs_write_port_cfg_data(mvi, i, lo);
+ mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
+ mvs_write_port_cfg_data(mvi, i, hi);
/* reset phy */
- tmp = readl(regs + MVS_P0_SER_CTLSTAT + (i * 4));
+ tmp = mvs_read_phy_ctl(mvi, i);
tmp |= PHY_RST;
- writel(tmp, regs + MVS_P0_SER_CTLSTAT + (i * 4));
+ mvs_write_phy_ctl(mvi, i, tmp);
}
msleep(100);
for (i = 0; i < mvi->chip->n_phy; i++) {
+ /* clear phy int status */
+ tmp = mvs_read_port_irq_stat(mvi, i);
+ tmp &= ~PHYEV_SIG_FIS;
+ mvs_write_port_irq_stat(mvi, i, tmp);
+
/* set phy int mask */
- writel(PHYEV_BROAD_CH | PHYEV_RDY_CH,
- regs + MVS_P0_INT_MASK + (i * 8));
+ tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS;
+ mvs_write_port_irq_mask(mvi, i, tmp);
- /* clear phy int status */
- tmp = readl(regs + MVS_P0_INT_STAT + (i * 8));
- writel(tmp, regs + MVS_P0_INT_STAT + (i * 8));
+ mvs_update_phyinfo(mvi, i);
+ mvs_enable_xmt(mvi, i);
}
/* FIXME: update wide port bitmaps */
+ /* little endian for open address and command table, etc. */
+ /* A.C.
+ * it seems that ( from the spec ) turning on big-endian won't
+ * do us any good on big-endian machines, need further confirmation
+ */
+ cctl = mr32(CTL);
+ cctl |= CCTL_ENDIAN_CMD;
+ cctl |= CCTL_ENDIAN_DATA;
+ cctl &= ~CCTL_ENDIAN_OPEN;
+ cctl |= CCTL_ENDIAN_RSP;
+ mw32_f(CTL, cctl);
+
+ /* reset CMD queue */
+ tmp = mr32(PCS);
+ tmp |= PCS_CMD_RST;
+ mw32(PCS, tmp);
+ /* interrupt coalescing may cause missing HW interrput in some case,
+ * and the max count is 0x1ff, while our max slot is 0x200,
+ * it will make count 0.
+ */
+ tmp = 0;
+ mw32(INT_COAL, tmp);
+
+ tmp = 0x100;
+ mw32(INT_COAL_TMOUT, tmp);
+
/* ladies and gentlemen, start your engines */
- mw32(TX_CFG, MVS_TX_RING_SZ | TX_EN);
+ mw32(TX_CFG, 0);
+ mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
+ /* enable CMD/CMPL_Q/RESP mode */
mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN |
((mvi->flags & MVF_MSI) ? PCS_SELF_CLEAR : 0));
/* re-enable interrupts globally */
mw32(GBL_CTL, INT_EN);
+ /* enable completion queue interrupt */
+ tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM);
+ mw32(INT_MASK, tmp);
+
return 0;
}
@@ -1680,7 +2519,7 @@ static void __devinit mvs_print_info(struct mvs_info *mvi)
}
static int __devinit mvs_pci_init(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+ const struct pci_device_id *ent)
{
int rc;
struct mvs_info *mvi;
@@ -1732,6 +2571,7 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
mvs_print_info(mvi);
scsi_scan_host(mvi->shost);
+
return 0;
err_out_shost:
@@ -1771,6 +2611,7 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
static struct sas_domain_function_template mvs_transport_ops = {
.lldd_execute_task = mvs_task_exec,
.lldd_control_phy = mvs_phy_control,
+ .lldd_abort_task = mvs_task_abort,
};
static struct pci_device_id __devinitdata mvs_pci_table[] = {
@@ -1822,4 +2663,3 @@ MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver");
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, mvs_pci_table);
-
--
1.5.4.rc4
On Fri, Jan 25, 2008 at 04:39:29PM -0600, James Bottomley wrote:
> On Sat, 2008-01-26 at 00:43 +0800, Ke Wei wrote:
>
> > struct mvs_phy {
> > struct mvs_port *port;
> > struct asd_sas_phy sas_phy;
> > + struct sas_identify identify;
> > + __le32 dev_info;
> > + __le64 dev_sas_addr;
> > + __le32 att_dev_info;
> > + __le64 att_dev_sas_addr;
> > + u32 type;
> > + __le32 phy_status;
> > + __le32 irq_status;
> > + u8 wide_port_phymap;
> > + u32 frame_rcvd_size;
> > + u8 frame_rcvd[32];
> >
> > - u8 frame_rcvd[24 + 1024];
> > };
>
> These __le quantites don't look right ... they're all read in by readl,
> which will convert little endian to CPU anyway.
>
>
> > @@ -437,27 +586,55 @@ struct mvs_info {
> > dma_addr_t rx_dma;
> > u32 rx_cons; /* RX consumer idx */
> >
> > - __le32 *rx_fis; /* RX'd FIS area */
> > + void *rx_fis; /* RX'd FIS area */
>
> Now the received FIS, on the other hand, provided you're storing it in
> wire format (which you look to be) *is* little endian data by definition
> in the ATA spec.
>
>
> > -static void mvs_tag_clear(struct mvs_info *mvi, unsigned int tag)
> > +static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
> > {
> > - mvi->tags[tag / sizeof(unsigned long)] &=
> > - ~(1UL << (tag % sizeof(unsigned long)));
> > + mvi->tag_in = (mvi->tag_in + 1) & (MVS_SLOTS - 1);
> > + mvi->tags[mvi->tag_in] = tag;
> > }
> >
> > -static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
> > +static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
> > {
> > - mvi->tags[tag / sizeof(unsigned long)] |=
> > - (1UL << (tag % sizeof(unsigned long)));
> > + mvi->tag_out = (mvi->tag_out - 1) & (MVS_SLOTS - 1);
> > }
> >
> > -static bool mvs_tag_test(struct mvs_info *mvi, unsigned int tag)
> > +static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
> > {
> > - return mvi->tags[tag / sizeof(unsigned long)] &
> > - (1UL << (tag % sizeof(unsigned long)));
> > + if (mvi->tag_out != mvi->tag_in) {
> > + *tag_out = mvi->tags[mvi->tag_out];
> > + mvi->tag_out = (mvi->tag_out + 1) & (MVS_SLOTS - 1);
> > + return 0;
> > + }
> > + return -EBUSY;
>
> I really don't think you should be doing this. That single ring governs
> all the potential tag slots for everything in this device. If you do a
> simple head tail allocation, what can happen is that you get a slow tag
> (attached to a format command, or a tape command) and then the ring head
> will hit the slow tag and the entire device will halt. I think you need
> a bitmap based allocation algorithm to ensure that if you have a free
> tag anywhere, you'll use it.
>
> If you look at the aic94xx index functions in aic94xx_hwi.h you'll see
> asd_tc_index_get() and asd_tc_index_release() doing exactly what you
> want with the native linux bitmap functions (the aic also uses a single
> issue queue with indexes into it).
>
> James
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-25 22:39 ` James Bottomley
2008-01-27 15:10 ` Ke Wei
@ 2008-01-27 15:27 ` Ke Wei
2008-01-27 18:13 ` James Bottomley
1 sibling, 1 reply; 22+ messages in thread
From: Ke Wei @ 2008-01-27 15:27 UTC (permalink / raw)
To: James Bottomley; +Cc: linux-scsi, kewei.mv, jeff, qswang, jfeng, qzhao, kewei
mvsas : Fixed coding problem
Signed-off-by: Ke Wei <kewei@marvell.com>
---
drivers/scsi/mvsas.c | 61 +++++++++++++++++++++++++++----------------------
1 files changed, 34 insertions(+), 27 deletions(-)
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
index 321be21..3bf009b 100755
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -55,11 +55,11 @@
/* offset for D2H FIS in the Received FIS List Structure */
#define SATA_RECEIVED_D2H_FIS(reg_set) \
- (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
+ ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
#define SATA_RECEIVED_PIO_FIS(reg_set) \
- (mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
+ ((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
#define UNASSOC_D2H_FIS(id) \
- (mvi->rx_fis + 0x100 * id)
+ ((void *) mvi->rx_fis + 0x100 * id)
/* driver compile-time configuration */
enum driver_configuration {
@@ -553,17 +553,16 @@ struct mvs_phy {
struct mvs_port *port;
struct asd_sas_phy sas_phy;
struct sas_identify identify;
- __le32 dev_info;
- __le64 dev_sas_addr;
- __le32 att_dev_info;
- __le64 att_dev_sas_addr;
+ u64 dev_sas_addr;
+ u64 att_dev_sas_addr;
+ u32 att_dev_info;
+ u32 dev_info;
u32 type;
- __le32 phy_status;
- __le32 irq_status;
- u8 wide_port_phymap;
+ u32 phy_status;
+ u32 irq_status;
u32 frame_rcvd_size;
u8 frame_rcvd[32];
-
+ u8 wide_port_phymap;
};
struct mvs_info {
@@ -586,7 +585,7 @@ struct mvs_info {
dma_addr_t rx_dma;
u32 rx_cons; /* RX consumer idx */
- void *rx_fis; /* RX'd FIS area */
+ __le32 *rx_fis; /* RX'd FIS area */
dma_addr_t rx_fis_dma;
struct mvs_cmd_hdr *slot; /* DMA command header slots */
@@ -624,7 +623,6 @@ static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val);
static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr);
static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port);
static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val);
-static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port);
static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val);
static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
@@ -705,8 +703,7 @@ static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
else
len_ct = MVS_SSP_CMD_SZ;
- offset =
- len_ct + MVS_OAF_SZ +
+ offset = len_ct + MVS_OAF_SZ +
sizeof(struct mvs_prd) * mvi->slot_info[tag].n_elem;
dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer :\n");
mvs_hexdump(32, (u8 *) mvi->slot_info[tag].response,
@@ -792,21 +789,27 @@ static void mvs_hba_cq_dump(struct mvs_info *mvi)
#endif
}
-static void mvs_hba_interrupt_enable(struct mvs_info *mvi, int enable)
+#if 0
+static void mvs_hba_interrupt_enable(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
u32 tmp;
- unsigned long flags;
- spin_lock_irqsave(&mvi->lock, flags);
tmp = mr32(GBL_CTL);
- if (enable)
- mw32(GBL_CTL, tmp | INT_EN);
- else
- mw32(GBL_CTL, tmp & ~INT_EN);
- spin_unlock_irqrestore(&mvi->lock, flags);
+ mw32(GBL_CTL, tmp | INT_EN);
+}
+
+static void mvs_hba_interrupt_disable(struct mvs_info *mvi)
+{
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ tmp = mr32(GBL_CTL);
+
+ mw32(GBL_CTL, tmp & ~INT_EN);
}
+#endif
static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
@@ -1345,6 +1348,7 @@ err_out:
return rc;
}
+#if 0
static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
{
void __iomem *regs = mvi->regs;
@@ -1364,6 +1368,7 @@ static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
port->taskfileset = MVS_ID_NOT_MAPPED;
}
+#endif
static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
{
@@ -2122,10 +2127,12 @@ static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val);
}
+#if 0
static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
{
return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port);
}
+#endif
static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
{
@@ -2258,17 +2265,17 @@ static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
{
struct mvs_phy *phy = &mvi->phy[i];
u32 tmp;
- __le64 tmp64;
+ u64 tmp64;
struct pci_dev *pdev = mvi->pdev;
mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
phy->dev_info = mvs_read_port_cfg_data(mvi, i);
mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_HI);
- phy->dev_sas_addr = (__le64) mvs_read_port_cfg_data(mvi, i) << 32;
+ phy->dev_sas_addr = (u64) mvs_read_port_cfg_data(mvi, i) << 32;
mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
- phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); /* le */
+ phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
phy->phy_status = mvs_read_phy_ctl(mvi, i);
@@ -2286,7 +2293,7 @@ static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
phy->att_dev_sas_addr =
- (__le64) mvs_read_port_cfg_data(mvi, i) << 32;
+ (u64) mvs_read_port_cfg_data(mvi, i) << 32;
mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
--
1.5.4.rc4
> I really don't think you should be doing this. That single ring governs
> all the potential tag slots for everything in this device. If you do a
> simple head tail allocation, what can happen is that you get a slow tag
> (attached to a format command, or a tape command) and then the ring head
> will hit the slow tag and the entire device will halt. I think you need
> a bitmap based allocation algorithm to ensure that if you have a free
> tag anywhere, you'll use it.
>
> If you look at the aic94xx index functions in aic94xx_hwi.h you'll see
> asd_tc_index_get() and asd_tc_index_release() doing exactly what you
> want with the native linux bitmap functions (the aic also uses a single
> issue queue with indexes into it).
I don't think we need to make use of a bitmap based allocation algorithm.
My algorithm is a simple non-blocking scheduling. Some faster tag may
be free in advance, so ring will alloc a tag number which has been
stored in mvi->tags array instead of waiting to hit the slow tag.
I think that the bitmap based allocation algorithm try to poll and find
the first zero bit. So process may be slow.
pls point out anything wrong.
On Fri, Jan 25, 2008 at 04:39:29PM -0600, James Bottomley wrote:
> On Sat, 2008-01-26 at 00:43 +0800, Ke Wei wrote:
>
> > struct mvs_phy {
> > struct mvs_port *port;
> > struct asd_sas_phy sas_phy;
> > + struct sas_identify identify;
> > + __le32 dev_info;
> > + __le64 dev_sas_addr;
> > + __le32 att_dev_info;
> > + __le64 att_dev_sas_addr;
> > + u32 type;
> > + __le32 phy_status;
> > + __le32 irq_status;
> > + u8 wide_port_phymap;
> > + u32 frame_rcvd_size;
> > + u8 frame_rcvd[32];
> >
> > - u8 frame_rcvd[24 + 1024];
> > };
>
> These __le quantites don't look right ... they're all read in by readl,
> which will convert little endian to CPU anyway.
>
>
> > @@ -437,27 +586,55 @@ struct mvs_info {
> > dma_addr_t rx_dma;
> > u32 rx_cons; /* RX consumer idx */
> >
> > - __le32 *rx_fis; /* RX'd FIS area */
> > + void *rx_fis; /* RX'd FIS area */
>
> Now the received FIS, on the other hand, provided you're storing it in
> wire format (which you look to be) *is* little endian data by definition
> in the ATA spec.
>
>
> > -static void mvs_tag_clear(struct mvs_info *mvi, unsigned int tag)
> > +static void mvs_tag_clear(struct mvs_info *mvi, u32 tag)
> > {
> > - mvi->tags[tag / sizeof(unsigned long)] &=
> > - ~(1UL << (tag % sizeof(unsigned long)));
> > + mvi->tag_in = (mvi->tag_in + 1) & (MVS_SLOTS - 1);
> > + mvi->tags[mvi->tag_in] = tag;
> > }
> >
> > -static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag)
> > +static void mvs_tag_free(struct mvs_info *mvi, u32 tag)
> > {
> > - mvi->tags[tag / sizeof(unsigned long)] |=
> > - (1UL << (tag % sizeof(unsigned long)));
> > + mvi->tag_out = (mvi->tag_out - 1) & (MVS_SLOTS - 1);
> > }
> >
> > -static bool mvs_tag_test(struct mvs_info *mvi, unsigned int tag)
> > +static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out)
> > {
> > - return mvi->tags[tag / sizeof(unsigned long)] &
> > - (1UL << (tag % sizeof(unsigned long)));
> > + if (mvi->tag_out != mvi->tag_in) {
> > + *tag_out = mvi->tags[mvi->tag_out];
> > + mvi->tag_out = (mvi->tag_out + 1) & (MVS_SLOTS - 1);
> > + return 0;
> > + }
> > + return -EBUSY;
>
> I really don't think you should be doing this. That single ring governs
> all the potential tag slots for everything in this device. If you do a
> simple head tail allocation, what can happen is that you get a slow tag
> (attached to a format command, or a tape command) and then the ring head
> will hit the slow tag and the entire device will halt. I think you need
> a bitmap based allocation algorithm to ensure that if you have a free
> tag anywhere, you'll use it.
>
> If you look at the aic94xx index functions in aic94xx_hwi.h you'll see
> asd_tc_index_get() and asd_tc_index_release() doing exactly what you
> want with the native linux bitmap functions (the aic also uses a single
> issue queue with indexes into it).
>
> James
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-27 15:27 ` Ke Wei
@ 2008-01-27 18:13 ` James Bottomley
2008-02-05 13:19 ` Ke Wei
0 siblings, 1 reply; 22+ messages in thread
From: James Bottomley @ 2008-01-27 18:13 UTC (permalink / raw)
To: Ke Wei; +Cc: linux-scsi, jeff, qswang, jfeng, qzhao, kewei
On Sun, 2008-01-27 at 23:27 +0800, Ke Wei wrote:
> > I really don't think you should be doing this. That single ring governs
> > all the potential tag slots for everything in this device. If you do a
> > simple head tail allocation, what can happen is that you get a slow tag
> > (attached to a format command, or a tape command) and then the ring head
> > will hit the slow tag and the entire device will halt. I think you need
> > a bitmap based allocation algorithm to ensure that if you have a free
> > tag anywhere, you'll use it.
> >
> > If you look at the aic94xx index functions in aic94xx_hwi.h you'll see
> > asd_tc_index_get() and asd_tc_index_release() doing exactly what you
> > want with the native linux bitmap functions (the aic also uses a single
> > issue queue with indexes into it).
>
> I don't think we need to make use of a bitmap based allocation
> algorithm.
> My algorithm is a simple non-blocking scheduling. Some faster tag may
> be free in advance, so ring will alloc a tag number which has been
> stored in mvi->tags array instead of waiting to hit the slow tag.
Ah, sorry I didn't see you were actually shuffling entries in the tag
array ...
> I think that the bitmap based allocation algorithm try to poll and
> find
> the first zero bit. So process may be slow.
>
> pls point out anything wrong.
I think you'll find a bitmap based algorithm can be much faster. The
linux bitmap routines are optimally coded on most architectures (large
numbers actually have a find bit in word/long word instruction). Even
for a nearly full bitmap, a 512bit array can find the free tag in at
most sixteen machine instructions; if the array is sparse, it can do it
in about two. Plus a bitmap based scheme has the advantage of tending
to allocate hot tags, thus usually keeping reasonable hot cache reuse.
A ring based algorithm will effectively do levelling to ensure that
every tag is used just about equally, which actually promotes pessimal
hot cache reuse.
Whether cache locality actually matters to the driver is something I
can't actually determine, so I'll leave it up to you to decide.
James
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-01-27 18:13 ` James Bottomley
@ 2008-02-05 13:19 ` Ke Wei
2008-02-05 21:00 ` Luben Tuikov
2008-02-07 0:33 ` Jeff Garzik
0 siblings, 2 replies; 22+ messages in thread
From: Ke Wei @ 2008-02-05 13:19 UTC (permalink / raw)
To: James Bottomley; +Cc: Ke Wei, linux-scsi, jeff, qswang, jfeng, qzhao, kewei
Added support for hotplug and wide port.
Signed-off-by: Ke Wei <kewei@marvell.com>
---
drivers/scsi/mvsas.c | 445 ++++++++++++++++++++++++++++++++++++++------------
1 files changed, 339 insertions(+), 106 deletions(-)
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
index 3bf009b..e5cf3ad 100755
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -26,6 +26,12 @@
structures. this permits elimination of all the le32_to_cpu()
and cpu_to_le32() conversions.
+ Changelog:
+ 2008-02-05 0.4 Added support for hotplug and wide port.
+ 2008-01-22 0.3 Added support for SAS HD and SATA Devices.
+ 2008-01-09 0.2 detect SAS disk.
+ 2007-09-95 0.1 rough draft, Initial version.
+
*/
#include <linux/kernel.h>
@@ -39,13 +45,13 @@
#include <asm/io.h>
#define DRV_NAME "mvsas"
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.4"
#define _MV_DUMP 0
#define MVS_DISABLE_NVRAM
#define mr32(reg) readl(regs + MVS_##reg)
#define mw32(reg,val) writel((val), regs + MVS_##reg)
-#define mw32_f(reg,val) do { \
+#define mw32_f(reg,val) do { \
writel((val), regs + MVS_##reg); \
readl(regs + MVS_##reg); \
} while (0)
@@ -54,13 +60,19 @@
#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
/* offset for D2H FIS in the Received FIS List Structure */
-#define SATA_RECEIVED_D2H_FIS(reg_set) \
+#define SATA_RECEIVED_D2H_FIS(reg_set) \
((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x40)
-#define SATA_RECEIVED_PIO_FIS(reg_set) \
+#define SATA_RECEIVED_PIO_FIS(reg_set) \
((void *) mvi->rx_fis + 0x400 + 0x100 * reg_set + 0x20)
-#define UNASSOC_D2H_FIS(id) \
+#define UNASSOC_D2H_FIS(id) \
((void *) mvi->rx_fis + 0x100 * id)
+#define for_each_phy(__lseq_mask, __mc, __lseq, __rest) \
+ for ((__mc) = (__lseq_mask), (__lseq) = 0; \
+ (__mc) != 0 && __rest; \
+ (++__lseq), (__mc) >>= 1) \
+ if (((__mc) & 1))
+
/* driver compile-time configuration */
enum driver_configuration {
MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */
@@ -130,6 +142,7 @@ enum hw_registers {
MVS_INT_STAT = 0x150, /* Central int status */
MVS_INT_MASK = 0x154, /* Central int enable */
MVS_INT_STAT_SRS = 0x158, /* SATA register set status */
+ MVS_INT_MASK_SRS = 0x15C,
/* ports 1-3 follow after this */
MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */
@@ -223,7 +236,7 @@ enum hw_register_bits {
/* shl for ports 1-3 */
CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */
- CINT_PORT = (1U << 8), /* port0 event */
+ CINT_PORT = (1U << 8), /* port0 event */
CINT_PORT_MASK_OFFSET = 8,
CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET),
@@ -300,6 +313,7 @@ enum hw_register_bits {
PHY_READY_MASK = (1U << 20),
/* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */
+ PHYEV_DEC_ERR = (1U << 24), /* Phy Decoding Error */
PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */
PHYEV_AN = (1U << 18), /* SATA async notification */
PHYEV_BIST_ACT = (1U << 17), /* BIST activate FIS */
@@ -501,6 +515,9 @@ enum status_buffer {
SB_RFB_MAX = 0x400, /* RFB size*/
};
+enum error_info_rec {
+ CMD_ISS_STPD = (1U << 31), /* Cmd Issue Stopped */
+};
struct mvs_chip_info {
u32 n_phy;
@@ -534,6 +551,7 @@ struct mvs_cmd_hdr {
struct mvs_slot_info {
struct sas_task *task;
u32 n_elem;
+ u32 tx;
/* DMA buffer for storing cmd tbl, open addr frame, status buffer,
* and PRD table
@@ -546,23 +564,28 @@ struct mvs_slot_info {
struct mvs_port {
struct asd_sas_port sas_port;
- u8 taskfileset;
+ u8 port_attached;
+ union {
+ u8 taskfileset;
+ u8 wide_port_phymap;
+ };
};
struct mvs_phy {
struct mvs_port *port;
struct asd_sas_phy sas_phy;
- struct sas_identify identify;
+ struct sas_identify identify;
+ struct scsi_device *sdev;
u64 dev_sas_addr;
u64 att_dev_sas_addr;
u32 att_dev_info;
u32 dev_info;
- u32 type;
+ u32 phy_type;
u32 phy_status;
u32 irq_status;
u32 frame_rcvd_size;
u8 frame_rcvd[32];
- u8 wide_port_phymap;
+ u8 phy_attached;
};
struct mvs_info {
@@ -610,6 +633,8 @@ struct mvs_queue_task {
void *uldd_task;
};
+static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
+ void *funcdata);
static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port);
static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val);
static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port);
@@ -624,9 +649,18 @@ static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr);
static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port);
static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val);
static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val);
+static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port);
+
+static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i);
+static void mvs_detect_porttype(struct mvs_info *mvi, int i);
+static void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
+static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port);
+static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port);
+static u32 mvs_is_sig_fis_received(u32 irq_status);
static int mvs_scan_finished(struct Scsi_Host *, unsigned long);
static void mvs_scan_start(struct Scsi_Host *);
+static int mvs_sas_slave_alloc(struct scsi_device *scsi_dev);
static struct scsi_transport_template *mvs_stt;
@@ -656,7 +690,7 @@ static struct scsi_host_template mvs_sht = {
.use_clustering = ENABLE_CLUSTERING,
.eh_device_reset_handler = sas_eh_device_reset_handler,
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
- .slave_alloc = sas_slave_alloc,
+ .slave_alloc = mvs_sas_slave_alloc,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
};
@@ -705,7 +739,8 @@ static void mvs_hba_sb_dump(struct mvs_info *mvi, u32 tag,
offset = len_ct + MVS_OAF_SZ +
sizeof(struct mvs_prd) * mvi->slot_info[tag].n_elem;
- dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer :\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "+---->Status buffer[%d] :\n",
+ tag);
mvs_hexdump(32, (u8 *) mvi->slot_info[tag].response,
(u32) mvi->slot_info[tag].buf_dma + offset);
}
@@ -789,7 +824,6 @@ static void mvs_hba_cq_dump(struct mvs_info *mvi)
#endif
}
-#if 0
static void mvs_hba_interrupt_enable(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
@@ -809,7 +843,6 @@ static void mvs_hba_interrupt_disable(struct mvs_info *mvi)
mw32(GBL_CTL, tmp & ~INT_EN);
}
-#endif
static int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
@@ -1002,6 +1035,28 @@ err_out:
#endif
}
+static void mvs_bytes_dmaed(struct mvs_info *mvi, int i)
+{
+ struct mvs_phy *phy = &mvi->phy[i];
+
+ if (!phy->phy_attached)
+ return;
+
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ struct sas_identify_frame *id;
+
+ id = (struct sas_identify_frame *)phy->frame_rcvd;
+ id->dev_type = phy->identify.device_type;
+ id->initiator_bits = SAS_PROTOCOL_ALL;
+ id->target_bits = phy->identify.target_port_protocols;
+ } else if (phy->phy_type & PORT_TYPE_SATA) {
+ /* TODO */
+ }
+ mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
+ mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
+ PORTE_BYTES_DMAED);
+}
+
static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
/* give the phy enabling interrupt event time to come in (1s
@@ -1016,34 +1071,79 @@ static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time)
static void mvs_scan_start(struct Scsi_Host *shost)
{
int i;
- struct sas_identify_frame *id;
struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha;
for (i = 0; i < mvi->chip->n_phy; ++i) {
- struct mvs_phy *phy = &mvi->phy[i];
- id = (struct sas_identify_frame *)phy->frame_rcvd;
- if (phy->type & PORT_TYPE_SAS) {
- id->dev_type = phy->identify.device_type;
- id->initiator_bits = SAS_PROTOCOL_ALL;
- id->target_bits = phy->identify.target_port_protocols;
- } else if (phy->type & PORT_TYPE_SATA) {
- }
- mvi->sas.sas_phy[i]->frame_rcvd_size = phy->frame_rcvd_size;
- mvi->sas.notify_port_event(mvi->sas.sas_phy[i],
- PORTE_BYTES_DMAED);
+ mvs_bytes_dmaed(mvi, i);
}
+}
+
+static int mvs_sas_slave_alloc(struct scsi_device *scsi_dev)
+{
+ int rc;
+
+ rc = sas_slave_alloc(scsi_dev);
+ return rc;
}
static void mvs_int_port(struct mvs_info *mvi, int port_no, u32 events)
{
struct pci_dev *pdev = mvi->pdev;
+ struct sas_ha_struct *sas_ha = &mvi->sas;
+ struct mvs_phy *phy = &mvi->phy[port_no];
+ struct asd_sas_phy *sas_phy = &phy->sas_phy;
+
+ phy->irq_status = mvs_read_port_irq_stat(mvi, port_no);
/*
* events is port event now ,
* we need check the interrupt status which belongs to per port.
*/
dev_printk(KERN_DEBUG, &pdev->dev,
- "Port0 = %d", mvs_read_port_irq_stat(mvi, 0));
+ "Port %d Event = %X\n",
+ port_no, phy->irq_status);
+
+ if ((phy->irq_status & PHYEV_POOF) ||
+ (phy->irq_status & PHYEV_DEC_ERR)) {
+ if (!mvs_is_phy_ready(mvi, port_no)) {
+ sas_phy_disconnected(sas_phy);
+ sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
+ } else
+ mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL);
+ }
+ if (!(phy->irq_status & PHYEV_DEC_ERR)) {
+ if (phy->irq_status & PHYEV_COMWAKE) {
+ u32 tmp = mvs_read_port_irq_mask(mvi, port_no);
+ mvs_write_port_irq_mask(mvi, port_no,
+ tmp | PHYEV_SIG_FIS);
+ }
+ if ((phy->irq_status & PHYEV_SIG_FIS) ||
+ (phy->irq_status & PHYEV_ID_DONE)) {
+ phy->phy_status = mvs_is_phy_ready(mvi, port_no);
+ if (phy->phy_status) {
+ mvs_detect_porttype(mvi, port_no);
+
+ if (phy->phy_type & PORT_TYPE_SATA) {
+ u32 tmp = mvs_read_port_irq_mask(mvi,
+ port_no);
+ tmp &= ~PHYEV_SIG_FIS;
+ mvs_write_port_irq_mask(mvi,
+ port_no, tmp);
+ }
+
+ mvs_update_phyinfo(mvi, port_no, 0);
+ sas_ha->notify_phy_event(sas_phy,
+ PHYE_OOB_DONE);
+ mvs_bytes_dmaed(mvi, port_no);
+ } else {
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "plugin interrupt but phy is gone\n");
+ mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET,
+ NULL);
+ }
+ }
+ }
+ mvs_write_port_irq_stat(mvi, port_no, phy->irq_status);
}
static void mvs_int_sata(struct mvs_info *mvi)
@@ -1075,13 +1175,24 @@ static void mvs_slot_free(struct mvs_info *mvi, struct sas_task *task,
break;
}
+ slot->task = NULL;
mvs_tag_clear(mvi, slot_idx);
}
static void mvs_slot_err(struct mvs_info *mvi, struct sas_task *task,
u32 slot_idx)
{
- /* FIXME */
+ struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
+ u64 err_dw0 = *(u32 *) slot->response;
+ void __iomem *regs = mvi->regs;
+ u32 tmp;
+
+ if (err_dw0 & CMD_ISS_STPD)
+ if (sas_protocol_ata(task->task_proto)) {
+ tmp = mr32(INT_STAT_SRS);
+ mw32(INT_STAT_SRS, tmp & 0xFFFF);
+ }
+
mvs_hba_sb_dump(mvi, slot_idx, task->task_proto);
}
@@ -1091,6 +1202,7 @@ static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
struct mvs_slot_info *slot = &mvi->slot_info[slot_idx];
struct sas_task *task = slot->task;
struct task_status_struct *tstat = &task->task_status;
+ struct mvs_port *port = &mvi->port[task->dev->port->id];
bool aborted;
spin_lock(&task->task_state_lock);
@@ -1108,6 +1220,12 @@ static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
memset(tstat, 0, sizeof(*tstat));
tstat->resp = SAS_TASK_COMPLETE;
+
+ if (unlikely(!port->port_attached)) {
+ tstat->stat = SAS_PHY_DOWN;
+ goto out;
+ }
+
/* error info record present */
if ((rx_desc & RXQ_ERR) && (*(u64 *) slot->response)) {
tstat->stat = SAM_CHECK_COND;
@@ -1142,9 +1260,6 @@ static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
case SAS_PROTOCOL_STP: {
struct ata_task_resp *resp =
(struct ata_task_resp *)tstat->buf;
- struct domain_device *dev = task->dev;
- struct mvs_port *port =
- (struct mvs_port *)dev->port->lldd_port;
if ((rx_desc & (RXQ_DONE | RXQ_ERR | RXQ_ATTN)) ==
RXQ_DONE)
@@ -1156,7 +1271,8 @@ static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc)
memcpy(&resp->ending_fis[0],
SATA_RECEIVED_D2H_FIS(port->taskfileset),
sizeof(struct dev_to_host_fis));
- /*mvs_hexdump(16,resp->ending_fis,0);*/
+ if (resp->ending_fis[2] & ATA_ERR)
+ mvs_hexdump(16, resp->ending_fis, 0);
break;
}
@@ -1232,11 +1348,13 @@ static int mvs_int_rx(struct mvs_info *mvi, bool self_clear)
if (unlikely(rx_desc & RXQ_DONE))
mvs_slot_complete(mvi, rx_desc);
- else if (rx_desc & RXQ_ATTN) {
+ if (rx_desc & RXQ_ATTN) {
attn = true;
- dev_printk(KERN_DEBUG, &pdev->dev, "ATTN\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n",
+ rx_desc);
} else if (rx_desc & RXQ_ERR) {
- dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR\n");
+ dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n",
+ rx_desc);
}
}
@@ -1269,6 +1387,7 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque)
return IRQ_HANDLED;
}
+#ifdef MVS_DISABLE_MSI
static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
{
struct mvs_info *mvi = opaque;
@@ -1281,10 +1400,12 @@ static irqreturn_t mvs_msi_interrupt(int irq, void *opaque)
return IRQ_HANDLED;
}
+#endif
struct mvs_task_exec_info {
struct sas_task *task;
struct mvs_cmd_hdr *hdr;
+ struct mvs_port *port;
u32 tag;
int n_elem;
};
@@ -1348,27 +1469,30 @@ err_out:
return rc;
}
-#if 0
static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port)
{
void __iomem *regs = mvi->regs;
u32 tmp, offs;
+ u8 *tfs = &port->taskfileset;
- if (port->taskfileset == MVS_ID_NOT_MAPPED)
+ if (*tfs == MVS_ID_NOT_MAPPED)
return;
- offs = 1U << ((port->taskfileset & 0x0f) + PCS_EN_SATA_REG_SHIFT);
- if (port->taskfileset < 16) {
+ offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
+ if (*tfs < 16) {
tmp = mr32(PCS);
- mw32(PCS, tmp | ~offs);
+ mw32(PCS, tmp & ~offs);
} else {
tmp = mr32(CTL);
- mw32(CTL, tmp | ~offs);
+ mw32(CTL, tmp & ~offs);
}
- port->taskfileset = MVS_ID_NOT_MAPPED;
+ tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
+ if (tmp)
+ mw32(INT_STAT_SRS, tmp);
+
+ *tfs = MVS_ID_NOT_MAPPED;
}
-#endif
static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
{
@@ -1392,6 +1516,9 @@ static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port)
mw32(PCS, tmp | offs);
else
mw32(CTL, tmp | offs);
+ tmp = mr32(INT_STAT_SRS) & (1U << i);
+ if (tmp)
+ mw32(INT_STAT_SRS, tmp);
return 0;
}
}
@@ -1419,7 +1546,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
struct mvs_slot_info *slot;
struct scatterlist *sg;
struct mvs_prd *buf_prd;
- struct mvs_port *port = (struct mvs_port *)sas_port->lldd_port;
+ struct mvs_port *port = tei->port;
u32 tag = tei->tag;
u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT);
void *buf_tmp;
@@ -1432,7 +1559,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi,
return -EBUSY;
slot = &mvi->slot_info[tag];
-
+ slot->tx = mvi->tx_prod;
mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
(TXQ_CMD_STP << TXQ_CMD_SHIFT) |
(sas_port->phy_mask << TXQ_PHY_SHIFT) |
@@ -1530,8 +1657,8 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
struct mvs_task_exec_info *tei)
{
struct sas_task *task = tei->task;
- struct asd_sas_port *sas_port = task->dev->port;
struct mvs_cmd_hdr *hdr = tei->hdr;
+ struct mvs_port *port = tei->port;
struct mvs_slot_info *slot;
struct scatterlist *sg;
struct mvs_prd *buf_prd;
@@ -1545,9 +1672,11 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
slot = &mvi->slot_info[tag];
+ slot->tx = mvi->tx_prod;
mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag |
- (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
- (sas_port->phy_mask << TXQ_PHY_SHIFT));
+ (TXQ_CMD_SSP << TXQ_CMD_SHIFT) |
+ (port->wide_port_phymap << TXQ_PHY_SHIFT));
+
flags = MCH_RETRY;
if (task->ssp_task.enable_first_burst) {
flags |= MCH_FBURST;
@@ -1642,11 +1771,12 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi,
static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
{
- struct mvs_info *mvi = task->dev->port->ha->lldd_ha;
+ struct domain_device *dev = task->dev;
+ struct mvs_info *mvi = dev->port->ha->lldd_ha;
struct pci_dev *pdev = mvi->pdev;
+ void __iomem *regs = mvi->regs;
struct mvs_task_exec_info tei;
struct sas_task *t = task;
- void __iomem *regs = mvi->regs;
u32 tag = 0xdeadbeef, rc, n_elem = 0;
unsigned long flags;
u32 n = num, pass = 0;
@@ -1654,6 +1784,15 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
spin_lock_irqsave(&mvi->lock, flags);
do {
+ tei.port = &mvi->port[dev->port->id];
+
+ if (!tei.port->port_attached) {
+ struct task_status_struct *ts = &t->task_status;
+ ts->stat = SAS_PHY_DOWN;
+ t->task_done(t);
+ rc = 0;
+ goto exec_exit;
+ }
if (!sas_protocol_ata(t->task_proto)) {
if (t->num_scatter) {
n_elem = pci_map_sg(mvi->pdev, t->scatter,
@@ -1724,11 +1863,12 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags)
err_out_tag:
mvs_tag_free(mvi, tag);
err_out:
- dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", pass);
+ dev_printk(KERN_ERR, &pdev->dev, "mvsas exec failed[%d]!\n", rc);
if (!sas_protocol_ata(t->task_proto))
if (n_elem)
pci_unmap_sg(mvi->pdev, t->scatter, n_elem,
t->data_dir);
+exec_exit:
if (pass)
mw32(TX_PROD_IDX, (mvi->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
spin_unlock_irqrestore(&mvi->lock, flags);
@@ -1751,6 +1891,7 @@ static int mvs_task_abort(struct sas_task *task)
/*FIXME*/
rc = TMF_RESP_FUNC_COMPLETE;
+
switch (task->task_proto) {
case SAS_PROTOCOL_SMP:
dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! ");
@@ -1823,11 +1964,10 @@ static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
void *funcdata)
{
struct mvs_info *mvi = sas_phy->ha->lldd_ha;
- void __iomem *reg;
int rc = 0, phy_id = sas_phy->id;
u32 tmp;
- reg = mvi->regs + MVS_P0_SER_CTLSTAT + (phy_id * 4);
+ tmp = mvs_read_phy_ctl(mvi, phy_id);
switch (func) {
case PHY_FUNC_SET_LINK_RATE:{
@@ -1837,7 +1977,6 @@ static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
lrmin = (rates->minimum_linkrate << 8);
lrmax = (rates->maximum_linkrate << 12);
- tmp = readl(reg);
if (lrmin) {
tmp &= ~(0xf << 8);
tmp |= lrmin;
@@ -1846,19 +1985,18 @@ static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
tmp &= ~(0xf << 12);
tmp |= lrmax;
}
- writel(tmp, reg);
+ mvs_write_phy_ctl(mvi, phy_id, tmp);
break;
}
case PHY_FUNC_HARD_RESET:
- tmp = readl(reg);
if (tmp & PHY_RST_HARD)
break;
- writel(tmp | PHY_RST_HARD, reg);
+ mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD);
break;
case PHY_FUNC_LINK_RESET:
- writel(readl(reg) | PHY_RST, reg);
+ mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST);
break;
case PHY_FUNC_DISABLE:
@@ -2127,12 +2265,10 @@ static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val)
mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val);
}
-#if 0
static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port)
{
return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port);
}
-#endif
static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val)
{
@@ -2211,18 +2347,14 @@ static void mvs_detect_porttype(struct mvs_info *mvi, int i)
u32 reg;
struct mvs_phy *phy = &mvi->phy[i];
- /* enable auto port detection */
- mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
- msleep(100);
-
/* TODO check & save device type */
reg = mr32(GBL_PORT_TYPE);
if (reg & MODE_SAS_SATA & (1 << i)) {
- phy->type = PORT_TYPE_SAS;
+ phy->phy_type |= PORT_TYPE_SAS;
phy->identify.target_port_protocols = SAS_PROTOCOL_SSP;
} else {
- phy->type = PORT_TYPE_SATA;
+ phy->phy_type |= PORT_TYPE_SATA;
phy->identify.target_port_protocols = SAS_PROTOCOL_STP;
}
@@ -2250,23 +2382,65 @@ static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf)
return (void *)s;
}
-static u32 mvs_is_sig_fis_received(struct mvs_info *mvi, int i)
+static u32 mvs_is_sig_fis_received(u32 irq_status)
+{
+ return irq_status & PHYEV_SIG_FIS;
+}
+
+static void mvs_update_wideport(struct mvs_info *mvi, int i)
+{
+ struct mvs_phy *phy = &mvi->phy[i];
+ struct mvs_port *port = phy->port;
+ int j, no;
+
+ for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy) {
+ mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
+ mvs_write_port_cfg_data(mvi, no , port->wide_port_phymap);
+ } else {
+ mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
+ mvs_write_port_cfg_data(mvi, no , 0);
+ }
+}
+
+static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i)
{
u32 tmp;
+ struct mvs_phy *phy = &mvi->phy[i];
+ struct mvs_port *port;
- tmp = mvs_read_port_irq_stat(mvi, i) & PHYEV_SIG_FIS;
- if (tmp)
- mvs_write_port_irq_stat(mvi, i, PHYEV_SIG_FIS);
+ tmp = mvs_read_phy_ctl(mvi, i);
- return tmp;
+ if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) {
+ if (!phy->port)
+ phy->phy_attached = 1;
+ return tmp;
+ }
+
+ port = phy->port;
+ if (port) {
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ port->wide_port_phymap &= ~(1U << i);
+ if (!port->wide_port_phymap)
+ port->port_attached = 0;
+ mvs_update_wideport(mvi, i);
+ } else if (phy->phy_type & PORT_TYPE_SATA) {
+ mvs_free_reg_set(mvi, phy->port);
+ port->port_attached = 0;
+ }
+ phy->port = NULL;
+ phy->phy_attached = 0;
+ phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA);
+ }
+ return 0;
}
-static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
+static void mvs_update_phyinfo(struct mvs_info *mvi, int i,
+ int get_st)
{
struct mvs_phy *phy = &mvi->phy[i];
- u32 tmp;
- u64 tmp64;
struct pci_dev *pdev = mvi->pdev;
+ u32 tmp, j;
+ u64 tmp64;
mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY);
phy->dev_info = mvs_read_port_cfg_data(mvi, i);
@@ -2277,20 +2451,23 @@ static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
mvs_write_port_cfg_addr(mvi, i, PHYR_ADDR_LO);
phy->dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
- phy->phy_status = mvs_read_phy_ctl(mvi, i);
-
- /* FIXME Update Wide Port info */
- phy->port = &mvi->port[i];
- phy->port->sas_port.lldd_port = phy->port;
- phy->port->taskfileset = MVS_ID_NOT_MAPPED;
+ if (get_st) {
+ phy->irq_status = mvs_read_port_irq_stat(mvi, i);
+ phy->phy_status = mvs_is_phy_ready(mvi, i);
+ }
- if (phy->phy_status & PHY_READY_MASK) {
+ if (phy->phy_status) {
u32 phy_st;
struct asd_sas_phy *sas_phy = mvi->sas.sas_phy[i];
mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT);
phy_st = mvs_read_port_cfg_data(mvi, i);
+ sas_phy->linkrate =
+ (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
+ PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
+
+ /* Updated attached_sas_addr */
mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI);
phy->att_dev_sas_addr =
(u64) mvs_read_port_cfg_data(mvi, i) << 32;
@@ -2298,36 +2475,57 @@ static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO);
phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i);
- /*Updated attached_sas_addr */
- tmp64 = phy->att_dev_sas_addr;
dev_printk(KERN_DEBUG, &pdev->dev,
"phy[%d] Get Attached Address 0x%llX ,"
" SAS Address 0x%llX\n",
- i, tmp64, phy->dev_sas_addr);
- tmp64 = cpu_to_be64(tmp64);
+ i, phy->att_dev_sas_addr, phy->dev_sas_addr);
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "Rate = %x , type = %d\n",
+ sas_phy->linkrate, phy->phy_type);
+
+#if 1
+ /*
+ * If the device is capable of supporting a wide port
+ * on its phys, it may configure the phys as a wide port.
+ */
+ if (phy->phy_type & PORT_TYPE_SAS)
+ for (j = 0; j < mvi->chip->n_phy && j != i; ++j) {
+ if ((mvi->phy[j].phy_attached) &&
+ (mvi->phy[j].phy_type & PORT_TYPE_SAS))
+ if (phy->att_dev_sas_addr ==
+ mvi->phy[j].att_dev_sas_addr - 1) {
+ phy->att_dev_sas_addr =
+ mvi->phy[j].att_dev_sas_addr;
+ break;
+ }
+ }
+
+#endif
+
+ tmp64 = cpu_to_be64(phy->att_dev_sas_addr);
memcpy(sas_phy->attached_sas_addr, &tmp64, SAS_ADDR_SIZE);
- if (phy->type & PORT_TYPE_SAS) {
+ if (phy->phy_type & PORT_TYPE_SAS) {
mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO);
phy->att_dev_info = mvs_read_port_cfg_data(mvi, i);
phy->identify.device_type =
phy->att_dev_info & PORT_DEV_TYPE_MASK;
- sas_phy->linkrate =
- (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >>
- PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET;
if (phy_st & PHY_OOB_DTCTD)
sas_phy->oob_mode = SAS_OOB_MODE;
phy->frame_rcvd_size =
sizeof(struct sas_identify_frame);
- } else if (phy->type & PORT_TYPE_SATA) {
- if (mvs_is_sig_fis_received(mvi, i)) {
+ } else if (phy->phy_type & PORT_TYPE_SATA) {
+ if (mvs_is_sig_fis_received(phy->irq_status)) {
if (phy_st & PHY_OOB_DTCTD)
sas_phy->oob_mode = SATA_OOB_MODE;
phy->frame_rcvd_size =
sizeof(struct dev_to_host_fis);
mvs_get_d2h_reg(mvi, i,
(void *)sas_phy->frame_rcvd);
+ } else {
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "No sig fis\n");
}
}
/* workaround for HW phy decoding error on 1.5g disk drive */
@@ -2342,7 +2540,28 @@ static void __devinit mvs_update_phyinfo(struct mvs_info *mvi, int i)
mvs_write_port_vsr_data(mvi, i, tmp);
}
- phy->irq_status = mvs_read_port_irq_stat(mvi, i);
+ if (get_st)
+ mvs_write_port_irq_stat(mvi, i, phy->irq_status);
+}
+
+static void mvs_port_formed(struct asd_sas_phy *sas_phy)
+{
+ struct sas_ha_struct *sas_ha = sas_phy->ha;
+ struct mvs_info *mvi = sas_ha->lldd_ha;
+ struct asd_sas_port *sas_port = sas_phy->port;
+ struct mvs_phy *phy = sas_phy->lldd_phy;
+ struct mvs_port *port = &mvi->port[sas_port->id];
+ unsigned long flags;
+
+ spin_lock_irqsave(&mvi->lock, flags);
+ port->port_attached = 1;
+ phy->port = port;
+ if (phy->phy_type & PORT_TYPE_SAS) {
+ port->wide_port_phymap = sas_port->phy_mask;
+ mvs_update_wideport(mvi, sas_phy->id);
+ } else if (phy->phy_type & PORT_TYPE_SATA)
+ port->taskfileset = MVS_ID_NOT_MAPPED;
+ spin_unlock_irqrestore(&mvi->lock, flags);
}
static int __devinit mvs_hw_init(struct mvs_info *mvi)
@@ -2431,6 +2650,9 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32(RX_LO, mvi->rx_dma);
mw32(RX_HI, (mvi->rx_dma >> 16) >> 16);
+ /* enable auto port detection */
+ mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN);
+ msleep(100);
/* init and reset phys */
for (i = 0; i < mvi->chip->n_phy; i++) {
/* FIXME: is this the correct dword order? */
@@ -2460,10 +2682,12 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mvs_write_port_irq_stat(mvi, i, tmp);
/* set phy int mask */
- tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS;
+ tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS |
+ PHYEV_ID_DONE | PHYEV_DEC_ERR;
mvs_write_port_irq_mask(mvi, i, tmp);
- mvs_update_phyinfo(mvi, i);
+ msleep(100);
+ mvs_update_phyinfo(mvi, i, 1);
mvs_enable_xmt(mvi, i);
}
@@ -2500,11 +2724,10 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi)
mw32(TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN);
mw32(RX_CFG, MVS_RX_RING_SZ | RX_EN);
/* enable CMD/CMPL_Q/RESP mode */
- mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN |
- ((mvi->flags & MVF_MSI) ? PCS_SELF_CLEAR : 0));
+ mw32(PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | PCS_CMD_EN);
/* re-enable interrupts globally */
- mw32(GBL_CTL, INT_EN);
+ mvs_hba_interrupt_enable(mvi);
/* enable completion queue interrupt */
tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM);
@@ -2556,10 +2779,16 @@ static int __devinit mvs_pci_init(struct pci_dev *pdev,
if (rc)
goto err_out_mvi;
+#ifdef MVS_DISABLE_MSI
if (!pci_enable_msi(pdev)) {
+ u32 tmp;
+ void __iomem *regs = mvi->regs;
mvi->flags |= MVF_MSI;
irq_handler = mvs_msi_interrupt;
+ tmp = mr32(PCS);
+ mw32(PCS, tmp | PCS_SELF_CLEAR);
}
+#endif
rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi);
if (rc)
@@ -2603,15 +2832,18 @@ static void __devexit mvs_pci_remove(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
- sas_unregister_ha(&mvi->sas);
- sas_remove_host(mvi->shost);
- scsi_remove_host(mvi->shost);
-
- free_irq(pdev->irq, mvi);
- if (mvi->flags & MVF_MSI)
- pci_disable_msi(pdev);
- mvs_free(mvi);
- pci_release_regions(pdev);
+ if (mvi) {
+ sas_unregister_ha(&mvi->sas);
+ mvs_hba_interrupt_disable(mvi);
+ sas_remove_host(mvi->shost);
+ scsi_remove_host(mvi->shost);
+
+ free_irq(pdev->irq, mvi);
+ if (mvi->flags & MVF_MSI)
+ pci_disable_msi(pdev);
+ mvs_free(mvi);
+ pci_release_regions(pdev);
+ }
pci_disable_device(pdev);
}
@@ -2619,6 +2851,7 @@ static struct sas_domain_function_template mvs_transport_ops = {
.lldd_execute_task = mvs_task_exec,
.lldd_control_phy = mvs_phy_control,
.lldd_abort_task = mvs_task_abort,
+ .lldd_port_formed = mvs_port_formed
};
static struct pci_device_id __devinitdata mvs_pci_table[] = {
--
1.5.4.rc4
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-02-05 13:19 ` Ke Wei
@ 2008-02-05 21:00 ` Luben Tuikov
2008-02-07 0:33 ` Jeff Garzik
1 sibling, 0 replies; 22+ messages in thread
From: Luben Tuikov @ 2008-02-05 21:00 UTC (permalink / raw)
To: James Bottomley, Ke Wei; +Cc: linux-scsi, jeff, qswang, jfeng, qzhao, kewei
--- On Tue, 2/5/08, Ke Wei <kewei.mv@gmail.com> wrote:
> + for_each_phy(port->wide_port_phymap, no, j, mvi->chip->n_phy) {
> + mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
> + mvs_write_port_cfg_data(mvi, no , port->wide_port_phymap);
> + } else {
> + mvs_write_port_cfg_addr(mvi, no, PHYR_WIDE_PORT);
> + mvs_write_port_cfg_data(mvi, no , 0);
> + }
> +}
Don't do this. Make the "if" explicit.
Since I can see you've taken this verbatim from the SAS code,
if "no" means number, then it is "j". "no" is just a temporary
register which gets shifted right each iteration and not of
much use outside the macro.
Also if "__rest" (which you added to the macro) is 0, then nether
statement would execute, which is probably not what you want.
If "n_phy" means "number of phys", then its usage that you added
into the macro is inconsistent. Furthermore it shouldn't be
necessary since wide_port_phymap & ~((2^n_phy)-1) must never be true.
Luben
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-02-05 13:19 ` Ke Wei
2008-02-05 21:00 ` Luben Tuikov
@ 2008-02-07 0:33 ` Jeff Garzik
1 sibling, 0 replies; 22+ messages in thread
From: Jeff Garzik @ 2008-02-07 0:33 UTC (permalink / raw)
To: Ke Wei; +Cc: James Bottomley, linux-scsi, qswang, jfeng, qzhao, kewei
Ke Wei wrote:
> Added support for hotplug and wide port.
>
>
> Signed-off-by: Ke Wei <kewei@marvell.com>
> ---
> drivers/scsi/mvsas.c | 445 ++++++++++++++++++++++++++++++++++++++------------
> 1 files changed, 339 insertions(+), 106 deletions(-)
Technically speaking, everything is looking great so far.
We need to correct one process problem, and we should be able to get
your work into the 'mvsas' branch of scsi-misc-2.6.git... and soon
thereafter hopefully into the official upstream kernel.
The process problem is... when making revisions, we need to get the
full patch each time. In this case, each patch should be diff'd against
the current version in the 'mvsas' branch: version 0.1.
The succession of emails would look like this:
Email #1:
Subject: [PATCH] mvsas: make it work
Convert the skeleton mvsas driver into a real, working
driver. Currently, the following works:
SAS, SAS expanders, SAS wide ports
SATA devices, SATAPI
Signed-off-by: Ke Wei <kewei@marvell.com>
And then James, myself, other reviewers reply. Or, you add some new
features like hotplugging.
Each time, you must regenerate a full patch against the most git
repository revision:
If a previous patch of yours, version "0.2", has been applied
to git, then you would create your patch against version 0.2.
If a previous patch of yours has NOT yet been applied to git,
then you would create your patch against version 0.1.
Thus, in this case, version 0.1 is in 'mvsas' branch, so your second
email would then be
Email #2:
Subject: [PATCH v2] mvsas: make it work
Convert the skeleton mvsas driver into a real, working
driver. Currently, the following works:
SAS, SAS expanders, SAS wide ports
SATA devices, SATAPI
Signed-off-by: Ke Wei <kewei@marvell.com>
---
Changes since last posting (version 0.2):
- fix coding problem
And then you continue your work, and add another revision while everyone
else is sleeping, the third email would look like:
Email #3:
Subject: [PATCH v3] mvsas: make it work
Convert the skeleton mvsas driver into a real, working
driver. Currently, the following works:
SAS, SAS expanders, SAS wide ports
SATA devices, SATAPI
Signed-off-by: Ke Wei <kewei@marvell.com>
---
Changes since last posting (version 0.3):
- add hotplug support
- add wide port support
Changes since last posting (version 0.2):
- fix coding problem
Thus, you always create a patch against the most recent source code in
the git repository.
It is common for patches to go through a few revisions on the mailing
list, before it is applied to the git repository.
So anyway... send a patch against the latest #mvsas (version 0.1), and
that patch should go in rapidly.
Thanks! And keep up the good work,
Jeff
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
[not found] <FE3F06125A99254E8D92161AA4569C6F02310B1A@sc-exch02.marvell.com>
@ 2008-02-22 16:26 ` Jeff Garzik
2008-02-22 16:38 ` James Bottomley
0 siblings, 1 reply; 22+ messages in thread
From: Jeff Garzik @ 2008-02-22 16:26 UTC (permalink / raw)
To: Ke Wei
Cc: Ke Wei, James Bottomley, linux-scsi, Michael Wang, Jacky Feng,
Qun Zhao, Larry Li, saeed bishara
Ke Wei wrote:
> Added support for Expander. Based on version 0.1 for mvsas.
>
>
> Signed-off-by: Ke Wei <kewei@marvell.com>
> ---
> diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
> old mode 100644
> new mode 100755
> index 03638b9..3c7a154
> --- a/drivers/scsi/mvsas.c
> +++ b/drivers/scsi/mvsas.c
> @@ -2,6 +2,7 @@
> mvsas.c - Marvell 88SE6440 SAS/SATA support
>
> Copyright 2007 Red Hat, Inc.
> + Copyright 2008 Marvell. <kewei@marvell.com>
>
> This program is free software; you can redistribute it and/or
> modify it under the terms of the GNU General Public License as
> @@ -25,6 +26,13 @@
> structures. this permits elimination of all the le32_to_cpu()
> and cpu_to_le32() conversions.
>
> + Changelog:
> + 2008-02-22 0.5 Added support for Expander.
> + 2008-02-05 0.4 Added support for hotplug and wide port.
> + 2008-01-22 0.3 Added support for SAS HD and SATA Devices.
> + 2008-01-09 0.2 detect SAS disk.
> + 2007-09-25 0.1 rough draft, Initial version.
> +
> */
>
> #include <linux/kernel.h>
Technical content: looks good, ACK
Patch content: looks diff'd against correct version, ACK
But we still have one major process problem, and a couple minor problems
to fix:
1) [minor] please do not include a changelog in the source code. That's
what the git repository history is for.
2) [minor] Your patch description (email body) is incorrect. It should
describe all changes since version 0.1, the version you diff'd against:
Convert rough draft Marvell 6440 driver to a working driver.
Added support for SAS and SATA devices, hotplug, wide port,
and expanders.
3) [minor] Your email subject should reflect that you are updating
version 0.1, the version you diff'd against:
[PATCH] mvsas: convert from rough draft to working driver
4) [major] Your email was encoded in base64, which makes it difficult
for automated tools to handle, and difficult for some mail clients to
view and reply-to.
It will require some email configuration on your part to disable this,
and send the email as a text/plain message.
I've copied Saeed Bishara @ Marvell on this email. Saeed has been
successfully sending patch for the sata_mv driver (5040, 6080, 6042,
etc.) Maybe Saeed can advise you on his email setup?
In any case, once we fix this last problem -- base64 -- we can finally
apply your patch and get things moving.
You are very close to having a working Linux kernel development setup,
thanks for your patience!
Jeff
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH] Marvell 6440 SAS/SATA driver
2008-02-22 16:26 ` Jeff Garzik
@ 2008-02-22 16:38 ` James Bottomley
0 siblings, 0 replies; 22+ messages in thread
From: James Bottomley @ 2008-02-22 16:38 UTC (permalink / raw)
To: Jeff Garzik
Cc: Ke Wei, Ke Wei, linux-scsi, Michael Wang, Jacky Feng, Qun Zhao,
Larry Li, saeed bishara
On Fri, 2008-02-22 at 11:26 -0500, Jeff Garzik wrote:
> 4) [major] Your email was encoded in base64, which makes it difficult
> for automated tools to handle, and difficult for some mail clients to
> view and reply-to.
Yes, I echo this, there's also another problem it causes: The email
didn't actually get through the scsi reflector in part, I suspect,
because of the base64 content (anybody who wasn't on the direct to or cc
list is only seeing Jeff's reply).
James
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2008-02-22 16:38 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20080122151857.GA8680@ubuntu.domain>
2008-01-22 15:24 ` [PATCH] Marvell 6440 SAS/SATA driver Ke Wei
2008-01-23 3:58 ` Jeff Garzik
2008-01-23 10:54 ` Ke Wei
2008-01-23 11:41 ` Jeff Garzik
2008-01-25 16:43 ` Ke Wei
2008-01-25 17:24 ` Grant Grundler
2008-01-25 17:38 ` James Bottomley
2008-01-25 22:12 ` Jeff Garzik
2008-01-25 17:38 ` Grant Grundler
2008-01-25 22:39 ` James Bottomley
2008-01-27 15:10 ` Ke Wei
2008-01-27 15:27 ` Ke Wei
2008-01-27 18:13 ` James Bottomley
2008-02-05 13:19 ` Ke Wei
2008-02-05 21:00 ` Luben Tuikov
2008-02-07 0:33 ` Jeff Garzik
2008-01-25 23:00 ` James Bottomley
2008-01-25 23:05 ` Jeff Garzik
2008-01-25 21:27 ` James Bottomley
2008-01-23 19:23 ` Grant Grundler
[not found] <FE3F06125A99254E8D92161AA4569C6F02310B1A@sc-exch02.marvell.com>
2008-02-22 16:26 ` Jeff Garzik
2008-02-22 16:38 ` James Bottomley
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).