PageRenderTime 43ms CodeModel.GetById 11ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/scsi/sym53c8xx_2/sym_fw.c

http://github.com/mirrors/linux
C | 537 lines | 306 code | 47 blank | 184 comment | 40 complexity | 8176fee44672f9bd701ac65a5d80ae65 MD5 | raw file
  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"
 47static struct sym_fwa_ofs sym_fw1a_ofs = {
 48	SYM_GEN_FW_A(struct SYM_FWA_SCR)
 49};
 50static struct sym_fwb_ofs sym_fw1b_ofs = {
 51	SYM_GEN_FW_B(struct SYM_FWB_SCR)
 52};
 53static 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"
 68static struct sym_fwa_ofs sym_fw2a_ofs = {
 69	SYM_GEN_FW_A(struct SYM_FWA_SCR)
 70};
 71static 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};
 76static 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 */
 93static void
 94sym_fw1_patch(struct Scsi_Host *shost)
 95{
 96	struct sym_hcb *np = sym_get_hcb(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 */
135static void
136sym_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 */
227static void
228sym_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 */
244static void 
245sym_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 */
281static void 
282sym_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(scripta0->data_in, 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 */
303static void 
304sym_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(scripta0->data_in, 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
325static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
326#endif	/* SYM_CONF_GENERIC_SUPPORT */
327static 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 */
332struct sym_fw * 
333sym_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 */
348void 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				/* fall through */
527			default:
528				new = 0;
529				panic("sym_fw_bind_script: "
530				      "weird relocation %x\n", old);
531				break;
532			}
533
534			*cur++ = cpu_to_scr(new);
535		}
536	};
537}