⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sym_fw.c

📁 h内核
💻 C
字号:
/* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family  * of PCI-SCSI IO processors. * * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr> * * This driver is derived from the Linux sym53c8xx driver. * Copyright (C) 1998-2000  Gerard Roudier * * The sym53c8xx driver is derived from the ncr53c8xx driver that had been  * a port of the FreeBSD ncr driver to Linux-1.2.13. * * The original ncr driver has been written for 386bsd and FreeBSD by *         Wolfgang Stanglmeier        <wolf@cologne.de> *         Stefan Esser                <se@mi.Uni-Koeln.de> * Copyright (C) 1994  Wolfgang Stanglmeier * * Other major contributions: * * NVRAM detection and reading. * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> * *----------------------------------------------------------------------------- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#ifdef __FreeBSD__#include <dev/sym/sym_glue.h>#else#include "sym_glue.h"#endif/* *  Macros used for all firmwares. */#define	SYM_GEN_A(s, label)	((short) offsetof(s, label)),#define	SYM_GEN_B(s, label)	((short) offsetof(s, label)),#define	SYM_GEN_Z(s, label)	((short) offsetof(s, label)),#define	PADDR_A(label)		SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)#define	PADDR_B(label)		SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)#if	SYM_CONF_GENERIC_SUPPORT/* *  Allocate firmware #1 script area. */#define	SYM_FWA_SCR		sym_fw1a_scr#define	SYM_FWB_SCR		sym_fw1b_scr#define	SYM_FWZ_SCR		sym_fw1z_scr#ifdef __FreeBSD__#include <dev/sym/sym_fw1.h>#else#include "sym_fw1.h"#endifstatic struct sym_fwa_ofs sym_fw1a_ofs = {	SYM_GEN_FW_A(struct SYM_FWA_SCR)};static struct sym_fwb_ofs sym_fw1b_ofs = {	SYM_GEN_FW_B(struct SYM_FWB_SCR)#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN	SYM_GEN_B(struct SYM_FWB_SCR, data_io)#endif};static struct sym_fwz_ofs sym_fw1z_ofs = {	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)};#undef	SYM_FWA_SCR#undef	SYM_FWB_SCR#undef	SYM_FWZ_SCR#endif	/* SYM_CONF_GENERIC_SUPPORT *//* *  Allocate firmware #2 script area. */#define	SYM_FWA_SCR		sym_fw2a_scr#define	SYM_FWB_SCR		sym_fw2b_scr#define	SYM_FWZ_SCR		sym_fw2z_scr#ifdef __FreeBSD__#include <dev/sym/sym_fw2.h>#else#include "sym_fw2.h"#endifstatic struct sym_fwa_ofs sym_fw2a_ofs = {	SYM_GEN_FW_A(struct SYM_FWA_SCR)};static struct sym_fwb_ofs sym_fw2b_ofs = {	SYM_GEN_FW_B(struct SYM_FWB_SCR)#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN	SYM_GEN_B(struct SYM_FWB_SCR, data_io)#endif	SYM_GEN_B(struct SYM_FWB_SCR, start64)	SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)};static struct sym_fwz_ofs sym_fw2z_ofs = {	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)};#undef	SYM_FWA_SCR#undef	SYM_FWB_SCR#undef	SYM_FWZ_SCR#undef	SYM_GEN_A#undef	SYM_GEN_B#undef	SYM_GEN_Z#undef	PADDR_A#undef	PADDR_B#if	SYM_CONF_GENERIC_SUPPORT/* *  Patch routine for firmware #1. */static voidsym_fw1_patch(struct sym_hcb *np){	struct sym_fw1a_scr *scripta0;	struct sym_fw1b_scr *scriptb0;	scripta0 = (struct sym_fw1a_scr *) np->scripta0;	scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;	/*	 *  Remove LED support if not needed.	 */	if (!(np->features & FE_LED0)) {		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);	}#ifdef SYM_CONF_IARB_SUPPORT	/*	 *    If user does not want to use IMMEDIATE ARBITRATION	 *    when we are reselected while attempting to arbitrate,	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.	 */	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);#endif	/*	 *  Patch some data in SCRIPTS.	 *  - start and done queue initial bus address.	 *  - target bus address table bus address.	 */	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);}#endif	/* SYM_CONF_GENERIC_SUPPORT *//* *  Patch routine for firmware #2. */static voidsym_fw2_patch(struct sym_hcb *np){	struct sym_fw2a_scr *scripta0;	struct sym_fw2b_scr *scriptb0;	scripta0 = (struct sym_fw2a_scr *) np->scripta0;	scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;	/*	 *  Remove LED support if not needed.	 */	if (!(np->features & FE_LED0)) {		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);	}#if   SYM_CONF_DMA_ADDRESSING_MODE == 2	/*	 *  Remove useless 64 bit DMA specific SCRIPTS, 	 *  when this feature is not available.	 */	if (!np->use_dac) {		scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);		scripta0->is_dmap_dirty[1] = 0;		scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);		scripta0->is_dmap_dirty[3] = 0;	}#endif#ifdef SYM_CONF_IARB_SUPPORT	/*	 *    If user does not want to use IMMEDIATE ARBITRATION	 *    when we are reselected while attempting to arbitrate,	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.	 */	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);#endif	/*	 *  Patch some variable in SCRIPTS.	 *  - start and done queue initial bus address.	 *  - target bus address table bus address.	 */	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);	/*	 *  Remove the load of SCNTL4 on reselection if not a C10.	 */	if (!(np->features & FE_C10)) {		scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);		scripta0->resel_scntl4[1] = cpu_to_scr(0);	}	/*	 *  Remove a couple of work-arounds specific to C1010 if 	 *  they are not desirable. See `sym_fw2.h' for more details.	 */	if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 &&	      np->revision_id < 0x1 &&	      np->pciclk_khz < 60000)) {		scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);		scripta0->datao_phase[1] = cpu_to_scr(0);	}	if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&	      /* np->revision_id < 0xff */ 1)) {		scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);		scripta0->sel_done[1] = cpu_to_scr(0);	}	/*	 *  Patch some other variables in SCRIPTS.	 *  These ones are loaded by the SCRIPTS processor.	 */	scriptb0->pm0_data_addr[0] =		cpu_to_scr(np->scripta_ba + 			   offsetof(struct sym_fw2a_scr, pm0_data));	scriptb0->pm1_data_addr[0] =		cpu_to_scr(np->scripta_ba + 			   offsetof(struct sym_fw2a_scr, pm1_data));}/* *  Fill the data area in scripts. *  To be done for all firmwares. */static voidsym_fw_fill_data (u32 *in, u32 *out){	int	i;	for (i = 0; i < SYM_CONF_MAX_SG; i++) {		*in++  = SCR_CHMOV_TBL ^ SCR_DATA_IN;		*in++  = offsetof (struct sym_dsb, data[i]);		*out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;		*out++ = offsetof (struct sym_dsb, data[i]);	}}/* *  Setup useful script bus addresses. *  To be done for all firmwares. */static void sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw){	u32 *pa;	u_short *po;	int i;	/*	 *  Build the bus address table for script A 	 *  from the script A offset table.	 */	po = (u_short *) fw->a_ofs;	pa = (u32 *) &np->fwa_bas;	for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)		pa[i] = np->scripta_ba + po[i];	/*	 *  Same for script B.	 */	po = (u_short *) fw->b_ofs;	pa = (u32 *) &np->fwb_bas;	for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)		pa[i] = np->scriptb_ba + po[i];	/*	 *  Same for script Z.	 */	po = (u_short *) fw->z_ofs;	pa = (u32 *) &np->fwz_bas;	for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++)		pa[i] = np->scriptz_ba + po[i];}#if	SYM_CONF_GENERIC_SUPPORT/* *  Setup routine for firmware #1. */static void sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw){	struct sym_fw1a_scr *scripta0;	struct sym_fw1b_scr *scriptb0;	scripta0 = (struct sym_fw1a_scr *) np->scripta0;	scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;	/*	 *  Fill variable parts in scripts.	 */	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);	/*	 *  Setup bus addresses used from the C code..	 */	sym_fw_setup_bus_addresses(np, fw);}#endif	/* SYM_CONF_GENERIC_SUPPORT *//* *  Setup routine for firmware #2. */static void sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw){	struct sym_fw2a_scr *scripta0;	struct sym_fw2b_scr *scriptb0;	scripta0 = (struct sym_fw2a_scr *) np->scripta0;	scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;	/*	 *  Fill variable parts in scripts.	 */	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);	/*	 *  Setup bus addresses used from the C code..	 */	sym_fw_setup_bus_addresses(np, fw);}/* *  Allocate firmware descriptors. */#if	SYM_CONF_GENERIC_SUPPORTstatic struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");#endif	/* SYM_CONF_GENERIC_SUPPORT */static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");/* *  Find the most appropriate firmware for a chip. */struct sym_fw * sym_find_firmware(struct sym_pci_chip *chip){	if (chip->features & FE_LDSTR)		return &sym_fw2;#if	SYM_CONF_GENERIC_SUPPORT	else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))		return &sym_fw1;#endif	else		return NULL;}/* *  Bind a script to physical addresses. */void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len){	u32 opcode, new, old, tmp1, tmp2;	u32 *end, *cur;	int relocs;	cur = start;	end = start + len/4;	while (cur < end) {		opcode = *cur;		/*		 *  If we forget to change the length		 *  in scripts, a field will be		 *  padded with 0. This is an illegal		 *  command.		 */		if (opcode == 0) {			printf ("%s: ERROR0 IN SCRIPT at %d.\n",				sym_name(np), (int) (cur-start));			++cur;			continue;		};		/*		 *  We use the bogus value 0xf00ff00f ;-)		 *  to reserve data area in SCRIPTS.		 */		if (opcode == SCR_DATA_ZERO) {			*cur++ = 0;			continue;		}		if (DEBUG_FLAGS & DEBUG_SCRIPT)			printf ("%d:  <%x>\n", (int) (cur-start),				(unsigned)opcode);		/*		 *  We don't have to decode ALL commands		 */		switch (opcode >> 28) {		case 0xf:			/*			 *  LOAD / STORE DSA relative, don't relocate.			 */			relocs = 0;			break;		case 0xe:			/*			 *  LOAD / STORE absolute.			 */			relocs = 1;			break;		case 0xc:			/*			 *  COPY has TWO arguments.			 */			relocs = 2;			tmp1 = cur[1];			tmp2 = cur[2];			if ((tmp1 ^ tmp2) & 3) {				printf ("%s: ERROR1 IN SCRIPT at %d.\n",					sym_name(np), (int) (cur-start));			}			/*			 *  If PREFETCH feature not enabled, remove 			 *  the NO FLUSH bit if present.			 */			if ((opcode & SCR_NO_FLUSH) &&			    !(np->features & FE_PFEN)) {				opcode = (opcode & ~SCR_NO_FLUSH);			}			break;		case 0x0:			/*			 *  MOVE/CHMOV (absolute address)			 */			if (!(np->features & FE_WIDE))				opcode = (opcode | OPC_MOVE);			relocs = 1;			break;		case 0x1:			/*			 *  MOVE/CHMOV (table indirect)			 */			if (!(np->features & FE_WIDE))				opcode = (opcode | OPC_MOVE);			relocs = 0;			break;#ifdef SYM_CONF_TARGET_ROLE_SUPPORT		case 0x2:			/*			 *  MOVE/CHMOV in target role (absolute address)			 */			opcode &= ~0x20000000;			if (!(np->features & FE_WIDE))				opcode = (opcode & ~OPC_TCHMOVE);			relocs = 1;			break;		case 0x3:			/*			 *  MOVE/CHMOV in target role (table indirect)			 */			opcode &= ~0x20000000;			if (!(np->features & FE_WIDE))				opcode = (opcode & ~OPC_TCHMOVE);			relocs = 0;			break;#endif		case 0x8:			/*			 *  JUMP / CALL			 *  don't relocate if relative :-)			 */			if (opcode & 0x00800000)				relocs = 0;			else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/				relocs = 2;			else				relocs = 1;			break;		case 0x4:		case 0x5:		case 0x6:		case 0x7:			relocs = 1;			break;		default:			relocs = 0;			break;		};		/*		 *  Scriptify:) the opcode.		 */		*cur++ = cpu_to_scr(opcode);		/*		 *  If no relocation, assume 1 argument 		 *  and just scriptize:) it.		 */		if (!relocs) {			*cur = cpu_to_scr(*cur);			++cur;			continue;		}		/*		 *  Otherwise performs all needed relocations.		 */		while (relocs--) {			old = *cur;			switch (old & RELOC_MASK) {			case RELOC_REGISTER:				new = (old & ~RELOC_MASK) + np->mmio_ba;				break;			case RELOC_LABEL_A:				new = (old & ~RELOC_MASK) + np->scripta_ba;				break;			case RELOC_LABEL_B:				new = (old & ~RELOC_MASK) + np->scriptb_ba;				break;			case RELOC_SOFTC:				new = (old & ~RELOC_MASK) + np->hcb_ba;				break;			case 0:				/*				 *  Don't relocate a 0 address.				 *  They are mostly used for patched or 				 *  script self-modified areas.				 */				if (old == 0) {					new = old;					break;				}				/* fall through */			default:				new = 0;				panic("sym_fw_bind_script: "				      "weird relocation %x\n", old);				break;			}			*cur++ = cpu_to_scr(new);		}	};}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -