[alt.sources] SCSI Device Driver for the Seagate ST-01

briana@tau-ceti.isc-br.com (Brian Who?) (08/30/90)

     Here is a very simple minded device driver using the ST-01 SCSI
interface card.  It is none to fast, and the code is probably not what
it could be, but for my first assembler project on a PC it does work.
Enjoy!

#
# 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:
#	Makefile
#	Readme.10
#	dump.asm
#	equ.inc
#	ioctl.asm
#	scsi.asm
#	sformat.c
#	struct.inc
#	subs.asm
#	units.asm
# This Archive created: Wed Aug 29 19:00:19 1990
# By: Brian Who? at I Saute Cats - Barbecue Rats, Spokane, WA
#
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(388 characters)'
if test -f 'Makefile'
then
echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^XX//' > 'Makefile' << \SHAR_EOF
XX#
XX# SCSI Stuff
XX#
XXall: scsi.sys sformat.exe
XX
XX#
XX# SCSI Disk Device Driver
XX#
XXscsi.sys: scsi.obj
XX	link +scsi.obj, scsi ;
XX	exe2bin scsi.exe scsi.sys
XX
XXscsi.obj: scsi.asm subs.asm ioctl.asm dump.asm units.asm equ.inc struct.inc
XX	masm scsi.asm scsi.obj scsi.lst ;
XX
XX#
XX# SCSI Disk Formatter
XX#
XXsformat.exe: sformat.c
XX	cl -G2 -Ox -o sformat.exe sformat.c
XX
XX#
XX# clean
XX#
XXclean:
XX	rm -f *.exe *.obj *.lst
SHAR_EOF
if test 388 -ne "`wc -c < 'Makefile'`"
then
echo shar: error transmitting "'Makefile'" '(should have been 388 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'Readme.10'" '(2706 characters)'
if test -f 'Readme.10'
then
echo shar: will not over-write existing file "'Readme.10'"
else
sed 's/^XX//' > 'Readme.10' << \SHAR_EOF
XXScsi Version 1.0
XX
XX     The code you received with this file is a very simple SCSI device
XXdriver that uses the Seagate ST-01 interface card.  As this driver is
XXmy first PC assembler project other then "hello world", please don't
XXsnicker to loudly.
XX
XX     The package includes the source for a device driver that will scan
XXthe SCSI bus for disk drives and partition any drives found into chunks
XXof 32Meg plus any leftovers.  As soon as I discover a way to get DOS to
XXlet me use > 512 byte sectors, It will just allocate the entire disk to
XXa single logical drive.  It also includes a utility to access the low
XXlevel SCSI format function for any disk found.  You may specify the
XXinterleave when the low level format is done and the version of the
XXdriver here seems to work fine at 1:1 with my 8Mhz NEC.
XX
XX     Some of the things to look out for are:
XX
XX#1 The receive_data and send_data functions in subs.asm use polled I/O
XX   to transfer data to/from the card.  I would have loved to just use
XX   the I/O Channel Ready line that the card is suppose to support, but
XX   my NEC does not seem to use that line.  Hence the polling of the REQ
XX   bit in the status port.
XX
XX#2 I did not know how to do clock speed independent timing loops, so there
XX   is a wait100us function in subs.asm that is very processor speed
XX   dependent :-(
XX
XX#3 In ioctl.asm there is a commented out call to scsi_verify.  This is
XX   used by the DOS format utility to scan for errors.  You may want to
XX   enable the call after you get everything setup.  I shut it off while
XX   I was testing as I didn't want to wait for the verify everytime I
XX   changed the interleave.
XX
XX     To bring up the driver.  Assemble and link scsi.sys and add it to
XXyour config.sys file.  After rebooting, you may optionaly do a low level
XXformat of each disk found using sformat.exe.  You then use the DOS format
XXutility on each logical drive.  I did figure out just what format needed
XXin the way of ioctl support to get it to do the high level format for me.
XXAt this point you should have fully functional DOS drives.  In testing
XXI found that with multi_sector support (subs.asm) enabled, the SCSI drives
XXwere just about as fast as the ST-412 C: that came with the machine.  I
XXam sure that the speed problem is basic to the inner loop of the data
XXtransfer routines, but I'm at a loss to figure out how to speed it up.
XX
XX     Anyway, maybe someone can find some use for the code.  I got the
XXcard for free, so I can't really complain about the speed or cost too
XXmuch :-)
XX
XX     Also thanks to the people that sent me samples of other device drivers
XXfor the PC.  I lost the names to a disk crash, but here is the result of
XXyour help and my thanks.
XX
XXBrian Antoine
XXAug 29, 1990
SHAR_EOF
if test 2706 -ne "`wc -c < 'Readme.10'`"
then
echo shar: error transmitting "'Readme.10'" '(should have been 2706 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'dump.asm'" '(973 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 (dx => buffer)
XX;
XXbin_ascii	proc	near
XX		pusha
XX		push	ax
XX		mov	bx,dx
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 to Ascii
XX;
XX; dx = value
XX; di => buffer
XX;
XXhex2asc		proc	near
XX		push	cx
XX		push	ax
XX		mov	cx,4		;Do Four Digits
XXh1:		push	cx
XX		mov	cl,4
XX		rol	dx,cl
XX		mov	al,dl		;Get the Current Digit
XX		and	al,0Fh
XX		cmp	al,0Ah		;Is It Hex?
XX		jge	h2
XX		add	al,30h		;Normal Digit
XX		jmp	h3
XXh2:		add	al,37h		;Hex Digit
XXh3:		mov	cs:[di],al	;Insert in Buffer
XX		inc	di
XX		pop	cx		;Go Do Another
XX		loop	h1
XX		pop	ax
XX		pop	cx
XX		ret
XXhex2asc		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 973 -ne "`wc -c < 'dump.asm'`"
then
echo shar: error transmitting "'dump.asm'" '(should have been 973 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'equ.inc'" '(3049 characters)'
if test -f 'equ.inc'
then
echo shar: will not over-write existing file "'equ.inc'"
else
sed 's/^XX//' > 'equ.inc' << \SHAR_EOF
XX;
XX; Equates
XX;
XXSCSI_CARD_SEG	EQU	0DE00h		;Base Segment of Card
XXSCSI_CMD_PORT	EQU	01A00h		;Offset to Command Port
XXSCSI_DATA_PORT	EQU	01C00h		;Offset to Data Port
XX
XXSTACK_SIZE	EQU	512		;Our Local Stack
XX
XX;
XX; How the 16 bit sector number is broken down
XX; into a sector and cylinder number.
XX;
XX; x = Cylinder, y = track, always have only 1 head
XX;
XX; xxxx xxxx xxxx yyyy
XX;
XX; SECT_2_FS is computed as: ((unit_bpb.bpb_ts / CLUSTSIZE) * 2) / P_SECT)
XX;
XXSECT_TRACK	EQU	16		;Logical Sectors in a Track
XXSECT_MASK	EQU	0000Fh		;Mask for Sector
XXCYL_MASK	EQU	0FFF0h		;Mask for Cylinder
XXSECT_2_CYL	EQU	4		;How far to shift to convert
XX					;Sector to Cylinder Number
XXSECT_2_FS	EQU	10		;How far to shift for
XX					;Total Sectors to Fat Sectors
XX
XXMAXUNIT		EQU	3		;Maximum Unit Number
XX
XXP_SECT		EQU	512		;Physical Sector Size
XXCLUSTSIZE	EQU	4		;Number of Sectors to a Cluster
XX
XX;
XX; For multi_sector reads and writes,
XX; set the following to '1'
XX;
XX; CHUNK_MASK is the maximum number of sectors to access in one
XX; SCSI request.  It MUST be a power of two, and CHUNK_MASK * P_SECT
XX; MUST be <= 64K to prevent segment wrap problems.
XX;
XXmulti_sector	=	1		;1 = multi sector, 0 = single sector
XXCHUNK_MAX	EQU	32
XX
XXCMDENABLE	EQU	080h		;Enable the output drivers
XXCMDENINTR	EQU	040h		;Enable Interrupt
XXCMDPARITY	EQU	020h		;Enable Parity
XXCMDSTARB	EQU	010h		;Start Bus Arbitration
XXCMDATTN		EQU	008h		;Assert ATTN
XXCMDBSY		EQU	004h		;Assert BSY
XXCMDSEL		EQU	002h		;Assert SEL
XXCMDRST		EQU	001h		;Assert RST
XX
XXCMDBASE		EQU	CMDPARITY	;Base value of all commands
XX
XXSTARBCOMPL	EQU	080h		;Arbitration Complete
XXSTPARERR	EQU	040h		;Parity Error
XXSTSEL		EQU	020h		;SEL Asserted
XXSTREQ		EQU	010h		;REQ Asserted
XXSTCD		EQU	008h		;C/D Asserted
XXSTIO		EQU	004h		;I/O Asserted
XXSTMSG		EQU	002h		;MSG Asserted
XXSTBSY		EQU	001h		;BSY Asserted
XX
XXFREE_MASK	EQU	03Fh
XX
XXREQ_MASK	EQU	STMSG or STCD or STIO
XXREQ_DATAOUT	EQU	000h		;Data Out Phase
XXREQ_DATAIN	EQU	STIO		;Data In Phase
XXREQ_CMDOUT	EQU	STCD		;Command Out Phase
XXREQ_STATIN	EQU	STCD or STIO	;Status In Phase
XXREQ_MSGOUT	EQU	STMSG or STCD	;Msg Out Phase
XXREQ_MSGIN	EQU	STMSG or STCD or STIO	;Msg In Phase
XX
XXCOK		EQU	0		;Command Completed OK
XXCNOCONNECT	EQU	1		;Unable to Connect to Target
XXCBUSBUSY	EQU	2		;Bus Busy
XXCTIMEOUT	EQU	3		;Timeout waiting for Response
XXCERROR		EQU	4		;Target Return Error
XXCBUSY		EQU	5		;Target was Busy
XXCDISCONNECT	EQU	6		;Target Disconnected
XX
XXSCSI_TESTREADY	EQU	000h		;Test Unit Ready (6 byte)
XXSCSI_REQSENSE	EQU	003h		;Request Sense (6 byte)
XXSCSI_FORMATUNIT	EQU	004h		;Format Disk (6 byte)
XXSCSI_INQUIRY	EQU	012h		;Inquire (6 byte)
XXSCSI_READSIZE	EQU	025h		;Read Drive Capacity (10 byte)
XXSCSI_READBLK	EQU	028h		;Read Sectors (10 byte)
XXSCSI_WRITEBLK	EQU	02Ah		;Write Sectors (10 byte)
XXSCSI_VERIFYBLK	EQU	02Fh		;Verify Blocks (10 byte)
XX
XXMSG_COMPLETE	EQU	000h		;Command is Complete
XXMSG_SAVE	EQU	002h		;Save Data Pointers
XXMSG_RESTORE	EQU	003h		;Restore Data Pointers
XXMSG_ERROR	EQU	005h		;Error Detected
XXMSG_ABORT	EQU	006h		;Abort the Command
XXMSG_REJECT	EQU	007h		;Reject the Command
XXMSG_NOP		EQU	008h		;No Operation
XXMSG_IDENTIFY	EQU	080h		;Identify Yourself
SHAR_EOF
if test 3049 -ne "`wc -c < 'equ.inc'`"
then
echo shar: error transmitting "'equ.inc'" '(should have been 3049 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ioctl.asm'" '(1824 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
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;		call	scsi_verify
XX		jmp	scsi_i_exit
XX
XXscsi_i_60h:	cmp	al,60h				;Get Device Params?
XX		jnz	scsi_i_62h
XX		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		mov	ax,[si].bpb_ts
XX		shr	ax,SECT_2_CYL			;Convert Sect to Cyl
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	scsi_i_exit
XX
XXscsi_i_62h:	cmp	al,62h				;Verify?
XX		jnz	scsi_i_error
XX		call	scsi_verify
XX		jmp	scsi_i_exit
XX
XXscsi_i_error:	stc
XXscsi_i_exit:	ret
XXscsi_ioctl	endp
XX
XXscsi_ioctl_write proc
XX		mov	di,es:[bx].rh12_buf_ofs
XX		mov	ax,es:[bx].rh12_buf_seg
XX		mov	es,ax
XX		mov	ax,es:[di].ioc_command		;What Command
XX		cmp	al,'F'				;Format?
XX		jnz	scsi_i_w_error
XX
XX		mov	ax,es:[di].ioc_data		;Get Interleave
XX		lea	di,cmd_format			;Insert into Command
XX		mov	[di].fmt_cmd_il_b0,al
XX		mov	[di].fmt_cmd_il_b1,ah
XX		call	docmd
XX		jmp	short scsi_i_w_exit
XX
XXscsi_i_w_error:	stc
XXscsi_i_w_exit:	ret
XXscsi_ioctl_write endp
SHAR_EOF
if test 1824 -ne "`wc -c < 'ioctl.asm'`"
then
echo shar: error transmitting "'ioctl.asm'" '(should have been 1824 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'scsi.asm'" '(8104 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		.286
XX		PAGE	76,132
XX
XX		INCLUDE	equ.inc
XX		INCLUDE	struct.inc
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:
XXnext_dev	dd	-1		;No other Device Drivers
XXattribute	dw	6040h		;Ioctl R/W, Block Device, Non-IBM, Get/Set
XXstrategy	dw	dev_strategy	;Address of 1st DOS Call
XXinterrupt	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;
XXrh_off		dw	?		;Request Header Offset
XXrh_seg		dw	?		;Request Header Segment
XX
XXcur_drive	db	-1
XXvol_id		db	'NO NAME    ',0
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
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	done		;Device Open
XX		dw	done		;Device Close
XX		dw	busy		;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; Strategy Procedure
XX;
XXdev_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		ret
XXdev_strategy	endp
XX
XX;
XX; Interrupt Procedure
XX;
XXdev_interrupt	proc	far
XX		cli				;Save Machine State On Entry
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		pushf
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:	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		mov	bx,rh_off
XX		mov	es,rh_seg
XX		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
XXMEDIA_CHECK:	call	find_unit
XX		jc	bad_unit
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
XX
XXGET_BPB:	call	find_unit
XX		jc	bad_unit
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
XX
XX;
XX; Read some data from the disk
XX;
XXREAD:		call	find_unit
XX		jc	bad_unit
XX		call	scsi_read
XX		jc	bad_read
XX		jmp	done
XX
XX;
XX; Write some data to the disk
XX;
XXWRITE		equ	$
XXWRITE_VERIFY:	call	find_unit
XX		jc	bad_unit
XX		call	scsi_write
XX		jc	bad_write
XX		jmp	done
XX
XX;
XX; Write Ioctl Packet
XX;
XXWRITE_IOCTL:	call	find_unit
XX		jc	bad_unit
XX		call	scsi_ioctl_write
XX		jc	unknown
XX		jmp	done
XX
XX;
XX; Special Control Functions
XX;
XXIOCTL:		call	find_unit
XX		jc	bad_unit
XX		call	scsi_ioctl
XX		jc	unknown
XX		jmp	done
XX
XXGET_DEV:	mov	es:[bx].rh_unit,0
XX		jmp	done
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
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		popf				;Restore All Registers
XX		pop	bp
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		sti				;We're Safe Now
XX		ret
XX
XX		INCLUDE	units.asm
XX		INCLUDE	subs.asm
XX		INCLUDE	ioctl.asm
XX		INCLUDE	dump.asm
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	di,seg_msg_value
XX		call	hex2asc
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		jmp	scan_err
XX
XXscan_inq_ok:	mov	di,cur_unit
XX		lea	dx,[di].unit_inq_buf.inq_manufact
XX		mov	[di].unit_inq_term,'$'
XX		mov	al,[di].unit_inq_buf.inq_dev_type
XX		or	al,al			;Look at device type
XX		jz	scan_is_drv
XX		jmp	scan_puts		;Must be a Tape Drive
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		mov	ax,[di].bpb_ts
XX		shr	ax,11
XX		inc	ax
XX		lea	dx,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		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		jmp	short scan_next
XX
XXscan_err:	lea	dx,no_dev
XX		cmp	al,CNOCONNECT
XX		jz	scan_puts
XX		lea	dx,err_dev
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:	ret
XXinitial		endp
XX
XX;
XX; Data Area Used Only During Initialization
XX;
XXhello_msg	db	0dh,0ah,'SCSI Device Driver Version 1.0',0Dh,0Ah,'$'
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_dev		db	'(Error On Device)$'
XXerr_size	db	'unknown size$'
XXdrv_msg		db	'  - Drive '
XXdrv_msg_let	db	'X: '
XXdrv_msg_size	db	'XXXXXX Meg',0dh,0ah,'$'
XXcrlf		db	0dh,0ah,'$'
XX
XXdev_interrupt	endp
XX_TEXT		ends
XX		end	scsi
SHAR_EOF
if test 8104 -ne "`wc -c < 'scsi.asm'`"
then
echo shar: error transmitting "'scsi.asm'" '(should have been 8104 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'sformat.c'" '(1842 characters)'
if test -f 'sformat.c'
then
echo shar: will not over-write existing file "'sformat.c'"
else
sed 's/^XX//' > 'sformat.c' << \SHAR_EOF
XX/*
XX** SCSI Disk Formatter (Low Level)
XX**
XX** usage: sformat drive: [interleave]
XX**
XX** Revision History:
XX**
XX** Version 1.0  08/03/90 Initial Release
XX**
XX** Version 1.1  08/20/90 Add verification message.
XX*/
XX#include <stdio.h>
XX#include <dos.h>
XX
XX#define TRUE (1)
XX#define FALSE (0)
XX#define VERSION "sformat Version 1.1 BWA"
XX
XXextern int _doserrno;
XX
XXstruct cmd {
XX	short command;		/* command type */
XX	short args;			/* command args */
XX} ioctl_data;
XXunion REGS inregs, outregs;
XXstruct SREGS segregs;
XXunsigned short interleave = 0;
XXunsigned char drive;
XXchar far *cp;
XX
XXmain(argc, argv)
XXint argc;
XXchar *argv[];
XX{
XX	/*
XX	** say hello
XX	*/
XX	puts(VERSION);
XX
XX	/*
XX	** figure out who to format
XX	*/
XX	switch (argc)
XX	{
XX		case 3:
XX		interleave = atoi(argv[2]);
XX		case 2:
XX		if (argv[1][1] != ':') usage();
XX		drive = argv[1][0];
XX		drive = toupper(drive);
XX		drive -= '@';
XX		break;
XX
XX		default:
XX		usage();
XX		break;
XX	}
XX
XX	/*
XX	** verify that this is what the user really wants to do
XX	*/
XX	printf("Do you really wish to format the SCSI\n");
XX	printf("device that contains drive %c: (y,n)? ", argv[1][0]);
XX	fflush(stdout);
XX	if ( getchar() != 'y' )
XX	{
XX		puts("Aborting low level format ....");
XX		exit(1);
XX	}
XX
XX	/*
XX	** put together the command
XX	*/
XX	inregs.h.ah = 0x44;			/* ioctl */
XX	inregs.h.al = 0x05;			/* write */
XX	inregs.h.bl = drive;		/* unit */
XX	inregs.x.cx = sizeof(struct cmd);
XX	cp = (char *) &ioctl_data;
XX	inregs.x.dx = FP_OFF(cp);
XX	segregs.ds = FP_SEG(cp);
XX	ioctl_data.command = 'F';
XX	ioctl_data.args = interleave;
XX
XX	/*
XX	** start the format
XX	*/
XX	puts("Now formating ....");
XX	puts("Please wait ....");
XX	intdosx(&inregs, &outregs, &segregs);
XX
XX	/*
XX	** see what happened
XX	*/
XX	if ( outregs.x.cflag )
XX		printf("DOS error %d occured during format.\n", _doserrno);
XX	else
XX		puts("Formating complete.");
XX	exit(0);
XX}
XX
XXusage()
XX{
XX	puts("usage: sformat drive: [interleave]");
XX	exit(1);
XX}
SHAR_EOF
if test 1842 -ne "`wc -c < 'sformat.c'`"
then
echo shar: error transmitting "'sformat.c'" '(should have been 1842 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'struct.inc'" '(5738 characters)'
if test -f 'struct.inc'
then
echo shar: will not over-write existing file "'struct.inc'"
else
sed 's/^XX//' > 'struct.inc' << \SHAR_EOF
XX;
XX; Structures for SCSI commands
XX;
XXio_cmd		struc
XXio_cmd_op	db	?		;Opcode
XXio_cmd_lun	db	?
XXio_cmd_lba_b3	db	?		;Logical Block Address
XXio_cmd_lba_b2	db	?
XXio_cmd_lba_b1	db	?
XXio_cmd_lba_b0	db	?
XXio_cmd_dummy1	db	?
XXio_cmd_cnt_b1	db	?		;Block Count
XXio_cmd_cnt_b0	db	?
XXio_cmd_dummy2	db	?
XXio_cmd		ends
XX
XX;
XX; Format the Unit
XX;
XXfmt_cmd		struc
XXfmt_cmd_op	db	?		;Opcode
XXfmt_cmd_type	db	?		;Format Type
XXfmt_cmd_dummy1	db	?
XXfmt_cmd_il_b1	db	?		;Interleave (MSB)
XXfmt_cmd_il_b0	db	?		;Interleave (LSB)
XXfmt_cmd_dummy3	db	?
XXfmt_cmd		ends
XX
XX;
XX; Verify Sectors
XX;
XXver_cmd		struc
XXver_cmd_op	db	?		;Opcode
XXver_cmd_lun	db	?		;Lun
XXver_cmd_lba_b3	db	?		;Logical Block Address MSB
XXver_cmd_lba_b2	db	?
XXver_cmd_lba_b1	db	?
XXver_cmd_lba_b0	db	?		;Logical Block Address LSB
XXver_cmd_dummy1	db	?
XXver_cmd_len_b1	db	?		;Length MSB
XXver_cmd_len_b0	db	?		;Length LSB
XXver_cmd_dummy2	db	?
XXver_cmd		ends
XX
XX;
XX; Structure returned by the unit inquiry command
XX;
XXinq		struc
XXinq_dev_type	db	?		;Device Type
XXinq_dev_qual	db	?		;Device Qualifier
XXinq_stand_rev	db	?		;Standard Revision Level
XXinq_format	db	?		;Response Format
XXinq_length	db	?		;Length of Extra Data
XXinq_reserv1	db	?
XXinq_reserv2	db	?
XXinq_reserv3	db	?
XXinq_manufact	db	8 dup (?)	;Manufacture
XXinq_product	db	16 dup (?)	;Product
XXinq		ends
XX
XX;
XX; Structure returned by the read drive capacity command
XX;
XXcap		struc
XXcap_sectors_b3	db	?		;MSB of sector count
XXcap_sectors_b2	db	?
XXcap_sectors_b1	db	?
XXcap_sectors_b0	db	?		;LSB of sector count
XXcap_size_b3	db	?		;MSB of sector size
XXcap_size_b2	db	?
XXcap_size_b1	db	?
XXcap_size_b0	db	?		;LSB of sector size
XXcap		ends
XX
XX;
XX; Structure Definitions For Our Device Driver
XX;
XXbpb		struc
XXbpb_ss		dw	?		;Sector Size
XXbpb_au		db	?		;Cluster Size in Sectors
XXbpb_rs		dw	?		;Reserved Sectors
XXbpb_nf		db	?		;Number of Fats
XXbpb_de		dw	?		;Number of Root Directory Entries
XXbpb_ts		dw	?		;Total Number Of Sectors
XXbpb_md		db	?		;Media Descriptor
XXbpb_fs		dw	?		;Number of Sectors in each Fat
XXbpb_st		dw	?		;Number of Sectors per Track
XXbpb_nh		dw	?		;Number of Heads
XXbpb_hs_lsw	dw	?		;Hidden Sectors (Least Sig Word)
XXbpb_hs_msw	dw	?		;Hidden Sectors (Most Sig Word)
XXbpb_ts_large	dd	?		;Large Total Sector Count
XXbpb_res		db	6 dup (?)	;Reserved
XXbpb		ends
XX
XX;
XX; ioctl function 42h
XX;
XXioctl_fmt	struc
XXioctl_fmt_spec	db	?		;Special Flags
XXioctl_fmt_head	dw	?		;Head to Format
XXioctl_fmt_cyl	dw	?		;Cylinder to Format
XXioctl_fmt	ends
XX
XX;
XX; ioctl function 60h
XX;
XXdpb		struc
XXdpb_special	db	?		;Special Flags
XXdpb_type	db	?		;Device Type
XXdpb_attr	dw	?		;Device Attributes
XXdpb_cyl		dw	?		;Device Cylinder Count
XXdpb_media	db	?		;Device Media Type if Diskette
XXdpb_bpb		db	size bpb dup (?)
XXdpb_sectors	dw	?		;Sectors in Track
XXdpb_track	dd	SECT_TRACK dup (?)
XXdpb		ends
XX
XX;
XX; The internal control structure for a SCSI device
XX;
XXunit		struc
XXunit_1st_drv	db	?		;DOS Drive Numbers
XXunit_num_drv	db	?		;DOS Drive Count
XXunit_select	db	?		;SCSI Select Bit
XXunit_mcheck	db	?		;Media Check Byte
XXunit_inq_buf	db	size inq dup (?)
XXunit_inq_term	db	?
XXunit_cap_buf	db	size cap dup (?)
XXunit		ends
XX
XX;
XX; Ioctl Commands
XX;
XXioc		struc
XXioc_command	dw	?		;Command
XXioc_data	dw	?		;Command Dependent Data
XXioc		ends
XX
XX;
XX; DOS requests
XX;
XXrh		struc
XXrh_len		db	?		;Length of Packet
XXrh_unit		db	?		;Unit Code (Block Only)
XXrh_cmd		db	?		;Command Code
XXrh_status	dw	?		;Returned Status
XXrh_res		db	8 dup (?)	;Reserved
XXrh		ends
XX
XXrh0		struc			;INITIALIZATION
XXrh0_rh		db	size rh dup (?)	;Fixed Portion
XXrh0_nunits	db	?		;Number of units (Block Only)
XXrh0_brk_ofs	dw	?		;Break Address (Offset)
XXrh0_brk_seg	dw	?		;Break Address (Segment)
XXrh0_bpb_tbo	dw	?		;Pointer to BPB Array (Offset)
XXrh0_bpb_tbs	dw	?		;Pointer to BPB Array (Segment)
XXrh0_drv_ltr	db	?		;First Available Drive (DOS 3+, Block Only)
XXrh0		ends
XX
XXrh1		struc			;MEDIA CHECK
XXrh1_rh		db	size rh dup (?)	;Fixed Portion
XXrh1_media	db	?		;Media Descriptor from DPB
XXrh1_md_stat	db	?		;Media Status returned by Device Driver
XXrh1_volid_ofs	dw	?		;Offset of Volume ID String (DOS 3+)
XXrh1_volid_seg	dw	?		;Segment of Volume ID String (DOS 3+)
XXrh1		ends
XX
XXrh2		struc			;GET BPB
XXrh2_rh		db	size rh dup (?)	;Fixed Portion
XXrh2_media	db	?		;Media Descriptor from DPB
XXrh2_buf_ofs	dw	?		;Offset of Data Transfer Area
XXrh2_buf_seg	dw	?		;Segment of Data Transfer Area
XXrh2_pbpbo	dw	?		;Offset of Pointer to BPB
XXrh2_pbpbs	dw	?		;Segment of Pointer to BPB
XXrh2		ends
XX
XXrh4		struc			;INPUT
XXrh4_rh		db	size rh dup (?)	;Fixed Portion
XXrh4_media	db	?		;Media Descriptor from DPB
XXrh4_buf_ofs	dw	?		;Offset of Data Transfer Area
XXrh4_buf_seg	dw	?		;Segment of Data Transfer Area
XXrh4_count	dw	?		;Transfer Count (Sectors)
XXrh4_start	dw	?		;Start Sector Number
XXrh4		ends
XX
XXrh8		struc			;OUTPUT
XXrh8_rh		db	size rh dup (?)	;Fixed Portion
XXrh8_media	db	?		;Media Descriptor from DPB
XXrh8_buf_ofs	dw	?		;Offset of Data Transfer Area
XXrh8_buf_seg	dw	?		;Segment of Data Transfer Area
XXrh8_count	dw	?		;Transfer Count (Sectors)
XXrh8_start	dw	?		;Start Sector Number
XXrh8		ends
XX
XXrh9		struc			;OUTPUT VERIFY
XXrh9_rh		db	size rh dup (?)	;Fixed Portion
XXrh9_media	db	?		;Media Descriptor from DPB
XXrh9_buf_ofs	dw	?		;Offset of Data Transfer Area
XXrh9_buf_seg	dw	?		;Segment of Data Transfer Area
XXrh9_count	dw	?		;Transfer Count (Sectors)
XXrh9_start	dw	?		;Start Sector Number
XXrh9		ends
XX
XXrh12		struc			;OUTPUT IOCTL
XXrh12_rh		db	size rh dup (?)	;Fixed Portion
XXrh12_media	db	?		;Media Descriptor from DPB
XXrh12_buf_ofs	dw	?		;Offset of Data Transfer Area
XXrh12_buf_seg	dw	?		;Segment of Data Transfer Area
XXrh12_count	dw	?		;Transfer Count (Sectors)
XXrh12_start	dw	?		;Start Sector Number
XXrh12		ends
XX
XXrh19		struc			;IOCTL
XXrh19_rh		db	size rh dup (?)	;Fixed Portion
XXrh19_major	db	?		;Major Code
XXrh19_minor	db	?		;Minor Code
XXrh19_si		dw	?		;Caller SI Register
XXrh19_di		dw	?		;Caller DI Register
XXrh19_buf_ofs	dw	?		;Caller Buffer Offset
XXrh19_buf_seg	dw	?		;Caller Buffer Segment
XXrh19		ends
SHAR_EOF
if test 5738 -ne "`wc -c < 'struct.inc'`"
then
echo shar: error transmitting "'struct.inc'" '(should have been 5738 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'subs.asm'" '(11083 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_format	db	SCSI_FORMATUNIT,0,0,0,0,0
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
XXcmd_inquire	db	SCSI_INQUIRY,0,0,0,size inq,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		even
XXdocmd_cmd	dw	?
XXdocmd_buf	dw	?
XXdocmd_buf_seg	dw	?
XXdocmd_len	dw	?
XXdocmd_unit_sel	db	?
XXdocmd_status	db	?
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	al,CMDBASE or CMDENABLE or CMDRST
XX		mov	es:[si],al		;Reset the bus
XX		call	wait1ms
XX		mov	al,CMDBASE
XX		mov	es:[si],al		;All done
XX		mov	cx,250			;Wait 250ms
XXreset_loop:	call	wait1ms
XX		loop	reset_loop
XX
XX		popa
XX		ret
XXscsi_reset	endp
XX
XX;
XX; Test the Ready Status of a unit
XX;
XX; al = return code, 'C' error
XX;
XXscsi_ready	proc	near
XX		lea	di,cmd_ready			;Command
XX		call	docmd
XX		ret
XXscsi_ready	endp
XX
XX;
XX; Inquire about the type of a unit
XX;
XX; 'C' error indicates an error
XX;
XXscsi_inquire	proc	near
XX		push	cx
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		pop	cx
XX		ret
XXscsi_inquire	endp
XX
XX;
XX; Determine the size of a disk
XX;
XX; 'C' error indicates an error
XX;
XXscsi_capacity	proc	near
XX		push	cx
XX		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		pop	cx
XX		ret
XXscsi_capacity	endp
XX
XX;
XX; Verify the Track given in an IOCTL Request
XX;
XX; 'C' indicates an error
XX;
XXscsi_verify	proc	near
XX		mov	di,es:[bx].rh19_buf_ofs		;Command Offset
XX		mov	ax,es:[bx].rh19_buf_seg		;Command Segment
XX		mov	es,ax
XX		mov	ax,es:[di].ioctl_fmt_cyl	;Track
XX		shl	ax,SECT_2_CYL			;Convert to Sector
XX
XX		mov	di,cur_bpb			;Add to Drive Offset
XX		mov	dx,[di].bpb_hs_msw
XX
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		call	docmd
XX		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;
XXscsi_read	proc	near
XX		mov	di,bx
XX		mov	cx,es:[di].rh4_count		;Sector Count
XX		mov	dx,es:[di].rh4_start		;Starting Sector
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		mov	ax,[si].bpb_hs_msw		;Drive Sector Offset
XX		mov	[di].io_cmd_lba_b3,ah		;Insert Sector
XX		mov	[di].io_cmd_lba_b2,al		;Into the Command
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	scsi_r_cok1			;Check for Boundary
XX		mov	ax,CHUNK_MAX
XXscsi_r_cok1:	shl	ax,9				;Convert to Buffer Size
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
XXscsi_r_loop:	jnc	scsi_r_nowrap
XX		mov	ax,bx				;Normalize the
XX		shr	ax,4				;Segment and
XX		mov	si,es				;Offset so that
XX		add	si,ax				;It dosn't Wrap
XX		mov	es,si
XX		and	bx,000Fh
XXscsi_r_nowrap:	push	cx
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	scsi_r_cok2			;Check for Boundary
XX		mov	cx,CHUNK_MAX
XXscsi_r_cok2:	mov	[di].io_cmd_cnt_b1,ch		;Insert Sector Count
XX		mov	[di].io_cmd_cnt_b0,cl		;Into the Command
XX		shl	cx,9				;Convert to Buffer Size
XX		else
XX		mov	cx,P_SECT			;Buffer Size
XX		endif
XX		call	docmd
XX		pop	cx
XX		jc	scsi_r_exit
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	scsi_r_cok3			;Check for Boundary
XX		mov	ax,CHUNK_MAX
XXscsi_r_cok3:	sub	cx,ax				;Dec Sector Count
XX		jz	scsi_r_exit
XX		add	dx,ax				;Bump to next Sector
XX		shl	ax,9				;Convert to Buffer Size
XX		add	bx,ax
XX		jmp	short scsi_r_loop
XX		else
XX		inc	dx				;Bump to next Sector
XX		add	bx,P_SECT
XX		loop	scsi_r_loop
XX		clc
XX		endif
XXscsi_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
XXscsi_read	endp
XX
XX;
XX; Write Some Blocks from the disk given
XX; the request header in es:bx
XX;
XX; al = return code, 'C' indicates an error
XX;
XXscsi_write	proc	near
XX		mov	di,bx
XX		mov	cx,es:[di].rh8_count		;Sector Count
XX		mov	dx,es:[di].rh8_start		;Starting Sector
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		mov	ax,[si].bpb_hs_msw		;Drive Sector Offset
XX		mov	[di].io_cmd_lba_b3,ah		;Insert Sector
XX		mov	[di].io_cmd_lba_b2,al		;Into the Command
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	scsi_w_cok1			;Check for Boundary
XX		mov	ax,CHUNK_MAX
XXscsi_w_cok1:	shl	ax,9				;Convert to Buffer Size
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
XXscsi_w_loop:	jnc	scsi_w_nowrap
XX		mov	ax,bx				;Normalize the
XX		shr	ax,4				;Segment and
XX		mov	si,es				;Offset so that
XX		add	si,ax				;It dosn't Wrap
XX		mov	es,si
XX		and	bx,000Fh
XXscsi_w_nowrap:	push	cx
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	scsi_w_cok2			;Check for Boundary
XX		mov	cx,CHUNK_MAX
XXscsi_w_cok2:	mov	[di].io_cmd_cnt_b1,ch		;Insert Sector Count
XX		mov	[di].io_cmd_cnt_b0,cl		;Into the Command
XX		shl	cx,9				;Convert to Buffer Size
XX		else
XX		mov	cx,P_SECT			;Buffer Size
XX		endif
XX		call	docmd
XX		pop	cx
XX		jc	scsi_w_exit
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	scsi_w_cok3			;Check for Boundary
XX		mov	ax,CHUNK_MAX
XXscsi_w_cok3:	sub	cx,ax				;Dec Sector Count
XX		jz	scsi_w_exit
XX		add	dx,ax				;Bump to next Sector
XX		shl	ax,9				;Convert to Buffer Size
XX		add	bx,ax
XX		jmp	short scsi_w_loop
XX		else
XX		inc	dx				;Bump to next Sector
XX		add	bx,P_SECT
XX		loop	scsi_w_loop
XX		clc
XX		endif
XXscsi_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
XXscsi_write	endp
XX
XX;
XX; Do a command
XX;
XX; bx => buffer for returned information
XX; cx = buffer len
XX; di => command string
XX; es = buffer segment for returned information
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
XX		mov	ax,SCSI_CARD_SEG	;Point at the Card
XX		mov	es,ax
XX		mov	si,SCSI_CMD_PORT	;Command Port
XX
XX;
XX; Wait for the Bus to become free
XX;
XX		mov	cx,65535
XXidle_loop:	mov	al,es:[si]		;Get the Status
XX		and	al,FREE_MASK
XX		jz	try_sel
XX		loop	idle_loop
XX
XX		call	scsi_reset
XX		mov	al,CBUSBUSY		;Bus still BUSY?
XX		stc
XX		jmp	docmd_exit
XX
XXtry_sel:	mov	al,CMDBASE		;Try to select target
XX		mov	es:[si],al
XX
XX		mov	di,cur_unit
XX		mov	al,[di].unit_select	;Get our Select Bit
XX		mov	di,SCSI_DATA_PORT	;Data Port
XX		mov	es:[di],al
XX
XX		mov	al,CMDBASE or CMDENABLE or CMDSEL
XX		mov	es:[si],al
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	;Look for BSY bit
XX		jnz	cmd_xfer
XX		call	wait100us
XX		loop	sel_loop
XX
XX		mov	al,CNOCONNECT		;Nothing Answered
XX		stc
XX		jmp	docmd_exit
XX
XX;
XX; Start the Command
XX;
XXcmd_xfer:	mov	al,CMDBASE or CMDENABLE
XX		mov	es:[si],al
XXxfer_loop:	mov	al,es:[si]
XX		test	al,STBSY		;Look for BSY bit
XX		jz	xfer_error
XX		test	al,STREQ		;And REQ bit
XX		jz	xfer_loop
XX
XX		and	al,REQ_MASK		;Look at REQ type
XX
XX		cmp	al,REQ_DATAOUT		;Is it Data Out?
XX		jnz	try_datain
XX		call	send_data
XX		jmp	short xfer_loop
XX
XXtry_datain:	cmp	al,REQ_DATAIN		;Is it Data In?
XX		jnz	try_cmdout
XX		call	receive_data
XX		jmp	short xfer_loop
XX
XXtry_cmdout:	cmp	al,REQ_CMDOUT		;Is it Command Out?
XX		jnz	try_statin
XX		call	send_cmd
XX		jmp	short xfer_loop
XX
XXtry_statin:	cmp	al,REQ_STATIN		;Is it Status In?
XX		jnz	try_msgout
XX		mov	al,es:[di]		;Get the Status Byte
XX		mov	docmd_status,al
XX		jmp	short xfer_loop
XX
XXtry_msgout:	cmp	al,REQ_MSGOUT		;Is it Message Out?
XX		jnz	try_msgin
XX		call	send_nop
XX		jmp	short xfer_loop
XX
XXtry_msgin:	cmp	al,REQ_MSGIN		;Is it Message In?
XX		jnz	xfer_error
XX
XX		mov	al,es:[di]		;Get Message Byte
XX		cmp	al,MSG_COMPLETE		;Are We All Done?
XX		jnz	short xfer_loop
XX		mov	al,docmd_status
XX		cmp	al,0
XX		jnz	xfer_error
XX		mov	al,COK
XX		clc
XX		jmp	docmd_exit
XX
XXxfer_error:	call	scsi_reset
XX		mov	al,CERROR
XX		stc
XX
XXdocmd_exit:	mov	docmd_status,al
XX		mov	al,CMDBASE
XX		mov	es:[si],al
XX		pop	es
XX		popa
XX		mov	al,docmd_status
XX		ret
XXdocmd		endp
XX
XX;
XX; Receive a Data Stream from the card
XX; On entry es:[di] points at the data port
XX;          es:[si] points at the command port
XX;
XXreceive_data	proc	near
XX		mov	dx,es			;Save ES
XX
XX		mov	bx,si
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	si,SCSI_DATA_PORT	;Source Offset
XX		mov	ds,ax			;Source Segment
XX		mov	al,STREQ
XX		cld
XX
XXreceive_loop:	movsb
XX		dec	si			;Don't blow the card buffer
XX		dec	cx
XX		jz	receive_exit
XXreceive_wait:	test	byte ptr [bx],al	;Ready?
XX		jnz	receive_loop
XX		jmp	short receive_wait
XX
XXreceive_exit:	mov	si,SCSI_CMD_PORT	;Restore the Environment
XX		mov	di,SCSI_DATA_PORT
XX		mov	ax,cs
XX		mov	ds,ax
XX		mov	es,dx
XX		ret
XXreceive_data	endp
XX
XX;
XX; Send a Command to the card
XX; On entry es:[di] points at the data port
XX;          es:[si] points at the command port
XX;
XXsend_cmd	proc	near
XX		mov	bx,docmd_cmd		;Get Command Pointer
XX		mov	al,[bx]			;Get a Command Byte
XX		mov	es:[di],al		;Send it to Card
XX		inc	bx			;Bump for Next Time
XX		mov	docmd_cmd,bx
XX		ret
XXsend_cmd	endp
XX
XX;
XX; Send a Data Stream to the card
XX; On entry es:[di] points at the data port
XX;          es:[si] points at the command port
XX;
XXsend_data	proc	near
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		mov	al,STREQ
XX		cld
XX
XXsend_loop:	movsb
XX		dec	di			;Don't blow the card buffer
XX		dec	cx
XX		jz	send_exit
XXsend_wait:	test	byte ptr es:[bx],al	;Ready?
XX		jnz	send_loop
XX		jmp	short send_wait
XX
XXsend_exit:	mov	si,SCSI_CMD_PORT	;Restore the Environment
XX		mov	di,SCSI_DATA_PORT
XX		mov	ax,cs
XX		mov	ds,ax
XX		ret
XXsend_data	endp
XX
XX;
XX; Send a NOP Message
XX;
XXsend_nop	proc	near
XX		mov	al,MSG_NOP		;Oops, send a nop
XX		mov	es:[di],al
XX		mov	al,CMDBASE or CMDENABLE
XX		mov	es:[si],al
XX		ret
XXsend_nop	endp
XX
XX;
XX; Wait One Milli second
XX;
XX; The value of 'cx' is computed for an 8 Mhz Clock
XX;
XXwait1ms		proc	near
XX		push	cx		;   (3) = 375ns
XX		mov	cx,798		;   (2) = 250ns
XXwait_m_loop:	loop	wait_m_loop	;  (10) = 1250ns * X
XX		pop	cx		;   (5) = 625ns
XX		ret			; (11+) = 1375ns
XXwait1ms		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,78		;   (2) = 250ns
XXwait_u_loop:	loop	wait_u_loop	;  (10) = 1250ns * X
XX		pop	cx		;   (5) = 625ns
XX		ret			; (11+) = 1375ns
XXwait100us	endp
SHAR_EOF
if test 11083 -ne "`wc -c < 'subs.asm'`"
then
echo shar: error transmitting "'subs.asm'" '(should have been 11083 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'units.asm'" '(3252 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		even
XXunit7		db	size unit dup (-1)
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		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
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		dw	unit7
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		dw	bpb8
XX		dw	bpb9
XX		dw	bpbA
XX		dw	bpbB
XX		dw	bpbC
XX		dw	bpbD
XX		dw	bpbE
XX		dw	bpbF
XXbpb_hw_mark	dw	bpb_array
XX
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		inc	dh			;Bump Drive Number
XX		dec	al			;Dec Drive count
XX		jnz	find_unit_loop		;Try next Drive
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		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	ah,[bx].unit_cap_buf.cap_sectors_b3
XX		mov	al,[bx].unit_cap_buf.cap_sectors_b2
XX		or	ax,ax
XX		jz	make_bpb_last		;Use up the last few sectors
XX		dec	ax			;Use up 65536 Sectors
XX		mov	[bx].unit_cap_buf.cap_sectors_b3,ah
XX		mov	[bx].unit_cap_buf.cap_sectors_b2,al
XX		mov	dx,65535		;Max of 32 Meg
XX		jmp	short make_bpb_ts
XXmake_bpb_last:	mov	dh,[bx].unit_cap_buf.cap_sectors_b1
XX		mov	[bx].unit_cap_buf.cap_sectors_b1,0
XX		mov	dl,0			;Round to nearest Cyl
XX		mov	[bx].unit_cap_buf.cap_sectors_b0,0
XX		dec	dx			;Make it zero relative
XXmake_bpb_ts:	mov	[di].bpb_ts,dx
XX		mov	[di].bpb_md,0F8h
XX		shr	dx,SECT_2_FS
XX		inc	dx			;Allow for round-off
XX		mov	[di].bpb_fs,dx
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		ret
XXmake_bpb	endp
SHAR_EOF
if test 3252 -ne "`wc -c < 'units.asm'`"
then
echo shar: error transmitting "'units.asm'" '(should have been 3252 characters)'
fi
fi # end of overwriting check
#
# End of shell archive
#
exit 0