mirror of
https://github.com/marciot/mac-tip.git
synced 2024-12-28 12:32:10 +00:00
1952 lines
74 KiB
NASM
1952 lines
74 KiB
NASM
;+-----------------------------------------------------------------------------+
|
||
;| ASPI.ASM Aspi Functions for Trouble In Paradise? |
|
||
;+-----------------------------------------------------------------------------+
|
||
|
||
DEFECT_LIST_HEADER struct 1t
|
||
;-------------------------------------------------------------------------------
|
||
DLH_reserved BYTE ? ; (00h)
|
||
DLH_BitFlags BYTE ? ; [000] [P] [G] [xxx - defect list format]
|
||
DLH_DefectListLength WORD ? ;
|
||
;-------------------------------------------------------------------------------
|
||
DEFECT_LIST_HEADER ends
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| CHECK FOR ASPI |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| This locates the system's ASPI functions. If all goes well it sets two |
|
||
;| pointers to the WinASPI entrypoints and returns with EAX != 0. In the |
|
||
;| event of trouble it sets the error message into the TROUBLE window, and |
|
||
;| sets the ErrorMode flag to cause the Trouble panel to be displayed. |
|
||
;+-----------------------------------------------------------------------------+
|
||
CheckForASPI PROC USES esi edi
|
||
;-------------------------------------------------------------------------------
|
||
; suppress any DLL not found errors and try to load our DLL
|
||
invoke SetErrorMode, SEM_NOOPENFILEERRORBOX
|
||
mov edi, eax
|
||
invoke LoadLibrary, ADDR szASPI32DLLName
|
||
IF FORCE_TROUBLE
|
||
zero eax
|
||
ENDIF
|
||
mov esi, eax
|
||
invoke SetErrorMode, edi
|
||
.IF (esi)
|
||
mov hASPIDLL, esi
|
||
invoke GetProcAddress, esi, ADDR szASPI32SupportInfo
|
||
mov lpGetASPI32SupportInfo, eax
|
||
invoke GetProcAddress, esi, ADDR szASPI32Command
|
||
mov lpSendASPI32Command, eax
|
||
invoke GetASPI32SupportInfoPtr PTR lpGetASPI32SupportInfo
|
||
cmp ah, SS_COMP ; did we succeed perfectly?
|
||
je Exit ; yep, so off we go ...
|
||
cmp ah, SS_FAILED_INIT ; nope, did we init fail?
|
||
jne No_ASPI ; nope, so some error
|
||
set ErrorMode
|
||
.ELSE ; set the static text for the ASPI version problem control
|
||
No_ASPI: set BadASPIDrivers
|
||
.ENDIF
|
||
zero eax
|
||
Exit: movzx eax, al
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
CheckForASPI ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| HOST ADAPTER INQUIRY |
|
||
;+-----------------------------------------------------------------------------+
|
||
HostAdapterInquiry PROC Adapter:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
ZeroASPI ; clear out our calling block's parameters
|
||
mov ASPI_CmdBlock.hai.SRB_Cmd, SC_HA_INQUIRY
|
||
movmov ASPI_CmdBlock.hai.SRB_HaId, al, byte ptr Adapter
|
||
invoke SendASPI32CommandPtr PTR lpSendASPI32Command, ADDR ASPI_CmdBlock
|
||
movzx eax, ASPI_CmdBlock.hai.SRB_Status
|
||
dec eax
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
HostAdapterInquiry ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| GET DEVICE TYPE |
|
||
;+-----------------------------------------------------------------------------+
|
||
GetDeviceType PROC Adapter:DWORD, Device:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
ZeroASPI
|
||
mov ASPI_CmdBlock.gdt.SRB_Cmd, SC_GET_DEV_TYPE ; w: ASPI command code
|
||
movmov ASPI_CmdBlock.gdt.SRB_HaId, al, byte ptr Adapter ; w: ASPI host adapter number
|
||
movmov ASPI_CmdBlock.gdt.SRB_Target, al, byte ptr Device ; w: target's SCSI ID
|
||
; do the command ...
|
||
invoke SendASPI32CommandPtr PTR lpSendASPI32Command, ADDR ASPI_CmdBlock
|
||
movzx eax, ASPI_CmdBlock.gdt.SRB_Status
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
GetDeviceType ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| GET DRIVE ENTRY OFFSET |
|
||
;| Returns the offset of the chosen drive's status word in EAX |
|
||
;+-----------------------------------------------------------------------------+
|
||
GetDriveEntryOffset PROC Adapter:DWORD, Device:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
mov eax, OFFSET DriveArray - SIZEOF DWORD
|
||
mov bl, byte ptr Adapter
|
||
mov bh, byte ptr Device
|
||
Next: add eax, SIZEOF DWORD
|
||
cmp [eax], bx ; did we find the right table slot?
|
||
jne Next
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
GetDriveEntryOffset ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| GET COMMAND DETAILS |
|
||
;| Given a SCSI command byte, this returns the command |
|
||
;| block length in AL and the Command Flags in AH. |
|
||
;+-----------------------------------------------------------------------------+
|
||
GetCommandDetails PROC USES ebx esi, command:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
mov bl, command
|
||
mov ecx, LENGTH_OF_DETAILS_TABLE
|
||
mov esi, OFFSET CommandDetailsTable
|
||
; search the table for the command entry
|
||
.REPEAT
|
||
lodsw ; pickup a command/FLAG pair
|
||
.BREAK .IF (al == bl) ; if we match we're done
|
||
.IF (ecx == 1) ; if we didn't locate it ...
|
||
zero eax ; return ZERO
|
||
jmp Exit
|
||
.ENDIF
|
||
.UNTILCXZ
|
||
mov al, 6 ; presume a short (6 byte) command
|
||
.IF (bl > TEN_BYTE_CMDS) ; but if it's a LONG one ....
|
||
mov al, 10 ; then return that
|
||
.ENDIF
|
||
Exit: ret
|
||
;-------------------------------------------------------------------------------
|
||
GetCommandDetails ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| SCSI COMMAND |
|
||
;| This executes a SCSI command through the ASPI interface. It receives a |
|
||
;| NEAR pointer to a standard SCSI command block (SCB) and a pointer and |
|
||
;| length to an IoBuffer for the command. It returns in EAX the complete |
|
||
;| three-byte sense code from the command. |
|
||
;+-----------------------------------------------------------------------------+
|
||
SCSICommand PROC USES esi edi, Adapter:DWORD, Device:DWORD, lpCmdBlk:LPVOID, lpIoBuf:LPVOID, IoBufLen:DWORD
|
||
LOCAL AbortSRB:SRB_Abort
|
||
;-------------------------------------------------------------------------------
|
||
ZeroASPI
|
||
mov ASPI_CmdBlock.io.SRB_Cmd, SC_EXEC_SCSI_CMD ; w: ASPI command code = SC_EXEC_SCSI_CMD
|
||
movmov ASPI_CmdBlock.io.SRB_HaId, al, byte ptr Adapter ; w: ASPI host adapter number
|
||
movmov ASPI_CmdBlock.io.SRB_Target, al, byte ptr Device ; w: target's SCSI ID
|
||
movmov ASPI_CmdBlock.io.SRB_BufPointer, eax, lpIoBuf ; w: data buffer pointer
|
||
movmov ASPI_CmdBlock.io.SRB_BufLen, eax, IoBufLen ; w: data allocation length
|
||
mov ASPI_CmdBlock.io.SRB_SenseLen, SIZEOF ASPI_CmdBlock.io.SRB_SenseArea ; w: sense allocation length
|
||
mov ASPI_CmdBlock.io.SRB_Flags, SRB_EVENT_NOTIFY ; w: SCSI request flags
|
||
movmov ASPI_CmdBlock.io.SRB_PostProc, eax, hCompletionEvent
|
||
|
||
; assemble our scsi command block
|
||
mov esi, lpCmdBlk ; get a pointer to the scsi command
|
||
invoke GetCommandDetails, [esi] ; al == cmd_length, ah == cmd_flags
|
||
or ASPI_CmdBlock.io.SRB_Flags, ah ; w: SCSI request flags
|
||
mov ASPI_CmdBlock.io.SRB_CDBLen, al ; w: CDB Length
|
||
|
||
; move the command block into the ASPI structure
|
||
lea edi, ASPI_CmdBlock.io.SRB_CDBByte
|
||
movzx ecx, al
|
||
rep movsb
|
||
|
||
; call the ASPI manager to forward the command to the device
|
||
invoke SendASPI32CommandPtr PTR lpSendASPI32Command, ADDR ASPI_CmdBlock
|
||
invoke WaitForSingleObject, hCompletionEvent, SCSI_TIMEOUT
|
||
movzx eax, ASPI_CmdBlock.io.SRB_Status
|
||
|
||
; if the command did not generate any Sense Data, just return NULL
|
||
.IF (al == SS_COMP)
|
||
NoError: zero eax
|
||
|
||
; else, if it's *NOT* a "Sense Data" error (SS_ERR)
|
||
.ELSEIF (al != SS_ERR)
|
||
movzx eax, al
|
||
or eax, 00FFFF00h ; [00 FF FF er]
|
||
|
||
; okay, we have an SS_ERR condition, let's check the SENSE DATA
|
||
.ELSE ; assemble [00 ASC ASCQ SenseKey]
|
||
movzx eax, word ptr ASPI_CmdBlock.io.SRB_SenseArea[12] ; [00 00 ASCQ ASC]
|
||
swap ah, al ; [00 00 ASC ASCQ]
|
||
shl eax, 8 ; [00 ASC ASCQ 00]
|
||
mov al, ASPI_CmdBlock.io.SRB_SenseArea[2] ; [00 ASC ASCQ xSenseKey]
|
||
and al, 0Fh ; [00 ASC ASCQ SenseKey]
|
||
.IF (eax == MEDIA_CHANGE_CODE)
|
||
invoke GetDriveEntryOffset, Adapter, Device
|
||
or dword ptr [eax], MEDIA_CHANGED
|
||
jmp NoError
|
||
.ELSEIF (!eax) ; if we had NO SENSE error, but SS_ERR
|
||
mov eax, SS_ERR ; return SS_ERR
|
||
.ENDIF
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
SCSICommand ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| ENUMERATE IOMEGA DEVICES |
|
||
;+-----------------------------------------------------------------------------+
|
||
EnumerateIomegaDevices PROC USES ebx
|
||
LOCAL FirstInvalidAdapter:DWORD, Scsi[6]:BYTE,
|
||
InqData[96]:CHAR, Adapter:DWORD, Device:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
IFE FORCE_NO_DRIVES
|
||
; get the total adapter count
|
||
invoke HostAdapterInquiry, 0
|
||
movzx eax, ASPI_CmdBlock.hai.HA_Count
|
||
; see whether it completed successfully
|
||
.IF (ASPI_CmdBlock.hai.SRB_Status != SS_COMP) || (!eax)
|
||
jmp Exit
|
||
.ENDIF
|
||
mov FirstInvalidAdapter, eax
|
||
reset Adapter
|
||
reset DriveCount ; reset the global DriveCount variable
|
||
.REPEAT
|
||
; check each adapter for "ppa3" string and small blk xfers
|
||
invoke HostAdapterInquiry, Adapter
|
||
.IF (ASPI_CmdBlock.hai.SRB_Status == SS_COMP)
|
||
; truncate at four chars so "PPA3NT" and "ppa3" both match!
|
||
mov byte ptr ASPI_CmdBlock.hai.HA_Identifier[4], 0
|
||
invoke lstrcmpi, ADDR ASPI_CmdBlock.hai.HA_Identifier, ADDR szPPA3
|
||
.IF (!eax)
|
||
mov eax, dword ptr ASPI_CmdBlock.hai.HA_Unique[4]
|
||
.IF (eax < 65536)
|
||
set OldPPA3Driver
|
||
.ENDIF
|
||
.ENDIF
|
||
.ENDIF
|
||
|
||
; now scan the devices on this host adapter
|
||
reset Device
|
||
.REPEAT
|
||
invoke GetDeviceType, Adapter, Device
|
||
cmp eax, SS_COMP
|
||
jne TryNextDrive
|
||
;--------------------------------------------------------------------------
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_Inquiry
|
||
mov Scsi[4], SIZEOF InqData
|
||
invoke SCSICommand, Adapter, Device, ADDR Scsi, ADDR InqData, SIZEOF InqData
|
||
check eax
|
||
jnz TryNextDrive
|
||
;--------------------------------------------------------------------------
|
||
mov byte ptr InqData[14], 0
|
||
invoke lstrcmpi, ADDR szIomega, ADDR InqData[8]
|
||
check eax
|
||
jnz TryNextDrive
|
||
;--------------------------------------------------------------------------
|
||
mov byte ptr InqData[19], 0
|
||
invoke lstrcmpi, ADDR szZip, ADDR InqData[16]
|
||
check eax
|
||
jz FoundZipOrJaz
|
||
;--------------------------------------------------------------------------
|
||
invoke lstrcmpi, ADDR szJaz, ADDR InqData[16]
|
||
check eax
|
||
jnz TryNextDrive
|
||
mov eax, JAZ_DRIVE
|
||
;--------------------------------------------------------------------------
|
||
; check for ANSI SCSI to see whether we need to play
|
||
; the Odd/Even password length game ...
|
||
FoundZipOrJaz: .IF !(byte ptr InqData[2] & 07h)
|
||
or eax, ODD_BYTE_COMPENSATION ; turn on compensation
|
||
.ENDIF
|
||
mov ebx, DriveCount
|
||
mov DriveArray[ebx*4], eax
|
||
movmov byte ptr DriveArray[ebx*4+0], al, byte ptr Adapter
|
||
movmov byte ptr DriveArray[ebx*4+1], al, byte ptr Device
|
||
inc ebx
|
||
mov DriveCount, ebx
|
||
cmp ebx, MAX_DRIVE_COUNT
|
||
jae Exit
|
||
;--------------------------------------------------------------------------
|
||
TryNextDrive: inc Device
|
||
.UNTIL (Device >= 16)
|
||
inc Adapter
|
||
mov eax, Adapter
|
||
.UNTIL (eax >= FirstInvalidAdapter)
|
||
;-------------------------------------------------------------------------------
|
||
ENDIF
|
||
Exit: .IF (!DriveCount)
|
||
set ErrorMode
|
||
.ENDIF
|
||
mov eax, DriveCount
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
EnumerateIomegaDevices ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| GET MODE PAGE |
|
||
;+-----------------------------------------------------------------------------+
|
||
GetModePage PROC Adapter:DWORD, Device:DWORD, PageToGet:DWORD, pBuffer:PTR, BufLen:DWORD
|
||
LOCAL Scsi[6]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_ModeSense
|
||
movmov Scsi[2], al, byte ptr PageToGet
|
||
movmov Scsi[4], al, byte ptr BufLen
|
||
invoke SCSICommand, Adapter, Device, ADDR Scsi, pBuffer, BufLen
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
GetModePage ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| SET MODE PAGE |
|
||
;+-----------------------------------------------------------------------------+
|
||
SetModePage PROC USES ebx, Adapter:DWORD, Device:DWORD, pBuffer:PTR
|
||
LOCAL Scsi[6]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
varzero Scsi ; init the SCSI parameter block
|
||
mov ebx, pBuffer ; get a pointer to the top of buffer
|
||
movzx ecx, byte ptr [ebx] ; get the total length
|
||
inc ecx ; adjust it up by one
|
||
reset byte ptr [ebx] ; now clear the two reserved bytes
|
||
reset byte ptr [ebx+2] ;
|
||
mov Scsi, SCSI_Cmd_ModeSelect ; set the command
|
||
mov Scsi[1], 10h ; set the Page Format bit
|
||
mov Scsi[4], cl ; set the parameter list length
|
||
invoke SCSICommand, Adapter, Device, ADDR Scsi, pBuffer, ecx
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
SetModePage ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| SET ERROR RECOVERY |
|
||
;+-----------------------------------------------------------------------------+
|
||
SetErrorRecovery PROC USES ebx, Retries:BOOL, ECC:BOOL, Testing:BOOL
|
||
LOCAL PageBuff[40]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
invoke GetModePage, CurrentAdapter, CurrentDevice, ERROR_RECOVERY_PAGE, ADDR PageBuff, SIZEOF PageBuff
|
||
lea ebx, PageBuff[4] ; get just past the header address
|
||
movzx eax, PageBuff[3] ; get the Block Descriptor Length
|
||
; form ebx == the offset to the top of the page we've read ...
|
||
add ebx, eax
|
||
; always turn off the PS bit (parameters savable)
|
||
and byte ptr [ebx], NOT 80h
|
||
; set the ECC fields
|
||
mov al, 0C1h ; presume ECC suppression
|
||
.IF (ECC)
|
||
mov al, 0C8h ; enable ECC and Early Recovery
|
||
.IF (Testing)
|
||
mov al, 0CCh ; we're testing, so EER & PER
|
||
.ENDIF
|
||
.ENDIF
|
||
mov [ebx+2], al ; and set the value
|
||
; set the retry counts
|
||
mov al, 16h ; set retries to 22 for Zip drive
|
||
.IF (JazDrive)
|
||
mov al, 64h ; and to 100 for Jaz drive
|
||
.ENDIF
|
||
.IF (!Retries) ; but if we have no retries ...
|
||
zero al ; then kill it.
|
||
.ENDIF
|
||
mov byte ptr [ebx+3], al ; set the common retry count
|
||
.IF (byte ptr [ebx+1] > 6) ; if we have a large format page ...
|
||
mov byte ptr [ebx+8], al ; then set the write count too
|
||
.ENDIF
|
||
invoke SetModePage, CurrentAdapter, CurrentDevice, ADDR PageBuff
|
||
|
||
; if we had an invalid field in the CDB (the EER bit was on)
|
||
.IF (eax == 00260005h)
|
||
invoke GetModePage, CurrentAdapter, CurrentDevice, ERROR_RECOVERY_PAGE, ADDR PageBuff, SIZEOF PageBuff
|
||
lea ebx, PageBuff[4] ; get just past the header address
|
||
movzx eax, PageBuff[3] ; get the Block Descriptor Length
|
||
; form ebx == the offset to the top of the page we've read ...
|
||
add ebx, eax
|
||
; always turn off the PS bit (parameters savable)
|
||
and byte ptr [ebx], NOT 80h
|
||
; set the ECC fields
|
||
mov al, 0C1h ; presume ECC suppression
|
||
.IF (ECC)
|
||
mov al, 0C0h ; enable ECC *BUT*NOT* Early Recovery
|
||
.IF (Testing)
|
||
mov al, 0C4h ; we're testing, PER
|
||
.ENDIF
|
||
.ENDIF
|
||
mov [ebx+2], al ; and set the value
|
||
; set the retry counts
|
||
mov al, 16h ; set retries to 22 for Zip drive
|
||
.IF (JazDrive)
|
||
mov al, 64h ; and to 100 for Jaz drive
|
||
.ENDIF
|
||
.IF (!Retries) ; but if we have no retries ...
|
||
zero al ; then kill it.
|
||
.ENDIF
|
||
mov byte ptr [ebx+3], al ; set the common retry count
|
||
.IF (byte ptr [ebx+1] > 6) ; if we have a large format page ...
|
||
mov byte ptr [ebx+8], al ; then set the write count too
|
||
.ENDIF
|
||
invoke SetModePage, CurrentAdapter, CurrentDevice, ADDR PageBuff
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
SetErrorRecovery ENDP
|
||
|
||
|
||
;-------------------------------------------------------------------------------
|
||
COMMENT ~
|
||
;+-----------------------------------------------------------------------------+
|
||
;| VENDOR SPECIFIC |
|
||
;+-----------------------------------------------------------------------------+
|
||
VendorSpecific PROC USES ebx, EnableVS:BOOL
|
||
LOCAL PageBuff[40]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
invoke GetModePage, CurrentAdapter, CurrentDevice, MODES_OF_OPERATION, ADDR PageBuff, SIZEOF PageBuff
|
||
lea ebx, PageBuff[4] ; get just past the header address
|
||
movzx eax, PageBuff[3] ; get the Block Descriptor Length
|
||
add ebx, eax
|
||
; now ebx has the offset to the top of the page we've read ...
|
||
.IF (EnableVS)
|
||
or byte ptr [ebx+2], 20h ; VSC
|
||
.ELSE
|
||
and byte ptr [ebx+2], NOT 20h ; turn off VSC bit
|
||
.ENDIF
|
||
and byte ptr [ebx], NOT 80h ; turn off the PS bit
|
||
invoke SetModePage, CurrentAdapter, CurrentDevice, ADDR PageBuff
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
VendorSpecific ENDP
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| DISABLE CACHING |
|
||
;+-----------------------------------------------------------------------------+
|
||
DisableCaching PROC USES ebx, Adapter:DWORD, Device:DWORD
|
||
LOCAL PageBuff[40]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
invoke GetModePage, Adapter, Device, CACHING_PAGE, ADDR PageBuff, SIZEOF PageBuff
|
||
lea ebx, PageBuff[4] ; get just past the header address
|
||
movzx eax, PageBuff[3] ; get the Block Descriptor Length
|
||
add ebx, eax
|
||
; now ebx has the offset to the top of the page we've read ...
|
||
mov byte ptr [ebx+2], 1 ; disable all caching
|
||
invoke SetModePage, Adapter, Device, ADDR PageBuff
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
DisableCaching ENDP
|
||
;-------------------------------------------------------------------------------
|
||
COMMENT ~
|
||
;-------------------------------------------------------------------------------
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| GET NON-SENSE PAGE DATA |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| Given Adapter, Device, DataPage, and a Buffer to receive the data, this |
|
||
;| fills the buffer we're given and returns with the SCSI Completion Code |
|
||
;+-----------------------------------------------------------------------------+
|
||
GetNonSenseData PROC Adapter:DWORD, Device:DWORD, DataPage:DWORD, Buffer:DWORD, BufLen:DWORD
|
||
LOCAL Scsi[6]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_NonSenseData ; do a Non-Sense Data Read
|
||
movmov Scsi[2], al, byte ptr DataPage ; which page to read
|
||
movmov Scsi[4], al, byte ptr BufLen ; tell drive page is this long
|
||
invoke SCSICommand, Adapter, Device, ADDR Scsi, Buffer, BufLen
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
GetNonSenseData ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| UNLOCK ALL MEDIA |
|
||
;+-----------------------------------------------------------------------------+
|
||
UnlockAllMedia PROC USES esi ebx
|
||
LOCAL DrivesLeft:DWORD, Scsi[6]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
; make sure the media is not locked as we exit ...
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_PreventAllow
|
||
; setup the SCSI command block for the operation
|
||
movmov DrivesLeft, eax, DriveCount
|
||
.IF (eax)
|
||
mov esi, OFFSET DriveArray
|
||
.REPEAT
|
||
movzx ebx, byte ptr [esi] ; pickup the Adapter
|
||
movzx ecx, byte ptr [esi+1] ; pickup the DeviceID
|
||
invoke SCSICommand, ebx, ecx, ADDR Scsi, NULL, 0
|
||
add esi, SIZEOF DWORD
|
||
dec DrivesLeft
|
||
.UNTIL (zero?)
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
UnlockAllMedia ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| LOCK CURRENT DRIVE |
|
||
;+-----------------------------------------------------------------------------+
|
||
LockCurrentDrive PROC
|
||
LOCAL Scsi[6]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
; lock the media to prevent its ejection
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_PreventAllow
|
||
mov Scsi[4], 1 ; set to ONE to lock the drive
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, NULL, 0
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
LockCurrentDrive ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| SPIN UP IOMEGA CARTRIDGE |
|
||
;+-----------------------------------------------------------------------------+
|
||
SpinUpIomegaCartridge PROC Adapter:DWORD, Device:DWORD
|
||
LOCAL Scsi[6]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
; issue an Asynchronous START command to induce spinup
|
||
varzero Scsi
|
||
mov Scsi[0], SCSI_Cmd_StartStopUnit
|
||
mov Scsi[1], 1 ; set the IMMED bit for offline
|
||
mov Scsi[4], 1 ; start the disk spinning
|
||
invoke SCSICommand, Adapter, Device, ADDR Scsi, NULL, 0
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
SpinUpIomegaCartridge ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| EJECT ALL MEDIA |
|
||
;+-----------------------------------------------------------------------------+
|
||
EjectAllMedia PROC USES esi ebx
|
||
LOCAL DrivesLeft:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
; setup the SCSI command block for the operation
|
||
movmov DrivesLeft, eax, DriveCount
|
||
.IF (eax)
|
||
mov esi, OFFSET DriveArray
|
||
.REPEAT
|
||
movzx eax, byte ptr [esi] ; pickup the Adapter
|
||
movzx ebx, byte ptr [esi+1] ; pickup the DeviceID
|
||
invoke EjectIomegaCartridge, eax, ebx
|
||
add esi, SIZEOF DWORD
|
||
dec DrivesLeft
|
||
.UNTIL (zero?)
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
EjectAllMedia ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| GET SPARE SECTOR COUNTS |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| This returns NON-ZERO if we have trouble and posted the error message |
|
||
;| into the RichText control, else it sets the number of spares available |
|
||
;+-----------------------------------------------------------------------------+
|
||
GetSpareSectorCounts PROC USES ebx, CheckPassword:BOOL
|
||
LOCAL Scsi[10]:BYTE, DefectHeader:DEFECT_LIST_HEADER, DiskStat[72]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
; ask for the defect list to make sure we're able to read it
|
||
ListChk:varzero Scsi
|
||
mov Scsi[0], SCSI_Cmd_ReadDefectData
|
||
mov Scsi[2], 00011110b ; defect format, G/P bits
|
||
mov Scsi[8], 4 ; ask for only FOUR bytes
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, ADDR DefectHeader, SIZEOF DefectHeader
|
||
.IF (!eax) || (eax == INCOMPATIBLE_MEDIA)
|
||
; we could read its defect list ... so show it!
|
||
invoke GetNonSenseData, CurrentAdapter, CurrentDevice, DISK_STATUS_PAGE, ADDR DiskStat, SIZEOF DiskStat
|
||
check eax
|
||
jnz ListChk
|
||
;--------------------------------------------------------------------------
|
||
zero ch ; clear the DRIVE_A_SUPPORT
|
||
.IF (JazDrive)
|
||
movzx eax, word ptr DiskStat[JAZ_SPARES_COUNT_OFFSET]
|
||
zero ebx
|
||
mov cl, DiskStat[JAZ_PROTECT_MODE_OFFSET]
|
||
mov edx, dword ptr DiskStat[JAZ_LAST_LBA_OFFSET]
|
||
.ELSE
|
||
.IF (DiskStat == DISK_STATUS_PAGE)
|
||
movzx eax, word ptr DiskStat[NEW_ZIP_SIDE_0_SPARES_COUNT_OFFSET]
|
||
movzx ebx, word ptr DiskStat[NEW_ZIP_SIDE_1_SPARES_COUNT_OFFSET]
|
||
mov cl, DiskStat[NEW_ZIP_PROTECT_MODE_OFFSET]
|
||
mov edx, dword ptr DiskStat[NEW_ZIP_LAST_LBA_OFFSET]
|
||
dec ch ; set the DRIVE_A_SUPPORT
|
||
.ELSE
|
||
movzx eax, word ptr DiskStat[OLD_ZIP_SIDE_0_SPARES_COUNT_OFFSET]
|
||
movzx ebx, word ptr DiskStat[OLD_ZIP_SIDE_1_SPARES_COUNT_OFFSET]
|
||
mov cl, DiskStat[OLD_ZIP_PROTECT_MODE_OFFSET]
|
||
mov edx, dword ptr DiskStat[OLD_ZIP_LAST_LBA_OFFSET]
|
||
.ENDIF
|
||
check ebx
|
||
jz NoSpares
|
||
.ENDIF
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
; bswap edx ; save the last LBA in any event
|
||
ror edx, 8 ; [dabc]
|
||
swap dh, dl ; [dacb]
|
||
ror edx, 16 ; [cbda]
|
||
swap dh, dl ; [cbad]
|
||
ror edx, 8 ; [dcba]
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
.IF (ch)
|
||
sub edx, DRIVE_A_SUPPORT_BIAS
|
||
.ENDIF
|
||
mov LastLBAOnCartridge, edx
|
||
swap al, ah ; make it little endian
|
||
mov Side_0_SparesCount, eax
|
||
swap bl, bh ; make it little endian
|
||
mov Side_1_SparesCount, ebx
|
||
; compute the number of troubles we encountered during the testing
|
||
push eax
|
||
mov eax, Initial_Side_0_Spares
|
||
sub eax, Side_0_SparesCount
|
||
add eax, Initial_Side_1_Spares
|
||
sub eax, Side_1_SparesCount
|
||
mov FirmErrors, eax
|
||
pop eax
|
||
; check to see whether we have ANY spare sectors remaining
|
||
.IF (!eax)
|
||
NoSpares: mov CartridgeStatus, DISK_TEST_FAILURE
|
||
mov eax, OFFSET szNoSpares
|
||
; if were running give them a different error message
|
||
.IF (TestingPhase)
|
||
mov eax, OFFSET szOutOfSpares
|
||
.ENDIF
|
||
invoke SetRichEditText, ADDR hTabText, eax
|
||
jmp ErrorExit
|
||
.ENDIF
|
||
; now let's checkout the cartridge's protection mode ...
|
||
.IF (cl & 07h) && (!(cl & 08h)) && CheckPassword ; if we have some protection mode
|
||
; if it's simply WRITE protected ... disable that ...
|
||
.IF (cl == 2)
|
||
invoke MessageBox, hMainWnd, ADDR szDisablingWPText, ADDR szDisablingWPTitle, MB_APPLMODAL or MB_OK
|
||
mov CartridgePassword, 0 ; set pswd to null
|
||
jmp TempDisablePswd
|
||
.ENDIF
|
||
; we need a password from the operator ...
|
||
invoke DialogBoxParam, hInst, ADDR szAppName, hMainWnd, ADDR PasswordWndProc, 0
|
||
.IF (eax)
|
||
TempDisablePswd: invoke GetDriveEntryOffset, CurrentAdapter, CurrentDevice
|
||
push eax ; save the table entry
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_CartProtect
|
||
mov Scsi[1], 08h ; request temporary unlock mode
|
||
invoke lstrlen, ADDR CartridgePassword
|
||
mov Scsi[4], al ; set THIS to the true transfer length
|
||
pop ebx ; recover the entry offset
|
||
.IF (dword ptr [ebx] & ODD_BYTE_COMPENSATION) && (al & 1) ; if password is ODD
|
||
or Scsi[1], 10h ; set the WA bit!
|
||
inc eax ; and round it up!
|
||
.ENDIF
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, ADDR CartridgePassword, eax
|
||
.IF (eax == SCSI_CMD_TIMED_OUT)
|
||
invoke MessageBox, hMainWnd, ADDR szCantUnlockText, ADDR szCantUnlockTitle, MB_APPLMODAL or MB_OK
|
||
jmp StillLocked
|
||
.ENDIF
|
||
jmp ListChk
|
||
.ENDIF
|
||
StillLocked: mov CartridgeStatus, DISK_PROTECTED
|
||
invoke SetRichEditText, ADDR hTabText, ADDR szLocked
|
||
jmp ErrorExit
|
||
.ENDIF
|
||
zero eax ; return zero since no error
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
.ELSE ; trouble of some sort ... so suppress controls and
|
||
; show the richedit control for the trouble
|
||
.IF (eax == DEFECT_LIST_READ_ERROR)
|
||
mov CartridgeStatus, DISK_Z_TRACK_FAILURE
|
||
invoke SetRichEditText, ADDR hTabText, ADDR szDefectList
|
||
ErrorExit: zero eax
|
||
dec eax ; return NON-ZERO since we have an error!
|
||
.ELSEIF (eax == MEDIA_NOT_PRESENT)
|
||
mov CartridgeStatus, DISK_NOT_PRESENT
|
||
IF DEVELOPMENT
|
||
; .ELSE
|
||
; invoke PostToScreen, eax
|
||
ENDIF
|
||
.ENDIF
|
||
.ENDIF
|
||
Exit: ret
|
||
;-------------------------------------------------------------------------------
|
||
GetSpareSectorCounts ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| HANDLE DRIVE CHANGING |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| If we're NOT in the middle of drive testing, check for any new drives |
|
||
;| going ready, eject all others, and Select the newer drive. |
|
||
;| If we *ARE* in the middle of drive testing, EJECT any new drive that's |
|
||
;| attempting to go ready. |
|
||
;+-----------------------------------------------------------------------------+
|
||
HandleDriveChanging PROC USES esi edi ebx
|
||
LOCAL DrivesLeft:DWORD, DiskStat[72]:BYTE, Selecting:BOOL, TroubleFlag:DWORD, PriorStatus:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
test hASPIDLL, -1 ; don't do ANYTHING if we didn't find
|
||
jz Exit ; the required ASPI goodies in the system
|
||
;--------------------------------------------------------------------------
|
||
reset Selecting ; true while we're changing selections
|
||
Rescan: movmov DrivesLeft, eax, DriveCount
|
||
check eax
|
||
jz Exit
|
||
;--------------------------------------------------------------------------
|
||
mov esi, OFFSET DriveArray
|
||
.REPEAT ; query the current state of the drive
|
||
.REPEAT ; clear media changed status
|
||
and dword ptr [esi], NOT MEDIA_CHANGED
|
||
movzx ebx, byte ptr [esi] ; pickup the Adapter
|
||
movzx ecx, byte ptr [esi+1] ; pickup the DeviceID
|
||
invoke GetNonSenseData, ebx, ecx, DISK_STATUS_PAGE, ADDR DiskStat, SIZEOF DiskStat
|
||
.UNTIL !(dword ptr [esi] & MEDIA_CHANGED) ; do it until NO media change!
|
||
;--------------------------------------------------------------------------
|
||
.IF (DiskStat == DISK_STATUS_PAGE)
|
||
movzx eax, DiskStat[NEW_DISK_STATUS_OFFSET]
|
||
.ELSE
|
||
movzx eax, DiskStat[OLD_DISK_STATUS_OFFSET]
|
||
.ENDIF
|
||
; if the device we have is NOT the currently selected one
|
||
movzx ebx, byte ptr [esi] ; pickup the Adapter
|
||
movzx ecx, byte ptr [esi+1] ; pickup the DeviceID
|
||
.IF (ebx != CurrentAdapter) || (ecx != CurrentDevice)
|
||
; if the disk is ANYTHING other than not present ...
|
||
.IF (al != DISK_NOT_PRESENT)
|
||
; we have a PRESENT DISK in a non-current drive
|
||
; if we're testing, reject it
|
||
.IF (Selecting) || (TestingPhase >= TESTING_STARTUP)
|
||
invoke EjectIomegaCartridge, ebx, ecx
|
||
; flag that we're waiting for spindown
|
||
or dword ptr [esi], DISK_EJECTING
|
||
; if we're not testing, and not awaiting eject
|
||
; then set the current drive ...
|
||
.ELSEIF !(dword ptr [esi] & DISK_EJECTING)
|
||
mov CurrentAdapter, ebx
|
||
mov CurrentDevice, ecx
|
||
reset TestingPhase ; show idle
|
||
set Selecting
|
||
jmp Rescan
|
||
; the PREVIOUS drive (if any) will be ejected on the next pass
|
||
.ENDIF
|
||
.ELSE ; the drive HAS spun down, so clear "waiting"
|
||
and dword ptr [esi], NOT DISK_EJECTING
|
||
.ENDIF
|
||
.ELSE ; we're checking the current drive ... make SURE that
|
||
; it is *NOT* empty! If it *IS* empty, kill current
|
||
.IF (al == DISK_NOT_PRESENT)
|
||
mov CurrentAdapter, -1
|
||
mov CurrentDevice, -1
|
||
call SetCartridgeStatusToEAX
|
||
.ENDIF
|
||
; if it's not already set correctly *and* either
|
||
; the cart status is one of the pre-test ones, or
|
||
; the NEW status from the cart is NOT "at speed" ...
|
||
.IF (eax != CartridgeStatus) && ((CartridgeStatus <= DISK_STALLED) || (eax != DISK_AT_SPEED))
|
||
call SetCartridgeStatusToEAX
|
||
.ENDIF
|
||
.ENDIF
|
||
add esi, SIZEOF DWORD
|
||
dec DrivesLeft
|
||
.UNTIL (zero?)
|
||
; if nothing was chosen ... set us to "Awaiting Cartridge" status
|
||
.IF (CurrentAdapter == (-1)) && (CurrentDevice == (-1)) && (al == DISK_NOT_PRESENT) && (CartridgeStatus != DISK_NOT_PRESENT)
|
||
call SetCartridgeStatusToEAX
|
||
.ENDIF
|
||
Exit: ret
|
||
|
||
;===============================================================================
|
||
SetCartridgeStatusToEAX:
|
||
;-------------------------------------------------------------------------------
|
||
reset JazDrive
|
||
.IF (dword ptr [esi] & JAZ_DRIVE)
|
||
set JazDrive
|
||
.ENDIF
|
||
push eax
|
||
push esi
|
||
reset TroubleFlag ; presume everything's okay
|
||
movmov PriorStatus, ebx, CartridgeStatus
|
||
mov CartridgeStatus, eax
|
||
|
||
; set the text of the "action initiate button"
|
||
.IF (CartridgeStatus == DISK_SPUN_DOWN)
|
||
; set the button to "Start Disk Spinning"
|
||
mov esi, OFFSET szPressToSpin
|
||
|
||
.ELSEIF (CartridgeStatus == DISK_TEST_UNDERWAY)
|
||
; set the button to "Stop Testing"
|
||
mov esi, OFFSET szPressToStop
|
||
|
||
.ELSEIF (CartridgeStatus == DISK_NOT_PRESENT)
|
||
Ejecting: invoke SetRichEditText, ADDR hTabText, ADDR szNotRunning
|
||
jmp DisableActions
|
||
|
||
.ELSEIF (CartridgeStatus == DISK_AT_SPEED)
|
||
invoke GetSpareSectorCounts, TRUE ; update the Cart Condition
|
||
cmp eax, MEDIA_NOT_PRESENT
|
||
je Ejecting
|
||
;--------------------------------------------------------------------------
|
||
mov TroubleFlag, eax ; decide whether we're in trouble
|
||
mov esi, OFFSET szPressToEject ; presume trouble
|
||
.IF (!eax)
|
||
movmov Initial_Side_0_Spares, eax, Side_0_SparesCount
|
||
movmov Initial_Side_1_Spares, eax, Side_1_SparesCount
|
||
reset FirmErrors
|
||
; check to see if we have enough spares to start
|
||
.IF (JazDrive)
|
||
cmp Side_0_SparesCount, MINIMUM_JAZ_SPARES
|
||
jb InsufficientSpares
|
||
.ELSE
|
||
cmp Side_0_SparesCount, MINIMUM_ZIP_SPARES
|
||
jb InsufficientSpares
|
||
.IF (Side_1_SparesCount < MINIMUM_ZIP_SPARES)
|
||
InsufficientSpares: invoke SetRichEditText, ADDR hTabText, ADDR szFewSpares
|
||
mov CartridgeStatus, DISK_LOW_SPARES
|
||
set TroubleFlag ; show the richedit control
|
||
mov esi, OFFSET szPressToProceed
|
||
jmp EnableTestBtn
|
||
.ENDIF
|
||
.ENDIF
|
||
; if no trouble, get ready to start testing ...
|
||
call PrepareToBeginTesting
|
||
mov esi, OFFSET szPressToStart
|
||
.ENDIF
|
||
; the disk *IS* at speed so enable the action button!
|
||
EnableTestBtn: invoke EnableWindow, hTestButton, TRUE
|
||
.IF (eax)
|
||
mov ActionButtonFlasher, FLASH_COUNT
|
||
invoke SetFocus, hTestButton
|
||
.ENDIF
|
||
|
||
.ELSE ; set the button to "One Moment Please"
|
||
|
||
DisableActions: invoke EnableWindow, hTestButton, FALSE
|
||
mov esi, OFFSET szOneMoment
|
||
|
||
.ENDIF
|
||
; set the Window's text based upon setting of esi
|
||
invoke SetWindowText, hTestButton, esi
|
||
; based upon the TroubleFlag, show them the proper page set
|
||
invoke SetTabErrorMode, TroubleFlag
|
||
; and if CartridgeStatus has changed, refresh the entire panel!
|
||
.IF (CurrentPage == PERFORM_TEST_PAGE)
|
||
zero ecx
|
||
.IF (PriorStatus == DISK_AT_SPEED) || (PriorStatus == DISK_SPUN_DOWN) || (PriorStatus >= DISK_LOW_SPARES)
|
||
not ecx
|
||
.ENDIF
|
||
.IF (CartridgeStatus == DISK_AT_SPEED) || (CartridgeStatus >= DISK_LOW_SPARES)
|
||
not ecx
|
||
.ENDIF
|
||
.IF (ecx) ; update the entire panel's data
|
||
invoke InvalidateRect, hTestMonitor, NULL, FALSE
|
||
.ELSE ; only paint the new cartridge status
|
||
invoke GetDC, hTestMonitor
|
||
mov edi, eax
|
||
invoke PaintCartStatus, edi
|
||
invoke ReleaseDC, hTestMonitor, edi
|
||
.ENDIF
|
||
; auto change to the first tab when changing disks.
|
||
; .ELSEIF (CurrentPage == EXPLAIN_RESULTS)
|
||
; .IF (ebx == DISK_NOT_PRESENT) || (eax == DISK_NOT_PRESENT)
|
||
; invoke SendMessage, hActionTabs, TCM_SETCURSEL, 0, NULL
|
||
; .IF (eax)
|
||
; mov CurrentPage, PERFORM_TEST_PAGE
|
||
; mov ActionsSubPage, PERFORM_TEST_PAGE
|
||
; call SetCurrentWindow
|
||
; .ENDIF
|
||
; .ENDIF
|
||
.ENDIF
|
||
;-------------------------------------------------------------------------------
|
||
pop esi
|
||
pop eax
|
||
LocalReturn
|
||
|
||
;-------------------------------------------------------------------------------
|
||
HandleDriveChanging ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| GET ELAPSED TIME IN SECONDS |
|
||
;| Returns seconds elapsed, or -1 if we could not determine it |
|
||
;+-----------------------------------------------------------------------------+
|
||
GetElapsedTimeInSeconds PROC USES ebx
|
||
LOCAL CurrentInstant:FILETIME
|
||
;-------------------------------------------------------------------------------
|
||
invoke GetSystemTimeAsFileTime, ADDR CurrentInstant
|
||
mov eax, dword ptr CurrentInstant
|
||
mov edx, dword ptr CurrentInstant[4]
|
||
sub eax, dword ptr StartingInstant
|
||
sbb edx, dword ptr StartingInstant[4]
|
||
mov ebx, FILE_TIME_TICKS_PER_SECOND
|
||
; verify that the result won't overflow
|
||
.IF (edx < ebx)
|
||
roundiv ebx
|
||
.ELSE
|
||
mov eax, -1
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
GetElapsedTimeInSeconds ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| PREPARE TO BEGIN TESTING |
|
||
;+-----------------------------------------------------------------------------+
|
||
PrepareToBeginTesting PROC
|
||
;-------------------------------------------------------------------------------
|
||
; zero all of the testing variables
|
||
zero eax
|
||
mov ecx, TESTING_VARIABLE_COUNT
|
||
mov edi, OFFSET FirstTestingVariable
|
||
rep stosd
|
||
; catch up the initial spares
|
||
movmov Initial_Side_0_Spares, eax, Side_0_SparesCount
|
||
movmov Initial_Side_1_Spares, eax, Side_1_SparesCount
|
||
reset FirmErrors
|
||
; set the flag to enable the "test" button to call "TestTheDisk"
|
||
mov TestingPhase, READY_TO_TEST
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
PrepareToBeginTesting ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| BUMP ERROR COUNTS |
|
||
;+-----------------------------------------------------------------------------+
|
||
BumpErrorCounts PROC USES ebx, ErrorCode:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
mov eax, ErrorCode ; get the error code
|
||
IF DEVELOPMENT
|
||
invoke PostToScreen, eax
|
||
ENDIF
|
||
.IF (eax == BUFFER_TOO_BIG) ; if we got BUFFER TOO BIG, halt!
|
||
set UserInterrupt
|
||
.ENDIF
|
||
mov ebx, eax
|
||
and ebx, 00FF00FFh ; mask off the middle byte
|
||
.IF (ebx == 00150004h) ; if it was one of the many seek
|
||
mov eax, ebx ; errors, cvrt to seek error
|
||
.ENDIF
|
||
.IF (eax)
|
||
mov LastError, eax
|
||
.ENDIF
|
||
.IF (eax == 320003h) || (eax == 328F03h)
|
||
mov CartridgeStatus, DISK_LOW_SPARES
|
||
.ENDIF
|
||
.IF (al == 1) ; recovered error
|
||
inc SoftErrors
|
||
.ELSE
|
||
inc HardErrors
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
BumpErrorCounts ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| READ SECTORS |
|
||
;+-----------------------------------------------------------------------------+
|
||
ReadSectors PROC pBuffer:LPSTR, LBAtoRead:DWORD, LBACount:DWORD
|
||
LOCAL Scsi[10]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_ReadMany
|
||
mov eax, LBAtoRead
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
; bswap eax ; [abcd] ; convert it into BIG endian format
|
||
ror eax, 8 ; [dabc]
|
||
swap ah, al ; [dacb]
|
||
ror eax, 16 ; [cbda]
|
||
swap ah, al ; [cbad]
|
||
ror eax, 8 ; [dcba]
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov dword ptr Scsi[2], eax
|
||
mov eax, LBACount ; and the NUMBER of LBA's to read
|
||
swap ah, al ; convert it into BIG endian format
|
||
mov word ptr Scsi[7], ax
|
||
swap ah, al
|
||
shl eax, LOG2_BYTES_PER_SECTOR
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, pBuffer, eax
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
ReadSectors ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| WRITE SECTORS |
|
||
;+-----------------------------------------------------------------------------+
|
||
WriteSectors PROC pBuffer:LPSTR, LBAtoWrite:DWORD, LBACount:DWORD
|
||
LOCAL Scsi[10]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_WriteMany
|
||
mov eax, LBAtoWrite
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
; bswap eax ; [abcd] ; convert it into BIG endian format
|
||
ror eax, 8 ; [dabc]
|
||
swap ah, al ; [dacb]
|
||
ror eax, 16 ; [cbda]
|
||
swap ah, al ; [cbad]
|
||
ror eax, 8 ; [dcba]
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov dword ptr Scsi[2], eax
|
||
mov eax, LBACount ; and the NUMBER of LBA's to read
|
||
swap ah, al ; convert it into BIG endian format
|
||
mov word ptr Scsi[7], ax
|
||
swap ah, al
|
||
shl eax, LOG2_BYTES_PER_SECTOR
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, pBuffer, eax
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
WriteSectors ENDP
|
||
|
||
|
||
;-/////////////////////////////////////////////////////////////////////////////-
|
||
IF COPY_BUTTON_DAMAGES
|
||
;-/////////////////////////////////////////////////////////////////////////////-
|
||
|
||
LONG_IO_XFER equ 564 ; (512+52) for Zip drives
|
||
; LONG_IO_XFER equ 550 ; (512+38) for Jaz drives
|
||
|
||
FIRST_SECTOR_TO_HURT equ 2246
|
||
LAST_SECTOR_TO_HURT equ 100000
|
||
SECTOR_HURT_SPACING equ 527
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| READ SECTOR LONG |
|
||
;+-----------------------------------------------------------------------------+
|
||
ReadSectorLong PROC pBuffer:LPSTR, LBAtoRead:DWORD
|
||
LOCAL Scsi[10]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_ReadLong
|
||
mov eax, LBAtoRead
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
; bswap eax ; convert it into BIG endian format
|
||
ror eax, 8 ; [dabc]
|
||
swap ah, al ; [dacb]
|
||
ror eax, 16 ; [cbda]
|
||
swap ah, al ; [cbad]
|
||
ror eax, 8 ; [dcba]
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov dword ptr Scsi[2], eax
|
||
mov ax, LONG_IO_XFER
|
||
swap ah, al
|
||
mov word ptr Scsi[7], ax ; read LONG number of bytes
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, pBuffer, LONG_IO_XFER
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
ReadSectorLong ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| WRITE SECTOR LONG |
|
||
;+-----------------------------------------------------------------------------+
|
||
WriteSectorLong PROC LBAtoWrite:DWORD, pBuffer:LPSTR
|
||
LOCAL Scsi[10]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_WriteLong
|
||
mov eax, LBAtoWrite
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
; bswap eax ; convert it into BIG endian format
|
||
ror eax, 8 ; [dabc]
|
||
swap ah, al ; [dacb]
|
||
ror eax, 16 ; [cbda]
|
||
swap ah, al ; [cbad]
|
||
ror eax, 8 ; [dcba]
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov dword ptr Scsi[2], eax
|
||
mov ax, LONG_IO_XFER
|
||
swap ah, al
|
||
mov word ptr Scsi[7], ax ; read LONG number of bytes
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, pBuffer, LONG_IO_XFER
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
WriteSectorLong ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| DAMAGE THE DISK |
|
||
;+-----------------------------------------------------------------------------+
|
||
DamageTheDisk PROC USES esi edi
|
||
LOCAL IOBuffer[LONG_IO_XFER]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
mov esi, FIRST_SECTOR_TO_HURT
|
||
.WHILE (esi <= LAST_SECTOR_TO_HURT)
|
||
|
||
; first we repair any prior damage
|
||
invoke ReadSectorLong, ADDR IOBuffer, esi
|
||
invoke WriteSector, esi, ADDR IOBuffer
|
||
invoke ReadSectorLong, ADDR IOBuffer, esi
|
||
|
||
; zap the buffer
|
||
lea edi, IOBuffer
|
||
xor dword ptr [edi + 100], 0FFFFFFFFh
|
||
xor dword ptr [edi + 104], 0FFFFFFFFh
|
||
xor dword ptr [edi + 108], 0FFFFFFFFh
|
||
xor dword ptr [edi + 112], 0FFFFFFFFh
|
||
xor dword ptr [edi + 116], 0FFFFFFFFh
|
||
xor dword ptr [edi + 120], 0FFFFFFFFh
|
||
xor dword ptr [edi + 124], 0FFFFFFFFh
|
||
xor dword ptr [edi + 128], 0FFFFFFFFh
|
||
xor dword ptr [edi + 132], 0FFFFFFFFh
|
||
xor dword ptr [edi + 136], 0FFFFFFFFh
|
||
|
||
invoke WriteSectorLong, esi, ADDR IOBuffer
|
||
|
||
; invoke ReadSector, ADDR IOBuffer, esi
|
||
|
||
add esi, SECTOR_HURT_SPACING
|
||
.ENDW
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
DamageTheDisk ENDP
|
||
|
||
;-/////////////////////////////////////////////////////////////////////////////-
|
||
ENDIF
|
||
;-/////////////////////////////////////////////////////////////////////////////-
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| OPEN DRIVE ACCESS |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| Returns TRUE on success |
|
||
;+-----------------------------------------------------------------------------+
|
||
OpenDriveAccess PROC DriveNumber:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
invoke SetErrorMode, SEM_FAILCRITICALERRORS
|
||
push eax ; stack the original error mode ...
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov eax, DriveNumber
|
||
inc eax
|
||
mov OneBasedDrive, eax
|
||
add al, 'A'-1 ; cvrt 0-based drive into capital letter
|
||
mov DriveLetter, al
|
||
mov DriveRootName, al
|
||
.IF (WinNT)
|
||
invoke CreateFile, ADDR DiskDrive, GENERIC_READ or GENERIC_WRITE,
|
||
FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
||
FILE_FLAG_WRITE_THROUGH or FILE_FLAG_NO_BUFFERING, NULL
|
||
.ELSE
|
||
invoke CreateFile, ADDR SystemVXD, GENERIC_READ or GENERIC_WRITE,
|
||
FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
|
||
FILE_FLAG_WRITE_THROUGH or FILE_FLAG_NO_BUFFERING, NULL
|
||
.ENDIF
|
||
mov hDriveAccess, eax
|
||
call SetErrorMode ; restore the original error mode ...
|
||
mov eax, hDriveAccess
|
||
.IF (eax == INVALID_HANDLE_VALUE)
|
||
zero eax
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
OpenDriveAccess ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| CLOSE DRIVE ACCESS |
|
||
;+-----------------------------------------------------------------------------+
|
||
CloseDriveAccess PROC
|
||
;-------------------------------------------------------------------------------
|
||
mov eax, hDriveAccess
|
||
.IF (eax)
|
||
invoke CloseHandle, eax
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
CloseDriveAccess ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| PERFORM DEVICE IO |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| Returns ZERO on success, and ERROR CODE on failure |
|
||
;+-----------------------------------------------------------------------------+
|
||
Win95DeviceIO PROC USES esi, _eax:DWORD, _ebx:DWORD, _ecx:DWORD, _edx:DWORD, _esi:DWORD, _edi:DWORD
|
||
LOCAL Registers:DEVIOCTL_REGISTERS, BytesReturned:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
movmov Registers.reg_EAX, eax, _eax
|
||
.IF (ah == 44h)
|
||
mov esi, VWIN32_DIOC_DOS_IOCTL ; (1)
|
||
.ELSEIF (ah == 25h)
|
||
mov esi, VWIN32_DIOC_DOS_INT25 ; (2)
|
||
.ELSEIF (ah == 26h)
|
||
mov esi, VWIN32_DIOC_DOS_INT26 ; (3)
|
||
.ELSEIF (ah == 73h)
|
||
mov esi, VWIN32_DIOC_DOS_DRIVEINFO ; (6)
|
||
.ELSE
|
||
zero eax
|
||
jmp Exit
|
||
.ENDIF
|
||
movmov Registers.reg_EBX, eax, _ebx
|
||
movmov Registers.reg_ECX, eax, _ecx
|
||
movmov Registers.reg_EDX, eax, _edx
|
||
movmov Registers.reg_ESI, eax, _esi
|
||
movmov Registers.reg_EDI, eax, _edi
|
||
mov Registers.reg_Flags, 1 ; preset the carry
|
||
invoke DeviceIoControl, hDriveAccess, esi, ; non-zero on success
|
||
ADDR Registers, SIZEOF DEVIOCTL_REGISTERS,
|
||
ADDR Registers, SIZEOF DEVIOCTL_REGISTERS,
|
||
ADDR BytesReturned, NULL
|
||
.IF (eax)
|
||
; DeviceIoControl succeeded, but what about the called func?
|
||
zero eax ; presume success (no carry set)
|
||
.IF (Registers.reg_Flags & 1)
|
||
; return was CY=1, so return the function's error val
|
||
mov eax, Registers.reg_EAX
|
||
.ENDIF
|
||
.ELSE
|
||
; DeviceIoControl failed, so return -1
|
||
mov eax, -1
|
||
.ENDIF
|
||
Exit: ret
|
||
;-------------------------------------------------------------------------------
|
||
Win95DeviceIO ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| QUALIFY DRIVE |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| Returns TRUE if this drive might be a Local Removable Iomega |
|
||
;+-----------------------------------------------------------------------------+
|
||
QualifyDrive PROC
|
||
LOCAL BytesReceived:DWORD, DriveMapInfo:DRIVE_MAP_INFO, MediaID:MEDIA_ID,
|
||
DiskGeometry:DISK_GEOMETRY, PartitionInfo:PARTITION_INFORMATION
|
||
;-------------------------------------------------------------------------------
|
||
; ask Windows what it knows about the drive
|
||
invoke GetDriveType, ADDR DriveRootName
|
||
cmp eax, DRIVE_REMOVABLE ; if it's NOT removable or FIXED
|
||
jb Disqualify ; then we're out of the game.
|
||
cmp eax, DRIVE_FIXED ; but it COULD be removable MASQUERADING
|
||
ja Disqualify ; as fixed ... so we need to check that!
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
; Windows says it's fixed or removable ... let's look closer ...
|
||
.IF (WinNT)
|
||
; check to see if the media is accessible
|
||
invoke DeviceIoControl, hDriveAccess, IOCTL_STORAGE_CHECK_VERIFY,
|
||
NULL, 0, NULL, 0, ADDR BytesReceived, NULL
|
||
check eax ; returns FALSE if it's NOT accessible
|
||
jz Exit
|
||
;--------------------------------------------------------------------------
|
||
invoke DeviceIoControl, hDriveAccess, IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
||
NULL, 0, ADDR DiskGeometry, SIZEOF DiskGeometry, ADDR BytesReceived, NULL
|
||
mov eax, DiskGeometry.MediaType
|
||
cmp eax, RemovableMedia
|
||
jne Disqualify
|
||
;--------------------------------------------------------------------------
|
||
invoke DeviceIoControl, hDriveAccess, IOCTL_DISK_GET_PARTITION_INFO,
|
||
NULL, 0, ADDR DiskGeometry, SIZEOF PartitionInfo, ADDR PartitionInfo, NULL
|
||
movmov PartitionOffset, eax, dword ptr PartitionInfo.StartingOffset
|
||
.ELSE
|
||
; look more closely at a status that ISN'T foolable
|
||
mov DriveMapInfo.dmiAllocationLength, SIZEOF DRIVE_MAP_INFO
|
||
invoke Win95DeviceIO, 440Dh, OneBasedDrive, 086Fh, ADDR DriveMapInfo,0,0
|
||
check eax ; returns an error code if the call failed
|
||
jnz Disqualify
|
||
movmov PartitionOffset, ecx, dword ptr DriveMapInfo.dmiPartitionStartRBA
|
||
;--------------------------------------------------------------------------
|
||
; we found a drive, so see if it supports EJECT!
|
||
; if not if can't be an IOMEGA removable drive
|
||
.IF (DriveMapInfo.dmiFlags & PROT_MODE_EJECT)
|
||
; yes, now can we read its MediaID ??
|
||
invoke Win95DeviceIO, 440Dh, OneBasedDrive, 0866h, ADDR MediaID,0,0
|
||
.IF (eax)
|
||
; MediaID failed, so fail our function
|
||
Disqualify: zero eax
|
||
.ELSE
|
||
; this looks like a PERFECT candidate ...
|
||
dec eax ; set EAX to -1 for success!
|
||
.ENDIF
|
||
.ENDIF
|
||
.ENDIF
|
||
Exit: ret
|
||
;-------------------------------------------------------------------------------
|
||
QualifyDrive ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| EXCLUSIVE ACCESS |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| Returns TRUE for Success |
|
||
;+-----------------------------------------------------------------------------+
|
||
ExclusiveAccess PROC DriveNumber:DWORD, Exclusive:BOOL
|
||
LOCAL BytesReceived
|
||
;-------------------------------------------------------------------------------
|
||
.IF (DriveNumber != (-1))
|
||
.IF (Exclusive)
|
||
invoke OpenDriveAccess, DriveNumber
|
||
.IF (WinNT)
|
||
invoke DeviceIoControl, hDriveAccess, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, ADDR BytesReceived, NULL
|
||
.ELSE
|
||
invoke Win95DeviceIO, 440Dh, OneBasedDrive, 084Ah, 0,0,0
|
||
.IF (eax)
|
||
; MediaID failed, so fail our function
|
||
zero eax
|
||
.ELSE
|
||
; this looks like a PERFECT candidate ...
|
||
dec eax ; set EAX to -1 for success!
|
||
.ENDIF
|
||
.ENDIF
|
||
.ELSE
|
||
.IF (WinNT)
|
||
invoke DeviceIoControl, hDriveAccess, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, ADDR BytesReceived, NULL
|
||
.ELSE
|
||
invoke Win95DeviceIO, 440Dh, OneBasedDrive, 086Ah, 0,0,0
|
||
.IF (eax)
|
||
; MediaID failed, so fail our function
|
||
zero eax
|
||
.ELSE
|
||
; this looks like a PERFECT candidate ...
|
||
dec eax ; set EAX to -1 for success!
|
||
.ENDIF
|
||
.ENDIF
|
||
push eax
|
||
call CloseDriveAccess
|
||
pop eax
|
||
.ENDIF
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
ExclusiveAccess ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| FILL BUFFER THROUGH ASPI |
|
||
;+-----------------------------------------------------------------------------+
|
||
FillBufferThroughASPI PROC
|
||
LOCAL Scsi[10]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_ReadMany
|
||
mov eax, PartitionOffset
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
; bswap eax ; convert it into BIG endian format
|
||
ror eax, 8 ; [dabc]
|
||
swap ah, al ; [dacb]
|
||
ror eax, 16 ; [cbda]
|
||
swap ah, al ; [cbad]
|
||
ror eax, 8 ; [dcba]
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov dword ptr Scsi[2], eax ; specify WHICH LBA's to read
|
||
mov Scsi[8], COMPARISON_SECTORS
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, pTargetBuffer, COMPARISON_BYTES
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
FillBufferThroughASPI ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| READ PHYSICAL SECTORS |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| Returns TRUE if it succeeds |
|
||
;+-----------------------------------------------------------------------------+
|
||
ReadPhysicalSectors PROC Sector:DWORD, Count:WORD, pBuffer:LPVOID
|
||
LOCAL DiskIO:DISKIO, BytesRead:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
; we must first read the sector containing the current Serial Number
|
||
.IF (WinNT)
|
||
mov eax, Sector ; get the starting sector number
|
||
shl eax, 9 ; multiply by 512 for starting BYTE
|
||
invoke SetFilePointer, hDriveAccess, eax, 0, FILE_BEGIN
|
||
movzx ebx, Count ; get the total sector count
|
||
shl ebx, 9 ; multiply by 512 for total bytes to read
|
||
invoke ReadFile, hDriveAccess, pBuffer, ebx, ADDR BytesRead, NULL
|
||
.ELSE
|
||
; setup the data transfer packet
|
||
movmov DiskIO.StartSector, eax, Sector
|
||
movmov DiskIO.Sectors, ax, Count
|
||
movmov DiskIO.Buffer, eax, pBuffer
|
||
; first try an Int25 (read) call ... for build 950
|
||
mov ecx, OneBasedDrive
|
||
dec ecx ; cvrt into 0-baed drive number
|
||
mov ch, 25h ; perform INT_25 direct access read
|
||
invoke Win95DeviceIO, ecx, ADDR DiskIO, -1, 0, 0, 0
|
||
check eax ; zero means we succeeded!
|
||
jz Success
|
||
;--------------------------------------------------------------------------
|
||
; for SR2 and later
|
||
invoke Win95DeviceIO, 7305h, ADDR DiskIO, -1, OneBasedDrive, 0,0
|
||
.IF (eax) ; non-zero means we failed, so return FALSE
|
||
zero eax
|
||
.ELSE ; zero means we succeeded ... to return -1
|
||
Success: dec eax ; set EAX to -1 for success!
|
||
.ENDIF
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
ReadPhysicalSectors ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| COMPARE BUFFERS |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| Returns TRUE if the buffers are identical |
|
||
;+-----------------------------------------------------------------------------+
|
||
CompareBuffers PROC USES esi edi
|
||
;-------------------------------------------------------------------------------
|
||
zero eax
|
||
mov ecx, COMPARISON_BYTES / 4
|
||
mov esi, pTargetBuffer
|
||
mov edi, pSearchBuffer
|
||
repe cmpsd
|
||
.IF (zero?)
|
||
dec eax
|
||
.ENDIF
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
CompareBuffers ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| FIND DRIVE LETTER |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| Returns the Zero-Based DOS drive letter, or -1 if not found |
|
||
;+-----------------------------------------------------------------------------+
|
||
FindDriveLetter PROC
|
||
LOCAL DriveNumber:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
; allocate two page-aligned read buffers for source disk reads
|
||
invoke VirtualAlloc, NULL, COMPARISON_BYTES, MEM_COMMIT, PAGE_READWRITE
|
||
mov pTargetBuffer, eax
|
||
invoke VirtualAlloc, NULL, COMPARISON_BYTES, MEM_COMMIT, PAGE_READWRITE
|
||
mov pSearchBuffer, eax
|
||
;--------------------------------------------------------------------------
|
||
; now search the drive letter space for the same data on a valid drive
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov DriveNumber, 'Z'-'A' ; start at "Z" and work downward ...
|
||
.REPEAT
|
||
invoke OpenDriveAccess, DriveNumber
|
||
call QualifyDrive ; returns true if it might be
|
||
.IF (eax)
|
||
; read the partition's first 8 sectors through the ASPI interface
|
||
AbsoluteRead: call FillBufferThroughASPI
|
||
.IF (!eax)
|
||
; now read the sectors through the device driver interface
|
||
invoke ReadPhysicalSectors, 0, COMPARISON_SECTORS, pSearchBuffer
|
||
.IF (eax) ; got a TRUE return, so compare'em
|
||
call CompareBuffers ; returns TRUE for equality
|
||
.IF (eax)
|
||
; yipeee! we found the drive! ...
|
||
call CloseDriveAccess
|
||
jmp Exit
|
||
.ELSEIF (PartitionOffset == 0)
|
||
add PartitionOffset, 20h
|
||
jmp AbsoluteRead
|
||
.ENDIF
|
||
.ENDIF
|
||
.ENDIF
|
||
.ENDIF
|
||
call CloseDriveAccess
|
||
dec DriveNumber
|
||
.UNTIL (sign?) ; 0-based, so this is past the end
|
||
; if DriveNumber == -1, we never found the drive
|
||
Exit: invoke VirtualFree, pTargetBuffer, 0, MEM_RELEASE
|
||
invoke VirtualFree, pSearchBuffer, 0, MEM_RELEASE
|
||
mov eax, DriveNumber
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
FindDriveLetter ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| EJECT IOMEGA CARTRIDGE |
|
||
;+-----------------------------------------------------------------------------+
|
||
EjectIomegaCartridge PROC Adapter:DWORD, Device:DWORD
|
||
LOCAL UnlockParams:DWORD, BytesReceived:DWORD
|
||
LOCAL Scsi[6]:BYTE
|
||
;-------------------------------------------------------------------------------
|
||
push CurrentAdapter
|
||
push CurrentDevice
|
||
movmov CurrentAdapter, eax, Adapter
|
||
movmov CurrentDevice, eax, Device
|
||
call FindDriveLetter
|
||
.IF (eax <= 'Z'-'A')
|
||
invoke OpenDriveAccess, eax
|
||
.IF (WinNT)
|
||
invoke DeviceIoControl, hDriveAccess, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, ADDR BytesReceived, NULL
|
||
.ELSE
|
||
mov UnlockParams, 1
|
||
invoke Win95DeviceIO, 440Dh, OneBasedDrive, 0848h, ADDR UnlockParams,0,0
|
||
invoke Win95DeviceIO, 440Dh, OneBasedDrive, 0849h, 0,0,0
|
||
.ENDIF
|
||
invoke CloseDriveAccess
|
||
.ELSE
|
||
; Could NOT do it through the IOCTL layer ... so eject with SCSI
|
||
; make sure the media is not locked ...
|
||
varzero Scsi
|
||
mov Scsi, SCSI_Cmd_PreventAllow
|
||
invoke SCSICommand, Adapter, Device, ADDR Scsi, NULL, 0
|
||
; issue an Asynchronous STOP command to induce spindown and ejection
|
||
varzero Scsi
|
||
mov Scsi[0], SCSI_Cmd_StartStopUnit
|
||
mov Scsi[1], 1 ; set the IMMED bit for offline
|
||
mov Scsi[4], 2 ; eject a Jaz disk after stopping
|
||
invoke SCSICommand, Adapter, Device, ADDR Scsi, NULL, 0
|
||
.ENDIF
|
||
pop CurrentDevice
|
||
pop CurrentAdapter
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
EjectIomegaCartridge ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| PERFORM REGION TRANSFER |
|
||
;+-----------------------------------------------------------------------------+
|
||
PerformRegionTransfer PROC USES ebx, XferCmd:DWORD, pBuffer:DWORD
|
||
LOCAL Scsi[10]:BYTE, LocalBuffer:DWORD, LocalCount:DWORD,
|
||
InitialHardErrors:DWORD, GlitchCount:DWORD, GlitchError:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
reset SingleTransferLBA ; show we're testing a range ...
|
||
movmov InitialHardErrors, eax, HardErrors
|
||
varzero Scsi ; clear out the SCSI CDB
|
||
movmov Scsi, al, byte ptr XferCmd
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov eax, FirstLBASector ; setup the first block to read
|
||
; bswap eax ; convert it into BIG endian format
|
||
ror eax, 8 ; [dabc]
|
||
swap ah, al ; [dacb]
|
||
ror eax, 16 ; [cbda]
|
||
swap ah, al ; [cbad]
|
||
ror eax, 8 ; [dcba]
|
||
mov dword ptr Scsi[2], eax ; specify WHICH LBA's to read
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov eax, NumberOfLBAs ; and the NUMBER of LBA's to read
|
||
swap ah, al ; convert it into BIG endian format
|
||
mov word ptr Scsi[7], ax ;
|
||
invoke SetErrorRecovery, FALSE, FALSE, TRUE ; disable Retries & ECC
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, pBuffer, AdapterMaxBytes
|
||
; if we failed somewhere during our transfer ... let's zero in on it
|
||
.IF (eax)
|
||
cmp eax, SS_ERR ; if it's a CONTROLLER ERROR, skip!
|
||
je Exit
|
||
cmp eax, BUFFER_TOO_BIG ; if we need to reduce the size
|
||
je Exit
|
||
cmp eax, LBA_TOO_LARGE
|
||
je Exit
|
||
;--------------------------------------------------------------------------
|
||
mov GlitchError, eax ; save the error which stopped us!
|
||
mov eax, SoftErrors ; get the current Soft + Hard Error count
|
||
add eax, HardErrors
|
||
mov GlitchCount, eax ; save it to see if we do FIND the glitch ...
|
||
movmov SingleTransferLBA, eax, FirstLBASector
|
||
call UpdateCurrentSector ; show what we're doing ...
|
||
movmov LocalBuffer, eax, pBuffer
|
||
movmov LocalCount, eax, AdapterMaxSectors
|
||
call ErrorSound
|
||
.REPEAT
|
||
; setup for our series of transfer tests ...
|
||
varzero Scsi ; clear out the SCSI CDB
|
||
movmov Scsi, al, byte ptr XferCmd
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov eax, SingleTransferLBA ; the single sector to xfer
|
||
; bswap eax ; convert it into BIG endian format
|
||
ror eax, 8 ; [dabc]
|
||
swap ah, al ; [dacb]
|
||
ror eax, 16 ; [cbda]
|
||
swap ah, al ; [cbad]
|
||
ror eax, 8 ; [dcba]
|
||
mov dword ptr Scsi[2], eax ; specify WHICH single LBA to read
|
||
;<3B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
mov Scsi[8], 1 ; a single sector
|
||
; disable all recovery techniques
|
||
invoke SetErrorRecovery, FALSE, FALSE, TRUE ; disable Retries & ECC
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, LocalBuffer, BYTES_PER_SECTOR
|
||
.IF (eax)
|
||
; some sort of problem encountered!
|
||
cmp eax, SS_ERR ; if it's a CONTROLLER ERROR, skip!
|
||
je Exit
|
||
;--------------------------------------------------------------------------
|
||
cmp al, 1 ; did we recover?
|
||
je PostTheError
|
||
;--------------------------------------------------------------------------
|
||
invoke SetErrorRecovery, TRUE, FALSE, TRUE ; enable retries
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, LocalBuffer, BYTES_PER_SECTOR
|
||
.IF (eax)
|
||
; failed even with retries
|
||
cmp eax, SS_ERR ; if it's a CONTROLLER ERROR, skip!
|
||
je Exit
|
||
;--------------------------------------------------------------------------
|
||
cmp al, 1 ; did we recover?
|
||
je PostTheError
|
||
;--------------------------------------------------------------------------
|
||
invoke SetErrorRecovery, TRUE, TRUE, TRUE ; enable retries AND ECC
|
||
invoke SCSICommand, CurrentAdapter, CurrentDevice, ADDR Scsi, LocalBuffer, BYTES_PER_SECTOR
|
||
.IF (eax)
|
||
; failed with retries and ECC
|
||
cmp eax, SS_ERR ; if it's a CONTROLLER ERROR, skip!
|
||
je Exit
|
||
.ELSE ; succeeded with ECC
|
||
mov eax, 180101h ; "ECC & Retries"
|
||
.ENDIF
|
||
.ELSE ; succeeded using retries
|
||
mov eax, 170101h ; "Read with Retries"
|
||
.IF (XferCmd == SCSI_Cmd_WriteMany)
|
||
mov eax, 0C8001h ; "Wrote with Retries"
|
||
.ENDIF
|
||
.ENDIF
|
||
;--------------------------------------------------------------------------
|
||
PostTheError: invoke BumpErrorCounts, eax ; given eax, count the errors
|
||
invoke GetSpareSectorCounts, FALSE ; update the Cart's Condition
|
||
call UpdateRunTimeDisplay
|
||
.ENDIF
|
||
inc SingleTransferLBA
|
||
call UpdateCurrentSector
|
||
add LocalBuffer, BYTES_PER_SECTOR
|
||
call ProcessPendingMessages
|
||
dec LocalCount
|
||
.UNTIL (zero?) || (UserInterrupt)
|
||
; now see whether we *did* found something to complain about ...
|
||
mov eax, SoftErrors
|
||
add eax, HardErrors
|
||
.IF (eax == GlitchCount)
|
||
; we missed it ... but SOMETHING happened! So let's report it ...
|
||
push SoftErrors ; save the existing counts
|
||
push HardErrors
|
||
mov eax, GlitchError ; get the error that triggered our search
|
||
mov ebx, eax
|
||
and ebx, 00FF00FFh ; strip the ASCQ byte
|
||
.IF (ebx == 00110003h) ; if we're about to say "unrecovered read"
|
||
mov eax, 170101h ; change it to: "Read with Retries"
|
||
.ENDIF
|
||
invoke BumpErrorCounts, eax ; given eax, count the errors
|
||
pop HardErrors ; restore the counts
|
||
pop SoftErrors
|
||
inc SoftErrors ; and bump the SOFT error count
|
||
call UpdateRunTimeDisplay
|
||
.ENDIF
|
||
reset SingleTransferLBA
|
||
zero eax ; now let's return happiness to our caller
|
||
mov ebx, HardErrors ; UNLESS we had some
|
||
.IF (ebx != InitialHardErrors) ; UNRECOVERABLE errors!
|
||
dec eax ; in which case return -1
|
||
.ENDIF
|
||
.ENDIF
|
||
; restore standard error recovery modes
|
||
Exit: push eax
|
||
invoke SetErrorRecovery, TRUE, TRUE, FALSE ; reenable Retries & ECC
|
||
pop eax
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
PerformRegionTransfer ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| TEST THE DISK |
|
||
;+-----------------------------------------------------------------------------+
|
||
TestTheDisk PROC
|
||
LOCAL TransferLength:DWORD, DataPattern:DWORD,
|
||
DriveNumber:DWORD, BlastRecoveryMode:BOOL
|
||
;-------------------------------------------------------------------------------
|
||
; USB seems to generate insane WM_TIMER messages, so we now stop
|
||
; the timer during data read/write processing.
|
||
call StopApplicationTimer
|
||
; determine whether to show "Unknown Error" or the Hex code ...
|
||
invoke GetAsyncKeyState, VK_SHIFT
|
||
shl eax, 1 ; move the high bit into CY
|
||
.IF (carry?)
|
||
set UnknownErrorMode
|
||
.ENDIF
|
||
|
||
; determine which drive to lock
|
||
call FindDriveLetter ; returns drive letter, or -1 if not found
|
||
mov DriveNumber, eax
|
||
.IF (eax == (-1))
|
||
mov al, "?"
|
||
.ELSE
|
||
invoke ExclusiveAccess, eax, TRUE
|
||
.IF (!eax) ; could NOT succeed in locking the drive!
|
||
mov al, byte ptr DriveNumber
|
||
add al, 'A'
|
||
mov szExclusiveDrive1, al
|
||
mov szExclusiveDrive2, al
|
||
invoke MessageBox, hMainWnd, ADDR szNoExclusiveText, ADDR szNoExclusiveTitle, MB_APPLMODAL or MB_OK
|
||
; allow operation on an unlocked drive!
|
||
invoke GetAsyncKeyState, VK_SHIFT
|
||
shl eax, 1 ; move the high bit into CY
|
||
jnc Exit
|
||
.ENDIF
|
||
mov al, byte ptr DriveNumber
|
||
add al, 'A'
|
||
.ENDIF
|
||
mov DriveUnderTest, al
|
||
;===============================================================================
|
||
call PreventProgramExit
|
||
invoke SetRichEditText, ADDR hTabText, ADDR szRunning
|
||
mov CartridgeStatus, DISK_TEST_UNDERWAY
|
||
mov TestingPhase, TESTING_STARTUP ; inhibit stopping now
|
||
invoke SetWindowText, hTestButton, ADDR szPressToStop
|
||
invoke InvalidateRect, hTestMonitor, NULL, FALSE
|
||
call LockCurrentDrive ; prevent media removal
|
||
|
||
; setup the initial maximum transfer ...
|
||
invoke HostAdapterInquiry, CurrentAdapter
|
||
mov eax, dword ptr ASPI_CmdBlock.hai.HA_Unique[4] ; get the max Xfer
|
||
.IF (!eax) || (eax > MAX_TRANSFER_PER_TEST) ; limit to our max
|
||
mov eax, MAX_TRANSFER_PER_TEST
|
||
.ENDIF
|
||
SizeIt: mov AdapterMaxBytes, eax
|
||
shr eax, 9 ; divide by Bytes/Sector
|
||
mov AdapterMaxSectors, eax
|
||
|
||
;----------------------- Check for "Blast Recovery Mode" -----------------------
|
||
|
||
call CheckForPartitionTable
|
||
; returns NON-ZERO if partition table was NOT found
|
||
.IF (eax)
|
||
call PerhapsBlastRecovery
|
||
; returns NON-ZERO if BlastRecovery *was* performed ...
|
||
.ENDIF
|
||
mov BlastRecoveryMode, eax
|
||
check eax
|
||
jnz GetOut
|
||
|
||
IF FORCE_STARTING_SECTOR
|
||
mov FirstLBASector, FORCE_STARTING_SECTOR ; and the starting point
|
||
ENDIF
|
||
|
||
;------------------------- Standard Testing Operation --------------------------
|
||
|
||
; log the starting time
|
||
invoke GetSystemTimeAsFileTime, ADDR StartingInstant
|
||
.REPEAT
|
||
; compute the number of LBS and Last LBA
|
||
mov eax, LastLBAOnCartridge ; get the maximum LBA count
|
||
sub eax, FirstLBASector ; and the starting point
|
||
inc eax ; number of sectors to go
|
||
.IF (eax > AdapterMaxSectors)
|
||
mov eax, AdapterMaxSectors ; trim it to the sector count
|
||
.ENDIF
|
||
mov NumberOfLBAs, eax
|
||
|
||
; compute the LastLBA
|
||
add eax, FirstLBASector ; get just past the end
|
||
dec eax ; get the last one
|
||
mov LastLBASector, eax
|
||
|
||
; compute the percentage complete
|
||
mov edx, FirstLBASector
|
||
zero eax
|
||
div LastLBAOnCartridge
|
||
mov PercentComplete, eax
|
||
|
||
; uppdate the elapsed time
|
||
call GetElapsedTimeInSeconds
|
||
.IF (eax != (-1))
|
||
mov SecondsElapsed, eax
|
||
.ENDIF
|
||
|
||
; get a random pattern of data to write
|
||
call GetRandomNumber
|
||
mov DataPattern, eax
|
||
mov ecx, AdapterMaxBytes
|
||
shr ecx, 2
|
||
mov edi, pPatternBuffer
|
||
rep stosd
|
||
|
||
; update the cartridge's status
|
||
invoke GetSpareSectorCounts, FALSE ; update the Cart's Condition
|
||
|
||
mov TestingPhase, READING_DATA
|
||
call UpdateRunTimeDisplay
|
||
invoke PerformRegionTransfer, SCSI_Cmd_ReadMany, pUserDataBuffer
|
||
.IF (!eax)
|
||
;--------------------------------------------------------------------------
|
||
mov TestingPhase, WRITING_PATT
|
||
invoke UpdateRunPhaseDisplay
|
||
invoke PerformRegionTransfer, SCSI_Cmd_WriteMany, pPatternBuffer
|
||
;--------------------------------------------------------------------------
|
||
mov TestingPhase, READING_PATT
|
||
invoke UpdateRunPhaseDisplay
|
||
invoke PerformRegionTransfer, SCSI_Cmd_Verify, pPatternBuffer
|
||
;--------------------------------------------------------------------------
|
||
mov TestingPhase, WRITING_DATA
|
||
invoke UpdateRunPhaseDisplay
|
||
invoke PerformRegionTransfer, SCSI_Cmd_WriteMany, pUserDataBuffer
|
||
;--------------------------------------------------------------------------
|
||
.ELSEIF (eax == BUFFER_TOO_BIG)
|
||
; we need to make it smaller
|
||
mov eax, AdapterMaxBytes ; get the current size
|
||
halve eax
|
||
jmp SizeIt
|
||
.ENDIF
|
||
; if we hit the end of the disk ... exit gracefully!
|
||
cmp eax, LBA_TOO_LARGE
|
||
je GetOut
|
||
; see if everything's still okay ...
|
||
.BREAK .IF (CartridgeStatus != DISK_TEST_UNDERWAY)
|
||
; bump the FirstLBASector up for the next transfer
|
||
mov eax, FirstLBASector
|
||
add eax, NumberOfLBAs
|
||
mov FirstLBASector, eax
|
||
.UNTIL (eax > LastLBAOnCartridge) || (UserInterrupt)
|
||
; show that we're post-test
|
||
GetOut: reset TestingPhase
|
||
call UnlockAllMedia
|
||
invoke SetErrorRecovery, TRUE, TRUE, FALSE ; reenable Retries & ECC
|
||
|
||
invoke SetWindowText, hTestButton, ADDR szPressToStart
|
||
mov CartridgeStatus, DISK_AT_SPEED
|
||
call AllowProgramExit
|
||
|
||
; compute the number of serious troubles
|
||
mov eax, FirmErrors
|
||
add eax, HardErrors
|
||
.IF (eax >= BADNESS_THRESHOLD)
|
||
mov eax, OFFSET szBadResult
|
||
.ELSEIF (UserInterrupt)
|
||
mov eax, OFFSET szInterrupted
|
||
.ELSE ; it wasn't interrupted, nor seriously bad, was it perfect?
|
||
add eax, SoftErrors
|
||
.IF (eax)
|
||
mov eax, OFFSET szExplainResult
|
||
.ELSE
|
||
mov eax, OFFSET szPerfectResult
|
||
.ENDIF
|
||
.ENDIF
|
||
invoke SetRichEditText, ADDR hTabText, eax
|
||
invoke InvalidateRect, hTestMonitor, NULL, FALSE
|
||
; release any exclusive filesystem lock we may have on the drive
|
||
Exit: invoke ExclusiveAccess, DriveNumber, FALSE
|
||
; if we've just un-zapped the disk ... let's eject it!
|
||
.IF (BlastRecoveryMode)
|
||
invoke EjectIomegaCartridge, CurrentAdapter, CurrentDevice
|
||
.ENDIF
|
||
; we're done (with USB'ness) so it's safe to restart the timer
|
||
call StartApplicationTimer
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
TestTheDisk ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| CHECK FOR PARTITION TABLE |
|
||
;| Return NON-ZERO if partition table was NOT found! |
|
||
;+-----------------------------------------------------------------------------+
|
||
CheckForPartitionTable PROC USES ebx
|
||
LOCAL Return:DWORD, ShiftCount:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
reset Return
|
||
; determine how many shift keys we're holding down ...
|
||
reset ShiftCount
|
||
invoke GetAsyncKeyState, VK_SHIFT
|
||
shl eax, 1 ; move the high bit into CY
|
||
.IF (carry?)
|
||
inc ShiftCount
|
||
.ENDIF
|
||
invoke GetAsyncKeyState, VK_CONTROL
|
||
shl eax, 1 ; move the high bit into CY
|
||
.IF (carry?)
|
||
inc ShiftCount
|
||
.ENDIF
|
||
invoke GetAsyncKeyState, VK_MENU
|
||
shl eax, 1 ; move the high bit into CY
|
||
.IF (carry?)
|
||
inc ShiftCount
|
||
.ENDIF
|
||
; allocate a page-aligned read buffer for disk read
|
||
invoke GlobalAlloc, GPTR, BYTES_PER_SECTOR
|
||
mov ebx, eax
|
||
; read the cartridge's partition table ...
|
||
invoke ReadSectors, ebx, 0, 1
|
||
|
||
; only if we got a good table read *AND* it's not a partition table
|
||
.IF (ShiftCount == 3) || ((!eax) && (word ptr [ebx+01FEh] != 0AA55h))
|
||
set Return
|
||
.ENDIF
|
||
invoke GlobalFree, ebx
|
||
mov eax, Return
|
||
ret
|
||
;-------------------------------------------------------------------------------
|
||
CheckForPartitionTable ENDP
|
||
|
||
|
||
;+-----------------------------------------------------------------------------+
|
||
;| PERHAPS BLAST RECOVERY |
|
||
;|-----------------------------------------------------------------------------|
|
||
;| No partition table was found ... so give them the option of performing |
|
||
;| a "blast recovery". Return TRUE if they took the option. |
|
||
;+-----------------------------------------------------------------------------+
|
||
PerhapsBlastRecovery PROC USES ebx esi
|
||
LOCAL StartOfFAT1:DWORD, StartOfFAT2:DWORD,
|
||
SectorsToCopy:DWORD
|
||
;-------------------------------------------------------------------------------
|
||
; update the LBA count
|
||
invoke GetSpareSectorCounts, FALSE ; update the Cart's Condition
|
||
; get the drive index {0-3}
|
||
mov eax, LastLBAOnCartridge
|
||
zero ebx
|
||
.WHILE (LBAMidPoints[ebx*4] < eax) && (ebx < 3)
|
||
inc ebx
|
||
.ENDW
|
||
; patch the cartridge size into the mesage box text
|
||
; get the starting address of the name strings
|
||
lea esi, IomegaDeviceNames[ebx*8]
|
||
|
||
movmov dword ptr CartSize1[0], eax, [esi]
|
||
movmov dword ptr CartSize2[0], eax, [esi]
|
||
movmov dword ptr CartSize3[0], eax, [esi]
|
||
movmov dword ptr CartSize4[0], eax, [esi]
|
||
movmov dword ptr CartSize5[0], eax, [esi]
|
||
|
||
movmov dword ptr CartSize1[4], eax, [esi+4]
|
||
movmov dword ptr CartSize2[4], eax, [esi+4]
|
||
movmov dword ptr CartSize3[4], eax, [esi+4]
|
||
movmov dword ptr CartSize4[4], eax, [esi+4]
|
||
movmov dword ptr CartSize5[4], eax, [esi+4]
|
||
|
||
invoke MessageBox, hMainWnd, ADDR szPerhapsBlastText, ADDR szPerhapsBlastTitle, MB_APPLMODAL or MB_OKCANCEL
|
||
sub eax, IDCANCEL
|
||
jz Exit
|
||
|
||
;=================== Restore the cartridge's Partition Table ===================
|
||
|
||
; make the offset to the drive's partition sector data
|
||
shl ebx, 10 ; multiply the drive index by 1024
|
||
add ebx, pSectorData
|
||
invoke WriteSectors, ebx, 0, 1
|
||
check eax
|
||
jnz Trouble
|
||
|
||
; get the number of sectors per track for the LBA offset of the
|
||
; partition boot sector ...
|
||
mov eax, [ebx+01F6h] ; eax == 32 or 63
|
||
mov StartOfFAT1, eax
|
||
inc StartOfFAT1 ; save the LBA sector for FAT1
|
||
|
||
;===================== Restore the Cartridge's Boot Sector =====================
|
||
|
||
add ebx, BYTES_PER_SECTOR ; skip up to the Boot Sector data
|
||
invoke WriteSectors, ebx, eax, 1 ; and send the boot sector out
|
||
check eax
|
||
jnz Trouble
|
||
|
||
;======================= Calc the FAT recovery variables =======================
|
||
|
||
mov eax, MAX_SECTORS_PER_TEST
|
||
sub eax, StartOfFAT1
|
||
mov SectorsToCopy, eax
|
||
|
||
movzx eax, word ptr [ebx + BPB_OFFSET + SECTORS_PER_FAT]
|
||
add eax, StartOfFAT1
|
||
invoke ReadSectors, pUserDataBuffer, eax, SectorsToCopy
|
||
check eax
|
||
jnz Trouble
|
||
|
||
invoke WriteSectors, pUserDataBuffer, StartOfFAT1, SectorsToCopy
|
||
.IF (eax)
|
||
Trouble: invoke MessageBox, hMainWnd, ADDR szBlastTroubleText, ADDR szBlastTroubleTitle, MB_APPLMODAL or MB_OK
|
||
.ELSE
|
||
invoke MessageBox, hMainWnd, ADDR szBlastSuccessText, ADDR szBlastSuccessTitle, MB_APPLMODAL or MB_OK
|
||
.ENDIF
|
||
zero eax
|
||
dec eax
|
||
Exit: ret
|
||
;-------------------------------------------------------------------------------
|
||
PerhapsBlastRecovery ENDP
|
||
|