SMART_RCV_DATA IOCTL and IoBuildDeviceIoControlRequest

Hi guys,
i need to retrieve unique information from an HD (i.e. serial number or
sort of). I’ve read on the list that the IOCTL to be used is
SMART_RCV_DATA, which should work even with non-SMART capable drives. So
i’ve put together this quick test code, but the IoCallDriver returns
STATUS_IO_DEVICE_ERROR (tested only on VMWare, but i doubt its a VMWare
fault). Have i missed something ?

NTSTATUS UtilGetHdInfo ()
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
UNICODE_STRING ucName;
char* pBuffer = NULL;
PIRP Irp = NULL;
SENDCMDINPARAMS SendParams;
PFILE_OBJECT FileObject = NULL;
PDEVICE_OBJECT DeviceObject = NULL;
KEVENT Event;
IO_STATUS_BLOCK Iosb;

pBuffer = ExAllocatePool(PagedPool,sizeof (SENDCMDOUTPARAMS) + 512

  • 1);
    if (!pBuffer)
    goto __exit;

// open physical disk 0 device
KdBreakPoint();
RtlInitUnicodeString(&ucName,L"\Device\Harddisk0\DR0");
Status = IoGetDeviceObjectPointer(&ucName,FILE_READ_ATTRIBUTES,
&FileObject,&DeviceObject);
if (!NT_SUCCESS (Status))
goto __exit;
ObDereferenceObject(FileObject);

// build and send irp to hd device
memset(&SendParams,0,sizeof (SENDCMDINPARAMS));
memset(pBuffer,0,sizeof (SENDCMDOUTPARAMS) + 512);
SendParams.cBufferSize = IDENTIFY_BUFFER_SIZE;
SendParams.bDriveNumber = 0;
SendParams.irDriveRegs.bFeaturesReg = 0;
SendParams.irDriveRegs.bCommandReg = ID_CMD;
SendParams.irDriveRegs.bSectorCountReg = 1;
SendParams.irDriveRegs.bSectorNumberReg = 0;
SendParams.irDriveRegs.bCylLowReg = SMART_CYL_LOW;
SendParams.irDriveRegs.bCylHighReg = SMART_CYL_HI;
SendParams.irDriveRegs.bDriveHeadReg = 0;

KeInitializeEvent(&Event,NotificationEvent,FALSE);
Irp = IoBuildDeviceIoControlRequest(SMART_RCV_DRIVE_DATA,
DeviceObject, &SendParams, sizeof(SENDCMDINPARAMS), pBuffer, sizeof
(SENDCMDOUTPARAMS) + 512,
FALSE, &Event, &Iosb);

// send command
Status = IoCallDriver(DeviceObject, Irp);

if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = Iosb.Status;
}

__exit:
if (pBuffer)
ExFreePool (pBuffer);
return Status;
}

Regards,
Valerio

Is the target an ide/atapi disk? If not I do not believe this command will
work. STATUS_IO_DEVICE_ERROR is the catch-all mapping of srb status values
to nt status values.

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of valerino
Sent: Tuesday, July 20, 2004 11:40 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] SMART_RCV_DATA IOCTL and
IoBuildDeviceIoControlRequest

Hi guys,
i need to retrieve unique information from an HD (i.e. serial
number or sort of). I’ve read on the list that the IOCTL to
be used is SMART_RCV_DATA, which should work even with
non-SMART capable drives. So i’ve put together this quick
test code, but the IoCallDriver returns
STATUS_IO_DEVICE_ERROR (tested only on VMWare, but i doubt
its a VMWare fault). Have i missed something ?

