1 #include <unistd.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "sg_lib.h"
7 #include "sg_pt.h"
8
9 /* This is a simple program executing a SCSI INQUIRY command and a
10 TEST UNIT READY command using the SCSI generic pass through
11 interface. This allows this example program to be ported to
12 OSes other than linux.
13
14 * Copyright (C) 2006-20018 D. Gilbert
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2, or (at your option)
18 * any later version.
19
20 Invocation: sg_simple5 [-x] <scsi_device>
21
22 Version 1.03 (20180220)
23
24 */
25
26 #define INQ_REPLY_LEN 96
27 #define INQ_CMD_LEN 6
28 #define TUR_CMD_LEN 6
29
30 #define CMD_TIMEOUT_SECS 60
31
32
main(int argc,char * argv[])33 int main(int argc, char * argv[])
34 {
35 int sg_fd, k, ok, dsize, res, duration, resid, cat, got, slen;
36 uint8_t inq_cdb [INQ_CMD_LEN] =
37 {0x12, 0, 0, 0, INQ_REPLY_LEN, 0};
38 uint8_t tur_cdb [TUR_CMD_LEN] =
39 {0x00, 0, 0, 0, 0, 0};
40 uint8_t inqBuff[INQ_REPLY_LEN];
41 char * file_name = 0;
42 char b[512];
43 uint8_t sense_b[32];
44 int verbose = 0;
45 struct sg_pt_base * ptvp;
46
47 for (k = 1; k < argc; ++k) {
48 if (0 == strcmp("-v", argv[k]))
49 verbose = 1;
50 else if (0 == strcmp("-vv", argv[k]))
51 verbose = 2;
52 else if (0 == strcmp("-vvv", argv[k]))
53 verbose = 3;
54 else if (*argv[k] == '-') {
55 printf("Unrecognized switch: %s\n", argv[k]);
56 file_name = 0;
57 break;
58 }
59 else if (0 == file_name)
60 file_name = argv[k];
61 else {
62 printf("too many arguments\n");
63 file_name = 0;
64 break;
65 }
66 }
67 if (0 == file_name) {
68 printf("Usage: 'sg_simple5 [-v|-vv|-vvv] <device>'\n");
69 return 1;
70 }
71
72 sg_fd = scsi_pt_open_device(file_name, 1 /* ro */, 0);
73 /* N.B. An access mode of O_RDWR is required for some SCSI commands */
74 if (sg_fd < 0) {
75 fprintf(stderr, "error opening file: %s: %s\n",
76 file_name, safe_strerror(-sg_fd));
77 return 1;
78 }
79
80 dsize = sizeof(inqBuff);
81 ok = 0;
82
83 ptvp = construct_scsi_pt_obj(); /* one object per command */
84 if (NULL == ptvp) {
85 fprintf(stderr, "sg_simple5: out of memory\n");
86 return -1;
87 }
88 set_scsi_pt_cdb(ptvp, inq_cdb, sizeof(inq_cdb));
89 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
90 set_scsi_pt_data_in(ptvp, inqBuff, dsize);
91 res = do_scsi_pt(ptvp, sg_fd, CMD_TIMEOUT_SECS, verbose);
92 if (res < 0) {
93 fprintf(stderr, " pass through os error: %s\n",
94 safe_strerror(-res));
95 goto finish_inq;
96 } else if (SCSI_PT_DO_BAD_PARAMS == res) {
97 fprintf(stderr, " bad pass through setup\n");
98 goto finish_inq;
99 } else if (SCSI_PT_DO_TIMEOUT == res) {
100 fprintf(stderr, " pass through timeout\n");
101 goto finish_inq;
102 }
103 if ((verbose > 1) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0))
104 fprintf(stderr, " duration=%d ms\n", duration);
105 resid = get_scsi_pt_resid(ptvp);
106 switch ((cat = get_scsi_pt_result_category(ptvp))) {
107 case SCSI_PT_RESULT_GOOD:
108 got = dsize - resid;
109 if (verbose && (resid > 0))
110 fprintf(stderr, " requested %d bytes but "
111 "got %d bytes)\n", dsize, got);
112 break;
113 case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */
114 if (verbose) {
115 sg_get_scsi_status_str(get_scsi_pt_status_response(ptvp),
116 sizeof(b), b);
117 fprintf(stderr, " scsi status: %s\n", b);
118 }
119 goto finish_inq;
120 case SCSI_PT_RESULT_SENSE:
121 slen = get_scsi_pt_sense_len(ptvp);
122 if (verbose) {
123 sg_get_sense_str("", sense_b, slen, (verbose > 1),
124 sizeof(b), b);
125 fprintf(stderr, "%s", b);
126 }
127 if (verbose && (resid > 0)) {
128 got = dsize - resid;
129 if ((verbose) || (got > 0))
130 fprintf(stderr, " requested %d bytes but "
131 "got %d bytes\n", dsize, got);
132 }
133 goto finish_inq;
134 case SCSI_PT_RESULT_TRANSPORT_ERR:
135 if (verbose) {
136 get_scsi_pt_transport_err_str(ptvp, sizeof(b), b);
137 fprintf(stderr, " transport: %s", b);
138 }
139 goto finish_inq;
140 case SCSI_PT_RESULT_OS_ERR:
141 if (verbose) {
142 get_scsi_pt_os_err_str(ptvp, sizeof(b), b);
143 fprintf(stderr, " os: %s", b);
144 }
145 goto finish_inq;
146 default:
147 fprintf(stderr, " unknown pass through result "
148 "category (%d)\n", cat);
149 goto finish_inq;
150 }
151
152 ok = 1;
153 finish_inq:
154 destruct_scsi_pt_obj(ptvp);
155
156 if (ok) { /* output result if it is available */
157 char * p = (char *)inqBuff;
158
159 printf("Some of the INQUIRY command's results:\n");
160 printf(" %.8s %.16s %.4s\n", p + 8, p + 16, p + 32);
161 }
162 ok = 0;
163
164
165 /* Now prepare TEST UNIT READY command */
166 ptvp = construct_scsi_pt_obj(); /* one object per command */
167 if (NULL == ptvp) {
168 fprintf(stderr, "sg_simple5: out of memory\n");
169 return -1;
170 }
171 set_scsi_pt_cdb(ptvp, tur_cdb, sizeof(tur_cdb));
172 set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b));
173 /* no data in or out */
174 res = do_scsi_pt(ptvp, sg_fd, CMD_TIMEOUT_SECS, verbose);
175 if (res < 0) {
176 fprintf(stderr, " pass through os error: %s\n",
177 safe_strerror(-res));
178 goto finish_inq;
179 } else if (SCSI_PT_DO_BAD_PARAMS == res) {
180 fprintf(stderr, " bad pass through setup\n");
181 goto finish_inq;
182 } else if (SCSI_PT_DO_TIMEOUT == res) {
183 fprintf(stderr, " pass through timeout\n");
184 goto finish_inq;
185 }
186 if ((verbose > 1) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0))
187 fprintf(stderr, " duration=%d ms\n", duration);
188 resid = get_scsi_pt_resid(ptvp);
189 switch ((cat = get_scsi_pt_result_category(ptvp))) {
190 case SCSI_PT_RESULT_GOOD:
191 break;
192 case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */
193 if (verbose) {
194 sg_get_scsi_status_str(get_scsi_pt_status_response(ptvp),
195 sizeof(b), b);
196 fprintf(stderr, " scsi status: %s\n", b);
197 }
198 goto finish_tur;
199 case SCSI_PT_RESULT_SENSE:
200 slen = get_scsi_pt_sense_len(ptvp);
201 if (verbose) {
202 sg_get_sense_str("", sense_b, slen, (verbose > 1),
203 sizeof(b), b);
204 fprintf(stderr, "%s", b);
205 }
206 goto finish_tur;
207 case SCSI_PT_RESULT_TRANSPORT_ERR:
208 if (verbose) {
209 get_scsi_pt_transport_err_str(ptvp, sizeof(b), b);
210 fprintf(stderr, " transport: %s", b);
211 }
212 goto finish_tur;
213 case SCSI_PT_RESULT_OS_ERR:
214 if (verbose) {
215 get_scsi_pt_os_err_str(ptvp, sizeof(b), b);
216 fprintf(stderr, " os: %s", b);
217 }
218 goto finish_tur;
219 default:
220 fprintf(stderr, " unknown pass through result "
221 "category (%d)\n", cat);
222 goto finish_tur;
223 }
224
225 ok = 1;
226 finish_tur:
227 destruct_scsi_pt_obj(ptvp);
228
229 if (ok)
230 printf("Test Unit Ready successful so unit is ready!\n");
231 else
232 printf("Test Unit Ready failed so unit may _not_ be ready!\n");
233
234 scsi_pt_close_device(sg_fd);
235 return 0;
236 }
237