1 #include <unistd.h>
2 #include <fcntl.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <stdint.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <sys/ioctl.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include "sg_lib.h"
12 #include "sg_io_linux.h"
13
14 /* This program performs a READ_16 command as scsi mid-level support
15 16 byte commands from lk 2.4.15
16
17 * Copyright (C) 2001-2018 D. Gilbert
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2, or (at your option)
21 * any later version.
22
23 Invocation: sg_simple16 <scsi_device>
24
25 Version 1.04 (20180218)
26
27 */
28
29 #define READ16_REPLY_LEN 512
30 #define READ16_CMD_LEN 16
31
32 #define EBUFF_SZ 256
33
main(int argc,char * argv[])34 int main(int argc, char * argv[])
35 {
36 int sg_fd, k, ok;
37 uint8_t r16_cdb [READ16_CMD_LEN] =
38 {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0};
39 sg_io_hdr_t io_hdr;
40 char * file_name = 0;
41 char ebuff[EBUFF_SZ];
42 uint8_t inBuff[READ16_REPLY_LEN];
43 uint8_t sense_buffer[32];
44
45 for (k = 1; k < argc; ++k) {
46 if (*argv[k] == '-') {
47 printf("Unrecognized switch: %s\n", argv[k]);
48 file_name = 0;
49 break;
50 }
51 else if (0 == file_name)
52 file_name = argv[k];
53 else {
54 printf("too many arguments\n");
55 file_name = 0;
56 break;
57 }
58 }
59 if (0 == file_name) {
60 printf("Usage: 'sg_simple16 <sg_device>'\n");
61 return 1;
62 }
63
64 if ((sg_fd = open(file_name, O_RDWR)) < 0) {
65 snprintf(ebuff, EBUFF_SZ,
66 "sg_simple16: error opening file: %s", file_name);
67 perror(ebuff);
68 return 1;
69 }
70 /* Just to be safe, check we have a new sg device by trying an ioctl */
71 if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
72 printf("sg_simple16: %s doesn't seem to be an new sg device\n",
73 file_name);
74 close(sg_fd);
75 return 1;
76 }
77
78 /* Prepare READ_16 command */
79 memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
80 io_hdr.interface_id = 'S';
81 io_hdr.cmd_len = sizeof(r16_cdb);
82 /* io_hdr.iovec_count = 0; */ /* memset takes care of this */
83 io_hdr.mx_sb_len = sizeof(sense_buffer);
84 io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
85 io_hdr.dxfer_len = READ16_REPLY_LEN;
86 io_hdr.dxferp = inBuff;
87 io_hdr.cmdp = r16_cdb;
88 io_hdr.sbp = sense_buffer;
89 io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */
90 /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */
91 /* io_hdr.pack_id = 0; */
92 /* io_hdr.usr_ptr = NULL; */
93
94 if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) {
95 perror("sg_simple16: Inquiry SG_IO ioctl error");
96 close(sg_fd);
97 return 1;
98 }
99
100 /* now for the error processing */
101 ok = 0;
102 switch (sg_err_category3(&io_hdr)) {
103 case SG_LIB_CAT_CLEAN:
104 ok = 1;
105 break;
106 case SG_LIB_CAT_RECOVERED:
107 printf("Recovered error on READ_16, continuing\n");
108 ok = 1;
109 break;
110 default: /* won't bother decoding other categories */
111 sg_chk_n_print3("READ_16 command error", &io_hdr, 1);
112 break;
113 }
114
115 if (ok) { /* output result if it is available */
116 printf("READ_16 duration=%u millisecs, resid=%d, msg_status=%d\n",
117 io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status);
118 }
119
120 close(sg_fd);
121 return 0;
122 }
123