1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family |
4 | * of PCI-SCSI IO processors. |
5 | * |
6 | * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> |
7 | * |
8 | * This driver is derived from the Linux sym53c8xx driver. |
9 | * Copyright (C) 1998-2000 Gerard Roudier |
10 | * |
11 | * The sym53c8xx driver is derived from the ncr53c8xx driver that had been |
12 | * a port of the FreeBSD ncr driver to Linux-1.2.13. |
13 | * |
14 | * The original ncr driver has been written for 386bsd and FreeBSD by |
15 | * Wolfgang Stanglmeier <wolf@cologne.de> |
16 | * Stefan Esser <se@mi.Uni-Koeln.de> |
17 | * Copyright (C) 1994 Wolfgang Stanglmeier |
18 | * |
19 | * Other major contributions: |
20 | * |
21 | * NVRAM detection and reading. |
22 | * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> |
23 | * |
24 | *----------------------------------------------------------------------------- |
25 | */ |
26 | |
27 | #include "sym_glue.h" |
28 | |
29 | /* |
30 | * Macros used for all firmwares. |
31 | */ |
32 | #define SYM_GEN_A(s, label) ((short) offsetof(s, label)), |
33 | #define SYM_GEN_B(s, label) ((short) offsetof(s, label)), |
34 | #define SYM_GEN_Z(s, label) ((short) offsetof(s, label)), |
35 | #define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label) |
36 | #define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label) |
37 | |
38 | |
39 | #if SYM_CONF_GENERIC_SUPPORT |
40 | /* |
41 | * Allocate firmware #1 script area. |
42 | */ |
43 | #define SYM_FWA_SCR sym_fw1a_scr |
44 | #define SYM_FWB_SCR sym_fw1b_scr |
45 | #define SYM_FWZ_SCR sym_fw1z_scr |
46 | #include "sym_fw1.h" |
47 | static struct sym_fwa_ofs sym_fw1a_ofs = { |
48 | SYM_GEN_FW_A(struct SYM_FWA_SCR) |
49 | }; |
50 | static struct sym_fwb_ofs sym_fw1b_ofs = { |
51 | SYM_GEN_FW_B(struct SYM_FWB_SCR) |
52 | }; |
53 | static struct sym_fwz_ofs sym_fw1z_ofs = { |
54 | SYM_GEN_FW_Z(struct SYM_FWZ_SCR) |
55 | }; |
56 | #undef SYM_FWA_SCR |
57 | #undef SYM_FWB_SCR |
58 | #undef SYM_FWZ_SCR |
59 | #endif /* SYM_CONF_GENERIC_SUPPORT */ |
60 | |
61 | /* |
62 | * Allocate firmware #2 script area. |
63 | */ |
64 | #define SYM_FWA_SCR sym_fw2a_scr |
65 | #define SYM_FWB_SCR sym_fw2b_scr |
66 | #define SYM_FWZ_SCR sym_fw2z_scr |
67 | #include "sym_fw2.h" |
68 | static struct sym_fwa_ofs sym_fw2a_ofs = { |
69 | SYM_GEN_FW_A(struct SYM_FWA_SCR) |
70 | }; |
71 | static struct sym_fwb_ofs sym_fw2b_ofs = { |
72 | SYM_GEN_FW_B(struct SYM_FWB_SCR) |
73 | SYM_GEN_B(struct SYM_FWB_SCR, start64) |
74 | SYM_GEN_B(struct SYM_FWB_SCR, pm_handle) |
75 | }; |
76 | static struct sym_fwz_ofs sym_fw2z_ofs = { |
77 | SYM_GEN_FW_Z(struct SYM_FWZ_SCR) |
78 | }; |
79 | #undef SYM_FWA_SCR |
80 | #undef SYM_FWB_SCR |
81 | #undef SYM_FWZ_SCR |
82 | |
83 | #undef SYM_GEN_A |
84 | #undef SYM_GEN_B |
85 | #undef SYM_GEN_Z |
86 | #undef PADDR_A |
87 | #undef PADDR_B |
88 | |
89 | #if SYM_CONF_GENERIC_SUPPORT |
90 | /* |
91 | * Patch routine for firmware #1. |
92 | */ |
93 | static void |
94 | sym_fw1_patch(struct Scsi_Host *shost) |
95 | { |
96 | struct sym_hcb *np = sym_get_hcb(host: shost); |
97 | struct sym_fw1a_scr *scripta0; |
98 | struct sym_fw1b_scr *scriptb0; |
99 | |
100 | scripta0 = (struct sym_fw1a_scr *) np->scripta0; |
101 | scriptb0 = (struct sym_fw1b_scr *) np->scriptb0; |
102 | |
103 | /* |
104 | * Remove LED support if not needed. |
105 | */ |
106 | if (!(np->features & FE_LED0)) { |
107 | scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); |
108 | scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); |
109 | scripta0->start[0] = cpu_to_scr(SCR_NO_OP); |
110 | } |
111 | |
112 | #ifdef SYM_CONF_IARB_SUPPORT |
113 | /* |
114 | * If user does not want to use IMMEDIATE ARBITRATION |
115 | * when we are reselected while attempting to arbitrate, |
116 | * patch the SCRIPTS accordingly with a SCRIPT NO_OP. |
117 | */ |
118 | if (!SYM_CONF_SET_IARB_ON_ARB_LOST) |
119 | scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); |
120 | #endif |
121 | /* |
122 | * Patch some data in SCRIPTS. |
123 | * - start and done queue initial bus address. |
124 | * - target bus address table bus address. |
125 | */ |
126 | scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); |
127 | scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); |
128 | scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); |
129 | } |
130 | #endif /* SYM_CONF_GENERIC_SUPPORT */ |
131 | |
132 | /* |
133 | * Patch routine for firmware #2. |
134 | */ |
135 | static void |
136 | sym_fw2_patch(struct Scsi_Host *shost) |
137 | { |
138 | struct sym_data *sym_data = shost_priv(shost); |
139 | struct pci_dev *pdev = sym_data->pdev; |
140 | struct sym_hcb *np = sym_data->ncb; |
141 | struct sym_fw2a_scr *scripta0; |
142 | struct sym_fw2b_scr *scriptb0; |
143 | |
144 | scripta0 = (struct sym_fw2a_scr *) np->scripta0; |
145 | scriptb0 = (struct sym_fw2b_scr *) np->scriptb0; |
146 | |
147 | /* |
148 | * Remove LED support if not needed. |
149 | */ |
150 | if (!(np->features & FE_LED0)) { |
151 | scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); |
152 | scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); |
153 | scripta0->start[0] = cpu_to_scr(SCR_NO_OP); |
154 | } |
155 | |
156 | #if SYM_CONF_DMA_ADDRESSING_MODE == 2 |
157 | /* |
158 | * Remove useless 64 bit DMA specific SCRIPTS, |
159 | * when this feature is not available. |
160 | */ |
161 | if (!use_dac(np)) { |
162 | scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP); |
163 | scripta0->is_dmap_dirty[1] = 0; |
164 | scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP); |
165 | scripta0->is_dmap_dirty[3] = 0; |
166 | } |
167 | #endif |
168 | |
169 | #ifdef SYM_CONF_IARB_SUPPORT |
170 | /* |
171 | * If user does not want to use IMMEDIATE ARBITRATION |
172 | * when we are reselected while attempting to arbitrate, |
173 | * patch the SCRIPTS accordingly with a SCRIPT NO_OP. |
174 | */ |
175 | if (!SYM_CONF_SET_IARB_ON_ARB_LOST) |
176 | scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); |
177 | #endif |
178 | /* |
179 | * Patch some variable in SCRIPTS. |
180 | * - start and done queue initial bus address. |
181 | * - target bus address table bus address. |
182 | */ |
183 | scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); |
184 | scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); |
185 | scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); |
186 | |
187 | /* |
188 | * Remove the load of SCNTL4 on reselection if not a C10. |
189 | */ |
190 | if (!(np->features & FE_C10)) { |
191 | scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP); |
192 | scripta0->resel_scntl4[1] = cpu_to_scr(0); |
193 | } |
194 | |
195 | /* |
196 | * Remove a couple of work-arounds specific to C1010 if |
197 | * they are not desirable. See `sym_fw2.h' for more details. |
198 | */ |
199 | if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 && |
200 | pdev->revision < 0x1 && |
201 | np->pciclk_khz < 60000)) { |
202 | scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP); |
203 | scripta0->datao_phase[1] = cpu_to_scr(0); |
204 | } |
205 | if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* && |
206 | pdev->revision < 0xff */)) { |
207 | scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP); |
208 | scripta0->sel_done[1] = cpu_to_scr(0); |
209 | } |
210 | |
211 | /* |
212 | * Patch some other variables in SCRIPTS. |
213 | * These ones are loaded by the SCRIPTS processor. |
214 | */ |
215 | scriptb0->pm0_data_addr[0] = |
216 | cpu_to_scr(np->scripta_ba + |
217 | offsetof(struct sym_fw2a_scr, pm0_data)); |
218 | scriptb0->pm1_data_addr[0] = |
219 | cpu_to_scr(np->scripta_ba + |
220 | offsetof(struct sym_fw2a_scr, pm1_data)); |
221 | } |
222 | |
223 | /* |
224 | * Fill the data area in scripts. |
225 | * To be done for all firmwares. |
226 | */ |
227 | static void |
228 | sym_fw_fill_data (u32 *in, u32 *out) |
229 | { |
230 | int i; |
231 | |
232 | for (i = 0; i < SYM_CONF_MAX_SG; i++) { |
233 | *in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN; |
234 | *in++ = offsetof (struct sym_dsb, data[i]); |
235 | *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT; |
236 | *out++ = offsetof (struct sym_dsb, data[i]); |
237 | } |
238 | } |
239 | |
240 | /* |
241 | * Setup useful script bus addresses. |
242 | * To be done for all firmwares. |
243 | */ |
244 | static void |
245 | sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw) |
246 | { |
247 | u32 *pa; |
248 | u_short *po; |
249 | int i; |
250 | |
251 | /* |
252 | * Build the bus address table for script A |
253 | * from the script A offset table. |
254 | */ |
255 | po = (u_short *) fw->a_ofs; |
256 | pa = (u32 *) &np->fwa_bas; |
257 | for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++) |
258 | pa[i] = np->scripta_ba + po[i]; |
259 | |
260 | /* |
261 | * Same for script B. |
262 | */ |
263 | po = (u_short *) fw->b_ofs; |
264 | pa = (u32 *) &np->fwb_bas; |
265 | for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++) |
266 | pa[i] = np->scriptb_ba + po[i]; |
267 | |
268 | /* |
269 | * Same for script Z. |
270 | */ |
271 | po = (u_short *) fw->z_ofs; |
272 | pa = (u32 *) &np->fwz_bas; |
273 | for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++) |
274 | pa[i] = np->scriptz_ba + po[i]; |
275 | } |
276 | |
277 | #if SYM_CONF_GENERIC_SUPPORT |
278 | /* |
279 | * Setup routine for firmware #1. |
280 | */ |
281 | static void |
282 | sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw) |
283 | { |
284 | struct sym_fw1a_scr *scripta0; |
285 | |
286 | scripta0 = (struct sym_fw1a_scr *) np->scripta0; |
287 | |
288 | /* |
289 | * Fill variable parts in scripts. |
290 | */ |
291 | sym_fw_fill_data(in: scripta0->data_in, out: scripta0->data_out); |
292 | |
293 | /* |
294 | * Setup bus addresses used from the C code.. |
295 | */ |
296 | sym_fw_setup_bus_addresses(np, fw); |
297 | } |
298 | #endif /* SYM_CONF_GENERIC_SUPPORT */ |
299 | |
300 | /* |
301 | * Setup routine for firmware #2. |
302 | */ |
303 | static void |
304 | sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw) |
305 | { |
306 | struct sym_fw2a_scr *scripta0; |
307 | |
308 | scripta0 = (struct sym_fw2a_scr *) np->scripta0; |
309 | |
310 | /* |
311 | * Fill variable parts in scripts. |
312 | */ |
313 | sym_fw_fill_data(in: scripta0->data_in, out: scripta0->data_out); |
314 | |
315 | /* |
316 | * Setup bus addresses used from the C code.. |
317 | */ |
318 | sym_fw_setup_bus_addresses(np, fw); |
319 | } |
320 | |
321 | /* |
322 | * Allocate firmware descriptors. |
323 | */ |
324 | #if SYM_CONF_GENERIC_SUPPORT |
325 | static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic" ); |
326 | #endif /* SYM_CONF_GENERIC_SUPPORT */ |
327 | static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based" ); |
328 | |
329 | /* |
330 | * Find the most appropriate firmware for a chip. |
331 | */ |
332 | struct sym_fw * |
333 | sym_find_firmware(struct sym_chip *chip) |
334 | { |
335 | if (chip->features & FE_LDSTR) |
336 | return &sym_fw2; |
337 | #if SYM_CONF_GENERIC_SUPPORT |
338 | else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC))) |
339 | return &sym_fw1; |
340 | #endif |
341 | else |
342 | return NULL; |
343 | } |
344 | |
345 | /* |
346 | * Bind a script to physical addresses. |
347 | */ |
348 | void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len) |
349 | { |
350 | u32 opcode, new, old, tmp1, tmp2; |
351 | u32 *end, *cur; |
352 | int relocs; |
353 | |
354 | cur = start; |
355 | end = start + len/4; |
356 | |
357 | while (cur < end) { |
358 | |
359 | opcode = *cur; |
360 | |
361 | /* |
362 | * If we forget to change the length |
363 | * in scripts, a field will be |
364 | * padded with 0. This is an illegal |
365 | * command. |
366 | */ |
367 | if (opcode == 0) { |
368 | printf ("%s: ERROR0 IN SCRIPT at %d.\n" , |
369 | sym_name(np), (int) (cur-start)); |
370 | ++cur; |
371 | continue; |
372 | } |
373 | |
374 | /* |
375 | * We use the bogus value 0xf00ff00f ;-) |
376 | * to reserve data area in SCRIPTS. |
377 | */ |
378 | if (opcode == SCR_DATA_ZERO) { |
379 | *cur++ = 0; |
380 | continue; |
381 | } |
382 | |
383 | if (DEBUG_FLAGS & DEBUG_SCRIPT) |
384 | printf ("%d: <%x>\n" , (int) (cur-start), |
385 | (unsigned)opcode); |
386 | |
387 | /* |
388 | * We don't have to decode ALL commands |
389 | */ |
390 | switch (opcode >> 28) { |
391 | case 0xf: |
392 | /* |
393 | * LOAD / STORE DSA relative, don't relocate. |
394 | */ |
395 | relocs = 0; |
396 | break; |
397 | case 0xe: |
398 | /* |
399 | * LOAD / STORE absolute. |
400 | */ |
401 | relocs = 1; |
402 | break; |
403 | case 0xc: |
404 | /* |
405 | * COPY has TWO arguments. |
406 | */ |
407 | relocs = 2; |
408 | tmp1 = cur[1]; |
409 | tmp2 = cur[2]; |
410 | if ((tmp1 ^ tmp2) & 3) { |
411 | printf ("%s: ERROR1 IN SCRIPT at %d.\n" , |
412 | sym_name(np), (int) (cur-start)); |
413 | } |
414 | /* |
415 | * If PREFETCH feature not enabled, remove |
416 | * the NO FLUSH bit if present. |
417 | */ |
418 | if ((opcode & SCR_NO_FLUSH) && |
419 | !(np->features & FE_PFEN)) { |
420 | opcode = (opcode & ~SCR_NO_FLUSH); |
421 | } |
422 | break; |
423 | case 0x0: |
424 | /* |
425 | * MOVE/CHMOV (absolute address) |
426 | */ |
427 | if (!(np->features & FE_WIDE)) |
428 | opcode = (opcode | OPC_MOVE); |
429 | relocs = 1; |
430 | break; |
431 | case 0x1: |
432 | /* |
433 | * MOVE/CHMOV (table indirect) |
434 | */ |
435 | if (!(np->features & FE_WIDE)) |
436 | opcode = (opcode | OPC_MOVE); |
437 | relocs = 0; |
438 | break; |
439 | #ifdef SYM_CONF_TARGET_ROLE_SUPPORT |
440 | case 0x2: |
441 | /* |
442 | * MOVE/CHMOV in target role (absolute address) |
443 | */ |
444 | opcode &= ~0x20000000; |
445 | if (!(np->features & FE_WIDE)) |
446 | opcode = (opcode & ~OPC_TCHMOVE); |
447 | relocs = 1; |
448 | break; |
449 | case 0x3: |
450 | /* |
451 | * MOVE/CHMOV in target role (table indirect) |
452 | */ |
453 | opcode &= ~0x20000000; |
454 | if (!(np->features & FE_WIDE)) |
455 | opcode = (opcode & ~OPC_TCHMOVE); |
456 | relocs = 0; |
457 | break; |
458 | #endif |
459 | case 0x8: |
460 | /* |
461 | * JUMP / CALL |
462 | * don't relocate if relative :-) |
463 | */ |
464 | if (opcode & 0x00800000) |
465 | relocs = 0; |
466 | else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/ |
467 | relocs = 2; |
468 | else |
469 | relocs = 1; |
470 | break; |
471 | case 0x4: |
472 | case 0x5: |
473 | case 0x6: |
474 | case 0x7: |
475 | relocs = 1; |
476 | break; |
477 | default: |
478 | relocs = 0; |
479 | break; |
480 | } |
481 | |
482 | /* |
483 | * Scriptify:) the opcode. |
484 | */ |
485 | *cur++ = cpu_to_scr(opcode); |
486 | |
487 | /* |
488 | * If no relocation, assume 1 argument |
489 | * and just scriptize:) it. |
490 | */ |
491 | if (!relocs) { |
492 | *cur = cpu_to_scr(*cur); |
493 | ++cur; |
494 | continue; |
495 | } |
496 | |
497 | /* |
498 | * Otherwise performs all needed relocations. |
499 | */ |
500 | while (relocs--) { |
501 | old = *cur; |
502 | |
503 | switch (old & RELOC_MASK) { |
504 | case RELOC_REGISTER: |
505 | new = (old & ~RELOC_MASK) + np->mmio_ba; |
506 | break; |
507 | case RELOC_LABEL_A: |
508 | new = (old & ~RELOC_MASK) + np->scripta_ba; |
509 | break; |
510 | case RELOC_LABEL_B: |
511 | new = (old & ~RELOC_MASK) + np->scriptb_ba; |
512 | break; |
513 | case RELOC_SOFTC: |
514 | new = (old & ~RELOC_MASK) + np->hcb_ba; |
515 | break; |
516 | case 0: |
517 | /* |
518 | * Don't relocate a 0 address. |
519 | * They are mostly used for patched or |
520 | * script self-modified areas. |
521 | */ |
522 | if (old == 0) { |
523 | new = old; |
524 | break; |
525 | } |
526 | fallthrough; |
527 | default: |
528 | new = 0; |
529 | panic(fmt: "sym_fw_bind_script: " |
530 | "weird relocation %x\n" , old); |
531 | break; |
532 | } |
533 | |
534 | *cur++ = cpu_to_scr(new); |
535 | } |
536 | } |
537 | } |
538 | |