2025-04-27 07:49:33 -04:00

5643 lines
159 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (C) Microsoft Corporation, 1997 - 2001
Module Name:
sbp2port.c
Abstract:
Main module for the SBP-2 port driver
Author:
George Chrysanthakopoulos January-1997
Environment:
Kernel mode
Revision History :
--*/
#include "sbp2port.h"
#include "stdarg.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#if DBG
ULONG Sbp2DebugLevel = 0;
#endif
BOOLEAN SystemIsNT;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
Sbp2AddDevice(
PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT Pdo
);
NTSTATUS
Sbp2StartDevice(
IN PDEVICE_OBJECT DeviceObject
);
NTSTATUS
Sbp2CreateDeviceRelations(
IN PFDO_DEVICE_EXTENSION FdoExtension,
IN PDEVICE_RELATIONS DeviceRelations
);
NTSTATUS
Sbp2CreateDevObject(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo
);
NTSTATUS
Sbp2DeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
Sbp2CreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
Sbp2PnpDeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
);
NTSTATUS
Sbp2FDOPnpDeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
);
NTSTATUS
Sbp2GetMultipleIds(
IN PDEVICE_OBJECT Pdo,
OUT PUNICODE_STRING UnicodeString,
BOOLEAN HwIds
);
NTSTATUS
Sbp2GetInstanceId(
IN PDEVICE_OBJECT Pdo,
OUT PUNICODE_STRING UnicodeString
);
NTSTATUS
Sbp2GetDeviceId(
IN PDEVICE_OBJECT Pdo,
OUT PUNICODE_STRING UnicodeString
);
NTSTATUS
Sbp2CreatePdo(
IN PFDO_DEVICE_EXTENSION FdoExtension,
IN PDEVICE_INFORMATION DeviceInfo,
ULONG instanceNum
);
NTSTATUS
Sbp2StringArrayToMultiString(
PUNICODE_STRING MultiString,
PCSTR StringArray[]
);
NTSTATUS
Sbp2QueryDeviceText(
IN PDEVICE_EXTENSION DeviceExtension,
IN DEVICE_TEXT_TYPE TextType,
IN LCID LocaleId,
IN OUT PWSTR *DeviceText
);
NTSTATUS
Sbp2PowerControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
);
NTSTATUS
Sbp2SystemControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
);
NTSTATUS
Sbp2FdoRequestCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT Event
);
VOID
Sbp2Unload(
IN PDRIVER_OBJECT DriverObject
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, DriverEntry)
#pragma alloc_text(PAGE, Sbp2AddDevice)
#pragma alloc_text(PAGE, Sbp2StartDevice)
#pragma alloc_text(PAGE, Sbp2CreateDeviceRelations)
#pragma alloc_text(PAGE, Sbp2CreatePdo)
#pragma alloc_text(PAGE, Sbp2QueryDeviceText)
#pragma alloc_text(PAGE, Sbp2StringArrayToMultiString)
#pragma alloc_text(PAGE, Sbp2GetDeviceId)
#pragma alloc_text(PAGE, Sbp2GetInstanceId)
#pragma alloc_text(PAGE, Sbp2GetMultipleIds)
#pragma alloc_text(PAGE, Sbp2CreateDevObject)
#pragma alloc_text(PAGE, Sbp2DeviceControl)
#pragma alloc_text(PAGE, Sbp2SystemControl)
#pragma alloc_text(PAGE, Sbp2CreateClose)
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine is called at system initialization time so we can fill in the basic dispatch points
Arguments:
DriverObject - Supplies the driver object.
RegistryPath - Supplies the registry path for this driver.
Return Value:
STATUS_SUCCESS
--*/
{
//
// Initialize the Driver Object with driver's entry points
//
DEBUGPRINT2(("Sbp2Port: DriverEntry: %s %s\n", __DATE__, __TIME__));
DriverObject->MajorFunction[IRP_MJ_CREATE] = Sbp2CreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = Sbp2CreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Sbp2DeviceControl;
DriverObject->MajorFunction[IRP_MJ_SCSI] = Sbp2ScsiRequests;
DriverObject->DriverExtension->AddDevice = Sbp2AddDevice;
DriverObject->MajorFunction[IRP_MJ_PNP] = Sbp2PnpDeviceControl;
DriverObject->MajorFunction[IRP_MJ_PNP_POWER] = Sbp2PnpDeviceControl;
DriverObject->MajorFunction[IRP_MJ_POWER] = Sbp2PowerControl;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = Sbp2SystemControl;
DriverObject->DriverStartIo = Sbp2StartIo;
DriverObject->DriverUnload = Sbp2Unload;
SystemIsNT = IoIsWdmVersionAvailable ((UCHAR)0x01, (UCHAR)0x10);
return STATUS_SUCCESS;
}
NTSTATUS
Sbp2AddDevice(
PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT Pdo
)
/*++
Routine Description:
This is our PNP AddDevice called with the PDO ejected from the bus driver
Arguments:
Argument1 - Driver Object.
Argument2 - PDO.
Return Value:
A valid return code for a DriverEntry routine.
--*/
{
return (Sbp2CreateDevObject (DriverObject,Pdo));
}
NTSTATUS
Sbp2CreateDevObject(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo
)
/*++
Routine Description:
This routine creates an object for the physical device specified and
sets up the deviceExtension.
Arguments:
DriverObject - Pointer to driver object created by system.
PhysicalDeviceObject = PDO we should attach to.
Return Value:
NTSTATUS
--*/
{
PFDO_DEVICE_EXTENSION deviceExtension;
NTSTATUS status;
PDEVICE_OBJECT deviceObject = NULL;
UNICODE_STRING uniDeviceName;
WCHAR buffer[64];
UNICODE_STRING unicodeDirectoryName;
HANDLE handle;
OBJECT_ATTRIBUTES objectAttributes;
ULONG NextId = 0;
//
// This is the sbp2 filter device object and name
//
do {
swprintf (buffer, L"\\Device\\Sbp2Port%x", NextId);
RtlInitUnicodeString (&uniDeviceName, buffer);
status = IoCreateDevice(DriverObject,
sizeof(FDO_DEVICE_EXTENSION),
&uniDeviceName,
FILE_DEVICE_BUS_EXTENDER,
FILE_DEVICE_SECURE_OPEN,
FALSE,
&deviceObject);
NextId++;
} while (status == STATUS_OBJECT_NAME_COLLISION);
if (!NT_SUCCESS(status)) {
return status;
}
deviceExtension = deviceObject->DeviceExtension;
RtlZeroMemory(deviceExtension,sizeof(FDO_DEVICE_EXTENSION));
if (Pdo != NULL) {
if ((deviceExtension->LowerDeviceObject =
IoAttachDeviceToDeviceStack(deviceObject,Pdo))==NULL){
IoDeleteDevice(deviceObject);
return status;
}
}
deviceExtension->Type = SBP2_FDO;
deviceExtension->DeviceFlags = 0;
deviceExtension->DeviceObject = deviceObject;
deviceExtension->Pdo = Pdo;
KeInitializeSpinLock(&deviceExtension->DeviceListLock);
KeInitializeMutex (&deviceExtension->EnableBusResetNotificationMutex, 0);
//
// create a directory object for Sbp2 children devices
//
swprintf(buffer, L"\\Device\\Sbp2");
RtlInitUnicodeString(&unicodeDirectoryName, buffer);
InitializeObjectAttributes(&objectAttributes,
&unicodeDirectoryName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
NULL);
status = ZwCreateDirectoryObject(&handle,
DIRECTORY_ALL_ACCESS,
&objectAttributes);
if (NT_SUCCESS(status)) {
deviceExtension->Sbp2ObjectDirectory = handle;
} else {
//
// the directory is already created by another instance of this driver..
//
status = STATUS_SUCCESS;
}
ExInitializeFastMutex(&deviceExtension->ResetMutex);
IoInitializeRemoveLock( &deviceExtension->RemoveLock,
'2pbS',
REMLOCK_TIMEOUT,
REMLOCK_HIGH_WATERMARK
);
#if DBG
deviceExtension->ulWorkItemCount = 0;
deviceExtension->ulBusResetMutexCount = 0;
#endif
deviceObject->Flags |= DO_DIRECT_IO;
deviceObject->Flags &=~DO_DEVICE_INITIALIZING;
return status;
}
NTSTATUS
Sbp2CreatePdo(
IN PFDO_DEVICE_EXTENSION FdoExtension,
IN PDEVICE_INFORMATION DeviceInfo,
ULONG InstanceNumber
)
{
PDEVICE_EXTENSION pdoExtension;
DEVICE_TYPE devType;
WCHAR *buffer;
UNICODE_STRING uniDeviceName;
NTSTATUS status;
ULONG byteSwappedData;
PAGED_CODE();
switch (DeviceInfo->CmdSetId.QuadPart) {
case 0x10483:
case SCSI_COMMAND_SET_ID:
switch ((DeviceInfo->Lun.u.HighPart & 0x001F)) {
case PRINTER_DEVICE:
devType = FILE_DEVICE_PRINTER;
break;
case SCANNER_DEVICE:
devType = FILE_DEVICE_SCANNER;
break;
case READ_ONLY_DIRECT_ACCESS_DEVICE:
case RBC_DEVICE:
case DIRECT_ACCESS_DEVICE:
default:
devType = FILE_DEVICE_MASS_STORAGE;
break;
}
break;
default:
devType = FILE_DEVICE_UNKNOWN;
break;
}
buffer = ExAllocatePool(PagedPool,
5 * SBP2_MAX_TEXT_LEAF_LENGTH * sizeof (WCHAR)
);
if (buffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
if (DeviceInfo->VendorLeaf && DeviceInfo->ModelLeaf) {
ValidateTextLeaf(DeviceInfo->VendorLeaf);
ValidateTextLeaf(DeviceInfo->ModelLeaf);
//
// check if we have unicode...
//
byteSwappedData = bswap(*(((PULONG) DeviceInfo->VendorLeaf+1)));
if (byteSwappedData & 0x80000000) {
swprintf(buffer,
L"\\Device\\Sbp2\\%ws&%ws&%x&%08x_%08x_Instance%02d",
&DeviceInfo->VendorLeaf->TL_Data,
&DeviceInfo->ModelLeaf->TL_Data,
DeviceInfo->Lun.u.LowPart,
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[0]),
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[1]),
InstanceNumber);
} else {
//
// ascii text leaf
//
// Note that Win9x doesn't seem to like %s args, so we 1st
// convert them to unicode manually
//
mbstowcs(&buffer[3 * SBP2_MAX_TEXT_LEAF_LENGTH],
&DeviceInfo->VendorLeaf->TL_Data,
strlen (&DeviceInfo->VendorLeaf->TL_Data) + 1);
mbstowcs(&buffer[4 * SBP2_MAX_TEXT_LEAF_LENGTH],
&DeviceInfo->ModelLeaf->TL_Data,
strlen (&DeviceInfo->ModelLeaf->TL_Data) + 1);
swprintf(buffer,
L"\\Device\\Sbp2\\%ws&%ws&%x&%08x_%08x_Instance%02d",
&buffer[3 * SBP2_MAX_TEXT_LEAF_LENGTH],
&buffer[4 * SBP2_MAX_TEXT_LEAF_LENGTH],
DeviceInfo->Lun.u.LowPart,
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[0]),
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[1]),
InstanceNumber);
}
} else {
swprintf(buffer,
L"\\Device\\Sbp2\\UNKNOWN_VENDOR&UNKNOWN_MODEL&%x&%08x_%08x_Instance%02d",
DeviceInfo->Lun.u.LowPart,
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[0]),
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[1]),
InstanceNumber);
}
RtlInitUnicodeString (&uniDeviceName, buffer);
//
// Need to create a device object for this device
//
status = IoCreateDevice(
FdoExtension->DeviceObject->DriverObject,
sizeof(DEVICE_EXTENSION),
&uniDeviceName,
devType,
0,
FALSE,
&DeviceInfo->DeviceObject
);
if (!NT_SUCCESS(status)) {
ExFreePool (buffer);
return status;
}
// only set alignment if it's less than we require
if (DeviceInfo->DeviceObject->AlignmentRequirement < SBP2_ALIGNMENT_MASK)
DeviceInfo->DeviceObject->AlignmentRequirement = SBP2_ALIGNMENT_MASK;
pdoExtension = (PDEVICE_EXTENSION)DeviceInfo->DeviceObject->DeviceExtension;
RtlZeroMemory(pdoExtension,sizeof(DEVICE_EXTENSION));
pdoExtension->LowerDeviceObject = FdoExtension->LowerDeviceObject;
pdoExtension->DeviceObject = DeviceInfo->DeviceObject;
pdoExtension->Type = SBP2_PDO;
pdoExtension->DeviceInfo = DeviceInfo;
pdoExtension->DeviceInfo->MaxClassTransferSize = FdoExtension->MaxClassTransferSize;
pdoExtension->BusFdo = FdoExtension->DeviceObject;
#if DBG
pdoExtension->ulPendingEvents = 0;
pdoExtension->ulInternalEventCount = 0;
#endif
KeInitializeSpinLock (&pdoExtension->ExtensionDataSpinLock);
IoInitializeRemoveLock(
&pdoExtension->RemoveLock,
'2pbS',
REMLOCK_TIMEOUT,
REMLOCK_HIGH_WATERMARK
);
switch (DeviceInfo->CmdSetId.QuadPart) {
case 0x10483:
case SCSI_COMMAND_SET_ID:
//
// intepret device type only for scsi-variant command sets
//
// NOTE: sbp2port.h #define's MAX_GENERIC_NAME_LENGTH as 16
//
switch ((DeviceInfo->Lun.u.HighPart & 0x001F)) {
case RBC_DEVICE:
case DIRECT_ACCESS_DEVICE:
sprintf(DeviceInfo->GenericName,"%s","GenDisk");
break;
case SEQUENTIAL_ACCESS_DEVICE:
sprintf(DeviceInfo->GenericName,"%s","GenSequential");
break;
case PRINTER_DEVICE:
sprintf(DeviceInfo->GenericName,"%s","GenPrinter");
break;
case WRITE_ONCE_READ_MULTIPLE_DEVICE:
sprintf(DeviceInfo->GenericName,"%s","GenWorm");
break;
case READ_ONLY_DIRECT_ACCESS_DEVICE:
sprintf(DeviceInfo->GenericName,"%s","GenCdRom");
break;
case SCANNER_DEVICE:
sprintf(DeviceInfo->GenericName,"%s","GenScanner");
break;
case OPTICAL_DEVICE:
sprintf(DeviceInfo->GenericName,"%s","GenOptical");
break;
case MEDIUM_CHANGER:
sprintf(DeviceInfo->GenericName,"%s","GenChanger");
break;
default:
sprintf(DeviceInfo->GenericName,"%s","GenSbp2Device");
break;
}
break;
default:
sprintf(DeviceInfo->GenericName,"%s","GenSbp2Device");
break;
}
DeviceInfo->DeviceObject->Flags |= DO_DIRECT_IO;
status = Sbp2PreAllocateLists (pdoExtension);
if (!NT_SUCCESS(status)) {
IoDeleteDevice (pdoExtension->DeviceObject);
DeviceInfo->DeviceObject = NULL;
} else {
PWCHAR symlinkBuffer;
symlinkBuffer = ExAllocatePool(PagedPool,
3 * SBP2_MAX_TEXT_LEAF_LENGTH * sizeof (WCHAR)
);
if (symlinkBuffer) {
swprintf(
symlinkBuffer,
L"\\DosDevices\\Sbp2&LUN%x&%08x%08x&Instance%02d",
DeviceInfo->Lun.u.LowPart,
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[0]),
bswap(FdoExtension->ConfigRom.CR_Node_UniqueID[1]),
InstanceNumber
);
RtlInitUnicodeString (&pdoExtension->UniSymLinkName,symlinkBuffer);
status = IoCreateUnprotectedSymbolicLink(
&pdoExtension->UniSymLinkName,
&uniDeviceName
);
if (NT_SUCCESS (status)) {
DEBUGPRINT2((
"Sbp2Port: CreatePdo: symLink=%ws\n",
symlinkBuffer
));
} else {
DEBUGPRINT1((
"\nSbp2Port: CreatePdo: createSymLink err=x%x\n",
status
));
}
} else {
DEBUGPRINT1(("\n Sbp2CreatePdo: failed to alloc sym link buf\n"));
}
//
// if sym link fails its not critical
//
status = STATUS_SUCCESS;
}
ExFreePool (buffer);
DeviceInfo->DeviceObject->Flags &=~DO_DEVICE_INITIALIZING;
return status;
}
NTSTATUS
Sbp2StartDevice(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This is our START_DEVICE, called when we get an IPR_MN_START_DEVICE. Initializes the driver and
retrieves physical device information and 1394 bus information required for accessing the device.
Arguments:
DeviceObject = Sbp2 driver's device object
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension=DeviceObject->DeviceExtension;
PFDO_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
NTSTATUS status;
ULONG temp;
BOOLEAN enabledBusResetNotification = FALSE;
if (deviceExtension->Type == SBP2_PDO) {
#if PASSWORD_SUPPORT
Sbp2GetExclusiveValue(DeviceObject, &deviceExtension->Exclusive);
#endif
if (!TEST_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZED)){
//
// initialize our device state flags
//
deviceExtension->DevicePowerState = PowerDeviceD0;
deviceExtension->SystemPowerState = PowerSystemWorking;
deviceExtension->MaxOrbListDepth = MAX_ORB_LIST_DEPTH;
}
deviceExtension->DeviceFlags = DEVICE_FLAG_PNP_STOPPED |
DEVICE_FLAG_STOPPED | DEVICE_FLAG_INITIALIZING;
//
// Initiliaze the Timer and timeout DPC used for resets, reconnects and TASK functions
//
KeInitializeDpc(
&deviceExtension->DeviceManagementTimeoutDpc,
Sbp2DeviceManagementTimeoutDpc,
deviceExtension
);
KeInitializeTimer(&deviceExtension->DeviceManagementTimer);
KeInitializeSpinLock(&deviceExtension->OrbListSpinLock);
KeInitializeSpinLock(&deviceExtension->ExtensionDataSpinLock);
KeInitializeSpinLock(&deviceExtension->StatusFifoLock);
KeInitializeSpinLock(&deviceExtension->FreeContextLock);
KeInitializeSpinLock(&deviceExtension->BusRequestLock);
ASSERT(!deviceExtension->ulPendingEvents);
ASSERT(!deviceExtension->ulInternalEventCount);
#if DBG
deviceExtension->ulPendingEvents = 0;
deviceExtension->ulInternalEventCount = 0;
#endif
//
// Initialize our device Extension ORB's, status blocks, Irp and Irb's
// Also allocate 1394 addresses for extension-held sbp2 ORB's
//
status = Sbp2InitializeDeviceExtension(deviceExtension);
if (!NT_SUCCESS(status)) {
goto exitStartDevice;
}
DEBUGPRINT2(("\nSbp2Port: StartDev: cmd set id=x%x\n", deviceExtension->DeviceInfo->CmdSetId.QuadPart));
switch (deviceExtension->DeviceInfo->CmdSetId.QuadPart) {
case 0x0:
case 0x10483:
case SCSI_COMMAND_SET_ID:
SET_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_SPC_CMD_SET);
DEBUGPRINT2(("Sbp2Port: StartDev: enabling SPC cmd set\n"));
break;
}
//
// login
//
status = Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGIN);
if (!NT_SUCCESS(status)) {
DEBUGPRINT1(("\nSbp2StartDev: Login failed with %x, retrying\n",status));
if (status == STATUS_ACCESS_DENIED) {
//
// retry the login. By now we should have access since our bus reset forced a logout
//
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_QUERY_LOGINS);
}
temp = 0;
do {
//
// Give things time (one second) to settle...
//
LARGE_INTEGER waitValue;
ASSERT(InterlockedIncrement(&deviceExtension->ulPendingEvents) == 1);
KeInitializeEvent(deviceExtension->ManagementOrbContext.Reserved, NotificationEvent, FALSE);
waitValue.QuadPart = -1 * 1000 * 1000 * 10;
KeWaitForSingleObject(deviceExtension->ManagementOrbContext.Reserved,Executive,KernelMode,FALSE,&waitValue);
ASSERT(InterlockedDecrement(&deviceExtension->ulPendingEvents) == 0);
//
// all the resident 1394 memory addresses's that we have, are
// now invalidated... So we need to free them and re-allocate
// them
Sbp2CleanDeviceExtension (deviceExtension->DeviceObject,FALSE);
Sbp2InitializeDeviceExtension(deviceExtension);
status = Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGIN);
temp ++;
//
// Note: We get STATUS_REQUEST_ABORTED rather than
// STATUS_INVALID_GENERATION at passive level,
// so check for that instead
//
} while ((status == STATUS_REQUEST_ABORTED) &&
(temp <= 3));
if (!NT_SUCCESS(status)) {
goto exitStartDevice;
}
}
#if PASSWORD_SUPPORT
if (deviceExtension->Exclusive & EXCLUSIVE_FLAG_ENABLE) {
status = Sbp2SetPasswordTransaction(
deviceExtension,
SBP2REQ_SET_PASSWORD_EXCLUSIVE
);
if (NT_SUCCESS(status)) {
deviceExtension->Exclusive = EXCLUSIVE_FLAG_SET;
} else {
deviceExtension->Exclusive = EXCLUSIVE_FLAG_CLEAR;
}
Sbp2SetExclusiveValue(
deviceExtension->DeviceObject,
&deviceExtension->Exclusive
);
}
#endif
//
// We are ready to receive and pass down requests, init the target's
// fetch agent. The value we write to it is not important
//
Sbp2AccessRegister(deviceExtension,&deviceExtension->Reserved,AGENT_RESET_REG | REG_WRITE_SYNC);
//
// enable unsolicited status reg
//
Sbp2AccessRegister(deviceExtension,&deviceExtension->Reserved,UNSOLICITED_STATUS_REG | REG_WRITE_SYNC);
CLEAR_FLAG(
deviceExtension->DeviceFlags,
(DEVICE_FLAG_PNP_STOPPED | DEVICE_FLAG_STOPPED)
);
//
// register for idle detection
//
deviceExtension->IdleCounter = PoRegisterDeviceForIdleDetection(DeviceObject,
-1,
-1,
PowerDeviceD3);
CLEAR_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZING );
SET_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZED);
//
// OK to register for bus reset notifications now
//
if (!Sbp2EnableBusResetNotification (deviceExtension, TRUE)) {
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
CleanupOrbList (deviceExtension, STATUS_REQUEST_ABORTED);
Sbp2ManagementTransaction (deviceExtension, TRANSACTION_LOGOUT);
status = STATUS_INSUFFICIENT_RESOURCES;
goto exitStartDevice;
}
enabledBusResetNotification = TRUE;
if (TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_SPC_CMD_SET)) {
//
// issue an Inquiry to the target...
//
status = Sbp2IssueInternalCommand (deviceExtension,SCSIOP_INQUIRY);
if (NT_SUCCESS(status)) {
DEBUGPRINT2((
"Sbp2Port: StartDev: cfgRom devType=x%x, inq devType=x%x\n",
(deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F),
deviceExtension->InquiryData.DeviceType
));
} else if ((status == STATUS_DEVICE_DOES_NOT_EXIST) ||
(status == STATUS_DEVICE_BUSY)) {
//
// In win2k if the inquiry failed we'd just turn off the
// SPC_CMD_SET flag and trundle on like nothing happened.
//
// However, we found some devices would allow logins but
// nothing else, like a powered-down mactell hd which would
// allow us to login but fail all other requests. This
// really caused problems in win9x because Ntmap would
// get loaded, but not init'd correctly, and on subsequent
// re-plugs of any device we'd see trap 14's and the like.
// So, it really makes alot more sense to just nip this
// in the bud and fail the start if we get an error back
// from the inquiry that tells us (per Sbp2ScsiRequests())
// that the device has been removed or it timed out the 1st
// inquiry . DanKn, 7 Apr 2000
//
DEBUGPRINT1((
"\nSbp2Port: StartDev: ext=x%p, fatal INQUIRY err=x%x, " \
"log out\n",
deviceExtension,
status
));
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGOUT);
status = STATUS_IO_DEVICE_ERROR;
goto exitStartDevice;
} else {
CLEAR_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_SPC_CMD_SET
);
DEBUGPRINT1((
"\nSbp2Port: StartDev: ext=x%p, non-fatal INQUIRY err=x%x\n",
deviceExtension,
status
));
status = STATUS_SUCCESS;
}
}
if (deviceExtension->InquiryData.DeviceType != (deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F)){
deviceExtension->InquiryData.DeviceType = (deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F);
DEBUGPRINT1(("\nSbp2StartDev: DeviceType mismatch, using one in ConfigRom %x\n",
(deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F)));
}
//
// if this is a scanner or a printer we dont need to remain logged on..
//
if ((deviceExtension->InquiryData.DeviceType == PRINTER_DEVICE) ||
(deviceExtension->InquiryData.DeviceType == SCANNER_DEVICE)){
if (NT_SUCCESS(status)) {
SET_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
CleanupOrbList(deviceExtension,STATUS_REQUEST_ABORTED);
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGOUT);
}
} else if (deviceExtension->InquiryData.DeviceType == RBC_DEVICE) {
if (NT_SUCCESS(status)) {
//
// retrieve the RBC device mode page
//
status = Sbp2IssueInternalCommand(deviceExtension,SCSIOP_MODE_SENSE);
if (!NT_SUCCESS(status)) {
DEBUGPRINT1(("\nSbp2StartDev: Failed to retrieve RBC mode page\n"));
goto exitStartDevice;
}
}
}
exitStartDevice:
if (!NT_SUCCESS(status)) {
PIO_ERROR_LOG_PACKET errorLogEntry;
ULONG errorId = __LINE__ ;
errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(DeviceObject,sizeof(IO_ERROR_LOG_PACKET));
if(errorLogEntry != NULL) {
errorLogEntry->ErrorCode = IO_ERR_DRIVER_ERROR;
errorLogEntry->UniqueErrorValue = errorId;
errorLogEntry->FinalStatus = status;
errorLogEntry->DumpDataSize = 0;
IoWriteErrorLogEntry(errorLogEntry);
}
DEBUGPRINT1((
"Sbp2Port: StartDev: FAILED, status=x%x\n",
status
));
SET_FLAG(
deviceExtension->DeviceFlags,
(DEVICE_FLAG_PNP_STOPPED | DEVICE_FLAG_DEVICE_FAILED)
);
if (enabledBusResetNotification) {
Sbp2EnableBusResetNotification (deviceExtension, FALSE);
}
} else {
if (!SystemIsNT) {
DeviceObject->Flags |= DO_POWER_PAGABLE;
} else {
DeviceObject->Flags &= ~DO_POWER_PAGABLE;
}
}
} else if (deviceExtension->Type == SBP2_FDO){
//
// Bus driver FDO start device
// retrieve parameters from the registry, if present
//
fdoExtension->MaxClassTransferSize = SBP2_MAX_TRANSFER_SIZE;
GetRegistryParameters(fdoExtension->LowerDeviceObject,&temp,&fdoExtension->MaxClassTransferSize);
DEBUGPRINT2(("Sbp2Port: StartDev: maxXferSize=x%x\n", fdoExtension->MaxClassTransferSize ));
fdoExtension->DevicePowerState = PowerDeviceD0;
fdoExtension->SystemPowerState = PowerSystemWorking;
deviceExtension->DeviceFlags=DEVICE_FLAG_INITIALIZED;
status = STATUS_SUCCESS;
} else {
status = STATUS_NO_SUCH_DEVICE;
}
return status;
}
NTSTATUS
Sbp2PreAllocateLists(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Initializes all the single linked workhorse lists plus lookasides. Only called from AddDevice or after
a REMOVE -> START
Arguments:
DeviceExtension = Sbp2 driver's extension
Return Value:
NTSTATUS
--*/
{
ULONG cnt ;
PIRBIRP packet;
NTSTATUS status;
PADDRESS_FIFO statusFifoElement ;
PREQUEST_CONTEXT rContext;
PSTATUS_FIFO_BLOCK statusFifo;
PASYNC_REQUEST_CONTEXT context;
//
// initialize all interlocked lists
//
SET_FLAG(
DeviceExtension->DeviceFlags,
(DEVICE_FLAG_INITIALIZING | DEVICE_FLAG_STOPPED |
DEVICE_FLAG_PNP_STOPPED)
);
InitializeListHead(&DeviceExtension->PendingOrbList);
ExInitializeSListHead(&DeviceExtension->FreeContextListHead);
ExInitializeSListHead(&DeviceExtension->BusRequestIrpIrbListHead);
ExInitializeSListHead(&DeviceExtension->BusRequestContextListHead);
ExInitializeSListHead(&DeviceExtension->StatusFifoListHead);
KeInitializeSpinLock(&DeviceExtension->OrbListSpinLock);
KeInitializeSpinLock(&DeviceExtension->ExtensionDataSpinLock);
KeInitializeSpinLock(&DeviceExtension->StatusFifoLock);
KeInitializeSpinLock(&DeviceExtension->FreeContextLock);
KeInitializeSpinLock(&DeviceExtension->BusRequestLock);
//
// alloc the irb/irp and context slists
//
for (cnt = 0; cnt < MAX_ORB_LIST_DEPTH; cnt++) {
packet = ExAllocatePoolWithTag (NonPagedPool,sizeof(IRBIRP),'2pbs');
if (!packet) {
goto Sbp2PreAllocateLists_error;
}
packet->Irb = ExAllocatePoolWithTag (NonPagedPool,sizeof(IRB),'2pbs');
if (!packet->Irb) {
ExFreePool(packet);
goto Sbp2PreAllocateLists_error;
}
packet->Irp = IoAllocateIrp (DeviceExtension->LowerDeviceObject->StackSize,FALSE);
if (!packet->Irp) {
ExFreePool(packet->Irb);
ExFreePool(packet);
goto Sbp2PreAllocateLists_error;
}
ExInterlockedPushEntrySList (&DeviceExtension->BusRequestIrpIrbListHead,
&packet->ListPointer,
&DeviceExtension->BusRequestLock);
}
for (cnt = 0; cnt < MAX_ORB_LIST_DEPTH; cnt++) {
rContext = NULL;
rContext = ExAllocatePoolWithTag(NonPagedPool,sizeof(REQUEST_CONTEXT),'2pbs');
if (!rContext) {
goto Sbp2PreAllocateLists_error;
}
ExInterlockedPushEntrySList (&DeviceExtension->BusRequestContextListHead,
&rContext->ListPointer,
&DeviceExtension->BusRequestLock);
}
//
// status FIFO list
//
cnt = (sizeof(ADDRESS_FIFO)+sizeof(STATUS_FIFO_BLOCK))*NUM_PREALLOCATED_STATUS_FIFO_ELEMENTS;
DeviceExtension->StatusFifoBase = \
(PASYNC_REQUEST_CONTEXT) ExAllocatePoolWithTag(NonPagedPool,cnt,'2pbs');
if (DeviceExtension->StatusFifoBase == NULL) {
goto Sbp2PreAllocateLists_error;
}
for (cnt = 0; cnt < (NUM_PREALLOCATED_STATUS_FIFO_ELEMENTS - 1); cnt++) {
statusFifoElement = (PADDRESS_FIFO) ((PUCHAR)DeviceExtension->StatusFifoBase + \
cnt * (sizeof(ADDRESS_FIFO)+sizeof(STATUS_FIFO_BLOCK)));
statusFifo = (PSTATUS_FIFO_BLOCK) ((PUCHAR)statusFifoElement + sizeof(ADDRESS_FIFO));
//
// make Mdl for this status fifo Element
//
statusFifoElement->FifoMdl = IoAllocateMdl(statusFifo,sizeof(STATUS_FIFO_BLOCK),FALSE,FALSE,NULL);
if (statusFifoElement->FifoMdl == NULL) {
goto Sbp2PreAllocateLists_error;
}
MmBuildMdlForNonPagedPool (statusFifoElement->FifoMdl);
ExInterlockedPushEntrySList(&DeviceExtension->StatusFifoListHead,
(PSINGLE_LIST_ENTRY) &statusFifoElement->FifoList,
&DeviceExtension->StatusFifoLock);
}
//
// Initialize the async request contexts (including page tables)
//
cnt = sizeof (ASYNC_REQUEST_CONTEXT) * MAX_ORB_LIST_DEPTH;
DeviceExtension->AsyncContextBase = (PASYNC_REQUEST_CONTEXT)
ExAllocatePoolWithTag (NonPagedPool, cnt, '2pbs');
if (DeviceExtension->AsyncContextBase == NULL) {
goto Sbp2PreAllocateLists_error;
}
RtlZeroMemory (DeviceExtension->AsyncContextBase, cnt);
AllocateIrpAndIrb (DeviceExtension, &packet);
if (!packet) {
goto Sbp2PreAllocateLists_error;
}
for (cnt = 0; cnt < MAX_ORB_LIST_DEPTH; cnt++) {
context = DeviceExtension->AsyncContextBase + cnt;
context->Tag = SBP2_ASYNC_CONTEXT_TAG;
//
// Initialize the timeout DPC and timer
//
KeInitializeDpc(
&context->TimerDpc,
Sbp2RequestTimeoutDpc,
DeviceExtension
);
KeInitializeTimer (&context->Timer);
//
// Alloc and/or map a page table
//
packet->Irb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
packet->Irb->u.AllocateAddressRange.nLength = PAGE_SIZE;
packet->Irb->u.AllocateAddressRange.fulNotificationOptions =
NOTIFY_FLAGS_NEVER;
packet->Irb->u.AllocateAddressRange.fulAccessType =
ACCESS_FLAGS_TYPE_READ;
packet->Irb->u.AllocateAddressRange.fulFlags =
ALLOCATE_ADDRESS_FLAGS_USE_COMMON_BUFFER;
packet->Irb->u.AllocateAddressRange.Callback = NULL;
packet->Irb->u.AllocateAddressRange.Context = NULL;
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_High = 0;
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_Low = 0;
packet->Irb->u.AllocateAddressRange.FifoSListHead = NULL;
packet->Irb->u.AllocateAddressRange.FifoSpinLock = NULL;
packet->Irb->u.AllocateAddressRange.AddressesReturned = 0;
packet->Irb->u.AllocateAddressRange.DeviceExtension = DeviceExtension;
packet->Irb->u.AllocateAddressRange.Mdl =
context->PageTableContext.AddressContext.RequestMdl;
packet->Irb->u.AllocateAddressRange.MaxSegmentSize =
(SBP2_MAX_DIRECT_BUFFER_SIZE + 1) / 2;
packet->Irb->u.AllocateAddressRange.p1394AddressRange =(PADDRESS_RANGE)
&context->PageTableContext.AddressContext.Address;
status = Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
if (!NT_SUCCESS (status)) {
DeAllocateIrpAndIrb (DeviceExtension, packet);
goto Sbp2PreAllocateLists_error;
}
//
// Common buffer allocations get an mdl *back* from the
// bus/port driver, need to retrieve a corresponding VA
//
context->PageTableContext.AddressContext.RequestMdl =
packet->Irb->u.AllocateAddressRange.Mdl;
context->PageTableContext.PageTable = MmGetMdlVirtualAddress(
packet->Irb->u.AllocateAddressRange.Mdl
);
context->PageTableContext.AddressContext.AddressHandle =
packet->Irb->u.AllocateAddressRange.hAddressRange;
context->PageTableContext.AddressContext.Address.BusAddress.NodeId =
DeviceExtension->InitiatorAddressId;
context->PageTableContext.MaxPages = SBP2_NUM_PAGE_TABLE_ENTRIES;
//
// add this context to the linked list
//
ExInterlockedPushEntrySList(
&DeviceExtension->FreeContextListHead,
&context->LookasideList,
&DeviceExtension->FreeContextLock
);
}
DeAllocateIrpAndIrb (DeviceExtension, packet);
//
// initialize the mdl used for quadlet requests to the port driver..
//
DeviceExtension->ReservedMdl = IoAllocateMdl(
&DeviceExtension->Reserved,
sizeof(QUADLET),
FALSE,
FALSE,
NULL
);
if (!DeviceExtension->ReservedMdl) {
goto Sbp2PreAllocateLists_error;
}
MmBuildMdlForNonPagedPool (DeviceExtension->ReservedMdl);
return STATUS_SUCCESS;
Sbp2PreAllocateLists_error:
Sbp2CleanDeviceExtension (DeviceExtension->DeviceObject, TRUE);
return STATUS_INSUFFICIENT_RESOURCES;
}
NTSTATUS
Sbp2InitializeDeviceExtension(
IN PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Initializes all the data structures in our device extension, allocates appropriate 1394 addresses and workhorse
Irps. It also creates a FreeList with pre-allocated contexts and command ORBs.
Arguments:
DeviceExtension = Sbp2 driver's extension
Return Value:
NTSTATUS
--*/
{
ULONG i;
KIRQL cIrql;
NTSTATUS status;
PDEVICE_OBJECT deviceObject = DeviceExtension->DeviceObject;
PASYNC_REQUEST_CONTEXT context, oldContext;
if (DeviceExtension->DeviceFlags & DEVICE_FLAG_REMOVED) {
return STATUS_SUCCESS;
}
InitializeListHead(&DeviceExtension->PendingOrbList);
DeviceExtension->NextContextToFree = NULL;
DeviceExtension->OrbListDepth = 0;
DeviceExtension->CurrentKey = 0;
//
// Get information volatile between bus resets
//
status = Sbp2UpdateNodeInformation (DeviceExtension);
if (!NT_SUCCESS(status)) {
goto exitInit;
}
//
// get 1394 data transfer information
//
status = Sbp2GetControllerInfo (DeviceExtension);
if (!NT_SUCCESS(status)) {
goto exitInit;
}
//
//
// allocate a status block for the task ORB and a Management ORB
//
if (DeviceExtension->TaskOrbStatusContext.AddressHandle == NULL) {
status = AllocateAddressForStatus(deviceObject,
&DeviceExtension->TaskOrbStatusContext,
TASK_STATUS_BLOCK);
if (!NT_SUCCESS(status)) {
goto exitInit;
}
}
if (DeviceExtension->ManagementOrbStatusContext.AddressHandle == NULL) {
status = AllocateAddressForStatus(deviceObject,
&DeviceExtension->ManagementOrbStatusContext,
MANAGEMENT_STATUS_BLOCK);
if (!NT_SUCCESS(status)) {
goto exitInit;
}
}
if (DeviceExtension->GlobalStatusContext.AddressHandle == NULL) {
//
// setup the status FIFO list with the bus driver
//
status = AllocateAddressForStatus(deviceObject,
&DeviceExtension->GlobalStatusContext,
CMD_ORB_STATUS_BLOCK);
if (!NT_SUCCESS(status)) {
goto exitInit;
}
}
#if PASSWORD_SUPPORT
if (DeviceExtension->PasswordOrbStatusContext.AddressHandle == NULL) {
status = AllocateAddressForStatus( deviceObject,
&DeviceExtension->PasswordOrbStatusContext,
PASSWORD_STATUS_BLOCK
);
if (!NT_SUCCESS(status)) {
goto exitInit;
}
}
DeviceExtension->PasswordOrbContext.DeviceObject = deviceObject;
#endif
//
// Allocate a dummy,task, management ORBs and a login response ,which are going to be reused through out the drivers life...
//
DeviceExtension->TaskOrbContext.DeviceObject = deviceObject;
DeviceExtension->ManagementOrbContext.DeviceObject = deviceObject;
DeviceExtension->LoginRespContext.DeviceObject = deviceObject;
DeviceExtension->QueryLoginRespContext.DeviceObject = deviceObject;
if (!DeviceExtension->ManagementOrbContext.Reserved) {
DeviceExtension->ManagementOrbContext.Reserved = ExAllocatePoolWithTag(NonPagedPool,sizeof(KEVENT),'2pbs');
}
if (!DeviceExtension->ManagementOrbContext.Reserved) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exitInit;
}
KeInitializeEvent(DeviceExtension->ManagementOrbContext.Reserved,SynchronizationEvent, FALSE);
#if PASSWORD_SUPPORT
// kevent for password orb context
DeviceExtension->PasswordOrbContext.DeviceObject = deviceObject;
if (!DeviceExtension->PasswordOrbContext.Reserved) {
DeviceExtension->PasswordOrbContext.Reserved = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(KEVENT),
'2pbs'
);
}
if (!DeviceExtension->PasswordOrbContext.Reserved) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto exitInit;
}
KeInitializeEvent(
DeviceExtension->PasswordOrbContext.Reserved,
SynchronizationEvent,
FALSE
);
#endif
if (DeviceExtension->CommonBufferContext.AddressHandle == NULL) {
status = AllocateSingle1394Address(
deviceObject,
NULL,
sizeof (*DeviceExtension->CommonBuffer),
ACCESS_FLAGS_TYPE_READ | ACCESS_FLAGS_TYPE_WRITE,
&DeviceExtension->CommonBufferContext
);
if (!NT_SUCCESS(status)) {
goto exitInit;
}
(PVOID) DeviceExtension->CommonBuffer =
DeviceExtension->CommonBufferContext.Reserved;
DeviceExtension->TaskOrb = &DeviceExtension->CommonBuffer->TaskOrb;
DeviceExtension->TaskOrbContext.Address.BusAddress =
DeviceExtension->CommonBufferContext.Address.BusAddress;
DeviceExtension->ManagementOrb =
&DeviceExtension->CommonBuffer->ManagementOrb;
DeviceExtension->ManagementOrbContext.Address.BusAddress =
DeviceExtension->CommonBufferContext.Address.BusAddress;
DeviceExtension->ManagementOrbContext.Address.BusAddress.Off_Low +=
(ULONG) ((PUCHAR) DeviceExtension->ManagementOrb -
(PUCHAR) DeviceExtension->CommonBuffer);
DeviceExtension->LoginResponse =
&DeviceExtension->CommonBuffer->LoginResponse;
DeviceExtension->LoginRespContext.Address.BusAddress =
DeviceExtension->CommonBufferContext.Address.BusAddress;
DeviceExtension->LoginRespContext.Address.BusAddress.Off_Low +=
(ULONG) ((PUCHAR) DeviceExtension->LoginResponse -
(PUCHAR) DeviceExtension->CommonBuffer);
DeviceExtension->QueryLoginResponse =
&DeviceExtension->CommonBuffer->QueryLoginResponse;
DeviceExtension->QueryLoginRespContext.Address.BusAddress =
DeviceExtension->CommonBufferContext.Address.BusAddress;
DeviceExtension->QueryLoginRespContext.Address.BusAddress.Off_Low +=
(ULONG) ((PUCHAR) DeviceExtension->QueryLoginResponse -
(PUCHAR) DeviceExtension->CommonBuffer);
#if PASSWORD_SUPPORT
DeviceExtension->PasswordOrb =
&DeviceExtension->CommonBuffer->PasswordOrb;
DeviceExtension->PasswordOrbContext.Address.BusAddress =
DeviceExtension->CommonBufferContext.Address.BusAddress;
DeviceExtension->PasswordOrbContext.Address.BusAddress.Off_Low +=
(ULONG) ((PUCHAR) DeviceExtension->PasswordOrb -
(PUCHAR) DeviceExtension->CommonBuffer);
#endif
DeviceExtension->OrbPoolContext.Reserved =
DeviceExtension->CommonBuffer->CmdOrbs;
DeviceExtension->OrbPoolContext.Address.BusAddress =
DeviceExtension->CommonBufferContext.Address.BusAddress;
DeviceExtension->OrbPoolContext.Address.BusAddress.Off_Low +=
(ULONG) ((PUCHAR) DeviceExtension->OrbPoolContext.Reserved -
(PUCHAR) DeviceExtension->CommonBuffer);
KeAcquireSpinLock (&DeviceExtension->OrbListSpinLock, &cIrql);
//
// Initialize our pool of contexts
//
for (i = 0, context = NULL; i < MAX_ORB_LIST_DEPTH; i++) {
//
// Mark this unused context as completed so if we had to
// free our freelist now (because we got a remove) we wouldn't
// try to complete its request
//
oldContext = context;
context = (PVOID) ExInterlockedPopEntrySList (&DeviceExtension->FreeContextListHead,
&DeviceExtension->FreeContextLock);
context = RETRIEVE_CONTEXT (context,LookasideList);
context->Flags |= ASYNC_CONTEXT_FLAG_COMPLETED;
//
// Create a linked list so we push all the entries later
//
context->OrbList.Blink = (PLIST_ENTRY) oldContext;
//
// Each command ORB gets a small piece of our continuous pool
// mapped into the 1394 memory space. The sizeof(PVOID) bytes
// before the cmdorb buffer are the pointer to its context.
//
context->CmdOrb = &DeviceExtension->CommonBuffer->CmdOrbs[i].Orb;
DeviceExtension->CommonBuffer->CmdOrbs[i].AsyncReqCtx = context;
context->CmdOrbAddress.BusAddress.Off_Low = \
DeviceExtension->OrbPoolContext.Address.BusAddress.Off_Low +
(i * sizeof (ARCP_ORB)) + FIELD_OFFSET (ARCP_ORB, Orb);
context->CmdOrbAddress.BusAddress.Off_High = \
DeviceExtension->OrbPoolContext.Address.BusAddress.Off_High;
context->CmdOrbAddress.BusAddress.NodeId = \
DeviceExtension->InitiatorAddressId;
}
//
// re-create the free list
//
while (context) {
oldContext = context;
ExInterlockedPushEntrySList(&DeviceExtension->FreeContextListHead,
&context->LookasideList,
&DeviceExtension->FreeContextLock);
context = (PASYNC_REQUEST_CONTEXT) oldContext->OrbList.Blink;
oldContext->OrbList.Blink = NULL;
}
KeReleaseSpinLock (&DeviceExtension->OrbListSpinLock,cIrql);
}
//
// Update the NodeId portion of the page table addr for each
// ASYNC_REQUEST_CONTEXT and for the login/queryLogin responses
//
for (i = 0; i < MAX_ORB_LIST_DEPTH; i++) {
context = DeviceExtension->AsyncContextBase + i;
context->PageTableContext.AddressContext.Address.BusAddress.NodeId =
DeviceExtension->InitiatorAddressId;
}
DeviceExtension->LoginRespContext.Address.BusAddress.NodeId =
DeviceExtension->InitiatorAddressId;
DeviceExtension->QueryLoginRespContext.Address.BusAddress.NodeId =
DeviceExtension->InitiatorAddressId;
//
// Finally, allocate a dummy addr that we can easily free & realloc
// to re-enable phyical addr filters after bus resets
//
if (DeviceExtension->DummyContext.AddressHandle == NULL) {
status = AllocateSingle1394Address(
deviceObject,
&DeviceExtension->Dummy,
sizeof(DeviceExtension->Dummy),
ACCESS_FLAGS_TYPE_READ | ACCESS_FLAGS_TYPE_WRITE,
&DeviceExtension->DummyContext
);
if (!NT_SUCCESS(status)) {
goto exitInit;
}
}
//
// Done
//
DEBUGPRINT2(("Sbp2Port: InitDevExt: ext=x%p\n", DeviceExtension));
exitInit:
return status;
}
BOOLEAN
Sbp2CleanDeviceExtension(
IN PDEVICE_OBJECT DeviceObject,
BOOLEAN FreeLists
)
/*++
Routine Description:
Called when we get a remove, so it will free all used pool and all the resident Irps.
It wil also free our FreeList of contexts and any complete any pending IO requests
Arguments:
DeviceExtension = Sbp2 driver's extension
FreeLists - TRUE means we cleanup EVERYTHING including our lookaside lists
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PFDO_DEVICE_EXTENSION fdoExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
KIRQL cIrql;
PREQUEST_CONTEXT rContext;
PADDRESS_FIFO statusFifoElement;
ULONG i;
BOOLEAN valid = FALSE;
PIRBIRP packet;
//
// there are two types of cleanups. One for the PDO and one for the FDO(alot simpler)
//
if (deviceExtension->Type == SBP2_PDO) {
//
// make sure that this PDO is something in our list and that we have NOT deleted
// it already....
//
fdoExtension = (PFDO_DEVICE_EXTENSION) deviceExtension->BusFdo->DeviceExtension;
for (i = 0; i < fdoExtension->DeviceListSize; i++) {
if (fdoExtension->DeviceList[i].DeviceObject == DeviceObject) {
valid = TRUE;
}
}
if (!valid) {
return FALSE;
}
if (TEST_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZED) ){
//
// stop the timer for any pending management requests
//
KeCancelTimer (&deviceExtension->DeviceManagementTimer);
//
// We have a list of requests pending, clean it up
// The reset/logout has automatically made the target to discard any requests
//
CleanupOrbList (deviceExtension, STATUS_REQUEST_ABORTED);
}
//
// after a bus reset we must reallocate at least one physical address to allow
// the ohci driver to re-enable the physical address filters
//
if (deviceExtension->DummyContext.AddressHandle != NULL) {
FreeAddressRange (deviceExtension,&deviceExtension->DummyContext);
}
if (FreeLists){
if (TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_INITIALIZED) ||
TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_INITIALIZING)){
FreeAddressRange(deviceExtension,&deviceExtension->TaskOrbStatusContext);
FreeAddressRange(deviceExtension,&deviceExtension->GlobalStatusContext);
#if PASSWORD_SUPPORT
FreeAddressRange(deviceExtension,&deviceExtension->PasswordOrbStatusContext);
#endif
FreeAddressRange(deviceExtension,&deviceExtension->ManagementOrbStatusContext);
if (deviceExtension->PowerDeferredIrp) {
deviceExtension->PowerDeferredIrp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
IoCompleteRequest (deviceExtension->PowerDeferredIrp, IO_NO_INCREMENT);
deviceExtension->PowerDeferredIrp = NULL;
}
if (deviceExtension->ManagementOrbContext.Reserved) {
ExFreePool(deviceExtension->ManagementOrbContext.Reserved);
deviceExtension->ManagementOrbContext.Reserved = NULL;
}
#if PASSWORD_SUPPORT
if (deviceExtension->PasswordOrbContext.Reserved) {
ExFreePool(deviceExtension->PasswordOrbContext.Reserved);
deviceExtension->PasswordOrbContext.Reserved = NULL;
}
#endif
if (deviceExtension->DeferredPowerRequest) {
deviceExtension->DeferredPowerRequest->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
IoCompleteRequest(deviceExtension->DeferredPowerRequest, IO_NO_INCREMENT);
deviceExtension->DeferredPowerRequest = NULL;
}
if (deviceExtension->UniSymLinkName.Buffer) {
IoDeleteSymbolicLink(&deviceExtension->UniSymLinkName);
RtlFreeUnicodeString(&deviceExtension->UniSymLinkName);
deviceExtension->UniSymLinkName.Buffer = NULL;
}
//
// before we go any further, check if the device is physically removed
//
if (!TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_REMOVED)) {
DEBUGPRINT2(("Sbp2Port: Cleanup: ext=x%p, not freeing ALL wkg sets, dev present\n", deviceExtension));
return TRUE;
} else {
DEBUGPRINT2(("Sbp2Port: Cleanup: ext=x%p, freeing ALL wkg sets\n", deviceExtension));
}
CLEAR_FLAG(deviceExtension->DeviceFlags, (DEVICE_FLAG_INITIALIZED | DEVICE_FLAG_INITIALIZING));
//
// OK to free common buffer if device is going away
//
FreeAddressRange(deviceExtension,&deviceExtension->CommonBufferContext);
deviceExtension->OrbPoolContext.Reserved = NULL;
//
// Free all the page tables & async context buffer
//
if (deviceExtension->AsyncContextBase != NULL) {
for (i = 0; i < MAX_ORB_LIST_DEPTH; i++) {
PASYNC_REQUEST_CONTEXT context;
context = deviceExtension->AsyncContextBase + i;
if (context->PageTableContext.PageTable != NULL) {
//
// Common buffer, we didn't alloc the mdl,
// so zero the field to prevent our free'ing it
//
context->PageTableContext.AddressContext.
RequestMdl = NULL;
FreeAddressRange(
deviceExtension,
&context->PageTableContext.AddressContext
);
}
}
ExFreePool (deviceExtension->AsyncContextBase);
deviceExtension->AsyncContextBase = NULL;
}
//
// free pool for status fifo list
//
if (deviceExtension->StatusFifoBase !=NULL ) {
statusFifoElement = (PVOID) ExInterlockedPopEntrySList (&deviceExtension->StatusFifoListHead,
&deviceExtension->StatusFifoLock);
while (statusFifoElement){
DEBUGPRINT3(("Sbp2Port: Cleanup: freeing statusFifo=x%p, fifoBase=x%p\n",
statusFifoElement,deviceExtension->StatusFifoBase));
IoFreeMdl (statusFifoElement->FifoMdl);
statusFifoElement = (PVOID) ExInterlockedPopEntrySList (&deviceExtension->StatusFifoListHead,
&deviceExtension->StatusFifoLock);
};
ExFreePool (deviceExtension->StatusFifoBase);
deviceExtension->StatusFifoBase = NULL;
}
//
// free the irb/irp and context slists
//
packet = (PIRBIRP) ExInterlockedPopEntrySList (&deviceExtension->BusRequestIrpIrbListHead,
&deviceExtension->BusRequestLock);
while (packet) {
ExFreePool(packet->Irb);
if (packet->Irp->Type == IO_TYPE_IRP) {
IoFreeIrp(packet->Irp);
}
ExFreePool(packet);
packet = (PIRBIRP) ExInterlockedPopEntrySList (&deviceExtension->BusRequestIrpIrbListHead,
&deviceExtension->BusRequestLock);
};
rContext = (PREQUEST_CONTEXT) ExInterlockedPopEntrySList (&deviceExtension->BusRequestContextListHead,
&deviceExtension->BusRequestLock);
while (rContext) {
ExFreePool (rContext);
rContext = (PREQUEST_CONTEXT) ExInterlockedPopEntrySList (&deviceExtension->BusRequestContextListHead,
&deviceExtension->BusRequestLock);
};
if (deviceExtension->ReservedMdl) {
IoFreeMdl (deviceExtension->ReservedMdl);
deviceExtension->ReservedMdl = NULL;
}
//
// free the model leaf
//
if (deviceExtension->DeviceInfo->ModelLeaf) {
ExFreePool (deviceExtension->DeviceInfo->ModelLeaf);
deviceExtension->DeviceInfo->ModelLeaf = NULL;
}
}
}
} else {
fdoExtension = (PFDO_DEVICE_EXTENSION) deviceExtension;
if (fdoExtension->Sbp2ObjectDirectory != NULL) {
ZwMakeTemporaryObject (fdoExtension->Sbp2ObjectDirectory);
ZwClose (fdoExtension->Sbp2ObjectDirectory);
fdoExtension->Sbp2ObjectDirectory = NULL;
}
if (fdoExtension->VendorLeaf) {
ExFreePool (fdoExtension->VendorLeaf);
fdoExtension->VendorLeaf = NULL;
}
if (TEST_FLAG(fdoExtension->DeviceFlags,DEVICE_FLAG_REMOVED)) {
return FALSE;
} else {
SET_FLAG (fdoExtension->DeviceFlags, DEVICE_FLAG_REMOVED);
}
if (fdoExtension->DeviceListSize != 0) {
//
// Disable bus reset notifications
//
AllocateIrpAndIrb ((PDEVICE_EXTENSION) fdoExtension, &packet);
if (packet) {
packet->Irb->FunctionNumber = REQUEST_BUS_RESET_NOTIFICATION;
packet->Irb->Flags = 0;
packet->Irb->u.BusResetNotification.fulFlags =
DEREGISTER_NOTIFICATION_ROUTINE;
Sbp2SendRequest(
(PDEVICE_EXTENSION) fdoExtension,
packet,
SYNC_1394_REQUEST
);
DeAllocateIrpAndIrb ((PDEVICE_EXTENSION) fdoExtension, packet);
}
}
//
// Clean up any remaining PDO's
//
KeAcquireSpinLock (&fdoExtension->DeviceListLock,&cIrql);
for (; fdoExtension->DeviceListSize > 0; fdoExtension->DeviceListSize--) {
i = fdoExtension->DeviceListSize - 1;
if (fdoExtension->DeviceList[i].DeviceObject) {
deviceExtension =
fdoExtension->DeviceList[i].DeviceObject->DeviceExtension;
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_REMOVED);
DeviceObject = fdoExtension->DeviceList[i].DeviceObject;
KeReleaseSpinLock (&fdoExtension->DeviceListLock, cIrql);
if (Sbp2CleanDeviceExtension (DeviceObject, TRUE)) {
//
// Acquire the pdo's remove lock, start the queue
// cleanup, and and wait for io to complete. Then
// delete the device & continue.
//
IoAcquireRemoveLock (&deviceExtension->RemoveLock, NULL);
KeRaiseIrql (DISPATCH_LEVEL, &cIrql);
Sbp2StartNextPacketByKey (DeviceObject, 0);
KeLowerIrql (cIrql);
DEBUGPRINT2((
"Sbp2Port: CleanDevExt: walking fdo, wait for " \
"io compl pdo=x%p...\n",
DeviceObject
));
IoReleaseRemoveLockAndWait(
&deviceExtension->RemoveLock,
NULL
);
deviceExtension->Type = SBP2_PDO_DELETED;
KeCancelTimer(&deviceExtension->DeviceManagementTimer);
IoDeleteDevice (DeviceObject);
DEBUGPRINT2((
"Sbp2Port: CleanDevExt: ............ io compl," \
" deleted pdo=x%p\n",
DeviceObject
));
KeAcquireSpinLock (&fdoExtension->DeviceListLock, &cIrql);
fdoExtension->DeviceList[i].DeviceObject = NULL;
} else {
KeAcquireSpinLock (&fdoExtension->DeviceListLock, &cIrql);
}
}
if (fdoExtension->DeviceList[i].ModelLeaf) {
ExFreePool (fdoExtension->DeviceList[i].ModelLeaf);
fdoExtension->DeviceList[i].ModelLeaf = NULL;
}
}
KeReleaseSpinLock (&fdoExtension->DeviceListLock, cIrql);
}
return TRUE;
}
VOID
Sbp2Unload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Does nothing really...
Arguments:
DriverObject - the driver being unloaded
Return Value:
none
--*/
{
DEBUGPRINT1(("Sbp2Port: unloading\n\n"));
return;
}
VOID
Sbp2DeviceManagementTimeoutDpc(
IN PKDPC Dpc,
IN PDEVICE_EXTENSION DeviceExtension,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
{
ULONG i;
PDEVICE_EXTENSION pdoExtension;
PFDO_DEVICE_EXTENSION fdoExtension;
if (Dpc != &DeviceExtension->DeviceManagementTimeoutDpc) {
return;
}
if (TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_REMOVED)) {
return;
}
if (TEST_FLAG(DeviceExtension->DeviceFlags,DEVICE_FLAG_RECONNECT)) {
//
// The flag indicates that a bus reset occured, and a reconnect never happened...
// OR that the device is realy hose so we reset it and we need to re-login
//
DEBUGPRINT1((
"Sbp2Port: RECONNECT timeout, Ext=x%p, Flags=x%x, doing re-login\n",
DeviceExtension,
DeviceExtension->DeviceFlags
));
//
// all the resident 1394 memory addresses's that we have, are
// now invalidated... So we need to free them and re-allocate
// them
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
CLEAR_FLAG(DeviceExtension->DeviceFlags,DEVICE_FLAG_RECONNECT);
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
//
// If device is marked STOPPED then a target reset was
// done and that affected all LUNs (spec sect 10.4.4).
// So if this is a multilun device try logins on each
// pdo as appropriate.
//
fdoExtension = (PFDO_DEVICE_EXTENSION)
DeviceExtension->BusFdo->DeviceExtension;
if ((fdoExtension->DeviceListSize > 1) &&
TEST_FLAG (DeviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED)) {
for (i = 0; i < fdoExtension->DeviceListSize; i++) {
pdoExtension = (PDEVICE_EXTENSION)
fdoExtension->DeviceList[i].DeviceObject->DeviceExtension;
if (pdoExtension->DeviceObject ==
DeviceExtension->DeviceObject) {
// No need to update node info since no bus reset done
Sbp2ManagementTransaction(
pdoExtension,
TRANSACTION_LOGIN
);
continue;
}
KeAcquireSpinLockAtDpcLevel(
&pdoExtension->ExtensionDataSpinLock
);
if (TEST_FLAG(
pdoExtension->DeviceFlags,
DEVICE_FLAG_INITIALIZED
) &&
!TEST_FLAG(
pdoExtension->DeviceFlags,
DEVICE_FLAG_STOPPED | DEVICE_FLAG_RESET_IN_PROGRESS |
DEVICE_FLAG_REMOVED | DEVICE_FLAG_LOGIN_IN_PROGRESS |
DEVICE_FLAG_RECONNECT | DEVICE_FLAG_DEVICE_FAILED |
DEVICE_FLAG_SURPRISE_REMOVED
)) {
SET_FLAG(
pdoExtension->DeviceFlags,
(DEVICE_FLAG_STOPPED | DEVICE_FLAG_RESET_IN_PROGRESS)
);
KeReleaseSpinLockFromDpcLevel(
&pdoExtension->ExtensionDataSpinLock
);
CleanupOrbList (pdoExtension, STATUS_REQUEST_ABORTED);
// No need to update node info since no bus reset done
Sbp2ManagementTransaction(
pdoExtension,
TRANSACTION_LOGIN
);
} else {
KeReleaseSpinLockFromDpcLevel(
&pdoExtension->ExtensionDataSpinLock
);
}
}
} else {
Sbp2UpdateNodeInformation (DeviceExtension);
Sbp2ManagementTransaction (DeviceExtension, TRANSACTION_LOGIN);
}
return ;
}
if (TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_LOGIN_IN_PROGRESS)) {
ULONG flags;
//
// the asynchronous login attempt timed out. This is bad news and means the
// device is not responding
//
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
flags = DeviceExtension->DeviceFlags;
CLEAR_FLAG(DeviceExtension->DeviceFlags,(DEVICE_FLAG_LOGIN_IN_PROGRESS | DEVICE_FLAG_RESET_IN_PROGRESS));
SET_FLAG(DeviceExtension->DeviceFlags, (DEVICE_FLAG_STOPPED | DEVICE_FLAG_DEVICE_FAILED));
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
//
// check if we had a power irp deferred.. If we did call startio to abort it..
//
if (DeviceExtension->DeferredPowerRequest) {
Sbp2StartIo(DeviceExtension->DeviceObject,DeviceExtension->DeferredPowerRequest);
DeviceExtension->DeferredPowerRequest = NULL;
}
DEBUGPRINT1((
"Sbp2Port: LOGIN timeout, Ext=x%p, Flags=x%x, device stopped\n",
DeviceExtension,
flags
));
Sbp2StartNextPacketByKey (DeviceExtension->DeviceObject, 0);
IoInvalidateDeviceState(DeviceExtension->DeviceObject);
return;
}
if (TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_RESET_IN_PROGRESS)) {
//
// the reset attempt has timed out
//
DEBUGPRINT1((
"Sbp2Port: RESET timeout, Ext=x%p, Flags=x%x, ",
DeviceExtension,
DeviceExtension->DeviceFlags
));
if (!TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED)) {
//
// Second level of recovery, do a TARGET_RESET task function
//
DEBUGPRINT1(("doing target reset\n"));
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
SET_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
DeviceExtension->MaxOrbListDepth = max(MIN_ORB_LIST_DEPTH,DeviceExtension->MaxOrbListDepth/2);
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
CleanupOrbList(DeviceExtension,STATUS_REQUEST_ABORTED);
//
// we are close to timing out a reset, try a hard reset
//
Sbp2Reset (DeviceExtension->DeviceObject, TRUE);
return;
} else {
//
// Third level of recovery. Do a hardware node reset
//
DEBUGPRINT1(("doing CMD_RESET and relogin.\n"));
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
DeviceExtension->Reserved = 0;
SET_FLAG(DeviceExtension->DeviceFlags, (DEVICE_FLAG_RESET_IN_PROGRESS | DEVICE_FLAG_RECONNECT | DEVICE_FLAG_STOPPED));
DeviceExtension->DueTime.HighPart = -1;
DeviceExtension->DueTime.LowPart = SBP2_RELOGIN_DELAY;
KeSetTimer(&DeviceExtension->DeviceManagementTimer,DeviceExtension->DueTime, &DeviceExtension->DeviceManagementTimeoutDpc);
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->ExtensionDataSpinLock);
Sbp2AccessRegister(DeviceExtension,&DeviceExtension->Reserved,CORE_RESET_REG | REG_WRITE_ASYNC);
return;
}
}
}
VOID
Sbp2RequestTimeoutDpc(
IN PKDPC Dpc,
IN PDEVICE_EXTENSION DeviceExtension,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
Arguments:
DeviceObject - Our Device object
Context - DeviceExtension
Return Value:
NTSTATUS
--*/
{
PIRP requestIrp = NULL;
PASYNC_REQUEST_CONTEXT current = NULL;
PASYNC_REQUEST_CONTEXT next = NULL;
#if DBG
ULONG xferLen;
UCHAR cdb[6];
#endif
//
// return if device is stopped, but since reset can occur while device is stopped
// thats why this check is ater the reset timing code
//
if (IsListEmpty (&DeviceExtension->PendingOrbList)) {
return ;
}
//
// search the linked list of contexts, to see which guy timed out
//
KeAcquireSpinLockAtDpcLevel(&DeviceExtension->OrbListSpinLock);
next = RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Flink,OrbList);
do {
current = next;
if ((&current->TimerDpc == Dpc) && (current->Flags & ASYNC_CONTEXT_FLAG_TIMER_STARTED)) {
if (TEST_FLAG(current->Flags,ASYNC_CONTEXT_FLAG_COMPLETED)) {
DEBUGPRINT1(("Sbp2Port: ReqTimeoutDpc: timeout, but req already compl!!\n" ));
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->OrbListSpinLock);
return;
}
//
// this is the timed out request
// do an abort Task Set
//
CLEAR_FLAG(current->Flags,ASYNC_CONTEXT_FLAG_TIMER_STARTED);
KeCancelTimer(&current->Timer);
#if DBG
xferLen = current->Srb->DataTransferLength;
cdb[0] = current->Srb->Cdb[0];
cdb[1] = current->Srb->Cdb[1];
cdb[2] = current->Srb->Cdb[2];
cdb[3] = current->Srb->Cdb[3];
cdb[4] = current->Srb->Cdb[4];
cdb[5] = current->Srb->Cdb[5];
#endif
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->OrbListSpinLock);
Sbp2CreateRequestErrorLog(DeviceExtension->DeviceObject,current,STATUS_TIMEOUT);
if (!TEST_FLAG(DeviceExtension->DeviceFlags,DEVICE_FLAG_RESET_IN_PROGRESS)){
DEBUGPRINT1((
"Sbp2Port: ReqTimeoutDpc: cdb=x%02x %02x %02x %02x %02x " \
"%02x, len=x%x\n",
cdb[0],
cdb[1],
cdb[2],
cdb[3],
cdb[4],
cdb[5],
xferLen
));
Sbp2Reset (DeviceExtension->DeviceObject, FALSE);
}
return;
}
next = (PASYNC_REQUEST_CONTEXT) current->OrbList.Flink;
} while ( current != RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Blink,OrbList));
KeReleaseSpinLockFromDpcLevel(&DeviceExtension->OrbListSpinLock);
return;
}
VOID
Sbp2Reset(
PDEVICE_OBJECT DeviceObject,
BOOLEAN HardReset
)
/*++
Routine Description:
Used to implement SBP2 high level recovery mechanisms. It will issue an ABORT_TASK_SET if HardReset == FALSE
otherswise it will issue a RESET_TARGET. Its all done asynchronously and out timer DPC will track the requests
to check if they timed out...
Arguments:
DeviceObject= Sbp2 driver's device object
HardReset = Type of recovery to perform, TRUE is a target reset, FALSE is an abort task set
Return Value:
NTSTATUS
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
KIRQL oldIrql;
NTSTATUS status;
#if DBG
ULONG generation;
#endif
if ((deviceExtension->DeviceFlags & DEVICE_FLAG_REMOVED) ||
(deviceExtension->DeviceFlags & DEVICE_FLAG_RECONNECT)) {
return;
}
if (HardReset == TRUE) {
DEBUGPRINT2(("Sbp2Port: Reset: ext=x%p, do target reset\n", deviceExtension ));
//
// Do a target reset
//
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock,&oldIrql);
deviceExtension->TaskOrbContext.TransactionType = TRANSACTION_TARGET_RESET;
deviceExtension->TaskOrb->OrbInfo.QuadPart = 0;
deviceExtension->TaskOrb->OrbInfo.u.HighPart |= ORB_NOTIFY_BIT_MASK;
deviceExtension->TaskOrb->OrbInfo.u.HighPart |= 0x00FF & TRANSACTION_TARGET_RESET;
deviceExtension->TaskOrb->OrbInfo.u.LowPart =
deviceExtension->LoginResponse->LengthAndLoginId.u.LowPart; // LOGIN ID
deviceExtension->TaskOrb->StatusBlockAddress.BusAddress =
deviceExtension->TaskOrbStatusContext.Address.BusAddress;
//
// endian conversion
//
octbswap (deviceExtension->TaskOrb->StatusBlockAddress);
deviceExtension->TaskOrb->OrbInfo.QuadPart =
bswap(deviceExtension->TaskOrb->OrbInfo.QuadPart);
//
// send the task ORB , mark start of reset/abort
//
deviceExtension->DeviceFlags |= DEVICE_FLAG_RESET_IN_PROGRESS;
//
// now set the timer to track this request
//
deviceExtension->DueTime.HighPart = -1;
deviceExtension->DueTime.LowPart = SBP2_HARD_RESET_TIMEOUT;
KeSetTimer(&deviceExtension->DeviceManagementTimer,deviceExtension->DueTime,&deviceExtension->DeviceManagementTimeoutDpc);
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,oldIrql);
status = Sbp2AccessRegister(deviceExtension, &deviceExtension->TaskOrbContext.Address, MANAGEMENT_AGENT_REG | REG_WRITE_ASYNC);
if (status == STATUS_INVALID_GENERATION) {
KeCancelTimer(&deviceExtension->DeviceManagementTimer);
#if DBG
//
// Check to see if perhaps we didn't get the reset
// notification we were expecting
//
generation = deviceExtension->CurrentGeneration;
status = Sbp2UpdateNodeInformation (deviceExtension);
DEBUGPRINT1((
"Sbp2Port: Reset: target reset error, sts=x%x, extGen=x%x, " \
"curGen=x%x\n",
status,
generation,
deviceExtension->CurrentGeneration
));
#endif
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&oldIrql);
SET_FLAG(deviceExtension->DeviceFlags, (DEVICE_FLAG_STOPPED | DEVICE_FLAG_DEVICE_FAILED));
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,oldIrql);
//
// check if we had a power irp deferred.. If we did call startio to abort it..
//
if (deviceExtension->DeferredPowerRequest) {
Sbp2StartIo(deviceExtension->DeviceObject,deviceExtension->DeferredPowerRequest);
deviceExtension->DeferredPowerRequest = NULL;
}
Sbp2StartNextPacketByKey (deviceExtension->DeviceObject, 0);
return;
}
} else {
DEBUGPRINT2(("Sbp2Port: Reset: ext=x%p, do abort task set\n", deviceExtension ));
//
// Do an abort task set
//
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock,&oldIrql);
deviceExtension->TaskOrbContext.TransactionType = TRANSACTION_ABORT_TASK_SET;
deviceExtension->TaskOrb->OrbInfo.QuadPart = 0;
deviceExtension->TaskOrb->OrbInfo.u.HighPart |= ORB_NOTIFY_BIT_MASK;
deviceExtension->TaskOrb->OrbInfo.u.HighPart |= 0x00FF & TRANSACTION_ABORT_TASK_SET;
deviceExtension->TaskOrb->OrbInfo.u.LowPart =
deviceExtension->LoginResponse->LengthAndLoginId.u.LowPart; // LOGIN ID
deviceExtension->TaskOrb->StatusBlockAddress.BusAddress =
deviceExtension->TaskOrbStatusContext.Address.BusAddress;
//
// endian conversion
//
octbswap (deviceExtension->TaskOrb->StatusBlockAddress);
deviceExtension->TaskOrb->OrbInfo.QuadPart =
bswap (deviceExtension->TaskOrb->OrbInfo.QuadPart);
//
// send the task ORB , mark start of reset/abort
//
deviceExtension->DeviceFlags |= DEVICE_FLAG_RESET_IN_PROGRESS;
//
// now set the timer to track this request
//
deviceExtension->DueTime.HighPart = -1;
deviceExtension->DueTime.LowPart = SBP2_RESET_TIMEOUT;
KeSetTimer(&deviceExtension->DeviceManagementTimer,deviceExtension->DueTime,&deviceExtension->DeviceManagementTimeoutDpc);
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,oldIrql);
Sbp2AccessRegister(deviceExtension, &deviceExtension->TaskOrbContext.Address, MANAGEMENT_AGENT_REG | REG_WRITE_ASYNC);
}
}
NTSTATUS
Sbp2DeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the device control dispatcher.
Arguments:
DeviceObject
Irp
Return Value:
NTSTATUS
--*/
{
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
NTSTATUS status;
if (deviceExtension->Type == SBP2_PDO) {
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_STORAGE_QUERY_PROPERTY: {
//
// Validate the query
//
PSTORAGE_PROPERTY_QUERY query = Irp->AssociatedIrp.SystemBuffer;
if(irpStack->Parameters.DeviceIoControl.InputBufferLength <
sizeof(STORAGE_PROPERTY_QUERY)) {
status = STATUS_INVALID_PARAMETER;
break;
}
status = Sbp2QueryProperty(DeviceObject, Irp);
break;
}
case IOCTL_SCSI_PASS_THROUGH:
case IOCTL_SCSI_PASS_THROUGH_DIRECT:
status = Sbp2SendPassThrough(deviceExtension, Irp);
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
break;
case IOCTL_SBP2_REQUEST:
status = Sbp2HandleApiRequest(deviceExtension, Irp);
break;
default:
DEBUGPRINT3(("Sbp2Port: Sbp2DeviceControl: Irp Not Handled.\n" ));
status = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Status =status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
break;
}
} else {
status = STATUS_NOT_SUPPORTED;
Irp->IoStatus.Status =status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
}
return status;
}
NTSTATUS
Sbp2HandleApiRequest(
IN PDEVICE_EXTENSION DeviceExtension,
IN PIRP Irp
)
{
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PSBP2_REQUEST sbp2Req;
NTSTATUS status;
status = IoAcquireRemoveLock (&DeviceExtension->RemoveLock, NULL);
if (!NT_SUCCESS (status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return status;
}
if (Irp->RequestorMode == KernelMode) {
sbp2Req = irpStack->Parameters.Others.Argument1;
} else { // UserMode
sbp2Req = Irp->AssociatedIrp.SystemBuffer;
}
if (sbp2Req == NULL) {
DEBUGPRINT1(("Sbp2Port: HandleApiReq: Invalid sbp2Req!"));
status = STATUS_INVALID_PARAMETER;
goto Exit_Sbp2HandleApiRequest;
}
status = STATUS_NOT_IMPLEMENTED;
switch (sbp2Req->RequestNumber) {
case SBP2_REQUEST_RETRIEVE_TEXT_LEAFS:
//
// Only allow kernel-mode requests of this type, since the
// RetrieveTextLeaf definition currently has us passing
// back a buf alloc'd via ExAllocPool - not something we
// want to hand back to user-mode.
//
if (Irp->RequestorMode == KernelMode) {
status = Sbp2Get1394ConfigInfo(
(PFDO_DEVICE_EXTENSION)
DeviceExtension->BusFdo->DeviceExtension,
sbp2Req
);
}
break;
case SBP2_REQUEST_ACCESS_TRANSPORT_SETTINGS:
switch (sbp2Req->u.AccessTransportSettings.Parameter) {
case SBP2REQ_ACCESS_SETTINGS_QUEUE_SIZE:
if (sbp2Req->Flags & SBP2REQ_FLAG_RETRIEVE_VALUE) {
sbp2Req->u.AccessTransportSettings.Value =
DeviceExtension->MaxOrbListDepth;
} else if (sbp2Req->Flags & SBP2REQ_FLAG_MODIFY_VALUE) {
DeviceExtension->MaxOrbListDepth = min(
MAX_ORB_LIST_DEPTH,
sbp2Req->u.AccessTransportSettings.Value
);
DeviceExtension->MaxOrbListDepth = max(
MIN_ORB_LIST_DEPTH,
sbp2Req->u.AccessTransportSettings.Value
);
sbp2Req->u.AccessTransportSettings.Value =
DeviceExtension->MaxOrbListDepth;
}
status = STATUS_SUCCESS;
break;
}
break;
#if PASSWORD_SUPPORT
case SBP2_REQUEST_SET_PASSWORD:
if (sbp2Req->u.SetPassword.fulFlags == SBP2REQ_SET_PASSWORD_CLEAR) {
DEBUGPRINT1(("Sbp2Port: Setting Password to Clear\n"));
status = Sbp2SetPasswordTransaction(
DeviceExtension,
SBP2REQ_SET_PASSWORD_CLEAR
);
if (NT_SUCCESS(status)) {
DeviceExtension->Exclusive = EXCLUSIVE_FLAG_CLEAR;
}
} else if (sbp2Req->u.SetPassword.fulFlags ==
SBP2REQ_SET_PASSWORD_EXCLUSIVE) {
DEBUGPRINT1 (("Sbp2Port: HandleApiReq: set passwd to excl\n"));
status = Sbp2SetPasswordTransaction(
DeviceExtension,
SBP2REQ_SET_PASSWORD_EXCLUSIVE
);
if (NT_SUCCESS(status)) {
DeviceExtension->Exclusive = EXCLUSIVE_FLAG_SET;
}
} else {
DEBUGPRINT1((
"Sbp2Port: HandleApiReq: set passwd, inval fl=x%x\n",
sbp2Req->u.SetPassword.fulFlags
));
status = STATUS_INVALID_PARAMETER;
goto Exit_Sbp2HandleApiRequest;
}
Sbp2SetExclusiveValue(
DeviceExtension->DeviceObject,
&DeviceExtension->Exclusive
);
DEBUGPRINT1((
"Sbp2Port: HandleApiReq: set passwd sts=x%x\n",
status
));
break;
#endif
default:
status = STATUS_INVALID_PARAMETER;
break;
}
Exit_Sbp2HandleApiRequest:
Irp->IoStatus.Status = status;
IoReleaseRemoveLock (&DeviceExtension->RemoveLock, NULL);
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return status;
}
NTSTATUS
Sbp2CreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
create and close routine. This is called by the I/O system
when the device is opened or closed. The sbp2 driver will do login and logout on
create/close respectively
Arguments:
DeviceObject - Pointer to device object for this miniport
Irp - IRP involved.
Return Value:
STATUS_SUCCESS.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
if (deviceExtension->Type == SBP2_PDO) {
if ((deviceExtension->InquiryData.DeviceType == PRINTER_DEVICE) ||
(deviceExtension->InquiryData.DeviceType == SCANNER_DEVICE)){
if (!(deviceExtension->DeviceFlags & DEVICE_FLAG_INITIALIZING)) {
status = IoAcquireRemoveLock(
&deviceExtension->RemoveLock,
NULL
);
if (!NT_SUCCESS (status)) {
goto Sbp2CreateClose_CompleteReq;
}
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
DEBUGPRINT2(("Sbp2Port: Sbp2CreateClose: OPEN_REQUEST, handle cound %d.\n", deviceExtension->HandleCount));
if (deviceExtension->DeviceFlags & DEVICE_FLAG_STOPPED) {
//
// do a login.
//
DEBUGPRINT2(("Sbp2Port: Sbp2CreateClose: LOGIN.\n" ));
status = Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGIN);
if (status == STATUS_SUCCESS) {
//
// make retry limit high for busy transactions
//
deviceExtension->Reserved = BUSY_TIMEOUT_SETTING;
Sbp2AccessRegister(deviceExtension,&deviceExtension->Reserved,CORE_BUSY_TIMEOUT_REG | REG_WRITE_SYNC);
//
// We are ready to receive and pass down requests, init the target's
// fetch agent.
//
Sbp2AccessRegister(deviceExtension,&deviceExtension->Reserved,AGENT_RESET_REG | REG_WRITE_ASYNC);
deviceExtension->DeviceFlags &= ~DEVICE_FLAG_STOPPED;
InterlockedIncrement(&deviceExtension->HandleCount);
}
} else {
InterlockedIncrement(&deviceExtension->HandleCount);
}
break;
case IRP_MJ_CLOSE:
if (deviceExtension->HandleCount) {
InterlockedDecrement(&deviceExtension->HandleCount);
}
DEBUGPRINT2(("Sbp2Port: Sbp2CreateClose: CLOSE_REQUEST, handle cound %d.\n", deviceExtension->HandleCount));
if (!(deviceExtension->DeviceFlags & (DEVICE_FLAG_REMOVED | DEVICE_FLAG_STOPPED)) &&
!deviceExtension->HandleCount) {
//
// Logout
//
DEBUGPRINT2(("Sbp2Port: Sbp2CreateClose: LOGIN OUT.\n" ));
deviceExtension->DeviceFlags |= DEVICE_FLAG_STOPPED;
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGOUT);
CleanupOrbList(deviceExtension,STATUS_REQUEST_ABORTED);
}
break;
}
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
}
} // device type check
} else if (deviceExtension->Type != SBP2_FDO) {
status = STATUS_NO_SUCH_DEVICE;
}
Sbp2CreateClose_CompleteReq:
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, 0);
return status;
}
NTSTATUS
Sbp2PnpDeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This routine handles the PNP requests (primarily for PDO's)
Arguments:
DeviceObject - Supplies a pointer to the device object for this request.
Irp - Supplies the Irp making the request.
Return Value:
NTSTATUS
--*/
{
KIRQL cIrql;
PULONG count;
NTSTATUS status;
UNICODE_STRING unicodeIdString;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PDEVICE_RELATIONS deviceRelations;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
PDEVICE_CAPABILITIES deviceCapabilities;
PFDO_DEVICE_EXTENSION fdoExtension;
#if DBG
const char * minorFuncs[] =
{
"START_DEV, ",
"QUERY_REMOVE_DEV, ",
"REMOVE_DEV, ",
"CANCEL_REMOVE_DEV, ",
"STOP_DEV, ",
"QUERY_STOP_DEV, ",
"CANCEL_STOP_DEV, ",
"QUERY_DEV_RELATIONS, ",
"QUERY_INTERFACE, ",
"QUERY_CAPABILITIES, ",
"QUERY_RESOURCES, ",
"QUERY_RESOURCE_REQS, ",
"QUERY_DEV_TEXT, ",
"FILTER_RESOURCE_REQS,",
"??, ", // 0xd (14)
"READ_CFG, ",
"WRITE_CFG, ",
"EJECT, ",
"SET_LOCK, ",
"QUERY_ID, ",
"QUERY_PNP_DEV_STATE, ",
"QUERY_BUS_INFO, ",
"DEV_USAGE_NOTIF, ",
"SURPRISE_REMOVAL, ",
"QUERY_LEG_BUS_INFO, " // 0x18
};
DEBUGPRINT2((
"Sbp2Port: Pnp: [x%02x] %s %sdoX=x%p, fl=x%x\n",
irpStack->MinorFunction,
(irpStack->MinorFunction <= 0x18 ?
minorFuncs[irpStack->MinorFunction] : minorFuncs[14]),
(deviceExtension->Type == SBP2_PDO ? "p" :
(deviceExtension->Type == SBP2_FDO ? "f" : "???")),
deviceExtension,
deviceExtension->DeviceFlags
));
#endif
//
// We may receive an IRP_MN_BUS_RESET before our AddDevice
// has completed. Check to make sure our DeviceObject is
// initialized before we allow processing of PNP Irps.
//
if (DeviceObject->Flags & DO_DEVICE_INITIALIZING) {
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return(STATUS_NO_SUCH_DEVICE);
}
switch (deviceExtension->Type) {
case SBP2_PDO:
break;
case SBP2_FDO:
return Sbp2FDOPnpDeviceControl (DeviceObject, Irp);
default:
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
return STATUS_NO_SUCH_DEVICE;
}
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, NULL);
if (!NT_SUCCESS (status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
return status;
}
switch (irpStack->MinorFunction) {
case IRP_MN_QUERY_DEVICE_RELATIONS:
DEBUGPRINT3((
"Sbp2Port: Pnp: ... Type = %x\n",
irpStack->Parameters.QueryDeviceRelations.Type
));
//
// Fill in the DeviceRelations array with this PDO,
// reference it, and return.
//
if (irpStack->Parameters.QueryDeviceRelations.Type !=
TargetDeviceRelation) {
status = Irp->IoStatus.Status;
break;
}
if (Irp->IoStatus.Information) {
deviceRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
} else {
deviceRelations = ExAllocatePool(
PagedPool,
sizeof (*deviceRelations)
);
if (!deviceRelations) {
Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
break;
}
deviceRelations->Count = 0;
}
deviceRelations->Objects[deviceRelations->Count] = DeviceObject;
deviceRelations->Count++;
ObReferenceObject (DeviceObject);
status = Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
break;
case IRP_MN_QUERY_DEVICE_TEXT:
Irp->IoStatus.Status = Sbp2QueryDeviceText(
deviceExtension,
irpStack->Parameters.QueryDeviceText.DeviceTextType,
irpStack->Parameters.QueryDeviceText.LocaleId,
(PWSTR *) &Irp->IoStatus.Information
);
status = Irp->IoStatus.Status;
break;
case IRP_MN_QUERY_ID:
//
// We've been asked for the id of one of the physical device objects
//
RtlInitUnicodeString (&unicodeIdString, NULL);
switch (irpStack->Parameters.QueryId.IdType) {
case BusQueryDeviceID:
status = Sbp2GetDeviceId (DeviceObject, &unicodeIdString);
break;
case BusQueryInstanceID:
status = Sbp2GetInstanceId (DeviceObject, &unicodeIdString);
break;
case BusQueryHardwareIDs:
status = Sbp2GetMultipleIds (DeviceObject, &unicodeIdString, TRUE);
break;
case BusQueryCompatibleIDs:
status = Sbp2GetMultipleIds (DeviceObject, &unicodeIdString,FALSE);
break;
default:
status = STATUS_NOT_SUPPORTED;
break;
}
Irp->IoStatus.Status = status;
if(NT_SUCCESS(status)) {
Irp->IoStatus.Information = (ULONG_PTR) unicodeIdString.Buffer;
} else {
Irp->IoStatus.Information = (ULONG_PTR) NULL;
}
break;
case IRP_MN_QUERY_CAPABILITIES:
deviceCapabilities =
irpStack->Parameters.DeviceCapabilities.Capabilities;
//
// Settings consistent across all 1394 devices
//
deviceCapabilities->Removable = TRUE;
deviceCapabilities->UniqueID = TRUE;
deviceCapabilities->SilentInstall = TRUE;
//
// Settings for different types of devices. We are very
// familar with SCSI-variant devices and can make some
// good choices here, but for other devices we'll leave
// these choices up to the higher-level driver(s).
//
switch (deviceExtension->DeviceInfo->CmdSetId.QuadPart) {
case 0x10483:
case SCSI_COMMAND_SET_ID:
switch ((deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F)) {
case PRINTER_DEVICE:
case SCANNER_DEVICE:
deviceCapabilities->RawDeviceOK = FALSE;
deviceCapabilities->SurpriseRemovalOK = TRUE;
break;
default:
deviceCapabilities->RawDeviceOK = TRUE;
break;
}
break;
default:
break;
}
deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
deviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD3;
deviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;
deviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;
deviceCapabilities->DeviceState[PowerSystemHibernate] = PowerDeviceD3;
deviceCapabilities->DeviceState[PowerSystemShutdown] = PowerDeviceD3;
deviceCapabilities->SystemWake = PowerSystemUnspecified;
deviceCapabilities->DeviceWake = PowerDeviceUnspecified;
deviceCapabilities->D1Latency = 1 * (1000 * 10); // 1 sec
deviceCapabilities->D2Latency = 1 * (1000 * 10); // 1
deviceCapabilities->D3Latency = 1 * (1000 * 10); // 1
status = Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
case IRP_MN_START_DEVICE:
status = Sbp2StartDevice (DeviceObject);
Irp->IoStatus.Status = status;
break;
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
status = Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IRP_MN_STOP_DEVICE:
//
// Disable bus reset notifications
//
Sbp2EnableBusResetNotification (deviceExtension, FALSE);
//
// disable idle detection
//
PoRegisterDeviceForIdleDetection (DeviceObject, 0L, 0L, PowerDeviceD3);
//
// Cleanup
//
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock, &cIrql);
if (!TEST_FLAG(deviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED)) {
SET_FLAG(
deviceExtension->DeviceFlags,
(DEVICE_FLAG_PNP_STOPPED | DEVICE_FLAG_STOPPED)
);
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
fdoExtension = (PFDO_DEVICE_EXTENSION)
deviceExtension->BusFdo->DeviceExtension;
ASSERT(!fdoExtension->ulWorkItemCount);
ExAcquireFastMutex(&fdoExtension->ResetMutex);
Sbp2ManagementTransaction (deviceExtension,TRANSACTION_LOGOUT);
ExReleaseFastMutex(&fdoExtension->ResetMutex);
Sbp2CleanDeviceExtension (DeviceObject,FALSE);
} else {
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_PNP_STOPPED);
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
}
Irp->IoStatus.Status = status = STATUS_SUCCESS;
ASSERT(!deviceExtension->ulPendingEvents);
ASSERT(!deviceExtension->ulInternalEventCount);
break;
case IRP_MN_BUS_RESET:
//
// Start of a PHY reset. We will re-connect asynchronously to the
// target when our callback is called, so this is ignored..
//
// After a bus reset is complete, the bus driver should call our
// BusResetNotification callback. When it does, we will attempt
// to reconnect. If the reconnect completion status callback,
// never fires, it means the following things:
//
// 1) The device never completed the RECONNECT, or
// 2) The device completed the reconnect but because our
// controlller was BUSY or hosed we didnt get it
//
// If 1 or 2 happens, the timeout DPC queued in our bus reset
// notification, should fire and attempt a relogin...
//
Irp->IoStatus.Status = status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
if (TEST_FLAG(
deviceExtension->DeviceFlags,
(DEVICE_FLAG_REMOVED | DEVICE_FLAG_DEVICE_FAILED)
) &&
!TEST_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_RESET_IN_PROGRESS
)){
//
// Set DEVICE_FLAG_REPORTED_FAILED so the SURPRISE_REMOVE
// handler knows it didn't get called because of physical
// hardware removal
//
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock,&cIrql);
SET_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_REPORTED_FAILED
);
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
//
// indicate our device is disabled due to a failure..
//
Irp->IoStatus.Information |= PNP_DEVICE_FAILED;
DEBUGPRINT2((
"Sbp2Port: Pnp: QUERY_DEVICE_STATE, device FAILED!!!\n"
));
}
status = Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
switch (irpStack->Parameters.UsageNotification.Type) {
case DeviceUsageTypeDumpFile:
count = &deviceExtension->CrashDumpCount;
break;
case DeviceUsageTypePaging:
count = &deviceExtension->PagingPathCount;
break;
case DeviceUsageTypeHibernation:
count = &deviceExtension->HibernateCount;
break;
default:
count = NULL;
break;
}
if (count) {
IoAdjustPagingPathCount(
count,
irpStack->Parameters.UsageNotification.InPath
);
}
status = Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
if (deviceExtension->PagingPathCount ||
deviceExtension->HibernateCount ||
deviceExtension->CrashDumpCount) {
status = Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
} else {
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
SET_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_REMOVE_PENDING);
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
status = Irp->IoStatus.Status = STATUS_SUCCESS;
}
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
CLEAR_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_REMOVE_PENDING);
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
status = Irp->IoStatus.Status = STATUS_SUCCESS;
break;
case IRP_MN_REMOVE_DEVICE:
status = STATUS_SUCCESS;
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_PNP_STOPPED);
if (TEST_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_SURPRISE_REMOVED
)) {
//
// We already cleaned up in SURPRISE_REMOVAL handler.
// Empty out the queue, wait for io to complete, then
// delete the device, complete the request, & return.
//
KeReleaseSpinLock(
&deviceExtension->ExtensionDataSpinLock,
cIrql
);
KeRaiseIrql (DISPATCH_LEVEL, &cIrql);
Sbp2StartNextPacketByKey (DeviceObject, 0);
KeLowerIrql (cIrql);
DEBUGPRINT2((
"Sbp2Port: Pnp: wait for io compl pdo=x%p...\n",
DeviceObject
));
IoReleaseRemoveLockAndWait (&deviceExtension->RemoveLock, NULL);
deviceExtension->Type = SBP2_PDO_DELETED;
KeCancelTimer(&deviceExtension->DeviceManagementTimer);
IoDeleteDevice (DeviceObject);
DEBUGPRINT2((
"Sbp2Port: Pnp: ......... deleted pdo=x%p\n", DeviceObject
));
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
if (TEST_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_REMOVE_PENDING
)) {
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
//
// If device is initialized & MgmtOrbCtx event is still around
// then do a log out
//
if (TEST_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_INITIALIZED
) &&
deviceExtension->ManagementOrbContext.Reserved) {
DEBUGPRINT1((
"Sbp2Port: Pnp: LOG OUT, since QUERY preceded RMV\n"
));
fdoExtension = (PFDO_DEVICE_EXTENSION)
deviceExtension->BusFdo->DeviceExtension;
ExAcquireFastMutex(&fdoExtension->ResetMutex);
Sbp2ManagementTransaction(deviceExtension,TRANSACTION_LOGOUT);
ExReleaseFastMutex(&fdoExtension->ResetMutex);
}
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
CLEAR_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_REMOVE_PENDING
);
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
} else if (!TEST_FLAG(
deviceExtension->DeviceFlags,
(DEVICE_FLAG_REMOVED | DEVICE_FLAG_DEVICE_FAILED)
)){
//
// If no query has preceded and NO SUPRISE_REMOVAL has preceded
// this means we are running under win98, where physical device
// removals are only indicated by only MN_REMOVES being sent,
// with no QUERY_REMOVE prior to the remove.
//
if (deviceExtension->DeviceFlags ==
(DEVICE_FLAG_INITIALIZING | DEVICE_FLAG_STOPPED) &&
!SystemIsNT) {
DEBUGPRINT1((
"Sbp2Port: Pnp: 9x REMOVE, don't delete dev\n"
));
deviceExtension->DeviceFlags =
DEVICE_FLAG_UNSTARTED_AND_REMOVED;
} else {
SET_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_REMOVED);
CLEAR_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_RESET_IN_PROGRESS | DEVICE_FLAG_RECONNECT |
DEVICE_FLAG_LOGIN_IN_PROGRESS
);
DEBUGPRINT1((
"Sbp2Port: Pnp: Suprise removal, since QUERY " \
"did not precede REMOVE.\n"
));
}
}
CLEAR_FLAG (deviceExtension->DeviceFlags, DEVICE_FLAG_CLAIMED);
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
if (!Sbp2CleanDeviceExtension (DeviceObject, TRUE)) {
DEBUGPRINT1(("Sbp2Port: Pnp: Double remove\n"));
}
//
// In all cases other than surprise removals, pdo's will get
// deleted by the fdo remove handler
//
Irp->IoStatus.Status = status;
break;
case IRP_MN_SURPRISE_REMOVAL: {
//
// If device was reported failed (due to async login failure &
// IoInvalidateDeviceState) then just set REMOVED & PNP_STOPPED
// flags and clean up the device extension - we don't want to
// delete the pdo at this point.
//
// Otherwise, assume physical device removal occured, in which
// case we need to do our own cleanup & teardown right here
// because the dev stack will start disintegrating.
//
// ISSUE: Per AdriaO, another case where we can get a
// SURPRISE_REMOVAL is if a START fails *after* a STOP
// - at any point in this pdo's stack! Not sure how to
// tell whether or not this is the case if it's not
// SBP2PORT that failed the START, so leaving that case
// as is for now. DanKn, 04-Jun-2001
//
BOOLEAN reportedMissing;
KeAcquireSpinLock (&deviceExtension->ExtensionDataSpinLock, &cIrql);
if (TEST_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_REPORTED_FAILED
)) {
SET_FLAG(
deviceExtension->DeviceFlags,
(DEVICE_FLAG_REMOVED | DEVICE_FLAG_PNP_STOPPED)
);
reportedMissing = FALSE;
} else {
SET_FLAG(
deviceExtension->DeviceFlags,
(DEVICE_FLAG_REMOVED | DEVICE_FLAG_SURPRISE_REMOVED |
DEVICE_FLAG_PNP_STOPPED)
);
reportedMissing = TRUE;
}
CLEAR_FLAG(
deviceExtension->DeviceFlags,
(DEVICE_FLAG_RESET_IN_PROGRESS | DEVICE_FLAG_RECONNECT |
DEVICE_FLAG_LOGIN_IN_PROGRESS | DEVICE_FLAG_REPORTED_FAILED)
);
KeReleaseSpinLock (&deviceExtension->ExtensionDataSpinLock, cIrql);
Sbp2CleanDeviceExtension (DeviceObject, TRUE);
if (reportedMissing) {
Sbp2HandleRemove (DeviceObject);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
}
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
//
// PnP walks up the device tree looking for the FILE_CHAR flags,
// and stops when it finds a node marked Removable. Since our pdo's
// are marked Removable, PnP won't make it to a BUS1394 PDO, so we
// need to propagate the FILE_CHAR flags here.
//
fdoExtension = (PFDO_DEVICE_EXTENSION)
deviceExtension->BusFdo->DeviceExtension;
DeviceObject->Characteristics |=
(FILE_CHARACTERISTICS_REMOVAL_POLICY_MASK &
fdoExtension->Pdo->Characteristics);
status = Irp->IoStatus.Status;
break;
default:
status = Irp->IoStatus.Status;
break;
}
//
// This is the bottom of the stack, complete the request
//
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
Sbp2FDOPnpDeviceControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This routine handles the PNP requests for FDO's
Arguments:
DeviceObject - Supplies a pointer to the device object for this request.
Irp - Supplies the Irp making the request.
Return Value:
NTSTATUS
--*/
{
KEVENT event;
NTSTATUS status;
PDEVICE_RELATIONS deviceRelations;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_CAPABILITIES deviceCapabilities;
PFDO_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
status = IoAcquireRemoveLock(&fdoExtension->RemoveLock, NULL);
if (!NT_SUCCESS(status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
return status;
}
switch (irpStack->MinorFunction) {
case IRP_MN_QUERY_DEVICE_RELATIONS:
DEBUGPRINT3((
"Sbp2Port: Pnp: ... Type = %x\n",
irpStack->Parameters.QueryDeviceRelations.Type
));
if (irpStack->Parameters.QueryDeviceRelations.Type != BusRelations) {
break;
}
deviceRelations = ExAllocatePool(
PagedPool,
sizeof (*deviceRelations) +
(SBP2_MAX_LUNS_PER_NODE * sizeof (PDEVICE_OBJECT))
);
if (!deviceRelations) {
DEBUGPRINT1 (("Sbp2Port: Pnp: devRels alloc failed!!\n"));
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return (STATUS_INSUFFICIENT_RESOURCES);
}
status = Sbp2CreateDeviceRelations (fdoExtension, deviceRelations);
Irp->IoStatus.Status = status;
if (NT_SUCCESS(status)) {
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
} else {
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
break;
case IRP_MN_QUERY_CAPABILITIES:
deviceCapabilities =
irpStack->Parameters.DeviceCapabilities.Capabilities;
deviceCapabilities->SurpriseRemovalOK = TRUE;
break;
case IRP_MN_START_DEVICE:
KeInitializeEvent (&event, SynchronizationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext (Irp);
IoSetCompletionRoutine(
Irp,
Sbp2FdoRequestCompletionRoutine,
(PVOID) &event,
TRUE,
TRUE,
TRUE
);
status = IoCallDriver (fdoExtension->LowerDeviceObject, Irp);
if(!NT_SUCCESS(Irp->IoStatus.Status) && (status != STATUS_PENDING)) {
status = Irp->IoStatus.Status;
} else {
KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
status = Sbp2StartDevice (DeviceObject);
}
IoReleaseRemoveLock(&fdoExtension->RemoveLock, NULL);
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
case IRP_MN_REMOVE_DEVICE:
KeInitializeEvent (&event, SynchronizationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(
Irp,
Sbp2FdoRequestCompletionRoutine,
(PVOID) &event,
TRUE,
TRUE,
TRUE
);
status = IoCallDriver (fdoExtension->LowerDeviceObject, Irp);
if (!NT_SUCCESS (Irp->IoStatus.Status) && status != STATUS_PENDING) {
status = Irp->IoStatus.Status;
} else {
KeWaitForSingleObject (&event, Executive, KernelMode, FALSE, NULL);
//
// do FDO cleanup..
//
IoReleaseRemoveLockAndWait(&fdoExtension->RemoveLock, NULL);
if (Sbp2CleanDeviceExtension (DeviceObject, TRUE)) {
ASSERT(!fdoExtension->ulBusResetMutexCount);
ASSERT(!fdoExtension->ulWorkItemCount);
IoDetachDevice (fdoExtension->LowerDeviceObject);
IoDeleteDevice (DeviceObject);
}
status = STATUS_SUCCESS;
}
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp,IO_NO_INCREMENT);
return status;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
Irp->IoStatus.Information |= PNP_DEVICE_DONT_DISPLAY_IN_UI;
break;
default:
break;
}
IoReleaseRemoveLock(&fdoExtension->RemoveLock, NULL);
//
// Pass the irp down the stack
//
IoCopyCurrentIrpStackLocationToNext (Irp);
status = IoCallDriver (fdoExtension->LowerDeviceObject, Irp);
return status;
}
VOID
Sbp2HandleRemove(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PFDO_DEVICE_EXTENSION fdoExtension;
KIRQL cIrql;
ULONG i,j;
PIRBIRP packet;
fdoExtension = (PFDO_DEVICE_EXTENSION) deviceExtension->BusFdo->DeviceExtension;
if (!TEST_FLAG (deviceExtension->DeviceFlags,DEVICE_FLAG_REMOVED)) {
return;
}
//
// now we need to remove ourselves from the DeviceList, the sbp2 FDO keeps of its
// children...
// then we re-condense the list..
//
KeAcquireSpinLock (&fdoExtension->DeviceListLock,&cIrql);
if (fdoExtension->DeviceListSize > 1) {
DEBUGPRINT1(("\'Sbp2Cleanup, condensing PDO list\n"));
for (i = 0; i < fdoExtension->DeviceListSize; i++) {
if (fdoExtension->DeviceList[i].DeviceObject == DeviceObject) {
//
// free the model descriptor only if its not the same as the FDOs
// this only happens in the multi-lu case
//
if (fdoExtension->DeviceList[i].ModelLeaf) {
ExFreePool(fdoExtension->DeviceList[i].ModelLeaf);
fdoExtension->DeviceList[i].ModelLeaf = NULL;
}
//
// we found our place in the list. Remove us and re-condense the list
//
for (j = i; j < fdoExtension->DeviceListSize; j++) {
if ((j + 1) < fdoExtension->DeviceListSize) {
fdoExtension->DeviceList[j] = fdoExtension->DeviceList[j+1];
//
// Change the (pdo)DevExt->DeviceInfo to point at
// the next postion in the device list
//
deviceExtension = fdoExtension->DeviceList[j].
DeviceObject->DeviceExtension;
deviceExtension->DeviceInfo =
&fdoExtension->DeviceList[j];
}
}
fdoExtension->DeviceListSize--;
}
}
} else {
if (fdoExtension->DeviceList[0].DeviceObject == DeviceObject) {
if (fdoExtension->DeviceList[0].ModelLeaf) {
ExFreePool(fdoExtension->DeviceList[0].ModelLeaf);
fdoExtension->DeviceList[0].ModelLeaf = NULL;
}
}
fdoExtension->DeviceList[0].DeviceObject = NULL;
fdoExtension->DeviceListSize = 0;
CLEAR_FLAG(deviceExtension->DeviceFlags,DEVICE_FLAG_INITIALIZED);
}
if (fdoExtension->DeviceListSize == 0) {
//
// all our children have been deleted, set our FDO to be inactive
// so it can not re create PDOs qhen it receives a QDR.
// The reaosn is that if our PDOS are all removed, we dont support
// dynamic changes ot the crom, which would then warrant us being
// able to eject PDOs again.
//
SET_FLAG(fdoExtension->DeviceFlags, DEVICE_FLAG_STOPPED);
KeReleaseSpinLock (&fdoExtension->DeviceListLock, cIrql);
//
// Disable bus reset notifications
//
AllocateIrpAndIrb ((PDEVICE_EXTENSION) fdoExtension, &packet);
if (packet) {
packet->Irb->FunctionNumber = REQUEST_BUS_RESET_NOTIFICATION;
packet->Irb->Flags = 0;
packet->Irb->u.BusResetNotification.fulFlags = DEREGISTER_NOTIFICATION_ROUTINE;
Sbp2SendRequest(
(PDEVICE_EXTENSION) fdoExtension,
packet,
SYNC_1394_REQUEST
);
DeAllocateIrpAndIrb((PDEVICE_EXTENSION)fdoExtension,packet);
}
fdoExtension->NumPDOsStarted = 0;
} else {
KeReleaseSpinLock (&fdoExtension->DeviceListLock, cIrql);
}
}
NTSTATUS
Sbp2FdoRequestCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT Event
)
{
KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
Sbp2CreateDeviceRelations(
IN PFDO_DEVICE_EXTENSION FdoExtension,
IN PDEVICE_RELATIONS DeviceRelations
)
{
ULONG i;
NTSTATUS status;
ULONG instanceNum;
PAGED_CODE();
//
// LUNS are static in the Config Rom. so if our DeviceListSize >0, that objetc
// has been seen before
//
DeviceRelations->Count = 0;
status = Sbp2Get1394ConfigInfo (FdoExtension, NULL);
if (!NT_SUCCESS(status)) {
ExFreePool (DeviceRelations);
return status;
}
if (TEST_FLAG (FdoExtension->DeviceFlags,DEVICE_FLAG_STOPPED)) {
ExFreePool(DeviceRelations);
return STATUS_UNSUCCESSFUL;
}
for (i = 0; i < FdoExtension->DeviceListSize; i++) {
if (!FdoExtension->DeviceList[i].DeviceObject) {
instanceNum = 0;
do {
status = Sbp2CreatePdo (FdoExtension,&FdoExtension->DeviceList[i],instanceNum++);
} while (status == STATUS_OBJECT_NAME_COLLISION);
if (!NT_SUCCESS(status)) {
DEBUGPRINT1(("\'Sbp2CreateDeviceRelations, Failed to create PDO \n"));
ExFreePool (DeviceRelations);
return status;
}
DeviceRelations->Objects[DeviceRelations->Count] = FdoExtension->DeviceList[i].DeviceObject;
DeviceRelations->Count++;
ObReferenceObject (FdoExtension->DeviceList[i].DeviceObject);
} else {
//
// On NT we always add existing pdo's to the dev relations list.
//
// On 9x, we only add pdo's to the list whose DevFlags field
// is non-zero. If we see a pdo with a zero DevFlags field
// then that means it was never started (likely for lack of
// a driver), and we don't want to re-indicate it to the caller.
// The pdo will eventually get deleted when cleaning up the fdo.
//
if (!SystemIsNT) {
PDEVICE_EXTENSION pdoExtension;
pdoExtension = (PDEVICE_EXTENSION)
FdoExtension->DeviceList[i].DeviceObject->DeviceExtension;
if (pdoExtension->DeviceFlags &
DEVICE_FLAG_UNSTARTED_AND_REMOVED) {
ASSERT(pdoExtension->DeviceFlags == DEVICE_FLAG_UNSTARTED_AND_REMOVED);
DEBUGPRINT2((
"Sbp2Port: CreateDevRelations: excluding ext=x%x\n",
pdoExtension
));
continue;
}
}
DeviceRelations->Objects[DeviceRelations->Count] =
FdoExtension->DeviceList[i].DeviceObject;
DeviceRelations->Count++;
ObReferenceObject (FdoExtension->DeviceList[i].DeviceObject);
}
}
return STATUS_SUCCESS;
}
NTSTATUS
Sbp2QueryDeviceText(
IN PDEVICE_EXTENSION DeviceExtension,
IN DEVICE_TEXT_TYPE TextType,
IN LCID LocaleId,
IN OUT PWSTR *DeviceText
)
{
UCHAR ansiBuffer[256];
ANSI_STRING ansiText;
ULONG byteSwappedData;
UNICODE_STRING unicodeText;
NTSTATUS status;
PAGED_CODE();
RtlInitUnicodeString(&unicodeText, NULL);
if (TextType == DeviceTextDescription) {
RtlZeroMemory(ansiBuffer, sizeof(ansiBuffer));
if (DeviceExtension->DeviceInfo->VendorLeaf && DeviceExtension->DeviceInfo->ModelLeaf) {
byteSwappedData = bswap(*(((PULONG) DeviceExtension->DeviceInfo->VendorLeaf+1)));
if (byteSwappedData & 0x80000000) {
sprintf(ansiBuffer, "%ws %ws IEEE 1394 SBP2 Device",
&DeviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&DeviceExtension->DeviceInfo->ModelLeaf->TL_Data);
} else {
sprintf(ansiBuffer, "%s %s IEEE 1394 SBP2 Device",
&DeviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&DeviceExtension->DeviceInfo->ModelLeaf->TL_Data);
}
} else {
sprintf(ansiBuffer, "UNKNOWN VENDOR AND MODEL IEEE 1394 SBP2 Device");
}
} else if (TextType == DeviceTextLocationInformation) {
sprintf(ansiBuffer, "LUN %d",
DeviceExtension->DeviceInfo->Lun.u.LowPart);
} else {
return STATUS_NOT_SUPPORTED;
}
RtlInitAnsiString(&ansiText, ansiBuffer);
status = RtlAnsiStringToUnicodeString (&unicodeText, &ansiText, TRUE);
*DeviceText = unicodeText.Buffer;
return status;
}
//
// code below ported from scsiport
//
NTSTATUS
Sbp2GetDeviceId(
IN PDEVICE_OBJECT Pdo,
OUT PUNICODE_STRING UnicodeString
)
/*++
Routine Description:
This routine will allocate space for and fill in a device id string for
the specified Pdo. This string is generated from the protocol type (sbp2) and
the type of the device.
Arguments:
Pdo - a pointer to the physical device object being queried
UnicodeString - a pointer to an already allocated unicode string structure.
This routine will allocate and fill in the buffer of this
structure
Returns:
status
--*/
{
PDEVICE_EXTENSION deviceExtension = Pdo->DeviceExtension;
UCHAR buffer[1024];
PUCHAR rawIdString = buffer;
ANSI_STRING ansiIdString;
ULONG byteSwappedData;
PAGED_CODE();
ASSERT(UnicodeString != NULL);
if (deviceExtension->DeviceInfo->VendorLeaf && deviceExtension->DeviceInfo->ModelLeaf) {
byteSwappedData = bswap(*(((PULONG) deviceExtension->DeviceInfo->VendorLeaf+1)));
if (byteSwappedData & 0x80000000) {
RtlZeroMemory(buffer, sizeof(buffer));
sprintf(rawIdString,
"SBP2\\%ws&%ws&LUN%x",
&deviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&deviceExtension->DeviceInfo->ModelLeaf->TL_Data,
(deviceExtension->DeviceInfo->Lun.u.LowPart));
rawIdString += strlen(rawIdString);
ASSERT(*rawIdString == '\0');
RtlInitAnsiString(&ansiIdString, buffer);
DEBUGPRINT2(("Sbp2Port: GetDevId: pdo=x%p, id=%Z\n",
Pdo, &ansiIdString));
return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
} else {
RtlZeroMemory(buffer, sizeof(buffer));
sprintf(rawIdString,
"SBP2\\%s&%s&LUN%x",
&deviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&deviceExtension->DeviceInfo->ModelLeaf->TL_Data,
(deviceExtension->DeviceInfo->Lun.u.LowPart));
rawIdString += strlen(rawIdString);
ASSERT(*rawIdString == '\0');
RtlInitAnsiString(&ansiIdString, buffer);
DEBUGPRINT2(("Sbp2Port: GetDevId: pdo=x%p id=%Z\n",
Pdo, &ansiIdString));
return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
}
} else {
RtlZeroMemory(buffer, sizeof(buffer));
sprintf(rawIdString,
"SBP2\\UNKNOWN VENDOR&UNKNOWN MODEL&LUN%x",
(deviceExtension->DeviceInfo->Lun.u.LowPart));
rawIdString += strlen(rawIdString);
ASSERT(*rawIdString == '\0');
RtlInitAnsiString(&ansiIdString, buffer);
DEBUGPRINT2(("Sbp2Port: GetDevId: pdo=x%p id=%Z\n",
Pdo, &ansiIdString));
return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
}
}
NTSTATUS
Sbp2GetInstanceId(
IN PDEVICE_OBJECT Pdo,
OUT PUNICODE_STRING UnicodeString
)
/*++
Routine Description:
This routine will allocate space for and fill in an instance id string for
the specified Pdo. This string will be generated either from the device
type + serial number of the device (if it has a serial number) or from
the address of the device.
Arguments:
Pdo - a pointer to the physical device object being queried
UnicodeString - a pointer to an already allocated unicode string structure.
This routine will allocate and fill in the buffer of this
structure
Returns:
status
--*/
{
PDEVICE_EXTENSION deviceExtension = Pdo->DeviceExtension;
UCHAR idStringBuffer[64];
ANSI_STRING ansiIdString;
PAGED_CODE();
ASSERT(UnicodeString != NULL);
sprintf(idStringBuffer,
"%08x%08x",
bswap(deviceExtension->DeviceInfo->ConfigRom->CR_Node_UniqueID[0]),
bswap(deviceExtension->DeviceInfo->ConfigRom->CR_Node_UniqueID[1])
);
RtlInitAnsiString(&ansiIdString, idStringBuffer);
DEBUGPRINT2(("Sbp2Port: GetInstId: pdo=x%p id=%Z\n",
Pdo, &ansiIdString));
return RtlAnsiStringToUnicodeString(UnicodeString, &ansiIdString, TRUE);
}
#define MAX_STRING_SIZE 512
NTSTATUS
Sbp2GetMultipleIds(
IN PDEVICE_OBJECT Pdo,
OUT PUNICODE_STRING UnicodeString,
BOOLEAN HwIds
)
/*++
Routine Description:
This routine will allocate space for and fill in a compatible id multi
string for the specified Pdo. This string is generated using the protocol and
device types for the device
Arguments:
Pdo - a pointer to the physical device object being queried
UnicodeString - a pointer to an already allocated unicode string structure.
This routine will allocate and fill in the buffer of this
structure
Returns:
status
--*/
{
PDEVICE_EXTENSION deviceExtension = Pdo->DeviceExtension;
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
ULONG byteSwappedData;
PSTR stringBuffer[6];
PAGED_CODE();
stringBuffer[0] = ExAllocatePoolWithTag (PagedPool,MAX_STRING_SIZE,'2pbs');
if (stringBuffer[0] == NULL) {
return status;
}
if (!HwIds) {
//
// Compat ID's, return the following string :
//
// 1. SBP2\<CmdSetSpecId,base10>&<CmdSetId,base10>&<Lun,base10>
//
sprintf(stringBuffer[0],
"SBP2\\%d&%d&%d",
deviceExtension->DeviceInfo->CmdSetSpecId.QuadPart,
deviceExtension->DeviceInfo->CmdSetId.QuadPart,
(ULONG) (deviceExtension->DeviceInfo->Lun.u.HighPart & 0x001F));
stringBuffer[1] = NULL;
status = Sbp2StringArrayToMultiString (UnicodeString, stringBuffer);
goto FreeString0;
}
stringBuffer[1] = ExAllocatePoolWithTag (PagedPool,MAX_STRING_SIZE,'2pbs');
if (stringBuffer[1] == NULL) {
goto FreeString0;
}
stringBuffer[2] = ExAllocatePoolWithTag (PagedPool,MAX_STRING_SIZE,'2pbs');
if (stringBuffer[2] == NULL) {
goto FreeString1;
}
stringBuffer[3] = ExAllocatePoolWithTag (PagedPool,MAX_STRING_SIZE,'2pbs');
if (stringBuffer[3] == NULL) {
goto FreeString2;
}
stringBuffer[4] = ExAllocatePoolWithTag (PagedPool,MAX_STRING_SIZE,'2pbs');
if (stringBuffer[4] == NULL) {
goto FreeString3;
}
stringBuffer[5] = NULL;
//
// Hardware ID's, return the folowing strings
//
// 1. SBP2\<Vendor>&<Model>&CmdSetId<number,base16>&Gen<dev type, ie. Disk>
// 2. SBP2\<Vendor>&<Model>&CmdSetId<number,base16>
// 3. SBP2\<Vendor>&<Model>&LUN<number,base16>
// 4. SBP2\Gen<dev type, i.e. Disk>
// 5. Gen<dev type, i.e Disk>
//
if (deviceExtension->DeviceInfo->VendorLeaf && deviceExtension->DeviceInfo->ModelLeaf) {
byteSwappedData = bswap(*(((PULONG) deviceExtension->DeviceInfo->VendorLeaf+1)));
if (byteSwappedData & 0x80000000) {
//
// strings are already in unicode..
//
sprintf(stringBuffer[0],
"SBP2\\%ws&%ws&CmdSetId%x&%s",
&deviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&deviceExtension->DeviceInfo->ModelLeaf->TL_Data,
deviceExtension->DeviceInfo->CmdSetId.QuadPart,
deviceExtension->DeviceInfo->GenericName);
sprintf(stringBuffer[1],
"SBP2\\%ws&%ws&CmdSetId%x",
&deviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&deviceExtension->DeviceInfo->ModelLeaf->TL_Data,
deviceExtension->DeviceInfo->CmdSetId.QuadPart);
sprintf(stringBuffer[2],
"SBP2\\%ws&%ws&LUN%x",
&deviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&deviceExtension->DeviceInfo->ModelLeaf->TL_Data,
deviceExtension->DeviceInfo->Lun.u.LowPart);
} else {
sprintf(stringBuffer[0],
"SBP2\\%s&%s&CmdSetId%x&%s",
&deviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&deviceExtension->DeviceInfo->ModelLeaf->TL_Data,
deviceExtension->DeviceInfo->CmdSetId.QuadPart,
deviceExtension->DeviceInfo->GenericName);
sprintf(stringBuffer[1],
"SBP2\\%s&%s&CmdSetId%x",
&deviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&deviceExtension->DeviceInfo->ModelLeaf->TL_Data,
deviceExtension->DeviceInfo->CmdSetId.QuadPart);
sprintf(stringBuffer[2],
"SBP2\\%s&%s&LUN%x",
&deviceExtension->DeviceInfo->VendorLeaf->TL_Data,
&deviceExtension->DeviceInfo->ModelLeaf->TL_Data,
deviceExtension->DeviceInfo->Lun.u.LowPart);
}
} else {
sprintf(stringBuffer[0],
"SBP2\\UNKNOWN VENDOR&UNKNOWN MODEL&CmdSetId%x&%s",
deviceExtension->DeviceInfo->CmdSetId.QuadPart,
deviceExtension->DeviceInfo->GenericName);
sprintf(stringBuffer[1],
"SBP2\\UNKNOWN VENDOR&UNKNOWN MODEL&CmdSetId%x",
deviceExtension->DeviceInfo->CmdSetId.QuadPart);
sprintf(stringBuffer[2],
"SBP2\\UNKNOWN VENDOR&UNKNOWN MODEL&LUN%x",
deviceExtension->DeviceInfo->Lun.u.LowPart);
}
sprintf(stringBuffer[3],
"SBP2\\%s",
deviceExtension->DeviceInfo->GenericName);
sprintf(stringBuffer[4],
"%s",
deviceExtension->DeviceInfo->GenericName);
status = Sbp2StringArrayToMultiString (UnicodeString, stringBuffer);
ExFreePool (stringBuffer[4]);
FreeString3:
ExFreePool (stringBuffer[3]);
FreeString2:
ExFreePool (stringBuffer[2]);
FreeString1:
ExFreePool (stringBuffer[1]);
FreeString0:
ExFreePool (stringBuffer[0]);
return status;
}
NTSTATUS
Sbp2StringArrayToMultiString(
PUNICODE_STRING MultiString,
PCSTR StringArray[]
)
/*++
Routine Description:
This routine will take a null terminated array of ascii strings and merge
them together into a unicode multi-string block.
This routine allocates memory for the string buffer - is the caller's
responsibility to free it.
Arguments:
MultiString - a UNICODE_STRING structure into which the multi string will
be built.
StringArray - a NULL terminated list of narrow strings which will be combined
together. This list may not be empty.
Return Value:
status
--*/
{
ANSI_STRING ansiEntry;
UNICODE_STRING unicodeEntry;
UCHAR i;
NTSTATUS status;
PAGED_CODE();
//
// Make sure we aren't going to leak any memory
//
ASSERT(MultiString->Buffer == NULL);
RtlInitUnicodeString(MultiString, NULL);
for (i = 0; StringArray[i] != NULL; i++) {
RtlInitAnsiString(&ansiEntry, StringArray[i]);
MultiString->Length += (USHORT) RtlAnsiStringToUnicodeSize(&ansiEntry);
}
ASSERT(MultiString->Length != 0);
MultiString->MaximumLength = MultiString->Length + sizeof(UNICODE_NULL);
MultiString->Buffer = ExAllocatePoolWithTag(PagedPool,
MultiString->MaximumLength,
'2pbs');
if(MultiString->Buffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(MultiString->Buffer, MultiString->MaximumLength);
unicodeEntry = *MultiString;
for (i = 0; StringArray[i] != NULL; i++) {
RtlInitAnsiString(&ansiEntry, StringArray[i]);
status = RtlAnsiStringToUnicodeString(
&unicodeEntry,
&ansiEntry,
FALSE);
//
// Push the buffer location up and reduce the maximum count
//
((PSTR) unicodeEntry.Buffer) += unicodeEntry.Length + sizeof(WCHAR);
unicodeEntry.MaximumLength -= unicodeEntry.Length + sizeof(WCHAR);
};
return STATUS_SUCCESS;
}
NTSTATUS
Sbp2SystemControl(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
/*++
Routine Description:
This routine handles only the WMI related requests. It mostly passes everything down
Arguments:
DeviceObject - Supplies a pointer to the device object for this request.
Irp - Supplies the Irp making the request.
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
if (deviceExtension->Type == SBP2_FDO) {
DEBUGPRINT2(("Sbp2Port: WmiCtl: irp=x%p not handled, passing it down\n", Irp));
IoCopyCurrentIrpStackLocationToNext(Irp);
return (IoCallDriver(deviceExtension->LowerDeviceObject, Irp));
} else {
status = Irp->IoStatus.Status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
}
/* ******************************* POWER MANAGEMENT ********************************/
NTSTATUS
Sbp2PowerControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine receives the various Power messages
Arguments:
DeviceObject - Pointer to class device object.
Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PFDO_DEVICE_EXTENSION fdoExtension;
PIO_STACK_LOCATION irpStack;
PIO_COMPLETION_ROUTINE complRoutine;
KIRQL cIrql;
NTSTATUS status;
POWER_STATE State;
UCHAR minorFunction;
irpStack = IoGetCurrentIrpStackLocation(Irp);
ASSERT(irpStack->MajorFunction == IRP_MJ_POWER);
DEBUGPRINT2((
"Sbp2Port: Power: %sExt=x%p, irp=x%p, minor=x%x\n",
(deviceExtension->Type == SBP2_FDO ? "fdo" : "pdo"),
deviceExtension,
Irp,
irpStack->MinorFunction
));
switch (deviceExtension->Type) {
case SBP2_PDO:
status = IoAcquireRemoveLock (&deviceExtension->RemoveLock, NULL);
if (!NT_SUCCESS (status)) {
DEBUGPRINT2((
"Sbp2Port: Power: pdoExt=x%p REMOVED!\n",
deviceExtension
));
Irp->IoStatus.Status = status;
PoStartNextPowerIrp (Irp);
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
switch ((minorFunction = irpStack->MinorFunction)) {
case IRP_MN_SET_POWER:
DEBUGPRINT2(("Sbp2Port: Power: Type = %d, State = %d\n",
irpStack->Parameters.Power.Type,irpStack->Parameters.Power.State.DeviceState));
State = irpStack->Parameters.Power.State;
if (irpStack->Parameters.Power.Type == SystemPowerState) {
BOOLEAN sendDIrp = FALSE;
//
// make up a device state to correspond to a system state
//
DEBUGPRINT2(("Sbp2Port: Power: sys power chg from %x to %x\n",deviceExtension->SystemPowerState,State));
status = STATUS_SUCCESS;
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
if (State.SystemState >= PowerSystemShutdown) {
//
// dont do anything for shutdown
//
DEBUGPRINT2(("Sbp2Port: Power: sys shutdown, ignoring\n"));
deviceExtension->SystemPowerState = State.SystemState;
} else if ((deviceExtension->SystemPowerState == PowerSystemWorking) &&
(State.SystemState != PowerSystemWorking)){
deviceExtension->SystemPowerState = State.SystemState;
if (deviceExtension->DevicePowerState != PowerDeviceD3) {
//
// Powering down
//
State.DeviceState = PowerDeviceD3;
sendDIrp = TRUE;
}
} else if (State.SystemState == PowerSystemWorking) {
deviceExtension->SystemPowerState = State.SystemState;
if (deviceExtension->DevicePowerState != PowerDeviceD0) {
//
// Powering up - check for an absent fdo
//
fdoExtension =
deviceExtension->BusFdo->DeviceExtension;
if (TEST_FLAG(
fdoExtension->DeviceFlags,
DEVICE_FLAG_ABSENT_ON_POWER_UP
)) {
SET_FLAG(
deviceExtension->DeviceFlags,
DEVICE_FLAG_ABSENT_ON_POWER_UP
);
DEBUGPRINT1((
"Sbp2Port: Power: dev absent, failing\n"
));
status = STATUS_NO_SUCH_DEVICE;
} else {
State.DeviceState = PowerDeviceD0;
sendDIrp = TRUE;
}
}
}
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
if (sendDIrp) {
DEBUGPRINT2((
"Sbp2Port: Power: ext=x%p send D irp for state %d\n",
deviceExtension,
State
));
IoMarkIrpPending (Irp);
status = PoRequestPowerIrp(
DeviceObject,
IRP_MN_SET_POWER,
State,
Sbp2PdoDIrpCompletion,
Irp,
NULL);
if (NT_SUCCESS (status)) {
return STATUS_PENDING;
}
irpStack->Control &= ~SL_PENDING_RETURNED;
DEBUGPRINT1((
"Sbp2Port: Power: ext=x%p PoReqPowerIrp err=x%x\n",
deviceExtension,
status
));
}
Irp->IoStatus.Status = status;
PoStartNextPowerIrp (Irp);
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
IoCompleteRequest(Irp,IO_NO_INCREMENT);
return status;
} else {
DEBUGPRINT2(("Sbp2Port: Power: dev power chg from %x to %x\n",deviceExtension->DevicePowerState,State));
KeAcquireSpinLock(&deviceExtension->ExtensionDataSpinLock,&cIrql);
deviceExtension->DevicePowerState = State.DeviceState;
KeReleaseSpinLock(&deviceExtension->ExtensionDataSpinLock,cIrql);
}
status = STATUS_SUCCESS;
break;
case IRP_MN_WAIT_WAKE:
case IRP_MN_POWER_SEQUENCE:
case IRP_MN_QUERY_POWER:
status = STATUS_SUCCESS;
break;
default:
status = Irp->IoStatus.Status;
break;
}
Irp->IoStatus.Status = status;
PoStartNextPowerIrp (Irp);
IoCompleteRequest (Irp, IO_NO_INCREMENT);
if ((minorFunction == IRP_MN_SET_POWER) &&
(State.DeviceState == PowerDeviceD0)) {
//
// restart our queue if we had to queue something while powering up
//
// ISSUE: This may be bad - there is already some logic in
// SBP2SCSI.C to restart the queue on power up, i.e.
// the UNLOCK_QUEUE handler. For now i am at least
// limiting this to SET_POWER irps when state is D0
// DanKn 02-Jun-2001
//
KeRaiseIrql (DISPATCH_LEVEL, &cIrql);
Sbp2StartNextPacketByKey(
DeviceObject,
deviceExtension->CurrentKey
);
KeLowerIrql (cIrql);
}
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
return (status);
case SBP2_FDO:
fdoExtension = (PFDO_DEVICE_EXTENSION) deviceExtension;
complRoutine = NULL;
if (irpStack->MinorFunction == IRP_MN_SET_POWER) {
DEBUGPRINT2((
"Sbp2Port: Power: Type = %d, State = %d\n",
irpStack->Parameters.Power.Type,
irpStack->Parameters.Power.State.DeviceState
));
if (irpStack->Parameters.Power.Type == SystemPowerState) {
State = irpStack->Parameters.Power.State;
DEBUGPRINT2((
"Sbp2Port: Power: sys power chg from %x to %x\n",
fdoExtension->SystemPowerState,
State
));
if (State.SystemState >= PowerSystemShutdown) {
//
// Shutdown (setting state here, the assumption being
// that we're shutting down regardless of the
// completion status of this request)
//
fdoExtension->SystemPowerState = State.SystemState;
} else if ((fdoExtension->SystemPowerState ==
PowerSystemWorking) &&
(State.SystemState != PowerSystemWorking)) {
//
// Power down. If DevPowerState != D3 then send
// a D irp first (when that completes successfully
// we'll continue with the S irp), else just
// set the completion routine so we can update
// the system state field in our extension on
// successful completion of this S irp.
//
if (fdoExtension->DevicePowerState != PowerDeviceD3) {
//
// Power down, send a D irp first
//
IoMarkIrpPending (Irp);
fdoExtension->SystemPowerIrp = Irp;
State.DeviceState = PowerDeviceD3;
DEBUGPRINT2((
"Sbp2Port: Power: ext=x%p sending D irp for state %x\n",
deviceExtension,
State
));
status = PoRequestPowerIrp(
fdoExtension->Pdo,
IRP_MN_SET_POWER,
State,
Sbp2FdoDIrpCompletion,
fdoExtension,
NULL
);
if (!NT_SUCCESS (status)) {
DEBUGPRINT1((
"Sbp2Port: Power: ext=x%p PoReqPowerIrp err=x%x\n",
fdoExtension,
status
));
irpStack->Control &= ~SL_PENDING_RETURNED;
Irp->IoStatus.Status = status;
PoStartNextPowerIrp (Irp);
IoCompleteRequest (Irp,IO_NO_INCREMENT);
}
return status;
} else {
complRoutine = Sbp2FdoSIrpCompletion;
}
} else if (State.SystemState == PowerSystemWorking) {
//
// Power up. Set the completion routine so we
// follow up with a D irp or update the system
// state field in our extension on successful
// completion of this S irp.
//
complRoutine = Sbp2FdoSIrpCompletion;
}
}
}
PoStartNextPowerIrp (Irp);
IoCopyCurrentIrpStackLocationToNext (Irp);
if (complRoutine) {
IoSetCompletionRoutine(
Irp,
Sbp2FdoSIrpCompletion,
NULL,
TRUE,
TRUE,
TRUE
);
}
return (PoCallDriver (deviceExtension->LowerDeviceObject, Irp));
default:
break;
}
Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
PoStartNextPowerIrp (Irp);
IoCompleteRequest (Irp,IO_NO_INCREMENT);
return STATUS_NO_SUCH_DEVICE;
}
VOID
Sbp2PdoDIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PIRP SIrp,
IN PIO_STATUS_BLOCK IoStatus
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
ASSERT(deviceExtension->Type == SBP2_PDO);
if (SIrp) {
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (SIrp);
SYSTEM_POWER_STATE state = irpStack->Parameters.Power.State.SystemState;
DEBUGPRINT1((
"Sbp2Port: PdoDIrpCompl: ext=x%p, sIrp=x%p, state=%d, status=x%x\n",
deviceExtension,
SIrp,
PowerState.DeviceState,
IoStatus->Status
));
SIrp->IoStatus.Status = STATUS_SUCCESS;
PoStartNextPowerIrp (SIrp);
IoReleaseRemoveLock (&deviceExtension->RemoveLock, NULL);
IoCompleteRequest (SIrp, IO_NO_INCREMENT);
}
}
NTSTATUS
Sbp2FdoSIrpCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Unused
)
{
KIRQL cIrql;
NTSTATUS status = Irp->IoStatus.Status;
POWER_STATE state;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation (Irp);
PFDO_DEVICE_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
state = irpStack->Parameters.Power.State;
DEBUGPRINT1((
"Sbp2Port: FdoSIrpCompl: fdoExt=x%p, status=x%x, state=%d\n",
fdoExtension,
status,
state
));
if (!NT_SUCCESS (status)) {
if ((status == STATUS_NO_SUCH_DEVICE) &&
(state.SystemState == PowerSystemWorking)) {
//
// Controller (i.e. pc card) was ejected while powered down
//
SET_FLAG(
fdoExtension->DeviceFlags,
DEVICE_FLAG_ABSENT_ON_POWER_UP
);
}
PoStartNextPowerIrp (Irp);
return STATUS_SUCCESS;
}
//
// If we're completing a power up S irp then see if we have
// to follow up with a power up D irp
//
if ((state.SystemState == PowerSystemWorking) &&
(fdoExtension->DevicePowerState != PowerDeviceD0)) {
fdoExtension->SystemPowerIrp = Irp;
state.DeviceState = PowerDeviceD0;
DEBUGPRINT1(("Sbp2Port: FdoSIrpCompl: sending D irp...\n"));
status = PoRequestPowerIrp(
fdoExtension->Pdo,
IRP_MN_SET_POWER,
state,
Sbp2FdoDIrpCompletion,
fdoExtension,
NULL
);
if (!NT_SUCCESS (status)) {
DEBUGPRINT1((
"Sbp2Port: FdoSIrpCompl: ERROR! fdoExt=x%p, D irp sts=x%x\n",
fdoExtension,
status
));
Irp->IoStatus.Status = status;
PoStartNextPowerIrp (Irp);
return status;
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
//
// Update appropriate XxxPowerState extension fields
//
if ((fdoExtension->SystemPowerState == PowerSystemWorking) &&
(state.SystemState != PowerSystemWorking)) {
//
// Power down (might not have sent a D irp but it doesn't
// hurt to overwrite the DevicePowerState field anyway)
//
fdoExtension->SystemPowerState = state.SystemState;
fdoExtension->DevicePowerState = PowerDeviceD3;
} else if (state.SystemState == PowerSystemWorking) {
//
// Power up
//
fdoExtension->SystemPowerState = PowerSystemWorking;
}
PoStartNextPowerIrp (Irp);
return STATUS_SUCCESS;
}
VOID
Sbp2FdoDIrpCompletion(
IN PDEVICE_OBJECT TargetDeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PFDO_DEVICE_EXTENSION FdoExtension,
IN PIO_STATUS_BLOCK IoStatus
)
{
PIRP sIrp = FdoExtension->SystemPowerIrp;
DEBUGPRINT1((
"Sbp2Port: FdoDIrpCompl: ext=x%p, status=x%x\n",
FdoExtension,
IoStatus->Status
));
FdoExtension->SystemPowerIrp = NULL;
if (NT_SUCCESS (IoStatus->Status)) {
if (PowerState.DeviceState == PowerDeviceD0) {
//
// Power up, update the XxxPowerState extension fields &
// complete the s irp
//
FdoExtension->SystemPowerState = PowerSystemWorking;
FdoExtension->DevicePowerState = PowerDeviceD0;
} else {
//
// Power down, forward the s irp
//
PoStartNextPowerIrp (sIrp);
IoCopyCurrentIrpStackLocationToNext (sIrp);
PoCallDriver (FdoExtension->LowerDeviceObject, sIrp);
return;
}
} else {
//
// Propagate the error to the S irp & complete it
//
DEBUGPRINT1((
"Sbp2Port: FdoDIrpCompl: ERROR! fdoExt=x%p, D irp status=x%x\n",
FdoExtension,
IoStatus->Status
));
sIrp->IoStatus.Status = IoStatus->Status;
}
PoStartNextPowerIrp (sIrp);
IoCompleteRequest (sIrp, IO_NO_INCREMENT);
}
BOOLEAN
Sbp2EnableBusResetNotification(
PDEVICE_EXTENSION DeviceExtension,
BOOLEAN Enable
)
/*++
Routine Description:
This routine serializes the enabling/disabling of the bus reset
notification routine for a set of related PDOs (1 or more).
Enables bus reset notifications for the first device to start, and
disables bus reset notifications when the last started device stops.
Arguments:
DeviceObject - Supplies a pointer to the device extension for this request.
StartDevice - Whether we are processing a START_DEVICE or (implicitly)
a STOP_DEVICE request.
Return Value:
BOOLEAN - yay or nay
--*/
{
BOOLEAN result = TRUE;
PIRBIRP packet;
LARGE_INTEGER waitValue;
PFDO_DEVICE_EXTENSION fdoExtension;
fdoExtension = DeviceExtension->BusFdo->DeviceExtension;
ASSERT(InterlockedIncrement(&fdoExtension->ulBusResetMutexCount) == 1);
waitValue.QuadPart = -3 * 1000 * 1000 * 10; // 3 seconds
KeWaitForSingleObject(
&fdoExtension->EnableBusResetNotificationMutex,
Executive,
KernelMode,
FALSE,
&waitValue
);
ASSERT(InterlockedDecrement(&fdoExtension->ulBusResetMutexCount) == 0);
if (Enable) {
fdoExtension->NumPDOsStarted++;
if (fdoExtension->NumPDOsStarted > 1) {
goto releaseMutex;
}
} else {
fdoExtension->NumPDOsStarted--;
if (fdoExtension->NumPDOsStarted > 0) {
goto releaseMutex;
}
}
AllocateIrpAndIrb (DeviceExtension, &packet);
if (packet) {
packet->Irb->FunctionNumber = REQUEST_BUS_RESET_NOTIFICATION;
packet->Irb->Flags = 0;
if (Enable) {
packet->Irb->u.BusResetNotification.fulFlags =
REGISTER_NOTIFICATION_ROUTINE;
packet->Irb->u.BusResetNotification.ResetRoutine =
(PBUS_BUS_RESET_NOTIFICATION) Sbp2BusResetNotification;
packet->Irb->u.BusResetNotification.ResetContext =
fdoExtension;
} else {
packet->Irb->u.BusResetNotification.fulFlags =
DEREGISTER_NOTIFICATION_ROUTINE;
}
Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
DeAllocateIrpAndIrb (DeviceExtension,packet);
} else {
if (Enable) {
fdoExtension->NumPDOsStarted--;
}
result = FALSE;
}
releaseMutex:
KeReleaseMutex (&fdoExtension->EnableBusResetNotificationMutex, FALSE);
return result;
}