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