1 /*
2 * Copyright (c) 1999-2018 Douglas Gilbert.
3 * All rights reserved.
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the BSD_LICENSE file.
6 */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <stdbool.h>
12 #include <string.h>
13 #include <ctype.h>
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif
18
19 #ifdef SG_LIB_LINUX
20
21 #include "sg_io_linux.h"
22
23
24 /* Version 1.07 20160405 */
25
26 #if defined(__GNUC__) || defined(__clang__)
27 static int pr2ws(const char * fmt, ...)
28 __attribute__ ((format (printf, 1, 2)));
29 #else
30 static int pr2ws(const char * fmt, ...);
31 #endif
32
33
34 static int
pr2ws(const char * fmt,...)35 pr2ws(const char * fmt, ...)
36 {
37 va_list args;
38 int n;
39
40 va_start(args, fmt);
41 n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args);
42 va_end(args);
43 return n;
44 }
45
46
47 void
sg_print_masked_status(int masked_status)48 sg_print_masked_status(int masked_status)
49 {
50 int scsi_status = (masked_status << 1) & 0x7e;
51
52 sg_print_scsi_status(scsi_status);
53 }
54
55 static const char * linux_host_bytes[] = {
56 "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT",
57 "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR",
58 "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR",
59 "DID_IMM_RETRY", "DID_REQUEUE", "DID_TRANSPORT_DISRUPTED",
60 "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE", "DID_NEXUS_FAILURE",
61 "DID_ALLOC_FAILURE", "DID_MEDIUM_ERROR",
62 };
63
64 #define LINUX_HOST_BYTES_SZ \
65 (int)(sizeof(linux_host_bytes) / sizeof(linux_host_bytes[0]))
66
67 void
sg_print_host_status(int host_status)68 sg_print_host_status(int host_status)
69 {
70 pr2ws("Host_status=0x%02x ", host_status);
71 if ((host_status < 0) || (host_status >= LINUX_HOST_BYTES_SZ))
72 pr2ws("is invalid ");
73 else
74 pr2ws("[%s] ", linux_host_bytes[host_status]);
75 }
76
77 static const char * linux_driver_bytes[] = {
78 "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA",
79 "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",
80 "DRIVER_SENSE"
81 };
82
83 #define LINUX_DRIVER_BYTES_SZ \
84 (int)(sizeof(linux_driver_bytes) / sizeof(linux_driver_bytes[0]))
85
86 #if 0
87 static const char * linux_driver_suggests[] = {
88 "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP",
89 "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN",
90 "SUGGEST_SENSE"
91 };
92
93 #define LINUX_DRIVER_SUGGESTS_SZ \
94 (int)(sizeof(linux_driver_suggests) / sizeof(linux_driver_suggests[0]))
95 #endif
96
97
98 void
sg_print_driver_status(int driver_status)99 sg_print_driver_status(int driver_status)
100 {
101 int driv;
102 const char * driv_cp = "invalid";
103
104 driv = driver_status & SG_LIB_DRIVER_MASK;
105 if (driv < LINUX_DRIVER_BYTES_SZ)
106 driv_cp = linux_driver_bytes[driv];
107 #if 0
108 sugg = (driver_status & SG_LIB_SUGGEST_MASK) >> 4;
109 if (sugg < LINUX_DRIVER_SUGGESTS_SZ)
110 sugg_cp = linux_driver_suggests[sugg];
111 #endif
112 pr2ws("Driver_status=0x%02x", driver_status);
113 pr2ws(" [%s] ", driv_cp);
114 }
115
116 /* Returns 1 if no errors found and thus nothing printed; otherwise
117 prints error/warning (prefix by 'leadin') and returns 0. */
118 static int
sg_linux_sense_print(const char * leadin,int scsi_status,int host_status,int driver_status,const unsigned char * sense_buffer,int sb_len,bool raw_sinfo)119 sg_linux_sense_print(const char * leadin, int scsi_status, int host_status,
120 int driver_status, const unsigned char * sense_buffer,
121 int sb_len, bool raw_sinfo)
122 {
123 bool done_leadin = false;
124 bool done_sense = false;
125
126 scsi_status &= 0x7e; /*sanity */
127 if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status))
128 return 1; /* No problems */
129 if (0 != scsi_status) {
130 if (leadin)
131 pr2ws("%s: ", leadin);
132 done_leadin = true;
133 pr2ws("SCSI status: ");
134 sg_print_scsi_status(scsi_status);
135 pr2ws("\n");
136 if (sense_buffer && ((scsi_status == SAM_STAT_CHECK_CONDITION) ||
137 (scsi_status == SAM_STAT_COMMAND_TERMINATED))) {
138 /* SAM_STAT_COMMAND_TERMINATED is obsolete */
139 sg_print_sense(0, sense_buffer, sb_len, raw_sinfo);
140 done_sense = true;
141 }
142 }
143 if (0 != host_status) {
144 if (leadin && (! done_leadin))
145 pr2ws("%s: ", leadin);
146 if (done_leadin)
147 pr2ws("plus...: ");
148 else
149 done_leadin = true;
150 sg_print_host_status(host_status);
151 pr2ws("\n");
152 }
153 if (0 != driver_status) {
154 if (done_sense &&
155 (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status)))
156 return 0;
157 if (leadin && (! done_leadin))
158 pr2ws("%s: ", leadin);
159 if (done_leadin)
160 pr2ws("plus...: ");
161 sg_print_driver_status(driver_status);
162 pr2ws("\n");
163 if (sense_buffer && (! done_sense) &&
164 (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status)))
165 sg_print_sense(0, sense_buffer, sb_len, raw_sinfo);
166 }
167 return 0;
168 }
169
170 #ifdef SG_IO
171
172 bool
sg_normalize_sense(const struct sg_io_hdr * hp,struct sg_scsi_sense_hdr * sshp)173 sg_normalize_sense(const struct sg_io_hdr * hp,
174 struct sg_scsi_sense_hdr * sshp)
175 {
176 if ((NULL == hp) || (0 == hp->sb_len_wr)) {
177 if (sshp)
178 memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
179 return 0;
180 }
181 return sg_scsi_normalize_sense(hp->sbp, hp->sb_len_wr, sshp);
182 }
183
184 /* Returns 1 if no errors found and thus nothing printed; otherwise
185 returns 0. */
186 int
sg_chk_n_print3(const char * leadin,struct sg_io_hdr * hp,bool raw_sinfo)187 sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp,
188 bool raw_sinfo)
189 {
190 return sg_linux_sense_print(leadin, hp->status, hp->host_status,
191 hp->driver_status, hp->sbp, hp->sb_len_wr,
192 raw_sinfo);
193 }
194 #endif
195
196 /* Returns 1 if no errors found and thus nothing printed; otherwise
197 returns 0. */
198 int
sg_chk_n_print(const char * leadin,int masked_status,int host_status,int driver_status,const unsigned char * sense_buffer,int sb_len,bool raw_sinfo)199 sg_chk_n_print(const char * leadin, int masked_status, int host_status,
200 int driver_status, const unsigned char * sense_buffer,
201 int sb_len, bool raw_sinfo)
202 {
203 int scsi_status = (masked_status << 1) & 0x7e;
204
205 return sg_linux_sense_print(leadin, scsi_status, host_status,
206 driver_status, sense_buffer, sb_len,
207 raw_sinfo);
208 }
209
210 #ifdef SG_IO
211 int
sg_err_category3(struct sg_io_hdr * hp)212 sg_err_category3(struct sg_io_hdr * hp)
213 {
214 return sg_err_category_new(hp->status, hp->host_status,
215 hp->driver_status, hp->sbp, hp->sb_len_wr);
216 }
217 #endif
218
219 int
sg_err_category(int masked_status,int host_status,int driver_status,const unsigned char * sense_buffer,int sb_len)220 sg_err_category(int masked_status, int host_status, int driver_status,
221 const unsigned char * sense_buffer, int sb_len)
222 {
223 int scsi_status = (masked_status << 1) & 0x7e;
224
225 return sg_err_category_new(scsi_status, host_status, driver_status,
226 sense_buffer, sb_len);
227 }
228
229 int
sg_err_category_new(int scsi_status,int host_status,int driver_status,const unsigned char * sense_buffer,int sb_len)230 sg_err_category_new(int scsi_status, int host_status, int driver_status,
231 const unsigned char * sense_buffer, int sb_len)
232 {
233 int masked_driver_status = (SG_LIB_DRIVER_MASK & driver_status);
234
235 scsi_status &= 0x7e;
236 if ((0 == scsi_status) && (0 == host_status) &&
237 (0 == masked_driver_status))
238 return SG_LIB_CAT_CLEAN;
239 if ((SAM_STAT_CHECK_CONDITION == scsi_status) ||
240 (SAM_STAT_COMMAND_TERMINATED == scsi_status) ||
241 (SG_LIB_DRIVER_SENSE == masked_driver_status))
242 return sg_err_category_sense(sense_buffer, sb_len);
243 if (0 != host_status) {
244 if ((SG_LIB_DID_NO_CONNECT == host_status) ||
245 (SG_LIB_DID_BUS_BUSY == host_status) ||
246 (SG_LIB_DID_TIME_OUT == host_status))
247 return SG_LIB_CAT_TIMEOUT;
248 if (SG_LIB_DID_NEXUS_FAILURE == host_status)
249 return SG_LIB_CAT_RES_CONFLICT;
250 }
251 if (SG_LIB_DRIVER_TIMEOUT == masked_driver_status)
252 return SG_LIB_CAT_TIMEOUT;
253 return SG_LIB_CAT_OTHER;
254 }
255
256 #endif /* if SG_LIB_LINUX defined */
257