There is no good solution when I find the serial number of the SCSI hard disk on the Internet. Most of the information on the Internet is about the IDE hard disk. After a large number of searches, I finally found an effective method, post it to share with you:
The Code is as follows:
# Include <unistd. h>
# Include <fcntl. h>
# Include <stdio. h>
# Include <string. h>
# Include <errno. h>
# Include <sys/IOCTL. h>
# Include <SCSI/SG. h>
# Define scsi_timeout 5000/* MS */
Static char * Device = "/dev/SDA ";
Int scsi_io (int fd, unsigned char * CDB, unsigned char cdb_size, int xfer_dir,
Unsigned char * data, unsigned int * data_size,
Unsigned char * Sense, unsigned int * sense_len)
{
Sg_io_hdr_t io_hdr;
Memset (& io_hdr, 0, sizeof (sg_io_hdr_t ));
Io_hdr.interface_id ='s ';
/* CDB */
Io_hdr.cmdp = CDB;
Io_hdr.cmd_len = cdb_size;
/* Where to store the sense_data, if there was an error */
Io_hdr.systolic = sense;
Io_hdr.mx_sb_len = * sense_len;
* Sense_len = 0;
/* Transfer ction, either in or out. Linux does not yet
Support bidirectional SCSI transfers?
*/
Io_hdr.dxfer_direction = xfer_dir;
/* Where to store the data in/out from the device and how big
Buffer is
*/
Io_hdr.dxferp = data;
Io_hdr.dxfer_len = * data_size;
/* SCSI timeout MS */
Io_hdr.timeout = scsi_timeout;
If (IOCTL (FD, sg_io, & io_hdr) <0 ){
Perror ("sg_io IOCTL failed ");
Return-1;
}
/* Now for the error processing */
If (io_hdr.info & sg_info_ OK _mask )! = Sg_info_ OK ){
If (io_hdr.sb_len_wr> 0 ){
* Sense_len = io_hdr.sb_len_wr;
Return 0;
}
}
If (io_hdr.masked_status ){
Printf ("status = 0x % x \ n", io_hdr.status );
Printf ("masked_status = 0x % x \ n", io_hdr.masked_status );
Return-2;
}
If (io_hdr.host_status ){
Printf ("host_status = 0x % x \ n", io_hdr.host_status );
Return-3;
}
If (io_hdr.driver_status ){
Printf ("driver_status = 0x % x \ n", io_hdr.driver_status );
Return-4;
}
Return 0;
}
Int scsi_inquiry_unit_serial_number (int fd)
{
Unsigned char CDB [] = {0x12, 0x0, 0x80, 0, 0 };
Unsigned int data_size = 0x00ff;
Unsigned char data [data_size];
Unsigned int sense_len = 32;
Unsigned char sense [sense_len];
Int res, PL, I;
CDB [3] = (data_size> 8) & 0xff;
CDB [4] = data_size & 0xff;
Printf ("Inquiry Unit serial number: \ n ");
Res = scsi_io (FD, CDB, sizeof (CDB), sg_dxfer_from_dev, Data, & data_size, sense, & sense_len );
If (RES ){
Printf ("scsi_io failed \ n ");
Return-1;
}
If (sense_len ){
Return-1;
}
/* Page length */
PL = data [3];
/* Unit serial number */
Printf ("unit serial number :");
For (I = 4; I <(PL + 4); I ++) printf ("% C", data [I] & 0xff ); printf ("\ n ");
Return 0;
}
Int open_scsi_device (const char * Dev)
{
Int FD, Vers;
If (FD = open (Dev, o_rdwr) <0 ){
Printf ("error cocould not open device % s \ n", Dev );
Return-1;
}
If (IOCTL (FD, sg_get_version_num, & vers) <0) | (vers <30000 )){
Printf ("/Dev is not an SG device, or old SG driver \ n ");
Close (FD );
Return-1;
}
Return FD;
}
Int main (INT argc, const char * argv [])
{
Int FD;
FD = open_scsi_device (device );
If (FD <0 ){
Printf ("cocould not open SCSI device % s \ n", device );
_ Exit (10 );
}
Scsi_inquiry_unit_serial_number (FD );
Return 0;
}
Note: hard disk serial numbers cannot be obtained under virtual machines in this method.