Rotina SplitTransferRequest do Driver de Classe de Armazenamento
Os dados STORAGE_ADAPTER_DESCRIPTOR retornados para a rotina GetDescriptor indicam os recursos de transferência de um determinado HBA para o driver de classe. Em particular, esses dados indicam o MaximumTransferLength em bytes e o MaximumPhysicalPages: ou seja, quantas páginas não contíguas o HBA pode gerenciar na memória física que dá suporte a um buffer do sistema (ou seja, a extensão de seu suporte de dispersão/coleta).
A maioria dos drivers de classe armazena um ponteiro para esses dados de configuração na extensão de dispositivo de cada objeto de dispositivo porque os drivers de classe de armazenamento são responsáveis por dividir todas as solicitações de transferência que excedem a capacidade do HBA de transferir dados. Em outras palavras, a rotina DispatchReadWrite de um driver de classe deve determinar se cada IRP solicita uma transferência maior do que o HBA pode manipular em uma única operação de transferência.
Por exemplo, tal rotina DispatchReadWrite pode ter um código semelhante ao seguinte:
PSTORAGE_ADAPTER_DESCRIPTOR adapterDescriptor =
commonExtension->PartitionZeroExtension->AdapterDescriptor;
ULONG transferPages;
ULONG maximumTransferLength =
adapterDescriptor->MaximumTransferLength;
: :
//
// Calculate number of pages in this transfer
//
transferPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
MmGetMdlVirtualAddress(Irp->MdlAddress),
currentIrpStack->Parameters.Read.Length);
//
// Check whether requested length is greater than the maximum number
// of bytes that can be transferred in a single operation
//
if (currentIrpStack->Parameters.Read.Length > maximumTransferLength ||
transferPages > adapterDescriptor->MaximumPhysicalPages) {
transferPages = adapterDescriptor->MaximumPhysicalPages - 1;
if (maximumTransferLength > transferPages << PAGE_SHIFT) {
maximumTransferLength = transferPages << PAGE_SHIFT;
}
IoMarkIrpPending(Irp);
SplitTransferRequest(DeviceObject,
Irp,
maximumTransferLength);
return STATUS_PENDING;
}
: :
O driver de classe não pode informar quantas quebras físicas o buffer terá depois de mapeado, portanto, ele deve assumir que cada página na transferência é discontigua e comparar o número de páginas com o número de quebras físicas permitidas.
Observe que essa rotina DispatchReadWrite de um driver chama IoMarkIrpPending e retorna STATUS_PENDING imediatamente após uma chamada para sua rotina SplitTransferRequest com o IRP original.
Para realizar a solicitação de transferência original, a rotina SplitTransferRequest do driver cria um ou mais IRPs para lidar com subbuffers dimensionados para atender aos recursos do HBA. Para cada IRP, a rotina SplitTransferRequest :
Configura um SRB, geralmente chamando uma rotina interna do BuildRequest (consulte Rotina BuildRequest do Driver de Classe de Armazenamento)
Copia o endereço MDL do IRP original para o novo IRP
Define o DataBuffer no SRB como um deslocamento em bytes para o MDL para esta parte da transferência
Configura sua rotina de IoCompletion antes de enviar o IRP para o driver de porta com IoCallDriver
Para acompanhar cada parte da transferência, SplitTransferRequest registra uma rotina IoCompletion para cada IRP alocado pelo driver que envia para o driver mais baixo. A rotina IoCompletion mantém uma contagem de solicitações de transferência parcial concluídas no IRP original, usando InterlockedIncrement e InterlockedDecrement para garantir que a contagem seja precisa.
Essa rotina de IoCompletion deve liberar todos os IRPs e/ou SRBs alocados pelo driver e deve concluir o IRP original quando todos os dados solicitados forem transferidos ou quando o driver de classe tiver esgotado as repetições do IRP e falhar devido a erros de transferência de dispositivo.