NTSTATUS UtilGetHdInfo ()
{
NTSTATUS Status = STATUS_UNSUCCESSFUL;
UNICODE_STRING ucName;
char* pBuffer = NULL;
PIRP Irp = NULL;
SENDCMDINPARAMS SendParams;
PFILE_OBJECT FileObject = NULL;
PDEVICE_OBJECT DeviceObject = NULL;
KEVENT Event;
IO_STATUS_BLOCK Iosb;

pBuffer = ExAllocatePool(PagedPool,sizeof
(SENDCMDOUTPARAMS) + 512

  • 1);
    if (!pBuffer)
    goto __exit;

// open physical disk 0 device
KdBreakPoint();
RtlInitUnicodeString(&ucName,L"\Device\Harddisk0\DR0");
Status = IoGetDeviceObjectPointer(&ucName,FILE_READ_ATTRIBUTES,
&FileObject,&DeviceObject);
if (!NT_SUCCESS (Status))
goto __exit;
ObDereferenceObject(FileObject);

// build and send irp to hd device
memset(&SendParams,0,sizeof (SENDCMDINPARAMS));
memset(pBuffer,0,sizeof (SENDCMDOUTPARAMS) + 512);
SendParams.cBufferSize = IDENTIFY_BUFFER_SIZE;
SendParams.bDriveNumber = 0;
SendParams.irDriveRegs.bFeaturesReg = 0;
SendParams.irDriveRegs.bCommandReg = ID_CMD;
SendParams.irDriveRegs.bSectorCountReg = 1;
SendParams.irDriveRegs.bSectorNumberReg = 0;
SendParams.irDriveRegs.bCylLowReg = SMART_CYL_LOW;
SendParams.irDriveRegs.bCylHighReg = SMART_CYL_HI;
SendParams.irDriveRegs.bDriveHeadReg = 0;

KeInitializeEvent(&Event,NotificationEvent,FALSE);
Irp =
IoBuildDeviceIoControlRequest(SMART_RCV_DRIVE_DATA,

DeviceObject, &SendParams, sizeof(SENDCMDINPARAMS),
pBuffer, sizeof
(SENDCMDOUTPARAMS) + 512,
FALSE, &Event, &Iosb);

// send command
Status = IoCallDriver(DeviceObject, Irp);

if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive,
KernelMode, FALSE, NULL);
Status = Iosb.Status;
}

__exit:
if (pBuffer)
ExFreePool (pBuffer);
return Status;
}

Regards,
Valerio


Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256

You are currently subscribed to ntdev as:
xxxxx@hollistech.com To unsubscribe send a blank email to
xxxxx@lists.osr.com

Yes Mark,
it is… at least, as i said i tested it on VMWare only, so probably
there’s some quircks. Maybe the emulated disk do not support such SMART
commands ? Now i think of it, VMWare emulated disks are SCSI disks.
But should that make any difference ?

Valerio

Mark Roddy wrote:

Is the target an ide/atapi disk? If not I do not believe this command will
work. STATUS_IO_DEVICE_ERROR is the catch-all mapping of srb status values
to nt status values.

>-----Original Message-----
>From: xxxxx@lists.osr.com
>[mailto:xxxxx@lists.osr.com] On Behalf Of valerino
>Sent: Tuesday, July 20, 2004 11:40 PM
>To: Windows System Software Devs Interest List
>Subject: [ntdev] SMART_RCV_DATA IOCTL and
>IoBuildDeviceIoControlRequest
>
>Hi guys,
>i need to retrieve unique information from an HD (i.e. serial
>number or sort of). I’ve read on the list that the IOCTL to
>be used is SMART_RCV_DATA, which should work even with
>non-SMART capable drives. So i’ve put together this quick
>test code, but the IoCallDriver returns
>STATUS_IO_DEVICE_ERROR (tested only on VMWare, but i doubt
>its a VMWare fault). Have i missed something ?
>
>NTSTATUS UtilGetHdInfo ()
>{
> NTSTATUS Status = STATUS_UNSUCCESSFUL;
> UNICODE_STRING ucName;
> char* pBuffer = NULL;
> PIRP Irp = NULL;
> SENDCMDINPARAMS SendParams;
> PFILE_OBJECT FileObject = NULL;
> PDEVICE_OBJECT DeviceObject = NULL;
> KEVENT Event;
> IO_STATUS_BLOCK Iosb;
>
> pBuffer = ExAllocatePool(PagedPool,sizeof
>(SENDCMDOUTPARAMS) + 512
>+ 1);
> if (!pBuffer)
> goto __exit;
>
> // open physical disk 0 device
> KdBreakPoint();
> RtlInitUnicodeString(&ucName,L"\Device\Harddisk0\DR0");
> Status = IoGetDeviceObjectPointer(&ucName,FILE_READ_ATTRIBUTES,
> &FileObject,&DeviceObject);
> if (!NT_SUCCESS (Status))
> goto __exit;
> ObDereferenceObject(FileObject);
>
> // build and send irp to hd device
> memset(&SendParams,0,sizeof (SENDCMDINPARAMS));
> memset(pBuffer,0,sizeof (SENDCMDOUTPARAMS) + 512);
> SendParams.cBufferSize = IDENTIFY_BUFFER_SIZE;
> SendParams.bDriveNumber = 0;
> SendParams.irDriveRegs.bFeaturesReg = 0;
> SendParams.irDriveRegs.bCommandReg = ID_CMD;
> SendParams.irDriveRegs.bSectorCountReg = 1;
> SendParams.irDriveRegs.bSectorNumberReg = 0;
> SendParams.irDriveRegs.bCylLowReg = SMART_CYL_LOW;
> SendParams.irDriveRegs.bCylHighReg = SMART_CYL_HI;
> SendParams.irDriveRegs.bDriveHeadReg = 0;
>
> KeInitializeEvent(&Event,NotificationEvent,FALSE);
> Irp =
>IoBuildDeviceIoControlRequest(SMART_RCV_DRIVE_DATA,
>
>DeviceObject, &SendParams, sizeof(SENDCMDINPARAMS),
> pBuffer, sizeof
>(SENDCMDOUTPARAMS) + 512,
> FALSE, &Event, &Iosb);
>
> // send command
> Status = IoCallDriver(DeviceObject, Irp);
>
> if (Status == STATUS_PENDING)
> {
> KeWaitForSingleObject(&Event, Executive,
>KernelMode, FALSE, NULL);
> Status = Iosb.Status;
> }
>
>__exit:
> if (pBuffer)
> ExFreePool (pBuffer);
> return Status;
>}
>
>Regards,
>Valerio
>
>—
>Questions? First check the Kernel Driver FAQ at
>http://www.osronline.com/article.cfm?id=256
>
>You are currently subscribed to ntdev as:
>xxxxx@hollistech.com To unsubscribe send a blank email to
>xxxxx@lists.osr.com
>

