xref: /reactos/drivers/storage/class/classpnp/debug.c (revision 15a7b9dd)
1 /*++
2 
3 Copyright (C) Microsoft Corporation, 1991 - 2010
4 
5 Module Name:
6 
7     debug.c
8 
9 Abstract:
10 
11     CLASSPNP debug code and data
12 
13 Environment:
14 
15     kernel mode only
16 
17 Notes:
18 
19 
20 Revision History:
21 
22 --*/
23 
24 
25 #include "classp.h"
26 #include "debug.h"
27 
28 #ifdef DEBUG_USE_WPP
29 #include "debug.tmh"
30 #endif
31 
32 #if DBG
33 
34     //
35     // default to not breaking in for lost irps, five minutes before we even
36     // bother checking for lost irps, using standard debug print macros, and
37     // using a 64k debug print buffer
38     //
39 
40     #ifndef     CLASS_GLOBAL_BREAK_ON_LOST_IRPS
41         #error "CLASS_GLOBAL_BREAK_ON_LOST_IRPS undefined"
42         #define CLASS_GLOBAL_BREAK_ON_LOST_IRPS 0
43     #endif   // CLASS_GLOBAL_BREAK_ON_LOST_IRPS
44 
45     #ifndef     CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB
46         #error "CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB undefined"
47         #define CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB 300
48     #endif   // CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB
49 
50     #ifndef     CLASS_GLOBAL_BUFFERED_DEBUG_PRINT
51         #error "CLASS_GLOBAL_BUFFERED_DEBUG_PRINT undefined"
52         #define CLASS_GLOBAL_BUFFERED_DEBUG_PRINT 0
53     #endif   // CLASS_GLOBAL_BUFFERED_DEBUG_PRINT
54 
55     #ifndef     CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE
56         #error "CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE undefined"
57         #define CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE 512
58     #endif   // CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE
59 
60     #ifndef     CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS
61         #error "CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS undefined"
62         #define CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS 512
63     #endif   // CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS
64 
65 #ifdef _MSC_VER
66     #pragma data_seg("NONPAGE")
67 #endif
68 
69 
70 
71     CLASSPNP_GLOBALS ClasspnpGlobals;
72 
73     //
74     // the low sixteen bits are used to see if the debug level is high enough
75     // the high sixteen bits are used to singly enable debug levels 1-16
76     //
77     LONG ClassDebug = 0x00000000;
78 
79     BOOLEAN DebugTrapOnWarn = FALSE;
80 
81     //
82     // Used to track callers when we receive an access and the disk
83     // is powered down.
84     //
85     ULONG DiskSpinupIndex = 0;
86     DISK_SPINUP_TRACES DiskSpinupTraces[NUMBER_OF_DISK_SPINUP_TRACES];
87 
ClasspInitializeDebugGlobals()88     VOID ClasspInitializeDebugGlobals()
89     {
90         KIRQL irql;
91 
92         if (InterlockedCompareExchange(&ClasspnpGlobals.Initializing, 1, 0) == 0) {
93 
94             KeInitializeSpinLock(&ClasspnpGlobals.SpinLock);
95 
96             KeAcquireSpinLock(&ClasspnpGlobals.SpinLock, &irql);
97 
98             TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_INIT, "CLASSPNP.SYS => Initializing ClasspnpGlobals...\n"));
99 
100             ClasspnpGlobals.Buffer = NULL;
101             ClasspnpGlobals.Index = (ULONG)-1;
102             ClasspnpGlobals.BreakOnLostIrps = CLASS_GLOBAL_BREAK_ON_LOST_IRPS;
103             ClasspnpGlobals.EachBufferSize = CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFER_SIZE;
104             ClasspnpGlobals.NumberOfBuffers = CLASS_GLOBAL_BUFFERED_DEBUG_PRINT_BUFFERS;
105             ClasspnpGlobals.SecondsToWaitForIrps = CLASS_GLOBAL_SECONDS_TO_WAIT_FOR_SYNCHRONOUS_SRB;
106 
107             //
108             // this should be the last item set
109             //
110 
111             ClasspnpGlobals.UseBufferedDebugPrint = CLASS_GLOBAL_BUFFERED_DEBUG_PRINT;
112 
113             KeReleaseSpinLock(&ClasspnpGlobals.SpinLock, irql);
114 
115             InterlockedExchange(&ClasspnpGlobals.Initialized, 1);
116 
117         }
118     }
119 
120     /*++////////////////////////////////////////////////////////////////////////////
121 
122     ClassDebugPrint()
123 
124     Routine Description:
125 
126         Debug print for all class drivers, NOOP on FRE versions.
127         Allows printing to a debug buffer (with auto fallback to kdprint) by
128         properly setting the Globals in classpnp on CHK versions.
129 
130     Arguments:
131 
132         Debug print level, or from 0 to 3 for legacy drivers.
133 
134     Return Value:
135 
136         None
137 
138     --*/
ClassDebugPrint(_In_ CLASS_DEBUG_LEVEL DebugPrintLevel,_In_z_ PCCHAR DebugMessage,...)139     VOID ClassDebugPrint(_In_ CLASS_DEBUG_LEVEL DebugPrintLevel, _In_z_ PCCHAR DebugMessage, ...)
140     {
141         va_list ap;
142         va_start(ap, DebugMessage);
143 
144         if ((DebugPrintLevel <= (ClassDebug & 0x0000ffff)) ||
145             ((1 << (DebugPrintLevel + 15)) & ClassDebug)) {
146 
147             if (ClasspnpGlobals.UseBufferedDebugPrint &&
148                 ClasspnpGlobals.Buffer == NULL) {
149 
150                 //
151                 // this double-check prevents always taking
152                 // a spinlock just to ensure we have a buffer
153                 //
154 
155                 KIRQL irql;
156 
157                 KeAcquireSpinLock(&ClasspnpGlobals.SpinLock, &irql);
158                 if (ClasspnpGlobals.Buffer == NULL) {
159 
160                     SIZE_T bufferSize;
161                     if (NT_SUCCESS(
162                             RtlSIZETMult(ClasspnpGlobals.NumberOfBuffers,
163                                          ClasspnpGlobals.EachBufferSize,
164                                          &bufferSize))) {
165 
166                         DbgPrintEx(DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL,
167                                    "ClassDebugPrint: Allocating %x bytes for "
168                                    "classdebugprint buffer\n", (ULONG)bufferSize);
169                         ClasspnpGlobals.Index = (ULONG)-1;
170                         ClasspnpGlobals.Buffer =
171                             ExAllocatePoolWithTag(NonPagedPoolNx, bufferSize, 'bDcS');
172                         DbgPrintEx(DPFLTR_CLASSPNP_ID, DPFLTR_ERROR_LEVEL,
173                                    "ClassDebugPrint: Allocated buffer at %p\n",
174                                    ClasspnpGlobals.Buffer);
175 
176                         if (ClasspnpGlobals.Buffer) {
177                             RtlZeroMemory(ClasspnpGlobals.Buffer, bufferSize);
178                         }
179                     }
180 
181                 }
182                 KeReleaseSpinLock(&ClasspnpGlobals.SpinLock, irql);
183 
184             }
185 
186             if (ClasspnpGlobals.UseBufferedDebugPrint &&
187                 ClasspnpGlobals.Buffer != NULL) {
188 
189                 //
190                 // we never free the buffer, so once it exists,
191                 // we can just print to it with immunity
192                 //
193 
194                 ULONG index;
195                 PUCHAR buffer;
196                 NTSTATUS status;
197                 index = InterlockedIncrement((volatile LONG *)&ClasspnpGlobals.Index);
198                 index %= ClasspnpGlobals.NumberOfBuffers;
199                 index *= (ULONG)ClasspnpGlobals.EachBufferSize;
200 
201                 buffer = ClasspnpGlobals.Buffer;
202                 buffer += index;
203 
204                 RtlZeroMemory(buffer, ClasspnpGlobals.EachBufferSize);
205 
206                 status = RtlStringCchVPrintfA((NTSTRSAFE_PSTR)buffer, ClasspnpGlobals.EachBufferSize, DebugMessage, ap);
207                 if (!NT_SUCCESS(status))
208                 {
209                     *buffer = 0; // force-null on failure
210                 }
211 
212             } else {
213 
214                 //
215                 // either we could not allocate a buffer for debug prints
216                 // or buffered debug prints are disabled
217                 //
218 
219                 vDbgPrintEx(DPFLTR_CLASSPNP_ID, DPFLTR_INFO_LEVEL, DebugMessage, ap);
220 
221             }
222 
223         }
224 
225         va_end(ap);
226 
227     }
228 
229 
230     /*
231      *  DbgCheckReturnedPkt
232      *
233      *      Check a completed TRANSFER_PACKET for all sorts of error conditions
234      *      and warn/trap appropriately.
235      */
DbgCheckReturnedPkt(TRANSFER_PACKET * Pkt)236     VOID DbgCheckReturnedPkt(TRANSFER_PACKET *Pkt)
237     {
238         PCDB pCdb = ClasspTransferPacketGetCdb(Pkt);
239 
240         NT_ASSERT(SrbGetOriginalRequest(Pkt->Srb) == Pkt->Irp);
241         NT_ASSERT(SrbGetDataBuffer(Pkt->Srb) == Pkt->BufPtrCopy);
242         NT_ASSERT(SrbGetDataTransferLength(Pkt->Srb) <= Pkt->BufLenCopy);
243         NT_ASSERT(!Pkt->Irp->CancelRoutine);
244 
245         if (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_PENDING){
246             TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "SRB completed with status PENDING in packet %ph: (op=%s srbstat=%s(%xh), irpstat=%xh)",
247                         Pkt,
248                         DBGGETSCSIOPSTR(Pkt->Srb),
249                         DBGGETSRBSTATUSSTR(Pkt->Srb),
250                         (ULONG)Pkt->Srb->SrbStatus,
251                         Pkt->Irp->IoStatus.Status));
252         }
253         else if (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_SUCCESS){
254             /*
255              *  Make sure SRB and IRP status match.
256              */
257             if (!NT_SUCCESS(Pkt->Irp->IoStatus.Status)){
258                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "SRB and IRP status don't match in packet %ph: (op=%s srbstat=%s(%xh), irpstat=%xh)",
259                             Pkt,
260                             DBGGETSCSIOPSTR(Pkt->Srb),
261                             DBGGETSRBSTATUSSTR(Pkt->Srb),
262                             (ULONG)Pkt->Srb->SrbStatus,
263                             Pkt->Irp->IoStatus.Status));
264             }
265 
266             if (Pkt->Irp->IoStatus.Information != SrbGetDataTransferLength(Pkt->Srb)){
267                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "SRB and IRP result transfer lengths don't match in succeeded packet %ph: (op=%s, SrbStatus=%s, Srb.DataTransferLength=%xh, Irp->IoStatus.Information=%Ixh).",
268                             Pkt,
269                             DBGGETSCSIOPSTR(Pkt->Srb),
270                             DBGGETSRBSTATUSSTR(Pkt->Srb),
271                             SrbGetDataTransferLength(Pkt->Srb),
272                             Pkt->Irp->IoStatus.Information));
273             }
274         }
275         else {
276             if (NT_SUCCESS(Pkt->Irp->IoStatus.Status)){
277                 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "SRB and IRP status don't match in packet %ph: (op=%s srbstat=%s(%xh), irpstat=%xh)",
278                             Pkt,
279                             DBGGETSCSIOPSTR(Pkt->Srb),
280                             DBGGETSRBSTATUSSTR(Pkt->Srb),
281                             (ULONG)Pkt->Srb->SrbStatus,
282                             Pkt->Irp->IoStatus.Status));
283             }
284             TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_RW, "Packet %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s)",
285                             Pkt,
286                             DBGGETSCSIOPSTR(Pkt->Srb),
287                             DBGGETSRBSTATUSSTR(Pkt->Srb),
288                             (ULONG)Pkt->Srb->SrbStatus,
289                             Pkt->Irp->IoStatus.Status,
290                             DBGGETSENSECODESTR(Pkt->Srb),
291                             DBGGETADSENSECODESTR(Pkt->Srb),
292                             DBGGETADSENSEQUALIFIERSTR(Pkt->Srb)));
293 
294             /*
295              *  If the SRB failed with underrun or overrun, then the actual
296              *  transferred length should be returned in both SRB and IRP.
297              *  (SRB's only have an error status for overrun, so it's overloaded).
298              */
299             if ((SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) &&
300                (Pkt->Irp->IoStatus.Information != SrbGetDataTransferLength(Pkt->Srb))){
301                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "SRB and IRP result transfer lengths don't match in failed packet %ph: (op=%s, SrbStatus=%s, Srb.DataTransferLength=%xh, Irp->IoStatus.Information=%Ixh).",
302                             Pkt,
303                             DBGGETSCSIOPSTR(Pkt->Srb),
304                             DBGGETSRBSTATUSSTR(Pkt->Srb),
305                             SrbGetDataTransferLength(Pkt->Srb),
306                             Pkt->Irp->IoStatus.Information));
307             }
308         }
309 
310         /*
311          *  If the port driver returned STATUS_INSUFFICIENT_RESOURCES,
312          *  make sure this is also the InternalStatus in the SRB so that we process it correctly.
313          */
314         if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){
315             NT_ASSERT(SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR);
316             NT_ASSERT(SrbGetSystemStatus(Pkt->Srb) == STATUS_INSUFFICIENT_RESOURCES);
317         }
318 
319         /*
320          *  Some miniport drivers have been caught changing the SCSI operation
321          *  code in the SRB.  This is absolutely disallowed as it breaks our error handling.
322          */
323         switch (pCdb->CDB10.OperationCode){
324             case SCSIOP_MEDIUM_REMOVAL:
325             case SCSIOP_MODE_SENSE:
326             case SCSIOP_READ_CAPACITY:
327             case SCSIOP_READ:
328             case SCSIOP_WRITE:
329             case SCSIOP_START_STOP_UNIT:
330             case SCSIOP_READ_CAPACITY16:
331             case SCSIOP_READ16:
332             case SCSIOP_WRITE16:
333                 break;
334             default:
335                 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_RW, "Miniport illegally changed Srb.Cdb.OperationCode in packet %ph failed (op=%s srbstat=%s(%xh), irpstat=%xh, sense=%s/%s/%s)",
336                                 Pkt,
337                                 DBGGETSCSIOPSTR(Pkt->Srb),
338                                 DBGGETSRBSTATUSSTR(Pkt->Srb),
339                                 (ULONG)Pkt->Srb->SrbStatus,
340                                 Pkt->Irp->IoStatus.Status,
341                                 DBGGETSENSECODESTR(Pkt->Srb),
342                                 DBGGETADSENSECODESTR(Pkt->Srb),
343                                 DBGGETADSENSEQUALIFIERSTR(Pkt->Srb)));
344                 break;
345         }
346 
347     }
348 
349 
DbgLogSendPacket(TRANSFER_PACKET * Pkt)350     VOID DbgLogSendPacket(TRANSFER_PACKET *Pkt)
351     {
352         PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
353         PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
354         KIRQL oldIrql;
355 
356         if (Pkt->OriginalIrp){
357             Pkt->DbgOriginalIrpCopy = *Pkt->OriginalIrp;
358             if (Pkt->OriginalIrp->MdlAddress){
359                 Pkt->DbgMdlCopy = *Pkt->OriginalIrp->MdlAddress;
360             }
361         }
362 
363         KeQueryTickCount(&Pkt->DbgTimeSent);
364         Pkt->DbgTimeReturned.QuadPart = 0L;
365 
366         KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
367         fdoData->DbgPacketLogs[fdoData->DbgPacketLogNextIndex] = *Pkt;
368         fdoData->DbgPacketLogNextIndex++;
369         fdoData->DbgPacketLogNextIndex %= DBG_NUM_PACKET_LOG_ENTRIES;
370         KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
371     }
372 
DbgLogReturnPacket(TRANSFER_PACKET * Pkt)373     VOID DbgLogReturnPacket(TRANSFER_PACKET *Pkt)
374     {
375         PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
376         PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
377         KIRQL oldIrql;
378 
379         KeQueryTickCount(&Pkt->DbgTimeReturned);
380 
381         #if 0
382             // ISSUE: there are some problems with this check (e.g. multiproc), so don't include it yet
383             if (Pkt->OriginalIrp){
384                 /*
385                  *  No one should have touched the original irp while the packet was outstanding,
386                  *  except for a couple fields that we ourselves update during the transfer
387                  *  or that are allowed to change;
388                  *  make those couple fields the same and then to a bytewise compare
389                  */
390                 ULONG lenSame;
391 
392                 Pkt->DbgOriginalIrpCopy.IoStatus.Status = Pkt->OriginalIrp->IoStatus.Status;
393                 Pkt->DbgOriginalIrpCopy.IoStatus.Information = Pkt->OriginalIrp->IoStatus.Information;
394                 Pkt->DbgOriginalIrpCopy.Tail.Overlay.DriverContext[0] = Pkt->OriginalIrp->Tail.Overlay.DriverContext[0];
395                 Pkt->DbgOriginalIrpCopy.ThreadListEntry = Pkt->OriginalIrp->ThreadListEntry;
396                 Pkt->DbgOriginalIrpCopy.Cancel = Pkt->OriginalIrp->Cancel;
397 
398                 lenSame = (ULONG)RtlCompareMemory(Pkt->OriginalIrp, &Pkt->DbgOriginalIrpCopy, sizeof(IRP));
399                 NT_ASSERT(lenSame == sizeof(IRP));
400             }
401         #endif
402 
403         KeAcquireSpinLock(&fdoData->SpinLock, &oldIrql);
404         fdoData->DbgPacketLogs[fdoData->DbgPacketLogNextIndex] = *Pkt;
405         fdoData->DbgPacketLogNextIndex++;
406         fdoData->DbgPacketLogNextIndex %= DBG_NUM_PACKET_LOG_ENTRIES;
407         KeReleaseSpinLock(&fdoData->SpinLock, oldIrql);
408     }
409 
410 
411     /*++////////////////////////////////////////////////////////////////////////////
412 
413     DbgSafeInc()
414 
415     Routine Description:
416 
417         Safely increments a ULONG. If the increment would result in an overflow,
418         the value is unchanged.
419 
420     Arguments:
421 
422         A pointer to the value to be incremented.
423 
424     --*/
DbgSafeInc(PULONG pValue)425     static VOID DbgSafeInc(PULONG pValue)
426     {
427         ULONG incrementResult;
428         if(NT_SUCCESS(RtlULongAdd(*pValue, 1, &incrementResult))) {
429             *pValue = incrementResult;
430         } else {
431             //
432             // Leave *pValue unchanged (i.e. at ULONG_MAX).
433             //
434         }
435     }
436 
DbgLogFlushInfo(PCLASS_PRIVATE_FDO_DATA FdoData,BOOLEAN IsIO,BOOLEAN IsFUA,BOOLEAN IsFlush)437     VOID DbgLogFlushInfo(PCLASS_PRIVATE_FDO_DATA FdoData, BOOLEAN IsIO, BOOLEAN IsFUA, BOOLEAN IsFlush)
438     {
439 
440         /*
441          *  Reset all FUA/Flush logging fields.
442          */
443         if (FdoData->DbgInitFlushLogging){
444             FdoData->DbgNumIORequests = 0;
445             FdoData->DbgNumFUAs = 0;
446             FdoData->DbgNumFlushes = 0;
447             FdoData->DbgIOsSinceFUA = 0;
448             FdoData->DbgIOsSinceFlush = 0;
449             FdoData->DbgAveIOsToFUA = 0;
450             FdoData->DbgAveIOsToFlush = 0;
451             FdoData->DbgMaxIOsToFUA = 0;
452             FdoData->DbgMaxIOsToFlush = 0;
453             FdoData->DbgMinIOsToFUA = 0xffffffff;
454             FdoData->DbgMinIOsToFlush = 0xffffffff;
455             FdoData->DbgInitFlushLogging = FALSE;
456         }
457 
458         //
459         // Using DbgSafeInc for all increments (instead of ++) guarantees
460         // that there will be no overflow hence no division by 0. All counters
461         // are capped at ULONG_MAX.
462         //
463 
464         if (IsIO){
465             DbgSafeInc(&FdoData->DbgNumIORequests);
466             DbgSafeInc(&FdoData->DbgIOsSinceFlush);
467             if (IsFUA){
468                 if (FdoData->DbgNumFUAs > 0){
469                     FdoData->DbgMinIOsToFUA = min(FdoData->DbgMinIOsToFUA, FdoData->DbgIOsSinceFUA);
470                 }
471                 DbgSafeInc(&FdoData->DbgNumFUAs);
472                 FdoData->DbgAveIOsToFUA =  FdoData->DbgNumIORequests/FdoData->DbgNumFUAs;
473                 FdoData->DbgIOsSinceFUA = 0;
474             }
475             else {
476                 DbgSafeInc(&FdoData->DbgIOsSinceFUA);
477                 FdoData->DbgMaxIOsToFUA = max(FdoData->DbgMaxIOsToFUA, FdoData->DbgIOsSinceFUA);
478             }
479             FdoData->DbgMaxIOsToFlush = max(FdoData->DbgMaxIOsToFlush, FdoData->DbgIOsSinceFlush);
480         }
481         else if (IsFlush){
482             if (FdoData->DbgNumFlushes > 0){
483                 FdoData->DbgMinIOsToFlush = min(FdoData->DbgMinIOsToFlush, FdoData->DbgIOsSinceFlush);
484             }
485             DbgSafeInc(&FdoData->DbgNumFlushes);
486             FdoData->DbgAveIOsToFlush =  FdoData->DbgNumIORequests/FdoData->DbgNumFlushes;
487             FdoData->DbgIOsSinceFlush = 0;
488         }
489 
490     }
491 
492 
493     /*++////////////////////////////////////////////////////////////////////////////
494 
495     SnapDiskStartup()
496 
497     Routine Description:
498 
499         This function will attempt to record the caller responsible for spinning
500         up the disk.
501 
502     Arguments:
503 
504         NONE.
505 
506     Return Value:
507 
508         NONE.
509 
510     --*/
511     VOID
SnapDiskStartup(VOID)512     SnapDiskStartup(
513         VOID
514     )
515     {
516         ULONG       Index;
517         PDISK_SPINUP_TRACES Entry;
518         LARGE_INTEGER   SpinUpTime;
519 
520 #ifdef _MSC_VER
521 #pragma warning(push)
522 #pragma warning(disable:4210) // nonstandard extension used : function given file scope
523 #endif
524         extern NTSYSAPI USHORT NTAPI RtlCaptureStackBackTrace(
525            _In_         ULONG FramesToSkip,
526            _In_         ULONG FramesToCapture,
527            _Out_writes_to_(FramesToCapture, return) PVOID * BackTrace,
528            _Out_opt_    PULONG BackTraceHash );
529 #ifdef _MSC_VER
530 #pragma warning(pop)
531 #endif
532 
533         //
534         // Grab the current count, then mod it so that it
535         // becomes an index into the DiskSpinupTraces array.
536         //
537         Index = InterlockedIncrement( (volatile LONG *)&DiskSpinupIndex );
538         Index = Index & (NUMBER_OF_DISK_SPINUP_TRACES - 1);
539         Entry = &DiskSpinupTraces[Index];
540 
541         //
542         // Timestamp the instance.
543         //
544         KeQueryTickCount(&SpinUpTime);
545         SpinUpTime.QuadPart = (SpinUpTime.QuadPart * KeQueryTimeIncrement())/(10000000);
546 
547 
548         //
549         // Ask the kernel to read back up our stack by
550         // DISK_SPINUP_BACKTRACE_LENGTH frames.
551         //
552         Entry->TimeStamp.QuadPart = SpinUpTime.QuadPart;
553         RtlZeroMemory( &Entry->StackTrace[0], DISK_SPINUP_BACKTRACE_LENGTH * sizeof(PVOID) );
554         RtlCaptureStackBackTrace( 5,                           // stacks to skip
555                                   DISK_SPINUP_BACKTRACE_LENGTH, // buffer size
556                                   Entry->StackTrace,
557                                   &Index );
558     }
559 
560 #else
561 
562     // We have to keep this in the retail build for legacy.
ClassDebugPrint(_In_ CLASS_DEBUG_LEVEL DebugPrintLevel,_In_z_ PCCHAR DebugMessage,...)563     VOID ClassDebugPrint(_In_ CLASS_DEBUG_LEVEL DebugPrintLevel, _In_z_ PCCHAR DebugMessage, ...)
564     {
565         UNREFERENCED_PARAMETER(DebugPrintLevel);
566         UNREFERENCED_PARAMETER(DebugMessage);
567     }
568 
569 #endif
570 
DbgGetIoctlStr(ULONG ioctl)571     char *DbgGetIoctlStr(ULONG ioctl)
572     {
573         char *ioctlStr = "?";
574 
575         switch (ioctl){
576 
577             #undef MAKE_CASE
578             #define MAKE_CASE(ioctlCode) case ioctlCode: ioctlStr = #ioctlCode; break;
579 
580             MAKE_CASE(IOCTL_STORAGE_CHECK_VERIFY)
581             MAKE_CASE(IOCTL_STORAGE_CHECK_VERIFY2)
582             MAKE_CASE(IOCTL_STORAGE_MEDIA_REMOVAL)
583             MAKE_CASE(IOCTL_STORAGE_EJECT_MEDIA)
584             MAKE_CASE(IOCTL_STORAGE_LOAD_MEDIA)
585             MAKE_CASE(IOCTL_STORAGE_LOAD_MEDIA2)
586             MAKE_CASE(IOCTL_STORAGE_RESERVE)
587             MAKE_CASE(IOCTL_STORAGE_RELEASE)
588             MAKE_CASE(IOCTL_STORAGE_PERSISTENT_RESERVE_IN)
589             MAKE_CASE(IOCTL_STORAGE_PERSISTENT_RESERVE_OUT)
590             MAKE_CASE(IOCTL_STORAGE_FIND_NEW_DEVICES)
591             MAKE_CASE(IOCTL_STORAGE_EJECTION_CONTROL)
592             MAKE_CASE(IOCTL_STORAGE_MCN_CONTROL)
593             MAKE_CASE(IOCTL_STORAGE_GET_MEDIA_TYPES)
594             MAKE_CASE(IOCTL_STORAGE_GET_MEDIA_TYPES_EX)
595             MAKE_CASE(IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER)
596             MAKE_CASE(IOCTL_STORAGE_GET_HOTPLUG_INFO)
597             MAKE_CASE(IOCTL_STORAGE_RESET_BUS)
598             MAKE_CASE(IOCTL_STORAGE_RESET_DEVICE)
599             MAKE_CASE(IOCTL_STORAGE_GET_DEVICE_NUMBER)
600             MAKE_CASE(IOCTL_STORAGE_PREDICT_FAILURE)
601             MAKE_CASE(IOCTL_STORAGE_QUERY_PROPERTY)
602             MAKE_CASE(OBSOLETE_IOCTL_STORAGE_RESET_BUS)
603             MAKE_CASE(OBSOLETE_IOCTL_STORAGE_RESET_DEVICE)
604         }
605 
606         return ioctlStr;
607     }
608 
DbgGetScsiOpStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)609     char *DbgGetScsiOpStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)
610     {
611         PCDB pCdb = SrbGetCdb(Srb);
612         char *scsiOpStr = "?";
613 
614         if (pCdb) {
615 
616             switch (pCdb->CDB6GENERIC.OperationCode){
617 
618                 #undef MAKE_CASE
619                 #define MAKE_CASE(scsiOpCode) case scsiOpCode: scsiOpStr = #scsiOpCode; break;
620 
621                 MAKE_CASE(SCSIOP_TEST_UNIT_READY)
622                 MAKE_CASE(SCSIOP_REWIND)    // aka SCSIOP_REZERO_UNIT
623                 MAKE_CASE(SCSIOP_REQUEST_BLOCK_ADDR)
624                 MAKE_CASE(SCSIOP_REQUEST_SENSE)
625                 MAKE_CASE(SCSIOP_FORMAT_UNIT)
626                 MAKE_CASE(SCSIOP_READ_BLOCK_LIMITS)
627                 MAKE_CASE(SCSIOP_INIT_ELEMENT_STATUS)   // aka SCSIOP_REASSIGN_BLOCKS
628                 MAKE_CASE(SCSIOP_RECEIVE)       // aka SCSIOP_READ6
629                 MAKE_CASE(SCSIOP_SEND)  // aka SCSIOP_WRITE6, SCSIOP_PRINT
630                 MAKE_CASE(SCSIOP_SLEW_PRINT)    // aka SCSIOP_SEEK6, SCSIOP_TRACK_SELECT
631                 MAKE_CASE(SCSIOP_SEEK_BLOCK)
632                 MAKE_CASE(SCSIOP_PARTITION)
633                 MAKE_CASE(SCSIOP_READ_REVERSE)
634                 MAKE_CASE(SCSIOP_FLUSH_BUFFER)      // aka SCSIOP_WRITE_FILEMARKS
635                 MAKE_CASE(SCSIOP_SPACE)
636                 MAKE_CASE(SCSIOP_INQUIRY)
637                 MAKE_CASE(SCSIOP_VERIFY6)
638                 MAKE_CASE(SCSIOP_RECOVER_BUF_DATA)
639                 MAKE_CASE(SCSIOP_MODE_SELECT)
640                 MAKE_CASE(SCSIOP_RESERVE_UNIT)
641                 MAKE_CASE(SCSIOP_RELEASE_UNIT)
642                 MAKE_CASE(SCSIOP_COPY)
643                 MAKE_CASE(SCSIOP_ERASE)
644                 MAKE_CASE(SCSIOP_MODE_SENSE)
645                 MAKE_CASE(SCSIOP_START_STOP_UNIT)   // aka SCSIOP_STOP_PRINT, SCSIOP_LOAD_UNLOAD
646                 MAKE_CASE(SCSIOP_RECEIVE_DIAGNOSTIC)
647                 MAKE_CASE(SCSIOP_SEND_DIAGNOSTIC)
648                 MAKE_CASE(SCSIOP_MEDIUM_REMOVAL)
649                 MAKE_CASE(SCSIOP_READ_FORMATTED_CAPACITY)
650                 MAKE_CASE(SCSIOP_READ_CAPACITY)
651                 MAKE_CASE(SCSIOP_READ)
652                 MAKE_CASE(SCSIOP_WRITE)
653                 MAKE_CASE(SCSIOP_SEEK)  // aka SCSIOP_LOCATE, SCSIOP_POSITION_TO_ELEMENT
654                 MAKE_CASE(SCSIOP_WRITE_VERIFY)
655                 MAKE_CASE(SCSIOP_VERIFY)
656                 MAKE_CASE(SCSIOP_SEARCH_DATA_HIGH)
657                 MAKE_CASE(SCSIOP_SEARCH_DATA_EQUAL)
658                 MAKE_CASE(SCSIOP_SEARCH_DATA_LOW)
659                 MAKE_CASE(SCSIOP_SET_LIMITS)
660                 MAKE_CASE(SCSIOP_READ_POSITION)
661                 MAKE_CASE(SCSIOP_SYNCHRONIZE_CACHE)
662                 MAKE_CASE(SCSIOP_COMPARE)
663                 MAKE_CASE(SCSIOP_COPY_COMPARE)
664                 MAKE_CASE(SCSIOP_WRITE_DATA_BUFF)
665                 MAKE_CASE(SCSIOP_READ_DATA_BUFF)
666                 MAKE_CASE(SCSIOP_CHANGE_DEFINITION)
667                 MAKE_CASE(SCSIOP_READ_SUB_CHANNEL)
668                 MAKE_CASE(SCSIOP_READ_TOC)
669                 MAKE_CASE(SCSIOP_READ_HEADER)
670                 MAKE_CASE(SCSIOP_PLAY_AUDIO)
671                 MAKE_CASE(SCSIOP_GET_CONFIGURATION)
672                 MAKE_CASE(SCSIOP_PLAY_AUDIO_MSF)
673                 MAKE_CASE(SCSIOP_PLAY_TRACK_INDEX)
674                 MAKE_CASE(SCSIOP_PLAY_TRACK_RELATIVE)
675                 MAKE_CASE(SCSIOP_GET_EVENT_STATUS)
676                 MAKE_CASE(SCSIOP_PAUSE_RESUME)
677                 MAKE_CASE(SCSIOP_LOG_SELECT)
678                 MAKE_CASE(SCSIOP_LOG_SENSE)
679                 MAKE_CASE(SCSIOP_STOP_PLAY_SCAN)
680                 MAKE_CASE(SCSIOP_READ_DISK_INFORMATION)
681                 MAKE_CASE(SCSIOP_READ_TRACK_INFORMATION)
682                 MAKE_CASE(SCSIOP_RESERVE_TRACK_RZONE)
683                 MAKE_CASE(SCSIOP_SEND_OPC_INFORMATION)
684                 MAKE_CASE(SCSIOP_MODE_SELECT10)
685                 MAKE_CASE(SCSIOP_MODE_SENSE10)
686                 MAKE_CASE(SCSIOP_CLOSE_TRACK_SESSION)
687                 MAKE_CASE(SCSIOP_READ_BUFFER_CAPACITY)
688                 MAKE_CASE(SCSIOP_SEND_CUE_SHEET)
689                 MAKE_CASE(SCSIOP_PERSISTENT_RESERVE_IN)
690                 MAKE_CASE(SCSIOP_PERSISTENT_RESERVE_OUT)
691                 MAKE_CASE(SCSIOP_REPORT_LUNS)
692                 MAKE_CASE(SCSIOP_BLANK)
693                 MAKE_CASE(SCSIOP_SEND_KEY)
694                 MAKE_CASE(SCSIOP_REPORT_KEY)
695                 MAKE_CASE(SCSIOP_MOVE_MEDIUM)
696                 MAKE_CASE(SCSIOP_LOAD_UNLOAD_SLOT)  // aka SCSIOP_EXCHANGE_MEDIUM
697                 MAKE_CASE(SCSIOP_SET_READ_AHEAD)
698                 MAKE_CASE(SCSIOP_READ_DVD_STRUCTURE)
699                 MAKE_CASE(SCSIOP_REQUEST_VOL_ELEMENT)
700                 MAKE_CASE(SCSIOP_SEND_VOLUME_TAG)
701                 MAKE_CASE(SCSIOP_READ_ELEMENT_STATUS)
702                 MAKE_CASE(SCSIOP_READ_CD_MSF)
703                 MAKE_CASE(SCSIOP_SCAN_CD)
704                 MAKE_CASE(SCSIOP_SET_CD_SPEED)
705                 MAKE_CASE(SCSIOP_PLAY_CD)
706                 MAKE_CASE(SCSIOP_MECHANISM_STATUS)
707                 MAKE_CASE(SCSIOP_READ_CD)
708                 MAKE_CASE(SCSIOP_SEND_DVD_STRUCTURE)
709                 MAKE_CASE(SCSIOP_INIT_ELEMENT_RANGE)
710                 MAKE_CASE(SCSIOP_READ16)
711                 MAKE_CASE(SCSIOP_WRITE16)
712                 MAKE_CASE(SCSIOP_VERIFY16)
713                 MAKE_CASE(SCSIOP_SYNCHRONIZE_CACHE16)
714                 MAKE_CASE(SCSIOP_READ_CAPACITY16)
715             }
716         }
717 
718         return scsiOpStr;
719     }
720 
721 
DbgGetSrbStatusStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)722     char *DbgGetSrbStatusStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)
723     {
724         char *srbStatStr = "?";
725 
726         switch (Srb->SrbStatus){
727 
728             #undef MAKE_CASE
729             #define MAKE_CASE(srbStat) \
730                         case srbStat: \
731                             srbStatStr = #srbStat; \
732                             break; \
733                         case srbStat|SRB_STATUS_QUEUE_FROZEN: \
734                             srbStatStr = #srbStat "|SRB_STATUS_QUEUE_FROZEN"; \
735                             break; \
736                         case srbStat|SRB_STATUS_AUTOSENSE_VALID: \
737                             srbStatStr = #srbStat "|SRB_STATUS_AUTOSENSE_VALID"; \
738                             break; \
739                         case srbStat|SRB_STATUS_QUEUE_FROZEN|SRB_STATUS_AUTOSENSE_VALID: \
740                             srbStatStr = #srbStat "|SRB_STATUS_QUEUE_FROZEN|SRB_STATUS_AUTOSENSE_VALID"; \
741                             break;
742 
743             MAKE_CASE(SRB_STATUS_PENDING)
744             MAKE_CASE(SRB_STATUS_SUCCESS)
745             MAKE_CASE(SRB_STATUS_ABORTED)
746             MAKE_CASE(SRB_STATUS_ABORT_FAILED)
747             MAKE_CASE(SRB_STATUS_ERROR)
748             MAKE_CASE(SRB_STATUS_BUSY)
749             MAKE_CASE(SRB_STATUS_INVALID_REQUEST)
750             MAKE_CASE(SRB_STATUS_INVALID_PATH_ID)
751             MAKE_CASE(SRB_STATUS_NO_DEVICE)
752             MAKE_CASE(SRB_STATUS_TIMEOUT)
753             MAKE_CASE(SRB_STATUS_SELECTION_TIMEOUT)
754             MAKE_CASE(SRB_STATUS_COMMAND_TIMEOUT)
755             MAKE_CASE(SRB_STATUS_MESSAGE_REJECTED)
756             MAKE_CASE(SRB_STATUS_BUS_RESET)
757             MAKE_CASE(SRB_STATUS_PARITY_ERROR)
758             MAKE_CASE(SRB_STATUS_REQUEST_SENSE_FAILED)
759             MAKE_CASE(SRB_STATUS_NO_HBA)
760             MAKE_CASE(SRB_STATUS_DATA_OVERRUN)
761             MAKE_CASE(SRB_STATUS_UNEXPECTED_BUS_FREE)
762             MAKE_CASE(SRB_STATUS_PHASE_SEQUENCE_FAILURE)
763             MAKE_CASE(SRB_STATUS_BAD_SRB_BLOCK_LENGTH)
764             MAKE_CASE(SRB_STATUS_REQUEST_FLUSHED)
765             MAKE_CASE(SRB_STATUS_INVALID_LUN)
766             MAKE_CASE(SRB_STATUS_INVALID_TARGET_ID)
767             MAKE_CASE(SRB_STATUS_BAD_FUNCTION)
768             MAKE_CASE(SRB_STATUS_ERROR_RECOVERY)
769             MAKE_CASE(SRB_STATUS_NOT_POWERED)
770             MAKE_CASE(SRB_STATUS_INTERNAL_ERROR)
771         }
772 
773         return srbStatStr;
774     }
775 
776 
DbgGetSenseCodeStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)777     char *DbgGetSenseCodeStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)
778     {
779         char *senseCodeStr = "?";
780 
781         if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID){
782 
783             PVOID senseData;
784             UCHAR senseCode;
785             BOOLEAN validSense;
786 
787             senseData = SrbGetSenseInfoBuffer(Srb);
788             NT_ASSERT(senseData);
789 
790             validSense = ScsiGetSenseKeyAndCodes(senseData,
791                                                  SrbGetSenseInfoBufferLength(Srb),
792                                                  SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
793                                                  &senseCode,
794                                                  NULL,
795                                                  NULL);
796             if (validSense) {
797                 switch (senseCode){
798 
799                     #undef MAKE_CASE
800                     #define MAKE_CASE(snsCod) case snsCod: senseCodeStr = #snsCod; break;
801 
802                     MAKE_CASE(SCSI_SENSE_NO_SENSE)
803                     MAKE_CASE(SCSI_SENSE_RECOVERED_ERROR)
804                     MAKE_CASE(SCSI_SENSE_NOT_READY)
805                     MAKE_CASE(SCSI_SENSE_MEDIUM_ERROR)
806                     MAKE_CASE(SCSI_SENSE_HARDWARE_ERROR)
807                     MAKE_CASE(SCSI_SENSE_ILLEGAL_REQUEST)
808                     MAKE_CASE(SCSI_SENSE_UNIT_ATTENTION)
809                     MAKE_CASE(SCSI_SENSE_DATA_PROTECT)
810                     MAKE_CASE(SCSI_SENSE_BLANK_CHECK)
811                     MAKE_CASE(SCSI_SENSE_UNIQUE)
812                     MAKE_CASE(SCSI_SENSE_COPY_ABORTED)
813                     MAKE_CASE(SCSI_SENSE_ABORTED_COMMAND)
814                     MAKE_CASE(SCSI_SENSE_EQUAL)
815                     MAKE_CASE(SCSI_SENSE_VOL_OVERFLOW)
816                     MAKE_CASE(SCSI_SENSE_MISCOMPARE)
817                     MAKE_CASE(SCSI_SENSE_RESERVED)
818                 }
819             }
820         }
821 
822         return senseCodeStr;
823     }
824 
825 
DbgGetAdditionalSenseCodeStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)826     char *DbgGetAdditionalSenseCodeStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)
827     {
828         char *adSenseCodeStr = "?";
829 
830         if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID){
831             PVOID senseData;
832             UCHAR adSenseCode;
833             BOOLEAN validSense;
834 
835             senseData = SrbGetSenseInfoBuffer(Srb);
836             NT_ASSERT(senseData);
837 
838             validSense = ScsiGetSenseKeyAndCodes(senseData,
839                                                  SrbGetSenseInfoBufferLength(Srb),
840                                                  SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
841                                                  NULL,
842                                                  &adSenseCode,
843                                                  NULL);
844 
845             if (validSense) {
846                 switch (adSenseCode){
847 
848                     #undef MAKE_CASE
849                     #define MAKE_CASE(adSnsCod) case adSnsCod: adSenseCodeStr = #adSnsCod; break;
850 
851                     MAKE_CASE(SCSI_ADSENSE_NO_SENSE)
852                     MAKE_CASE(SCSI_ADSENSE_LUN_NOT_READY)
853                     MAKE_CASE(SCSI_ADSENSE_TRACK_ERROR)
854                     MAKE_CASE(SCSI_ADSENSE_SEEK_ERROR)
855                     MAKE_CASE(SCSI_ADSENSE_REC_DATA_NOECC)
856                     MAKE_CASE(SCSI_ADSENSE_REC_DATA_ECC)
857                     MAKE_CASE(SCSI_ADSENSE_ILLEGAL_COMMAND)
858                     MAKE_CASE(SCSI_ADSENSE_ILLEGAL_BLOCK)
859                     MAKE_CASE(SCSI_ADSENSE_INVALID_CDB)
860                     MAKE_CASE(SCSI_ADSENSE_INVALID_LUN)
861                     MAKE_CASE(SCSI_ADSENSE_WRITE_PROTECT)   // aka SCSI_ADWRITE_PROTECT
862                     MAKE_CASE(SCSI_ADSENSE_MEDIUM_CHANGED)
863                     MAKE_CASE(SCSI_ADSENSE_BUS_RESET)
864                     MAKE_CASE(SCSI_ADSENSE_INVALID_MEDIA)
865                     MAKE_CASE(SCSI_ADSENSE_NO_MEDIA_IN_DEVICE)
866                     MAKE_CASE(SCSI_ADSENSE_POSITION_ERROR)
867                     MAKE_CASE(SCSI_ADSENSE_OPERATOR_REQUEST)
868                     MAKE_CASE(SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED)
869                     MAKE_CASE(SCSI_ADSENSE_COPY_PROTECTION_FAILURE)
870                     MAKE_CASE(SCSI_ADSENSE_VENDOR_UNIQUE)
871                     MAKE_CASE(SCSI_ADSENSE_MUSIC_AREA)
872                     MAKE_CASE(SCSI_ADSENSE_DATA_AREA)
873                     MAKE_CASE(SCSI_ADSENSE_VOLUME_OVERFLOW)
874                 }
875             }
876         }
877 
878         return adSenseCodeStr;
879     }
880 
881 
DbgGetAdditionalSenseCodeQualifierStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)882     char *DbgGetAdditionalSenseCodeQualifierStr(PSTORAGE_REQUEST_BLOCK_HEADER Srb)
883     {
884         char *adSenseCodeQualStr = "?";
885 
886         if (Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID){
887             PVOID senseData;
888             UCHAR adSenseCode;
889             UCHAR adSenseCodeQual;
890             BOOLEAN validSense;
891 
892             senseData = SrbGetSenseInfoBuffer(Srb);
893             NT_ASSERT(senseData);
894 
895             validSense = ScsiGetSenseKeyAndCodes(senseData,
896                                                  SrbGetSenseInfoBufferLength(Srb),
897                                                  SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
898                                                  NULL,
899                                                  &adSenseCode,
900                                                  &adSenseCodeQual);
901             if (validSense) {
902                 switch (adSenseCode){
903 
904                     #undef MAKE_CASE
905                     #define MAKE_CASE(adSnsCodQual) case adSnsCodQual: adSenseCodeQualStr = #adSnsCodQual; break;
906 
907                     case SCSI_ADSENSE_LUN_NOT_READY:
908                         switch (adSenseCodeQual){
909                             MAKE_CASE(SCSI_SENSEQ_CAUSE_NOT_REPORTABLE)
910                             MAKE_CASE(SCSI_SENSEQ_BECOMING_READY)
911                             MAKE_CASE(SCSI_SENSEQ_INIT_COMMAND_REQUIRED)
912                             MAKE_CASE(SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED)
913                             MAKE_CASE(SCSI_SENSEQ_FORMAT_IN_PROGRESS)
914                             MAKE_CASE(SCSI_SENSEQ_REBUILD_IN_PROGRESS)
915                             MAKE_CASE(SCSI_SENSEQ_RECALCULATION_IN_PROGRESS)
916                             MAKE_CASE(SCSI_SENSEQ_OPERATION_IN_PROGRESS)
917                             MAKE_CASE(SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS)
918                         }
919                         break;
920                     case SCSI_ADSENSE_NO_SENSE:
921                         switch (adSenseCodeQual){
922                             MAKE_CASE(SCSI_SENSEQ_FILEMARK_DETECTED)
923                             MAKE_CASE(SCSI_SENSEQ_END_OF_MEDIA_DETECTED)
924                             MAKE_CASE(SCSI_SENSEQ_SETMARK_DETECTED)
925                             MAKE_CASE(SCSI_SENSEQ_BEGINNING_OF_MEDIA_DETECTED)
926                         }
927                         break;
928                     case SCSI_ADSENSE_ILLEGAL_BLOCK:
929                         switch (adSenseCodeQual){
930                             MAKE_CASE(SCSI_SENSEQ_ILLEGAL_ELEMENT_ADDR)
931                         }
932                         break;
933                     case SCSI_ADSENSE_POSITION_ERROR:
934                         switch (adSenseCodeQual){
935                             MAKE_CASE(SCSI_SENSEQ_DESTINATION_FULL)
936                             MAKE_CASE(SCSI_SENSEQ_SOURCE_EMPTY)
937                         }
938                         break;
939                     case SCSI_ADSENSE_INVALID_MEDIA:
940                         switch (adSenseCodeQual){
941                             MAKE_CASE(SCSI_SENSEQ_INCOMPATIBLE_MEDIA_INSTALLED)
942                             MAKE_CASE(SCSI_SENSEQ_UNKNOWN_FORMAT)
943                             MAKE_CASE(SCSI_SENSEQ_INCOMPATIBLE_FORMAT)
944                             MAKE_CASE(SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED)
945                         }
946                         break;
947                     case SCSI_ADSENSE_OPERATOR_REQUEST:
948                         switch (adSenseCodeQual){
949                             MAKE_CASE(SCSI_SENSEQ_STATE_CHANGE_INPUT)
950                             MAKE_CASE(SCSI_SENSEQ_MEDIUM_REMOVAL)
951                             MAKE_CASE(SCSI_SENSEQ_WRITE_PROTECT_ENABLE)
952                             MAKE_CASE(SCSI_SENSEQ_WRITE_PROTECT_DISABLE)
953                         }
954                         break;
955                     case SCSI_ADSENSE_COPY_PROTECTION_FAILURE:
956                         switch (adSenseCodeQual){
957                             MAKE_CASE(SCSI_SENSEQ_AUTHENTICATION_FAILURE)
958                             MAKE_CASE(SCSI_SENSEQ_KEY_NOT_PRESENT)
959                             MAKE_CASE(SCSI_SENSEQ_KEY_NOT_ESTABLISHED)
960                             MAKE_CASE(SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION)
961                             MAKE_CASE(SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT)
962                             MAKE_CASE(SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR)
963                         }
964                         break;
965                 }
966             }
967         }
968 
969         return adSenseCodeQualStr;
970     }
971 
972 
973