Pull to refresh

Пробрасывание LTO-1 стримера по iSCSI, проблемы и решения

Reading time11 min
Views2.7K
imageПосле просмотра серии видеороликов «Данные на магнитной ленте» от Макс “Fagear” Крюков. Захотелось себе приобрести, что-нибудь из стримеров. Требование было чтобы оно ещё работало, стоило не как крыло самолета. И было вполне годно не только чтобы проиграться. Порывшись на барахолках, был найден стример HP LTO-1, со SCSI контроллером и кучей картриджей небольшой юзаности. Подключил к компу, погонял стандартной XPшной прогой для бэкапов. Всё работает всё хорошо. Но выяснилась одна проблема, слоты PCI на материнке расположены так, что две PCI карты туда нормально не воткнуть. А убирать X-Fi не хотелось, к тому же SCSI контроллер греется, и желательно бы его охлаждать, а это лишний шум который не нужен. Было принято решение поставить стример в другой комп(благо ненужных комплектующих хватает). Поставить Linux, и пробросить стример по iSCSI. А уже включать по мере необходимости, или вообще держать там, где шума не слышно. Опыт работы с iSCSI был, всё должно было заработать без сучка и без задоринки.

Попытка первая SCST


Уже около семи лет я использую SCST для проброски жестких дисков или их образов по iSCSI. Проблем никогда не было. Более того, там есть модуль, заточенный под проброску стримеров. Настраиваю конфиг, запускаю. Подключаюсь по iSCSI, устройство находится, жизнь прекрасна. Но попытка записать, что-либо на картридж вызывает ошибку.

Попытка заглянуть в исходники, успехом не увенчалось. Как работает SCSI, я примерно знаю. Но как оно работает в ядре Linux это для меня загадка. И пока разбираться необходимости не было. В целом я отыскал, где пересылаются команды. Но там было много не очень понятных мест. Ну и к тому же SCST явно делал не всегда то, что его просили. Например если команда завершалась ошибкой мог по своему усмотрению послать доп.команды для уточнения ошибки. А разбираться в таком без крайней необходимости, то ещё удовольствие.
В итоге решил поискать другое решение, попроще.

Попытка вторая TGT(STGT)


На сайте же SCST было найдено сравнение других вариантов iSCSI target. Поддержка SCSI pass-through была у SCST, STGT и LIO/TCM. SCST отпал из за неработоспособности(ну или кривых рук). Про LIO/TCM я мало что слышал, с STGT вроде бы, когда-то работал. Ну, плюс ко всему LIO/TCM был kernel-mode, что в случае дебага сразу бы усложнило задачу. А вот STGT полностью UserSpace, что обещает ниже производительность, но и меньше проблем в случае дебага.

Почитал документацию проброска устройства выполняется через модуль bs_sg, который работает с SG(SCSI Generic) устройствами. То есть по факту ему всё равно, с чем работать, что внушало надежды. Скомпилировалось и запустилось всё без проблем. Настроил проброс SG устройства.

./tgtadm --lld iscsi --op new --mode target --tid 1 -T iqn.2022-03.home.storage:storage.streamers.org
./tgtadm --lld iscsi --op new --mode logicalunit --tid 1 --lun 1 --bstype=sg --device-type=pt -b /dev/sg1
./tgtadm --lld iscsi --op bind --mode target --tid 1 -I ALL

Подключился инициатором, система увидела стример, попытка записать в NTBackup завершилась успешно. Казалось бы победа!

Но как гласит одно из правил бэкапов, тестируйте резервные копии. Пытаемся прочитать записанное на ленту. И получаем облом, система говорит, мол, не тот картридж воткнут, и выплевывает его.


Подключил стример напрямую к компу, данные восстанавливаются нормально, контрольные суммы сходятся. Вернул на iSCSI говорит не тот картридж вставлен.

Дебаг так дебаг


Посмотрев код bs_sg.c был приятно удивлен, всё написано просто и понятно. Главное внимательно читать и не путать функции bsg и sg. Судя по коду было две интересные функции:

static int bs_sg_cmd_submit(struct scsi_cmd *cmd)
static void bs_sg_cmd_complete(int fd, int events, void *data)

Первая принимает команду и пересылает её SG устройству, вторая вызывается, когда команда обработана и отсылает результат запросившему. Теперь надо было понять, что не так и как это решить. Для этого надо разобраться, как из винды слать SCSI команды, и как тоже самое делать из линукса чтобы можно было сравнить вызовы и результаты. В винде за это отвечает SPTI(по крайней мере, в XP дальше пока было неинтересно). Как с ним работать можно почитать в статье RSDN Укрощение строптивого… CD-ROM. Как работать с SG устройствами частично описано здесь.

Пришло время заняться отладкой, дебагер вещь хорошая, но тут хотелось обойтись банальными printf. Хотя бы на первом этапе. Функция bs_sg_cmd_complete была изменена так, чтобы выводить на экран, что посылали SG устройству, и что оно вернуло.

Код получившейся функции
static void bs_sg_cmd_complete(int fd, int events, void *data)
{
    struct sg_io_hdr io_hdr;
    struct scsi_cmd *cmd;
    int err;
    uint32_t actual_len;

    memset(&io_hdr, 0, sizeof(io_hdr));
    io_hdr.interface_id = 'S';
    io_hdr.pack_id = -1;

    err = graceful_read(fd, &io_hdr, sizeof(io_hdr));
    if (err)
        return;

    cmd = (struct scsi_cmd *)io_hdr.usr_ptr;

    printf("CDB:");
    for(uint8_t i=0; i < cmd->scb_len; i++){
        printf("%02X ", cmd->scb[i]);
    }

    printf("STATUS: %02X, LEN: %02X ", io_hdr.status, io_hdr.dxfer_len - io_hdr.resid);

    printf("SENS[%d]:", io_hdr.sb_len_wr);
    for(uint8_t i=0; i<io_hdr.sb_len_wr; i++){
        printf("%02X ", io_hdr.sbp[i]);
    }
    printf("\r\n");

    if (!io_hdr.status) {
        actual_len = io_hdr.dxfer_len - io_hdr.resid;
    } else {
        /* NO SENSE | ILI (Incorrect Length Indicator) */
        if (io_hdr.sbp[2] == 0x20)
            actual_len = io_hdr.dxfer_len - io_hdr.resid;
        else
            actual_len = 0;

        cmd->sense_len = io_hdr.sb_len_wr;

    }


    if (!actual_len || io_hdr.resid) {
        if (io_hdr.dxfer_direction == SG_DXFER_TO_DEV)
            scsi_set_out_resid_by_actual(cmd, actual_len);
        else
            scsi_set_in_resid_by_actual(cmd, actual_len);
    }

    target_cmd_io_done(cmd, io_hdr.status);
}

  


Запускаем пробуем прочитать данные с ленты и смотрим на полученный лог(удалены команды check condition(0x00)):

Лог последовательности команд
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:1B 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:1E 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:1A 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 0C SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:1A 00 10 00 1C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 1C SENS[0]:
CDB:1A 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 0C SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:1A 08 10 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:1A 08 0F 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 06 SENS[0]:
CDB:1A 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 0C SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:15 10 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 0C SENS[0]:
CDB:1A 08 10 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:1A 08 0F 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 06 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:1A 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 0C SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:1A 08 10 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:1A 08 0F 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 06 SENS[0]:
CDB:1A 08 10 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:1A 08 0F 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 06 SENS[0]:
CDB:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:
CDB:1A 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 0C SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:08 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 02, LEN: 400 SENS[22]:F0 00 80 00 00 01 FE 0E 00 00 00 00 00 01 00 00 30 21 00 00 00 00
CDB:1A 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 0C SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:1A 08 10 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:1A 08 0F 00 14 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 14 SENS[0]:
CDB:05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 06 SENS[0]:
CDB:1A 00 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 0C SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:15 10 00 00 0C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 0C SENS[0]:
CDB:01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:
CDB:4D 00 31 00 00 00 00 00 3C 00 00 00 00 00 00 00 STATUS: 00, LEN: 24 SENS[0]:
CDB:1A 00 10 00 1C 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 1C SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:1E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:03 00 00 00 16 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 16 SENS[0]:
CDB:1E 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:
CDB:1B 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 00, LEN: 00 SENS[0]:


Первый байт CDB это номер SCSI команды, со списком можно ознакомиться здесь. Статус показывает, успешность окончания команды:

00h GOOD
02h CHECK CONDITION
04h CONDITION MET
08h BUSY
18h RESERVATION CONFLICT
28h TASK SET FULL
30h ACA ACTIVE
40h TASK ABORTED

SENS соответственно дополнительная информация о ошибке с которой завершилась команда.
Почти все команды носят информационный характер, чтения ошибок, чтение объема картриджа, итд.

И все выполняются без ошибок кроме команды 08 (READ(6)). Попробовал посмотреть, что возвращается при выполнении этой команды из винды. Плюс это единственная команда, которая что-то читает с реальной ленты. Набросал простую программку:

Код программы для теста
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winioctl.h>
#include <ntddscsi.h>

#define SPT_CDB_LENGTH 32
#define SPT_SENSE_LENGTH 32
#define SPTWB_DATA_LENGTH 32768

#define offsetof(st, m) \
((size_t)&(((st *)0)->m))

#pragma pack(push, mode_params, 1)
typedef struct _MODE_PARAMETER_HEADER {
UCHAR ModeDataLength;
UCHAR MediumType;
UCHAR DeviceSpecificParameter;
UCHAR BlockDescriptorLength;
}MODE_PARAMETER_HEADER, *PMODE_PARAMETER_HEADER;
#pragma pack(pop, mode_params)

#pragma pack(push, mode_params_block, 1)
typedef struct _MODE_PARAMETER_BLOCK {
UCHAR DensityCode;
UCHAR NumberOfBlocks[3];
UCHAR Reserved;
UCHAR BlockLength[3];
}MODE_PARAMETER_BLOCK, *PMODE_PARAMETER_BLOCK;
#pragma pack(pop, mode_params_block)

typedef struct _MODE_DEVICE_CONFIGURATION_PAGE {

UCHAR PageCode : 6;
UCHAR Reserved1 : 1;
UCHAR PS : 1;
UCHAR PageLength;
UCHAR ActiveFormat : 5;
UCHAR CAFBit : 1;
UCHAR CAPBit : 1;
UCHAR Reserved2 : 1;
UCHAR ActivePartition;
UCHAR WriteBufferFullRatio;
UCHAR ReadBufferEmptyRatio;
UCHAR WriteDelayTime[2];
UCHAR REW : 1;
UCHAR RBO : 1;
UCHAR SOCF : 2;
UCHAR AVC : 1;
UCHAR RSmk : 1;
UCHAR BIS : 1;
UCHAR DBR : 1;
UCHAR GapSize;
UCHAR Reserved3 : 3;
UCHAR SEW : 1;
UCHAR EEG : 1;
UCHAR EODdefined : 3;
UCHAR BufferSize[3];
UCHAR DCAlgorithm;
UCHAR Reserved4;

} MODE_DEVICE_CONFIGURATION_PAGE, *PMODE_DEVICE_CONFIGURATION_PAGE;

typedef struct _MODE_DEVICE_CONFIG_PAGE_PLUS {

MODE_PARAMETER_HEADER ParameterListHeader;
MODE_PARAMETER_BLOCK ParameterListBlock;
MODE_DEVICE_CONFIGURATION_PAGE DeviceConfigPage;

} MODE_DEVICE_CONFIG_PAGE_PLUS, *PMODE_DEVICE_CONFIG_PAGE_PLUS ;

typedef struct _SCSI_PASS_THROUGH_WITH_BUFFERS {
SCSI_PASS_THROUGH spt;
ULONG Filler; // realign buffers to double word boundary
UCHAR ucSenseBuf[SPT_SENSE_LENGTH];
UCHAR ucDataBuf[SPTWB_DATA_LENGTH];
} SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS;

SCSI_PASS_THROUGH_WITH_BUFFERS spti;
SCSI_INQUIRY_DATA inq;
int main(){
ULONG length = 0,
errorCode = 0,
returned = 0,
sectorSize = 512;
BOOL status = 0;
int i;
HANDLE x;
PMODE_DEVICE_CONFIG_PAGE_PLUS configInformation;

FILE * file;
x = CreateFileA("\\\\.\\tape0",
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0 , NULL);

ZeroMemory(&spti,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));
spti.spt.Length = sizeof(SCSI_PASS_THROUGH);
spti.spt.PathId = 0;
spti.spt.TargetId = 1;
spti.spt.Lun = 0;
spti.spt.CdbLength = 6;
spti.spt.SenseInfoLength = SPT_SENSE_LENGTH;
spti.spt.DataIn = SCSI_IOCTL_DATA_IN;
spti.spt.DataTransferLength = 0x200;//sizeof(spti.ucDataBuf);
spti.spt.TimeOutValue = 2;
spti.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf);
spti.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucSenseBuf);
spti.spt.Cdb[0] = 0x08;
spti.spt.Cdb[1] = 0x01;
spti.spt.Cdb[2] = 0x00;
spti.spt.Cdb[3] = 0x02;
spti.spt.Cdb[4] = 0x00;
spti.spt.Cdb[5] = 0x00;

