diff options
Diffstat (limited to 'drivers/block/smart1,2.h')
-rw-r--r-- | drivers/block/smart1,2.h | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/drivers/block/smart1,2.h b/drivers/block/smart1,2.h new file mode 100644 index 000000000000..a0b403a6b4ed --- /dev/null +++ b/drivers/block/smart1,2.h | |||
@@ -0,0 +1,278 @@ | |||
1 | /* | ||
2 | * Disk Array driver for Compaq SMART2 Controllers | ||
3 | * Copyright 1998 Compaq Computer Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
13 | * NON INFRINGEMENT. See the GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | * | ||
19 | * Questions/Comments/Bugfixes to iss_storagedev@hp.com | ||
20 | * | ||
21 | * If you want to make changes, improve or add functionality to this | ||
22 | * driver, you'll probably need the Compaq Array Controller Interface | ||
23 | * Specificiation (Document number ECG086/1198) | ||
24 | */ | ||
25 | |||
26 | /* | ||
27 | * This file contains the controller communication implementation for | ||
28 | * Compaq SMART-1 and SMART-2 controllers. To the best of my knowledge, | ||
29 | * this should support: | ||
30 | * | ||
31 | * PCI: | ||
32 | * SMART-2/P, SMART-2DH, SMART-2SL, SMART-221, SMART-3100ES, SMART-3200 | ||
33 | * Integerated SMART Array Controller, SMART-4200, SMART-4250ES | ||
34 | * | ||
35 | * EISA: | ||
36 | * SMART-2/E, SMART, IAES, IDA-2, IDA | ||
37 | */ | ||
38 | |||
39 | /* | ||
40 | * Memory mapped FIFO interface (SMART 42xx cards) | ||
41 | */ | ||
42 | static void smart4_submit_command(ctlr_info_t *h, cmdlist_t *c) | ||
43 | { | ||
44 | writel(c->busaddr, h->vaddr + S42XX_REQUEST_PORT_OFFSET); | ||
45 | } | ||
46 | |||
47 | /* | ||
48 | * This card is the opposite of the other cards. | ||
49 | * 0 turns interrupts on... | ||
50 | * 0x08 turns them off... | ||
51 | */ | ||
52 | static void smart4_intr_mask(ctlr_info_t *h, unsigned long val) | ||
53 | { | ||
54 | if (val) | ||
55 | { /* Turn interrupts on */ | ||
56 | writel(0, h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET); | ||
57 | } else /* Turn them off */ | ||
58 | { | ||
59 | writel( S42XX_INTR_OFF, | ||
60 | h->vaddr + S42XX_REPLY_INTR_MASK_OFFSET); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * For older cards FIFO Full = 0. | ||
66 | * On this card 0 means there is room, anything else FIFO Full. | ||
67 | * | ||
68 | */ | ||
69 | static unsigned long smart4_fifo_full(ctlr_info_t *h) | ||
70 | { | ||
71 | |||
72 | return (!readl(h->vaddr + S42XX_REQUEST_PORT_OFFSET)); | ||
73 | } | ||
74 | |||
75 | /* This type of controller returns -1 if the fifo is empty, | ||
76 | * Not 0 like the others. | ||
77 | * And we need to let it know we read a value out | ||
78 | */ | ||
79 | static unsigned long smart4_completed(ctlr_info_t *h) | ||
80 | { | ||
81 | long register_value | ||
82 | = readl(h->vaddr + S42XX_REPLY_PORT_OFFSET); | ||
83 | |||
84 | /* Fifo is empty */ | ||
85 | if( register_value == 0xffffffff) | ||
86 | return 0; | ||
87 | |||
88 | /* Need to let it know we got the reply */ | ||
89 | /* We do this by writing a 0 to the port we just read from */ | ||
90 | writel(0, h->vaddr + S42XX_REPLY_PORT_OFFSET); | ||
91 | |||
92 | return ((unsigned long) register_value); | ||
93 | } | ||
94 | |||
95 | /* | ||
96 | * This hardware returns interrupt pending at a different place and | ||
97 | * it does not tell us if the fifo is empty, we will have check | ||
98 | * that by getting a 0 back from the comamnd_completed call. | ||
99 | */ | ||
100 | static unsigned long smart4_intr_pending(ctlr_info_t *h) | ||
101 | { | ||
102 | unsigned long register_value = | ||
103 | readl(h->vaddr + S42XX_INTR_STATUS); | ||
104 | |||
105 | if( register_value & S42XX_INTR_PENDING) | ||
106 | return FIFO_NOT_EMPTY; | ||
107 | return 0 ; | ||
108 | } | ||
109 | |||
110 | static struct access_method smart4_access = { | ||
111 | smart4_submit_command, | ||
112 | smart4_intr_mask, | ||
113 | smart4_fifo_full, | ||
114 | smart4_intr_pending, | ||
115 | smart4_completed, | ||
116 | }; | ||
117 | |||
118 | /* | ||
119 | * Memory mapped FIFO interface (PCI SMART2 and SMART 3xxx cards) | ||
120 | */ | ||
121 | static void smart2_submit_command(ctlr_info_t *h, cmdlist_t *c) | ||
122 | { | ||
123 | writel(c->busaddr, h->vaddr + COMMAND_FIFO); | ||
124 | } | ||
125 | |||
126 | static void smart2_intr_mask(ctlr_info_t *h, unsigned long val) | ||
127 | { | ||
128 | writel(val, h->vaddr + INTR_MASK); | ||
129 | } | ||
130 | |||
131 | static unsigned long smart2_fifo_full(ctlr_info_t *h) | ||
132 | { | ||
133 | return readl(h->vaddr + COMMAND_FIFO); | ||
134 | } | ||
135 | |||
136 | static unsigned long smart2_completed(ctlr_info_t *h) | ||
137 | { | ||
138 | return readl(h->vaddr + COMMAND_COMPLETE_FIFO); | ||
139 | } | ||
140 | |||
141 | static unsigned long smart2_intr_pending(ctlr_info_t *h) | ||
142 | { | ||
143 | return readl(h->vaddr + INTR_PENDING); | ||
144 | } | ||
145 | |||
146 | static struct access_method smart2_access = { | ||
147 | smart2_submit_command, | ||
148 | smart2_intr_mask, | ||
149 | smart2_fifo_full, | ||
150 | smart2_intr_pending, | ||
151 | smart2_completed, | ||
152 | }; | ||
153 | |||
154 | /* | ||
155 | * IO access for SMART-2/E cards | ||
156 | */ | ||
157 | static void smart2e_submit_command(ctlr_info_t *h, cmdlist_t *c) | ||
158 | { | ||
159 | outl(c->busaddr, h->io_mem_addr + COMMAND_FIFO); | ||
160 | } | ||
161 | |||
162 | static void smart2e_intr_mask(ctlr_info_t *h, unsigned long val) | ||
163 | { | ||
164 | outl(val, h->io_mem_addr + INTR_MASK); | ||
165 | } | ||
166 | |||
167 | static unsigned long smart2e_fifo_full(ctlr_info_t *h) | ||
168 | { | ||
169 | return inl(h->io_mem_addr + COMMAND_FIFO); | ||
170 | } | ||
171 | |||
172 | static unsigned long smart2e_completed(ctlr_info_t *h) | ||
173 | { | ||
174 | return inl(h->io_mem_addr + COMMAND_COMPLETE_FIFO); | ||
175 | } | ||
176 | |||
177 | static unsigned long smart2e_intr_pending(ctlr_info_t *h) | ||
178 | { | ||
179 | return inl(h->io_mem_addr + INTR_PENDING); | ||
180 | } | ||
181 | |||
182 | static struct access_method smart2e_access = { | ||
183 | smart2e_submit_command, | ||
184 | smart2e_intr_mask, | ||
185 | smart2e_fifo_full, | ||
186 | smart2e_intr_pending, | ||
187 | smart2e_completed, | ||
188 | }; | ||
189 | |||
190 | /* | ||
191 | * IO access for older SMART-1 type cards | ||
192 | */ | ||
193 | #define SMART1_SYSTEM_MASK 0xC8E | ||
194 | #define SMART1_SYSTEM_DOORBELL 0xC8F | ||
195 | #define SMART1_LOCAL_MASK 0xC8C | ||
196 | #define SMART1_LOCAL_DOORBELL 0xC8D | ||
197 | #define SMART1_INTR_MASK 0xC89 | ||
198 | #define SMART1_LISTADDR 0xC90 | ||
199 | #define SMART1_LISTLEN 0xC94 | ||
200 | #define SMART1_TAG 0xC97 | ||
201 | #define SMART1_COMPLETE_ADDR 0xC98 | ||
202 | #define SMART1_LISTSTATUS 0xC9E | ||
203 | |||
204 | #define CHANNEL_BUSY 0x01 | ||
205 | #define CHANNEL_CLEAR 0x02 | ||
206 | |||
207 | static void smart1_submit_command(ctlr_info_t *h, cmdlist_t *c) | ||
208 | { | ||
209 | /* | ||
210 | * This __u16 is actually a bunch of control flags on SMART | ||
211 | * and below. We want them all to be zero. | ||
212 | */ | ||
213 | c->hdr.size = 0; | ||
214 | |||
215 | outb(CHANNEL_CLEAR, h->io_mem_addr + SMART1_SYSTEM_DOORBELL); | ||
216 | |||
217 | outl(c->busaddr, h->io_mem_addr + SMART1_LISTADDR); | ||
218 | outw(c->size, h->io_mem_addr + SMART1_LISTLEN); | ||
219 | |||
220 | outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_LOCAL_DOORBELL); | ||
221 | } | ||
222 | |||
223 | static void smart1_intr_mask(ctlr_info_t *h, unsigned long val) | ||
224 | { | ||
225 | if (val == 1) { | ||
226 | outb(0xFD, h->io_mem_addr + SMART1_SYSTEM_DOORBELL); | ||
227 | outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_LOCAL_DOORBELL); | ||
228 | outb(0x01, h->io_mem_addr + SMART1_INTR_MASK); | ||
229 | outb(0x01, h->io_mem_addr + SMART1_SYSTEM_MASK); | ||
230 | } else { | ||
231 | outb(0, h->io_mem_addr + 0xC8E); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | static unsigned long smart1_fifo_full(ctlr_info_t *h) | ||
236 | { | ||
237 | unsigned char chan; | ||
238 | chan = inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_CLEAR; | ||
239 | return chan; | ||
240 | } | ||
241 | |||
242 | static unsigned long smart1_completed(ctlr_info_t *h) | ||
243 | { | ||
244 | unsigned char status; | ||
245 | unsigned long cmd; | ||
246 | |||
247 | if (inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY) { | ||
248 | outb(CHANNEL_BUSY, h->io_mem_addr + SMART1_SYSTEM_DOORBELL); | ||
249 | |||
250 | cmd = inl(h->io_mem_addr + SMART1_COMPLETE_ADDR); | ||
251 | status = inb(h->io_mem_addr + SMART1_LISTSTATUS); | ||
252 | |||
253 | outb(CHANNEL_CLEAR, h->io_mem_addr + SMART1_LOCAL_DOORBELL); | ||
254 | |||
255 | /* | ||
256 | * this is x86 (actually compaq x86) only, so it's ok | ||
257 | */ | ||
258 | if (cmd) ((cmdlist_t*)bus_to_virt(cmd))->req.hdr.rcode = status; | ||
259 | } else { | ||
260 | cmd = 0; | ||
261 | } | ||
262 | return cmd; | ||
263 | } | ||
264 | |||
265 | static unsigned long smart1_intr_pending(ctlr_info_t *h) | ||
266 | { | ||
267 | unsigned char chan; | ||
268 | chan = inb(h->io_mem_addr + SMART1_SYSTEM_DOORBELL) & CHANNEL_BUSY; | ||
269 | return chan; | ||
270 | } | ||
271 | |||
272 | static struct access_method smart1_access = { | ||
273 | smart1_submit_command, | ||
274 | smart1_intr_mask, | ||
275 | smart1_fifo_full, | ||
276 | smart1_intr_pending, | ||
277 | smart1_completed, | ||
278 | }; | ||