1*44704f69SBart Van Assche /*
2*44704f69SBart Van Assche * (c) 2000 Kurt Garloff
3*44704f69SBart Van Assche * heavily based on Douglas Gilbert's sg_rbuf program.
4*44704f69SBart Van Assche * (c) 1999-2022 Douglas Gilbert
5*44704f69SBart Van Assche *
6*44704f69SBart Van Assche * Program to test the SCSI host adapter by issuing
7*44704f69SBart Van Assche * write and read operations on a device's buffer
8*44704f69SBart Van Assche * and calculating checksums.
9*44704f69SBart Van Assche * NOTE: If you can not reserve the buffer of the device
10*44704f69SBart Van Assche * for this purpose (SG_GET_RESERVED_SIZE), you risk
11*44704f69SBart Van Assche * serious data corruption, if the device is accessed by
12*44704f69SBart Van Assche * somebody else in the meantime.
13*44704f69SBart Van Assche *
14*44704f69SBart Van Assche * This program is free software; you can redistribute it and/or modify
15*44704f69SBart Van Assche * it under the terms of the GNU General Public License as published by
16*44704f69SBart Van Assche * the Free Software Foundation; either version 2, or (at your option)
17*44704f69SBart Van Assche * any later version.
18*44704f69SBart Van Assche *
19*44704f69SBart Van Assche * SPDX-License-Identifier: GPL-2.0-or-later
20*44704f69SBart Van Assche *
21*44704f69SBart Van Assche * $Id: sg_test_rwbuf.c,v 1.1 2000/03/02 13:50:03 garloff Exp $
22*44704f69SBart Van Assche *
23*44704f69SBart Van Assche * 2003/11/11 switch sg3_utils version to use SG_IO ioctl [dpg]
24*44704f69SBart Van Assche * 2004/06/08 remove SG_GET_VERSION_NUM check [dpg]
25*44704f69SBart Van Assche */
26*44704f69SBart Van Assche
27*44704f69SBart Van Assche #include <unistd.h>
28*44704f69SBart Van Assche #include <fcntl.h>
29*44704f69SBart Van Assche #include <stdio.h>
30*44704f69SBart Van Assche #include <stdlib.h>
31*44704f69SBart Van Assche #include <stdarg.h>
32*44704f69SBart Van Assche #include <stdbool.h>
33*44704f69SBart Van Assche #include <string.h>
34*44704f69SBart Van Assche #include <errno.h>
35*44704f69SBart Van Assche #include <getopt.h>
36*44704f69SBart Van Assche #include <sys/ioctl.h>
37*44704f69SBart Van Assche #include <sys/types.h>
38*44704f69SBart Van Assche #include <time.h>
39*44704f69SBart Van Assche
40*44704f69SBart Van Assche #ifdef HAVE_CONFIG_H
41*44704f69SBart Van Assche #include "config.h"
42*44704f69SBart Van Assche #endif
43*44704f69SBart Van Assche
44*44704f69SBart Van Assche #include "sg_lib.h"
45*44704f69SBart Van Assche #include "sg_io_linux.h"
46*44704f69SBart Van Assche #include "sg_unaligned.h"
47*44704f69SBart Van Assche #include "sg_pr2serr.h"
48*44704f69SBart Van Assche
49*44704f69SBart Van Assche
50*44704f69SBart Van Assche static const char * version_str = "1.21 20220118";
51*44704f69SBart Van Assche
52*44704f69SBart Van Assche #define BPI (signed)(sizeof(int))
53*44704f69SBart Van Assche
54*44704f69SBart Van Assche #define RB_MODE_DESC 3
55*44704f69SBart Van Assche #define RWB_MODE_DATA 2
56*44704f69SBart Van Assche #define RB_DESC_LEN 4
57*44704f69SBart Van Assche
58*44704f69SBart Van Assche /* The microcode in a SCSI device is _not_ modified by doing a WRITE BUFFER
59*44704f69SBart Van Assche * with mode set to "data" (0x2) as done by this utility. Therefore this
60*44704f69SBart Van Assche * utility is safe in that respect. [Mode values 0x4, 0x5, 0x6 and 0x7 are
61*44704f69SBart Van Assche * the dangerous ones :-)]
62*44704f69SBart Van Assche */
63*44704f69SBart Van Assche
64*44704f69SBart Van Assche #define ME "sg_test_rwbuf: "
65*44704f69SBart Van Assche
66*44704f69SBart Van Assche static int base = 0x12345678;
67*44704f69SBart Van Assche static int buf_capacity = 0;
68*44704f69SBart Van Assche static int buf_granul = 255;
69*44704f69SBart Van Assche static uint8_t *cmpbuf = NULL;
70*44704f69SBart Van Assche static uint8_t *free_cmpbuf = NULL;
71*44704f69SBart Van Assche
72*44704f69SBart Van Assche
73*44704f69SBart Van Assche /* Options */
74*44704f69SBart Van Assche static int size = -1;
75*44704f69SBart Van Assche static bool do_quick = false;
76*44704f69SBart Van Assche static int addwrite = 0;
77*44704f69SBart Van Assche static int addread = 0;
78*44704f69SBart Van Assche static int verbose = 0;
79*44704f69SBart Van Assche
80*44704f69SBart Van Assche static struct option long_options[] = {
81*44704f69SBart Van Assche {"help", no_argument, 0, 'h'},
82*44704f69SBart Van Assche {"quick", no_argument, 0, 'q'},
83*44704f69SBart Van Assche {"addrd", required_argument, 0, 'r'},
84*44704f69SBart Van Assche {"size", required_argument, 0, 's'},
85*44704f69SBart Van Assche {"times", required_argument, 0, 't'},
86*44704f69SBart Van Assche {"verbose", no_argument, 0, 'v'},
87*44704f69SBart Van Assche {"version", no_argument, 0, 'V'},
88*44704f69SBart Van Assche {"addwr", required_argument, 0, 'w'},
89*44704f69SBart Van Assche {0, 0, 0, 0},
90*44704f69SBart Van Assche };
91*44704f69SBart Van Assche
92*44704f69SBart Van Assche static int
find_out_about_buffer(int sg_fd)93*44704f69SBart Van Assche find_out_about_buffer(int sg_fd)
94*44704f69SBart Van Assche {
95*44704f69SBart Van Assche uint8_t rb_cdb[] = {READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0};
96*44704f69SBart Van Assche uint8_t rbBuff[RB_DESC_LEN];
97*44704f69SBart Van Assche uint8_t sense_buffer[32];
98*44704f69SBart Van Assche struct sg_io_hdr io_hdr;
99*44704f69SBart Van Assche int res;
100*44704f69SBart Van Assche
101*44704f69SBart Van Assche rb_cdb[1] = RB_MODE_DESC;
102*44704f69SBart Van Assche rb_cdb[8] = RB_DESC_LEN;
103*44704f69SBart Van Assche memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
104*44704f69SBart Van Assche io_hdr.interface_id = 'S';
105*44704f69SBart Van Assche io_hdr.cmd_len = sizeof(rb_cdb);
106*44704f69SBart Van Assche io_hdr.mx_sb_len = sizeof(sense_buffer);
107*44704f69SBart Van Assche io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
108*44704f69SBart Van Assche io_hdr.dxfer_len = RB_DESC_LEN;
109*44704f69SBart Van Assche io_hdr.dxferp = rbBuff;
110*44704f69SBart Van Assche io_hdr.cmdp = rb_cdb;
111*44704f69SBart Van Assche io_hdr.sbp = sense_buffer;
112*44704f69SBart Van Assche io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */
113*44704f69SBart Van Assche
114*44704f69SBart Van Assche if (verbose) {
115*44704f69SBart Van Assche char b[128];
116*44704f69SBart Van Assche
117*44704f69SBart Van Assche pr2serr(" read buffer [mode desc] cdb: %s\n",
118*44704f69SBart Van Assche sg_get_command_str(rb_cdb, (int)sizeof(rb_cdb), false,
119*44704f69SBart Van Assche sizeof(b), b));
120*44704f69SBart Van Assche }
121*44704f69SBart Van Assche if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
122*44704f69SBart Van Assche perror(ME "SG_IO READ BUFFER descriptor error");
123*44704f69SBart Van Assche return -1;
124*44704f69SBart Van Assche }
125*44704f69SBart Van Assche /* now for the error processing */
126*44704f69SBart Van Assche res = sg_err_category3(&io_hdr);
127*44704f69SBart Van Assche switch (res) {
128*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
129*44704f69SBart Van Assche sg_chk_n_print3("READ BUFFER descriptor, continuing",
130*44704f69SBart Van Assche &io_hdr, true);
131*44704f69SBart Van Assche #if defined(__GNUC__)
132*44704f69SBart Van Assche #if (__GNUC__ >= 7)
133*44704f69SBart Van Assche __attribute__((fallthrough));
134*44704f69SBart Van Assche /* FALL THROUGH */
135*44704f69SBart Van Assche #endif
136*44704f69SBart Van Assche #endif
137*44704f69SBart Van Assche case SG_LIB_CAT_CLEAN:
138*44704f69SBart Van Assche break;
139*44704f69SBart Van Assche default: /* won't bother decoding other categories */
140*44704f69SBart Van Assche sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr,
141*44704f69SBart Van Assche true);
142*44704f69SBart Van Assche return res;
143*44704f69SBart Van Assche }
144*44704f69SBart Van Assche
145*44704f69SBart Van Assche buf_capacity = sg_get_unaligned_be24(rbBuff + 1);
146*44704f69SBart Van Assche buf_granul = (uint8_t)rbBuff[0];
147*44704f69SBart Van Assche #if 0
148*44704f69SBart Van Assche printf("READ BUFFER reports: %02x %02x %02x %02x\n",
149*44704f69SBart Van Assche rbBuff[0], rbBuff[1], rbBuff[2], rbBuff[3]);
150*44704f69SBart Van Assche #endif
151*44704f69SBart Van Assche if (verbose)
152*44704f69SBart Van Assche printf("READ BUFFER reports: buffer capacity=%d, offset "
153*44704f69SBart Van Assche "boundary=%d\n", buf_capacity, buf_granul);
154*44704f69SBart Van Assche return 0;
155*44704f69SBart Van Assche }
156*44704f69SBart Van Assche
157*44704f69SBart Van Assche static int
mymemcmp(uint8_t * bf1,uint8_t * bf2,int len)158*44704f69SBart Van Assche mymemcmp (uint8_t *bf1, uint8_t *bf2, int len)
159*44704f69SBart Van Assche {
160*44704f69SBart Van Assche int df;
161*44704f69SBart Van Assche for (df = 0; df < len; df++)
162*44704f69SBart Van Assche if (bf1[df] != bf2[df]) return df;
163*44704f69SBart Van Assche return 0;
164*44704f69SBart Van Assche }
165*44704f69SBart Van Assche
166*44704f69SBart Van Assche /* return 0 if good, else 2222 */
167*44704f69SBart Van Assche static int
do_checksum(int * buf,int len,bool quiet)168*44704f69SBart Van Assche do_checksum(int *buf, int len, bool quiet)
169*44704f69SBart Van Assche {
170*44704f69SBart Van Assche int sum = base;
171*44704f69SBart Van Assche int i; int rln = len;
172*44704f69SBart Van Assche for (i = 0; i < len/BPI; i++)
173*44704f69SBart Van Assche sum += buf[i];
174*44704f69SBart Van Assche while (rln%BPI) sum += ((char*)buf)[--rln];
175*44704f69SBart Van Assche if (sum != 0x12345678) {
176*44704f69SBart Van Assche if (!quiet) printf ("sg_test_rwbuf: Checksum error (sz=%i):"
177*44704f69SBart Van Assche " %08x\n", len, sum);
178*44704f69SBart Van Assche if (cmpbuf && !quiet) {
179*44704f69SBart Van Assche int diff = mymemcmp (cmpbuf, (uint8_t*)buf,
180*44704f69SBart Van Assche len);
181*44704f69SBart Van Assche printf ("Differ at pos %i/%i:\n", diff, len);
182*44704f69SBart Van Assche for (i = 0; i < 24 && i+diff < len; i++)
183*44704f69SBart Van Assche printf (" %02x", cmpbuf[i+diff]);
184*44704f69SBart Van Assche printf ("\n");
185*44704f69SBart Van Assche for (i = 0; i < 24 && i+diff < len; i++)
186*44704f69SBart Van Assche printf (" %02x",
187*44704f69SBart Van Assche ((uint8_t*)buf)[i+diff]);
188*44704f69SBart Van Assche printf ("\n");
189*44704f69SBart Van Assche }
190*44704f69SBart Van Assche return 2222;
191*44704f69SBart Van Assche }
192*44704f69SBart Van Assche else {
193*44704f69SBart Van Assche if (verbose > 1)
194*44704f69SBart Van Assche printf("Checksum value: 0x%x\n", sum);
195*44704f69SBart Van Assche return 0;
196*44704f69SBart Van Assche }
197*44704f69SBart Van Assche }
198*44704f69SBart Van Assche
do_fill_buffer(int * buf,int len)199*44704f69SBart Van Assche void do_fill_buffer (int *buf, int len)
200*44704f69SBart Van Assche {
201*44704f69SBart Van Assche int sum;
202*44704f69SBart Van Assche int i; int rln = len;
203*44704f69SBart Van Assche
204*44704f69SBart Van Assche srand(time(0));
205*44704f69SBart Van Assche retry:
206*44704f69SBart Van Assche if (len >= BPI)
207*44704f69SBart Van Assche base = 0x12345678 + rand(); /* don't need strong crypto */
208*44704f69SBart Van Assche else
209*44704f69SBart Van Assche base = 0x12345678 + (char)rand();
210*44704f69SBart Van Assche sum = base;
211*44704f69SBart Van Assche for (i = 0; i < len/BPI - 1; i++)
212*44704f69SBart Van Assche {
213*44704f69SBart Van Assche /* we rely on rand() giving full range of int */
214*44704f69SBart Van Assche buf[i] = rand();
215*44704f69SBart Van Assche sum += buf[i];
216*44704f69SBart Van Assche }
217*44704f69SBart Van Assche while (rln%BPI)
218*44704f69SBart Van Assche {
219*44704f69SBart Van Assche ((char*)buf)[--rln] = rand();
220*44704f69SBart Van Assche sum += ((char*)buf)[rln];
221*44704f69SBart Van Assche }
222*44704f69SBart Van Assche if (len >= BPI) buf[len/BPI - 1] = 0x12345678 - sum;
223*44704f69SBart Van Assche else ((char*)buf)[0] = 0x12345678 + ((char*)buf)[0] - sum;
224*44704f69SBart Van Assche if (do_checksum(buf, len, true)) {
225*44704f69SBart Van Assche if (len < BPI) goto retry;
226*44704f69SBart Van Assche printf ("sg_test_rwbuf: Memory corruption?\n");
227*44704f69SBart Van Assche exit (1);
228*44704f69SBart Van Assche }
229*44704f69SBart Van Assche if (cmpbuf) memcpy (cmpbuf, (char*)buf, len);
230*44704f69SBart Van Assche }
231*44704f69SBart Van Assche
232*44704f69SBart Van Assche
read_buffer(int sg_fd,unsigned ssize)233*44704f69SBart Van Assche int read_buffer (int sg_fd, unsigned ssize)
234*44704f69SBart Van Assche {
235*44704f69SBart Van Assche int res;
236*44704f69SBart Van Assche uint8_t rb_cdb[] = {READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0};
237*44704f69SBart Van Assche int bufSize = ssize + addread;
238*44704f69SBart Van Assche uint8_t * free_rbBuff = NULL;
239*44704f69SBart Van Assche uint8_t * rbBuff = (uint8_t *)sg_memalign(bufSize, 0, &free_rbBuff,
240*44704f69SBart Van Assche false);
241*44704f69SBart Van Assche uint8_t sense_buffer[32];
242*44704f69SBart Van Assche struct sg_io_hdr io_hdr;
243*44704f69SBart Van Assche
244*44704f69SBart Van Assche if (NULL == rbBuff)
245*44704f69SBart Van Assche return -1;
246*44704f69SBart Van Assche rb_cdb[1] = RWB_MODE_DATA;
247*44704f69SBart Van Assche sg_put_unaligned_be24((uint32_t)bufSize, rb_cdb + 6);
248*44704f69SBart Van Assche memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
249*44704f69SBart Van Assche io_hdr.interface_id = 'S';
250*44704f69SBart Van Assche io_hdr.cmd_len = sizeof(rb_cdb);
251*44704f69SBart Van Assche io_hdr.mx_sb_len = sizeof(sense_buffer);
252*44704f69SBart Van Assche io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
253*44704f69SBart Van Assche io_hdr.dxfer_len = bufSize;
254*44704f69SBart Van Assche io_hdr.dxferp = rbBuff;
255*44704f69SBart Van Assche io_hdr.cmdp = rb_cdb;
256*44704f69SBart Van Assche io_hdr.sbp = sense_buffer;
257*44704f69SBart Van Assche io_hdr.pack_id = 2;
258*44704f69SBart Van Assche io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */
259*44704f69SBart Van Assche if (verbose) {
260*44704f69SBart Van Assche char b[128];
261*44704f69SBart Van Assche
262*44704f69SBart Van Assche pr2serr(" read buffer [mode data] cdb: %s\n",
263*44704f69SBart Van Assche sg_get_command_str(rb_cdb, (int)sizeof(rb_cdb), false,
264*44704f69SBart Van Assche sizeof(b), b));
265*44704f69SBart Van Assche }
266*44704f69SBart Van Assche
267*44704f69SBart Van Assche if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
268*44704f69SBart Van Assche perror(ME "SG_IO READ BUFFER data error");
269*44704f69SBart Van Assche free(rbBuff);
270*44704f69SBart Van Assche return -1;
271*44704f69SBart Van Assche }
272*44704f69SBart Van Assche /* now for the error processing */
273*44704f69SBart Van Assche res = sg_err_category3(&io_hdr);
274*44704f69SBart Van Assche switch (res) {
275*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
276*44704f69SBart Van Assche sg_chk_n_print3("READ BUFFER data, continuing", &io_hdr, true);
277*44704f69SBart Van Assche #if defined(__GNUC__)
278*44704f69SBart Van Assche #if (__GNUC__ >= 7)
279*44704f69SBart Van Assche __attribute__((fallthrough));
280*44704f69SBart Van Assche /* FALL THROUGH */
281*44704f69SBart Van Assche #endif
282*44704f69SBart Van Assche #endif
283*44704f69SBart Van Assche case SG_LIB_CAT_CLEAN:
284*44704f69SBart Van Assche break;
285*44704f69SBart Van Assche default: /* won't bother decoding other categories */
286*44704f69SBart Van Assche sg_chk_n_print3("READ BUFFER data error", &io_hdr, true);
287*44704f69SBart Van Assche free(rbBuff);
288*44704f69SBart Van Assche return res;
289*44704f69SBart Van Assche }
290*44704f69SBart Van Assche
291*44704f69SBart Van Assche res = do_checksum((int*)rbBuff, ssize, false);
292*44704f69SBart Van Assche if (free_rbBuff)
293*44704f69SBart Van Assche free(free_rbBuff);
294*44704f69SBart Van Assche return res;
295*44704f69SBart Van Assche }
296*44704f69SBart Van Assche
write_buffer(int sg_fd,unsigned ssize)297*44704f69SBart Van Assche int write_buffer (int sg_fd, unsigned ssize)
298*44704f69SBart Van Assche {
299*44704f69SBart Van Assche uint8_t wb_cdb[] = {WRITE_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0};
300*44704f69SBart Van Assche int bufSize = ssize + addwrite;
301*44704f69SBart Van Assche uint8_t * free_wbBuff = NULL;
302*44704f69SBart Van Assche uint8_t * wbBuff = (uint8_t *)sg_memalign(bufSize, 0, &free_wbBuff,
303*44704f69SBart Van Assche false);
304*44704f69SBart Van Assche uint8_t sense_buffer[32];
305*44704f69SBart Van Assche struct sg_io_hdr io_hdr;
306*44704f69SBart Van Assche int res;
307*44704f69SBart Van Assche
308*44704f69SBart Van Assche if (NULL == wbBuff)
309*44704f69SBart Van Assche return -1;
310*44704f69SBart Van Assche memset(wbBuff, 0, bufSize);
311*44704f69SBart Van Assche do_fill_buffer ((int*)wbBuff, ssize);
312*44704f69SBart Van Assche wb_cdb[1] = RWB_MODE_DATA;
313*44704f69SBart Van Assche sg_put_unaligned_be24((uint32_t)bufSize, wb_cdb + 6);
314*44704f69SBart Van Assche memset(&io_hdr, 0, sizeof(struct sg_io_hdr));
315*44704f69SBart Van Assche io_hdr.interface_id = 'S';
316*44704f69SBart Van Assche io_hdr.cmd_len = sizeof(wb_cdb);
317*44704f69SBart Van Assche io_hdr.mx_sb_len = sizeof(sense_buffer);
318*44704f69SBart Van Assche io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
319*44704f69SBart Van Assche io_hdr.dxfer_len = bufSize;
320*44704f69SBart Van Assche io_hdr.dxferp = wbBuff;
321*44704f69SBart Van Assche io_hdr.cmdp = wb_cdb;
322*44704f69SBart Van Assche io_hdr.sbp = sense_buffer;
323*44704f69SBart Van Assche io_hdr.pack_id = 1;
324*44704f69SBart Van Assche io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */
325*44704f69SBart Van Assche if (verbose) {
326*44704f69SBart Van Assche char b[128];
327*44704f69SBart Van Assche
328*44704f69SBart Van Assche pr2serr(" write buffer [mode data] cdb: %s\n",
329*44704f69SBart Van Assche sg_get_command_str(wb_cdb, (int)sizeof(wb_cdb), false,
330*44704f69SBart Van Assche sizeof(b), b));
331*44704f69SBart Van Assche }
332*44704f69SBart Van Assche
333*44704f69SBart Van Assche if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
334*44704f69SBart Van Assche perror(ME "SG_IO WRITE BUFFER data error");
335*44704f69SBart Van Assche free(wbBuff);
336*44704f69SBart Van Assche return -1;
337*44704f69SBart Van Assche }
338*44704f69SBart Van Assche /* now for the error processing */
339*44704f69SBart Van Assche res = sg_err_category3(&io_hdr);
340*44704f69SBart Van Assche switch (res) {
341*44704f69SBart Van Assche case SG_LIB_CAT_RECOVERED:
342*44704f69SBart Van Assche sg_chk_n_print3("WRITE BUFFER data, continuing", &io_hdr, true);
343*44704f69SBart Van Assche #if defined(__GNUC__)
344*44704f69SBart Van Assche #if (__GNUC__ >= 7)
345*44704f69SBart Van Assche __attribute__((fallthrough));
346*44704f69SBart Van Assche /* FALL THROUGH */
347*44704f69SBart Van Assche #endif
348*44704f69SBart Van Assche #endif
349*44704f69SBart Van Assche case SG_LIB_CAT_CLEAN:
350*44704f69SBart Van Assche break;
351*44704f69SBart Van Assche default: /* won't bother decoding other categories */
352*44704f69SBart Van Assche sg_chk_n_print3("WRITE BUFFER data error", &io_hdr, true);
353*44704f69SBart Van Assche free(wbBuff);
354*44704f69SBart Van Assche return res;
355*44704f69SBart Van Assche }
356*44704f69SBart Van Assche if (free_wbBuff)
357*44704f69SBart Van Assche free(free_wbBuff);
358*44704f69SBart Van Assche return res;
359*44704f69SBart Van Assche }
360*44704f69SBart Van Assche
usage()361*44704f69SBart Van Assche void usage ()
362*44704f69SBart Van Assche {
363*44704f69SBart Van Assche printf ("Usage: sg_test_rwbuf [--addrd=AR] [--addwr=AW] [--help] "
364*44704f69SBart Van Assche "[--quick]\n");
365*44704f69SBart Van Assche printf (" --size=SZ [--times=NUM] [--verbose] "
366*44704f69SBart Van Assche "[--version]\n"
367*44704f69SBart Van Assche " DEVICE\n"
368*44704f69SBart Van Assche " or\n"
369*44704f69SBart Van Assche " sg_test_rwbuf DEVICE SZ [AW] [AR]\n");
370*44704f69SBart Van Assche printf (" where:\n"
371*44704f69SBart Van Assche " --addrd=AR|-r extra bytes to fetch during READ "
372*44704f69SBart Van Assche "BUFFER\n"
373*44704f69SBart Van Assche " --addwr=AW|-w extra bytes to send to WRITE BUFFER\n"
374*44704f69SBart Van Assche " --help|-l output this usage message then exit\n"
375*44704f69SBart Van Assche " --quick|-q output read buffer size then exit\n"
376*44704f69SBart Van Assche " --size=SZ|-s size of buffer (in bytes) to write "
377*44704f69SBart Van Assche "then read back\n"
378*44704f69SBart Van Assche " --times=NUM|-t number of times to run test "
379*44704f69SBart Van Assche "(default 1)\n"
380*44704f69SBart Van Assche " --verbose|-v increase verbosity of output\n"
381*44704f69SBart Van Assche " --version|-V output version then exit\n");
382*44704f69SBart Van Assche printf ("\nWARNING: If you access the device at the same time, e.g. "
383*44704f69SBart Van Assche "because it's a\n");
384*44704f69SBart Van Assche printf (" mounted hard disk, the device's buffer may be used by the "
385*44704f69SBart Van Assche "device itself\n");
386*44704f69SBart Van Assche printf (" for other data at the same time, and overwriting it may or "
387*44704f69SBart Van Assche "may not\n");
388*44704f69SBart Van Assche printf (" cause data corruption!\n");
389*44704f69SBart Van Assche printf ("(c) Douglas Gilbert, Kurt Garloff, 2000-2007, GNU GPL\n");
390*44704f69SBart Van Assche }
391*44704f69SBart Van Assche
392*44704f69SBart Van Assche
main(int argc,char * argv[])393*44704f69SBart Van Assche int main (int argc, char * argv[])
394*44704f69SBart Van Assche {
395*44704f69SBart Van Assche bool verbose_given = false;
396*44704f69SBart Van Assche bool version_given = false;
397*44704f69SBart Van Assche int sg_fd, res;
398*44704f69SBart Van Assche const char * device_name = NULL;
399*44704f69SBart Van Assche int times = 1;
400*44704f69SBart Van Assche int ret = 0;
401*44704f69SBart Van Assche int k = 0;
402*44704f69SBart Van Assche int err;
403*44704f69SBart Van Assche
404*44704f69SBart Van Assche while (1) {
405*44704f69SBart Van Assche int option_index = 0;
406*44704f69SBart Van Assche int c;
407*44704f69SBart Van Assche
408*44704f69SBart Van Assche c = getopt_long(argc, argv, "hqr:s:t:w:vV",
409*44704f69SBart Van Assche long_options, &option_index);
410*44704f69SBart Van Assche if (c == -1)
411*44704f69SBart Van Assche break;
412*44704f69SBart Van Assche
413*44704f69SBart Van Assche switch (c) {
414*44704f69SBart Van Assche case 'h':
415*44704f69SBart Van Assche usage();
416*44704f69SBart Van Assche return 0;
417*44704f69SBart Van Assche case 'q':
418*44704f69SBart Van Assche do_quick = true;
419*44704f69SBart Van Assche break;
420*44704f69SBart Van Assche case 'r':
421*44704f69SBart Van Assche addread = sg_get_num(optarg);
422*44704f69SBart Van Assche if (-1 == addread) {
423*44704f69SBart Van Assche pr2serr("bad argument to '--addrd'\n");
424*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
425*44704f69SBart Van Assche }
426*44704f69SBart Van Assche break;
427*44704f69SBart Van Assche case 's':
428*44704f69SBart Van Assche size = sg_get_num(optarg);
429*44704f69SBart Van Assche if (-1 == size) {
430*44704f69SBart Van Assche pr2serr("bad argument to '--size'\n");
431*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
432*44704f69SBart Van Assche }
433*44704f69SBart Van Assche break;
434*44704f69SBart Van Assche case 't':
435*44704f69SBart Van Assche times = sg_get_num(optarg);
436*44704f69SBart Van Assche if (-1 == times) {
437*44704f69SBart Van Assche pr2serr("bad argument to '--times'\n");
438*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
439*44704f69SBart Van Assche }
440*44704f69SBart Van Assche break;
441*44704f69SBart Van Assche case 'v':
442*44704f69SBart Van Assche verbose_given = true;
443*44704f69SBart Van Assche verbose++;
444*44704f69SBart Van Assche break;
445*44704f69SBart Van Assche case 'V':
446*44704f69SBart Van Assche version_given = true;
447*44704f69SBart Van Assche break;
448*44704f69SBart Van Assche case 'w':
449*44704f69SBart Van Assche addwrite = sg_get_num(optarg);
450*44704f69SBart Van Assche if (-1 == addwrite) {
451*44704f69SBart Van Assche pr2serr("bad argument to '--addwr'\n");
452*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
453*44704f69SBart Van Assche }
454*44704f69SBart Van Assche break;
455*44704f69SBart Van Assche default:
456*44704f69SBart Van Assche usage();
457*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
458*44704f69SBart Van Assche }
459*44704f69SBart Van Assche }
460*44704f69SBart Van Assche if (optind < argc) {
461*44704f69SBart Van Assche if (NULL == device_name) {
462*44704f69SBart Van Assche device_name = argv[optind];
463*44704f69SBart Van Assche ++optind;
464*44704f69SBart Van Assche }
465*44704f69SBart Van Assche }
466*44704f69SBart Van Assche if (optind < argc) {
467*44704f69SBart Van Assche if (-1 == size) {
468*44704f69SBart Van Assche size = sg_get_num(argv[optind]);
469*44704f69SBart Van Assche if (-1 == size) {
470*44704f69SBart Van Assche pr2serr("bad <sz>\n");
471*44704f69SBart Van Assche usage();
472*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
473*44704f69SBart Van Assche }
474*44704f69SBart Van Assche if (++optind < argc) {
475*44704f69SBart Van Assche addwrite = sg_get_num(argv[optind]);
476*44704f69SBart Van Assche if (-1 == addwrite) {
477*44704f69SBart Van Assche pr2serr("bad [addwr]\n");
478*44704f69SBart Van Assche usage();
479*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
480*44704f69SBart Van Assche }
481*44704f69SBart Van Assche if (++optind < argc) {
482*44704f69SBart Van Assche addread = sg_get_num(argv[optind]);
483*44704f69SBart Van Assche if (-1 == addread) {
484*44704f69SBart Van Assche pr2serr("bad [addrd]\n");
485*44704f69SBart Van Assche usage();
486*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
487*44704f69SBart Van Assche }
488*44704f69SBart Van Assche }
489*44704f69SBart Van Assche }
490*44704f69SBart Van Assche
491*44704f69SBart Van Assche }
492*44704f69SBart Van Assche if (optind < argc) {
493*44704f69SBart Van Assche for (; optind < argc; ++optind)
494*44704f69SBart Van Assche pr2serr("Unexpected extra argument" ": %s\n",
495*44704f69SBart Van Assche argv[optind]);
496*44704f69SBart Van Assche usage();
497*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
498*44704f69SBart Van Assche }
499*44704f69SBart Van Assche }
500*44704f69SBart Van Assche
501*44704f69SBart Van Assche #ifdef DEBUG
502*44704f69SBart Van Assche pr2serr("In DEBUG mode, ");
503*44704f69SBart Van Assche if (verbose_given && version_given) {
504*44704f69SBart Van Assche pr2serr("but override: '-vV' given, zero verbose and "
505*44704f69SBart Van Assche "continue\n");
506*44704f69SBart Van Assche verbose_given = false;
507*44704f69SBart Van Assche version_given = false;
508*44704f69SBart Van Assche verbose = 0;
509*44704f69SBart Van Assche } else if (! verbose_given) {
510*44704f69SBart Van Assche pr2serr("set '-vv'\n");
511*44704f69SBart Van Assche verbose = 2;
512*44704f69SBart Van Assche } else
513*44704f69SBart Van Assche pr2serr("keep verbose=%d\n", verbose);
514*44704f69SBart Van Assche #else
515*44704f69SBart Van Assche if (verbose_given && version_given)
516*44704f69SBart Van Assche pr2serr("Not in DEBUG mode, so '-vV' has no special action\n");
517*44704f69SBart Van Assche #endif
518*44704f69SBart Van Assche if (version_given) {
519*44704f69SBart Van Assche pr2serr(ME "version: %s\n", version_str);
520*44704f69SBart Van Assche return 0;
521*44704f69SBart Van Assche }
522*44704f69SBart Van Assche
523*44704f69SBart Van Assche if (NULL == device_name) {
524*44704f69SBart Van Assche pr2serr("no device name given\n");
525*44704f69SBart Van Assche usage();
526*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
527*44704f69SBart Van Assche }
528*44704f69SBart Van Assche if ((size <= 0) && (! do_quick)) {
529*44704f69SBart Van Assche pr2serr("must give '--size' or '--quick' options or <sz> "
530*44704f69SBart Van Assche "argument\n");
531*44704f69SBart Van Assche usage();
532*44704f69SBart Van Assche return SG_LIB_SYNTAX_ERROR;
533*44704f69SBart Van Assche }
534*44704f69SBart Van Assche
535*44704f69SBart Van Assche sg_fd = open(device_name, O_RDWR | O_NONBLOCK);
536*44704f69SBart Van Assche if (sg_fd < 0) {
537*44704f69SBart Van Assche err = errno;
538*44704f69SBart Van Assche perror("sg_test_rwbuf: open error");
539*44704f69SBart Van Assche return sg_convert_errno(err);
540*44704f69SBart Van Assche }
541*44704f69SBart Van Assche ret = find_out_about_buffer(sg_fd);
542*44704f69SBart Van Assche if (ret)
543*44704f69SBart Van Assche goto err_out;
544*44704f69SBart Van Assche if (do_quick) {
545*44704f69SBart Van Assche printf ("READ BUFFER read descriptor reports a buffer "
546*44704f69SBart Van Assche "of %d bytes [%d KiB]\n", buf_capacity,
547*44704f69SBart Van Assche buf_capacity / 1024);
548*44704f69SBart Van Assche goto err_out;
549*44704f69SBart Van Assche }
550*44704f69SBart Van Assche if (size > buf_capacity) {
551*44704f69SBart Van Assche pr2serr (ME "sz=%i > buf_capacity=%i\n", size, buf_capacity);
552*44704f69SBart Van Assche ret = SG_LIB_CAT_OTHER;
553*44704f69SBart Van Assche goto err_out;
554*44704f69SBart Van Assche }
555*44704f69SBart Van Assche
556*44704f69SBart Van Assche cmpbuf = (uint8_t *)sg_memalign(size, 0, &free_cmpbuf, false);
557*44704f69SBart Van Assche for (k = 0; k < times; ++k) {
558*44704f69SBart Van Assche ret = write_buffer (sg_fd, size);
559*44704f69SBart Van Assche if (ret) {
560*44704f69SBart Van Assche goto err_out;
561*44704f69SBart Van Assche }
562*44704f69SBart Van Assche ret = read_buffer (sg_fd, size);
563*44704f69SBart Van Assche if (ret) {
564*44704f69SBart Van Assche if (2222 == ret)
565*44704f69SBart Van Assche ret = SG_LIB_CAT_MALFORMED;
566*44704f69SBart Van Assche goto err_out;
567*44704f69SBart Van Assche }
568*44704f69SBart Van Assche }
569*44704f69SBart Van Assche
570*44704f69SBart Van Assche err_out:
571*44704f69SBart Van Assche if (free_cmpbuf)
572*44704f69SBart Van Assche free(free_cmpbuf);
573*44704f69SBart Van Assche res = close(sg_fd);
574*44704f69SBart Van Assche if (res < 0) {
575*44704f69SBart Van Assche perror(ME "close error");
576*44704f69SBart Van Assche if (0 == ret)
577*44704f69SBart Van Assche ret = sg_convert_errno(errno);
578*44704f69SBart Van Assche }
579*44704f69SBart Van Assche if ((0 == ret) && (! do_quick))
580*44704f69SBart Van Assche printf ("Success\n");
581*44704f69SBart Van Assche else if (times > 1)
582*44704f69SBart Van Assche printf ("Failed after %d successful cycles\n", k);
583*44704f69SBart Van Assche return (ret >= 0) ? ret : SG_LIB_CAT_OTHER;
584*44704f69SBart Van Assche }
585