diff options
author | Jeff Garzik <jeff@garzik.org> | 2009-05-08 17:44:01 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-05-20 18:21:12 -0400 |
commit | dd4969a892ea522ecf9d7d826ba1531ce044d46f (patch) | |
tree | 262978c450f749b3df5cb575feeb39bc982289ae /drivers/scsi | |
parent | 2ad52f473bbc1aa5b33c4a329b8a359f125e19d1 (diff) |
[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: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/mvsas/Makefile | 5 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_64xx.c | 184 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_64xx.h | 92 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_chips.h | 118 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_defs.h | 441 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_init.c | 524 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_sas.c | 2816 | ||||
-rw-r--r-- | drivers/scsi/mvsas/mv_sas.h | 205 |
8 files changed, 2273 insertions, 2112 deletions
diff --git a/drivers/scsi/mvsas/Makefile b/drivers/scsi/mvsas/Makefile index 1ac6ed955a04..a1ca681e1a57 100644 --- a/drivers/scsi/mvsas/Makefile +++ b/drivers/scsi/mvsas/Makefile | |||
@@ -22,5 +22,6 @@ | |||
22 | # USA | 22 | # USA |
23 | 23 | ||
24 | obj-$(CONFIG_SCSI_MVSAS) += mvsas.o | 24 | obj-$(CONFIG_SCSI_MVSAS) += mvsas.o |
25 | mvsas-y += mv_sas.o | 25 | mvsas-y += mv_init.o \ |
26 | 26 | mv_sas.o \ | |
27 | mv_64xx.o | ||
diff --git a/drivers/scsi/mvsas/mv_64xx.c b/drivers/scsi/mvsas/mv_64xx.c new file mode 100644 index 000000000000..697806c856af --- /dev/null +++ b/drivers/scsi/mvsas/mv_64xx.c | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | mv_64xx.c - Marvell 88SE6440 SAS/SATA support | ||
3 | |||
4 | Copyright 2007 Red Hat, Inc. | ||
5 | Copyright 2008 Marvell. <kewei@marvell.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or | ||
8 | modify it under the terms of the GNU General Public License as | ||
9 | published by the Free Software Foundation; either version 2, | ||
10 | or (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty | ||
14 | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | See the GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public | ||
18 | License along with this program; see the file COPYING. If not, | ||
19 | write to the Free Software Foundation, 675 Mass Ave, Cambridge, | ||
20 | MA 02139, USA. | ||
21 | |||
22 | */ | ||
23 | |||
24 | #include "mv_sas.h" | ||
25 | #include "mv_64xx.h" | ||
26 | #include "mv_chips.h" | ||
27 | |||
28 | void mvs_detect_porttype(struct mvs_info *mvi, int i) | ||
29 | { | ||
30 | void __iomem *regs = mvi->regs; | ||
31 | u32 reg; | ||
32 | struct mvs_phy *phy = &mvi->phy[i]; | ||
33 | |||
34 | /* TODO check & save device type */ | ||
35 | reg = mr32(GBL_PORT_TYPE); | ||
36 | |||
37 | if (reg & MODE_SAS_SATA & (1 << i)) | ||
38 | phy->phy_type |= PORT_TYPE_SAS; | ||
39 | else | ||
40 | phy->phy_type |= PORT_TYPE_SATA; | ||
41 | } | ||
42 | |||
43 | void mvs_enable_xmt(struct mvs_info *mvi, int PhyId) | ||
44 | { | ||
45 | void __iomem *regs = mvi->regs; | ||
46 | u32 tmp; | ||
47 | |||
48 | tmp = mr32(PCS); | ||
49 | if (mvi->chip->n_phy <= 4) | ||
50 | tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT); | ||
51 | else | ||
52 | tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2); | ||
53 | mw32(PCS, tmp); | ||
54 | } | ||
55 | |||
56 | void __devinit mvs_phy_hacks(struct mvs_info *mvi) | ||
57 | { | ||
58 | void __iomem *regs = mvi->regs; | ||
59 | u32 tmp; | ||
60 | |||
61 | /* workaround for SATA R-ERR, to ignore phy glitch */ | ||
62 | tmp = mvs_cr32(regs, CMD_PHY_TIMER); | ||
63 | tmp &= ~(1 << 9); | ||
64 | tmp |= (1 << 10); | ||
65 | mvs_cw32(regs, CMD_PHY_TIMER, tmp); | ||
66 | |||
67 | /* enable retry 127 times */ | ||
68 | mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f); | ||
69 | |||
70 | /* extend open frame timeout to max */ | ||
71 | tmp = mvs_cr32(regs, CMD_SAS_CTL0); | ||
72 | tmp &= ~0xffff; | ||
73 | tmp |= 0x3fff; | ||
74 | mvs_cw32(regs, CMD_SAS_CTL0, tmp); | ||
75 | |||
76 | /* workaround for WDTIMEOUT , set to 550 ms */ | ||
77 | mvs_cw32(regs, CMD_WD_TIMER, 0x86470); | ||
78 | |||
79 | /* not to halt for different port op during wideport link change */ | ||
80 | mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d); | ||
81 | |||
82 | /* workaround for Seagate disk not-found OOB sequence, recv | ||
83 | * COMINIT before sending out COMWAKE */ | ||
84 | tmp = mvs_cr32(regs, CMD_PHY_MODE_21); | ||
85 | tmp &= 0x0000ffff; | ||
86 | tmp |= 0x00fa0000; | ||
87 | mvs_cw32(regs, CMD_PHY_MODE_21, tmp); | ||
88 | |||
89 | tmp = mvs_cr32(regs, CMD_PHY_TIMER); | ||
90 | tmp &= 0x1fffffff; | ||
91 | tmp |= (2U << 29); /* 8 ms retry */ | ||
92 | mvs_cw32(regs, CMD_PHY_TIMER, tmp); | ||
93 | |||
94 | /* TEST - for phy decoding error, adjust voltage levels */ | ||
95 | mw32(P0_VSR_ADDR + 0, 0x8); | ||
96 | mw32(P0_VSR_DATA + 0, 0x2F0); | ||
97 | |||
98 | mw32(P0_VSR_ADDR + 8, 0x8); | ||
99 | mw32(P0_VSR_DATA + 8, 0x2F0); | ||
100 | |||
101 | mw32(P0_VSR_ADDR + 16, 0x8); | ||
102 | mw32(P0_VSR_DATA + 16, 0x2F0); | ||
103 | |||
104 | mw32(P0_VSR_ADDR + 24, 0x8); | ||
105 | mw32(P0_VSR_DATA + 24, 0x2F0); | ||
106 | |||
107 | } | ||
108 | |||
109 | void mvs_hba_interrupt_enable(struct mvs_info *mvi) | ||
110 | { | ||
111 | void __iomem *regs = mvi->regs; | ||
112 | u32 tmp; | ||
113 | |||
114 | tmp = mr32(GBL_CTL); | ||
115 | |||
116 | mw32(GBL_CTL, tmp | INT_EN); | ||
117 | } | ||
118 | |||
119 | void mvs_hba_interrupt_disable(struct mvs_info *mvi) | ||
120 | { | ||
121 | void __iomem *regs = mvi->regs; | ||
122 | u32 tmp; | ||
123 | |||
124 | tmp = mr32(GBL_CTL); | ||
125 | |||
126 | mw32(GBL_CTL, tmp & ~INT_EN); | ||
127 | } | ||
128 | |||
129 | void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port) | ||
130 | { | ||
131 | void __iomem *regs = mvi->regs; | ||
132 | u32 tmp, offs; | ||
133 | u8 *tfs = &port->taskfileset; | ||
134 | |||
135 | if (*tfs == MVS_ID_NOT_MAPPED) | ||
136 | return; | ||
137 | |||
138 | offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT); | ||
139 | if (*tfs < 16) { | ||
140 | tmp = mr32(PCS); | ||
141 | mw32(PCS, tmp & ~offs); | ||
142 | } else { | ||
143 | tmp = mr32(CTL); | ||
144 | mw32(CTL, tmp & ~offs); | ||
145 | } | ||
146 | |||
147 | tmp = mr32(INT_STAT_SRS) & (1U << *tfs); | ||
148 | if (tmp) | ||
149 | mw32(INT_STAT_SRS, tmp); | ||
150 | |||
151 | *tfs = MVS_ID_NOT_MAPPED; | ||
152 | } | ||
153 | |||
154 | u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port) | ||
155 | { | ||
156 | int i; | ||
157 | u32 tmp, offs; | ||
158 | void __iomem *regs = mvi->regs; | ||
159 | |||
160 | if (port->taskfileset != MVS_ID_NOT_MAPPED) | ||
161 | return 0; | ||
162 | |||
163 | tmp = mr32(PCS); | ||
164 | |||
165 | for (i = 0; i < mvi->chip->srs_sz; i++) { | ||
166 | if (i == 16) | ||
167 | tmp = mr32(CTL); | ||
168 | offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT); | ||
169 | if (!(tmp & offs)) { | ||
170 | port->taskfileset = i; | ||
171 | |||
172 | if (i < 16) | ||
173 | mw32(PCS, tmp | offs); | ||
174 | else | ||
175 | mw32(CTL, tmp | offs); | ||
176 | tmp = mr32(INT_STAT_SRS) & (1U << i); | ||
177 | if (tmp) | ||
178 | mw32(INT_STAT_SRS, tmp); | ||
179 | return 0; | ||
180 | } | ||
181 | } | ||
182 | return MVS_ID_NOT_MAPPED; | ||
183 | } | ||
184 | |||
diff --git a/drivers/scsi/mvsas/mv_64xx.h b/drivers/scsi/mvsas/mv_64xx.h new file mode 100644 index 000000000000..c9f399ebc926 --- /dev/null +++ b/drivers/scsi/mvsas/mv_64xx.h | |||
@@ -0,0 +1,92 @@ | |||
1 | #ifndef _MVS64XX_REG_H_ | ||
2 | #define _MVS64XX_REG_H_ | ||
3 | |||
4 | /* enhanced mode registers (BAR4) */ | ||
5 | enum hw_registers { | ||
6 | MVS_GBL_CTL = 0x04, /* global control */ | ||
7 | MVS_GBL_INT_STAT = 0x08, /* global irq status */ | ||
8 | MVS_GBL_PI = 0x0C, /* ports implemented bitmask */ | ||
9 | MVS_GBL_PORT_TYPE = 0xa0, /* port type */ | ||
10 | |||
11 | MVS_CTL = 0x100, /* SAS/SATA port configuration */ | ||
12 | MVS_PCS = 0x104, /* SAS/SATA port control/status */ | ||
13 | MVS_CMD_LIST_LO = 0x108, /* cmd list addr */ | ||
14 | MVS_CMD_LIST_HI = 0x10C, | ||
15 | MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */ | ||
16 | MVS_RX_FIS_HI = 0x114, | ||
17 | |||
18 | MVS_TX_CFG = 0x120, /* TX configuration */ | ||
19 | MVS_TX_LO = 0x124, /* TX (delivery) ring addr */ | ||
20 | MVS_TX_HI = 0x128, | ||
21 | |||
22 | MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */ | ||
23 | MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */ | ||
24 | MVS_RX_CFG = 0x134, /* RX configuration */ | ||
25 | MVS_RX_LO = 0x138, /* RX (completion) ring addr */ | ||
26 | MVS_RX_HI = 0x13C, | ||
27 | MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */ | ||
28 | |||
29 | MVS_INT_COAL = 0x148, /* Int coalescing config */ | ||
30 | MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */ | ||
31 | MVS_INT_STAT = 0x150, /* Central int status */ | ||
32 | MVS_INT_MASK = 0x154, /* Central int enable */ | ||
33 | MVS_INT_STAT_SRS = 0x158, /* SATA register set status */ | ||
34 | MVS_INT_MASK_SRS = 0x15C, | ||
35 | |||
36 | /* ports 1-3 follow after this */ | ||
37 | MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */ | ||
38 | MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */ | ||
39 | MVS_P4_INT_STAT = 0x200, /* Port 4 interrupt status */ | ||
40 | MVS_P4_INT_MASK = 0x204, /* Port 4 interrupt enable mask */ | ||
41 | |||
42 | /* ports 1-3 follow after this */ | ||
43 | MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */ | ||
44 | MVS_P4_SER_CTLSTAT = 0x220, /* port4 serial control/status */ | ||
45 | |||
46 | MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */ | ||
47 | MVS_CMD_DATA = 0x1BC, /* Command register port (data) */ | ||
48 | |||
49 | /* ports 1-3 follow after this */ | ||
50 | MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */ | ||
51 | MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */ | ||
52 | MVS_P4_CFG_ADDR = 0x230, /* Port 4 config address */ | ||
53 | MVS_P4_CFG_DATA = 0x234, /* Port 4 config data */ | ||
54 | |||
55 | /* ports 1-3 follow after this */ | ||
56 | MVS_P0_VSR_ADDR = 0x1E0, /* port0 VSR address */ | ||
57 | MVS_P0_VSR_DATA = 0x1E4, /* port0 VSR data */ | ||
58 | MVS_P4_VSR_ADDR = 0x250, /* port 4 VSR addr */ | ||
59 | MVS_P4_VSR_DATA = 0x254, /* port 4 VSR data */ | ||
60 | }; | ||
61 | |||
62 | enum pci_cfg_registers { | ||
63 | PCR_PHY_CTL = 0x40, | ||
64 | PCR_PHY_CTL2 = 0x90, | ||
65 | PCR_DEV_CTRL = 0xE8, | ||
66 | }; | ||
67 | |||
68 | /* SAS/SATA Vendor Specific Port Registers */ | ||
69 | enum sas_sata_vsp_regs { | ||
70 | VSR_PHY_STAT = 0x00, /* Phy Status */ | ||
71 | VSR_PHY_MODE1 = 0x01, /* phy tx */ | ||
72 | VSR_PHY_MODE2 = 0x02, /* tx scc */ | ||
73 | VSR_PHY_MODE3 = 0x03, /* pll */ | ||
74 | VSR_PHY_MODE4 = 0x04, /* VCO */ | ||
75 | VSR_PHY_MODE5 = 0x05, /* Rx */ | ||
76 | VSR_PHY_MODE6 = 0x06, /* CDR */ | ||
77 | VSR_PHY_MODE7 = 0x07, /* Impedance */ | ||
78 | VSR_PHY_MODE8 = 0x08, /* Voltage */ | ||
79 | VSR_PHY_MODE9 = 0x09, /* Test */ | ||
80 | VSR_PHY_MODE10 = 0x0A, /* Power */ | ||
81 | VSR_PHY_MODE11 = 0x0B, /* Phy Mode */ | ||
82 | VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */ | ||
83 | VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */ | ||
84 | }; | ||
85 | |||
86 | struct mvs_prd { | ||
87 | __le64 addr; /* 64-bit buffer address */ | ||
88 | __le32 reserved; | ||
89 | __le32 len; /* 16-bit length */ | ||
90 | }; | ||
91 | |||
92 | #endif | ||
diff --git a/drivers/scsi/mvsas/mv_chips.h b/drivers/scsi/mvsas/mv_chips.h new file mode 100644 index 000000000000..cf74b7a3f643 --- /dev/null +++ b/drivers/scsi/mvsas/mv_chips.h | |||
@@ -0,0 +1,118 @@ | |||
1 | #ifndef _MV_CHIPS_H_ | ||
2 | #define _MV_CHIPS_H_ | ||
3 | |||
4 | #define mr32(reg) readl(regs + MVS_##reg) | ||
5 | #define mw32(reg,val) writel((val), regs + MVS_##reg) | ||
6 | #define mw32_f(reg,val) do { \ | ||
7 | writel((val), regs + MVS_##reg); \ | ||
8 | readl(regs + MVS_##reg); \ | ||
9 | } while (0) | ||
10 | |||
11 | static inline u32 mvs_cr32(void __iomem *regs, u32 addr) | ||
12 | { | ||
13 | mw32(CMD_ADDR, addr); | ||
14 | return mr32(CMD_DATA); | ||
15 | } | ||
16 | |||
17 | static inline void mvs_cw32(void __iomem *regs, u32 addr, u32 val) | ||
18 | { | ||
19 | mw32(CMD_ADDR, addr); | ||
20 | mw32(CMD_DATA, val); | ||
21 | } | ||
22 | |||
23 | static inline u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port) | ||
24 | { | ||
25 | void __iomem *regs = mvi->regs; | ||
26 | return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4): | ||
27 | mr32(P4_SER_CTLSTAT + (port - 4) * 4); | ||
28 | } | ||
29 | |||
30 | static inline void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val) | ||
31 | { | ||
32 | void __iomem *regs = mvi->regs; | ||
33 | if (port < 4) | ||
34 | mw32(P0_SER_CTLSTAT + port * 4, val); | ||
35 | else | ||
36 | mw32(P4_SER_CTLSTAT + (port - 4) * 4, val); | ||
37 | } | ||
38 | |||
39 | static inline u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port) | ||
40 | { | ||
41 | void __iomem *regs = mvi->regs + off; | ||
42 | void __iomem *regs2 = mvi->regs + off2; | ||
43 | return (port < 4)?readl(regs + port * 8): | ||
44 | readl(regs2 + (port - 4) * 8); | ||
45 | } | ||
46 | |||
47 | static inline void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2, | ||
48 | u32 port, u32 val) | ||
49 | { | ||
50 | void __iomem *regs = mvi->regs + off; | ||
51 | void __iomem *regs2 = mvi->regs + off2; | ||
52 | if (port < 4) | ||
53 | writel(val, regs + port * 8); | ||
54 | else | ||
55 | writel(val, regs2 + (port - 4) * 8); | ||
56 | } | ||
57 | |||
58 | static inline u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port) | ||
59 | { | ||
60 | return mvs_read_port(mvi, MVS_P0_CFG_DATA, | ||
61 | MVS_P4_CFG_DATA, port); | ||
62 | } | ||
63 | |||
64 | static inline void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val) | ||
65 | { | ||
66 | mvs_write_port(mvi, MVS_P0_CFG_DATA, | ||
67 | MVS_P4_CFG_DATA, port, val); | ||
68 | } | ||
69 | |||
70 | static inline void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr) | ||
71 | { | ||
72 | mvs_write_port(mvi, MVS_P0_CFG_ADDR, | ||
73 | MVS_P4_CFG_ADDR, port, addr); | ||
74 | } | ||
75 | |||
76 | static inline u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port) | ||
77 | { | ||
78 | return mvs_read_port(mvi, MVS_P0_VSR_DATA, | ||
79 | MVS_P4_VSR_DATA, port); | ||
80 | } | ||
81 | |||
82 | static inline void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val) | ||
83 | { | ||
84 | mvs_write_port(mvi, MVS_P0_VSR_DATA, | ||
85 | MVS_P4_VSR_DATA, port, val); | ||
86 | } | ||
87 | |||
88 | static inline void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr) | ||
89 | { | ||
90 | mvs_write_port(mvi, MVS_P0_VSR_ADDR, | ||
91 | MVS_P4_VSR_ADDR, port, addr); | ||
92 | } | ||
93 | |||
94 | static inline u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port) | ||
95 | { | ||
96 | return mvs_read_port(mvi, MVS_P0_INT_STAT, | ||
97 | MVS_P4_INT_STAT, port); | ||
98 | } | ||
99 | |||
100 | static inline void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val) | ||
101 | { | ||
102 | mvs_write_port(mvi, MVS_P0_INT_STAT, | ||
103 | MVS_P4_INT_STAT, port, val); | ||
104 | } | ||
105 | |||
106 | static inline u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port) | ||
107 | { | ||
108 | return mvs_read_port(mvi, MVS_P0_INT_MASK, | ||
109 | MVS_P4_INT_MASK, port); | ||
110 | } | ||
111 | |||
112 | static inline void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val) | ||
113 | { | ||
114 | mvs_write_port(mvi, MVS_P0_INT_MASK, | ||
115 | MVS_P4_INT_MASK, port, val); | ||
116 | } | ||
117 | |||
118 | #endif | ||
diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h new file mode 100644 index 000000000000..d8e96a3e5a21 --- /dev/null +++ b/drivers/scsi/mvsas/mv_defs.h | |||
@@ -0,0 +1,441 @@ | |||
1 | /* | ||
2 | mv_defs.h - Marvell 88SE6440 SAS/SATA support | ||
3 | |||
4 | Copyright 2007 Red Hat, Inc. | ||
5 | Copyright 2008 Marvell. <kewei@marvell.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or | ||
8 | modify it under the terms of the GNU General Public License as | ||
9 | published by the Free Software Foundation; either version 2, | ||
10 | or (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty | ||
14 | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | See the GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public | ||
18 | License along with this program; see the file COPYING. If not, | ||
19 | write to the Free Software Foundation, 675 Mass Ave, Cambridge, | ||
20 | MA 02139, USA. | ||
21 | |||
22 | */ | ||
23 | |||
24 | #ifndef _MV_DEFS_H_ | ||
25 | #define _MV_DEFS_H_ | ||
26 | |||
27 | /* driver compile-time configuration */ | ||
28 | enum driver_configuration { | ||
29 | MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */ | ||
30 | MVS_RX_RING_SZ = 1024, /* RX ring size (12-bit) */ | ||
31 | /* software requires power-of-2 | ||
32 | ring size */ | ||
33 | |||
34 | MVS_SLOTS = 512, /* command slots */ | ||
35 | MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */ | ||
36 | MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */ | ||
37 | MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */ | ||
38 | MVS_OAF_SZ = 64, /* Open address frame buffer size */ | ||
39 | |||
40 | MVS_RX_FIS_COUNT = 17, /* Optional rx'd FISs (max 17) */ | ||
41 | |||
42 | MVS_QUEUE_SIZE = 30, /* Support Queue depth */ | ||
43 | MVS_CAN_QUEUE = MVS_SLOTS - 1, /* SCSI Queue depth */ | ||
44 | }; | ||
45 | |||
46 | /* unchangeable hardware details */ | ||
47 | enum hardware_details { | ||
48 | MVS_MAX_PHYS = 8, /* max. possible phys */ | ||
49 | MVS_MAX_PORTS = 8, /* max. possible ports */ | ||
50 | MVS_RX_FISL_SZ = 0x400 + (MVS_RX_FIS_COUNT * 0x100), | ||
51 | }; | ||
52 | |||
53 | /* peripheral registers (BAR2) */ | ||
54 | enum peripheral_registers { | ||
55 | SPI_CTL = 0x10, /* EEPROM control */ | ||
56 | SPI_CMD = 0x14, /* EEPROM command */ | ||
57 | SPI_DATA = 0x18, /* EEPROM data */ | ||
58 | }; | ||
59 | |||
60 | enum peripheral_register_bits { | ||
61 | TWSI_RDY = (1U << 7), /* EEPROM interface ready */ | ||
62 | TWSI_RD = (1U << 4), /* EEPROM read access */ | ||
63 | |||
64 | SPI_ADDR_MASK = 0x3ffff, /* bits 17:0 */ | ||
65 | }; | ||
66 | |||
67 | enum hw_register_bits { | ||
68 | /* MVS_GBL_CTL */ | ||
69 | INT_EN = (1U << 1), /* Global int enable */ | ||
70 | HBA_RST = (1U << 0), /* HBA reset */ | ||
71 | |||
72 | /* MVS_GBL_INT_STAT */ | ||
73 | INT_XOR = (1U << 4), /* XOR engine event */ | ||
74 | INT_SAS_SATA = (1U << 0), /* SAS/SATA event */ | ||
75 | |||
76 | /* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */ | ||
77 | SATA_TARGET = (1U << 16), /* port0 SATA target enable */ | ||
78 | MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */ | ||
79 | MODE_AUTO_DET_PORT6 = (1U << 14), | ||
80 | MODE_AUTO_DET_PORT5 = (1U << 13), | ||
81 | MODE_AUTO_DET_PORT4 = (1U << 12), | ||
82 | MODE_AUTO_DET_PORT3 = (1U << 11), | ||
83 | MODE_AUTO_DET_PORT2 = (1U << 10), | ||
84 | MODE_AUTO_DET_PORT1 = (1U << 9), | ||
85 | MODE_AUTO_DET_PORT0 = (1U << 8), | ||
86 | MODE_AUTO_DET_EN = MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 | | ||
87 | MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 | | ||
88 | MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 | | ||
89 | MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7, | ||
90 | MODE_SAS_PORT7_MASK = (1U << 7), /* port0 SAS(1), SATA(0) mode */ | ||
91 | MODE_SAS_PORT6_MASK = (1U << 6), | ||
92 | MODE_SAS_PORT5_MASK = (1U << 5), | ||
93 | MODE_SAS_PORT4_MASK = (1U << 4), | ||
94 | MODE_SAS_PORT3_MASK = (1U << 3), | ||
95 | MODE_SAS_PORT2_MASK = (1U << 2), | ||
96 | MODE_SAS_PORT1_MASK = (1U << 1), | ||
97 | MODE_SAS_PORT0_MASK = (1U << 0), | ||
98 | MODE_SAS_SATA = MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK | | ||
99 | MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK | | ||
100 | MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK | | ||
101 | MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK, | ||
102 | |||
103 | /* SAS_MODE value may be | ||
104 | * dictated (in hw) by values | ||
105 | * of SATA_TARGET & AUTO_DET | ||
106 | */ | ||
107 | |||
108 | /* MVS_TX_CFG */ | ||
109 | TX_EN = (1U << 16), /* Enable TX */ | ||
110 | TX_RING_SZ_MASK = 0xfff, /* TX ring size, bits 11:0 */ | ||
111 | |||
112 | /* MVS_RX_CFG */ | ||
113 | RX_EN = (1U << 16), /* Enable RX */ | ||
114 | RX_RING_SZ_MASK = 0xfff, /* RX ring size, bits 11:0 */ | ||
115 | |||
116 | /* MVS_INT_COAL */ | ||
117 | COAL_EN = (1U << 16), /* Enable int coalescing */ | ||
118 | |||
119 | /* MVS_INT_STAT, MVS_INT_MASK */ | ||
120 | CINT_I2C = (1U << 31), /* I2C event */ | ||
121 | CINT_SW0 = (1U << 30), /* software event 0 */ | ||
122 | CINT_SW1 = (1U << 29), /* software event 1 */ | ||
123 | CINT_PRD_BC = (1U << 28), /* PRD BC err for read cmd */ | ||
124 | CINT_DMA_PCIE = (1U << 27), /* DMA to PCIE timeout */ | ||
125 | CINT_MEM = (1U << 26), /* int mem parity err */ | ||
126 | CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */ | ||
127 | CINT_SRS = (1U << 3), /* SRS event */ | ||
128 | CINT_CI_STOP = (1U << 1), /* cmd issue stopped */ | ||
129 | CINT_DONE = (1U << 0), /* cmd completion */ | ||
130 | |||
131 | /* shl for ports 1-3 */ | ||
132 | CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */ | ||
133 | CINT_PORT = (1U << 8), /* port0 event */ | ||
134 | CINT_PORT_MASK_OFFSET = 8, | ||
135 | CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET), | ||
136 | |||
137 | /* TX (delivery) ring bits */ | ||
138 | TXQ_CMD_SHIFT = 29, | ||
139 | TXQ_CMD_SSP = 1, /* SSP protocol */ | ||
140 | TXQ_CMD_SMP = 2, /* SMP protocol */ | ||
141 | TXQ_CMD_STP = 3, /* STP/SATA protocol */ | ||
142 | TXQ_CMD_SSP_FREE_LIST = 4, /* add to SSP targ free list */ | ||
143 | TXQ_CMD_SLOT_RESET = 7, /* reset command slot */ | ||
144 | TXQ_MODE_I = (1U << 28), /* mode: 0=target,1=initiator */ | ||
145 | TXQ_PRIO_HI = (1U << 27), /* priority: 0=normal, 1=high */ | ||
146 | TXQ_SRS_SHIFT = 20, /* SATA register set */ | ||
147 | TXQ_SRS_MASK = 0x7f, | ||
148 | TXQ_PHY_SHIFT = 12, /* PHY bitmap */ | ||
149 | TXQ_PHY_MASK = 0xff, | ||
150 | TXQ_SLOT_MASK = 0xfff, /* slot number */ | ||
151 | |||
152 | /* RX (completion) ring bits */ | ||
153 | RXQ_GOOD = (1U << 23), /* Response good */ | ||
154 | RXQ_SLOT_RESET = (1U << 21), /* Slot reset complete */ | ||
155 | RXQ_CMD_RX = (1U << 20), /* target cmd received */ | ||
156 | RXQ_ATTN = (1U << 19), /* attention */ | ||
157 | RXQ_RSP = (1U << 18), /* response frame xfer'd */ | ||
158 | RXQ_ERR = (1U << 17), /* err info rec xfer'd */ | ||
159 | RXQ_DONE = (1U << 16), /* cmd complete */ | ||
160 | RXQ_SLOT_MASK = 0xfff, /* slot number */ | ||
161 | |||
162 | /* mvs_cmd_hdr bits */ | ||
163 | MCH_PRD_LEN_SHIFT = 16, /* 16-bit PRD table len */ | ||
164 | MCH_SSP_FR_TYPE_SHIFT = 13, /* SSP frame type */ | ||
165 | |||
166 | /* SSP initiator only */ | ||
167 | MCH_SSP_FR_CMD = 0x0, /* COMMAND frame */ | ||
168 | |||
169 | /* SSP initiator or target */ | ||
170 | MCH_SSP_FR_TASK = 0x1, /* TASK frame */ | ||
171 | |||
172 | /* SSP target only */ | ||
173 | MCH_SSP_FR_XFER_RDY = 0x4, /* XFER_RDY frame */ | ||
174 | MCH_SSP_FR_RESP = 0x5, /* RESPONSE frame */ | ||
175 | MCH_SSP_FR_READ = 0x6, /* Read DATA frame(s) */ | ||
176 | MCH_SSP_FR_READ_RESP = 0x7, /* ditto, plus RESPONSE */ | ||
177 | |||
178 | MCH_PASSTHRU = (1U << 12), /* pass-through (SSP) */ | ||
179 | MCH_FBURST = (1U << 11), /* first burst (SSP) */ | ||
180 | MCH_CHK_LEN = (1U << 10), /* chk xfer len (SSP) */ | ||
181 | MCH_RETRY = (1U << 9), /* tport layer retry (SSP) */ | ||
182 | MCH_PROTECTION = (1U << 8), /* protection info rec (SSP) */ | ||
183 | MCH_RESET = (1U << 7), /* Reset (STP/SATA) */ | ||
184 | MCH_FPDMA = (1U << 6), /* First party DMA (STP/SATA) */ | ||
185 | MCH_ATAPI = (1U << 5), /* ATAPI (STP/SATA) */ | ||
186 | MCH_BIST = (1U << 4), /* BIST activate (STP/SATA) */ | ||
187 | MCH_PMP_MASK = 0xf, /* PMP from cmd FIS (STP/SATA)*/ | ||
188 | |||
189 | CCTL_RST = (1U << 5), /* port logic reset */ | ||
190 | |||
191 | /* 0(LSB first), 1(MSB first) */ | ||
192 | CCTL_ENDIAN_DATA = (1U << 3), /* PRD data */ | ||
193 | CCTL_ENDIAN_RSP = (1U << 2), /* response frame */ | ||
194 | CCTL_ENDIAN_OPEN = (1U << 1), /* open address frame */ | ||
195 | CCTL_ENDIAN_CMD = (1U << 0), /* command table */ | ||
196 | |||
197 | /* MVS_Px_SER_CTLSTAT (per-phy control) */ | ||
198 | PHY_SSP_RST = (1U << 3), /* reset SSP link layer */ | ||
199 | PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */ | ||
200 | PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */ | ||
201 | PHY_RST = (1U << 0), /* phy reset */ | ||
202 | PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8), | ||
203 | PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12), | ||
204 | PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16), | ||
205 | PHY_NEG_SPP_PHYS_LINK_RATE_MASK = | ||
206 | (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET), | ||
207 | PHY_READY_MASK = (1U << 20), | ||
208 | |||
209 | /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */ | ||
210 | PHYEV_DEC_ERR = (1U << 24), /* Phy Decoding Error */ | ||
211 | PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */ | ||
212 | PHYEV_AN = (1U << 18), /* SATA async notification */ | ||
213 | PHYEV_BIST_ACT = (1U << 17), /* BIST activate FIS */ | ||
214 | PHYEV_SIG_FIS = (1U << 16), /* signature FIS */ | ||
215 | PHYEV_POOF = (1U << 12), /* phy ready from 1 -> 0 */ | ||
216 | PHYEV_IU_BIG = (1U << 11), /* IU too long err */ | ||
217 | PHYEV_IU_SMALL = (1U << 10), /* IU too short err */ | ||
218 | PHYEV_UNK_TAG = (1U << 9), /* unknown tag */ | ||
219 | PHYEV_BROAD_CH = (1U << 8), /* broadcast(CHANGE) */ | ||
220 | PHYEV_COMWAKE = (1U << 7), /* COMWAKE rx'd */ | ||
221 | PHYEV_PORT_SEL = (1U << 6), /* port selector present */ | ||
222 | PHYEV_HARD_RST = (1U << 5), /* hard reset rx'd */ | ||
223 | PHYEV_ID_TMOUT = (1U << 4), /* identify timeout */ | ||
224 | PHYEV_ID_FAIL = (1U << 3), /* identify failed */ | ||
225 | PHYEV_ID_DONE = (1U << 2), /* identify done */ | ||
226 | PHYEV_HARD_RST_DONE = (1U << 1), /* hard reset done */ | ||
227 | PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */ | ||
228 | |||
229 | /* MVS_PCS */ | ||
230 | PCS_EN_SATA_REG_SHIFT = (16), /* Enable SATA Register Set */ | ||
231 | PCS_EN_PORT_XMT_SHIFT = (12), /* Enable Port Transmit */ | ||
232 | PCS_EN_PORT_XMT_SHIFT2 = (8), /* For 6480 */ | ||
233 | PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */ | ||
234 | PCS_RSP_RX_EN = (1U << 7), /* raw response rx */ | ||
235 | PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */ | ||
236 | PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */ | ||
237 | PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */ | ||
238 | PCS_CMD_RST = (1U << 1), /* reset cmd issue */ | ||
239 | PCS_CMD_EN = (1U << 0), /* enable cmd issue */ | ||
240 | |||
241 | /* Port n Attached Device Info */ | ||
242 | PORT_DEV_SSP_TRGT = (1U << 19), | ||
243 | PORT_DEV_SMP_TRGT = (1U << 18), | ||
244 | PORT_DEV_STP_TRGT = (1U << 17), | ||
245 | PORT_DEV_SSP_INIT = (1U << 11), | ||
246 | PORT_DEV_SMP_INIT = (1U << 10), | ||
247 | PORT_DEV_STP_INIT = (1U << 9), | ||
248 | PORT_PHY_ID_MASK = (0xFFU << 24), | ||
249 | PORT_DEV_TRGT_MASK = (0x7U << 17), | ||
250 | PORT_DEV_INIT_MASK = (0x7U << 9), | ||
251 | PORT_DEV_TYPE_MASK = (0x7U << 0), | ||
252 | |||
253 | /* Port n PHY Status */ | ||
254 | PHY_RDY = (1U << 2), | ||
255 | PHY_DW_SYNC = (1U << 1), | ||
256 | PHY_OOB_DTCTD = (1U << 0), | ||
257 | |||
258 | /* VSR */ | ||
259 | /* PHYMODE 6 (CDB) */ | ||
260 | PHY_MODE6_LATECLK = (1U << 29), /* Lock Clock */ | ||
261 | PHY_MODE6_DTL_SPEED = (1U << 27), /* Digital Loop Speed */ | ||
262 | PHY_MODE6_FC_ORDER = (1U << 26), /* Fibre Channel Mode Order*/ | ||
263 | PHY_MODE6_MUCNT_EN = (1U << 24), /* u Count Enable */ | ||
264 | PHY_MODE6_SEL_MUCNT_LEN = (1U << 22), /* Training Length Select */ | ||
265 | PHY_MODE6_SELMUPI = (1U << 20), /* Phase Multi Select (init) */ | ||
266 | PHY_MODE6_SELMUPF = (1U << 18), /* Phase Multi Select (final) */ | ||
267 | PHY_MODE6_SELMUFF = (1U << 16), /* Freq Loop Multi Sel(final) */ | ||
268 | PHY_MODE6_SELMUFI = (1U << 14), /* Freq Loop Multi Sel(init) */ | ||
269 | PHY_MODE6_FREEZE_LOOP = (1U << 12), /* Freeze Rx CDR Loop */ | ||
270 | PHY_MODE6_INT_RXFOFFS = (1U << 3), /* Rx CDR Freq Loop Enable */ | ||
271 | PHY_MODE6_FRC_RXFOFFS = (1U << 2), /* Initial Rx CDR Offset */ | ||
272 | PHY_MODE6_STAU_0D8 = (1U << 1), /* Rx CDR Freq Loop Saturate */ | ||
273 | PHY_MODE6_RXSAT_DIS = (1U << 0), /* Saturate Ctl */ | ||
274 | }; | ||
275 | |||
276 | /* SAS/SATA configuration port registers, aka phy registers */ | ||
277 | enum sas_sata_config_port_regs { | ||
278 | PHYR_IDENTIFY = 0x00, /* info for IDENTIFY frame */ | ||
279 | PHYR_ADDR_LO = 0x04, /* my SAS address (low) */ | ||
280 | PHYR_ADDR_HI = 0x08, /* my SAS address (high) */ | ||
281 | PHYR_ATT_DEV_INFO = 0x0C, /* attached device info */ | ||
282 | PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */ | ||
283 | PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */ | ||
284 | PHYR_SATA_CTL = 0x18, /* SATA control */ | ||
285 | PHYR_PHY_STAT = 0x1C, /* PHY status */ | ||
286 | PHYR_SATA_SIG0 = 0x20, /*port SATA signature FIS(Byte 0-3) */ | ||
287 | PHYR_SATA_SIG1 = 0x24, /*port SATA signature FIS(Byte 4-7) */ | ||
288 | PHYR_SATA_SIG2 = 0x28, /*port SATA signature FIS(Byte 8-11) */ | ||
289 | PHYR_SATA_SIG3 = 0x2c, /*port SATA signature FIS(Byte 12-15) */ | ||
290 | PHYR_R_ERR_COUNT = 0x30, /* port R_ERR count register */ | ||
291 | PHYR_CRC_ERR_COUNT = 0x34, /* port CRC error count register */ | ||
292 | PHYR_WIDE_PORT = 0x38, /* wide port participating */ | ||
293 | PHYR_CURRENT0 = 0x80, /* current connection info 0 */ | ||
294 | PHYR_CURRENT1 = 0x84, /* current connection info 1 */ | ||
295 | PHYR_CURRENT2 = 0x88, /* current connection info 2 */ | ||
296 | }; | ||
297 | |||
298 | enum mvs_info_flags { | ||
299 | MVF_MSI = (1U << 0), /* MSI is enabled */ | ||
300 | MVF_PHY_PWR_FIX = (1U << 1), /* bug workaround */ | ||
301 | }; | ||
302 | |||
303 | enum sas_cmd_port_registers { | ||
304 | CMD_CMRST_OOB_DET = 0x100, /* COMRESET OOB detect register */ | ||
305 | CMD_CMWK_OOB_DET = 0x104, /* COMWAKE OOB detect register */ | ||
306 | CMD_CMSAS_OOB_DET = 0x108, /* COMSAS OOB detect register */ | ||
307 | CMD_BRST_OOB_DET = 0x10c, /* burst OOB detect register */ | ||
308 | CMD_OOB_SPACE = 0x110, /* OOB space control register */ | ||
309 | CMD_OOB_BURST = 0x114, /* OOB burst control register */ | ||
310 | CMD_PHY_TIMER = 0x118, /* PHY timer control register */ | ||
311 | CMD_PHY_CONFIG0 = 0x11c, /* PHY config register 0 */ | ||
312 | CMD_PHY_CONFIG1 = 0x120, /* PHY config register 1 */ | ||
313 | CMD_SAS_CTL0 = 0x124, /* SAS control register 0 */ | ||
314 | CMD_SAS_CTL1 = 0x128, /* SAS control register 1 */ | ||
315 | CMD_SAS_CTL2 = 0x12c, /* SAS control register 2 */ | ||
316 | CMD_SAS_CTL3 = 0x130, /* SAS control register 3 */ | ||
317 | CMD_ID_TEST = 0x134, /* ID test register */ | ||
318 | CMD_PL_TIMER = 0x138, /* PL timer register */ | ||
319 | CMD_WD_TIMER = 0x13c, /* WD timer register */ | ||
320 | CMD_PORT_SEL_COUNT = 0x140, /* port selector count register */ | ||
321 | CMD_APP_MEM_CTL = 0x144, /* Application Memory Control */ | ||
322 | CMD_XOR_MEM_CTL = 0x148, /* XOR Block Memory Control */ | ||
323 | CMD_DMA_MEM_CTL = 0x14c, /* DMA Block Memory Control */ | ||
324 | CMD_PORT_MEM_CTL0 = 0x150, /* Port Memory Control 0 */ | ||
325 | CMD_PORT_MEM_CTL1 = 0x154, /* Port Memory Control 1 */ | ||
326 | CMD_SATA_PORT_MEM_CTL0 = 0x158, /* SATA Port Memory Control 0 */ | ||
327 | CMD_SATA_PORT_MEM_CTL1 = 0x15c, /* SATA Port Memory Control 1 */ | ||
328 | CMD_XOR_MEM_BIST_CTL = 0x160, /* XOR Memory BIST Control */ | ||
329 | CMD_XOR_MEM_BIST_STAT = 0x164, /* XOR Memroy BIST Status */ | ||
330 | CMD_DMA_MEM_BIST_CTL = 0x168, /* DMA Memory BIST Control */ | ||
331 | CMD_DMA_MEM_BIST_STAT = 0x16c, /* DMA Memory BIST Status */ | ||
332 | CMD_PORT_MEM_BIST_CTL = 0x170, /* Port Memory BIST Control */ | ||
333 | CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */ | ||
334 | CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */ | ||
335 | CMD_STP_MEM_BIST_CTL = 0x17c, /* STP Memory BIST Control */ | ||
336 | CMD_STP_MEM_BIST_STAT0 = 0x180, /* STP Memory BIST Status 0 */ | ||
337 | CMD_STP_MEM_BIST_STAT1 = 0x184, /* STP Memory BIST Status 1 */ | ||
338 | CMD_RESET_COUNT = 0x188, /* Reset Count */ | ||
339 | CMD_MONTR_DATA_SEL = 0x18C, /* Monitor Data/Select */ | ||
340 | CMD_PLL_PHY_CONFIG = 0x190, /* PLL/PHY Configuration */ | ||
341 | CMD_PHY_CTL = 0x194, /* PHY Control and Status */ | ||
342 | CMD_PHY_TEST_COUNT0 = 0x198, /* Phy Test Count 0 */ | ||
343 | CMD_PHY_TEST_COUNT1 = 0x19C, /* Phy Test Count 1 */ | ||
344 | CMD_PHY_TEST_COUNT2 = 0x1A0, /* Phy Test Count 2 */ | ||
345 | CMD_APP_ERR_CONFIG = 0x1A4, /* Application Error Configuration */ | ||
346 | CMD_PND_FIFO_CTL0 = 0x1A8, /* Pending FIFO Control 0 */ | ||
347 | CMD_HOST_CTL = 0x1AC, /* Host Control Status */ | ||
348 | CMD_HOST_WR_DATA = 0x1B0, /* Host Write Data */ | ||
349 | CMD_HOST_RD_DATA = 0x1B4, /* Host Read Data */ | ||
350 | CMD_PHY_MODE_21 = 0x1B8, /* Phy Mode 21 */ | ||
351 | CMD_SL_MODE0 = 0x1BC, /* SL Mode 0 */ | ||
352 | CMD_SL_MODE1 = 0x1C0, /* SL Mode 1 */ | ||
353 | CMD_PND_FIFO_CTL1 = 0x1C4, /* Pending FIFO Control 1 */ | ||
354 | }; | ||
355 | |||
356 | enum pci_cfg_register_bits { | ||
357 | PCTL_PWR_ON = (0xFU << 24), | ||
358 | PCTL_OFF = (0xFU << 12), | ||
359 | PRD_REQ_SIZE = (0x4000), | ||
360 | PRD_REQ_MASK = (0x00007000), | ||
361 | }; | ||
362 | |||
363 | enum nvram_layout_offsets { | ||
364 | NVR_SIG = 0x00, /* 0xAA, 0x55 */ | ||
365 | NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */ | ||
366 | }; | ||
367 | |||
368 | enum chip_flavors { | ||
369 | chip_6320, | ||
370 | chip_6440, | ||
371 | chip_6480, | ||
372 | }; | ||
373 | |||
374 | enum port_type { | ||
375 | PORT_TYPE_SAS = (1L << 1), | ||
376 | PORT_TYPE_SATA = (1L << 0), | ||
377 | }; | ||
378 | |||
379 | /* Command Table Format */ | ||
380 | enum ct_format { | ||
381 | /* SSP */ | ||
382 | SSP_F_H = 0x00, | ||
383 | SSP_F_IU = 0x18, | ||
384 | SSP_F_MAX = 0x4D, | ||
385 | /* STP */ | ||
386 | STP_CMD_FIS = 0x00, | ||
387 | STP_ATAPI_CMD = 0x40, | ||
388 | STP_F_MAX = 0x10, | ||
389 | /* SMP */ | ||
390 | SMP_F_T = 0x00, | ||
391 | SMP_F_DEP = 0x01, | ||
392 | SMP_F_MAX = 0x101, | ||
393 | }; | ||
394 | |||
395 | enum status_buffer { | ||
396 | SB_EIR_OFF = 0x00, /* Error Information Record */ | ||
397 | SB_RFB_OFF = 0x08, /* Response Frame Buffer */ | ||
398 | SB_RFB_MAX = 0x400, /* RFB size*/ | ||
399 | }; | ||
400 | |||
401 | enum error_info_rec { | ||
402 | CMD_ISS_STPD = (1U << 31), /* Cmd Issue Stopped */ | ||
403 | CMD_PI_ERR = (1U << 30), /* Protection info error. see flags2 */ | ||
404 | RSP_OVER = (1U << 29), /* rsp buffer overflow */ | ||
405 | RETRY_LIM = (1U << 28), /* FIS/frame retry limit exceeded */ | ||
406 | UNK_FIS = (1U << 27), /* unknown FIS */ | ||
407 | DMA_TERM = (1U << 26), /* DMA terminate primitive rx'd */ | ||
408 | SYNC_ERR = (1U << 25), /* SYNC rx'd during frame xmit */ | ||
409 | TFILE_ERR = (1U << 24), /* SATA taskfile Error bit set */ | ||
410 | R_ERR = (1U << 23), /* SATA returned R_ERR prim */ | ||
411 | RD_OFS = (1U << 20), /* Read DATA frame invalid offset */ | ||
412 | XFER_RDY_OFS = (1U << 19), /* XFER_RDY offset error */ | ||
413 | UNEXP_XFER_RDY = (1U << 18), /* unexpected XFER_RDY error */ | ||
414 | DATA_OVER_UNDER = (1U << 16), /* data overflow/underflow */ | ||
415 | INTERLOCK = (1U << 15), /* interlock error */ | ||
416 | NAK = (1U << 14), /* NAK rx'd */ | ||
417 | ACK_NAK_TO = (1U << 13), /* ACK/NAK timeout */ | ||
418 | CXN_CLOSED = (1U << 12), /* cxn closed w/out ack/nak */ | ||
419 | OPEN_TO = (1U << 11), /* I_T nexus lost, open cxn timeout */ | ||
420 | PATH_BLOCKED = (1U << 10), /* I_T nexus lost, pathway blocked */ | ||
421 | NO_DEST = (1U << 9), /* I_T nexus lost, no destination */ | ||
422 | STP_RES_BSY = (1U << 8), /* STP resources busy */ | ||
423 | BREAK = (1U << 7), /* break received */ | ||
424 | BAD_DEST = (1U << 6), /* bad destination */ | ||
425 | BAD_PROTO = (1U << 5), /* protocol not supported */ | ||
426 | BAD_RATE = (1U << 4), /* cxn rate not supported */ | ||
427 | WRONG_DEST = (1U << 3), /* wrong destination error */ | ||
428 | CREDIT_TO = (1U << 2), /* credit timeout */ | ||
429 | WDOG_TO = (1U << 1), /* watchdog timeout */ | ||
430 | BUF_PAR = (1U << 0), /* buffer parity error */ | ||
431 | }; | ||
432 | |||
433 | enum error_info_rec_2 { | ||
434 | SLOT_BSY_ERR = (1U << 31), /* Slot Busy Error */ | ||
435 | GRD_CHK_ERR = (1U << 14), /* Guard Check Error */ | ||
436 | APP_CHK_ERR = (1U << 13), /* Application Check error */ | ||
437 | REF_CHK_ERR = (1U << 12), /* Reference Check Error */ | ||
438 | USR_BLK_NM = (1U << 0), /* User Block Number */ | ||
439 | }; | ||
440 | |||
441 | #endif | ||
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c new file mode 100644 index 000000000000..258a1a923290 --- /dev/null +++ b/drivers/scsi/mvsas/mv_init.c | |||
@@ -0,0 +1,524 @@ | |||
1 | /* | ||
2 | mv_init.c - Marvell 88SE6440 SAS/SATA init support | ||
3 | |||
4 | Copyright 2007 Red Hat, Inc. | ||
5 | Copyright 2008 Marvell. <kewei@marvell.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or | ||
8 | modify it under the terms of the GNU General Public License as | ||
9 | published by the Free Software Foundation; either version 2, | ||
10 | or (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty | ||
14 | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | See the GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public | ||
18 | License along with this program; see the file COPYING. If not, | ||
19 | write to the Free Software Foundation, 675 Mass Ave, Cambridge, | ||
20 | MA 02139, USA. | ||
21 | |||
22 | */ | ||
23 | |||
24 | #include "mv_sas.h" | ||
25 | #include "mv_64xx.h" | ||
26 | #include "mv_chips.h" | ||
27 | |||
28 | static struct scsi_transport_template *mvs_stt; | ||
29 | |||
30 | static const struct mvs_chip_info mvs_chips[] = { | ||
31 | [chip_6320] = { 2, 16, 9 }, | ||
32 | [chip_6440] = { 4, 16, 9 }, | ||
33 | [chip_6480] = { 8, 32, 10 }, | ||
34 | }; | ||
35 | |||
36 | static struct scsi_host_template mvs_sht = { | ||
37 | .module = THIS_MODULE, | ||
38 | .name = DRV_NAME, | ||
39 | .queuecommand = sas_queuecommand, | ||
40 | .target_alloc = sas_target_alloc, | ||
41 | .slave_configure = mvs_slave_configure, | ||
42 | .slave_destroy = sas_slave_destroy, | ||
43 | .scan_finished = mvs_scan_finished, | ||
44 | .scan_start = mvs_scan_start, | ||
45 | .change_queue_depth = sas_change_queue_depth, | ||
46 | .change_queue_type = sas_change_queue_type, | ||
47 | .bios_param = sas_bios_param, | ||
48 | .can_queue = 1, | ||
49 | .cmd_per_lun = 1, | ||
50 | .this_id = -1, | ||
51 | .sg_tablesize = SG_ALL, | ||
52 | .max_sectors = SCSI_DEFAULT_MAX_SECTORS, | ||
53 | .use_clustering = ENABLE_CLUSTERING, | ||
54 | .eh_device_reset_handler = sas_eh_device_reset_handler, | ||
55 | .eh_bus_reset_handler = sas_eh_bus_reset_handler, | ||
56 | .slave_alloc = sas_slave_alloc, | ||
57 | .target_destroy = sas_target_destroy, | ||
58 | .ioctl = sas_ioctl, | ||
59 | }; | ||
60 | |||
61 | static struct sas_domain_function_template mvs_transport_ops = { | ||
62 | .lldd_execute_task = mvs_task_exec, | ||
63 | .lldd_control_phy = mvs_phy_control, | ||
64 | .lldd_abort_task = mvs_task_abort, | ||
65 | .lldd_port_formed = mvs_port_formed, | ||
66 | .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, | ||
67 | }; | ||
68 | |||
69 | static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) | ||
70 | { | ||
71 | struct mvs_phy *phy = &mvi->phy[phy_id]; | ||
72 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
73 | |||
74 | sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; | ||
75 | sas_phy->class = SAS; | ||
76 | sas_phy->iproto = SAS_PROTOCOL_ALL; | ||
77 | sas_phy->tproto = 0; | ||
78 | sas_phy->type = PHY_TYPE_PHYSICAL; | ||
79 | sas_phy->role = PHY_ROLE_INITIATOR; | ||
80 | sas_phy->oob_mode = OOB_NOT_CONNECTED; | ||
81 | sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; | ||
82 | |||
83 | sas_phy->id = phy_id; | ||
84 | sas_phy->sas_addr = &mvi->sas_addr[0]; | ||
85 | sas_phy->frame_rcvd = &phy->frame_rcvd[0]; | ||
86 | sas_phy->ha = &mvi->sas; | ||
87 | sas_phy->lldd_phy = phy; | ||
88 | } | ||
89 | |||
90 | static void mvs_free(struct mvs_info *mvi) | ||
91 | { | ||
92 | int i; | ||
93 | |||
94 | if (!mvi) | ||
95 | return; | ||
96 | |||
97 | for (i = 0; i < MVS_SLOTS; i++) { | ||
98 | struct mvs_slot_info *slot = &mvi->slot_info[i]; | ||
99 | |||
100 | if (slot->buf) | ||
101 | dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ, | ||
102 | slot->buf, slot->buf_dma); | ||
103 | } | ||
104 | |||
105 | if (mvi->tx) | ||
106 | dma_free_coherent(&mvi->pdev->dev, | ||
107 | sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, | ||
108 | mvi->tx, mvi->tx_dma); | ||
109 | if (mvi->rx_fis) | ||
110 | dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ, | ||
111 | mvi->rx_fis, mvi->rx_fis_dma); | ||
112 | if (mvi->rx) | ||
113 | dma_free_coherent(&mvi->pdev->dev, | ||
114 | sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), | ||
115 | mvi->rx, mvi->rx_dma); | ||
116 | if (mvi->slot) | ||
117 | dma_free_coherent(&mvi->pdev->dev, | ||
118 | sizeof(*mvi->slot) * MVS_SLOTS, | ||
119 | mvi->slot, mvi->slot_dma); | ||
120 | #ifdef MVS_ENABLE_PERI | ||
121 | if (mvi->peri_regs) | ||
122 | iounmap(mvi->peri_regs); | ||
123 | #endif | ||
124 | if (mvi->regs) | ||
125 | iounmap(mvi->regs); | ||
126 | if (mvi->shost) | ||
127 | scsi_host_put(mvi->shost); | ||
128 | kfree(mvi->sas.sas_port); | ||
129 | kfree(mvi->sas.sas_phy); | ||
130 | kfree(mvi); | ||
131 | } | ||
132 | |||
133 | #ifdef MVS_USE_TASKLET | ||
134 | static void mvs_tasklet(unsigned long data) | ||
135 | { | ||
136 | struct mvs_info *mvi = (struct mvs_info *) data; | ||
137 | unsigned long flags; | ||
138 | |||
139 | spin_lock_irqsave(&mvi->lock, flags); | ||
140 | |||
141 | #ifdef MVS_DISABLE_MSI | ||
142 | mvs_int_full(mvi); | ||
143 | #else | ||
144 | mvs_int_rx(mvi, true); | ||
145 | #endif | ||
146 | spin_unlock_irqrestore(&mvi->lock, flags); | ||
147 | } | ||
148 | #endif | ||
149 | |||
150 | static irqreturn_t mvs_interrupt(int irq, void *opaque) | ||
151 | { | ||
152 | struct mvs_info *mvi = opaque; | ||
153 | void __iomem *regs = mvi->regs; | ||
154 | u32 stat; | ||
155 | |||
156 | stat = mr32(GBL_INT_STAT); | ||
157 | |||
158 | if (stat == 0 || stat == 0xffffffff) | ||
159 | return IRQ_NONE; | ||
160 | |||
161 | /* clear CMD_CMPLT ASAP */ | ||
162 | mw32_f(INT_STAT, CINT_DONE); | ||
163 | |||
164 | #ifndef MVS_USE_TASKLET | ||
165 | spin_lock(&mvi->lock); | ||
166 | |||
167 | mvs_int_full(mvi); | ||
168 | |||
169 | spin_unlock(&mvi->lock); | ||
170 | #else | ||
171 | tasklet_schedule(&mvi->tasklet); | ||
172 | #endif | ||
173 | return IRQ_HANDLED; | ||
174 | } | ||
175 | |||
176 | static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev, | ||
177 | const struct pci_device_id *ent) | ||
178 | { | ||
179 | struct mvs_info *mvi; | ||
180 | unsigned long res_start, res_len, res_flag; | ||
181 | struct asd_sas_phy **arr_phy; | ||
182 | struct asd_sas_port **arr_port; | ||
183 | const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data]; | ||
184 | int i; | ||
185 | |||
186 | /* | ||
187 | * alloc and init our per-HBA mvs_info struct | ||
188 | */ | ||
189 | |||
190 | mvi = kzalloc(sizeof(*mvi), GFP_KERNEL); | ||
191 | if (!mvi) | ||
192 | return NULL; | ||
193 | |||
194 | spin_lock_init(&mvi->lock); | ||
195 | #ifdef MVS_USE_TASKLET | ||
196 | tasklet_init(&mvi->tasklet, mvs_tasklet, (unsigned long)mvi); | ||
197 | #endif | ||
198 | mvi->pdev = pdev; | ||
199 | mvi->chip = chip; | ||
200 | |||
201 | if (pdev->device == 0x6440 && pdev->revision == 0) | ||
202 | mvi->flags |= MVF_PHY_PWR_FIX; | ||
203 | |||
204 | /* | ||
205 | * alloc and init SCSI, SAS glue | ||
206 | */ | ||
207 | |||
208 | mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *)); | ||
209 | if (!mvi->shost) | ||
210 | goto err_out; | ||
211 | |||
212 | arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL); | ||
213 | arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL); | ||
214 | if (!arr_phy || !arr_port) | ||
215 | goto err_out; | ||
216 | |||
217 | for (i = 0; i < MVS_MAX_PHYS; i++) { | ||
218 | mvs_phy_init(mvi, i); | ||
219 | arr_phy[i] = &mvi->phy[i].sas_phy; | ||
220 | arr_port[i] = &mvi->port[i].sas_port; | ||
221 | mvi->port[i].taskfileset = MVS_ID_NOT_MAPPED; | ||
222 | mvi->port[i].wide_port_phymap = 0; | ||
223 | mvi->port[i].port_attached = 0; | ||
224 | INIT_LIST_HEAD(&mvi->port[i].list); | ||
225 | } | ||
226 | |||
227 | SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas; | ||
228 | mvi->shost->transportt = mvs_stt; | ||
229 | mvi->shost->max_id = 21; | ||
230 | mvi->shost->max_lun = ~0; | ||
231 | mvi->shost->max_channel = 0; | ||
232 | mvi->shost->max_cmd_len = 16; | ||
233 | |||
234 | mvi->sas.sas_ha_name = DRV_NAME; | ||
235 | mvi->sas.dev = &pdev->dev; | ||
236 | mvi->sas.lldd_module = THIS_MODULE; | ||
237 | mvi->sas.sas_addr = &mvi->sas_addr[0]; | ||
238 | mvi->sas.sas_phy = arr_phy; | ||
239 | mvi->sas.sas_port = arr_port; | ||
240 | mvi->sas.num_phys = chip->n_phy; | ||
241 | mvi->sas.lldd_max_execute_num = 1; | ||
242 | mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE; | ||
243 | mvi->shost->can_queue = MVS_CAN_QUEUE; | ||
244 | mvi->shost->cmd_per_lun = MVS_SLOTS / mvi->sas.num_phys; | ||
245 | mvi->sas.lldd_ha = mvi; | ||
246 | mvi->sas.core.shost = mvi->shost; | ||
247 | |||
248 | mvs_tag_init(mvi); | ||
249 | |||
250 | /* | ||
251 | * ioremap main and peripheral registers | ||
252 | */ | ||
253 | |||
254 | #ifdef MVS_ENABLE_PERI | ||
255 | res_start = pci_resource_start(pdev, 2); | ||
256 | res_len = pci_resource_len(pdev, 2); | ||
257 | if (!res_start || !res_len) | ||
258 | goto err_out; | ||
259 | |||
260 | mvi->peri_regs = ioremap_nocache(res_start, res_len); | ||
261 | if (!mvi->peri_regs) | ||
262 | goto err_out; | ||
263 | #endif | ||
264 | |||
265 | res_start = pci_resource_start(pdev, 4); | ||
266 | res_len = pci_resource_len(pdev, 4); | ||
267 | if (!res_start || !res_len) | ||
268 | goto err_out; | ||
269 | |||
270 | res_flag = pci_resource_flags(pdev, 4); | ||
271 | if (res_flag & IORESOURCE_CACHEABLE) | ||
272 | mvi->regs = ioremap(res_start, res_len); | ||
273 | else | ||
274 | mvi->regs = ioremap_nocache(res_start, res_len); | ||
275 | |||
276 | if (!mvi->regs) | ||
277 | goto err_out; | ||
278 | |||
279 | /* | ||
280 | * alloc and init our DMA areas | ||
281 | */ | ||
282 | |||
283 | mvi->tx = dma_alloc_coherent(&pdev->dev, | ||
284 | sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, | ||
285 | &mvi->tx_dma, GFP_KERNEL); | ||
286 | if (!mvi->tx) | ||
287 | goto err_out; | ||
288 | memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ); | ||
289 | |||
290 | mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ, | ||
291 | &mvi->rx_fis_dma, GFP_KERNEL); | ||
292 | if (!mvi->rx_fis) | ||
293 | goto err_out; | ||
294 | memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ); | ||
295 | |||
296 | mvi->rx = dma_alloc_coherent(&pdev->dev, | ||
297 | sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), | ||
298 | &mvi->rx_dma, GFP_KERNEL); | ||
299 | if (!mvi->rx) | ||
300 | goto err_out; | ||
301 | memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1)); | ||
302 | |||
303 | mvi->rx[0] = cpu_to_le32(0xfff); | ||
304 | mvi->rx_cons = 0xfff; | ||
305 | |||
306 | mvi->slot = dma_alloc_coherent(&pdev->dev, | ||
307 | sizeof(*mvi->slot) * MVS_SLOTS, | ||
308 | &mvi->slot_dma, GFP_KERNEL); | ||
309 | if (!mvi->slot) | ||
310 | goto err_out; | ||
311 | memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS); | ||
312 | |||
313 | for (i = 0; i < MVS_SLOTS; i++) { | ||
314 | struct mvs_slot_info *slot = &mvi->slot_info[i]; | ||
315 | |||
316 | slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ, | ||
317 | &slot->buf_dma, GFP_KERNEL); | ||
318 | if (!slot->buf) | ||
319 | goto err_out; | ||
320 | memset(slot->buf, 0, MVS_SLOT_BUF_SZ); | ||
321 | } | ||
322 | |||
323 | /* finally, read NVRAM to get our SAS address */ | ||
324 | if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8)) | ||
325 | goto err_out; | ||
326 | return mvi; | ||
327 | |||
328 | err_out: | ||
329 | mvs_free(mvi); | ||
330 | return NULL; | ||
331 | } | ||
332 | |||
333 | /* move to PCI layer or libata core? */ | ||
334 | static int pci_go_64(struct pci_dev *pdev) | ||
335 | { | ||
336 | int rc; | ||
337 | |||
338 | if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { | ||
339 | rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); | ||
340 | if (rc) { | ||
341 | rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
342 | if (rc) { | ||
343 | dev_printk(KERN_ERR, &pdev->dev, | ||
344 | "64-bit DMA enable failed\n"); | ||
345 | return rc; | ||
346 | } | ||
347 | } | ||
348 | } else { | ||
349 | rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
350 | if (rc) { | ||
351 | dev_printk(KERN_ERR, &pdev->dev, | ||
352 | "32-bit DMA enable failed\n"); | ||
353 | return rc; | ||
354 | } | ||
355 | rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
356 | if (rc) { | ||
357 | dev_printk(KERN_ERR, &pdev->dev, | ||
358 | "32-bit consistent DMA enable failed\n"); | ||
359 | return rc; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | return rc; | ||
364 | } | ||
365 | |||
366 | static int __devinit mvs_pci_init(struct pci_dev *pdev, | ||
367 | const struct pci_device_id *ent) | ||
368 | { | ||
369 | int rc; | ||
370 | struct mvs_info *mvi; | ||
371 | irq_handler_t irq_handler = mvs_interrupt; | ||
372 | |||
373 | rc = pci_enable_device(pdev); | ||
374 | if (rc) | ||
375 | return rc; | ||
376 | |||
377 | pci_set_master(pdev); | ||
378 | |||
379 | rc = pci_request_regions(pdev, DRV_NAME); | ||
380 | if (rc) | ||
381 | goto err_out_disable; | ||
382 | |||
383 | rc = pci_go_64(pdev); | ||
384 | if (rc) | ||
385 | goto err_out_regions; | ||
386 | |||
387 | mvi = mvs_alloc(pdev, ent); | ||
388 | if (!mvi) { | ||
389 | rc = -ENOMEM; | ||
390 | goto err_out_regions; | ||
391 | } | ||
392 | |||
393 | rc = mvs_hw_init(mvi); | ||
394 | if (rc) | ||
395 | goto err_out_mvi; | ||
396 | |||
397 | #ifndef MVS_DISABLE_MSI | ||
398 | if (!pci_enable_msi(pdev)) { | ||
399 | u32 tmp; | ||
400 | void __iomem *regs = mvi->regs; | ||
401 | mvi->flags |= MVF_MSI; | ||
402 | irq_handler = mvs_msi_interrupt; | ||
403 | tmp = mr32(PCS); | ||
404 | mw32(PCS, tmp | PCS_SELF_CLEAR); | ||
405 | } | ||
406 | #endif | ||
407 | |||
408 | rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi); | ||
409 | if (rc) | ||
410 | goto err_out_msi; | ||
411 | |||
412 | rc = scsi_add_host(mvi->shost, &pdev->dev); | ||
413 | if (rc) | ||
414 | goto err_out_irq; | ||
415 | |||
416 | rc = sas_register_ha(&mvi->sas); | ||
417 | if (rc) | ||
418 | goto err_out_shost; | ||
419 | |||
420 | pci_set_drvdata(pdev, mvi); | ||
421 | |||
422 | mvs_print_info(mvi); | ||
423 | |||
424 | mvs_hba_interrupt_enable(mvi); | ||
425 | |||
426 | scsi_scan_host(mvi->shost); | ||
427 | |||
428 | return 0; | ||
429 | |||
430 | err_out_shost: | ||
431 | scsi_remove_host(mvi->shost); | ||
432 | err_out_irq: | ||
433 | free_irq(pdev->irq, mvi); | ||
434 | err_out_msi: | ||
435 | if (mvi->flags |= MVF_MSI) | ||
436 | pci_disable_msi(pdev); | ||
437 | err_out_mvi: | ||
438 | mvs_free(mvi); | ||
439 | err_out_regions: | ||
440 | pci_release_regions(pdev); | ||
441 | err_out_disable: | ||
442 | pci_disable_device(pdev); | ||
443 | return rc; | ||
444 | } | ||
445 | |||
446 | static void __devexit mvs_pci_remove(struct pci_dev *pdev) | ||
447 | { | ||
448 | struct mvs_info *mvi = pci_get_drvdata(pdev); | ||
449 | |||
450 | pci_set_drvdata(pdev, NULL); | ||
451 | |||
452 | if (mvi) { | ||
453 | sas_unregister_ha(&mvi->sas); | ||
454 | mvs_hba_interrupt_disable(mvi); | ||
455 | sas_remove_host(mvi->shost); | ||
456 | scsi_remove_host(mvi->shost); | ||
457 | |||
458 | free_irq(pdev->irq, mvi); | ||
459 | if (mvi->flags & MVF_MSI) | ||
460 | pci_disable_msi(pdev); | ||
461 | mvs_free(mvi); | ||
462 | pci_release_regions(pdev); | ||
463 | } | ||
464 | pci_disable_device(pdev); | ||
465 | } | ||
466 | |||
467 | static struct pci_device_id __devinitdata mvs_pci_table[] = { | ||
468 | { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 }, | ||
469 | { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 }, | ||
470 | { | ||
471 | .vendor = PCI_VENDOR_ID_MARVELL, | ||
472 | .device = 0x6440, | ||
473 | .subvendor = PCI_ANY_ID, | ||
474 | .subdevice = 0x6480, | ||
475 | .class = 0, | ||
476 | .class_mask = 0, | ||
477 | .driver_data = chip_6480, | ||
478 | }, | ||
479 | { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 }, | ||
480 | { PCI_VDEVICE(MARVELL, 0x6480), chip_6480 }, | ||
481 | |||
482 | { } /* terminate list */ | ||
483 | }; | ||
484 | |||
485 | static struct pci_driver mvs_pci_driver = { | ||
486 | .name = DRV_NAME, | ||
487 | .id_table = mvs_pci_table, | ||
488 | .probe = mvs_pci_init, | ||
489 | .remove = __devexit_p(mvs_pci_remove), | ||
490 | }; | ||
491 | |||
492 | static int __init mvs_init(void) | ||
493 | { | ||
494 | int rc; | ||
495 | |||
496 | mvs_stt = sas_domain_attach_transport(&mvs_transport_ops); | ||
497 | if (!mvs_stt) | ||
498 | return -ENOMEM; | ||
499 | |||
500 | rc = pci_register_driver(&mvs_pci_driver); | ||
501 | if (rc) | ||
502 | goto err_out; | ||
503 | |||
504 | return 0; | ||
505 | |||
506 | err_out: | ||
507 | sas_release_transport(mvs_stt); | ||
508 | return rc; | ||
509 | } | ||
510 | |||
511 | static void __exit mvs_exit(void) | ||
512 | { | ||
513 | pci_unregister_driver(&mvs_pci_driver); | ||
514 | sas_release_transport(mvs_stt); | ||
515 | } | ||
516 | |||
517 | module_init(mvs_init); | ||
518 | module_exit(mvs_exit); | ||
519 | |||
520 | MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>"); | ||
521 | MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver"); | ||
522 | MODULE_VERSION(DRV_VERSION); | ||
523 | MODULE_LICENSE("GPL"); | ||
524 | MODULE_DEVICE_TABLE(pci, mvs_pci_table); | ||
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index e4acebd10d1b..6a583c19c6e5 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | mvsas.c - Marvell 88SE6440 SAS/SATA support | 2 | mv_sas.c - Marvell 88SE6440 SAS/SATA support |
3 | 3 | ||
4 | Copyright 2007 Red Hat, Inc. | 4 | Copyright 2007 Red Hat, Inc. |
5 | Copyright 2008 Marvell. <kewei@marvell.com> | 5 | Copyright 2008 Marvell. <kewei@marvell.com> |
@@ -28,34 +28,9 @@ | |||
28 | 28 | ||
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <linux/kernel.h> | 31 | #include "mv_sas.h" |
32 | #include <linux/module.h> | 32 | #include "mv_64xx.h" |
33 | #include <linux/pci.h> | 33 | #include "mv_chips.h" |
34 | #include <linux/interrupt.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/delay.h> | ||
37 | #include <linux/dma-mapping.h> | ||
38 | #include <linux/ctype.h> | ||
39 | #include <scsi/libsas.h> | ||
40 | #include <scsi/scsi_tcq.h> | ||
41 | #include <scsi/sas_ata.h> | ||
42 | #include <asm/io.h> | ||
43 | |||
44 | #define DRV_NAME "mvsas" | ||
45 | #define DRV_VERSION "0.5.2" | ||
46 | #define _MV_DUMP 0 | ||
47 | #define MVS_DISABLE_NVRAM | ||
48 | #define MVS_DISABLE_MSI | ||
49 | |||
50 | #define mr32(reg) readl(regs + MVS_##reg) | ||
51 | #define mw32(reg,val) writel((val), regs + MVS_##reg) | ||
52 | #define mw32_f(reg,val) do { \ | ||
53 | writel((val), regs + MVS_##reg); \ | ||
54 | readl(regs + MVS_##reg); \ | ||
55 | } while (0) | ||
56 | |||
57 | #define MVS_ID_NOT_MAPPED 0x7f | ||
58 | #define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width) | ||
59 | 34 | ||
60 | /* offset for D2H FIS in the Received FIS List Structure */ | 35 | /* offset for D2H FIS in the Received FIS List Structure */ |
61 | #define SATA_RECEIVED_D2H_FIS(reg_set) \ | 36 | #define SATA_RECEIVED_D2H_FIS(reg_set) \ |
@@ -65,670 +40,70 @@ | |||
65 | #define UNASSOC_D2H_FIS(id) \ | 40 | #define UNASSOC_D2H_FIS(id) \ |
66 | ((void *) mvi->rx_fis + 0x100 * id) | 41 | ((void *) mvi->rx_fis + 0x100 * id) |
67 | 42 | ||
68 | #define for_each_phy(__lseq_mask, __mc, __lseq, __rest) \ | 43 | struct mvs_task_exec_info { |
69 | for ((__mc) = (__lseq_mask), (__lseq) = 0; \ | 44 | struct sas_task *task; |
70 | (__mc) != 0 && __rest; \ | 45 | struct mvs_cmd_hdr *hdr; |
71 | (++__lseq), (__mc) >>= 1) | 46 | struct mvs_port *port; |
72 | 47 | u32 tag; | |
73 | /* driver compile-time configuration */ | 48 | int n_elem; |
74 | enum driver_configuration { | ||
75 | MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */ | ||
76 | MVS_RX_RING_SZ = 1024, /* RX ring size (12-bit) */ | ||
77 | /* software requires power-of-2 | ||
78 | ring size */ | ||
79 | |||
80 | MVS_SLOTS = 512, /* command slots */ | ||
81 | MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */ | ||
82 | MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */ | ||
83 | MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */ | ||
84 | MVS_OAF_SZ = 64, /* Open address frame buffer size */ | ||
85 | |||
86 | MVS_RX_FIS_COUNT = 17, /* Optional rx'd FISs (max 17) */ | ||
87 | |||
88 | MVS_QUEUE_SIZE = 30, /* Support Queue depth */ | ||
89 | MVS_CAN_QUEUE = MVS_SLOTS - 1, /* SCSI Queue depth */ | ||
90 | }; | ||
91 | |||
92 | /* unchangeable hardware details */ | ||
93 | enum hardware_details { | ||
94 | MVS_MAX_PHYS = 8, /* max. possible phys */ | ||
95 | MVS_MAX_PORTS = 8, /* max. possible ports */ | ||
96 | MVS_RX_FISL_SZ = 0x400 + (MVS_RX_FIS_COUNT * 0x100), | ||
97 | }; | ||
98 | |||
99 | /* peripheral registers (BAR2) */ | ||
100 | enum peripheral_registers { | ||
101 | SPI_CTL = 0x10, /* EEPROM control */ | ||
102 | SPI_CMD = 0x14, /* EEPROM command */ | ||
103 | SPI_DATA = 0x18, /* EEPROM data */ | ||
104 | }; | ||
105 | |||
106 | enum peripheral_register_bits { | ||
107 | TWSI_RDY = (1U << 7), /* EEPROM interface ready */ | ||
108 | TWSI_RD = (1U << 4), /* EEPROM read access */ | ||
109 | |||
110 | SPI_ADDR_MASK = 0x3ffff, /* bits 17:0 */ | ||
111 | }; | ||
112 | |||
113 | /* enhanced mode registers (BAR4) */ | ||
114 | enum hw_registers { | ||
115 | MVS_GBL_CTL = 0x04, /* global control */ | ||
116 | MVS_GBL_INT_STAT = 0x08, /* global irq status */ | ||
117 | MVS_GBL_PI = 0x0C, /* ports implemented bitmask */ | ||
118 | MVS_GBL_PORT_TYPE = 0xa0, /* port type */ | ||
119 | |||
120 | MVS_CTL = 0x100, /* SAS/SATA port configuration */ | ||
121 | MVS_PCS = 0x104, /* SAS/SATA port control/status */ | ||
122 | MVS_CMD_LIST_LO = 0x108, /* cmd list addr */ | ||
123 | MVS_CMD_LIST_HI = 0x10C, | ||
124 | MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */ | ||
125 | MVS_RX_FIS_HI = 0x114, | ||
126 | |||
127 | MVS_TX_CFG = 0x120, /* TX configuration */ | ||
128 | MVS_TX_LO = 0x124, /* TX (delivery) ring addr */ | ||
129 | MVS_TX_HI = 0x128, | ||
130 | |||
131 | MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */ | ||
132 | MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */ | ||
133 | MVS_RX_CFG = 0x134, /* RX configuration */ | ||
134 | MVS_RX_LO = 0x138, /* RX (completion) ring addr */ | ||
135 | MVS_RX_HI = 0x13C, | ||
136 | MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */ | ||
137 | |||
138 | MVS_INT_COAL = 0x148, /* Int coalescing config */ | ||
139 | MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */ | ||
140 | MVS_INT_STAT = 0x150, /* Central int status */ | ||
141 | MVS_INT_MASK = 0x154, /* Central int enable */ | ||
142 | MVS_INT_STAT_SRS = 0x158, /* SATA register set status */ | ||
143 | MVS_INT_MASK_SRS = 0x15C, | ||
144 | |||
145 | /* ports 1-3 follow after this */ | ||
146 | MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */ | ||
147 | MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */ | ||
148 | MVS_P4_INT_STAT = 0x200, /* Port 4 interrupt status */ | ||
149 | MVS_P4_INT_MASK = 0x204, /* Port 4 interrupt enable mask */ | ||
150 | |||
151 | /* ports 1-3 follow after this */ | ||
152 | MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */ | ||
153 | MVS_P4_SER_CTLSTAT = 0x220, /* port4 serial control/status */ | ||
154 | |||
155 | MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */ | ||
156 | MVS_CMD_DATA = 0x1BC, /* Command register port (data) */ | ||
157 | |||
158 | /* ports 1-3 follow after this */ | ||
159 | MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */ | ||
160 | MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */ | ||
161 | MVS_P4_CFG_ADDR = 0x230, /* Port 4 config address */ | ||
162 | MVS_P4_CFG_DATA = 0x234, /* Port 4 config data */ | ||
163 | |||
164 | /* ports 1-3 follow after this */ | ||
165 | MVS_P0_VSR_ADDR = 0x1E0, /* port0 VSR address */ | ||
166 | MVS_P0_VSR_DATA = 0x1E4, /* port0 VSR data */ | ||
167 | MVS_P4_VSR_ADDR = 0x250, /* port 4 VSR addr */ | ||
168 | MVS_P4_VSR_DATA = 0x254, /* port 4 VSR data */ | ||
169 | }; | ||
170 | |||
171 | enum hw_register_bits { | ||
172 | /* MVS_GBL_CTL */ | ||
173 | INT_EN = (1U << 1), /* Global int enable */ | ||
174 | HBA_RST = (1U << 0), /* HBA reset */ | ||
175 | |||
176 | /* MVS_GBL_INT_STAT */ | ||
177 | INT_XOR = (1U << 4), /* XOR engine event */ | ||
178 | INT_SAS_SATA = (1U << 0), /* SAS/SATA event */ | ||
179 | |||
180 | /* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */ | ||
181 | SATA_TARGET = (1U << 16), /* port0 SATA target enable */ | ||
182 | MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */ | ||
183 | MODE_AUTO_DET_PORT6 = (1U << 14), | ||
184 | MODE_AUTO_DET_PORT5 = (1U << 13), | ||
185 | MODE_AUTO_DET_PORT4 = (1U << 12), | ||
186 | MODE_AUTO_DET_PORT3 = (1U << 11), | ||
187 | MODE_AUTO_DET_PORT2 = (1U << 10), | ||
188 | MODE_AUTO_DET_PORT1 = (1U << 9), | ||
189 | MODE_AUTO_DET_PORT0 = (1U << 8), | ||
190 | MODE_AUTO_DET_EN = MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 | | ||
191 | MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 | | ||
192 | MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 | | ||
193 | MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7, | ||
194 | MODE_SAS_PORT7_MASK = (1U << 7), /* port0 SAS(1), SATA(0) mode */ | ||
195 | MODE_SAS_PORT6_MASK = (1U << 6), | ||
196 | MODE_SAS_PORT5_MASK = (1U << 5), | ||
197 | MODE_SAS_PORT4_MASK = (1U << 4), | ||
198 | MODE_SAS_PORT3_MASK = (1U << 3), | ||
199 | MODE_SAS_PORT2_MASK = (1U << 2), | ||
200 | MODE_SAS_PORT1_MASK = (1U << 1), | ||
201 | MODE_SAS_PORT0_MASK = (1U << 0), | ||
202 | MODE_SAS_SATA = MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK | | ||
203 | MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK | | ||
204 | MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK | | ||
205 | MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK, | ||
206 | |||
207 | /* SAS_MODE value may be | ||
208 | * dictated (in hw) by values | ||
209 | * of SATA_TARGET & AUTO_DET | ||
210 | */ | ||
211 | |||
212 | /* MVS_TX_CFG */ | ||
213 | TX_EN = (1U << 16), /* Enable TX */ | ||
214 | TX_RING_SZ_MASK = 0xfff, /* TX ring size, bits 11:0 */ | ||
215 | |||
216 | /* MVS_RX_CFG */ | ||
217 | RX_EN = (1U << 16), /* Enable RX */ | ||
218 | RX_RING_SZ_MASK = 0xfff, /* RX ring size, bits 11:0 */ | ||
219 | |||
220 | /* MVS_INT_COAL */ | ||
221 | COAL_EN = (1U << 16), /* Enable int coalescing */ | ||
222 | |||
223 | /* MVS_INT_STAT, MVS_INT_MASK */ | ||
224 | CINT_I2C = (1U << 31), /* I2C event */ | ||
225 | CINT_SW0 = (1U << 30), /* software event 0 */ | ||
226 | CINT_SW1 = (1U << 29), /* software event 1 */ | ||
227 | CINT_PRD_BC = (1U << 28), /* PRD BC err for read cmd */ | ||
228 | CINT_DMA_PCIE = (1U << 27), /* DMA to PCIE timeout */ | ||
229 | CINT_MEM = (1U << 26), /* int mem parity err */ | ||
230 | CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */ | ||
231 | CINT_SRS = (1U << 3), /* SRS event */ | ||
232 | CINT_CI_STOP = (1U << 1), /* cmd issue stopped */ | ||
233 | CINT_DONE = (1U << 0), /* cmd completion */ | ||
234 | |||
235 | /* shl for ports 1-3 */ | ||
236 | CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */ | ||
237 | CINT_PORT = (1U << 8), /* port0 event */ | ||
238 | CINT_PORT_MASK_OFFSET = 8, | ||
239 | CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET), | ||
240 | |||
241 | /* TX (delivery) ring bits */ | ||
242 | TXQ_CMD_SHIFT = 29, | ||
243 | TXQ_CMD_SSP = 1, /* SSP protocol */ | ||
244 | TXQ_CMD_SMP = 2, /* SMP protocol */ | ||
245 | TXQ_CMD_STP = 3, /* STP/SATA protocol */ | ||
246 | TXQ_CMD_SSP_FREE_LIST = 4, /* add to SSP targ free list */ | ||
247 | TXQ_CMD_SLOT_RESET = 7, /* reset command slot */ | ||
248 | TXQ_MODE_I = (1U << 28), /* mode: 0=target,1=initiator */ | ||
249 | TXQ_PRIO_HI = (1U << 27), /* priority: 0=normal, 1=high */ | ||
250 | TXQ_SRS_SHIFT = 20, /* SATA register set */ | ||
251 | TXQ_SRS_MASK = 0x7f, | ||
252 | TXQ_PHY_SHIFT = 12, /* PHY bitmap */ | ||
253 | TXQ_PHY_MASK = 0xff, | ||
254 | TXQ_SLOT_MASK = 0xfff, /* slot number */ | ||
255 | |||
256 | /* RX (completion) ring bits */ | ||
257 | RXQ_GOOD = (1U << 23), /* Response good */ | ||
258 | RXQ_SLOT_RESET = (1U << 21), /* Slot reset complete */ | ||
259 | RXQ_CMD_RX = (1U << 20), /* target cmd received */ | ||
260 | RXQ_ATTN = (1U << 19), /* attention */ | ||
261 | RXQ_RSP = (1U << 18), /* response frame xfer'd */ | ||
262 | RXQ_ERR = (1U << 17), /* err info rec xfer'd */ | ||
263 | RXQ_DONE = (1U << 16), /* cmd complete */ | ||
264 | RXQ_SLOT_MASK = 0xfff, /* slot number */ | ||
265 | |||
266 | /* mvs_cmd_hdr bits */ | ||
267 | MCH_PRD_LEN_SHIFT = 16, /* 16-bit PRD table len */ | ||
268 | MCH_SSP_FR_TYPE_SHIFT = 13, /* SSP frame type */ | ||
269 | |||
270 | /* SSP initiator only */ | ||
271 | MCH_SSP_FR_CMD = 0x0, /* COMMAND frame */ | ||
272 | |||
273 | /* SSP initiator or target */ | ||
274 | MCH_SSP_FR_TASK = 0x1, /* TASK frame */ | ||
275 | |||
276 | /* SSP target only */ | ||
277 | MCH_SSP_FR_XFER_RDY = 0x4, /* XFER_RDY frame */ | ||
278 | MCH_SSP_FR_RESP = 0x5, /* RESPONSE frame */ | ||
279 | MCH_SSP_FR_READ = 0x6, /* Read DATA frame(s) */ | ||
280 | MCH_SSP_FR_READ_RESP = 0x7, /* ditto, plus RESPONSE */ | ||
281 | |||
282 | MCH_PASSTHRU = (1U << 12), /* pass-through (SSP) */ | ||
283 | MCH_FBURST = (1U << 11), /* first burst (SSP) */ | ||
284 | MCH_CHK_LEN = (1U << 10), /* chk xfer len (SSP) */ | ||
285 | MCH_RETRY = (1U << 9), /* tport layer retry (SSP) */ | ||
286 | MCH_PROTECTION = (1U << 8), /* protection info rec (SSP) */ | ||
287 | MCH_RESET = (1U << 7), /* Reset (STP/SATA) */ | ||
288 | MCH_FPDMA = (1U << 6), /* First party DMA (STP/SATA) */ | ||
289 | MCH_ATAPI = (1U << 5), /* ATAPI (STP/SATA) */ | ||
290 | MCH_BIST = (1U << 4), /* BIST activate (STP/SATA) */ | ||
291 | MCH_PMP_MASK = 0xf, /* PMP from cmd FIS (STP/SATA)*/ | ||
292 | |||
293 | CCTL_RST = (1U << 5), /* port logic reset */ | ||
294 | |||
295 | /* 0(LSB first), 1(MSB first) */ | ||
296 | CCTL_ENDIAN_DATA = (1U << 3), /* PRD data */ | ||
297 | CCTL_ENDIAN_RSP = (1U << 2), /* response frame */ | ||
298 | CCTL_ENDIAN_OPEN = (1U << 1), /* open address frame */ | ||
299 | CCTL_ENDIAN_CMD = (1U << 0), /* command table */ | ||
300 | |||
301 | /* MVS_Px_SER_CTLSTAT (per-phy control) */ | ||
302 | PHY_SSP_RST = (1U << 3), /* reset SSP link layer */ | ||
303 | PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */ | ||
304 | PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */ | ||
305 | PHY_RST = (1U << 0), /* phy reset */ | ||
306 | PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8), | ||
307 | PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12), | ||
308 | PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16), | ||
309 | PHY_NEG_SPP_PHYS_LINK_RATE_MASK = | ||
310 | (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET), | ||
311 | PHY_READY_MASK = (1U << 20), | ||
312 | |||
313 | /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */ | ||
314 | PHYEV_DEC_ERR = (1U << 24), /* Phy Decoding Error */ | ||
315 | PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */ | ||
316 | PHYEV_AN = (1U << 18), /* SATA async notification */ | ||
317 | PHYEV_BIST_ACT = (1U << 17), /* BIST activate FIS */ | ||
318 | PHYEV_SIG_FIS = (1U << 16), /* signature FIS */ | ||
319 | PHYEV_POOF = (1U << 12), /* phy ready from 1 -> 0 */ | ||
320 | PHYEV_IU_BIG = (1U << 11), /* IU too long err */ | ||
321 | PHYEV_IU_SMALL = (1U << 10), /* IU too short err */ | ||
322 | PHYEV_UNK_TAG = (1U << 9), /* unknown tag */ | ||
323 | PHYEV_BROAD_CH = (1U << 8), /* broadcast(CHANGE) */ | ||
324 | PHYEV_COMWAKE = (1U << 7), /* COMWAKE rx'd */ | ||
325 | PHYEV_PORT_SEL = (1U << 6), /* port selector present */ | ||
326 | PHYEV_HARD_RST = (1U << 5), /* hard reset rx'd */ | ||
327 | PHYEV_ID_TMOUT = (1U << 4), /* identify timeout */ | ||
328 | PHYEV_ID_FAIL = (1U << 3), /* identify failed */ | ||
329 | PHYEV_ID_DONE = (1U << 2), /* identify done */ | ||
330 | PHYEV_HARD_RST_DONE = (1U << 1), /* hard reset done */ | ||
331 | PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */ | ||
332 | |||
333 | /* MVS_PCS */ | ||
334 | PCS_EN_SATA_REG_SHIFT = (16), /* Enable SATA Register Set */ | ||
335 | PCS_EN_PORT_XMT_SHIFT = (12), /* Enable Port Transmit */ | ||
336 | PCS_EN_PORT_XMT_SHIFT2 = (8), /* For 6480 */ | ||
337 | PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */ | ||
338 | PCS_RSP_RX_EN = (1U << 7), /* raw response rx */ | ||
339 | PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */ | ||
340 | PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */ | ||
341 | PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */ | ||
342 | PCS_CMD_RST = (1U << 1), /* reset cmd issue */ | ||
343 | PCS_CMD_EN = (1U << 0), /* enable cmd issue */ | ||
344 | |||
345 | /* Port n Attached Device Info */ | ||
346 | PORT_DEV_SSP_TRGT = (1U << 19), | ||
347 | PORT_DEV_SMP_TRGT = (1U << 18), | ||
348 | PORT_DEV_STP_TRGT = (1U << 17), | ||
349 | PORT_DEV_SSP_INIT = (1U << 11), | ||
350 | PORT_DEV_SMP_INIT = (1U << 10), | ||
351 | PORT_DEV_STP_INIT = (1U << 9), | ||
352 | PORT_PHY_ID_MASK = (0xFFU << 24), | ||
353 | PORT_DEV_TRGT_MASK = (0x7U << 17), | ||
354 | PORT_DEV_INIT_MASK = (0x7U << 9), | ||
355 | PORT_DEV_TYPE_MASK = (0x7U << 0), | ||
356 | |||
357 | /* Port n PHY Status */ | ||
358 | PHY_RDY = (1U << 2), | ||
359 | PHY_DW_SYNC = (1U << 1), | ||
360 | PHY_OOB_DTCTD = (1U << 0), | ||
361 | |||
362 | /* VSR */ | ||
363 | /* PHYMODE 6 (CDB) */ | ||
364 | PHY_MODE6_LATECLK = (1U << 29), /* Lock Clock */ | ||
365 | PHY_MODE6_DTL_SPEED = (1U << 27), /* Digital Loop Speed */ | ||
366 | PHY_MODE6_FC_ORDER = (1U << 26), /* Fibre Channel Mode Order*/ | ||
367 | PHY_MODE6_MUCNT_EN = (1U << 24), /* u Count Enable */ | ||
368 | PHY_MODE6_SEL_MUCNT_LEN = (1U << 22), /* Training Length Select */ | ||
369 | PHY_MODE6_SELMUPI = (1U << 20), /* Phase Multi Select (init) */ | ||
370 | PHY_MODE6_SELMUPF = (1U << 18), /* Phase Multi Select (final) */ | ||
371 | PHY_MODE6_SELMUFF = (1U << 16), /* Freq Loop Multi Sel(final) */ | ||
372 | PHY_MODE6_SELMUFI = (1U << 14), /* Freq Loop Multi Sel(init) */ | ||
373 | PHY_MODE6_FREEZE_LOOP = (1U << 12), /* Freeze Rx CDR Loop */ | ||
374 | PHY_MODE6_INT_RXFOFFS = (1U << 3), /* Rx CDR Freq Loop Enable */ | ||
375 | PHY_MODE6_FRC_RXFOFFS = (1U << 2), /* Initial Rx CDR Offset */ | ||
376 | PHY_MODE6_STAU_0D8 = (1U << 1), /* Rx CDR Freq Loop Saturate */ | ||
377 | PHY_MODE6_RXSAT_DIS = (1U << 0), /* Saturate Ctl */ | ||
378 | }; | ||
379 | |||
380 | enum mvs_info_flags { | ||
381 | MVF_MSI = (1U << 0), /* MSI is enabled */ | ||
382 | MVF_PHY_PWR_FIX = (1U << 1), /* bug workaround */ | ||
383 | }; | ||
384 | |||
385 | enum sas_cmd_port_registers { | ||
386 | CMD_CMRST_OOB_DET = 0x100, /* COMRESET OOB detect register */ | ||
387 | CMD_CMWK_OOB_DET = 0x104, /* COMWAKE OOB detect register */ | ||
388 | CMD_CMSAS_OOB_DET = 0x108, /* COMSAS OOB detect register */ | ||
389 | CMD_BRST_OOB_DET = 0x10c, /* burst OOB detect register */ | ||
390 | CMD_OOB_SPACE = 0x110, /* OOB space control register */ | ||
391 | CMD_OOB_BURST = 0x114, /* OOB burst control register */ | ||
392 | CMD_PHY_TIMER = 0x118, /* PHY timer control register */ | ||
393 | CMD_PHY_CONFIG0 = 0x11c, /* PHY config register 0 */ | ||
394 | CMD_PHY_CONFIG1 = 0x120, /* PHY config register 1 */ | ||
395 | CMD_SAS_CTL0 = 0x124, /* SAS control register 0 */ | ||
396 | CMD_SAS_CTL1 = 0x128, /* SAS control register 1 */ | ||
397 | CMD_SAS_CTL2 = 0x12c, /* SAS control register 2 */ | ||
398 | CMD_SAS_CTL3 = 0x130, /* SAS control register 3 */ | ||
399 | CMD_ID_TEST = 0x134, /* ID test register */ | ||
400 | CMD_PL_TIMER = 0x138, /* PL timer register */ | ||
401 | CMD_WD_TIMER = 0x13c, /* WD timer register */ | ||
402 | CMD_PORT_SEL_COUNT = 0x140, /* port selector count register */ | ||
403 | CMD_APP_MEM_CTL = 0x144, /* Application Memory Control */ | ||
404 | CMD_XOR_MEM_CTL = 0x148, /* XOR Block Memory Control */ | ||
405 | CMD_DMA_MEM_CTL = 0x14c, /* DMA Block Memory Control */ | ||
406 | CMD_PORT_MEM_CTL0 = 0x150, /* Port Memory Control 0 */ | ||
407 | CMD_PORT_MEM_CTL1 = 0x154, /* Port Memory Control 1 */ | ||
408 | CMD_SATA_PORT_MEM_CTL0 = 0x158, /* SATA Port Memory Control 0 */ | ||
409 | CMD_SATA_PORT_MEM_CTL1 = 0x15c, /* SATA Port Memory Control 1 */ | ||
410 | CMD_XOR_MEM_BIST_CTL = 0x160, /* XOR Memory BIST Control */ | ||
411 | CMD_XOR_MEM_BIST_STAT = 0x164, /* XOR Memroy BIST Status */ | ||
412 | CMD_DMA_MEM_BIST_CTL = 0x168, /* DMA Memory BIST Control */ | ||
413 | CMD_DMA_MEM_BIST_STAT = 0x16c, /* DMA Memory BIST Status */ | ||
414 | CMD_PORT_MEM_BIST_CTL = 0x170, /* Port Memory BIST Control */ | ||
415 | CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */ | ||
416 | CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */ | ||
417 | CMD_STP_MEM_BIST_CTL = 0x17c, /* STP Memory BIST Control */ | ||
418 | CMD_STP_MEM_BIST_STAT0 = 0x180, /* STP Memory BIST Status 0 */ | ||
419 | CMD_STP_MEM_BIST_STAT1 = 0x184, /* STP Memory BIST Status 1 */ | ||
420 | CMD_RESET_COUNT = 0x188, /* Reset Count */ | ||
421 | CMD_MONTR_DATA_SEL = 0x18C, /* Monitor Data/Select */ | ||
422 | CMD_PLL_PHY_CONFIG = 0x190, /* PLL/PHY Configuration */ | ||
423 | CMD_PHY_CTL = 0x194, /* PHY Control and Status */ | ||
424 | CMD_PHY_TEST_COUNT0 = 0x198, /* Phy Test Count 0 */ | ||
425 | CMD_PHY_TEST_COUNT1 = 0x19C, /* Phy Test Count 1 */ | ||
426 | CMD_PHY_TEST_COUNT2 = 0x1A0, /* Phy Test Count 2 */ | ||
427 | CMD_APP_ERR_CONFIG = 0x1A4, /* Application Error Configuration */ | ||
428 | CMD_PND_FIFO_CTL0 = 0x1A8, /* Pending FIFO Control 0 */ | ||
429 | CMD_HOST_CTL = 0x1AC, /* Host Control Status */ | ||
430 | CMD_HOST_WR_DATA = 0x1B0, /* Host Write Data */ | ||
431 | CMD_HOST_RD_DATA = 0x1B4, /* Host Read Data */ | ||
432 | CMD_PHY_MODE_21 = 0x1B8, /* Phy Mode 21 */ | ||
433 | CMD_SL_MODE0 = 0x1BC, /* SL Mode 0 */ | ||
434 | CMD_SL_MODE1 = 0x1C0, /* SL Mode 1 */ | ||
435 | CMD_PND_FIFO_CTL1 = 0x1C4, /* Pending FIFO Control 1 */ | ||
436 | }; | ||
437 | |||
438 | /* SAS/SATA configuration port registers, aka phy registers */ | ||
439 | enum sas_sata_config_port_regs { | ||
440 | PHYR_IDENTIFY = 0x00, /* info for IDENTIFY frame */ | ||
441 | PHYR_ADDR_LO = 0x04, /* my SAS address (low) */ | ||
442 | PHYR_ADDR_HI = 0x08, /* my SAS address (high) */ | ||
443 | PHYR_ATT_DEV_INFO = 0x0C, /* attached device info */ | ||
444 | PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */ | ||
445 | PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */ | ||
446 | PHYR_SATA_CTL = 0x18, /* SATA control */ | ||
447 | PHYR_PHY_STAT = 0x1C, /* PHY status */ | ||
448 | PHYR_SATA_SIG0 = 0x20, /*port SATA signature FIS(Byte 0-3) */ | ||
449 | PHYR_SATA_SIG1 = 0x24, /*port SATA signature FIS(Byte 4-7) */ | ||
450 | PHYR_SATA_SIG2 = 0x28, /*port SATA signature FIS(Byte 8-11) */ | ||
451 | PHYR_SATA_SIG3 = 0x2c, /*port SATA signature FIS(Byte 12-15) */ | ||
452 | PHYR_R_ERR_COUNT = 0x30, /* port R_ERR count register */ | ||
453 | PHYR_CRC_ERR_COUNT = 0x34, /* port CRC error count register */ | ||
454 | PHYR_WIDE_PORT = 0x38, /* wide port participating */ | ||
455 | PHYR_CURRENT0 = 0x80, /* current connection info 0 */ | ||
456 | PHYR_CURRENT1 = 0x84, /* current connection info 1 */ | ||
457 | PHYR_CURRENT2 = 0x88, /* current connection info 2 */ | ||
458 | }; | ||
459 | |||
460 | /* SAS/SATA Vendor Specific Port Registers */ | ||
461 | enum sas_sata_vsp_regs { | ||
462 | VSR_PHY_STAT = 0x00, /* Phy Status */ | ||
463 | VSR_PHY_MODE1 = 0x01, /* phy tx */ | ||
464 | VSR_PHY_MODE2 = 0x02, /* tx scc */ | ||
465 | VSR_PHY_MODE3 = 0x03, /* pll */ | ||
466 | VSR_PHY_MODE4 = 0x04, /* VCO */ | ||
467 | VSR_PHY_MODE5 = 0x05, /* Rx */ | ||
468 | VSR_PHY_MODE6 = 0x06, /* CDR */ | ||
469 | VSR_PHY_MODE7 = 0x07, /* Impedance */ | ||
470 | VSR_PHY_MODE8 = 0x08, /* Voltage */ | ||
471 | VSR_PHY_MODE9 = 0x09, /* Test */ | ||
472 | VSR_PHY_MODE10 = 0x0A, /* Power */ | ||
473 | VSR_PHY_MODE11 = 0x0B, /* Phy Mode */ | ||
474 | VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */ | ||
475 | VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */ | ||
476 | }; | ||
477 | |||
478 | enum pci_cfg_registers { | ||
479 | PCR_PHY_CTL = 0x40, | ||
480 | PCR_PHY_CTL2 = 0x90, | ||
481 | PCR_DEV_CTRL = 0xE8, | ||
482 | }; | ||
483 | |||
484 | enum pci_cfg_register_bits { | ||
485 | PCTL_PWR_ON = (0xFU << 24), | ||
486 | PCTL_OFF = (0xFU << 12), | ||
487 | PRD_REQ_SIZE = (0x4000), | ||
488 | PRD_REQ_MASK = (0x00007000), | ||
489 | }; | ||
490 | |||
491 | enum nvram_layout_offsets { | ||
492 | NVR_SIG = 0x00, /* 0xAA, 0x55 */ | ||
493 | NVR_SAS_ADDR = 0x02, /* 8-byte SAS address */ | ||
494 | }; | ||
495 | |||
496 | enum chip_flavors { | ||
497 | chip_6320, | ||
498 | chip_6440, | ||
499 | chip_6480, | ||
500 | }; | ||
501 | |||
502 | enum port_type { | ||
503 | PORT_TYPE_SAS = (1L << 1), | ||
504 | PORT_TYPE_SATA = (1L << 0), | ||
505 | }; | ||
506 | |||
507 | /* Command Table Format */ | ||
508 | enum ct_format { | ||
509 | /* SSP */ | ||
510 | SSP_F_H = 0x00, | ||
511 | SSP_F_IU = 0x18, | ||
512 | SSP_F_MAX = 0x4D, | ||
513 | /* STP */ | ||
514 | STP_CMD_FIS = 0x00, | ||
515 | STP_ATAPI_CMD = 0x40, | ||
516 | STP_F_MAX = 0x10, | ||
517 | /* SMP */ | ||
518 | SMP_F_T = 0x00, | ||
519 | SMP_F_DEP = 0x01, | ||
520 | SMP_F_MAX = 0x101, | ||
521 | }; | ||
522 | |||
523 | enum status_buffer { | ||
524 | SB_EIR_OFF = 0x00, /* Error Information Record */ | ||
525 | SB_RFB_OFF = 0x08, /* Response Frame Buffer */ | ||
526 | SB_RFB_MAX = 0x400, /* RFB size*/ | ||
527 | }; | ||
528 | |||
529 | enum error_info_rec { | ||
530 | CMD_ISS_STPD = (1U << 31), /* Cmd Issue Stopped */ | ||
531 | CMD_PI_ERR = (1U << 30), /* Protection info error. see flags2 */ | ||
532 | RSP_OVER = (1U << 29), /* rsp buffer overflow */ | ||
533 | RETRY_LIM = (1U << 28), /* FIS/frame retry limit exceeded */ | ||
534 | UNK_FIS = (1U << 27), /* unknown FIS */ | ||
535 | DMA_TERM = (1U << 26), /* DMA terminate primitive rx'd */ | ||
536 | SYNC_ERR = (1U << 25), /* SYNC rx'd during frame xmit */ | ||
537 | TFILE_ERR = (1U << 24), /* SATA taskfile Error bit set */ | ||
538 | R_ERR = (1U << 23), /* SATA returned R_ERR prim */ | ||
539 | RD_OFS = (1U << 20), /* Read DATA frame invalid offset */ | ||
540 | XFER_RDY_OFS = (1U << 19), /* XFER_RDY offset error */ | ||
541 | UNEXP_XFER_RDY = (1U << 18), /* unexpected XFER_RDY error */ | ||
542 | DATA_OVER_UNDER = (1U << 16), /* data overflow/underflow */ | ||
543 | INTERLOCK = (1U << 15), /* interlock error */ | ||
544 | NAK = (1U << 14), /* NAK rx'd */ | ||
545 | ACK_NAK_TO = (1U << 13), /* ACK/NAK timeout */ | ||
546 | CXN_CLOSED = (1U << 12), /* cxn closed w/out ack/nak */ | ||
547 | OPEN_TO = (1U << 11), /* I_T nexus lost, open cxn timeout */ | ||
548 | PATH_BLOCKED = (1U << 10), /* I_T nexus lost, pathway blocked */ | ||
549 | NO_DEST = (1U << 9), /* I_T nexus lost, no destination */ | ||
550 | STP_RES_BSY = (1U << 8), /* STP resources busy */ | ||
551 | BREAK = (1U << 7), /* break received */ | ||
552 | BAD_DEST = (1U << 6), /* bad destination */ | ||
553 | BAD_PROTO = (1U << 5), /* protocol not supported */ | ||
554 | BAD_RATE = (1U << 4), /* cxn rate not supported */ | ||
555 | WRONG_DEST = (1U << 3), /* wrong destination error */ | ||
556 | CREDIT_TO = (1U << 2), /* credit timeout */ | ||
557 | WDOG_TO = (1U << 1), /* watchdog timeout */ | ||
558 | BUF_PAR = (1U << 0), /* buffer parity error */ | ||
559 | }; | ||
560 | |||
561 | enum error_info_rec_2 { | ||
562 | SLOT_BSY_ERR = (1U << 31), /* Slot Busy Error */ | ||
563 | GRD_CHK_ERR = (1U << 14), /* Guard Check Error */ | ||
564 | APP_CHK_ERR = (1U << 13), /* Application Check error */ | ||
565 | REF_CHK_ERR = (1U << 12), /* Reference Check Error */ | ||
566 | USR_BLK_NM = (1U << 0), /* User Block Number */ | ||
567 | }; | ||
568 | |||
569 | struct mvs_chip_info { | ||
570 | u32 n_phy; | ||
571 | u32 srs_sz; | ||
572 | u32 slot_width; | ||
573 | }; | ||
574 | |||
575 | struct mvs_err_info { | ||
576 | __le32 flags; | ||
577 | __le32 flags2; | ||
578 | }; | ||
579 | |||
580 | struct mvs_prd { | ||
581 | __le64 addr; /* 64-bit buffer address */ | ||
582 | __le32 reserved; | ||
583 | __le32 len; /* 16-bit length */ | ||
584 | }; | ||
585 | |||
586 | struct mvs_cmd_hdr { | ||
587 | __le32 flags; /* PRD tbl len; SAS, SATA ctl */ | ||
588 | __le32 lens; /* cmd, max resp frame len */ | ||
589 | __le32 tags; /* targ port xfer tag; tag */ | ||
590 | __le32 data_len; /* data xfer len */ | ||
591 | __le64 cmd_tbl; /* command table address */ | ||
592 | __le64 open_frame; /* open addr frame address */ | ||
593 | __le64 status_buf; /* status buffer address */ | ||
594 | __le64 prd_tbl; /* PRD tbl address */ | ||
595 | __le32 reserved[4]; | ||
596 | }; | ||
597 | |||
598 | struct mvs_port { | ||
599 | struct asd_sas_port sas_port; | ||
600 | u8 port_attached; | ||
601 | u8 taskfileset; | ||
602 | u8 wide_port_phymap; | ||
603 | struct list_head list; | ||
604 | }; | ||
605 | |||
606 | struct mvs_phy { | ||
607 | struct mvs_port *port; | ||
608 | struct asd_sas_phy sas_phy; | ||
609 | struct sas_identify identify; | ||
610 | struct scsi_device *sdev; | ||
611 | u64 dev_sas_addr; | ||
612 | u64 att_dev_sas_addr; | ||
613 | u32 att_dev_info; | ||
614 | u32 dev_info; | ||
615 | u32 phy_type; | ||
616 | u32 phy_status; | ||
617 | u32 irq_status; | ||
618 | u32 frame_rcvd_size; | ||
619 | u8 frame_rcvd[32]; | ||
620 | u8 phy_attached; | ||
621 | enum sas_linkrate minimum_linkrate; | ||
622 | enum sas_linkrate maximum_linkrate; | ||
623 | }; | ||
624 | |||
625 | struct mvs_slot_info { | ||
626 | struct list_head list; | ||
627 | struct sas_task *task; | ||
628 | u32 n_elem; | ||
629 | u32 tx; | ||
630 | |||
631 | /* DMA buffer for storing cmd tbl, open addr frame, status buffer, | ||
632 | * and PRD table | ||
633 | */ | ||
634 | void *buf; | ||
635 | dma_addr_t buf_dma; | ||
636 | #if _MV_DUMP | ||
637 | u32 cmd_size; | ||
638 | #endif | ||
639 | |||
640 | void *response; | ||
641 | struct mvs_port *port; | ||
642 | }; | 49 | }; |
643 | 50 | ||
644 | struct mvs_info { | 51 | static void mvs_release_task(struct mvs_info *mvi, int phy_no); |
645 | unsigned long flags; | 52 | static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i); |
646 | 53 | static void mvs_update_phyinfo(struct mvs_info *mvi, int i, | |
647 | spinlock_t lock; /* host-wide lock */ | 54 | int get_st); |
648 | struct pci_dev *pdev; /* our device */ | 55 | static int mvs_int_rx(struct mvs_info *mvi, bool self_clear); |
649 | void __iomem *regs; /* enhanced mode registers */ | 56 | static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task, |
650 | void __iomem *peri_regs; /* peripheral registers */ | 57 | u32 slot_idx); |
651 | |||
652 | u8 sas_addr[SAS_ADDR_SIZE]; | ||
653 | struct sas_ha_struct sas; /* SCSI/SAS glue */ | ||
654 | struct Scsi_Host *shost; | ||
655 | |||
656 | __le32 *tx; /* TX (delivery) DMA ring */ | ||
657 | dma_addr_t tx_dma; | ||
658 | u32 tx_prod; /* cached next-producer idx */ | ||
659 | |||
660 | __le32 *rx; /* RX (completion) DMA ring */ | ||
661 | dma_addr_t rx_dma; | ||
662 | u32 rx_cons; /* RX consumer idx */ | ||
663 | |||
664 | __le32 *rx_fis; /* RX'd FIS area */ | ||
665 | dma_addr_t rx_fis_dma; | ||
666 | |||
667 | struct mvs_cmd_hdr *slot; /* DMA command header slots */ | ||
668 | dma_addr_t slot_dma; | ||
669 | |||
670 | const struct mvs_chip_info *chip; | ||
671 | 58 | ||
672 | u8 tags[MVS_SLOTS]; | 59 | static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) |
673 | struct mvs_slot_info slot_info[MVS_SLOTS]; | 60 | { |
674 | /* further per-slot information */ | 61 | if (task->lldd_task) { |
675 | struct mvs_phy phy[MVS_MAX_PHYS]; | 62 | struct mvs_slot_info *slot; |
676 | struct mvs_port port[MVS_MAX_PHYS]; | 63 | slot = (struct mvs_slot_info *) task->lldd_task; |
677 | #ifdef MVS_USE_TASKLET | 64 | *tag = slot - mvi->slot_info; |
678 | struct tasklet_struct tasklet; | 65 | return 1; |
679 | #endif | 66 | } |
680 | }; | 67 | return 0; |
68 | } | ||
681 | 69 | ||
682 | static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, | 70 | static void mvs_tag_clear(struct mvs_info *mvi, u32 tag) |
683 | void *funcdata); | 71 | { |
684 | static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port); | 72 | void *bitmap = (void *) &mvi->tags; |
685 | static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val); | 73 | clear_bit(tag, bitmap); |
686 | static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port); | 74 | } |
687 | static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val); | ||
688 | static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val); | ||
689 | static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port); | ||
690 | 75 | ||
691 | static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i); | 76 | static void mvs_tag_free(struct mvs_info *mvi, u32 tag) |
692 | static void mvs_detect_porttype(struct mvs_info *mvi, int i); | 77 | { |
693 | static void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st); | 78 | mvs_tag_clear(mvi, tag); |
694 | static void mvs_release_task(struct mvs_info *mvi, int phy_no); | 79 | } |
695 | 80 | ||
696 | static int mvs_scan_finished(struct Scsi_Host *, unsigned long); | 81 | static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) |
697 | static void mvs_scan_start(struct Scsi_Host *); | 82 | { |
698 | static int mvs_slave_configure(struct scsi_device *sdev); | 83 | void *bitmap = (void *) &mvi->tags; |
84 | set_bit(tag, bitmap); | ||
85 | } | ||
699 | 86 | ||
700 | static struct scsi_transport_template *mvs_stt; | 87 | static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) |
88 | { | ||
89 | unsigned int index, tag; | ||
90 | void *bitmap = (void *) &mvi->tags; | ||
701 | 91 | ||
702 | static const struct mvs_chip_info mvs_chips[] = { | 92 | index = find_first_zero_bit(bitmap, MVS_SLOTS); |
703 | [chip_6320] = { 2, 16, 9 }, | 93 | tag = index; |
704 | [chip_6440] = { 4, 16, 9 }, | 94 | if (tag >= MVS_SLOTS) |
705 | [chip_6480] = { 8, 32, 10 }, | 95 | return -SAS_QUEUE_FULL; |
706 | }; | 96 | mvs_tag_set(mvi, tag); |
97 | *tag_out = tag; | ||
98 | return 0; | ||
99 | } | ||
707 | 100 | ||
708 | static struct scsi_host_template mvs_sht = { | 101 | void mvs_tag_init(struct mvs_info *mvi) |
709 | .module = THIS_MODULE, | 102 | { |
710 | .name = DRV_NAME, | 103 | int i; |
711 | .queuecommand = sas_queuecommand, | 104 | for (i = 0; i < MVS_SLOTS; ++i) |
712 | .target_alloc = sas_target_alloc, | 105 | mvs_tag_clear(mvi, i); |
713 | .slave_configure = mvs_slave_configure, | 106 | } |
714 | .slave_destroy = sas_slave_destroy, | ||
715 | .scan_finished = mvs_scan_finished, | ||
716 | .scan_start = mvs_scan_start, | ||
717 | .change_queue_depth = sas_change_queue_depth, | ||
718 | .change_queue_type = sas_change_queue_type, | ||
719 | .bios_param = sas_bios_param, | ||
720 | .can_queue = 1, | ||
721 | .cmd_per_lun = 1, | ||
722 | .this_id = -1, | ||
723 | .sg_tablesize = SG_ALL, | ||
724 | .max_sectors = SCSI_DEFAULT_MAX_SECTORS, | ||
725 | .use_clustering = ENABLE_CLUSTERING, | ||
726 | .eh_device_reset_handler = sas_eh_device_reset_handler, | ||
727 | .eh_bus_reset_handler = sas_eh_bus_reset_handler, | ||
728 | .slave_alloc = sas_slave_alloc, | ||
729 | .target_destroy = sas_target_destroy, | ||
730 | .ioctl = sas_ioctl, | ||
731 | }; | ||
732 | 107 | ||
733 | static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr) | 108 | static void mvs_hexdump(u32 size, u8 *data, u32 baseaddr) |
734 | { | 109 | { |
@@ -848,234 +223,52 @@ static void mvs_hba_cq_dump(struct mvs_info *mvi) | |||
848 | #endif | 223 | #endif |
849 | } | 224 | } |
850 | 225 | ||
851 | static void mvs_hba_interrupt_enable(struct mvs_info *mvi) | 226 | /* FIXME: locking? */ |
852 | { | 227 | int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, void *funcdata) |
853 | void __iomem *regs = mvi->regs; | ||
854 | u32 tmp; | ||
855 | |||
856 | tmp = mr32(GBL_CTL); | ||
857 | |||
858 | mw32(GBL_CTL, tmp | INT_EN); | ||
859 | } | ||
860 | |||
861 | static void mvs_hba_interrupt_disable(struct mvs_info *mvi) | ||
862 | { | 228 | { |
863 | void __iomem *regs = mvi->regs; | 229 | struct mvs_info *mvi = sas_phy->ha->lldd_ha; |
230 | int rc = 0, phy_id = sas_phy->id; | ||
864 | u32 tmp; | 231 | u32 tmp; |
865 | 232 | ||
866 | tmp = mr32(GBL_CTL); | 233 | tmp = mvs_read_phy_ctl(mvi, phy_id); |
867 | |||
868 | mw32(GBL_CTL, tmp & ~INT_EN); | ||
869 | } | ||
870 | 234 | ||
871 | static int mvs_int_rx(struct mvs_info *mvi, bool self_clear); | 235 | switch (func) { |
236 | case PHY_FUNC_SET_LINK_RATE:{ | ||
237 | struct sas_phy_linkrates *rates = funcdata; | ||
238 | u32 lrmin = 0, lrmax = 0; | ||
872 | 239 | ||
873 | /* move to PCI layer or libata core? */ | 240 | lrmin = (rates->minimum_linkrate << 8); |
874 | static int pci_go_64(struct pci_dev *pdev) | 241 | lrmax = (rates->maximum_linkrate << 12); |
875 | { | ||
876 | int rc; | ||
877 | 242 | ||
878 | if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { | 243 | if (lrmin) { |
879 | rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); | 244 | tmp &= ~(0xf << 8); |
880 | if (rc) { | 245 | tmp |= lrmin; |
881 | rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
882 | if (rc) { | ||
883 | dev_printk(KERN_ERR, &pdev->dev, | ||
884 | "64-bit DMA enable failed\n"); | ||
885 | return rc; | ||
886 | } | 246 | } |
247 | if (lrmax) { | ||
248 | tmp &= ~(0xf << 12); | ||
249 | tmp |= lrmax; | ||
250 | } | ||
251 | mvs_write_phy_ctl(mvi, phy_id, tmp); | ||
252 | break; | ||
887 | } | 253 | } |
888 | } else { | ||
889 | rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
890 | if (rc) { | ||
891 | dev_printk(KERN_ERR, &pdev->dev, | ||
892 | "32-bit DMA enable failed\n"); | ||
893 | return rc; | ||
894 | } | ||
895 | rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
896 | if (rc) { | ||
897 | dev_printk(KERN_ERR, &pdev->dev, | ||
898 | "32-bit consistent DMA enable failed\n"); | ||
899 | return rc; | ||
900 | } | ||
901 | } | ||
902 | |||
903 | return rc; | ||
904 | } | ||
905 | |||
906 | static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) | ||
907 | { | ||
908 | if (task->lldd_task) { | ||
909 | struct mvs_slot_info *slot; | ||
910 | slot = (struct mvs_slot_info *) task->lldd_task; | ||
911 | *tag = slot - mvi->slot_info; | ||
912 | return 1; | ||
913 | } | ||
914 | return 0; | ||
915 | } | ||
916 | |||
917 | static void mvs_tag_clear(struct mvs_info *mvi, u32 tag) | ||
918 | { | ||
919 | void *bitmap = (void *) &mvi->tags; | ||
920 | clear_bit(tag, bitmap); | ||
921 | } | ||
922 | |||
923 | static void mvs_tag_free(struct mvs_info *mvi, u32 tag) | ||
924 | { | ||
925 | mvs_tag_clear(mvi, tag); | ||
926 | } | ||
927 | |||
928 | static void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) | ||
929 | { | ||
930 | void *bitmap = (void *) &mvi->tags; | ||
931 | set_bit(tag, bitmap); | ||
932 | } | ||
933 | |||
934 | static int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) | ||
935 | { | ||
936 | unsigned int index, tag; | ||
937 | void *bitmap = (void *) &mvi->tags; | ||
938 | |||
939 | index = find_first_zero_bit(bitmap, MVS_SLOTS); | ||
940 | tag = index; | ||
941 | if (tag >= MVS_SLOTS) | ||
942 | return -SAS_QUEUE_FULL; | ||
943 | mvs_tag_set(mvi, tag); | ||
944 | *tag_out = tag; | ||
945 | return 0; | ||
946 | } | ||
947 | |||
948 | static void mvs_tag_init(struct mvs_info *mvi) | ||
949 | { | ||
950 | int i; | ||
951 | for (i = 0; i < MVS_SLOTS; ++i) | ||
952 | mvs_tag_clear(mvi, i); | ||
953 | } | ||
954 | |||
955 | #ifndef MVS_DISABLE_NVRAM | ||
956 | static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data) | ||
957 | { | ||
958 | int timeout = 1000; | ||
959 | |||
960 | if (addr & ~SPI_ADDR_MASK) | ||
961 | return -EINVAL; | ||
962 | |||
963 | writel(addr, regs + SPI_CMD); | ||
964 | writel(TWSI_RD, regs + SPI_CTL); | ||
965 | |||
966 | while (timeout-- > 0) { | ||
967 | if (readl(regs + SPI_CTL) & TWSI_RDY) { | ||
968 | *data = readl(regs + SPI_DATA); | ||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | udelay(10); | ||
973 | } | ||
974 | |||
975 | return -EBUSY; | ||
976 | } | ||
977 | |||
978 | static int mvs_eep_read_buf(void __iomem *regs, u32 addr, | ||
979 | void *buf, u32 buflen) | ||
980 | { | ||
981 | u32 addr_end, tmp_addr, i, j; | ||
982 | u32 tmp = 0; | ||
983 | int rc; | ||
984 | u8 *tmp8, *buf8 = buf; | ||
985 | |||
986 | addr_end = addr + buflen; | ||
987 | tmp_addr = ALIGN(addr, 4); | ||
988 | if (addr > 0xff) | ||
989 | return -EINVAL; | ||
990 | |||
991 | j = addr & 0x3; | ||
992 | if (j) { | ||
993 | rc = mvs_eep_read(regs, tmp_addr, &tmp); | ||
994 | if (rc) | ||
995 | return rc; | ||
996 | |||
997 | tmp8 = (u8 *)&tmp; | ||
998 | for (i = j; i < 4; i++) | ||
999 | *buf8++ = tmp8[i]; | ||
1000 | |||
1001 | tmp_addr += 4; | ||
1002 | } | ||
1003 | |||
1004 | for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) { | ||
1005 | rc = mvs_eep_read(regs, tmp_addr, &tmp); | ||
1006 | if (rc) | ||
1007 | return rc; | ||
1008 | |||
1009 | memcpy(buf8, &tmp, 4); | ||
1010 | buf8 += 4; | ||
1011 | } | ||
1012 | |||
1013 | if (tmp_addr < addr_end) { | ||
1014 | rc = mvs_eep_read(regs, tmp_addr, &tmp); | ||
1015 | if (rc) | ||
1016 | return rc; | ||
1017 | |||
1018 | tmp8 = (u8 *)&tmp; | ||
1019 | j = addr_end - tmp_addr; | ||
1020 | for (i = 0; i < j; i++) | ||
1021 | *buf8++ = tmp8[i]; | ||
1022 | |||
1023 | tmp_addr += 4; | ||
1024 | } | ||
1025 | 254 | ||
1026 | return 0; | 255 | case PHY_FUNC_HARD_RESET: |
1027 | } | 256 | if (tmp & PHY_RST_HARD) |
1028 | #endif | 257 | break; |
1029 | 258 | mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD); | |
1030 | static int mvs_nvram_read(struct mvs_info *mvi, u32 addr, | 259 | break; |
1031 | void *buf, u32 buflen) | ||
1032 | { | ||
1033 | #ifndef MVS_DISABLE_NVRAM | ||
1034 | void __iomem *regs = mvi->regs; | ||
1035 | int rc, i; | ||
1036 | u32 sum; | ||
1037 | u8 hdr[2], *tmp; | ||
1038 | const char *msg; | ||
1039 | |||
1040 | rc = mvs_eep_read_buf(regs, addr, &hdr, 2); | ||
1041 | if (rc) { | ||
1042 | msg = "nvram hdr read failed"; | ||
1043 | goto err_out; | ||
1044 | } | ||
1045 | rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen); | ||
1046 | if (rc) { | ||
1047 | msg = "nvram read failed"; | ||
1048 | goto err_out; | ||
1049 | } | ||
1050 | |||
1051 | if (hdr[0] != 0x5A) { | ||
1052 | /* entry id */ | ||
1053 | msg = "invalid nvram entry id"; | ||
1054 | rc = -ENOENT; | ||
1055 | goto err_out; | ||
1056 | } | ||
1057 | 260 | ||
1058 | tmp = buf; | 261 | case PHY_FUNC_LINK_RESET: |
1059 | sum = ((u32)hdr[0]) + ((u32)hdr[1]); | 262 | mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST); |
1060 | for (i = 0; i < buflen; i++) | 263 | break; |
1061 | sum += ((u32)tmp[i]); | ||
1062 | 264 | ||
1063 | if (sum) { | 265 | case PHY_FUNC_DISABLE: |
1064 | msg = "nvram checksum failure"; | 266 | case PHY_FUNC_RELEASE_SPINUP_HOLD: |
1065 | rc = -EILSEQ; | 267 | default: |
1066 | goto err_out; | 268 | rc = -EOPNOTSUPP; |
1067 | } | 269 | } |
1068 | 270 | ||
1069 | return 0; | ||
1070 | |||
1071 | err_out: | ||
1072 | dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg); | ||
1073 | return rc; | 271 | return rc; |
1074 | #else | ||
1075 | /* FIXME , For SAS target mode */ | ||
1076 | memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8); | ||
1077 | return 0; | ||
1078 | #endif | ||
1079 | } | 272 | } |
1080 | 273 | ||
1081 | static void mvs_bytes_dmaed(struct mvs_info *mvi, int i) | 274 | static void mvs_bytes_dmaed(struct mvs_info *mvi, int i) |
@@ -1111,28 +304,7 @@ static void mvs_bytes_dmaed(struct mvs_info *mvi, int i) | |||
1111 | PORTE_BYTES_DMAED); | 304 | PORTE_BYTES_DMAED); |
1112 | } | 305 | } |
1113 | 306 | ||
1114 | static int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time) | 307 | int mvs_slave_configure(struct scsi_device *sdev) |
1115 | { | ||
1116 | /* give the phy enabling interrupt event time to come in (1s | ||
1117 | * is empirically about all it takes) */ | ||
1118 | if (time < HZ) | ||
1119 | return 0; | ||
1120 | /* Wait for discovery to finish */ | ||
1121 | scsi_flush_work(shost); | ||
1122 | return 1; | ||
1123 | } | ||
1124 | |||
1125 | static void mvs_scan_start(struct Scsi_Host *shost) | ||
1126 | { | ||
1127 | int i; | ||
1128 | struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha; | ||
1129 | |||
1130 | for (i = 0; i < mvi->chip->n_phy; ++i) { | ||
1131 | mvs_bytes_dmaed(mvi, i); | ||
1132 | } | ||
1133 | } | ||
1134 | |||
1135 | static int mvs_slave_configure(struct scsi_device *sdev) | ||
1136 | { | 308 | { |
1137 | struct domain_device *dev = sdev_to_domain_dev(sdev); | 309 | struct domain_device *dev = sdev_to_domain_dev(sdev); |
1138 | int ret = sas_slave_configure(sdev); | 310 | int ret = sas_slave_configure(sdev); |
@@ -1151,456 +323,26 @@ static int mvs_slave_configure(struct scsi_device *sdev) | |||
1151 | return 0; | 323 | return 0; |
1152 | } | 324 | } |
1153 | 325 | ||
1154 | static void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) | 326 | void mvs_scan_start(struct Scsi_Host *shost) |
1155 | { | ||
1156 | struct pci_dev *pdev = mvi->pdev; | ||
1157 | struct sas_ha_struct *sas_ha = &mvi->sas; | ||
1158 | struct mvs_phy *phy = &mvi->phy[phy_no]; | ||
1159 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
1160 | |||
1161 | phy->irq_status = mvs_read_port_irq_stat(mvi, phy_no); | ||
1162 | /* | ||
1163 | * events is port event now , | ||
1164 | * we need check the interrupt status which belongs to per port. | ||
1165 | */ | ||
1166 | dev_printk(KERN_DEBUG, &pdev->dev, | ||
1167 | "Port %d Event = %X\n", | ||
1168 | phy_no, phy->irq_status); | ||
1169 | |||
1170 | if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) { | ||
1171 | mvs_release_task(mvi, phy_no); | ||
1172 | if (!mvs_is_phy_ready(mvi, phy_no)) { | ||
1173 | sas_phy_disconnected(sas_phy); | ||
1174 | sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL); | ||
1175 | dev_printk(KERN_INFO, &pdev->dev, | ||
1176 | "Port %d Unplug Notice\n", phy_no); | ||
1177 | |||
1178 | } else | ||
1179 | mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL); | ||
1180 | } | ||
1181 | if (!(phy->irq_status & PHYEV_DEC_ERR)) { | ||
1182 | if (phy->irq_status & PHYEV_COMWAKE) { | ||
1183 | u32 tmp = mvs_read_port_irq_mask(mvi, phy_no); | ||
1184 | mvs_write_port_irq_mask(mvi, phy_no, | ||
1185 | tmp | PHYEV_SIG_FIS); | ||
1186 | } | ||
1187 | if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) { | ||
1188 | phy->phy_status = mvs_is_phy_ready(mvi, phy_no); | ||
1189 | if (phy->phy_status) { | ||
1190 | mvs_detect_porttype(mvi, phy_no); | ||
1191 | |||
1192 | if (phy->phy_type & PORT_TYPE_SATA) { | ||
1193 | u32 tmp = mvs_read_port_irq_mask(mvi, | ||
1194 | phy_no); | ||
1195 | tmp &= ~PHYEV_SIG_FIS; | ||
1196 | mvs_write_port_irq_mask(mvi, | ||
1197 | phy_no, tmp); | ||
1198 | } | ||
1199 | |||
1200 | mvs_update_phyinfo(mvi, phy_no, 0); | ||
1201 | sas_ha->notify_phy_event(sas_phy, | ||
1202 | PHYE_OOB_DONE); | ||
1203 | mvs_bytes_dmaed(mvi, phy_no); | ||
1204 | } else { | ||
1205 | dev_printk(KERN_DEBUG, &pdev->dev, | ||
1206 | "plugin interrupt but phy is gone\n"); | ||
1207 | mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, | ||
1208 | NULL); | ||
1209 | } | ||
1210 | } else if (phy->irq_status & PHYEV_BROAD_CH) { | ||
1211 | mvs_release_task(mvi, phy_no); | ||
1212 | sas_ha->notify_port_event(sas_phy, | ||
1213 | PORTE_BROADCAST_RCVD); | ||
1214 | } | ||
1215 | } | ||
1216 | mvs_write_port_irq_stat(mvi, phy_no, phy->irq_status); | ||
1217 | } | ||
1218 | |||
1219 | static void mvs_int_sata(struct mvs_info *mvi) | ||
1220 | { | 327 | { |
1221 | u32 tmp; | ||
1222 | void __iomem *regs = mvi->regs; | ||
1223 | tmp = mr32(INT_STAT_SRS); | ||
1224 | mw32(INT_STAT_SRS, tmp & 0xFFFF); | ||
1225 | } | ||
1226 | |||
1227 | static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task, | ||
1228 | u32 slot_idx) | ||
1229 | { | ||
1230 | void __iomem *regs = mvi->regs; | ||
1231 | struct domain_device *dev = task->dev; | ||
1232 | struct asd_sas_port *sas_port = dev->port; | ||
1233 | struct mvs_port *port = mvi->slot_info[slot_idx].port; | ||
1234 | u32 reg_set, phy_mask; | ||
1235 | |||
1236 | if (!sas_protocol_ata(task->task_proto)) { | ||
1237 | reg_set = 0; | ||
1238 | phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap : | ||
1239 | sas_port->phy_mask; | ||
1240 | } else { | ||
1241 | reg_set = port->taskfileset; | ||
1242 | phy_mask = sas_port->phy_mask; | ||
1243 | } | ||
1244 | mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx | | ||
1245 | (TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) | | ||
1246 | (phy_mask << TXQ_PHY_SHIFT) | | ||
1247 | (reg_set << TXQ_SRS_SHIFT)); | ||
1248 | |||
1249 | mw32(TX_PROD_IDX, mvi->tx_prod); | ||
1250 | mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); | ||
1251 | } | ||
1252 | |||
1253 | static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, | ||
1254 | u32 slot_idx, int err) | ||
1255 | { | ||
1256 | struct mvs_port *port = mvi->slot_info[slot_idx].port; | ||
1257 | struct task_status_struct *tstat = &task->task_status; | ||
1258 | struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; | ||
1259 | int stat = SAM_GOOD; | ||
1260 | |||
1261 | resp->frame_len = sizeof(struct dev_to_host_fis); | ||
1262 | memcpy(&resp->ending_fis[0], | ||
1263 | SATA_RECEIVED_D2H_FIS(port->taskfileset), | ||
1264 | sizeof(struct dev_to_host_fis)); | ||
1265 | tstat->buf_valid_size = sizeof(*resp); | ||
1266 | if (unlikely(err)) | ||
1267 | stat = SAS_PROTO_RESPONSE; | ||
1268 | return stat; | ||
1269 | } | ||
1270 | |||
1271 | static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) | ||
1272 | { | ||
1273 | u32 slot_idx = rx_desc & RXQ_SLOT_MASK; | ||
1274 | mvs_tag_clear(mvi, slot_idx); | ||
1275 | } | ||
1276 | |||
1277 | static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, | ||
1278 | struct mvs_slot_info *slot, u32 slot_idx) | ||
1279 | { | ||
1280 | if (!sas_protocol_ata(task->task_proto)) | ||
1281 | if (slot->n_elem) | ||
1282 | pci_unmap_sg(mvi->pdev, task->scatter, | ||
1283 | slot->n_elem, task->data_dir); | ||
1284 | |||
1285 | switch (task->task_proto) { | ||
1286 | case SAS_PROTOCOL_SMP: | ||
1287 | pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1, | ||
1288 | PCI_DMA_FROMDEVICE); | ||
1289 | pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1, | ||
1290 | PCI_DMA_TODEVICE); | ||
1291 | break; | ||
1292 | |||
1293 | case SAS_PROTOCOL_SATA: | ||
1294 | case SAS_PROTOCOL_STP: | ||
1295 | case SAS_PROTOCOL_SSP: | ||
1296 | default: | ||
1297 | /* do nothing */ | ||
1298 | break; | ||
1299 | } | ||
1300 | list_del(&slot->list); | ||
1301 | task->lldd_task = NULL; | ||
1302 | slot->task = NULL; | ||
1303 | slot->port = NULL; | ||
1304 | } | ||
1305 | |||
1306 | static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, | ||
1307 | u32 slot_idx) | ||
1308 | { | ||
1309 | struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; | ||
1310 | u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response)); | ||
1311 | u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4)); | ||
1312 | int stat = SAM_CHECK_COND; | ||
1313 | |||
1314 | if (err_dw1 & SLOT_BSY_ERR) { | ||
1315 | stat = SAS_QUEUE_FULL; | ||
1316 | mvs_slot_reset(mvi, task, slot_idx); | ||
1317 | } | ||
1318 | switch (task->task_proto) { | ||
1319 | case SAS_PROTOCOL_SSP: | ||
1320 | break; | ||
1321 | case SAS_PROTOCOL_SMP: | ||
1322 | break; | ||
1323 | case SAS_PROTOCOL_SATA: | ||
1324 | case SAS_PROTOCOL_STP: | ||
1325 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: | ||
1326 | if (err_dw0 & TFILE_ERR) | ||
1327 | stat = mvs_sata_done(mvi, task, slot_idx, 1); | ||
1328 | break; | ||
1329 | default: | ||
1330 | break; | ||
1331 | } | ||
1332 | |||
1333 | mvs_hexdump(16, (u8 *) slot->response, 0); | ||
1334 | return stat; | ||
1335 | } | ||
1336 | |||
1337 | static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) | ||
1338 | { | ||
1339 | u32 slot_idx = rx_desc & RXQ_SLOT_MASK; | ||
1340 | struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; | ||
1341 | struct sas_task *task = slot->task; | ||
1342 | struct task_status_struct *tstat; | ||
1343 | struct mvs_port *port; | ||
1344 | bool aborted; | ||
1345 | void *to; | ||
1346 | |||
1347 | if (unlikely(!task || !task->lldd_task)) | ||
1348 | return -1; | ||
1349 | |||
1350 | mvs_hba_cq_dump(mvi); | ||
1351 | |||
1352 | spin_lock(&task->task_state_lock); | ||
1353 | aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; | ||
1354 | if (!aborted) { | ||
1355 | task->task_state_flags &= | ||
1356 | ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); | ||
1357 | task->task_state_flags |= SAS_TASK_STATE_DONE; | ||
1358 | } | ||
1359 | spin_unlock(&task->task_state_lock); | ||
1360 | |||
1361 | if (aborted) { | ||
1362 | mvs_slot_task_free(mvi, task, slot, slot_idx); | ||
1363 | mvs_slot_free(mvi, rx_desc); | ||
1364 | return -1; | ||
1365 | } | ||
1366 | |||
1367 | port = slot->port; | ||
1368 | tstat = &task->task_status; | ||
1369 | memset(tstat, 0, sizeof(*tstat)); | ||
1370 | tstat->resp = SAS_TASK_COMPLETE; | ||
1371 | |||
1372 | if (unlikely(!port->port_attached || flags)) { | ||
1373 | mvs_slot_err(mvi, task, slot_idx); | ||
1374 | if (!sas_protocol_ata(task->task_proto)) | ||
1375 | tstat->stat = SAS_PHY_DOWN; | ||
1376 | goto out; | ||
1377 | } | ||
1378 | |||
1379 | /* error info record present */ | ||
1380 | if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) { | ||
1381 | tstat->stat = mvs_slot_err(mvi, task, slot_idx); | ||
1382 | goto out; | ||
1383 | } | ||
1384 | |||
1385 | switch (task->task_proto) { | ||
1386 | case SAS_PROTOCOL_SSP: | ||
1387 | /* hw says status == 0, datapres == 0 */ | ||
1388 | if (rx_desc & RXQ_GOOD) { | ||
1389 | tstat->stat = SAM_GOOD; | ||
1390 | tstat->resp = SAS_TASK_COMPLETE; | ||
1391 | } | ||
1392 | /* response frame present */ | ||
1393 | else if (rx_desc & RXQ_RSP) { | ||
1394 | struct ssp_response_iu *iu = | ||
1395 | slot->response + sizeof(struct mvs_err_info); | ||
1396 | sas_ssp_task_response(&mvi->pdev->dev, task, iu); | ||
1397 | } | ||
1398 | |||
1399 | /* should never happen? */ | ||
1400 | else | ||
1401 | tstat->stat = SAM_CHECK_COND; | ||
1402 | break; | ||
1403 | |||
1404 | case SAS_PROTOCOL_SMP: { | ||
1405 | struct scatterlist *sg_resp = &task->smp_task.smp_resp; | ||
1406 | tstat->stat = SAM_GOOD; | ||
1407 | to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); | ||
1408 | memcpy(to + sg_resp->offset, | ||
1409 | slot->response + sizeof(struct mvs_err_info), | ||
1410 | sg_dma_len(sg_resp)); | ||
1411 | kunmap_atomic(to, KM_IRQ0); | ||
1412 | break; | ||
1413 | } | ||
1414 | |||
1415 | case SAS_PROTOCOL_SATA: | ||
1416 | case SAS_PROTOCOL_STP: | ||
1417 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { | ||
1418 | tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0); | ||
1419 | break; | ||
1420 | } | ||
1421 | |||
1422 | default: | ||
1423 | tstat->stat = SAM_CHECK_COND; | ||
1424 | break; | ||
1425 | } | ||
1426 | |||
1427 | out: | ||
1428 | mvs_slot_task_free(mvi, task, slot, slot_idx); | ||
1429 | if (unlikely(tstat->stat != SAS_QUEUE_FULL)) | ||
1430 | mvs_slot_free(mvi, rx_desc); | ||
1431 | |||
1432 | spin_unlock(&mvi->lock); | ||
1433 | task->task_done(task); | ||
1434 | spin_lock(&mvi->lock); | ||
1435 | return tstat->stat; | ||
1436 | } | ||
1437 | |||
1438 | static void mvs_release_task(struct mvs_info *mvi, int phy_no) | ||
1439 | { | ||
1440 | struct list_head *pos, *n; | ||
1441 | struct mvs_slot_info *slot; | ||
1442 | struct mvs_phy *phy = &mvi->phy[phy_no]; | ||
1443 | struct mvs_port *port = phy->port; | ||
1444 | u32 rx_desc; | ||
1445 | |||
1446 | if (!port) | ||
1447 | return; | ||
1448 | |||
1449 | list_for_each_safe(pos, n, &port->list) { | ||
1450 | slot = container_of(pos, struct mvs_slot_info, list); | ||
1451 | rx_desc = (u32) (slot - mvi->slot_info); | ||
1452 | mvs_slot_complete(mvi, rx_desc, 1); | ||
1453 | } | ||
1454 | } | ||
1455 | |||
1456 | static void mvs_int_full(struct mvs_info *mvi) | ||
1457 | { | ||
1458 | void __iomem *regs = mvi->regs; | ||
1459 | u32 tmp, stat; | ||
1460 | int i; | 328 | int i; |
329 | struct mvs_info *mvi = SHOST_TO_SAS_HA(shost)->lldd_ha; | ||
1461 | 330 | ||
1462 | stat = mr32(INT_STAT); | 331 | for (i = 0; i < mvi->chip->n_phy; ++i) { |
1463 | 332 | mvs_bytes_dmaed(mvi, i); | |
1464 | mvs_int_rx(mvi, false); | ||
1465 | |||
1466 | for (i = 0; i < MVS_MAX_PORTS; i++) { | ||
1467 | tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED); | ||
1468 | if (tmp) | ||
1469 | mvs_int_port(mvi, i, tmp); | ||
1470 | } | 333 | } |
1471 | |||
1472 | if (stat & CINT_SRS) | ||
1473 | mvs_int_sata(mvi); | ||
1474 | |||
1475 | mw32(INT_STAT, stat); | ||
1476 | } | 334 | } |
1477 | 335 | ||
1478 | static int mvs_int_rx(struct mvs_info *mvi, bool self_clear) | 336 | int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time) |
1479 | { | 337 | { |
1480 | void __iomem *regs = mvi->regs; | 338 | /* give the phy enabling interrupt event time to come in (1s |
1481 | u32 rx_prod_idx, rx_desc; | 339 | * is empirically about all it takes) */ |
1482 | bool attn = false; | 340 | if (time < HZ) |
1483 | struct pci_dev *pdev = mvi->pdev; | ||
1484 | |||
1485 | /* the first dword in the RX ring is special: it contains | ||
1486 | * a mirror of the hardware's RX producer index, so that | ||
1487 | * we don't have to stall the CPU reading that register. | ||
1488 | * The actual RX ring is offset by one dword, due to this. | ||
1489 | */ | ||
1490 | rx_prod_idx = mvi->rx_cons; | ||
1491 | mvi->rx_cons = le32_to_cpu(mvi->rx[0]); | ||
1492 | if (mvi->rx_cons == 0xfff) /* h/w hasn't touched RX ring yet */ | ||
1493 | return 0; | ||
1494 | |||
1495 | /* The CMPL_Q may come late, read from register and try again | ||
1496 | * note: if coalescing is enabled, | ||
1497 | * it will need to read from register every time for sure | ||
1498 | */ | ||
1499 | if (mvi->rx_cons == rx_prod_idx) | ||
1500 | mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK; | ||
1501 | |||
1502 | if (mvi->rx_cons == rx_prod_idx) | ||
1503 | return 0; | 341 | return 0; |
1504 | 342 | /* Wait for discovery to finish */ | |
1505 | while (mvi->rx_cons != rx_prod_idx) { | 343 | scsi_flush_work(shost); |
1506 | 344 | return 1; | |
1507 | /* increment our internal RX consumer pointer */ | ||
1508 | rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1); | ||
1509 | |||
1510 | rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]); | ||
1511 | |||
1512 | if (likely(rx_desc & RXQ_DONE)) | ||
1513 | mvs_slot_complete(mvi, rx_desc, 0); | ||
1514 | if (rx_desc & RXQ_ATTN) { | ||
1515 | attn = true; | ||
1516 | dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n", | ||
1517 | rx_desc); | ||
1518 | } else if (rx_desc & RXQ_ERR) { | ||
1519 | if (!(rx_desc & RXQ_DONE)) | ||
1520 | mvs_slot_complete(mvi, rx_desc, 0); | ||
1521 | dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n", | ||
1522 | rx_desc); | ||
1523 | } else if (rx_desc & RXQ_SLOT_RESET) { | ||
1524 | dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n", | ||
1525 | rx_desc); | ||
1526 | mvs_slot_free(mvi, rx_desc); | ||
1527 | } | ||
1528 | } | ||
1529 | |||
1530 | if (attn && self_clear) | ||
1531 | mvs_int_full(mvi); | ||
1532 | |||
1533 | return 0; | ||
1534 | } | ||
1535 | |||
1536 | #ifdef MVS_USE_TASKLET | ||
1537 | static void mvs_tasklet(unsigned long data) | ||
1538 | { | ||
1539 | struct mvs_info *mvi = (struct mvs_info *) data; | ||
1540 | unsigned long flags; | ||
1541 | |||
1542 | spin_lock_irqsave(&mvi->lock, flags); | ||
1543 | |||
1544 | #ifdef MVS_DISABLE_MSI | ||
1545 | mvs_int_full(mvi); | ||
1546 | #else | ||
1547 | mvs_int_rx(mvi, true); | ||
1548 | #endif | ||
1549 | spin_unlock_irqrestore(&mvi->lock, flags); | ||
1550 | } | ||
1551 | #endif | ||
1552 | |||
1553 | static irqreturn_t mvs_interrupt(int irq, void *opaque) | ||
1554 | { | ||
1555 | struct mvs_info *mvi = opaque; | ||
1556 | void __iomem *regs = mvi->regs; | ||
1557 | u32 stat; | ||
1558 | |||
1559 | stat = mr32(GBL_INT_STAT); | ||
1560 | |||
1561 | if (stat == 0 || stat == 0xffffffff) | ||
1562 | return IRQ_NONE; | ||
1563 | |||
1564 | /* clear CMD_CMPLT ASAP */ | ||
1565 | mw32_f(INT_STAT, CINT_DONE); | ||
1566 | |||
1567 | #ifndef MVS_USE_TASKLET | ||
1568 | spin_lock(&mvi->lock); | ||
1569 | |||
1570 | mvs_int_full(mvi); | ||
1571 | |||
1572 | spin_unlock(&mvi->lock); | ||
1573 | #else | ||
1574 | tasklet_schedule(&mvi->tasklet); | ||
1575 | #endif | ||
1576 | return IRQ_HANDLED; | ||
1577 | } | ||
1578 | |||
1579 | #ifndef MVS_DISABLE_MSI | ||
1580 | static irqreturn_t mvs_msi_interrupt(int irq, void *opaque) | ||
1581 | { | ||
1582 | struct mvs_info *mvi = opaque; | ||
1583 | |||
1584 | #ifndef MVS_USE_TASKLET | ||
1585 | spin_lock(&mvi->lock); | ||
1586 | |||
1587 | mvs_int_rx(mvi, true); | ||
1588 | |||
1589 | spin_unlock(&mvi->lock); | ||
1590 | #else | ||
1591 | tasklet_schedule(&mvi->tasklet); | ||
1592 | #endif | ||
1593 | return IRQ_HANDLED; | ||
1594 | } | 345 | } |
1595 | #endif | ||
1596 | |||
1597 | struct mvs_task_exec_info { | ||
1598 | struct sas_task *task; | ||
1599 | struct mvs_cmd_hdr *hdr; | ||
1600 | struct mvs_port *port; | ||
1601 | u32 tag; | ||
1602 | int n_elem; | ||
1603 | }; | ||
1604 | 346 | ||
1605 | static int mvs_task_prep_smp(struct mvs_info *mvi, | 347 | static int mvs_task_prep_smp(struct mvs_info *mvi, |
1606 | struct mvs_task_exec_info *tei) | 348 | struct mvs_task_exec_info *tei) |
@@ -1728,62 +470,6 @@ err_out: | |||
1728 | return rc; | 470 | return rc; |
1729 | } | 471 | } |
1730 | 472 | ||
1731 | static void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port) | ||
1732 | { | ||
1733 | void __iomem *regs = mvi->regs; | ||
1734 | u32 tmp, offs; | ||
1735 | u8 *tfs = &port->taskfileset; | ||
1736 | |||
1737 | if (*tfs == MVS_ID_NOT_MAPPED) | ||
1738 | return; | ||
1739 | |||
1740 | offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT); | ||
1741 | if (*tfs < 16) { | ||
1742 | tmp = mr32(PCS); | ||
1743 | mw32(PCS, tmp & ~offs); | ||
1744 | } else { | ||
1745 | tmp = mr32(CTL); | ||
1746 | mw32(CTL, tmp & ~offs); | ||
1747 | } | ||
1748 | |||
1749 | tmp = mr32(INT_STAT_SRS) & (1U << *tfs); | ||
1750 | if (tmp) | ||
1751 | mw32(INT_STAT_SRS, tmp); | ||
1752 | |||
1753 | *tfs = MVS_ID_NOT_MAPPED; | ||
1754 | } | ||
1755 | |||
1756 | static u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port) | ||
1757 | { | ||
1758 | int i; | ||
1759 | u32 tmp, offs; | ||
1760 | void __iomem *regs = mvi->regs; | ||
1761 | |||
1762 | if (port->taskfileset != MVS_ID_NOT_MAPPED) | ||
1763 | return 0; | ||
1764 | |||
1765 | tmp = mr32(PCS); | ||
1766 | |||
1767 | for (i = 0; i < mvi->chip->srs_sz; i++) { | ||
1768 | if (i == 16) | ||
1769 | tmp = mr32(CTL); | ||
1770 | offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT); | ||
1771 | if (!(tmp & offs)) { | ||
1772 | port->taskfileset = i; | ||
1773 | |||
1774 | if (i < 16) | ||
1775 | mw32(PCS, tmp | offs); | ||
1776 | else | ||
1777 | mw32(CTL, tmp | offs); | ||
1778 | tmp = mr32(INT_STAT_SRS) & (1U << i); | ||
1779 | if (tmp) | ||
1780 | mw32(INT_STAT_SRS, tmp); | ||
1781 | return 0; | ||
1782 | } | ||
1783 | } | ||
1784 | return MVS_ID_NOT_MAPPED; | ||
1785 | } | ||
1786 | |||
1787 | static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag) | 473 | static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag) |
1788 | { | 474 | { |
1789 | struct ata_queued_cmd *qc = task->uldd_task; | 475 | struct ata_queued_cmd *qc = task->uldd_task; |
@@ -2037,7 +723,7 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi, | |||
2037 | return 0; | 723 | return 0; |
2038 | } | 724 | } |
2039 | 725 | ||
2040 | static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags) | 726 | int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags) |
2041 | { | 727 | { |
2042 | struct domain_device *dev = task->dev; | 728 | struct domain_device *dev = task->dev; |
2043 | struct mvs_info *mvi = dev->port->ha->lldd_ha; | 729 | struct mvs_info *mvi = dev->port->ha->lldd_ha; |
@@ -2157,538 +843,39 @@ out_done: | |||
2157 | return rc; | 843 | return rc; |
2158 | } | 844 | } |
2159 | 845 | ||
2160 | static int mvs_task_abort(struct sas_task *task) | 846 | static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) |
2161 | { | 847 | { |
2162 | int rc; | 848 | u32 slot_idx = rx_desc & RXQ_SLOT_MASK; |
2163 | unsigned long flags; | 849 | mvs_tag_clear(mvi, slot_idx); |
2164 | struct mvs_info *mvi = task->dev->port->ha->lldd_ha; | 850 | } |
2165 | struct pci_dev *pdev = mvi->pdev; | ||
2166 | int tag; | ||
2167 | 851 | ||
2168 | spin_lock_irqsave(&task->task_state_lock, flags); | 852 | static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, |
2169 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | 853 | struct mvs_slot_info *slot, u32 slot_idx) |
2170 | rc = TMF_RESP_FUNC_COMPLETE; | 854 | { |
2171 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 855 | if (!sas_protocol_ata(task->task_proto)) |
2172 | goto out_done; | 856 | if (slot->n_elem) |
2173 | } | 857 | pci_unmap_sg(mvi->pdev, task->scatter, |
2174 | spin_unlock_irqrestore(&task->task_state_lock, flags); | 858 | slot->n_elem, task->data_dir); |
2175 | 859 | ||
2176 | switch (task->task_proto) { | 860 | switch (task->task_proto) { |
2177 | case SAS_PROTOCOL_SMP: | 861 | case SAS_PROTOCOL_SMP: |
2178 | dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n"); | 862 | pci_unmap_sg(mvi->pdev, &task->smp_task.smp_resp, 1, |
2179 | break; | 863 | PCI_DMA_FROMDEVICE); |
2180 | case SAS_PROTOCOL_SSP: | 864 | pci_unmap_sg(mvi->pdev, &task->smp_task.smp_req, 1, |
2181 | dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n"); | 865 | PCI_DMA_TODEVICE); |
2182 | break; | 866 | break; |
867 | |||
2183 | case SAS_PROTOCOL_SATA: | 868 | case SAS_PROTOCOL_SATA: |
2184 | case SAS_PROTOCOL_STP: | 869 | case SAS_PROTOCOL_STP: |
2185 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{ | 870 | case SAS_PROTOCOL_SSP: |
2186 | dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n"); | ||
2187 | #if _MV_DUMP | ||
2188 | dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n"); | ||
2189 | mvs_hexdump(sizeof(struct host_to_dev_fis), | ||
2190 | (void *)&task->ata_task.fis, 0); | ||
2191 | dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n"); | ||
2192 | mvs_hexdump(16, task->ata_task.atapi_packet, 0); | ||
2193 | #endif | ||
2194 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
2195 | if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) { | ||
2196 | /* TODO */ | ||
2197 | ; | ||
2198 | } | ||
2199 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
2200 | break; | ||
2201 | } | ||
2202 | default: | 871 | default: |
872 | /* do nothing */ | ||
2203 | break; | 873 | break; |
2204 | } | 874 | } |
2205 | 875 | list_del(&slot->list); | |
2206 | if (mvs_find_tag(mvi, task, &tag)) { | 876 | task->lldd_task = NULL; |
2207 | spin_lock_irqsave(&mvi->lock, flags); | 877 | slot->task = NULL; |
2208 | mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag); | 878 | slot->port = NULL; |
2209 | spin_unlock_irqrestore(&mvi->lock, flags); | ||
2210 | } | ||
2211 | if (!mvs_task_exec(task, 1, GFP_ATOMIC)) | ||
2212 | rc = TMF_RESP_FUNC_COMPLETE; | ||
2213 | else | ||
2214 | rc = TMF_RESP_FUNC_FAILED; | ||
2215 | out_done: | ||
2216 | return rc; | ||
2217 | } | ||
2218 | |||
2219 | static void mvs_free(struct mvs_info *mvi) | ||
2220 | { | ||
2221 | int i; | ||
2222 | |||
2223 | if (!mvi) | ||
2224 | return; | ||
2225 | |||
2226 | for (i = 0; i < MVS_SLOTS; i++) { | ||
2227 | struct mvs_slot_info *slot = &mvi->slot_info[i]; | ||
2228 | |||
2229 | if (slot->buf) | ||
2230 | dma_free_coherent(&mvi->pdev->dev, MVS_SLOT_BUF_SZ, | ||
2231 | slot->buf, slot->buf_dma); | ||
2232 | } | ||
2233 | |||
2234 | if (mvi->tx) | ||
2235 | dma_free_coherent(&mvi->pdev->dev, | ||
2236 | sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, | ||
2237 | mvi->tx, mvi->tx_dma); | ||
2238 | if (mvi->rx_fis) | ||
2239 | dma_free_coherent(&mvi->pdev->dev, MVS_RX_FISL_SZ, | ||
2240 | mvi->rx_fis, mvi->rx_fis_dma); | ||
2241 | if (mvi->rx) | ||
2242 | dma_free_coherent(&mvi->pdev->dev, | ||
2243 | sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), | ||
2244 | mvi->rx, mvi->rx_dma); | ||
2245 | if (mvi->slot) | ||
2246 | dma_free_coherent(&mvi->pdev->dev, | ||
2247 | sizeof(*mvi->slot) * MVS_SLOTS, | ||
2248 | mvi->slot, mvi->slot_dma); | ||
2249 | #ifdef MVS_ENABLE_PERI | ||
2250 | if (mvi->peri_regs) | ||
2251 | iounmap(mvi->peri_regs); | ||
2252 | #endif | ||
2253 | if (mvi->regs) | ||
2254 | iounmap(mvi->regs); | ||
2255 | if (mvi->shost) | ||
2256 | scsi_host_put(mvi->shost); | ||
2257 | kfree(mvi->sas.sas_port); | ||
2258 | kfree(mvi->sas.sas_phy); | ||
2259 | kfree(mvi); | ||
2260 | } | ||
2261 | |||
2262 | /* FIXME: locking? */ | ||
2263 | static int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, | ||
2264 | void *funcdata) | ||
2265 | { | ||
2266 | struct mvs_info *mvi = sas_phy->ha->lldd_ha; | ||
2267 | int rc = 0, phy_id = sas_phy->id; | ||
2268 | u32 tmp; | ||
2269 | |||
2270 | tmp = mvs_read_phy_ctl(mvi, phy_id); | ||
2271 | |||
2272 | switch (func) { | ||
2273 | case PHY_FUNC_SET_LINK_RATE:{ | ||
2274 | struct sas_phy_linkrates *rates = funcdata; | ||
2275 | u32 lrmin = 0, lrmax = 0; | ||
2276 | |||
2277 | lrmin = (rates->minimum_linkrate << 8); | ||
2278 | lrmax = (rates->maximum_linkrate << 12); | ||
2279 | |||
2280 | if (lrmin) { | ||
2281 | tmp &= ~(0xf << 8); | ||
2282 | tmp |= lrmin; | ||
2283 | } | ||
2284 | if (lrmax) { | ||
2285 | tmp &= ~(0xf << 12); | ||
2286 | tmp |= lrmax; | ||
2287 | } | ||
2288 | mvs_write_phy_ctl(mvi, phy_id, tmp); | ||
2289 | break; | ||
2290 | } | ||
2291 | |||
2292 | case PHY_FUNC_HARD_RESET: | ||
2293 | if (tmp & PHY_RST_HARD) | ||
2294 | break; | ||
2295 | mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST_HARD); | ||
2296 | break; | ||
2297 | |||
2298 | case PHY_FUNC_LINK_RESET: | ||
2299 | mvs_write_phy_ctl(mvi, phy_id, tmp | PHY_RST); | ||
2300 | break; | ||
2301 | |||
2302 | case PHY_FUNC_DISABLE: | ||
2303 | case PHY_FUNC_RELEASE_SPINUP_HOLD: | ||
2304 | default: | ||
2305 | rc = -EOPNOTSUPP; | ||
2306 | } | ||
2307 | |||
2308 | return rc; | ||
2309 | } | ||
2310 | |||
2311 | static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) | ||
2312 | { | ||
2313 | struct mvs_phy *phy = &mvi->phy[phy_id]; | ||
2314 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
2315 | |||
2316 | sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; | ||
2317 | sas_phy->class = SAS; | ||
2318 | sas_phy->iproto = SAS_PROTOCOL_ALL; | ||
2319 | sas_phy->tproto = 0; | ||
2320 | sas_phy->type = PHY_TYPE_PHYSICAL; | ||
2321 | sas_phy->role = PHY_ROLE_INITIATOR; | ||
2322 | sas_phy->oob_mode = OOB_NOT_CONNECTED; | ||
2323 | sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; | ||
2324 | |||
2325 | sas_phy->id = phy_id; | ||
2326 | sas_phy->sas_addr = &mvi->sas_addr[0]; | ||
2327 | sas_phy->frame_rcvd = &phy->frame_rcvd[0]; | ||
2328 | sas_phy->ha = &mvi->sas; | ||
2329 | sas_phy->lldd_phy = phy; | ||
2330 | } | ||
2331 | |||
2332 | static struct mvs_info *__devinit mvs_alloc(struct pci_dev *pdev, | ||
2333 | const struct pci_device_id *ent) | ||
2334 | { | ||
2335 | struct mvs_info *mvi; | ||
2336 | unsigned long res_start, res_len, res_flag; | ||
2337 | struct asd_sas_phy **arr_phy; | ||
2338 | struct asd_sas_port **arr_port; | ||
2339 | const struct mvs_chip_info *chip = &mvs_chips[ent->driver_data]; | ||
2340 | int i; | ||
2341 | |||
2342 | /* | ||
2343 | * alloc and init our per-HBA mvs_info struct | ||
2344 | */ | ||
2345 | |||
2346 | mvi = kzalloc(sizeof(*mvi), GFP_KERNEL); | ||
2347 | if (!mvi) | ||
2348 | return NULL; | ||
2349 | |||
2350 | spin_lock_init(&mvi->lock); | ||
2351 | #ifdef MVS_USE_TASKLET | ||
2352 | tasklet_init(&mvi->tasklet, mvs_tasklet, (unsigned long)mvi); | ||
2353 | #endif | ||
2354 | mvi->pdev = pdev; | ||
2355 | mvi->chip = chip; | ||
2356 | |||
2357 | if (pdev->device == 0x6440 && pdev->revision == 0) | ||
2358 | mvi->flags |= MVF_PHY_PWR_FIX; | ||
2359 | |||
2360 | /* | ||
2361 | * alloc and init SCSI, SAS glue | ||
2362 | */ | ||
2363 | |||
2364 | mvi->shost = scsi_host_alloc(&mvs_sht, sizeof(void *)); | ||
2365 | if (!mvi->shost) | ||
2366 | goto err_out; | ||
2367 | |||
2368 | arr_phy = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL); | ||
2369 | arr_port = kcalloc(MVS_MAX_PHYS, sizeof(void *), GFP_KERNEL); | ||
2370 | if (!arr_phy || !arr_port) | ||
2371 | goto err_out; | ||
2372 | |||
2373 | for (i = 0; i < MVS_MAX_PHYS; i++) { | ||
2374 | mvs_phy_init(mvi, i); | ||
2375 | arr_phy[i] = &mvi->phy[i].sas_phy; | ||
2376 | arr_port[i] = &mvi->port[i].sas_port; | ||
2377 | mvi->port[i].taskfileset = MVS_ID_NOT_MAPPED; | ||
2378 | mvi->port[i].wide_port_phymap = 0; | ||
2379 | mvi->port[i].port_attached = 0; | ||
2380 | INIT_LIST_HEAD(&mvi->port[i].list); | ||
2381 | } | ||
2382 | |||
2383 | SHOST_TO_SAS_HA(mvi->shost) = &mvi->sas; | ||
2384 | mvi->shost->transportt = mvs_stt; | ||
2385 | mvi->shost->max_id = 21; | ||
2386 | mvi->shost->max_lun = ~0; | ||
2387 | mvi->shost->max_channel = 0; | ||
2388 | mvi->shost->max_cmd_len = 16; | ||
2389 | |||
2390 | mvi->sas.sas_ha_name = DRV_NAME; | ||
2391 | mvi->sas.dev = &pdev->dev; | ||
2392 | mvi->sas.lldd_module = THIS_MODULE; | ||
2393 | mvi->sas.sas_addr = &mvi->sas_addr[0]; | ||
2394 | mvi->sas.sas_phy = arr_phy; | ||
2395 | mvi->sas.sas_port = arr_port; | ||
2396 | mvi->sas.num_phys = chip->n_phy; | ||
2397 | mvi->sas.lldd_max_execute_num = 1; | ||
2398 | mvi->sas.lldd_queue_size = MVS_QUEUE_SIZE; | ||
2399 | mvi->shost->can_queue = MVS_CAN_QUEUE; | ||
2400 | mvi->shost->cmd_per_lun = MVS_SLOTS / mvi->sas.num_phys; | ||
2401 | mvi->sas.lldd_ha = mvi; | ||
2402 | mvi->sas.core.shost = mvi->shost; | ||
2403 | |||
2404 | mvs_tag_init(mvi); | ||
2405 | |||
2406 | /* | ||
2407 | * ioremap main and peripheral registers | ||
2408 | */ | ||
2409 | |||
2410 | #ifdef MVS_ENABLE_PERI | ||
2411 | res_start = pci_resource_start(pdev, 2); | ||
2412 | res_len = pci_resource_len(pdev, 2); | ||
2413 | if (!res_start || !res_len) | ||
2414 | goto err_out; | ||
2415 | |||
2416 | mvi->peri_regs = ioremap_nocache(res_start, res_len); | ||
2417 | if (!mvi->peri_regs) | ||
2418 | goto err_out; | ||
2419 | #endif | ||
2420 | |||
2421 | res_start = pci_resource_start(pdev, 4); | ||
2422 | res_len = pci_resource_len(pdev, 4); | ||
2423 | if (!res_start || !res_len) | ||
2424 | goto err_out; | ||
2425 | |||
2426 | res_flag = pci_resource_flags(pdev, 4); | ||
2427 | if (res_flag & IORESOURCE_CACHEABLE) | ||
2428 | mvi->regs = ioremap(res_start, res_len); | ||
2429 | else | ||
2430 | mvi->regs = ioremap_nocache(res_start, res_len); | ||
2431 | |||
2432 | if (!mvi->regs) | ||
2433 | goto err_out; | ||
2434 | |||
2435 | /* | ||
2436 | * alloc and init our DMA areas | ||
2437 | */ | ||
2438 | |||
2439 | mvi->tx = dma_alloc_coherent(&pdev->dev, | ||
2440 | sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, | ||
2441 | &mvi->tx_dma, GFP_KERNEL); | ||
2442 | if (!mvi->tx) | ||
2443 | goto err_out; | ||
2444 | memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ); | ||
2445 | |||
2446 | mvi->rx_fis = dma_alloc_coherent(&pdev->dev, MVS_RX_FISL_SZ, | ||
2447 | &mvi->rx_fis_dma, GFP_KERNEL); | ||
2448 | if (!mvi->rx_fis) | ||
2449 | goto err_out; | ||
2450 | memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ); | ||
2451 | |||
2452 | mvi->rx = dma_alloc_coherent(&pdev->dev, | ||
2453 | sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), | ||
2454 | &mvi->rx_dma, GFP_KERNEL); | ||
2455 | if (!mvi->rx) | ||
2456 | goto err_out; | ||
2457 | memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1)); | ||
2458 | |||
2459 | mvi->rx[0] = cpu_to_le32(0xfff); | ||
2460 | mvi->rx_cons = 0xfff; | ||
2461 | |||
2462 | mvi->slot = dma_alloc_coherent(&pdev->dev, | ||
2463 | sizeof(*mvi->slot) * MVS_SLOTS, | ||
2464 | &mvi->slot_dma, GFP_KERNEL); | ||
2465 | if (!mvi->slot) | ||
2466 | goto err_out; | ||
2467 | memset(mvi->slot, 0, sizeof(*mvi->slot) * MVS_SLOTS); | ||
2468 | |||
2469 | for (i = 0; i < MVS_SLOTS; i++) { | ||
2470 | struct mvs_slot_info *slot = &mvi->slot_info[i]; | ||
2471 | |||
2472 | slot->buf = dma_alloc_coherent(&pdev->dev, MVS_SLOT_BUF_SZ, | ||
2473 | &slot->buf_dma, GFP_KERNEL); | ||
2474 | if (!slot->buf) | ||
2475 | goto err_out; | ||
2476 | memset(slot->buf, 0, MVS_SLOT_BUF_SZ); | ||
2477 | } | ||
2478 | |||
2479 | /* finally, read NVRAM to get our SAS address */ | ||
2480 | if (mvs_nvram_read(mvi, NVR_SAS_ADDR, &mvi->sas_addr, 8)) | ||
2481 | goto err_out; | ||
2482 | return mvi; | ||
2483 | |||
2484 | err_out: | ||
2485 | mvs_free(mvi); | ||
2486 | return NULL; | ||
2487 | } | ||
2488 | |||
2489 | static u32 mvs_cr32(void __iomem *regs, u32 addr) | ||
2490 | { | ||
2491 | mw32(CMD_ADDR, addr); | ||
2492 | return mr32(CMD_DATA); | ||
2493 | } | ||
2494 | |||
2495 | static void mvs_cw32(void __iomem *regs, u32 addr, u32 val) | ||
2496 | { | ||
2497 | mw32(CMD_ADDR, addr); | ||
2498 | mw32(CMD_DATA, val); | ||
2499 | } | ||
2500 | |||
2501 | static u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port) | ||
2502 | { | ||
2503 | void __iomem *regs = mvi->regs; | ||
2504 | return (port < 4)?mr32(P0_SER_CTLSTAT + port * 4): | ||
2505 | mr32(P4_SER_CTLSTAT + (port - 4) * 4); | ||
2506 | } | ||
2507 | |||
2508 | static void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val) | ||
2509 | { | ||
2510 | void __iomem *regs = mvi->regs; | ||
2511 | if (port < 4) | ||
2512 | mw32(P0_SER_CTLSTAT + port * 4, val); | ||
2513 | else | ||
2514 | mw32(P4_SER_CTLSTAT + (port - 4) * 4, val); | ||
2515 | } | ||
2516 | |||
2517 | static u32 mvs_read_port(struct mvs_info *mvi, u32 off, u32 off2, u32 port) | ||
2518 | { | ||
2519 | void __iomem *regs = mvi->regs + off; | ||
2520 | void __iomem *regs2 = mvi->regs + off2; | ||
2521 | return (port < 4)?readl(regs + port * 8): | ||
2522 | readl(regs2 + (port - 4) * 8); | ||
2523 | } | ||
2524 | |||
2525 | static void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2, | ||
2526 | u32 port, u32 val) | ||
2527 | { | ||
2528 | void __iomem *regs = mvi->regs + off; | ||
2529 | void __iomem *regs2 = mvi->regs + off2; | ||
2530 | if (port < 4) | ||
2531 | writel(val, regs + port * 8); | ||
2532 | else | ||
2533 | writel(val, regs2 + (port - 4) * 8); | ||
2534 | } | ||
2535 | |||
2536 | static u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port) | ||
2537 | { | ||
2538 | return mvs_read_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port); | ||
2539 | } | ||
2540 | |||
2541 | static void mvs_write_port_cfg_data(struct mvs_info *mvi, u32 port, u32 val) | ||
2542 | { | ||
2543 | mvs_write_port(mvi, MVS_P0_CFG_DATA, MVS_P4_CFG_DATA, port, val); | ||
2544 | } | ||
2545 | |||
2546 | static void mvs_write_port_cfg_addr(struct mvs_info *mvi, u32 port, u32 addr) | ||
2547 | { | ||
2548 | mvs_write_port(mvi, MVS_P0_CFG_ADDR, MVS_P4_CFG_ADDR, port, addr); | ||
2549 | } | ||
2550 | |||
2551 | static u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port) | ||
2552 | { | ||
2553 | return mvs_read_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port); | ||
2554 | } | ||
2555 | |||
2556 | static void mvs_write_port_vsr_data(struct mvs_info *mvi, u32 port, u32 val) | ||
2557 | { | ||
2558 | mvs_write_port(mvi, MVS_P0_VSR_DATA, MVS_P4_VSR_DATA, port, val); | ||
2559 | } | ||
2560 | |||
2561 | static void mvs_write_port_vsr_addr(struct mvs_info *mvi, u32 port, u32 addr) | ||
2562 | { | ||
2563 | mvs_write_port(mvi, MVS_P0_VSR_ADDR, MVS_P4_VSR_ADDR, port, addr); | ||
2564 | } | ||
2565 | |||
2566 | static u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port) | ||
2567 | { | ||
2568 | return mvs_read_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port); | ||
2569 | } | ||
2570 | |||
2571 | static void mvs_write_port_irq_stat(struct mvs_info *mvi, u32 port, u32 val) | ||
2572 | { | ||
2573 | mvs_write_port(mvi, MVS_P0_INT_STAT, MVS_P4_INT_STAT, port, val); | ||
2574 | } | ||
2575 | |||
2576 | static u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port) | ||
2577 | { | ||
2578 | return mvs_read_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port); | ||
2579 | } | ||
2580 | |||
2581 | static void mvs_write_port_irq_mask(struct mvs_info *mvi, u32 port, u32 val) | ||
2582 | { | ||
2583 | mvs_write_port(mvi, MVS_P0_INT_MASK, MVS_P4_INT_MASK, port, val); | ||
2584 | } | ||
2585 | |||
2586 | static void __devinit mvs_phy_hacks(struct mvs_info *mvi) | ||
2587 | { | ||
2588 | void __iomem *regs = mvi->regs; | ||
2589 | u32 tmp; | ||
2590 | |||
2591 | /* workaround for SATA R-ERR, to ignore phy glitch */ | ||
2592 | tmp = mvs_cr32(regs, CMD_PHY_TIMER); | ||
2593 | tmp &= ~(1 << 9); | ||
2594 | tmp |= (1 << 10); | ||
2595 | mvs_cw32(regs, CMD_PHY_TIMER, tmp); | ||
2596 | |||
2597 | /* enable retry 127 times */ | ||
2598 | mvs_cw32(regs, CMD_SAS_CTL1, 0x7f7f); | ||
2599 | |||
2600 | /* extend open frame timeout to max */ | ||
2601 | tmp = mvs_cr32(regs, CMD_SAS_CTL0); | ||
2602 | tmp &= ~0xffff; | ||
2603 | tmp |= 0x3fff; | ||
2604 | mvs_cw32(regs, CMD_SAS_CTL0, tmp); | ||
2605 | |||
2606 | /* workaround for WDTIMEOUT , set to 550 ms */ | ||
2607 | mvs_cw32(regs, CMD_WD_TIMER, 0x86470); | ||
2608 | |||
2609 | /* not to halt for different port op during wideport link change */ | ||
2610 | mvs_cw32(regs, CMD_APP_ERR_CONFIG, 0xffefbf7d); | ||
2611 | |||
2612 | /* workaround for Seagate disk not-found OOB sequence, recv | ||
2613 | * COMINIT before sending out COMWAKE */ | ||
2614 | tmp = mvs_cr32(regs, CMD_PHY_MODE_21); | ||
2615 | tmp &= 0x0000ffff; | ||
2616 | tmp |= 0x00fa0000; | ||
2617 | mvs_cw32(regs, CMD_PHY_MODE_21, tmp); | ||
2618 | |||
2619 | tmp = mvs_cr32(regs, CMD_PHY_TIMER); | ||
2620 | tmp &= 0x1fffffff; | ||
2621 | tmp |= (2U << 29); /* 8 ms retry */ | ||
2622 | mvs_cw32(regs, CMD_PHY_TIMER, tmp); | ||
2623 | |||
2624 | /* TEST - for phy decoding error, adjust voltage levels */ | ||
2625 | mw32(P0_VSR_ADDR + 0, 0x8); | ||
2626 | mw32(P0_VSR_DATA + 0, 0x2F0); | ||
2627 | |||
2628 | mw32(P0_VSR_ADDR + 8, 0x8); | ||
2629 | mw32(P0_VSR_DATA + 8, 0x2F0); | ||
2630 | |||
2631 | mw32(P0_VSR_ADDR + 16, 0x8); | ||
2632 | mw32(P0_VSR_DATA + 16, 0x2F0); | ||
2633 | |||
2634 | mw32(P0_VSR_ADDR + 24, 0x8); | ||
2635 | mw32(P0_VSR_DATA + 24, 0x2F0); | ||
2636 | |||
2637 | } | ||
2638 | |||
2639 | static void mvs_enable_xmt(struct mvs_info *mvi, int PhyId) | ||
2640 | { | ||
2641 | void __iomem *regs = mvi->regs; | ||
2642 | u32 tmp; | ||
2643 | |||
2644 | tmp = mr32(PCS); | ||
2645 | if (mvi->chip->n_phy <= 4) | ||
2646 | tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT); | ||
2647 | else | ||
2648 | tmp |= 1 << (PhyId + PCS_EN_PORT_XMT_SHIFT2); | ||
2649 | mw32(PCS, tmp); | ||
2650 | } | ||
2651 | |||
2652 | static void mvs_detect_porttype(struct mvs_info *mvi, int i) | ||
2653 | { | ||
2654 | void __iomem *regs = mvi->regs; | ||
2655 | u32 reg; | ||
2656 | struct mvs_phy *phy = &mvi->phy[i]; | ||
2657 | |||
2658 | /* TODO check & save device type */ | ||
2659 | reg = mr32(GBL_PORT_TYPE); | ||
2660 | |||
2661 | if (reg & MODE_SAS_SATA & (1 << i)) | ||
2662 | phy->phy_type |= PORT_TYPE_SAS; | ||
2663 | else | ||
2664 | phy->phy_type |= PORT_TYPE_SATA; | ||
2665 | } | ||
2666 | |||
2667 | static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) | ||
2668 | { | ||
2669 | u32 *s = (u32 *) buf; | ||
2670 | |||
2671 | if (!s) | ||
2672 | return NULL; | ||
2673 | |||
2674 | mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3); | ||
2675 | s[3] = mvs_read_port_cfg_data(mvi, i); | ||
2676 | |||
2677 | mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2); | ||
2678 | s[2] = mvs_read_port_cfg_data(mvi, i); | ||
2679 | |||
2680 | mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1); | ||
2681 | s[1] = mvs_read_port_cfg_data(mvi, i); | ||
2682 | |||
2683 | mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0); | ||
2684 | s[0] = mvs_read_port_cfg_data(mvi, i); | ||
2685 | |||
2686 | return (void *)s; | ||
2687 | } | ||
2688 | |||
2689 | static u32 mvs_is_sig_fis_received(u32 irq_status) | ||
2690 | { | ||
2691 | return irq_status & PHYEV_SIG_FIS; | ||
2692 | } | 879 | } |
2693 | 880 | ||
2694 | static void mvs_update_wideport(struct mvs_info *mvi, int i) | 881 | static void mvs_update_wideport(struct mvs_info *mvi, int i) |
@@ -2738,6 +925,33 @@ static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i) | |||
2738 | return 0; | 925 | return 0; |
2739 | } | 926 | } |
2740 | 927 | ||
928 | static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) | ||
929 | { | ||
930 | u32 *s = (u32 *) buf; | ||
931 | |||
932 | if (!s) | ||
933 | return NULL; | ||
934 | |||
935 | mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3); | ||
936 | s[3] = mvs_read_port_cfg_data(mvi, i); | ||
937 | |||
938 | mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2); | ||
939 | s[2] = mvs_read_port_cfg_data(mvi, i); | ||
940 | |||
941 | mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1); | ||
942 | s[1] = mvs_read_port_cfg_data(mvi, i); | ||
943 | |||
944 | mvs_write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0); | ||
945 | s[0] = mvs_read_port_cfg_data(mvi, i); | ||
946 | |||
947 | return (void *)s; | ||
948 | } | ||
949 | |||
950 | static u32 mvs_is_sig_fis_received(u32 irq_status) | ||
951 | { | ||
952 | return irq_status & PHYEV_SIG_FIS; | ||
953 | } | ||
954 | |||
2741 | static void mvs_update_phyinfo(struct mvs_info *mvi, int i, | 955 | static void mvs_update_phyinfo(struct mvs_info *mvi, int i, |
2742 | int get_st) | 956 | int get_st) |
2743 | { | 957 | { |
@@ -2846,7 +1060,7 @@ out_done: | |||
2846 | mvs_write_port_irq_stat(mvi, i, phy->irq_status); | 1060 | mvs_write_port_irq_stat(mvi, i, phy->irq_status); |
2847 | } | 1061 | } |
2848 | 1062 | ||
2849 | static void mvs_port_formed(struct asd_sas_phy *sas_phy) | 1063 | void mvs_port_formed(struct asd_sas_phy *sas_phy) |
2850 | { | 1064 | { |
2851 | struct sas_ha_struct *sas_ha = sas_phy->ha; | 1065 | struct sas_ha_struct *sas_ha = sas_phy->ha; |
2852 | struct mvs_info *mvi = sas_ha->lldd_ha; | 1066 | struct mvs_info *mvi = sas_ha->lldd_ha; |
@@ -2866,12 +1080,561 @@ static void mvs_port_formed(struct asd_sas_phy *sas_phy) | |||
2866 | spin_unlock_irqrestore(&mvi->lock, flags); | 1080 | spin_unlock_irqrestore(&mvi->lock, flags); |
2867 | } | 1081 | } |
2868 | 1082 | ||
2869 | static int mvs_I_T_nexus_reset(struct domain_device *dev) | 1083 | int mvs_I_T_nexus_reset(struct domain_device *dev) |
2870 | { | 1084 | { |
2871 | return TMF_RESP_FUNC_FAILED; | 1085 | return TMF_RESP_FUNC_FAILED; |
2872 | } | 1086 | } |
2873 | 1087 | ||
2874 | static int __devinit mvs_hw_init(struct mvs_info *mvi) | 1088 | static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, |
1089 | u32 slot_idx, int err) | ||
1090 | { | ||
1091 | struct mvs_port *port = mvi->slot_info[slot_idx].port; | ||
1092 | struct task_status_struct *tstat = &task->task_status; | ||
1093 | struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; | ||
1094 | int stat = SAM_GOOD; | ||
1095 | |||
1096 | resp->frame_len = sizeof(struct dev_to_host_fis); | ||
1097 | memcpy(&resp->ending_fis[0], | ||
1098 | SATA_RECEIVED_D2H_FIS(port->taskfileset), | ||
1099 | sizeof(struct dev_to_host_fis)); | ||
1100 | tstat->buf_valid_size = sizeof(*resp); | ||
1101 | if (unlikely(err)) | ||
1102 | stat = SAS_PROTO_RESPONSE; | ||
1103 | return stat; | ||
1104 | } | ||
1105 | |||
1106 | static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, | ||
1107 | u32 slot_idx) | ||
1108 | { | ||
1109 | struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; | ||
1110 | u32 err_dw0 = le32_to_cpu(*(u32 *) (slot->response)); | ||
1111 | u32 err_dw1 = le32_to_cpu(*(u32 *) (slot->response + 4)); | ||
1112 | int stat = SAM_CHECK_COND; | ||
1113 | |||
1114 | if (err_dw1 & SLOT_BSY_ERR) { | ||
1115 | stat = SAS_QUEUE_FULL; | ||
1116 | mvs_slot_reset(mvi, task, slot_idx); | ||
1117 | } | ||
1118 | switch (task->task_proto) { | ||
1119 | case SAS_PROTOCOL_SSP: | ||
1120 | break; | ||
1121 | case SAS_PROTOCOL_SMP: | ||
1122 | break; | ||
1123 | case SAS_PROTOCOL_SATA: | ||
1124 | case SAS_PROTOCOL_STP: | ||
1125 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: | ||
1126 | if (err_dw0 & TFILE_ERR) | ||
1127 | stat = mvs_sata_done(mvi, task, slot_idx, 1); | ||
1128 | break; | ||
1129 | default: | ||
1130 | break; | ||
1131 | } | ||
1132 | |||
1133 | mvs_hexdump(16, (u8 *) slot->response, 0); | ||
1134 | return stat; | ||
1135 | } | ||
1136 | |||
1137 | static int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) | ||
1138 | { | ||
1139 | u32 slot_idx = rx_desc & RXQ_SLOT_MASK; | ||
1140 | struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; | ||
1141 | struct sas_task *task = slot->task; | ||
1142 | struct task_status_struct *tstat; | ||
1143 | struct mvs_port *port; | ||
1144 | bool aborted; | ||
1145 | void *to; | ||
1146 | |||
1147 | if (unlikely(!task || !task->lldd_task)) | ||
1148 | return -1; | ||
1149 | |||
1150 | mvs_hba_cq_dump(mvi); | ||
1151 | |||
1152 | spin_lock(&task->task_state_lock); | ||
1153 | aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; | ||
1154 | if (!aborted) { | ||
1155 | task->task_state_flags &= | ||
1156 | ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); | ||
1157 | task->task_state_flags |= SAS_TASK_STATE_DONE; | ||
1158 | } | ||
1159 | spin_unlock(&task->task_state_lock); | ||
1160 | |||
1161 | if (aborted) { | ||
1162 | mvs_slot_task_free(mvi, task, slot, slot_idx); | ||
1163 | mvs_slot_free(mvi, rx_desc); | ||
1164 | return -1; | ||
1165 | } | ||
1166 | |||
1167 | port = slot->port; | ||
1168 | tstat = &task->task_status; | ||
1169 | memset(tstat, 0, sizeof(*tstat)); | ||
1170 | tstat->resp = SAS_TASK_COMPLETE; | ||
1171 | |||
1172 | if (unlikely(!port->port_attached || flags)) { | ||
1173 | mvs_slot_err(mvi, task, slot_idx); | ||
1174 | if (!sas_protocol_ata(task->task_proto)) | ||
1175 | tstat->stat = SAS_PHY_DOWN; | ||
1176 | goto out; | ||
1177 | } | ||
1178 | |||
1179 | /* error info record present */ | ||
1180 | if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) { | ||
1181 | tstat->stat = mvs_slot_err(mvi, task, slot_idx); | ||
1182 | goto out; | ||
1183 | } | ||
1184 | |||
1185 | switch (task->task_proto) { | ||
1186 | case SAS_PROTOCOL_SSP: | ||
1187 | /* hw says status == 0, datapres == 0 */ | ||
1188 | if (rx_desc & RXQ_GOOD) { | ||
1189 | tstat->stat = SAM_GOOD; | ||
1190 | tstat->resp = SAS_TASK_COMPLETE; | ||
1191 | } | ||
1192 | /* response frame present */ | ||
1193 | else if (rx_desc & RXQ_RSP) { | ||
1194 | struct ssp_response_iu *iu = | ||
1195 | slot->response + sizeof(struct mvs_err_info); | ||
1196 | sas_ssp_task_response(&mvi->pdev->dev, task, iu); | ||
1197 | } | ||
1198 | |||
1199 | /* should never happen? */ | ||
1200 | else | ||
1201 | tstat->stat = SAM_CHECK_COND; | ||
1202 | break; | ||
1203 | |||
1204 | case SAS_PROTOCOL_SMP: { | ||
1205 | struct scatterlist *sg_resp = &task->smp_task.smp_resp; | ||
1206 | tstat->stat = SAM_GOOD; | ||
1207 | to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); | ||
1208 | memcpy(to + sg_resp->offset, | ||
1209 | slot->response + sizeof(struct mvs_err_info), | ||
1210 | sg_dma_len(sg_resp)); | ||
1211 | kunmap_atomic(to, KM_IRQ0); | ||
1212 | break; | ||
1213 | } | ||
1214 | |||
1215 | case SAS_PROTOCOL_SATA: | ||
1216 | case SAS_PROTOCOL_STP: | ||
1217 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { | ||
1218 | tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0); | ||
1219 | break; | ||
1220 | } | ||
1221 | |||
1222 | default: | ||
1223 | tstat->stat = SAM_CHECK_COND; | ||
1224 | break; | ||
1225 | } | ||
1226 | |||
1227 | out: | ||
1228 | mvs_slot_task_free(mvi, task, slot, slot_idx); | ||
1229 | if (unlikely(tstat->stat != SAS_QUEUE_FULL)) | ||
1230 | mvs_slot_free(mvi, rx_desc); | ||
1231 | |||
1232 | spin_unlock(&mvi->lock); | ||
1233 | task->task_done(task); | ||
1234 | spin_lock(&mvi->lock); | ||
1235 | return tstat->stat; | ||
1236 | } | ||
1237 | |||
1238 | static void mvs_release_task(struct mvs_info *mvi, int phy_no) | ||
1239 | { | ||
1240 | struct list_head *pos, *n; | ||
1241 | struct mvs_slot_info *slot; | ||
1242 | struct mvs_phy *phy = &mvi->phy[phy_no]; | ||
1243 | struct mvs_port *port = phy->port; | ||
1244 | u32 rx_desc; | ||
1245 | |||
1246 | if (!port) | ||
1247 | return; | ||
1248 | |||
1249 | list_for_each_safe(pos, n, &port->list) { | ||
1250 | slot = container_of(pos, struct mvs_slot_info, list); | ||
1251 | rx_desc = (u32) (slot - mvi->slot_info); | ||
1252 | mvs_slot_complete(mvi, rx_desc, 1); | ||
1253 | } | ||
1254 | } | ||
1255 | |||
1256 | static void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) | ||
1257 | { | ||
1258 | struct pci_dev *pdev = mvi->pdev; | ||
1259 | struct sas_ha_struct *sas_ha = &mvi->sas; | ||
1260 | struct mvs_phy *phy = &mvi->phy[phy_no]; | ||
1261 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
1262 | |||
1263 | phy->irq_status = mvs_read_port_irq_stat(mvi, phy_no); | ||
1264 | /* | ||
1265 | * events is port event now , | ||
1266 | * we need check the interrupt status which belongs to per port. | ||
1267 | */ | ||
1268 | dev_printk(KERN_DEBUG, &pdev->dev, | ||
1269 | "Port %d Event = %X\n", | ||
1270 | phy_no, phy->irq_status); | ||
1271 | |||
1272 | if (phy->irq_status & (PHYEV_POOF | PHYEV_DEC_ERR)) { | ||
1273 | mvs_release_task(mvi, phy_no); | ||
1274 | if (!mvs_is_phy_ready(mvi, phy_no)) { | ||
1275 | sas_phy_disconnected(sas_phy); | ||
1276 | sas_ha->notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL); | ||
1277 | dev_printk(KERN_INFO, &pdev->dev, | ||
1278 | "Port %d Unplug Notice\n", phy_no); | ||
1279 | |||
1280 | } else | ||
1281 | mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, NULL); | ||
1282 | } | ||
1283 | if (!(phy->irq_status & PHYEV_DEC_ERR)) { | ||
1284 | if (phy->irq_status & PHYEV_COMWAKE) { | ||
1285 | u32 tmp = mvs_read_port_irq_mask(mvi, phy_no); | ||
1286 | mvs_write_port_irq_mask(mvi, phy_no, | ||
1287 | tmp | PHYEV_SIG_FIS); | ||
1288 | } | ||
1289 | if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) { | ||
1290 | phy->phy_status = mvs_is_phy_ready(mvi, phy_no); | ||
1291 | if (phy->phy_status) { | ||
1292 | mvs_detect_porttype(mvi, phy_no); | ||
1293 | |||
1294 | if (phy->phy_type & PORT_TYPE_SATA) { | ||
1295 | u32 tmp = mvs_read_port_irq_mask(mvi, | ||
1296 | phy_no); | ||
1297 | tmp &= ~PHYEV_SIG_FIS; | ||
1298 | mvs_write_port_irq_mask(mvi, | ||
1299 | phy_no, tmp); | ||
1300 | } | ||
1301 | |||
1302 | mvs_update_phyinfo(mvi, phy_no, 0); | ||
1303 | sas_ha->notify_phy_event(sas_phy, | ||
1304 | PHYE_OOB_DONE); | ||
1305 | mvs_bytes_dmaed(mvi, phy_no); | ||
1306 | } else { | ||
1307 | dev_printk(KERN_DEBUG, &pdev->dev, | ||
1308 | "plugin interrupt but phy is gone\n"); | ||
1309 | mvs_phy_control(sas_phy, PHY_FUNC_LINK_RESET, | ||
1310 | NULL); | ||
1311 | } | ||
1312 | } else if (phy->irq_status & PHYEV_BROAD_CH) { | ||
1313 | mvs_release_task(mvi, phy_no); | ||
1314 | sas_ha->notify_port_event(sas_phy, | ||
1315 | PORTE_BROADCAST_RCVD); | ||
1316 | } | ||
1317 | } | ||
1318 | mvs_write_port_irq_stat(mvi, phy_no, phy->irq_status); | ||
1319 | } | ||
1320 | |||
1321 | static int mvs_int_rx(struct mvs_info *mvi, bool self_clear) | ||
1322 | { | ||
1323 | void __iomem *regs = mvi->regs; | ||
1324 | u32 rx_prod_idx, rx_desc; | ||
1325 | bool attn = false; | ||
1326 | struct pci_dev *pdev = mvi->pdev; | ||
1327 | |||
1328 | /* the first dword in the RX ring is special: it contains | ||
1329 | * a mirror of the hardware's RX producer index, so that | ||
1330 | * we don't have to stall the CPU reading that register. | ||
1331 | * The actual RX ring is offset by one dword, due to this. | ||
1332 | */ | ||
1333 | rx_prod_idx = mvi->rx_cons; | ||
1334 | mvi->rx_cons = le32_to_cpu(mvi->rx[0]); | ||
1335 | if (mvi->rx_cons == 0xfff) /* h/w hasn't touched RX ring yet */ | ||
1336 | return 0; | ||
1337 | |||
1338 | /* The CMPL_Q may come late, read from register and try again | ||
1339 | * note: if coalescing is enabled, | ||
1340 | * it will need to read from register every time for sure | ||
1341 | */ | ||
1342 | if (mvi->rx_cons == rx_prod_idx) | ||
1343 | mvi->rx_cons = mr32(RX_CONS_IDX) & RX_RING_SZ_MASK; | ||
1344 | |||
1345 | if (mvi->rx_cons == rx_prod_idx) | ||
1346 | return 0; | ||
1347 | |||
1348 | while (mvi->rx_cons != rx_prod_idx) { | ||
1349 | |||
1350 | /* increment our internal RX consumer pointer */ | ||
1351 | rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1); | ||
1352 | |||
1353 | rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]); | ||
1354 | |||
1355 | if (likely(rx_desc & RXQ_DONE)) | ||
1356 | mvs_slot_complete(mvi, rx_desc, 0); | ||
1357 | if (rx_desc & RXQ_ATTN) { | ||
1358 | attn = true; | ||
1359 | dev_printk(KERN_DEBUG, &pdev->dev, "ATTN %X\n", | ||
1360 | rx_desc); | ||
1361 | } else if (rx_desc & RXQ_ERR) { | ||
1362 | if (!(rx_desc & RXQ_DONE)) | ||
1363 | mvs_slot_complete(mvi, rx_desc, 0); | ||
1364 | dev_printk(KERN_DEBUG, &pdev->dev, "RXQ_ERR %X\n", | ||
1365 | rx_desc); | ||
1366 | } else if (rx_desc & RXQ_SLOT_RESET) { | ||
1367 | dev_printk(KERN_DEBUG, &pdev->dev, "Slot reset[%X]\n", | ||
1368 | rx_desc); | ||
1369 | mvs_slot_free(mvi, rx_desc); | ||
1370 | } | ||
1371 | } | ||
1372 | |||
1373 | if (attn && self_clear) | ||
1374 | mvs_int_full(mvi); | ||
1375 | |||
1376 | return 0; | ||
1377 | } | ||
1378 | |||
1379 | #ifndef MVS_DISABLE_NVRAM | ||
1380 | static int mvs_eep_read(void __iomem *regs, u32 addr, u32 *data) | ||
1381 | { | ||
1382 | int timeout = 1000; | ||
1383 | |||
1384 | if (addr & ~SPI_ADDR_MASK) | ||
1385 | return -EINVAL; | ||
1386 | |||
1387 | writel(addr, regs + SPI_CMD); | ||
1388 | writel(TWSI_RD, regs + SPI_CTL); | ||
1389 | |||
1390 | while (timeout-- > 0) { | ||
1391 | if (readl(regs + SPI_CTL) & TWSI_RDY) { | ||
1392 | *data = readl(regs + SPI_DATA); | ||
1393 | return 0; | ||
1394 | } | ||
1395 | |||
1396 | udelay(10); | ||
1397 | } | ||
1398 | |||
1399 | return -EBUSY; | ||
1400 | } | ||
1401 | |||
1402 | static int mvs_eep_read_buf(void __iomem *regs, u32 addr, | ||
1403 | void *buf, u32 buflen) | ||
1404 | { | ||
1405 | u32 addr_end, tmp_addr, i, j; | ||
1406 | u32 tmp = 0; | ||
1407 | int rc; | ||
1408 | u8 *tmp8, *buf8 = buf; | ||
1409 | |||
1410 | addr_end = addr + buflen; | ||
1411 | tmp_addr = ALIGN(addr, 4); | ||
1412 | if (addr > 0xff) | ||
1413 | return -EINVAL; | ||
1414 | |||
1415 | j = addr & 0x3; | ||
1416 | if (j) { | ||
1417 | rc = mvs_eep_read(regs, tmp_addr, &tmp); | ||
1418 | if (rc) | ||
1419 | return rc; | ||
1420 | |||
1421 | tmp8 = (u8 *)&tmp; | ||
1422 | for (i = j; i < 4; i++) | ||
1423 | *buf8++ = tmp8[i]; | ||
1424 | |||
1425 | tmp_addr += 4; | ||
1426 | } | ||
1427 | |||
1428 | for (j = ALIGN(addr_end, 4); tmp_addr < j; tmp_addr += 4) { | ||
1429 | rc = mvs_eep_read(regs, tmp_addr, &tmp); | ||
1430 | if (rc) | ||
1431 | return rc; | ||
1432 | |||
1433 | memcpy(buf8, &tmp, 4); | ||
1434 | buf8 += 4; | ||
1435 | } | ||
1436 | |||
1437 | if (tmp_addr < addr_end) { | ||
1438 | rc = mvs_eep_read(regs, tmp_addr, &tmp); | ||
1439 | if (rc) | ||
1440 | return rc; | ||
1441 | |||
1442 | tmp8 = (u8 *)&tmp; | ||
1443 | j = addr_end - tmp_addr; | ||
1444 | for (i = 0; i < j; i++) | ||
1445 | *buf8++ = tmp8[i]; | ||
1446 | |||
1447 | tmp_addr += 4; | ||
1448 | } | ||
1449 | |||
1450 | return 0; | ||
1451 | } | ||
1452 | #endif | ||
1453 | |||
1454 | int mvs_nvram_read(struct mvs_info *mvi, u32 addr, void *buf, u32 buflen) | ||
1455 | { | ||
1456 | #ifndef MVS_DISABLE_NVRAM | ||
1457 | void __iomem *regs = mvi->regs; | ||
1458 | int rc, i; | ||
1459 | u32 sum; | ||
1460 | u8 hdr[2], *tmp; | ||
1461 | const char *msg; | ||
1462 | |||
1463 | rc = mvs_eep_read_buf(regs, addr, &hdr, 2); | ||
1464 | if (rc) { | ||
1465 | msg = "nvram hdr read failed"; | ||
1466 | goto err_out; | ||
1467 | } | ||
1468 | rc = mvs_eep_read_buf(regs, addr + 2, buf, buflen); | ||
1469 | if (rc) { | ||
1470 | msg = "nvram read failed"; | ||
1471 | goto err_out; | ||
1472 | } | ||
1473 | |||
1474 | if (hdr[0] != 0x5A) { | ||
1475 | /* entry id */ | ||
1476 | msg = "invalid nvram entry id"; | ||
1477 | rc = -ENOENT; | ||
1478 | goto err_out; | ||
1479 | } | ||
1480 | |||
1481 | tmp = buf; | ||
1482 | sum = ((u32)hdr[0]) + ((u32)hdr[1]); | ||
1483 | for (i = 0; i < buflen; i++) | ||
1484 | sum += ((u32)tmp[i]); | ||
1485 | |||
1486 | if (sum) { | ||
1487 | msg = "nvram checksum failure"; | ||
1488 | rc = -EILSEQ; | ||
1489 | goto err_out; | ||
1490 | } | ||
1491 | |||
1492 | return 0; | ||
1493 | |||
1494 | err_out: | ||
1495 | dev_printk(KERN_ERR, &mvi->pdev->dev, "%s", msg); | ||
1496 | return rc; | ||
1497 | #else | ||
1498 | /* FIXME , For SAS target mode */ | ||
1499 | memcpy(buf, "\x50\x05\x04\x30\x11\xab\x00\x00", 8); | ||
1500 | return 0; | ||
1501 | #endif | ||
1502 | } | ||
1503 | |||
1504 | static void mvs_int_sata(struct mvs_info *mvi) | ||
1505 | { | ||
1506 | u32 tmp; | ||
1507 | void __iomem *regs = mvi->regs; | ||
1508 | tmp = mr32(INT_STAT_SRS); | ||
1509 | mw32(INT_STAT_SRS, tmp & 0xFFFF); | ||
1510 | } | ||
1511 | |||
1512 | static void mvs_slot_reset(struct mvs_info *mvi, struct sas_task *task, | ||
1513 | u32 slot_idx) | ||
1514 | { | ||
1515 | void __iomem *regs = mvi->regs; | ||
1516 | struct domain_device *dev = task->dev; | ||
1517 | struct asd_sas_port *sas_port = dev->port; | ||
1518 | struct mvs_port *port = mvi->slot_info[slot_idx].port; | ||
1519 | u32 reg_set, phy_mask; | ||
1520 | |||
1521 | if (!sas_protocol_ata(task->task_proto)) { | ||
1522 | reg_set = 0; | ||
1523 | phy_mask = (port->wide_port_phymap) ? port->wide_port_phymap : | ||
1524 | sas_port->phy_mask; | ||
1525 | } else { | ||
1526 | reg_set = port->taskfileset; | ||
1527 | phy_mask = sas_port->phy_mask; | ||
1528 | } | ||
1529 | mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | slot_idx | | ||
1530 | (TXQ_CMD_SLOT_RESET << TXQ_CMD_SHIFT) | | ||
1531 | (phy_mask << TXQ_PHY_SHIFT) | | ||
1532 | (reg_set << TXQ_SRS_SHIFT)); | ||
1533 | |||
1534 | mw32(TX_PROD_IDX, mvi->tx_prod); | ||
1535 | mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); | ||
1536 | } | ||
1537 | |||
1538 | void mvs_int_full(struct mvs_info *mvi) | ||
1539 | { | ||
1540 | void __iomem *regs = mvi->regs; | ||
1541 | u32 tmp, stat; | ||
1542 | int i; | ||
1543 | |||
1544 | stat = mr32(INT_STAT); | ||
1545 | |||
1546 | mvs_int_rx(mvi, false); | ||
1547 | |||
1548 | for (i = 0; i < MVS_MAX_PORTS; i++) { | ||
1549 | tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED); | ||
1550 | if (tmp) | ||
1551 | mvs_int_port(mvi, i, tmp); | ||
1552 | } | ||
1553 | |||
1554 | if (stat & CINT_SRS) | ||
1555 | mvs_int_sata(mvi); | ||
1556 | |||
1557 | mw32(INT_STAT, stat); | ||
1558 | } | ||
1559 | |||
1560 | #ifndef MVS_DISABLE_MSI | ||
1561 | static irqreturn_t mvs_msi_interrupt(int irq, void *opaque) | ||
1562 | { | ||
1563 | struct mvs_info *mvi = opaque; | ||
1564 | |||
1565 | #ifndef MVS_USE_TASKLET | ||
1566 | spin_lock(&mvi->lock); | ||
1567 | |||
1568 | mvs_int_rx(mvi, true); | ||
1569 | |||
1570 | spin_unlock(&mvi->lock); | ||
1571 | #else | ||
1572 | tasklet_schedule(&mvi->tasklet); | ||
1573 | #endif | ||
1574 | return IRQ_HANDLED; | ||
1575 | } | ||
1576 | #endif | ||
1577 | |||
1578 | int mvs_task_abort(struct sas_task *task) | ||
1579 | { | ||
1580 | int rc; | ||
1581 | unsigned long flags; | ||
1582 | struct mvs_info *mvi = task->dev->port->ha->lldd_ha; | ||
1583 | struct pci_dev *pdev = mvi->pdev; | ||
1584 | int tag; | ||
1585 | |||
1586 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
1587 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
1588 | rc = TMF_RESP_FUNC_COMPLETE; | ||
1589 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
1590 | goto out_done; | ||
1591 | } | ||
1592 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
1593 | |||
1594 | switch (task->task_proto) { | ||
1595 | case SAS_PROTOCOL_SMP: | ||
1596 | dev_printk(KERN_DEBUG, &pdev->dev, "SMP Abort! \n"); | ||
1597 | break; | ||
1598 | case SAS_PROTOCOL_SSP: | ||
1599 | dev_printk(KERN_DEBUG, &pdev->dev, "SSP Abort! \n"); | ||
1600 | break; | ||
1601 | case SAS_PROTOCOL_SATA: | ||
1602 | case SAS_PROTOCOL_STP: | ||
1603 | case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:{ | ||
1604 | dev_printk(KERN_DEBUG, &pdev->dev, "STP Abort! \n"); | ||
1605 | #if _MV_DUMP | ||
1606 | dev_printk(KERN_DEBUG, &pdev->dev, "Dump D2H FIS: \n"); | ||
1607 | mvs_hexdump(sizeof(struct host_to_dev_fis), | ||
1608 | (void *)&task->ata_task.fis, 0); | ||
1609 | dev_printk(KERN_DEBUG, &pdev->dev, "Dump ATAPI Cmd : \n"); | ||
1610 | mvs_hexdump(16, task->ata_task.atapi_packet, 0); | ||
1611 | #endif | ||
1612 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
1613 | if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) { | ||
1614 | /* TODO */ | ||
1615 | ; | ||
1616 | } | ||
1617 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
1618 | break; | ||
1619 | } | ||
1620 | default: | ||
1621 | break; | ||
1622 | } | ||
1623 | |||
1624 | if (mvs_find_tag(mvi, task, &tag)) { | ||
1625 | spin_lock_irqsave(&mvi->lock, flags); | ||
1626 | mvs_slot_task_free(mvi, task, &mvi->slot_info[tag], tag); | ||
1627 | spin_unlock_irqrestore(&mvi->lock, flags); | ||
1628 | } | ||
1629 | if (!mvs_task_exec(task, 1, GFP_ATOMIC)) | ||
1630 | rc = TMF_RESP_FUNC_COMPLETE; | ||
1631 | else | ||
1632 | rc = TMF_RESP_FUNC_FAILED; | ||
1633 | out_done: | ||
1634 | return rc; | ||
1635 | } | ||
1636 | |||
1637 | int __devinit mvs_hw_init(struct mvs_info *mvi) | ||
2875 | { | 1638 | { |
2876 | void __iomem *regs = mvi->regs; | 1639 | void __iomem *regs = mvi->regs; |
2877 | int i; | 1640 | int i; |
@@ -3041,7 +1804,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi) | |||
3041 | return 0; | 1804 | return 0; |
3042 | } | 1805 | } |
3043 | 1806 | ||
3044 | static void __devinit mvs_print_info(struct mvs_info *mvi) | 1807 | void __devinit mvs_print_info(struct mvs_info *mvi) |
3045 | { | 1808 | { |
3046 | struct pci_dev *pdev = mvi->pdev; | 1809 | struct pci_dev *pdev = mvi->pdev; |
3047 | static int printed_version; | 1810 | static int printed_version; |
@@ -3053,170 +1816,3 @@ static void __devinit mvs_print_info(struct mvs_info *mvi) | |||
3053 | mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr)); | 1816 | mvi->chip->n_phy, SAS_ADDR(mvi->sas_addr)); |
3054 | } | 1817 | } |
3055 | 1818 | ||
3056 | static int __devinit mvs_pci_init(struct pci_dev *pdev, | ||
3057 | const struct pci_device_id *ent) | ||
3058 | { | ||
3059 | int rc; | ||
3060 | struct mvs_info *mvi; | ||
3061 | irq_handler_t irq_handler = mvs_interrupt; | ||
3062 | |||
3063 | rc = pci_enable_device(pdev); | ||
3064 | if (rc) | ||
3065 | return rc; | ||
3066 | |||
3067 | pci_set_master(pdev); | ||
3068 | |||
3069 | rc = pci_request_regions(pdev, DRV_NAME); | ||
3070 | if (rc) | ||
3071 | goto err_out_disable; | ||
3072 | |||
3073 | rc = pci_go_64(pdev); | ||
3074 | if (rc) | ||
3075 | goto err_out_regions; | ||
3076 | |||
3077 | mvi = mvs_alloc(pdev, ent); | ||
3078 | if (!mvi) { | ||
3079 | rc = -ENOMEM; | ||
3080 | goto err_out_regions; | ||
3081 | } | ||
3082 | |||
3083 | rc = mvs_hw_init(mvi); | ||
3084 | if (rc) | ||
3085 | goto err_out_mvi; | ||
3086 | |||
3087 | #ifndef MVS_DISABLE_MSI | ||
3088 | if (!pci_enable_msi(pdev)) { | ||
3089 | u32 tmp; | ||
3090 | void __iomem *regs = mvi->regs; | ||
3091 | mvi->flags |= MVF_MSI; | ||
3092 | irq_handler = mvs_msi_interrupt; | ||
3093 | tmp = mr32(PCS); | ||
3094 | mw32(PCS, tmp | PCS_SELF_CLEAR); | ||
3095 | } | ||
3096 | #endif | ||
3097 | |||
3098 | rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, mvi); | ||
3099 | if (rc) | ||
3100 | goto err_out_msi; | ||
3101 | |||
3102 | rc = scsi_add_host(mvi->shost, &pdev->dev); | ||
3103 | if (rc) | ||
3104 | goto err_out_irq; | ||
3105 | |||
3106 | rc = sas_register_ha(&mvi->sas); | ||
3107 | if (rc) | ||
3108 | goto err_out_shost; | ||
3109 | |||
3110 | pci_set_drvdata(pdev, mvi); | ||
3111 | |||
3112 | mvs_print_info(mvi); | ||
3113 | |||
3114 | mvs_hba_interrupt_enable(mvi); | ||
3115 | |||
3116 | scsi_scan_host(mvi->shost); | ||
3117 | |||
3118 | return 0; | ||
3119 | |||
3120 | err_out_shost: | ||
3121 | scsi_remove_host(mvi->shost); | ||
3122 | err_out_irq: | ||
3123 | free_irq(pdev->irq, mvi); | ||
3124 | err_out_msi: | ||
3125 | if (mvi->flags |= MVF_MSI) | ||
3126 | pci_disable_msi(pdev); | ||
3127 | err_out_mvi: | ||
3128 | mvs_free(mvi); | ||
3129 | err_out_regions: | ||
3130 | pci_release_regions(pdev); | ||
3131 | err_out_disable: | ||
3132 | pci_disable_device(pdev); | ||
3133 | return rc; | ||
3134 | } | ||
3135 | |||
3136 | static void __devexit mvs_pci_remove(struct pci_dev *pdev) | ||
3137 | { | ||
3138 | struct mvs_info *mvi = pci_get_drvdata(pdev); | ||
3139 | |||
3140 | pci_set_drvdata(pdev, NULL); | ||
3141 | |||
3142 | if (mvi) { | ||
3143 | sas_unregister_ha(&mvi->sas); | ||
3144 | mvs_hba_interrupt_disable(mvi); | ||
3145 | sas_remove_host(mvi->shost); | ||
3146 | scsi_remove_host(mvi->shost); | ||
3147 | |||
3148 | free_irq(pdev->irq, mvi); | ||
3149 | if (mvi->flags & MVF_MSI) | ||
3150 | pci_disable_msi(pdev); | ||
3151 | mvs_free(mvi); | ||
3152 | pci_release_regions(pdev); | ||
3153 | } | ||
3154 | pci_disable_device(pdev); | ||
3155 | } | ||
3156 | |||
3157 | static struct sas_domain_function_template mvs_transport_ops = { | ||
3158 | .lldd_execute_task = mvs_task_exec, | ||
3159 | .lldd_control_phy = mvs_phy_control, | ||
3160 | .lldd_abort_task = mvs_task_abort, | ||
3161 | .lldd_port_formed = mvs_port_formed, | ||
3162 | .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, | ||
3163 | }; | ||
3164 | |||
3165 | static struct pci_device_id __devinitdata mvs_pci_table[] = { | ||
3166 | { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 }, | ||
3167 | { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 }, | ||
3168 | { | ||
3169 | .vendor = PCI_VENDOR_ID_MARVELL, | ||
3170 | .device = 0x6440, | ||
3171 | .subvendor = PCI_ANY_ID, | ||
3172 | .subdevice = 0x6480, | ||
3173 | .class = 0, | ||
3174 | .class_mask = 0, | ||
3175 | .driver_data = chip_6480, | ||
3176 | }, | ||
3177 | { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 }, | ||
3178 | { PCI_VDEVICE(MARVELL, 0x6480), chip_6480 }, | ||
3179 | |||
3180 | { } /* terminate list */ | ||
3181 | }; | ||
3182 | |||
3183 | static struct pci_driver mvs_pci_driver = { | ||
3184 | .name = DRV_NAME, | ||
3185 | .id_table = mvs_pci_table, | ||
3186 | .probe = mvs_pci_init, | ||
3187 | .remove = __devexit_p(mvs_pci_remove), | ||
3188 | }; | ||
3189 | |||
3190 | static int __init mvs_init(void) | ||
3191 | { | ||
3192 | int rc; | ||
3193 | |||
3194 | mvs_stt = sas_domain_attach_transport(&mvs_transport_ops); | ||
3195 | if (!mvs_stt) | ||
3196 | return -ENOMEM; | ||
3197 | |||
3198 | rc = pci_register_driver(&mvs_pci_driver); | ||
3199 | if (rc) | ||
3200 | goto err_out; | ||
3201 | |||
3202 | return 0; | ||
3203 | |||
3204 | err_out: | ||
3205 | sas_release_transport(mvs_stt); | ||
3206 | return rc; | ||
3207 | } | ||
3208 | |||
3209 | static void __exit mvs_exit(void) | ||
3210 | { | ||
3211 | pci_unregister_driver(&mvs_pci_driver); | ||
3212 | sas_release_transport(mvs_stt); | ||
3213 | } | ||
3214 | |||
3215 | module_init(mvs_init); | ||
3216 | module_exit(mvs_exit); | ||
3217 | |||
3218 | MODULE_AUTHOR("Jeff Garzik <jgarzik@pobox.com>"); | ||
3219 | MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver"); | ||
3220 | MODULE_VERSION(DRV_VERSION); | ||
3221 | MODULE_LICENSE("GPL"); | ||
3222 | MODULE_DEVICE_TABLE(pci, mvs_pci_table); | ||
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h new file mode 100644 index 000000000000..7a954a95a217 --- /dev/null +++ b/drivers/scsi/mvsas/mv_sas.h | |||
@@ -0,0 +1,205 @@ | |||
1 | /* | ||
2 | mv_sas.h - Marvell 88SE6440 SAS/SATA support | ||
3 | |||
4 | Copyright 2007 Red Hat, Inc. | ||
5 | Copyright 2008 Marvell. <kewei@marvell.com> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or | ||
8 | modify it under the terms of the GNU General Public License as | ||
9 | published by the Free Software Foundation; either version 2, | ||
10 | or (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty | ||
14 | of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
15 | See the GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public | ||
18 | License along with this program; see the file COPYING. If not, | ||
19 | write to the Free Software Foundation, 675 Mass Ave, Cambridge, | ||
20 | MA 02139, USA. | ||
21 | |||
22 | */ | ||
23 | |||
24 | #ifndef _MV_SAS_H_ | ||
25 | #define _MV_SAS_H_ | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/types.h> | ||
32 | #include <linux/ctype.h> | ||
33 | #include <linux/dma-mapping.h> | ||
34 | #include <linux/pci.h> | ||
35 | #include <linux/platform_device.h> | ||
36 | #include <linux/interrupt.h> | ||
37 | #include <linux/irq.h> | ||
38 | #include <linux/vmalloc.h> | ||
39 | #include <scsi/libsas.h> | ||
40 | #include <scsi/scsi_tcq.h> | ||
41 | #include <scsi/sas_ata.h> | ||
42 | #include <linux/version.h> | ||
43 | #include "mv_defs.h" | ||
44 | |||
45 | #define DRV_NAME "mvsas" | ||
46 | #define DRV_VERSION "0.5.2" | ||
47 | #define _MV_DUMP 0 | ||
48 | #define MVS_DISABLE_NVRAM | ||
49 | #define MVS_DISABLE_MSI | ||
50 | |||
51 | #define MVS_ID_NOT_MAPPED 0x7f | ||
52 | #define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width) | ||
53 | |||
54 | #define for_each_phy(__lseq_mask, __mc, __lseq, __rest) \ | ||
55 | for ((__mc) = (__lseq_mask), (__lseq) = 0; \ | ||
56 | (__mc) != 0 && __rest; \ | ||
57 | (++__lseq), (__mc) >>= 1) | ||
58 | |||
59 | struct mvs_chip_info { | ||
60 | u32 n_phy; | ||
61 | u32 srs_sz; | ||
62 | u32 slot_width; | ||
63 | }; | ||
64 | |||
65 | struct mvs_err_info { | ||
66 | __le32 flags; | ||
67 | __le32 flags2; | ||
68 | }; | ||
69 | |||
70 | struct mvs_cmd_hdr { | ||
71 | __le32 flags; /* PRD tbl len; SAS, SATA ctl */ | ||
72 | __le32 lens; /* cmd, max resp frame len */ | ||
73 | __le32 tags; /* targ port xfer tag; tag */ | ||
74 | __le32 data_len; /* data xfer len */ | ||
75 | __le64 cmd_tbl; /* command table address */ | ||
76 | __le64 open_frame; /* open addr frame address */ | ||
77 | __le64 status_buf; /* status buffer address */ | ||
78 | __le64 prd_tbl; /* PRD tbl address */ | ||
79 | __le32 reserved[4]; | ||
80 | }; | ||
81 | |||
82 | struct mvs_port { | ||
83 | struct asd_sas_port sas_port; | ||
84 | u8 port_attached; | ||
85 | u8 taskfileset; | ||
86 | u8 wide_port_phymap; | ||
87 | struct list_head list; | ||
88 | }; | ||
89 | |||
90 | struct mvs_phy { | ||
91 | struct mvs_port *port; | ||
92 | struct asd_sas_phy sas_phy; | ||
93 | struct sas_identify identify; | ||
94 | struct scsi_device *sdev; | ||
95 | u64 dev_sas_addr; | ||
96 | u64 att_dev_sas_addr; | ||
97 | u32 att_dev_info; | ||
98 | u32 dev_info; | ||
99 | u32 phy_type; | ||
100 | u32 phy_status; | ||
101 | u32 irq_status; | ||
102 | u32 frame_rcvd_size; | ||
103 | u8 frame_rcvd[32]; | ||
104 | u8 phy_attached; | ||
105 | enum sas_linkrate minimum_linkrate; | ||
106 | enum sas_linkrate maximum_linkrate; | ||
107 | }; | ||
108 | |||
109 | struct mvs_slot_info { | ||
110 | struct list_head list; | ||
111 | struct sas_task *task; | ||
112 | u32 n_elem; | ||
113 | u32 tx; | ||
114 | |||
115 | /* DMA buffer for storing cmd tbl, open addr frame, status buffer, | ||
116 | * and PRD table | ||
117 | */ | ||
118 | void *buf; | ||
119 | dma_addr_t buf_dma; | ||
120 | #if _MV_DUMP | ||
121 | u32 cmd_size; | ||
122 | #endif | ||
123 | |||
124 | void *response; | ||
125 | struct mvs_port *port; | ||
126 | }; | ||
127 | |||
128 | struct mvs_info { | ||
129 | unsigned long flags; | ||
130 | |||
131 | /* host-wide lock */ | ||
132 | spinlock_t lock; | ||
133 | |||
134 | /* our device */ | ||
135 | struct pci_dev *pdev; | ||
136 | |||
137 | /* enhanced mode registers */ | ||
138 | void __iomem *regs; | ||
139 | |||
140 | /* peripheral registers */ | ||
141 | void __iomem *peri_regs; | ||
142 | |||
143 | u8 sas_addr[SAS_ADDR_SIZE]; | ||
144 | |||
145 | /* SCSI/SAS glue */ | ||
146 | struct sas_ha_struct sas; | ||
147 | struct Scsi_Host *shost; | ||
148 | |||
149 | /* TX (delivery) DMA ring */ | ||
150 | __le32 *tx; | ||
151 | dma_addr_t tx_dma; | ||
152 | |||
153 | /* cached next-producer idx */ | ||
154 | u32 tx_prod; | ||
155 | |||
156 | /* RX (completion) DMA ring */ | ||
157 | __le32 *rx; | ||
158 | dma_addr_t rx_dma; | ||
159 | |||
160 | /* RX consumer idx */ | ||
161 | u32 rx_cons; | ||
162 | |||
163 | /* RX'd FIS area */ | ||
164 | __le32 *rx_fis; | ||
165 | dma_addr_t rx_fis_dma; | ||
166 | |||
167 | /* DMA command header slots */ | ||
168 | struct mvs_cmd_hdr *slot; | ||
169 | dma_addr_t slot_dma; | ||
170 | |||
171 | const struct mvs_chip_info *chip; | ||
172 | |||
173 | u8 tags[MVS_SLOTS]; | ||
174 | struct mvs_slot_info slot_info[MVS_SLOTS]; | ||
175 | /* further per-slot information */ | ||
176 | struct mvs_phy phy[MVS_MAX_PHYS]; | ||
177 | struct mvs_port port[MVS_MAX_PHYS]; | ||
178 | #ifdef MVS_USE_TASKLET | ||
179 | struct tasklet_struct tasklet; | ||
180 | #endif | ||
181 | }; | ||
182 | |||
183 | int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, | ||
184 | void *funcdata); | ||
185 | int mvs_slave_configure(struct scsi_device *sdev); | ||
186 | void mvs_scan_start(struct Scsi_Host *shost); | ||
187 | int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time); | ||
188 | int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags); | ||
189 | int mvs_task_abort(struct sas_task *task); | ||
190 | void mvs_port_formed(struct asd_sas_phy *sas_phy); | ||
191 | int mvs_I_T_nexus_reset(struct domain_device *dev); | ||
192 | void mvs_int_full(struct mvs_info *mvi); | ||
193 | void mvs_tag_init(struct mvs_info *mvi); | ||
194 | int mvs_nvram_read(struct mvs_info *mvi, u32 addr, void *buf, u32 buflen); | ||
195 | int __devinit mvs_hw_init(struct mvs_info *mvi); | ||
196 | void __devinit mvs_print_info(struct mvs_info *mvi); | ||
197 | void mvs_hba_interrupt_enable(struct mvs_info *mvi); | ||
198 | void mvs_hba_interrupt_disable(struct mvs_info *mvi); | ||
199 | void mvs_detect_porttype(struct mvs_info *mvi, int i); | ||
200 | u8 mvs_assign_reg_set(struct mvs_info *mvi, struct mvs_port *port); | ||
201 | void mvs_enable_xmt(struct mvs_info *mvi, int PhyId); | ||
202 | void __devinit mvs_phy_hacks(struct mvs_info *mvi); | ||
203 | void mvs_free_reg_set(struct mvs_info *mvi, struct mvs_port *port); | ||
204 | |||
205 | #endif | ||