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