// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Device driver for the SYMBIOS / LSILOGIC 53 C8XX and 53 C1010 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 386 bsd 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 >
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
#include "sym_glue.h"
#include "sym_nvram.h"
#ifdef SYM_CONF_DEBUG_NVRAM
static u_char Tekram_boot_delay[7 ] = {3 , 5 , 10 , 20 , 30 , 60 , 120 };
#endif
/*
* Get host setup from NVRAM .
*/
void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
{
/*
* Get parity checking , host ID , verbose mode
* and miscellaneous host flags from NVRAM .
*/
switch (nvram->type) {
case SYM_SYMBIOS_NVRAM:
if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
np->rv_scntl0 &= ~0 x0a;
np->myaddr = nvram->data.Symbios.host_id & 0 x0f;
if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
np->verbose += 1 ;
if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
shost->reverse_ordering = 1 ;
if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
np->usrflags |= SYM_AVOID_BUS_RESET;
break ;
case SYM_TEKRAM_NVRAM:
np->myaddr = nvram->data.Tekram.host_id & 0 x0f;
break ;
#ifdef CONFIG_PARISC
case SYM_PARISC_PDC:
if (nvram->data.parisc.host_id != -1 )
np->myaddr = nvram->data.parisc.host_id;
if (nvram->data.parisc.factor != -1 )
np->minsync = nvram->data.parisc.factor;
if (nvram->data.parisc.width != -1 )
np->maxwide = nvram->data.parisc.width;
switch (nvram->data.parisc.mode) {
case 0 : np->scsi_mode = SMODE_SE; break ;
case 1 : np->scsi_mode = SMODE_HVD; break ;
case 2 : np->scsi_mode = SMODE_LVD; break ;
default : break ;
}
#endif
default :
break ;
}
}
/*
* Get target set - up from Symbios format NVRAM .
*/
static void
sym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram)
{
Symbios_target *tn = &nvram->target[target];
if (!(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED))
tp->usrtags = 0 ;
if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
tp->usrflags &= ~SYM_DISC_ENABLED;
if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
tp->usrflags |= SYM_SCAN_BOOT_DISABLED;
if (!(tn->flags & SYMBIOS_SCAN_LUNS))
tp->usrflags |= SYM_SCAN_LUNS_DISABLED;
tp->usr_period = (tn->sync_period + 3 ) / 4 ;
tp->usr_width = (tn->bus_width == 0 x8) ? 0 : 1 ;
}
static const unsigned char Tekram_sync[16 ] = {
25 , 31 , 37 , 43 , 50 , 62 , 75 , 125 , 12 , 15 , 18 , 21 , 6 , 7 , 9 , 10
};
/*
* Get target set - up from Tekram format NVRAM .
*/
static void
sym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram)
{
struct Tekram_target *tn = &nvram->target[target];
if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
tp->usrtags = 2 << nvram->max_tags_index;
}
if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
tp->usrflags |= SYM_DISC_ENABLED;
if (tn->flags & TEKRAM_SYNC_NEGO)
tp->usr_period = Tekram_sync[tn->sync_index & 0 xf];
tp->usr_width = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0 ;
}
/*
* Get target setup from NVRAM .
*/
void sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp)
{
switch (nvp->type) {
case SYM_SYMBIOS_NVRAM:
sym_Symbios_setup_target(tp, target, &nvp->data.Symbios);
break ;
case SYM_TEKRAM_NVRAM:
sym_Tekram_setup_target(tp, target, &nvp->data.Tekram);
break ;
default :
break ;
}
}
#ifdef SYM_CONF_DEBUG_NVRAM
/*
* Dump Symbios format NVRAM for debugging purpose .
*/
static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
{
int i;
/* display Symbios nvram host data */
printf("%s: HOST ID=%d%s%s%s%s%s%s\n" ,
sym_name(np), nvram->host_id & 0 x0f,
(nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"" ,
(nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"" ,
(nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"" ,
(nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"" ,
(nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"" ,
(nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :"" );
/* display Symbios nvram drive data */
for (i = 0 ; i < 15 ; i++) {
struct Symbios_target *tn = &nvram->target[i];
printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n" ,
sym_name(np), i,
(tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "" ,
(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "" ,
(tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "" ,
(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "" ,
tn->bus_width,
tn->sync_period / 4 ,
tn->timeout);
}
}
/*
* Dump TEKRAM format NVRAM for debugging purpose .
*/
static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram)
{
int i, tags, boot_delay;
char *rem;
/* display Tekram nvram host data */
tags = 2 << nvram->max_tags_index;
boot_delay = 0 ;
if (nvram->boot_delay_index < 6 )
boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6 ) {
default :
case 0 : rem = "" ; break ;
case 1 : rem = " REMOVABLE=boot device" ; break ;
case 2 : rem = " REMOVABLE=all" ; break ;
}
printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n" ,
sym_name(np), nvram->host_id & 0 x0f,
(nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"" ,
(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES" :"" ,
(nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"" ,
(nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"" ,
(nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"" ,
(nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"" ,
(nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"" ,
(nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"" ,
rem, boot_delay, tags);
/* display Tekram nvram drive data */
for (i = 0 ; i <= 15 ; i++) {
int sync, j;
struct Tekram_target *tn = &nvram->target[i];
j = tn->sync_index & 0 xf;
sync = Tekram_sync[j];
printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n" ,
sym_name(np), i,
(tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "" ,
(tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "" ,
(tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "" ,
(tn->flags & TEKRAM_START_CMD) ? " START" : "" ,
(tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "" ,
(tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "" ,
sync);
}
}
#else
static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void )np; (void )nvram; }
static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void )np; (void )nvram; }
#endif /* SYM_CONF_DEBUG_NVRAM */
/*
* 24 C16 EEPROM reading .
*
* GPIO0 - data in / data out
* GPIO1 - clock
* Symbios NVRAM wiring now also used by Tekram .
*/
#define SET_BIT 0
#define CLR_BIT 1
#define SET_CLK 2
#define CLR_CLK 3
/*
* Set / clear data / clock bit in GPIO0
*/
static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg,
int bit_mode)
{
udelay(5 );
switch (bit_mode) {
case SET_BIT:
*gpreg |= write_bit;
break ;
case CLR_BIT:
*gpreg &= 0 xfe;
break ;
case SET_CLK:
*gpreg |= 0 x02;
break ;
case CLR_CLK:
*gpreg &= 0 xfd;
break ;
}
OUTB(np, nc_gpreg, *gpreg);
INB(np, nc_mbox1);
udelay(5 );
}
/*
* Send START condition to NVRAM to wake it up .
*/
static void S24C16_start(struct sym_device *np, u_char *gpreg)
{
S24C16_set_bit(np, 1 , gpreg, SET_BIT);
S24C16_set_bit(np, 0 , gpreg, SET_CLK);
S24C16_set_bit(np, 0 , gpreg, CLR_BIT);
S24C16_set_bit(np, 0 , gpreg, CLR_CLK);
}
/*
* Send STOP condition to NVRAM - puts NVRAM to sleep . . . ZZzzzz ! !
*/
static void S24C16_stop(struct sym_device *np, u_char *gpreg)
{
S24C16_set_bit(np, 0 , gpreg, SET_CLK);
S24C16_set_bit(np, 1 , gpreg, SET_BIT);
}
/*
* Read or write a bit to the NVRAM ,
* read if GPIO0 input else write if GPIO0 output
*/
static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit,
u_char *gpreg)
{
S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
S24C16_set_bit(np, 0 , gpreg, SET_CLK);
if (read_bit)
*read_bit = INB(np, nc_gpreg);
S24C16_set_bit(np, 0 , gpreg, CLR_CLK);
S24C16_set_bit(np, 0 , gpreg, CLR_BIT);
}
/*
* Output an ACK to the NVRAM after reading ,
* change GPIO0 to output and when done back to an input
*/
static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg,
u_char *gpcntl)
{
OUTB(np, nc_gpcntl, *gpcntl & 0 xfe);
S24C16_do_bit(np, NULL, write_bit, gpreg);
OUTB(np, nc_gpcntl, *gpcntl);
}
/*
* Input an ACK from NVRAM after writing ,
* change GPIO0 to input and when done back to an output
*/
static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg,
u_char *gpcntl)
{
OUTB(np, nc_gpcntl, *gpcntl | 0 x01);
S24C16_do_bit(np, read_bit, 1 , gpreg);
OUTB(np, nc_gpcntl, *gpcntl);
}
/*
* WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK ,
* GPIO0 must already be set as an output
*/
static void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data,
u_char *gpreg, u_char *gpcntl)
{
int x;
for (x = 0 ; x < 8 ; x++)
S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0 x01, gpreg);
S24C16_read_ack(np, ack_data, gpreg, gpcntl);
}
/*
* READ a byte from the NVRAM and then send an ACK to say we have got it ,
* GPIO0 must already be set as an input
*/
static void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data,
u_char *gpreg, u_char *gpcntl)
{
int x;
u_char read_bit;
*read_data = 0 ;
for (x = 0 ; x < 8 ; x++) {
S24C16_do_bit(np, &read_bit, 1 , gpreg);
*read_data |= ((read_bit & 0 x01) << (7 - x));
}
S24C16_write_ack(np, ack_data, gpreg, gpcntl);
}
#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT
/*
* Write ' len ' bytes starting at ' offset ' .
*/
static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
u_char *data, int len)
{
u_char gpcntl, gpreg;
u_char old_gpcntl, old_gpreg;
u_char ack_data;
int x;
/* save current state of GPCNTL and GPREG */
old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB(np, nc_gpcntl);
gpcntl = old_gpcntl & 0 x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB(np, nc_gpreg, old_gpreg);
OUTB(np, nc_gpcntl, gpcntl);
/* this is to set NVRAM into a known state with GPIO0/1 both low */
gpreg = old_gpreg;
S24C16_set_bit(np, 0 , &gpreg, CLR_CLK);
S24C16_set_bit(np, 0 , &gpreg, CLR_BIT);
/* now set NVRAM inactive with GPIO0/1 both high */
S24C16_stop(np, &gpreg);
/* NVRAM has to be written in segments of 16 bytes */
for (x = 0 ; x < len ; x += 16 ) {
do {
S24C16_start(np, &gpreg);
S24C16_write_byte(np, &ack_data,
0 xa0 | (((offset+x) >> 7 ) & 0 x0e),
&gpreg, &gpcntl);
} while (ack_data & 0 x01);
S24C16_write_byte(np, &ack_data, (offset+x) & 0 xff,
&gpreg, &gpcntl);
for (y = 0 ; y < 16 ; y++)
S24C16_write_byte(np, &ack_data, data[x+y],
&gpreg, &gpcntl);
S24C16_stop(np, &gpreg);
}
/* return GPIO0/1 to original states after having accessed NVRAM */
OUTB(np, nc_gpcntl, old_gpcntl);
OUTB(np, nc_gpreg, old_gpreg);
return 0 ;
}
#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */
/*
* Read ' len ' bytes starting at ' offset ' .
*/
static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len)
{
u_char gpcntl, gpreg;
u_char old_gpcntl, old_gpreg;
u_char ack_data;
int retv = 1 ;
int x;
/* save current state of GPCNTL and GPREG */
old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB(np, nc_gpcntl);
gpcntl = old_gpcntl & 0 x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB(np, nc_gpreg, old_gpreg);
OUTB(np, nc_gpcntl, gpcntl);
/* this is to set NVRAM into a known state with GPIO0/1 both low */
gpreg = old_gpreg;
S24C16_set_bit(np, 0 , &gpreg, CLR_CLK);
S24C16_set_bit(np, 0 , &gpreg, CLR_BIT);
/* now set NVRAM inactive with GPIO0/1 both high */
S24C16_stop(np, &gpreg);
/* activate NVRAM */
S24C16_start(np, &gpreg);
/* write device code and random address MSB */
S24C16_write_byte(np, &ack_data,
0 xa0 | ((offset >> 7 ) & 0 x0e), &gpreg, &gpcntl);
if (ack_data & 0 x01)
goto out;
/* write random address LSB */
S24C16_write_byte(np, &ack_data,
offset & 0 xff, &gpreg, &gpcntl);
if (ack_data & 0 x01)
goto out;
/* regenerate START state to set up for reading */
S24C16_start(np, &gpreg);
/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
S24C16_write_byte(np, &ack_data,
0 xa1 | ((offset >> 7 ) & 0 x0e), &gpreg, &gpcntl);
if (ack_data & 0 x01)
goto out;
/* now set up GPIO0 for inputting data */
gpcntl |= 0 x01;
OUTB(np, nc_gpcntl, gpcntl);
/* input all requested data - only part of total NVRAM */
for (x = 0 ; x < len; x++)
S24C16_read_byte(np, &data[x], (x == (len-1 )), &gpreg, &gpcntl);
/* finally put NVRAM back in inactive mode */
gpcntl &= 0 xfe;
OUTB(np, nc_gpcntl, gpcntl);
S24C16_stop(np, &gpreg);
retv = 0 ;
out:
/* return GPIO0/1 to original states after having accessed NVRAM */
OUTB(np, nc_gpcntl, old_gpcntl);
OUTB(np, nc_gpreg, old_gpreg);
return retv;
}
#undef SET_BIT
#undef CLR_BIT
#undef SET_CLK
#undef CLR_CLK
/*
* Try reading Symbios NVRAM .
* Return 0 if OK .
*/
static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
{
static u_char Symbios_trailer[6 ] = {0 xfe, 0 xfe, 0 , 0 , 0 , 0 };
u_char *data = (u_char *) nvram;
int len = sizeof (*nvram);
u_short csum;
int x;
/* probe the 24c16 and read the SYMBIOS 24c16 area */
if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
return 1 ;
/* check valid NVRAM signature, verify byte count and checksum */
if (nvram->type != 0 ||
memcmp(nvram->trailer, Symbios_trailer, 6 ) ||
nvram->byte_count != len - 12 )
return 1 ;
/* verify checksum */
for (x = 6 , csum = 0 ; x < len - 6 ; x++)
csum += data[x];
if (csum != nvram->checksum)
return 1 ;
return 0 ;
}
/*
* 93 C46 EEPROM reading .
*
* GPIO0 - data in
* GPIO1 - data out
* GPIO2 - clock
* GPIO4 - chip select
*
* Used by Tekram .
*/
/*
* Pulse clock bit in GPIO0
*/
static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
{
OUTB(np, nc_gpreg, *gpreg | 0 x04);
INB(np, nc_mbox1);
udelay(2 );
OUTB(np, nc_gpreg, *gpreg);
}
/*
* Read bit from NVRAM
*/
static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg)
{
udelay(2 );
T93C46_Clk(np, gpreg);
*read_bit = INB(np, nc_gpreg);
}
/*
* Write bit to GPIO0
*/
static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg)
{
if (write_bit & 0 x01)
*gpreg |= 0 x02;
else
*gpreg &= 0 xfd;
*gpreg |= 0 x10;
OUTB(np, nc_gpreg, *gpreg);
INB(np, nc_mbox1);
udelay(2 );
T93C46_Clk(np, gpreg);
}
/*
* Send STOP condition to NVRAM - puts NVRAM to sleep . . . ZZZzzz ! !
*/
static void T93C46_Stop(struct sym_device *np, u_char *gpreg)
{
*gpreg &= 0 xef;
OUTB(np, nc_gpreg, *gpreg);
INB(np, nc_mbox1);
udelay(2 );
T93C46_Clk(np, gpreg);
}
/*
* Send read command and address to NVRAM
*/
static void T93C46_Send_Command(struct sym_device *np, u_short write_data,
u_char *read_bit, u_char *gpreg)
{
int x;
/* send 9 bits, start bit (1), command (2), address (6) */
for (x = 0 ; x < 9 ; x++)
T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
*read_bit = INB(np, nc_gpreg);
}
/*
* READ 2 bytes from the NVRAM
*/
static void T93C46_Read_Word(struct sym_device *np,
unsigned short *nvram_data, unsigned char *gpreg)
{
int x;
u_char read_bit;
*nvram_data = 0 ;
for (x = 0 ; x < 16 ; x++) {
T93C46_Read_Bit(np, &read_bit, gpreg);
if (read_bit & 0 x01)
*nvram_data |= (0 x01 << (15 - x));
else
*nvram_data &= ~(0 x01 << (15 - x));
}
}
/*
* Read Tekram NvRAM data .
*/
static int T93C46_Read_Data(struct sym_device *np, unsigned short *data,
int len, unsigned char *gpreg)
{
int x;
for (x = 0 ; x < len; x++) {
unsigned char read_bit;
/* output read command and address */
T93C46_Send_Command(np, 0 x180 | x, &read_bit, gpreg);
if (read_bit & 0 x01)
return 1 ; /* Bad */
T93C46_Read_Word(np, &data[x], gpreg);
T93C46_Stop(np, gpreg);
}
return 0 ;
}
/*
* Try reading 93 C46 Tekram NVRAM .
*/
static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram)
{
u_char gpcntl, gpreg;
u_char old_gpcntl, old_gpreg;
int retv;
/* save current state of GPCNTL and GPREG */
old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB(np, nc_gpcntl);
/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
1/2/4 out */
gpreg = old_gpreg & 0 xe9;
OUTB(np, nc_gpreg, gpreg);
gpcntl = (old_gpcntl & 0 xe9) | 0 x09;
OUTB(np, nc_gpcntl, gpcntl);
/* input all of NVRAM, 64 words */
retv = T93C46_Read_Data(np, (u_short *) nvram,
sizeof (*nvram) / sizeof (short ), &gpreg);
/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
OUTB(np, nc_gpcntl, old_gpcntl);
OUTB(np, nc_gpreg, old_gpreg);
return retv;
}
/*
* Try reading Tekram NVRAM .
* Return 0 if OK .
*/
static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
{
u_char *data = (u_char *) nvram;
int len = sizeof (*nvram);
u_short csum;
int x;
switch (np->pdev->device) {
case PCI_DEVICE_ID_NCR_53C885:
case PCI_DEVICE_ID_NCR_53C895:
case PCI_DEVICE_ID_NCR_53C896:
x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
data, len);
break ;
case PCI_DEVICE_ID_NCR_53C875:
x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
data, len);
if (!x)
break ;
fallthrough;
default :
x = sym_read_T93C46_nvram(np, nvram);
break ;
}
if (x)
return 1 ;
/* verify checksum */
for (x = 0 , csum = 0 ; x < len - 1 ; x += 2 )
csum += data[x] + (data[x+1 ] << 8 );
if (csum != 0 x1234)
return 1 ;
return 0 ;
}
#ifdef CONFIG_PARISC
/*
* Host firmware ( PDC ) keeps a table for altering SCSI capabilities .
* Many newer machines export one channel of 53 c896 chip as SE , 50 - pin HD .
* Also used for Multi - initiator SCSI clusters to set the SCSI Initiator ID .
*/
static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc)
{
struct hardware_path hwpath;
get_pci_node_path(np->pdev, &hwpath);
if (!pdc_get_initiator(&hwpath, pdc))
return 0 ;
return SYM_PARISC_PDC;
}
#else
static inline int sym_read_parisc_pdc(struct sym_device *np,
struct pdc_initiator *x)
{
return 0 ;
}
#endif
/*
* Try reading Symbios or Tekram NVRAM
*/
int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
{
if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) {
nvp->type = SYM_SYMBIOS_NVRAM;
sym_display_Symbios_nvram(np, &nvp->data.Symbios);
} else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) {
nvp->type = SYM_TEKRAM_NVRAM;
sym_display_Tekram_nvram(np, &nvp->data.Tekram);
} else {
nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc);
}
return nvp->type;
}
char *sym_nvram_type(struct sym_nvram *nvp)
{
switch (nvp->type) {
case SYM_SYMBIOS_NVRAM:
return "Symbios NVRAM" ;
case SYM_TEKRAM_NVRAM:
return "Tekram NVRAM" ;
case SYM_PARISC_PDC:
return "PA-RISC Firmware" ;
default :
return "No NVRAM" ;
}
}
Messung V0.5 in Prozent C=92 H=88 G=89
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland