コード例 #1
0
ULONGLONG
RhelGetLba(
    IN PVOID DeviceExtension,
    IN PCDB Cdb
    )
{

    EIGHT_BYTE lba;
    PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension;

    lba.AsULongLong = 0;

    switch (Cdb->CDB6GENERIC.OperationCode) {

        case SCSIOP_READ:
        case SCSIOP_WRITE:
        case SCSIOP_READ_CAPACITY:
        case SCSIOP_WRITE_VERIFY: {
            lba.Byte0 = Cdb->CDB10.LogicalBlockByte3;
            lba.Byte1 = Cdb->CDB10.LogicalBlockByte2;
            lba.Byte2 = Cdb->CDB10.LogicalBlockByte1;
            lba.Byte3 = Cdb->CDB10.LogicalBlockByte0;
        }
        break;
        case SCSIOP_READ6:
        case SCSIOP_WRITE6: {
            lba.Byte0 = Cdb->CDB6READWRITE.LogicalBlockMsb1;
            lba.Byte1 = Cdb->CDB6READWRITE.LogicalBlockMsb0;
            lba.Byte2 = Cdb->CDB6READWRITE.LogicalBlockLsb;
        }
        break;
        case SCSIOP_READ12:
        case SCSIOP_WRITE12:
        case SCSIOP_WRITE_VERIFY12: {
            REVERSE_BYTES(&lba, &Cdb->CDB12.LogicalBlock[0]);
        }
        break;
        case SCSIOP_READ16:
        case SCSIOP_WRITE16:
        case SCSIOP_READ_CAPACITY16:
        case SCSIOP_WRITE_VERIFY16: {
            REVERSE_BYTES_QUAD(&lba, &Cdb->CDB16.LogicalBlock[0]);
        }
        break;
        default: {
            ASSERT(FALSE);
            return (ULONGLONG)-1;
        }
    }
    return (lba.AsULongLong * (adaptExt->info.blk_size / SECTOR_SIZE));
}
コード例 #2
0
ファイル: xferpkt.c プロジェクト: kcrazy/winekit
/*
 *  SetupDriveCapacityTransferPacket
 *
 *      Set up a transferPacket for a synchronous Drive Capacity transfer.
 */
VOID SetupDriveCapacityTransferPacket(   TRANSFER_PACKET *Pkt,
                                        PVOID ReadCapacityBuffer,
                                        ULONG ReadCapacityBufferLen,
                                        PKEVENT SyncEventPtr,
                                        PIRP OriginalIrp,
                                        BOOLEAN Use16ByteCdb)
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
    PCDB pCdb;

    RtlZeroMemory(&Pkt->Srb, sizeof(SCSI_REQUEST_BLOCK));

    Pkt->Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
    Pkt->Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
    Pkt->Srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
    Pkt->Srb.OriginalRequest = Pkt->Irp;
    Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
    Pkt->Srb.SenseInfoBufferLength = sizeof(SENSE_DATA);
    Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
    Pkt->Srb.DataBuffer = ReadCapacityBuffer;
    Pkt->Srb.DataTransferLength = ReadCapacityBufferLen;

    Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
    SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DATA_IN);
    SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
    SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);

    pCdb = (PCDB)Pkt->Srb.Cdb;
    if (Use16ByteCdb == TRUE) {
        ASSERT(ReadCapacityBufferLen >= sizeof(READ_CAPACITY_DATA_EX));
        Pkt->Srb.CdbLength = 16;
        pCdb->CDB16.OperationCode = SCSIOP_READ_CAPACITY16;
        REVERSE_BYTES(&pCdb->CDB16.TransferLength, &ReadCapacityBufferLen);
        pCdb->AsByte[1] = 0x10; // Service Action
    } else {
        Pkt->Srb.CdbLength = 10;
        pCdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
    }

    Pkt->BufPtrCopy = ReadCapacityBuffer;
    Pkt->BufLenCopy = ReadCapacityBufferLen;

    Pkt->OriginalIrp = OriginalIrp;
    Pkt->NumRetries = NUM_DRIVECAPACITY_RETRIES;
    Pkt->SyncEventPtr = SyncEventPtr;
    Pkt->CompleteOriginalIrpWhenLastPacketCompletes = FALSE;
}
コード例 #3
0
ファイル: retry.c プロジェクト: uri247/wdk80
/*
 *  InterpretTransferPacketError
 *
 *      Interpret the SRB error into a meaningful IRP status.
 *      ClassInterpretSenseInfo also may modify the SRB for the retry.
 *
 *      Return TRUE iff packet should be retried.
 */
