File indexing completed on 2024-04-21 04:49:44

0001 /*
0002     k3bscsicommand_win32.cpp
0003     SPDX-FileCopyrightText: 2007 Jeremy C. Andrus <jeremy@jeremya.com>
0004     SPDX-FileCopyrightText: 2009 Ralf Habacker <ralf.habacker@freenet.de>
0005     SPDX-FileCopyrightText: 1998-2007 Sebastian Trueg <trueg@k3b.org>
0006 
0007     Parts of this file are inspired (and copied) from various source
0008     files in the cdrdao project (C) J. Schilling, Andreas Mueller
0009     and many others.
0010 
0011     SPDX-License-Identifier: GPL-2.0-or-later
0012 */
0013 
0014 #include "k3bscsicommand.h"
0015 #include "k3bdevice.h"
0016 
0017 #include <windows.h>
0018 #include <stdio.h>
0019 #include <fcntl.h>
0020 #include <errno.h>
0021 #include <string.h>
0022 #include <assert.h>
0023 
0024 #include "winspti.h"
0025 
0026 
0027 class K3b::Device::ScsiCommand::Private
0028 {
0029 public:
0030     SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER m_cmd;
0031     
0032     SCSI_SENSE_DATA m_senseData;
0033 };
0034 
0035 
0036 void K3b::Device::ScsiCommand::clear()
0037 {
0038     ::memset( &d->m_cmd, 0, sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER) );
0039 }
0040 
0041 
0042 unsigned char& K3b::Device::ScsiCommand::operator[]( size_t i )
0043 {
0044     if( d->m_cmd.spt.CdbLength < i+1 )
0045         d->m_cmd.spt.CdbLength = i+1;
0046     return d->m_cmd.spt.Cdb[i];
0047 }
0048 
0049 
0050 int K3b::Device::ScsiCommand::transport( TransportDirection dir,
0051                                        void* data,
0052                                        size_t len )
0053 {
0054     bool needToClose = false;
0055     ULONG returned = 0;
0056     BOOL status = TRUE;
0057 
0058     // closing device every time breaks scsi operation, disabled for now
0059     //needToClose = !m_device->isOpen();
0060     m_device->open( dir == TR_DIR_WRITE );
0061 
0062     if( !m_device->isOpen() ) {
0063         qDebug() << "(K3bScsiCommand::transport) could not perform Win32 IOCTL on invalid handle value" << Qt::endl;
0064         return -1;
0065     }
0066 
0067     if ( dir == TR_DIR_READ )
0068         d->m_cmd.spt.DataIn           = SCSI_IOCTL_DATA_IN;
0069     else if ( dir == TR_DIR_WRITE )
0070         d->m_cmd.spt.DataIn           = SCSI_IOCTL_DATA_OUT;
0071     else
0072         d->m_cmd.spt.DataIn           = SCSI_IOCTL_DATA_UNSPECIFIED;
0073 
0074     d->m_cmd.spt.Length             = sizeof(SCSI_PASS_THROUGH_DIRECT);
0075     d->m_cmd.spt.SenseInfoLength    = SENSE_LEN_SPTI;
0076     d->m_cmd.spt.DataTransferLength = len;
0077     d->m_cmd.spt.TimeOutValue       = 2;
0078     d->m_cmd.spt.DataBuffer         = len ? data : NULL;
0079     d->m_cmd.spt.SenseInfoOffset    = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
0080 
0081     status = DeviceIoControl( m_device->handle(),
0082                 IOCTL_SCSI_PASS_THROUGH_DIRECT,
0083                 &(d->m_cmd), sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),
0084                 &(d->m_cmd), sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER),
0085                 &returned, NULL);
0086 
0087     if( needToClose )
0088         m_device->close();
0089 
0090     // get the sense data on error
0091     if ( !status ) {
0092         qDebug() << "(K3bScsiCommand::transport) ioctl failed: " << GetLastError() << ", returned=" << returned << Qt::endl;
0093         ::memcpy( &(d->m_senseData), d->m_cmd.ucSenseBuf, SENSE_LEN_SPTI );
0094 
0095         debugError( d->m_cmd.spt.Cdb[0],
0096             d->m_senseData.SD_Error,
0097             d->m_senseData.SD_SenseKey,
0098             d->m_senseData.SD_ASC,
0099             d->m_senseData.SD_ASCQ );
0100 
0101         int errCode =
0102             (d->m_senseData.SD_Error << 24)    & 0xF000 |
0103             (d->m_senseData.SD_SenseKey << 16) & 0x0F00 |
0104             (d->m_senseData.SD_ASC << 8)       & 0x00F0 |
0105             (d->m_senseData.SD_ASCQ)           & 0x000F;
0106 
0107         return ( errCode != 0 ? errCode : 1 );
0108     }
0109     qDebug() 
0110         << "len:" << d->m_cmd.spt.CdbLength  
0111         << "cmd:" << commandString(d->m_cmd.spt.Cdb[0]) 
0112         << d->m_cmd.spt.Cdb[0]
0113         << d->m_cmd.spt.Cdb[1] 
0114         << d->m_cmd.spt.Cdb[2] 
0115         << d->m_cmd.spt.Cdb[3] 
0116         << d->m_cmd.spt.Cdb[4] 
0117         << d->m_cmd.spt.Cdb[5] 
0118         << d->m_cmd.spt.Cdb[6] 
0119         << d->m_cmd.spt.Cdb[7] 
0120         << d->m_cmd.spt.Cdb[8] 
0121         << d->m_cmd.spt.Cdb[9] 
0122         << "datalen=" << d->m_cmd.spt.DataTransferLength
0123         << "returned=" << returned
0124     ;
0125 
0126     return 0;
0127 }