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

Share your advanced PureBasic knowledge/code with the community.
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

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

Post by Thunder93 »

ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
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 »

Thunder93 wrote:Have you tried the following ... http://msdn.microsoft.com/en-ca/library ... s.85).aspx

?
I don't remember. I will see it. Now I see something else.... I will inform you when I will have news!
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 »

I found this code in C++

Code: Select all

target = $A0
type = CMD_TYPE_SAT
BOOL CAtaSmart::DoIdentifyDeviceSat(INT physicalDriveId, BYTE target, IDENTIFY_DEVICE* data, COMMAND_TYPE type)
{
	BOOL	bRet;
	HANDLE	hIoCtrl;
	DWORD	dwReturned;
	DWORD	length;

	SCSI_PASS_THROUGH_WITH_BUFFERS sptwb;

	if(data == NULL)
	{
		return	FALSE;
	}

	::ZeroMemory(data, sizeof(IDENTIFY_DEVICE));

	hIoCtrl = GetIoCtrlHandle(physicalDriveId);
	if(hIoCtrl == INVALID_HANDLE_VALUE)
	{
		return	FALSE;
	}

	::ZeroMemory(&sptwb,sizeof(SCSI_PASS_THROUGH_WITH_BUFFERS));

	sptwb.Spt.Length = sizeof(SCSI_PASS_THROUGH);
	sptwb.Spt.PathId = 0;
	sptwb.Spt.TargetId = 0;
	sptwb.Spt.Lun = 0;
	sptwb.Spt.SenseInfoLength = 24;
	sptwb.Spt.DataIn = SCSI_IOCTL_DATA_IN;
	sptwb.Spt.DataTransferLength = IDENTIFY_BUFFER_SIZE;
	sptwb.Spt.TimeOutValue = 2;
	sptwb.Spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf);
	sptwb.Spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, SenseBuf);


	if(type == CMD_TYPE_SAT)
	{
		sptwb.Spt.CdbLength = 12;
		sptwb.Spt.Cdb[0] = 0xA1;//ATA PASS THROUGH(12) OPERATION CODE(A1h)
		sptwb.Spt.Cdb[1] = (4 << 1) | 0; //MULTIPLE_COUNT=0,PROTOCOL=4(PIO Data-In),Reserved
		sptwb.Spt.Cdb[2] = (1 << 3) | (1 << 2) | 2;//OFF_LINE=0,CK_COND=0,Reserved=0,T_DIR=1(ToDevice),BYTE_BLOCK=1,T_LENGTH=2
		sptwb.Spt.Cdb[3] = 0;//FEATURES (7:0)
		sptwb.Spt.Cdb[4] = 1;//SECTOR_COUNT (7:0)
		sptwb.Spt.Cdb[5] = 0;//LBA_LOW (7:0)
		sptwb.Spt.Cdb[6] = 0;//LBA_MID (7:0)
		sptwb.Spt.Cdb[7] = 0;//LBA_HIGH (7:0)
		sptwb.Spt.Cdb[8] = target;
		sptwb.Spt.Cdb[9] = ID_CMD;//COMMAND
	}
	else
	{
		return FALSE;
	}

	length = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, DataBuf) + sptwb.Spt.DataTransferLength;

	bRet = ::DeviceIoControl(hIoCtrl, IOCTL_SCSI_PASS_THROUGH, 
		&sptwb, sizeof(SCSI_PASS_THROUGH),
		&sptwb, length,	&dwReturned, NULL);

	::CloseHandle(hIoCtrl);
	
	if(bRet == FALSE || dwReturned != length)
	{
		return	FALSE;
	}

	memcpy_s(data, sizeof(IDENTIFY_DEVICE), sptwb.DataBuf, sizeof(IDENTIFY_DEVICE));

	return	TRUE;
}
and I translated it as follows (I had a code that uses SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER structure so I used it):

Code: Select all

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
    ;Fill.l       ;
    SenseBuffer.a[64]       ; Debugging-Info from the drive
    DataBuffer.a[16384]
 EndStructure

pswb.t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER: OL.OVERLAPPED
Length.l: returned.l: i.l
status.l
;If fh = 0: ProcedureReturn 0: EndIf
;check the timeout
;If WFE: Timeout = 9999: ElseIf Timeout = 0: Timeout = 10: EndIf

With pswb\spt
	\length = SizeOf(t_SPTD)                                       ; size of the substructure
	\PathId = 0
	\TargetId = 0
	\Lun = 0
	\DataIn = 1                                     ; data dir
	\TimeOutValue = Timeout                            ; 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;PointerLen                   ; data len
	\DataBufferOffset = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\DataBuffer)    ; data buffer pointer
	\Cdb[0] = $A1
	\Cdb[1] = (4 << 1) | 0
	\Cdb[2] = (1 << 3) | (1 << 2) | 2
	\Cdb[3] = 0
	\Cdb[4] = 1
	\Cdb[5] = 0
	\Cdb[6] = 0
	\Cdb[7] = 0
	\Cdb[8] = $A0
	\Cdb[9] = 7

	\CdbLength = 12                                ; CDB len
