diff --git a/DiscImageChef.Core/Devices/Dumping/ATA.cs b/DiscImageChef.Core/Devices/Dumping/ATA.cs index 78202c3bc..f0aaf2402 100644 --- a/DiscImageChef.Core/Devices/Dumping/ATA.cs +++ b/DiscImageChef.Core/Devices/Dumping/ATA.cs @@ -74,15 +74,8 @@ namespace DiscImageChef.Core.Devices.Dumping byte[] cmdBuf; bool sense; - ulong blocks = 0; - uint blockSize = 512; ushort currentProfile = 0x0001; Decoders.ATA.AtaErrorRegistersCHS errorChs; - Decoders.ATA.AtaErrorRegistersLBA28 errorLba; - Decoders.ATA.AtaErrorRegistersLBA48 errorLba48; - bool lbaMode = false; - byte heads = 0, sectors = 0; - ushort cylinders = 0; uint timeout = 5; double duration; @@ -155,192 +148,6 @@ namespace DiscImageChef.Core.Devices.Dumping sidecar.BlockMedia[0].ATA.Identify.Checksums = Checksum.GetChecksums(cmdBuf).ToArray(); DataFile.WriteTo("ATA Dump", sidecar.BlockMedia[0].ATA.Identify.Image, cmdBuf); - if(ataId.CurrentCylinders > 0 && ataId.CurrentHeads > 0 && ataId.CurrentSectorsPerTrack > 0) - { - cylinders = ataId.CurrentCylinders; - heads = (byte)ataId.CurrentHeads; - sectors = (byte)ataId.CurrentSectorsPerTrack; - blocks = (ulong)(cylinders * heads * sectors); - } - - if((ataId.CurrentCylinders == 0 || ataId.CurrentHeads == 0 || ataId.CurrentSectorsPerTrack == 0) && - (ataId.Cylinders > 0 && ataId.Heads > 0 && ataId.SectorsPerTrack > 0)) - { - cylinders = ataId.Cylinders; - heads = (byte)ataId.Heads; - sectors = (byte)ataId.SectorsPerTrack; - blocks = (ulong)(cylinders * heads * sectors); - } - - if(ataId.Capabilities.HasFlag(Decoders.ATA.Identify.CapabilitiesBit.LBASupport)) - { - blocks = ataId.LBASectors; - lbaMode = true; - } - - if(ataId.CommandSet2.HasFlag(Decoders.ATA.Identify.CommandSetBit2.LBA48)) - { - blocks = ataId.LBA48Sectors; - lbaMode = true; - } - - uint physicalsectorsize = blockSize; - if((ataId.PhysLogSectorSize & 0x8000) == 0x0000 && - (ataId.PhysLogSectorSize & 0x4000) == 0x4000) - { - if((ataId.PhysLogSectorSize & 0x1000) == 0x1000) - { - if(ataId.LogicalSectorWords <= 255 || ataId.LogicalAlignment == 0xFFFF) - blockSize = 512; - else - blockSize = ataId.LogicalSectorWords * 2; - } - else - blockSize = 512; - - if((ataId.PhysLogSectorSize & 0x2000) == 0x2000) - { -#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created - physicalsectorsize = blockSize * (uint)Math.Pow(2, (double)(ataId.PhysLogSectorSize & 0xF)); -#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created - } - else - physicalsectorsize = blockSize; - } - else - { - blockSize = 512; - physicalsectorsize = 512; - } - - bool ReadLba = false; - bool ReadRetryLba = false; - bool ReadDmaLba = false; - bool ReadDmaRetryLba = false; - - bool ReadLba48 = false; - bool ReadDmaLba48 = false; - - bool Read = false; - bool ReadRetry = false; - bool ReadDma = false; - bool ReadDmaRetry = false; - - sense = dev.Read(out cmdBuf, out errorChs, false, 0, 0, 1, 1, timeout, out duration); - Read = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - sense = dev.Read(out cmdBuf, out errorChs, true, 0, 0, 1, 1, timeout, out duration); - ReadRetry = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorChs, false, 0, 0, 1, 1, timeout, out duration); - ReadDma = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorChs, true, 0, 0, 1, 1, timeout, out duration); - ReadDmaRetry = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - - sense = dev.Read(out cmdBuf, out errorLba, false, 0, 1, timeout, out duration); - ReadLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - sense = dev.Read(out cmdBuf, out errorLba, true, 0, 1, timeout, out duration); - ReadRetryLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorLba, false, 0, 1, timeout, out duration); - ReadDmaLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorLba, true, 0, 1, timeout, out duration); - ReadDmaRetryLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - - sense = dev.Read(out cmdBuf, out errorLba48, 0, 1, timeout, out duration); - ReadLba48 = (!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorLba48, 0, 1, timeout, out duration); - ReadDmaLba48 = (!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - - if(!lbaMode) - { - if(blocks > 0xFFFFFFF && !ReadLba48 && !ReadDmaLba48) - { - DicConsole.ErrorWriteLine("Device needs 48-bit LBA commands but I can't issue them... Aborting."); - return; - } - - if(!ReadLba && !ReadRetryLba && !ReadDmaLba && !ReadDmaRetryLba) - { - DicConsole.ErrorWriteLine("Device needs 28-bit LBA commands but I can't issue them... Aborting."); - return; - } - } - else - { - if(!Read && !ReadRetry && !ReadDma && !ReadDmaRetry) - { - DicConsole.ErrorWriteLine("Device needs CHS commands but I can't issue them... Aborting."); - return; - } - } - - if(ReadDmaLba48) - DicConsole.WriteLine("Using ATA READ DMA EXT command."); - else if(ReadLba48) - DicConsole.WriteLine("Using ATA READ EXT command."); - else if(ReadDmaRetryLba) - DicConsole.WriteLine("Using ATA READ DMA command with retries (LBA)."); - else if(ReadDmaLba) - DicConsole.WriteLine("Using ATA READ DMA command (LBA)."); - else if(ReadRetryLba) - DicConsole.WriteLine("Using ATA READ command with retries (LBA)."); - else if(ReadLba) - DicConsole.WriteLine("Using ATA READ command (LBA)."); - else if(ReadDmaRetry) - DicConsole.WriteLine("Using ATA READ DMA command with retries (CHS)."); - else if(ReadDma) - DicConsole.WriteLine("Using ATA READ DMA command (CHS)."); - else if(ReadRetry) - DicConsole.WriteLine("Using ATA READ command with retries (CHS)."); - else if(Read) - DicConsole.WriteLine("Using ATA READ command (CHS)."); - - uint blocksToRead = 64; - bool error = true; - while(lbaMode) - { - if(ReadDmaLba48) - { - sense = dev.ReadDma(out cmdBuf, out errorLba48, 0, (byte)blocksToRead, timeout, out duration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - } - else if(ReadLba48) - { - sense = dev.Read(out cmdBuf, out errorLba48, 0, (byte)blocksToRead, timeout, out duration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - } - else if(ReadDmaRetryLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, true, 0, (byte)blocksToRead, timeout, out duration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - else if(ReadDmaLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, false, 0, (byte)blocksToRead, timeout, out duration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - else if(ReadRetryLba) - { - sense = dev.Read(out cmdBuf, out errorLba, true, 0, (byte)blocksToRead, timeout, out duration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - else if(ReadLba) - { - sense = dev.Read(out cmdBuf, out errorLba, false, 0, (byte)blocksToRead, timeout, out duration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - - if(error) - blocksToRead /= 2; - - if(!error || blocksToRead == 1) - break; - } - - if(error && lbaMode) - { - DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError); - return; - } - DateTime start; DateTime end; double totalDuration = 0; @@ -359,7 +166,30 @@ namespace DiscImageChef.Core.Devices.Dumping DataFile dumpFile; - if(lbaMode) + // Initializate reader + Reader ataReader = new Reader(dev, timeout, cmdBuf); + // Fill reader blocks + ulong blocks = ataReader.GetDeviceBlocks(); + // Check block sizes + if(ataReader.GetBlockSize()) + { + DicConsole.ErrorWriteLine(ataReader.ErrorMessage); + return; + } + uint blockSize = ataReader.LogicalBlockSize; + uint physicalsectorsize = ataReader.PhysicalBlockSize; + // Check how many blocks to read, if error show and return + if(ataReader.GetBlocksToRead()) + { + DicConsole.ErrorWriteLine(ataReader.ErrorMessage); + return; + } + uint blocksToRead = ataReader.BlocksToRead; + ushort cylinders = ataReader.Cylinders; + byte heads = ataReader.Heads; + byte sectors = ataReader.Sectors; + + if(ataReader.IsLBA) { DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); @@ -373,8 +203,6 @@ namespace DiscImageChef.Core.Devices.Dumping if(aborted) break; - double cmdDuration = 0; - if((blocks - i) < blocksToRead) blocksToRead = (byte)(blocks - i); @@ -387,73 +215,28 @@ namespace DiscImageChef.Core.Devices.Dumping DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed); - error = true; - byte status = 0, errorByte = 0; - - if(ReadDmaLba48) - { - sense = dev.ReadDma(out cmdBuf, out errorLba48, i, (byte)blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - status = errorLba48.status; - errorByte = errorLba48.error; - } - else if(ReadLba48) - { - sense = dev.Read(out cmdBuf, out errorLba48, i, (byte)blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - status = errorLba48.status; - errorByte = errorLba48.error; - } - else if(ReadDmaRetryLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, true, (uint)i, (byte)blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - status = errorLba.status; - errorByte = errorLba.error; - } - else if(ReadDmaLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, false, (uint)i, (byte)blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - status = errorLba.status; - errorByte = errorLba.error; - } - else if(ReadRetryLba) - { - sense = dev.Read(out cmdBuf, out errorLba, true, (uint)i, (byte)blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - status = errorLba.status; - errorByte = errorLba.error; - } - else if(ReadLba) - { - sense = dev.Read(out cmdBuf, out errorLba, false, (uint)i, (byte)blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - status = errorLba.status; - errorByte = errorLba.error; - } + bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration); if(!error) { - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, duration); ibgLog.Write(i, currentSpeed * 1024); dumpFile.Write(cmdBuf); } else { - DicConsole.DebugWriteLine("Media-Scan", "ATA ERROR: {0} STATUS: {1}", errorByte, status); unreadableSectors.Add(i); - if(cmdDuration < 500) + if(duration < 500) mhddLog.Write(i, 65535); else - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, duration); ibgLog.Write(i, 0); dumpFile.Write(new byte[blockSize * blocksToRead]); } #pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created - currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (cmdDuration / (double)1000); + currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (duration / (double)1000); #pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created GC.Collect(); } @@ -490,42 +273,11 @@ namespace DiscImageChef.Core.Devices.Dumping if(aborted) break; - double cmdDuration = 0; - DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : ""); - if(ReadDmaLba48) - { - sense = dev.ReadDma(out cmdBuf, out errorLba48, badSector, 1, timeout, out cmdDuration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - } - else if(ReadLba48) - { - sense = dev.Read(out cmdBuf, out errorLba48, badSector, 1, timeout, out cmdDuration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - } - else if(ReadDmaRetryLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, true, (uint)badSector, 1, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - else if(ReadDmaLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, false, (uint)badSector, 1, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - else if(ReadRetryLba) - { - sense = dev.Read(out cmdBuf, out errorLba, true, (uint)badSector, 1, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - else if(ReadLba) - { - sense = dev.Read(out cmdBuf, out errorLba, false, (uint)badSector, 1, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } + bool error = ataReader.ReadBlock(out cmdBuf, badSector, out duration); - totalDuration += cmdDuration; + totalDuration += duration; if(!error) { @@ -567,8 +319,6 @@ namespace DiscImageChef.Core.Devices.Dumping if(aborted) break; - double cmdDuration = 0; - #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator if(currentSpeed > maxSpeed && currentSpeed != 0) maxSpeed = currentSpeed; @@ -578,61 +328,30 @@ namespace DiscImageChef.Core.Devices.Dumping DicConsole.Write("\rReading cylinder {0} head {1} sector {2} ({3:F3} MiB/sec.)", Cy, Hd, Sc, currentSpeed); - error = true; - byte status = 0, errorByte = 0; + bool error = ataReader.ReadCHS(out cmdBuf, Cy, Hd, Sc, out duration); - if(ReadDmaRetry) - { - sense = dev.ReadDma(out cmdBuf, out errorChs, true, Cy, Hd, Sc, 1, timeout, out cmdDuration); - error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - status = errorChs.status; - errorByte = errorChs.error; - } - else if(ReadDma) - { - sense = dev.ReadDma(out cmdBuf, out errorChs, false, Cy, Hd, Sc, 1, timeout, out cmdDuration); - error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - status = errorChs.status; - errorByte = errorChs.error; - } - else if(ReadRetry) - { - sense = dev.Read(out cmdBuf, out errorChs, true, Cy, Hd, Sc, 1, timeout, out cmdDuration); - error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - status = errorChs.status; - errorByte = errorChs.error; - } - else if(Read) - { - sense = dev.Read(out cmdBuf, out errorChs, false, Cy, Hd, Sc, 1, timeout, out cmdDuration); - error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - status = errorChs.status; - errorByte = errorChs.error; - } - - totalDuration += cmdDuration; + totalDuration += duration; if(!error) { - mhddLog.Write(currentBlock, cmdDuration); + mhddLog.Write(currentBlock, duration); ibgLog.Write(currentBlock, currentSpeed * 1024); dumpFile.Write(cmdBuf); } else { - DicConsole.DebugWriteLine("Media-Scan", "ATA ERROR: {0} STATUS: {1}", errorByte, status); unreadableSectors.Add(currentBlock); - if(cmdDuration < 500) + if(duration < 500) mhddLog.Write(currentBlock, 65535); else - mhddLog.Write(currentBlock, cmdDuration); + mhddLog.Write(currentBlock, duration); ibgLog.Write(currentBlock, 0); dumpFile.Write(new byte[blockSize]); } #pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created - currentSpeed = ((double)blockSize / (double)1048576) / (cmdDuration / (double)1000); + currentSpeed = ((double)blockSize / (double)1048576) / (duration / (double)1000); #pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created GC.Collect(); diff --git a/DiscImageChef.Core/Devices/Dumping/SCSI.cs b/DiscImageChef.Core/Devices/Dumping/SCSI.cs index 431a2a650..0082e5c6a 100644 --- a/DiscImageChef.Core/Devices/Dumping/SCSI.cs +++ b/DiscImageChef.Core/Devices/Dumping/SCSI.cs @@ -144,6 +144,7 @@ namespace DiscImageChef.Core.Devices.Dumping } } + Reader scsiReader = null; if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.DirectAccess || dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice || dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.OCRWDevice || @@ -151,36 +152,13 @@ namespace DiscImageChef.Core.Devices.Dumping dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.SimplifiedDevice || dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.WriteOnceDevice) { - sense = dev.ReadCapacity(out cmdBuf, out senseBuf, dev.Timeout, out duration); - if(!sense) + scsiReader = new Reader(dev, dev.Timeout, null, dumpRaw); + blocks = scsiReader.GetDeviceBlocks(); + blockSize = scsiReader.LogicalBlockSize; + if(scsiReader.FindReadCommand()) { - blocks = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + (cmdBuf[3])); - blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + (cmdBuf[7])); - } - - if(sense || blocks == 0xFFFFFFFF) - { - sense = dev.ReadCapacity16(out cmdBuf, out senseBuf, dev.Timeout, out duration); - - if(sense && blocks == 0) - { - // Not all MMC devices support READ CAPACITY, as they have READ TOC - if(dev.SCSIType != Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice) - { - DicConsole.ErrorWriteLine("Unable to get media capacity"); - DicConsole.ErrorWriteLine("{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); - } - } - - if(!sense) - { - byte[] temp = new byte[8]; - - Array.Copy(cmdBuf, 0, temp, 0, 8); - Array.Reverse(temp); - blocks = BitConverter.ToUInt64(temp, 0); - blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + (cmdBuf[7])); - } + DicConsole.ErrorWriteLine("Unable to read medium."); + return; } if(blocks != 0 && blockSize != 0) @@ -191,7 +169,7 @@ namespace DiscImageChef.Core.Devices.Dumping } logicalBlockSize = blockSize; - physicalBlockSize = blockSize; + physicalBlockSize = scsiReader.PhysicalBlockSize; } DateTime start; @@ -1502,10 +1480,7 @@ namespace DiscImageChef.Core.Devices.Dumping e.Cancel = aborted = true; }; - // TODO: Raw reading - bool read6 = false, read10 = false, read12 = false, read16 = false, readcd = false; - bool readLong10 = false, readLong16 = false, hldtstReadRaw = false, readLongDvd = false; - bool plextorReadRaw = false, syqReadLong6 = false, syqReadLong10 = false; + bool readcd = false; #region CompactDisc dump if(compactDisc) @@ -1994,7 +1969,7 @@ namespace DiscImageChef.Core.Devices.Dumping DicConsole.WriteLine("Real layer break: {0}", layerBreak); DicConsole.WriteLine(); - read12 = !dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, false, dev.Timeout, out duration); + bool read12 = !dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, false, dev.Timeout, out duration); if(!read12) { DicConsole.ErrorWriteLine("Cannot read medium, aborting scan..."); @@ -2605,246 +2580,13 @@ namespace DiscImageChef.Core.Devices.Dumping #endregion Xbox Game Disc else { - uint longBlockSize = blockSize; - bool rawAble = false; + uint longBlockSize = scsiReader.LongBlockSize; if(dumpRaw) { - bool testSense; - Decoders.SCSI.FixedSense? decSense; - - if(dev.SCSIType != Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice) - { - /*testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 0xFFFF, dev.Timeout, out duration); - if (testSense && !dev.Error) - { - decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); - if (decSense.HasValue) - { - if (decSense.Value.SenseKey == DiscImageChef.Decoders.SCSI.SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) - { - rawAble = true; - if (decSense.Value.InformationValid && decSense.Value.ILI) - { - longBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); - readLong16 = !dev.ReadLong16(out readBuffer, out senseBuf, false, 0, longBlockSize, dev.Timeout, out duration); - } - } - } - }*/ - - testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 0xFFFF, dev.Timeout, out duration); - if(testSense && !dev.Error) - { - decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); - if(decSense.HasValue) - { - if(decSense.Value.SenseKey == Decoders.SCSI.SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) - { - rawAble = true; - if(decSense.Value.InformationValid && decSense.Value.ILI) - { - longBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); - readLong10 = !dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, (ushort)longBlockSize, dev.Timeout, out duration); - } - } - } - } - - if(rawAble && longBlockSize == blockSize) - { - if(blockSize == 512) - { - // Long sector sizes for 512-byte magneto-opticals - foreach(ushort testSize in new[] { 600, 610, 630 }) - { - testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, testSize, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong16 = true; - longBlockSize = testSize; - rawAble = true; - break; - } - - testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, testSize, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong10 = true; - longBlockSize = testSize; - rawAble = true; - break; - } - } - } - else if(blockSize == 1024) - { - testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 1200, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong16 = true; - longBlockSize = 1200; - rawAble = true; - } - else - { - testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 1200, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong10 = true; - longBlockSize = 1200; - rawAble = true; - } - } - } - else if(blockSize == 2048) - { - testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 2380, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong16 = true; - longBlockSize = 2380; - rawAble = true; - } - else - { - testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 2380, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong10 = true; - longBlockSize = 2380; - rawAble = true; - } - } - } - else if(blockSize == 4096) - { - testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 4760, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong16 = true; - longBlockSize = 4760; - rawAble = true; - } - else - { - testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 4760, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong10 = true; - longBlockSize = 4760; - rawAble = true; - } - } - } - else if(blockSize == 8192) - { - testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 9424, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong16 = true; - longBlockSize = 9424; - rawAble = true; - } - else - { - testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 9424, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLong10 = true; - longBlockSize = 9424; - rawAble = true; - } - } - } - } - - if(!rawAble && dev.Manufacturer == "SYQUEST") - { - testSense = dev.SyQuestReadLong10(out readBuffer, out senseBuf, 0, 0xFFFF, dev.Timeout, out duration); - if(testSense) - { - decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); - if(decSense.HasValue) - { - if(decSense.Value.SenseKey == Decoders.SCSI.SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) - { - rawAble = true; - if(decSense.Value.InformationValid && decSense.Value.ILI) - { - longBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); - syqReadLong10 = !dev.SyQuestReadLong10(out readBuffer, out senseBuf, 0, longBlockSize, dev.Timeout, out duration); - } - } - else - { - testSense = dev.SyQuestReadLong6(out readBuffer, out senseBuf, 0, 0xFFFF, dev.Timeout, out duration); - if(testSense) - { - decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); - if(decSense.HasValue) - { - if(decSense.Value.SenseKey == Decoders.SCSI.SenseKeys.IllegalRequest && - decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) - { - rawAble = true; - if(decSense.Value.InformationValid && decSense.Value.ILI) - { - longBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); - syqReadLong6 = !dev.SyQuestReadLong6(out readBuffer, out senseBuf, 0, longBlockSize, dev.Timeout, out duration); - } - } - } - } - } - } - } - - if(!rawAble && blockSize == 256) - { - testSense = dev.SyQuestReadLong6(out readBuffer, out senseBuf, 0, 262, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - syqReadLong6 = true; - longBlockSize = 262; - rawAble = true; - } - } - } - } - else - { - if(dev.Manufacturer == "HL-DT-ST") - hldtstReadRaw = !dev.HlDtStReadRawDvd(out readBuffer, out senseBuf, 0, 1, dev.Timeout, out duration); - - if(dev.Manufacturer == "PLEXTOR") - hldtstReadRaw = !dev.PlextorReadRawDvd(out readBuffer, out senseBuf, 0, 1, dev.Timeout, out duration); - - if(hldtstReadRaw || plextorReadRaw) - { - rawAble = true; - longBlockSize = 2064; - } - - // READ LONG (10) for some DVD drives - if(!rawAble && dev.Manufacturer == "MATSHITA") - { - testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 37856, dev.Timeout, out duration); - if(!testSense && !dev.Error) - { - readLongDvd = true; - longBlockSize = 37856; - rawAble = true; - } - } - } - if(blockSize == longBlockSize) { - if(!rawAble) + if(!scsiReader.CanReadRaw) { DicConsole.ErrorWriteLine("Device doesn't seem capable of reading raw data from media."); } @@ -2865,22 +2607,8 @@ namespace DiscImageChef.Core.Devices.Dumping } else { - if(readLong16) - DicConsole.WriteLine("Using SCSI READ LONG (16) command."); - else if(readLong10 || readLongDvd) - DicConsole.WriteLine("Using SCSI READ LONG (10) command."); - else if(syqReadLong10) - DicConsole.WriteLine("Using SyQuest READ LONG (10) command."); - else if(syqReadLong6) - DicConsole.WriteLine("Using SyQuest READ LONG (6) command."); - else if(hldtstReadRaw) - DicConsole.WriteLine("Using HL-DT-ST raw DVD reading."); - else if(plextorReadRaw) - DicConsole.WriteLine("Using Plextor raw DVD reading."); - else - throw new AccessViolationException("Should not arrive here"); - if(readLongDvd) // Only a block will be read, but it contains 16 sectors and command expect sector number not block number + if(longBlockSize == 37856) // Only a block will be read, but it contains 16 sectors and command expect sector number not block number blocksToRead = 16; else blocksToRead = 1; @@ -2889,87 +2617,8 @@ namespace DiscImageChef.Core.Devices.Dumping physicalBlockSize = longBlockSize; blockSize = longBlockSize; } + } - - if(!dumpRaw) - { - read6 = !dev.Read6(out readBuffer, out senseBuf, 0, blockSize, dev.Timeout, out duration); - - read10 = !dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, dev.Timeout, out duration); - - read12 = !dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, false, dev.Timeout, out duration); - - read16 = !dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, 0, blockSize, 0, 1, false, dev.Timeout, out duration); - - if(!read6 && !read10 && !read12 && !read16) - { - DicConsole.ErrorWriteLine("Cannot read medium, aborting scan..."); - return; - } - - if(read6 && !read10 && !read12 && !read16 && blocks > (0x001FFFFF + 1)) - { - DicConsole.ErrorWriteLine("Device only supports SCSI READ (6) but has more than {0} blocks ({1} blocks total)", 0x001FFFFF + 1, blocks); - return; - } - -#pragma warning disable IDE0004 // Remove Unnecessary Cast - if(!read16 && blocks > ((long)0xFFFFFFFF + (long)1)) -#pragma warning restore IDE0004 // Remove Unnecessary Cast - { -#pragma warning disable IDE0004 // Remove Unnecessary Cast - DicConsole.ErrorWriteLine("Device only supports SCSI READ (10) but has more than {0} blocks ({1} blocks total)", (long)0xFFFFFFFF + (long)1, blocks); -#pragma warning restore IDE0004 // Remove Unnecessary Cast - return; - } - - if(read16) - DicConsole.WriteLine("Using SCSI READ (16) command."); - else if(read12) - DicConsole.WriteLine("Using SCSI READ (12) command."); - else if(read10) - DicConsole.WriteLine("Using SCSI READ (10) command."); - else if(read6) - DicConsole.WriteLine("Using SCSI READ (6) command."); - - while(true) - { - if(read16) - { - sense = dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, 0, blockSize, 0, blocksToRead, false, dev.Timeout, out duration); - if(dev.Error) - blocksToRead /= 2; - } - else if(read12) - { - sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, 0, blockSize, 0, blocksToRead, false, dev.Timeout, out duration); - if(dev.Error) - blocksToRead /= 2; - } - else if(read10) - { - sense = dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, (ushort)blocksToRead, dev.Timeout, out duration); - if(dev.Error) - blocksToRead /= 2; - } - else if(read6) - { - sense = dev.Read6(out readBuffer, out senseBuf, 0, blockSize, (byte)blocksToRead, dev.Timeout, out duration); - if(dev.Error) - blocksToRead /= 2; - } - - if(!dev.Error || blocksToRead == 1) - break; - } - - if(dev.Error) - { - DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError); - return; - } - } - DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); mhddLog = new MHDDLog(outputPrefix + ".mhddlog.bin", dev, blocks, blockSize, blocksToRead); @@ -2999,56 +2648,8 @@ namespace DiscImageChef.Core.Devices.Dumping DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", i, blocks, currentSpeed); - if(readLong16) - { - sense = dev.ReadLong16(out readBuffer, out senseBuf, false, i, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(readLong10 || readLongDvd) - { - sense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, (uint)i, (ushort)blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(syqReadLong10) - { - sense = dev.SyQuestReadLong10(out readBuffer, out senseBuf, (uint)i, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(syqReadLong6) - { - sense = dev.SyQuestReadLong6(out readBuffer, out senseBuf, (uint)i, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(hldtstReadRaw) - { - sense = dev.HlDtStReadRawDvd(out readBuffer, out senseBuf, (uint)i, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(plextorReadRaw) - { - sense = dev.PlextorReadRawDvd(out readBuffer, out senseBuf, (uint)i, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(read16) - { - sense = dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, i, blockSize, 0, blocksToRead, false, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(read12) - { - sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)i, blockSize, 0, blocksToRead, false, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(read10) - { - sense = dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0, (ushort)blocksToRead, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(read6) - { - sense = dev.Read6(out readBuffer, out senseBuf, (uint)i, blockSize, (byte)blocksToRead, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } + sense = scsiReader.ReadBlocks(out readBuffer, i, blocksToRead, out cmdDuration); + totalDuration += cmdDuration; if(!sense && !dev.Error) { @@ -3069,7 +2670,6 @@ namespace DiscImageChef.Core.Devices.Dumping errored += blocksToRead; unreadableSectors.Add(i); - DicConsole.DebugWriteLine("Dump-Media", "READ error:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); if(cmdDuration < 500) mhddLog.Write(i, 65535); else @@ -3119,56 +2719,8 @@ namespace DiscImageChef.Core.Devices.Dumping DicConsole.Write("\rRetrying sector {0}, pass {1}, {3}{2}", badSector, pass + 1, forward ? "forward" : "reverse", runningPersistent ? "recovering partial data, " : ""); - if(readLong16) - { - sense = dev.ReadLong16(out readBuffer, out senseBuf, false, badSector, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(readLong10) - { - sense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, (uint)badSector, (ushort)blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(syqReadLong10) - { - sense = dev.SyQuestReadLong10(out readBuffer, out senseBuf, (uint)badSector, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(syqReadLong6) - { - sense = dev.SyQuestReadLong6(out readBuffer, out senseBuf, (uint)badSector, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(hldtstReadRaw) - { - sense = dev.HlDtStReadRawDvd(out readBuffer, out senseBuf, (uint)badSector, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(plextorReadRaw) - { - sense = dev.PlextorReadRawDvd(out readBuffer, out senseBuf, (uint)badSector, blockSize, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(read16) - { - sense = dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, badSector, blockSize, 0, 1, false, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(read12) - { - sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)badSector, blockSize, 0, 1, false, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(read10) - { - sense = dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)badSector, blockSize, 0, 1, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } - else if(read6) - { - sense = dev.Read6(out readBuffer, out senseBuf, (uint)badSector, blockSize, 1, dev.Timeout, out cmdDuration); - totalDuration += cmdDuration; - } + sense = scsiReader.ReadBlock(out readBuffer, badSector, out cmdDuration); + totalDuration += cmdDuration; if(!sense && !dev.Error) { diff --git a/DiscImageChef.Core/Devices/Reader.cs b/DiscImageChef.Core/Devices/Reader.cs new file mode 100644 index 000000000..d02b46ddd --- /dev/null +++ b/DiscImageChef.Core/Devices/Reader.cs @@ -0,0 +1,214 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : Reader.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : Component +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; +using DiscImageChef.Devices; +using DiscImageChef.Decoders.ATA; + +namespace DiscImageChef.Core.Devices +{ + public partial class Reader + { + Device dev; + uint timeout; + ulong blocks; + uint blocksToRead; + string errorMessage; + bool readRaw; + uint blockSize; + uint physicalsectorsize; + uint longBlockSize; + + public string ErrorMessage { get { return errorMessage; } } + public ulong Blocks { get { return blocks; } } + public uint BlocksToRead { get { return blocksToRead; } } + public uint LogicalBlockSize { get { return blockSize; } } + public uint PhysicalBlockSize { get { return physicalsectorsize; } } + public uint LongBlockSize { get { return longBlockSize; } } + public bool CanReadRaw { get { return readRaw; } } + public bool CanSeek { get { return ataSeek || seek6 || seek10; } } + public bool CanSeekLBA { get { return ataSeekLba || seek6 || seek10; } } + + public Reader(Device dev, uint timeout, byte[] identification, bool raw = false) + { + this.dev = dev; + this.timeout = timeout; + blocksToRead = 64; + readRaw = raw; + + switch(dev.Type) + { + case DeviceType.ATA: + if(Identify.Decode(identification).HasValue) + ataId = Identify.Decode(identification).Value; + break; + case DeviceType.NVMe: + throw new NotImplementedException("NVMe devices not yet supported."); + case DeviceType.MMC: + case DeviceType.SecureDigital: + throw new NotImplementedException("MMC/SD devices not yet supported."); + } + } + + public ulong GetDeviceBlocks() + { + switch(dev.Type) + { + case DeviceType.ATA: + return AtaGetBlocks(); + case DeviceType.ATAPI: + case DeviceType.SCSI: + return ScsiGetBlocks(); + default: + errorMessage = string.Format("Unknown device type {0}.", dev.Type); + return 0; + } + } + + public bool FindReadCommand() + { + switch(dev.Type) + { + case DeviceType.ATA: + return AtaFindReadCommand(); + case DeviceType.ATAPI: + case DeviceType.SCSI: + return ScsiFindReadCommand(); + default: + errorMessage = string.Format("Unknown device type {0}.", dev.Type); + return true; + } + } + + public bool GetBlockSize() + { + switch(dev.Type) + { + case DeviceType.ATA: + return AtaGetBlockSize(); + case DeviceType.ATAPI: + case DeviceType.SCSI: + return ScsiGetBlockSize(); + default: + errorMessage = string.Format("Unknown device type {0}.", dev.Type); + return true; + } + } + + public bool GetBlocksToRead(uint startWithBlocks = 64) + { + switch(dev.Type) + { + case DeviceType.ATA: + return AtaGetBlocksToRead(startWithBlocks); + case DeviceType.ATAPI: + case DeviceType.SCSI: + return ScsiGetBlocksToRead(startWithBlocks); + default: + errorMessage = string.Format("Unknown device type {0}.", dev.Type); + return true; + } + } + + public bool ReadBlock(out byte[] buffer, ulong block, out double duration) + { + return ReadBlocks(out buffer, block, 1, out duration); + } + + public bool ReadBlocks(out byte[] buffer, ulong block, out double duration) + { + return ReadBlocks(out buffer, block, blocksToRead, out duration); + } + + public bool ReadBlocks(out byte[] buffer, ulong block, uint count, out double duration) + { + switch(dev.Type) + { + case DeviceType.ATA: + return AtaReadBlocks(out buffer, block, count, out duration); + case DeviceType.ATAPI: + case DeviceType.SCSI: + return ScsiReadBlocks(out buffer, block, count, out duration); + default: + buffer = null; + duration = 0d; + return true; + } + } + + public bool ReadCHS(out byte[] buffer, ushort cylinder, byte head, byte sector, out double duration) + { + switch(dev.Type) + { + case DeviceType.ATA: + return AtaReadCHS(out buffer, cylinder, head, sector, out duration); + default: + buffer = null; + duration = 0d; + return true; + } + } + + public bool Seek(ulong block, out double duration) + { + switch(dev.Type) + { + case DeviceType.ATA: + return AtaSeek(block, out duration); + case DeviceType.ATAPI: + case DeviceType.SCSI: + return ScsiSeek(block, out duration); + default: + duration = 0d; + return true; + } + } + + public bool SeekCHS(ushort cylinder, byte head, byte sector, out double duration) + { + switch(dev.Type) + { + case DeviceType.ATA: + return AtaSeekCHS(cylinder, head, sector, out duration); + default: + duration = 0; + return true; + } + } + } +} diff --git a/DiscImageChef.Core/Devices/ReaderATA.cs b/DiscImageChef.Core/Devices/ReaderATA.cs new file mode 100644 index 000000000..55f7ef549 --- /dev/null +++ b/DiscImageChef.Core/Devices/ReaderATA.cs @@ -0,0 +1,420 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : ReaderATA.cs +// Version : 1.0 +// Author(s) : Natalia Portillo +// +// Component : Component +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; +using DiscImageChef.Decoders.ATA; +using DiscImageChef.Devices; + +namespace DiscImageChef.Core.Devices +{ + public partial class Reader + { + bool ataReadLba; + bool ataReadRetryLba; + bool ataReadDmaLba; + bool ataReadDmaRetryLba; + bool ataReadLba48; + bool ataReadDmaLba48; + bool ataRead; + bool ataReadRetry; + bool ataReadDma; + bool ataReadDmaRetry; + bool lbaMode; + ushort cylinders; + byte heads, sectors; + bool ataSeek; + bool ataSeekLba; + + Identify.IdentifyDevice ataId; + + public bool IsLBA { get { return lbaMode; } } + public ushort Cylinders { get { return cylinders; } } + public byte Heads { get { return heads; } } + public byte Sectors { get { return sectors; } } + + public (uint, byte, byte) GetDeviceCHS() + { + if(dev.Type != DeviceType.ATA) + return (0, 0, 0); + + if(ataId.CurrentCylinders > 0 && ataId.CurrentHeads > 0 && ataId.CurrentSectorsPerTrack > 0) + { + cylinders = ataId.CurrentCylinders; + heads = (byte)ataId.CurrentHeads; + sectors = (byte)ataId.CurrentSectorsPerTrack; + blocks = (ulong)(cylinders * heads * sectors); + } + + if((ataId.CurrentCylinders == 0 || ataId.CurrentHeads == 0 || ataId.CurrentSectorsPerTrack == 0) && + (ataId.Cylinders > 0 && ataId.Heads > 0 && ataId.SectorsPerTrack > 0)) + { + cylinders = ataId.Cylinders; + heads = (byte)ataId.Heads; + sectors = (byte)ataId.SectorsPerTrack; + blocks = (ulong)(cylinders * heads * sectors); + } + + return (cylinders, heads, sectors); + } + + ulong AtaGetBlocks() + { + GetDeviceCHS(); + + if(ataId.Capabilities.HasFlag(Identify.CapabilitiesBit.LBASupport)) + { + blocks = ataId.LBASectors; + lbaMode = true; + } + + if(ataId.CommandSet2.HasFlag(Identify.CommandSetBit2.LBA48)) + { + blocks = ataId.LBA48Sectors; + lbaMode = true; + } + + return blocks; + } + + bool AtaFindReadCommand() + { + byte[] cmdBuf; + bool sense; + AtaErrorRegistersCHS errorChs; + AtaErrorRegistersLBA28 errorLba; + AtaErrorRegistersLBA48 errorLba48; + double duration; + + sense = dev.Read(out cmdBuf, out errorChs, false, 0, 0, 1, 1, timeout, out duration); + ataRead = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); + sense = dev.Read(out cmdBuf, out errorChs, true, 0, 0, 1, 1, timeout, out duration); + ataReadRetry = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); + sense = dev.ReadDma(out cmdBuf, out errorChs, false, 0, 0, 1, 1, timeout, out duration); + ataReadDma = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); + sense = dev.ReadDma(out cmdBuf, out errorChs, true, 0, 0, 1, 1, timeout, out duration); + ataReadDmaRetry = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); + + sense = dev.Read(out cmdBuf, out errorLba, false, 0, 1, timeout, out duration); + ataReadLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); + sense = dev.Read(out cmdBuf, out errorLba, true, 0, 1, timeout, out duration); + ataReadRetryLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); + sense = dev.ReadDma(out cmdBuf, out errorLba, false, 0, 1, timeout, out duration); + ataReadDmaLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); + sense = dev.ReadDma(out cmdBuf, out errorLba, true, 0, 1, timeout, out duration); + ataReadDmaRetryLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); + + sense = dev.Read(out cmdBuf, out errorLba48, 0, 1, timeout, out duration); + ataReadLba48 = (!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); + sense = dev.ReadDma(out cmdBuf, out errorLba48, 0, 1, timeout, out duration); + ataReadDmaLba48 = (!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); + + sense = dev.Seek(out errorChs, 0, 0, 1, timeout, out duration); + ataSeek = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0); + sense = dev.Seek(out errorLba, 0, timeout, out duration); + ataSeekLba = (!sense && (errorLba.status & 0x27) == 0 && errorChs.error == 0); + + if(!lbaMode) + { + if(blocks > 0xFFFFFFF && !ataReadLba48 && !ataReadDmaLba48) + { + errorMessage = "Device needs 48-bit LBA commands but I can't issue them... Aborting."; + return true; + } + + if(!ataReadLba && !ataReadRetryLba && !ataReadDmaLba && !ataReadDmaRetryLba) + { + errorMessage = "Device needs 28-bit LBA commands but I can't issue them... Aborting."; + return true; + } + } + else + { + if(!ataRead && !ataReadRetry && !ataReadDma && !ataReadDmaRetry) + { + errorMessage = "Device needs CHS commands but I can't issue them... Aborting."; + return true; + } + } + + if(ataReadDmaLba48) + DicConsole.WriteLine("Using ATA READ DMA EXT command."); + else if(ataReadLba48) + DicConsole.WriteLine("Using ATA READ EXT command."); + else if(ataReadDmaRetryLba) + DicConsole.WriteLine("Using ATA READ DMA command with retries (LBA)."); + else if(ataReadDmaLba) + DicConsole.WriteLine("Using ATA READ DMA command (LBA)."); + else if(ataReadRetryLba) + DicConsole.WriteLine("Using ATA READ command with retries (LBA)."); + else if(ataReadLba) + DicConsole.WriteLine("Using ATA READ command (LBA)."); + else if(ataReadDmaRetry) + DicConsole.WriteLine("Using ATA READ DMA command with retries (CHS)."); + else if(ataReadDma) + DicConsole.WriteLine("Using ATA READ DMA command (CHS)."); + else if(ataReadRetry) + DicConsole.WriteLine("Using ATA READ command with retries (CHS)."); + else if(ataRead) + DicConsole.WriteLine("Using ATA READ command (CHS)."); + + return false; + } + + bool AtaGetBlockSize() + { + if((ataId.PhysLogSectorSize & 0x8000) == 0x0000 && + (ataId.PhysLogSectorSize & 0x4000) == 0x4000) + { + if((ataId.PhysLogSectorSize & 0x1000) == 0x1000) + { + if(ataId.LogicalSectorWords <= 255 || ataId.LogicalAlignment == 0xFFFF) + blockSize = 512; + else + blockSize = ataId.LogicalSectorWords * 2; + } + else + blockSize = 512; + + if((ataId.PhysLogSectorSize & 0x2000) == 0x2000) + { +#pragma warning disable IDE0004 // Cast is necessary, otherwise incorrect value is created + physicalsectorsize = blockSize * (uint)Math.Pow(2, (double)(ataId.PhysLogSectorSize & 0xF)); +#pragma warning restore IDE0004 // Cast is necessary, otherwise incorrect value is created + } + else + physicalsectorsize = blockSize; + } + else + { + blockSize = 512; + physicalsectorsize = 512; + } + + // TODO: ATA READ LONG + longBlockSize = 0; + + return false; + } + + bool AtaGetBlocksToRead(uint startWithBlocks) + { + blocksToRead = startWithBlocks; + + if(!lbaMode) + { + blocksToRead = 1; + return false; + } + + byte[] cmdBuf; + bool sense; + AtaErrorRegistersLBA28 errorLba; + AtaErrorRegistersLBA48 errorLba48; + double duration; + bool error = true; + + while(lbaMode) + { + if(ataReadDmaLba48) + { + sense = dev.ReadDma(out cmdBuf, out errorLba48, 0, (byte)blocksToRead, timeout, out duration); + error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); + } + else if(ataReadLba48) + { + sense = dev.Read(out cmdBuf, out errorLba48, 0, (byte)blocksToRead, timeout, out duration); + error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); + } + else if(ataReadDmaRetryLba) + { + sense = dev.ReadDma(out cmdBuf, out errorLba, true, 0, (byte)blocksToRead, timeout, out duration); + error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); + } + else if(ataReadDmaLba) + { + sense = dev.ReadDma(out cmdBuf, out errorLba, false, 0, (byte)blocksToRead, timeout, out duration); + error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); + } + else if(ataReadRetryLba) + { + sense = dev.Read(out cmdBuf, out errorLba, true, 0, (byte)blocksToRead, timeout, out duration); + error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); + } + else if(ataReadLba) + { + sense = dev.Read(out cmdBuf, out errorLba, false, 0, (byte)blocksToRead, timeout, out duration); + error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); + } + + if(error) + blocksToRead /= 2; + + if(!error || blocksToRead == 1) + break; + } + + if(error && lbaMode) + { + blocksToRead = 1; + errorMessage=string.Format("Device error {0} trying to guess ideal transfer length.", dev.LastError); + return true; + } + + return false; + } + + bool AtaReadBlocks(out byte[] buffer, ulong block, uint count, out double duration) + { + bool error = true; + bool sense; + AtaErrorRegistersLBA28 errorLba; + AtaErrorRegistersLBA48 errorLba48; + byte status = 0, errorByte = 0; + buffer = null; + duration = 0; + + if(ataReadDmaLba48) + { + sense = dev.ReadDma(out buffer, out errorLba48, block, (byte)count, timeout, out duration); + error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && buffer.Length > 0); + status = errorLba48.status; + errorByte = errorLba48.error; + } + else if(ataReadLba48) + { + sense = dev.Read(out buffer, out errorLba48, block, (byte)count, timeout, out duration); + error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && buffer.Length > 0); + status = errorLba48.status; + errorByte = errorLba48.error; + } + else if(ataReadDmaRetryLba) + { + sense = dev.ReadDma(out buffer, out errorLba, true, (uint)block, (byte)count, timeout, out duration); + error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && buffer.Length > 0); + status = errorLba.status; + errorByte = errorLba.error; + } + else if(ataReadDmaLba) + { + sense = dev.ReadDma(out buffer, out errorLba, false, (uint)block, (byte)count, timeout, out duration); + error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && buffer.Length > 0); + status = errorLba.status; + errorByte = errorLba.error; + } + else if(ataReadRetryLba) + { + sense = dev.Read(out buffer, out errorLba, true, (uint)block, (byte)count, timeout, out duration); + error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && buffer.Length > 0); + status = errorLba.status; + errorByte = errorLba.error; + } + else if(ataReadLba) + { + sense = dev.Read(out buffer, out errorLba, false, (uint)block, (byte)count, timeout, out duration); + error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && buffer.Length > 0); + status = errorLba.status; + errorByte = errorLba.error; + } + + if(error) + DicConsole.DebugWriteLine("ATA Reader", "ATA ERROR: {0} STATUS: {1}", errorByte, status); + + return error; + } + + bool AtaReadCHS(out byte[] buffer, ushort cylinder, byte head, byte sectir, out double duration) + { + bool error = true; + bool sense; + AtaErrorRegistersCHS errorChs; + byte status = 0, errorByte = 0; + buffer = null; + duration = 0; + + if(ataReadDmaRetry) + { + sense = dev.ReadDma(out buffer, out errorChs, true, cylinder, head, sectir, 1, timeout, out duration); + error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && buffer.Length > 0); + status = errorChs.status; + errorByte = errorChs.error; + } + else if(ataReadDma) + { + sense = dev.ReadDma(out buffer, out errorChs, false, cylinder, head, sectir, 1, timeout, out duration); + error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && buffer.Length > 0); + status = errorChs.status; + errorByte = errorChs.error; + } + else if(ataReadRetry) + { + sense = dev.Read(out buffer, out errorChs, true, cylinder, head, sectir, 1, timeout, out duration); + error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && buffer.Length > 0); + status = errorChs.status; + errorByte = errorChs.error; + } + else if(ataRead) + { + sense = dev.Read(out buffer, out errorChs, false, cylinder, head, sectir, 1, timeout, out duration); + error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && buffer.Length > 0); + status = errorChs.status; + errorByte = errorChs.error; + } + + if(error) + DicConsole.DebugWriteLine("ATA Reader", "ATA ERROR: {0} STATUS: {1}", errorByte, status); + + return error; + } + + bool AtaSeek(ulong block, out double duration) + { + AtaErrorRegistersLBA28 errorLba; + + bool sense = dev.Seek(out errorLba, (uint)block, timeout, out duration); + return !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0); + } + + bool AtaSeekCHS(ushort cylinder, byte head, byte sector, out double duration) + { + AtaErrorRegistersCHS errorChs; + + bool sense = dev.Seek(out errorChs, cylinder, head, sector, timeout, out duration); + return !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0); + } + } +} diff --git a/DiscImageChef.Core/Devices/ReaderSCSI.cs b/DiscImageChef.Core/Devices/ReaderSCSI.cs new file mode 100644 index 000000000..253948898 --- /dev/null +++ b/DiscImageChef.Core/Devices/ReaderSCSI.cs @@ -0,0 +1,525 @@ +// /*************************************************************************** +// The Disc Image Chef +// ---------------------------------------------------------------------------- +// +// Filename : ReaderSCSI.cs +// Version : 1.0 +// Author(s) : NScsilia Portillo +// +// Component : Component +// +// Revision : $Revision$ +// Last change by : $Author$ +// Date : $Date$ +// +// --[ Description ] ---------------------------------------------------------- +// +// Description +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// Copyright (C) 2011-2015 Claunia.com +// ****************************************************************************/ +// //$Id$ +using System; +using DiscImageChef.Console; + +namespace DiscImageChef.Core.Devices +{ + public partial class Reader + { + // TODO: Raw reading + bool read6; + bool read10; + bool read12; + bool read16; + bool readLong10; + bool readLong16; + bool hldtstReadRaw; + bool readLongDvd; + bool plextorReadRaw; + bool syqReadLong6; + bool syqReadLong10; + bool seek6; + bool seek10; + + ulong ScsiGetBlocks() + { + return ScsiGetBlockSize() ? 0 : blocks; + } + + bool ScsiFindReadCommand() + { + byte[] readBuffer; + byte[] senseBuf; + double duration; + + read6 = !dev.Read6(out readBuffer, out senseBuf, 0, blockSize, timeout, out duration); + + read10 = !dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, timeout, out duration); + + read12 = !dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, false, timeout, out duration); + + read16 = !dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, 0, blockSize, 0, 1, false, timeout, out duration); + + seek6 = !dev.Seek6(out senseBuf, 0, timeout, out duration); + + seek10 = !dev.Seek10(out senseBuf, 0, timeout, out duration); + + if(!read6 && !read10 && !read12 && !read16) + { + errorMessage = "Cannot read medium, aborting scan..."; + return true; + } + + if(read6 && !read10 && !read12 && !read16 && blocks > (0x001FFFFF + 1)) + { + errorMessage = string.Format("Device only supports SCSI READ (6) but has more than {0} blocks ({1} blocks total)", 0x001FFFFF + 1, blocks); + return true; + } + +#pragma warning disable IDE0004 // Remove Unnecessary Cast + if(!read16 && blocks > ((long)0xFFFFFFFF + (long)1)) +#pragma warning restore IDE0004 // Remove Unnecessary Cast + { +#pragma warning disable IDE0004 // Remove Unnecessary Cast + errorMessage = string.Format("Device only supports SCSI READ (10) but has more than {0} blocks ({1} blocks total)", (long)0xFFFFFFFF + (long)1, blocks); +#pragma warning restore IDE0004 // Remove Unnecessary Cast + return true; + } + + if(readRaw) + { + bool testSense; + Decoders.SCSI.FixedSense? decSense; + readRaw = false; + + if(dev.SCSIType != Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice) + { + /*testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 0xFFFF, timeout, out duration); + if (testSense && !dev.Error) + { + decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); + if (decSense.HasValue) + { + if (decSense.Value.SenseKey == DiscImageChef.Decoders.SCSI.SenseKeys.IllegalRequest && + decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) + { + readRaw = true; + if (decSense.Value.InformationValid && decSense.Value.ILI) + { + longBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); + readLong16 = !dev.ReadLong16(out readBuffer, out senseBuf, false, 0, longBlockSize, timeout, out duration); + } + } + } + }*/ + + testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 0xFFFF, timeout, out duration); + if(testSense && !dev.Error) + { + decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); + if(decSense.HasValue) + { + if(decSense.Value.SenseKey == Decoders.SCSI.SenseKeys.IllegalRequest && + decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) + { + readRaw = true; + if(decSense.Value.InformationValid && decSense.Value.ILI) + { + longBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); + readLong10 = !dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, (ushort)longBlockSize, timeout, out duration); + } + } + } + } + + if(readRaw && longBlockSize == blockSize) + { + if(blockSize == 512) + { + // Long sector sizes for 512-byte magneto-opticals + foreach(ushort testSize in new[] { 600, 610, 630 }) + { + testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, testSize, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong16 = true; + longBlockSize = testSize; + readRaw = true; + break; + } + + testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, testSize, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong10 = true; + longBlockSize = testSize; + readRaw = true; + break; + } + } + } + else if(blockSize == 1024) + { + testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 1200, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong16 = true; + longBlockSize = 1200; + readRaw = true; + } + else + { + testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 1200, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong10 = true; + longBlockSize = 1200; + readRaw = true; + } + } + } + else if(blockSize == 2048) + { + testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 2380, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong16 = true; + longBlockSize = 2380; + readRaw = true; + } + else + { + testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 2380, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong10 = true; + longBlockSize = 2380; + readRaw = true; + } + } + } + else if(blockSize == 4096) + { + testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 4760, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong16 = true; + longBlockSize = 4760; + readRaw = true; + } + else + { + testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 4760, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong10 = true; + longBlockSize = 4760; + readRaw = true; + } + } + } + else if(blockSize == 8192) + { + testSense = dev.ReadLong16(out readBuffer, out senseBuf, false, 0, 9424, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong16 = true; + longBlockSize = 9424; + readRaw = true; + } + else + { + testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 9424, timeout, out duration); + if(!testSense && !dev.Error) + { + readLong10 = true; + longBlockSize = 9424; + readRaw = true; + } + } + } + } + + if(!readRaw && dev.Manufacturer == "SYQUEST") + { + testSense = dev.SyQuestReadLong10(out readBuffer, out senseBuf, 0, 0xFFFF, timeout, out duration); + if(testSense) + { + decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); + if(decSense.HasValue) + { + if(decSense.Value.SenseKey == Decoders.SCSI.SenseKeys.IllegalRequest && + decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) + { + readRaw = true; + if(decSense.Value.InformationValid && decSense.Value.ILI) + { + longBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); + syqReadLong10 = !dev.SyQuestReadLong10(out readBuffer, out senseBuf, 0, longBlockSize, timeout, out duration); + } + } + else + { + testSense = dev.SyQuestReadLong6(out readBuffer, out senseBuf, 0, 0xFFFF, timeout, out duration); + if(testSense) + { + decSense = Decoders.SCSI.Sense.DecodeFixed(senseBuf); + if(decSense.HasValue) + { + if(decSense.Value.SenseKey == Decoders.SCSI.SenseKeys.IllegalRequest && + decSense.Value.ASC == 0x24 && decSense.Value.ASCQ == 0x00) + { + readRaw = true; + if(decSense.Value.InformationValid && decSense.Value.ILI) + { + longBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF); + syqReadLong6 = !dev.SyQuestReadLong6(out readBuffer, out senseBuf, 0, longBlockSize, timeout, out duration); + } + } + } + } + } + } + } + + if(!readRaw && blockSize == 256) + { + testSense = dev.SyQuestReadLong6(out readBuffer, out senseBuf, 0, 262, timeout, out duration); + if(!testSense && !dev.Error) + { + syqReadLong6 = true; + longBlockSize = 262; + readRaw = true; + } + } + } + } + else + { + if(dev.Manufacturer == "HL-DT-ST") + hldtstReadRaw = !dev.HlDtStReadRawDvd(out readBuffer, out senseBuf, 0, 1, timeout, out duration); + + if(dev.Manufacturer == "PLEXTOR") + plextorReadRaw = !dev.PlextorReadRawDvd(out readBuffer, out senseBuf, 0, 1, timeout, out duration); + + if(hldtstReadRaw || plextorReadRaw) + { + readRaw = true; + longBlockSize = 2064; + } + + // READ LONG (10) for some DVD drives + if(!readRaw && dev.Manufacturer == "MATSHITA") + { + testSense = dev.ReadLong10(out readBuffer, out senseBuf, false, false, 0, 37856, timeout, out duration); + if(!testSense && !dev.Error) + { + readLongDvd = true; + longBlockSize = 37856; + readRaw = true; + } + } + } + } + + if(readRaw) + { + if(readLong16) + DicConsole.WriteLine("Using SCSI READ LONG (16) command."); + else if(readLong10 || readLongDvd) + DicConsole.WriteLine("Using SCSI READ LONG (10) command."); + else if(syqReadLong10) + DicConsole.WriteLine("Using SyQuest READ LONG (10) command."); + else if(syqReadLong6) + DicConsole.WriteLine("Using SyQuest READ LONG (6) command."); + else if(hldtstReadRaw) + DicConsole.WriteLine("Using HL-DT-ST raw DVD reading."); + else if(plextorReadRaw) + DicConsole.WriteLine("Using Plextor raw DVD reading."); + } + else if(read16) + DicConsole.WriteLine("Using SCSI READ (16) command."); + else if(read12) + DicConsole.WriteLine("Using SCSI READ (12) command."); + else if(read10) + DicConsole.WriteLine("Using SCSI READ (10) command."); + else if(read6) + DicConsole.WriteLine("Using SCSI READ (6) command."); + + return false; + } + + bool ScsiGetBlockSize() + { + bool sense; + byte[] cmdBuf; + byte[] senseBuf; + double duration; + blocks = 0; + + sense = dev.ReadCapacity(out cmdBuf, out senseBuf, timeout, out duration); + if(!sense) + { + blocks = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + (cmdBuf[3])); + blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + (cmdBuf[7])); + } + + if(sense || blocks == 0xFFFFFFFF) + { + sense = dev.ReadCapacity16(out cmdBuf, out senseBuf, timeout, out duration); + + if(sense && blocks == 0) + { + // Not all MMC devices support READ CAPACITY, as they have READ TOC + if(dev.SCSIType != Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice) + { + errorMessage = string.Format("Unable to get media capacity\n" + + "{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + + return true; + } + } + + if(!sense) + { + byte[] temp = new byte[8]; + + Array.Copy(cmdBuf, 0, temp, 0, 8); + Array.Reverse(temp); + blocks = BitConverter.ToUInt64(temp, 0); + blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + (cmdBuf[7])); + } + } + + physicalsectorsize = blockSize; + longBlockSize = blockSize; + return false; + } + + bool ScsiGetBlocksToRead(uint startWithBlocks) + { + bool sense; + byte[] readBuffer; + byte[] senseBuf; + double duration; + blocksToRead = startWithBlocks; + + while(true) + { + if(read16) + { + sense = dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, 0, blockSize, 0, blocksToRead, false, timeout, out duration); + if(dev.Error) + blocksToRead /= 2; + } + else if(read12) + { + sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, 0, blockSize, 0, blocksToRead, false, timeout, out duration); + if(dev.Error) + blocksToRead /= 2; + } + else if(read10) + { + sense = dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, (ushort)blocksToRead, timeout, out duration); + if(dev.Error) + blocksToRead /= 2; + } + else if(read6) + { + sense = dev.Read6(out readBuffer, out senseBuf, 0, blockSize, (byte)blocksToRead, timeout, out duration); + if(dev.Error) + blocksToRead /= 2; + } + + if(!dev.Error || blocksToRead == 1) + break; + } + + if(dev.Error) + { + blocksToRead = 1; + errorMessage = string.Format("Device error {0} trying to guess ideal transfer length.", dev.LastError); + return true; + } + + return false; + } + + bool ScsiReadBlocks(out byte[] buffer, ulong block, uint count, out double duration) + { + bool sense = false; + byte[] senseBuf = null; + buffer = null; + duration = 0; + + if(readRaw) + { + if(readLong16) + sense = dev.ReadLong16(out buffer, out senseBuf, false, block, longBlockSize, timeout, out duration); + else if(readLong10) + sense = dev.ReadLong10(out buffer, out senseBuf, false, false, (uint)block, (ushort)longBlockSize, timeout, out duration); + else if(syqReadLong10) + sense = dev.SyQuestReadLong10(out buffer, out senseBuf, (uint)block, longBlockSize, timeout, out duration); + else if(syqReadLong6) + sense = dev.SyQuestReadLong6(out buffer, out senseBuf, (uint)block, longBlockSize, timeout, out duration); + else if(hldtstReadRaw) + sense = dev.HlDtStReadRawDvd(out buffer, out senseBuf, (uint)block, longBlockSize, timeout, out duration); + else if(plextorReadRaw) + sense = dev.PlextorReadRawDvd(out buffer, out senseBuf, (uint)block, longBlockSize, timeout, out duration); + else + return true; + } + else + { + if(read16) + sense = dev.Read16(out buffer, out senseBuf, 0, false, true, false, block, blockSize, 0, count, false, timeout, out duration); + else if(read12) + sense = dev.Read12(out buffer, out senseBuf, 0, false, false, false, false, (uint)block, blockSize, 0, count, false, timeout, out duration); + else if(read10) + sense = dev.Read10(out buffer, out senseBuf, 0, false, true, false, false, (uint)block, blockSize, 0, (ushort)count, timeout, out duration); + else if(read6) + sense = dev.Read6(out buffer, out senseBuf, (uint)block, blockSize, (byte)count, timeout, out duration); + else + return true; + } + + if(sense || dev.Error) + { + DicConsole.DebugWriteLine("SCSI Reader", "READ error:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); + return true; + } + + return false; + } + + bool ScsiSeek(ulong block, out double duration) + { + byte[] senseBuf; + bool sense = true; + duration = 0; + + if(seek6) + sense = dev.Seek6(out senseBuf, (uint)block, timeout, out duration); + else if(seek10) + sense = dev.Seek10(out senseBuf, (uint)block, timeout, out duration); + + return sense; + } + } +} diff --git a/DiscImageChef.Core/Devices/Scanning/ATA.cs b/DiscImageChef.Core/Devices/Scanning/ATA.cs index 3309efa5d..0ed4fd187 100644 --- a/DiscImageChef.Core/Devices/Scanning/ATA.cs +++ b/DiscImageChef.Core/Devices/Scanning/ATA.cs @@ -54,200 +54,38 @@ namespace DiscImageChef.Core.Devices.Scanning byte[] cmdBuf; bool sense; results.blocks = 0; - uint blockSize; ushort currentProfile = 0x0001; Decoders.ATA.AtaErrorRegistersCHS errorChs; - Decoders.ATA.AtaErrorRegistersLBA28 errorLba; - Decoders.ATA.AtaErrorRegistersLBA48 errorLba48; bool lbaMode = false; - byte heads = 0, sectors = 0; - ushort cylinders = 0; uint timeout = 5; - double duration; + double duration = 0; sense = dev.AtaIdentify(out cmdBuf, out errorChs); if(!sense && Decoders.ATA.Identify.Decode(cmdBuf).HasValue) { Decoders.ATA.Identify.IdentifyDevice ataId = Decoders.ATA.Identify.Decode(cmdBuf).Value; - if(ataId.CurrentCylinders > 0 && ataId.CurrentHeads > 0 && ataId.CurrentSectorsPerTrack > 0) + // Initializate reader + Reader ataReader = new Reader(dev, timeout, cmdBuf); + // Fill reader blocks + results.blocks = ataReader.GetDeviceBlocks(); + // Check block sizes + if(ataReader.GetBlockSize()) { - cylinders = ataId.CurrentCylinders; - heads = (byte)ataId.CurrentHeads; - sectors = (byte)ataId.CurrentSectorsPerTrack; - results.blocks = (ulong)(cylinders * heads * sectors); - } - - if((ataId.CurrentCylinders == 0 || ataId.CurrentHeads == 0 || ataId.CurrentSectorsPerTrack == 0) && - (ataId.Cylinders > 0 && ataId.Heads > 0 && ataId.SectorsPerTrack > 0)) - { - cylinders = ataId.Cylinders; - heads = (byte)ataId.Heads; - sectors = (byte)ataId.SectorsPerTrack; - results.blocks = (ulong)(cylinders * heads * sectors); - } - - if(ataId.Capabilities.HasFlag(Decoders.ATA.Identify.CapabilitiesBit.LBASupport)) - { - results.blocks = ataId.LBASectors; - lbaMode = true; - } - - if(ataId.CommandSet2.HasFlag(Decoders.ATA.Identify.CommandSetBit2.LBA48)) - { - results.blocks = ataId.LBA48Sectors; - lbaMode = true; - } - - if((ataId.PhysLogSectorSize & 0x8000) == 0x0000 && - (ataId.PhysLogSectorSize & 0x4000) == 0x4000) - { - if((ataId.PhysLogSectorSize & 0x1000) == 0x1000) - { - if(ataId.LogicalSectorWords <= 255 || ataId.LogicalAlignment == 0xFFFF) - blockSize = 512; - else - blockSize = ataId.LogicalSectorWords * 2; - } - else - blockSize = 512; - } - else - blockSize = 512; - - bool ReadLba = false; - bool ReadRetryLba = false; - bool ReadDmaLba = false; - bool ReadDmaRetryLba = false; - bool SeekLba = false; - - bool ReadLba48 = false; - bool ReadDmaLba48 = false; - - bool Read = false; - bool ReadRetry = false; - bool ReadDma = false; - bool ReadDmaRetry = false; - bool Seek = false; - - sense = dev.Read(out cmdBuf, out errorChs, false, 0, 0, 1, 1, timeout, out duration); - Read = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - sense = dev.Read(out cmdBuf, out errorChs, true, 0, 0, 1, 1, timeout, out duration); - ReadRetry = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorChs, false, 0, 0, 1, 1, timeout, out duration); - ReadDma = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorChs, true, 0, 0, 1, 1, timeout, out duration); - ReadDmaRetry = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - sense = dev.Seek(out errorChs, 0, 0, 1, timeout, out duration); - Seek = (!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0); - - sense = dev.Read(out cmdBuf, out errorLba, false, 0, 1, timeout, out duration); - ReadLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - sense = dev.Read(out cmdBuf, out errorLba, true, 0, 1, timeout, out duration); - ReadRetryLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorLba, false, 0, 1, timeout, out duration); - ReadDmaLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorLba, true, 0, 1, timeout, out duration); - ReadDmaRetryLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - sense = dev.Seek(out errorLba, 0, timeout, out duration); - SeekLba = (!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0); - - sense = dev.Read(out cmdBuf, out errorLba48, 0, 1, timeout, out duration); - ReadLba48 = (!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - sense = dev.ReadDma(out cmdBuf, out errorLba48, 0, 1, timeout, out duration); - ReadDmaLba48 = (!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - - if(!lbaMode) - { - if(results.blocks > 0xFFFFFFF && !ReadLba48 && !ReadDmaLba48) - { - DicConsole.ErrorWriteLine("Device needs 48-bit LBA commands but I can't issue them... Aborting."); - return results; - } - - if(!ReadLba && !ReadRetryLba && !ReadDmaLba && !ReadDmaRetryLba) - { - DicConsole.ErrorWriteLine("Device needs 28-bit LBA commands but I can't issue them... Aborting."); - return results; - } - } - else - { - if(!Read && !ReadRetry && !ReadDma && !ReadDmaRetry) - { - DicConsole.ErrorWriteLine("Device needs CHS commands but I can't issue them... Aborting."); - return results; - } - } - - if(ReadDmaLba48) - DicConsole.WriteLine("Using ATA READ DMA EXT command."); - else if(ReadLba48) - DicConsole.WriteLine("Using ATA READ EXT command."); - else if(ReadDmaRetryLba) - DicConsole.WriteLine("Using ATA READ DMA command with retries (LBA)."); - else if(ReadDmaLba) - DicConsole.WriteLine("Using ATA READ DMA command (LBA)."); - else if(ReadRetryLba) - DicConsole.WriteLine("Using ATA READ command with retries (LBA)."); - else if(ReadLba) - DicConsole.WriteLine("Using ATA READ command (LBA)."); - else if(ReadDmaRetry) - DicConsole.WriteLine("Using ATA READ DMA command with retries (CHS)."); - else if(ReadDma) - DicConsole.WriteLine("Using ATA READ DMA command (CHS)."); - else if(ReadRetry) - DicConsole.WriteLine("Using ATA READ command with retries (CHS)."); - else if(Read) - DicConsole.WriteLine("Using ATA READ command (CHS)."); - - byte blocksToRead = 254; - bool error = true; - while(lbaMode) - { - if(ReadDmaLba48) - { - sense = dev.ReadDma(out cmdBuf, out errorLba48, 0, blocksToRead, timeout, out duration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - } - else if(ReadLba48) - { - sense = dev.Read(out cmdBuf, out errorLba48, 0, blocksToRead, timeout, out duration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - } - else if(ReadDmaRetryLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, true, 0, blocksToRead, timeout, out duration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - else if(ReadDmaLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, false, 0, blocksToRead, timeout, out duration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - else if(ReadRetryLba) - { - sense = dev.Read(out cmdBuf, out errorLba, true, 0, blocksToRead, timeout, out duration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - else if(ReadLba) - { - sense = dev.Read(out cmdBuf, out errorLba, false, 0, blocksToRead, timeout, out duration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - } - - if(error) - blocksToRead /= 2; - - if(!error || blocksToRead == 1) - break; - } - - if(error && lbaMode) - { - DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError); + DicConsole.ErrorWriteLine(ataReader.ErrorMessage); return results; } + uint blockSize = ataReader.LogicalBlockSize; + // Check how many blocks to read, if error show and return + if(ataReader.GetBlocksToRead(254)) + { + DicConsole.ErrorWriteLine(ataReader.ErrorMessage); + return results; + } + uint blocksToRead = ataReader.BlocksToRead; + ushort cylinders = ataReader.Cylinders; + byte heads = ataReader.Heads; + byte sectors = ataReader.Sectors; results.A = 0; // <3ms results.B = 0; // >=3ms, <10ms @@ -296,8 +134,6 @@ namespace DiscImageChef.Core.Devices.Scanning if(aborted) break; - double cmdDuration = 0; - if((results.blocks - i) < blocksToRead) blocksToRead = (byte)(results.blocks - i); @@ -310,71 +146,27 @@ namespace DiscImageChef.Core.Devices.Scanning DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", i, results.blocks, currentSpeed); - error = true; - byte status = 0, errorByte = 0; - - if(ReadDmaLba48) - { - sense = dev.ReadDma(out cmdBuf, out errorLba48, i, blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - status = errorLba48.status; - errorByte = errorLba48.error; - } - else if(ReadLba48) - { - sense = dev.Read(out cmdBuf, out errorLba48, i, blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba48.status & 0x27) == 0 && errorLba48.error == 0 && cmdBuf.Length > 0); - status = errorLba48.status; - errorByte = errorLba48.error; - } - else if(ReadDmaRetryLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, true, (uint)i, blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - status = errorLba.status; - errorByte = errorLba.error; - } - else if(ReadDmaLba) - { - sense = dev.ReadDma(out cmdBuf, out errorLba, false, (uint)i, blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - status = errorLba.status; - errorByte = errorLba.error; - } - else if(ReadRetryLba) - { - sense = dev.Read(out cmdBuf, out errorLba, true, (uint)i, blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - status = errorLba.status; - errorByte = errorLba.error; - } - else if(ReadLba) - { - sense = dev.Read(out cmdBuf, out errorLba, false, (uint)i, blocksToRead, timeout, out cmdDuration); - error = !(!sense && (errorLba.status & 0x27) == 0 && errorLba.error == 0 && cmdBuf.Length > 0); - status = errorLba.status; - errorByte = errorLba.error; - } + bool error = ataReader.ReadBlocks(out cmdBuf, i, blocksToRead, out duration); if(!error) { - if(cmdDuration >= 500) + if(duration >= 500) { results.F += blocksToRead; } - else if(cmdDuration >= 150) + else if(duration >= 150) { results.E += blocksToRead; } - else if(cmdDuration >= 50) + else if(duration >= 50) { results.D += blocksToRead; } - else if(cmdDuration >= 10) + else if(duration >= 10) { results.C += blocksToRead; } - else if(cmdDuration >= 3) + else if(duration >= 3) { results.B += blocksToRead; } @@ -383,24 +175,23 @@ namespace DiscImageChef.Core.Devices.Scanning results.A += blocksToRead; } - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, duration); ibgLog.Write(i, currentSpeed * 1024); } else { - DicConsole.DebugWriteLine("Media-Scan", "ATA ERROR: {0} STATUS: {1}", errorByte, status); results.errored += blocksToRead; results.unreadableSectors.Add(i); - if(cmdDuration < 500) + if(duration < 500) mhddLog.Write(i, 65535); else - mhddLog.Write(i, cmdDuration); + mhddLog.Write(i, duration); ibgLog.Write(i, 0); } #pragma warning disable IDE0004 // Without this specific cast, it gives incorrect values - currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (cmdDuration / (double)1000); + currentSpeed = ((double)blockSize * blocksToRead / (double)1048576) / (duration / (double)1000); #pragma warning restore IDE0004 // Without this specific cast, it gives incorrect values GC.Collect(); } @@ -411,7 +202,7 @@ namespace DiscImageChef.Core.Devices.Scanning ibgLog.Close(dev, results.blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(results.blocks + 1)) / 1024) / (results.processingTime / 1000), devicePath); #pragma warning restore IDE0004 // Without this specific cast, it gives incorrect values - if(SeekLba) + if(ataReader.CanSeekLBA) { for(int i = 0; i < seekTimes; i++) { @@ -422,8 +213,7 @@ namespace DiscImageChef.Core.Devices.Scanning DicConsole.Write("\rSeeking to sector {0}...\t\t", seekPos); - if(SeekLba) - dev.Seek(out errorLba, seekPos, timeout, out seekCur); + ataReader.Seek(seekPos, out seekCur); #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator if(seekCur > results.seekMax && seekCur != 0) @@ -454,8 +244,6 @@ namespace DiscImageChef.Core.Devices.Scanning if(aborted) break; - double cmdDuration = 0; - #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator if(currentSpeed > results.maxSpeed && currentSpeed != 0) results.maxSpeed = currentSpeed; @@ -465,57 +253,27 @@ namespace DiscImageChef.Core.Devices.Scanning DicConsole.Write("\rReading cylinder {0} head {1} sector {2} ({3:F3} MiB/sec.)", Cy, Hd, Sc, currentSpeed); - error = true; - byte status = 0, errorByte = 0; - - if(ReadDmaRetry) - { - sense = dev.ReadDma(out cmdBuf, out errorChs, true, Cy, Hd, Sc, 1, timeout, out cmdDuration); - error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - status = errorChs.status; - errorByte = errorChs.error; - } - else if(ReadDma) - { - sense = dev.ReadDma(out cmdBuf, out errorChs, false, Cy, Hd, Sc, 1, timeout, out cmdDuration); - error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - status = errorChs.status; - errorByte = errorChs.error; - } - else if(ReadRetry) - { - sense = dev.Read(out cmdBuf, out errorChs, true, Cy, Hd, Sc, 1, timeout, out cmdDuration); - error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - status = errorChs.status; - errorByte = errorChs.error; - } - else if(Read) - { - sense = dev.Read(out cmdBuf, out errorChs, false, Cy, Hd, Sc, 1, timeout, out cmdDuration); - error = !(!sense && (errorChs.status & 0x27) == 0 && errorChs.error == 0 && cmdBuf.Length > 0); - status = errorChs.status; - errorByte = errorChs.error; - } + bool error = ataReader.ReadCHS(out cmdBuf, Cy, Hd, Sc, out duration); if(!error) { - if(cmdDuration >= 500) + if(duration >= 500) { results.F += blocksToRead; } - else if(cmdDuration >= 150) + else if(duration >= 150) { results.E += blocksToRead; } - else if(cmdDuration >= 50) + else if(duration >= 50) { results.D += blocksToRead; } - else if(cmdDuration >= 10) + else if(duration >= 10) { results.C += blocksToRead; } - else if(cmdDuration >= 3) + else if(duration >= 3) { results.B += blocksToRead; } @@ -524,24 +282,23 @@ namespace DiscImageChef.Core.Devices.Scanning results.A += blocksToRead; } - mhddLog.Write(currentBlock, cmdDuration); + mhddLog.Write(currentBlock, duration); ibgLog.Write(currentBlock, currentSpeed * 1024); } else { - DicConsole.DebugWriteLine("Media-Scan", "ATA ERROR: {0} STATUS: {1}", errorByte, status); results.errored += blocksToRead; results.unreadableSectors.Add(currentBlock); - if(cmdDuration < 500) + if(duration < 500) mhddLog.Write(currentBlock, 65535); else - mhddLog.Write(currentBlock, cmdDuration); + mhddLog.Write(currentBlock, duration); ibgLog.Write(currentBlock, 0); } #pragma warning disable IDE0004 // Without this specific cast, it gives incorrect values - currentSpeed = ((double)blockSize / (double)1048576) / (cmdDuration / (double)1000); + currentSpeed = ((double)blockSize / (double)1048576) / (duration / (double)1000); #pragma warning restore IDE0004 // Without this specific cast, it gives incorrect values GC.Collect(); @@ -556,7 +313,7 @@ namespace DiscImageChef.Core.Devices.Scanning ibgLog.Close(dev, results.blocks, blockSize, (end - start).TotalSeconds, currentSpeed * 1024, (((double)blockSize * (double)(results.blocks + 1)) / 1024) / (results.processingTime / 1000), devicePath); #pragma warning restore IDE0004 // Without this specific cast, it gives incorrect values - if(Seek) + if(ataReader.CanSeek) { for(int i = 0; i < seekTimes; i++) { @@ -569,8 +326,7 @@ namespace DiscImageChef.Core.Devices.Scanning DicConsole.Write("\rSeeking to cylinder {0}, head {1}, sector {2}...\t\t", seekCy, seekHd, seekSc); - if(Seek) - dev.Seek(out errorChs, seekCy, seekHd, seekSc, timeout, out seekCur); + ataReader.SeekCHS(seekCy, seekHd, seekSc, out seekCur); #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator if(seekCur > results.seekMax && seekCur != 0) diff --git a/DiscImageChef.Core/Devices/Scanning/SCSI.cs b/DiscImageChef.Core/Devices/Scanning/SCSI.cs index af9632ff7..b5103a0a0 100644 --- a/DiscImageChef.Core/Devices/Scanning/SCSI.cs +++ b/DiscImageChef.Core/Devices/Scanning/SCSI.cs @@ -121,6 +121,8 @@ namespace DiscImageChef.Core.Devices.Scanning } } + Reader scsiReader = null; + if(dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.DirectAccess || dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice || dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.OCRWDevice || @@ -128,37 +130,14 @@ namespace DiscImageChef.Core.Devices.Scanning dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.SimplifiedDevice || dev.SCSIType == Decoders.SCSI.PeripheralDeviceTypes.WriteOnceDevice) { - sense = dev.ReadCapacity(out cmdBuf, out senseBuf, dev.Timeout, out duration); - if(!sense) + scsiReader = new Reader(dev, dev.Timeout, null, false); + results.blocks = scsiReader.GetDeviceBlocks(); + if(scsiReader.FindReadCommand()) { - results.blocks = (ulong)((cmdBuf[0] << 24) + (cmdBuf[1] << 16) + (cmdBuf[2] << 8) + (cmdBuf[3])); - blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + (cmdBuf[7])); - } - - if(sense || results.blocks == 0xFFFFFFFF) - { - sense = dev.ReadCapacity16(out cmdBuf, out senseBuf, dev.Timeout, out duration); - - if(sense && results.blocks == 0) - { - // Not all MMC devices support READ CAPACITY, as they have READ TOC - if(dev.SCSIType != Decoders.SCSI.PeripheralDeviceTypes.MultiMediaDevice) - { - DicConsole.ErrorWriteLine("Unable to get media capacity"); - DicConsole.ErrorWriteLine("{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); - } - } - - if(!sense) - { - byte[] temp = new byte[8]; - - Array.Copy(cmdBuf, 0, temp, 0, 8); - Array.Reverse(temp); - results.blocks = BitConverter.ToUInt64(temp, 0); - blockSize = (uint)((cmdBuf[5] << 24) + (cmdBuf[5] << 16) + (cmdBuf[6] << 8) + (cmdBuf[7])); - } + DicConsole.ErrorWriteLine("Unable to read medium."); + return results; } + blockSize = scsiReader.LogicalBlockSize; if(results.blocks != 0 && blockSize != 0) { @@ -249,7 +228,7 @@ namespace DiscImageChef.Core.Devices.Scanning e.Cancel = aborted = true; }; - bool read6 = false, read10 = false, read12 = false, read16 = false, readcd; + bool readcd = false; if(compactDisc) { @@ -399,80 +378,8 @@ namespace DiscImageChef.Core.Devices.Scanning } else { - read6 = !dev.Read6(out readBuffer, out senseBuf, 0, blockSize, dev.Timeout, out duration); - - read10 = !dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, dev.Timeout, out duration); - - read12 = !dev.Read12(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, 1, false, dev.Timeout, out duration); - - read16 = !dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, 0, blockSize, 0, 1, false, dev.Timeout, out duration); - - if(!read6 && !read10 && !read12 && !read16) - { - DicConsole.ErrorWriteLine("Cannot read medium, aborting scan..."); - return results; - } - - if(read6 && !read10 && !read12 && !read16 && results.blocks > (0x001FFFFF + 1)) - { - DicConsole.ErrorWriteLine("Device only supports SCSI READ (6) but has more than {0} blocks ({1} blocks total)", 0x001FFFFF + 1, results.blocks); - return results; - } - - if(!read16 && results.blocks > 0xFFFFFFFFL + 1L) - { - DicConsole.ErrorWriteLine("Device only supports SCSI READ (10) but has more than {0} blocks ({1} blocks total)", 0xFFFFFFFFL + 1L, results.blocks); - return results; - } - - if(read16) - DicConsole.WriteLine("Using SCSI READ (16) command."); - else if(read12) - DicConsole.WriteLine("Using SCSI READ (12) command."); - else if(read10) - DicConsole.WriteLine("Using SCSI READ (10) command."); - else if(read6) - DicConsole.WriteLine("Using SCSI READ (6) command."); - start = DateTime.UtcNow; - while(true) - { - if(read16) - { - sense = dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, 0, blockSize, 0, blocksToRead, false, dev.Timeout, out duration); - if(dev.Error) - blocksToRead /= 2; - } - else if(read12) - { - sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, 0, blockSize, 0, blocksToRead, false, dev.Timeout, out duration); - if(dev.Error) - blocksToRead /= 2; - } - else if(read10) - { - sense = dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, 0, blockSize, 0, (ushort)blocksToRead, dev.Timeout, out duration); - if(dev.Error) - blocksToRead /= 2; - } - else if(read6) - { - sense = dev.Read6(out readBuffer, out senseBuf, 0, blockSize, (byte)blocksToRead, dev.Timeout, out duration); - if(dev.Error) - blocksToRead /= 2; - } - - if(!dev.Error || blocksToRead == 1) - break; - } - - if(dev.Error) - { - DicConsole.ErrorWriteLine("Device error {0} trying to guess ideal transfer length.", dev.LastError); - return results; - } - DicConsole.WriteLine("Reading {0} sectors at a time.", blocksToRead); mhddLog = new MHDDLog(MHDDLogPath, dev, results.blocks, blockSize, blocksToRead); @@ -497,26 +404,8 @@ namespace DiscImageChef.Core.Devices.Scanning DicConsole.Write("\rReading sector {0} of {1} ({2:F3} MiB/sec.)", i, results.blocks, currentSpeed); - if(read16) - { - sense = dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, i, blockSize, 0, blocksToRead, false, dev.Timeout, out cmdDuration); - results.processingTime += cmdDuration; - } - else if(read12) - { - sense = dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, (uint)i, blockSize, 0, blocksToRead, false, dev.Timeout, out cmdDuration); - results.processingTime += cmdDuration; - } - else if(read10) - { - sense = dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, (uint)i, blockSize, 0, (ushort)blocksToRead, dev.Timeout, out cmdDuration); - results.processingTime += cmdDuration; - } - else if(read6) - { - sense = dev.Read6(out readBuffer, out senseBuf, (uint)i, blockSize, (byte)blocksToRead, dev.Timeout, out cmdDuration); - results.processingTime += cmdDuration; - } + sense = scsiReader.ReadBlocks(out readBuffer, i, blocksToRead, out cmdDuration); + results.processingTime += cmdDuration; if(!sense && !dev.Error) { @@ -541,7 +430,6 @@ namespace DiscImageChef.Core.Devices.Scanning { results.errored += blocksToRead; results.unreadableSectors.Add(i); - DicConsole.DebugWriteLine("Media-Scan", "READ error:\n{0}", Decoders.SCSI.Sense.PrettifySense(senseBuf)); if(cmdDuration < 500) mhddLog.Write(i, 65535); else @@ -562,12 +450,6 @@ namespace DiscImageChef.Core.Devices.Scanning #pragma warning restore IDE0004 // Without this specific cast, it gives incorrect values } - bool seek6, seek10; - - seek6 = !dev.Seek6(out senseBuf, 0, dev.Timeout, out duration); - - seek10 = !dev.Seek10(out senseBuf, 0, dev.Timeout, out duration); - results.seekMax = double.MinValue; results.seekMin = double.MaxValue; results.seekTotal = 0; @@ -579,28 +461,6 @@ namespace DiscImageChef.Core.Devices.Scanning uint seekPos = (uint)rnd.Next((int)results.blocks); - if(seek6) - { - dev.Seek6(out senseBuf, seekPos, dev.Timeout, out seekCur); - DicConsole.WriteLine("Using SCSI SEEK (6) command."); - } - else if(seek10) - { - dev.Seek10(out senseBuf, seekPos, dev.Timeout, out seekCur); - DicConsole.WriteLine("Using SCSI SEEK (10) command."); - } - else - { - if(read16) - DicConsole.WriteLine("Using SCSI READ (16) command for seeking."); - else if(read12) - DicConsole.WriteLine("Using SCSI READ (12) command for seeking."); - else if(read10) - DicConsole.WriteLine("Using SCSI READ (10) command for seeking."); - else if(read6) - DicConsole.WriteLine("Using SCSI READ (6) command for seeking."); - } - for(int i = 0; i < seekTimes; i++) { if(aborted) @@ -610,29 +470,10 @@ namespace DiscImageChef.Core.Devices.Scanning DicConsole.Write("\rSeeking to sector {0}...\t\t", seekPos); - if(seek6) - dev.Seek6(out senseBuf, seekPos, dev.Timeout, out seekCur); - else if(seek10) - dev.Seek10(out senseBuf, seekPos, dev.Timeout, out seekCur); + if(scsiReader.CanSeek) + scsiReader.Seek(seekPos, out seekCur); else - { - if(read16) - { - dev.Read16(out readBuffer, out senseBuf, 0, false, true, false, seekPos, blockSize, 0, 1, false, dev.Timeout, out seekCur); - } - else if(read12) - { - dev.Read12(out readBuffer, out senseBuf, 0, false, false, false, false, seekPos, blockSize, 0, 1, false, dev.Timeout, out seekCur); - } - else if(read10) - { - dev.Read10(out readBuffer, out senseBuf, 0, false, true, false, false, seekPos, blockSize, 0, 1, dev.Timeout, out seekCur); - } - else if(read6) - { - dev.Read6(out readBuffer, out senseBuf, seekPos, blockSize, 1, dev.Timeout, out seekCur); - } - } + scsiReader.ReadBlock(out readBuffer, seekPos, out seekCur); #pragma warning disable RECS0018 // Comparison of floating point numbers with equality operator if(seekCur > results.seekMax && seekCur != 0) diff --git a/DiscImageChef.Core/DiscImageChef.Core.csproj b/DiscImageChef.Core/DiscImageChef.Core.csproj index 0e0d83526..dd3d2fc46 100644 --- a/DiscImageChef.Core/DiscImageChef.Core.csproj +++ b/DiscImageChef.Core/DiscImageChef.Core.csproj @@ -32,6 +32,9 @@ + + ..\packages\System.ValueTuple.4.3.1\lib\portable-net40+sl4+win8+wp8\System.ValueTuple.dll + @@ -66,6 +69,9 @@ + + + @@ -129,6 +135,9 @@ + + + diff --git a/DiscImageChef.Core/packages.config b/DiscImageChef.Core/packages.config new file mode 100644 index 000000000..02150605b --- /dev/null +++ b/DiscImageChef.Core/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file