// SPDX-License-Identifier: GPL-2.0-or-later /* * 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> * *-----------------------------------------------------------------------------
*/
/* * 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 */
/* * 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 (!use_dac(np)) {
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 (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 &&
pdev->revision < 0x1 &&
np->pciclk_khz < 60000)) {
scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
scripta0->datao_phase[1] = cpu_to_scr(0);
} if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* &&
pdev->revision < 0xff */
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.
*/ staticvoid
sym_fw_fill_data (u32 *in, u32 *out)
{ int i;
/* * Setup useful script bus addresses. * To be done for all firmwares.
*/ staticvoid
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];
}
/* * Find the most appropriate firmware for a chip.
*/ struct sym_fw *
sym_find_firmware(struct sym_chip *chip)
{ if (chip->features & FE_LDSTR) return &sym_fw2; #if SYM_CONF_GENERIC_SUPPORT elseif (!(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; elseif ((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;
}
fallthrough; default: new = 0;
panic("sym_fw_bind_script: " "weird relocation %x\n", old); break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.