diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2007-06-27 02:56:58 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2007-06-27 02:56:58 +0000 |
commit | a948a8887d8180a4c22dbc740d349a3ddfd02b9b (patch) | |
tree | 2f6468a7e10f9a8f0cf0eebc17ffe4be6bee4474 /examples | |
parent | 22cbb24d59c600b0f4be6874848cc73691ebd69a (diff) | |
download | sg3_utils-a948a8887d8180a4c22dbc740d349a3ddfd02b9b.tar.gz |
Load sg3_utils-1.05 into trunk/.
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@34 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'examples')
-rw-r--r-- | examples/sg_iovec_tst.c | 194 | ||||
-rw-r--r-- | examples/sg_simple_aio.c | 219 |
2 files changed, 413 insertions, 0 deletions
diff --git a/examples/sg_iovec_tst.c b/examples/sg_iovec_tst.c new file mode 100644 index 00000000..16e7a4d7 --- /dev/null +++ b/examples/sg_iovec_tst.c @@ -0,0 +1,194 @@ +#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 "sg_include.h" +#include "sg_err.h" + +/* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg") + device driver. +* Copyright (C) 2003 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 will read a certain number of blocks of a given block size + from a given sg device node and write what is retrieved out to a + normal file. The purpose is to test the sg_iovec mechanism within the + sg_io_hdr structure. + + Version 0.10 (20030529) +*/ + + +#define ME "sg_iovec_tst: " + +#define A_PRIME 509 +#define IOVEC_ELEMS 2048 + +#define SENSE_BUFF_LEN 32 +#define DEF_TIMEOUT 40000 /* 40,000 milliseconds */ + +struct sg_iovec iovec[IOVEC_ELEMS]; + +/* Returns 0 if everything ok */ +int sg_read(int sg_fd, unsigned char * buff, int num_blocks, int from_block, + int bs) +{ + unsigned char rdCmd[10] = {READ_10, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + unsigned char senseBuff[SENSE_BUFF_LEN]; + struct sg_io_hdr io_hdr; + int dxfer_len = bs * num_blocks; + int k, pos, rem; + + rdCmd[2] = (unsigned char)((from_block >> 24) & 0xff); + rdCmd[3] = (unsigned char)((from_block >> 16) & 0xff); + rdCmd[4] = (unsigned char)((from_block >> 8) & 0xff); + rdCmd[5] = (unsigned char)(from_block & 0xff); + rdCmd[7] = (unsigned char)((num_blocks >> 8) & 0xff); + rdCmd[8] = (unsigned char)(num_blocks & 0xff); + + for (k = 0, pos = 0, rem = dxfer_len; k < IOVEC_ELEMS; ++k) { + iovec[k].iov_base = buff + pos; + iovec[k].iov_len = (rem > A_PRIME) ? A_PRIME : rem; + if (rem <= A_PRIME) + break; + pos += A_PRIME; + rem -= A_PRIME; + } + if (k >= IOVEC_ELEMS) { + fprintf(stderr, "Can't fit dxfer_len=%d bytes in iovec\n", dxfer_len); + return -1; + } + memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); + io_hdr.interface_id = 'S'; + io_hdr.cmd_len = sizeof(rdCmd); + io_hdr.cmdp = rdCmd; + io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; + io_hdr.dxfer_len = dxfer_len; + io_hdr.iovec_count = k + 1; + io_hdr.dxferp = iovec; + io_hdr.mx_sb_len = SENSE_BUFF_LEN; + io_hdr.sbp = senseBuff; + io_hdr.timeout = DEF_TIMEOUT; + io_hdr.pack_id = from_block; + + if (ioctl(sg_fd, SG_IO, &io_hdr)) { + perror("reading (SG_IO) on sg device, error"); + return -1; + } + switch (sg_err_category3(&io_hdr)) { + case SG_ERR_CAT_CLEAN: + break; + case SG_ERR_CAT_RECOVERED: + fprintf(stderr, "Recovered error while reading block=%d, num=%d\n", + from_block, num_blocks); + break; + case SG_ERR_CAT_MEDIA_CHANGED: + fprintf(stderr, "Media changed\n"); + return -1; + default: + sg_chk_n_print3("reading", &io_hdr); + return -1; + } + return 0; +} + + +int main(int argc, char * argv[]) +{ + int sg_fd, fd, res, j, m, dxfer_len; + unsigned int k, num; + int do_help = 0; + int blk_size = 512; + int count = 0; + char * sg_file_name = 0; + char * out_file_name = 0; + unsigned char * buffp; + + for (j = 1; j < argc; ++j) { + if (0 == strncmp("-b=", argv[j], 3)) { + m = 3; + num = sscanf(argv[j] + m, "%d", &blk_size); + if ((1 != num) || (blk_size <= 0)) { + printf("Couldn't decode number after '-b' switch\n"); + sg_file_name = 0; + break; + } + } + else if (0 == strncmp("-c=", argv[j], 3)) { + m = 3; + num = sscanf(argv[j] + m, "%d", &count); + if (1 != num) { + printf("Couldn't decode number after '-c' switch\n"); + sg_file_name = 0; + break; + } + } + else if (0 == strcmp("-h", argv[j])) + do_help = 1; + else if (*argv[j] == '-') { + printf("Unrecognized switch: %s\n", argv[j]); + sg_file_name = 0; + break; + } + else if (NULL == sg_file_name) + sg_file_name = argv[j]; + else + out_file_name = argv[j]; + } + if ((NULL == sg_file_name) || (NULL == out_file_name) || (0 == count)) { + printf("Usage: sg_iovec_tst [-h] [-b=num] -c=num <generic_device> " + "<output_filename>\n"); + printf(" where: -h this usage message\n"); + printf(" -b=num block size (default 512 Bytes)\n"); + printf(" -c=num count of blocks to transfer\n"); + printf(" reads from <generic_device> and sends to <output_filename>\n"); + return 1; + } + + sg_fd = open(sg_file_name, O_RDONLY); + if (sg_fd < 0) { + perror(ME "sg device node open error"); + return 1; + } + /* Don't worry, being very careful not to write to a none-sg file ... */ + res = ioctl(sg_fd, SG_GET_VERSION_NUM, &k); + if ((res < 0) || (k < 30000)) { + printf(ME "not a sg device, or driver prior to 3.x\n"); + return 1; + } + fd = open(out_file_name, O_WRONLY | O_CREAT, 0666); + if (fd < 0) { + perror(ME "output file open error"); + return 1; + } + dxfer_len = count * blk_size; + buffp = malloc(dxfer_len); + if (buffp) { + if (0 == sg_read(sg_fd, buffp, count, 0, blk_size)) { + if (write(fd, buffp, dxfer_len) < 0) + perror(ME "output write failed"); + } + free(buffp); + } + res = close(fd); + if (res < 0) { + perror(ME "output file close error"); + close(sg_fd); + return 1; + } + res = close(sg_fd); + if (res < 0) { + perror(ME "sg device close error"); + return 1; + } + return 0; +} diff --git a/examples/sg_simple_aio.c b/examples/sg_simple_aio.c new file mode 100644 index 00000000..127629aa --- /dev/null +++ b/examples/sg_simple_aio.c @@ -0,0 +1,219 @@ +#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 <libaio.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 to test async I/O. + +* Copyright (C) 2003 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_simple_aio [-x] <sg_device> + + Version 0.91 (20031109) + +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 + +void my_io_callback(io_context_t ctx, struct iocb *iocb, long res, long res2) +{ + printf("my_io_callback: res=%ld, res2=%ld\n", res, res2); +} + +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_simple_aio [-x] <sg_device>'\n"); + return 1; + } + + /* An access mode of O_RDWR is required for write()/read() interface */ + if ((sg_fd = open(file_name, O_RDWR)) < 0) { + snprintf(ebuff, EBUFF_SZ, + "sg_simple_aio: 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_simple_aio: %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 1 + { + struct iocb a_iocb; + struct iocb * iocb_arr[1]; + io_context_t io_ctx; + int res; + + if (0 != (res = io_queue_init(1, &io_ctx))) { + printf("io_queue_init: failed %s\n", strerror(-res)); + close(sg_fd); + return 1; + } + iocb_arr[0] = &a_iocb; + io_prep_pwrite(iocb_arr[0], sg_fd, &io_hdr, sizeof(io_hdr), 0); + io_set_callback(iocb_arr[0], my_io_callback); + res = io_submit(io_ctx, 1, iocb_arr); + if (1 != res) { + printf("io_submit: returned %d\n", res); + close(sg_fd); + return 1; + } + } +#else + if (write(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) { + perror("sg_simple_aio: Inquiry write error"); + close(sg_fd); + return 1; + } +#endif + /* sleep(3); */ + if (read(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) { + perror("sg_simple_aio: Inquiry read 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_simple_aio: 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; +} |