Read SCSI (10) and write (10) using the common SCSI interface

I am trying to get scsi to read (10) and write (10) on an SSD. I am using this sample code as reference / base code.

This is my 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)); } 

And this is my scsi writes:

 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); } } 

In the following example, I do

  • scsi read
  • scsi write
  • scsi read

And I print hexdumps of data that is written (scsi write) and read (scsi read)

 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 .... 

running the three commands again, I have to read Abcdefg with the first read. Right? But launching them again does not change anything. Now you can assume that the memory I use still contains data from previous functions, but I get the same result even if I run memset(Readbuff,0,sizeof(Readbuff)) before sys_read() happens.

I suggested that the LBA I am trying to write may not be allowed to write, and I am reading the cache. But interacting with LBA addresses from 0x00-0xFF does not change anything - that means I am reading the same data ( Abcdefg ).

Do you know an example scsi implementation for reading or writing using the scsi common interface?

+6
source share
1 answer

In SCSI, LBA units and transmission lengths are in blocks, sometimes called sectors. This is almost always 512 bytes. Thus, you cannot read or write only 32 bytes. At a minimum, you have to do 512 bytes == one block. This is one of the things you need to fix.

The length of your transfer is zero in your scsi_write implementation, so it is not going to write any data.

You must use different buffers for CDB and write / read data. I suspect that confusion with these buffers forces your implementation to write after the end of one of your statically distributed arrays and on top of your ReadBuffer. Run it under Valgrind and see what appears.

And finally, a lot can go wrong as it is in handle_scsi_cmd. It can be difficult to set up data transfer ... in particular, make sure you know exactly what direction the data goes in the dxfer_direction I / O header: SG_DXFER_TO_DEV for writing, SG_DXFER_FROM_DEV for reading.

Check out this example of how to do a read (16). It is more like what you are trying to achieve.

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

+4
source

Source: https://habr.com/ru/post/922373/


All Articles