brintos

brintos / linux-shallow public Read only

0
0
Text · 12.2 KiB · c536d2a Raw
538 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 Roudier10 *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 by15 *         Wolfgang Stanglmeier        <wolf@cologne.de>16 *         Stefan Esser                <se@mi.Uni-Koeln.de>17 * Copyright (C) 1994  Wolfgang Stanglmeier18 *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_SUPPORT40/*41 *  Allocate firmware #1 script area.42 */43#define	SYM_FWA_SCR		sym_fw1a_scr44#define	SYM_FWB_SCR		sym_fw1b_scr45#define	SYM_FWZ_SCR		sym_fw1z_scr46#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_SCR57#undef	SYM_FWB_SCR58#undef	SYM_FWZ_SCR59#endif	/* SYM_CONF_GENERIC_SUPPORT */60 61/*62 *  Allocate firmware #2 script area.63 */64#define	SYM_FWA_SCR		sym_fw2a_scr65#define	SYM_FWB_SCR		sym_fw2b_scr66#define	SYM_FWZ_SCR		sym_fw2z_scr67#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_SCR80#undef	SYM_FWB_SCR81#undef	SYM_FWZ_SCR82 83#undef	SYM_GEN_A84#undef	SYM_GEN_B85#undef	SYM_GEN_Z86#undef	PADDR_A87#undef	PADDR_B88 89#if	SYM_CONF_GENERIC_SUPPORT90/*91 *  Patch routine for firmware #1.92 */93static void94sym_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_SUPPORT113	/*114	 *    If user does not want to use IMMEDIATE ARBITRATION115	 *    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#endif121	/*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 void136sym_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 == 2157	/*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#endif168 169#ifdef SYM_CONF_IARB_SUPPORT170	/*171	 *    If user does not want to use IMMEDIATE ARBITRATION172	 *    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#endif178	/*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 void228sym_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_SUPPORT278/*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_SUPPORT325static 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_SUPPORT338	else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))339		return &sym_fw1;340#endif341	else342		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 length363		 *  in scripts, a field will be364		 *  padded with 0. This is an illegal365		 *  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 commands389		 */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_SUPPORT440		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#endif459		case 0x8:460			/*461			 *  JUMP / CALL462			 *  don't relocate if relative :-)463			 */464			if (opcode & 0x00800000)465				relocs = 0;466			else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/467				relocs = 2;468			else469				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				fallthrough;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}538