cmodelhard-driveserial-numberscsi

scsi inquiry commands to get serial and model information


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

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!