Newsgroups: comp.sources.misc
From: briana@tau-ceti.isc-br.com (Brian W. Antoine)
Subject:  v25i019:  st01scsi - DOS SCSI Driver for the Seagate ST-01, v2.0, Part02/02
Message-ID: <1991Nov5.033452.4414@sparky.imd.sterling.com>
X-Md4-Signature: db7f3dda25e39475703534e67a7028f3
Date: Tue, 5 Nov 1991 03:34:52 GMT
Approved: kent@sparky.imd.sterling.com

Submitted-by: briana@tau-ceti.isc-br.com (Brian W. Antoine)
Posting-number: Volume 25, Issue 19
Archive-name: st01scsi/part02
Environment: DOS, ST-01
Supersedes: ST01SCSI.12: Volume 15, Issue 2-3

#
# This is a Shell Archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through #! /bin/sh.
# -----cut here-----cut here-----cut here-----cut here-----
#! /bin/sh
# Execute the file with #! /bin/sh (not csh) to create the files:
#	dump.asm
#	ioctl.asm
#	kludge.asm
#	scsi.asm
#	subs.asm
#	units.asm
# This Archive created: Fri Oct 18 22:46:09 1991
# By: Brian W. Antoine at ISC - Bunker Ramo, Spokane, WA
#
export PATH; PATH=/bin:$PATH
echo shar: extracting "'dump.asm'" '(1362 characters)'
if test -f 'dump.asm'
then
echo shar: will not over-write existing file "'dump.asm'"
else
sed 's/^XX//' > 'dump.asm' << \SHAR_EOF
XX;
XX; Convert bin (ax) to ascii (bx => buffer)
XX;
XXbin_ascii	proc	near
XX		pusha
XX		push	ax
XX		mov	cx,6
XXfill_buff:	mov	byte ptr [bx],' '
XX		inc	bx
XX		loop	fill_buff
XX		mov	si,10
XX		or	ax,ax
XX		jns	clr_dvd
XX		neg	ax
XXclr_dvd:	sub	dx,dx
XX		div	si
XX		add	dx,'0'
XX		dec	bx
XX		mov	[bx],dl
XX		inc	cx
XX		or	ax,ax
XX		jnz	clr_dvd
XX		pop	ax
XX		or	ax,ax
XX		jns	no_more
XX		dec	bx
XX		mov	byte ptr [bx],'-'
XXno_more:	popa
XX		ret
XXbin_ascii	endp
XX
XX;
XX; Convert Hex (dx) to Ascii (bx => buffer)
XX;
XXhex2asc4	proc	near
XX		push	cx
XX		push	ax
XX		mov	cx,4		;Do Four Digits
XXh241:		rol	dx,1
XX		rol	dx,1
XX		rol	dx,1
XX		rol	dx,1
XX		mov	al,dl		;Get the Current Digit
XX		and	al,0Fh
XX		cmp	al,0Ah		;Is It Hex?
XX		jge	h242
XX		add	al,30h		;Normal Digit
XX		jmp	h243
XXh242:		add	al,37h		;Hex Digit
XXh243:		mov	[bx],al		;Insert in Buffer
XX		inc	bx
XX		loop	h241
XX		pop	ax
XX		pop	cx
XX		ret
XXhex2asc4	endp
XX
XX;
XX; Convert Hex (dl) to Ascii (bx => buffer)
XX;
XXhex2asc2	proc	near
XX		push	cx
XX		push	ax
XX		mov	cx,2		;Do Two Digits
XXh221:		rol	dl,1
XX		rol	dl,1
XX		rol	dl,1
XX		rol	dl,1
XX		mov	al,dl		;Get the Current Digit
XX		and	al,0Fh
XX		cmp	al,0Ah		;Is It Hex?
XX		jge	h222
XX		add	al,30h		;Normal Digit
XX		jmp	h223
XXh222:		add	al,37h		;Hex Digit
XXh223:		mov	[bx],al		;Insert in Buffer
XX		inc	bx
XX		loop	h221
XX		pop	ax
XX		pop	cx
XX		ret
XXhex2asc2	endp
XX
XX;
XX; Print a string
XX;
XX; ds:dx => string
XX;
XXputs		proc	near
XX		pusha
XX		mov	ah,9		;DOS print string
XX		int	21h
XX		popa
XX		ret
XXputs		endp
SHAR_EOF
if test 1362 -ne "`wc -c < 'dump.asm'`"
then
echo shar: error transmitting "'dump.asm'" '(should have been 1362 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ioctl.asm'" '(5778 characters)'
if test -f 'ioctl.asm'
then
echo shar: will not over-write existing file "'ioctl.asm'"
else
sed 's/^XX//' > 'ioctl.asm' << \SHAR_EOF
XX;
XX; Process an ioctl request for the current unit
XX;
XX; return 'C' on error
XX;
XXscsi_ioctl	proc
XX		mov	al,es:[bx].rh19_minor		;Get the minor number
XX		cmp	al,40h				;Set Device Params?
XX		jnz	scsi_i_42h
XX		clc
XX		jmp	scsi_i_exit
XX
XXscsi_i_42h:	cmp	al,42h				;Format and Verify?
XX		jnz	scsi_i_60h
XX		mov	di,es:[bx].rh19_buf_ofs		;Get the Param Buffer
XX		mov	ax,es:[bx].rh19_buf_seg
XX		mov	es,ax
XX		mov	ax,es:[di].ioctl_fmt_cyl	;Cylinder
XX		mov	bx,SECT_TRACK
XX		mul	bx				;Convert to Sector
XX		mov	cx,es:[di].ioctl_fmt_head	;Head
XX		or	cx,cx
XX		jz	head0_42h
XXhead_loop_42h:	add	ax,SECT_TRACK			;Add Head Tracks
XX		adc	dx,0
XX		loop	head_loop_42h
XXhead0_42h:	mov	bx,0
XX		mov	cx,es:[di].ioctl_fmt_len	;How Many Tracks
XXlen_loop_42h:	add	bx,SECT_TRACK			;Convert to Sectors
XX		loop	len_loop_42h
XX		mov	cx,bx
XX
XX		ife large_drives
XX		mov	di,cur_bpb			;Add Drive Offset
XX		mov	dx,[di].bpb_hs_msw
XX		endif
XX
XX		call	scsi_verify
XX		jmp	scsi_i_exit
XX
XXscsi_i_60h:	cmp	al,60h				;Get Device Params?
XX		jnz	scsi_i_61h
XXbuild_bpb:	mov	si,cur_bpb			;Get the Current BPB
XX		mov	di,es:[bx].rh19_buf_ofs		;Get the Param Buffer
XX		mov	ax,es:[bx].rh19_buf_seg
XX		mov	es,ax
XX		mov	es:[di].dpb_special,05h		;Sect Same/Use Cur BPB
XX		mov	es:[di].dpb_type,05h		;Fixed Disk
XX		mov	es:[di].dpb_attr,0001h		;Not Removable
XX		if large_drives
XX		mov	dx,[si].bpb_ts_msw
XX		mov	ax,[si].bpb_ts_lsw
XX		else
XX		mov	dx,0
XX		mov	ax,[si].bpb_ts
XX		endif
XX		add	ax,1				;Sectors (1-n)
XX		adc	dx,0
XX		mov	bx,SECT_TRACK
XX		div	bx
XX		mov	es:[di].dpb_cyl,ax
XX		mov	es:[di].dpb_media,0		;????
XX		mov	es:[di].dpb_sectors,SECT_TRACK	;Sectors per Track
XX
XX		push	di
XX		lea	di,es:[di].dpb_bpb		;Copy the bpb into
XX		mov	cx,size bpb			;the requestors buffer
XX		cld
XX	rep	movsb
XX		pop	di
XX
XX		lea	di,es:[di].dpb_track		;Build the Track List
XX		mov	cx,SECT_TRACK
XX		mov	ax,0				;Start with Sector 0
XXscsi_i_t_loop:	mov	es:[di],ax			;Sector Number
XX		inc	ax
XX		inc	di
XX		inc	di
XX		mov	word ptr es:[di],P_SECT		;Sector Size
XX		inc	di
XX		inc	di
XX		loop	scsi_i_t_loop
XX		clc
XX		jmp	short scsi_i_exit
XX
XXscsi_i_61h:	cmp	al,61h				;Read Track?
XX		jnz	scsi_i_62h
XX		mov	di,es:[bx].rh19_buf_ofs		;Get the Param Buffer
XX		mov	ax,es:[bx].rh19_buf_seg
XX		mov	es,ax
XX		mov	ax,es:[di].ioctl_read_cyl	;Cylinder
XX		mov	bx,SECT_TRACK
XX		mul	bx				;Convert to Sector
XX		mov	cx,es:[di].ioctl_read_head	;Head
XX		or	cx,cx
XX		jz	head0_61h
XXhead_loop_61h:	add	ax,SECT_TRACK			;Add Head Tracks
XX		adc	dx,0
XX		loop	head_loop_61h
XXhead0_61h:	add	ax,es:[di].ioctl_read_sect	;Offset into the Track
XX		adc	dx,0
XX		mov	cx,es:[di].ioctl_read_len	;How Many Sectors
XX
XX		ife large_drives
XX		mov	di,cur_bpb			;Add Drive Offset
XX		mov	dx,[di].bpb_hs_msw
XX		endif
XX
XX		call	scsi_verify
XX		jc	scsi_i_error
XX		mov	es,rh_seg
XX		mov	bx,rh_off
XX		jmp	build_bpb
XX
XXscsi_i_62h:	cmp	al,62h				;Verify?
XX		jnz	scsi_i_error
XX		mov	di,es:[bx].rh19_buf_ofs		;Get the Param Buffer
XX		mov	ax,es:[bx].rh19_buf_seg
XX		mov	es,ax
XX		mov	ax,es:[di].ioctl_fmt_cyl	;Cylinder
XX		mov	bx,SECT_TRACK
XX		mul	bx				;Convert to Sector
XX		mov	cx,es:[di].ioctl_fmt_head	;Head
XX		or	cx,cx
XX		jz	head0_62h
XXhead_loop_62h:	add	ax,SECT_TRACK			;Add Head Tracks
XX		adc	dx,0
XX		loop	head_loop_62h
XXhead0_62h:	mov	bx,0
XX		mov	cx,es:[di].ioctl_fmt_len	;How Many Tracks
XXlen_loop_62h:	add	bx,SECT_TRACK			;Convert to Sectors
XX		loop	len_loop_62h
XX		mov	cx,bx
XX
XX		ife large_drives
XX		mov	di,cur_bpb			;Add Drive Offset
XX		mov	dx,[di].bpb_hs_msw
XX		endif
XX
XX		call	scsi_verify
XX		jmp	short scsi_i_exit
XX
XXscsi_i_error:	stc
XXscsi_i_exit:	ret
XXscsi_ioctl	endp
XX
XX;
XX; Process an ioctl_write request
XX;
XXscsi_ioctl_write proc
XX		mov	di,es:[bx].rh12_buf_ofs		;Get The Command
XX		mov	ax,es:[bx].rh12_buf_seg		;Buffer
XX		mov	es,ax
XX		mov	ax,es:[di].ioc_command		;What Command
XX
XX;
XX; Format Disk Unit
XX;
XX		cmp	al,'F'				;Format?
XX		jnz	try_erase
XX		mov	ax,es:[di].ioc_param1		;Get Interleave
XX		mov	bx,es:[di].ioc_buf_ofs		;Get Buffer Offset
XX		mov	cx,es:[di].ioc_buf_len		;Get Buffer Length
XX		mov	dx,es:[di].ioc_param2		;Get Format Type
XX		mov	es,es:[di].ioc_buf_seg		;Get Buffer Seg
XX		lea	di,cmd_format			;Insert into Command
XX		mov	[di].fmt_cmd_il_b1,ah
XX		mov	[di].fmt_cmd_il_b0,al
XX		mov	[di].fmt_cmd_type,dl
XX		call	docmd
XX		jnc	format_exit
XX		call	scsi_sense
XXformat_exit:	jmp	scsi_i_w_exit
XX
XX;
XX; Erase Tape Unit
XX;
XXtry_erase:	cmp	al,'E'				;Erase?
XX		jnz	try_rewind
XX		lea	di,cmd_erase			;Now Erase Tape
XX		call	docmd
XX		jnc	erase_exit
XX		call	scsi_sense
XXerase_exit:	jmp	scsi_i_w_exit
XX
XX;
XX; Rewind Tape Unit
XX;
XXtry_rewind:	cmp	al,'R'				;Rewind?
XX		jnz	try_load
XX		lea	di,cmd_rewind			;Now Rewind Tape
XX		call	docmd
XX		jnc	rewind_exit
XX		call	scsi_sense
XXrewind_exit:	jmp	scsi_i_w_exit
XX
XX;
XX; Load Tape on Open
XX;
XXtry_load:	cmp	al,'L'				;Load?
XX		jnz	try_noload
XX		mov	load_flag,TRUE
XX		jmp	scsi_i_w_exit
XX
XX;
XX; No Load Tape on Open
XX;
XXtry_noload:	cmp	al,'N'				;No Load?
XX		jnz	try_space
XX		mov	load_flag,FALSE
XX		jmp	scsi_i_w_exit
XX
XX;
XX; Space Tape
XX;
XXtry_space:	cmp	al,'S'				;Space?
XX		jnz	try_filemark
XX		mov	ax,es:[di].ioc_param1		;Get Count
XX		mov	bx,es:[di].ioc_param2		;Get Type
XX		lea	di,cmd_space			;Insert into Command
XX		mov	[di].space_cmd_code,bl
XX		mov	[di].space_cmd_cnt2,ah		;Dup of ah
XX		mov	[di].space_cmd_cnt1,ah
XX		mov	[di].space_cmd_cnt0,al
XX		call	docmd
XX		jnc	scsi_i_w_exit
XX		call	scsi_sense
XX		jmp	scsi_i_w_exit
XX
XX;
XX; Write Filemarks
XX;
XXtry_filemark:	cmp	al,'M'				;Mark?
XX		jnz	try_remap
XX		mov	ax,es:[di].ioc_param1		;Get Count
XX		lea	di,cmd_twritefm			;Insert into Command
XX		mov	[di].fm_cmd_cnt_b1,ah
XX		mov	[di].fm_cmd_cnt_b0,al
XX		call	docmd
XX		jnc	scsi_i_w_exit
XX		call	scsi_sense
XX		jmp	scsi_i_w_exit
XX
XX;
XX; Reassign Block
XX;
XXtry_remap:	cmp	al,'A'				;ReAssign?
XX		jnz	scsi_i_w_error
XX		mov	bx,es:[di].ioc_buf_ofs		;Get Buffer Offset
XX		mov	cx,es:[di].ioc_buf_len		;Get Buffer Length
XX		mov	es,es:[di].ioc_buf_seg		;Get Buffer Seg
XX		lea	di,cmd_remap			;Command
XX		call	docmd
XX		jnc	scsi_i_w_exit
XX		call	scsi_sense
XX		jmp	scsi_i_w_exit
XX
XXscsi_i_w_error:	stc
XXscsi_i_w_exit:	ret
XXscsi_ioctl_write endp
SHAR_EOF
if test 5778 -ne "`wc -c < 'ioctl.asm'`"
then
echo shar: error transmitting "'ioctl.asm'" '(should have been 5778 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'kludge.asm'" '(2417 characters)'
if test -f 'kludge.asm'
then
echo shar: will not over-write existing file "'kludge.asm'"
else
sed 's/^XX//' > 'kludge.asm' << \SHAR_EOF
XX;
XX; This code is needed because DOS insists on opening a char device
XX; in cooked mode.  The problem is that without adding code to every
XX; application that would ever use us, we have no way to alter this
XX; because the use of O_BINARY or setmode() do not affect char devices.
XX;
XX; The solution (kludge) is to watch open requests issued thru the
XX; INT 21 vector.  If we see a open request followed by a OPEN_DEV
XX; call to us, it must have been an open for us.  So during the return,
XX; force a call to the ioctl facility that will switch to raw mode.
XX;
XX
XX;
XX; The Original INT 21 Vector
XX;
XXvect_int_21	equ	word ptr 4 * 21h
XXorig_int_21	dd	?			;Original INT 21 Vector
XX
XX;
XX; OPEN_DEV flag is TRUE when we are opened
XX;
XXopened_flag	db	FALSE
XX
XXpatch_us_in	proc	near
XX		push	es
XX		push	ax
XX		mov	ax,0			;Patch Ourselves into
XX		mov	es,ax			;the INT 21 Vector
XX		mov	ax,es:[vect_int_21]	;Offset
XX		mov	word ptr orig_int_21,ax
XX		lea	ax,our_int_21
XX		mov	es:[vect_int_21],ax
XX		mov	ax,es:[vect_int_21+2]	;Segment
XX		mov	word ptr orig_int_21+2,ax
XX		mov	ax,cs
XX		mov	es:[vect_int_21+2],ax
XX		pop	ax
XX		pop	es
XX		ret
XXpatch_us_in	endp
XX
XXour_int_21	proc	far
XX		pushf				;Save entry flags
XX		cmp	ah,3Dh			;Is it an open request?
XX		jnz	not_open_req
XX		popf				;Restore entry flags
XX;
XX; We need to set things up so the 'iret' done by the INT 21
XX; code will have some the right stuff on the stack.
XX; #1 Flags with interrupts enabled
XX; #2 Return Address
XX;
XX		sti				;Allow interrupts
XX		pushf				;After the iret
XX		cli				;Shut interrupts off
XX		call	cs:orig_int_21		;While we Pass the request on
XX;
XX; Upon return, interrupts are enabled, so shut them off while we work
XX;
XX		pushf
XX		cli
XX		cmp	cs:opened_flag,FALSE	;Was it an open for us?
XX		jz	not_our_open
XX		mov	cs:opened_flag,FALSE	;Clear for next time
XX;
XX; We need to forge a call to the ioctl interface
XX; to switch DOS to raw mode when it talks to us
XX;
XX		pusha
XX		mov	bx,ax			;Save the Handle
XX		mov	ax,4400h		;Get Device Information
XX		pushf
XX		call	cs:orig_int_21
XX		mov	dh,0			;Setup
XX		or	dl,20h			;for RAW Mode
XX		mov	ax,4401h		;Set Device Information
XX		pushf
XX		call	cs:orig_int_21
XX		popa
XX
XXnot_our_open:	popf				;The Original Flags to return
XX;
XX; When we return, we need to pop the flags that the original INT 21
XX; call left on the stack, and return the flags we got back
XX;
XX		ret	2			;Return and discard flags
XX
XXnot_open_req:	popf				;Pop the saved flags
XX		jmp	cs:orig_int_21		;Continue with original code
XXour_int_21	endp
SHAR_EOF
if test 2417 -ne "`wc -c < 'kludge.asm'`"
then
echo shar: error transmitting "'kludge.asm'" '(should have been 2417 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'scsi.asm'" '(14291 characters)'
if test -f 'scsi.asm'
then
echo shar: will not over-write existing file "'scsi.asm'"
else
sed 's/^XX//' > 'scsi.asm' << \SHAR_EOF
XX;
XX; Simple SCSI Device Driver
XX;
XX		PAGE	76,132
XX
XX		INCLUDE	options.inc
XX		INCLUDE	equ.inc
XX		INCLUDE	struct.inc
XX
XX		ife oldcode
XX		.286
XX		else
XX		.8086
XXpusha		macro
XX		push	ax
XX		push	bx
XX		push	cx
XX		push	dx
XX		push	si
XX		push	di
XX		endm
XX
XXpopa		macro
XX		pop	di
XX		pop	si
XX		pop	dx
XX		pop	cx
XX		pop	bx
XX		pop	ax
XX		endm
XX		endif
XX
XX;
XX; Start of Code and Data
XX;
XX_TEXT		segment	word public 'CODE'
XX		assume	cs:_TEXT, ds:_TEXT, es:_TEXT
XX
XX		org	0
XX
XX;
XX; Device Header Required By DOS
XX;
XXscsi:
XXtape_link_ofs	dw	disk_link_ofs	;Forward Link
XXtape_link_seg	dw	-1
XX		dw	0C800h		;Char Device
XX		dw	tape_strategy	;Address of 1st DOS Call
XX		dw	dev_interrupt	;Address of 2nd DOS Call
XX		db	'SCSITAPE'	;Device Name
XX
XXdisk_link_ofs	dw	-1		;Forward Link
XXdisk_link_seg	dw	-1
XX		if large_drives
XX		dw	06042h		;Ioctl R/W, Block Device, Non-IBM, Get/Set, 32 bit
XX		else
XX		dw	06040h		;Ioctl R/W, Block Device, Non-IBM, Get/Set
XX		endif
XX		dw	disk_strategy	;Address of 1st DOS Call
XX		dw	dev_interrupt	;Address of 2nd DOS Call
XXdisk_count	db	0		;Number of Disks Present
XX		db	7 dup(?)
XX
XX;
XX; Work Space For Our Device Driver
XX;
XX		even
XXrh_off		dw	?		;Request Header Offset
XXrh_seg		dw	?		;Request Header Segment
XXrh_type		db	?		;Request Type
XX
XXwrite_flag	db	FALSE		;TRUE When Tape Write Seen
XXread_flag	db	FALSE		;TRUE When Tape Read Seen
XXerror_flag	db	FALSE		;TRUE When Tape Error Seen
XXload_flag	db	TRUE		;TRUE When Tape should Load/Unload
XXcur_drive	db	-1
XXvol_id		db	'NO NAME    ',0
XX
XX;
XX; The Original INT 24 Vector
XX;
XXvect_int_24	equ	word ptr 4 * 24h
XXorig_int_24	dd	?			;Original INT 24 Vector
XX
XX;
XX; Define our own personal Stack
XX;
XX		even
XXnew_stack	db	STACK_SIZE-2 dup (?)	;Our Local Stack
XXnew_stack_top	dw	?
XX
XXstack_ptr	dw	?			;Old Stack Pointer
XXstack_seg	dw	?			;Old Stack Segment
XX
XX;
XX; Command Table
XX;
XXcmdtab		label	byte		;* = Char Only Devices
XX		dw	INITIALIZATION	;Initialization
XX		dw	MEDIA_CHECK	;Media Check (Block Only)
XX		dw	GET_BPB		;Build BPB (Block Only)
XX		dw	unknown		;IOCTL Read
XX		dw	READ		;Read Data
XX		dw	done		;*Non Destructive Read
XX		dw	done		;*Read Status
XX		dw	done		;*Flush Read Buffer
XX		dw	WRITE		;Write Data
XX		dw	WRITE_VERIFY	;Write With Verify
XX		dw	done		;*Write Status
XX		dw	done		;*Flush Write Buffer
XX		dw	WRITE_IOCTL	;IOCTL Write
XX		dw	OPEN_DEV	;Device Open
XX		dw	CLOSE_DEV	;Device Close
XX		dw	done		;Removable Check
XX		dw	unknown		;*Write Until Busy
XX		dw	unknown		;Unknown Call
XX		dw	unknown		;Unknown Call
XX		dw	IOCTL		;Generic Ioctl
XX		dw	unknown		;Unknown Call
XX		dw	unknown		;Unknown Call
XX		dw	unknown		;Unknown Call
XX		dw	GET_DEV		;Get Device
XX		dw	SET_DEV		;Set Device
XX
XX;
XX; Int 24 (Fatal Error Handler)
XX;
XX; The test for our tape device only works because the
XX; device header for the tape is located at the start
XX; of the driver binary.
XX;
XXour_int_24	proc	far
XX		push	ax
XX		mov	ax,cs		;Is it our Segment
XX		cmp	bp,ax
XX		jnz	not_our_tape
XX		cmp	si,0		;Is it the Tape Device
XX		jnz	not_our_tape
XX		pop	ax
XX		mov	al,3		;Fail the System Call
XX		iret
XXnot_our_tape:	pop	ax
XX		jmp	cs:orig_int_24	;Pass the Request On
XXour_int_24	endp
XX
XX;
XX; Strategy Procedure
XX;
XXdisk_strategy	proc	far
XX		mov	cs:rh_seg,es		;Save Request Header Ptr Segment
XX		mov	cs:rh_off,bx		;Save Request Header Ptr Offset
XX		mov	cs:rh_type,DISK_REQUEST
XX		ret
XXdisk_strategy	endp
XX
XXtape_strategy	proc	far
XX		mov	cs:rh_seg,es		;Save Request Header Ptr Segment
XX		mov	cs:rh_off,bx		;Save Request Header Ptr Offset
XX		mov	cs:rh_type,TAPE_REQUEST
XX		ret
XXtape_strategy	endp
XX
XX;
XX; Interrupt Procedure
XX;
XXdev_interrupt	proc	far
XX		pushf				;Save Machine State On Entry
XX		cli
XX		push	ds
XX		push	es
XX		push	ax
XX		push	bx
XX		push	cx
XX		push	dx
XX		push	si
XX		push	di
XX		push	bp
XX
XX		mov	cs:stack_seg,ss		;Save Old Stack
XX		mov	cs:stack_ptr,sp
XX
XX		mov	ax,cs			;Save us the Segment Override Crap
XX		mov	ds,ax
XX		mov	es,ax
XX
XX		mov	ss,ax			;Setup Our Local Stack
XX		lea	ax,new_stack_top
XX		mov	sp,ax
XX		sti				;We're Safe Now
XX
XX;
XX; Perform branch based on the command passed in the Request Header
XX;
XX		mov	es,rh_seg		;Point us at the Request Header
XX		mov	bx,rh_off
XX
XX		mov	al,es:[bx].rh_cmd	;Get Command Code
XX		rol	al,1			;Get offset into table
XX		lea	di,cmdtab		;Get address of command table
XX		mov	ah,0			;Clear hi order byte
XX		add	di,ax			;Add offset
XX		jmp	word ptr [di]		;Jump Indirect
XX
XX;
XX; Command Procedures
XX;
XXINITIALIZATION:	cmp	rh_type,TAPE_REQUEST	;Is this SCSITAPE: Init?
XX		jz	init_skip
XX		mov	al,es:[bx].rh0_drv_ltr	;Save the starting Drive
XX		add	al,041h
XX		mov	cur_drive,al
XX		call	initial			;Setup
XX		if use_kludge
XX		call	patch_us_in
XX		endif
XX		mov	bx,rh_off
XX		mov	es,rh_seg
XXinit_skip:	lea	ax,initial		;Set The Break Address
XX		mov	es:[bx].rh0_brk_ofs,ax
XX		mov	es:[bx].rh0_brk_seg,cs
XX		mov	al,disk_count		;Number of Disk Devices Supported
XX		mov	es:[bx].rh0_nunits,al
XX		lea	dx,bpb_array		;BPB Array
XX		mov	es:[bx].rh0_bpb_tbo,dx
XX		mov	es:[bx].rh0_bpb_tbs,cs
XX		jmp	done
XX
XX;
XX; Has the Media Changed
XX;
XXMEDIA_CHECK:	call	find_unit
XX		jc	mc_jmp_err
XX		mov	di,cur_unit
XX		mov	al,[di].unit_mcheck	;Get Initial Status
XX		mov	[di].unit_mcheck,1	;Always OK from then on
XX		mov	es:[bx].rh1_md_stat,al
XX		lea	dx,vol_id		;Address of Volume ID
XX		mov	es:[bx].rh1_volid_ofs,dx
XX		mov	es:[bx].rh1_volid_seg,cs
XX		jmp	done
XXmc_jmp_err:	jmp	bad_unit
XX
XX;
XX; Get Disk Parameter Block
XX;
XXGET_BPB:	call	find_unit
XX		jc	get_jmp_err
XX		mov	dx,cur_bpb		;Address of BPB
XX		mov	es:[bx].rh2_pbpbo,dx
XX		mov	es:[bx].rh2_pbpbs,cs
XX		jmp	done
XXget_jmp_err:	jmp	bad_unit
XX
XX;
XX; Read some data from the disk/tape
XX;
XXREAD:		cmp	rh_type,DISK_REQUEST
XX		jz	read_a_disk
XX		mov	ax,tape_unit		;Do We Have a Tape?
XX		cmp	ax,-1
XX		jz	read_jmp_err1
XX		mov	cur_unit,ax
XX		call	tape_read
XX		jc	read_jmp_err2
XX		jmp	done
XXread_a_disk:	call	find_unit
XX		jc	read_jmp_err1
XX		call	disk_read
XX		jc	read_jmp_err2
XX		jmp	done
XXread_jmp_err1:	jmp	bad_unit
XXread_jmp_err2:	jmp	bad_read
XX
XX;
XX; Write some data to the disk/tape
XX;
XXWRITE		equ	$
XXWRITE_VERIFY:	cmp	rh_type,DISK_REQUEST
XX		jz	write_a_disk
XX		mov	ax,tape_unit		;Do We Have a Tape?
XX		cmp	ax,-1
XX		jz	write_jmp_err1
XX		mov	cur_unit,ax
XX		call	tape_write
XX		jc	write_jmp_err2
XX		jmp	done
XXwrite_a_disk:	call	find_unit
XX		jc	write_jmp_err1
XX		call	disk_write
XX		jc	write_jmp_err2
XX		jmp	done
XXwrite_jmp_err1:	jmp	bad_unit
XXwrite_jmp_err2:	jmp	bad_write
XXwrite_jmp_err3:	jmp	unknown
XX
XX;
XX; Write Ioctl Packet
XX;
XXWRITE_IOCTL:	cmp	rh_type,DISK_REQUEST
XX		jz	ioctl_a_disk
XX		mov	ax,tape_unit			;Do we have a SCSITAPE?
XX		cmp	ax,-1
XX		jz	write_jmp_err1
XX		mov	cur_unit,ax
XX		jmp	short ioctl_do
XXioctl_a_disk:	call	find_unit
XX		jc	write_jmp_err1
XXioctl_do:	call	scsi_ioctl_write
XX		jc	write_jmp_err3
XX		jmp	done
XX
XX;
XX; Special Control Functions
XX;
XXIOCTL:		call	find_unit
XX		jc	ioctl_jmp_err1
XX		call	scsi_ioctl
XX		jc	ioctl_jmp_err2		;Must have been a Verify error
XX		jmp	done
XXioctl_jmp_err1:	jmp	bad_unit
XXioctl_jmp_err2:	jmp	bad_read
XX
XX;
XX; Open Tape Device
XX;
XXOPEN_DEV:	mov	di,tape_unit
XX		cmp	di,-1			;Do We have a SCSITAPE: Unit?
XX		jnz	open_tape
XX		jmp	bad_unit
XXopen_tape:	mov	cur_unit,di			;New Current Unit
XX		lea	bx,[di].unit_sense		;Buffer Offset
XX		push	ds				;Buffer Segment
XX		pop	es
XX		mov	cx,size sense			;Buffer Size
XX		lea	di,cmd_sense			;Command
XX		call	docmd
XX		jc	open_err
XX		cmp	load_flag,TRUE			;Should we LOAD?
XX		jnz	open_ok
XX		ife mini_inquire
XX		mov	di,cur_unit			;Check Unit Type
XX		mov	ax,word ptr [di].unit_inq_buf.inq_manufact
XX		lea	di,cmd_rewind			;Default to Rewind
XX		cmp	ax,'ET'				;If this is a TEAC Unit
XX		jz	open_rewind
XX		endif
XX		lea	di,cmd_load			;Now Load Tape
XX		mov	[di].load_cmd_type,LOAD_TAPE
XXopen_rewind:	call	docmd
XX		jnc	open_ok
XX		call	scsi_sense
XXopen_err:	jmp	general
XXopen_ok:	mov	write_flag,FALSE		;No Writes Seen
XX		mov	read_flag,FALSE			;No Reads Seen
XX		mov	error_flag,FALSE		;No Error Yet
XX		if use_kludge
XX		mov	opened_flag,TRUE		;We are Open
XX		endif
XX		mov	ax,0				;Patch Ourselves into
XX		mov	es,ax				;the INT 24 Vector
XX		mov	ax,es:[vect_int_24]		;Offset
XX		mov	word ptr orig_int_24,ax
XX		lea	ax,our_int_24
XX		mov	es:[vect_int_24],ax
XX		mov	ax,es:[vect_int_24+2]		;Segment
XX		mov	word ptr orig_int_24+2,ax
XX		mov	ax,cs
XX		mov	es:[vect_int_24+2],ax
XX		jmp	done
XX
XX;
XX; Close Tape Device
XX;
XXCLOSE_DEV:	mov	di,tape_unit
XX		cmp	di,-1		;Do We have a SCSITAPE: Unit?
XX		jnz	close_tape
XX		jmp	bad_unit
XXclose_tape:	mov	ax,0				;Restore
XX		mov	es,ax				;the INT 24 Vector
XX		mov	word ptr orig_int_24,ax
XX		mov	es:[vect_int_24],ax		;Offset
XX		mov	word ptr orig_int_24+2,ax
XX		mov	es:[vect_int_24+2],ax		;Segment
XX		mov	cur_unit,di			;New Current Unit
XX		cmp	error_flag,TRUE			;Any Tape Errors
XX		jz	skip_extras
XX		cmp	write_flag,TRUE			;Were We Writing?
XX		jnz	not_writing
XX		lea	di,cmd_twritefm			;End Tape with FM(s)
XX		mov	[di].fm_cmd_cnt_b0,CLOSE_FM_CNT
XX		call	docmd
XX		jnc	skip_extras
XX		call	get_sense
XX		jmp	short skip_extras
XXnot_writing:	cmp	read_flag,TRUE			;Were We Reading?
XX		jnz	skip_extras
XX		cmp	load_flag,TRUE			;No Rewind?
XX		jz	skip_extras
XX		lea	di,cmd_space			;Space Forward
XX		mov	[di].space_cmd_code,1		;By FileMark
XX		mov	[di].space_cmd_cnt2,0
XX		mov	[di].space_cmd_cnt1,0
XX		mov	[di].space_cmd_cnt0,1
XX		call	docmd
XX		jnc	skip_extras
XX		call	get_sense
XXskip_extras:	cmp	load_flag,TRUE			;Should we Unload?
XX		jnz	close_ok	
XX		ife mini_inquire
XX		mov	di,cur_unit			;Check Unit Type
XX		mov	ax,word ptr [di].unit_inq_buf.inq_manufact
XX		lea	di,cmd_rewind
XX		cmp	ax,'ET'				;Rewind instead of
XX		jz	close_rewind			;Unload TEAC Unit
XX		endif
XX		lea	di,cmd_load			;Now Unload Tape
XX		mov	[di].load_cmd_type,UNLOAD_TAPE
XXclose_rewind:	call	docmd
XX		jnc	close_ok
XX		call	scsi_sense
XX		jmp	general
XXclose_ok:	jmp	done
XX
XX;
XX; Get Device Assignment
XX;
XXGET_DEV:	mov	es:[bx].rh_unit,0
XX		jmp	done
XX
XX;
XX; Set Device Assignment
XX;
XXSET_DEV:	jmp	done
XX
XXbad_unit:	mov	es,rh_seg		;Point us at the Request Header
XX		mov	bx,rh_off
XX		or	es:[bx].rh_status,8001h
XX		jmp	short done
XX
XXunknown:	mov	es,rh_seg		;Point us at the Request Header
XX		mov	bx,rh_off
XX		or	es:[bx].rh_status,8003h
XX		jmp	short done
XX
XXbad_write:	mov	es,rh_seg		;Point us at the Request Header
XX		mov	bx,rh_off
XX		or	es:[bx].rh_status,800Ah
XX		jmp	short done
XX
XXbad_read:	mov	es,rh_seg		;Point us at the Request Header
XX		mov	bx,rh_off
XX		or	es:[bx].rh_status,800Bh
XX		jmp	short done
XX
XXgeneral:	mov	es,rh_seg		;Point us at the Request Header
XX		mov	bx,rh_off
XX		or	es:[bx].rh_status,800Ch
XX		jmp	short done
XX
XXbusy:		mov	es,rh_seg		;Point us at the Request Header
XX		mov	bx,rh_off
XX		or	es:[bx].rh_status,0200h
XX
XXdone:		mov	es,rh_seg		;Point us at the Request Header
XX		mov	bx,rh_off
XX		or	es:[bx].rh_status,0100h
XX
XX		cli				;Make sure we're left alone
XX		mov	ax,cs:stack_seg		;Restore DOS Stack
XX		mov	ss,ax
XX		mov	ax,cs:stack_ptr
XX		mov	sp,ax
XX
XX		pop	bp			;Restore All Registers
XX		pop	di
XX		pop	si
XX		pop	dx
XX		pop	cx
XX		pop	bx
XX		pop	ax
XX		pop	es
XX		pop	ds
XX		popf
XX		ret
XX
XX		INCLUDE	units.asm
XX		INCLUDE	subs.asm
XX		INCLUDE	ioctl.asm
XX		INCLUDE	dump.asm
XX		if use_kludge
XX		INCLUDE	kludge.asm
XX		endif
XX
XX;
XX; End of Program
XX; Stuff Placed Here Gets Handed Back To DOS For Re-use
XX;
XXinitial		proc	near
XX		lea	dx,hello_msg		;Tell them the driver version
XX		call	puts
XX		push	cs
XX		pop	dx
XX		lea	bx,seg_msg_value
XX		call	hex2asc4
XX		lea	dx,seg_msg		;And Were We Loaded
XX		call	puts
XX
XX		call	scsi_reset		;Reset the bus
XX
XX		mov	cx,0			;Scan for devices
XXscan:		mov	ax,cx
XX		add	al,030h
XX		mov	scan_dev,al
XX		mov	ax,1			;Create Select Bit
XX		shl	ax,cl
XX		mov	di,cur_unit
XX		mov	[di].unit_select,al
XX		mov	[di].unit_num_drv,0	;No Drives to start with
XX		mov	al,disk_count		;We will start with
XX		mov	[di].unit_1st_drv,al	;Drive Number if any
XX
XX		lea	dx,scan_dev		;Print the device number
XX		call	puts
XX		call	scsi_inquire		;Inquire as to its type
XX		jnc	scan_inq_ok
XX
XX		lea	dx,no_dev		;If the error was
XX		cmp	al,CNOCONNECT		;'No Such Device'
XX		jz	puts_jmp
XX
XX		lea	dx,dumb_disk_msg	;Assume it is a 'SCSI I'
XX		jmp	short scan_is_drv	;Old style disk
XX
XXscan_inq_ok:	mov	di,cur_unit
XX		if mini_inquire
XX		lea	dx,disk_dev_msg
XX		else
XX		lea	dx,[di].unit_inq_buf.inq_manufact
XX		mov	[di].unit_inq_term,'$'
XX		endif
XX		mov	al,[di].unit_inq_buf.inq_dev_type
XX		or	al,al			;Look at device type
XX		jz	scan_is_drv
XX		if mini_inquire
XX		lea	dx,tape_dev_msg
XX		endif
XX		cmp	tape_unit,-1		;Do We Already Have A Tape?
XX		jnz	puts_jmp
XX		call	puts			;Make this our SCSITAPE: Unit
XX		mov	tape_unit,di
XX		lea	dx,tape_msg
XXputs_jmp:	jmp	scan_puts
XX
XXscan_is_drv:	call	puts			;Output the Device String
XX		call	scsi_capacity		;Inquire as to its size
XX		lea	dx,err_size
XX		jc	scan_puts		;Do not use unknown drives
XX		lea	dx,crlf
XX		call	puts
XX
XXscan_next_drv:	mov	di,cur_unit
XX		mov	al,disk_count		;Number Of Drives Found
XX		inc	al
XX		mov	disk_count,al
XX		mov	al,[di].unit_num_drv	;We have a valid Drive
XX		inc	al
XX		mov	[di].unit_num_drv,al
XX		mov	al,cur_drive		;Get Current Drive Letter
XX		mov	drv_msg_let,al		;Insert it in message
XX		inc	al			;Bump Drive Letter
XX		mov	cur_drive,al
XX		call	make_bpb		;Setup the BPB for this drive
XX		mov	di,cur_bpb		;Current Working BPB
XX		if large_drives
XX		mov	dx,[di].bpb_ts_msw
XX		mov	ax,[di].bpb_ts_lsw
XX		else
XX		mov	dx,0
XX		mov	ax,[di].bpb_ts
XX		endif
XX		mov	bx,2048
XX		div	bx
XX		inc	ax
XX		lea	bx,drv_msg_size
XX		call	bin_ascii
XX		mov	bx,bpb_hw_mark		;Get the BPB High Water Mark
XX		inc	bx			;Bump HW Mark for next time
XX		inc	bx
XX		mov	ax,[bx]			;Get the BPB
XX		mov	cur_bpb,ax		;Make it the current BPB
XX		mov	bpb_hw_mark,bx
XX		lea	dx,drv_msg
XX		call	puts
XX		ife large_drives
XX		mov	bx,cur_unit
XX		mov	ah,0
XX		mov	al,[bx].unit_num_drv	;Insert Drive Offset
XX		dec	al			;Into BPB for this Drive
XX		mov	[di].bpb_hs_msw,ax
XX		mov	al,[bx].unit_cap_buf.cap_sectors_b3
XX		or	al,[bx].unit_cap_buf.cap_sectors_b2
XX		or	al,[bx].unit_cap_buf.cap_sectors_b1
XX		or	al,[bx].unit_cap_buf.cap_sectors_b0
XX		jnz	scan_next_drv		;Room left for another Drive
XX		endif
XX		jmp	short scan_next
XX
XXscan_puts:	call	puts
XX		lea	dx,crlf
XX		call	puts
XX
XXscan_next:	inc	cx
XX		cmp	cx,MAXUNIT	;End of devices?
XX		jg	scan_exit
XX		mov	bx,cx		;Bump to next unit
XX		shl	bx,1
XX		mov	ax,word ptr unit_array[bx]
XX		mov	cur_unit,ax
XX		jmp	scan
XX
XXscan_exit:	lea	dx,crlf
XX		call	puts
XX		ret
XXinitial		endp
XX
XX;
XX; Data Area Used Only During Initialization
XX;
XXhello_msg	db	0dh,0ah,'SCSI Device Driver Version 2.0, '
XX		if oldcode
XX		db	'8086 Flavor',0Dh,0Ah,'$'
XX		else
XX		db	'80286 Flavor',0Dh,0Ah,'$'
XX		endif
XXseg_msg		db	'Driver Loaded At Segment '
XXseg_msg_value	db	'0000',0dh,0ah,'$'
XXscan_dev	db	'X - ','$'
XXno_dev		db	'(No Installed Device)$'
XXerr_size	db	'(Unknown Size)$'
XXdrv_msg		db	'  - Drive '
XXdrv_msg_let	db	'X: '
XXdrv_msg_size	db	'XXXXXX Meg',0dh,0ah,'$'
XXtape_msg	db	0dh,0ah,'  - Is The SCSITAPE: Device$'
XXdumb_disk_msg	db	'UNKNOWN DUMB DISK $'
XXcrlf		db	0dh,0ah,'$'
XX		if mini_inquire
XXdisk_dev_msg	db	'Disk Device $'
XXtape_dev_msg	db	'Tape Device $'
XX		endif
XX
XX
XXdev_interrupt	endp
XX_TEXT		ends
XX		end
SHAR_EOF
if test 14291 -ne "`wc -c < 'scsi.asm'`"
then
echo shar: error transmitting "'scsi.asm'" '(should have been 14291 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'subs.asm'" '(22277 characters)'
if test -f 'subs.asm'
then
echo shar: will not over-write existing file "'subs.asm'"
else
sed 's/^XX//' > 'subs.asm' << \SHAR_EOF
XX;
XX; Data storage for local subroutines
XX;
XXcmd_ready	db	SCSI_TESTREADY,0,0,0,0,0
XXcmd_rewind	db	SCSI_REWIND,0,0,0,0,0
XXcmd_sense	db	SCSI_REQSENSE,0,0,0,size sense,0
XXcmd_e_sense	db	SCSI_REQSENSE,0,0,0,size e_sense,0
XXcmd_format	db	SCSI_FORMATUNIT,FORMAT_NORMAL,0,0,0,0
XXcmd_remap	db	SCSI_REASSIGN,0,0,0,0,0
XXcmd_space	db	SCSI_SPACE,1,0,0,0,0
XX		if extended_io
XXcmd_read	db	SCSI_READBLK,0,0,0,0,0,0,0,1,0
XXcmd_write	db	SCSI_WRITEBLK,0,0,0,0,0,0,0,1,0
XX		else
XXcmd_read	db	SCSI_READBLK,0,0,0,1,0
XXcmd_write	db	SCSI_WRITEBLK,0,0,0,1,0
XX		endif
XXcmd_tread	db	SCSI_READBLK,1,0,0,0,0
XXcmd_twrite	db	SCSI_WRITEBLK,1,0,0,0,0
XXcmd_twritefm	db	SCSI_WRITEFM,0,0,0,CLOSE_FM_CNT,0
XXcmd_inquire	db	SCSI_INQUIRY,0,0,0,size inq,0
XXcmd_erase	db	SCSI_ERASE,1,0,0,0,0
XXcmd_load	db	SCSI_LOAD,0,0,0,0,0
XXcmd_capacity	db	SCSI_READSIZE,0,0,0,0,0,0,0,0,0
XXcmd_verify	db	SCSI_VERIFYBLK,0,0,0,0,0,0,0,SECT_TRACK,0
XX
XX		if large_drives
XX		even
XXlsect_lsw	dw	?
XXlsect_msw	dw	?
XX		endif
XX
XX		even
XXdocmd_cmd	dw	?
XXdocmd_buf	dw	?
XXdocmd_buf_seg	dw	?
XXdocmd_len	dw	?
XXdocmd_ustatus	db	?
XXdocmd_estatus	db	?
XXdocmd_message	db	?
XX
XXsense_ustatus	db	?
XXsense_estatus	db	?
XXsense_message	db	?
XX
XXretry_cnt	db	?
XX
XX		if dump_sense
XXsense_msg1	db	0dh,07h,'Unit '
XXsense_unit	db	'xxh, Err '
XXsense_err	db	'xxh, Stat '
XXsense_ustat	db	'xxh, Msg '
XXsense_msg	db	'xxh, Retry '
XXsense_retry	db	'xxh$'
XXsense_msg2	db	', Sense '
XXsense_code	db	'xxh, Addr '
XXsense_addr3	db	'xx'
XXsense_addr2	db	'xx'
XXsense_addr1	db	'xx'
XXsense_addr0	db	'xxh$'
XX		ife monitor
XXsense_msg3	db	0dh,0ah,'$'
XX		endif
XX		endif
XX
XX;
XX; Reset the SCSI Bus
XX;
XXscsi_reset	proc	near
XX		pusha
XX
XX		mov	ax,SCSI_CARD_SEG	;Point at the command port
XX		mov	es,ax
XX		mov	si,SCSI_CMD_PORT
XX
XX		mov	byte ptr es:[si],CMDBASE or CMDRST
XX		call	wait100us
XX		mov	byte ptr es:[si],CMDBASE
XX		call	wait100us
XX
XX		popa
XX		ret
XXscsi_reset	endp
XX
XX;
XX; Request Sense data from a unit and display the result
XX; Called after every SCSI command with the exit code in 'al'
XX;
XXscsi_sense	proc	near
XX		pushf
XX		pusha
XX		push	es
XX
XX		if dump_sense
XX;
XX; Print out the first part even if we can't retrieve any sense status
XX;
XX		mov	al,docmd_estatus	;Save for printing
XX		mov	sense_estatus,al
XX		mov	al,docmd_ustatus
XX		mov	sense_ustatus,al
XX		mov	al,docmd_message
XX		mov	sense_message,al
XX		mov	di,cur_unit
XX		mov	dl,[di].unit_select
XX		lea	bx,sense_unit		;Unit
XX		call	hex2asc2
XX		mov	dl,sense_estatus	;Error (from docmd)
XX		lea	bx,sense_err
XX		call	hex2asc2
XX		mov	dl,sense_ustatus	;Status (from unit)
XX		lea	bx,sense_ustat
XX		call	hex2asc2
XX		mov	dl,sense_message	;Msg (from unit)
XX		lea	bx,sense_msg
XX		call	hex2asc2
XX		mov	dl,retry_cnt		;Retry
XX		lea	bx,sense_retry
XX		call	hex2asc2
XX		lea	dx,sense_msg1
XX		call	puts
XX		endif
XX
XX;
XX; Try to retrieve sense status
XX;
XX		mov	di,cur_unit			;Unit
XX		lea	bx,[di].unit_sense		;Buffer Offset
XX		mov	cx,size sense			;Buffer Size
XX		lea	dx,cmd_sense			;Command
XX		cmp	[di].unit_sense.sense_sense,SENSE_CCS
XX		jnz	no_e_sense
XX		lea	bx,[di].unit_e_sense		;Buffer Offset
XX		mov	cx,size e_sense			;Buffer Size
XX		lea	dx,cmd_e_sense			;Command
XXno_e_sense:	push	ds				;Buffer Segment
XX		pop	es
XX		mov	di,dx
XX		call	docmd
XX
XX		if dump_sense
XX;
XX; If we got something, print it
XX;
XX		jnc	sense_dump
XX		jmp	sense_exit
XX
XXsense_dump:	mov	di,cur_unit
XX		cmp	[di].unit_sense.sense_sense,SENSE_CCS
XX		jz	dump_e_sense
XX
XX		mov	dl,[di].unit_sense.sense_sense
XX		lea	bx,sense_code		;Sense
XX		call	hex2asc2
XX		mov	dl,0
XX		lea	bx,sense_addr3
XX		call	hex2asc2
XX		mov	dl,[di].unit_sense.sense_lba_b2
XX		lea	bx,sense_addr2
XX		call	hex2asc2
XX		mov	dl,[di].unit_sense.sense_lba_b1
XX		lea	bx,sense_addr1
XX		call	hex2asc2
XX		mov	dl,[di].unit_sense.sense_lba_b0
XX		lea	bx,sense_addr0
XX		call	hex2asc2
XX		jmp	short sense_print
XX
XXdump_e_sense:	mov	dl,[di].unit_e_sense.e_sense_sense
XX		lea	bx,sense_code		;Sense
XX		call	hex2asc2
XX		mov	dl,[di].unit_e_sense.e_sense_lba_b3
XX		lea	bx,sense_addr3		;Address
XX		call	hex2asc2
XX		mov	dl,[di].unit_e_sense.e_sense_lba_b2
XX		lea	bx,sense_addr2
XX		call	hex2asc2
XX		mov	dl,[di].unit_e_sense.e_sense_lba_b1
XX		lea	bx,sense_addr1
XX		call	hex2asc2
XX		mov	dl,[di].unit_e_sense.e_sense_lba_b0
XX		lea	bx,sense_addr0
XX		call	hex2asc2
XX
XXsense_print:	lea	dx,sense_msg2
XX		call	puts
XX		endif
XX
XXsense_exit:	if dump_sense
XX		if monitor
XX		mov	cx,20000
XXsense_wait:	call	wait100us
XX		loop	sense_wait
XX		else
XX		lea	dx,sense_msg3		;Terminate the Message
XX		call	puts
XX		endif
XX		endif
XX
XX		pop	es
XX		popa
XX		popf
XX		ret
XXscsi_sense	endp
XX
XX;
XX; Get the Extended Sense Status from the current Unit
XX;
XXget_sense	proc	near
XX		mov	di,cur_unit			;Unit
XX		lea	bx,[di].unit_e_sense		;Buffer Offset
XX		push	ds				;Buffer Segment
XX		pop	es
XX		mov	cx,size e_sense			;Buffer Size
XX		lea	di,cmd_e_sense			;Command
XX		call	docmd				;Always ask first
XX		ret
XXget_sense	endp
XX
XX;
XX; Inquire about the type of a unit
XX;
XX; This MUST be the first call to a unit after the reset is done!
XX;
XX; al = return code, 'C' error indicates an error
XX;
XXscsi_inquire	proc	near
XX		push	cx
XX
XX;
XX; First thing we should do is wait for the unit to be ready
XX; as it takes some drives a while to spin up.
XX;
XX		mov	retry_cnt,READY_RETRY
XXready_loop1:	lea	di,cmd_ready		;Command
XX		call	docmd
XX		jnc	unit_is_ready
XX		cmp	al,CNOCONNECT		;No such unit?
XX		jz	ready_error
XX		push	cx
XX		mov	cx,10000		;Wait 1 Second
XXready_loop2:	call	wait100us
XX		loop	ready_loop2
XX		pop	cx
XX		dec	retry_cnt		;RETRY Times
XX		jns	ready_loop1
XX		jmp	short unit_is_ready	;Still Try the Inquire
XXready_error:	stc
XX		jmp	short inquire_exit
XX
XX;
XX; Then requests its sense status.
XX; This gives us a chance to find out if the
XX; device supports the Command Command Set (CCS)
XX;
XXunit_is_ready:	call	get_sense
XX		jc	inquire_exit
XX
XX;
XX; Ok, Now find out what kind of device it is
XX;
XX		mov	di,cur_unit			;Unit
XX		lea	bx,[di].unit_inq_buf		;Buffer Offset
XX		push	ds				;Buffer Segment
XX		pop	es
XX		mov	cx,size inq			;Buffer Size
XX		lea	di,cmd_inquire			;Command
XX		call	docmd
XX
XXinquire_exit:	pop	cx
XX		ret
XXscsi_inquire	endp
XX
XX;
XX; Determine the size of a disk
XX;
XX; al = return code, 'C' error indicates an error
XX;
XXscsi_capacity	proc	near
XX		push	cx
XX		mov	retry_cnt,MAX_RETRY
XX
XXcapacity_retry:	mov	di,cur_unit			;Unit
XX		lea	bx,[di].unit_cap_buf		;Buffer Offset
XX		push	ds				;Buffer Segment
XX		pop	es
XX		mov	cx,size cap			;Buffer Size
XX		lea	di,cmd_capacity			;Command
XX		call	docmd
XX		jnc	capacity_exit
XX		call	scsi_sense
XX		dec	retry_cnt
XX		jns	capacity_retry
XX		stc
XX
XXcapacity_exit:	pop	cx
XX		ret
XXscsi_capacity	endp
XX
XX;
XX; Verify (cx) Sectors starting with (dx:ax)
XX;
XX; al = return code, 'C' indicates an error
XX;
XX
XXscsi_verify	proc	near
XX		mov	retry_cnt,0		;Don't do retrys
XX		lea	di,cmd_verify			;Command
XX		mov	[di].ver_cmd_lba_b3,dh		;Insert Sector
XX		mov	[di].ver_cmd_lba_b2,dl		; into Command
XX		mov	[di].ver_cmd_lba_b1,ah		;Insert Sector
XX		mov	[di].ver_cmd_lba_b0,al		; into Command
XX		mov	[di].ver_cmd_len_b1,ch		;Insert Length
XX		mov	[di].ver_cmd_len_b0,cl		; into Command
XX		call	docmd
XX		jnc	verify_exit
XX		call	scsi_sense
XX
XXverify_exit:	ret
XXscsi_verify	endp
XX
XX;
XX; Read Some Blocks from the disk given
XX; the request header in es:bx
XX;
XX; al = return code, 'C' indicates an error
XX;
XXdisk_read	proc	near
XX		mov	retry_cnt,MAX_RETRY
XX
XX		mov	di,bx
XX		mov	cx,es:[di].rh4_count		;Sector Count
XX		if large_drives
XX		mov	dx,es:[di].rh4_lsect_lsw	;Starting Sector
XX		mov	lsect_lsw,dx
XX		mov	dx,es:[di].rh4_lsect_msw
XX		mov	lsect_msw,dx
XX		else
XX		mov	dx,es:[di].rh4_sector		;Starting Sector
XX		endif
XX		mov	bx,es:[di].rh4_buf_ofs		;Buffer Offset
XX		mov	ax,es:[di].rh4_buf_seg		;Buffer Segment
XX		mov	es,ax
XX
XX		mov	si,cur_bpb
XX		lea	di,cmd_read			;Command
XX		ife large_drives
XX		mov	ax,[si].bpb_hs_msw		;Drive Sector Offset
XX		if extended_io
XX		mov	[di].io_cmd_lba_b3,ah		;Insert Sector
XX		endif
XX		mov	[di].io_cmd_lba_b2,al		;Into the Command
XX		endif
XX
XX		if multi_sector
XX		mov	ax,cx				;Get Sector Count
XX		and	ax,CHUNK_MAX-1			;Mask Off the I/O Chunk
XX		jnz	disk_r_cok1			;Check for Boundary
XX		mov	ax,CHUNK_MAX
XX		if oldcode
XXdisk_r_cok1:	shl	ax,1				;Convert to Buffer Size
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		else
XXdisk_r_cok1:	shl	ax,9				;Convert to Buffer Size
XX		endif
XX		add	ax,bx				;Check for Wrap
XX		else
XX		mov	ax,bx				;Check for Wrap
XX		add	ax,P_SECT			;The First Time
XX		endif
XXdisk_r_loop:	jnc	disk_r_nowrap
XX		mov	ax,bx				;Normalize the
XX		if oldcode
XX		shr	ax,1				;Segment and
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		else
XX		shr	ax,4				;Segment and
XX		endif
XX		mov	si,es				;Offset so that
XX		add	si,ax				;It dosn't Wrap
XX		mov	es,si
XX		and	bx,000Fh
XXdisk_r_nowrap:	push	cx
XX		if large_drives
XX		mov	dx,lsect_msw
XX		if extended_io
XX		mov	[di].io_cmd_lba_b3,dh
XX		mov	[di].io_cmd_lba_b2,dl
XX		else
XX		and	dl,01Fh
XX		mov	[di].io_cmd_lba_b2,dl
XX		endif
XX		mov	dx,lsect_lsw
XX		endif
XX		mov	[di].io_cmd_lba_b1,dh		;Insert Sector
XX		mov	[di].io_cmd_lba_b0,dl		;Into the Command
XX		if multi_sector
XX		and	cx,CHUNK_MAX-1			;Mask Off the I/O Chunk
XX		jnz	disk_r_cok2			;Check for Boundary
XX		mov	cx,CHUNK_MAX
XXdisk_r_cok2:
XX		if extended_io
XX		mov	[di].io_cmd_cnt_b1,ch		;Insert Sector Count
XX		endif
XX		mov	[di].io_cmd_cnt_b0,cl		;Into the Command
XX		if oldcode
XX		shl	cx,1				;Convert to Buffer Size
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		else
XX		shl	cx,9				;Convert to Buffer Size
XX		endif
XX		else
XX		mov	cx,P_SECT			;Buffer Size
XX		endif
XXdisk_r_retry:	call	docmd
XX		jnc	disk_r_cok3
XX		call	scsi_sense
XX		dec	retry_cnt
XX		jns	disk_r_retry			;Already Setup
XX		pop	cx
XX		stc
XX		jmp	short disk_r_exit
XX		if multi_sector
XXdisk_r_cok3:	pop	cx
XX		mov	ax,cx				;Get Sector Count
XX		and	ax,CHUNK_MAX-1			;Mask Off the I/O Chunk
XX		jnz	disk_r_cok4			;Check for Boundary
XX		mov	ax,CHUNK_MAX
XXdisk_r_cok4:	sub	cx,ax				;Dec Sector Count
XX		jz	disk_r_exit
XX		if large_drives
XX		add	lsect_lsw,ax			;Bump to next Sector
XX		adc	lsect_msw,0
XX		else
XX		add	dx,ax				;Bump to next Sector
XX		endif
XX		if oldcode
XX		shl	ax,1				;Convert to Buffer Size
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		else
XX		shl	ax,9				;Convert to Buffer Size
XX		endif
XX		add	bx,ax
XX		jmp	disk_r_loop
XX		else
XXdisk_r_cok3:	pop	cx
XX		if large_drives
XX		add	lsect_lsw,1			;Bump to next Sector
XX		adc	lsect_msw,0
XX		else
XX		inc	dx				;Bump to next Sector
XX		endif
XX		add	bx,P_SECT
XX		loop	disk_r_loop
XX		clc
XX		endif
XX
XXdisk_r_exit:	mov	es,rh_seg
XX		mov	bx,rh_off
XX		pushf
XX		mov	ax,es:[bx].rh4_count		;Update the Count
XX		sub	ax,cx
XX		mov	es:[bx].rh4_count,ax
XX		popf
XX		ret
XXdisk_read	endp
XX
XX;
XX; Write Some Blocks to the disk given
XX; the request header in es:bx
XX;
XX; al = return code, 'C' indicates an error
XX;
XXdisk_write	proc	near
XX		mov	retry_cnt,MAX_RETRY
XX
XX		mov	di,bx
XX		mov	cx,es:[di].rh8_count		;Sector Count
XX		if large_drives
XX		mov	dx,es:[di].rh8_lsect_lsw	;Starting Sector
XX		mov	lsect_lsw,dx
XX		mov	dx,es:[di].rh8_lsect_msw
XX		mov	lsect_msw,dx
XX		else
XX		mov	dx,es:[di].rh8_sector		;Starting Sector
XX		endif
XX		mov	bx,es:[di].rh8_buf_ofs		;Buffer Offset
XX		mov	ax,es:[di].rh8_buf_seg		;Buffer Segment
XX		mov	es,ax
XX
XX		mov	si,cur_bpb
XX		lea	di,cmd_write			;Command
XX		ife large_drives
XX		mov	ax,[si].bpb_hs_msw		;Drive Sector Offset
XX		if extended_io
XX		mov	[di].io_cmd_lba_b3,ah		;Insert Sector
XX		endif
XX		mov	[di].io_cmd_lba_b2,al		;Into the Command
XX		endif
XX
XX		if multi_sector
XX		mov	ax,cx				;Get Sector Count
XX		and	ax,CHUNK_MAX-1			;Mask Off the I/O Chunk
XX		jnz	disk_w_cok1			;Check for Boundary
XX		mov	ax,CHUNK_MAX
XX		if oldcode
XXdisk_w_cok1:	shl	ax,1				;Convert to Buffer Size
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		else
XXdisk_w_cok1:	shl	ax,9				;Convert to Buffer Size
XX		endif
XX		add	ax,bx				;Check for Wrap
XX		else
XX		mov	ax,bx				;Check for Wrap
XX		add	ax,P_SECT			;The First Time
XX		endif
XXdisk_w_loop:	jnc	disk_w_nowrap
XX		mov	ax,bx				;Normalize the
XX		if oldcode
XX		shr	ax,1				;Segment and
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		else
XX		shr	ax,4				;Segment and
XX		endif
XX		mov	si,es				;Offset so that
XX		add	si,ax				;It dosn't Wrap
XX		mov	es,si
XX		and	bx,000Fh
XXdisk_w_nowrap:	push	cx
XX		if large_drives
XX		mov	dx,lsect_msw
XX		if extended_io
XX		mov	[di].io_cmd_lba_b3,dh
XX		mov	[di].io_cmd_lba_b2,dl
XX		else
XX		and	dl,01Fh
XX		mov	[di].io_cmd_lba_b2,dl
XX		endif
XX		mov	dx,lsect_lsw
XX		endif
XX		mov	[di].io_cmd_lba_b1,dh		;Insert Sector
XX		mov	[di].io_cmd_lba_b0,dl		;Into the Command
XX		if multi_sector
XX		and	cx,CHUNK_MAX-1			;Mask Off the I/O Chunk
XX		jnz	disk_w_cok2			;Check for Boundary
XX		mov	cx,CHUNK_MAX
XXdisk_w_cok2:
XX		if extended_io
XX		mov	[di].io_cmd_cnt_b1,ch		;Insert Sector Count
XX		endif
XX		mov	[di].io_cmd_cnt_b0,cl		;Into the Command
XX		if oldcode
XX		shl	cx,1				;Convert to Buffer Size
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		shl	cx,1
XX		else
XX		shl	cx,9				;Convert to Buffer Size
XX		endif
XX		else
XX		mov	cx,P_SECT			;Buffer Size
XX		endif
XXdisk_w_retry:	call	docmd
XX		jnc	disk_w_cok3
XX		call	scsi_sense
XX		dec	retry_cnt
XX		jns	disk_w_retry			;Already Setup
XX		pop	cx
XX		stc
XX		jmp	short disk_w_exit
XX		if multi_sector
XXdisk_w_cok3:	pop	cx
XX		mov	ax,cx				;Get Sector Count
XX		and	ax,CHUNK_MAX-1			;Mask Off the I/O Chunk
XX		jnz	disk_w_cok4			;Check for Boundary
XX		mov	ax,CHUNK_MAX
XXdisk_w_cok4:	sub	cx,ax				;Dec Sector Count
XX		jz	disk_w_exit
XX		if large_drives
XX		add	lsect_lsw,ax			;Bump to next Sector
XX		adc	lsect_msw,0
XX		else
XX		add	dx,ax				;Bump to next Sector
XX		endif
XX		if oldcode
XX		shl	ax,1				;Convert to Buffer Size
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		shl	ax,1
XX		else
XX		shl	ax,9				;Convert to Buffer Size
XX		endif
XX		add	bx,ax
XX		jmp	disk_w_loop
XX		else
XXdisk_w_cok3:	pop	cx
XX		if large_drives
XX		add	lsect_lsw,1			;Bump to next Sector
XX		adc	lsect_msw,0
XX		else
XX		inc	dx				;Bump to next Sector
XX		endif
XX		add	bx,P_SECT
XX		loop	disk_w_loop
XX		clc
XX		endif
XX
XXdisk_w_exit:	mov	es,rh_seg
XX		mov	bx,rh_off
XX		pushf
XX		mov	ax,es:[bx].rh8_count		;Update the Count
XX		sub	ax,cx
XX		mov	es:[bx].rh8_count,ax
XX		popf
XX		ret
XXdisk_write	endp
XX
XX;
XX; Read Some Blocks from the Tape
XX;
XXtape_read	proc	near
XX		mov	read_flag,TRUE			;Data Read from Tape
XX		mov	di,bx
XX		mov	cx,es:[di].rh4_count		;Byte Count
XX		mov	ax,cx				;Test for invalid
XX		and	ax,P_SECT-1			;Byte Count
XX		jz	tape_r_valid
XX		mov	error_flag,TRUE
XX		mov	es:[di].rh4_count,0		;Nothing Read
XX		stc					;Oops
XX		ret
XXtape_r_valid:	mov	bx,es:[di].rh4_buf_ofs		;Buffer Offset
XX		mov	ax,es:[di].rh4_buf_seg		;Buffer Segment
XX		mov	es,ax
XX		mov	ax,bx				;Normalize the
XX		if oldcode
XX		shr	ax,1				;Segment and
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		else
XX		shr	ax,4				;Segment and
XX		endif
XX		mov	si,es				;Offset so that
XX		add	si,ax				;It dosn't Wrap
XX		mov	es,si
XX		and	bx,000Fh
XX		lea	di,cmd_tread
XX		mov	ax,cx				;Convert Bytes
XX		if oldcode
XX		shr	ax,1				;to Blocks
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		else
XX		shr	ax,9				;to Blocks
XX		endif
XX		mov	[di].tio_cmd_cnt_b1,ah		;Insert into Command
XX		mov	[di].tio_cmd_cnt_b0,al
XX		call	docmd
XX		jnc	tape_r_ok
XX;
XX; Get the Extended Sense Status to check for reading FileMark
XX;
XX		call	get_sense			;Get Extended Sense
XX		jc	tape_r_kaboom
XX		mov	di,cur_unit			;Unit
XX		cmp	[di].unit_e_sense.e_sense_sense,80h
XX		jnz	tape_r_eom
XXtape_r_kaboom:	mov	error_flag,TRUE			;Real Error Occured
XX		stc
XX		ret
XXtape_r_eom:	mov	es,rh_seg
XX		mov	bx,rh_off
XX		mov	es:[bx].rh4_count,0		;Nothing Read
XX		clc
XXtape_r_ok:	ret
XXtape_read	endp
XX
XX;
XX; Write Some Blocks to the Tape
XX;
XXtape_write	proc	near
XX		mov	write_flag,TRUE			;Data Written to Tape
XX		mov	di,bx
XX		mov	cx,es:[di].rh8_count		;Byte Count
XX		mov	ax,cx				;Test for invalid
XX		and	ax,P_SECT-1			;Byte Count
XX		jz	tape_w_valid
XX		mov	es:[di].rh8_count,0		;Nothing Written
XX		mov	error_flag,TRUE			;ERROR!
XX		stc					;Oops
XX		ret
XXtape_w_valid:	mov	cx,es:[di].rh8_count		;Byte Count
XX		mov	bx,es:[di].rh8_buf_ofs		;Buffer Offset
XX		mov	ax,es:[di].rh8_buf_seg		;Buffer Segment
XX		mov	es,ax
XX		mov	ax,bx				;Normalize the
XX		if oldcode
XX		shr	ax,1				;Segment and
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		else
XX		shr	ax,4				;Segment and
XX		endif
XX		mov	si,es				;Offset so that
XX		add	si,ax				;It dosn't Wrap
XX		mov	es,si
XX		and	bx,000Fh
XX		lea	di,cmd_twrite
XX		mov	ax,cx				;Convert Bytes
XX		if oldcode
XX		shr	ax,1				;to Blocks
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		shr	ax,1
XX		else
XX		shr	ax,9				;to Blocks
XX		endif
XX		mov	[di].tio_cmd_cnt_b1,ah		;Insert into Command
XX		mov	[di].tio_cmd_cnt_b0,al
XX		call	docmd
XX		jnc	tape_w_ok
XX;
XX; Get the Sense Status and see if we hit EOM.
XX; This is to allow the FileMark to still be written
XX; during the close processing.
XX;
XX		call	get_sense			;Get Extended Sense
XX		jc	tape_w_kaboom
XX		mov	di,cur_unit			;Unit
XX		cmp	[di].unit_e_sense.e_sense_sense,40h
XX		jz	tape_w_eom
XXtape_w_kaboom:	mov	error_flag,TRUE			;Real Error Occured
XX		mov	es,rh_seg
XX		mov	bx,rh_off
XX		mov	es:[bx].rh8_count,0		;Nothing Written
XXtape_w_eom:	stc
XXtape_w_ok:	ret
XXtape_write	endp
XX
XX;
XX; Do a command
XX;
XX; bx = buffer offset
XX; es = buffer segment
XX; cx = buffer len
XX; di => command string
XX;
XX; al = return code, 'C' indicates an error
XX;
XXdocmd		proc	near
XX		pusha
XX		push	es
XX
XX		mov	docmd_buf,bx		;Save our arguments
XX		mov	docmd_buf_seg,es
XX		mov	docmd_len,cx
XX		mov	docmd_cmd,di
XX		mov	docmd_ustatus,0FFh
XX
XX		if monitor
XX		mov	ax,'F'			;Arbitrate for Bus
XX		call	show_phase
XX		endif
XX
XX		mov	ax,SCSI_CARD_SEG	;Point at the Card
XX		mov	es,ax
XX		mov	si,SCSI_CMD_PORT	;Command Port
XX		mov	di,SCSI_DATA_PORT	;Data Port
XX		mov	bx,cur_unit
XX		mov	al,[bx].unit_select	;Get our Select Bit
XX
XX		if reserve_addr
XX;
XX; Get us control of the BUS by starting Arbitration
XX; Wait a maximum of 250ms for Control of the Bus
XX;
XX		or	al,080h			;Add our Address
XX		mov	byte ptr es:[si],CMDBASE
XX		nop
XX		mov	byte ptr es:[di],080h	;Our Address
XX		nop
XX		mov	byte ptr es:[si],CMDBASE or CMDSTARB
XX		mov	cx,2500
XXarb_loop:	test	byte ptr es:[si],STARBCOMPL
XX		jnz	try_sel
XX		call	wait100us
XX		loop	arb_loop
XX		else
XX;
XX; Wait 250ms for the Bus to become free
XX;
XX		mov	cx,2500
XXidle_loop:	test	byte ptr es:[si],STBSY	;Busy?
XX		jz	try_sel
XX		call	wait100us
XX		loop	idle_loop
XX		endif
XX
XX		call	scsi_reset
XX		mov	al,CBUSBUSY		;Bus still BUSY?
XX		jmp	docmd_exit
XX
XXtry_sel:	mov	byte ptr es:[di],al	;Select Bit
XX		nop
XX		mov	byte ptr es:[si],CMDBASE or CMDENABLE or CMDSEL
XX
XX		if monitor
XX		mov	ax,'S'			;Select Target
XX		call	show_phase
XX		endif
XX
XX;
XX; Wait 250 ms for the Target to be SELected
XX;
XX		mov	cx,2500
XXsel_loop:	test	byte ptr es:[si],STBSY	;Wait for BSY
XX		jnz	cmd_xfer
XX		call	wait100us
XX		loop	sel_loop
XX
XX		if monitor
XX		mov	ax,'A'			;Abort Selection
XX		call	show_phase
XX		endif
XX
XX		mov	byte ptr es:[si],CMDBASE or CMDSEL
XX		call	wait100us		;Spec says wait 200us
XX		call	wait100us		;to abort selection phase
XX		test	byte ptr es:[si],STBSY	;Look one final time
XX		jnz	cmd_xfer		;Device did answer
XX		mov	al,CNOCONNECT		;Nothing Answered
XX		jmp	docmd_exit
XX
XX;
XX; Start the Command, (al) contains last known status
XX;
XXcmd_xfer:	mov	byte ptr es:[si],CMDBASE or CMDENABLE
XX		nop
XXxfer_loop:	mov	al,es:[si]		;Get Status Byte
XX		test	al,STBSY		;Look for BSY bit
XX		jnz	still_busy
XX		jmp	xfer_offline
XX		if scsi_parity
XXstill_busy:	test	al,STPARERR		;Parity Error?
XX		jz	still_good
XX		jmp	xfer_parerr
XXstill_good:	test	al,STREQ		;Request?
XX		jz	xfer_loop
XX		else
XXstill_busy:	test	al,STREQ		;Request?
XX		jz	xfer_loop
XX		endif
XX
XX;
XX; Figure out what type of request it is
XX;
XX		and	al,REQ_MASK
XX		cmp	al,REQ_CMDOUT		;Is it Command Out?
XX		jnz	try_dataout
XX
XX		if monitor
XX		mov	ax,'C'			;Command
XX		call	show_phase
XX		endif
XX
XX		mov	si,docmd_cmd		;Get Command Pointer
XX		movsb				;Send Byte to Card
XX		mov	docmd_cmd,si
XX		mov	si,SCSI_CMD_PORT	;Restore Command Port
XX		mov	di,SCSI_DATA_PORT	;Restore Data Port
XX		jmp	xfer_loop
XX
XXtry_dataout:	cmp	al,REQ_DATAOUT		;Is it Data Out?
XX		jnz	try_datain
XX
XX		if monitor
XX		mov	ax,'W'			;Write
XX		call	show_phase
XX		endif
XX
XX		mov	bx,si
XX		mov	cx,docmd_len		;Get the Data Count
XX		mov	si,docmd_buf		;Source Offset
XX		mov	ds,docmd_buf_seg	;Source Segment
XX		cld
XX
XXdataout_loop:	test	byte ptr es:[bx],STBSY	;Must be BUSY
XX		jz	dataout_exit
XX		test	byte ptr es:[bx],STREQ	;Wait for REQ
XX		jz	dataout_loop
XX		movsb				;Transfer a Byte
XX		dec	di			;Keep in Valid
XX		loop	dataout_loop		;Done Yet?
XX
XXdataout_exit:	mov	si,bx			;Restore the Environment
XX		mov	ax,cs
XX		mov	ds,ax
XX		jmp	xfer_loop
XX
XXtry_datain:	cmp	al,REQ_DATAIN		;Is it Data In?
XX		jnz	try_statin
XX
XX		if monitor
XX		mov	ax,'R'			;Read
XX		call	show_phase
XX		endif
XX
XX		mov	bx,si
XX		mov	si,di			;Source Offset
XX		mov	ax,es
XX		mov	cx,docmd_len		;Length
XX		mov	di,docmd_buf		;Dest Offset
XX		mov	es,docmd_buf_seg	;Dest Segment
XX		mov	ds,ax			;Source Segment
XX		cld
XX
XXdatain_loop:	test	byte ptr [bx],STBSY	;Must be BUSY
XX		jz	datain_exit
XX		test	byte ptr [bx],STREQ	;Wait for REQ
XX		jz	datain_loop
XX		movsb				;Transfer a Byte
XX		dec	si			;Keep in Valid
XX		loop	datain_loop		;Done Yet?
XX
XXdatain_exit:	mov	ax,ds			;Restore the Environment
XX		mov	es,ax
XX		mov	ax,cs
XX		mov	ds,ax
XX		mov	di,si
XX		mov	si,bx
XX		jmp	xfer_loop
XX
XXtry_statin:	cmp	al,REQ_STATIN		;Is it Status In?
XX		jnz	try_msgout
XX
XX		if monitor
XX		mov	ax,'s'			;Status
XX		call	show_phase
XX		endif
XX
XX		mov	al,es:[di]		;Get the Status Byte
XX		mov	docmd_ustatus,al
XX		jmp	xfer_loop
XX
XXtry_msgout:	cmp	al,REQ_MSGOUT		;Is it Message Out?
XX		jnz	try_msgin
XX
XX		if monitor
XX		mov	ax,'M'			;Message Out
XX		call	show_phase
XX		endif
XX
XX		mov	byte ptr es:[di],MSG_REJECT
XX		jmp	xfer_loop
XX
XXtry_msgin:	cmp	al,REQ_MSGIN		;Is it Message In?
XX		jnz	kaboom
XX
XX		if monitor
XX		mov	ax,'m'			;Message In
XX		call	show_phase
XX		endif
XX
XX		mov	al,es:[di]		;Get the MSG Byte
XX		mov	docmd_message,al	;And Save it
XX		cmp	al,MSG_COMPLETE		;Are We All Done?
XX		jnz	xfer_error
XX		cmp	docmd_ustatus,0		;Did we have an error?
XX		mov	al,COK			;Preload OK code
XX		jz	docmd_exit
XX		jmp	xfer_error		;Oops
XX
XXkaboom:		call	scsi_reset		;Reset the BUS
XX
XX		if monitor
XX		mov	ax,'?'			;Message In
XX		call	show_phase
XX		endif
XX		
XXxfer_error:	mov	al,CERROR		;Command Failed with Bad Status
XX		jmp	short docmd_exit
XXxfer_offline:	mov	al,COFFLINE		;Unit went OffLine
XX		jmp	short docmd_exit
XXxfer_parerr:	mov	al,CPARERR		;Parity Error Detected
XX		jmp	short docmd_exit
XXxfer_selerr:	mov	al,CSELERR		;Re-Select?
XX
XXdocmd_exit:	mov	docmd_estatus,al
XX		mov	byte ptr es:[si],CMDBASE
XX		pop	es
XX		popa
XX		mov	al,docmd_estatus
XX		cmp	al,COK
XX		jz	docmd_exit_ok
XX		stc
XXdocmd_exit_ok:	ret
XXdocmd		endp
XX
XX;
XX; Wait One Hundred Micros Seconds
XX;
XX; The value of 'cx' is computed for an 8 Mhz Clock
XX;
XXwait100us	proc	near
XX		push	cx		;   (3) = 375ns
XX		mov	cx,79		;   (2) = 250ns
XXwait_u_loop:	loop	wait_u_loop	;  (10) = 1250ns * X
XX		pop	cx		;   (5) = 625ns
XX		ret			; (11+) = 1375ns
XXwait100us	endp
XX
XX;
XX; Monitor the Bus Phase on the Video Screen
XX;
XX		if monitor
XXshow_phase	proc
XX		push	es
XX		push	di
XX		or	ax,VIDEO_COLOR
XX		mov	di,VIDEO_SEG
XX		mov	es,di
XX		mov	di,VIDEO_OFS
XX		stosw
XX		pop	di
XX		pop	es
XX		ret
XXshow_phase	endp
XX		endif
SHAR_EOF
if test 22277 -ne "`wc -c < 'subs.asm'`"
then
echo shar: error transmitting "'subs.asm'" '(should have been 22277 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'units.asm'" '(3996 characters)'
if test -f 'units.asm'
then
echo shar: will not over-write existing file "'units.asm'"
else
sed 's/^XX//' > 'units.asm' << \SHAR_EOF
XX;
XX; target information/control structures
XX;
XX		even
XXunit0		db	size unit dup (-1)
XX		even
XXunit1		db	size unit dup (-1)
XX		even
XXunit2		db	size unit dup (-1)
XX		even
XXunit3		db	size unit dup (-1)
XX		even
XXunit4		db	size unit dup (-1)
XX		even
XXunit5		db	size unit dup (-1)
XX		even
XXunit6		db	size unit dup (-1)
XX		ife reserve_addr
XX		even
XXunit7		db	size unit dup (-1)
XX		endif
XX
XX;
XX; basic BPB array
XX;
XX		even
XXbpb0		db	size bpb dup (-1)
XX		even
XXbpb1		db	size bpb dup (-1)
XX		even
XXbpb2		db	size bpb dup (-1)
XX		even
XXbpb3		db	size bpb dup (-1)
XX		even
XXbpb4		db	size bpb dup (-1)
XX		even
XXbpb5		db	size bpb dup (-1)
XX		even
XXbpb6		db	size bpb dup (-1)
XX		even
XXbpb7		db	size bpb dup (-1)
XX
XX;
XX; Additional entries if needed
XX;
XX		ife large_drives
XX		even
XXbpb8		db	size bpb dup (-1)
XX		even
XXbpb9		db	size bpb dup (-1)
XX		even
XXbpbA		db	size bpb dup (-1)
XX		even
XXbpbB		db	size bpb dup (-1)
XX		even
XXbpbC		db	size bpb dup (-1)
XX		even
XXbpbD		db	size bpb dup (-1)
XX		even
XXbpbE		db	size bpb dup (-1)
XX		even
XXbpbF		db	size bpb dup (-1)
XX		endif
XX
XX		even
XXunit_array	dw	unit0
XX		dw	unit1
XX		dw	unit2
XX		dw	unit3
XX		dw	unit4
XX		dw	unit5
XX		dw	unit6
XX		ife reserve_addr
XX		dw	unit7
XX		endif
XX
XX		even
XXbpb_array	dw	bpb0		;BPB Array for DOS
XX		dw	bpb1
XX		dw	bpb2
XX		dw	bpb3
XX		dw	bpb4
XX		dw	bpb5
XX		dw	bpb6
XX		dw	bpb7
XX		ife large_drives
XX		dw	bpb8
XX		dw	bpb9
XX		dw	bpbA
XX		dw	bpbB
XX		dw	bpbC
XX		dw	bpbD
XX		dw	bpbE
XX		dw	bpbF
XX		endif
XXbpb_hw_mark	dw	bpb_array
XX
XXtape_unit	dw	-1
XXcur_unit	dw	unit0
XXcur_bpb		dw	bpb0
XX
XX;
XX; Given the request header in es:bx
XX; Return a pointer in ds:di to the unit entry
XX; or 'C' if no such unit exists.
XX;
XX; Do not destroy es:bx !!!
XX;
XXfind_unit	proc	near
XX		pusha
XX		mov	ah,es:[bx].rh_unit	;What drive did they want
XX		lea	di,unit_array
XX		lea	si,bpb_array
XX		mov	cx,MAXUNIT		;How many to search
XXfind_loop:	mov	bx,[di]			;Point at a unit	
XX		mov	al,[bx].unit_num_drv	;Does this SCSI device
XX		or	al,al			;Have any Drives Defined?
XX		jz	find_next
XX		mov	dh,[bx].unit_1st_drv	;Get First Drive Number
XXfind_unit_loop:	cmp	ah,dh			;Is this the correct drive?
XX		jz	find_match
XX		inc	si			;Bump to next BPB
XX		inc	si
XX		ife large_drives
XX		inc	dh			;Bump Drive Number
XX		dec	al			;Dec Drive count
XX		jnz	find_unit_loop		;Try next Drive
XX		endif
XX		jmp	short find_next		;Try next SCSI device
XXfind_match:	mov	cur_unit,bx		;Found a match
XX		mov	ax,[si]
XX		mov	cur_bpb,ax
XX		clc
XX		jmp	find_exit
XXfind_next:	inc	di
XX		inc	di
XX		loop	find_loop
XX		stc				;No More units, Error
XXfind_exit:	popa
XX		ret
XXfind_unit	endp
XX
XX;
XX; Given the data in a unit entry,
XX; create the bpb for the unit.
XX;
XXmake_bpb	proc	near
XX		mov	di,cur_bpb		;Get the current BPB
XX		mov	bx,cur_unit		;Get the current Unit
XX;
XX; First the basic stuff
XX;
XX		mov	[di].bpb_ss,P_SECT
XX		mov	[di].bpb_au,CLUSTSIZE
XX		mov	[di].bpb_rs,1
XX		mov	[di].bpb_nf,2
XX		mov	[di].bpb_de,512
XX		mov	[di].bpb_st,SECT_TRACK
XX		mov	[di].bpb_nh,1
XX		mov	[di].bpb_hs_lsw,0
XX		mov	[di].bpb_hs_msw,0
XX		mov	[di].bpb_md,0F8h
XX;
XX; then the size and fat sectors
XX;
XX		mov	dh,[bx].unit_cap_buf.cap_sectors_b3
XX		mov	dl,[bx].unit_cap_buf.cap_sectors_b2
XX		mov	ah,[bx].unit_cap_buf.cap_sectors_b1
XX		mov	al,[bx].unit_cap_buf.cap_sectors_b0
XX		if large_drives
XX		mov	[di].bpb_ts,0		;(32 bit size)
XX		and	ax,ROUND_CYL		;Round to nearest Cyl
XX		mov	[di].bpb_ts_lsw,ax
XX		mov	[di].bpb_ts_msw,dx
XX		sub	[di].bpb_ts_lsw,1	;Make it zero relative
XX		sbb	[di].bpb_ts_msw,0
XX		mov	bx,P_SECT		;Figure out how many
XX		div	bx			;sectors it will take
XX		mov	dx,0			;to hold the FAT for
XX		mov	bx,CLUSTSIZE		;this drive.
XX		div	bx
XX		mov	dx,0
XX		mov	bx,2
XX		mul	bx
XX		else
XX		or	dx,dx
XX		jz	make_bpb_last		;Use up the last few sectors
XX		dec	dx			;Use up 65536 Sectors
XX		mov	[bx].unit_cap_buf.cap_sectors_b3,dh
XX		mov	[bx].unit_cap_buf.cap_sectors_b2,dl
XX		mov	dx,0			;Max of 32 Meg
XX		mov	ax,65535
XX		jmp	short make_bpb_ts
XXmake_bpb_last:	mov	[bx].unit_cap_buf.cap_sectors_b1,0
XX		mov	[bx].unit_cap_buf.cap_sectors_b0,0
XX		and	ax,ROUND_CYL		;Round to nearest Cyl
XX		dec	ax			;Make it zero relative
XXmake_bpb_ts:	mov	[di].bpb_ts,ax
XX		shr	ax,SECT_2_FS
XX		endif
XX		inc	ax			;Allow for round-off
XX		mov	[di].bpb_fs,ax
XX		ret
XXmake_bpb	endp
SHAR_EOF
if test 3996 -ne "`wc -c < 'units.asm'`"
then
echo shar: error transmitting "'units.asm'" '(should have been 3996 characters)'
fi
fi # end of overwriting check
#
# End of shell archive
#
exit 0
-- 
Brian Antoine                   |
ISC-Bunker Ramo                 |  ...uunet!isc-br!tau-ceti!briana
Spokane, WA                     |     briana@tau-ceti.isc-br.com

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.
