blob: 95dfcfa201bc14977f2aced837445de2282f5474 [file] [log] [blame]
Douglas Gilberta948a882007-06-27 02:56:58 +00001#include <unistd.h>
2#include <fcntl.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <errno.h>
7#include <sys/ioctl.h>
8#include <sys/types.h>
9#include <sys/stat.h>
Douglas Gilbert78fa03f2010-03-21 02:14:23 +000010
11/*
12 * To use "aio" then uncomment the 'WANT_AIO' define.
13 * Depending on the distribution libaio and libaio-dev packages
14 * may need to be loaded.
15 * If WANT_AIO is defined then a '-laio' term will most likely
16 * be required in the Makefile.
17 */
18/* #define WANT_AIO 1 */
19
20#ifdef WANT_AIO
Douglas Gilberta948a882007-06-27 02:56:58 +000021#include <libaio.h>
Douglas Gilbert78fa03f2010-03-21 02:14:23 +000022#endif
23
Douglas Gilbertfa6966c2007-06-27 03:00:59 +000024#include "sg_lib.h"
Douglas Gilbert78fa03f2010-03-21 02:14:23 +000025#include "sg_io_linux.h"
Douglas Gilbert68f4f8d2007-06-27 03:20:52 +000026#include "sg_linux_inc.h"
Douglas Gilberta948a882007-06-27 02:56:58 +000027
28/* This is a simple program executing a SCSI INQUIRY command and a
29 TEST UNIT READY command using the SCSI generic (sg) driver
30 This variant to test async I/O.
31
Douglas Gilbert78fa03f2010-03-21 02:14:23 +000032* Copyright (C) 2003-2010 D. Gilbert
Douglas Gilberta948a882007-06-27 02:56:58 +000033* This program is free software; you can redistribute it and/or modify
34* it under the terms of the GNU General Public License as published by
35* the Free Software Foundation; either version 2, or (at your option)
36* any later version.
37
38 Invocation: sg_simple_aio [-x] <sg_device>
39
Douglas Gilbert78fa03f2010-03-21 02:14:23 +000040 Version 0.92 (20100320)
Douglas Gilberta948a882007-06-27 02:56:58 +000041
426 byte INQUIRY command:
43[0x12][ |lu][pg cde][res ][al len][cntrl ]
44
456 byte TEST UNIT READY command:
46[0x00][ |lu][res ][res ][res ][res ]
47
48*/
49
50#define INQ_REPLY_LEN 96
51#define INQ_CMD_LEN 6
52#define TUR_CMD_LEN 6
53
54#define EBUFF_SZ 256
55
Douglas Gilbert78fa03f2010-03-21 02:14:23 +000056
57
58#ifdef WANT_AIO
Douglas Gilberta948a882007-06-27 02:56:58 +000059void my_io_callback(io_context_t ctx, struct iocb *iocb, long res, long res2)
60{
61 printf("my_io_callback: res=%ld, res2=%ld\n", res, res2);
62}
Douglas Gilbert78fa03f2010-03-21 02:14:23 +000063#endif
64
Douglas Gilberta948a882007-06-27 02:56:58 +000065
66int main(int argc, char * argv[])
67{
68 int sg_fd, k, ok;
69 unsigned char inqCmdBlk [INQ_CMD_LEN] =
70 {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
71 unsigned char turCmdBlk [TUR_CMD_LEN] =
72 {0x00, 0, 0, 0, 0, 0};
73 unsigned char inqBuff[INQ_REPLY_LEN];
74 sg_io_hdr_t io_hdr;
75 char * file_name = 0;
76 char ebuff[EBUFF_SZ];
77 unsigned char sense_buffer[32];
78 int do_extra = 0;
79
80 for (k = 1; k < argc; ++k) {
81 if (0 == memcmp("-x", argv[k], 2))
82 do_extra = 1;
83 else if (*argv[k] == '-') {
84 printf("Unrecognized switch: %s\n", argv[k]);
85 file_name = 0;
86 break;
87 }
88 else if (0 == file_name)
89 file_name = argv[k];
90 else {
91 printf("too many arguments\n");
92 file_name = 0;
93 break;
94 }
95 }
96 if (0 == file_name) {
97 printf("Usage: 'sg_simple_aio [-x] <sg_device>'\n");
98 return 1;
99 }
100
101 /* An access mode of O_RDWR is required for write()/read() interface */
102 if ((sg_fd = open(file_name, O_RDWR)) < 0) {
103 snprintf(ebuff, EBUFF_SZ,
Douglas Gilbert78fa03f2010-03-21 02:14:23 +0000104 "sg_simple_aio: error opening file: %s", file_name);
Douglas Gilberta948a882007-06-27 02:56:58 +0000105 perror(ebuff);
106 return 1;
107 }
108 /* Just to be safe, check we have a new sg device by trying an ioctl */
109 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
110 printf("sg_simple_aio: %s doesn't seem to be an new sg device\n",
111 file_name);
112 close(sg_fd);
113 return 1;
114 }
115
116 /* Prepare INQUIRY command */
117 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
118 io_hdr.interface_id = 'S';
119 io_hdr.cmd_len = sizeof(inqCmdBlk);
120 /* io_hdr.iovec_count = 0; */ /* memset takes care of this */
121 io_hdr.mx_sb_len = sizeof(sense_buffer);
122 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
123 io_hdr.dxfer_len = INQ_REPLY_LEN;
124 io_hdr.dxferp = inqBuff;
125 io_hdr.cmdp = inqCmdBlk;
126 io_hdr.sbp = sense_buffer;
127 io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
128 /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */
129 /* io_hdr.pack_id = 0; */
130 /* io_hdr.usr_ptr = NULL; */
131
Douglas Gilbert78fa03f2010-03-21 02:14:23 +0000132#if WANT_AIO
Douglas Gilberta948a882007-06-27 02:56:58 +0000133 {
134 struct iocb a_iocb;
135 struct iocb * iocb_arr[1];
136 io_context_t io_ctx;
137 int res;
138
139 if (0 != (res = io_queue_init(1, &io_ctx))) {
140 printf("io_queue_init: failed %s\n", strerror(-res));
141 close(sg_fd);
142 return 1;
143 }
144 iocb_arr[0] = &a_iocb;
145 io_prep_pwrite(iocb_arr[0], sg_fd, &io_hdr, sizeof(io_hdr), 0);
146 io_set_callback(iocb_arr[0], my_io_callback);
147 res = io_submit(io_ctx, 1, iocb_arr);
148 if (1 != res) {
149 printf("io_submit: returned %d\n", res);
150 close(sg_fd);
151 return 1;
152 }
153 }
154#else
155 if (write(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) {
156 perror("sg_simple_aio: Inquiry write error");
157 close(sg_fd);
158 return 1;
159 }
160#endif
161 /* sleep(3); */
162 if (read(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) {
163 perror("sg_simple_aio: Inquiry read error");
164 close(sg_fd);
165 return 1;
166 }
167
168 /* now for the error processing */
169 ok = 0;
170 switch (sg_err_category3(&io_hdr)) {
Douglas Gilbertfa6966c2007-06-27 03:00:59 +0000171 case SG_LIB_CAT_CLEAN:
Douglas Gilberta948a882007-06-27 02:56:58 +0000172 ok = 1;
173 break;
Douglas Gilbertfa6966c2007-06-27 03:00:59 +0000174 case SG_LIB_CAT_RECOVERED:
Douglas Gilberta948a882007-06-27 02:56:58 +0000175 printf("Recovered error on INQUIRY, continuing\n");
176 ok = 1;
177 break;
178 default: /* won't bother decoding other categories */
Douglas Gilbert78fa03f2010-03-21 02:14:23 +0000179 sg_chk_n_print3("INQUIRY command error", &io_hdr, 1);
Douglas Gilberta948a882007-06-27 02:56:58 +0000180 break;
181 }
182
183 if (ok) { /* output result if it is available */
184 char * p = (char *)inqBuff;
185 int f = (int)*(p + 7);
186 printf("Some of the INQUIRY command's results:\n");
187 printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32);
188 printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n",
189 !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1));
190 /* Extra info, not necessary to look at */
191 if (do_extra)
192 printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n",
193 io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);
194 }
195
196 /* Prepare TEST UNIT READY command */
197 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
198 io_hdr.interface_id = 'S';
199 io_hdr.cmd_len = sizeof(turCmdBlk);
200 io_hdr.mx_sb_len = sizeof(sense_buffer);
201 io_hdr.dxfer_direction = SG_DXFER_NONE;
202 io_hdr.cmdp = turCmdBlk;
203 io_hdr.sbp = sense_buffer;
204 io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
205
206 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
207 perror("sg_simple_aio: Test Unit Ready SG_IO ioctl error");
208 close(sg_fd);
209 return 1;
210 }
211
212 /* now for the error processing */
213 ok = 0;
214 switch (sg_err_category3(&io_hdr)) {
Douglas Gilbertfa6966c2007-06-27 03:00:59 +0000215 case SG_LIB_CAT_CLEAN:
Douglas Gilberta948a882007-06-27 02:56:58 +0000216 ok = 1;
217 break;
Douglas Gilbertfa6966c2007-06-27 03:00:59 +0000218 case SG_LIB_CAT_RECOVERED:
Douglas Gilberta948a882007-06-27 02:56:58 +0000219 printf("Recovered error on Test Unit Ready, continuing\n");
220 ok = 1;
221 break;
222 default: /* won't bother decoding other categories */
Douglas Gilbert78fa03f2010-03-21 02:14:23 +0000223 sg_chk_n_print3("Test Unit Ready command error", &io_hdr, 1);
Douglas Gilberta948a882007-06-27 02:56:58 +0000224 break;
225 }
226
227 if (ok)
228 printf("Test Unit Ready successful so unit is ready!\n");
229 else
230 printf("Test Unit Ready failed so unit may _not_ be ready!\n");
231
232 if (do_extra)
Douglas Gilbertfb2bb1d2012-12-11 12:56:34 +0000233 printf("TEST UNIT READY duration=%u millisecs, resid=%d, "
234 "msg_status=%d\n", io_hdr.duration, io_hdr.resid,
235 (int)io_hdr.msg_status);
Douglas Gilberta948a882007-06-27 02:56:58 +0000236
237 close(sg_fd);
238 return 0;
239}