EndWith
Length = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\DataBuffer) + pswb\spt\DataTransferLength;;SizeOf(pswb)                                ; size of the structure
hdh = CreateFile_("\\.\PhysicalDrive2",#GENERIC_READ | #GENERIC_WRITE, #FILE_SHARE_READ | #FILE_SHARE_WRITE,0, #OPEN_EXISTING, 0, 0)
;SPTD
status = DeviceIoControl_(hdh, $4d004, @pswb, Length, @pswb, Length, @returned, @OL)
DeviceIOControl seems to run ok, "returned" variable = 66 but DataBuffer is empty. Some values are in SenseBuffer. What do I do wrong? Something is not translated as it should be.... but what?
Last edited by doctorized on Fri Sep 12, 2014 1:19 pm, edited 1 time in total.
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 »

Thunder93 wrote:Have you tried the following ... http://msdn.microsoft.com/en-ca/library ... s.85).aspx

?
I tried it now with this code:

Code: Select all

OL.OVERLAPPED
hdh = CreateFile_("\\.\PhysicalDrive0",#GENERIC_READ | #GENERIC_WRITE, #FILE_SHARE_READ | #FILE_SHARE_WRITE,0, #OPEN_EXISTING, 0, 0) 
buf.s=Space(255)
DeviceIoControl_(hdh, 2952208, #Null, 0, @buf, 255, @returned, @OL)
Debug GetLastError_()
Debug buf
and GetLastError_() returns 1, incorrect function.
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

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

Post by Thunder93 »

CrystalDiskInfo does use WMI. I've changed the WMI service to 'Disabled' and stopped the service and upon CrystalDiskInfo launch, the WMI service configuration is reverted back.

The ProductID \ Model, should be-able to be retrieved even with docking station usage, and not resorting to WMI usage. Or requiring administrator privileges.

Regarding the link for serial information retrieval, forget about that method. That will just lead you down the wrong path. Apparently not every manufacturer chooses to support this.


.. I don't know what to tell you about your situation and not retrieving the Model information.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

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

Post by Thunder93 »

Instead of using CrystalDiskInfo, results from Winsim DiskId32 - http://www.winsim.com/diskid32/diskid32.html would be interesting.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
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 »

Thunder93 wrote:Instead of using CrystalDiskInfo, results from Winsim DiskId32 - http://www.winsim.com/diskid32/diskid32.html would be interesting.
I tried this app too and I do not remeber well what did it tell me and I am not at home to run it again. If I am not wrong, it told me the same with your code. CrystalDiskInfo stopped finding my disk when I turned SAT (Scsi / ATA Translation) off. I think I had turned WMI off before that. I am not sure. I did so many thing that I am not remembering now what I did. I only remember this, the deactivation of SAT. That's why I focused on this. When I will get back home I will have specific info to post.

EDIT: As I said before, CreateFile_() gets handle of the drive. That means (at least for me, I may be wrong) it is treated the same as my internal drives. The point is what more is needed for DeviceIOControl_() to return the info properly. It may be a small change, a value to some point that will do the job. But, is there any?
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 »

I plugged in my WD disk in the docking station and also my Transcend StoreJet 2.5" Portable USB 2.0 Storage Drive. Diskid32 shows the same as your code, it is obvious as they both use #IOCTL_STORAGE_QUERY_PROPERTY. The only difference is in the serial numbers. Diskid32 show correctly the serial numbers for both my internal drives, for WD shows the data a little bit altered. What I mean?
Your code tells WD-WCAV5H710181 which is correct, as we saw in CrystalDiskMark and I see on the disk (the disk refers it without "WD-" in front, just WCAV5H710181) but diskid32 tells: "DWW-AC5V7H0181 1", as it is changing high-low bytes (big-little endian). From the other hand, your code shows "2020202020202020202020205139354d3338544c" for my Seagate disk but diskid32 shows correctly: "9QM583LT". All these 20s are hex values of demical 32 which is space character. $51 is "Q", $39 is "9" and so on. Changing high-low byte and throughing away the spaces we take the right serial. When the serial contains only digits you must use your Hex2Dec() procedure and also this one:

Code: Select all

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
And now the Transcend disk. Your code (and diskid32) gives these:

Code: Select all

Drive K: is a 
 USB Device
ProductID=TS80GSJ25S      
ProductRevision=
VendorID=StoreJet
Serial=
CrystalDiskInfo is not showing this disk, even if I have enabled all the options in Function->Advanced feature->USB/IEEE1394 and also ATA_PASS_THROUGH and "Advanced disk search". My code is not showing this disk too. It takes a handle with CreateFile_("\\.\PhysicalDrive2",.....) and DeviceIOControl_() returns zero, GetLastError_() returns 50, the request is not supported, as it happens with the WD disk.

EDIT: I turn off all of the above settings in CrystalDiskInfo. I close the program and launch it again. WD is not detected. I turn SAT on and relaunch. WD is detected. So, I do something wrong with the translated code that I posted above. The point is what do I do wrong...... I missed something in the translation.
User avatar
Thunder93
Addict
Addict
Posts: 1788
Joined: Tue Mar 21, 2006 12:31 am
Location: Canada

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

Post by Thunder93 »

All I get is one character return from DataBuffer.
ʽʽSuccess is almost totally dependent upon drive and persistence. The extra energy required to make another effort or try another approach is the secret of winning.ʾʾ --Dennis Waitley
User avatar
Rings
Moderator
Moderator
Posts: 1427
Joined: Sat Apr 26, 2003 1:11 am

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

Post by Rings »

Thunder93 wrote:All I get is one character return from DataBuffer.
looks like a unicodestring
SPAMINATOR NR.1
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 »

Zero data are still returned. Only some bytes are returned in SenseBuffer without any valuable usage. Where are the 66 bytes that "returned" is talking about?

Code: Select all

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 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
    ;Fill.l       ;
    SenseBuffer.a[32]       ; Debugging-Info from the drive
    DataBuffer.a[512]
 EndStructure

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] = $A1
   \Cdb[1] = (4 << 1) | 0
   \Cdb[2] = (1 << 3) | (1 << 2) | 2
   \Cdb[3] = 0
   \Cdb[4] = 1
   \Cdb[5] = 0
   \Cdb[6] = 0
   \Cdb[7] = 0
   \Cdb[8] = $A0
   \Cdb[9] = 7

   \CdbLength = 12                                ; CDB len
EndWith
Length = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\DataBuffer) + pswb\spt\DataTransferLength;;SizeOf(pswb)                                ; size of the structure

hdh = CreateFile_("\\.\PhysicalDrive2",#GENERIC_READ | #GENERIC_WRITE, #FILE_SHARE_READ | #FILE_SHARE_WRITE,0, #OPEN_EXISTING, 0, 0)
status = DeviceIoControl_(hdh, $4d004, @pswb, SizeOf(t_SPTD), @pswb, Length, @returned, @OL)
Debug GetLastError_()
Debug returned
;ShowMemoryViewer(@pswb,SizeOf(DeviceData))
;CallDebugger
dev_data.DeviceData
CopyMemory(@pswb\DataBuffer,@dev_data,SizeOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER))
Debug SizeOf(t_SPTD)
ShowMemoryViewer(@dev_data,SizeOf(DeviceData))
EDIT: a combination of W32Dasm and Hiew revealed that this is the code to get the data from my WD external drive.
But I cannot understand something. From W32Dasm disassembling CrystalDiskInfo:

Code: Select all

mov al, byte ptr [ebp+0C]
mov [esp+26], 0C
mov [esp+3C], A1
mov [esp+3D], 08
mov [esp+3E], 0E
mov byte ptr [esp+3F], bl
mov byte ptr [esp+43], bl
mov byte ptr [esp+44], al
mov [esp+45], EC
that means:
[esp+26] = CdbLength
[esp+3C] = Cdb[0]
[esp+3D] = Cdb[1]
[esp+3E] = Cdb[2]
[esp+3F] = Cdb[3]
[esp+43] = Cdb[7]
[esp+44] = Cdb[8]
[esp+45] = Cdb[9]

with other words "\Cdb[4] = 1", "\Cdb[5] = 0" and "\Cdb[6] = 0" is missing from the assembly and "\Cdb[9] = $EC".
I think there is a disagreement between assembly and source of AtaSmart.cpp. Am I correct?
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 »

I finally made it! My code now detects my external Western Digital from the docking station. I tested the code with a Seagate and a Samsung disk too. Please test it and tell me if it is detecting correctly your drives, especially the external ones.

Disks.pb

Code: Select all

IncludeFile "HDD_Families.pb"

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(1)
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

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
		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
		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\ReservedForFutureSerialAta > 0
	If (idsec\ReservedForFutureSerialAta & $E) >> 1 = 3
		Cur = "SATA 600"
	ElseIf (idsec\ReservedForFutureSerialAta & $E) >> 1 = 2
		Cur = "SATA 300"
	ElseIf (idsec\ReservedForFutureSerialAta & $E) >> 1 = 1
		Cur = "SATA 150"
	EndIf
ElseIf idsec\SerialAtaCapabilities > 0
	Cur = "SATA"
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 ReadAttributes(CurrentDrive.l, SCSITargetID.l)
   cbBytesReturned.l
   Dim bArrOut.a(SizeOf(SENDCMDOUTPARAMS))
   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)
			;ShowMemoryViewer(@bArrOut(),512)
			;CallDebugger
		Else; it is USB
			ClearStructure(@pswb, t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)
			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] = $A1
			   \Cdb[1] = (4 << 1) | 0
			   \Cdb[2] = $E
			   \Cdb[3] = $D0
			   ;\Cdb[4] = 1
			   \Cdb[5] = 1
			   \Cdb[6] = $4F
			   \Cdb[7] = $C2
			   \Cdb[8] = $A1
			   \Cdb[9] = $B0
			
			   \CdbLength = 12                                ; CDB len
			EndWith
			Length.l = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\DataBuffer) + pswb\spt\DataTransferLength;;SizeOf(pswb)                                ; size of the structure
			Result = DeviceIoControl_(hdh, $4d004, @pswb, SizeOf(t_SPTD), @pswb, Length, @dummy, @OL)
			If dummy > 0
				CopyMemory(@pswb\DataBuffer-16,@bArrOut(), SizeOf(SENDCMDOUTPARAMS))
				;ShowMemoryViewer(@pswb\DataBuffer-16,512)
			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 = $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
			ClearStructure(@pswb, t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER)
			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] = $A1
			   \Cdb[1] = (4 << 1) | 0
			   \Cdb[2] = $E
			   \Cdb[3] = $D1
			   ;\Cdb[4] = 1
			   \Cdb[5] = 1
			   \Cdb[6] = $4F
			   \Cdb[7] = $C2
			   \Cdb[8] = $A1
			   \Cdb[9] = $B0
			
			   \CdbLength = 12                                ; CDB len
			EndWith
			Length.l = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\DataBuffer) + pswb\spt\DataTransferLength;;SizeOf(pswb)                                ; size of the structure
			Result = DeviceIoControl_(hdh, $4d004, @pswb, SizeOf(t_SPTD), @pswb, Length, @dummy, @OL)
			If dummy > 0
				CopyMemory(@pswb\DataBuffer-16,@bArrOut(), SizeOf(SENDCMDOUTPARAMS))
				;ShowMemoryViewer(@pswb\DataBuffer-16,512)
			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 = $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, #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

Structure PUSB_DEVICE_DESCRIPTOR
bLength.a
bDescriptorType.a
bcdUSB.w
bDeviceClass.a
bDeviceSubClass.a
bDeviceProtocol.a
bMaxPacketSize0.a
idVendor.w
idProduct.w
bcdDevice.w
iManufacturer.a
iProduct.a
iSerialNumber.a
bNumConfigurations.a
EndStructure

