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