Commit dd4969a8 authored by Jeff Garzik's avatar Jeff Garzik Committed by James Bottomley

[SCSI] mvsas: split driver into multiple files

Split mvsas driver into multiple source codes, based on the split
and function distribution found in Marvell's mvsas update.
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 2ad52f47
...@@ -22,5 +22,6 @@ ...@@ -22,5 +22,6 @@
# USA # USA
obj-$(CONFIG_SCSI_MVSAS) += mvsas.o obj-$(CONFIG_SCSI_MVSAS) += mvsas.o
mvsas-y += mv_sas.o mvsas-y += mv_init.o \
mv_sas.o \
mv_64xx.o
/*
mv_64xx.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
published by the Free Software Foundation; either version 2,
or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; see the file COPYING. If not,
write to the Free Software Foundation, 675 Mass Ave, Cambridge,
MA 02139, USA.
*/
#include "mv_sas.h"
#include "mv_64xx.h"
#include "mv_chips.h"
void mvs_detect_porttype(struct mvs_info *mvi, int i)
{
void __iomem *regs = mvi->regs;
u32 reg;
struct mvs_phy *phy = &mvi->phy[i];
/* TODO check & save device type */
reg = mr32(GBL_PORT_TYPE);
if (reg & MODE_SAS_SATA & (1 << i))
phy->phy_type |= PORT_TYPE_SAS;
else
phy->phy_type |= PORT_TYPE_SATA;
}
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);
}
void __devinit mvs_phy_hacks(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
u32 tmp;
/* workaround for SATA R-ERR, to ignore phy glitch */
tmp = mvs_cr32(regs, CMD_PHY_TIMER);
tmp &= ~(1 << 9);
tmp |= (1 << 10);
mvs_cw32(regs, CMD_PHY_TIMER, tmp);
/* enable retry 127 times */
mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f);
/* extend open frame timeout to max */
tmp = mvs_cr32(regs, CMD_SAS_CTL0);
tmp &= ~0xffff;
tmp |= 0x3fff;
mvs_cw32(regs, CMD_SAS_CTL0, tmp);
/* workaround for WDTIMEOUT , set to 550 ms */
mvs_cw32(regs, CMD_WD_TIMER, 0x86470);
/* not to halt for different port op during wideport link change */
mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d);
/* workaround for Seagate disk not-found OOB sequence, recv
* COMINIT before sending out COMWAKE */
tmp = mvs_cr32(regs, CMD_PHY_MODE_21);
tmp &= 0x0000ffff;
tmp |= 0x00fa0000;
mvs_cw32(regs, CMD_PHY_MODE_21, tmp);
tmp = mvs_cr32(regs, CMD_PHY_TIMER);
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);
}
void mvs_hba_interrupt_enable(struct mvs_info *mvi)
{
void __iomem *regs = mvi->regs;
u32 tmp;
tmp = mr32(GBL_CTL);
mw32(GBL_CTL, tmp | INT_EN);
}
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);
}
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 (*tfs == MVS_ID_NOT_MAPPED)
return;
offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT);
if (*tfs < 16) {
tmp = mr32(PCS);
mw32(PCS, tmp & ~offs);
} else {
tmp = mr32(CTL);
mw32(CTL, tmp & ~offs);
}
tmp = mr32(INT_STAT_SRS) & (1U << *tfs);
if (tmp)
mw32(INT_STAT_SRS, tmp);
*tfs = MVS_ID_NOT_MAPPED;
}
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);
tmp = mr32(INT_STAT_SRS) & (1U << i);
if (tmp)
mw32(INT_STAT_SRS, tmp);
return 0;
}
}
return MVS_ID_NOT_MAPPED;
}
#ifndef _MVS64XX_REG_H_
#define _MVS64XX_REG_H_
/* enhanced mode registers (BAR4) */
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 = 0xa0, /* port type */
MVS_CTL = 0x100, /* SAS/SATA port configuration */
MVS_PCS = 0x104, /* SAS/SATA port control/status */
MVS_CMD_LIST_LO = 0x108, /* cmd list addr */
MVS_CMD_LIST_HI = 0x10C,
MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */
MVS_RX_FIS_HI = 0x114,
MVS_TX_CFG = 0x120, /* TX configuration */
MVS_TX_LO = 0x124, /* TX (delivery) ring addr */
MVS_TX_HI = 0x128,
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 */
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 */
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) */
/* 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 pci_cfg_registers {
PCR_PHY_CTL = 0x40,
PCR_PHY_CTL2 = 0x90,
PCR_DEV_CTRL = 0xE8,
};
/* 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 */
};
struct mvs_prd {
__le64 addr; /* 64-bit buffer address */
__le32 reserved;
__le32 len; /* 16-bit length */
};
#endif
#ifndef _MV_CHIPS_H_
#define _MV_CHIPS_H_
#define mr32(reg) readl(regs + MVS_##reg)
#define mw32(reg,val) writel((val), regs + MVS_##reg)
#define mw32_f(reg,val) do { \
writel((val), regs + MVS_##reg); \
readl(regs + MVS_##reg); \
} while (0)
static inline 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)
{
mw32(CMD_ADDR, addr);
mw32(CMD_DATA, val);
}
static inline u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port)
{
void __iomem *regs = mvi->regs;
return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4):
mr32(P4_SER_CTLSTAT + (port - 4) * 4);
}
static inline void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val)
{
void __iomem *regs = mvi->regs;
if (port < 4)
mw32(P0_SER_CTLSTAT + port * 4, val);
else
mw32(P4_SER_CTLSTAT + (port - 4) * 4, val);
}
static inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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);
}
#endif
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
mv_sas.h - 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
published by the Free Software Foundation; either version 2,
or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public
License along with this program; see the file COPYING. If not,
write to the Free Software Foundation, 675 Mass Ave, Cambridge,
MA 02139, USA.
*/
#ifndef _MV_SAS_H_
#define _MV_SAS_H_
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/dma-mapping.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/vmalloc.h>
#include <scsi/libsas.h>
#include <scsi/scsi_tcq.h>
#include <scsi/sas_ata.h>
#include <linux/version.h>
#include "mv_defs.h"
#define DRV_NAME "mvsas"
#define DRV_VERSION "0.5.2"
#define _MV_DUMP 0
#define MVS_DISABLE_NVRAM
#define MVS_DISABLE_MSI
#define MVS_ID_NOT_MAPPED 0x7f
#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
#define for_each_phy(__lseq_mask, __mc, __lseq, __rest) \
for ((__mc) = (__lseq_mask), (__lseq) = 0; \
(__mc) != 0 && __rest; \
(++__lseq), (__mc) >>= 1)
struct mvs_chip_info {
u32 n_phy;
u32 srs_sz;
u32 slot_width;
};
struct mvs_err_info {
__le32 flags;
__le32 flags2;
};
struct mvs_cmd_hdr {
__le32 flags; /* PRD tbl len; SAS, SATA ctl */
__le32 lens; /* cmd, max resp frame len */
__le32 tags; /* targ port xfer tag; tag */
__le32 data_len; /* data xfer len */
__le64 cmd_tbl; /* command table address */
__le64 open_frame; /* open addr frame address */
__le64 status_buf; /* status buffer address */
__le64 prd_tbl; /* PRD tbl address */
__le32 reserved[4];
};
struct mvs_port {
struct asd_sas_port sas_port;
u8 port_attached;
u8 taskfileset;
u8 wide_port_phymap;
struct list_head list;
};
struct mvs_phy {
struct mvs_port *port;
struct asd_sas_phy sas_phy;
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 phy_type;
u32 phy_status;
u32 irq_status;
u32 frame_rcvd_size;
u8 frame_rcvd[32];
u8 phy_attached;
enum sas_linkrate minimum_linkrate;
enum sas_linkrate maximum_linkrate;
};
struct mvs_slot_info {
struct list_head list;
struct sas_task *task;
u32 n_elem;
u32 tx;
/* DMA buffer for storing cmd tbl, open addr frame, status buffer,
* and PRD table
*/
void *buf;
dma_addr_t buf_dma;
#if _MV_DUMP
u32 cmd_size;
#endif
void *response;
struct mvs_port *port;
};
struct mvs_info {
unsigned long flags;
/* host-wide lock */
spinlock_t lock;
/* our device */
struct pci_dev *pdev;
/* enhanced mode registers */
void __iomem *regs;
/* peripheral registers */
void __iomem *peri_regs;
u8 sas_addr[SAS_ADDR_SIZE];
/* SCSI/SAS glue */
struct sas_ha_struct sas;
struct Scsi_Host *shost;
/* TX (delivery) DMA ring */
__le32 *tx;
dma_addr_t tx_dma;
/* cached next-producer idx */
u32 tx_prod;
/* RX (completion) DMA ring */
__le32 *rx;
dma_addr_t rx_dma;
/* RX consumer idx */
u32 rx_cons;
/* RX'd FIS area */
__le32 *rx_fis;
dma_addr_t rx_fis_dma;
/* DMA command header slots */
struct mvs_cmd_hdr *slot;
dma_addr_t slot_dma;
const struct mvs_chip_info *chip;
u8 tags[MVS_SLOTS];
struct mvs_slot_info slot_info[MVS_SLOTS];
/* further per-slot information */
struct mvs_phy phy[MVS_MAX_PHYS];
struct mvs_port port[MVS_MAX_PHYS];
#ifdef MVS_USE_TASKLET
struct tasklet_struct tasklet;
#endif
};
int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
void *funcdata);
int mvs_slave_configure(struct scsi_device *sdev);
void mvs_scan_start(struct Scsi_Host *shost);
int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time);
int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags);
int mvs_task_abort(struct sas_task *task);
void mvs_port_formed(struct asd_sas_phy *sas_phy);
int mvs_I_T_nexus_reset(struct domain_device *dev);
void mvs_int_full(struct mvs_info *mvi);
void mvs_tag_init(struct mvs_info *mvi);
int mvs_nvram_read(struct mvs_info *mvi, u32 addr, void *buf, u32 buflen);
int __devinit mvs_hw_init(struct mvs_info *mvi);
void __devinit mvs_print_info(struct mvs_info *mvi);
void mvs_hba_interrupt_enable(struct mvs_info *mvi);
void mvs_hba_interrupt_disable(struct mvs_info *mvi);
void mvs_detect_porttype(struct mvs_info *mvi, int i);
u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port);
void mvs_enable_xmt(struct mvs_info *mvi, int PhyId);
void __devinit mvs_phy_hacks(struct mvs_info *mvi);
void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment