mirror of
				https://github.com/pbatard/rufus.git
				synced 2024-08-14 23:57:05 +00:00 
			
		
		
		
	[core] SMART/ATA over USB initial support
* This is meant to be used as part of #219 * Also improve WindowsErrorString() so that it doesn't alter the current errcode
This commit is contained in:
		
							parent
							
								
									8d50a8491f
								
							
						
					
					
						commit
						803a4bff1c
					
				
					 12 changed files with 842 additions and 10 deletions
				
			
		|  | @ -189,6 +189,7 @@ | |||
|     <ClCompile Include="..\net.c" /> | ||||
|     <ClCompile Include="..\parser.c" /> | ||||
|     <ClCompile Include="..\rufus.c" /> | ||||
|     <ClCompile Include="..\smart.c" /> | ||||
|     <ClCompile Include="..\stdfn.c" /> | ||||
|     <ClCompile Include="..\stdio.c" /> | ||||
|     <ClCompile Include="..\stdlg.c" /> | ||||
|  | @ -210,6 +211,7 @@ | |||
|     <ClInclude Include="..\resource.h" /> | ||||
|     <ClInclude Include="..\rufus.h" /> | ||||
|     <ClInclude Include="..\license.h" /> | ||||
|     <ClInclude Include="..\smart.h" /> | ||||
|     <ClInclude Include="..\sys_types.h" /> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|  |  | |||
|  | @ -63,6 +63,9 @@ | |||
|     <ClCompile Include="..\localization.c"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|     <ClCompile Include="..\smart.c"> | ||||
|       <Filter>Source Files</Filter> | ||||
|     </ClCompile> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <ClInclude Include="..\rufus.h"> | ||||
|  | @ -110,6 +113,9 @@ | |||
|     <ClInclude Include="..\localization_data.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|     <ClInclude Include="..\smart.h"> | ||||
|       <Filter>Header Files</Filter> | ||||
|     </ClInclude> | ||||
|   </ItemGroup> | ||||
|   <ItemGroup> | ||||
|     <None Include="..\..\res\rufus.ico"> | ||||
|  |  | |||
|  | @ -43,6 +43,7 @@ SOURCES=rufus.c          \ | |||
|         dos_locale.c     \ | ||||
|         badblocks.c      \ | ||||
|         drive.c          \ | ||||
|         smart.c          \ | ||||
|         syslinux.c       \ | ||||
|         vhd.c            \ | ||||
|         rufus.rc | ||||
|  |  | |||
|  | @ -9,7 +9,7 @@ pkg_v_rc_0 = @echo "  RC     $@"; | |||
| %_rc.o: %.rc ../res/localization/embedded.loc | ||||
| 	$(pkg_v_rc)$(WINDRES) $(AM_RCFLAGS) -i $< -o $@ | ||||
| 
 | ||||
| rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c stdio.c stdfn.c stdlg.c rufus.c | ||||
| rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c smart.c stdio.c stdfn.c stdlg.c rufus.c | ||||
| rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./libcdio $(AM_CFLAGS) | ||||
| rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows | ||||
| rufus_LDADD = rufus_rc.o ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \ | ||||
|  |  | |||
|  | @ -48,9 +48,9 @@ am_rufus_OBJECTS = rufus-drive.$(OBJEXT) rufus-icon.$(OBJEXT) \ | |||
| 	rufus-iso.$(OBJEXT) rufus-net.$(OBJEXT) rufus-dos.$(OBJEXT) \
 | ||||
| 	rufus-dos_locale.$(OBJEXT) rufus-badblocks.$(OBJEXT) \
 | ||||
| 	rufus-syslinux.$(OBJEXT) rufus-vhd.$(OBJEXT) \
 | ||||
| 	rufus-format.$(OBJEXT) rufus-stdio.$(OBJEXT) \
 | ||||
| 	rufus-stdfn.$(OBJEXT) rufus-stdlg.$(OBJEXT) \
 | ||||
| 	rufus-rufus.$(OBJEXT) | ||||
| 	rufus-format.$(OBJEXT) rufus-smart.$(OBJEXT) \
 | ||||
| 	rufus-stdio.$(OBJEXT) rufus-stdfn.$(OBJEXT) \
 | ||||
| 	rufus-stdlg.$(OBJEXT) rufus-rufus.$(OBJEXT) | ||||
| rufus_OBJECTS = $(am_rufus_OBJECTS) | ||||
| rufus_DEPENDENCIES = rufus_rc.o ms-sys/libmssys.a \
 | ||||
| 	syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \
 | ||||
|  | @ -186,7 +186,7 @@ SUBDIRS = ms-sys syslinux/libfat syslinux/libinstaller libcdio/iso9660 libcdio/u | |||
| pkg_v_rc = $(pkg_v_rc_$(V)) | ||||
| pkg_v_rc_ = $(pkg_v_rc_$(AM_DEFAULT_VERBOSITY)) | ||||
| pkg_v_rc_0 = @echo "  RC     $@"; | ||||
| rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c stdio.c stdfn.c stdlg.c rufus.c | ||||
| rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c smart.c stdio.c stdfn.c stdlg.c rufus.c | ||||
| rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./libcdio $(AM_CFLAGS) | ||||
| rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows | ||||
| rufus_LDADD = rufus_rc.o ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \
 | ||||
|  | @ -343,6 +343,14 @@ rufus-format.obj: format.c | |||
| 	$(AM_V_CC) @AM_BACKSLASH@ | ||||
| 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-format.obj `if test -f 'format.c'; then $(CYGPATH_W) 'format.c'; else $(CYGPATH_W) '$(srcdir)/format.c'; fi` | ||||
| 
 | ||||
| rufus-smart.o: smart.c | ||||
| 	$(AM_V_CC) @AM_BACKSLASH@ | ||||
| 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-smart.o `test -f 'smart.c' || echo '$(srcdir)/'`smart.c | ||||
| 
 | ||||
| rufus-smart.obj: smart.c | ||||
| 	$(AM_V_CC) @AM_BACKSLASH@ | ||||
| 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-smart.obj `if test -f 'smart.c'; then $(CYGPATH_W) 'smart.c'; else $(CYGPATH_W) '$(srcdir)/smart.c'; fi` | ||||
| 
 | ||||
| rufus-stdio.o: stdio.c | ||||
| 	$(AM_V_CC) @AM_BACKSLASH@ | ||||
| 	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-stdio.o `test -f 'stdio.c' || echo '$(srcdir)/'`stdio.c | ||||
|  |  | |||
|  | @ -38,6 +38,9 @@ | |||
| RUFUS_DRIVE_INFO SelectedDrive; | ||||
| extern BOOL enable_fixed_disks; | ||||
| 
 | ||||
| // TODO: add a DetectSectorSize()?
 | ||||
| // http://msdn.microsoft.com/en-us/library/ff800831.aspx
 | ||||
| 
 | ||||
