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