xref: /aosp_15_r20/external/sg3_utils/src/sg_test_rwbuf.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
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