Routine SplitTransferRequest del driver di classe di archiviazione
La STORAGE_ADAPTER_DESCRIPTOR dati restituiti alla routine GetDescriptor indica le funzionalità di trasferimento di un determinato HBA al driver di classe. In particolare, questi dati indicano il valore MaximumTransferLength in byte e MaximumPhysicalPages, ovvero il numero di pagine non contigue che l'HBA può gestire nel backup fisico di un buffer di sistema, ad esempio l'estensione del supporto di dispersione/raccolta.
La maggior parte dei driver di classe archivia un puntatore a questi dati di configurazione nell'estensione del dispositivo di ogni oggetto dispositivo perché i driver della classe di archiviazione sono responsabili della suddivisione di tutte le richieste di trasferimento che superano la capacità dell'HBA di trasferire i dati. In altre parole, la routine DispatchReadWrite di un driver di classe deve determinare se ogni IRP richiede un trasferimento superiore a quello dell'HBA può gestire in una singola operazione di trasferimento.
Ad esempio, una routine DispatchReadWrite potrebbe avere codice simile al seguente:
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;
}
: :
Il driver di classe non può indicare il numero di interruzioni fisiche del buffer dopo che è stato mappato, quindi deve presupporre che ogni pagina nel trasferimento sia disconcrono e confrontare il numero di pagine rispetto al numero di interruzioni fisiche consentite.
Si noti che tale routine DispatchReadWrite di un driver chiama IoMarkIrpPending e restituisce STATUS_PENDING immediatamente dopo una chiamata alla routine SplitTransferRequest con l'IRP originale.
Per eseguire la richiesta di trasferimento originale, la routine SplitTransferRequest del driver crea uno o più IRP per gestire le sottobuffere ridimensionate per soddisfare le funzionalità dell'HBA. Per ogni IRP, la routine SplitTransferRequest :
Configura una SRB, in genere chiamando una routine BuildRequest interna (vedere La routine BuildRequest del driver di classe di archiviazione)
Copia l'indirizzo MDL dall'IRP originale al nuovo IRP
Imposta DataBuffer in SRB su un offset in byte nell'oggetto MDL per questa parte del trasferimento
Configura la routine IoCompletion prima di inviare l'IRP al driver di porta con IoCallDriver
Per tenere traccia di ogni pezzo del trasferimento, SplitTransferRequest registra una routine IoCompletion per ogni IRP allocata dal driver che invia al driver inferiore successivo. La routine IoCompletion gestisce un conteggio delle richieste di trasferimento parziale completate nell'IRP originale, usando InterlockedIncrement e InterlockedDecrement per assicurarsi che il conteggio sia accurato.
Una routine IoCompletion di questo tipo deve liberare tutti gli IRP e/o gli SRB allocati e deve completare l'IRP originale quando tutti i dati richiesti sono stati trasferiti o quando il driver di classe ha esaurito i tentativi dell'IRP e deve non riuscire a causa di errori di trasferimento del dispositivo.