aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDouglas Gilbert <dgilbert@interlog.com>2007-06-27 02:56:58 +0000
committerDouglas Gilbert <dgilbert@interlog.com>2007-06-27 02:56:58 +0000
commita948a8887d8180a4c22dbc740d349a3ddfd02b9b (patch)
tree2f6468a7e10f9a8f0cf0eebc17ffe4be6bee4474 /examples
parent22cbb24d59c600b0f4be6874848cc73691ebd69a (diff)
downloadsg3_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.c194
-rw-r--r--examples/sg_simple_aio.c219
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;
+}