*BSD News Article 5691


Return to BSD News archive

Newsgroups: comp.unix.bsd
Path: sserve!manuel!munnari.oz.au!spool.mu.edu!agate!tfs.com!tfs.com!julian
From: julian@tfs.com (Julian Elischer)
Subject: New driver for SCSI system, Bustek 74x EISA 32bit.
Message-ID: <1992Sep27.230441.14468@tfs.com>
Organization: TRW Financial Systems
Date: Sun, 27 Sep 1992 23:04:41 GMT
Lines: 1769

Here is the second supported driver for the new SCSI system
This is for the bustek 742a (and I believe  747a ) EISA SCSI
adapter.

It supports the 742 in Extended mode, allowing direct access to
more than 16MB of ram.
I have run this driver with upto 64MB ram under MACH and with
16MB under 386BSD. (It's all by 386bsd machine has)
however if it fails with more than 16MB it's probably
not the driver 8-)

It uses full 32bit addresses, and can handle the board when it is set
up to use EISA dma rather than ISA emulation DMA.
(select 'none' under the EISA config program when setting the DMA)

The patch files here will patch from unmodified source
so to integrate this driver in with the rest of the sources
it may be simpler to do the patches by hand (3 lines) than to
back out the original patches and apply these.
config BTTEST will build a sample system using this board

the aha1542 driver and the bt742a driver cannot co-exist at this
time due to lack of forthought.. they share some symbol names
This will change. If you must run one bt and one aha, then
you must be running with less than 16MB ram, so just use the 
aha1542 driver for both, you will not lose performance.

julian

# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	i386/isa/isa.h.patch
#	i386/conf/files.i386.patch
#	i386/conf/BTTEST
#	i386/isa/bt742a.c
#
echo x - i386/isa/isa.h.patch
sed 's/^X//' >i386/isa/isa.h.patch << 'END-of-i386/isa/isa.h.patch'
X*** /usr/src/syschanges/sys.originals/i386/isa/isa.h	Tue May 12 21:51:02 1992
X--- /usr/src/sys.386bsd/i386/isa/isa.h	Sat Sep 26 18:35:12 1992
X***************
X*** 86,93 ****
X  					/* 0x280 - 0x2F7 Open */
X  
X  #define IO_COM2		0x2f8		/* COM2 i/o address */
X  
X! 					/* 0x300 - 0x36F Open */
X  
X  #define IO_FD2		0x370		/* secondary base i/o address */
X  #define IO_LPT1		0x378		/* Parallel Port #1 */
X--- 86,98 ----
X  					/* 0x280 - 0x2F7 Open */
X  
X  #define IO_COM2		0x2f8		/* COM2 i/o address */
X+ 					/* 0x300 - 0x32F Open */
X  
X! #define	IO_BT0		0x330		/* bustek 742a default addr. */
X! #define	IO_AHA0		0x330		/* adaptec 1542 default addr. */
X! #define	IO_BT1		0x334		/* bustek 742a default addr. */
X! #define	IO_AHA1		0x334		/* adaptec 1542 default addr. */
X! 					/* 0x338 - 0x36F Open */
X  
X  #define IO_FD2		0x370		/* secondary base i/o address */
X  #define IO_LPT1		0x378		/* Parallel Port #1 */
END-of-i386/isa/isa.h.patch
echo x - i386/conf/files.i386.patch
sed 's/^X//' >i386/conf/files.i386.patch << 'END-of-i386/conf/files.i386.patch'
X*** /usr/src/syschanges/sys.originals/i386/conf/files.i386	Mon May 25 12:25:04 1992
X--- /usr/src/sys.386bsd/i386/conf/files.i386	Sat Sep 26 17:31:03 1992
X***************
X*** 25,27 ****
X--- 25,34 ----
X  i386/i386/db_disasm.c	optional ddb
X  i386/i386/db_interface.c	optional ddb
X  i386/i386/db_trace.c	optional ddb
X+ i386/isa/aha1542.c	optional aha
X+ i386/isa/bt742a.c	optional bt
X+ scsi/st.c		optional st
X+ scsi/sd.c		optional sd
X+ scsi/cd.c		optional cd
X+ scsi/ch.c		optional ch
X+ scsi/scsiconf.c		optional scbus
END-of-i386/conf/files.i386.patch
echo x - i386/conf/BTTEST
sed 's/^X//' >i386/conf/BTTEST << 'END-of-i386/conf/BTTEST'
X#
X# SCSITEST -- Generic ISA machine -- scsi test kernel
X#
Xmachine		"i386"
Xcpu		"i386"
Xident		SCSITEST
Xtimezone	8 dst
Xmaxusers	10
Xoptions		INET,ISOFS,NFS
Xoptions		"COMPAT_43"
Xoptions		"TCP_COMPAT_42"
X
Xconfig		"386bsd"	root on sd0 swap on sd0
X
Xcontroller	isa0
Xcontroller	wd0	at isa? port "IO_WD1" bio irq 14 vector wdintr
Xdisk		wd0	at wd0 drive 0
Xdisk		wd0	at wd0 drive 1
X
Xcontroller	fd0	at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr
Xdisk		fd0	at fd0 drive 0
Xdisk		fd1	at fd0 drive 1
X
Xdevice		pc0	at isa? port "IO_KBD" tty irq 1 vector pcrint
Xdevice		npx0	at isa? port "IO_NPX" irq 13 vector npxintr
Xdevice		com1	at isa? port "IO_COM1" tty irq 4 vector comintr
Xdevice		com2	at isa? port "IO_COM2" tty irq 3 vector comintr
X
X#controller	aha0	at isa? port "IO_AHA0" bio irq 11 drq 5 vector ahaintr
X#controller	aha1	at isa? port "IO_AHA1" bio irq 12 drq 7 vector ahaintr
Xcontroller	bt0	at isa? port "IO_BT0" bio irq 12  vector btintr
Xcontroller	scbus0
X
Xdevice		sd0
Xdevice		sd1
Xdevice		sd2
Xdevice		sd3
X
Xdevice		st0
Xdevice		st1
Xdevice		st2
Xdevice		st3
X
Xdevice		cd0
Xdevice		cd1
X
Xdevice		we0 at isa? port 0x280 net irq 2 iomem 0xd0000 iosiz 8192 vector weintr
X
X
Xpseudo-device	loop
Xpseudo-device	ether
Xpseudo-device	sl	2
Xpseudo-device	log
Xpseudo-device	ddb
Xpseudo-device	pty	4
X
Xpseudo-device	swappager
Xpseudo-device	vnodepager
Xpseudo-device	devpager
END-of-i386/conf/BTTEST
echo x - i386/isa/bt742a.c
sed 's/^X//' >i386/isa/bt742a.c << 'END-of-i386/isa/bt742a.c'
X/* 
X * Mach Operating System
X * Copyright (c) 1990 Carnegie-Mellon University
X * Copyright (c) 1989 Carnegie-Mellon University
X * All rights reserved.  The CMU software License Agreement specifies
X * the terms and conditions for use and redistribution.
X */
X/*
X * HISTORY
X * $Log: bt742a.c,v $
X * Revision 1.7  1992/08/24  22:40:16  jason
X * BIG_DMA ifdef for 512 dma segments instead of 128 segments
X *
X * Revision 1.6  1992/08/24  21:01:58  jason
X * many changes and bugfixes for osf1
X *
X * Revision 1.5  1992/07/31  01:22:03  julian
X * support improved scsi.h layout
X *
X * Revision 1.4  1992/07/25  03:11:26  julian
X * check each request fro sane flags.
X *
X * Revision 1.3  1992/07/24  00:52:45  julian
X * improved timeout handling.
X * added support for two arguments to the sd_done (or equiv) call so that
X * they can pre-queue several arguments.
X * slightly clean up error handling
X *
X * Revision 1.2  1992/07/17  22:03:54  julian
X * upgraded the timeout code.
X * added support for UIO-based i/o (as used for pmem operations)
X *
X * Revision 1.1  1992/05/27  00:51:12  balsup
X * machkern/cor merge
X *
X * Revision 1.5  1992/05/20  16:26:58  julian
X * add and correct timeout code.
X * add some state to the ccbs.
X * add some timeout debugging code.
X *
X * Revision 1.4  1992/05/15  22:34:34  julian
X * expect and use a timeout value on each request. also use the
X * calibrated delay variables set up by the system, for setup delays.
X *
X * Revision 1.3  1992/03/19  05:24:34  julian
X * fixed the 'overwriting it's own port number' bug we fixed in the aha
X * about 4 months ago.
X *
X * Revision 1.2  1992/03/18  05:05:21  julian
X * remove all non EISA code.. only runs on eisa.
X *
X * Revision 1.1  1991/11/27  06:21:08  julian
X * Initial revision
X *
X * Revision 1.4  1991/11/17  07:02:46  julian
X * fix stupid type.
X *
X * Revision 1.3  1991/11/17  02:35:42  julian
X * allow for EISA machines capable of doing 100nS operations.
X *
X * Revision 1.2  1991/10/18  21:11:14  balsup
X * machkm merge
X *
X * Revision 1.15  91/06/24  18:15:26  julian
X * add 'reset device' command support
X * 
X * Revision 1.14  91/06/14  14:53:23  julian
X * add debug prints for exact dump of ccb sent to bt.
X * 
X * Revision 1.13  91/06/13  15:27:11  julian
X * can't use sctter/gather if no data xfered.
X * 
X * Revision 1.12  91/06/07  17:51:51  julian
X * use the (new) bit B_NPAGES in buf to tell physstrat to map multiple
X * pages for use with the physaddr
X * 
X * Revision 1.11  91/06/05  17:06:51  julian
X * moved device probing to scsiconf.
X * improved error returns
X * 
X * Revision 1.10  91/05/24  16:36:47  julian
X * added extra debug output on scsi errors.
X * 
X * Revision 1.9  91/05/20  20:35:19  julian
X * 1/ self configure from jumpers.
X * 2/adjust bus speed to suit motherboard.
X * 3/bt_cmd() waits for hacc and clears it
X * + more
X * 
X * Revision 1.8  91/05/19  00:01:52  julian
X * chase down bus speed bug to allow operation on 'free' 486 motherboard.
X * 
X * Revision 1.7  91/05/16  13:49:55  julian
X * improved error handling
X * 
X * Revision 1.6  91/05/15  14:21:30  julian
X * first version that works with 2 disks
X * 
X * Revision 1.5  91/05/13  12:34:24  julian
X * broken down to be a generic scsi driver (see sd,c)
X * 
X * Revision 1.4  91/05/03  17:02:31  julian
X * rewrite as base driver/device driver. (see sd.c (real soon))
X * 
X * Revision 1.3  91/05/01  17:46:00  julian
X * temporarily make minphys return 1 page or less.
X * 
X * Revision 1.2  91/04/22  13:31:13  julian
X * back port interrupt setup to m kernel from v kernel
X * 
X * Revision 1.1  91/04/22  13:19:37  julian
X * Initial revision
X * 
X * Revision 2.1.1.1  91/03/28  08:45:03  rvb
X * 	Acquired from osf.
X * 	[91/03/25            rvb]
X * 
X */
X
X/*
X * bt742a BT-1542A SCSI driver
X * Copyright (c) 1990 OSF Research Institute 
X */
X
X/*
X * Copyright 1990 by Open Software Foundation,
X * Grenoble, FRANCE
X *
X * 		All Rights Reserved
X * 
X *   Permission to use, copy, modify, and distribute this software and
X * its documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appears in all copies and
X * that both the copyright notice and this permission notice appear in
X * supporting documentation, and that the name of OSF or Open Software
X * Foundation not be used in advertising or publicity pertaining to
X * distribution of the software without specific, written prior
X * permission.
X * 
X *   OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
X * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
X * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
X * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
X * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
X */
X
X#include <sys/types.h>
X#include <bt.h>
X
X#include <sys/param.h>
X#include <sys/systm.h>
X#include <sys/errno.h>
X#include <sys/ioctl.h>
X#include <sys/buf.h>
X#include <sys/proc.h>
X#include <sys/user.h>
X
X#ifdef	MACH	/* EITHER CMU OR OSF */
X#include <i386/ipl.h>
X#include <i386at/scsi.h>
X#include <i386at/scsiconf.h>
X
X#ifdef	OSF	/* OSF ONLY */
X#include <sys/table.h>
X#include <i386/handler.h>
X#include <i386/dispatcher.h>
X#include <i386/AT386/atbus.h>
X
X#else	OSF	/* CMU ONLY */
X#include <i386at/atbus.h>
X#include <i386/pio.h>
X#endif	OSF
X#endif	MACH	/* end of MACH specific */
X
X#ifdef	__386BSD__	/* 386BSD specific */
X#define isa_dev isa_device
X#define dev_unit id_unit
X#define dev_addr id_iobase
X
X#include <i386/isa/isa_device.h>
X#include <scsi/scsi_all.h>
X#include <scsi/scsiconf.h>
X#endif	__386BSD__
X
X
X#ifdef	__386BSD__
X#include "ddb.h"
X#if	NDDB > 0
Xint	Debugger();
X#else	NDDB
X#define	Debugger() panic("should call debugger here (adaptec.c)")
X#endif	NDDB
X#endif	__386BSD__
X
X#ifdef	MACH
Xint	Debugger();
X#endif	MACH
X
Xextern int delaycount;	/* from clock setup code */
Xtypedef unsigned long int physaddr;
X
X/*
X * I/O Port Interface
X */
X
X#define	BT_BASE		bt_base[unit]
X#define	BT_CTRL_STAT_PORT	(BT_BASE + 0x0)	/* control & status */
X#define	BT_CMD_DATA_PORT	(BT_BASE + 0x1)	/* cmds and datas */
X#define	BT_INTR_PORT		(BT_BASE + 0x2)	/* Intr. stat */
X
X/*
X * BT_CTRL_STAT bits (write)
X */
X
X#define BT_HRST		0x80	/* Hardware reset */
X#define BT_SRST		0x40	/* Software reset */
X#define BT_IRST		0x20	/* Interrupt reset */
X#define BT_SCRST	0x10	/* SCSI bus reset */
X
X/*
X * BT_CTRL_STAT bits (read)
X */
X
X#define BT_STST		0x80	/* Self test in Progress */
X#define BT_DIAGF	0x40	/* Diagnostic Failure */
X#define BT_INIT		0x20	/* Mbx Init required */
X#define BT_IDLE		0x10	/* Host Adapter Idle */
X#define BT_CDF		0x08	/* cmd/data out port full */
X#define BT_DF		0x04	/* Data in port full */
X#define BT_INVDCMD	0x01	/* Invalid command */
X
X/*
X * BT_CMD_DATA bits (write)
X */
X
X#define	BT_NOP			0x00	/* No operation */
X#define BT_MBX_INIT		0x01	/* Mbx initialization */
X#define BT_START_SCSI		0x02	/* start scsi command */
X#define BT_START_BIOS		0x03	/* start bios command */
X#define BT_INQUIRE		0x04	/* Adapter Inquiry */
X#define BT_MBO_INTR_EN		0x05	/* Enable MBO available interrupt */
X#define BT_SEL_TIMEOUT_SET	0x06	/* set selection time-out */
X#define BT_BUS_ON_TIME_SET	0x07	/* set bus-on time */
X#define BT_BUS_OFF_TIME_SET	0x08	/* set bus-off time */
X#define BT_SPEED_SET		0x09	/* set transfer speed */
X#define BT_DEV_GET		0x0a	/* return installed devices */
X#define BT_CONF_GET		0x0b	/* return configuration data */
X#define BT_TARGET_EN		0x0c	/* enable target mode */
X#define BT_SETUP_GET		0x0d	/* return setup data */
X#define BT_WRITE_CH2		0x1a	/* write channel 2 buffer */
X#define BT_READ_CH2		0x1b	/* read channel 2 buffer */
X#define BT_WRITE_FIFO		0x1c	/* write fifo buffer */
X#define BT_READ_FIFO		0x1d	/* read fifo buffer */
X#define BT_ECHO			0x1e	/* Echo command data */
X#define BT_MBX_INIT_EXTENDED	0x81	/* Mbx initialization */
X#define BT_INQUIRE_EXTENDED	0x8D	/* Adapter Setup Inquiry */
X
Xstruct bt_cmd_buf {
X	 u_char byte[16];	
X};
X
X/*
X * BT_INTR_PORT bits (read)
X */
X
X#define BT_ANY_INTR		0x80	/* Any interrupt */
X#define BT_SCRD		0x08	/* SCSI reset detected */
X#define BT_HACC		0x04	/* Command complete */
X#define BT_MBOA		0x02	/* MBX out empty */
X#define BT_MBIF		0x01	/* MBX in full */
X
X/*
X * Mail box defs 
X */
X
X#define BT_MBX_SIZE		16	/* mail box size */
X
Xstruct bt_mbx
X{
X	struct bt_mbx_out {
X		physaddr	ccb_addr;
X		unsigned char	dummy[3];
X		unsigned char	cmd;
X	} mbo [BT_MBX_SIZE];
X	struct bt_mbx_in{
X		physaddr	ccb_addr;
X		unsigned char	btstat;
X		unsigned char 	sdstat;
X		unsigned char	dummy;
X		unsigned char	stat;
X	} mbi[BT_MBX_SIZE];
X};
X
X/*
X * mbo.cmd values
X */
X
X#define BT_MBO_FREE	0x0	/* MBO entry is free */
X#define BT_MBO_START	0x1	/* MBO activate entry */
X#define BT_MBO_ABORT	0x2	/* MBO abort entry */
X
X#define BT_MBI_FREE	0x0	/* MBI entry is free */
X#define BT_MBI_OK	0x1	/* completed without error */
X#define BT_MBI_ABORT	0x2	/* aborted ccb */
X#define BT_MBI_UNKNOWN	0x3	/* Tried to abort invalid CCB */
X#define BT_MBI_ERROR	0x4	/* Completed with error */
X
Xextern struct bt_mbx bt_mbx[];
X
X#if	defined(BIG_DMA)
X/* #define	BT_NSEG	8192	/* Number of scatter gather segments - to much vm */
X#define	BT_NSEG	512
X#else
X#define	BT_NSEG	33
X#endif	/* BIG_DMA */
Xstruct	bt_scat_gath
X	{
X		unsigned long	seg_len;
X		physaddr	seg_addr;
X	};
X
Xstruct bt_ccb {
X	unsigned char		opcode;
X	unsigned char		:3,data_in:1,data_out:1,:3;
X	unsigned char		scsi_cmd_length;
X	unsigned char		req_sense_length;
X	/*------------------------------------longword boundary */
X	unsigned long		data_length;
X	/*------------------------------------longword boundary */
X	physaddr		data_addr;
X	/*------------------------------------longword boundary */
X	unsigned char		dummy[2];
X	unsigned char		host_stat;
X	unsigned char		target_stat;
X	/*------------------------------------longword boundary */
X	unsigned char		target;
X	unsigned char		lun;
X	unsigned char 		scsi_cmd[12];	/* 12 bytes (bytes only)*/
X	unsigned char		dummy2[1];
X	unsigned char		link_id;
X	/*------------------------------------4 longword boundary */
X	physaddr		link_addr;
X	/*------------------------------------longword boundary */
X	physaddr		sense_ptr;
X	/*------------------------------------longword boundary */
X	struct	scsi_sense_data	scsi_sense;
X	/*------------------------------------longword boundary */
X	struct	bt_scat_gath	scat_gath[BT_NSEG];
X	/*------------------------------------longword boundary */
X	struct	bt_ccb		*next;
X	/*------------------------------------longword boundary */
X	struct	scsi_xfer	*xfer;		/* the scsi_xfer for this cmd */
X	/*------------------------------------longword boundary */
X	struct	bt_mbx_out	*mbx;		/* pointer to mail box */
X	/*------------------------------------longword boundary */
X	long	int	delta;	/* difference from previous*/
X	struct bt_ccb	*later,*sooner;
X	int		flags;
X#define	CCB_FREE	0
X#define CCB_ACTIVE	1
X#define	CCB_ABORTED	2
X};
X
Xstruct	bt_ccb *soonest = (struct bt_ccb *)0;
Xstruct	bt_ccb *latest = (struct bt_ccb *)0;
Xlong int	furtherest = 0;	/* longest time in the timeout queue */
X/*
X * opcode fields
X */
X
X#define BT_INITIATOR_CCB	0x00	/* SCSI Initiator CCB */
X#define BT_TARGET_CCB		0x01	/* SCSI Target CCB */
X#define BT_INIT_SCAT_GATH_CCB	0x02	/* SCSI Initiator with scattter gather*/
X#define BT_RESET_CCB		0x81	/* SCSI Bus reset */
X
X
X/*
X * bt_ccb.host_stat values
X */
X
X#define BT_OK		0x00	/* cmd ok */
X#define BT_LINK_OK	0x0a	/* Link cmd ok */
X#define BT_LINK_IT	0x0b	/* Link cmd ok + int */
X#define BT_SEL_TIMEOUT	0x11	/* Selection time out */
X#define BT_OVER_UNDER	0x12	/* Data over/under run */
X#define BT_BUS_FREE	0x13	/* Bus dropped at unexpected time */
X#define BT_INV_BUS	0x14	/* Invalid bus phase/sequence */
X#define BT_BAD_MBO	0x15	/* Incorrect MBO cmd */
X#define BT_BAD_CCB	0x16	/* Incorrect ccb opcode */
X#define BT_BAD_LINK	0x17	/* Not same values of LUN for links */
X#define BT_INV_TARGET	0x18	/* Invalid target direction */
X#define BT_CCB_DUP	0x19	/* Duplicate CCB received */
X#define BT_INV_CCB	0x1a	/* Invalid CCB or segment list */
X#define BT_ABORTED	42	/* pseudo value from driver */
X
X
X
Xstruct bt_setup
X{
X	u_char	sync_neg:1;
X	u_char	parity:1;
X	u_char	:6;
X	u_char	speed;
X	u_char	bus_on;
X	u_char	bus_off;
X	u_char	num_mbx;
X	u_char	mbx[4];
X	struct
X	{
X		u_char	offset:4;
X		u_char	period:3;
X		u_char	valid:1;
X	}sync[8];
X	u_char	disc_sts;
X};
X
Xstruct	bt_config
X{
X	u_char	chan;
X	u_char	intr;
X	u_char	scsi_dev:3;
X	u_char	:5;
X};
X
X#define INT9	0x01
X#define INT10	0x02
X#define INT11	0x04
X#define INT12	0x08
X#define INT14	0x20
X#define INT15	0x40
X
X#define EISADMA	0x00
X#define CHAN0	0x01
X#define CHAN5	0x20
X#define CHAN6	0x40
X#define CHAN7	0x80
X
X
X
X
X#ifdef        MACH
Xextern physaddr	kvtophys();
X#define PHYSTOKV(x)   phystokv(x)
X#define KVTOPHYS(x)   kvtophys(x)
X#endif MACH
X
X#ifdef        __386BSD__
X#define PHYSTOKV(x)   (x | 0xFE000000)
X#define KVTOPHYS(x)   vtophys(x)
X#endif        __386BSD__
X
X
X
X#define PAGESIZ 	4096
X#define INVALIDATE_CACHE {asm volatile( ".byte	0x0F ;.byte 0x08" ); }
X
X
Xu_char			bt_scratch_buf[256];
X#ifdef	MACH
Xcaddr_t			bt_base[NBT];		/* base port for each board */
X#else	MACH
Xshort			bt_base[NBT];		/* base port for each board */
X#endif	MACH
Xstruct	bt_mbx		bt_mbx[NBT];
Xstruct	bt_ccb		*bt_ccb_free[NBT];
Xstruct	bt_ccb		bt_ccb[NBT][BT_MBX_SIZE];
Xstruct	scsi_xfer	bt_scsi_xfer[NBT];
Xstruct	isa_dev		*btinfo[NBT];
Xstruct	bt_ccb		*bt_get_ccb();
Xint			bt_int[NBT];
Xint			bt_dma[NBT];
Xint			bt_scsi_dev[NBT];
Xint			bt_initialized[NBT];
X#if defined(OSF)
Xint			bt_attached[NBT];
X#endif /* defined(OSF) */
X
X/***********debug values *************/
X#define	BT_SHOWCCBS 0x01
X#define	BT_SHOWINTS 0x02
X#define	BT_SHOWCMDS 0x04
X#define	BT_SHOWMISC 0x08
Xint	bt_debug = 0;
X
X
Xint btprobe(), btattach();
Xint btintr();
X
X#ifdef	MACH
Xstruct	isa_driver	btdriver = { btprobe, 0, btattach, "bt", 0, 0, 0};
Xint (*btintrs[])() = {btintr, 0};
X#endif	MACH
X
X#ifdef	__386BSD__
Xstruct	isa_driver	btdriver = { btprobe, btattach, "bt"};
X#endif	__386BSD__
X
Xstatic	int	btunit = 0;
X
X#define bt_abortmbx(mbx) \
X	(mbx)->cmd = BT_MBO_ABORT; \
X	outb(BT_CMD_DATA_PORT, BT_START_SCSI);
X#define bt_startmbx(mbx) \
X	(mbx)->cmd = BT_MBO_START; \
X	outb(BT_CMD_DATA_PORT, BT_START_SCSI);
X
X
X
Xint	bt_scsi_cmd();
Xint	bt_timeout();
Xvoid	btminphys();
X
Xstruct	scsi_switch	bt_switch =
X{
X	bt_scsi_cmd,
X	btminphys
X};	
X#define BT_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */
X#define BT_RESET_TIMEOUT 1000000
X#define BT_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */
X
X
X/***********************************************************************\
X* bt_cmd(unit,icnt, ocnt,wait, retval, opcode, args)			*
X* Activate Adapter command						*
X*	icnt:	number of args (outbound bytes written after opcode)	*
X*	ocnt:	number of expected returned bytes			*
X*	wait:   number of seconds to wait for response			*
X*	retval:	buffer where to place returned bytes			*
X*	opcode:	opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ...		*
X*	args:	parameters						*
X*									*
X* Performs an adapter command through the ports. Not to be confused	*
X*	with a scsi command, which is read in via the dma		*
X* One of the adapter commands tells it to read in a scsi command	*
X\***********************************************************************/
Xbt_cmd(unit,icnt, ocnt, wait,retval, opcode, args)
X
Xu_char *retval;
Xunsigned opcode;
Xu_char args;
X{
X	unsigned *ic = &opcode;
X	u_char oc;
X	register i;
X	int	sts;
X
X	/*******************************************************\
X	* multiply the wait argument by a big constant		*
X	* zero defaults to 1					*
X	\*******************************************************/
X	if(!wait) 
X		wait = BT_CMD_TIMEOUT_FUDGE * delaycount; 
X	else
X		wait *= BT_CMD_TIMEOUT_FUDGE * delaycount; 
X	/*******************************************************\
X	* Wait for the adapter to go idle, unless it's one of	*
X	* the commands which don't need this			*
X	\*******************************************************/
X	if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI)
X	{
X		i = BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/
X		while (--i)
X		{
X			sts = inb(BT_CTRL_STAT_PORT);
X			if (sts & BT_IDLE)
X			{
X				break;
X			}
X		}
X		if (!i)
X		{
X			printf("bt_cmd: bt742a host not idle(0x%x)\n",sts);
X			return(ENXIO);
X		}
X	}
X	/*******************************************************\
X	* Now that it is idle, if we expect output, preflush the*
X	* queue feeding to us.					*
X	\*******************************************************/
X	if (ocnt)
X	{
X		while((inb(BT_CTRL_STAT_PORT)) & BT_DF)
X			inb(BT_CMD_DATA_PORT);
X	}
X			
X	/*******************************************************\
X	* Output the command and the number of arguments given	*
X	* for each byte, first check the port is empty.		*
X	\*******************************************************/
X	icnt++;		/* include the command */
X	while (icnt--)
X	{
X		sts = inb(BT_CTRL_STAT_PORT);
X		for (i=0; i< wait; i++)
X		{
X			sts = inb(BT_CTRL_STAT_PORT);
X			if (!(sts & BT_CDF))
X				break;
X		}
X		if (i >=  wait)
X		{
X			printf("bt_cmd: bt742a cmd/data port full\n");
X			outb(BT_CTRL_STAT_PORT, BT_SRST); 
X			return(ENXIO);
X		}
X		outb(BT_CMD_DATA_PORT, (u_char)(*ic++));
X	}
X	/*******************************************************\
X	* If we expect input, loop that many times, each time,	*
X	* looking for the data register to have valid data	*
X	\*******************************************************/
X	while (ocnt--)
X	{
X		sts = inb(BT_CTRL_STAT_PORT);
X		for (i=0; i< wait; i++)
X		{
X			sts = inb(BT_CTRL_STAT_PORT);
X			if (sts  & BT_DF)
X				break;
X		}
X		if (i >=  wait)
X		{
X			printf("bt_cmd: bt742a cmd/data port empty %d\n",ocnt);
X			return(ENXIO);
X		}
X		oc = inb(BT_CMD_DATA_PORT);
X		if (retval)
X			*retval++ = oc;
X	}
X	/*******************************************************\
X	* Wait for the board to report a finised instruction	*
X	\*******************************************************/
X	i=BT_CMD_TIMEOUT_FUDGE * delaycount;	/* 1 sec? */
X	while (--i)
X	{
X		sts = inb(BT_INTR_PORT);
X		if (sts & BT_HACC)
X		{
X			break;
X		}
X	}
X	if (!i)
X	{
X		printf("bt_cmd: bt742a host not finished(0x%x)\n",sts);
X		return(ENXIO);
X	}
X	outb(BT_CTRL_STAT_PORT, BT_IRST);
X	return(0);
X}
X
X/*******************************************************\
X* Check if the device can be found at the port given	*
X* and if so, set it up ready for further work		*
X* as an argument, takes the isa_dev structure from	*
X* autoconf.c						*
X\*******************************************************/
X
Xbtprobe(dev)
Xstruct isa_dev *dev;
X{
X	/***********************************************\
X	* find unit and check we have that many defined	*
X	\***********************************************/
X	int     unit = btunit;
X#if defined(OSF)
X	static ihandler_t bt_handler[NBT];
X	static ihandler_id_t *bt_handler_id[NBT];
X	register ihandler_t *chp = &bt_handler[unit];;
X#endif /* defined(OSF) */
X
X	dev->dev_unit = unit;
X	bt_base[unit] = dev->dev_addr;
X	if(unit >= NBT) 
X	{
X		printf("bt: unit number (%d) too high\n",unit);
X		return(0);
X	}
X	/***********************************************\
X	* Try initialise a unit at this location	*
X	* sets up dma and bus speed, loads bt_int[unit]*
X	\***********************************************/
X	if (bt_init(unit) != 0)
X	{
X		return(0);
X	}
X
X	/***********************************************\
X	* If it's there, put in it's interrupt vectors	*
X	\***********************************************/
X#ifdef	MACH
X#if defined(OSF)				/* OSF */
X	chp->ih_level = dev->dev_pic;
X	chp->ih_handler = dev->dev_intr[0];
X	chp->ih_resolver = i386_resolver;
X	chp->ih_rdev = dev;
X	chp->ih_stats.intr_type = INTR_DEVICE;
X	chp->ih_stats.intr_cnt = 0;
X	chp->ih_hparam[0].intparam = unit;
X	if ((bt_handler_id[unit] = handler_add(chp)) != NULL)
X		handler_enable(bt_handler_id[unit]);
X	else
X		panic("Unable to add bt interrupt handler");
X#else 						/* CMU */
X	dev->dev_pic = bt_int[unit];
X	take_dev_irq(dev);
X#endif /* !defined(OSF) */
X	printf("port=%x spl=%d\n", dev->dev_addr, dev->dev_spl);
X#endif	MACH
X#ifdef  __386BSD__				/* 386BSD */
X        dev->id_irq = (1 << bt_int[unit]);
X        dev->id_drq = bt_dma[unit];
X	printf("\n  **");
X#endif  __386BSD__
X
X	btunit++;
X	return(1);
X}
X
X/***********************************************\
X* Attach all the sub-devices we can find	*
X\***********************************************/
Xbtattach(dev)
Xstruct	isa_dev	*dev;
X{
X	int	unit = dev->dev_unit;
X
X
X#ifdef  __386BSD__
X	printf(" probing for scsi devices**\n");
X#endif  __386BSD__
X
X	/***********************************************\
X	* ask the adapter what subunits are present	*
X	\***********************************************/
X	scsi_attachdevs( unit, bt_scsi_dev[unit], &bt_switch);
X#if defined(OSF)
X	bt_attached[unit]=1;
X#endif /* defined(OSF) */
X	if(!unit) /* only one for all boards */
X	{
X		bt_timeout(0);
X	}
X#ifdef  __386BSD__
X	printf("bt%d",unit);
X#endif  __386BSD__
X	return;
X}
X
X/***********************************************\
X* Catch an interrupt from the adaptor		*
X\***********************************************/
Xbtintr(unit)
X{
X	struct bt_ccb *ccb;
X	unsigned char stat;
X	register i;
X
X	if(scsi_debug & PRINTROUTINES)
X		printf("btintr ");
X	/***********************************************\
X	* First acknowlege the interrupt, Then if it's	*
X	* not telling about a completed operation	*
X	* just return. 					*
X	\***********************************************/
X	stat = inb(BT_INTR_PORT);
X	outb(BT_CTRL_STAT_PORT, BT_IRST);
X	if(scsi_debug & TRACEINTERRUPTS)
X		printf("int = 0x%x ",stat);
X	if (! (stat & BT_MBIF))
X		return 1;
X	if(scsi_debug & TRACEINTERRUPTS)
X		printf("mbxi ");
X#if defined(OSF)
X	if (!bt_attached[unit])
X	{
X		return(1);
X	}
X#endif /* defined(OSF) */
X	/***********************************************\
X	* If it IS then process the competed operation	*
X	\***********************************************/
X	for (i = 0; i < BT_MBX_SIZE; i++)
X	{
X		if (bt_mbx[unit].mbi[i].stat != BT_MBI_FREE)
X		{
X			ccb = (struct bt_ccb *)PHYSTOKV(
X					(bt_mbx[unit].mbi[i].ccb_addr));
X			if((bt_debug & BT_SHOWCCBS) && ccb)
X				printf("<int ccb(%x)>",ccb);
X			if((stat =  bt_mbx[unit].mbi[i].stat) != BT_MBI_OK)
X			{
X				switch(stat)
X				{
X				case	BT_MBI_ABORT:
X					if(bt_debug & BT_SHOWMISC)
X						printf("abort ");
X					ccb->host_stat = BT_ABORTED;
X					break;
X
X				case	BT_MBI_UNKNOWN:
X					ccb = (struct bt_ccb *)0;
X					if(bt_debug & BT_SHOWMISC)
X						printf("unknown ccb for abort");
X					break;
X
X				case	BT_MBI_ERROR:
X					break;
X
X				default:
X					panic("Impossible mbxi status");
X
X				}
X				if((bt_debug & BT_SHOWCMDS ) && ccb)
X				{
X					u_char	*cp;
X					cp = ccb->scsi_cmd;
X					printf("op=%x %x %x %x %x %x\n", 
X						cp[0], cp[1], cp[2],
X						cp[3], cp[4], cp[5]);
X					printf("stat %x for mbi[%d]\n"
X						, bt_mbx[unit].mbi[i].stat, i);
X					printf("addr = 0x%x\n", ccb);
X				}
X			}
X			if(ccb)
X			{
X				remove_timeout(ccb);
X				bt_done(unit,ccb);
X			}
X			bt_mbx[unit].mbi[i].stat = BT_MBI_FREE;
X		}
X	}
X	return(1);
X}
X
X/***********************************************\
X* A ccb (and hence a mbx-out is put onto the 	*
X* free list.					*
X\***********************************************/
Xbt_free_ccb(unit,ccb, flags)
Xstruct bt_ccb *ccb;
X{
X	unsigned int opri;
X	
X	if(scsi_debug & PRINTROUTINES)
X		printf("ccb%d(0x%x)> ",unit,flags);
X	if (!(flags & SCSI_NOMASK)) 
X	  	opri = splbio();
X
X	ccb->next = bt_ccb_free[unit];
X	bt_ccb_free[unit] = ccb;
X	ccb->flags = CCB_FREE;
X	/***********************************************\
X	* If there were none, wake abybody waiting for	*
X	* one to come free, starting with queued entries*
X	\***********************************************/
X	if (!ccb->next) {
X		wakeup(&bt_ccb_free[unit]);
X	}
X	if (!(flags & SCSI_NOMASK)) 
X		splx(opri);
X}
X
X/***********************************************\
X* Get a free ccb (and hence mbox-out entry)	*
X\***********************************************/
Xstruct bt_ccb *
Xbt_get_ccb(unit,flags)
X{
X	unsigned opri;
X	struct bt_ccb *rc;
X
X	if(scsi_debug & PRINTROUTINES)
X		printf("<ccb%d(0x%x) ",unit,flags);
X	if (!(flags & SCSI_NOMASK)) 
X	  	opri = splbio();
X	/***********************************************\
X	* If we can and have to, sleep waiting for one	*
X	* to come free					*
X	\***********************************************/
X	while ((!(rc = bt_ccb_free[unit])) && (!(flags & SCSI_NOSLEEP)))
X	{
X		sleep(&bt_ccb_free[unit], PRIBIO);
X	}
X	if (rc) 
X	{
X		bt_ccb_free[unit] = rc->next;
X		rc->flags = CCB_ACTIVE;
X	}
X	if (!(flags & SCSI_NOMASK)) 
X		splx(opri);
X	return(rc);
X}
X		
X
X/***********************************************\
X* We have a ccb which has been processed by the	*
X* adaptor, now we look to see how the operation	*
X* went. Wake up the owner if waiting		*
X\***********************************************/
Xbt_done(unit,ccb)
Xstruct bt_ccb *ccb;
X{
X	struct	scsi_sense_data *s1,*s2;
X	struct	scsi_xfer *xs = ccb->xfer;
X
X	if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS))
X		printf("bt_done ");
X	/***********************************************\
X	* Otherwise, put the results of the operation	*
X	* into the xfer and call whoever started it	*
X	\***********************************************/
X	if (  	(	ccb->host_stat != BT_OK 
X			|| ccb->target_stat != SCSI_OK)
X	      && (!(xs->flags & SCSI_ERR_OK)))
X	{
X
X		s1 = &(ccb->scsi_sense);
X		s2 = &(xs->sense);
X
X		if(ccb->host_stat)
X		{
X			switch(ccb->host_stat)
X			{
X			case	BT_ABORTED:	/* No response */
X			case	BT_SEL_TIMEOUT:	/* No response */
X				if (bt_debug & BT_SHOWMISC)
X				{
X					printf("timeout reported back\n");
X				}
X				xs->error = XS_TIMEOUT;
X				break;
X			default:	/* Other scsi protocol messes */
X				xs->error = XS_DRIVER_STUFFUP;
X				if (bt_debug & BT_SHOWMISC)
X				{
X					printf("unexpected host_stat: %x\n",
X						ccb->host_stat);
X				}
X			}
X
X		}
X		else
X		{
X			switch(ccb->target_stat)
X			{
X			case 0x02:
X				/* structure copy!!!!!*/
X				*s2=*s1;
X				xs->error = XS_SENSE;
X				break;
X			case 0x08:
X				xs->error = XS_BUSY;
X				break;
X			default:
X				if (bt_debug & BT_SHOWMISC)
X				{
X					printf("unexpected target_stat: %x\n",
X						ccb->target_stat);
X				}
X				xs->error = XS_DRIVER_STUFFUP;
X			}
X		}
X	}
X	else		/* All went correctly  OR errors expected */
X	{
X		xs->resid = 0;
X	}
X	xs->flags |= ITSDONE;
X	bt_free_ccb(unit,ccb, xs->flags);
X	if(xs->when_done)
X		(*(xs->when_done))(xs->done_arg,xs->done_arg2);
X}
X
X/***********************************************\
X* Start the board, ready for normal operation	*
X\***********************************************/
Xbt_init(unit)
Xint	unit;
X{
X	unsigned char ad[4];
X	volatile int i,sts;
X	struct	bt_config conf;
X
X	/***********************************************\
X	* reset board, If it doesn't respond, assume 	*
X	* that it's not there.. good for the probe	*
X	\***********************************************/
X
X	outb(BT_CTRL_STAT_PORT, BT_HRST|BT_SRST);
X
X	for (i=0; i < BT_RESET_TIMEOUT; i++)
X	{
X		sts = inb(BT_CTRL_STAT_PORT) ;
X		if ( sts == (BT_IDLE | BT_INIT))
X			break;
X	}
X	if (i >= BT_RESET_TIMEOUT)
X	{
X		if (bt_debug & BT_SHOWMISC)
X			printf("bt_init: No answer from bt742a board\n");
X		return(ENXIO);
X	}
X
X	/***********************************************\
X	* Assume we have a board at this stage		*
X	* setup dma channel from jumpers and save int	*
X	* level						*
X	\***********************************************/
X#ifdef	__386BSD__
X	printf("bt%d reading board settings, ",unit);
X#define	PRNT(x)
X#else	__386BSD__
X	printf("bt%d:",unit);
X#define	PRNT(x) printf(x)
X#endif	__386BSD__
X
X	bt_cmd(unit,0, sizeof(conf), 0 ,&conf, BT_CONF_GET);
X	switch(conf.chan)
X	{
X	case	EISADMA:
X		bt_dma[unit] = -1;
X		PRNT("eisa dma ");
X		break;
X	case	CHAN0:
X		outb(0x0b, 0x0c);
X		outb(0x0a, 0x00);
X		bt_dma[unit] = 0;
X		PRNT("dma=0 ");
X		break;
X	case	CHAN5:
X		outb(0xd6, 0xc1);
X		outb(0xd4, 0x01);
X		bt_dma[unit] = 5;
X		PRNT("dma=5 ");
X		break;
X	case	CHAN6:
X		outb(0xd6, 0xc2);
X		outb(0xd4, 0x02);
X		bt_dma[unit] = 6;
X		PRNT("dma=6 ");
X		break;
X	case	CHAN7:
X		outb(0xd6, 0xc3);
X		outb(0xd4, 0x03);
X		bt_dma[unit] = 7;
X		PRNT("dma=7 ");
X		break;
X	default:
X		printf("illegal dma setting %x\n",conf.chan);
X		return(EIO);
X	}
X	switch(conf.intr)
X	{
X	case	INT9:
X		bt_int[unit] = 9;
X		PRNT("int=9 ");
X		break;
X	case	INT10:
X		bt_int[unit] = 10;
X		PRNT("int=10 ");
X		break;
X	case	INT11:
X		bt_int[unit] = 11;
X		PRNT("int=11 ");
X		break;
X	case	INT12:
X		bt_int[unit] = 12;
X		PRNT("int=12 ");
X		break;
X	case	INT14:
X		bt_int[unit] = 14;
X		PRNT("int=14 ");
X		break;
X	case	INT15:
X		bt_int[unit] = 15;
X		PRNT("int=15 ");
X		break;
X	default:
X		printf("illegal int setting\n");
X		return(EIO);
X	}
X	/* who are we on the scsi bus */
X	bt_scsi_dev[unit] = conf.scsi_dev;
X	/***********************************************\
X	* Initialize mail box 				*
X	\***********************************************/
X
X	*((physaddr *)ad) = KVTOPHYS(&bt_mbx[unit]);
X	bt_cmd(unit,5, 0, 0, 0, BT_MBX_INIT_EXTENDED
X		, BT_MBX_SIZE
X		, ad[0]
X		, ad[1]
X		, ad[2] 
X		, ad[3]);
X
X	/***********************************************\
X	* link the ccb's with the mbox-out entries and	*
X	* into a free-list				*
X	\***********************************************/
X	for (i=0; i < BT_MBX_SIZE; i++) {
X		bt_ccb[unit][i].next = bt_ccb_free[unit];
X		bt_ccb_free[unit] = &bt_ccb[unit][i];
X		bt_ccb_free[unit]->flags = CCB_FREE;
X		bt_ccb_free[unit]->mbx = &bt_mbx[unit].mbo[i];
X		bt_mbx[unit].mbo[i].ccb_addr = KVTOPHYS(bt_ccb_free[unit]) ;
X	}
X
X	/***********************************************\
X	* Note that we are going and return (to probe)	*
X	\***********************************************/
X	bt_initialized[unit]++;
X	return( 0 );
X}
X
X
X#ifndef	min
X#define min(x,y) (x < y ? x : y)
X#endif	min
X
X
Xvoid btminphys(bp)
Xstruct	buf *bp;
X{
X#ifdef	MACH
X#if	!defined(OSF)
X	bp->b_flags |= B_NPAGES;		/* can support scat/gather */
X#endif	/* defined(OSF) */
X#endif	MACH
X	if(bp->b_bcount > ((BT_NSEG-1) * PAGESIZ))
X	{
X		bp->b_bcount = ((BT_NSEG-1) * PAGESIZ);
X	}
X}
X	
X/***********************************************\
X* start a scsi operation given the command and	*
X* the data address. Also needs the unit, target	*
X* and lu					*
X\***********************************************/
Xint	bt_scsi_cmd(xs)
Xstruct scsi_xfer *xs;
X{
X	struct	scsi_sense_data *s1,*s2;
X	struct bt_ccb *ccb;
X	struct bt_scat_gath *sg;
X	int	seg;	/* scatter gather seg being worked on */
X	int i	= 0;
X	int rc	=  0;
X	int	thiskv;
X	physaddr	thisphys,nextphys;
X	int	unit =xs->adapter;
X	int	bytes_this_seg,bytes_this_page,datalen,flags;
X	struct	iovec	*iovp;
X
X	if(scsi_debug & PRINTROUTINES)
X		printf("bt_scsi_cmd ");
X	/***********************************************\
X	* get a ccb (mbox-out) to use. If the transfer	*
X	* is from a buf (possibly from interrupt time)	*
X	* then we can't allow it to sleep		*
X	\***********************************************/
X	flags = xs->flags;
X	if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */
X	if(flags & ITSDONE)
X	{
X		printf("Already done?");
X		xs->flags &= ~ITSDONE;
X	}
X	if(!(flags & INUSE))
X	{
X		printf("Not in use?");
X		xs->flags |= INUSE;
X	}
X	if (!(ccb = bt_get_ccb(unit,flags)))
X	{
X		xs->error = XS_DRIVER_STUFFUP;
X		return(TRY_AGAIN_LATER);
X	}
X
X	if(bt_debug & BT_SHOWCCBS)
X				printf("<start ccb(%x)>",ccb);
X	if (ccb->mbx->cmd != BT_MBO_FREE)
X		printf("MBO not free\n");
X
X	/***********************************************\
X	* Put all the arguments for the xfer in the ccb	*
X	\***********************************************/
X	ccb->xfer		=	xs;
X	if(flags & SCSI_RESET)
X	{
X		ccb->opcode	=	BT_RESET_CCB;
X	}
X	else
X	{
X		/* can't use S/G if zero length */
X		ccb->opcode	=	(xs->datalen?
X						BT_INIT_SCAT_GATH_CCB
X						:BT_INITIATOR_CCB);
X	}
X	ccb->target		=	xs->targ;;
X	ccb->data_out		=	0;
X	ccb->data_in		=	0;
X	ccb->lun		=	xs->lu;
X	ccb->scsi_cmd_length	=	xs->cmdlen;
X	ccb->sense_ptr		=	KVTOPHYS(&(ccb->scsi_sense));
X	ccb->req_sense_length	=	sizeof(ccb->scsi_sense);
X
X	if((xs->datalen) && (!(flags & SCSI_RESET)))
X	{ /* can use S/G only if not zero length */
X		ccb->data_addr = KVTOPHYS(ccb->scat_gath);
X		sg		=	ccb->scat_gath ;
X		seg 		=	0;
X		if(flags & SCSI_DATA_UIO)
X		{
X			iovp = ((struct uio *)xs->data)->uio_iov;
X			datalen = ((struct uio *)xs->data)->uio_iovcnt;
X			xs->datalen = 0;
X			while ((datalen) && (seg < BT_NSEG))
X			{
X				sg->seg_addr = (physaddr)iovp->iov_base;
X				xs->datalen += sg->seg_len = iovp->iov_len;	
X				if(scsi_debug & SHOWSCATGATH)
X					printf("(0x%x@0x%x)"
X							,iovp->iov_len
X							,iovp->iov_base);
X				sg++;
X				iovp++;
X				seg++;
X				datalen--;
X			}
X		}
X		else
X		{
X			/***********************************************\
X			* Set up the scatter gather block		*
X			\***********************************************/
X		
X			if(scsi_debug & SHOWSCATGATH)
X				printf("%d @0x%x:- ",xs->datalen,xs->data);
X			datalen		=	xs->datalen;
X			thiskv		=	(int)xs->data;
X			thisphys	=	KVTOPHYS(thiskv);
X		
X			while ((datalen) && (seg < BT_NSEG))
X			{
X				bytes_this_seg	= 0;
X	
X				/* put in the base address */
X				sg->seg_addr = thisphys;
X		
X				if(scsi_debug & SHOWSCATGATH)
X					printf("0x%x",thisphys);
X	
X				/* do it at least once */
X				nextphys = thisphys;	
X				while ((datalen) && (thisphys == nextphys))
X				/*********************************************\
X				* This page is contiguous (physically) with   *
X				* the the last, just extend the length	      *
X				\*********************************************/
X				{
X					/* how far to the end of the page */
X					nextphys= (thisphys & (~(PAGESIZ - 1)))
X								+ PAGESIZ;
X					bytes_this_page	= nextphys - thisphys;
X					/**** or the data ****/
X					bytes_this_page	= min(bytes_this_page
X								,datalen);
X					bytes_this_seg	+= bytes_this_page;
X					datalen		-= bytes_this_page;
X		
X					/* get more ready for the next page */
X					thiskv	= (thiskv & (~(PAGESIZ - 1)))
X								+ PAGESIZ;
X					if(datalen)
X						thisphys = KVTOPHYS(thiskv);
X				}
X				/********************************************\
X				* next page isn't contiguous, finish the seg *
X				\********************************************/
X				if(scsi_debug & SHOWSCATGATH)
X					printf("(0x%x)",bytes_this_seg);
X				sg->seg_len = bytes_this_seg;	
X				sg++;
X				seg++;
X			}
X		} /*end of iov/kv decision */
X		ccb->data_length = seg * sizeof(struct bt_scat_gath);
X		if(scsi_debug & SHOWSCATGATH)
X			printf("\n");
X		if (datalen)
X		{ /* there's still data, must have run out of segs! */
X			printf("bt_scsi_cmd%d: more than %d DMA segs\n",
X				unit,BT_NSEG);
X			xs->error = XS_DRIVER_STUFFUP;
X			bt_free_ccb(unit,ccb,flags);
X			return(HAD_ERROR);
X		}
X
X	}
X	else
X	{	/* No data xfer, use non S/G values */
X		ccb->data_addr = (physaddr)0;
X		ccb->data_length = 0;
X	}
X	ccb->link_id = 0;
X	ccb->link_addr = (physaddr)0;
X	/***********************************************\
X	* Put the scsi command in the ccb and start it	*
X	\***********************************************/
X	if(!(flags & SCSI_RESET))
X	{
X		bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length);
X	}
X	if(scsi_debug & SHOWCOMMANDS)
X	{
X		u_char	*b = ccb->scsi_cmd;
X		if(!(flags & SCSI_RESET))
X		{
X			int i = 0;
X			printf("bt%d:%d:%d-"
X				,unit
X				,ccb->target
X				,ccb->lun);
X			while(i < ccb->scsi_cmd_length )
X			{
X				if(i) printf(",");
X				printf("%x",b[i++]);
X			}
X			printf("-\n");
X		}
X		else
X		{
X			printf("bt%d:%d:%d-RESET- " 
X				,unit 
X				,ccb->target
X				,ccb->lun
X			);
X		}
X	}
X	bt_startmbx(ccb->mbx);
X	/***********************************************\
X	* Usually return SUCCESSFULLY QUEUED		*
X	\***********************************************/
X	if(scsi_debug & TRACEINTERRUPTS)
X		printf("cmd_sent ");
X	if (!(flags & SCSI_NOMASK))
X	{
X		add_timeout(ccb,xs->timeout);
X		return(SUCCESSFULLY_QUEUED);
X	}
X	/***********************************************\
X	* If we can't use interrupts, poll on completion*
X	\***********************************************/
X	{
X		int done = 0;
X		int count = delaycount * xs->timeout / BT_SCSI_TIMEOUT_FUDGE;
X		if(scsi_debug & TRACEINTERRUPTS)
X			printf("wait ");
X		while((!done) && count)
X		{
X			i=0;
X			while ( (!done) && i<BT_MBX_SIZE)
X			{
X				if ((bt_mbx[unit].mbi[i].stat != BT_MBI_FREE )
X				   && (PHYSTOKV(bt_mbx[unit].mbi[i].ccb_addr)
X					== (int)ccb))
X				{
X					bt_mbx[unit].mbi[i].stat = BT_MBI_FREE;
X					bt_done(unit,ccb);
X					done++;
X				}
X				i++;
X			}
X			count--;
X		}
X		if (!count)
X		{
X			if (!(xs->flags & SCSI_SILENT))
X				printf("cmd fail\n");
X			bt_abortmbx(ccb->mbx);
X			count = delaycount * 2000 / BT_SCSI_TIMEOUT_FUDGE;
X			while((!done) && count)
X			{
X				i=0;
X				while ( (!done) && i<BT_MBX_SIZE)
X				{
X					if ((bt_mbx[unit].mbi[i].stat != BT_MBI_FREE )
X				   	&& (PHYSTOKV((bt_mbx[unit].mbi[i].ccb_addr)
X						== (int)ccb)))
X					{
X						bt_mbx[unit].mbi[i].stat = BT_MBI_FREE;
X						bt_done(unit,ccb);
X						done++;
X					}
X					i++;
X				}
X				count--;
X			}
X			if(!count)
X			{
X				printf("abort failed in wait\n");
X				ccb->mbx->cmd = BT_MBO_FREE;
X			}
X			bt_free_ccb(unit,ccb,flags);
X			btintr(unit);
X			xs->error = XS_DRIVER_STUFFUP;
X			return(HAD_ERROR);
X		}
X		btintr(unit);
X		if(xs->error) return(HAD_ERROR);
X		return(COMPLETE);
X	} 
X}
X
X/*
X *              +----------+     +----------+     +----------+
X * soonest----->|    later |---->|     later|---->|     later|--->0
X *              | [Delta]  |     | [Delta]  |     | [Delta]  |
X *       0<-----|sooner    |<----|sooner    |<----|sooner    |<----latest
X *              +----------+     +----------+     +----------+
X *
X *     furtherest = sum(Delta[1..n])
X */
Xadd_timeout(ccb,time)
Xstruct	bt_ccb	*ccb;
Xint	time;
X{
X	int	timeprev;
X	struct bt_ccb *prev;
X	int	s = splbio();
X
X	if(prev = latest) /* yes, an assign */
X	{
X		timeprev = furtherest;
X	}
X	else
X	{
X		timeprev = 0;
X	}
X	while(prev && (timeprev > time)) 
X	{
X		timeprev -= prev->delta;
X		prev = prev->sooner;
X	}
X	if(prev)
X	{
X		ccb->delta = time - timeprev;
X		if( ccb->later = prev->later) /* yes an assign */
X		{
X			ccb->later->sooner = ccb;
X			ccb->later->delta -= ccb->delta;
X		}
X		else
X		{
X			furtherest = time;
X			latest = ccb;
X		}
X		ccb->sooner = prev;
X		prev->later = ccb;
X	}
X	else
X	{
X		if( ccb->later = soonest) /* yes, an assign*/
X		{
X			ccb->later->sooner = ccb;
X			ccb->later->delta -= time;
X		}
X		else
X		{
X			furtherest = time;
X			latest = ccb;
X		}
X		ccb->delta = time;
X		ccb->sooner = (struct bt_ccb *)0;
X		soonest = ccb;
X	}
X	splx(s);
X}
X
Xremove_timeout(ccb)
Xstruct	bt_ccb	*ccb;
X{
X	int	s = splbio();
X
X	if(ccb->sooner)
X	{
X		ccb->sooner->later = ccb->later;
X	}
X	else
X	{
X		soonest = ccb->later;
X	}
X	if(ccb->later)
X	{
X		ccb->later->sooner = ccb->sooner;
X		ccb->later->delta += ccb->delta;
X	}
X	else
X	{
X		latest = ccb->sooner;
X		furtherest -= ccb->delta;
X	}
X	ccb->sooner = ccb->later = (struct bt_ccb *)0;
X	splx(s);
X}
X
X
Xextern int 	hz;
X#define ONETICK 500 /* milliseconds */
X#define SLEEPTIME ((hz * 1000) / ONETICK)
Xbt_timeout(arg)
Xint	arg;
X{
X	struct  bt_ccb  *ccb;
X	int	unit;
X	int	s	= splbio();
X
X	while( ccb = soonest )
X	{
X		if(ccb->delta <= ONETICK)
X		/***********************************************\
X		* It has timed out, we need to do some work	*
X		\***********************************************/
X		{
X			unit = ccb->xfer->adapter;
X			printf("bt%d:%d device timed out\n",unit
X					,ccb->xfer->targ);
X			if(bt_debug & BT_SHOWCCBS)
X				tfs_print_active_ccbs();
X
X			/***************************************\
X			* Unlink it from the queue		*
X			\***************************************/
X			remove_timeout(ccb);
X
X			/***************************************\
X			* If The ccb's mbx is not free, then	*
X			* the board has gone south		*
X			\***************************************/
X			if(ccb->mbx->cmd != BT_MBO_FREE)
X			{
X				printf("bt%d not taking commands!\n"
X							,unit);
X				Debugger();
X			}
X			/***************************************\
X			* If it has been through before, then	*
X			* a previous abort has failed, don't	*
X			* try abort again			*
X			\***************************************/
X			if(ccb->flags == CCB_ABORTED) /* abort timed out */
X			{
X				printf("AGAIN");
X				ccb->xfer->retries = 0; /* I MEAN IT ! */
X				ccb->host_stat = BT_ABORTED;
X				bt_done(unit,ccb);
X			}
X			else	/* abort the operation that has timed out */
X			{
X				printf("\n");
X				bt_abortmbx(ccb->mbx);
X					/* 2 secs for the abort */
X				add_timeout(ccb,2000 + ONETICK);
X				ccb->flags = CCB_ABORTED;
X			}
X		}
X		else
X		/***********************************************\
X		* It has not timed out, adjust and leave	*
X		\***********************************************/
X		{
X			ccb->delta -= ONETICK;
X			furtherest -= ONETICK;
X			break;
X		}
X	}
X	splx(s);
X	timeout(bt_timeout,arg,SLEEPTIME);
X}
X
Xtfs_print_ccb(ccb)
Xstruct	bt_ccb *ccb;
X{
X	printf("ccb:%x op:%x cmdlen:%d senlen:%d\n"
X		,ccb
X		,ccb->opcode
X		,ccb->scsi_cmd_length
X		,ccb->req_sense_length);
X	printf("	datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n"
X		,ccb->data_length
X		,ccb->host_stat
X		,ccb->target_stat
X		,ccb->delta
X		,ccb->flags);
X}
X
Xtfs_print_active_ccbs()
X{
X	struct	bt_ccb *ccb;
X	ccb = soonest;
X
X	while(ccb)
X	{
X		tfs_print_ccb(ccb);
X		ccb = ccb->later;
X	}
X	printf("Furtherest = %d\n",furtherest);
X}
END-of-i386/isa/bt742a.c
exit