| /*
 | ||||
|  * Working with drive indexes quite risky (left unchecked,inadvertently passing 0 as | ||||
|  * index would return a handle to C:, which we might then proceed to unknowingly | ||||
|  |  | |||
|  | @ -730,6 +730,8 @@ static BOOL GetUSBDevices(DWORD devnum) | |||
| 				continue; | ||||
| 			} | ||||
| 
 | ||||
| //			Identify(hDrive);
 | ||||
| 
 | ||||
| 			if (GetDriveLabel(device_number.DeviceNumber + DRIVE_INDEX_MIN, &drive_letter, &label)) { | ||||
| 				// Must ensure that the combo box is UNSORTED for indexes to be the same
 | ||||
| 				StrArrayAdd(&DriveID, buffer); | ||||
|  |  | |||
|  | @ -350,6 +350,7 @@ extern char* replace_in_token_data(const char* filename, const char* token, cons | |||
| extern void parse_update(char* buf, size_t len); | ||||
| extern BOOL WimExtractCheck(void); | ||||
| extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst); | ||||
| extern BOOL Identify(HANDLE hPhysical); | ||||
| 
 | ||||
| static __inline BOOL UnlockDrive(HANDLE hDrive) | ||||
| { | ||||
|  |  | |||
							
								
								
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							|  | @ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL | |||
| IDD_DIALOG DIALOGEX 12, 12, 206, 329 | ||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||
| EXSTYLE WS_EX_APPWINDOW | ||||
| CAPTION "Rufus v1.4.0.314" | ||||
| CAPTION "Rufus v1.4.0.315" | ||||
| FONT 8, "MS Shell Dlg", 400, 0, 0x1 | ||||
| BEGIN | ||||
|     DEFPUSHBUTTON   "Start",IDC_START,94,291,50,14 | ||||
|  | @ -289,8 +289,8 @@ END | |||
| // | ||||
| 
 | ||||
| VS_VERSION_INFO VERSIONINFO | ||||
|  FILEVERSION 1,4,0,314 | ||||
|  PRODUCTVERSION 1,4,0,314 | ||||
|  FILEVERSION 1,4,0,315 | ||||
|  PRODUCTVERSION 1,4,0,315 | ||||
|  FILEFLAGSMASK 0x3fL | ||||
| #ifdef _DEBUG | ||||
|  FILEFLAGS 0x1L | ||||
|  | @ -307,13 +307,13 @@ BEGIN | |||
|         BEGIN | ||||
|             VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" | ||||
|             VALUE "FileDescription", "Rufus" | ||||
|             VALUE "FileVersion", "1.4.0.314" | ||||
|             VALUE "FileVersion", "1.4.0.315" | ||||
|             VALUE "InternalName", "Rufus" | ||||
|             VALUE "LegalCopyright", "© 2011-2013 Pete Batard (GPL v3)" | ||||
|             VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" | ||||
|             VALUE "OriginalFilename", "rufus.exe" | ||||
|             VALUE "ProductName", "Rufus" | ||||
|             VALUE "ProductVersion", "1.4.0.314" | ||||
|             VALUE "ProductVersion", "1.4.0.315" | ||||
|         END | ||||
|     END | ||||
|     BLOCK "VarFileInfo" | ||||
|  |  | |||
							
								
								
									
										400
									
								
								src/smart.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								src/smart.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,400 @@ | |||
| /*
 | ||||
|  * Rufus: The Reliable USB Formatting Utility | ||||
|  * SMART HDD vs Flash detection (using ATA over USB, S.M.A.R.T., etc.) | ||||
|  * Copyright © 2013 Pete Batard <pete@akeo.ie> | ||||
|  * | ||||
|  * Based in part on scsiata.cpp from Smartmontools: http://smartmontools.sourceforge.net
 | ||||
|  * Copyright © 2006-12 Douglas Gilbert <dgilbert@interlog.com> | ||||
|  * Copyright © 2009-13 Christian Franke <smartmontools-support@lists.sourceforge.net> | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| #ifdef _CRTDBG_MAP_ALLOC | ||||
| #include <stdlib.h> | ||||
| #include <crtdbg.h> | ||||
| #endif | ||||
| 
 | ||||
| #include <windows.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <ctype.h> | ||||
| #include <stddef.h> | ||||
| 
 | ||||
| #include "msapi_utf8.h" | ||||
| #include "rufus.h" | ||||
| #include "smart.h" | ||||
| 
 | ||||
| 
 | ||||
| /* Helper functions */ | ||||
| static uint8_t GetAtaDirection(uint8_t AtaCmd, uint8_t Features) { | ||||
| 	// Far from complete -- only the commands we *may* use.
 | ||||
| 
 | ||||
| 	// Most SMART commands require DATA_IN but there are a couple exceptions
 | ||||
| 	BOOL smart_out = (AtaCmd == ATA_SMART_CMD) &&  | ||||
| 		((Features == ATA_SMART_STATUS) || (Features == ATA_SMART_WRITE_LOG_SECTOR)); | ||||
| 
 | ||||
| 	switch (AtaCmd) { | ||||
| 	case ATA_IDENTIFY_DEVICE: | ||||
| 	case ATA_READ_LOG_EXT: | ||||
| 		return ATA_PASSTHROUGH_DATA_IN; | ||||
| 	case ATA_SMART_CMD: | ||||
| 		if (!smart_out) | ||||
| 			return ATA_PASSTHROUGH_DATA_IN; | ||||
| 		// fall through
 | ||||
| 	case ATA_DATA_SET_MANAGEMENT: | ||||
| 		return ATA_PASSTHROUGH_DATA_OUT; | ||||
| 	default: | ||||
| 		return ATA_PASSTHROUGH_DATA_NONE; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| const char* SptStrerr(int errcode) | ||||
| { | ||||
| 	static char scsi_err[64]; | ||||
| 
 | ||||
| 	if ((errcode > 0) && (errcode <= 0xff)) { | ||||
| 		safe_sprintf(scsi_err, sizeof(scsi_err), "SCSI status: 0x%02X", (uint8_t)errcode); | ||||
| 		return (const char*)scsi_err; | ||||
| 	} | ||||
| 
 | ||||
| 	switch(errcode) { | ||||
| 	case SPT_SUCCESS: | ||||
| 		return "Success"; | ||||
| 	case SPT_ERROR_CDB_LENGTH: | ||||
| 		return "Invalid CDB length"; | ||||
| 	case SPT_ERROR_BUFFER: | ||||
| 		return "Buffer must be aligned to a page boundary and less than 64KB in size"; | ||||
| 	case SPT_ERROR_DIRECTION: | ||||
| 		return "Invalid Direction"; | ||||
| 	case SPT_ERROR_EXTENDED_CDB: | ||||
| 		return "Extended and variable length CDB commands are not supported"; | ||||
| 	case SPT_ERROR_CDB_OPCODE: | ||||
| 		return "Opcodes above 0xC0 are not supported"; | ||||
| 	case SPT_ERROR_TIMEOUT: | ||||
| 		return "Timeout"; | ||||
| 	case SPT_ERROR_INVALID_PARAMETER: | ||||
| 		return "Invalid DeviceIoControl parameter"; | ||||
| 	case SPT_ERROR_CHECK_STATUS: | ||||
| 		return "SCSI error (check Status)"; | ||||
| 	default: | ||||
| 		return "Unknown error"; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * SCSI Passthrough (using IOCTL_SCSI_PASS_THROUGH_DIRECT) | ||||
|  * Should be provided a handle to the physical device (R/W) as well as a Cdb and a buffer that is page aligned | ||||
|  * Direction should be one of SCSI_IOCTL_DATA_### | ||||
|  * | ||||
|  * Returns 0 (SPT_SUCCESS) on success, a positive SCSI Status in case of an SCSI error or negative otherwise. | ||||
|  */ | ||||
| 
 | ||||
| BOOL ScsiPassthroughDirect(HANDLE hPhysical, uint8_t* Cdb, size_t CdbLen, uint8_t Direction, | ||||
| 						   void* DataBuffer, size_t BufLen, uint32_t Timeout) | ||||
| { | ||||
| 	SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER sptdwb = {{0}, 0, {0}}; | ||||
| 	DWORD err, size = sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER); | ||||
| 	BOOL r; | ||||
| 
 | ||||
| 	// Sanity checks
 | ||||
| 	if ((CdbLen == 0) || (CdbLen > sizeof(sptdwb.sptd.Cdb))) | ||||
| 		return SPT_ERROR_CDB_LENGTH; | ||||
| 
 | ||||
| 	if (((uintptr_t)DataBuffer % 0x10 != 0) || (BufLen > 0xFFFF)) | ||||
| 		return SPT_ERROR_BUFFER; | ||||
| 
 | ||||
| 	if (Direction > SCSI_IOCTL_DATA_UNSPECIFIED) | ||||
| 		return SPT_ERROR_DIRECTION; | ||||
| 
 | ||||
| 	// http://en.wikipedia.org/wiki/SCSI_command
 | ||||
| 	if ((Cdb[0] == 0x7e) || (Cdb[0] == 0x7f)) | ||||
| 		return SPT_ERROR_EXTENDED_CDB; | ||||
| 
 | ||||
| 	// Opcodes above 0xC0 are unsupported (apart for the special JMicron/Sunplus modes)
 | ||||
| 	if ( (Cdb[0] >= 0xc0) && (Cdb[0] != USB_JMICRON_ATA_PASSTHROUGH) | ||||
| 	  && (Cdb[0] != USB_SUNPLUS_ATA_PASSTHROUGH) ) | ||||
| 		return SPT_ERROR_CDB_OPCODE; | ||||
| 
 | ||||
| 	sptdwb.sptd.Length = sizeof(SCSI_PASS_THROUGH_DIRECT); | ||||
| 	sptdwb.sptd.PathId = 0; | ||||
| 	sptdwb.sptd.TargetId = 0; | ||||
| 	sptdwb.sptd.Lun = 0; | ||||
| 	sptdwb.sptd.CdbLength = (uint8_t)CdbLen; | ||||
| 	sptdwb.sptd.DataIn = Direction;		// One of SCSI_IOCTL_DATA_###
 | ||||
| 	sptdwb.sptd.SenseInfoLength = SPT_SENSE_LENGTH; | ||||
| 	sptdwb.sptd.DataTransferLength = (uint16_t)BufLen; | ||||
| 	sptdwb.sptd.TimeOutValue = Timeout; | ||||
| 	sptdwb.sptd.DataBuffer = DataBuffer; | ||||
| 	sptdwb.sptd.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, SenseBuf); | ||||
| 
 | ||||
| 	memcpy(sptdwb.sptd.Cdb, Cdb, CdbLen); | ||||
| 
 | ||||
| 	r = DeviceIoControl(hPhysical, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptdwb, size, &sptdwb, size, &size, FALSE); | ||||
| 	if ((r) && (sptdwb.sptd.ScsiStatus == 0)) { | ||||
| 		return SPT_SUCCESS; | ||||
| 	} | ||||
| 
 | ||||
| 	if (sptdwb.sptd.ScsiStatus != 0) { | ||||
| 		// uprintf("ScsiPassthroughDirect: CDB command 0x%02X failed (SCSI status 0x%02X)\n", Cdb[0], sptdwb.sptd.ScsiStatus);
 | ||||
| 		return (int)sptdwb.sptd.ScsiStatus; | ||||
| 	} else { | ||||
| 		err = GetLastError(); | ||||
| 		// uprintf("ScsiPassthroughDirect: CDB command 0x%02X failed %s\n", Cdb[0], WindowsErrorString()); SetLastError(err);
 | ||||
| 		switch(err) { | ||||
| 		case ERROR_SEM_TIMEOUT: | ||||
| 			return SPT_ERROR_TIMEOUT; | ||||
| 		case ERROR_INVALID_PARAMETER: | ||||
| 			return SPT_ERROR_INVALID_PARAMETER; | ||||
| 		default: | ||||
| 			return SPT_ERROR_UNKNOWN_ERROR; | ||||
| 		} | ||||
| 	} | ||||
| 	return FALSE; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* See ftp://ftp.t10.org/t10/document.04/04-262r8.pdf, http://www.scsitoolbox.com/pdfs/UsingSAT.pdf,
 | ||||
|  * as well as http://nevar.pl/pliki/ATA8-ACS-3.pdf */
 | ||||
| static int SatAtaPassthrough(HANDLE hPhysical, ATA_PASSTHROUGH_CMD* Command, void* DataBuffer, size_t BufLen, uint32_t Timeout) | ||||
| { | ||||
| 	uint8_t Cdb[12] = {0}; | ||||
| 	int extend = 0;     /* For 48-bit ATA command (unused here) */ | ||||
| 	int ck_cond = 0;    /* Set to 1 to read register(s) back */ | ||||
| 	int protocol = 3;   /* Non-data */ | ||||
| 	int t_dir = 1;      /* 0 -> to device, 1 -> from device */ | ||||
| 	int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ | ||||
| 	int t_length = 0;   /* 0 -> no data transferred */ | ||||
| 	uint8_t Direction; | ||||
| 
 | ||||
| 	if (BufLen % 512 != 0) { | ||||
| 		uprintf("SatAtaPassthrough: BufLen must be a multiple of <block size>\n"); | ||||
| 		return SPT_ERROR_BUFFER; | ||||
| 	} | ||||
| 
 | ||||
| 	// Set data direction
 | ||||
| 	Direction = GetAtaDirection(Command->AtaCmd, Command->Features); | ||||
| 	if (BufLen != 0) { | ||||
| 		switch (Direction) { | ||||
| 		case ATA_PASSTHROUGH_DATA_NONE: | ||||
| 			break; | ||||
| 		case ATA_PASSTHROUGH_DATA_IN: | ||||
| 			protocol = 4;  // PIO data-in
 | ||||
| 			t_length = 2;  // The transfer length is specified in the sector_count field
 | ||||
| 			break; | ||||
| 		case ATA_PASSTHROUGH_DATA_OUT: | ||||
| 			protocol = 5;  // PIO data-out
 | ||||
| 			t_length = 2;  // The transfer length is specified in the sector_count field
 | ||||
| 			t_dir = 0;     // to device
 | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	Cdb[0] = SAT_ATA_PASSTHROUGH_12; | ||||
| 	Cdb[1] = (protocol << 1) | extend; | ||||
| 	Cdb[2] = (ck_cond << 5) | (t_dir << 3) | (byte_block << 2) | t_length; | ||||
| 	Cdb[3] = Command->Features; | ||||
| 	Cdb[4] = (uint8_t)(BufLen >> SECTOR_SIZE_SHIFT_BIT); | ||||
| 	Cdb[5] = Command->Lba_low; | ||||
| 	Cdb[6] = Command->Lba_mid; | ||||
| 	Cdb[7] = Command->Lba_high; | ||||
| 	Cdb[8] = Command->Device;			// (m_port == 0 ? 0xa0 : 0xb0);  // Must be 0 for identify
 | ||||
| 	Cdb[9] = Command->AtaCmd; | ||||
| 
 | ||||
| 	return ScsiPassthroughDirect(hPhysical, Cdb, sizeof(Cdb), Direction, DataBuffer, BufLen, Timeout); | ||||
| } | ||||
| 
 | ||||
| /* The only differences between JMicron and Prolific are the extra 2 bytes for the CDB */ | ||||
| static int _UsbJMPLAtaPassthrough(HANDLE hPhysical, ATA_PASSTHROUGH_CMD* Command, | ||||
| 		void* DataBuffer, size_t BufLen, uint32_t Timeout, BOOL prolific) | ||||
| { | ||||
| 	uint8_t Cdb[14] = {0}; | ||||
| 	uint8_t Direction; | ||||
| 
 | ||||
| 	Direction = GetAtaDirection(Command->AtaCmd, Command->Features); | ||||
| 
 | ||||
| 	Cdb[0] = USB_JMICRON_ATA_PASSTHROUGH; | ||||
| 	Cdb[1] = ((BufLen != 0) && (Direction == ATA_PASSTHROUGH_DATA_OUT))?0x00:0x10; | ||||
| 	Cdb[3] = (uint8_t)(BufLen >> 8); | ||||
| 	Cdb[4] = (uint8_t)(BufLen); | ||||
| 	Cdb[5] = Command->Features; | ||||
| 	Cdb[6] = (uint8_t)(BufLen >> SECTOR_SIZE_SHIFT_BIT); | ||||
| 	Cdb[7] = Command->Lba_low; | ||||
| 	Cdb[8] = Command->Lba_mid; | ||||
| 	Cdb[9] = Command->Lba_high; | ||||
| 	Cdb[10] = Command->Device;			// (m_port == 0 ? 0xa0 : 0xb0);  // Must be 0 for identify
 | ||||
| 	Cdb[11] = Command->AtaCmd; | ||||
| 	// Prolific PL3507
 | ||||
| 	Cdb[12] = 0x06; | ||||
| 	Cdb[13] = 0x7b; | ||||
| 
 | ||||
| 	return ScsiPassthroughDirect(hPhysical, Cdb, sizeof(Cdb)-(prolific?2:0), Direction, DataBuffer, BufLen, Timeout); | ||||
| } | ||||
| 
 | ||||
| static int UsbJmicronAtaPassthrough(HANDLE hPhysical, ATA_PASSTHROUGH_CMD* Command, void* DataBuffer, size_t BufLen, uint32_t Timeout) | ||||
| { | ||||
| 	return _UsbJMPLAtaPassthrough(hPhysical, Command, DataBuffer, BufLen, Timeout, FALSE); | ||||
| } | ||||
| 
 | ||||
| /* UNTESTED!!! */ | ||||
| static int UsbProlificAtaPassthrough(HANDLE hPhysical, ATA_PASSTHROUGH_CMD* Command, void* DataBuffer, size_t BufLen, uint32_t Timeout) | ||||
| { | ||||
| 	return _UsbJMPLAtaPassthrough(hPhysical, Command, DataBuffer, BufLen, Timeout, TRUE); | ||||
| } | ||||
| 
 | ||||
| /* UNTESTED!!! */ | ||||
| static int UsbSunPlusAtaPassthrough(HANDLE hPhysical, ATA_PASSTHROUGH_CMD* Command, void* DataBuffer, size_t BufLen, uint32_t Timeout) | ||||
| { | ||||
| 	uint8_t Cdb[12] = {0}; | ||||
| 	uint8_t Direction; | ||||
| 
 | ||||
| 	Direction = GetAtaDirection(Command->AtaCmd, Command->Features); | ||||
| 
 | ||||
| 	Cdb[0] = USB_SUNPLUS_ATA_PASSTHROUGH; | ||||
| 	Cdb[2] = 0x22; | ||||
| 	if (BufLen != 0) { | ||||
| 		if (Direction == ATA_PASSTHROUGH_DATA_IN) | ||||
| 			Cdb[3] = 0x10; | ||||
| 		else if (Direction == ATA_PASSTHROUGH_DATA_OUT) | ||||
| 			Cdb[3] = 0x11; | ||||
| 	} | ||||
| 	Cdb[4] = (uint8_t)(BufLen >> SECTOR_SIZE_SHIFT_BIT); | ||||
| 	Cdb[5] = Command->Features; | ||||
| 	Cdb[6] = (uint8_t)(BufLen >> SECTOR_SIZE_SHIFT_BIT); | ||||
| 	Cdb[7] = Command->Lba_low; | ||||
| 	Cdb[8] = Command->Lba_mid; | ||||
| 	Cdb[9] = Command->Lba_high; | ||||
| 	Cdb[10] = Command->Device | 0xa0; | ||||
| 	Cdb[11] = Command->AtaCmd; | ||||
| 
 | ||||
| 	return ScsiPassthroughDirect(hPhysical, Cdb, sizeof(Cdb), Direction, DataBuffer, BufLen, Timeout); | ||||
| } | ||||
| 
 | ||||
| /* UNTESTED!!! */ | ||||
| /* See: http://kernel.opensuse.org/cgit/kernel/tree/drivers/usb/storage/cypress_atacb.c */ | ||||
| static int UsbCypressAtaPassthrough(HANDLE hPhysical, ATA_PASSTHROUGH_CMD* Command, void* DataBuffer, size_t BufLen, uint32_t Timeout) | ||||
| { | ||||
| 	uint8_t Cdb[16] = {0}; | ||||
| 	uint8_t Direction; | ||||
| 
 | ||||
| 	Direction = GetAtaDirection(Command->AtaCmd, Command->Features); | ||||
| 
 | ||||
| 	Cdb[0] = USB_CYPRESS_ATA_PASSTHROUGH; | ||||
| 	Cdb[1] = USB_CYPRESS_ATA_PASSTHROUGH; | ||||
| 	if (Command->AtaCmd == ATA_IDENTIFY_DEVICE || Command->AtaCmd == ATA_IDENTIFY_PACKET_DEVICE) | ||||
| 		Cdb[2] = (1<<7);				// Set IdentifyPacketDevice
 | ||||
| 	Cdb[3] = 0xff - (1<<0) - (1<<6);	// Features, sector count, lba low, lba med, lba high
 | ||||
| 	Cdb[4] = 1;							// Units in blocks rather than bytes
 | ||||
| 
 | ||||
| 	Cdb[6] = Command->Features; | ||||
| 	Cdb[7] = (uint8_t)(BufLen >> SECTOR_SIZE_SHIFT_BIT); | ||||
| 	Cdb[8] = Command->Lba_low; | ||||
| 	Cdb[9] = Command->Lba_mid; | ||||
| 	Cdb[10] = Command->Lba_high; | ||||
| 	Cdb[11] = Command->Device; | ||||
| 	Cdb[12] = Command->AtaCmd; | ||||
| 
 | ||||
| 	return ScsiPassthroughDirect(hPhysical, Cdb, sizeof(Cdb), Direction, DataBuffer, BufLen, Timeout); | ||||
| } | ||||
| 
 | ||||
| /* The various bridges we will try, in order */ | ||||
| AtaPassThroughType pt[] = { | ||||
| 	{ SatAtaPassthrough, "SAT" }, | ||||
| 	{ UsbJmicronAtaPassthrough, "JMicron" }, | ||||
| 	{ UsbProlificAtaPassthrough, "Prolific" }, | ||||
| 	{ UsbSunPlusAtaPassthrough, "SunPlus" }, | ||||
| 	{ UsbCypressAtaPassthrough, "Cypress" }, | ||||
| }; | ||||
| 
 | ||||
| BOOL Identify(HANDLE hPhysical) | ||||
| { | ||||
| 	ATA_PASSTHROUGH_CMD Command = {0}; | ||||
| 	IDENTIFY_DEVICE_DATA* idd; | ||||
| 	int i, r; | ||||
| 
 | ||||
| 	Command.AtaCmd = ATA_IDENTIFY_DEVICE; | ||||
| 
 | ||||
| 	// You'll get an error here if your compiler does not properly pack the IDENTIFY struct
 | ||||
| 	COMPILE_TIME_ASSERT(sizeof(IDENTIFY_DEVICE_DATA) == 512); | ||||
| 
 | ||||
| 	idd = (IDENTIFY_DEVICE_DATA*)_aligned_malloc(sizeof(IDENTIFY_DEVICE_DATA), 0x10); | ||||
| 	if (idd == NULL) | ||||
| 		return FALSE; | ||||
| 
 | ||||
| 	for (i=0; i<ARRAYSIZE(pt); i++) { | ||||
| 		r = pt[i].fn(hPhysical, &Command, idd, sizeof(IDENTIFY_DEVICE_DATA), SPT_TIMEOUT_VALUE); | ||||
| 		if (r == SPT_SUCCESS) { | ||||
| 			uprintf("Success using %s\n", pt[i].type); | ||||
| 			if (idd->CommandSetSupport.SmartCommands) { | ||||
| 				DumpBufferHex(idd, sizeof(IDENTIFY_DEVICE_DATA)); | ||||
| 				uprintf("SMART support detected!\n"); | ||||
| 			} else { | ||||
| 				uprintf("No SMART support\n"); | ||||
| 			} | ||||
| 			break; | ||||
| 		} | ||||
| 		uprintf("No joy with: %s (%s)\n", pt[i].type, SptStrerr(r)); | ||||
| 	} | ||||
| 	if (i >= ARRAYSIZE(pt)) | ||||
| 		uprintf("NO ATA FOR YOU!\n"); | ||||
| 
 | ||||
| 	_aligned_free(idd); | ||||
| 	return TRUE; | ||||
| } | ||||
| 
 | ||||
| /* Generic SMART access. Kept for reference, as it doesn't work for USB to ATA/SATA bridges */ | ||||
| #if 0 | ||||
| #pragma pack(1) | ||||
| typedef struct  { | ||||
| 	UCHAR  bVersion; | ||||
| 	UCHAR  bRevision; | ||||
| 	UCHAR  bReserved; | ||||
| 	UCHAR  bIDEDeviceMap; | ||||
| 	ULONG  fCapabilities; | ||||
| 	ULONG  dwReserved[4]; | ||||
| } MY_GETVERSIONINPARAMS; | ||||
| #pragma pack() | ||||
| 
 | ||||
| #ifndef SMART_GET_VERSION | ||||
| #define SMART_GET_VERSION \ | ||||
|   CTL_CODE(IOCTL_DISK_BASE, 0x0020, METHOD_BUFFERED, FILE_READ_ACCESS) | ||||
| #endif | ||||
| 
 | ||||
| BOOL SmartGetVersion(HANDLE hdevice) | ||||
| { | ||||
| 	MY_GETVERSIONINPARAMS vers; | ||||
| 	DWORD size = sizeof(MY_GETVERSIONINPARAMS); | ||||
| 	BOOL r; | ||||
| 
 | ||||
| 	memset(&vers, 0, sizeof(vers)); | ||||
| 
 | ||||
| 	r = DeviceIoControl(hdevice, SMART_GET_VERSION, NULL, 0, &vers, sizeof(vers), &size, NULL); | ||||
| 	if ( (!r) || (size != sizeof(MY_GETVERSIONINPARAMS)) ) { | ||||
| 		uprintf("SmartGetVersion failed: %s\n", r?"unexpected size":WindowsErrorString()); | ||||
| 		return FALSE; | ||||
| 	} | ||||
| 	uprintf("Smart Version: %d.%d, Caps = 0x%x, DeviceMap = 0x%02x\n", | ||||
| 		vers.bVersion, vers.bRevision, (unsigned)vers.fCapabilities, vers.bIDEDeviceMap); | ||||
| 
 | ||||
| 	return vers.bIDEDeviceMap; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* 
 | ||||
|  * TODO: SMART HDD vs UFD detection: | ||||
|  * - if the USB ID starts with  | ||||
|  * "WDC", "IBM", "ST" + number, "STM", "HTS", "HITACHI", "SEAGATE", "MAXTOR", "SAMSUNG", "HP ", "FUJITSU", "TOSHIBA", "QUANTUM" | ||||
|  * - if IDENTIFY reports SMART capabilities | ||||
|  * - if it has extra non hidden partitions that aren't Windows | ||||
|  * - if the VID:PID (or VID) is of known USB to IDE/SATA bridge or known UFD maker | ||||
|  */ | ||||
							
								
								
									
										407
									
								
								src/smart.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								src/smart.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,407 @@ | |||
| /*
 | ||||
|  * Rufus: The Reliable USB Formatting Utility | ||||
|  * SMART HDD vs Flash detection (using ATA over USB, S.M.A.R.T., etc.) | ||||
|  * Copyright © 2013 Pete Batard <pete@akeo.ie> | ||||
|  * | ||||
|  * Based in part on Smartmontools: http://smartmontools.sourceforge.net
 | ||||
|  * Copyright © 2006-12 Douglas Gilbert <dgilbert@interlog.com> | ||||
|  * Copyright © 2009-13 Christian Franke <smartmontools-support@lists.sourceforge.net> | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation, either version 3 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
|  */ | ||||
| 
 | ||||
| #if defined(__MINGW32__) | ||||
| #define _aligned_malloc                 __mingw_aligned_malloc | ||||
| #define _aligned_free                   __mingw_aligned_free | ||||
| #endif | ||||
| 
 | ||||
| // From http://stackoverflow.com/a/9284679
 | ||||
| #define COMPILE_TIME_ASSERT(pred)       switch(0) {case 0: case pred:;} | ||||
| 
 | ||||
| // Official commands
 | ||||
| #define ATA_DATA_SET_MANAGEMENT         0x06	// TRIM command for SSDs
 | ||||
| #define ATA_READ_LOG_EXT                0x2f | ||||
| #define ATA_CHECK_POWER_MODE            0xe5 | ||||
| #define ATA_IDENTIFY_DEVICE             0xec | ||||
| #define ATA_IDENTIFY_PACKET_DEVICE      0xa1 | ||||
| #define ATA_IDLE                        0xe3 | ||||
| #define ATA_SMART_CMD                   0xb0 | ||||
| #define ATA_SECURITY_FREEZE_LOCK        0xf5 | ||||
| #define ATA_SET_FEATURES                0xef | ||||
| #define ATA_STANDBY_IMMEDIATE           0xe0 | ||||
| #define SAT_ATA_PASSTHROUGH_12          0xa1 | ||||
| // Non official pseudo commands
 | ||||
| #define USB_CYPRESS_ATA_PASSTHROUGH     0x24 | ||||
| #define USB_JMICRON_ATA_PASSTHROUGH     0xdf | ||||
| #define USB_SUNPLUS_ATA_PASSTHROUGH     0xf8 | ||||
| 
 | ||||
| // SMART ATA Subcommands
 | ||||
| // Also see https://github.com/gregkh/ndas/blob/master/udev.c
 | ||||
| #define ATA_SMART_READ_VALUES           0xd0 | ||||
| #define ATA_SMART_READ_THRESHOLDS       0xd1 | ||||
| #define ATA_SMART_AUTOSAVE              0xd2 | ||||
| #define ATA_SMART_SAVE                  0xd3 | ||||
| #define ATA_SMART_IMMEDIATE_OFFLINE     0xd4 | ||||
| #define ATA_SMART_READ_LOG_SECTOR       0xd5 | ||||
| #define ATA_SMART_WRITE_LOG_SECTOR      0xd6 | ||||
| #define ATA_SMART_WRITE_THRESHOLDS      0xd7 | ||||
| #define ATA_SMART_ENABLE                0xd8 | ||||
| #define ATA_SMART_DISABLE               0xd9 | ||||
| #define ATA_SMART_STATUS                0xda | ||||
| 
 | ||||
| #define SCSI_IOCTL_DATA_OUT             0 | ||||
| #define SCSI_IOCTL_DATA_IN              1 | ||||
| #define SCSI_IOCTL_DATA_UNSPECIFIED     2 | ||||
| 
 | ||||
| #define ATA_PASSTHROUGH_DATA_OUT        SCSI_IOCTL_DATA_OUT | ||||
| #define ATA_PASSTHROUGH_DATA_IN         SCSI_IOCTL_DATA_IN | ||||
| #define ATA_PASSTHROUGH_DATA_NONE       SCSI_IOCTL_DATA_UNSPECIFIED | ||||
| 
 | ||||
| // Status codes returned by ScsiPassthroughDirect()
 | ||||
| #define SPT_SUCCESS                     0 | ||||
| #define SPT_ERROR_CDB_LENGTH            -1 | ||||
| #define SPT_ERROR_BUFFER                -2 | ||||
| #define SPT_ERROR_DIRECTION             -3 | ||||
| #define SPT_ERROR_EXTENDED_CDB          -4 | ||||
| #define SPT_ERROR_CDB_OPCODE            -5 | ||||
| #define SPT_ERROR_TIMEOUT               -6 | ||||
| #define SPT_ERROR_INVALID_PARAMETER     -7 | ||||
| #define SPT_ERROR_CHECK_STATUS          -8 | ||||
| #define SPT_ERROR_UNKNOWN_ERROR         -99 | ||||
| 
 | ||||
| #define SPT_CDB_LENGTH                  16 | ||||
| #define SPT_SENSE_LENGTH                32 | ||||
| #define SPT_TIMEOUT_VALUE               2	// In seconds
 | ||||
| #define SECTOR_SIZE_SHIFT_BIT           9	// We use 512 bytes sectors always
 | ||||
| 
 | ||||
| #define IOCTL_SCSI_BASE                 FILE_DEVICE_CONTROLLER | ||||
| #define IOCTL_SCSI_PASS_THROUGH         \ | ||||
| 	CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) | ||||
| #define IOCTL_SCSI_PASS_THROUGH_DIRECT  \ | ||||
| 	CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) | ||||
| 
 | ||||
| typedef struct { | ||||
| 	USHORT Length; | ||||
| 	UCHAR  ScsiStatus; | ||||
| 	UCHAR  PathId; | ||||
| 	UCHAR  TargetId; | ||||
| 	UCHAR  Lun; | ||||
| 	UCHAR  CdbLength; | ||||
| 	UCHAR  SenseInfoLength; | ||||
| 	UCHAR  DataIn; | ||||
| 	ULONG  DataTransferLength; | ||||
| 	ULONG  TimeOutValue; | ||||
| 	ULONG_PTR DataBufferOffset; | ||||
| 	ULONG  SenseInfoOffset; | ||||
| 	UCHAR  Cdb[SPT_CDB_LENGTH]; | ||||
| } SCSI_PASS_THROUGH; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	USHORT Length; | ||||
| 	UCHAR  ScsiStatus; | ||||
| 	UCHAR  PathId; | ||||
| 	UCHAR  TargetId; | ||||
| 	UCHAR  Lun; | ||||
| 	UCHAR  CdbLength; | ||||
| 	UCHAR  SenseInfoLength; | ||||
| 	UCHAR  DataIn; | ||||
| 	ULONG  DataTransferLength; | ||||
| 	ULONG  TimeOutValue; | ||||
| 	PVOID  DataBuffer; | ||||
| 	ULONG  SenseInfoOffset; | ||||
| 	UCHAR  Cdb[SPT_CDB_LENGTH]; | ||||
| } SCSI_PASS_THROUGH_DIRECT; | ||||
| 
 | ||||
| typedef struct { | ||||
| 	SCSI_PASS_THROUGH_DIRECT sptd; | ||||
| 	ULONG Align; | ||||
| 	UCHAR SenseBuf[SPT_SENSE_LENGTH]; | ||||
| } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; | ||||
| 
 | ||||
| // Custom ATA over USB command
 | ||||
| typedef struct { | ||||
| 	uint8_t AtaCmd;			// eg: ATA_SMART_CMD = 0xb0, IDENTIFY = 0xec, etc.
 | ||||
| 	uint8_t Features;		// SMART subcommand, eg: SMART_ENABLE_OPS = 0xd8, etc.
 | ||||
| 	uint8_t Device;			// 0x00 for Identify, 0xA0, 0xB0 for JMicron/SAT SMART ops
 | ||||
| 	uint8_t Align; | ||||
| 	uint8_t Lba_low;		// LBA
 | ||||
| 	uint8_t Lba_mid; | ||||
| 	uint8_t Lba_high; | ||||
| 	uint8_t Lba_unused; | ||||
| } ATA_PASSTHROUGH_CMD; | ||||
| 
 | ||||
| typedef BOOL (*AtaPassthroughFn_t)( | ||||
| 	HANDLE hPhysical, | ||||
| 	ATA_PASSTHROUGH_CMD* Command, | ||||
| 	void* DataBuffer, | ||||
| 	size_t BufLen, | ||||
| 	uint32_t Timeout | ||||
| ); | ||||
| 
 | ||||
| typedef struct { | ||||
| 	AtaPassthroughFn_t fn; | ||||
| 	const char* type; | ||||
| } AtaPassThroughType; | ||||
| 
 | ||||
| // From http://msdn.microsoft.com/en-us/library/windows/hardware/ff559006.aspx
 | ||||
| #pragma pack(1)		// Packed as the size must be 512 bytes exactly
 | ||||
| typedef struct _IDENTIFY_DEVICE_DATA { | ||||
| 	struct { | ||||
| 		USHORT Reserved1 :1; | ||||
| 		USHORT Retired3 :1; | ||||
| 		USHORT ResponseIncomplete :1; | ||||
| 		USHORT Retired2 :3; | ||||
| 		USHORT FixedDevice :1; | ||||
| 		USHORT RemovableMedia :1; | ||||
| 		USHORT Retired1 :7; | ||||
| 		USHORT DeviceType :1; | ||||
| 	} GeneralConfiguration; | ||||
| 	USHORT NumCylinders; | ||||
| 	USHORT ReservedWord2; | ||||
| 	USHORT NumHeads; | ||||
| 	USHORT Retired1[2]; | ||||
| 	USHORT NumSectorsPerTrack; | ||||
| 	USHORT VendorUnique1[3]; | ||||
| 	UCHAR  SerialNumber[20]; | ||||
| 	USHORT Retired2[2]; | ||||
| 	USHORT Obsolete1; | ||||
| 	UCHAR  FirmwareRevision[8]; | ||||
| 	UCHAR  ModelNumber[40]; | ||||
| 	UCHAR  MaximumBlockTransfer; | ||||
| 	UCHAR  VendorUnique2; | ||||
| 	USHORT ReservedWord48; | ||||
| 	struct { | ||||
| 		UCHAR  ReservedByte49; | ||||
| 		UCHAR  DmaSupported :1; | ||||
| 		UCHAR  LbaSupported :1; | ||||
| 		UCHAR  IordyDisable :1; | ||||
| 		UCHAR  IordySupported :1; | ||||
| 		UCHAR  Reserved1 :1; | ||||
| 		UCHAR  StandybyTimerSupport :1; | ||||
| 		UCHAR  Reserved2 :2; | ||||
| 		USHORT ReservedWord50; | ||||
| 	} Capabilities; | ||||
| 	USHORT ObsoleteWords51[2]; | ||||
| 	USHORT TranslationFieldsValid :3; | ||||
| 	USHORT Reserved3 :13; | ||||
| 	USHORT NumberOfCurrentCylinders; | ||||
| 	USHORT NumberOfCurrentHeads; | ||||
| 	USHORT CurrentSectorsPerTrack; | ||||
| 	ULONG  CurrentSectorCapacity; | ||||
| 	UCHAR  CurrentMultiSectorSetting; | ||||
| 	UCHAR  MultiSectorSettingValid :1; | ||||
| 	UCHAR  ReservedByte59 :7; | ||||
| 	ULONG  UserAddressableSectors; | ||||
| 	USHORT ObsoleteWord62; | ||||
| 	USHORT MultiWordDMASupport :8; | ||||
| 	USHORT MultiWordDMAActive :8; | ||||
| 	USHORT AdvancedPIOModes :8; | ||||
| 	USHORT ReservedByte64 :8; | ||||
| 	USHORT MinimumMWXferCycleTime; | ||||
| 	USHORT RecommendedMWXferCycleTime; | ||||
| 	USHORT MinimumPIOCycleTime; | ||||
| 	USHORT MinimumPIOCycleTimeIORDY; | ||||
| 	USHORT ReservedWords69[6]; | ||||
| 	USHORT QueueDepth :5; | ||||
| 	USHORT ReservedWord75 :11; | ||||
| 	USHORT ReservedWords76[4]; | ||||
| 	USHORT MajorRevision; | ||||
| 	USHORT MinorRevision; | ||||
| 	struct { | ||||
| 		USHORT SmartCommands :1; | ||||
| 		USHORT SecurityMode :1; | ||||
| 		USHORT RemovableMediaFeature :1; | ||||
| 		USHORT PowerManagement :1; | ||||
| 		USHORT Reserved1 :1; | ||||
| 		USHORT WriteCache :1; | ||||
| 		USHORT LookAhead :1; | ||||
| 		USHORT ReleaseInterrupt :1; | ||||
| 		USHORT ServiceInterrupt :1; | ||||
| 		USHORT DeviceReset :1; | ||||
| 		USHORT HostProtectedArea :1; | ||||
| 		USHORT Obsolete1 :1; | ||||
| 		USHORT WriteBuffer :1; | ||||
| 		USHORT ReadBuffer :1; | ||||
| 		USHORT Nop :1; | ||||
| 		USHORT Obsolete2 :1; | ||||
| 		USHORT DownloadMicrocode :1; | ||||
| 		USHORT DmaQueued :1; | ||||
| 		USHORT Cfa :1; | ||||
| 		USHORT AdvancedPm :1; | ||||
| 		USHORT Msn :1; | ||||
| 		USHORT PowerUpInStandby :1; | ||||
| 		USHORT ManualPowerUp :1; | ||||
| 		USHORT Reserved2 :1; | ||||
| 		USHORT SetMax :1; | ||||
| 		USHORT Acoustics :1; | ||||
| 		USHORT BigLba :1; | ||||
| 		USHORT DeviceConfigOverlay :1; | ||||
| 		USHORT FlushCache :1; | ||||
| 		USHORT FlushCacheExt :1; | ||||
| 		USHORT Resrved3 :2; | ||||
| 		USHORT SmartErrorLog :1; | ||||
| 		USHORT SmartSelfTest :1; | ||||
| 		USHORT MediaSerialNumber :1; | ||||
| 		USHORT MediaCardPassThrough :1; | ||||
| 		USHORT StreamingFeature :1; | ||||
| 		USHORT GpLogging :1; | ||||
| 		USHORT WriteFua :1; | ||||
| 		USHORT WriteQueuedFua :1; | ||||
| 		USHORT WWN64Bit :1; | ||||
| 		USHORT URGReadStream :1; | ||||
| 		USHORT URGWriteStream :1; | ||||
| 		USHORT ReservedForTechReport :2; | ||||
| 		USHORT IdleWithUnloadFeature :1; | ||||
| 		USHORT Reserved4 :2; | ||||
| 	} CommandSetSupport; | ||||
| 	struct { | ||||
| 		USHORT SmartCommands :1; | ||||
| 		USHORT SecurityMode :1; | ||||
| 		USHORT RemovableMediaFeature :1; | ||||
| 		USHORT PowerManagement :1; | ||||
| 		USHORT Reserved1 :1; | ||||
| 		USHORT WriteCache :1; | ||||
| 		USHORT LookAhead :1; | ||||
| 		USHORT ReleaseInterrupt :1; | ||||
| 		USHORT ServiceInterrupt :1; | ||||
| 		USHORT DeviceReset :1; | ||||
| 		USHORT HostProtectedArea :1; | ||||
| 		USHORT Obsolete1 :1; | ||||
| 		USHORT WriteBuffer :1; | ||||
| 		USHORT ReadBuffer :1; | ||||
| 		USHORT Nop :1; | ||||
| 		USHORT Obsolete2 :1; | ||||
| 		USHORT DownloadMicrocode :1; | ||||
| 		USHORT DmaQueued :1; | ||||
| 		USHORT Cfa :1; | ||||
| 		USHORT AdvancedPm :1; | ||||
| 		USHORT Msn :1; | ||||
| 		USHORT PowerUpInStandby :1; | ||||
| 		USHORT ManualPowerUp :1; | ||||
| 		USHORT Reserved2 :1; | ||||
| 		USHORT SetMax :1; | ||||
| 		USHORT Acoustics :1; | ||||
| 		USHORT BigLba :1; | ||||
| 		USHORT DeviceConfigOverlay :1; | ||||
| 		USHORT FlushCache :1; | ||||
| 		USHORT FlushCacheExt :1; | ||||
| 		USHORT Resrved3 :2; | ||||
| 		USHORT SmartErrorLog :1; | ||||
| 		USHORT SmartSelfTest :1; | ||||
| 		USHORT MediaSerialNumber :1; | ||||
| 		USHORT MediaCardPassThrough :1; | ||||
| 		USHORT StreamingFeature :1; | ||||
| 		USHORT GpLogging :1; | ||||
| 		USHORT WriteFua :1; | ||||
| 		USHORT WriteQueuedFua :1; | ||||
| 		USHORT WWN64Bit :1; | ||||
| 		USHORT URGReadStream :1; | ||||
| 		USHORT URGWriteStream :1; | ||||
| 		USHORT ReservedForTechReport :2; | ||||
| 		USHORT IdleWithUnloadFeature :1; | ||||
| 		USHORT Reserved4 :2; | ||||
| 	} CommandSetActive; | ||||
| 	USHORT UltraDMASupport :8; | ||||
| 	USHORT UltraDMAActive :8; | ||||
| 	USHORT ReservedWord89[4]; | ||||
| 	USHORT HardwareResetResult; | ||||
| 	USHORT CurrentAcousticValue :8; | ||||
| 	USHORT RecommendedAcousticValue :8; | ||||
| 	USHORT ReservedWord95[5]; | ||||
| 	ULONG  Max48BitLBA[2]; | ||||
| 	USHORT StreamingTransferTime; | ||||
| 	USHORT ReservedWord105; | ||||
| 	struct { | ||||
| 		USHORT LogicalSectorsPerPhysicalSector :4; | ||||
| 		USHORT Reserved0 :8; | ||||
| 		USHORT LogicalSectorLongerThan256Words :1; | ||||
| 		USHORT MultipleLogicalSectorsPerPhysicalSector :1; | ||||
| 		USHORT Reserved1 :2; | ||||
| 	} PhysicalLogicalSectorSize; | ||||
| 	USHORT InterSeekDelay; | ||||
| 	USHORT WorldWideName[4]; | ||||
| 	USHORT ReservedForWorldWideName128[4]; | ||||
| 	USHORT ReservedForTlcTechnicalReport; | ||||
| 	USHORT WordsPerLogicalSector[2]; | ||||
| 	struct { | ||||
| 		USHORT ReservedForDrqTechnicalReport :1; | ||||
| 		USHORT WriteReadVerifySupported :1; | ||||
| 		USHORT Reserved01 :11; | ||||
| 		USHORT Reserved1 :2; | ||||
| 	} CommandSetSupportExt; | ||||
| 	struct { | ||||
| 		USHORT ReservedForDrqTechnicalReport :1; | ||||
| 		USHORT WriteReadVerifyEnabled :1; | ||||
| 		USHORT Reserved01 :11; | ||||
| 		USHORT Reserved1 :2; | ||||
| 	} CommandSetActiveExt; | ||||
| 	USHORT ReservedForExpandedSupportandActive[6]; | ||||
| 	USHORT MsnSupport :2; | ||||
| 	USHORT ReservedWord1274 :14; | ||||
| 	struct { | ||||
| 		USHORT SecuritySupported :1; | ||||
| 		USHORT SecurityEnabled :1; | ||||
| 		USHORT SecurityLocked :1; | ||||
| 		USHORT SecurityFrozen :1; | ||||
| 		USHORT SecurityCountExpired :1; | ||||
| 		USHORT EnhancedSecurityEraseSupported :1; | ||||
| 		USHORT Reserved0 :2; | ||||
| 		USHORT SecurityLevel :1; | ||||
| 		USHORT Reserved1 :7; | ||||
| 	} SecurityStatus; | ||||
| 	USHORT ReservedWord129[31]; | ||||
| 	struct { | ||||
| 		USHORT MaximumCurrentInMA2 :12; | ||||
| 		USHORT CfaPowerMode1Disabled :1; | ||||
| 		USHORT CfaPowerMode1Required :1; | ||||
| 		USHORT Reserved0 :1; | ||||
| 		USHORT Word160Supported :1; | ||||
| 	} CfaPowerModel; | ||||
| 	USHORT ReservedForCfaWord161[8]; | ||||
| 	struct { | ||||
| 		USHORT SupportsTrim :1; | ||||
| 		USHORT Reserved0 :15; | ||||
| 	} DataSetManagementFeature; | ||||
| 	USHORT ReservedForCfaWord170[6]; | ||||
| 	USHORT CurrentMediaSerialNumber[30]; | ||||
| 	USHORT ReservedWord206; | ||||
| 	USHORT ReservedWord207[2]; | ||||
| 	struct { | ||||
| 		USHORT AlignmentOfLogicalWithinPhysical :14; | ||||
| 		USHORT Word209Supported :1; | ||||
| 		USHORT Reserved0 :1; | ||||
| 	} BlockAlignment; | ||||
| 	USHORT WriteReadVerifySectorCountMode3Only[2]; | ||||
| 	USHORT WriteReadVerifySectorCountMode2Only[2]; | ||||
| 	struct { | ||||
| 		USHORT NVCachePowerModeEnabled :1; | ||||
| 		USHORT Reserved0 :3; | ||||
| 		USHORT NVCacheFeatureSetEnabled :1; | ||||
| 		USHORT Reserved1 :3; | ||||
| 		USHORT NVCachePowerModeVersion :4; | ||||
| 		USHORT NVCacheFeatureSetVersion :4; | ||||
| 	} NVCacheCapabilities; | ||||
| 	USHORT NVCacheSizeLSW; | ||||
| 	USHORT NVCacheSizeMSW; | ||||
| 	USHORT NominalMediaRotationRate; | ||||
| 	USHORT ReservedWord218; | ||||
| 	struct { | ||||
| 		UCHAR NVCacheEstimatedTimeToSpinUpInSeconds; | ||||
| 		UCHAR Reserved; | ||||
| 	} NVCacheOptions; | ||||
| 	USHORT ReservedWord220[35]; | ||||
| 	USHORT Signature :8; | ||||
| 	USHORT CheckSum :8; | ||||
| } IDENTIFY_DEVICE_DATA, *PIDENTIFY_DEVICE_DATA; | ||||
| #pragma pack() | ||||
|  | @ -129,6 +129,8 @@ static char err_string[256] = {0}; | |||
| 		else | ||||
| 			safe_sprintf(err_string, sizeof(err_string), "Unknown error 0x%08X", error_code); | ||||
| 	} | ||||
| 
 | ||||
| 	SetLastError(error_code);	// Make sure we don't change the errorcode on exit
 | ||||
| 	return err_string; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue