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