• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 1999-2021 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  * SPDX-License-Identifier: BSD-2-Clause
8  */
9 
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <stdarg.h>
13 #include <stdbool.h>
14 #include <string.h>
15 #include <ctype.h>
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #ifdef SG_LIB_LINUX
22 
23 #include "sg_io_linux.h"
24 #include "sg_pr2serr.h"
25 
26 
27 /* Version 1.13 20210831 */
28 
29 
30 void
sg_print_masked_status(int masked_status)31 sg_print_masked_status(int masked_status)
32 {
33     int scsi_status = (masked_status << 1) & 0x7e;
34 
35     sg_print_scsi_status(scsi_status);
36 }
37 
38 /* host_bytes: DID_* are Linux SCSI result (a 32 bit variable) bits 16:23 */
39 
40 static const char * linux_host_bytes[] = {
41     "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT",
42     "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR",
43     "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR",
44     "DID_IMM_RETRY", "DID_REQUEUE", "DID_TRANSPORT_DISRUPTED",
45     "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE", "DID_NEXUS_FAILURE",
46     "DID_ALLOC_FAILURE", "DID_MEDIUM_ERROR", "DID_TRANSPORT_MARGINAL",
47 };
48 
49 void
sg_print_host_status(int host_status)50 sg_print_host_status(int host_status)
51 {
52     pr2ws("Host_status=0x%02x ", host_status);
53     if ((host_status < 0) ||
54         (host_status >= (int)SG_ARRAY_SIZE(linux_host_bytes)))
55         pr2ws("is invalid ");
56     else
57         pr2ws("[%s] ", linux_host_bytes[host_status]);
58 }
59 
60 /* DRIVER_* are Linux SCSI result (a 32 bit variable) bits 24:27 .
61  * These where made obsolete around lk 5.12.0 . Only DRIVER_SENSE [0x8] is
62  * defined in scsi/sg.h for backward comaptibility */
63 static const char * linux_driver_bytes[] = {
64     "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA",
65     "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD",
66     "DRIVER_SENSE",
67 };
68 
69 #if 0
70 
71 /* SUGGEST_* are Linux SCSI result (a 32 bit variable) bits 28:31 */
72 
73 static const char * linux_driver_suggests[] = {
74     "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP",
75     "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN",
76     "SUGGEST_SENSE",
77 };
78 #endif
79 
80 
81 void
sg_print_driver_status(int driver_status)82 sg_print_driver_status(int driver_status)
83 {
84     int driv;
85     const char * driv_cp = "invalid";
86 
87     driv = driver_status & SG_LIB_DRIVER_MASK;
88     if (driv < (int)SG_ARRAY_SIZE(linux_driver_bytes))
89         driv_cp = linux_driver_bytes[driv];
90     pr2ws("Driver_status=0x%02x", driver_status);
91     pr2ws(" [%s] ", driv_cp);
92 }
93 
94 /* Returns 1 if no errors found and thus nothing printed; otherwise
95  * prints error/warning (prefix by 'leadin') to stderr (pr2ws) and
96  * returns 0. */
97 int
sg_linux_sense_print(const char * leadin,int scsi_status,int host_status,int driver_status,const uint8_t * sense_buffer,int sb_len,bool raw_sinfo)98 sg_linux_sense_print(const char * leadin, int scsi_status, int host_status,
99                      int driver_status, const uint8_t * sense_buffer,
100                      int sb_len, bool raw_sinfo)
101 {
102     bool done_leadin = false;
103     bool done_sense = false;
104 
105     scsi_status &= 0x7e; /*sanity */
106     if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status))
107         return 1;       /* No problems */
108     if (0 != scsi_status) {
109         if (leadin)
110             pr2ws("%s: ", leadin);
111         done_leadin = true;
112         pr2ws("SCSI status: ");
113         sg_print_scsi_status(scsi_status);
114         pr2ws("\n");
115         if (sense_buffer && ((scsi_status == SAM_STAT_CHECK_CONDITION) ||
116                              (scsi_status == SAM_STAT_COMMAND_TERMINATED))) {
117             /* SAM_STAT_COMMAND_TERMINATED is obsolete */
118             sg_print_sense(0, sense_buffer, sb_len, raw_sinfo);
119             done_sense = true;
120         }
121     }
122     if (0 != host_status) {
123         if (leadin && (! done_leadin))
124             pr2ws("%s: ", leadin);
125         if (done_leadin)
126             pr2ws("plus...: ");
127         else
128             done_leadin = true;
129         sg_print_host_status(host_status);
130         pr2ws("\n");
131     }
132     if (0 != driver_status) {
133         if (done_sense &&
134             (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status)))
135             return 0;
136         if (leadin && (! done_leadin))
137             pr2ws("%s: ", leadin);
138         if (done_leadin)
139             pr2ws("plus...: ");
140         sg_print_driver_status(driver_status);
141         pr2ws("\n");
142         if (sense_buffer && (! done_sense) &&
143             (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status)))
144             sg_print_sense(0, sense_buffer, sb_len, raw_sinfo);
145     }
146     return 0;
147 }
148 
149 #ifdef SG_IO
150 
151 bool
sg_normalize_sense(const struct sg_io_hdr * hp,struct sg_scsi_sense_hdr * sshp)152 sg_normalize_sense(const struct sg_io_hdr * hp,
153                    struct sg_scsi_sense_hdr * sshp)
154 {
155     if ((NULL == hp) || (0 == hp->sb_len_wr)) {
156         if (sshp)
157             memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr));
158         return 0;
159     }
160     return sg_scsi_normalize_sense(hp->sbp, hp->sb_len_wr, sshp);
161 }
162 
163 /* Returns 1 if no errors found and thus nothing printed; otherwise
164    returns 0. */
165 int
sg_chk_n_print3(const char * leadin,struct sg_io_hdr * hp,bool raw_sinfo)166 sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp,
167                 bool raw_sinfo)
168 {
169     return sg_linux_sense_print(leadin, hp->status, hp->host_status,
170                                 hp->driver_status, hp->sbp, hp->sb_len_wr,
171                                 raw_sinfo);
172 }
173 #endif
174 
175 /* Returns 1 if no errors found and thus nothing printed; otherwise
176    returns 0. */
177 int
sg_chk_n_print(const char * leadin,int masked_status,int host_status,int driver_status,const uint8_t * sense_buffer,int sb_len,bool raw_sinfo)178 sg_chk_n_print(const char * leadin, int masked_status, int host_status,
179                int driver_status, const uint8_t * sense_buffer,
180                int sb_len, bool raw_sinfo)
181 {
182     int scsi_status = (masked_status << 1) & 0x7e;
183 
184     return sg_linux_sense_print(leadin, scsi_status, host_status,
185                                 driver_status, sense_buffer, sb_len,
186                                 raw_sinfo);
187 }
188 
189 #ifdef SG_IO
190 int
sg_err_category3(struct sg_io_hdr * hp)191 sg_err_category3(struct sg_io_hdr * hp)
192 {
193     return sg_err_category_new(hp->status, hp->host_status,
194                                hp->driver_status, hp->sbp, hp->sb_len_wr);
195 }
196 #endif
197 
198 int
sg_err_category(int masked_status,int host_status,int driver_status,const uint8_t * sense_buffer,int sb_len)199 sg_err_category(int masked_status, int host_status, int driver_status,
200                 const uint8_t * sense_buffer, int sb_len)
201 {
202     int scsi_status = (masked_status << 1) & 0x7e;
203 
204     return sg_err_category_new(scsi_status, host_status, driver_status,
205                                sense_buffer, sb_len);
206 }
207 
208 int
sg_err_category_new(int scsi_status,int host_status,int driver_status,const uint8_t * sense_buffer,int sb_len)209 sg_err_category_new(int scsi_status, int host_status, int driver_status,
210                     const uint8_t * sense_buffer, int sb_len)
211 {
212     int masked_driver_status = (SG_LIB_DRIVER_MASK & driver_status);
213 
214     scsi_status &= 0x7e;
215     if ((0 == scsi_status) && (0 == host_status) &&
216         (0 == masked_driver_status))
217         return SG_LIB_CAT_CLEAN;
218     if ((SAM_STAT_CHECK_CONDITION == scsi_status) ||
219         (SAM_STAT_COMMAND_TERMINATED == scsi_status) ||
220         (SG_LIB_DRIVER_SENSE == masked_driver_status))
221         return sg_err_category_sense(sense_buffer, sb_len);
222     if (0 != host_status) {
223         if ((SG_LIB_DID_NO_CONNECT == host_status) ||
224             (SG_LIB_DID_BUS_BUSY == host_status) ||
225             (SG_LIB_DID_TIME_OUT == host_status))
226             return SG_LIB_CAT_TIMEOUT;
227         if (SG_LIB_DID_NEXUS_FAILURE == host_status)
228             return SG_LIB_CAT_RES_CONFLICT;
229     }
230     if (SG_LIB_DRIVER_TIMEOUT == masked_driver_status)
231         return SG_LIB_CAT_TIMEOUT;
232     return SG_LIB_CAT_OTHER;
233 }
234 
235 #endif  /* if SG_LIB_LINUX defined */
236