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