v15i002: DOS Device Driver for the ST-01 (Part 1 of 2)

Brian Who? briana at tau-ceti.isc-br.com
Sat Oct 6 10:02:43 AEST 1990


Posting-number: Volume 15, Issue 2
Submitted-by: briana at tau-ceti.isc-br.com (Brian Who?)
Archive-name: st-01_scsi/part01

     The following is a DOS Device Driver using the Seagate ST-01 interface
card.  It does not use the prom that comes with the card, and in fact the
prom is not even installed.  It supports up to 7 SCSI devices one of which
can be a tape drive.  Included is a low level SCSI formater for disks and
a control program for the tape drive.

Submitted-by: briana at tau-ceti.isc-br.com
Archive-name: ST01SCSI.12/part01

#!/bin/sh
# This is ST01SCSI.12, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 09/25/1990 02:47 UTC by briana at tau-ceti.isc-br.com
# Source directory /u/briana/scsi/scsi-1.2
#
# existing files will NOT be overwritten unless -c is specified
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    497 -rw-r--r-- binmode.c
#   1296 -rw-r--r-- dump.asm
#   3921 -rw-r--r-- equ.inc
#   3256 -rw-r--r-- ioctl.asm
#   2417 -rw-r--r-- kludge.asm
#    506 -rw-r--r-- makefile
#   2744 -rw-r--r-- mt.c
#   1165 -rw-r--r-- options.inc
#   2706 -rw-r--r-- readme.10
#   2983 -rw-r--r-- readme.11
#   1210 -rw-r--r-- readme.12
#  11458 -rw-r--r-- scsi.asm
#   2518 -rw-r--r-- scsi.sys
#   1931 -rw-r--r-- sformat.c
#   7166 -rw-r--r-- struct.inc
#  15830 -rw-r--r-- subs.asm
#   3322 -rw-r--r-- units.asm
#
# ============= binmode.c ==============
if test -f 'binmode.c' -a X"$1" != X"-c"; then
	echo 'x - skipping binmode.c (File already exists)'
else
echo 'x - extracting binmode.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'binmode.c' &&
X#ifdef MSDOS
X#include <dos.h>
X
Xbinmode(fd)
Xint fd;
X{
X	union REGS inregs, outregs;
X
X	/*
X	** get the current mode
X	*/
X	inregs.h.ah = 0x44;			/* ioctl */
X	inregs.h.al = 0x00;			/* get */
X	inregs.x.bx = fd;			/* unit */
X	intdos(&inregs, &outregs);
X
X	/*
X	** set to BINARY mode (this works for char devices)
X	*/
X	inregs.h.ah = 0x44;			/* ioctl */
X	inregs.h.al = 0x01;			/* set */
X	inregs.x.bx = fd;			/* unit */
X	inregs.h.dh = 0;
X	inregs.h.dl = outregs.h.dl | 0x20;
X	intdos(&inregs, &outregs);
X}
X#endif
SHAR_EOF
chmod 0644 binmode.c ||
echo 'restore of binmode.c failed'
Wc_c="`wc -c < 'binmode.c'`"
test 497 -eq "$Wc_c" ||
	echo 'binmode.c: original size 497, current size' "$Wc_c"
fi
# ============= dump.asm ==============
if test -f 'dump.asm' -a X"$1" != X"-c"; then
	echo 'x - skipping dump.asm (File already exists)'
else
echo 'x - extracting dump.asm (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'dump.asm' &&
X;
X; Convert bin (ax) to ascii (bx => buffer)
X;
Xbin_ascii	proc	near
X		pusha
X		push	ax
X		mov	cx,6
Xfill_buff:	mov	byte ptr [bx],' '
X		inc	bx
X		loop	fill_buff
X		mov	si,10
X		or	ax,ax
X		jns	clr_dvd
X		neg	ax
Xclr_dvd:	sub	dx,dx
X		div	si
X		add	dx,'0'
X		dec	bx
X		mov	[bx],dl
X		inc	cx
X		or	ax,ax
X		jnz	clr_dvd
X		pop	ax
X		or	ax,ax
X		jns	no_more
X		dec	bx
X		mov	byte ptr [bx],'-'
Xno_more:	popa
X		ret
Xbin_ascii	endp
X
X;
X; Convert Hex (dx) to Ascii (bx => buffer)
X;
Xhex2asc4	proc	near
X		push	cx
X		push	ax
X		mov	cx,4		;Do Four Digits
Xh241:		rol	dx,4
X		mov	al,dl		;Get the Current Digit
X		and	al,0Fh
X		cmp	al,0Ah		;Is It Hex?
X		jge	h242
X		add	al,30h		;Normal Digit
X		jmp	h243
Xh242:		add	al,37h		;Hex Digit
Xh243:		mov	[bx],al		;Insert in Buffer
X		inc	bx
X		loop	h241
X		pop	ax
X		pop	cx
X		ret
Xhex2asc4	endp
X
X;
X; Convert Hex (dl) to Ascii (bx => buffer)
X;
Xhex2asc2	proc	near
X		push	cx
X		push	ax
X		mov	cx,2		;Do Two Digits
Xh221:		rol	dl,4
X		mov	al,dl		;Get the Current Digit
X		and	al,0Fh
X		cmp	al,0Ah		;Is It Hex?
X		jge	h222
X		add	al,30h		;Normal Digit
X		jmp	h223
Xh222:		add	al,37h		;Hex Digit
Xh223:		mov	[bx],al		;Insert in Buffer
X		inc	bx
X		loop	h221
X		pop	ax
X		pop	cx
X		ret
Xhex2asc2	endp
X
X;
X; Print a string
X;
X; ds:dx => string
X;
Xputs		proc	near
X		pusha
X		mov	ah,9		;DOS print string
X		int	21h
X		popa
X		ret
Xputs		endp
SHAR_EOF
chmod 0644 dump.asm ||
echo 'restore of dump.asm failed'
Wc_c="`wc -c < 'dump.asm'`"
test 1296 -eq "$Wc_c" ||
	echo 'dump.asm: original size 1296, current size' "$Wc_c"
fi
# ============= equ.inc ==============
if test -f 'equ.inc' -a X"$1" != X"-c"; then
	echo 'x - skipping equ.inc (File already exists)'
