Skip to content

Commit b407aa6

Browse files
committed
Cleaned up new code
1 parent aad94db commit b407aa6

File tree

1 file changed

+137
-21
lines changed

1 file changed

+137
-21
lines changed

Library/DiscUtils.Iscsi/ScsiSenseData.cs

Lines changed: 137 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@ internal ScsiSenseData(
115115
public override string ToString()
116116
{
117117
if (KnownSenseCode is ScsiKnownSenseCode known)
118+
{
118119
return $"{KnownSenseCode} ({Description}) [SK={SenseKey}, ASC=0x{AdditionalSenseCode:X2}, ASCQ=0x{AdditionalSenseCodeQualifier:X2}]";
120+
}
121+
119122
return $"{Description} [SK={SenseKey}, ASC=0x{AdditionalSenseCode:X2}, ASCQ=0x{AdditionalSenseCodeQualifier:X2}]";
120123
}
121124
}
@@ -173,31 +176,130 @@ private static readonly Dictionary<ScsiKnownSenseCode, string> KnownDescriptions
173176
{ ScsiKnownSenseCode.AbortedCommand_ScsiParityError, "SCSI parity error (command aborted)" },
174177
};
175178

179+
/// <summary>
180+
/// Parse SCSI sense data from a byte array (fixed or descriptor format).
181+
/// </summary>
182+
/// <param name="buffer">Sense data buffer.</param>
183+
/// <param name="sense"></param>
184+
/// <param name="offset">Offset into the buffer where sense data starts.</param>
176185
public static bool TryParse(byte[] buffer, out ScsiSenseData sense, int offset = 0)
177186
{
178187
sense = null;
179188

180-
try
189+
// --- Top-level basic validation ---------------------------------------
190+
if (buffer == null)
181191
{
182-
// Basic validation — but never throw.
183-
if (buffer == null)
184-
return false;
185-
if (offset < 0 || offset >= buffer.Length)
186-
return false;
192+
return false;
193+
}
194+
195+
if (offset < 0 || offset >= buffer.Length)
196+
{
197+
return false;
198+
}
199+
200+
// Need at least 4 bytes to even know format
201+
if (buffer.Length - offset < 4)
202+
{
203+
return false;
204+
}
205+
206+
// --- Read response code safely ----------------------------------------
207+
var b0 = buffer[offset];
208+
var responseCode = (byte)(b0 & 0x7F);
209+
210+
var isDescriptorFormat = responseCode is 0x72 or 0x73;
211+
var isFixedFormat = responseCode is 0x70 or 0x71;
187212

188-
// Very small sense buffers cannot be parsed.
213+
if (!isDescriptorFormat && !isFixedFormat)
214+
{
215+
// Unknown/unsupported format
216+
return false;
217+
}
218+
219+
ScsiSenseKey senseKey;
220+
byte asc = 0;
221+
byte ascq = 0;
222+
uint? information = null;
223+
224+
// --- Descriptor format (0x72 or 0x73) ---------------------------------
225+
if (isDescriptorFormat)
226+
{
227+
// Descriptor format header is at least 4 bytes
189228
if (buffer.Length - offset < 4)
229+
{
190230
return false;
231+
}
191232

192-
sense = Parse(buffer, offset);
193-
return true;
233+
// Byte 1: Sense key (low nibble)
234+
senseKey = (ScsiSenseKey)(buffer[offset + 1] & 0x0F);
235+
236+
// Byte 2: ASC
237+
asc = buffer[offset + 2];
238+
239+
// Byte 3: ASCQ
240+
ascq = buffer[offset + 3];
241+
242+
// INFORMATION descriptor parsing optional and skipped here
194243
}
195-
catch
244+
// --- Fixed format (0x70 or 0x71) --------------------------------------
245+
else
196246
{
197-
// Ensure no exception leaks out.
198-
sense = null;
199-
return false;
247+
// Need at least 14 bytes for fixed‐format ASC/ASCQ + info
248+
if (buffer.Length - offset < 14)
249+
{
250+
return false;
251+
}
252+
253+
// Byte 2: sense key (low nibble)
254+
senseKey = (ScsiSenseKey)(buffer[offset + 2] & 0x0F);
255+
256+
// Bytes 3–6: INFORMATION (often LBA)
257+
unchecked
258+
{
259+
information =
260+
(uint)((buffer[offset + 3] << 24) |
261+
(buffer[offset + 4] << 16) |
262+
(buffer[offset + 5] << 8) |
263+
buffer[offset + 6]);
264+
}
265+
266+
// Byte 12: ASC
267+
asc = buffer[offset + 12];
268+
269+
// Byte 13: ASCQ
270+
ascq = buffer[offset + 13];
271+
}
272+
273+
// --- Resolve KCQ into known enum --------------------------------------
274+
ScsiKnownSenseCode? knownCode = null;
275+
string description;
276+
277+
if (KnownMap.TryGetValue((senseKey, asc, ascq), out var found))
278+
{
279+
knownCode = found;
280+
if (!KnownDescriptions.TryGetValue(found, out description))
281+
{
282+
description = found.ToString();
283+
}
200284
}
285+
else
286+
{
287+
// Fallback description
288+
description = GetDefaultDescription(senseKey, asc, ascq);
289+
}
290+
291+
sense = new ScsiSenseData(
292+
responseCode: responseCode,
293+
isCurrent: responseCode is 0x70 or 0x72,
294+
isDescriptor: isDescriptorFormat,
295+
senseKey: senseKey,
296+
asc: asc,
297+
ascq: ascq,
298+
information: information,
299+
known: knownCode,
300+
description: description);
301+
302+
return true;
201303
}
202304

203305
/// <summary>
@@ -207,19 +309,27 @@ public static bool TryParse(byte[] buffer, out ScsiSenseData sense, int offset =
207309
/// <param name="offset">Offset into the buffer where sense data starts.</param>
208310
public static ScsiSenseData Parse(byte[] buffer, int offset = 0)
209311
{
210-
if (buffer == null) throw new ArgumentNullException(nameof(buffer));
312+
if (buffer == null)
313+
{
314+
throw new ArgumentNullException(nameof(buffer));
315+
}
316+
211317
if (offset < 0 || offset >= buffer.Length)
318+
{
212319
throw new ArgumentOutOfRangeException(nameof(offset));
320+
}
213321

214322
if (buffer.Length - offset < 4)
323+
{
215324
throw new ArgumentException("Sense buffer is too short.", nameof(buffer));
325+
}
216326

217327
// Byte 0: Response code (low 7 bits) and VALID bit (bit 7 in fixed format).
218-
byte raw0 = buffer[offset + 0];
219-
byte responseCode = (byte)(raw0 & 0x7F);
328+
var raw0 = buffer[offset + 0];
329+
var responseCode = (byte)(raw0 & 0x7F);
220330

221-
bool isCurrent = responseCode == 0x70 || responseCode == 0x72;
222-
bool isDescriptorFormat = responseCode == 0x72 || responseCode == 0x73;
331+
var isCurrent = responseCode is 0x70 or 0x72;
332+
var isDescriptorFormat = responseCode is 0x72 or 0x73;
223333

224334
ScsiSenseKey senseKey;
225335
byte asc;
@@ -233,7 +343,9 @@ public static ScsiSenseData Parse(byte[] buffer, int offset = 0)
233343
// Byte 2: ASC
234344
// Byte 3: ASCQ
235345
if (buffer.Length - offset < 4)
346+
{
236347
throw new ArgumentException("Descriptor sense buffer is too short.", nameof(buffer));
348+
}
237349

238350
senseKey = (ScsiSenseKey)(buffer[offset + 1] & 0x0F);
239351
asc = buffer[offset + 2];
@@ -250,7 +362,9 @@ public static ScsiSenseData Parse(byte[] buffer, int offset = 0)
250362
// Byte 12: ASC
251363
// Byte 13: ASCQ
252364
if (buffer.Length - offset < 14)
365+
{
253366
throw new ArgumentException("Fixed-format sense buffer is too short.", nameof(buffer));
367+
}
254368

255369
senseKey = (ScsiSenseKey)(buffer[offset + 2] & 0x0F);
256370

@@ -273,7 +387,9 @@ public static ScsiSenseData Parse(byte[] buffer, int offset = 0)
273387
{
274388
knownCode = found;
275389
if (!KnownDescriptions.TryGetValue(found, out description))
390+
{
276391
description = found.ToString();
392+
}
277393
}
278394
else
279395
{
@@ -295,9 +411,9 @@ public static ScsiSenseData Parse(byte[] buffer, int offset = 0)
295411

296412
private static (ScsiSenseKey key, byte asc, byte ascq) ScsiTriple(ScsiKnownSenseCode code)
297413
{
298-
int value = (int)code;
299-
byte asc = (byte)((value >> 8) & 0xFF);
300-
byte ascq = (byte)(value & 0xFF);
414+
var value = (int)code;
415+
var asc = (byte)((value >> 8) & 0xFF);
416+
var ascq = (byte)(value & 0xFF);
301417
ScsiSenseKey key = (ScsiSenseKey)((value >> 16) & 0x0F);
302418
return (key, asc, ascq);
303419
}

0 commit comments

Comments
 (0)