Return to BSD News archive
Newsgroups: comp.unix.bsd
Path: sserve!manuel!munnari.oz.au!network.ucsd.edu!sdd.hp.com!uakari.primate.wisc.edu!ames!agate!tfs.com!tfs.com!julian
From: julian@tfs.com (Julian Elischer)
Subject: New scsi system beta3 (part 9 of 10)
Message-ID: <1992Oct3.040245.14080@tfs.com>
Organization: TRW Financial Systems
Date: Sat, 3 Oct 1992 04:02:45 GMT
Lines: 1513
# 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:
#
# scsi/README.AHA1742
# i386/conf/AHBTEST
# i386/isa/aha1742.c
#
echo x - scsi/README.AHA1742
sed 's/^X//' >scsi/README.AHA1742 << 'END-of-scsi/README.AHA1742'
XJust a note:
X
XThe new bootblocks do not work with the 1742 in extended mode:
XThey DO however love it in standard mode.
X
XThe driver automatically switches the board to extended mode when
Xit finds it
Xso leave your 1742 board in standard mode and just boot with the new bootblocks.
X
XWhen unix starts the board will magically be in extended mode
Xand when it is rebooted the bios will take it back to standard mode again.
X
XEventually I will fix the bootblocks, but this works just as well.
X
Xjulian
X
X
END-of-scsi/README.AHA1742
echo x - i386/conf/AHBTEST
sed 's/^X//' >i386/conf/AHBTEST << 'END-of-i386/conf/AHBTEST'
X
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
X#controller bt0 at isa? port "IO_BT0" bio irq 12 vector btintr
Xcontroller ahb0 at isa? bio irq 12 vector ahbintr
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/AHBTEST
echo x - i386/isa/aha1742.c
sed 's/^X//' >i386/isa/aha1742.c << 'END-of-i386/isa/aha1742.c'
X/*
X * Written by Julian Elischer (julian@tfs.com)
X * for TRW Financial Systems for use under the MACH(2.5) operating system.
X *
X * TRW Financial Systems, in accordance with their agreement with Carnegie
X * Mellon University, makes this software available to CMU to distribute
X * or use in any manner that they see fit as long as this message is kept with
X * the software. For this reason TFS also grants any other persons or
X * organisations permission to use or modify this software.
X *
X * TFS supplies this software to be publicly redistributed
X * on the understanding that TFS is not responsible for the correct
X * functioning of this software in any circumstances.
X *
X * commenced: Sun Sep 27 18:14:01 PDT 1992
X */
X
X#include <sys/types.h>
X#include <ahb.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/include/pio.h>
X#include <i386/isa/isa_device.h>
X#include <scsi/scsi_all.h>
X#include <scsi/scsiconf.h>
X#endif __386BSD__
X
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
Xtypedef unsigned long int physaddr;
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
Xextern int delaycount; /* from clock setup code */
X#define NUM_CONCURRENT 16 /* number of concurrent ops per board */
X#define AHB_NSEG 33 /* number of dma segments supported */
X#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */
X/**/
X/***********************************************************************\
X* AHA1740 standard EISA Host ID regs (Offset from slot base) *
X\***********************************************************************/
X#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */
X#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */
X#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */
X#define HID3 0xC83 /* firmware revision */
X
X#define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@')
X#define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@')
X#define CHAR3(B1,B2) ((B2 & 0x1F) | '@')
X
X/* AHA1740 EISA board control registers (Offset from slot base) */
X#define EBCTRL 0xC84
X#define CDEN 0x01
X/***********************************************************************\
X* AHA1740 EISA board mode registers (Offset from slot base) *
X\***********************************************************************/
X#define PORTADDR 0xCC0
X#define PORTADDR_ENHANCED 0x80
X#define BIOSADDR 0xCC1
X#define INTDEF 0xCC2
X#define SCSIDEF 0xCC3
X#define BUSDEF 0xCC4
X#define RESV0 0xCC5
X#define RESV1 0xCC6
X#define RESV2 0xCC7
X/**** bit definitions for INTDEF ****/
X#define INT9 0x00
X#define INT10 0x01
X#define INT11 0x02
X#define INT12 0x03
X#define INT14 0x05
X#define INT15 0x06
X#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */
X#define INTEN 0x10
X/**** bit definitions for SCSIDEF ****/
X#define HSCSIID 0x0F /* our SCSI ID */
X#define RSTPWR 0x10 /* reset scsi bus on power up or reset */
X/**** bit definitions for BUSDEF ****/
X#define B0uS 0x00 /* give up bus immediatly */
X#define B4uS 0x01 /* delay 4uSec. */
X#define B8uS 0x02
X/***********************************************************************\
X* AHA1740 ENHANCED mode mailbox control regs (Offset from slot base) *
X\***********************************************************************/
X#define MBOXOUT0 0xCD0
X#define MBOXOUT1 0xCD1
X#define MBOXOUT2 0xCD2
X#define MBOXOUT3 0xCD3
X
X#define ATTN 0xCD4
X#define G2CNTRL 0xCD5
X#define G2INTST 0xCD6
X#define G2STAT 0xCD7
X
X#define MBOXIN0 0xCD8
X#define MBOXIN1 0xCD9
X#define MBOXIN2 0xCDA
X#define MBOXIN3 0xCDB
X
X#define G2STAT2 0xCDC
X
X/*******************************************************\
X* Bit definitions for the 5 control/status registers *
X\*******************************************************/
X#define ATTN_TARGET 0x0F
X#define ATTN_OPCODE 0xF0
X#define OP_IMMED 0x10
X#define AHB_TARG_RESET 0x80
X#define OP_START_ECB 0x40
X#define OP_ABORT_ECB 0x50
X
X#define G2CNTRL_SET_HOST_READY 0x20
X#define G2CNTRL_CLEAR_EISA_INT 0x40
X#define G2CNTRL_HARD_RESET 0x80
X
X#define G2INTST_TARGET 0x0F
X#define G2INTST_INT_STAT 0xF0
X#define AHB_ECB_OK 0x10
X#define AHB_ECB_RECOVERED 0x50
X#define AHB_HW_ERR 0x70
X#define AHB_IMMED_OK 0xA0
X#define AHB_ECB_ERR 0xC0
X#define AHB_ASN 0xD0 /* for target mode */
X#define AHB_IMMED_ERR 0xE0
X
X#define G2STAT_BUSY 0x01
X#define G2STAT_INT_PEND 0x02
X#define G2STAT_MBOX_EMPTY 0x04
X
X#define G2STAT2_HOST_READY 0x01
X/**/
X
Xstruct ahb_dma_seg
X{
X physaddr addr;
X long len;
X};
X
Xstruct ahb_ecb_status
X{
X u_short status;
X# define ST_DON 0x0001
X# define ST_DU 0x0002
X# define ST_QF 0x0008
X# define ST_SC 0x0010
X# define ST_DO 0x0020
X# define ST_CH 0x0040
X# define ST_INT 0x0080
X# define ST_ASA 0x0100
X# define ST_SNS 0x0200
X# define ST_INI 0x0800
X# define ST_ME 0x1000
X# define ST_ECA 0x4000
X u_char ha_status;
X# define HS_OK 0x00
X# define HS_CMD_ABORTED_HOST 0x04
X# define HS_CMD_ABORTED_ADAPTER 0x05
X# define HS_TIMED_OUT 0x11
X# define HS_HARDWARE_ERR 0x20
X# define HS_SCSI_RESET_ADAPTER 0x22
X# define HS_SCSI_RESET_INCOMING 0x23
X u_char targ_status;
X# define TS_OK 0x00
X# define TS_CHECK_CONDITION 0x02
X# define TS_BUSY 0x08
X u_long resid_count;
X u_long resid_addr;
X u_short addit_status;
X u_char sense_len;
X u_char unused[9];
X u_char cdb[6];
X};
X
X/**/
X
Xstruct ecb
X{
X u_char opcode;
X# define ECB_SCSI_OP 0x01
X u_char :4;
X u_char options:3;
X u_char :1;
X short opt1;
X# define ECB_CNE 0x0001
X# define ECB_DI 0x0080
X# define ECB_SES 0x0400
X# define ECB_S_G 0x1000
X# define ECB_DSB 0x4000
X# define ECB_ARS 0x8000
X short opt2;
X# define ECB_LUN 0x0007
X# define ECB_TAG 0x0008
X# define ECB_TT 0x0030
X# define ECB_ND 0x0040
X# define ECB_DAT 0x0100
X# define ECB_DIR 0x0200
X# define ECB_ST 0x0400
X# define ECB_CHK 0x0800
X# define ECB_REC 0x4000
X# define ECB_NRB 0x8000
X u_short unused1;
X physaddr data;
X u_long datalen;
X physaddr status;
X physaddr chain;
X short unused2;
X short unused3;
X physaddr sense;
X u_char senselen;
X u_char cdblen;
X short cksum;
X u_char cdb[12];
X /*-----------------end of hardware supported fields----------------*/
X struct ecb *next; /* in free list */
X struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
X long int delta; /* difference from previous*/
X struct ecb *later,*sooner;
X int flags;
X#define ECB_FREE 0
X#define ECB_ACTIVE 1
X#define ECB_ABORTED 2
X#define ECB_IMMED 4
X#define ECB_IMMED_FAIL 8
X struct ahb_dma_seg ahb_dma[AHB_NSEG];
X struct ahb_ecb_status ecb_status;
X struct scsi_sense_data ecb_sense;
X};
X
Xstruct ecb *ahb_soonest = (struct ecb *)0;
Xstruct ecb *ahb_latest = (struct ecb *)0;
Xlong int ahb_furtherest = 0; /* longest time in the timeout queue */
X/**/
X
Xstruct ahb_data
X{
X int flags;
X#define AHB_INIT 0x01;
X int baseport;
X struct ecb ecbs[NUM_CONCURRENT];
X struct ecb *free_ecb;
X int our_id; /* our scsi id */
X int vect;
X struct ecb *immed_ecb; /* an outstanding immediete command */
X} ahb_data[NAHB];
X
Xint ahbprobe();
Xint ahb_attach();
Xint ahbintr();
Xint ahb_scsi_cmd();
Xint ahb_timeout();
Xstruct ecb *cheat;
Xvoid ahbminphys();
Xlong int ahb_adapter_info();
X
X#ifdef MACH
Xstruct isa_driver ahbdriver = { ahbprobe, 0, ahb_attach, "ahb", 0, 0, 0};
Xint (*ahbintrs[])() = {ahbintr, 0};
X#endif MACH
X
X#ifdef __386BSD__
Xstruct isa_driver ahbdriver = { ahbprobe, ahb_attach, "ahb"};
X#endif __386BSD__
X
X#define MAX_SLOTS 8
Xstatic ahb_slot = 0; /* slot last board was found in */
Xstatic ahb_unit = 0;
Xint ahb_debug = 0;
X#define AHB_SHOWECBS 0x01
X#define AHB_SHOWINTS 0x02
X#define AHB_SHOWCMDS 0x04
X#define AHB_SHOWMISC 0x08
X#define FAIL 1
X#define SUCCESS 0
X#define PAGESIZ 4096
X
Xstruct scsi_switch ahb_switch =
X{
X ahb_scsi_cmd,
X ahbminphys,
X 0,
X 0,
X ahb_adapter_info,
X 0,0,0
X};
X
X/**/
X/***********************************************************************\
X* Function to send a command out through a mailbox *
X\***********************************************************************/
Xahb_send_mbox( int unit
X ,int opcode
X ,int target
X ,struct ecb *ecb)
X{
X int port = ahb_data[unit].baseport;
X int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */
X int s = splbio();
X int stport = port + G2STAT;
X
X while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
X != (G2STAT_MBOX_EMPTY))
X && (spincount--));
X if(spincount == -1)
X {
X printf("ahb%d: board not responding\n",unit);
X Debugger();
X }
X
X outl(port + MBOXOUT0,KVTOPHYS(ecb)); /* don't know this will work */
X outb(port + ATTN, opcode|target);
X
X splx(s);
X}
X
X/***********************************************************************\
X* Function to poll for command completion when in poll mode *
X\***********************************************************************/
Xahb_poll(int unit ,int wait) /* in msec */
X{
X int port = ahb_data[unit].baseport;
X int spincount = FUDGE(delaycount) * wait; /* in msec */
X int stport = port + G2STAT;
Xint start = spincount;
X
Xretry:
X while( (spincount--) && (!(inb(stport) & G2STAT_INT_PEND)));
X if(spincount == -1)
X {
X printf("ahb%d: board not responding\n",unit);
X return(EIO);
X }
Xif ((int)cheat != PHYSTOKV(inl(port + MBOXIN0)))
X{
X printf("discarding %x ",inl(port + MBOXIN0));
X outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
X spinwait(50);
X goto retry;
X}/* don't know this will work */
X ahbintr(unit);
X return(0);
X}
X/***********************************************************************\
X* Function to send an immediate type command to the adapter *
X\***********************************************************************/
Xahb_send_immed( int unit
X ,int target
X ,u_long cmd)
X{
X int port = ahb_data[unit].baseport;
X int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */
X int s = splbio();
X int stport = port + G2STAT;
X
X while( ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
X != (G2STAT_MBOX_EMPTY))
X && (spincount--));
X if(spincount == -1)
X {
X printf("ahb%d: board not responding\n",unit);
X Debugger();
X }
X
X outl(port + MBOXOUT0,cmd); /* don't know this will work */
X outb(port + G2CNTRL, G2CNTRL_SET_HOST_READY);
X outb(port + ATTN, OP_IMMED | target);
X splx(s);
X}
X
X/**/
X
X/*******************************************************\
X* Check the slots looking for a board we recognise *
X* If we find one, note it's address (slot) and call *
X* the actual probe routine to check it out. *
X\*******************************************************/
Xahbprobe(dev)
Xstruct isa_dev *dev;
X{
X int port;
X u_char byte1,byte2,byte3;
X ahb_slot++;
X while (ahb_slot<8)
X {
X port = 0x1000 * ahb_slot;
X byte1 = inb(port + HID0);
X byte2 = inb(port + HID1);
X byte3 = inb(port + HID2);
X if(byte1 == 0xff)
X {
X ahb_slot++;
X continue;
X }
X if ((CHAR1(byte1,byte2) == 'A')
X && (CHAR2(byte1,byte2) == 'D')
X && (CHAR3(byte1,byte2) == 'P')
X && ((byte3 == 0 ) || (byte3 == 1)))
X {
X dev->dev_addr = port;
X return(ahbprobe1(dev));
X }
X ahb_slot++;
X }
X return(0);
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\*******************************************************/
Xahbprobe1(dev)
Xstruct isa_dev *dev;
X{
X /***********************************************\
X * find unit and check we have that many defined *
X \***********************************************/
X int unit = ahb_unit;
X#if defined(OSF)
X static ihandler_t ahb_handler[NAHB];
X static ihandler_id_t *ahb_handler_id[NAHB];
X register ihandler_t *chp = &ahb_handler[unit];;
X#endif /* defined(OSF) */
X
X dev->dev_unit = unit;
X ahb_data[unit].baseport = dev->dev_addr;
X if(unit >= NAHB)
X {
X printf("ahb: 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 ahb_data[unit].vect*
X \***********************************************/
X if (ahb_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 ((ahb_handler_id[unit] = handler_add(chp)) != NULL)
X handler_enable(ahb_handler_id[unit]);
X else
X panic("Unable to add ahb interrupt handler");
X#else /* CMU */
X dev->dev_pic = ahb_data[unit].vect;
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 << ahb_data[unit].vect);
X dev->id_drq = -1; /* use EISA dma */
X printf("\n **");
X#endif __386BSD__
X
X ahb_unit++;
X return(1);
X}
X
X/***********************************************\
X* Attach all the sub-devices we can find *
X\***********************************************/
Xahb_attach(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, ahb_data[unit].our_id, &ahb_switch);
X#if defined(OSF)
X ahb_attached[unit]=1;
X#endif /* defined(OSF) */
X if(!unit) /* only one for all boards */
X {
X ahb_timeout(0);
X }
X#ifdef __386BSD__
X printf("ahb%d",unit);
X#endif __386BSD__
X return;
X}
X
X/***********************************************\
X* Return some information to the caller about *
X* the adapter and it's capabilities *
X\***********************************************/
Xlong int ahb_adapter_info(unit)
Xint unit;
X{
X return(2); /* 2 outstanding requests at a time per device */
X}
X
X/***********************************************\
X* Catch an interrupt from the adaptor *
X\***********************************************/
Xahbintr(unit)
X{
X struct ecb *ecb;
X unsigned char stat;
X register i;
X u_char ahbstat;
X int target;
X long int mboxval;
X
X int port = ahb_data[unit].baseport;
X
X if(scsi_debug & PRINTROUTINES)
X printf("ahbintr ");
X
X#if defined(OSF)
X if (!ahb_attached[unit])
X {
X return(1);
X }
X#endif /* defined(OSF) */
X while(inb(port + G2STAT) & G2STAT_INT_PEND)
X {
X /***********************************************\
X * First get all the information and then *
X * acknowlege the interrupt *
X \***********************************************/
X ahbstat = inb(port + G2INTST);
X target = ahbstat & G2INTST_TARGET;
X stat = ahbstat & G2INTST_INT_STAT;
X mboxval = inl(port + MBOXIN0);/* don't know this will work */
X outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
X if(scsi_debug & TRACEINTERRUPTS)
X printf("status = 0x%x ",stat);
X /***********************************************\
X * Process the completed operation *
X \***********************************************/
X
X if(stat == AHB_ECB_OK) /* common case is fast */
X {
X ecb = (struct ecb *)PHYSTOKV(mboxval);
X }
X else
X {
X switch(stat)
X {
X case AHB_IMMED_OK:
X ecb = ahb_data[unit].immed_ecb;
X ahb_data[unit].immed_ecb = 0;
X break;
X case AHB_IMMED_ERR:
X ecb = ahb_data[unit].immed_ecb;
X ecb->flags |= ECB_IMMED_FAIL;
X ahb_data[unit].immed_ecb = 0;
X break;
X case AHB_ASN: /* for target mode */
X ecb = 0;
X break;
X case AHB_HW_ERR:
X ecb = 0;
X break;
X case AHB_ECB_RECOVERED:
X ecb = (struct ecb *)PHYSTOKV(mboxval);
X break;
X case AHB_ECB_ERR:
X ecb = (struct ecb *)PHYSTOKV(mboxval);
X break;
X default:
X printf(" Unknown return from ahb%d(%x)\n",unit,ahbstat);
X ecb=0;
X }
X }
X if(ecb)
X {
X if(ahb_debug & AHB_SHOWCMDS )
X {
X ahb_show_scsi_cmd(ecb->xs);
X }
X if((ahb_debug & AHB_SHOWECBS) && ecb)
X printf("<int ecb(%x)>",ecb);
X ahb_remove_timeout(ecb);
X ahb_done(unit,ecb,((stat == AHB_ECB_OK)?SUCCESS:FAIL));
X }
X }
X return(1);
X}
X
X/***********************************************\
X* We have a ecb which has been processed by the *
X* adaptor, now we look to see how the operation *
X* went. *
X\***********************************************/
Xahb_done(unit,ecb,state)
Xint unit,state;
Xstruct ecb *ecb;
X{
X struct ahb_ecb_status *stat = &ecb->ecb_status;
X struct scsi_sense_data *s1,*s2;
X struct scsi_xfer *xs = ecb->xs;
X
X if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS))
X printf("ahb_done ");
X /***********************************************\
X * Otherwise, put the results of the operation *
X * into the xfer and call whoever started it *
X \***********************************************/
X if(ecb->flags & ECB_IMMED)
X {
X if(ecb->flags & ECB_IMMED_FAIL)
X {
X xs->error = XS_DRIVER_STUFFUP;
X }
X goto done;
X }
X if ( (state == SUCCESS) || (xs->flags & SCSI_ERR_OK))
X { /* All went correctly OR errors expected */
X xs->resid = 0;
X xs->error = 0;
X }
X else
X {
X
X s1 = &(ecb->ecb_sense);
X s2 = &(xs->sense);
X
X if(stat->ha_status)
X {
X switch(stat->ha_status)
X {
X case HS_SCSI_RESET_ADAPTER:
X break;
X case HS_SCSI_RESET_INCOMING:
X break;
X case HS_CMD_ABORTED_HOST: /* No response */
X case HS_CMD_ABORTED_ADAPTER: /* No response */
X break;
X case HS_TIMED_OUT: /* No response */
X if (ahb_debug & AHB_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 (ahb_debug & AHB_SHOWMISC)
X {
X printf("unexpected ha_status: %x\n",
X stat->ha_status);
X }
X }
X
X }
X else
X {
X switch(stat->targ_status)
X {
X case TS_CHECK_CONDITION:
X /* structure copy!!!!!*/
X *s2=*s1;
X xs->error = XS_SENSE;
X break;
X case TS_BUSY:
X xs->error = XS_BUSY;
X break;
X default:
X if (ahb_debug & AHB_SHOWMISC)
X {
X printf("unexpected targ_status: %x\n",
X stat->targ_status);
X }
X xs->error = XS_DRIVER_STUFFUP;
X }
X }
X }
Xdone: xs->flags |= ITSDONE;
X ahb_free_ecb(unit,ecb, xs->flags);
X if(xs->when_done)
X (*(xs->when_done))(xs->done_arg,xs->done_arg2);
X}
X
X/***********************************************\
X* A ecb (and hence a mbx-out is put onto the *
X* free list. *
X\***********************************************/
Xahb_free_ecb(unit,ecb, flags)
Xstruct ecb *ecb;
X{
X unsigned int opri;
X
X if(scsi_debug & PRINTROUTINES)
X printf("ecb%d(0x%x)> ",unit,flags);
X if (!(flags & SCSI_NOMASK))
X opri = splbio();
X
X ecb->next = ahb_data[unit].free_ecb;
X ahb_data[unit].free_ecb = ecb;
X ecb->flags = ECB_FREE;
X /***********************************************\
X * If there were none, wake abybody waiting for *
X * one to come free, starting with queued entries*
X \***********************************************/
X if (!ecb->next) {
X wakeup(&ahb_data[unit].free_ecb);
X }
X if (!(flags & SCSI_NOMASK))
X splx(opri);
X}
X
X/***********************************************\
X* Get a free ecb (and hence mbox-out entry) *
X\***********************************************/
Xstruct ecb *
Xahb_get_ecb(unit,flags)
X{
X unsigned opri;
X struct ecb *rc;
X
X if(scsi_debug & PRINTROUTINES)
X printf("<ecb%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 = ahb_data[unit].free_ecb)) && (!(flags & SCSI_NOSLEEP)))
X {
X sleep(&ahb_data[unit].free_ecb, PRIBIO);
X }
X if (rc)
X {
X ahb_data[unit].free_ecb = rc->next;
X rc->flags = ECB_ACTIVE;
X }
X if (!(flags & SCSI_NOMASK))
X splx(opri);
X return(rc);
X}
X
X
X
X/***********************************************\
X* Start the board, ready for normal operation *
X\***********************************************/
Xahb_init(unit)
Xint unit;
X{
X int port = ahb_data[unit].baseport;
X int intdef;
X int spincount = FUDGE(delaycount) * 1000; /* 1 sec enough? */
X int i;
X int stport = port + G2STAT;
X#define NO_NO 1
X#ifdef NO_NO
X /***********************************************\
X * reset board, If it doesn't respond, assume *
X * that it's not there.. good for the probe *
X \***********************************************/
X outb(port + EBCTRL,CDEN); /* enable full card */
X outb(port + PORTADDR,PORTADDR_ENHANCED);
X
X outb(port + G2CNTRL,G2CNTRL_HARD_RESET);
X spinwait(1);
X outb(port + G2CNTRL,0);
X spinwait(10);
X while( ((inb(stport) & G2STAT_BUSY ))
X && (spincount--));
X if(spincount == -1)
X {
X if (ahb_debug & AHB_SHOWMISC)
X printf("ahb_init: No answer from bt742a board\n");
X return(ENXIO);
X }
X i = inb(port + MBOXIN0) & 0xff;
X if(i)
X {
X printf("self test failed, val = 0x%x\n",i);
X return(EIO);
X }
X#endif
X while( inb(stport) & G2STAT_INT_PEND)
X {
X printf(".");
X outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
X spinwait(10);
X }
X outb(port + EBCTRL,CDEN); /* enable full card */
X outb(port + PORTADDR,PORTADDR_ENHANCED);
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("ahb%d reading board settings, ",unit);
X#define PRNT(x)
X#else __386BSD__
X printf("ahb%d:",unit);
X#define PRNT(x) printf(x)
X#endif __386BSD__
X
X intdef = inb(port + INTDEF);
X switch(intdef & 0x07)
X {
X case INT9:
X ahb_data[unit].vect = 9;
X PRNT("int=9 ");
X break;
X case INT10:
X ahb_data[unit].vect = 10;
X PRNT("int=10 ");
X break;
X case INT11:
X ahb_data[unit].vect = 11;
X PRNT("int=11 ");
X break;
X case INT12:
X ahb_data[unit].vect = 12;
X PRNT("int=12 ");
X break;
X case INT14:
X ahb_data[unit].vect = 14;
X PRNT("int=14 ");
X break;
X case INT15:
X ahb_data[unit].vect = 15;
X PRNT("int=15 ");
X break;
X default:
X printf("illegal int setting\n");
X return(EIO);
X }
X outb(port + INTDEF ,(intdef | INTEN)); /* make sure we can interrupt */
X /* who are we on the scsi bus */
X ahb_data[unit].our_id = (inb(port + SCSIDEF) & HSCSIID);
X
X /***********************************************\
X * link up all our ECBs into a free list *
X \***********************************************/
X for (i=0; i < NUM_CONCURRENT; i++)
X {
X ahb_data[unit].ecbs[i].next = ahb_data[unit].free_ecb;
X ahb_data[unit].free_ecb = &ahb_data[unit].ecbs[i];
X ahb_data[unit].free_ecb->flags = ECB_FREE;
X }
X
X /***********************************************\
X * Note that we are going and return (to probe) *
X \***********************************************/
X ahb_data[unit].flags |= AHB_INIT;
X return( 0 );
X}
X
X
X#ifndef min
X#define min(x,y) (x < y ? x : y)
X#endif min
X
X
Xvoid ahbminphys(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 > ((AHB_NSEG-1) * PAGESIZ))
X {
X bp->b_bcount = ((AHB_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 ahb_scsi_cmd(xs)
Xstruct scsi_xfer *xs;
X{
X struct scsi_sense_data *s1,*s2;
X struct ecb *ecb;
X struct ahb_dma_seg *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 int s;
X if(scsi_debug & PRINTROUTINES)
X printf("ahb_scsi_cmd ");
X /***********************************************\
X * get a ecb (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 (!(ecb = ahb_get_ecb(unit,flags)))
X {
X xs->error = XS_DRIVER_STUFFUP;
X return(TRY_AGAIN_LATER);
X }
X
Xcheat = ecb;
X if(ahb_debug & AHB_SHOWECBS)
X printf("<start ecb(%x)>",ecb);
X if(scsi_debug & SHOWCOMMANDS)
X {
X ahb_show_scsi_cmd(xs);
X }
X ecb->xs = xs;
X /***********************************************\
X * If it's a reset, we need to do an 'immediate' *
X * command, and store it's ccb for later *
X * if there is already an immediate waiting, *
X * then WE must wait *
X \***********************************************/
X if(flags & SCSI_RESET)
X {
X ecb->flags |= ECB_IMMED;
X if(ahb_data[unit].immed_ecb)
X {
X return(TRY_AGAIN_LATER);
X }
X ahb_data[unit].immed_ecb = ecb;
X if (!(flags & SCSI_NOMASK))
X {
X s = splbio();
X ahb_send_immed(unit,xs->targ,AHB_TARG_RESET);
X ahb_add_timeout(ecb,xs->timeout);
X splx(s);
X return(SUCCESSFULLY_QUEUED);
X }
X else
X {
X ahb_send_immed(unit,xs->targ,AHB_TARG_RESET);
X /***********************************************\
X * If we can't use interrupts, poll on completion*
X \***********************************************/
X if(scsi_debug & TRACEINTERRUPTS)
X printf("wait ");
X if( ahb_poll(unit,xs->timeout))
X {
X ahb_free_ecb(unit,ecb,flags);
X xs->error = XS_TIMEOUT;
X return(HAD_ERROR);
X }
X return(COMPLETE);
X }
X }
X /***********************************************\
X * Put all the arguments for the xfer in the ecb *
X \***********************************************/
X ecb->opcode = ECB_SCSI_OP;
X ecb->opt1 = ECB_SES|ECB_DSB|ECB_ARS;
X if(xs->datalen)
X {
X ecb->opt1 |= ECB_S_G;
X }
X ecb->opt2 = xs->lu | ECB_NRB;
X ecb->cdblen = xs->cmdlen;
X ecb->sense = KVTOPHYS(&(ecb->ecb_sense));
X ecb->senselen = sizeof(ecb->ecb_sense);
X ecb->status = KVTOPHYS(&(ecb->ecb_status));
X
X if(xs->datalen)
X { /* should use S/G only if not zero length */
X ecb->data = KVTOPHYS(ecb->ahb_dma);
X sg = ecb->ahb_dma ;
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 < AHB_NSEG))
X {
X sg->addr = (physaddr)iovp->iov_base;
X xs->datalen += sg->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 < AHB_NSEG))
X {
X bytes_this_seg = 0;
X
X /* put in the base address */
X sg->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->len = bytes_this_seg;
X sg++;
X seg++;
X }
X } /*end of iov/kv decision */
X ecb->datalen = seg * sizeof(struct ahb_dma_seg);
X if(scsi_debug & SHOWSCATGATH)
X printf("\n");
X if (datalen)
X { /* there's still data, must have run out of segs! */
X printf("ahb_scsi_cmd%d: more than %d DMA segs\n",
X unit,AHB_NSEG);
X xs->error = XS_DRIVER_STUFFUP;
X ahb_free_ecb(unit,ecb,flags);
X return(HAD_ERROR);
X }
X
X }
X else
X { /* No data xfer, use non S/G values */
X ecb->data = (physaddr)0;
X ecb->datalen = 0;
X }
X ecb->chain = (physaddr)0;
X /***********************************************\
X * Put the scsi command in the ecb and start it *
X \***********************************************/
X bcopy(xs->cmd, ecb->cdb, xs->cmdlen);
X /***********************************************\
X * Usually return SUCCESSFULLY QUEUED *
X \***********************************************/
X if (!(flags & SCSI_NOMASK))
X {
X s = splbio();
X ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb);
X ahb_add_timeout(ecb,xs->timeout);
X splx(s);
X if(scsi_debug & TRACEINTERRUPTS)
X printf("cmd_sent ");
X return(SUCCESSFULLY_QUEUED);
X }
X /***********************************************\
X * If we can't use interrupts, poll on completion*
X \***********************************************/
X ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb);
X if(scsi_debug & TRACEINTERRUPTS)
X printf("cmd_wait ");
X do
X {
X if(ahb_poll(unit,xs->timeout))
X {
X if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n");
X ahb_send_mbox(unit,OP_ABORT_ECB,xs->targ,ecb);
X if(ahb_poll(unit,2000))
X {
X printf("abort failed in wait\n");
X ahb_free_ecb(unit,ecb,flags);
X }
X xs->error = XS_DRIVER_STUFFUP;
X splx(s);
X return(HAD_ERROR);
X }
X } while (!(xs->flags & ITSDONE));/* something (?) else finished */
X splx(s);
Xscsi_debug = 0;ahb_debug = 0;
X if(xs->error)
X {
X return(HAD_ERROR);
X }
X return(COMPLETE);
X}
X
X/*
X * +----------+ +----------+ +----------+
X * ahb_soonest--->| later |--->| later|--->| later|--->0
X * | [Delta] | | [Delta] | | [Delta] |
X * 0<---|sooner |<---|sooner |<---|sooner |<---ahb_latest
X * +----------+ +----------+ +----------+
X *
X * ahb_furtherest = sum(Delta[1..n])
X */
Xahb_add_timeout(ecb,time)
Xstruct ecb *ecb;
Xint time;
X{
X int timeprev;
X struct ecb *prev;
X int s = splbio();
X
X if(prev = ahb_latest) /* yes, an assign */
X {
X timeprev = ahb_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 ecb->delta = time - timeprev;
X if( ecb->later = prev->later) /* yes an assign */
X {
X ecb->later->sooner = ecb;
X ecb->later->delta -= ecb->delta;
X }
X else
X {
X ahb_furtherest = time;
X ahb_latest = ecb;
X }
X ecb->sooner = prev;
X prev->later = ecb;
X }
X else
X {
X if( ecb->later = ahb_soonest) /* yes, an assign*/
X {
X ecb->later->sooner = ecb;
X ecb->later->delta -= time;
X }
X else
X {
X ahb_furtherest = time;
X ahb_latest = ecb;
X }
X ecb->delta = time;
X ecb->sooner = (struct ecb *)0;
X ahb_soonest = ecb;
X }
X splx(s);
X}
X
Xahb_remove_timeout(ecb)
Xstruct ecb *ecb;
X{
X int s = splbio();
X
X if(ecb->sooner)
X {
X ecb->sooner->later = ecb->later;
X }
X else
X {
X ahb_soonest = ecb->later;
X }
X if(ecb->later)
X {
X ecb->later->sooner = ecb->sooner;
X ecb->later->delta += ecb->delta;
X }
X else
X {
X ahb_latest = ecb->sooner;
X ahb_furtherest -= ecb->delta;
X }
X ecb->sooner = ecb->later = (struct ecb *)0;
X splx(s);
X}
X
X
Xextern int hz;
X#define ONETICK 500 /* milliseconds */
X#define SLEEPTIME ((hz * 1000) / ONETICK)
Xahb_timeout(arg)
Xint arg;
X{
X struct ecb *ecb;
X int unit;
X int s = splbio();
X
X while( ecb = ahb_soonest )
X {
X if(ecb->delta <= ONETICK)
X /***********************************************\
X * It has timed out, we need to do some work *
X \***********************************************/
X {
X unit = ecb->xs->adapter;
X printf("ahb%d:%d device timed out\n",unit
X ,ecb->xs->targ);
X if(ahb_debug & AHB_SHOWECBS)
X ahb_print_active_ecb();
X
X /***************************************\
X * Unlink it from the queue *
X \***************************************/
X ahb_remove_timeout(ecb);
X
X /***************************************\
X * If it's immediate, don't try abort it *
X \***************************************/
X if(ecb->flags & ECB_IMMED)
X {
X ecb->xs->retries = 0; /* I MEAN IT ! */
X ecb->flags |= ECB_IMMED_FAIL;
X ahb_done(unit,ecb,FAIL);
X continue;
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(ecb->flags == ECB_ABORTED) /* abort timed out */
X {
X printf("AGAIN");
X ecb->xs->retries = 0; /* I MEAN IT ! */
X ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST;
X ahb_done(unit,ecb,FAIL);
X }
X else /* abort the operation that has timed out */
X {
X printf("\n");
X ahb_send_mbox(unit,OP_ABORT_ECB,ecb->xs->targ,ecb);
X /* 2 secs for the abort */
X ahb_add_timeout(ecb,2000 + ONETICK);
X ecb->flags = ECB_ABORTED;
X }
X }
X else
X /***********************************************\
X * It has not timed out, adjust and leave *
X \***********************************************/
X {
X ecb->delta -= ONETICK;
X ahb_furtherest -= ONETICK;
X break;
X }
X }
X splx(s);
X timeout(ahb_timeout,arg,SLEEPTIME);
X}
X
Xahb_show_scsi_cmd(struct scsi_xfer *xs)
X{
X u_char *b = (u_char *)xs->cmd;
X int i = 0;
X if(!(xs->flags & SCSI_RESET))
X {
X printf("ahb%d:%d:%d-"
X ,xs->adapter
X ,xs->targ
X ,xs->lu);
X while(i < xs->cmdlen )
X {
X if(i) printf(",");
X printf("%x",b[i++]);
X }
X printf("-\n");
X }
X else
X {
X printf("ahb%d:%d:%d-RESET-\n"
X ,xs->adapter
X ,xs->targ
X ,xs->lu
X );
X }
X}
Xahb_print_ecb(ecb)
Xstruct ecb *ecb;
X{
X printf("ecb:%x op:%x cmdlen:%d senlen:%d\n"
X ,ecb
X ,ecb->opcode
X ,ecb->cdblen
X ,ecb->senselen);
X printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n"
X ,ecb->datalen
X ,ecb->ecb_status.ha_status
X ,ecb->ecb_status.targ_status
X ,ecb->delta
X ,ecb->flags);
X ahb_show_scsi_cmd(ecb->xs);
X}
X
Xahb_print_active_ecb()
X{
X struct ecb *ecb;
X ecb = ahb_soonest;
X
X while(ecb)
X {
X ahb_print_ecb(ecb);
X ecb = ecb->later;
X }
X printf("Furtherest = %d\n",ahb_furtherest);
X}
END-of-i386/isa/aha1742.c
exit