📄 class2.c
字号:
NTSTATUS
STDCALL
ScsiClassGetCapabilities(
IN PDEVICE_OBJECT PortDeviceObject,
OUT PIO_SCSI_CAPABILITIES *PortCapabilities
)
/*++
Routine Description:
This routine builds and sends a request to the port driver to
get a pointer to a structure that describes the adapter's
capabilities/limitations. This routine is sychronous.
Arguments:
PortDeviceObject - Port driver device object representing the HBA.
PortCapabilities - Location to store pointer to capabilities structure.
Return Value:
Nt status indicating the results of the operation.
Notes:
This routine should only be called at initialization time.
--*/
{
PIRP irp;
IO_STATUS_BLOCK ioStatus;
KEVENT event;
NTSTATUS status;
PAGED_CODE();
//
// Create notification event object to be used to signal the
// request completion.
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// Build the synchronous request to be sent to the port driver
// to perform the request.
//
irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_CAPABILITIES,
PortDeviceObject,
NULL,
0,
PortCapabilities,
sizeof(PVOID),
FALSE,
&event,
&ioStatus);
if (irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Pass request to port driver and wait for request to complete.
//
status = IoCallDriver(PortDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
return(ioStatus.Status);
}
return status;
} // end ScsiClassGetCapabilities()
NTSTATUS
STDCALL
ScsiClassGetInquiryData(
IN PDEVICE_OBJECT PortDeviceObject,
OUT PSCSI_ADAPTER_BUS_INFO *ConfigInfo
)
/*++
Routine Description:
This routine sends a request to a port driver to return
configuration information. Space for the information is
allocated by this routine. The caller is responsible for
freeing the configuration information. This routine is
synchronous.
Arguments:
PortDeviceObject - Port driver device object representing the HBA.
ConfigInfo - Returns a pointer to the configuration information.
Return Value:
Nt status indicating the results of the operation.
Notes:
This routine should be called only at initialization time.
--*/
{
PIRP irp;
IO_STATUS_BLOCK ioStatus;
KEVENT event;
NTSTATUS status;
PSCSI_ADAPTER_BUS_INFO buffer;
PAGED_CODE();
buffer = ExAllocatePool(PagedPool, INQUIRY_DATA_SIZE);
*ConfigInfo = buffer;
if (buffer == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
//
// Create notification event object to be used to signal the inquiry
// request completion.
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
//
// Build the synchronous request to be sent to the port driver
// to perform the inquiries.
//
irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_INQUIRY_DATA,
PortDeviceObject,
NULL,
0,
buffer,
INQUIRY_DATA_SIZE,
FALSE,
&event,
&ioStatus);
if (irp == NULL) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
//
// Pass request to port driver and wait for request to complete.
//
status = IoCallDriver(PortDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Suspended, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
if (!NT_SUCCESS(status)) {
//
// Free the buffer on an error.
//
ExFreePool(buffer);
*ConfigInfo = NULL;
}
return status;
} // end ScsiClassGetInquiryData()
NTSTATUS
STDCALL
ScsiClassReadDriveCapacity(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine sends a READ CAPACITY to the requested device, updates
the geometry information in the device object and returns
when it is complete. This routine is synchronous.
Arguments:
DeviceObject - Supplies a pointer to the device object that represents
the device whose capacity is to be read.
Return Value:
Status is returned.
--*/
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
ULONG retries = 1;
ULONG lastSector;
PCDB cdb;
PREAD_CAPACITY_DATA readCapacityBuffer;
SCSI_REQUEST_BLOCK srb;
NTSTATUS status;
//
// Allocate read capacity buffer from nonpaged pool.
//
readCapacityBuffer = ExAllocatePool(NonPagedPoolCacheAligned,
sizeof(READ_CAPACITY_DATA));
if (!readCapacityBuffer) {
return(STATUS_INSUFFICIENT_RESOURCES);
}
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
//
// Build the read capacity CDB.
//
srb.CdbLength = 10;
cdb = (PCDB)srb.Cdb;
//
// Set timeout value from device extension.
//
srb.TimeOutValue = deviceExtension->TimeOutValue;
cdb->CDB10.OperationCode = SCSIOP_READ_CAPACITY;
Retry:
status = ScsiClassSendSrbSynchronous(DeviceObject,
&srb,
readCapacityBuffer,
sizeof(READ_CAPACITY_DATA),
FALSE);
if (NT_SUCCESS(status)) {
//
// Copy sector size from read capacity buffer to device extension
// in reverse byte order.
//
((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte0 =
((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte3;
((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte1 =
((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte2;
((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte2 =
((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte1;
((PFOUR_BYTE)&deviceExtension->DiskGeometry->BytesPerSector)->Byte3 =
((PFOUR_BYTE)&readCapacityBuffer->BytesPerBlock)->Byte0;
//
// Copy last sector in reverse byte order.
//
((PFOUR_BYTE)&lastSector)->Byte0 =
((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte3;
((PFOUR_BYTE)&lastSector)->Byte1 =
((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte2;
((PFOUR_BYTE)&lastSector)->Byte2 =
((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte1;
((PFOUR_BYTE)&lastSector)->Byte3 =
((PFOUR_BYTE)&readCapacityBuffer->LogicalBlockAddress)->Byte0;
//
// Calculate sector to byte shift.
//
WHICH_BIT(deviceExtension->DiskGeometry->BytesPerSector, deviceExtension->SectorShift);
DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Sector size is %d\n",
deviceExtension->DiskGeometry->BytesPerSector));
DebugPrint((2,"SCSI ScsiClassReadDriveCapacity: Number of Sectors is %d\n",
lastSector + 1));
//
// Calculate media capacity in bytes.
//
deviceExtension->PartitionLength.QuadPart = (LONGLONG)(lastSector + 1);
//
// Calculate number of cylinders.
//
deviceExtension->DiskGeometry->Cylinders.QuadPart = (LONGLONG)((lastSector + 1)/(32 * 64));
deviceExtension->PartitionLength.QuadPart =
(deviceExtension->PartitionLength.QuadPart << deviceExtension->SectorShift);
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
//
// This device supports removable media.
//
deviceExtension->DiskGeometry->MediaType = RemovableMedia;
} else {
//
// Assume media type is fixed disk.
//
deviceExtension->DiskGeometry->MediaType = FixedMedia;
}
//
// Assume sectors per track are 32;
//
deviceExtension->DiskGeometry->SectorsPerTrack = 32;
//
// Assume tracks per cylinder (number of heads) is 64.
//
deviceExtension->DiskGeometry->TracksPerCylinder = 64;
}
if (status == STATUS_VERIFY_REQUIRED) {
//
// Routine ScsiClassSendSrbSynchronous does not retry
// requests returned with this status.
// Read Capacities should be retried
// anyway.
//
if (retries--) {
//
// Retry request.
//
goto Retry;
}
}
if (!NT_SUCCESS(status)) {
//
// If the read capacity fails, set the geometry to reasonable parameter
// so things don't fail at unexpected places. Zero the geometry
// except for the bytes per sector and sector shift.
//
RtlZeroMemory(deviceExtension->DiskGeometry, sizeof(DISK_GEOMETRY));
deviceExtension->DiskGeometry->BytesPerSector = 512;
deviceExtension->SectorShift = 9;
deviceExtension->PartitionLength.QuadPart = (LONGLONG) 0;
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
//
// This device supports removable media.
//
deviceExtension->DiskGeometry->MediaType = RemovableMedia;
} else {
//
// Assume media type is fixed disk.
//
deviceExtension->DiskGeometry->MediaType = FixedMedia;
}
}
//
// Deallocate read capacity buffer.
//
ExFreePool(readCapacityBuffer);
return status;
} // end ScsiClassReadDriveCapacity()
VOID
STDCALL
ScsiClassReleaseQueue(
IN PDEVICE_OBJECT DeviceObject
)
/*++
Routine Description:
This routine issues an internal device control command
to the port driver to release a frozen queue. The call
is issued asynchronously as ScsiClassReleaseQueue will be invoked
from the IO completion DPC (and will have no context to
wait for a synchronous call to complete).
Arguments:
DeviceObject - The device object for the logical unit with
the frozen queue.
Return Value:
None.
--*/
{
PIO_STACK_LOCATION irpStack;
PIRP irp;
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PCOMPLETION_CONTEXT context;
PSCSI_REQUEST_BLOCK srb;
KIRQL currentIrql;
//
// Allocate context from nonpaged pool.
//
context = ExAllocatePool(NonPagedPoolMustSucceed,
sizeof(COMPLETION_CONTEXT));
//
// Save the device object in the context for use by the completion
// routine.
//
context->DeviceObject = DeviceObject;
srb = &context->Srb;
//
// Zero out srb.
//
RtlZeroMemory(srb, SCSI_REQUEST_BLOCK_SIZE);
//
// Write length to SRB.
//
srb->Length = SCSI_REQUEST_BLOCK_SIZE;
//
// Set up SCSI bus address.
//
srb->PathId = deviceExtension->PathId;
srb->TargetId = deviceExtension->TargetId;
srb->Lun = deviceExtension->Lun;
//
// If this device is removable then flush the queue. This will also
// release it.
//
if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
srb->Function = SRB_FUNCTION_FLUSH_QUEUE;
} else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -