briana@tau-ceti.isc-br.com (Brian Who?) (09/09/90)
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