else
echo 'x - extracting equ.inc (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'equ.inc' &&
X;
X; Equates
X;
XTRUE		EQU	001h
XFALSE		EQU	000h
X
XDISK_REQUEST	EQU	000h		;Disk I/O Request
XTAPE_REQUEST	EQU	001h		;Tape I/O Request
X
X;
X; ST-01 Card Registers
X;
XSCSI_CARD_SEG	EQU	0DE00h		;Base Segment of Card
XSCSI_CMD_PORT	EQU	01A00h		;Offset to Command Port
XSCSI_DATA_PORT	EQU	01C00h		;Offset to Data Port
X
XSTACK_SIZE	EQU	512		;Our Local Stack
X
X;
X; How the 16 bit sector number is broken down
X; into a sector and cylinder number.
X;
X; x = Cylinder, y = track, always have only 1 head
X;
X; xxxx xxxx xxxx yyyy
X;
X; SECT_2_FS is computed as: ((unit_bpb.bpb_ts / CLUSTSIZE) * 2) / P_SECT)
X;
XSECT_TRACK	EQU	16		;Logical Sectors in a Track
XSECT_MASK	EQU	0000Fh		;Mask for Sector
XCYL_MASK	EQU	0FFF0h		;Mask for Cylinder
XSECT_2_CYL	EQU	4		;How far to shift to convert
X					;Sector to Cylinder Number
XSECT_2_FS	EQU	10		;How far to shift for
X					;Total Sectors to Fat Sectors
X
X;
X; The max target to check for (0-X).
X; If using 'reserve_addr', this should not execede 6!
X;
XMAXUNIT		EQU	6		;Maximum Unit Number
X
XP_SECT		EQU	512		;Physical Sector Size
XCLUSTSIZE	EQU	4		;Number of Sectors to a Cluster
X
X;
X; For multi_sector reads and writes,
X; set the following to '1'
X;
X; CHUNK_MASK is the maximum number of sectors to access in one
X; SCSI request.  It MUST be a power of two, and CHUNK_MASK * P_SECT
X; MUST be <= 64K to prevent segment wrap problems.
X;
XCHUNK_MAX	EQU	32
X
XCMDENABLE	EQU	080h		;Enable the output drivers
XCMDENINTR	EQU	040h		;Enable Interrupt
XCMDPARITY	EQU	020h		;Enable Parity
XCMDSTARB	EQU	010h		;Start Bus Arbitration
XCMDATTN		EQU	008h		;Assert ATTN
XCMDBSY		EQU	004h		;Assert BSY
XCMDSEL		EQU	002h		;Assert SEL
XCMDRST		EQU	001h		;Assert RST
X
X		if scsi_parity
XCMDBASE		EQU	CMDPARITY	;Base value of all commands
X		else
XCMDBASE		EQU	000h		;Base value of all commands
X		endif
X
XSTARBCOMPL	EQU	080h		;Arbitration Complete
XSTPARERR	EQU	040h		;Parity Error
XSTSEL		EQU	020h		;SEL Asserted
XSTREQ		EQU	010h		;REQ Asserted
XSTCD		EQU	008h		;C/D Asserted
XSTIO		EQU	004h		;I/O Asserted
XSTMSG		EQU	002h		;MSG Asserted
XSTBSY		EQU	001h		;BSY Asserted
X
XFREE_MASK	EQU	03Fh
X
XREQ_MASK	EQU	STMSG or STCD or STIO
XREQ_DATAOUT	EQU	000h		;Data Out Phase
XREQ_DATAIN	EQU	STIO		;Data In Phase
XREQ_CMDOUT	EQU	STCD		;Command Out Phase
XREQ_STATIN	EQU	STCD or STIO	;Status In Phase
XREQ_MSGOUT	EQU	STMSG or STCD	;Msg Out Phase
XREQ_MSGIN	EQU	STMSG or STCD or STIO	;Msg In Phase
X
XCOK		EQU	0		;Command Completed OK
XCNOCONNECT	EQU	1		;Unable to Connect to Target
XCBUSBUSY	EQU	2		;Bus Busy
XCTIMEOUT	EQU	3		;Timeout waiting for Response
XCERROR		EQU	4		;Target Return Error
XCBUSY		EQU	5		;Target was Busy
XCDISCONNECT	EQU	6		;Target Disconnected
X
XSCSI_TESTREADY	EQU	000h		;Test Unit Ready (6 byte)
XSCSI_REWIND	EQU	001h		;Rewind (6 byte)
XSCSI_REQSENSE	EQU	003h		;Request Sense (6 byte)
XSCSI_FORMATUNIT	EQU	004h		;Format Disk (6 byte)
XSCSI_WRITEFM	EQU	010h		;Write File Marks (6 byte)
XSCSI_SPACE	EQU	011h		;Space Tape (6 byte)
XSCSI_INQUIRY	EQU	012h		;Inquire (6 byte)
XSCSI_MODE_SET	EQU	015h		;Mode Select (6 byte)
XSCSI_ERASE	EQU	019h		;Erase Tape (6 byte)
XSCSI_MODE_GET	EQU	01Ah		;Mode Sense (6 byte)
XSCSI_LOAD	EQU	01Bh		;Load / Unload Tape (6 byte)
XSCSI_READSIZE	EQU	025h		;Read Drive Capacity (10 byte)
X		if extended_io
XSCSI_READBLK	EQU	028h		;Read Sectors (10 byte)
XSCSI_WRITEBLK	EQU	02Ah		;Write Sectors (10 byte)
X		else
XSCSI_READBLK	EQU	008h		;Read Sectors (6 byte)
XSCSI_WRITEBLK	EQU	00Ah		;Write Sectors (6 byte)
X		endif
XSCSI_VERIFYBLK	EQU	02Fh		;Verify Blocks (10 byte)
X
XMSG_COMPLETE	EQU	000h		;Command is Complete
XMSG_SAVE	EQU	002h		;Save Data Pointers
XMSG_RESTORE	EQU	003h		;Restore Data Pointers
XMSG_ERROR	EQU	005h		;Error Detected
XMSG_ABORT	EQU	006h		;Abort the Command
XMSG_REJECT	EQU	007h		;Reject the Command
XMSG_NOP		EQU	008h		;No Operation
XMSG_IDENTIFY	EQU	080h		;Identify Yourself
X
XLOAD_TAPE	EQU	001h		;Load
XUNLOAD_TAPE	EQU	000h		;Unload
X
X;
X; We write one filemark at the end of a tape
X; so that we can space forward over stuff.
X;
XCLOSE_FM_CNT	EQU	001h
SHAR_EOF
chmod 0644 equ.inc ||
echo 'restore of equ.inc failed'
Wc_c="`wc -c < 'equ.inc'`"
test 3921 -eq "$Wc_c" ||
	echo 'equ.inc: original size 3921, current size' "$Wc_c"
fi
# ============= ioctl.asm ==============
if test -f 'ioctl.asm' -a X"$1" != X"-c"; then
	echo 'x - skipping ioctl.asm (File already exists)'
