File indexing completed on 2024-04-14 04:44:45

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 }