BOOLEAN InterpretTransferPacketError(PTRANSFER_PACKET Pkt)
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExtension = Pkt->Fdo->DeviceExtension;
    PCLASS_PRIVATE_FDO_DATA fdoData = fdoExtension->PrivateFdoData;
    ULONG timesAlreadyRetried;
    BOOLEAN shouldRetry = FALSE;
    PCDB pCdb = ClasspTransferPacketGetCdb(Pkt);

    /*
     *  Interpret the error using the returned sense info first.
     */
    Pkt->RetryIn100nsUnits = 0;

    /*
     *  Pre-calculate the number of times the IO has already been
     *  retried, so that all InterpretSenseInfo routines get the right value.
     */
    if (pCdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL)
    {
        timesAlreadyRetried = NUM_LOCKMEDIAREMOVAL_RETRIES - Pkt->NumRetries;
    }
    else if ((pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) ||
             (pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10))
    {
        timesAlreadyRetried = NUM_MODESENSE_RETRIES - Pkt->NumRetries;
    }
    else if ((pCdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY) ||
             (pCdb->CDB16.OperationCode == SCSIOP_READ_CAPACITY16))
    {
        timesAlreadyRetried = NUM_DRIVECAPACITY_RETRIES - Pkt->NumRetries;
    }
    else if (IS_SCSIOP_READWRITE(pCdb->CDB10.OperationCode))
    {
        timesAlreadyRetried = NUM_IO_RETRIES - Pkt->NumRetries;
    }
    else if (pCdb->TOKEN_OPERATION.OperationCode == SCSIOP_POPULATE_TOKEN &&
             pCdb->TOKEN_OPERATION.ServiceAction == SERVICE_ACTION_POPULATE_TOKEN)
    {
        timesAlreadyRetried = NUM_POPULATE_TOKEN_RETRIES - Pkt->NumRetries;
    }
    else if (pCdb->TOKEN_OPERATION.OperationCode == SCSIOP_WRITE_USING_TOKEN &&
             pCdb->TOKEN_OPERATION.ServiceAction == SERVICE_ACTION_WRITE_USING_TOKEN)
    {
        timesAlreadyRetried = NUM_WRITE_USING_TOKEN_RETRIES - Pkt->NumRetries;
    }
    else if (ClasspIsReceiveTokenInformation(pCdb))
    {
        timesAlreadyRetried = NUM_RECEIVE_TOKEN_INFORMATION_RETRIES - Pkt->NumRetries;
    }
    else
    {
        TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt));
        timesAlreadyRetried = 0;
    }


    if (fdoData->InterpretSenseInfo != NULL) {

        SCSI_REQUEST_BLOCK tempSrb = {0};
        PSCSI_REQUEST_BLOCK srbPtr = (PSCSI_REQUEST_BLOCK)Pkt->Srb;

        // SAL annotation and ClassInitializeEx() both validate this
        NT_ASSERT(fdoData->InterpretSenseInfo->Interpret != NULL);

        //
        // If class driver does not support extended SRB and this is
        // an extended SRB, convert to legacy SRB and pass to class
        // driver.
        //
        if ((Pkt->Srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) &&
            ((fdoExtension->CommonExtension.DriverExtension->SrbSupport &
              CLASS_SRB_STORAGE_REQUEST_BLOCK) == 0)) {
            ClasspConvertToScsiRequestBlock(&tempSrb, (PSTORAGE_REQUEST_BLOCK)Pkt->Srb);
            srbPtr = &tempSrb;
        }

        shouldRetry = fdoData->InterpretSenseInfo->Interpret(Pkt->Fdo,
                                                             Pkt->OriginalIrp,
                                                             srbPtr,
                                                             IRP_MJ_SCSI,
                                                             0,
                                                             timesAlreadyRetried,
                                                             Pkt->RetryHistory,
                                                             &Pkt->Irp->IoStatus.Status,
                                                             &Pkt->RetryIn100nsUnits);

    }
    else if (pCdb->MEDIA_REMOVAL.OperationCode == SCSIOP_MEDIUM_REMOVAL){

        ULONG retryIntervalSeconds = 0;
        /*
         *  This is an Ejection Control SRB.  Interpret its sense info specially.
         */
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);

        if (shouldRetry){
            /*
             *  If the device is not ready, wait at least 2 seconds before retrying.
             */
            PVOID senseInfoBuffer = ClasspTransferPacketGetSenseInfoBuffer(Pkt);

            UCHAR senseInfoBufferLength = ClasspTransferPacketGetSenseInfoBufferLength(Pkt);
            BOOLEAN validSense = FALSE;
            UCHAR additionalSenseCode = 0;
            BOOLEAN setRetryIntervalSeconds = FALSE;

            validSense = ScsiGetSenseKeyAndCodes(senseInfoBuffer,
                                                 senseInfoBufferLength,
                                                 SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
                                                 NULL,
                                                 &additionalSenseCode,
                                                 NULL);

            if (validSense) {

                if ((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
                    (additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) {
                    setRetryIntervalSeconds = TRUE;
                }
            }

            if (!setRetryIntervalSeconds && (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
                setRetryIntervalSeconds = TRUE;
            }

            if (setRetryIntervalSeconds) {
                retryIntervalSeconds = MAX(retryIntervalSeconds, 2);
            }
        }

        if (shouldRetry)
        {
            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
        }

    }
    else if ((pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE) ||
            (pCdb->MODE_SENSE.OperationCode == SCSIOP_MODE_SENSE10)){

        ULONG retryIntervalSeconds = 0;
        /*
         *  This is an Mode Sense SRB.  Interpret its sense info specially.
         */
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);
        if (shouldRetry){
            /*
             *  If the device is not ready, wait at least 2 seconds before retrying.
             */
            PVOID senseInfoBuffer = ClasspTransferPacketGetSenseInfoBuffer(Pkt);
            UCHAR senseInfoBufferLength = ClasspTransferPacketGetSenseInfoBufferLength(Pkt);
            BOOLEAN validSense = FALSE;
            UCHAR additionalSenseCode = 0;
            BOOLEAN setRetryIntervalSeconds = FALSE;

            NT_ASSERT(senseInfoBuffer);

            validSense = ScsiGetSenseKeyAndCodes(senseInfoBuffer,
                                                 senseInfoBufferLength,
                                                 SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
                                                 NULL,
                                                 &additionalSenseCode,
                                                 NULL);

            if (validSense) {
                if ((Pkt->Irp->IoStatus.Status == STATUS_DEVICE_NOT_READY) &&
                    (additionalSenseCode == SCSI_ADSENSE_LUN_NOT_READY)) {
                    setRetryIntervalSeconds = TRUE;
                }
            }

            if (!setRetryIntervalSeconds && (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_SELECTION_TIMEOUT)) {
                setRetryIntervalSeconds = TRUE;
            }

            if (setRetryIntervalSeconds) {
                retryIntervalSeconds = MAX(retryIntervalSeconds, 2);
            }
        }

        /*
         *  Some special cases for mode sense.
         */
        if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
            shouldRetry = TRUE;
        }
        else if (SRB_STATUS(Pkt->Srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN){
            /*
             *  This is a HACK.
             *  Atapi returns SRB_STATUS_DATA_OVERRUN when it really means
             *  underrun (i.e. success, and the buffer is longer than needed).
             *  So treat this as a success.
             *  When the caller of this function sees that the status was changed to success,
             *  it will add the transferred length to the original irp.
             */
            Pkt->Irp->IoStatus.Status = STATUS_SUCCESS;
            shouldRetry = FALSE;
        }

        if (shouldRetry)
        {
            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
        }

    }
    else if ((pCdb->CDB10.OperationCode == SCSIOP_READ_CAPACITY) ||
             (pCdb->CDB16.OperationCode == SCSIOP_READ_CAPACITY16)) {

        ULONG retryIntervalSeconds = 0;

        /*
         *  This is a Drive Capacity SRB.  Interpret its sense info specially.
         */
        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);
        if (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED){
            shouldRetry = TRUE;
        }

        if (shouldRetry)
        {
            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
        }

    }
    else if (IS_SCSIOP_READWRITE(pCdb->CDB10.OperationCode)) {

        ULONG retryIntervalSeconds = 0;
        /*
         *  This is a Read/Write Data packet.
         */
        PIO_STACK_LOCATION origCurrentSp = IoGetCurrentIrpStackLocation(Pkt->OriginalIrp);

        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            origCurrentSp->MajorFunction,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);
        /*
         *  Deal with some special cases.
         */
        if (Pkt->Irp->IoStatus.Status == STATUS_INSUFFICIENT_RESOURCES){
            /*
             *  We are in extreme low-memory stress.
             *  We will retry in smaller chunks.
             */
            shouldRetry = TRUE;
        }
        else if (TEST_FLAG(origCurrentSp->Flags, SL_OVERRIDE_VERIFY_VOLUME) &&
                (Pkt->Irp->IoStatus.Status == STATUS_VERIFY_REQUIRED)){
            /*
             *  We are still verifying a (possibly) reloaded disk/cdrom.
             *  So retry the request.
             */
            Pkt->Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
            shouldRetry = TRUE;
        }

        if (shouldRetry)
        {
            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;
        }

    } else if (ClasspIsOffloadDataTransferCommand(pCdb)) {

        ULONG retryIntervalSeconds = 0;

        Pkt->TransferCount = 0;

        shouldRetry = ClassInterpretSenseInfo(
                            Pkt->Fdo,
                            (PSCSI_REQUEST_BLOCK)Pkt->Srb,
                            IRP_MJ_SCSI,
                            0,
                            timesAlreadyRetried,
                            &Pkt->Irp->IoStatus.Status,
                            &retryIntervalSeconds);

        if (shouldRetry) {

            Pkt->RetryIn100nsUnits = retryIntervalSeconds;
            Pkt->RetryIn100nsUnits *= 1000 * 1000 * 10;

        } else {

            if (ClasspIsTokenOperation(pCdb)) {

                PVOID senseInfoBuffer = ClasspTransferPacketGetSenseInfoBuffer(Pkt);
                UCHAR senseInfoBufferLength = ClasspTransferPacketGetSenseInfoBufferLength(Pkt);
                BOOLEAN validSense = FALSE;
                UCHAR senseKey = 0;
                UCHAR additionalSenseCode = 0;
                UCHAR additionalSenseQual = 0;
                BOOLEAN isInformationValid = FALSE;
                ULONGLONG information = 0;

                NT_ASSERT(senseInfoBuffer);

                validSense = ScsiGetSenseKeyAndCodes(senseInfoBuffer,
                                                     senseInfoBufferLength,
                                                     SCSI_SENSE_OPTIONS_FIXED_FORMAT_IF_UNKNOWN_FORMAT_INDICATED,
                                                     &senseKey,
                                                     &additionalSenseCode,
                                                     &additionalSenseQual);

                if (validSense) {

                    //
                    // If this is a data underrun condition (i.e. target truncated the offload data transfer),
                    // the SenseData's Information field may have the TransferCount.
                    //
                    if ((senseKey == SCSI_SENSE_COPY_ABORTED || senseKey == SCSI_SENSE_ABORTED_COMMAND) &&
                        (additionalSenseCode == SCSI_ADSENSE_COPY_TARGET_DEVICE_ERROR && additionalSenseQual == SCSI_SENSEQ_DATA_UNDERRUN)) {

                            //
                            // Sense data in Descriptor format
                            //
                            if (IsDescriptorSenseDataFormat(senseInfoBuffer)) {

                                PVOID startBuffer = NULL;
                                UCHAR startBufferLength = 0;


                                if (ScsiGetSenseDescriptor(senseInfoBuffer,
                                                           SrbGetSenseInfoBufferLength(Pkt->Srb),
                                                           &startBuffer,
                                                           &startBufferLength)) {
                                    UCHAR outType;
                                    PVOID outBuffer = NULL;
                                    UCHAR outBufferLength = 0;

                                    UCHAR typeList[1] = {SCSI_SENSE_DESCRIPTOR_TYPE_INFORMATION};

                                    if (ScsiGetNextSenseDescriptorByType(startBuffer,
                                                                         startBufferLength,
                                                                         typeList,
                                                                         ARRAYSIZE(typeList),
                                                                         &outType,
                                                                         &outBuffer,
                                                                         &outBufferLength)) {

                                        if (outType == SCSI_SENSE_DESCRIPTOR_TYPE_INFORMATION) {

                                            if (ScsiValidateInformationSenseDescriptor(outBuffer, outBufferLength)) {
                                                REVERSE_BYTES_QUAD(&information, &(((PSCSI_SENSE_DESCRIPTOR_INFORMATION)outBuffer)->Information));
                                                isInformationValid = TRUE;
                                            }

                                        } else {

                                            //
                                            // ScsiGetNextDescriptorByType should only return a type that is specified by us.
                                            //
                                            NT_ASSERT(FALSE);
                                        }
                                    }
                                }
                            } else {

                                //
                                // Sense data in Fixed format
                                //
                                REVERSE_BYTES(&information, &(((PFIXED_SENSE_DATA)senseInfoBuffer)->Information));
                                isInformationValid = TRUE;
                            }

                        if (isInformationValid) {
                            Pkt->TransferCount = information;
                        }
                    }
                }
            }
        }

    }
    else {
        TracePrint((TRACE_LEVEL_ERROR, TRACE_FLAG_GENERAL, "Unhandled SRB Function %xh in error path for packet %p (did miniport change Srb.Cdb.OperationCode ?)", (ULONG)pCdb->CDB10.OperationCode, Pkt));
    }

    return shouldRetry;
}
コード例 #4
0
UCHAR
RhelScsiGetCapacity(
    IN PVOID DeviceExtension,
    IN OUT PSCSI_REQUEST_BLOCK Srb
    )
{
    UCHAR SrbStatus = SRB_STATUS_SUCCESS;
    PREAD_CAPACITY_DATA readCap;
    PREAD_CAPACITY_DATA_EX readCapEx;
    u64 lastLBA;
    EIGHT_BYTE lba;
    u64 blocksize;
    BOOLEAN depthSet;
    PADAPTER_EXTENSION adaptExt= (PADAPTER_EXTENSION)DeviceExtension;
    PCDB cdb = (PCDB)&Srb->Cdb[0];
    UCHAR  PMI = 0;
#ifdef USE_STORPORT
    depthSet = StorPortSetDeviceQueueDepth(DeviceExtension,
                                           Srb->PathId,
                                           Srb->TargetId,
                                           Srb->Lun,
                                           adaptExt->queue_depth);
    ASSERT(depthSet);
#endif

    readCap = (PREAD_CAPACITY_DATA)Srb->DataBuffer;
    readCapEx = (PREAD_CAPACITY_DATA_EX)Srb->DataBuffer;

    lba.AsULongLong = 0;
    if (cdb->CDB6GENERIC.OperationCode == SCSIOP_READ_CAPACITY16 ){
         PMI = cdb->READ_CAPACITY16.PMI & 1;
         REVERSE_BYTES_QUAD(&lba, &cdb->READ_CAPACITY16.LogicalBlock[0]);
    }

    if (!PMI && lba.AsULongLong) {

        PSENSE_DATA senseBuffer = (PSENSE_DATA) Srb->SenseInfoBuffer;
        Srb->ScsiStatus = SCSISTAT_CHECK_CONDITION;
        senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST;
        senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_INVALID_CDB;
        return SrbStatus;
    }

    blocksize = adaptExt->info.blk_size;
    lastLBA = adaptExt->info.capacity / (blocksize / SECTOR_SIZE) - 1;

    if (Srb->DataTransferLength == sizeof(READ_CAPACITY_DATA)) {
        if (lastLBA > 0xFFFFFFFF) {
            readCap->LogicalBlockAddress = (ULONG)-1;
        } else {
            REVERSE_BYTES(&readCap->LogicalBlockAddress,
                          &lastLBA);
        }
        REVERSE_BYTES(&readCap->BytesPerBlock,
                          &blocksize);
    } else {
        ASSERT(Srb->DataTransferLength ==
                          sizeof(READ_CAPACITY_DATA_EX));
        REVERSE_BYTES_QUAD(&readCapEx->LogicalBlockAddress.QuadPart,
                          &lastLBA);
        REVERSE_BYTES(&readCapEx->BytesPerBlock,
                          &blocksize);
    }
    Srb->ScsiStatus = SCSISTAT_GOOD;
    return SrbStatus;
}
コード例 #5
0
ファイル: xferpkt.c プロジェクト: kcrazy/winekit
/*
 *  SetupReadWriteTransferPacket
 *
 *        This function is called once to set up the first attempt to send a packet.
 *        It is not called before a retry, as SRB fields may be modified for the retry.
 *
 *      Set up the Srb of the TRANSFER_PACKET for the transfer.
 *        The Irp is set up in SubmitTransferPacket because it must be reset
 *        for each packet submission.
 */
VOID SetupReadWriteTransferPacket(  PTRANSFER_PACKET Pkt,
                                    PVOID Buf,
                                    ULONG Len,
                                    LARGE_INTEGER DiskLocation,
                                    PIRP OriginalIrp)
{
    PFUNCTIONAL_DEVICE_EXTENSION fdoExt = Pkt->Fdo->DeviceExtension;
    PCOMMON_DEVICE_EXTENSION commonExtension = Pkt->Fdo->DeviceExtension;
    PCLASS_PRIVATE_FDO_DATA fdoData = fdoExt->PrivateFdoData;
    PIO_STACK_LOCATION origCurSp = IoGetCurrentIrpStackLocation(OriginalIrp);
    UCHAR majorFunc = origCurSp->MajorFunction;
    LARGE_INTEGER logicalBlockAddr;
    ULONG numTransferBlocks;
    PCDB pCdb;

    logicalBlockAddr.QuadPart = Int64ShrlMod32(DiskLocation.QuadPart, fdoExt->SectorShift);
    numTransferBlocks = Len >> fdoExt->SectorShift;

    /*
     * This field is useful when debugging, since low-memory conditions are
     * handled differently for CDROM (which is the only driver using StartIO)
     */
    Pkt->DriverUsesStartIO = (commonExtension->DriverExtension->InitData.ClassStartIo != NULL);

    /*
     *  Slap the constant SRB fields in from our pre-initialized template.
     *  We'll then only have to fill in the unique fields for this transfer.
     *  Tell lower drivers to sort the SRBs by the logical block address
     *  so that disk seeks are minimized.
     */
    Pkt->Srb = fdoData->SrbTemplate;    // copies _contents_ of SRB blocks
    Pkt->Srb.DataBuffer = Buf;
    Pkt->Srb.DataTransferLength = Len;
    Pkt->Srb.QueueSortKey = logicalBlockAddr.LowPart;
    if (logicalBlockAddr.QuadPart > 0xFFFFFFFF) {
        //
        // If the requested LBA is more than max ULONG set the
        // QueueSortKey to the maximum value, so that these
        // requests can be added towards the end of the queue.
        //

        Pkt->Srb.QueueSortKey = 0xFFFFFFFF;
    }
    Pkt->Srb.OriginalRequest = Pkt->Irp;
    Pkt->Srb.SenseInfoBuffer = &Pkt->SrbErrorSenseData;
    //
    // Temporarily disable timeout calculation based on transfer size due to
    // the large default timeout value.
    //
    Pkt->Srb.TimeOutValue = fdoExt->TimeOutValue;
//    Pkt->Srb.TimeOutValue = (Len/0x10000) + ((Len%0x10000) ? 1 : 0);
//    Pkt->Srb.TimeOutValue *= fdoExt->TimeOutValue;

    /*
     *  Arrange values in CDB in big-endian format.
     */
    pCdb = (PCDB)Pkt->Srb.Cdb;
    if (TEST_FLAG(fdoExt->DeviceFlags, DEV_USE_16BYTE_CDB)) {
        REVERSE_BYTES_QUAD(&pCdb->CDB16.LogicalBlock, &logicalBlockAddr);
        REVERSE_BYTES(&pCdb->CDB16.TransferLength, &numTransferBlocks);
        pCdb->CDB16.OperationCode = (majorFunc==IRP_MJ_READ) ? SCSIOP_READ16 : SCSIOP_WRITE16;
        Pkt->Srb.CdbLength = 16;
    } else {
        pCdb->CDB10.LogicalBlockByte0 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte3;
        pCdb->CDB10.LogicalBlockByte1 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte2;
        pCdb->CDB10.LogicalBlockByte2 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte1;
        pCdb->CDB10.LogicalBlockByte3 = ((PFOUR_BYTE)&logicalBlockAddr.LowPart)->Byte0;
        pCdb->CDB10.TransferBlocksMsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte1;
        pCdb->CDB10.TransferBlocksLsb = ((PFOUR_BYTE)&numTransferBlocks)->Byte0;
        pCdb->CDB10.OperationCode = (majorFunc==IRP_MJ_READ) ? SCSIOP_READ : SCSIOP_WRITE;
    }

    /*
     *  Set SRB and IRP flags
     */
    Pkt->Srb.SrbFlags = fdoExt->SrbFlags;
    if (TEST_FLAG(OriginalIrp->Flags, IRP_PAGING_IO) ||
        TEST_FLAG(OriginalIrp->Flags, IRP_SYNCHRONOUS_PAGING_IO)){
        SET_FLAG(Pkt->Srb.SrbFlags, SRB_CLASS_FLAGS_PAGING);
    }
    SET_FLAG(Pkt->Srb.SrbFlags, (majorFunc==IRP_MJ_READ) ? SRB_FLAGS_DATA_IN : SRB_FLAGS_DATA_OUT);

    /*
     *  Allow caching only if this is not a write-through request.
     *  If write-through and caching is enabled on the device, force
     *  media access.
     *  Ignore SL_WRITE_THROUGH for reads; it's only set because the file handle was opened with WRITE_THROUGH.
     */
    if ((majorFunc == IRP_MJ_WRITE) && TEST_FLAG(origCurSp->Flags, SL_WRITE_THROUGH))
    {
        pCdb->CDB10.ForceUnitAccess = fdoExt->CdbForceUnitAccess;
    }
    else {
        SET_FLAG(Pkt->Srb.SrbFlags, SRB_FLAGS_ADAPTER_CACHE_ENABLE);
    }

    /*
     *  Remember the buf and len in the SRB because miniports
     *  can overwrite SRB.DataTransferLength and we may need it again
     *  for the retry.
     */
    Pkt->BufPtrCopy = Buf;
    Pkt->BufLenCopy = Len;
    Pkt->TargetLocationCopy = DiskLocation;

    Pkt->OriginalIrp = OriginalIrp;
    Pkt->NumRetries = NUM_IO_RETRIES;
    Pkt->SyncEventPtr = NULL;
    Pkt->CompleteOriginalIrpWhenLastPacketCompletes = TRUE;

    
    DBGLOGFLUSHINFO(fdoData, TRUE, (BOOLEAN)(pCdb->CDB10.ForceUnitAccess), FALSE);
}
コード例 #6
0
VOID
ImScsiDispatchWork(
__in pMP_WorkRtnParms        pWkRtnParms
)
{
    pHW_HBA_EXT               pHBAExt = pWkRtnParms->pHBAExt;
    pHW_LU_EXTENSION          pLUExt = pWkRtnParms->pLUExt;
    PSCSI_REQUEST_BLOCK       pSrb = pWkRtnParms->pSrb;
    PETHREAD                  pReqThread = pWkRtnParms->pReqThread;
    PCDB                      pCdb = (PCDB)pSrb->Cdb;

    KdPrint2(("PhDskMnt::ImScsiDispatchWork Action: 0x%X, pSrb: 0x%p, pSrb->DataBuffer: 0x%p pSrb->DataTransferLength: 0x%X\n",
        (int)pSrb->Cdb[0], pSrb, pSrb->DataBuffer, pSrb->DataTransferLength));

    switch (pSrb->Function)
    {
    case SRB_FUNCTION_IO_CONTROL:
    {
        PSRB_IO_CONTROL srb_io_control = (PSRB_IO_CONTROL)pSrb->DataBuffer;

        switch (srb_io_control->ControlCode)
        {
        case SMP_IMSCSI_CREATE_DEVICE:
        {                       // Create new?
            KIRQL lowest_assumed_irql = PASSIVE_LEVEL;

            KdPrint(("PhDskMnt::ImScsiDispatchWork: Request to create new device.\n"));

            ImScsiCreateLU(pHBAExt, pSrb, pReqThread, &lowest_assumed_irql);

            ObDereferenceObject(pReqThread);
        }
        break;

        default:
            break;
        }
    }
    break;

    case SRB_FUNCTION_EXECUTE_SCSI:
        switch (pSrb->Cdb[0])
        {
        case SCSIOP_READ:
        case SCSIOP_WRITE:
        case SCSIOP_READ16:
        case SCSIOP_WRITE16:
        {
            // Read/write?
            PVOID sysaddress;
            PVOID buffer;
            ULONG status;
            LARGE_INTEGER startingSector;
            LARGE_INTEGER startingOffset;
            KLOCK_QUEUE_HANDLE LockHandle;
            KIRQL lowest_assumed_irql = PASSIVE_LEVEL;

            if ((pCdb->AsByte[0] == SCSIOP_READ16) |
                (pCdb->AsByte[0] == SCSIOP_WRITE16))
            {
                REVERSE_BYTES_QUAD(&startingSector, pCdb->CDB16.LogicalBlock);
            }
            else
            {
                startingSector.QuadPart = 0;
                REVERSE_BYTES(&startingSector, &pCdb->CDB10.LogicalBlockByte0);
            }

            startingOffset.QuadPart = startingSector.QuadPart << pLUExt->BlockPower;

            KdPrint2(("PhDskMnt::ImScsiDispatchWork starting sector: 0x%I64X\n", startingSector));

            status = StoragePortGetSystemAddress(pHBAExt, pSrb, &sysaddress);

            if ((status != STORAGE_STATUS_SUCCESS) | (sysaddress == NULL))
            {
                DbgPrint("PhDskMnt::ImScsiDispatchWork: StorPortGetSystemAddress failed: status=0x%X address=0x%p translated=0x%p\n",
                    status,
                    pSrb->DataBuffer,
                    sysaddress);

                pSrb->SrbStatus = SRB_STATUS_ERROR;
                pSrb->ScsiStatus = SCSISTAT_GOOD;

                break;
            }

            buffer = ExAllocatePoolWithTag(NonPagedPool, pSrb->DataTransferLength, MP_TAG_GENERAL);

            if (buffer == NULL)
            {
                DbgPrint("PhDskMnt::ImScsiDispatchWork: Memory allocation failed.\n");

                pSrb->SrbStatus = SRB_STATUS_ERROR;
                pSrb->ScsiStatus = SCSISTAT_GOOD;

                break;
            }
            else
            {
                NTSTATUS status = STATUS_NOT_IMPLEMENTED;

                /// For write operations, prepare temporary buffer
                if ((pSrb->Cdb[0] == SCSIOP_WRITE) | (pSrb->Cdb[0] == SCSIOP_WRITE16))
                {
                    RtlMoveMemory(buffer, sysaddress, pSrb->DataTransferLength);
                }

                if ((pSrb->Cdb[0] == SCSIOP_READ) | (pSrb->Cdb[0] == SCSIOP_READ16))
                {
                    status = ImScsiReadDevice(pLUExt, buffer, &startingOffset, &pSrb->DataTransferLength);
                }
                else if ((pSrb->Cdb[0] == SCSIOP_WRITE) | (pSrb->Cdb[0] == SCSIOP_WRITE16))
                {
                    status = ImScsiWriteDevice(pLUExt, buffer, &startingOffset, &pSrb->DataTransferLength);
                }

                if (!NT_SUCCESS(status))
                {
                    ExFreePoolWithTag(buffer, MP_TAG_GENERAL);

                    DbgPrint("PhDskMnt::ImScsiDispatchWork: I/O error status=0x%X\n", status);
                    switch (status)
                    {
                    case STATUS_INVALID_BUFFER_SIZE:
                    {
                        DbgPrint("PhDskMnt::ImScsiDispatchWork: STATUS_INVALID_BUFFER_SIZE from image I/O. Reporting SCSI_SENSE_ILLEGAL_REQUEST/SCSI_ADSENSE_INVALID_CDB/0x00.\n");
                        ScsiSetCheckCondition(
                            pSrb,
                            SRB_STATUS_ERROR,
                            SCSI_SENSE_ILLEGAL_REQUEST,
                            SCSI_ADSENSE_INVALID_CDB,
                            0);
                        break;
                    }
                    case STATUS_DEVICE_BUSY:
                    {
                        DbgPrint("PhDskMnt::ImScsiDispatchWork: STATUS_DEVICE_BUSY from image I/O. Reporting SRB_STATUS_BUSY/SCSI_SENSE_NOT_READY/SCSI_ADSENSE_LUN_NOT_READY/SCSI_SENSEQ_BECOMING_READY.\n");
                        ScsiSetCheckCondition(
                            pSrb,
                            SRB_STATUS_BUSY,
                            SCSI_SENSE_NOT_READY,
                            SCSI_ADSENSE_LUN_NOT_READY,
                            SCSI_SENSEQ_BECOMING_READY
                            );
                        break;
                    }
                    default:
                    {
                        ScsiSetError(pSrb, SRB_STATUS_PARITY_ERROR);
                        break;
                    }
                    }

                    break;
                }

                /// Fake random disk signature in case mounted read-only, 0xAA55 at end of mbr and 0x00000000 in disk id field.
                /// Compatibility fix for mounting Windows Backup vhd files in read-only.
                if ((pLUExt->FakeDiskSignature != 0) &&
                    ((pSrb->Cdb[0] == SCSIOP_READ) |
                    (pSrb->Cdb[0] == SCSIOP_READ16)) &&
                    (startingSector.QuadPart == 0) &&
                    (pSrb->DataTransferLength >= 512) &&
                    (pLUExt->ReadOnly))
                {
                    PUCHAR mbr = (PUCHAR)buffer;

                    if ((*(PUSHORT)(mbr + 0x01FE) == 0xAA55) &
                        (*(PUSHORT)(mbr + 0x01BC) == 0x0000) &
                        ((*(mbr + 0x01BE) & 0x7F) == 0x00) &
                        ((*(mbr + 0x01CE) & 0x7F) == 0x00) &
                        ((*(mbr + 0x01DE) & 0x7F) == 0x00) &
                        ((*(mbr + 0x01EE) & 0x7F) == 0x00) &
                        ((*(PULONG)(mbr + 0x01B8) == 0x00000000UL)))
                    {
                        DbgPrint("PhDskMnt::ImScsiDispatchWork: Faking disk signature as %#X.\n", pLUExt->FakeDiskSignature);

                        *(PULONG)(mbr + 0x01B8) = pLUExt->FakeDiskSignature;
                    }
                }

                /// For write operations, temporary buffer holds read data.
                /// Copy that to system buffer.
                if ((pSrb->Cdb[0] == SCSIOP_READ) | (pSrb->Cdb[0] == SCSIOP_READ16))
                {
                    RtlMoveMemory(sysaddress, buffer, pSrb->DataTransferLength);
                }
            }

            ImScsiAcquireLock(&pLUExt->LastIoLock, &LockHandle, lowest_assumed_irql);

            if (pLUExt->LastIoBuffer != NULL)
                ExFreePoolWithTag(pLUExt->LastIoBuffer, MP_TAG_GENERAL);

            pLUExt->LastIoStartSector = startingSector.QuadPart;
            pLUExt->LastIoLength = pSrb->DataTransferLength;
            pLUExt->LastIoBuffer = buffer;

            ImScsiReleaseLock(&LockHandle, &lowest_assumed_irql);

            ScsiSetSuccess(pSrb, pSrb->DataTransferLength);
        }
        break;

        default:
        {
            DbgPrint("PhDskMnt::ImScsiDispatchWork unknown function: 0x%X\n", (int)pSrb->Cdb[0]);

            ScsiSetError(pSrb, SRB_STATUS_INTERNAL_ERROR);
        }
        }

    default:
        break;
    }

    KdPrint2(("PhDskMnt::ImScsiDispatchWork: End pSrb: 0x%p.\n", pSrb));

}                                                     // End ImScsiDispatchWork().