else
echo 'x - extracting ioctl.asm (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'ioctl.asm' &&
X;
X; Process an ioctl request for the current unit
X;
X; return 'C' on error
X;
Xscsi_ioctl	proc
X		mov	al,es:[bx].rh19_minor		;Get the minor number
X
X		cmp	al,40h				;Set Device Params?
X		jnz	scsi_i_42h
X		clc
X		jmp	short scsi_i_exit
X
Xscsi_i_42h:	cmp	al,42h				;Format and Verify?
X		jnz	scsi_i_60h
X		call	scsi_verify
X		jmp	short scsi_i_exit
X
Xscsi_i_60h:	cmp	al,60h				;Get Device Params?
X		jnz	scsi_i_62h
X		mov	si,cur_bpb			;Get the Current BPB
X		mov	di,es:[bx].rh19_buf_ofs		;Get the Param Buffer
X		mov	ax,es:[bx].rh19_buf_seg
X		mov	es,ax
X		mov	es:[di].dpb_special,05h		;Sect Same/Use Cur BPB
X		mov	es:[di].dpb_type,05h		;Fixed Disk
X		mov	es:[di].dpb_attr,0001h		;Not Removable
X		mov	ax,[si].bpb_ts
X		shr	ax,SECT_2_CYL			;Convert Sect to Cyl
X		mov	es:[di].dpb_cyl,ax
X		mov	es:[di].dpb_media,0		;????
X		mov	es:[di].dpb_sectors,SECT_TRACK	;Sectors per Track
X
X		push	di
X		lea	di,es:[di].dpb_bpb		;Copy the bpb into
X		mov	cx,size bpb			;the requestors buffer
X		cld
X	rep	movsb
X		pop	di
X
X		lea	di,es:[di].dpb_track		;Build the Track List
X		mov	cx,SECT_TRACK
X		mov	ax,0				;Start with Sector 0
Xscsi_i_t_loop:	mov	es:[di],ax			;Sector Number
X		inc	ax
X		inc	di
X		inc	di
X		mov	word ptr es:[di],P_SECT		;Sector Size
X		inc	di
X		inc	di
X		loop	scsi_i_t_loop
X		clc
X		jmp	short scsi_i_exit
X
Xscsi_i_62h:	cmp	al,62h				;Verify?
X		jnz	scsi_i_error
X		call	scsi_verify
X		jmp	short scsi_i_exit
X
Xscsi_i_error:	stc
Xscsi_i_exit:	ret
Xscsi_ioctl	endp
X
X;
X; Process an ioctl_write request
X;
Xscsi_ioctl_write proc
X		mov	di,es:[bx].rh12_buf_ofs		;Get The Command
X		mov	ax,es:[bx].rh12_buf_seg		;Buffer
X		mov	es,ax
X		mov	ax,es:[di].ioc_command		;What Command
X
X;
X; Format Disk Unit
X;
X		cmp	al,'F'				;Format?
X		jnz	try_erase
X		mov	ax,es:[di].ioc_param1		;Get Interleave
X		lea	di,cmd_format			;Insert into Command
X		mov	[di].fmt_cmd_il_b1,ah
X		mov	[di].fmt_cmd_il_b0,al
X		call	docmd
X		jnc	format_exit
X		call	scsi_sense
Xformat_exit:	jmp	scsi_i_w_exit
X
X;
X; Erase Tape Unit
X;
Xtry_erase:	cmp	al,'E'				;Erase?
X		jnz	try_rewind
X		lea	di,cmd_erase			;Now Erase Tape
X		call	docmd
X		jnc	scsi_i_w_exit
X		call	scsi_sense
X		jmp	scsi_i_w_error
X
X;
X; Rewind Tape Unit
X;
Xtry_rewind:	cmp	al,'R'				;Rewind?
X		jnz	try_load
X		lea	di,cmd_rewind			;Now Rewind Tape
X		call	docmd
X		jnc	scsi_i_w_exit
X		call	scsi_sense
X		jmp	scsi_i_w_error
X
X;
X; Load Tape on Open
X;
Xtry_load:	cmp	al,'L'				;Load?
X		jnz	try_noload
X		mov	load_flag,TRUE
X		jmp	scsi_i_w_exit
X
X;
X; No Load Tape on Open
X;
Xtry_noload:	cmp	al,'N'				;No Load?
X		jnz	try_space
X		mov	load_flag,FALSE
X		jmp	scsi_i_w_exit
X
X;
X; Space Tape
X;
Xtry_space:	cmp	al,'S'				;Space?
X		jnz	try_filemark
X		mov	ax,es:[di].ioc_param1		;Get Count
X		mov	bx,es:[di].ioc_param2		;Get Type
X		lea	di,cmd_space			;Insert into Command
X		mov	[di].space_cmd_code,bl
X		mov	[di].space_cmd_cnt2,ah		;Dup of ah
X		mov	[di].space_cmd_cnt1,ah
X		mov	[di].space_cmd_cnt0,al
X		call	docmd
X		jnc	scsi_i_w_exit
X		call	scsi_sense
X		jmp	scsi_i_w_exit
X
X;
X; Write Filemarks
X;
Xtry_filemark:	cmp	al,'M'				;Mark?
X		jnz	scsi_i_w_error
X		mov	ax,es:[di].ioc_param1		;Get Count
X		lea	di,cmd_twritefm			;Insert into Command
X		mov	[di].fm_cmd_cnt_b1,ah
X		mov	[di].fm_cmd_cnt_b0,al
X		call	docmd
X		jnc	scsi_i_w_exit
X		call	scsi_sense
X		jmp	scsi_i_w_exit
X
Xscsi_i_w_error:	stc
Xscsi_i_w_exit:	ret
Xscsi_ioctl_write endp
SHAR_EOF
chmod 0644 ioctl.asm ||
echo 'restore of ioctl.asm failed'
Wc_c="`wc -c < 'ioctl.asm'`"
test 3256 -eq "$Wc_c" ||
	echo 'ioctl.asm: original size 3256, current size' "$Wc_c"
fi
# ============= kludge.asm ==============
if test -f 'kludge.asm' -a X"$1" != X"-c"; then
	echo 'x - skipping kludge.asm (File already exists)'
else
echo 'x - extracting kludge.asm (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'kludge.asm' &&
X;
X; This code is needed because DOS insists on opening a char device
X; in cooked mode.  The problem is that without adding code to every
X; application that would ever use us, we have no way to alter this
X; because the use of O_BINARY or setmode() do not affect char devices.
X;
X; The solution (kludge) is to watch open requests issued thru the
X; INT 21 vector.  If we see a open request followed by a OPEN_DEV
X; call to us, it must have been an open for us.  So during the return,
X; force a call to the ioctl facility that will switch to raw mode.
X;
X
X;
X; The Original INT 21 Vector
X;
Xvect_int_21	equ	word ptr 4 * 21h
Xorig_int_21	dd	?			;Original INT 21 Vector
X
X;
X; OPEN_DEV flag is TRUE when we are opened
X;
Xopened_flag	db	FALSE
X
Xpatch_us_in	proc	near
X		push	es
X		push	ax
X		mov	ax,0			;Patch Ourselves into
X		mov	es,ax			;the INT 21 Vector
X		mov	ax,es:[vect_int_21]	;Offset
X		mov	word ptr orig_int_21,ax
X		lea	ax,our_int_21
X		mov	es:[vect_int_21],ax
X		mov	ax,es:[vect_int_21+2]	;Segment
X		mov	word ptr orig_int_21+2,ax
X		mov	ax,cs
X		mov	es:[vect_int_21+2],ax
X		pop	ax
X		pop	es
X		ret
Xpatch_us_in	endp
X
Xour_int_21	proc	far
X		pushf				;Save entry flags
X		cmp	ah,3Dh			;Is it an open request?
X		jnz	not_open_req
X		popf				;Restore entry flags
X;
X; We need to set things up so the 'iret' done by the INT 21
X; code will have some the right stuff on the stack.
X; #1 Flags with interrupts enabled
X; #2 Return Address
X;
X		sti				;Allow interrupts
X		pushf				;After the iret
X		cli				;Shut interrupts off
X		call	cs:orig_int_21		;While we Pass the request on
X;
X; Upon return, interrupts are enabled, so shut them off while we work
X;
X		pushf
X		cli
X		cmp	cs:opened_flag,FALSE	;Was it an open for us?
X		jz	not_our_open
X		mov	cs:opened_flag,FALSE	;Clear for next time
X;
X; We need to forge a call to the ioctl interface
X; to switch DOS to raw mode when it talks to us
X;
X		pusha
X		mov	bx,ax			;Save the Handle
X		mov	ax,4400h		;Get Device Information
X		pushf
X		call	cs:orig_int_21
X		mov	dh,0			;Setup
X		or	dl,20h			;for RAW Mode
X		mov	ax,4401h		;Set Device Information
X		pushf
X		call	cs:orig_int_21
X		popa
X
Xnot_our_open:	popf				;The Original Flags to return
X;
X; When we return, we need to pop the flags that the original INT 21
X; call left on the stack, and return the flags we got back
X;
X		ret	2			;Return and discard flags
X
Xnot_open_req:	popf				;Pop the saved flags
X		jmp	cs:orig_int_21		;Continue with original code
Xour_int_21	endp
SHAR_EOF
chmod 0644 kludge.asm ||
echo 'restore of kludge.asm failed'
Wc_c="`wc -c < 'kludge.asm'`"
test 2417 -eq "$Wc_c" ||
	echo 'kludge.asm: original size 2417, current size' "$Wc_c"
fi
# ============= makefile ==============
if test -f 'makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping makefile (File already exists)'
else
echo 'x - extracting makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'makefile' &&
X#
X# SCSI Stuff
X#
XSRCS = scsi.asm subs.asm ioctl.asm dump.asm units.asm kludge.asm \
X       options.inc equ.inc struct.inc
X
Xall: scsi.sys sformat.exe mt.exe
X
X#
X# SCSI Disk Device Driver
X#
Xscsi.sys: scsi.obj
X	link +scsi.obj, scsi ;
X	exe2bin scsi.exe scsi.sys
X
Xscsi.obj: $(SRCS)
X	masm scsi.asm scsi.obj scsi.lst ;
X
X#
X# SCSI Disk Formatter
X#
Xsformat.exe: sformat.c
X	cl -G2 -Ox -o sformat.exe sformat.c
X
X#
X# SCSI Tape Erase
X#
Xmt.exe: mt.c
X	cl -G2 -Ox -o mt.exe mt.c
X
X#
X# clean
X#
Xclean:
X	rm -f *.exe *.obj *.lst
SHAR_EOF
chmod 0644 makefile ||
echo 'restore of makefile failed'
Wc_c="`wc -c < 'makefile'`"
test 506 -eq "$Wc_c" ||
	echo 'makefile: original size 506, current size' "$Wc_c"
