vserver 2.0 rc7
[linux-2.6.git] / drivers / scsi / sym53c8xx_2 / sym_fw.c
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
68 static struct sym_fwa_ofs sym_fw1a_ofs = {
69         SYM_GEN_FW_A(struct SYM_FWA_SCR)
70 };
71 static 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 };
77 static 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
96 static struct sym_fwa_ofs sym_fw2a_ofs = {
97         SYM_GEN_FW_A(struct SYM_FWA_SCR)
98 };
99 static 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 };
107 static 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  */
124 static void
125 sym_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  */
165 static void
166 sym_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  */
254 static void
255 sym_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  */
271 static void 
272 sym_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  */
308 static void 
309 sym_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  */
332 static void 
333 sym_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
356 static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
357 #endif  /* SYM_CONF_GENERIC_SUPPORT */
358 static 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  */
363 struct sym_fw * 
364 sym_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  */
379 void 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 }