Get detailed hard disk info [updated 28/6/10]

Share your advanced PureBasic knowledge/code with the community.
Tranquil
Addict
Addict
Posts: 952
Joined: Mon Apr 28, 2003 2:22 pm
Location: Europe

Post by Tranquil »

Thanks in advance. I will take a closer look on WMI Services. Maybe SMART provides some information.
Tranquil
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Post by doctorized »

Tranquil wrote:I will take a closer look on WMI Services. Maybe SMART provides some information.
If you find anything, let me know.
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Post by doctorized »

Take a look at: http://kc2000labs.110mb.com/pb/zips/4.3 ... o_4.31.zip

I made some improvements (and changed site location, as yahoo geocities is closing).

Does anyone have SSD or Serial attached SCSI (SAS) drive to test my code?
pthien
Enthusiast
Enthusiast
Posts: 148
Joined: Sun Jun 29, 2003 9:39 pm

Re:

Post by pthien »

doctorized wrote:Take a look at: http://kc2000labs.110mb.com/pb/zips/4.3 ... o_4.31.zip

I made some improvements (and changed site location, as yahoo geocities is closing).

Does anyone have SSD or Serial attached SCSI (SAS) drive to test my code?
I downloaded this and tried it on a machine w/ SCSI. It did not detect my SCSI Jaz drive. It actually showed two of my primary SATA drives instead.

I'd like to modify the code so it can detect and report USB connected drives as well. I have a program called HDDScan 3.3 that can read SMART via USB drives. I know not all USB adapters support this, but many do.

Ultimately, I'd like a program that at boot time will check all connected drives for the reallocation parameter. Optionally maybe have it set so it checks every 5-10 minutes after that (command-line parameters) and throws-up a dialog box if a drive is reallocating. Drives that are reallocating may fail soon and it would be nice to have a program to install on machines I build that tells users their drive may be failing and should be replaced sooner rather than later.

I found some C code that uses iodevicecontrol to talk to USB devices, but it will take me FOREVER to port it to PB. I'm just not that good.

If anyone here knows how to do this quickly, I'd appreciate some code. I'll post the source for my completed project, I'm not trying to make money at this, just prevent data loss.
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Re:

Post by doctorized »

pthien wrote:I downloaded this and tried it on a machine w/ SCSI. It did not detect my SCSI Jaz drive.
Have you tried CrystalDiskInfo? Does it show your SCSI disk?
pthien
Enthusiast
Enthusiast
Posts: 148
Joined: Sun Jun 29, 2003 9:39 pm

Re: Re:

Post by pthien »

doctorized wrote:
pthien wrote:I downloaded this and tried it on a machine w/ SCSI. It did not detect my SCSI Jaz drive.
Have you tried CrystalDiskInfo? Does it show your SCSI disk?
I installed CrystalDiskInfo and it does not even enumerate the Jaz drive. So I ran HDDScan 3.3 and it does enumerate it, but doesn't provide smart data (gives me error when I ask for smart data).

The CrystalDiskInfo DOES see the USB hard drive, and DOES provide SMART data for it.

I'd really like to have PureBasic code that can provide SMART data for USB devices.

But if you still need someone to test an actual SCSI drive with your code, I can get that done in the next couple of days I'll bet.

Let me know if you need that, I'd be happy to oblige.
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Post by doctorized »

@ pthien: can you run a WMI program to see the DeviceID of the Jaz drive?

You can use mine, from http://kc2000labs.110mb.com/pb/zips/4.3 ... r_4.41.zip and from the alphabetical tab select Win32_DiskDrive.
pthien
Enthusiast
Enthusiast
Posts: 148
Joined: Sun Jun 29, 2003 9:39 pm

Re: Get detailed hard disk info [updated 28/6/10]

Post by pthien »

I downloaded and ran your program and yes, that showed the Jaz drive as item #2.
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get detailed hard disk info [updated 28/6/10]

Post by doctorized »

pthien wrote:I downloaded and ran your program and yes, that showed the Jaz drive as item #2.
I didn't mean this. I want you to tell me the 'DeviceID' property. All IDE/SATA drives have a DeviceID '\\.\PHYSICALDRIVEX' where X is a number. Your Jaz drive has the DeviceID: '\\.\PHYSICALDRIVE2' or something else?
pthien
Enthusiast
Enthusiast
Posts: 148
Joined: Sun Jun 29, 2003 9:39 pm

Re: Get detailed hard disk info [updated 28/6/10]

Post by pthien »

OH, sorry. Here is a screenshot...

It is PHYSICALDRIVE1

Image
User avatar
freepurebasic
Enthusiast
Enthusiast
Posts: 123
Joined: Fri Sep 24, 2010 12:02 pm
Location: world wide web

Re: Get detailed hard disk info [updated 28/6/10]

Post by freepurebasic »

i found an error....
my hard disk was appear in the list (the same hard disk) by twice...


so i modified

Code: Select all

