SCSI inquiry to get storage device serial number

  • Follow


Hi,

I'm trying to get the serial number of a storage device. I've tried
sg3_utils and sg_inq does this. I tried calling the functions within
the sg3 source files, but I can't seem to build it even after
including the relevant header files.

I've also tried forming my own SCSI inquiry CDB and sending it to the
device, but I only seem to get the vendor ID and product ID, no serial
number and other information.

Does anyone know how to use the functions within sg3_utils, or how to
obtain the serial number?

Thanks!
0
Reply galapogos 6/8/2009 3:17:16 AM

galapogos wrote:
> 
> I'm trying to get the serial number of a storage device. I've tried
> sg3_utils and sg_inq does this. I tried calling the functions within
> the sg3 source files, but I can't seem to build it even after
> including the relevant header files.

You have to link against "libsgutils". Copy the following files:
- .libs/libsgutils.a
- sg_cmds.h
- sg_include.h
- sg_lib.h
- sg_inq.c

.... and build a binary like this:
gcc -o sg_inq sg_inq.c -lsgutils

Now you can strip down "sg_inq.c" to your needs.

> I've also tried forming my own SCSI inquiry CDB and sending it to the
> device, but I only seem to get the vendor ID and product ID, no serial
> number and other information.

The Standard Inquiry Data don't contain the serial number, you have to
readout the "Vital Product Data" page 0x80. For details look at the SPC
document.

> Does anyone know how to use the functions within sg3_utils, or how to
> obtain the serial number?

Example:
----------------------------------------------------------------------
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <scsi/sg.h>

int  main(void)
{
   const char  devicefile[] = "/dev/sg1";
   const char*  file_name = NULL;
   int  sg_fd;
   unsigned char  reply_buffer[96];
   unsigned char  sense_buffer[32];
   sg_io_hdr_t  io_hdr;
   unsigned char  inquiry[6]
    = {0x12, 0x01, 0x80, 0x00, sizeof(reply_buffer), 0x00};
   int  i;

   /* Open device file */
   file_name = devicefile;
   printf("\nGet Type & SN from device file: %s\n\n", file_name);
   if ((sg_fd = open(file_name, O_RDWR | O_EXCL)) < 0)
   {
      fprintf(stderr, "Cannot open devicefile!\n\n");
      exit(1);
   }

   /* 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.mx_sb_len = sizeof(sense_buffer);
   io_hdr.sbp = sense_buffer;
   io_hdr.dxfer_len = sizeof(reply_buffer);
   io_hdr.dxferp = reply_buffer;
   io_hdr.cmd_len = sizeof(inquiry);
   io_hdr.cmdp = inquiry;
   io_hdr.timeout = 1000;  /* Miliseconds */
   if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
   {
      fprintf(stderr, "Cannot send INQUIRY command!\n\n");
      exit(1);
   }
   if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)
   {
      fprintf(stderr, "INQUIRY command failed!\n");
      if (io_hdr.sb_len_wr > 0)
      {
         printf("Sense data: ");
         for (i = 0; i < io_hdr.sb_len_wr; i++)
         {
            printf("0x%02X ", sense_buffer[i]);
         }
         printf("\n");
      }
      exit(1);
   }

   /* Extract SN */
   if (reply_buffer[1] != 0x80)
   {
      fprintf(stderr, "Unit serial number page invalid!\n\n");
      exit(1);
   }
   printf("Device type: 0x%02X\n", reply_buffer[1] & 0x1F);
   printf("Serial number: ");
   for (i = 4; i < reply_buffer[3] + 4; i++)
   {
      printf("%c", reply_buffer[i]);
   }
   printf("\n\n");
   exit(0);
}
----------------------------------------------------------------------
You want to tune the error handling. ILLEGAL REQUEST may occur and it
must not be a real error because VPD page support was not mandatory (or
not specified at all) in older SCSI revisions.

The output from my example should look like this for a disk [1]:
----------------------------------------------------------------------
$ ./getsn 

Get Type & SN from device file: /dev/sg1

Device type: 0x00
Serial number:         AJF61666
----------------------------------------------------------------------


Micha

[1] http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
0
Reply Michael 6/8/2009 9:09:18 AM


