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)); }
/* * 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; }
/* * 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; }
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; }
/* * 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); }
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().