Чтение SCSI (10) и запись (10) с помощью универсального интерфейса SCSI

Я пытаюсь выполнить команду scsi read(10) и запись(10) на SSD. Я использую этот пример кода в качестве справочного/базового кода.

Это мое чтение scsi:

#define READ_REPLY_LEN 32
#define READ_CMDLEN 10
void scsi_read()
{
  unsigned char Readbuffer[ SCSI_OFF + READ_REPLY_LEN ];
  unsigned char cmdblk [ READ_CMDLEN ] =
      {        0x28,  /* command */
                  0,  /* lun/reserved */
                  0,  /* lba */
                  0,  /* lba */
                  0,  /* lba */
                  0,  /* lba */
                  0,  /* reserved */
                  0,  /* transfer length */
     READ_REPLY_LEN,  /* transfer length */
                  0 };/* reserved/flag/link */
  memset(Readbuffer,0,sizeof(Readbuffer));
  memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) );

  /*
   * +------------------+
   * | struct sg_header | <- cmd
   * +------------------+
   * | copy of cmdblk   | <- cmd + SCSI_OFF
   * +------------------+
   */

  if (handle_scsi_cmd(sizeof(cmdblk), 0, cmd,
                      sizeof(Readbuffer) - SCSI_OFF, Readbuffer )) {
      fprintf( stderr, "read failed\n" );
      exit(2);
  }
  hex_dump(Readbuffer,sizeof(Readbuffer));
}

И это мой scsi пишет:

void scsi_write ( void )
{
  unsigned char Writebuffer[SCSI_OFF];
  unsigned char cmdblk [] =
      {        0x2A,  /* 0: command */
                  0,  /* 1: lun/reserved */
                  0,  /* 2: LBA */
                  0,  /* 3: LBA */
                  0,  /* 4: LBA */
                  0,  /* 5: LBA */
                  0,  /* 6: reserved */
                  0,  /* 7: transfer length */
                  0,  /* 8: transfer length */
                  0 };/* 9: control */

  memset(Writebuffer,0,sizeof(Writebuffer));
  memcpy( cmd + SCSI_OFF, cmdblk, sizeof(cmdblk) );
  cmd[SCSI_OFF+sizeof(cmdblk)+0] = 'A';
  cmd[SCSI_OFF+sizeof(cmdblk)+1] = 'b';
  cmd[SCSI_OFF+sizeof(cmdblk)+2] = 'c';
  cmd[SCSI_OFF+sizeof(cmdblk)+3] = 'd';
  cmd[SCSI_OFF+sizeof(cmdblk)+4] = 'e';
  cmd[SCSI_OFF+sizeof(cmdblk)+5] = 'f';
  cmd[SCSI_OFF+sizeof(cmdblk)+6] = 'g';
  cmd[SCSI_OFF+sizeof(cmdblk)+7] = 0;
  /*
   * +------------------+
   * | struct sg_header | <- cmd
   * +------------------+
   * | copy of cmdblk   | <- cmd + SCSI_OFF
   * +------------------+
   * | data to write    | 
   * +------------------+
   */

  if (handle_scsi_cmd(sizeof(cmdblk), 8, cmd, 
                      sizeof(Writebuffer) - SCSI_OFF, Writebuffer )) {
      fprintf( stderr, "write failed\n" );
      exit(2);
  }
}

В следующем примере я делаю

  1. scsi читать
  2. scsi написать
  3. scsi читать

И я печатаю шестнадцатеричные дампы данных, которые записываются (запись scsi) и считываются (чтение scsi)

Read(10)
[0000]   00 00 00 44 00 00 00 44   00 00 00 00 00 00 00 00   ...D...D ........
[0010]   00 2C 00 00 00 00 00 00   00 00 00 00 00 00 00 00   ........ ........
[0020]   00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00   ........ ........
[0030]   00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00   ........ ........
[0040]   00 00 00 00                                         ....

Write(10):
[0000]   00 00 00 00 00 00 00 24   00 00 00 00 00 00 00 00   ........ ........
[0010]   00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00   ........ ........
[0020]   00 00 00 00 2A 00 00 00   00 00 00 00 00 00 41 62   ........ ......Ab
[0030]   63 64 65 66 67 00                                   cdefg.

Read(10):
[0000]   00 00 00 44 00 00 00 44   00 00 00 00 00 00 00 00   ...D...D ........
[0010]   04 00 20 00 70 00 02 00   00 00 00 0A 00 00 00 00   ....p... ........
[0020]   04 00 00 00 41 62 63 64   65 66 67 00 00 00 00 00   ....Abcd efg.....
[0030]   00 00 00 00 00 00 00 00   00 00 00 00 00 00 00 00   ........ ........
[0040]   00 00 00 00                                         ....

после повторного запуска трех команд я должен прочитать Abcdefg при первом чтении. Верно? Но запуск их снова ничего не меняет. Теперь вы можете предположить, что используемая мной память все еще содержит данные из предыдущих функций, но я получаю тот же результат, даже если запускаю memset(Readbuff,0,sizeof(Readbuff)) до того, как произойдет sys_read().

Я предположил, что LBA, который я пытаюсь записать, возможно, запрещен для записи, и я прочитал кеш. Но взаимодействие по LBA-адресам от 0x00-0xFF ничего не меняет - значит, я читаю одни и те же данные (Abcdefg).

Вы знаете пример реализации чтения или записи scsi с помощью универсального интерфейса scsi?


person samuirai    schedule 08.08.2012    source источник


Ответы (1)


В SCSI единицы LBA и длины передачи представлены в блоках, иногда называемых секторами. Это почти всегда 512 байт. Таким образом, вы не можете прочитать или записать только 32 байта. Как минимум, вам нужно будет сделать 512 байт == один блок. Этот единственный момент — большая часть того, что вам нужно исправить.

Ваша длина передачи равна нулю в вашей реализации scsi_write, поэтому на самом деле она не будет записывать никаких данных.

Вы должны использовать разные буферы для CDB и данных записи/чтения. Я подозреваю, что путаница с этими буферами приводит к тому, что ваша реализация записывает за конец одного из ваших статически выделенных массивов и за ваш ReadBuffer. Запустите его под valgrind и посмотрите, что появится.

И, наконец, многое может пойти не так в том, что находится в handle_scsi_cmd. Настроить передачу данных может быть сложно... в частности, убедитесь, что вы правильно понимаете, в каком направлении данные идут в dxfer_direction заголовка ввода-вывода: SG_DXFER_TO_DEV для записи, SG_DXFER_FROM_DEV для чтения.

Посмотрите этот пример того, как выполнить чтение (16). Это больше похоже на то, чего вы пытаетесь достичь.

https://github.com/hreinecke/sg3_utils/blob/master/examples/sg_simple16.c

person Mike Andrews    schedule 10.08.2012
comment
большое спасибо. Мне очень помог пример sg3_utils, и теперь он работает. - person samuirai; 13.08.2012