diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2007-06-27 02:56:10 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2007-06-27 02:56:10 +0000 |
commit | 4996eb9a33d3f74377625fcce22c5462d0708018 (patch) | |
tree | 4b4babecd18a48b4ce7e33d7b44b33f5f9b801f9 /examples | |
parent | 6e64b86f968c387672eac691acad20f91b4bd526 (diff) | |
download | sg3_utils-4996eb9a33d3f74377625fcce22c5462d0708018.tar.gz |
To prepare to load sg3_utils-1.04 into trunk/, perform 7 renames.
* trunk//examples/scsi_inquiry.c: Renamed from trunk//scsi_inquiry.c.
* trunk//archive/sg_debug.c: Renamed from trunk//sg_debug.c.
* trunk//examples/sg_simple1.c: Renamed from trunk//sg_simple1.c.
* trunk//examples/sg_simple16.c: Renamed from trunk//sg_simple16.c.
* trunk//examples/sg_simple2.c: Renamed from trunk//sg_simple2.c.
* trunk//examples/sg_simple3.c: Renamed from trunk//sg_simple3.c.
* trunk//examples/sg_simple4.c: Renamed from trunk//sg_simple4.c.
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@31 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'examples')
-rw-r--r-- | examples/scsi_inquiry.c | 127 | ||||
-rw-r--r-- | examples/sg_simple1.c | 186 | ||||
-rw-r--r-- | examples/sg_simple16.c | 121 | ||||
-rw-r--r-- | examples/sg_simple2.c | 194 | ||||
-rw-r--r-- | examples/sg_simple3.c | 204 | ||||
-rw-r--r-- | examples/sg_simple4.c | 236 |
6 files changed, 1068 insertions, 0 deletions
diff --git a/examples/scsi_inquiry.c b/examples/scsi_inquiry.c new file mode 100644 index 00000000..6b6e79d0 --- /dev/null +++ b/examples/scsi_inquiry.c @@ -0,0 +1,127 @@ +#include <unistd.h> +#include <signal.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <scsi/scsi.h> +/* #include <scsi/scsi_ioctl.h> */ /* glibc hides this file sometimes */ + +/* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg") + device driver. +* Copyright (C) 1999 D. Gilbert +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. + + This program does a SCSI inquiry command on the given device and + outputs some of the result. This program highlights the use of the + SCSI_IOCTL_SEND_COMMAND ioctl. This should be able to be applied to + any SCSI device file descriptor (not just one related to sg). [Whether + this is a good idea on a disk while it is mounted is debatable. + No detrimental effects when this was tested ...] + +Version 0.14 20011218 +*/ + + +typedef struct my_scsi_ioctl_command { + unsigned int inlen; /* _excluding_ scsi command length */ + unsigned int outlen; + unsigned char data[1]; /* was 0 but that's not ISO C!! */ + /* on input, scsi command starts here then opt. data */ +} My_Scsi_Ioctl_Command; + +#define OFF (2 * sizeof(unsigned int)) + +#ifndef SCSI_IOCTL_SEND_COMMAND +#define SCSI_IOCTL_SEND_COMMAND 1 +#endif + +#define INQUIRY_CMD 0x12 +#define INQUIRY_CMDLEN 6 +#define INQUIRY_REPLY_LEN 96 + + +int main(int argc, char * argv[]) +{ + int s_fd, res, k, to; + unsigned char inqCmdBlk [INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, + INQUIRY_REPLY_LEN, 0}; + unsigned char * inqBuff = malloc(OFF + sizeof(inqCmdBlk) + 512); + unsigned char * buffp = inqBuff + OFF; + My_Scsi_Ioctl_Command * ishp = (My_Scsi_Ioctl_Command *)inqBuff; + char * file_name = 0; + int do_nonblock = 0; + int oflags = 0; + + for (k = 1; k < argc; ++k) { + if (0 == strcmp(argv[k], "-n")) + do_nonblock = 1; + else if (*argv[k] != '-') + file_name = argv[k]; + else { + printf("Unrecognized argument '%s'\n", argv[k]); + file_name = 0; + break; + } + } + if (0 == file_name) { + printf("Usage: 'scsi_inquiry [-n] <scsi_device>'\n"); + printf(" where: -n open device in non-blocking mode\n"); + printf(" Examples: scsi_inquiry /dev/sda\n"); + printf(" scsi_inquiry /dev/sg0\n"); + printf(" scsi_inquiry -n /dev/scd0\n"); + return 1; + } + + if (do_nonblock) + oflags = O_NONBLOCK; + s_fd = open(file_name, oflags | O_RDWR); + if (s_fd < 0) { + if ((EROFS == errno) || (EACCES == errno)) { + s_fd = open(file_name, oflags | O_RDONLY); + if (s_fd < 0) { + perror("scsi_inquiry: open error"); + return 1; + } + } + else { + perror("scsi_inquiry: open error"); + return 1; + } + } + /* Don't worry, being very careful not to write to a none-scsi file ... */ + res = ioctl(s_fd, SCSI_IOCTL_GET_BUS_NUMBER, &to); + if (res < 0) { + /* perror("ioctl on scsi device, error"); */ + printf("scsi_inquiry: not a scsi device\n"); + return 1; + } + + ishp->inlen = 0; + ishp->outlen = INQUIRY_REPLY_LEN; + memcpy(buffp, inqCmdBlk, INQUIRY_CMDLEN); + res = ioctl(s_fd, SCSI_IOCTL_SEND_COMMAND, inqBuff); + if (0 == res) { + to = (int)*(buffp + 7); + printf(" %.8s %.16s %.4s, byte_7=0x%x\n", buffp + 8, + buffp + 16, buffp + 32, to); + } + else if (res < 0) + perror("scsi_inquiry: SCSI_IOCTL_SEND_COMMAND err"); + else + printf("scsi_inquiry: SCSI_IOCTL_SEND_COMMAND status=0x%x\n", res); + + res = close(s_fd); + if (res < 0) { + perror("scsi_inquiry: close error"); + return 1; + } + return 0; +} diff --git a/examples/sg_simple1.c b/examples/sg_simple1.c new file mode 100644 index 00000000..7e57e2a3 --- /dev/null +++ b/examples/sg_simple1.c @@ -0,0 +1,186 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "sg_include.h" +#include "sg_err.h" + +/* This is a simple program executing a SCSI INQUIRY command and a + TEST UNIT READY command using the SCSI generic (sg) driver + There is another variant of this program called "sg_simple2" + which does not include the sg_err.h header and logic and so has + simpler but more primitive error processing. + +* Copyright (C) 1999 D. Gilbert +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. + + Invocation: sg_simple1 [-x] <sg_device> + + Version 03.57 (20020226) + +6 byte INQUIRY command: +[0x12][ |lu][pg cde][res ][al len][cntrl ] + +6 byte TEST UNIT READY command: +[0x00][ |lu][res ][res ][res ][res ] + +*/ + +#define INQ_REPLY_LEN 96 +#define INQ_CMD_LEN 6 +#define TUR_CMD_LEN 6 + +#define EBUFF_SZ 256 + +int main(int argc, char * argv[]) +{ + int sg_fd, k, ok; + unsigned char inqCmdBlk [INQ_CMD_LEN] = + {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; + unsigned char turCmdBlk [TUR_CMD_LEN] = + {0x00, 0, 0, 0, 0, 0}; + unsigned char inqBuff[INQ_REPLY_LEN]; + sg_io_hdr_t io_hdr; + char * file_name = 0; + char ebuff[EBUFF_SZ]; + unsigned char sense_buffer[32]; + int do_extra = 0; + + for (k = 1; k < argc; ++k) { + if (0 == memcmp("-x", argv[k], 2)) + do_extra = 1; + else if (*argv[k] == '-') { + printf("Unrecognized switch: %s\n", argv[k]); + file_name = 0; + break; + } + else if (0 == file_name) + file_name = argv[k]; + else { + printf("too many arguments\n"); + file_name = 0; + break; + } + } + if (0 == file_name) { + printf("Usage: 'sg_simple1 [-x] <sg_device>'\n"); + return 1; + } + + /* N.B. An access mode of O_RDWR is required for some SCSI commands */ + if ((sg_fd = open(file_name, O_RDONLY)) < 0) { + snprintf(ebuff, EBUFF_SZ, + "sg_simple1: error opening file: %s", file_name); + perror(ebuff); + return 1; + } + /* Just to be safe, check we have a new sg device by trying an ioctl */ + if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { + printf("sg_simple1: %s doesn't seem to be an new sg device\n", + file_name); + close(sg_fd); + return 1; + } + + /* Prepare INQUIRY command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(inqCmdBlk); + /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = INQ_REPLY_LEN; + io_hdr.dxferp = inqBuff; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ + /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ + /* io_hdr.pack_id = 0; */ + /* io_hdr.usr_ptr = NULL; */ + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("sg_simple1: Inquiry SG_IO ioctl error"); + close(sg_fd); + return 1; + } + + /* now for the error processing */ + ok = 0; + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + ok = 1; + break; + case SG_ERR_CAT_RECOVERED: + printf("Recovered error on INQUIRY, continuing\n"); + ok = 1; + break; + default: /* won't bother decoding other categories */ + sg_chk_n_print3("INQUIRY command error", &io_hdr); + break; + } + + if (ok) { /* output result if it is available */ + char * p = (char *)inqBuff; + int f = (int)*(p + 7); + printf("Some of the INQUIRY command's results:\n"); + printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); + printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", + !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); + /* Extra info, not necessary to look at */ + if (do_extra) + printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", + io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); + } + + + /* Prepare TEST UNIT READY command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(turCmdBlk); + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_NONE; + io_hdr.cmdp = turCmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("sg_simple1: Test Unit Ready SG_IO ioctl error"); + close(sg_fd); + return 1; + } + + /* now for the error processing */ + ok = 0; + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + ok = 1; + break; + case SG_ERR_CAT_RECOVERED: + printf("Recovered error on Test Unit Ready, continuing\n"); + ok = 1; + break; + default: /* won't bother decoding other categories */ + sg_chk_n_print3("Test Unit Ready command error", &io_hdr); + break; + } + + if (ok) + printf("Test Unit Ready successful so unit is ready!\n"); + else + printf("Test Unit Ready failed so unit may _not_ be ready!\n"); + + if (do_extra) + printf("TEST UNIT READY duration=%u millisecs, resid=%d, msg_status=%d\n", + io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); + + close(sg_fd); + return 0; +} diff --git a/examples/sg_simple16.c b/examples/sg_simple16.c new file mode 100644 index 00000000..7aa26202 --- /dev/null +++ b/examples/sg_simple16.c @@ -0,0 +1,121 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "sg_include.h" +#include "sg_err.h" + +/* This program performs a READ_16 command as scsi mid-level support + 16 byte commands from lk 2.4.15 + +* Copyright (C) 2001 D. Gilbert +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. + + Invocation: sg_simple16 <sg_device> + + Version 1.02 (20020206) + +*/ + +#define READ16_REPLY_LEN 512 +#define READ16_CMD_LEN 16 + +#define EBUFF_SZ 256 + +int main(int argc, char * argv[]) +{ + int sg_fd, k, ok; + unsigned char r16CmdBlk [READ16_CMD_LEN] = + {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; + sg_io_hdr_t io_hdr; + char * file_name = 0; + char ebuff[EBUFF_SZ]; + unsigned char inBuff[READ16_REPLY_LEN]; + unsigned char sense_buffer[32]; + + for (k = 1; k < argc; ++k) { + if (*argv[k] == '-') { + printf("Unrecognized switch: %s\n", argv[k]); + file_name = 0; + break; + } + else if (0 == file_name) + file_name = argv[k]; + else { + printf("too many arguments\n"); + file_name = 0; + break; + } + } + if (0 == file_name) { + printf("Usage: 'sg_simple16 <sg_device>'\n"); + return 1; + } + + if ((sg_fd = open(file_name, O_RDWR)) < 0) { + snprintf(ebuff, EBUFF_SZ, + "sg_simple16: error opening file: %s", file_name); + perror(ebuff); + return 1; + } + /* Just to be safe, check we have a new sg device by trying an ioctl */ + if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { + printf("sg_simple16: %s doesn't seem to be an new sg device\n", + file_name); + close(sg_fd); + return 1; + } + + /* Prepare READ_16 command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(r16CmdBlk); + /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = READ16_REPLY_LEN; + io_hdr.dxferp = inBuff; + io_hdr.cmdp = r16CmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ + /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ + /* io_hdr.pack_id = 0; */ + /* io_hdr.usr_ptr = NULL; */ + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("sg_simple16: Inquiry SG_IO ioctl error"); + close(sg_fd); + return 1; + } + + /* now for the error processing */ + ok = 0; + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + ok = 1; + break; + case SG_ERR_CAT_RECOVERED: + printf("Recovered error on READ_16, continuing\n"); + ok = 1; + break; + default: /* won't bother decoding other categories */ + sg_chk_n_print3("READ_16 command error", &io_hdr); + break; + } + + if (ok) { /* output result if it is available */ + printf("READ_16 duration=%u millisecs, resid=%d, msg_status=%d\n", + io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); + } + + close(sg_fd); + return 0; +} diff --git a/examples/sg_simple2.c b/examples/sg_simple2.c new file mode 100644 index 00000000..37e9dc71 --- /dev/null +++ b/examples/sg_simple2.c @@ -0,0 +1,194 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "sg_include.h" + +/* This is a simple program executing a SCSI INQUIRY command and a + TEST UNIT READY command using the SCSI generic (sg) driver. + There is another variant of this program called "sg_simple1" + which includes the sg_err.h header and logic and so has more + advanced error processing. + This version demonstrates the "sg3" interface. + +* Copyright (C) 1999 D. Gilbert +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. + + Invocation: sg_simple2 [-x] <sg_device> + + Version 03.57 (20020226) + +6 byte INQUIRY command: +[0x12][ |lu][pg cde][res ][al len][cntrl ] + +6 byte TEST UNIT READY command: +[0x00][ |lu][res ][res ][res ][res ] + +*/ + +#define INQ_REPLY_LEN 96 /* logic assumes >= sizeof(inqCmdBlk) */ +#define INQ_CMD_LEN 6 +#define TUR_CMD_LEN 6 + +#define EBUFF_SZ 256 + + +int main(int argc, char * argv[]) +{ + int sg_fd, k; + unsigned char inqCmdBlk [INQ_CMD_LEN] = + {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; + unsigned char turCmdBlk [TUR_CMD_LEN] = + {0x00, 0, 0, 0, 0, 0}; + unsigned char inqBuff[INQ_REPLY_LEN]; + sg_io_hdr_t io_hdr; + char * file_name = 0; + char ebuff[EBUFF_SZ]; + unsigned char sense_buffer[32]; + int do_extra = 0; + + for (k = 1; k < argc; ++k) { + if (0 == memcmp("-x", argv[k], 2)) + do_extra = 1; + else if (*argv[k] == '-') { + printf("Unrecognized switch: %s\n", argv[k]); + file_name = 0; + break; + } + else if (0 == file_name) + file_name = argv[k]; + else { + printf("too many arguments\n"); + file_name = 0; + break; + } + } + if (0 == file_name) { + printf("Usage: 'sg_simple2 [-x] <sg_device>'\n"); + return 1; + } + + /* N.B. An access mode of O_RDWR is required for some SCSI commands */ + if ((sg_fd = open(file_name, O_RDONLY)) < 0) { + snprintf(ebuff, EBUFF_SZ, + "sg_simple2: error opening file: %s", file_name); + perror(ebuff); + return 1; + } + /* Just to be safe, check we have a new sg device by trying an ioctl */ + if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { + printf("sg_simple2: %s doesn't seem to be an new sg device\n", + file_name); + close(sg_fd); + return 1; + } + + /* Prepare INQUIRY command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(inqCmdBlk); + /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = INQ_REPLY_LEN; + io_hdr.dxferp = inqBuff; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ + /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ + /* io_hdr.pack_id = 0; */ + /* io_hdr.usr_ptr = NULL; */ + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("sg_simple2: Inquiry SG_IO ioctl error"); + close(sg_fd); + 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) { + printf("INQUIRY sense data: "); + for (k = 0; k < io_hdr.sb_len_wr; ++k) { + if ((k > 0) && (0 == (k % 10))) + printf("\n "); + printf("0x%02x ", sense_buffer[k]); + } + printf("\n"); + } + if (io_hdr.masked_status) + printf("INQUIRY SCSI status=0x%x\n", io_hdr.status); + if (io_hdr.host_status) + printf("INQUIRY host_status=0x%x\n", io_hdr.host_status); + if (io_hdr.driver_status) + printf("INQUIRY driver_status=0x%x\n", io_hdr.driver_status); + } + else { /* output result if it is available */ + char * p = (char *)inqBuff; + int f = (int)*(p + 7); + printf("Some of the INQUIRY command's results:\n"); + printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); + printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", + !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); + } + /* Extra info, not necessary to look at */ + if (do_extra) + printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", + io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); + + /* Prepare TEST UNIT READY command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(turCmdBlk); + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_NONE; + io_hdr.cmdp = turCmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("sg_simple2: Test Unit Ready SG_IO ioctl error"); + close(sg_fd); + 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) { + printf("TEST UNIT READY sense data: "); + for (k = 0; k < io_hdr.sb_len_wr; ++k) { + if ((k > 0) && (0 == (k % 10))) + printf("\n "); + printf("0x%02x ", sense_buffer[k]); + } + printf("\n"); + } + else if (io_hdr.masked_status) + printf("TEST UNIT READY SCSI status=0x%x\n", io_hdr.status); + else if (io_hdr.host_status) + printf("TEST UNIT READY host_status=0x%x\n", io_hdr.host_status); + else if (io_hdr.driver_status) + printf("TEST UNIT READY driver_status=0x%x\n", + io_hdr.driver_status); + else + printf("TEST UNIT READY unexpected error\n"); + printf("Test Unit Ready failed so unit may _not_ be ready!\n"); + } + else + printf("Test Unit Ready successful so unit is ready!\n"); + /* Extra info, not necessary to look at */ + if (do_extra) + printf("TEST UNIT READY duration=%u millisecs, resid=%d, msg_status=%d\n", + io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); + + close(sg_fd); + return 0; +} diff --git a/examples/sg_simple3.c b/examples/sg_simple3.c new file mode 100644 index 00000000..6a6f1c3b --- /dev/null +++ b/examples/sg_simple3.c @@ -0,0 +1,204 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include "sg_include.h" +#include "sg_err.h" + +/* This is a simple program executing a SCSI INQUIRY command and a + TEST UNIT READY command using the SCSI generic (sg) driver. + There is another variant of this program called "sg_simple1". + This variant demonstrates using the scatter gather facility in + the sg_io_hdr interface to break an INQUIRY response into its + component parts. + +* Copyright (C) 1999 D. Gilbert +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. + + Invocation: sg_simple3 [-x] <sg_device> + + Version 03.58 (20020226) + +6 byte INQUIRY command: +[0x12][ |lu][pg cde][res ][al len][cntrl ] + +6 byte TEST UNIT READY command: +[0x00][ |lu][res ][res ][res ][res ] + +*/ + +#define INQ_REPLY_BASE_LEN 8 +#define INQ_REPLY_VID_LEN 8 +#define INQ_REPLY_PID_LEN 16 +#define INQ_REPLY_PREV_LEN 4 +#define INQ_REPLY_IOVEC_COUNT 4 +#define INQ_CMD_LEN 6 +#define TUR_CMD_LEN 6 + +#define EBUFF_SZ 256 + +int main(int argc, char * argv[]) +{ + int sg_fd, k, ok; + unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, + INQ_REPLY_BASE_LEN + INQ_REPLY_VID_LEN + + INQ_REPLY_PID_LEN + INQ_REPLY_PREV_LEN, 0}; + unsigned char turCmdBlk [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; + sg_iovec_t iovec[INQ_REPLY_IOVEC_COUNT]; + unsigned char inqBaseBuff[INQ_REPLY_BASE_LEN]; + char inqVidBuff[INQ_REPLY_VID_LEN]; + char inqPidBuff[INQ_REPLY_PID_LEN]; + char inqPRevBuff[INQ_REPLY_PREV_LEN]; + sg_io_hdr_t io_hdr; + char * file_name = 0; + char ebuff[EBUFF_SZ]; + unsigned char sense_buffer[32]; + int do_extra = 0; + + for (k = 1; k < argc; ++k) { + if (0 == memcmp("-x", argv[k], 2)) + do_extra = 1; + else if (*argv[k] == '-') { + printf("Unrecognized switch: %s\n", argv[k]); + file_name = 0; + break; + } + else if (0 == file_name) + file_name = argv[k]; + else { + printf("too many arguments\n"); + file_name = 0; + break; + } + } + if (0 == file_name) { + printf("Usage: 'sg_simple3 [-x] <sg_device>'\n"); + return 1; + } + + /* N.B. An access mode of O_RDWR is required for some SCSI commands */ + if ((sg_fd = open(file_name, O_RDONLY)) < 0) { + snprintf(ebuff, EBUFF_SZ, + "sg_simple3: error opening file: %s", file_name); + perror(ebuff); + return 1; + } + /* Just to be safe, check we have a new sg device by trying an ioctl */ + if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { + printf("sg_simple3: %s doesn't seem to be an new sg device\n", + file_name); + close(sg_fd); + return 1; + } + + /* Prepare INQUIRY command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(inqCmdBlk); + io_hdr.iovec_count = INQ_REPLY_IOVEC_COUNT; + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = INQ_REPLY_BASE_LEN + INQ_REPLY_VID_LEN + + INQ_REPLY_PID_LEN + INQ_REPLY_PREV_LEN; + iovec[0].iov_base = inqBaseBuff; + iovec[0].iov_len = INQ_REPLY_BASE_LEN; + iovec[1].iov_base = inqVidBuff; + iovec[1].iov_len = INQ_REPLY_VID_LEN; + iovec[2].iov_base = inqPidBuff; + iovec[2].iov_len = INQ_REPLY_PID_LEN; + iovec[3].iov_base = inqPRevBuff; + iovec[3].iov_len = INQ_REPLY_PREV_LEN; + io_hdr.dxferp = iovec; + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ + /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ + /* io_hdr.pack_id = 0; */ + /* io_hdr.usr_ptr = NULL; */ + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("sg_simple3: Inquiry SG_IO ioctl error"); + close(sg_fd); + return 1; + } + + /* now for the error processing */ + ok = 0; + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + ok = 1; + break; + case SG_ERR_CAT_RECOVERED: + printf("Recovered error on INQUIRY, continuing\n"); + ok = 1; + break; + default: /* won't bother decoding other categories */ + sg_chk_n_print3("INQUIRY command error", &io_hdr); + break; + } + + if (ok) { /* output result if it is available */ + char * p = (char *)inqBaseBuff; + int f = (int)*(p + 7); + printf("Some of the INQUIRY command's results:\n"); + printf(" %.8s %.16s %.4s ", inqVidBuff, inqPidBuff, inqPRevBuff); + printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", + !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); + /* Extra info, not necessary to look at */ + if (do_extra) + printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", + io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); + } + + + /* Prepare TEST UNIT READY command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(turCmdBlk); + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_NONE; + io_hdr.cmdp = turCmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("sg_simple3: Test Unit Ready SG_IO ioctl error"); + close(sg_fd); + return 1; + } + + /* now for the error processing */ + ok = 0; + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + ok = 1; + break; + case SG_ERR_CAT_RECOVERED: + printf("Recovered error on Test Unit Ready, continuing\n"); + ok = 1; + break; + default: /* won't bother decoding other categories */ + sg_chk_n_print3("Test Unit Ready command error", &io_hdr); + break; + } + + if (ok) + printf("Test Unit Ready successful so unit is ready!\n"); + else + printf("Test Unit Ready failed so unit may _not_ be ready!\n"); + + if (do_extra) + printf("TEST UNIT READY duration=%u millisecs, resid=%d, msg_status=%d\n", + io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); + + close(sg_fd); + return 0; +} diff --git a/examples/sg_simple4.c b/examples/sg_simple4.c new file mode 100644 index 00000000..1297532e --- /dev/null +++ b/examples/sg_simple4.c @@ -0,0 +1,236 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include "sg_include.h" +#include "sg_err.h" + +/* This is a simple program executing a SCSI INQUIRY command and a + TEST UNIT READY command using the SCSI generic (sg) driver + This variant shows mmap-ed IO being used to read the data returned + by the INQUIRY command. + +* Copyright (C) 2001 D. Gilbert +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. + + Invocation: sg_simple4 [-x] <sg_device> + + Version 1.01 (20020113) + +6 byte INQUIRY command: +[0x12][ |lu][pg cde][res ][al len][cntrl ] + +6 byte TEST UNIT READY command: +[0x00][ |lu][res ][res ][res ][res ] + +*/ + +#ifndef SG_FLAG_MMAP_IO +#define SG_FLAG_MMAP_IO 4 +#endif /* since /usr/include/scsi/sg.h doesn't know about this yet */ + +#define INQ_REPLY_LEN 96 +#define INQ_CMD_LEN 6 +#define TUR_CMD_LEN 6 + +#define EBUFF_SZ 256 + +int main(int argc, char * argv[]) +{ + int sg_fd, k, ok; + unsigned char inqCmdBlk [INQ_CMD_LEN] = + {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; + unsigned char turCmdBlk [TUR_CMD_LEN] = + {0x00, 0, 0, 0, 0, 0}; + unsigned char * inqBuff; + unsigned char * inqBuff2; + sg_io_hdr_t io_hdr; + char * file_name = 0; + char ebuff[EBUFF_SZ]; + unsigned char sense_buffer[32]; + int do_extra = 0; + + for (k = 1; k < argc; ++k) { + if (0 == memcmp("-x", argv[k], 2)) + do_extra = 1; + else if (*argv[k] == '-') { + printf("Unrecognized switch: %s\n", argv[k]); + file_name = 0; + break; + } + else if (0 == file_name) + file_name = argv[k]; + else { + printf("too many arguments\n"); + file_name = 0; + break; + } + } + if (0 == file_name) { + printf("Usage: 'sg_simple4 [-x] <sg_device>'\n"); + return 1; + } + + /* N.B. An access mode of O_RDWR is required for some SCSI commands */ + if ((sg_fd = open(file_name, O_RDWR)) < 0) { + snprintf(ebuff, EBUFF_SZ, + "sg_simple4: error opening file: %s", file_name); + perror(ebuff); + return 1; + } + /* Just to be safe, check we have a new sg device by trying an ioctl */ + if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30122)) { + printf("sg_simple4: %s needs sg driver version >= 3.1.22\n", + file_name); + close(sg_fd); + return 1; + } + + /* since I know this program will only read from inqBuff then I use + PROT_READ rather than PROT_READ | PROT_WRITE */ + inqBuff = mmap(NULL, 8000, PROT_READ | PROT_WRITE, MAP_SHARED, sg_fd, 0); + if (MAP_FAILED == inqBuff) { + snprintf(ebuff, EBUFF_SZ, "sg_simple4: error using mmap() on " + "file: %s", file_name); + perror(ebuff); + return 1; + } + if (inqBuff[0]) + printf("non-null char at inqBuff[0]\n"); + if (inqBuff[5000]) + printf("non-null char at inqBuff[5000]\n"); + + /* Prepare INQUIRY command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(inqCmdBlk); + /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = INQ_REPLY_LEN; + /* io_hdr.dxferp = inqBuff; // ignored in mmap-ed IO */ + io_hdr.cmdp = inqCmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ + io_hdr.flags = SG_FLAG_MMAP_IO; + /* io_hdr.pack_id = 0; */ + /* io_hdr.usr_ptr = NULL; */ + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("sg_simple4: Inquiry SG_IO ioctl error"); + close(sg_fd); + return 1; + } + + /* now for the error processing */ + ok = 0; + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + ok = 1; + break; + case SG_ERR_CAT_RECOVERED: + printf("Recovered error on INQUIRY, continuing\n"); + ok = 1; + break; + default: /* won't bother decoding other categories */ + sg_chk_n_print3("INQUIRY command error", &io_hdr); + break; + } + + if (ok) { /* output result if it is available */ + char * p = (char *)inqBuff; + int f = (int)*(p + 7); + printf("Some of the INQUIRY command's results:\n"); + printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); + printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", + !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); + /* Extra info, not necessary to look at */ + if (do_extra) + printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", + io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); + } + + + /* Prepare TEST UNIT READY command */ + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(turCmdBlk); + io_hdr.mx_sb_len = sizeof(sense_buffer); + io_hdr.dxfer_direction = SG_DXFER_NONE; + io_hdr.cmdp = turCmdBlk; + io_hdr.sbp = sense_buffer; + io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ + + if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { + perror("sg_simple4: Test Unit Ready SG_IO ioctl error"); + close(sg_fd); + return 1; + } + + /* now for the error processing */ + ok = 0; + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + ok = 1; + break; + case SG_ERR_CAT_RECOVERED: + printf("Recovered error on Test Unit Ready, continuing\n"); + ok = 1; + break; + default: /* won't bother decoding other categories */ + sg_chk_n_print3("Test Unit Ready command error", &io_hdr); + break; + } + + if (ok) + printf("Test Unit Ready successful so unit is ready!\n"); + else + printf("Test Unit Ready failed so unit may _not_ be ready!\n"); + + if (do_extra) + printf("TEST UNIT READY duration=%u millisecs, resid=%d, " + "msg_status=%d\n", + io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); + + /* munmap(inqBuff, 8000); */ + /* could call munmap(inqBuff, INQ_REPLY_LEN) here but following close() + causes this too happen anyway */ +#if 1 + inqBuff2 = mmap(NULL, 8000, PROT_READ | PROT_WRITE, MAP_SHARED, sg_fd, 0); + if (MAP_FAILED == inqBuff2) { + snprintf(ebuff, EBUFF_SZ, "sg_simple4: error using mmap() 2 on " + "file: %s", file_name); + perror(ebuff); + return 1; + } + if (inqBuff2[0]) + printf("non-null char at inqBuff2[0]\n"); + if (inqBuff2[5000]) + printf("non-null char at inqBuff2[5000]\n"); + { + pid_t pid; + pid = fork(); + if (pid) { + inqBuff2[5000] = 33; + munmap(inqBuff, 8000); + sleep(3); + } + else { + inqBuff[5000] = 0xaa; + munmap(inqBuff, 8000); + sleep(1); + } + } +#endif + close(sg_fd); + return 0; +} |