用户态发送SCSI命令例程 ( sg )

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

下面是一个Linux用户定时器的简单例程: ```c #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <time.h> #include <unistd.h> #define TIMER_SIG SIGRTMIN void timer_handler(int sig, siginfo_t *si, void *uc) { printf("Timer expired.\n"); } int main(int argc, char *argv[]) { timer_t timerid; struct sigevent sev; struct itimerspec its; struct sigaction sa; // 设置定时器信号处理函数 sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = timer_handler; sigemptyset(&sa.sa_mask); if (sigaction(TIMER_SIG, &sa, NULL) == -1) { perror("sigaction"); exit(EXIT_FAILURE); } // 创建定时器 sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = TIMER_SIG; sev.sigev_value.sival_ptr = &timerid; if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) { perror("timer_create"); exit(EXIT_FAILURE); } // 设置定时器 its.it_value.tv_sec = 5; // 初始定时器时间为5秒 its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 1; // 定时器到期后每1秒重新启动一次 its.it_interval.tv_nsec = 0; if (timer_settime(timerid, 0, &its, NULL) == -1) { perror("timer_settime"); exit(EXIT_FAILURE); } // 循环等待定时器信号 while (1) { sleep(1); } return 0; } ``` 该程序使用 `timer_create()` 创建一个定时器,并使用 `timer_settime()` 设置定时器的初始值和周期值。在定时器到期时,会触发一个 `SIGRTMIN` 信号,该信号将被注册的信号处理函数 `timer_handler()` 捕获并执行。在该例程中,我们简单地打印了一条消息来表示定时器已经到期。 要编译上述程序,请使用以下命令: ``` gcc -o timer timer.c ``` 运行程序,它将等待5秒钟,然后输出一条消息,之后每隔1秒钟再输出一条消息。你可以使用 `Ctrl+C` 组合键来中断程序。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值