Routine SplitTransferRequest du pilote de classe de stockage
Les données STORAGE_ADAPTER_DESCRIPTOR retournées à la routine GetDescriptor indiquent les fonctionnalités de transfert d’un HBA donné vers le pilote de classe. En particulier, ces données indiquent la valeur MaximumTransferLength en octets et la valeur MaximumPhysicalPages: c’est-à-dire le nombre de pages non incohérentes que l’adaptateur HBA peut gérer dans la mémoire physique qui sauvegarde une mémoire tampon système (c’est-à-dire l’étendue de sa prise en charge des points/regroupements).
La plupart des pilotes de classe stockent un pointeur vers ces données de configuration dans l’extension de périphérique de chaque objet de périphérique, car les pilotes de classe de stockage sont chargés de fractionner toutes les demandes de transfert qui dépassent la capacité du HBA à transférer des données. En d’autres termes, la routine DispatchReadWrite d’un pilote de classe doit déterminer si chaque IRP demande un transfert supérieur à ce que le HBA peut gérer en une seule opération de transfert.
Par exemple, une telle routine DispatchReadWrite peut avoir un code similaire à ce qui suit :
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;
}
: :
Le pilote de classe ne peut pas indiquer le nombre d’interruptions physiques que la mémoire tampon aura une fois qu’elle a été mappée. Il doit donc supposer que chaque page du transfert est discontiguante et comparer le nombre de pages par rapport au nombre d’interruptions physiques autorisées.
Notez que la routine DispatchReadWrite d’un tel pilote appelle IoMarkIrpPending et retourne STATUS_PENDING immédiatement après un appel à sa routine SplitTransferRequest avec l’IRP d’origine.
Pour effectuer la demande de transfert d’origine, la routine SplitTransferRequest du pilote crée un ou plusieurs IRP pour gérer les sous-coffres dimensionnés en fonction des fonctionnalités de l’adaptateur HBA. Pour chaque IRP de ce type, la routine SplitTransferRequest :
Configure un SRB, généralement en appelant une routine BuildRequest interne (consultez Routine BuildRequest du pilote de classe de stockage)
Copie l’adresse MDL de l’IRP d’origine vers la nouvelle IRP
Définit le DataBuffer dans le SRB sur un décalage en octets dans la MDL pour cette partie du transfert
Configure sa routine IoCompletion avant d’envoyer l’IRP au pilote de port avec IoCallDriver
Pour suivre chaque élément du transfert, SplitTransferRequest enregistre une routine IoCompletion pour chaque IRP alloué au pilote qu’elle envoie au pilote inférieur suivant. La routine IoCompletion gère un nombre de demandes de transfert partiel terminées dans l’IRP d’origine, en utilisant InterlockedIncrement et InterlockedDecrement pour garantir l’exactitude du nombre.
Une telle routine IoCompletion doit libérer tous les IRP et/ou SDR que le pilote a alloués et doit terminer l’IRP d’origine lorsque toutes les données demandées ont été transférées ou lorsque le pilote de classe a épuisé les nouvelles tentatives de l’IRP et doit l’échouer en raison d’erreurs de transfert d’appareil.