summaryrefslogtreecommitdiff
path: root/disk.asm
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2017-12-06 00:35:28 -0500
committerJoseph Hunkeler <jhunkeler@gmail.com>2017-12-06 00:35:28 -0500
commit8aa86e06385c0a32f52d67b13c524c5290fbe78d (patch)
tree8d37b4102823f94f21e5edca07fefd8be5f38204 /disk.asm
parent5f8a989e38e5b9d236bbc67b309df79bf13fb2bb (diff)
downloadminos-8aa86e06385c0a32f52d67b13c524c5290fbe78d.tar.gz
Add drive error reporting
Diffstat (limited to 'disk.asm')
-rw-r--r--disk.asm194
1 files changed, 182 insertions, 12 deletions
diff --git a/disk.asm b/disk.asm
index bc588f6..4177c8d 100644
--- a/disk.asm
+++ b/disk.asm
@@ -26,8 +26,116 @@ disk_info:
pop bp
ret
+disk_last_status:
+ push bp
+ mov bp, sp
-disk_info_fmt: db 'HDD(%c): INT 13h Ext: %x (%x)', CR, 0
+ ; DL = drive number
+ mov ah, 01h ; BIOS get status of last drive operation
+ int 13h ; BIOS disk service
+ ; carry set on error
+ mov sp, bp
+ pop bp
+ ret
+
+
+disk_convert_status:
+ push bp
+ mov bp, sp
+ pusha
+
+ cmp ax, 01h ; Avoid writing "success" message
+ jl .return
+
+ xor cx, cx
+ mov cx, ax ; AL contains the sector count
+ and cx, 00ffh ; store in CX
+ shr ax, 8 ; shift error code into AL
+
+ ; This block handles AL when not 00h..11h
+ ; The extended error values have no real order
+ cmp al, 20h
+ je .status_20
+
+ cmp al, 40h
+ je .status_40
+
+ cmp al, 80h
+ je .status_80
+
+ cmp al, 0AAh
+ je .status_AA
+
+ cmp al, 0BBh
+ je .status_BB
+
+ cmp al, 0CCh
+ je .status_CC
+
+ cmp al, 0E0h
+ je .status_E0
+
+ cmp al, 0FFh
+ je .status_FF
+
+ jmp .convert ; No match, convert AL as-is
+
+ ; Adjust error code so that it can be indexed
+ ; easily by error_msg_disk_table
+ .status_20:
+ mov al, 12h
+ jmp .convert
+
+ .status_40:
+ mov al, 13h
+ jmp .convert
+
+ .status_80:
+ mov al, 14h
+ jmp .convert
+
+ .status_AA:
+ mov al, 15h
+ jmp .convert
+
+ .status_BB:
+ mov al, 16h
+ jmp .convert
+
+ .status_CC:
+ mov al, 17h
+ jmp .convert
+
+ .status_E0:
+ mov al, 18h
+ jmp .convert
+
+ .status_FF:
+ mov al, 19h
+ jmp .convert
+
+ .convert:
+ mov bx, ax ; Get array index
+ imul bx, bx, 2 ; Calculate index offset
+ ; in human speak: idx * (idx * WORD)
+
+ lea si, [error_msg_disk_table] ; Load address of table into source index
+ add si, bx ; Add calculated index offset
+
+ and dx, 00ffh ; get drive number
+
+ push word [si] ; error message
+ push dx ; drive number
+ push ax ; error code
+ push error_msg_disk_status_fmt
+ call printf ; Print error message
+ add sp, 8 ; Clean up stack
+
+.return:
+ popa
+ mov sp, bp
+ pop bp
+ ret
disk_lba_chs:
@@ -50,14 +158,7 @@ disk_reset:
int 13h ; BIOS disk service
jnc .success
- push error_msg_disk_reset
- call panic
-
.success:
- push msg_disk_reset
- call puts
- add sp, 2
-
popa
mov sp, bp
pop bp
@@ -74,27 +175,35 @@ disk_read:
push ax
push bx
push cx
+ push dx
+ ; AL = Sectors to read
+ ; ES:BX = Buffer address
+ ; CH = Cylinder (10 bits [6 & 7 of CL are MSB])
+ ; CL = Sector (5 lower bits)
+ ; DH = Head
+ ; DL = Drive
mov ah, 02h ; BIOS - read disk sectors
int 13h ; BIOS disk service
jnc .success
+ call disk_convert_status
+
push dx
call disk_reset
add sp, 2
+
+ pop dx
pop cx
pop bx
pop ax
+
dec di
jnz .readloop
- push error_msg_disk_read
- call panic
- add sp, 2
-
.success:
pop di
mov sp, bp
@@ -103,6 +212,7 @@ disk_read:
; data
+align 2
drive0: dw 0
msg_disk_reset: db "Drive reset successful.", CR, 0
@@ -111,4 +221,64 @@ msg_disk_read: db "Sector read successful.", CR, 0
error_msg_disk_reset: db "Drive reset failed!", CR, 0
error_msg_disk_read: db "Drive read failed!", CR, 0
+disk_info_fmt: db 'HDD(%c): INT 13h Ext: %x (%x)', CR, 0
+error_msg_disk_status_fmt: db 'ERROR %x: Drive %x: %s', CR, 0
+error_msg_disk:
+ eds_success: db "Success", 0 ; 00h
+ eds_invalid_command: db "Invalid command", 0
+ eds_address_mark: db "Cannot find address mark", 0
+ eds_write_protected: db "Attempted write on write protected disk", 0
+ eds_sector_not_found: db "Sector not found.", 0
+ eds_reset_failed: db "Reset failed.", 0
+ eds_disk_change_line_active: db "Disk change line active", 0
+ eds_drive_parameter_activity_failed: db "Drive parameter activity failed", 0
+ eds_dma_overrun: db "DMA overrun", 0
+ eds_dma_boundary_64: db "DMA over 64kb boundary", 0
+ eds_bad_sector: db "Bad sector detected", 0
+ eds_bad_cylinder: db "Bad cylinder detected", 0
+ eds_media_type_not_found: db "Media type not found", 0
+ eds_invalid_number_of_sectors: db "Invalid number of sectors", 0
+ eds_control_data_address_mark: db "Control data address mark detected", 0
+ eds_dma_out_of_range: db "DMA out of range", 0
+ eds_crc_ecc_data_error: db "CRC/ECC data error", 0 ; 10h
+ eds_ecc_corrected_data_error: db "ECC corrected data error", 0 ; 11h
+ ; Everything was normal until... this...
+ eds_controller_failure: db "Controller failure", 0 ; 20h
+ eds_seek_failure: db "Seek failure", 0 ; 40h
+ eds_timeout: db "Drive timed out (not ready?)", 0 ; 80h
+ eds_not_ready: db "Drive not ready", 0 ; AAh
+ eds_undefined_error: db "Undefined error", 0 ; BBh
+ eds_write_fault: db "Write fault", 0 ; CCh
+ eds_status_error: db "Status error", 0 ; E0h
+ eds_sense_operation_failed: db "Sense operation failed", 0 ; FFh
+
+error_msg_disk_table: ; is an array of pointers for each error message
+ dw eds_success
+ dw eds_invalid_command
+ dw eds_address_mark
+ dw eds_write_protected
+ dw eds_sector_not_found
+ dw eds_reset_failed
+ dw eds_disk_change_line_active
+ dw eds_drive_parameter_activity_failed
+ dw eds_dma_overrun
+ dw eds_dma_boundary_64
+ dw eds_bad_sector
+ dw eds_bad_cylinder
+ dw eds_media_type_not_found
+ dw eds_invalid_number_of_sectors
+ dw eds_control_data_address_mark
+ dw eds_dma_out_of_range
+ dw eds_crc_ecc_data_error
+ dw eds_ecc_corrected_data_error
+ dw eds_controller_failure
+ dw eds_seek_failure
+ dw eds_timeout
+ dw eds_not_ready
+ dw eds_undefined_error
+ dw eds_write_fault
+ dw eds_status_error
+ dw eds_sense_operation_failed
+ dw 0000h ; END of error_msg_disk_table
+
%endif ; _DISK_ASM