Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Como qualquer outro driver de modo kernel de nível superior, um SFD (driver de filtro de armazenamento) deve ter uma ou mais rotinas de expedição para lidar com cada solicitação de IRP_MJ_XXX para a qual o driver de armazenamento subjacente fornece um ponto de entrada dispatch . Dependendo da natureza de seu dispositivo, o ponto de entrada Dispatch de um SFD pode fazer um dos seguintes procedimentos para qualquer solicitação específica:
Para uma solicitação que não requer tratamento especial, configure o local da pilha de E/S no IRP para o driver mais baixo, possivelmente chame IoSetCompletionRoutine para configurar sua rotina de IoCompletion para o IRP e passe o IRP para processamento adicional por drivers inferiores com IoCallDriver.
Para uma solicitação já manipulada por um driver de classe de armazenamento, modifique o SRB no local da pilha de E/S do IRP antes de configurar o local da pilha de E/S, possivelmente defina uma rotina IoCompletion e passe o IRP para o driver mais baixo com IoCallDriver.
Configure um novo IRP com um SRB e CDB para seu dispositivo, chame IoSetCompletionRoutine para que o SRB (e o IRP se o driver chamar IoAllocateIrp ou IoBuildAsynchronousFsdRequest) possa ser liberado e passe o IRP com IoCallDriver
É mais provável que um SFD configure novos IRPs com o código de função principal IRP_MJ_INTERNAL_DEVICE_CONTROL.
Processamento de solicitações
Para solicitações que não exigem tratamento especial, a rotina de expedição de um SFD geralmente chama IoSkipCurrentIrpStackLocation com um IRP de entrada e, em seguida, chama IoCallDriver com ponteiros para o objeto de dispositivo do driver de classe e o IRP. Observe que um SFD raramente define sua rotina de IoCompletion em IRPs que não exigem tratamento especial, pois uma chamada para a rotina IoCompletion é desnecessária e porque degrada a taxa de transferência de E/S para os dispositivos do driver. Se um SFD definir uma rotina IoCompletion , ele chamará IoCopyCurrentIrpStackLocationToNext em vez de IoSkipCurrentIrpStackLocation e chamará IoSetCompletionRoutine antes de chamar IoCallDriver.
Para solicitações que exigem tratamento especial, o SFD pode fazer o seguinte:
Crie um novo IRP com IoBuildDeviceIoControlRequest, IoAllocateIrp, IoBuildSynchronousFsdRequest ou IoBuildAsynchronousFsdRequest, geralmente especificando um local de pilha de E/S para si mesmo.
Verifique o ponteiro IRP retornado para NULL e retorne STATUS_INSUFFICIENT_RESOURCES se um IRP não pôde ser alocado.
Se o IRP criado pelo driver incluir um local de pilha de E/S para o SFD, chame IoSetNextIrpStackLocation para configurar o ponteiro de local da pilha IRP. Em seguida, chame IoGetCurrentIrpStackLocation para obter um ponteiro para seu próprio local de pilha de E/S no IRP criado pelo driver e configurá-lo com o estado a ser usado por sua própria rotina IoCompletion .
Chame IoGetNextIrpStackLocation para obter um ponteiro para o local da pilha de E/S do driver mais baixo no IRP criado pelo driver e configurá-lo com o código de função principal IRP_MJ_SCSI e um SRB (consulte Drivers de classe de armazenamento).
Traduza os dados a serem transferidos para o dispositivo em um formato não padrão específico do dispositivo, se necessário.
Chame IoSetCompletionRoutine se o driver alocasse alguma memória, como memória para um buffer SRB, SCSI request-sense, MDL e/ou IRP com uma chamada para IoAllocateIrp ou IoBuildAsynchronousFsdRequest ou se o driver deve traduzir dados transferidos do dispositivo em um formato não padrão específico do dispositivo.
Passe o IRP criado pelo driver para (e através) do driver mais baixo com IoCallDriver.
Manipulando formatos SRB
Começando com Windows 8, uma filtragem SFD entre o driver de classe e o driver de porta deve marcar para o formato SRB com suporte. Especificamente, isso envolve detectar o formato SRB e acessar corretamente os membros da estrutura. O SRB no IRP é um SCSI_REQUEST_BLOCK e ou um STORAGE_REQUEST_BLOCK. Um driver de filtro pode determinar antecipadamente quais SRBs são compatíveis com o driver de porta abaixo, emitindo uma solicitação IOCTL_STORAGE_QUERY_PROPERTY e especificando o identificador StorageAdapterProperty . Os valores SrbType e AddressType retornados na estrutura STORAGE_ADAPTER_DESCRIPTOR indicam o esquema de endereçamento e formato SRB usado pelo driver de porta. Todos os novos SRBs alocados e enviados pelo driver de filtro devem ser do tipo retornado pela consulta.
Da mesma forma, começando com Windows 8, os SFDs que dão suporte apenas a SRBs do tipo SCSI_REQUEST_BLOCK devem marcar que o valor SrbType retornado na estrutura STORAGE_ADAPTER_DESCRIPTOR seja definido como SRB_TYPE_SCSI_REQUEST_BLOCK. Para lidar com a situação quando SrbType é definido como SRB_TYPE_STORAGE_REQUEST_BLOCK , o driver de filtro deve definir uma rotina de conclusão para IOCTL_STORAGE_QUERY_PROPERTY quando o identificador StorageAdapterProperty for definido na solicitação enviada por drivers acima dele. Na rotina de conclusão, o membro SrbType no STORAGE_ADAPTER_DESCRIPTOR é modificado para SRB_TYPE_SCSI_REQUEST_BLOCK para definir corretamente o tipo com suporte.
Veja a seguir um exemplo de uma rotina de expedição de filtro que manipula ambos os formatos SRB.
NTSTATUS FilterScsiIrp(
PDEVICE_OBJECT DeviceObject,
PIRP Irp
)
{
PFILTER_DEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS status;
PSCSI_REQUEST_BLOCK srb;
ULONG srbFunction;
ULONG srbFlags;
//
// Acquire the remove lock so that device will not be removed while
// processing this irp.
//
status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp);
if (!NT_SUCCESS(status)) {
Irp->IoStatus.Status = status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
}
srb = irpStack->Parameters.Scsi.Srb;
if (srb->Function == SRB_FUNCTION_STORAGE_REQUEST_BLOCK) {
srbFunction = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFunction;
srbFlags = ((PSTORAGE_REQUEST_BLOCK)srb)->SrbFlags;
} else {
srbFunction = srb->Function;
srbFlags = srb->SrbFlags;
}
if (srbFunction == SRB_FUNCTION_EXECUTE_SCSI) {
if (srbFlags & SRB_FLAGS_UNSPECIFIED_DIRECTION) {
// ...
// filter processing for SRB_FUNCTION_EXECUTE_SCSI
// ...
}
}
IoMarkIrpPending(Irp);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
FilterScsiIrpCompletion,
DeviceExtension->DeviceObject,
TRUE, TRUE, TRUE);
IoCallDriver(DeviceExtension->TargetDeviceObject, Irp);
return STATUS_PENDING;
}
Configurando solicitações
Como um driver de classe de armazenamento, um SFD pode ter rotinas BuildRequest ou SplitTransferRequest para ser chamado das rotinas de Expedição do driver ou pode implementar a mesma funcionalidade embutida.
Para obter mais informações sobre as rotinas BuildRequest e SplitTransferRequest , consulte Drivers de classe de armazenamento. Para obter mais informações sobre os requisitos gerais para rotinas de expedição , consulte Escrevendo rotinas de expedição.