2017-05-28 21:01:17 +01:00
|
|
|
|
// /***************************************************************************
|
|
|
|
|
|
// The Disc Image Chef
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
//
|
2017-12-19 03:50:57 +00:00
|
|
|
|
// Filename : General.cs
|
|
|
|
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
2017-05-28 21:01:17 +01:00
|
|
|
|
//
|
2017-12-19 03:50:57 +00:00
|
|
|
|
// Component : Core algorithms.
|
2017-05-28 21:01:17 +01:00
|
|
|
|
//
|
|
|
|
|
|
// --[ Description ] ----------------------------------------------------------
|
|
|
|
|
|
//
|
2017-12-19 03:50:57 +00:00
|
|
|
|
// Creates reports from SCSI devices.
|
2017-05-28 21:01:17 +01:00
|
|
|
|
//
|
|
|
|
|
|
// --[ 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 <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
//
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2017-12-19 03:50:57 +00:00
|
|
|
|
// Copyright © 2011-2018 Natalia Portillo
|
2017-05-28 21:01:17 +01:00
|
|
|
|
// ****************************************************************************/
|
2017-12-19 03:50:57 +00:00
|
|
|
|
|
2017-05-28 21:01:17 +01:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
2017-12-21 07:08:26 +00:00
|
|
|
|
using System.Linq;
|
2018-06-25 19:08:16 +01:00
|
|
|
|
using DiscImageChef.CommonTypes.Metadata;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
using DiscImageChef.Console;
|
2017-12-21 14:30:38 +00:00
|
|
|
|
using DiscImageChef.Decoders.SCSI;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
using DiscImageChef.Devices;
|
|
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
namespace DiscImageChef.Core.Devices.Report
|
2017-05-28 21:01:17 +01:00
|
|
|
|
{
|
2018-11-25 20:08:28 +00:00
|
|
|
|
public partial class DeviceReport
|
2017-05-28 21:01:17 +01:00
|
|
|
|
{
|
2018-11-25 20:08:28 +00:00
|
|
|
|
public Scsi ReportScsiInquiry()
|
2017-05-28 21:01:17 +01:00
|
|
|
|
{
|
2018-11-25 20:08:28 +00:00
|
|
|
|
DicConsole.WriteLine("Querying SCSI INQUIRY...");
|
|
|
|
|
|
bool sense = dev.ScsiInquiry(out byte[] buffer, out byte[] senseBuffer);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
Scsi report = new Scsi();
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
if(sense || !Inquiry.Decode(buffer).HasValue) return null;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-12-23 21:38:01 +00:00
|
|
|
|
report.InquiryData = buffer;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
return report;
|
|
|
|
|
|
}
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-11-27 01:42:25 +00:00
|
|
|
|
public List<ScsiPage> ReportEvpdPages()
|
2018-11-25 20:08:28 +00:00
|
|
|
|
{
|
2017-05-28 21:01:17 +01:00
|
|
|
|
DicConsole.WriteLine("Querying list of SCSI EVPDs...");
|
2018-11-25 20:08:28 +00:00
|
|
|
|
bool sense = dev.ScsiInquiry(out byte[] buffer, out _, 0x00);
|
2017-12-21 07:08:26 +00:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
if(sense) return null;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
byte[] evpdPages = EVPD.DecodePage00(buffer);
|
|
|
|
|
|
if(evpdPages == null || evpdPages.Length <= 0) return null;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
List<ScsiPage> evpds = new List<ScsiPage>();
|
|
|
|
|
|
foreach(byte page in evpdPages.Where(page => page != 0x80))
|
2017-05-28 21:01:17 +01:00
|
|
|
|
{
|
2018-11-25 20:08:28 +00:00
|
|
|
|
DicConsole.WriteLine("Querying SCSI EVPD {0:X2}h...", page);
|
|
|
|
|
|
sense = dev.ScsiInquiry(out buffer, out _, page);
|
|
|
|
|
|
if(sense) continue;
|
2017-12-21 23:00:30 +00:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
ScsiPage evpd = new ScsiPage {page = page, value = buffer};
|
|
|
|
|
|
evpds.Add(evpd);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-27 01:42:25 +00:00
|
|
|
|
return evpds.Count > 0 ? evpds : null;
|
2018-11-25 20:08:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-12-23 21:38:01 +00:00
|
|
|
|
public void ReportScsiModes(ref DeviceReportV2 report, out byte[] cdromMode)
|
2018-11-25 20:08:28 +00:00
|
|
|
|
{
|
2018-06-22 08:08:38 +01:00
|
|
|
|
Modes.DecodedMode? decMode = null;
|
2017-12-21 14:30:38 +00:00
|
|
|
|
PeripheralDeviceTypes devType = dev.ScsiType;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Querying all mode pages and subpages using SCSI MODE SENSE (10)...");
|
2018-11-25 20:08:28 +00:00
|
|
|
|
bool sense = dev.ModeSense10(out byte[] mode10Buffer, out _, false, true, ScsiModeSensePageControl.Default,
|
|
|
|
|
|
0x3F, 0xFF, dev.Timeout, out _);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
if(sense || dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
DicConsole.WriteLine("Querying all mode pages using SCSI MODE SENSE (10)...");
|
2018-11-25 20:08:28 +00:00
|
|
|
|
sense = dev.ModeSense10(out mode10Buffer, out _, false, true, ScsiModeSensePageControl.Default, 0x3F,
|
|
|
|
|
|
0x00, dev.Timeout, out _);
|
2017-12-16 23:18:41 +00:00
|
|
|
|
if(!sense && !dev.Error)
|
2017-05-28 21:01:17 +01:00
|
|
|
|
{
|
2018-06-22 08:08:38 +01:00
|
|
|
|
report.SCSI.SupportsModeSense10 = true;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
report.SCSI.SupportsModeSubpages = false;
|
2018-06-22 08:08:38 +01:00
|
|
|
|
decMode = Modes.DecodeMode10(mode10Buffer, devType);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2018-06-22 08:08:38 +01:00
|
|
|
|
report.SCSI.SupportsModeSense10 = true;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
report.SCSI.SupportsModeSubpages = true;
|
2018-06-22 08:08:38 +01:00
|
|
|
|
decMode = Modes.DecodeMode10(mode10Buffer, devType);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Querying all mode pages and subpages using SCSI MODE SENSE (6)...");
|
2018-11-25 20:08:28 +00:00
|
|
|
|
sense = dev.ModeSense6(out byte[] mode6Buffer, out _, false, ScsiModeSensePageControl.Default, 0x3F, 0xFF,
|
|
|
|
|
|
dev.Timeout, out _);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
if(sense || dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
DicConsole.WriteLine("Querying all mode pages using SCSI MODE SENSE (6)...");
|
2018-11-25 20:08:28 +00:00
|
|
|
|
sense = dev.ModeSense6(out mode6Buffer, out _, false, ScsiModeSensePageControl.Default, 0x3F, 0x00,
|
|
|
|
|
|
dev.Timeout, out _);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
if(sense || dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
DicConsole.WriteLine("Querying SCSI MODE SENSE (6)...");
|
2018-11-25 20:08:28 +00:00
|
|
|
|
sense = dev.ModeSense(out mode6Buffer, out _, dev.Timeout, out _);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
else report.SCSI.SupportsModeSubpages = true;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2017-12-23 17:41:23 +00:00
|
|
|
|
if(!sense && !dev.Error && !decMode.HasValue) decMode = Modes.DecodeMode6(mode6Buffer, devType);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2017-12-20 17:26:28 +00:00
|
|
|
|
report.SCSI.SupportsModeSense6 |= !sense && !dev.Error;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
cdromMode = null;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-06-22 08:08:38 +01:00
|
|
|
|
if(debug && report.SCSI.SupportsModeSense6) report.SCSI.ModeSense6Data = mode6Buffer;
|
2017-12-19 20:33:03 +00:00
|
|
|
|
if(debug && report.SCSI.SupportsModeSense10) report.SCSI.ModeSense10Data = mode10Buffer;
|
2017-09-05 15:47:36 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
if(!decMode.HasValue) return;
|
|
|
|
|
|
|
|
|
|
|
|
report.SCSI.ModeSense = new ScsiMode
|
|
|
|
|
|
{
|
|
|
|
|
|
BlankCheckEnabled = decMode.Value.Header.EBC,
|
|
|
|
|
|
DPOandFUA = decMode.Value.Header.DPOFUA,
|
|
|
|
|
|
WriteProtected = decMode.Value.Header.WriteProtected
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if(decMode.Value.Header.BufferedMode > 0)
|
|
|
|
|
|
report.SCSI.ModeSense.BufferedMode = decMode.Value.Header.BufferedMode;
|
|
|
|
|
|
|
|
|
|
|
|
if(decMode.Value.Header.Speed > 0) report.SCSI.ModeSense.Speed = decMode.Value.Header.Speed;
|
|
|
|
|
|
|
|
|
|
|
|
if(decMode.Value.Pages == null) return;
|
|
|
|
|
|
|
|
|
|
|
|
List<ScsiPage> modePages = new List<ScsiPage>();
|
|
|
|
|
|
foreach(Modes.ModePage page in decMode.Value.Pages)
|
|
|
|
|
|
{
|
|
|
|
|
|
ScsiPage modePage = new ScsiPage {page = page.Page, subpage = page.Subpage, value = page.PageResponse};
|
|
|
|
|
|
modePages.Add(modePage);
|
|
|
|
|
|
|
|
|
|
|
|
if(modePage.page == 0x2A && modePage.subpage == 0x00)
|
2018-12-23 21:38:01 +00:00
|
|
|
|
cdromMode = page.PageResponse;
|
2018-11-25 20:08:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-27 01:42:25 +00:00
|
|
|
|
if(modePages.Count > 0) report.SCSI.ModeSense.ModePages = modePages;
|
2018-11-25 20:08:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public TestedMedia ReportScsiMedia()
|
|
|
|
|
|
{
|
|
|
|
|
|
TestedMedia mediaTest = new TestedMedia();
|
|
|
|
|
|
DicConsole.WriteLine("Querying SCSI READ CAPACITY...");
|
|
|
|
|
|
bool sense = dev.ReadCapacity(out byte[] buffer, out byte[] senseBuffer, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
mediaTest.SupportsReadCapacity = true;
|
|
|
|
|
|
mediaTest.Blocks =
|
|
|
|
|
|
(ulong)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) + 1;
|
|
|
|
|
|
mediaTest.BlockSize =
|
|
|
|
|
|
(uint)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Querying SCSI READ CAPACITY (16)...");
|
|
|
|
|
|
sense = dev.ReadCapacity16(out buffer, out buffer, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
mediaTest.SupportsReadCapacity16 = true;
|
|
|
|
|
|
byte[] temp = new byte[8];
|
|
|
|
|
|
Array.Copy(buffer, 0, temp, 0, 8);
|
|
|
|
|
|
Array.Reverse(temp);
|
|
|
|
|
|
mediaTest.Blocks = BitConverter.ToUInt64(temp, 0) + 1;
|
|
|
|
|
|
mediaTest.BlockSize = (uint)((buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + buffer[11]);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Modes.DecodedMode? decMode = null;
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Querying SCSI MODE SENSE (10)...");
|
|
|
|
|
|
sense = dev.ModeSense10(out buffer, out senseBuffer, false, true, ScsiModeSensePageControl.Current, 0x3F,
|
|
|
|
|
|
0x00, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
decMode = Modes.DecodeMode10(buffer, dev.ScsiType);
|
|
|
|
|
|
if(debug) mediaTest.ModeSense10Data = buffer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Querying SCSI MODE SENSE...");
|
|
|
|
|
|
sense = dev.ModeSense(out buffer, out senseBuffer, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(!decMode.HasValue) decMode = Modes.DecodeMode6(buffer, dev.ScsiType);
|
|
|
|
|
|
if(debug) mediaTest.ModeSense6Data = buffer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2017-05-28 21:01:17 +01:00
|
|
|
|
if(decMode.HasValue)
|
|
|
|
|
|
{
|
2018-11-25 20:08:28 +00:00
|
|
|
|
mediaTest.MediumType = (byte)decMode.Value.Header.MediumType;
|
|
|
|
|
|
if(decMode.Value.Header.BlockDescriptors != null && decMode.Value.Header.BlockDescriptors.Length > 0)
|
|
|
|
|
|
mediaTest.Density = (byte)decMode.Value.Header.BlockDescriptors[0].Density;
|
|
|
|
|
|
}
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ (6)...");
|
|
|
|
|
|
mediaTest.SupportsRead6 = !dev.Read6(out buffer, out senseBuffer, 0,
|
|
|
|
|
|
mediaTest.BlockSize ?? 512, dev.Timeout, out _);
|
|
|
|
|
|
DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead6);
|
|
|
|
|
|
if(debug)
|
|
|
|
|
|
DataFile.WriteTo("SCSI Report", "read6", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results",
|
|
|
|
|
|
buffer);
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ (10)...");
|
|
|
|
|
|
mediaTest.SupportsRead10 = !dev.Read10(out buffer, out senseBuffer, 0, false, true, false, false, 0,
|
|
|
|
|
|
mediaTest.BlockSize ?? 512, 0, 1, dev.Timeout, out _);
|
|
|
|
|
|
DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead10);
|
|
|
|
|
|
if(debug)
|
|
|
|
|
|
DataFile.WriteTo("SCSI Report", "read10", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results",
|
|
|
|
|
|
buffer);
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ (12)...");
|
|
|
|
|
|
mediaTest.SupportsRead12 = !dev.Read12(out buffer, out senseBuffer, 0, false, true, false, false, 0,
|
|
|
|
|
|
mediaTest.BlockSize ?? 512, 0, 1, false, dev.Timeout, out _);
|
|
|
|
|
|
DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead12);
|
|
|
|
|
|
if(debug)
|
|
|
|
|
|
DataFile.WriteTo("SCSI Report", "read12", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results",
|
|
|
|
|
|
buffer);
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ (16)...");
|
|
|
|
|
|
mediaTest.SupportsRead16 = !dev.Read16(out buffer, out senseBuffer, 0, false, true, false, 0,
|
|
|
|
|
|
mediaTest.BlockSize ?? 512, 0, 1, false, dev.Timeout, out _);
|
|
|
|
|
|
DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !mediaTest.SupportsRead16);
|
|
|
|
|
|
if(debug)
|
|
|
|
|
|
DataFile.WriteTo("SCSI Report", "read16", "_debug_" + mediaTest.MediumTypeName + ".bin", "read results",
|
|
|
|
|
|
buffer);
|
|
|
|
|
|
|
|
|
|
|
|
mediaTest.LongBlockSize = mediaTest.BlockSize;
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ LONG (10)...");
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 0xFFFF, dev.Timeout, out _);
|
|
|
|
|
|
if(sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
FixedSense? decSense = Sense.DecodeFixed(senseBuffer);
|
|
|
|
|
|
if(decSense.HasValue)
|
|
|
|
|
|
if(decSense.Value.SenseKey == SenseKeys.IllegalRequest && decSense.Value.ASC == 0x24 &&
|
|
|
|
|
|
decSense.Value.ASCQ == 0x00)
|
|
|
|
|
|
{
|
|
|
|
|
|
mediaTest.SupportsReadLong = true;
|
|
|
|
|
|
if(decSense.Value.InformationValid && decSense.Value.ILI)
|
|
|
|
|
|
mediaTest.LongBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(mediaTest.SupportsReadLong == true && mediaTest.LongBlockSize == mediaTest.BlockSize)
|
|
|
|
|
|
if(mediaTest.BlockSize == 512)
|
|
|
|
|
|
foreach(int i in new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
// Long sector sizes for floppies
|
|
|
|
|
|
514,
|
|
|
|
|
|
// Long sector sizes for SuperDisk
|
|
|
|
|
|
536, 558,
|
|
|
|
|
|
// Long sector sizes for 512-byte magneto-opticals
|
|
|
|
|
|
600, 610, 630
|
|
|
|
|
|
})
|
|
|
|
|
|
{
|
|
|
|
|
|
ushort testSize = (ushort)i;
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, testSize, dev.Timeout,
|
|
|
|
|
|
out _);
|
|
|
|
|
|
if(sense || dev.Error) continue;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
mediaTest.SupportsReadLong = true;
|
|
|
|
|
|
mediaTest.LongBlockSize = testSize;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(mediaTest.BlockSize == 1024)
|
|
|
|
|
|
foreach(int i in new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
// Long sector sizes for floppies
|
|
|
|
|
|
1026,
|
|
|
|
|
|
// Long sector sizes for 1024-byte magneto-opticals
|
|
|
|
|
|
1200
|
|
|
|
|
|
})
|
|
|
|
|
|
{
|
|
|
|
|
|
ushort testSize = (ushort)i;
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)i, dev.Timeout,
|
|
|
|
|
|
out _);
|
|
|
|
|
|
if(sense || dev.Error) continue;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
mediaTest.SupportsReadLong = true;
|
|
|
|
|
|
mediaTest.LongBlockSize = testSize;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(mediaTest.BlockSize == 2048)
|
2017-05-28 21:01:17 +01:00
|
|
|
|
{
|
2018-11-25 20:08:28 +00:00
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 2380, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
2017-05-28 21:01:17 +01:00
|
|
|
|
{
|
2018-11-25 20:08:28 +00:00
|
|
|
|
mediaTest.SupportsReadLong = true;
|
|
|
|
|
|
mediaTest.LongBlockSize = 2380;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(mediaTest.BlockSize == 4096)
|
|
|
|
|
|
{
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 4760, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
mediaTest.SupportsReadLong = true;
|
|
|
|
|
|
mediaTest.LongBlockSize = 4760;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(mediaTest.BlockSize == 8192)
|
|
|
|
|
|
{
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 9424, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
mediaTest.SupportsReadLong = true;
|
|
|
|
|
|
mediaTest.LongBlockSize = 9424;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2018-11-25 20:08:28 +00:00
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ MEDIA SERIAL NUMBER...");
|
|
|
|
|
|
mediaTest.CanReadMediaSerial = !dev.ReadMediaSerialNumber(out buffer, out senseBuffer, dev.Timeout, out _);
|
|
|
|
|
|
|
|
|
|
|
|
return mediaTest;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public TestedMedia ReportScsi()
|
|
|
|
|
|
{
|
|
|
|
|
|
TestedMedia capabilities = new TestedMedia {MediaIsRecognized = true};
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Querying SCSI READ CAPACITY...");
|
|
|
|
|
|
bool sense = dev.ReadCapacity(out byte[] buffer, out byte[] senseBuffer, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
capabilities.SupportsReadCapacity = true;
|
|
|
|
|
|
capabilities.Blocks =
|
|
|
|
|
|
(ulong)((buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) + 1;
|
|
|
|
|
|
capabilities.BlockSize =
|
|
|
|
|
|
(uint)((buffer[4] << 24) + (buffer[5] << 16) + (buffer[6] << 8) + buffer[7]);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
DicConsole.WriteLine("Querying SCSI READ CAPACITY (16)...");
|
|
|
|
|
|
sense = dev.ReadCapacity16(out buffer, out buffer, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
capabilities.SupportsReadCapacity16 = true;
|
|
|
|
|
|
byte[] temp = new byte[8];
|
|
|
|
|
|
Array.Copy(buffer, 0, temp, 0, 8);
|
|
|
|
|
|
Array.Reverse(temp);
|
|
|
|
|
|
capabilities.Blocks = BitConverter.ToUInt64(temp, 0) + 1;
|
|
|
|
|
|
capabilities.BlockSize = (uint)((buffer[8] << 24) + (buffer[9] << 16) + (buffer[10] << 8) + buffer[11]);
|
|
|
|
|
|
}
|
2018-11-25 17:47:14 +00:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
Modes.DecodedMode? decMode = null;
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Querying SCSI MODE SENSE (10)...");
|
|
|
|
|
|
sense = dev.ModeSense10(out buffer, out senseBuffer, false, true, ScsiModeSensePageControl.Current, 0x3F,
|
|
|
|
|
|
0x00, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
2017-12-23 17:41:23 +00:00
|
|
|
|
{
|
2018-11-25 20:08:28 +00:00
|
|
|
|
decMode = Modes.DecodeMode10(buffer, dev.ScsiType);
|
|
|
|
|
|
if(debug) capabilities.ModeSense10Data = buffer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Querying SCSI MODE SENSE...");
|
|
|
|
|
|
sense = dev.ModeSense(out buffer, out senseBuffer, dev.Timeout, out _);
|
|
|
|
|
|
if(!sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(!decMode.HasValue) decMode = Modes.DecodeMode6(buffer, dev.ScsiType);
|
|
|
|
|
|
if(debug) capabilities.ModeSense6Data = buffer;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(decMode.HasValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
capabilities.MediumType = (byte)decMode.Value.Header.MediumType;
|
|
|
|
|
|
if(decMode.Value.Header.BlockDescriptors != null && decMode.Value.Header.BlockDescriptors.Length > 0)
|
|
|
|
|
|
capabilities.Density = (byte)decMode.Value.Header.BlockDescriptors[0].Density;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ (6)...");
|
|
|
|
|
|
capabilities.SupportsRead6 = !dev.Read6(out buffer, out senseBuffer, 0, capabilities.BlockSize ?? 512,
|
|
|
|
|
|
dev.Timeout, out _);
|
|
|
|
|
|
DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead6);
|
|
|
|
|
|
if(debug) DataFile.WriteTo("SCSI Report", "read6", "_debug_" + dev.Model + ".bin", "read results", buffer);
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ (10)...");
|
|
|
|
|
|
capabilities.SupportsRead10 = !dev.Read10(out buffer, out senseBuffer, 0, false, true, false, false, 0,
|
|
|
|
|
|
capabilities.BlockSize ?? 512, 0, 1, dev.Timeout, out _);
|
|
|
|
|
|
DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead10);
|
|
|
|
|
|
if(debug) DataFile.WriteTo("SCSI Report", "read10", "_debug_" + dev.Model + ".bin", "read results", buffer);
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ (12)...");
|
|
|
|
|
|
capabilities.SupportsRead12 = !dev.Read12(out buffer, out senseBuffer, 0, false, true, false, false, 0,
|
|
|
|
|
|
capabilities.BlockSize ?? 512, 0, 1, false, dev.Timeout, out _);
|
|
|
|
|
|
DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead12);
|
|
|
|
|
|
if(debug) DataFile.WriteTo("SCSI Report", "read12", "_debug_" + dev.Model + ".bin", "read results", buffer);
|
|
|
|
|
|
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ (16)...");
|
|
|
|
|
|
capabilities.SupportsRead16 = !dev.Read16(out buffer, out senseBuffer, 0, false, true, false, 0,
|
|
|
|
|
|
capabilities.BlockSize ?? 512, 0, 1, false, dev.Timeout, out _);
|
|
|
|
|
|
DicConsole.DebugWriteLine("SCSI Report", "Sense = {0}", !capabilities.SupportsRead16);
|
|
|
|
|
|
if(debug) DataFile.WriteTo("SCSI Report", "read16", "_debug_" + dev.Model + ".bin", "read results", buffer);
|
|
|
|
|
|
|
|
|
|
|
|
capabilities.LongBlockSize = capabilities.BlockSize;
|
|
|
|
|
|
DicConsole.WriteLine("Trying SCSI READ LONG (10)...");
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 0xFFFF, dev.Timeout, out _);
|
|
|
|
|
|
if(sense && !dev.Error)
|
|
|
|
|
|
{
|
|
|
|
|
|
FixedSense? decSense = Sense.DecodeFixed(senseBuffer);
|
|
|
|
|
|
if(decSense.HasValue)
|
|
|
|
|
|
if(decSense.Value.SenseKey == SenseKeys.IllegalRequest && decSense.Value.ASC == 0x24 &&
|
|
|
|
|
|
decSense.Value.ASCQ == 0x00)
|
2017-12-21 04:43:29 +00:00
|
|
|
|
{
|
2018-11-25 20:08:28 +00:00
|
|
|
|
capabilities.SupportsReadLong = true;
|
|
|
|
|
|
if(decSense.Value.InformationValid && decSense.Value.ILI)
|
|
|
|
|
|
capabilities.LongBlockSize = 0xFFFF - (decSense.Value.Information & 0xFFFF);
|
2017-05-28 21:01:17 +01:00
|
|
|
|
}
|
2018-11-25 20:08:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(capabilities.SupportsReadLong != true || capabilities.LongBlockSize != capabilities.BlockSize)
|
|
|
|
|
|
return capabilities;
|
|
|
|
|
|
|
|
|
|
|
|
if(capabilities.BlockSize == 512)
|
|
|
|
|
|
foreach(int i in new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
// Long sector sizes for floppies
|
|
|
|
|
|
514,
|
|
|
|
|
|
// Long sector sizes for SuperDisk
|
|
|
|
|
|
536, 558,
|
|
|
|
|
|
// Long sector sizes for 512-byte magneto-opticals
|
|
|
|
|
|
600, 610, 630
|
|
|
|
|
|
})
|
|
|
|
|
|
{
|
|
|
|
|
|
ushort testSize = (ushort)i;
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)i, dev.Timeout, out _);
|
|
|
|
|
|
if(sense || dev.Error) continue;
|
2017-06-03 19:26:48 +01:00
|
|
|
|
|
2018-11-25 20:08:28 +00:00
|
|
|
|
capabilities.SupportsReadLong = true;
|
|
|
|
|
|
capabilities.LongBlockSize = testSize;
|
2017-12-21 04:43:29 +00:00
|
|
|
|
break;
|
2018-11-25 20:08:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
else if(capabilities.BlockSize == 1024)
|
|
|
|
|
|
foreach(int i in new[]
|
|
|
|
|
|
{
|
|
|
|
|
|
// Long sector sizes for floppies
|
|
|
|
|
|
1026,
|
|
|
|
|
|
// Long sector sizes for 1024-byte magneto-opticals
|
|
|
|
|
|
1200
|
|
|
|
|
|
})
|
|
|
|
|
|
{
|
|
|
|
|
|
ushort testSize = (ushort)i;
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, (ushort)i, dev.Timeout, out _);
|
|
|
|
|
|
if(sense || dev.Error) continue;
|
|
|
|
|
|
|
|
|
|
|
|
capabilities.SupportsReadLong = true;
|
|
|
|
|
|
capabilities.LongBlockSize = testSize;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(capabilities.BlockSize == 2048)
|
|
|
|
|
|
{
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 2380, dev.Timeout, out _);
|
|
|
|
|
|
if(sense || dev.Error) return capabilities;
|
|
|
|
|
|
|
|
|
|
|
|
capabilities.SupportsReadLong = true;
|
|
|
|
|
|
capabilities.LongBlockSize = 2380;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
}
|
2018-11-25 20:08:28 +00:00
|
|
|
|
else if(capabilities.BlockSize == 4096)
|
|
|
|
|
|
{
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 4760, dev.Timeout, out _);
|
|
|
|
|
|
if(sense || dev.Error) return capabilities;
|
|
|
|
|
|
|
|
|
|
|
|
capabilities.SupportsReadLong = true;
|
|
|
|
|
|
capabilities.LongBlockSize = 4760;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(capabilities.BlockSize == 8192)
|
|
|
|
|
|
{
|
|
|
|
|
|
sense = dev.ReadLong10(out buffer, out senseBuffer, false, false, 0, 9424, dev.Timeout, out _);
|
|
|
|
|
|
if(sense || dev.Error) return capabilities;
|
|
|
|
|
|
|
|
|
|
|
|
capabilities.SupportsReadLong = true;
|
|
|
|
|
|
capabilities.LongBlockSize = 9424;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return capabilities;
|
2017-05-28 21:01:17 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2017-12-19 20:33:03 +00:00
|
|
|
|
}
|