|
|
/*++
Copyright (C) 1990 - 99 Microsoft Corporation
Module Name:
port.c
Abstract:
Ide bus enumeration
Authors:
Mike Glass Jeff Havens Joe Dai
Environment:
kernel mode only
Revision History:
--*/
#include "ideport.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(NONPAGE, IssueSyncAtapiCommand)
#pragma alloc_text(NONPAGE, IssueSyncAtapiCommandSafe)
#pragma alloc_text(NONPAGE, IdePortDmaCdromDrive)
//#pragma alloc_text(PAGESCAN, IdePortDmaCdromDrive)
#pragma alloc_text(PAGE, IdePortInitFdo)
#pragma alloc_text(PAGE, IssueInquirySafe)
#pragma alloc_text(PAGE, IdePortQueryNonCdNumLun)
#pragma alloc_text(PAGE, IdeBuildDeviceMap)
#pragma alloc_text(PAGE, IdeCreateNumericKey)
extern LONG IdePAGESCANLockCount; #endif
static PWCHAR IdePortUserRegistryDeviceTypeName[MAX_IDE_DEVICE * MAX_IDE_LINE] = { USER_MASTER_DEVICE_TYPE_REG_KEY, USER_SLAVE_DEVICE_TYPE_REG_KEY, USER_MASTER_DEVICE_TYPE2_REG_KEY, USER_SLAVE_DEVICE_TYPE2_REG_KEY };
static PWCHAR IdePortRegistryUserDeviceTimingModeAllowedName[MAX_IDE_DEVICE * MAX_IDE_LINE] = { USER_MASTER_DEVICE_TIMING_MODE_ALLOWED, USER_SLAVE_DEVICE_TIMING_MODE_ALLOWED, USER_MASTER_DEVICE_TIMING_MODE_ALLOWED2, USER_SLAVE_DEVICE_TIMING_MODE_ALLOWED2 };
//
// Idle Timeout
//
//ULONG PdoConservationIdleTime = -1;
//ULONG PdoPerformanceIdleTime = -1;
NTSTATUS IdePortInitFdo( IN OUT PFDO_EXTENSION FdoExtension ) /*++
Routine Description:
This routine enumerates the IDE bus and initialize the fdo extension
Arguments:
FdoExtension - FDO extension
RegistryPath - registry path passed in via DriverEntry
Return Value:
--*/
{ PFDO_EXTENSION fdoExtension = FdoExtension; NTSTATUS status; PDEVICE_OBJECT deviceObject; ULONG uniqueId; KIRQL irql; PIO_SCSI_CAPABILITIES capabilities; PIO_ERROR_LOG_PACKET errorLogEntry; ULONG i; ULONG j; BOOLEAN ideDeviceFound;
status = STATUS_SUCCESS; deviceObject = fdoExtension->DeviceObject;
//
// Save the dependent driver routines in the device extension.
//
fdoExtension->HwDeviceExtension = (PVOID)(fdoExtension + 1);
//
// Mark this object as supporting direct I/O so that I/O system
// will supply mdls in irps.
//
deviceObject->Flags |= DO_DIRECT_IO;
//
// Initialize the maximum lu count variable.
//
fdoExtension->MaxLuCount = SCSI_MAXIMUM_LOGICAL_UNITS;
//
// Allocate spin lock for critical sections.
//
KeInitializeSpinLock(&fdoExtension->SpinLock);
//
// Spinlock that protects LogicalUnitList manipulation
//
KeInitializeSpinLock(&fdoExtension->LogicalUnitListSpinLock);
//
// Initialize DPC routine.
//
IoInitializeDpcRequest(deviceObject, IdePortCompletionDpc);
//
// Initialize the port timeout counter.
//
fdoExtension->PortTimeoutCounter = PD_TIMER_STOPPED;
//
// Initialize timer.
//
IoInitializeTimer(deviceObject, IdePortTickHandler, NULL);
//
// Initialize miniport timer and timer DPC.
//
KeInitializeTimer(&fdoExtension->MiniPortTimer); KeInitializeDpc(&fdoExtension->MiniPortTimerDpc, IdeMiniPortTimerDpc, deviceObject );
//
// Start timer. Request timeout counters
// in the logical units have already been
// initialized.
//
IoStartTimer(deviceObject); fdoExtension->Flags |= PD_DISCONNECT_RUNNING;
//
// Check to see if an error was logged.
//
if (fdoExtension->InterruptData.InterruptFlags & PD_LOG_ERROR) {
CLRMASK (fdoExtension->InterruptData.InterruptFlags, PD_LOG_ERROR | PD_NOTIFICATION_REQUIRED); LogErrorEntry(fdoExtension, &fdoExtension->InterruptData.LogEntry); }
//
// Initialize the capabilities pointer.
//
capabilities = &fdoExtension->Capabilities;
//
// Initailize the capabilities structure.
//
capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
if (fdoExtension->BoundWithBmParent) {
if (fdoExtension->HwDeviceExtension->BusMasterInterface.MaxTransferByteSize < MAX_TRANSFER_SIZE_PER_SRB) {
capabilities->MaximumTransferLength = fdoExtension->HwDeviceExtension->BusMasterInterface.MaxTransferByteSize;
} else {
capabilities->MaximumTransferLength = MAX_TRANSFER_SIZE_PER_SRB; } } else {
capabilities->MaximumTransferLength = MAX_TRANSFER_SIZE_PER_SRB; }
capabilities->TaggedQueuing = FALSE; capabilities->AdapterScansDown = FALSE; capabilities->AlignmentMask = deviceObject->AlignmentRequirement; capabilities->MaximumPhysicalPages = BYTES_TO_PAGES(capabilities->MaximumTransferLength);
if (fdoExtension->IdeResource.TranslatedCommandBaseAddress) { DebugPrint((1, "IdePort: Initialize: Translated IO Base address %x\n", fdoExtension->IdeResource.TranslatedCommandBaseAddress)); }
for (i=0; i< MAX_IDE_DEVICE * MAX_IDE_LINE; i++) {
fdoExtension->UserChoiceDeviceType[i] = DeviceUnknown; IdePortGetDeviceParameter ( fdoExtension, IdePortUserRegistryDeviceTypeName[i], (PULONG)(fdoExtension->UserChoiceDeviceType + i) );
}
//
// the acpi _GTM buffer should be initialized with -1s
//
for (i=0; i<MAX_IDE_DEVICE; i++) {
PACPI_IDE_TIMING timingSettings = &(FdoExtension->BootAcpiTimingSettings); timingSettings->Speed[i].Pio = ACPI_XFER_MODE_NOT_SUPPORT; timingSettings->Speed[i].Dma = ACPI_XFER_MODE_NOT_SUPPORT; }
fdoExtension->DmaDetectionLevel = DdlFirmwareOk; IdePortGetDeviceParameter ( fdoExtension, DMA_DETECTION_LEVEL_REG_KEY, (PULONG)&fdoExtension->DmaDetectionLevel );
//
// non-pcmcia controller, MayHaveSlaveDevice is always set
// if pcmcia controller, it is not set unless
// registry flag PCMCIA_IDE_CONTROLLER_HAS_SLAVE
// is non-zero
//
if (!ChannelQueryPcmciaParent (fdoExtension)) { fdoExtension->MayHaveSlaveDevice = 1; } else { fdoExtension->MayHaveSlaveDevice = 0; IdePortGetDeviceParameter ( fdoExtension, PCMCIA_IDE_CONTROLLER_HAS_SLAVE, (PULONG)&fdoExtension->MayHaveSlaveDevice ); }
#ifdef ENABLE_ATAPI_VERIFIER
ViIdeInitVerifierSettings(fdoExtension); #endif
return status;
} // IdePortInitFdo
NTSTATUS SyncAtapiSafeCompletion ( PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context ) { PSYNC_ATA_PASSTHROUGH_CONTEXT context = Context;
context->Status = Irp->IoStatus.Status;
KeSetEvent (&context->Event, 0, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED; }
NTSTATUS IssueSyncAtapiCommandSafe ( IN PFDO_EXTENSION FdoExtension, IN PPDO_EXTENSION PdoExtension, IN PCDB Cdb, IN PVOID DataBuffer, IN ULONG DataBufferSize, IN BOOLEAN DataIn, IN ULONG RetryCount, IN BOOLEAN ByPassBlockedQueue
) /*++
Routine Description:
Build IRP, SRB and CDB for the given CDB
Send and wait for the IRP to complete
Arguments:
FdoExtension - FDO extension
PdoExtension - device extension of the PDO to which the command is sent
Cdb - Command Descriptor Block
DataBuffer - data buffer for the command
DataBufferSize - byte size of DataBuffer
DataIn - TRUE is the command causes the device to return data
RetryCount - number of times to retry the command if the command fails
Return Value:
NTSTATUS
If any of the pre-alloc related operation fails, it returns STATUS_INSUFFICIENT_RESOURCES The caller should take care of the condition
--*/ { PIRP irp; PIO_STACK_LOCATION irpStack; PSCSI_REQUEST_BLOCK srb; KEVENT event; IO_STATUS_BLOCK ioStatusBlock; KIRQL currentIrql; NTSTATUS status; ULONG flushCount;
PSENSE_DATA senseInfoBuffer; UCHAR senseInfoBufferSize; PENUMERATION_STRUCT enumStruct; SYNC_ATA_PASSTHROUGH_CONTEXT context; ULONG locked;
ASSERT(InterlockedCompareExchange(&(FdoExtension->EnumStructLock), 1, 0) == 0);
enumStruct=FdoExtension->PreAllocEnumStruct;
if (enumStruct == NULL) { ASSERT(FdoExtension->PreAllocEnumStruct); return STATUS_INSUFFICIENT_RESOURCES; }
senseInfoBufferSize = SENSE_BUFFER_SIZE; senseInfoBuffer = enumStruct->SenseInfoBuffer;
ASSERT (senseInfoBuffer);
DebugPrint((1, "Using Sync Atapi safe!\n"));
srb= enumStruct->Srb;
ASSERT(srb);
status = STATUS_UNSUCCESSFUL; RetryCount = 5; flushCount = 100; irp = enumStruct->Irp1;
ASSERT (irp);
ASSERT (enumStruct->DataBufferSize >= DataBufferSize);
while (!NT_SUCCESS(status) && RetryCount--) {
//
// Initialize the notification event.
//
KeInitializeEvent(&context.Event, NotificationEvent, FALSE);
IoInitializeIrp(irp, IoSizeOfIrp(PREALLOC_STACK_LOCATIONS), PREALLOC_STACK_LOCATIONS);
irp->MdlAddress = enumStruct->MdlAddress;
irpStack = IoGetNextIrpStackLocation(irp); irpStack->MajorFunction = IRP_MJ_SCSI;
if (DataBuffer) { RtlCopyMemory(enumStruct->DataBuffer, DataBuffer, DataBufferSize); } RtlZeroMemory(srb, sizeof(SCSI_REQUEST_BLOCK));
irpStack->Parameters.Scsi.Srb = srb;
srb->PathId = PdoExtension->PathId; srb->TargetId = PdoExtension->TargetId; srb->Lun = PdoExtension->Lun;
srb->Function = SRB_FUNCTION_EXECUTE_SCSI; srb->Length = sizeof(SCSI_REQUEST_BLOCK);
//
// Set flags to disable synchronous negociation.
//
srb->SrbFlags = DataIn ? SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER : SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
if (ByPassBlockedQueue) { srb->SrbFlags |= SRB_FLAGS_BYPASS_FROZEN_QUEUE; }
srb->SrbStatus = srb->ScsiStatus = 0;
srb->NextSrb = 0;
srb->OriginalRequest = irp;
//
// Set timeout to 4 seconds.
//
srb->TimeOutValue = 4;
srb->CdbLength = 6;
//
// Enable auto request sense.
//
srb->SenseInfoBuffer = senseInfoBuffer; srb->SenseInfoBufferLength = senseInfoBufferSize;
srb->DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress); srb->DataTransferLength = DataBufferSize;
//
// Set CDB operation code.
//
RtlCopyMemory(srb->Cdb, Cdb, sizeof(CDB));
IoSetCompletionRoutine( irp, SyncAtapiSafeCompletion, &context, TRUE, TRUE, TRUE );
//
// Wait for request to complete.
//
if (IoCallDriver(PdoExtension->DeviceObject, irp) == STATUS_PENDING) {
KeWaitForSingleObject(&context.Event, Executive, KernelMode, FALSE, NULL); }
RtlCopyMemory(DataBuffer, srb->DataBuffer, DataBufferSize);
if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
DebugPrint((1,"IssueSyncAtapiCommand: atapi command failed SRB status %x\n", srb->SrbStatus));
if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_REQUEST_FLUSHED) { //
// we will give it a few more retries if our request
// got flushed.
//
flushCount--; if (flushCount) { RetryCount++; } } if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
status = STATUS_DATA_OVERRUN;
} else {
status = STATUS_UNSUCCESSFUL; }
//
// Unfreeze queue if necessary
//
if (srb->SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
DebugPrint((3, "IssueSyncAtapiCommand: Unfreeze Queue TID %d\n", srb->TargetId));
//
// unfreeze queue
//
CLRMASK (PdoExtension->LuFlags, PD_QUEUE_FROZEN);
//
// restart queue
//
KeAcquireSpinLock(&FdoExtension->SpinLock, ¤tIrql); GetNextLuRequest(FdoExtension, PdoExtension); KeLowerIrql(currentIrql); }
if ((srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && (senseInfoBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)) {
//
// A sense key of illegal request was recieved. This indicates
// that the mech status command is illegal.
//
status = STATUS_INVALID_DEVICE_REQUEST;
//
// The command is illegal, no point to keep trying
//
RetryCount = 0; }
} else {
status = STATUS_SUCCESS; } }
if (flushCount != 100) { DebugPrint ((DBG_ALWAYS, "IssueSyncAtapiCommand: flushCount is %u\n", flushCount)); }
//
// Unlock
//
ASSERT(InterlockedCompareExchange(&(FdoExtension->EnumStructLock), 0, 1) == 1);
return status;
} // IssueSyncAtapiCommandSafe
BOOLEAN IdePortDmaCdromDrive( IN PFDO_EXTENSION FdoExtension, IN PPDO_EXTENSION PdoExtension, IN BOOLEAN LowMem ) /*++
Routine Description:
Build IRP, SRB and CDB for SCSI MODE_SENSE10 command.
Arguments:
DeviceExtension - address of adapter's device object extension. LowMem - Low memory condition, use the safe (but not thread-safe) version - This should be one only when called during enumeration.
Return Value:
NTSTATUS
--*/ { CDB cdb; NTSTATUS status; BOOLEAN isDVD = FALSE; ULONG bufLength; ULONG capPageOffset; PMODE_PARAMETER_HEADER10 modePageHeader; PCDVD_CAPABILITIES_PAGE capPage;
/*
//
// Code is paged until locked down.
//
PAGED_CODE();
#ifdef ALLOC_PRAGMA
ASSERT(IdePAGESCANLockCount > 0); #endif
*/
RtlZeroMemory(&cdb, sizeof(CDB));
bufLength = sizeof(CDVD_CAPABILITIES_PAGE) + sizeof(MODE_PARAMETER_HEADER10);
capPageOffset = sizeof(MODE_PARAMETER_HEADER10);
cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; cdb.MODE_SENSE10.Dbd = 1; cdb.MODE_SENSE10.PageCode = MODE_PAGE_CAPABILITIES; cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR)(bufLength >> 8); cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR)(bufLength >> 0);
modePageHeader = ExAllocatePool(NonPagedPoolCacheAligned, bufLength);
if (modePageHeader) {
RtlZeroMemory(modePageHeader, bufLength);
if (LowMem) { status = IssueSyncAtapiCommandSafe ( FdoExtension, PdoExtension, &cdb, modePageHeader, bufLength, TRUE, INQUIRY_RETRY_COUNT, TRUE ); } else { status = IssueSyncAtapiCommand ( FdoExtension, PdoExtension, &cdb, modePageHeader, bufLength, TRUE, INQUIRY_RETRY_COUNT, TRUE ); }
if (NT_SUCCESS(status) || (status == STATUS_DATA_OVERRUN)) {
capPage = (PCDVD_CAPABILITIES_PAGE) (((PUCHAR) modePageHeader) + capPageOffset);
if ((capPage->PageCode == MODE_PAGE_CAPABILITIES) && (capPage->CDRWrite || capPage->CDEWrite || capPage->DVDROMRead || capPage->DVDRRead || capPage->DVDRAMRead || capPage->DVDRWrite || capPage->DVDRAMWrite)) {
isDVD=TRUE; } } ExFreePool (modePageHeader); }
return isDVD; }
NTSTATUS IssueInquirySafe( IN PFDO_EXTENSION FdoExtension, IN PPDO_EXTENSION PdoExtension, OUT PINQUIRYDATA InquiryData, IN BOOLEAN LowMem ) /*++
Routine Description:
Build IRP, SRB and CDB for SCSI INQUIRY command.
Arguments:
DeviceExtension - address of adapter's device object extension. LunInfo - address of buffer for INQUIRY information. LowMem - Low memory condition, use the safe (but not thread-safe) version - This should be one only when called during enumeration.
Return Value:
NTSTATUS
--*/ { CDB cdb; NTSTATUS status;
PAGED_CODE();
RtlZeroMemory(InquiryData, sizeof(*InquiryData));
RtlZeroMemory(&cdb, sizeof(CDB));
cdb.CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
//
// Set CDB LUN.
//
cdb.CDB6INQUIRY.LogicalUnitNumber = PdoExtension->Lun; cdb.CDB6INQUIRY.Reserved1 = 0;
//
// Set allocation length to inquiry data buffer size.
//
cdb.CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
//
// Zero reserve field and
// Set EVPD Page Code to zero.
// Set Control field to zero.
// (See SCSI-II Specification.)
//
cdb.CDB6INQUIRY.PageCode = 0; cdb.CDB6INQUIRY.IReserved = 0; cdb.CDB6INQUIRY.Control = 0;
if (LowMem ) {
// Use the memory safe one
status = IssueSyncAtapiCommandSafe ( FdoExtension, PdoExtension, &cdb, InquiryData, INQUIRYDATABUFFERSIZE, TRUE, INQUIRY_RETRY_COUNT, FALSE ); } else {
// Use the thread safe one
status = IssueSyncAtapiCommand ( FdoExtension, PdoExtension, &cdb, InquiryData, INQUIRYDATABUFFERSIZE, TRUE, INQUIRY_RETRY_COUNT, FALSE ); }
return status;
} // IssueInquiry
NTSTATUS IssueSyncAtapiCommand ( IN PFDO_EXTENSION FdoExtension, IN PPDO_EXTENSION PdoExtension, IN PCDB Cdb, IN PVOID DataBuffer, IN ULONG DataBufferSize, IN BOOLEAN DataIn, IN ULONG RetryCount, IN BOOLEAN ByPassBlockedQueue
) /*++
Routine Description:
Build IRP, SRB and CDB for the given CDB
Send and wait for the IRP to complete
Arguments:
FdoExtension - FDO extension
PdoExtension - device extension of the PDO to which the command is sent
Cdb - Command Descriptor Block
DataBuffer - data buffer for the command
DataBufferSize - byte size of DataBuffer
DataIn - TRUE is the command causes the device to return data
RetryCount - number of times to retry the command if the command fails
Return Value:
NTSTATUS
--*/ { PIRP irp; PIO_STACK_LOCATION irpStack; SCSI_REQUEST_BLOCK srb; KEVENT event; IO_STATUS_BLOCK ioStatusBlock; KIRQL currentIrql; NTSTATUS status; ULONG flushCount;
PSENSE_DATA senseInfoBuffer; UCHAR senseInfoBufferSize;
//
// Sense buffer is in non-paged pool.
//
senseInfoBufferSize = SENSE_BUFFER_SIZE; senseInfoBuffer = ExAllocatePool( NonPagedPoolCacheAligned, senseInfoBufferSize);
if (senseInfoBuffer == NULL) { DebugPrint((1,"IssueSyncAtapiCommand: Can't allocate request sense buffer\n")); IdeLogNoMemoryError(FdoExtension, PdoExtension->TargetId, NonPagedPoolCacheAligned, senseInfoBufferSize, IDEPORT_TAG_SYNCATAPI_SENSE );
return(STATUS_INSUFFICIENT_RESOURCES); }
status = STATUS_UNSUCCESSFUL; RetryCount = 5; flushCount = 100; while (!NT_SUCCESS(status) && RetryCount--) {
//
// Initialize the notification event.
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// Build IRP for this request.
//
irp = IoBuildDeviceIoControlRequest( DataIn ? IOCTL_SCSI_EXECUTE_IN : IOCTL_SCSI_EXECUTE_OUT, FdoExtension->DeviceObject, DataBuffer, DataBufferSize, DataBuffer, DataBufferSize, TRUE, &event, &ioStatusBlock);
if (!irp) {
RetryCount = 0; IdeLogNoMemoryError(FdoExtension, PdoExtension->TargetId, NonPagedPool, IoSizeOfIrp(FdoExtension->DeviceObject->StackSize), IDEPORT_TAG_SYNCATAPI_IRP );
status = STATUS_INSUFFICIENT_RESOURCES; break; }
irpStack = IoGetNextIrpStackLocation(irp);
//
// Fill in SRB fields.
//
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
irpStack->Parameters.Scsi.Srb = &srb;
srb.PathId = PdoExtension->PathId; srb.TargetId = PdoExtension->TargetId; srb.Lun = PdoExtension->Lun;
srb.Function = SRB_FUNCTION_EXECUTE_SCSI; srb.Length = sizeof(SCSI_REQUEST_BLOCK);
//
// Set flags to disable synchronous negociation.
//
srb.SrbFlags = DataIn ? SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER : SRB_FLAGS_DATA_OUT | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
if (ByPassBlockedQueue) { srb.SrbFlags |= SRB_FLAGS_BYPASS_FROZEN_QUEUE; }
srb.SrbStatus = srb.ScsiStatus = 0;
srb.NextSrb = 0;
srb.OriginalRequest = irp;
//
// Set timeout to 4 seconds.
//
srb.TimeOutValue = 4;
srb.CdbLength = 6;
//
// Enable auto request sense.
//
srb.SenseInfoBuffer = senseInfoBuffer; srb.SenseInfoBufferLength = senseInfoBufferSize;
srb.DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress); srb.DataTransferLength = DataBufferSize;
//
// Set CDB operation code.
//
RtlCopyMemory(srb.Cdb, Cdb, sizeof(CDB));
//
// Wait for request to complete.
//
if (IoCallDriver(PdoExtension->DeviceObject, irp) == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); }
if (SRB_STATUS(srb.SrbStatus) != SRB_STATUS_SUCCESS) {
DebugPrint((1,"IssueSyncAtapiCommand: atapi command failed SRB status %x\n", srb.SrbStatus));
if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_REQUEST_FLUSHED) { //
// we will give it a few more retries if our request
// got flushed.
//
flushCount--; if (flushCount) { RetryCount++; } } if (SRB_STATUS(srb.SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
status = STATUS_DATA_OVERRUN;
} else {
status = STATUS_UNSUCCESSFUL; // if (SRB_STATUS(srb.SrbStatus) != SRB_STATUS_REQUEST_FLUSHED) {
// if (srb.Lun == 0 && Cdb->CDB6INQUIRY.OperationCode == SCSIOP_INQUIRY) {
// DebugPrint ((DBG_ALWAYS, "IssueSyncAtapiCommand: inquiry on lun 0 returned unexpected error: srb, status = 0x%x, 0x%x\n", &srb, srb.SrbStatus));
// DbgBreakPoint();
// }
// }
}
//
// Unfreeze queue if necessary
//
if (srb.SrbStatus & SRB_STATUS_QUEUE_FROZEN) {
DebugPrint((3, "IssueSyncAtapiCommand: Unfreeze Queue TID %d\n", srb.TargetId));
//
// unfreeze queue
//
CLRMASK (PdoExtension->LuFlags, PD_QUEUE_FROZEN);
//
// restart queue
//
KeAcquireSpinLock(&FdoExtension->SpinLock, ¤tIrql); GetNextLuRequest(FdoExtension, PdoExtension); KeLowerIrql(currentIrql); }
if ((srb.SrbStatus & SRB_STATUS_AUTOSENSE_VALID) && (senseInfoBuffer->SenseKey == SCSI_SENSE_ILLEGAL_REQUEST)) {
//
// A sense key of illegal request was recieved. This indicates
// that the mech status command is illegal.
//
status = STATUS_INVALID_DEVICE_REQUEST;
//
// The command is illegal, no point to keep trying
//
RetryCount = 0; }
} else {
status = STATUS_SUCCESS; } }
//
// Free buffers
//
ExFreePool(senseInfoBuffer); if (flushCount != 100) { DebugPrint ((DBG_ALWAYS, "IssueSyncAtapiCommand: flushCount is %u\n", flushCount)); }
return status;
} // IssueSyncAtapiCommand
ULONG IdePortQueryNonCdNumLun ( IN PFDO_EXTENSION FdoExtension, IN PPDO_EXTENSION PdoExtension, IN BOOLEAN ByPassBlockedQueue ) /*++
Routine Description:
query number of Luns a device has using the protocol defined in the ATAPI Removable Rewritable Spec (SFF-8070i)
Arguments:
FdoExtension - FDO extension
PdoExtension - device extension of the PDO to be queried
Return Value:
Number of logical units
--*/ { PIRP irp; PIO_STACK_LOCATION irpStack; SCSI_REQUEST_BLOCK srb; CDB cdb; IO_STATUS_BLOCK ioStatusBlock; KIRQL currentIrql; NTSTATUS status;
PMODE_PARAMETER_HEADER10 modeParameterHeader; PATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES accessCap; PATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE opMode; ULONG modePageSize; ULONG accessCapPageSize; ULONG opModePageSize;
PAGED_CODE();
if (IsNEC_98) {
PIDENTIFY_DATA fullIdentifyData;
fullIdentifyData = &FdoExtension->HwDeviceExtension->IdentifyData[PdoExtension->TargetId];
if (fullIdentifyData->GeneralConfiguration & 0x80) { if (fullIdentifyData->ModelNumber[8] == 0x44 && fullIdentifyData->ModelNumber[9] == 0x50 && fullIdentifyData->ModelNumber[10] == 0x31 && fullIdentifyData->ModelNumber[11] == 0x2D ) {
//
// Find ATAPI PD drive.
//
return 2; } } }
//
// compute the size of the mode page needed
//
accessCapPageSize = sizeof (MODE_PARAMETER_HEADER10) + sizeof (ATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES);
opModePageSize = sizeof (MODE_PARAMETER_HEADER10) + sizeof (ATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE);
if (sizeof(ATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES) >= sizeof(ATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE)) {
modePageSize = accessCapPageSize;
} else {
modePageSize = opModePageSize; }
modeParameterHeader = ExAllocatePool ( NonPagedPoolCacheAligned, modePageSize );
if (modeParameterHeader == NULL) {
DebugPrint((DBG_ALWAYS,"QueryNonCdNumLun: Can't allocate modeParameterHeader buffer\n")); return(0);
} RtlZeroMemory(modeParameterHeader, accessCapPageSize); RtlZeroMemory(&cdb, sizeof(CDB));
//
// Set CDB operation code.
//
cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; cdb.MODE_SENSE10.PageCode = ATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGECODE; cdb.MODE_SENSE10.Pc = MODE_SENSE_CURRENT_VALUES; cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR) ((accessCapPageSize & 0xff00) >> 8); cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR) ((accessCapPageSize & 0x00ff) >> 0);
//
// get the removable block access capabilities page
//
status = IssueSyncAtapiCommand ( FdoExtension, PdoExtension, &cdb, modeParameterHeader, accessCapPageSize, TRUE, 3, ByPassBlockedQueue );
accessCap = (PATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES) (modeParameterHeader + 1);
if (NT_SUCCESS(status) && (accessCap->PageCode == ATAPI_REMOVABLE_BLOCK_ACCESS_CAPABILITIES_PAGECODE)) {
DebugPrint ((DBG_PNP, "QueryNonCdNumLun: Removable Block Access Capabilities Page:\n" "page save bit: 0x%x\n" "format progress report support: 0x%x\n" "system floppy device: 0x%x\n" "total LUNs: 0x%x\n" "in single-Lun mode: 0x%x\n" "non-CD optical deivce: 0x%x\n", accessCap->PSBit, accessCap->SRFP, accessCap->SFLP, accessCap->TotalLun, accessCap->SML, accessCap->NCD ));
if (accessCap->NCD) {
//
// we have a non-CD optical deivce
//
RtlZeroMemory(modeParameterHeader, opModePageSize); RtlZeroMemory(&cdb, sizeof(CDB));
//
// Set CDB operation code.
//
cdb.MODE_SENSE10.OperationCode = SCSIOP_MODE_SENSE10; cdb.MODE_SENSE10.PageCode = ATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE_PAGECODE; cdb.MODE_SENSE10.Pc = MODE_SENSE_CURRENT_VALUES; cdb.MODE_SENSE10.AllocationLength[0] = (UCHAR) ((opModePageSize & 0xff00) >> 8); cdb.MODE_SENSE10.AllocationLength[1] = (UCHAR) ((opModePageSize & 0x00ff) >> 0);
//
// get the non-cd drive operation mode page
//
status = IssueSyncAtapiCommand ( FdoExtension, PdoExtension, &cdb, modeParameterHeader, opModePageSize, TRUE, 3, ByPassBlockedQueue );
opMode = (PATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE) (modeParameterHeader + 1);
if (NT_SUCCESS(status) && (opMode->PageCode == ATAPI_NON_CD_DRIVE_OPERATION_MODE_PAGE_PAGECODE)) {
DebugPrint ((DBG_PNP, "QueryNonCdNumLun: Non-CD device Operation Mode Page:\n" "page save bit: 0x%x\n" "disable verify for write: 0x%x\n" "Lun for R/W device: 0x%x\n" "multi-Lun mode: 0x%x\n", opMode->PSBit, opMode->DVW, opMode->SLR, opMode->SLM ));
RtlZeroMemory(modeParameterHeader, sizeof (MODE_PARAMETER_HEADER10));
//
// With mode select, this is reserved and must be 0
//
opMode->PSBit = 0;
//
// Turn on multi-lun mode
//
opMode->SLM = 1;
//
// non-CD device shall be Lun 1
//
opMode->SLR = 1;
RtlZeroMemory(&cdb, sizeof(CDB));
//
// Set CDB operation code.
//
cdb.MODE_SELECT10.OperationCode = SCSIOP_MODE_SELECT10; cdb.MODE_SELECT10.SPBit = 1; // save page
cdb.MODE_SELECT10.PFBit = 1; cdb.MODE_SELECT10.ParameterListLength[0] = (UCHAR) ((opModePageSize & 0xff00) >> 8); cdb.MODE_SELECT10.ParameterListLength[1] = (UCHAR) ((opModePageSize & 0x00ff) >> 0);
status = IssueSyncAtapiCommand ( FdoExtension, PdoExtension, &cdb, modeParameterHeader, opModePageSize, FALSE, 3, ByPassBlockedQueue );
if (!NT_SUCCESS(status)) {
DebugPrint ((DBG_ALWAYS, "IdePortQueryNonCdNumLun: Unable to set non-CD device into dual Lun Mode\n")); } } } }
//
// Free buffers
//
ExFreePool(modeParameterHeader);
if (!NT_SUCCESS(status)) {
return 0;
} else {
return 2; }
} // IdePortQueryNonCdNumLun
VOID IdeBuildDeviceMap( IN PFDO_EXTENSION FdoExtension, IN PUNICODE_STRING ServiceKey ) /*++
Routine Description:
The routine takes the inquiry data which has been collected and creates a device map for it.
Arguments:
FdoExtension - FDO extension
ServiceKey - Suppiles the name of the service key.
Return Value:
None.
--*/ {
UNICODE_STRING name; UNICODE_STRING unicodeString; ANSI_STRING ansiString; HANDLE key; HANDLE busKey; HANDLE targetKey; HANDLE lunKey; OBJECT_ATTRIBUTES objectAttributes; NTSTATUS status; ULONG disposition; PWSTR start; WCHAR buffer[32]; UCHAR lastTarget; ULONG i; ULONG dmaEnableMask; PCSTR peripheralType;
UCHAR lastBus; IDE_PATH_ID pathId; IN PPDO_EXTENSION pdoExtension;
PAGED_CODE();
//
// Create the SCSI key in the device map.
//
RtlInitUnicodeString(&name, L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
//
// Initialize the object for the key.
//
InitializeObjectAttributes(&objectAttributes, &name, OBJ_CASE_INSENSITIVE, NULL, (PSECURITY_DESCRIPTOR) NULL);
//
// Create the key or open it.
//
status = ZwCreateKey(&lunKey, KEY_READ | KEY_WRITE, &objectAttributes, 0, (PUNICODE_STRING) NULL, REG_OPTION_VOLATILE, &disposition );
if (!NT_SUCCESS(status)) { return; }
status = IdeCreateNumericKey(lunKey, FdoExtension->ScsiPortNumber, L"Scsi Port ", &key);
ZwClose(lunKey);
if (!NT_SUCCESS(status)) { return; }
#ifdef IDE_MEASURE_BUSSCAN_SPEED
RtlInitUnicodeString(&name, L"FirstBusScanTimeInMs");
status = ZwSetValueKey(key, &name, 0, REG_DWORD, &FdoExtension->BusScanTime, sizeof(ULONG));
#endif // IDE_MEASURE_BUSSCAN_SPEED
//
// Add DMA enable mask value.
//
dmaEnableMask = 0; for (i=0; i<FdoExtension->HwDeviceExtension->MaxIdeDevice; i++) {
if (FdoExtension->HwDeviceExtension->DeviceFlags[i] & DFLAGS_USE_DMA) {
dmaEnableMask |= (1 << i);
} }
RtlInitUnicodeString(&name, L"DMAEnabled");
status = ZwSetValueKey(key, &name, 0, REG_DWORD, &dmaEnableMask, 4);
//
// Add Interrupt value.
//
// if (FdoExtension->InterruptLevel) {
//
// RtlInitUnicodeString(&name, L"Interrupt");
//
// status = ZwSetValueKey(key,
// &name,
// 0,
// REG_DWORD,
// &FdoExtension->InterruptLevel,
// 4);
// }
//
// //
// // Add base IO address value.
// //
//
// if (FdoExtension->IdeResource.TranslatedCommandBaseAddress) {
//
// RtlInitUnicodeString(&name, L"IOAddress");
//
// status = ZwSetValueKey(key,
// &name,
// 0,
// REG_DWORD,
// &FdoExtension->IdeResource.TranslatedCommandBaseAddress,
// 4);
// }
if (ServiceKey != NULL) {
//
// Add identifier value. This value is equal to the name of the driver
// in the from the service key. Note the service key name is not NULL
// terminated.
//
RtlInitUnicodeString(&name, L"Driver");
//
// Get the name of the driver from the service key name.
//
start = (PWSTR) ((PCHAR) ServiceKey->Buffer + ServiceKey->Length); start--; while (*start != L'\\' && start > ServiceKey->Buffer) { start--; }
if (*start != L'\\') { ZwClose(key); return; }
start++; for (i = 0; i < 31; i++) {
buffer[i] = *start++;
if (start >= ServiceKey->Buffer + ServiceKey->Length / sizeof(wchar_t)) { break; } }
i++; buffer[i] = L'\0';
status = ZwSetValueKey(key, &name, 0, REG_SZ, buffer, (i + 1) * sizeof(wchar_t));
if (!NT_SUCCESS(status)) { ZwClose(key); return; } }
//
// Cycle through each of the lun.
//
lastBus = 0xff; pathId.l = 0; busKey = 0; targetKey = 0; lunKey = 0; while (pdoExtension = NextLogUnitExtensionWithTag ( FdoExtension, &pathId, FALSE, IdeBuildDeviceMap )) {
//
// Create a key entry for the bus.
//
if (lastBus != pathId.b.Path) {
if (busKey) {
ZwClose(busKey); busKey = 0; }
if (targetKey) {
ZwClose(targetKey); targetKey = 0; }
status = IdeCreateNumericKey(key, pathId.b.Path, L"Scsi Bus ", &busKey);
if (!NT_SUCCESS(status)) { break; }
lastBus = (UCHAR) pathId.b.Path;
//
// Create a key entry for the Scsi bus adapter.
//
status = IdeCreateNumericKey(busKey, IDE_PSUEDO_INITIATOR_ID, L"Initiator Id ", &targetKey);
if (!NT_SUCCESS(status)) { break; }
lastTarget = IDE_PSUEDO_INITIATOR_ID; }
//
// Process the data for the logical units.
//
//
// If this is a new target Id then create a new target entry.
//
if (lastTarget != pdoExtension->TargetId) {
ZwClose(targetKey); targetKey = 0;
status = IdeCreateNumericKey(busKey, pdoExtension->TargetId, L"Target Id ", &targetKey);
if (!NT_SUCCESS(status)) { break; }
lastTarget = pdoExtension->TargetId; }
//
// Create the Lun entry.
//
status = IdeCreateNumericKey(targetKey, pdoExtension->Lun, L"Logical Unit Id ", &lunKey);
if (!NT_SUCCESS(status)) { break; }
//
// Create identifier value.
//
RtlInitUnicodeString(&name, L"Identifier");
//
// Get the Identifier from the inquiry data.
//
RtlInitAnsiString(&ansiString, pdoExtension->FullVendorProductId);
status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, TRUE);
if (!NT_SUCCESS(status)) { break; }
status = ZwSetValueKey(lunKey, &name, 0, REG_SZ, unicodeString.Buffer, unicodeString.Length + sizeof(wchar_t));
RtlFreeUnicodeString(&unicodeString);
if (!NT_SUCCESS(status)) { break; }
//
// Determine the perpherial type.
//
peripheralType = IdePortGetPeripheralIdString ( pdoExtension->ScsiDeviceType ); if (!peripheralType) {
peripheralType = "OtherPeripheral"; }
RtlInitAnsiString(&ansiString, peripheralType);
unicodeString.MaximumLength = (USHORT) RtlAnsiStringToUnicodeSize(&ansiString) + sizeof(WCHAR); unicodeString.Length = 0; unicodeString.Buffer = ExAllocatePool (PagedPool, unicodeString.MaximumLength);
if (unicodeString.Buffer) {
status = RtlAnsiStringToUnicodeString( &unicodeString, &ansiString, FALSE );
if (NT_SUCCESS(status)) {
//
// Set type value.
//
RtlInitUnicodeString(&name, L"Type");
unicodeString.Buffer[unicodeString.Length / sizeof (WCHAR)] = L'\0';
status = ZwSetValueKey(lunKey, &name, 0, REG_SZ, unicodeString.Buffer, unicodeString.Length + sizeof (WCHAR));
ExFreePool (unicodeString.Buffer); }
} else {
status = STATUS_NO_MEMORY; }
ZwClose(lunKey); lunKey = 0;
if (!NT_SUCCESS(status)) { break; }
UnrefLogicalUnitExtensionWithTag ( FdoExtension, pdoExtension, IdeBuildDeviceMap ); pdoExtension = NULL; }
if (lunKey) {
ZwClose(lunKey); }
if (busKey) {
ZwClose(busKey); }
if (targetKey) {
ZwClose(targetKey); }
if (pdoExtension) {
UnrefLogicalUnitExtensionWithTag ( FdoExtension, pdoExtension, IdeBuildDeviceMap ); }
ZwClose(key); } // IdeBuildDeviceMap
NTSTATUS IdeCreateNumericKey( IN HANDLE Root, IN ULONG Name, IN PWSTR Prefix, OUT PHANDLE NewKey ) /*++
Routine Description:
This function creates a registry key. The name of the key is a string version of numeric value passed in.
Arguments:
RootKey - Supplies a handle to the key where the new key should be inserted.
Name - Supplies the numeric value to name the key.
Prefix - Supplies a prefix name to add to name.
NewKey - Returns the handle for the new key.
Return Value:
Returns the status of the operation.
--*/
{
UNICODE_STRING string; UNICODE_STRING stringNum; OBJECT_ATTRIBUTES objectAttributes; WCHAR bufferNum[16]; WCHAR buffer[64]; ULONG disposition; NTSTATUS status;
PAGED_CODE();
//
// Copy the Prefix into a string.
//
string.Length = 0; string.MaximumLength=64; string.Buffer = buffer;
RtlInitUnicodeString(&stringNum, Prefix);
RtlCopyUnicodeString(&string, &stringNum);
//
// Create a port number key entry.
//
stringNum.Length = 0; stringNum.MaximumLength = 16; stringNum.Buffer = bufferNum;
status = RtlIntegerToUnicodeString(Name, 10, &stringNum);
if (!NT_SUCCESS(status)) { return status; }
//
// Append the prefix and the numeric name.
//
RtlAppendUnicodeStringToString(&string, &stringNum);
InitializeObjectAttributes( &objectAttributes, &string, OBJ_CASE_INSENSITIVE, Root, (PSECURITY_DESCRIPTOR) NULL );
status = ZwCreateKey(NewKey, KEY_READ | KEY_WRITE, &objectAttributes, 0, (PUNICODE_STRING) NULL, REG_OPTION_VOLATILE, &disposition );
return(status); } // IdeCreateNumericKey
|