length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS,ucDataBuf) + spti.spt.DataTransferLength;
memset(spti.ucSenseBuf, 0xFF, sizeof(spti.ucSenseBuf));\
status = DeviceIoControl(x, IOCTL_SCSI_PASS_THROUGH,
&spti,
sizeof(SCSI_PASS_THROUGH),
&spti,
length,
&returned,
FALSE);

printf("STATUS: %d[%02X]\r\n", status, spti.spt.ScsiStatus);

printf("DATA[%d]:", spti.spt.DataTransferLength);
for(i=0; i<spti.spt.DataTransferLength && i < 15; i++){
printf("%02X ", spti.ucDataBuf[i]);
}
printf("\r\n");

printf("SENS[%d]:", spti.spt.SenseInfoLength);
for(i=0; i<spti.spt.SenseInfoLength; i++){
printf("%02X ", spti.ucSenseBuf[i]);
}
printf("\r\n");

return 0;
}


Запускаю и что мы видим:

STATUS: 1[02]
DATA[0]:
SENS[22]:70 00 05 00 00 00 00 0E 00 00 00 00 24 00 00 C8 00 01 00 00 00 00

Сравниваем с оригиналом:
CDB:08 01 00 02 00 00 00 00 00 00 00 00 00 00 00 00 STATUS: 02, LEN: 400 SENS[22]:F0 00 80 00 00 01 FE 0E 00 00 00 00 00 01 00 00 30 21 00 00 00 00

Статус совпадает, SENS совпадает. Но при работе с SG он сказал, что вернул 0x400 байт данных, а SPTI нам говорит, что данных она не получила. Интересно, посмотрим код внимательней, в поисках кто на это мог повлиять. И видим кусок:

    if (!io_hdr.status) {
        actual_len = io_hdr.dxfer_len - io_hdr.resid;
    } else {
        /* NO SENSE | ILI (Incorrect Length Indicator) */
        if (io_hdr.sbp[2] == 0x20)
            actual_len = io_hdr.dxfer_len - io_hdr.resid;
        else
            actual_len = 0;
 
        cmd->sense_len = io_hdr.sb_len_wr;

    }

Итак, если статус GOOD то читаем размер данных из того что нам вернул SG, если же нет то проверяем третий байт SENS на константу 0x20. И если это так то берем размер данных из SG, а если нет, то возвращаем 0. Смотрим наш случай и видим третий байт у нас 0x80 то есть код работает правильно. Но делает ли он то, что нужно? Посмотрим, что такое же значат все эти циферки в SENS. Самое понятное, что я смог найти, это был документ от Oracle описывающий команды LTO5(о нем может быть позже) стримера docs.oracle.com/cd/E21419_04/en/LTO5_Vol3_E5b/LTO5_Vol3_E5b.pdf



И тут мы видим что третий байт это комбинированное поле содержащее три флага:
Mark(или FMK) - при чтении блока мы встретили признак конца блока данных.
EOM - Мы писали данные, и дошли до конца носителя
ILI - Мы хотели прочитать наприме 1024 байт, а выставлен режим чтения по 512 байт.

И поля SENS CODE которое уточняет что случилось. В нашем случае оно «0», что по описанию:



И вообще это не ошибка, а просто информация.

Получаем, что выше указанный код явно не очень корректно работает. Так как флаг FMK/EOM он не обрабатывает должным образом, к тому же SENS CODE тоже игнорируется. И главный вопрос, что он вообще тут делает. Возможно, он обрабатывал какую то старую ошибку. Или возможно просто тот, кто писал не до конца разобрался с этими кодами. Но по мне код делал лишнюю работу, и искажал данные, передаваемые между SG и iSCSI.

Меняем все эти условия на такой кусок:

actual_len = io_hdr.dxfer_len - io_hdr.resid;
cmd->sense_len = io_hdr.sb_len_wr;

Компилируем, запускаем, работает.


Данные восстанавливаются. Проверил, хэш файла совпал с оригиналом. Отлично. Осталось последнее, отдать патч назад в опенсорс. Может, кому пригодится. Ну или хотя бы объяснят, почему так делать не надо, и для чего были все эти проверки. Самый простой способ оказался через гитхаб. Заслать пулл реквест автору проекта. Так и было сделано. Как не странно в этот раз всё прошло замечательно, уже на следующий день патч был принят, и смержен с основной веткой проекта. И теперь такая, казалось бы, тривиальная вещь, как проброска SCSI устройства через iSCSI стала более тривиальной.
Tags:
Hubs:
Total votes 13: ↑13 and ↓0+13
Comments12

Articles