Routine SplitTransferRequest del driver della classe di archiviazione

I dati STORAGE_ADAPTER_DESCRIPTOR restituiti alla routine GetDescriptor indicano 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 nella memoria fisica che supporta 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 maggiore di quello che l'HBA può gestire in una singola operazione di trasferimento.

Ad esempio, una routine DispatchReadWrite di questo tipo 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 discontigua e confrontare il numero di pagine rispetto al numero di interruzioni fisiche consentite.

Si noti che la routine DispatchReadWrite di un driver di questo tipo 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 subbuffer ridimensionati in base alle funzionalità dell'HBA. Per ogni tale IRP, la routine SplitTransferRequest:

  • Configura un SRB, di solito chiamando una routine interna BuildRequest (vedere Routine BuildRequest del driver della classe di archiviazione)

  • Copia l'indirizzo MDL dall'IRP originale al nuovo IRP

  • Imposta DataBuffer nell'SRB su un offset in byte nell'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 parte del trasferimento, SplitTransferRequest registra una routine IoCompletion per ogni IRP allocato dal driver inviato al driver inferiore successivo. La routine IoCompletion gestisce un conteggio delle richieste di trasferimento parziale completate nell'IRP originale, usando InterlockedIncrement e InterlockedDecrement per garantire che il conteggio sia accurato.

Una routine IoCompletion di questo tipo deve liberare tutti gli IRP e/o SRB allocati dal driver e deve completare l'IRP originale quando tutti i dati richiesti sono stati trasferiti o quando il driver di classe ha esaurito i tentativi con l'IRP e deve fallire a causa di errori di trasferimento del dispositivo.