On Jun 8, 5:09=A0pm, Michael Baeuerle <michael.baeue...@stz-e.de> wrote:
> galapogos wrote:
>
> > I'm trying to get the serial number of a storage device. I've tried
> > sg3_utils and sg_inq does this. I tried calling the functions within
> > the sg3 source files, but I can't seem to build it even after
> > including the relevant header files.
>
> You have to link against "libsgutils". Copy the following files:
> - .libs/libsgutils.a
> - sg_cmds.h
> - sg_include.h
> - sg_lib.h
> - sg_inq.c
>
> ... and build a binary like this:
> gcc -o sg_inq sg_inq.c -lsgutils
>
> Now you can strip down "sg_inq.c" to your needs.
>
> > I've also tried forming my own SCSI inquiry CDB and sending it to the
> > device, but I only seem to get the vendor ID and product ID, no serial
> > number and other information.
>
> The Standard Inquiry Data don't contain the serial number, you have to
> readout the "Vital Product Data" page 0x80. For details look at the SPC
> document.
>
> > Does anyone know how to use the functions within sg3_utils, or how to
> > obtain the serial number?
>
> Example:
> ----------------------------------------------------------------------
> #include <stdlib.h>
> #include <unistd.h>
> #include <fcntl.h>
> #include <stdio.h>
> #include <string.h>
> #include <sys/ioctl.h>
> #include <sys/types.h>
> #include <scsi/sg.h>
>
> int =A0main(void)
> {
> =A0 =A0const char =A0devicefile[] =3D "/dev/sg1";
> =A0 =A0const char* =A0file_name =3D NULL;
> =A0 =A0int =A0sg_fd;
> =A0 =A0unsigned char =A0reply_buffer[96];
> =A0 =A0unsigned char =A0sense_buffer[32];
> =A0 =A0sg_io_hdr_t =A0io_hdr;
> =A0 =A0unsigned char =A0inquiry[6]
> =A0 =A0 =3D {0x12, 0x01, 0x80, 0x00, sizeof(reply_buffer), 0x00};
> =A0 =A0int =A0i;
>
> =A0 =A0/* Open device file */
> =A0 =A0file_name =3D devicefile;
> =A0 =A0printf("\nGet Type & SN from device file: %s\n\n", file_name);
> =A0 =A0if ((sg_fd =3D open(file_name, O_RDWR | O_EXCL)) < 0)
> =A0 =A0{
> =A0 =A0 =A0 fprintf(stderr, "Cannot open devicefile!\n\n");
> =A0 =A0 =A0 exit(1);
> =A0 =A0}
>
> =A0 =A0/* Send INQUIRY command */
> =A0 =A0memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
> =A0 =A0io_hdr.interface_id =3D 'S';
> =A0 =A0io_hdr.dxfer_direction =3D SG_DXFER_FROM_DEV;
> =A0 =A0io_hdr.mx_sb_len =3D sizeof(sense_buffer);
> =A0 =A0io_hdr.sbp =3D sense_buffer;
> =A0 =A0io_hdr.dxfer_len =3D sizeof(reply_buffer);
> =A0 =A0io_hdr.dxferp =3D reply_buffer;
> =A0 =A0io_hdr.cmd_len =3D sizeof(inquiry);
> =A0 =A0io_hdr.cmdp =3D inquiry;
> =A0 =A0io_hdr.timeout =3D 1000; =A0/* Miliseconds */
> =A0 =A0if (ioctl(sg_fd, SG_IO, &io_hdr) < 0)
> =A0 =A0{
> =A0 =A0 =A0 fprintf(stderr, "Cannot send INQUIRY command!\n\n");
> =A0 =A0 =A0 exit(1);
> =A0 =A0}
> =A0 =A0if ((io_hdr.info & SG_INFO_OK_MASK) !=3D SG_INFO_OK)
> =A0 =A0{
> =A0 =A0 =A0 fprintf(stderr, "INQUIRY command failed!\n");
> =A0 =A0 =A0 if (io_hdr.sb_len_wr > 0)
> =A0 =A0 =A0 {
> =A0 =A0 =A0 =A0 =A0printf("Sense data: ");
> =A0 =A0 =A0 =A0 =A0for (i =3D 0; i < io_hdr.sb_len_wr; i++)
> =A0 =A0 =A0 =A0 =A0{
> =A0 =A0 =A0 =A0 =A0 =A0 printf("0x%02X ", sense_buffer[i]);
> =A0 =A0 =A0 =A0 =A0}
> =A0 =A0 =A0 =A0 =A0printf("\n");
> =A0 =A0 =A0 }
> =A0 =A0 =A0 exit(1);
> =A0 =A0}
>
> =A0 =A0/* Extract SN */
> =A0 =A0if (reply_buffer[1] !=3D 0x80)
> =A0 =A0{
> =A0 =A0 =A0 fprintf(stderr, "Unit serial number page invalid!\n\n");
> =A0 =A0 =A0 exit(1);
> =A0 =A0}
> =A0 =A0printf("Device type: 0x%02X\n", reply_buffer[1] & 0x1F);
> =A0 =A0printf("Serial number: ");
> =A0 =A0for (i =3D 4; i < reply_buffer[3] + 4; i++)
> =A0 =A0{
> =A0 =A0 =A0 printf("%c", reply_buffer[i]);
> =A0 =A0}
> =A0 =A0printf("\n\n");
> =A0 =A0exit(0);}
>
> ----------------------------------------------------------------------
> You want to tune the error handling. ILLEGAL REQUEST may occur and it
> must not be a real error because VPD page support was not mandatory (or
> not specified at all) in older SCSI revisions.
>
> The output from my example should look like this for a disk [1]:
> ----------------------------------------------------------------------
> $ ./getsn
>
> Get Type & SN from device file: /dev/sg1
>
> Device type: 0x00
> Serial number: =A0 =A0 =A0 =A0 AJF61666
> ----------------------------------------------------------------------
>
> Micha
>
> [1]http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type

Thanks! That worked...
0
Reply galapogos 6/9/2009 3:01:36 PM

> I'm trying to get the serial number of a storage device. I've tried
> sg3_utils and sg_inq does this. I tried calling the functions within
> the sg3 source files, but I can't seem to build it even after
> including the relevant header files.

I take it that my DiskID32 http://www.winsim.com/diskid32/diskid32.html
program fails also ?

Lynn
0
Reply Lynn 7/14/2009 4:37:28 PM

3 Replies
476 Views

(page loaded in 0.305 seconds)

Similiar Articles:













7/26/2012 11:42:14 PM


Reply: