aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sym53c8xx_2/sym_fw.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/scsi/sym53c8xx_2/sym_fw.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/scsi/sym53c8xx_2/sym_fw.c')
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_fw.c568
1 files changed, 568 insertions, 0 deletions
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c
new file mode 100644
index 000000000000..fd36cf9858cb
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.c
@@ -0,0 +1,568 @@
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
40#ifdef __FreeBSD__
41#include <dev/sym/sym_glue.h>
42#else
43#include "sym_glue.h"
44#endif
45
46/*
47 * Macros used for all firmwares.
48 */
49#define SYM_GEN_A(s, label) ((short) offsetof(s, label)),
50#define SYM_GEN_B(s, label) ((short) offsetof(s, label)),
51#define SYM_GEN_Z(s, label) ((short) offsetof(s, label)),
52#define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)
53#define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)
54
55
56#if SYM_CONF_GENERIC_SUPPORT
57/*
58 * Allocate firmware #1 script area.
59 */
60#define SYM_FWA_SCR sym_fw1a_scr
61#define SYM_FWB_SCR sym_fw1b_scr
62#define SYM_FWZ_SCR sym_fw1z_scr
63#ifdef __FreeBSD__
64#include <dev/sym/sym_fw1.h>
65#else
66#include "sym_fw1.h"
67#endif
68static struct sym_fwa_ofs sym_fw1a_ofs = {
69 SYM_GEN_FW_A(struct SYM_FWA_SCR)
70};
71static struct sym_fwb_ofs sym_fw1b_ofs = {
72 SYM_GEN_FW_B(struct SYM_FWB_SCR)
73#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
74 SYM_GEN_B(struct SYM_FWB_SCR, data_io)
75#endif
76};
77static struct sym_fwz_ofs sym_fw1z_ofs = {
78 SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
79};
80#undef SYM_FWA_SCR
81#undef SYM_FWB_SCR
82#undef SYM_FWZ_SCR
83#endif /* SYM_CONF_GENERIC_SUPPORT */
84
85/*
86 * Allocate firmware #2 script area.
87 */
88#define SYM_FWA_SCR sym_fw2a_scr
89#define SYM_FWB_SCR sym_fw2b_scr
90#define SYM_FWZ_SCR sym_fw2z_scr
91#ifdef __FreeBSD__
92#include <dev/sym/sym_fw2.h>
93#else
94#include "sym_fw2.h"
95#endif
96static struct sym_fwa_ofs sym_fw2a_ofs = {
97 SYM_GEN_FW_A(struct SYM_FWA_SCR)
98};
99static struct sym_fwb_ofs sym_fw2b_ofs = {
100 SYM_GEN_FW_B(struct SYM_FWB_SCR)
101#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
102 SYM_GEN_B(struct SYM_FWB_SCR, data_io)
103#endif
104 SYM_GEN_B(struct SYM_FWB_SCR, start64)
105 SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)
106};
107static struct sym_fwz_ofs sym_fw2z_ofs = {
108 SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
109};
110#undef SYM_FWA_SCR
111#undef SYM_FWB_SCR
112#undef SYM_FWZ_SCR
113
114#undef SYM_GEN_A
115#undef SYM_GEN_B
116#undef SYM_GEN_Z
117#undef PADDR_A
118#undef PADDR_B
119
120#if SYM_CONF_GENERIC_SUPPORT
121/*
122 * Patch routine for firmware #1.
123 */
124static void
125sym_fw1_patch(struct sym_hcb *np)
126{
127 struct sym_fw1a_scr *scripta0;
128 struct sym_fw1b_scr *scriptb0;
129
130 scripta0 = (struct sym_fw1a_scr *) np->scripta0;
131 scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
132
133 /*
134 * Remove LED support if not needed.
135 */
136 if (!(np->features & FE_LED0)) {
137 scripta0->idle[0] = cpu_to_scr(SCR_NO_OP);
138 scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
139 scripta0->start[0] = cpu_to_scr(SCR_NO_OP);
140 }
141
142#ifdef SYM_CONF_IARB_SUPPORT
143 /*
144 * If user does not want to use IMMEDIATE ARBITRATION
145 * when we are reselected while attempting to arbitrate,
146 * patch the SCRIPTS accordingly with a SCRIPT NO_OP.
147 */
148 if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
149 scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
150#endif
151 /*
152 * Patch some data in SCRIPTS.
153 * - start and done queue initial bus address.
154 * - target bus address table bus address.
155 */
156 scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba);
157 scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba);
158 scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba);
159}
160#endif /* SYM_CONF_GENERIC_SUPPORT */
161
162/*
163 * Patch routine for firmware #2.
164 */
165static void
166sym_fw2_patch(struct sym_hcb *np)
167{
168 struct sym_fw2a_scr *scripta0;
169 struct sym_fw2b_scr *scriptb0;
170
171 scripta0 = (struct sym_fw2a_scr *) np->scripta0;
172 scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
173
174 /*
175 * Remove LED support if not needed.
176 */
177 if (!(np->features & FE_LED0)) {
178 scripta0->idle[0] = cpu_to_scr(SCR_NO_OP);
179 scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
180 scripta0->start[0] = cpu_to_scr(SCR_NO_OP);
181 }
182
183#if SYM_CONF_DMA_ADDRESSING_MODE == 2
184 /*
185 * Remove useless 64 bit DMA specific SCRIPTS,
186 * when this feature is not available.
187 */
188 if (!np->use_dac) {
189 scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
190 scripta0->is_dmap_dirty[1] = 0;
191 scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
192 scripta0->is_dmap_dirty[3] = 0;
193 }
194#endif
195
196#ifdef SYM_CONF_IARB_SUPPORT
197 /*
198 * If user does not want to use IMMEDIATE ARBITRATION
199 * when we are reselected while attempting to arbitrate,
200 * patch the SCRIPTS accordingly with a SCRIPT NO_OP.
201 */
202 if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
203 scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
204#endif
205 /*
206 * Patch some variable in SCRIPTS.
207 * - start and done queue initial bus address.
208 * - target bus address table bus address.
209 */
210 scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba);
211 scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba);
212 scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba);
213
214 /*
215 * Remove the load of SCNTL4 on reselection if not a C10.
216 */
217 if (!(np->features & FE_C10)) {
218 scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
219 scripta0->resel_scntl4[1] = cpu_to_scr(0);
220 }
221
222 /*
223 * Remove a couple of work-arounds specific to C1010 if
224 * they are not desirable. See `sym_fw2.h' for more details.
225 */
226 if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 &&
227 np->revision_id < 0x1 &&
228 np->pciclk_khz < 60000)) {
229 scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
230 scripta0->datao_phase[1] = cpu_to_scr(0);
231 }
232 if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
233 /* np->revision_id < 0xff */ 1)) {
234 scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
235 scripta0->sel_done[1] = cpu_to_scr(0);
236 }
237
238 /*
239 * Patch some other variables in SCRIPTS.
240 * These ones are loaded by the SCRIPTS processor.
241 */
242 scriptb0->pm0_data_addr[0] =
243 cpu_to_scr(np->scripta_ba +
244 offsetof(struct sym_fw2a_scr, pm0_data));
245 scriptb0->pm1_data_addr[0] =
246 cpu_to_scr(np->scripta_ba +
247 offsetof(struct sym_fw2a_scr, pm1_data));
248}
249
250/*
251 * Fill the data area in scripts.
252 * To be done for all firmwares.
253 */
254static void
255sym_fw_fill_data (u32 *in, u32 *out)
256{
257 int i;
258
259 for (i = 0; i < SYM_CONF_MAX_SG; i++) {
260 *in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN;
261 *in++ = offsetof (struct sym_dsb, data[i]);
262 *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;
263 *out++ = offsetof (struct sym_dsb, data[i]);
264 }
265}
266
267/*
268 * Setup useful script bus addresses.
269 * To be done for all firmwares.
270 */
271static void
272sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw)
273{
274 u32 *pa;
275 u_short *po;
276 int i;
277
278 /*
279 * Build the bus address table for script A
280 * from the script A offset table.
281 */
282 po = (u_short *) fw->a_ofs;
283 pa = (u32 *) &np->fwa_bas;
284 for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)
285 pa[i] = np->scripta_ba + po[i];
286
287 /*
288 * Same for script B.
289 */
290 po = (u_short *) fw->b_ofs;
291 pa = (u32 *) &np->fwb_bas;
292 for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)
293 pa[i] = np->scriptb_ba + po[i];
294
295 /*
296 * Same for script Z.
297 */
298 po = (u_short *) fw->z_ofs;
299 pa = (u32 *) &np->fwz_bas;
300 for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++)
301 pa[i] = np->scriptz_ba + po[i];
302}
303
304#if SYM_CONF_GENERIC_SUPPORT
305/*
306 * Setup routine for firmware #1.
307 */
308static void
309sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw)
310{
311 struct sym_fw1a_scr *scripta0;
312 struct sym_fw1b_scr *scriptb0;
313
314 scripta0 = (struct sym_fw1a_scr *) np->scripta0;
315 scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
316
317 /*
318 * Fill variable parts in scripts.
319 */
320 sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
321
322 /*
323 * Setup bus addresses used from the C code..
324 */
325 sym_fw_setup_bus_addresses(np, fw);
326}
327#endif /* SYM_CONF_GENERIC_SUPPORT */
328
329/*
330 * Setup routine for firmware #2.
331 */
332static void
333sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw)
334{
335 struct sym_fw2a_scr *scripta0;
336 struct sym_fw2b_scr *scriptb0;
337
338 scripta0 = (struct sym_fw2a_scr *) np->scripta0;
339 scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
340
341 /*
342 * Fill variable parts in scripts.
343 */
344 sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
345
346 /*
347 * Setup bus addresses used from the C code..
348 */
349 sym_fw_setup_bus_addresses(np, fw);
350}
351
352/*
353 * Allocate firmware descriptors.
354 */
355#if SYM_CONF_GENERIC_SUPPORT
356static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
357#endif /* SYM_CONF_GENERIC_SUPPORT */
358static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
359
360/*
361 * Find the most appropriate firmware for a chip.
362 */
363struct sym_fw *
364sym_find_firmware(struct sym_chip *chip)
365{
366 if (chip->features & FE_LDSTR)
367 return &sym_fw2;
368#if SYM_CONF_GENERIC_SUPPORT
369 else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))
370 return &sym_fw1;
371#endif
372 else
373 return NULL;
374}
375
376/*
377 * Bind a script to physical addresses.
378 */
379void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
380{
381 u32 opcode, new, old, tmp1, tmp2;
382 u32 *end, *cur;
383 int relocs;
384
385 cur = start;
386 end = start + len/4;
387
388 while (cur < end) {
389
390 opcode = *cur;
391
392 /*
393 * If we forget to change the length
394 * in scripts, a field will be
395 * padded with 0. This is an illegal
396 * command.
397 */
398 if (opcode == 0) {
399 printf ("%s: ERROR0 IN SCRIPT at %d.\n",
400 sym_name(np), (int) (cur-start));
401 ++cur;
402 continue;
403 };
404
405 /*
406 * We use the bogus value 0xf00ff00f ;-)
407 * to reserve data area in SCRIPTS.
408 */
409 if (opcode == SCR_DATA_ZERO) {
410 *cur++ = 0;
411 continue;
412 }
413
414 if (DEBUG_FLAGS & DEBUG_SCRIPT)
415 printf ("%d: <%x>\n", (int) (cur-start),
416 (unsigned)opcode);
417
418 /*
419 * We don't have to decode ALL commands
420 */
421 switch (opcode >> 28) {
422 case 0xf:
423 /*
424 * LOAD / STORE DSA relative, don't relocate.
425 */
426 relocs = 0;
427 break;
428 case 0xe:
429 /*
430 * LOAD / STORE absolute.
431 */
432 relocs = 1;
433 break;
434 case 0xc:
435 /*
436 * COPY has TWO arguments.
437 */
438 relocs = 2;
439 tmp1 = cur[1];
440 tmp2 = cur[2];
441 if ((tmp1 ^ tmp2) & 3) {
442 printf ("%s: ERROR1 IN SCRIPT at %d.\n",
443 sym_name(np), (int) (cur-start));
444 }
445 /*
446 * If PREFETCH feature not enabled, remove
447 * the NO FLUSH bit if present.
448 */
449 if ((opcode & SCR_NO_FLUSH) &&
450 !(np->features & FE_PFEN)) {
451 opcode = (opcode & ~SCR_NO_FLUSH);
452 }
453 break;
454 case 0x0:
455 /*
456 * MOVE/CHMOV (absolute address)
457 */
458 if (!(np->features & FE_WIDE))
459 opcode = (opcode | OPC_MOVE);
460 relocs = 1;
461 break;
462 case 0x1:
463 /*
464 * MOVE/CHMOV (table indirect)
465 */
466 if (!(np->features & FE_WIDE))
467 opcode = (opcode | OPC_MOVE);
468 relocs = 0;
469 break;
470#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
471 case 0x2:
472 /*
473 * MOVE/CHMOV in target role (absolute address)
474 */
475 opcode &= ~0x20000000;
476 if (!(np->features & FE_WIDE))
477 opcode = (opcode & ~OPC_TCHMOVE);
478 relocs = 1;
479 break;
480 case 0x3:
481 /*
482 * MOVE/CHMOV in target role (table indirect)
483 */
484 opcode &= ~0x20000000;
485 if (!(np->features & FE_WIDE))
486 opcode = (opcode & ~OPC_TCHMOVE);
487 relocs = 0;
488 break;
489#endif
490 case 0x8:
491 /*
492 * JUMP / CALL
493 * don't relocate if relative :-)
494 */
495 if (opcode & 0x00800000)
496 relocs = 0;
497 else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
498 relocs = 2;
499 else
500 relocs = 1;
501 break;
502 case 0x4:
503 case 0x5:
504 case 0x6:
505 case 0x7:
506 relocs = 1;
507 break;
508 default:
509 relocs = 0;
510 break;
511 };
512
513 /*
514 * Scriptify:) the opcode.
515 */
516 *cur++ = cpu_to_scr(opcode);
517
518 /*
519 * If no relocation, assume 1 argument
520 * and just scriptize:) it.
521 */
522 if (!relocs) {
523 *cur = cpu_to_scr(*cur);
524 ++cur;
525 continue;
526 }
527
528 /*
529 * Otherwise performs all needed relocations.
530 */
531 while (relocs--) {
532 old = *cur;
533
534 switch (old & RELOC_MASK) {
535 case RELOC_REGISTER:
536 new = (old & ~RELOC_MASK) + np->mmio_ba;
537 break;
538 case RELOC_LABEL_A:
539 new = (old & ~RELOC_MASK) + np->scripta_ba;
540 break;
541 case RELOC_LABEL_B:
542 new = (old & ~RELOC_MASK) + np->scriptb_ba;
543 break;
544 case RELOC_SOFTC:
545 new = (old & ~RELOC_MASK) + np->hcb_ba;
546 break;
547 case 0:
548 /*
549 * Don't relocate a 0 address.
550 * They are mostly used for patched or
551 * script self-modified areas.
552 */
553 if (old == 0) {
554 new = old;
555 break;
556 }
557 /* fall through */
558 default:
559 new = 0;
560 panic("sym_fw_bind_script: "
561 "weird relocation %x\n", old);
562 break;
563 }
564
565 *cur++ = cpu_to_scr(new);
566 }
567 };
568}