> Now i think of it, VMWare

emulated disks are SCSI disks.
But should that make any difference ?

Yeah I think it does. Maybe somebody from msft can confirm this, but I think
that smart commands, or at least specifically the smart ID command end up
being atapi/ide only. Scsiport appears to eat this stuff.

You can get the serial number off of a scsi disk using other mechanisms.

Here, try this thread:
http://groups.google.com/groups?hl=en&lr=lang_en&ie=UTF-8&safe=off&threadm=2
47007806.20040108194605%40tell.this&rnum=111&prev=/groups%3Fq%3Ddisk%2Bseria
l%2Bnumber%26hl%3Den%26lr%3Dlang_en%26ie%3DUTF-8%26safe%3Doff%26start%3D110%
26sa%3DN

If you want to do this generically then you have to be prepared to try
several methods until you find one that works, for each target of interest.

SMART_RCV_DRIVE_DATA does not send any SMART commands to the hardware. The
IOCTL is just misnamed.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

----- Original Message -----
From: “valerino”
Newsgroups: ntdev
To: “Windows System Software Devs Interest List”
Sent: Wednesday, July 21, 2004 3:46 PM
Subject: Re:[ntdev] SMART_RCV_DATA IOCTL and IoBuildDeviceIoControlRequest

> Yes Mark,
> it is… at least, as i said i tested it on VMWare only, so probably
> there’s some quircks. Maybe the emulated disk do not support such SMART
> commands ? Now i think of it, VMWare emulated disks are SCSI disks.
> But should that make any difference ?
>
> Valerio
>
>
> Mark Roddy wrote:
>
> > Is the target an ide/atapi disk? If not I do not believe this command will
> > work. STATUS_IO_DEVICE_ERROR is the catch-all mapping of srb status values
> > to nt status values.
> >
> >
> >>-----Original Message-----
> >>From: xxxxx@lists.osr.com
> >>[mailto:xxxxx@lists.osr.com] On Behalf Of valerino
> >>Sent: Tuesday, July 20, 2004 11:40 PM
> >>To: Windows System Software Devs Interest List
> >>Subject: [ntdev] SMART_RCV_DATA IOCTL and
> >>IoBuildDeviceIoControlRequest
> >>
> >>Hi guys,
> >>i need to retrieve unique information from an HD (i.e. serial
> >>number or sort of). I’ve read on the list that the IOCTL to
> >>be used is SMART_RCV_DATA, which should work even with
> >>non-SMART capable drives. So i’ve put together this quick
> >>test code, but the IoCallDriver returns
> >>STATUS_IO_DEVICE_ERROR (tested only on VMWare, but i doubt
> >>its a VMWare fault). Have i missed something ?
> >>
> >>NTSTATUS UtilGetHdInfo ()
> >>{
> >> NTSTATUS Status = STATUS_UNSUCCESSFUL;
> >> UNICODE_STRING ucName;
> >> char* pBuffer = NULL;
> >> PIRP Irp = NULL;
> >> SENDCMDINPARAMS SendParams;
> >> PFILE_OBJECT FileObject = NULL;
> >> PDEVICE_OBJECT DeviceObject = NULL;
> >> KEVENT Event;
> >> IO_STATUS_BLOCK Iosb;
> >>
> >> pBuffer = ExAllocatePool(PagedPool,sizeof
> >>(SENDCMDOUTPARAMS) + 512
> >>+ 1);
> >> if (!pBuffer)
> >> goto __exit;
> >>
> >> // open physical disk 0 device
> >> KdBreakPoint();
> >> RtlInitUnicodeString(&ucName,L"\Device\Harddisk0\DR0");
> >> Status = IoGetDeviceObjectPointer(&ucName,FILE_READ_ATTRIBUTES,
> >> &FileObject,&DeviceObject);
> >> if (!NT_SUCCESS (Status))
> >> goto__exit;
> >> ObDereferenceObject(FileObject);
> >>
> >> // build and send irp to hd device
> >> memset(&SendParams,0,sizeof (SENDCMDINPARAMS));
> >> memset(pBuffer,0,sizeof (SENDCMDOUTPARAMS) + 512);
> >> SendParams.cBufferSize = IDENTIFY_BUFFER_SIZE;
> >> SendParams.bDriveNumber = 0;
> >> SendParams.irDriveRegs.bFeaturesReg = 0;
> >> SendParams.irDriveRegs.bCommandReg = ID_CMD;
> >> SendParams.irDriveRegs.bSectorCountReg = 1;
> >> SendParams.irDriveRegs.bSectorNumberReg = 0;
> >> SendParams.irDriveRegs.bCylLowReg = SMART_CYL_LOW;
> >> SendParams.irDriveRegs.bCylHighReg = SMART_CYL_HI;
> >> SendParams.irDriveRegs.bDriveHeadReg = 0;
> >>
> >> KeInitializeEvent(&Event,NotificationEvent,FALSE);
> >> Irp =
> >>IoBuildDeviceIoControlRequest(SMART_RCV_DRIVE_DATA,
> >>
> >>DeviceObject, &SendParams, sizeof(SENDCMDINPARAMS),
> >> pBuffer, sizeof
> >>(SENDCMDOUTPARAMS) + 512,
> >> FALSE, &Event, &Iosb);
> >>
> >> // send command
> >> Status = IoCallDriver(DeviceObject, Irp);
> >>
> >> if (Status == STATUS_PENDING)
> >> {
> >> KeWaitForSingleObject(&Event, Executive,
> >>KernelMode, FALSE, NULL);
> >> Status = Iosb.Status;
> >> }
> >>
> >>__exit:
> >> if (pBuffer)
> >> ExFreePool (pBuffer);
> >> return Status;
> >>}
> >>
> >>Regards,
> >>Valerio
> >>
> >>—
> >>Questions? First check the Kernel Driver FAQ at
> >>http://www.osronline.com/article.cfm?id=256
> >>
> >>You are currently subscribed to ntdev as:
> >>xxxxx@hollistech.com To unsubscribe send a blank email to
> >>xxxxx@lists.osr.com
> >>
> >
> >
> >
> >
> >
>
> —
> Questions? First check the Kernel Driver FAQ at
http://www.osronline.com/article.cfm?id=256
>
> You are currently subscribed to ntdev as: xxxxx@storagecraft.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com

