/* * Copyright (c) 1999-2018 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include <stdio.h> #include <stdlib.h> #include <stdarg.h> #include <stdbool.h> #include <string.h> #include <ctype.h> #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef SG_LIB_LINUX #include "sg_io_linux.h" /* Version 1.07 20160405 */ #if defined(__GNUC__) || defined(__clang__) static int pr2ws(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2ws(const char * fmt, ...); #endif static int pr2ws(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(sg_warnings_strm ? sg_warnings_strm : stderr, fmt, args); va_end(args); return n; } void sg_print_masked_status(int masked_status) { int scsi_status = (masked_status << 1) & 0x7e; sg_print_scsi_status(scsi_status); } static const char * linux_host_bytes[] = { "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE", "DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE", "DID_NEXUS_FAILURE", "DID_ALLOC_FAILURE", "DID_MEDIUM_ERROR", }; #define LINUX_HOST_BYTES_SZ \ (int)(sizeof(linux_host_bytes) / sizeof(linux_host_bytes[0])) void sg_print_host_status(int host_status) { pr2ws("Host_status=0x%02x ", host_status); if ((host_status < 0) || (host_status >= LINUX_HOST_BYTES_SZ)) pr2ws("is invalid "); else pr2ws("[%s] ", linux_host_bytes[host_status]); } static const char * linux_driver_bytes[] = { "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE" }; #define LINUX_DRIVER_BYTES_SZ \ (int)(sizeof(linux_driver_bytes) / sizeof(linux_driver_bytes[0])) #if 0 static const char * linux_driver_suggests[] = { "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN", "SUGGEST_SENSE" }; #define LINUX_DRIVER_SUGGESTS_SZ \ (int)(sizeof(linux_driver_suggests) / sizeof(linux_driver_suggests[0])) #endif void sg_print_driver_status(int driver_status) { int driv; const char * driv_cp = "invalid"; driv = driver_status & SG_LIB_DRIVER_MASK; if (driv < LINUX_DRIVER_BYTES_SZ) driv_cp = linux_driver_bytes[driv]; #if 0 sugg = (driver_status & SG_LIB_SUGGEST_MASK) >> 4; if (sugg < LINUX_DRIVER_SUGGESTS_SZ) sugg_cp = linux_driver_suggests[sugg]; #endif pr2ws("Driver_status=0x%02x", driver_status); pr2ws(" [%s] ", driv_cp); } /* Returns 1 if no errors found and thus nothing printed; otherwise prints error/warning (prefix by 'leadin') and returns 0. */ 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) { bool done_leadin = false; bool done_sense = false; scsi_status &= 0x7e; /*sanity */ if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status)) return 1; /* No problems */ if (0 != scsi_status) { if (leadin) pr2ws("%s: ", leadin); done_leadin = true; pr2ws("SCSI status: "); sg_print_scsi_status(scsi_status); pr2ws("\n"); if (sense_buffer && ((scsi_status == SAM_STAT_CHECK_CONDITION) || (scsi_status == SAM_STAT_COMMAND_TERMINATED))) { /* SAM_STAT_COMMAND_TERMINATED is obsolete */ sg_print_sense(0, sense_buffer, sb_len, raw_sinfo); done_sense = true; } } if (0 != host_status) { if (leadin && (! done_leadin)) pr2ws("%s: ", leadin); if (done_leadin) pr2ws("plus...: "); else done_leadin = true; sg_print_host_status(host_status); pr2ws("\n"); } if (0 != driver_status) { if (done_sense && (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status))) return 0; if (leadin && (! done_leadin)) pr2ws("%s: ", leadin); if (done_leadin) pr2ws("plus...: "); sg_print_driver_status(driver_status); pr2ws("\n"); if (sense_buffer && (! done_sense) && (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status))) sg_print_sense(0, sense_buffer, sb_len, raw_sinfo); } return 0; } #ifdef SG_IO bool sg_normalize_sense(const struct sg_io_hdr * hp, struct sg_scsi_sense_hdr * sshp) { if ((NULL == hp) || (0 == hp->sb_len_wr)) { if (sshp) memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr)); return 0; } return sg_scsi_normalize_sense(hp->sbp, hp->sb_len_wr, sshp); } /* Returns 1 if no errors found and thus nothing printed; otherwise returns 0. */ int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp, bool raw_sinfo) { return sg_linux_sense_print(leadin, hp->status, hp->host_status, hp->driver_status, hp->sbp, hp->sb_len_wr, raw_sinfo); } #endif /* Returns 1 if no errors found and thus nothing printed; otherwise returns 0. */ 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) { int scsi_status = (masked_status << 1) & 0x7e; return sg_linux_sense_print(leadin, scsi_status, host_status, driver_status, sense_buffer, sb_len, raw_sinfo); } #ifdef SG_IO int sg_err_category3(struct sg_io_hdr * hp) { return sg_err_category_new(hp->status, hp->host_status, hp->driver_status, hp->sbp, hp->sb_len_wr); } #endif int sg_err_category(int masked_status, int host_status, int driver_status, const unsigned char * sense_buffer, int sb_len) { int scsi_status = (masked_status << 1) & 0x7e; return sg_err_category_new(scsi_status, host_status, driver_status, sense_buffer, sb_len); } int sg_err_category_new(int scsi_status, int host_status, int driver_status, const unsigned char * sense_buffer, int sb_len) { int masked_driver_status = (SG_LIB_DRIVER_MASK & driver_status); scsi_status &= 0x7e; if ((0 == scsi_status) && (0 == host_status) && (0 == masked_driver_status)) return SG_LIB_CAT_CLEAN; if ((SAM_STAT_CHECK_CONDITION == scsi_status) || (SAM_STAT_COMMAND_TERMINATED == scsi_status) || (SG_LIB_DRIVER_SENSE == masked_driver_status)) return sg_err_category_sense(sense_buffer, sb_len); if (0 != host_status) { if ((SG_LIB_DID_NO_CONNECT == host_status) || (SG_LIB_DID_BUS_BUSY == host_status) || (SG_LIB_DID_TIME_OUT == host_status)) return SG_LIB_CAT_TIMEOUT; if (SG_LIB_DID_NEXUS_FAILURE == host_status) return SG_LIB_CAT_RES_CONFLICT; } if (SG_LIB_DRIVER_TIMEOUT == masked_driver_status) return SG_LIB_CAT_TIMEOUT; return SG_LIB_CAT_OTHER; } #endif /* if SG_LIB_LINUX defined */