xref: /aosp_15_r20/external/sg3_utils/examples/sg_simple5.c (revision 44704f698541f6367e81f991ef8bb54ccbf3fc18)
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