fi
# ============= mt.c ==============
if test -f 'mt.c' -a X"$1" != X"-c"; then
	echo 'x - skipping mt.c (File already exists)'
else
echo 'x - extracting mt.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'mt.c' &&
X/*
X** SCSI Tape Control (Low Level)
X**
X** usage: mt [-e|r|l|n|s count|m count]
X**
X** Revision History:
X**
X** Version 1.0  09/09/90 Initial Release
X**
X*/
X#include <stdio.h>
X#include <fcntl.h>
X#include <dos.h>
X
X#define TRUE (1)
X#define FALSE (0)
X#define VERSION "mt Version 1.0 BWA"
X
Xextern int _doserrno;
X
Xstruct cmd {
X	short command;		/* command type */
X	short arg1;			/* command args */
X	short arg2;			/* command args */
X} ioctl_data;
Xunion REGS inregs, outregs;
Xstruct SREGS segregs;
Xint fd;
Xchar *device = "SCSITAPE", *operation = NULL;
Xchar far *cp;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	/*
X	** say hello
X	*/
X	puts(VERSION);
X	switch ( argc )
X	{
X		case 3:
X		if (argv[1][0] != '-' || argv[1][2] != 0) usage();
X		switch( argv[1][1] )
X		{
X			case 's':
X			ioctl_data.command = 'S';
X			ioctl_data.arg1 = atoi(argv[2]);
X			ioctl_data.arg2 = 1;		/* space by filemark */
X			if (ioctl_data.arg1 > 0)
X				operation = "space forward";
X			else if (ioctl_data.arg1 < 0)
X				operation = "space backward";
X			else
X			{
X				operation = "space EOD";
X				ioctl_data.arg2 = 3;	/* space to EOD */
X			}
X			break;
X
X			case 'm':
X			ioctl_data.command = 'M';
X			ioctl_data.arg1 = atoi(argv[2]);
X			operation = "filemark";
X			break;
X
X			default:
X			usage();
X			break;
X		}
X		break;
X
X		case 2:
X		if (argv[1][0] != '-' || argv[1][2] != 0) usage();
X		switch( argv[1][1] )
X		{
X			case 'e':
X			/*
X			** verify that this is what the user really wants to do
X			*/
X			printf("Do you really wish to erase the tape\n");
X			printf("contained in the SCSITAPE unit (y,n)? ");
X			fflush(stdout);
X			if ( getchar() != 'y' )
X			{
X				printf("Aborting ....\n");
X				exit(1);
X			}
X			operation = "erase";
X			ioctl_data.command = 'E';
X			break;
X
X			case 'r':
X			operation = "rewind";
X			ioctl_data.command = 'R';
X			break;
X
X			case 'l':
X			operation = "load enable";
X			ioctl_data.command = 'L';
X			break;
X
X			case 'n':
X			operation = "load disable";
X			ioctl_data.command = 'N';
X			break;
X
X			default:
X			usage();
X			break;
X		}
X		break;
X
X		default:
X		usage();
X		break;
X	}
X
X	/*
X	** put together the command
X	*/
X	fd = open(device, O_WRONLY);
X	if ( fd < 0 )
X	{
X		perror(device);
X		exit(1);
X	}
X	inregs.h.ah = 0x44;			/* ioctl */
X	inregs.h.al = 0x03;			/* write */
X	inregs.x.bx = fd;			/* unit */
X	inregs.x.cx = sizeof(struct cmd);
X	cp = (char *) &ioctl_data;
X	inregs.x.dx = FP_OFF(cp);
X	segregs.ds = FP_SEG(cp);
X
X	/*
X	** start the format
X	*/
X	printf("Now performing %s command ....\n", operation);
X	puts("Please wait ....");
X	intdosx(&inregs, &outregs, &segregs);
X
X	/*
X	** see what happened
X	*/
X	if ( outregs.x.cflag )
X		printf("DOS error %d occured during %s.\n", _doserrno, operation);
X	close(fd);
X	exit(0);
X}
X
Xusage()
X{
X	puts("usage: mt [-e|r|l|n|s count|m count]");
X	exit(1);
X}
SHAR_EOF
chmod 0644 mt.c ||
echo 'restore of mt.c failed'
Wc_c="`wc -c < 'mt.c'`"
test 2744 -eq "$Wc_c" ||
	echo 'mt.c: original size 2744, current size' "$Wc_c"
fi
# ============= options.inc ==============
if test -f 'options.inc' -a X"$1" != X"-c"; then
	echo 'x - skipping options.inc (File already exists)'
else
echo 'x - extracting options.inc (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'options.inc' &&
X;
X; Allow multi_sector reads and writes.
X;
X; This means that a read request of less then CHUNK_MAX
X; sectors will be done in one request to the drive rather
X; then multiple single sector requests.
X;
X; The disadvantage here is that the code in receive_data()
X; and send_data() must keep the transfer from exceding the
X; 512 byte buffer on the ST-01 card.
X;
Xmulti_sector	=	1	;Enable multi_sector support
X
X;
X; Use the extended SCSI commands for reads and writes.
X;
X; This means that we can access drives larger then 1Gb
X; and read/write more then 256 sectors per command.
X;
X; The disadvantage here is that not all devices support
X; the extended command set.
X;
Xextended_io	=	0	;Disable use of extended io commands
X
X;
X; Use parity on the SCSI bus
X;
Xscsi_parity	=	1	;Enable use of parity on the SCSI bus
X
X;
X; Reserve SCSI Address 7 for card
X;
Xreserve_addr	=	1	;Reserve Address for Card Use
X
X;
X; Dump Sense information to the screen
X;
Xdump_sense	=	1	;Dump Sense Message to the Screen
X
X;
X; Extended Sense or Normal Sense
X;
Xextended_sense	=	1	;Request Extended Sense
X
X;
X; Include the code to kludge the RAW ioctl call after an open
X;
Xuse_kludge	=	1	;Enable the ioctl kludge
SHAR_EOF
chmod 0644 options.inc ||
echo 'restore of options.inc failed'
Wc_c="`wc -c < 'options.inc'`"
test 1165 -eq "$Wc_c" ||
	echo 'options.inc: original size 1165, current size' "$Wc_c"
fi
# ============= readme.10 ==============
if test -f 'readme.10' -a X"$1" != X"-c"; then
	echo 'x - skipping readme.10 (File already exists)'
