File indexing completed on 2025-03-23 04:28:11
0001 /* 0002 SPDX-FileCopyrightText: 2003-2009 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 2011 Andriy Gapon <avg@FreeBSD.org> 0004 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "k3bscsicommand.h" 0010 #include "k3bdevice.h" 0011 0012 #include <QDebug> 0013 0014 #include <stdio.h> 0015 #include <errno.h> 0016 #include <camlib.h> 0017 #include <cam/scsi/scsi_message.h> 0018 #include <cam/scsi/scsi_pass.h> 0019 0020 namespace /*anonymous*/ 0021 { 0022 inline int sense_to_err( const struct scsi_sense_data& s ) 0023 { 0024 int errorCode, senseKey, addSenseCode, addSenseCodeQual; 0025 scsi_extract_sense( (struct scsi_sense_data*) &s, &errorCode, 0026 &senseKey, &addSenseCode, &addSenseCodeQual ); 0027 return (errorCode << 24) | (senseKey << 16) | 0028 (addSenseCode << 8) | addSenseCodeQual; 0029 } 0030 } 0031 0032 0033 class K3b::Device::ScsiCommand::Private 0034 { 0035 typedef union ccb CCB; 0036 0037 public: 0038 Private(); 0039 int transport( const Device* device, TransportDirection dir, void* data, size_t len ); 0040 unsigned char& operator[]( size_t i ); 0041 void clear(); 0042 const CCB& get_ccb() { return ccb; } 0043 0044 private: 0045 CCB ccb; 0046 }; 0047 0048 0049 void K3b::Device::ScsiCommand::clear() 0050 { 0051 d->clear(); 0052 } 0053 0054 unsigned char& K3b::Device::ScsiCommand::operator[]( size_t i ) 0055 { 0056 return (*d)[i]; 0057 } 0058 0059 int K3b::Device::ScsiCommand::transport( TransportDirection dir, 0060 void* data, 0061 size_t len ) 0062 { 0063 if( !m_device ) 0064 return -1; 0065 0066 m_device->usageLock(); 0067 0068 bool needToClose = false; 0069 if( !m_device->isOpen() ) { 0070 needToClose = true; 0071 } 0072 0073 if( !m_device->open( true ) ) { 0074 m_device->usageUnlock(); 0075 return -1; 0076 } 0077 0078 int ret = d->transport( m_device, dir, data, len ); 0079 if( ret != 0 ) { 0080 const struct scsi_sense_data& s = d->get_ccb().csio.sense_data; 0081 int errorCode, senseKey, addSenseCode, addSenseCodeQual; 0082 scsi_extract_sense( (struct scsi_sense_data*) &s, &errorCode, &senseKey, 0083 &addSenseCode, &addSenseCodeQual ); 0084 debugError( d->get_ccb().csio.cdb_io.cdb_bytes[0], 0085 errorCode, 0086 senseKey, 0087 addSenseCode, 0088 addSenseCodeQual ); 0089 } 0090 0091 if( needToClose ) 0092 m_device->close(); 0093 m_device->usageUnlock(); 0094 0095 return ret; 0096 } 0097 0098 K3b::Device::ScsiCommand::Private::Private() 0099 { 0100 clear(); 0101 } 0102 0103 void K3b::Device::ScsiCommand::Private::clear() 0104 { 0105 memset( &ccb, 0, sizeof(ccb) ); 0106 } 0107 0108 unsigned char& K3b::Device::ScsiCommand::Private::operator[]( size_t i ) 0109 { 0110 if( ccb.csio.cdb_len < i + 1 ) 0111 ccb.csio.cdb_len = i + 1; 0112 return ccb.csio.cdb_io.cdb_bytes[i]; 0113 } 0114 0115 int K3b::Device::ScsiCommand::Private::transport( const Device* device, TransportDirection dir, void* data, size_t len ) 0116 { 0117 ccb.ccb_h.path_id = device->handle()->path_id; 0118 ccb.ccb_h.target_id = device->handle()->target_id; 0119 ccb.ccb_h.target_lun = device->handle()->target_lun; 0120 0121 qDebug() << "(K3b::Device::ScsiCommand) transport command " << commandString(ccb.csio.cdb_io.cdb_bytes[0]) 0122 << " (" << QString::number((int)ccb.csio.cdb_io.cdb_bytes[0], 16) << "), length: " << (int)ccb.csio.cdb_len; 0123 int direction = CAM_DEV_QFRZDIS; 0124 if (!len) 0125 direction |= CAM_DIR_NONE; 0126 else 0127 direction |= (dir & TR_DIR_READ) ? CAM_DIR_IN : CAM_DIR_OUT; 0128 0129 cam_fill_csio( &(ccb.csio), 1, NULL, direction, MSG_SIMPLE_Q_TAG, (uint8_t*)data, len, sizeof(ccb.csio.sense_data), ccb.csio.cdb_len, 30*1000 ); 0130 int ret = cam_send_ccb( device->handle(), &ccb ); 0131 if( ret < 0 ) { 0132 qCritical() << "(K3b::Device::ScsiCommand) transport cam_send_ccb failed: ret = " << ret 0133 << ", errno = " << errno << ", cam_errbuf = " << cam_errbuf; 0134 return 1; 0135 } 0136 else if( (ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP ) { 0137 qDebug() << "(K3b::Device::ScsiCommand) transport succeeded"; 0138 return 0; 0139 } 0140 0141 qDebug() << "(K3b::Device::ScsiCommand) transport command failed: scsi_status = " << QString::number(ccb.csio.scsi_status, 16); 0142 0143 if( ccb.csio.scsi_status == SCSI_STATUS_CHECK_COND && 0144 !(ccb.ccb_h.status & CAM_AUTOSNS_VALID) && 0145 ccb.csio.cdb_io.cdb_bytes[0] != MMC_REQUEST_SENSE ) 0146 { 0147 qDebug() << "(K3b::Device::ScsiCommand) transport requesting sense data"; 0148 0149 struct scsi_sense_data sense; 0150 ScsiCommand::Private cmd; 0151 cmd[0] = MMC_REQUEST_SENSE; 0152 cmd[4] = SSD_MIN_SIZE; 0153 cmd[5] = 0; // Necessary to set the proper command length 0154 0155 memset( &sense, 0, sizeof(sense) ); 0156 ret = cmd.transport( device, TR_DIR_READ, &sense, SSD_MIN_SIZE ); 0157 if( ret < 0 ) 0158 { 0159 qWarning() << "(K3b::Device::ScsiCommand) transport getting sense data failed: " << ret; 0160 return 1; 0161 } 0162 0163 ccb.csio.sense_data = sense; 0164 ccb.ccb_h.status |= CAM_AUTOSNS_VALID; 0165 } 0166 0167 if( !(ccb.ccb_h.status & CAM_AUTOSNS_VALID) ) 0168 qDebug() << "(K3b::Device::ScsiCommand) sense data is not available"; 0169 0170 ret = sense_to_err(ccb.csio.sense_data); 0171 if( ret == 0 ) 0172 ret = 1; 0173 qDebug() << "(K3b::Device::ScsiCommand) transport failed: " << ret; 0174 return ret; 0175 }