sg3_utils 是一个Linux的开发包,用来直接使用 SCSI 命令集访问设备。
下面自己写一个例程:sg.c
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <scsi/scsi_ioctl.h>
#define SENSE_LEN 255
#define BLOCK_LEN 32
#define SCSI_TIMEOUT 20000
unsigned char sense_buffer[SENSE_LEN];
unsigned char data_buffer[BLOCK_LEN*256];
void show_hdr_outputs(struct sg_io_hdr * hdr) {
printf("status:%d\n", hdr->status);
printf("masked_status:%d\n", hdr->masked_status);
printf("msg_status:%d\n", hdr->msg_status);
printf("sb_len_wr:%d\n", hdr->sb_len_wr);
printf("host_status:%d\n", hdr->host_status);
printf("driver_status:%d\n", hdr->driver_status);
printf("resid:%d\n", hdr->resid);
printf("duration:%d\n", hdr->duration);
printf("info:%d\n", hdr->info);
}
void show_sense_buffer(struct sg_io_hdr * hdr) {
unsigned char * buffer = hdr->sbp;
int i;
for (i=0; i<hdr->mx_sb_len; ++i) {
putchar(buffer[i]);
}
}
void show_vendor(struct sg_io_hdr * hdr) {
unsigned char * buffer = hdr->dxferp;
int i;
printf("the device type: %x \n",buffer[0]&(1<<5 -1));
//设备类型:0 磁盘 1磁带 12存储阵列(raid) 13拓展柜(expander)
printf("vendor id:");
for (i=8; i<16; ++i) {
putchar(buffer[i]);
}
putchar('\n');
}
void show_product(struct sg_io_hdr * hdr) {
unsigned char * buffer = hdr->dxferp;
int i;
printf("product id:");
for (i=16; i<32; ++i) {
putchar(buffer[i]);
}
putchar('\n');
}
void show_product_rev(struct sg_io_hdr * hdr) {
unsigned char * buffer = hdr->dxferp;
int i;
printf("product ver:");
for (i=32; i<36; ++i) {
putchar(buffer[i]);
}
putchar('\n');
}
/***************************************************************************
* name: execute_Inquiry
* parameter:
* fd: file descripter
* page_code: cdb page code
* evpd: cdb evpd
* p_hdr: poiter to sg_io_hdr struct
* function: make Inquiry cdb and execute it.
* **************************************************************************/
int execute_Inquiry(int fd, int page_code, int evpd, struct sg_io_hdr * p_hdr) {
unsigned char cdb[6];
/* set the cdb format */
cdb[0] = 0x12; /*This is for Inquery*/
cdb[1] = evpd & 1;
cdb[2] = page_code & 0xff;
cdb[3] = 0;
cdb[4] = 0xff;
cdb[5] = 0; /*For control filed, just use 0*/
p_hdr->dxfer_direction = SG_DXFER_FROM_DEV;
p_hdr->cmdp = cdb;
p_hdr->cmd_len = 6;
int ret = ioctl(fd, SG_IO, p_hdr);
if (ret<0) {
printf("Sending SCSI Command failed.\n");
close(fd);
exit(1);
}
return p_hdr->status;
}
void test_execute_Inquiry(char * path, int evpd, int page_code) {
int status = 0;
//初始化p_hdr
struct sg_io_hdr * p_hdr = (struct sg_io_hdr *)malloc(sizeof(struct sg_io_hdr));
memset(p_hdr, 0, sizeof(struct sg_io_hdr));
p_hdr->interface_id = 'S'; /* this is the only choice we have! */
p_hdr->flags = SG_FLAG_LUN_INHIBIT; /* this would put the LUN to 2nd byte of cdb*/
//设置传输数据buffer
p_hdr->dxferp = data_buffer; //INQUIRY 数据格式 SPC-3
p_hdr->dxfer_len = BLOCK_LEN*256;
//设置sense buffer
p_hdr->sbp = sense_buffer;
p_hdr->mx_sb_len = SENSE_LEN;
printf("the device name:%s \n",path[5]);
int fd = open(path, O_RDWR);
if (fd>0) {
status = execute_Inquiry(fd, page_code, evpd, p_hdr);
if (status!=0) {
show_sense_buffer(p_hdr);
} else{
show_vendor(p_hdr);
show_product(p_hdr);
show_product_rev(p_hdr);
}
} else {
printf("failed to open sg file %s\n", path);
}
close(fd);
free(p_hdr);
}
int main(int argc, char * argv[]) {
test_execute_Inquiry(argv[1], 0, 0);
return EXIT_SUCCESS;
}