Rutina SplitTransferRequest del controlador de clase de almacenamiento
Los datos STORAGE_ADAPTER_DESCRIPTOR devueltos a la rutina GetDescriptor indican las funcionalidades de transferencia de un HBA determinado al controlador de clase. En concreto, estos datos indican maximumTransferLength en bytes y MaximumPhysicalPages: es decir, cuántas páginas no contiguas puede administrar el HBA en la memoria física que respalda un búfer del sistema (es decir, la extensión de su compatibilidad de dispersión/recopilación).
La mayoría de los controladores de clase almacenan un puntero a estos datos de configuración en la extensión de dispositivo de cada objeto de dispositivo porque los controladores de clase de almacenamiento son responsables de dividir todas las solicitudes de transferencia que superan la capacidad de HBA para transferir datos. En otras palabras, la rutina DispatchReadWrite de un controlador de clase debe determinar si cada IRP solicita una transferencia más que el HBA puede controlar en una sola operación de transferencia.
Por ejemplo, una rutina DispatchReadWrite podría tener código similar al siguiente:
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;
}
: :
El controlador de clase no puede indicar cuántos saltos físicos tendrá el búfer una vez que se haya asignado, por lo que debe suponer que cada página de la transferencia es desconcertante y compara el número de páginas con el número de saltos físicos permitidos.
Tenga en cuenta que la rutina DispatchReadWrite de un controlador llama a IoMarkIrpPending y devuelve STATUS_PENDING inmediatamente después de una llamada a su rutina SplitTransferRequest con el IRP original.
Para llevar a cabo la solicitud de transferencia original, la rutina SplitTransferRequest del controlador crea uno o varios IRP para controlar subbuffers de tamaño que se ajusten a las capacidades del HBA. Para cada IRP, la rutina SplitTransferRequest :
Configura un SRB, normalmente mediante una llamada a una rutina BuildRequest interna (consulte La rutina BuildRequest del controlador de clase de almacenamiento).
Copia la dirección MDL del IRP original en el nuevo IRP
Establece dataBuffer en el SRB en un desplazamiento en bytes en la MDL para esta parte de la transferencia.
Configura su rutina de IoCompletion antes de enviar el IRP al controlador de puerto con IoCallDriver.
Para realizar un seguimiento de cada parte de la transferencia, SplitTransferRequest registra una rutina de IoCompletion para cada IRP asignado por el controlador que envía al controlador inferior siguiente. La rutina IoCompletion mantiene un recuento de solicitudes de transferencia parcial completadas en el IRP original, mediante InterlockedIncrement e InterlockedDecrement para asegurarse de que el recuento es preciso.
Esta rutina de IoCompletion debe liberar cualquier IRP o SRB que el controlador haya asignado y debe completar el IRP original cuando se hayan transferido todos los datos solicitados o cuando el controlador de clase haya agotado los reintentos del IRP y debe fallar debido a errores de transferencia de dispositivos.