> > Now i think of it, VMWare

> emulated disks are SCSI disks.
> But should that make any difference ?

Yeah I think it does.

Surely. SMART_RCV_DRIVE_DATA is ATA-only thing which returns the drive’s
IDENTIFY data. IDENTIFY is ATA-only concept not in SCSI.

The real SMART work is possibly supported on SCSI via some mode page.

Maxim Shatskih, Windows DDK MVP
StorageCraft Corporation
xxxxx@storagecraft.com
http://www.storagecraft.com

> Yes Mark,

it is… at least, as i said i tested it on VMWare only, so probably
there’s some quircks. Maybe the emulated disk do not support
such SMART
commands ? Now i think of it, VMWare emulated disks are SCSI disks.
But should that make any difference ?

Valerio

VMware Workstation emulates SCSI and ATA (IDE) discs.
Windows NT based VMs by default get SCSI disks, but it is easy to add
an IDE disk.

Emulated disks do not support SMART commands, it doesn’t
make much sense to emulate them.

BTW, some BIOSes have an option to enable/disable SMART
reporting, so relying on SMART is not a good idea for a widely
distributed software.

Dmitriy Budko, VMware

Thanks everybody guys,
i made it work using IOCTL_STORAGE_QUERY_PROPERTY on the device
corresponding to \DosDevice\PhysicalDisk0. Works both on vmware and
real hardware.

Thanks,
Valerio