mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2137 lines
51 KiB
2137 lines
51 KiB
/*++
|
|
|
|
|
|
Copyright (C) Microsoft Corporation, 1997 - 2001
|
|
|
|
Module Name:
|
|
|
|
util.c
|
|
|
|
Abstract:
|
|
|
|
Utility functions for the SBP-2 port driver
|
|
|
|
Author:
|
|
|
|
George Chrysanthakopoulos January-1997
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History :
|
|
|
|
--*/
|
|
|
|
|
|
#include "sbp2port.h"
|
|
|
|
|
|
VOID
|
|
AllocateIrpAndIrb(
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PIRBIRP *Packet
|
|
)
|
|
{
|
|
PIRBIRP pkt;
|
|
|
|
|
|
if (DeviceExtension->Type == SBP2_PDO) {
|
|
|
|
*Packet = (PIRBIRP) ExInterlockedPopEntrySList (&DeviceExtension->BusRequestIrpIrbListHead,
|
|
&DeviceExtension->BusRequestLock);
|
|
|
|
} else {
|
|
|
|
*Packet = NULL;
|
|
}
|
|
|
|
if (*Packet == NULL) {
|
|
|
|
//
|
|
// run out , allocate a new one
|
|
//
|
|
|
|
pkt = ExAllocatePoolWithTag(NonPagedPool,sizeof(IRBIRP),'2pbs');
|
|
|
|
if (pkt) {
|
|
|
|
pkt->Irb = NULL;
|
|
pkt->Irb = ExAllocatePoolWithTag(NonPagedPool,sizeof(IRB),'2pbs');
|
|
|
|
if (!pkt->Irb) {
|
|
|
|
ExFreePool(pkt);
|
|
return;
|
|
}
|
|
|
|
pkt->Irp = NULL;
|
|
pkt->Irp = IoAllocateIrp(DeviceExtension->LowerDeviceObject->StackSize,FALSE);
|
|
|
|
if (!pkt->Irp) {
|
|
|
|
ExFreePool(pkt->Irb);
|
|
ExFreePool(pkt);
|
|
return;
|
|
}
|
|
|
|
DEBUGPRINT3((
|
|
"Sbp2Port: AllocPkt: %sdo, new irp=x%p, irb=x%p\n",
|
|
(DeviceExtension->Type == SBP2_PDO ? "p" : "f"),
|
|
pkt->Irp,
|
|
pkt->Irb
|
|
));
|
|
|
|
} else {
|
|
|
|
return;
|
|
}
|
|
|
|
*Packet = pkt;
|
|
}
|
|
|
|
pkt = *Packet;
|
|
}
|
|
|
|
|
|
VOID
|
|
DeAllocateIrpAndIrb(
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PIRBIRP Packet
|
|
)
|
|
{
|
|
if (DeviceExtension->Type == SBP2_PDO) {
|
|
|
|
ExInterlockedPushEntrySList (&DeviceExtension->BusRequestIrpIrbListHead,
|
|
&Packet->ListPointer,
|
|
&DeviceExtension->BusRequestLock);
|
|
|
|
} else {
|
|
|
|
IoFreeIrp(Packet->Irp);
|
|
ExFreePool(Packet->Irb);
|
|
ExFreePool(Packet);
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AllocateSingle1394Address(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Buffer,
|
|
IN ULONG Length,
|
|
IN ULONG AccessType,
|
|
IN OUT PADDRESS_CONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A wrapper to the bus driver AllocateAddressRange call, for Async Requests
|
|
or ORB's that dont use callbacks.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Sbp2 device object
|
|
Buffer - Data buffer to mapped to 1394 address space
|
|
Length - Size of buffer in bytes
|
|
AccessType - 1394 bus access to allocated range
|
|
Address - Returned Address, from 1394 address space
|
|
AddressHanle - Handle associated with the 1394 address
|
|
RequestMedl - Mdl associated with this range
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG finalTransferMode;
|
|
PIRBIRP packet;
|
|
NTSTATUS status;
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
|
|
|
|
AllocateIrpAndIrb (deviceExtension, &packet);
|
|
|
|
if (!packet) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
packet->Irb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
|
|
packet->Irb->Flags = 0;
|
|
|
|
packet->Irb->u.AllocateAddressRange.MaxSegmentSize = 0;
|
|
packet->Irb->u.AllocateAddressRange.nLength = Length;
|
|
packet->Irb->u.AllocateAddressRange.fulAccessType = AccessType;
|
|
packet->Irb->u.AllocateAddressRange.fulNotificationOptions = NOTIFY_FLAGS_NEVER;
|
|
|
|
packet->Irb->u.AllocateAddressRange.Callback = NULL;
|
|
packet->Irb->u.AllocateAddressRange.Context = NULL;
|
|
|
|
packet->Irb->u.AllocateAddressRange.FifoSListHead = NULL;
|
|
packet->Irb->u.AllocateAddressRange.FifoSpinLock = NULL;
|
|
|
|
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_High = 0;
|
|
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_Low = 0;
|
|
|
|
packet->Irb->u.AllocateAddressRange.AddressesReturned = 0;
|
|
packet->Irb->u.AllocateAddressRange.DeviceExtension = deviceExtension;
|
|
packet->Irb->u.AllocateAddressRange.p1394AddressRange = (PADDRESS_RANGE) &Context->Address;
|
|
|
|
if (Buffer) {
|
|
|
|
packet->Irb->u.AllocateAddressRange.fulFlags = 0;
|
|
|
|
Context->RequestMdl = IoAllocateMdl (Buffer, Length, FALSE, FALSE, NULL);
|
|
|
|
if (!Context->RequestMdl) {
|
|
|
|
DeAllocateIrpAndIrb (deviceExtension,packet);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
MmBuildMdlForNonPagedPool (Context->RequestMdl);
|
|
|
|
packet->Irb->u.AllocateAddressRange.Mdl = Context->RequestMdl;
|
|
|
|
} else {
|
|
|
|
packet->Irb->u.AllocateAddressRange.fulFlags =
|
|
ALLOCATE_ADDRESS_FLAGS_USE_COMMON_BUFFER;
|
|
|
|
packet->Irb->u.AllocateAddressRange.Mdl = NULL;
|
|
}
|
|
|
|
status = Sbp2SendRequest (deviceExtension, packet, SYNC_1394_REQUEST);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
Context->AddressHandle =
|
|
packet->Irb->u.AllocateAddressRange.hAddressRange;
|
|
Context->Address.BusAddress.NodeId =
|
|
deviceExtension->InitiatorAddressId;
|
|
|
|
if (!Buffer) {
|
|
|
|
//
|
|
// For common buffers we get an mdl *back* from the
|
|
// bus/port driver, & need to retrieve a corresponding VA
|
|
//
|
|
|
|
Context->RequestMdl = packet->Irb->u.AllocateAddressRange.Mdl;
|
|
|
|
Context->Reserved = MmGetMdlVirtualAddress (Context->RequestMdl);
|
|
}
|
|
}
|
|
|
|
DeAllocateIrpAndIrb (deviceExtension, packet);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
AllocateAddressForStatus(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PADDRESS_CONTEXT Context,
|
|
IN UCHAR StatusType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A wrapper to 1394 bus IOCTL AllocateAddressRange for status blocks that
|
|
need a Callback notification when the device access the 1394 range...
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Device Object for the sbp2 driver
|
|
ADDRESS_CONTEXT - Mini Context for an individual 1394 request
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
|
|
OCTLET address[2];
|
|
PIRBIRP packet = NULL;
|
|
|
|
|
|
AllocateIrpAndIrb (deviceExtension,&packet);
|
|
|
|
if (!packet) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
packet->Irb->FunctionNumber = REQUEST_ALLOCATE_ADDRESS_RANGE;
|
|
packet->Irb->Flags = 0;
|
|
packet->Irb->u.AllocateAddressRange.nLength = sizeof(STATUS_FIFO_BLOCK);
|
|
packet->Irb->u.AllocateAddressRange.fulAccessType = ACCESS_FLAGS_TYPE_WRITE;
|
|
packet->Irb->u.AllocateAddressRange.fulNotificationOptions = NOTIFY_FLAGS_AFTER_WRITE;
|
|
|
|
packet->Irb->u.AllocateAddressRange.FifoSListHead = NULL;
|
|
packet->Irb->u.AllocateAddressRange.FifoSpinLock = NULL;
|
|
packet->Irb->u.AllocateAddressRange.fulFlags = 0;
|
|
|
|
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_High = 0;
|
|
packet->Irb->u.AllocateAddressRange.Required1394Offset.Off_Low = 0;
|
|
|
|
packet->Irb->u.AllocateAddressRange.AddressesReturned = 0;
|
|
packet->Irb->u.AllocateAddressRange.MaxSegmentSize = 0;
|
|
packet->Irb->u.AllocateAddressRange.DeviceExtension = deviceExtension;
|
|
|
|
switch (StatusType) {
|
|
|
|
case TASK_STATUS_BLOCK:
|
|
|
|
packet->Irb->u.AllocateAddressRange.Callback = Sbp2TaskOrbStatusCallback;
|
|
|
|
Context->RequestMdl = IoAllocateMdl(&deviceExtension->TaskOrbStatusBlock, sizeof (STATUS_FIFO_BLOCK),FALSE,FALSE,NULL);
|
|
|
|
if (!Context->RequestMdl) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exitAllocateAddress;
|
|
}
|
|
|
|
break;
|
|
|
|
case MANAGEMENT_STATUS_BLOCK:
|
|
|
|
packet->Irb->u.AllocateAddressRange.Callback = Sbp2ManagementOrbStatusCallback;
|
|
|
|
Context->RequestMdl = IoAllocateMdl(&deviceExtension->ManagementOrbStatusBlock, sizeof (STATUS_FIFO_BLOCK),FALSE,FALSE,NULL);
|
|
|
|
if (!Context->RequestMdl) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exitAllocateAddress;
|
|
}
|
|
|
|
break;
|
|
|
|
case CMD_ORB_STATUS_BLOCK:
|
|
|
|
//
|
|
// setup the FIFO list that will receive the status blocks
|
|
//
|
|
|
|
packet->Irb->u.AllocateAddressRange.Callback = Sbp2GlobalStatusCallback;
|
|
|
|
Context->RequestMdl = packet->Irb->u.AllocateAddressRange.Mdl = NULL;
|
|
|
|
packet->Irb->u.AllocateAddressRange.FifoSListHead = &deviceExtension->StatusFifoListHead;
|
|
packet->Irb->u.AllocateAddressRange.FifoSpinLock = &deviceExtension->StatusFifoLock;
|
|
|
|
break;
|
|
|
|
#if PASSWORD_SUPPORT
|
|
|
|
case PASSWORD_STATUS_BLOCK:
|
|
|
|
packet->Irb->u.AllocateAddressRange.Callback =
|
|
Sbp2SetPasswordOrbStatusCallback;
|
|
|
|
Context->RequestMdl = IoAllocateMdl(
|
|
&deviceExtension->PasswordOrbStatusBlock,
|
|
sizeof(STATUS_FIFO_BLOCK),
|
|
FALSE,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
|
|
if (!Context->RequestMdl) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto exitAllocateAddress;
|
|
}
|
|
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
if (Context->RequestMdl) {
|
|
|
|
MmBuildMdlForNonPagedPool(Context->RequestMdl);
|
|
}
|
|
|
|
packet->Irb->u.AllocateAddressRange.Mdl = Context->RequestMdl;
|
|
packet->Irb->u.AllocateAddressRange.Context = Context;
|
|
|
|
packet->Irb->u.AllocateAddressRange.p1394AddressRange = (PADDRESS_RANGE) &address;
|
|
|
|
status = Sbp2SendRequest (deviceExtension, packet, SYNC_1394_REQUEST);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
//
|
|
// Setup the address context for the status block
|
|
//
|
|
|
|
Context->Address = address[0];
|
|
Context->AddressHandle = packet->Irb->u.AllocateAddressRange.hAddressRange;
|
|
Context->DeviceObject = DeviceObject;
|
|
|
|
Context->Address.BusAddress.NodeId = deviceExtension->InitiatorAddressId;
|
|
}
|
|
|
|
exitAllocateAddress:
|
|
|
|
DeAllocateIrpAndIrb (deviceExtension, packet);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
VOID
|
|
CleanupOrbList(
|
|
PDEVICE_EXTENSION DeviceExtension,
|
|
NTSTATUS CompletionStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will free a linked list of RequestContexts
|
|
and will also free the 1394 addresses associated with the
|
|
buffers in the context. If the DEVICE_FLAG_RECONNECT i set
|
|
instead of completing pending irps, it will requeue them...
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Device Extension of the sbp2 device
|
|
CompletionSTATUS - If one of the linked requests is not completed,
|
|
complete it with this status
|
|
Return Value:
|
|
None
|
|
--*/
|
|
|
|
{
|
|
PIRP requestIrp;
|
|
PASYNC_REQUEST_CONTEXT currentListItem;
|
|
PASYNC_REQUEST_CONTEXT lastItem,nextItem;
|
|
|
|
KIRQL oldIrql;
|
|
|
|
//
|
|
// Go through the linked list, complete its original Irp and
|
|
// free all the associated memory and 1394 resources...
|
|
// Since this function is called when we get a REMOVE irp,
|
|
// all irps will be terminated with error status
|
|
//
|
|
|
|
KeAcquireSpinLock(&DeviceExtension->OrbListSpinLock,&oldIrql);
|
|
|
|
if (DeviceExtension->NextContextToFree) {
|
|
|
|
FreeAsyncRequestContext(DeviceExtension,DeviceExtension->NextContextToFree);
|
|
|
|
DeviceExtension->NextContextToFree = NULL;
|
|
}
|
|
|
|
if (IsListEmpty (&DeviceExtension->PendingOrbList)) {
|
|
|
|
//
|
|
// nothing to do
|
|
//
|
|
|
|
KeReleaseSpinLock (&DeviceExtension->OrbListSpinLock,oldIrql);
|
|
return;
|
|
|
|
} else {
|
|
|
|
nextItem = RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Flink,OrbList);
|
|
|
|
lastItem = RETRIEVE_CONTEXT(DeviceExtension->PendingOrbList.Blink,OrbList);
|
|
|
|
InitializeListHead(&DeviceExtension->PendingOrbList);
|
|
|
|
KeReleaseSpinLock(&DeviceExtension->OrbListSpinLock,oldIrql);
|
|
}
|
|
|
|
|
|
//
|
|
// Qe have essentially detached this pending context list from
|
|
// the main list so we can now free it without holding the lock
|
|
// and allowing other requests to be processed.
|
|
//
|
|
|
|
do {
|
|
|
|
currentListItem = nextItem;
|
|
nextItem = (PASYNC_REQUEST_CONTEXT) currentListItem->OrbList.Flink;
|
|
if (!TEST_FLAG(currentListItem->Flags,ASYNC_CONTEXT_FLAG_COMPLETED)) {
|
|
|
|
SET_FLAG(currentListItem->Flags,ASYNC_CONTEXT_FLAG_COMPLETED);
|
|
|
|
CLEAR_FLAG(currentListItem->Flags, ASYNC_CONTEXT_FLAG_TIMER_STARTED);
|
|
|
|
Sbp2_SCSI_RBC_Conversion (currentListItem); // unwind MODE_SENSE hacks
|
|
|
|
KeCancelTimer(¤tListItem->Timer);
|
|
|
|
requestIrp =(PIRP)currentListItem->Srb->OriginalRequest;
|
|
requestIrp->IoStatus.Status = CompletionStatus;
|
|
|
|
switch (CompletionStatus) {
|
|
|
|
case STATUS_DEVICE_DOES_NOT_EXIST:
|
|
|
|
currentListItem->Srb->SrbStatus = SRB_STATUS_NO_DEVICE;
|
|
break;
|
|
|
|
case STATUS_REQUEST_ABORTED:
|
|
|
|
currentListItem->Srb->SrbStatus = SRB_STATUS_REQUEST_FLUSHED;
|
|
break;
|
|
|
|
case STATUS_IO_TIMEOUT:
|
|
|
|
currentListItem->Srb->SrbStatus = SRB_STATUS_TIMEOUT;
|
|
break;
|
|
|
|
default:
|
|
|
|
currentListItem->Srb->SrbStatus = SRB_STATUS_ERROR;
|
|
break;
|
|
}
|
|
|
|
if (requestIrp->Type == IO_TYPE_IRP) {
|
|
|
|
if (TEST_FLAG(DeviceExtension->DeviceFlags, DEVICE_FLAG_RECONNECT)) {
|
|
|
|
Sbp2StartPacket(
|
|
DeviceExtension->DeviceObject,
|
|
requestIrp,
|
|
¤tListItem->Srb->QueueSortKey
|
|
);
|
|
|
|
//
|
|
// free everything related to this request
|
|
//
|
|
|
|
currentListItem->Srb = NULL;
|
|
|
|
FreeAsyncRequestContext (DeviceExtension, currentListItem);
|
|
|
|
} else {
|
|
|
|
//
|
|
// free everything related to this request
|
|
//
|
|
|
|
currentListItem->Srb = NULL;
|
|
|
|
FreeAsyncRequestContext (DeviceExtension, currentListItem);
|
|
|
|
DEBUGPRINT2(("Sbp2Port: CleanupOrbList: aborted irp x%p compl\n", requestIrp));
|
|
|
|
IoReleaseRemoveLock (&DeviceExtension->RemoveLock, NULL);
|
|
|
|
IoCompleteRequest (requestIrp, IO_NO_INCREMENT);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// free everything related to this request
|
|
//
|
|
|
|
FreeAsyncRequestContext (DeviceExtension, currentListItem);
|
|
}
|
|
|
|
} while (lastItem != currentListItem); // while loop
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
FreeAddressRange(
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
IN PADDRESS_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
1394 BUS IOCTL call for freeing an address range.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Pointer to sbp2 deviceExtension.
|
|
|
|
context - address context
|
|
|
|
Return Value:
|
|
NTSTATUS
|
|
--*/
|
|
|
|
{
|
|
PIRBIRP packet ;
|
|
|
|
|
|
if (Context->AddressHandle == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
AllocateIrpAndIrb (DeviceExtension, &packet);
|
|
|
|
if (!packet) {
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// FreeAddressRange is synchronous call
|
|
//
|
|
|
|
packet->Irb->FunctionNumber = REQUEST_FREE_ADDRESS_RANGE;
|
|
packet->Irb->Flags = 0;
|
|
|
|
//
|
|
// We always free one address handle even it refers to multiple
|
|
// 1394 addresses. The mdl associated with the original Allocate
|
|
// is freed by the port driver.
|
|
//
|
|
|
|
packet->Irb->u.FreeAddressRange.nAddressesToFree = 1;
|
|
packet->Irb->u.FreeAddressRange.p1394AddressRange = (PADDRESS_RANGE) &Context->Address;
|
|
packet->Irb->u.FreeAddressRange.pAddressRange = &Context->AddressHandle;
|
|
|
|
if (Context->RequestMdl) {
|
|
|
|
if (Context == &DeviceExtension->CommonBufferContext) {
|
|
|
|
Context->RequestMdl = NULL; // common buffer, we didn't alloc mdl
|
|
|
|
} else {
|
|
|
|
packet->Irb->u.FreeAddressRange.p1394AddressRange->AR_Length =
|
|
(USHORT) MmGetMdlByteCount(Context->RequestMdl);
|
|
}
|
|
|
|
} else if (Context == (PADDRESS_CONTEXT) &DeviceExtension->GlobalStatusContext) {
|
|
|
|
packet->Irb->u.FreeAddressRange.p1394AddressRange->AR_Length = sizeof(STATUS_FIFO_BLOCK);
|
|
}
|
|
|
|
packet->Irb->u.FreeAddressRange.DeviceExtension = DeviceExtension;
|
|
|
|
if ((KeGetCurrentIrql() >= DISPATCH_LEVEL) && !Context->Address.BusAddress.Off_High) {
|
|
|
|
PPORT_PHYS_ADDR_ROUTINE routine = DeviceExtension->HostRoutineAPI.PhysAddrMappingRoutine;
|
|
|
|
(*routine) (DeviceExtension->HostRoutineAPI.Context,packet->Irb);
|
|
|
|
} else {
|
|
|
|
//
|
|
// dont care about the status of this op
|
|
//
|
|
|
|
Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
|
|
}
|
|
|
|
Context->AddressHandle = NULL;
|
|
|
|
if (Context->RequestMdl) {
|
|
|
|
IoFreeMdl (Context->RequestMdl);
|
|
Context->RequestMdl = NULL;
|
|
}
|
|
|
|
DeAllocateIrpAndIrb (DeviceExtension, packet);
|
|
}
|
|
|
|
|
|
VOID
|
|
Free1394DataMapping(
|
|
PDEVICE_EXTENSION DeviceExtension,
|
|
PASYNC_REQUEST_CONTEXT Context
|
|
)
|
|
{
|
|
PIRBIRP packet ;
|
|
|
|
|
|
if (Context->DataMappingHandle == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
AllocateIrpAndIrb (DeviceExtension, &packet);
|
|
|
|
if (!packet) {
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Free the data buffer's 1394 address range
|
|
//
|
|
|
|
packet->Irb->FunctionNumber = REQUEST_FREE_ADDRESS_RANGE;
|
|
packet->Irb->Flags = 0;
|
|
packet->Irb->u.FreeAddressRange.nAddressesToFree = 1;
|
|
packet->Irb->u.FreeAddressRange.p1394AddressRange = (PADDRESS_RANGE) NULL;
|
|
packet->Irb->u.FreeAddressRange.pAddressRange = &Context->DataMappingHandle;
|
|
packet->Irb->u.FreeAddressRange.DeviceExtension = DeviceExtension;
|
|
|
|
if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
|
|
|
|
PPORT_PHYS_ADDR_ROUTINE routine = DeviceExtension->HostRoutineAPI.PhysAddrMappingRoutine;
|
|
|
|
(*routine) (DeviceExtension->HostRoutineAPI.Context, packet->Irb);
|
|
|
|
} else {
|
|
|
|
//
|
|
// dont care about the status of this op
|
|
//
|
|
|
|
Sbp2SendRequest (DeviceExtension, packet, SYNC_1394_REQUEST);
|
|
}
|
|
|
|
if (Context->PartialMdl) {
|
|
|
|
IoFreeMdl (Context->PartialMdl);
|
|
Context->PartialMdl = NULL;
|
|
}
|
|
|
|
Context->DataMappingHandle = NULL;
|
|
|
|
DeAllocateIrpAndIrb (DeviceExtension, packet);
|
|
}
|
|
|
|
|
|
ULONG
|
|
FreeAsyncRequestContext(
|
|
PDEVICE_EXTENSION DeviceExtension,
|
|
PASYNC_REQUEST_CONTEXT Context
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine will free a single RequestContext and will cleanup all
|
|
its buffers and 1394 ranges, ONLY of the device is marked as STOPPED.
|
|
Otherwise it will add the context to the FreeList, so it can be reused
|
|
later one by another request. This way we are drastically speeding up
|
|
each request.
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Device Extension of the sbp2 device
|
|
Context - Context to freed or returned to FreeList
|
|
|
|
Return Value:
|
|
|
|
None - The result of the decrement of DeviceExtension->OrbListDepth
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// This ORB can now be freed along with its data descriptor,
|
|
// page tables and context
|
|
//
|
|
|
|
if (!Context || (Context->Tag != SBP2_ASYNC_CONTEXT_TAG)) {
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: FreeAsyncReqCtx: attempt to push freed ctx=x%p\n",
|
|
Context
|
|
));
|
|
|
|
ASSERT(FALSE);
|
|
return 0;
|
|
}
|
|
|
|
ASSERT(Context->Srb == NULL);
|
|
|
|
if (Context->DataMappingHandle) {
|
|
|
|
Free1394DataMapping(DeviceExtension,Context);
|
|
ASSERT(Context->DataMappingHandle==NULL);
|
|
}
|
|
|
|
//
|
|
// Re-initiliaze this context so it can be reused
|
|
// This context is still part on our FreeAsyncContextPool
|
|
// All we have to do is initialize some flags, so next time
|
|
// we try to retrieve it, we think its empty
|
|
//
|
|
|
|
Context->Flags |= ASYNC_CONTEXT_FLAG_COMPLETED;
|
|
Context->Tag = 0;
|
|
|
|
if (Context->OriginalSrb) {
|
|
|
|
ExFreePool(Context->OriginalSrb);
|
|
Context->OriginalSrb = NULL;
|
|
}
|
|
|
|
DEBUGPRINT3(("Sbp2Port: FreeAsyncReqCtx: push ctx=x%p on free list\n",Context));
|
|
|
|
ExInterlockedPushEntrySList(&DeviceExtension->FreeContextListHead,
|
|
&Context->LookasideList,
|
|
&DeviceExtension->FreeContextLock);
|
|
|
|
return InterlockedDecrement (&DeviceExtension->OrbListDepth);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2SendRequest(
|
|
PDEVICE_EXTENSION DeviceExtension,
|
|
PIRBIRP RequestPacket,
|
|
ULONG TransferMode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Function used to send requests to the 1394 bus driver. It attaches
|
|
a completion routine to each request it sends down, and it also wraps
|
|
them in a small context, so we can track their completion
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Sbp2 device extension
|
|
Irp - Irp to send to the bus driver
|
|
Irb - Bus driver packet, in the Irp
|
|
TransferMode - Indicates if we want ot send this request synchronously
|
|
or asynchronously
|
|
FinalTransferMode - Indicates whether the request was sent synchronously
|
|
or asynchronously
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG originalTransferMode = TransferMode;
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT deviceObject = DeviceExtension->DeviceObject;
|
|
PREQUEST_CONTEXT requestContext = NULL;
|
|
PIO_STACK_LOCATION nextIrpStack;
|
|
|
|
|
|
if (DeviceExtension->Type == SBP2_PDO) {
|
|
|
|
//
|
|
// if device is removed, dont send any requests down
|
|
//
|
|
|
|
if (TEST_FLAG(DeviceExtension->DeviceFlags,DEVICE_FLAG_REMOVED) &&
|
|
(RequestPacket->Irb->FunctionNumber != REQUEST_FREE_ADDRESS_RANGE)) {
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// get a context for this request, from our pool
|
|
//
|
|
|
|
requestContext = (PREQUEST_CONTEXT) \
|
|
ExInterlockedPopEntrySList(&DeviceExtension->BusRequestContextListHead,&DeviceExtension->BusRequestLock);
|
|
|
|
} else {
|
|
|
|
requestContext = ExAllocatePool (NonPagedPool,sizeof(REQUEST_CONTEXT));
|
|
}
|
|
|
|
if (!requestContext) {
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: SendReq: ERROR, couldn't allocate bus req ctx\n"
|
|
));
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
if (TransferMode == SYNC_1394_REQUEST) {
|
|
|
|
if (KeGetCurrentIrql() >= DISPATCH_LEVEL) {
|
|
|
|
//
|
|
// Since we can't block at this level, we will have to do the
|
|
// synch request asynchronously
|
|
//
|
|
|
|
TransferMode = ASYNC_SYNC_1394_REQUEST;
|
|
requestContext->Complete = 0;
|
|
|
|
} else {
|
|
|
|
KeInitializeEvent(
|
|
&requestContext->Event,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
}
|
|
}
|
|
|
|
requestContext->DeviceExtension = DeviceExtension;
|
|
requestContext->RequestType = TransferMode;
|
|
|
|
if (TransferMode == SYNC_1394_REQUEST){
|
|
|
|
requestContext->Packet = NULL;
|
|
|
|
} else {
|
|
|
|
requestContext->Packet = RequestPacket;
|
|
}
|
|
|
|
nextIrpStack = IoGetNextIrpStackLocation (RequestPacket->Irp);
|
|
|
|
nextIrpStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
|
|
nextIrpStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_1394_CLASS;
|
|
nextIrpStack->Parameters.Others.Argument1 = RequestPacket->Irb;
|
|
|
|
IoSetCompletionRoutine(RequestPacket->Irp,
|
|
Sbp2RequestCompletionRoutine,
|
|
requestContext,
|
|
TRUE,
|
|
TRUE,
|
|
TRUE
|
|
);
|
|
|
|
status = IoCallDriver(
|
|
DeviceExtension->LowerDeviceObject,
|
|
RequestPacket->Irp
|
|
);
|
|
|
|
if (status == STATUS_INVALID_GENERATION) {
|
|
|
|
DEBUGPRINT1(("Sbp2Port: SendReq: Bus drv ret'd invalid generation\n"));
|
|
RequestPacket->Irp->IoStatus.Status = STATUS_REQUEST_ABORTED;
|
|
}
|
|
|
|
if (originalTransferMode == SYNC_1394_REQUEST ) {
|
|
|
|
if (TransferMode == SYNC_1394_REQUEST) {
|
|
|
|
if (status == STATUS_PENDING) {
|
|
|
|
//
|
|
// < DISPATCH_LEVEL so wait on an event
|
|
//
|
|
|
|
KeWaitForSingleObject(
|
|
&requestContext->Event,
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
} else { // ASYNC_SYNC_1394_REQUEST
|
|
|
|
//
|
|
// >= DISPATCH_LEVEL so we can't wait, do the nasty...
|
|
//
|
|
|
|
volatile ULONG *pComplete = &requestContext->Complete;
|
|
|
|
while (*pComplete == 0);
|
|
|
|
status = RequestPacket->Irp->IoStatus.Status;
|
|
}
|
|
|
|
//
|
|
// Free the context (the Irp.Irb will be returnd by the caller)
|
|
//
|
|
|
|
if (DeviceExtension->Type == SBP2_PDO) {
|
|
|
|
ExInterlockedPushEntrySList(
|
|
&DeviceExtension->BusRequestContextListHead,
|
|
&requestContext->ListPointer,
|
|
&DeviceExtension->BusRequestLock
|
|
);
|
|
|
|
} else {
|
|
|
|
ExFreePool (requestContext);
|
|
}
|
|
|
|
return RequestPacket->Irp->IoStatus.Status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2RequestCompletionRoutine(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PREQUEST_CONTEXT Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completion routine used for all requests to 1394 bus driver
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object created by system.
|
|
|
|
Irp - Irp that just completed
|
|
|
|
Event - Event we'll signal to say Irp is done
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ASSERT(Context!=NULL);
|
|
ASSERT(Context->DeviceExtension);
|
|
|
|
if (Context->RequestType == SYNC_1394_REQUEST) {
|
|
|
|
//
|
|
// Synch request completion (either synch, or synch at DPC)
|
|
//
|
|
|
|
KeSetEvent (&Context->Event, IO_NO_INCREMENT, FALSE);
|
|
|
|
} else if (Context->RequestType == ASYNC_1394_REQUEST) {
|
|
|
|
//
|
|
// Asynchronous request completion, so do any necessary
|
|
// post-processing & return the context and the Irp/Irb
|
|
// to the free lists.
|
|
//
|
|
|
|
if (Context->Packet) {
|
|
|
|
switch (Context->Packet->Irb->FunctionNumber) {
|
|
|
|
case REQUEST_ASYNC_READ:
|
|
case REQUEST_ASYNC_WRITE:
|
|
|
|
if (Context->Packet->Irb->u.AsyncWrite.nNumberOfBytesToWrite ==
|
|
sizeof(OCTLET)) {
|
|
|
|
IoFreeMdl (Context->Packet->Irb->u.AsyncRead.Mdl);
|
|
|
|
Context->Packet->Irb->u.AsyncRead.Mdl = NULL;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
DeAllocateIrpAndIrb (Context->DeviceExtension, Context->Packet);
|
|
}
|
|
|
|
if (Context->DeviceExtension->Type == SBP2_PDO) {
|
|
|
|
ExInterlockedPushEntrySList(
|
|
&Context->DeviceExtension->BusRequestContextListHead,
|
|
&Context->ListPointer,
|
|
&Context->DeviceExtension->BusRequestLock
|
|
);
|
|
|
|
} else {
|
|
|
|
ExFreePool (Context);
|
|
}
|
|
|
|
} else { // ASYNC_SYNC_1394_REQUEST
|
|
|
|
//
|
|
// Just set the Complete flag to unblock Sbp2SendRequest
|
|
//
|
|
|
|
Context->Complete = 1;
|
|
}
|
|
|
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2CreateRequestErrorLog(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PASYNC_REQUEST_CONTEXT Context,
|
|
IN NTSTATUS Status
|
|
)
|
|
|
|
{
|
|
PIO_ERROR_LOG_PACKET errorLogEntry;
|
|
|
|
|
|
errorLogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
|
|
DeviceObject,
|
|
sizeof(IO_ERROR_LOG_PACKET) + sizeof(ORB_NORMAL_CMD)
|
|
);
|
|
|
|
if (errorLogEntry) {
|
|
|
|
switch (Status) {
|
|
|
|
case STATUS_DEVICE_POWER_FAILURE:
|
|
|
|
errorLogEntry->ErrorCode = IO_ERR_NOT_READY;
|
|
break;
|
|
|
|
case STATUS_INSUFFICIENT_RESOURCES:
|
|
|
|
errorLogEntry->ErrorCode = IO_ERR_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
|
|
case STATUS_TIMEOUT:
|
|
|
|
errorLogEntry->ErrorCode = IO_ERR_TIMEOUT;
|
|
break;
|
|
|
|
case STATUS_DEVICE_PROTOCOL_ERROR:
|
|
|
|
errorLogEntry->ErrorCode = IO_ERR_BAD_FIRMWARE;
|
|
break;
|
|
|
|
|
|
case STATUS_INVALID_PARAMETER:
|
|
case STATUS_INVALID_DEVICE_REQUEST:
|
|
|
|
errorLogEntry->ErrorCode = IO_ERR_INVALID_REQUEST;
|
|
break;
|
|
|
|
case STATUS_REQUEST_ABORTED:
|
|
|
|
errorLogEntry->ErrorCode = IO_ERR_RESET;
|
|
break;
|
|
|
|
default:
|
|
|
|
errorLogEntry->ErrorCode = IO_ERR_BAD_FIRMWARE;
|
|
break;
|
|
}
|
|
|
|
errorLogEntry->SequenceNumber = 0;
|
|
errorLogEntry->MajorFunctionCode = IRP_MJ_SCSI;
|
|
errorLogEntry->RetryCount = 0;
|
|
errorLogEntry->UniqueErrorValue = 0;
|
|
errorLogEntry->FinalStatus = Status;
|
|
|
|
if (Context) {
|
|
|
|
errorLogEntry->DumpDataSize = sizeof(ORB_NORMAL_CMD);
|
|
RtlCopyMemory(&(errorLogEntry->DumpData[0]),Context->CmdOrb,sizeof(ORB_NORMAL_CMD));
|
|
|
|
} else {
|
|
|
|
errorLogEntry->DumpDataSize = 0;
|
|
}
|
|
|
|
IoWriteErrorLogEntry(errorLogEntry);
|
|
|
|
DEBUGPRINT2((
|
|
"Sbp2Port: ErrorLog: dev=x%p, status=x%x, ctx=x%p\n",
|
|
DeviceObject,
|
|
Status,
|
|
Context
|
|
));
|
|
|
|
} else {
|
|
|
|
DEBUGPRINT2 (("Sbp2Port: ErrorLog: failed to allocate log entry\n"));
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CheckStatusResponseValue(
|
|
IN PSTATUS_FIFO_BLOCK StatusBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
It checks the status block result bits and maps the errors to
|
|
NT status errors
|
|
|
|
Arguments:
|
|
|
|
DeviceExtension - Sbp2 device extension
|
|
|
|
ManagementStatus - If true then we check the management orb status
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
++*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
UCHAR resp;
|
|
USHORT statusFlags = StatusBlock->AddressAndStatus.u.HighQuad.u.HighPart;
|
|
|
|
|
|
if (statusFlags & STATUS_BLOCK_UNSOLICITED_BIT_MASK) {
|
|
|
|
//
|
|
// The unsolicited bit is set, which means this status is
|
|
// not related to anything...
|
|
//
|
|
|
|
status = STATUS_NOT_FOUND;
|
|
|
|
} else {
|
|
|
|
resp = statusFlags & STATUS_BLOCK_RESP_MASK;
|
|
|
|
if (resp == 0x01) {
|
|
|
|
resp = (statusFlags & STATUS_BLOCK_RESP_MASK) & 0x0F;
|
|
|
|
//
|
|
// This a protocol/transport error. Check the redefined sbp-status field for serial-bus erros
|
|
//
|
|
|
|
switch (resp) {
|
|
|
|
case 0x02: //time out
|
|
case 0x0D: // data error
|
|
case 0x0C: // conflict error
|
|
|
|
status = STATUS_DEVICE_PROTOCOL_ERROR;
|
|
break;
|
|
|
|
case 0x04: // busy retry limit exceeded
|
|
|
|
status = STATUS_DEVICE_BUSY;
|
|
break;
|
|
|
|
case 0x09: // rejected
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
|
|
case 0x0F: // address error
|
|
|
|
status = STATUS_INVALID_ADDRESS;
|
|
break;
|
|
|
|
case 0x0E: // type error
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
|
|
default:
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
if (resp == 0x02) {
|
|
|
|
return STATUS_ILLEGAL_FUNCTION;
|
|
}
|
|
|
|
//
|
|
// REQUEST_COMPLETE. Check sbp_status field for more info
|
|
//
|
|
|
|
if (resp == 0x00) {
|
|
|
|
switch ((statusFlags & STATUS_BLOCK_SBP_STATUS_MASK)) {
|
|
|
|
case 0x11: //dummy orb completed
|
|
case 0x00: // no additional status to report
|
|
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case 0x01: // request type not supported
|
|
case 0x02: // speed not supported
|
|
case 0x03: // page size not supported
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
|
|
case 0x10: // login id not recognized
|
|
|
|
status = STATUS_TRANSACTION_INVALID_ID;
|
|
break;
|
|
|
|
case 0xFF: // unspecifed error
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
|
|
case 0x09: // function rejected
|
|
|
|
status = STATUS_ILLEGAL_FUNCTION;
|
|
break;
|
|
|
|
case 0x04: // access denied
|
|
case 0x05: //LUN not supported
|
|
|
|
status = STATUS_ACCESS_DENIED;
|
|
break;
|
|
|
|
case 0x07:
|
|
case 0x08:
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
break;
|
|
|
|
default:
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetRegistryParameters(
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
IN OUT PULONG DiagnosticFlags,
|
|
IN OUT PULONG MaxTransferSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function gets some values out of the registry for initialization
|
|
|
|
Arguments:
|
|
|
|
PhysicalDeviceObject - The Port driver's parent device object
|
|
|
|
DiagnosticFlags - Used for debugging
|
|
|
|
ReceiveWorkers - Max number of receive worker structures
|
|
|
|
TransmitWorkers - Max number of xmit worker structures
|
|
|
|
bAllowPhyConfigPackets - do we allow phy config packets to be sent
|
|
|
|
Return Value:
|
|
|
|
Status is returned from Irp
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
HANDLE handle;
|
|
WCHAR diagnosticModeKey[] = L"DiagnosticFlags";
|
|
WCHAR maxTransferSizeKey[] = L"MaxTransferSize";
|
|
|
|
status = IoOpenDeviceRegistryKey(
|
|
PhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
STANDARD_RIGHTS_ALL,
|
|
&handle
|
|
);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
GetRegistryKeyValue(
|
|
handle,
|
|
diagnosticModeKey,
|
|
sizeof(diagnosticModeKey),
|
|
DiagnosticFlags,
|
|
sizeof(*DiagnosticFlags)
|
|
);
|
|
|
|
GetRegistryKeyValue(
|
|
handle,
|
|
maxTransferSizeKey,
|
|
sizeof(maxTransferSizeKey),
|
|
MaxTransferSize,
|
|
sizeof(*MaxTransferSize)
|
|
);
|
|
|
|
|
|
ZwClose(handle);
|
|
}
|
|
|
|
DEBUGPRINT3((
|
|
"Sbp2Port: GetRegParams: status=x%x, diag=x%x, maxXfer=x%x\n",
|
|
status,
|
|
*DiagnosticFlags,
|
|
*MaxTransferSize
|
|
));
|
|
|
|
return (status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
GetRegistryKeyValue (
|
|
IN HANDLE Handle,
|
|
IN PWCHAR KeyNameString,
|
|
IN ULONG KeyNameStringLength,
|
|
IN PVOID Data,
|
|
IN ULONG DataLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine gets the specified value out of the registry
|
|
|
|
Arguments:
|
|
|
|
Handle - Handle to location in registry
|
|
|
|
KeyNameString - registry key we're looking for
|
|
|
|
KeyNameStringLength - length of registry key we're looking for
|
|
|
|
Data - where to return the data
|
|
|
|
DataLength - how big the data is
|
|
|
|
Return Value:
|
|
|
|
status is returned from ZwQueryValueKey
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
|
|
UNICODE_STRING keyName;
|
|
ULONG length;
|
|
PKEY_VALUE_FULL_INFORMATION fullInfo;
|
|
|
|
|
|
RtlInitUnicodeString(&keyName, KeyNameString);
|
|
|
|
length = sizeof(KEY_VALUE_FULL_INFORMATION) +
|
|
KeyNameStringLength + DataLength;
|
|
|
|
fullInfo = ExAllocatePoolWithTag(PagedPool, length,'2pbs');
|
|
|
|
if (fullInfo) {
|
|
|
|
status = ZwQueryValueKey(
|
|
Handle,
|
|
&keyName,
|
|
KeyValueFullInformation,
|
|
fullInfo,
|
|
length,
|
|
&length
|
|
);
|
|
|
|
if (NT_SUCCESS(status)){
|
|
|
|
if (DataLength == fullInfo->DataLength) {
|
|
|
|
RtlCopyMemory(
|
|
Data,
|
|
((PUCHAR) fullInfo) + fullInfo->DataOffset,
|
|
DataLength
|
|
);
|
|
|
|
} else {
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: GetRegKeyVal: keyLen!=exp, dataLen=x%x " \
|
|
"fullInfoLen=x%x\n",
|
|
DataLength,
|
|
fullInfo->DataLength
|
|
));
|
|
}
|
|
}
|
|
|
|
ExFreePool(fullInfo);
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
|
|
VOID
|
|
ValidateTextLeaf(
|
|
IN PTEXTUAL_LEAF Leaf
|
|
)
|
|
{
|
|
PUCHAR buff;
|
|
PWCHAR wBuff;
|
|
ULONG byteSwappedData;
|
|
|
|
|
|
//
|
|
// check the lengths. insert null terminators if they are
|
|
// too long...
|
|
//
|
|
|
|
byteSwappedData = bswap(*((PULONG)Leaf+1));
|
|
wBuff = (PWCHAR) &Leaf->TL_Data;
|
|
buff = &Leaf->TL_Data;
|
|
|
|
if (Leaf->TL_Length > SBP2_MAX_TEXT_LEAF_LENGTH) {
|
|
|
|
ASSERT(Leaf->TL_Length <= SBP2_MAX_TEXT_LEAF_LENGTH);
|
|
buff[SBP2_MAX_TEXT_LEAF_LENGTH-1] = 0;
|
|
buff[SBP2_MAX_TEXT_LEAF_LENGTH-2] = 0;
|
|
}
|
|
|
|
//
|
|
// check for invalid characters and replace them with _
|
|
//
|
|
|
|
if (byteSwappedData & 0x80000000) {
|
|
|
|
//
|
|
// unicode
|
|
//
|
|
|
|
for (wBuff = (PWCHAR) &Leaf->TL_Data; *wBuff; wBuff++) {
|
|
|
|
if ((*wBuff < L' ') || (*wBuff > (WCHAR)0x7F) || (*wBuff == L',')) {
|
|
|
|
*wBuff = L'_';
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// ascii
|
|
//
|
|
|
|
for (buff = &Leaf->TL_Data; *buff; buff++) {
|
|
|
|
if ((*buff < L' ') || (*buff > (CHAR)0x7F) || (*buff == L',')) {
|
|
|
|
*buff = L'_';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2StartNextPacketByKey(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN ULONG Key
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine was lifted from the Io sources
|
|
(IopStartNextPacketByKey), and duplicated/modifed here for
|
|
two reasons: 1) we got tired of hitting the queue-not-busy assert
|
|
in KeRemoveXxx, and 2) we needed a way to prevent stack-blowing
|
|
recursion, for example, arising from a bunch of requests sent to
|
|
a stopped device (all failed in StartIo, which calls this func).
|
|
|
|
These routines were originally designed with the idea that there
|
|
would only be one outstanding request at a time, but this driver
|
|
can have multiple outstanding requests, and it frequently ends up
|
|
making redundant calls to XxStartNextPacket(ByKey), which result
|
|
in the aforementioned assert.
|
|
|
|
Rolling our own version of this also allows us to get rid the
|
|
the cancel overhead, since we do not (currently) support cancels.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object itself
|
|
|
|
Key - Specifics the Key used to remove the entry from the queue
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION)
|
|
DeviceObject->DeviceExtension;
|
|
PKDEVICE_QUEUE_ENTRY packet;
|
|
|
|
|
|
//
|
|
// Increment the StartNextPacketCount, and if result is != 1
|
|
// then just return because we don't want to worry about
|
|
// recursion & blowing the stack. The instance of this
|
|
// function that caused the SNPCount 0 to 1 transition
|
|
// will eventually make another pass through the loop below
|
|
// on this instance's behalf.
|
|
//
|
|
|
|
if (InterlockedIncrement (&deviceExtension->StartNextPacketCount) != 1) {
|
|
|
|
return;
|
|
}
|
|
|
|
do {
|
|
|
|
//
|
|
// Attempt to remove the indicated packet according to the key
|
|
// from the device queue. If one is found, then process it.
|
|
//
|
|
|
|
packet = Sbp2RemoveByKeyDeviceQueueIfBusy(
|
|
&DeviceObject->DeviceQueue,
|
|
Key
|
|
);
|
|
|
|
if (packet) {
|
|
|
|
irp = CONTAINING_RECORD (packet,IRP,Tail.Overlay.DeviceQueueEntry);
|
|
|
|
Sbp2StartIo (DeviceObject, irp);
|
|
}
|
|
|
|
} while (InterlockedDecrement (&deviceExtension->StartNextPacketCount));
|
|
}
|
|
|
|
|
|
VOID
|
|
Sbp2StartPacket(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp,
|
|
IN PULONG Key OPTIONAL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(See routine description for Sbp2StartNextPacketByKey)
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to device object itself
|
|
|
|
Irp - I/O Request Packet which should be started on the device
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
KIRQL oldIrql;
|
|
BOOLEAN inserted;
|
|
PLIST_ENTRY nextEntry;
|
|
PKDEVICE_QUEUE queue = &DeviceObject->DeviceQueue;
|
|
PKDEVICE_QUEUE_ENTRY queueEntry = &Irp->Tail.Overlay.DeviceQueueEntry,
|
|
queueEntry2;
|
|
|
|
|
|
//
|
|
// Raise the IRQL of the processor to dispatch level for synchronization
|
|
//
|
|
|
|
KeRaiseIrql (DISPATCH_LEVEL, &oldIrql);
|
|
|
|
KeAcquireSpinLockAtDpcLevel (&queue->Lock);
|
|
|
|
if (Key) {
|
|
|
|
//
|
|
// Insert the specified device queue entry in the device queue at the
|
|
// position specified by the sort key if the device queue is busy.
|
|
// Otherwise set the device queue busy an don't insert the device
|
|
// queue entry.
|
|
//
|
|
|
|
queueEntry->SortKey = *Key;
|
|
|
|
if (queue->Busy == TRUE) {
|
|
|
|
inserted = TRUE;
|
|
|
|
nextEntry = queue->DeviceListHead.Flink;
|
|
|
|
while (nextEntry != &queue->DeviceListHead) {
|
|
|
|
queueEntry2 = CONTAINING_RECORD(
|
|
nextEntry,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry
|
|
);
|
|
|
|
if (*Key < queueEntry2->SortKey) {
|
|
|
|
break;
|
|
}
|
|
|
|
nextEntry = nextEntry->Flink;
|
|
}
|
|
|
|
nextEntry = nextEntry->Blink;
|
|
|
|
InsertHeadList (nextEntry, &queueEntry->DeviceListEntry);
|
|
|
|
} else {
|
|
|
|
queue->Busy = TRUE;
|
|
inserted = FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Insert the specified device queue entry at the end of the device
|
|
// queue if the device queue is busy. Otherwise set the device queue
|
|
// busy and don't insert the device queue entry.
|
|
//
|
|
|
|
if (queue->Busy == TRUE) {
|
|
|
|
inserted = TRUE;
|
|
|
|
InsertTailList(
|
|
&queue->DeviceListHead,
|
|
&queueEntry->DeviceListEntry
|
|
);
|
|
|
|
} else {
|
|
|
|
queue->Busy = TRUE;
|
|
inserted = FALSE;
|
|
}
|
|
}
|
|
|
|
queueEntry->Inserted = inserted;
|
|
|
|
KeReleaseSpinLockFromDpcLevel (&queue->Lock);
|
|
|
|
//
|
|
// If the packet was not inserted into the queue, then this request is
|
|
// now the current packet for this device. Indicate so by storing its
|
|
// address in the current IRP field, and begin processing the request.
|
|
//
|
|
|
|
if (!inserted) {
|
|
|
|
//
|
|
// Invoke the driver's start I/O routine to get the request going
|
|
// on the device
|
|
//
|
|
|
|
Sbp2StartIo (DeviceObject, Irp);
|
|
}
|
|
|
|
//
|
|
// Restore the IRQL back to its value upon entry to this function before
|
|
// returning to the caller
|
|
//
|
|
|
|
KeLowerIrql (oldIrql);
|
|
}
|
|
|
|
|
|
PKDEVICE_QUEUE_ENTRY
|
|
Sbp2RemoveByKeyDeviceQueueIfBusy(
|
|
IN PKDEVICE_QUEUE DeviceQueue,
|
|
IN ULONG SortKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine was lifted directly from Ke sources
|
|
(KeRemoveByKeyDeviceQueueIfBusy) to allow this driver to maintain
|
|
WDM compatibility, since the Ke API does not exist on Win9x or Win2k.
|
|
|
|
N.B. This function can only be called from DISPATCH_LEVEL.
|
|
|
|
Arguments:
|
|
|
|
DeviceQueue - Supplies a pointer to a control object of type device queue.
|
|
|
|
SortKey - Supplies the sort key by which the position to remove the device
|
|
queue entry is to be determined.
|
|
|
|
Return Value:
|
|
|
|
A NULL pointer is returned if the device queue is empty. Otherwise a
|
|
pointer to a device queue entry is returned.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY nextEntry;
|
|
PKDEVICE_QUEUE_ENTRY queueEntry;
|
|
|
|
|
|
ASSERT (KeGetCurrentIrql() == DISPATCH_LEVEL);
|
|
|
|
//
|
|
// Lock specified device queue.
|
|
//
|
|
|
|
KeAcquireSpinLockAtDpcLevel (&DeviceQueue->Lock);
|
|
|
|
//
|
|
// If the device queue is busy, then attempt to remove an entry from
|
|
// the queue using the sort key. Otherwise, set the device queue not
|
|
// busy.
|
|
//
|
|
|
|
if (DeviceQueue->Busy != FALSE) {
|
|
|
|
if (IsListEmpty (&DeviceQueue->DeviceListHead) != FALSE) {
|
|
|
|
DeviceQueue->Busy = FALSE;
|
|
queueEntry = NULL;
|
|
|
|
} else {
|
|
|
|
nextEntry = DeviceQueue->DeviceListHead.Flink;
|
|
|
|
while (nextEntry != &DeviceQueue->DeviceListHead) {
|
|
|
|
queueEntry = CONTAINING_RECORD(
|
|
nextEntry,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry
|
|
);
|
|
|
|
if (SortKey <= queueEntry->SortKey) {
|
|
|
|
break;
|
|
}
|
|
|
|
nextEntry = nextEntry->Flink;
|
|
}
|
|
|
|
if (nextEntry != &DeviceQueue->DeviceListHead) {
|
|
|
|
RemoveEntryList (&queueEntry->DeviceListEntry);
|
|
|
|
} else {
|
|
|
|
nextEntry = RemoveHeadList (&DeviceQueue->DeviceListHead);
|
|
|
|
queueEntry = CONTAINING_RECORD(
|
|
nextEntry,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry
|
|
);
|
|
}
|
|
|
|
queueEntry->Inserted = FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
queueEntry = NULL;
|
|
}
|
|
|
|
//
|
|
// Unlock specified device queue and return address of device queue
|
|
// entry.
|
|
//
|
|
|
|
KeReleaseSpinLockFromDpcLevel (&DeviceQueue->Lock);
|
|
|
|
return queueEntry;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
Sbp2InsertByKeyDeviceQueue(
|
|
PKDEVICE_QUEUE DeviceQueue,
|
|
PKDEVICE_QUEUE_ENTRY DeviceQueueEntry,
|
|
ULONG SortKey
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
(Again, stolen from Ke src to maintain consistent use of spinlocks.)
|
|
|
|
This function inserts a device queue entry into the specified device
|
|
queue according to a sort key. If the device is not busy, then it is
|
|
set busy and the entry is not placed in the device queue. Otherwise
|
|
the specified entry is placed in the device queue at a position such
|
|
that the specified sort key is greater than or equal to its predecessor
|
|
and less than its successor.
|
|
|
|
N.B. This function can only be called from DISPATCH_LEVEL.
|
|
|
|
Arguments:
|
|
|
|
DeviceQueue - Supplies a pointer to a control object of type device queue.
|
|
|
|
DeviceQueueEntry - Supplies a pointer to a device queue entry.
|
|
|
|
SortKey - Supplies the sort key by which the position to insert the device
|
|
queue entry is to be determined.
|
|
|
|
Return Value:
|
|
|
|
If the device is not busy, then a value of FALSE is returned. Otherwise a
|
|
value of TRUE is returned.
|
|
|
|
--*/
|
|
{
|
|
BOOLEAN inserted;
|
|
PLIST_ENTRY nextEntry;
|
|
PKDEVICE_QUEUE queue = DeviceQueue;
|
|
PKDEVICE_QUEUE_ENTRY queueEntry = DeviceQueueEntry,
|
|
queueEntry2;
|
|
|
|
|
|
KeAcquireSpinLockAtDpcLevel (&queue->Lock);
|
|
|
|
//
|
|
// Insert the specified device queue entry in the device queue at the
|
|
// position specified by the sort key if the device queue is busy.
|
|
// Otherwise set the device queue busy an don't insert the device
|
|
// queue entry.
|
|
//
|
|
|
|
queueEntry->SortKey = SortKey;
|
|
|
|
if (queue->Busy == TRUE) {
|
|
|
|
inserted = TRUE;
|
|
|
|
nextEntry = queue->DeviceListHead.Flink;
|
|
|
|
while (nextEntry != &queue->DeviceListHead) {
|
|
|
|
queueEntry2 = CONTAINING_RECORD(
|
|
nextEntry,
|
|
KDEVICE_QUEUE_ENTRY,
|
|
DeviceListEntry
|
|
);
|
|
|
|
if (SortKey < queueEntry2->SortKey) {
|
|
|
|
break;
|
|
}
|
|
|
|
nextEntry = nextEntry->Flink;
|
|
}
|
|
|
|
nextEntry = nextEntry->Blink;
|
|
|
|
InsertHeadList (nextEntry, &queueEntry->DeviceListEntry);
|
|
|
|
} else {
|
|
|
|
queue->Busy = TRUE;
|
|
inserted = FALSE;
|
|
}
|
|
|
|
KeReleaseSpinLockFromDpcLevel (&queue->Lock);
|
|
|
|
return inserted;
|
|
}
|
|
|
|
#if PASSWORD_SUPPORT
|
|
|
|
NTSTATUS
|
|
Sbp2GetExclusiveValue(
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
OUT PULONG Exclusive
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
HANDLE RootHandle = NULL;
|
|
UNICODE_STRING uniTempName;
|
|
|
|
|
|
// set default value...
|
|
|
|
*Exclusive = EXCLUSIVE_FLAG_CLEAR;
|
|
|
|
uniTempName.Buffer = NULL;
|
|
|
|
ntStatus = IoOpenDeviceRegistryKey( PhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
KEY_ALL_ACCESS,
|
|
&RootHandle
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2GetExclusiveValue;
|
|
}
|
|
|
|
uniTempName.Length = 0;
|
|
uniTempName.MaximumLength = 128;
|
|
|
|
uniTempName.Buffer = ExAllocatePool(
|
|
NonPagedPool,
|
|
uniTempName.MaximumLength
|
|
);
|
|
|
|
if (!uniTempName.Buffer) {
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2GetExclusiveValue;
|
|
}
|
|
|
|
{
|
|
PKEY_VALUE_PARTIAL_INFORMATION KeyInfo;
|
|
ULONG KeyLength;
|
|
ULONG ResultLength;
|
|
|
|
KeyLength = sizeof (KEY_VALUE_PARTIAL_INFORMATION) + sizeof (ULONG);
|
|
|
|
KeyInfo = ExAllocatePool (NonPagedPool, KeyLength);
|
|
|
|
if (KeyInfo == NULL) {
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2GetExclusiveValue;
|
|
}
|
|
|
|
RtlZeroMemory(uniTempName.Buffer, uniTempName.MaximumLength);
|
|
uniTempName.Length = 0;
|
|
RtlAppendUnicodeToString(&uniTempName, L"Exclusive");
|
|
|
|
ntStatus = ZwQueryValueKey( RootHandle,
|
|
&uniTempName,
|
|
KeyValuePartialInformation,
|
|
KeyInfo,
|
|
KeyLength,
|
|
&ResultLength
|
|
);
|
|
|
|
if (NT_SUCCESS(ntStatus)) {
|
|
|
|
*Exclusive = *((PULONG) &KeyInfo->Data);
|
|
|
|
DEBUGPRINT1 (("Sbp2Port: GetExclVal: excl=x%x\n", *Exclusive));
|
|
|
|
} else {
|
|
|
|
DEBUGPRINT1((
|
|
"Sbp2Port: GetExclVal: QueryValueKey err=x%x\n",
|
|
ntStatus
|
|
));
|
|
}
|
|
|
|
ExFreePool (KeyInfo);
|
|
}
|
|
|
|
Exit_Sbp2GetExclusiveValue:
|
|
|
|
if (RootHandle) {
|
|
|
|
ZwClose (RootHandle);
|
|
}
|
|
|
|
if (uniTempName.Buffer) {
|
|
|
|
ExFreePool (uniTempName.Buffer);
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
Sbp2SetExclusiveValue(
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
IN PULONG Exclusive
|
|
)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
HANDLE RootHandle = NULL;
|
|
UNICODE_STRING uniTempName;
|
|
|
|
|
|
uniTempName.Buffer = NULL;
|
|
|
|
ntStatus = IoOpenDeviceRegistryKey( PhysicalDeviceObject,
|
|
PLUGPLAY_REGKEY_DEVICE,
|
|
KEY_ALL_ACCESS,
|
|
&RootHandle
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
goto Exit_Sbp2SetExclusiveValue;
|
|
}
|
|
|
|
uniTempName.Length = 0;
|
|
uniTempName.MaximumLength = 128;
|
|
|
|
uniTempName.Buffer = ExAllocatePool(
|
|
NonPagedPool,
|
|
uniTempName.MaximumLength
|
|
);
|
|
|
|
if (!uniTempName.Buffer) {
|
|
|
|
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto Exit_Sbp2SetExclusiveValue;
|
|
}
|
|
|
|
RtlZeroMemory (uniTempName.Buffer, uniTempName.MaximumLength);
|
|
uniTempName.Length = 0;
|
|
RtlAppendUnicodeToString(&uniTempName, L"Exclusive");
|
|
|
|
ntStatus = ZwSetValueKey( RootHandle,
|
|
&uniTempName,
|
|
0,
|
|
REG_DWORD,
|
|
Exclusive,
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
if (!NT_SUCCESS(ntStatus)) {
|
|
|
|
DEBUGPRINT1(("Sbp2Port: SetExclVal: SetValueKey err=x%x\n", ntStatus));
|
|
*Exclusive = 0;
|
|
}
|
|
else {
|
|
|
|
DEBUGPRINT1(("Sbp2Port: SetExclVal: excl=x%x\n", *Exclusive));
|
|
}
|
|
|
|
Exit_Sbp2SetExclusiveValue:
|
|
|
|
if (RootHandle) {
|
|
|
|
ZwClose(RootHandle);
|
|
}
|
|
|
|
if (uniTempName.Buffer) {
|
|
|
|
ExFreePool(uniTempName.Buffer);
|
|
}
|
|
|
|
return ntStatus;
|
|
}
|
|
|
|
#endif
|