|
|
(не показана 1 промежуточная версия этого же участника) |
Строка 44: |
Строка 44: |
|
Все манипуляции проводить только с 1 битом, например если было значение <code>fe</code> |
|
Все манипуляции проводить только с 1 битом, например если было значение <code>fe</code> |
|
<BR> |
|
<BR> |
− |
( Бинарное <code>11111110</code> ) то записать следует <code>ff</code>( Бинарное <code>11111111</code> |
+ |
( Бинарное <code>11111110</code> ) то записать следует <code>ff</code>( Бинарное <code>11111111</code> ) |
|
<PRE> |
|
<PRE> |
|
ethtool -E enp1s0 magic 0x10fb8086 offset 0x58 value 0xff |
|
ethtool -E enp1s0 magic 0x10fb8086 offset 0x58 value 0xff |
Строка 392: |
Строка 392: |
|
return 0; |
|
return 0; |
|
} |
|
} |
− |
</PRE> |
|
− |
}} |
|
− |
|
|
− |
==<code>4</code>== |
|
− |
{{#spoiler:show=1| |
|
− |
|
|
− |
<PRE> |
|
|
</PRE> |
|
</PRE> |
|
}} |
|
}} |
Текущая версия на 11:17, 25 февраля 2024
Ошибка ixgbe failed to load because an unsupported SFP+ module type was detected
x520
- файл
/etc/default/grub.d/60_custom.cfg
GRUB_CMDLINE_LINUX="$GRUB_CMDLINE_LINUX ixgbe.allow_unsupported_sfp=1"
Или если более чем одна карта - ixgbe.allow_unsupported_sfp=1,1,1,1
- Файл
/etc/modprobe.d/ixgbe.conf
options ixgbe allow_unsupported_sfp=1,1,1,1
Тут нужно указать список если более чем одна карта (или порт?)
x520 Unlocker
В теории это нужно что бы установить карту там, где драйвер не имеет опции отключения проверки.
Последний бит должен быть установлен 1 (в примере уже установлен, в обоих случаях )
ethtool -e enp3s0f1 offset 0x58 length 1
Offset Values
------ ------
0x0058: fd
ethtool -e enp7s0f0 offset 0x58 length 1
Offset Values
------ ------
0x0058: ff
Все манипуляции проводить только с 1 битом, например если было значение fe
( Бинарное 11111110
) то записать следует ff
( Бинарное 11111111
)
ethtool -E enp1s0 magic 0x10fb8086 offset 0x58 value 0xff
Магическое значение можно посмотреть так:
lspci -nn | grep 82599
03:00.0 Ethernet controller [0200]: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection [8086:10fb] (rev 01)
03:00.1 Ethernet controller [0200]: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection [8086:10fb] (rev 01)
[8086:10fb]
--> 0x 10fb 8086
Что бы не возиться руками все те же манипуляции можно сделать скриптом
cat intel_x520_patcher.py
#!/usr/bin/env python3
#
# Simple Intel x520 EEPROM patcher
# Modifies the EEPROM to unlock the card for non-intel branded SFP modules.
#
# Copyright 2020,2021,2022 Andreas Thienemann <andreas@bawue.net>
#
# Licensed under the GPLv3
#
# Based on research described at https://forums.servethehome.com/index.php?threads/patching-intel-x520-eeprom-to-unlock-all-sfp-transceivers.24634/
#
# Quick explanation of what's going on:
# Looking at the Intel driver at e.g. https://elixir.bootlin.com/linux/v5.8/source/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h#L2140 we can see
# that the bit 0x1 at Address 0x58 contains a configuration setting whether the card allows any SFP modules or if Intel specific ones are enforced
# by the driver.
#
# Addr Bitstring
# 0x58 xxxxxxx0 means Intel specific SFPs
# 0x58 xxxxxxx1 means any SFP is allowed.
#
# Using the parameter allow_unsupported_sfp for the kernel module we can tell the driver to accept any SFPs.
# But this tool will flip the right bit 1 to make that change permanent in the configuration bits in the EEPROM,
# thus making kernel module parameters unnecessary.
#
import subprocess
import sys
try:
intf = sys.argv[1]
except IndexError:
print("%s <interface>" % sys.argv[0])
sys.exit(255)
try:
with open("/sys/class/net/%s/device/vendor" % intf) as f:
vdr_id = f.read().strip()
with open("/sys/class/net/%s/device/device" % intf) as f:
dev_id = f.read().strip()
except IOError:
print("Can't read interface data.")
sys.exit(2)
if vdr_id not in ('0x8086') or dev_id not in ('0x10fb', '0x154d'):
print("Not a recognized Intel x520 card.")
sys.exit(3)
output = subprocess.check_output(['ethtool', '-e', intf, 'offset', '0x58', 'length', '1'])
print(output)
v = output.strip().decode('utf-8').split('\n')
print(v)
val = output.strip().decode('utf-8').split('\n')[-1].split()[-1]
val_bin = int(val, 16)
print("EEPROM Value at 0x58 is 0x%s (%s)" % (val, bin(val_bin)))
if val_bin & 0b00000001 == 1:
print("Card is already unlocked for all SFP modules. Nothing to do.")
exit(1)
if val_bin & 0b00000001 == 0:
print("Card is locked to Intel only SFP modules. Patching EEPROM...")
new_val = val_bin | 0b00000001
print("New EEPROM Value at 0x58 will be %s (%s)" % (hex(new_val), bin(new_val)))
magic = "%s%s" % (dev_id, vdr_id[2:])
cmd = ['ethtool', '-E', intf, 'magic', magic, 'offset', '0x58', 'value', hex(new_val), 'length', 1]
print("Running %s" % " ".join(cmd))
#subprocess.call(cmd)
print("Reboot the machine for changes to take effect...")
xl710
# ./xl710_unlock -n enp4s0f0
EMP SR offset: 0x67a8
PHY offset: 0x68f6
PHY data struct size: 0x000c
MISC: 0x6b0c <- locked
MISC: 0x6b0c <- locked
MISC: 0x6b0c <- locked
MISC: 0x6b0c <- locked
Ready to fix it? [y/N]: y
Makefile
TARGETS = xl710_unlock
all: $(TARGETS)
clean:
rm -f $(TARGETS)
%: %.c
gcc -Wall -O2 $< -o $@
syscalls.h
#ifndef SYSCALLS_H
#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */
#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data. */
#define I40E_NVM_TRANS_SHIFT 8
#define I40E_NVM_TRANS_MASK (0xf << I40E_NVM_TRANS_SHIFT)
#define I40E_NVM_CON 0x0
#define I40E_NVM_SNT 0x1
#define I40E_NVM_LCB 0x2
#define I40E_NVM_SA (I40E_NVM_SNT | I40E_NVM_LCB)
#define I40E_NVM_ERA 0x4
#define I40E_NVM_CSUM 0x8
#define I40E_NVM_EXEC 0xf
struct ethtool_eeprom {
uint32_t cmd;
uint32_t magic;
uint32_t offset;
uint32_t len;
uint8_t data[0];
};
#endif
xl710_unlock.c
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <unistd.h>
#include "syscalls.h"
void die( const char *reason ) {
perror( reason );
exit( EXIT_FAILURE );
}
void print_usage( void )
{
printf( "xl710_unlock\n" );
printf( " -n <device_name>, required\n" );
printf( " -i <device_id>, default: 0x1572\n" );
printf( " -p lock/unlock\n" );
exit( EXIT_FAILURE );
}
int main(int argc, char *const *argv) {
/* Parse arguments */
char *c_devid = "0x1572";
char *c_devname = NULL;
int patching = 0;
int c;
while( ( c = getopt( argc, argv, "i:n:h?" ) ) != -1 )
{
switch( c )
{
case 'i':
c_devid = optarg;
break;
case 'n':
c_devname = optarg;
break;
case 'h':
case '?':
default:
print_usage();
break;
}
}
if( c_devname == NULL ) print_usage();
int mod = 0;
uint16_t length = 0x02;
int fd;
struct ifreq ifr;
struct ethtool_eeprom *eeprom;
const int devid = strtol( c_devid, 0, 0 );
const char *ethDev = c_devname;
fd = socket( AF_INET, SOCK_DGRAM, 0 );
if( fd == -1 ) die( "socket" );
eeprom = calloc( 1, sizeof( *eeprom ) + ( length << 1 ) );
if( !eeprom ) die( "calloc" );
eeprom->cmd = ETHTOOL_GEEPROM;
eeprom->magic = (devid << 16) | (I40E_NVM_SA << I40E_NVM_TRANS_SHIFT) | mod;
eeprom->len = length;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ethDev);
/*
Get offset to EMP SR
offset 0x48
length 0x2
*/
eeprom->offset = 0x48 << 1;
ifr.ifr_data = (void*)eeprom;
if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) die("ioctl");
uint16_t emp_offset = *(uint16_t*)(eeprom+1);
printf("EMP SR offset: 0x%04x\n", emp_offset);
/*
Get offset to PHY Capabilities 0
emp_offset + 0x19
length 0x2
*/
uint16_t cap_offset = 0x19;
eeprom->offset = (emp_offset + cap_offset) << 1;
ifr.ifr_data = (void*)eeprom;
if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) die("ioctl");
uint16_t phy_offset = *(uint16_t*)(eeprom+1) + emp_offset + cap_offset;
printf("PHY offset: 0x%04x\n", phy_offset);
/*
Get PHY data size
offset phy_offset
*/
eeprom->offset = phy_offset << 1;
ifr.ifr_data = (void*)eeprom;
if( ioctl( fd, SIOCETHTOOL, &ifr ) == -1 ) die( "ioctl" );
uint16_t phy_cap_size = *(uint16_t*)(eeprom + 1);
printf("PHY data struct size: 0x%04x\n", phy_cap_size);
/*
Get misc0
*/
uint16_t misc_offset = 0x8;
int i;
uint16_t misc0 = 0x0;
int change_count = 0;
for( i = 0; i < 4; ++i)
{
eeprom->offset = (phy_offset + misc_offset + (phy_cap_size + 1) * i) << 1;
ifr.ifr_data = (void*)eeprom;
if( ioctl( fd, SIOCETHTOOL, &ifr ) == -1 ) die( "ioctl" );
uint16_t misc = *(uint16_t*)(eeprom + 1);
printf( "MISC: 0x%04x", misc);
if( misc & 0x0800 ) printf( " <- locked\n" );
else printf( " <- unlocked\n" );
if( misc != misc0 )
{
++change_count;
misc0 = misc;
}
}
if( change_count > 1 ) die( "Different MISC's values" );
/*
Patching
*/
printf( "Ready to fix it? [y/N]: " );
char choice = getchar();
switch( choice )
{
case 'y':
case 'Y':
patching = 1;
break;
default:
patching = 0;
}
if( patching )
{
for( i = 0; i < 4; ++i)
{
eeprom->cmd = ETHTOOL_SEEPROM;
eeprom->offset = (phy_offset + misc_offset + (phy_cap_size + 1) * i) << 1;
*(uint16_t*)(eeprom + 1) = misc0 ^ 0x0800;
ifr.ifr_data = (void*)eeprom;
if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) die("write");
sleep(1);
}
// update checksum
eeprom->cmd = ETHTOOL_SEEPROM;
eeprom->magic = (devid << 16) | ((I40E_NVM_CSUM|I40E_NVM_SA) << I40E_NVM_TRANS_SHIFT) | mod;
eeprom->len = 2;
eeprom->offset = 0;
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_name, ethDev);
ifr.ifr_data = (void*)eeprom;
if (ioctl(fd, SIOCETHTOOL, &ifr) == -1) die("checksum");
}
return 0;
}