Bagikan melalui


Rutinitas SplitTransferRequest Driver Kelas Penyimpanan

Data STORAGE_ADAPTER_DESCRIPTOR yang dikembalikan ke rutinitas GetDescriptor menunjukkan kemampuan transfer HBA tertentu ke driver kelas. Secara khusus, data ini menunjukkan MaximumTransferLength dalam byte dan MaximumPhysicalPages: yaitu, berapa banyak halaman yang tidak berdekatan yang dapat dikelola HBA dalam memori fisik yang mendukung buffer sistem (yaitu, tingkat dukungannya yang menyebar/mengumpulkan).

Sebagian besar driver kelas menyimpan pointer ke data konfigurasi ini di ekstensi perangkat setiap objek perangkat karena driver kelas penyimpanan bertanggung jawab untuk membagi semua permintaan transfer yang melebihi kemampuan HBA untuk mentransfer data. Dengan kata lain, rutinitas DispatchReadWrite driver kelas harus menentukan apakah setiap IRP meminta transfer yang lebih dari yang dapat ditangani HBA dalam satu operasi transfer.

Misalnya, rutinitas DispatchReadWrite seperti itu dapat memiliki kode yang mirip dengan yang berikut:

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

Driver kelas tidak dapat memberi tahu berapa banyak pemutusan fisik yang akan dilakukan buffer setelah dipetakan, jadi harus berasumsi bahwa setiap halaman dalam transfer tidak bersifat tidak berdosa dan membandingkan jumlah halaman dengan jumlah jeda fisik yang diizinkan.

Perhatikan bahwa rutinitas DispatchReadWrite driver seperti itu memanggil IoMarkIrpPending dan mengembalikan STATUS_PENDING segera setelah panggilan ke rutinitas SplitTransferRequest dengan IRP asli.

Untuk melakukan permintaan transfer asli, rutinitas SplitTransferRequest driver membuat satu atau beberapa RUNP untuk menangani subbuffer yang berukuran sesuai dengan kemampuan HBA. Untuk setiap IRP tersebut, rutinitas SplitTransferRequest :

  • Menyiapkan SRB, biasanya dengan memanggil rutinitas BuildRequest internal (lihat Rutinitas BuildRequest Driver Kelas Penyimpanan)

  • Menyalin alamat MDL dari IRP asli ke IRP baru

  • Mengatur DataBuffer di SRB ke offset dalam byte ke MDL untuk bagian transfer ini

  • Menyiapkan rutinitas IoCompletion sebelum mengirim IRP ke driver port dengan IoCallDriver

Untuk melacak setiap bagian transfer, SplitTransferRequest mendaftarkan rutinitas IoCompletion untuk setiap IRP yang dialokasikan driver yang dikirim ke driver berikutnya yang lebih rendah. Rutinitas IoCompletion mempertahankan hitungan permintaan transfer parsial yang selesai di IRP asli, menggunakan InterlockedIncrement dan InterlockedDecrement untuk memastikan bahwa jumlahnya akurat.

Rutinitas IoCompletion semacam itu harus membebaskan IRP dan/atau SRB yang telah dialokasikan driver dan harus menyelesaikan IRP asli ketika semua data yang diminta telah ditransfer atau ketika driver kelas telah kelelahan mencoba kembali IRP dan harus gagal karena kesalahan transfer perangkat.