Procedure.l HDDInfo(CurrentDrive.l, SCSIPort.l, SCSITargetID.l)
;DebugMe("Current drive = " + Str(CurrentDrive))
sYesNo.s: USB_Drive = 0
OpenSmart(CurrentDrive, SCSIPort)
		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
	         \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
          	;Debug "DUMMY > 0"
          	CopyMemory(@bout(16),@idsec,512)
          Else; no data recieved maybe it is a USB drive.
          	;Debug "DUMMY < 0"
          	;Debug "CurrentDrive = " + Str(CurrentDrive)
				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 ;READ_ATTRIBUTE_BUFFER_SIZE ; data len
				   \DataBufferOffset = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\DataBuffer)    ; data buffer pointer
				   \Cdb[0] = $A1
				   \Cdb[1] = (4 << 1) | 0
				   \Cdb[2] = (1 << 3) | (1 << 2) | 2
				   ;\Cdb[3] = 0
				   ;\Cdb[4] = 1
				   ;\Cdb[5] = 1
				   ;\Cdb[6] = 0
				   ;\Cdb[7] = 0
				   \Cdb[8] = $A0
				   \Cdb[9] = $EC;7
				
				   \CdbLength = 12                                ; CDB len
				EndWith
				Length.l = OffsetOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER\DataBuffer) + pswb\spt\DataTransferLength;;SizeOf(pswb)                                ; size of the structure
				Result = DeviceIoControl_(hdh, $4d004, @pswb, SizeOf(t_SPTD), @pswb, Length, @dummy, @OL)
				If dummy > 0
					CopyMemory(@pswb\DataBuffer,@idsec,512);SizeOf(t_SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER))
					USB_Drive = 1
					;ShowMemoryViewer(@idsec,512)
				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
			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 > 1: ReDim di.DriveInfo(HDDCount): EndIf
			di(HDDCount)\PartitionCount = Str(PartCount): PartCount = 0
			di(HDDCount)\SerialNumber =Trim(ChangeHighLowByte(PeekS(@idsec\SerialNumber[0],20,#PB_Ascii)))
			di(HDDCount)\Model = Trim(ChangeHighLowByte(PeekS(@idsec\ModelNumber[0],40,#PB_Ascii)))
			di(HDDCount)\Family = DiskFamily(di(HDDCount)\Model)
			di(HDDCount)\FirmWare = Trim(ChangeHighLowByte(PeekS(@idsec\FirmwareRev[0],8,#PB_Ascii)))
			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 + " , " + "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")
			;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

;HDDInfo(2,-1,-1)
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, 300, 20)
 TextGadget(3,320,14,150,20,"<-- Please select a drive.")
;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
    	If EventGadget() = 2
slct_gadget:
      	If CurrentHDD <> GetGadgetState(2)
				CurrentHDD = GetGadgetState(2)
		    	If CurrentHDD < 0: CurrentHDD = 0: EndIf
				SetGadgetState(2, CurrentHDD)
				ClearGadgetItems(0)
				ClearGadgetItems(1)
				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,Hex(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
    EndIf

  Until Quit = 1
  
EndIf

End 
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 »

HDD_Families.pb

Code: Select all

Procedure.s DiskFamily(Code.s)
	Protected Model.s = ""
	If FindString(UCase(Code),"SAMSUNG SSD") > 0 Or FindString(UCase(Code),"ADATA") > 0 Or FindString(UCase(Code),"OCZ") > 0 Or FindString(UCase(Code),"RADEON") > 0 Or FindString(UCase(Code),"SANDISK") > 0 Or FindString(UCase(Code),"TOSHIBA") > 0
		Model = Code
	ElseIf FindString(UCase(Code),"KINGSTON") > 0
		Select Mid(Code,10, 7)
			Case "SV300S3"
				Model = "SSDNow V300 Drive"
			Case "SV310S3"
				Model = "SSDNow V310 Drive"
			Case "SHFS37A"
				Model = "HyperX FURY SSD"
			Case "SH103S3"
				Model = "HyperX 3K SSD"
			Case "SKC380S"
				Model = "SSDNow KC380 Drive"
			Case "SKC300S"
				Model = "SSDNow KC300 Drive"
			Case "SE100S3"
				Model = "SSDNow E100 Drive"
			Case "SE50S37"
				Model = "SSDNow E50 Drive"
			Case "SMS200S"
				Model = "SSDNow mS200 Drive"
			Case "SM2280S"
				Model = "M.2 SATA SSD"
			Case "SS200S3"
				Model = "SSDNow S200 Drive"
		EndSelect		
	Else
		Restore HDD_CODES
		Repeat
			Read.s HDDModel.s
			If HDDModel = ""
				Break
			EndIf
			Read.s HDDCodeExpression.s
			If CreateRegularExpression(0, HDDCodeExpression)
				If MatchRegularExpression(0, UCase(Code))
					FreeRegularExpression(0)
					Model = HDDModel
					Break
				EndIf
				FreeRegularExpression(0)
			EndIf
		ForEver
	EndIf
ProcedureReturn Model
EndProcedure


DataSection
	HDD_CODES:
		Data.s "ExcelStor J240", "^EXCELSTOR TECHNOLOGY J240$"
		Data.s "ExcelStor J340", "^EXCELSTOR TECHNOLOGY J340$"
		Data.s "ExcelStor J360", "^EXCELSTOR TECHNOLOGY J360$"
		Data.s "ExcelStor J680", "^EXCELSTOR TECHNOLOGY J680$"
		Data.s "ExcelStor J880", "^EXCELSTOR TECHNOLOGY J880$"
		Data.s "IBM Deskstar 60GXP", "(IBM-|HITACHI )?IC35L0[12346]0AVER07"
		Data.s "IBM Deskstar 40GV & 75GXP", "(IBM-)?DTLA-30[57]0[123467][05]"
		Data.s "Fujitsu M1623TAU", "^FUJITSU M1623TAU$"
		Data.s "Fujitsu MHM2200AT", "^FUJITSU MHM2200AT"
		Data.s "Fujitsu MHM2150AT", "^FUJITSU MHM2150AT"
		Data.s "Fujitsu MHM2100AT", "^FUJITSU MHM2100AT"
		Data.s "Fujitsu MHM2060AT", "^FUJITSU MHM2060AT"
		Data.s "Fujitsu MHG", "^FUJITSU MHG2...ATU?"
		Data.s "Fujitsu MHH", "^FUJITSU MHH2...ATU?"
		Data.s "Fujitsu MHJ", "^FUJITSU MHJ2...ATU?"
		Data.s "Fujitsu MHK", "^FUJITSU MHK2...ATU?"
		Data.s "Fujitsu MHL2300AT", "^FUJITSU MHL2300AT$"
		Data.s "Fujitsu MHN", "^FUJITSU MHN2...AT$"
		Data.s "Fujitsu MHR2020AT", "^FUJITSU MHR2020AT$"
		Data.s "Fujitsu MHR2040AT", "^FUJITSU MHR2040AT$"
		Data.s "Fujitsu MHSxxxxAT", "^FUJITSU MHS20[6432]0AT(  .)?$"
		Data.s "Fujitsu MHT", "^FUJITSU MHT2...(AH|AS|AT|BH)U?"
		Data.s "Fujitsu MHU", "^FUJITSU MHU2...ATU?"
		Data.s "Fujitsu MHV", "^FUJITSU MHV2...(AH|AS|AT|BH|BS|BT)"
		Data.s "Fujitsu MPA..MPG", "^FUJITSU MP[A-G]3...A[HTEV]U?"
		Data.s "Fujitsu MHW2 BH", "^FUJITSU MHW2(04|06|08|10|12|16)0BH$"
		Data.s "Samsung SV4012H", "^SAMSUNG SV4012H$"
		Data.s "Samsung SV0412H", "^SAMSUNG SV0412H$"
		Data.s "Samsung SV1204H", "^SAMSUNG SV1204H$"
		Data.s "Samsung SV0322A", "^SAMSUNG SV0322A$"
		Data.s "Samsung SP40A2H with RR100-07 firmware",     "^SAMSUNG SP40A2H$"
		Data.s "Samsung SP8004H with QW100-61 firmware", "^SAMSUNG SP8004H$"
		Data.s "Samsung SpinPoint T133", "^SAMSUNG HD(250KD|(30[01]|320|40[01])L[DJ])$"
		Data.s "Samsung SpinPoint T166", "^SAMSUNG HD(080G|160H|32[01]K|403L|50[01]L)J$"
		Data.s "Samsung SpinPoint P120", "^SAMSUNG SP(16[01]3|2[05][01]4)[CN]$"
		Data.s "Samsung SpinPoint P80 SD", "^SAMSUNG HD(080H|120I|160J)J$"
		Data.s "Samsung SpinPoint P80", "^SAMSUNG SP(0451|08[0124]2|12[0145]3|16[0145]4)[CN]$"
		Data.s "Samsung SpinPoint F1", "^SAMSUNG HD(753L|642J|501I|322H|25[12]H|103U|16[12]G)J$"
		Data.s "Samsung SpinPoint F1 CE", "^SAMSUNG HA(751L|501I|321H|251H|101U)J$"
		Data.s "Samsung SpinPoint F1 DT", "^SAMSUNG HD(753LI|642JI|083GJ)$"
		Data.s "Samsung SpinPoint F1 RAID Class", "^SAMSUNG HE(753L|642J|502I|322H|252H|103U)J$"
		Data.s "Samsung SpinPoint F3", "^SAMSUNG HD(754J|502H|103S)J$"
		Data.s "Samsung SpinPoint F4", "^SAMSUNG HD(16[56]|25[56]|322)GJ$"
		Data.s "Samsung SpinPoint M5", "^SAMSUNG HM(250JI|1(60|21)H[IC])$"
		Data.s "Samsung SpinPoint M6", "^SAMSUNG HM([54]00L|(320|251)J)I$"
		Data.s "Samsung SpinPoint M7", "^SAMSUNG HM([54]00J|320I|250H|161H|120G)I$"
		Data.s "Samsung SpinPoint M7E", "^SAMSUNG HM641JI$"
		Data.s "Samsung SpinPoint M8", "^SAMSUNG HN-M(320|500|750|101)MBB$"
		Data.s "Samsung SpinPoint MC30", "^SAMSUNG HM031HC$"
		Data.s "Samsung SpinPoint MP2", "^SAMSUNG HM((08|12|10)[01]HJ)|((25|20|16)[01]JJ)$"
		Data.s "Samsung SpinPoint MP4", "^SAMSUNG HM((64|50)0J|(32|25)0H)J$"
		Data.s "Samsung SpinPoint MU-X", "^SAMSUNG HM(320J|251J|160H)X$"
		Data.s "Samsung SpinPoint N2B", "^SAMSUNG HS((08[02]|06[0T]|04[0T])HB)|030GB|122JB$"
		Data.s "Samsung SpinPoint N3A", "^SAMSUNG HS(0[68]|12)YHA$"
		Data.s "Samsung SpinPoint N3B", "^SAMSUNG HS12UHE$"
		Data.s "Samsung SpinPoint N3C", "^SAMSUNG HS(0[68]VH|1[26]VJ)F$"
		Data.s "Samsung EcoGreen F1 CE ", "^SAMSUNG HA(753L|642J|502J|322H|252H|103U)I$"
		Data.s "Samsung EcoGreen F1 DT", "^SAMSUNG HD(753L|642J|502J|322H|252H|103U)I$"
		Data.s "Samsung EcoGreen F2", "^SAMSUNG HD(502HI|10[23]SI|15[34]UI)$"
		Data.s "Samsung EcoGreen F3", "^SAMSUNG HD(754J|503H|203W|253G|105S|153W)I$"
		Data.s "Maxtor Fireball 541DX", "^MAXTOR 2B0(0[468]|1[05]|20)H1$"
		Data.s "Maxtor Fireball 3", "^MAXTOR 2F0[234]0[JL]0$"
		Data.s "Maxtor DiamondMax 1750 Ultra ATA", "^MAXTOR 8(1750[AD]2|2560[AD]3|3240[AD]4|3500[AD]4|4320[AD]5|5250[AD]6|6480[AD]8|7000[AD]8)$"
		Data.s "Maxtor DiamondMax 2160 Ultra ATA", "^MAXTOR 8(2160D2|3228D3|3240D3|4320D4|6480D6|8400D8|8455D8)$"
		Data.s "Maxtor DiamondMax 2880 Ultra ATA", "^MAXTOR 9(0256D2|0288D2|0432D3|0510D4|0576D4|0648D5|0720D5|084[05]D6|0864D6|1008D[78]|1152D8)$"
		Data.s "Maxtor DiamondMax 3400 Ultra ATA", "^MAXTOR 9(1(360|350|202)D8|1190D7|10[12]0D6|0840D5|06[48]0D4|0510D3|0340D2|1(350|202)E8|1010E6|0840E5|0640E4)$";256k
		Data.s "Maxtor DiamondMax D540X", "^MAXTOR 4(G(120J6|160J[68])|[DK](020H1|040H2|060H3|080H4)$";2
		Data.s "Maxtor DiamondMax Plus D740X", "^MAXTOR 6L0(20[JL]1|40[JL]2|60[JL]3|80[JL]4)$";2
		Data.s "Maxtor DiamondMax Plus 2500 Ultra ATA", "^MAXTOR 9(0500D4|0625D5|0750D6|0840D7|0875D7|0910D8|1000D8)$"
		Data.s "Maxtor DiamondMax Plus 5120 Ultra ATA 33", "^MAXTOR 9(0512D2|0680D3|0750D3|0913D4|1024D4|1360D6|1536D6|1792D7|2048D8)$"
		Data.s "Maxtor DiamondMax Plus 6800 Ultra ATA 66", "^MAXTOR 9(2732U8|2390U7|2049U6|1707U5|1366U4|1024U3|0845U3|0683U2)$"
		Data.s "Maxtor DiamondMax 6800 Ultra ATA 66", "^MAXTOR 9(2720U8|2040U6|1360U4|1020U3|0845U3|0650U2)$";2
		Data.s "Maxtor DiamondMax D540X-4D", "^MAXTOR 4D0(20H1|40H2|60H3|80H4)$"
		Data.s "Maxtor DiamondMax 4320 Ultra ATA", "^MAXTOR (91728D8|91512D7|91303D6|91080D5|90845D4|90645D3|90648D[34]|90432D2)$"
		Data.s "Maxtor DiamondMax 17 VL", "^MAXTOR 9(0431U1|0641U2|0871U2|1301U3|1741U4)$";512K
		Data.s "Maxtor DiamondMax 20 VL", "^MAXTOR (94091U8|93071U6|92561U5|92041U4|917[34]1U4|91531U3|913[06]1U3|91021U2|908[47]1U2|90651U2|90431U1)$";512K
		Data.s "Maxtor DiamondMax 30 VL", "^MAXTOR (33073U4|32049U3|31536U2|30768U1)$";512K
		Data.s "Maxtor DiamondMax 36", "^MAXTOR (93652U8|92739U6|91826U4|91369U3|90913U2|90845U2|90435U1)$"
		Data.s "Maxtor DiamondMax 40 ATA 66", "^MAXTOR 9(0684U2|1024U2|136[29]U3|1536U3|1826U4|2049U4|2562U5|2739U6|3073U6|3652U8|4098U8)$";2
		Data.s "Maxtor DiamondMax Plus 40 (Ultra ATA 66 and Ultra ATA 100)", "^MAXTOR (54098[UH]8|53073[UH]6|52732[UH]6|52049[UH]4|51536[UH]3|51369[UH]3|51024[UH]2)$";2
		Data.s "Maxtor DiamondMax 40 VL Ultra ATA 100", "^MAXTOR 3(1024H1|1535H2|2049H2|3073H3|4098H4)( B)?$"
		Data.s "Maxtor DiamondMax Plus 45 Ulta ATA 100", "^MAXTOR 5(4610H6|4098H6|3073H4|2049H3|1536H2|1369H2|1023H2)$";2
		Data.s "Maxtor DiamondMax 60 ATA 66", "^MAXTOR 9(1023U2|1536U2|2049U3|2305U3|3073U4|4610U6|6147U8)$"
		Data.s "Maxtor DiamondMax 60 ATA 100", "^MAXTOR 9(1023H2|1536H2|2049H3|2305H3|3073H4|4610H6|6147H8)$"
		Data.s "Maxtor DiamondMax Plus 60", "^MAXTOR 5T0(60H6|40H4|30H3|20H2|10H1)$"
		Data.s "Maxtor DiamondMax 80", "^MAXTOR (98196H8|96147H6)$"
		Data.s "Maxtor DiamondMax 8S", "^MAXTOR 6[EN]040T0$";2
		Data.s "Maxtor DiamondMax 536DX", "^MAXTOR 4W(100H6|080H6|060H4|040H3|030H2)$"
		Data.s "Maxtor DiamondMax Plus 8", "^MAXTOR 6(E0[234]|K04)0L0$"
		Data.s "Maxtor DiamondMax 10 (ATA/133 and SATA/150)", "^MAXTOR 6(B(30|25|20|16|12|08)0[MPRS]|L(080[MLP]|(100|120)[MP]|160[MP]|200[MPRS]|250[RS]|300[RS]))0$"
		Data.s "Maxtor DiamondMax 10 (SATA/300)", "^MAXTOR 6V(080E|160E|200E|250F|300F|320F)0$"
		Data.s "Maxtor DiamondMax Plus 9", "^MAXTOR 6Y((060|080|120|160)L0|(080|120|160|200|250)P0|(060|080|120|160|200|250)M0)$"
		Data.s "Maxtor DiamondMax 11", "^MAXTOR 6H[45]00[FR]0$"
		Data.s "Maxtor DiamondMax 16", "^MAXTOR 4(R0[468]0[JL]0|R1[26]0L0|A160J0|A250J0|A300J0|R120L4)$"
		Data.s "Maxtor DiamondMax 17", "^MAXTOR 6G(080[LE]|160[PE]|250[PE]|320[PE])0$"
		Data.s "Seagate Maxtor DiamondMax 20", "^MAXTOR STM3(402111|802110|160[28]12|200827|25062[34]|300622)A$"
		Data.s "Seagate Maxtor DiamondMax 21", "^MAXTOR STM3(((402|80[28]|160[28])15)|250310|((2008|250[68]|3006|320[68])20)|250824|500630)AS?$"
		Data.s "Seagate Maxtor DiamondMax 22", "^MAXTOR STM3(160813|320614|500[368]20|750[36]30|1000[36](34|40))AS$"
		Data.s "Seagate Maxtor DiamondMax 23", "^MAXTOR STM3(16031|25031|32041|50041|75052|100052)8AS$";8/16/32
		Data.s "Seagate Maxtor OneTouch 4", "^MAXTOR STM30(2503|5004|7504)OT[AB]3E1-RK$";8/16/32
		Data.s "Seagate Maxtor OneTouch 4 Mini", "^MAXTOR STM90(8|12|16)03OT[AB]3E1-RK$";8
		Data.s "Maxtor MaXLine Plus II", "^MAXTOR 7Y250[PM]0$"
		Data.s "Maxtor MaXLine II", "^MAXTOR [45]A(25|30|32)0[JN]0$"
		Data.s "Maxtor MaXLine III (ATA/133 and SATA 1)", "^MAXTOR 7L(25|30)0[SR]0$"
		Data.s "Maxtor MaXLine III (SATA 2)", "^MAXTOR 7V(25|30)0F0$"
		Data.s "Maxtor MaXLine Pro 500", "^MAXTOR 7H500F0$"
		Data.s "Hitachi DK14FA-20B", "^HITACHI_DK14FA-20B$"
		Data.s "Hitachi Travelstar DK23XX/DK23XXB", "^HITACHI_DK23..-..B?$"
		Data.s "Hitachi Endurastar J4K20/N4K20", "^(HITACHI_DK23FA-20J|HTA422020F9AT[JN]0)$"
		Data.s "IBM Deskstar 14GXP and 16GP", "^IBM-DTTA-3(7101|7129|7144|5032|5043|5064|5084|5101|5129|5168)0$"
		Data.s "IBM Deskstar 25GP and 22GXP", "^IBM-DJNA-3(5(101|152|203|250)|7(091|135|180|220))0$"
		Data.s "IBM Travelstar 4GT", "^IBM-DTCA-2(324|409)0$"
		Data.s "IBM Travelstar 25GS, 18GT, and 12GN", "^IBM-DARA-2(25|18|15|12|09|06)000$"
		Data.s "IBM Travelstar 48GH, 30GN, and 15GN", "^(IBM-|Hitachi )?IC25(T048ATDA05|N0(30|20|15|12|10|07|06|05)ATDA04)-.$"
		Data.s "IBM Travelstar 32GH, 30GT, and 20GN", "^IBM-DJSA-2(32|30|20|10|05)$"
		Data.s "IBM Travelstar 4GN", "^IBM-DKLA-2(216|324|432)0$"
		Data.s "IBM Deskstar 37GP and 34GXP", "^IBM-DPTA-3(5(375|300|225|150)|7(342|273|205|136))0$"
		Data.s "IBM/Hitachi Travelstar 60GH and 40GN", "^(IBM-|Hitachi )?IC25(T060ATC[SX]05|N0[4321]0ATC[SX]04)-.$"
		Data.s "IBM/Hitachi Travelstar 40GNX", "^(IBM-|Hitachi )?IC25N0[42]0ATC[SX]05-.$"
		Data.s "Hitachi Travelstar 80GN", "^(HITACHI )?IC25N0[23468]0ATMR04-.$"
		Data.s "Hitachi Travelstar 4K40", "^(HITACHI )?HTS4240[234]0M9AT00$"
		Data.s "Hitachi Travelstar 5K80", "^(HITACHI )?HTS5480[8642]0M9AT00$"
		Data.s "Hitachi Travelstar 5K100", "^(HITACHI )?HTS5410[1864]0G9(AT|SA)00$"
		Data.s "Hitachi Travelstar E5K100", "^(HITACHI )?HTE541040G9(AT|SA)00$"
		Data.s "Hitachi Travelstar 5K120", "^(HITACHI )?HTS5412(60|80|10|12)H9(AT|SA)00$"
		Data.s "Hitachi Travelstar 5K160", "^(HITACHI )?HTS5416([468]0|1[26])J9(AT|SA)00$"
		Data.s "Hitachi Travelstar 7K60", "^(HITACHI )?HTS726060M9AT00$"
		Data.s "Hitachi Travelstar E7K60", "^(HITACHI )?HTE7260[46]0M9AT00$"
		Data.s "Hitachi Travelstar 7K100", "^(HITACHI )?HTS7210[168]0G9(AT|SA)00$"
		Data.s "Hitachi Travelstar E7K100", "^(HITACHI )?HTE7210[168]0G9(AT|SA)00$"
		Data.s "Hitachi Travelstar 7K200", "^(HITACHI )?HTS7220(80|10|12|16|20)K9(A3|SA)00$"
		Data.s "IBM/Hitachi Deskstar 120GXP", "^(IBM-)?IC35L((020|040|060|080|120)AVVA|0[24]0AVVN)07-[01]$"
		Data.s "IBM/Hitachi Deskstar GXP-180", "^(IBM-)?IC35L(030|060|090|120|180)AVV207-[01]$"
		Data.s "IBM Travelstar 14GS", "^IBM-DCYA-214000$"
		Data.s "IBM Travelstar 4LP", "^IBM-DTNA-2(180|216)0$"
		Data.s "Hitachi Deskstar 7K80", "^(HITACHI )?HDS7280([48]0PLAT20|(40)?PLA320|80PLA380)$"
		Data.s "Hitachi Deskstar 7K160", "^(HITACHI )?HDS7216(80|16)PLA[3T]80$"
		Data.s "Hitachi Deskstar 7K250", "^(HITACHI )?HDS7225((40|80|12|16)VLAT20|(12|16|25)VLAT80|(80|12|16|25)VLSA80)$"
		Data.s "Hitachi Deskstar T7K250", "^(HITACHI )?HDT7225((25|20|16)DLA(T80|380))$"
		Data.s "Hitachi Deskstar 7K400", "^(HITACHI )?HDS724040KL(AT|SA)80$"
		Data.s "Hitachi Deskstar 7K500", "^(HITACHI )?HDS725050KLA(360|T80)$"
		Data.s "Hitachi Deskstar T7K500", "^(HITACHI )?HDT7250(25|32|40|50)VLA(360|380|T80)$"
		Data.s "Hitachi Deskstar 7K1000", "^(HITACHI )?HDS7210(75|10)KLA330$"
		Data.s "Hitachi Ultrastar A7K2000", "^(HITACHI )?HUA7220(20|10|50)CLA33(0|1)$"
		Data.s "Hitachi Ultrastar 15K600", "^(HITACHI )?HUS1560(30|45|60)VL(S|F)(4|6)0(0|1)$"
		Data.s "Hitachi Ultrastar 15K450", "^(HITACHI )?HUS1545(30|45)VL(S|F)(3|4)00$"
		Data.s "Hitachi Ultrastar C15K147", "^(HITACHI )?HUC1514(14|73)CSS60(0|1)$"
		Data.s "Hitachi Ultrastar C10K300", "^(HITACHI )?HUC1030(14|30)CSS600$"
		Data.s "Hitachi Ultrastar 7K1000", "^(HITACHI )?HUA7210(50|75|10)KLA330$"
		Data.s "Hitachi Ultrastar 7K1000.C", "^(HITACHI )?HDS7210(16|25|32|50|64|75|10|20)CLA3(3|6|8)(0|2)$"
		Data.s "Hitachi Ultrastar 7K2000", "^(HITACHI )?HDS722020ALA330$"
		Data.s "Hitachi CinemaStar 7K1000.C", "^(HITACHI )?HCS7210(16|25|32|50|75|10)CLA3(3|8)2$"
		Data.s "Hitachi CinemaStar 5K1000", "^(HITACHI )?HCS5C(10(16|25|32|50|75|10)CLA382|3225SLA380)$"
		Data.s "Hitachi CinemaStar C5K500", "^(HITACHI )?HCC5450(16|25|32|50)B9A300$"
		Data.s "Hitachi CinemaStar Z5K320", "^(HITACHI )?HCC5432(16|25|32)A7A380$"
		Data.s "Hitachi CinemaStar 7K500", "^(HITACHI )?HTE7250(16|25|32|50)A9A364$"
		Data.s "Hitachi CinemaStar 5K500.B", "^(HITACHI )?HTE5450(16|25|32|50)B9A300$"
		Data.s "Hitachi CinemaStar Z7K320", "^(HITACHI )?HTE7232(16|25|32)A7A364$"
		Data.s "Hitachi CinemaStar Z5K320", "^(HITACHI )?HTE5432(16|25|32)A7A384$"
		Data.s "Hitachi EnduraStar J4K100", "^(HITACHI )?HEJ4210(40|80|10)G9(AT|SA)00$"
		Data.s "Hitachi EnduraStar N4K100", "^(HITACHI )?HEN4210(40|80|10)G9(AT00|T00)$"
		
		;Data.s "Toshiba 2.5'' HDD (30-60 GB)", "^TOSHIBA MK((6034|4032)GSX|(6034|4032)GAX|(6026|4026|4019|3019)GAXB?|(6025|6021|4025|4021|4018|3025|3021|3018)GAS|(4036|3029)GACE?|(4018|3017)GAP)$"
		;Data.s "Toshiba 2.5'' HDD (80 GB And above)", "^TOSHIBA MK(80(25GAS|26GAX|32GAX|32GSX)|10(31GAS|32GAX)|12(33GAS|34G[As]X)|2035GSS)$"
		;Data.s "Toshiba 1.8'' HDD", "^TOSHIBA MK[23468]00[4-9]GA[HL]$"

		;{
		Data.s "Seagate Atlas 15K", "^(MAXTOR )?8C(018|036|073)[JL]0$";8
		Data.s "Seagate Atlas 15K II", "^(MAXTOR )?8[EK](036|073|147)[JL]0$";8
		Data.s "Seagate Atlas 15K II SAS", "^(MAXTOR )?8K(036|073|147)S0$";16
		Data.s "Seagate Atlas 10K III", "^(MAXTOR )?KU(018[JL]2|036[JL]4|073[JL]8)$";8
		Data.s "Seagate Atlas 10K IV", "^(MAXTOR )?8B(036|073|146)[LJ]0$";8
		Data.s "Seagate Atlas 10K V", "^(MAXTOR )?8[DJ](073|147|300)[LJ]0$";8
		Data.s "Seagate Momentus", "^ST9(20|28|40|48)11A$"
		Data.s "Seagate Momentus Blade Server", "^ST94811AB$"
		Data.s "Seagate Momentus XT", "^ST9(500562|320562|250561)0AS$";32
		Data.s "Seagate Momentus Thin", "^ST9(16|25)03010AS$";8
		Data.s "Seagate Momentus 42", "^ST9(2014|3015|4019)A$";2
		Data.s "Seagate Momentus 42.2", "^ST9(30219|402113)A$";2
		Data.s "Seagate Momentus 42.2", "^ST9(60821|808210|100822)A$";8
		Data.s "Seagate Momentus 54", "^ST9[24][08]11A$";8
		Data.s "Seagate Momentus 4200.2", "^ST9(120824|10082[25]|8082(9|10)|608(12|21)|50214|402112|30218)A$";8
		Data.s "Seagate Momentus 4200 N-Lite", "^ST940110A$";2
		Data.s "Seagate Momentus 4200.2", "^ST9(50212|40211[23]|3021[89])A$";2
		Data.s "Seagate Momentus 4200.3", "^ST9(408116|960813|80811)A$";8
		Data.s "Seagate Momentus 5400 PSD", "^ST9(1[26]08220|808212)AS$";8
		Data.s "Seagate Momentus 5400 FDE", "^ST9((500327|250317)AS|(40811|60814|80821|100826|120826)A)$";8
		Data.s "Seagate Momentus 5400 FDE.2 SATA", "^ST9(80816|120827|160824)AS$";8
		Data.s "Seagate Momentus 5400 FDE.3", "^ST9(32032|1[26]031)[29]AS$";8
		Data.s "Seagate Momentus 5400 FDE.4", "^ST9(80314|(1[26]|25)0317|(32|50)0327)AS$";8
		Data.s "Seagate Momentus 5400.1", "^ST93012AM?$";2
		Data.s "Seagate Momentus 5400.2", "^ST9(808211|60822|408114|308110|120821|10082[34]|8823|6812|4813|3811)AS?$"
		Data.s "Seagate Momentus 5400.3", "^ST9(4081[45]|6081[35]|8081[15]|100828|120822|160821)A$";8
		Data.s "Seagate Momentus 5400.3 ED", "^ST9(4081[45]|6081[35]|8081[15]|100828|120822|160821)AB$"
		Data.s "Seagate Momentus 5400.4", "^ST9((25|20|16)0827|120817)AS$";8
		Data.s "Seagate Momentus 5400.5", "^ST9((8|16)0310|320320)ASG?$";8
		Data.s "Seagate Momentus 5400.6", "^ST9((50|32)0325|250315|160314|120315)ASG?$";8
		Data.s "Seagate Momentus 5400.7", "^ST9(160316|250310|32031[02]|50032[01]|64032[02])AS$"
		Data.s "Seagate Momentus 7200 FDE", "^ST9(500421|250411)AS$";16
		Data.s "Seagate Momentus 7200.1", "^ST9(10021|80825|6023|4015)AS?$";8
		Data.s "Seagate Momentus 7200.2", "^ST9(80813|100821|120823|160823|200420)ASG?$";8/ 16 o 200
		Data.s "Seagate Momentus 7200.3", "^ST9(((8|12|16)0411)|((20|25|32)0421))ASG?$";16
		Data.s "Seagate Momentus 7200.4", "^ST9(120410|160412|250410|320423|500420)ASG?$";16
		Data.s "Seagate UX", "^ST3(10014A(CE)?|20014A)$"
		Data.s "Seagate U7", "^ST3(30012|40012|60012|80022|120020)A$"
		Data.s "Seagate U6", "^ST3(8002|6002|4081|3061|2041)0A$"
		Data.s "Seagate U5", "^ST3(40823|30621|20413|15311|10211)A$"
		Data.s "Seagate U4", "^ST3(2112|4311|6421|8421)A$"
		Data.s "Seagate U8", "^ST3(8410|4313|17221|13021)A$"
		Data.s "Seagate U10", "^ST3(20423|15323|10212)A$"
		Data.s "Seagate Constellation SAS", "^ST950043[01]SS$";16
		Data.s "Seagate Constellation SATA", "^ST9(500530|160511)NS$";32
		Data.s "Seagate Constellation ES", "^ST3(5|10|20)00(4[124][45]SS|5[124]4NS)$"
		Data.s "Seagate Cheetah 15K.7", "^ST3(300[56]|450[78]|600[09])57(FC|SS)$"
		Data.s "Seagate Cheetah 15K.6", "^ST3(4508|3006|1463)56(FC|SS)$"
		Data.s "Seagate Cheetah 15K.5", "^ST3(3006|1468|734)55(LW|LC|FC|SS)$"
		Data.s "Seagate Cheetah 15K.4", "^ST3(1468|734|367)54(LW|LC|FC|SS)$";8
		Data.s "Seagate Cheetah 15K.3", "^ST3(734|367|184)53(LW|LC|FC)$";8
		Data.s "Seagate Cheetah 10K.7", "^ST3(3000|1467|732|368)07(LW|LC|FC)$";8
		Data.s "Seagate Cheetah 10K.6", "^ST3(1468|733|366)07(LW|LC|FC)$";8
		Data.s "Seagate Cheetah X15", "^ST3(184|92)51(LW|LC)$";8
		Data.s "Seagate Cheetah X15-36LP", "^ST3(367|184)[53]2(LW|LC|FC)$";8
		Data.s "Seagate Cheetah T10 SAS", "^ST3(733|1467|3005)55SS$";8
		Data.s "Seagate Cheetah NS", "^ST3(3009|4007)55(FC|SS)$";8
		Data.s "Seagate Cheetah 9", "^ST19101(N|W|WC|WD|DC)$";8
		Data.s "Seagate Cheetah 9LP", "^ST3(91|45)02L[WC]$";8
		Data.s "Seagate Cheetah 73LP", "^ST3(734|366)05(LC|LCV|LW|FC)$"
		Data.s "Seagate Cheetah 73", "^ST173404(LC|LCV|LWV|LW|FC|FCV)$"
		Data.s "Seagate Cheetah 36", "^ST136403(LC|LCV|LWV|LW|FC|FCV)$"
		Data.s "Seagate Cheetah 36LP", "^ST336704(LC|LCV|LWV|LW|FC|FCV)$"
		Data.s "Seagate Cheetah 36XL", "^ST3(184|92)05L[WC]$"
		Data.s "Seagate Cheetah 36ES", "^ST3(367|184)[04]6L[WC]$";4
		Data.s "Seagate Cheetah 18", "^ST118202L[WC]$"
		Data.s "Seagate Cheetah 18XL", "^ST3(92|184)04L[WC]$"
		Data.s "Seagate Cheetah 18LP", "^ST3(91|182)[03]3(LW|LC|FC|LWV|LCV|FCV)$"
		Data.s "Seagate Cheetah 4LP", "^ST34501(N|W|WC|WD|DC)$"
		Data.s "Seagate DB35.4", "^ST3250310CS$"
		Data.s "Seagate DB35.3", "^ST3(8|16|25|32|40|50|75)0(640|8[234]0|215)[SA]CE$"
		Data.s "Seagate DB32 7200.2", "^ST3(8|12|16|20|25|30|40|50)0(8(41|33|2[247])|2110|21[23])[SA]CE$"
		Data.s "Seagate DB35 (IDE)", "^ST3(20|25|30|40)08(2[36]|3[12])ACE$"
		Data.s "Seagate DB35 (SATA)", "^ST3(20|25|30|40)08(2[36]|3[12])SCE$"
		Data.s "Seagate EE25.2", "^ST9[48]081[78][SA]M$"
		Data.s "Seagate EE25.1", "^ST9[234]081[34]AM$"
		Data.s "Seagate Pipeline HD.2 SATA", "^ST3(16|25|32|50|100)0(3(1[126]|22)|4(1([234]|24)CS$"
		Data.s "Seagate Pipeline HD Pro", "^ST31000533CS$"
		Data.s "Seagate Pipeline HD Mini SATA", "^ST9(16|25|32|50)03[12](1|3|8|10)CS$"
		Data.s "Seagate Pipeline HD", "^ST3(16|25|32|50|100)03[12][0126]CS$";8
		Data.s "Seagate Savvio 15K.2", "^ST9((146[78]52)|73[34]52)SS$"
		Data.s "Seagate Savvio 15K.1 FC", "^ST9(367|734)51FC$"
		Data.s "Seagate Savvio 15K", "^ST9(367|734)51SS$";16
		Data.s "Seagate Savvio 10K.4", "^ST9(600[12]|450[34])04(SS|FC)$"
		Data.s "Seagate Savvio 10K.3", "^ST9(300[65]|146[78])03SS$";16
		Data.s "Seagate Savvio 10K.2", "^ST9(1468|734)02SS$";16
		Data.s "Seagate Savvio 10K", "^ST9(734|367)01(LC|SS)$";8
		Data.s "Seagate SV35.5", "^ST3(1000525|500410|250311)SV$";32/16/8
		Data.s "Seagate SV35.4", "^ST3320410SV$";16
		Data.s "Seagate SV35.3", "^ST3(100034|75033|50032|25031)0SV$";16
		Data.s "Seagate SV35.2", "^ST3(750640|500630|320620|250820|160815)[AS]V$"
		Data.s "Seagate SV35", "^ST3(500641|250824|160812)[AS]V$";16/8/8
		Data.s "Seagate Barracuda ATA", "^ST3(2804|2043|1362|1022|6810)0A$"
		Data.s "Seagate Barracuda ATA II", "^ST3(3063|2042|1532|1021)0A$"
		Data.s "Seagate Barracuda ATA II 100", "^ST3(30631|20424|15324|10216)A$"
		Data.s "Seagate Barracuda ATA III", "^ST3(40824|30620|20414|15310|10215)A$"
		Data.s "Seagate Barracuda ATA IV", "^ST3(20011|30011|40016|60021|80021)A$"
		Data.s "Seagate Barracuda ATA V", "^ST3(12002(3A|4A|9A|3AS)|800(23A|15A|23AS)|60(015A|210A)|40017A)$"
		Data.s "Seagate Barracuda 5400.1", "^ST340015A$"
		Data.s "Seagate Barracuda 7200.7 and 7200.7 Plus", "^ST3(200021A|200822AS?|16002[13]AS?|12002[26]AS?|1[26]082[78]AS|8001[13]AS?|80817AS|60014A|40111AS|40014AS?)$"
		Data.s "Seagate Barracuda 7200.8", "^ST3(400[68]32|300[68]31|250[68]23|200826)AS?$"
		Data.s "Seagate Barracuda 7200.9", "^ST3(402111?|80[28]110?|120[28]1[0134]|160[28]1[012]|200827|250[68]24|300[68]22|(320|400)[68]33|500[68](32|41))AS?$"
		Data.s "Seagate Barracuda 7200.10", "^ST3((80|160)[28]15|200820|250[34]10|(250|300|320|400)[68]20|500[68]30|750[68]40)AS?$";16
		Data.s "Seagate Barracuda 7200.11", "^ST3(500[368]2|750[36]3|1000[36]4)0AS$";OK
		Data.s "Seagate Barracuda 7200.11", "^ST3(1500341|1000333|640[36]23|320[68]13|160813)AS$";firmware with bugs!
		Data.s "Seagate Barracuda 7200.12", "^ST3(160318|250318|320418|50041[08]|750528|1000528)AS$";8/16/32
		Data.s "Seagate Barracuda LP", "^ST3(10|15|20)005(20|41|42)|(500412)AS?$"
		Data.s "Seagate Barracuda 9LP", "^ST3(91|45)73(N|W|WD|LW|WC|LC)$"
		Data.s "Seagate Barracuda 9", "^ST19171(N|W|WD|WC|DC)$"
		Data.s "Seagate Barracuda 4", "^ST15150(N|W|ND|WD|WC|DC)$"
		Data.s "Seagate Barracuda 4XL", "^ST3(22|45)72(N|W|WD|WC|DC)$"
		Data.s "Seagate Barracuda 4LP", "^ST3(22|45|21|43)71(N|W|WD|WC|DC)$"
		Data.s "Seagate Barracuda 2LP", "^ST3(12|25)50(N|ND|W|WD|WC|DC)$"
		Data.s "Seagate Barracuda 2 / 2HP", "^ST12450(W|WD)$"
		Data.s "Seagate Barracuda 18", "^ST118273(N|W|WD|LW|WC|LC)$"
		Data.s "Seagate Barracuda 1", "^ST11950(N|ND|W|WD)$"
		Data.s "Seagate Barracuda 2", "^ST12550(N|ND|W|WD)$"
		Data.s "Seagate Barracuda 18LP", "^ST3(91|182)75L[WC]$"
		Data.s "Seagate Barracuda 18XL", "^ST3(92|184)[123]6(N|W|LW|LC|LCV|LWV)$"
		Data.s "Seagate Barracuda 50", "^ST150176L[WC]$"
		Data.s "Seagate Barracuda ES", "^ST3(250[68]2|320[68]2|400[68]2|500[68]3|750[68]4)0NS$"
		Data.s "Seagate Barracuda ES+", "^ST3(25|32|40|50|75)0[68][234]1NS$"
		Data.s "Seagate Barracuda ES.2", "^ST3((500620|750630|1000640)S)|((250310|250610|500320|750330|1000340)N)S$"
		Data.s "Seagate Barracuda 36", "^ST136475L[WC]$"
		Data.s "Seagate Barracuda 36ES", "^ST3(3673|184[13])7(N|W|LW|LC)$"
		Data.s "Seagate Barracuda 36ES2", "^ST3(369|184)(18N|38LW)$";64
		Data.s "Seagate Barracuda 180", "^ST1181677(LC|LW|FC)V$";64
		Data.s "Seagate Barracuda XT", "^ST32000641AS$";64
		Data.s "Seagate Medalist 17240", "^ST317240A$"
		Data.s "Seagate Medalist 13030", "^ST313030A$"
		Data.s "Seagate Medalist 10231", "^ST310231A$"
		Data.s "Seagate Medalist 8420", "^ST38420A$"
		Data.s "Seagate Medalist 4310", "^ST34310A$"
		Data.s "Seagate Medalist 17242", "^ST317242A$"
		Data.s "Seagate Medalist 13032", "^ST313032A$"
		Data.s "Seagate Medalist 10232", "^ST310232A$"
		Data.s "Seagate Medalist 8422", "^ST38422A$"
		Data.s "Seagate Medalist 4312", "^ST34312A$"
		Data.s "Seagate Medalist 2110", "^ST32110A$"
		Data.s "Seagate Medalist 3221", "^ST33221A$"
		Data.s "Seagate Medalist 4321", "^ST34321A$"
		Data.s "Seagate Medalist 6531", "^ST36531A$"
		Data.s "Seagate Medalist 8641", "^ST38641A$"
		Data.s "Seagate NL35", "^ST3(250623|250823|400632|400832|250824|250624|400633|400833|500641|500841)NS$"
		Data.s "Seagate DB35.3", "^ST3((8|16)0215|(25|32|40)0820|500830|750[68]40)[AS]CE$"
		
		Data.s "Seagate Backup Plus Desktop Drive", "^STDT[2-5]000200$"
		Data.s "Seagate Backup Plus Desktop Drive for Mac", "^STDU([24]000100|3000101)$"
		Data.s "Seagate Central", "^STCG[2-4]000200$"
		Data.s "Seagate Expansion Desktop", "^STBV[1-5]000200$"
		Data.s "Seagate NAS HDD", "^ST[2-4]000VN000$"
		Data.s "Seagate Desktop SSHD", "^ST([124]000DX001|CL[24]000400)$"
		Data.s "Seagate Desktop HDD", "^ST(4000DM000|BD4000400)$"
		Data.s "Seagate Barracuda Desktop Hard Drive ", "^ST([23]000DM001|1[05]00DM003|750DM003|500DM002|(25|32)DM000)$"
		Data.s "Seagate Barracuda 3.5 Inch Retail Kit SATA 3TB", "^STBD3000200$"
		Data.s "Seagate Barracuda® 3.5 Retail Kit SATA 2TB ", "^STBD2000201$"
		Data.s "Seagate Backup Plus Slim Portable Drive", "^ST(CD50020[24]|DR[12]00020[0-3])$"
		Data.s "Seagate Fast HDD USB 3.0 4TB Black Hard Drive ", "^STDA4000200$"
		Data.s "Seagate Wireless Plus Mobile Device Storage ", "^STC(V5|K10|V20)00200$"
		Data.s "Seagate Slim Portable Drive for Mac USB 3.0", "^ST(CF500203|DS(5|10|20)00900)$"
		Data.s "Seagate Expansion Portable 500GB USB 3.0 Hard Drive ", "^STBX(500200|1000201|2000401)$"
		Data.s "Seagate Laptop SSHD 1TB Drive", "^ST100LM0(1[45]|28)$"
		Data.s "Seagate Momentus XT 6Gb/s Hard Drive (SSHD)", "^STBD(1000400|750201)$"
		Data.s "Seagate Laptop Thin SSHD", "^ST500LM0(0[01]|20)$"
		Data.s "Seagate Ultra Mobile SSHD", "^ST500LX01[2346]$"
		Data.s "Seagate Laptop Ultrathin HDD", "^ST(500LT03[23]|320LT03[01])$"
		Data.s "Seagate Laptop Thin HDD", "^ST(500LM021|320LM010)$"
		Data.s "Seagate Momentus Thin 5400.9", "^ST(50|32|25)0LT0(12|15|25)$"
		Data.s "Seagate Surveillance HDD", "^ST(4000VX000|3000VX002)$"
		Data.s "Seagate SV35.6 Series SATA Hard Drive ", "^ST[1-3]000VX000$"
		Data.s "Seagate Video 3.5 HDD", "^ST(4000VM000|3000VM002)$"
		Data.s "Seagate Pipeline HD", "^ST([12]000VM002|2000VM003|3(50|25)0312CS|3320311CS|1000322CS)$"
		Data.s "Seagate Enterprise Capacity 3.5 HDD (SATA)", "^ST(6000NM00[0248]4|[245]000NM00[24]4|5000NM0084)$"
		Data.s "Seagate Enterprise Capacity 3.5 HDD (SAS)", "^ST(6000NM0(0[135]|10)4|[245]000NM00[35]4)$"
		Data.s "Seagate Constellation ES (SAS)", "^ST(5|10|20)00NM00[024]1$"
		Data.s "Seagate Constellation ES (SATA)", "^ST(5|10|20)00NM00[135]1$"
		Data.s "Seagate Constellation ES.2 (SAS)", "^ST3(300065[0-2]|200064[5-7])SS$"
		Data.s "Seagate Constellation ES.2 (SATA)", "^ST3(300065[0-2]|200064[5-7])NS$"
		Data.s "Seagate Constellation ES.3 (SAS)", "^ST[1-4]000NM00[246]3$"
		Data.s "Seagate Constellation ES.3 (SATA)", "^ST[1-4]000NM00[35]3$"
		Data.s "Seagate Video 2.5 HDD", "^ST(50|32|25)0VT000$"
		Data.s "Seagate NAS 2-Bay", "^STCT([2468]|10)000200$"
		Data.s "Seagate NAS 4-Bay", "^STCU(4|8|16|20)000200$"
		Data.s "Seagate NAS Pro 2-Bay", "^STDD(2|4|8|10)000200$"
		Data.s "Seagate NAS Pro 4-Bay", "^STDE(4|8|16|20)000200$"
		Data.s "Seagate NAS Pro 6-Bay", "^STDF(6|12|24|30)000200$"
		Data.s "Seagate Business Storage 8-bay Rackmount NAS", "^STDP(8|12|16|24|32)000200$"
		Data.s "Seagate Business Storage 4-bay Rackmount NAS", "^STDN(4|8|12|16)000200$"
		Data.s "Seagate Business Storage Windows Server 4-bay NAS", "^STDM(4|8|12|16)000200$"
		Data.s "Seagate Business Storage 4-Bay NAS", "^STBP(4|8|12|16)000200$"
		Data.s "Seagate Business Storage 2-Bay NAS", "^STBN[468]000200$"
		Data.s "Seagate Business Storage 1-Bay NAS", "^STBM[2-4]000200$"
		Data.s "Seagate Terascale HDD", "^ST([124]000NC00[01]|3000NC00[02]$"
		Data.s "Seagate Savvio 10K.7", "^ST1200MM00[0-3]7$"
		Data.s "Seagate Savvio 10K.6", "^ST((90|60|45|30)0MM0026|900MM0036)$"
		Data.s "Seagate Savvio 10K.5", "^ST9(900[6-8]05SS|600[0-2]05SS|450[2-4]05SS|300[4-6]05SS|(9008|6002|4504|3006)05FC)$"
		Data.s "Seagate Enterprise Performance 15K.5 HDD", "^ST[36]00MP00[0-8]5$"
		Data.s "Seagate Savvio 15K.3 HDD", "^ST9(300[4-6]|146[6-8])53SS$"
		Data.s "Seagate Savvio 15K.2 HDD", "^ST9(146[6-8]|73[2-4])52SS$"
		Data.s "Seagate 1200 SSD", "^ST(1|2|4|8)00FM0(0[1-9]|1[0-2])3$"
		;Data.s "Seagate ", "^ST$"
		
		Data.s "Western Digital Protege", "^WDC WD([2468]00E|1[26]00A)B-.*$"
		Data.s "Western Digital Caviar", "^WDC WD(2|3|4|6|8|10|12|16|18|20|25)00BB-.*$"
		Data.s "Western Digital Caviar Black", "^WDC WD((((50|64|75)01A)|1001F)ALS)|2001FASS|1002FAEX-.*$"
		Data.s "Western Digital Caviar Green", "^WDC WD((50|64|75)00AAC|(64|80)00AAR|(10|15|20)EAR|(50|64|75)00AAD|(10|15|20)EAD|(50|64|75)00AAV|10EAV)S-.*$"
		Data.s "Western Digital Caviar Blue SATA with 32MB cache", "^WDC WD10EALS-.*$"
		Data.s "Western Digital Caviar Blue SATA with 16MB cache", "^WDC WD(25|32|40|50|64|75)00AAKS-.*$"
		Data.s "Western Digital Caviar Blue SATA with 8MB cache", "^WDC WD(8|12|16|25|32|40|50)00AAJS-.*$"
		Data.s "Western Digital Caviar Blue SATA with 8MB cache", "^WDC WD(400JB|800JD)-.*$"
		Data.s "Western Digital Caviar Blue SATA with 2MB cache", "^WDC WD(800BD|1600AABS)-.*$"
		Data.s "Western Digital Caviar Blue EIDE with 16MB cache", "^WDC WD(32|40|50)00AAKB-.*$"
		Data.s "Western Digital Caviar Blue EIDE with 8MB cache", "^WDC WD(8|16|25|32|40|50)00AAJB-.*$"
		Data.s "Western Digital Caviar Blue EIDE with 8MB cache", "^WDC WD800JB-.*$"
		Data.s "Western Digital Caviar Blue EIDE with 2MB cache", "^WDC WD1600AABB-.*$"
		Data.s "Western Digital Caviar Blue EIDE with 2MB cache", "^WDC WD([48]00BB)-.*$"
		Data.s "Western Digital AV", "^WDC WD(16|25|32|50)00AVJ[BS]-.*$";8
		Data.s "Western Digital AV", "^WDC WD1600AVBS-.*$";2
		Data.s "Western Digital AV-GP", "^WDC WD((16|25|32|50|64|75)00A|10E)VVS|(50|75)00AVDS|(10|15|20)EVDS|[123]0EUR[SX]|5000AUDX|(50|32|25|16)00AVCS-.*$";8/32
		Data.s "Western Digital AV-25", "^WDC WD(16|25|32|50)BUDT-.*$";32
		Data.s "Western Digital Caviar AC12500", "^WDC AC12500.?"
		Data.s "Western Digital Caviar AC14300", "^WDC AC14300.?"
		Data.s "Western Digital Caviar AC23200", "^WDC AC23200.?"
		Data.s "Western Digital Caviar AC24300", "^WDC AC24300.?"
		Data.s "Western Digital Caviar AC25100", "^WDC AC25100.?"
		Data.s "Western Digital Caviar AC36400", "^WDC AC36400.?"
		Data.s "Western Digital Caviar AC38400", "^WDC AC38400.?"
		Data.s "Western Digital Caviar WDxxxAB", "^WDC WD(3|4|6)00AB-.*$"
		Data.s "Western Digital Caviar WDxxxAA", "^WDC WD...?AA(-.*)?$"
		Data.s "Western Digital Caviar WDxxxBA", "^WDC WD...BA-.*$"
		Data.s "Western Digital Caviar Serial ATA", "^WDC WD(4|8|20|32)00BD-.*$"
		Data.s "Western Digital Caviar SE", "^WDC WD((4|6|8|10|12|16|18|20|25|30|32|40|50)00(JB|PB|AAJB|AAKB))-.*$"
		Data.s "Western Digital Caviar SE Serial ATA", "^WDC WD((4|8|12|16|20|25|32|40)00(JD|KD))-.*$"
		Data.s "Western Digital Caviar Second Generation Serial ATA", "^WDC WD((8|12|16|20|25|30|32|40|50|75)00(JS|KS|AABS|AAJS|AAKS))-.*$"
		Data.s "Western Digital Caviar RE Serial ATA", "^WDC WD((12|16|25|32|40|50|75)00(SD|YD|YR|YS|ABYS|AYYS))-.*$"
		Data.s "Western Digital Caviar RE EIDE", "^WDC WD((12|16|25|32)00SB)-.*$"
		Data.s "Western Digital RE2-GP", "^WDC WD(7500A|1000F)YPS-.*$";16
		Data.s "Western Digital RE3", "^WDC WD((25|32|50|75)02A|1002F)BYS-.*$";16/32
		Data.s "Western Digital RE4", "^WDC WD(25|50|10|15|20)03([AF]BYX|FYYS)-.*$";64
		Data.s "Western Digital RE4-GP", "^WDC WD2002FYPS-.*$";64
		Data.s "Western Digital Raptor", "^WDC WD((360|740|800)GD|(360|740|1500)ADFD)-.*$"
		Data.s "Western Digital VelociRaptor", "^WDC WD(15|30|45|60)00[BH]L(FS|HX)-.*$";16
		Data.s "Western Digital Scorpio", "^WDC WD((4|6|8|10|12|16|20|25)00(UE|VE|BEAS|BEVE|BEVS))-.*$"
		Data.s "Western Digital Scorpio Black", "^WDC WD(8|12|16|25|32|50)00B[EJ]KT-.*$";16
		Data.s "Western Digital Scorpio Blue", "^WDC WD(8|12|16|25|32|40|50|64|75)00B(EV[TSE]|PVT)-.*$";8
		Data.s "Western Digital SiliconEdge", "^WDC SSC-D0(064|128|256)SC-2100-.*$"
		
		Data.s "Western Digital Caviar Blue (Desktop drive)", "^WDC WD((10EZE|7500AZE|10EAL)X)|7500(AALX|AZEX)|5000A(ZLX|AKS)|((25|30|32|50)00AAKX)|((8|16|25|32)00AAJB)-.*$"
		Data.s "Western Digital Caviar Green (Desktop drive)", "^WDC WD((10|15|20|30|40|50|60)E|5000A)ZRX-.*$"
		Data.s "Western Digital Black (Desktop drive)", "^WDC WD[1234]003FZEX|5003AZEX|[12]002FAEX|[34]001FAEX-.*$"
		Data.s "Western Digital Blue (Mobile drive)", "^WDC WD(10(SPCX|JPV[XT]))|(7500(LPCX|BPVX))|(5000(MPCK|LPVX))|((25|32)00LPVX)|((25|32|50|75)00BPVT)|((25|32|50)00LPVT)-.*$"
		Data.s "Western Digital Green (Mobile drive)", "^WDC WD(15|20)NPV[TX]-.*$"
		Data.s "Western Digital Scorpio Black (Mobile drive)", "^WDC WD(50|75)00BPK[XT]|(16|25|32)00BEK[XT]-.*$"
		Data.s "Western Digital Black² (Mobile drive)", "^WDC WD1001X06XDTL-.*$"
		Data.s "Western Digital Red (NAS)", "^WDC WD(10|20|30|40|50|60)EFRX|(10J|7500B)FCX-.*$"
		Data.s "Western Digital Red Pro (NAS)", "^WDC WD[234]001FFSX-.*$"
		Data.s "Western Digital Re (NAS, Datacenter, Surveillance)", "^WDC WD[234]000FYYZ|1003FBY[XZ]|(25|50)03ABY[XZ]|2003FYYS|[1234]001FYYG-.*$"
		Data.s "Western Digital Xe (Datacenter)", "^WDC WD(30|45|60|90)01[BH]KHG-.*$"
		Data.s "Western Digital Se (Datacenter, Surveillance)", "^WDC WD(1002|[234]000)F9YZ-.*$"
		Data.s "Western Digital Purple (Surveillance)", "^WDC WD[1234]0PURX-.*$"
		Data.s "Western Digital AV", "^WDC WD(16|25|32|50)BUCT|5000LUCT|10JUCT|7500AURS|[1234]0EURX|(10|15|20|25|30)0EURS-.*$"
		Data.s "Western Digital VelociRaptor (Workstation)", "^WDC WD((25|50)00B|1000C|(25|50)00H|1000D)HTZ-.*$"
		Data.s "Western Digital Laptop Everyday (Internal Drive Kit)", "^WDC WDBMYH(0010B|5000A|3200A)NC-.*$"
		Data.s "Western Digital Desktop Everyday (Internal Drive Kit)", "^WDC WDBH2D(00[1234]0H|5000E)NC-.*$"
		Data.s "Western Digital Desktop Performance (Internal Drive Kit)", "^WDC WDBSLA00[124]0HNC-.*$"
		Data.s "Western Digital NAS (Internal Drive Kit)", "^WDC WDBMMA00[123]0HNC-.*$"
		Data.s "Western Digital My Book Duo (Desktop drive)", "^WDC WDBLWE0(12|0[468])0JCH-.*$"
		Data.s "Western Digital My Book (Desktop drive)", "^WDC WDBFJK00[2346]0HBK-.*$"
		Data.s "Western Digital Elements Desktop", "^WDC WDBWLG00[23]0HBK-.*$"
		Data.s "Western Digital My Passport Ultra (Portable drive)", "^WDC WDB(BUZ|MWV)0020B(RD|BK|TT|BL)|(JNZ|ZFP)0010B(RD|BK|TT|BL)|(LNP|PGC)5000A(BL|TT|BK|RD)|(MWV002|ZFP001)0BWT-.*$"
		Data.s "Western Digital My Passport Ultra Metal Edition (Portable drive)", "^WDC WDB(EZW|TYH)00[12]0B(BA|CG|SL)-.*$"
		Data.s "Western Digital My Passport Slim (Portable drive)", "^WDC WDB(PDZ|GMT)00[12]0BAL-.*$"
		Data.s "Western Digital Elements Portable", "^WDC WDBU(6Y|ZG)(5000|00[12]0|0015)BBK-.*$"
		Data.s "Western Digital My Book for Mac (Desktop drive)", "^WDC WDBYCC00[23]0HBK-.*$"
		Data.s "Western Digital My Book Studio (Desktop drive for Mac)", "^WDC WDBHML00[2-4]0HAL-.*$"
		Data.s "Western Digital My Book Thunderbolt Duo (Desktop drive for Mac)", "^WDC WDBUTV00[468]0JSL-.*$"
		Data.s "Western Digital My Book VelociRaptor Duo (Desktop drive for Mac)", "^WDC WDBUWZ0020JBK-.*$"
		Data.s "Western Digital My Passport Air (Portable drive for Mac)", "^WDC WDB(WDG0010B|BLW5000A)AL-.*$"
		Data.s "Western Digital My Passport for Mac (Portable drive)", "^WDC WDB(ZYL0020|LUZ0010)BSL|LUZ5000ASL-.*$"
		Data.s "Western Digital My Passport Studio (Portable drive for Mac)", "^WDC WDB(U4M002|GJA001)0BBK-.*$"
		Data.s "Western Digital My Passport Pro (Portable drive for Mac)", "^WDC WDBR(NB004|MP002)0DBK-.*$"
		Data.s "Western Digital My Cloud (Consumer Series)", "^WDC WDBCTL00[2346]0HWT-.*$"
		Data.s "Western Digital My Cloud Mirror (Consumer Series)", "^WDC WDBZVM0(04|06|08|10|12)0JWT-.*$"
		Data.s "Western Digital MY Cloud EX2 (Expert Series)", "^WDC WDBVKW00([468]0J|00N)CH-.*$"
		Data.s "Western Digital My Cloud EX4 (Expert Series)", "^WDC WDBWWD0((08|12|16)0K|000N)BK-.*$"
		Data.s "Western Digital My Passport Wireless", "^WDC WDB(DAF002BBK|K8Z0010BBK|LJT5000ABK)-.*$"
		Data.s "Western Digital My Book AV (DVR Expander)", "^WDC WDBABT0010HBK-.*$"
		Data.s "Western Digital Elements Play (Multimedia Drive)", "^WDC WDB(MCE|NLC)00[12]0HBK-.*$"
		Data.s "Western Digital TV (Media Player)", "^WDC WDB(YMN|PUF)0000NBK-.*$"
		Data.s "Western Digital My Book AV-TV (TV Storage)", "^WDC WDBGLG00[12]0HBK-.*$"
		Data.s "Western Digital My Passport AV-TV (TV Storage)", "^WDC WDBHDK(0010B|5000A)BK-.*$"
		Data.s "Western Digital Sentinel DX4000 (Network Storage Server)", "^WDC WDBLGT0(04|08|12|16)0KBK-.*$"
		Data.s "Western Digital Sentinel RX4100 (Network Storage Server)", "^WDC WDBLVH0(08|12|16)0KBK-.*$"
		Data.s "Western Digital Sentinel DS5100 (Ultra-compact Storage Plus Server)", "^WDC WDBYVE00[48]0KBK-.*$"
		Data.s "Western Digital Sentinel DS6100 (Ultra-compact Storage Plus Server)", "^WDC WDBWVL0(08|12|16)0KBK-.*$"
		Data.s "Western Digital My Passport Enterprise (Windows To Go Storage)", "^WDC WDBHEZ5000ABK-.*$"
		
		Data.s "Quantum BIGFOOT TS10.0A", "^QUANTUM BIGFOOT TS10.0A$"
		Data.s "Quantum FIREBALLlct15 20 And QUANTUM FIREBALLlct15 30", "^QUANTUM FIREBALLlct15 [123]0$"
		Data.s "Quantum FIREBALLlct20", "^QUANTUM FIREBALLlct20 [234]0$"
		Data.s "Quantum FIREBALL CX10.2A", "^QUANTUM FIREBALL CX10.2A$"
		Data.s "Quantum Fireball Plus LM", "^QUANTUM FIREBALLP LM(10.2|15|20.5|30)$"
		Data.s "Quantum Fireball CR", "^QUANTUM FIREBALL CR(4.3|8.4)A$"
		Data.s "Quantum FIREBALLP AS10.2, AS20.5, AS30.0, And AS40.0", "^QUANTUM FIREBALLP AS(10.2|20.5|30.0|40.0)$"
		Data.s "Quantum FIREBALL EX6.4A", "^QUANTUM FIREBALL EX6.4A$"
		Data.s "Quantum FIREBALL ST3.2A", "^QUANTUM FIREBALL ST(3.2|4.3)A$"
		Data.s "Quantum FIREBALL EX3.2A", "^QUANTUM FIREBALL EX3.2A$"
		Data.s "Quantum FIREBALLP KX27.3", "^QUANTUM FIREBALLP KX27.3$"
		Data.s "Quantum Fireball Plus KA", "^QUANTUM FIREBALLP KA(9|10).1$"
		Data.s "Quantum Fireball SE", "^QUANTUM FIREBALL SE4.3A$"
		Data.s ""	; Marks end of data
		;}
	EndDataSection
IdeasVacuum
Always Here
Always Here
Posts: 6425
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

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

Post by IdeasVacuum »

Great piece of code!

On my PC it has found all 4 internal drives and 1 of 2 external drives. The external drive it detected is a 4GB Seagate Expansion - that is detected as 2 drives, probably because of what the Seagate driver has to do to make it work with WinXP 32bit. The external drive it failed to find is a Seagate FreeAgent.

Despite all the info your app delivers, most will find it difficult to correlate if they have a number of drives and those are divided into partitions. What is needed is the OS partition letters and User-defined partition names.
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
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 »

The code is not 100% complete. There are 4-5 more ways to detect drives. They are similar to the new way I used (SPTD), but they use different Cdb[] input data. I will add them too, I just wanted to have a preliminary "taste" of what is going on. In an hour I will be at home, I will send you a code to see what data is returned from Seagate Expansion drive. You said that it is detected as 2 drives, maybe it is a bug in my code.... I will check it out.
Post Reply