mac-tip/x86-asm-source/ASPI.ASM
2021-11-19 21:28:52 -07:00

1952 lines
74 KiB
NASM
Raw Blame History

;+-----------------------------------------------------------------------------+
;| 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