Compartir a través de


Rutina SplitTransferRequest del controlador de clase storage

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 repartir cada una de las solicitudes de transferencia que superan la capacidad del HBA para transferir datos. En otras palabras, la rutina DispatchReadWrite de un controlador de clase debe determinar si cada IRP solicita una transferencia que sea más que la HBA puede controlar en una sola operación de transferencia.

Por ejemplo, esta 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 ha asignado, por lo que debe suponer que cada página de la transferencia es discontinua y comparar el número de páginas contra el número de saltos físicos permitidos.

Tenga en cuenta que la rutina DispatchReadWrite de un controlador invoca 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 los subbúferes de tamaño que se ajusten a las capacidades del HBA. Para cada IRP de este tipo, la rutina SplitTransferRequest :

  • Configura una 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 al nuevo IRP

  • Establece DataBuffer en el SRB en un desplazamiento en bytes dentro del MDL para esta parte de la transferencia.

  • Configura su rutina 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 haya asignado el controlador y debe completar el IRP original cuando se hayan transferido todos los datos solicitados, o debe fallarlo cuando el controlador de clase haya agotado los reintentos del IRP debido a errores de transferencia del dispositivo.