else
echo 'x - extracting readme.10 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'readme.10' &&
XScsi Version 1.0
X
X     The code you received with this file is a very simple SCSI device
Xdriver that uses the Seagate ST-01 interface card.  As this driver is
Xmy first PC assembler project other then "hello world", please don't
Xsnicker to loudly.
X
X     The package includes the source for a device driver that will scan
Xthe SCSI bus for disk drives and partition any drives found into chunks
Xof 32Meg plus any leftovers.  As soon as I discover a way to get DOS to
Xlet me use > 512 byte sectors, It will just allocate the entire disk to
Xa single logical drive.  It also includes a utility to access the low
Xlevel SCSI format function for any disk found.  You may specify the
Xinterleave when the low level format is done and the version of the
Xdriver here seems to work fine at 1:1 with my 8Mhz NEC.
X
X     Some of the things to look out for are:
X
X#1 The receive_data and send_data functions in subs.asm use polled I/O
X   to transfer data to/from the card.  I would have loved to just use
X   the I/O Channel Ready line that the card is suppose to support, but
X   my NEC does not seem to use that line.  Hence the polling of the REQ
X   bit in the status port.
X
X#2 I did not know how to do clock speed independent timing loops, so there
X   is a wait100us function in subs.asm that is very processor speed
X   dependent :-(
X
X#3 In ioctl.asm there is a commented out call to scsi_verify.  This is
X   used by the DOS format utility to scan for errors.  You may want to
X   enable the call after you get everything setup.  I shut it off while
X   I was testing as I didn't want to wait for the verify everytime I
X   changed the interleave.
X
X     To bring up the driver.  Assemble and link scsi.sys and add it to
Xyour config.sys file.  After rebooting, you may optionaly do a low level
Xformat of each disk found using sformat.exe.  You then use the DOS format
Xutility on each logical drive.  I did figure out just what format needed
Xin the way of ioctl support to get it to do the high level format for me.
XAt this point you should have fully functional DOS drives.  In testing
XI found that with multi_sector support (subs.asm) enabled, the SCSI drives
Xwere just about as fast as the ST-412 C: that came with the machine.  I
Xam sure that the speed problem is basic to the inner loop of the data
Xtransfer routines, but I'm at a loss to figure out how to speed it up.
X
X     Anyway, maybe someone can find some use for the code.  I got the
Xcard for free, so I can't really complain about the speed or cost too
Xmuch :-)
X
X     Also thanks to the people that sent me samples of other device drivers
Xfor the PC.  I lost the names to a disk crash, but here is the result of
Xyour help and my thanks.
X
XBrian Antoine
XAug 29, 1990
SHAR_EOF
chmod 0644 readme.10 ||
echo 'restore of readme.10 failed'
Wc_c="`wc -c < 'readme.10'`"
test 2706 -eq "$Wc_c" ||
	echo 'readme.10: original size 2706, current size' "$Wc_c"
fi
# ============= readme.11 ==============
if test -f 'readme.11' -a X"$1" != X"-c"; then
	echo 'x - skipping readme.11 (File already exists)'
else
echo 'x - extracting readme.11 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'readme.11' &&
XScsi Version 1.1
X
X     This version of the driver add support for a single tape drive, and
Xcleans up some of the code a little.  It also adds a file that has equates
Xto customize some of the major areas of the driver.
X
X     When the driver is initialized it does a scan of the SCSI bus for
Xdevices.  The FIRST tape device found is assigned to a char device with the
Xname "SCSITAPE".  If no tape drive is found, the char device is still valid
Xbut will generate a "bad unit" error when accessed.
X
X     The SCSITAPE device expects reads and writes to be done in some variation
Xof 512 bytes.  I/O done where (size mod 512) is non-zero will generate an
Xerror.  Tape access must be done in RAW mode, and this is where I had to
Xsome code in the driver that I'm not sure is very pretty.  The problem is
Xthat DOS insists on opening char devices in cooked mode.  It does give you
Xthe ability to switch to RAW mode, but only by using 'intdos()' to access
Xthe ioctl interface.  The MSC 'setmode()' call for binary will not effect
Xchar devices, nor will opening the file with O_BINARY.  So I had two choices.
XI could modify every program that expected to talk to the tape so that it
Xalso issued the ioctl stuff (see binmode.c), or I could kludge the driver
Xto issue the required calls.
X
X     In the end, I punted and did both.  The code in binmode.c is the function
Xthat along with 'setmode()', will make sure that ANYTHING you open is accessed
Xin RAW mode.  Simply check for any call to 'setmode()' that is switching to
XO_BINARY, and add another call to 'binmode()'.  This assumes that you have
Xthe source to the utility in question.  For those who are don't mind a little
Xkludge amount friends.  The file options.inc has an equate called 'use_kludge'
Xthat when enabled turns on some code in kludge.asm.  This code links into the
XINT 21h vector and waits for a DOS open request to go by.  When it sees an
Xopen request, it 'calls' rather then 'jmps' to the normal vector.  This allows
Xthe driver to get the 'handle' returned by DOS.  Because the SCSITAPE device
Xenables the driver_open function, I can tell from the fact that an open is
Xin progress and wether the driver just got an open request, wether any
Xparticular open was for me.  When the open was in fact for the SCSITAPE device,
XI take the 'handle' returned by DOS and forge the required ioctl calls to
Xswitch to RAW mode.
X
X     With the addition of tape support.  I now use GNU Tar to swap tapes with
Xmy normal UN*X system at work.  The driver works well enough that I have yet
Xto have a format problem with the different systems.  It is also a lot faster
Xwhen doing backups on the PC.  Using 'fastback' I would get about 1 Meg a
Xminute thruput on my 8 Mhz AT.  Using GNU Tar and the SCSITAPE device I get
X> 2.5 Meg a minute to the tape and don't have to swap disks quite so often :-)
X
X     Anyway, I hope that someone out there actually gets some use out of this
Xcode.  It has been a real adventure for me.
X
XBrian Antoine
XSept 8, 1990
SHAR_EOF
chmod 0644 readme.11 ||
echo 'restore of readme.11 failed'
Wc_c="`wc -c < 'readme.11'`"
test 2983 -eq "$Wc_c" ||
	echo 'readme.11: original size 2983, current size' "$Wc_c"
fi
# ============= readme.12 ==============
if test -f 'readme.12' -a X"$1" != X"-c"; then
	echo 'x - skipping readme.12 (File already exists)'
else
echo 'x - extracting readme.12 (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'readme.12' &&
XScsi Version 1.2
X
X     This version of the driver enhances the tape drive support by adding
Xa program to control the action of the tape drive, and move around within
Xmultiple containers on the tape.  As I used the Bezerkley 'mt' command for
Xideas, the program is naturally called 'mt'.  You can tell the driver to:
X
X#1 Rewind/No Rewind on close.
X#2 Erase the tape.
X#3 Step forwards or backwards X tape marks.
X   Note: the command 'mt -s 0' steps to End Of Data.
X
X     I also did a little more work on the routines that actually transfer
Xdate to/from the card.  I found that I had left out a check for timeout
Xin the inner loops of the the data xfer routines.  When the random parity
Xerror or other glitch occured.  The driver would hang forever.  Not very
Xfriendly...  The added code does not seem to slow the driver any, or at
Xleast the disk thru-put tester I use shows no difference.
X
X     As the driver seems to be stable now, and it does about everything
XI started out to do.  I'm going to post this to comp.sources.misc instead
Xof alt.sources in the hopes that more people will see it.  Hopefully this
Xwill be usefull to someone else (at least they might get a good chuckle).
X
XBrian Antoine
XSept 25, 1990
SHAR_EOF
chmod 0644 readme.12 ||
echo 'restore of readme.12 failed'
Wc_c="`wc -c < 'readme.12'`"
test 1210 -eq "$Wc_c" ||
	echo 'readme.12: original size 1210, current size' "$Wc_c"
fi
# ============= scsi.asm ==============
if test -f 'scsi.asm' -a X"$1" != X"-c"; then
	echo 'x - skipping scsi.asm (File already exists)'
