1 /* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg")
2 device driver.
3 * Copyright (C) 1999 - 2002 D. Gilbert
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8
9 This program scans the "sg" device space (ie actual + simulated SCSI
10 generic devices).
11 Options: -w open writable (new driver opens readable unless -i)
12 -n numeric scan: scan /dev/sg0,1,2, ....
13 -a alpha scan: scan /dev/sga,b,c, ....
14 -i do SCSI inquiry on device (implies -w)
15 -x extra information output
16
17 By default this program will look for /dev/sg0 first (i.e. numeric scan)
18
19 Note: This program is written to work under both the original and
20 the new sg driver.
21
22 Version 1.00 20031022
23
24 F. Jansen - modification to extend beyond 26 sg devices.
25 M. Ridgeway - Roll code together for SCSI testing with one command line
26
27 6 byte INQUIRY command:
28 [0x12][ |lu][pg cde][res ][al len][cntrl ]
29 */
30
31 #define _GNU_SOURCE
32 #include <unistd.h>
33 #include <fcntl.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <dirent.h>
39 #include <limits.h>
40 #include <time.h>
41 #include <sys/ioctl.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <signal.h>
45 #include <ctype.h>
46 #include <pthread.h>
47 #include <sys/sysmacros.h>
48 #include <sys/time.h>
49 #include <sys/mman.h>
50 #include <linux/major.h>
51 #include "sg_include.h"
52 #include "sg_err.h"
53 #include "llseek.h"
54
55 #define ME "scsimain: "
56
57 #define NUMERIC_SCAN_DEF 1 /* change to 0 to make alpha scan default */
58 //static char * version_str = "0.21 20030513";
59
60 #define BPI (signed)(sizeof(int))
61 #define READWRITE_BASE_NUM 0x12345678
62 #define DEF_BLOCK_SIZE 512
63 #define DEF_NUM_THREADS 16
64 #define MAX_NUM_THREADS SG_MAX_QUEUE
65 #define DEF_BLOCKS_PER_TRANSFER 128
66 #define DEF_SCSI_CDBSZ 10
67 #define MAX_SCSI_CDBSZ 16
68 #define TUR_CMD_LEN 6
69 #define DEVNAME_SZ 256
70 #define MAX_HOLES 4
71
72 #define OFF sizeof(struct sg_header)
73 #define INQ_REPLY_LEN 96 /* logic assumes >= sizeof(inqCmdBlk) */
74 #define INQUIRY_CMDLEN 6
75 #define INQUIRY_CMD 0x12
76 #define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
77 #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */
78 #define REASON_SZ 128
79
80 #define SENSE_BUFF_SZ 64
81 #define RCAP_REPLY_LEN 8
82 #define LOG_SENSE_CMD 0x4d
83 #define LOG_SENSE_CMDLEN 10
84 #define MX_ALLOC_LEN (1024 * 17)
85 #define D_ROOT_SZ 512
86 #define STR_SZ 1024
87 #define INOUTF_SZ 512
88 #define EBUFF_SZ 512
89 #define MDEV_NAME_SZ 256
90
91 #define PG_CODE_ALL 0x00
92
93 #define TRUE 1
94 #define FALSE 0
95 #define MAX_DEVICES 50
96
97 #define NAME_LEN_MAX 256
98 #define LEVELS 4
99
100 #define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */
101 #define INQ_ALLOC_LEN 255
102
103 #ifndef SCSI_IOCTL_GET_PCI
104 #define SCSI_IOCTL_GET_PCI 0x5387
105 #endif
106
107 #define READ_CAP_REPLY_LEN 8
108
109 #ifndef RAW_MAJOR
110 #define RAW_MAJOR 255 /*unlikey value */
111 #endif
112
113 #define FT_OTHER 1 /* filetype is probably normal */
114 #define FT_SG 2 /* filetype is sg char device or supports
115 SG_IO ioctl */
116 #define FT_RAW 4 /* filetype is raw char device */
117 #define FT_DEV_NULL 8 /* either "/dev/null" or "." as filename */
118 #define FT_ST 16 /* filetype is st char device (tape) */
119 #define FT_BLOCK 32 /* filetype is block device */
120
121 #define DEV_NULL_MINOR_NUM 3
122
123 #ifdef SG_GET_RESERVED_SIZE
124 #define OPEN_FLAG O_RDONLY
125 #else
126 #define OPEN_FLAG O_RDWR
127 #endif
128
129 #ifndef SG_MAX_SENSE
130 #define SG_MAX_SENSE 16
131 #endif
132
133 #define TEST_START 0
134 #define TEST_BREAK 1
135 #define TEST_STOP 2
136 #define MAX_SG_DEVS 128
137 #define MAX_SD_DEVS 128
138 #define MAX_SR_DEVS 128
139 #define MAX_ST_DEVS 128
140 #define MAX_OSST_DEVS 128
141 #define MAX_ERRORS 5
142
143 #define LIN_DEV_TYPE_UNKNOWN 0
144 #define LIN_DEV_TYPE_SD 1
145 #define LIN_DEV_TYPE_SR 2
146 #define LIN_DEV_TYPE_ST 3
147 #define LIN_DEV_TYPE_SCD 4
148 #define LIN_DEV_TYPE_OSST 5
149
150 #define MODE_SENSE6_CMD 0x1a
151 #define MODE_SENSE6_CMDLEN 6
152 #define MODE_SENSE10_CMD 0x5a
153 #define MODE_SENSE10_CMDLEN 10
154 #define INQUIRY_CMD 0x12
155 #define INQUIRY_CMDLEN 6
156 #define MODE_ALLOC_LEN (1024 * 4)
157
158 #define MODE_CODE_ALL 0x3f
159
160 #define RB_MODE_DESC 3
161 #define RB_MODE_DATA 2
162 #define RB_DESC_LEN 4
163 #define RB_MB_TO_READ 200
164 #define RB_OPCODE 0x3C
165 #define RB_CMD_LEN 10
166
167 /* #define SG_DEBUG */
168
169 #ifndef SG_FLAG_MMAP_IO
170 #define SG_FLAG_MMAP_IO 4
171 #endif
172 #ifndef SG_SCSI_RESET
173 #define SG_SCSI_RESET 0x2284
174 #endif
175
176 #ifndef SG_SCSI_RESET_NOTHING
177 #define SG_SCSI_RESET_NOTHING 0
178 #define SG_SCSI_RESET_DEVICE 1
179 #define SG_SCSI_RESET_BUS 2
180 #define SG_SCSI_RESET_HOST 3
181 #endif
182 #define LONG_TIMEOUT 2400000 /* 2,400,000 millisecs == 40 minutes */
183
184 #define SEND_DIAGNOSTIC_CMD 0x1d
185 #define SEND_DIAGNOSTIC_CMDLEN 6
186 #define RECEIVE_DIAGNOSTIC_CMD 0x1c
187 #define RECEIVE_DIAGNOSTIC_CMDLEN 6
188
189 #define START_STOP 0x1b
190 #define SYNCHRONIZE_CACHE 0x35
191
192 #define DEF_START_TIMEOUT 120000 /* 120,000 millisecs == 2 minutes */
193
194 #define DEVICE_RESET 0
195 #define HOST_RESET 1
196 #define BUS_RESET 2
197 #define SG_HSZ sizeof(struct sg_header)
198 #define OFFSET_HEADER (SG_HSZ - (2 * sizeof(int)))
199 #define SIZEOF_BUFFER (256*1024)
200 #define SIZEOF_BUFFER1 (16*1024)
201 #define MAXPARM 32
202
203 #define SETUP_MODE_PAGE(NPAGE, NPARAM) \
204 status = get_mode_page(NPAGE, page_code); \
205 if (status) { printf("\n"); return status; } \
206 bdlen = buffer[11]; \
207 pagestart = buffer + 12 + bdlen;
208
209 typedef struct request_collection { /* one instance visible to all threads */
210 int infd;
211 int skip;
212 int in_type;
213 int in_scsi_type;
214 int in_blk; /* -\ next block address to read */
215 int in_count; /* | blocks remaining for next read */
216 int in_done_count; /* | count of completed in blocks */
217 int in_partial; /* | */
218 int in_stop; /* | */
219 pthread_mutex_t in_mutex; /* -/ */
220 int outfd;
221 int seek;
222 int out_type;
223 int out_scsi_type;
224 int out_blk; /* -\ next block address to write */
225 int out_count; /* | blocks remaining for next write */
226 int out_done_count; /* | count of completed out blocks */
227 int out_partial; /* | */
228 int out_stop; /* | */
229 pthread_mutex_t out_mutex; /* | */
230 pthread_cond_t out_sync_cv; /* -/ hold writes until "in order" */
231 int bs;
232 int bpt;
233 int fua_mode;
234 int dio;
235 int dio_incomplete; /* -\ */
236 int sum_of_resids; /* | */
237 pthread_mutex_t aux_mutex; /* -/ (also serializes some printf()s */
238 int coe;
239 int cdbsz;
240 int debug;
241 } Rq_coll;
242
243 typedef struct request_element { /* one instance per worker thread */
244 int infd;
245 int outfd;
246 int wr;
247 int blk;
248 int num_blks;
249 unsigned char *buffp;
250 unsigned char *alloc_bp;
251 sg_io_hdr_t io_hdr;
252 unsigned char cmd[MAX_SCSI_CDBSZ];
253 unsigned char sb[SENSE_BUFF_LEN];
254 int bs;
255 int fua_mode;
256 int dio;
257 int dio_incomplete;
258 int resid;
259 int in_scsi_type;
260 int out_scsi_type;
261 int cdbsz;
262 int debug;
263 } Rq_elem;
264
265 typedef struct my_map_info {
266 int active;
267 int lin_dev_type;
268 int oth_dev_num;
269 struct sg_scsi_id sg_dat;
270 char vendor[8];
271 char product[16];
272 char revision[4];
273 } my_map_info_t;
274
275 typedef struct sg_map {
276 int bus;
277 int channel;
278 int target_id;
279 int lun;
280 char *dev_name;
281 } Sg_map;
282
283 typedef struct my_scsi_idlun {
284 /* why can't userland see this structure ??? */
285 int dev_id;
286 int host_unique_id;
287 } My_scsi_idlun;
288
289 struct page_code_desc {
290 int page_code;
291 const char *desc;
292 };
293
294 static const char *pg_control_str_arr[] = {
295 "current",
296 "changeable",
297 "default",
298 "saved"
299 };
300
301 char *devices[] =
302 { "/dev/sda", "/dev/sdb", "/dev/sdc", "/dev/sdd", "/dev/sde", "/dev/sdf",
303 "/dev/sdg", "/dev/sdh", "/dev/sdi", "/dev/sdj", "/dev/sdk", "/dev/sdl",
304 "/dev/sdm", "/dev/sdn", "/dev/sdo", "/dev/sdp", "/dev/sdq", "/dev/sdr",
305 "/dev/sds", "/dev/sdt", "/dev/sdu", "/dev/sdv", "/dev/sdw", "/dev/sdx",
306 "/dev/sdy", "/dev/sdz", "/dev/sdaa", "/dev/sdab", "/dev/sdac",
307 "/dev/sdad",
308 "/dev/scd0", "/dev/scd1", "/dev/scd2", "/dev/scd3", "/dev/scd4",
309 "/dev/scd5",
310 "/dev/scd6", "/dev/scd7", "/dev/scd8", "/dev/scd9", "/dev/scd10",
311 "/dev/scd11",
312 "/dev/sr0", "/dev/sr1", "/dev/sr2", "/dev/sr3", "/dev/sr4", "/dev/sr5",
313 "/dev/sr6", "/dev/sr7", "/dev/sr8", "/dev/sr9", "/dev/sr10",
314 "/dev/sr11",
315 "/dev/nst0", "/dev/nst1", "/dev/nst2", "/dev/nst3", "/dev/nst4",
316 "/dev/nst5",
317 "/dev/nosst0", "/dev/nosst1", "/dev/nosst2", "/dev/nosst3",
318 "/dev/nosst4"
319 };
320
321 static char *page_names[] = {
322 NULL,
323 "Read-Write Error Recovery",
324 "Disconnect-Reconnect",
325 "Format Device",
326 "Rigid Disk Geometry",
327 /* "Flexible Disk" */ NULL,
328 NULL,
329 "Verify Error Recovery",
330 "Caching",
331 "Peripheral Device",
332 "Control Mode",
333 /* "Medium Types Supported" */ NULL,
334 "Notch and Partition",
335 /* "CD-ROM" */ NULL,
336 /* "CD-ROM Audio Control" */ NULL,
337 NULL,
338 /* "Medium Partition (1)" */ NULL,
339 /* "Medium Partition (2)" */ NULL,
340 /* "Medium Partition (3)" */ NULL,
341 /* "Medium Partition (4)" */ NULL
342 };
343
344 #define MAX_PAGENO (sizeof(page_names)/sizeof(char *))
345
346 /* Following 2 macros from D.R. Butenhof's POSIX threads book:
347 ISBN 0-201-63392-2 . [Highly recommended book.] */
348 #define err_exit(code,text) do { \
349 fprintf(stderr, "%s at \"%s\":%d: %s\n", \
350 text, __FILE__, __LINE__, strerror(code)); \
351 exit(1); \
352 } while (0)
353
354 static Sg_map sg_map_arr[(sizeof(devices) / sizeof(char *)) + 1];
355
356 static const unsigned char scsi_command_size[8] = { 6, 10, 10, 12,
357 12, 12, 10, 10
358 };
359 const unsigned char rbCmdBlk[10] = { READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
360 static const char *level_arr[LEVELS] = { "host", "bus", "target", "lun" };
361
362 static const char *proc_allow_dio = "/proc/scsi/sg/allow_dio";
363 static const char *devfs_id = "/dev/.devfsd";
364 static my_map_info_t map_arr[MAX_SG_DEVS];
365 static char ebuff[EBUFF_SZ];
366 static int glob_fd;
367 static char defectformat = 0x4;
368 static sigset_t signal_set;
369 static pthread_t sig_listen_thread_id;
370
371 static int do_ide = 0;
372 static int do_inq = 1;
373 static int do_leaf = 1;
374 static int do_extra = 1;
375 static int do_quiet = 0;
376 static int checked_sg = 1;
377 static int sum_of_resids = 0;
378
379 static int dd_count = -1;
380 static int in_full = 0;
381 static int in_partial = 0;
382 static int out_full = 0;
383 static int out_partial = 0;
384 static int do_coe = 0;
385 int base = READWRITE_BASE_NUM;
386 unsigned char *cmpbuf = 0;
387 static unsigned char buff_a[SIZEOF_BUFFER + SG_HSZ + 12];
388 static unsigned char *buffer = buff_a + OFFSET_HEADER;
389
390 typedef struct my_sg_scsi_id {
391 int host_no; /* as in "scsi<n>" where 'n' is one of 0, 1, 2 etc */
392 int channel;
393 int scsi_id; /* scsi id of target device */
394 int lun;
395 int scsi_type; /* TYPE_... defined in scsi/scsi.h */
396 short h_cmd_per_lun; /* host (adapter) maximum commands per lun */
397 short d_queue_depth; /* device (or adapter) maximum queue length */
398 int unused1; /* probably find a good use, set 0 for now */
399 int unused2; /* ditto */
400 } My_sg_scsi_id;
401
402 // Prototypes
403 int do_scsi_sgp_read_write(char *device);
404 int do_scsi_sgm_read_write(char *device);
405 void sg_in_operation(Rq_coll * clp, Rq_elem * rep);
406 void sg_out_operation(Rq_coll * clp, Rq_elem * rep);
407 int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks);
408 void normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks);
409 int sg_start_io(Rq_elem * rep);
410 int sg_finish_io(int wr, Rq_elem * rep, pthread_mutex_t * a_mutp);
411 int run_sg_scan_tests(void);
412 int show_scsi_logs(char *device);
413 int validate_device(char *device);
414 int show_devfs_devices(void);
415 void usage(void);
416 int do_scsi_device_read_write(char *device);
417 int do_scsi_inquiry(char *device, int hex_flag);
418 int show_scsi_maps(void);
419 int show_scsi_modes(char *device);
420 int do_scsi_read_buffer(char *device);
421 int show_scsi_read_capacity(char *device);
422 int do_scsi_reset_devices(char *device, int reset_opts);
423 int do_scsi_send_diagnostics(char *device);
424 int do_scsi_start_stop(char *device, int startstop);
425 int do_scsi_read_write_buffer(char *device);
426 int do_scsi_test_unit_ready(char *device);
427 int show_scsi_info(char *device);
428 void print_msg(int msg_num, const char *msg);
429 static void scan_dev_type(const char *leadin, int max_dev, int do_numeric,
430 int lin_dev_type, int last_sg_ind);
431
432 #ifdef SG_IO
433 int sg3_inq(int sg_fd, unsigned char *inqBuff, int do_extra);
434 #endif
435
436 static unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
437 { 0x12, 0, 0, 0, INQ_REPLY_LEN, 0 };
438
print_msg(int msg_num,const char * msg)439 void print_msg(int msg_num, const char *msg)
440 {
441 switch (msg_num) {
442 case TEST_START:
443 printf
444 ("\n****************** Starting Tests ***************************\n");
445 break;
446 case TEST_STOP:
447 printf
448 ("\n****************** Tests Complete ***************************\n");
449 break;
450 case TEST_BREAK:
451 printf("\n------------------ %s Test ------------------\n\n",
452 msg);
453 break;
454 }
455 }
456
main(int argc,char * argv[])457 int main(int argc, char *argv[])
458 {
459 int rc = 0;
460
461 if (argc < 2) {
462 printf("\n\nERROR:No device passed to test\n\n");
463 usage();
464 return 1;
465 }
466
467 rc = validate_device(argv[1]);
468 if (rc == 0) {
469
470 print_msg(TEST_START, NULL);
471
472 rc = run_sg_scan_tests();
473 if (rc != 0) {
474 printf("ERROR: run_sg_scan_tests failed %d\n", rc);
475 }
476
477 rc = show_scsi_logs(argv[1]);
478 if (rc != 0) {
479 printf("ERROR: show_scsi_logs failed %d\n", rc);
480 }
481
482 rc = show_devfs_devices();
483 if (rc != 0) {
484 printf("ERROR: show_devfs_devices failed %d\n", rc);
485 }
486
487 rc = do_scsi_device_read_write(argv[1]);
488 if (rc != 0) {
489 printf("ERROR: do_scsi_devices_read_write failed %d\n",
490 rc);
491 }
492
493 rc = do_scsi_inquiry(argv[1], TRUE);
494 if (rc != 0) {
495 printf("ERROR: do_scsi_inquiry HEX failed %d\n", rc);
496 } else {
497 rc = do_scsi_inquiry(argv[1], FALSE);
498 if (rc != 0) {
499 printf("ERROR: do_scsi_inquiry PCI failed %d\n",
500 rc);
501 }
502 }
503
504 rc = show_scsi_maps();
505 if (rc != 0) {
506 printf("ERROR: show_scsi_maps failed %d\n", rc);
507 }
508
509 rc = show_scsi_modes(argv[1]);
510 if (rc != 0) {
511 printf("ERROR: show_scsi_modes failed %d\n", rc);
512 }
513
514 rc = do_scsi_read_buffer(argv[1]);
515 if (rc != 0 && rc != 1) {
516 printf("ERROR: do_scsi_read_buffer failed %d\n", rc);
517 }
518
519 rc = show_scsi_read_capacity(argv[1]);
520 if (rc != 0) {
521 printf("ERROR: show_scsi_read_capacity failed %d\n",
522 rc);
523 }
524
525 rc |= do_scsi_reset_devices(argv[1], DEVICE_RESET);
526 rc |= do_scsi_reset_devices(argv[1], BUS_RESET);
527 rc |= do_scsi_reset_devices(argv[1], HOST_RESET);
528 if (rc != 0) {
529 printf("ERROR: do_scsi_reset_devices failed %d\n", rc);
530 }
531
532 rc = do_scsi_send_diagnostics(argv[1]);
533 if (rc != 0) {
534 printf("ERROR: do_scsi_send_diagnostics failed %d\n",
535 rc);
536 }
537
538 rc |= do_scsi_start_stop(argv[1], FALSE);
539 rc |= do_scsi_start_stop(argv[1], TRUE);
540 if (rc != 0) {
541 printf("ERROR: do_scsi_start_top failed %d\n", rc);
542 }
543
544 rc = do_scsi_read_write_buffer(argv[1]);
545 if (rc != 0 && rc != 1) {
546 printf("ERROR: do_scsi_read_write_buffer failed %d\n",
547 rc);
548 }
549
550 rc = do_scsi_test_unit_ready(argv[1]);
551 if (rc != 0) {
552 printf("ERROR: do_scsi_test_unit_ready failed %d\n",
553 rc);
554 }
555
556 rc = show_scsi_info(argv[1]);
557 if (rc != 0) {
558 printf("ERROR: show_scsi_info failed %d\n", rc);
559 }
560
561 rc = do_scsi_sgp_read_write(argv[1]);
562 if (rc != 0) {
563 printf("ERROR: do_scsi_sgp_read_write failed %d\n", rc);
564 }
565
566 rc = do_scsi_sgm_read_write(argv[1]);
567 if (rc != 0) {
568 printf("ERROR: do_scsi_sgm_read_write failed %d\n", rc);
569 }
570
571 print_msg(TEST_STOP, NULL);
572 } else {
573 printf("\nERROR: Invalid device passed to test\n\n\n");
574 usage();
575
576 }
577
578 return 0;
579 }
580
validate_device(char * device)581 int validate_device(char *device)
582 {
583 int rc = 0;
584 int i, found = FALSE;
585 char device_string[25];
586
587 for (i = 0; i < MAX_DEVICES && !found; i++) {
588 sprintf(device_string, "/dev/sg%d", i);
589 //printf("checking %s \n", device_string);
590 if (strcmp(device, device_string) == 0) {
591 found = TRUE;
592 }
593 }
594
595 return rc;
596 }
597
usage()598 void usage()
599 {
600 printf("Usage: 'sg_scan [-a] [-n] [-w] [-i] [-x]'\n");
601 printf(" where: -a do alpha scan (ie sga, sgb, sgc)\n");
602 printf(" -n do numeric scan (ie sg0, sg1...) [default]\n");
603 printf(" -w force open with read/write flag\n");
604 printf(" -i do SCSI INQUIRY, output results\n");
605 printf(" -x extra information output about queuing\n\n\n");
606 }
607
make_dev_name(char * fname,const char * leadin,int k,int do_numeric)608 void make_dev_name(char *fname, const char *leadin, int k, int do_numeric)
609 {
610 char buff[64];
611 int big, little;
612
613 strcpy(fname, leadin ? leadin : "/dev/sg");
614 if (do_numeric) {
615 sprintf(buff, "%d", k);
616 strcat(fname, buff);
617 } else {
618 if (k < 26) {
619 buff[0] = 'a' + (char)k;
620 buff[1] = '\0';
621 strcat(fname, buff);
622 } else if (k <= 255) { /* assumes sequence goes x,y,z,aa,ab,ac etc */
623 big = k / 26;
624 little = k - (26 * big);
625 big = big - 1;
626
627 buff[0] = 'a' + (char)big;
628 buff[1] = 'a' + (char)little;
629 buff[2] = '\0';
630 strcat(fname, buff);
631 } else
632 strcat(fname, "xxxx");
633 }
634 }
635
run_sg_scan_tests()636 int run_sg_scan_tests()
637 {
638 int sg_fd, res, k, f;
639 unsigned char inqBuff[OFF + INQ_REPLY_LEN];
640 int inqInLen = OFF + sizeof(inqCmdBlk);
641 int inqOutLen = OFF + INQ_REPLY_LEN;
642 unsigned char *buffp = inqBuff + OFF;
643 struct sg_header *isghp = (struct sg_header *)inqBuff;
644 int do_numeric = NUMERIC_SCAN_DEF;
645 int do_inquiry = 0;
646 int do_extra = 1;
647 int writeable = 0;
648 int num_errors = 0;
649 int num_silent = 0;
650 int eacces_err = 0;
651 char fname[64];
652 My_scsi_idlun my_idlun;
653 int host_no;
654 int flags;
655 int emul;
656
657 print_msg(TEST_BREAK, __FUNCTION__);
658
659 flags = writeable ? O_RDWR : OPEN_FLAG;
660
661 do_numeric = 1;
662 writeable = O_RDONLY;
663 do_inquiry = 1;
664 do_extra = 1;
665
666 for (k = 0, res = 0; (k < 1000) && (num_errors < MAX_ERRORS);
667 ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) {
668 if (res < 0) {
669 snprintf(ebuff, EBUFF_SZ, ME "Error closing %s ",
670 fname);
671 perror(ME "close error");
672 return 1;
673 }
674 make_dev_name(fname, NULL, k, do_numeric);
675
676 sg_fd = open(fname, flags | O_NONBLOCK);
677 if (sg_fd < 0) {
678 if (EBUSY == errno) {
679 printf
680 ("%s: device busy (O_EXCL lock), skipping\n",
681 fname);
682 continue;
683 } else if ((ENODEV == errno) || (ENOENT == errno) ||
684 (ENXIO == errno)) {
685 ++num_errors;
686 ++num_silent;
687 continue;
688 } else {
689 if (EACCES == errno)
690 eacces_err = 1;
691 snprintf(ebuff, EBUFF_SZ,
692 ME "Error opening %s ", fname);
693 perror(ebuff);
694 ++num_errors;
695 continue;
696 }
697 }
698 res = ioctl(sg_fd, SCSI_IOCTL_GET_IDLUN, &my_idlun);
699 if (res < 0) {
700 snprintf(ebuff, EBUFF_SZ,
701 ME "device %s failed on scsi ioctl, skip",
702 fname);
703 perror(ebuff);
704 ++num_errors;
705 continue;
706 }
707 res = ioctl(sg_fd, SCSI_IOCTL_GET_BUS_NUMBER, &host_no);
708 if (res < 0) {
709 snprintf(ebuff, EBUFF_SZ, ME "device %s failed on scsi "
710 "ioctl(2), skip", fname);
711 perror(ebuff);
712 ++num_errors;
713 continue;
714 }
715 #ifdef SG_EMULATED_HOST
716 res = ioctl(sg_fd, SG_EMULATED_HOST, &emul);
717 if (res < 0) {
718 snprintf(ebuff, EBUFF_SZ,
719 ME "device %s failed on sg ioctl(3), skip",
720 fname);
721 perror(ebuff);
722 ++num_errors;
723 continue;
724 }
725 #else
726 emul = 0;
727 #endif
728 printf("%s: scsi%d channel=%d id=%d lun=%d", fname, host_no,
729 (my_idlun.dev_id >> 16) & 0xff, my_idlun.dev_id & 0xff,
730 (my_idlun.dev_id >> 8) & 0xff);
731 if (emul)
732 printf(" [em]");
733 #if 0
734 printf(", huid=%d", my_idlun.host_unique_id);
735 #endif
736 #ifdef SG_GET_RESERVED_SIZE
737 {
738 My_sg_scsi_id m_id; /* compatible with sg_scsi_id_t in sg.h */
739
740 res = ioctl(sg_fd, SG_GET_SCSI_ID, &m_id);
741 if (res < 0) {
742 snprintf(ebuff, EBUFF_SZ,
743 ME "device %s ioctls(4), skip", fname);
744 perror(ebuff);
745 ++num_errors;
746 continue;
747 }
748 printf(" type=%d", m_id.scsi_type);
749 if (do_extra)
750 printf(" cmd_per_lun=%hd queue_depth=%hd\n",
751 m_id.h_cmd_per_lun, m_id.d_queue_depth);
752 else
753 printf("\n");
754 }
755 #else
756 printf("\n");
757 #endif
758 if (!do_inquiry)
759 continue;
760
761 #ifdef SG_IO
762 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &f) >= 0) && (f >= 30000)) {
763 res = sg3_inq(sg_fd, inqBuff, do_extra);
764 continue;
765 }
766 #endif
767 memset(isghp, 0, sizeof(struct sg_header));
768 isghp->reply_len = inqOutLen;
769 memcpy(inqBuff + OFF, inqCmdBlk, INQUIRY_CMDLEN);
770
771 if (O_RDWR == (flags & O_ACCMODE)) { /* turn on blocking */
772 f = fcntl(sg_fd, F_GETFL);
773 fcntl(sg_fd, F_SETFL, f & (~O_NONBLOCK));
774 } else {
775 close(sg_fd);
776 sg_fd = open(fname, O_RDWR);
777 }
778
779 res = write(sg_fd, inqBuff, inqInLen);
780 if (res < 0) {
781 snprintf(ebuff, EBUFF_SZ, ME "device %s writing, skip",
782 fname);
783 perror(ebuff);
784 ++num_errors;
785 continue;
786 }
787 res = read(sg_fd, inqBuff, inqOutLen);
788 if (res < 0) {
789 snprintf(ebuff, EBUFF_SZ, ME "device %s reading, skip",
790 fname);
791 perror(ebuff);
792 ++num_errors;
793 continue;
794 }
795 #ifdef SG_GET_RESERVED_SIZE
796 if (!sg_chk_n_print("Error from Inquiry", isghp->target_status,
797 isghp->host_status, isghp->driver_status,
798 isghp->sense_buffer, SG_MAX_SENSE))
799 continue;
800 #else
801 if ((isghp->result != 0) || (0 != isghp->sense_buffer[0])) {
802 printf("Error from Inquiry: result=%d\n",
803 isghp->result);
804 if (0 != isghp->sense_buffer[0])
805 sg_print_sense("Error from Inquiry",
806 isghp->sense_buffer,
807 SG_MAX_SENSE);
808 continue;
809 }
810 #endif
811 f = (int)*(buffp + 7);
812 printf(" %.8s %.16s %.4s ", buffp + 8, buffp + 16,
813 buffp + 32);
814 printf("[wide=%d sync=%d cmdq=%d sftre=%d pq=0x%x]\n",
815 ! !(f & 0x20), ! !(f & 0x10), ! !(f & 2), ! !(f & 1),
816 (*buffp & 0xe0) >> 5);
817 }
818 if ((num_errors >= MAX_ERRORS) && (num_silent < num_errors)) {
819 printf("Stopping because there are too many error\n");
820 if (eacces_err)
821 printf(" root access may be required\n");
822 }
823 return 0;
824 }
825
826 #ifdef SG_IO
sg3_inq(int sg_fd,unsigned char * inqBuff,int do_extra)827 int sg3_inq(int sg_fd, unsigned char *inqBuff, int do_extra)
828 {
829 sg_io_hdr_t io_hdr;
830 unsigned char sense_buffer[32];
831 int ok;
832
833 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
834 io_hdr.interface_id = 'S';
835 io_hdr.cmd_len = sizeof(inqCmdBlk);
836 io_hdr.mx_sb_len = sizeof(sense_buffer);
837 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
838 io_hdr.dxfer_len = INQ_REPLY_LEN;
839 io_hdr.dxferp = inqBuff;
840 io_hdr.cmdp = inqCmdBlk;
841 io_hdr.sbp = sense_buffer;
842 io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
843
844 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
845 perror(ME "Inquiry SG_IO ioctl error");
846 return 1;
847 }
848
849 /* now for the error processing */
850 ok = 0;
851 switch (sg_err_category3(&io_hdr)) {
852 case SG_ERR_CAT_CLEAN:
853 case SG_ERR_CAT_RECOVERED:
854 ok = 1;
855 break;
856 default: /* won't bother decoding other categories */
857 sg_chk_n_print3("INQUIRY command error", &io_hdr);
858 break;
859 }
860
861 if (ok) { /* output result if it is available */
862 char *p = (char *)inqBuff;
863 int f = (int)*(p + 7);
864 printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32);
865 printf("[wide=%d sync=%d cmdq=%d sftre=%d pq=0x%x] ",
866 ! !(f & 0x20), ! !(f & 0x10), ! !(f & 2), ! !(f & 1),
867 (*p & 0xe0) >> 5);
868 if (do_extra)
869 printf("dur=%ums\n", io_hdr.duration);
870 else
871 printf("\n");
872 }
873 return 0;
874 }
875 #endif
876
do_logs(int sg_fd,int ppc,int sp,int pc,int pg_code,int paramp,void * resp,int mx_resp_len,int noisy)877 static int do_logs(int sg_fd, int ppc, int sp, int pc, int pg_code,
878 int paramp, void *resp, int mx_resp_len, int noisy)
879 {
880 int res;
881 unsigned char logsCmdBlk[LOG_SENSE_CMDLEN] =
882 { LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
883 unsigned char sense_b[SENSE_BUFF_LEN];
884 sg_io_hdr_t io_hdr;
885
886 logsCmdBlk[1] = (unsigned char)((ppc ? 2 : 0) | (sp ? 1 : 0));
887 logsCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
888 logsCmdBlk[5] = (unsigned char)((paramp >> 8) & 0xff);
889 logsCmdBlk[6] = (unsigned char)(paramp & 0xff);
890 if (mx_resp_len > 0xffff) {
891 printf(ME "mx_resp_len too big\n");
892 return -1;
893 }
894 logsCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
895 logsCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff);
896
897 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
898 io_hdr.interface_id = 'S';
899 io_hdr.cmd_len = sizeof(logsCmdBlk);
900 io_hdr.mx_sb_len = sizeof(sense_b);
901 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
902 io_hdr.dxfer_len = mx_resp_len;
903 io_hdr.dxferp = resp;
904 io_hdr.cmdp = logsCmdBlk;
905 io_hdr.sbp = sense_b;
906 io_hdr.timeout = DEF_TIMEOUT;
907
908 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
909 perror("SG_IO (log sense) error");
910 return -1;
911 }
912 #if 0
913 printf("SG_IO ioctl: status=%d, info=%d, sb_len_wr=%d\n",
914 io_hdr.status, io_hdr.info, io_hdr.sb_len_wr);
915 #endif
916 res = sg_err_category3(&io_hdr);
917 switch (res) {
918 case SG_ERR_CAT_CLEAN:
919 case SG_ERR_CAT_RECOVERED:
920 return 0;
921 default:
922 if (noisy) {
923 char ebuff[EBUFF_SZ];
924 snprintf(ebuff, EBUFF_SZ, ME "ppc=%d, sp=%d, "
925 "pc=%d, page_code=%x, paramp=%x\n ", ppc,
926 sp, pc, pg_code, paramp);
927 sg_chk_n_print3(ebuff, &io_hdr);
928 }
929 return -1;
930 }
931 }
932
dStrHex(const char * str,int len,int no_ascii)933 static void dStrHex(const char *str, int len, int no_ascii)
934 {
935 const char *p = str;
936 unsigned char c;
937 char buff[82];
938 int a = 0;
939 const int bpstart = 5;
940 const int cpstart = 60;
941 int cpos = cpstart;
942 int bpos = bpstart;
943 int i, k;
944
945 if (len <= 0)
946 return;
947 memset(buff, ' ', 80);
948 buff[80] = '\0';
949 k = sprintf(buff + 1, "%.2x", a);
950 buff[k + 1] = ' ';
951 if (bpos >= ((bpstart + (9 * 3))))
952 bpos++;
953
954 for (i = 0; i < len; i++) {
955 c = *p++;
956 bpos += 3;
957 if (bpos == (bpstart + (9 * 3)))
958 bpos++;
959 sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c);
960 buff[bpos + 2] = ' ';
961 if (no_ascii)
962 buff[cpos++] = ' ';
963 else {
964 if ((c < ' ') || (c >= 0x7f))
965 c = '.';
966 buff[cpos++] = c;
967 }
968 if (cpos > (cpstart + 15)) {
969 printf("%s\n", buff);
970 bpos = bpstart;
971 cpos = cpstart;
972 a += 16;
973 memset(buff, ' ', 80);
974 k = sprintf(buff + 1, "%.2x", a);
975 buff[k + 1] = ' ';
976 }
977 }
978 if (cpos > cpstart) {
979 printf("%s\n", buff);
980 }
981 }
982
show_page_name(int page_no)983 static void show_page_name(int page_no)
984 {
985 switch (page_no) {
986 case 0x0:
987 printf(" 0x00 Supported log pages\n");
988 break;
989 case 0x1:
990 printf(" 0x01 Buffer over-run/under-run\n");
991 break;
992 case 0x2:
993 printf(" 0x02 Error counters (write)\n");
994 break;
995 case 0x3:
996 printf(" 0x03 Error counters (read)\n");
997 break;
998 case 0x4:
999 printf(" 0x04 Error counters (read reverse)\n");
1000 break;
1001 case 0x5:
1002 printf(" 0x05 Error counters (verify)\n");
1003 break;
1004 case 0x6:
1005 printf(" 0x06 Non-medium errors\n");
1006 break;
1007 case 0x7:
1008 printf(" 0x07 Last n error events\n");
1009 break;
1010 case 0x8:
1011 printf(" 0x08 Format status (sbc2)\n");
1012 break;
1013 case 0xb:
1014 printf(" 0x0b Last n deferred errors of "
1015 "asynchronous events\n");
1016 break;
1017 case 0xc:
1018 printf(" 0x0c Sequential Access (ssc-2)\n");
1019 break;
1020 case 0xd:
1021 printf(" 0x0d Temperature\n");
1022 break;
1023 case 0xe:
1024 printf(" 0x0e Start-stop cycle counter\n");
1025 break;
1026 case 0xf:
1027 printf(" 0x0f Application client\n");
1028 break;
1029 case 0x10:
1030 printf(" 0x10 Self-test results\n");
1031 break;
1032 case 0x18:
1033 printf(" 0x18 Protocol specific port\n");
1034 break;
1035 case 0x2e:
1036 printf(" 0x2e Tape alerts (ssc-2)\n");
1037 break;
1038 case 0x2f:
1039 printf(" 0x2f Informational exceptions (SMART)\n");
1040 break;
1041 default:
1042 printf(" 0x%.2x\n", page_no);
1043 break;
1044 }
1045 }
1046
show_buffer_under_overrun_page(unsigned char * resp,int len)1047 static void show_buffer_under_overrun_page(unsigned char *resp, int len)
1048 {
1049 int k, j, num, pl, count_basis, cause;
1050 unsigned char *ucp;
1051 unsigned char *xp;
1052 unsigned long long ull;
1053
1054 printf("Buffer over-run/under-run page\n");
1055 num = len - 4;
1056 ucp = &resp[0] + 4;
1057 while (num > 3) {
1058 pl = ucp[3] + 4;
1059 count_basis = (ucp[1] >> 5) & 0x7;
1060 printf(" Count basis: ");
1061 switch (count_basis) {
1062 case 0:
1063 printf("undefined");
1064 break;
1065 case 1:
1066 printf("per command");
1067 break;
1068 case 2:
1069 printf("per failed reconnect");
1070 break;
1071 case 3:
1072 printf("per unit of time");
1073 break;
1074 default:
1075 printf("reserved [0x%x]", count_basis);
1076 break;
1077 }
1078 cause = (ucp[1] >> 1) & 0xf;
1079 printf(", Cause: ");
1080 switch (cause) {
1081 case 0:
1082 printf("bus busy");
1083 break;
1084 case 1:
1085 printf("transfer rate too slow");
1086 break;
1087 default:
1088 printf("reserved [0x%x]", cause);
1089 break;
1090 }
1091 printf(", Type: ");
1092 if (ucp[1] & 1)
1093 printf("over-run");
1094 else
1095 printf("under-run");
1096 printf(", count");
1097 k = pl - 4;
1098 xp = ucp + 4;
1099 if (k > sizeof(ull)) {
1100 xp += (k - sizeof(ull));
1101 k = sizeof(ull);
1102 }
1103 ull = 0;
1104 for (j = 0; j < k; ++j) {
1105 if (j > 0)
1106 ull <<= 8;
1107 ull |= xp[j];
1108 }
1109 printf(" = %llu\n", ull);
1110 num -= pl;
1111 ucp += pl;
1112 }
1113 }
1114
show_error_counter_page(unsigned char * resp,int len)1115 static void show_error_counter_page(unsigned char *resp, int len)
1116 {
1117 int k, j, num, pl, pc;
1118 unsigned char *ucp;
1119 unsigned char *xp;
1120 unsigned long long ull;
1121
1122 switch (resp[0]) {
1123 case 2:
1124 printf("Write error counter page\n");
1125 break;
1126 case 3:
1127 printf("Read error counter page\n");
1128 break;
1129 case 4:
1130 printf("Read Reverse error counter page\n");
1131 break;
1132 case 5:
1133 printf("Verify error counter page\n");
1134 break;
1135 default:
1136 printf("expecting error counter page, got page=0x%x\n",
1137 resp[0]);
1138 return;
1139 }
1140 num = len - 4;
1141 ucp = &resp[0] + 4;
1142 while (num > 3) {
1143 pc = (ucp[0] << 8) | ucp[1];
1144 pl = ucp[3] + 4;
1145 switch (pc) {
1146 case 0:
1147 printf(" Errors corrected without substantion delay");
1148 break;
1149 case 1:
1150 printf(" Errors corrected with possible delays");
1151 break;
1152 case 2:
1153 printf(" Total operations");
1154 break;
1155 case 3:
1156 printf(" Total errors corrected");
1157 break;
1158 case 4:
1159 printf(" Total times correction algorithm processed");
1160 break;
1161 case 5:
1162 printf(" Total bytes processed");
1163 break;
1164 case 6:
1165 printf(" Total uncorrected errors");
1166 break;
1167 default:
1168 printf(" Reserved or vendor specific [0x%x]", pc);
1169 break;
1170 }
1171 k = pl - 4;
1172 xp = ucp + 4;
1173 if (k > sizeof(ull)) {
1174 xp += (k - sizeof(ull));
1175 k = sizeof(ull);
1176 }
1177 ull = 0;
1178 for (j = 0; j < k; ++j) {
1179 if (j > 0)
1180 ull <<= 8;
1181 ull |= xp[j];
1182 }
1183 printf(" = %llu\n", ull);
1184 num -= pl;
1185 ucp += pl;
1186 }
1187 }
1188
show_non_medium_error_page(unsigned char * resp,int len)1189 static void show_non_medium_error_page(unsigned char *resp, int len)
1190 {
1191 int k, j, num, pl, pc;
1192 unsigned char *ucp;
1193 unsigned char *xp;
1194 unsigned long long ull;
1195
1196 printf("Non-medium error page\n");
1197 num = len - 4;
1198 ucp = &resp[0] + 4;
1199 while (num > 3) {
1200 pc = (ucp[0] << 8) | ucp[1];
1201 pl = ucp[3] + 4;
1202 switch (pc) {
1203 case 0:
1204 printf(" Non-medium error count");
1205 break;
1206 default:
1207 if (pc <= 0x7fff)
1208 printf(" Reserved [0x%x]", pc);
1209 else
1210 printf(" Vendor specific [0x%x]", pc);
1211 break;
1212 }
1213 k = pl - 4;
1214 xp = ucp + 4;
1215 if (k > sizeof(ull)) {
1216 xp += (k - sizeof(ull));
1217 k = sizeof(ull);
1218 }
1219 ull = 0;
1220 for (j = 0; j < k; ++j) {
1221 if (j > 0)
1222 ull <<= 8;
1223 ull |= xp[j];
1224 }
1225 printf(" = %llu\n", ull);
1226 num -= pl;
1227 ucp += pl;
1228 }
1229 }
1230
1231 const char *self_test_code[] = {
1232 "default", "background short", "background extended", "reserved",
1233 "aborted background", "foreground short", "foreground extended",
1234 "reserved"
1235 };
1236
1237 const char *self_test_result[] = {
1238 "completed without error",
1239 "aborted by SEND DIAGNOSTIC",
1240 "aborted other than by SEND DIAGNOSTIC",
1241 "unknown error, unable to complete",
1242 "self test completed with failure in test segment (which one unkown)",
1243 "first segment in self test failed",
1244 "second segment in self test failed",
1245 "another segment in self test failed",
1246 "reserved", "reserved", "reserved", "reserved", "reserved", "reserved",
1247 "reserved",
1248 "self test in progress"
1249 };
1250
show_self_test_page(unsigned char * resp,int len)1251 static void show_self_test_page(unsigned char *resp, int len)
1252 {
1253 int k, num, n, res;
1254 unsigned char *ucp;
1255 unsigned long long ull;
1256
1257 num = len - 4;
1258 if (num < 0x190) {
1259 printf("badly formed self-test results page\n");
1260 return;
1261 }
1262 printf("Self-test results page\n");
1263 for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20) {
1264 n = (ucp[6] << 8) | ucp[7];
1265 if ((0 == n) && (0 == ucp[4]))
1266 break;
1267 printf(" Parameter code=%d, accumulated power-on hours=%d\n",
1268 (ucp[0] << 8) | ucp[1], n);
1269 printf(" self test code: %s [%d]\n",
1270 self_test_code[(ucp[4] >> 5) & 0x7],
1271 (ucp[4] >> 5) & 0x7);
1272 res = ucp[4] & 0xf;
1273 printf(" self test result: %s [%d]\n",
1274 self_test_result[res], res);
1275 if (ucp[5])
1276 printf(" self-test number=%d\n", (int)ucp[5]);
1277 ull = ucp[8];
1278 ull <<= 8;
1279 ull |= ucp[9];
1280 ull <<= 8;
1281 ull |= ucp[10];
1282 ull <<= 8;
1283 ull |= ucp[11];
1284 ull <<= 8;
1285 ull |= ucp[12];
1286 ull <<= 8;
1287 ull |= ucp[13];
1288 ull <<= 8;
1289 ull |= ucp[14];
1290 ull <<= 8;
1291 ull |= ucp[14];
1292 ull <<= 8;
1293 ull |= ucp[15];
1294 if ((0xffffffffffffffffULL != ull) && (res > 0) && (res < 0xf))
1295 printf(" address of first error=0x%llx\n", ull);
1296 if (ucp[16] & 0xf)
1297 printf(" sense key=0x%x, asc=0x%x, asq=0x%x\n",
1298 ucp[16] & 0xf, ucp[17], ucp[18]);
1299 }
1300 }
1301
show_Temperature_page(unsigned char * resp,int len,int hdr)1302 static void show_Temperature_page(unsigned char *resp, int len, int hdr)
1303 {
1304 int k, num, extra, pc;
1305 unsigned char *ucp;
1306
1307 num = len - 4;
1308 ucp = &resp[0] + 4;
1309 if (num < 4) {
1310 printf("badly formed Temperature log page\n");
1311 return;
1312 }
1313 if (hdr)
1314 printf("Temperature log page\n");
1315 for (k = num; k > 0; k -= extra, ucp += extra) {
1316 if (k < 3) {
1317 printf("short Temperature log page\n");
1318 return;
1319 }
1320 extra = ucp[3] + 4;
1321 pc = ((ucp[0] << 8) & 0xff) + ucp[1];
1322 if (0 == pc) {
1323 if (extra > 5) {
1324 if (ucp[5] < 0xff)
1325 printf(" Current temperature= %d C\n",
1326 ucp[5]);
1327 else
1328 printf
1329 (" Current temperature=<not available>\n");
1330 }
1331 } else if (1 == pc) {
1332 if (extra > 5) {
1333 if (ucp[5] < 0xff)
1334 printf
1335 (" Reference temperature= %d C\n",
1336 ucp[5]);
1337 else
1338 printf
1339 (" Reference temperature=<not available>\n");
1340 }
1341
1342 } else {
1343 printf(" parameter code=0x%x, contents in hex:\n", pc);
1344 dStrHex((const char *)ucp, extra, 1);
1345 }
1346 }
1347 }
1348
show_IE_page(unsigned char * resp,int len,int full)1349 static void show_IE_page(unsigned char *resp, int len, int full)
1350 {
1351 int k, num, extra, pc;
1352 unsigned char *ucp;
1353
1354 num = len - 4;
1355 ucp = &resp[0] + 4;
1356 if (num < 4) {
1357 printf("badly formed Informational Exceptions log page\n");
1358 return;
1359 }
1360 if (full)
1361 printf("Informational Exceptions log page\n");
1362 for (k = num; k > 0; k -= extra, ucp += extra) {
1363 if (k < 3) {
1364 printf("short Informational Exceptions log page\n");
1365 return;
1366 }
1367 extra = ucp[3] + 4;
1368 pc = ((ucp[0] << 8) & 0xff) + ucp[1];
1369 if (0 == pc) {
1370 if (extra > 5) {
1371 if (full)
1372 printf(" IE asc=0x%x, ascq=0x%x",
1373 ucp[4], ucp[5]);
1374 if (extra > 6) {
1375 if (full)
1376 printf(",");
1377 if (ucp[6] < 0xff)
1378 printf
1379 (" Current temperature=%d C",
1380 ucp[6]);
1381 else
1382 printf
1383 (" Current temperature=<not available>");
1384 }
1385 printf("\n");
1386 }
1387 } else if (full) {
1388 printf(" parameter code=0x%x, contents in hex:\n", pc);
1389 dStrHex((const char *)ucp, extra, 1);
1390 }
1391 }
1392 }
1393
show_ascii_page(unsigned char * resp,int len)1394 static void show_ascii_page(unsigned char *resp, int len)
1395 {
1396 int k, n, num;
1397
1398 if (len < 0) {
1399 printf("response has bad length\n");
1400 return;
1401 }
1402 num = len - 4;
1403 switch (resp[0]) {
1404 case 0:
1405 printf("Supported pages:\n");
1406 for (k = 0; k < num; ++k)
1407 show_page_name((int)resp[4 + k]);
1408 break;
1409 case 0x1:
1410 show_buffer_under_overrun_page(resp, len);
1411 break;
1412 case 0x2:
1413 case 0x3:
1414 case 0x4:
1415 case 0x5:
1416 show_error_counter_page(resp, len);
1417 break;
1418 case 0x6:
1419 show_non_medium_error_page(resp, len);
1420 break;
1421 case 0xd:
1422 show_Temperature_page(resp, len, 1);
1423 break;
1424 case 0xe:
1425 if (len < 40) {
1426 printf("badly formed start-stop cycle counter page\n");
1427 break;
1428 }
1429 printf("Start-stop cycle counter page\n");
1430 printf(" Date of manufacture, year: %.4s, week: %.2s\n",
1431 &resp[8], &resp[12]);
1432 printf(" Accounting date, year: %.4s, week: %.2s\n",
1433 &resp[18], &resp[22]);
1434 n = (resp[28] << 24) | (resp[29] << 16) | (resp[30] << 8) |
1435 resp[31];
1436 printf(" Specified cycle count over device lifetime=%d\n", n);
1437 n = (resp[36] << 24) | (resp[37] << 16) | (resp[38] << 8) |
1438 resp[39];
1439 printf(" Accumulated start-stop cycles=%d\n", n);
1440 break;
1441 case 0x10:
1442 show_self_test_page(resp, len);
1443 break;
1444 case 0x2f:
1445 show_IE_page(resp, len, 1);
1446 break;
1447 default:
1448 printf("No ascii information for page=0x%x, here is hex:\n",
1449 resp[0]);
1450 dStrHex((const char *)resp, len, 1);
1451 break;
1452 }
1453 }
1454
fetchTemperature(int sg_fd,int do_hex,unsigned char * resp,int max_len)1455 static int fetchTemperature(int sg_fd, int do_hex, unsigned char *resp,
1456 int max_len)
1457 {
1458 int res = 0;
1459
1460 if (0 == do_logs(sg_fd, 0, 0, 1, 0xd, 0, resp, max_len, 0))
1461 show_Temperature_page(resp, (resp[2] << 8) + resp[3] + 4, 0);
1462 else if (0 == do_logs(sg_fd, 0, 0, 1, 0x2f, 0, resp, max_len, 0))
1463 show_IE_page(resp, (resp[2] << 8) + resp[3] + 4, 0);
1464 else {
1465 printf
1466 ("Unable to find temperature in either log page (temperature "
1467 "or IE)\n");
1468 res = 1;
1469 }
1470 close(sg_fd);
1471 return res;
1472 }
1473
show_scsi_logs(char * device)1474 int show_scsi_logs(char *device)
1475 {
1476 int sg_fd, k, pg_len;
1477 char *file_name = 0;
1478 unsigned char rsp_buff[MX_ALLOC_LEN];
1479 int pg_code = 0;
1480 int pc = 1; /* N.B. some disks only give data for current cumulative */
1481 int paramp = 0;
1482 int do_list = 0;
1483 int do_ppc = 0;
1484 int do_sp = 0;
1485 int do_hex = 0;
1486 int do_all = 1;
1487 int do_temp = 0;
1488 int oflags = O_RDWR | O_NONBLOCK;
1489
1490 file_name = device;
1491 print_msg(TEST_BREAK, __FUNCTION__);
1492
1493 if ((sg_fd = open(file_name, oflags)) < 0) {
1494 snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s",
1495 file_name);
1496 perror(ebuff);
1497 return 1;
1498 }
1499 /* Just to be safe, check we have a new sg device by trying an ioctl */
1500 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
1501 printf(ME "%s doesn't seem to be a version 3 sg device\n",
1502 file_name);
1503 close(sg_fd);
1504 return 1;
1505 }
1506 if (do_list || do_all)
1507 pg_code = PG_CODE_ALL;
1508 pg_len = 0;
1509 if (1 == do_temp)
1510 return fetchTemperature(sg_fd, do_hex, rsp_buff, MX_ALLOC_LEN);
1511
1512 if (0 == do_logs(sg_fd, do_ppc, do_sp, pc, pg_code, paramp,
1513 rsp_buff, MX_ALLOC_LEN, 1)) {
1514 pg_len = (rsp_buff[2] << 8) + rsp_buff[3];
1515 if ((pg_len + 4) > MX_ALLOC_LEN) {
1516 printf
1517 ("Only fetched %d bytes of response, truncate output\n",
1518 MX_ALLOC_LEN);
1519 pg_len = MX_ALLOC_LEN - 4;
1520 }
1521 if (do_hex) {
1522 printf("Returned log page code=0x%x, page len=0x%x\n",
1523 rsp_buff[0], pg_len);
1524 dStrHex((const char *)rsp_buff, pg_len + 4, 1);
1525 } else
1526 show_ascii_page(rsp_buff, pg_len + 4);
1527 }
1528 if (do_all && (pg_len > 1)) {
1529 int my_len = pg_len - 1;
1530 unsigned char parr[256];
1531
1532 memcpy(parr, rsp_buff + 5, my_len);
1533 for (k = 0; k < my_len; ++k) {
1534 printf("\n");
1535 pg_code = parr[k];
1536 if (0 ==
1537 do_logs(sg_fd, do_ppc, do_sp, pc, pg_code, paramp,
1538 rsp_buff, MX_ALLOC_LEN, 1)) {
1539 pg_len = (rsp_buff[2] << 8) + rsp_buff[3];
1540 if ((pg_len + 4) > MX_ALLOC_LEN) {
1541 printf
1542 ("Only fetched %d bytes of response, truncate "
1543 "output\n", MX_ALLOC_LEN);
1544 pg_len = MX_ALLOC_LEN - 4;
1545 }
1546 if (do_hex) {
1547 printf
1548 ("Returned log page code=0x%x, page len=0x%x\n",
1549 rsp_buff[0], pg_len);
1550 dStrHex((const char *)rsp_buff,
1551 pg_len + 4, 1);
1552 } else
1553 show_ascii_page(rsp_buff, pg_len + 4);
1554 }
1555 }
1556 }
1557 close(sg_fd);
1558 return 0;
1559 }
1560
do_inquiry(int sg_fd,void * resp,int mx_resp_len)1561 static int do_inquiry(int sg_fd, void *resp, int mx_resp_len)
1562 {
1563 int res;
1564 unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
1565 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
1566 unsigned char sense_b[SENSE_BUFF_LEN];
1567 sg_io_hdr_t io_hdr;
1568
1569 inqCmdBlk[4] = (unsigned char)mx_resp_len;
1570 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
1571 io_hdr.interface_id = 'S';
1572 io_hdr.cmd_len = sizeof(inqCmdBlk);
1573 io_hdr.mx_sb_len = sizeof(sense_b);
1574 io_hdr.dxfer_direction = SG_DXFER_TO_FROM_DEV;
1575 io_hdr.dxfer_len = mx_resp_len;
1576 io_hdr.dxferp = resp;
1577 io_hdr.cmdp = inqCmdBlk;
1578 io_hdr.timeout = DEF_TIMEOUT;
1579
1580 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
1581 perror("SG_IO (inquiry) error");
1582 return -1;
1583 }
1584 res = sg_err_category3(&io_hdr);
1585 switch (res) {
1586 case SG_ERR_CAT_CLEAN:
1587 case SG_ERR_CAT_RECOVERED:
1588 return 0;
1589 default:
1590 sg_chk_n_print3("Failed INQUIRY", &io_hdr);
1591 return -1;
1592 }
1593 }
1594
leaf_dir(const char * lf,unsigned int * larr)1595 void leaf_dir(const char *lf, unsigned int *larr)
1596 {
1597 char name[NAME_LEN_MAX * 2];
1598 int res;
1599
1600 if (do_quiet) {
1601 printf("%u\t%u\t%u\t%u\n", larr[0], larr[1], larr[2], larr[3]);
1602 return;
1603 }
1604 printf("%u\t%u\t%u\t%u\t%s\n", larr[0], larr[1], larr[2], larr[3], lf);
1605 if (do_leaf) {
1606 struct dirent *de_entry;
1607 struct dirent *de_result;
1608 DIR *sdir;
1609 int outpos;
1610
1611 if (NULL == (sdir = opendir(lf))) {
1612 fprintf(stderr, "leaf_dir: opendir of %s: failed\n",
1613 lf);
1614 return;
1615 }
1616 de_entry = malloc(sizeof(struct dirent) + NAME_LEN_MAX);
1617 if (NULL == de_entry)
1618 return;
1619 res = 0;
1620 printf("\t");
1621 outpos = 8;
1622 while (1) {
1623 res = readdir_r(sdir, de_entry, &de_result);
1624 if (0 != res) {
1625 fprintf(stderr,
1626 "leaf_dir: readdir_r of %s: %s\n", lf,
1627 strerror(res));
1628 res = -2;
1629 break;
1630 }
1631 if (de_result == NULL)
1632 break;
1633 strncpy(name, de_entry->d_name, NAME_LEN_MAX * 2);
1634 if ((0 == strcmp("..", name))
1635 || (0 == strcmp(".", name)))
1636 continue;
1637 if (do_extra) {
1638 struct stat st;
1639 char devname[NAME_LEN_MAX * 2];
1640
1641 strncpy(devname, lf, NAME_LEN_MAX * 2);
1642 strcat(devname, "/");
1643 strcat(devname, name);
1644 if (stat(devname, &st) < 0)
1645 return;
1646 if (S_ISCHR(st.st_mode)) {
1647 strcat(name, "(c ");
1648 sprintf(name + strlen(name), "%d %d)",
1649 major(st.st_rdev),
1650 minor(st.st_rdev));
1651 } else if (S_ISBLK(st.st_mode)) {
1652 strcat(name, "(b ");
1653 sprintf(name + strlen(name), "%d %d)",
1654 major(st.st_rdev),
1655 minor(st.st_rdev));
1656 }
1657 }
1658 res = strlen(name);
1659 if ((outpos + res + 2) > 80) {
1660 printf("\n\t");
1661 outpos = 8;
1662 }
1663 printf("%s ", name);
1664 outpos += res + 2;
1665 }
1666 printf("\n");
1667 }
1668 if (do_inq) {
1669 int sg_fd;
1670 char buff[64];
1671
1672 memset(buff, 0, sizeof(buff));
1673 strncpy(name, lf, NAME_LEN_MAX * 2);
1674 strcat(name, "/generic");
1675 if ((sg_fd = open(name, O_RDONLY)) < 0) {
1676 if (!checked_sg) {
1677 checked_sg = 1;
1678 if ((sg_fd = open("/dev/sg0", O_RDONLY)) >= 0)
1679 close(sg_fd); /* try and get sg module loaded */
1680 sg_fd = open(name, O_RDONLY);
1681 }
1682 if (sg_fd < 0) {
1683 printf("Unable to open sg device: %s, %s\n",
1684 name, strerror(errno));
1685 return;
1686 }
1687 }
1688 if (0 != do_inquiry(sg_fd, buff, 64))
1689 return;
1690 close(sg_fd);
1691 dStrHex(buff, 64, 0);
1692 }
1693 }
1694
1695 /* Return 0 -> ok, -1 -> opendir() error, -2 -> readdir_r error,
1696 -3 -> malloc error */
hbtl_scan(const char * path,int level,unsigned int * larr)1697 int hbtl_scan(const char *path, int level, unsigned int *larr)
1698 {
1699 struct dirent *de_entry;
1700 struct dirent *de_result;
1701 char new_path[NAME_LEN_MAX * 2];
1702 DIR *sdir;
1703 int res;
1704 size_t level_slen;
1705
1706 level_slen = strlen(level_arr[level]);
1707 if (NULL == (sdir = opendir(path))) {
1708 fprintf(stderr, "hbtl_scan: opendir of %s: failed\n", path);
1709 return -1;
1710 }
1711 de_entry = malloc(sizeof(struct dirent) + NAME_LEN_MAX);
1712 if (NULL == de_entry)
1713 return -3;
1714 res = 0;
1715 while (1) {
1716 res = readdir_r(sdir, de_entry, &de_result);
1717 if (0 != res) {
1718 fprintf(stderr, "hbtl_scan: readdir_r of %s: %s\n",
1719 path, strerror(res));
1720 res = -2;
1721 break;
1722 }
1723 if (de_result == NULL)
1724 break;
1725 if (0 ==
1726 strncmp(level_arr[level], de_entry->d_name, level_slen)) {
1727 if (1 !=
1728 sscanf(de_entry->d_name + level_slen, "%u",
1729 larr + level))
1730 larr[level] = UINT_MAX;
1731 strncpy(new_path, path, NAME_LEN_MAX * 2);
1732 strcat(new_path, "/");
1733 strcat(new_path, de_entry->d_name);
1734 if ((level + 1) < LEVELS) {
1735 res = hbtl_scan(new_path, level + 1, larr);
1736 if (res < 0)
1737 break;
1738 } else
1739 leaf_dir(new_path, larr);
1740 }
1741 }
1742 free(de_entry);
1743 closedir(sdir);
1744 return res;
1745 }
1746
show_devfs_devices()1747 int show_devfs_devices()
1748 {
1749 int res;
1750 char ds_root[D_ROOT_SZ];
1751 char di_root[D_ROOT_SZ];
1752 unsigned int larr[LEVELS];
1753 struct stat st;
1754
1755 print_msg(TEST_BREAK, __FUNCTION__);
1756 strncpy(ds_root, "/dev", D_ROOT_SZ);
1757
1758 strncpy(di_root, ds_root, D_ROOT_SZ);
1759
1760 strcat(di_root, "/.devfsd");
1761
1762 if (stat(di_root, &st) < 0) {
1763 printf("Didn't find %s so perhaps devfs is not present,"
1764 " attempting to continue ...\n", di_root);
1765 }
1766
1767 strncpy(di_root, ds_root, D_ROOT_SZ);
1768 strcat(ds_root, "/scsi");
1769 strcat(di_root, "/ide");
1770
1771 if (!do_ide)
1772 printf("SCSI scan:\n");
1773
1774 res = hbtl_scan(ds_root, 0, larr);
1775
1776 if (res < 0)
1777 printf("main: scsi hbtl_scan res=%d\n", res);
1778
1779 do_ide = TRUE;
1780 do_inq = 0; /* won't try SCSI INQUIRY on IDE devices */
1781
1782 if (do_ide) {
1783 printf("\nIDE scan:\n");
1784 res = hbtl_scan(di_root, 0, larr);
1785
1786 if (res < 0)
1787 printf("main: ide hbtl_scan res=%d\n", res);
1788 }
1789 return 0;
1790 }
1791
install_handler(int sig_num,void (* sig_handler)(int sig))1792 static void install_handler(int sig_num, void (*sig_handler) (int sig))
1793 {
1794 struct sigaction sigact;
1795 sigaction(sig_num, NULL, &sigact);
1796 if (sigact.sa_handler != SIG_IGN) {
1797 sigact.sa_handler = sig_handler;
1798 sigemptyset(&sigact.sa_mask);
1799 sigact.sa_flags = 0;
1800 sigaction(sig_num, &sigact, NULL);
1801 }
1802 }
1803
print_stats()1804 void print_stats()
1805 {
1806 if (0 != dd_count)
1807 fprintf(stderr, " remaining block count=%d\n", dd_count);
1808 fprintf(stderr, "%d+%d records in\n", in_full - in_partial, in_partial);
1809 fprintf(stderr, "%d+%d records out\n", out_full - out_partial,
1810 out_partial);
1811 }
1812
interrupt_handler(int sig)1813 static void interrupt_handler(int sig)
1814 {
1815 struct sigaction sigact;
1816
1817 sigact.sa_handler = SIG_DFL;
1818 sigemptyset(&sigact.sa_mask);
1819 sigact.sa_flags = 0;
1820 sigaction(sig, &sigact, NULL);
1821 fprintf(stderr, "Interrupted by signal,");
1822 print_stats();
1823 kill(getpid(), sig);
1824 }
1825
siginfo_handler(int sig)1826 static void siginfo_handler(int sig)
1827 {
1828 fprintf(stderr, "Progress report, continuing ...\n");
1829 print_stats();
1830 }
1831
dd_filetype(const char * filename)1832 int dd_filetype(const char *filename)
1833 {
1834 struct stat st;
1835 size_t len = strlen(filename);
1836
1837 if ((1 == len) && ('.' == filename[0]))
1838 return FT_DEV_NULL;
1839 if (stat(filename, &st) < 0)
1840 return FT_OTHER;
1841 if (S_ISCHR(st.st_mode)) {
1842 if ((MEM_MAJOR == major(st.st_rdev)) &&
1843 (DEV_NULL_MINOR_NUM == minor(st.st_rdev)))
1844 return FT_DEV_NULL;
1845 if (RAW_MAJOR == major(st.st_rdev))
1846 return FT_RAW;
1847 if (SCSI_GENERIC_MAJOR == major(st.st_rdev))
1848 return FT_SG;
1849 if (SCSI_TAPE_MAJOR == major(st.st_rdev))
1850 return FT_ST;
1851 } else if (S_ISBLK(st.st_mode))
1852 return FT_BLOCK;
1853 return FT_OTHER;
1854 }
1855
read_capacity(int sg_fd,int * num_sect,int * sect_sz)1856 int read_capacity(int sg_fd, int *num_sect, int *sect_sz)
1857 {
1858 int res;
1859 unsigned char rcCmdBlk[10] =
1860 { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1861 unsigned char rcBuff[READ_CAP_REPLY_LEN];
1862 unsigned char sense_b[64];
1863 sg_io_hdr_t io_hdr;
1864
1865 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
1866 io_hdr.interface_id = 'S';
1867 io_hdr.cmd_len = sizeof(rcCmdBlk);
1868 io_hdr.mx_sb_len = sizeof(sense_b);
1869 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
1870 io_hdr.dxfer_len = sizeof(rcBuff);
1871 io_hdr.dxferp = rcBuff;
1872 io_hdr.cmdp = rcCmdBlk;
1873 io_hdr.sbp = sense_b;
1874 io_hdr.timeout = DEF_TIMEOUT;
1875
1876 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
1877 perror("read_capacity (SG_IO) error");
1878 return -1;
1879 }
1880 res = sg_err_category3(&io_hdr);
1881 if (SG_ERR_CAT_MEDIA_CHANGED == res)
1882 return 2; /* probably have another go ... */
1883 else if (SG_ERR_CAT_CLEAN != res) {
1884 sg_chk_n_print3("read capacity", &io_hdr);
1885 return -1;
1886 }
1887 *num_sect = 1 + ((rcBuff[0] << 24) | (rcBuff[1] << 16) |
1888 (rcBuff[2] << 8) | rcBuff[3]);
1889 *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) |
1890 (rcBuff[6] << 8) | rcBuff[7];
1891 return 0;
1892 }
1893
1894 /* Return of 0 -> success, -1 -> failure, 2 -> try again */
sync_cache(int sg_fd)1895 int sync_cache(int sg_fd)
1896 {
1897 int res;
1898 unsigned char scCmdBlk[10] = { SYNCHRONIZE_CACHE, 0, 0, 0, 0, 0, 0,
1899 0, 0, 0
1900 };
1901 unsigned char sense_b[64];
1902 sg_io_hdr_t io_hdr;
1903
1904 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
1905 io_hdr.interface_id = 'S';
1906 io_hdr.cmd_len = sizeof(scCmdBlk);
1907 io_hdr.mx_sb_len = sizeof(sense_b);
1908 io_hdr.dxfer_direction = SG_DXFER_NONE;
1909 io_hdr.dxfer_len = 0;
1910 io_hdr.dxferp = NULL;
1911 io_hdr.cmdp = scCmdBlk;
1912 io_hdr.sbp = sense_b;
1913 io_hdr.timeout = DEF_TIMEOUT;
1914
1915 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
1916 perror("synchronize_cache (SG_IO) error");
1917 return -1;
1918 }
1919 res = sg_err_category3(&io_hdr);
1920 if (SG_ERR_CAT_MEDIA_CHANGED == res)
1921 return 2; /* probably have another go ... */
1922 else if (SG_ERR_CAT_CLEAN != res) {
1923 sg_chk_n_print3("synchronize cache", &io_hdr);
1924 return -1;
1925 }
1926 return 0;
1927 }
1928
sg_build_scsi_cdb(unsigned char * cdbp,int cdb_sz,unsigned int blocks,unsigned int start_block,int write_true,int fua,int dpo)1929 int sg_build_scsi_cdb(unsigned char *cdbp, int cdb_sz, unsigned int blocks,
1930 unsigned int start_block, int write_true, int fua,
1931 int dpo)
1932 {
1933 int rd_opcode[] = { 0x8, 0x28, 0xa8, 0x88 };
1934 int wr_opcode[] = { 0xa, 0x2a, 0xaa, 0x8a };
1935 int sz_ind;
1936
1937 memset(cdbp, 0, cdb_sz);
1938 if (dpo)
1939 cdbp[1] |= 0x10;
1940 if (fua)
1941 cdbp[1] |= 0x8;
1942 switch (cdb_sz) {
1943 case 6:
1944 sz_ind = 0;
1945 cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] :
1946 rd_opcode[sz_ind]);
1947 cdbp[1] = (unsigned char)((start_block >> 16) & 0x1f);
1948 cdbp[2] = (unsigned char)((start_block >> 8) & 0xff);
1949 cdbp[3] = (unsigned char)(start_block & 0xff);
1950 cdbp[4] = (256 == blocks) ? 0 : (unsigned char)blocks;
1951 if (blocks > 256) {
1952 fprintf(stderr,
1953 ME "for 6 byte commands, maximum number of "
1954 "blocks is 256\n");
1955 return 1;
1956 }
1957 if ((start_block + blocks - 1) & (~0x1fffff)) {
1958 fprintf(stderr,
1959 ME "for 6 byte commands, can't address blocks"
1960 " beyond %d\n", 0x1fffff);
1961 return 1;
1962 }
1963 if (dpo || fua) {
1964 fprintf(stderr,
1965 ME "for 6 byte commands, neither dpo nor fua"
1966 " bits supported\n");
1967 return 1;
1968 }
1969 break;
1970 case 10:
1971 sz_ind = 1;
1972 cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] :
1973 rd_opcode[sz_ind]);
1974 cdbp[2] = (unsigned char)((start_block >> 24) & 0xff);
1975 cdbp[3] = (unsigned char)((start_block >> 16) & 0xff);
1976 cdbp[4] = (unsigned char)((start_block >> 8) & 0xff);
1977 cdbp[5] = (unsigned char)(start_block & 0xff);
1978 cdbp[7] = (unsigned char)((blocks >> 8) & 0xff);
1979 cdbp[8] = (unsigned char)(blocks & 0xff);
1980 if (blocks & (~0xffff)) {
1981 fprintf(stderr,
1982 ME "for 10 byte commands, maximum number of "
1983 "blocks is %d\n", 0xffff);
1984 return 1;
1985 }
1986 break;
1987 case 12:
1988 sz_ind = 2;
1989 cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] :
1990 rd_opcode[sz_ind]);
1991 cdbp[2] = (unsigned char)((start_block >> 24) & 0xff);
1992 cdbp[3] = (unsigned char)((start_block >> 16) & 0xff);
1993 cdbp[4] = (unsigned char)((start_block >> 8) & 0xff);
1994 cdbp[5] = (unsigned char)(start_block & 0xff);
1995 cdbp[6] = (unsigned char)((blocks >> 24) & 0xff);
1996 cdbp[7] = (unsigned char)((blocks >> 16) & 0xff);
1997 cdbp[8] = (unsigned char)((blocks >> 8) & 0xff);
1998 cdbp[9] = (unsigned char)(blocks & 0xff);
1999 break;
2000 case 16:
2001 sz_ind = 3;
2002 cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] :
2003 rd_opcode[sz_ind]);
2004 /* can't cope with block number > 32 bits (yet) */
2005 cdbp[6] = (unsigned char)((start_block >> 24) & 0xff);
2006 cdbp[7] = (unsigned char)((start_block >> 16) & 0xff);
2007 cdbp[8] = (unsigned char)((start_block >> 8) & 0xff);
2008 cdbp[9] = (unsigned char)(start_block & 0xff);
2009 cdbp[10] = (unsigned char)((blocks >> 24) & 0xff);
2010 cdbp[11] = (unsigned char)((blocks >> 16) & 0xff);
2011 cdbp[12] = (unsigned char)((blocks >> 8) & 0xff);
2012 cdbp[13] = (unsigned char)(blocks & 0xff);
2013 break;
2014 default:
2015 fprintf(stderr,
2016 ME "expected cdb size of 6, 10, 12, or 16 but got"
2017 "=%d\n", cdb_sz);
2018 return 1;
2019 }
2020 return 0;
2021 }
2022
2023 /* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM),
2024 2 -> try again */
sg_read(int sg_fd,unsigned char * buff,int blocks,int from_block,int bs,int cdbsz,int fua,int * diop)2025 int sg_read(int sg_fd, unsigned char *buff, int blocks, int from_block,
2026 int bs, int cdbsz, int fua, int *diop)
2027 {
2028 unsigned char rdCmd[MAX_SCSI_CDBSZ];
2029 unsigned char senseBuff[SENSE_BUFF_LEN];
2030 sg_io_hdr_t io_hdr;
2031
2032 if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, 0)) {
2033 fprintf(stderr,
2034 ME "bad rd cdb build, from_block=%d, blocks=%d\n",
2035 from_block, blocks);
2036 return -1;
2037 }
2038
2039 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
2040 io_hdr.interface_id = 'S';
2041 io_hdr.cmd_len = cdbsz;
2042 io_hdr.cmdp = rdCmd;
2043 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
2044 io_hdr.dxfer_len = bs * blocks;
2045 io_hdr.dxferp = buff;
2046 io_hdr.mx_sb_len = SENSE_BUFF_LEN;
2047 io_hdr.sbp = senseBuff;
2048 io_hdr.timeout = DEF_TIMEOUT;
2049 io_hdr.pack_id = from_block;
2050 if (diop && *diop)
2051 io_hdr.flags |= SG_FLAG_DIRECT_IO;
2052
2053 if (ioctl(sg_fd, SG_IO, &io_hdr)) {
2054 if (ENOMEM == errno)
2055 return 1;
2056 perror("reading (SG_IO) on sg device, error");
2057 return -1;
2058 }
2059 switch (sg_err_category3(&io_hdr)) {
2060 case SG_ERR_CAT_CLEAN:
2061 break;
2062 case SG_ERR_CAT_RECOVERED:
2063 fprintf(stderr,
2064 "Recovered error while reading block=%d, num=%d\n",
2065 from_block, blocks);
2066 break;
2067 case SG_ERR_CAT_MEDIA_CHANGED:
2068 return 2;
2069 default:
2070 sg_chk_n_print3("reading", &io_hdr);
2071 if (do_coe) {
2072 memset(buff, 0, bs * blocks);
2073 fprintf(stderr, ">> unable to read at blk=%d for "
2074 "%d bytes, use zeros\n", from_block,
2075 bs * blocks);
2076 return 0; /* fudge success */
2077 } else
2078 return -1;
2079 }
2080 if (diop && *diop &&
2081 ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
2082 *diop = 0; /* flag that dio not done (completely) */
2083 sum_of_resids += io_hdr.resid;
2084 #if SG_DEBUG
2085 fprintf(stderr, "duration=%u ms\n", io_hdr.duration);
2086 #endif
2087 return 0;
2088 }
2089
2090 /* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM),
2091 2 -> try again */
sg_write(int sg_fd,unsigned char * buff,int blocks,int to_block,int bs,int cdbsz,int fua,int * diop)2092 int sg_write(int sg_fd, unsigned char *buff, int blocks, int to_block,
2093 int bs, int cdbsz, int fua, int *diop)
2094 {
2095 unsigned char wrCmd[MAX_SCSI_CDBSZ];
2096 unsigned char senseBuff[SENSE_BUFF_LEN];
2097 sg_io_hdr_t io_hdr;
2098
2099 if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, 1, fua, 0)) {
2100 fprintf(stderr, ME "bad wr cdb build, to_block=%d, blocks=%d\n",
2101 to_block, blocks);
2102 return -1;
2103 }
2104
2105 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
2106 io_hdr.interface_id = 'S';
2107 io_hdr.cmd_len = cdbsz;
2108 io_hdr.cmdp = wrCmd;
2109 io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
2110 io_hdr.dxfer_len = bs * blocks;
2111 io_hdr.dxferp = buff;
2112 io_hdr.mx_sb_len = SENSE_BUFF_LEN;
2113 io_hdr.sbp = senseBuff;
2114 io_hdr.timeout = DEF_TIMEOUT;
2115 io_hdr.pack_id = to_block;
2116 if (diop && *diop)
2117 io_hdr.flags |= SG_FLAG_DIRECT_IO;
2118
2119 if (ioctl(sg_fd, SG_IO, &io_hdr)) {
2120 if (ENOMEM == errno)
2121 return 1;
2122 perror("writing (SG_IO) on sg device, error");
2123 return -1;
2124 }
2125 switch (sg_err_category3(&io_hdr)) {
2126 case SG_ERR_CAT_CLEAN:
2127 break;
2128 case SG_ERR_CAT_RECOVERED:
2129 fprintf(stderr,
2130 "Recovered error while writing block=%d, num=%d\n",
2131 to_block, blocks);
2132 break;
2133 case SG_ERR_CAT_MEDIA_CHANGED:
2134 return 2;
2135 default:
2136 sg_chk_n_print3("writing", &io_hdr);
2137 if (do_coe) {
2138 fprintf(stderr, ">> ignored errors for out blk=%d for "
2139 "%d bytes\n", to_block, bs * blocks);
2140 return 0; /* fudge success */
2141 } else
2142 return -1;
2143 }
2144 if (diop && *diop &&
2145 ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
2146 *diop = 0; /* flag that dio not done (completely) */
2147 return 0;
2148 }
2149
get_num(char * buf)2150 int get_num(char *buf)
2151 {
2152 int res, num;
2153 char c;
2154
2155 res = sscanf(buf, "%d%c", &num, &c);
2156 if (0 == res)
2157 return -1;
2158 else if (1 == res)
2159 return num;
2160 else {
2161 switch (c) {
2162 case 'c':
2163 case 'C':
2164 return num;
2165 case 'b':
2166 case 'B':
2167 return num * 512;
2168 case 'k':
2169 return num * 1024;
2170 case 'K':
2171 return num * 1000;
2172 case 'm':
2173 return num * 1024 * 1024;
2174 case 'M':
2175 return num * 1000000;
2176 case 'g':
2177 return num * 1024 * 1024 * 1024;
2178 case 'G':
2179 return num * 1000000000;
2180 default:
2181 fprintf(stderr, "unrecognized multiplier\n");
2182 return -1;
2183 }
2184 }
2185 }
2186
do_scsi_device_read_write(char * device)2187 int do_scsi_device_read_write(char *device)
2188 {
2189 int skip = 0;
2190 int seek = 0;
2191 int bs = 0;
2192 int ibs = 0;
2193 int obs = 0;
2194 int bpt = DEF_BLOCKS_PER_TRANSFER;
2195 char inf[INOUTF_SZ];
2196 int in_type = FT_OTHER;
2197 char outf[INOUTF_SZ];
2198 int out_type = FT_OTHER;
2199 int dio = 0;
2200 int dio_incomplete = 0;
2201 int do_time = 1;
2202 int do_odir = 1;
2203 int scsi_cdbsz = DEF_SCSI_CDBSZ;
2204 int fua_mode = 0;
2205 int do_sync = 1;
2206 int do_blk_sgio = 1;
2207 int do_append = 1;
2208 int res, t, buf_sz, dio_tmp;
2209 int infd, outfd, blocks;
2210 unsigned char *wrkBuff;
2211 unsigned char *wrkPos;
2212 int in_num_sect = 0;
2213 int out_num_sect = 0;
2214 int in_sect_sz, out_sect_sz;
2215 char ebuff[EBUFF_SZ];
2216 int blocks_per;
2217 int req_count;
2218 struct timeval start_tm, end_tm;
2219
2220 print_msg(TEST_BREAK, __FUNCTION__);
2221 strcpy(inf, "/dev/zero");
2222 strcpy(outf, device);
2223
2224 if (bs <= 0) {
2225 bs = DEF_BLOCK_SIZE;
2226 fprintf(stderr,
2227 "Assume default 'bs' (block size) of %d bytes\n", bs);
2228 }
2229 if ((ibs && (ibs != bs)) || (obs && (obs != bs))) {
2230 fprintf(stderr,
2231 "If 'ibs' or 'obs' given must be same as 'bs'\n");
2232 usage();
2233 return 1;
2234 }
2235 if ((skip < 0) || (seek < 0)) {
2236 fprintf(stderr, "skip and seek cannot be negative\n");
2237 return 1;
2238 }
2239 if ((do_append > 0) && (seek > 0)) {
2240 fprintf(stderr, "Can't use both append and seek switches\n");
2241 return 1;
2242 }
2243 #ifdef SG_DEBUG
2244 fprintf(stderr, ME "if=%s skip=%d of=%s seek=%d count=%d\n",
2245 inf, skip, outf, seek, dd_count);
2246 #endif
2247 install_handler(SIGINT, interrupt_handler);
2248 install_handler(SIGQUIT, interrupt_handler);
2249 install_handler(SIGPIPE, interrupt_handler);
2250 install_handler(SIGUSR1, siginfo_handler);
2251
2252 infd = STDIN_FILENO;
2253 outfd = STDOUT_FILENO;
2254 if (inf[0] && ('-' != inf[0])) {
2255 in_type = dd_filetype(inf);
2256
2257 if ((FT_BLOCK & in_type) && do_blk_sgio)
2258 in_type |= FT_SG;
2259
2260 if (FT_ST == in_type) {
2261 fprintf(stderr,
2262 ME "unable to use scsi tape device %s\n", inf);
2263 return 1;
2264 } else if (FT_SG & in_type) {
2265 if ((infd = open(inf, O_RDWR)) < 0) {
2266 snprintf(ebuff, EBUFF_SZ,
2267 ME "could not open %s for sg reading",
2268 inf);
2269 perror(ebuff);
2270 return 1;
2271 }
2272 t = bs * bpt;
2273 res = ioctl(infd, SG_SET_RESERVED_SIZE, &t);
2274 if (res < 0)
2275 perror(ME "SG_SET_RESERVED_SIZE error");
2276 res = ioctl(infd, SG_GET_VERSION_NUM, &t);
2277 if ((res < 0) || (t < 30000)) {
2278 if (FT_BLOCK & in_type)
2279 fprintf(stderr,
2280 ME
2281 "SG_IO unsupported on this block"
2282 " device\n");
2283 else
2284 fprintf(stderr,
2285 ME
2286 "sg driver prior to 3.x.y\n");
2287 return 1;
2288 }
2289 } else {
2290 if (do_odir && (FT_BLOCK == in_type))
2291 infd = open(inf, O_RDONLY | O_DIRECT);
2292 else
2293 infd = open(inf, O_RDONLY);
2294 if (infd < 0) {
2295 snprintf(ebuff, EBUFF_SZ,
2296 ME "could not open %s for reading",
2297 inf);
2298 perror(ebuff);
2299 return 1;
2300 } else if (skip > 0) {
2301 llse_loff_t offset = skip;
2302
2303 offset *= bs; /* could exceed 32 bits here! */
2304 if (llse_llseek(infd, offset, SEEK_SET) < 0) {
2305 snprintf(ebuff, EBUFF_SZ,
2306 ME
2307 "couldn't skip to required position on %s",
2308 inf);
2309 perror(ebuff);
2310 return 1;
2311 }
2312 }
2313 }
2314 }
2315
2316 if (outf[0] && ('-' != outf[0])) {
2317 out_type = dd_filetype(outf);
2318
2319 if ((FT_BLOCK & out_type) && do_blk_sgio)
2320 out_type |= FT_SG;
2321
2322 if (FT_ST == out_type) {
2323 fprintf(stderr,
2324 ME "unable to use scsi tape device %s\n", outf);
2325 return 1;
2326 } else if (FT_SG & out_type) {
2327 if ((outfd = open(outf, O_RDWR)) < 0) {
2328 snprintf(ebuff, EBUFF_SZ,
2329 ME "could not open %s for sg writing",
2330 outf);
2331 perror(ebuff);
2332 return 1;
2333 }
2334 t = bs * bpt;
2335 res = ioctl(outfd, SG_SET_RESERVED_SIZE, &t);
2336 if (res < 0)
2337 perror(ME "SG_SET_RESERVED_SIZE error");
2338 res = ioctl(outfd, SG_GET_VERSION_NUM, &t);
2339 if ((res < 0) || (t < 30000)) {
2340 fprintf(stderr,
2341 ME "sg driver prior to 3.x.y\n");
2342 return 1;
2343 }
2344 } else if (FT_DEV_NULL & out_type)
2345 outfd = -1; /* don't bother opening */
2346 else {
2347 if (FT_RAW != out_type) {
2348 int flags = O_WRONLY | O_CREAT;
2349
2350 if (do_odir && (FT_BLOCK == out_type))
2351 flags |= O_DIRECT;
2352 else if (do_append)
2353 flags |= O_APPEND;
2354 if ((outfd = open(outf, flags, 0666)) < 0) {
2355 snprintf(ebuff, EBUFF_SZ,
2356 ME
2357 "could not open %s for writing",
2358 outf);
2359 perror(ebuff);
2360 return 1;
2361 }
2362 } else {
2363 if ((outfd = open(outf, O_WRONLY)) < 0) {
2364 snprintf(ebuff, EBUFF_SZ,
2365 ME
2366 "could not open %s for raw writing",
2367 outf);
2368 perror(ebuff);
2369 return 1;
2370 }
2371 }
2372 if (seek > 0) {
2373 llse_loff_t offset = seek;
2374
2375 offset *= bs; /* could exceed 32 bits here! */
2376 if (llse_llseek(outfd, offset, SEEK_SET) < 0) {
2377 snprintf(ebuff, EBUFF_SZ,
2378 ME
2379 "couldn't seek to required position on %s",
2380 outf);
2381 perror(ebuff);
2382 return 1;
2383 }
2384 }
2385 }
2386 }
2387 if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) {
2388 fprintf(stderr,
2389 "Can't have both 'if' as stdin _and_ 'of' as stdout\n");
2390 return 1;
2391 }
2392
2393 if (dd_count < 0) {
2394 if (FT_SG & in_type) {
2395 res = read_capacity(infd, &in_num_sect, &in_sect_sz);
2396 if (2 == res) {
2397 fprintf(stderr,
2398 "Unit attention, media changed(in), continuing\n");
2399 res =
2400 read_capacity(infd, &in_num_sect,
2401 &in_sect_sz);
2402 }
2403 if (0 != res) {
2404 fprintf(stderr,
2405 "Unable to read capacity on %s\n", inf);
2406 in_num_sect = -1;
2407 } else {
2408 if (in_num_sect > skip)
2409 in_num_sect -= skip;
2410 }
2411 }
2412 if (FT_SG & out_type) {
2413 res = read_capacity(outfd, &out_num_sect, &out_sect_sz);
2414 if (2 == res) {
2415 fprintf(stderr,
2416 "Unit attention, media changed(out), continuing\n");
2417 res =
2418 read_capacity(outfd, &out_num_sect,
2419 &out_sect_sz);
2420 }
2421 if (0 != res) {
2422 fprintf(stderr,
2423 "Unable to read capacity on %s\n",
2424 outf);
2425 out_num_sect = -1;
2426 } else {
2427 if (out_num_sect > seek)
2428 out_num_sect -= seek;
2429 }
2430 }
2431 #ifdef SG_DEBUG
2432 fprintf(stderr,
2433 "Start of loop, count=%d, in_num_sect=%d, out_num_sect=%d\n",
2434 dd_count, in_num_sect, out_num_sect);
2435 #endif
2436 if (in_num_sect > 0) {
2437 if (out_num_sect > 0)
2438 dd_count =
2439 (in_num_sect >
2440 out_num_sect) ? out_num_sect : in_num_sect;
2441 else
2442 dd_count = in_num_sect;
2443 } else
2444 dd_count = out_num_sect;
2445 }
2446 if (dd_count < 0) {
2447 fprintf(stderr, "Couldn't calculate count, please give one\n");
2448 return 1;
2449 }
2450
2451 if (dio || do_odir || (FT_RAW == in_type) || (FT_RAW == out_type)) {
2452 size_t psz = getpagesize();
2453 wrkBuff = malloc(bs * bpt + psz);
2454 if (0 == wrkBuff) {
2455 fprintf(stderr, "Not enough user memory for raw\n");
2456 return 1;
2457 }
2458 wrkPos = (unsigned char *)(((unsigned long)wrkBuff + psz - 1) &
2459 (~(psz - 1)));
2460 } else {
2461 wrkBuff = malloc(bs * bpt);
2462 if (0 == wrkBuff) {
2463 fprintf(stderr, "Not enough user memory\n");
2464 return 1;
2465 }
2466 wrkPos = wrkBuff;
2467 }
2468
2469 blocks_per = bpt;
2470 #ifdef SG_DEBUG
2471 fprintf(stderr, "Start of loop, count=%d, blocks_per=%d\n",
2472 dd_count, blocks_per);
2473 #endif
2474 if (do_time) {
2475 start_tm.tv_sec = 0;
2476 start_tm.tv_usec = 0;
2477 gettimeofday(&start_tm, NULL);
2478 }
2479 req_count = dd_count;
2480
2481 while (dd_count > 0) {
2482 blocks = (dd_count > blocks_per) ? blocks_per : dd_count;
2483 if (FT_SG & in_type) {
2484 int fua = fua_mode & 2;
2485
2486 dio_tmp = dio;
2487 res =
2488 sg_read(infd, wrkPos, blocks, skip, bs, scsi_cdbsz,
2489 fua, &dio_tmp);
2490 if (1 == res) { /* ENOMEM, find what's available+try that */
2491 if (ioctl(infd, SG_GET_RESERVED_SIZE, &buf_sz) <
2492 0) {
2493 perror("RESERVED_SIZE ioctls failed");
2494 break;
2495 }
2496 blocks_per = (buf_sz + bs - 1) / bs;
2497 blocks = blocks_per;
2498 fprintf(stderr,
2499 "Reducing read to %d blocks per loop\n",
2500 blocks_per);
2501 res =
2502 sg_read(infd, wrkPos, blocks, skip, bs,
2503 scsi_cdbsz, fua, &dio_tmp);
2504 } else if (2 == res) {
2505 fprintf(stderr,
2506 "Unit attention, media changed, continuing (r)\n");
2507 res =
2508 sg_read(infd, wrkPos, blocks, skip, bs,
2509 scsi_cdbsz, fua, &dio_tmp);
2510 }
2511 if (0 != res) {
2512 fprintf(stderr, "sg_read failed, skip=%d\n",
2513 skip);
2514 break;
2515 } else {
2516 in_full += blocks;
2517 if (dio && (0 == dio_tmp))
2518 dio_incomplete++;
2519 }
2520 } else {
2521 while (((res = read(infd, wrkPos, blocks * bs)) < 0) &&
2522 (EINTR == errno)) ;
2523 if (res < 0) {
2524 snprintf(ebuff, EBUFF_SZ,
2525 ME "reading, skip=%d ", skip);
2526 perror(ebuff);
2527 break;
2528 } else if (res < blocks * bs) {
2529 dd_count = 0;
2530 blocks = res / bs;
2531 if ((res % bs) > 0) {
2532 blocks++;
2533 in_partial++;
2534 }
2535 }
2536 in_full += blocks;
2537 }
2538
2539 if (FT_SG & out_type) {
2540 int fua = fua_mode & 1;
2541
2542 dio_tmp = dio;
2543 res =
2544 sg_write(outfd, wrkPos, blocks, seek, bs,
2545 scsi_cdbsz, fua, &dio_tmp);
2546 if (1 == res) { /* ENOMEM, find what's available+try that */
2547 if (ioctl(outfd, SG_GET_RESERVED_SIZE, &buf_sz)
2548 < 0) {
2549 perror("RESERVED_SIZE ioctls failed");
2550 break;
2551 }
2552 blocks_per = (buf_sz + bs - 1) / bs;
2553 blocks = blocks_per;
2554 fprintf(stderr,
2555 "Reducing write to %d blocks per loop\n",
2556 blocks);
2557 res =
2558 sg_write(outfd, wrkPos, blocks, seek, bs,
2559 scsi_cdbsz, fua, &dio_tmp);
2560 } else if (2 == res) {
2561 fprintf(stderr,
2562 "Unit attention, media changed, continuing (w)\n");
2563 res =
2564 sg_write(outfd, wrkPos, blocks, seek, bs,
2565 scsi_cdbsz, fua, &dio_tmp);
2566 } else if (0 != res) {
2567 fprintf(stderr, "sg_write failed, seek=%d\n",
2568 seek);
2569 break;
2570 } else {
2571 out_full += blocks;
2572 if (dio && (0 == dio_tmp))
2573 dio_incomplete++;
2574 }
2575 } else if (FT_DEV_NULL & out_type)
2576 out_full += blocks; /* act as if written out without error */
2577 else {
2578 while (((res = write(outfd, wrkPos, blocks * bs)) < 0)
2579 && (EINTR == errno)) ;
2580 if (res < 0) {
2581 snprintf(ebuff, EBUFF_SZ,
2582 ME "writing, seek=%d ", seek);
2583 perror(ebuff);
2584 break;
2585 } else if (res < blocks * bs) {
2586 fprintf(stderr,
2587 "output file probably full, seek=%d ",
2588 seek);
2589 blocks = res / bs;
2590 out_full += blocks;
2591 if ((res % bs) > 0)
2592 out_partial++;
2593 break;
2594 } else
2595 out_full += blocks;
2596 }
2597 if (dd_count > 0)
2598 dd_count -= blocks;
2599 skip += blocks;
2600 seek += blocks;
2601 }
2602 if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
2603 struct timeval res_tm;
2604 double a, b;
2605
2606 gettimeofday(&end_tm, NULL);
2607 res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
2608 res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
2609 if (res_tm.tv_usec < 0) {
2610 --res_tm.tv_sec;
2611 res_tm.tv_usec += 1000000;
2612 }
2613 a = res_tm.tv_sec;
2614 a += (0.000001 * res_tm.tv_usec);
2615 b = (double)bs *(req_count - dd_count);
2616 printf("time to transfer data was %d.%06d secs",
2617 (int)res_tm.tv_sec, (int)res_tm.tv_usec);
2618 if ((a > 0.00001) && (b > 511))
2619 printf(", %.2f MB/sec\n", b / (a * 1000000.0));
2620 else
2621 printf("\n");
2622 }
2623 if (do_sync) {
2624 if (FT_SG & out_type) {
2625 fprintf(stderr, ">> Synchronizing cache on %s\n", outf);
2626 res = sync_cache(outfd);
2627 if (2 == res) {
2628 fprintf(stderr,
2629 "Unit attention, media changed(in), continuing\n");
2630 res = sync_cache(outfd);
2631 }
2632 if (0 != res)
2633 fprintf(stderr,
2634 "Unable to synchronize cache\n");
2635 }
2636 }
2637 free(wrkBuff);
2638 if (STDIN_FILENO != infd)
2639 close(infd);
2640 if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type))
2641 close(outfd);
2642 res = 0;
2643 if (0 != dd_count) {
2644 fprintf(stderr, "Some error occurred,");
2645 res = 2;
2646 }
2647 print_stats();
2648 if (dio_incomplete) {
2649 int fd;
2650 char c;
2651
2652 fprintf(stderr,
2653 ">> Direct IO requested but incomplete %d times\n",
2654 dio_incomplete);
2655 if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) {
2656 if (1 == read(fd, &c, 1)) {
2657 if ('0' == c)
2658 fprintf(stderr,
2659 ">>> %s set to '0' but should be set "
2660 "to '1' for direct IO\n",
2661 proc_allow_dio);
2662 }
2663 close(fd);
2664 }
2665 }
2666 if (sum_of_resids)
2667 fprintf(stderr, ">> Non-zero sum of residual counts=%d\n",
2668 sum_of_resids);
2669 return res;
2670 }
2671
2672 /* Returns 0 when successful, else -1 */
do_scsi_inq(int sg_fd,int cmddt,int evpd,unsigned int pg_op,void * resp,int mx_resp_len,int noisy)2673 static int do_scsi_inq(int sg_fd, int cmddt, int evpd, unsigned int pg_op,
2674 void *resp, int mx_resp_len, int noisy)
2675 {
2676 int res;
2677 unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
2678 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
2679 unsigned char sense_b[SENSE_BUFF_LEN];
2680 sg_io_hdr_t io_hdr;
2681
2682 if (cmddt)
2683 inqCmdBlk[1] |= 2;
2684 if (evpd)
2685 inqCmdBlk[1] |= 1;
2686 inqCmdBlk[2] = (unsigned char)pg_op;
2687 inqCmdBlk[4] = (unsigned char)mx_resp_len;
2688 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
2689 io_hdr.interface_id = 'S';
2690 io_hdr.cmd_len = sizeof(inqCmdBlk);
2691 io_hdr.mx_sb_len = sizeof(sense_b);
2692 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
2693 io_hdr.dxfer_len = mx_resp_len;
2694 io_hdr.dxferp = resp;
2695 io_hdr.cmdp = inqCmdBlk;
2696 io_hdr.sbp = sense_b;
2697 io_hdr.timeout = DEF_TIMEOUT;
2698
2699 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
2700 perror("SG_IO (inquiry) error");
2701 return -1;
2702 }
2703 res = sg_err_category3(&io_hdr);
2704 switch (res) {
2705 case SG_ERR_CAT_CLEAN:
2706 case SG_ERR_CAT_RECOVERED:
2707 return 0;
2708 default:
2709 if (noisy) {
2710 char ebuff[EBUFF_SZ];
2711 snprintf(ebuff, EBUFF_SZ, "Inquiry error, CmdDt=%d, "
2712 "EVPD=%d, page_opcode=%x ", cmddt, evpd,
2713 pg_op);
2714 sg_chk_n_print3(ebuff, &io_hdr);
2715 }
2716 return -1;
2717 }
2718 }
2719
do_scsi_inquiry(char * device,int hex_flag)2720 int do_scsi_inquiry(char *device, int hex_flag)
2721 {
2722 int sg_fd, k, j, num, len, act_len;
2723 int support_num;
2724 char *file_name = 0;
2725 char buff[MX_ALLOC_LEN + 1];
2726 unsigned char rsp_buff[MX_ALLOC_LEN + 1];
2727 unsigned int num_opcode = 0;
2728 int do_evpd = 0;
2729 int do_cmddt = 0;
2730 int do_cmdlst = 0;
2731 int do_hex = 0;
2732 int do_raw = 0;
2733 int do_pci = 0;
2734 int do_36 = 0;
2735 int oflags = O_RDONLY | O_NONBLOCK;
2736 int ansi_version = 0;
2737 int ret = 0;
2738
2739 file_name = device;
2740
2741 if (hex_flag) {
2742 do_hex = TRUE;
2743 print_msg(TEST_BREAK, __FUNCTION__);
2744 } else {
2745 do_pci = TRUE;
2746 }
2747
2748 if (do_pci)
2749 oflags = O_RDWR | O_NONBLOCK;
2750 if ((sg_fd = open(file_name, oflags)) < 0) {
2751 snprintf(ebuff, EBUFF_SZ, "sg_inq: error opening file: %s",
2752 file_name);
2753 perror(ebuff);
2754 return 1;
2755 }
2756 /* Just to be safe, check we have a new sg device by trying an ioctl */
2757 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
2758 fprintf(stderr,
2759 "sg_inq: %s doesn't seem to be a version 3 sg device\n",
2760 file_name);
2761 close(sg_fd);
2762 return 1;
2763 }
2764 memset(rsp_buff, 0, MX_ALLOC_LEN + 1);
2765
2766 if (!(do_cmddt || do_evpd)) {
2767 if (!do_raw)
2768 printf("standard INQUIRY:\n");
2769 if (num_opcode > 0)
2770 printf
2771 (" <<given opcode or page_code is being ignored>>\n");
2772
2773 if (0 == do_scsi_inq(sg_fd, 0, 0, 0, rsp_buff, 36, 1)) {
2774 len = rsp_buff[4] + 5;
2775 ansi_version = rsp_buff[2] & 0x7;
2776 if ((len > 36) && (len < 256) && (!do_36)) {
2777 if (do_scsi_inq
2778 (sg_fd, 0, 0, 0, rsp_buff, len, 1)) {
2779 fprintf(stderr,
2780 "second INQUIRY (%d byte) failed\n",
2781 len);
2782 return 1;
2783 }
2784 if (len != (rsp_buff[4] + 5)) {
2785 fprintf(stderr,
2786 "strange, twin INQUIRYs yield different "
2787 "'additional length'\n");
2788 ret = 2;
2789 }
2790 }
2791 if (do_36) {
2792 act_len = len;
2793 len = 36;
2794 } else
2795 act_len = len;
2796 if (do_hex)
2797 dStrHex((const char *)rsp_buff, len, 0);
2798 else {
2799 printf
2800 (" PQual=%d, Device type=%d, RMB=%d, ANSI version=%d, ",
2801 (rsp_buff[0] & 0xe0) >> 5,
2802 rsp_buff[0] & 0x1f,
2803 ! !(rsp_buff[1] & 0x80), ansi_version);
2804 printf("[full version=0x%02x]\n",
2805 (unsigned int)rsp_buff[2]);
2806 printf
2807 (" AERC=%d, TrmTsk=%d, NormACA=%d, HiSUP=%d, "
2808 "Resp data format=%d, SCCS=%d\n",
2809 ! !(rsp_buff[3] & 0x80),
2810 ! !(rsp_buff[3] & 0x40),
2811 ! !(rsp_buff[3] & 0x20),
2812 ! !(rsp_buff[3] & 0x10),
2813 rsp_buff[3] & 0x0f,
2814 ! !(rsp_buff[5] & 0x80));
2815 printf
2816 (" BQue=%d, EncServ=%d, MultiP=%d, MChngr=%d, "
2817 "ACKREQQ=%d, ", ! !(rsp_buff[6] & 0x80),
2818 ! !(rsp_buff[6] & 0x40),
2819 ! !(rsp_buff[6] & 0x10),
2820 ! !(rsp_buff[6] & 0x08),
2821 ! !(rsp_buff[6] & 0x04));
2822 printf("Addr16=%d\n RelAdr=%d, ",
2823 ! !(rsp_buff[6] & 0x01),
2824 ! !(rsp_buff[7] & 0x80));
2825 printf
2826 ("WBus16=%d, Sync=%d, Linked=%d, TranDis=%d, ",
2827 ! !(rsp_buff[7] & 0x20),
2828 ! !(rsp_buff[7] & 0x10),
2829 ! !(rsp_buff[7] & 0x08),
2830 ! !(rsp_buff[7] & 0x04));
2831 printf("CmdQue=%d\n", ! !(rsp_buff[7] & 0x02));
2832 if (len > 56)
2833 printf
2834 (" Clocking=0x%x, QAS=%d, IUS=%d\n",
2835 (rsp_buff[56] & 0x0c) >> 2,
2836 ! !(rsp_buff[56] & 0x2),
2837 ! !(rsp_buff[56] & 0x1));
2838 if (act_len == len)
2839 printf(" length=%d (0x%x)", len,
2840 len);
2841 else
2842 printf
2843 (" length=%d (0x%x), but only read 36 bytes",
2844 len, len);
2845 if ((ansi_version >= 2) && (len < 36))
2846 printf
2847 (" [for SCSI>=2, len>=36 is expected]\n");
2848 else
2849 printf("\n");
2850
2851 if (len <= 8)
2852 printf
2853 (" Inquiry response length=%d\n, no vendor, "
2854 "product or revision data\n", len);
2855 else {
2856 if (len < 36)
2857 rsp_buff[len] = '\0';
2858 memcpy(buff, &rsp_buff[8], 8);
2859 buff[8] = '\0';
2860 printf(" Vendor identification: %s\n",
2861 buff);
2862 if (len <= 16)
2863 printf
2864 (" Product identification: <none>\n");
2865 else {
2866 memcpy(buff, &rsp_buff[16], 16);
2867 buff[16] = '\0';
2868 printf
2869 (" Product identification: %s\n",
2870 buff);
2871 }
2872 if (len <= 32)
2873 printf
2874 (" Product revision level: <none>\n");
2875 else {
2876 memcpy(buff, &rsp_buff[32], 4);
2877 buff[4] = '\0';
2878 printf
2879 (" Product revision level: %s\n",
2880 buff);
2881 }
2882 }
2883 }
2884 if (!do_raw &&
2885 (0 ==
2886 do_scsi_inq(sg_fd, 0, 1, 0x80, rsp_buff,
2887 MX_ALLOC_LEN, 0))) {
2888 len = rsp_buff[3];
2889 if (len > 0) {
2890 memcpy(buff, rsp_buff + 4, len);
2891 buff[len] = '\0';
2892 printf(" Product serial number: %s\n",
2893 buff);
2894 }
2895 }
2896 } else {
2897 printf("36 byte INQUIRY failed\n");
2898 return 1;
2899 }
2900 } else if (do_cmddt) {
2901 int reserved_cmddt;
2902 char op_name[128];
2903
2904 if (do_cmdlst) {
2905 printf("Supported command list:\n");
2906 for (k = 0; k < 256; ++k) {
2907 if (0 ==
2908 do_scsi_inq(sg_fd, 1, 0, k, rsp_buff,
2909 MX_ALLOC_LEN, 1)) {
2910 support_num = rsp_buff[1] & 7;
2911 reserved_cmddt = rsp_buff[4];
2912 if ((3 == support_num)
2913 || (5 == support_num)) {
2914 num = rsp_buff[5];
2915 for (j = 0; j < num; ++j)
2916 printf(" %.2x",
2917 (int)rsp_buff[6 +
2918 j]);
2919 if (5 == support_num)
2920 printf
2921 (" [vendor specific manner (5)]");
2922 sg_get_command_name((unsigned
2923 char)k,
2924 sizeof
2925 (op_name) -
2926 1, op_name);
2927 op_name[sizeof(op_name) - 1] =
2928 '\0';
2929 printf(" %s\n", op_name);
2930 } else if ((4 == support_num)
2931 || (6 == support_num))
2932 printf
2933 (" opcode=0x%.2x vendor specific (%d)\n",
2934 k, support_num);
2935 else if ((0 == support_num)
2936 && (reserved_cmddt > 0)) {
2937 printf
2938 (" opcode=0x%.2x ignored cmddt bit, "
2939 "given standard INQUIRY response, stop\n",
2940 k);
2941 break;
2942 }
2943 } else {
2944 fprintf(stderr,
2945 "CmdDt INQUIRY on opcode=0x%.2x: failed\n",
2946 k);
2947 break;
2948 }
2949 }
2950 } else {
2951 if (!do_raw) {
2952 printf("CmdDt INQUIRY, opcode=0x%.2x: [",
2953 num_opcode);
2954 sg_get_command_name((unsigned char)num_opcode,
2955 sizeof(op_name) - 1,
2956 op_name);
2957 op_name[sizeof(op_name) - 1] = '\0';
2958 printf("%s]\n", op_name);
2959 }
2960 if (0 == do_scsi_inq(sg_fd, 1, 0, num_opcode, rsp_buff,
2961 MX_ALLOC_LEN, 1)) {
2962 len = rsp_buff[5] + 6;
2963 reserved_cmddt = rsp_buff[4];
2964 if (do_hex)
2965 dStrHex((const char *)rsp_buff, len, 0);
2966 else {
2967 const char *desc_p;
2968 int prnt_cmd = 0;
2969
2970 support_num = rsp_buff[1] & 7;
2971 num = rsp_buff[5];
2972 switch (support_num) {
2973 case 0:
2974 if (0 == reserved_cmddt)
2975 desc_p =
2976 "no data available";
2977 else
2978 desc_p =
2979 "ignored cmddt bit, standard INQUIRY "
2980 "response";
2981 break;
2982 case 1:
2983 desc_p = "not supported";
2984 break;
2985 case 2:
2986 desc_p = "reserved (2)";
2987 break;
2988 case 3:
2989 desc_p =
2990 "supported as per standard";
2991 prnt_cmd = 1;
2992 break;
2993 case 4:
2994 desc_p = "vendor specific (4)";
2995 break;
2996 case 5:
2997 desc_p =
2998 "supported in vendor specific way";
2999 prnt_cmd = 1;
3000 break;
3001 case 6:
3002 desc_p = "vendor specific (6)";
3003 break;
3004 case 7:
3005 desc_p = "reserved (7)";
3006 break;
3007 default:
3008 desc_p = "impossible value > 7";
3009 break;
3010 }
3011 if (prnt_cmd) {
3012 printf(" Support field: %s [",
3013 desc_p);
3014 for (j = 0; j < num; ++j)
3015 printf(" %.2x",
3016 (int)rsp_buff[6 +
3017 j]);
3018 printf(" ]\n");
3019 } else
3020 printf(" Support field: %s\n",
3021 desc_p);
3022 }
3023 } else {
3024 fprintf(stderr,
3025 "CmdDt INQUIRY on opcode=0x%.2x: failed\n",
3026 num_opcode);
3027 return 1;
3028 }
3029
3030 }
3031 } else if (do_evpd) {
3032 if (!do_raw)
3033 printf("EVPD INQUIRY, page code=0x%.2x:\n", num_opcode);
3034 if (0 ==
3035 do_scsi_inq(sg_fd, 0, 1, num_opcode, rsp_buff, MX_ALLOC_LEN,
3036 1)) {
3037 len = rsp_buff[3] + 4;
3038 if (num_opcode != rsp_buff[1])
3039 printf
3040 ("non evpd respone; probably a STANDARD INQUIRY "
3041 "response\n");
3042 else {
3043 if (!do_hex)
3044 printf(" Only hex output supported\n");
3045 dStrHex((const char *)rsp_buff, len, 0);
3046 }
3047 } else {
3048 fprintf(stderr,
3049 "EVPD INQUIRY, page code=0x%.2x: failed\n",
3050 num_opcode);
3051 return 1;
3052 }
3053 }
3054
3055 if (do_pci) {
3056 unsigned char slot_name[16];
3057
3058 printf("\n");
3059 memset(slot_name, '\0', sizeof(slot_name));
3060 if (ioctl(sg_fd, SCSI_IOCTL_GET_PCI, slot_name) < 0) {
3061 if (EINVAL == errno)
3062 printf
3063 ("ioctl(SCSI_IOCTL_GET_PCI) not supported by this "
3064 "kernel\n");
3065 else if (ENXIO == errno)
3066 printf
3067 ("associated adapter not a PCI device?\n");
3068 else
3069 perror("ioctl(SCSI_IOCTL_GET_PCI) failed");
3070 } else
3071 printf("PCI:slot_name: %s\n", slot_name);
3072 }
3073
3074 close(sg_fd);
3075 return ret;
3076 }
3077
show_scsi_maps()3078 int show_scsi_maps()
3079 {
3080 int sg_fd, res, k;
3081 int do_numeric = NUMERIC_SCAN_DEF;
3082 int do_all_s = 1;
3083 int do_sd = 0;
3084 int do_st = 0;
3085 int do_osst = 0;
3086 int do_sr = 0;
3087 int do_scd = 0;
3088 int do_extra = 1;
3089 int do_inquiry = 0;
3090 char fname[64];
3091 int num_errors = 0;
3092 int num_silent = 0;
3093 int eacces_err = 0;
3094 int last_sg_ind = -1;
3095 struct stat stat_buf;
3096
3097 print_msg(TEST_BREAK, __FUNCTION__);
3098
3099 if (stat(devfs_id, &stat_buf) == 0)
3100 printf("# Note: the devfs pseudo file system is present\n");
3101
3102 for (k = 0, res = 0; (k < MAX_SG_DEVS) && (num_errors < MAX_ERRORS);
3103 ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) {
3104 if (res < 0) {
3105 snprintf(ebuff, EBUFF_SZ, "Error closing %s ", fname);
3106 perror("sg_map: close error");
3107 return 1;
3108 }
3109 make_dev_name(fname, "/dev/sg", k, do_numeric);
3110
3111 sg_fd = open(fname, O_RDONLY | O_NONBLOCK);
3112 if (sg_fd < 0) {
3113 if (EBUSY == errno) {
3114 map_arr[k].active = -2;
3115 continue;
3116 } else if ((ENODEV == errno) || (ENOENT == errno) ||
3117 (ENXIO == errno)) {
3118 ++num_errors;
3119 ++num_silent;
3120 map_arr[k].active = -1;
3121 continue;
3122 } else {
3123 if (EACCES == errno)
3124 eacces_err = 1;
3125 snprintf(ebuff, EBUFF_SZ, "Error opening %s ",
3126 fname);
3127 perror(ebuff);
3128 ++num_errors;
3129 continue;
3130 }
3131 }
3132 res = ioctl(sg_fd, SG_GET_SCSI_ID, &map_arr[k].sg_dat);
3133 if (res < 0) {
3134 snprintf(ebuff, EBUFF_SZ,
3135 "device %s failed on sg ioctl, skip", fname);
3136 perror(ebuff);
3137 ++num_errors;
3138 continue;
3139 }
3140 if (do_inquiry) {
3141 char buff[36];
3142
3143 if (0 ==
3144 do_scsi_inq(sg_fd, 0, 0, 0, buff, sizeof(buff),
3145 1)) {
3146 memcpy(map_arr[k].vendor, &buff[8], 8);
3147 memcpy(map_arr[k].product, &buff[16], 16);
3148 memcpy(map_arr[k].revision, &buff[32], 4);
3149 }
3150 }
3151 map_arr[k].active = 1;
3152 map_arr[k].oth_dev_num = -1;
3153 last_sg_ind = k;
3154 }
3155 if ((num_errors >= MAX_ERRORS) && (num_silent < num_errors)) {
3156 printf("Stopping because there are too many error\n");
3157 if (eacces_err)
3158 printf(" root access may be required\n");
3159 return 1;
3160 }
3161 if (last_sg_ind < 0) {
3162 printf("Stopping because no sg devices found\n");
3163 }
3164
3165 if (do_all_s || do_sd)
3166 scan_dev_type("/dev/sd", MAX_SD_DEVS, 0, LIN_DEV_TYPE_SD,
3167 last_sg_ind);
3168 if (do_all_s || do_sr)
3169 scan_dev_type("/dev/sr", MAX_SR_DEVS, 1, LIN_DEV_TYPE_SR,
3170 last_sg_ind);
3171 if (do_all_s || do_scd)
3172 scan_dev_type("/dev/scd", MAX_SR_DEVS, 1, LIN_DEV_TYPE_SCD,
3173 last_sg_ind);
3174 if (do_all_s || do_st)
3175 scan_dev_type("/dev/st", MAX_ST_DEVS, 1, LIN_DEV_TYPE_ST,
3176 last_sg_ind);
3177 if (do_all_s || do_osst)
3178 scan_dev_type("/dev/osst", MAX_OSST_DEVS, 1, LIN_DEV_TYPE_OSST,
3179 last_sg_ind);
3180
3181 for (k = 0; k <= last_sg_ind; ++k) {
3182 make_dev_name(fname, "/dev/sg", k, do_numeric);
3183 printf("%s", fname);
3184 switch (map_arr[k].active) {
3185 case -2:
3186 printf(do_extra ? " -2 -2 -2 -2 -2" : " busy");
3187 break;
3188 case -1:
3189 printf(do_extra ? " -1 -1 -1 -1 -1" :
3190 " not present");
3191 break;
3192 case 0:
3193 printf(do_extra ? " -3 -3 -3 -3 -3" :
3194 " some error\n");
3195 break;
3196 case 1:
3197 if (do_extra)
3198 printf(" %d %d %d %d %d",
3199 map_arr[k].sg_dat.host_no,
3200 map_arr[k].sg_dat.channel,
3201 map_arr[k].sg_dat.scsi_id,
3202 map_arr[k].sg_dat.lun,
3203 map_arr[k].sg_dat.scsi_type);
3204 switch (map_arr[k].lin_dev_type) {
3205 case LIN_DEV_TYPE_SD:
3206 make_dev_name(fname, "/dev/sd",
3207 map_arr[k].oth_dev_num, 0);
3208 printf(" %s", fname);
3209 break;
3210 case LIN_DEV_TYPE_ST:
3211 make_dev_name(fname, "/dev/st",
3212 map_arr[k].oth_dev_num, 1);
3213 printf(" %s", fname);
3214 break;
3215 case LIN_DEV_TYPE_OSST:
3216 make_dev_name(fname, "/dev/osst",
3217 map_arr[k].oth_dev_num, 1);
3218 printf(" %s", fname);
3219 break;
3220 case LIN_DEV_TYPE_SR:
3221 make_dev_name(fname, "/dev/sr",
3222 map_arr[k].oth_dev_num, 1);
3223 printf(" %s", fname);
3224 break;
3225 case LIN_DEV_TYPE_SCD:
3226 make_dev_name(fname, "/dev/scd",
3227 map_arr[k].oth_dev_num, 1);
3228 printf(" %s", fname);
3229 break;
3230 default:
3231 break;
3232 }
3233 if (do_inquiry)
3234 printf(" %.8s %.16s %.4s", map_arr[k].vendor,
3235 map_arr[k].product, map_arr[k].revision);
3236 break;
3237 default:
3238 printf(" bad logic\n");
3239 break;
3240 }
3241 printf("\n");
3242 }
3243 return 0;
3244 }
3245
find_dev_in_sg_arr(My_scsi_idlun * my_idlun,int host_no,int last_sg_ind)3246 static int find_dev_in_sg_arr(My_scsi_idlun * my_idlun, int host_no,
3247 int last_sg_ind)
3248 {
3249 int k;
3250 struct sg_scsi_id *sidp;
3251
3252 for (k = 0; k <= last_sg_ind; ++k) {
3253 sidp = &(map_arr[k].sg_dat);
3254 if ((host_no == sidp->host_no) &&
3255 ((my_idlun->dev_id & 0xff) == sidp->scsi_id) &&
3256 (((my_idlun->dev_id >> 8) & 0xff) == sidp->lun) &&
3257 (((my_idlun->dev_id >> 16) & 0xff) == sidp->channel))
3258 return k;
3259 }
3260 return -1;
3261 }
3262
scan_dev_type(const char * leadin,int max_dev,int do_numeric,int lin_dev_type,int last_sg_ind)3263 static void scan_dev_type(const char *leadin, int max_dev, int do_numeric,
3264 int lin_dev_type, int last_sg_ind)
3265 {
3266 int k, res, ind, sg_fd = 0;
3267 int num_errors = 0;
3268 int num_silent = 0;
3269 int host_no = -1;
3270 int nonMappedDevicesPresent = FALSE;
3271 My_scsi_idlun my_idlun;
3272 char fname[64];
3273
3274 for (k = 0, res = 0; (k < max_dev) && (num_errors < MAX_ERRORS);
3275 ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) {
3276
3277 /* ignore close() errors */
3278 #if 0
3279 if (res < 0) {
3280 snprintf(ebuff, EBUFF_SZ, "Error closing %s ", fname);
3281 perror("sg_map: close error");
3282 #ifndef IGN_CLOSE_ERR
3283 return;
3284 #else
3285 ++num_errors;
3286 sg_fd = 0;
3287 #endif
3288 }
3289 #endif
3290 make_dev_name(fname, leadin, k, do_numeric);
3291 #ifdef DEBUG
3292 printf("Trying %s: ", fname);
3293 #endif
3294
3295 sg_fd = open(fname, O_RDONLY | O_NONBLOCK);
3296 if (sg_fd < 0) {
3297 #ifdef DEBUG
3298 printf("ERROR %i\n", errno);
3299 #endif
3300 if (EBUSY == errno) {
3301 printf("Device %s is busy\n", fname);
3302 ++num_errors;
3303 continue;
3304 } else if ((ENODEV == errno) || (ENOENT == errno) ||
3305 (ENXIO == errno)) {
3306 ++num_errors;
3307 ++num_silent;
3308 continue;
3309 } else {
3310 snprintf(ebuff, EBUFF_SZ, "Error opening %s ",
3311 fname);
3312 perror(ebuff);
3313 ++num_errors;
3314 continue;
3315 }
3316 }
3317
3318 res = ioctl(sg_fd, SCSI_IOCTL_GET_IDLUN, &my_idlun);
3319 if (res < 0) {
3320 snprintf(ebuff, EBUFF_SZ,
3321 "device %s failed on scsi ioctl(idlun), skip",
3322 fname);
3323 perror(ebuff);
3324 ++num_errors;
3325 #ifdef DEBUG
3326 printf("Couldn't get IDLUN!\n");
3327 #endif
3328 continue;
3329 }
3330 res = ioctl(sg_fd, SCSI_IOCTL_GET_BUS_NUMBER, &host_no);
3331 if (res < 0) {
3332 snprintf(ebuff, EBUFF_SZ,
3333 "device %s failed on scsi ioctl(bus_number), skip",
3334 fname);
3335 perror(ebuff);
3336 ++num_errors;
3337 #ifdef DEBUG
3338 printf("Couldn't get BUS!\n");
3339 #endif
3340 continue;
3341 }
3342 #ifdef DEBUG
3343 printf("%i(%x) %i %i %i %i\n", host_no, my_idlun.host_unique_id,
3344 (my_idlun.dev_id >> 24) & 0xff,
3345 (my_idlun.dev_id >> 16) & 0xff,
3346 (my_idlun.dev_id >> 8) & 0xff, my_idlun.dev_id & 0xff);
3347 #endif
3348 ind = find_dev_in_sg_arr(&my_idlun, host_no, last_sg_ind);
3349 if (ind >= 0) {
3350 map_arr[ind].oth_dev_num = k;
3351 map_arr[ind].lin_dev_type = lin_dev_type;
3352 } else if (ind != -1) {
3353 printf
3354 ("Strange, could not find device %s mapped to sg device error %d??\n",
3355 fname, ind);
3356 } else {
3357 nonMappedDevicesPresent = TRUE;
3358 }
3359 }
3360 if (nonMappedDevicesPresent) {
3361 printf("Unmapped Devices found...\n\n");
3362 }
3363 }
3364
3365 /* Returns 0 when successful, else -1 */
do_simple_inq(int sg_fd,void * resp,int mx_resp_len,int noisy)3366 static int do_simple_inq(int sg_fd, void *resp, int mx_resp_len, int noisy)
3367 {
3368 int res;
3369 unsigned char inqCmdBlk[INQUIRY_CMDLEN] =
3370 { INQUIRY_CMD, 0, 0, 0, 0, 0 };
3371 unsigned char sense_b[SENSE_BUFF_LEN];
3372 sg_io_hdr_t io_hdr;
3373
3374 inqCmdBlk[4] = (unsigned char)mx_resp_len;
3375 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
3376 io_hdr.interface_id = 'S';
3377 io_hdr.cmd_len = sizeof(inqCmdBlk);
3378 io_hdr.mx_sb_len = sizeof(sense_b);
3379 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
3380 io_hdr.dxfer_len = mx_resp_len;
3381 io_hdr.dxferp = resp;
3382 io_hdr.cmdp = inqCmdBlk;
3383 io_hdr.sbp = sense_b;
3384 io_hdr.timeout = DEF_TIMEOUT;
3385
3386 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
3387 perror("SG_IO (inquiry) error");
3388 return -1;
3389 }
3390 res = sg_err_category3(&io_hdr);
3391 switch (res) {
3392 case SG_ERR_CAT_CLEAN:
3393 case SG_ERR_CAT_RECOVERED:
3394 return 0;
3395 default:
3396 if (noisy) {
3397 char ebuff[EBUFF_SZ];
3398 snprintf(ebuff, EBUFF_SZ, "Inquiry error ");
3399 sg_chk_n_print3(ebuff, &io_hdr);
3400 }
3401 return -1;
3402 }
3403 }
3404
do_modes(int sg_fd,int dbd,int pc,int pg_code,int sub_pg_code,void * resp,int mx_resp_len,int noisy,int mode6)3405 static int do_modes(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code,
3406 void *resp, int mx_resp_len, int noisy, int mode6)
3407 {
3408 int res;
3409 unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] =
3410 { MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
3411 unsigned char sense_b[SENSE_BUFF_LEN];
3412 sg_io_hdr_t io_hdr;
3413
3414 modesCmdBlk[1] = (unsigned char)(dbd ? 0x8 : 0);
3415 modesCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
3416 modesCmdBlk[3] = (unsigned char)(sub_pg_code & 0xff);
3417 if (mx_resp_len > (mode6 ? 0xff : 0xffff)) {
3418 printf(ME "mx_resp_len too big\n");
3419 return -1;
3420 }
3421 if (mode6) {
3422 modesCmdBlk[0] = MODE_SENSE6_CMD;
3423 modesCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff);
3424 } else {
3425 modesCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
3426 modesCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff);
3427 }
3428
3429 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
3430 memset(sense_b, 0, sizeof(sense_b));
3431 io_hdr.interface_id = 'S';
3432 io_hdr.cmd_len = mode6 ? MODE_SENSE6_CMDLEN : MODE_SENSE10_CMDLEN;
3433 io_hdr.mx_sb_len = sizeof(sense_b);
3434 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
3435 io_hdr.dxfer_len = mx_resp_len;
3436 io_hdr.dxferp = resp;
3437 io_hdr.cmdp = modesCmdBlk;
3438 io_hdr.sbp = sense_b;
3439 io_hdr.timeout = DEF_TIMEOUT;
3440
3441 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
3442 perror("SG_IO (mode sense) error");
3443 return -1;
3444 }
3445 res = sg_err_category3(&io_hdr);
3446 switch (res) {
3447 case SG_ERR_CAT_CLEAN:
3448 case SG_ERR_CAT_RECOVERED:
3449 return 0;
3450 default:
3451 if (noisy) {
3452 char ebuff[EBUFF_SZ];
3453 snprintf(ebuff, EBUFF_SZ, "Mode sense error, dbd=%d "
3454 "pc=%d page_code=%x sub_page_code=%x\n ",
3455 dbd, pc, pg_code, sub_pg_code);
3456 sg_chk_n_print3(ebuff, &io_hdr);
3457 }
3458 if ((0x70 == (0x7f & sense_b[0])) && (0x20 == sense_b[12]) &&
3459 (0x0 == sense_b[13])) {
3460 if (mode6)
3461 fprintf(stderr,
3462 ">>>>>> drop '-6' switch and try again with "
3463 "a 10 byte MODE SENSE\n");
3464 else
3465 fprintf(stderr,
3466 ">>>>>> add '-6' switch and try again with "
3467 "a 6 byte MODE SENSE\n");
3468 }
3469 return -1;
3470 }
3471 }
3472
3473 const char *scsi_ptype_strs[] = {
3474 "disk",
3475 "tape",
3476 "printer",
3477 "processor",
3478 "write once optical disk",
3479 "cd/dvd",
3480 "scanner",
3481 "optical memory device",
3482 "medium changer",
3483 "communications",
3484 "graphics",
3485 "graphics",
3486 "storage array controller",
3487 "enclosure services device",
3488 "simplified direct access device",
3489 "optical card reader/writer device",
3490 };
3491
get_ptype_str(int scsi_ptype)3492 const char *get_ptype_str(int scsi_ptype)
3493 {
3494 int num = sizeof(scsi_ptype_strs) / sizeof(scsi_ptype_strs[0]);
3495
3496 return (scsi_ptype < num) ? scsi_ptype_strs[scsi_ptype] : "";
3497 }
3498
3499 static struct page_code_desc pc_desc_all[] = {
3500 {0x0, "Unit Attention condition [vendor: page format not required]"},
3501 {0x2, "Disconnect-Reconnect"},
3502 {0xa, "Control"},
3503 {0x15, "Extended"},
3504 {0x16, "Extended device-type specific"},
3505 {0x18, "Protocol specific LUN"},
3506 {0x19, "Protocol specific port"},
3507 {0x1a, "Power condition"},
3508 {0x1c, "Informational exceptions control"},
3509 {0x3f, "[yields all supported pages]"},
3510 };
3511
3512 static struct page_code_desc pc_desc_disk[] = {
3513 {0x1, "Read-Write error recovery"},
3514 {0x3, "Format"},
3515 {0x4, "Rigid disk geometry"},
3516 {0x5, "Flexible geometry"},
3517 {0x7, "Verify error recovery"},
3518 {0x8, "Caching"},
3519 {0x9, "Peripheral device (spc-2 ?)"},
3520 {0xb, "Medium types supported"},
3521 {0xc, "Notch and partition"},
3522 {0xd, "Power condition (obsolete)"},
3523 {0x10, "XOR control"},
3524 };
3525
3526 static struct page_code_desc pc_desc_tape[] = {
3527 {0xf, "Data Compression"},
3528 {0x10, "Device config"},
3529 {0x11, "Medium Partition [1]"},
3530 {0x12, "Medium Partition [2]"},
3531 {0x13, "Medium Partition [3]"},
3532 {0x14, "Medium Partition [4]"},
3533 {0x1c, "Informational exceptions control (tape version)"},
3534 };
3535
3536 static struct page_code_desc pc_desc_cddvd[] = {
3537 {0x1, "Read-Write error recovery"},
3538 {0x3, "MRW"},
3539 {0x5, "Write parameters"},
3540 {0xd, "CD device parameters (obsolete)"},
3541 {0xe, "CD audio"},
3542 {0x1a, "Power condition"},
3543 {0x1c, "Fault/failure reporting control"},
3544 {0x1d, "Timeout and protect"},
3545 {0x2a, "MM capabilities and mechanical status (obsolete)"},
3546 };
3547
3548 static struct page_code_desc pc_desc_smc[] = {
3549 {0x1d, "Element address assignment"},
3550 {0x1e, "Transport geometry parameters"},
3551 {0x1f, "Device capabilities"},
3552 };
3553
3554 static struct page_code_desc pc_desc_scc[] = {
3555 {0x1b, "LUN mapping"},
3556 };
3557
3558 static struct page_code_desc pc_desc_ses[] = {
3559 {0x14, "Enclosure services management"},
3560 };
3561
find_mode_page_table(int scsi_ptype,int * size)3562 struct page_code_desc *find_mode_page_table(int scsi_ptype, int *size)
3563 {
3564 switch (scsi_ptype) {
3565 case 0: /* disk (direct access) type devices */
3566 case 4:
3567 case 7:
3568 case 0xe:
3569 *size = sizeof(pc_desc_disk) / sizeof(pc_desc_disk[0]);
3570 return &pc_desc_disk[0];
3571 case 1: /* tape devices */
3572 case 2:
3573 *size = sizeof(pc_desc_tape) / sizeof(pc_desc_tape[0]);
3574 return &pc_desc_tape[0];
3575 case 5: /* cd/dvd devices */
3576 *size = sizeof(pc_desc_cddvd) / sizeof(pc_desc_cddvd[0]);
3577 return &pc_desc_cddvd[0];
3578 case 8: /* medium changer devices */
3579 *size = sizeof(pc_desc_smc) / sizeof(pc_desc_smc[0]);
3580 return &pc_desc_smc[0];
3581 case 0xc: /* storage array devices */
3582 *size = sizeof(pc_desc_scc) / sizeof(pc_desc_scc[0]);
3583 return &pc_desc_scc[0];
3584 case 0xd: /* enclosure services devices */
3585 *size = sizeof(pc_desc_ses) / sizeof(pc_desc_ses[0]);
3586 return &pc_desc_ses[0];
3587 }
3588 *size = 0;
3589 return NULL;
3590 }
3591
find_page_code_desc(int page_num,int scsi_ptype)3592 const char *find_page_code_desc(int page_num, int scsi_ptype)
3593 {
3594 int k;
3595 int num;
3596 const struct page_code_desc *pcdp;
3597
3598 pcdp = find_mode_page_table(scsi_ptype, &num);
3599 if (pcdp) {
3600 for (k = 0; k < num; ++k, ++pcdp) {
3601 if (page_num == pcdp->page_code)
3602 return pcdp->desc;
3603 else if (page_num < pcdp->page_code)
3604 break;
3605 }
3606 }
3607 pcdp = &pc_desc_all[0];
3608 num = sizeof(pc_desc_all) / sizeof(pc_desc_all[0]);
3609 for (k = 0; k < num; ++k, ++pcdp) {
3610 if (page_num == pcdp->page_code)
3611 return pcdp->desc;
3612 else if (page_num < pcdp->page_code)
3613 break;
3614 }
3615 return NULL;
3616 }
3617
list_page_codes(int scsi_ptype)3618 static void list_page_codes(int scsi_ptype)
3619 {
3620 int k;
3621 int num = sizeof(pc_desc_all) / sizeof(pc_desc_all[0]);
3622 const struct page_code_desc *pcdp = &pc_desc_all[0];
3623 int num_ptype;
3624 const struct page_code_desc *pcd_ptypep;
3625
3626 pcd_ptypep = find_mode_page_table(scsi_ptype, &num_ptype);
3627 printf("Page_Code Description\n");
3628 for (k = 0; k < 0x3f; ++k) {
3629 if (pcd_ptypep && (num_ptype > 0)) {
3630 if (k == pcd_ptypep->page_code) {
3631 printf(" 0x%02x %s\n",
3632 pcd_ptypep->page_code, pcd_ptypep->desc);
3633 ++pcd_ptypep;
3634 --num_ptype;
3635 continue;
3636 } else if (k > pcd_ptypep->page_code) {
3637 pcd_ptypep++;
3638 --num_ptype;
3639 }
3640 }
3641 if (pcdp && (num > 0)) {
3642 if (k == pcdp->page_code) {
3643 printf(" 0x%02x %s\n", pcdp->page_code,
3644 pcdp->desc);
3645 ++pcdp;
3646 --num;
3647 continue;
3648 } else if (k > pcdp->page_code) {
3649 pcdp++;
3650 --num;
3651 }
3652 }
3653 }
3654 }
3655
show_scsi_modes(char * device)3656 int show_scsi_modes(char *device)
3657 {
3658 int sg_fd, k, num, len, md_len, bd_len, longlba, page_num;
3659 char *file_name = 0;
3660 char ebuff[EBUFF_SZ];
3661 const char *descp;
3662 unsigned char rsp_buff[MODE_ALLOC_LEN];
3663 int rsp_buff_size = MODE_ALLOC_LEN;
3664 int pg_code = 0;
3665 int sub_pg_code = 0;
3666 int pc = 0;
3667 int do_all = 1;
3668 int do_dbd = 0;
3669 int do_hex = 0;
3670 int do_mode6 = 0; /* Use MODE SENSE(6) instead of MODE SENSE(10) */
3671 int oflags = O_RDONLY | O_NONBLOCK;
3672 struct sg_scsi_id a_sid;
3673 int scsi_ptype, density_code_off;
3674 unsigned char *ucp;
3675 unsigned char uc;
3676
3677 print_msg(TEST_BREAK, __FUNCTION__);
3678
3679 file_name = device;
3680
3681 list_page_codes(0);
3682
3683 /* The 6 bytes command only allows up to 255 bytes of response data */
3684 if (do_mode6)
3685 rsp_buff_size = 255;
3686
3687 if ((sg_fd = open(file_name, oflags)) < 0) {
3688 snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s",
3689 file_name);
3690 perror(ebuff);
3691 return 1;
3692 }
3693 /* Just to be safe, check we have a new sg device by trying an ioctl */
3694 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
3695 printf(ME "%s doesn't seem to be a version 3 sg device\n",
3696 file_name);
3697 close(sg_fd);
3698 return 1;
3699 }
3700 if (ioctl(sg_fd, SG_GET_SCSI_ID, &a_sid) < 0) {
3701 unsigned char inqBuff[36];
3702
3703 if (do_simple_inq(sg_fd, inqBuff, sizeof(inqBuff), 1)) {
3704 printf(ME "%s doesn't respond to a SCSI INQUIRY\n",
3705 file_name);
3706 close(sg_fd);
3707 return 1;
3708 }
3709 scsi_ptype = inqBuff[0] & 0x1f; /* fetch peripheral device type */
3710 } else
3711 scsi_ptype = a_sid.scsi_type;
3712 printf(" SCSI peripheral type: %s [0x%x] (from INQUIRY)\n",
3713 get_ptype_str(scsi_ptype), scsi_ptype);
3714
3715 if (do_all)
3716 pg_code = MODE_CODE_ALL;
3717
3718 if (0 == do_modes(sg_fd, do_dbd, pc, pg_code, sub_pg_code,
3719 rsp_buff, rsp_buff_size, 1, do_mode6)) {
3720 int medium_type, specific, headerlen;
3721
3722 printf("Mode parameter header from %s byte MODE SENSE:\n",
3723 (do_mode6 ? "6" : "10"));
3724 if (do_mode6) {
3725 headerlen = 4;
3726 if (do_hex)
3727 dStrHex((const char *)rsp_buff, headerlen, 1);
3728 md_len = rsp_buff[0] + 1;
3729 bd_len = rsp_buff[3];
3730 medium_type = rsp_buff[1];
3731 specific = rsp_buff[2];
3732 longlba = 0; /* what is this field? */
3733 } else {
3734 headerlen = 8;
3735 md_len = (rsp_buff[0] << 8) + rsp_buff[1] + 2;
3736 bd_len = (rsp_buff[6] << 8) + rsp_buff[7];
3737 medium_type = rsp_buff[2];
3738 specific = rsp_buff[3];
3739 longlba = rsp_buff[4] & 1;
3740 }
3741 if (do_hex)
3742 dStrHex((const char *)rsp_buff, headerlen, 1);
3743 printf(" Mode data length=%d, medium type=0x%.2x, specific"
3744 " param=0x%.2x, longlba=%d\n", md_len, medium_type,
3745 specific, longlba);
3746 if (md_len > rsp_buff_size) {
3747 printf
3748 ("Only fetched %d bytes of response, truncate output\n",
3749 rsp_buff_size);
3750 md_len = rsp_buff_size;
3751 if (bd_len + headerlen > rsp_buff_size)
3752 bd_len = rsp_buff_size - headerlen;
3753 }
3754 printf(" Block descriptor length=%d\n", bd_len);
3755 if (bd_len > 0) {
3756 len = 8;
3757 density_code_off = 0;
3758 num = bd_len;
3759 if (longlba) {
3760 printf("> longlba block descriptors:\n");
3761 len = 16;
3762 density_code_off = 8;
3763 } else if (0 == scsi_ptype) {
3764 printf
3765 ("> Direct access device block descriptors:\n");
3766 density_code_off = 4;
3767 } else
3768 printf
3769 ("> General mode parameter block descriptors:\n");
3770
3771 ucp = rsp_buff + headerlen;
3772 while (num > 0) {
3773 printf(" Density code=0x%x\n",
3774 *(ucp + density_code_off));
3775 dStrHex((const char *)ucp, len, 1);
3776 ucp += len;
3777 num -= len;
3778 }
3779 printf("\n");
3780 }
3781 ucp = rsp_buff + bd_len + headerlen; /* start of mode page(s) */
3782 md_len -= bd_len + headerlen; /* length of mode page(s) */
3783 while (md_len > 0) { /* got mode page(s) */
3784 uc = *ucp;
3785 page_num = ucp[0] & 0x3f;
3786 if (do_hex)
3787 descp = NULL;
3788 else {
3789 descp =
3790 find_page_code_desc(page_num, scsi_ptype);
3791 if (NULL == descp)
3792 snprintf(ebuff, EBUFF_SZ,
3793 "vendor[0x%x]", page_num);
3794 }
3795 if (uc & 0x40) {
3796 len = (ucp[2] << 8) + ucp[3] + 4;
3797 if (do_hex)
3798 printf
3799 (">> page_code=0x%x, subpage_code=0x%x, "
3800 "page_control=%d\n", page_num,
3801 ucp[1], pc);
3802 else
3803 printf
3804 (">> page_code: %s, subpage_code=0x%x, "
3805 "page_control: %s\n",
3806 (descp ? descp : ebuff), ucp[1],
3807 pg_control_str_arr[pc]);
3808 } else {
3809 len = ucp[1] + 2;
3810 if (do_hex)
3811 printf
3812 (">> page_code=0x%x, page_control=%d\n",
3813 page_num, pc);
3814 else
3815 printf
3816 (">> page_code: %s, page_control: %s\n",
3817 (descp ? descp : ebuff),
3818 pg_control_str_arr[pc]);
3819 }
3820 dStrHex((const char *)ucp, len, 1);
3821 ucp += len;
3822 md_len -= len;
3823 }
3824 }
3825
3826 close(sg_fd);
3827 return 0;
3828 }
3829
do_scsi_read_buffer(char * device)3830 int do_scsi_read_buffer(char *device)
3831 {
3832 int sg_fd, res;
3833 unsigned int k, num;
3834 unsigned char rbCmdBlk[RB_CMD_LEN];
3835 unsigned char *rbBuff = NULL;
3836 void *rawp = NULL;
3837 unsigned char sense_buffer[32];
3838 int buf_capacity = 0;
3839 int do_quick = 0;
3840 int do_dio = 0;
3841 int do_mmap = 1;
3842 int do_time = 0;
3843 int buf_size = 0;
3844 unsigned int total_size_mb = RB_MB_TO_READ;
3845 char *file_name = 0;
3846 size_t psz = getpagesize();
3847 int dio_incomplete = 0;
3848 sg_io_hdr_t io_hdr;
3849 struct timeval start_tm, end_tm;
3850 #ifdef SG_DEBUG
3851 int clear = 1;
3852 #endif
3853
3854 print_msg(TEST_BREAK, __FUNCTION__);
3855
3856 file_name = device;
3857
3858 sg_fd = open(file_name, O_RDONLY);
3859 if (sg_fd < 0) {
3860 perror(ME "open error");
3861 return 1;
3862 }
3863 /* Don't worry, being very careful not to write to a none-sg file ... */
3864 res = ioctl(sg_fd, SG_GET_VERSION_NUM, &k);
3865 if ((res < 0) || (k < 30000)) {
3866 printf(ME "not a sg device, or driver prior to 3.x\n");
3867 return 1;
3868 }
3869 if (do_mmap) {
3870 do_dio = 0;
3871 do_quick = 0;
3872 }
3873 if (NULL == (rawp = malloc(512))) {
3874 printf(ME "out of memory (query)\n");
3875 return 1;
3876 }
3877 rbBuff = rawp;
3878
3879 memset(rbCmdBlk, 0, RB_CMD_LEN);
3880 rbCmdBlk[0] = RB_OPCODE;
3881 rbCmdBlk[1] = RB_MODE_DESC;
3882 rbCmdBlk[8] = RB_DESC_LEN;
3883 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
3884 io_hdr.interface_id = 'S';
3885 io_hdr.cmd_len = sizeof(rbCmdBlk);
3886 io_hdr.mx_sb_len = sizeof(sense_buffer);
3887 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
3888 io_hdr.dxfer_len = RB_DESC_LEN;
3889 io_hdr.dxferp = rbBuff;
3890 io_hdr.cmdp = rbCmdBlk;
3891 io_hdr.sbp = sense_buffer;
3892 io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */
3893 /* do normal IO to find RB size (not dio or mmap-ed at this stage) */
3894
3895 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
3896 perror(ME "SG_IO READ BUFFER descriptor error");
3897 if (rawp)
3898 free(rawp);
3899 return 1;
3900 }
3901
3902 /* now for the error processing */
3903 switch (sg_err_category3(&io_hdr)) {
3904 case SG_ERR_CAT_CLEAN:
3905 break;
3906 case SG_ERR_CAT_RECOVERED:
3907 printf
3908 ("Recovered error on READ BUFFER descriptor, continuing\n");
3909 break;
3910 default: /* won't bother decoding other categories */
3911 sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr);
3912 if (rawp)
3913 free(rawp);
3914 return 1;
3915 }
3916
3917 buf_capacity = ((rbBuff[1] << 16) | (rbBuff[2] << 8) | rbBuff[3]);
3918 printf("READ BUFFER reports: buffer capacity=%d, offset boundary=%d\n",
3919 buf_capacity, (int)rbBuff[0]);
3920
3921 if (0 == buf_size)
3922 buf_size = buf_capacity;
3923 else if (buf_size > buf_capacity) {
3924 printf
3925 ("Requested buffer size=%d exceeds reported capacity=%d\n",
3926 buf_size, buf_capacity);
3927 if (rawp)
3928 free(rawp);
3929 return 1;
3930 }
3931 if (rawp) {
3932 free(rawp);
3933 rawp = NULL;
3934 }
3935
3936 if (!do_dio) {
3937 k = buf_size;
3938 if (do_mmap && (0 != (k % psz)))
3939 k = ((k / psz) + 1) * psz; /* round up to page size */
3940 res = ioctl(sg_fd, SG_SET_RESERVED_SIZE, &k);
3941 if (res < 0)
3942 perror(ME "SG_SET_RESERVED_SIZE error");
3943 }
3944
3945 if (do_mmap) {
3946 rbBuff = mmap(NULL, buf_size, PROT_READ, MAP_SHARED, sg_fd, 0);
3947 if (MAP_FAILED == rbBuff) {
3948 if (ENOMEM == errno)
3949 printf(ME "mmap() out of memory, try a smaller "
3950 "buffer size than %d KB\n",
3951 buf_size / 1024);
3952 else
3953 perror(ME "error using mmap()");
3954 return 1;
3955 }
3956 } else { /* non mmap-ed IO */
3957 rawp = malloc(buf_size + (do_dio ? psz : 0));
3958 if (NULL == rawp) {
3959 printf(ME "out of memory (data)\n");
3960 return 1;
3961 }
3962 if (do_dio) /* align to page boundary */
3963 rbBuff =
3964 (unsigned char *)(((unsigned long)rawp + psz - 1) &
3965 (~(psz - 1)));
3966 else
3967 rbBuff = rawp;
3968 }
3969
3970 num = (total_size_mb * 1024U * 1024U) / (unsigned int)buf_size;
3971 if (do_time) {
3972 start_tm.tv_sec = 0;
3973 start_tm.tv_usec = 0;
3974 gettimeofday(&start_tm, NULL);
3975 }
3976 /* main data reading loop */
3977 for (k = 0; k < num; ++k) {
3978 memset(rbCmdBlk, 0, RB_CMD_LEN);
3979 rbCmdBlk[0] = RB_OPCODE;
3980 rbCmdBlk[1] = RB_MODE_DATA;
3981 rbCmdBlk[6] = 0xff & (buf_size >> 16);
3982 rbCmdBlk[7] = 0xff & (buf_size >> 8);
3983 rbCmdBlk[8] = 0xff & buf_size;
3984 #ifdef SG_DEBUG
3985 memset(rbBuff, 0, buf_size);
3986 #endif
3987
3988 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
3989 io_hdr.interface_id = 'S';
3990 io_hdr.cmd_len = sizeof(rbCmdBlk);
3991 io_hdr.mx_sb_len = sizeof(sense_buffer);
3992 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
3993 io_hdr.dxfer_len = buf_size;
3994 if (!do_mmap)
3995 io_hdr.dxferp = rbBuff;
3996 io_hdr.cmdp = rbCmdBlk;
3997 io_hdr.sbp = sense_buffer;
3998 io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
3999 io_hdr.pack_id = k;
4000 if (do_mmap)
4001 io_hdr.flags |= SG_FLAG_MMAP_IO;
4002 else if (do_dio)
4003 io_hdr.flags |= SG_FLAG_DIRECT_IO;
4004 else if (do_quick)
4005 io_hdr.flags |= SG_FLAG_NO_DXFER;
4006
4007 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
4008 if (ENOMEM == errno)
4009 printf(ME
4010 "SG_IO data; out of memory, try a smaller "
4011 "buffer size than %d KB\n",
4012 buf_size / 1024);
4013 else
4014 perror(ME "SG_IO READ BUFFER data error");
4015 if (rawp)
4016 free(rawp);
4017 return 1;
4018 }
4019
4020 /* now for the error processing */
4021 switch (sg_err_category3(&io_hdr)) {
4022 case SG_ERR_CAT_CLEAN:
4023 break;
4024 case SG_ERR_CAT_RECOVERED:
4025 printf
4026 ("Recovered error on READ BUFFER data, continuing\n");
4027 break;
4028 default: /* won't bother decoding other categories */
4029 sg_chk_n_print3("READ BUFFER data error", &io_hdr);
4030 if (rawp)
4031 free(rawp);
4032 return 1;
4033 }
4034 if (do_dio &&
4035 ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) !=
4036 SG_INFO_DIRECT_IO))
4037 dio_incomplete = 1; /* flag that dio not done (completely) */
4038
4039 #ifdef SG_DEBUG
4040 if (clear) {
4041 for (j = 0; j < buf_size; ++j) {
4042 if (rbBuff[j] != 0) {
4043 clear = 0;
4044 break;
4045 }
4046 }
4047 }
4048 #endif
4049 }
4050 if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
4051 struct timeval res_tm;
4052 double a, b;
4053
4054 gettimeofday(&end_tm, NULL);
4055 res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
4056 res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
4057 if (res_tm.tv_usec < 0) {
4058 --res_tm.tv_sec;
4059 res_tm.tv_usec += 1000000;
4060 }
4061 a = res_tm.tv_sec;
4062 a += (0.000001 * res_tm.tv_usec);
4063 b = (double)buf_size *num;
4064 printf("time to read data from buffer was %d.%06d secs",
4065 (int)res_tm.tv_sec, (int)res_tm.tv_usec);
4066 if ((a > 0.00001) && (b > 511))
4067 printf(", %.2f MB/sec\n", b / (a * 1000000.0));
4068 else
4069 printf("\n");
4070 }
4071 if (dio_incomplete)
4072 printf(">> direct IO requested but not done\n");
4073 printf
4074 ("Read %u MBytes (actual %u MB, %u bytes), buffer size=%d KBytes\n",
4075 total_size_mb, (num * buf_size) / 1048576, num * buf_size,
4076 buf_size / 1024);
4077
4078 if (rawp)
4079 free(rawp);
4080 res = close(sg_fd);
4081 if (res < 0) {
4082 perror(ME "close error");
4083 return 0;
4084 }
4085 #ifdef SG_DEBUG
4086 if (clear)
4087 printf("read buffer always zero\n");
4088 else
4089 printf("read buffer non-zero\n");
4090 #endif
4091 return 0;
4092 }
4093
4094 /* Performs a 10 byte READ CAPACITY command and fetches response. There is
4095 * evidently a 16 byte READ CAPACITY command coming.
4096 * Return of 0 -> success, -1 -> failure */
do_readcap_10(int sg_fd,int pmi,unsigned int lba,unsigned int * last_sect,unsigned int * sect_sz)4097 int do_readcap_10(int sg_fd, int pmi, unsigned int lba,
4098 unsigned int *last_sect, unsigned int *sect_sz)
4099 {
4100 int res;
4101 unsigned char rcCmdBlk[10] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
4102 unsigned char rcBuff[RCAP_REPLY_LEN];
4103 unsigned char sense_b[SENSE_BUFF_SZ];
4104 sg_io_hdr_t io_hdr;
4105
4106 if (pmi) { /* lbs only valid when pmi set */
4107 rcCmdBlk[8] |= 1;
4108 rcCmdBlk[2] = (lba >> 24) & 0xff;
4109 rcCmdBlk[3] = (lba >> 16) & 0xff;
4110 rcCmdBlk[4] = (lba >> 8) & 0xff;
4111 rcCmdBlk[5] = lba & 0xff;
4112 }
4113 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
4114 io_hdr.interface_id = 'S';
4115 io_hdr.cmd_len = sizeof(rcCmdBlk);
4116 io_hdr.mx_sb_len = sizeof(sense_b);
4117 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
4118 io_hdr.dxfer_len = sizeof(rcBuff);
4119 io_hdr.dxferp = rcBuff;
4120 io_hdr.cmdp = rcCmdBlk;
4121 io_hdr.sbp = sense_b;
4122 io_hdr.timeout = 60000;
4123
4124 while (1) {
4125 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
4126 perror("read_capacity (SG_IO) error");
4127 return -1;
4128 }
4129 res = sg_err_category3(&io_hdr);
4130 if (SG_ERR_CAT_MEDIA_CHANGED == res)
4131 continue;
4132 else if (SG_ERR_CAT_CLEAN != res) {
4133 sg_chk_n_print3("READ CAPACITY command error", &io_hdr);
4134 return -1;
4135 } else
4136 break;
4137 }
4138 *last_sect = ((rcBuff[0] << 24) | (rcBuff[1] << 16) |
4139 (rcBuff[2] << 8) | rcBuff[3]);
4140 *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) |
4141 (rcBuff[6] << 8) | rcBuff[7];
4142 return 0;
4143 }
4144
show_scsi_read_capacity(char * device)4145 int show_scsi_read_capacity(char *device)
4146 {
4147 int sg_fd, k, res;
4148 unsigned int lba = 0;
4149 int pmi = 1;
4150 unsigned int last_blk_addr, block_size;
4151 char ebuff[EBUFF_SZ];
4152 const char *file_name = 0;
4153
4154 print_msg(TEST_BREAK, __FUNCTION__);
4155
4156 file_name = device;
4157
4158 if ((0 == pmi) && (lba > 0)) {
4159 fprintf(stderr,
4160 ME "lba can only be non-zero when pmi is set\n");
4161 usage();
4162 return 1;
4163 }
4164 if ((sg_fd = open(file_name, O_RDONLY)) < 0) {
4165 snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s",
4166 file_name);
4167 perror(ebuff);
4168 return 1;
4169 }
4170 /* Just to be safe, check we have a new sg device by trying an ioctl */
4171 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
4172 printf(ME "%s doesn't seem to be a version 3 sg device\n",
4173 file_name);
4174 close(sg_fd);
4175 return 1;
4176 }
4177 res = do_readcap_10(sg_fd, pmi, lba, &last_blk_addr, &block_size);
4178
4179 if (0 == res) {
4180 printf("Read Capacity results:\n");
4181 if (pmi)
4182 printf(" PMI mode: given lba=0x%x, last block before "
4183 "delay=0x%x\n", lba, last_blk_addr);
4184 else
4185 printf
4186 (" Last block address=%u (0x%x), Number of blocks=%u\n",
4187 last_blk_addr, last_blk_addr, last_blk_addr + 1);
4188 printf(" Block size = %u bytes\n", block_size);
4189 }
4190 close(sg_fd);
4191 return 0;
4192 }
4193
do_scsi_reset_devices(char * device,int reset_opt)4194 int do_scsi_reset_devices(char *device, int reset_opt)
4195 {
4196 int sg_fd, res, k;
4197 int do_device_reset = 0;
4198 int do_bus_reset = 0;
4199 int do_host_reset = 0;
4200 char *file_name = 0;
4201
4202 switch (reset_opt) {
4203 case DEVICE_RESET:
4204 print_msg(TEST_BREAK, __FUNCTION__);
4205 do_device_reset = 1;
4206 break;
4207 case HOST_RESET:
4208 do_host_reset = 1;
4209 break;
4210 case BUS_RESET:
4211 do_bus_reset = 1;
4212 break;
4213 }
4214
4215 file_name = device;
4216
4217 sg_fd = open(file_name, O_RDWR | O_NONBLOCK);
4218 if (sg_fd < 0) {
4219 perror("sg_reset: open error");
4220 return 1;
4221 }
4222
4223 k = SG_SCSI_RESET_NOTHING;
4224 if (do_device_reset) {
4225 printf("sg_reset: starting device reset\n");
4226 k = SG_SCSI_RESET_DEVICE;
4227 } else if (do_bus_reset) {
4228 printf("sg_reset: starting bus reset\n");
4229 k = SG_SCSI_RESET_BUS;
4230 } else if (do_host_reset) {
4231 printf("sg_reset: starting host reset\n");
4232 k = SG_SCSI_RESET_HOST;
4233 }
4234
4235 res = ioctl(sg_fd, SG_SCSI_RESET, &k);
4236 if (res < 0) {
4237 if (EBUSY == errno)
4238 printf("sg_reset: BUSY, may be resetting now\n");
4239 else if (EIO == errno)
4240 printf
4241 ("sg_reset: requested type of reset may not be available\n");
4242 else if (EACCES == errno)
4243 printf("sg_reset: reset requires CAP_SYS_ADMIN (root) "
4244 "permission\n");
4245 else if (EINVAL == errno)
4246 printf("sg_reset: SG_SCSI_RESET not supported\n");
4247 else if (EIO == errno)
4248 printf("sg_reset: scsi_reset_provider() call failed\n");
4249 else
4250 perror("sg_reset: SG_SCSI_RESET failed");
4251 return 1;
4252 }
4253 if (SG_SCSI_RESET_NOTHING == k)
4254 printf("sg_reset: did nothing, device is normal mode\n");
4255 else if (SG_SCSI_RESET_DEVICE == k)
4256 printf("sg_reset: completed device reset\n");
4257 else if (SG_SCSI_RESET_BUS == k)
4258 printf("sg_reset: completed bus reset\n");
4259 else if (SG_SCSI_RESET_HOST == k)
4260 printf("sg_reset: completed host reset\n");
4261
4262 if (close(sg_fd) < 0) {
4263 perror("sg_reset: close error");
4264 return 1;
4265 }
4266 return 0;
4267 }
4268
do_senddiag(int sg_fd,int sf_code,int pf_bit,int sf_bit,int devofl_bit,int unitofl_bit,void * outgoing_pg,int outgoing_len,int noisy)4269 static int do_senddiag(int sg_fd, int sf_code, int pf_bit, int sf_bit,
4270 int devofl_bit, int unitofl_bit, void *outgoing_pg,
4271 int outgoing_len, int noisy)
4272 {
4273 int res;
4274 unsigned char senddiagCmdBlk[SEND_DIAGNOSTIC_CMDLEN] =
4275 { SEND_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0 };
4276 unsigned char sense_b[SENSE_BUFF_LEN];
4277 sg_io_hdr_t io_hdr;
4278
4279 senddiagCmdBlk[1] = (unsigned char)((sf_code << 5) | (pf_bit << 4) |
4280 (sf_bit << 2) | (devofl_bit << 1) |
4281 unitofl_bit);
4282 senddiagCmdBlk[3] = (unsigned char)((outgoing_len >> 8) & 0xff);
4283 senddiagCmdBlk[4] = (unsigned char)(outgoing_len & 0xff);
4284
4285 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
4286 io_hdr.interface_id = 'S';
4287 io_hdr.cmd_len = SEND_DIAGNOSTIC_CMDLEN;
4288 io_hdr.mx_sb_len = sizeof(sense_b);
4289 io_hdr.dxfer_direction = outgoing_len ? SG_DXFER_TO_DEV : SG_DXFER_NONE;
4290 io_hdr.dxfer_len = outgoing_len;
4291 io_hdr.dxferp = outgoing_pg;
4292 io_hdr.cmdp = senddiagCmdBlk;
4293 io_hdr.sbp = sense_b;
4294 io_hdr.timeout = LONG_TIMEOUT;
4295
4296 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
4297 perror("SG_IO (send diagnostic) error");
4298 return -1;
4299 }
4300 res = sg_err_category3(&io_hdr);
4301 switch (res) {
4302 case SG_ERR_CAT_CLEAN:
4303 case SG_ERR_CAT_RECOVERED:
4304 return 0;
4305 default:
4306 if (noisy) {
4307 char ebuff[EBUFF_SZ];
4308 snprintf(ebuff, EBUFF_SZ,
4309 "Send diagnostic error, sf_code=0x%x, "
4310 "pf_bit=%d, sf_bit=%d ", sf_code, pf_bit,
4311 sf_bit);
4312 sg_chk_n_print3(ebuff, &io_hdr);
4313 }
4314 return -1;
4315 }
4316 }
4317
do_rcvdiag(int sg_fd,int pcv,int pg_code,void * resp,int mx_resp_len,int noisy)4318 static int do_rcvdiag(int sg_fd, int pcv, int pg_code, void *resp,
4319 int mx_resp_len, int noisy)
4320 {
4321 int res;
4322 unsigned char rcvdiagCmdBlk[RECEIVE_DIAGNOSTIC_CMDLEN] =
4323 { RECEIVE_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0 };
4324 unsigned char sense_b[SENSE_BUFF_LEN];
4325 sg_io_hdr_t io_hdr;
4326
4327 rcvdiagCmdBlk[1] = (unsigned char)(pcv ? 0x1 : 0);
4328 rcvdiagCmdBlk[2] = (unsigned char)(pg_code);
4329 rcvdiagCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff);
4330 rcvdiagCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff);
4331
4332 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
4333 io_hdr.interface_id = 'S';
4334 io_hdr.cmd_len = RECEIVE_DIAGNOSTIC_CMDLEN;
4335 io_hdr.mx_sb_len = sizeof(sense_b);
4336 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
4337 io_hdr.dxfer_len = mx_resp_len;
4338 io_hdr.dxferp = resp;
4339 io_hdr.cmdp = rcvdiagCmdBlk;
4340 io_hdr.sbp = sense_b;
4341 io_hdr.timeout = DEF_TIMEOUT;
4342
4343 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
4344 perror("SG_IO (receive diagnostic) error");
4345 return -1;
4346 }
4347 res = sg_err_category3(&io_hdr);
4348 switch (res) {
4349 case SG_ERR_CAT_CLEAN:
4350 case SG_ERR_CAT_RECOVERED:
4351 return 0;
4352 default:
4353 if (noisy) {
4354 char ebuff[EBUFF_SZ];
4355 snprintf(ebuff, EBUFF_SZ,
4356 "Receive diagnostic error, pcv=%d, "
4357 "page_code=%x ", pcv, pg_code);
4358 sg_chk_n_print3(ebuff, &io_hdr);
4359 }
4360 return -1;
4361 }
4362 }
4363
4364 /* Get last extended self-test time from mode page 0xa (for '-e' option) */
do_modes_0a(int sg_fd,void * resp,int mx_resp_len,int noisy,int mode6)4365 static int do_modes_0a(int sg_fd, void *resp, int mx_resp_len, int noisy,
4366 int mode6)
4367 {
4368 int res;
4369 unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] =
4370 { MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
4371 unsigned char sense_b[SENSE_BUFF_LEN];
4372 sg_io_hdr_t io_hdr;
4373 int dbd = 1;
4374 int pc = 0;
4375 int pg_code = 0xa;
4376
4377 modesCmdBlk[1] = (unsigned char)(dbd ? 0x8 : 0);
4378 modesCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f));
4379 if (mx_resp_len > (mode6 ? 0xff : 0xffff)) {
4380 printf(ME "mx_resp_len too big\n");
4381 return -1;
4382 }
4383 if (mode6) {
4384 modesCmdBlk[0] = MODE_SENSE6_CMD;
4385 modesCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff);
4386 } else {
4387 modesCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff);
4388 modesCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff);
4389 }
4390
4391 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
4392 io_hdr.interface_id = 'S';
4393 io_hdr.cmd_len = mode6 ? MODE_SENSE6_CMDLEN : MODE_SENSE10_CMDLEN;
4394 io_hdr.mx_sb_len = sizeof(sense_b);
4395 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
4396 io_hdr.dxfer_len = mx_resp_len;
4397 io_hdr.dxferp = resp;
4398 io_hdr.cmdp = modesCmdBlk;
4399 io_hdr.sbp = sense_b;
4400 io_hdr.timeout = DEF_TIMEOUT;
4401
4402 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
4403 perror("SG_IO (mode sense) error");
4404 return -1;
4405 }
4406 res = sg_err_category3(&io_hdr);
4407 switch (res) {
4408 case SG_ERR_CAT_CLEAN:
4409 case SG_ERR_CAT_RECOVERED:
4410 return 0;
4411 default:
4412 if (noisy) {
4413 char ebuff[EBUFF_SZ];
4414 snprintf(ebuff, EBUFF_SZ, "Mode sense error, dbd=%d, "
4415 "pc=%d, page_code=%x ", dbd, pc, pg_code);
4416 sg_chk_n_print3(ebuff, &io_hdr);
4417 }
4418 return -1;
4419 }
4420 }
4421
do_scsi_send_diagnostics(char * device)4422 int do_scsi_send_diagnostics(char *device)
4423 {
4424 int sg_fd, k, num, rsp_len;
4425 char *file_name = 0;
4426 unsigned char rsp_buff[MODE_ALLOC_LEN];
4427 int rsp_buff_size = MODE_ALLOC_LEN;
4428 int self_test_code = 6;
4429 int do_pf = 0;
4430 int do_doff = 0;
4431 int do_def_test = 0;
4432 int do_uoff = 0;
4433 int oflags = O_RDWR;
4434
4435 print_msg(TEST_BREAK, __FUNCTION__);
4436
4437 file_name = device;
4438
4439 if ((sg_fd = open(file_name, oflags)) < 0) {
4440 snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s",
4441 file_name);
4442 perror(ebuff);
4443 return 1;
4444 }
4445 /* Just to be safe, check we have a new sg device by trying an ioctl */
4446 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
4447 printf(ME "%s doesn't seem to be a version 3 sg device\n",
4448 file_name);
4449 close(sg_fd);
4450 return 1;
4451 }
4452
4453 if (0 == do_modes_0a(sg_fd, rsp_buff, 32, 1, 0)) {
4454 /* Assume mode sense(10) response without block descriptors */
4455 num = (rsp_buff[0] << 8) + rsp_buff[1] - 6;
4456 if (num >= 0xc) {
4457 int secs;
4458
4459 secs = (rsp_buff[18] << 8) + rsp_buff[19];
4460 printf
4461 ("Previous extended self-test duration=%d seconds "
4462 "(%.2f minutes)\n", secs, secs / 60.0);
4463 } else
4464 printf("Extended self-test duration not available\n");
4465 } else
4466 printf("Extended self-test duration (mode page 0xa) failed\n");
4467
4468 memset(rsp_buff, 0, sizeof(rsp_buff));
4469 if (0 == do_senddiag(sg_fd, 0, do_pf, 0, 0, 0, rsp_buff, 4, 1)) {
4470 if (0 == do_rcvdiag(sg_fd, 0, 0, rsp_buff, rsp_buff_size, 1)) {
4471 printf("Supported diagnostic pages response:\n");
4472 rsp_len = (rsp_buff[2] << 8) + rsp_buff[3] + 4;
4473 for (k = 0; k < (rsp_len - 4); ++k)
4474 printf(" %s\n",
4475 find_page_code_desc(rsp_buff[k + 4], 0));
4476 }
4477 }
4478
4479 if (0 == do_senddiag(sg_fd, self_test_code, do_pf, do_def_test,
4480 do_doff, do_uoff, NULL, 0, 1)) {
4481 if ((5 == self_test_code) || (6 == self_test_code))
4482 printf("Foreground self test returned GOOD status\n");
4483 else if (do_def_test && (!do_doff) && (!do_uoff))
4484 printf("Default self test returned GOOD status\n");
4485 }
4486 close(sg_fd);
4487 return 0;
4488 }
4489
do_start_stop(int fd,int start,int immed,int loej,int power_conditions)4490 static void do_start_stop(int fd, int start, int immed, int loej,
4491 int power_conditions)
4492 {
4493 unsigned char cmdblk[6] = {
4494 START_STOP, /* Command */
4495 0, /* Resvd/Immed */
4496 0, /* Reserved */
4497 0, /* Reserved */
4498 0, /* PowCond/Resvd/LoEj/Start */
4499 0
4500 }; /* Reserved/Flag/Link */
4501 unsigned char sense_b[32];
4502 sg_io_hdr_t io_hdr;
4503 int k, res, debug = 1;
4504
4505 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
4506 cmdblk[1] = immed & 1;
4507 cmdblk[4] = ((power_conditions & 0xf) << 4) |
4508 ((loej & 1) << 1) | (start & 1);
4509 io_hdr.interface_id = 'S';
4510 io_hdr.cmd_len = sizeof(cmdblk);
4511 io_hdr.mx_sb_len = sizeof(sense_b);
4512 io_hdr.dxfer_direction = SG_DXFER_NONE;
4513 io_hdr.dxfer_len = 0;
4514 io_hdr.dxferp = NULL;
4515 io_hdr.cmdp = cmdblk;
4516 io_hdr.sbp = sense_b;
4517 io_hdr.timeout = DEF_START_TIMEOUT;
4518
4519 if (debug) {
4520 printf(" Start/Stop command:");
4521 for (k = 0; k < 6; ++k)
4522 printf(" %02x", cmdblk[k]);
4523 printf("\n");
4524 }
4525
4526 if (ioctl(fd, SG_IO, &io_hdr) < 0) {
4527 perror("start_stop (SG_IO) error");
4528 return;
4529 }
4530 res = sg_err_category3(&io_hdr);
4531 if (SG_ERR_CAT_MEDIA_CHANGED == res) {
4532 fprintf(stderr, "media change report, try start_stop again\n");
4533 if (ioctl(fd, SG_IO, &io_hdr) < 0) {
4534 perror("start_stop (SG_IO) error");
4535 return;
4536 }
4537 }
4538 if (SG_ERR_CAT_CLEAN != res) {
4539 sg_chk_n_print3("start_stop", &io_hdr);
4540 return;
4541 }
4542 if (debug)
4543 fprintf(stderr, "start_stop [%s] successful\n",
4544 start ? "start" : "stop");
4545 }
4546
do_sync_cache(int fd)4547 static void do_sync_cache(int fd)
4548 {
4549 unsigned char cmdblk[10] = {
4550 SYNCHRONIZE_CACHE, /* Command */
4551 0, /* Immed (2) */
4552 0, 0, 0, 0, /* LBA */
4553 0, /* Reserved */
4554 0, 0, /* No of blocks */
4555 0
4556 }; /* Reserved/Flag/Link */
4557 unsigned char sense_b[32];
4558 sg_io_hdr_t io_hdr;
4559 int res, debug = 1;
4560
4561 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
4562 io_hdr.interface_id = 'S';
4563 io_hdr.cmd_len = sizeof(cmdblk);
4564 io_hdr.mx_sb_len = sizeof(sense_b);
4565 io_hdr.dxfer_direction = SG_DXFER_NONE;
4566 io_hdr.dxfer_len = 0;
4567 io_hdr.dxferp = NULL;
4568 io_hdr.cmdp = cmdblk;
4569 io_hdr.sbp = sense_b;
4570 io_hdr.timeout = DEF_START_TIMEOUT;
4571
4572 if (ioctl(fd, SG_IO, &io_hdr) < 0) {
4573 perror("sync_cache (SG_IO) error");
4574 return;
4575 }
4576 res = sg_err_category3(&io_hdr);
4577 if (SG_ERR_CAT_MEDIA_CHANGED == res) {
4578 fprintf(stderr, "media change report, try sync_cache again\n");
4579 if (ioctl(fd, SG_IO, &io_hdr) < 0) {
4580 perror("sync_cache (SG_IO) error");
4581 return;
4582 }
4583 }
4584 if (SG_ERR_CAT_CLEAN != res) {
4585 sg_chk_n_print3("sync_cache", &io_hdr);
4586 return;
4587 }
4588 if (debug)
4589 fprintf(stderr, "synchronize cache successful\n");
4590 }
4591
do_scsi_start_stop(char * device,int startstop)4592 int do_scsi_start_stop(char *device, int startstop)
4593 {
4594 int synccache = 1;
4595 char *file_name = 0;
4596 int fd;
4597 int immed = 1;
4598 int loej = 0;
4599 int power_conds = 0;
4600
4601 print_msg(TEST_BREAK, __FUNCTION__);
4602
4603 file_name = device;
4604
4605 fd = open(file_name, O_RDWR | O_NONBLOCK);
4606 if (fd < 0) {
4607 fprintf(stderr, "Error trying to open %s\n", file_name);
4608 perror("");
4609 usage();
4610 return 2;
4611 }
4612 if (ioctl(fd, SG_GET_TIMEOUT, 0) < 0) {
4613 fprintf(stderr, "Given file not block or SCSI "
4614 "generic device\n");
4615 close(fd);
4616 return 3;
4617 }
4618
4619 if (synccache)
4620 do_sync_cache(fd);
4621
4622 if (power_conds > 0)
4623 do_start_stop(fd, 0, immed, 0, power_conds);
4624 else if (startstop != -1)
4625 do_start_stop(fd, startstop, immed, loej, 0);
4626
4627 close(fd);
4628 return 0;
4629 }
4630
find_out_about_buffer(int sg_fd,int * buf_capacity,char * file_name)4631 int find_out_about_buffer(int sg_fd, int *buf_capacity, char *file_name)
4632 {
4633 int res, buf_granul = 255;
4634 unsigned char *rbBuff = malloc(OFF + sizeof(rbCmdBlk) + 512);
4635 struct sg_header *rsghp = (struct sg_header *)rbBuff;
4636 int rbInLen = OFF + RB_DESC_LEN;
4637 int rbOutLen = OFF + sizeof(rbCmdBlk);
4638 unsigned char *buffp = rbBuff + OFF;
4639 rsghp->pack_len = 0; /* don't care */
4640 rsghp->pack_id = 0;
4641 rsghp->reply_len = rbInLen;
4642 rsghp->twelve_byte = 0;
4643 rsghp->result = 0;
4644 #ifndef SG_GET_RESERVED_SIZE
4645 rsghp->sense_buffer[0] = 0;
4646 #endif
4647 memcpy(rbBuff + OFF, rbCmdBlk, sizeof(rbCmdBlk));
4648 rbBuff[OFF + 1] = RB_MODE_DESC;
4649 rbBuff[OFF + 8] = RB_DESC_LEN;
4650
4651 res = write(sg_fd, rbBuff, rbOutLen);
4652 if (res < 0) {
4653 perror("sg_test_rwbuf: write (desc) error");
4654 if (rbBuff)
4655 free(rbBuff);
4656 return 1;
4657 }
4658 if (res < rbOutLen) {
4659 printf("sg_test_rwbuf: wrote less (desc), ask=%d, got=%d\n",
4660 rbOutLen, res);
4661 if (rbBuff)
4662 free(rbBuff);
4663 return 1;
4664 }
4665
4666 memset(rbBuff + OFF, 0, RB_DESC_LEN);
4667 res = read(sg_fd, rbBuff, rbInLen);
4668 if (res < 0) {
4669 perror("sg_test_rwbuf: read (desc) error");
4670 if (rbBuff)
4671 free(rbBuff);
4672 return 1;
4673 }
4674 if (res < rbInLen) {
4675 printf("sg_test_rwbuf: read less (desc), ask=%d, got=%d\n",
4676 rbInLen, res);
4677 if (rbBuff)
4678 free(rbBuff);
4679 return 1;
4680 }
4681 #ifdef SG_GET_RESERVED_SIZE
4682 if (!sg_chk_n_print("sg_test_rwbuf: desc", rsghp->target_status,
4683 rsghp->host_status, rsghp->driver_status,
4684 rsghp->sense_buffer, SG_MAX_SENSE)) {
4685 printf
4686 ("sg_test_rwbuf: perhaps %s doesn't support READ BUFFER\n",
4687 file_name);
4688 if (rbBuff)
4689 free(rbBuff);
4690 return 1;
4691 }
4692 #else
4693 if ((rsghp->result != 0) || (0 != rsghp->sense_buffer[0])) {
4694 printf("sg_test_rwbuf: read(desc) result=%d\n", rsghp->result);
4695 if (0 != rsghp->sense_buffer[0])
4696 sg_print_sense("sg_test_rwbuf: desc",
4697 rsghp->sense_buffer, SG_MAX_SENSE);
4698 printf
4699 ("sg_test_rwbuf: perhaps %s doesn't support READ BUFFER\n",
4700 file_name);
4701 if (rbBuff)
4702 free(rbBuff);
4703 return 1;
4704 }
4705 #endif
4706 *(buf_capacity) = ((buffp[1] << 16) | (buffp[2] << 8) | buffp[3]);
4707 buf_granul = (unsigned char)buffp[0];
4708
4709 printf("READ BUFFER reports: %02x %02x %02x %02x %02x %02x %02x %02x\n",
4710 buffp[0], buffp[1], buffp[2], buffp[3],
4711 buffp[4], buffp[5], buffp[6], buffp[7]);
4712
4713 printf("READ BUFFER reports: buffer capacity=%d, offset boundary=%d\n",
4714 *(buf_capacity), buf_granul);
4715 #ifdef SG_DEF_RESERVED_SIZE
4716 res = ioctl(sg_fd, SG_SET_RESERVED_SIZE, buf_capacity);
4717 if (res < 0)
4718 perror("sg_test_rwbuf: SG_SET_RESERVED_SIZE error");
4719 #endif
4720 return 0;
4721 }
4722
mymemcmp(unsigned char * bf1,unsigned char * bf2,int len)4723 int mymemcmp(unsigned char *bf1, unsigned char *bf2, int len)
4724 {
4725 int df;
4726 for (df = 0; df < len; df++)
4727 if (bf1[df] != bf2[df])
4728 return df;
4729 return 0;
4730 }
4731
do_checksum(int * buf,int len,int quiet)4732 int do_checksum(int *buf, int len, int quiet)
4733 {
4734 int sum = base;
4735 int i;
4736 int rln = len;
4737 for (i = 0; i < len / BPI; i++)
4738 sum += buf[i];
4739 while (rln % BPI)
4740 sum += ((char *)buf)[--rln];
4741 if (sum != READWRITE_BASE_NUM) {
4742 if (!quiet)
4743 printf("sg_test_rwbuf: Checksum error (sz=%i): %08x\n",
4744 len, sum);
4745 if (cmpbuf && !quiet) {
4746 int diff = mymemcmp(cmpbuf, (unsigned char *)buf, len);
4747 printf("Differ at pos %i/%i:\n", diff, len);
4748 for (i = 0; i < 24 && i + diff < len; i++)
4749 printf(" %02x", cmpbuf[i + diff]);
4750 printf("\n");
4751 for (i = 0; i < 24 && i + diff < len; i++)
4752 printf(" %02x",
4753 ((unsigned char *)buf)[i + diff]);
4754 printf("\n");
4755 }
4756 return 2;
4757 } else
4758 return 0;
4759 }
4760
do_fill_buffer(int * buf,int len)4761 void do_fill_buffer(int *buf, int len)
4762 {
4763 int sum;
4764 int i;
4765 int rln = len;
4766 srand(time(0));
4767 retry:
4768 if (len >= BPI)
4769 base = READWRITE_BASE_NUM + rand();
4770 else
4771 base = READWRITE_BASE_NUM + (char)rand();
4772 sum = base;
4773 for (i = 0; i < len / BPI - 1; i++) {
4774 /* we rely on rand() giving full range of int */
4775 buf[i] = rand();
4776 sum += buf[i];
4777 }
4778 while (rln % BPI) {
4779 ((char *)buf)[--rln] = rand();
4780 sum += ((char *)buf)[rln];
4781 }
4782 if (len >= BPI)
4783 buf[len / BPI - 1] = READWRITE_BASE_NUM - sum;
4784 else
4785 ((char *)buf)[0] = READWRITE_BASE_NUM + ((char *)buf)[0] - sum;
4786 if (do_checksum(buf, len, 1)) {
4787 if (len < BPI)
4788 goto retry;
4789 printf("sg_test_rwbuf: Memory corruption?\n");
4790 exit(1);
4791 }
4792 if (cmpbuf)
4793 memcpy(cmpbuf, (char *)buf, len);
4794 }
4795
read_buffer(int sg_fd,unsigned size)4796 int read_buffer(int sg_fd, unsigned size)
4797 {
4798 int res;
4799 unsigned char *rbBuff = malloc(OFF + sizeof(rbCmdBlk) + size);
4800 struct sg_header *rsghp = (struct sg_header *)rbBuff;
4801
4802 int rbInLen = OFF + size;
4803 int rbOutLen = OFF + sizeof(rbCmdBlk);
4804 memset(rbBuff, 0, OFF + sizeof(rbCmdBlk) + size);
4805 rsghp->pack_len = 0; /* don't care */
4806 rsghp->reply_len = rbInLen;
4807 rsghp->twelve_byte = 0;
4808 rsghp->result = 0;
4809 memcpy(rbBuff + OFF, rbCmdBlk, sizeof(rbCmdBlk));
4810 rbBuff[OFF + 1] = RB_MODE_DATA;
4811 rbBuff[OFF + 6] = 0xff & ((size) >> 16);
4812 rbBuff[OFF + 7] = 0xff & ((size) >> 8);
4813 rbBuff[OFF + 8] = 0xff & (size);
4814
4815 rsghp->pack_id = 2;
4816 res = write(sg_fd, rbBuff, rbOutLen);
4817 if (res < 0) {
4818 perror("sg_test_rwbuf: write (data) error");
4819 if (rbBuff)
4820 free(rbBuff);
4821 return 1;
4822 }
4823 if (res < rbOutLen) {
4824 printf("sg_test_rwbuf: wrote less (data), ask=%d, got=%d\n",
4825 rbOutLen, res);
4826 if (rbBuff)
4827 free(rbBuff);
4828 return 1;
4829 }
4830
4831 res = read(sg_fd, rbBuff, rbInLen);
4832 if (res < 0) {
4833 perror("sg_test_rwbuf: read (data) error");
4834 if (rbBuff)
4835 free(rbBuff);
4836 return 1;
4837 }
4838 if (res < rbInLen) {
4839 printf("sg_test_rwbuf: read less (data), ask=%d, got=%d\n",
4840 rbInLen, res);
4841 if (rbBuff)
4842 free(rbBuff);
4843 return 1;
4844 }
4845 res = do_checksum((int *)(rbBuff + OFF), size, 0);
4846 if (rbBuff)
4847 free(rbBuff);
4848 return res;
4849 }
4850
write_buffer(int sg_fd,unsigned size)4851 int write_buffer(int sg_fd, unsigned size)
4852 {
4853 int res;
4854 unsigned char *rbBuff = malloc(OFF + sizeof(rbCmdBlk) + size);
4855 struct sg_header *rsghp = (struct sg_header *)rbBuff;
4856 //unsigned char * buffp = rbBuff + OFF;
4857
4858 int rbInLen = OFF;
4859 int rbOutLen = OFF + sizeof(rbCmdBlk) + size;
4860
4861 do_fill_buffer((int *)(rbBuff + OFF + sizeof(rbCmdBlk)), size);
4862 rsghp->pack_len = 0; /* don't care */
4863 rsghp->reply_len = rbInLen;
4864 rsghp->twelve_byte = 0;
4865 rsghp->result = 0;
4866 memcpy(rbBuff + OFF, rbCmdBlk, sizeof(rbCmdBlk));
4867 rbBuff[OFF + 0] = WRITE_BUFFER;
4868 rbBuff[OFF + 1] = RB_MODE_DATA;
4869 rbBuff[OFF + 6] = 0xff & ((size) >> 16);
4870 rbBuff[OFF + 7] = 0xff & ((size) >> 8);
4871 rbBuff[OFF + 8] = 0xff & (size);
4872
4873 rsghp->pack_id = 1;
4874 res = write(sg_fd, rbBuff, rbOutLen);
4875 if (res < 0) {
4876 perror("sg_test_rwbuf: write (data) error");
4877 if (rbBuff)
4878 free(rbBuff);
4879 return 1;
4880 }
4881 if (res < rbOutLen) {
4882 printf("sg_test_rwbuf: wrote less (data), ask=%d, got=%d\n",
4883 rbOutLen, res);
4884 if (rbBuff)
4885 free(rbBuff);
4886 return 1;
4887 }
4888
4889 res = read(sg_fd, rbBuff, rbInLen);
4890 if (res < 0) {
4891 perror("sg_test_rwbuf: read (status) error");
4892 if (rbBuff)
4893 free(rbBuff);
4894 return 1;
4895 }
4896 if (rbBuff)
4897 free(rbBuff);
4898 return 0;
4899 }
4900
do_scsi_read_write_buffer(char * device)4901 int do_scsi_read_write_buffer(char *device)
4902 {
4903 int sg_fd;
4904 int res, buf_capacity;
4905 char *file_name = device;
4906 struct stat a_st;
4907 int block_dev = 0;
4908
4909 print_msg(TEST_BREAK, __FUNCTION__);
4910
4911 sg_fd = open(file_name, O_RDWR);
4912 if (sg_fd < 0) {
4913 perror("sg_test_rwbuf: open error");
4914 return 1;
4915 }
4916 if (fstat(sg_fd, &a_st) < 0) {
4917 fprintf(stderr, "could do fstat() on fd ??\n");
4918 close(sg_fd);
4919 return 1;
4920 }
4921 if (S_ISBLK(a_st.st_mode))
4922 block_dev = 1;
4923 /* Don't worry, being very careful not to write to a none-sg file ... */
4924 if (block_dev || (ioctl(sg_fd, SG_GET_TIMEOUT, 0) < 0)) {
4925 /* perror("ioctl on generic device, error"); */
4926 printf("sg_test_rwbuf: not a sg device, or wrong driver\n");
4927 return 1;
4928 }
4929 if (find_out_about_buffer(sg_fd, &buf_capacity, file_name))
4930 return 1;
4931
4932 cmpbuf = malloc(buf_capacity);
4933 if (write_buffer(sg_fd, buf_capacity))
4934 return 3;
4935 res = read_buffer(sg_fd, buf_capacity);
4936 if (res)
4937 return (res + 4);
4938
4939 res = close(sg_fd);
4940 if (res < 0) {
4941 perror("sg_test_rwbuf: close error");
4942 return 6;
4943 }
4944 printf("Success\n");
4945 return 0;
4946 }
4947
do_scsi_test_unit_ready(char * device)4948 int do_scsi_test_unit_ready(char *device)
4949 {
4950 int sg_fd, k;
4951 unsigned char turCmdBlk[TUR_CMD_LEN] = { 0x00, 0, 0, 0, 0, 0 };
4952 sg_io_hdr_t io_hdr;
4953 char *file_name = device;
4954 char ebuff[EBUFF_SZ];
4955 unsigned char sense_buffer[32];
4956 int num_turs = 10240;
4957 int num_errs = 0;
4958 int do_time = 1;
4959 struct timeval start_tm, end_tm;
4960
4961 print_msg(TEST_BREAK, __FUNCTION__);
4962
4963 if ((sg_fd = open(file_name, O_RDONLY)) < 0) {
4964 snprintf(ebuff, EBUFF_SZ,
4965 "sg_turs: error opening file: %s", file_name);
4966 perror(ebuff);
4967 return 1;
4968 }
4969 /* Just to be safe, check we have a new sg driver by trying an ioctl */
4970 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
4971 printf
4972 ("sg_turs: %s isn't an sg device (or the sg driver is old)\n",
4973 file_name);
4974 close(sg_fd);
4975 return 1;
4976 }
4977 /* Prepare TEST UNIT READY command */
4978 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
4979 io_hdr.interface_id = 'S';
4980 io_hdr.cmd_len = sizeof(turCmdBlk);
4981 io_hdr.mx_sb_len = sizeof(sense_buffer);
4982 io_hdr.dxfer_direction = SG_DXFER_NONE;
4983 io_hdr.cmdp = turCmdBlk;
4984 io_hdr.sbp = sense_buffer;
4985 io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
4986 if (do_time) {
4987 start_tm.tv_sec = 0;
4988 start_tm.tv_usec = 0;
4989 gettimeofday(&start_tm, NULL);
4990 }
4991 for (k = 0; k < num_turs; ++k) {
4992 io_hdr.pack_id = k;
4993 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
4994 perror("sg_turs: Test Unit Ready SG_IO ioctl error");
4995 close(sg_fd);
4996 return 1;
4997 }
4998 if (io_hdr.info & SG_INFO_OK_MASK) {
4999 ++num_errs;
5000 if (1 == num_turs) { /* then print out the error message */
5001 if (SG_ERR_CAT_CLEAN !=
5002 sg_err_category3(&io_hdr))
5003 sg_chk_n_print3("tur", &io_hdr);
5004 }
5005 }
5006 }
5007 if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
5008 struct timeval res_tm;
5009 double a, b;
5010
5011 gettimeofday(&end_tm, NULL);
5012 res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
5013 res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
5014 if (res_tm.tv_usec < 0) {
5015 --res_tm.tv_sec;
5016 res_tm.tv_usec += 1000000;
5017 }
5018 a = res_tm.tv_sec;
5019 a += (0.000001 * res_tm.tv_usec);
5020 b = (double)num_turs;
5021 printf("time to perform commands was %d.%06d secs",
5022 (int)res_tm.tv_sec, (int)res_tm.tv_usec);
5023 if (a > 0.00001)
5024 printf("; %.2f operations/sec\n", b / a);
5025 else
5026 printf("\n");
5027 }
5028
5029 printf("Completed %d Test Unit Ready commands with %d errors\n",
5030 num_turs, num_errs);
5031 close(sg_fd);
5032 return 0;
5033 }
5034
5035 /* Returns 0 -> ok, 1 -> err, 2 -> recovered error */
do_sg_io(int sg_fd,unsigned char * buff)5036 static int do_sg_io(int sg_fd, unsigned char *buff)
5037 {
5038 /* N.B. Assuming buff contains pointer 'buffer' or 'buffer1' */
5039 struct sg_header *sghp = (struct sg_header *)(buff - OFF);
5040 int res;
5041
5042 sghp->pack_len = 0;
5043 sghp->reply_len = SG_HSZ + *(((int *)buff) + 1);
5044 sghp->pack_id = 0;
5045 sghp->twelve_byte = 0;
5046 sghp->other_flags = 0;
5047 #ifndef SG_GET_RESERVED_SIZE
5048 sghp->sense_buffer[0] = 0;
5049 #endif
5050 #if 0
5051 sg_print_command(buff + 8);
5052 printf(" write_len=%d, read_len=%d\n",
5053 SG_HSZ + sg_get_command_size(buff[8]) + *((int *)buff),
5054 sghp->reply_len);
5055 #endif
5056 res = write(sg_fd, (const void *)sghp,
5057 SG_HSZ + sg_get_command_size(buff[8]) + *((int *)buff));
5058 if (res < 0) {
5059 #ifdef SG_IO_DEBUG
5060 perror("write to sg failed");
5061 #endif
5062 return 1;
5063 }
5064 res = read(sg_fd, (void *)sghp, sghp->reply_len);
5065 if (res < 0) {
5066 #ifdef SG_IO_DEBUG
5067 perror("read from sg failed");
5068 #endif
5069 return 1;
5070 }
5071 #ifdef SG_GET_RESERVED_SIZE
5072 res = sg_err_category(sghp->target_status, sghp->host_status,
5073 sghp->driver_status, sghp->sense_buffer,
5074 SG_MAX_SENSE);
5075 switch (res) {
5076 case SG_ERR_CAT_CLEAN:
5077 return 0;
5078 case SG_ERR_CAT_RECOVERED:
5079 return 2;
5080 default:
5081 #ifdef SG_IO_DEBUG
5082 sg_chk_n_print("read from sg", sghp->target_status,
5083 sghp->host_status, sghp->driver_status,
5084 sghp->sense_buffer, SG_MAX_SENSE);
5085 #endif
5086 return 1;
5087 }
5088 #else
5089 if (0 != sghp->sense_buffer[0]) {
5090 #ifdef SG_IO_DEBUG
5091 int k;
5092 printf("read from sg, sense buffer (in hex):\n ");
5093 for (k = 0; k < 16; ++k)
5094 printf("%02x ", (int)sghp->sense_buffer[k]);
5095 printf("\n");
5096 #endif
5097 return 1;
5098 } else if (0 != sghp->result) {
5099 #ifdef SG_IO_DEBUG
5100 printf("read from sg, bad result=%d\n", sghp->result);
5101 #endif
5102 return 1;
5103 } else
5104 return 0;
5105 #endif
5106 }
5107
get_page_name(int pageno)5108 static char *get_page_name(int pageno)
5109 {
5110 if ((pageno <= 0) || (pageno >= MAX_PAGENO) || (!page_names[pageno]))
5111 return "Mode";
5112 return page_names[pageno];
5113 }
5114
getnbyte(unsigned char * pnt,int nbyte)5115 static int getnbyte(unsigned char *pnt, int nbyte)
5116 {
5117 unsigned int result;
5118 int i;
5119 result = 0;
5120 for (i = 0; i < nbyte; i++)
5121 result = (result << 8) | (pnt[i] & 0xff);
5122 return result;
5123 }
5124
bitfield(unsigned char * pageaddr,char * text,int mask,int shift)5125 static void bitfield(unsigned char *pageaddr, char *text, int mask, int shift)
5126 {
5127 printf("%-35s%d\n", text, (*pageaddr >> shift) & mask);
5128 }
5129
notbitfield(unsigned char * pageaddr,char * text,int mask,int shift)5130 static void notbitfield(unsigned char *pageaddr, char *text, int mask,
5131 int shift)
5132 {
5133 printf("%-35s%d\n", text, !((*pageaddr >> shift) & mask));
5134 }
5135
intfield(unsigned char * pageaddr,int nbytes,char * text)5136 static void intfield(unsigned char *pageaddr, int nbytes, char *text)
5137 {
5138 printf("%-35s%d\n", text, getnbyte(pageaddr, nbytes));
5139 }
5140
hexfield(unsigned char * pageaddr,int nbytes,char * text)5141 static void hexfield(unsigned char *pageaddr, int nbytes, char *text)
5142 {
5143 printf("%-35s0x%x\n", text, getnbyte(pageaddr, nbytes));
5144 }
5145
hexdatafield(unsigned char * pageaddr,int nbytes,char * text)5146 static void hexdatafield(unsigned char *pageaddr, int nbytes, char *text)
5147 {
5148 printf("%-35s0x", text);
5149 while (nbytes-- > 0)
5150 printf("%02x", *pageaddr++);
5151 putchar('\n');
5152 }
5153
get_mode_page(int page,int page_code)5154 static int get_mode_page(int page, int page_code)
5155 {
5156 int status, quiet;
5157 unsigned char *cmd;
5158
5159 memset(buffer, 0, SIZEOF_BUFFER);
5160
5161 quiet = page_code & ~3;
5162 page_code &= 3;
5163
5164 *((int *)buffer) = 0; /* length of input data */
5165 *(((int *)buffer) + 1) = 0xff; /* length of output data */
5166
5167 cmd = (unsigned char *)(((int *)buffer) + 2);
5168
5169 cmd[0] = MODE_SENSE; /* MODE SENSE (6) */
5170 cmd[1] = 0x00; /* lun = 0, inhibitting BD makes this fail
5171 for me */
5172 cmd[2] = (page_code << 6) | page;
5173 cmd[3] = 0x00; /* (reserved) */
5174 cmd[4] = (unsigned char)0xff; /* allocation length */
5175 cmd[5] = 0x00; /* control */
5176
5177 status = do_sg_io(glob_fd, buffer);
5178 if (status && (!quiet))
5179 fprintf(stdout, ">>> Unable to read %s Page %02xh\n",
5180 get_page_name(page), page);
5181 //dump (buffer+2, 46);
5182 return status;
5183 }
5184
5185 /* Same as above, but this time with MODE_SENSE_10 */
get_mode_page10(int page,int page_code)5186 static int get_mode_page10(int page, int page_code)
5187 {
5188 int status, quiet;
5189 unsigned char *cmd;
5190
5191 memset(buffer, 0, SIZEOF_BUFFER);
5192
5193 quiet = page_code & ~3;
5194 page_code &= 3;
5195
5196 *((int *)buffer) = 0; /* length of input data */
5197 *(((int *)buffer) + 1) = 0xffff; /* length of output buffer */
5198
5199 cmd = (unsigned char *)(((int *)buffer) + 2);
5200
5201 cmd[0] = MODE_SENSE_10; /* MODE SENSE (10) */
5202 cmd[1] = 0x00; /* lun = 0, inhibitting BD makes this fail
5203 for me */
5204 cmd[2] = (page_code << 6) | page;
5205 cmd[3] = 0x00; /* (reserved) */
5206 cmd[4] = 0x00; /* (reserved) */
5207 cmd[5] = 0x00; /* (reserved) */
5208 cmd[6] = 0x00; /* (reserved) */
5209 cmd[7] = 0xff; /* allocation length hi */
5210 cmd[8] = 0xff; /* allocation length lo */
5211 cmd[9] = 0x00; /* control */
5212
5213 status = do_sg_io(glob_fd, buffer);
5214 if (status && (!quiet))
5215 fprintf(stdout,
5216 ">>> Unable to read %s Page %02xh with MODESENSE(10)\n",
5217 get_page_name(page), page);
5218 return status;
5219 }
5220
5221 /* Contents should point to the mode parameter header that we obtained
5222 in a prior read operation. This way we do not have to work out the
5223 format of the beast */
5224
read_geometry(int page_code)5225 static int read_geometry(int page_code)
5226 {
5227 int status;
5228 int bdlen;
5229 unsigned char *pagestart;
5230
5231 SETUP_MODE_PAGE(4, 9);
5232
5233 printf("Data from Rigid Disk Drive Geometry Page\n");
5234 printf("----------------------------------------\n");
5235 intfield(pagestart + 2, 3, "Number of cylinders");
5236 intfield(pagestart + 5, 1, "Number of heads");
5237 intfield(pagestart + 6, 3, "Starting write precomp");
5238 intfield(pagestart + 9, 3, "Starting reduced current");
5239 intfield(pagestart + 12, 2, "Drive step rate");
5240 intfield(pagestart + 14, 3, "Landing Zone Cylinder");
5241 bitfield(pagestart + 17, "RPL", 3, 0);
5242 intfield(pagestart + 18, 1, "Rotational Offset");
5243 intfield(pagestart + 20, 2, "Rotational Rate");
5244 printf("\n");
5245 return 0;
5246
5247 }
5248
read_disconnect_reconnect_data(int page_code)5249 static int read_disconnect_reconnect_data(int page_code)
5250 {
5251 int status;
5252 int bdlen;
5253 unsigned char *pagestart;
5254
5255 SETUP_MODE_PAGE(2, 7);
5256
5257 printf("Data from Disconnect-Reconnect Page\n");
5258 printf("-----------------------------------\n");
5259 intfield(pagestart + 2, 1, "Buffer full ratio");
5260 intfield(pagestart + 3, 1, "Buffer empty ratio");
5261 intfield(pagestart + 4, 2, "Bus Inactivity Limit");
5262 intfield(pagestart + 6, 2, "Disconnect Time Limit");
5263 intfield(pagestart + 8, 2, "Connect Time Limit");
5264 intfield(pagestart + 10, 2, "Maximum Burst Size");
5265 hexfield(pagestart + 12, 1, "DTDC");
5266 printf("\n");
5267 return 0;
5268
5269 }
5270
read_control_page(int page_code)5271 static int read_control_page(int page_code)
5272 {
5273 int status;
5274 int bdlen;
5275 unsigned char *pagestart;
5276
5277 SETUP_MODE_PAGE(10, 9);
5278
5279 printf("Data from Control Page\n");
5280 printf("----------------------\n");
5281 bitfield(pagestart + 2, "RLEC", 1, 0);
5282 bitfield(pagestart + 3, "QErr", 1, 1);
5283 bitfield(pagestart + 3, "DQue", 1, 0);
5284 bitfield(pagestart + 4, "EECA", 1, 7);
5285 bitfield(pagestart + 4, "RAENP", 1, 2);
5286 bitfield(pagestart + 4, "UUAENP", 1, 1);
5287 bitfield(pagestart + 4, "EAENP", 1, 0);
5288 bitfield(pagestart + 3, "Queue Algorithm Modifier", 0xf, 4);
5289 intfield(pagestart + 6, 2, "Ready AEN Holdoff Period");
5290 printf("\n");
5291 return 0;
5292
5293 }
5294
error_recovery_page(int page_code)5295 static int error_recovery_page(int page_code)
5296 {
5297 int status;
5298 int bdlen;
5299 unsigned char *pagestart;
5300
5301 SETUP_MODE_PAGE(1, 14);
5302 printf("Data from Error Recovery Page\n");
5303 printf("-----------------------------\n");
5304 bitfield(pagestart + 2, "AWRE", 1, 7);
5305 bitfield(pagestart + 2, "ARRE", 1, 6);
5306 bitfield(pagestart + 2, "TB", 1, 5);
5307 bitfield(pagestart + 2, "RC", 1, 4);
5308 bitfield(pagestart + 2, "EER", 1, 3);
5309 bitfield(pagestart + 2, "PER", 1, 2);
5310 bitfield(pagestart + 2, "DTE", 1, 1);
5311 bitfield(pagestart + 2, "DCR", 1, 0);
5312 intfield(pagestart + 3, 1, "Read Retry Count");
5313 intfield(pagestart + 4, 1, "Correction Span");
5314 intfield(pagestart + 5, 1, "Head Offset Count");
5315 intfield(pagestart + 6, 1, "Data Strobe Offset Count");
5316 intfield(pagestart + 8, 1, "Write Retry Count");
5317 intfield(pagestart + 10, 2, "Recovery Time Limit");
5318 printf("\n");
5319 return 0;
5320 }
5321
notch_parameters_page(int page_code)5322 static int notch_parameters_page(int page_code)
5323 {
5324 int status;
5325 int bdlen;
5326 unsigned char *pagestart;
5327
5328 SETUP_MODE_PAGE(0xc, 7);
5329
5330 printf("Data from Notch Parameters Page\n");
5331 printf("-------------------------------\n");
5332 bitfield(pagestart + 2, "Notched Drive", 1, 7);
5333 bitfield(pagestart + 2, "Logical or Physical Notch", 1, 6);
5334 intfield(pagestart + 4, 2, "Max # of notches");
5335 intfield(pagestart + 6, 2, "Active Notch");
5336 if (pagestart[2] & 0x40) {
5337 intfield(pagestart + 8, 4, "Starting Boundary");
5338 intfield(pagestart + 12, 4, "Ending Boundary");
5339 } else { /* Hex is more meaningful for physical notches */
5340 hexfield(pagestart + 8, 4, "Starting Boundary");
5341 hexfield(pagestart + 12, 4, "Ending Boundary");
5342 }
5343
5344 printf("0x%8.8x%8.8x", getnbyte(pagestart + 16, 4),
5345 getnbyte(pagestart + 20, 4));
5346
5347 printf("\n");
5348 return 0;
5349 }
5350
formatname(int format)5351 static char *formatname(int format)
5352 {
5353 switch (format) {
5354 case 0x0:
5355 return "logical blocks";
5356 case 0x4:
5357 return "bytes from index [Cyl:Head:Off]\n"
5358 "Offset -1 marks whole track as bad.\n";
5359 case 0x5:
5360 return "physical blocks [Cyl:Head:Sect]\n"
5361 "Sector -1 marks whole track as bad.\n";
5362 }
5363 return "Weird, unknown format";
5364 }
5365
read_defect_list(int page_code)5366 static int read_defect_list(int page_code)
5367 {
5368 int status = 0, i, len, reallen, table, k;
5369 unsigned char *cmd, *df = 0;
5370 int trunc;
5371
5372 printf("Data from Defect Lists\n" "----------------------\n");
5373 for (table = 0; table < 2; table++) {
5374 memset(buffer, 0, SIZEOF_BUFFER);
5375 trunc = 0;
5376
5377 *((int *)buffer) = 0; /* length of input data */
5378 *(((int *)buffer) + 1) = 4; /* length of output buffer */
5379
5380 cmd = (unsigned char *)(((int *)buffer) + 2);
5381
5382 cmd[0] = 0x37; /* READ DEFECT DATA */
5383 cmd[1] = 0x00; /* lun=0 */
5384 cmd[2] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */
5385 cmd[3] = 0x00; /* (reserved) */
5386 cmd[4] = 0x00; /* (reserved) */
5387 cmd[5] = 0x00; /* (reserved) */
5388 cmd[6] = 0x00; /* (reserved) */
5389 cmd[7] = 0x00; /* Alloc len */
5390 cmd[8] = 0x04; /* Alloc len */
5391 cmd[9] = 0x00; /* control */
5392
5393 i = do_sg_io(glob_fd, buffer);
5394 if (2 == i)
5395 i = 0; /* Recovered error, probably returned a different
5396 format */
5397 if (i) {
5398 fprintf(stdout, ">>> Unable to read %s defect data.\n",
5399 (table ? "grown" : "manufacturer"));
5400 status |= i;
5401 continue;
5402 }
5403 len = (buffer[10] << 8) | buffer[11];
5404 reallen = len;
5405 if (len > 0) {
5406 if (len >= 0xfff8) {
5407 len = SIZEOF_BUFFER - 8;
5408 k = len + 8; /* length of defect list */
5409 *((int *)buffer) = 0; /* length of input data */
5410 *(((int *)buffer) + 1) = k; /* length of output buffer */
5411 ((struct sg_header *)buffer)->twelve_byte = 1;
5412 cmd[0] = 0xB7; /* READ DEFECT DATA */
5413 cmd[1] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */
5414 cmd[2] = 0x00; /* (reserved) */
5415 cmd[3] = 0x00; /* (reserved) */
5416 cmd[4] = 0x00; /* (reserved) */
5417 cmd[5] = 0x00; /* (reserved) */
5418 cmd[6] = 0x00; /* Alloc len */
5419 cmd[7] = (k >> 16); /* Alloc len */
5420 cmd[8] = (k >> 8); /* Alloc len */
5421 cmd[9] = (k & 0xff); /* Alloc len */
5422 cmd[10] = 0x00; /* reserved */
5423 cmd[11] = 0x00; /* control */
5424 i = do_sg_io(glob_fd, buffer);
5425 if (i == 2)
5426 i = 0;
5427 if (i)
5428 goto trytenbyte;
5429 reallen =
5430 (buffer[12] << 24 | buffer[13] << 16 |
5431 buffer[14] << 8 | buffer[15]);
5432 len = reallen;
5433 if (len > SIZEOF_BUFFER - 8) {
5434 len = SIZEOF_BUFFER - 8;
5435 trunc = 1;
5436 }
5437 df = (unsigned char *)(buffer + 16);
5438 } else {
5439 trytenbyte:
5440 if (len > 0xfff8) {
5441 len = 0xfff8;
5442 trunc = 1;
5443 }
5444 k = len + 4; /* length of defect list */
5445 *((int *)buffer) = 0; /* length of input data */
5446 *(((int *)buffer) + 1) = k; /* length of output buffer */
5447 cmd[0] = 0x37; /* READ DEFECT DATA */
5448 cmd[1] = 0x00; /* lun=0 */
5449 cmd[2] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */
5450 cmd[3] = 0x00; /* (reserved) */
5451 cmd[4] = 0x00; /* (reserved) */
5452 cmd[5] = 0x00; /* (reserved) */
5453 cmd[6] = 0x00; /* (reserved) */
5454 cmd[7] = (k >> 8); /* Alloc len */
5455 cmd[8] = (k & 0xff); /* Alloc len */
5456 cmd[9] = 0x00; /* control */
5457 i = do_sg_io(glob_fd, buffer);
5458 df = (unsigned char *)(buffer + 12);
5459 }
5460 }
5461 if (2 == i)
5462 i = 0; /* Recovered error, probably returned a different
5463 format */
5464 if (i) {
5465 fprintf(stdout, ">>> Unable to read %s defect data.\n",
5466 (table ? "grown" : "manufacturer"));
5467 status |= i;
5468 continue;
5469 } else {
5470 if (table && !status)
5471 printf("\n");
5472 printf("%d entries (%d bytes) in %s table.\n"
5473 "Format (%x) is: %s\n",
5474 reallen / ((buffer[9] & 7) ? 8 : 4), reallen,
5475 (table ? "grown" : "manufacturer"),
5476 buffer[9] & 7, formatname(buffer[9] & 7));
5477 i = 0;
5478 if ((buffer[9] & 7) == 4) {
5479 while (len > 0) {
5480 snprintf((char *)buffer, 40,
5481 "%6d:%3u:%8d", getnbyte(df, 3),
5482 df[3], getnbyte(df + 4, 4));
5483 printf("%19s", (char *)buffer);
5484 len -= 8;
5485 df += 8;
5486 i++;
5487 if (i >= 4) {
5488 printf("\n");
5489 i = 0;
5490 } else
5491 printf("|");
5492 }
5493 } else if ((buffer[9] & 7) == 5) {
5494 while (len > 0) {
5495 snprintf((char *)buffer, 40,
5496 "%6d:%2u:%5d", getnbyte(df, 3),
5497 df[3], getnbyte(df + 4, 4));
5498 printf("%15s", (char *)buffer);
5499 len -= 8;
5500 df += 8;
5501 i++;
5502 if (i >= 5) {
5503 printf("\n");
5504 i = 0;
5505 } else
5506 printf("|");
5507 }
5508 } else {
5509 while (len > 0) {
5510 printf("%10d", getnbyte(df, 4));
5511 len -= 4;
5512 df += 4;
5513 i++;
5514 if (i >= 7) {
5515 printf("\n");
5516 i = 0;
5517 } else
5518 printf("|");
5519 }
5520 }
5521 if (i)
5522 printf("\n");
5523 }
5524 if (trunc)
5525 printf("[truncated]\n");
5526 }
5527 printf("\n");
5528 return status;
5529 }
5530
read_cache(int page_code)5531 static int read_cache(int page_code)
5532 {
5533 int status;
5534 int bdlen;
5535 unsigned char *pagestart;
5536
5537 SETUP_MODE_PAGE(8, 9);
5538
5539 printf("Data from Caching Page\n");
5540 printf("----------------------\n");
5541 bitfield(pagestart + 2, "Write Cache", 1, 2);
5542 notbitfield(pagestart + 2, "Read Cache", 1, 0);
5543 bitfield(pagestart + 2, "Prefetch units", 1, 1);
5544 bitfield(pagestart + 3, "Demand Read Retention Priority", 0xf, 4);
5545 bitfield(pagestart + 3, "Demand Write Retention Priority", 0xf, 0);
5546 intfield(pagestart + 4, 2, "Disable Pre-fetch Transfer Length");
5547 intfield(pagestart + 6, 2, "Minimum Pre-fetch");
5548 intfield(pagestart + 8, 2, "Maximum Pre-fetch");
5549 intfield(pagestart + 10, 2, "Maximum Pre-fetch Ceiling");
5550 printf("\n");
5551 return 0;
5552 }
5553
read_format_info(int page_code)5554 static int read_format_info(int page_code)
5555 {
5556 int status;
5557 int bdlen;
5558 unsigned char *pagestart;
5559
5560 SETUP_MODE_PAGE(3, 13);
5561
5562 printf("Data from Format Device Page\n");
5563 printf("----------------------------\n");
5564 bitfield(pagestart + 20, "Removable Medium", 1, 5);
5565 bitfield(pagestart + 20, "Supports Hard Sectoring", 1, 6);
5566 bitfield(pagestart + 20, "Supports Soft Sectoring", 1, 7);
5567 bitfield(pagestart + 20, "Addresses assigned by surface", 1, 4);
5568 intfield(pagestart + 2, 2, "Tracks per Zone");
5569 intfield(pagestart + 4, 2, "Alternate sectors per zone");
5570 intfield(pagestart + 6, 2, "Alternate tracks per zone");
5571 intfield(pagestart + 8, 2, "Alternate tracks per lun");
5572 intfield(pagestart + 10, 2, "Sectors per track");
5573 intfield(pagestart + 12, 2, "Bytes per sector");
5574 intfield(pagestart + 14, 2, "Interleave");
5575 intfield(pagestart + 16, 2, "Track skew factor");
5576 intfield(pagestart + 18, 2, "Cylinder skew factor");
5577 printf("\n");
5578 return 0;
5579
5580 }
5581
verify_error_recovery(int page_code)5582 static int verify_error_recovery(int page_code)
5583 {
5584 int status;
5585 int bdlen;
5586 unsigned char *pagestart;
5587
5588 SETUP_MODE_PAGE(7, 7);
5589
5590 printf("Data from Verify Error Recovery Page\n");
5591 printf("------------------------------------\n");
5592 bitfield(pagestart + 2, "EER", 1, 3);
5593 bitfield(pagestart + 2, "PER", 1, 2);
5594 bitfield(pagestart + 2, "DTE", 1, 1);
5595 bitfield(pagestart + 2, "DCR", 1, 0);
5596 intfield(pagestart + 3, 1, "Verify Retry Count");
5597 intfield(pagestart + 4, 1, "Verify Correction Span (bits)");
5598 intfield(pagestart + 10, 2, "Verify Recovery Time Limit (ms)");
5599
5600 printf("\n");
5601 return 0;
5602 }
5603
peripheral_device_page(int page_code)5604 static int peripheral_device_page(int page_code)
5605 {
5606 static char *idents[] = {
5607 "X3.131: Small Computer System Interface",
5608 "X3.91M-1987: Storage Module Interface",
5609 "X3.170: Enhanced Small Device Interface",
5610 "X3.130-1986; X3T9.3/87-002: IPI-2",
5611 "X3.132-1987; X3.147-1988: IPI-3"
5612 };
5613 int status;
5614 int bdlen;
5615 unsigned ident;
5616 unsigned char *pagestart;
5617 char *name;
5618
5619 SETUP_MODE_PAGE(9, 2);
5620
5621 printf("Data from Peripheral Device Page\n");
5622 printf("--------------------------------\n");
5623
5624 ident = getnbyte(pagestart + 2, 2);
5625 if (ident < (sizeof(idents) / sizeof(char *)))
5626 name = idents[ident];
5627 else if (ident < 0x8000)
5628 name = "Reserved";
5629 else
5630 name = "Vendor Specific";
5631
5632 bdlen = pagestart[1] - 6;
5633 if (bdlen < 0)
5634 bdlen = 0;
5635 else
5636 SETUP_MODE_PAGE(9, 2);
5637
5638 hexfield(pagestart + 2, 2, "Interface Identifier");
5639 for (ident = 0; ident < 35; ident++)
5640 putchar(' ');
5641 puts(name);
5642
5643 hexdatafield(pagestart + 8, bdlen, "Vendor Specific Data");
5644
5645 printf("\n");
5646 return 0;
5647 }
5648
5649 /* end */
5650
do_user_page(int page_code,int page_no)5651 static int do_user_page(int page_code, int page_no)
5652 {
5653 int status;
5654 int bdlen;
5655 int i;
5656 //unsigned ident;
5657 unsigned char *pagestart;
5658 char *name;
5659
5660 SETUP_MODE_PAGE(page_no, 0);
5661 //printf ("Page 0x%02x len: %i\n", page_code, pagestart[1]);
5662
5663 name = "Vendor specific";
5664 for (i = 2; i < pagestart[1] + 2; i++) {
5665 char nm[8];
5666 snprintf(nm, 8, "%02x", i);
5667 hexdatafield(pagestart + i, 1, nm);
5668 }
5669
5670 printf("\n");
5671 puts(name);
5672 return 0;
5673 }
5674
5675 /* end */
5676
do_scsi_info_inquiry(int page_code)5677 static int do_scsi_info_inquiry(int page_code)
5678 {
5679 int status, i, x_interface = 0;
5680 unsigned char *cmd;
5681 unsigned char *pagestart;
5682 unsigned char tmp;
5683
5684 for (i = 0; i < 1024; i++) {
5685 buffer[i] = 0;
5686 }
5687
5688 *((int *)buffer) = 0; /* length of input data */
5689 *(((int *)buffer) + 1) = 36; /* length of output buffer */
5690
5691 cmd = (unsigned char *)(((int *)buffer) + 2);
5692
5693 cmd[0] = 0x12; /* INQUIRY */
5694 cmd[1] = 0x00; /* lun=0, evpd=0 */
5695 cmd[2] = 0x00; /* page code = 0 */
5696 cmd[3] = 0x00; /* (reserved) */
5697 cmd[4] = 0x24; /* allocation length */
5698 cmd[5] = 0x00; /* control */
5699
5700 status = do_sg_io(glob_fd, buffer);
5701 if (status) {
5702 printf("Error doing INQUIRY (1)");
5703 return status;
5704 }
5705
5706 pagestart = buffer + 8;
5707
5708 printf("Inquiry command\n");
5709 printf("---------------\n");
5710 bitfield(pagestart + 7, "Relative Address", 1, 7);
5711 bitfield(pagestart + 7, "Wide bus 32", 1, 6);
5712 bitfield(pagestart + 7, "Wide bus 16", 1, 5);
5713 bitfield(pagestart + 7, "Synchronous neg.", 1, 4);
5714 bitfield(pagestart + 7, "Linked Commands", 1, 3);
5715 bitfield(pagestart + 7, "Command Queueing", 1, 1);
5716 bitfield(pagestart + 7, "SftRe", 1, 0);
5717 bitfield(pagestart + 0, "Device Type", 0x1f, 0);
5718 bitfield(pagestart + 0, "Peripheral Qualifier", 0x7, 5);
5719 bitfield(pagestart + 1, "Removable?", 1, 7);
5720 bitfield(pagestart + 1, "Device Type Modifier", 0x7f, 0);
5721 bitfield(pagestart + 2, "ISO Version", 3, 6);
5722 bitfield(pagestart + 2, "ECMA Version", 7, 3);
5723 bitfield(pagestart + 2, "ANSI Version", 7, 0);
5724 bitfield(pagestart + 3, "AENC", 1, 7);
5725 bitfield(pagestart + 3, "TrmIOP", 1, 6);
5726 bitfield(pagestart + 3, "Response Data Format", 0xf, 0);
5727 tmp = pagestart[16];
5728 pagestart[16] = 0;
5729 printf("%s%s\n", (!x_interface ? "Vendor: " : ""),
5730 pagestart + 8);
5731 pagestart[16] = tmp;
5732
5733 tmp = pagestart[32];
5734 pagestart[32] = 0;
5735 printf("%s%s\n", (!x_interface ? "Product: " : ""),
5736 pagestart + 16);
5737 pagestart[32] = tmp;
5738
5739 printf("%s%s\n", (!x_interface ? "Revision level: " : ""),
5740 pagestart + 32);
5741
5742 printf("\n");
5743 return status;
5744
5745 }
5746
do_serial_number(int page_code)5747 static int do_serial_number(int page_code)
5748 {
5749 int status, i, pagelen;
5750 unsigned char *cmd;
5751 unsigned char *pagestart;
5752
5753 for (i = 0; i < 1024; i++) {
5754 buffer[i] = 0;
5755 }
5756
5757 *((int *)buffer) = 0; /* length of input data */
5758 *(((int *)buffer) + 1) = 4; /* length of output buffer */
5759
5760 cmd = (unsigned char *)(((int *)buffer) + 2);
5761
5762 cmd[0] = 0x12; /* INQUIRY */
5763 cmd[1] = 0x01; /* lun=0, evpd=1 */
5764 cmd[2] = 0x80; /* page code = 0x80, serial number */
5765 cmd[3] = 0x00; /* (reserved) */
5766 cmd[4] = 0x04; /* allocation length */
5767 cmd[5] = 0x00; /* control */
5768
5769 status = do_sg_io(glob_fd, buffer);
5770 if (status) {
5771 printf("Error doing INQUIRY (evpd=1, serial number)\n");
5772 return status;
5773 }
5774
5775 pagestart = buffer + 8;
5776
5777 pagelen = 4 + pagestart[3];
5778 *((int *)buffer) = 0; /* length of input data */
5779 *(((int *)buffer) + 1) = pagelen; /* length of output buffer */
5780
5781 cmd[0] = 0x12; /* INQUIRY */
5782 cmd[1] = 0x01; /* lun=0, evpd=1 */
5783 cmd[2] = 0x80; /* page code = 0x80, serial number */
5784 cmd[3] = 0x00; /* (reserved) */
5785 cmd[4] = (unsigned char)pagelen; /* allocation length */
5786 cmd[5] = 0x00; /* control */
5787
5788 status = do_sg_io(glob_fd, buffer);
5789 if (status) {
5790 printf("Error doing INQUIRY (evpd=1, serial number, len)\n");
5791 return status;
5792 }
5793
5794 printf("Serial Number '");
5795 for (i = 0; i < pagestart[3]; i++)
5796 printf("%c", pagestart[4 + i]);
5797 printf("'\n");
5798 printf("\n");
5799
5800 return status;
5801 }
5802
5803 /* Print out a list of the known devices on the system */
show_devices()5804 static void show_devices()
5805 {
5806 int k, j, fd, err, bus;
5807 My_scsi_idlun m_idlun;
5808 char name[MDEV_NAME_SZ];
5809 char ebuff[EBUFF_SZ];
5810 int do_numeric = 1;
5811 int max_holes = MAX_HOLES;
5812
5813 for (k = 0, j = 0; k < sizeof(devices) / sizeof(char *); k++) {
5814 fd = open(devices[k], O_RDONLY | O_NONBLOCK);
5815 if (fd < 0)
5816 continue;
5817 err =
5818 ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &(sg_map_arr[j].bus));
5819 if (err < 0) {
5820 snprintf(ebuff, EBUFF_SZ,
5821 "SCSI(1) ioctl on %s failed", devices[k]);
5822 perror(ebuff);
5823 close(fd);
5824 continue;
5825 }
5826 err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun);
5827 if (err < 0) {
5828 snprintf(ebuff, EBUFF_SZ,
5829 "SCSI(2) ioctl on %s failed", devices[k]);
5830 perror(ebuff);
5831 close(fd);
5832 continue;
5833 }
5834 sg_map_arr[j].channel = (m_idlun.dev_id >> 16) & 0xff;
5835 sg_map_arr[j].lun = (m_idlun.dev_id >> 8) & 0xff;
5836 sg_map_arr[j].target_id = m_idlun.dev_id & 0xff;
5837 sg_map_arr[j].dev_name = devices[k];
5838
5839 printf("[scsi%d ch=%d id=%d lun=%d %s] ", sg_map_arr[j].bus,
5840 sg_map_arr[j].channel, sg_map_arr[j].target_id,
5841 sg_map_arr[j].lun, sg_map_arr[j].dev_name);
5842
5843 ++j;
5844 printf("%s ", devices[k]);
5845 close(fd);
5846 };
5847 printf("\n");
5848 for (k = 0; k < MAX_SG_DEVS; k++) {
5849 make_dev_name(name, NULL, k, do_numeric);
5850 fd = open(name, O_RDWR | O_NONBLOCK);
5851 if (fd < 0) {
5852 if ((ENOENT == errno) && (0 == k)) {
5853 do_numeric = 0;
5854 make_dev_name(name, NULL, k, do_numeric);
5855 fd = open(name, O_RDWR | O_NONBLOCK);
5856 }
5857 if (fd < 0) {
5858 if (EBUSY == errno)
5859 continue; /* step over if O_EXCL already on it */
5860 else {
5861 #if 0
5862 snprintf(ebuff, EBUFF_SZ,
5863 "open on %s failed (%d)", name,
5864 errno);
5865 perror(ebuff);
5866 #endif
5867 if (max_holes-- > 0)
5868 continue;
5869 else
5870 break;
5871 }
5872 }
5873 }
5874 max_holes = MAX_HOLES;
5875 err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus);
5876 if (err < 0) {
5877 snprintf(ebuff, EBUFF_SZ, "SCSI(3) ioctl on %s failed",
5878 name);
5879 perror(ebuff);
5880 close(fd);
5881 continue;
5882 }
5883 err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun);
5884 if (err < 0) {
5885 snprintf(ebuff, EBUFF_SZ, "SCSI(3) ioctl on %s failed",
5886 name);
5887 perror(ebuff);
5888 close(fd);
5889 continue;
5890 }
5891
5892 printf("[scsi%d ch=%d id=%d lun=%d %s]", bus,
5893 (m_idlun.dev_id >> 16) & 0xff, m_idlun.dev_id & 0xff,
5894 (m_idlun.dev_id >> 8) & 0xff, name);
5895
5896 for (j = 0; sg_map_arr[j].dev_name; ++j) {
5897 if ((bus == sg_map_arr[j].bus) &&
5898 ((m_idlun.dev_id & 0xff) == sg_map_arr[j].target_id)
5899 && (((m_idlun.dev_id >> 16) & 0xff) ==
5900 sg_map_arr[j].channel)
5901 && (((m_idlun.dev_id >> 8) & 0xff) ==
5902 sg_map_arr[j].lun)) {
5903 printf("%s [=%s scsi%d ch=%d id=%d lun=%d]\n",
5904 name, sg_map_arr[j].dev_name, bus,
5905 ((m_idlun.dev_id >> 16) & 0xff),
5906 m_idlun.dev_id & 0xff,
5907 ((m_idlun.dev_id >> 8) & 0xff));
5908 break;
5909 }
5910 }
5911 if (NULL == sg_map_arr[j].dev_name)
5912 printf("%s [scsi%d ch=%d id=%d lun=%d]\n", name, bus,
5913 ((m_idlun.dev_id >> 16) & 0xff),
5914 m_idlun.dev_id & 0xff,
5915 ((m_idlun.dev_id >> 8) & 0xff));
5916 close(fd);
5917 }
5918 printf("\n");
5919 }
5920
show_pages(int page_code)5921 static int show_pages(int page_code)
5922 {
5923 int offset;
5924 int length;
5925 int i;
5926 unsigned long long pages_sup = 0;
5927 unsigned long long pages_mask = 0;
5928
5929 if (!get_mode_page10(0x3f, page_code | 0x10)) {
5930 length = 9 + getnbyte(buffer + 8, 2);
5931 offset = 16 + getnbyte(buffer + 14, 2);
5932 } else if (!get_mode_page(0x3f, page_code | 0x10)) {
5933 length = 9 + buffer[8];
5934 offset = 12 + buffer[11];
5935 } else { /* Assume SCSI-1 and fake settings to report NO pages */
5936 offset = 10;
5937 length = 0;
5938 }
5939
5940 /* Get mask of pages supported by prog: */
5941 for (i = 0; i < MAX_PAGENO; i++)
5942 if (page_names[i])
5943 pages_mask |= (1LL << i);
5944
5945 /* Get pages listed in mode_pages */
5946 while (offset < length) {
5947 pages_sup |= (1LL << (buffer[offset] & 0x3f));
5948 offset += 2 + buffer[offset + 1];
5949 }
5950
5951 /* Mask out pages unsupported by this binary */
5952 pages_sup &= pages_mask;
5953
5954 /* Notch page supported? */
5955 if (pages_sup & (1LL << 12)) {
5956 if (get_mode_page(12, 0))
5957 return 2;
5958 offset = 12 + buffer[11];
5959 } else { /* Fake empty notch page */
5960 memset(buffer, 0, SIZEOF_BUFFER);
5961 offset = 0;
5962 }
5963
5964 pages_mask = getnbyte(buffer + offset + 16, 4);
5965 pages_mask <<= 32;
5966 pages_mask += getnbyte(buffer + offset + 20, 4);
5967
5968 puts("Mode Pages supported by this binary and target:");
5969 puts("-----------------------------------------------");
5970 for (i = 0; i < MAX_PAGENO; i++)
5971 if (pages_sup & (1LL << i))
5972 printf("%02xh: %s Page%s\n", i, get_page_name(i),
5973 (pages_mask & (1LL << i)) ? " (notched)" : "");
5974 if (pages_sup & (1LL << 12)) {
5975 printf("\nCurrent notch is %d.\n",
5976 getnbyte(buffer + offset + 6, 2));
5977 }
5978 if (!pages_sup)
5979 puts("No mode pages supported (SCSI-1?).");
5980
5981 return 0;
5982 }
5983
open_sg_dev(char * devname)5984 static int open_sg_dev(char *devname)
5985 {
5986 int fd, err, bus, bbus, k;
5987 My_scsi_idlun m_idlun, mm_idlun;
5988 int do_numeric = 1;
5989 char name[DEVNAME_SZ];
5990 struct stat a_st;
5991 int block_dev = 0;
5992
5993 strncpy(name, devname, DEVNAME_SZ);
5994 name[DEVNAME_SZ - 1] = '\0';
5995 fd = open(name, O_RDONLY);
5996 if (fd < 0)
5997 return fd;
5998 if (fstat(fd, &a_st) < 0) {
5999 fprintf(stderr, "could do fstat() on fd ??\n");
6000 close(fd);
6001 return -9999;
6002 }
6003 if (S_ISBLK(a_st.st_mode))
6004 block_dev = 1;
6005 if (block_dev || (ioctl(fd, SG_GET_TIMEOUT, 0) < 0)) {
6006 err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus);
6007 if (err < 0) {
6008 perror("A SCSI device name is required\n");
6009 close(fd);
6010 return -9999;
6011 }
6012 err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun);
6013 if (err < 0) {
6014 perror("A SCSI device name is required\n");
6015 close(fd);
6016 return -9999;
6017 }
6018 close(fd);
6019
6020 for (k = 0; k < MAX_SG_DEVS; k++) {
6021 make_dev_name(name, NULL, k, do_numeric);
6022 fd = open(name, O_RDWR | O_NONBLOCK);
6023 if (fd < 0) {
6024 if ((ENOENT == errno) && (0 == k)) {
6025 do_numeric = 0;
6026 make_dev_name(name, NULL, k,
6027 do_numeric);
6028 fd = open(name, O_RDWR | O_NONBLOCK);
6029 }
6030 if (fd < 0) {
6031 if (EBUSY == errno)
6032 continue; /* step over if O_EXCL already on it */
6033 else
6034 break;
6035 }
6036 }
6037 err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bbus);
6038 if (err < 0) {
6039 perror("sg ioctl failed");
6040 close(fd);
6041 fd = -9999;
6042 }
6043 err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &mm_idlun);
6044 if (err < 0) {
6045 perror("sg ioctl failed");
6046 close(fd);
6047 fd = -9999;
6048 }
6049 if ((bus == bbus) &&
6050 ((m_idlun.dev_id & 0xff) ==
6051 (mm_idlun.dev_id & 0xff))
6052 && (((m_idlun.dev_id >> 8) & 0xff) ==
6053 ((mm_idlun.dev_id >> 8) & 0xff))
6054 && (((m_idlun.dev_id >> 16) & 0xff) ==
6055 ((mm_idlun.dev_id >> 16) & 0xff)))
6056 break;
6057 else {
6058 close(fd);
6059 fd = -9999;
6060 }
6061 }
6062 }
6063 if (fd >= 0) {
6064 #ifdef SG_GET_RESERVED_SIZE
6065 int size;
6066
6067 if (ioctl(fd, SG_GET_RESERVED_SIZE, &size) < 0) {
6068 fprintf(stderr,
6069 "Compiled with new driver, running on old!!\n");
6070 close(fd);
6071 return -9999;
6072 }
6073 #endif
6074 close(fd);
6075 return open(name, O_RDWR);
6076 } else
6077 return fd;
6078 }
6079
show_scsi_info(char * device)6080 int show_scsi_info(char *device)
6081 {
6082 int page_code = 0;
6083 int status = 0;
6084
6085 print_msg(TEST_BREAK, __FUNCTION__);
6086
6087 show_devices();
6088
6089 glob_fd = open_sg_dev(device);
6090 if (glob_fd < 0) {
6091 if (-9999 == glob_fd)
6092 fprintf(stderr,
6093 "Couldn't find sg device corresponding to %s\n",
6094 device);
6095 else {
6096 perror("sginfo(open)");
6097 fprintf(stderr,
6098 "file=%s, or no corresponding sg device found\n",
6099 device);
6100 fprintf(stderr, "Is sg driver loaded?\n");
6101 }
6102 return 1;
6103 }
6104
6105 status |= do_scsi_info_inquiry(page_code);
6106
6107 status |= do_serial_number(page_code);
6108
6109 status |= read_geometry(page_code);
6110
6111 status |= read_cache(page_code);
6112
6113 status |= read_format_info(page_code);
6114
6115 status |= error_recovery_page(page_code);
6116
6117 status |= read_control_page(page_code);
6118
6119 status |= read_disconnect_reconnect_data(page_code);
6120
6121 status |= read_defect_list(page_code);
6122
6123 status |= notch_parameters_page(page_code);
6124
6125 status |= verify_error_recovery(page_code);
6126
6127 status |= peripheral_device_page(page_code);
6128
6129 status |= do_user_page(page_code, 0);
6130
6131 status |= show_pages(page_code);
6132
6133 return status;
6134 }
6135
6136 /* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM),
6137 2 -> try again */
sg_read2(int sg_fd,unsigned char * buff,int blocks,int from_block,int bs,int cdbsz,int fua,int do_mmap)6138 int sg_read2(int sg_fd, unsigned char *buff, int blocks, int from_block,
6139 int bs, int cdbsz, int fua, int do_mmap)
6140 {
6141 unsigned char rdCmd[MAX_SCSI_CDBSZ];
6142 unsigned char senseBuff[SENSE_BUFF_LEN];
6143 sg_io_hdr_t io_hdr;
6144 int res;
6145
6146 if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, 0)) {
6147 fprintf(stderr,
6148 ME "bad rd cdb build, from_block=%d, blocks=%d\n",
6149 from_block, blocks);
6150 return -1;
6151 }
6152 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
6153 io_hdr.interface_id = 'S';
6154 io_hdr.cmd_len = cdbsz;
6155 io_hdr.cmdp = rdCmd;
6156 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
6157 io_hdr.dxfer_len = bs * blocks;
6158 if (!do_mmap)
6159 io_hdr.dxferp = buff;
6160 io_hdr.mx_sb_len = SENSE_BUFF_LEN;
6161 io_hdr.sbp = senseBuff;
6162 io_hdr.timeout = DEF_TIMEOUT;
6163 io_hdr.pack_id = from_block;
6164 if (do_mmap)
6165 io_hdr.flags |= SG_FLAG_MMAP_IO;
6166
6167 while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
6168 (EINTR == errno)) ;
6169 if (res < 0) {
6170 if (ENOMEM == errno)
6171 return 1;
6172 perror("reading (wr) on sg device, error");
6173 return -1;
6174 }
6175
6176 while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
6177 (EINTR == errno)) ;
6178 if (res < 0) {
6179 perror("reading (rd) on sg device, error");
6180 return -1;
6181 }
6182 switch (sg_err_category3(&io_hdr)) {
6183 case SG_ERR_CAT_CLEAN:
6184 break;
6185 case SG_ERR_CAT_RECOVERED:
6186 fprintf(stderr,
6187 "Recovered error while reading block=%d, num=%d\n",
6188 from_block, blocks);
6189 break;
6190 case SG_ERR_CAT_MEDIA_CHANGED:
6191 return 2;
6192 default:
6193 sg_chk_n_print3("reading", &io_hdr);
6194 return -1;
6195 }
6196 sum_of_resids += io_hdr.resid;
6197 #if SG_DEBUG
6198 fprintf(stderr, "duration=%u ms\n", io_hdr.duration);
6199 #endif
6200 return 0;
6201 }
6202
6203 /* -1 -> unrecoverable error, 0 -> successful, 1 -> recoverable (ENOMEM),
6204 2 -> try again */
sg_write2(int sg_fd,unsigned char * buff,int blocks,int to_block,int bs,int cdbsz,int fua,int do_mmap,int * diop)6205 int sg_write2(int sg_fd, unsigned char *buff, int blocks, int to_block,
6206 int bs, int cdbsz, int fua, int do_mmap, int *diop)
6207 {
6208 unsigned char wrCmd[MAX_SCSI_CDBSZ];
6209 unsigned char senseBuff[SENSE_BUFF_LEN];
6210 sg_io_hdr_t io_hdr;
6211 int res;
6212
6213 if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, 1, fua, 0)) {
6214 fprintf(stderr, ME "bad wr cdb build, to_block=%d, blocks=%d\n",
6215 to_block, blocks);
6216 return -1;
6217 }
6218
6219 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
6220 io_hdr.interface_id = 'S';
6221 io_hdr.cmd_len = cdbsz;
6222 io_hdr.cmdp = wrCmd;
6223 io_hdr.dxfer_direction = SG_DXFER_TO_DEV;
6224 io_hdr.dxfer_len = bs * blocks;
6225 if (!do_mmap)
6226 io_hdr.dxferp = buff;
6227 io_hdr.mx_sb_len = SENSE_BUFF_LEN;
6228 io_hdr.sbp = senseBuff;
6229 io_hdr.timeout = DEF_TIMEOUT;
6230 io_hdr.pack_id = to_block;
6231 if (do_mmap)
6232 io_hdr.flags |= SG_FLAG_MMAP_IO;
6233 if (diop && *diop)
6234 io_hdr.flags |= SG_FLAG_DIRECT_IO;
6235
6236 while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
6237 (EINTR == errno)) ;
6238 if (res < 0) {
6239 if (ENOMEM == errno)
6240 return 1;
6241 perror("writing (wr) on sg device, error");
6242 return -1;
6243 }
6244
6245 while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) &&
6246 (EINTR == errno)) ;
6247 if (res < 0) {
6248 perror("writing (rd) on sg device, error");
6249 return -1;
6250 }
6251 switch (sg_err_category3(&io_hdr)) {
6252 case SG_ERR_CAT_CLEAN:
6253 break;
6254 case SG_ERR_CAT_RECOVERED:
6255 fprintf(stderr,
6256 "Recovered error while writing block=%d, num=%d\n",
6257 to_block, blocks);
6258 break;
6259 case SG_ERR_CAT_MEDIA_CHANGED:
6260 return 2;
6261 default:
6262 sg_chk_n_print3("writing", &io_hdr);
6263 return -1;
6264 }
6265 if (diop && *diop &&
6266 ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
6267 *diop = 0; /* flag that dio not done (completely) */
6268 return 0;
6269 }
6270
do_scsi_sgm_read_write(char * device)6271 int do_scsi_sgm_read_write(char *device)
6272 {
6273 int skip = 0;
6274 int seek = 0;
6275 int bs = 0;
6276 int bpt = DEF_BLOCKS_PER_TRANSFER;
6277 char inf[INOUTF_SZ];
6278 int in_type = FT_OTHER;
6279 char outf[INOUTF_SZ];
6280 int out_type = FT_OTHER;
6281 int res, t;
6282 int infd, outfd, blocks;
6283 unsigned char *wrkPos;
6284 unsigned char *wrkBuff = NULL;
6285 unsigned char *wrkMmap = NULL;
6286 int in_num_sect = 0;
6287 int in_res_sz = 0;
6288 int out_num_sect = 0;
6289 int out_res_sz = 0;
6290 int do_time = 1;
6291 int scsi_cdbsz = DEF_SCSI_CDBSZ;
6292 int do_sync = 1;
6293 int do_dio = 0;
6294 int num_dio_not_done = 0;
6295 int fua_mode = 0;
6296 int in_sect_sz, out_sect_sz;
6297 char ebuff[EBUFF_SZ];
6298 int blocks_per;
6299 int req_count;
6300 size_t psz = getpagesize();
6301 struct timeval start_tm, end_tm;
6302
6303 print_msg(TEST_BREAK, __FUNCTION__);
6304
6305 strcpy(inf, "/dev/zero");
6306 strcpy(outf, device);
6307
6308 install_handler(SIGINT, interrupt_handler);
6309 install_handler(SIGQUIT, interrupt_handler);
6310 install_handler(SIGPIPE, interrupt_handler);
6311 install_handler(SIGUSR1, siginfo_handler);
6312
6313 infd = STDIN_FILENO;
6314 outfd = STDOUT_FILENO;
6315
6316 in_type = dd_filetype(inf);
6317
6318 if (FT_ST == in_type) {
6319 fprintf(stderr, ME "unable to use scsi tape device %s\n", inf);
6320 return 1;
6321 } else if (FT_SG == in_type) {
6322 if ((infd = open(inf, O_RDWR)) < 0) {
6323 snprintf(ebuff, EBUFF_SZ,
6324 ME "could not open %s for sg reading", inf);
6325 perror(ebuff);
6326 return 1;
6327 }
6328 res = ioctl(infd, SG_GET_VERSION_NUM, &t);
6329 if ((res < 0) || (t < 30122)) {
6330 fprintf(stderr, ME "sg driver prior to 3.1.22\n");
6331 return 1;
6332 }
6333 in_res_sz = bs * bpt;
6334 if (0 != (in_res_sz % psz)) /* round up to next page */
6335 in_res_sz = ((in_res_sz / psz) + 1) * psz;
6336 if (ioctl(infd, SG_GET_RESERVED_SIZE, &t) < 0) {
6337 perror(ME "SG_GET_RESERVED_SIZE error");
6338 return 1;
6339 }
6340 if (in_res_sz > t) {
6341 if (ioctl(infd, SG_SET_RESERVED_SIZE, &in_res_sz) < 0) {
6342 perror(ME "SG_SET_RESERVED_SIZE error");
6343 return 1;
6344 }
6345 }
6346 wrkMmap = mmap(NULL, in_res_sz, PROT_READ | PROT_WRITE,
6347 MAP_SHARED, infd, 0);
6348 if (MAP_FAILED == wrkMmap) {
6349 snprintf(ebuff, EBUFF_SZ,
6350 ME "error using mmap() on file: %s", inf);
6351 perror(ebuff);
6352 return 1;
6353 }
6354 } else {
6355 if ((infd = open(inf, O_RDONLY)) < 0) {
6356 snprintf(ebuff, EBUFF_SZ,
6357 ME "could not open %s for reading", inf);
6358 perror(ebuff);
6359 return 1;
6360 } else if (skip > 0) {
6361 llse_loff_t offset = skip;
6362
6363 offset *= bs; /* could exceed 32 bits here! */
6364 if (llse_llseek(infd, offset, SEEK_SET) < 0) {
6365 snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to "
6366 "required position on %s", inf);
6367 perror(ebuff);
6368 return 1;
6369 }
6370 }
6371 }
6372
6373 if (outf[0] && ('-' != outf[0])) {
6374 out_type = dd_filetype(outf);
6375
6376 if (FT_ST == out_type) {
6377 fprintf(stderr,
6378 ME "unable to use scsi tape device %s\n", outf);
6379 return 1;
6380 } else if (FT_SG == out_type) {
6381 if ((outfd = open(outf, O_RDWR)) < 0) {
6382 snprintf(ebuff, EBUFF_SZ,
6383 ME "could not open %s for "
6384 "sg writing", outf);
6385 perror(ebuff);
6386 return 1;
6387 }
6388 res = ioctl(outfd, SG_GET_VERSION_NUM, &t);
6389 if ((res < 0) || (t < 30122)) {
6390 fprintf(stderr,
6391 ME "sg driver prior to 3.1.22\n");
6392 return 1;
6393 }
6394 if (ioctl(outfd, SG_GET_RESERVED_SIZE, &t) < 0) {
6395 perror(ME "SG_GET_RESERVED_SIZE error");
6396 return 1;
6397 }
6398 out_res_sz = bs * bpt;
6399 if (out_res_sz > t) {
6400 if (ioctl
6401 (outfd, SG_SET_RESERVED_SIZE,
6402 &out_res_sz) < 0) {
6403 perror(ME "SG_SET_RESERVED_SIZE error");
6404 return 1;
6405 }
6406 }
6407 if (NULL == wrkMmap) {
6408 wrkMmap =
6409 mmap(NULL, out_res_sz,
6410 PROT_READ | PROT_WRITE, MAP_SHARED,
6411 outfd, 0);
6412 if (MAP_FAILED == wrkMmap) {
6413 snprintf(ebuff, EBUFF_SZ,
6414 ME
6415 "error using mmap() on file: %s",
6416 outf);
6417 perror(ebuff);
6418 return 1;
6419 }
6420 }
6421 } else if (FT_DEV_NULL == out_type)
6422 outfd = -1; /* don't bother opening */
6423 else {
6424 if (FT_RAW != out_type) {
6425 if ((outfd =
6426 open(outf, O_WRONLY | O_CREAT,
6427 0666)) < 0) {
6428 snprintf(ebuff, EBUFF_SZ,
6429 ME
6430 "could not open %s for writing",
6431 outf);
6432 perror(ebuff);
6433 return 1;
6434 }
6435 } else {
6436 if ((outfd = open(outf, O_WRONLY)) < 0) {
6437 snprintf(ebuff, EBUFF_SZ,
6438 ME "could not open %s "
6439 "for raw writing", outf);
6440 perror(ebuff);
6441 return 1;
6442 }
6443 }
6444 if (seek > 0) {
6445 llse_loff_t offset = seek;
6446
6447 offset *= bs; /* could exceed 32 bits here! */
6448 if (llse_llseek(outfd, offset, SEEK_SET) < 0) {
6449 snprintf(ebuff, EBUFF_SZ,
6450 ME "couldn't seek to "
6451 "required position on %s",
6452 outf);
6453 perror(ebuff);
6454 return 1;
6455 }
6456 }
6457 }
6458 }
6459 if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) {
6460 fprintf(stderr,
6461 "Can't have both 'if' as stdin _and_ 'of' as stdout\n");
6462 return 1;
6463 }
6464 #if 0
6465 if ((FT_OTHER == in_type) && (FT_OTHER == out_type)) {
6466 fprintf(stderr, "Both 'if' and 'of' can't be ordinary files\n");
6467 return 1;
6468 }
6469 #endif
6470 if (dd_count < 0) {
6471 if (FT_SG == in_type) {
6472 res = read_capacity(infd, &in_num_sect, &in_sect_sz);
6473 if (2 == res) {
6474 fprintf(stderr,
6475 "Unit attention, media changed(in), continuing\n");
6476 res =
6477 read_capacity(infd, &in_num_sect,
6478 &in_sect_sz);
6479 }
6480 if (0 != res) {
6481 fprintf(stderr,
6482 "Unable to read capacity on %s\n", inf);
6483 in_num_sect = -1;
6484 } else {
6485 #if 0
6486 if (0 == in_sect_sz)
6487 in_sect_sz = bs;
6488 else if (in_sect_sz > bs)
6489 in_num_sect *= (in_sect_sz / bs);
6490 else if (in_sect_sz < bs)
6491 in_num_sect /= (bs / in_sect_sz);
6492 #endif
6493 if (in_num_sect > skip)
6494 in_num_sect -= skip;
6495 }
6496 }
6497 if (FT_SG == out_type) {
6498 res = read_capacity(outfd, &out_num_sect, &out_sect_sz);
6499 if (2 == res) {
6500 fprintf(stderr,
6501 "Unit attention, media changed(out), continuing\n");
6502 res =
6503 read_capacity(outfd, &out_num_sect,
6504 &out_sect_sz);
6505 }
6506 if (0 != res) {
6507 fprintf(stderr,
6508 "Unable to read capacity on %s\n",
6509 outf);
6510 out_num_sect = -1;
6511 } else {
6512 if (out_num_sect > seek)
6513 out_num_sect -= seek;
6514 }
6515 }
6516 #ifdef SG_DEBUG
6517 fprintf(stderr,
6518 "Start of loop, count=%d, in_num_sect=%d, out_num_sect=%d\n",
6519 dd_count, in_num_sect, out_num_sect);
6520 #endif
6521 if (in_num_sect > 0) {
6522 if (out_num_sect > 0)
6523 dd_count =
6524 (in_num_sect >
6525 out_num_sect) ? out_num_sect : in_num_sect;
6526 else
6527 dd_count = in_num_sect;
6528 } else
6529 dd_count = out_num_sect;
6530 }
6531 if (dd_count < 0) {
6532 fprintf(stderr, "Couldn't calculate count, please give one\n");
6533 return 1;
6534 }
6535 if (do_dio && (FT_SG != in_type)) {
6536 do_dio = 0;
6537 fprintf(stderr,
6538 ">>> dio only performed on 'of' side when 'if' is"
6539 " an sg device\n");
6540 }
6541 if (do_dio) {
6542 int fd;
6543 char c;
6544
6545 if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) {
6546 if (1 == read(fd, &c, 1)) {
6547 if ('0' == c)
6548 fprintf(stderr,
6549 ">>> %s set to '0' but should be set "
6550 "to '1' for direct IO\n",
6551 proc_allow_dio);
6552 }
6553 close(fd);
6554 }
6555 }
6556
6557 if (wrkMmap)
6558 wrkPos = wrkMmap;
6559 else {
6560 if ((FT_RAW == in_type) || (FT_RAW == out_type)) {
6561 wrkBuff = malloc(bs * bpt + psz);
6562 if (0 == wrkBuff) {
6563 fprintf(stderr,
6564 "Not enough user memory for raw\n");
6565 return 1;
6566 }
6567 wrkPos =
6568 (unsigned char *)(((unsigned long)wrkBuff + psz - 1)
6569 & (~(psz - 1)));
6570 } else {
6571 wrkBuff = malloc(bs * bpt);
6572 if (0 == wrkBuff) {
6573 fprintf(stderr, "Not enough user memory\n");
6574 return 1;
6575 }
6576 wrkPos = wrkBuff;
6577 }
6578 }
6579
6580 blocks_per = bpt;
6581 #ifdef SG_DEBUG
6582 fprintf(stderr, "Start of loop, count=%d, blocks_per=%d\n",
6583 dd_count, blocks_per);
6584 #endif
6585 if (do_time) {
6586 start_tm.tv_sec = 0;
6587 start_tm.tv_usec = 0;
6588 gettimeofday(&start_tm, NULL);
6589 }
6590 req_count = dd_count;
6591
6592 while (dd_count > 0) {
6593 blocks = (dd_count > blocks_per) ? blocks_per : dd_count;
6594 if (FT_SG == in_type) {
6595 int fua = fua_mode & 2;
6596
6597 res =
6598 sg_read2(infd, wrkPos, blocks, skip, bs, scsi_cdbsz,
6599 fua, 1);
6600 if (2 == res) {
6601 fprintf(stderr,
6602 "Unit attention, media changed, continuing (r)\n");
6603 res =
6604 sg_read2(infd, wrkPos, blocks, skip, bs,
6605 scsi_cdbsz, fua, 1);
6606 }
6607 if (0 != res) {
6608 fprintf(stderr, "sg_read2 failed, skip=%d\n",
6609 skip);
6610 break;
6611 } else
6612 in_full += blocks;
6613 } else {
6614 while (((res = read(infd, wrkPos, blocks * bs)) < 0) &&
6615 (EINTR == errno)) ;
6616 if (res < 0) {
6617 snprintf(ebuff, EBUFF_SZ,
6618 ME "reading, skip=%d ", skip);
6619 perror(ebuff);
6620 break;
6621 } else if (res < blocks * bs) {
6622 dd_count = 0;
6623 blocks = res / bs;
6624 if ((res % bs) > 0) {
6625 blocks++;
6626 in_partial++;
6627 }
6628 }
6629 in_full += blocks;
6630 }
6631
6632 if (FT_SG == out_type) {
6633 int do_mmap = (FT_SG == in_type) ? 0 : 1;
6634 int fua = fua_mode & 1;
6635 int dio_res = do_dio;
6636
6637 res =
6638 sg_write2(outfd, wrkPos, blocks, seek, bs,
6639 scsi_cdbsz, fua, do_mmap, &dio_res);
6640 if (2 == res) {
6641 fprintf(stderr,
6642 "Unit attention, media changed, continuing (w)\n");
6643 res =
6644 sg_write2(outfd, wrkPos, blocks, seek, bs,
6645 scsi_cdbsz, fua, do_mmap,
6646 &dio_res);
6647 } else if (0 != res) {
6648 fprintf(stderr, "sg_write2 failed, seek=%d\n",
6649 seek);
6650 break;
6651 } else {
6652 out_full += blocks;
6653 if (do_dio && (0 == dio_res))
6654 num_dio_not_done++;
6655 }
6656 } else if (FT_DEV_NULL == out_type)
6657 out_full += blocks; /* act as if written out without error */
6658 else {
6659 while (((res = write(outfd, wrkPos, blocks * bs)) < 0)
6660 && (EINTR == errno)) ;
6661 if (res < 0) {
6662 snprintf(ebuff, EBUFF_SZ,
6663 ME "writing, seek=%d ", seek);
6664 perror(ebuff);
6665 break;
6666 } else if (res < blocks * bs) {
6667 fprintf(stderr,
6668 "output file probably full, seek=%d ",
6669 seek);
6670 blocks = res / bs;
6671 out_full += blocks;
6672 if ((res % bs) > 0)
6673 out_partial++;
6674 break;
6675 } else
6676 out_full += blocks;
6677 }
6678 if (dd_count > 0)
6679 dd_count -= blocks;
6680 skip += blocks;
6681 seek += blocks;
6682 }
6683 if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
6684 struct timeval res_tm;
6685 double a, b;
6686
6687 gettimeofday(&end_tm, NULL);
6688 res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
6689 res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
6690 if (res_tm.tv_usec < 0) {
6691 --res_tm.tv_sec;
6692 res_tm.tv_usec += 1000000;
6693 }
6694 a = res_tm.tv_sec;
6695 a += (0.000001 * res_tm.tv_usec);
6696 b = (double)bs *(req_count - dd_count);
6697 printf("time to transfer data was %d.%06d secs",
6698 (int)res_tm.tv_sec, (int)res_tm.tv_usec);
6699 if ((a > 0.00001) && (b > 511))
6700 printf(", %.2f MB/sec\n", b / (a * 1000000.0));
6701 else
6702 printf("\n");
6703 }
6704 if (do_sync) {
6705 if (FT_SG == out_type) {
6706 fprintf(stderr, ">> Synchronizing cache on %s\n", outf);
6707 res = sync_cache(outfd);
6708 if (2 == res) {
6709 fprintf(stderr,
6710 "Unit attention, media changed(in), continuing\n");
6711 res = sync_cache(outfd);
6712 }
6713 if (0 != res)
6714 fprintf(stderr,
6715 "Unable to synchronize cache\n");
6716 }
6717 }
6718
6719 if (wrkBuff)
6720 free(wrkBuff);
6721 if (STDIN_FILENO != infd)
6722 close(infd);
6723 if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type))
6724 close(outfd);
6725 res = 0;
6726 if (0 != dd_count) {
6727 fprintf(stderr, "Some error occurred,");
6728 res = 2;
6729 }
6730 print_stats();
6731 if (sum_of_resids)
6732 fprintf(stderr, ">> Non-zero sum of residual counts=%d\n",
6733 sum_of_resids);
6734 if (num_dio_not_done)
6735 fprintf(stderr, ">> dio requested but _not done %d times\n",
6736 num_dio_not_done);
6737 return res;
6738 }
6739
guarded_stop_in(Rq_coll * clp)6740 static void guarded_stop_in(Rq_coll * clp)
6741 {
6742 pthread_mutex_lock(&clp->in_mutex);
6743 clp->in_stop = 1;
6744 pthread_mutex_unlock(&clp->in_mutex);
6745 }
6746
guarded_stop_out(Rq_coll * clp)6747 static void guarded_stop_out(Rq_coll * clp)
6748 {
6749 pthread_mutex_lock(&clp->out_mutex);
6750 clp->out_stop = 1;
6751 pthread_mutex_unlock(&clp->out_mutex);
6752 }
6753
guarded_stop_both(Rq_coll * clp)6754 static void guarded_stop_both(Rq_coll * clp)
6755 {
6756 guarded_stop_in(clp);
6757 guarded_stop_out(clp);
6758 }
6759
sig_listen_thread(void * v_clp)6760 void *sig_listen_thread(void *v_clp)
6761 {
6762 Rq_coll *clp = (Rq_coll *) v_clp;
6763 int sig_number;
6764
6765 while (1) {
6766 sigwait(&signal_set, &sig_number);
6767 if (SIGINT == sig_number) {
6768 fprintf(stderr, ME "interrupted by SIGINT\n");
6769 guarded_stop_both(clp);
6770 pthread_cond_broadcast(&clp->out_sync_cv);
6771 }
6772 }
6773 return NULL;
6774 }
6775
cleanup_in(void * v_clp)6776 void cleanup_in(void *v_clp)
6777 {
6778 Rq_coll *clp = (Rq_coll *) v_clp;
6779
6780 fprintf(stderr, "thread cancelled while in mutex held\n");
6781 clp->in_stop = 1;
6782 pthread_mutex_unlock(&clp->in_mutex);
6783 guarded_stop_out(clp);
6784 pthread_cond_broadcast(&clp->out_sync_cv);
6785 }
6786
cleanup_out(void * v_clp)6787 void cleanup_out(void *v_clp)
6788 {
6789 Rq_coll *clp = (Rq_coll *) v_clp;
6790
6791 fprintf(stderr, "thread cancelled while out mutex held\n");
6792 clp->out_stop = 1;
6793 pthread_mutex_unlock(&clp->out_mutex);
6794 guarded_stop_in(clp);
6795 pthread_cond_broadcast(&clp->out_sync_cv);
6796 }
6797
read_write_thread(void * v_clp)6798 void *read_write_thread(void *v_clp)
6799 {
6800 Rq_coll *clp = (Rq_coll *) v_clp;
6801 Rq_elem rel;
6802 Rq_elem *rep = &rel;
6803 size_t psz = 0;
6804 int sz = clp->bpt * clp->bs;
6805 int stop_after_write = 0;
6806 int seek_skip = clp->seek - clp->skip;
6807 int blocks, status;
6808
6809 memset(rep, 0, sizeof(Rq_elem));
6810 psz = getpagesize();
6811 if (NULL == (rep->alloc_bp = malloc(sz + psz)))
6812 err_exit(ENOMEM, "out of memory creating user buffers\n");
6813 rep->buffp =
6814 (unsigned char *)(((unsigned long)rep->alloc_bp + psz - 1) &
6815 (~(psz - 1)));
6816 /* Follow clp members are constant during lifetime of thread */
6817 rep->bs = clp->bs;
6818 rep->fua_mode = clp->fua_mode;
6819 rep->dio = clp->dio;
6820 rep->infd = clp->infd;
6821 rep->outfd = clp->outfd;
6822 rep->debug = clp->debug;
6823 rep->in_scsi_type = clp->in_scsi_type;
6824 rep->out_scsi_type = clp->out_scsi_type;
6825 rep->cdbsz = clp->cdbsz;
6826
6827 while (1) {
6828 status = pthread_mutex_lock(&clp->in_mutex);
6829 if (0 != status)
6830 err_exit(status, "lock in_mutex");
6831 if (clp->in_stop || (clp->in_count <= 0)) {
6832 /* no more to do, exit loop then thread */
6833 status = pthread_mutex_unlock(&clp->in_mutex);
6834 if (0 != status)
6835 err_exit(status, "unlock in_mutex");
6836 break;
6837 }
6838 blocks = (clp->in_count > clp->bpt) ? clp->bpt : clp->in_count;
6839 rep->wr = 0;
6840 rep->blk = clp->in_blk;
6841 rep->num_blks = blocks;
6842 clp->in_blk += blocks;
6843 clp->in_count -= blocks;
6844
6845 pthread_cleanup_push(cleanup_in, (void *)clp);
6846 if (FT_SG == clp->in_type)
6847 sg_in_operation(clp, rep); /* lets go of in_mutex mid operation */
6848 else {
6849 stop_after_write =
6850 normal_in_operation(clp, rep, blocks);
6851 status = pthread_mutex_unlock(&clp->in_mutex);
6852 if (0 != status)
6853 err_exit(status, "unlock in_mutex");
6854 }
6855 pthread_cleanup_pop(0);
6856
6857 status = pthread_mutex_lock(&clp->out_mutex);
6858 if (0 != status)
6859 err_exit(status, "lock out_mutex");
6860 if (FT_DEV_NULL != clp->out_type) {
6861 while ((!clp->out_stop) &&
6862 ((rep->blk + seek_skip) != clp->out_blk)) {
6863 /* if write would be out of sequence then wait */
6864 pthread_cleanup_push(cleanup_out, (void *)clp);
6865 status =
6866 pthread_cond_wait(&clp->out_sync_cv,
6867 &clp->out_mutex);
6868 if (0 != status)
6869 err_exit(status, "cond out_sync_cv");
6870 pthread_cleanup_pop(0);
6871 }
6872 }
6873
6874 if (clp->out_stop || (clp->out_count <= 0)) {
6875 if (!clp->out_stop)
6876 clp->out_stop = 1;
6877 status = pthread_mutex_unlock(&clp->out_mutex);
6878 if (0 != status)
6879 err_exit(status, "unlock out_mutex");
6880 break;
6881 }
6882 if (stop_after_write)
6883 clp->out_stop = 1;
6884 rep->wr = 1;
6885 rep->blk = clp->out_blk;
6886 /* rep->num_blks = blocks; */
6887 clp->out_blk += blocks;
6888 clp->out_count -= blocks;
6889
6890 pthread_cleanup_push(cleanup_out, (void *)clp);
6891 if (FT_SG == clp->out_type)
6892 sg_out_operation(clp, rep); /* releases out_mutex mid operation */
6893 else if (FT_DEV_NULL == clp->out_type) {
6894 /* skip actual write operation */
6895 clp->out_done_count -= blocks;
6896 status = pthread_mutex_unlock(&clp->out_mutex);
6897 if (0 != status)
6898 err_exit(status, "unlock out_mutex");
6899 } else {
6900 normal_out_operation(clp, rep, blocks);
6901 status = pthread_mutex_unlock(&clp->out_mutex);
6902 if (0 != status)
6903 err_exit(status, "unlock out_mutex");
6904 }
6905 pthread_cleanup_pop(0);
6906
6907 if (stop_after_write)
6908 break;
6909 pthread_cond_broadcast(&clp->out_sync_cv);
6910 } /* end of while loop */
6911 if (rep->alloc_bp)
6912 free(rep->alloc_bp);
6913 status = pthread_mutex_lock(&clp->in_mutex);
6914 if (0 != status)
6915 err_exit(status, "lock in_mutex");
6916 if (!clp->in_stop)
6917 clp->in_stop = 1; /* flag other workers to stop */
6918 status = pthread_mutex_unlock(&clp->in_mutex);
6919 if (0 != status)
6920 err_exit(status, "unlock in_mutex");
6921 pthread_cond_broadcast(&clp->out_sync_cv);
6922 return stop_after_write ? NULL : v_clp;
6923 }
6924
normal_in_operation(Rq_coll * clp,Rq_elem * rep,int blocks)6925 int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks)
6926 {
6927 int res;
6928 int stop_after_write = 0;
6929
6930 /* enters holding in_mutex */
6931 while (((res = read(clp->infd, rep->buffp,
6932 blocks * clp->bs)) < 0) && (EINTR == errno)) ;
6933 if (res < 0) {
6934 if (clp->coe) {
6935 memset(rep->buffp, 0, rep->num_blks * rep->bs);
6936 fprintf(stderr,
6937 ">> substituted zeros for in blk=%d for "
6938 "%d bytes, %s\n", rep->blk,
6939 rep->num_blks * rep->bs, strerror(errno));
6940 res = rep->num_blks * clp->bs;
6941 } else {
6942 fprintf(stderr, "error in normal read, %s\n",
6943 strerror(errno));
6944 clp->in_stop = 1;
6945 guarded_stop_out(clp);
6946 return 1;
6947 }
6948 }
6949 if (res < blocks * clp->bs) {
6950 int o_blocks = blocks;
6951 stop_after_write = 1;
6952 blocks = res / clp->bs;
6953 if ((res % clp->bs) > 0) {
6954 blocks++;
6955 clp->in_partial++;
6956 }
6957 /* Reverse out + re-apply blocks on clp */
6958 clp->in_blk -= o_blocks;
6959 clp->in_count += o_blocks;
6960 rep->num_blks = blocks;
6961 clp->in_blk += blocks;
6962 clp->in_count -= blocks;
6963 }
6964 clp->in_done_count -= blocks;
6965 return stop_after_write;
6966 }
6967
normal_out_operation(Rq_coll * clp,Rq_elem * rep,int blocks)6968 void normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks)
6969 {
6970 int res;
6971
6972 /* enters holding out_mutex */
6973 while (((res = write(clp->outfd, rep->buffp,
6974 rep->num_blks * clp->bs)) < 0)
6975 && (EINTR == errno)) ;
6976 if (res < 0) {
6977 if (clp->coe) {
6978 fprintf(stderr, ">> ignored error for out blk=%d for "
6979 "%d bytes, %s\n", rep->blk,
6980 rep->num_blks * rep->bs, strerror(errno));
6981 res = rep->num_blks * clp->bs;
6982 } else {
6983 fprintf(stderr, "error normal write, %s\n",
6984 strerror(errno));
6985 guarded_stop_in(clp);
6986 clp->out_stop = 1;
6987 return;
6988 }
6989 }
6990 if (res < blocks * clp->bs) {
6991 blocks = res / clp->bs;
6992 if ((res % clp->bs) > 0) {
6993 blocks++;
6994 clp->out_partial++;
6995 }
6996 rep->num_blks = blocks;
6997 }
6998 clp->out_done_count -= blocks;
6999 }
7000
sg_in_operation(Rq_coll * clp,Rq_elem * rep)7001 void sg_in_operation(Rq_coll * clp, Rq_elem * rep)
7002 {
7003 int res;
7004 int status;
7005
7006 /* enters holding in_mutex */
7007 while (1) {
7008 res = sg_start_io(rep);
7009 if (1 == res)
7010 err_exit(ENOMEM, "sg starting in command");
7011 else if (res < 0) {
7012 fprintf(stderr, ME "inputting to sg failed, blk=%d\n",
7013 rep->blk);
7014 status = pthread_mutex_unlock(&clp->in_mutex);
7015 if (0 != status)
7016 err_exit(status, "unlock in_mutex");
7017 guarded_stop_both(clp);
7018 return;
7019 }
7020 /* Now release in mutex to let other reads run in parallel */
7021 status = pthread_mutex_unlock(&clp->in_mutex);
7022 if (0 != status)
7023 err_exit(status, "unlock in_mutex");
7024
7025 res = sg_finish_io(rep->wr, rep, &clp->aux_mutex);
7026 if (res < 0) {
7027 if (clp->coe) {
7028 memset(rep->buffp, 0, rep->num_blks * rep->bs);
7029 fprintf(stderr,
7030 ">> substituted zeros for in blk=%d for "
7031 "%d bytes\n", rep->blk,
7032 rep->num_blks * rep->bs);
7033 } else {
7034 fprintf(stderr,
7035 "error finishing sg in command\n");
7036 guarded_stop_both(clp);
7037 return;
7038 }
7039 }
7040 if (res <= 0) { /* looks good, going to return */
7041 if (rep->dio_incomplete || rep->resid) {
7042 status = pthread_mutex_lock(&clp->aux_mutex);
7043 if (0 != status)
7044 err_exit(status, "lock aux_mutex");
7045 clp->dio_incomplete += rep->dio_incomplete;
7046 clp->sum_of_resids += rep->resid;
7047 status = pthread_mutex_unlock(&clp->aux_mutex);
7048 if (0 != status)
7049 err_exit(status, "unlock aux_mutex");
7050 }
7051 status = pthread_mutex_lock(&clp->in_mutex);
7052 if (0 != status)
7053 err_exit(status, "lock in_mutex");
7054 clp->in_done_count -= rep->num_blks;
7055 status = pthread_mutex_unlock(&clp->in_mutex);
7056 if (0 != status)
7057 err_exit(status, "unlock in_mutex");
7058 return;
7059 }
7060 /* else assume 1 == res so try again with same addr, count info */
7061 /* now re-acquire read mutex for balance */
7062 /* N.B. This re-read could now be out of read sequence */
7063 status = pthread_mutex_lock(&clp->in_mutex);
7064 if (0 != status)
7065 err_exit(status, "lock in_mutex");
7066 }
7067 }
7068
sg_out_operation(Rq_coll * clp,Rq_elem * rep)7069 void sg_out_operation(Rq_coll * clp, Rq_elem * rep)
7070 {
7071 int res;
7072 int status;
7073
7074 /* enters holding out_mutex */
7075 while (1) {
7076 res = sg_start_io(rep);
7077 if (1 == res)
7078 err_exit(ENOMEM, "sg starting out command");
7079 else if (res < 0) {
7080 fprintf(stderr,
7081 ME "outputting from sg failed, blk=%d\n",
7082 rep->blk);
7083 status = pthread_mutex_unlock(&clp->out_mutex);
7084 if (0 != status)
7085 err_exit(status, "unlock out_mutex");
7086 guarded_stop_both(clp);
7087 return;
7088 }
7089 /* Now release in mutex to let other reads run in parallel */
7090 status = pthread_mutex_unlock(&clp->out_mutex);
7091 if (0 != status)
7092 err_exit(status, "unlock out_mutex");
7093
7094 res = sg_finish_io(rep->wr, rep, &clp->aux_mutex);
7095 if (res < 0) {
7096 if (clp->coe)
7097 fprintf(stderr,
7098 ">> ignored error for out blk=%d for "
7099 "%d bytes\n", rep->blk,
7100 rep->num_blks * rep->bs);
7101 else {
7102 fprintf(stderr,
7103 "error finishing sg out command\n");
7104 guarded_stop_both(clp);
7105 return;
7106 }
7107 }
7108 if (res <= 0) {
7109 if (rep->dio_incomplete || rep->resid) {
7110 status = pthread_mutex_lock(&clp->aux_mutex);
7111 if (0 != status)
7112 err_exit(status, "lock aux_mutex");
7113 clp->dio_incomplete += rep->dio_incomplete;
7114 clp->sum_of_resids += rep->resid;
7115 status = pthread_mutex_unlock(&clp->aux_mutex);
7116 if (0 != status)
7117 err_exit(status, "unlock aux_mutex");
7118 }
7119 status = pthread_mutex_lock(&clp->out_mutex);
7120 if (0 != status)
7121 err_exit(status, "lock out_mutex");
7122 clp->out_done_count -= rep->num_blks;
7123 status = pthread_mutex_unlock(&clp->out_mutex);
7124 if (0 != status)
7125 err_exit(status, "unlock out_mutex");
7126 return;
7127 }
7128 /* else assume 1 == res so try again with same addr, count info */
7129 /* now re-acquire out mutex for balance */
7130 /* N.B. This re-write could now be out of write sequence */
7131 status = pthread_mutex_lock(&clp->out_mutex);
7132 if (0 != status)
7133 err_exit(status, "lock out_mutex");
7134 }
7135 }
7136
sg_start_io(Rq_elem * rep)7137 int sg_start_io(Rq_elem * rep)
7138 {
7139 sg_io_hdr_t *hp = &rep->io_hdr;
7140 int fua = rep->wr ? (rep->fua_mode & 1) : (rep->fua_mode & 2);
7141 int res;
7142
7143 if (sg_build_scsi_cdb(rep->cmd, rep->cdbsz, rep->num_blks, rep->blk,
7144 rep->wr, fua, 0)) {
7145 fprintf(stderr, ME "bad cdb build, start_blk=%d, blocks=%d\n",
7146 rep->blk, rep->num_blks);
7147 return -1;
7148 }
7149 memset(hp, 0, sizeof(sg_io_hdr_t));
7150 hp->interface_id = 'S';
7151 hp->cmd_len = rep->cdbsz;
7152 hp->cmdp = rep->cmd;
7153 hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
7154 hp->dxfer_len = rep->bs * rep->num_blks;
7155 hp->dxferp = rep->buffp;
7156 hp->mx_sb_len = sizeof(rep->sb);
7157 hp->sbp = rep->sb;
7158 hp->timeout = DEF_TIMEOUT;
7159 hp->usr_ptr = rep;
7160 hp->pack_id = rep->blk;
7161 if (rep->dio)
7162 hp->flags |= SG_FLAG_DIRECT_IO;
7163 if (rep->debug > 8) {
7164 fprintf(stderr, "sg_start_io: SCSI %s, blk=%d num_blks=%d\n",
7165 rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks);
7166 sg_print_command(hp->cmdp);
7167 fprintf(stderr, "dir=%d, len=%d, dxfrp=%p, cmd_len=%d\n",
7168 hp->dxfer_direction, hp->dxfer_len, hp->dxferp,
7169 hp->cmd_len);
7170 }
7171
7172 while (((res = write(rep->wr ? rep->outfd : rep->infd, hp,
7173 sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno)) ;
7174 if (res < 0) {
7175 if (ENOMEM == errno)
7176 return 1;
7177 perror("starting io on sg device, error");
7178 return -1;
7179 }
7180 return 0;
7181 }
7182
7183 /* -1 -> unrecoverable error, 0 -> successful, 1 -> try again */
sg_finish_io(int wr,Rq_elem * rep,pthread_mutex_t * a_mutp)7184 int sg_finish_io(int wr, Rq_elem * rep, pthread_mutex_t * a_mutp)
7185 {
7186 int res, status;
7187 sg_io_hdr_t io_hdr;
7188 sg_io_hdr_t *hp;
7189 #if 0
7190 static int testing = 0; /* thread dubious! */
7191 #endif
7192
7193 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
7194 /* FORCE_PACK_ID active set only read packet with matching pack_id */
7195 io_hdr.interface_id = 'S';
7196 io_hdr.dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV;
7197 io_hdr.pack_id = rep->blk;
7198
7199 while (((res = read(wr ? rep->outfd : rep->infd, &io_hdr,
7200 sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno)) ;
7201 if (res < 0) {
7202 perror("finishing io on sg device, error");
7203 return -1;
7204 }
7205 if (rep != (Rq_elem *) io_hdr.usr_ptr)
7206 err_exit(0,
7207 "sg_finish_io: bad usr_ptr, request-response mismatch\n");
7208 memcpy(&rep->io_hdr, &io_hdr, sizeof(sg_io_hdr_t));
7209 hp = &rep->io_hdr;
7210
7211 switch (sg_err_category3(hp)) {
7212 case SG_ERR_CAT_CLEAN:
7213 break;
7214 case SG_ERR_CAT_RECOVERED:
7215 fprintf(stderr, "Recovered error on block=%d, num=%d\n",
7216 rep->blk, rep->num_blks);
7217 break;
7218 case SG_ERR_CAT_MEDIA_CHANGED:
7219 return 1;
7220 default:
7221 {
7222 char ebuff[EBUFF_SZ];
7223
7224 snprintf(ebuff, EBUFF_SZ,
7225 "%s blk=%d", rep->wr ? "writing" : "reading",
7226 rep->blk);
7227 status = pthread_mutex_lock(a_mutp);
7228 if (0 != status)
7229 err_exit(status, "lock aux_mutex");
7230 sg_chk_n_print3(ebuff, hp);
7231 status = pthread_mutex_unlock(a_mutp);
7232 if (0 != status)
7233 err_exit(status, "unlock aux_mutex");
7234 return -1;
7235 }
7236 }
7237 #if 0
7238 if (0 == (++testing % 100))
7239 return -1;
7240 #endif
7241 if (rep->dio &&
7242 ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO))
7243 rep->dio_incomplete = 1; /* count dios done as indirect IO */
7244 else
7245 rep->dio_incomplete = 0;
7246 rep->resid = hp->resid;
7247 if (rep->debug > 8)
7248 fprintf(stderr, "sg_finish_io: completed %s\n",
7249 wr ? "WRITE" : "READ");
7250 return 0;
7251 }
7252
sg_prepare(int fd,int bs,int bpt,int * scsi_typep)7253 int sg_prepare(int fd, int bs, int bpt, int *scsi_typep)
7254 {
7255 int res, t;
7256
7257 res = ioctl(fd, SG_GET_VERSION_NUM, &t);
7258 if ((res < 0) || (t < 30000)) {
7259 fprintf(stderr, ME "sg driver prior to 3.x.y\n");
7260 return 1;
7261 }
7262 res = 0;
7263 t = bs * bpt;
7264 res = ioctl(fd, SG_SET_RESERVED_SIZE, &t);
7265 if (res < 0)
7266 perror(ME "SG_SET_RESERVED_SIZE error");
7267 t = 1;
7268 res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t);
7269 if (res < 0)
7270 perror(ME "SG_SET_FORCE_PACK_ID error");
7271 if (scsi_typep) {
7272 struct sg_scsi_id info;
7273
7274 res = ioctl(fd, SG_GET_SCSI_ID, &info);
7275 if (res < 0)
7276 perror(ME "SG_SET_SCSI_ID error");
7277 *scsi_typep = info.scsi_type;
7278 }
7279 return 0;
7280 }
7281
do_scsi_sgp_read_write(char * device)7282 int do_scsi_sgp_read_write(char *device)
7283 {
7284 int skip = 0;
7285 int seek = 0;
7286 int count = -1;
7287 char inf[INOUTF_SZ];
7288 char outf[INOUTF_SZ];
7289 int res, k;
7290 int in_num_sect = 0;
7291 int out_num_sect = 0;
7292 int num_threads = DEF_NUM_THREADS;
7293 pthread_t threads[MAX_NUM_THREADS];
7294 int do_time = 1;
7295 int do_sync = 1;
7296 int in_sect_sz, out_sect_sz, status, infull, outfull;
7297 void *vp;
7298 char ebuff[EBUFF_SZ];
7299 struct timeval start_tm, end_tm;
7300 Rq_coll rcoll;
7301
7302 print_msg(TEST_BREAK, __FUNCTION__);
7303
7304 memset(&rcoll, 0, sizeof(Rq_coll));
7305 rcoll.bpt = DEF_BLOCKS_PER_TRANSFER;
7306 rcoll.in_type = FT_OTHER;
7307 rcoll.out_type = FT_OTHER;
7308 rcoll.cdbsz = DEF_SCSI_CDBSZ;
7309
7310 strcpy(inf, "/dev/zero");
7311 strcpy(outf, device);
7312
7313 if (rcoll.bs <= 0) {
7314 rcoll.bs = DEF_BLOCK_SIZE;
7315 fprintf(stderr,
7316 "Assume default 'bs' (block size) of %d bytes\n",
7317 rcoll.bs);
7318 }
7319
7320 if (rcoll.debug)
7321 fprintf(stderr, ME "if=%s skip=%d of=%s seek=%d count=%d\n",
7322 inf, skip, outf, seek, count);
7323
7324 rcoll.infd = STDIN_FILENO;
7325 rcoll.outfd = STDOUT_FILENO;
7326 if (inf[0] && ('-' != inf[0])) {
7327 rcoll.in_type = dd_filetype(inf);
7328
7329 if (FT_ST == rcoll.in_type) {
7330 fprintf(stderr,
7331 ME "unable to use scsi tape device %s\n", inf);
7332 return 1;
7333 } else if (FT_SG == rcoll.in_type) {
7334 if ((rcoll.infd = open(inf, O_RDWR)) < 0) {
7335 snprintf(ebuff, EBUFF_SZ,
7336 ME "could not open %s for sg reading",
7337 inf);
7338 perror(ebuff);
7339 return 1;
7340 }
7341 if (sg_prepare(rcoll.infd, rcoll.bs, rcoll.bpt,
7342 &rcoll.in_scsi_type))
7343 return 1;
7344 } else {
7345 if ((rcoll.infd = open(inf, O_RDONLY)) < 0) {
7346 snprintf(ebuff, EBUFF_SZ,
7347 ME "could not open %s for reading",
7348 inf);
7349 perror(ebuff);
7350 return 1;
7351 } else if (skip > 0) {
7352 llse_loff_t offset = skip;
7353
7354 offset *= rcoll.bs; /* could exceed 32 here! */
7355 if (llse_llseek(rcoll.infd, offset, SEEK_SET) <
7356 0) {
7357 snprintf(ebuff, EBUFF_SZ,
7358 ME
7359 "couldn't skip to required position on %s",
7360 inf);
7361 perror(ebuff);
7362 return 1;
7363 }
7364 }
7365 }
7366 }
7367 if (outf[0] && ('-' != outf[0])) {
7368 rcoll.out_type = dd_filetype(outf);
7369
7370 if (FT_ST == rcoll.out_type) {
7371 fprintf(stderr,
7372 ME "unable to use scsi tape device %s\n", outf);
7373 return 1;
7374 } else if (FT_SG == rcoll.out_type) {
7375 if ((rcoll.outfd = open(outf, O_RDWR)) < 0) {
7376 snprintf(ebuff, EBUFF_SZ,
7377 ME "could not open %s for sg writing",
7378 outf);
7379 perror(ebuff);
7380 return 1;
7381 }
7382
7383 if (sg_prepare(rcoll.outfd, rcoll.bs, rcoll.bpt,
7384 &rcoll.out_scsi_type))
7385 return 1;
7386 } else if (FT_DEV_NULL == rcoll.out_type)
7387 rcoll.outfd = -1; /* don't bother opening */
7388 else {
7389 if (FT_RAW != rcoll.out_type) {
7390 if ((rcoll.outfd =
7391 open(outf, O_WRONLY | O_CREAT,
7392 0666)) < 0) {
7393 snprintf(ebuff, EBUFF_SZ,
7394 ME
7395 "could not open %s for writing",
7396 outf);
7397 perror(ebuff);
7398 return 1;
7399 }
7400 } else {
7401 if ((rcoll.outfd = open(outf, O_WRONLY)) < 0) {
7402 snprintf(ebuff, EBUFF_SZ,
7403 ME
7404 "could not open %s for raw writing",
7405 outf);
7406 perror(ebuff);
7407 return 1;
7408 }
7409 }
7410 if (seek > 0) {
7411 llse_loff_t offset = seek;
7412
7413 offset *= rcoll.bs; /* could exceed 32 bits here! */
7414 if (llse_llseek(rcoll.outfd, offset, SEEK_SET) <
7415 0) {
7416 snprintf(ebuff, EBUFF_SZ,
7417 ME
7418 "couldn't seek to required position on %s",
7419 outf);
7420 perror(ebuff);
7421 return 1;
7422 }
7423 }
7424 }
7425 }
7426 if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) {
7427 fprintf(stderr,
7428 "Disallow both if and of to be stdin and stdout");
7429 return 1;
7430 }
7431 if (count < 0) {
7432 if (FT_SG == rcoll.in_type) {
7433 res =
7434 read_capacity(rcoll.infd, &in_num_sect,
7435 &in_sect_sz);
7436 if (2 == res) {
7437 fprintf(stderr,
7438 "Unit attention, media changed(in), continuing\n");
7439 res =
7440 read_capacity(rcoll.infd, &in_num_sect,
7441 &in_sect_sz);
7442 }
7443 if (0 != res) {
7444 fprintf(stderr,
7445 "Unable to read capacity on %s\n", inf);
7446 in_num_sect = -1;
7447 } else {
7448 if (in_num_sect > skip)
7449 in_num_sect -= skip;
7450 }
7451 }
7452 if (FT_SG == rcoll.out_type) {
7453 res =
7454 read_capacity(rcoll.outfd, &out_num_sect,
7455 &out_sect_sz);
7456 if (2 == res) {
7457 fprintf(stderr,
7458 "Unit attention, media changed(out), continuing\n");
7459 res =
7460 read_capacity(rcoll.outfd, &out_num_sect,
7461 &out_sect_sz);
7462 }
7463 if (0 != res) {
7464 fprintf(stderr,
7465 "Unable to read capacity on %s\n",
7466 outf);
7467 out_num_sect = -1;
7468 } else {
7469 if (out_num_sect > seek)
7470 out_num_sect -= seek;
7471 }
7472 }
7473 if (in_num_sect > 0) {
7474 if (out_num_sect > 0)
7475 count =
7476 (in_num_sect >
7477 out_num_sect) ? out_num_sect : in_num_sect;
7478 else
7479 count = in_num_sect;
7480 } else
7481 count = out_num_sect;
7482 }
7483 if (rcoll.debug > 1)
7484 fprintf(stderr, "Start of loop, count=%d, in_num_sect=%d, "
7485 "out_num_sect=%d\n", count, in_num_sect, out_num_sect);
7486 if (count < 0) {
7487 fprintf(stderr, "Couldn't calculate count, please give one\n");
7488 return 1;
7489 }
7490
7491 rcoll.in_count = count;
7492 rcoll.in_done_count = count;
7493 rcoll.skip = skip;
7494 rcoll.in_blk = skip;
7495 rcoll.out_count = count;
7496 rcoll.out_done_count = count;
7497 rcoll.seek = seek;
7498 rcoll.out_blk = seek;
7499 status = pthread_mutex_init(&rcoll.in_mutex, NULL);
7500 if (0 != status)
7501 err_exit(status, "init in_mutex");
7502 status = pthread_mutex_init(&rcoll.out_mutex, NULL);
7503 if (0 != status)
7504 err_exit(status, "init out_mutex");
7505 status = pthread_mutex_init(&rcoll.aux_mutex, NULL);
7506 if (0 != status)
7507 err_exit(status, "init aux_mutex");
7508 status = pthread_cond_init(&rcoll.out_sync_cv, NULL);
7509 if (0 != status)
7510 err_exit(status, "init out_sync_cv");
7511
7512 sigemptyset(&signal_set);
7513 sigaddset(&signal_set, SIGINT);
7514 status = pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
7515 if (0 != status)
7516 err_exit(status, "pthread_sigmask");
7517 status = pthread_create(&sig_listen_thread_id, NULL,
7518 sig_listen_thread, (void *)&rcoll);
7519 if (0 != status)
7520 err_exit(status, "pthread_create, sig...");
7521
7522 if (do_time) {
7523 start_tm.tv_sec = 0;
7524 start_tm.tv_usec = 0;
7525 gettimeofday(&start_tm, NULL);
7526 }
7527
7528 /* vvvvvvvvvvv Start worker threads vvvvvvvvvvvvvvvvvvvvvvvv */
7529 if ((rcoll.out_done_count > 0) && (num_threads > 0)) {
7530 /* Run 1 work thread to shake down infant retryable stuff */
7531 status = pthread_mutex_lock(&rcoll.out_mutex);
7532 if (0 != status)
7533 err_exit(status, "lock out_mutex");
7534 status = pthread_create(&threads[0], NULL, read_write_thread,
7535 (void *)&rcoll);
7536 if (0 != status)
7537 err_exit(status, "pthread_create");
7538 if (rcoll.debug)
7539 fprintf(stderr, "Starting worker thread k=0\n");
7540
7541 /* wait for any broadcast */
7542 pthread_cleanup_push(cleanup_out, (void *)&rcoll);
7543 status =
7544 pthread_cond_wait(&rcoll.out_sync_cv, &rcoll.out_mutex);
7545 if (0 != status)
7546 err_exit(status, "cond out_sync_cv");
7547 pthread_cleanup_pop(0);
7548 status = pthread_mutex_unlock(&rcoll.out_mutex);
7549 if (0 != status)
7550 err_exit(status, "unlock out_mutex");
7551
7552 /* now start the rest of the threads */
7553 for (k = 1; k < num_threads; ++k) {
7554 status =
7555 pthread_create(&threads[k], NULL, read_write_thread,
7556 (void *)&rcoll);
7557 if (0 != status)
7558 err_exit(status, "pthread_create");
7559 if (rcoll.debug)
7560 fprintf(stderr, "Starting worker thread k=%d\n",
7561 k);
7562 }
7563
7564 /* now wait for worker threads to finish */
7565 for (k = 0; k < num_threads; ++k) {
7566 status = pthread_join(threads[k], &vp);
7567 if (0 != status)
7568 err_exit(status, "pthread_join");
7569 if (rcoll.debug)
7570 fprintf(stderr,
7571 "Worker thread k=%d terminated\n", k);
7572 }
7573 }
7574
7575 if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) {
7576 struct timeval res_tm;
7577 double a, b;
7578
7579 gettimeofday(&end_tm, NULL);
7580 res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec;
7581 res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec;
7582 if (res_tm.tv_usec < 0) {
7583 --res_tm.tv_sec;
7584 res_tm.tv_usec += 1000000;
7585 }
7586 a = res_tm.tv_sec;
7587 a += (0.000001 * res_tm.tv_usec);
7588 b = (double)rcoll.bs * (count - rcoll.out_done_count);
7589 printf("time to transfer data was %d.%06d secs",
7590 (int)res_tm.tv_sec, (int)res_tm.tv_usec);
7591 if ((a > 0.00001) && (b > 511))
7592 printf(", %.2f MB/sec\n", b / (a * 1000000.0));
7593 else
7594 printf("\n");
7595 }
7596 if (do_sync) {
7597 if (FT_SG == rcoll.out_type) {
7598 fprintf(stderr, ">> Synchronizing cache on %s\n", outf);
7599 res = sync_cache(rcoll.outfd);
7600 if (2 == res) {
7601 fprintf(stderr,
7602 "Unit attention, media changed(in), continuing\n");
7603 res = sync_cache(rcoll.outfd);
7604 }
7605 if (0 != res)
7606 fprintf(stderr,
7607 "Unable to synchronize cache\n");
7608 }
7609 }
7610
7611 status = pthread_cancel(sig_listen_thread_id);
7612 if (0 != status)
7613 err_exit(status, "pthread_cancel");
7614 if (STDIN_FILENO != rcoll.infd)
7615 close(rcoll.infd);
7616 if ((STDOUT_FILENO != rcoll.outfd) && (FT_DEV_NULL != rcoll.out_type))
7617 close(rcoll.outfd);
7618 res = 0;
7619 if (0 != rcoll.out_count) {
7620 fprintf(stderr,
7621 ">>>> Some error occurred, remaining blocks=%d\n",
7622 rcoll.out_count);
7623 res = 2;
7624 }
7625 infull = count - rcoll.in_done_count - rcoll.in_partial;
7626 fprintf(stderr, "%d+%d records in\n", infull, rcoll.in_partial);
7627 outfull = count - rcoll.out_done_count - rcoll.out_partial;
7628 fprintf(stderr, "%d+%d records out\n", outfull, rcoll.out_partial);
7629 if (rcoll.dio_incomplete) {
7630 int fd;
7631 char c;
7632
7633 fprintf(stderr,
7634 ">> Direct IO requested but incomplete %d times\n",
7635 rcoll.dio_incomplete);
7636 if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) {
7637 if (1 == read(fd, &c, 1)) {
7638 if ('0' == c)
7639 fprintf(stderr,
7640 ">>> %s set to '0' but should be set "
7641 "to '1' for direct IO\n",
7642 proc_allow_dio);
7643 }
7644 close(fd);
7645 }
7646 }
7647 if (rcoll.sum_of_resids)
7648 fprintf(stderr, ">> Non-zero sum of residual counts=%d\n",
7649 rcoll.sum_of_resids);
7650 return res;
7651 }
7652