_Out_ _Deref_out_range_()

in storage/class/cdrom/src/sense.c [491:1077]


    _Out_ _Deref_out_range_(0,100) ULONG*         RetryIntervalInSeconds,  
    _Inout_   PERROR_LOG_CONTEXT        LogContext
    )
/*
    This function will interpret error based on ASC/ASCQ. 

    If the error code is not processed in this function, e.g. return value is TRUE, 
    caller needs to call SenseInfoInterpretBySenseKey() for further interpret.
*/
{
    BOOLEAN     needFurtherInterpret = TRUE;
    PSENSE_DATA senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer;

    // set default values for retry fields.
    *Status = STATUS_IO_DEVICE_ERROR;
    *Retry = TRUE;
    *RetryIntervalInSeconds = 0;

    switch (AdditionalSenseCode) 
    {
    case SCSI_ADSENSE_LUN_NOT_READY: 
        {
            TracePrint((TRACE_LEVEL_WARNING, TRACE_FLAG_GENERAL, 
                        "SenseInfoInterpretByAdditionalSenseCode: Lun not ready\n"));

            //
            //  Many non-WHQL certified drives (mostly CD-RW) return
            //  2/4/0 when they have no media instead of the obvious choice of:
            //
            //      SCSI_SENSE_NOT_READY/SCSI_ADSENSE_NO_MEDIA_IN_DEVICE
            //
            //  These drives should not pass WHQL certification due to this discrepency.
            //
            //  However, we have to retry on 2/4/0 (Not ready, LUN not ready, no info) 
            //  and also 3/2/0 (no seek complete).
            //
            //  These conditions occur when the shell tries to examine an
            //  injected CD (e.g. for autoplay) before the CD is spun up.
            //
            //  The drive should be returning an ASCQ of SCSI_SENSEQ_BECOMING_READY
            //  (0x01) in order to comply with WHQL standards.
            //
            //  The default retry timeout of one second is acceptable to balance
            //  these discrepencies.  don't modify the status, though....
            //
            
            switch (AdditionalSenseCodeQual) 
            {
            case SCSI_SENSEQ_OPERATION_IN_PROGRESS: 
                {
                    DEVICE_EVENT_BECOMING_READY notReady = {0};

                    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 
                                "SenseInfoInterpretByAdditionalSenseCode: Operation In Progress\n"));

                    needFurtherInterpret = FALSE;
            
                    *Retry = TRUE;
                    *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
                    *Status = STATUS_DEVICE_NOT_READY;

                    notReady.Version = 1;
                    notReady.Reason = 2;
                    notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10;
                    DeviceSendNotification(DeviceExtension,
                                           &GUID_IO_DEVICE_BECOMING_READY,
                                           sizeof(DEVICE_EVENT_BECOMING_READY),
                                           &notReady);

                    break;
                }

            case SCSI_SENSEQ_BECOMING_READY: 
                {
                    DEVICE_EVENT_BECOMING_READY notReady = {0};

                    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
                                "SenseInfoInterpretByAdditionalSenseCode: In process of becoming ready\n"));

                    needFurtherInterpret = FALSE;
            
                    *Retry = TRUE;
                    *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;
                    *Status = STATUS_DEVICE_NOT_READY;

                    notReady.Version = 1;
                    notReady.Reason = 1;
                    notReady.Estimated100msToReady = *RetryIntervalInSeconds * 10;
                    DeviceSendNotification(DeviceExtension,
                                           &GUID_IO_DEVICE_BECOMING_READY,
                                           sizeof(DEVICE_EVENT_BECOMING_READY),
                                           &notReady);

                    break;
                }

            case SCSI_SENSEQ_LONG_WRITE_IN_PROGRESS: 
                {
                    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 
                                "SenseInfoInterpretByAdditionalSenseCode: Long write in progress\n"));

                    needFurtherInterpret = FALSE;
            
                    // This has been seen as a transcient failure on some drives
                    *Status = STATUS_DEVICE_NOT_READY;
                    *Retry = TRUE;
                    // Set retry interval to be 0 as the drive can be ready at anytime.
                    *RetryIntervalInSeconds = 0;

                    break;
                }

            case SCSI_SENSEQ_MANUAL_INTERVENTION_REQUIRED: 
                {
                    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 
                                "SenseInfoInterpretByAdditionalSenseCode: Manual intervention required\n"));

                    needFurtherInterpret = FALSE;

                    *Status = STATUS_NO_MEDIA_IN_DEVICE;
                    *Retry = FALSE;
                    *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;

                    break;
                }

            case SCSI_SENSEQ_FORMAT_IN_PROGRESS: 
                {
                    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,
                                "SenseInfoInterpretByAdditionalSenseCode: Format in progress\n"));
            
                    needFurtherInterpret = FALSE;

                    *Status = STATUS_DEVICE_NOT_READY;
                    *Retry = FALSE;
                    *RetryIntervalInSeconds = NOT_READY_RETRY_INTERVAL;

                    break;
                }

            case SCSI_SENSEQ_CAUSE_NOT_REPORTABLE: 
            case SCSI_SENSEQ_INIT_COMMAND_REQUIRED:
            default:
                {
                    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 
                                "SenseInfoInterpretByAdditionalSenseCode: Initializing command required\n"));

                    needFurtherInterpret = FALSE;

                    *Status = STATUS_DEVICE_NOT_READY;
                    *Retry = TRUE;
                    *RetryIntervalInSeconds = 0;

                    // This sense code/additional sense code combination may indicate 
                    // that the device needs to be started. 
                    if (TEST_FLAG(DeviceExtension->DeviceFlags, DEV_SAFE_START_UNIT) &&
                        !TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_LOW_PRIORITY))
                    {
                        DeviceSendStartUnit(DeviceExtension->Device);
                    }

                    break;
                }
            } // end switch (AdditionalSenseCodeQual)
            break;

        } // end case (SCSI_ADSENSE_LUN_NOT_READY)

    case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE: 
        {
            TracePrint((TRACE_LEVEL_VERBOSE, TRACE_FLAG_GENERAL, 
                        "SenseInfoInterpretByAdditionalSenseCode: No Media in device.\n"));

            needFurtherInterpret = FALSE;

            *Status = STATUS_NO_MEDIA_IN_DEVICE;
            *Retry = FALSE;

            if (AdditionalSenseCodeQual == 0xCC)
            {
                //  The IMAPIv1 filter returns this ASCQ value while it is burning CD media, and we want
                //  to preserve this functionality for compatibility reasons.
                //  We want to indicate that the media is not present to most applications;
                //  but RSM has to know that the media is still in the drive (i.e. the drive is not free).
                DeviceSetMediaChangeStateEx(DeviceExtension, MediaUnavailable, NULL);
            }
            else 
            {
                DeviceSetMediaChangeStateEx(DeviceExtension, MediaNotPresent, NULL);
            }

            break;
        } // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE

    case SCSI_ADSENSE_INVALID_MEDIA: 
        {
        switch (AdditionalSenseCodeQual) 
        {

        case SCSI_SENSEQ_UNKNOWN_FORMAT: 
            {
                needFurtherInterpret = FALSE;
            
                // Log error only if this is a paging request
                *Status = STATUS_UNRECOGNIZED_MEDIA;
                *Retry = FALSE;

                LogContext->LogError = TEST_FLAG(Srb->SrbFlags, SRB_CLASS_FLAGS_PAGING);
                LogContext->UniqueErrorValue = 256;
                LogContext->ErrorCode = IO_ERR_BAD_BLOCK;

                break;
            }

        case SCSI_SENSEQ_INCOMPATIBLE_FORMAT: 
            {
                needFurtherInterpret = FALSE;
            
                *Status = STATUS_UNRECOGNIZED_MEDIA;
                *Retry = FALSE;

                LogContext->LogError = FALSE;

                break;
            }   

        case SCSI_SENSEQ_CLEANING_CARTRIDGE_INSTALLED:
            {
                needFurtherInterpret = FALSE;
            
                *Status = STATUS_CLEANER_CARTRIDGE_INSTALLED;
                *Retry = FALSE;

                LogContext->LogError = FALSE;
                LogContext->UniqueErrorValue = 256;
                LogContext->ErrorCode = IO_ERR_BAD_BLOCK;
                break;
            }

        default:
            {
                needFurtherInterpret = TRUE;
                break;
            }
        } // end case AdditionalSenseCodeQual

        break;
        } // end case SCSI_ADSENSE_NO_MEDIA_IN_DEVICE

    case SCSI_ADSENSE_NO_SEEK_COMPLETE: 
        {
        switch (AdditionalSenseCodeQual) 
        {

        case 0x00: 
            {
                needFurtherInterpret = FALSE;
            
                *Status = STATUS_DEVICE_DATA_ERROR;
                *Retry = TRUE;
                *RetryIntervalInSeconds = 0;
                LogContext->LogError = TRUE;
                LogContext->UniqueErrorValue = 256;
                LogContext->ErrorCode = IO_ERR_BAD_BLOCK;
                break;
            }

        default:
            {
                needFurtherInterpret = TRUE;
                break;
            }
        }

        break;
        } // end case SCSI_ADSENSE_NO_SEEK_COMPLETE

    case SCSI_ADSENSE_LUN_COMMUNICATION: 
        {
        switch (AdditionalSenseCodeQual) 
        {

        case SCSI_SESNEQ_COMM_CRC_ERROR: 
            {
                needFurtherInterpret = FALSE;
            
                *Status = STATUS_IO_DEVICE_ERROR;
                *Retry = TRUE;
                *RetryIntervalInSeconds = 1;
                LogContext->LogError = TRUE;
                LogContext->UniqueErrorValue = 257;
                LogContext->ErrorCode = IO_ERR_CONTROLLER_ERROR;
                break;
            }

        default:
            {
                needFurtherInterpret = TRUE;
                break;
            }
        }

        break;
        } // end case SCSI_ADSENSE_LUN_COMMUNICATION

    case SCSI_ADSENSE_ILLEGAL_BLOCK: 
        {
            needFurtherInterpret = FALSE;

            TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 
                        "SenseInfoInterpretByAdditionalSenseCode: Illegal block address\n"));
            *Status = STATUS_NONEXISTENT_SECTOR;
            *Retry = FALSE;
            break;
        }

    case SCSI_ADSENSE_INVALID_LUN: 
        {
            needFurtherInterpret = FALSE;

            TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,  
                        "SenseInfoInterpretByAdditionalSenseCode: Invalid LUN\n"));
            *Status = STATUS_NO_SUCH_DEVICE;
            *Retry = FALSE;
            break;
        }

    case SCSI_ADSENSE_COPY_PROTECTION_FAILURE: 
        {
            needFurtherInterpret = FALSE;

            *Retry = FALSE;

            TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, 
                        "SenseInfoInterpretByAdditionalSenseCode: Key - Copy protection failure\n"));

            switch (AdditionalSenseCodeQual) 
            {
            case SCSI_SENSEQ_AUTHENTICATION_FAILURE:
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
                            "SenseInfoInterpretByAdditionalSenseCode: Authentication failure\n"));
                *Status = STATUS_CSS_AUTHENTICATION_FAILURE;
                break;
            case SCSI_SENSEQ_KEY_NOT_PRESENT:
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
                            "SenseInfoInterpretByAdditionalSenseCode: Key not present\n"));
                *Status = STATUS_CSS_KEY_NOT_PRESENT;
                break;
            case SCSI_SENSEQ_KEY_NOT_ESTABLISHED:
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
                            "SenseInfoInterpretByAdditionalSenseCode: Key not established\n"));
                *Status = STATUS_CSS_KEY_NOT_ESTABLISHED;
                break;
            case SCSI_SENSEQ_READ_OF_SCRAMBLED_SECTOR_WITHOUT_AUTHENTICATION:
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
                            "SenseInfoInterpretByAdditionalSenseCode: Read of scrambled sector w/o authentication\n"));
                *Status = STATUS_CSS_SCRAMBLED_SECTOR;
                break;
            case SCSI_SENSEQ_MEDIA_CODE_MISMATCHED_TO_LOGICAL_UNIT:
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
                            "SenseInfoInterpretByAdditionalSenseCode: Media region does not logical unit region\n"));
                *Status = STATUS_CSS_REGION_MISMATCH;
                break;
            case SCSI_SENSEQ_LOGICAL_UNIT_RESET_COUNT_ERROR:
                TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,
                            "SenseInfoInterpretByAdditionalSenseCode: Region set error -- region may be permanent\n"));
                *Status = STATUS_CSS_RESETS_EXHAUSTED;
                break;

            default:
                *Status = STATUS_COPY_PROTECTION_FAILURE;
                break;
            } // end switch of ASCQ for COPY_PROTECTION_FAILURE

            break;
        }

    case SCSI_ADSENSE_INVALID_CDB: 
        {
            needFurtherInterpret = FALSE;

            TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL,  
                        "SenseInfoInterpretByAdditionalSenseCode: Key - Invalid CDB\n"));

            *Status = STATUS_INVALID_DEVICE_REQUEST;
            *Retry = FALSE;

            // Note: the retry interval is not typically used.
            // it is set here only because a ClassErrorHandler
            // cannot set the RetryIntervalInSeconds, and the error may
            // require a few commands to be sent to clear whatever
            // caused this condition (i.e. disk clears the write
            // cache, requiring at least two commands)
            //
            // hopefully, this shortcoming can be changed for blackcomb.
            *RetryIntervalInSeconds = 3;

            break;
        }

    case SCSI_ADSENSE_MEDIUM_CHANGED: 
        {
            needFurtherInterpret = FALSE;
            *RetryIntervalInSeconds = 0;

            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_MCN,  
                        "SenseInfoInterpretByAdditionalSenseCode: Media changed\n"));

            DeviceSetMediaChangeStateEx(DeviceExtension, MediaPresent, NULL);

            // special process for Media Change
            if (IsVolumeMounted(DeviceExtension->DeviceObject))
            {
                // Set bit to indicate that media may have changed and volume needs verification.
                SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);

                *Status = STATUS_VERIFY_REQUIRED;
                *Retry = FALSE;
            }
            else 
            {
                *Status = STATUS_IO_DEVICE_ERROR;
                *Retry = TRUE;
            }
            break;
        }

    case SCSI_ADSENSE_OPERATOR_REQUEST: 
        {
            switch (AdditionalSenseCodeQual) 
            {
            case SCSI_SENSEQ_MEDIUM_REMOVAL: 
                {
                    needFurtherInterpret = FALSE;
                    *RetryIntervalInSeconds = 0;
            
                    InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
                    
                    TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,  
                        "SenseInfoInterpretByAdditionalSenseCode: Ejection request received!\n"));
                    //Send eject notification.
                    DeviceSendNotification(DeviceExtension,
                                           &GUID_IO_MEDIA_EJECT_REQUEST,
                                           0,
                                           NULL);
                    // special process for Media Change
                    if (IsVolumeMounted(DeviceExtension->DeviceObject))
                    {
                        // Set bit to indicate that media may have changed and volume needs verification.
                        SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);

                        *Status = STATUS_VERIFY_REQUIRED;
                        *Retry = FALSE;
                    }
                    else 
                    {
                        *Status = STATUS_IO_DEVICE_ERROR;
                        *Retry = TRUE;
                    }
                    break;
                }
            default:
                {
                    needFurtherInterpret = TRUE;
                    break;
                }
            }
            break;
        }

    case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED: 
        {
            needFurtherInterpret = FALSE;
            *RetryIntervalInSeconds = 5;

            InterlockedIncrement((PLONG)&DeviceExtension->MediaChangeCount);
                    
            // Device information has changed, we need to rescan the
            // bus for changed information such as the capacity.
            TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL,  
                        "SenseInfoInterpretByAdditionalSenseCode: Device information changed. Invalidate the bus\n"));

            IoInvalidateDeviceRelations(DeviceExtension->LowerPdo, BusRelations);

            // special process for Media Change
            if (IsVolumeMounted(DeviceExtension->DeviceObject))
            {
                // Set bit to indicate that media may have changed and volume needs verification.
                SET_FLAG(DeviceExtension->DeviceObject->Flags, DO_VERIFY_VOLUME);

                *Status = STATUS_VERIFY_REQUIRED;
                *Retry = FALSE;
            }
            else 
            {
                *Status = STATUS_IO_DEVICE_ERROR;
                *Retry = TRUE;
            }
            break;
        } //end Case SCSI_ADSENSE_OPERATING_CONDITIONS_CHANGED


    case SCSI_ADSENSE_REC_DATA_NOECC:
    case SCSI_ADSENSE_REC_DATA_ECC: 
        {
            needFurtherInterpret = FALSE;

            *Status = STATUS_SUCCESS;
            *Retry = FALSE;
            LogContext->LogError = TRUE;
            LogContext->UniqueErrorValue = 258;
            LogContext->ErrorCode = IO_RECOVERED_VIA_ECC;

            if (senseBuffer->IncorrectLength) 
            {
                TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 
                            "SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n"));
                *Status = STATUS_INVALID_BLOCK_LENGTH ;
            }
            break;
        }

    case SCSI_ADSENSE_FAILURE_PREDICTION_THRESHOLD_EXCEEDED: 
        {
            UCHAR wmiEventData[sizeof(ULONG)+sizeof(UCHAR)] = {0};

            *((PULONG)wmiEventData) = sizeof(UCHAR);
            wmiEventData[sizeof(ULONG)] = AdditionalSenseCodeQual;

            needFurtherInterpret = FALSE;

            // Don't log another eventlog if we have already logged once
            // NOTE: this should have been interlocked, but the structure
            //       was publicly defined to use a BOOLEAN (char).  Since
            //       media only reports these errors once per X minutes,
            //       the potential race condition is nearly non-existant.
            //       the worst case is duplicate log entries, so ignore.

            *Status = STATUS_SUCCESS;
            *Retry = FALSE;
            LogContext->UniqueErrorValue = 258;
            LogContext->LogError = TRUE;
            LogContext->ErrorCode = IO_WRN_FAILURE_PREDICTED;

            if (senseBuffer->IncorrectLength) 
            {
                TracePrint((TRACE_LEVEL_INFORMATION, TRACE_FLAG_GENERAL, 
                            "SenseInfoInterpretByAdditionalSenseCode: Incorrect length detected.\n"));
                *Status = STATUS_INVALID_BLOCK_LENGTH ;
            }
            break;
        }

    case 0x57: 
        {
            // UNABLE_TO_RECOVER_TABLE_OF_CONTENTS
            // the Matshita CR-585 returns this for all read commands
            // on blank CD-R and CD-RW media, and we need to handle
            // this for READ_CD detection ability.
            switch (AdditionalSenseCodeQual) 
            {
            case 0x00: 
                {
                    needFurtherInterpret = FALSE;

                    *Status = STATUS_UNRECOGNIZED_MEDIA;
                    *Retry = FALSE;
                    break;
                }
            default:
                {
                    needFurtherInterpret = TRUE;
                    break;
                }
            }
            break;
        }   //end case Matshita specific error 0x57

    default:
        {
            needFurtherInterpret = TRUE;
            break;
        }
    }

    return needFurtherInterpret;
}