Question

I have problems getting serial and model information from SCSI drives via an inquiry. My inquiry always returns empty strings.

Here is a quick and dirty code of the inquiry which should at least output the entire return of the inquiry. The output isn't formatted to really get specific information, but it should still work. But it doesn't.

#define          DRIVEAMOUNT                20
#define          MODELINQUIRY               0x12,0x00,0x00,0x00,0x4A,0x00     /* SCSI command for standard inquiry*/
#define          SERIALINQUIRY              0x12,0x01,0x80,0x00,0x60,0x00     /* SCSI command for VPD inquiry page 0x80 for serial number */

/* used libraries */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <scsi/sg.h>
#include <inttypes.h>

/* send scsi command and recieve output, designed for use with *ONLY* an inquiry command but might work with more than only inquiry*/
int SCSI_sendcmd(uint64_t sg_fd, unsigned char *cmdblk, char *output) {
    unsigned char reply_buffer[96];
    sg_io_hdr_t  io_hdr;
    int i;

    /* Send INQUIRY command */
    memset(&io_hdr,0,sizeof(sg_io_hdr_t));
    io_hdr.interface_id='S';
    io_hdr.dxfer_direction=SG_DXFER_FROM_DEV;
    io_hdr.dxfer_len=sizeof(reply_buffer);
    io_hdr.dxferp=reply_buffer;
    io_hdr.cmd_len=sizeof(cmdblk);
    io_hdr.cmdp=cmdblk;
    io_hdr.timeout=1000;

    if (ioctl(sg_fd,SG_IO,&io_hdr)<0) {return 3;}   /* cannot send inquiry command */

    if ((io_hdr.info&SG_INFO_OK_MASK)!=SG_INFO_OK) {return 2;}  /* inquiry command failed */

    for (i=0;i<96;i++) {
       output[i]=reply_buffer[i];
    }
    return 1; /*succes*/
}

int main () {
    /* initialize various vars.*/
    FILE                                    *driveptr; 

    int                                     i;

    char                                    OSpointer[9];

    unsigned char                           output1[96],
                                            output2[96],
                                            serialinq[6]={SERIALINQUIRY},                          /* var to store SCSI inquiry for serial number */
                                            modelinq[6]={MODELINQUIRY};                            /* var to store SCSI inquiry for model string */

    for (i=0;i<DRIVEAMOUNT;i++) {
        strcpy(OSpointer,"/dev/sdX");
        OSpointer[7]='a'+i;

        driveptr=fopen(OSpointer,"r");
        if (driveptr==NULL) {
            continue;
        }

        if (SCSI_sendcmd(fileno(driveptr),modelinq,output1)==1)  {printf("model:|%s|\n",output1);}
        if (SCSI_sendcmd(fileno(driveptr),serialinq,output2)==1) {printf("serial:|%s|\n",output2);}
        printf("\n");

        fclose(driveptr);
    } 
}
Was it helpful?

Solution

early parts of the string have terminating('\0') characters, %s only prints out until such a character is reached! either removing them or printing out each char in a loop!

OTHER TIPS

for (i=0;i<96;i++) {
       output[i]=reply_buffer[i];
}

should start at reply_buffer[4]

Using a debugger for SCSI_sendcmd() to inspect the contents of replay_buffer or output would have shown how the result looks like. Example (gdb):

(gdb) n
34         output[i]=reply_buffer[i];
(gdb) p reply_buffer 
$2 = "\000\000\005\002[\000\000\000ATA     WDC WD7500AVDS-60A01", '\000' <repeats 23 times>, "`\003 \002`", '\000' <repeats 31 times>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top