1 /*-- 2 3 Copyright (C) Microsoft Corporation. All rights reserved. 4 5 Module Name: 6 7 sense.c 8 9 Abstract: 10 11 This file contains the methods needed to accurately 12 determine how to retry requests on CDROM device types. 13 14 Environment: 15 16 kernel mode only 17 18 Revision History: 19 20 --*/ 21 22 #include "stddef.h" 23 #include "string.h" 24 25 #include "ntddk.h" 26 #include "ntddstor.h" 27 #include "cdrom.h" 28 #include "ntstrsafe.h" 29 30 31 #ifdef DEBUG_USE_WPP 32 #include "sense.tmh" 33 #endif 34 35 // Forward declarations 36 VOID 37 SenseInfoInterpretRefineByIoControl( 38 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 39 _In_ ULONG IoControlCode, 40 _In_ BOOLEAN OverrideVerifyVolume, 41 _Inout_ BOOLEAN* Retry, 42 _Inout_ NTSTATUS* Status 43 ); 44 45 46 #ifdef ALLOC_PRAGMA 47 48 #pragma alloc_text(PAGE, SenseInfoInterpretRefineByIoControl) 49 50 #endif 51 52 53 // 54 // FROM CLASSPNP\CLASSP.H 55 // Lots of retries of synchronized SCSI commands that devices may not 56 // even support really slows down the system (especially while booting). 57 // (Even GetDriveCapacity may be failed on purpose if an external disk is powered off). 58 // If a disk cannot return a small initialization buffer at startup 59 // in two attempts (with delay interval) then we cannot expect it to return 60 // data consistently with four retries. 61 // So don't set the retry counts as high here as for data SRBs. 62 // 63 // If we find that these requests are failing consecutively, 64 // despite the retry interval, on otherwise reliable media, 65 // then we should either increase the retry interval for 66 // that failure or (by all means) increase these retry counts as appropriate. 67 // 68 69 #define TOTAL_COUNT_RETRY_DEFAULT 4 70 #define TOTAL_COUNT_RETRY_LOCK_MEDIA 1 71 #define TOTAL_COUNT_RETRY_MODESENSE 1 72 #define TOTAL_COUNT_RETRY_READ_CAPACITY 1 73 74 75 #define TOTAL_SECONDS_RETRY_TIME_WRITE 160 76 #define TOTAL_SECONDS_RETRY_TIME_MEDIUM_REMOVAL 120 77 78 typedef struct _ERROR_LOG_CONTEXT { 79 BOOLEAN LogError; 80 BOOLEAN ErrorUnhandled; 81 NTSTATUS ErrorCode; 82 ULONG UniqueErrorValue; 83 ULONG BadSector; 84 } ERROR_LOG_CONTEXT, *PERROR_LOG_CONTEXT; 85 86 NTSTATUS 87 DeviceErrorHandlerForMmc( 88 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 89 _In_ PSCSI_REQUEST_BLOCK Srb, 90 _Inout_ PNTSTATUS Status, 91 _Inout_ PBOOLEAN Retry 92 ) 93 /*++ 94 95 Routine Description: 96 97 this routine will be used for error handler for all MMC devices. 98 it's invoked by DeviceErrorHandler()that invoked by SenseInfoInterpret() or GESN 99 100 This routine just checks for media change sense/asc/ascq and 101 also for other events, such as bus resets. this is used to 102 determine if the device behaviour has changed, to allow for 103 read and write operations to be allowed and/or disallowed. 104 105 Arguments: 106 107 DeviceExtension - device context 108 Srb - SRB structure for analyze 109 110 Return Value: 111 112 NTSTATUS 113 Status - 114 Retry - 115 116 --*/ 117 { 118 BOOLEAN mediaChange = FALSE; 119 PCDB cdb = (PCDB)Srb->Cdb; 120 121 if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) 122 { 123 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; 124 125 // the following sense keys could indicate a change in capabilities. 126 127 // we used to expect this to be serialized, and only hit from our 128 // own routine. we now allow some requests to continue during our 129 // processing of the capabilities update in order to allow 130 // IoReadPartitionTable() to succeed. 131 switch (senseBuffer->SenseKey & 0xf) 132 { 133 134 case SCSI_SENSE_NOT_READY: 135 { 136 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) 137 { 138 if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed) 139 { 140 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 141 "DeviceErrorHandlerForMmc: media removed, writes will be " 142 "failed until new media detected\n")); 143 } 144 145 // NOTE - REF #0002 146 DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; 147 } 148 else if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) 149 { 150 if (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_BECOMING_READY) 151 { 152 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 153 "DeviceErrorHandlerForMmc: media becoming ready, " 154 "SHOULD notify shell of change time by sending " 155 "GESN request immediately!\n")); 156 } 157 else if (((senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_OPERATION_IN_PROGRESS) || 158 (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS) 159 ) && 160 ((Srb->Cdb[0] == SCSIOP_READ) || 161 (Srb->Cdb[0] == SCSIOP_READ6) || 162 (Srb->Cdb[0] == SCSIOP_READ_CAPACITY) || 163 (Srb->Cdb[0] == SCSIOP_READ_CD) || 164 (Srb->Cdb[0] == SCSIOP_READ_CD_MSF) || 165 (Srb->Cdb[0] == SCSIOP_READ_TOC) || 166 (Srb->Cdb[0] == SCSIOP_WRITE) || 167 (Srb->Cdb[0] == SCSIOP_WRITE6) || 168 (Srb->Cdb[0] == SCSIOP_READ_TRACK_INFORMATION) || 169 (Srb->Cdb[0] == SCSIOP_READ_DISK_INFORMATION) 170 ) 171 ) 172 { 173 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 174 "DeviceErrorHandlerForMmc: LONG_WRITE or " 175 "OP_IN_PROGRESS for limited subset of cmds -- " 176 "setting retry to TRUE\n")); 177 *Retry = TRUE; 178 *Status = STATUS_DEVICE_BUSY; 179 } 180 } 181 break; 182 } // end SCSI_SENSE_NOT_READY 183 184 case SCSI_SENSE_UNIT_ATTENTION: 185 { 186 switch (senseBuffer->AdditionalSenseCode) 187 { 188 case SCSI_ADSENSE_MEDIUM_CHANGED: 189 { 190 // always update if the medium may have changed 191 192 // NOTE - REF #0002 193 DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; 194 DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; 195 196 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 197 "DeviceErrorHandlerForMmc: media change detected, need to " 198 "update drive capabilities\n")); 199 mediaChange = TRUE; 200 break; 201 202 } // end SCSI_ADSENSE_MEDIUM_CHANGED 203 204 case SCSI_ADSENSE_BUS_RESET: 205 { 206 // NOTE - REF #0002 207 DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; 208 DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; 209 210 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 211 "DeviceErrorHandlerForMmc: bus reset detected, need to " 212 "update drive capabilities\n")); 213 break; 214 215 } // end SCSI_ADSENSE_BUS_RESET 216 217 case SCSI_ADSENSE_OPERATOR_REQUEST: 218 { 219 220 BOOLEAN b = FALSE; 221 222 switch (senseBuffer->AdditionalSenseCodeQualifier) 223 { 224 case SCSI_SENSEQ_MEDIUM_REMOVAL: 225 { 226 // eject notification currently handled by classpnp 227 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 228 "DeviceErrorHandlerForMmc: Eject requested by user\n")); 229 *Retry = TRUE; 230 *Status = STATUS_DEVICE_BUSY; 231 break; 232 } 233 234 case SCSI_SENSEQ_WRITE_PROTECT_DISABLE: 235 b = TRUE; 236 case SCSI_SENSEQ_WRITE_PROTECT_ENABLE: 237 { 238 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 239 "DeviceErrorHandlerForMmc: Write protect %s requested " 240 "by user\n", 241 (b ? "disable" : "enable"))); 242 *Retry = TRUE; 243 *Status = STATUS_DEVICE_BUSY; 244 // NOTE - REF #0002 245 DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; 246 DeviceExtension->DeviceAdditionalData.Mmc.UpdateState = CdromMmcUpdateRequired; 247 248 break; 249 } 250 251 } // end of AdditionalSenseCodeQualifier switch 252 253 254 break; 255 256 } // end SCSI_ADSENSE_OPERATOR_REQUEST 257 258 default: 259 { 260 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 261 "DeviceErrorHandlerForMmc: Unit attention %02x/%02x\n", 262 senseBuffer->AdditionalSenseCode, 263 senseBuffer->AdditionalSenseCodeQualifier)); 264 break; 265 } 266 267 } // end of AdditionSenseCode switch 268 break; 269 270 } // end SCSI_SENSE_UNIT_ATTENTION 271 272 case SCSI_SENSE_ILLEGAL_REQUEST: 273 { 274 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_WRITE_PROTECT) 275 { 276 if (DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed) 277 { 278 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 279 "DeviceErrorHandlerForMmc: media was writable, but " 280 "failed request with WRITE_PROTECT error...\n")); 281 } 282 // NOTE - REF #0002 283 // do not update all the capabilities just because 284 // we can't write to the disc. 285 DeviceExtension->DeviceAdditionalData.Mmc.WriteAllowed = FALSE; 286 } 287 break; 288 } // end SCSI_SENSE_ILLEGAL_REQUEST 289 290 } // end of SenseKey switch 291 292 // Check if we failed to set the DVD region key and send appropriate error 293 if (cdb->CDB16.OperationCode == SCSIOP_SEND_KEY) 294 { 295 if (cdb->SEND_KEY.KeyFormat == DvdSetRpcKey) 296 { 297 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_NO_MEDIA_IN_DEVICE) 298 { 299 // media of appropriate region required 300 *Status = STATUS_NO_MEDIA_IN_DEVICE; 301 *Retry = FALSE; 302 } 303 else if ((senseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) && 304 (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_COPY_PROTECTION_FAILURE) && 305 (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT)) 306 { 307 // media of appropriate region required 308 *Status = STATUS_CSS_REGION_MISMATCH; 309 *Retry = FALSE; 310 } 311 else if ((senseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST) && 312 (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INVALID_MEDIA) && 313 (senseBuffer->AdditionalSenseCodeQualifier == SCSI_SENSEQ_INCOMPATIBLE_FORMAT)) 314 { 315 // media of appropriate region required 316 *Status = STATUS_CSS_REGION_MISMATCH; 317 *Retry = FALSE; 318 } 319 } 320 } 321 } // end of SRB_STATUS_AUTOSENSE_VALID 322 323 // On media change, if device speed should be reset to default then 324 // queue a workitem to send the commands to the device. Do this on 325 // media arrival as some device will fail this command if no media 326 // is present. Ignore the fake media change from classpnp driver. 327 if ((mediaChange == TRUE) && (*Status != STATUS_MEDIA_CHANGED)) 328 { 329 if (DeviceExtension->DeviceAdditionalData.RestoreDefaults == TRUE) 330 { 331 NTSTATUS status = STATUS_SUCCESS; 332 WDF_OBJECT_ATTRIBUTES attributes; 333 WDF_WORKITEM_CONFIG workitemConfig; 334 WDFWORKITEM workItem; 335 336 WDF_OBJECT_ATTRIBUTES_INIT(&attributes); 337 attributes.ParentObject = DeviceExtension->Device; 338 339 WDF_WORKITEM_CONFIG_INIT(&workitemConfig, 340 DeviceRestoreDefaultSpeed); 341 342 status = WdfWorkItemCreate(&workitemConfig, 343 &attributes, 344 &workItem); 345 if (!NT_SUCCESS(status)) 346 { 347 return STATUS_SUCCESS; 348 } 349 350 WdfWorkItemEnqueue(workItem); 351 352 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 353 "DeviceErrorHandlerForMmc: Restore device default speed for %p\n", 354 DeviceExtension->DeviceObject)); 355 } 356 } 357 return STATUS_SUCCESS; 358 } 359 360 NTSTATUS 361 DeviceErrorHandlerForHitachiGD2000( 362 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 363 _In_ PSCSI_REQUEST_BLOCK Srb, 364 _Inout_ PNTSTATUS Status, 365 _Inout_ PBOOLEAN Retry 366 ) 367 /*++ 368 369 Routine Description: 370 371 error handler for HITACHI CDR-1750S, CDR-3650/1650S 372 373 This routine checks the type of error. If the error suggests that the 374 drive has spun down and cannot reinitialize itself, send a 375 START_UNIT or READ to the device. This will force the drive to spin 376 up. This drive also loses the AGIDs it has granted when it spins down, 377 which may result in playback failure the first time around. 378 379 Arguments: 380 381 DeviceExtension - the device object. 382 383 Srb - Supplies a pointer to the failing Srb. 384 385 Status - return the final status for this command? 386 387 Retry - return if the command should be retried. 388 389 Return Value: 390 391 None. 392 393 --*/ 394 { 395 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; 396 397 if (!TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) 398 { 399 return STATUS_SUCCESS; //nobody cares about this return value yet. 400 } 401 402 if (((senseBuffer->SenseKey & 0xf) == SCSI_SENSE_HARDWARE_ERROR) && 403 (senseBuffer->AdditionalSenseCode == 0x44)) 404 { 405 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 406 "DeviceErrorHandlerForHitachiGD2000 (%p) => Internal Target " 407 "Failure Detected -- spinning up drive\n", DeviceExtension->Device)); 408 409 // the request should be retried because the device isn't ready 410 *Retry = TRUE; 411 *Status = STATUS_DEVICE_NOT_READY; 412 413 // send a START_STOP unit to spin up the drive 414 // NOTE: this temporarily violates the StartIo serialization 415 // mechanism, but the completion routine on this will NOT 416 // call StartNextPacket(), so it's a temporary disruption 417 // of the serialization only. 418 DeviceSendStartUnit(DeviceExtension->Device); 419 } 420 421 return STATUS_SUCCESS; 422 } 423 424 425 VOID 426 SenseInfoRequestGetInformation( 427 _In_ WDFREQUEST Request, 428 _Out_ UCHAR* MajorFunctionCode, 429 _Out_ ULONG* IoControlCode, 430 _Out_ BOOLEAN* OverrideVerifyVolume, 431 _Out_ ULONGLONG* Total100nsSinceFirstSend 432 ) 433 { 434 PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); 435 436 *MajorFunctionCode = 0; 437 *IoControlCode = 0; 438 *OverrideVerifyVolume = FALSE; 439 *Total100nsSinceFirstSend = 0; 440 441 if (requestContext->OriginalRequest != NULL) 442 { 443 PIO_STACK_LOCATION originalIrpStack = NULL; 444 445 PIRP originalIrp = WdfRequestWdmGetIrp(requestContext->OriginalRequest); 446 447 if (originalIrp != NULL) 448 { 449 originalIrpStack = IoGetCurrentIrpStackLocation(originalIrp); 450 } 451 452 if (originalIrpStack != NULL) 453 { 454 *MajorFunctionCode = originalIrpStack->MajorFunction; 455 456 if (*MajorFunctionCode == IRP_MJ_DEVICE_CONTROL) 457 { 458 *IoControlCode = originalIrpStack->Parameters.DeviceIoControl.IoControlCode; 459 } 460 461 *OverrideVerifyVolume = TEST_FLAG(originalIrpStack->Flags, SL_OVERRIDE_VERIFY_VOLUME); 462 } 463 } 464 465 // Calculate time past since the request was first time sent. 466 if (requestContext->TimeSentDownFirstTime.QuadPart > 0) 467 { 468 LARGE_INTEGER tmp; 469 KeQueryTickCount(&tmp); 470 tmp.QuadPart -= requestContext->TimeSentDownFirstTime.QuadPart; 471 tmp.QuadPart *= KeQueryTimeIncrement(); 472 *Total100nsSinceFirstSend = tmp.QuadPart; 473 } 474 else 475 { 476 // set to -1 if field TimeSentDownFirstTime not set. 477 *Total100nsSinceFirstSend = (ULONGLONG) -1; 478 } 479 480 return; 481 } 482 483 BOOLEAN 484 SenseInfoInterpretByAdditionalSenseCode( 485 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 486 _In_ PSCSI_REQUEST_BLOCK Srb, 487 _In_ UCHAR AdditionalSenseCode, 488 _In_ UCHAR AdditionalSenseCodeQual, 489 _Inout_ NTSTATUS* Status, 490 _Inout_ BOOLEAN* Retry, 491 _Out_ _Deref_out_range_(0,100) ULONG* RetryIntervalInSeconds, 492 _Inout_ PERROR_LOG_CONTEXT LogContext 493 ) 494 /* 495 This function will interpret error based on ASC/ASCQ. 496 497 If the error code is not processed in this function, e.g. return value is TRUE, 498 caller needs to call SenseInfoInterpretBySenseKey() for further interpret. 499 */ 500 { 501 BOOLEAN needFurtherInterpret = TRUE; 502 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 503 504 // set default values for retry fields. 505 *Status = STATUS_IO_DEVICE_ERROR; 506 *Retry = TRUE; 507 *RetryIntervalInSeconds = 0; 508 509 switch (AdditionalSenseCode) 510 { 511 case SCSI_ADSENSE_LUN_NOT_READY: 512 { 513 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 514 "SenseInfoInterpretByAdditionalSenseCode: Lun not ready\n")); 515 516 // 517 // Many non-WHQL certified drives (mostly CD-RW) return 518 // 2/4/0 when they have no media instead of the obvious choice of: 519 // 520 // SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 521 // 522 // These drives should not pass WHQL certification due to this discrepency. 523 // 524 // However, we have to retry on 2/4/0 (Not ready, LUN not ready, no info) 525 // and also 3/2/0 (no seek complete). 526 // 527 // These conditions occur when the shell tries to examine an 528 // injected CD (e.g. for autoplay) before the CD is spun up. 529 // 530 // The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY 531 // (0x01) in order to comply with WHQL standards. 532 // 533 // The default retry timeout of one second is acceptable to balance 534 // these discrepencies. don't modify the status, though.... 535 // 536 537 switch (AdditionalSenseCodeQual) 538 { 539 case SCSI_SENSEQ_OPERATION_IN_PROGRESS: 540 { 541 DEVICE_EVENT_BECOMING_READY notReady = {0}; 542 543 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 544 "SenseInfoInterpretByAdditionalSenseCode: Operation In Progress\n")); 545 546 needFurtherInterpret = FALSE; 547 548 *Retry = TRUE; 549 *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL; 550 *Status = STATUS_DEVICE_NOT_READY; 551 552 notReady.Version = 1; 553 notReady.Reason = 2; 554 notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10; 555 DeviceSendNotification(DeviceExtension, 556 &GUID_IO_DEVICE_BECOMING_READY, 557 sizeof(DEVICE_EVENT_BECOMING_READY), 558 ¬Ready); 559 560 break; 561 } 562 563 case SCSI_SENSEQ_BECOMING_READY: 564 { 565 DEVICE_EVENT_BECOMING_READY notReady = {0}; 566 567 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 568 "SenseInfoInterpretByAdditionalSenseCode: In process of becoming ready\n")); 569 570 needFurtherInterpret = FALSE; 571 572 *Retry = TRUE; 573 *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL; 574 *Status = STATUS_DEVICE_NOT_READY; 575 576 notReady.Version = 1; 577 notReady.Reason = 1; 578 notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10; 579 DeviceSendNotification(DeviceExtension, 580 &GUID_IO_DEVICE_BECOMING_READY, 581 sizeof(DEVICE_EVENT_BECOMING_READY), 582 ¬Ready); 583 584 break; 585 } 586 587 case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: 588 { 589 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 590 "SenseInfoInterpretByAdditionalSenseCode: Long write in progress\n")); 591 592 needFurtherInterpret = FALSE; 593 594 // This has been seen as a transcient failure on some drives 595 *Status = STATUS_DEVICE_NOT_READY; 596 *Retry = TRUE; 597 // Set retry interval to be 0 as the drive can be ready at anytime. 598 *RetryIntervalInSeconds = 0; 599 600 break; 601 } 602 603 case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: 604 { 605 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 606 "SenseInfoInterpretByAdditionalSenseCode: Manual intervention required\n")); 607 608 needFurtherInterpret = FALSE; 609 610 *Status = STATUS_NO_MEDIA_IN_DEVICE; 611 *Retry = FALSE; 612 *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL; 613 614 break; 615 } 616 617 case SCSI_SENSEQ_FORMAT_IN_PROGRESS: 618 { 619 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 620 "SenseInfoInterpretByAdditionalSenseCode: Format in progress\n")); 621 622 needFurtherInterpret = FALSE; 623 624 *Status = STATUS_DEVICE_NOT_READY; 625 *Retry = FALSE; 626 *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL; 627 628 break; 629 } 630 631 case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: 632 case SCSI_SENSEQ_INIT_COMMAND_REQUIRED: 633 default: 634 { 635 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 636 "SenseInfoInterpretByAdditionalSenseCode: Initializing command required\n")); 637 638 needFurtherInterpret = FALSE; 639 640 *Status = STATUS_DEVICE_NOT_READY; 641 *Retry = TRUE; 642 *RetryIntervalInSeconds = 0; 643 644 // This sense code/additional sense code combination may indicate 645 // that the device needs to be started. 646 if (TEST_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT) && 647 !TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY)) 648 { 649 DeviceSendStartUnit(DeviceExtension->Device); 650 } 651 652 break; 653 } 654 } // end switch (AdditionalSenseCodeQual) 655 break; 656 657 } // end case (SCSI_ADSENSE_LUN_NOT_READY) 658 659 case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: 660 { 661 TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, 662 "SenseInfoInterpretByAdditionalSenseCode: No Media in device.\n")); 663 664 needFurtherInterpret = FALSE; 665 666 *Status = STATUS_NO_MEDIA_IN_DEVICE; 667 *Retry = FALSE; 668 669 if (AdditionalSenseCodeQual == 0xCC) 670 { 671 // The IMAPIv1 filter returns this ASCQ value while it is burning CD media, and we want 672 // to preserve this functionality for compatibility reasons. 673 // We want to indicate that the media is not present to most applications; 674 // but RSM has to know that the media is still in the drive (i.e. the drive is not free). 675 DeviceSetMediaChangeStateEx(DeviceExtension, MediaUnavailable, NULL); 676 } 677 else 678 { 679 DeviceSetMediaChangeStateEx(DeviceExtension, MediaNotPresent, NULL); 680 } 681 682 break; 683 } // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 684 685 case SCSI_ADSENSE_INVALID_MEDIA: 686 { 687 switch (AdditionalSenseCodeQual) 688 { 689 690 case SCSI_SENSEQ_UNKNOWN_FORMAT: 691 { 692 needFurtherInterpret = FALSE; 693 694 // Log error only if this is a paging request 695 *Status = STATUS_UNRECOGNIZED_MEDIA; 696 *Retry = FALSE; 697 698 LogContext->LogError = TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING); 699 LogContext->UniqueErrorValue = 256; 700 LogContext->ErrorCode = IO_ERR_BAD_BLOCK; 701 702 break; 703 } 704 705 case SCSI_SENSEQ_INCOMPATIBLE_FORMAT: 706 { 707 needFurtherInterpret = FALSE; 708 709 *Status = STATUS_UNRECOGNIZED_MEDIA; 710 *Retry = FALSE; 711 712 LogContext->LogError = FALSE; 713 714 break; 715 } 716 717 case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED: 718 { 719 needFurtherInterpret = FALSE; 720 721 *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED; 722 *Retry = FALSE; 723 724 LogContext->LogError = FALSE; 725 LogContext->UniqueErrorValue = 256; 726 LogContext->ErrorCode = IO_ERR_BAD_BLOCK; 727 break; 728 } 729 730 default: 731 { 732 needFurtherInterpret = TRUE; 733 break; 734 } 735 } // end case AdditionalSenseCodeQual 736 737 break; 738 } // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 739 740 case SCSI_ADSENSE_NO_SEEK_COMPLETE: 741 { 742 switch (AdditionalSenseCodeQual) 743 { 744 745 case 0x00: 746 { 747 needFurtherInterpret = FALSE; 748 749 *Status = STATUS_DEVICE_DATA_ERROR; 750 *Retry = TRUE; 751 *RetryIntervalInSeconds = 0; 752 LogContext->LogError = TRUE; 753 LogContext->UniqueErrorValue = 256; 754 LogContext->ErrorCode = IO_ERR_BAD_BLOCK; 755 break; 756 } 757 758 default: 759 { 760 needFurtherInterpret = TRUE; 761 break; 762 } 763 } 764 765 break; 766 } // end case SCSI_ADSENSE_NO_SEEK_COMPLETE 767 768 case SCSI_ADSENSE_LUN_COMMUNICATION: 769 { 770 switch (AdditionalSenseCodeQual) 771 { 772 773 case SCSI_SESNEQ_COMM_CRC_ERROR: 774 { 775 needFurtherInterpret = FALSE; 776 777 *Status = STATUS_IO_DEVICE_ERROR; 778 *Retry = TRUE; 779 *RetryIntervalInSeconds = 1; 780 LogContext->LogError = TRUE; 781 LogContext->UniqueErrorValue = 257; 782 LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR; 783 break; 784 } 785 786 default: 787 { 788 needFurtherInterpret = TRUE; 789 break; 790 } 791 } 792 793 break; 794 } // end case SCSI_ADSENSE_LUN_COMMUNICATION 795 796 case SCSI_ADSENSE_ILLEGAL_BLOCK: 797 { 798 needFurtherInterpret = FALSE; 799 800 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 801 "SenseInfoInterpretByAdditionalSenseCode: Illegal block address\n")); 802 *Status = STATUS_NONEXISTENT_SECTOR; 803 *Retry = FALSE; 804 break; 805 } 806 807 case SCSI_ADSENSE_INVALID_LUN: 808 { 809 needFurtherInterpret = FALSE; 810 811 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 812 "SenseInfoInterpretByAdditionalSenseCode: Invalid LUN\n")); 813 *Status = STATUS_NO_SUCH_DEVICE; 814 *Retry = FALSE; 815 break; 816 } 817 818 case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: 819 { 820 needFurtherInterpret = FALSE; 821 822 *Retry = FALSE; 823 824 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 825 "SenseInfoInterpretByAdditionalSenseCode: Key - Copy protection failure\n")); 826 827 switch (AdditionalSenseCodeQual) 828 { 829 case SCSI_SENSEQ_AUTHENTICATION_FAILURE: 830 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 831 "SenseInfoInterpretByAdditionalSenseCode: Authentication failure\n")); 832 *Status = STATUS_CSS_AUTHENTICATION_FAILURE; 833 break; 834 case SCSI_SENSEQ_KEY_NOT_PRESENT: 835 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 836 "SenseInfoInterpretByAdditionalSenseCode: Key not present\n")); 837 *Status = STATUS_CSS_KEY_NOT_PRESENT; 838 break; 839 case SCSI_SENSEQ_KEY_NOT_ESTABLISHED: 840 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 841 "SenseInfoInterpretByAdditionalSenseCode: Key not established\n")); 842 *Status = STATUS_CSS_KEY_NOT_ESTABLISHED; 843 break; 844 case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION: 845 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 846 "SenseInfoInterpretByAdditionalSenseCode: Read of scrambled sector w/o authentication\n")); 847 *Status = STATUS_CSS_SCRAMBLED_SECTOR; 848 break; 849 case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT: 850 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 851 "SenseInfoInterpretByAdditionalSenseCode: Media region does not logical unit region\n")); 852 *Status = STATUS_CSS_REGION_MISMATCH; 853 break; 854 case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR: 855 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 856 "SenseInfoInterpretByAdditionalSenseCode: Region set error -- region may be permanent\n")); 857 *Status = STATUS_CSS_RESETS_EXHAUSTED; 858 break; 859 860 default: 861 *Status = STATUS_COPY_PROTECTION_FAILURE; 862 break; 863 } // end switch of ASCQ for COPY_PROTECTION_FAILURE 864 865 break; 866 } 867 868 case SCSI_ADSENSE_INVALID_CDB: 869 { 870 needFurtherInterpret = FALSE; 871 872 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 873 "SenseInfoInterpretByAdditionalSenseCode: Key - Invalid CDB\n")); 874 875 *Status = STATUS_INVALID_DEVICE_REQUEST; 876 *Retry = FALSE; 877 878 // Note: the retry interval is not typically used. 879 // it is set here only because a ClassErrorHandler 880 // cannot set the RetryIntervalInSeconds, and the error may 881 // require a few commands to be sent to clear whatever 882 // caused this condition (i.e. disk clears the write 883 // cache, requiring at least two commands) 884 // 885 // hopefully, this shortcoming can be changed for blackcomb. 886 *RetryIntervalInSeconds = 3; 887 888 break; 889 } 890 891 case SCSI_ADSENSE_MEDIUM_CHANGED: 892 { 893 needFurtherInterpret = FALSE; 894 *RetryIntervalInSeconds = 0; 895 896 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, 897 "SenseInfoInterpretByAdditionalSenseCode: Media changed\n")); 898 899 DeviceSetMediaChangeStateEx(DeviceExtension, MediaPresent, NULL); 900 901 // special process for Media Change 902 if (IsVolumeMounted(DeviceExtension->DeviceObject)) 903 { 904 // Set bit to indicate that media may have changed and volume needs verification. 905 SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); 906 907 *Status = STATUS_VERIFY_REQUIRED; 908 *Retry = FALSE; 909 } 910 else 911 { 912 *Status = STATUS_IO_DEVICE_ERROR; 913 *Retry = TRUE; 914 } 915 break; 916 } 917 918 case SCSI_ADSENSE_OPERATOR_REQUEST: 919 { 920 switch (AdditionalSenseCodeQual) 921 { 922 case SCSI_SENSEQ_MEDIUM_REMOVAL: 923 { 924 needFurtherInterpret = FALSE; 925 *RetryIntervalInSeconds = 0; 926 927 InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount); 928 929 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 930 "SenseInfoInterpretByAdditionalSenseCode: Ejection request received!\n")); 931 //Send eject notification. 932 DeviceSendNotification(DeviceExtension, 933 &GUID_IO_MEDIA_EJECT_REQUEST, 934 0, 935 NULL); 936 // special process for Media Change 937 if (IsVolumeMounted(DeviceExtension->DeviceObject)) 938 { 939 // Set bit to indicate that media may have changed and volume needs verification. 940 SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); 941 942 *Status = STATUS_VERIFY_REQUIRED; 943 *Retry = FALSE; 944 } 945 else 946 { 947 *Status = STATUS_IO_DEVICE_ERROR; 948 *Retry = TRUE; 949 } 950 break; 951 } 952 default: 953 { 954 needFurtherInterpret = TRUE; 955 break; 956 } 957 } 958 break; 959 } 960 961 case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED: 962 { 963 needFurtherInterpret = FALSE; 964 *RetryIntervalInSeconds = 5; 965 966 InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount); 967 968 // Device information has changed, we need to rescan the 969 // bus for changed information such as the capacity. 970 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 971 "SenseInfoInterpretByAdditionalSenseCode: Device information changed. Invalidate the bus\n")); 972 973 IoInvalidateDeviceRelations(DeviceExtension->LowerPdo, BusRelations); 974 975 // special process for Media Change 976 if (IsVolumeMounted(DeviceExtension->DeviceObject)) 977 { 978 // Set bit to indicate that media may have changed and volume needs verification. 979 SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); 980 981 *Status = STATUS_VERIFY_REQUIRED; 982 *Retry = FALSE; 983 } 984 else 985 { 986 *Status = STATUS_IO_DEVICE_ERROR; 987 *Retry = TRUE; 988 } 989 break; 990 } //end Case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED 991 992 993 case SCSI_ADSENSE_REC_DATA_NOECC: 994 case SCSI_ADSENSE_REC_DATA_ECC: 995 { 996 needFurtherInterpret = FALSE; 997 998 *Status = STATUS_SUCCESS; 999 *Retry = FALSE; 1000 LogContext->LogError = TRUE; 1001 LogContext->UniqueErrorValue = 258; 1002 LogContext->ErrorCode = IO_RECOVERED_VIA_ECC; 1003 1004 if (senseBuffer->IncorrectLength) 1005 { 1006 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 1007 "SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n")); 1008 *Status = STATUS_INVALID_BLOCK_LENGTH ; 1009 } 1010 break; 1011 } 1012 1013 case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED: 1014 { 1015 UCHAR wmiEventData[sizeof(ULONG)+sizeof(UCHAR)] = {0}; 1016 1017 *((PULONG)wmiEventData) = sizeof(UCHAR); 1018 wmiEventData[sizeof(ULONG)] = AdditionalSenseCodeQual; 1019 1020 needFurtherInterpret = FALSE; 1021 1022 // Don't log another eventlog if we have already logged once 1023 // NOTE: this should have been interlocked, but the structure 1024 // was publicly defined to use a BOOLEAN (char). Since 1025 // media only reports these errors once per X minutes, 1026 // the potential race condition is nearly non-existant. 1027 // the worst case is duplicate log entries, so ignore. 1028 1029 *Status = STATUS_SUCCESS; 1030 *Retry = FALSE; 1031 LogContext->UniqueErrorValue = 258; 1032 LogContext->LogError = TRUE; 1033 LogContext->ErrorCode = IO_WRN_FAILURE_PREDICTED; 1034 1035 if (senseBuffer->IncorrectLength) 1036 { 1037 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 1038 "SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n")); 1039 *Status = STATUS_INVALID_BLOCK_LENGTH ; 1040 } 1041 break; 1042 } 1043 1044 case 0x57: 1045 { 1046 // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS 1047 // the Matshita CR-585 returns this for all read commands 1048 // on blank CD-R and CD-RW media, and we need to handle 1049 // this for READ_CD detection ability. 1050 switch (AdditionalSenseCodeQual) 1051 { 1052 case 0x00: 1053 { 1054 needFurtherInterpret = FALSE; 1055 1056 *Status = STATUS_UNRECOGNIZED_MEDIA; 1057 *Retry = FALSE; 1058 break; 1059 } 1060 default: 1061 { 1062 needFurtherInterpret = TRUE; 1063 break; 1064 } 1065 } 1066 break; 1067 } //end case Matshita specific error 0x57 1068 1069 default: 1070 { 1071 needFurtherInterpret = TRUE; 1072 break; 1073 } 1074 } 1075 1076 return needFurtherInterpret; 1077 } 1078 1079 VOID 1080 SenseInfoInterpretBySenseKey( 1081 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1082 _In_ PSENSE_DATA SenseData, 1083 _In_ UCHAR SenseKey, 1084 _Inout_ NTSTATUS* Status, 1085 _Inout_ BOOLEAN* Retry, 1086 _Out_ _Deref_out_range_(0,100) ULONG* RetryIntervalInSeconds, 1087 _Inout_ PERROR_LOG_CONTEXT LogContext 1088 ) 1089 { 1090 // set default values for retry fields. 1091 *Status = STATUS_IO_DEVICE_ERROR; 1092 *Retry = TRUE; 1093 *RetryIntervalInSeconds = 0; 1094 1095 switch (SenseKey) 1096 { 1097 case SCSI_SENSE_NOT_READY: 1098 { 1099 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 1100 "SenseInfoInterpretBySenseKey: Key - Not Ready (bad block)\n")); 1101 1102 *Status = STATUS_DEVICE_NOT_READY; 1103 *Retry = TRUE; 1104 1105 // for unprocessed "not ready" codes, retry the command immediately. 1106 *RetryIntervalInSeconds = 0; 1107 break; 1108 } 1109 1110 case SCSI_SENSE_DATA_PROTECT: 1111 { 1112 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 1113 "SenseInfoInterpretBySenseKey: Key - Media write protected\n")); 1114 *Status = STATUS_MEDIA_WRITE_PROTECTED; 1115 *Retry = FALSE; 1116 break; 1117 } 1118 1119 case SCSI_SENSE_MEDIUM_ERROR: 1120 { 1121 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 1122 "SenseInfoInterpretBySenseKey: Key - Medium Error (bad block)\n")); 1123 1124 *Status = STATUS_DEVICE_DATA_ERROR; 1125 *Retry = FALSE; 1126 LogContext->LogError = TRUE; 1127 LogContext->UniqueErrorValue = 256; 1128 LogContext->ErrorCode = IO_ERR_BAD_BLOCK; 1129 1130 break; 1131 } // end SCSI_SENSE_MEDIUM_ERROR 1132 1133 case SCSI_SENSE_HARDWARE_ERROR: 1134 { 1135 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 1136 "SenseInfoInterpretBySenseKey: Key - Hardware error\n")); 1137 1138 *Status = STATUS_IO_DEVICE_ERROR; 1139 *Retry = TRUE; 1140 LogContext->LogError = TRUE; 1141 LogContext->UniqueErrorValue = 257; 1142 LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR; 1143 1144 break; 1145 } // end SCSI_SENSE_HARDWARE_ERROR 1146 1147 case SCSI_SENSE_ILLEGAL_REQUEST: 1148 { 1149 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 1150 "SenseInfoInterpretBySenseKey: Key - Illegal SCSI request\n")); 1151 *Status = STATUS_INVALID_DEVICE_REQUEST; 1152 *Retry = FALSE; 1153 1154 break; 1155 } // end SCSI_SENSE_ILLEGAL_REQUEST 1156 1157 case SCSI_SENSE_UNIT_ATTENTION: 1158 { 1159 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 1160 "SenseInfoInterpretBySenseKey: Key - Unit Attention\n")); 1161 1162 // A media change may have occured so increment the change 1163 // count for the physical device 1164 InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount); 1165 1166 if (IsVolumeMounted(DeviceExtension->DeviceObject)) 1167 { 1168 // Set bit to indicate that media may have changed 1169 // and volume needs verification. 1170 SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME); 1171 1172 *Status = STATUS_VERIFY_REQUIRED; 1173 *Retry = FALSE; 1174 } 1175 else 1176 { 1177 *Status = STATUS_IO_DEVICE_ERROR; 1178 *Retry = TRUE; 1179 } 1180 1181 break; 1182 1183 } // end SCSI_SENSE_UNIT_ATTENTION 1184 1185 case SCSI_SENSE_ABORTED_COMMAND: 1186 { 1187 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 1188 "SenseInfoInterpretBySenseKey: Command aborted\n")); 1189 *Status = STATUS_IO_DEVICE_ERROR; 1190 *Retry = TRUE; 1191 *RetryIntervalInSeconds = 1; 1192 break; 1193 } // end SCSI_SENSE_ABORTED_COMMAND 1194 1195 case SCSI_SENSE_BLANK_CHECK: 1196 { 1197 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 1198 "SenseInfoInterpretBySenseKey: Media blank check\n")); 1199 *Retry = FALSE; 1200 *Status = STATUS_NO_DATA_DETECTED; 1201 break; 1202 } // end SCSI_SENSE_BLANK_CHECK 1203 1204 case SCSI_SENSE_RECOVERED_ERROR: 1205 { 1206 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 1207 "SenseInfoInterpretBySenseKey: Recovered error\n")); 1208 *Status = STATUS_SUCCESS; 1209 *Retry = FALSE; 1210 LogContext->LogError = TRUE; 1211 LogContext->UniqueErrorValue = 258; 1212 LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR; 1213 1214 if (SenseData->IncorrectLength) 1215 { 1216 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 1217 "SenseInfoInterpretBySenseKey: Incorrect length detected.\n")); 1218 *Status = STATUS_INVALID_BLOCK_LENGTH ; 1219 } 1220 1221 break; 1222 } // end SCSI_SENSE_RECOVERED_ERROR 1223 1224 case SCSI_SENSE_NO_SENSE: 1225 { 1226 // Check other indicators. 1227 if (SenseData->IncorrectLength) 1228 { 1229 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 1230 "SenseInfoInterpretBySenseKey: Incorrect length detected.\n")); 1231 *Status = STATUS_INVALID_BLOCK_LENGTH ; 1232 *Retry = FALSE; 1233 } 1234 else 1235 { 1236 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 1237 "SenseInfoInterpretBySenseKey: No specific sense key\n")); 1238 *Status = STATUS_IO_DEVICE_ERROR; 1239 *Retry = TRUE; 1240 } 1241 1242 break; 1243 } // end SCSI_SENSE_NO_SENSE 1244 1245 default: 1246 { 1247 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 1248 "SenseInfoInterpretBySenseKey: Unrecognized sense code\n")); 1249 *Status = STATUS_IO_DEVICE_ERROR; 1250 *Retry = TRUE; 1251 *RetryIntervalInSeconds = 0; 1252 1253 break; 1254 } 1255 1256 } // end switch (SenseKey) 1257 1258 return; 1259 } 1260 1261 VOID 1262 SenseInfoInterpretBySrbStatus( 1263 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1264 _In_ PSCSI_REQUEST_BLOCK Srb, 1265 _In_ ULONG RetriedCount, 1266 _Inout_ NTSTATUS* Status, 1267 _Inout_ BOOLEAN* Retry, 1268 _Out_ _Deref_out_range_(0,100) ULONG* RetryIntervalInSeconds, 1269 _Inout_ PERROR_LOG_CONTEXT LogContext 1270 ) 1271 { 1272 BOOLEAN incrementErrorCount = FALSE; 1273 1274 // set default values for retry fields. 1275 *Status = STATUS_IO_DEVICE_ERROR; 1276 *Retry = TRUE; 1277 *RetryIntervalInSeconds = 0; 1278 1279 switch (SRB_STATUS(Srb->SrbStatus)) 1280 { 1281 case SRB_STATUS_INVALID_LUN: 1282 case SRB_STATUS_INVALID_TARGET_ID: 1283 case SRB_STATUS_NO_DEVICE: 1284 case SRB_STATUS_NO_HBA: 1285 case SRB_STATUS_INVALID_PATH_ID: 1286 { 1287 *Status = STATUS_NO_SUCH_DEVICE; 1288 *Retry = FALSE; 1289 break; 1290 } 1291 1292 case SRB_STATUS_COMMAND_TIMEOUT: 1293 case SRB_STATUS_TIMEOUT: 1294 { 1295 // Update the error count for the device. 1296 *Status = STATUS_IO_TIMEOUT; 1297 *Retry = TRUE; 1298 *RetryIntervalInSeconds = 0; 1299 incrementErrorCount = TRUE; 1300 break; 1301 } 1302 1303 case SRB_STATUS_ABORTED: 1304 { 1305 // Update the error count for the device. 1306 *Status = STATUS_IO_TIMEOUT; 1307 *Retry = TRUE; 1308 *RetryIntervalInSeconds = 1; 1309 incrementErrorCount = TRUE; 1310 break; 1311 } 1312 1313 case SRB_STATUS_SELECTION_TIMEOUT: 1314 { 1315 *Status = STATUS_DEVICE_NOT_CONNECTED; 1316 *Retry = FALSE; 1317 *RetryIntervalInSeconds = 2; 1318 LogContext->LogError = TRUE; 1319 LogContext->ErrorCode = IO_ERR_NOT_READY; 1320 LogContext->UniqueErrorValue = 260; 1321 break; 1322 } 1323 1324 case SRB_STATUS_DATA_OVERRUN: 1325 { 1326 *Status = STATUS_DATA_OVERRUN; 1327 *Retry = FALSE; 1328 break; 1329 } 1330 1331 case SRB_STATUS_PHASE_SEQUENCE_FAILURE: 1332 { 1333 // Update the error count for the device. 1334 incrementErrorCount = TRUE; 1335 *Status = STATUS_IO_DEVICE_ERROR; 1336 1337 // If there was phase sequence error then limit the number of retries. 1338 *Retry = (RetriedCount <= 1); 1339 1340 break; 1341 } 1342 1343 case SRB_STATUS_REQUEST_FLUSHED: 1344 { 1345 // If the status needs verification bit is set. Then set 1346 // the status to need verification and no retry; otherwise, 1347 // just retry the request. 1348 if (TEST_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME)) 1349 { 1350 *Status = STATUS_VERIFY_REQUIRED; 1351 *Retry = FALSE; 1352 } 1353 else 1354 { 1355 *Status = STATUS_IO_DEVICE_ERROR; 1356 *Retry = TRUE; 1357 } 1358 1359 break; 1360 } 1361 1362 case SRB_STATUS_INVALID_REQUEST: 1363 { 1364 *Status = STATUS_INVALID_DEVICE_REQUEST; 1365 *Retry = FALSE; 1366 break; 1367 } 1368 1369 case SRB_STATUS_UNEXPECTED_BUS_FREE: 1370 case SRB_STATUS_PARITY_ERROR: 1371 // Update the error count for the device and fall through to below 1372 incrementErrorCount = TRUE; 1373 1374 case SRB_STATUS_BUS_RESET: 1375 { 1376 *Status = STATUS_IO_DEVICE_ERROR; 1377 *Retry = TRUE; 1378 break; 1379 } 1380 1381 case SRB_STATUS_ERROR: 1382 { 1383 *Status = STATUS_IO_DEVICE_ERROR; 1384 *Retry = TRUE; 1385 1386 if (Srb->ScsiStatus == 0) 1387 { 1388 // This is some strange return code. Update the error 1389 // count for the device. 1390 incrementErrorCount = TRUE; 1391 } 1392 1393 if (Srb->ScsiStatus == SCSISTAT_BUSY) 1394 { 1395 *Status = STATUS_DEVICE_NOT_READY; 1396 } 1397 1398 break; 1399 } 1400 1401 default: 1402 { 1403 *Status = STATUS_IO_DEVICE_ERROR; 1404 *Retry = TRUE; 1405 LogContext->LogError = TRUE; 1406 LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR; 1407 LogContext->UniqueErrorValue = 259; 1408 LogContext->ErrorUnhandled = TRUE; 1409 break; 1410 } 1411 1412 } //end of (SRB_STATUS(Srb->SrbStatus)) 1413 1414 if (incrementErrorCount) 1415 { 1416 // if any error count occurred, delay the retry of this io by 1417 // at least one second, if caller supports it. 1418 if (*RetryIntervalInSeconds == 0) 1419 { 1420 *RetryIntervalInSeconds = 1; 1421 } 1422 1423 DevicePerfIncrementErrorCount(DeviceExtension); 1424 } 1425 1426 return; 1427 } 1428 1429 VOID 1430 SenseInfoLogError( 1431 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1432 _In_ PSCSI_REQUEST_BLOCK Srb, 1433 _In_ UCHAR MajorFunctionCode, 1434 _In_ ULONG IoControlCode, 1435 _In_ ULONG RetriedCount, 1436 _In_ NTSTATUS* Status, 1437 _In_ BOOLEAN* Retry, 1438 _Inout_ PERROR_LOG_CONTEXT LogContext 1439 ) 1440 { 1441 // Always log the error in our internal log. 1442 // If logError is set, also log the error in the system log. 1443 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 1444 ULONG totalSize = 0; 1445 ULONG senseBufferSize = 0; 1446 IO_ERROR_LOG_PACKET staticErrLogEntry = {0}; 1447 CDROM_ERROR_LOG_DATA staticErrLogData = {0}; 1448 1449 // Calculate the total size of the error log entry. 1450 // add to totalSize in the order that they are used. 1451 // the advantage to calculating all the sizes here is 1452 // that we don't have to do a bunch of extraneous checks 1453 // later on in this code path. 1454 totalSize = sizeof(IO_ERROR_LOG_PACKET) // required 1455 + sizeof(CDROM_ERROR_LOG_DATA); // struct for ease 1456 1457 // also save any available extra sense data, up to the maximum errlog 1458 // packet size . WMI should be used for real-time analysis. 1459 // the event log should only be used for post-mortem debugging. 1460 if (TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) 1461 { 1462 ULONG validSenseBytes; 1463 BOOLEAN validSense; 1464 1465 // make sure we can at least access the AdditionalSenseLength field 1466 validSense = RTL_CONTAINS_FIELD(senseBuffer, 1467 Srb->SenseInfoBufferLength, 1468 AdditionalSenseLength); 1469 if (validSense) 1470 { 1471 // if extra info exists, copy the maximum amount of available 1472 // sense data that is safe into the the errlog. 1473 validSenseBytes = senseBuffer->AdditionalSenseLength 1474 + offsetof(SENSE_DATA, AdditionalSenseLength); 1475 1476 // this is invalid because it causes overflow! 1477 // whoever sent this type of request would cause 1478 // a system crash. 1479 NT_ASSERT(validSenseBytes < MAX_ADDITIONAL_SENSE_BYTES); 1480 1481 // set to save the most sense buffer possible 1482 senseBufferSize = max(validSenseBytes, sizeof(SENSE_DATA)); 1483 senseBufferSize = min(senseBufferSize, Srb->SenseInfoBufferLength); 1484 } 1485 else 1486 { 1487 // it's smaller than required to read the total number of 1488 // valid bytes, so just use the SenseInfoBufferLength field. 1489 senseBufferSize = Srb->SenseInfoBufferLength; 1490 } 1491 1492 // Bump totalSize by the number of extra senseBuffer bytes 1493 // (beyond the default sense buffer within CDROM_ERROR_LOG_DATA). 1494 // Make sure to never allocate more than ERROR_LOG_MAXIMUM_SIZE. 1495 if (senseBufferSize > sizeof(SENSE_DATA)) 1496 { 1497 totalSize += senseBufferSize-sizeof(SENSE_DATA); 1498 if (totalSize > ERROR_LOG_MAXIMUM_SIZE) 1499 { 1500 senseBufferSize -= totalSize-ERROR_LOG_MAXIMUM_SIZE; 1501 totalSize = ERROR_LOG_MAXIMUM_SIZE; 1502 } 1503 } 1504 } 1505 1506 // If we've used up all of our retry attempts, set the final status to 1507 // reflect the appropriate result. 1508 // 1509 // ISSUE: the test below should also check RetriedCount to determine if we will actually retry, 1510 // but there is no easy test because we'd have to consider the original retry count 1511 // for the op; besides, InterpretTransferPacketError sometimes ignores the retry 1512 // decision returned by this function. So just ErrorRetried to be true in the majority case. 1513 // 1514 if (*Retry) 1515 { 1516 staticErrLogEntry.FinalStatus = STATUS_SUCCESS; 1517 staticErrLogData.ErrorRetried = TRUE; 1518 } 1519 else 1520 { 1521 staticErrLogEntry.FinalStatus = *Status; 1522 } 1523 1524 // Don't log generic IO_WARNING_PAGING_FAILURE message if either the 1525 // I/O is retried, or it completed successfully. 1526 if ((LogContext->ErrorCode == IO_WARNING_PAGING_FAILURE) && 1527 (*Retry || NT_SUCCESS(*Status)) ) 1528 { 1529 LogContext->LogError = FALSE; 1530 } 1531 1532 if (TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) 1533 { 1534 staticErrLogData.ErrorPaging = TRUE; 1535 } 1536 1537 staticErrLogData.ErrorUnhandled = LogContext->ErrorUnhandled; 1538 1539 // Calculate the device offset if there is a geometry. 1540 staticErrLogEntry.DeviceOffset.QuadPart = (LONGLONG)LogContext->BadSector; 1541 staticErrLogEntry.DeviceOffset.QuadPart *= (LONGLONG)DeviceExtension->DiskGeometry.BytesPerSector; 1542 1543 if (LogContext->ErrorCode == -1) 1544 { 1545 staticErrLogEntry.ErrorCode = STATUS_IO_DEVICE_ERROR; 1546 } 1547 else 1548 { 1549 staticErrLogEntry.ErrorCode = LogContext->ErrorCode; 1550 } 1551 1552 // The dump data follows the IO_ERROR_LOG_PACKET 1553 staticErrLogEntry.DumpDataSize = (USHORT)totalSize - sizeof(IO_ERROR_LOG_PACKET); 1554 1555 staticErrLogEntry.SequenceNumber = 0; 1556 staticErrLogEntry.MajorFunctionCode = MajorFunctionCode; 1557 staticErrLogEntry.IoControlCode = IoControlCode; 1558 staticErrLogEntry.RetryCount = (UCHAR)RetriedCount; 1559 staticErrLogEntry.UniqueErrorValue = LogContext->UniqueErrorValue; 1560 1561 KeQueryTickCount(&staticErrLogData.TickCount); 1562 staticErrLogData.PortNumber = (ULONG)-1; 1563 1564 // Save the entire contents of the SRB. 1565 staticErrLogData.Srb = *Srb; 1566 1567 // For our private log, save just the default length of the SENSE_DATA. 1568 if (senseBufferSize != 0) 1569 { 1570 RtlCopyMemory(&staticErrLogData.SenseData, senseBuffer, min(senseBufferSize, sizeof(SENSE_DATA))); 1571 } 1572 1573 // Save the error log in our context. 1574 // We only save the default sense buffer length. 1575 { 1576 KIRQL oldIrql; 1577 KeAcquireSpinLock(&DeviceExtension->PrivateFdoData->SpinLock, &oldIrql); 1578 DeviceExtension->PrivateFdoData->ErrorLogs[DeviceExtension->PrivateFdoData->ErrorLogNextIndex] = staticErrLogData; 1579 DeviceExtension->PrivateFdoData->ErrorLogNextIndex++; 1580 DeviceExtension->PrivateFdoData->ErrorLogNextIndex %= NUM_ERROR_LOG_ENTRIES; 1581 KeReleaseSpinLock(&DeviceExtension->PrivateFdoData->SpinLock, oldIrql); 1582 } 1583 1584 // If logError is set, also save this log in the system's error log. 1585 // But make sure we don't log TUR failures over and over 1586 // (e.g. if an external drive was switched off and we're still sending TUR's to it every second). 1587 if (LogContext->LogError) 1588 { 1589 // We do not want to log certain system events repetitively 1590 switch (((PCDB)Srb->Cdb)->CDB10.OperationCode) 1591 { 1592 case SCSIOP_TEST_UNIT_READY: 1593 { 1594 if (DeviceExtension->PrivateFdoData->LoggedTURFailureSinceLastIO) 1595 { 1596 LogContext->LogError = FALSE; 1597 } 1598 else 1599 { 1600 DeviceExtension->PrivateFdoData->LoggedTURFailureSinceLastIO = TRUE; 1601 } 1602 1603 break; 1604 } 1605 1606 case SCSIOP_SYNCHRONIZE_CACHE: 1607 { 1608 if (DeviceExtension->PrivateFdoData->LoggedSYNCFailure) 1609 { 1610 LogContext->LogError = FALSE; 1611 } 1612 else 1613 { 1614 DeviceExtension->PrivateFdoData->LoggedSYNCFailure = TRUE; 1615 } 1616 1617 break; 1618 } 1619 } 1620 1621 // Do not log 5/21/00 LOGICAL BLOCK ADDRESS OUT OF RANGE if the disc is blank, 1622 // it is known to litter the Event Log with repetitive errors 1623 // Do not log this error for READ, as it's known that File System mount process reads different sectors from media. 1624 if (senseBufferSize > RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier) && 1625 senseBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST && 1626 senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_ILLEGAL_BLOCK && 1627 senseBuffer->AdditionalSenseCodeQualifier == 0 && 1628 IS_SCSIOP_READ(((PCDB)Srb->Cdb)->CDB10.OperationCode)) 1629 { 1630 LogContext->LogError = FALSE; 1631 } 1632 } 1633 1634 // Write the error log packet to the system error logging thread. 1635 if (LogContext->LogError) 1636 { 1637 PIO_ERROR_LOG_PACKET errorLogEntry; 1638 PCDROM_ERROR_LOG_DATA errlogData; 1639 1640 errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(DeviceExtension->DeviceObject, (UCHAR)totalSize); 1641 if (errorLogEntry) 1642 { 1643 errlogData = (PCDROM_ERROR_LOG_DATA)errorLogEntry->DumpData; 1644 1645 *errorLogEntry = staticErrLogEntry; 1646 *errlogData = staticErrLogData; 1647 1648 // For the system log, copy as much of the sense buffer as possible. 1649 if (senseBufferSize != 0) 1650 { 1651 RtlCopyMemory(&errlogData->SenseData, senseBuffer, senseBufferSize); 1652 } 1653 1654 // errorLogEntry - It will be freed by the kernel. 1655 IoWriteErrorLogEntry(errorLogEntry); 1656 } 1657 } 1658 1659 return; 1660 } 1661 1662 VOID 1663 SenseInfoInterpretRefineByScsiCommand( 1664 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1665 _In_ PSCSI_REQUEST_BLOCK Srb, 1666 _In_ ULONG RetriedCount, 1667 _In_ LONGLONG Total100nsSinceFirstSend, 1668 _In_ BOOLEAN OverrideVerifyVolume, 1669 _Inout_ BOOLEAN* Retry, 1670 _Inout_ NTSTATUS* Status, 1671 _Inout_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) 1672 LONGLONG* RetryIntervalIn100ns 1673 ) 1674 /*++ 1675 1676 Routine Description: 1677 1678 Based on SCSI command, modify the interpretion result. 1679 1680 Arguments: 1681 1682 DeviceExtension - device extension. 1683 Srb - Supplies the scsi request block which failed. 1684 RetriedCount - retried count. 1685 Total100nsUnitsSinceFirstSend - time spent after the request was sent down first time. 1686 OverrideVerifyVolume - should override verify volume request. 1687 1688 Return Value: 1689 1690 Retry - the reques should be retried or not. 1691 Status - Returns the status for the request. 1692 RetryInterval - waiting time (in 100ns) before the request should be retried. 1693 Zero indicates the request should be immediately retried. 1694 1695 --*/ 1696 { 1697 UCHAR const opCode = Srb->Cdb[0]; 1698 CDB const* cdb = (CDB const*)(Srb->Cdb); 1699 PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; 1700 1701 if (opCode == SCSIOP_MEDIUM_REMOVAL) 1702 { 1703 if (( cdb->AsByte[1] == 0) && 1704 ( cdb->AsByte[2] == 0) && 1705 ( cdb->AsByte[3] == 0) && 1706 ((cdb->AsByte[4] & 0xFC) == 0) 1707 ) 1708 { 1709 // byte[4] == 0x3 or byte[4] == 0x1 == UNLOCK OF MEDIA 1710 if ((cdb->AsByte[4] & 0x01) == 0) 1711 { 1712 if (RetriedCount < TOTAL_COUNT_RETRY_DEFAULT) 1713 { 1714 // keep retrying unlock operation for several times 1715 *Retry = TRUE; 1716 } 1717 } 1718 else // LOCK REQUEST 1719 { 1720 // do not retry LOCK requests more than once (per CLASSPNP code) 1721 if (RetriedCount > TOTAL_COUNT_RETRY_LOCK_MEDIA) 1722 { 1723 *Retry = FALSE; 1724 } 1725 } 1726 } 1727 1728 // want a minimum time to retry of 2 seconds 1729 if ((*Status == STATUS_DEVICE_NOT_READY) && 1730 (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) 1731 { 1732 *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2)); 1733 } 1734 else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) 1735 { 1736 *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2)); 1737 } 1738 } 1739 else if ((opCode == SCSIOP_MODE_SENSE) || (opCode == SCSIOP_MODE_SENSE10)) 1740 { 1741 // want a minimum time to retry of 2 seconds 1742 if ((*Status == STATUS_DEVICE_NOT_READY) && 1743 (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) 1744 { 1745 *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2)); 1746 } 1747 else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT) 1748 { 1749 *RetryIntervalIn100ns = max(*RetryIntervalIn100ns, SECONDS_TO_100NS_UNITS(2)); 1750 } 1751 1752 // Want to ignore a STATUS_VERIFY_REQUIRED error because it either 1753 // doesn't make sense or is required to satisfy the VERIFY. 1754 if (*Status == STATUS_VERIFY_REQUIRED) 1755 { 1756 *Retry = TRUE; 1757 } 1758 else if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) 1759 { 1760 /* 1761 * This is a HACK. 1762 * Atapi returns SRB_STATUS_DATA_OVERRUN when it really means 1763 * underrun (i.e. success, and the buffer is longer than needed). 1764 * So treat this as a success. 1765 * When the caller of this function sees that the status was changed to success, 1766 * it will add the transferred length to the original irp. 1767 */ 1768 *Status = STATUS_SUCCESS; 1769 *Retry = FALSE; 1770 } 1771 1772 // limit the count of retries 1773 if (RetriedCount > TOTAL_COUNT_RETRY_MODESENSE) 1774 { 1775 *Retry = FALSE; 1776 } 1777 } 1778 else if ((opCode == SCSIOP_READ_CAPACITY) || (opCode == SCSIOP_READ_CAPACITY16)) 1779 { 1780 // Want to ignore a STATUS_VERIFY_REQUIRED error because it either 1781 // doesn't make sense or is required to satisfy the VERIFY. 1782 if (*Status == STATUS_VERIFY_REQUIRED) 1783 { 1784 *Retry = TRUE; 1785 } 1786 1787 if (RetriedCount > TOTAL_COUNT_RETRY_READ_CAPACITY) 1788 { 1789 *Retry = FALSE; 1790 } 1791 } 1792 else if ((opCode == SCSIOP_RESERVE_UNIT) || (opCode == SCSIOP_RELEASE_UNIT)) 1793 { 1794 // The RESERVE(6) / RELEASE(6) commands are optional. 1795 // So if they aren't supported, try the 10-byte equivalents 1796 if (*Status == STATUS_INVALID_DEVICE_REQUEST) 1797 { 1798 PCDB tempCdb = (PCDB)Srb->Cdb; 1799 1800 Srb->CdbLength = 10; 1801 tempCdb->CDB10.OperationCode = (tempCdb->CDB6GENERIC.OperationCode == SCSIOP_RESERVE_UNIT) 1802 ? SCSIOP_RESERVE_UNIT10 1803 : SCSIOP_RELEASE_UNIT10; 1804 1805 SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_RESERVE6); 1806 *Retry = TRUE; 1807 } 1808 } 1809 else if (IS_SCSIOP_READWRITE(opCode)) 1810 { 1811 // Retry if still verifying a (possibly) reloaded disk/cdrom. 1812 if (OverrideVerifyVolume && (*Status == STATUS_VERIFY_REQUIRED)) 1813 { 1814 *Status = STATUS_IO_DEVICE_ERROR; 1815 *Retry = TRUE; 1816 } 1817 1818 // Special case for streaming READ/WRITE commands 1819 if (((opCode == SCSIOP_READ12) && (cdb->READ12.Streaming == 1)) || 1820 ((opCode == SCSIOP_WRITE12) && (cdb->WRITE12.Streaming == 1))) 1821 { 1822 // We've got a failure while performing a streaming operation and now need to guess if 1823 // it's likely to be a permanent error because the drive does not support streaming at all 1824 // (in which case we're going to fall back to normal reads/writes), or a transient error 1825 // (in which case we quickly fail the request but contrinue to use streaming). 1826 // 1827 // We analyze the sense information to make that decision. Bus resets and device timeouts 1828 // are treated as permanent errors, because some non-compliant devices may even hang when 1829 // they get a command that they do not expect. 1830 1831 BOOLEAN disableStreaming = FALSE; 1832 1833 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_TIMEOUT || 1834 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_COMMAND_TIMEOUT || 1835 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT || 1836 SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_BUS_RESET) 1837 { 1838 disableStreaming = TRUE; 1839 } 1840 else if ((senseBuffer->SenseKey &0xf) == SCSI_SENSE_UNIT_ATTENTION) 1841 { 1842 if (senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_BUS_RESET || 1843 senseBuffer->AdditionalSenseCode == SCSI_ADSENSE_INSUFFICIENT_TIME_FOR_OPERATION) 1844 { 1845 disableStreaming = TRUE; 1846 } 1847 } 1848 else if ((senseBuffer->SenseKey &0xf) == SCSI_SENSE_ILLEGAL_REQUEST) 1849 { 1850 // LBA Out of Range is an exception, as it's more likely to be caused by 1851 // upper layers attempting to read/write a wrong LBA. 1852 if (senseBuffer->AdditionalSenseCode != SCSI_ADSENSE_ILLEGAL_BLOCK) 1853 { 1854 disableStreaming = TRUE; 1855 } 1856 } 1857 1858 if (disableStreaming) 1859 { 1860 // if the failure looks permanent, we disable streaming for all future reads/writes 1861 // and retry the command immediately 1862 SET_FLAG(DeviceExtension->PrivateFdoData->HackFlags, FDO_HACK_NO_STREAMING); 1863 *Retry = TRUE; 1864 *RetryIntervalIn100ns = 0; 1865 } 1866 else 1867 { 1868 // if the failure looks transient, we simply fail the current request without retries 1869 // to minimize the time of processing 1870 *Retry = FALSE; 1871 } 1872 } 1873 1874 // Special-case handling of READ/WRITE commands. These commands now have a 120 second timeout, 1875 // but the preferred behavior (and that taken by many drives) is to immediately report 2/4/x 1876 // on OPC and similar commands. Thus, retries must occur for at least 160 seconds 1877 // (120 seconds + four 10 second retries) as a conservative guess. 1878 // Note: 160s retry time is also a result of discussion with OEMs for case of 2/4/7 and 2/4/8. 1879 if (*Retry) 1880 { 1881 if ((Total100nsSinceFirstSend < 0) || 1882 (((senseBuffer->SenseKey &0xf) == SCSI_SENSE_HARDWARE_ERROR) && (senseBuffer->AdditionalSenseCode == 0x09))) 1883 { 1884 // time information is not valid. use default retry count. 1885 // or if it's SERVO FAILURE, use retry count instead of 160s retry. 1886 *Retry = (RetriedCount <= TOTAL_COUNT_RETRY_DEFAULT); 1887 } 1888 else if (Total100nsSinceFirstSend > SECONDS_TO_100NS_UNITS(TOTAL_SECONDS_RETRY_TIME_WRITE)) 1889 { 1890 *Retry = FALSE; 1891 } 1892 1893 // How long should we request a delay for during writing? This depends entirely on 1894 // the current write speed of the drive. If we request retries too quickly, 1895 // we can overload the processor on the drive (resulting in garbage being written), 1896 // but too slowly results in lesser performance. 1897 // 1898 *RetryIntervalIn100ns = DeviceExtension->DeviceAdditionalData.ReadWriteRetryDelay100nsUnits; 1899 1900 } // end retry for 160 seconds modification 1901 } 1902 else if (opCode == SCSIOP_GET_PERFORMANCE) 1903 { 1904 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) 1905 { 1906 // This is a HACK. 1907 // Atapi returns SRB_STATUS_DATA_OVERRUN when it really means 1908 // underrun (i.e. success, and the buffer is longer than needed). 1909 // So treat this as a success. 1910 // When the caller of this function sees that the status was changed to success, 1911 // it will add the transferred length to the original irp. 1912 *Status = STATUS_SUCCESS; 1913 *Retry = FALSE; 1914 } 1915 1916 if ((Srb->SenseInfoBufferLength < RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA,AdditionalSenseCodeQualifier)) || 1917 !TEST_FLAG(Srb->SrbStatus, SRB_STATUS_AUTOSENSE_VALID)) 1918 { 1919 // If get configuration command is failing and if the request type is TYPE ONE 1920 // then most likely the device does not support this request type. Set the 1921 // flag so that the TYPE ONE requests will be tried as TYPE ALL requets. 1922 if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) && 1923 (SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_DATA_OVERRUN) && 1924 (((PCDB)Srb->Cdb)->GET_CONFIGURATION.RequestType == SCSI_GET_CONFIGURATION_REQUEST_TYPE_ONE)) 1925 { 1926 1927 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 1928 "TYPE ONE GetConfiguration failed. Set hack flag and retry.\n")); 1929 SET_FLAG(DeviceExtension->DeviceAdditionalData.HackFlags, CDROM_HACK_BAD_TYPE_ONE_GET_CONFIG); 1930 *Retry = TRUE; 1931 } 1932 } 1933 1934 // limit retries to GET_PERFORMANCE commands to default retry count 1935 if (RetriedCount > TOTAL_COUNT_RETRY_DEFAULT) 1936 { 1937 *Retry = FALSE; 1938 } 1939 } 1940 else // default handler -- checks for retry count only. 1941 { 1942 if (RetriedCount > TOTAL_COUNT_RETRY_DEFAULT) 1943 { 1944 *Retry = FALSE; 1945 } 1946 } 1947 1948 return; 1949 } 1950 1951 1952 VOID 1953 SenseInfoInterpretRefineByIoControl( 1954 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 1955 _In_ ULONG IoControlCode, 1956 _In_ BOOLEAN OverrideVerifyVolume, 1957 _Inout_ BOOLEAN* Retry, 1958 _Inout_ NTSTATUS* Status 1959 ) 1960 /*++ 1961 1962 Routine Description: 1963 1964 Based on IOCTL code, modify the interpretion result. 1965 1966 Arguments: 1967 1968 Device - Supplies the device object associated with this request. 1969 OriginalRequest - the irp that error occurs on. 1970 Srb - Supplies the scsi request block which failed. 1971 MajorFunctionCode - Supplies the function code to be used for logging. 1972 IoDeviceCode - Supplies the device code to be used for logging. 1973 PreviousRetryCount - retried count. 1974 RequestHistory_DoNotUse - the history list 1975 1976 Return Value: 1977 1978 BOOLEAN TRUE: Drivers should retry this request. 1979 FALSE: Drivers should not retry this request. 1980 Status - Returns the status for the request. 1981 RetryInterval - Number of seconds before the request should be retried. 1982 Zero indicates the request should be immediately retried. 1983 1984 --*/ 1985 { 1986 PAGED_CODE(); 1987 1988 if ((IoControlCode == IOCTL_CDROM_GET_LAST_SESSION) || 1989 (IoControlCode == IOCTL_CDROM_READ_TOC) || 1990 (IoControlCode == IOCTL_CDROM_READ_TOC_EX) || 1991 (IoControlCode == IOCTL_CDROM_GET_CONFIGURATION)|| 1992 (IoControlCode == IOCTL_CDROM_GET_VOLUME)) 1993 { 1994 if (*Status == STATUS_DATA_OVERRUN) 1995 { 1996 *Status = STATUS_SUCCESS; 1997 *Retry = FALSE; 1998 } 1999 } 2000 2001 if (IoControlCode == IOCTL_CDROM_READ_Q_CHANNEL) 2002 { 2003 PLAY_ACTIVE(DeviceExtension) = FALSE; 2004 } 2005 2006 // If the status is verified required and the this request 2007 // should bypass verify required then retry the request. 2008 if (OverrideVerifyVolume && (*Status == STATUS_VERIFY_REQUIRED)) 2009 { 2010 // note: status gets overwritten here 2011 *Status = STATUS_IO_DEVICE_ERROR; 2012 *Retry = TRUE; 2013 2014 if ((IoControlCode == IOCTL_CDROM_CHECK_VERIFY) || 2015 (IoControlCode == IOCTL_STORAGE_CHECK_VERIFY) || 2016 (IoControlCode == IOCTL_STORAGE_CHECK_VERIFY2) || 2017 (IoControlCode == IOCTL_DISK_CHECK_VERIFY) 2018 ) 2019 { 2020 // Update the geometry information, as the media could have changed. 2021 (VOID) MediaReadCapacity(DeviceExtension->Device); 2022 } // end of ioctls to update capacity 2023 } 2024 2025 if (!NT_SUCCESS(*Status) && (IoControlCode == IOCTL_CDROM_SET_SPEED)) 2026 { 2027 // If set speed request fails then we should disable the restore speed option. 2028 // Otherwise we will try to restore to default speed on next media change, 2029 // if requested by the caller. 2030 DeviceExtension->DeviceAdditionalData.RestoreDefaults = FALSE; 2031 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_IOCTL, "Disable restore default\n")); 2032 } 2033 2034 return; 2035 } 2036 2037 BOOLEAN 2038 SenseInfoInterpret( 2039 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 2040 _In_ WDFREQUEST Request, 2041 _In_ PSCSI_REQUEST_BLOCK Srb, 2042 _In_ ULONG RetriedCount, 2043 _Out_ NTSTATUS* Status, 2044 _Out_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) 2045 LONGLONG* RetryIntervalIn100ns 2046 ) 2047 /*++ 2048 2049 SenseInfoInterpret() 2050 2051 Routine Description: 2052 2053 This routine interprets the data returned from the SCSI request sense. 2054 It determines the status to return in the IRP 2055 and whether this request can be retried. 2056 2057 Arguments: 2058 2059 Device - Supplies the device object associated with this request. 2060 Srb - Supplies the scsi request block which failed. 2061 MajorFunctionCode - Supplies the function code to be used for logging. 2062 IoDeviceCode - Supplies the device code to be used for logging. 2063 2064 Return Value: 2065 2066 BOOLEAN TRUE: Drivers should retry this request. 2067 FALSE: Drivers should not retry this request. 2068 Status - Returns the status for the request. 2069 RetryInterval - Number of seconds before the request should be retried. 2070 Zero indicates the request should be immediately retried. 2071 2072 --*/ 2073 { 2074 ULONG retryIntervalInSeconds = 0; 2075 BOOLEAN retry = TRUE; 2076 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; 2077 ULONG readSector = 0; 2078 ERROR_LOG_CONTEXT logContext; 2079 2080 UCHAR majorFunctionCode = 0; 2081 ULONG ioControlCode = 0; 2082 BOOLEAN overrideVerifyVolume = FALSE; 2083 ULONGLONG total100nsSinceFirstSend = 0; 2084 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; 2085 2086 // 2087 *Status = STATUS_IO_DEVICE_ERROR; 2088 2089 RtlZeroMemory(&logContext, sizeof(ERROR_LOG_CONTEXT)); 2090 logContext.ErrorCode = -1; 2091 2092 // Get Original Request related information 2093 SenseInfoRequestGetInformation(Request, 2094 &majorFunctionCode, 2095 &ioControlCode, 2096 &overrideVerifyVolume, 2097 &total100nsSinceFirstSend); 2098 2099 if(TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING)) 2100 { 2101 // Log anything remotely incorrect about paging i/o 2102 logContext.LogError = TRUE; 2103 logContext.UniqueErrorValue = 301; 2104 logContext.ErrorCode = IO_WARNING_PAGING_FAILURE; 2105 } 2106 2107 // must handle the SRB_STATUS_INTERNAL_ERROR case first, 2108 // as it has all the flags set. 2109 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_INTERNAL_ERROR) 2110 { 2111 TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 2112 "SenseInfoInterpret: Internal Error code is %x\n", 2113 Srb->InternalStatus)); 2114 2115 retry = FALSE; 2116 *Status = Srb->InternalStatus; 2117 } 2118 else if (Srb->ScsiStatus == SCSISTAT_RESERVATION_CONFLICT) 2119 { 2120 retry = FALSE; 2121 *Status = STATUS_DEVICE_BUSY; 2122 logContext.LogError = FALSE; 2123 } 2124 else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && 2125 (Srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength))) 2126 { 2127 UCHAR senseKey = (UCHAR)(senseBuffer->SenseKey & 0x0f); 2128 UCHAR additionalSenseCode = 0; 2129 UCHAR additionalSenseCodeQual = 0; 2130 2131 // Zero the additional sense code and additional sense code qualifier 2132 // if they were not returned by the device. 2133 readSector = senseBuffer->AdditionalSenseLength + offsetof(SENSE_DATA, AdditionalSenseLength); 2134 if (readSector > Srb->SenseInfoBufferLength) 2135 { 2136 readSector = Srb->SenseInfoBufferLength; 2137 } 2138 2139 additionalSenseCode = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) ? 2140 senseBuffer->AdditionalSenseCode : 0; 2141 additionalSenseCodeQual = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) ? 2142 senseBuffer->AdditionalSenseCodeQualifier : 0; 2143 2144 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 2145 "SCSI Error - \n" 2146 "\tcdb: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n" 2147 "\tsrb status: %X; sense: %02X/%02X/%02X; Retried count: %d\n\n", 2148 Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3], Srb->Cdb[4], Srb->Cdb[5], 2149 Srb->Cdb[6], Srb->Cdb[7], Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11], 2150 Srb->Cdb[12], Srb->Cdb[13], Srb->Cdb[14], Srb->Cdb[15], 2151 SRB_STATUS(Srb->SrbStatus), 2152 senseKey, 2153 additionalSenseCode, 2154 additionalSenseCodeQual, 2155 RetriedCount)); 2156 2157 if (senseKey == SCSI_SENSE_UNIT_ATTENTION) 2158 { 2159 ULONG mediaChangeCount; 2160 2161 // A media change may have occured so increment the change count for the physical device 2162 mediaChangeCount = InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount); 2163 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN, 2164 "SenseInfoInterpret: Media change count for device %d incremented to %#lx\n", 2165 DeviceExtension->DeviceNumber, mediaChangeCount)); 2166 } 2167 2168 if ((zpoddInfo != NULL) && 2169 (((PCDB)Srb->Cdb)->CDB6GENERIC.OperationCode == SCSIOP_TEST_UNIT_READY)) 2170 { 2171 // This sense code is in response to the Test Unit Ready sent during delayed power down 2172 // request. Copy the sense data into the zpoddInfo structure for later processing. 2173 zpoddInfo->SenseKey = senseKey; 2174 zpoddInfo->AdditionalSenseCode = additionalSenseCode; 2175 zpoddInfo->AdditionalSenseCodeQualifier = additionalSenseCodeQual; 2176 } 2177 2178 // Interpret error by specific ASC & ASCQ first, 2179 // If the error is not handled, interpret using f 2180 { 2181 BOOLEAN notHandled = FALSE; 2182 notHandled = SenseInfoInterpretByAdditionalSenseCode(DeviceExtension, 2183 Srb, 2184 additionalSenseCode, 2185 additionalSenseCodeQual, 2186 Status, 2187 &retry, 2188 &retryIntervalInSeconds, 2189 &logContext); 2190 2191 if (notHandled) 2192 { 2193 SenseInfoInterpretBySenseKey(DeviceExtension, 2194 senseBuffer, 2195 senseKey, 2196 Status, 2197 &retry, 2198 &retryIntervalInSeconds, 2199 &logContext); 2200 } 2201 } 2202 2203 // Try to determine the bad sector from the inquiry data. 2204 if ((IS_SCSIOP_READWRITE(((PCDB)Srb->Cdb)->CDB10.OperationCode)) || 2205 (((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY) || 2206 (((PCDB)Srb->Cdb)->CDB10.OperationCode == SCSIOP_VERIFY16)) 2207 { 2208 ULONG index; 2209 readSector = 0; 2210 2211 for (index = 0; index < 4; index++) 2212 { 2213 logContext.BadSector = (logContext.BadSector << 8) | senseBuffer->Information[index]; 2214 } 2215 2216 for (index = 0; index < 4; index++) 2217 { 2218 readSector = (readSector << 8) | Srb->Cdb[index+2]; 2219 } 2220 2221 index = (((PCDB)Srb->Cdb)->CDB10.TransferBlocksMsb << 8) | 2222 ((PCDB)Srb->Cdb)->CDB10.TransferBlocksLsb; 2223 2224 // Make sure the bad sector is within the read sectors. 2225 if (!(logContext.BadSector >= readSector && logContext.BadSector < (readSector + index))) 2226 { 2227 logContext.BadSector = readSector; 2228 } 2229 } 2230 } 2231 else 2232 { 2233 // Request sense buffer not valid. No sense information 2234 // to pinpoint the error. Return general request fail. 2235 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 2236 "SCSI Error - \n" 2237 "\tcdb: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n" 2238 "\tsrb status: %X; sense info not valid; Retried count: %d\n\n", 2239 Srb->Cdb[0], Srb->Cdb[1], Srb->Cdb[2], Srb->Cdb[3], Srb->Cdb[4], Srb->Cdb[5], 2240 Srb->Cdb[6], Srb->Cdb[7], Srb->Cdb[8], Srb->Cdb[9], Srb->Cdb[10], Srb->Cdb[11], 2241 Srb->Cdb[12], Srb->Cdb[13], Srb->Cdb[14], Srb->Cdb[15], 2242 SRB_STATUS(Srb->SrbStatus), 2243 RetriedCount)); 2244 2245 SenseInfoInterpretBySrbStatus(DeviceExtension, 2246 Srb, 2247 RetriedCount, 2248 Status, 2249 &retry, 2250 &retryIntervalInSeconds, 2251 &logContext); 2252 } 2253 2254 // all functions using unit - seconds for retry Interval already be called. 2255 *RetryIntervalIn100ns = SECONDS_TO_100NS_UNITS(retryIntervalInSeconds); 2256 2257 // call the device specific error handler if it has one. 2258 // DeviceErrorHandlerForMmmc() for all MMC devices 2259 // or DeviceErrorHandlerForHitachiGD2000() for HITACHI GD-2000, HITACHI DVD-ROM GD-2000 2260 if (DeviceExtension->DeviceAdditionalData.ErrorHandler) 2261 { 2262 DeviceExtension->DeviceAdditionalData.ErrorHandler(DeviceExtension, Srb, Status, &retry); 2263 } 2264 2265 // Refine retry based on SCSI command 2266 SenseInfoInterpretRefineByScsiCommand(DeviceExtension, 2267 Srb, 2268 RetriedCount, 2269 total100nsSinceFirstSend, 2270 overrideVerifyVolume, 2271 &retry, 2272 Status, 2273 RetryIntervalIn100ns); 2274 2275 // Refine retry based on IOCTL code. 2276 if (majorFunctionCode == IRP_MJ_DEVICE_CONTROL) 2277 { 2278 SenseInfoInterpretRefineByIoControl(DeviceExtension, 2279 ioControlCode, 2280 overrideVerifyVolume, 2281 &retry, 2282 Status); 2283 } 2284 2285 // LOG the error: 2286 // Always log the error in our internal log. 2287 // If logError is set, also log the error in the system log. 2288 SenseInfoLogError(DeviceExtension, 2289 Srb, 2290 majorFunctionCode, 2291 ioControlCode, 2292 RetriedCount, 2293 Status, 2294 &retry, 2295 &logContext); 2296 2297 // all process about the error done. check if the irp was cancelled. 2298 if ((!NT_SUCCESS(*Status)) && retry) 2299 { 2300 PCDROM_REQUEST_CONTEXT requestContext = RequestGetContext(Request); 2301 2302 if ((requestContext->OriginalRequest != NULL) && 2303 WdfRequestIsCanceled(requestContext->OriginalRequest) 2304 ) 2305 { 2306 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 2307 "Request %p was cancelled when it would have been retried\n", 2308 requestContext->OriginalRequest)); 2309 2310 *Status = STATUS_CANCELLED; 2311 retry = FALSE; 2312 *RetryIntervalIn100ns = 0; 2313 } 2314 } 2315 2316 // now, all decisions are made. display trace information. 2317 if (retry) 2318 { 2319 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 2320 "Command shall be retried in %2I64d.%03I64d seconds\n", 2321 (*RetryIntervalIn100ns / UNIT_100NS_PER_SECOND), 2322 (*RetryIntervalIn100ns / 10000) % 1000 2323 )); 2324 } 2325 else 2326 { 2327 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 2328 "Will not retry; Sense/ASC/ASCQ of %02x/%02x/%02x\n", 2329 senseBuffer->SenseKey, 2330 senseBuffer->AdditionalSenseCode, 2331 senseBuffer->AdditionalSenseCodeQualifier 2332 )); 2333 } 2334 2335 return retry; 2336 2337 } // end SenseInfoInterpret() 2338 2339 2340 BOOLEAN 2341 SenseInfoInterpretForZPODD( 2342 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 2343 _In_ PSCSI_REQUEST_BLOCK Srb, 2344 _Out_ NTSTATUS* Status, 2345 _Out_ _Out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) 2346 LONGLONG* RetryIntervalIn100ns 2347 ) 2348 /*++ 2349 2350 SenseInfoInterpretForZPODD() 2351 2352 Routine Description: 2353 2354 This routine interprets the data returned from the SCSI request sense. 2355 It determines the status to return in the IRP 2356 and whether this request can be retried. 2357 2358 Arguments: 2359 2360 Device - Supplies the device object associated with this request. 2361 Srb - Supplies the scsi request block which failed. 2362 2363 Return Value: 2364 2365 BOOLEAN TRUE: Drivers should retry this request. 2366 FALSE: Drivers should not retry this request. 2367 Status - Returns the status for the request. 2368 RetryInterval - Number of seconds before the request should be retried. 2369 Zero indicates the request should be immediately retried. 2370 2371 --*/ 2372 { 2373 BOOLEAN retry = FALSE; 2374 PSENSE_DATA senseBuffer = Srb->SenseInfoBuffer; 2375 ULONG readSector = 0; 2376 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; 2377 2378 *Status = STATUS_IO_DEVICE_ERROR; 2379 *RetryIntervalIn100ns = 0; 2380 2381 if (zpoddInfo->RetryFirstCommand != FALSE) 2382 { 2383 // The first command to the logical unit after power resumed will be terminated 2384 // with CHECK CONDITION Status, 6/29/00 POWER ON, RESET, OR BUS DEVICE RESET OCCURRED 2385 2386 // We have observed some devices return a different sense code, and thus as long as 2387 // the first command after power resume fails, we just retry one more time. 2388 zpoddInfo->RetryFirstCommand = FALSE; 2389 2390 retry = TRUE; 2391 } 2392 else if ((Srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && 2393 (Srb->SenseInfoBufferLength >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseLength))) 2394 { 2395 UCHAR senseKey = (UCHAR)(senseBuffer->SenseKey & 0x0f); 2396 UCHAR additionalSenseCode = 0; 2397 UCHAR additionalSenseCodeQual = 0; 2398 2399 // Zero the additional sense code and additional sense code qualifier 2400 // if they were not returned by the device. 2401 readSector = senseBuffer->AdditionalSenseLength + offsetof(SENSE_DATA, AdditionalSenseLength); 2402 if (readSector > Srb->SenseInfoBufferLength) 2403 { 2404 readSector = Srb->SenseInfoBufferLength; 2405 } 2406 2407 additionalSenseCode = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCode)) ? 2408 senseBuffer->AdditionalSenseCode : 0; 2409 additionalSenseCodeQual = (readSector >= RTL_SIZEOF_THROUGH_FIELD(SENSE_DATA, AdditionalSenseCodeQualifier)) ? 2410 senseBuffer->AdditionalSenseCodeQualifier : 0; 2411 2412 // If sense code is 2/4/1, device is becoming ready from ZPODD mode. According to Mt Fuji, device 2413 // could take up to 800msec to be fully operational. 2414 if ((senseKey == SCSI_SENSE_NOT_READY) && 2415 (additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY) && 2416 (additionalSenseCodeQual == SCSI_SENSEQ_BECOMING_READY)) 2417 { 2418 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 2419 "SenseInfoInterpretForZPODD: In process of becoming ready\n")); 2420 2421 zpoddInfo->BecomingReadyRetryCount--; 2422 2423 if (zpoddInfo->BecomingReadyRetryCount > 0) 2424 { 2425 DEVICE_EVENT_BECOMING_READY notReady = {0}; 2426 2427 retry = TRUE; 2428 *Status = STATUS_DEVICE_NOT_READY; 2429 *RetryIntervalIn100ns = BECOMING_READY_RETRY_INTERNVAL_IN_100NS; 2430 2431 notReady.Version = 1; 2432 notReady.Reason = 1; 2433 notReady.Estimated100msToReady = (ULONG) *RetryIntervalIn100ns / (1000 * 1000); 2434 DeviceSendNotification(DeviceExtension, 2435 &GUID_IO_DEVICE_BECOMING_READY, 2436 sizeof(DEVICE_EVENT_BECOMING_READY), 2437 ¬Ready); 2438 } 2439 } 2440 } 2441 2442 // now, all decisions are made. display trace information. 2443 if (retry) 2444 { 2445 TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 2446 "Command shall be retried in %2I64d.%03I64d seconds\n", 2447 (*RetryIntervalIn100ns / UNIT_100NS_PER_SECOND), 2448 (*RetryIntervalIn100ns / 10000) % 1000 2449 )); 2450 } 2451 else 2452 { 2453 TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 2454 "Will not retry; Sense/ASC/ASCQ of %02x/%02x/%02x\n", 2455 senseBuffer->SenseKey, 2456 senseBuffer->AdditionalSenseCode, 2457 senseBuffer->AdditionalSenseCodeQualifier 2458 )); 2459 } 2460 2461 return retry; 2462 2463 } // end SenseInfoInterpret() 2464 2465 2466 BOOLEAN 2467 RequestSenseInfoInterpret( 2468 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 2469 _In_ WDFREQUEST Request, 2470 _In_ PSCSI_REQUEST_BLOCK Srb, 2471 _In_ ULONG RetriedCount, 2472 _Out_ NTSTATUS* Status, 2473 _Out_opt_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) 2474 LONGLONG* RetryIntervalIn100ns 2475 ) 2476 /*++ 2477 2478 Routine Description: 2479 2480 Interpret the error, process it. 2481 1. Release device queue if it's frozen. 2482 2. Interpret and process the error. 2483 2484 Arguments: 2485 2486 DeviceExtension - Supplies the device object associated with this request. 2487 Request - the Request that error occurs on. 2488 Srb - Supplies the scsi request block which failed. 2489 RetriedCount - retried count. 2490 2491 Return Value: 2492 2493 BOOLEAN TRUE: Drivers should retry this request. 2494 FALSE: Drivers should not retry this request. 2495 Status - Returns the status for the request. 2496 RetryIntervalIn100nsUnits - Number of 100ns before the request should be retried. 2497 Zero indicates the request should be immediately retried. 2498 2499 --*/ 2500 { 2501 BOOLEAN retry = FALSE; 2502 LONGLONG retryIntervalIn100ns = 0; 2503 PZERO_POWER_ODD_INFO zpoddInfo = DeviceExtension->ZeroPowerODDInfo; 2504 2505 if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) 2506 { 2507 // request succeeded. 2508 if ((zpoddInfo != NULL) && 2509 (zpoddInfo->BecomingReadyRetryCount > 0)) 2510 { 2511 zpoddInfo->BecomingReadyRetryCount = 0; 2512 } 2513 2514 *Status = STATUS_SUCCESS; 2515 retry = FALSE; 2516 } 2517 else 2518 { 2519 // request failed. We need to process the error. 2520 2521 // 1. Release the queue if it is frozen. 2522 if (Srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) 2523 { 2524 DeviceReleaseQueue(DeviceExtension->Device); 2525 } 2526 2527 if ((zpoddInfo != NULL) && 2528 ((zpoddInfo->RetryFirstCommand != FALSE) || (zpoddInfo->BecomingReadyRetryCount > 0))) 2529 { 2530 retry = SenseInfoInterpretForZPODD(DeviceExtension, 2531 Srb, 2532 Status, 2533 &retryIntervalIn100ns); 2534 } 2535 2536 if (retry == FALSE) 2537 { 2538 // 2. Error Processing 2539 if ((zpoddInfo != NULL) && 2540 (zpoddInfo->BecomingReadyRetryCount > 0)) 2541 { 2542 zpoddInfo->BecomingReadyRetryCount = 0; 2543 } 2544 2545 retry = SenseInfoInterpret(DeviceExtension, 2546 Request, 2547 Srb, 2548 RetriedCount, 2549 Status, 2550 &retryIntervalIn100ns); 2551 } 2552 } 2553 2554 if (RetryIntervalIn100ns != NULL) 2555 { 2556 *RetryIntervalIn100ns = retryIntervalIn100ns; 2557 } 2558 2559 return retry; 2560 } 2561 2562 2563 BOOLEAN 2564 RequestSenseInfoInterpretForScratchBuffer( 2565 _In_ PCDROM_DEVICE_EXTENSION DeviceExtension, 2566 _In_ ULONG RetriedCount, 2567 _Out_ NTSTATUS* Status, 2568 _Out_ _Deref_out_range_(0, MAXIMUM_RETRY_FOR_SINGLE_IO_IN_100NS_UNITS) 2569 LONGLONG* RetryIntervalIn100ns 2570 ) 2571 /*++ 2572 2573 Routine Description: 2574 2575 to analyze the error occurred and set the status, retry interval and decide to retry or not. 2576 2577 Arguments: 2578 2579 DeviceExtension - device extension 2580 RetriedCount - already retried count. 2581 2582 Return Value: 2583 2584 BOOLEAN - TRUE (should retry) 2585 Status - NTSTATUS 2586 RetryIntervalIn100nsUnits - retry interval 2587 2588 --*/ 2589 { 2590 NT_ASSERT(DeviceExtension->ScratchContext.ScratchInUse != 0); 2591 2592 return RequestSenseInfoInterpret(DeviceExtension, 2593 DeviceExtension->ScratchContext.ScratchRequest, 2594 DeviceExtension->ScratchContext.ScratchSrb, 2595 RetriedCount, 2596 Status, 2597 RetryIntervalIn100ns); 2598 } 2599 2600 2601