Skip to content

Commit 1b63452

Browse files
committed
Added 64 bit read/write support
1 parent fe01317 commit 1b63452

File tree

6 files changed

+150
-25
lines changed

6 files changed

+150
-25
lines changed

Library/DiscUtils.Iscsi/DiskStream.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public DiskStream(Session session, long lun, FileAccess access)
4545
_session = session;
4646
_lun = lun;
4747

48-
var capacity = session.ReadCapacity16(lun);
48+
var capacity = session.GetCapacity(lun);
4949
_blockSize = capacity.BlockSize;
5050
_length = capacity.LogicalBlockCount * capacity.BlockSize;
5151
CanWrite = access != FileAccess.Read;
@@ -95,7 +95,7 @@ public override int Read(Span<byte> buffer)
9595
var tempBuffer = ArrayPool<byte>.Shared.Rent(checked((int)((lastBlock - firstBlock) * _blockSize)));
9696
try
9797
{
98-
var numRead = _session.Read(_lun, firstBlock, (short)(lastBlock - firstBlock), tempBuffer);
98+
var numRead = _session.Read(_lun, firstBlock, checked((int)(lastBlock - firstBlock)), tempBuffer);
9999

100100
var numCopied = Math.Min(maxToRead, numRead);
101101
tempBuffer.AsSpan((int)(_position - firstBlock * _blockSize), numCopied).CopyTo(buffer);
@@ -125,7 +125,7 @@ public override async ValueTask<int> ReadAsync(Memory<byte> buffer, Cancellation
125125
var tempBuffer = ArrayPool<byte>.Shared.Rent(checked((int)((lastBlock - firstBlock) * _blockSize)));
126126
try
127127
{
128-
var numRead = await _session.ReadAsync(_lun, firstBlock, (short)(lastBlock - firstBlock), tempBuffer, cancellationToken).ConfigureAwait(false);
128+
var numRead = await _session.ReadAsync(_lun, firstBlock, checked((int)(lastBlock - firstBlock)), tempBuffer, cancellationToken).ConfigureAwait(false);
129129

130130
var numCopied = Math.Min(maxToRead, numRead);
131131
tempBuffer.AsSpan((int)(_position - firstBlock * _blockSize), numCopied).CopyTo(buffer.Span);
@@ -219,7 +219,7 @@ public override void Write(ReadOnlySpan<byte> buffer)
219219
else
220220
{
221221
// Processing at least one whole block, just write (after making sure to trim any partial sectors from the end)...
222-
var numBlocks = (short)(toWrite / _blockSize);
222+
var numBlocks = toWrite / _blockSize;
223223
toWrite = numBlocks * _blockSize;
224224

225225
_session.Write(_lun, block, numBlocks, _blockSize, buffer.Slice(numWritten));

Library/DiscUtils.Iscsi/ScsiReadCommand.cs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525

2626
namespace DiscUtils.Iscsi;
2727

28-
internal class ScsiReadCommand : ScsiCommand
28+
internal class ScsiRead10Command : ScsiCommand
2929
{
3030
private readonly uint _logicalBlockAddress;
3131
private readonly ushort _numBlocks;
3232

33-
public ScsiReadCommand(ulong targetLun, uint logicalBlockAddress, ushort numBlocks)
33+
public ScsiRead10Command(ulong targetLun, uint logicalBlockAddress, ushort numBlocks)
3434
: base(targetLun)
3535
{
3636
_logicalBlockAddress = logicalBlockAddress;
@@ -53,4 +53,34 @@ public override void WriteTo(Span<byte> buffer)
5353
EndianUtilities.WriteBytesBigEndian(_numBlocks, buffer.Slice(7));
5454
buffer[9] = 0;
5555
}
56+
}
57+
58+
internal class ScsiRead16Command : ScsiCommand
59+
{
60+
private readonly long _logicalBlockAddress;
61+
private readonly int _numBlocks;
62+
63+
public ScsiRead16Command(ulong targetLun, long logicalBlockAddress, int numBlocks)
64+
: base(targetLun)
65+
{
66+
_logicalBlockAddress = logicalBlockAddress;
67+
_numBlocks = numBlocks;
68+
}
69+
70+
public override int Size => 16;
71+
72+
public override int ReadFrom(ReadOnlySpan<byte> buffer)
73+
{
74+
throw new NotImplementedException();
75+
}
76+
77+
public override void WriteTo(Span<byte> buffer)
78+
{
79+
buffer[0] = (byte)ScsiOpCode.Read16; // OpCode: READ(16)
80+
buffer[1] = 0;
81+
EndianUtilities.WriteBytesBigEndian(_logicalBlockAddress, buffer.Slice(2));
82+
EndianUtilities.WriteBytesBigEndian(_numBlocks, buffer.Slice(10));
83+
buffer[14] = 0;
84+
buffer[15] = 0;
85+
}
5686
}

Library/DiscUtils.Iscsi/ScsiWriteCommand.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525

2626
namespace DiscUtils.Iscsi;
2727

28-
internal class ScsiWriteCommand : ScsiCommand
28+
internal class ScsiWrite10Command : ScsiCommand
2929
{
3030
private readonly uint _logicalBlockAddress;
3131

32-
public ScsiWriteCommand(ulong targetLun, uint logicalBlockAddress, ushort numBlocks)
32+
public ScsiWrite10Command(ulong targetLun, uint logicalBlockAddress, ushort numBlocks)
3333
: base(targetLun)
3434
{
3535
_logicalBlockAddress = logicalBlockAddress;
@@ -56,4 +56,37 @@ public override void WriteTo(Span<byte> buffer)
5656
EndianUtilities.WriteBytesBigEndian(NumBlocks, buffer.Slice(7));
5757
buffer[9] = 0;
5858
}
59+
}
60+
61+
internal class ScsiWrite16Command : ScsiCommand
62+
{
63+
private readonly long _logicalBlockAddress;
64+
65+
public ScsiWrite16Command(ulong targetLun, long logicalBlockAddress, int numBlocks)
66+
: base(targetLun)
67+
{
68+
_logicalBlockAddress = logicalBlockAddress;
69+
NumBlocks = numBlocks;
70+
}
71+
72+
public int NumBlocks { get; }
73+
74+
public override int Size => 16;
75+
76+
public override TaskAttributes TaskAttributes => TaskAttributes.Simple;
77+
78+
public override int ReadFrom(ReadOnlySpan<byte> buffer)
79+
{
80+
throw new NotImplementedException();
81+
}
82+
83+
public override void WriteTo(Span<byte> buffer)
84+
{
85+
buffer[0] = (byte)ScsiOpCode.Write10;
86+
buffer[1] = 0;
87+
EndianUtilities.WriteBytesBigEndian(_logicalBlockAddress, buffer.Slice(2));
88+
EndianUtilities.WriteBytesBigEndian(NumBlocks, buffer.Slice(10));
89+
buffer[14] = 0;
90+
buffer[15] = 0;
91+
}
5992
}

Library/DiscUtils.Iscsi/Session.cs

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,35 @@ public LunInfo GetInfo(long lun)
175175
return new LunInfo(targetInfo, lun, resp.DeviceType, resp.Removable, resp.VendorId, resp.ProductId, resp.ProductRevision);
176176
}
177177

178+
private bool _no16support;
179+
178180
/// <summary>
179-
/// Gets the capacity of a particular LUN.
181+
/// Gets the capacity of a particular LUN. First attempts
182+
/// to get 64 bit capacity and if that is not supported by
183+
/// target, gets 32 bit capacity instead.
184+
/// </summary>
185+
/// <param name="lun">The LUN to query.</param>
186+
/// <returns>The LUN's capacity.</returns>
187+
public LunCapacity GetCapacity(long lun)
188+
{
189+
if (!_no16support)
190+
{
191+
try
192+
{
193+
return ReadCapacity16(lun);
194+
}
195+
catch
196+
{
197+
}
198+
199+
_no16support = true;
200+
}
201+
202+
return ReadCapacity10(lun);
203+
}
204+
205+
/// <summary>
206+
/// Gets the 32 bit capacity of a particular LUN.
180207
/// </summary>
181208
/// <param name="lun">The LUN to query.</param>
182209
/// <returns>The LUN's capacity.</returns>
@@ -197,7 +224,7 @@ public LunCapacity ReadCapacity10(long lun)
197224
}
198225

199226
/// <summary>
200-
/// Gets the capacity of a particular LUN.
227+
/// Gets the 64 bit capacity of a particular LUN.
201228
/// </summary>
202229
/// <param name="lun">The LUN to query.</param>
203230
/// <returns>The LUN's capacity.</returns>
@@ -212,6 +239,8 @@ public LunCapacity ReadCapacity16(long lun)
212239
throw new InvalidProtocolException("Truncated response");
213240
}
214241

242+
_no16support = false;
243+
215244
// READ CAPACITY returns the address of the LAST logical block (zero-indexed)
216245
// So the actual count is last_block_address + 1
217246
return new LunCapacity(resp.NumLogicalBlocks + 1L, (int)resp.LogicalBlockSize);
@@ -246,10 +275,18 @@ public Disk OpenDisk(long lun, FileAccess access)
246275
/// <param name="blockCount">The number of blocks to read.</param>
247276
/// <param name="buffer">The buffer to fill.</param>
248277
/// <returns>The number of bytes read.</returns>
249-
public int Read(long lun, long startBlock, short blockCount, Span<byte> buffer)
278+
public int Read(long lun, long startBlock, int blockCount, Span<byte> buffer)
250279
{
251-
var cmd = checked(new ScsiReadCommand((ulong)lun, (uint)startBlock, (ushort)blockCount));
252-
return Send(cmd, default, buffer);
280+
if (startBlock + blockCount > uint.MaxValue || blockCount > ushort.MaxValue)
281+
{
282+
var cmd = checked(new ScsiRead16Command((ulong)lun, startBlock, blockCount));
283+
return Send(cmd, default, buffer);
284+
}
285+
else
286+
{
287+
var cmd = checked(new ScsiRead10Command((ulong)lun, (uint)startBlock, (ushort)blockCount));
288+
return Send(cmd, default, buffer);
289+
}
253290
}
254291

255292
/// <summary>
@@ -261,10 +298,18 @@ public int Read(long lun, long startBlock, short blockCount, Span<byte> buffer)
261298
/// <param name="buffer">The buffer to fill.</param>
262299
/// <param name="cancellationToken"></param>
263300
/// <returns>The number of bytes read.</returns>
264-
public ValueTask<int> ReadAsync(long lun, long startBlock, short blockCount, Memory<byte> buffer, CancellationToken cancellationToken)
301+
public ValueTask<int> ReadAsync(long lun, long startBlock, int blockCount, Memory<byte> buffer, CancellationToken cancellationToken)
265302
{
266-
var cmd = checked(new ScsiReadCommand((ulong)lun, (uint)startBlock, (ushort)blockCount));
267-
return SendAsync(cmd, default, buffer, cancellationToken);
303+
if (startBlock + blockCount > uint.MaxValue || blockCount > ushort.MaxValue)
304+
{
305+
var cmd = checked(new ScsiRead16Command((ulong)lun, startBlock, blockCount));
306+
return SendAsync(cmd, default, buffer, cancellationToken);
307+
}
308+
else
309+
{
310+
var cmd = checked(new ScsiRead10Command((ulong)lun, (uint)startBlock, (ushort)blockCount));
311+
return SendAsync(cmd, default, buffer, cancellationToken);
312+
}
268313
}
269314

270315
/// <summary>
@@ -275,10 +320,18 @@ public ValueTask<int> ReadAsync(long lun, long startBlock, short blockCount, Mem
275320
/// <param name="blockCount">The number of blocks to write.</param>
276321
/// <param name="blockSize">The size of each block (must match the actual LUN geometry).</param>
277322
/// <param name="buffer">The data to write.</param>
278-
public void Write(long lun, long startBlock, short blockCount, int blockSize, ReadOnlySpan<byte> buffer)
323+
public int Write(long lun, long startBlock, int blockCount, int blockSize, ReadOnlySpan<byte> buffer)
279324
{
280-
var cmd = checked(new ScsiWriteCommand((ulong)lun, (uint)startBlock, (ushort)blockCount));
281-
Send(cmd, buffer.Slice(0, blockCount * blockSize), default);
325+
if (startBlock + blockCount > uint.MaxValue || blockCount > ushort.MaxValue)
326+
{
327+
var cmd = checked(new ScsiWrite16Command((ulong)lun, startBlock, blockCount));
328+
return Send(cmd, buffer.Slice(0, blockCount * blockSize), default);
329+
}
330+
else
331+
{
332+
var cmd = checked(new ScsiWrite10Command((ulong)lun, (uint)startBlock, (ushort)blockCount));
333+
return Send(cmd, buffer.Slice(0, blockCount * blockSize), default);
334+
}
282335
}
283336

284337
/// <summary>
@@ -290,10 +343,18 @@ public void Write(long lun, long startBlock, short blockCount, int blockSize, Re
290343
/// <param name="blockSize">The size of each block (must match the actual LUN geometry).</param>
291344
/// <param name="buffer">The data to write.</param>
292345
/// <param name="cancellationToken"></param>
293-
public ValueTask WriteAsync(long lun, long startBlock, short blockCount, int blockSize, ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
346+
public ValueTask<int> WriteAsync(long lun, long startBlock, int blockCount, int blockSize, ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken)
294347
{
295-
var cmd = checked(new ScsiWriteCommand((ulong)lun, (uint)startBlock, (ushort)blockCount));
296-
return new(SendAsync(cmd, buffer.Slice(0, blockCount * blockSize), default, cancellationToken).AsTask());
348+
if (startBlock + blockCount > uint.MaxValue || blockCount > ushort.MaxValue)
349+
{
350+
var cmd = checked(new ScsiWrite16Command((ulong)lun, startBlock, blockCount));
351+
return SendAsync(cmd, buffer.Slice(0, blockCount * blockSize), default, cancellationToken);
352+
}
353+
else
354+
{
355+
var cmd = checked(new ScsiWrite10Command((ulong)lun, (uint)startBlock, (ushort)blockCount));
356+
return SendAsync(cmd, buffer.Slice(0, blockCount * blockSize), default, cancellationToken);
357+
}
297358
}
298359

299360
/// <summary>

Utilities/FileExtract/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ protected override void DoRun()
9393
else
9494
{
9595
volInfo = volMgr.GetLogicalVolumes().FirstOrDefault()
96-
?? throw new DriveNotFoundException("Logical volume not found");
96+
?? throw new DriveNotFoundException("Logical volume not found");
9797
}
9898

9999
var fsInfo = FileSystemManager.DetectFileSystems(volInfo).FirstOrDefault()

Utilities/VolInfo/Program.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
using System.IO;
2525
using DiscUtils;
2626
using DiscUtils.Common;
27+
using LTRData.Extensions.Formatting;
2728

2829
namespace VolInfo;
2930

@@ -76,7 +77,7 @@ protected override void DoRun()
7677
Console.WriteLine($" Disk Id: {physVol.DiskIdentity}");
7778
Console.WriteLine($" Disk Sig: {physVol.DiskSignature:X8}");
7879
Console.WriteLine($" Part Id: {physVol.PartitionIdentity}");
79-
Console.WriteLine($" Length: {physVol.Length} bytes");
80+
Console.WriteLine($" Length: {physVol.Length} bytes ({SizeFormatting.FormatBytes(physVol.Length)})");
8081
Console.WriteLine($" Disk Geometry: {physVol.PhysicalGeometry}");
8182
Console.WriteLine($" First Sector: {physVol.PhysicalStartSector}");
8283
Console.WriteLine();
@@ -86,7 +87,7 @@ protected override void DoRun()
8687
foreach (var logVol in volMgr.GetLogicalVolumes())
8788
{
8889
Console.WriteLine($" Identity: {logVol.Identity}");
89-
Console.WriteLine($" Length: {logVol.Length} bytes");
90+
Console.WriteLine($" Length: {logVol.Length} bytes ({SizeFormatting.FormatBytes(logVol.Length)})");
9091
Console.WriteLine($" Disk Geometry: {logVol.PhysicalGeometry}");
9192
Console.WriteLine($" First Sector: {logVol.PhysicalStartSector}");
9293
Console.WriteLine();

0 commit comments

Comments
 (0)