;  volume.S
;
;  Copyright 2003-2004 John Coffman
;  Copyright 2009-2011 Joachim Wiedorn
;  All rights reserved.
;
;  Licensed under the terms contained in the file 'COPYING'
;  in the source directory.
;

#ifdef BSS_DATA

#if 0
vtab:	.blkw	MAX_BIOS_DEVICES_asm*2	; volume IDs indexed by
					;  REAL bios device code

rtab:	.blkw	MAX_BIOS_DEVICES_asm*2	; raid offsets indexed the same


devmap:	.blkw	MAX_BIOS_DEVICES+2	; device code map
					; logical -> physical
					; (lo-byte::hi-byte)
#endif

vtab	=	*
	.org	*+MAX_BIOS_DEVICES_asm*4	; volume IDs indexed by
					;  REAL bios device code

rtab	=	*
	.org	*+MAX_BIOS_DEVICES_asm*4	; raid offsets indexed the same


devmap	=	*
	.org	*+MAX_BIOS_DEVICES*2+4	; device code map
					; logical -> physical
					; (lo-byte::hi-byte)

#else

rmask:	.word	0		; physical raid mask

; build_vol_tab	-- Build the table of volume IDs
;			and fill in the device translate table
;
;   Enter with:
;	DS=ES=CS
;
;   Exit with:
;	Nothing
;
;   Side effects:	The volume ID table is built
;			The from:to device translate table is filled in
;
;
build_vol_tab:
	pusha

	xor	cx,cx		; depend on this being preserved
	xor	dx,dx
	xchg	[devmap],dx	; clear our First Stage mapping

	call	is_prev_mapper	; is there a previous mapper
	jz	bvt0

; have previous mapper active

; ****** 22.5.7
	push	di
	or	dx,dx		; any translation?
	jz	bvt003
bvt001:
	seg es
	mov	ax,(di)		; get previous translation
	inc	di
	inc	di
	or	ax,ax
	jz	bvt003
	cmp	al,dh		; does it affect us?
	jne	bvt001
	mov	[init_dx],ah	; update physical device
bvt003:
	pop	di
; ****** 22.5.7

	seg es
	  mov	(di),cx		; sterilize it
bvt0:	
	push	cs
	pop	es		; restore ES

; ****** 22.5.8
	mov	di,#KEYTABLE+256+mt_serial_no
	mov	cx,#MAX_BIOS_DEVICES_asm
	xor	eax,eax
	repe
	  scasd			; scan for any serial nos in table
	je	bvt90		; if none, skip reading vol_ids
				;    as there will be no translations
; ****** 22.5.8


	xor	cx,cx		; start at hard drive 0 (0x80)
	mov	di,#vtab	; place to put IDs
bvt1:
	call	read_vol_id	; get VolumeID in EAX
	stosd			; store in table
	or	eax,eax		; test for zero
	jz	bvt9		; end, or no volume ID

; now see if there will be a translation
	push	di
	push	cx

; ****** 22.5.9
	mov	cx,di		; 4*table count to CX
	mov	di,#vtab
	sub	cx,di		; 4*count
	shr	cx,#2		; table count
	dec	cx
	jz	bvt1.5		; table empty
	repne			; repeat while no match
	  scasd
	jne	bvt1.5

	mov	bx,#msg_dupl	; duplicate message
	call	say
#if !DEBUG_NEW
	call	pause
#endif
	pop	cx
	pop	di

	mov	dword (di-4),#0	; zero the duplicated volumeID
	jmp	bvt9		; skip to next on duplication

bvt1.5:
; ****** 22.5.9
	mov	si,#KEYTABLE+256+mt_serial_no
	mov	cx,#MAX_BIOS_DEVICES_asm
	mov	di,si
bvt2:	jcxz	bvt7
	repne			; repeat while not matching
	  scasd
	jne	bvt7		; jump if no match
#if 0
; print the raw serial_no match
	pushad
	push	eax
	call	dout
	call crlf
	popad
#endif
	lea	dx,(di-4)	; DX is address of match
	sub	dx,si		; DX is 4*index
	shr	dx,#2		; DX is input device #
	pop	bx		; BX is real device #
	push	bx
	cmp	bx,dx		
; ****** 22.5.9
;;;	je	bvt2		; equal means no translation
	je	bvt7		; equal means no translation
; ****** 22.5.9
	mov	dh,bl		;
	or	dx,#0x8080	; make into HD bios codes
#if 0
; print the raw TT entry
	pusha
	mov	ax,dx
	call	wout
	call	crlf
	popa
#endif
	push	si
	mov	bx,#devmap	; scan the device translation table
bvt4:
	mov	si,(bx)		; get from(low):to(high)  pair
	inc	bx
	inc	bx		; bump pointer by 2
	cmp	si,dx		; duplicate?
	je	bvt5

	or	si,si		; not duplicate; at end?
	jnz	bvt4

	mov	(bx-2),dx	; put at end of table
	mov	(bx),si		; and mark new end
bvt5:
	pop	si
; ****** 22.5.9
;;;	jmp	bvt2
; ****** 22.5.9

bvt7:
	pop	cx
	pop	di
bvt9:
	inc	cx
	cmp	cx,#MAX_BIOS_DEVICES_asm
	jb	bvt1

bvt90:
; now build the RAID offset table

	mov	si,#KEYTABLE+256+mt_raid_offset
	mov	dx,[KEYTABLE+256+mt_raid_dev_mask]
	xor	bx,bx		; count thru devices
bvt91:
	xor	eax,eax		; may store 0
	shr	dx,#1		; is it raid?
	jnc	bvt92		; not a raid device

	lodsd			; get raid offset
	push	eax		; save value in stack

	mov	eax,[KEYTABLE+256+mt_serial_no](bx)
	mov	di,#vtab	; physical table address
	mov	cx,#MAX_BIOS_DEVICES_asm
	repne
	  scasd			; scan for a match
	jne	bvt_not_found	; the logical volume is not there	
	lea	di,(di-4-vtab)	; DI is 4*index into table
	mov	cx,di
	shr	cx,#2		; make 0..15
	mov	ax,#1
	shl	ax,cl		; mask bit in right position
	or	[rmask],ax
	pop	dword ptr rtab(di)	; store RAID offset
	jmp	bvt92
bvt_not_found:
	pop	eax		; clean up the stack
bvt92:
	add	bx,#4		;
	cmp	bx,#MAX_BIOS_DEVICES_asm*4
	jb	bvt91

#if DEBUG_NEW
	mov	bx,#msg_voltab
	call	say
	mov	si,#vtab
	mov	di,#rtab
	mov	cx,#MAX_BIOS_DEVICES_asm
;;;	mov	dx,[KEYTABLE+256+mt_raid_dev_mask] ; was logical mask
	mov	dx,[rmask]		; get physical mask value

; truncate all the empty entries from the end of the list
;
bvtA:	mov	bx,cx
	dec	bx
	shl	bx,#2
	cmp	dword ptr (bx+si),#0
	jne	bvtA2
	loop	bvtA		; 22.6.1

bvtA2:	inc	cx

bvtX:
	lodsd			; get volume serial number
	push	eax
	call	dout		; print it
	shr	dx,#1
	mov	bx,#msg_star
	jc	bvtX1
	mov	bx,#msg_nostar
bvtX1:
	call	say
	push	dword (di)
	call	dout
	add	di,#4
	call	crlf
	loop	bvtX		; loop back

	call	crlf

; now the device translate table:

	mov	bx,#msg_tt
	call	say
	mov	si,#devmap
bvtB:	lodsw			; get from,to pair
	push	ax
	call	bout
	mov	bx,#msg_arr
	call	say
	pop	ax	
	xchg	al,ah
	push	ax
	call	bout
	call	crlf
	pop	ax
	or	ax,ax
	jnz	bvtB
	call	pause	
#endif
	popa		; restore all the regs
	ret

msg_dupl:
	.ascii	"O\nError: Duplicated Volume ID\n"
	.byte	0
#if DEBUG_NEW

msg_voltab:
	.ascii	"The physical VolumeID / Raid1-reloc table\n"
	.byte	0
msg_star:	.ascii	" * "
	.byte	0
msg_nostar:	.ascii	"   "
	.byte	0
msg_space = msg_nostar

msg_tt:	.ascii	"The device translate table:\n"
	.byte	0
msg_arr:  .ascii	" -> "
	.byte	0
msg_plus: .ascii	" + "
	.byte	0
msg_rw:	.ascii	"RAID physical write: "
	.byte	0
#endif

#ifdef LCF_READAHEAD
; ****** 22.6.1 begin
;
; enable_readahead	-- Enable readahead on an EDD drive
;
;   Enter with:
;	DL = hard disk BIOS code 
;	ES=DS=CS
;
;   Return:
;	Nothing		-- enable read-ahead, if possible
;
enable_readahead:
	pusha
#if DEBUG_NEW
	push	dx		; save device code
	xchg	ax,dx
	call	bout
	pop	dx		; restore device code
#endif
	mov     bx,#0x55AA      ;magic number
	mov     ah,#0x41        ;function call
	int     0x13
	jc      enrd9
	cmp     bx,#0xAA55      ;magic return
	jne     enrd9
	test    cl,#EDD_SUBSET|EDD_PACKET	; some EDD support?
	jz      enrd9
#if 0
	cmp	ah,#0x21	; EDD version 1.1 or later?
	jb	enrd9
#endif

	mov	ax,#0x4E00	; enable prefetch
	int	0x13
#if DEBUG_NEW
	mov	al,#'-		; '
	jc	enrd8_d
	test	ah,ah		; check return code in AH
	jnz	enrd8_d
	mov	al,#'+		; '
  enrd8_d:
	call	display
#endif

enrd9:
#if DEBUG_NEW
	call	crlf
#endif
	popa
	ret
; ****** 22.6.1 end
#endif


; read_vol_id	-- Read the volume ID off of a drive
;
;   Enter with:
;	CX = drive number to read (hard disk 0..15)
;	ES=DS=CS
;
;   Return:
;	Carry Clear on success
;	EAX = volume ID         (0 means no ID)
;
;	Carry set on error
;	EAX = 0
;
;
read_vol_id:
	push	bx
	push	dx
	push	cx
	push	di

	push	cx
	push	es		; paranoia (floppies touch it)

	mov	ah,#8		; get number of drives in DL
	mov	dl,#0x80
	call	dsk_do_int13	; retry 5 times

	pop	es
	pop	cx		; restore device code

	jc	rvi_9
	cmp	cl,dl
	jae	rvi_9

	mov	dl,cl
	mov	cx,#1
	mov	bx,#Map
	or	dl,#0x80
	mov	dh,ch
; ****** 22.6.1
#ifdef LCF_READAHEAD
	call	enable_readahead
#endif
; ****** 22.6.1
	mov	ax,#0x201	; read
	call	dsk_do_int13
	jc	rvi_9

	seg es
	  mov	eax,(bx+PART_TABLE_OFFSET-6)	; fetch return
	jmp	rvi_exit
rvi_9:
	xor	eax,eax
	stc
rvi_exit:
	pop	di
	pop	cx
	pop	dx
	pop	bx
	ret


; map_device -- Take the logical device code in DL and map it
;		into the physical device code preserving all flags
;	22.5.6	Any RAID relocated device code maps to the boot device code
;
;  Enter with:
;	DL containing logical device code & flags
;	DS register not guaranteed
;
;  Exit with:
;	DL containing physical device code & same flags
;
;
map_device:
	push	si		; save working registers
	push	ax
	push	bx
	mov	si,#devmap	; point at translation table
	mov	bl,dl
	and	bl,#DEV_MASK_asm	; from device code in BL
