/*
* @project The CERN Tape Archive (CTA)
* @copyright Copyright(C) 2003-2021 CERN
* @license This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "Exception.hpp"
//------------------------------------------------------------------------------
// ExceptionLauncher
//------------------------------------------------------------------------------
void castor::tape::SCSI::ExceptionLauncher(const SCSI::Structures::LinuxSGIO_t &
sgio, std::string context) {
std::stringstream contextWithStatuses;
contextWithStatuses << context
<< std::hex << std::nouppercase << std::showbase
<< " status=" << static_cast(sgio.status)
<< " host_status=" << sgio.host_status
<< " driver_status=" << sgio.driver_status
<< ":";
checkAndThrowSgStatus(sgio, contextWithStatuses.str());
checkAndThrowSgHostStatus(sgio, contextWithStatuses.str());
checkAndThrowSgDriverStatus(sgio, contextWithStatuses.str());
}
//------------------------------------------------------------------------------
// checkAndThrowSgStatus
//------------------------------------------------------------------------------
void castor::tape::SCSI::checkAndThrowSgStatus(
const SCSI::Structures::LinuxSGIO_t & sgio, const std::string context) {
if (SCSI::Status::GOOD != sgio.status) {
if (SCSI::Status::CHECK_CONDITION == sgio.status) {
unsigned char senseKey;
castor::tape::SCSI::Structures::senseData_t<255> * sense =
(SCSI::Structures::senseData_t<255> *)sgio.sbp;
try {
senseKey = sense->getSenseKey();
} catch (...) {
throw Exception(sgio.status,
(SCSI::Structures::senseData_t<255> *)sgio.sbp, context);
}
switch (senseKey) {
case castor::tape::SCSI::senseKeys::notReady :
throw NotReadyException(sgio.status,
(SCSI::Structures::senseData_t<255> *)sgio.sbp, context);
case castor::tape::SCSI::senseKeys::unitAttention :
throw UnitAttentionException(sgio.status,
(SCSI::Structures::senseData_t<255> *)sgio.sbp, context);
default:
throw Exception(sgio.status,
(SCSI::Structures::senseData_t<255> *)sgio.sbp, context);
}
} else {
throw Exception(sgio.status,
(SCSI::Structures::senseData_t<255> *)sgio.sbp, context);
}
}
}
//------------------------------------------------------------------------------
// checkAndThrowSgHostStatus
//------------------------------------------------------------------------------
void castor::tape::SCSI::checkAndThrowSgHostStatus(
const SCSI::Structures::LinuxSGIO_t & sgio, const std::string context) {
if (SCSI::HostStatus::OK != sgio.host_status) {
throw HostException(sgio.host_status, context);
}
}
//------------------------------------------------------------------------------
// checkAndThrowSgDriverStatus
//------------------------------------------------------------------------------
void castor::tape::SCSI::checkAndThrowSgDriverStatus(
const SCSI::Structures::LinuxSGIO_t & sgio, const std::string context) {
if (SCSI::DriverStatus::OK != sgio.driver_status) {
throw DriverException(sgio.driver_status,
(SCSI::Structures::senseData_t<255> *)sgio.sbp, context);
}
}
//------------------------------------------------------------------------------
// Exception
//------------------------------------------------------------------------------
castor::tape::SCSI::Exception::Exception(
unsigned char status, castor::tape::SCSI::Structures::senseData_t<255>* sense,
const std::string& context): cta::exception::Exception("") {
std::stringstream w;
w << context << (context.size()?" ":"")
<< "SCSI command failed with status "
<< SCSI::statusToString(status);
if (SCSI::Status::CHECK_CONDITION == status) {
w << ": Sense Information";
try {
w << ": " << sense->getSenseKeyString();
} catch (Exception &ex) {
w << ": In addition, failed to get Sense Key string: "
<< ex.getMessage().str();
}
try {
w << ": " << sense->getACSString();
} catch (Exception &ex) {
w << ": In addition, failed to get ACS string: "
<< ex.getMessage().str();
}
}
setWhat(w.str());
}
//------------------------------------------------------------------------------
// HostException
//------------------------------------------------------------------------------
castor::tape::SCSI::HostException::HostException(
const unsigned short int host_status, const std::string& context):
cta::exception::Exception("") {
std::stringstream w;
w << context << (context.size()?" ":"")
<< "SCSI command failed with host_status: "
<< SCSI::hostStatusToString(host_status);
setWhat(w.str());
}
//------------------------------------------------------------------------------
// DriverException
//------------------------------------------------------------------------------
castor::tape::SCSI::DriverException::DriverException(
const unsigned short int driver_status,
castor::tape::SCSI::Structures::senseData_t<255>* sense,
const std::string& context) : cta::exception::Exception("") {
std::stringstream w;
const std::string driverSuggestions =
SCSI::driverStatusSuggestionsToString(driver_status);
w << context << (context.size() ? " " : "")
<< "SCSI command failed with driver_status: "
<< SCSI::driverStatusToString(driver_status)
<< (driverSuggestions.size() ? ": Driver suggestions:" : "")
<< driverSuggestions;
if (SCSI::DriverStatus::SENSE & driver_status) {
w << ": Sense Information";
try {
w << ": " << sense->getSenseKeyString();
} catch (Exception &ex) {
w << ": In addition, failed to get Sense Key string: "
<< ex.getMessage().str();
}
try {
w << ": " << sense->getACSString();
} catch (Exception &ex) {
w << ": In addition, failed to get ACS string: "
<< ex.getMessage().str();
}
}
setWhat(w.str());
}