Commit | Line | Data |
---|---|---|
2908d778 JB |
1 | /* |
2 | * Aic94xx SAS/SATA driver sequencer interface. | |
3 | * | |
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | |
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | |
6 | * | |
7 | * Parts of this code adapted from David Chaw's adp94xx_seq.c. | |
8 | * | |
9 | * This file is licensed under GPLv2. | |
10 | * | |
11 | * This file is part of the aic94xx driver. | |
12 | * | |
13 | * The aic94xx driver is free software; you can redistribute it and/or | |
14 | * modify it under the terms of the GNU General Public License as | |
15 | * published by the Free Software Foundation; version 2 of the | |
16 | * License. | |
17 | * | |
18 | * The aic94xx driver is distributed in the hope that it will be useful, | |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
21 | * General Public License for more details. | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License | |
24 | * along with the aic94xx driver; if not, write to the Free Software | |
25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
26 | * | |
27 | */ | |
28 | ||
29 | #include <linux/delay.h> | |
5a0e3ad6 | 30 | #include <linux/gfp.h> |
2908d778 | 31 | #include <linux/pci.h> |
bc229b36 | 32 | #include <linux/module.h> |
2908d778 JB |
33 | #include <linux/firmware.h> |
34 | #include "aic94xx_reg.h" | |
35 | #include "aic94xx_hwi.h" | |
36 | ||
37 | #include "aic94xx_seq.h" | |
38 | #include "aic94xx_dump.h" | |
39 | ||
40 | /* It takes no more than 0.05 us for an instruction | |
41 | * to complete. So waiting for 1 us should be more than | |
42 | * plenty. | |
43 | */ | |
44 | #define PAUSE_DELAY 1 | |
45 | #define PAUSE_TRIES 1000 | |
46 | ||
47 | static const struct firmware *sequencer_fw; | |
2908d778 JB |
48 | static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task, |
49 | cseq_idle_loop, lseq_idle_loop; | |
0bc202e0 | 50 | static const u8 *cseq_code, *lseq_code; |
2908d778 JB |
51 | static u32 cseq_code_size, lseq_code_size; |
52 | ||
53 | static u16 first_scb_site_no = 0xFFFF; | |
54 | static u16 last_scb_site_no; | |
55 | ||
56 | /* ---------- Pause/Unpause CSEQ/LSEQ ---------- */ | |
57 | ||
58 | /** | |
59 | * asd_pause_cseq - pause the central sequencer | |
60 | * @asd_ha: pointer to host adapter structure | |
61 | * | |
62 | * Return 0 on success, negative on failure. | |
63 | */ | |
81e56ded | 64 | static int asd_pause_cseq(struct asd_ha_struct *asd_ha) |
2908d778 JB |
65 | { |
66 | int count = PAUSE_TRIES; | |
67 | u32 arp2ctl; | |
68 | ||
69 | arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); | |
70 | if (arp2ctl & PAUSED) | |
71 | return 0; | |
72 | ||
73 | asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl | EPAUSE); | |
74 | do { | |
75 | arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); | |
76 | if (arp2ctl & PAUSED) | |
77 | return 0; | |
78 | udelay(PAUSE_DELAY); | |
79 | } while (--count > 0); | |
80 | ||
81 | ASD_DPRINTK("couldn't pause CSEQ\n"); | |
82 | return -1; | |
83 | } | |
84 | ||
85 | /** | |
86 | * asd_unpause_cseq - unpause the central sequencer. | |
87 | * @asd_ha: pointer to host adapter structure. | |
88 | * | |
89 | * Return 0 on success, negative on error. | |
90 | */ | |
81e56ded | 91 | static int asd_unpause_cseq(struct asd_ha_struct *asd_ha) |
2908d778 JB |
92 | { |
93 | u32 arp2ctl; | |
94 | int count = PAUSE_TRIES; | |
95 | ||
96 | arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); | |
97 | if (!(arp2ctl & PAUSED)) | |
98 | return 0; | |
99 | ||
100 | asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl & ~EPAUSE); | |
101 | do { | |
102 | arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); | |
103 | if (!(arp2ctl & PAUSED)) | |
104 | return 0; | |
105 | udelay(PAUSE_DELAY); | |
106 | } while (--count > 0); | |
107 | ||
108 | ASD_DPRINTK("couldn't unpause the CSEQ\n"); | |
109 | return -1; | |
110 | } | |
111 | ||
112 | /** | |
113 | * asd_seq_pause_lseq - pause a link sequencer | |
114 | * @asd_ha: pointer to a host adapter structure | |
115 | * @lseq: link sequencer of interest | |
116 | * | |
117 | * Return 0 on success, negative on error. | |
118 | */ | |
81e56ded | 119 | static int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq) |
2908d778 JB |
120 | { |
121 | u32 arp2ctl; | |
122 | int count = PAUSE_TRIES; | |
123 | ||
124 | arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); | |
125 | if (arp2ctl & PAUSED) | |
126 | return 0; | |
127 | ||
128 | asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl | EPAUSE); | |
129 | do { | |
130 | arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); | |
131 | if (arp2ctl & PAUSED) | |
132 | return 0; | |
133 | udelay(PAUSE_DELAY); | |
134 | } while (--count > 0); | |
135 | ||
136 | ASD_DPRINTK("couldn't pause LSEQ %d\n", lseq); | |
137 | return -1; | |
138 | } | |
139 | ||
140 | /** | |
141 | * asd_pause_lseq - pause the link sequencer(s) | |
142 | * @asd_ha: pointer to host adapter structure | |
143 | * @lseq_mask: mask of link sequencers of interest | |
144 | * | |
145 | * Return 0 on success, negative on failure. | |
146 | */ | |
81e56ded | 147 | static int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) |
2908d778 JB |
148 | { |
149 | int lseq; | |
150 | int err = 0; | |
151 | ||
152 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | |
153 | err = asd_seq_pause_lseq(asd_ha, lseq); | |
154 | if (err) | |
155 | return err; | |
156 | } | |
157 | ||
158 | return err; | |
159 | } | |
160 | ||
161 | /** | |
162 | * asd_seq_unpause_lseq - unpause a link sequencer | |
163 | * @asd_ha: pointer to host adapter structure | |
164 | * @lseq: link sequencer of interest | |
165 | * | |
166 | * Return 0 on success, negative on error. | |
167 | */ | |
81e56ded | 168 | static int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq) |
2908d778 JB |
169 | { |
170 | u32 arp2ctl; | |
171 | int count = PAUSE_TRIES; | |
172 | ||
173 | arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); | |
174 | if (!(arp2ctl & PAUSED)) | |
175 | return 0; | |
176 | ||
177 | asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl & ~EPAUSE); | |
178 | do { | |
179 | arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); | |
180 | if (!(arp2ctl & PAUSED)) | |
181 | return 0; | |
182 | udelay(PAUSE_DELAY); | |
183 | } while (--count > 0); | |
184 | ||
185 | ASD_DPRINTK("couldn't unpause LSEQ %d\n", lseq); | |
186 | return 0; | |
187 | } | |
188 | ||
189 | ||
2908d778 JB |
190 | /* ---------- Downloading CSEQ/LSEQ microcode ---------- */ |
191 | ||
192 | static int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog, | |
193 | u32 size) | |
194 | { | |
195 | u32 addr = CSEQ_RAM_REG_BASE_ADR; | |
196 | const u32 *prog = (u32 *) _prog; | |
197 | u32 i; | |
198 | ||
199 | for (i = 0; i < size; i += 4, prog++, addr += 4) { | |
200 | u32 val = asd_read_reg_dword(asd_ha, addr); | |
201 | ||
202 | if (le32_to_cpu(*prog) != val) { | |
203 | asd_printk("%s: cseq verify failed at %u " | |
204 | "read:0x%x, wanted:0x%x\n", | |
205 | pci_name(asd_ha->pcidev), | |
206 | i, val, le32_to_cpu(*prog)); | |
207 | return -1; | |
208 | } | |
209 | } | |
210 | ASD_DPRINTK("verified %d bytes, passed\n", size); | |
211 | return 0; | |
212 | } | |
213 | ||
214 | /** | |
215 | * asd_verify_lseq - verify the microcode of a link sequencer | |
216 | * @asd_ha: pointer to host adapter structure | |
217 | * @_prog: pointer to the microcode | |
218 | * @size: size of the microcode in bytes | |
219 | * @lseq: link sequencer of interest | |
220 | * | |
221 | * The link sequencer code is accessed in 4 KB pages, which are selected | |
222 | * by setting LmRAMPAGE (bits 8 and 9) of the LmBISTCTL1 register. | |
223 | * The 10 KB LSEQm instruction code is mapped, page at a time, at | |
224 | * LmSEQRAM address. | |
225 | */ | |
226 | static int asd_verify_lseq(struct asd_ha_struct *asd_ha, const u8 *_prog, | |
227 | u32 size, int lseq) | |
228 | { | |
229 | #define LSEQ_CODEPAGE_SIZE 4096 | |
230 | int pages = (size + LSEQ_CODEPAGE_SIZE - 1) / LSEQ_CODEPAGE_SIZE; | |
231 | u32 page; | |
232 | const u32 *prog = (u32 *) _prog; | |
233 | ||
234 | for (page = 0; page < pages; page++) { | |
235 | u32 i; | |
236 | ||
237 | asd_write_reg_dword(asd_ha, LmBISTCTL1(lseq), | |
238 | page << LmRAMPAGE_LSHIFT); | |
239 | for (i = 0; size > 0 && i < LSEQ_CODEPAGE_SIZE; | |
240 | i += 4, prog++, size-=4) { | |
241 | ||
242 | u32 val = asd_read_reg_dword(asd_ha, LmSEQRAM(lseq)+i); | |
243 | ||
244 | if (le32_to_cpu(*prog) != val) { | |
245 | asd_printk("%s: LSEQ%d verify failed " | |
246 | "page:%d, offs:%d\n", | |
247 | pci_name(asd_ha->pcidev), | |
248 | lseq, page, i); | |
249 | return -1; | |
250 | } | |
251 | } | |
252 | } | |
253 | ASD_DPRINTK("LSEQ%d verified %d bytes, passed\n", lseq, | |
254 | (int)((u8 *)prog-_prog)); | |
255 | return 0; | |
256 | } | |
257 | ||
258 | /** | |
259 | * asd_verify_seq -- verify CSEQ/LSEQ microcode | |
260 | * @asd_ha: pointer to host adapter structure | |
261 | * @prog: pointer to microcode | |
262 | * @size: size of the microcode | |
263 | * @lseq_mask: if 0, verify CSEQ microcode, else mask of LSEQs of interest | |
264 | * | |
265 | * Return 0 if microcode is correct, negative on mismatch. | |
266 | */ | |
267 | static int asd_verify_seq(struct asd_ha_struct *asd_ha, const u8 *prog, | |
268 | u32 size, u8 lseq_mask) | |
269 | { | |
270 | if (lseq_mask == 0) | |
271 | return asd_verify_cseq(asd_ha, prog, size); | |
272 | else { | |
273 | int lseq, err; | |
274 | ||
275 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | |
276 | err = asd_verify_lseq(asd_ha, prog, size, lseq); | |
277 | if (err) | |
278 | return err; | |
279 | } | |
280 | } | |
281 | ||
282 | return 0; | |
283 | } | |
284 | #define ASD_DMA_MODE_DOWNLOAD | |
285 | #ifdef ASD_DMA_MODE_DOWNLOAD | |
286 | /* This is the size of the CSEQ Mapped instruction page */ | |
287 | #define MAX_DMA_OVLY_COUNT ((1U << 14)-1) | |
288 | static int asd_download_seq(struct asd_ha_struct *asd_ha, | |
289 | const u8 * const prog, u32 size, u8 lseq_mask) | |
290 | { | |
291 | u32 comstaten; | |
292 | u32 reg; | |
293 | int page; | |
294 | const int pages = (size + MAX_DMA_OVLY_COUNT - 1) / MAX_DMA_OVLY_COUNT; | |
295 | struct asd_dma_tok *token; | |
296 | int err = 0; | |
297 | ||
298 | if (size % 4) { | |
299 | asd_printk("sequencer program not multiple of 4\n"); | |
300 | return -1; | |
301 | } | |
302 | ||
303 | asd_pause_cseq(asd_ha); | |
304 | asd_pause_lseq(asd_ha, 0xFF); | |
305 | ||
306 | /* save, disable and clear interrupts */ | |
307 | comstaten = asd_read_reg_dword(asd_ha, COMSTATEN); | |
308 | asd_write_reg_dword(asd_ha, COMSTATEN, 0); | |
309 | asd_write_reg_dword(asd_ha, COMSTAT, COMSTAT_MASK); | |
310 | ||
311 | asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN); | |
312 | asd_write_reg_dword(asd_ha, CHIMINT, CHIMINT_MASK); | |
313 | ||
314 | token = asd_alloc_coherent(asd_ha, MAX_DMA_OVLY_COUNT, GFP_KERNEL); | |
315 | if (!token) { | |
316 | asd_printk("out of memory for dma SEQ download\n"); | |
317 | err = -ENOMEM; | |
318 | goto out; | |
319 | } | |
320 | ASD_DPRINTK("dma-ing %d bytes\n", size); | |
321 | ||
322 | for (page = 0; page < pages; page++) { | |
323 | int i; | |
324 | u32 left = min(size-page*MAX_DMA_OVLY_COUNT, | |
325 | (u32)MAX_DMA_OVLY_COUNT); | |
326 | ||
327 | memcpy(token->vaddr, prog + page*MAX_DMA_OVLY_COUNT, left); | |
328 | asd_write_reg_addr(asd_ha, OVLYDMAADR, token->dma_handle); | |
329 | asd_write_reg_dword(asd_ha, OVLYDMACNT, left); | |
330 | reg = !page ? RESETOVLYDMA : 0; | |
331 | reg |= (STARTOVLYDMA | OVLYHALTERR); | |
332 | reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); | |
333 | /* Start DMA. */ | |
334 | asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); | |
335 | ||
336 | for (i = PAUSE_TRIES*100; i > 0; i--) { | |
337 | u32 dmadone = asd_read_reg_dword(asd_ha, OVLYDMACTL); | |
338 | if (!(dmadone & OVLYDMAACT)) | |
339 | break; | |
340 | udelay(PAUSE_DELAY); | |
341 | } | |
342 | } | |
343 | ||
344 | reg = asd_read_reg_dword(asd_ha, COMSTAT); | |
345 | if (!(reg & OVLYDMADONE) || (reg & OVLYERR) | |
346 | || (asd_read_reg_dword(asd_ha, CHIMINT) & DEVEXCEPT_MASK)){ | |
347 | asd_printk("%s: error DMA-ing sequencer code\n", | |
348 | pci_name(asd_ha->pcidev)); | |
349 | err = -ENODEV; | |
350 | } | |
351 | ||
352 | asd_free_coherent(asd_ha, token); | |
353 | out: | |
354 | asd_write_reg_dword(asd_ha, COMSTATEN, comstaten); | |
355 | ||
356 | return err ? : asd_verify_seq(asd_ha, prog, size, lseq_mask); | |
357 | } | |
358 | #else /* ASD_DMA_MODE_DOWNLOAD */ | |
359 | static int asd_download_seq(struct asd_ha_struct *asd_ha, const u8 *_prog, | |
360 | u32 size, u8 lseq_mask) | |
361 | { | |
362 | int i; | |
363 | u32 reg = 0; | |
364 | const u32 *prog = (u32 *) _prog; | |
365 | ||
366 | if (size % 4) { | |
367 | asd_printk("sequencer program not multiple of 4\n"); | |
368 | return -1; | |
369 | } | |
370 | ||
371 | asd_pause_cseq(asd_ha); | |
372 | asd_pause_lseq(asd_ha, 0xFF); | |
373 | ||
374 | reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); | |
375 | reg |= PIOCMODE; | |
376 | ||
377 | asd_write_reg_dword(asd_ha, OVLYDMACNT, size); | |
378 | asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); | |
379 | ||
380 | ASD_DPRINTK("downloading %s sequencer%s in PIO mode...\n", | |
381 | lseq_mask ? "LSEQ" : "CSEQ", lseq_mask ? "s" : ""); | |
382 | ||
383 | for (i = 0; i < size; i += 4, prog++) | |
384 | asd_write_reg_dword(asd_ha, SPIODATA, *prog); | |
385 | ||
386 | reg = (reg & ~PIOCMODE) | OVLYHALTERR; | |
387 | asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); | |
388 | ||
389 | return asd_verify_seq(asd_ha, _prog, size, lseq_mask); | |
390 | } | |
391 | #endif /* ASD_DMA_MODE_DOWNLOAD */ | |
392 | ||
393 | /** | |
394 | * asd_seq_download_seqs - download the sequencer microcode | |
395 | * @asd_ha: pointer to host adapter structure | |
396 | * | |
397 | * Download the central and link sequencer microcode. | |
398 | */ | |
399 | static int asd_seq_download_seqs(struct asd_ha_struct *asd_ha) | |
400 | { | |
401 | int err; | |
402 | ||
403 | if (!asd_ha->hw_prof.enabled_phys) { | |
404 | asd_printk("%s: no enabled phys!\n", pci_name(asd_ha->pcidev)); | |
405 | return -ENODEV; | |
406 | } | |
407 | ||
408 | /* Download the CSEQ */ | |
409 | ASD_DPRINTK("downloading CSEQ...\n"); | |
410 | err = asd_download_seq(asd_ha, cseq_code, cseq_code_size, 0); | |
411 | if (err) { | |
412 | asd_printk("CSEQ download failed:%d\n", err); | |
413 | return err; | |
414 | } | |
415 | ||
416 | /* Download the Link Sequencers code. All of the Link Sequencers | |
417 | * microcode can be downloaded at the same time. | |
418 | */ | |
419 | ASD_DPRINTK("downloading LSEQs...\n"); | |
420 | err = asd_download_seq(asd_ha, lseq_code, lseq_code_size, | |
421 | asd_ha->hw_prof.enabled_phys); | |
422 | if (err) { | |
423 | /* Try it one at a time */ | |
424 | u8 lseq; | |
425 | u8 lseq_mask = asd_ha->hw_prof.enabled_phys; | |
426 | ||
427 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | |
428 | err = asd_download_seq(asd_ha, lseq_code, | |
429 | lseq_code_size, 1<<lseq); | |
430 | if (err) | |
431 | break; | |
432 | } | |
433 | } | |
434 | if (err) | |
435 | asd_printk("LSEQs download failed:%d\n", err); | |
436 | ||
437 | return err; | |
438 | } | |
439 | ||
440 | /* ---------- Initializing the chip, chip memory, etc. ---------- */ | |
441 | ||
442 | /** | |
443 | * asd_init_cseq_mip - initialize CSEQ mode independent pages 4-7 | |
444 | * @asd_ha: pointer to host adapter structure | |
445 | */ | |
446 | static void asd_init_cseq_mip(struct asd_ha_struct *asd_ha) | |
447 | { | |
448 | /* CSEQ Mode Independent, page 4 setup. */ | |
449 | asd_write_reg_word(asd_ha, CSEQ_Q_EXE_HEAD, 0xFFFF); | |
450 | asd_write_reg_word(asd_ha, CSEQ_Q_EXE_TAIL, 0xFFFF); | |
451 | asd_write_reg_word(asd_ha, CSEQ_Q_DONE_HEAD, 0xFFFF); | |
452 | asd_write_reg_word(asd_ha, CSEQ_Q_DONE_TAIL, 0xFFFF); | |
453 | asd_write_reg_word(asd_ha, CSEQ_Q_SEND_HEAD, 0xFFFF); | |
454 | asd_write_reg_word(asd_ha, CSEQ_Q_SEND_TAIL, 0xFFFF); | |
455 | asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_HEAD, 0xFFFF); | |
456 | asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_TAIL, 0xFFFF); | |
457 | asd_write_reg_word(asd_ha, CSEQ_Q_COPY_HEAD, 0xFFFF); | |
458 | asd_write_reg_word(asd_ha, CSEQ_Q_COPY_TAIL, 0xFFFF); | |
459 | asd_write_reg_word(asd_ha, CSEQ_REG0, 0); | |
460 | asd_write_reg_word(asd_ha, CSEQ_REG1, 0); | |
461 | asd_write_reg_dword(asd_ha, CSEQ_REG2, 0); | |
462 | asd_write_reg_byte(asd_ha, CSEQ_LINK_CTL_Q_MAP, 0); | |
463 | { | |
464 | u8 con = asd_read_reg_byte(asd_ha, CCONEXIST); | |
465 | u8 val = hweight8(con); | |
466 | asd_write_reg_byte(asd_ha, CSEQ_MAX_CSEQ_MODE, (val<<4)|val); | |
467 | } | |
468 | asd_write_reg_word(asd_ha, CSEQ_FREE_LIST_HACK_COUNT, 0); | |
469 | ||
470 | /* CSEQ Mode independent, page 5 setup. */ | |
471 | asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE, 0); | |
472 | asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE+4, 0); | |
473 | asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT, 0); | |
474 | asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT+4, 0); | |
475 | asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_HEAD, 0xFFFF); | |
476 | asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_TAIL, 0xFFFF); | |
477 | asd_write_reg_word(asd_ha, CSEQ_NEED_EST_NEXUS_SCB, 0); | |
478 | asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_HEAD, 0); | |
479 | asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_TAIL, 0); | |
480 | asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_SCB_OFFSET, 0); | |
481 | ||
482 | /* CSEQ Mode independent, page 6 setup. */ | |
483 | asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR0, 0); | |
484 | asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR1, 0); | |
485 | asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_SCBPTR, 0); | |
486 | asd_write_reg_byte(asd_ha, CSEQ_INT_ROUT_MODE, 0); | |
487 | asd_write_reg_byte(asd_ha, CSEQ_ISR_SCRATCH_FLAGS, 0); | |
488 | asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_SINDEX, 0); | |
489 | asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_DINDEX, 0); | |
490 | asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_HEAD, 0xFFFF); | |
491 | asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_TAIL, 0xFFFF); | |
492 | /* Calculate the free scb mask. */ | |
493 | { | |
494 | u16 cmdctx = asd_get_cmdctx_size(asd_ha); | |
495 | cmdctx = (~((cmdctx/128)-1)) >> 8; | |
496 | asd_write_reg_byte(asd_ha, CSEQ_FREE_SCB_MASK, (u8)cmdctx); | |
497 | } | |
498 | asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_HEAD, | |
499 | first_scb_site_no); | |
500 | asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_TAIL, | |
501 | last_scb_site_no); | |
502 | asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_HEAD, 0xFFFF); | |
503 | asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_TAIL, 0xFFFF); | |
504 | ||
505 | /* CSEQ Mode independent, page 7 setup. */ | |
506 | asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE, 0); | |
507 | asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE+4, 0); | |
508 | asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT, 0); | |
509 | asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT+4, 0); | |
510 | asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_HEAD, 0xFFFF); | |
511 | asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_TAIL, 0xFFFF); | |
512 | asd_write_reg_word(asd_ha, CSEQ_NEED_EMPTY_SCB, 0); | |
513 | asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_HEAD, 0); | |
514 | asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_TAIL, 0); | |
515 | asd_write_reg_byte(asd_ha, CSEQ_EMPTY_SCB_OFFSET, 0); | |
516 | asd_write_reg_word(asd_ha, CSEQ_PRIMITIVE_DATA, 0); | |
517 | asd_write_reg_dword(asd_ha, CSEQ_TIMEOUT_CONST, 0); | |
518 | } | |
519 | ||
520 | /** | |
521 | * asd_init_cseq_mdp - initialize CSEQ Mode dependent pages | |
522 | * @asd_ha: pointer to host adapter structure | |
523 | */ | |
524 | static void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha) | |
525 | { | |
526 | int i; | |
527 | int moffs; | |
528 | ||
529 | moffs = CSEQ_PAGE_SIZE * 2; | |
530 | ||
531 | /* CSEQ Mode dependent, modes 0-7, page 0 setup. */ | |
532 | for (i = 0; i < 8; i++) { | |
533 | asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SINDEX, 0); | |
534 | asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCBPTR, 0); | |
535 | asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_HEAD, 0xFFFF); | |
536 | asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_TAIL, 0xFFFF); | |
537 | asd_write_reg_byte(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCRPAGE, 0); | |
538 | } | |
539 | ||
540 | /* CSEQ Mode dependent, mode 0-7, page 1 and 2 shall be ignored. */ | |
541 | ||
542 | /* CSEQ Mode dependent, mode 8, page 0 setup. */ | |
543 | asd_write_reg_word(asd_ha, CSEQ_RET_ADDR, 0xFFFF); | |
544 | asd_write_reg_word(asd_ha, CSEQ_RET_SCBPTR, 0); | |
545 | asd_write_reg_word(asd_ha, CSEQ_SAVE_SCBPTR, 0); | |
546 | asd_write_reg_word(asd_ha, CSEQ_EMPTY_TRANS_CTX, 0); | |
547 | asd_write_reg_word(asd_ha, CSEQ_RESP_LEN, 0); | |
548 | asd_write_reg_word(asd_ha, CSEQ_TMF_SCBPTR, 0); | |
549 | asd_write_reg_word(asd_ha, CSEQ_GLOBAL_PREV_SCB, 0); | |
550 | asd_write_reg_word(asd_ha, CSEQ_GLOBAL_HEAD, 0); | |
551 | asd_write_reg_word(asd_ha, CSEQ_CLEAR_LU_HEAD, 0); | |
552 | asd_write_reg_byte(asd_ha, CSEQ_TMF_OPCODE, 0); | |
553 | asd_write_reg_byte(asd_ha, CSEQ_SCRATCH_FLAGS, 0); | |
554 | asd_write_reg_word(asd_ha, CSEQ_HSB_SITE, 0); | |
555 | asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_SCB_SITE, | |
556 | (u16)last_scb_site_no+1); | |
557 | asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_DDB_SITE, | |
558 | (u16)asd_ha->hw_prof.max_ddbs); | |
559 | ||
560 | /* CSEQ Mode dependent, mode 8, page 1 setup. */ | |
561 | asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR, 0); | |
562 | asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR + 4, 0); | |
563 | asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK, 0); | |
564 | asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK + 4, 0); | |
565 | ||
566 | /* CSEQ Mode dependent, mode 8, page 2 setup. */ | |
567 | /* Tell the sequencer the bus address of the first SCB. */ | |
568 | asd_write_reg_addr(asd_ha, CSEQ_HQ_NEW_POINTER, | |
569 | asd_ha->seq.next_scb.dma_handle); | |
570 | ASD_DPRINTK("First SCB dma_handle: 0x%llx\n", | |
571 | (unsigned long long)asd_ha->seq.next_scb.dma_handle); | |
572 | ||
573 | /* Tell the sequencer the first Done List entry address. */ | |
574 | asd_write_reg_addr(asd_ha, CSEQ_HQ_DONE_BASE, | |
575 | asd_ha->seq.actual_dl->dma_handle); | |
576 | ||
577 | /* Initialize the Q_DONE_POINTER with the least significant | |
578 | * 4 bytes of the first Done List address. */ | |
579 | asd_write_reg_dword(asd_ha, CSEQ_HQ_DONE_POINTER, | |
580 | ASD_BUSADDR_LO(asd_ha->seq.actual_dl->dma_handle)); | |
581 | ||
582 | asd_write_reg_byte(asd_ha, CSEQ_HQ_DONE_PASS, ASD_DEF_DL_TOGGLE); | |
583 | ||
584 | /* CSEQ Mode dependent, mode 8, page 3 shall be ignored. */ | |
585 | } | |
586 | ||
587 | /** | |
588 | * asd_init_cseq_scratch -- setup and init CSEQ | |
589 | * @asd_ha: pointer to host adapter structure | |
590 | * | |
421f91d2 | 591 | * Setup and initialize Central sequencers. Initialize the mode |
2908d778 JB |
592 | * independent and dependent scratch page to the default settings. |
593 | */ | |
594 | static void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha) | |
595 | { | |
596 | asd_init_cseq_mip(asd_ha); | |
597 | asd_init_cseq_mdp(asd_ha); | |
598 | } | |
599 | ||
600 | /** | |
601 | * asd_init_lseq_mip -- initialize LSEQ Mode independent pages 0-3 | |
602 | * @asd_ha: pointer to host adapter structure | |
603 | */ | |
604 | static void asd_init_lseq_mip(struct asd_ha_struct *asd_ha, u8 lseq) | |
605 | { | |
606 | int i; | |
607 | ||
608 | /* LSEQ Mode independent page 0 setup. */ | |
609 | asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_HEAD(lseq), 0xFFFF); | |
610 | asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_TAIL(lseq), 0xFFFF); | |
611 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_NUMBER(lseq), lseq); | |
612 | asd_write_reg_byte(asd_ha, LmSEQ_SCRATCH_FLAGS(lseq), | |
613 | ASD_NOTIFY_ENABLE_SPINUP); | |
614 | asd_write_reg_dword(asd_ha, LmSEQ_CONNECTION_STATE(lseq),0x08000000); | |
615 | asd_write_reg_word(asd_ha, LmSEQ_CONCTL(lseq), 0); | |
616 | asd_write_reg_byte(asd_ha, LmSEQ_CONSTAT(lseq), 0); | |
617 | asd_write_reg_byte(asd_ha, LmSEQ_CONNECTION_MODES(lseq), 0); | |
618 | asd_write_reg_word(asd_ha, LmSEQ_REG1_ISR(lseq), 0); | |
619 | asd_write_reg_word(asd_ha, LmSEQ_REG2_ISR(lseq), 0); | |
620 | asd_write_reg_word(asd_ha, LmSEQ_REG3_ISR(lseq), 0); | |
621 | asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq), 0); | |
622 | asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq)+4, 0); | |
623 | ||
624 | /* LSEQ Mode independent page 1 setup. */ | |
625 | asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR0(lseq), 0xFFFF); | |
626 | asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR1(lseq), 0xFFFF); | |
627 | asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR2(lseq), 0xFFFF); | |
628 | asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR3(lseq), 0xFFFF); | |
629 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE0(lseq), 0); | |
630 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE1(lseq), 0); | |
631 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE2(lseq), 0); | |
632 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE3(lseq), 0); | |
633 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_HEAD(lseq), 0); | |
634 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_TAIL(lseq), 0); | |
635 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_BUF_AVAIL(lseq), 0); | |
636 | asd_write_reg_dword(asd_ha, LmSEQ_TIMEOUT_CONST(lseq), 0); | |
637 | asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_SINDEX(lseq), 0); | |
638 | asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_DINDEX(lseq), 0); | |
639 | ||
640 | /* LSEQ Mode Independent page 2 setup. */ | |
641 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR0(lseq), 0xFFFF); | |
642 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR1(lseq), 0xFFFF); | |
643 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR2(lseq), 0xFFFF); | |
644 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR3(lseq), 0xFFFF); | |
645 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD0(lseq), 0); | |
646 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD1(lseq), 0); | |
647 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD2(lseq), 0); | |
648 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD3(lseq), 0); | |
649 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_HEAD(lseq), 0); | |
650 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_TAIL(lseq), 0); | |
651 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_BUFS_AVAIL(lseq), 0); | |
652 | for (i = 0; i < 12; i += 4) | |
653 | asd_write_reg_dword(asd_ha, LmSEQ_ATA_SCR_REGS(lseq) + i, 0); | |
654 | ||
655 | /* LSEQ Mode Independent page 3 setup. */ | |
656 | ||
657 | /* Device present timer timeout */ | |
658 | asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TMR_TOUT_CONST(lseq), | |
659 | ASD_DEV_PRESENT_TIMEOUT); | |
660 | ||
661 | /* SATA interlock timer disabled */ | |
662 | asd_write_reg_dword(asd_ha, LmSEQ_SATA_INTERLOCK_TIMEOUT(lseq), | |
663 | ASD_SATA_INTERLOCK_TIMEOUT); | |
664 | ||
665 | /* STP shutdown timer timeout constant, IGNORED by the sequencer, | |
666 | * always 0. */ | |
667 | asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMEOUT(lseq), | |
668 | ASD_STP_SHUTDOWN_TIMEOUT); | |
669 | ||
670 | asd_write_reg_dword(asd_ha, LmSEQ_SRST_ASSERT_TIMEOUT(lseq), | |
671 | ASD_SRST_ASSERT_TIMEOUT); | |
672 | ||
673 | asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMEOUT(lseq), | |
674 | ASD_RCV_FIS_TIMEOUT); | |
675 | ||
676 | asd_write_reg_dword(asd_ha, LmSEQ_ONE_MILLISEC_TIMEOUT(lseq), | |
677 | ASD_ONE_MILLISEC_TIMEOUT); | |
678 | ||
679 | /* COM_INIT timer */ | |
680 | asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(lseq), | |
681 | ASD_TEN_MILLISEC_TIMEOUT); | |
682 | ||
683 | asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMEOUT(lseq), | |
684 | ASD_SMP_RCV_TIMEOUT); | |
685 | } | |
686 | ||
687 | /** | |
688 | * asd_init_lseq_mdp -- initialize LSEQ mode dependent pages. | |
689 | * @asd_ha: pointer to host adapter structure | |
690 | */ | |
691 | static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq) | |
692 | { | |
693 | int i; | |
694 | u32 moffs; | |
695 | u16 ret_addr[] = { | |
696 | 0xFFFF, /* mode 0 */ | |
697 | 0xFFFF, /* mode 1 */ | |
698 | mode2_task, /* mode 2 */ | |
699 | 0, | |
700 | 0xFFFF, /* mode 4/5 */ | |
701 | 0xFFFF, /* mode 4/5 */ | |
702 | }; | |
703 | ||
704 | /* | |
705 | * Mode 0,1,2 and 4/5 have common field on page 0 for the first | |
706 | * 14 bytes. | |
707 | */ | |
708 | for (i = 0; i < 3; i++) { | |
709 | moffs = i * LSEQ_MODE_SCRATCH_SIZE; | |
710 | asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)+moffs, | |
711 | ret_addr[i]); | |
712 | asd_write_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)+moffs, 0); | |
713 | asd_write_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)+moffs, 0); | |
714 | asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)+moffs,0xFFFF); | |
715 | asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)+moffs,0xFFFF); | |
716 | asd_write_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)+moffs,0); | |
717 | asd_write_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)+moffs,0); | |
718 | } | |
719 | /* | |
720 | * Mode 5 page 0 overlaps the same scratch page with Mode 0 page 3. | |
721 | */ | |
722 | asd_write_reg_word(asd_ha, | |
723 | LmSEQ_RET_ADDR(lseq)+LSEQ_MODE5_PAGE0_OFFSET, | |
724 | ret_addr[5]); | |
725 | asd_write_reg_word(asd_ha, | |
726 | LmSEQ_REG0_MODE(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); | |
727 | asd_write_reg_word(asd_ha, | |
728 | LmSEQ_MODE_FLAGS(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); | |
729 | asd_write_reg_word(asd_ha, | |
730 | LmSEQ_RET_ADDR2(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); | |
731 | asd_write_reg_word(asd_ha, | |
732 | LmSEQ_RET_ADDR1(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); | |
733 | asd_write_reg_byte(asd_ha, | |
734 | LmSEQ_OPCODE_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); | |
735 | asd_write_reg_word(asd_ha, | |
736 | LmSEQ_DATA_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); | |
737 | ||
738 | /* LSEQ Mode dependent 0, page 0 setup. */ | |
739 | asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_DDB_SITE(lseq), | |
740 | (u16)asd_ha->hw_prof.max_ddbs); | |
741 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_TRANS_CTX(lseq), 0); | |
742 | asd_write_reg_word(asd_ha, LmSEQ_RESP_LEN(lseq), 0); | |
743 | asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_SCB_SITE(lseq), | |
744 | (u16)last_scb_site_no+1); | |
745 | asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq), | |
355edd2e | 746 | (u16) ((LmM0INTEN_MASK & 0xFFFF0000) >> 16)); |
2908d778 JB |
747 | asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq) + 2, |
748 | (u16) LmM0INTEN_MASK & 0xFFFF); | |
749 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_FRM_LEN(lseq), 0); | |
750 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_PROTOCOL(lseq), 0); | |
751 | asd_write_reg_byte(asd_ha, LmSEQ_RESP_STATUS(lseq), 0); | |
752 | asd_write_reg_byte(asd_ha, LmSEQ_LAST_LOADED_SGE(lseq), 0); | |
753 | asd_write_reg_word(asd_ha, LmSEQ_SAVE_SCBPTR(lseq), 0); | |
754 | ||
755 | /* LSEQ mode dependent, mode 1, page 0 setup. */ | |
756 | asd_write_reg_word(asd_ha, LmSEQ_Q_XMIT_HEAD(lseq), 0xFFFF); | |
757 | asd_write_reg_word(asd_ha, LmSEQ_M1_EMPTY_TRANS_CTX(lseq), 0); | |
758 | asd_write_reg_word(asd_ha, LmSEQ_INI_CONN_TAG(lseq), 0); | |
759 | asd_write_reg_byte(asd_ha, LmSEQ_FAILED_OPEN_STATUS(lseq), 0); | |
760 | asd_write_reg_byte(asd_ha, LmSEQ_XMIT_REQUEST_TYPE(lseq), 0); | |
761 | asd_write_reg_byte(asd_ha, LmSEQ_M1_RESP_STATUS(lseq), 0); | |
762 | asd_write_reg_byte(asd_ha, LmSEQ_M1_LAST_LOADED_SGE(lseq), 0); | |
763 | asd_write_reg_word(asd_ha, LmSEQ_M1_SAVE_SCBPTR(lseq), 0); | |
764 | ||
765 | /* LSEQ Mode dependent mode 2, page 0 setup */ | |
766 | asd_write_reg_word(asd_ha, LmSEQ_PORT_COUNTER(lseq), 0); | |
767 | asd_write_reg_word(asd_ha, LmSEQ_PM_TABLE_PTR(lseq), 0); | |
768 | asd_write_reg_word(asd_ha, LmSEQ_SATA_INTERLOCK_TMR_SAVE(lseq), 0); | |
769 | asd_write_reg_word(asd_ha, LmSEQ_IP_BITL(lseq), 0); | |
770 | asd_write_reg_word(asd_ha, LmSEQ_COPY_SMP_CONN_TAG(lseq), 0); | |
771 | asd_write_reg_byte(asd_ha, LmSEQ_P0M2_OFFS1AH(lseq), 0); | |
772 | ||
773 | /* LSEQ Mode dependent, mode 4/5, page 0 setup. */ | |
774 | asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_STATUS(lseq), 0); | |
775 | asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_MODE(lseq), 0); | |
776 | asd_write_reg_word(asd_ha, LmSEQ_Q_LINK_HEAD(lseq), 0xFFFF); | |
777 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_ERR(lseq), 0); | |
778 | asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_SIGNALS(lseq), 0); | |
779 | asd_write_reg_byte(asd_ha, LmSEQ_SAS_RESET_MODE(lseq), 0); | |
780 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_RESET_RETRY_COUNT(lseq), 0); | |
781 | asd_write_reg_byte(asd_ha, LmSEQ_NUM_LINK_RESET_RETRIES(lseq), 0); | |
782 | asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0); | |
783 | /* | |
784 | * Set the desired interval between transmissions of the NOTIFY | |
421f91d2 | 785 | * (ENABLE SPINUP) primitive. Must be initialized to val - 1. |
2908d778 JB |
786 | */ |
787 | asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq), | |
788 | ASD_NOTIFY_TIMEOUT - 1); | |
789 | /* No delay for the first NOTIFY to be sent to the attached target. */ | |
790 | asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq), | |
791 | ASD_NOTIFY_DOWN_COUNT); | |
083d1631 WG |
792 | asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(lseq), |
793 | ASD_NOTIFY_DOWN_COUNT); | |
2908d778 JB |
794 | |
795 | /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */ | |
796 | for (i = 0; i < 2; i++) { | |
797 | int j; | |
798 | /* Start from Page 1 of Mode 0 and 1. */ | |
799 | moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE; | |
b595076a | 800 | /* All the fields of page 1 can be initialized to 0. */ |
2908d778 JB |
801 | for (j = 0; j < LSEQ_PAGE_SIZE; j += 4) |
802 | asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0); | |
803 | } | |
804 | ||
805 | /* LSEQ Mode dependent, mode 2, page 1 setup. */ | |
806 | asd_write_reg_dword(asd_ha, LmSEQ_INVALID_DWORD_COUNT(lseq), 0); | |
807 | asd_write_reg_dword(asd_ha, LmSEQ_DISPARITY_ERROR_COUNT(lseq), 0); | |
808 | asd_write_reg_dword(asd_ha, LmSEQ_LOSS_OF_SYNC_COUNT(lseq), 0); | |
809 | ||
810 | /* LSEQ Mode dependent, mode 4/5, page 1. */ | |
811 | for (i = 0; i < LSEQ_PAGE_SIZE; i+=4) | |
812 | asd_write_reg_dword(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq)+i, 0); | |
813 | asd_write_reg_byte(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq), 0xFF); | |
814 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq), 0xFF); | |
815 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+1,0xFF); | |
816 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+2,0xFF); | |
817 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq), 0xFF); | |
818 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+1, 0xFF); | |
819 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+2, 0xFF); | |
820 | asd_write_reg_dword(asd_ha, LmSEQ_DATA_OFFSET(lseq), 0xFFFFFFFF); | |
821 | ||
822 | /* LSEQ Mode dependent, mode 0, page 2 setup. */ | |
823 | asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMER_TERM_TS(lseq), 0); | |
824 | asd_write_reg_byte(asd_ha, LmSEQ_DEVICE_BITS(lseq), 0); | |
825 | asd_write_reg_word(asd_ha, LmSEQ_SDB_DDB(lseq), 0); | |
826 | asd_write_reg_byte(asd_ha, LmSEQ_SDB_NUM_TAGS(lseq), 0); | |
827 | asd_write_reg_byte(asd_ha, LmSEQ_SDB_CURR_TAG(lseq), 0); | |
828 | ||
829 | /* LSEQ Mode Dependent 1, page 2 setup. */ | |
830 | asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq), 0); | |
831 | asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq)+4, 0); | |
832 | asd_write_reg_dword(asd_ha, LmSEQ_OPEN_TIMER_TERM_TS(lseq), 0); | |
833 | asd_write_reg_dword(asd_ha, LmSEQ_SRST_AS_TIMER_TERM_TS(lseq), 0); | |
834 | asd_write_reg_dword(asd_ha, LmSEQ_LAST_LOADED_SG_EL(lseq), 0); | |
835 | ||
836 | /* LSEQ Mode Dependent 2, page 2 setup. */ | |
837 | /* The LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS is IGNORED by the sequencer, | |
838 | * i.e. always 0. */ | |
839 | asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(lseq),0); | |
840 | asd_write_reg_dword(asd_ha, LmSEQ_CLOSE_TIMER_TERM_TS(lseq), 0); | |
841 | asd_write_reg_dword(asd_ha, LmSEQ_BREAK_TIMER_TERM_TS(lseq), 0); | |
842 | asd_write_reg_dword(asd_ha, LmSEQ_DWS_RESET_TIMER_TERM_TS(lseq), 0); | |
843 | asd_write_reg_dword(asd_ha,LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(lseq),0); | |
844 | asd_write_reg_dword(asd_ha, LmSEQ_MCTL_TIMER_TERM_TS(lseq), 0); | |
845 | ||
846 | /* LSEQ Mode Dependent 4/5, page 2 setup. */ | |
847 | asd_write_reg_dword(asd_ha, LmSEQ_COMINIT_TIMER_TERM_TS(lseq), 0); | |
848 | asd_write_reg_dword(asd_ha, LmSEQ_RCV_ID_TIMER_TERM_TS(lseq), 0); | |
849 | asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMER_TERM_TS(lseq), 0); | |
850 | asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TIMER_TERM_TS(lseq), 0); | |
851 | } | |
852 | ||
853 | /** | |
854 | * asd_init_lseq_scratch -- setup and init link sequencers | |
855 | * @asd_ha: pointer to host adapter struct | |
856 | */ | |
857 | static void asd_init_lseq_scratch(struct asd_ha_struct *asd_ha) | |
858 | { | |
859 | u8 lseq; | |
860 | u8 lseq_mask; | |
861 | ||
862 | lseq_mask = asd_ha->hw_prof.enabled_phys; | |
863 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | |
864 | asd_init_lseq_mip(asd_ha, lseq); | |
865 | asd_init_lseq_mdp(asd_ha, lseq); | |
866 | } | |
867 | } | |
868 | ||
869 | /** | |
870 | * asd_init_scb_sites -- initialize sequencer SCB sites (memory). | |
871 | * @asd_ha: pointer to host adapter structure | |
872 | * | |
873 | * This should be done before initializing common CSEQ and LSEQ | |
874 | * scratch since those areas depend on some computed values here, | |
875 | * last_scb_site_no, etc. | |
876 | */ | |
877 | static void asd_init_scb_sites(struct asd_ha_struct *asd_ha) | |
878 | { | |
879 | u16 site_no; | |
880 | u16 max_scbs = 0; | |
881 | ||
882 | for (site_no = asd_ha->hw_prof.max_scbs-1; | |
883 | site_no != (u16) -1; | |
884 | site_no--) { | |
885 | u16 i; | |
886 | ||
887 | /* Initialize all fields in the SCB site to 0. */ | |
888 | for (i = 0; i < ASD_SCB_SIZE; i += 4) | |
889 | asd_scbsite_write_dword(asd_ha, site_no, i, 0); | |
890 | ||
3b709df5 DW |
891 | /* Initialize SCB Site Opcode field to invalid. */ |
892 | asd_scbsite_write_byte(asd_ha, site_no, | |
893 | offsetof(struct scb_header, opcode), | |
894 | 0xFF); | |
895 | ||
896 | /* Initialize SCB Site Flags field to mean a response | |
897 | * frame has been received. This means inadvertent | |
898 | * frames received to be dropped. */ | |
899 | asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01); | |
900 | ||
2908d778 JB |
901 | /* Workaround needed by SEQ to fix a SATA issue is to exclude |
902 | * certain SCB sites from the free list. */ | |
903 | if (!SCB_SITE_VALID(site_no)) | |
904 | continue; | |
905 | ||
906 | if (last_scb_site_no == 0) | |
907 | last_scb_site_no = site_no; | |
908 | ||
909 | /* For every SCB site, we need to initialize the | |
910 | * following fields: Q_NEXT, SCB_OPCODE, SCB_FLAGS, | |
911 | * and SG Element Flag. */ | |
912 | ||
913 | /* Q_NEXT field of the last SCB is invalidated. */ | |
914 | asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no); | |
915 | ||
2908d778 JB |
916 | first_scb_site_no = site_no; |
917 | max_scbs++; | |
918 | } | |
919 | asd_ha->hw_prof.max_scbs = max_scbs; | |
920 | ASD_DPRINTK("max_scbs:%d\n", asd_ha->hw_prof.max_scbs); | |
921 | ASD_DPRINTK("first_scb_site_no:0x%x\n", first_scb_site_no); | |
922 | ASD_DPRINTK("last_scb_site_no:0x%x\n", last_scb_site_no); | |
923 | } | |
924 | ||
925 | /** | |
926 | * asd_init_cseq_cio - initialize CSEQ CIO registers | |
927 | * @asd_ha: pointer to host adapter structure | |
928 | */ | |
929 | static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha) | |
930 | { | |
931 | int i; | |
932 | ||
933 | asd_write_reg_byte(asd_ha, CSEQCOMINTEN, 0); | |
934 | asd_write_reg_byte(asd_ha, CSEQDLCTL, ASD_DL_SIZE_BITS); | |
935 | asd_write_reg_byte(asd_ha, CSEQDLOFFS, 0); | |
936 | asd_write_reg_byte(asd_ha, CSEQDLOFFS+1, 0); | |
937 | asd_ha->seq.scbpro = 0; | |
938 | asd_write_reg_dword(asd_ha, SCBPRO, 0); | |
939 | asd_write_reg_dword(asd_ha, CSEQCON, 0); | |
940 | ||
b595076a | 941 | /* Initialize CSEQ Mode 11 Interrupt Vectors. |
2908d778 JB |
942 | * The addresses are 16 bit wide and in dword units. |
943 | * The values of their macros are in byte units. | |
944 | * Thus we have to divide by 4. */ | |
945 | asd_write_reg_word(asd_ha, CM11INTVEC0, cseq_vecs[0]); | |
946 | asd_write_reg_word(asd_ha, CM11INTVEC1, cseq_vecs[1]); | |
947 | asd_write_reg_word(asd_ha, CM11INTVEC2, cseq_vecs[2]); | |
948 | ||
949 | /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ | |
950 | asd_write_reg_byte(asd_ha, CARP2INTEN, EN_ARP2HALTC); | |
951 | ||
952 | /* Initialize CSEQ Scratch Page to 0x04. */ | |
953 | asd_write_reg_byte(asd_ha, CSCRATCHPAGE, 0x04); | |
954 | ||
955 | /* Initialize CSEQ Mode[0-8] Dependent registers. */ | |
956 | /* Initialize Scratch Page to 0. */ | |
957 | for (i = 0; i < 9; i++) | |
958 | asd_write_reg_byte(asd_ha, CMnSCRATCHPAGE(i), 0); | |
959 | ||
960 | /* Reset the ARP2 Program Count. */ | |
961 | asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); | |
962 | ||
963 | for (i = 0; i < 8; i++) { | |
b595076a | 964 | /* Initialize Mode n Link m Interrupt Enable. */ |
2908d778 JB |
965 | asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF); |
966 | /* Initialize Mode n Request Mailbox. */ | |
967 | asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0); | |
968 | } | |
969 | } | |
970 | ||
971 | /** | |
972 | * asd_init_lseq_cio -- initialize LmSEQ CIO registers | |
973 | * @asd_ha: pointer to host adapter structure | |
974 | */ | |
975 | static void asd_init_lseq_cio(struct asd_ha_struct *asd_ha, int lseq) | |
976 | { | |
977 | u8 *sas_addr; | |
978 | int i; | |
979 | ||
980 | /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ | |
981 | asd_write_reg_dword(asd_ha, LmARP2INTEN(lseq), EN_ARP2HALTC); | |
982 | ||
983 | asd_write_reg_byte(asd_ha, LmSCRATCHPAGE(lseq), 0); | |
984 | ||
985 | /* Initialize Mode 0,1, and 2 SCRATCHPAGE to 0. */ | |
986 | for (i = 0; i < 3; i++) | |
987 | asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, i), 0); | |
988 | ||
989 | /* Initialize Mode 5 SCRATCHPAGE to 0. */ | |
990 | asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, 5), 0); | |
991 | ||
992 | asd_write_reg_dword(asd_ha, LmRSPMBX(lseq), 0); | |
993 | /* Initialize Mode 0,1,2 and 5 Interrupt Enable and | |
994 | * Interrupt registers. */ | |
995 | asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 0), LmM0INTEN_MASK); | |
996 | asd_write_reg_dword(asd_ha, LmMnINT(lseq, 0), 0xFFFFFFFF); | |
997 | /* Mode 1 */ | |
998 | asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 1), LmM1INTEN_MASK); | |
999 | asd_write_reg_dword(asd_ha, LmMnINT(lseq, 1), 0xFFFFFFFF); | |
1000 | /* Mode 2 */ | |
1001 | asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 2), LmM2INTEN_MASK); | |
1002 | asd_write_reg_dword(asd_ha, LmMnINT(lseq, 2), 0xFFFFFFFF); | |
1003 | /* Mode 5 */ | |
1004 | asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 5), LmM5INTEN_MASK); | |
1005 | asd_write_reg_dword(asd_ha, LmMnINT(lseq, 5), 0xFFFFFFFF); | |
1006 | ||
1007 | /* Enable HW Timer status. */ | |
1008 | asd_write_reg_byte(asd_ha, LmHWTSTATEN(lseq), LmHWTSTATEN_MASK); | |
1009 | ||
1010 | /* Enable Primitive Status 0 and 1. */ | |
1011 | asd_write_reg_dword(asd_ha, LmPRIMSTAT0EN(lseq), LmPRIMSTAT0EN_MASK); | |
1012 | asd_write_reg_dword(asd_ha, LmPRIMSTAT1EN(lseq), LmPRIMSTAT1EN_MASK); | |
1013 | ||
1014 | /* Enable Frame Error. */ | |
1015 | asd_write_reg_dword(asd_ha, LmFRMERREN(lseq), LmFRMERREN_MASK); | |
1016 | asd_write_reg_byte(asd_ha, LmMnHOLDLVL(lseq, 0), 0x50); | |
1017 | ||
1018 | /* Initialize Mode 0 Transfer Level to 512. */ | |
1019 | asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 0), LmMnXFRLVL_512); | |
1020 | /* Initialize Mode 1 Transfer Level to 256. */ | |
1021 | asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 1), LmMnXFRLVL_256); | |
1022 | ||
1023 | /* Initialize Program Count. */ | |
1024 | asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); | |
1025 | ||
1026 | /* Enable Blind SG Move. */ | |
1027 | asd_write_reg_dword(asd_ha, LmMODECTL(lseq), LmBLIND48); | |
1028 | asd_write_reg_word(asd_ha, LmM3SATATIMER(lseq), | |
1029 | ASD_SATA_INTERLOCK_TIMEOUT); | |
1030 | ||
1031 | (void) asd_read_reg_dword(asd_ha, LmREQMBX(lseq)); | |
1032 | ||
1033 | /* Clear Primitive Status 0 and 1. */ | |
1034 | asd_write_reg_dword(asd_ha, LmPRMSTAT0(lseq), 0xFFFFFFFF); | |
1035 | asd_write_reg_dword(asd_ha, LmPRMSTAT1(lseq), 0xFFFFFFFF); | |
1036 | ||
1037 | /* Clear HW Timer status. */ | |
1038 | asd_write_reg_byte(asd_ha, LmHWTSTAT(lseq), 0xFF); | |
1039 | ||
1040 | /* Clear DMA Errors for Mode 0 and 1. */ | |
1041 | asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 0), 0xFF); | |
1042 | asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 1), 0xFF); | |
1043 | ||
1044 | /* Clear SG DMA Errors for Mode 0 and 1. */ | |
1045 | asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 0), 0xFF); | |
1046 | asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 1), 0xFF); | |
1047 | ||
1048 | /* Clear Mode 0 Buffer Parity Error. */ | |
1049 | asd_write_reg_byte(asd_ha, LmMnBUFSTAT(lseq, 0), LmMnBUFPERR); | |
1050 | ||
1051 | /* Clear Mode 0 Frame Error register. */ | |
1052 | asd_write_reg_dword(asd_ha, LmMnFRMERR(lseq, 0), 0xFFFFFFFF); | |
1053 | ||
1054 | /* Reset LSEQ external interrupt arbiter. */ | |
1055 | asd_write_reg_byte(asd_ha, LmARP2INTCTL(lseq), RSTINTCTL); | |
1056 | ||
1057 | /* Set the Phy SAS for the LmSEQ WWN. */ | |
1058 | sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr; | |
1059 | for (i = 0; i < SAS_ADDR_SIZE; i++) | |
1060 | asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]); | |
1061 | ||
1062 | /* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */ | |
1063 | asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0); | |
1064 | ||
1065 | /* Set the Bus Inactivity Time Limit Timer. */ | |
1066 | asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9); | |
1067 | ||
1068 | /* Enable SATA Port Multiplier. */ | |
1069 | asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80); | |
1070 | ||
1071 | /* Initialize Interrupt Vector[0-10] address in Mode 3. | |
1072 | * See the comment on CSEQ_INT_* */ | |
1073 | asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), lseq_vecs[0]); | |
1074 | asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), lseq_vecs[1]); | |
1075 | asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), lseq_vecs[2]); | |
1076 | asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), lseq_vecs[3]); | |
1077 | asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), lseq_vecs[4]); | |
1078 | asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), lseq_vecs[5]); | |
1079 | asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), lseq_vecs[6]); | |
1080 | asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), lseq_vecs[7]); | |
1081 | asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), lseq_vecs[8]); | |
1082 | asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), lseq_vecs[9]); | |
1083 | asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), lseq_vecs[10]); | |
1084 | /* | |
1085 | * Program the Link LED control, applicable only for | |
1086 | * Chip Rev. B or later. | |
1087 | */ | |
1088 | asd_write_reg_dword(asd_ha, LmCONTROL(lseq), | |
1089 | (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms)); | |
1090 | ||
1091 | /* Set the Align Rate for SAS and STP mode. */ | |
1092 | asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT); | |
1093 | asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT); | |
1094 | } | |
1095 | ||
1096 | ||
1097 | /** | |
1098 | * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox | |
1099 | * @asd_ha: pointer to host adapter struct | |
1100 | */ | |
1101 | static void asd_post_init_cseq(struct asd_ha_struct *asd_ha) | |
1102 | { | |
1103 | int i; | |
1104 | ||
1105 | for (i = 0; i < 8; i++) | |
1106 | asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF); | |
1107 | for (i = 0; i < 8; i++) | |
1108 | asd_read_reg_dword(asd_ha, CMnRSPMBX(i)); | |
1109 | /* Reset the external interrupt arbiter. */ | |
1110 | asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL); | |
1111 | } | |
1112 | ||
1113 | /** | |
1114 | * asd_init_ddb_0 -- initialize DDB 0 | |
1115 | * @asd_ha: pointer to host adapter structure | |
1116 | * | |
1117 | * Initialize DDB site 0 which is used internally by the sequencer. | |
1118 | */ | |
1119 | static void asd_init_ddb_0(struct asd_ha_struct *asd_ha) | |
1120 | { | |
1121 | int i; | |
1122 | ||
1123 | /* Zero out the DDB explicitly */ | |
1124 | for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4) | |
1125 | asd_ddbsite_write_dword(asd_ha, 0, i, 0); | |
1126 | ||
1127 | asd_ddbsite_write_word(asd_ha, 0, | |
1128 | offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0); | |
1129 | asd_ddbsite_write_word(asd_ha, 0, | |
1130 | offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail), | |
1131 | asd_ha->hw_prof.max_ddbs-1); | |
1132 | asd_ddbsite_write_word(asd_ha, 0, | |
1133 | offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0); | |
1134 | asd_ddbsite_write_word(asd_ha, 0, | |
1135 | offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF); | |
1136 | asd_ddbsite_write_word(asd_ha, 0, | |
1137 | offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF); | |
1138 | asd_ddbsite_write_word(asd_ha, 0, | |
1139 | offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0); | |
1140 | asd_ddbsite_write_word(asd_ha, 0, | |
1141 | offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0); | |
1142 | asd_ddbsite_write_word(asd_ha, 0, | |
1143 | offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0); | |
1144 | asd_ddbsite_write_word(asd_ha, 0, | |
1145 | offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh), | |
1146 | asd_ha->hw_prof.num_phys * 2); | |
1147 | asd_ddbsite_write_byte(asd_ha, 0, | |
1148 | offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0); | |
1149 | asd_ddbsite_write_byte(asd_ha, 0, | |
1150 | offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF); | |
1151 | asd_ddbsite_write_byte(asd_ha, 0, | |
1152 | offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00); | |
1153 | /* DDB 0 is reserved */ | |
1154 | set_bit(0, asd_ha->hw_prof.ddb_bitmap); | |
1155 | } | |
1156 | ||
3b709df5 DW |
1157 | static void asd_seq_init_ddb_sites(struct asd_ha_struct *asd_ha) |
1158 | { | |
1159 | unsigned int i; | |
1160 | unsigned int ddb_site; | |
1161 | ||
1162 | for (ddb_site = 0 ; ddb_site < ASD_MAX_DDBS; ddb_site++) | |
1163 | for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) | |
1164 | asd_ddbsite_write_dword(asd_ha, ddb_site, i, 0); | |
1165 | } | |
1166 | ||
2908d778 JB |
1167 | /** |
1168 | * asd_seq_setup_seqs -- setup and initialize central and link sequencers | |
1169 | * @asd_ha: pointer to host adapter structure | |
1170 | */ | |
1171 | static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha) | |
1172 | { | |
1173 | int lseq; | |
1174 | u8 lseq_mask; | |
1175 | ||
3b709df5 DW |
1176 | /* Initialize DDB sites */ |
1177 | asd_seq_init_ddb_sites(asd_ha); | |
1178 | ||
2908d778 JB |
1179 | /* Initialize SCB sites. Done first to compute some values which |
1180 | * the rest of the init code depends on. */ | |
1181 | asd_init_scb_sites(asd_ha); | |
1182 | ||
1183 | /* Initialize CSEQ Scratch RAM registers. */ | |
1184 | asd_init_cseq_scratch(asd_ha); | |
1185 | ||
1186 | /* Initialize LmSEQ Scratch RAM registers. */ | |
1187 | asd_init_lseq_scratch(asd_ha); | |
1188 | ||
1189 | /* Initialize CSEQ CIO registers. */ | |
1190 | asd_init_cseq_cio(asd_ha); | |
1191 | ||
1192 | asd_init_ddb_0(asd_ha); | |
1193 | ||
1194 | /* Initialize LmSEQ CIO registers. */ | |
1195 | lseq_mask = asd_ha->hw_prof.enabled_phys; | |
1196 | for_each_sequencer(lseq_mask, lseq_mask, lseq) | |
1197 | asd_init_lseq_cio(asd_ha, lseq); | |
1198 | asd_post_init_cseq(asd_ha); | |
1199 | } | |
1200 | ||
1201 | ||
1202 | /** | |
1203 | * asd_seq_start_cseq -- start the central sequencer, CSEQ | |
1204 | * @asd_ha: pointer to host adapter structure | |
1205 | */ | |
1206 | static int asd_seq_start_cseq(struct asd_ha_struct *asd_ha) | |
1207 | { | |
1208 | /* Reset the ARP2 instruction to location zero. */ | |
1209 | asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); | |
1210 | ||
1211 | /* Unpause the CSEQ */ | |
1212 | return asd_unpause_cseq(asd_ha); | |
1213 | } | |
1214 | ||
1215 | /** | |
1216 | * asd_seq_start_lseq -- start a link sequencer | |
1217 | * @asd_ha: pointer to host adapter structure | |
1218 | * @lseq: the link sequencer of interest | |
1219 | */ | |
1220 | static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq) | |
1221 | { | |
1222 | /* Reset the ARP2 instruction to location zero. */ | |
1223 | asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); | |
1224 | ||
1225 | /* Unpause the LmSEQ */ | |
1226 | return asd_seq_unpause_lseq(asd_ha, lseq); | |
1227 | } | |
1228 | ||
bf2a1928 DW |
1229 | int asd_release_firmware(void) |
1230 | { | |
ee51f443 | 1231 | release_firmware(sequencer_fw); |
bf2a1928 DW |
1232 | return 0; |
1233 | } | |
1234 | ||
2908d778 JB |
1235 | static int asd_request_firmware(struct asd_ha_struct *asd_ha) |
1236 | { | |
1237 | int err, i; | |
0bc202e0 DW |
1238 | struct sequencer_file_header header; |
1239 | const struct sequencer_file_header *hdr_ptr; | |
2908d778 JB |
1240 | u32 csum = 0; |
1241 | u16 *ptr_cseq_vecs, *ptr_lseq_vecs; | |
1242 | ||
1243 | if (sequencer_fw) | |
1244 | /* already loaded */ | |
1245 | return 0; | |
1246 | ||
1247 | err = request_firmware(&sequencer_fw, | |
1248 | SAS_RAZOR_SEQUENCER_FW_FILE, | |
1249 | &asd_ha->pcidev->dev); | |
1250 | if (err) | |
1251 | return err; | |
1252 | ||
0bc202e0 | 1253 | hdr_ptr = (const struct sequencer_file_header *)sequencer_fw->data; |
2908d778 JB |
1254 | |
1255 | header.csum = le32_to_cpu(hdr_ptr->csum); | |
1256 | header.major = le32_to_cpu(hdr_ptr->major); | |
1257 | header.minor = le32_to_cpu(hdr_ptr->minor); | |
2908d778 JB |
1258 | header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset); |
1259 | header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size); | |
1260 | header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset); | |
1261 | header.lseq_table_size = le32_to_cpu(hdr_ptr->lseq_table_size); | |
1262 | header.cseq_code_offset = le32_to_cpu(hdr_ptr->cseq_code_offset); | |
1263 | header.cseq_code_size = le32_to_cpu(hdr_ptr->cseq_code_size); | |
1264 | header.lseq_code_offset = le32_to_cpu(hdr_ptr->lseq_code_offset); | |
1265 | header.lseq_code_size = le32_to_cpu(hdr_ptr->lseq_code_size); | |
1266 | header.mode2_task = le16_to_cpu(hdr_ptr->mode2_task); | |
1267 | header.cseq_idle_loop = le16_to_cpu(hdr_ptr->cseq_idle_loop); | |
1268 | header.lseq_idle_loop = le16_to_cpu(hdr_ptr->lseq_idle_loop); | |
1269 | ||
1270 | for (i = sizeof(header.csum); i < sequencer_fw->size; i++) | |
1271 | csum += sequencer_fw->data[i]; | |
1272 | ||
1273 | if (csum != header.csum) { | |
1274 | asd_printk("Firmware file checksum mismatch\n"); | |
1275 | return -EINVAL; | |
1276 | } | |
1277 | ||
1278 | if (header.cseq_table_size != CSEQ_NUM_VECS || | |
1279 | header.lseq_table_size != LSEQ_NUM_VECS) { | |
1280 | asd_printk("Firmware file table size mismatch\n"); | |
1281 | return -EINVAL; | |
1282 | } | |
1283 | ||
a29fdd3c JB |
1284 | asd_printk("Found sequencer Firmware version %d.%d (%s)\n", |
1285 | header.major, header.minor, hdr_ptr->version); | |
1286 | ||
1287 | if (header.major != SAS_RAZOR_SEQUENCER_FW_MAJOR) { | |
1288 | asd_printk("Firmware Major Version Mismatch;" | |
1289 | "driver requires version %d.X", | |
1290 | SAS_RAZOR_SEQUENCER_FW_MAJOR); | |
1291 | return -EINVAL; | |
1292 | } | |
1293 | ||
2908d778 JB |
1294 | ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset]; |
1295 | ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset]; | |
1296 | mode2_task = header.mode2_task; | |
1297 | cseq_idle_loop = header.cseq_idle_loop; | |
1298 | lseq_idle_loop = header.lseq_idle_loop; | |
1299 | ||
1300 | for (i = 0; i < CSEQ_NUM_VECS; i++) | |
1301 | cseq_vecs[i] = le16_to_cpu(ptr_cseq_vecs[i]); | |
1302 | ||
1303 | for (i = 0; i < LSEQ_NUM_VECS; i++) | |
1304 | lseq_vecs[i] = le16_to_cpu(ptr_lseq_vecs[i]); | |
1305 | ||
1306 | cseq_code = &sequencer_fw->data[header.cseq_code_offset]; | |
1307 | cseq_code_size = header.cseq_code_size; | |
1308 | lseq_code = &sequencer_fw->data[header.lseq_code_offset]; | |
1309 | lseq_code_size = header.lseq_code_size; | |
1310 | ||
1311 | return 0; | |
1312 | } | |
1313 | ||
1314 | int asd_init_seqs(struct asd_ha_struct *asd_ha) | |
1315 | { | |
1316 | int err; | |
1317 | ||
1318 | err = asd_request_firmware(asd_ha); | |
1319 | ||
1320 | if (err) { | |
1321 | asd_printk("Failed to load sequencer firmware file %s, error %d\n", | |
1322 | SAS_RAZOR_SEQUENCER_FW_FILE, err); | |
1323 | return err; | |
1324 | } | |
1325 | ||
2908d778 JB |
1326 | err = asd_seq_download_seqs(asd_ha); |
1327 | if (err) { | |
1328 | asd_printk("couldn't download sequencers for %s\n", | |
1329 | pci_name(asd_ha->pcidev)); | |
1330 | return err; | |
1331 | } | |
1332 | ||
1333 | asd_seq_setup_seqs(asd_ha); | |
1334 | ||
1335 | return 0; | |
1336 | } | |
1337 | ||
1338 | int asd_start_seqs(struct asd_ha_struct *asd_ha) | |
1339 | { | |
1340 | int err; | |
1341 | u8 lseq_mask; | |
1342 | int lseq; | |
1343 | ||
1344 | err = asd_seq_start_cseq(asd_ha); | |
1345 | if (err) { | |
1346 | asd_printk("couldn't start CSEQ for %s\n", | |
1347 | pci_name(asd_ha->pcidev)); | |
1348 | return err; | |
1349 | } | |
1350 | ||
1351 | lseq_mask = asd_ha->hw_prof.enabled_phys; | |
1352 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | |
1353 | err = asd_seq_start_lseq(asd_ha, lseq); | |
1354 | if (err) { | |
c19ca6cb | 1355 | asd_printk("couldn't start LSEQ %d for %s\n", lseq, |
2908d778 JB |
1356 | pci_name(asd_ha->pcidev)); |
1357 | return err; | |
1358 | } | |
1359 | } | |
1360 | ||
1361 | return 0; | |
1362 | } | |
1363 | ||
1364 | /** | |
1365 | * asd_update_port_links -- update port_map_by_links and phy_is_up | |
1366 | * @sas_phy: pointer to the phy which has been added to a port | |
1367 | * | |
1368 | * 1) When a link reset has completed and we got BYTES DMAED with a | |
1369 | * valid frame we call this function for that phy, to indicate that | |
1370 | * the phy is up, i.e. we update the phy_is_up in DDB 0. The | |
1371 | * sequencer checks phy_is_up when pending SCBs are to be sent, and | |
1372 | * when an open address frame has been received. | |
1373 | * | |
1374 | * 2) When we know of ports, we call this function to update the map | |
1375 | * of phys participaing in that port, i.e. we update the | |
1376 | * port_map_by_links in DDB 0. When a HARD_RESET primitive has been | |
1377 | * received, the sequencer disables all phys in that port. | |
1378 | * port_map_by_links is also used as the conn_mask byte in the | |
1379 | * initiator/target port DDB. | |
1380 | */ | |
3f048109 | 1381 | void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy) |
2908d778 | 1382 | { |
3f048109 | 1383 | const u8 phy_mask = (u8) phy->asd_port->phy_mask; |
2908d778 JB |
1384 | u8 phy_is_up; |
1385 | u8 mask; | |
1386 | int i, err; | |
57ba07dc | 1387 | unsigned long flags; |
2908d778 | 1388 | |
57ba07dc | 1389 | spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); |
2908d778 JB |
1390 | for_each_phy(phy_mask, mask, i) |
1391 | asd_ddbsite_write_byte(asd_ha, 0, | |
1392 | offsetof(struct asd_ddb_seq_shared, | |
1393 | port_map_by_links)+i,phy_mask); | |
1394 | ||
1395 | for (i = 0; i < 12; i++) { | |
1396 | phy_is_up = asd_ddbsite_read_byte(asd_ha, 0, | |
1397 | offsetof(struct asd_ddb_seq_shared, phy_is_up)); | |
1398 | err = asd_ddbsite_update_byte(asd_ha, 0, | |
1399 | offsetof(struct asd_ddb_seq_shared, phy_is_up), | |
1400 | phy_is_up, | |
1401 | phy_is_up | phy_mask); | |
1402 | if (!err) | |
1403 | break; | |
1404 | else if (err == -EFAULT) { | |
1405 | asd_printk("phy_is_up: parity error in DDB 0\n"); | |
1406 | break; | |
1407 | } | |
1408 | } | |
57ba07dc | 1409 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); |
2908d778 JB |
1410 | |
1411 | if (err) | |
1412 | asd_printk("couldn't update DDB 0:error:%d\n", err); | |
1413 | } | |
bc229b36 JB |
1414 | |
1415 | MODULE_FIRMWARE(SAS_RAZOR_SEQUENCER_FW_FILE); |