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