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