File indexing completed on 2025-03-23 04:28:11
0001 /* 0002 SPDX-FileCopyrightText: 2003-2009 Sebastian Trueg <trueg@k3b.org> 0003 SPDX-FileCopyrightText: 1998-2009 Sebastian Trueg <trueg@k3b.org> 0004 0005 Parts of this file are inspired (and copied) from transport.hxx 0006 from the dvd+rw-tools (C) Andy Polyakov <appro@fy.chalmers.se> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "k3bscsicommand.h" 0012 #include "k3bdevice.h" 0013 0014 #include <QDebug> 0015 0016 #include <sys/ioctl.h> 0017 #undef __STRICT_ANSI__ 0018 #include <linux/cdrom.h> 0019 #define __STRICT_ANSI__ 0020 #include <scsi/sg.h> 0021 0022 #include <unistd.h> 0023 #include <sys/types.h> 0024 #include <sys/utsname.h> 0025 0026 0027 #if !defined(SG_FLAG_LUN_INHIBIT) 0028 # if defined(SG_FLAG_UNUSED_LUN_INHIBIT) 0029 # define SG_FLAG_LUN_INHIBIT SG_FLAG_UNUSED_LUN_INHIBIT 0030 # else 0031 # define SG_FLAG_LUN_INHIBIT 0 0032 # endif 0033 #endif 0034 0035 #ifdef SG_IO 0036 static bool useSgIo() 0037 { 0038 struct utsname buf; 0039 uname( &buf ); 0040 // was CDROM_SEND_PACKET declared dead in 2.5? 0041 return ( strcmp( buf.release, "2.5.43" ) >=0 ); 0042 } 0043 #endif 0044 0045 0046 class K3b::Device::ScsiCommand::Private 0047 { 0048 public: 0049 struct cdrom_generic_command cmd; 0050 struct request_sense sense; 0051 0052 #ifdef SG_IO 0053 bool useSgIo; 0054 struct sg_io_hdr sgIo; 0055 #endif 0056 }; 0057 0058 0059 void K3b::Device::ScsiCommand::clear() 0060 { 0061 ::memset( &d->cmd, 0, sizeof(struct cdrom_generic_command) ); 0062 ::memset( &d->sense, 0, sizeof(struct request_sense) ); 0063 0064 d->cmd.quiet = 1; 0065 d->cmd.sense = &d->sense; 0066 0067 #ifdef SG_IO 0068 d->useSgIo = useSgIo(); 0069 ::memset( &d->sgIo, 0, sizeof(struct sg_io_hdr) ); 0070 #endif 0071 } 0072 0073 0074 unsigned char& K3b::Device::ScsiCommand::operator[]( size_t i ) 0075 { 0076 #ifdef SG_IO 0077 if( d->sgIo.cmd_len < i+1 ) 0078 d->sgIo.cmd_len = i+1; 0079 #endif 0080 return d->cmd.cmd[i]; 0081 } 0082 0083 0084 int K3b::Device::ScsiCommand::transport( TransportDirection dir, 0085 void* data, 0086 size_t len ) 0087 { 0088 bool needToClose = false; 0089 int deviceHandle = -1; 0090 if( m_device ) { 0091 m_device->usageLock(); 0092 if( !m_device->isOpen() ) { 0093 needToClose = true; 0094 } 0095 if ( !m_device->open( dir == TR_DIR_WRITE ) ) { 0096 m_device->usageUnlock(); 0097 return -1; 0098 } 0099 deviceHandle = m_device->handle(); 0100 } 0101 0102 if( deviceHandle == -1 ) { 0103 return -1; 0104 } 0105 0106 int i = -1; 0107 0108 #ifdef SG_IO 0109 if( d->useSgIo ) { 0110 d->sgIo.interface_id= 'S'; 0111 d->sgIo.mx_sb_len = sizeof( struct request_sense ); 0112 d->sgIo.cmdp = d->cmd.cmd; 0113 d->sgIo.sbp = (unsigned char*)&d->sense; 0114 d->sgIo.flags = SG_FLAG_LUN_INHIBIT|SG_FLAG_DIRECT_IO; 0115 d->sgIo.dxferp = data; 0116 d->sgIo.dxfer_len = len; 0117 d->sgIo.timeout = 5000; 0118 if( dir == TR_DIR_READ ) 0119 d->sgIo.dxfer_direction = SG_DXFER_FROM_DEV; 0120 else if( dir == TR_DIR_WRITE ) 0121 d->sgIo.dxfer_direction = SG_DXFER_TO_DEV; 0122 else 0123 d->sgIo.dxfer_direction = SG_DXFER_NONE; 0124 0125 i = ::ioctl( deviceHandle, SG_IO, &d->sgIo ); 0126 0127 if( ( d->sgIo.info&SG_INFO_OK_MASK ) != SG_INFO_OK ) 0128 i = -1; 0129 } 0130 else { 0131 #endif 0132 d->cmd.buffer = (unsigned char*)data; 0133 d->cmd.buflen = len; 0134 if( dir == TR_DIR_READ ) 0135 d->cmd.data_direction = CGC_DATA_READ; 0136 else if( dir == TR_DIR_WRITE ) 0137 d->cmd.data_direction = CGC_DATA_WRITE; 0138 else 0139 d->cmd.data_direction = CGC_DATA_NONE; 0140 0141 i = ::ioctl( deviceHandle, CDROM_SEND_PACKET, &d->cmd ); 0142 #ifdef SG_IO 0143 } 0144 #endif 0145 0146 if( needToClose ) 0147 m_device->close(); 0148 0149 if ( m_device ) { 0150 m_device->usageUnlock(); 0151 } 0152 0153 if( i ) { 0154 debugError( d->cmd.cmd[0], 0155 d->sense.error_code, 0156 d->sense.sense_key, 0157 d->sense.asc, 0158 d->sense.ascq ); 0159 0160 int errCode = 0161 ((d->sense.error_code<<24) & 0xF000) | 0162 ((d->sense.sense_key<<16) & 0x0F00) | 0163 ((d->sense.asc<<8) & 0x00F0) | 0164 ((d->sense.ascq) & 0x000F); 0165 0166 return( errCode != 0 ? errCode : 1 ); 0167 } 0168 else 0169 return 0; 0170 }