diff options
author | phk <phk@FreeBSD.org> | 1998-12-27 13:06:44 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 1998-12-27 13:06:44 +0000 |
commit | a20df1525176cfcc049d8282308a210b2ffe1095 (patch) | |
tree | d94f351de920f7eec4bbc420b60864f1738e46a1 | |
parent | eb15c87aad94ce69d22c6cbaf4c91c7678b3f397 (diff) | |
download | FreeBSD-src-a20df1525176cfcc049d8282308a210b2ffe1095.zip FreeBSD-src-a20df1525176cfcc049d8282308a210b2ffe1095.tar.gz |
Pre 3.0 branch cleanup casualty #5: nca, sea, wds, uha
No CAM drivers available. If somebody CAMifies one of these, they
will be welcome back in the tree
-rw-r--r-- | share/man/man4/man4.i386/Makefile | 11 | ||||
-rw-r--r-- | share/man/man4/man4.i386/nca.4 | 71 | ||||
-rw-r--r-- | share/man/man4/man4.i386/sea.4 | 90 | ||||
-rw-r--r-- | share/man/man4/man4.i386/uha.4 | 73 | ||||
-rw-r--r-- | sys/amd64/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/conf/NOTES | 18 | ||||
-rw-r--r-- | sys/conf/files.i386 | 6 | ||||
-rw-r--r-- | sys/i386/conf/GENERIC | 3 | ||||
-rw-r--r-- | sys/i386/conf/LINT | 18 | ||||
-rw-r--r-- | sys/i386/conf/NOTES | 18 | ||||
-rw-r--r-- | sys/i386/conf/files.i386 | 6 | ||||
-rw-r--r-- | sys/i386/isa/ic/ncr53400.h | 49 | ||||
-rw-r--r-- | sys/i386/isa/ic/ncr5380.h | 90 | ||||
-rw-r--r-- | sys/i386/isa/ncr5380.c | 1539 | ||||
-rw-r--r-- | sys/i386/isa/seagate.c | 1509 | ||||
-rw-r--r-- | sys/i386/isa/ultra14f.c | 1366 | ||||
-rw-r--r-- | sys/i386/isa/wd7000.c | 727 |
17 files changed, 17 insertions, 5580 deletions
diff --git a/share/man/man4/man4.i386/Makefile b/share/man/man4/man4.i386/Makefile index f976e26..e29a2a2 100644 --- a/share/man/man4/man4.i386/Makefile +++ b/share/man/man4/man4.i386/Makefile @@ -1,13 +1,13 @@ -# $Id: Makefile,v 1.90 1998/12/27 12:44:49 phk Exp $ +# $Id: Makefile,v 1.91 1998/12/27 12:52:39 phk Exp $ MAN4= adv.4 adw.4 aha.4 ahb.4 ahc.4 aic.4 alog.4 apm.4 ar.4 asc.4 bktr.4 \ bt.4 cs.4 cx.4 cy.4 de.4 \ dgb.4 dpt.4 ed.4 el.4 en.4 ep.4 ex.4 fdc.4 fe.4 fxp.4 gsc.4 ie.4 \ io.4 joy.4 keyboard.4 labpc.4 le.4 lnc.4 lp.4 lpt.4 matcd.4 mcd.4 \ - mem.4 meteor.4 mouse.4 mse.4 mtio.4 mx.4 nca.4 ncr.4 npx.4 \ + mem.4 meteor.4 mouse.4 mse.4 mtio.4 mx.4 ncr.4 npx.4 \ pcf.4 pcm.4 perfmon.4 pn.4 pnp.4 ppc.4 psm.4 \ - rdp.4 rl.4 sb.4 scd.4 screen.4 sea.4 si.4 sio.4 \ - spkr.4 sr.4 sysmouse.4 tl.4 tw.4 tx.4 uha.4 vr.4 vx.4 \ + rdp.4 rl.4 sb.4 scd.4 screen.4 si.4 sio.4 \ + spkr.4 sr.4 sysmouse.4 tl.4 tw.4 tx.4 vr.4 vx.4 \ wb.4 wd.4 wfd.4 wl.4 wt.4 xl.4 ze.4 zp.4 MLINKS= adv.4 ../adv.4 @@ -54,7 +54,6 @@ MLINKS+= mouse.4 ../mouse.4 MLINKS+= mse.4 ../mse.4 MLINKS+= mtio.4 ../mtio.4 MLINKS+= mx.4 ../mx.4 -MLINKS+= nca.4 ../nca.4 MLINKS+= ncr.4 ../ncr.4 MLINKS+= npx.4 ../npx.4 MLINKS+= pcf.4 ../pcf.4 @@ -69,7 +68,6 @@ MLINKS+= rl.4 ../rl.4 MLINKS+= sb.4 ../sb.4 MLINKS+= scd.4 ../scd.4 MLINKS+= screen.4 ../screen.4 -MLINKS+= sea.4 ../sea.4 MLINKS+= si.4 ../si.4 MLINKS+= sio.4 ../sio.4 MLINKS+= spkr.4 ../spkr.4 spkr.4 speaker.4 spkr.4 ../speaker.4 @@ -78,7 +76,6 @@ MLINKS+= sysmouse.4 ../sysmouse.4 MLINKS+= tl.4 ../tl.4 MLINKS+= tw.4 ../tw.4 MLINKS+= tx.4 ../tx.4 -MLINKS+= uha.4 ../uha.4 MLINKS+= vr.4 ../vr.4 MLINKS+= vx.4 ../vx.4 MLINKS+= wb.4 ../wb.4 diff --git a/share/man/man4/man4.i386/nca.4 b/share/man/man4/man4.i386/nca.4 deleted file mode 100644 index 1dc00b9..0000000 --- a/share/man/man4/man4.i386/nca.4 +++ /dev/null @@ -1,71 +0,0 @@ -.\"Manual pages for FreeBSD generic NCR-5380/NCR-53C400 SCSI driver. -.\" -.\"Copyright 1994, Serge Vakulenko (vak@cronyx.ru) -.\" -.\"Redistribution and use of this document, with or without -.\"modification, are permitted provided redistributions must retain -.\"the above copyright notice and this condition. -.\" -.\" $Id: nca.4,v 1.5 1997/02/22 13:25:35 peter Exp $ -.Dd January 9, 1995 -.Dt NCA 4 i386 -.Os FreeBSD -.Sh NAME -.Nm nca -.Nd -Generic NCR-5380/NCR-53C400 SCSI adapter driver -.Sh SYNOPSIS -Trantor 130, with IRQ: -.Cd "controller nca0 at isa? port 0x350 bio irq 5" -.Pp -Trantor 130, without IRQ: -.Cd "controller nca0 at isa? port 0x350 -.Pp -ProAudioSpectrum-16, with IRQ: -.Cd "controller nca0 at isa? port 0x1f88 bio irq 5" -.Cd "controller nca1 at isa? port 0x1f84 bio irq 5" -.Cd "controller nca2 at isa? port 0x1f8c bio irq 5" -.Cd "controller nca3 at isa? port 0x1e88 bio irq 5" -.Pp -ProAudioSpectrum-16, without IRQ: -.Cd "controller nca0 at isa? port 0x1f88 -.Cd "controller nca1 at isa? port 0x1f84 -.Cd "controller nca2 at isa? port 0x1f8c -.Cd "controller nca3 at isa? port 0x1e88 -.Sh DESCRIPTION -This driver provides access to SCSI devices connected to -NCR-5380/NCR-53C400 SCSI adapter. -.Pp -It's possible to use the adapter without IRQ line. -The data rate then slightly decreases (by 20-30%). -.Pp -The \fBflags\fP keyword in the configuration file can be used to set -some adapter driver parameters: -.Pp -Bits Description -.br ------------------------------------------- -.br -0x01 Disable SCSI bus parity check. -.Pp -Tested on the following hardware: -.br - Adapter: Trantor T130 - Adapter: ProAudioSpectrum16 -.br - Streamer: Archive Viper 150 -.br - CD-ROM: NEC CDR-25 - CD-ROM: PLEXTOR CD-ROM PX-4XCH -.Sh FILES -.Bl -tag -width Pa -compact -.It Pa /sys/i386/isa/ncr5380.c -.It Pa /sys/i386/isa/ic/ncr5380.h -.It Pa /sys/i386/isa/ic/ncr53400.h -driver source -.El -.Sh SEE ALSO -.Xr cd 4 , -.Xr scsi 4 , -.Xr sd 4 , -.Xr st 4 diff --git a/share/man/man4/man4.i386/sea.4 b/share/man/man4/man4.i386/sea.4 deleted file mode 100644 index 060cbd9..0000000 --- a/share/man/man4/man4.i386/sea.4 +++ /dev/null @@ -1,90 +0,0 @@ -.\"Manual pages for FreeBSD Seagate ST01/02, Future Domain TMC-885, -.\"TMC-950 SCSI driver. -.\" -.\"Copyright 1994, Serge Vakulenko (vak@cronyx.ru) -.\" -.\"Redistribution and use of this document, with or without -.\"modification, are permitted provided redistributions must retain -.\"the above copyright notice and this condition. -.\" -.\" $Id: sea.4,v 1.7 1998/06/08 06:11:59 jkoshy Exp $ -.Dd December 25, 1994 -.Dt SEA 4 i386 -.Os FreeBSD -.Sh NAME -.Nm sea -.Nd -Seagate ST01/ST02, Future Domain TMC-885, TMC-950 SCSI adapter driver -.Sh SYNOPSIS -With explicit memory and IRQ parameters: -.Cd "controller sea0 at isa? bio irq 5 iomem 0xc8000" -.Pp -With automatic memory address detection and no IRQ: -.Cd "controller sea0 at isa? -.Pp -.Cd "controller scbus0 -.Pp -For each connected disk: -.Cd "device sd0 -.Pp -For each connected tape device: -.Cd "device st0 -.Pp -For one or more cdroms: -.Cd "device cd0 -.Sh DESCRIPTION -This driver provides access to SCSI devices connected to Seagate ST01/ST02 or -Future Domain TMC-885, TMC-950 SCSI adapter. -.Pp -It's possible to use the Seagate ST01/ST02 adapter without IRQ line. -The data rate then slightly decreases (by 20-30%). -.Pp -The \fBflags\fP keyword in the configuration file can be used to set -some adapter driver parameters: -.Pp -Bits Description -.br ------------------------------------------- -.br -0x01 Disable SCSI bus parity check. -.Pp -The original Seagate ST02 -BIOS cannot coexist with IDE or any other disk controller -because it does not share BIOS disk drive numbers (80h, 81h) -with others. The probing code of the driver allows using ST02 controller -without BIOS: just unplug the ST02 BIOS chip from the board. -.Pp -Another problem is the floppy adapter on ST02 which could not be -disabled by jumpers. The ST02 adapter it the best as a cheap solution -for attaching the tape and CD-ROM drives, and an extra floppy controller -is just a headache. There exist a simple workaround: cutting off -the AEN signal (A11 contact on ISA connector). AEN then goes high and -disables the floppy adapter port address decoder. -.Pp -Some motherboards also have a problem with ST02 conflicting with IDE during -IDE data write phase. It seems than ST02 makes some noise -on /IOW line. The /IOW line is used only for floppy controller -part of ST02, and because it's rarely needed, cutting off the /IOW -(contact B13) will help. -.Pp -Tested on the following hardware: -.br - Adapter: Seagate ST02 -.br - Disk: HP D1686 -.br -Streamers: Archive Viper 150, Wangtek 5525 -.br - CD-ROMs: Toshiba XM-3401, NEC CDR-25 -.Pp -Maximum data rate is about 270-280 kbytes/sec (on 386DX/40). -.Sh FILES -.Bl -tag -width Pa -compact -.It Pa /sys/i386/isa/seagate.c -driver source -.El -.Sh SEE ALSO -.Xr cd 4 , -.Xr scsi 4 , -.Xr sd 4 , -.Xr st 4 diff --git a/share/man/man4/man4.i386/uha.4 b/share/man/man4/man4.i386/uha.4 deleted file mode 100644 index 4714c42..0000000 --- a/share/man/man4/man4.i386/uha.4 +++ /dev/null @@ -1,73 +0,0 @@ -.\" -.\" Copyright (c) 1994 Wilko Bulte -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote products -.\" derived from this software withough specific prior written permission -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" $Id: uha.4,v 1.9 1998/04/29 17:09:40 andreas Exp $ -.Dd August 31, 1994 -.Dt UHA 4 i386 -.Os FreeBSD -.Sh NAME -.Nm uha -.Nd -UltraStor SCSI host adapter driver -.Sh SYNOPSIS -For ULTRA 24F controllers in EISA mode: -.Cd "controller uha0 at isa? bio irq ?" -.Cd "controller scbus0 -.Pp -For ULTRA 14F and 34F controllers: -.Cd "controller uha0 at isa? port" \&"IO_UHA0\&" bio irq ? drq 5 -.Cd "controller scbus0 -.Pp -For each disk: -.Cd "device sd0 -.Pp -For each tape device: -.Cd "device st0 -.Pp -For one or more cdroms: -.Cd "device cd0 -.Sh DESCRIPTION -This driver provides access to SCSI devices connected to an UltraStor -ULTRA 14F, ULTRA 24F or ULTRA 34F host adapter. -.Pp -Note that for an ULTRA 24F in EISA mode no I/O addresses or DMA channels -are required in the kernel config file. If they are present, the driver -will correctly find the ULTRA 24F, but you tie up precious DMA channels -and I/O ranges which are not used by the card. -The ULTRA 24F uses EISA slot specific I/O which is configured -automatically. -.Sh FILES -.Bl -tag -width Pa -compact -.It Pa /sys/i386/conf/GENERIC -sample generic kernel config file for Bustek and UltraStor based systems -.It Pa /sys/i386/isa/ultra14f.c -driver source -.El -.Sh SEE ALSO -.Xr cd 4 , -.Xr scsi 4 , -.Xr sd 4 , -.Xr st 4 diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC index de0e261..7519449 100644 --- a/sys/amd64/conf/GENERIC +++ b/sys/amd64/conf/GENERIC @@ -11,7 +11,7 @@ # device lines is present in the ./LINT configuration file. If you are # in doubt as to the purpose or necessity of a line, check first in LINT. # -# $Id: GENERIC,v 1.135 1998/12/13 23:04:35 n_hibma Exp $ +# $Id: GENERIC,v 1.136 1998/12/27 12:52:45 phk Exp $ machine "i386" cpu "I386_CPU" @@ -84,7 +84,6 @@ controller adv0 at isa? port ? cam irq ? controller adw0 controller bt0 at isa? port ? cam irq ? controller aha0 at isa? port ? cam irq ? -#controller uha0 at isa? port "IO_UHA0" bio irq ? drq 5 #controller aic0 at isa? port 0x340 bio irq 11 controller scbus0 diff --git a/sys/conf/NOTES b/sys/conf/NOTES index f7b566b..02cca8b 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.514 1998/12/27 12:44:54 phk Exp $ +# $Id: LINT,v 1.515 1998/12/27 12:52:45 phk Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -886,7 +886,7 @@ device npx0 at isa? port IO_NPX iosiz 0x0 flags 0x0 irq 13 # # -# SCSI host adapters: `aha', `aic', `bt', `nca' +# SCSI host adapters: `aha', `aic', `bt' # # adv: All Narrow SCSI bus AdvanSys controllers. # adw: Second Generation AdvanSys controllers including the ADV940UW. @@ -894,10 +894,6 @@ device npx0 at isa? port IO_NPX iosiz 0x0 flags 0x0 irq 13 # ahc: Adaptec 274x/284x/294x # aic: Adaptec 152x and sound cards using the Adaptec AIC-6360 (slow!) # bt: Most Buslogic controllers -# nca: ProAudioSpectrum cards using the NCR 5380 or Trantor T130 -# uha: UltraStor ULTRA 14F/24F/34F -# sea: Seagate ST01/02 8 bit controller (slow!) -# wds: Western Digital WD7000 controller (no scatter/gather!). # # Note that the order is important in order for Buslogic cards to be # probed correctly. @@ -907,17 +903,9 @@ controller bt0 at isa? port "IO_BT0" cam irq ? controller adv0 at isa? port ? cam irq ? controller adw0 controller aha0 at isa? port ? cam irq ? -#!CAM# controller uha0 at isa? port "IO_UHA0" bio irq ? drq 5 #!CAM# controller aic0 at isa? port 0x340 bio irq 11 -#!CAM# controller nca0 at isa? port 0x1f88 bio irq 10 -#!CAM# controller nca1 at isa? port 0x1f84 -#!CAM# controller nca2 at isa? port 0x1f8c -#!CAM# controller nca3 at isa? port 0x1e88 -#!CAM# controller nca4 at isa? port 0x350 bio irq 5 - -#!CAM# controller sea0 at isa? bio irq 5 iomem 0xdc000 iosiz 0x2000 -#!CAM# controller wds0 at isa? port 0x350 bio irq 15 drq 6 + # # ST-506, ESDI, and IDE hard disks: `wdc' and `wd' diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 40ede78..249a285 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.209 1998/12/27 12:44:55 phk Exp $ +# $Id: files.i386,v 1.210 1998/12/27 12:52:46 phk Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -142,7 +142,6 @@ i386/isa/lpt.c optional lpt device-driver i386/isa/labpc.c optional labpc device-driver i386/isa/mcd.c optional mcd device-driver i386/isa/mse.c optional mse device-driver -#i386/isa/ncr5380.c optional nca device-driver i386/isa/npx.c mandatory npx device-driver i386/isa/pcaudio.c optional pca device-driver i386/isa/matcd/matcd.c optional matcd device-driver @@ -158,7 +157,6 @@ i386/isa/random_machdep.c standard i386/isa/rc.c optional rc device-driver i386/isa/rp.c optional rp device-driver i386/isa/scd.c optional scd device-driver -#i386/isa/seagate.c optional sea device-driver i386/isa/si.c optional si device-driver i386/isa/si2_z280.c optional si device-driver i386/isa/si3_t225.c optional si device-driver @@ -238,7 +236,6 @@ i386/isa/scvesactl.c optional sc device-driver i386/isa/videoio.c optional sc device-driver i386/isa/vesa.c optional sc device-driver i386/isa/tw.c optional tw device-driver -#i386/isa/ultra14f.c optional uha device-driver i386/isa/wd.c optional wdc device-driver i386/isa/wd.c optional wd device-driver i386/isa/atapi.c optional atapi device-driver @@ -246,7 +243,6 @@ i386/isa/atapi-cd.c optional acd device-driver i386/isa/wcd.c optional wcd device-driver i386/isa/wfd.c optional wfd device-driver i386/isa/wst.c optional wst device-driver -i386/isa/wd7000.c optional wds device-driver i386/isa/wt.c optional wt device-driver i386/linux/imgact_linux.c optional compat_linux i386/linux/linux_dummy.c optional compat_linux diff --git a/sys/i386/conf/GENERIC b/sys/i386/conf/GENERIC index de0e261..7519449 100644 --- a/sys/i386/conf/GENERIC +++ b/sys/i386/conf/GENERIC @@ -11,7 +11,7 @@ # device lines is present in the ./LINT configuration file. If you are # in doubt as to the purpose or necessity of a line, check first in LINT. # -# $Id: GENERIC,v 1.135 1998/12/13 23:04:35 n_hibma Exp $ +# $Id: GENERIC,v 1.136 1998/12/27 12:52:45 phk Exp $ machine "i386" cpu "I386_CPU" @@ -84,7 +84,6 @@ controller adv0 at isa? port ? cam irq ? controller adw0 controller bt0 at isa? port ? cam irq ? controller aha0 at isa? port ? cam irq ? -#controller uha0 at isa? port "IO_UHA0" bio irq ? drq 5 #controller aic0 at isa? port 0x340 bio irq 11 controller scbus0 diff --git a/sys/i386/conf/LINT b/sys/i386/conf/LINT index f7b566b..02cca8b 100644 --- a/sys/i386/conf/LINT +++ b/sys/i386/conf/LINT @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.514 1998/12/27 12:44:54 phk Exp $ +# $Id: LINT,v 1.515 1998/12/27 12:52:45 phk Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -886,7 +886,7 @@ device npx0 at isa? port IO_NPX iosiz 0x0 flags 0x0 irq 13 # # -# SCSI host adapters: `aha', `aic', `bt', `nca' +# SCSI host adapters: `aha', `aic', `bt' # # adv: All Narrow SCSI bus AdvanSys controllers. # adw: Second Generation AdvanSys controllers including the ADV940UW. @@ -894,10 +894,6 @@ device npx0 at isa? port IO_NPX iosiz 0x0 flags 0x0 irq 13 # ahc: Adaptec 274x/284x/294x # aic: Adaptec 152x and sound cards using the Adaptec AIC-6360 (slow!) # bt: Most Buslogic controllers -# nca: ProAudioSpectrum cards using the NCR 5380 or Trantor T130 -# uha: UltraStor ULTRA 14F/24F/34F -# sea: Seagate ST01/02 8 bit controller (slow!) -# wds: Western Digital WD7000 controller (no scatter/gather!). # # Note that the order is important in order for Buslogic cards to be # probed correctly. @@ -907,17 +903,9 @@ controller bt0 at isa? port "IO_BT0" cam irq ? controller adv0 at isa? port ? cam irq ? controller adw0 controller aha0 at isa? port ? cam irq ? -#!CAM# controller uha0 at isa? port "IO_UHA0" bio irq ? drq 5 #!CAM# controller aic0 at isa? port 0x340 bio irq 11 -#!CAM# controller nca0 at isa? port 0x1f88 bio irq 10 -#!CAM# controller nca1 at isa? port 0x1f84 -#!CAM# controller nca2 at isa? port 0x1f8c -#!CAM# controller nca3 at isa? port 0x1e88 -#!CAM# controller nca4 at isa? port 0x350 bio irq 5 - -#!CAM# controller sea0 at isa? bio irq 5 iomem 0xdc000 iosiz 0x2000 -#!CAM# controller wds0 at isa? port 0x350 bio irq 15 drq 6 + # # ST-506, ESDI, and IDE hard disks: `wdc' and `wd' diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index f7b566b..02cca8b 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -2,7 +2,7 @@ # LINT -- config file for checking all the sources, tries to pull in # as much of the source tree as it can. # -# $Id: LINT,v 1.514 1998/12/27 12:44:54 phk Exp $ +# $Id: LINT,v 1.515 1998/12/27 12:52:45 phk Exp $ # # NB: You probably don't want to try running a kernel built from this # file. Instead, you should start from GENERIC, and add options from @@ -886,7 +886,7 @@ device npx0 at isa? port IO_NPX iosiz 0x0 flags 0x0 irq 13 # # -# SCSI host adapters: `aha', `aic', `bt', `nca' +# SCSI host adapters: `aha', `aic', `bt' # # adv: All Narrow SCSI bus AdvanSys controllers. # adw: Second Generation AdvanSys controllers including the ADV940UW. @@ -894,10 +894,6 @@ device npx0 at isa? port IO_NPX iosiz 0x0 flags 0x0 irq 13 # ahc: Adaptec 274x/284x/294x # aic: Adaptec 152x and sound cards using the Adaptec AIC-6360 (slow!) # bt: Most Buslogic controllers -# nca: ProAudioSpectrum cards using the NCR 5380 or Trantor T130 -# uha: UltraStor ULTRA 14F/24F/34F -# sea: Seagate ST01/02 8 bit controller (slow!) -# wds: Western Digital WD7000 controller (no scatter/gather!). # # Note that the order is important in order for Buslogic cards to be # probed correctly. @@ -907,17 +903,9 @@ controller bt0 at isa? port "IO_BT0" cam irq ? controller adv0 at isa? port ? cam irq ? controller adw0 controller aha0 at isa? port ? cam irq ? -#!CAM# controller uha0 at isa? port "IO_UHA0" bio irq ? drq 5 #!CAM# controller aic0 at isa? port 0x340 bio irq 11 -#!CAM# controller nca0 at isa? port 0x1f88 bio irq 10 -#!CAM# controller nca1 at isa? port 0x1f84 -#!CAM# controller nca2 at isa? port 0x1f8c -#!CAM# controller nca3 at isa? port 0x1e88 -#!CAM# controller nca4 at isa? port 0x350 bio irq 5 - -#!CAM# controller sea0 at isa? bio irq 5 iomem 0xdc000 iosiz 0x2000 -#!CAM# controller wds0 at isa? port 0x350 bio irq 15 drq 6 + # # ST-506, ESDI, and IDE hard disks: `wdc' and `wd' diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index 40ede78..249a285 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.209 1998/12/27 12:44:55 phk Exp $ +# $Id: files.i386,v 1.210 1998/12/27 12:52:46 phk Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -142,7 +142,6 @@ i386/isa/lpt.c optional lpt device-driver i386/isa/labpc.c optional labpc device-driver i386/isa/mcd.c optional mcd device-driver i386/isa/mse.c optional mse device-driver -#i386/isa/ncr5380.c optional nca device-driver i386/isa/npx.c mandatory npx device-driver i386/isa/pcaudio.c optional pca device-driver i386/isa/matcd/matcd.c optional matcd device-driver @@ -158,7 +157,6 @@ i386/isa/random_machdep.c standard i386/isa/rc.c optional rc device-driver i386/isa/rp.c optional rp device-driver i386/isa/scd.c optional scd device-driver -#i386/isa/seagate.c optional sea device-driver i386/isa/si.c optional si device-driver i386/isa/si2_z280.c optional si device-driver i386/isa/si3_t225.c optional si device-driver @@ -238,7 +236,6 @@ i386/isa/scvesactl.c optional sc device-driver i386/isa/videoio.c optional sc device-driver i386/isa/vesa.c optional sc device-driver i386/isa/tw.c optional tw device-driver -#i386/isa/ultra14f.c optional uha device-driver i386/isa/wd.c optional wdc device-driver i386/isa/wd.c optional wd device-driver i386/isa/atapi.c optional atapi device-driver @@ -246,7 +243,6 @@ i386/isa/atapi-cd.c optional acd device-driver i386/isa/wcd.c optional wcd device-driver i386/isa/wfd.c optional wfd device-driver i386/isa/wst.c optional wst device-driver -i386/isa/wd7000.c optional wds device-driver i386/isa/wt.c optional wt device-driver i386/linux/imgact_linux.c optional compat_linux i386/linux/linux_dummy.c optional compat_linux diff --git a/sys/i386/isa/ic/ncr53400.h b/sys/i386/isa/ic/ncr53400.h deleted file mode 100644 index 4a60f01..0000000 --- a/sys/i386/isa/ic/ncr53400.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Definitions for 53C400 SCSI-controller chip. - * - * Derived from Linux NCR-5380 generic driver sources (by Drew Eckhardt). - * - * Copyright (C) 1994 Serge Vakulenko (vak@cronyx.ru) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPERS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _IC_NCR_53C400_H_ -#define _IC_NCR_53C400_H_ - -#define C400_CSR 0 /* rw - Control and Status Reg. */ -#define CSR_5380_ENABLE 0x80 -#define CSR_TRANSFER_DIRECTION 0x40 -#define CSR_TRANSFER_READY_INTR 0x20 -#define CSR_5380_INTR 0x10 -#define CSR_SHARED_INTR 0x08 -#define CSR_HOST_BUF_NOT_READY 0x04 /* read only */ -#define CSR_SCSI_BUF_READY 0x02 /* read only */ -#define CSR_5380_GATED_IRQ 0x01 /* read only */ -#define CSR_BITS "\20\1irq\2sbrdy\3hbrdy\4shintr\5intr\6tintr\7tdir\10enable" - -#define C400_CCR 1 /* rw - Clock Counter Reg. */ -#define C400_HBR 4 /* rw - Host Buffer Reg. */ - -#define C400_5380_REG_OFFSET 8 /* Offset of 5380 registers. */ - -#endif /* _IC_NCR_53C400_H_ */ diff --git a/sys/i386/isa/ic/ncr5380.h b/sys/i386/isa/ic/ncr5380.h deleted file mode 100644 index ce14fec..0000000 --- a/sys/i386/isa/ic/ncr5380.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * <phk@login.dkuug.dk> wrote this file. As long as you retain this notice you - * can do whatever you want with this stuff. If we meet some day, and you think - * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp - * ---------------------------------------------------------------------------- - * Modified by Serge Vakulenko (vak@cronyx.ru) - * - * ncr_5380.h,v 1.2 1994/09/11 20:29:18 phk Exp - * - * Definitions for 5380 SCSI-controller chip. - * - * Derived from "NCR 53C80 Family SCSI Protocol Controller Data Manual" - */ - -#ifndef _IC_NCR_5380_H_ -#define _IC_NCR_5380_H_ - -#define C80_CSDR 0 /* ro - Current SCSI Data Reg. */ -#define C80_ODR 0 /* wo - Output Data Reg. */ - -#define C80_ICR 1 /* rw - Initiator Command Reg. */ -#define ICR_ASSERT_RST 0x80 -#define ICR_ARBITRATION_IN_PROGRESS 0x40 /* read only */ -#define ICR_TRI_STATE_MODE 0x40 /* write only */ -#define ICR_LOST_ARBITRATION 0x20 /* read only */ -#define ICR_DIFF_ENABLE 0x20 /* write only */ -#define ICR_ASSERT_ACK 0x10 -#define ICR_ASSERT_BSY 0x08 -#define ICR_ASSERT_SEL 0x04 -#define ICR_ASSERT_ATN 0x02 -#define ICR_ASSERT_DATA_BUS 0x01 -#define ICR_BITS "\20\1dbus\2atn\3sel\4bsy\5ack\6arblost\7arb\10rst" - -/* - * The mask to use when doing read_modify_write on ICR. - */ -#define ICR_MASK (~(ICR_DIFF_ENABLE | ICR_TRI_STATE_MODE)) - -#define C80_MR 2 /* rw - Mode Reg. */ -#define MR_BLOCK_MODE_DMA 0x80 -#define MR_TARGET_MODE 0x40 -#define MR_ENABLE_PARITY_CHECKING 0x20 -#define MR_ENABLE_PARITY_INTERRUPT 0x10 -#define MR_ENABLE_EOP_INTERRUPT 0x08 -#define MR_MONITOR_BUSY 0x04 -#define MR_DMA_MODE 0x02 -#define MR_ARBITRATE 0x01 -#define MR_BITS "\20\1arb\2dma\3mbusy\4eopintr\5parintr\6pcheck\7targ\10blk" - -#define C80_TCR 3 /* rw - Target Command Reg. */ -#define TCR_LAST_BYTE_SENT 0x80 /* read only */ -#define TCR_ASSERT_REQ 0x08 -#define TCR_ASSERT_MSG 0x04 -#define TCR_ASSERT_CD 0x02 -#define TCR_ASSERT_IO 0x01 -#define TCR_BITS "\20\1i/o\2c/d\3msg\4req\10lastbyte" - -#define C80_CSBR 4 /* ro - Current SCSI Bus Status Reg. */ -#define CSBR_RST 0x80 -#define CSBR_BSY 0x40 -#define CSBR_REQ 0x20 -#define CSBR_MSG 0x10 -#define CSBR_CD 0x08 -#define CSBR_IO 0x04 -#define CSBR_SEL 0x02 -#define CSBR_ACK 0x01 -#define CSBR_BITS "\20\1ack\2sel\3i/o\4c/d\5msg\6req\7bsy\10rst" - -#define C80_SER 4 /* wo - Select Enable Reg. */ - -#define C80_BSR 5 /* ro - Bus and Status Reg. */ -#define BSR_END_OF_DMA_XFER 0x80 -#define BSR_DMA_REQUEST 0x40 -#define BSR_PARITY_ERROR 0x20 -#define BSR_INTERRUPT_REQUEST_ACTIVE 0x10 -#define BSR_PHASE_MISMATCH 0x08 -#define BSR_BUSY_ERROR 0x04 -#define BSR_ATN 0x02 -#define BSR_ACK 0x01 -#define BSR_BITS "\20\1ack\2atn\3busyerr\4pherr\5irq\6parerr\7drq\10dend" - -#define C80_SDSR 5 /* wo - Start DMA Send Reg. */ -#define C80_IDR 6 /* ro - Input Data Reg. */ -#define C80_SDTR 6 /* wo - Start DMA Target Receive Reg. */ -#define C80_RPIR 7 /* ro - Reset Parity/Interrupt Reg. */ -#define C80_SDIR 7 /* wo - Start DMA Initiator Receive Reg. */ - -#endif /* _IC_NCR_5380_H_ */ diff --git a/sys/i386/isa/ncr5380.c b/sys/i386/isa/ncr5380.c deleted file mode 100644 index cb01305..0000000 --- a/sys/i386/isa/ncr5380.c +++ /dev/null @@ -1,1539 +0,0 @@ -/* - * FreeBSD generic NCR-5380/NCR-53C400 SCSI driver - * - * Copyright (C) 1994 Serge Vakulenko (vak@cronyx.ru) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPERS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Tested on the following hardware: - * Adapter: Trantor T130 - * Streamer: Archive Viper 150, - * CD-ROM: NEC CDR-25 - */ -#undef DEBUG - -#include "nca.h" -#if NNCA > 0 - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> - -#include <machine/clock.h> - -#include <i386/isa/isa_device.h> -#include <i386/isa/ic/ncr5380.h> -#include <i386/isa/ic/ncr53400.h> - -#include <scsi/scsiconf.h> - -#ifdef DEBUG -# define PRINT(s) printf s -#else -# define PRINT(s) /*void*/ -#endif - -#define SCB_TABLE_SIZE 8 /* start with 8 scb entries in table */ -#define BLOCK_SIZE 512 /* size of READ/WRITE areas on SCSI card */ -#define HOST_SCSI_ADDR 7 /* address of the adapter on the SCSI bus */ - -/* - * Defice config flags - */ -#define FLAG_NOPARITY 0x01 /* disable SCSI bus parity check */ - -/* - * ProAudioSpectrum registers - */ -#define PAS16_DATA 8 /* Data Register */ -#define PAS16_STAT 9 /* Status Register */ -#define PAS16_STAT_DREQ 0x80 /* Pseudo-DMA ready bit */ -#define PAS16_REG(r) (((r) & 0xc) << 11 | ((r) & 3)) - -static u_char pas16_irq_magic[] = - { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; - -/* - * SCSI bus phases - */ -#define PHASE_MASK (CSBR_MSG | CSBR_CD | CSBR_IO) -#define PHASE_DATAOUT 0 -#define PHASE_DATAIN CSBR_IO -#define PHASE_CMDOUT CSBR_CD -#define PHASE_STATIN (CSBR_CD | CSBR_IO) -#define PHASE_MSGOUT (CSBR_MSG | CSBR_CD) -#define PHASE_MSGIN (CSBR_MSG | CSBR_CD | CSBR_IO) -#define PHASE_NAME(ph) phase_name[(ph)>>2] -#define PHASE_TO_TCR(ph) ((ph) >> 2) - -static char *phase_name[] = { - "DATAOUT", "DATAIN", "CMDOUT", "STATIN", - "Phase4?", "Phase5?", "MSGOUT", "MSGIN", -}; - -/* - * SCSI message codes - */ -#define MSG_COMMAND_COMPLETE 0x00 -#define MSG_SAVE_POINTERS 0x02 -#define MSG_RESTORE_POINTERS 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_ABORT 0x06 -#define MSG_MESSAGE_REJECT 0x07 -#define MSG_NOP 0x08 -#define MSG_BUS_DEV_RESET 0x0c -#define MSG_IDENTIFY(lun) (0xc0 | ((lun) & 0x7)) -#define MSG_ISIDENT(m) ((m) & 0x80) - -/* - * SCSI control block used to keep info about a scsi command - */ -typedef struct scb { - int flags; /* status of the instruction */ -#define SCB_FREE 0x00 -#define SCB_ACTIVE 0x01 -#define SCB_ABORTED 0x02 -#define SCB_TIMEOUT 0x04 -#define SCB_ERROR 0x08 -#define SCB_TIMECHK 0x10 /* we have set a timeout on this one */ -#define SCB_SENSE 0x20 /* sensed data available */ -#define SCB_TBUSY 0x40 /* target busy */ - struct scb *next; /* in free list */ - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ - u_char *data; /* position in data buffer so far */ - int32_t datalen; /* bytes remaining to transfer */ -} scb_t; - -typedef enum { - CTLR_NONE, - CTLR_NCR_5380, - CTLR_NCR_53C400, - CTLR_PAS_16 -} ctlr_t; - -/* - * Data structure describing the target state. - */ -typedef struct { - u_char busy; /* mask of busy luns at device target */ - u_long perrcnt; /* counter of target parity errors */ -} target_t; - -/* - * Data structure describing current status of the scsi bus. One for each - * controller card. - */ -typedef struct { - ctlr_t type; /* Seagate or Future Domain */ - char *name; /* adapter name */ - - /* NCR-5380 controller registers */ - u_short ODR; /* (wo-0) Output Data Register */ - u_short CSDR; /* (ro-0) Current SCSI Data Register */ - u_short ICR; /* (rw-1) Initiator Command Register */ - u_short MR; /* (rw-2) Mode Register */ - u_short TCR; /* (rw-3) Target Command Register */ - u_short SER; /* (wo-4) Select Enable Register */ - u_short CSBR; /* (ro-4) Current SCSI Bus Status Register */ - u_short BSR; /* (ro-5) Bus and Status Register */ - u_short SDSR; /* (wo-5) Start DMA Send Register */ - u_short SDIR; /* (wo-7) Start DMA Initiator Receive Register */ - u_short RPIR; /* (ro-7) Reset Parity/Interrupt Register */ - - /* NCR-53C400 controller registers */ - u_short CSR; /* (rw-0) Control and Status Register */ - u_short CCR; /* (rw-1) Clock Counter Register */ - u_short HBR; /* (rw-4) Host Buffer Register */ - - /* ProAudioSpectrum controller registers */ - u_short PDATA; /* (rw) Pseudo-DMA Data Register */ - u_short PSTAT; /* (rw) Pseudo-DMA Status Register */ - - u_char scsi_addr; /* our scsi address, 0..7 */ - u_char scsi_id; /* our scsi id mask */ - u_char parity; /* parity flag: CMD_EN_PARITY or 0 */ - u_char irq; /* IRQ number used or 0 if no IRQ */ - u_int timeout_active : 1; /* timeout() active (requested) */ - - struct scsi_link sc_link; /* struct connecting different data */ - scb_t *queue; /* waiting to be issued */ - scb_t *disconnected_queue; /* waiting to reconnect */ - - int numscb; /* number of scsi control blocks */ - scb_t *free_scb; /* free scb list */ - scb_t scbs[SCB_TABLE_SIZE]; - - target_t target[8]; /* target state data */ -} adapter_t; - -static adapter_t ncadata[NNCA]; - -#define IS_BUSY(a,b) ((a)->target[(b)->xfer->sc_link->target].busy &\ - (1 << (b)->xfer->sc_link->lun)) -#define SET_BUSY(a,b) ((a)->target[(b)->xfer->sc_link->target].busy |=\ - (1 << (b)->xfer->sc_link->lun)) -#define CLEAR_BUSY(a,b) ((a)->target[(b)->xfer->sc_link->target].busy &=\ - ~(1 << (b)->xfer->sc_link->lun)) - -/* - * Wait for condition, given as an boolean expression. - * Print the message on timeout. - */ -#define WAITFOR(condition,count,message) {\ - register u_long cnt = count; char *_msg = message;\ - while (cnt-- && ! (condition)) continue;\ - if (cnt == -1 && _msg)\ - printf ("nca: %s timeout\n", _msg); } - -static int nca_probe (struct isa_device *dev); -static int nca_attach (struct isa_device *dev); -static int32_t nca_scsi_cmd (struct scsi_xfer *xs); -static u_int32_t nca_adapter_info (int unit); -static void nca_timeout (void *scb); -static void ncaminphys (struct buf *bp); -static void nca_done (adapter_t *z, scb_t *scb); -static void nca_start (adapter_t *z); -static void nca_information_transfer (adapter_t *z, scb_t *scb); -static int nca_poll (adapter_t *z, scb_t *scb); -static int nca_init (adapter_t *z); -static ointhand2_t ncaintr; -static int nca_reselect (adapter_t *z); -static int nca_select (adapter_t *z, scb_t *scb); -static int nca_abort (adapter_t *z, scb_t *scb); -static void nca_send_abort (adapter_t *z); -static u_char nca_msg_input (adapter_t *z); -static void nca_tick (void *arg); -static int nca_sense (adapter_t *z, scb_t *scb); -static void nca_data_output (adapter_t *z, u_char **pdata, u_long *plen); -static void nca_data_input (adapter_t *z, u_char **pdata, u_long *plen); -static void nca_cmd_output (adapter_t *z, u_char *cmd, int cmdlen); -static void nca_53400_dma_xfer (adapter_t *z, int r, u_char **dat, u_long *len); -static void nca_pas_dma_xfer (adapter_t *z, int r, u_char **dat, u_long *len); - -static struct scsi_adapter nca_switch = { - nca_scsi_cmd, ncaminphys, 0, 0, nca_adapter_info, "nca", {0}, -}; -static struct scsi_device nca_dev = { NULL, NULL, NULL, NULL, "nca", 0, {0} }; -struct isa_driver ncadriver = { nca_probe, nca_attach, "nca" }; - -/* - * Check if the device can be found at the port given and if so, - * detect the type of board. Set it up ready for further work. - * Takes the isa_dev structure from autoconf as an argument. - * Returns 1 if card recognized, 0 if errors. - */ -int nca_probe (struct isa_device *dev) -{ - adapter_t *z = &ncadata[dev->id_unit]; - int i; - - /* Init fields used by our routines */ - z->parity = (dev->id_flags & FLAG_NOPARITY) ? 0 : - MR_ENABLE_PARITY_CHECKING; - z->scsi_addr = HOST_SCSI_ADDR; - z->scsi_id = 1 << z->scsi_addr; - z->irq = dev->id_irq ? ffs (dev->id_irq) - 1 : 0; - z->queue = 0; - z->disconnected_queue = 0; - for (i=0; i<8; i++) - z->target[i].busy = 0; - - /* Link up the free list of scbs */ - z->numscb = SCB_TABLE_SIZE; - z->free_scb = z->scbs; - for (i=1; i<SCB_TABLE_SIZE; i++) - z->scbs[i-1].next = z->scbs + i; - z->scbs[SCB_TABLE_SIZE-1].next = 0; - - /* Try NCR 5380. */ - z->type = CTLR_NCR_5380; - z->name = "NCR-5380"; - z->ODR = dev->id_iobase + C80_ODR; - z->CSDR = dev->id_iobase + C80_CSDR; - z->ICR = dev->id_iobase + C80_ICR; - z->MR = dev->id_iobase + C80_MR; - z->TCR = dev->id_iobase + C80_TCR; - z->SER = dev->id_iobase + C80_SER; - z->CSBR = dev->id_iobase + C80_CSBR; - z->BSR = dev->id_iobase + C80_BSR; - z->SDSR = dev->id_iobase + C80_SDSR; - z->SDIR = dev->id_iobase + C80_SDIR; - z->RPIR = dev->id_iobase + C80_RPIR; - z->CSR = 0; - z->CCR = 0; - z->HBR = 0; - z->PDATA = 0; - z->PSTAT = 0; - if (nca_init (z) == 0) - return (8); - - /* Try NCR 53C400. */ - z->type = CTLR_NCR_53C400; - z->name = "NCR-53C400"; - z->ODR = dev->id_iobase + C400_5380_REG_OFFSET + C80_ODR; - z->CSDR = dev->id_iobase + C400_5380_REG_OFFSET + C80_CSDR; - z->ICR = dev->id_iobase + C400_5380_REG_OFFSET + C80_ICR; - z->MR = dev->id_iobase + C400_5380_REG_OFFSET + C80_MR; - z->TCR = dev->id_iobase + C400_5380_REG_OFFSET + C80_TCR; - z->SER = dev->id_iobase + C400_5380_REG_OFFSET + C80_SER; - z->CSBR = dev->id_iobase + C400_5380_REG_OFFSET + C80_CSBR; - z->BSR = dev->id_iobase + C400_5380_REG_OFFSET + C80_BSR; - z->SDSR = dev->id_iobase + C400_5380_REG_OFFSET + C80_SDSR; - z->SDIR = dev->id_iobase + C400_5380_REG_OFFSET + C80_SDIR; - z->RPIR = dev->id_iobase + C400_5380_REG_OFFSET + C80_RPIR; - z->CSR = dev->id_iobase + C400_CSR; - z->CCR = dev->id_iobase + C400_CCR; - z->HBR = dev->id_iobase + C400_HBR; - z->PDATA = 0; - z->PSTAT = 0; - if (nca_init (z) == 0) - return (16); - - /* Try ProAudioSpectrum-16. */ - z->type = CTLR_PAS_16; - z->name = "ProAudioSpectrum"; /* changed later */ - z->ODR = dev->id_iobase ^ PAS16_REG (C80_ODR); - z->CSDR = dev->id_iobase ^ PAS16_REG (C80_CSDR); - z->ICR = dev->id_iobase ^ PAS16_REG (C80_ICR); - z->MR = dev->id_iobase ^ PAS16_REG (C80_MR); - z->TCR = dev->id_iobase ^ PAS16_REG (C80_TCR); - z->SER = dev->id_iobase ^ PAS16_REG (C80_SER); - z->CSBR = dev->id_iobase ^ PAS16_REG (C80_CSBR); - z->BSR = dev->id_iobase ^ PAS16_REG (C80_BSR); - z->SDSR = dev->id_iobase ^ PAS16_REG (C80_SDSR); - z->SDIR = dev->id_iobase ^ PAS16_REG (C80_SDIR); - z->RPIR = dev->id_iobase ^ PAS16_REG (C80_RPIR); - z->CSR = 0; - z->CCR = 0; - z->HBR = 0; - z->PDATA = dev->id_iobase ^ PAS16_REG (PAS16_DATA); - z->PSTAT = dev->id_iobase ^ PAS16_REG (PAS16_STAT); - if (nca_init (z) == 0) - return (4); - - bzero (z, sizeof (*z)); - return (0); -} - -/* - * Probe the adapter, and if found, reset the board and the scsi bus. - * Return 0 if the adapter found. - */ -int nca_init (adapter_t *z) -{ - int i, c; - - if (z->type == CTLR_NCR_53C400) { - if (inb (z->CSR) == 0xFF) - return (100); - - /* Reset 53C400. */ - outb (z->CSR, CSR_5380_ENABLE); - - /* Enable interrupts. */ - outb (z->CSR, z->irq ? CSR_5380_INTR : 0); - } - - if (z->type == CTLR_PAS_16) { - u_short base = z->PDATA & 0x3FF; - - outb (0x9a01, 0xbc + (z-ncadata)); /* unit number */ - outb (0x9a01, base >> 2); - - if (inb (base^0x803) == 0xFF) - return (200); - - if (inb (z->CSDR) == 0xFF && inb (z->CSDR^0x2000) == 0xFF && - inb (z->CSDR) == 0xFF && inb (z->CSDR^0x2000) == 0xFF && - inb (z->CSDR) == 0xFF && inb (z->CSDR^0x2000) == 0xFF && - inb (z->CSDR) == 0xFF && inb (z->CSDR^0x2000) == 0xFF) - return (201); - - i = inb (base^0x803); - outb (base^0x803, i ^ 0xE0); - c = inb (base^0x803); - outb (base^0x803, 1); - if (i != c) - return (202); - - /* Various magic. */ - outb (base^0x4000, 0x30); /* Timeout counter */ - outb (base^0x4001, 0x01); /* Reset TC */ - outb (base^0xbc00, 0x01); /* 1 Wait state */ - outb (base^0x8003, 0x4d); /* sysconfig_4 */ - i = pas16_irq_magic[z->irq]; - if (!i) { - z->irq = 0; - } else { - outb (base^0xf002, i << 4); - outb (base^0x8003, 0x6d); /* sysconfig_4 */ - } - - switch (inb (base^0xEC03) & 0xF) { - case 6: z->name = "ProAudioSpectrum-Plus"; break; - case 12: z->name = "ProAudioSpectrum-16D"; break; - case 14: z->name = "ProAudioSpectrum-CDPC"; break; - case 15: z->name = "ProAudioSpectrum-16"; break; - default: return (203); - } - } - - /* Read RPI port, resetting parity/interrupt state. */ - inb (z->RPIR); - - /* Test BSR: parity error, interrupt request and busy loss state - * should be cleared. */ - if (inb (z->BSR) & (BSR_PARITY_ERROR | - BSR_INTERRUPT_REQUEST_ACTIVE | BSR_BUSY_ERROR)) { - PRINT (("nca: invalid bsr[0x%x]=%b\n", z->BSR, - inb (z->BSR), BSR_BITS)); - return (1); - } - - /* Reset the SCSI bus. */ - outb (z->ICR, ICR_ASSERT_RST); - outb (z->ODR, 0); - /* Hold reset for at least 25 microseconds. */ - DELAY (25); - /* Check that status cleared. */ - if (inb (z->CSBR) != CSBR_RST) { - PRINT (("nca: invalid csbr[0x%x]=%b\n", z->CSBR, - inb (z->CSBR), CSBR_BITS)); - outb (z->ICR, 0); - return (2); - } - /* Clear reset. */ - outb (z->ICR, 0); - /* Wait a Bus Clear Delay (800 ns + bus free delay 800 ns). */ - DELAY (2); - - /* Enable data drivers. */ - outb (z->ICR, ICR_ASSERT_DATA_BUS); - - /* Check that data register is writable. */ - for (i=0; i<256; ++i) { - outb (z->ODR, i); - DELAY (1); - if (inb (z->CSDR) != i) { - PRINT (("nca: ODR[0x%x] not writable: 0x%x should be 0x%x\n", - z->ODR, inb (z->CSDR), i)); - outb (z->ICR, 0); - return (3); - } - } - - /* Disable data drivers. */ - outb (z->ICR, 0); - - /* Check that data register is NOT writable. */ - c = inb (z->CSDR); - for (i=0; i<256; ++i) { - outb (z->ODR, i); - DELAY (1); - if (inb (z->CSDR) != c) { - PRINT (("nca: ODR[0x%x] writable: 0x%x should be 0x%x\n", - z->ODR, inb (z->CSDR), c)); - return (4); - } - } - - /* Initialize the controller. */ - outb (z->MR, z->parity); - outb (z->TCR, 0); - outb (z->SER, z->scsi_id); - return (0); -} - -/* - * Attach all sub-devices we can find. - */ -int nca_attach (struct isa_device *dev) -{ - int unit = dev->id_unit; - adapter_t *z = &ncadata[unit]; - struct scsibus_data *scbus; - - printf ("nca%d: type %s%s\n", unit, z->name, - (dev->id_flags & FLAG_NOPARITY) ? ", no parity" : ""); - - dev->id_ointr = ncaintr; - - /* fill in the prototype scsi_link */ - z->sc_link.adapter_unit = unit; - z->sc_link.adapter_targ = z->scsi_addr; - z->sc_link.adapter_softc = z; - z->sc_link.adapter = &nca_switch; - z->sc_link.device = &nca_dev; - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = &z->sc_link; - - /* ask the adapter what subunits are present */ - scsi_attachdevs (scbus); - - return (1); -} - -/* - * Return some information to the caller about - * the adapter and its capabilities. - */ -u_int32_t nca_adapter_info (int unit) -{ - return (1); -} - -void ncaminphys (struct buf *bp) -{ -} - -/* - * Catch an interrupt from the adaptor. - */ -static void ncaintr (int unit) -{ - adapter_t *z = &ncadata[unit]; - - PRINT (("nca%d: interrupt bsr=%b csbr=%b\n", unit, - inb (z->BSR), BSR_BITS, inb (z->CSBR), CSBR_BITS)); - nca_start (z); - /* Reset interrupt state. */ - inb (z->RPIR); -} - -/* - * This routine is used in the case when we have no IRQ line (z->irq == 0). - * It is called every timer tick and polls for reconnect from target. - */ -void nca_tick (void *arg) -{ - adapter_t *z = arg; - int x = splbio (); - - z->timeout_active = 0; - nca_start (z); - /* Reset interrupt state. */ - inb (z->RPIR); - if (z->disconnected_queue && ! z->timeout_active) { - timeout (nca_tick, z, 1); - z->timeout_active = 1; - } - splx (x); -} - -/* - * Start a scsi operation given the command and the data address. - * Also needs the unit, target and lu. Get a free scb and set it up. - * Call send_scb. Either start timer or wait until done. - */ -int32_t nca_scsi_cmd (struct scsi_xfer *xs) -{ - int unit = xs->sc_link->adapter_unit, flags = xs->flags, x = 0; - adapter_t *z = (adapter_t *)xs->sc_link->adapter_softc; - scb_t *scb; - - /* PRINT (("nca%d/%d/%d command 0x%x\n", unit, xs->sc_link->target, - xs->sc_link->lun, xs->cmd->opcode)); */ - if (xs->bp) - flags |= SCSI_NOSLEEP; - if (flags & ITSDONE) { - printf ("nca%d: already done?", unit); - xs->flags &= ~ITSDONE; - } - if (! (flags & INUSE)) { - printf ("nca%d: not in use?", unit); - xs->flags |= INUSE; - } - if (flags & SCSI_RESET) - printf ("nca%d: SCSI_RESET not implemented\n", unit); - - if (! (flags & SCSI_NOMASK)) - x = splbio (); - - /* Get a free scb. - * If we can and have to, sleep waiting for one to come free. */ - while (! (scb = z->free_scb)) { - if (flags & SCSI_NOSLEEP) { - xs->error = XS_DRIVER_STUFFUP; - if (! (flags & SCSI_NOMASK)) - splx (x); - return (TRY_AGAIN_LATER); - } - tsleep ((caddr_t)&z->free_scb, PRIBIO, "ncascb", 0); - } - /* Get scb from free list. */ - z->free_scb = scb->next; - scb->next = 0; - scb->flags = SCB_ACTIVE; - - /* Put all the arguments for the xfer in the scb */ - scb->xfer = xs; - scb->datalen = xs->datalen; - scb->data = xs->data; - - /* Setup the scb to contain necessary values. - * The interesting values can be read from the xs that is saved. - * I therefore think that the structure can be kept very small. - * The driver doesn't use DMA so the scatter/gather is not needed? */ - if (! z->queue) { - scb->next = z->queue; - z->queue = scb; - } else { - scb_t *q; - - for (q=z->queue; q->next; q=q->next) - continue; - q->next = scb; - scb->next = 0; /* placed at the end of the queue */ - } - - /* Try to send this command to the board. */ - nca_start (z); - - /* Usually return SUCCESSFULLY QUEUED. */ - if (! (flags & SCSI_NOMASK)) { - splx (x); - if (xs->flags & ITSDONE) - /* Timeout timer not started, already finished. - * Tried to return COMPLETE but the machine hanged - * with this. */ - return (SUCCESSFULLY_QUEUED); - xs->timeout_ch = timeout (nca_timeout, (caddr_t) scb, - (xs->timeout * hz) / 1000); - scb->flags |= SCB_TIMECHK; - PRINT (("nca%d/%d/%d command queued\n", unit, - xs->sc_link->target, xs->sc_link->lun)); - return (SUCCESSFULLY_QUEUED); - } - - /* If we can't use interrupts, poll on completion. */ - if (! nca_poll (z, scb)) { - /* We timed out, so call the timeout handler manually, - * accounting for the fact that the clock is not running yet - * by taking out the clock queue entry it makes. */ - nca_timeout ((void*) scb); - - /* Because we are polling, take out the timeout entry - * nca_timeout made. */ - untimeout (nca_timeout, (void*) scb, scb->xfer->timeout_ch); - - if (! nca_poll (z, scb)) - /* We timed out again... This is bad. Notice that - * this time there is no clock queue entry to remove. */ - nca_timeout ((void*) scb); - } - /* PRINT (("nca%d/%d/%d command %s\n", unit, - xs->sc_link->target, xs->sc_link->lun, - xs->error ? "failed" : "done")); */ - return (xs->error ? HAD_ERROR : COMPLETE); -} - -/* - * Coroutine that runs as long as more work can be done. - * Both scsi_cmd() and intr() will try to start it in - * case it is not running. - * Always called with interrupts disabled. - */ -void nca_start (adapter_t *z) -{ - scb_t *q, *prev; -again: - /* First check that if any device has tried - * a reconnect while we have done other things - * with interrupts disabled. */ - if (nca_reselect (z)) - goto again; - - /* Search through the queue for a command - * destined for a target that's not busy. */ - for (q=z->queue, prev=0; q; prev=q, q=q->next) { - /* Attempt to establish an I_T_L nexus here. */ - if (IS_BUSY (z, q) || ! nca_select (z, q)) - continue; - - /* Remove the command from the issue queue. */ - if (prev) - prev->next = q->next; - else - z->queue = q->next; - q->next = 0; - - /* We are connected. Do the task. */ - nca_information_transfer (z, q); - goto again; - } -} - -void nca_timeout (void *arg) -{ - scb_t *scb = (scb_t*) arg; - int unit = scb->xfer->sc_link->adapter_unit; - adapter_t *z = (adapter_t *)scb->xfer->sc_link->adapter_softc; - int x = splbio (); - - if (! (scb->xfer->flags & SCSI_NOMASK)) - printf ("nca%d/%d/%d (%s%d) timed out\n", unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, - scb->xfer->sc_link->device->name, - scb->xfer->sc_link->dev_unit); - - /* If it has been through before, then a previous abort has failed, - * don't try abort again. */ - if (! (scb->flags & SCB_ABORTED)) { - nca_abort (z, scb); - /* 2 seconds for the abort */ - scb->xfer->timeout_ch = timeout (nca_timeout, (caddr_t)scb, - 2*hz); - scb->flags |= (SCB_ABORTED | SCB_TIMECHK); - } else { - /* abort timed out */ - scb->flags |= SCB_ABORTED; - scb->xfer->retries = 0; - nca_done (z, scb); - } - splx (x); -} - -static __inline void nca_sendbyte (adapter_t *z, u_char data) -{ - outb (z->ODR, data); - outb (z->ICR, ICR_ASSERT_DATA_BUS | ICR_ASSERT_ACK); - WAITFOR (! (inb (z->CSBR) & CSBR_REQ), 10000, "sendbyte"); - outb (z->ICR, ICR_ASSERT_DATA_BUS); -} - -static __inline u_char nca_recvbyte (adapter_t *z) -{ - u_char data; - - data = inb (z->CSDR); - outb (z->ICR, ICR_ASSERT_ACK); - WAITFOR (! (inb (z->CSBR) & CSBR_REQ), 10000, "recvbyte"); - outb (z->ICR, 0); - return (data); -} - -/* - * Establish I_T_L or I_T_L_Q nexus for new or existing command - * including ARBITRATION, SELECTION, and initial message out - * for IDENTIFY and queue messages. - * Return 1 if selection succeded. - */ -int nca_select (adapter_t *z, scb_t *scb) -{ - /* Set the phase bits to 0, otherwise the NCR5380 won't drive the - * data bus during SELECTION. */ - outb (z->TCR, 0); - - /* Start arbitration. */ - outb (z->ODR, z->scsi_id); - outb (z->MR, MR_ARBITRATE); - - /* Wait for arbitration logic to complete (20 usec) */ - WAITFOR (inb (z->ICR) & ICR_ARBITRATION_IN_PROGRESS, 200, 0); - if (! (inb (z->ICR) & ICR_ARBITRATION_IN_PROGRESS)) { - PRINT (("nca%d/%d/%d no arbitration progress, bsr=%b csbr=%b\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, inb (z->BSR), BSR_BITS, - inb (z->CSBR), CSBR_BITS)); - outb (z->MR, z->parity); - return (0); - } - DELAY (3); - - /* Check for lost arbitration. */ - if ((inb (z->ICR) & ICR_LOST_ARBITRATION) || - (inb (z->CSDR) >> 1 >> z->scsi_addr) || - (inb (z->ICR) & ICR_LOST_ARBITRATION)) { - PRINT (("nca%d/%d/%d arbitration lost\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - outb (z->MR, z->parity); - return (0); - } - - outb (z->ICR, ICR_ASSERT_SEL); - if (inb (z->ICR) & ICR_LOST_ARBITRATION) { - PRINT (("nca%d/%d/%d arbitration lost after SEL\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - outb (z->ICR, 0); - outb (z->MR, z->parity); - return (0); - } - DELAY (2); - - /* Start selection, asserting the host and target ID's on the bus. */ - outb (z->SER, 0); - outb (z->ODR, z->scsi_id | (1 << scb->xfer->sc_link->target)); - outb (z->ICR, ICR_ASSERT_DATA_BUS | ICR_ASSERT_BSY | - ICR_ASSERT_SEL); - - /* Finish arbitration, drop BSY. */ - outb (z->MR, 0); - outb (z->ICR, ICR_ASSERT_DATA_BUS | ICR_ASSERT_SEL | - ICR_ASSERT_ATN); - DELAY (1); - - /* The SCSI specification calls for a 250 ms timeout for the actual - * selection. */ - WAITFOR (inb (z->CSBR) & CSBR_BSY, 100000, 0); - if (! (inb (z->CSBR) & CSBR_BSY)) { - /* The target does not respond. Not an error, though. */ - PRINT (("nca%d/%d/%d target does not respond\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - outb (z->ICR, 0); - outb (z->SER, z->scsi_id); - outb (z->MR, z->parity); - scb->flags |= SCB_TIMEOUT; - return (0); - } - - /* Clear SEL and SCSI id. - * Wait for start of REQ/ACK handshake. */ - outb (z->ICR, ICR_ASSERT_DATA_BUS | ICR_ASSERT_ATN); - WAITFOR (inb (z->CSBR) & CSBR_REQ, 100000, 0); - if (! (inb (z->CSBR) & CSBR_REQ)) { - PRINT (("nca%d/%d/%d timeout waiting for REQ\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - outb (z->ICR, 0); - outb (z->SER, z->scsi_id); - outb (z->MR, z->parity); - scb->flags |= SCB_ERROR; - return (0); - } - - /* Check for phase mismatch. */ - if ((inb (z->CSBR) & PHASE_MASK) != PHASE_MSGOUT) { - /* This should not be taken as an error, but more like - * an unsupported feature! - * Should set a flag indicating that the target don't support - * messages, and continue without failure. - * (THIS IS NOT AN ERROR!) */ - PRINT (("nca%d/%d/%d waiting for MSGOUT: invalid phase %s\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, - PHASE_NAME (inb (z->CSBR) & PHASE_MASK))); - outb (z->ICR, 0); - outb (z->SER, z->scsi_id); - outb (z->MR, z->parity); - scb->flags |= SCB_ERROR; - return (0); - } - - /* Allow disconnects. */ - outb (z->TCR, PHASE_TO_TCR (PHASE_MSGOUT)); - outb (z->ICR, ICR_ASSERT_DATA_BUS); - nca_sendbyte (z, MSG_IDENTIFY (scb->xfer->sc_link->lun)); - outb (z->ICR, 0); - outb (z->SER, z->scsi_id); - outb (z->MR, z->parity); - - SET_BUSY (z, scb); - return (1); -} - -int nca_reselect (adapter_t *z) -{ - scb_t *q = 0, *prev = 0; - u_char msg, target_mask, lun; -again: - /* Wait for a device to win the reselection phase. */ - /* Signals this by asserting the I/O signal. */ - if ((inb (z->CSBR) & (CSBR_SEL | CSBR_IO | CSBR_BSY)) != - (CSBR_SEL | CSBR_IO)) - return (0); - - /* The data bus contains original initiator id ORed with target id. */ - /* See that we really are the initiator. */ - target_mask = inb (z->CSDR); - if (! (target_mask & z->scsi_id)) { - PRINT (("nca%d reselect not for me: mask=0x%x, csbr=%b\n", - z->sc_link.adapter_unit, target_mask, - inb (z->CSBR), CSBR_BITS)); - goto again; - } - - /* Find target who won. */ - /* Host responds by asserting the BSY signal. */ - /* Target should respond by deasserting the SEL signal. */ - target_mask &= ~z->scsi_id; - outb (z->ICR, ICR_ASSERT_BSY); - WAITFOR (! (inb (z->CSBR) & CSBR_SEL), 10000, "SEL deassert"); - - /* Remove the busy status. */ - /* Target should set the MSGIN phase. */ - outb (z->ICR, 0); - WAITFOR (inb (z->CSBR) & CSBR_REQ, 10000, "MSGIN"); - - /* Hope we get an IDENTIFY message. */ - msg = nca_msg_input (z); - if (MSG_ISIDENT (msg)) { - /* Find the command corresponding to the I_T_L or I_T_L_Q - * nexus we just restablished, and remove it from - * the disconnected queue. */ - lun = (msg & 7); - for (q=z->disconnected_queue; q; prev=q, q=q->next) { - if (target_mask != (1 << q->xfer->sc_link->target)) - continue; - if (lun != q->xfer->sc_link->lun) - continue; - if (prev) - prev->next = q->next; - else - z->disconnected_queue = q->next; - q->next = 0; - PRINT (("nca%d/%d/%d reselect done\n", - z->sc_link.adapter_unit, - ffs (target_mask) - 1, lun)); - nca_information_transfer (z, q); - WAITFOR (! (inb (z->CSBR) & CSBR_BSY), 100000, "reselect !busy"); - return (1); - } - } else - printf ("nca%d reselect: expecting IDENTIFY, got 0x%x\n", - z->sc_link.adapter_unit, msg); - - /* Since we have an established nexus that we can't - * do anything with, we must abort it. */ - nca_send_abort (z); - PRINT (("nca%d reselect aborted\n", z->sc_link.adapter_unit)); - WAITFOR (! (inb (z->CSBR) & CSBR_BSY), 100000, "reselect abort !busy"); - goto again; -} - -/* - * Send an abort to the target. - * Return 1 success, 0 on failure. - * Called on splbio level. - */ -int nca_abort (adapter_t *z, scb_t *scb) -{ - scb_t *q, **prev; - - /* If the command hasn't been issued yet, we simply remove it - * from the issue queue. */ - prev = &z->queue; - for (q=z->queue; q; q=q->next) { - if (scb == q) { - (*prev) = q->next; - q->next = 0; - return (1); - } - prev = &q->next; - } - - /* If the command is currently disconnected from the bus, - * we reconnect the I_T_L or I_T_L_Q nexus associated with it, - * go into message out, and send an abort message. */ - for (q=z->disconnected_queue; q; q=q->next) { - if (scb != q) - continue; - - if (! nca_select (z, scb)) - return (0); - nca_send_abort (z); - - prev = &z->disconnected_queue; - for (q=z->disconnected_queue; q; q=q->next) { - if (scb == q) { - *prev = q->next; - q->next = 0; - /* Set some type of error result - * for the operation. */ - return (1); - } - prev = &q->next; - } - } - - /* Command not found in any queue. */ - return (0); -} - -/* - * The task accomplished, mark the i/o control block as done. - * Always called with interrupts disabled. - */ -void nca_done (adapter_t *z, scb_t *scb) -{ - struct scsi_xfer *xs = scb->xfer; - - if (scb->flags & SCB_TIMECHK) - untimeout (nca_timeout, (caddr_t) scb, xs->timeout_ch); - - /* How much of the buffer was not touched. */ - xs->resid = scb->datalen; - - if (scb->flags != SCB_ACTIVE && ! (xs->flags & SCSI_ERR_OK)) - if (scb->flags & (SCB_TIMEOUT | SCB_ABORTED)) - xs->error = XS_TIMEOUT; - else if (scb->flags & SCB_ERROR) - xs->error = XS_DRIVER_STUFFUP; - else if (scb->flags & SCB_TBUSY) - xs->error = XS_BUSY; - else if (scb->flags & SCB_SENSE) - xs->error = XS_SENSE; - - xs->flags |= ITSDONE; - - /* Free the control block. */ - scb->next = z->free_scb; - z->free_scb = scb; - scb->flags = SCB_FREE; - - /* If there were none, wake anybody waiting for one to come free, - * starting with queued entries. */ - if (! scb->next) - wakeup ((caddr_t) &z->free_scb); - - scsi_done (xs); -} - -/* - * Wait for completion of command in polled mode. - * Always called with interrupts masked out. - */ -int nca_poll (adapter_t *z, scb_t *scb) -{ - int count; - - for (count=0; count<30; ++count) { - DELAY (1000); /* delay for a while */ - nca_start (z); /* retry operation */ - if (scb->xfer->flags & ITSDONE) - return (1); /* all is done */ - if (scb->flags & SCB_TIMEOUT) - return (0); /* no target present */ - } - return (0); -} - -/* - * Perform NCR-53C400 pseudo-dma data transfer. - */ -void nca_53400_dma_xfer (adapter_t *z, int read, u_char **pdata, u_long *plen) -{ - /* Set dma direction. */ - outb (z->CSR, read ? CSR_TRANSFER_DIRECTION : 0); - - /* Enable dma mode. */ - outb (z->MR, MR_DMA_MODE | (read ? z->parity : 0)); - - /* Start dma transfer. */ - outb (read ? z->SDIR : z->SDSR, 0); - - /* Set up clock counter. */ - outb (z->CCR, *plen/128); - - for (; *plen>=128; *plen-=128, *pdata+=128) { - /* Wait for 53C400 host buffer ready. */ - WAITFOR (! (inb (z->CSR) & CSR_HOST_BUF_NOT_READY), 100000, 0); - if (inb (z->CSR) & CSR_HOST_BUF_NOT_READY) - break; - - /* Transfer 128 bytes of data. */ - if (read) - insw (z->HBR, *pdata, 64); - else - outsw (z->HBR, *pdata, 64); - } - - /* Wait for 5380 registers ready. */ - WAITFOR (inb (z->CSR) & CSR_5380_ENABLE, 10000, 0); - if (! (inb (z->CSR) & CSR_5380_ENABLE)) { - /* Reset 53C400. */ - PRINT (("nca%d: reset: pseudo-dma incomplete, csr=%b\n", - z->sc_link.adapter_unit, inb (z->CSR), CSR_BITS)); - outb (z->CSR, CSR_5380_ENABLE); - outb (z->CSR, 0); - } - - /* Wait for FIFO flush on write. */ - if (! read) - WAITFOR (inb (z->TCR) & TCR_LAST_BYTE_SENT, 10000, "last byte"); - - /* Clear dma mode. */ - outb (z->MR, z->parity); - - /* Re-enable interrupts. */ - outb (z->CSR, z->irq ? CSR_5380_INTR : 0); -} - -/* - * Perform PAS-16 pseudo-dma data transfer. - */ -void nca_pas_dma_xfer (adapter_t *z, int read, u_char **pdata, u_long *plen) -{ - /* Enable dma mode. */ - outb (z->MR, MR_DMA_MODE | (read ? z->parity : 0)); - - /* Start dma transfer. */ - outb (read ? z->SDIR : z->SDSR, 0); - - for (; *plen>=512; *plen-=512, *pdata+=512) { - /* Wait for pseudo-DMA request. */ - WAITFOR (inb (z->PSTAT) & PAS16_STAT_DREQ, 10000, "pseudo-dma"); - if (! (inb (z->PSTAT) & PAS16_STAT_DREQ)) - break; - - /* Transfer 512 bytes of data. */ - if (read) - insb (z->PDATA, *pdata, 512); - else - outsb (z->PDATA, *pdata, 512); - } - - /* Clear dma mode. */ - outb (z->MR, z->parity); -} - -/* - * Send data to the target. - */ -void nca_data_output (adapter_t *z, u_char **pdata, u_long *plen) -{ - u_char *data = *pdata; - u_long len = *plen; - - outb (z->ICR, ICR_ASSERT_DATA_BUS); - if (z->type == CTLR_NCR_53C400 && len%128 == 0) - /* Use NCR-53C400 pseudo-dma for data transfer. */ - nca_53400_dma_xfer (z, 0, &data, &len); - else if (z->type == CTLR_PAS_16 && len%512 == 0) - /* Use PAS-16 pseudo-dma for data transfer. */ - nca_pas_dma_xfer (z, 0, &data, &len); - else - for (;;) { - /* Check SCSI bus phase. */ - u_char s = inb (z->CSBR) ^ (CSBR_BSY | PHASE_DATAOUT); - if (s & (CSBR_BSY | PHASE_MASK)) - break; - - /* Wait for REQ. */ - if (! (s & CSBR_REQ)) - continue; - - /* Output data. */ - outb (z->ODR, *data++); - - /* Assert ACK and wait for REQ deassert, - * with irqs disabled. */ - disable_intr (); - outb (z->ICR, ICR_ASSERT_ACK | ICR_ASSERT_DATA_BUS); - WAITFOR (! (inb (z->CSBR) & CSBR_REQ), 1000, 0); - enable_intr (); - - /* Deassert ACK. */ - outb (z->ICR, ICR_ASSERT_DATA_BUS); - --len; - } - outb (z->ICR, 0); - PRINT (("nca (DATAOUT) send %ld bytes\n", *plen - len)); - *plen = len; - *pdata = data; -} - -/* - * Receive data from the target. - */ -void nca_data_input (adapter_t *z, u_char **pdata, u_long *plen) -{ - u_char *data = *pdata; - u_long len = *plen; - - if (z->type == CTLR_NCR_53C400 && len%128 == 0) - /* Use NCR-53C400 pseudo-dma for data transfer. */ - nca_53400_dma_xfer (z, 1, &data, &len); - else if (z->type == CTLR_PAS_16 && len%512 == 0) - /* Use PAS-16 pseudo-dma for data transfer. */ - nca_pas_dma_xfer (z, 1, &data, &len); - else - for (;;) { - /* Check SCSI bus phase. */ - u_char s = inb (z->CSBR) ^ (CSBR_BSY | PHASE_DATAIN); - if (s & (CSBR_BSY | PHASE_MASK)) - break; - - /* Wait for REQ. */ - if (! (s & CSBR_REQ)) - continue; - - /* Input data. */ - *data++ = inb (z->CSDR); - - /* Assert ACK and wait for REQ deassert, - * with irqs disabled. */ - disable_intr (); - outb (z->ICR, ICR_ASSERT_ACK); - WAITFOR (! (inb (z->CSBR) & CSBR_REQ), 1000, 0); - enable_intr (); - - /* Deassert ACK. */ - outb (z->ICR, 0); - --len; - } - PRINT (("nca (DATAIN) got %ld bytes\n", *plen - len)); - *plen = len; - *pdata = data; -} - -/* - * Send the command to the target. - */ -void nca_cmd_output (adapter_t *z, u_char *cmd, int cmdlen) -{ - PRINT (("nca%d send command (%d bytes) ", z->sc_link.adapter_unit, - cmdlen)); - - outb (z->ICR, ICR_ASSERT_DATA_BUS); - while (cmdlen) { - /* Check for target disconnect. */ - u_char sts = inb (z->CSBR); - if (! (sts & CSBR_BSY)) - break; - - /* Check for phase mismatch. */ - if ((sts & PHASE_MASK) != PHASE_CMDOUT) { - printf ("nca: sending command: invalid phase %s\n", - PHASE_NAME (sts & PHASE_MASK)); - break; - } - - /* Wait for REQ. */ - if (! (sts & CSBR_REQ)) - continue; - - PRINT (("-%x", *cmd)); - nca_sendbyte (z, *cmd++); - --cmdlen; - } - outb (z->ICR, 0); - PRINT (("\n")); -} - -/* - * Send the message to the target. - */ -void nca_send_abort (adapter_t *z) -{ - u_char sts; - - outb (z->ICR, ICR_ASSERT_ATN); - - /* Wait for REQ, after which the phase bits will be valid. */ - WAITFOR (inb (z->CSBR) & CSBR_REQ, 1000000, "abort message"); - sts = inb (z->CSBR); - if (! (sts & CSBR_REQ)) - goto ret; - - /* Check for phase mismatch. */ - if ((sts & PHASE_MASK) != PHASE_MSGOUT) { - printf ("nca: sending MSG_ABORT: invalid phase %s\n", - PHASE_NAME (sts & PHASE_MASK)); - goto ret; - } - - outb (z->ICR, ICR_ASSERT_DATA_BUS); - outb (z->TCR, PHASE_TO_TCR (PHASE_MSGOUT)); - nca_sendbyte (z, MSG_ABORT); - - PRINT (("nca%d send MSG_ABORT\n", z->sc_link.adapter_unit)); -ret: outb (z->ICR, 0); -} - -/* - * Get the message from the target. - * Return the length of the received message. - */ -u_char nca_msg_input (adapter_t *z) -{ - u_char sts, msg; - - /* Wait for REQ, after which the phase bits will be valid. */ - WAITFOR (inb (z->CSBR) & CSBR_REQ, 1000000, "message input"); - sts = inb (z->CSBR); - if (! (sts & CSBR_REQ)) - return (MSG_ABORT); - - /* Check for phase mismatch. - * Reached if the target decides that it has finished the transfer. */ - if ((sts & PHASE_MASK) != PHASE_MSGIN) { - printf ("nca: sending message: invalid phase %s\n", - PHASE_NAME (sts & PHASE_MASK)); - return (MSG_ABORT); - } - - /* Do actual transfer from SCSI bus to memory. */ - outb (z->TCR, PHASE_TO_TCR (PHASE_MSGIN)); - msg = nca_recvbyte (z); - PRINT (("nca%d (MSG_INPUT) got 0x%x\n", z->sc_link.adapter_unit, msg)); - return (msg); -} - -/* - * Send request-sense op to the target. - * Return 1 success, 0 on failure. - * Called on splbio level. - */ -int nca_sense (adapter_t *z, scb_t *scb) -{ - u_char cmd[6], status, msg, *data; - u_long len; - - /* Wait for target to disconnect. */ - WAITFOR (! (inb (z->CSBR) & CSBR_BSY), 100000, "sense bus free"); - if (inb (z->CSBR) & CSBR_BSY) - return (0); - - /* Select the target again. */ - if (! nca_select (z, scb)) - return (0); - - /* Wait for CMDOUT phase. */ - WAITFOR (inb (z->CSBR) & CSBR_REQ, 100000, "sense CMDOUT"); - if (! (inb (z->CSBR) & CSBR_REQ) || - (inb (z->CSBR) & PHASE_MASK) != PHASE_CMDOUT) - return (0); - outb (z->TCR, PHASE_TO_TCR (PHASE_CMDOUT)); - - /* Send command. */ - len = sizeof (scb->xfer->sense); - cmd[0] = REQUEST_SENSE; - cmd[1] = scb->xfer->sc_link->lun << 5; - cmd[2] = 0; - cmd[3] = 0; - cmd[4] = len; - cmd[5] = 0; - nca_cmd_output (z, cmd, sizeof (cmd)); - - /* Wait for DATAIN phase. */ - WAITFOR (inb (z->CSBR) & CSBR_REQ, 100000, "sense DATAIN"); - if (! (inb (z->CSBR) & CSBR_REQ) || - (inb (z->CSBR) & PHASE_MASK) != PHASE_DATAIN) - return (0); - outb (z->TCR, PHASE_TO_TCR (PHASE_DATAIN)); - - data = (u_char*) &scb->xfer->sense; - nca_data_input (z, &data, &len); - PRINT (("nca%d sense %x-%x-%x-%x-%x-%x-%x-%x\n", - z->sc_link.adapter_unit, scb->xfer->sense.error_code, - scb->xfer->sense.ext.extended.segment, - scb->xfer->sense.ext.extended.flags, - scb->xfer->sense.ext.extended.info[0], - scb->xfer->sense.ext.extended.info[1], - scb->xfer->sense.ext.extended.info[2], - scb->xfer->sense.ext.extended.info[3], - scb->xfer->sense.ext.extended.extra_len)); - - /* Wait for STATIN phase. */ - WAITFOR (inb (z->CSBR) & CSBR_REQ, 100000, "sense STATIN"); - if (! (inb (z->CSBR) & CSBR_REQ) || - (inb (z->CSBR) & PHASE_MASK) != PHASE_STATIN) - return (0); - outb (z->TCR, PHASE_TO_TCR (PHASE_STATIN)); - - status = nca_recvbyte (z); - - /* Wait for MSGIN phase. */ - WAITFOR (inb (z->CSBR) & CSBR_REQ, 100000, "sense MSGIN"); - if (! (inb (z->CSBR) & CSBR_REQ) || - (inb (z->CSBR) & PHASE_MASK) != PHASE_MSGIN) - return (0); - outb (z->TCR, PHASE_TO_TCR (PHASE_MSGIN)); - - msg = nca_recvbyte (z); - - if (status != 0 || msg != 0) - printf ("nca%d: bad sense status=0x%x, msg=0x%x\n", - z->sc_link.adapter_unit, status, msg); - return (1); -} - -/* - * Do the transfer. We know we are connected. Update the flags, - * call nca_done when task accomplished. Dialog controlled by the target. - * Always called with interrupts disabled. - */ -void nca_information_transfer (adapter_t *z, scb_t *scb) -{ - u_char *data = scb->data; /* current data buffer */ - u_long datalen = scb->datalen; /* current data transfer size */ - register u_char sts; - u_char msg; - - while ((sts = inb (z->CSBR)) & CSBR_BSY) { - /* We only have a valid SCSI phase when REQ is asserted. */ - if (! (sts & CSBR_REQ)) - continue; - if (inb (z->BSR) & BSR_PARITY_ERROR) { - int target = scb->xfer->sc_link->target; - if (++z->target[target].perrcnt <= 8) - printf ("nca%d/%d/%d parity error\n", - z->sc_link.adapter_unit, target, - scb->xfer->sc_link->lun); - if (z->target[target].perrcnt == 8) - printf ("nca%d/%d/%d too many parity errors, not logging any more\n", - z->sc_link.adapter_unit, target, - scb->xfer->sc_link->lun); - /* Clear parity error. */ - inb (z->RPIR); - } - outb (z->TCR, PHASE_TO_TCR (sts & PHASE_MASK)); - switch (sts & PHASE_MASK) { - case PHASE_DATAOUT: - if (datalen <= 0) { - printf ("nca%d/%d/%d data length underflow\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun); - /* send zero byte */ - outb (z->ICR, ICR_ASSERT_DATA_BUS); - nca_sendbyte (z, 0); - outb (z->ICR, 0); - break; - } - nca_data_output (z, &data, &datalen); - break; - case PHASE_DATAIN: - if (datalen <= 0) { - /* Get extra data. Some devices (e.g. CDROMs) - * use fixed-length blocks (e.g. 2k), - * even if we need less. */ - PRINT (("@")); - nca_recvbyte (z); - break; - } - nca_data_input (z, &data, &datalen); - break; - case PHASE_CMDOUT: - nca_cmd_output (z, (u_char*) scb->xfer->cmd, - scb->xfer->cmdlen); - break; - case PHASE_STATIN: - scb->xfer->status = nca_recvbyte (z); - PRINT (("nca%d/%d/%d (STATIN) got 0x%x\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, - (u_char) scb->xfer->status)); - break; - case PHASE_MSGOUT: - /* Send no-op message. */ - outb (z->ICR, ICR_ASSERT_DATA_BUS); - nca_sendbyte (z, MSG_NOP); - outb (z->ICR, 0); - PRINT (("nca%d/%d/%d (MSGOUT) send NOP\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - break; - case PHASE_MSGIN: - /* Don't handle multi-byte messages here, because they - * should not be present here. */ - msg = nca_recvbyte (z); - PRINT (("nca%d/%d/%d (MSGIN) got 0x%x\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, msg)); - switch (msg) { - case MSG_COMMAND_COMPLETE: - scb->data = data; - scb->datalen = datalen; - /* In the case of check-condition status, - * perform the request-sense op. */ - switch (scb->xfer->status & 0x1e) { - case SCSI_CHECK: - if (nca_sense (z, scb)) - scb->flags = SCB_SENSE; - break; - case SCSI_BUSY: - scb->flags = SCB_TBUSY; - break; - } - goto done; - case MSG_ABORT: - printf ("nca: command aborted by target\n"); - scb->flags = SCB_ABORTED; - goto done; - case MSG_MESSAGE_REJECT: - printf ("nca: message rejected\n"); - scb->flags = SCB_ABORTED; - goto done; - case MSG_DISCONNECT: - scb->next = z->disconnected_queue; - z->disconnected_queue = scb; - if (! z->irq && ! z->timeout_active) { - timeout (nca_tick, z, 1); - z->timeout_active = 1; - } - PRINT (("nca%d/%d/%d disconnected\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - goto ret; - case MSG_SAVE_POINTERS: - scb->data = data; - scb->datalen = datalen; - break; - case MSG_RESTORE_POINTERS: - data = scb->data; - datalen = scb->datalen; - break; - default: - printf ("nca%d/%d/%d unknown message: 0x%x\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, msg); - break; - } - break; - default: - printf ("nca: unknown phase: %b\n", sts, CSBR_BITS); - break; - } - } - printf ("nca%d/%d/%d unexpected target disconnect\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun); - scb->flags = SCB_ERROR; -done: - CLEAR_BUSY (z, scb); - nca_done (z, scb); -ret: - outb (z->ICR, 0); - outb (z->TCR, 0); - outb (z->SER, z->scsi_id); - WAITFOR (! (inb (z->CSBR) & CSBR_BSY), 100000, "xfer bus free"); -} -#endif /* NNCA */ diff --git a/sys/i386/isa/seagate.c b/sys/i386/isa/seagate.c deleted file mode 100644 index 30ca28c..0000000 --- a/sys/i386/isa/seagate.c +++ /dev/null @@ -1,1509 +0,0 @@ -/* - * (Free/Net/386)BSD ST01/02, Future Domain TMC-885, TMC-950 SCSI driver for - * Julians SCSI-code - * - * Copyright 1994, Kent Palmkvist (kentp@isy.liu.se) - * Copyright 1994, Robert Knier (rknier@qgraph.com) - * Copyright 1992, 1994 Drew Eckhardt (drew@colorado.edu) - * Copyright 1994, Julian Elischer (julian@tfs.com) - * Copyright 1994-1995, Serge Vakulenko (vak@cronyx.ru) - * Copyright 1995 Stephen Hocking (sysseh@devetir.qld.gov.au) - * - * Others that has contributed by example code is - * Glen Overby (overby@cray.com) - * Tatu Yllnen - * Brian E Litzinger - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPERS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * kentp 940307 alpha version based on newscsi-03 version of Julians SCSI-code - * kentp 940314 Added possibility to not use messages - * rknier 940331 Added fast transfer code - * rknier 940407 Added assembler coded data transfers - * vak 941226 New probe algorithm, based on expected behaviour - * instead of BIOS signatures analysis, better timeout handling, - * new asm fragments for data input/output, target-dependent - * delays, device flags, polling mode, generic cleanup - * vak 950115 Added request-sense ops - * seh 950701 Fixed up Future Domain TMC-885 problems with disconnects, - * weird phases and the like. (we could probably investigate - * what the board's idea of the phases are, but that requires - * doco that I don't have). Note that it is slower than the - * 2.0R driver with both SEA_BLINDTRANSFER & SEA_ASSEMBLER - * defined by a factor of more than 2. I'll look at that later! - * seh 950712 The performance release 8^). Put in the blind transfer code - * from the 2.0R source. Don't use it by commenting out the - * SEA_BLINDTRANSFER below. Note that it only kicks in during - * DATAOUT or DATAIN and then only when the transfer is a - * multiple of BLOCK_SIZE bytes (512). Most devices fit into - * that category, with the possible exception of scanners and - * some of the older MO drives. - * - * $Id: seagate.c,v 1.31 1998/08/11 17:22:42 bde Exp $ - */ - -/* - * What should really be done: - * - * Restructure interrupt enable/disable code (runs too long with int disabled) - * Add code to handle Future Domain 840, 841, 880 and 881 - * Add code to use tagged commands in SCSI2 - * Add code to handle slow devices better (sleep if device not disconnecting) - * Fix unnecessary interrupts - */ - -/* Note to users trying to share a disk between DOS and unix: - * The ST01/02 is a translating host-adapter. It is not giving DOS - * the same number of heads/tracks/sectors as specified by the disk. - * It is therefore important to look at what numbers DOS thinks the - * disk has. Use these to disklabel your disk in an appropriate manner - * - * About ST02+IDE coexistence: the original Seagate ST02 - * BIOS cannot coexist with IDE or any other disk controller - * because it does not share BIOS disk drive numbers (80h, 81h) - * with others. New probing code allows using ST02 controller - * without BIOS: just unplug the ST02 BIOS chip from the board. - * - * Another problem is the floppy adapter on ST02 which could not be - * disabled by jumpers. I commonly use ST02 adapter as a cheap solution - * for atttaching the tape and CD-ROM drives, and an extra floppy controller - * is just a headache. I found a simple workaround: cutting off - * the AEN signal (A11 contact on ISA connector). AEN then goes high and - * disables the floppy adapter port address decoder. - * - * I also had a problem with ST02 conflicting with IDE during - * IDE data write phase. It seems than ST02 makes some noise - * on /IOW line. The /IOW line is used only for floppy controller - * part of ST02, and because I don't need it, I cut off the /IOW (contact B13) - * and it helped. (vak) - * - * Tested on the following hardware: - * Adapter: Seagate ST02 - * Disk: HP D1686 - * Streamers: Archive Viper 150, Wangtek 5525 - * CD-ROMs: Toshiba XM-3401, NEC CDR-25 - * - * Maximum data rate is about 270-280 kbytes/sec (on 386DX/40). - * (vak) - */ -#undef DEBUG - -#include "sea.h" -#if NSEA > 0 - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> - -#include <machine/clock.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/pmap.h> - -#include <i386/isa/isa_device.h> - -#include <scsi/scsiconf.h> - -#ifdef DEBUG -# define PRINT(s) printf s -#else -# define PRINT(s) /*void*/ -#endif - -#define SCB_TABLE_SIZE 8 /* start with 8 scb entries in table */ -#define BLOCK_SIZE 512 /* size of READ/WRITE areas on SCSI card */ -#define HOST_SCSI_ADDR 7 /* address of the adapter on the SCSI bus */ -#define SEA_BLINDTRANSFER 1 /* for quicker than quick xfers */ -/* - * Define config flags - */ -#define FLAG_NOPARITY 0x01 /* disable SCSI bus parity check */ - -/* - * Board CONTROL register - */ -#define CMD_RST 0x01 /* scsi reset */ -#define CMD_SEL 0x02 /* scsi select */ -#define CMD_BSY 0x04 /* scsi busy */ -#define CMD_ATTN 0x08 /* scsi attention */ -#define CMD_START_ARB 0x10 /* start arbitration bit */ -#define CMD_EN_PARITY 0x20 /* enable scsi parity generation */ -#define CMD_INTR 0x40 /* enable scsi interrupts */ -#define CMD_DRVR_ENABLE 0x80 /* scsi enable */ - -/* - * Board STATUS register - */ -#define STAT_BSY 0x01 /* scsi busy */ -#define STAT_MSG 0x02 /* scsi msg */ -#define STAT_IO 0x04 /* scsi I/O */ -#define STAT_CD 0x08 /* scsi C/D */ -#define STAT_REQ 0x10 /* scsi req */ -#define STAT_SEL 0x20 /* scsi select */ -#define STAT_PARITY 0x40 /* parity error bit */ -#define STAT_ARB_CMPL 0x80 /* arbitration complete bit */ -#define STAT_BITS "\20\1bsy\2msg\3i/o\4c/d\5req\6sel\7parity\10arb" - -/* - * SCSI bus phases - */ -#define PHASE_MASK (STAT_MSG | STAT_CD | STAT_IO) -#define PHASE_DATAOUT 0 -#define PHASE_DATAIN STAT_IO -#define PHASE_CMDOUT STAT_CD -#define PHASE_STATIN (STAT_CD | STAT_IO) -#define PHASE_MSGOUT (STAT_MSG | STAT_CD) -#define PHASE_MSGIN (STAT_MSG | STAT_CD | STAT_IO) -#define PHASE_NAME(ph) phase_name[(ph)>>2] - -static char *phase_name[] = { - "DATAOUT", "Phase1?", "Phase2?", "Phase3?", - "DATAIN", "Phase5?", "Phase6?", "Phase7?", - "CMDOUT", "Phase9?", "MSGOUT", "Phase11?", - "STATIN", "Phase13?", "MSGIN", "Phase15?", -}; - -/* - * SCSI message codes - */ -#define MSG_COMMAND_COMPLETE 0x00 -#define MSG_SAVE_POINTERS 0x02 -#define MSG_RESTORE_POINTERS 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_ABORT 0x06 -#define MSG_MESSAGE_REJECT 0x07 -#define MSG_NOP 0x08 -#define MSG_BUS_DEV_RESET 0x0c -#define MSG_IDENTIFY(lun) (0xc0 | ((lun) & 0x7)) -#define MSG_ISIDENT(m) ((m) & 0x80) - -/* - * SCSI control block used to keep info about a scsi command - */ -typedef struct scb { - int flags; /* status of the instruction */ -#define SCB_FREE 0x00 -#define SCB_ACTIVE 0x01 -#define SCB_ABORTED 0x02 -#define SCB_TIMEOUT 0x04 -#define SCB_ERROR 0x08 -#define SCB_TIMECHK 0x10 /* we have set a timeout on this one */ -#define SCB_SENSE 0x20 /* sensed data available */ -#define SCB_TBUSY 0x40 /* target busy */ - struct scb *next; /* in free list */ - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ - u_char *data; /* position in data buffer so far */ - int32_t datalen; /* bytes remaining to transfer */ -} scb_t; - -typedef enum { - CTLR_NONE, - CTLR_SEAGATE, - CTLR_FUTURE_DOMAIN -} ctlr_t; - -/* - * Flags for waiting for REQ deassert during some SCSI bus phases. - */ -typedef struct { - unsigned cmdout1 : 1; /* after CMDOUT[0] byte */ - unsigned cmdout : 1; /* after CMDOUT[1..N] bytes */ - unsigned msgout : 1; /* after MSGOUT byte */ - unsigned statin : 1; /* after STATIN byte */ -} phase_t; - -/* - * Data structure describing the target state. - */ -typedef struct { - struct adapter *adapter; /* pointer to the adapter structure */ - u_char busy; /* mask of busy luns at device target */ - u_long perrcnt; /* counter of target parity errors */ - phase_t ndelay; /* "don't delay" flags */ - phase_t init; /* "initialized" flags */ -} target_t; - -/* - * Data structure describing current status of the scsi bus. One for each - * controller card. - */ -typedef struct adapter { - ctlr_t type; /* Seagate or Future Domain */ - char *name; /* adapter name */ - volatile u_char *addr; /* base address for card */ - - volatile u_char *CONTROL; /* address of control register */ - volatile u_char *STATUS; /* address of status register */ - volatile u_char *DATA; /* address of data register */ - - u_char scsi_addr; /* our scsi address, 0..7 */ - u_char scsi_id; /* our scsi id mask */ - u_char parity; /* parity flag: CMD_EN_PARITY or 0 */ - u_char irq; /* IRQ number used or 0 if no IRQ */ - u_int timeout_active : 1; /* timeout() active (requested) */ - - struct scsi_link sc_link; /* struct connecting different data */ - scb_t *queue; /* waiting to be issued */ - scb_t *disconnected_queue; /* waiting to reconnect */ - - int numscb; /* number of scsi control blocks */ - scb_t *free_scb; /* free scb list */ - scb_t scbs[SCB_TABLE_SIZE]; - - target_t target[8]; /* target state data */ -} adapter_t; - -static adapter_t seadata[NSEA]; - -#define IS_BUSY(a,b) ((a)->target[(b)->xfer->sc_link->target].busy &\ - (1 << (b)->xfer->sc_link->lun)) -#define SET_BUSY(a,b) ((a)->target[(b)->xfer->sc_link->target].busy |=\ - (1 << (b)->xfer->sc_link->lun)) -#define CLEAR_BUSY(a,b) ((a)->target[(b)->xfer->sc_link->target].busy &=\ - ~(1 << (b)->xfer->sc_link->lun)) - -/* - * Wait for condition, given as an boolean expression. - * Print the message on timeout. - */ -#define WAITFOR(condition,message) {\ - register u_long cnt = 100000; char *_msg = message;\ - while (cnt-- && ! (condition)) continue;\ - if (cnt == -1 && _msg)\ - printf ("sea: %s timeout\n", _msg); } - -#define WAITFOR10(condition,message) {\ - register u_long cnt = 1000000; char *_msg = message;\ - while (cnt-- && ! (condition)) continue;\ - if (cnt == -1 && _msg)\ - printf ("sea: %s timeout\n", _msg); } - -/* - * Seagate adapter does not support in hardware - * waiting for REQ deassert after transferring each data byte. - * We must do it in software. - * The problem is that some SCSI devices deassert REQ so fast that - * we can miss it. We the flag for each target sayind if we should (not) - * wait for REQ deassert. This flag is initialized when the first - * operation on the target is done. - * 1) Test if we don't need to wait for REQ deassert (`nodelay' flag). - * Initially the flag is off, i.e. wait. If the flag is set, - * go to the step 4. - * 2) Wait for REQ deassert (call sea_wait_for_req_deassert function). - * If REQ deassert got, go to the step 4. If REQ did not cleared - * during timeout period, go to the next step. - * 3) If `nodelay' flag did not initialized yet (`init' flag), - * then set `ndelay' flag. - * 4) Set `init' flag. Done. - */ -#define WAITREQ(t,op,cnt) {\ - if (! (t)->ndelay.op &&\ - ! sea_wait_for_req_deassert ((t)->adapter, cnt, #op) &&\ - ! (t)->init.op)\ - (t)->ndelay.op = 1;\ - (t)->init.op = 1; } - -static int sea_probe (struct isa_device *dev); -static int sea_detect (adapter_t *z, struct isa_device *dev); -static int sea_attach (struct isa_device *dev); -static int32_t sea_scsi_cmd (struct scsi_xfer *xs); -static u_int32_t sea_adapter_info (int unit); -static void sea_timeout (void *scb); -static void seaminphys (struct buf *bp); -static void sea_done (adapter_t *z, scb_t *scb); -static void sea_start (adapter_t *z); -static void sea_information_transfer (adapter_t *z, scb_t *scb); -static int sea_poll (adapter_t *z, scb_t *scb); -static int sea_init (adapter_t *z); -static ointhand2_t seaintr; -static int sea_reselect (adapter_t *z); -static int sea_select (volatile adapter_t *z, scb_t *scb); -static int sea_abort (adapter_t *z, scb_t *scb); -static void sea_send_abort (adapter_t *z); -static u_char sea_msg_input (adapter_t *z); -static void sea_tick (void *arg); -static int sea_sense (adapter_t *z, scb_t *scb); -static void sea_data_output (adapter_t *z, u_char **pdata, u_long *plen); -static void sea_data_input (adapter_t *z, u_char **pdata, u_long *plen); -static void sea_cmd_output (target_t *z, u_char *cmd, int cmdlen); - -static struct scsi_adapter sea_switch = { - sea_scsi_cmd, seaminphys, 0, 0, sea_adapter_info, "sea", {0}, -}; -static struct scsi_device sea_dev = { NULL, NULL, NULL, NULL, "sea", 0, {0} }; -struct isa_driver seadriver = { sea_probe, sea_attach, "sea" }; - -/* FD TMC885's can't handle detach & re-attach */ -static int sea_select_cmd = CMD_DRVR_ENABLE | CMD_ATTN; - -/* - * Check if the device can be found at the port given and if so, - * detect the type of board. Set it up ready for further work. - * Takes the isa_dev structure from autoconf as an argument. - * Returns 1 if card recognized, 0 if errors. - */ -int sea_probe (struct isa_device *dev) -{ - adapter_t *z = &seadata[dev->id_unit]; - static const int addrtab[] = { - 0xc8000, 0xca000, 0xcc000, 0xce000, 0xdc000, 0xde000, 0, - }; - int i; - - /* Init fields used by our routines */ - z->parity = (dev->id_flags & FLAG_NOPARITY) ? 0 : CMD_EN_PARITY; - z->scsi_addr = HOST_SCSI_ADDR; - z->scsi_id = 1 << z->scsi_addr; - z->irq = dev->id_irq ? ffs (dev->id_irq) - 1 : 0; - z->queue = 0; - z->disconnected_queue = 0; - for (i=0; i<8; i++) { - z->target[i].adapter = z; - z->target[i].busy = 0; - } - - /* Link up the free list of scbs */ - z->numscb = SCB_TABLE_SIZE; - z->free_scb = z->scbs; - for (i=1; i<SCB_TABLE_SIZE; i++) - z->scbs[i-1].next = z->scbs + i; - z->scbs[SCB_TABLE_SIZE-1].next = 0; - - /* Detect the adapter. */ - dev->id_msize = 0x4000; - if (! dev->id_maddr) - for (i=0; addrtab[i]; ++i) { - dev->id_maddr = (u_char*) KERNBASE + addrtab[i]; - if (sea_detect (z, dev)) - return (1); - } - else if (sea_detect (z, dev)) - return (1); - - bzero (z, sizeof (*z)); - return (0); -} - -int sea_detect (adapter_t *z, struct isa_device *dev) -{ - z->addr = dev->id_maddr; - - /* Try Seagate. */ - z->type = CTLR_SEAGATE; - z->name = "Seagate ST01/ST02"; - z->CONTROL = z->addr + 0x1a00; /* ST01/ST02 register offsets */ - z->STATUS = z->addr + 0x1a00; - z->DATA = z->addr + 0x1c00; - if (sea_init (z) == 0) - return (1); - - /* Try Future Domain. */ - z->type = CTLR_FUTURE_DOMAIN; - z->name = "Future Domain TMC-885/TMC-950"; - z->CONTROL = z->addr + 0x1c00; /* TMC-885/TMC-950 reg. offsets */ - z->STATUS = z->addr + 0x1c00; - z->DATA = z->addr + 0x1e00; - /* FD TMC885's can't handle detach & re-attach */ - sea_select_cmd = CMD_DRVR_ENABLE; - /* FD TMC-885 is supposed to be at id 6. How strange. */ - z->scsi_addr = HOST_SCSI_ADDR - 1; - z->scsi_id = 1 << z->scsi_addr; - if (sea_init (z) == 0) - return (1); - - return (0); -} - -/* - * Probe the adapter, and if found, reset the board and the scsi bus. - * Return 0 if the adapter found. - */ -int sea_init (adapter_t *z) -{ - volatile u_char *p; - int i, c; - - /* Check that STATUS..STATUS+200h are equal. */ - p = z->STATUS; - c = *p; - if (c == 0xff) - return (2); - while (++p < z->STATUS+0x200) - if (*p != c) - return (3); - - /* Check that DATA..DATA+200h are equal. */ - for (p=z->DATA, c= *p++; p<z->DATA+0x200; ++p) - if (*p != c) - return (4); - - /* Check that addr..addr+1800h are not writable. */ - for (p=z->addr; p<z->addr+0x1800; ++p) { - c = *p; - *p = ~c; - if (*p == ~c) { - *p = c; - return (5); - } - } - - /* Check that addr+1800h..addr+1880h are writable. */ - for (p=z->addr+0x1800; p<z->addr+0x1880; ++p) { - c = *p; - *p = 0x55; - if (*p != 0x55) { - *p = c; - return (6); - } - *p = 0xaa; - if (*p != 0xaa) { - *p = c; - return (7); - } - } - - /* Reset the scsi bus (I don't know if this is needed). */ - *z->CONTROL = CMD_RST | CMD_DRVR_ENABLE | z->parity | CMD_INTR; - /* Hold reset for at least 25 microseconds. */ - DELAY (25); - /* Check that status cleared. */ - if (*z->STATUS != 0) { - *z->CONTROL = 0; - return (8); - } - - /* Check that DATA register is writable. */ - for (i=0; i<256; ++i) { - *z->DATA = i; - if (*z->DATA != i) { - *z->CONTROL = 0; - return (9); - } - } - - /* Enable the adapter. */ - *z->CONTROL = CMD_INTR | z->parity; - /* Wait a Bus Clear Delay (800 ns + bus free delay 800 ns). */ - DELAY (10); - - /* Check that DATA register is NOT writable. */ - c = *z->DATA; - for (i=0; i<256; ++i) { - *z->DATA = i; - if (*z->DATA != c) { - *z->CONTROL = 0; - return (10); - } - } - - return (0); -} - -/* - * Attach all sub-devices we can find. - */ -int sea_attach (struct isa_device *dev) -{ - int unit = dev->id_unit; - adapter_t *z = &seadata[unit]; - struct scsibus_data *scbus; - - printf ("\nsea%d: type %s%s\n", unit, z->name, - (dev->id_flags & FLAG_NOPARITY) ? ", no parity" : ""); - - dev->id_ointr = seaintr; - - /* fill in the prototype scsi_link */ - z->sc_link.adapter_unit = unit; - z->sc_link.adapter_targ = z->scsi_addr; - z->sc_link.adapter_softc = z; - z->sc_link.adapter = &sea_switch; - z->sc_link.device = &sea_dev; - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = &z->sc_link; - - /* ask the adapter what subunits are present */ - scsi_attachdevs (scbus); - - return (1); -} - -/* - * Return some information to the caller about - * the adapter and its capabilities. - */ -u_int32_t sea_adapter_info (int unit) -{ - return (1); -} - -void seaminphys (struct buf *bp) -{ -} - -/* - * Catch an interrupt from the adaptor. - */ -static void seaintr (int unit) -{ - adapter_t *z = &seadata[unit]; - - PRINT (("sea%d: interrupt status=%b\n", unit, *z->STATUS, STAT_BITS)); - sea_start (z); -} - -/* - * This routine is used in the case when we have no IRQ line (z->irq == 0). - * It is called every timer tick and polls for reconnect from target. - */ -void sea_tick (void *arg) -{ - adapter_t *z = arg; - int x = splbio (); - - z->timeout_active = 0; - sea_start (z); - if (z->disconnected_queue && ! z->timeout_active) { - timeout (sea_tick, z, 1); - z->timeout_active = 1; - } - splx (x); -} - -/* - * Start a scsi operation given the command and the data address. - * Also needs the unit, target and lu. Get a free scb and set it up. - * Call send_scb. Either start timer or wait until done. - */ -int32_t sea_scsi_cmd (struct scsi_xfer *xs) -{ - int flags = xs->flags, x = 0; - adapter_t *z = (adapter_t *)xs->sc_link->adapter_softc; - scb_t *scb; - - PRINT (("sea%d/%d/%d command 0x%x\n", unit, xs->sc_link->target, - xs->sc_link->lun, xs->cmd->opcode)); - if (xs->bp) - flags |= SCSI_NOSLEEP; - if (flags & ITSDONE) { - printf ("sea%d: already done?", xs->sc_link->adapter_unit); - xs->flags &= ~ITSDONE; - } - if (! (flags & INUSE)) { - printf ("sea%d: not in use?", xs->sc_link->adapter_unit); - xs->flags |= INUSE; - } - if (flags & SCSI_RESET) - printf ("sea%d: SCSI_RESET not implemented\n", - xs->sc_link->adapter_unit); - - if (! (flags & SCSI_NOMASK)) - x = splbio (); - - /* Get a free scb. - * If we can and have to, sleep waiting for one to come free. */ - while (! (scb = z->free_scb)) { - if (flags & SCSI_NOSLEEP) { - xs->error = XS_DRIVER_STUFFUP; - if (! (flags & SCSI_NOMASK)) - splx (x); - return (TRY_AGAIN_LATER); - } - tsleep ((caddr_t)&z->free_scb, PRIBIO, "seascb", 0); - } - /* Get scb from free list. */ - z->free_scb = scb->next; - scb->next = 0; - scb->flags = SCB_ACTIVE; - - /* Put all the arguments for the xfer in the scb */ - scb->xfer = xs; - scb->datalen = xs->datalen; - scb->data = xs->data; - - /* Setup the scb to contain necessary values. - * The interesting values can be read from the xs that is saved. - * I therefore think that the structure can be kept very small. - * The driver doesn't use DMA so the scatter/gather is not needed? */ - if (! z->queue) { - scb->next = z->queue; - z->queue = scb; - } else { - scb_t *q; - - for (q=z->queue; q->next; q=q->next) - continue; - q->next = scb; - scb->next = 0; /* placed at the end of the queue */ - } - - /* Try to send this command to the board. */ - sea_start (z); - - /* Usually return SUCCESSFULLY QUEUED. */ - if (! (flags & SCSI_NOMASK)) { - splx (x); - if (xs->flags & ITSDONE) - /* Timeout timer not started, already finished. - * Tried to return COMPLETE but the machine hanged - * with this. */ - return (SUCCESSFULLY_QUEUED); - xs->timeout_ch = timeout (sea_timeout, (caddr_t) scb, - (xs->timeout * hz) / 1000); - scb->flags |= SCB_TIMECHK; - PRINT (("sea%d/%d/%d command queued\n", - xs->sc_link->adapter_unit, - xs->sc_link->target, xs->sc_link->lun)); - return (SUCCESSFULLY_QUEUED); - } - - /* If we can't use interrupts, poll on completion. */ - if (! sea_poll (z, scb)) { - /* We timed out, so call the timeout handler manually, - * accounting for the fact that the clock is not running yet - * by taking out the clock queue entry it makes. */ - sea_timeout ((void*) scb); - - /* Because we are polling, take out the timeout entry - * sea_timeout made. */ - untimeout (sea_timeout, (void*) scb, xs->timeout_ch); - - if (! sea_poll (z, scb)) - /* We timed out again... This is bad. Notice that - * this time there is no clock queue entry to remove. */ - sea_timeout ((void*) scb); - } - PRINT (("sea%d/%d/%d command %s\n", xs->sc_link->adapter_unit, - xs->sc_link->target, xs->sc_link->lun, - xs->error ? "failed" : "done")); - return (xs->error ? HAD_ERROR : COMPLETE); -} - -/* - * Coroutine that runs as long as more work can be done. - * Both scsi_cmd() and intr() will try to start it in - * case it is not running. - * Always called with interrupts disabled. - */ -void sea_start (adapter_t *z) -{ - scb_t *q, *prev; -again: - /* First check that if any device has tried - * a reconnect while we have done other things - * with interrupts disabled. */ - if (sea_reselect (z)) - goto again; - - /* Search through the queue for a command - * destined for a target that's not busy. */ - for (q=z->queue, prev=0; q; prev=q, q=q->next) { - /* Attempt to establish an I_T_L nexus here. */ - if (IS_BUSY (z, q) || ! sea_select (z, q)) - continue; - - /* Remove the command from the issue queue. */ - if (prev) - prev->next = q->next; - else - z->queue = q->next; - q->next = 0; - - /* We are connected. Do the task. */ - sea_information_transfer (z, q); - goto again; - } -} - -void sea_timeout (void *arg) -{ - scb_t *scb = (scb_t*) arg; - adapter_t *z = (adapter_t *)scb->xfer->sc_link->adapter_softc; - int x = splbio (); - - if (! (scb->xfer->flags & SCSI_NOMASK)) - printf ("sea%d/%d/%d (%s%d) timed out\n", - scb->xfer->sc_link->adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, - scb->xfer->sc_link->device->name, - scb->xfer->sc_link->dev_unit); - - /* If it has been through before, then a previous abort has failed, - * don't try abort again. */ - if (! (scb->flags & SCB_ABORTED)) { - sea_abort (z, scb); - /* 2 seconds for the abort */ - scb->xfer->timeout_ch = timeout (sea_timeout, - (caddr_t)scb, 2*hz); - scb->flags |= (SCB_ABORTED | SCB_TIMECHK); - } else { - /* abort timed out */ - scb->flags |= SCB_ABORTED; - scb->xfer->retries = 0; - sea_done (z, scb); - } - splx (x); -} - -/* - * Wait until REQ goes down. This is needed for some devices (CDROMs) - * after every MSGOUT, MSGIN, CMDOUT, STATIN request. - * Return true if REQ deassert found. - */ -static __inline int sea_wait_for_req_deassert (adapter_t *z, int cnt, char *msg) -{ - __asm __volatile (" - 1: testb $0x10, %2 - jz 2f - loop 1b - 2:" - : "=c" (cnt) /* output */ - : "0" (cnt), "m" (*z->STATUS)); /* input */ - if (! cnt) { - PRINT (("sea%d (%s) timeout waiting for !REQ\n", - z->sc_link.adapter_unit, msg)); - return (0); - } - /* PRINT (("sea_wait_for_req_deassert %s count=%d\n", msg, cnt)); */ - return (1); -} - -/* - * Establish I_T_L or I_T_L_Q nexus for new or existing command - * including ARBITRATION, SELECTION, and initial message out - * for IDENTIFY and queue messages. - * Return 1 if selection succeded. - */ -int sea_select (volatile adapter_t *z, scb_t *scb) -{ - /* Start arbitration. */ - *z->CONTROL = z->parity | CMD_INTR; - *z->DATA = z->scsi_id; - *z->CONTROL = CMD_START_ARB | z->parity; - - /* Wait for arbitration to complete. */ - WAITFOR (*z->STATUS & STAT_ARB_CMPL, "arbitration"); - if (! (*z->STATUS & STAT_ARB_CMPL)) { - if (*z->STATUS & STAT_SEL) { - printf ("sea: arbitration lost\n"); - scb->flags |= SCB_ERROR; - } else { - printf ("sea: arbitration timeout\n"); - scb->flags |= SCB_TIMEOUT; - } - *z->CONTROL = CMD_INTR | z->parity; - return (0); - } - DELAY (1); - - *z->DATA = (1 << scb->xfer->sc_link->target) | z->scsi_id; - *z->CONTROL = sea_select_cmd | CMD_SEL | z->parity; - DELAY (2); - - /* Wait for a bsy from target. - * If the target is not present on the bus, we get - * the timeout. Don't PRINT any message -- it's not an error. */ - WAITFOR (*z->STATUS & STAT_BSY, 0); - if (! (*z->STATUS & STAT_BSY)) { - /* The target does not respond. Not an error, though. */ - PRINT (("sea%d/%d/%d target does not respond\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - *z->CONTROL = CMD_INTR | z->parity; - scb->flags |= SCB_TIMEOUT; - return (0); - } - - /* Try to make the target to take a message from us. - * Should start a MSGOUT phase. */ - *z->CONTROL = sea_select_cmd | z->parity; - DELAY (15); - WAITFOR (*z->STATUS & STAT_REQ, 0); - - if (z->type == CTLR_FUTURE_DOMAIN) - *z->CONTROL = CMD_INTR | z->parity | CMD_DRVR_ENABLE; - - WAITFOR (*z->STATUS & STAT_REQ, 0); - if (! (*z->STATUS & STAT_REQ)) { - PRINT (("sea%d/%d/%d timeout waiting for REQ\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - scb->flags |= SCB_ERROR; - *z->CONTROL = CMD_INTR | z->parity; - return (0); - } - - /* Check for phase mismatch. FD 885 always seems to get this wrong! */ - if ((*z->STATUS & PHASE_MASK) != PHASE_MSGOUT && z->type != CTLR_FUTURE_DOMAIN) { - PRINT (("sea%d/%d/%d waiting for MSGOUT: invalid phase %s\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, - PHASE_NAME (*z->STATUS & PHASE_MASK))); - scb->flags |= SCB_ERROR; - *z->CONTROL = CMD_INTR | z->parity; - return (0); - } - - /* Allow disconnects. (except for FD controllers) */ - if (z->type == CTLR_SEAGATE) { - *z->CONTROL = CMD_DRVR_ENABLE | z->parity; - *z->DATA = MSG_IDENTIFY (scb->xfer->sc_link->lun); - WAITREQ (&z->target[scb->xfer->sc_link->target], msgout, 1000); - } - *z->CONTROL = CMD_INTR | CMD_DRVR_ENABLE | z->parity; - - SET_BUSY (z, scb); - return (1); -} - -int sea_reselect (adapter_t *z) -{ - scb_t *q = 0, *prev = 0; - u_char msg, target_mask, lun; -again: - /* Wait for a device to win the reselection phase. */ - /* Signals this by asserting the I/O signal. */ - if ((*z->STATUS & (STAT_SEL | STAT_IO | STAT_BSY)) != - (STAT_SEL | STAT_IO)) - return (0); - - /* The data bus contains original initiator id ORed with target id. */ - /* See that we really are the initiator. */ - target_mask = *z->DATA; - if (! (target_mask & z->scsi_id)) { - PRINT (("sea%d reselect not for me: mask=0x%x, status=%b\n", - z->sc_link.adapter_unit, target_mask, - *z->STATUS, STAT_BITS)); - goto again; - } - - /* Find target who won. */ - /* Host responds by asserting the BSY signal. */ - /* Target should respond by deasserting the SEL signal. */ - target_mask &= ~z->scsi_id; - *z->CONTROL = CMD_DRVR_ENABLE | CMD_BSY | z->parity | CMD_INTR; - WAITFOR (! (*z->STATUS & STAT_SEL), "reselection acknowledge"); - - /* Remove the busy status. */ - /* Target should set the MSGIN phase. */ - *z->CONTROL = CMD_INTR | CMD_DRVR_ENABLE | z->parity; - WAITFOR (*z->STATUS & STAT_REQ, "identify message"); - - /* Hope we get an IDENTIFY message. */ - msg = sea_msg_input (z); - if (MSG_ISIDENT (msg)) { - /* Find the command corresponding to the I_T_L or I_T_L_Q - * nexus we just restablished, and remove it from - * the disconnected queue. */ - lun = (msg & 7); - for (q=z->disconnected_queue; q; prev=q, q=q->next) { - if (target_mask != (1 << q->xfer->sc_link->target)) - continue; - if (lun != q->xfer->sc_link->lun) - continue; - if (prev) - prev->next = q->next; - else - z->disconnected_queue = q->next; - q->next = 0; - PRINT (("sea%d/%d/%d reselect done\n", - z->sc_link.adapter_unit, - ffs (target_mask) - 1, lun)); - sea_information_transfer (z, q); - WAITFOR (! (*z->STATUS & STAT_BSY), "reselect !busy"); - return (1); - } - } else - printf ("sea%d reselect: expecting IDENTIFY, got 0x%x\n", - z->sc_link.adapter_unit, msg); - - /* Since we have an established nexus that we can't - * do anything with, we must abort it. */ - sea_send_abort (z); - PRINT (("sea%d reselect aborted\n", z->sc_link.adapter_unit)); - WAITFOR (! (*z->STATUS & STAT_BSY), "bus free after reselect abort"); - goto again; -} - -/* - * Send an abort to the target. - * Return 1 success, 0 on failure. - * Called on splbio level. - */ -int sea_abort (adapter_t *z, scb_t *scb) -{ - scb_t *q, **prev; - - /* If the command hasn't been issued yet, we simply remove it - * from the issue queue. */ - prev = &z->queue; - for (q=z->queue; q; q=q->next) { - if (scb == q) { - (*prev) = q->next; - q->next = 0; - return (1); - } - prev = &q->next; - } - - /* If the command is currently disconnected from the bus, - * we reconnect the I_T_L or I_T_L_Q nexus associated with it, - * go into message out, and send an abort message. */ - for (q=z->disconnected_queue; q; q=q->next) { - if (scb != q) - continue; - - if (! sea_select (z, scb)) - return (0); - sea_send_abort (z); - - prev = &z->disconnected_queue; - for (q=z->disconnected_queue; q; q=q->next) { - if (scb == q) { - *prev = q->next; - q->next = 0; - /* Set some type of error result - * for the operation. */ - return (1); - } - prev = &q->next; - } - } - - /* Command not found in any queue. */ - return (0); -} - -/* - * The task accomplished, mark the i/o control block as done. - * Always called with interrupts disabled. - */ -void sea_done (adapter_t *z, scb_t *scb) -{ - struct scsi_xfer *xs = scb->xfer; - - if (scb->flags & SCB_TIMECHK) - untimeout (sea_timeout, (caddr_t) scb, xs->timeout_ch); - - /* How much of the buffer was not touched. */ - xs->resid = scb->datalen; - - if (scb->flags != SCB_ACTIVE && ! (xs->flags & SCSI_ERR_OK)) - if (scb->flags & (SCB_TIMEOUT | SCB_ABORTED)) - xs->error = XS_TIMEOUT; - else if (scb->flags & SCB_ERROR) - xs->error = XS_DRIVER_STUFFUP; - else if (scb->flags & SCB_TBUSY) - xs->error = XS_BUSY; - else if (scb->flags & SCB_SENSE) - xs->error = XS_SENSE; - - xs->flags |= ITSDONE; - - /* Free the control block. */ - scb->next = z->free_scb; - z->free_scb = scb; - scb->flags = SCB_FREE; - - /* If there were none, wake anybody waiting for one to come free, - * starting with queued entries. */ - if (! scb->next) - wakeup ((caddr_t) &z->free_scb); - - scsi_done (xs); -} - -/* - * Wait for completion of command in polled mode. - * Always called with interrupts masked out. - */ -int sea_poll (adapter_t *z, scb_t *scb) -{ - int count; - - for (count=0; count<30; ++count) { - DELAY (1000); /* delay for a while */ - sea_start (z); /* retry operation */ - if (scb->xfer->flags & ITSDONE) - return (1); /* all is done */ - if (scb->flags & SCB_TIMEOUT) - return (0); /* no target present */ - } - return (0); -} - -/* - * Send data to the target. - */ -void sea_data_output (adapter_t *z, u_char **pdata, u_long *plen) -{ - volatile u_char *data = *pdata; - volatile u_int len = *plen; - -#ifdef SEA_BLINDTRANSFER - if (len && !(len % BLOCK_SIZE)) { - while (len) { - WAITFOR10 (*z->STATUS & STAT_REQ, "blind block read"); - __asm __volatile (" - shr $2, %%ecx; - cld; - rep; - movsl; " : : - "D" (z->DATA), "S" (data), "c" (BLOCK_SIZE) : - "cx", "si", "di" ); - data += BLOCK_SIZE; - len -= BLOCK_SIZE; - } - } else { -#endif - __asm __volatile ("cld - 1: movb (%%ebx), %%al - xorb $1, %%al - testb $0xf, %%al - jnz 2f - testb $0x10, %%al - jz 1b - lodsb - movb %%al, (%%edi) - loop 1b - 2:" - : "=S" (data), "=c" (len) /* output */ - : "D" (z->DATA), "b" (z->STATUS), /* input */ - "0" (data), "1" (len) - : "eax", "ebx", "edi"); /* clobbered */ -#ifdef SEA_BLINDTRANSFER - } -#endif - PRINT (("sea (DATAOUT) send %ld bytes\n", *plen - len)); - *plen = len; - *pdata = (u_char *)data; -} - -/* - * Receive data from the target. - */ -void sea_data_input (adapter_t *z, u_char **pdata, u_long *plen) -{ - volatile u_char *data = *pdata; - volatile u_int len = *plen; - -#ifdef SEA_BLINDTRANSFER - if (len && !(len % BLOCK_SIZE)) { - while (len) { - WAITFOR10 (*z->STATUS & STAT_REQ, "blind block read"); - __asm __volatile (" - shr $2, %%ecx; - cld; - rep; - movsl; " : : - "S" (z->DATA), "D" (data), "c" (BLOCK_SIZE) : - "cx", "si", "di" ); - data += BLOCK_SIZE; - len -= BLOCK_SIZE; - } - } else { -#endif - if (len >= 512) { - __asm __volatile (" cld - 1: movb (%%esi), %%al - xorb $5, %%al - testb $0xf, %%al - jnz 2f - testb $0x10, %%al - jz 1b - movb (%%ebx), %%al - stosb - loop 1b - 2:" - : "=D" (data), "=c" (len) /* output */ - : "b" (z->DATA), "S" (z->STATUS), - "0" (data), "1" (len) /* input */ - : "eax", "ebx", "esi"); /* clobbered */ - } else { - __asm __volatile (" cld - 1: movb (%%esi), %%al - xorb $5, %%al - testb $0xf, %%al - jnz 2f - testb $0x10, %%al - jz 1b - movb (%%ebx), %%al - stosb - movb $1000, %%al - 3: testb $0x10, (%%esi) - jz 4f - dec %%al - jnz 3b - 4: loop 1b - 2:" - : "=D" (data), "=c" (len) /* output */ - : "b" (z->DATA), "S" (z->STATUS), - "0" (data), "1" (len) /* input */ - : "eax", "ebx", "esi"); /* clobbered */ - } -#ifdef SEA_BLINDTRANSFER - } -#endif - PRINT (("sea (DATAIN) got %ld bytes\n", *plen - len)); - *plen = len; - *pdata = (u_char *)data; -} - -/* - * Send the command to the target. - */ -void sea_cmd_output (target_t *t, u_char *cmd, int cmdlen) -{ - adapter_t *z = t->adapter; - - PRINT (("sea%d send command (%d bytes) ", z->sc_link.adapter_unit, - cmdlen)); - - PRINT (("%x", *cmd)); - *z->DATA = *cmd++; - if (z->type == CTLR_SEAGATE) - WAITREQ (t, cmdout1, 10000); - --cmdlen; - - while (cmdlen) { - /* Check for target disconnect. */ - u_char sts = *z->STATUS; - if (! (sts & STAT_BSY)) - break; - - /* Check for phase mismatch. FD 885 seems to get this wrong! */ - if ((sts & PHASE_MASK) != PHASE_CMDOUT && z->type != CTLR_FUTURE_DOMAIN) { - printf ("sea: sea_cmd_output: invalid phase %s\n", - PHASE_NAME (sts & PHASE_MASK)); - return; - } - - /* Wait for REQ. */ - if (! (sts & STAT_REQ)) - continue; - - PRINT (("-%x", *cmd)); - *z->DATA = *cmd++; - if (z->type == CTLR_SEAGATE) - WAITREQ (t, cmdout, 1000); - --cmdlen; - } - PRINT (("\n")); -} - -/* - * Send the message to the target. - */ -void sea_send_abort (adapter_t *z) -{ - u_char sts; - - *z->CONTROL = CMD_INTR | CMD_DRVR_ENABLE | CMD_ATTN | z->parity; - - /* Wait for REQ, after which the phase bits will be valid. */ - WAITFOR (*z->STATUS & STAT_REQ, "abort message"); - sts = *z->STATUS; - if (! (sts & STAT_REQ)) - goto ret; - - /* Check for phase mismatch. */ - if ((sts & PHASE_MASK) != PHASE_MSGOUT) { - printf ("sea: sending MSG_ABORT: invalid phase %s\n", - PHASE_NAME (sts & PHASE_MASK)); - goto ret; - } - - *z->DATA = MSG_ABORT; - sea_wait_for_req_deassert (z, 1000, "MSG_OUTPUT"); - PRINT (("sea%d send abort message\n", z->sc_link.adapter_unit)); -ret: - *z->CONTROL = CMD_INTR | CMD_DRVR_ENABLE | z->parity; -} - -/* - * Get the message from the target. - * Return the length of the received message. - */ -u_char sea_msg_input (adapter_t *z) -{ - u_char sts, msg; - - /* Wait for REQ, after which the phase bits will be valid. */ - WAITFOR (*z->STATUS & STAT_REQ, "message input"); - sts = *z->STATUS; - if (! (sts & STAT_REQ)) - return (MSG_ABORT); - - /* Check for phase mismatch. - * Reached if the target decides that it has finished the transfer. */ - if ((sts & PHASE_MASK) != PHASE_MSGIN) { - printf ("sea: sea_msg_input: invalid phase %s\n", - PHASE_NAME (sts & PHASE_MASK)); - return (MSG_ABORT); - } - - /* Do actual transfer from SCSI bus to/from memory. */ - msg = *z->DATA; - sea_wait_for_req_deassert (z, 1000, "MSG_INPUT"); - PRINT (("sea%d (MSG_INPUT) got 0x%x\n", z->sc_link.adapter_unit, msg)); - return (msg); -} - -/* - * Send request-sense op to the target. - * Return 1 success, 0 on failure. - * Called on splbio level. - */ -int sea_sense (adapter_t *z, scb_t *scb) -{ - u_char cmd[6], status, msg, *data; - u_long len; - - /* Wait for target to disconnect. */ - WAITFOR (! (*z->STATUS & STAT_BSY), "sense bus free"); - if (*z->STATUS & STAT_BSY) - return (0); - - /* Select the target again. */ - if (! sea_select (z, scb)) - return (0); - - /* Wait for CMDOUT phase. */ - WAITFOR (*z->STATUS & STAT_REQ, "sense CMDOUT"); - if (! (*z->STATUS & STAT_REQ) || - (*z->STATUS & PHASE_MASK) != PHASE_CMDOUT) - return (0); - - /* Send command. */ - len = sizeof (scb->xfer->sense); - cmd[0] = REQUEST_SENSE; - cmd[1] = scb->xfer->sc_link->lun << 5; - cmd[2] = 0; - cmd[3] = 0; - cmd[4] = len; - cmd[5] = 0; - sea_cmd_output (&z->target[scb->xfer->sc_link->target], - cmd, sizeof (cmd)); - - /* Wait for DATAIN phase. */ - WAITFOR (*z->STATUS & STAT_REQ, "sense DATAIN"); - if (! (*z->STATUS & STAT_REQ) || - (*z->STATUS & PHASE_MASK) != PHASE_DATAIN) - return (0); - - data = (u_char*) &scb->xfer->sense; - sea_data_input (z, &data, &len); - PRINT (("sea%d sense %x-%x-%x-%x-%x-%x-%x-%x\n", - z->sc_link.adapter_unit, scb->xfer->sense.error_code, - scb->xfer->sense.ext.extended.segment, - scb->xfer->sense.ext.extended.flags, - scb->xfer->sense.ext.extended.info[0], - scb->xfer->sense.ext.extended.info[1], - scb->xfer->sense.ext.extended.info[2], - scb->xfer->sense.ext.extended.info[3], - scb->xfer->sense.ext.extended.extra_len)); - - /* Wait for STATIN phase. */ - WAITFOR (*z->STATUS & STAT_REQ, "sense STATIN"); - if (! (*z->STATUS & STAT_REQ) || - (*z->STATUS & PHASE_MASK) != PHASE_STATIN) - return (0); - - status = *z->DATA; - - /* Wait for MSGIN phase. */ - WAITFOR (*z->STATUS & STAT_REQ, "sense MSGIN"); - if (! (*z->STATUS & STAT_REQ) || - (*z->STATUS & PHASE_MASK) != PHASE_MSGIN) - return (0); - - msg = *z->DATA; - - if (status != 0 || msg != 0) - printf ("sea%d: bad sense status=0x%x, msg=0x%x\n", - z->sc_link.adapter_unit, status, msg); - return (1); -} - -/* - * Do the transfer. We know we are connected. Update the flags, - * call sea_done when task accomplished. Dialog controlled by the target. - * Always called with interrupts disabled. - */ -void sea_information_transfer (adapter_t *z, scb_t *scb) -{ - u_char *data = scb->data; /* current data buffer */ - u_long datalen = scb->datalen; /* current data transfer size */ - target_t *t = &z->target[scb->xfer->sc_link->target]; - register u_char sts; - u_char msg; - - while ((sts = *z->STATUS) & STAT_BSY) { - /* We only have a valid SCSI phase when REQ is asserted. */ - if (! (sts & STAT_REQ)) - continue; - if (sts & STAT_PARITY) { - int target = scb->xfer->sc_link->target; - if (++z->target[target].perrcnt <= 8) - printf ("sea%d/%d/%d parity error\n", - z->sc_link.adapter_unit, target, - scb->xfer->sc_link->lun); - if (z->target[target].perrcnt == 8) - printf ("sea%d/%d/%d too many parity errors, not logging any more\n", - z->sc_link.adapter_unit, target, - scb->xfer->sc_link->lun); - } - switch (sts & PHASE_MASK) { - case PHASE_DATAOUT: - if (datalen <= 0) { - printf ("sea%d/%d/%d data length underflow\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun); - /* send zero byte */ - *z->DATA = 0; - break; - } - sea_data_output (z, &data, &datalen); - break; - case PHASE_DATAIN: - if (datalen <= 0) { - /* Get extra data. Some devices (e.g. CDROMs) - * use fixed-length blocks (e.g. 2k), - * even if we need less. */ - PRINT (("@")); - sts = *z->DATA; - break; - } - sea_data_input (z, &data, &datalen); - break; - case PHASE_CMDOUT: - sea_cmd_output (t, (u_char*) scb->xfer->cmd, - scb->xfer->cmdlen); - break; - case PHASE_STATIN: - scb->xfer->status = *z->DATA; - if (z->type == CTLR_SEAGATE) - WAITREQ (t, statin, 2000); - PRINT (("sea%d/%d/%d (STATIN) got 0x%x\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, - (u_char) scb->xfer->status)); - break; - case PHASE_MSGOUT: - /* Send no-op message. */ - *z->DATA = MSG_NOP; - sea_wait_for_req_deassert (z, 1000, "MSGOUT"); - PRINT (("sea%d/%d/%d (MSGOUT) send NOP\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - break; - case PHASE_MSGIN: - /* Don't handle multi-byte messages here, because they - * should not be present here. */ - msg = *z->DATA; - sea_wait_for_req_deassert (z, 2000, "MSGIN"); - PRINT (("sea%d/%d/%d (MSGIN) got 0x%x\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, msg)); - switch (msg) { - case MSG_COMMAND_COMPLETE: - scb->data = data; - scb->datalen = datalen; - /* In the case of check-condition status, - * perform the request-sense op. */ - switch (scb->xfer->status & 0x1e) { - case SCSI_CHECK: - if (sea_sense (z, scb)) - scb->flags = SCB_SENSE; - break; - case SCSI_BUSY: - scb->flags = SCB_TBUSY; - break; - } - goto done; - case MSG_ABORT: - printf ("sea: command aborted by target\n"); - scb->flags = SCB_ABORTED; - goto done; - case MSG_MESSAGE_REJECT: - printf ("sea: message rejected\n"); - scb->flags = SCB_ABORTED; - goto done; - case MSG_DISCONNECT: - scb->next = z->disconnected_queue; - z->disconnected_queue = scb; - if (! z->irq && ! z->timeout_active) { - timeout (sea_tick, z, 1); - z->timeout_active = 1; - } - PRINT (("sea%d/%d/%d disconnected\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun)); - goto ret; - case MSG_SAVE_POINTERS: - scb->data = data; - scb->datalen = datalen; - break; - case MSG_RESTORE_POINTERS: - data = scb->data; - datalen = scb->datalen; - break; - default: - printf ("sea%d/%d/%d unknown message: 0x%x\n", - z->sc_link.adapter_unit, - scb->xfer->sc_link->target, - scb->xfer->sc_link->lun, msg); - break; - } - break; - default: - printf ("sea: unknown phase: %b\n", sts, STAT_BITS); - break; - } - } - printf ("sea%d/%d/%d unexpected target disconnect\n", - z->sc_link.adapter_unit, scb->xfer->sc_link->target, - scb->xfer->sc_link->lun); - scb->flags = SCB_ERROR; -done: - CLEAR_BUSY (z, scb); - sea_done (z, scb); -ret: - *z->CONTROL = CMD_INTR | z->parity; -} -#endif /* NSEA */ diff --git a/sys/i386/isa/ultra14f.c b/sys/i386/isa/ultra14f.c deleted file mode 100644 index 1687811..0000000 --- a/sys/i386/isa/ultra14f.c +++ /dev/null @@ -1,1366 +0,0 @@ -/* - * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu) - * Slight fixes to timeouts to run with the 34F - * Thanks to Julian Elischer for advice and help with this port. - * - * Written by Julian Elischer (julian@tfs.com) - * for TRW Financial Systems for use under the MACH(2.5) operating system. - * - * TRW Financial Systems, in accordance with their agreement with Carnegie - * Mellon University, makes this software available to CMU to distribute - * or use in any manner that they see fit as long as this message is kept with - * the software. For this reason TFS also grants any other persons or - * organisations permission to use or modify this software. - * - * TFS supplies this software to be publicly redistributed - * on the understanding that TFS is not responsible for the correct - * functioning of this software in any circumstances. - * - * commenced: Sun Sep 27 18:14:01 PDT 1992 - * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993 - * - * today: Fri Jun 2 17:21:03 EST 1994 - * added 24F support ++sg - * - * $Id: ultra14f.c,v 1.61 1998/06/21 15:49:39 bde Exp $ - */ - -#ifdef KERNEL /* don't laugh.. this compiles to a program too.. look */ -#include "uha.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/malloc.h> -#include <sys/buf.h> -#include <sys/kernel.h> - -#include <machine/clock.h> - -#include <vm/vm.h> -#include <vm/pmap.h> - -#include <i386/isa/isa_device.h> -#endif /*KERNEL */ -#include <scsi/scsiconf.h> -#include <scsi/scsi_debug.h> - -/* */ - -#ifndef KERNEL -#define NUHA 1 -#endif /*KERNEL */ - -typedef struct { - unsigned char addr[4]; -} physaddr; -typedef struct { - unsigned char len[4]; -} physlen; - -#define KVTOPHYS(x) vtophys(x) - -#define UHA_MSCP_MAX 32 /* store up to 32MSCPs at any one time - * MAX = ? - */ -#define MSCP_HASH_SIZE 32 /* when we have a physical addr. for - * a mscp and need to find the mscp in - * space, look it up in the hash table - */ -#define MSCP_HASH_SHIFT 9 /* only hash on multiples of 512 */ -#define MSCP_HASH(x) ((((long int)(x))>>MSCP_HASH_SHIFT) % MSCP_HASH_SIZE) - -#define UHA_NSEG 33 /* number of dma segments supported */ - -/************************** board definitions *******************************/ -struct uha_reg -{ - int id; /* product id reg */ - int type; /* product type reg */ - int ectl; /* EISA expansion control bits */ - int config; /* configuration bits */ - int lmask; /* local doorbell mask reg */ - int lint; /* local doorbell int/stat reg */ - int smask; /* system doorbell mask reg */ - int sint; /* system doorbell int/stat reg */ - int ogmcmd; /* outgoing mail command */ - int ogmptr; /* outgoing mail ptr */ - int icmcmd; /* incoming mail command */ - int icmptr; /* incoming mail ptr */ -}; - -struct uha_bits -{ - /* uha_lint (read) */ - unsigned char ldip; - - /* uha_lint (write) */ - unsigned char adrst; - unsigned char sbrst; - unsigned char asrst; - unsigned char abort; - unsigned char ogmint; - - /* uha_sint (read) */ - unsigned char sintp; - unsigned char abort_succ; - unsigned char abort_fail; - - /* uha_sint (write) */ - unsigned char abort_ack; - unsigned char icm_ack; -}; - - -/* - * UHA_LINT bits (read) - */ - -#define UHA_LDIP 0x80 /* local doorbell int pending */ -#define U24_LDIP 0x02 - -/* - * UHA_LINT bits (write) - */ - -#define UHA_ADRST 0x40 /* adapter soft reset */ -#define UHA_SBRST 0x20 /* scsi bus reset */ -#define UHA_ASRST 0x60 /* adapter and scsi reset */ -#define UHA_ABORT 0x10 /* abort MSCP */ -#define UHA_OGMINT 0x01 /* tell adapter to get mail */ -#define U24_SBRST 0x40 /* scsi bus reset */ -#define U24_ADRST 0x80 /* adapter soft reset */ -#define U24_ASRST 0xc0 /* adapter and scsi reset */ -#define U24_ABORT 0x10 /* same? */ -#define U24_OGMINT 0x02 /* enable OGM interrupt */ - -/* - * UHA_SMASK bits (read) - */ - -#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */ -#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */ -#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled */ - -/* - * UHA_SMASK bits (write) - */ - -#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */ -#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */ -#define UHA_ENICM 0x01 /* enable ICM interrupt */ - -/* - * UHA_SINT bits (read) - */ - -#define UHA_SINTP 0x80 /* system doorbell int pending */ -#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */ -#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */ -#define U24_SINTP 0x02 /* system doorbell int pending */ -#define U24_ABORT_SUCC 0x10 /* same? */ -#define U24_ABORT_FAIL 0x18 /* same? */ - -/* - * UHA_SINT bits (write) - */ - -#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */ -#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */ -#define U24_ABORT_ACK 0x18 /* same */ -#define U24_ICM_ACK 0x02 /* 24F acknowledge ICM and clear */ - -/* - * UHA_CONF1 bits (read only) - */ - -#define UHA_DMA_CH5 0x00 /* DMA channel 5 */ -#define UHA_DMA_CH6 0x40 /* 6 */ -#define UHA_DMA_CH7 0x80 /* 7 */ -#define UHA_IRQ15 0x00 /* IRQ 15 */ -#define UHA_IRQ14 0x10 /* 14 */ -#define UHA_IRQ11 0x20 /* 11 */ -#define UHA_IRQ10 0x30 /* 10 */ - -#define EISA_CONFIG 0x0c80 /* Configuration base port */ -#define EISA_DISABLE 0x01 /* EISA disable bit */ - -/* - * ha_status error codes - */ - -#define UHA_NO_ERR 0x00 /* No error supposedly */ -#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */ -#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */ -#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */ -#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */ -#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */ -#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */ -#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */ - -struct uha_dma_seg { - physaddr addr; - physlen len; -}; - -struct mscp { - unsigned int opcode:3; -#define U14_HAC 0x01 /* host adapter command */ -#define U14_TSP 0x02 /* target scsi pass through command */ -#define U14_SDR 0x04 /* scsi device reset */ - unsigned int xdir:2; /* xfer direction */ -#define U14_SDET 0x00 /* determined by scsi command */ -#define U14_SDIN 0x01 /* scsi data in */ -#define U14_SDOUT 0x02 /* scsi data out */ -#define U14_NODATA 0x03 /* no data xfer */ - unsigned int dcn:1; /* disable disconnect for this command */ - unsigned int ca:1; /* cache control */ - unsigned int sgth:1; /* scatter gather flag */ - unsigned int target:3; - unsigned int chan:2; /* scsi channel (always 0 for 14f) */ - unsigned int lun:3; - physaddr data; - physlen datalen; - physaddr link; - unsigned char link_id; - unsigned char sg_num; /*number of scat gath segs */ - /*in s-g list if sg flag is */ - /*set. starts at 1, 8bytes per */ - unsigned char senselen; - unsigned char cdblen; - unsigned char cdb[12]; - unsigned char ha_status; - unsigned char targ_status; - physaddr sense; /* if 0 no auto sense */ - /*-----------------end of hardware supported fields----------------*/ - struct mscp *next; /* in free list */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - int flags; -#define MSCP_FREE 0 -#define MSCP_ACTIVE 1 -#define MSCP_ABORTED 2 - struct uha_dma_seg uha_dma[UHA_NSEG]; - struct scsi_sense_data mscp_sense; - struct mscp *nexthash; - long int hashkey; -}; - -static struct uha_data { - int flags; -#define UHA_INIT 0x01 -#define UHA_24F 0x02 - int baseport; - struct mscp *mscphash[MSCP_HASH_SIZE]; - struct mscp *free_mscp; - int unit; - int our_id; /* our scsi id */ - int vect; - int dma; - int nummscps; - struct scsi_link sc_link; - struct uha_reg *ur; - struct uha_bits *ub; -} *uhadata[NUHA]; - -static int uha_abort __P((struct uha_data *uha, struct mscp *mscp)); -static u_int32_t uha_adapter_info __P((int unit)); -static int uha_attach __P((struct isa_device *dev)); -static void uha_done __P((struct uha_data *uha, struct mscp *mscp)); -static void uha_free_mscp __P((struct uha_data *uha, struct mscp *mscp, - int flags)); -static struct mscp * - uha_get_mscp __P((struct uha_data *uha, int flags)); -static int uha_init __P((struct uha_data *uha)); -static int uha24_init __P((struct uha_data *uha)); -static ointhand2_t - uhaintr; -static void uhaminphys __P((struct buf *bp)); -static struct mscp * - uha_mscp_phys_kv __P((struct uha_data *uha, long mscp_phys)); -static int uha_poll __P((struct uha_data *uha, int wait)); -#ifdef UHADEBUG -static void uha_print_active_mscp __P((struct uha_data *uha)); -static void uha_print_mscp __P((struct mscp *mscp)); -#endif -static int uhaprobe __P((struct isa_device *dev)); -static int32_t uha_scsi_cmd __P((struct scsi_xfer *xs)); -static void uha_send_mbox __P((struct uha_data *uha, struct mscp *mscp)); -static timeout_t - uha_timeout; - -static unsigned long int scratch; -#define EISA_MAX_SLOTS 16 /* XXX This should go into a comon header */ -static int uha_slot; /* slot last board was found in */ -static int uha_unit; -#define UHA_SHOWMSCPS 0x01 -#define UHA_SHOWINTS 0x02 -#define UHA_SHOWCMDS 0x04 -#define UHA_SHOWMISC 0x08 -#define FAIL 1 -#define SUCCESS 0 -#define PAGESIZ 4096 - -#ifdef KERNEL -struct isa_driver uhadriver = -{ - uhaprobe, - uha_attach, - "uha" -}; - -static struct scsi_adapter uha_switch = -{ - uha_scsi_cmd, - uhaminphys, - 0, - 0, - uha_adapter_info, - "uha", - { 0, 0 } -}; - -/* the below structure is so we have a default dev struct for out link struct */ -static struct scsi_device uha_dev = -{ - NULL, /* Use default error handler */ - NULL, /* have a queue, served by this */ - NULL, /* have no async handler */ - NULL, /* Use default 'done' routine */ - "uha", - 0, - { 0, 0 } -}; - -#endif /*KERNEL */ - -#ifndef KERNEL -main() -{ - printf("uha_data is %d bytes\n", sizeof(struct uha_data)); - printf("mscp is %d bytes\n", sizeof(struct mscp)); -} - -#else /*KERNEL*/ -/* - * Function to send a command out through a mailbox - */ -static void -uha_send_mbox(struct uha_data *uha, struct mscp *mscp) -{ - int spincount = 100000; /* 1s should be enough */ - struct uha_reg *ur = uha->ur; - struct uha_bits *ub = uha->ub; - int s = splbio(); - - while (--spincount) { - if ((inb(ur->lint) & ub->ldip) == 0) - break; - DELAY(100); - } - if (spincount == 0) { - printf("uha%d: uha_send_mbox, board is not responding\n", - uha->unit); - Debugger("ultra14f"); - } - outl(ur->ogmptr, KVTOPHYS(mscp)); - if (uha->flags & UHA_24F) outb(ur->ogmcmd, 1); - outb(ur->lint, ub->ogmint); - splx(s); -} - -/* - * Function to send abort to 14f - */ -int -uha_abort(struct uha_data *uha, struct mscp *mscp) -{ - int spincount = 100; /* 1 mSec */ - int abortcount = 200000; /*2 secs */ - struct uha_reg *ur = uha->ur; - struct uha_bits *ub = uha->ub; - int s = splbio(); - - while (--spincount) { - if ((inb(ur->lint) & ub->ldip) == 0) - break; - DELAY(10); - } - if (spincount == 0) { - printf("uha%d: uha_abort, board is not responding\n", uha->unit); - Debugger("ultra14f"); - } - outl(ur->ogmptr,KVTOPHYS(mscp)); - if (uha->flags & UHA_24F) outb(ur->ogmcmd, 1); - outb(ur->lint, ub->abort); - - while (--abortcount) { - if (inb(ur->sint) & ub->abort_fail) - break; - DELAY(10); - } - if (abortcount == 0) { - printf("uha%d: uha_abort, board is not responding\n", uha->unit); - Debugger("ultra14f"); - } - if ((inb(ur->sint) & 0x10) != 0) { - outb(ur->sint, ub->abort_ack); - splx(s); - return (1); - } else { - outb(ur->sint, ub->abort_ack); - splx(s); - return (0); - } -} - -/* - * Function to poll for command completion when in poll mode. - * - * wait = timeout in msec - */ -static int -uha_poll(struct uha_data *uha, int wait) -{ - struct uha_reg *ur = uha->ur; - struct uha_bits *ub = uha->ub; - int stport = ur->sint; - - while (--wait) { - if (inb(stport) & ub->sintp) - break; - DELAY(1000); /* 1 mSec per loop */ - } - if (wait == 0) { - printf("uha%d: uha_poll, board is not responding\n", uha->unit); - return (EIO); - } - uhaintr(uha->unit); - return (0); -} - -/* - * Check if the device can be found at the port given and if so, set it up - * ready for further work as an argument, takes the isa_device structure - * from autoconf.c - */ -int -uhaprobe(dev) - struct isa_device *dev; -{ - int unit = uha_unit; - struct uha_data *uha; - - dev->id_unit = unit; /* XXX */ - - /* - * find unit and check we have that many defined - */ - if (unit >= NUHA) { - printf("uha: unit number (%d) too high\n", unit); - return (0); - } - dev->id_unit = unit; - - /* - * Allocate a storage area for us - */ - if (uhadata[unit]) { - printf("uha%d: memory already allocated\n", unit); - return 0; - } - uha = malloc(sizeof(struct uha_data), M_TEMP, M_NOWAIT); - if (!uha) { - printf("uha%d: cannot malloc!\n", unit); - return 0; - } - bzero(uha, sizeof(struct uha_data)); - - uha->ur = malloc(sizeof(struct uha_reg), M_TEMP, M_NOWAIT); - if (!uha->ur) { - printf("uha%d: cannot malloc!\n", unit); - return 0; - } - bzero(uha->ur, sizeof(struct uha_reg)); - - uha->ub = malloc(sizeof(struct uha_bits), M_TEMP, M_NOWAIT); - if (!uha->ub) { - printf("uha%d: cannot malloc!\n", unit); - return 0; - } - bzero(uha->ub, sizeof(struct uha_bits)); - - uhadata[unit] = uha; - uha->unit = unit; - uha->baseport = dev->id_iobase; - /* - * Try initialise a unit at this location - * sets up dma and bus speed, loads uha->vect - */ - if (uha_init(uha) != 0 && uha24_init(uha) != 0) { - uhadata[unit] = NULL; - free(uha->ur, M_TEMP); - free(uha->ub, M_TEMP); - free(uha, M_TEMP); - return (0); - } - /* if it's there put in its interrupt and DRQ vectors */ - dev->id_irq = (1 << uha->vect); - dev->id_drq = uha->dma; - dev->id_iobase = uha->baseport; - - uha_unit++; - return (16); -} - -/* - * Attach all the sub-devices we can find - */ -int -uha_attach(dev) - struct isa_device *dev; -{ - int unit = dev->id_unit; - struct uha_data *uha = uhadata[unit]; - struct scsibus_data *scbus; - - dev->id_ointr = uhaintr; - - /* - * fill in the prototype scsi_link. - */ - uha->sc_link.adapter_unit = unit; - uha->sc_link.adapter_targ = uha->our_id; - uha->sc_link.adapter_softc = uha; - uha->sc_link.adapter = &uha_switch; - uha->sc_link.device = &uha_dev; - uha->sc_link.flags = SDEV_BOUNCE; - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = &uha->sc_link; - - /* - * ask the adapter what subunits are present - */ - scsi_attachdevs(scbus); - - return 1; -} - -/* - * Return some information to the caller about - * the adapter and its capabilities - */ -u_int32_t -uha_adapter_info(unit) - int unit; -{ - return (2); /* 2 outstanding requests at a time per device */ -} - -/* - * Catch an interrupt from the adaptor - */ -static void -uhaintr(unit) - int unit; -{ - struct uha_data *uha = uhadata[unit]; - struct mscp *mscp; - u_char uhastat; - unsigned long int mboxval; - struct uha_reg *ur; - struct uha_bits *ub; - int port; - - ur = uha->ur; - ub = uha->ub; - port = uha->baseport; - -#ifdef UHADEBUG - printf("uhaintr "); -#endif /*UHADEBUG */ - - while ((uhastat = inb(ur->sint)) & ub->sintp) { - /* - * First get all the information and then - * acknowledge the interrupt - */ - mboxval = inl(ur->icmptr); - outb(ur->sint, ub->icm_ack); - if (uha->flags & UHA_24F) outb(ur->icmcmd, 0); - -#ifdef UHADEBUG - printf("status = 0x%x ", uhastat); -#endif /*UHADEBUG*/ - /* - * Process the completed operation - */ - - mscp = uha_mscp_phys_kv(uha, mboxval); - if (!mscp) { - printf("uha: BAD MSCP RETURNED\n"); - return; /* whatever it was, it'll timeout */ - } - untimeout(uha_timeout, (caddr_t)mscp, mscp->xs->timeout_ch); - - uha_done(uha, mscp); - } -} - -/* - * We have a mscp which has been processed by the adaptor, now we look to see - * how the operation went. - */ -void -uha_done(uha, mscp) - struct uha_data *uha; - struct mscp *mscp; -{ - struct scsi_sense_data *s1, *s2; - struct scsi_xfer *xs = mscp->xs; - - SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); - /* - * Otherwise, put the results of the operation - * into the xfer and call whoever started it - */ - if (((mscp->ha_status != UHA_NO_ERR) || (mscp->targ_status != SCSI_OK)) - && ((xs->flags & SCSI_ERR_OK) == 0)) { - - s1 = &(mscp->mscp_sense); - s2 = &(xs->sense); - - if (mscp->ha_status != UHA_NO_ERR) { - switch (mscp->ha_status) { - case UHA_SBUS_ABORT_ERR: - case UHA_SBUS_TIMEOUT: /* No sel response */ - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("abort or timeout; ha_status 0x%x\n", - mscp->ha_status)); - xs->error = XS_TIMEOUT; - break; - case UHA_SBUS_OVER_UNDER: - SC_DEBUG(xs->sc_link, SDEV_DB3, - ("scsi bus xfer over/underrun\n")); - xs->error = XS_DRIVER_STUFFUP; - break; - default: /* Other scsi protocol messes */ - xs->error = XS_DRIVER_STUFFUP; - printf("uha%d: unexpected ha_status 0x%x (target status 0x%x)\n", - uha->unit, mscp->ha_status, - mscp->targ_status); - break; - } - } else { - /* Target status problem */ - SC_DEBUG(xs->sc_link, SDEV_DB3, ("target err 0x%x\n", - mscp->targ_status)); - switch (mscp->targ_status) { - case 0x02: - *s2 = *s1; - xs->error = XS_SENSE; - break; - case 0x08: - xs->error = XS_BUSY; - break; - default: - printf("uha%d: unexpected targ_status 0x%x\n", - uha->unit, mscp->targ_status); - xs->error = XS_DRIVER_STUFFUP; - break; - } - } - } - else { - /* All went correctly OR errors expected */ - xs->resid = 0; - xs->error = 0; - } - xs->flags |= ITSDONE; - uha_free_mscp(uha, mscp, xs->flags); - scsi_done(xs); -} - -/* - * A mscp (and hence a mbx-out) is put onto the free list. - */ -void -uha_free_mscp(uha, mscp, flags) - struct uha_data *uha; - struct mscp *mscp; - int flags; -{ - unsigned int opri = 0; - - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - - mscp->next = uha->free_mscp; - uha->free_mscp = mscp; - mscp->flags = MSCP_FREE; - /* - * If there were none, wake abybody waiting for - * one to come free, starting with queued entries - */ - if (!mscp->next) { - wakeup((caddr_t)&uha->free_mscp); - } - if (!(flags & SCSI_NOMASK)) - splx(opri); -} - -/* - * Get a free mscp - * - * If there are none, see if we can allocate a new one. If so, put it in the - * hash table too otherwise either return an error or sleep. - */ -static struct mscp * -uha_get_mscp(uha, flags) - struct uha_data *uha; - int flags; -{ - unsigned opri = 0; - struct mscp *mscpp; - int hashnum; - - if (!(flags & SCSI_NOMASK)) - opri = splbio(); - /* - * If we can and have to, sleep waiting for one to come free - * but only if we can't allocate a new one - */ - while (!(mscpp = uha->free_mscp)) { - if (uha->nummscps < UHA_MSCP_MAX) { - if (mscpp = (struct mscp *)malloc(sizeof(struct mscp), - M_TEMP, - M_NOWAIT)) { - bzero(mscpp, sizeof(struct mscp)); - uha->nummscps++; - mscpp->flags = MSCP_ACTIVE; - /* - * put in the phystokv hash table - * Never gets taken out. - */ - mscpp->hashkey = KVTOPHYS(mscpp); - hashnum = MSCP_HASH(mscpp->hashkey); - mscpp->nexthash = uha->mscphash[hashnum]; - uha->mscphash[hashnum] = mscpp; - } else { - printf("uha%d: Can't malloc MSCP\n", uha->unit); - } - goto gottit; - } else { - if (!(flags & SCSI_NOSLEEP)) { - tsleep((caddr_t)&uha->free_mscp, PRIBIO, - "uhamscp", 0); - } - } - } - if (mscpp) { - /* Get MSCP from from free list */ - uha->free_mscp = mscpp->next; - mscpp->flags = MSCP_ACTIVE; - } - gottit: - if (!(flags & SCSI_NOMASK)) - splx(opri); - - return (mscpp); -} - -/* - * given a physical address, find the mscp that it corresponds to. - */ -static struct mscp * -uha_mscp_phys_kv(uha, mscp_phys) - struct uha_data *uha; - long int mscp_phys; -{ - int hashnum = MSCP_HASH(mscp_phys); - struct mscp *mscpp = uha->mscphash[hashnum]; - - while (mscpp) { - if (mscpp->hashkey == mscp_phys) - break; - mscpp = mscpp->nexthash; - } - return mscpp; -} - -/* - * Start the board, ready for normal operation - */ -int -uha_init(uha) - struct uha_data *uha; -{ - volatile unsigned char model; - volatile unsigned char submodel; - unsigned char config_reg1; - unsigned char config_reg2; - unsigned char dma_ch; - unsigned char irq_ch; - unsigned char uha_id; - int port = uha->baseport; - int resetcount = 4000; /* 4 secs? */ - struct uha_reg *ur = uha->ur; - struct uha_bits *ub = uha->ub; - - /* - * Prepare to use a 14/34F. - */ - ur->id = port + 0x04; - ur->type = port + 0x00; /* 24F only */ - ur->ectl = port + 0x00; /* 24F only */ - ur->config = port + 0x06; /* 0-1 for 14F */ - ur->lmask = port + 0x00; - ur->lint = port + 0x01; - ur->smask = port + 0x02; - ur->sint = port + 0x03; - ur->ogmcmd = port + 0x00; /* 24F only */ - ur->ogmptr = port + 0x08; - ur->icmcmd = port + 0x00; /* 24F only */ - ur->icmptr = port + 0x0c; - - ub->ldip = UHA_LDIP; - ub->adrst = UHA_ADRST; - ub->sbrst = UHA_SBRST; - ub->asrst = UHA_ASRST; - ub->abort = UHA_ABORT; - ub->ogmint = UHA_OGMINT; - ub->sintp = UHA_SINTP; - ub->abort_succ = UHA_ABORT_SUCC; - ub->abort_fail = UHA_ABORT_FAIL; - ub->abort_ack = UHA_ABORT_ACK; - ub->icm_ack = UHA_ICM_ACK; - - model = inb(ur->id); - submodel = inb(ur->id + 1); - if ((model != 0x56) & (submodel != 0x40)) return(ENXIO); - printf("uha%d: reading board settings, ", uha->unit); - - config_reg1 = inb(ur->config); - config_reg2 = inb(ur->config + 1); - dma_ch = (config_reg1 & 0xc0); - irq_ch = (config_reg1 & 0x30); - uha_id = (config_reg2 & 0x07); - - switch (dma_ch) { - case UHA_DMA_CH5: - uha->dma = 5; - printf("dma=5 "); - break; - case UHA_DMA_CH6: - uha->dma = 6; - printf("dma=6 "); - break; - case UHA_DMA_CH7: - uha->dma = 7; - printf("dma=7 "); - break; - default: - printf("illegal dma jumper setting\n"); - return (EIO); - } - switch (irq_ch) { - case UHA_IRQ10: - uha->vect = 10; - printf("int=10 "); - break; - case UHA_IRQ11: - uha->vect = 11; - printf("int=11 "); - break; - case UHA_IRQ14: - uha->vect = 14; - printf("int=14 "); - break; - case UHA_IRQ15: - uha->vect = 15; - printf("int=15 "); - break; - default: - printf("illegal int jumper setting\n"); - return (EIO); - } - - /* who are we on the scsi bus */ - printf("id=%x\n", uha_id); - uha->our_id = uha_id; - - /* - * Note that we are going and return (to probe) - */ - outb(ur->lint, ub->asrst); - while (--resetcount) { - if (inb(ur->lint)) - break; - DELAY(1000); /* 1 mSec per loop */ - } - if (resetcount == 0) { - printf("uha%d: board timed out during reset\n", uha->unit); - return (ENXIO); - } - outb(ur->smask, 0x81); /* make sure interrupts are enabled */ - uha->flags |= UHA_INIT; - return (0); -} - - -/* - * Initialize an Ultrastor 24F - */ -int -uha24_init(uha) - struct uha_data *uha; -{ - unsigned char p0, p1, p2, p3, p5, p7; - unsigned char id[7], rev, haid; - int port = 0, irq; - int resetcount = 4000; - struct uha_reg *ur = uha->ur; - struct uha_bits *ub = uha->ub; - - /* Search for the 24F's product ID */ - uha_slot++; - while (uha_slot < EISA_MAX_SLOTS) { - /* - * Prepare to use a 24F. - */ - port = EISA_CONFIG | (uha_slot << 12); - ur->id = port + 0x00; - ur->type = port + 0x02; - ur->ectl = port + 0x04; - ur->config = port + 0x05; /* 0-2 for 24F */ - ur->lmask = port + 0x0c; - ur->lint = port + 0x0d; - ur->smask = port + 0x0e; - ur->sint = port + 0x0f; - ur->ogmcmd = port + 0x16; - ur->ogmptr = port + 0x17; - ur->icmcmd = port + 0x1b; - ur->icmptr = port + 0x1c; - - ub->ldip = U24_LDIP; - ub->adrst = U24_ADRST; - ub->sbrst = U24_SBRST; - ub->asrst = U24_ASRST; - ub->abort = U24_ABORT; - ub->ogmint = U24_OGMINT; - ub->sintp = U24_SINTP; - ub->abort_succ = U24_ABORT_SUCC; - ub->abort_fail = U24_ABORT_FAIL; - ub->abort_ack = U24_ABORT_ACK; - ub->icm_ack = U24_ICM_ACK; - - /* - * Make sure an EISA card is installed in this slot, - * and if it is make sure that the card is enabled. - */ - outb(ur->id, 0xff); - p0 = inb(ur->id); - if ((p0 == 0xff) || - ((p0 & 0x80) != 0) || - ((inb(ur->ectl) & EISA_DISABLE) == 0)) { - uha_slot++; - continue; - } - - /* Found an enabled card. Grab the product ID. */ - p1 = inb(ur->id+1); - p2 = inb(ur->type); - p3 = inb(ur->type+1); - id[0] = 0x40 + ((p0 >> 2) & 0x1f); - id[1] = 0x40 + (((p0 & 0x03) << 3) | ((p1 >> 5) & 0x07)); - id[2] = 0x40 + (p1 & 0x1f); - id[3] = hex2ascii((p2 >> 4) & 0x0f); - id[4] = hex2ascii(p2 & 0x0f); - id[5] = hex2ascii((p3 >> 4) & 0x0f); - id[6] = '\0'; - rev = p3 & 0xf; - - /* We only want the 24F product ID. */ - if (!strcmp(id, "USC024")) break; - uha_slot++; - } - if (uha_slot == EISA_MAX_SLOTS) return(ENODEV); - - /* We have the card! Grab remaining config. */ - p5 = inb(ur->config); - p7 = inb(ur->config+2); - - switch (p5 & 0xf0) { - case 0x10: irq = 15; break; - case 0x20: irq = 14; break; - case 0x40: irq = 11; break; - case 0x80: irq = 10; break; - default: - printf("uha%d: bad 24F irq\n", uha->unit); - return(ENXIO); - } - - haid = (p7 & 0x07); - printf("uha%d: UltraStor 24F int=%d id=%d\n", uha->unit, irq, haid); - - /* Issue SCSI and adapter reset */ - outb(ur->lint, ub->asrst); - while (--resetcount) { - if (inb(ur->lint)) - break; - DELAY(1000); /* 1 mSec per loop */ - } - if (resetcount == 0) { - printf("uha%d: board timed out during reset\n", uha->unit); - return (ENXIO); - } - outb(ur->smask, 0xc2); /* make sure interrupts are enabled */ - uha->flags |= (UHA_INIT | UHA_24F); - uha->baseport = port; - uha->our_id = haid; - uha->vect = irq; - uha->dma = -1; - return(0); -} - -#ifndef min -#define min(x,y) (x < y ? x : y) -#endif /* min */ - -void -uhaminphys(bp) - struct buf *bp; -{ - if (bp->b_bcount > ((UHA_NSEG - 1) * PAGESIZ)) { - bp->b_bcount = ((UHA_NSEG - 1) * PAGESIZ); - } -} - -/* - * start a scsi operation given the command and the data address. Also - * needs the unit, target and lu. - */ -static int32_t -uha_scsi_cmd(xs) - struct scsi_xfer *xs; -{ - struct mscp *mscp; - struct uha_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - int thiskv; - unsigned long int thisphys, nextphys; - int bytes_this_seg, bytes_this_page, datalen, flags; - struct uha_data *uha; - int s; - unsigned long int templen; - - uha = (struct uha_data *)xs->sc_link->adapter_softc; - SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); - /* - * get a mscp (mbox-out) to use. If the transfer - * is from a buf (possibly from interrupt time) - * then we can't allow it to sleep - */ - flags = xs->flags; - if (xs->bp) - flags |= (SCSI_NOSLEEP); /* just to be sure */ - if (flags & ITSDONE) { - printf("uha%d: Already done?", uha->unit); - xs->flags &= ~ITSDONE; - } - if (!(flags & INUSE)) { - printf("uha%d: Not in use?", uha->unit); - xs->flags |= INUSE; - } - if (!(mscp = uha_get_mscp(uha, flags))) { - xs->error = XS_DRIVER_STUFFUP; - return (TRY_AGAIN_LATER); - } - SC_DEBUG(xs->sc_link, SDEV_DB3, ("start mscp(%p)\n", mscp)); - mscp->xs = xs; - - /* - * Put all the arguments for the xfer in the mscp - */ - if (flags & SCSI_RESET) { - mscp->opcode = 0x04; - mscp->ca = 0x01; - } else { - mscp->opcode = 0x02; - mscp->ca = 0x01; - } - if (flags & SCSI_DATA_IN) { - mscp->xdir = 0x01; - } - if (flags & SCSI_DATA_OUT) { - mscp->xdir = 0x02; - } -#ifdef GOTTABEJOKING - if (xs->sc_link->lun != 0) { - xs->error = XS_DRIVER_STUFFUP; - uha_free_mscp(uha, mscp, flags); - return (HAD_ERROR); - } -#endif - mscp->dcn = 0x00; - mscp->chan = 0x00; - mscp->target = xs->sc_link->target; - mscp->lun = xs->sc_link->lun; - mscp->link.addr[0] = 0x00; - mscp->link.addr[1] = 0x00; - mscp->link.addr[2] = 0x00; - mscp->link.addr[3] = 0x00; - mscp->link_id = 0x00; - mscp->cdblen = xs->cmdlen; - scratch = KVTOPHYS(&(mscp->mscp_sense)); - mscp->sense.addr[0] = (scratch & 0xff); - mscp->sense.addr[1] = ((scratch >> 8) & 0xff); - mscp->sense.addr[2] = ((scratch >> 16) & 0xff); - mscp->sense.addr[3] = ((scratch >> 24) & 0xff); - mscp->senselen = sizeof(mscp->mscp_sense); - mscp->ha_status = 0x00; - mscp->targ_status = 0x00; - - if (xs->datalen) { /* should use S/G only if not zero length */ - scratch = KVTOPHYS(mscp->uha_dma); - mscp->data.addr[0] = (scratch & 0xff); - mscp->data.addr[1] = ((scratch >> 8) & 0xff); - mscp->data.addr[2] = ((scratch >> 16) & 0xff); - mscp->data.addr[3] = ((scratch >> 24) & 0xff); - sg = mscp->uha_dma; - seg = 0; - mscp->sgth = 0x01; - -#ifdef TFS - if (flags & SCSI_DATA_UIO) { - iovp = ((struct uio *) xs->data)->uio_iov; - datalen = ((struct uio *) xs->data)->uio_iovcnt; - xs->datalen = 0; - while ((datalen) && (seg < UHA_NSEG)) { - scratch = (unsigned long) iovp->iov_base; - sg->addr.addr[0] = (scratch & 0xff); - sg->addr.addr[1] = ((scratch >> 8) & 0xff); - sg->addr.addr[2] = ((scratch >> 16) & 0xff); - sg->addr.addr[3] = ((scratch >> 24) & 0xff); - xs->datalen += *(unsigned long *) sg->len.len = iovp->iov_len; - SC_DEBUGN(xs->sc_link, SDEV_DB4, ("(0x%x@0x%x)", - iovp->iov_len, - iovp->iov_base)); - sg++; - iovp++; - seg++; - datalen--; - } - } else -#endif /*TFS */ - { - /* - * Set up the scatter gather block - */ - - SC_DEBUG(xs->sc_link, SDEV_DB4, - ("%ld @%p:- ", xs->datalen, xs->data)); - datalen = xs->datalen; - thiskv = (int) xs->data; - thisphys = KVTOPHYS(thiskv); - templen = 0; - - while ((datalen) && (seg < UHA_NSEG)) { - bytes_this_seg = 0; - - /* put in the base address */ - sg->addr.addr[0] = (thisphys & 0xff); - sg->addr.addr[1] = ((thisphys >> 8) & 0xff); - sg->addr.addr[2] = ((thisphys >> 16) & 0xff); - sg->addr.addr[3] = ((thisphys >> 24) & 0xff); - - SC_DEBUGN(xs->sc_link, SDEV_DB4, ("0x%lx", - thisphys)); - - /* do it at least once */ - nextphys = thisphys; - while ((datalen) && (thisphys == nextphys)) - /* - * This page is contiguous (physically) with - * the the last, just extend the length - */ - { - /* how far to the end of the page */ - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = nextphys - thisphys; - /**** or the data ****/ - bytes_this_page = min(bytes_this_page - ,datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - - /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if (datalen) - thisphys = KVTOPHYS(thiskv); - } - /* - * next page isn't contiguous, finish the seg - */ - SC_DEBUGN(xs->sc_link, SDEV_DB4, - ("(0x%x)", bytes_this_seg)); - sg->len.len[0] = (bytes_this_seg & 0xff); - sg->len.len[1] = ((bytes_this_seg >> 8) & 0xff); - sg->len.len[2] = ((bytes_this_seg >> 16) & 0xff); - sg->len.len[3] = ((bytes_this_seg >> 24) & 0xff); - templen += bytes_this_seg; - sg++; - seg++; - } - } - - /* end of iov/kv decision */ - mscp->datalen.len[0] = (templen & 0xff); - mscp->datalen.len[1] = ((templen >> 8) & 0xff); - mscp->datalen.len[2] = ((templen >> 16) & 0xff); - mscp->datalen.len[3] = ((templen >> 24) & 0xff); - mscp->sg_num = seg; - - SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); - if (datalen) { /* there's still data, must have run out of segs! */ - printf("uha%d: uha_scsi_cmd, more than %d DMA segs\n", - uha->unit, UHA_NSEG); - xs->error = XS_DRIVER_STUFFUP; - uha_free_mscp(uha, mscp, flags); - return (HAD_ERROR); - } - } else { /* No data xfer, use non S/G values */ - mscp->data.addr[0] = 0x00; - mscp->data.addr[1] = 0x00; - mscp->data.addr[2] = 0x00; - mscp->data.addr[3] = 0x00; - mscp->datalen.len[0] = 0x00; - mscp->datalen.len[1] = 0x00; - mscp->datalen.len[2] = 0x00; - mscp->datalen.len[3] = 0x00; - mscp->xdir = 0x03; - mscp->sgth = 0x00; - mscp->sg_num = 0x00; - } - - /* - * Put the scsi command in the mscp and start it - */ - bcopy(xs->cmd, mscp->cdb, xs->cmdlen); - - /* - * Usually return SUCCESSFULLY QUEUED - */ - if (!(flags & SCSI_NOMASK)) { - s = splbio(); - uha_send_mbox(uha, mscp); - xs->timeout_ch = timeout(uha_timeout, (caddr_t)mscp, - (xs->timeout * hz) / 1000); - splx(s); - SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n")); - return (SUCCESSFULLY_QUEUED); - } - - /* - * If we can't use interrupts, poll on completion - */ - uha_send_mbox(uha, mscp); - SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_wait\n")); - do { - if (uha_poll(uha, xs->timeout)) { - if (!(xs->flags & SCSI_SILENT)) - printf("uha%d: cmd fail\n", uha->unit); - if (!(uha_abort(uha, mscp))) { - printf("uha%d: abort failed in wait\n", - uha->unit); - uha_free_mscp(uha, mscp, flags); - } - xs->error = XS_DRIVER_STUFFUP; - return (HAD_ERROR); - } - } - while (!(xs->flags & ITSDONE)); /* something (?) else finished */ - if (xs->error) { - return (HAD_ERROR); - } - return (COMPLETE); -} - -static void -uha_timeout(arg1) - void *arg1; -{ - struct mscp *mscp = (struct mscp *)arg1; - struct uha_data *uha; - int s = splbio(); - - uha = (struct uha_data *)mscp->xs->sc_link->adapter_softc; - printf("uha%d:%d:%d (%s%d) timed out ", uha->unit - ,mscp->xs->sc_link->target - ,mscp->xs->sc_link->lun - ,mscp->xs->sc_link->device->name - ,mscp->xs->sc_link->dev_unit); - -#ifdef UHADEBUG - uha_print_active_mscp(uha); -#endif /*UHADEBUG */ - - if ((uha_abort(uha, mscp) != 1) || (mscp->flags = MSCP_ABORTED)) { - printf("AGAIN"); - mscp->xs->retries = 0; /* I MEAN IT ! */ - uha_done(uha, mscp); - } else { /* abort the operation that has timed out */ - printf("\n"); - mscp->xs->timeout_ch = timeout(uha_timeout, (caddr_t)mscp, - 2 * hz); - mscp->flags = MSCP_ABORTED; - } - splx(s); -} - -#ifdef UHADEBUG -void -uha_print_mscp(mscp) - struct mscp *mscp; -{ - printf("mscp:%x op:%x cmdlen:%d senlen:%d\n" - ,mscp - ,mscp->opcode - ,mscp->cdblen - ,mscp->senselen); - printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x flags:%x\n" - ,mscp->sgth - ,mscp->sg_num - ,mscp->datalen - ,mscp->ha_status - ,mscp->targ_status - ,mscp->flags); - show_scsi_cmd(mscp->xs); -} - -void -uha_print_active_mscp(struct uha_data *uha) -{ - struct mscp *mscp; - int i = 0; - - while (i < MSCP_HASH_SIZE) { - mscp = uha->mscphash[i]; - while (mscp) { - if (mscp->flags != MSCP_FREE) { - uha_print_mscp(mscp); - } - mscp = mscp->nexthash; - } - i++; - } -} -#endif /*UHADEBUG */ -#endif /*KERNEL */ diff --git a/sys/i386/isa/wd7000.c b/sys/i386/isa/wd7000.c deleted file mode 100644 index 3da995f..0000000 --- a/sys/i386/isa/wd7000.c +++ /dev/null @@ -1,727 +0,0 @@ -/* - * Copyright (c) 1994 Ludd, University of Lule}, Sweden. - * All rights reserved. - * - * Written by Olof Johansson (offe@ludd.luth.se) 1995. - * Based on code written by Theo de Raadt (deraadt@fsa.ca). - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed at Ludd, University of Lule}. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - - /* All bugs are subject to removal without further notice */ - -/* - * offe 01/07/95 - * - * This version of the driver _still_ doesn't implement scatter/gather for the - * WD7000-FASST2. This is due to the fact that my controller doesn't seem to - * support it. That, and the lack of documentation makes it impossible for - * me to implement it. - * What I've done instead is allocated a local buffer, contiguous buffer big - * enough to handle the requests. I haven't seen any read/write bigger than 64k, - * so I allocate a buffer of 64+16k. The data that needs to be DMA'd to/from - * the controller is copied to/from that buffer before/after the command is - * sent to the card. - */ - -#include "wds.h" -#if NWDS > 0 - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/buf.h> - -#include <scsi/scsiconf.h> - -#include <machine/clock.h> - -#include <vm/vm.h> -#include <vm/pmap.h> - -#include <i386/isa/isa_device.h> - -static struct scsi_device wds_dev = -{ - NULL, - NULL, - NULL, - NULL, - "wds", - 0, - { 0, 0 } -}; - -/* - XXX THIS SHOULD BE FIXED! - I haven't got the KERNBASE-version to work, but on my system the kernel - is at virtual address 0xFxxxxxxx, responding to physical address - 0x0xxxxxxx. -#define PHYSTOKV(x) ((x) + KERNBASE) -*/ -#define PHYSTOKV(x) ((x) | 0xf0000000) -#define KVTOPHYS(x) vtophys(x) -/* 0x10000 (64k) should be enough. But just to be sure... */ -#define BUFSIZ 0x12000 - - -/* WD7000 registers */ -#define WDS_STAT 0 /* read */ -#define WDS_IRQSTAT 1 /* read */ - -#define WDS_CMD 0 /* write */ -#define WDS_IRQACK 1 /* write */ -#define WDS_HCR 2 /* write */ - -/* WDS_STAT (read) defs */ -#define WDS_IRQ 0x80 -#define WDS_RDY 0x40 -#define WDS_REJ 0x20 -#define WDS_INIT 0x10 - -/* WDS_IRQSTAT (read) defs */ -#define WDSI_MASK 0xc0 -#define WDSI_ERR 0x00 -#define WDSI_MFREE 0x80 -#define WDSI_MSVC 0xc0 - -/* WDS_CMD (write) defs */ -#define WDSC_NOOP 0x00 -#define WDSC_INIT 0x01 -#define WDSC_DISUNSOL 0x02 -#define WDSC_ENAUNSOL 0x03 -#define WDSC_IRQMFREE 0x04 -#define WDSC_SCSIRESETSOFT 0x05 -#define WDSC_SCSIRESETHARD 0x06 -#define WDSC_MSTART(m) (0x80 + (m)) -#define WDSC_MMSTART(m) (0xc0 + (m)) - -/* WDS_HCR (write) defs */ -#define WDSH_IRQEN 0x08 -#define WDSH_DRQEN 0x04 -#define WDSH_SCSIRESET 0x02 -#define WDSH_ASCRESET 0x01 - -struct wds_cmd { - u_char cmd; - u_char targ; - u_char scb[12]; /*u_char scb[12];*/ - u_char stat; - u_char venderr; - u_char len[3]; - u_char data[3]; - u_char next[3]; - u_char write; - u_char xx[6]; -}; - -struct wds_req { - struct wds_cmd cmd; - struct wds_cmd sense; - struct scsi_xfer *sxp; - int busy, polled; - int done, ret, ombn; -}; - -#define WDSX_SCSICMD 0x00 -#define WDSX_OPEN_RCVBUF 0x80 -#define WDSX_RCV_CMD 0x81 -#define WDSX_RCV_DATA 0x82 -#define WDSX_RCV_DATASTAT 0x83 -#define WDSX_SND_DATA 0x84 -#define WDSX_SND_DATASTAT 0x85 -#define WDSX_SND_CMDSTAT 0x86 -#define WDSX_READINIT 0x88 -#define WDSX_READSCSIID 0x89 -#define WDSX_SETUNSOLIRQMASK 0x8a -#define WDSX_GETUNSOLIRQMASK 0x8b -#define WDSX_GETFIRMREV 0x8c -#define WDSX_EXECDIAG 0x8d -#define WDSX_SETEXECPARM 0x8e -#define WDSX_GETEXECPARM 0x8f - -struct wds_mb { - u_char stat; - u_char addr[3]; -}; -/* ICMB status value */ -#define ICMB_OK 0x01 -#define ICMB_OKERR 0x02 -#define ICMB_ETIME 0x04 -#define ICMB_ERESET 0x05 -#define ICMB_ETARCMD 0x06 -#define ICMB_ERESEL 0x80 -#define ICMB_ESEL 0x81 -#define ICMB_EABORT 0x82 -#define ICMB_ESRESET 0x83 -#define ICMB_EHRESET 0x84 - -struct wds_setup { - u_char cmd; - u_char scsi_id; - u_char buson_t; - u_char busoff_t; - u_char xx; - u_char mbaddr[3]; - u_char nomb; - u_char nimb; -}; - -#define WDS_NOMB 8 -#define WDS_NIMB 8 -#define MAXSIMUL 8 - -static int wdsunit=0; - -static u_char wds_data[NWDS][BUFSIZ]; -static u_char wds_data_in_use[NWDS]; - -static struct wds { - int addr; - struct wds_req wdsr[MAXSIMUL]; - struct wds_mb ombs[WDS_NOMB], imbs[WDS_NIMB]; - struct scsi_link sc_link; -} wds[NWDS]; - -static int wdsprobe(struct isa_device *); -static void wds_minphys(struct buf *); -static struct wds_req *wdsr_alloc(int); -static int32_t wds_scsi_cmd(struct scsi_xfer *); -static u_int32_t wds_adapter_info(int); -static ointhand2_t wdsintr; -static int wds_done(int, struct wds_cmd *, u_char); -static int wdsattach(struct isa_device *); -static int wds_init(struct isa_device *); -static int wds_cmd(int, u_char *, int); -static void wds_wait(int, int, int); - -struct isa_driver wdsdriver = -{ - wdsprobe, - wdsattach, - "wds" -}; - -static struct scsi_adapter wds_switch = -{ - wds_scsi_cmd, - wds_minphys, - 0, - 0, - wds_adapter_info, - "wds", - {0,0} -}; - -int -wdsprobe(struct isa_device *dev) -{ - if(wdsunit > NWDS) - return 0; - - dev->id_unit = wdsunit; /* XXX WRONG! */ - wds[wdsunit].addr = dev->id_iobase; - - if(wds_init(dev) != 0) - return 0; - wdsunit++; - return 8; -} - -void -wds_minphys(struct buf *bp) -{ - if(bp->b_bcount > BUFSIZ) - bp->b_bcount = BUFSIZ; -} - -struct wds_req * -wdsr_alloc(int unit) -{ - struct wds_req *r; - int x; - int i; - - r = NULL; - x = splbio(); - for(i=0; i<MAXSIMUL; i++) - if(!wds[unit].wdsr[i].busy) - { - r = &wds[unit].wdsr[i]; - r->busy = 1; - break; - } - if(!r) - { - splx(x); - return NULL; - } - - r->ombn = -1; - for(i=0; i<WDS_NOMB; i++) - if(!wds[unit].ombs[i].stat) - { - wds[unit].ombs[i].stat = 1; - r->ombn = i; - break; - } - if(r->ombn == -1 ) - { - r->busy = 0; - splx(x); - return NULL; - } - splx(x); - return r; -} - -int32_t -wds_scsi_cmd(struct scsi_xfer *sxp) -{ - struct wds_req *r; - int unit = sxp->sc_link->adapter_unit; - int base; - u_char c; - int i; - - base = wds[unit].addr; - - if( sxp->flags & SCSI_RESET) - { - printf("reset!\n"); - return COMPLETE; - } - - r = wdsr_alloc(unit); - if(r==NULL) - { - printf("no request slot available!\n"); - sxp->error = XS_DRIVER_STUFFUP; - return TRY_AGAIN_LATER; - } - r->done = 0; - r->sxp = sxp; - - if(sxp->flags & SCSI_DATA_UIO) - { - printf("UIO!\n"); - sxp->error = XS_DRIVER_STUFFUP; - return TRY_AGAIN_LATER; - } - - scsi_uto3b(KVTOPHYS(&r->cmd),wds[unit].ombs[r->ombn].addr); - - bzero(&r->cmd, sizeof r->cmd); - r->cmd.cmd = WDSX_SCSICMD; - r->cmd.targ = (sxp->sc_link->target << 5) | sxp->sc_link->lun; - bcopy(sxp->cmd, &r->cmd.scb, sxp->cmdlen<12 ? sxp->cmdlen : 12); - scsi_uto3b(sxp->datalen, r->cmd.len); - - if(wds_data_in_use[unit]) - { - sxp->error = XS_DRIVER_STUFFUP; - return TRY_AGAIN_LATER; - } - else - wds_data_in_use[unit] = 1; - - if(sxp->datalen && !(sxp->flags&SCSI_DATA_IN)) - bcopy(sxp->data, wds_data[unit], sxp->datalen); - - scsi_uto3b(sxp->datalen ? KVTOPHYS(wds_data[unit]) : 0, r->cmd.data); - - r->cmd.write = (sxp->flags&SCSI_DATA_IN)? 0x80 : 0x00; - - scsi_uto3b(KVTOPHYS(&r->sense),r->cmd.next); - - bzero(&r->sense, sizeof r->sense); - r->sense.cmd = r->cmd.cmd; - r->sense.targ = r->cmd.targ; - r->sense.scb[0] = REQUEST_SENSE; - scsi_uto3b(KVTOPHYS(&sxp->sense),r->sense.data); - scsi_uto3b(sizeof(sxp->sense), r->sense.len); - r->sense.write = 0x80; - - if(sxp->flags & SCSI_NOMASK) - { - outb(base+WDS_HCR, WDSH_DRQEN); - r->polled = 1; - } else - { - outb(base+WDS_HCR, WDSH_IRQEN|WDSH_DRQEN); - r->polled = 0; - } - - c = WDSC_MSTART(r->ombn); - - if( wds_cmd(base, &c, sizeof c) != 0) - { - printf("wds%d: unable to start outgoing mbox\n", unit); - r->busy = 0; - wds[unit].ombs[r->ombn].stat = 0; - - return TRY_AGAIN_LATER; - } - - if(sxp->flags & SCSI_NOMASK) - { - repoll: - - i = 0; - while(!(inb(base+WDS_STAT) & WDS_IRQ)) - { - - DELAY(20000); - if(++i == 20) - { - outb(base + WDS_IRQACK, 0); - /*r->busy = 0;*/ - sxp->error = XS_TIMEOUT; - return HAD_ERROR; - } - } - wdsintr(unit); - if(r->done) - { - r->sxp->flags |= ITSDONE; - r->busy = 0; - return r->ret; - } - goto repoll; - } - - return SUCCESSFULLY_QUEUED; -} - -u_int32_t -wds_adapter_info(int unit) -{ - return 1; -} - -static void -wdsintr(int unit) -{ - struct wds_cmd *pc, *vc; - struct wds_mb *in; - u_char stat; - u_char c; - - if(!inb(wds[unit].addr+WDS_STAT) & WDS_IRQ) - { - outb(wds[unit].addr + WDS_IRQACK, 0); - return; - } - - c = inb(wds[unit].addr + WDS_IRQSTAT); - if( (c&WDSI_MASK) == WDSI_MSVC) - { - c = c & ~WDSI_MASK; - in = &wds[unit].imbs[c]; - - pc = (struct wds_cmd *)scsi_3btou(in->addr); - vc = (struct wds_cmd *)PHYSTOKV((intptr_t)(void *)pc); - stat = in->stat; - - wds_done(unit, vc, stat); - in->stat = 0; - - outb(wds[unit].addr + WDS_IRQACK, 0); - } -} - -int -wds_done(int unit, struct wds_cmd *c, u_char stat) -{ - struct wds_req *r; - int i; - - r = (struct wds_req *)NULL; - - for(i=0; i<MAXSIMUL; i++) - if( c == &wds[unit].wdsr[i].cmd && !wds[unit].wdsr[i].done) - { - r = &wds[unit].wdsr[i]; - break; - } - if(r == (struct wds_req *)NULL) - { - /* failed to find request! */ - return 1; - } - - r->done = 1; - wds[unit].ombs[r->ombn].stat = 0; - r->ret = HAD_ERROR; - switch(stat) - { - case ICMB_OK: - r->ret = COMPLETE; - if(r->sxp) - r->sxp->resid = 0; - break; - case ICMB_OKERR: - if(!(r->sxp->flags & SCSI_ERR_OK) && c->stat) - { - r->sxp->sense.error_code = c->venderr; - r->sxp->error=XS_SENSE; - } - else - r->sxp->error=XS_NOERROR; - r->ret = COMPLETE; - break; - case ICMB_ETIME: - r->sxp->error = XS_TIMEOUT; - r->ret = HAD_ERROR; - break; - case ICMB_ERESET: - case ICMB_ETARCMD: - case ICMB_ERESEL: - case ICMB_ESEL: - case ICMB_EABORT: - case ICMB_ESRESET: - case ICMB_EHRESET: - r->sxp->error = XS_DRIVER_STUFFUP; - r->ret = HAD_ERROR; - break; - } - - if(r->sxp) - if(r->sxp->datalen && (r->sxp->flags&SCSI_DATA_IN)) - bcopy(wds_data[unit],r->sxp->data,r->sxp->datalen); - - wds_data_in_use[unit] = 0; - - if(!r->polled) - { - r->sxp->flags |= ITSDONE; - scsi_done(r->sxp); - } - - r->busy = 0; - - return 0; -} - -static int -wds_getvers(int unit) -{ - struct wds_req *r; - int base; - u_char c; - int i; - - base = wds[unit].addr; - - r = wdsr_alloc(unit); - if(!r) - { - printf("wds%d: no request slot available!\n", unit); - return -1; - } - - r->done = 0; - r->sxp = NULL; - - scsi_uto3b(KVTOPHYS(&r->cmd), wds[unit].ombs[r->ombn].addr); - - bzero(&r->cmd, sizeof r->cmd); - r->cmd.cmd = WDSX_GETFIRMREV; - - outb(base+WDS_HCR, WDSH_DRQEN); - r->polled = 1; - - c = WDSC_MSTART(r->ombn); - if(wds_cmd(base, (u_char *)&c, sizeof c)) - { - printf("wds%d: version request failed\n", unit); - r->busy = 0; - wds[unit].ombs[r->ombn].stat = 0; - return -1; - } - - while(1) - { - i = 0; - while( (inb(base+WDS_STAT) & WDS_IRQ) == 0) - { - DELAY(9000); - if(++i == 20) - return -1; - } - wdsintr(unit); - if(r->done) - { - printf("wds%d: firmware version %d.%02d\n", unit, - r->cmd.targ, r->cmd.scb[0]); - r->busy = 0; - return 0; - } - } -} - -int -wdsattach(struct isa_device *dev) -{ - int masunit; - static u_long versprobe=0; /* max 32 controllers */ - int unit = dev->id_unit; - struct scsibus_data *scbus; - - dev->id_ointr = wdsintr; - masunit = dev->id_unit; - - if( !(versprobe & (1<<masunit))) - { - versprobe |= (1<<masunit); - if(wds_getvers(masunit)==-1) - printf("wds%d: getvers failed\n", masunit); - } - - printf("wds%d: using %d bytes for dma buffer\n",unit,BUFSIZ); - - wds[unit].sc_link.adapter_unit = unit; - wds[unit].sc_link.adapter_targ = 7; - wds[unit].sc_link.adapter = &wds_switch; - wds[unit].sc_link.device = &wds_dev; - wds[unit].sc_link.flags = SDEV_BOUNCE; - - /* - * Prepare the scsibus_data area for the upperlevel - * scsi code. - */ - scbus = scsi_alloc_bus(); - if(!scbus) - return 0; - scbus->adapter_link = &wds[unit].sc_link; - - scsi_attachdevs(scbus); - - return 1; -} - -int -wds_init(struct isa_device *dev) -{ - struct wds_setup init; - int base; - int unit, i; - struct wds_cmd wc; - - unit = dev->id_unit; - base = wds[unit].addr; - - /* - * Sending a command causes the CMDRDY bit to clear. - */ - - outb(base+WDS_CMD, WDSC_NOOP); - if( inb(base+WDS_STAT) & WDS_RDY) - return 1; - - /* - * the controller exists. reset and init. - */ - outb(base+WDS_HCR, WDSH_ASCRESET|WDSH_SCSIRESET); - DELAY(30); - outb(base+WDS_HCR, 0); - - outb(base+WDS_HCR, WDSH_DRQEN); - - isa_dmacascade(dev->id_drq); - - if( (inb(base+WDS_STAT) & (WDS_RDY)) != WDS_RDY) - { - for(i=0; i<10; i++) - { - if( (inb(base+WDS_STAT) & (WDS_RDY)) == WDS_RDY) - break; - DELAY(40000); - } - if( (inb(base+WDS_STAT) & (WDS_RDY)) != WDS_RDY) /* probe timeout */ - return 1; - } - - bzero(&init, sizeof init); - init.cmd = WDSC_INIT; - init.scsi_id = 7; - init.buson_t = 24; - init.busoff_t = 48; - scsi_uto3b(KVTOPHYS(wds[unit].ombs), init.mbaddr); - init.xx = 0; - init.nomb = WDS_NOMB; - init.nimb = WDS_NIMB; - - wds_wait(base+WDS_STAT, WDS_RDY, WDS_RDY); - if( wds_cmd(base, (u_char *)&init, sizeof init) != 0) - { - printf("wds%d: wds_cmd failed\n", unit); - return 1; - } - - wds_wait(base+WDS_STAT, WDS_INIT, WDS_INIT); - - wds_wait(base+WDS_STAT, WDS_RDY, WDS_RDY); - - bzero(&wc,sizeof wc); - wc.cmd = WDSC_DISUNSOL; - if( wds_cmd(base, (char *)&wc, sizeof wc) != 0) - { - printf("wds%d: wds_cmd failed\n", unit); - return 1; - } - - return 0; -} - -int -wds_cmd(int base, u_char *p, int l) -{ - int s=splbio(); - - while(l--) - { - do - { - outb(base+WDS_CMD,*p); - wds_wait(base+WDS_STAT,WDS_RDY,WDS_RDY); - } while (inb(base+WDS_STAT) & WDS_REJ); - p++; - } - - wds_wait(base+WDS_STAT,WDS_RDY,WDS_RDY); - - splx(s); - - return 0; -} - -void -wds_wait(int reg, int mask, int val) -{ - while((inb(reg) & mask) != val); -} - -#endif |