Procedure.l HDDInfo(CurrentDrive.l, SCSIPort.l, SCSITargetID.l)
;DebugMe("Current drive = " + Str(CurrentDrive))
sYesNo.s
	If CheckSmartEnabled(CurrentDrive,SCSIPort, SCSITargetID)
		;DebugMe("SMART enabled")
		dummy.l
		If CurrentDrive > 0
			Dim bout.b(527)
			With bin
	  	      \cBufferSize = 512 ;IDENTIFY_BUFFER_SIZE
	  	      \irDriveRegs\bFeaturesReg = 0
	  	      \irDriveRegs\bSectorCountReg = 1
	         \irDriveRegs\bSectorNumberReg = 1
	         \irDriveRegs\bCylLowReg = 0
	         \irDriveRegs\bCylHighReg = 0
	         \irDriveRegs\bDriveHeadReg = $A0
	         ;If Not IsWindowsNT Then .bDriveHeadReg = .bDriveHeadReg Or (DriveNum And 1) * 16
	         \irDriveRegs\bCommandReg = $EC;CByte(IDCmd)
         
           	\bDriveNumber = CurrentDrive
          EndWith
         Result=DeviceIoControl_(hdh, #DFP_RECEIVE_DRIVE_DATA, @bin, SizeOf(SENDCMDINPARAMS), @bout(), 528,@dummy,0)
         CopyMemory(@bout(16),@idsec,512)
      Else
      	Dim buffer.b(SizeOf(SRB_IO_CONTROL) + SizeOf(SENDCMDOUTPARAMS) + #SCSI_MINIPORT_BUFFER_SIZE)
			*p.SRB_IO_CONTROL      = @buffer()
			*pin.SENDCMDINPARAMS   = @buffer() + SizeOf(SRB_IO_CONTROL)
			*pout.SENDCMDOUTPARAMS = *pin
			With *p
				\HeaderLength = SizeOf(SRB_IO_CONTROL)
				\Timeout = 2
				\Length = SizeOf(SENDCMDOUTPARAMS) + #SCSI_MINIPORT_BUFFER_SIZE
				\ControlCode = $1B0501
				CopyMemory(@"SCSIDISK", @\Signature, 8)
			EndWith
			With *pin
				\irDriveRegs\bCommandReg	= $ec;#SMART_CMD
				\bDriveNumber			= SCSITargetID
			EndWith
			Result = DeviceIoControl_(hdh, #IOCTL_SCSI_MINIPORT, @buffer(), SizeOf(SRB_IO_CONTROL) + SizeOf(SENDCMDINPARAMS) - 1, @buffer(), SizeOf(SRB_IO_CONTROL) + SizeOf(SENDCMDOUTPARAMS) + #SCSI_MINIPORT_BUFFER_SIZE, @dummy, #Null)
			CopyMemory(@buffer() + SizeOf(SRB_IO_CONTROL)+16,@idsec, SizeOf(SENDCMDOUTPARAMS))
		EndIf
		;DebugMe("DeviceIOControl returned = " + Str(Result) + " (dummy = " + Str(dummy) + ")")
		If dummy>0
		;GetSMARTVersion()
			;For ii.l=16 To 527 Step 16
			;For k.l=0 To 15
			;;If bout(ii+k)=2: sms.s + "i= " + Str(ii+k) + " / ":EndIf
			;sms.s +  "i= " + Str(ii+k) + " == " +Hex(Val(StrU(bout(ii+k),#Byte))) + " / ";Chr(bout(ii+k));Hex(Val(StrU(bout(ii+k),#Byte))) + " / "
			;Next
			;sms + Chr(10)
			;Next
			;MessageRequester("", sms)
			HDDCount + 1
			;MessageRequester("SerialAtaFeaturesSupported",Str(idsec\UltraDmaMode))
			;MessageRequester("SerialAtaFeaturesed",Str(idsec\PioMode))
			aa.DRIVE_LAYOUT_INFORMATION
			PartCount.l
			DeviceIoControl_(hdh,475148, #Null,0,@aa, SizeOf(DRIVE_LAYOUT_INFORMATION), @BytesRet.l,0)
			For i=0 To aa\PartitionCount-1
			  If aa\PartitionEntry[i]\RecognizedPartition = 1
			    ;Debug aa\PartitionEntry[i]\PartitionLength
			    ;Debug GetPartitionType(aa\PartitionEntry[i]\PartitionType)
			    PartCount + 1
			  EndIf
			Next
			;DebugMe("hdd data")
			di(HDDCount)\PartitionCount = Str(PartCount): PartCount = 0
			If HDDCount > 1:ReDim di.DriveInfo(HDDCount): EndIf
			di(HDDCount)\SerialNumber =Trim(ChangeHighLowByte(PeekS(@idsec\SerialNumber[0],20)))
			di(HDDCount)\Model = Trim(ChangeHighLowByte(PeekS(@idsec\ModelNumber[0],40)))
			di(HDDCount)\Family = DiskFamily(di(HDDCount)\Model)
			di(HDDCount)\FirmWare = Trim(ChangeHighLowByte(PeekS(@idsec\FirmwareRev[0],8)))
			di(HDDCount)\BufferSize = Str(idsec\BufferSize / 2) + " KB"; * 512 / 1024 in KBs.
			If di(HDDCount)\BufferSize = "0 KB": di(HDDCount)\BufferSize = "Not available": EndIf
			di(HDDCount)\ECCBytes = Str(idsec\ECCSize) + " bytes"
			di(HDDCount)\LBASectors = FormatByteSize(idsec\MaxUserLBA)
			di(HDDCount)\CurTransferMode = CurrentTransferMode()
			di(HDDCount)\MaxTransferMode = MaximumTransferMode()
			If idsec\SerialAtaCapabilities <>0 And SerialAtaCapabilities <> $FFFF
				di(HDDCount)\InterfaceType = "Serial ATA"
			Else
				di(HDDCount)\InterfaceType = "Parallel ATA"
			EndIf
			di(HDDCount)\Standard = GetATAMajorVersion() + "  ( " + GetATAMinorVersion() + " )"
			If idsec\MaxUserLBA > 0
				di(HDDCount)\TheoriticalCapacity = c2str(idsec\MaxUserLba * 512 / 1000000000,2) + " GB"
				di(HDDCount)\RealCapacity = c2str(idsec\MaxUserLba * 512 / (1024*1024*1024),2) + " GB"
			ElseIf idsec\TotalAddressableSectors > 0
				di(HDDCount)\TheoriticalCapacity = c2str(idsec\TotalAddressableSectors * 512 / 1000000000,2) + " GB"
				di(HDDCount)\RealCapacity = c2str(idsec\TotalAddressableSectors * 512 / (1024*1024*1024),2) + " GB"
			Else
				di(HDDCount)\TheoriticalCapacity = "Not Available"
				di(HDDCount)\RealCapacity = "Not Available"
			EndIf
			;FLAGS
			; word 82
			;DebugMe("Entering hdd flags")
			If ATAVersion >= 3 And idsec\CommandSetSupported1 & 1
				di(HDDCount)\Flags\SMART = "YES"
				If idsec\CommandSetEnabled1 & 1
					sYesNo = "YES"
				Else
					sYesNo = "NO"
				EndIf
				di(HDDCount)\Flags\SMART + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\SMART = "NO"
			EndIf
			;security mode ataversion ?
			If ATAVersion >= 5 And (idsec\CommandSetSupported1 >> 1) & 1
				di(HDDCount)\Flags\SecMode = "YES"
				If (idsec\CommandSetEnabled1 >> 1) & 1
					sYesNo = "YES"
				Else
					sYesNo = "NO"
				EndIf
				di(HDDCount)\Flags\SecMode + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\SecMode = "NO"
			EndIf
			;power management ataversion ?
			If ATAVersion >= 5 And (idsec\CommandSetSupported1 >> 3) & 1
				di(HDDCount)\Flags\PM = "YES"
				If (idsec\CommandSetEnabled1 >> 3) & 1
					sYesNo = "YES"
				Else
					sYesNo = "NO"
				EndIf
				di(HDDCount)\Flags\PM + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\PM = "NO"
			EndIf
			;WORD 83
			;DOWNLOAD MICROCODE.
			If idsec\CommandSetSupported2 & 1
				di(HDDCount)\Flags\DMicro = "YES"
				If idsec\CommandSetEnabled2 & 1
					sYesNo = "YES"
				Else
					sYesNo = "NO"
				EndIf
				di(HDDCount)\Flags\DMicro + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\DMicro = "NO"
			EndIf
			;TCQ
			If ATAVersion >= 5 And (idsec\CommandSetSupported2 >> 1) & 1 And (idsec\CommandSetSupported2 >> 14) & 1 And (idsec\CommandSetSupported2 >> 15) & 1 = 0
				di(HDDCount)\Flags\TCQ = "YES"
				tmi = (idsec\CommandSetEnabled2 >> 1) & 1
				di(HDDCount)\Flags\TCQ + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\TCQ = "NO"
			EndIf
			;CFA
			If (idsec\CfaPowerMode1 >> 12) & 1 = 1 Or (idsec\CommandSetSupported2 >> 2) & 1 = 1
				di(HDDCount)\Flags\CFA = "YES"
			Else
				di(HDDCount)\Flags\CFA = "NO"
			EndIf
			If (idsec\CfaPowerMode1 >> 13) & 1 = 1
				di(HDDCount)\Flags\CFA + " , " + "Required : " + "YES"
			Else
				di(HDDCount)\Flags\CFA + " , " + "Required : " + "NO"
			EndIf
			;APM
			If ATAVersion >= 3 And (idsec\CommandSetSupported2 >> 3) & 1
				di(HDDCount)\Flags\APM = "YES"
				If (idsec\CommandSetEnabled2 >> 3) & 1 = 1
					sYesNo = "YES"
				Else
					sYesNo = "NO"
				EndIf
				di(HDDCount)\Flags\APM + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\APM = "NO"
			EndIf
			;PUIS
			If ATAVersion >= 3 And (idsec\CommandSetSupported2 >> 5) & 1
				di(HDDCount)\Flags\PUIS = "YES"
				If (idsec\CommandSetEnabled2 >> 5) & 1
					sYesNo = "YES"
				Else
					sYesNo = "NO"
				EndIf
				di(HDDCount)\Flags\PUIS + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\PUIS = "NO"
			EndIf
			;AAM
			If ATAVersion >= 5 And (idsec\CommandSetSupported2 >> 9) & 1
				di(HDDCount)\Flags\AAM = "YES"
				If (idsec\CommandSetEnabled2 >> 9) & 1
					sYesNo = "YES"
				Else
					sYesNo = "NO"
				EndIf
				di(HDDCount)\Flags\AAM + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\AAM = "NO"
			EndIf
			;48bit LBA
			If ATAVersion >= 5 And (idsec\CommandSetSupported2 >> 10) & 1
				di(HDDCount)\Flags\LBA48 = "YES"
				If (idsec\CommandSetEnabled2 >> 10) & 1
					sYesNo = "YES"
				Else
					sYesNo = "NO"
				EndIf
				di(HDDCount)\Flags\LBA48 + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\LBA48 = "NO"
			EndIf
			;DCO
			If ATAVersion >= 6 And (idsec\CommandSetSupported2 >> 11) & 1
				di(HDDCount)\Flags\DCO = "YES"
				If (idsec\CommandSetEnabled2 >> 11) & 1
					sYesNo = "YES"
				Else
					sYesNo = "NO"
				EndIf
				di(HDDCount)\Flags\DCO + "  ( " + "Enabled : " + sYesNo + " )"
			Else
				di(HDDCount)\Flags\DCO = "NO"
			EndIf
			
			;MessageRequester("pio",StrU(idsec\CommandSetSupported2,#PB_Long))
			;SCT
			If ATAVersion >= 8 And idsec\SctCommandTransport & 1
				di(HDDCount)\Flags\SCT = "YES"
			Else
				di(HDDCount)\Flags\SCT = "NO"
			EndIf
			;PIO
			If (idsec\Field88and7064 >> 1) & 1 = 1;means words 64-70 are valid.
				If idsec\PioMode & 1 = 1: di(HDDCount)\Flags\PIO = "Mode   3": EndIf
				If (idsec\PioMode >> 1) & 1 = 1: di(HDDCount)\Flags\PIO = "Mode   4": EndIf
			Else
				di(HDDCount)\Flags\PIO = "Not Available"
			EndIf
			;UDMA
			Dim dmamode.s(6)
			dmamode(0) = " (ATA 16)"
			dmamode(1) = " (ATA 25)"
			dmamode(2) = " (ATA 33)"
			dmamode(3) = " (ATA 44)"
			dmamode(4) = " (ATA 66)"
			dmamode(5) = " (ATA 100)"
			dmamode(6) = " (ATA 133)"
			For i = 6 To 0 Step -1
				If (idsec\UltraDmaMode >> i) & 1 = 1
					di(HDDCount)\Flags\UDMA = "Max Supported" + Str(i) + dmamode(i)
					Break
				EndIf
			Next
			For i = 14 To 8 Step -1
				If (idsec\UltraDmaMode >> i) & 1 = 1
					di(HDDCount)\Flags\UDMA + " , " + "Current Enabled" + Str(i-8) + dmamode(i-8)
					Break
				EndIf
			Next
			;multi word dma
			If idsec\MultiWordDma & 3 = 0
				di(HDDCount)\Flags\MWDMA = "Not Supported"
			Else
				If idsec\MultiWordDma & 1 = 1: di(HDDCount)\Flags\MWDMA = "Supported : " + "Mode  0": EndIf
				If (idsec\MultiWordDma >> 1) & 1 = 1: di(HDDCount)\Flags\MWDMA = "Supported : " + "Mode  1": EndIf
				If (idsec\MultiWordDma >> 2) & 1 = 1: di(HDDCount)\Flags\MWDMA = "Supported : " + "Mode  2": EndIf
				If (idsec\MultiWordDma >> 8) & 1 = 1: di(HDDCount)\Flags\MWDMA + " , " + "Supported : " + "Mode  0": EndIf
				If (idsec\MultiWordDma >> 9) & 1 = 1: di(HDDCount)\Flags\MWDMA + " , " + "Supported : " + "Mode  1": EndIf
				If (idsec\MultiWordDma >> 10) & 1 = 1: di(HDDCount)\Flags\MWDMA + " , " + "Supported : " + "Mode  2": EndIf
			EndIf
			;IORDY
			If (idsec\Capabilities1 >> 11) & 1 = 1
				di(HDDCount)\Flags\IORDY = "YES"
			Else
				di(HDDCount)\Flags\IORDY = "NO"
			EndIf
			;Native Command Queuing
			If ATAVersion >= 6 And (idsec\SerialAtaCapabilities >> 8) & 1
				di(HDDCount)\Flags\NCQ = "YES"
			Else
				di(HDDCount)\Flags\NCQ = "NO"
			EndIf
			;NV Cache
			If ATAVersion >= 7 And idsec\NvCacheCapabilities & 1
				di(HDDCount)\Flags\NVCache = "YES"
			Else
				di(HDDCount)\Flags\NVCache = "NO"
			EndIf
			;TRIM
			If ATAVersion >= 7 And idsec\DataSetManagement & 1
				di(HDDCount)\Flags\TRIM = "YES"
			Else
				di(HDDCount)\Flags\TRIM = "NO"
			EndIf
			;rotation rate
			If ATAVersion >=7 And idsec\NominalMediaRotationRate > 1000 And idsec\NominalMediaRotationRate < $FFFF
				di(HDDCount)\RotationRate = StrU(idsec\NominalMediaRotationRate,#PB_Word) + " RPM"
			EndIf
			;SSD
			If ATAVersion>=7 And idsec\NominalMediaRotationRate = 1
				di(HDDCount)\Flags\SSD = "YES"
			Else
				di(HDDCount)\Flags\SSD = "NO"
			EndIf
			;DebugMe("Reading Attributes")
			ReadAttributes(CurrentDrive, SCSITargetID)
			;DebugMe("Reading Thresholds")
			ReadThresholds(CurrentDrive, SCSITargetID)
			If di(HDDCount)\Temperature = "": di(HDDCount)\Temperature = "Not Available": EndIf
			di(HDDCount)\DiskStatus = DiskStatus()
			;DebugMe("1 will be returned")
			ProcedureReturn 1
		Else
			;DebugMe("2 will be returned")
			ProcedureReturn 0
		EndIf
	Else
		;DebugMe("3 will be returned")
		ProcedureReturn 0
	EndIf
;DebugMe("10 will be returned")
EndProcedure


...

Code: Select all

751:  If CurrentDrive > 0
so is workin' fine right now


nice script!
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get detailed hard disk info [updated 28/6/10]

Post by doctorized »

freepurebasic wrote:

Code: Select all

751:  If CurrentDrive > 0
so is workin' fine right now
You are wrong. The command MUST remain "If CurrentDrive >= 0", because otherwise we are missing
drive #0. Test the code to a computer with two or more drives to check it out.
I tested it to my computer and the code refers only the second and the third drive, not the fisrt one,
and it is reasonable if you think that drive enumeration begins with "\\.\PhysicalDrive0" and not
"\\.\PhysicalDrive1" to use only "> 0", so ">= 0" is absolutely needed.

That means something else is going on with your computer. (RAID? Windows sucks?)
pthien
Enthusiast
Enthusiast
Posts: 148
Joined: Sun Jun 29, 2003 9:39 pm

Re: Get detailed hard disk info [updated 28/6/10]

Post by pthien »

doctorized wrote:
freepurebasic wrote:

Code: Select all

751:  If CurrentDrive > 0
so is workin' fine right now
You are wrong. The command MUST remain "If CurrentDrive >= 0", because otherwise we are missing
drive #0. Test the code to a computer with two or more drives to check it out.
I tested it to my computer and the code refers only the second and the third drive, not the fisrt one,
and it is reasonable if you think that drive enumeration begins with "\\.\PhysicalDrive0" and not
"\\.\PhysicalDrive1" to use only "> 0", so ">= 0" is absolutely needed.

That means something else is going on with your computer. (RAID? Windows sucks?)
It shows my IDE drive twice as well, though.
User avatar
doctorized
Addict
Addict
Posts: 882
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: Get detailed hard disk info [updated 28/6/10]

Post by doctorized »

pthien wrote:It shows my IDE drive twice as well, though.
Can you send me an image of the debug window?

Replace HDDInfo procedure with this:

Code: Select all

Procedure.l HDDInfo(CurrentDrive.l, SCSIPort.l, SCSITargetID.l)
;DebugMe("Current drive = " + Str(CurrentDrive))
sYesNo.s
OpenSmart(CurrentDrive, SCSIPort)
Debug hdh
    ;IF CheckSmartEnabled(CurrentDrive,SCSIPort, SCSITargetID)
        ;DebugMe("SMART enabled")
        dummy.l
        If CurrentDrive >= 0
            Dim bout.b(527)
            With bin
                \cBufferSize = 512 ;IDENTIFY_BUFFER_SIZE
                \irDriveRegs\bFeaturesReg = 0
                \irDriveRegs\bSectorCountReg = 1
             \irDriveRegs\bSectorNumberReg = 1
             \irDriveRegs\bCylLowReg = 0
             \irDriveRegs\bCylHighReg = 0
             \irDriveRegs\bDriveHeadReg = $A0
             ;If Not IsWindowsNT Then .bDriveHeadReg = .bDriveHeadReg Or (DriveNum And 1) * 16
             \irDriveRegs\bCommandReg = $EC;CByte(IDCmd)
         
               \bDriveNumber = CurrentDrive
          EndWith
         Result=DeviceIoControl_(hdh, #DFP_RECEIVE_DRIVE_DATA, @bin, SizeOf(SENDCMDINPARAMS), @bout(), 528,@dummy,0)
         CopyMemory(@bout(16),@idsec,512)
      Else
          Dim buffer.b(SizeOf(SRB_IO_CONTROL) + SizeOf(SENDCMDOUTPARAMS) + #SCSI_MINIPORT_BUFFER_SIZE)
            *p.SRB_IO_CONTROL      = @buffer()
            *pin.SENDCMDINPARAMS   = @buffer() + SizeOf(SRB_IO_CONTROL)
            *pout.SENDCMDOUTPARAMS = *pin
            With *p
                \HeaderLength = SizeOf(SRB_IO_CONTROL)
                \Timeout = 2
                \Length = SizeOf(SENDCMDOUTPARAMS) + #SCSI_MINIPORT_BUFFER_SIZE
                \ControlCode = $1B0501
                CopyMemory(@"SCSIDISK", @\Signature, 8)
            EndWith
            With *pin
                \irDriveRegs\bCommandReg    = $ec;#SMART_CMD
                \bDriveNumber            = SCSITargetID
            EndWith
            Result = DeviceIoControl_(hdh, #IOCTL_SCSI_MINIPORT, @buffer(), SizeOf(SRB_IO_CONTROL) + SizeOf(SENDCMDINPARAMS) - 1, @buffer(), SizeOf(SRB_IO_CONTROL) + SizeOf(SENDCMDOUTPARAMS) + #SCSI_MINIPORT_BUFFER_SIZE, @dummy, #Null)
            CopyMemory(@buffer() + SizeOf(SRB_IO_CONTROL)+16,@idsec, SizeOf(SENDCMDOUTPARAMS))
        EndIf
        ;DebugMe("DeviceIOControl returned = " + Str(Result) + " (dummy = " + Str(dummy) + ")")
        Debug "DeviceIOControl returned = " + Str(Result) + " (dummy = " + Str(dummy) + ")"
        If dummy>0
        ;GetSMARTVersion()
            ;For ii.l=16 To 527 Step 16
            ;For k.l=0 To 15
            ;;If bout(ii+k)=2: sms.s + "i= " + Str(ii+k) + " / ":EndIf
            ;sms.s +  "i= " + Str(ii+k) + " == " +Hex(Val(StrU(bout(ii+k),#Byte))) + " / ";Chr(bout(ii+k));Hex(Val(StrU(bout(ii+k),#Byte))) + " / "
            ;Next
            ;sms + Chr(10)
            ;Next
            ;MessageRequester("", sms)
            HDDCount + 1
            ;MessageRequester("SerialAtaFeaturesSupported",Str(idsec\UltraDmaMode))
            ;MessageRequester("SerialAtaFeaturesed",Str(idsec\PioMode))
            aa.DRIVE_LAYOUT_INFORMATION
            PartCount.l
            DeviceIoControl_(hdh,475148, #Null,0,@aa, SizeOf(DRIVE_LAYOUT_INFORMATION), @BytesRet.l,0)
            For i=0 To aa\PartitionCount-1
              If aa\PartitionEntry[i]\RecognizedPartition = 1
                ;Debug aa\PartitionEntry[i]\PartitionLength
                ;Debug GetPartitionType(aa\PartitionEntry[i]\PartitionType)
                PartCount + 1
              EndIf
            Next
            ;DebugMe("hdd data")
            If HDDCount > 1: ReDim di.DriveInfo(HDDCount): EndIf
            di(HDDCount)\PartitionCount = Str(PartCount): PartCount = 0
            di(HDDCount)\SerialNumber =Trim(ChangeHighLowByte(PeekS(@idsec\SerialNumber[0],20)))
            di(HDDCount)\Model = Trim(ChangeHighLowByte(PeekS(@idsec\ModelNumber[0],40)))
            di(HDDCount)\Family = DiskFamily(di(HDDCount)\Model)
            di(HDDCount)\FirmWare = Trim(ChangeHighLowByte(PeekS(@idsec\FirmwareRev[0],8)))
            di(HDDCount)\BufferSize = Str(idsec\BufferSize / 2) + " KB"; * 512 / 1024 in KBs.
            If di(HDDCount)\BufferSize = "0 KB": di(HDDCount)\BufferSize = "Not available": EndIf
            di(HDDCount)\ECCBytes = Str(idsec\ECCSize) + " bytes"
            di(HDDCount)\LBASectors = FormatByteSize(idsec\MaxUserLBA)
            di(HDDCount)\CurTransferMode = CurrentTransferMode()
            di(HDDCount)\MaxTransferMode = MaximumTransferMode()
            If idsec\SerialAtaCapabilities <>0 And SerialAtaCapabilities <> $FFFF
                di(HDDCount)\InterfaceType = "Serial ATA"
            Else
                di(HDDCount)\InterfaceType = "Parallel ATA"
            EndIf
            di(HDDCount)\Standard = GetATAMajorVersion() + "  ( " + GetATAMinorVersion() + " )"
            If idsec\MaxUserLBA > 0
                di(HDDCount)\TheoriticalCapacity = c2str(idsec\MaxUserLba * 512 / 1000000000,2) + " GB"
                di(HDDCount)\RealCapacity = c2str(idsec\MaxUserLba * 512 / (1024*1024*1024),2) + " GB"
            ElseIf idsec\TotalAddressableSectors > 0
                di(HDDCount)\TheoriticalCapacity = c2str(idsec\TotalAddressableSectors * 512 / 1000000000,2) + " GB"
                di(HDDCount)\RealCapacity = c2str(idsec\TotalAddressableSectors * 512 / (1024*1024*1024),2) + " GB"
            Else
                di(HDDCount)\TheoriticalCapacity = "Not Available"
                di(HDDCount)\RealCapacity = "Not Available"
            EndIf
            ;FLAGS
            ; word 82
            ;DebugMe("Entering hdd flags")
            If ATAVersion >= 3 And idsec\CommandSetSupported1 & 1
                di(HDDCount)\Flags\SMART = "YES"
                If idsec\CommandSetEnabled1 & 1
                    sYesNo = "YES"
                Else
                    sYesNo = "NO"
                EndIf
                di(HDDCount)\Flags\SMART + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\SMART = "NO"
            EndIf
            ;security mode ataversion ?
            If ATAVersion >= 5 And (idsec\CommandSetSupported1 >> 1) & 1
                di(HDDCount)\Flags\SecMode = "YES"
                If (idsec\CommandSetEnabled1 >> 1) & 1
                    sYesNo = "YES"
                Else
                    sYesNo = "NO"
                EndIf
                di(HDDCount)\Flags\SecMode + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\SecMode = "NO"
            EndIf
            ;power management ataversion ?
            If ATAVersion >= 5 And (idsec\CommandSetSupported1 >> 3) & 1
                di(HDDCount)\Flags\PM = "YES"
                If (idsec\CommandSetEnabled1 >> 3) & 1
                    sYesNo = "YES"
                Else
                    sYesNo = "NO"
                EndIf
                di(HDDCount)\Flags\PM + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\PM = "NO"
            EndIf
            ;WORD 83
            ;DOWNLOAD MICROCODE.
            If idsec\CommandSetSupported2 & 1
                di(HDDCount)\Flags\DMicro = "YES"
                If idsec\CommandSetEnabled2 & 1
                    sYesNo = "YES"
                Else
                    sYesNo = "NO"
                EndIf
                di(HDDCount)\Flags\DMicro + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\DMicro = "NO"
            EndIf
            ;TCQ
            If ATAVersion >= 5 And (idsec\CommandSetSupported2 >> 1) & 1 And (idsec\CommandSetSupported2 >> 14) & 1 And (idsec\CommandSetSupported2 >> 15) & 1 = 0
                di(HDDCount)\Flags\TCQ = "YES"
                tmi = (idsec\CommandSetEnabled2 >> 1) & 1
                di(HDDCount)\Flags\TCQ + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\TCQ = "NO"
            EndIf
            ;CFA
            If (idsec\CfaPowerMode1 >> 12) & 1 = 1 Or (idsec\CommandSetSupported2 >> 2) & 1 = 1
                di(HDDCount)\Flags\CFA = "YES"
            Else
                di(HDDCount)\Flags\CFA = "NO"
            EndIf
            If (idsec\CfaPowerMode1 >> 13) & 1 = 1
                di(HDDCount)\Flags\CFA + " , " + "Required : " + "YES"
            Else
                di(HDDCount)\Flags\CFA + " , " + "Required : " + "NO"
            EndIf
            ;APM
            If ATAVersion >= 3 And (idsec\CommandSetSupported2 >> 3) & 1
                di(HDDCount)\Flags\APM = "YES"
                If (idsec\CommandSetEnabled2 >> 3) & 1 = 1
                    sYesNo = "YES"
                Else
                    sYesNo = "NO"
                EndIf
                di(HDDCount)\Flags\APM + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\APM = "NO"
            EndIf
            ;PUIS
            If ATAVersion >= 3 And (idsec\CommandSetSupported2 >> 5) & 1
                di(HDDCount)\Flags\PUIS = "YES"
                If (idsec\CommandSetEnabled2 >> 5) & 1
                    sYesNo = "YES"
                Else
                    sYesNo = "NO"
                EndIf
                di(HDDCount)\Flags\PUIS + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\PUIS = "NO"
            EndIf
            ;AAM
            If ATAVersion >= 5 And (idsec\CommandSetSupported2 >> 9) & 1
                di(HDDCount)\Flags\AAM = "YES"
                If (idsec\CommandSetEnabled2 >> 9) & 1
                    sYesNo = "YES"
                Else
                    sYesNo = "NO"
                EndIf
                di(HDDCount)\Flags\AAM + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\AAM = "NO"
            EndIf
            ;48bit LBA
            If ATAVersion >= 5 And (idsec\CommandSetSupported2 >> 10) & 1
                di(HDDCount)\Flags\LBA48 = "YES"
                If (idsec\CommandSetEnabled2 >> 10) & 1
                    sYesNo = "YES"
                Else
                    sYesNo = "NO"
                EndIf
                di(HDDCount)\Flags\LBA48 + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\LBA48 = "NO"
            EndIf
            ;DCO
            If ATAVersion >= 6 And (idsec\CommandSetSupported2 >> 11) & 1
                di(HDDCount)\Flags\DCO = "YES"
                If (idsec\CommandSetEnabled2 >> 11) & 1
                    sYesNo = "YES"
                Else
                    sYesNo = "NO"
                EndIf
                di(HDDCount)\Flags\DCO + "  ( " + "Enabled : " + sYesNo + " )"
            Else
                di(HDDCount)\Flags\DCO = "NO"
            EndIf
            
            ;MessageRequester("pio",StrU(idsec\CommandSetSupported2,#PB_Long))
            ;SCT
            If ATAVersion >= 8 And idsec\SctCommandTransport & 1
                di(HDDCount)\Flags\SCT = "YES"
            Else
                di(HDDCount)\Flags\SCT = "NO"
            EndIf
            ;PIO
            If (idsec\Field88and7064 >> 1) & 1 = 1;means words 64-70 are valid.
                If idsec\PioMode & 1 = 1: di(HDDCount)\Flags\PIO = "Mode   3": EndIf
                If (idsec\PioMode >> 1) & 1 = 1: di(HDDCount)\Flags\PIO = "Mode   4": EndIf
            Else
                di(HDDCount)\Flags\PIO = "Not Available"
            EndIf
            ;UDMA
            Dim dmamode.s(6)
            dmamode(0) = " (ATA 16)"
            dmamode(1) = " (ATA 25)"
            dmamode(2) = " (ATA 33)"
            dmamode(3) = " (ATA 44)"
            dmamode(4) = " (ATA 66)"
            dmamode(5) = " (ATA 100)"
            dmamode(6) = " (ATA 133)"
            For i = 6 To 0 Step -1
                If (idsec\UltraDmaMode >> i) & 1 = 1
                    di(HDDCount)\Flags\UDMA = "Max Supported" + Str(i) + dmamode(i)
                    Break
                EndIf
            Next
            For i = 14 To 8 Step -1
                If (idsec\UltraDmaMode >> i) & 1 = 1
                    di(HDDCount)\Flags\UDMA + " , " + "Current Enabled" + Str(i-8) + dmamode(i-8)
                    Break
                EndIf
            Next
            ;multi word dma
            If idsec\MultiWordDma & 3 = 0
                di(HDDCount)\Flags\MWDMA = "Not Supported"
            Else
                If idsec\MultiWordDma & 1 = 1: di(HDDCount)\Flags\MWDMA = "Supported : " + "Mode  0": EndIf
                If (idsec\MultiWordDma >> 1) & 1 = 1: di(HDDCount)\Flags\MWDMA = "Supported : " + "Mode  1": EndIf
                If (idsec\MultiWordDma >> 2) & 1 = 1: di(HDDCount)\Flags\MWDMA = "Supported : " + "Mode  2": EndIf
                If (idsec\MultiWordDma >> 8) & 1 = 1: di(HDDCount)\Flags\MWDMA + " , " + "Supported : " + "Mode  0": EndIf
                If (idsec\MultiWordDma >> 9) & 1 = 1: di(HDDCount)\Flags\MWDMA + " , " + "Supported : " + "Mode  1": EndIf
                If (idsec\MultiWordDma >> 10) & 1 = 1: di(HDDCount)\Flags\MWDMA + " , " + "Supported : " + "Mode  2": EndIf
            EndIf
            ;IORDY
            If (idsec\Capabilities1 >> 11) & 1 = 1
                di(HDDCount)\Flags\IORDY = "YES"
            Else
                di(HDDCount)\Flags\IORDY = "NO"
            EndIf
            ;Native Command Queuing
            If ATAVersion >= 6 And (idsec\SerialAtaCapabilities >> 8) & 1
                di(HDDCount)\Flags\NCQ = "YES"
            Else
                di(HDDCount)\Flags\NCQ = "NO"
            EndIf
            ;NV Cache
            If ATAVersion >= 7 And idsec\NvCacheCapabilities & 1
                di(HDDCount)\Flags\NVCache = "YES"
            Else
                di(HDDCount)\Flags\NVCache = "NO"
            EndIf
            ;TRIM
            If ATAVersion >= 7 And idsec\DataSetManagement & 1
                di(HDDCount)\Flags\TRIM = "YES"
            Else
                di(HDDCount)\Flags\TRIM = "NO"
            EndIf
            ;rotation rate
            If ATAVersion >=7 And idsec\NominalMediaRotationRate > 1000 And idsec\NominalMediaRotationRate < $FFFF
                di(HDDCount)\RotationRate = StrU(idsec\NominalMediaRotationRate,#PB_Word) + " RPM"
            EndIf
            ;SSD
            If ATAVersion>=7 And idsec\NominalMediaRotationRate = 1
                di(HDDCount)\Flags\SSD = "YES"
            Else
                di(HDDCount)\Flags\SSD = "NO"
            EndIf
            ;DebugMe("Reading Attributes")
            If CheckSmartEnabled(CurrentDrive,SCSIPort, SCSITargetID)
                ReadAttributes(CurrentDrive, SCSITargetID)
                ;DebugMe("Reading Thresholds")
                ReadThresholds(CurrentDrive, SCSITargetID)
                If di(HDDCount)\Temperature = "": di(HDDCount)\Temperature = "Not Available": EndIf
                di(HDDCount)\DiskStatus = DiskStatus()
            EndIf
            ;DebugMe("1 will be returned")
            ProcedureReturn 1
        Else
            ;DebugMe("2 will be returned")
            ProcedureReturn 0
        EndIf
    ;Else
    ;    ;DebugMe("3 will be returned")
    ;    ProcedureReturn 0
    ;EndIf
;DebugMe("10 will be returned")
EndProcedure
My second PC has only an IDE disk and the code shows him only one time.
ruslanx
User
User
Posts: 46
Joined: Mon Jun 06, 2011 8:28 am

Re: Get detailed hard disk info [updated 28/6/10]

Post by ruslanx »

How [or can you] can I modify to work in unicode ... pls !!!
Post Reply