else
echo 'x - extracting scsi.asm (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'scsi.asm' &&
X;
X; Simple SCSI Device Driver
X;
X		.286
X		PAGE	76,132
X
X		INCLUDE	options.inc
X		INCLUDE	equ.inc
X		INCLUDE	struct.inc
X;
X; Start of Code and Data
X;
X_TEXT		segment	word public 'CODE'
X		assume	cs:_TEXT, ds:_TEXT, es:_TEXT
X
X		org	0
X
X;
X; Device Header Required By DOS
X;
Xscsi:
Xtape_link_ofs	dw	disk_link_ofs	;Forward Link
Xtape_link_seg	dw	-1
X		dw	0C800h		;Char Device
X		dw	tape_strategy	;Address of 1st DOS Call
X		dw	dev_interrupt	;Address of 2nd DOS Call
X		db	'SCSITAPE'	;Device Name
X
Xdisk_link_ofs	dw	-1		;Forward Link
Xdisk_link_seg	dw	-1
X		dw	06040h		;Ioctl R/W, Block Device, Non-IBM, Get/Set
X		dw	disk_strategy	;Address of 1st DOS Call
X		dw	dev_interrupt	;Address of 2nd DOS Call
Xdisk_count	db	0		;Number of Disks Present
X		db	7 dup(?)
X
X;
X; Work Space For Our Device Driver
X;
X		even
Xrh_off		dw	?		;Request Header Offset
Xrh_seg		dw	?		;Request Header Segment
Xrh_type		db	?		;Request Type
X
Xwrite_flag	db	FALSE		;TRUE When Tape Write Seen
Xload_flag	db	TRUE		;TRUE When Tape should Load/Unload
Xcur_drive	db	-1
Xvol_id		db	'NO NAME    ',0
X
X;
X; Define our own personal Stack
X;
X		even
Xnew_stack	db	STACK_SIZE-2 dup (?)	;Our Local Stack
Xnew_stack_top	dw	?
X
Xstack_ptr	dw	?			;Old Stack Pointer
Xstack_seg	dw	?			;Old Stack Segment
X
X;
X; Command Table
X;
Xcmdtab		label	byte		;* = Char Only Devices
X		dw	INITIALIZATION	;Initialization
X		dw	MEDIA_CHECK	;Media Check (Block Only)
X		dw	GET_BPB		;Build BPB (Block Only)
X		dw	unknown		;IOCTL Read
X		dw	READ		;Read Data
X		dw	done		;*Non Destructive Read
X		dw	done		;*Read Status
X		dw	done		;*Flush Read Buffer
X		dw	WRITE		;Write Data
X		dw	WRITE_VERIFY	;Write With Verify
X		dw	done		;*Write Status
X		dw	done		;*Flush Write Buffer
X		dw	WRITE_IOCTL	;IOCTL Write
X		dw	OPEN_DEV	;Device Open
X		dw	CLOSE_DEV	;Device Close
X		dw	done		;Removable Check
X		dw	unknown		;*Write Until Busy
X		dw	unknown		;Unknown Call
X		dw	unknown		;Unknown Call
X		dw	IOCTL		;Generic Ioctl
X		dw	unknown		;Unknown Call
X		dw	unknown		;Unknown Call
X		dw	unknown		;Unknown Call
X		dw	GET_DEV		;Get Device
X		dw	SET_DEV		;Set Device
X
X;
X; Strategy Procedure
X;
Xdisk_strategy	proc	far
X		mov	cs:rh_seg,es		;Save Request Header Ptr Segment
X		mov	cs:rh_off,bx		;Save Request Header Ptr Offset
X		mov	cs:rh_type,DISK_REQUEST
X		ret
Xdisk_strategy	endp
X
Xtape_strategy	proc	far
X		mov	cs:rh_seg,es		;Save Request Header Ptr Segment
X		mov	cs:rh_off,bx		;Save Request Header Ptr Offset
X		mov	cs:rh_type,TAPE_REQUEST
X		ret
Xtape_strategy	endp
X
X;
X; Interrupt Procedure
X;
Xdev_interrupt	proc	far
X		cli				;Save Machine State On Entry
X		push	ds
X		push	es
X		push	ax
X		push	bx
X		push	cx
X		push	dx
X		push	si
X		push	di
X		push	bp
X		pushf
X
X		mov	cs:stack_seg,ss		;Save Old Stack
X		mov	cs:stack_ptr,sp
X
X		mov	ax,cs			;Save us the Segment Override Crap
X		mov	ds,ax
X		mov	es,ax
X
X		mov	ss,ax			;Setup Our Local Stack
X		lea	ax,new_stack_top
X		mov	sp,ax
X		sti				;We're Safe Now
X
X;
X; Perform branch based on the command passed in the Request Header
X;
X		mov	es,rh_seg		;Point us at the Request Header
X		mov	bx,rh_off
X
X		mov	al,es:[bx].rh_cmd	;Get Command Code
X		rol	al,1			;Get offset into table
X		lea	di,cmdtab		;Get address of command table
X		mov	ah,0			;Clear hi order byte
X		add	di,ax			;Add offset
X		jmp	word ptr [di]		;Jump Indirect
X
X;
X; Command Procedures
X;
XINITIALIZATION:	cmp	rh_type,TAPE_REQUEST	;Is this SCSITAPE: Init?
X		jz	init_skip
X		mov	al,es:[bx].rh0_drv_ltr	;Save the starting Drive
X		add	al,041h
X		mov	cur_drive,al
X		call	initial			;Setup
X		if use_kludge
X		call	patch_us_in
X		endif
X		mov	bx,rh_off
X		mov	es,rh_seg
Xinit_skip:	lea	ax,initial		;Set The Break Address
X		mov	es:[bx].rh0_brk_ofs,ax
X		mov	es:[bx].rh0_brk_seg,cs
X		mov	al,disk_count		;Number of Disk Devices Supported
X		mov	es:[bx].rh0_nunits,al
X		lea	dx,bpb_array		;BPB Array
X		mov	es:[bx].rh0_bpb_tbo,dx
X		mov	es:[bx].rh0_bpb_tbs,cs
X		jmp	done
X
X;
X; Has the Media Changed
X;
XMEDIA_CHECK:	call	find_unit
X		jc	mc_jmp_err
X		mov	di,cur_unit
X		mov	al,[di].unit_mcheck	;Get Initial Status
X		mov	[di].unit_mcheck,1	;Always OK from then on
X		mov	es:[bx].rh1_md_stat,al
X		lea	dx,vol_id		;Address of Volume ID
X		mov	es:[bx].rh1_volid_ofs,dx
X		mov	es:[bx].rh1_volid_seg,cs
X		jmp	done
Xmc_jmp_err:	jmp	bad_unit
X
X;
X; Get Disk Parameter Block
X;
XGET_BPB:	call	find_unit
X		jc	get_jmp_err
X		mov	dx,cur_bpb		;Address of BPB
X		mov	es:[bx].rh2_pbpbo,dx
X		mov	es:[bx].rh2_pbpbs,cs
X		jmp	done
Xget_jmp_err:	jmp	bad_unit
X
X;
X; Read some data from the disk/tape
X;
XREAD:		cmp	rh_type,DISK_REQUEST
X		jz	read_a_disk
X		mov	ax,tape_unit		;Do We Have a Tape?
X		cmp	ax,-1
X		jz	read_jmp_err1
X		mov	cur_unit,ax
X		call	tape_read
X		jc	read_jmp_err2
X		jmp	done
Xread_a_disk:	call	find_unit
X		jc	read_jmp_err1
X		call	disk_read
X		jc	read_jmp_err2
X		jmp	done
Xread_jmp_err1:	jmp	bad_unit
Xread_jmp_err2:	jmp	bad_read
X
X;
X; Write some data to the disk/tape
X;
XWRITE		equ	$
XWRITE_VERIFY:	cmp	rh_type,DISK_REQUEST
X		jz	write_a_disk
X		mov	ax,tape_unit		;Do We Have a Tape?
X		cmp	ax,-1
X		jz	write_jmp_err1
X		mov	cur_unit,ax
X		call	tape_write
X		jc	write_jmp_err2
X		jmp	done
Xwrite_a_disk:	call	find_unit
X		jc	write_jmp_err1
X		call	disk_write
X		jc	write_jmp_err2
X		jmp	done
Xwrite_jmp_err1:	jmp	bad_unit
Xwrite_jmp_err2:	jmp	bad_write
Xwrite_jmp_err3:	jmp	unknown
X
X;
X; Write Ioctl Packet
X;
XWRITE_IOCTL:	cmp	rh_type,DISK_REQUEST
X		jz	ioctl_a_disk
X		mov	ax,tape_unit			;Do we have a SCSITAPE?
X		cmp	ax,-1
X		jz	write_jmp_err1
X		mov	cur_unit,ax
X		jmp	short ioctl_do
Xioctl_a_disk:	call	find_unit
X		jc	write_jmp_err1
Xioctl_do:	call	scsi_ioctl_write
X		jc	write_jmp_err3
X		jmp	done
X
X;
X; Special Control Functions
X;
XIOCTL:		call	find_unit
X		jc	ioctl_jmp_err1
X		call	scsi_ioctl
X		jc	ioctl_jmp_err2
X		jmp	done
Xioctl_jmp_err1:	jmp	bad_unit
Xioctl_jmp_err2:	jmp	unknown
X
X;
X; Open Tape Device
X;
XOPEN_DEV:	mov	di,tape_unit
X		cmp	di,-1		;Do We have a SCSITAPE: Unit?
X		jz	open_err1
X		mov	cur_unit,di			;New Current Unit
X		lea	bx,[di].unit_sense_buf		;Buffer Offset
X		push	ds				;Buffer Segment
X		pop	es
X		mov	cx,size sense			;Buffer Size
X		lea	di,cmd_sense			;Command
X		call	docmd
X		jc	open_err2
X		cmp	load_flag,TRUE			;Should we LOAD?
X		jnz	open_ok
X		lea	di,cmd_load			;Now Load Tape
X		mov	[di].load_cmd_type,LOAD_TAPE
X		call	docmd
X		jnc	open_ok
X		call	scsi_sense
Xopen_err2:	jmp	general
Xopen_err1:	jmp	bad_unit
Xopen_ok:	mov	opened_flag,TRUE		;We are open
X		mov	write_flag,FALSE		;No Writes Seen
X		jmp	done
X
X;
X; Close Tape Device
X;
XCLOSE_DEV:	mov	di,tape_unit
X		cmp	di,-1		;Do We have a SCSITAPE: Unit?
X		jz	close_err1
X		mov	cur_unit,di			;New Current Unit
X		cmp	write_flag,TRUE			;Were We Writing?
X		jnz	tape_no_write
X		lea	di,cmd_twritefm			;End Tape with FM(s)
X		mov	[di].fm_cmd_cnt_b0,CLOSE_FM_CNT
X		call	docmd
X		jnc	tape_no_write
X		call	scsi_sense
Xtape_no_write:	cmp	load_flag,TRUE			;Should we Unload?
X		jnz	close_ok	
X		lea	di,cmd_load			;Now Unload Tape
X		mov	[di].load_cmd_type,UNLOAD_TAPE
X		call	docmd
X		jnc	close_ok
X		call	scsi_sense
Xclose_err2:	jmp	general
Xclose_err1:	jmp	bad_unit
Xclose_ok:	jmp	done
X
X;
X; Get Device Assignment
X;
XGET_DEV:	mov	es:[bx].rh_unit,0
X		jmp	done
X
X;
X; Set Device Assignment
X;
XSET_DEV:	jmp	done
X
Xbad_unit:	mov	es,rh_seg		;Point us at the Request Header
X		mov	bx,rh_off
X		or	es:[bx].rh_status,8001h
X		jmp	short done
X
Xunknown:	mov	es,rh_seg		;Point us at the Request Header
X		mov	bx,rh_off
X		or	es:[bx].rh_status,8003h
X		jmp	short done
X
Xbad_write:	mov	es,rh_seg		;Point us at the Request Header
X		mov	bx,rh_off
X		or	es:[bx].rh_status,800Ah
X		jmp	short done
X
Xbad_read:	mov	es,rh_seg		;Point us at the Request Header
X		mov	bx,rh_off
X		or	es:[bx].rh_status,800Bh
X		jmp	short done
X
Xgeneral:	mov	es,rh_seg		;Point us at the Request Header
X		mov	bx,rh_off
X		or	es:[bx].rh_status,800Ch
X		jmp	short done
X
Xbusy:		mov	es,rh_seg		;Point us at the Request Header
X		mov	bx,rh_off
X		or	es:[bx].rh_status,0200h
X
Xdone:		mov	es,rh_seg		;Point us at the Request Header
X		mov	bx,rh_off
X		or	es:[bx].rh_status,0100h
X
X		cli				;Make sure we're left alone
X		mov	ax,cs:stack_seg		;Restore DOS Stack
X		mov	ss,ax
X		mov	ax,cs:stack_ptr
X		mov	sp,ax
X
X		popf				;Restore All Registers
X		pop	bp
X		pop	di
X		pop	si
X		pop	dx
X		pop	cx
X		pop	bx
X		pop	ax
X		pop	es
X		pop	ds
X		sti				;We're Safe Now
X		ret
X
X		INCLUDE	units.asm
X		INCLUDE	subs.asm
X		INCLUDE	ioctl.asm
X		INCLUDE	dump.asm
X		if use_kludge
X		INCLUDE	kludge.asm
X		endif
X
X;
X; End of Program
X; Stuff Placed Here Gets Handed Back To DOS For Re-use
X;
Xinitial		proc	near
X		lea	dx,hello_msg		;Tell them the driver version
X		call	puts
X		push	cs
X		pop	dx
X		lea	bx,seg_msg_value
X		call	hex2asc4
X		lea	dx,seg_msg		;And Were We Loaded
X		call	puts
X
X		call	scsi_reset		;Reset the bus
X
X		mov	cx,0			;Scan for devices
Xscan:		mov	ax,cx
X		add	al,030h
X		mov	scan_dev,al
X		mov	ax,1			;Create Select Bit
X		shl	ax,cl
X		if reserve_addr
X		or	al,80h			;Add Card Select Bit
X		endif
X		mov	di,cur_unit
X		mov	[di].unit_select,al
X		mov	[di].unit_num_drv,0	;No Drives to start with
X		mov	al,disk_count		;We will start with
X		mov	[di].unit_1st_drv,al	;Drive Number if any
X
X		lea	dx,scan_dev		;Print the device number
X		call	puts
X		call	scsi_inquire		;Inquire as to its type
X		jnc	scan_inq_ok
X		jmp	scan_err
X
Xscan_inq_ok:	mov	di,cur_unit
X		lea	dx,[di].unit_inq_buf.inq_manufact
X		mov	[di].unit_inq_term,'$'
X		mov	al,[di].unit_inq_buf.inq_dev_type
X		or	al,al			;Look at device type
X		jz	scan_is_drv
X		cmp	tape_unit,-1		;Do We Already Have A Tape?
X		jnz	tape_jmp
X		call	puts			;Make this our SCSITAPE: Unit
X		mov	tape_unit,di
X		lea	dx,tape_msg
Xtape_jmp:	jmp	scan_puts
X
Xscan_is_drv:	call	puts			;Output the Device String
X		call	scsi_capacity		;Inquire as to its size
X		lea	dx,err_size
X		jc	scan_puts		;Do not use unknown drives
X		lea	dx,crlf
X		call	puts
X
Xscan_next_drv:	mov	di,cur_unit
X		mov	al,disk_count		;Number Of Drives Found
X		inc	al
X		mov	disk_count,al
X		mov	al,[di].unit_num_drv	;We have a valid Drive
X		inc	al
X		mov	[di].unit_num_drv,al
X		mov	al,cur_drive		;Get Current Drive Letter
X		mov	drv_msg_let,al		;Insert it in message
X		inc	al			;Bump Drive Letter
X		mov	cur_drive,al
X		call	make_bpb		;Setup the BPB for this drive
X		mov	di,cur_bpb		;Current Working BPB
X		mov	ax,[di].bpb_ts
X		shr	ax,11
X		inc	ax
X		lea	bx,drv_msg_size
X		call	bin_ascii
X		mov	bx,bpb_hw_mark		;Get the BPB High Water Mark
X		inc	bx			;Bump HW Mark for next time
X		inc	bx
X		mov	ax,[bx]			;Get the BPB
X		mov	cur_bpb,ax		;Make it the current BPB
X		mov	bpb_hw_mark,bx
X		lea	dx,drv_msg
X		call	puts
X		mov	bx,cur_unit
X		mov	ah,0
X		mov	al,[bx].unit_num_drv	;Insert Drive Offset
X		dec	al			;Into BPB for this Drive
X		mov	[di].bpb_hs_msw,ax
X		mov	al,[bx].unit_cap_buf.cap_sectors_b3
X		or	al,[bx].unit_cap_buf.cap_sectors_b2
X		or	al,[bx].unit_cap_buf.cap_sectors_b1
X		or	al,[bx].unit_cap_buf.cap_sectors_b0
X		jnz	scan_next_drv		;Room left for another Drive
X		jmp	short scan_next
X
Xscan_err:	lea	dx,no_dev
X		cmp	al,CNOCONNECT
X		jz	scan_puts
X		lea	dx,err_dev
Xscan_puts:	call	puts
X		lea	dx,crlf
X		call	puts
X
Xscan_next:	inc	cx
X		cmp	cx,MAXUNIT	;End of devices?
X		jg	scan_exit
X		mov	bx,cx		;Bump to next unit
X		shl	bx,1
X		mov	ax,word ptr unit_array[bx]
X		mov	cur_unit,ax
X		jmp	scan
X
Xscan_exit:	ret
Xinitial		endp
X
X;
X; Data Area Used Only During Initialization
X;
Xhello_msg	db	0dh,0ah,'SCSI Device Driver Version 1.2',0Dh,0Ah,'$'
Xseg_msg		db	'Driver Loaded At Segment '
Xseg_msg_value	db	'0000',0dh,0ah,'$'
Xscan_dev	db	'X - ','$'
Xno_dev		db	'(No Installed Device)$'
Xerr_dev		db	'(Error On Device)$'
Xerr_size	db	'unknown size$'
Xdrv_msg		db	'  - Drive '
Xdrv_msg_let	db	'X: '
Xdrv_msg_size	db	'XXXXXX Meg',0dh,0ah,'$'
Xtape_msg	db	0dh,0ah,'  - Is The SCSITAPE: Device$'
Xcrlf		db	0dh,0ah,'$'
X
Xdev_interrupt	endp
X_TEXT		ends
X		end
SHAR_EOF
chmod 0644 scsi.asm ||
echo 'restore of scsi.asm failed'
Wc_c="`wc -c < 'scsi.asm'`"
test 11458 -eq "$Wc_c" ||
	echo 'scsi.asm: original size 11458, current size' "$Wc_c"
fi
# ============= scsi.sys ==============
if test -f 'scsi.sys' -a X"$1" != X"-c"; then
	echo 'x - skipping scsi.sys (File already exists)'
else
echo 'x - extracting scsi.sys (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'scsi.sys' &&
XHSCSITAPE@`nNO NAME    L2IPPPvvPP&Z#PGgo.&.	$.F(K.&.	$.F(KzPSQRVWU.:.	&8HX at P
6`{&$&
XGP@
><4x%XGA"+hIh\$&
(&	G&O &G
r&	W&OiDhr>
XEFE&G
,&	W&Oi!i at her&	W&Oi
Xi)Xr_i	hPrhN
Xri|ii(>t/	>
]-9
>H	h9rXXg
>d
6r9
XG
X at t
X7:ft
XFF~F~Hutk	#xkGGbVyaC>GFEGEFEGE
Xg%
XG&@tHg%G&:k
Xw'FG'2FG(J	UFE
XxAj
XB	UGEGEGEGEC
X
X %/SCSI Unit: 0xxx, Sense Status: 0xxx, Block Address: 0xxxxxxxxx
X$`8^@>&G+A&	GCF){&MA%t&GEyC&]&E@CAhFpFc
>f	AAh	eEh^sh=}CF){&MA%t&GEF)yC&M&]&E@CAhFpFc
>l	AAh	eEhsF)he}C`	 	"		$		>	8^@>=`X8D.96Xzsi">
UFE$$
XE
X at t>uh$	>
Vihhz
/r{
th> ~@"
XE~@E +"F~@"+h	x>EAh@
Ihf~CC#	
<h<~4
XG~H	E
XG%
XG&
XG'
XG(uk
<t
h~
th~AyYQcd#iC
XSCSI Device Driver Version 1.2
X$Driver Loaded At Segment 0000
X$X - $(No Installed Device)$(Error On Device)$unknown size$  - Drive X: XXXXXX Meg
X$
X  - Is The SCSITAPE: Device$
X$
SHAR_EOF
chmod 0644 scsi.sys ||
echo 'restore of scsi.sys failed'
Wc_c="`wc -c < 'scsi.sys'`"
test 2518 -eq "$Wc_c" ||
	echo 'scsi.sys: original size 2518, current size' "$Wc_c"
fi
# ============= sformat.c ==============
if test -f 'sformat.c' -a X"$1" != X"-c"; then
	echo 'x - skipping sformat.c (File already exists)'
else
echo 'x - extracting sformat.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'sformat.c' &&
X/*
X** SCSI Disk Formatter (Low Level)
X**
X** usage: sformat drive: [interleave]
X**
X** Revision History:
X**
X** Version 1.0  08/03/90 Initial Release
X**
X** Version 1.1  08/20/90 Add verification message.
X**
X** Version 1.2  09/18/90 Correct ioctl_data struct.
X*/
X#include <stdio.h>
X#include <dos.h>
X
X#define TRUE (1)
X#define FALSE (0)
X#define VERSION "sformat Version 1.2 BWA"
X
Xextern int _doserrno;
X
Xstruct cmd {
X	short command;		/* command type */
X	short arg1;			/* command args */
X	short arg2;			/* command args */
X} ioctl_data;
Xunion REGS inregs, outregs;
Xstruct SREGS segregs;
Xunsigned short interleave = 0;
Xunsigned char drive;
Xchar far *cp;
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	/*
X	** say hello
X	*/
X	puts(VERSION);
X
X	/*
X	** figure out who to format
X	*/
X	switch (argc)
X	{
X		case 3:
X		interleave = atoi(argv[2]);
X		case 2:
X		if (argv[1][1] != ':') usage();
X		drive = argv[1][0];
X		drive = toupper(drive);
X		drive -= '@';
X		break;
X
X		default:
X		usage();
X		break;
X	}
X
X	/*
X	** verify that this is what the user really wants to do
X	*/
X	printf("Do you really wish to format the SCSI\n");
X	printf("device that contains drive %c: (y,n)? ", argv[1][0]);
X	fflush(stdout);
X	if ( getchar() != 'y' )
X	{
X		puts("Aborting low level format ....");
X		exit(1);
X	}
X
X	/*
X	** put together the command
X	*/
X	inregs.h.ah = 0x44;			/* ioctl */
X	inregs.h.al = 0x05;			/* write */
X	inregs.h.bl = drive;		/* unit */
X	inregs.x.cx = sizeof(struct cmd);
X	cp = (char *) &ioctl_data;
X	inregs.x.dx = FP_OFF(cp);
X	segregs.ds = FP_SEG(cp);
X	ioctl_data.command = 'F';
X	ioctl_data.arg1 = interleave;
X
X	/*
X	** start the format
X	*/
X	puts("Now formating ....");
X	puts("Please wait ....");
X	intdosx(&inregs, &outregs, &segregs);
X
X	/*
X	** see what happened
X	*/
X	if ( outregs.x.cflag )
X		printf("DOS error %d occured during format.\n", _doserrno);
X	else
X		puts("Formating complete.");
X	exit(0);
X}
X
Xusage()
X{
X	puts("usage: sformat drive: [interleave]");
X	exit(1);
X}
SHAR_EOF
chmod 0644 sformat.c ||
echo 'restore of sformat.c failed'
Wc_c="`wc -c < 'sformat.c'`"
test 1931 -eq "$Wc_c" ||
	echo 'sformat.c: original size 1931, current size' "$Wc_c"
fi
true || echo 'restore of struct.inc failed'
echo End of part 1, continue with part 2
exit 0



More information about the Comp.sources.misc mailing list