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