home *** CD-ROM | disk | FTP | other *** search
- From: tin@szebra.szebra.uucp (Tin Le)
- Newsgroups: alt.sources
- Subject: ST-0X 386/ix driver pt 2/6
- Message-ID: <1990Sep17.062917.25505@szebra.uucp>
- Date: 17 Sep 90 06:29:17 GMT
-
- Seagate ST-0x 386/ix driver v1.0
-
- #!/bin/sh
- # this is st02.02 (part 2 of a multipart archive)
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file README continued
- #
- if test ! -r _shar_seq_.tmp; then
- echo 'Please unpack part 1 first!'
- exit 1
- fi
- (read Scheck
- if test "$Scheck" != 2; then
- echo Please unpack part "$Scheck" next!
- exit 1
- else
- exit 0
- fi
- ) < _shar_seq_.tmp || exit 1
- if test ! -f _shar_wnt_.tmp; then
- echo 'x - still skipping README'
- else
- echo 'x - continuing file README'
- sed 's/^X//' << 'SHAR_EOF' >> 'README' &&
- pins A-B shorted CE000H
- pins A-B & C-D shorted DE000H
- X
- The memory address set on the card must match the value defined in the driver.
- Check the driver source for the correct address. If you want to use a
- different address, change the define in the source.
- X
- X
- Interrupt selection
- X
- No jumper installed interrupts disabled (default configuration)
- E-F shorted IRQ3
- F-G shorted IRQ5
- X
- Interrupts must be enabled to use my driver under unix. The interrupt
- selected must match the value in file "config" in the modules/scsi
- directory. Check the config file for the correct value; change the value
- in config file if you wish to use some other value.
- X
- NOTE: at least in the card I received, there were no jumper connectors
- in E, F and G. There were just holes in the card. You have to solder the
- connection yourself. It is not a difficult task if you have ever done
- any soldering, and luckily the card does not cost very much if something
- goes wrong... It is better to ground the soldering iron before doing
- anything.
- X
- If I recall correctly, I am using IRQ5, and soldered F&G together with a
- short wire. A friend of mine had both of those interrupts in use,
- and soldered F to some other interrupt number on the bus and everything
- works fine. However, I can't help with that. For more info, see
- IBM AT technical manual. (You might get some help by sending mail to
- jnopanen@hupu.hut.fi).
- X
- It seems like Seagate has been thinking that the controller would never
- be used with unix...
- X
- X
- I think the 0ws jumper should be connected on most (almost every?)
- machines. On my machine it raised the transfer rate from about 500kB/sec
- to about 700kB/sec under msdos. The transfer rate is really cpu-bound
- as the data transfers are done in software (the card does not support
- dma), so faster machines might get faster transfer rates (mine is a slow
- 16 MHz 386).
- X
- X Tatu Yl|nen ylo@hupu.hut.fi
- X
- SHAR_EOF
- echo 'File README is complete' &&
- chmod 0644 README ||
- echo 'restore of README failed'
- Wc_c="`wc -c < 'README'`"
- test 10877 -eq "$Wc_c" ||
- echo 'README: original size 10877, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= README.2 ==============
- if test -f 'README.2' -a X"$1" != X"-c"; then
- echo 'x - skipping README.2 (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting README.2 (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'README.2' &&
- Copyright (c) 1990 Tin Le
- X
- ST0x SCSI driver version 1.0
- X
- Sunday 9/16/90
- X
- First, to cover my behind (don't you love lawyers? :) )
- X
- DISCLAIMER
- ----------
- X
- X This software has been tested to the best of my abilities.
- X It works for me. However, you use this at your own risks.
- X
- README
- ------
- X
- X SCSI driver for Seagate ST-02 Host Adapter for Interactive
- X 386/ix v2.0.2. Usage rights are release into the public
- X domain. You may use and distribute this package, but you
- X may not charge for it.
- X
- X This is a modified version of the ST-01 driver by Tatu Ylonen.
- X His driver was for Microport UNIX v3.00e, I adapted it for
- X 386/ix, fixed some problems (changed char to unsigned char),
- X optimized things a little bit more.
- X
- X The difference between the ST-01 and ST-02 is that the ST-02
- X also include floppy ctlr (both 5 1/4" and 3 1/2"). Since Tatu
- X wrote his driver, Seagate apparently changed the revision of
- X the ST-0X boards. They now uses 16K BIOS instead of 8K.
- X Luckily, the hardware addresses seemed to have been kept the
- X same (anyone who knows how I can get more technical information
- X on these boards, please let me know - email to tin@szebra.uucp
- X or uunet!claris!szebra!tin).
- X
- X Here is a recap of the featurres and drawbacks of the boards:
- X
- X Advantages:
- X
- X - will work with most SCSI disks
- X - no limit on disk or partition size
- X - each physical driver can have up to 15 partitions
- X - support multiple drives (up to 7) on a single ctrlr
- X - transfer rate faster than MFM disk
- X - the ST-02 (ST-01) will work in the system along with
- X other controller you have (ST506 or RLL).
- X - driver is free and complete SCSI subsystem can be put
- X together at low cost
- X - you have source code!
- X
- X Disadvantages:
- X
- X - does not use DMA
- X - character devices not supported (no raw I/O)
- X - you can not boot from SCSI disk
- X - lots of data movement at each interrupt, which can
- X lead to contention with the serial ports
- X
- X Besides the drives Tatu used, some of the other ones that works
- X are: a CDC Imprimis 94161-156 (150MB formatted), Seagate ST296N
- X (80MB formatted). I used it on my Usenet news node, and also
- X XBBS. As I mentioned, under heavy disk usage, the serial port
- X will start dropping characters. However, I run my Telebit+ at
- X 19200 bps so my guess is that 2400 or less should be OK. I
- X might eventually rewrite the driver interrupt in assembler to
- X help speed up things, but I doubt it'd make much difference.
- X There's only so much that can be done in moving large amounts
- X of data using interrupts driven approach. My suggestion is to
- X use the FAS driver with a 16550AN (that's what I did, and yes
- X it works!).
- X
- X I also have a WD1003 ST506 16 bit controller (since I can't
- X boot on SCSI - yet!) in the system controlling a Micropolis 72MB
- X and 2 floppies.
- X
- X
- INSTALLATION
- ------------
- X
- NOTE: You must be root during this entire installation process!
- X
- X I am assuming that you are using Interactive 386/ix v2.0.2,
- X as that is the only *NIX I have available to me for my 386.
- X If (when) I decide to move to newer versions, I will definitely
- X port the driver.
- X
- X BEFORE YOU DO ANYTHING, BACK UP YOUR DATA FILES!
- X
- X Backup this file:
- X
- X /etc/conf/cf.d/mdevice ---------> /etc/conf/cf.d/mdevice.org
- X
- NOTE:
- The ST-01 and ST-02 comes with BIOS (either 8K or 16K), you
- WILL HAVE TO REMOVE it or the driver won't work. At least it
- didn't for me until I removed the BIOS. Save it somewhere for
- a time you decided to sell the board or <ugh, shudder!> go
- back to MSDOS!
- X
- X There are 2 methods you can use to install the driver. You can
- X use my automated install script, or you can do it by hand. I'll
- X describe how to do it manually in case something went wrong with
- X the script.
- X
- Using install script
- X
- X To use the install script, go to some directory where you have
- X enough room to unpack the driver package. I recommend /tmp or
- X /usr/tmp. Make a directory there call scsi. Unpack the package
- X in there. Then execute install by: sh install. That should
- X do most of the work for you. Go to the next section, running
- X kconfig when it tells you to.
- X
- Manual installation
- X
- X Go to the /etc/conf/pack.d directory, create a scsi directory
- X there and unpack the files in it.
- X
- X Change dir (cd) into /etc/conf/pack.d/scsi
- X
- X You will now need to copy some of the files into the correct
- X directories. The files and their directories are:
- X
- X node.d ----------------> /etc/conf/node.d/scsi
- X sdevice.d ----------------> /etc/conf/sdevice.d/scsi
- X
- X Example: cp node.d /etc/conf/node.d/scsi
- X cp sdevice.d /etc/conf/sdevice.d/scsi
- X
- X You will need to either edit /etc/conf/cf.d/mdevice to add the
- X lines in mdevice or you can do the following:
- X
- X cat mdevice >> /etc/conf/cf.d/mdevice
- X
- X If you have the SDS, then you can recompile the source files.
- X Everything is setup in the makefile for that, so you just need
- X to type make.
- X
- X If you don't have the SDS, then you can use the included
- X pre-compiled object (Driver.o). I am currently using this in
- X my own system, so I know it works.
- X
- X A WARNING: DO NOT USE gcc as it uses a few routines in gcc-lib
- X that the regular kernel libraries do not have. The resulting
- X kernel will be unusable!
- X
- Running kconfig
- X
- X After all the config files have been setup and the driver
- X compiled, you will need to run kconfig to relink the kernel.
- X
- X /etc/kconfig
- X
- X After asking you about Root Directory (just press Enter here), it
- X will give you a menu of 3 choices:
- X
- X MAIN MENU
- X
- X 1) CONFIGURE KERNEL
- X 2) BUILD A KERNEL
- X 3) INSTALL A KERNEL
- X
- X Enter Choice [1-3,q]:
- X
- X Chose choice 2 to build a kernel. That's it. kconfig will build
- X the kernel, then after about 10-15 minutes (depending on how fast
- X your system is), it will ask if you want to install the kernel.
- X At this time, if you are ready to install, then type yes.
- X
- WARNING: installing a new kernel mean that you will have to reboot so
- make sure no one else is on the system and that you don't have anything
- important running!
- X
- X When the system rebooted, the new kernel will be install and you
- X should see the driver copyright message at boot up. If you have
- X a SCSI disk connected to the controller, then the driver will
- X also print its geometry information (manufacturer id, size).
- X
- X Unless you had already somehow formatted and partitioned the
- X disk before hand, you will now need to do just that. Run the
- X program scsipart to low level format the disk and partition
- X it.
- X
- X Interleave: I am currently using 3:1 interleave and block size
- X of 512 bytes, that seems to be the best for my configuration
- X (386/20 Mhz interleaved memory). For those of you lucky enough
- X to have faster systems, you can problably use 1:1 interleave.
- X Just remember that you will need to experiment a little bit
- X to find the best combination for your applications requirements.
- X
- SUMMARY
- -------
- X
- X I will enhance and fix bugs for the package as time permits.
- X Please send me any fixes and enhancements you've made so that
- X I can incorporate it in for the next release. I'd like to
- X keep the changes coordinated so that it is easier on everyone
- X in tracking software versions (and system problems).
- X
- X Comments, fixes/bug reports, fan mails to:
- X
- X tin@szebra.uucp or uunet!claris!szebra!tin
- X
- -- Tin Le
- X
- SHAR_EOF
- chmod 0644 README.2 ||
- echo 'restore of README.2 failed'
- Wc_c="`wc -c < 'README.2'`"
- test 7169 -eq "$Wc_c" ||
- echo 'README.2: original size 7169, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= config ==============
- if test -f 'config' -a X"$1" != X"-c"; then
- echo 'x - skipping config (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting config (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'config' &&
- *
- * config file for scsi driver on Microport System V/386
- * Copyright (c) 9.6.1988 Tatu Yl|nen
- * All rights reserved.
- *
- X
- character(9)
- block(9)
- X
- prefix = scsi
- X
- intvec = 5
- X
- intpri = SPL5
- X
- functions = init, open, close, read, write, ioctl, strategy
- SHAR_EOF
- chmod 0644 config ||
- echo 'restore of config failed'
- Wc_c="`wc -c < 'config'`"
- test 260 -eq "$Wc_c" ||
- echo 'config: original size 260, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= install ==============
- if test -f 'install' -a X"$1" != X"-c"; then
- echo 'x - skipping install (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting install (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'install' &&
- #!/bin/sh
- # Install script for ST-0X SCSI driver
- #
- # 9/16/90 Tin Le
- X
- if test ! `who am i | cut -f1 -d' '` = "root" ; then
- X echo "You must be root to do this!"
- X exit 1
- fi
- X
- PATH=/bin:/usr/bin:/usr/local/bin
- export PATH
- X
- CONFROOT=/etc/conf
- ST02DIR=/etc/conf/pack.d/scsi
- X
- echo;echo
- echo "Checking for /etc/conf directory ..."
- if test ! -d /etc/conf ; then
- X echo "You don't have the kernel config package loaded!"
- X echo "Please load it first before installing this driver."
- X exit 1
- fi
- X
- echo "/etc/conf found, checking for /etc/conf/pack.d directory ..."
- if test ! -d /etc/conf/pack.d ; then
- X echo "/etc/conf/pack.d directory not found!"
- X echo "Did you loaded the kernel config package correctly?"
- X exit 1
- fi
- X
- echo "/etc/conf/pack.d found, checking for scsi directory ..."
- if test ! -d ${ST02DIR} ; then
- X echo "${ST02DIR} does not exist"
- X echo "creating it ..."
- X mkdir /etc/conf/pack.d/scsi
- X echo "moving driver files into it ..."
- X mv * ${ST02DIR}
- else
- X echo "${ST02DIR} exist!"
- X echo "will save files there in ${ST02DIR}/OLD directory"
- X mkdir ${ST02DIR}/OLD
- X mv ${ST02DIR}/* ${ST02DIR}/OLD
- X mv * ${ST02DIR}
- fi
- cd ${ST02DIR}
- X
- echo "Copying sdevice.d to ${CONFROOT}/sdevice.d"
- cp sdevice.d ${CONFROOT}/sdevice.d/scsi
- echo "Copying node.d to ${CONFROOT}/node.d"
- cp node.d ${CONFROOT}/node.d/scsi
- X
- echo "Adding mdevice to ${CONFROOT}/cf.d/mdevice"
- # Back it up first!
- cp ${CONFROOT}/cf.d/mdevice ${CONFROOT}/cf.d/mdevice.org
- cat mdevice >> ${CONFROOT}/cf.d/mdevice
- X
- echo "The package comes with a precompiled Driver.o file."
- echo "You will have to use it if your system do not have the Software"
- echo "Development Package. Or you could recompile it."
- echo -n "Do you wish to use the included Driver.o file? [yes] "
- read ans
- case $ans in
- y*|Y*) echo "Using the included Driver.o file" ;;
- *) echo "Recompiling the source files" ;
- X touch *.c
- X make ;;
- esac
- X
- echo; echo
- echo "All the data and config files have been set up."
- echo "You need to run kconfig now to relink the kernel."
- X
- SHAR_EOF
- chmod 0755 install ||
- echo 'restore of install failed'
- Wc_c="`wc -c < 'install'`"
- test 1975 -eq "$Wc_c" ||
- echo 'install: original size 1975, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= makefile ==============
- if test -f 'makefile' -a X"$1" != X"-c"; then
- echo 'x - skipping makefile (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting makefile (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'makefile' &&
- #
- # makefile for scsi driver
- #
- # Copyright (c) 8.6.1988 Tatu Yl|nen
- # Copyright (c) 16.9.1990 Tin Le
- # All rights reserved.
- #
- # 8/90 Tin
- # Added scsiasm.o to makefile (using ld -r)
- # Added Driver.o, td, scsipart targets
- #
- X
- CC = cc
- #CFLAGS = -O -DASM -fstrength-reduce -fpcc-struct-return -DDEBUG # -DDEBUG0
- #CFLAGS = -O -fstrength-reduce -fpcc-struct-return -DDEBUG # -DDEBUG0
- CFLAGS = -O -DDEBUG -DASM # -DDEBUG0
- X
- all: scsi.o scsiasm.o scsipart Driver.o td
- X
- td: td.c
- X cc td.c -o td -O
- X
- Driver.o: scsi.o scsiasm.o
- X ld -r scsi.o scsiasm.o
- X mv a.out Driver.o
- X
- scsiasm.o: scsiasm.s
- X
- scsi.o: scsi.c scsi.h
- X
- scsipart: scsipart.c scsi.h
- X cc -o scsipart scsipart.c
- X
- SHAR_EOF
- chmod 0644 makefile ||
- echo 'restore of makefile failed'
- Wc_c="`wc -c < 'makefile'`"
- test 673 -eq "$Wc_c" ||
- echo 'makefile: original size 673, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= mdevice ==============
- if test -f 'mdevice' -a X"$1" != X"-c"; then
- echo 'x - skipping mdevice (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting mdevice (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'mdevice' &&
- scsi Iocrwi icbHo scsi 9 60 1 7 -1
- SHAR_EOF
- chmod 0644 mdevice ||
- echo 'restore of mdevice failed'
- Wc_c="`wc -c < 'mdevice'`"
- test 36 -eq "$Wc_c" ||
- echo 'mdevice: original size 36, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= node.d ==============
- if test -f 'node.d' -a X"$1" != X"-c"; then
- echo 'x - skipping node.d (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting node.d (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'node.d' &&
- scsi rscsi0s c 15
- scsi rscsi1s c 15
- SHAR_EOF
- chmod 0644 node.d ||
- echo 'restore of node.d failed'
- Wc_c="`wc -c < 'node.d'`"
- test 36 -eq "$Wc_c" ||
- echo 'node.d: original size 36, current size' "$Wc_c"
- rm -f _shar_wnt_.tmp
- fi
- # ============= scsi.c ==============
- if test -f 'scsi.c' -a X"$1" != X"-c"; then
- echo 'x - skipping scsi.c (File already exists)'
- rm -f _shar_wnt_.tmp
- else
- > _shar_wnt_.tmp
- echo 'x - extracting scsi.c (Text)'
- sed 's/^X//' << 'SHAR_EOF' > 'scsi.c' &&
- /*
- X
- 9/16/90 Tin Le
- X - Released to the world version 1.0
- X
- X Modified for Interactive 386/ix v2.0.2 with some bug fixes
- X and minor enhancements.
- X Will work with ST-02.
- X
- SCSI disk driver for unix system V (Microport system V/386)
- This driver uses the ST-01 controller. This supports multiple initiators
- and multiple targets.
- X
- Copyright (c) 9.6.1988 Tatu Yl|nen
- Copyright (c) 16.9.1988 Tin Le
- X All rights reserved.
- X
- */
- X
- #include <fcntl.h>
- X
- #include <sys/sysmacros.h>
- #include <sys/types.h>
- #include <sys/param.h>
- #include <sys/signal.h>
- #include <sys/errno.h>
- #include <sys/dir.h>
- #include <sys/file.h>
- #include <sys/user.h>
- #include <sys/buf.h>
- #include <sys/iobuf.h>
- #include <sys/immu.h>
- #include <sys/region.h>
- #include <sys/proc.h>
- #include "scsi.h"
- X
- #define COPYRIGHT "SCSI disk driver V1.1 Copyright (c) 9.6.1988 Tatu Yl|nen\n\tCopyright (c) 8.8.1990 Tin Le"
- X
- /* #define ASM */ /* use certain routines coded in assembly */
- X
- #define TICKSPERSECOND HZ /* system timer ticks per second */
- #define RWTIMEOUT 5 /* timeout for read/write waiting for reconnect */
- #define MYSLEEPPRI (PZERO+1) /* sleeping priority (allow signals) */
- #define PAGESIZE 4096 /* page size in sptalloc */
- X
- #define UNITNO(minornum) ((minornum)>>4) /* minor device to unit */
- #define PARTNO(minornum) ((minornum)&15) /* minor device to partition */
- #define BLTOSEC(unit,bl) ((long)(bl)*NBPSCTR/d[unit].blocksize)
- X /* converts block number to sector number */
- #define BLPTOSEC(unit,part,bl) (BLTOSEC(unit,bl)+d[unit].parts[part].start)
- X /* calculates sector number from block and partition */
- X
- #define splnointrs() spl6() /* disable any interrupts to this driver (clock!)*/
- X
- #define NULL 0
- X
- #define SCSIBASE 0x000cb000l /* address of the scsi controller(no rom)*/
- #define SCSICONTROLOFS 0x00000a00l /* control/status port offset */
- #define SCSIDATAOFS 0x00000c00l /* data port offset */
- #define SCSIDATAPORTSZ 1024 /* size of data port */
- #define SCSISIZE 4096 /* size of controller memory area */
- X
- #define MYADDR 0x80 /* my address as bit mask */
- X
- #define CMDENABLE 0x80 /* scsi enable */
- #define CMDENINTR 0x40 /* enable scsi interrupts */
- #define CMDPARENB 0x20 /* enable scsi parity generation */
- #define CMDSTARB 0x10 /* start arbitration bit */
- #define CMDATTN 0x08 /* scsi attention */
- #define CMDBSY 0x04 /* scsi busy */
- #define CMDSEL 0x02 /* scsi select */
- #define CMDRST 0x01 /* scsi reset */
- X
- #define STARBCOMPL 0x80 /* arbitration complete bit */
- #define STPARERR 0x40 /* parity error bit */
- #define STSEL 0x20 /* scsi select */
- #define STREQ 0x10 /* scsi req */
- #define STCD 0x08 /* scsi c/d */
- #define STIO 0x04 /* scsi i/o */
- #define STMSG 0x02 /* scsi msg */
- #define STBSY 0x01 /* scsi busy */
- X
- #define CMDBASE (CMDPARENB|CMDENINTR) /* cmd when doing nothing */
- X
- #define SCSIREAD 0x28 /* read command code (10-byte) */
- #define SCSIWRITE 0x2a /* write command code (10-byte) */
- #define SCSIINQUIRY 0x12 /* inquiry command (6-byte) */
- #define SCSIREADCAPACITY 0x25 /* read drive capacity and block size */
- #define SCSIMODESELECT 0x15 /* select format parameters */
- #define SCSIFORMATUNIT 0x04 /* hard format the scsi drive */
- #define SCSIREQSENSE 0x03 /* request sense command */
- #define SCSITESTREADY 0x00 /* test unit ready command */
- X
- #define MSGMYIDENTIFY 0xc0 /* our identify message to send to target */
- X
- #define MSGCOMPLETE 0x00 /* command complete */
- #define MSGSAVEDATAPTR 0x02 /* save data pointer */
- #define MSGRESTOREPTR 0x03 /* restore pointer */
- #define MSGDISCONNECT 0x04 /* disconnect message */
- #define MSGIDETECTERR 0x05 /* initiator detected error */
- #define MSGABORT 0x06 /* scsi abort message */
- #define MSGMSGREJECT 0x07 /* message reject */
- #define MSGNOP 0x08 /* no operation message */
- #define MSGIDENTIFY 0x80 /* identify message from target */
- X
- #define COK 0 /* command completed successfully */
- #define CNOCONNECT 1 /* no connection could be made to the drive */
- #define CBUSBUSY 2 /* the bus is busy and cannot be cleared */
- #define CTIMEOUT 3 /* timeout waiting for the drive */
- #define CERROR 4 /* an error was returned by the target */
- #define CBUSY 5 /* the drive is busy - wait and retry later */
- #define CDISCONNECT 6 /* target disconnected; this is not an error */
- X
- #ifdef DEBUG0
- static char *Cresults[] = {
- X "COK", "CNOCONNECT", "CBUSBUSY", "CTIMEOUT",
- X "CERROR", "CBUSY", "CDISCONNECT", "BAD_RESULT_CODE"
- };
- #endif
- X
- static unchar *baseaddr=NULL; /* controller base address */
- static unchar *cmdport; /* controller command port */
- unchar *scsidataport; /* controller data port */
- X
- static SCSIDRIVE d[SCSIMAXDRIVES]; /* drive information */
- X
- static struct buf scsibuf; /* used for raw io */
- static unchar rawiobuf[SCSIDATAPORTSZ]; /* data copied temporarily here */
- X
- static char timeouting=0;
- static char intrserviced=0;
- X
- /* marks the unit as not busy and starts any pending io */
- static void marknotbusy();
- X
- /* This generates a hard reset on the scsi bus by asserting the reset line */
- X
- static void resetscsibus()
- {
- X long l;
- X int a;
- X
- X printf("scsi: sending hard reset to scsi bus\n");
- X *cmdport=CMDBASE|CMDENABLE|CMDRST;
- X for (l=0;l<10000l;l++); /* keep rst asserted for a while */
- X *cmdport=CMDBASE;
- X for (l=0;l<500000l;l++); /* give some time to recover before returning */
- X for (a=0;a<SCSIMAXDRIVES;a++)
- X d[a].connected=0; /* do this just in case */
- }
- X
- /* This arbitrates for the scsi bus and selects the desired target. This
- X returns a C* result code. This will also set the connected flag
- X if appropriate. If there are possibly recoverable errors, this will
- X retry. The calling procedure should not retry if this returns
- X failure. */
- X
- static int arbitrate(unit)
- int unit;
- {
- X long l;
- X int arbcnt,bsycnt; /* retry counts */
- X
- X arbcnt=0;
- X bsycnt=0;
- X retryarb:
- X *cmdport=CMDBASE;
- X *scsidataport=MYADDR;
- X *cmdport=(CMDBASE&~CMDENINTR)|CMDSTARB;
- X /* wait for arbitration complete */
- X for (l=0;l<300000l;l++)
- X if (*cmdport & STARBCOMPL)
- X goto gotarb;
- X /* arbitration timeout - someone is keeping the bus reserved. */
- X *cmdport=CMDBASE;
- X if (arbcnt >= 2) /* retry twice, then give up */
- X {
- X printf("scsi: arbitration timeout - someone is sitting on the bus?\n");
- X return CBUSBUSY;
- X }
- X resetscsibus(); /* reset the bus and hope the condition clears */
- X arbcnt++;
- X goto retryarb;
- X gotarb:
- X arbcnt=0;
- X *scsidataport|=1<<unit;
- X *cmdport=CMDBASE|CMDENABLE|CMDSEL|CMDATTN;
- X for (l=0;l<100000l;l++)
- X if (*cmdport & STBSY)
- X goto gotbusy;
- X /* timeout waiting for busy */
- X *cmdport=CMDBASE;
- X if (bsycnt >= 2)
- X {
- #ifdef DEBUG0
- X printf("scsi arbitrate: returning CNOCONNECT\n");
- #endif
- X return CNOCONNECT; /* probably no drive present */
- X }
- X bsycnt++;
- X for (l=0;l<20000l;l++); /* give some time for the drive */
- #ifdef DEBUG0
- X printf("scsi: busy timeout on drive %d\n",unit);
- #endif
- X goto retryarb;
- X gotbusy:
- X d[unit].connected=1;
- X if (!d[unit].nomsgs)
- X {
- X *cmdport=CMDBASE|CMDENABLE|CMDATTN;
- X for (l=0;l<200000l;l++)
- X if ((*cmdport & (STMSG|STCD|STIO|STREQ)) == (STMSG|STCD|0|STREQ))
- X goto gotmsgreq;
- X /* timeout waiting for msg out */
- X printf("scsi: timeout identify msg out - drive %d does not support messages?\n",
- X unit);
- X d[unit].nomsgs=1; /* don't try messages again */
- X *cmdport=CMDBASE|CMDENABLE;
- X return COK;
- X gotmsgreq:
- X *scsidataport=MSGMYIDENTIFY; /* this enables disconnect */
- X /* fall to successful completion */
- X }
- #ifdef DEBUG
- X if (!(*cmdport & STBSY))
- X {
- X printf("scsi: after successful arbitrate !STBSY\n");
- X for (l=0;l<10000000l;l++);
- X arbcnt++;
- X goto retryarb;
- X }
- #endif /* DEBUG */
- X *cmdport=CMDBASE|CMDENABLE;
- X return COK;
- }
- X
- #ifndef ASM
- X
- /* This copies data to the scsi data port as fast as possible. This could
- X even be coded in assembly language for efficiency. */
- X
- static void sendtoscsi(buf,len)
- register unchar *buf;
- register int len;
- {
- X while (len--)
- X *scsidataport=(*buf++);
- }
- X
- /* This reads data from the scsi data port as fast as possible. */
- X
- static void getfromscsi(buf,len)
- register unchar *buf;
- register int len;
- {
- X while (len--)
- X *buf++=(*scsidataport);
- }
- X
- #endif /* ASM */
- X
- /* This implements the scsi data out phase. There are several operating
- X modes for this. 1) normal as fast as possible io 2) slow io where we
- X check req individually for each character 3) moving data directly from
- X user space. If an error is encountered (such as a protection fault when
- X moving data from user space), this will return 0. Moving data from
- X user space is only implemented in "fast" mode. */
- X
- static int dataout(unit)
- int unit;
- {
- X register int le;
- X long l;
- X register char slow;
- X int copyin();
- X
- X slow=d[unit].xferslow;
- X for (;d[unit].xferlen > 0;d[unit].xferlen-=le,d[unit].xferbuf+=le)
- X {
- X for (l=0;l<100000l;l++)
- X if (*cmdport & STREQ)
- X goto gotreq;
- X /* timeout */
- X break;
- X gotreq:
- X if ((*cmdport & (STMSG|STCD|STIO)) != (0|0|0))
- X break;
- X if (slow)
- X {
- X le=1;
- X *scsidataport=(*d[unit].xferbuf);
- X continue;
- X }
- X le=d[unit].xferlen;
- X if (le > SCSIDATAPORTSZ)
- X le=SCSIDATAPORTSZ;
- X if (le > d[unit].blocksize)
- X le=d[unit].blocksize;
- X if (d[unit].xferphys)
- X {
- X if (le > sizeof(rawiobuf))
- X le=sizeof(rawiobuf);
- X if (copyin(d[unit].xferbuf,rawiobuf,le) == -1)
- X return 0;
- X sendtoscsi(rawiobuf,le);
- X }
- X else
- X sendtoscsi(d[unit].xferbuf,le);
- X }
- X while ((*cmdport & (STMSG|STCD|STIO|STREQ)) == (0|0|0|STREQ))
- X {
- X *scsidataport=0;
- X for (l=0;l<4000l;l++)
- X if (*cmdport & STREQ)
- X break;
- X }
- X return 1;
- }
- X
- /* this implements the scsi data in phase. This copies data from
- X scsi bus to system memory. There are three modes of operation:
- X 1) "slow" transfer to kernel memory 2) "fast" transfer to kernel
- X memory 3) "fast" transfer to user memory */
- X
- static int datain(unit)
- int unit;
- {
- X register int le;
- X long l;
- X register char slow;
- X int copyout();
- X
- /* slow=d[unit].xferslow; */
- X slow=1;
- X d[unit].xferphys=0;
- X for (;d[unit].xferlen > 0;d[unit].xferlen-=le,d[unit].xferbuf+=le)
- X {
- X for (l=0;l<100000l;l++)
- X if (*cmdport & STREQ)
- X goto gotreq;
- X /* timeout */
- X break;
- X gotreq:
- X if ((*cmdport & (STMSG|STCD|STIO)) != (0|0|STIO))
- X break;
- X if (slow)
- X {
- X le=1;
- X *d[unit].xferbuf=(*scsidataport);
- X continue;
- X }
- X le=d[unit].xferlen;
- X if (le > SCSIDATAPORTSZ)
- X le=SCSIDATAPORTSZ;
- X if (le > d[unit].blocksize)
- X le=d[unit].blocksize;
- X if (d[unit].xferphys)
- X { /* directly to user space */
- X if (le > sizeof(rawiobuf))
- X le=sizeof(rawiobuf);
- X getfromscsi(rawiobuf,le);
- X if (copyout(rawiobuf,d[unit].xferbuf,le) == -1)
- X return 0;
- X }
- X else
- X getfromscsi(d[unit].xferbuf,le);
- X }
- X while ((*cmdport & (STMSG|STCD|STIO|STREQ)) == (0|0|STIO|STREQ))
- X {
- X le=(*scsidataport);
- X for (l=0;l<4000l;l++)
- X if (*cmdport & STREQ)
- X break;
- X }
- X return 1;
- }
- X
- /* This is called when we are connected to the target on the scsi bus.
- X This will do any exchange of data with the target. The dialog is
- X controlled by the target. This will remain connected until the
- X target sends a disconnect message, the command is complete, or a timeout
- X is encountered. There should be no interrupts while this is executing,
- X as the unit should be connected all the time. This returns a C* completion
- X status. Normally, this should return quite fast. This will never sleep
- X and will also be called at interrupt time. With dumb drives not supporting
- X disconnect (are there any?) this would block the system for the duration
- X of this call. This will only mark the drive not busy if the command
- X completed successfully. If an error is returned, the drive has not
- X been marked not busy. */
- X
- static int doxfernosleep(unit)
- int unit;
- {
- X register int a;
- X long l;
- X
- X for (l=0; l<1000000l || d[unit].xfertimeout == 0; l++)
- X {
- X if (!(*cmdport & STBSY))
- X {
- #ifdef DEBUG
- X printf("scsi doxfernosleep: !STBSY unit %d\n",unit);
- #endif
- X d[unit].connected=0;
- X return CERROR; /* we are no longer connected??? */
- X }
- X if (!(*cmdport & STREQ))
- X continue; /* loop until target requesting something */
- #ifdef DEBUG1
- X printf("scsi doxfernosleep: new state=%x\n",*cmdport);
- #endif
- X switch ((*cmdport & (STMSG|STCD|STIO)) & 0xff)
- X {
- X case 0|0|0: /* data out */
- X if (!dataout(unit))
- X {
- #ifdef DEBUG
- X printf("scsi: dataout returned error; unit=%d\n",unit);
- #endif
- X return CERROR;
- X }
- X break;
- X case 0|0|STIO: /* data in */
- X if (!datain(unit))
- X {
- #ifdef DEBUG
- X printf("scsi: datain returned error; unit=%d\n",unit);
- #endif
- X return CERROR;
- X }
- X break;
- X case 0|STCD|0: /* command out */
- X *scsidataport=(*d[unit].xfercmd++);
- X break;
- X case 0|STCD|STIO: /* status in */
- X d[unit].xferstatus=(*scsidataport);
- X break;
- X case STMSG|STCD|0: /* msg out */
- X /* we should never get here. We don't want to send a message.
- X Lets just drop attention and hope the drive understands. */
- #ifdef DEBUG0
- X printf("scsi: unexpected msg out state; status=%x\n",*cmdport);
- #endif
- X *scsidataport=MSGNOP; /* send a no-operation message */
- X *cmdport=CMDBASE|CMDENABLE;
- X break;
- X case STMSG|STCD|STIO: /* msg in */
- X a=(*scsidataport) & 0xff;
- X switch (a)
- X {
- X case MSGCOMPLETE:
- X d[unit].connected=0;
- X *cmdport=CMDBASE;
- #ifdef DEBUG0
- X printf("scsi: COMMAND complete message received\n");
- #endif
- X if (d[unit].xferstatus == 0) /* completed succesfully */
- X {
- X marknotbusy(unit,COK);
- X return COK;
- X }
- X return CERROR;
- X case MSGSAVEDATAPTR:
- X d[unit].savedbuf=d[unit].xferbuf;
- X d[unit].savedlen=d[unit].xferlen;
- X break;
- X case MSGRESTOREPTR:
- X d[unit].xferbuf=d[unit].savedbuf;
- X d[unit].xferlen=d[unit].savedlen;
- X d[unit].xfercmd=d[unit].savedcmd;
- X break;
- X case MSGDISCONNECT:
- X d[unit].connected=0;
- X d[unit].xfertime=1;
- X *cmdport=CMDBASE;
- #ifdef DEBUG0
- X printf("scsi: disconnected\n");
- #endif
- X return CDISCONNECT;
- X case MSGMSGREJECT:
- X break; /* the target rejected some message... Who cares. */
- X case MSGNOP:
- X break; /* this should not be sent by the target, but... */
- X case MSGIDENTIFY:
- X break; /* we don't care about targets identify messages */
- X default:
- X if (a & 0x80)
- X break; /* assume it is an identify message */
- X printf("scsi: unknown message received from drive %d: %x\n",
- X unit,a);
- X break;
- X }
- X break;
- X default:
- X /* unexpected stack state. Now I don't know what to do. Lets
- X hope the drive changes to another state. */
- #ifdef DEBUG
- X printf("scsi: unexpected bus state: status=%x\n",*cmdport);
- #endif
- X break;
- X }
- X }
- X return CTIMEOUT;
- }
- X
- /* This implements polled wait for reconnect. This is mainly used at
- X system initialization time when the interrupt system may not be fully
- X initialized. This returns true if reconnect was encountered.
- X If there is no successful reconnect, this will time out after a few
- X seconds and return false. */
- X
- static int polledwaitreconnect(unit)
- int unit;
- {
- X long l;
- X unsigned char ch;
- X
- X *cmdport=CMDBASE&~CMDENINTR;
- X for (l=0;l<4000000l;l++)
- X {
- X if ((*cmdport & (STSEL|STIO|STBSY)) != (STSEL|STIO|0))
- X continue;
- X ch=(*scsidataport);
- X if (!(ch & MYADDR))
- X {
- #ifdef DEBUG
- X printf("scsi: polled reselection was not for me: %x\n",ch);
- #endif
- X continue;
- X }
- X ch&=~MYADDR;
- X if (!(ch & (1 << unit)))
- X {
- #ifdef DEBUG
- X printf("scsi: reselecting (polled) unit other than expected: %x\n",
- X ch);
- #endif
- X continue;
- X }
- X *cmdport=(CMDBASE&~CMDENINTR)|CMDBSY|CMDENABLE;
- X for (l=0;l<200000l;l++)
- X if (!(*cmdport & STSEL))
- X break;
- X for (l=0;l<200000l;l++)
- X if (!(*cmdport & STBSY))
- X break;
- X *cmdport=CMDBASE|CMDENABLE;
- X d[unit].connected=1;
- X return 1;
- X }
- X *cmdport=CMDBASE;
- #ifdef DEBUG
- X printf("scsi: timeout polled wait for reselection from %d\n",unit);
- #endif
- X return 0;
- }
- X
- /* This starts the scsi command. Interrupts may be enabled when this is
- X called. When this retuns, either the drive must have been marked not
- X busy (error or completion), or the target has disconnected and the drive
- X will be marked not busy when an interrupt or timeout comes. A failure
- X to mark the drive not busy will block the drive from all future
- X requests. If retries are made for a command, this will be called to
- X start the retry. */
- X
- static int startscsi(unit)
- int unit;
- {
- X int a;
- X
- X d[unit].xferbuf=d[unit].savedbuf=d[unit].origbuf;
- X d[unit].xferlen=d[unit].savedlen=d[unit].origlen;
- X d[unit].xfercmd=d[unit].savedcmd=d[unit].origcmd;
- X
- X startagain:
- X
- #ifdef DEBUG0
- X printf("scsi: arbitrating for %d\n",unit);
- #endif
- X a=arbitrate(unit);
- X if (a != COK) /* arbitrate does the necessary retries */
- X return a;
- X
- #ifdef DEBUG0
- X printf("scsi: arbitration complete\n");
- #endif
- X while (1)
- X {
- X a=doxfernosleep(unit);
- #ifdef DEBUG0
- X printf("scsi: doxfernosleep returned %d=%s\n",
- X a, Cresults[(a>=0 && a<7 ? a : 7)]);
- #endif
- X if (a == CDISCONNECT)
- X { /* The target disconnected */
- X if (d[unit].xferpolled)
- X {
- #ifdef DEBUG0
- X printf("scsi: polled wait\n");
- #endif
- X if (!polledwaitreconnect(unit))
- X goto retry;
- #ifdef DEBUG0
- X printf("scsi: polled wait complete - reconnected\n");
- #endif
- X continue;
- X }
- X if (d[unit].currentbuf)
- X { /* We are doing io for a buffer */
- X /* All we have to do is to return; intr will call iodone. */
- X d[unit].xfertime=1; /* enable timeouts */
- X return CDISCONNECT;
- X }
- X
- X /* disconnect; we do not have a buffer but may use intrs */
- X /* This is not too efficient, as the delay from wakeup to
- X continuing execution might be substantial, but this is not
- X a typical case, as transfers do not normally go to
- X internal buffers. */
- X d[unit].xfertime=1; /* enable timeouts */
- X if (sleep(&d[unit].connected,MYSLEEPPRI|PCATCH) == 1)
- X { /* caught a signal */
- X d[unit].busy=0; /* I guess this is an atomic operation */
- X return CERROR;
- X }
- X if (!d[unit].connected)
- X goto retry; /* it must have been a timeout */
- X continue;
- X }
- X if (a == COK || a == CNOCONNECT || a == CBUSBUSY)
- X {
- X if (a != COK)
- X marknotbusy(unit,a);
- X return a;
- X }
- X goto retry;
- X }
- X retry:
- X /* a possibly recoverable error was encountered */
- #ifdef DEBUG
- X printf("scsi: startscsi: retrying or failing\n");
- #endif
- X if (d[unit].xferretries > 1)
- X {
- X d[unit].xferretries--;
- X goto startagain;
- X }
- X if (a == CTIMEOUT || a == CBUSBUSY)
- X resetscsibus(); /* in case the drive was hanging on the bus */
- X d[unit].connected=0;
- X *cmdport=CMDBASE;
- X marknotbusy(unit,a);
- X return a; /* too many retries - return error */
- }
- X
- /* This executes the given command on the unit. This returns command status
- X (C* constants). There is no need to retry the operation after calling
- X this. */
- X
- static int doscsicmd(unit,cmd,buf,len,timeout,retries,slow,phys,polled,bp)
- int unit, /* drive number */
- X len, /* buffer size */
- X timeout, /* timeout in 1/10 secs if != 0 */
- X retries, /* number of tries before returning failure; 1=try only once */
- X slow, /* set to true if slow transfer (only true for read & write) */
- X phys, /* set to true if xfer directly to/from user space (raw io) */
- X polled; /* set to true if polled transfer */
- unchar *cmd, /* command to execute */
- X *buf; /* transfer buffer address */
- struct buf *bp; /* io buffer being executed, or NULL */
- {
- X int x;
- X
- #ifdef DEBUG0
- X printf("scsi: cmd unit=%d buf=%x len=%d timeout=%d retries=%d slow=%d phys=%d polled=%d bp=%x\n",
- X unit,buf,len,timeout,retries,slow,phys,polled,bp);
- #endif
- X
- X x=splnointrs();
- X if (d[unit].busy)
- X {
- X if (bp)
- X {
- X splx(x);
- X return CBUSY;
- X }
- X while (d[unit].busy)
- X {
- X splx(x);
- X if (sleep(&d[unit].busy,MYSLEEPPRI) == 1)
- X { /* caught a signal */
- X return CERROR;
- X }
- X x=splnointrs();
- X }
- X }
- X d[unit].origbuf=buf;
- X d[unit].origlen=len;
- X d[unit].origcmd=cmd;
- X d[unit].xferslow=slow;
- X d[unit].xferstatus=0x01; /* indicates error */
- X d[unit].xfertimeout=timeout?timeout+1:0;
- X d[unit].xfertime=0;
- X d[unit].xferretries=retries;
- X d[unit].xferphys=phys;
- X d[unit].xferpolled=polled;
- X d[unit].currentbuf=bp;
- X d[unit].busy=1;
- X splx(x);
- X
- X return startscsi(unit);
- }
- X
- static int dorw(unit,sec,buf,len,flags,polled,bp)
- int unit;
- long sec;
- unchar *buf;
- int len,flags,polled;
- struct buf *bp;
- {
- X unchar cmd[10];
- X int nblocks,a;
- X
- X a=d[unit].blocksize;
- X if (a == 0)
- X a=512;
- X nblocks=(len+a-1)/a;
- X
- #ifdef DEBUG0
- X printf("scsi: dorw: unit=%d sec=%d buf=%x len=%d flags=%x polled=%d bp=%x\n",
- X unit,sec,buf,len,flags,polled,bp);
- #endif
- X
- X cmd[0]=(flags & B_READ)?SCSIREAD:SCSIWRITE;
- X cmd[1]=0x00; /* LU & RADDR */
- X cmd[2]=sec >> 24;
- X cmd[3]=sec >> 16;
- X cmd[4]=sec >> 8;
- X cmd[5]=sec;
- X cmd[6]=0;
- X cmd[7]=nblocks >> 8;
- X cmd[8]=nblocks;
- X cmd[9]=0;
- X
- X return doscsicmd(unit,cmd,buf,len,RWTIMEOUT,3,0,flags & B_PHYS,polled,bp);
- }
- X
- /* This starts an io operation on the given buffer. This is called when
- X a new buffer is added to the io queue, and when a previous operation has
- X completed, to start io on the next buffer. If the unit is busy, this will
- X do nothing. If it is not busy, this will start the request. This should
- X be called with splnointrs. Any routines called by this will not change
- X the interrupt level to a lower value. */
- SHAR_EOF
- true || echo 'restore of scsi.c failed'
- fi
- echo 'End of part 2'
- echo 'File scsi.c is continued in part 3'
- echo 3 > _shar_seq_.tmp
- exit 0
- --
- +-----------------------------------------------------------------
- Station Zebra ....!{claris,zorch}!szebra!tin
- Sunnyvale, CA (408) 739-1520 24hrs Telebit+ 300-19200bps
- Pub *NIX, Usenet and mail (no fee)
-