Udostępnij przez


Procedura SplitTransferRequest sterownika klasy pamięci

Dane STORAGE_ADAPTER_DESCRIPTOR zwrócone procedurze GetDescriptor informują o możliwościach transferu danej karty HBA do sterownika klasy urządzeń. W szczególności te dane wskazują MaximumTransferLength w bajtach i MaximumPhysicalPages: czyli liczbę stron nieciągłych, którymi karta HBA może zarządzać w pamięci fizycznej obsługującej bufor systemowy (tj. zakres jego obsługi scatter/gather).

Większość sterowników klasy magazynu przechowuje wskaźnik do danych konfiguracji w rozszerzeniu każdego obiektu urządzenia, ponieważ są one odpowiedzialne za dzielenie wszystkich żądań transferu, które przekraczają możliwości przełącznika HBA w zakresie transferu danych. Innymi słowy, procedura DispatchReadWrite sterownika klasy musi określić, czy każdy IRP żąda transferu przekraczającego możliwości HBA w ramach pojedynczej operacji transferu.

Na przykład taka rutyna DispatchReadWrite może mieć kod podobny do następującego:

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; 
} 
    :        : 

Sterownik klasy nie jest w stanie stwierdzić, ile podziałów fizycznych bufor będzie miał po zmapowaniu, więc należy założyć, że każda strona w transferze jest nieciągła i należy porównać liczbę stron z dozwoloną liczbą podziałów fizycznych.

Należy pamiętać, że taka procedura DispatchReadWrite sterownika wywołuje metodę IoMarkIrpPending i zwraca STATUS_PENDING natychmiast po wywołaniu procedury SplitTransferRequest z oryginalnym IRP.

Aby zrealizować pierwotne żądanie transferu, procedura SplitTransferRequest sterownika tworzy co najmniej jeden IRP do obsługi podbuforów, dostosowanych do możliwości HBA. Dla każdego takiego IRP, procedura SplitTransferRequest:

  • Konfiguruje SRB, zwykle przez wywołanie wewnętrznej procedury BuildRequest (zobacz Procedura BuildRequest sterownika klasy magazynowej)

  • Kopiuje adres MDL z oryginalnego IRP do nowego IRP

  • Ustawia wartość dataBuffer w SRB na przesunięcie w bajtach do MDL dla tego fragmentu transferu

  • Konfiguruje procedurę IoCompletion przed wysłaniem protokołu IRP do sterownika portu za pomocą usługi IoCallDriver

Aby śledzić każdy element transferu, SplitTransferRequest rejestruje procedurę IoCompletion dla każdego IRP przydzielonego przez sterownik, który jest wysyłany do kolejnego niższego sterownika. Rutyna IoCompletion utrzymuje licznik ukończonych częściowych żądań transferu w oryginalnym IRP, używając InterlockedIncrement i InterlockedDecrement, aby zapewnić, że liczba jest dokładna.

Taka procedura IoCompletion musi zwolnić wszystkie IRPs i/lub SRBs przydzielone przez sterownik i musi ukończyć oryginalny IRP, gdy wszystkie żądane dane zostały przesłane lub gdy sterownik klasy wyczerpał próby ponownego przesłania IRP i musi zakończyć zadanie IRP niepowodzeniem z powodu błędów przesyłu danych urządzenia.