;
; SCSI I/F Dependent Routine
;

;
; Request Sense
; OUT: AL = CCS Sense Key 
;      Carry Set-> Error
;
ReqSense proc	near
  ifdef DEBUG
	push	es
	push	ds
	push	di
	push	si
	push	cx
; Copy CDB & Status to Debug Buffer
	mov	di,cs
	mov	es,di
	mov	ds,di
	mov	di,offset ErrCDB
    if IF_TYPE EQ ASPI
	mov	si,offset SRB+64
    else
	mov	si,offset CDB
    endif
	mov	cx,11
	rep	movsb
;
	pop	cx
	pop	si
	pop	di
	pop	ds
	pop	es
  endif
    if IF_TYPE EQ ASPI
	mov	si,offset SRB	; SRB Pointer
	xor	bx,bx
	mov	bl,[si+23]	; Get CDB Size
	lea	si,[si+bx+64]	; Set Sense Buffer Pointer
	mov	al,[si+2]	; Get Sense Key
    else
; Setup SCSI-Pointer & CDB
	mov	si,[bp.TempPtr]	; Buffer
	mov	al,03h		; Request Sense Command
	call	[bp.SetScPtr]	; Setup SCSI-Pointer
	mov	byte ptr [si+4],04h	; 4-Byte

; Go SCSI Phase
	tfrp	4406h,4
	call	[bp.PhasePtr]
	jc	RSense9
	mov	si,[bp.TempPtr]	; Buffer Pointer
	mov	al,[si+2]	; Get Sense Key
RSense9:
    endif
	ret
ReqSense endp

;
; Setup SCSI-Pointer
;  IN: al = Command
;      [ds:si] = Data Buffer Pointer
; OUT: [ds:si] = CDB Pointer
;      [es:di] = SCSI Pointer
;
SetupSc proc	near
	push	ax
;-------------------------< for ASPI >--------------------------
    if IF_TYPE EQ ASPI
	push	cs		; |
	pop	es		; |-> es = cs
	mov	di,offset SRB	; CDB Pointer
	mov	es:[di+15],si	;|-> Save Buffer Address
	mov	es:[di+17],ds	;|
	push	cs		; |
	pop	ds		; |-> ds = cs
	lea	si,[di+64]	; Set CDB Address
    endif
;----------------------< for PC9801-55 >------------------------
    if IF_TYPE EQ PC9801
	mov	word ptr cs:ScsiPtr,si	; Buffer Offset
	mov	word ptr cs:ScsiPtr+2,ds	; Buffer Segment
	push	cs		; |
	pop	ds		; |-> ds = cs
	mov	si,offset CDB
    endif
;----------------------< for FM-R/TOWNS >-----------------------
    if IF_TYPE EQ FM
	push	cs		; |
	pop	es		; |-> es = cs
	mov	di,offset Work_0	; CDB Pointer
	mov	es:[di],si	;|-> Save Buffer Address
	mov	es:[di+2],ds	;|
	push	cs		; |
	pop	ds		; |-> ds = cs
	lea	si,[di+4]	; Set CDB Address
    endif

; Clear CDB 10 byte
	mov	ah,00h
	mov	word ptr [si],ax	; Command Code
	mov	al,ah
	mov	word ptr [si+2],ax
	mov	word ptr [si+4],ax
	mov	word ptr [si+6],ax
	mov	word ptr [si+8],ax
;
	pop	ax
	ret
SetupSc endp

;
;
;
Phase	proc	near
	call	ExPhase
	jc	Phase9

; Error Check
	or	al,al		; Check Status
	jz	Phase8
	call	ReqSense
	stc
Phase8:
	ret
Phase9:
	mov	al,0ffh
	ret
Phase	endp

;
; Call SCSI Phase
;  IN: bh = Direction for PC9801-55 & ASPI
;      bl = CDB Byte for PC9801-55 & ASPI
;      cx = Data Transfer Count
;      [es:di] = SCSI Pointer' Pointer
;      [ds:si] = CDB Pointer' Pointer
;
ExPhase	proc	near
    if IF_TYPE EQ PC9801
; ----------------- Begin PC9801-55 Routine ---------------------
	push	es
	push	di
	push	si
	push	dx
;
	mov	si,offset Work_0
	mov	al,[bp.Lun]
	mov	byte ptr [si],al	; Target LUN
	mov	byte ptr [si+1],bh	; Transfer Direction
	mov	byte ptr [si+2],bl	; CDB Length
	mov	byte ptr [si+3],00h	; Reserve
	mov	dx,si
	les	bx,dword ptr ScsiPtr	; Get Data Buffer Address
	mov	al,[bp.ScsiID]
	and	al,00000111b		; Only SCSI-ID
	or	al,0c0h
	mov	ah,09h			; Select without ATN & Transfer
	int	1bh			; Call SCSI-BIOS
	mov	si,dx
	mov	al,byte ptr [si]	; Get Status
	and	ah,0f0h
	jz	ExPhase9
	stc
ExPhase9:
	pop	dx
	pop	si
	pop	di
	pop	es
	ret
    endif
;
    if IF_TYPE EQ FM
; ----------------- Begin FM-R/TOWNS Routine ---------------------
	push	ds
	push	si
;
	mov	di,offset Work_0
	xor	cx,cx
	mov	ch,[bp.Lun]
	mov	ah,0fdh			; Direct Command Function
	mov	al,[bp.ScsiID]
	and	al,00000111b		; Only SCSI-ID
	or	al,10110000b		; Select SCSI Hard Disk
	int	93h			; Call SCSI-BIOS
	xchg	al,ah
	or	ah,ah
	jz	ExPhase2
	stc
ExPhase2:
	pop	si
	pop	ds
	ret
    endif
;
    if IF_TYPE EQ ASPI
; ---------------- Begin ASPI Routine -----------------
	mov	byte ptr [di],02h	; Execute SCSI I/O Request
	mov	al,[bp.ScsiID]
	mov	ah,[bp.Lun]
	mov	word ptr [di+8],ax	; Set Target SCSI-ID & LUN
	mov	byte ptr [di+23],bl	; Set CDB Length
	mov	word ptr [di+10],cx	; Set Data Length
	mov	byte ptr [di+3],bh	; Set SCSI Request Flag
	mov	byte ptr [di+14],04h	; Set Sense Alocation Length
	push	es
	push	di
	mov	bx,offset ScsiPtr
	call	dword ptr [bx]		; Call ASPI Manager
	pop	di
	pop	es
PhASPI2:
	mov	al,byte ptr [di+1]	; Get ASPI Status
	test	al,80h			; is Error ?
	jnz	PhASPI8
	or	al,al			; End of Transfer ?
	jz	PhASPI2
	mov	ax,word ptr [di+24]	; Get Host Adapter & Target Status
	xchg	ah,al
	or	ah,ah
	jz	PhASPI9
PhASPI8:
	stc
PhASPI9:
	ret
    endif
;
ExPhase	endp

	even
ScsiPtr	dd	?		; SCSI Pointer or ASPI Entry Address
    if IF_TYPE EQ ASPI
SRB	db	90 dup (?)
    else
Work_0	db	4 dup (?)	; FM-R Data Pointer or PC9801-55 Work
CDB	db	10 dup (?)
Status	db	1 dup (?)
    endif

; Break Address
Break	equ	$

;
; Check SCSI Driver Install
;
ChkSCSI	proc	near
    if IF_TYPE EQ ASPI
	mov	dx,offset ScMgrName	; Point to SCSI Manager Name
	mov	ax,3d00h		; Open Function
	int	21h
	jc	ChkSCSI2

; Get ASPI Manager Entry Point
	mov	bx,ax			; Set File Handle
	push	bx
	mov	ax,4402h		; IOCTL Func 2
	mov	dx,offset ScsiPtr
	mov	cx,4			; Entry Address 4-byte
	int	21h
	pop	bx
	mov	ah,3eh			; Close Function
	int	21h
	xor	ah,ah
ChkSCSI2:
	ret
;
ScMgrName db	'SCSIMGR$',0
    endif
    if IF_TYPE EQ FM
	xor	ah,ah
	ret
    endif
    if IF_TYPE EQ PC9801
	xor	ah,ah
	ret
    endif
ChkSCSI	endp
