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