📄 diskwmi.c
字号:
{
PSRB_IO_CONTROL srbControl;
NTSTATUS status;
PSENDCMDINPARAMS sendCmdInParams;
ULONG logSize, bufferSize;
PAGED_CODE();
logSize = SectorCount * SMART_LOG_SECTOR_SIZE;
bufferSize = sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDINPARAMS) - 1 +
logSize;
srbControl = ExAllocatePoolWithTag(NonPagedPool,
bufferSize,
DISK_TAG_SMART);
if (srbControl != NULL)
{
sendCmdInParams = (PSENDCMDINPARAMS)((PUCHAR)srbControl +
sizeof(SRB_IO_CONTROL));
RtlCopyMemory(&sendCmdInParams->bBuffer[0],
Buffer,
logSize);
status = DiskPerformSmartCommand(FdoExtension,
IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG,
SMART_CMD,
SMART_WRITE_LOG,
SectorCount,
LogAddress,
srbControl,
&bufferSize);
ExFreePool(srbControl);
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
return(status);
}
NTSTATUS
DiskPerformSmartCommand(
IN PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
IN ULONG SrbControlCode,
IN UCHAR Command,
IN UCHAR Feature,
IN UCHAR SectorCount,
IN UCHAR SectorNumber,
IN OUT PSRB_IO_CONTROL SrbControl,
OUT PULONG BufferSize
)
/*++
Routine Description:
This routine will perform some SMART command
Arguments:
FdoExtension is the FDO device extension
SrbControlCode is the SRB control code to use for the request
Command is the SMART command to be executed. It may be SMART_CMD or
ID_CMD.
Feature is the value to place in the IDE feature register.
SectorCount is the value to place in the IDE SectorCount register
SrbControl is the buffer used to build the SRB_IO_CONTROL and pass
any input parameters. It also returns the output parameters.
*BufferSize on entry has total size of SrbControl and on return has
the size used in SrbControl.
Return Value:
status
--*/
{
PCOMMON_DEVICE_EXTENSION commonExtension = (PCOMMON_DEVICE_EXTENSION)FdoExtension;
PDISK_DATA diskData = (PDISK_DATA)(commonExtension->DriverData);
PUCHAR buffer;
PSENDCMDINPARAMS cmdInParameters;
PSENDCMDOUTPARAMS cmdOutParameters;
ULONG outBufferSize;
NTSTATUS status;
ULONG availableBufferSize;
KEVENT event;
PIRP irp;
IO_STATUS_BLOCK ioStatus;
SCSI_REQUEST_BLOCK srb;
LARGE_INTEGER startingOffset;
ULONG length;
PIO_STACK_LOCATION irpStack;
PAGED_CODE();
//
// Point to the 'buffer' portion of the SRB_CONTROL and compute how
// much room we have left in the srb control
//
buffer = (PUCHAR)SrbControl;
(ULONG_PTR)buffer += sizeof(SRB_IO_CONTROL);
cmdInParameters = (PSENDCMDINPARAMS)buffer;
cmdOutParameters = (PSENDCMDOUTPARAMS)buffer;
availableBufferSize = *BufferSize - sizeof(SRB_IO_CONTROL);
#if DBG
//
// Ensure control codes and buffer lengths passed are correct
//
{
ULONG controlCode;
ULONG lengthNeeded = sizeof(SENDCMDINPARAMS) - 1;
if (Command == SMART_CMD)
{
switch (Feature)
{
case ENABLE_SMART:
{
controlCode = IOCTL_SCSI_MINIPORT_ENABLE_SMART;
break;
}
case DISABLE_SMART:
{
controlCode = IOCTL_SCSI_MINIPORT_DISABLE_SMART;
break;
}
case RETURN_SMART_STATUS:
{
//
// Ensure bBuffer is at least 2 bytes (to hold the values of
// cylinderLow and cylinderHigh).
//
lengthNeeded = sizeof(SENDCMDINPARAMS) - 1 + sizeof(IDEREGS);
controlCode = IOCTL_SCSI_MINIPORT_RETURN_STATUS;
break;
}
case ENABLE_DISABLE_AUTOSAVE:
{
controlCode = IOCTL_SCSI_MINIPORT_ENABLE_DISABLE_AUTOSAVE;
break;
}
case SAVE_ATTRIBUTE_VALUES:
{
controlCode = IOCTL_SCSI_MINIPORT_SAVE_ATTRIBUTE_VALUES;
break;
}
case EXECUTE_OFFLINE_DIAGS:
{
controlCode = IOCTL_SCSI_MINIPORT_EXECUTE_OFFLINE_DIAGS;
break;
}
case READ_ATTRIBUTES:
{
controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_ATTRIBS;
lengthNeeded = READ_ATTRIBUTE_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS) - 1;
break;
}
case READ_THRESHOLDS:
{
controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_THRESHOLDS;
lengthNeeded = READ_THRESHOLD_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS) - 1;
break;
}
case SMART_READ_LOG:
{
controlCode = IOCTL_SCSI_MINIPORT_READ_SMART_LOG;
lengthNeeded = (SectorCount * SMART_LOG_SECTOR_SIZE) +
sizeof(SENDCMDINPARAMS) - 1;
break;
}
case SMART_WRITE_LOG:
{
controlCode = IOCTL_SCSI_MINIPORT_WRITE_SMART_LOG;
lengthNeeded = (SectorCount * SMART_LOG_SECTOR_SIZE) +
sizeof(SENDCMDINPARAMS) - 1;
break;
}
}
} else if (Command == ID_CMD) {
controlCode = IOCTL_SCSI_MINIPORT_IDENTIFY;
lengthNeeded = IDENTIFY_BUFFER_SIZE + sizeof(SENDCMDOUTPARAMS) -1;
} else {
ASSERT(FALSE);
}
ASSERT(controlCode == SrbControlCode);
ASSERT(availableBufferSize >= lengthNeeded);
}
#endif
//
// Build SrbControl and input to SMART command
//
SrbControl->HeaderLength = sizeof(SRB_IO_CONTROL);
RtlMoveMemory (SrbControl->Signature, "SCSIDISK", 8);
SrbControl->Timeout = FdoExtension->TimeOutValue;
SrbControl->Length = availableBufferSize;
SrbControl->ControlCode = SrbControlCode;
cmdInParameters->cBufferSize = sizeof(SENDCMDINPARAMS);
cmdInParameters->bDriveNumber = diskData->ScsiAddress.TargetId;
cmdInParameters->irDriveRegs.bFeaturesReg = Feature;
cmdInParameters->irDriveRegs.bSectorCountReg = SectorCount;
cmdInParameters->irDriveRegs.bSectorNumberReg = SectorNumber;
cmdInParameters->irDriveRegs.bCylLowReg = SMART_CYL_LOW;
cmdInParameters->irDriveRegs.bCylHighReg = SMART_CYL_HI;
cmdInParameters->irDriveRegs.bCommandReg = Command;
//
// Create and send irp
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
startingOffset.QuadPart = (LONGLONG) 1;
length = SrbControl->HeaderLength + SrbControl->Length;
irp = IoBuildSynchronousFsdRequest(
IRP_MJ_SCSI,
commonExtension->LowerDeviceObject,
SrbControl,
length,
&startingOffset,
&event,
&ioStatus);
if (irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
irpStack = IoGetNextIrpStackLocation(irp);
//
// Set major and minor codes.
//
irpStack->MajorFunction = IRP_MJ_SCSI;
irpStack->MinorFunction = 1;
//
// Fill in SRB fields.
//
irpStack->Parameters.Others.Argument1 = &srb;
//
// Zero out the srb.
//
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
srb.PathId = diskData->ScsiAddress.PathId;
srb.TargetId = diskData->ScsiAddress.TargetId;
srb.Lun = diskData->ScsiAddress.Lun;
srb.Function = SRB_FUNCTION_IO_CONTROL;
srb.Length = sizeof(SCSI_REQUEST_BLOCK);
srb.SrbFlags = FdoExtension->SrbFlags;
SET_FLAG(srb.SrbFlags, SRB_FLAGS_DATA_IN);
SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_QUEUE_FREEZE);
SET_FLAG(srb.SrbFlags, SRB_FLAGS_NO_KEEP_AWAKE);
srb.QueueAction = SRB_SIMPLE_TAG_REQUEST;
srb.QueueTag = SP_UNTAGGED;
srb.OriginalRequest = irp;
//
// Set timeout to requested value.
//
srb.TimeOutValue = SrbControl->Timeout;
//
// Set the data buffer.
//
srb.DataBuffer = SrbControl;
srb.DataTransferLength = length;
//
// Flush the data buffer for output. This will insure that the data is
// written back to memory. Since the data-in flag is the the port driver
// will flush the data again for input which will ensure the data is not
// in the cache.
//
KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
//
// Call port driver to handle this request.
//
status = IoCallDriver(commonExtension->LowerDeviceObject, irp);
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
return status;
}
NTSTATUS
DiskGetIdentifyInfo(
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
PBOOLEAN SupportSmart
)
{
UCHAR outBuffer[sizeof(SRB_IO_CONTROL) + (sizeof(SENDCMDINPARAMS)-1) + IDENTIFY_BUFFER_SIZE];
ULONG outBufferSize = sizeof(outBuffer);
NTSTATUS status;
PAGED_CODE();
status = DiskGetIdentifyData(FdoExtension,
(PSRB_IO_CONTROL)outBuffer,
&outBufferSize);
if (NT_SUCCESS(status))
{
PUSHORT identifyData = (PUSHORT)&(outBuffer[sizeof(SRB_IO_CONTROL) + sizeof(SENDCMDOUTPARAMS)-1]);
USHORT commandSetSupported = identifyData[82];
*SupportSmart = ((commandSetSupported != 0xffff) &&
(commandSetSupported != 0) &&
((commandSetSupported & 1) == 1));
} else {
*SupportSmart = FALSE;
}
DebugPrint((3, "DiskGetIdentifyInfo: SMART %s supported for device %p, status %lx\n",
*SupportSmart ? "is" : "is not",
FdoExtension->DeviceObject,
status));
return status;
}
//
// FP Ioctl specific routines
//
NTSTATUS
DiskSendFailurePredictIoctl(
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
PSTORAGE_PREDICT_FAILURE checkFailure
)
{
KEVENT event;
PDEVICE_OBJECT deviceObject;
IO_STATUS_BLOCK ioStatus;
PIRP irp;
NTSTATUS status;
PAGED_CODE();
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
deviceObject = IoGetAttachedDeviceReference(FdoExtension->DeviceObject);
irp = IoBuildDeviceIoControlRequest(
IOCTL_STORAGE_PREDICT_FAILURE,
deviceObject,
NULL,
0,
checkFailure,
sizeof(STORAGE_PREDICT_FAILURE),
FALSE,
&event,
&ioStatus);
if (irp != NULL)
{
status = IoCallDriver(deviceObject, irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
} else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
ObDereferenceObject(deviceObject);
return status;
}
//
// FP type independent routines
//
NTSTATUS
DiskEnableDisableFailurePrediction(
PFUNCTIONAL_DEVICE_EXTENSION FdoExtension,
BOOLEAN Enable
)
/*++
Routine Description:
Enable or disable failure prediction at the hardware level
Arguments:
FdoExtension
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -