SCSI Version 1.1
Brian Who?
briana at tau-ceti.isc-br.com
Sun Sep 9 05:15:46 AEST 1990
Here is version 1.1 of my SCSI Device Driver for the Seagate ST-01
interface card. It add support for a single tape device and cleans up
the code a little.
#
# 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:
# binmode.c
# dump.asm
# equ.inc
# ioctl.asm
# kludge.asm
# makefile
# options.inc
# readme.10
# readme.11
# scsi.asm
# serase.c
# sformat.c
# struct.inc
# subs.asm
# units.asm
# This Archive created: Sat Sep 8 12:13:37 1990
# By: Brian Who? at I Saute Cats - Barbecue Rats, Spokane, WA
#
export PATH; PATH=/bin:$PATH
echo shar: extracting "'binmode.c'" '(497 characters)'
if test -f 'binmode.c'
then
echo shar: will not over-write existing file "'binmode.c'"
else
sed 's/^XX//' > 'binmode.c' << \SHAR_EOF
XX#ifdef MSDOS
XX#include <dos.h>
XX
XXbinmode(fd)
XXint fd;
XX{
XX union REGS inregs, outregs;
XX
XX /*
XX ** get the current mode
XX */
XX inregs.h.ah = 0x44; /* ioctl */
XX inregs.h.al = 0x00; /* get */
XX inregs.x.bx = fd; /* unit */
XX intdos(&inregs, &outregs);
XX
XX /*
XX ** set to BINARY mode (this works for char devices)
XX */
XX inregs.h.ah = 0x44; /* ioctl */
XX inregs.h.al = 0x01; /* set */
XX inregs.x.bx = fd; /* unit */
XX inregs.h.dh = 0;
XX inregs.h.dl = outregs.h.dl | 0x20;
XX intdos(&inregs, &outregs);
XX}
XX#endif
SHAR_EOF
if test 497 -ne "`wc -c < 'binmode.c'`"
then
echo shar: error transmitting "'binmode.c'" '(should have been 497 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'dump.asm'" '(1296 characters)'
if test -f 'dump.asm'
then
echo shar: will not over-write existing file "'dump.asm'"
else
sed 's/^XX//' > 'dump.asm' << \SHAR_EOF
XX;
XX; Convert bin (ax) to ascii (bx => buffer)
XX;
XXbin_ascii proc near
XX pusha
XX push ax
XX mov cx,6
XXfill_buff: mov byte ptr [bx],' '
XX inc bx
XX loop fill_buff
XX mov si,10
XX or ax,ax
XX jns clr_dvd
XX neg ax
XXclr_dvd: sub dx,dx
XX div si
XX add dx,'0'
XX dec bx
XX mov [bx],dl
XX inc cx
XX or ax,ax
XX jnz clr_dvd
XX pop ax
XX or ax,ax
XX jns no_more
XX dec bx
XX mov byte ptr [bx],'-'
XXno_more: popa
XX ret
XXbin_ascii endp
XX
XX;
XX; Convert Hex (dx) to Ascii (bx => buffer)
XX;
XXhex2asc4 proc near
XX push cx
XX push ax
XX mov cx,4 ;Do Four Digits
XXh241: rol dx,4
XX mov al,dl ;Get the Current Digit
XX and al,0Fh
XX cmp al,0Ah ;Is It Hex?
XX jge h242
XX add al,30h ;Normal Digit
XX jmp h243
XXh242: add al,37h ;Hex Digit
XXh243: mov [bx],al ;Insert in Buffer
XX inc bx
XX loop h241
XX pop ax
XX pop cx
XX ret
XXhex2asc4 endp
XX
XX;
XX; Convert Hex (dl) to Ascii (bx => buffer)
XX;
XXhex2asc2 proc near
XX push cx
XX push ax
XX mov cx,2 ;Do Two Digits
XXh221: rol dl,4
XX mov al,dl ;Get the Current Digit
XX and al,0Fh
XX cmp al,0Ah ;Is It Hex?
XX jge h222
XX add al,30h ;Normal Digit
XX jmp h223
XXh222: add al,37h ;Hex Digit
XXh223: mov [bx],al ;Insert in Buffer
XX inc bx
XX loop h221
XX pop ax
XX pop cx
XX ret
XXhex2asc2 endp
XX
XX;
XX; Print a string
XX;
XX; ds:dx => string
XX;
XXputs proc near
XX pusha
XX mov ah,9 ;DOS print string
XX int 21h
XX popa
XX ret
XXputs endp
SHAR_EOF
if test 1296 -ne "`wc -c < 'dump.asm'`"
then
echo shar: error transmitting "'dump.asm'" '(should have been 1296 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'equ.inc'" '(3726 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;
XXTRUE EQU 001h
XXFALSE EQU 000h
XX
XXDISK_REQUEST EQU 000h ;Disk I/O Request
XXTAPE_REQUEST EQU 001h ;Tape I/O Request
XX
XX;
XX; ST-01 Card Registers
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
XX;
XX; The max target to check for (0-X).
XX; If using 'reserve_addr', this should not execede 6!
XX;
XXMAXUNIT EQU 6 ;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;
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
XX if scsi_parity
XXCMDBASE EQU CMDPARITY ;Base value of all commands
XX else
XXCMDBASE EQU 000h ;Base value of all commands
XX endif
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_WRITEFM EQU 010h ;Write File Marks (6 byte)
XXSCSI_INQUIRY EQU 012h ;Inquire (6 byte)
XXSCSI_MODE_SET EQU 015h ;Mode Select (6 byte)
XXSCSI_ERASE EQU 019h ;Erase Tape (6 byte)
XXSCSI_MODE_GET EQU 01Ah ;Mode Sense (6 byte)
XXSCSI_LOAD EQU 01Bh ;Load / Unload Tape (6 byte)
XXSCSI_READSIZE EQU 025h ;Read Drive Capacity (10 byte)
XX if extended_io
XXSCSI_READBLK EQU 028h ;Read Sectors (10 byte)
XXSCSI_WRITEBLK EQU 02Ah ;Write Sectors (10 byte)
XX else
XXSCSI_READBLK EQU 008h ;Read Sectors (6 byte)
XXSCSI_WRITEBLK EQU 00Ah ;Write Sectors (6 byte)
XX endif
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
XX
XXLOAD_TAPE EQU 001h ;Load
XXUNLOAD_TAPE EQU 000h ;Unload
SHAR_EOF
echo shar: a missing newline was added to "'equ.inc'"
if test 3726 -ne "`wc -c < 'equ.inc'`"
then
echo shar: error transmitting "'equ.inc'" '(should have been 3726 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ioctl.asm'" '(2148 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 short scsi_i_exit
XX
XXscsi_i_42h: cmp al,42h ;Format and Verify?
XX jnz scsi_i_60h
XX call scsi_verify
XX jmp short 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 short scsi_i_exit
XX
XXscsi_i_62h: cmp al,62h ;Verify?
XX jnz scsi_i_error
XX call scsi_verify
XX jmp short scsi_i_exit
XX
XXscsi_i_error: stc
XXscsi_i_exit: ret
XXscsi_ioctl endp
XX
XX;
XX; Process an ioctl_write request
XX;
XXscsi_ioctl_write proc
XX mov di,es:[bx].rh12_buf_ofs ;Get The Command
XX mov ax,es:[bx].rh12_buf_seg ;Buffer
XX mov es,ax
XX mov ax,es:[di].ioc_command ;What Command
XX
XX;
XX; Format Disk Unit
XX;
XX cmp al,'F' ;Format?
XX jnz try_erase
XX mov ax,es:[di].ioc_param ;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 jnc scsi_i_w_exit
XX call scsi_sense
XX jmp scsi_i_w_exit
XX
XX;
XX; Erase Tape Unit
XX;
XXtry_erase: cmp al,'E' ;Erase?
XX jnz scsi_i_w_error
XX lea di,cmd_erase ;Now Erase Tape
XX call docmd
XX jnc scsi_i_w_exit
XX call scsi_sense
XX jmp scsi_i_w_error
XX
XXscsi_i_w_error: stc
XXscsi_i_w_exit: ret
XXscsi_ioctl_write endp
SHAR_EOF
if test 2148 -ne "`wc -c < 'ioctl.asm'`"
then
echo shar: error transmitting "'ioctl.asm'" '(should have been 2148 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'kludge.asm'" '(2417 characters)'
if test -f 'kludge.asm'
then
echo shar: will not over-write existing file "'kludge.asm'"
else
sed 's/^XX//' > 'kludge.asm' << \SHAR_EOF
XX;
XX; This code is needed because DOS insists on opening a char device
XX; in cooked mode. The problem is that without adding code to every
XX; application that would ever use us, we have no way to alter this
XX; because the use of O_BINARY or setmode() do not affect char devices.
XX;
XX; The solution (kludge) is to watch open requests issued thru the
XX; INT 21 vector. If we see a open request followed by a OPEN_DEV
XX; call to us, it must have been an open for us. So during the return,
XX; force a call to the ioctl facility that will switch to raw mode.
XX;
XX
XX;
XX; The Original INT 21 Vector
XX;
XXvect_int_21 equ word ptr 4 * 21h
XXorig_int_21 dd ? ;Original INT 21 Vector
XX
XX;
XX; OPEN_DEV flag is TRUE when we are opened
XX;
XXopened_flag db FALSE
XX
XXpatch_us_in proc near
XX push es
XX push ax
XX mov ax,0 ;Patch Ourselves into
XX mov es,ax ;the INT 21 Vector
XX mov ax,es:[vect_int_21] ;Offset
XX mov word ptr orig_int_21,ax
XX lea ax,our_int_21
XX mov es:[vect_int_21],ax
XX mov ax,es:[vect_int_21+2] ;Segment
XX mov word ptr orig_int_21+2,ax
XX mov ax,cs
XX mov es:[vect_int_21+2],ax
XX pop ax
XX pop es
XX ret
XXpatch_us_in endp
XX
XXour_int_21 proc far
XX pushf ;Save entry flags
XX cmp ah,3Dh ;Is it an open request?
XX jnz not_open_req
XX popf ;Restore entry flags
XX;
XX; We need to set things up so the 'iret' done by the INT 21
XX; code will have some the right stuff on the stack.
XX; #1 Flags with interrupts enabled
XX; #2 Return Address
XX;
XX sti ;Allow interrupts
XX pushf ;After the iret
XX cli ;Shut interrupts off
XX call cs:orig_int_21 ;While we Pass the request on
XX;
XX; Upon return, interrupts are enabled, so shut them off while we work
XX;
XX pushf
XX cli
XX cmp cs:opened_flag,FALSE ;Was it an open for us?
XX jz not_our_open
XX mov cs:opened_flag,FALSE ;Clear for next time
XX;
XX; We need to forge a call to the ioctl interface
XX; to switch DOS to raw mode when it talks to us
XX;
XX pusha
XX mov bx,ax ;Save the Handle
XX mov ax,4400h ;Get Device Information
XX pushf
XX call cs:orig_int_21
XX mov dh,0 ;Setup
XX or dl,20h ;for RAW Mode
XX mov ax,4401h ;Set Device Information
XX pushf
XX call cs:orig_int_21
XX popa
XX
XXnot_our_open: popf ;The Original Flags to return
XX;
XX; When we return, we need to pop the flags that the original INT 21
XX; call left on the stack, and return the flags we got back
XX;
XX ret 2 ;Return and discard flags
XX
XXnot_open_req: popf ;Pop the saved flags
XX jmp cs:orig_int_21 ;Continue with original code
XXour_int_21 endp
SHAR_EOF
if test 2417 -ne "`wc -c < 'kludge.asm'`"
then
echo shar: error transmitting "'kludge.asm'" '(should have been 2417 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'makefile'" '(526 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#
XXSRCS = scsi.asm subs.asm ioctl.asm dump.asm units.asm kludge.asm \
XX options.inc equ.inc struct.inc
XX
XXall: scsi.sys sformat.exe serase.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: $(SRCS)
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# SCSI Tape Erase
XX#
XXserase.exe: serase.c
XX cl -G2 -Ox -o serase.exe serase.c
XX
XX#
XX# clean
XX#
XXclean:
XX rm -f *.exe *.obj *.lst
SHAR_EOF
if test 526 -ne "`wc -c < 'makefile'`"
then
echo shar: error transmitting "'makefile'" '(should have been 526 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'options.inc'" '(1165 characters)'
if test -f 'options.inc'
then
echo shar: will not over-write existing file "'options.inc'"
else
sed 's/^XX//' > 'options.inc' << \SHAR_EOF
XX;
XX; Allow multi_sector reads and writes.
XX;
XX; This means that a read request of less then CHUNK_MAX
XX; sectors will be done in one request to the drive rather
XX; then multiple single sector requests.
XX;
XX; The disadvantage here is that the code in receive_data()
XX; and send_data() must keep the transfer from exceding the
XX; 512 byte buffer on the ST-01 card.
XX;
XXmulti_sector = 1 ;Enable multi_sector support
XX
XX;
XX; Use the extended SCSI commands for reads and writes.
XX;
XX; This means that we can access drives larger then 1Gb
XX; and read/write more then 256 sectors per command.
XX;
XX; The disadvantage here is that not all devices support
XX; the extended command set.
XX;
XXextended_io = 0 ;Disable use of extended io commands
XX
XX;
XX; Use parity on the SCSI bus
XX;
XXscsi_parity = 1 ;Enable use of parity on the SCSI bus
XX
XX;
XX; Reserve SCSI Address 7 for card
XX;
XXreserve_addr = 1 ;Reserve Address for Card Use
XX
XX;
XX; Dump Sense information to the screen
XX;
XXdump_sense = 1 ;Dump Sense Message to the Screen
XX
XX;
XX; Extended Sense or Normal Sense
XX;
XXextended_sense = 1 ;Request Extended Sense
XX
XX;
XX; Include the code to kludge the RAW ioctl call after an open
XX;
XXuse_kludge = 1 ;Enable the ioctl kludge
SHAR_EOF
if test 1165 -ne "`wc -c < 'options.inc'`"
then
echo shar: error transmitting "'options.inc'" '(should have been 1165 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 "'readme.11'" '(2983 characters)'
if test -f 'readme.11'
then
echo shar: will not over-write existing file "'readme.11'"
else
sed 's/^XX//' > 'readme.11' << \SHAR_EOF
XXScsi Version 1.1
XX
XX This version of the driver add support for a single tape drive, and
XXcleans up some of the code a little. It also adds a file that has equates
XXto customize some of the major areas of the driver.
XX
XX When the driver is initialized it does a scan of the SCSI bus for
XXdevices. The FIRST tape device found is assigned to a char device with the
XXname "SCSITAPE". If no tape drive is found, the char device is still valid
XXbut will generate a "bad unit" error when accessed.
XX
XX The SCSITAPE device expects reads and writes to be done in some variation
XXof 512 bytes. I/O done where (size mod 512) is non-zero will generate an
XXerror. Tape access must be done in RAW mode, and this is where I had to
XXsome code in the driver that I'm not sure is very pretty. The problem is
XXthat DOS insists on opening char devices in cooked mode. It does give you
XXthe ability to switch to RAW mode, but only by using 'intdos()' to access
XXthe ioctl interface. The MSC 'setmode()' call for binary will not effect
XXchar devices, nor will opening the file with O_BINARY. So I had two choices.
XXI could modify every program that expected to talk to the tape so that it
XXalso issued the ioctl stuff (see binmode.c), or I could kludge the driver
XXto issue the required calls.
XX
XX In the end, I punted and did both. The code in binmode.c is the function
XXthat along with 'setmode()', will make sure that ANYTHING you open is accessed
XXin RAW mode. Simply check for any call to 'setmode()' that is switching to
XXO_BINARY, and add another call to 'binmode()'. This assumes that you have
XXthe source to the utility in question. For those who are don't mind a little
XXkludge amount friends. The file options.inc has an equate called 'use_kludge'
XXthat when enabled turns on some code in kludge.asm. This code links into the
XXINT 21h vector and waits for a DOS open request to go by. When it sees an
XXopen request, it 'calls' rather then 'jmps' to the normal vector. This allows
XXthe driver to get the 'handle' returned by DOS. Because the SCSITAPE device
XXenables the driver_open function, I can tell from the fact that an open is
XXin progress and wether the driver just got an open request, wether any
XXparticular open was for me. When the open was in fact for the SCSITAPE device,
XXI take the 'handle' returned by DOS and forge the required ioctl calls to
XXswitch to RAW mode.
XX
XX With the addition of tape support. I now use GNU Tar to swap tapes with
XXmy normal UN*X system at work. The driver works well enough that I have yet
XXto have a format problem with the different systems. It is also a lot faster
XXwhen doing backups on the PC. Using 'fastback' I would get about 1 Meg a
XXminute thruput on my 8 Mhz AT. Using GNU Tar and the SCSITAPE device I get
XX> 2.5 Meg a minute to the tape and don't have to swap disks quite so often :-)
XX
XX Anyway, I hope that someone out there actually gets some use out of this
XXcode. It has been a real adventure for me.
XX
XXBrian Antoine
XXSept 8, 1990
SHAR_EOF
if test 2983 -ne "`wc -c < 'readme.11'`"
then
echo shar: error transmitting "'readme.11'" '(should have been 2983 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'scsi.asm'" '(11664 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 options.inc
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:
XXtape_link_ofs dw disk_link_ofs ;Forward Link
XXtape_link_seg dw -1
XX dw 0C800h ;Char Device
XX dw tape_strategy ;Address of 1st DOS Call
XX dw dev_interrupt ;Address of 2nd DOS Call
XX db 'SCSITAPE' ;Device Name
XX
XXdisk_link_ofs dw -1 ;Forward Link
XXdisk_link_seg dw -1
XX dw 06040h ;Ioctl R/W, Block Device, Non-IBM, Get/Set
XX dw disk_strategy ;Address of 1st DOS Call
XX dw dev_interrupt ;Address of 2nd DOS Call
XXdisk_count db 0 ;Number of Disks Present
XX db 7 dup(?)
XX
XX;
XX; Work Space For Our Device Driver
XX;
XX even
XXrh_off dw ? ;Request Header Offset
XXrh_seg dw ? ;Request Header Segment
XXrh_type db ? ;Request Type
XX
XXwrite_flag db FALSE ;TRUE When Tape Write Seen
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 (Block Only)
XX dw unknown ;IOCTL Read
XX dw READ ;Read Data
XX dw done ;*Non Destructive Read
XX dw done ;*Read Status
XX dw done ;*Flush Read Buffer
XX dw WRITE ;Write Data
XX dw WRITE_VERIFY ;Write With Verify
XX dw done ;*Write Status
XX dw done ;*Flush Write Buffer
XX dw WRITE_IOCTL ;IOCTL Write
XX dw OPEN_DEV ;Device Open
XX dw CLOSE_DEV ;Device Close
XX dw done ;Removable Check
XX dw unknown ;*Write Until Busy
XX dw unknown ;Unknown Call
XX dw unknown ;Unknown Call
XX dw IOCTL ;Generic Ioctl
XX dw unknown ;Unknown Call
XX dw unknown ;Unknown Call
XX dw unknown ;Unknown Call
XX dw GET_DEV ;Get Device
XX dw SET_DEV ;Set Device
XX
XXreq_msg db 0dh,'Request: '
XXreq_msg_type db 'xx, Count: '
XXreq_msg_count db 'xxxx, Start: '
XXreq_msg_start db 'xxxx',0dh,0ah,'$'
XX
XX;
XX; Strategy Procedure
XX;
XXdisk_strategy proc far
XX mov cs:rh_seg,es ;Save Request Header Ptr Segment
XX mov cs:rh_off,bx ;Save Request Header Ptr Offset
XX mov cs:rh_type,DISK_REQUEST
XX ret
XXdisk_strategy endp
XX
XXtape_strategy proc far
XX mov cs:rh_seg,es ;Save Request Header Ptr Segment
XX mov cs:rh_off,bx ;Save Request Header Ptr Offset
XX mov cs:rh_type,TAPE_REQUEST
XX ret
XXtape_strategy endp
XX
XX;
XX; Interrupt Procedure
XX;
XXdev_interrupt proc far
XX 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; pusha
XX; mov di,bx
XX; mov dl,es:[di].rh_cmd ;Get Command Code
XX; lea bx,req_msg_type
XX; call hex2asc2
XX; mov dx,es:[di].rh4_count
XX; lea bx,req_msg_count
XX; call hex2asc4
XX; mov dx,es:[di].rh4_start
XX; lea bx,req_msg_start
XX; call hex2asc4
XX; lea dx,req_msg
XX; call puts
XX; popa
XX
XX mov al,es:[bx].rh_cmd ;Get Command Code
XX rol al,1 ;Get offset into table
XX lea di,cmdtab ;Get address of command table
XX mov ah,0 ;Clear hi order byte
XX add di,ax ;Add offset
XX jmp word ptr [di] ;Jump Indirect
XX
XX;
XX; Command Procedures
XX;
XXINITIALIZATION: cmp rh_type,TAPE_REQUEST ;Is this SCSITAPE: Init?
XX jz init_skip
XX mov al,es:[bx].rh0_drv_ltr ;Save the starting Drive
XX add al,041h
XX mov cur_drive,al
XX call initial ;Setup
XX if use_kludge
XX call patch_us_in
XX endif
XX mov bx,rh_off
XX mov es,rh_seg
XXinit_skip: lea ax,initial ;Set The Break Address
XX mov es:[bx].rh0_brk_ofs,ax
XX mov es:[bx].rh0_brk_seg,cs
XX mov al,disk_count ;Number of Disk Devices Supported
XX mov es:[bx].rh0_nunits,al
XX lea dx,bpb_array ;BPB Array
XX mov es:[bx].rh0_bpb_tbo,dx
XX mov es:[bx].rh0_bpb_tbs,cs
XX jmp done
XX
XX;
XX; Has the Media Changed
XX;
XXMEDIA_CHECK: call find_unit
XX jc mc_jmp_err
XX mov di,cur_unit
XX mov al,[di].unit_mcheck ;Get Initial Status
XX mov [di].unit_mcheck,1 ;Always OK from then on
XX mov es:[bx].rh1_md_stat,al
XX lea dx,vol_id ;Address of Volume ID
XX mov es:[bx].rh1_volid_ofs,dx
XX mov es:[bx].rh1_volid_seg,cs
XX jmp done
XXmc_jmp_err: jmp bad_unit
XX
XX;
XX; Get Disk Parameter Block
XX;
XXGET_BPB: call find_unit
XX jc get_jmp_err
XX mov dx,cur_bpb ;Address of BPB
XX mov es:[bx].rh2_pbpbo,dx
XX mov es:[bx].rh2_pbpbs,cs
XX jmp done
XXget_jmp_err: jmp bad_unit
XX
XX;
XX; Read some data from the disk/tape
XX;
XXREAD: cmp rh_type,DISK_REQUEST
XX jz read_a_disk
XX mov ax,tape_unit ;Do We Have a Tape?
XX cmp ax,-1
XX jz read_jmp_err1
XX mov cur_unit,ax
XX call tape_read
XX jc read_jmp_err2
XX jmp done
XXread_a_disk: call find_unit
XX jc read_jmp_err1
XX call disk_read
XX jc read_jmp_err2
XX jmp done
XXread_jmp_err1: jmp bad_unit
XXread_jmp_err2: jmp bad_read
XX
XX;
XX; Write some data to the disk/tape
XX;
XXWRITE equ $
XXWRITE_VERIFY: cmp rh_type,DISK_REQUEST
XX jz write_a_disk
XX mov ax,tape_unit ;Do We Have a Tape?
XX cmp ax,-1
XX jz write_jmp_err1
XX mov cur_unit,ax
XX call tape_write
XX jc write_jmp_err2
XX jmp done
XXwrite_a_disk: call find_unit
XX jc write_jmp_err1
XX call disk_write
XX jc write_jmp_err2
XX jmp done
XXwrite_jmp_err1: jmp bad_unit
XXwrite_jmp_err2: jmp bad_write
XXwrite_jmp_err3: jmp unknown
XX
XX;
XX; Write Ioctl Packet
XX;
XXWRITE_IOCTL: cmp rh_type,DISK_REQUEST
XX jz ioctl_a_disk
XX mov ax,tape_unit ;Do we have a SCSITAPE?
XX cmp ax,-1
XX jz write_jmp_err1
XX mov cur_unit,ax
XX jmp short ioctl_do
XXioctl_a_disk: call find_unit
XX jc write_jmp_err1
XXioctl_do: call scsi_ioctl_write
XX jc write_jmp_err3
XX jmp done
XX
XX;
XX; Special Control Functions
XX;
XXIOCTL: call find_unit
XX jc ioctl_jmp_err1
XX call scsi_ioctl
XX jc ioctl_jmp_err2
XX jmp done
XXioctl_jmp_err1: jmp bad_unit
XXioctl_jmp_err2: jmp unknown
XX
XX;
XX; Open Tape Device
XX;
XXOPEN_DEV: mov di,tape_unit
XX cmp di,-1 ;Do We have a SCSITAPE: Unit?
XX jz open_err1
XX mov cur_unit,di ;New Current Unit
XX lea bx,[di].unit_sense_buf ;Buffer Offset
XX push ds ;Buffer Segment
XX pop es
XX mov cx,size sense ;Buffer Size
XX lea di,cmd_sense ;Command
XX call docmd
XX jc open_err2
XX lea di,cmd_load ;Now Load Tape
XX mov [di].load_cmd_type,LOAD_TAPE
XX call docmd
XX jnc open_ok
XX call scsi_sense
XXopen_err2: jmp general
XXopen_err1: jmp bad_unit
XXopen_ok: mov opened_flag,TRUE ;We are open
XX mov write_flag,FALSE ;No Writes Seen
XX jmp done
XX
XX;
XX; Close Tape Device
XX;
XXCLOSE_DEV: mov di,tape_unit
XX cmp di,-1 ;Do We have a SCSITAPE: Unit?
XX jz close_err1
XX mov cur_unit,di ;New Current Unit
XX cmp write_flag,TRUE ;Were We Writing?
XX jnz tape_no_write
XX lea di,cmd_twritefm ;End Tape with FM
XX call docmd
XX jnc tape_no_write
XX call scsi_sense
XXtape_no_write: lea di,cmd_load ;Now Unload Tape
XX mov [di].load_cmd_type,UNLOAD_TAPE
XX call docmd
XX jnc close_jmp
XX call scsi_sense
XXclose_err2: jmp general
XXclose_err1: jmp bad_unit
XXclose_jmp: jmp done
XX
XX;
XX; Get Device Assignment
XX;
XXGET_DEV: mov es:[bx].rh_unit,0
XX jmp done
XX
XX;
XX; Set Device Assignment
XX;
XXSET_DEV: jmp done
XX
XXbad_unit: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,8001h
XX jmp short done
XX
XXunknown: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,8003h
XX jmp short done
XX
XXbad_write: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,800Ah
XX jmp short done
XX
XXbad_read: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,800Bh
XX jmp short done
XX
XXgeneral: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,800Ch
XX jmp short done
XX
XXbusy: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,0200h
XX
XXdone: mov es,rh_seg ;Point us at the Request Header
XX mov bx,rh_off
XX or es:[bx].rh_status,0100h
XX
XX cli ;Make sure we're left alone
XX mov ax,cs:stack_seg ;Restore DOS Stack
XX mov ss,ax
XX mov ax,cs:stack_ptr
XX mov sp,ax
XX
XX 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 if use_kludge
XX INCLUDE kludge.asm
XX endif
XX
XX;
XX; End of Program
XX; Stuff Placed Here Gets Handed Back To DOS For Re-use
XX;
XXinitial proc near
XX lea dx,hello_msg ;Tell them the driver version
XX call puts
XX push cs
XX pop dx
XX lea bx,seg_msg_value
XX call hex2asc4
XX lea dx,seg_msg ;And Were We Loaded
XX call puts
XX
XX call scsi_reset ;Reset the bus
XX
XX mov cx,0 ;Scan for devices
XXscan: mov ax,cx
XX add al,030h
XX mov scan_dev,al
XX mov ax,1 ;Create Select Bit
XX shl ax,cl
XX if reserve_addr
XX or al,80h ;Add Card Select Bit
XX endif
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 cmp tape_unit,-1 ;Do We Already Have A Tape?
XX jnz tape_jmp
XX call puts ;Make this our SCSITAPE: Unit
XX mov tape_unit,di
XX lea dx,tape_msg
XXtape_jmp: jmp scan_puts
XX
XXscan_is_drv: call puts ;Output the Device String
XX call scsi_capacity ;Inquire as to its size
XX lea dx,err_size
XX jc scan_puts ;Do not use unknown drives
XX lea dx,crlf
XX call puts
XX
XXscan_next_drv: mov di,cur_unit
XX mov al,disk_count ;Number Of Drives Found
XX inc al
XX mov disk_count,al
XX mov al,[di].unit_num_drv ;We have a valid Drive
XX inc al
XX mov [di].unit_num_drv,al
XX mov al,cur_drive ;Get Current Drive Letter
XX mov drv_msg_let,al ;Insert it in message
XX inc al ;Bump Drive Letter
XX mov cur_drive,al
XX call make_bpb ;Setup the BPB for this drive
XX mov di,cur_bpb ;Current Working BPB
XX mov ax,[di].bpb_ts
XX shr ax,11
XX inc ax
XX lea bx,drv_msg_size
XX call bin_ascii
XX mov bx,bpb_hw_mark ;Get the BPB High Water Mark
XX inc bx ;Bump HW Mark for next time
XX inc bx
XX mov ax,[bx] ;Get the BPB
XX mov cur_bpb,ax ;Make it the current BPB
XX mov bpb_hw_mark,bx
XX lea dx,drv_msg
XX call puts
XX 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.1',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,'$'
XXtape_msg db 0dh,0ah,' - Is The SCSITAPE: Device$'
XXcrlf db 0dh,0ah,'$'
XX
XXdev_interrupt endp
XX_TEXT ends
XX end
SHAR_EOF
if test 11664 -ne "`wc -c < 'scsi.asm'`"
then
echo shar: error transmitting "'scsi.asm'" '(should have been 11664 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'serase.c'" '(1658 characters)'
if test -f 'serase.c'
then
echo shar: will not over-write existing file "'serase.c'"
else
sed 's/^XX//' > 'serase.c' << \SHAR_EOF
XX/*
XX** SCSI Tape Erase (Low Level)
XX**
XX** usage: serase
XX**
XX** Revision History:
XX**
XX** Version 1.0 09/03/90 Initial Release
XX**
XX*/
XX#include <stdio.h>
XX#include <fcntl.h>
XX#include <dos.h>
XX
XX#define TRUE (1)
XX#define FALSE (0)
XX#define VERSION "serase Version 1.0 BWA"
XX
XXextern int _doserrno;
XX
XXstruct cmd {
XX short command; /* command type */
XX short args; /* command args */
XX short unit; /* command unit */
XX short buf_ofs; /* buffer offset */
XX short buf_seg; /* buffer segment */
XX} ioctl_data;
XXunion REGS inregs, outregs;
XXstruct SREGS segregs;
XXint fd;
XXchar *device = "SCSITAPE";
XXchar far *cp;
XX
XXmain(argc, argv)
XXint argc;
XXchar *argv[];
XX{
XX /*
XX ** say hello
XX */
XX puts(VERSION);
XX if (argc != 1) usage();
XX
XX /*
XX ** verify that this is what the user really wants to do
XX */
XX printf("Do you really wish to erase the tape\n");
XX printf("contained in SCSITAPE unit (y,n)? ");
XX fflush(stdout);
XX if ( getchar() != 'y' )
XX {
XX puts("Aborting erase ....");
XX exit(1);
XX }
XX
XX /*
XX ** put together the command
XX */
XX fd = open(device, O_WRONLY);
XX if ( fd < 0 )
XX {
XX perror(device);
XX exit(1);
XX }
XX inregs.h.ah = 0x44; /* ioctl */
XX inregs.h.al = 0x03; /* write */
XX inregs.x.bx = fd; /* 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 = 'E';
XX
XX /*
XX ** start the format
XX */
XX puts("Now erasing ....");
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 erase.\n", _doserrno);
XX else
XX puts("Erasing complete.");
XX close(fd);
XX exit(0);
XX}
XX
XXusage()
XX{
XX puts("usage: serase");
XX exit(1);
XX}
SHAR_EOF
if test 1658 -ne "`wc -c < 'serase.c'`"
then
echo shar: error transmitting "'serase.c'" '(should have been 1658 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'" '(6833 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
XX if extended_io
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 ?
XX else
XXio_cmd_lba_b2 db ? ;Logical Block Address / Lun
XXio_cmd_lba_b1 db ?
XXio_cmd_lba_b0 db ?
XXio_cmd_cnt_b0 db ? ;Block Count
XXio_cmd_dummy1 db ?
XX endif
XXio_cmd ends
XX
XXtio_cmd struc
XXtio_cmd_op db ? ;Opcode
XXtio_cmd_lun db ? ;Lun
XXtio_cmd_cnt_b2 db ? ;Block Count
XXtio_cmd_cnt_b1 db ?
XXtio_cmd_cnt_b0 db ?
XXtio_cmd_dummy1 db ?
XXtio_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; Load / Unload a Tape
XX;
XXload_cmd struc
XXload_cmd_op db ? ;Opcode
XXload_cmd_lun db ? ;Lun
XXload_cmd_dummy1 db 2 dup (?)
XXload_cmd_type db ? ;Load / Unload
XXload_cmd_dummy2 db ?
XXload_cmd ends
XX
XX;
XX; Structure returned by the sense command
XX;
XXsense struc
XX if extended_sense
XXsense_ccs db ? ;0x70 for Extended Sense
XXsense_dummy1 db ?
XXsense_sense db ? ;Sense (Error) Group
XXsense_lba_b3 db ? ;Failed Block Address
XXsense_lba_b2 db ?
XXsense_lba_b1 db ?
XXsense_lba_b0 db ?
XX else
XXsense_sense db ? ;Sense (Error) code
XXsense_lba_b2 db ? ;Failed Block Address
XXsense_lba_b1 db ?
XXsense_lba_b0 db ?
XX endif
XXsense 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_sense_buf db size sense dup (?)
XXunit ends
XX
XX;
XX; Ioctl Commands
XX;
XXioc struc
XXioc_command dw ? ;Command
XXioc_param dw ? ;Command Dependent Data
XXioc_unit dw ? ;Forced SCSI Unit Number
XXioc_buf_ofs dw ? ;Buffer Offset
XXioc_buf_seg dw ? ;Buffer Segment
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 6833 -ne "`wc -c < 'struct.inc'`"
then
echo shar: error transmitting "'struct.inc'" '(should have been 6833 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'subs.asm'" '(15406 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_sense db SCSI_REQSENSE,0,0,0,size sense,0
XXcmd_format db SCSI_FORMATUNIT,0,0,0,0,0
XX if extended_io
XXcmd_read db SCSI_READBLK,0,0,0,0,0,0,0,1,0
XXcmd_write db SCSI_WRITEBLK,0,0,0,0,0,0,0,1,0
XX else
XXcmd_read db SCSI_READBLK,0,0,0,1,0
XXcmd_write db SCSI_WRITEBLK,0,0,0,1,0
XX endif
XXcmd_tread db SCSI_READBLK,1,0,0,0,0
XXcmd_twrite db SCSI_WRITEBLK,1,0,0,0,0
XXcmd_twritefm db SCSI_WRITEFM,0,0,0,1,0
XXcmd_inquire db SCSI_INQUIRY,0,0,0,size inq,0
XXcmd_erase db SCSI_ERASE,1,0,0,0,0
XXcmd_load db SCSI_LOAD,0,0,0,0,0
XXcmd_capacity db SCSI_READSIZE,0,0,0,0,0,0,0,0,0
XXcmd_verify db SCSI_VERIFYBLK,0,0,0,0,0,0,0,SECT_TRACK,0
XX
XX even
XXdocmd_cmd dw ?
XXdocmd_buf dw ?
XXdocmd_buf_seg dw ?
XXdocmd_len dw ?
XXdocmd_status db ?
XXdocmd_tempb db ?
XX
XX if dump_sense
XXsense_msg db 0dh,07h,'SCSI Unit: 0x'
XXsense_unit db 'xx, Sense Status: 0x'
XXsense_code db 'xx, Block Address: 0x'
XX if extended_sense
XXsense_addr3 db 'xx'
XX endif
XXsense_addr2 db 'xx'
XXsense_addr1 db 'xx'
XXsense_addr0 db 'xx',0dh,0ah,'$'
XX endif
XX
XX;
XX; Reset the SCSI Bus
XX;
XXscsi_reset proc near
XX pusha
XX
XX mov ax,SCSI_CARD_SEG ;Point at the command port
XX mov es,ax
XX mov si,SCSI_CMD_PORT
XX
XX mov 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; Request Sense data from a unit and display the result
XX; Called after every SCSI command with the exit code in 'al'
XX;
XXscsi_sense proc near
XX pushf
XX pusha
XX mov di,cur_unit ;Unit
XX lea bx,[di].unit_sense_buf ;Buffer Offset
XX push ds ;Buffer Segment
XX pop es
XX mov cx,size sense ;Buffer Size
XX lea di,cmd_sense ;Command
XX call docmd
XX if dump_sense
XX jc sense_exit
XX mov di,cur_unit
XX mov dl,[di].unit_select
XX if reserve_addr
XX and dl,07Fh ;Remove Cards Bit
XX endif
XX lea bx,sense_unit ;Unit
XX call hex2asc2
XX mov dl,[di].unit_sense_buf.sense_sense
XX lea bx,sense_code ;Sense
XX call hex2asc2
XX if extended_sense
XX mov dl,[di].unit_sense_buf.sense_lba_b3
XX lea bx,sense_addr3 ;Address
XX call hex2asc2
XX endif
XX mov dl,[di].unit_sense_buf.sense_lba_b2
XX lea bx,sense_addr2
XX call hex2asc2
XX mov dl,[di].unit_sense_buf.sense_lba_b1
XX lea bx,sense_addr1
XX call hex2asc2
XX mov dl,[di].unit_sense_buf.sense_lba_b0
XX lea bx,sense_addr0
XX call hex2asc2
XX lea dx,sense_msg
XX call puts
XX endif
XXsense_exit: popa
XX popf
XX ret
XXscsi_sense endp
XX
XX;
XX; Inquire about the type of a unit
XX;
XX; al = return code, '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 jnc inquire_exit
XX call scsi_sense
XXinquire_exit: pop cx
XX ret
XXscsi_inquire endp
XX
XX;
XX; Determine the size of a disk
XX;
XX; al = return code, 'C' error indicates an error
XX;
XXscsi_capacity proc near
XX push cx
XX mov di,cur_unit ;Unit
XX lea bx,[di].unit_cap_buf ;Buffer Offset
XX push ds ;Buffer Segment
XX pop es
XX mov cx,size cap ;Buffer Size
XX lea di,cmd_capacity ;Command
XX call docmd
XX jnc capacity_exit
XX call scsi_sense
XXcapacity_exit: pop cx
XX ret
XXscsi_capacity endp
XX
XX;
XX; Verify the Track given in an IOCTL Request
XX;
XX; al = return code, '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 jnc verify_exit
XX call scsi_sense
XXverify_exit: ret
XXscsi_verify endp
XX
XX;
XX; Read Some Blocks from the disk given
XX; the request header in es:bx
XX;
XX; al = return code, 'C' indicates an error
XX;
XXdisk_read proc near
XX mov 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 if extended_io
XX mov [di].io_cmd_lba_b3,ah ;Insert Sector
XX endif
XX mov [di].io_cmd_lba_b2,al ;Into the Command
XX
XX if multi_sector
XX mov ax,cx ;Get Sector Count
XX and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
XX jnz disk_r_cok1 ;Check for Boundary
XX mov ax,CHUNK_MAX
XXdisk_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
XXdisk_r_loop: jnc disk_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
XXdisk_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 disk_r_cok2 ;Check for Boundary
XX mov cx,CHUNK_MAX
XXdisk_r_cok2:
XX if extended_io
XX mov [di].io_cmd_cnt_b1,ch ;Insert Sector Count
XX endif
XX mov [di].io_cmd_cnt_b0,cl ;Into the Command
XX 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 disk_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 disk_r_cok3 ;Check for Boundary
XX mov ax,CHUNK_MAX
XXdisk_r_cok3: sub cx,ax ;Dec Sector Count
XX jz disk_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 disk_r_loop
XX else
XX inc dx ;Bump to next Sector
XX add bx,P_SECT
XX loop disk_r_loop
XX clc
XX endif
XXdisk_r_exit: jnc disk_r_exit2 ;If no error occured
XX call scsi_sense ;Display Sense Status
XXdisk_r_exit2: mov es,rh_seg
XX mov bx,rh_off
XX pushf
XX mov ax,es:[bx].rh4_count ;Update the Count
XX sub ax,cx
XX mov es:[bx].rh4_count,ax
XX popf
XX ret
XXdisk_read endp
XX
XX;
XX; Write Some Blocks to the disk given
XX; the request header in es:bx
XX;
XX; al = return code, 'C' indicates an error
XX;
XXdisk_write proc near
XX mov 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 if extended_io
XX mov [di].io_cmd_lba_b3,ah ;Insert Sector
XX endif
XX mov [di].io_cmd_lba_b2,al ;Into the Command
XX
XX if multi_sector
XX mov ax,cx ;Get Sector Count
XX and ax,CHUNK_MAX-1 ;Mask Off the I/O Chunk
XX jnz disk_w_cok1 ;Check for Boundary
XX mov ax,CHUNK_MAX
XXdisk_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
XXdisk_w_loop: jnc disk_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
XXdisk_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 disk_w_cok2 ;Check for Boundary
XX mov cx,CHUNK_MAX
XXdisk_w_cok2:
XX if extended_io
XX mov [di].io_cmd_cnt_b1,ch ;Insert Sector Count
XX endif
XX mov [di].io_cmd_cnt_b0,cl ;Into the Command
XX 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 disk_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 disk_w_cok3 ;Check for Boundary
XX mov ax,CHUNK_MAX
XXdisk_w_cok3: sub cx,ax ;Dec Sector Count
XX jz disk_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 disk_w_loop
XX else
XX inc dx ;Bump to next Sector
XX add bx,P_SECT
XX loop disk_w_loop
XX clc
XX endif
XXdisk_w_exit: jnc disk_w_exit2 ;If no error occured
XX call scsi_sense ;Display Sense Status
XXdisk_w_exit2: mov es,rh_seg
XX mov bx,rh_off
XX pushf
XX mov ax,es:[bx].rh8_count ;Update the Count
XX sub ax,cx
XX mov es:[bx].rh8_count,ax
XX popf
XX ret
XXdisk_write endp
XX
XX;
XX; Read Some Blocks from the Tape
XX;
XXtape_read proc near
XX mov write_flag,FALSE ;Cancel if READ seen
XX mov di,bx
XX mov cx,es:[di].rh4_count ;Byte Count
XX mov ax,cx ;Test for invalid
XX and ax,P_SECT-1 ;Byte Count
XX jz tape_r_ok
XX mov es:[di].rh4_count,0 ;Nothing Read
XX stc ;Oops
XX ret
XXtape_r_ok: mov bx,es:[di].rh4_buf_ofs ;Buffer Offset
XX mov ax,es:[di].rh4_buf_seg ;Buffer Segment
XX mov es,ax
XX mov ax,bx ;Normalize the
XX 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
XX lea di,cmd_tread
XX mov ax,cx ;Convert Bytes
XX shr ax,9 ;to Blocks
XX mov [di].tio_cmd_cnt_b1,ah ;Insert into Command
XX mov [di].tio_cmd_cnt_b0,al
XX call docmd
XX jnc tape_r_exit
XX call scsi_sense
XXtape_r_exit: ret
XXtape_read endp
XX
XX;
XX; Write Some Blocks to the Tape
XX;
XXtape_write proc near
XX mov write_flag,TRUE ;Write Done
XX mov di,bx
XX mov cx,es:[di].rh8_count ;Byte Count
XX mov ax,cx ;Test for invalid
XX and ax,P_SECT-1 ;Byte Count
XX jz tape_w_ok
XX mov es:[di].rh8_count,0 ;Nothing Write
XX mov write_flag,FALSE ;Cancel if ERROR!
XX stc ;Oops
XX ret
XXtape_w_ok: mov cx,es:[di].rh8_count ;Byte Count
XX mov bx,es:[di].rh8_buf_ofs ;Buffer Offset
XX mov ax,es:[di].rh8_buf_seg ;Buffer Segment
XX mov es,ax
XX mov ax,bx ;Normalize the
XX 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
XX lea di,cmd_twrite
XX mov ax,cx ;Convert Bytes
XX shr ax,9 ;to Blocks
XX mov [di].tio_cmd_cnt_b1,ah ;Insert into Command
XX mov [di].tio_cmd_cnt_b0,al
XX call docmd
XX jnc tape_w_exit
XX mov write_flag,FALSE ;Cancel if ERROR!
XX call scsi_sense
XXtape_w_exit: ret
XXtape_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 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 call wait100us ;Spec says wait 90us here
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,CMDBASE or CMDSEL ;Release the data BUS
XX mov es:[si],al
XX call wait100us ;Spec says wait 290us
XX call wait100us ;to abort selection phase
XX call wait100us
XX test byte ptr es:[si],STBSY ;Look one final time
XX jnz cmd_xfer ;Device did answer
XX mov al,CNOCONNECT ;Nothing Answered
XX jmp docmd_exit
XX
XX;
XX; Start the Command
XX;
XXcmd_xfer: call wait100us ;Spec say wait 90us here
XX mov al,CMDBASE or CMDENABLE ;Drop SEL and begin talking
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 or al,al ;Did we have an error?
XX mov al,COK ;Preload OK code
XX jz docmd_exit
XX
XXxfer_error: mov al,CERROR ;Command Failed Somehow
XX
XXdocmd_exit: mov docmd_tempb,al
XX mov al,CMDBASE ;Release the BUS
XX mov es:[si],al
XX pop es
XX popa
XX mov al,docmd_tempb
XX cmp al,COK
XX jz docmd_exit_ok
XX stc
XXdocmd_exit_ok: 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 if multi_sector
XX dec si ;Don't blow the card buffer
XX endif
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 if multi_sector
XX dec di ;Don't blow the card buffer
XX endif
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 15406 -ne "`wc -c < 'subs.asm'`"
then
echo shar: error transmitting "'subs.asm'" '(should have been 15406 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'units.asm'" '(3322 characters)'
if test -f 'units.asm'
then
echo shar: will not over-write existing file "'units.asm'"
else
sed 's/^XX//' > 'units.asm' << \SHAR_EOF
XX;
XX; target information/control structures
XX;
XX even
XXunit0 db size unit dup (-1)
XX even
XXunit1 db size unit dup (-1)
XX even
XXunit2 db size unit dup (-1)
XX even
XXunit3 db size unit dup (-1)
XX even
XXunit4 db size unit dup (-1)
XX even
XXunit5 db size unit dup (-1)
XX even
XXunit6 db size unit dup (-1)
XX ife reserve_addr
XX even
XXunit7 db size unit dup (-1)
XX endif
XX
XX 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 ife reserve_addr
XX dw unit7
XX endif
XX
XX even
XXbpb_array dw bpb0 ;BPB Array for DOS
XX dw bpb1
XX dw bpb2
XX dw bpb3
XX dw bpb4
XX dw bpb5
XX dw bpb6
XX dw bpb7
XX 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
XXtape_unit dw -1
XXcur_unit dw unit0
XXcur_bpb dw bpb0
XX
XX;
XX; Given the request header in es:bx
XX; Return a pointer in ds:di to the unit entry
XX; or 'C' if no such unit exists.
XX;
XX; Do not destroy es:bx !!!
XX;
XXfind_unit proc near
XX pusha
XX mov ah,es:[bx].rh_unit ;What drive did they want
XX lea di,unit_array
XX lea si,bpb_array
XX mov cx,MAXUNIT ;How many to search
XXfind_loop: mov bx,[di] ;Point at a unit
XX mov al,[bx].unit_num_drv ;Does this SCSI device
XX or al,al ;Have any Drives Defined?
XX jz find_next
XX mov dh,[bx].unit_1st_drv ;Get First Drive Number
XXfind_unit_loop: cmp ah,dh ;Is this the correct drive?
XX jz find_match
XX inc si ;Bump to next BPB
XX inc si
XX 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 3322 -ne "`wc -c < 'units.asm'`"
then
echo shar: error transmitting "'units.asm'" '(should have been 3322 characters)'
fi
fi # end of overwriting check
#
# End of shell archive
#
exit 0
More information about the Alt.sources
mailing list