retrieve harddisk`s modell,serial,firmware (Windows only)

Share your advanced PureBasic knowledge/code with the community.
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by doctorized »

IdeasVacuum wrote:Well here is some news - since running your code CreateFile_("\\.\PhysicalDrive2" etc, the OS cannot 'see' the Expansion drive, even after a re-boot. I didn't realise until my back-up failed because that is what the drive is for.
It is not the fault. You have 4 internal drives with number 0 to 3. The external drives take 4 and 5. So, "\\.\PhysicalDrive2" is reffering to one of the internal drives but the above code looks for extrenal drives only. I will post the completed code as soon as it gets completed.
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by doctorized »

My new code is here: https://arahiotis.sites.sch.gr/HDDInfo.rar
It must be currect with HDD drives. It is not excactly correct for flash drives. My Card Reader is detected fine but flash drives need more work.

PS: Fred, do not say a word! I posted rar file as the code is 99% completed. When it reaches 100% I will post it as text. :D
Last edited by doctorized on Tue Nov 22, 2022 10:42 am, edited 1 time in total.
ricky
New User
New User
Posts: 8
Joined: Fri Sep 07, 2012 9:27 am
Location: Suisse

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by ricky »

Hello,

very interesting you script. There is a way to record all infos in a file?
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by doctorized »

ricky wrote:There is a way to record all infos in a file?
That's the easiest thing. I added this feature to my initial code.

Code: Select all

IncludeFile "HDD_Families.pb"

Enumeration
	#Controller_SAT = 1
	#Controller_SUNPLUS
	#Controller_IO_DATA
	#Controller_LOGITEC
	#Controller_JMICRON
	#Controller_CYPRESS
EndEnumeration

Enumeration
#BusTypeUnknown
#BusTypeScsi
#BusTypeAtapi
#BusTypeAta
#BusType1394
#BusTypeSsa
#BusTypeFibre
#BusTypeUsb
#BusTypeRAID
#BusTypeMaxReserved = $7F
EndEnumeration

Structure STORAGE_PROPERTY_QUERY
  PropertyId.l;STORAGE_PROPERTY_ID
  QueryType.l;STORAGE_QUERY_TYPE
  AdditionalParameters.l
EndStructure

Structure STORAGE_DEVICE_DESCRIPTOR
  Version.l
  Size.l;                                    As Long
  DeviceType.a;                              As Byte
  DeviceTypeModifier.a;                      As Byte
  RemovableMedia.a;                          As Byte
  CommandQueueing.a;                         As Byte
  VendorIdOffset.l;                          As Long
  ProductIdOffset.l;                         As Long
  ProductRevisionOffset.l;                   As Long
  SerialNumberOffset.l;                      As Long
  BusType.w;                                 As Integer
  RawPropertiesLength.l;                     As Long
  RawDeviceProperties.a;                     As Byte
  Reserved.a[1024]
EndStructure

Structure DeviceData
	GeneralConfiguration.w;				; 0
	LogicalCylinders.w;					; 1	Obsolete
	SpecificConfiguration.w;				; 2
	LogicalHeads.w;						; 3 Obsolete
	Retired1.w[2];						; 4-5
	LogicalSectors.w;						; 6 Obsolete
	ReservedForCompactFlash.l;			; 7-8
	Retired2.w;							; 9
	SerialNumber.a[20];					; 10-19
	Retired3.w;							; 20
	BufferSize.w;							; 21 Obsolete
	ECCSize.w;							; 22
	FirmwareRev.a[8];						; 23-26
	ModelNumber.a[40];							; 27-46
	MaxNumPerInterupt.w;					; 47
	Reserved1.w;							; 48
	Capabilities1.w;						; 49
	Capabilities2.w;						; 50
	Obsolute5.l;							; 51-52
	Field88and7064.w;						; 53
	Obsolute6.w[5];						; 54-58
	MultSectorStuff.w;					; 59
	TotalAddressableSectors.l;			; 60-61
	Obsolute7.w;							; 62
	MultiWordDma.w;						; 63
	PioMode.w;							; 64
	MinMultiwordDmaCycleTime.w;			; 65
	RecommendedMultiwordDmaCycleTime.w;	; 66
	MinPioCycleTimewoFlowCtrl.w;			; 67
	MinPioCycleTimeWithFlowCtrl.w;		; 68
	Reserved2.w[6];						; 69-74
	QueueDepth.w;							; 75
	SerialAtaCapabilities.w;				; 76
	ReservedForFutureSerialAta.w;			; 77
	SerialAtaFeaturesSupported.w;			; 78
	SerialAtaFeaturesEnabled.w;			; 79
	MajorVersion.w;						; 80
	MinorVersion.w;						; 81
	CommandSetSupported1.w;				; 82
	CommandSetSupported2.w;				; 83
	CommandSetSupported3.w;				; 84
	CommandSetEnabled1.w;					; 85
	CommandSetEnabled2.w;					; 86
	CommandSetDefault.w;					; 87
	UltraDmaMode.w;						; 88
	TimeReqForSecurityErase.w;			; 89
	TimeReqForEnhancedSecure.w;			; 90
	CurrentPowerManagement.w;				; 91
	MasterPasswordRevision.w;				; 92
	HardwareResetResult.w;				; 93
	Acoustricmanagement.w;				; 94
	StreamMinRequestSize.w;				; 95
	StreamingTimeDma.w;					; 96
	StreamingAccessLatency.w;				; 97
	StreamingPerformance.l;				; 98-99
	MaxUserLba.q;							; 100-103
	StremingTimePio.w;					; 104
	Reserved3.w;							; 105
	SectorSize.w;							; 106
	InterSeekDelay.w;						; 107
	IeeeOui.w;							; 108
	UniqueId3.w;							; 109
	UniqueId2.w;							; 110
	UniqueId1.w;							; 111
	Reserved4.w[4];						; 112-115
	Reserved5.w;							; 116
	WordsPerLogicalSector.l;				; 117-118
	Reserved6.w[8];						; 119-126
	RemovableMediaStatus.w;				; 127
	SecurityStatus.w;						; 128
	VendorSpecific.w[31];					; 129-159
	CfaPowerMode1.w;						; 160
	Reserved7.w[7];						; 161-167
	DeviceNominalFormFactor.w;			;	168
	DataSetManagement.w;					;	169
	AdditionalProductIdentifier.w[4] ;  170-173
	ReservedForCompactFlashAssociation.w[2];  174-175
	CurrentMediaSerialNo.a[60];			; 176-205
	SctCommandTransport.w;				; 206  254
	ReservedForCeAta1.w[2];				; 207-208
	AlignmentOfLogicalBlocks.w;			; 209
	WriteReadVerifySectorCountMode3.l;	; 210-211
	WriteReadVerifySectorCountMode2.l;	; 212-213
	NvCacheCapabilities.w;				; 214
	NvCacheSizeLogicalBlocks.l;			; 215-216
	NominalMediaRotationRate.w;			; 217
	Reserved8.w;							; 218
	NvCacheOptions1.w;					; 219
	NvCacheOptions2.w;					; 220
	Reserved9.w;							; 221
	TransportMajorVersionNumber.w;		; 222
	TransportMinorVersionNumber.w;		; 223
	ReservedForCeAta2.w[10];				; 224-233
	MinimumBlocksPerDownloadMicrocode.w;	; 234
	MaximumBlocksPerDownloadMicrocode.w;	; 235
	Reserved10.w[19];						; 236-254
	IntegrityWord.w;						; 255
EndStructure

Structure IDEREGS 
    bFeaturesReg.a 
    bSectorCountReg.a 
    bSectorNumberReg.a 
    bCylLowReg.a 
    bCylHighReg.a 
    bDriveHeadReg.a 
    bCommandReg.a 
    bReserved.a 
EndStructure 
Structure SENDCMDINPARAMS 
    cBufferSize.l 
    irDriveRegs.IDEREGS 
    bDriveNumber.a
    bReserved.a[3] 
    dwReserved.l[4]
EndStructure 

Structure  DRIVERSTATUS 
    bDriveError.a 
    bIDEStatus.a 
    bReserved.a[2]
    dwReserved.l[2]
EndStructure 
Structure  SENDCMDOUTPARAMS 
    cBufferSize.l 
    DStatus.DRIVERSTATUS      
    bBuffer.a[512]
EndStructure

Structure SupportedFlags
	SMART.s
	LBA48.s
	AAM.s
	PM.s
	APM.s
	NCQ.s
	TCQ.s
	PUIS.s
	DCO.s
	SETMAX.s
	NVCache.s
	TRIM.s
	SCT.s
	UDMA.s
	IORDY.s
	CFA.s
	PIO.s
	MWDMA.s
	SSD.s
	SecMode.s
	DMicro.s
EndStructure

Structure SRB_IO_CONTROL
	HeaderLength.l
	Signature.a[8]
	Timeout.l
	ControlCode.l
	ReturnCode.l
	Length.l
EndStructure

Structure AttrData
   AttrID.a
   AttrName.s
   AttrValue.a
   AttrWorstValue.a
   AttrThreshold.a
   AttrRaw.q
   StatusFlags.w
EndStructure

Structure DriveInfo
	SerialNumber.s
	Model.s
	Family.s
	FirmWare.s
	BufferSize.s
	ECCBytes.s
	LBASectors.s
	CurTransferMode.s
	MaxTransferMode.s
	InterfaceType.s
	Standard.s
	RotationRate.s
	Flags.SupportedFlags
	NumAttributes.l
	Attributes.AttrData[31]
	Temperature.s
	HoursOn.s
	CountsOn.s
	TheoriticalCapacity.s
	RealCapacity.s
	DiskStatus.s
	PartitionCount.s
EndStructure

Structure PARTITION_INFORMATION
    StartingOffset.q
    PartitionLength.q
    HiddenSectors.l
    PartitionNumber.l
    PartitionType.b
    BootIndicator.b;bool
    RecognizedPartition.b;bool
    RewritePartition.b;bool
    dummy.l
EndStructure

Structure DRIVE_LAYOUT_INFORMATION 
   PartitionCount.l
   Signature.l
   PartitionEntry.PARTITION_INFORMATION[50]
EndStructure

Structure t_SPTD
    Length.w ; data len
    ScsiStatus.a    ; SCSI Status
    PathId.a    ; Bus Number
    TargetId.a    ; Target
    Lun.a    ; Logical Unit Number
    CdbLength.a    ; CDB (Command Descriptor Block)
    SenseInfoLength.a    ; Sense Info len
    DataIn.a    ; data direction
    padding0.a[3]
    DataTransferLength.l    ; data transfer length
    TimeOutValue.i    ; command timeout
    DataBufferOffset.i    ; Pointer to the data buffer
    SenseInfoOffset.l    ; Sense Info Offset
    Cdb.a[16]    ; Command Descriptor Block
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
   Fill.a[4]    ;
CompilerEndIf
EndStructure

Structure t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER
    spt.t_SPTD     ; SPTD structure
    SenseBuffer.a[32]       ; Debugging-Info from the drive
    DataBuffer.a[512]
 EndStructure

#DFP_RECEIVE_DRIVE_DATA = $7C088
#DFP_SEND_DRIVE_COMMAND	= $7C084
#IOCTL_SCSI_MINIPORT    = $4D008
#IOCTL_SCSI_MINIPORT_ENABLE_SMART = $1B0504
#SCSI_MINIPORT_BUFFER_SIZE = 512

Global idsec.DeviceData
Global Dim di.DriveInfo(10)
Global hdh.i, USB_Drive.l
Global HDDCount.l = -1
Global ATAVersion.l;, pswb.t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, OL.OVERLAPPED
Global bin.SENDCMDINPARAMS
Global bout.SENDCMDOUTPARAMS
Global Dim cmd.a(16);command bytes 0-15 and byte 16 is length.

Procedure.s ChangeHighLowByte(Instring.s) 
  ;Change BIG-Little Endian 
  sdummy.s="" 
  L=Len(Instring) 
  For I=1 To L Step 2 
  If (I+1)<=L 
    sdummy = sdummy + Mid(Instring,I+1,1)+Mid(Instring,I,1)  
  EndIf 
  Next I 
  ProcedureReturn sdummy
EndProcedure

Declare ReadAttributes(CurrentDrive.l, SCSITargetID.l)
Declare ReadThresholds(CurrentDrive.l, SCSITargetID.l)

Procedure.s FormatByteSize(n.q)
  Protected s.s=Str(n)
  Protected len=Len(s)
  Protected ret.s
 
  For i=0 To len-1
    If i And Not i%3 : ret="." + ret : EndIf; "." is the greek symbol for separating thousands. Use your own.
    ret= Mid(s,len-i,1) +ret
  Next
 
  ProcedureReturn ret
EndProcedure

Procedure.s c2str(num.d, demical.l=0)
;This procedure is used to change the english "." demical separator to the greek ",".
;Use yor own symbol if you want.
ProcedureReturn ReplaceString(StrD(num,demical), ".", ",")
EndProcedure

Procedure OpenSmart(CurrentDrive.l, SCSIPort.l)
If CurrentDrive >= 0; ATA
	Select OSVersion()
		Case #PB_OS_Windows_95, #PB_OS_Windows_98, #PB_OS_Windows_ME
			hdh = CreateFile_("\\.\SMARTVSD.VXD", 0, 0, 0, #CREATE_NEW, 0, 0)
		Default
			hdh = CreateFile_("\\.\PhysicalDrive" + Str(CurrentDrive),#GENERIC_READ | #GENERIC_WRITE, #FILE_SHARE_READ | #FILE_SHARE_WRITE,0, #OPEN_EXISTING, 0, 0) 
	EndSelect
Else; SCSI
	hdh = CreateFile_("\\.\Scsi" + Str(SCSIPort) + ":", #GENERIC_READ | #GENERIC_WRITE, #FILE_SHARE_READ | #FILE_SHARE_WRITE, #Null, #OPEN_EXISTING, 0, #Null)
EndIf
EndProcedure

Procedure.s GetAttributeName(AttribID.l)
Select AttribID
	Case 0
		ProcedureReturn "Invalid Attribute"
	Case 1
		ProcedureReturn "Raw Read Error Rate"
	Case 2
		ProcedureReturn "ThroughPut Performance"
	Case 3
		ProcedureReturn "Spin Up Time"
	Case 4
		ProcedureReturn "Start/Stop Count"
	Case 5
		ProcedureReturn "Reallocated Sector Count"
	Case 6
		ProcedureReturn "Read Channel Margin"
	Case 7
		ProcedureReturn "Seek Error Rate"
	Case 8
		ProcedureReturn "Seek Time Performance"
	Case 9
		ProcedureReturn "Power On Hours Count"
	Case 10
		ProcedureReturn "Spin Retry Count"
	Case 11
		ProcedureReturn "Calibration Retry Count"
	Case 12
		ProcedureReturn "Power Cycle Count"
	Case 13
		ProcedureReturn "Soft Read Error Rate"
	Case 170
		ProcedureReturn "Available Reserved Space"
	Case 171
		ProcedureReturn "SSD Program Fail Count"
	Case 172
		ProcedureReturn "SSD Erase Fail Count"
	Case 174
		ProcedureReturn "Unexpected power loss count"
	Case 175
		ProcedureReturn "Power Loss Protection Failure"
	Case 177
		ProcedureReturn "Wear Range Delta"
	Case 179
		ProcedureReturn "Used Reserved Block Count Total"
	Case 180
		ProcedureReturn "Unused Reserved Block Count Total"
	Case 181
		;If FindString(LCase(di(HDDCount)\Model),"seagate",1) > 0 
		;	ProcedureReturn "Temperature Difference from 100"
		;Else
		;	ProcedureReturn "Airflow Temperature"
		;EndIf
		ProcedureReturn "Program Fail Count Total or Non-4K Aligned Access Count"
	Case 182
		ProcedureReturn "Erase Fail Count"
	Case 183
		ProcedureReturn "SATA Downshift Error Count"
	Case 184
		ProcedureReturn "End-to-End error"
	Case 185
		ProcedureReturn "Head Stability"
	Case 186
		ProcedureReturn "Induced Op-Vibration Detection"
	Case 187
		ProcedureReturn "Reported Uncorrectable Errors"
	Case 188
		ProcedureReturn "Command Timeout"
	Case 189
		ProcedureReturn "High Fly Writes (WDC)"
	Case 190
		If FindString(LCase(di(HDDCount)\Model),"seagate",1) > 0 
			ProcedureReturn "Temperature Difference from 100"
		Else
			ProcedureReturn "Airflow Temperature"
		EndIf
	Case 191
		ProcedureReturn "G Sense Error Rate"
	Case 192
		ProcedureReturn "Power Off Retract Cycle"
	Case 193
		ProcedureReturn "Load/Unload Cycle Count"
	Case 194
		ProcedureReturn "Temperature"
	Case 195
		ProcedureReturn "Hardware ECC Recovered"
	Case 196
		ProcedureReturn "Reallocation Events Count"
	Case 197
		ProcedureReturn "Current Pending Sector Count"
	Case 198
		ProcedureReturn "Uncorrectable Sector Count"
	Case 199
		ProcedureReturn "Ultra DMA CRC Error Rate"
	Case 200
		ProcedureReturn "Write Error Rate / Multi-Zone Error Rate"
	Case 201
		ProcedureReturn "Soft Read Error Rate"
	Case 202
		ProcedureReturn "Data Address Mark errors"
	Case 203
		ProcedureReturn "Run Out Cancel"
	Case 204
		ProcedureReturn "Soft ECC Correction"
	Case 205
		ProcedureReturn "Thermal Asperity Rate"
	Case 206
		ProcedureReturn "Flying Height"
	Case 207
		ProcedureReturn "Spin High Current"
	Case 208
		ProcedureReturn "Spin Buzz"
	Case 209
		ProcedureReturn "Offline Seek Performance"
	Case 210
		ProcedureReturn "Vibration During Write"
	Case 211
		ProcedureReturn "Vibration During Write"
	Case 212
		ProcedureReturn "Shock During Write"
	Case 220
		ProcedureReturn "Disk Shift"
	Case 221
		ProcedureReturn "G Sense Error Rate II"
	Case 222
		ProcedureReturn "Loaded Hours"
	Case 223
		ProcedureReturn "Load/Unload Retry Count"
	Case 224
		ProcedureReturn "Load Friction"
	Case 225
		ProcedureReturn "Load/Unload Cycle Count II"
	Case 226
		ProcedureReturn "Load In Time"
	Case 227
		ProcedureReturn "Torque Amplification Count"
	Case 228
		ProcedureReturn "Power Off Retract Count"
	Case 230
		ProcedureReturn "GMR Head Amplitude"
	Case 231
		ProcedureReturn "Temperature II or SSD Life Left"
	Case 232
		ProcedureReturn "Available Reserved Space"
	Case 233
		If FindString(LCase(di(HDDCount)\Model),"intel",1) > 0 
			ProcedureReturn "Media Wearout Indicator"
		Else
			ProcedureReturn "Power-On Hours"
		EndIf
	Case 234
		ProcedureReturn "Average erase count AND Maximum Erase Count"
	Case 235
		ProcedureReturn "Good Block Count AND System(Free) Block Count"
	Case 240
		If FindString(LCase(di(HDDCount)\Model),"fujitsu",1) > 0 
			ProcedureReturn "Transfer Error Rate"
		Else
			ProcedureReturn "Head Flying Hours"
		EndIf
	Case 241
		ProcedureReturn "Total LBAs Written"
	Case 242
		ProcedureReturn "Total LBAs Read"
	Case 249
		ProcedureReturn "NAND_Writes_1GB"
	Case 250
		ProcedureReturn "Read Error Retry Rate"
	Case 254
		ProcedureReturn "Free Fall Protection"
	Default 
		ProcedureReturn "Unknown value  ( " + Str(AttribID) + " )"
		
EndSelect
EndProcedure

Procedure.l CheckSmartEnabled(CurrentDrive.l,SCSIPort.l, SCSITargetID.l)
lBytesReturned.l=0
;OpenSmart(CurrentDrive, SCSIPort)
If hdh
	If CurrentDrive >= 0
		If USB_Drive = 0
			With bin
			\irDriveRegs\bFeaturesReg = $D8;SMART_ENABLE_SMART_OPERATIONS
			\irDriveRegs\bSectorCountReg = 1
			\irDriveRegs\bSectorNumberReg = 1
			\irDriveRegs\bCylLowReg = $4F;SMART_CYL_LOW
			\irDriveRegs\bCylHighReg = $C2;SMART_CYL_HI
			\irDriveRegs\bCommandReg = $B0;IDE_EXECUTE_SMART_FUNCTION
			
				\bDriveNumber = CurrentDrive
				\cBufferSize = 0
				If (CurrentDrive & 1)
					\irDriveRegs\bDriveHeadReg = $B0
				Else
					\irDriveRegs\bDriveHeadReg = $A0
				EndIf
			EndWith
			ProcedureReturn DeviceIoControl_(hdh, #DFP_SEND_DRIVE_COMMAND, @bin, SizeOf(SENDCMDINPARAMS), @bout, SizeOf(SENDCMDOUTPARAMS), @lBytesReturned, 0)
		Else
			
		EndIf
	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
			;If command = #DISABLE_SMART
			;	\ControlCode = #IOCTL_SCSI_MINIPORT_DISABLE_SMART
			;Else
				\ControlCode = #IOCTL_SCSI_MINIPORT_ENABLE_SMART
			;EndIf
			CopyMemory(@"SCSIDISK", @\Signature, 8)
			;\Signature = "SCSIDISK"
		EndWith
		With *pin
			\irDriveRegs\bFeaturesReg	= $d8;command
			\irDriveRegs\bSectorCountReg	= 1
			\irDriveRegs\bSectorNumberReg	= 1
			\irDriveRegs\bCylLowReg		= $4f;#SMART_CYL_LOW
			\irDriveRegs\bCylHighReg	= $c2;#SMART_CYL_HI
			\irDriveRegs\bCommandReg	= $b0;#SMART_CMD
			\cBufferSize			= #SCSI_MINIPORT_BUFFER_SIZE
			\bDriveNumber			= SCSITargetID
		EndWith
		ProcedureReturn 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.l, #Null)
	EndIf
EndIf
ProcedureReturn 0
EndProcedure

Procedure.s MaximumTransferMode()
;max value
Max.s
If (idsec\UltraDmaMode & $40)
	Max = "Ultra DMA 133 (Mode 6)"
ElseIf (idsec\UltraDmaMode & $20)
	Max = "Ultra DMA 100 (Mode 5)"
ElseIf (idsec\UltraDmaMode & $10)
	Max = "Ultra DMA 66 (Mode 4)"
ElseIf (idsec\UltraDmaMode & 8)
	Max = "Ultra DMA 44(Mode 3)"
ElseIf (idsec\UltraDmaMode & 4)
	Max = "Ultra DMA 33 (Mode 2)"
ElseIf (idsec\UltraDmaMode & 2)
	Max = "Ultra DMA 25 (Mode 1)"
ElseIf (idsec\UltraDmaMode & 1)
	Max = "Ultra DMA 16 (Mode 0)"
EndIf
If idsec\SerialAtaCapabilities & 8
	Max = "SATA 600"
ElseIf idsec\SerialAtaCapabilities & 4
	Max = "SATA 300"
ElseIf idsec\SerialAtaCapabilities & 2
	Max = "SATA 150"
EndIf
ProcedureReturn Max
EndProcedure

Procedure.s CurrentTransferMode()
;current value
cur.s
If (idsec\UltraDmaMode & $4000)
	Cur = "Ultra DMA 133 (Mode 6)"
ElseIf (idsec\UltraDmaMode & $2000)
	Cur = "Ultra DMA 100 (Mode 5)"
ElseIf (idsec\UltraDmaMode & $1000)
	Cur = "Ultra DMA 66 (Mode 4)"
ElseIf (idsec\UltraDmaMode & 800)
	Cur = "Ultra DMA 44(Mode 3)"
ElseIf (idsec\UltraDmaMode & 400)
	Cur = "Ultra DMA 33 (Mode 2)"
ElseIf (idsec\UltraDmaMode & 200)
	Cur = "Ultra DMA 25 (Mode 1)"
ElseIf (idsec\UltraDmaMode & 100)
	Cur = "Ultra DMA 16 (Mode 0)"
EndIf
;If Cur ="";SATA
If idsec\SerialAtaCapabilities & 8
	Cur = "SATA 600"
ElseIf idsec\SerialAtaCapabilities & 4
	Cur = "SATA 300"
ElseIf idsec\SerialAtaCapabilities & 2
	Cur = "SATA 150"
EndIf
;EndIf
If Cur = "": Cur = "Unknown": EndIf
ProcedureReturn Cur
EndProcedure

Procedure.s GetATAMajorVersion()
If idsec\MajorVersion<>0 And idsec\MajorVersion<> $FFFF
	For i.l=14 To 1 Step -1
		If (idsec\MajorVersion >> i) & 1
			ATAVersion = i
			Break
		EndIf
	Next
	Select i
		Case 11
			ProcedureReturn "ACS-4"
		Case 10
			ProcedureReturn "ACS-3"
		Case 9
			ProcedureReturn "ACS-2"
		Case 8
			ProcedureReturn "ATA" + Str(i) + "-ACS"
		Case 4 To 7
			ProcedureReturn "ATA/ATAPI-" + Str(i)
		Case 0
			ProcedureReturn "Unknown"
		Default
			ProcedureReturn "ATA-" + Str(i)
	EndSelect
EndIf
ProcedureReturn "Unknown"
EndProcedure

Procedure.s GetATAMinorVersion()
Select idsec\MinorVersion
	Case $0000, $FFFF:	ProcedureReturn "----"
	Case $0001:	ProcedureReturn "ATA (ATA-1) X3T9.2 781D prior to revision 4"
	Case $0002:	ProcedureReturn "ATA-1 published, ANSI X3.221-1994"
	Case $0003:	ProcedureReturn "ATA (ATA-1) X3T10 781D revision 4"
	Case $0004:	ProcedureReturn "ATA-2 published, ANSI X3.279-1996"
	Case $0005:	ProcedureReturn "ATA-2 X3T10 948D prior to revision 2k"
	Case $0006:	ProcedureReturn "ATA-3 X3T10 2008D revision 1"
	Case $0007:	ProcedureReturn "ATA-2 X3T10 948D revision 2k"
	Case $0008:	ProcedureReturn "ATA-3 X3T10 2008D revision 0"
	Case $0009:	ProcedureReturn "ATA-2 X3T10 948D revision 3"
	Case $000A:	ProcedureReturn "ATA-3 published, ANSI X3.298-199x"
	Case $000B:	ProcedureReturn "ATA-3 X3T10 2008D revision 6"
	Case $000C:	ProcedureReturn "ATA-3 X3T13 2008D revision 7 and 7a"
	Case $000D:	ProcedureReturn "ATA/ATAPI-4 X3T13 1153D version 6"
	Case $000E:	ProcedureReturn "ATA/ATAPI-4 T13 1153D version 13"
	Case $000F:	ProcedureReturn "ATA/ATAPI-4 X3T13 1153D version 7"
	Case $0010:	ProcedureReturn "ATA/ATAPI-4 T13 1153D version 18"
	Case $0011:	ProcedureReturn "ATA/ATAPI-4 T13 1153D version 15"
	Case $0012:	ProcedureReturn "ATA/ATAPI-4 published, ANSI INCITS 317-1998"
	Case $0013:	ProcedureReturn "ATA/ATAPI-5 T13 1321D version 3"
	Case $0014:	ProcedureReturn "ATA/ATAPI-4 T13 1153D version 14"
	Case $0015:	ProcedureReturn "ATA/ATAPI-5 T13 1321D version 1"
	Case $0016:	ProcedureReturn "ATA/ATAPI-5 published, ANSI INCITS 340-2000"
	Case $0017:	ProcedureReturn "ATA/ATAPI-4 T13 1153D version 17"
	Case $0018:	ProcedureReturn "ATA/ATAPI-6 T13 1410D version 0"
	Case $0019:	ProcedureReturn "ATA/ATAPI-6 T13 1410D version 3a"
	Case $001A:	ProcedureReturn "ATA/ATAPI-7 T13 1532D version 1"
	Case $001B:	ProcedureReturn "ATA/ATAPI-6 T13 1410D version 2"
	Case $001C:	ProcedureReturn "ATA/ATAPI-6 T13 1410D version 1"
	Case $001D:	ProcedureReturn "ATA/ATAPI-7 published ANSI INCITS 397-2005"
	Case $001E:	ProcedureReturn "ATA/ATAPI-7 T13 1532D version 0"
	Case $0021:	ProcedureReturn "ATA/ATAPI-7 T13 1532D version 4a"
	Case $0022:	ProcedureReturn "ATA/ATAPI-6 published, ANSI INCITS 361-2002"
	Case $0027:	ProcedureReturn "ATA8-ACS version 3c"
	Case $0028:	ProcedureReturn "ATA8-ACS version 6"
	Case $0029:	ProcedureReturn "ATA8-ACS version 4"
	Case $0033:	ProcedureReturn "ATA8-ACS version 3e"
	Case $0039:	ProcedureReturn "ATA8-ACS version 4c"
	Case $0042:	ProcedureReturn "ATA8-ACS version 3f"
	Case $0052:	ProcedureReturn "ATA8-ACS version 3b"
	Case $0107:	ProcedureReturn "ATA8-ACS version 2d"
	Default: ProcedureReturn  "Unknown " + RSet(Hex(idsec\MinorVersion),4,"0")
EndSelect
EndProcedure

Procedure.i HDD_SPTD(StartOfCopy.i, *OutBuffer, BufferLen.i)
pswb.t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER: OL.OVERLAPPED
Length.l: returned.l: i.l
status.l
With pswb\spt
   \length = SizeOf(t_SPTD)                                       ; size of the substructure
   \PathId = 0
   \TargetId = 0
   \Lun = 0
   \DataIn = 1                                     ; data dir
   \TimeOutValue = 2                            ; Timeout
   \senseInfoLength = 24;SizeOf(pswb\SenseBuffer)-1      ; Sense Info size
   \senseInfoOffset = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\SenseBuffer) ; Sense Info Offset
   \DataTransferLength = 512                   ; data len
   \DataBufferOffset = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\DataBuffer)    ; data buffer pointer
   \Cdb[0] = cmd(0)
   \Cdb[1] = cmd(1)
   \Cdb[2] = cmd(2)
   \Cdb[3] = cmd(3)
   \Cdb[4] = cmd(4)
   \Cdb[5] = cmd(5)
   \Cdb[6] = cmd(6)
   \Cdb[7] = cmd(7)
   \Cdb[8] = cmd(8)
   \Cdb[9] = cmd(9)
   \Cdb[10] = cmd(10)
   \Cdb[11] = cmd(11)
   \Cdb[12] = cmd(12)

   \CdbLength = cmd(16)                                ; CDB len
EndWith
Length = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\DataBuffer) + pswb\spt\DataTransferLength;;SizeOf(pswb)                                ; size of the structure
status = DeviceIoControl_(hdh, $4d004, @pswb, SizeOf(t_SPTD), @pswb, Length, @returned, @OL)
If returned > 100
	CopyMemory(@pswb\DataBuffer + StartOfCopy, *OutBuffer, BufferLen)
	;ShowMemoryViewer(@pswb,582)
	;CallDebugger
EndIf
ProcedureReturn returned
EndProcedure
			
Procedure ReadAttributes(CurrentDrive.l, SCSITargetID.l)
   cbBytesReturned.l
   Dim bArrOut.a(527)
   If CurrentDrive >= 0
   	If USB_Drive = 0
			With bin
				\cBufferSize = 512;READ_ATTRIBUTE_BUFFER_SIZE
				\irDriveRegs\bFeaturesReg = $D0;SMART_READ_ATTRIBUTE_VALUES
				\irDriveRegs\bSectorCountReg = 1
				\irDriveRegs\bSectorNumberReg = 1
				\irDriveRegs\bCylLowReg = $4F;SMART_CYL_LOW
				\irDriveRegs\bCylHighReg = $C2;SMART_CYL_HI
				\irDriveRegs\bDriveHeadReg = $A0
				;If Not IsWindowsNT Then .bDriveHeadReg = .bDriveHeadReg Or (DriveNum And 1) * 16
				\irDriveRegs\bCommandReg = $B0;IDE_EXECUTE_SMART_FUNCTION
				
				\bDriveNumber = CurrentDrive
			EndWith
			ReadAttributesCmd = DeviceIoControl_(hdh, #DFP_RECEIVE_DRIVE_DATA, @bin, SizeOf(SENDCMDINPARAMS), @bArrOut(), 528, @cbBytesReturned, 0)
		Else; it is USB
			For i=0 To 16
				tmp$ + Hex(cmd(i)) + " "
			Next
			Select USB_Drive
				Case #Controller_SAT
					cmd(3) = $D0
					cmd(6) = $4F
				   cmd(7) = $C2
				   cmd(8) = 0;$A1
				   cmd(9) = $B0
				Case #Controller_SUNPLUS
					cmd(5) = $D0
					cmd(8) = $4F
					cmd(9) = $C2
					cmd(10) = 0
					cmd(11) = $B0
				Case #Controller_IO_DATA
					cmd(2) = $D0
					cmd(3) = 0
					cmd(5) = $4F
				   cmd(6) = $C2
				   cmd(7) = 0
				   cmd(8) = $B0
				Case #Controller_LOGITEC
					cmd(2) = $D0
					cmd(5) = $4F
					cmd(6) = $C2
					cmd(7) = 0
					cmd(8) = $B0
					cmd(9) = $4C
				Case #Controller_JMICRON
					cmd(5) = $D0
					cmd(7) = 1
					cmd(8) = $4F
					cmd(9) = $C2
					cmd(10) = 0
					cmd(11) = $B0
				Case #Controller_CYPRESS
					cmd(6) = $D0
					cmd(7) = 0
					cmd(9) = $4F
					cmd(10) = $C2
					cmd(11) = 0
					cmd(12) = $B0
			EndSelect
			HDD_SPTD(-16, @bArrOut(), SizeOf(SENDCMDOUTPARAMS))
		EndIf
	 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 = $1b0502;#IOCTL_SCSI_MINIPORT_ENABLE_SMART
			CopyMemory(@"SCSIDISK", @\Signature, 8)
		EndWith
		With *pin
			\irDriveRegs\bFeaturesReg	= $d0;command
			\irDriveRegs\bSectorCountReg	= 1
			\irDriveRegs\bSectorNumberReg	= 1
			\irDriveRegs\bCylLowReg		= $4f;#SMART_CYL_LOW
			\irDriveRegs\bCylHighReg	= $c2;#SMART_CYL_HI
			\irDriveRegs\bCommandReg	= $b0;#SMART_CMD
			\cBufferSize			= #SCSI_MINIPORT_BUFFER_SIZE
			\bDriveNumber			= SCSITargetID
		EndWith
		bRet = 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),@bArrOut(), SizeOf(SENDCMDOUTPARAMS))
	EndIf 
	di(HDDCount)\NumAttributes = 0
	For i = 0 To 29
		If bArrOut(18 + i * 12) > 0
			di(HDDCount)\Attributes[i]\AttrID = bArrOut(18 + i * 12)
         di(HDDCount)\Attributes[i]\AttrName = GetAttributeName(bArrOut(18 + i * 12))
         CopyMemory(@bArrOut(23 + i * 12), @di(HDDCount)\Attributes[i]\AttrRaw, 6)
         di(HDDCount)\Attributes[i]\AttrValue = bArrOut(21 + i * 12)
         di(HDDCount)\Attributes[i]\AttrWorstValue = bArrOut(22 + i * 12)
         If bArrOut(18 + i * 12) = $C2 Or bArrOut(18 + i * 12) = 190; Temperature
         	far.l=(di(HDDCount)\Attributes[i]\AttrRaw & $FF) * 1.8 + 32
         	di(HDDCount)\Temperature = Str(di(HDDCount)\Attributes[i]\AttrRaw & $FF) + " " +Chr(176)+"C  ( " + Str(far) + " " +Chr(176)+"F )"
         EndIf
         If bArrOut(18 + i * 12) = 9;hours on
         	di(HDDCount)\HoursOn = Str(di(HDDCount)\Attributes[i]\AttrRaw) + " hours"
         EndIf
         If bArrOut(18 + i * 12) = 12;counts on
         	di(HDDCount)\CountsOn = Str(di(HDDCount)\Attributes[i]\AttrRaw) + " counts"
         EndIf
         di(HDDCount)\NumAttributes + 1
      EndIf
  Next
EndProcedure

Procedure ReadThresholds(CurrentDrive.l, SCSITargetID.l)
	cbBytesReturned.l
	Dim bArrOut.a(527)
	If CurrentDrive >= 0
		If USB_Drive = 0
		  	With bin
				\cBufferSize = 512;READ_ATTRIBUTE_BUFFER_SIZE
				\irDriveRegs\bFeaturesReg = $D1;SMART_READ_ATTRIBUTE_THRESHOLDS
				\irDriveRegs\bSectorCountReg = 1
				\irDriveRegs\bSectorNumberReg = 1
				\irDriveRegs\bCylLowReg = $4F;SMART_CYL_LOW
				\irDriveRegs\bCylHighReg = $C2;SMART_CYL_HI
				
				\irDriveRegs\bDriveHeadReg = $A0
				;If Not IsWindowsNT Then .bDriveHeadReg = .bDriveHeadReg Or (DriveNum And 1) * 16
				\irDriveRegs\bCommandReg = $B0;IDE_EXECUTE_SMART_FUNCTION
				\bDriveNumber = CurrentDrive
			EndWith
			ReadAttributesCmd = DeviceIoControl_(hdh, #DFP_RECEIVE_DRIVE_DATA, @bin, SizeOf(SENDCMDINPARAMS), @bArrOut(), 528, @cbBytesReturned, 0)
		Else
			Select USB_Drive
				Case #Controller_SAT
					cmd(3) = $D1
					cmd(6) = $4F
				   cmd(7) = $C2
				   cmd(8) = 0;$A1
				   cmd(9) = $B0
				Case #Controller_SUNPLUS
					cmd(5) = $D1
					cmd(8) = $4F
					cmd(9) = $C2
					cmd(10) = 0
					cmd(11) = $B0
				Case #Controller_IO_DATA
					cmd(2) = $D1
					cmd(3) = 0
					cmd(5) = $4F
				   cmd(6) = $C2
				   cmd(7) = 0
				   cmd(8) = $B0
				Case #Controller_LOGITEC
					cmd(2) = $D1
					cmd(5) = $4F
					cmd(6) = $C2
					cmd(7) = 0
					cmd(8) = $B0
					cmd(9) = $4C
				Case #Controller_JMICRON
					cmd(5) = $D1
					cmd(7) = 1
					cmd(8) = $4F
					cmd(9) = $C2
					cmd(10) = 0
					cmd(11) = $B0
				Case #Controller_CYPRESS
					cmd(6) = $D1
					cmd(7) = 0
					cmd(9) = $4F
					cmd(10) = $C2
					cmd(11) = 0
					cmd(12) = $B0
			EndSelect
			HDD_SPTD(-16, @bArrOut(), SizeOf(SENDCMDOUTPARAMS))
		EndIf
	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 = $1b0503
			CopyMemory(@"SCSIDISK", @\Signature, 8)
		EndWith
		With *pin
			\irDriveRegs\bFeaturesReg	= $d1;command
			\irDriveRegs\bSectorCountReg	= 1
			\irDriveRegs\bSectorNumberReg	= 1
			\irDriveRegs\bCylLowReg		= $4f;#SMART_CYL_LOW
			\irDriveRegs\bCylHighReg	= $c2;#SMART_CYL_HI
			\irDriveRegs\bCommandReg	= $b0;#SMART_CMD
			\cBufferSize			= #SCSI_MINIPORT_BUFFER_SIZE
			\bDriveNumber			= SCSITargetID
		EndWith
		bRet = 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.l, #Null)
		CopyMemory(@buffer() + SizeOf(SRB_IO_CONTROL),@bArrOut(), SizeOf(SENDCMDOUTPARAMS))
	EndIf
  For i=0 To 29
  	If bArrOut(18 + i * 12) > 0
  		For j.l=0 To di(HDDCount)\NumAttributes
  			If bArrOut(18 + i * 12) = di(HDDCount)\Attributes[j]\AttrID
  				di(HDDCount)\Attributes[j]\AttrThreshold = bArrOut(19 + i * 12)
  			EndIf
  		Next
  	EndIf
  Next
EndProcedure

Procedure.s DiskStatus()
error.l
caution.l
flagUnknown.l = 1
For j = 0 To di(HDDCount)\NumAttributes-1
	If di(HDDCount)\Attributes[j]\AttrID <> $BE And di(HDDCount)\Attributes[j]\AttrThreshold <> 0 And di(HDDCount)\Attributes[j]\AttrValue <= di(HDDCount)\Attributes[J]\AttrThreshold
		error+1
	EndIf
	Select di(HDDCount)\Attributes[j]\AttrID
;		Case 5: ;;  Reallocated Sectors Count
;; 		Case 0xC4: ;  Reallocation Event Count
;		Case $C5:; ;  Current Pending Sector Count
;		Case $C6: ;;  Off-Line Scan Uncorrectable Sector Count
		Case 5, $C4, $C5, $C6
			If di(HDDCount)\Attributes[j]\AttrRaw & $00FFFFFFFF = $FFFFFFFF
				flagUnknown = 0
			Else
				caution + di(HDDCount)\Attributes[j]\AttrRaw & $FF + (di(HDDCount)\Attributes[j]\AttrRaw >> 8) & $FF
				flagUnknown = 0
			EndIf
	EndSelect
Next

	If error > 0
		ProcedureReturn "Bad"
	ElseIf flagUnknown = 1
		ProcedureReturn "Unknown"
	ElseIf caution > 0
		ProcedureReturn "Attention"
	Else
		ProcedureReturn "Good"
	EndIf

EndProcedure

Procedure.l HDDInfo(CurrentDrive.l, SCSIPort.l, SCSITargetID.l)
	;DebugMe("Current drive = " + Str(CurrentDrive))
sYesNo.s: USB_Drive = 0
OpenSmart(CurrentDrive, SCSIPort)
dummy.l
ClearStructure(@idsec,DeviceData)
		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
	         \irDriveRegs\bCommandReg = $EC;CByte(IDCmd)
           	\bDriveNumber = CurrentDrive
          EndWith
          Result = DeviceIoControl_(hdh, #DFP_RECEIVE_DRIVE_DATA, @bin, SizeOf(SENDCMDINPARAMS), @bout(), 528,@dummy,0)
          If dummy > 0
          	CopyMemory(@bout(16),@idsec,512)
          Else; no data recieved maybe it is a USB drive.
				;SAT 1
				cmd(0) = $A1
				cmd(1) = 8
				cmd(2) = $E
				cmd(3) = 0
				cmd(7) = 0
				cmd(8) = $A0
				cmd(9) = $EC
				cmd(16) = 12
				If HDD_SPTD(0, @idsec, 512) < 100
					;SAT 2
					cmd(8) = $B0
					If HDD_SPTD(0, @idsec, 512) < 100
						;SUNPLUS 1
						cmd(0) = $F8
						cmd(1) = 0
						cmd(2) = $22
						cmd(3) = $10
						cmd(4) = 0
						cmd(5) = 0
						cmd(6) = 1
						cmd(7) = 0
						cmd(8) = 0
						cmd(9) = 0
						cmd(10) = $A0
						cmd(11) = $EC
						cmd(16) = 12
						If HDD_SPTD(0, @idsec, 512) < 100
							;SUNPLUS 2
							cmd(10) = $B0
							If HDD_SPTD(0, @idsec, 512) < 100
								;IO_DATA 1
								cmd(0) = $E3
								cmd(1) = 0
								cmd(2) = 0
								cmd(3) = 1
								cmd(4) = 0
								cmd(5) = 0
								cmd(6) = 0
								cmd(7) = $A0
								cmd(8) = $EC
								cmd(9) = 0
								cmd(10) = 0
								cmd(11) = 0
								cmd(16) = 12
								If HDD_SPTD(0, @idsec, 512) < 100
									;IO_DATA 2
									cmd(7) = $B0
									If HDD_SPTD(0, @idsec, 512) < 100
										;LOGITEC 1
										cmd(0) = $E0
										cmd(1) = 0
										cmd(2) = 0
										cmd(3) = 0
										cmd(4) = 0
										cmd(5) = 0
										cmd(6) = 0
										cmd(7) = $A0
										cmd(8) = $EC
										cmd(9) = $C
										cmd(10) = 0
										cmd(11) = 0
										cmd(16) = 10
										If HDD_SPTD(0, @idsec, 512) < 100
											;LOGITEC 2
											cmd(7) = $B0
											If HDD_SPTD(0, @idsec, 512) < 100
												;JMICRON 1
												cmd(0) = $DF
												cmd(1) = $10
												cmd(2) = 0
												cmd(3) = 2
												cmd(4) = 0
												cmd(5) = 0
												cmd(6) = 1
												cmd(7) = 0
												cmd(8) = 0
												cmd(9) = 0
												cmd(10) = $A0
												cmd(11) = $EC
												cmd(16) = 12
												If HDD_SPTD(0, @idsec, 512) < 100
													;JMICRON 2
													cmd(10) = $B0
													If HDD_SPTD(0, @idsec, 512) < 100
														;CYPRESS 1
														cmd(0) = $24
														cmd(1) = $24
														cmd(2) = 0
														cmd(3) = $BE
														cmd(4) = 0
														cmd(5) = 0
														cmd(6) = 0
														cmd(7) = 1
														cmd(8) = 0
														cmd(9) = 0
														cmd(10) = 0
														cmd(11) = $A0
														cmd(12) = $EC
														cmd(16) = 16
														If HDD_SPTD(0, @idsec, 512) < 100
															;CYPRESS 2
															cmd(11) = $B0
															If HDD_SPTD(0, @idsec, 512) > 100
																USB_Drive = #Controller_CYPRESS
															EndIf
														Else
															USB_Drive = #Controller_CYPRESS
														EndIf
													Else
														USB_Drive = #Controller_JMICRON
													EndIf
												Else
													USB_Drive = #Controller_JMICRON
												EndIf
											Else
												USB_Drive = #Controller_LOGITEC
											EndIf
										Else
											USB_Drive = #Controller_LOGITEC
										EndIf
									Else
										USB_Drive = #Controller_IO_DATA
									EndIf
								Else
									USB_Drive = #Controller_IO_DATA
								EndIf
							Else
								USB_Drive = 22;#Controller_SUNPLUS
							EndIf
						Else
							USB_Drive = 33;#Controller_SUNPLUS
						EndIf
					Else
						USB_Drive = #Controller_SAT
					EndIf
				Else
					USB_Drive = #Controller_SAT
				EndIf
			EndIf
		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
		If dummy > 0 Or USB_Drive > 0 ;and hdh > 0
			HDDCount + 1
			aa.DRIVE_LAYOUT_INFORMATION
			PartCount.l
			i=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
			    PartCount + 1
			  EndIf
			Next
			;DebugMe("hdd data")
			If HDDCount > 10: ReDim di.DriveInfo(HDDCount): EndIf
			di(HDDCount)\Model = Trim(ChangeHighLowByte(PeekS(@idsec\ModelNumber[0],40,#PB_Ascii)))
			di(HDDCount)\FirmWare = Trim(ChangeHighLowByte(PeekS(@idsec\FirmwareRev[0],8,#PB_Ascii)))
			di(HDDCount)\SerialNumber =Trim(ChangeHighLowByte(PeekS(@idsec\SerialNumber[0],20,#PB_Ascii)))
			If di(HDDCount)\Model = "" And di(HDDCount)\FirmWare = ""
				DontAdd = 1
				Goto try_next_way
			Else
				For x=1 To Len(di(HDDCount)\Model)
					If Asc(Mid(di(HDDCount)\Model,x, 1)) > 255 Or Asc(Mid(di(HDDCount)\Model,x, 1)) < 32
						DontAdd = 1
						Goto try_next_way
					EndIf
				Next
			EndIf
			di(HDDCount)\PartitionCount = Str(PartCount): PartCount = 0
			di(HDDCount)\Family = DiskFamily(di(HDDCount)\Model)
			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 idsec\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 + " , " + "enabled : " + "Mode  0": EndIf
				If (idsec\MultiWordDma >> 9) & 1 = 1: di(HDDCount)\Flags\MWDMA + " , " + "enabled : " + "Mode  1": EndIf
				If (idsec\MultiWordDma >> 10) & 1 = 1: di(HDDCount)\Flags\MWDMA + " , " + "enabled : " + "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"
				di(HDDCount)\RotationRate = "---- (SSD)"
			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")
		Else
			;#IOCTL_STORAGE_QUERY_PROPERTY
			try_next_way:
			udtQuery.STORAGE_PROPERTY_QUERY
			udtOut.STORAGE_DEVICE_DESCRIPTOR
			Result = DeviceIoControl_(hdh, $2D1400, udtQuery,SizeOf(udtQuery), @udtOut, SizeOf(udtOut), @dwOutBytes, 0)
			If dwOutBytes > 100
				If DontAdd = 0: HDDCount + 1: EndIf
				If HDDCount > 10: ReDim di.DriveInfo(HDDCount): EndIf
				di(HDDCount)\Model = Trim(PeekS(@udtOut +  udtOut\VendorIdOffset,-1,#PB_Ascii)) + Trim(PeekS(@udtOut + udtOut\ProductIdOffset,-1,#PB_Ascii))
				di(HDDCount)\FirmWare =  PeekS(@udtOut +  udtOut\ProductRevisionOffset,-1,#PB_Ascii)
				di(HDDCount)\SerialNumber = Trim(PeekS(@udtOut + udtOut\SerialNumberOffset,-1,#PB_Ascii))
				Select(udtOut\Bustype)
					Case #BusTypeUnknown, #BusTypeScsi
						di(HDDCount)\InterfaceType = "SCSI"
					Case #BusTypeAtapi
						di(HDDCount)\InterfaceType = "ATAPI"
					Case #BusTypeAta
						di(HDDCount)\InterfaceType = "ATA"
					Case #BusType1394, #BusTypeSsa, #BusTypeFibre, #BusTypeUsb
				     di(HDDCount)\InterfaceType = "USB"
				  	Case #BusTypeRAID
				       di(HDDCount)\InterfaceType = "RAID"
			       Case #BusTypeMaxReserved
			       Default
						di(HDDCount)\InterfaceType = "Bustype = " + Str(udtOut\BusType)
				EndSelect
			EndIf
		EndIf
		CloseHandle_(hdh)
EndProcedure

Procedure SaveFile(type.a)
;type = 1 save current disk
;type = 0 save all disks
Pattern$ = "Text (*.txt)|*.txt|All files (*.*)|*.*"
Pattern = 0
File$ = SaveFileRequester("Please choose file name", "", Pattern$, Pattern)
If File$
	If ReadFile(0,File$);file already exists
		CloseFile(0)
		i=MessageRequester("Warning","File already exists. Overwrite ?",#PB_MessageRequester_YesNo)
		If i= #PB_MessageRequester_No			
			ProcedureReturn
		EndIf
	EndIf
	If GetExtensionPart(File$) = ""
		File$ + ".txt"
	EndIf
	If type = 1
		FromDisk = GetGadgetState(2)
		ToDisk = FromDisk
		x = ToDisk
	Else
		FromDisk = 0
		ToDisk = HDDCount
	EndIf
	ii = OpenFile(#PB_Any,File$)
	For i = FromDisk To ToDisk
		WriteStringN(ii,"Disk #" + x)
		If di(i)\LBASectors = "" And di(i)\InterfaceType = "USB"
			WriteStringN(ii,"Model"+ " : " + di(i)\Model)
			WriteStringN(ii,"FirmWare"+ " : " + di(i)\FirmWare)
			WriteStringN(ii,"Serial Number"+ " : " + di(i)\SerialNumber)
			WriteStringN(ii,"Interface Type"+ " : " + di(i)\InterfaceType)
		Else
			WriteStringN(ii,"Model            "+ " : " + di(i)\Model)
			WriteStringN(ii,"Family           "+ " : " + di(i)\Family)
			WriteStringN(ii,"Serial Number    "+ " : " + di(i)\SerialNumber)
			WriteStringN(ii,"FirmWare         "+ " : " + di(i)\FirmWare)
			WriteStringN(ii,"Buffer Size      "+ " : " + di(i)\BufferSize)
			WriteStringN(ii,"ECC Bytes        "+ " : " + di(i)\ECCBytes)
			WriteStringN(ii,"LBA Sectors      "+ " : " + di(i)\LBASectors)
			WriteStringN(ii,"Theor Capacity   "+ " : " + di(i)\TheoriticalCapacity)
			WriteStringN(ii,"Real Capacity    "+ " : " + di(i)\RealCapacity)
			WriteStringN(ii,"Temperature      "+ " : " + di(i)\Temperature)
			WriteStringN(ii,"Power On Count   "+ " : " + di(i)\CountsOn)
			WriteStringN(ii,"Power On Hours   "+ " : " + di(i)\HoursOn)
			WriteStringN(ii,"Interface Type   "+ " : " + di(i)\InterfaceType)
			WriteStringN(ii,"Cur Transfer Mode"+ " : " + di(i)\CurTransferMode)
			WriteStringN(ii,"Max Transfer Mode"+ " : " + di(i)\MaxTransferMode)
			WriteStringN(ii,"Standard         "+ " : " + di(i)\Standard)
			WriteStringN(ii,"Rotation rate    "+ " : " + di(i)\RotationRate)
			WriteStringN(ii,"Partition Count  "+ " : " + di(i)\PartitionCount)
			WriteStringN(ii,"Disk Status      "+ " : " + di(i)\DiskStatus)
			WriteStringN(ii,"Is SSD           "+ " : " + di(i)\Flags\SSD)
			WriteStringN(ii,"UDMA             "+ " : " + di(i)\Flags\UDMA)
			WriteStringN(ii,"MWDMA            "+ " : " + di(i)\Flags\MWDMA)
			WriteStringN(ii,"PIO              "+ " : " + di(i)\Flags\PIO)
			WriteStringN(ii,"")
			WriteStringN(ii,"Flags")
			WriteStringN(ii,"S.M.A.R.T.                               "+ " : " + di(i)\Flags\SMART)
			WriteStringN(ii,"48bit Logical Block Addressing  ( LBA48 )"+ " : " + di(i)\Flags\LBA48)
			WriteStringN(ii,"Automatic  Acoustic  Management  ( AAM ) "+ " : " + di(i)\Flags\AAM)
			WriteStringN(ii,"Power Management  ( PM )                 "+ " : " + di(i)\Flags\PM)
			WriteStringN(ii,"Advanced Power Management  ( APM )       "+ " : " + di(i)\Flags\APM)
			WriteStringN(ii,"Power-up in Standby  ( PUIS )            "+ " : " + di(i)\Flags\PUIS)
			WriteStringN(ii,"Device Configuration Overlays  ( DCO )   "+ " : " + di(i)\Flags\DCO)
			WriteStringN(ii,"SATA  Native  Command  Queuing  ( NCQ )  "+ " : " + di(i)\Flags\NCQ)
			WriteStringN(ii,"Tagged  Command  Queuing  ( TCQ )        "+ " : " + di(i)\Flags\TCQ)
			WriteStringN(ii,"Security Mode                            "+ " : " + di(i)\Flags\SecMode)
			WriteStringN(ii,"NonVolatile Cache                        "+ " : " + di(i)\Flags\NVCache)
			WriteStringN(ii,"TRIM function                            "+ " : " + di(i)\Flags\TRIM)
			WriteStringN(ii,"SMART Command Transport  ( SCT )         "+ " : " + di(i)\Flags\SCT)
			WriteStringN(ii,"Input/Output  Channel  ReaDY  ( IORDY )  "+ " : " + di(i)\Flags\IORDY)
			WriteStringN(ii,"Compact Flash Association  ( CFA )       "+ " : " + di(i)\Flags\CFA)
			WriteStringN(ii,"Download  Microcode  command             "+ " : " + di(i)\Flags\DMicro)
			WriteStringN(ii,"")
			WriteStringN(ii,"Attributes")
			WriteStringN(ii,"  #   Name                                                Current Worst Threshold  Raw value")
			For iii=0 To di(i)\NumAttributes-1
				If di(i)\Attributes[iii]\AttrName="": Break: EndIf
				WriteStringN(ii,RSet(Str(di(i)\Attributes[iii]\AttrID),3," ") + " : " + LSet(di(i)\Attributes[iii]\AttrName,50," ")+ " : " + RSet(Str(di(i)\Attributes[iii]\AttrValue),5," ")+ " : " + RSet(Str(di(i)\Attributes[iii]\AttrWorstValue),3," ") + " : " + RSet(Str(di(i)\Attributes[iii]\AttrThreshold),7," ")+ " : " + RSet(Hex(di(i)\Attributes[iii]\AttrRaw),12,"0"))
			Next
			WriteStringN(ii,"")
			WriteStringN(ii,"")
			x + 1
		EndIf
	Next
	CloseFile(ii)
	MessageRequester("","File created successfully.")
EndIf
EndProcedure 
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by doctorized »

And the rest of the code:

Code: Select all

For i=0 To 5
	HDDInfo(i,-1,-1)
Next
For i=0 To 16
	For ii=0 To 8
		HDDInfo(-1,i,ii)
	Next
Next

If OpenWindow(0, 100, 200, 620, 620, "Hard Disk Info", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
;If CreateGadgetList(WindowID(0))   
 ListIconGadget(0,5,40,610,260,"Item",238,#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
 AddGadgetColumn(0,1,"Data",350)
 ListIconGadget(1,5,310,610,300,"ID",35,#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
 AddGadgetColumn(1,1,"Name",270)
 AddGadgetColumn(1,2,"Current",60)
 AddGadgetColumn(1,3,"Worst",60)
 AddGadgetColumn(1,4,"Threshold",60)
 AddGadgetColumn(1,5,"Raw",100)
 ComboBoxGadget(2, 5, 10, 260, 20)
 TextGadget(3,280,14,150,20,"<-- Please select a drive.")
 ButtonGadget(4,410,14,100,20,"Save current disk")
 ButtonGadget(5,516,14,100,20,"Save all disks")
;EndIf

For i=0 To HDDCount
	AddGadgetItem(2,-1,di(i)\Model)
Next
Goto slct_gadget
  Repeat
    EventID = WaitWindowEvent()
    If EventID = #PB_Event_CloseWindow
      Quit = 1
    ElseIf EventID = #PB_Event_Gadget
    	Select EventGadget()
    		Case 2
slct_gadget:
	      	If CurrentHDD <> GetGadgetState(2)
					CurrentHDD = GetGadgetState(2)
			    	If CurrentHDD < 0: CurrentHDD = 0: EndIf
					SetGadgetState(2, CurrentHDD)
					ClearGadgetItems(0)
					ClearGadgetItems(1)
					If di(CurrentHDD)\LBASectors = "" And di(CurrentHDD)\InterfaceType = "USB"
						AddGadgetItem(0,-1,"Model"+Chr(10)+di(CurrentHDD)\Model)
						AddGadgetItem(0,-1,"FirmWare"+Chr(10)+di(CurrentHDD)\FirmWare)
						AddGadgetItem(0,-1,"Serial Number"+Chr(10)+di(CurrentHDD)\SerialNumber)
						AddGadgetItem(0,-1,"Interface Type"+Chr(10)+di(CurrentHDD)\InterfaceType)
					Else
						AddGadgetItem(0,-1,"Model"+Chr(10)+di(CurrentHDD)\Model)
						AddGadgetItem(0,-1,"Family"+Chr(10)+di(CurrentHDD)\Family)
						AddGadgetItem(0,-1,"Serial Number"+Chr(10)+di(CurrentHDD)\SerialNumber)
						AddGadgetItem(0,-1,"FirmWare"+Chr(10)+di(CurrentHDD)\FirmWare)
						AddGadgetItem(0,-1,"Buffer Size"+Chr(10)+di(CurrentHDD)\BufferSize)
						AddGadgetItem(0,-1,"ECC Bytes"+Chr(10)+di(CurrentHDD)\ECCBytes)
						AddGadgetItem(0,-1,"LBA Sectors"+Chr(10)+di(CurrentHDD)\LBASectors)
						AddGadgetItem(0,-1,"Theor Capacity"+Chr(10)+di(CurrentHDD)\TheoriticalCapacity)
						AddGadgetItem(0,-1,"Real Capacity"+Chr(10)+di(CurrentHDD)\RealCapacity)
						AddGadgetItem(0,-1,"Temperature"+Chr(10)+di(CurrentHDD)\Temperature)
						AddGadgetItem(0,-1,"Power On Count"+Chr(10)+di(CurrentHDD)\CountsOn)
						AddGadgetItem(0,-1,"Power On Hours"+Chr(10)+di(CurrentHDD)\HoursOn)
						AddGadgetItem(0,-1,"Interface Type"+Chr(10)+di(CurrentHDD)\InterfaceType)
						AddGadgetItem(0,-1,"Cur Transfer Mode"+Chr(10)+di(CurrentHDD)\CurTransferMode)
						AddGadgetItem(0,-1,"Max Transfer Mode"+Chr(10)+di(CurrentHDD)\MaxTransferMode)
						AddGadgetItem(0,-1,"Standard"+Chr(10)+di(CurrentHDD)\Standard)
						AddGadgetItem(0,-1,"Rotation rate"+Chr(10)+di(CurrentHDD)\RotationRate)
						AddGadgetItem(0,-1,"Partition Count"+Chr(10)+di(CurrentHDD)\PartitionCount)
						AddGadgetItem(0,-1,"Disk Status"+Chr(10)+di(CurrentHDD)\DiskStatus)
						AddGadgetItem(0,-1,"Is SSD"+Chr(10)+di(CurrentHDD)\Flags\SSD)
						AddGadgetItem(0,-1,"UMDA"+Chr(10)+di(CurrentHDD)\Flags\UDMA)
						AddGadgetItem(0,-1,"MWDMA"+Chr(10)+di(CurrentHDD)\Flags\MWDMA)
						AddGadgetItem(0,-1,"PIO"+Chr(10)+di(CurrentHDD)\Flags\PIO)
						AddGadgetItem(0,-1,"Flags")
						SetGadgetItemColor(0,CountGadgetItems(0)-1,#PB_Gadget_FrontColor,$d06000)
						AddGadgetItem(0,-1,"S.M.A.R.T."+Chr(10)+di(CurrentHDD)\Flags\SMART)
						AddGadgetItem(0,-1,"48bit Logical Block Addressing  ( LBA48 )" + Chr(10) + di(CurrentHDD)\Flags\LBA48)
						AddGadgetItem(0,-1,"Automatic  Acoustic  Management  ( AAM )" + Chr(10) + di(CurrentHDD)\Flags\AAM)
						AddGadgetItem(0,-1,"Power Management  ( PM )" + Chr(10) + di(CurrentHDD)\Flags\PM)
						AddGadgetItem(0,-1,"Advanced Power Management  ( APM )" + Chr(10) + di(CurrentHDD)\Flags\APM)
						AddGadgetItem(0,-1,"Power-up in Standby  ( PUIS )" + Chr(10) + di(CurrentHDD)\Flags\PUIS)
						;AddGadgetItem(0,-1,"SETMAX" + chr(10) + di(CurrentHDD)\Flags\SETMAX)
						AddGadgetItem(0,-1,"Device Configuration Overlays  ( DCO )" + Chr(10) + di(CurrentHDD)\Flags\DCO)
						AddGadgetItem(0,-1,"SATA  Native  Command  Queuing  ( NCQ )" + Chr(10) + di(CurrentHDD)\Flags\NCQ)
						AddGadgetItem(0,-1,"Tagged  Command  Queuing  ( TCQ )" + Chr(10) + di(CurrentHDD)\Flags\TCQ)
						AddGadgetItem(0,-1,"Security Mode" + Chr(10) + di(CurrentHDD)\Flags\SecMode)
						AddGadgetItem(0,-1,"NonVolatile Cache" + Chr(10) + di(CurrentHDD)\Flags\NVCache)
						AddGadgetItem(0,-1,"TRIM function" + Chr(10) + di(CurrentHDD)\Flags\TRIM)
						AddGadgetItem(0,-1,"SMART Command Transport  ( SCT )" + Chr(10) + di(CurrentHDD)\Flags\SCT)
						AddGadgetItem(0,-1,"Input/Output  Channel  ReaDY  ( IORDY )" + Chr(10) + di(CurrentHDD)\Flags\IORDY)
						AddGadgetItem(0,-1,"Compact Flash Association  ( CFA )" + Chr(10) + di(CurrentHDD)\Flags\CFA)
						AddGadgetItem(0,-1,"Download  Microcode  command" + Chr(10) + di(CurrentHDD)\Flags\DMicro)
						For i=0 To di(CurrentHDD)\NumAttributes-1
							If di(CurrentHDD)\Attributes[i]\AttrName="": Break: EndIf
							AddGadgetItem(1,-1,Str(di(CurrentHDD)\Attributes[i]\AttrID) + Chr(10) + di(CurrentHDD)\Attributes[i]\AttrName + Chr(10) + Str(di(CurrentHDD)\Attributes[i]\AttrValue) + Chr(10) + Str(di(CurrentHDD)\Attributes[i]\AttrWorstValue) + Chr(10) + Str(di(CurrentHDD)\Attributes[i]\AttrThreshold) + Chr(10) + RSet(Hex(di(CurrentHDD)\Attributes[i]\AttrRaw),12,"0"))
						Next
					EndIf
				EndIf
			Case 4
				SaveFile(1)
			Case 5
				SaveFile(0)
		EndSelect
    EndIf

  Until Quit = 1
  
EndIf

End 
ricky
New User
New User
Posts: 8
Joined: Fri Sep 07, 2012 9:27 am
Location: Suisse

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by ricky »

Maybe, i'm stupid. It's a same file? Could you please give me a link to download a file.

Edit: strange it doesn't work!
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by doctorized »

ricky wrote:Maybe, i'm stupid. It's a same file? Could you please give me a link to download a file.

Edit: strange it doesn't work!
Did you enable admin rights? Without admin rights it cannot run. Here is your link: https://arahiotis.sites.sch.gr/HDDInfo.rar
The way looks like the same but is not really the same. The user gives the file name, so it not the same. Ask if you have further questions.
Last edited by doctorized on Tue Nov 22, 2022 10:42 am, edited 1 time in total.
ricky
New User
New User
Posts: 8
Joined: Fri Sep 07, 2012 9:27 am
Location: Suisse

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by ricky »

Hello,

I tried your version, but it crash immediatly, why? But with the syntax check nothing is wrong. I compile with the version 5.30. I test on a x64 system.
Image below:
https://www.dropbox.com/s/g1xf9ymsxpgzr ... r.png?dl=0
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by doctorized »

ricky wrote:I tried your version, but it crash immediatly
Yes, suddenly x64 version crushes to me too. x86 version works fine. PB 5.30 here too so I will check it out.


EDIT:
In line 1193 change

Code: Select all

CopyMemory(@buffer() + SizeOf(SRB_IO_CONTROL)+16,@idsec, SizeOf(SENDCMDOUTPARAMS))
to

Code: Select all

CopyMemory(@buffer() + SizeOf(SRB_IO_CONTROL)+16,@idsec, SizeOf(DeviceData))
After SaveFile() Procedure delete the code you have and add this:

Code: Select all

Procedure ShowData()
CurrentHDD = GetGadgetState(2)
If CurrentHDD < 0: CurrentHDD = 0: EndIf
SetGadgetState(2, CurrentHDD)
ClearGadgetItems(0)
ClearGadgetItems(1)
If di(CurrentHDD)\LBASectors = "" And di(CurrentHDD)\InterfaceType = "USB"
	AddGadgetItem(0,-1,"Model"+Chr(10)+di(CurrentHDD)\Model)
	AddGadgetItem(0,-1,"FirmWare"+Chr(10)+di(CurrentHDD)\FirmWare)
	AddGadgetItem(0,-1,"Serial Number"+Chr(10)+di(CurrentHDD)\SerialNumber)
	AddGadgetItem(0,-1,"Interface Type"+Chr(10)+di(CurrentHDD)\InterfaceType)
Else
	AddGadgetItem(0,-1,"Model"+Chr(10)+di(CurrentHDD)\Model)
	AddGadgetItem(0,-1,"Family"+Chr(10)+di(CurrentHDD)\Family)
	AddGadgetItem(0,-1,"Serial Number"+Chr(10)+di(CurrentHDD)\SerialNumber)
	AddGadgetItem(0,-1,"FirmWare"+Chr(10)+di(CurrentHDD)\FirmWare)
	AddGadgetItem(0,-1,"Buffer Size"+Chr(10)+di(CurrentHDD)\BufferSize)
	AddGadgetItem(0,-1,"ECC Bytes"+Chr(10)+di(CurrentHDD)\ECCBytes)
	AddGadgetItem(0,-1,"LBA Sectors"+Chr(10)+di(CurrentHDD)\LBASectors)
	AddGadgetItem(0,-1,"Theor Capacity"+Chr(10)+di(CurrentHDD)\TheoriticalCapacity)
	AddGadgetItem(0,-1,"Real Capacity"+Chr(10)+di(CurrentHDD)\RealCapacity)
	AddGadgetItem(0,-1,"Temperature"+Chr(10)+di(CurrentHDD)\Temperature)
	AddGadgetItem(0,-1,"Power On Count"+Chr(10)+di(CurrentHDD)\CountsOn)
	AddGadgetItem(0,-1,"Power On Hours"+Chr(10)+di(CurrentHDD)\HoursOn)
	AddGadgetItem(0,-1,"Interface Type"+Chr(10)+di(CurrentHDD)\InterfaceType)
	AddGadgetItem(0,-1,"Cur Transfer Mode"+Chr(10)+di(CurrentHDD)\CurTransferMode)
	AddGadgetItem(0,-1,"Max Transfer Mode"+Chr(10)+di(CurrentHDD)\MaxTransferMode)
	AddGadgetItem(0,-1,"Standard"+Chr(10)+di(CurrentHDD)\Standard)
	AddGadgetItem(0,-1,"Rotation rate"+Chr(10)+di(CurrentHDD)\RotationRate)
	AddGadgetItem(0,-1,"Partition Count"+Chr(10)+di(CurrentHDD)\PartitionCount)
	AddGadgetItem(0,-1,"Disk Status"+Chr(10)+di(CurrentHDD)\DiskStatus)
	AddGadgetItem(0,-1,"Is SSD"+Chr(10)+di(CurrentHDD)\Flags\SSD)
	AddGadgetItem(0,-1,"UMDA"+Chr(10)+di(CurrentHDD)\Flags\UDMA)
	AddGadgetItem(0,-1,"MWDMA"+Chr(10)+di(CurrentHDD)\Flags\MWDMA)
	AddGadgetItem(0,-1,"PIO"+Chr(10)+di(CurrentHDD)\Flags\PIO)
	AddGadgetItem(0,-1,"Flags")
	SetGadgetItemColor(0,CountGadgetItems(0)-1,#PB_Gadget_FrontColor,$d06000)
	AddGadgetItem(0,-1,"S.M.A.R.T."+Chr(10)+di(CurrentHDD)\Flags\SMART)
	AddGadgetItem(0,-1,"48bit Logical Block Addressing  ( LBA48 )" + Chr(10) + di(CurrentHDD)\Flags\LBA48)
	AddGadgetItem(0,-1,"Automatic  Acoustic  Management  ( AAM )" + Chr(10) + di(CurrentHDD)\Flags\AAM)
	AddGadgetItem(0,-1,"Power Management  ( PM )" + Chr(10) + di(CurrentHDD)\Flags\PM)
	AddGadgetItem(0,-1,"Advanced Power Management  ( APM )" + Chr(10) + di(CurrentHDD)\Flags\APM)
	AddGadgetItem(0,-1,"Power-up in Standby  ( PUIS )" + Chr(10) + di(CurrentHDD)\Flags\PUIS)
	;AddGadgetItem(0,-1,"SETMAX" + chr(10) + di(CurrentHDD)\Flags\SETMAX)
	AddGadgetItem(0,-1,"Device Configuration Overlays  ( DCO )" + Chr(10) + di(CurrentHDD)\Flags\DCO)
	AddGadgetItem(0,-1,"SATA  Native  Command  Queuing  ( NCQ )" + Chr(10) + di(CurrentHDD)\Flags\NCQ)
	AddGadgetItem(0,-1,"Tagged  Command  Queuing  ( TCQ )" + Chr(10) + di(CurrentHDD)\Flags\TCQ)
	AddGadgetItem(0,-1,"Security Mode" + Chr(10) + di(CurrentHDD)\Flags\SecMode)
	AddGadgetItem(0,-1,"NonVolatile Cache" + Chr(10) + di(CurrentHDD)\Flags\NVCache)
	AddGadgetItem(0,-1,"TRIM function" + Chr(10) + di(CurrentHDD)\Flags\TRIM)
	AddGadgetItem(0,-1,"SMART Command Transport  ( SCT )" + Chr(10) + di(CurrentHDD)\Flags\SCT)
	AddGadgetItem(0,-1,"Input/Output  Channel  ReaDY  ( IORDY )" + Chr(10) + di(CurrentHDD)\Flags\IORDY)
	AddGadgetItem(0,-1,"Compact Flash Association  ( CFA )" + Chr(10) + di(CurrentHDD)\Flags\CFA)
	AddGadgetItem(0,-1,"Download  Microcode  command" + Chr(10) + di(CurrentHDD)\Flags\DMicro)
	For i=0 To di(CurrentHDD)\NumAttributes-1
		If di(CurrentHDD)\Attributes[i]\AttrName="": Break: EndIf
		AddGadgetItem(1,-1,Str(di(CurrentHDD)\Attributes[i]\AttrID) + Chr(10) + di(CurrentHDD)\Attributes[i]\AttrName + Chr(10) + Str(di(CurrentHDD)\Attributes[i]\AttrValue) + Chr(10) + Str(di(CurrentHDD)\Attributes[i]\AttrWorstValue) + Chr(10) + Str(di(CurrentHDD)\Attributes[i]\AttrThreshold) + Chr(10) + RSet(Hex(di(CurrentHDD)\Attributes[i]\AttrRaw),12,"0"))
	Next
EndIf
EndProcedure
			
For i=0 To 5
	HDDInfo(i,-1,-1)
Next
For i=0 To 16
	For ii=0 To 8
		HDDInfo(-1,i,ii)
	Next
Next

If OpenWindow(0, 100, 200, 620, 620, "Hard Disk Info", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_ScreenCentered)
	ListIconGadget(0,5,40,610,260,"Item",238,#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
	AddGadgetColumn(0,1,"Data",350)
	ListIconGadget(1,5,310,610,300,"ID",35,#PB_ListIcon_GridLines|#PB_ListIcon_FullRowSelect)
	AddGadgetColumn(1,1,"Name",270)
	AddGadgetColumn(1,2,"Current",60)
	AddGadgetColumn(1,3,"Worst",60)
	AddGadgetColumn(1,4,"Threshold",60)
	AddGadgetColumn(1,5,"Raw",100)
	ComboBoxGadget(2, 5, 10, 260, 20)
	TextGadget(3,280,14,150,20,"<-- Please select a drive.")
	ButtonGadget(4,410,14,100,20,"Save current disk")
	ButtonGadget(5,516,14,100,20,"Save all disks")
	
	For i=0 To HDDCount
		AddGadgetItem(2,-1,di(i)\Model)
	Next
	ShowData()
	Repeat
	EventID = WaitWindowEvent()
	If EventID = #PB_Event_CloseWindow
		Quit = 1
	ElseIf EventID = #PB_Event_Gadget
		Select EventGadget()
			Case 2
				ShowData()
			Case 4
				SaveFile(1)
			Case 5
				SaveFile(0)
		EndSelect
	EndIf
	
	Until Quit = 1

EndIf

End 
ricky
New User
New User
Posts: 8
Joined: Fri Sep 07, 2012 9:27 am
Location: Suisse

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by ricky »

Thanks, now it works.
But I want to have immediatly all infos in a file.

I remove the Procedure ShowData() and put only SaveFile(0) and it doesn't work, I have nothing in the file, why?
User avatar
doctorized
Addict
Addict
Posts: 856
Joined: Fri Mar 27, 2009 9:41 am
Location: Athens, Greece

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by doctorized »

ricky wrote:Thanks, now it works.
But I want to have immediatly all infos in a file.

I remove the Procedure ShowData() and put only SaveFile(0) and it doesn't work, I have nothing in the file, why?
After SaveFile() procedure and before SaveFile(0) did you leave:

Code: Select all

For i=0 To 5
	HDDInfo(i,-1,-1)
Next
For i=0 To 16
	For ii=0 To 8
		HDDInfo(-1,i,ii)
	Next
Next
If not, the data are not retrieved and the file is 100% empty.
ricky
New User
New User
Posts: 8
Joined: Fri Sep 07, 2012 9:27 am
Location: Suisse

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by ricky »

It works, thanks for your help.
kvitaliy
Enthusiast
Enthusiast
Posts: 162
Joined: Mon May 10, 2010 4:02 pm

Re: retrieve harddisk`s modell,serial,firmware (Windows only

Post by kvitaliy »

Is it possible to fix the code for working with external USB hard disks?
Simo_na
Enthusiast
Enthusiast
Posts: 177
Joined: Sun Mar 03, 2013 9:01 am

Re: retrieve harddisk`s modell,serial,firmware (Windows only)

Post by Simo_na »

This 'code' should be well preserved and updated, thanks for sharing.
Post Reply