#if 1
; ****** 22.5.6
	seg cs
	mov	ah,[init_dx]	; get boot device code
	test	dl,#RAID_REL_FLAG
	jnz	bios_tt_match	; it is RAID, go use the boot device code
; ***** 22.5.6
#endif
bios_tt_next:
	seg cs			; DS may be bad
	  lodsw			; get from/to pair
	or	ax,ax		; end of list?
	jz	bios_tt_done
	cmp	al,bl
	jne	bios_tt_next
; got a match
bios_tt_match:
	and	dl,#0xFF-DEV_MASK_asm	; save flags
	or	dl,ah		; put on the TO device code
bios_tt_done:
	pop	bx
	pop	ax
	pop	si
	ret


#if 0

; rev_map_device -- Take the physical device code in DL and map it
;		into the logical device code preserving all flags
;
;  Enter with:
;	DL containing physical device code & flags
;
;  Exit with:
;	DL containing logical device code & same flags
;
;
rev_map_device:
	push	si		; save working registers
	push	ax
	push	bx
	mov	si,#devmap	; point at translation table
	mov	bl,dl
	and	bl,#DEV_MASK_asm	; TO device code in BL
bios_tt_next:
	lodsw			; get from/to pair
	or	ax,ax		; end of list?
	jz	bios_tt_done
	cmp	ah,bl
	jne	bios_tt_next
; got a match
	and	dl,#0xFF-DEV_MASK_asm	; save flags
	or	dl,al		; put on the FROM device code
bios_tt_done:
	pop	bx
	pop	ax
	pop	si
	ret
#endif


; translate -- test for a raid device, and do the offsetting
;
;  Enter with:
;	DI:CX	LBA32 or LINEAR address
;	DL	physical device code & flags (RAID_REL_FLAG is set)
;	AL	sector count
;	ES:BX	buffer pointer for R/W
;
;  Exit with:
;	DI:CX	updated if RAID translation takes place
;	All other registers are unchanged
;
;
translate:
	push	bp
	mov	bp,sp

	cmp	word [rmask],#0		; any translate bits set?
	jnz	trans_1

; this special cases the initial Keytable read, when no setup has been done
	BEG_FS
	SEG_FS
	add	cx,par1_raid_offset+SSDIFF	; ***** RAID ******
	SEG_FS
	adc	di,par1_raid_offset+2+SSDIFF	; ***** RAID ******
	END_FS
	jmp	trans_ret

trans_1:
	push	di
	push	cx	; form  dword (bp-4)

	mov	di,dx		; DI gets full device code
	and	di,#DEV_MASK_asm & 0x7F
#if DEBUG_NEW
	pusha
	cmp	byte ptr [dsk_wrflag],#0
	jz	trans_01
	mov	bx,#msg_rw
	call	say
	mov	ax,di
	or	ax,#0x80
	call	bout
	mov	bx,#msg_space
	call	say
	push	(bp-4+2)
	push	(bp-4)
	call	dout
trans_01:
	popa
#endif
	shl	di,#2	; index into array

	mov	cx,[rtab](di)	; get low relocation value
	mov	di,[rtab+2](di)	; get high relocation value
#if DEBUG_NEW
	pusha
	cmp	byte ptr [dsk_wrflag],#0
	jz	trans_02
	mov	bx,#msg_plus
	call	say
	push	di
	push	cx
	call	dout
	mov	bx,#msg_arr
	call	say
trans_02:
	popa
#endif

	add	(bp-4),cx	; relocate
	adc	(bp-4+2),di	;  **

	pop	cx
	pop	di
#if DEBUG_NEW
	pusha
	cmp	byte ptr [dsk_wrflag],#0
	jz	trans_03
	push	di
	push	cx
	call	dout
	call	crlf
trans_03:
	popa
#endif

trans_ret:
	pop	bp
	ret

#endif	/* BSS_DATA */

/* end  volume.S */
