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