diff --git a/sys/arch/i386/eisa/aha1742.c b/sys/arch/i386/eisa/aha1742.c index 09e02ae74ad9..6da708734d8b 100644 --- a/sys/arch/i386/eisa/aha1742.c +++ b/sys/arch/i386/eisa/aha1742.c @@ -1,5 +1,36 @@ /* - * Written by Julian Elischer (julian@tfs.com) + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: aha1742.c,v 1.23 1994/03/29 04:30:18 mycroft Exp $ + */ + +/* + * Originally written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -12,63 +43,66 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * $Id: aha1742.c,v 1.22 1994/03/25 07:40:53 mycroft Exp $ + * commenced: Sun Sep 27 18:14:01 PDT 1992 */ -#include "ahb.h" - #include #include #include +#include #include #include +#include +#include #include #include #include -#include -#include -#include #include +#include +#include #include #include -#include - - #ifdef DDB -int Debugger(); -#else DDB -#define Debugger() panic("should call debugger here (adaptec.c)") -#endif DDB +int Debugger(); +#else /* DDB */ +#define Debugger() +#endif /* DDB */ -typedef unsigned long int physaddr; +typedef u_long physaddr; -#define PHYSTOKV(x) ((x) + KERNBASE) -#define KVTOPHYS(x) vtophys(x) +#define KVTOPHYS(x) vtophys(x) -extern int delaycount; /* from clock setup code */ -#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ -#define AHB_NSEG 33 /* number of dma segments supported */ -#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ +#define AHB_ECB_MAX 32 /* store up to 32ECBs at any one time */ + /* in aha1742 H/W ( Not MAX ? ) */ +#define ECB_HASH_SIZE 32 /* when we have a physical addr. for */ + /* a ecb and need to find the ecb in */ + /* space, look it up in the hash table */ +#define ECB_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define ECB_HASH(x) ((((long int)(x))>>ECB_HASH_SHIFT) % ECB_HASH_SIZE) +#define AHB_NSEG 33 /* number of dma segments supported */ /* * AHA1740 standard EISA Host ID regs (Offset from slot base) */ -#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ -#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ -#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ -#define HID3 0xC83 /* firmware revision */ +#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ +#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ +#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ +#define HID3 0xC83 /* firmware revision */ #define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@') #define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@') #define CHAR3(B1,B2) ((B2 & 0x1F) | '@') -/* AHA1740 EISA board control registers (Offset from slot base) */ +/* + * AHA1740 EISA board control registers (Offset from slot base) + */ #define EBCTRL 0xC84 #define CDEN 0x01 + /* * AHA1740 EISA board mode registers (Offset from slot base) */ @@ -81,24 +115,21 @@ extern int delaycount; /* from clock setup code */ #define RESV0 0xCC5 #define RESV1 0xCC6 #define RESV2 0xCC7 - -/* bit definitions for INTDEF */ +/**** bit definitions for INTDEF ****/ #define INT9 0x00 #define INT10 0x01 #define INT11 0x02 #define INT12 0x03 #define INT14 0x05 #define INT15 0x06 -#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ +#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ #define INTEN 0x10 - -/* bit definitions for SCSIDEF */ -#define HSCSIID 0x0F /* our SCSI ID */ -#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ - -/* bit definitions for BUSDEF */ -#define B0uS 0x00 /* give up bus immediatly */ -#define B4uS 0x01 /* delay 4uSec. */ +/**** bit definitions for SCSIDEF ****/ +#define HSCSIID 0x0F /* our SCSI ID */ +#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ +/**** bit definitions for BUSDEF ****/ +#define B0uS 0x00 /* give up bus immediatly */ +#define B4uS 0x01 /* delay 4uSec. */ #define B8uS 0x02 /* @@ -151,225 +182,253 @@ extern int delaycount; /* from clock setup code */ #define G2STAT2_HOST_READY 0x01 - struct ahb_dma_seg { - physaddr addr; - long len; + physaddr addr; + long len; }; struct ahb_ecb_status { - u_short status; -# define ST_DON 0x0001 -# define ST_DU 0x0002 -# define ST_QF 0x0008 -# define ST_SC 0x0010 -# define ST_DO 0x0020 -# define ST_CH 0x0040 -# define ST_INT 0x0080 -# define ST_ASA 0x0100 -# define ST_SNS 0x0200 -# define ST_INI 0x0800 -# define ST_ME 0x1000 -# define ST_ECA 0x4000 - u_char ha_status; -# define HS_OK 0x00 -# define HS_CMD_ABORTED_HOST 0x04 -# define HS_CMD_ABORTED_ADAPTER 0x05 -# define HS_TIMED_OUT 0x11 -# define HS_HARDWARE_ERR 0x20 -# define HS_SCSI_RESET_ADAPTER 0x22 -# define HS_SCSI_RESET_INCOMING 0x23 - u_char targ_status; -# define TS_OK 0x00 -# define TS_CHECK_CONDITION 0x02 -# define TS_BUSY 0x08 - u_long resid_count; - u_long resid_addr; - u_short addit_status; - u_char sense_len; - u_char unused[9]; - u_char cdb[6]; + u_short status; +#define ST_DON 0x0001 +#define ST_DU 0x0002 +#define ST_QF 0x0008 +#define ST_SC 0x0010 +#define ST_DO 0x0020 +#define ST_CH 0x0040 +#define ST_INT 0x0080 +#define ST_ASA 0x0100 +#define ST_SNS 0x0200 +#define ST_INI 0x0800 +#define ST_ME 0x1000 +#define ST_ECA 0x4000 + u_char ha_status; +#define HS_OK 0x00 +#define HS_CMD_ABORTED_HOST 0x04 +#define HS_CMD_ABORTED_ADAPTER 0x05 +#define HS_TIMED_OUT 0x11 +#define HS_HARDWARE_ERR 0x20 +#define HS_SCSI_RESET_ADAPTER 0x22 +#define HS_SCSI_RESET_INCOMING 0x23 + u_char targ_status; +#define TS_OK 0x00 +#define TS_CHECK_CONDITION 0x02 +#define TS_BUSY 0x08 + u_long resid_count; + u_long resid_addr; + u_short addit_status; + u_char sense_len; + u_char unused[9]; + u_char cdb[6]; }; - struct ecb { - u_char opcode; -# define ECB_SCSI_OP 0x01 - u_char :4; - u_char options:3; - u_char :1; - short opt1; -# define ECB_CNE 0x0001 -# define ECB_DI 0x0080 -# define ECB_SES 0x0400 -# define ECB_S_G 0x1000 -# define ECB_DSB 0x4000 -# define ECB_ARS 0x8000 - short opt2; -# define ECB_LUN 0x0007 -# define ECB_TAG 0x0008 -# define ECB_TT 0x0030 -# define ECB_ND 0x0040 -# define ECB_DAT 0x0100 -# define ECB_DIR 0x0200 -# define ECB_ST 0x0400 -# define ECB_CHK 0x0800 -# define ECB_REC 0x4000 -# define ECB_NRB 0x8000 - u_short unused1; - physaddr data; - u_long datalen; - physaddr status; - physaddr chain; - short unused2; - short unused3; - physaddr sense; - u_char senselen; - u_char cdblen; - short cksum; - u_char cdb[12]; + u_char opcode; +#define ECB_SCSI_OP 0x01 + u_char:4; + u_char options:3; + u_char:1; + short opt1; +#define ECB_CNE 0x0001 +#define ECB_DI 0x0080 +#define ECB_SES 0x0400 +#define ECB_S_G 0x1000 +#define ECB_DSB 0x4000 +#define ECB_ARS 0x8000 + short opt2; +#define ECB_LUN 0x0007 +#define ECB_TAG 0x0008 +#define ECB_TT 0x0030 +#define ECB_ND 0x0040 +#define ECB_DAT 0x0100 +#define ECB_DIR 0x0200 +#define ECB_ST 0x0400 +#define ECB_CHK 0x0800 +#define ECB_REC 0x4000 +#define ECB_NRB 0x8000 + u_short unused1; + physaddr data; + u_long datalen; + physaddr status; + physaddr chain; + short unused2; + short unused3; + physaddr sense; + u_char senselen; + u_char cdblen; + short cksum; + u_char cdb[12]; /*-----------------end of hardware supported fields----------------*/ - struct ecb *next; /* in free list */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - long int delta; /* difference from previous*/ - struct ecb *later,*sooner; - int flags; + struct ecb *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + int flags; #define ECB_FREE 0 #define ECB_ACTIVE 1 #define ECB_ABORTED 2 #define ECB_IMMED 4 #define ECB_IMMED_FAIL 8 - struct ahb_dma_seg ahb_dma[AHB_NSEG]; - struct ahb_ecb_status ecb_status; - struct scsi_sense_data ecb_sense; + struct ahb_dma_seg ahb_dma[AHB_NSEG]; + struct ahb_ecb_status ecb_status; + struct scsi_sense_data ecb_sense; + struct ecb *nexthash; + physaddr hashkey; /* physaddr of this struct */ }; -struct ecb *ahb_soonest = (struct ecb *)0; -struct ecb *ahb_latest = (struct ecb *)0; -long int ahb_furtherest = 0; /* longest time in the timeout queue */ +struct ahb_softc { + struct device sc_dev; + struct isadev sc_id; + struct intrhand sc_ih; -struct ahb_data { - int flags; -#define AHB_INIT 0x01; - int baseport; - struct ecb ecbs[NUM_CONCURRENT]; + u_short baseport; + struct ecb *ecbhash[ECB_HASH_SIZE]; struct ecb *free_ecb; - int vect; - struct ecb *immed_ecb; /* an outstanding immediete command */ -} ahb_data[NAHB]; + int our_id; /* our scsi id */ + int vect; + struct ecb *immed_ecb; /* an outstanding immediete command */ + int numecbs; + struct scsi_link sc_link; +}; -struct ecb *cheat; +void ahb_send_mbox __P((struct ahb_softc *, int, int, struct ecb *)); +int ahb_poll __P((struct ahb_softc *, int)); +void ahb_send_immed __P((struct ahb_softc *, int, u_long)); +u_int ahb_adapter_info __P((struct ahb_softc *)); +int ahbintr __P((int)); +void ahb_done __P((struct ahb_softc *, struct ecb *, int)); +void ahb_free_ecb __P((struct ahb_softc *, struct ecb *, int)); +struct ecb *ahb_get_ecb __P((struct ahb_softc *, int)); +struct ecb *ahb_ecb_phys_kv __P((struct ahb_softc *, physaddr)); +int ahb_find __P((struct ahb_softc *)); +void ahb_init __P((struct ahb_softc *)); +void ahbminphys __P((struct buf *)); +int ahb_scsi_cmd __P((struct scsi_xfer *)); +void ahb_timeout __P((caddr_t)); +void ahb_print_ecb __P((struct ecb *)); +void ahb_print_active_ecb __P((struct ahb_softc *)); -#define MAX_SLOTS 8 -static ahb_slot = 0; /* slot last board was found in */ -static ahb_unit = 0; -int ahb_debug = 0; +struct ecb *cheat; + +#define MAX_SLOTS 15 +static ahb_slot = 0; /* slot last board was found in */ +int ahb_debug = 0; #define AHB_SHOWECBS 0x01 #define AHB_SHOWINTS 0x02 #define AHB_SHOWCMDS 0x04 #define AHB_SHOWMISC 0x08 -#define FAIL 1 -#define SUCCESS 0 -#define PAGESIZ 4096 - -int ahbprobe(struct isa_device *); -int ahbprobe1(struct isa_device *); -int ahb_attach(struct isa_device *); -long int ahb_adapter_info(int); -int ahbintr(int); -void ahb_done(int, struct ecb *, int); -void ahb_free_ecb(int, struct ecb *, int); -struct ecb * ahb_get_ecb(int, int); -int ahb_init(int); -void ahbminphys(struct buf *); -int ahb_scsi_cmd(struct scsi_xfer *); -void ahb_add_timeout(struct ecb *, int); -void ahb_remove_timeout(struct ecb *); -void ahb_timeout(int); -void ahb_show_scsi_cmd(struct scsi_xfer *); -void ahb_print_ecb(struct ecb *); -void ahb_print_active_ecb(void); - - -struct isa_driver ahbdriver = { - ahbprobe, - ahb_attach, +struct scsi_adapter ahb_switch = { + ahb_scsi_cmd, + ahbminphys, + 0, + 0, + ahb_adapter_info, "ahb" }; -struct scsi_switch ahb_switch[NAHB]; +/* the below structure is so we have a default dev struct for our link struct */ +struct scsi_device ahb_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "ahb", + 0 +}; + +int ahbprobe(); +int ahbprobe1 __P((struct ahb_softc *, struct isa_attach_args *)); +void ahbattach(); + +struct cfdriver ahbcd = { + NULL, "ahb", ahbprobe, ahbattach, DV_DULL, sizeof(struct ahb_softc) +}; /* * Function to send a command out through a mailbox */ void -ahb_send_mbox(int unit, int opcode, int target, struct ecb *ecb) +ahb_send_mbox(ahb, opcode, target, ecb) + struct ahb_softc *ahb; + int opcode, target; + struct ecb *ecb; { - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ - int stport = port + G2STAT, s; + u_short port = ahb->baseport; + u_short stport = port + G2STAT; + int wait = 100; /* 1ms should be enough */ + int s = splbio(); - s = splbio(); - while( ((inb(stport) & - (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) != G2STAT_MBOX_EMPTY) - && spincount--) - ; - if(spincount == -1) { - printf("ahb%d: board not responding\n",unit); + while (--wait) { + if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + == (G2STAT_MBOX_EMPTY)) + break; + delay(10); + } + if (!wait) { + printf("%s: board not responding\n", ahb->sc_dev.dv_xname); Debugger(); } - outl(port+MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */ - outb(port+ATTN, opcode|target); + outl(port + MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */ + outb(port + ATTN, opcode | target); + splx(s); } /* * Function to poll for command completion when in poll mode - * wait is in msec */ int -ahb_poll(int unit, int wait) -{ - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * wait; /* in msec */ - int stport = port + G2STAT; - int start = spincount; +ahb_poll(ahb, wait) + struct ahb_softc *ahb; + int wait; +{ /* in msec */ + u_short port = ahb->baseport; + u_short stport = port + G2STAT; -retry: - while( spincount-- && (!(inb(stport) & G2STAT_INT_PEND))) - ; - if(spincount == -1) { - printf("ahb%d: board not responding\n",unit); - return(EIO); + retry: + while (--wait) { + if (inb(stport) & G2STAT_INT_PEND) + break; + delay(1000); } - if( (int)cheat != PHYSTOKV(inl(port+MBOXIN0)) ) { - printf("discarding %x ", inl(port+MBOXIN0)); + if (!wait) { + printf("%s: board not responding\n", ahb->sc_dev.dv_xname); + return EIO; + } + + if (cheat != ahb_ecb_phys_kv(ahb, inl(port + MBOXIN0))) { + printf("discarding %x ", inl(port + MBOXIN0)); outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - spinwait(50); + delay(50000); goto retry; } - ahbintr(unit); - return(0); + + /* don't know this will work */ + ahbintr(ahb->sc_dev.dv_unit); + return 0; } + /* * Function to send an immediate type command to the adapter */ void -ahb_send_immed(int unit, int target, u_long cmd) +ahb_send_immed(ahb, target, cmd) + struct ahb_softc *ahb; + int target; + u_long cmd; { - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ + u_short port = ahb->baseport; + u_short stport = port + G2STAT; + int wait = 100; /* 1 ms enough? */ int s = splbio(); - int stport = port + G2STAT; - while( ((inb(stport) & - (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) != (G2STAT_MBOX_EMPTY)) && - spincount--) - ; - if(spincount == -1) { - printf("ahb%d: board not responding\n",unit); + while (--wait) { + if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + == (G2STAT_MBOX_EMPTY)) + break; + delay(10); + } + if (!wait) { + printf("%s: board not responding\n", ahb->sc_dev.dv_xname); Debugger(); } @@ -380,234 +439,257 @@ ahb_send_immed(int unit, int target, u_long cmd) } /* - * Check the slots looking for a board we recognise + * Check the slots looking for a board we recognise * If we find one, note it's address (slot) and call * the actual probe routine to check it out. */ int -ahbprobe(struct isa_device *dev) +ahbprobe(parent, self, aux) + struct device *parent, *self; + void *aux; { - int port; - u_char byte1,byte2,byte3; + struct ahb_softc *ahb = (void *)self; + struct isa_attach_args *ia = aux; + u_short port; + u_char byte1, byte2, byte3; - if (dev->id_parent) - return 1; +#ifdef NEWCONFIG + if (ia->ia_iobase != IOBASEUNK) + return ahbprobe1(ahb, ia); +#endif - ahb_slot++; - while (ahb_slot<8) { + while (ahb_slot < MAX_SLOTS) { + ahb_slot++; port = 0x1000 * ahb_slot; byte1 = inb(port + HID0); byte2 = inb(port + HID1); byte3 = inb(port + HID2); - if(byte1 == 0xff) { - ahb_slot++; + if (byte1 == 0xff) + continue; + if (CHAR1(byte1, byte2) != 'A' || + CHAR2(byte1, byte2) != 'D' || + CHAR3(byte1, byte2) != 'P' || + (byte3 != 0 && byte3 != 1)) { continue; } - if ((CHAR1(byte1,byte2) == 'A') - && (CHAR2(byte1,byte2) == 'D') - && (CHAR3(byte1,byte2) == 'P') - && ((byte3 == 0 ) || (byte3 == 1))) { - dev->id_iobase = port; - return ahbprobe1(dev); - } - ahb_slot++; + ia->ia_iobase = port; + if (ahbprobe1(ahb, ia)) + return 1; } + return 0; } /* - * Check if the device can be found at the port given * - * and if so, set it up ready for further work * - * as an argument, takes the isa_device structure from * - * autoconf.c * + * Check if the device can be found at the port given + * and if so, set it up ready for further work + * as an argument, takes the isa_device structure from + * autoconf.c. */ int -ahbprobe1(struct isa_device *dev) +ahbprobe1(ahb, ia) + struct ahb_softc *ahb; + struct isa_attach_args *ia; { - int unit = ahb_unit; - dev->id_unit = unit; - ahb_data[unit].baseport = dev->id_iobase; - if(unit >= NAHB) { - printf("ahb: unit number (%d) too high\n",unit); - return 0; - } + ahb->baseport = ia->ia_iobase; /* * Try initialise a unit at this location - * sets up dma and bus speed, loads ahb_data[unit].vect* + * sets up dma and bus speed, loads ahb->vect */ - if (ahb_init(unit) != 0) + if (ahb_find(ahb) != 0) return 0; - /* If it's there, put in it's interrupt vectors */ - dev->id_irq = (1 << ahb_data[unit].vect); - dev->id_drq = -1; /* using EISA dma */ - ahb_unit++; - return 0x1000; +#ifdef NEWCONFIG + if (ia->ia_irq == IRQUNK) { + ia->ia_irq = (1 << ahb->vect); + } else { + if (ia->ia_irq != (1 << ahb->vect)) { + printf("ahb%d: irq mismatch, %x != %x\n", + ahb->sc_dev.dv_unit, ia->ia_irq, + 1 << ahb->vect); + return 0; + } + } +#endif + + ia->ia_drq = DRQUNK; + ia->ia_msize = 0; + ia->ia_iosize = 0x1000; + return 1; +} + +ahbprint() +{ + } /* * Attach all the sub-devices we can find */ -int -ahb_attach(struct isa_device *dev) +void +ahbattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - static int firsttime; - static int firstswitch[NAHB]; - int masunit; - int r; + struct isa_attach_args *ia = aux; + struct ahb_softc *ahb = (void *)self; - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; + ahb_init(ahb); - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - ahb_switch[masunit].name = "ahb"; - ahb_switch[masunit].scsi_cmd = ahb_scsi_cmd; - ahb_switch[masunit].scsi_minphys = ahbminphys; - ahb_switch[masunit].open_target_lu = 0; - ahb_switch[masunit].close_target_lu = 0; - ahb_switch[masunit].adapter_info = ahb_adapter_info; - for (r = 0; r < 8; r++) { - ahb_switch[masunit].empty[r] = 0; - ahb_switch[masunit].used[r] = 0; - ahb_switch[masunit].printed[r] = 0; - } - } - r = scsi_attach(masunit, &ahb_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); + /* + * fill in the prototype scsi_link. + */ + ahb->sc_link.adapter_softc = ahb; + ahb->sc_link.adapter_targ = ahb->our_id; + ahb->sc_link.adapter = &ahb_switch; + ahb->sc_link.device = &ahb_dev; - /* only one for all boards */ - if(firsttime==0) { - firsttime = 1; - ahb_timeout(0); - } - return r; + printf("\n"); + +#ifdef NEWCONFIG + isa_establish(&ahb->sc_id, &ahb->sc_dev); + ahb->sc_ih.ih_fun = ahbintr; + ahb->sc_ih.ih_arg = ahb; + /* XXX and DV_TAPE, but either gives us splbio */ + intr_establish(ia->ia_irq, &ahb->sc_ih, DV_DISK); +#endif + + /* + * ask the adapter what subunits are present + */ + config_found(self, &ahb->sc_link, ahbprint); } /* - * Return some information to the caller about * - * the adapter and it's capabilities * - * 2 outstanding requests at a time per device + * Return some information to the caller about + * the adapter and it's capabilities */ -long int -ahb_adapter_info(int unit) +u_int +ahb_adapter_info(ahb) + struct ahb_softc *ahb; { - return 2; + + return 2; /* 2 outstanding requests at a time per device */ } /* * Catch an interrupt from the adaptor */ int -ahbintr(int unit) +ahbintr(unit) + int unit; { - struct ecb *ecb; - unsigned char stat; - register i; - u_char ahbstat; - int target; - long int mboxval; + struct ahb_softc *ahb = ahbcd.cd_devs[unit]; + struct ecb *ecb; + u_char stat, ahbstat; + u_long mboxval; + u_short port = ahb->baseport; - int port = ahb_data[unit].baseport; +#ifdef AHBDEBUG + printf("ahbintr "); +#endif /*AHBDEBUG */ - if(scsi_debug & PRINTROUTINES) - printf("ahbintr "); - - while(inb(port + G2STAT) & G2STAT_INT_PEND) { + while (inb(port + G2STAT) & G2STAT_INT_PEND) { /* * First get all the information and then * acknowlege the interrupt */ ahbstat = inb(port + G2INTST); - target = ahbstat & G2INTST_TARGET; stat = ahbstat & G2INTST_INT_STAT; - mboxval = inl(port + MBOXIN0);/* don't know this will work */ + mboxval = inl(port + MBOXIN0); /* don't know this will work */ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - if(scsi_debug & TRACEINTERRUPTS) - printf("status = 0x%x ",stat); + +#ifdef AHBDEBUG + printf("status = 0x%x ", ahbstat); +#endif /*AHBDEBUG */ /* * Process the completed operation */ - if(stat == AHB_ECB_OK) - ecb = (struct ecb *)PHYSTOKV(mboxval); - else { - switch(stat) { + if (stat == AHB_ECB_OK) { /* common case is fast */ + ecb = ahb_ecb_phys_kv(ahb, mboxval); + } else { + switch (stat) { case AHB_IMMED_OK: - ecb = ahb_data[unit].immed_ecb; - ahb_data[unit].immed_ecb = 0; + ecb = ahb->immed_ecb; + ahb->immed_ecb = 0; break; case AHB_IMMED_ERR: - ecb = ahb_data[unit].immed_ecb; + ecb = ahb->immed_ecb; ecb->flags |= ECB_IMMED_FAIL; - ahb_data[unit].immed_ecb = 0; + ahb->immed_ecb = 0; break; case AHB_ASN: /* for target mode */ + printf("%s: Unexpected ASN interrupt(%x)\n", + ahb->sc_dev.dv_xname, mboxval); ecb = 0; break; case AHB_HW_ERR: + printf("%s: Hardware error interrupt(%x)\n", + ahb->sc_dev.dv_xname, mboxval); ecb = 0; break; case AHB_ECB_RECOVERED: - ecb = (struct ecb *)PHYSTOKV(mboxval); + ecb = ahb_ecb_phys_kv(ahb, mboxval); break; case AHB_ECB_ERR: - ecb = (struct ecb *)PHYSTOKV(mboxval); + ecb = ahb_ecb_phys_kv(ahb, mboxval); break; default: - printf(" Unknown return from ahb%d(%x)\n",unit,ahbstat); - ecb=0; + printf("%s: Unknown return %x\n", + ahb->sc_dev.dv_xname, ahbstat); + ecb = 0; } - } - if(ecb) { - if(ahb_debug & AHB_SHOWCMDS ) - ahb_show_scsi_cmd(ecb->xs); - if((ahb_debug & AHB_SHOWECBS) && ecb) - printf("",ecb); - ahb_remove_timeout(ecb); - ahb_done(unit, ecb, (stat==AHB_ECB_OK)? SUCCESS: FAIL); + } if (ecb) { +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWCMDS) + show_scsi_cmd(ecb->xs); + if ((ahb_debug & AHB_SHOWECBS) && ecb) + printf("", ecb); +#endif /*AHBDEBUG */ + untimeout((timeout_t)ahb_timeout, (caddr_t)ecb); + ahb_done(ahb, ecb, stat != AHB_ECB_OK); } } return 1; } /* - * We have a ecb which has been processed by the - * adaptor, now we look to see how the operation - * went. + * We have a ecb which has been processed by the adaptor, now we look to see + * how the operation went. */ void -ahb_done(int unit, struct ecb *ecb, int state) +ahb_done(ahb, ecb, failed) + struct ahb_softc *ahb; + struct ecb *ecb; + int failed; { - struct ahb_ecb_status *stat = &ecb->ecb_status; - struct scsi_sense_data *s1,*s2; + struct ahb_ecb_status *stat = &ecb->ecb_status; + struct scsi_sense_data *s1, *s2; struct scsi_xfer *xs = ecb->xs; - if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("ahb_done "); - + SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_done\n")); /* * Otherwise, put the results of the operation * into the xfer and call whoever started it */ - if(ecb->flags & ECB_IMMED) { - if(ecb->flags & ECB_IMMED_FAIL) + if (ecb->flags & ECB_IMMED) { + if (ecb->flags & ECB_IMMED_FAIL) xs->error = XS_DRIVER_STUFFUP; goto done; } - if ( (state == SUCCESS) || (xs->flags & SCSI_ERR_OK)) { - /* All went correctly OR errors expected */ + + if (!failed || (xs->flags & SCSI_ERR_OK)) { /* All went correctly OR errors expected */ xs->resid = 0; xs->error = 0; } else { s1 = &(ecb->ecb_sense); s2 = &(xs->sense); - if(stat->ha_status) { - switch(stat->ha_status) { + if (stat->ha_status) { + switch (stat->ha_status) { case HS_SCSI_RESET_ADAPTER: break; case HS_SCSI_RESET_INCOMING: @@ -615,22 +697,25 @@ ahb_done(int unit, struct ecb *ecb, int state) case HS_CMD_ABORTED_HOST: /* No response */ case HS_CMD_ABORTED_ADAPTER: /* No response */ break; - case HS_TIMED_OUT: /* No response */ + case HS_TIMED_OUT: /* No response */ +#ifdef AHBDEBUG if (ahb_debug & AHB_SHOWMISC) printf("timeout reported back\n"); +#endif /*AHBDEBUG */ xs->error = XS_TIMEOUT; break; - default: - /* Other scsi protocol messes */ + default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; +#ifdef AHBDEBUG if (ahb_debug & AHB_SHOWMISC) - printf("unexpected ha_status: %x\n", + printf("unexpected ha_status %x\n", stat->ha_status); +#endif /*AHBDEBUG */ } - } else { - switch(stat->targ_status) { + switch (stat->targ_status) { case TS_CHECK_CONDITION: + /* structure copy!!!!! */ *s2 = *s1; xs->error = XS_SENSE; break; @@ -638,19 +723,20 @@ ahb_done(int unit, struct ecb *ecb, int state) xs->error = XS_BUSY; break; default: - if (ahb_debug & AHB_SHOWMISC) - printf("unexpected targ_status: %x\n", +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWMISC) { + printf("unexpected targ_status %x\n", stat->targ_status); + } +#endif /*AHBDEBUG */ xs->error = XS_DRIVER_STUFFUP; } } } - -done: + done: xs->flags |= ITSDONE; - ahb_free_ecb(unit, ecb, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + ahb_free_ecb(ahb, ecb, xs->flags); + scsi_done(xs); } /* @@ -658,72 +744,122 @@ done: * free list. */ void -ahb_free_ecb(int unit, struct ecb *ecb, int flags) +ahb_free_ecb(ahb, ecb, flags) + struct ahb_softc *ahb; + struct ecb *ecb; + int flags; { - unsigned int opri; + int opri; - if(scsi_debug & PRINTROUTINES) - printf("ecb%d(0x%x)> ",unit,flags); - if (!(flags & SCSI_NOMASK)) - opri = splbio(); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); - ecb->next = ahb_data[unit].free_ecb; - ahb_data[unit].free_ecb = ecb; + ecb->next = ahb->free_ecb; + ahb->free_ecb = ecb; ecb->flags = ECB_FREE; - /* * If there were none, wake abybody waiting for - * one to come free, starting with queued entries* + * one to come free, starting with queued entries */ if (!ecb->next) - wakeup((caddr_t)&ahb_data[unit].free_ecb); + wakeup((caddr_t)&ahb->free_ecb); - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); } /* - * Get a free ecb (and hence mbox-out entry) + * Get a free ecb + * + * If there are none, see if we can allocate a new one. If so, put it in the + * hash table too otherwise either return an error or sleep. */ struct ecb * -ahb_get_ecb(int unit, int flags) +ahb_get_ecb(ahb, flags) + struct ahb_softc *ahb; + int flags; { - unsigned opri; - struct ecb *rc; + int opri; + struct ecb *ecbp; + int hashnum; - if(scsi_debug & PRINTROUTINES) - printf("next; - rc->flags = ECB_ACTIVE; + while (!(ecbp = ahb->free_ecb)) { + if (ahb->numecbs < AHB_ECB_MAX) { + if (ecbp = (struct ecb *) malloc(sizeof(struct ecb), + M_TEMP, + M_NOWAIT)) { + bzero(ecbp, sizeof(struct ecb)); + ahb->numecbs++; + ecbp->flags = ECB_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + ecbp->hashkey = KVTOPHYS(ecbp); + hashnum = ECB_HASH(ecbp->hashkey); + ecbp->nexthash = ahb->ecbhash[hashnum]; + ahb->ecbhash[hashnum] = ecbp; + } else { + printf("%s: Can't malloc ECB\n", + ahb->sc_dev.dv_xname); + } + goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) + tsleep((caddr_t)&ahb->free_ecb, PRIBIO, + "ahbecb", 0); + } } - - if (!(flags & SCSI_NOMASK)) + if (ecbp) { + /* Get ECB from from free list */ + ahb->free_ecb = ecbp->next; + ecbp->flags = ECB_ACTIVE; + } + gottit: + if (!(flags & SCSI_NOMASK)) splx(opri); - return rc; + + return ecbp; +} + +/* + * given a physical address, find the ecb that it corresponds to. + */ +struct ecb * +ahb_ecb_phys_kv(ahb, ecb_phys) + struct ahb_softc *ahb; + physaddr ecb_phys; +{ + int hashnum = ECB_HASH(ecb_phys); + struct ecb *ecbp = ahb->ecbhash[hashnum]; + + while (ecbp) { + if (ecbp->hashkey == ecb_phys) + break; + ecbp = ecbp->nexthash; + } + return ecbp; } /* * Start the board, ready for normal operation */ int -ahb_init(int unit) +ahb_find(ahb) + struct ahb_softc *ahb; { - int port = ahb_data[unit].baseport; - int intdef; - int spincount = FUDGE(delaycount) * 1000; /* 1 sec enough? */ + u_short port = ahb->baseport; + u_short stport = port + G2STAT; + u_char intdef; int i; - int stport = port + G2STAT; + int wait = 1000; /* 1 sec enough? */ #define NO_NO 1 #ifdef NO_NO @@ -731,497 +867,388 @@ ahb_init(int unit) * reset board, If it doesn't respond, assume * that it's not there.. good for the probe */ - outb(port + EBCTRL,CDEN); /* enable full card */ - outb(port + PORTADDR,PORTADDR_ENHANCED); + outb(port + EBCTRL, CDEN); /* enable full card */ + outb(port + PORTADDR, PORTADDR_ENHANCED); - outb(port + G2CNTRL,G2CNTRL_HARD_RESET); - spinwait(1); - outb(port + G2CNTRL,0); - spinwait(10); - while( (inb(stport) & G2STAT_BUSY ) && spincount--) - ; - if(spincount == -1) { - if (ahb_debug & AHB_SHOWMISC) - printf("ahb_init: No answer from bt742a board\n"); - return(ENXIO); + outb(port + G2CNTRL, G2CNTRL_HARD_RESET); + delay(1000); + outb(port + G2CNTRL, 0); + delay(10000); + while (--wait) { + if ((inb(stport) & G2STAT_BUSY) == 0) + break; + delay(1000); } - - i = inb(port + MBOXIN0) & 0xff; - if(i) { - printf("self test failed, val = 0x%x\n",i); - return(EIO); + if (!wait) { +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWMISC) + printf("ahb_find: No answer from aha1742 board\n"); +#endif /*AHBDEBUG */ + return ENXIO; + } + i = inb(port + MBOXIN0); + if (i) { + printf("self test failed, val = 0x%x\n", i); + return EIO; } #endif - while( inb(stport) & G2STAT_INT_PEND) { + while (inb(stport) & G2STAT_INT_PEND) { printf("."); outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - spinwait(10); + delay(10000); } - outb(port + EBCTRL,CDEN); /* enable full card */ - outb(port + PORTADDR,PORTADDR_ENHANCED); - - /* - * Assume we have a board at this stage - * setup dma channel from jumpers and save int - * level - */ + outb(port + EBCTRL, CDEN); /* enable full card */ + outb(port + PORTADDR, PORTADDR_ENHANCED); intdef = inb(port + INTDEF); - switch(intdef & 0x07) { + switch (intdef & 0x07) { case INT9: - ahb_data[unit].vect = 9; + ahb->vect = 9; break; case INT10: - ahb_data[unit].vect = 10; + ahb->vect = 10; break; case INT11: - ahb_data[unit].vect = 11; + ahb->vect = 11; break; case INT12: - ahb_data[unit].vect = 12; + ahb->vect = 12; break; case INT14: - ahb_data[unit].vect = 14; + ahb->vect = 14; break; case INT15: - ahb_data[unit].vect = 15; + ahb->vect = 15; break; default: - ahb_data[unit].vect = -1; - printf("ahb%d: illegal irq setting\n", unit); - return(EIO); + printf("illegal int setting %x\n", intdef); + return EIO; } - outb(port + INTDEF, intdef|INTEN); /* make sure we can interrupt */ - ahb_switch[unit].scsi_dev = (inb(port + SCSIDEF) & HSCSIID); + outb(port + INTDEF, (intdef | INTEN)); /* make sure we can interrupt */ - /* - * link up all our ECBs into a free list - */ - for (i=0; i < NUM_CONCURRENT; i++) { - ahb_data[unit].ecbs[i].next = ahb_data[unit].free_ecb; - ahb_data[unit].free_ecb = &ahb_data[unit].ecbs[i]; - ahb_data[unit].free_ecb->flags = ECB_FREE; - } + /* who are we on the scsi bus? */ + ahb->our_id = (inb(port + SCSIDEF) & HSCSIID); /* * Note that we are going and return (to probe) */ - ahb_data[unit].flags |= AHB_INIT; return 0; } void -ahbminphys(struct buf *bp) +ahb_init(ahb) + struct ahb_softc *ahb; { - if(bp->b_bcount > ((AHB_NSEG-1) * PAGESIZ)) - bp->b_bcount = ((AHB_NSEG-1) * PAGESIZ); + +} + +void +ahbminphys(bp) + struct buf *bp; +{ + + if (bp->b_bcount > ((AHB_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((AHB_NSEG - 1) << PGSHIFT); } /* - * start a scsi operation given the command and - * the data address. Also needs the unit, target - * and lu + * start a scsi operation given the command and the data address. Also needs + * the unit, target and lu. */ -int -ahb_scsi_cmd(struct scsi_xfer *xs) +int +ahb_scsi_cmd(xs) + struct scsi_xfer *xs; { - struct scsi_sense_data *s1,*s2; + struct scsi_link *sc_link = xs->sc_link; + struct ahb_softc *ahb = sc_link->adapter_softc; struct ecb *ecb; struct ahb_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; - physaddr thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; - int s; - if(scsi_debug & PRINTROUTINES) - printf("ahb_scsi_cmd "); + int seg; /* scatter gather seg being worked on */ + int thiskv; + physaddr thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + int s; + + SC_DEBUG(sc_link, SDEV_DB2, ("ahb_scsi_cmd\n")); /* * get a ecb (mbox-out) to use. If the transfer * is from a buf (possibly from interrupt time) * then we can't allow it to sleep */ flags = xs->flags; - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if(flags & ITSDONE) { - printf("Already done?"); + if (xs->bp) + flags |= SCSI_NOSLEEP; /* just to be sure */ + if (flags & ITSDONE) { + printf("%s: already done?", ahb->sc_dev.dv_xname); xs->flags &= ~ITSDONE; } - if( !(flags & INUSE) ) { - printf("Not in use?"); + if (!(flags & INUSE)) { + printf("%s: not in use?", ahb->sc_dev.dv_xname); xs->flags |= INUSE; } - if (!(ecb = ahb_get_ecb(unit,flags))) { + if (!(ecb = ahb_get_ecb(ahb, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return TRY_AGAIN_LATER; } - -cheat = ecb; - - if(ahb_debug & AHB_SHOWECBS) - printf("",ecb); - if(scsi_debug & SHOWCOMMANDS) - ahb_show_scsi_cmd(xs); - + cheat = ecb; + SC_DEBUG(sc_link, SDEV_DB3, ("start ecb(%x)\n", ecb)); ecb->xs = xs; + /* * If it's a reset, we need to do an 'immediate' - * command, and store it's ccb for later + * command, and store it's ecb for later * if there is already an immediate waiting, * then WE must wait */ - if(flags & SCSI_RESET) { + if (flags & SCSI_RESET) { ecb->flags |= ECB_IMMED; - if(ahb_data[unit].immed_ecb) - return(TRY_AGAIN_LATER); - - ahb_data[unit].immed_ecb = ecb; + if (ahb->immed_ecb) + return TRY_AGAIN_LATER; + ahb->immed_ecb = ecb; if (!(flags & SCSI_NOMASK)) { s = splbio(); - ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); - ahb_add_timeout(ecb,xs->timeout); + ahb_send_immed(ahb, sc_link->target, AHB_TARG_RESET); + timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000); splx(s); - return(SUCCESSFULLY_QUEUED); + return SUCCESSFULLY_QUEUED; } else { - ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); + ahb_send_immed(ahb, sc_link->target, AHB_TARG_RESET); /* - * If we can't use interrupts, poll on completion* + * If we can't use interrupts, poll on completion */ - if(scsi_debug & TRACEINTERRUPTS) - printf("wait "); - if( ahb_poll(unit,xs->timeout)) { - ahb_free_ecb(unit,ecb,flags); + SC_DEBUG(sc_link, SDEV_DB3, ("wait\n")); + if (ahb_poll(ahb, xs->timeout)) { + ahb_free_ecb(ahb, ecb, flags); xs->error = XS_TIMEOUT; - return(HAD_ERROR); + return HAD_ERROR; } - return(COMPLETE); + return COMPLETE; } } /* * Put all the arguments for the xfer in the ecb */ ecb->opcode = ECB_SCSI_OP; - ecb->opt1 = ECB_SES|ECB_DSB|ECB_ARS; - if(xs->datalen) + ecb->opt1 = ECB_SES | ECB_DSB | ECB_ARS; + if (xs->datalen) ecb->opt1 |= ECB_S_G; - ecb->opt2 = xs->lu | ECB_NRB; - ecb->cdblen = xs->cmdlen; - ecb->sense = KVTOPHYS(&(ecb->ecb_sense)); - ecb->senselen = sizeof(ecb->ecb_sense); - ecb->status = KVTOPHYS(&(ecb->ecb_status)); + ecb->opt2 = sc_link->lun | ECB_NRB; + ecb->cdblen = xs->cmdlen; + ecb->sense = KVTOPHYS(&ecb->ecb_sense); + ecb->senselen = sizeof(ecb->ecb_sense); + ecb->status = KVTOPHYS(&ecb->ecb_status); - if(xs->datalen) { - /* should use S/G only if not zero length */ - ecb->data = KVTOPHYS(ecb->ahb_dma); - sg = ecb->ahb_dma ; - seg = 0; - if(flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; + if (xs->datalen) { /* should use S/G only if not zero length */ + ecb->data = KVTOPHYS(ecb->ahb_dma); + sg = ecb->ahb_dma; + seg = 0; + +#ifdef TFS + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while ((datalen) && (seg < AHB_NSEG)) { - sg->addr = (physaddr)iovp->iov_base; + while (datalen && seg < AHB_NSEG) { + sg->addr = (physaddr) iovp->iov_base; xs->datalen += sg->len = iovp->iov_len; - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)", iovp->iov_len, - iovp->iov_base); + SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } else { - /* Set up the scatter gather block */ + } + else +#endif /*TFS */ + { + /* + * Set up the scatter gather block + */ + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + datalen = xs->datalen; + thiskv = (int) xs->data; + thisphys = KVTOPHYS(thiskv); - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ", xs->datalen, xs->data); - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - - while ((datalen) && (seg < AHB_NSEG)) { - bytes_this_seg = 0; + while (datalen && seg < AHB_NSEG) { + bytes_this_seg = 0; /* put in the base address */ sg->addr = thisphys; - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); + SC_DEBUGN(sc_link, SDEV_DB4, + ("0x%x", thisphys)); /* do it at least once */ nextphys = thisphys; while ((datalen) && (thisphys == nextphys)) { - /* - * This page is contiguous (physically) with * - * the the last, just extend the length * - */ - nextphys= (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = min(nextphys - thisphys, - datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; + /* + * This page is contiguous (physically) + * with the the last, just extend the + * length + */ + /* how far to the end of the page */ + nextphys = (thisphys & ~PGOFSET) + NBPG; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page, + datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + thiskv = (thiskv & ~PGOFSET) + NBPG; + if (datalen) thisphys = KVTOPHYS(thiskv); } /* - * next page isn't contiguous, finish the seg * + * next page isn't contiguous, finish the seg */ - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); + SC_DEBUGN(sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); sg->len = bytes_this_seg; sg++; seg++; } } - ecb->datalen = seg * sizeof(struct ahb_dma_seg); - if(scsi_debug & SHOWSCATGATH) - printf("\n"); - if (datalen) { - /* there's still data, must have run out of segs! */ - printf("ahb_scsi_cmd%d: more than %d DMA segs\n", - unit, AHB_NSEG); - xs->error = XS_DRIVER_STUFFUP; - ahb_free_ecb(unit,ecb,flags); - return(HAD_ERROR); - } - } else { - /* No data xfer, use non S/G values */ - ecb->data = (physaddr)0; + /*end of iov/kv decision */ + ecb->datalen = seg * sizeof(struct ahb_dma_seg); + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); + + if (datalen) { + /* + * there's still data, must have run out of segs! + */ + printf("%s: ahb_scsi_cmd, more than %d DMA segs\n", + ahb->sc_dev.dv_xname, AHB_NSEG); + xs->error = XS_DRIVER_STUFFUP; + ahb_free_ecb(ahb, ecb, flags); + return HAD_ERROR; + } + } else { /* No data xfer, use non S/G values */ + ecb->data = (physaddr) 0; ecb->datalen = 0; } + ecb->chain = (physaddr) 0; - ecb->chain = (physaddr)0; /* * Put the scsi command in the ecb and start it */ bcopy(xs->cmd, ecb->cdb, xs->cmdlen); - /* Usually return SUCCESSFULLY QUEUED */ - if( !(flags & SCSI_NOMASK) ) { + /* + * Usually return SUCCESSFULLY QUEUED + */ + if (!(flags & SCSI_NOMASK)) { s = splbio(); - ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); - ahb_add_timeout(ecb,xs->timeout); + ahb_send_mbox(ahb, OP_START_ECB, sc_link->target, ecb); + timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000); splx(s); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); + return SUCCESSFULLY_QUEUED; } - /* If we can't use interrupts, poll on completion */ - ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_wait "); - + /* + * If we can't use interrupts, poll on completion + */ + ahb_send_mbox(ahb, OP_START_ECB, sc_link->target, ecb); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_wait\n")); do { - if(ahb_poll(unit,xs->timeout)) { - if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); - ahb_send_mbox(unit,OP_ABORT_ECB,xs->targ,ecb); - if(ahb_poll(unit, 2000)) { - printf("abort failed in wait\n"); - ahb_free_ecb(unit,ecb,flags); + if (ahb_poll(ahb, xs->timeout)) { + if (!(xs->flags & SCSI_SILENT)) + printf("%s: cmd fail\n", ahb->sc_dev.dv_xname); + ahb_send_mbox(ahb, OP_ABORT_ECB, sc_link->target, ecb); + if (ahb_poll(ahb, 2000)) { + printf("%s: abort failed in wait\n", + ahb->sc_dev.dv_xname); + ahb_free_ecb(ahb, ecb, flags); } xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); + return HAD_ERROR; } - } while (!(xs->flags & ITSDONE)); - - scsi_debug = 0; - ahb_debug = 0; - if(xs->error) + } while (!(xs->flags & ITSDONE));/* something (?) else finished */ + if (xs->error) return HAD_ERROR; return COMPLETE; } -/* - * +----------+ +----------+ +----------+ - * ahb_soonest--->| later |--->| later|--->| later|--->0 - * | [Delta] | | [Delta] | | [Delta] | - * 0<---|sooner |<---|sooner |<---|sooner |<---ahb_latest - * +----------+ +----------+ +----------+ - * - * ahb_furtherest = sum(Delta[1..n]) - */ void -ahb_add_timeout(struct ecb *ecb, int time) +ahb_timeout(arg) + caddr_t arg; { - int timeprev; - struct ecb *prev; - int s = splbio(); + int s = splbio(); + struct ecb *ecb = (void *)arg; + struct ahb_softc *ahb = ecb->xs->sc_link->adapter_softc; - prev = ahb_latest; - if(prev) - timeprev = ahb_furtherest; - else - timeprev = 0; + sc_print_addr(ecb->xs->sc_link); + printf("timed out "); - while(prev && (timeprev > time)) { - timeprev -= prev->delta; - prev = prev->sooner; +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWECBS) + ahb_print_active_ecb(ahb); +#endif /*AHBDEBUG */ + + /* + * If it's immediate, don't try abort it + */ + if (ecb->flags & ECB_IMMED) { + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->flags |= ECB_IMMED_FAIL; + ahb_done(ahb, ecb, 1); + splx(s); + return; } - if(prev) { - ecb->delta = time - timeprev; - ecb->later = prev->later; - if(ecb->later) { - ecb->later->sooner = ecb; - ecb->later->delta -= ecb->delta; - } else { - ahb_furtherest = time; - ahb_latest = ecb; - } - ecb->sooner = prev; - prev->later = ecb; - } - else - { - ecb->later = ahb_soonest; - if(ahb_soonest) { - ecb->later->sooner = ecb; - ecb->later->delta -= time; - } else { - ahb_furtherest = time; - ahb_latest = ecb; - } - ecb->delta = time; - ecb->sooner = (struct ecb *)0; - ahb_soonest = ecb; + + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (ecb->flags == ECB_ABORTED) { + printf("AGAIN\n"); + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST; + ahb_done(ahb, ecb, 1); + } else { /* abort the operation that has timed out */ + printf("\n"); + ahb_send_mbox(ahb, OP_ABORT_ECB, ecb->xs->sc_link->target, ecb); + timeout(ahb_timeout, (caddr_t)ecb, 2 * hz); + ecb->flags = ECB_ABORTED; } splx(s); } +#ifdef AHBDEBUG void -ahb_remove_timeout(struct ecb *ecb) +ahb_print_ecb(ecb) + struct ecb *ecb; { - int s = splbio(); - - if(ecb->sooner) - ecb->sooner->later = ecb->later; - else - ahb_soonest = ecb->later; - - if(ecb->later) { - ecb->later->sooner = ecb->sooner; - ecb->later->delta += ecb->delta; - } else { - ahb_latest = ecb->sooner; - ahb_furtherest -= ecb->delta; - } - ecb->sooner = ecb->later = (struct ecb *)0; - splx(s); + printf("ecb:%x op:%x cmdlen:%d senlen:%d\n", + ecb, ecb->opcode, ecb->cdblen, ecb->senselen); + printf(" datlen:%d hstat:%x tstat:%x flags:%x\n", + ecb->datalen, ecb->ecb_status.ha_status, + ecb->ecb_status.targ_status, ecb->flags); + show_scsi_cmd(ecb->xs); } - -extern int hz; -#define ONETICK 500 /* milliseconds */ -#define SLEEPTIME ((hz * 1000) / ONETICK) - void -ahb_timeout(int arg) +ahb_print_active_ecb(ahb) + struct ahb_softc *ahb; { struct ecb *ecb; - int unit; - int s = splbio(); - - while( ecb = ahb_soonest ) { - if(ecb->delta <= ONETICK) { - /* It has timed out, we need to do some work */ - unit = ecb->xs->adapter; - printf("ahb%d targ %d: device timed out\n", unit, - ecb->xs->targ); - if(ahb_debug & AHB_SHOWECBS) - ahb_print_active_ecb(); - - /* Unlink it from the queue */ - ahb_remove_timeout(ecb); - - /* - * If it's immediate, don't try abort it * - */ - if(ecb->flags & ECB_IMMED) { - ecb->xs->retries = 0; /* I MEAN IT ! */ - ecb->flags |= ECB_IMMED_FAIL; - ahb_done(unit,ecb,FAIL); - continue; - } - - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if(ecb->flags == ECB_ABORTED) { - printf("AGAIN"); - ecb->xs->retries = 0; /* I MEAN IT ! */ - ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST; - ahb_done(unit,ecb,FAIL); - } else { - printf("\n"); - ahb_send_mbox(unit,OP_ABORT_ECB,ecb->xs->targ,ecb); - /* 2 secs for the abort */ - ahb_add_timeout(ecb,2000 + ONETICK); - ecb->flags = ECB_ABORTED; - } - } else { - ecb->delta -= ONETICK; - ahb_furtherest -= ONETICK; - break; - } - } - splx(s); - timeout((timeout_t)ahb_timeout,(caddr_t)arg,SLEEPTIME); -} - -void -ahb_show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *)xs->cmd; int i = 0; - if( !(xs->flags & SCSI_RESET) ) { - printf("ahb%d targ %d lun %d:", xs->adapter, - xs->targ, xs->lu); - while(i < xs->cmdlen ) { - if(i) - printf(","); - printf("%x", b[i++]); + while (i++ < ECB_HASH_SIZE) { + ecb = ahb->ecbhash[i]; + while (ecb) { + if (ecb->flags != ECB_FREE) + ahb_print_ecb(ecb); + ecb = ecb->nexthash; } - printf("\n"); - } else { - printf("ahb%d targ %d lun%d: RESET\n", xs->adapter, - xs->targ, xs->lu); } } - -void -ahb_print_ecb(struct ecb *ecb) -{ - printf("ecb:%x op:%x cmdlen:%d senlen:%d\n", ecb, ecb->opcode, - ecb->cdblen, ecb->senselen); - printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n", - ecb->datalen, ecb->ecb_status.ha_status, - ecb->ecb_status.targ_status, ecb->delta, ecb->flags); - ahb_show_scsi_cmd(ecb->xs); -} - -void -ahb_print_active_ecb(void) -{ - struct ecb *ecb; - ecb = ahb_soonest; - - while(ecb) { - ahb_print_ecb(ecb); - ecb = ecb->later; - } - printf("Furtherest = %d\n", ahb_furtherest); -} +#endif /* AHBDEBUG */ diff --git a/sys/arch/i386/isa/aha1542.c b/sys/arch/i386/isa/aha1542.c index 41da1a396f65..7a371f9fc22c 100644 --- a/sys/arch/i386/isa/aha1542.c +++ b/sys/arch/i386/isa/aha1542.c @@ -1,5 +1,36 @@ /* - * (Mostly) Written by Julian Elischer (julian@tfs.com) + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: aha1542.c,v 1.24 1994/03/29 04:30:15 mycroft Exp $ + */ + +/* + * Originally written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -11,81 +42,58 @@ * TFS supplies this software to be publicly redistributed * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. - * - * $Id: aha1542.c,v 1.23 1994/03/25 07:40:50 mycroft Exp $ */ /* - * a FEW lines in this driver come from a MACH adaptec-disk driver - * so the copyright below is included: - * - * Copyright 1990 by Open Software Foundation, - * Grenoble, FRANCE - * - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation, and that the name of OSF or Open Software - * Foundation not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 */ -#include "aha.h" - #include #include #include +#include #include #include +#include +#include #include #include #include -#include -#include -#include -#include #include +#include +#include #include #include -#include - - -#ifdef DDB +#ifdef DDB int Debugger(); -#else DDB +#else /* NDDB */ #define Debugger() panic("should call debugger here (adaptec.c)") -#endif DDB +#endif /* NDDB */ -extern int delaycount; /* from clock setup code */ +/************************** board definitions *******************************/ -/* I/O Port Interface */ -#define AHA_BASE aha_base[unit] +/* + * I/O Port Interface + */ +#define AHA_BASE aha->aha_base #define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */ #define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */ #define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */ -/* AHA_CTRL_STAT bits (write) */ +/* + * AHA_CTRL_STAT bits (write) + */ #define AHA_HRST 0x80 /* Hardware reset */ #define AHA_SRST 0x40 /* Software reset */ #define AHA_IRST 0x20 /* Interrupt reset */ #define AHA_SCRST 0x10 /* SCSI bus reset */ -/* AHA_CTRL_STAT bits (read) */ +/* + * AHA_CTRL_STAT bits (read) + */ #define AHA_STST 0x80 /* Self test in Progress */ #define AHA_DIAGF 0x40 /* Diagnostic Failure */ #define AHA_INIT 0x20 /* Mbx Init required */ @@ -94,7 +102,9 @@ extern int delaycount; /* from clock setup code */ #define AHA_DF 0x04 /* Data in port full */ #define AHA_INVDCMD 0x01 /* Invalid command */ -/* AHA_CMD_DATA bits (write) */ +/* + * AHA_CMD_DATA bits (write) + */ #define AHA_NOP 0x00 /* No operation */ #define AHA_MBX_INIT 0x01 /* Mbx initialization */ #define AHA_START_SCSI 0x02 /* start scsi command */ @@ -114,95 +124,99 @@ extern int delaycount; /* from clock setup code */ #define AHA_WRITE_FIFO 0x1c /* write fifo buffer */ #define AHA_READ_FIFO 0x1d /* read fifo buffer */ #define AHA_ECHO 0x1e /* Echo command data */ +#define AHA_EXT_BIOS 0x28 /* return extended bios info */ +#define AHA_MBX_ENABLE 0x29 /* enable mail box interface */ struct aha_cmd_buf { - u_char byte[16]; + u_char byte[16]; }; -/* AHA_INTR_PORT bits (read) */ +/* + * AHA_INTR_PORT bits (read) + */ #define AHA_ANY_INTR 0x80 /* Any interrupt */ #define AHA_SCRD 0x08 /* SCSI reset detected */ #define AHA_HACC 0x04 /* Command complete */ #define AHA_MBOA 0x02 /* MBX out empty */ #define AHA_MBIF 0x01 /* MBX in full */ -/* Mail box defs */ +/* + * Mail box defs + */ #define AHA_MBX_SIZE 16 /* mail box size */ struct aha_mbx { struct aha_mbx_out { - unsigned char cmd; - unsigned char ccb_addr[3]; + u_char cmd; + u_char ccb_addr[3]; } mbo[AHA_MBX_SIZE]; - struct aha_mbx_in{ - unsigned char stat; - unsigned char ccb_addr[3]; + struct aha_mbx_in { + u_char stat; + u_char ccb_addr[3]; } mbi[AHA_MBX_SIZE]; }; -/* mbo.cmd values */ +/* + * mbo.cmd values + */ #define AHA_MBO_FREE 0x0 /* MBO entry is free */ #define AHA_MBO_START 0x1 /* MBO activate entry */ #define AHA_MBO_ABORT 0x2 /* MBO abort entry */ +/* + * mbi.stat values + */ #define AHA_MBI_FREE 0x0 /* MBI entry is free */ #define AHA_MBI_OK 0x1 /* completed without error */ #define AHA_MBI_ABORT 0x2 /* aborted ccb */ #define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ #define AHA_MBI_ERROR 0x4 /* Completed with error */ -extern struct aha_mbx aha_mbx[]; - /* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */ -/* Number of scatter gather segments <= 16, allow 64 K i/o (min) */ -#define AHA_NSEG 17 +#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */ + /* allow 64 K i/o (min) */ struct aha_ccb { - unsigned char opcode; - unsigned char lun:3; - unsigned char data_in:1; /* must be 0 */ - unsigned char data_out:1; /* must be 0 */ - unsigned char target:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; - unsigned char data_length[3]; - unsigned char data_addr[3]; - unsigned char link_addr[3]; - unsigned char link_id; - unsigned char host_stat; - unsigned char target_stat; - unsigned char reserved[2]; - struct scsi_generic scsi_cmd; - struct scsi_sense_data scsi_sense; - struct aha_scat_gath { - unsigned char seg_len[3]; - unsigned char seg_addr[3]; + u_char opcode; + u_char lun:3; + u_char data_in:1; /* must be 0 */ + u_char data_out:1; /* must be 0 */ + u_char target:3; + u_char scsi_cmd_length; + u_char req_sense_length; + u_char data_length[3]; + u_char data_addr[3]; + u_char link_addr[3]; + u_char link_id; + u_char host_stat; + u_char target_stat; + u_char reserved[2]; + struct scsi_generic scsi_cmd; + struct scsi_sense_data scsi_sense; + struct aha_scat_gath { + u_char seg_len[3]; + u_char seg_addr[3]; } scat_gath[AHA_NSEG]; - struct aha_ccb *next; - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ - struct aha_mbx_out *mbx; /* pointer to mail box */ - long int delta; /* difference from previous*/ - struct aha_ccb *later,*sooner; - int flags; + struct aha_ccb *next; + struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ + struct aha_mbx_out *mbx; /* pointer to mail box */ + int flags; +#define CCB_FREE 0 +#define CCB_ACTIVE 1 +#define CCB_ABORTED 2 }; -/* flags value? */ -#define CCB_FREE 0 -#define CCB_ACTIVE 1 -#define CCB_ABORTED 2 - -struct aha_ccb *aha_soonest = (struct aha_ccb *)0; -struct aha_ccb *aha_latest = (struct aha_ccb *)0; -long int aha_furtherest = 0; /* longest time in the timeout queue */ - -/* opcode fields */ +/* + * opcode fields + */ #define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ #define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */ -#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather*/ +#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */ #define AHA_RESET_CCB 0x81 /* SCSI Bus reset */ - -/* aha_ccb.host_stat values */ +/* + * aha_ccb.host_stat values + */ #define AHA_OK 0x00 /* cmd ok */ #define AHA_LINK_OK 0x0a /* Link cmd ok */ #define AHA_LINK_IT 0x0b /* Link cmd ok + int */ @@ -216,30 +230,52 @@ long int aha_furtherest = 0; /* longest time in the timeout queue */ #define AHA_INV_TARGET 0x18 /* Invalid target direction */ #define AHA_CCB_DUP 0x19 /* Duplicate CCB received */ #define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */ -#define AHA_ABORTED 42 +#define AHA_ABORTED 42 struct aha_setup { - u_char sync_neg:1; - u_char parity:1; - u_char :6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; + u_char sync_neg:1; + u_char parity:1; + u_char:6; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[3]; struct { - u_char offset:4; - u_char period:3; - u_char valid:1; + u_char offset:4; + u_char period:3; + u_char valid:1; } sync[8]; - u_char disc_sts; + u_char disc_sts; }; -struct aha_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char :5; +struct aha_config { + u_char chan; + u_char intr; + u_char scsi_dev:3; + u_char:5; +}; + +struct aha_inquire { + u_char boardid; /* type of board */ + /* 0x20 = BusLogic 545, but it gets + the command wrong, only returns + one byte */ + /* 0x31 = AHA-1540 */ + /* 0x41 = AHA-1540A/1542A/1542B */ + /* 0x42 = AHA-1640 */ + /* 0x43 = AHA-1542C */ + /* 0x44 = AHA-1542CF */ + /* 0x45 = AHA-1542CF, BIOS v2.01 */ + u_char spec_opts; /* special options ID */ + /* 0x41 = Board is standard model */ + u_char revision_1; /* firmware revision [0-9A-Z] */ + u_char revision_2; /* firmware revision [0-9A-Z] */ +}; + +struct aha_extbios { + u_char flags; /* Bit 3 == 1 extended bios enabled */ + u_char mailboxlock; /* mail box lock code to unlock it */ }; #define INT9 0x01 @@ -254,30 +290,80 @@ struct aha_config { #define CHAN6 0x40 #define CHAN7 0x80 +/*********************************** end of board definitions***************/ - -#define PHYSTOKV(x) ((x) + KERNBASE) +#define PHYSTOKV(x) (((long int)(x)) ^ aha->kv_phys_xor) #define KVTOPHYS(x) vtophys(x) -#define AHA_DMA_PAGES AHA_NSEG -#define PAGESIZ 4096 -#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } +u_char aha_scratch_buf[256]; +#ifdef AHADEBUG +int aha_debug = 1; +#endif /*AHADEBUG */ -struct scsi_xfer aha_scsi_xfer[NAHA]; -struct isa_device *ahainfo[NAHA]; -struct aha_mbx aha_mbx[NAHA]; -struct aha_ccb *aha_ccb_free[NAHA]; -struct aha_ccb aha_ccb[NAHA][AHA_MBX_SIZE]; -struct aha_ccb *aha_get_ccb(); -u_char aha_scratch_buf[256]; -short aha_base[NAHA]; /* base port for each board */ -int speed[NAHA]; -int aha_int[NAHA]; -int aha_dma[NAHA]; -int aha_initialized[NAHA]; +struct aha_softc { + struct device sc_dev; + struct isadev sc_id; + struct intrhand sc_ih; -int aha_debug = 0; -static int ahaunit = 0; + u_short aha_base; /* base port for each board */ + /* + * xor this with a physaddr to get a kv addr and visa versa + * for items in THIS STRUCT only. + * Used to get the CCD's physical and kv addresses from each + * other. + */ + long int kv_phys_xor; + struct aha_mbx aha_mbx; /* all the mailboxes */ + struct aha_ccb *aha_ccb_free; /* the next free ccb */ + struct aha_ccb aha_ccb[AHA_MBX_SIZE]; /* all the CCBs */ + int aha_int; /* our irq level */ + int aha_dma; /* out DMA req channel */ + int aha_scsi_dev; /* ourscsi bus address */ + struct scsi_link sc_link; /* prototype for subdevs */ +}; + +int aha_cmd(); /* XXX must be varargs to prototype */ +u_int aha_adapter_info __P((struct aha_softc *)); +int ahaintr __P((int)); +void aha_free_ccb __P((struct aha_softc *, struct aha_ccb *, int)); +struct aha_ccb *aha_get_ccb __P((struct aha_softc *, int)); +void aha_done __P((struct aha_softc *, struct aha_ccb *)); +int aha_find __P((struct aha_softc *)); +void aha_init __P((struct aha_softc *)); +void ahaminphys __P((struct buf *)); +int aha_scsi_cmd __P((struct scsi_xfer *)); +int aha_poll __P((struct aha_softc *, struct scsi_xfer *, struct aha_ccb *)); +int aha_set_bus_speed __P((struct aha_softc *)); +int aha_bus_speed_check __P((struct aha_softc *, int)); +void aha_timeout __P((caddr_t)); + +struct scsi_adapter aha_switch = { + aha_scsi_cmd, + ahaminphys, + 0, + 0, + aha_adapter_info, + "aha" +}; + +/* the below structure is so we have a default dev struct for out link struct */ +struct scsi_device aha_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "aha", + 0 +}; + +int ahaprobe(); +void ahaattach(); + +struct cfdriver ahacd = { + NULL, "aha", ahaprobe, ahaattach, DV_DULL, sizeof(struct aha_softc) +}; + +void aha_init __P((struct aha_softc *)); #define aha_abortmbx(mbx) \ (mbx)->cmd = AHA_MBO_ABORT; \ @@ -286,154 +372,132 @@ static int ahaunit = 0; (mbx)->cmd = AHA_MBO_START; \ outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); -#define AHA_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */ -#define AHA_RESET_TIMEOUT 1000000 /* time to wait for reset */ -#define AHA_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */ - - -int aha_cmd(int, int, int, int, u_char *, ...); -int ahaprobe(struct isa_device *); -int ahaattach(struct isa_device *); -long int aha_adapter_info(int); -int ahaintr(int); -void aha_free_ccb(int, struct aha_ccb *, int); -struct aha_ccb * aha_get_ccb(int, int); -int aha_done(int, struct aha_ccb *); -int aha_init(int); -void ahaminphys(struct buf *); -int aha_scsi_cmd(struct scsi_xfer *); -int aha_set_bus_speed(int); -int aha_bus_speed_check(int, int); -void aha_add_timeout(struct aha_ccb *, int); -void aha_remove_timeout(struct aha_ccb *); -void aha_timeout(int); - - -struct isa_driver ahadriver = { - ahaprobe, - ahaattach, - "aha" -}; - -struct scsi_switch aha_switch[NAHA]; +#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */ /* - * aha_cmd(unit, icnt, ocnt,wait, retval, ...) + * aha_cmd(aha,icnt, ocnt,wait, retval, opcode, args) * Activate Adapter command - * icnt: number of args (outbound bytes written after opcode) - * ocnt: number of expected returned bytes - * wait: number of seconds to wait for response - * retval: buffer where to place returned bytes - * ...: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI & parameters + * icnt: number of args (outbound bytes written after opcode) + * ocnt: number of expected returned bytes + * wait: number of seconds to wait for response + * retval: buffer where to place returned bytes + * opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ... + * args: parameters * * Performs an adapter command through the ports. Not to be confused - * with a scsi command, which is read in via the dma - * One of the adapter commands tells it to read in a scsi command + * with a scsi command, which is read in via the dma. One of the adapter + * commands tells it to read in a scsi command but that one is done + * separately. This is only called during set-up. */ int -aha_cmd(int unit, int icnt, int ocnt, int wait, u_char *retval, ...) +aha_cmd(aha, icnt, ocnt, wait, retval, opcode, args) + struct aha_softc *aha; + int icnt, ocnt, wait; + u_char *retval; + unsigned opcode; + u_char args; { - va_list ap; - int opc, sts; + unsigned *ic = &opcode; u_char oc; register i; - - va_start(ap, retval); - opc = (u_char)va_arg(ap, int); - /*printf("command: %08x %02x\n", opc, (u_char)opc);*/ + int sts; /* * multiply the wait argument by a big constant - * zero defaults to 1 + * zero defaults to 1 sec.. + * all wait loops are in 50uSec cycles */ - if(!wait) - wait = AHA_CMD_TIMEOUT_FUDGE * delaycount; + if (wait) + wait *= 20000; else - wait *= AHA_CMD_TIMEOUT_FUDGE * delaycount; + wait = 20000; /* * Wait for the adapter to go idle, unless it's one of * the commands which don't need this */ - if (opc != AHA_MBX_INIT && opc != AHA_START_SCSI) { - i = AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/ + if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) { + i = 20000; /*do this for upto about a second */ while (--i) { sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_IDLE) + if (sts & AHA_IDLE) { break; + } + delay(50); } if (!i) { - printf("aha_cmd: aha1542 host not idle(0x%x)\n", sts); - return(ENXIO); + printf("%s: aha_cmd, host not idle(0x%x)\n", + aha->sc_dev.dv_xname, sts); + return ENXIO; } } /* - * Now that it is idle, if we expect output, preflush the* + * Now that it is idle, if we expect output, preflush the * queue feeding to us. */ if (ocnt) { - while((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) + while ((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) inb(AHA_CMD_DATA_PORT); } - /* * Output the command and the number of arguments given * for each byte, first check the port is empty. */ - icnt++; /* include the command */ + icnt++; + /* include the command */ while (icnt--) { sts = inb(AHA_CTRL_STAT_PORT); - for (i=0; i< wait; i++) { + for (i = wait; i; i--) { sts = inb(AHA_CTRL_STAT_PORT); if (!(sts & AHA_CDF)) break; + delay(50); } - if (i >= wait) { - printf("aha_cmd: aha1542 cmd/data port full\n"); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return(ENXIO); - } - outb(AHA_CMD_DATA_PORT, (u_char)opc); - if(icnt) { - opc = (u_char)va_arg(ap, int); - /*printf("extra: %08x %02x\n", opc, (u_char)opc);*/ + if (!i) { + printf("%s: aha_cmd, cmd/data port full\n", + aha->sc_dev.dv_xname); + outb(AHA_CTRL_STAT_PORT, AHA_SRST); + return ENXIO; } + outb(AHA_CMD_DATA_PORT, (u_char) (*ic++)); } - va_end(ap); - /* * If we expect input, loop that many times, each time, * looking for the data register to have valid data */ while (ocnt--) { sts = inb(AHA_CTRL_STAT_PORT); - for (i=0; i< wait; i++) { + for (i = wait; i; i--) { sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_DF) + if (sts & AHA_DF) break; + delay(50); } - if (i >= wait) { - printf("aha_cmd: aha1542 cmd/data port empty %d\n",ocnt); - return(ENXIO); + if (!i) { + printf("%s: aha_cmd, cmd/data port empty %d\n", + aha->sc_dev.dv_xname, ocnt); + return ENXIO; } oc = inb(AHA_CMD_DATA_PORT); if (retval) - *retval++ = oc; + *retval++ = oc; } /* * Wait for the board to report a finised instruction */ - i=AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ + i = 20000; while (--i) { sts = inb(AHA_INTR_PORT); if (sts & AHA_HACC) break; + delay(50); } if (!i) { - printf("aha_cmd: aha1542 host not finished(0x%x)\n",sts); - return(ENXIO); + printf("%s: aha_cmd, host not finished(0x%x)\n", + aha->sc_dev.dv_xname, sts); + return ENXIO; } outb(AHA_CTRL_STAT_PORT, AHA_IRST); - return(0); + return 0; } /* @@ -443,165 +507,208 @@ aha_cmd(int unit, int icnt, int ocnt, int wait, u_char *retval, ...) * autoconf.c */ int -ahaprobe(struct isa_device *dev) +ahaprobe(parent, self, aux) + struct device *parent, *self; + void *aux; { - int unit; + struct aha_softc *aha = (void *)self; + struct isa_attach_args *ia = aux; - if (dev->id_parent) - return 1; +#ifdef NEWCONFIG + if (ia->ia_iobase == IOBASEUNK) + return 0; +#endif - dev->id_unit = unit = ahaunit; - aha_base[unit] = dev->id_iobase; - if(unit >= NAHA) { - printf("aha: unit number (%d) too high\n",unit); - return(0); - } + aha->aha_base = ia->ia_iobase; /* * Try initialise a unit at this location - * sets up dma and bus speed, loads aha_int[unit] + * sets up dma and bus speed, loads aha->aha_int */ - if (aha_init(unit) != 0) - return(0); + if (aha_find(aha) != 0) + return 0; /* - * If it's there, put in it's interrupt vectors + * Calculate the xor product of the aha struct's + * physical and virtual address. This allows us + * to change addresses within the structure + * from physical to virtual easily, as long as + * the structure is less than 1 page in size. + * This is used to recognise CCBs which are in + * this struct and which are refered to by the + * hardware using physical addresses. + * (assumes malloc returns a chunk that doesn't + * span pages) + * eventually use the hash table in aha1742.c */ - dev->id_irq = (1 << aha_int[unit]); - dev->id_drq = aha_dma[unit]; - ahaunit++; - return(8); + aha->kv_phys_xor = (long int) aha ^ (KVTOPHYS(aha)); + +#ifdef NEWCONFIG + /* + * If it's there, put in it's interrupt vectors and dma channel + */ + if (ia->ia_irq == IRQUNK) { + ia->ia_irq = (1 << aha->aha_int); + } else { + if (ia->ia_irq != (1 << aha->aha_int)) { + printf("aha%d: irq mismatch, %x != %x\n", + aha->sc_dev.dv_unit, ia->ia_irq, + 1 << aha->aha_int); + return 0; + } + } + + if (ia->ia_drq == DRQUNK) { + ia->ia_drq = aha->aha_dma; + } else { + if (ia->ia_drq != aha->aha_dma) { + printf("aha%d: drq mismatch, %x != %x\n", + aha->sc_dev.dv_unit, ia->ia_drq, aha->aha_dma); + return 0; + } + } +#endif + + ia->ia_msize = 0; + ia->ia_iosize = 4; + return 1; +} + +ahaprint() +{ + } /* * Attach all the sub-devices we can find */ -int -ahaattach(struct isa_device *dev) +void +ahaattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - static int firsttime; - static int firstswitch[NAHA]; - static u_long speedprint; /* max 32 aha controllers */ - int masunit; - int r; + struct isa_attach_args *ia = aux; + struct aha_softc *aha = (void *)self; - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; + aha_init(aha); - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - aha_switch[masunit].name = "aha"; - aha_switch[masunit].scsi_cmd = aha_scsi_cmd; - aha_switch[masunit].scsi_minphys = ahaminphys; - aha_switch[masunit].open_target_lu = 0; - aha_switch[masunit].close_target_lu = 0; - aha_switch[masunit].adapter_info = aha_adapter_info; - for (r = 0; r < 8; r++) { - aha_switch[masunit].empty[r] = 0; - aha_switch[masunit].used[r] = 0; - aha_switch[masunit].printed[r] = 0; - } - } - if(!(speedprint & (1<sc_link.adapter_softc = aha; + aha->sc_link.adapter_targ = aha->aha_scsi_dev; + aha->sc_link.adapter = &aha_switch; + aha->sc_link.device = &aha_dev; - r = scsi_attach(masunit, &aha_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); + printf("\n"); - /* only one for all boards */ - if(firsttime==0) { - firsttime = 1; - aha_timeout(0); - } - return r; +#ifdef NEWCONFIG + isa_establish(&aha->sc_id, &aha->sc_dev); + aha->sc_ih.ih_fun = ahaintr; + aha->sc_ih.ih_arg = aha; + /* XXX and DV_TAPE, but either gives us splbio */ + intr_establish(ia->ia_irq, &aha->sc_ih, DV_DISK); +#endif + + /* + * ask the adapter what subunits are present + */ + config_found(self, &aha->sc_link, ahaprint); } - /* - * Return some information to the caller about - * the adapter and it's capabilities + * Return some information to the caller about the adapter and its + * capabilities. */ -long int -aha_adapter_info(int unit) +u_int +aha_adapter_info(aha) + struct aha_softc *aha; { - return(2); /* 2 outstanding requests at a time per device */ + + return 2; /* 2 outstanding requests at a time per device */ } /* * Catch an interrupt from the adaptor */ int -ahaintr(int unit) +ahaintr(unit) + int unit; { + struct aha_softc *aha = ahacd.cd_devs[unit]; struct aha_ccb *ccb; - unsigned char stat; + u_char stat; register i; - if(scsi_debug & PRINTROUTINES) - printf("ahaintr "); +#ifdef AHADEBUG + printf("ahaintr "); +#endif /*AHADEBUG */ /* - * First acknowlege the interrupt, Then if it's - * not telling about a completed operation - * just return. + * First acknowlege the interrupt, Then if it's not telling about + * a completed operation just return. */ stat = inb(AHA_INTR_PORT); outb(AHA_CTRL_STAT_PORT, AHA_IRST); - if(scsi_debug & TRACEINTERRUPTS) - printf("int "); - if (! (stat & AHA_MBIF)) - return(1); - if(scsi_debug & TRACEINTERRUPTS) - printf("b "); - + if (!(stat & AHA_MBIF)) + return 1; +#ifdef AHADEBUG + printf("mbxin "); +#endif /*AHADEBUG */ /* * If it IS then process the competed operation */ for (i = 0; i < AHA_MBX_SIZE; i++) { - if (aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE) { - ccb = (struct aha_ccb *)PHYSTOKV( - (_3btol(aha_mbx[unit].mbi[i].ccb_addr))); - if((stat = aha_mbx[unit].mbi[i].stat) != AHA_MBI_OK) { - switch(stat) { + if (aha->aha_mbx.mbi[i].stat != AHA_MBI_FREE) { + ccb = (struct aha_ccb *) PHYSTOKV( + (_3btol(aha->aha_mbx.mbi[i].ccb_addr))); + + if ((stat = aha->aha_mbx.mbi[i].stat) != AHA_MBI_OK) { + switch (stat) { case AHA_MBI_ABORT: - if(aha_debug) - printf("abort"); +#ifdef AHADEBUG + if (aha_debug) + printf("abort"); +#endif /*AHADEBUG */ ccb->host_stat = AHA_ABORTED; break; + case AHA_MBI_UNKNOWN: - ccb = (struct aha_ccb *)0; - if(aha_debug) - printf("unknown ccb for abort "); + ccb = (struct aha_ccb *) 0; +#ifdef AHADEBUG + if (aha_debug) + printf("unknown ccb for abort "); +#endif /*AHADEBUG */ /* may have missed it */ /* no such ccb known for abort */ - break; + case AHA_MBI_ERROR: break; + default: panic("Impossible mbxi status"); + } - if( aha_debug && ccb ) { - u_char *cp; - cp = (u_char *)(&(ccb->scsi_cmd)); - printf("op=%x %x %x %x %x %x\n", +#ifdef AHADEBUG + if (aha_debug && ccb) { + u_char *cp; + cp = (u_char *) (&(ccb->scsi_cmd)); + printf("op=%x %x %x %x %x %x\n", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); - printf("stat %x for mbi[%d]\n" - , aha_mbx[unit].mbi[i].stat, i); + printf("stat %x for mbi[%d]\n", + aha->aha_mbx.mbi[i].stat, i); printf("addr = 0x%x\n", ccb); } +#endif /*AHADEBUG */ } - if(ccb) { - aha_remove_timeout(ccb); - aha_done(unit,ccb); + if (ccb) { + untimeout(aha_timeout, (caddr_t)ccb); + aha_done(aha, ccb); } - aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE; + aha->aha_mbx.mbi[i].stat = AHA_MBI_FREE; } } - return(1); + return 1; } /* @@ -609,29 +716,27 @@ ahaintr(int unit) * free list. */ void -aha_free_ccb(int unit, struct aha_ccb *ccb, int flags) +aha_free_ccb(aha, ccb, flags) + struct aha_softc *aha; + struct aha_ccb *ccb; + int flags; { - unsigned int opri; + int opri; - if(scsi_debug & PRINTROUTINES) - printf("ccb%d(0x%x)> ",unit,flags); - if (!(flags & SCSI_NOMASK)) - opri = splbio(); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); - ccb->next = aha_ccb_free[unit]; - aha_ccb_free[unit] = ccb; + ccb->next = aha->aha_ccb_free; + aha->aha_ccb_free = ccb; ccb->flags = CCB_FREE; - if(ccb->sooner || ccb->later) { - printf("yikes, still in timeout queue\n"); - aha_remove_timeout(ccb); - } /* - * If there were none, wake abybody waiting for - * one to come free, starting with queued entries* + * If there were none, wake anybody waiting for one to come free, + * starting with queued entries. */ if (!ccb->next) - wakeup( (caddr_t)&aha_ccb_free[unit]); - if (!(flags & SCSI_NOMASK)) + wakeup((caddr_t)&aha->aha_ccb_free); + + if (!(flags & SCSI_NOMASK)) splx(opri); } @@ -639,344 +744,387 @@ aha_free_ccb(int unit, struct aha_ccb *ccb, int flags) * Get a free ccb (and hence mbox-out entry) */ struct aha_ccb * -aha_get_ccb(int unit, int flags) +aha_get_ccb(aha, flags) + struct aha_softc *aha; + int flags; { - unsigned opri; + int opri; struct aha_ccb *rc; - if(scsi_debug & PRINTROUTINES) - printf("aha_ccb_free)) && (!(flags & SCSI_NOSLEEP))) + tsleep((caddr_t)&aha->aha_ccb_free, PRIBIO, "ahaccb", 0); if (rc) { - aha_ccb_free[unit] = aha_ccb_free[unit]->next; + aha->aha_ccb_free = aha->aha_ccb_free->next; rc->flags = CCB_ACTIVE; } - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); - return(rc); + return rc; } - /* * We have a ccb which has been processed by the * adaptor, now we look to see how the operation * went. Wake up the owner if waiting */ -int -aha_done(int unit, struct aha_ccb *ccb) +void +aha_done(aha, ccb) + struct aha_softc *aha; + struct aha_ccb *ccb; { - struct scsi_sense_data *s1,*s2; - struct scsi_xfer *xs = ccb->xfer; + struct scsi_sense_data *s1, *s2; + struct scsi_xfer *xs = ccb->xfer; - if(scsi_debug & PRINTROUTINES ) - printf("aha_done "); + SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n")); /* * Otherwise, put the results of the operation * into the xfer and call whoever started it */ - if(!(xs->flags & INUSE)) { - printf("exiting but not in use! "); + if (!(xs->flags & INUSE)) { + printf("%s: exiting but not in use!\n", aha->sc_dev.dv_xname); Debugger(); } if ((ccb->host_stat != AHA_OK || ccb->target_stat != SCSI_OK) && (!(xs->flags & SCSI_ERR_OK))) { - s1 = (struct scsi_sense_data *)(((char *)(&ccb->scsi_cmd)) - + ccb->scsi_cmd_length); + /* + * We have an error, that we cannot ignore. + */ + s1 = (struct scsi_sense_data *) (((char *) (&ccb->scsi_cmd)) + + ccb->scsi_cmd_length); s2 = &(xs->sense); - if(ccb->host_stat) { - switch(ccb->host_stat) { + if (ccb->host_stat) { + SC_DEBUG(xs->sc_link, SDEV_DB3, ("host err 0x%x\n", + ccb->host_stat)); + switch (ccb->host_stat) { case AHA_ABORTED: case AHA_SEL_TIMEOUT: /* No response */ xs->error = XS_TIMEOUT; break; default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; - if (aha_debug > 1) - printf("host_stat%x\n", ccb->host_stat); + printf("%s: host_stat %x\n", + aha->sc_dev.dv_xname, ccb->host_stat); } - } else { - switch(ccb->target_stat) { + SC_DEBUG(xs->sc_link, SDEV_DB3, ("target err 0x%x\n", + ccb->target_stat)); + switch (ccb->target_stat) { case 0x02: - /* structure copy!!!!!*/ - *s2=*s1; + /* structure copy!!!!! */ + *s2 = *s1; xs->error = XS_SENSE; break; case 0x08: xs->error = XS_BUSY; break; default: - if (aha_debug > 1) - printf("target_stat%x\n", ccb->target_stat); + printf("%s: target_stat %x\n", + aha->sc_dev.dv_xname, ccb->target_stat); xs->error = XS_DRIVER_STUFFUP; } } - } else + } else { + /* All went correctly OR errors expected */ xs->resid = 0; - + } xs->flags |= ITSDONE; - aha_free_ccb(unit,ccb, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + aha_free_ccb(aha, ccb, xs->flags); + scsi_done(xs); } - /* - * Start the board, ready for normal operation + * Find the board and find its irq/drq */ int -aha_init(int unit) +aha_find(aha) + struct aha_softc *aha; { + u_char ad[3]; + volatile int i, sts; struct aha_config conf; - unsigned char ad[3]; - volatile int i,sts; + struct aha_inquire inquire; + struct aha_extbios extbios; /* - * reset board, If it doesn't respond, assume + * reset board, If it doesn't respond, assume * that it's not there.. good for the probe */ - outb(AHA_CTRL_STAT_PORT, AHA_HRST|AHA_SRST); + outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST); - for (i=0; i < AHA_RESET_TIMEOUT; i++) { - sts = inb(AHA_CTRL_STAT_PORT) ; - if(sts == (AHA_IDLE | AHA_INIT)) + for (i = AHA_RESET_TIMEOUT; i; i--) { + sts = inb(AHA_CTRL_STAT_PORT); + if (sts == (AHA_IDLE | AHA_INIT)) break; + delay(1000); /* calibrated in msec */ } - - if (i >= AHA_RESET_TIMEOUT) { + if (!i) { +#ifdef AHADEBUG if (aha_debug) - printf("aha_init: No answer from adaptec board\n"); - return(ENXIO); + printf("aha_find: No answer from adaptec board\n"); +#endif /*AHADEBUG */ + return ENXIO; } /* - * Assume we have a board at this stage - * setup dma channel from jumpers and save int level + * Assume we have a board at this stage, do an adapter inquire + * to find out what type of controller it is */ - delay(1000); - aha_cmd(unit, 0, sizeof(conf), 0, (u_char *)&conf, AHA_CONF_GET); - switch(conf.chan) { + aha_cmd(aha, 0, sizeof(inquire), 1 ,&inquire, AHA_INQUIRE); +#ifdef AHADEBUG + printf("%s: inquire %x, %x, %x, %x\n", + aha->sc_dev.dv_xname, + inquire.boardid, inquire.spec_opts, + inquire.revision_1, inquire.revision_2); +#endif /* AHADEBUG */ + /* + * XXX The Buslogic 545S gets the AHA_INQUIRE command wrong, + * they only return one byte which causes us to print an error, + * so if the boardid comes back as 0x20, tell the user why they + * get the "cmd/data port empty" message + */ + if (inquire.boardid == 0x20) { + /* looks like a Buslogic 545 */ + printf("%s: above cmd/data port empty due to Buslogic 545\n", + aha->sc_dev.dv_xname); + } + /* + * If we are a 1542C or 1542CF disable the extended bios so that the + * mailbox interface is unlocked. + * No need to check the extended bios flags as some of the + * extensions that cause us problems are not flagged in that byte. + */ + if (inquire.boardid == 0x43 || inquire.boardid == 0x44 || + inquire.boardid == 0x45) { + aha_cmd(aha, 0, sizeof(extbios), 0, &extbios, AHA_EXT_BIOS); +#ifdef AHADEBUG + printf("%s: extended bios flags %x\n", aha->sc_dev.dv_xname, + extbios.flags); +#endif /* AHADEBUG */ + printf("%s: 1542C/CF detected, unlocking mailbox\n", + aha->sc_dev.dv_xname); + aha_cmd(aha, 2, 0, 0, 0, AHA_MBX_ENABLE, + 0, extbios.mailboxlock); + } + + /* + * setup dma channel from jumpers and save int + * level + */ + delay(1000); /* for Bustek 545 */ + aha_cmd(aha, 0, sizeof(conf), 0, &conf, AHA_CONF_GET); + switch (conf.chan) { case CHAN0: outb(0x0b, 0x0c); outb(0x0a, 0x00); - aha_dma[unit] = 0; + aha->aha_dma = 0; break; case CHAN5: outb(0xd6, 0xc1); outb(0xd4, 0x01); - aha_dma[unit] = 5; + aha->aha_dma = 5; break; case CHAN6: outb(0xd6, 0xc2); outb(0xd4, 0x02); - aha_dma[unit] = 6; + aha->aha_dma = 6; break; case CHAN7: outb(0xd6, 0xc3); outb(0xd4, 0x03); - aha_dma[unit] = 7; + aha->aha_dma = 7; break; default: - printf("illegal dma jumper setting\n"); - return(EIO); + printf("illegal dma setting %x\n", conf.chan); + return EIO; } - switch(conf.intr) { + switch (conf.intr) { case INT9: - aha_int[unit] = 9; + aha->aha_int = 9; break; case INT10: - aha_int[unit] = 10; + aha->aha_int = 10; break; case INT11: - aha_int[unit] = 11; + aha->aha_int = 11; break; case INT12: - aha_int[unit] = 12; + aha->aha_int = 12; break; case INT14: - aha_int[unit] = 14; + aha->aha_int = 14; break; case INT15: - aha_int[unit] = 15; + aha->aha_int = 15; break; default: - printf("illegal int jumper setting\n"); - return(EIO); + printf("illegal int setting %x\n", conf.intr); + return EIO; } - /* who are we on the scsi bus */ - aha_switch[unit].scsi_dev = conf.scsi_dev; + /* who are we on the scsi bus? */ + aha->aha_scsi_dev = conf.scsi_dev; + /* + * Change the bus on/off times to not clash with other dma users. + */ + aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7); + aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4); + +#ifdef TUNE_1542 /* * Initialize memory transfer speed + * Not compiled in by default because it breaks some machines */ - speed[unit] = aha_set_bus_speed(unit); - if(speed[unit] == 0) { - printf("aha%d found, but unable to talk to it correctly\n"); - return(EIO); - } + if (!(aha_set_bus_speed(aha))) + return EIO; +#endif /*TUNE_1542*/ + + return 0; +} + +/* + * Start the board, ready for normal operation + */ +void +aha_init(aha) + struct aha_softc *aha; +{ + u_char ad[4]; + volatile int i; /* - * Initialize bus-on time - * - * The default is 11ms, which can result in the fd driver becoming - * starved for data during simultaneous fd & scsi transfers. We - * set it to 9ms - if this still gives you trouble, set to 6 (ms) - * and work your way up. + * Initialize mail box */ - aha_cmd(unit,1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 9); - - /* - * Initialize mail box - */ - lto3b(KVTOPHYS(&aha_mbx[unit]), ad); - - aha_cmd(unit, 4, 0, 0, (u_char *)0, AHA_MBX_INIT, AHA_MBX_SIZE, - ad[0], ad[1], ad[2]); + lto3b(KVTOPHYS(&aha->aha_mbx), ad); + aha_cmd(aha, 4, 0, 0, 0, AHA_MBX_INIT, + AHA_MBX_SIZE, ad[0], ad[1], ad[2]); /* * link the ccb's with the mbox-out entries and * into a free-list + * this is a kludge but it works */ - for (i=0; i < AHA_MBX_SIZE; i++) { - aha_ccb[unit][i].next = aha_ccb_free[unit]; - aha_ccb_free[unit] = &aha_ccb[unit][i]; - aha_ccb_free[unit]->flags = CCB_FREE; - aha_ccb_free[unit]->mbx = &aha_mbx[unit].mbo[i]; - lto3b(KVTOPHYS(aha_ccb_free[unit]), aha_mbx[unit].mbo[i].ccb_addr); + for (i = 0; i < AHA_MBX_SIZE; i++) { + aha->aha_ccb[i].next = aha->aha_ccb_free; + aha->aha_ccb_free = &aha->aha_ccb[i]; + aha->aha_ccb_free->flags = CCB_FREE; + aha->aha_ccb_free->mbx = &aha->aha_mbx.mbo[i]; + lto3b(KVTOPHYS(aha->aha_ccb_free), aha->aha_mbx.mbo[i].ccb_addr); } +} - /* - * Note that we are going and return (to probe) - */ - aha_initialized[unit]++; - return(0); +void +ahaminphys(bp) + struct buf *bp; +{ + +/* aha seems to explode with 17 segs (64k may require 17 segs) */ +/* on old boards so use a max of 16 segs if you have problems here */ + if (bp->b_bcount > ((AHA_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((AHA_NSEG - 1) << PGSHIFT); } /* - * aha seems to explode with 17 segs (64k may require 17 segs) - * on old boards so use a max of 16 segs if you have problems - * here + * start a scsi operation given the command and the data address. Also needs + * the unit, target and lu. */ -void -ahaminphys(struct buf *bp) +int +aha_scsi_cmd(xs) + struct scsi_xfer *xs; { - if(bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ)) - bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ); -} - -/* - * start a scsi operation given the command and - * the data address. Also needs the unit, target - * and lu - */ -int -aha_scsi_cmd(struct scsi_xfer *xs) -{ - struct scsi_sense_data *s1,*s2; + struct scsi_link *sc_link = xs->sc_link; + struct aha_softc *aha = sc_link->adapter_softc; struct aha_ccb *ccb; struct aha_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; - int thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; - int s; + int seg; /* scatter gather seg being worked on */ + int thiskv; + int thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + struct iovec *iovp; + int s; - if(scsi_debug & PRINTROUTINES) - printf("aha_scsi_cmd "); + SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n")); /* * get a ccb (mbox-out) to use. If the transfer * is from a buf (possibly from interrupt time) * then we can't allow it to sleep */ flags = xs->flags; - if(!(flags & INUSE)) { - printf("not in use!"); - Debugger(); - xs->flags |= INUSE; - } - if(flags & ITSDONE) { - printf("Already done! check device retry code "); - Debugger(); - xs->flags &= ~ITSDONE; - } - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if (!(ccb = aha_get_ccb(unit,flags))) { + if (!(ccb = aha_get_ccb(aha, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return TRY_AGAIN_LATER; } - if (ccb->mbx->cmd != AHA_MBO_FREE) - printf("MBO not free\n"); + printf("%s: MBO not free\n", aha->sc_dev.dv_xname); /* * Put all the arguments for the xfer in the ccb - * (can't use S/G if zero length) */ ccb->xfer = xs; - if(flags & SCSI_RESET) + if (flags & SCSI_RESET) { ccb->opcode = AHA_RESET_CCB; - else - ccb->opcode = (xs->datalen ? AHA_INIT_SCAT_GATH_CCB : AHA_INITIATOR_CCB); - ccb->target = xs->targ;; + } else { + /* can't use S/G if zero length */ + ccb->opcode = (xs->datalen ? AHA_INIT_SCAT_GATH_CCB + : AHA_INITIATOR_CCB); + } + ccb->target = sc_link->target; ccb->data_out = 0; ccb->data_in = 0; - ccb->lun = xs->lu; + ccb->lun = sc_link->lun; ccb->scsi_cmd_length = xs->cmdlen; ccb->req_sense_length = sizeof(ccb->scsi_sense); - /* can use S/G only if not zero length */ - if((xs->datalen) && (!(flags & SCSI_RESET))) { + if ((xs->datalen) && (!(flags & SCSI_RESET))) { + /* can use S/G only if not zero length */ lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr); sg = ccb->scat_gath; seg = 0; - if(flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; +#ifdef TFS_ONLY + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; while ((datalen) && (seg < AHA_NSEG)) { - lto3b((u_long)iovp->iov_base, (u_char *)&sg->seg_addr); - lto3b(iovp->iov_len, (u_char *)&sg->seg_len); - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)", iovp->iov_len, - iovp->iov_base); + lto3b(iovp->iov_base, sg->seg_addr); + lto3b(iovp->iov_len, sg->seg_len); + SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } else { + } else +#endif /*TFS_ONLY */ + { /* * Set up the scatter gather block */ - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ", xs->datalen, xs->data); + + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); datalen = xs->datalen; - thiskv = (int)xs->data; + thiskv = (int) xs->data; thisphys = KVTOPHYS(thiskv); while ((datalen) && (seg < AHA_NSEG)) { - bytes_this_seg = 0; + bytes_this_seg = 0; /* put in the base address */ - lto3b(thisphys, (u_char *)&(sg->seg_addr)); + lto3b(thisphys, sg->seg_addr); - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); + SC_DEBUGN(sc_link, SDEV_DB4, + ("0x%x", thisphys)); /* do it at least once */ nextphys = thisphys; @@ -986,399 +1134,312 @@ aha_scsi_cmd(struct scsi_xfer *xs) * with the the last, just extend the * length */ - /* how far to the end of the page? */ - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = - min(nextphys - thisphys, datalen); + /* check it fits on the ISA bus */ + if (thisphys > 0xFFFFFF) { + printf("%s: DMA beyond" + " end of ISA\n", + aha->sc_dev.dv_xname); + xs->error = XS_DRIVER_STUFFUP; + aha_free_ccb(aha, ccb, flags); + return HAD_ERROR; + } + /** how far to the end of the page ***/ + nextphys = (thisphys & ~PGOFSET) + NBPG; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page, + datalen); bytes_this_seg += bytes_this_page; datalen -= bytes_this_page; - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + /* get more ready for the next page */ + thiskv = (thiskv & ~PGOFSET) + NBPG; + if (datalen) thisphys = KVTOPHYS(thiskv); } /* * next page isn't contiguous, finish the seg */ - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); - lto3b(bytes_this_seg, (u_char *)&(sg->seg_len)); + SC_DEBUGN(sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); + lto3b(bytes_this_seg, sg->seg_len); sg++; seg++; } } lto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length); - if(scsi_debug & SHOWSCATGATH) - printf("\n"); + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); + if (datalen) { - /* there's still data, must have run out of segs! */ - printf("aha_scsi_cmd%d: needed more than %d DMA segs, %d\n", - unit, AHA_NSEG, datalen); + /* + * there's still data, must have run out of segs! + */ + printf("%s: aha_scsi_cmd, more than %d DMA segs\n", + aha->sc_dev.dv_xname, AHA_NSEG); xs->error = XS_DRIVER_STUFFUP; - aha_free_ccb(unit, ccb, flags); - return(HAD_ERROR); + aha_free_ccb(aha, ccb, flags); + return HAD_ERROR; } - } else { /* No data xfer, use non S/G values */ - lto3b(0, ccb->data_addr ); + } else { /* No data xfer, use non S/G values */ + lto3b(0, ccb->data_addr); lto3b(0, ccb->data_length); } lto3b(0, ccb->link_addr); + /* * Put the scsi command in the ccb and start it */ - if(!(flags & SCSI_RESET)) + if (!(flags & SCSI_RESET)) bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length); - if(scsi_debug & SHOWCOMMANDS) - { - u_char *b = (u_char *)&ccb->scsi_cmd; - if(!(flags & SCSI_RESET)) - { - int i = 0; - printf("aha%d:%d:%d-" - ,unit - ,ccb->target - ,ccb->lun ); - while(i < ccb->scsi_cmd_length ) - { - if(i) printf(","); - printf("%x",b[i++]); - } - } - else - { - printf("aha%d:%d:%d-RESET- " - ,unit - ,ccb->target - ,ccb->lun - ); - } - } - if (!(flags & SCSI_NOMASK)) - { - s= splbio(); /* stop instant timeouts */ - aha_add_timeout(ccb,xs->timeout); + if (!(flags & SCSI_NOMASK)) { + s = splbio(); /* stop instant timeouts */ + timeout(aha_timeout, (caddr_t)ccb, (xs->timeout * hz) / 1000); aha_startmbx(ccb->mbx); /* * Usually return SUCCESSFULLY QUEUED */ splx(s); - if(scsi_debug & TRACEINTERRUPTS) - printf("sent "); - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(sc_link, SDEV_DB3, ("sent\n")); + return SUCCESSFULLY_QUEUED; } aha_startmbx(ccb->mbx); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent, waiting "); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd sent, waiting\n")); + /* - * If we can't use interrupts, poll on completion* + * If we can't use interrupts, poll on completion */ - { - int done = 0; - int count = delaycount * xs->timeout / AHA_SCSI_TIMEOUT_FUDGE; - while((!done) && count) - { - i=0; - while ( (!done) && iflags & SCSI_SILENT)) - printf("cmd fail\n"); - aha_abortmbx(ccb->mbx); - count = delaycount * 2000 / AHA_SCSI_TIMEOUT_FUDGE; - while((!done) && count) { - i=0; - while ( (!done) && imbx->cmd = AHA_MBO_FREE; - } - aha_free_ccb(unit,ccb,flags); - ahaintr(unit); - xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); - } - ahaintr(unit); - if(xs->error) return(HAD_ERROR); - return(COMPLETE); - } - /* return ??? */ + return aha_poll(aha, xs, ccb); /* only during boot */ } /* - * try each speed in turn, when we find one that works, use - * the NEXT one for a safety margin, unless that doesn't exist - * or doesn't work. returns the nsec value of the time used - * or 0 if it could get a working speed ( or the NEXT speed - * failed) - * Go one slower to be safe, unless eisa at 100 ns.. trust it + * Poll a particular unit, looking for a particular xs */ -int -aha_set_bus_speed(int unit) +int +aha_poll(aha, xs, ccb) + struct aha_softc *aha; + struct scsi_xfer *xs; + struct aha_ccb *ccb; { - int retval, retval2; - int speed; + int done = 0; + int count = xs->timeout; + u_char stat; -#ifdef EISA - speed = 0; /* start at the fastest */ -#else EISA - speed = 1; /* 100 ns can crash some ISA busses (!?!) */ -#endif EISA - while (1) { - retval = aha_bus_speed_check(unit, speed); - if(retval == HAD_ERROR) { - printf("no working bus speed!!!\n"); - return 0; + /* timeouts are in msec, so we loop in 1000 usec cycles */ + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + stat = inb(AHA_INTR_PORT); + if (stat & AHA_ANY_INTR) + ahaintr(aha->sc_dev.dv_unit); + if (xs->flags & ITSDONE) + break; + delay(1000); /* only happens in boot so ok */ + count--; + } + if (!count) { + /* + * We timed out, so call the timeout handler manually, + * accounting for the fact that the clock is not running yet + * by taking out the clock queue entry it makes. + */ + aha_timeout((caddr_t)ccb); + + /* + * because we are polling, take out the timeout entry + * aha_timeout made + */ + untimeout(aha_timeout, (caddr_t)ccb); + count = 2000; + while (count) { + /* + * Once again, wait for the int bit + */ + stat = inb(AHA_INTR_PORT); + if (stat & AHA_ANY_INTR) + ahaintr(aha->sc_dev.dv_unit); + if (xs->flags & ITSDONE) + break; + delay(1000); /* only happens in boot so ok */ + count--; } + if (!count) { + /* + * We timed out again.. this is bad + * Notice that this time there is no + * clock queue entry to remove + */ + aha_timeout((caddr_t)ccb); + } + } + if (xs->error) + return HAD_ERROR; + return COMPLETE; - if(retval == 0) - speed++; - else { - if(speed != 0) - speed++; +} - /*printf("%d nsec ok, but using ", retval);*/ - retval2 = aha_bus_speed_check(unit, speed); - if(retval2 == HAD_ERROR) { - /*printf("marginal ");*/ - retval2 = retval; - } - if(retval2) { - /*printf("%d nsec\n", retval2);*/ - return retval2; - } else { - /*printf(".. slower failed, abort.\n", retval);*/ +#ifdef TUNE_1542 +/* + * Try all the speeds from slowest to fastest.. if it finds a + * speed that fails, back off one notch from the last working + * speed (unless there is no other notch). + * Returns the nSEC value of the time used + * or 0 if it could get a working speed (or the NEXT speed + * failed) + */ +static struct bus_speed +{ + char arg; + int nsecs; +} aha_bus_speeds[] = +{ + {0x88,100}, + {0x99,150}, + {0xaa,200}, + {0xbb,250}, + {0xcc,300}, + {0xdd,350}, + {0xee,400}, + {0xff,450} +}; + +int +aha_set_bus_speed(aha) + struct aha_softc *aha; +{ + int speed; + int lastworking; + int retval,retval2; + + lastworking = -1; + speed = 7; + while (1) { + retval = aha_bus_speed_check(aha, speed); + if (retval != 0) + lastworking = speed; + if ((retval == 0) || (speed == 0)) { + if (lastworking == -1) { + printf("No working bus speed for aha154X\n"); return 0; } + printf("%d nSEC ok, using " + ,aha_bus_speeds[lastworking].nsecs); + if (lastworking == 7) /* is slowest already */ + printf("marginal "); + else + lastworking++; + retval2 = aha_bus_speed_check(aha, lastworking); + if (retval2 == 0) { + printf("test retry failed.. aborting.\n"); + return 0; + } + printf("%d nSEC\n",retval2); + return retval2 ; + } + speed--; } } /* * Set the DMA speed to the Nth speed and try an xfer. If it - * fails return 0, if it succeeds return the nsec value selected + * fails return 0, if it succeeds return the nSec value selected * If there is no such speed return HAD_ERROR. */ -static struct bus_speed { - char arg; - int nsecs; -} aha_bus_speeds[] = { - {0x88, 100}, - {0x99, 150}, - {0xaa, 200}, - {0xbb, 250}, - {0xcc, 300}, - {0xdd, 350}, - {0xee, 400}, - {0xff, 450} -}; -static char aha_test_string[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; +static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; -int -aha_bus_speed_check(int unit, int speed) +int +aha_bus_speed_check(aha, speed) + struct aha_softc *aha; + int speed; { - int numspeeds = sizeof(aha_bus_speeds)/sizeof(struct bus_speed); - u_char ad[3]; + int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed); + int loopcount; + u_char ad[3]; /* * Check we have such an entry */ - if(speed >= numspeeds) return(HAD_ERROR); /* illegal speed */ + if (speed >= numspeeds) + return HAD_ERROR; /* illegal speed */ /* * Set the dma-speed */ - aha_cmd(unit,1, 0, 0, (u_char *)0, AHA_SPEED_SET,aha_bus_speeds[speed].arg); + aha_cmd(aha, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg); /* * put the test data into the buffer and calculate * it's address. Read it onto the board */ - strcpy((char *)aha_scratch_buf, (char *)aha_test_string); lto3b(KVTOPHYS(aha_scratch_buf), ad); + for (loopcount = 2000; loopcount; loopcount--) { + strcpy(aha_scratch_buf, aha_test_string); - aha_cmd(unit,3, 0, 0, (u_char *)0, AHA_WRITE_FIFO, - ad[0], ad[1], ad[2]); + aha_cmd(aha, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]); + + /* + * clear the buffer then copy the contents back from the + * board. + */ + bzero(aha_scratch_buf, 54); /* 54 bytes transfered by test */ + + aha_cmd(aha, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]); + + /* + * Compare the original data and the final data and + * return the correct value depending upon the result + */ + if (strcmp(aha_test_string, aha_scratch_buf)) + return 0; /* failed test */ + } + /* copy succeded assume speed ok */ + + return aha_bus_speeds[speed].nsecs; + +} +#endif /*TUNE_1542*/ + +void +aha_timeout(arg) + caddr_t arg; +{ + int s = splbio(); + struct aha_ccb *ccb = (void *)arg; + struct aha_softc *aha; + + aha = ccb->xfer->sc_link->adapter_softc; + sc_print_addr(ccb->xfer->sc_link); + printf("timed out "); /* - * clear the buffer then copy the contents back from the - * board. + * If The ccb's mbx is not free, then + * the board has gone south */ - bzero(aha_scratch_buf,54); /* 54 bytes transfered by test */ - - aha_cmd(unit,3, 0, 0, (u_char *)0, AHA_READ_FIFO, - ad[0], ad[1], ad[2]); + if (ccb->mbx->cmd != AHA_MBO_FREE) { + printf("\nadapter not taking commands.. frozen?!\n"); + Debugger(); + } /* - * Compare the original data and the final data and - * return the correct value depending upon the result - * if copy fails.. assume too fast + * If it has been through before, then + * a previous abort has failed, don't + * try abort again */ - if(strcmp(aha_test_string, (char *)aha_scratch_buf)) - return(0); - return(aha_bus_speeds[speed].nsecs); -} - - -/* - * +----------+ +----------+ +----------+ - * aha_soonest--->| later |--->| later|--->| later|-->0 - * | [Delta] | | [Delta] | | [Delta] | - * 0<---|sooner |<---|sooner |<---|sooner |<---aha_latest - * +----------+ +----------+ +----------+ - * - * aha_furtherest = sum(Delta[1..n]) - */ -void -aha_add_timeout(struct aha_ccb *ccb, int time) -{ - int timeprev; - struct aha_ccb *prev; - int s = splbio(); - - if(prev = aha_latest) /* yes, an assign */ - timeprev = aha_furtherest; - else - timeprev = 0; - - while(prev && (timeprev > time)) { - timeprev -= prev->delta; - prev = prev->sooner; - } - if(prev) { - ccb->delta = time - timeprev; - if( ccb->later = prev->later) { - ccb->later->sooner = ccb; - ccb->later->delta -= ccb->delta; - } else { - aha_furtherest = time; - aha_latest = ccb; - } - ccb->sooner = prev; - prev->later = ccb; + if (ccb->flags == CCB_ABORTED) { + /* abort timed out */ + printf("AGAIN\n"); + ccb->xfer->retries = 0; /* I MEAN IT ! */ + ccb->host_stat = AHA_ABORTED; + aha_done(aha, ccb); } else { - if( ccb->later = aha_soonest) { - ccb->later->sooner = ccb; - ccb->later->delta -= time; - } else { - aha_furtherest = time; - aha_latest = ccb; - } - ccb->delta = time; - ccb->sooner = (struct aha_ccb *)0; - aha_soonest = ccb; + /* abort the operation that has timed out */ + printf("\n"); + aha_abortmbx(ccb->mbx); + /* 4 secs for the abort */ + timeout(aha_timeout, (caddr_t)ccb, 2 * hz); + ccb->flags = CCB_ABORTED; } splx(s); } - -void -aha_remove_timeout(struct aha_ccb *ccb) -{ - int s = splbio(); - - if(ccb->sooner) - ccb->sooner->later = ccb->later; - else - aha_soonest = ccb->later; - - if(ccb->later) { - ccb->later->sooner = ccb->sooner; - ccb->later->delta += ccb->delta; - } else { - aha_latest = ccb->sooner; - aha_furtherest -= ccb->delta; - } - ccb->sooner = ccb->later = (struct aha_ccb *)0; - splx(s); -} - -extern int hz; -#define ONETICK 500 /* milliseconds */ -#define SLEEPTIME ((hz * 1000) / ONETICK) - -void -aha_timeout(int arg) -{ - struct aha_ccb *ccb; - int unit; - int s = splbio(); - - while( ccb = aha_soonest ) { - if(ccb->delta <= ONETICK) { - /* - * It has timed out, we need to do some work - */ - unit = ccb->xfer->adapter; - printf("aha%d: device %d timed out ", unit, - ccb->xfer->targ); - - /* - * Unlink it from the queue - */ - aha_remove_timeout(ccb); - - /* - * If The ccb's mbx is not free, then - * the board has gone south - */ - if(ccb->mbx->cmd != AHA_MBO_FREE) { - printf("aha%d not taking commands!\n", unit); - Debugger(); - } - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if(ccb->flags == CCB_ABORTED) { - /* abort timed out */ - printf(" AGAIN\n"); - ccb->xfer->retries = 0; /* I MEAN IT ! */ - ccb->host_stat = AHA_ABORTED; - aha_done(unit,ccb); - } else { - /* abort the operation that has timed out */ - printf("\n"); - aha_abortmbx(ccb->mbx); - /* 2 secs for the abort */ - aha_add_timeout(ccb,2000 + ONETICK); - ccb->flags = CCB_ABORTED; - } - } else { - /* - * It has not timed out, adjust and leave - */ - ccb->delta -= ONETICK; - aha_furtherest -= ONETICK; - break; - } - } - splx(s); - timeout((timeout_t)aha_timeout, (caddr_t)arg, SLEEPTIME); -} diff --git a/sys/arch/i386/isa/aha1742.c b/sys/arch/i386/isa/aha1742.c index 09e02ae74ad9..6da708734d8b 100644 --- a/sys/arch/i386/isa/aha1742.c +++ b/sys/arch/i386/isa/aha1742.c @@ -1,5 +1,36 @@ /* - * Written by Julian Elischer (julian@tfs.com) + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: aha1742.c,v 1.23 1994/03/29 04:30:18 mycroft Exp $ + */ + +/* + * Originally written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -12,63 +43,66 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * $Id: aha1742.c,v 1.22 1994/03/25 07:40:53 mycroft Exp $ + * commenced: Sun Sep 27 18:14:01 PDT 1992 */ -#include "ahb.h" - #include #include #include +#include #include #include +#include +#include #include #include #include -#include -#include -#include #include +#include +#include #include #include -#include - - #ifdef DDB -int Debugger(); -#else DDB -#define Debugger() panic("should call debugger here (adaptec.c)") -#endif DDB +int Debugger(); +#else /* DDB */ +#define Debugger() +#endif /* DDB */ -typedef unsigned long int physaddr; +typedef u_long physaddr; -#define PHYSTOKV(x) ((x) + KERNBASE) -#define KVTOPHYS(x) vtophys(x) +#define KVTOPHYS(x) vtophys(x) -extern int delaycount; /* from clock setup code */ -#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ -#define AHB_NSEG 33 /* number of dma segments supported */ -#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ +#define AHB_ECB_MAX 32 /* store up to 32ECBs at any one time */ + /* in aha1742 H/W ( Not MAX ? ) */ +#define ECB_HASH_SIZE 32 /* when we have a physical addr. for */ + /* a ecb and need to find the ecb in */ + /* space, look it up in the hash table */ +#define ECB_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define ECB_HASH(x) ((((long int)(x))>>ECB_HASH_SHIFT) % ECB_HASH_SIZE) +#define AHB_NSEG 33 /* number of dma segments supported */ /* * AHA1740 standard EISA Host ID regs (Offset from slot base) */ -#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ -#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ -#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ -#define HID3 0xC83 /* firmware revision */ +#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ +#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ +#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ +#define HID3 0xC83 /* firmware revision */ #define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@') #define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@') #define CHAR3(B1,B2) ((B2 & 0x1F) | '@') -/* AHA1740 EISA board control registers (Offset from slot base) */ +/* + * AHA1740 EISA board control registers (Offset from slot base) + */ #define EBCTRL 0xC84 #define CDEN 0x01 + /* * AHA1740 EISA board mode registers (Offset from slot base) */ @@ -81,24 +115,21 @@ extern int delaycount; /* from clock setup code */ #define RESV0 0xCC5 #define RESV1 0xCC6 #define RESV2 0xCC7 - -/* bit definitions for INTDEF */ +/**** bit definitions for INTDEF ****/ #define INT9 0x00 #define INT10 0x01 #define INT11 0x02 #define INT12 0x03 #define INT14 0x05 #define INT15 0x06 -#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ +#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ #define INTEN 0x10 - -/* bit definitions for SCSIDEF */ -#define HSCSIID 0x0F /* our SCSI ID */ -#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ - -/* bit definitions for BUSDEF */ -#define B0uS 0x00 /* give up bus immediatly */ -#define B4uS 0x01 /* delay 4uSec. */ +/**** bit definitions for SCSIDEF ****/ +#define HSCSIID 0x0F /* our SCSI ID */ +#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ +/**** bit definitions for BUSDEF ****/ +#define B0uS 0x00 /* give up bus immediatly */ +#define B4uS 0x01 /* delay 4uSec. */ #define B8uS 0x02 /* @@ -151,225 +182,253 @@ extern int delaycount; /* from clock setup code */ #define G2STAT2_HOST_READY 0x01 - struct ahb_dma_seg { - physaddr addr; - long len; + physaddr addr; + long len; }; struct ahb_ecb_status { - u_short status; -# define ST_DON 0x0001 -# define ST_DU 0x0002 -# define ST_QF 0x0008 -# define ST_SC 0x0010 -# define ST_DO 0x0020 -# define ST_CH 0x0040 -# define ST_INT 0x0080 -# define ST_ASA 0x0100 -# define ST_SNS 0x0200 -# define ST_INI 0x0800 -# define ST_ME 0x1000 -# define ST_ECA 0x4000 - u_char ha_status; -# define HS_OK 0x00 -# define HS_CMD_ABORTED_HOST 0x04 -# define HS_CMD_ABORTED_ADAPTER 0x05 -# define HS_TIMED_OUT 0x11 -# define HS_HARDWARE_ERR 0x20 -# define HS_SCSI_RESET_ADAPTER 0x22 -# define HS_SCSI_RESET_INCOMING 0x23 - u_char targ_status; -# define TS_OK 0x00 -# define TS_CHECK_CONDITION 0x02 -# define TS_BUSY 0x08 - u_long resid_count; - u_long resid_addr; - u_short addit_status; - u_char sense_len; - u_char unused[9]; - u_char cdb[6]; + u_short status; +#define ST_DON 0x0001 +#define ST_DU 0x0002 +#define ST_QF 0x0008 +#define ST_SC 0x0010 +#define ST_DO 0x0020 +#define ST_CH 0x0040 +#define ST_INT 0x0080 +#define ST_ASA 0x0100 +#define ST_SNS 0x0200 +#define ST_INI 0x0800 +#define ST_ME 0x1000 +#define ST_ECA 0x4000 + u_char ha_status; +#define HS_OK 0x00 +#define HS_CMD_ABORTED_HOST 0x04 +#define HS_CMD_ABORTED_ADAPTER 0x05 +#define HS_TIMED_OUT 0x11 +#define HS_HARDWARE_ERR 0x20 +#define HS_SCSI_RESET_ADAPTER 0x22 +#define HS_SCSI_RESET_INCOMING 0x23 + u_char targ_status; +#define TS_OK 0x00 +#define TS_CHECK_CONDITION 0x02 +#define TS_BUSY 0x08 + u_long resid_count; + u_long resid_addr; + u_short addit_status; + u_char sense_len; + u_char unused[9]; + u_char cdb[6]; }; - struct ecb { - u_char opcode; -# define ECB_SCSI_OP 0x01 - u_char :4; - u_char options:3; - u_char :1; - short opt1; -# define ECB_CNE 0x0001 -# define ECB_DI 0x0080 -# define ECB_SES 0x0400 -# define ECB_S_G 0x1000 -# define ECB_DSB 0x4000 -# define ECB_ARS 0x8000 - short opt2; -# define ECB_LUN 0x0007 -# define ECB_TAG 0x0008 -# define ECB_TT 0x0030 -# define ECB_ND 0x0040 -# define ECB_DAT 0x0100 -# define ECB_DIR 0x0200 -# define ECB_ST 0x0400 -# define ECB_CHK 0x0800 -# define ECB_REC 0x4000 -# define ECB_NRB 0x8000 - u_short unused1; - physaddr data; - u_long datalen; - physaddr status; - physaddr chain; - short unused2; - short unused3; - physaddr sense; - u_char senselen; - u_char cdblen; - short cksum; - u_char cdb[12]; + u_char opcode; +#define ECB_SCSI_OP 0x01 + u_char:4; + u_char options:3; + u_char:1; + short opt1; +#define ECB_CNE 0x0001 +#define ECB_DI 0x0080 +#define ECB_SES 0x0400 +#define ECB_S_G 0x1000 +#define ECB_DSB 0x4000 +#define ECB_ARS 0x8000 + short opt2; +#define ECB_LUN 0x0007 +#define ECB_TAG 0x0008 +#define ECB_TT 0x0030 +#define ECB_ND 0x0040 +#define ECB_DAT 0x0100 +#define ECB_DIR 0x0200 +#define ECB_ST 0x0400 +#define ECB_CHK 0x0800 +#define ECB_REC 0x4000 +#define ECB_NRB 0x8000 + u_short unused1; + physaddr data; + u_long datalen; + physaddr status; + physaddr chain; + short unused2; + short unused3; + physaddr sense; + u_char senselen; + u_char cdblen; + short cksum; + u_char cdb[12]; /*-----------------end of hardware supported fields----------------*/ - struct ecb *next; /* in free list */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - long int delta; /* difference from previous*/ - struct ecb *later,*sooner; - int flags; + struct ecb *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + int flags; #define ECB_FREE 0 #define ECB_ACTIVE 1 #define ECB_ABORTED 2 #define ECB_IMMED 4 #define ECB_IMMED_FAIL 8 - struct ahb_dma_seg ahb_dma[AHB_NSEG]; - struct ahb_ecb_status ecb_status; - struct scsi_sense_data ecb_sense; + struct ahb_dma_seg ahb_dma[AHB_NSEG]; + struct ahb_ecb_status ecb_status; + struct scsi_sense_data ecb_sense; + struct ecb *nexthash; + physaddr hashkey; /* physaddr of this struct */ }; -struct ecb *ahb_soonest = (struct ecb *)0; -struct ecb *ahb_latest = (struct ecb *)0; -long int ahb_furtherest = 0; /* longest time in the timeout queue */ +struct ahb_softc { + struct device sc_dev; + struct isadev sc_id; + struct intrhand sc_ih; -struct ahb_data { - int flags; -#define AHB_INIT 0x01; - int baseport; - struct ecb ecbs[NUM_CONCURRENT]; + u_short baseport; + struct ecb *ecbhash[ECB_HASH_SIZE]; struct ecb *free_ecb; - int vect; - struct ecb *immed_ecb; /* an outstanding immediete command */ -} ahb_data[NAHB]; + int our_id; /* our scsi id */ + int vect; + struct ecb *immed_ecb; /* an outstanding immediete command */ + int numecbs; + struct scsi_link sc_link; +}; -struct ecb *cheat; +void ahb_send_mbox __P((struct ahb_softc *, int, int, struct ecb *)); +int ahb_poll __P((struct ahb_softc *, int)); +void ahb_send_immed __P((struct ahb_softc *, int, u_long)); +u_int ahb_adapter_info __P((struct ahb_softc *)); +int ahbintr __P((int)); +void ahb_done __P((struct ahb_softc *, struct ecb *, int)); +void ahb_free_ecb __P((struct ahb_softc *, struct ecb *, int)); +struct ecb *ahb_get_ecb __P((struct ahb_softc *, int)); +struct ecb *ahb_ecb_phys_kv __P((struct ahb_softc *, physaddr)); +int ahb_find __P((struct ahb_softc *)); +void ahb_init __P((struct ahb_softc *)); +void ahbminphys __P((struct buf *)); +int ahb_scsi_cmd __P((struct scsi_xfer *)); +void ahb_timeout __P((caddr_t)); +void ahb_print_ecb __P((struct ecb *)); +void ahb_print_active_ecb __P((struct ahb_softc *)); -#define MAX_SLOTS 8 -static ahb_slot = 0; /* slot last board was found in */ -static ahb_unit = 0; -int ahb_debug = 0; +struct ecb *cheat; + +#define MAX_SLOTS 15 +static ahb_slot = 0; /* slot last board was found in */ +int ahb_debug = 0; #define AHB_SHOWECBS 0x01 #define AHB_SHOWINTS 0x02 #define AHB_SHOWCMDS 0x04 #define AHB_SHOWMISC 0x08 -#define FAIL 1 -#define SUCCESS 0 -#define PAGESIZ 4096 - -int ahbprobe(struct isa_device *); -int ahbprobe1(struct isa_device *); -int ahb_attach(struct isa_device *); -long int ahb_adapter_info(int); -int ahbintr(int); -void ahb_done(int, struct ecb *, int); -void ahb_free_ecb(int, struct ecb *, int); -struct ecb * ahb_get_ecb(int, int); -int ahb_init(int); -void ahbminphys(struct buf *); -int ahb_scsi_cmd(struct scsi_xfer *); -void ahb_add_timeout(struct ecb *, int); -void ahb_remove_timeout(struct ecb *); -void ahb_timeout(int); -void ahb_show_scsi_cmd(struct scsi_xfer *); -void ahb_print_ecb(struct ecb *); -void ahb_print_active_ecb(void); - - -struct isa_driver ahbdriver = { - ahbprobe, - ahb_attach, +struct scsi_adapter ahb_switch = { + ahb_scsi_cmd, + ahbminphys, + 0, + 0, + ahb_adapter_info, "ahb" }; -struct scsi_switch ahb_switch[NAHB]; +/* the below structure is so we have a default dev struct for our link struct */ +struct scsi_device ahb_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "ahb", + 0 +}; + +int ahbprobe(); +int ahbprobe1 __P((struct ahb_softc *, struct isa_attach_args *)); +void ahbattach(); + +struct cfdriver ahbcd = { + NULL, "ahb", ahbprobe, ahbattach, DV_DULL, sizeof(struct ahb_softc) +}; /* * Function to send a command out through a mailbox */ void -ahb_send_mbox(int unit, int opcode, int target, struct ecb *ecb) +ahb_send_mbox(ahb, opcode, target, ecb) + struct ahb_softc *ahb; + int opcode, target; + struct ecb *ecb; { - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ - int stport = port + G2STAT, s; + u_short port = ahb->baseport; + u_short stport = port + G2STAT; + int wait = 100; /* 1ms should be enough */ + int s = splbio(); - s = splbio(); - while( ((inb(stport) & - (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) != G2STAT_MBOX_EMPTY) - && spincount--) - ; - if(spincount == -1) { - printf("ahb%d: board not responding\n",unit); + while (--wait) { + if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + == (G2STAT_MBOX_EMPTY)) + break; + delay(10); + } + if (!wait) { + printf("%s: board not responding\n", ahb->sc_dev.dv_xname); Debugger(); } - outl(port+MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */ - outb(port+ATTN, opcode|target); + outl(port + MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */ + outb(port + ATTN, opcode | target); + splx(s); } /* * Function to poll for command completion when in poll mode - * wait is in msec */ int -ahb_poll(int unit, int wait) -{ - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * wait; /* in msec */ - int stport = port + G2STAT; - int start = spincount; +ahb_poll(ahb, wait) + struct ahb_softc *ahb; + int wait; +{ /* in msec */ + u_short port = ahb->baseport; + u_short stport = port + G2STAT; -retry: - while( spincount-- && (!(inb(stport) & G2STAT_INT_PEND))) - ; - if(spincount == -1) { - printf("ahb%d: board not responding\n",unit); - return(EIO); + retry: + while (--wait) { + if (inb(stport) & G2STAT_INT_PEND) + break; + delay(1000); } - if( (int)cheat != PHYSTOKV(inl(port+MBOXIN0)) ) { - printf("discarding %x ", inl(port+MBOXIN0)); + if (!wait) { + printf("%s: board not responding\n", ahb->sc_dev.dv_xname); + return EIO; + } + + if (cheat != ahb_ecb_phys_kv(ahb, inl(port + MBOXIN0))) { + printf("discarding %x ", inl(port + MBOXIN0)); outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - spinwait(50); + delay(50000); goto retry; } - ahbintr(unit); - return(0); + + /* don't know this will work */ + ahbintr(ahb->sc_dev.dv_unit); + return 0; } + /* * Function to send an immediate type command to the adapter */ void -ahb_send_immed(int unit, int target, u_long cmd) +ahb_send_immed(ahb, target, cmd) + struct ahb_softc *ahb; + int target; + u_long cmd; { - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ + u_short port = ahb->baseport; + u_short stport = port + G2STAT; + int wait = 100; /* 1 ms enough? */ int s = splbio(); - int stport = port + G2STAT; - while( ((inb(stport) & - (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) != (G2STAT_MBOX_EMPTY)) && - spincount--) - ; - if(spincount == -1) { - printf("ahb%d: board not responding\n",unit); + while (--wait) { + if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + == (G2STAT_MBOX_EMPTY)) + break; + delay(10); + } + if (!wait) { + printf("%s: board not responding\n", ahb->sc_dev.dv_xname); Debugger(); } @@ -380,234 +439,257 @@ ahb_send_immed(int unit, int target, u_long cmd) } /* - * Check the slots looking for a board we recognise + * Check the slots looking for a board we recognise * If we find one, note it's address (slot) and call * the actual probe routine to check it out. */ int -ahbprobe(struct isa_device *dev) +ahbprobe(parent, self, aux) + struct device *parent, *self; + void *aux; { - int port; - u_char byte1,byte2,byte3; + struct ahb_softc *ahb = (void *)self; + struct isa_attach_args *ia = aux; + u_short port; + u_char byte1, byte2, byte3; - if (dev->id_parent) - return 1; +#ifdef NEWCONFIG + if (ia->ia_iobase != IOBASEUNK) + return ahbprobe1(ahb, ia); +#endif - ahb_slot++; - while (ahb_slot<8) { + while (ahb_slot < MAX_SLOTS) { + ahb_slot++; port = 0x1000 * ahb_slot; byte1 = inb(port + HID0); byte2 = inb(port + HID1); byte3 = inb(port + HID2); - if(byte1 == 0xff) { - ahb_slot++; + if (byte1 == 0xff) + continue; + if (CHAR1(byte1, byte2) != 'A' || + CHAR2(byte1, byte2) != 'D' || + CHAR3(byte1, byte2) != 'P' || + (byte3 != 0 && byte3 != 1)) { continue; } - if ((CHAR1(byte1,byte2) == 'A') - && (CHAR2(byte1,byte2) == 'D') - && (CHAR3(byte1,byte2) == 'P') - && ((byte3 == 0 ) || (byte3 == 1))) { - dev->id_iobase = port; - return ahbprobe1(dev); - } - ahb_slot++; + ia->ia_iobase = port; + if (ahbprobe1(ahb, ia)) + return 1; } + return 0; } /* - * Check if the device can be found at the port given * - * and if so, set it up ready for further work * - * as an argument, takes the isa_device structure from * - * autoconf.c * + * Check if the device can be found at the port given + * and if so, set it up ready for further work + * as an argument, takes the isa_device structure from + * autoconf.c. */ int -ahbprobe1(struct isa_device *dev) +ahbprobe1(ahb, ia) + struct ahb_softc *ahb; + struct isa_attach_args *ia; { - int unit = ahb_unit; - dev->id_unit = unit; - ahb_data[unit].baseport = dev->id_iobase; - if(unit >= NAHB) { - printf("ahb: unit number (%d) too high\n",unit); - return 0; - } + ahb->baseport = ia->ia_iobase; /* * Try initialise a unit at this location - * sets up dma and bus speed, loads ahb_data[unit].vect* + * sets up dma and bus speed, loads ahb->vect */ - if (ahb_init(unit) != 0) + if (ahb_find(ahb) != 0) return 0; - /* If it's there, put in it's interrupt vectors */ - dev->id_irq = (1 << ahb_data[unit].vect); - dev->id_drq = -1; /* using EISA dma */ - ahb_unit++; - return 0x1000; +#ifdef NEWCONFIG + if (ia->ia_irq == IRQUNK) { + ia->ia_irq = (1 << ahb->vect); + } else { + if (ia->ia_irq != (1 << ahb->vect)) { + printf("ahb%d: irq mismatch, %x != %x\n", + ahb->sc_dev.dv_unit, ia->ia_irq, + 1 << ahb->vect); + return 0; + } + } +#endif + + ia->ia_drq = DRQUNK; + ia->ia_msize = 0; + ia->ia_iosize = 0x1000; + return 1; +} + +ahbprint() +{ + } /* * Attach all the sub-devices we can find */ -int -ahb_attach(struct isa_device *dev) +void +ahbattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - static int firsttime; - static int firstswitch[NAHB]; - int masunit; - int r; + struct isa_attach_args *ia = aux; + struct ahb_softc *ahb = (void *)self; - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; + ahb_init(ahb); - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - ahb_switch[masunit].name = "ahb"; - ahb_switch[masunit].scsi_cmd = ahb_scsi_cmd; - ahb_switch[masunit].scsi_minphys = ahbminphys; - ahb_switch[masunit].open_target_lu = 0; - ahb_switch[masunit].close_target_lu = 0; - ahb_switch[masunit].adapter_info = ahb_adapter_info; - for (r = 0; r < 8; r++) { - ahb_switch[masunit].empty[r] = 0; - ahb_switch[masunit].used[r] = 0; - ahb_switch[masunit].printed[r] = 0; - } - } - r = scsi_attach(masunit, &ahb_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); + /* + * fill in the prototype scsi_link. + */ + ahb->sc_link.adapter_softc = ahb; + ahb->sc_link.adapter_targ = ahb->our_id; + ahb->sc_link.adapter = &ahb_switch; + ahb->sc_link.device = &ahb_dev; - /* only one for all boards */ - if(firsttime==0) { - firsttime = 1; - ahb_timeout(0); - } - return r; + printf("\n"); + +#ifdef NEWCONFIG + isa_establish(&ahb->sc_id, &ahb->sc_dev); + ahb->sc_ih.ih_fun = ahbintr; + ahb->sc_ih.ih_arg = ahb; + /* XXX and DV_TAPE, but either gives us splbio */ + intr_establish(ia->ia_irq, &ahb->sc_ih, DV_DISK); +#endif + + /* + * ask the adapter what subunits are present + */ + config_found(self, &ahb->sc_link, ahbprint); } /* - * Return some information to the caller about * - * the adapter and it's capabilities * - * 2 outstanding requests at a time per device + * Return some information to the caller about + * the adapter and it's capabilities */ -long int -ahb_adapter_info(int unit) +u_int +ahb_adapter_info(ahb) + struct ahb_softc *ahb; { - return 2; + + return 2; /* 2 outstanding requests at a time per device */ } /* * Catch an interrupt from the adaptor */ int -ahbintr(int unit) +ahbintr(unit) + int unit; { - struct ecb *ecb; - unsigned char stat; - register i; - u_char ahbstat; - int target; - long int mboxval; + struct ahb_softc *ahb = ahbcd.cd_devs[unit]; + struct ecb *ecb; + u_char stat, ahbstat; + u_long mboxval; + u_short port = ahb->baseport; - int port = ahb_data[unit].baseport; +#ifdef AHBDEBUG + printf("ahbintr "); +#endif /*AHBDEBUG */ - if(scsi_debug & PRINTROUTINES) - printf("ahbintr "); - - while(inb(port + G2STAT) & G2STAT_INT_PEND) { + while (inb(port + G2STAT) & G2STAT_INT_PEND) { /* * First get all the information and then * acknowlege the interrupt */ ahbstat = inb(port + G2INTST); - target = ahbstat & G2INTST_TARGET; stat = ahbstat & G2INTST_INT_STAT; - mboxval = inl(port + MBOXIN0);/* don't know this will work */ + mboxval = inl(port + MBOXIN0); /* don't know this will work */ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - if(scsi_debug & TRACEINTERRUPTS) - printf("status = 0x%x ",stat); + +#ifdef AHBDEBUG + printf("status = 0x%x ", ahbstat); +#endif /*AHBDEBUG */ /* * Process the completed operation */ - if(stat == AHB_ECB_OK) - ecb = (struct ecb *)PHYSTOKV(mboxval); - else { - switch(stat) { + if (stat == AHB_ECB_OK) { /* common case is fast */ + ecb = ahb_ecb_phys_kv(ahb, mboxval); + } else { + switch (stat) { case AHB_IMMED_OK: - ecb = ahb_data[unit].immed_ecb; - ahb_data[unit].immed_ecb = 0; + ecb = ahb->immed_ecb; + ahb->immed_ecb = 0; break; case AHB_IMMED_ERR: - ecb = ahb_data[unit].immed_ecb; + ecb = ahb->immed_ecb; ecb->flags |= ECB_IMMED_FAIL; - ahb_data[unit].immed_ecb = 0; + ahb->immed_ecb = 0; break; case AHB_ASN: /* for target mode */ + printf("%s: Unexpected ASN interrupt(%x)\n", + ahb->sc_dev.dv_xname, mboxval); ecb = 0; break; case AHB_HW_ERR: + printf("%s: Hardware error interrupt(%x)\n", + ahb->sc_dev.dv_xname, mboxval); ecb = 0; break; case AHB_ECB_RECOVERED: - ecb = (struct ecb *)PHYSTOKV(mboxval); + ecb = ahb_ecb_phys_kv(ahb, mboxval); break; case AHB_ECB_ERR: - ecb = (struct ecb *)PHYSTOKV(mboxval); + ecb = ahb_ecb_phys_kv(ahb, mboxval); break; default: - printf(" Unknown return from ahb%d(%x)\n",unit,ahbstat); - ecb=0; + printf("%s: Unknown return %x\n", + ahb->sc_dev.dv_xname, ahbstat); + ecb = 0; } - } - if(ecb) { - if(ahb_debug & AHB_SHOWCMDS ) - ahb_show_scsi_cmd(ecb->xs); - if((ahb_debug & AHB_SHOWECBS) && ecb) - printf("",ecb); - ahb_remove_timeout(ecb); - ahb_done(unit, ecb, (stat==AHB_ECB_OK)? SUCCESS: FAIL); + } if (ecb) { +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWCMDS) + show_scsi_cmd(ecb->xs); + if ((ahb_debug & AHB_SHOWECBS) && ecb) + printf("", ecb); +#endif /*AHBDEBUG */ + untimeout((timeout_t)ahb_timeout, (caddr_t)ecb); + ahb_done(ahb, ecb, stat != AHB_ECB_OK); } } return 1; } /* - * We have a ecb which has been processed by the - * adaptor, now we look to see how the operation - * went. + * We have a ecb which has been processed by the adaptor, now we look to see + * how the operation went. */ void -ahb_done(int unit, struct ecb *ecb, int state) +ahb_done(ahb, ecb, failed) + struct ahb_softc *ahb; + struct ecb *ecb; + int failed; { - struct ahb_ecb_status *stat = &ecb->ecb_status; - struct scsi_sense_data *s1,*s2; + struct ahb_ecb_status *stat = &ecb->ecb_status; + struct scsi_sense_data *s1, *s2; struct scsi_xfer *xs = ecb->xs; - if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("ahb_done "); - + SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_done\n")); /* * Otherwise, put the results of the operation * into the xfer and call whoever started it */ - if(ecb->flags & ECB_IMMED) { - if(ecb->flags & ECB_IMMED_FAIL) + if (ecb->flags & ECB_IMMED) { + if (ecb->flags & ECB_IMMED_FAIL) xs->error = XS_DRIVER_STUFFUP; goto done; } - if ( (state == SUCCESS) || (xs->flags & SCSI_ERR_OK)) { - /* All went correctly OR errors expected */ + + if (!failed || (xs->flags & SCSI_ERR_OK)) { /* All went correctly OR errors expected */ xs->resid = 0; xs->error = 0; } else { s1 = &(ecb->ecb_sense); s2 = &(xs->sense); - if(stat->ha_status) { - switch(stat->ha_status) { + if (stat->ha_status) { + switch (stat->ha_status) { case HS_SCSI_RESET_ADAPTER: break; case HS_SCSI_RESET_INCOMING: @@ -615,22 +697,25 @@ ahb_done(int unit, struct ecb *ecb, int state) case HS_CMD_ABORTED_HOST: /* No response */ case HS_CMD_ABORTED_ADAPTER: /* No response */ break; - case HS_TIMED_OUT: /* No response */ + case HS_TIMED_OUT: /* No response */ +#ifdef AHBDEBUG if (ahb_debug & AHB_SHOWMISC) printf("timeout reported back\n"); +#endif /*AHBDEBUG */ xs->error = XS_TIMEOUT; break; - default: - /* Other scsi protocol messes */ + default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; +#ifdef AHBDEBUG if (ahb_debug & AHB_SHOWMISC) - printf("unexpected ha_status: %x\n", + printf("unexpected ha_status %x\n", stat->ha_status); +#endif /*AHBDEBUG */ } - } else { - switch(stat->targ_status) { + switch (stat->targ_status) { case TS_CHECK_CONDITION: + /* structure copy!!!!! */ *s2 = *s1; xs->error = XS_SENSE; break; @@ -638,19 +723,20 @@ ahb_done(int unit, struct ecb *ecb, int state) xs->error = XS_BUSY; break; default: - if (ahb_debug & AHB_SHOWMISC) - printf("unexpected targ_status: %x\n", +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWMISC) { + printf("unexpected targ_status %x\n", stat->targ_status); + } +#endif /*AHBDEBUG */ xs->error = XS_DRIVER_STUFFUP; } } } - -done: + done: xs->flags |= ITSDONE; - ahb_free_ecb(unit, ecb, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + ahb_free_ecb(ahb, ecb, xs->flags); + scsi_done(xs); } /* @@ -658,72 +744,122 @@ done: * free list. */ void -ahb_free_ecb(int unit, struct ecb *ecb, int flags) +ahb_free_ecb(ahb, ecb, flags) + struct ahb_softc *ahb; + struct ecb *ecb; + int flags; { - unsigned int opri; + int opri; - if(scsi_debug & PRINTROUTINES) - printf("ecb%d(0x%x)> ",unit,flags); - if (!(flags & SCSI_NOMASK)) - opri = splbio(); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); - ecb->next = ahb_data[unit].free_ecb; - ahb_data[unit].free_ecb = ecb; + ecb->next = ahb->free_ecb; + ahb->free_ecb = ecb; ecb->flags = ECB_FREE; - /* * If there were none, wake abybody waiting for - * one to come free, starting with queued entries* + * one to come free, starting with queued entries */ if (!ecb->next) - wakeup((caddr_t)&ahb_data[unit].free_ecb); + wakeup((caddr_t)&ahb->free_ecb); - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); } /* - * Get a free ecb (and hence mbox-out entry) + * Get a free ecb + * + * If there are none, see if we can allocate a new one. If so, put it in the + * hash table too otherwise either return an error or sleep. */ struct ecb * -ahb_get_ecb(int unit, int flags) +ahb_get_ecb(ahb, flags) + struct ahb_softc *ahb; + int flags; { - unsigned opri; - struct ecb *rc; + int opri; + struct ecb *ecbp; + int hashnum; - if(scsi_debug & PRINTROUTINES) - printf("next; - rc->flags = ECB_ACTIVE; + while (!(ecbp = ahb->free_ecb)) { + if (ahb->numecbs < AHB_ECB_MAX) { + if (ecbp = (struct ecb *) malloc(sizeof(struct ecb), + M_TEMP, + M_NOWAIT)) { + bzero(ecbp, sizeof(struct ecb)); + ahb->numecbs++; + ecbp->flags = ECB_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + ecbp->hashkey = KVTOPHYS(ecbp); + hashnum = ECB_HASH(ecbp->hashkey); + ecbp->nexthash = ahb->ecbhash[hashnum]; + ahb->ecbhash[hashnum] = ecbp; + } else { + printf("%s: Can't malloc ECB\n", + ahb->sc_dev.dv_xname); + } + goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) + tsleep((caddr_t)&ahb->free_ecb, PRIBIO, + "ahbecb", 0); + } } - - if (!(flags & SCSI_NOMASK)) + if (ecbp) { + /* Get ECB from from free list */ + ahb->free_ecb = ecbp->next; + ecbp->flags = ECB_ACTIVE; + } + gottit: + if (!(flags & SCSI_NOMASK)) splx(opri); - return rc; + + return ecbp; +} + +/* + * given a physical address, find the ecb that it corresponds to. + */ +struct ecb * +ahb_ecb_phys_kv(ahb, ecb_phys) + struct ahb_softc *ahb; + physaddr ecb_phys; +{ + int hashnum = ECB_HASH(ecb_phys); + struct ecb *ecbp = ahb->ecbhash[hashnum]; + + while (ecbp) { + if (ecbp->hashkey == ecb_phys) + break; + ecbp = ecbp->nexthash; + } + return ecbp; } /* * Start the board, ready for normal operation */ int -ahb_init(int unit) +ahb_find(ahb) + struct ahb_softc *ahb; { - int port = ahb_data[unit].baseport; - int intdef; - int spincount = FUDGE(delaycount) * 1000; /* 1 sec enough? */ + u_short port = ahb->baseport; + u_short stport = port + G2STAT; + u_char intdef; int i; - int stport = port + G2STAT; + int wait = 1000; /* 1 sec enough? */ #define NO_NO 1 #ifdef NO_NO @@ -731,497 +867,388 @@ ahb_init(int unit) * reset board, If it doesn't respond, assume * that it's not there.. good for the probe */ - outb(port + EBCTRL,CDEN); /* enable full card */ - outb(port + PORTADDR,PORTADDR_ENHANCED); + outb(port + EBCTRL, CDEN); /* enable full card */ + outb(port + PORTADDR, PORTADDR_ENHANCED); - outb(port + G2CNTRL,G2CNTRL_HARD_RESET); - spinwait(1); - outb(port + G2CNTRL,0); - spinwait(10); - while( (inb(stport) & G2STAT_BUSY ) && spincount--) - ; - if(spincount == -1) { - if (ahb_debug & AHB_SHOWMISC) - printf("ahb_init: No answer from bt742a board\n"); - return(ENXIO); + outb(port + G2CNTRL, G2CNTRL_HARD_RESET); + delay(1000); + outb(port + G2CNTRL, 0); + delay(10000); + while (--wait) { + if ((inb(stport) & G2STAT_BUSY) == 0) + break; + delay(1000); } - - i = inb(port + MBOXIN0) & 0xff; - if(i) { - printf("self test failed, val = 0x%x\n",i); - return(EIO); + if (!wait) { +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWMISC) + printf("ahb_find: No answer from aha1742 board\n"); +#endif /*AHBDEBUG */ + return ENXIO; + } + i = inb(port + MBOXIN0); + if (i) { + printf("self test failed, val = 0x%x\n", i); + return EIO; } #endif - while( inb(stport) & G2STAT_INT_PEND) { + while (inb(stport) & G2STAT_INT_PEND) { printf("."); outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - spinwait(10); + delay(10000); } - outb(port + EBCTRL,CDEN); /* enable full card */ - outb(port + PORTADDR,PORTADDR_ENHANCED); - - /* - * Assume we have a board at this stage - * setup dma channel from jumpers and save int - * level - */ + outb(port + EBCTRL, CDEN); /* enable full card */ + outb(port + PORTADDR, PORTADDR_ENHANCED); intdef = inb(port + INTDEF); - switch(intdef & 0x07) { + switch (intdef & 0x07) { case INT9: - ahb_data[unit].vect = 9; + ahb->vect = 9; break; case INT10: - ahb_data[unit].vect = 10; + ahb->vect = 10; break; case INT11: - ahb_data[unit].vect = 11; + ahb->vect = 11; break; case INT12: - ahb_data[unit].vect = 12; + ahb->vect = 12; break; case INT14: - ahb_data[unit].vect = 14; + ahb->vect = 14; break; case INT15: - ahb_data[unit].vect = 15; + ahb->vect = 15; break; default: - ahb_data[unit].vect = -1; - printf("ahb%d: illegal irq setting\n", unit); - return(EIO); + printf("illegal int setting %x\n", intdef); + return EIO; } - outb(port + INTDEF, intdef|INTEN); /* make sure we can interrupt */ - ahb_switch[unit].scsi_dev = (inb(port + SCSIDEF) & HSCSIID); + outb(port + INTDEF, (intdef | INTEN)); /* make sure we can interrupt */ - /* - * link up all our ECBs into a free list - */ - for (i=0; i < NUM_CONCURRENT; i++) { - ahb_data[unit].ecbs[i].next = ahb_data[unit].free_ecb; - ahb_data[unit].free_ecb = &ahb_data[unit].ecbs[i]; - ahb_data[unit].free_ecb->flags = ECB_FREE; - } + /* who are we on the scsi bus? */ + ahb->our_id = (inb(port + SCSIDEF) & HSCSIID); /* * Note that we are going and return (to probe) */ - ahb_data[unit].flags |= AHB_INIT; return 0; } void -ahbminphys(struct buf *bp) +ahb_init(ahb) + struct ahb_softc *ahb; { - if(bp->b_bcount > ((AHB_NSEG-1) * PAGESIZ)) - bp->b_bcount = ((AHB_NSEG-1) * PAGESIZ); + +} + +void +ahbminphys(bp) + struct buf *bp; +{ + + if (bp->b_bcount > ((AHB_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((AHB_NSEG - 1) << PGSHIFT); } /* - * start a scsi operation given the command and - * the data address. Also needs the unit, target - * and lu + * start a scsi operation given the command and the data address. Also needs + * the unit, target and lu. */ -int -ahb_scsi_cmd(struct scsi_xfer *xs) +int +ahb_scsi_cmd(xs) + struct scsi_xfer *xs; { - struct scsi_sense_data *s1,*s2; + struct scsi_link *sc_link = xs->sc_link; + struct ahb_softc *ahb = sc_link->adapter_softc; struct ecb *ecb; struct ahb_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; - physaddr thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; - int s; - if(scsi_debug & PRINTROUTINES) - printf("ahb_scsi_cmd "); + int seg; /* scatter gather seg being worked on */ + int thiskv; + physaddr thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + int s; + + SC_DEBUG(sc_link, SDEV_DB2, ("ahb_scsi_cmd\n")); /* * get a ecb (mbox-out) to use. If the transfer * is from a buf (possibly from interrupt time) * then we can't allow it to sleep */ flags = xs->flags; - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if(flags & ITSDONE) { - printf("Already done?"); + if (xs->bp) + flags |= SCSI_NOSLEEP; /* just to be sure */ + if (flags & ITSDONE) { + printf("%s: already done?", ahb->sc_dev.dv_xname); xs->flags &= ~ITSDONE; } - if( !(flags & INUSE) ) { - printf("Not in use?"); + if (!(flags & INUSE)) { + printf("%s: not in use?", ahb->sc_dev.dv_xname); xs->flags |= INUSE; } - if (!(ecb = ahb_get_ecb(unit,flags))) { + if (!(ecb = ahb_get_ecb(ahb, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return TRY_AGAIN_LATER; } - -cheat = ecb; - - if(ahb_debug & AHB_SHOWECBS) - printf("",ecb); - if(scsi_debug & SHOWCOMMANDS) - ahb_show_scsi_cmd(xs); - + cheat = ecb; + SC_DEBUG(sc_link, SDEV_DB3, ("start ecb(%x)\n", ecb)); ecb->xs = xs; + /* * If it's a reset, we need to do an 'immediate' - * command, and store it's ccb for later + * command, and store it's ecb for later * if there is already an immediate waiting, * then WE must wait */ - if(flags & SCSI_RESET) { + if (flags & SCSI_RESET) { ecb->flags |= ECB_IMMED; - if(ahb_data[unit].immed_ecb) - return(TRY_AGAIN_LATER); - - ahb_data[unit].immed_ecb = ecb; + if (ahb->immed_ecb) + return TRY_AGAIN_LATER; + ahb->immed_ecb = ecb; if (!(flags & SCSI_NOMASK)) { s = splbio(); - ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); - ahb_add_timeout(ecb,xs->timeout); + ahb_send_immed(ahb, sc_link->target, AHB_TARG_RESET); + timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000); splx(s); - return(SUCCESSFULLY_QUEUED); + return SUCCESSFULLY_QUEUED; } else { - ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); + ahb_send_immed(ahb, sc_link->target, AHB_TARG_RESET); /* - * If we can't use interrupts, poll on completion* + * If we can't use interrupts, poll on completion */ - if(scsi_debug & TRACEINTERRUPTS) - printf("wait "); - if( ahb_poll(unit,xs->timeout)) { - ahb_free_ecb(unit,ecb,flags); + SC_DEBUG(sc_link, SDEV_DB3, ("wait\n")); + if (ahb_poll(ahb, xs->timeout)) { + ahb_free_ecb(ahb, ecb, flags); xs->error = XS_TIMEOUT; - return(HAD_ERROR); + return HAD_ERROR; } - return(COMPLETE); + return COMPLETE; } } /* * Put all the arguments for the xfer in the ecb */ ecb->opcode = ECB_SCSI_OP; - ecb->opt1 = ECB_SES|ECB_DSB|ECB_ARS; - if(xs->datalen) + ecb->opt1 = ECB_SES | ECB_DSB | ECB_ARS; + if (xs->datalen) ecb->opt1 |= ECB_S_G; - ecb->opt2 = xs->lu | ECB_NRB; - ecb->cdblen = xs->cmdlen; - ecb->sense = KVTOPHYS(&(ecb->ecb_sense)); - ecb->senselen = sizeof(ecb->ecb_sense); - ecb->status = KVTOPHYS(&(ecb->ecb_status)); + ecb->opt2 = sc_link->lun | ECB_NRB; + ecb->cdblen = xs->cmdlen; + ecb->sense = KVTOPHYS(&ecb->ecb_sense); + ecb->senselen = sizeof(ecb->ecb_sense); + ecb->status = KVTOPHYS(&ecb->ecb_status); - if(xs->datalen) { - /* should use S/G only if not zero length */ - ecb->data = KVTOPHYS(ecb->ahb_dma); - sg = ecb->ahb_dma ; - seg = 0; - if(flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; + if (xs->datalen) { /* should use S/G only if not zero length */ + ecb->data = KVTOPHYS(ecb->ahb_dma); + sg = ecb->ahb_dma; + seg = 0; + +#ifdef TFS + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while ((datalen) && (seg < AHB_NSEG)) { - sg->addr = (physaddr)iovp->iov_base; + while (datalen && seg < AHB_NSEG) { + sg->addr = (physaddr) iovp->iov_base; xs->datalen += sg->len = iovp->iov_len; - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)", iovp->iov_len, - iovp->iov_base); + SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } else { - /* Set up the scatter gather block */ + } + else +#endif /*TFS */ + { + /* + * Set up the scatter gather block + */ + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + datalen = xs->datalen; + thiskv = (int) xs->data; + thisphys = KVTOPHYS(thiskv); - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ", xs->datalen, xs->data); - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - - while ((datalen) && (seg < AHB_NSEG)) { - bytes_this_seg = 0; + while (datalen && seg < AHB_NSEG) { + bytes_this_seg = 0; /* put in the base address */ sg->addr = thisphys; - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); + SC_DEBUGN(sc_link, SDEV_DB4, + ("0x%x", thisphys)); /* do it at least once */ nextphys = thisphys; while ((datalen) && (thisphys == nextphys)) { - /* - * This page is contiguous (physically) with * - * the the last, just extend the length * - */ - nextphys= (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = min(nextphys - thisphys, - datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; + /* + * This page is contiguous (physically) + * with the the last, just extend the + * length + */ + /* how far to the end of the page */ + nextphys = (thisphys & ~PGOFSET) + NBPG; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page, + datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + thiskv = (thiskv & ~PGOFSET) + NBPG; + if (datalen) thisphys = KVTOPHYS(thiskv); } /* - * next page isn't contiguous, finish the seg * + * next page isn't contiguous, finish the seg */ - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); + SC_DEBUGN(sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); sg->len = bytes_this_seg; sg++; seg++; } } - ecb->datalen = seg * sizeof(struct ahb_dma_seg); - if(scsi_debug & SHOWSCATGATH) - printf("\n"); - if (datalen) { - /* there's still data, must have run out of segs! */ - printf("ahb_scsi_cmd%d: more than %d DMA segs\n", - unit, AHB_NSEG); - xs->error = XS_DRIVER_STUFFUP; - ahb_free_ecb(unit,ecb,flags); - return(HAD_ERROR); - } - } else { - /* No data xfer, use non S/G values */ - ecb->data = (physaddr)0; + /*end of iov/kv decision */ + ecb->datalen = seg * sizeof(struct ahb_dma_seg); + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); + + if (datalen) { + /* + * there's still data, must have run out of segs! + */ + printf("%s: ahb_scsi_cmd, more than %d DMA segs\n", + ahb->sc_dev.dv_xname, AHB_NSEG); + xs->error = XS_DRIVER_STUFFUP; + ahb_free_ecb(ahb, ecb, flags); + return HAD_ERROR; + } + } else { /* No data xfer, use non S/G values */ + ecb->data = (physaddr) 0; ecb->datalen = 0; } + ecb->chain = (physaddr) 0; - ecb->chain = (physaddr)0; /* * Put the scsi command in the ecb and start it */ bcopy(xs->cmd, ecb->cdb, xs->cmdlen); - /* Usually return SUCCESSFULLY QUEUED */ - if( !(flags & SCSI_NOMASK) ) { + /* + * Usually return SUCCESSFULLY QUEUED + */ + if (!(flags & SCSI_NOMASK)) { s = splbio(); - ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); - ahb_add_timeout(ecb,xs->timeout); + ahb_send_mbox(ahb, OP_START_ECB, sc_link->target, ecb); + timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000); splx(s); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); + return SUCCESSFULLY_QUEUED; } - /* If we can't use interrupts, poll on completion */ - ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_wait "); - + /* + * If we can't use interrupts, poll on completion + */ + ahb_send_mbox(ahb, OP_START_ECB, sc_link->target, ecb); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_wait\n")); do { - if(ahb_poll(unit,xs->timeout)) { - if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); - ahb_send_mbox(unit,OP_ABORT_ECB,xs->targ,ecb); - if(ahb_poll(unit, 2000)) { - printf("abort failed in wait\n"); - ahb_free_ecb(unit,ecb,flags); + if (ahb_poll(ahb, xs->timeout)) { + if (!(xs->flags & SCSI_SILENT)) + printf("%s: cmd fail\n", ahb->sc_dev.dv_xname); + ahb_send_mbox(ahb, OP_ABORT_ECB, sc_link->target, ecb); + if (ahb_poll(ahb, 2000)) { + printf("%s: abort failed in wait\n", + ahb->sc_dev.dv_xname); + ahb_free_ecb(ahb, ecb, flags); } xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); + return HAD_ERROR; } - } while (!(xs->flags & ITSDONE)); - - scsi_debug = 0; - ahb_debug = 0; - if(xs->error) + } while (!(xs->flags & ITSDONE));/* something (?) else finished */ + if (xs->error) return HAD_ERROR; return COMPLETE; } -/* - * +----------+ +----------+ +----------+ - * ahb_soonest--->| later |--->| later|--->| later|--->0 - * | [Delta] | | [Delta] | | [Delta] | - * 0<---|sooner |<---|sooner |<---|sooner |<---ahb_latest - * +----------+ +----------+ +----------+ - * - * ahb_furtherest = sum(Delta[1..n]) - */ void -ahb_add_timeout(struct ecb *ecb, int time) +ahb_timeout(arg) + caddr_t arg; { - int timeprev; - struct ecb *prev; - int s = splbio(); + int s = splbio(); + struct ecb *ecb = (void *)arg; + struct ahb_softc *ahb = ecb->xs->sc_link->adapter_softc; - prev = ahb_latest; - if(prev) - timeprev = ahb_furtherest; - else - timeprev = 0; + sc_print_addr(ecb->xs->sc_link); + printf("timed out "); - while(prev && (timeprev > time)) { - timeprev -= prev->delta; - prev = prev->sooner; +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWECBS) + ahb_print_active_ecb(ahb); +#endif /*AHBDEBUG */ + + /* + * If it's immediate, don't try abort it + */ + if (ecb->flags & ECB_IMMED) { + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->flags |= ECB_IMMED_FAIL; + ahb_done(ahb, ecb, 1); + splx(s); + return; } - if(prev) { - ecb->delta = time - timeprev; - ecb->later = prev->later; - if(ecb->later) { - ecb->later->sooner = ecb; - ecb->later->delta -= ecb->delta; - } else { - ahb_furtherest = time; - ahb_latest = ecb; - } - ecb->sooner = prev; - prev->later = ecb; - } - else - { - ecb->later = ahb_soonest; - if(ahb_soonest) { - ecb->later->sooner = ecb; - ecb->later->delta -= time; - } else { - ahb_furtherest = time; - ahb_latest = ecb; - } - ecb->delta = time; - ecb->sooner = (struct ecb *)0; - ahb_soonest = ecb; + + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (ecb->flags == ECB_ABORTED) { + printf("AGAIN\n"); + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST; + ahb_done(ahb, ecb, 1); + } else { /* abort the operation that has timed out */ + printf("\n"); + ahb_send_mbox(ahb, OP_ABORT_ECB, ecb->xs->sc_link->target, ecb); + timeout(ahb_timeout, (caddr_t)ecb, 2 * hz); + ecb->flags = ECB_ABORTED; } splx(s); } +#ifdef AHBDEBUG void -ahb_remove_timeout(struct ecb *ecb) +ahb_print_ecb(ecb) + struct ecb *ecb; { - int s = splbio(); - - if(ecb->sooner) - ecb->sooner->later = ecb->later; - else - ahb_soonest = ecb->later; - - if(ecb->later) { - ecb->later->sooner = ecb->sooner; - ecb->later->delta += ecb->delta; - } else { - ahb_latest = ecb->sooner; - ahb_furtherest -= ecb->delta; - } - ecb->sooner = ecb->later = (struct ecb *)0; - splx(s); + printf("ecb:%x op:%x cmdlen:%d senlen:%d\n", + ecb, ecb->opcode, ecb->cdblen, ecb->senselen); + printf(" datlen:%d hstat:%x tstat:%x flags:%x\n", + ecb->datalen, ecb->ecb_status.ha_status, + ecb->ecb_status.targ_status, ecb->flags); + show_scsi_cmd(ecb->xs); } - -extern int hz; -#define ONETICK 500 /* milliseconds */ -#define SLEEPTIME ((hz * 1000) / ONETICK) - void -ahb_timeout(int arg) +ahb_print_active_ecb(ahb) + struct ahb_softc *ahb; { struct ecb *ecb; - int unit; - int s = splbio(); - - while( ecb = ahb_soonest ) { - if(ecb->delta <= ONETICK) { - /* It has timed out, we need to do some work */ - unit = ecb->xs->adapter; - printf("ahb%d targ %d: device timed out\n", unit, - ecb->xs->targ); - if(ahb_debug & AHB_SHOWECBS) - ahb_print_active_ecb(); - - /* Unlink it from the queue */ - ahb_remove_timeout(ecb); - - /* - * If it's immediate, don't try abort it * - */ - if(ecb->flags & ECB_IMMED) { - ecb->xs->retries = 0; /* I MEAN IT ! */ - ecb->flags |= ECB_IMMED_FAIL; - ahb_done(unit,ecb,FAIL); - continue; - } - - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if(ecb->flags == ECB_ABORTED) { - printf("AGAIN"); - ecb->xs->retries = 0; /* I MEAN IT ! */ - ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST; - ahb_done(unit,ecb,FAIL); - } else { - printf("\n"); - ahb_send_mbox(unit,OP_ABORT_ECB,ecb->xs->targ,ecb); - /* 2 secs for the abort */ - ahb_add_timeout(ecb,2000 + ONETICK); - ecb->flags = ECB_ABORTED; - } - } else { - ecb->delta -= ONETICK; - ahb_furtherest -= ONETICK; - break; - } - } - splx(s); - timeout((timeout_t)ahb_timeout,(caddr_t)arg,SLEEPTIME); -} - -void -ahb_show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *)xs->cmd; int i = 0; - if( !(xs->flags & SCSI_RESET) ) { - printf("ahb%d targ %d lun %d:", xs->adapter, - xs->targ, xs->lu); - while(i < xs->cmdlen ) { - if(i) - printf(","); - printf("%x", b[i++]); + while (i++ < ECB_HASH_SIZE) { + ecb = ahb->ecbhash[i]; + while (ecb) { + if (ecb->flags != ECB_FREE) + ahb_print_ecb(ecb); + ecb = ecb->nexthash; } - printf("\n"); - } else { - printf("ahb%d targ %d lun%d: RESET\n", xs->adapter, - xs->targ, xs->lu); } } - -void -ahb_print_ecb(struct ecb *ecb) -{ - printf("ecb:%x op:%x cmdlen:%d senlen:%d\n", ecb, ecb->opcode, - ecb->cdblen, ecb->senselen); - printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n", - ecb->datalen, ecb->ecb_status.ha_status, - ecb->ecb_status.targ_status, ecb->delta, ecb->flags); - ahb_show_scsi_cmd(ecb->xs); -} - -void -ahb_print_active_ecb(void) -{ - struct ecb *ecb; - ecb = ahb_soonest; - - while(ecb) { - ahb_print_ecb(ecb); - ecb = ecb->later; - } - printf("Furtherest = %d\n", ahb_furtherest); -} +#endif /* AHBDEBUG */ diff --git a/sys/arch/i386/isa/bt742a.c b/sys/arch/i386/isa/bt742a.c index 7318c3d06201..b5f8f4f23d98 100644 --- a/sys/arch/i386/isa/bt742a.c +++ b/sys/arch/i386/isa/bt742a.c @@ -1,5 +1,36 @@ /* - * Written by Julian Elischer (julian@tfs.com) + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: bt742a.c,v 1.21 1994/03/29 04:30:21 mycroft Exp $ + */ + +/* + * Originally written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -11,51 +42,46 @@ * TFS supplies this software to be publicly redistributed * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. - * - * $Id: bt742a.c,v 1.20 1994/03/25 07:40:55 mycroft Exp $ */ /* - * BusTech/BusLogic SCSI card driver (all cards) - * - * Modified to support round-robin mailbox allocation and page-aligned - * buffer allocation by Michael VanLoon (michaelv@iastate.edu) + * bt742a SCSI driver */ -#include "bt.h" - #include #include #include +#include #include #include +#include #include #include #include #include -#include -#include -#include +#include + +#include +#include #include #include #ifdef DDB int Debugger(); -#else -#define Debugger() panic("should call debugger here (bt742a.c)") -#endif +#else /* DDB */ +#define Debugger() +#endif /* DDB */ -extern int delaycount; /* from clock setup code */ -typedef unsigned long int physaddr; +typedef u_long physaddr; /* * I/O Port Interface */ -#define BT_BASE bt_base[unit] -#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ -#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ -#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ +#define BT_BASE bt->bt_base +#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ +#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ +#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ /* * BT_CTRL_STAT bits (write) @@ -101,6 +127,11 @@ typedef unsigned long int physaddr; #define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */ #define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */ +/* Follows command appeared at FirmWare 3.31 */ +#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */ +#define BT_DISABLE 0x00 /* Parameter value for Disable */ +#define BT_ENABLE 0x01 /* Parameter value for Enable */ + struct bt_cmd_buf { u_char byte[16]; }; @@ -108,30 +139,51 @@ struct bt_cmd_buf { /* * BT_INTR_PORT bits (read) */ -#define BT_ANY_INTR 0x80 /* Any interrupt */ +#define BT_ANY_INTR 0x80 /* Any interrupt */ #define BT_SCRD 0x08 /* SCSI reset detected */ #define BT_HACC 0x04 /* Command complete */ #define BT_MBOA 0x02 /* MBX out empty */ #define BT_MBIF 0x01 /* MBX in full */ /* - * Mail box defs + * Mail box defs etc. + * these could be bigger but we need the bt_softc to fit on a single page.. */ -#define BT_MBX_SIZE 32 /* mail box size */ +#define BT_MBX_SIZE 16 /* mail box size (MAX 255 MBxs) */ + /* don't need that many really */ +#define BT_CCB_MAX 32 /* store up to 32CCBs at any one time */ + /* in bt742a H/W ( Not MAX ? ) */ +#define CCB_HASH_SIZE 32 /* when we have a physical addr. for */ + /* a ccb and need to find the ccb in */ + /* space, look it up in the hash table */ +#define CCB_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define CCB_HASH(x) ((((long int)(x))>>CCB_HASH_SHIFT) % CCB_HASH_SIZE) + +#define bt_nextmbx( wmb, mbx, mbio ) \ + if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) \ + (wmb) = &((mbx)->mbio[0]); \ + else \ + (wmb)++; + +typedef struct bt_mbx_out { + physaddr ccb_addr; + u_char dummy[3]; + u_char cmd; +} BT_MBO; + +typedef struct bt_mbx_in { + physaddr ccb_addr; + u_char btstat; + u_char sdstat; + u_char dummy; + u_char stat; +} BT_MBI; struct bt_mbx { - struct bt_mbx_out { - physaddr ccb_addr; - unsigned char dummy[3]; - unsigned char cmd; - } mbo[BT_MBX_SIZE]; - struct bt_mbx_in { - physaddr ccb_addr; - unsigned char btstat; - unsigned char sdstat; - unsigned char dummy; - unsigned char stat; - } mbi[BT_MBX_SIZE]; + BT_MBO mbo[BT_MBX_SIZE]; + BT_MBI mbi[BT_MBX_SIZE]; + BT_MBO *tmbo; /* Target Mail Box out */ + BT_MBI *tmbi; /* Target Mail Box in */ }; /* @@ -141,43 +193,52 @@ struct bt_mbx { #define BT_MBO_START 0x1 /* MBO activate entry */ #define BT_MBO_ABORT 0x2 /* MBO abort entry */ +/* + * mbi.stat values + */ #define BT_MBI_FREE 0x0 /* MBI entry is free */ #define BT_MBI_OK 0x1 /* completed without error */ #define BT_MBI_ABORT 0x2 /* aborted ccb */ #define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ #define BT_MBI_ERROR 0x4 /* Completed with error */ -#define BT_NSEG 32 +#if defined(BIG_DMA) +WARNING...THIS WON'T WORK(won't fit on 1 page) +/* #define BT_NSEG 2048 /* Number of scatter gather segments - to much vm */ +#define BT_NSEG 128 +#else +#define BT_NSEG 33 +#endif /* BIG_DMA */ struct bt_scat_gath { - unsigned long seg_len; + u_long seg_len; physaddr seg_addr; }; struct bt_ccb { - unsigned char opcode; - unsigned char:3, data_in:1, data_out:1,:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; + u_char opcode; + u_char:3, data_in:1, data_out:1,:3; + u_char scsi_cmd_length; + u_char req_sense_length; /*------------------------------------longword boundary */ - unsigned long data_length; + u_long data_length; /*------------------------------------longword boundary */ physaddr data_addr; /*------------------------------------longword boundary */ - unsigned char dummy[2]; - unsigned char host_stat; - unsigned char target_stat; + u_char dummy[2]; + u_char host_stat; + u_char target_stat; /*------------------------------------longword boundary */ - unsigned char target; - unsigned char lun; - unsigned char scsi_cmd[12]; /* 12 bytes (bytes only) */ - unsigned char dummy2[1]; - unsigned char link_id; + u_char target; + u_char lun; + u_char scsi_cmd[12]; /* 12 bytes (bytes only) */ + u_char dummy2[1]; + u_char link_id; /*------------------------------------4 longword boundary */ physaddr link_addr; /*------------------------------------longword boundary */ physaddr sense_ptr; - /*------------------------------------longword boundary */ +/*-----end of HW fields-------------------------------longword boundary */ struct scsi_sense_data scsi_sense; /*------------------------------------longword boundary */ struct bt_scat_gath scat_gath[BT_NSEG]; @@ -188,19 +249,17 @@ struct bt_ccb { /*------------------------------------longword boundary */ struct bt_mbx_out *mbx; /* pointer to mail box */ /*------------------------------------longword boundary */ - long delta; /* difference from previous */ - struct bt_ccb *later, *sooner; int flags; #define CCB_FREE 0 #define CCB_ACTIVE 1 #define CCB_ABORTED 2 - unsigned char dummy3[24]; /* align struct to 32 bits */ + /*------------------------------------longword boundary */ + struct bt_ccb *nexthash; /* if two hash the same */ + /*------------------------------------longword boundary */ + physaddr hashkey; /*physaddr of this ccb */ + /*------------------------------------longword boundary */ }; -struct bt_ccb *bt_soonest = (struct bt_ccb *) 0; -struct bt_ccb *bt_latest = (struct bt_ccb *) 0; -long int bt_furthest = 0; /* longest time in the timeout queue */ - /* * opcode fields */ @@ -227,28 +286,36 @@ long int bt_furthest = 0; /* longest time in the timeout queue */ #define BT_INV_CCB 0x1a /* Invalid CCB or segment list */ #define BT_ABORTED 42 /* pseudo value from driver */ +struct bt_boardID { + u_char board_type; + u_char custom_feture; + char firm_revision; + u_char firm_version; +}; + struct bt_setup { - u_char sync_neg:1; - u_char parity:1; - u_char xxx:6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[4]; + u_char sync_neg:1; + u_char parity:1; + u_char :6; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[3]; /*XXX */ + /* doesn't make sense with 32bit addresses */ struct { - u_char offset:4; - u_char period:3; - u_char valid:1; + u_char offset:4; + u_char period:3; + u_char valid:1; } sync[8]; - u_char disc_sts; + u_char disc_sts; }; struct bt_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char xxx:5; + u_char chan; + u_char intr; + u_char scsi_dev:3; + u_char :5; }; #define INT9 0x01 @@ -266,33 +333,21 @@ struct bt_config { #define KVTOPHYS(x) vtophys(x) -#define PAGESIZ NBPG -#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } +struct bt_softc { + struct device sc_dev; + struct isadev sc_id; + struct intrhand sc_ih; -short bt_base[NBT]; /* base port for each board */ -struct isa_device *btinfo[NBT]; -struct bt_ccb *bt_get_ccb(); -int bt_int[NBT]; -int bt_dma[NBT]; -int bt_initialized[NBT]; - -/* we'll malloc memory for these in bt_init() */ -struct bt_data { - struct bt_mbx bt_mbx; - struct bt_ccb bt_ccb[BT_MBX_SIZE]; - struct scsi_xfer bt_scsi_xfer; - int sleepers; -} *btdata[NBT]; - -struct bt_ccb_lu { - struct bt_ccb *kv_addr; - physaddr phys_addr; -} bt_ccb_lut[NBT][BT_MBX_SIZE]; - -struct { /* mbo and mbi last used */ - u_char mbo; - u_char mbi; -} bt_last[NBT]; + u_short bt_base; /* base port for each board */ + struct bt_mbx bt_mbx; /* all our mailboxes */ + struct bt_ccb *bt_ccb_free; /* list of free CCBs */ + struct bt_ccb *ccbhash[CCB_HASH_SIZE]; /* phys to kv hash */ + int bt_int; /* int. read off board */ + int bt_dma; /* DMA channel read of board */ + int bt_scsi_dev; /* adapters scsi id */ + int numccbs; /* how many we have malloc'd */ + struct scsi_link sc_link; /* prototype for devs */ +}; /***********debug values *************/ #define BT_SHOWCCBS 0x01 @@ -301,87 +356,111 @@ struct { /* mbo and mbi last used */ #define BT_SHOWMISC 0x08 int bt_debug = 0; -int btprobe(), btattach(); -int btintr(); +int bt_cmd(); /* XXX must be varargs to prototype */ +u_int bt_adapter_info __P((struct bt_softc *)); +int btintr __P((int)); +void bt_free_ccb __P((struct bt_softc *, struct bt_ccb *, int)); +struct bt_ccb *bt_get_ccb __P((struct bt_softc *, int)); +struct bt_ccb *bt_ccb_phys_kv __P((struct bt_softc *, physaddr)); +BT_MBO *bt_send_mbo __P((struct bt_softc *, int, int, struct bt_ccb *)); +void bt_done __P((struct bt_softc *, struct bt_ccb *)); +int bt_find __P((struct bt_softc *)); +void bt_init __P((struct bt_softc *)); +void bt_inquire_setup_information __P((struct bt_softc *)); +void btminphys __P((struct buf *)); +int bt_scsi_cmd __P((struct scsi_xfer *)); +int bt_poll __P((struct bt_softc *, struct scsi_xfer *, struct bt_ccb *)); +void bt_timeout __P((caddr_t)); +#ifdef UTEST +void bt_print_ccb __P((struct bt_ccb *)); +void bt_print_active_ccbs __P((struct bt_softc *)); +#endif -struct isa_driver btdriver = { - btprobe, - btattach, +struct scsi_adapter bt_switch = { + bt_scsi_cmd, + btminphys, + 0, + 0, + bt_adapter_info, "bt" }; -static int btunit = 0; +/* the below structure is so we have a default dev struct for out link struct */ +struct scsi_device bt_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "bt", + 0 +}; -#define bt_abortmbx(mbx) \ - (mbx)->cmd = BT_MBO_ABORT; \ - outb(BT_CMD_DATA_PORT, BT_START_SCSI); -#define bt_startmbx(mbx) \ - (mbx)->cmd = BT_MBO_START; \ - outb(BT_CMD_DATA_PORT, BT_START_SCSI); +int btprobe(); +void btattach(); -int bt_scsi_cmd(); -int bt_timeout(); -void btminphys(); -long int bt_adapter_info(); +struct cfdriver btcd = { + NULL, "bt", btprobe, btattach, DV_DULL, sizeof(struct bt_softc) +}; -struct scsi_switch bt_switch[NBT]; - -#define BT_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */ -#define BT_RESET_TIMEOUT 1000000 /* */ -#define BT_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */ +#define BT_RESET_TIMEOUT 1000 /* - * Activate Adapter command - * icnt: number of args (outbound bytes written after opcode) - * ocnt: number of expected returned bytes - * wait: number of seconds to wait for response - * retval: buffer where to place returned bytes - * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... - * args: parameters + * bt_cmd(bt, icnt, ocnt,wait, retval, opcode, args) * - * Performs an adapter command through the ports. Not to be confused - * with a scsi command, which is read in via the dma - * One of the adapter commands tells it to read in a scsi command + * Activate Adapter command + * icnt: number of args (outbound bytes written after opcode) + * ocnt: number of expected returned bytes + * wait: number of seconds to wait for response + * retval: buffer where to place returned bytes + * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... + * args: parameters + * + * Performs an adapter command through the ports. Not to be confused with a + * scsi command, which is read in via the dma; one of the adapter commands + * tells it to read in a scsi command. */ -bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) +int +bt_cmd(bt, icnt, ocnt, wait, retval, opcode, args) + struct bt_softc *bt; + int icnt, ocnt, wait; u_char *retval; unsigned opcode; - u_char args; + u_char args; { unsigned *ic = &opcode; - u_char oc; + u_char oc; register i; - int sts; - struct bt_data *bt = btdata[unit]; + int sts; /* * multiply the wait argument by a big constant * zero defaults to 1 */ - if (!wait) - wait = BT_CMD_TIMEOUT_FUDGE * delaycount; + if (wait) + wait *= 100000; else - wait *= BT_CMD_TIMEOUT_FUDGE * delaycount; - + wait = 100000; /* * Wait for the adapter to go idle, unless it's one of * the commands which don't need this */ if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) { - i = BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ + i = 100000; /* 1 sec? */ while (--i) { sts = inb(BT_CTRL_STAT_PORT); if (sts & BT_IDLE) { break; } + delay(10); } if (!i) { - printf("bt_cmd: bt742a host not idle(0x%x)\n", sts); - return (ENXIO); + printf("%s: bt_cmd, host not idle(0x%x)\n", + bt->sc_dev.dv_xname, sts); + return ENXIO; } } /* - * Now that it is idle, if we expect output, preflush the* + * Now that it is idle, if we expect output, preflush the * queue feeding to us. */ if (ocnt) { @@ -392,18 +471,21 @@ bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) * Output the command and the number of arguments given * for each byte, first check the port is empty. */ - icnt++; /* include the command */ + icnt++; + /* include the command */ while (icnt--) { sts = inb(BT_CTRL_STAT_PORT); - for (i = 0; i < wait; i++) { + for (i = wait; i; i--) { sts = inb(BT_CTRL_STAT_PORT); if (!(sts & BT_CDF)) break; + delay(10); } - if (i >= wait) { - printf("bt_cmd: bt742a cmd/data port full\n"); + if (!i) { + printf("%s: bt_cmd, cmd/data port full\n", + bt->sc_dev.dv_xname); outb(BT_CTRL_STAT_PORT, BT_SRST); - return (ENXIO); + return ENXIO; } outb(BT_CMD_DATA_PORT, (u_char) (*ic++)); } @@ -413,14 +495,16 @@ bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) */ while (ocnt--) { sts = inb(BT_CTRL_STAT_PORT); - for (i = 0; i < wait; i++) { + for (i = wait; i; i--) { sts = inb(BT_CTRL_STAT_PORT); if (sts & BT_DF) break; + delay(10); } - if (i >= wait) { - printf("bt_cmd: bt742a cmd/data port empty %d\n", ocnt); - return (ENXIO); + if (!i) { + printf("bt%d: bt_cmd, cmd/data port empty %d\n", + bt->sc_dev.dv_xname, ocnt); + return ENXIO; } oc = inb(BT_CMD_DATA_PORT); if (retval) @@ -429,19 +513,20 @@ bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) /* * Wait for the board to report a finised instruction */ - i = BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ + i = 100000; /* 1 sec? */ while (--i) { sts = inb(BT_INTR_PORT); - if (sts & BT_HACC) { + if (sts & BT_HACC) break; - } + delay(10); } if (!i) { - printf("bt_cmd: bt742a host not finished(0x%x)\n", sts); - return (ENXIO); + printf("%s: bt_cmd, host not finished(0x%x)\n", + bt->sc_dev.dv_xname, sts); + return ENXIO; } outb(BT_CTRL_STAT_PORT, BT_IRST); - return (0); + return 0; } /* @@ -450,301 +535,414 @@ bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) * as an argument, takes the isa_device structure from * autoconf.c */ -btprobe(dev) - struct isa_device *dev; +int +btprobe(parent, self, aux) + struct device *parent, *self; + void *aux; { - /* - * find unit and check we have that many defined - */ - int unit; - struct bt_data *bt; + struct bt_softc *bt = (void *)self; + register struct isa_attach_args *ia = aux; - if (dev->id_parent) - return 1; +#ifdef NEWCONFIG + if (ia->ia_iobase == IOBASEUNK) + return 0; +#endif + + bt->bt_base = ia->ia_iobase; - dev->id_unit = unit = btunit; - bt = btdata[unit]; - bt_base[unit] = dev->id_iobase; - if (unit >= NBT) { - printf("bt: unit number (%d) too high\n", unit); - return (0); - } /* * Try initialise a unit at this location - * sets up dma and bus speed, loads bt_int[unit]* + * sets up dma and bus speed, loads bt->bt_int */ - if (bt_init(unit) != 0) { - return (0); - } - /* - * If it's there, put in it's interrupt vectors - */ - dev->id_irq = (1 << bt_int[unit]); - dev->id_drq = bt_dma[unit]; + if (bt_find(bt) != 0) + return 0; + +#ifdef NEWCONFIG + /* + * If it's there, put in it's interrupt vectors and dma channel + */ + if (ia->ia_irq == IRQUNK) { + ia->ia_irq = (1 << bt->bt_int); + } else { + if (ia->ia_irq != (1 << bt->bt_int)) { + printf("bt%d: irq mismatch, %x != %x\n", + bt->sc_dev.dv_unit, ia->ia_irq, + 1 << bt->bt_int); + return 0; + } + } + + if (ia->ia_drq == DRQUNK) { + ia->ia_drq = bt->bt_dma; + } else { + if (ia->ia_drq != bt->bt_dma) { + printf("bt%d: drq mismatch, %x != %x\n", + bt->sc_dev.dv_unit, ia->ia_drq, bt->bt_dma); + return 0; + } + } +#endif + + ia->ia_msize = 0; + ia->ia_iosize = 4; + return 1; +} + +btprint() +{ - btunit++; - return (8); } /* * Attach all the sub-devices we can find */ -btattach(dev) - struct isa_device *dev; +void +btattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - static int firsttime; - static int firstswitch[NBT]; - int masunit; - int r; + struct isa_attach_args *ia = aux; + struct bt_softc *bt = (void *)self; - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; + bt_init(bt); - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - bt_switch[masunit].name = "bt"; - bt_switch[masunit].scsi_cmd = bt_scsi_cmd; - bt_switch[masunit].scsi_minphys = btminphys; - bt_switch[masunit].open_target_lu = 0; - bt_switch[masunit].close_target_lu = 0; - bt_switch[masunit].adapter_info = bt_adapter_info; - for (r = 0; r < 8; r++) { - bt_switch[masunit].empty[r] = 0; - bt_switch[masunit].used[r] = 0; - bt_switch[masunit].printed[r] = 0; - } - } - r = scsi_attach(masunit, &bt_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); + /* + * fill in the prototype scsi_link. + */ + bt->sc_link.adapter_softc = bt; + bt->sc_link.adapter_targ = bt->bt_scsi_dev; + bt->sc_link.adapter = &bt_switch; + bt->sc_link.device = &bt_dev; - /* only one for all boards */ - if (firsttime == 0) { - firsttime = 1; - bt_timeout(0); - } - return r; + printf("\n"); + +#ifdef NEWCONFIG + isa_establish(&bt->sc_id, &bt->sc_dev); + bt->sc_ih.ih_fun = btintr; + bt->sc_ih.ih_arg = bt; + /* XXX and DV_TAPE, but either gives us splbio */ + intr_establish(ia->ia_irq, &bt->sc_ih, DV_DISK); +#endif + + /* + * ask the adapter what subunits are present + */ + config_found(self, &bt->sc_link, btprint); } /* - * Return some information to the caller about - * the adapter and it's capabilities + * Return some information to the caller about the adapter and its + * capabilities. */ -long -bt_adapter_info(unit) - int unit; +u_int +bt_adapter_info(bt) + struct bt_softc *bt; { - /* 2 outstanding requests at a time per device */ - return (2); -} + return 2; /* 2 outstanding requests at a time per device */ +} /* * Catch an interrupt from the adaptor */ +int btintr(unit) + int unit; { + struct bt_softc *bt = btcd.cd_devs[unit]; + BT_MBI *wmbi; + struct bt_mbx *wmbx; struct bt_ccb *ccb; - unsigned char stat; - register int i, j; - u_char found_one = 0, done = 0; - struct bt_data *bt = btdata[unit]; + u_char stat; + int i, wait; + int found = 0; - if ((scsi_debug & PRINTROUTINES) || bt_debug) - printf("btintr "); +#ifdef UTEST + printf("btintr "); +#endif /* * First acknowlege the interrupt, Then if it's * not telling about a completed operation - * just return. + * just return. */ stat = inb(BT_INTR_PORT); - outb(BT_CTRL_STAT_PORT, BT_IRST); - if ((scsi_debug & TRACEINTERRUPTS) || bt_debug) - printf("int = 0x%x ", stat); - if (!(stat & BT_MBIF)) - return 1; - if (scsi_debug & TRACEINTERRUPTS) - printf("mbxi "); + /* Mail Box out empty ? */ + if (stat & BT_MBOA) { + printf("%s: Available Free mbo post\n", bt->sc_dev.dv_xname); + /* Disable MBO available interrupt */ + outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN); + wait = 100000; /* 1 sec enough? */ + for (i = wait; i; i--) { + if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) + break; + delay(10); + } + if (i == 0) { + printf("%s: bt_intr, cmd/data port full\n", + bt->sc_dev.dv_xname); + outb(BT_CTRL_STAT_PORT, BT_SRST); + return 1; + } + outb(BT_CMD_DATA_PORT, 0x00); /* Disable */ + wakeup((caddr_t)&bt->bt_mbx); + outb(BT_CTRL_STAT_PORT, BT_IRST); + return 1; + } + if (!(stat & BT_MBIF)) { + outb(BT_CTRL_STAT_PORT, BT_IRST); + return 1; + } /* * If it IS then process the competed operation */ - for (i = bt_last[unit].mbi; !done && (i < BT_MBX_SIZE); i++) { - if (bt->bt_mbx.mbi[i].stat != BT_MBI_FREE) { - found_one++; - for (j = BT_MBX_SIZE - 1; j >= 0; j--) - if (bt_ccb_lut[unit][j].phys_addr == - bt->bt_mbx.mbi[i].ccb_addr) { - ccb = bt_ccb_lut[unit][j]. - kv_addr; - break; - } - if ((bt_debug & BT_SHOWCCBS) && ccb) - printf(" ", ccb, KVTOPHYS(ccb)); - if ((stat = bt->bt_mbx.mbi[i].stat) != BT_MBI_OK) { - switch (stat) { - case BT_MBI_ABORT: - if (bt_debug & BT_SHOWMISC) - printf("abort "); - ccb->host_stat = BT_ABORTED; - break; - case BT_MBI_UNKNOWN: - ccb = (struct bt_ccb *) 0; - if (bt_debug & BT_SHOWMISC) - printf("unknown ccb for abort"); - break; - case BT_MBI_ERROR: - break; - default: - printf("bad mbxi status %d, in mbx at 0x%x (0x%x)\n", - stat, &bt->bt_mbx.mbi[i], - KVTOPHYS(&bt->bt_mbx.mbi[i])); - Debugger(); - } - if ((bt_debug & BT_SHOWCMDS) && ccb) { - u_char *cp; - cp = ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi[%d]\n", - bt->bt_mbx.mbi[i].stat, i); - printf("addr = 0x%x\n", ccb); - } + wmbx = &bt->bt_mbx; + wmbi = wmbx->tmbi; + AGAIN: + while (wmbi->stat != BT_MBI_FREE) { + ccb = bt_ccb_phys_kv(bt, (wmbi->ccb_addr)); + if (!ccb) { + wmbi->stat = BT_MBI_FREE; + printf("bt: BAD CCB ADDR!\n"); + continue; + } + found++; + if ((stat = wmbi->stat) != BT_MBI_OK) { + switch (stat) { + case BT_MBI_ABORT: +#ifdef UTEST + if (bt_debug & BT_SHOWMISC) + printf("abort "); +#endif + ccb->host_stat = BT_ABORTED; + break; + + case BT_MBI_UNKNOWN: + ccb = (struct bt_ccb *) 0; +#ifdef UTEST + if (bt_debug & BT_SHOWMISC) + printf("unknown ccb for abort"); +#endif + break; + + case BT_MBI_ERROR: + break; + + default: + panic("Impossible mbxi status"); + } - if (ccb) { - bt_remove_timeout(ccb); - bt_done(unit, ccb); +#ifdef UTEST + if ((bt_debug & BT_SHOWCMDS) && ccb) { + u_char *cp; + cp = ccb->scsi_cmd; + printf("op=%x %x %x %x %x %x\n", + cp[0], cp[1], cp[2], + cp[3], cp[4], cp[5]); + printf("stat %x for mbi addr = 0x%08x\n" + ,wmbi->stat, wmbi); + printf("addr = 0x%x\n", ccb); } - bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; +#endif + } + wmbi->stat = BT_MBI_FREE; + if (ccb) { + untimeout(bt_timeout, (caddr_t)ccb); + bt_done(bt, ccb); + } + /* Set the IN mail Box pointer for next */ bt_nextmbx(wmbi, wmbx, mbi); + } + if (!found) { + for (i = 0; i < BT_MBX_SIZE; i++) { + if (wmbi->stat != BT_MBI_FREE) { + found++; + break; + } + bt_nextmbx(wmbi, wmbx, mbi); + } + if (!found) { + printf("%s: mbi at 0x%08x should be found, stat=%02x..resync\n", + bt->sc_dev.dv_xname, wmbi, stat); } else { - /* free mailbox -- done if following a used mbi */ - if (found_one) - done++; + found = 0; + goto AGAIN; } } - if (done) { - bt_last[unit].mbi = i % BT_MBX_SIZE; - return (1); - } - for (i = 0; !done && (i < bt_last[unit].mbi); i++) { - if (bt->bt_mbx.mbi[i].stat != BT_MBI_FREE) { - found_one++; - for (j = BT_MBX_SIZE - 1; j >= 0; j--) - if (bt_ccb_lut[unit][j].phys_addr == - bt->bt_mbx.mbi[i].ccb_addr) { - ccb = bt_ccb_lut[unit][j]. - kv_addr; - break; - } - if ((bt_debug & BT_SHOWCCBS) && ccb) - printf(" ", ccb, KVTOPHYS(ccb)); - if ((stat = bt->bt_mbx.mbi[i].stat) != BT_MBI_OK) { - switch (stat) { - case BT_MBI_ABORT: - if (bt_debug & BT_SHOWMISC) - printf("abort "); - ccb->host_stat = BT_ABORTED; - break; - case BT_MBI_UNKNOWN: - ccb = (struct bt_ccb *) 0; - if (bt_debug & BT_SHOWMISC) - printf("unknown ccb for abort"); - break; - case BT_MBI_ERROR: - break; - default: - printf("bad mbxi status %d, in mbx at 0x%x (0x%x)\n", - stat, &bt->bt_mbx.mbi[i], - KVTOPHYS(&bt->bt_mbx.mbi[i])); - Debugger(); - } - if ((bt_debug & BT_SHOWCMDS) && ccb) { - u_char *cp; - cp = ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi[%d]\n", - bt->bt_mbx.mbi[i].stat, i); - printf("addr = 0x%x\n", ccb); - } - } - if (ccb) { - bt_remove_timeout(ccb); - bt_done(unit, ccb); - } - bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; - } else { - /* free mailbox -- done if following a used mbi */ - if (found_one) - done++; - } - } - bt_last[unit].mbi = i % BT_MBX_SIZE; - return (1); + wmbx->tmbi = wmbi; + outb(BT_CTRL_STAT_PORT, BT_IRST); + return 1; } /* - * A ccb (and hence a mbx-out is put onto the - * free list. + * A ccb is put onto the free list. */ -bt_free_ccb(unit, ccb, flags) +void +bt_free_ccb(bt, ccb, flags) + struct bt_softc *bt; struct bt_ccb *ccb; + int flags; { - unsigned int opri; - struct bt_data *bt = btdata[unit]; + int opri; - if (scsi_debug & PRINTROUTINES) - printf("ccb%d(0x%x)> ", unit, flags); if (!(flags & SCSI_NOMASK)) opri = splbio(); + ccb->next = bt->bt_ccb_free; + bt->bt_ccb_free = ccb; ccb->flags = CCB_FREE; /* - * If there were none, wake abybody waiting for - * one to come free, starting with queued entries + * If there were none, wake anybody waiting for one to come free, + * starting with queued entries. */ - if (bt->sleepers) { - bt->sleepers = 0; - wakeup((caddr_t) & bt->sleepers); - } + if (!ccb->next) + wakeup((caddr_t)&bt->bt_ccb_free); + if (!(flags & SCSI_NOMASK)) splx(opri); } /* - * Get a free ccb (and hence mbox-out entry) + * Get a free ccb + * + * If there are none, see if we can allocate a new one. If so, put it in + * the hash table too otherwise either return an error or sleep. */ struct bt_ccb * -bt_get_ccb(unit, flags) +bt_get_ccb(bt, flags) + struct bt_softc *bt; + int flags; { - unsigned int opri; - struct bt_ccb *rc = NULL; - struct bt_data *bt = btdata[unit]; - int next_mbx = bt_last[unit].mbo; + int opri; + struct bt_ccb *ccbp; + struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ + BT_MBO *wmbo; /* Out Mail Box pointer */ + int hashnum; - if (scsi_debug & PRINTROUTINES) - printf("bt_ccb[next_mbx].flags == CCB_FREE) && - !(flags & SCSI_NOSLEEP)) { - bt->sleepers = 1; - sleep((caddr_t) & bt->sleepers, PRIBIO); + while (!(ccbp = bt->bt_ccb_free)) { + if (bt->numccbs < BT_CCB_MAX) { + if (ccbp = (struct bt_ccb *) malloc(sizeof(struct bt_ccb), + M_TEMP, + M_NOWAIT)) { + bzero(ccbp, sizeof(struct bt_ccb)); + bt->numccbs++; + ccbp->flags = CCB_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + ccbp->hashkey = KVTOPHYS(ccbp); + hashnum = CCB_HASH(ccbp->hashkey); + ccbp->nexthash = bt->ccbhash[hashnum]; + bt->ccbhash[hashnum] = ccbp; + } else { + printf("%s: Can't malloc CCB\n", + bt->sc_dev.dv_xname); + } + goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) { + tsleep((caddr_t)&bt->bt_ccb_free, PRIBIO, + "btccb", 0); + } + } } - if (bt->bt_ccb[next_mbx].flags == CCB_FREE) { - rc = &bt->bt_ccb[next_mbx]; - bt_last[unit].mbo = (bt_last[unit].mbo + 1) % BT_MBX_SIZE; - rc->flags = CCB_ACTIVE; + if (ccbp) { + /* Get CCB from from free list */ + bt->bt_ccb_free = ccbp->next; + ccbp->flags = CCB_ACTIVE; } + gottit: + if (!(flags & SCSI_NOMASK)) + splx(opri); + + return ccbp; +} + +/* + * given a physical address, find the ccb that + * it corresponds to: + */ +struct bt_ccb * +bt_ccb_phys_kv(bt, ccb_phys) + struct bt_softc *bt; + physaddr ccb_phys; +{ + int hashnum = CCB_HASH(ccb_phys); + struct bt_ccb *ccbp = bt->ccbhash[hashnum]; + + while (ccbp) { + if (ccbp->hashkey == ccb_phys) + break; + ccbp = ccbp->nexthash; + } + return ccbp; +} + +/* + * Get a MBO and then Send it + */ +BT_MBO * +bt_send_mbo(bt, flags, cmd, ccb) + struct bt_softc *bt; + int flags, cmd; + struct bt_ccb *ccb; +{ + int opri; + BT_MBO *wmbo; /* Mail Box Out pointer */ + struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ + int i, wait; + + wmbx = &bt->bt_mbx; + + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + + /* Get the Target OUT mail Box pointer and move to Next */ + wmbo = wmbx->tmbo; + wmbx->tmbo = (wmbo == &(wmbx->mbo[BT_MBX_SIZE - 1]) ? + &(wmbx->mbo[0]) : wmbo + 1); + + /* + * Check the outmail box is free or not. + * Note: Under the normal operation, it shuld NOT happen to wait. + */ + while (wmbo->cmd != BT_MBO_FREE) { + wait = 100000; /* 1 sec enough? */ + /* Enable MBO available interrupt */ + outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN); + for (i = wait; i; i--) { + if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) + break; + delay(10); + } + if (!i) { + printf("%s: bt_send_mbo, cmd/data port full\n", + bt->sc_dev.dv_xname); + outb(BT_CTRL_STAT_PORT, BT_SRST); + return NULL; + } + outb(BT_CMD_DATA_PORT, 0x01); /* Enable */ + tsleep((caddr_t)wmbx, PRIBIO, "btsnd", 0);/*XXX can't do this */ + /* May be servicing an int */ + } + /* Link CCB to the Mail Box */ + wmbo->ccb_addr = KVTOPHYS(ccb); + ccb->mbx = wmbo; + wmbo->cmd = cmd; + + /* Send it! */ + outb(BT_CMD_DATA_PORT, BT_START_SCSI); + if (!(flags & SCSI_NOMASK)) splx(opri); - return (rc); + + return wmbo; } /* @@ -752,21 +950,20 @@ bt_get_ccb(unit, flags) * adaptor, now we look to see how the operation * went. Wake up the owner if waiting */ -bt_done(unit, ccb) +void +bt_done(bt, ccb) + struct bt_softc *bt; struct bt_ccb *ccb; { struct scsi_sense_data *s1, *s2; struct scsi_xfer *xs = ccb->xfer; - struct bt_data *bt = btdata[unit]; - if (scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("bt_done "); + SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_done\n")); /* * Otherwise, put the results of the operation * into the xfer and call whoever started it */ - if ((ccb->host_stat != BT_OK - || ccb->target_stat != SCSI_OK) + if ((ccb->host_stat != BT_OK || ccb->target_stat != SCSI_OK) && (!(xs->flags & SCSI_ERR_OK))) { s1 = &(ccb->scsi_sense); @@ -776,19 +973,16 @@ bt_done(unit, ccb) switch (ccb->host_stat) { case BT_ABORTED: /* No response */ case BT_SEL_TIMEOUT: /* No response */ - if (bt_debug & BT_SHOWMISC) { - printf("timeout reported back\n"); - } + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("timeout reported back\n")); xs->error = XS_TIMEOUT; break; default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; - if (bt_debug & BT_SHOWMISC) { - printf("unexpected host_stat: %x\n", - ccb->host_stat); - } + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected host_stat: %x\n", + ccb->host_stat)); } - } else { switch (ccb->target_stat) { case 0x02: @@ -799,10 +993,9 @@ bt_done(unit, ccb) xs->error = XS_BUSY; break; default: - if (bt_debug & BT_SHOWMISC) { - printf("unexpected target_stat: %x\n", - ccb->target_stat); - } + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected target_stat: %x\n", + ccb->target_stat)); xs->error = XS_DRIVER_STUFFUP; } } @@ -810,201 +1003,218 @@ bt_done(unit, ccb) xs->resid = 0; } xs->flags |= ITSDONE; - bt_free_ccb(unit, ccb, xs->flags); - if (xs->when_done) - (*(xs->when_done)) (xs->done_arg, xs->done_arg2); + bt_free_ccb(bt, ccb, xs->flags); + scsi_done(xs); +} + +/* + * Find the board and find it's irq/drq + */ +int +bt_find(bt) + struct bt_softc *bt; +{ + u_char ad[4]; + volatile int i, sts; + struct bt_config conf; + + /* + * reset board, If it doesn't respond, assume + * that it's not there.. good for the probe + */ + + outb(BT_CTRL_STAT_PORT, BT_HRST | BT_SRST); + + for (i = BT_RESET_TIMEOUT; i; i--) { + sts = inb(BT_CTRL_STAT_PORT); + if (sts == (BT_IDLE | BT_INIT)) + break; + delay(1000); + } + if (!i) { +#ifdef UTEST + printf("bt_find: No answer from bt742a board\n"); +#endif + return ENXIO; + } + + /* + * Assume we have a board at this stage setup dma channel from + * jumpers and save int level + */ + delay(1000); + bt_cmd(bt, 0, sizeof(conf), 0, &conf, BT_CONF_GET); + switch (conf.chan) { + case EISADMA: + bt->bt_dma = -1; + break; + case CHAN0: + outb(0x0b, 0x0c); + outb(0x0a, 0x00); + bt->bt_dma = 0; + break; + case CHAN5: + outb(0xd6, 0xc1); + outb(0xd4, 0x01); + bt->bt_dma = 5; + break; + case CHAN6: + outb(0xd6, 0xc2); + outb(0xd4, 0x02); + bt->bt_dma = 6; + break; + case CHAN7: + outb(0xd6, 0xc3); + outb(0xd4, 0x03); + bt->bt_dma = 7; + break; + default: + printf("illegal dma setting %x\n", conf.chan); + return EIO; + } + + switch (conf.intr) { + case INT9: + bt->bt_int = 9; + break; + case INT10: + bt->bt_int = 10; + break; + case INT11: + bt->bt_int = 11; + break; + case INT12: + bt->bt_int = 12; + break; + case INT14: + bt->bt_int = 14; + break; + case INT15: + bt->bt_int = 15; + break; + default: + printf("illegal int setting %x\n", conf.intr); + return EIO; + } + + /* who are we on the scsi bus? */ + bt->bt_scsi_dev = conf.scsi_dev; + + return 0; } /* * Start the board, ready for normal operation */ -bt_init(unit) - int unit; +void +bt_init(bt) + struct bt_softc *bt; { - unsigned char ad[4]; - volatile int i, sts; - struct bt_config conf; - struct bt_data *bt; + u_char ad[4]; + volatile int i; /* - * reset board, If it doesn't respond, assume - * that it's not there.. good for the probe - */ - outb(BT_CTRL_STAT_PORT, BT_HRST | BT_SRST); - - for (i = 0; i < BT_RESET_TIMEOUT; i++) { - sts = inb(BT_CTRL_STAT_PORT); - if (sts == (BT_IDLE | BT_INIT)) - break; - } - if (i >= BT_RESET_TIMEOUT) { - if (bt_debug & BT_SHOWMISC) - printf("bt_init: No answer from bt742a board\n"); - return (ENXIO); - } - - /* - * Assume we have a board at this stage - * setup dma channel from jumpers and save int - * level - */ - delay(200); - - bt_cmd(unit, 0, sizeof(conf), 0, &conf, BT_CONF_GET); - switch (conf.chan) { - case EISADMA: - bt_dma[unit] = -1; - break; - case CHAN0: - outb(0x0b, 0x0c); - outb(0x0a, 0x00); - bt_dma[unit] = 0; - break; - case CHAN5: - outb(0xd6, 0xc1); - outb(0xd4, 0x01); - bt_dma[unit] = 5; - break; - case CHAN6: - outb(0xd6, 0xc2); - outb(0xd4, 0x02); - bt_dma[unit] = 6; - break; - case CHAN7: - outb(0xd6, 0xc3); - outb(0xd4, 0x03); - bt_dma[unit] = 7; - break; - default: - printf("illegal dma setting %x\n", conf.chan); - return (EIO); - } - switch (conf.intr) { - case INT9: - bt_int[unit] = 9; - break; - case INT10: - bt_int[unit] = 10; - break; - case INT11: - bt_int[unit] = 11; - break; - case INT12: - bt_int[unit] = 12; - break; - case INT14: - bt_int[unit] = 14; - break; - case INT15: - bt_int[unit] = 15; - break; - default: - printf("illegal int setting\n"); - return (EIO); - } - /* who are we on the scsi bus */ - bt_switch[unit].scsi_dev = conf.scsi_dev; - - printf("bt%d: mbx (%d@) %d, ccb %d * %d, xs %d, bt %d bytes\n", unit, - BT_MBX_SIZE, sizeof(struct bt_mbx), - BT_MBX_SIZE, sizeof(struct bt_ccb), - sizeof(struct scsi_xfer), sizeof(struct bt_data)); - bt = malloc(sizeof(struct bt_data), M_DEVBUF, M_NOWAIT); - if (!bt) { - printf("bt%d: cannot malloc buffers\n", unit); - return (0); - } - if (bt_debug) - printf("bt%d: buffer allocated at 0x%x (0x%x)\n", - unit, bt, KVTOPHYS(bt)); - bzero(bt, sizeof(struct bt_data)); - btdata[unit] = bt; - - /* - * Initialize mail box + * Initialize mail box */ *((physaddr *) ad) = KVTOPHYS(&bt->bt_mbx); - if (bt_debug) { - printf("bt%d: mailbox struct at 0x%x (0x%x)\n", - unit, &bt->bt_mbx, *(physaddr *) ad); - printf("bt%d: ccb struct at 0x%x (0x%x)\n", - unit, bt->bt_ccb, KVTOPHYS(bt->bt_ccb)); - printf("bt%d: xs struct at 0x%x (0x%x)\n", - unit, &bt->bt_scsi_xfer, KVTOPHYS(&bt->bt_scsi_xfer)); - printf("bt%d: sleepers at 0x%x (0x%x)\n", - unit, &bt->sleepers, KVTOPHYS(&bt->sleepers)); - } - bt_cmd(unit, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED, BT_MBX_SIZE, - ad[0], ad[1], ad[2], ad[3]); + + bt_cmd(bt, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED, + BT_MBX_SIZE, ad[0], ad[1], ad[2], ad[3]); /* - * link the ccb's with the mbox-out entries and - * into a free-list + * Set Pointer chain null for just in case + * Link the ccb's into a free-list W/O mbox + * Initialize mail box status to free */ - bt_last[unit].mbo = bt_last[unit].mbi = 0; - for (i = 0; i < (BT_MBX_SIZE - 1); i++) { - bt->bt_ccb[i].next = &bt->bt_ccb[i + 1]; - bt->bt_ccb[i].flags = CCB_FREE; - bt->bt_ccb[i].mbx = &bt->bt_mbx.mbo[i]; - bt->bt_mbx.mbo[i].ccb_addr = KVTOPHYS(&bt->bt_ccb[i]); - bt_ccb_lut[unit][i].kv_addr = &bt->bt_ccb[i]; - bt_ccb_lut[unit][i].phys_addr = - bt->bt_mbx.mbo[i].ccb_addr; + if (bt->bt_ccb_free) { + printf("%s: bt_ccb_free is NOT initialized but init here\n", + bt->sc_dev.dv_xname); + bt->bt_ccb_free = NULL; + } + for (i = 0; i < BT_MBX_SIZE; i++) { + bt->bt_mbx.mbo[i].cmd = BT_MBO_FREE; + bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; } - bt->bt_ccb[i].next = &bt->bt_ccb[0]; /* loop around to first ccb */ - bt->bt_ccb[i].flags = CCB_FREE; - bt->bt_ccb[i].mbx = &bt->bt_mbx.mbo[i]; - bt->bt_mbx.mbo[i].ccb_addr = KVTOPHYS(&bt->bt_ccb[i]); - bt_ccb_lut[unit][i].kv_addr = &bt->bt_ccb[i]; - bt_ccb_lut[unit][i].phys_addr = - bt->bt_mbx.mbo[i].ccb_addr; /* - * Note that we are going and return (to probe) + * Set up initial mail box for round-robin operation. */ - bt_initialized[unit]++; - return (0); + bt->bt_mbx.tmbo = &bt->bt_mbx.mbo[0]; + bt->bt_mbx.tmbi = &bt->bt_mbx.mbi[0]; + bt_inquire_setup_information(bt); + + /* Enable round-robin scheme - appeared at firmware rev. 3.31 */ + bt_cmd(bt, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE); } - -#ifndef min -#define min(x,y) (x < y ? x : y) -#endif /* min */ - void +bt_inquire_setup_information(bt) + struct bt_softc *bt; +{ + struct bt_setup setup; + struct bt_boardID bID; + int i; + + /* Inquire Board ID to Bt742 for firmware version */ + bt_cmd(bt, 0, sizeof(bID), 0, &bID, BT_INQUIRE); + printf(": version %c.%c, ", bt->sc_dev.dv_xname, + bID.firm_revision, bID.firm_version); + + /* Obtain setup information from Bt742. */ + bt_cmd(bt, 1, sizeof(setup), 0, &setup, BT_SETUP_GET, sizeof(setup)); + + if (setup.sync_neg) + printf("sync, "); + else + printf("async, "); + if (setup.parity) + printf("parity, "); + else + printf("no parity, "); + printf("%d mbxs", setup.num_mbx); + + for (i = 0; i < 8; i++) { + if (!setup.sync[i].offset && + !setup.sync[i].period && + !setup.sync[i].valid) + continue; + + printf("%s: dev%02d Offset=%d, Transfer period=%d, Synchronous? %s", + bt->sc_dev.dv_xname, i, + setup.sync[i].offset, setup.sync[i].period, + setup.sync[i].valid ? "Yes" : "No"); + } +} + +void btminphys(bp) struct buf *bp; { - if (bp->b_bcount > ((BT_NSEG - 1) * PAGESIZ)) { - bp->b_bcount = ((BT_NSEG - 1) * PAGESIZ); - } + + if (bp->b_bcount > ((BT_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((BT_NSEG - 1) << PGSHIFT); } /* - * start a scsi operation given the command and the - * data address. Also needs the unit, target and lu + * start a scsi operation given the command and the data address. Also needs + * the unit, target and lu. */ -int +int bt_scsi_cmd(xs) struct scsi_xfer *xs; { - struct scsi_sense_data *s1, *s2; + struct scsi_link *sc_link = xs->sc_link; + struct bt_softc *bt = sc_link->adapter_softc; struct bt_ccb *ccb; struct bt_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; + int seg; /* scatter gather seg being worked on */ + int thiskv; physaddr thisphys, nextphys; - int unit = xs->adapter; - int bytes_this_seg, bytes_this_page, datalen, flags; + int bytes_this_seg, bytes_this_page, datalen, flags; struct iovec *iovp; - struct bt_data *bt = btdata[unit]; - int done, count; - - if (scsi_debug & PRINTROUTINES) - printf("bt_scsi_cmd "); + BT_MBO *mbo; + SC_DEBUG(sc_link, SDEV_DB2, ("bt_scsi_cmd\n")); /* * get a ccb (mbox-out) to use. If the transfer * is from a buf (possibly from interrupt time) @@ -1014,23 +1224,19 @@ bt_scsi_cmd(xs) if (xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ if (flags & ITSDONE) { - printf("Already done?"); + printf("%s: Already done?\n", bt->sc_dev.dv_xname); xs->flags &= ~ITSDONE; } if (!(flags & INUSE)) { - printf("Not in use?"); + printf("%s: Not in use?\n", bt->sc_dev.dv_xname); xs->flags |= INUSE; } - if (!(ccb = bt_get_ccb(unit, flags))) { + if (!(ccb = bt_get_ccb(bt, flags))) { xs->error = XS_DRIVER_STUFFUP; - return (TRY_AGAIN_LATER); + return TRY_AGAIN_LATER; } - if (bt_debug & BT_SHOWCCBS) - printf("", ccb, KVTOPHYS(ccb)); - if (ccb->mbx->cmd != BT_MBO_FREE) - printf("MBO not free (%x(%x))\n", - ccb->mbx, KVTOPHYS(ccb->mbx)); - + SC_DEBUG(sc_link, SDEV_DB3, + ("start ccb(%x)\n", ccb)); /* * Put all the arguments for the xfer in the ccb */ @@ -1039,44 +1245,45 @@ bt_scsi_cmd(xs) ccb->opcode = BT_RESET_CCB; } else { /* can't use S/G if zero length */ - ccb->opcode = (xs->datalen ? BT_INIT_SCAT_GATH_CCB : - BT_INITIATOR_CCB); + ccb->opcode = (xs->datalen ? BT_INIT_SCAT_GATH_CCB + : BT_INITIATOR_CCB); } - ccb->target = xs->targ;; + ccb->target = sc_link->target; ccb->data_out = 0; ccb->data_in = 0; - ccb->lun = xs->lu; + ccb->lun = sc_link->lun; ccb->scsi_cmd_length = xs->cmdlen; ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense)); ccb->req_sense_length = sizeof(ccb->scsi_sense); if ((xs->datalen) && (!(flags & SCSI_RESET))) { - /* can use S/G only if not zero length */ ccb->data_addr = KVTOPHYS(ccb->scat_gath); sg = ccb->scat_gath; seg = 0; +#ifdef TFS if (flags & SCSI_DATA_UIO) { iovp = ((struct uio *) xs->data)->uio_iov; datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while (datalen && (seg < BT_NSEG)) { + while ((datalen) && (seg < BT_NSEG)) { sg->seg_addr = (physaddr) iovp->iov_base; xs->datalen += sg->seg_len = iovp->iov_len; - if (scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)", - iovp->iov_len, - iovp->iov_base); + SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } else { + } else +#endif /* TFS */ + { /* * Set up the scatter gather block */ - if (scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ", xs->datalen, xs->data); + + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); datalen = xs->datalen; thiskv = (int) xs->data; thisphys = KVTOPHYS(thiskv); @@ -1087,56 +1294,55 @@ bt_scsi_cmd(xs) /* put in the base address */ sg->seg_addr = thisphys; - if (scsi_debug & SHOWSCATGATH) - printf("0x%x", thisphys); + SC_DEBUGN(sc_link, SDEV_DB4, + ("0x%x", thisphys)); /* do it at least once */ nextphys = thisphys; while ((datalen) && (thisphys == nextphys)) { /* - * This page is contiguous (physically) with - * the the last, just extend the length - * how far to the end of the page + * This page is contiguous (physically) + * with the the last, just extend the + * length */ - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; + /* how far to the end of the page */ + nextphys = (thisphys & ~PGOFSET) + NBPG; bytes_this_page = nextphys - thisphys; /**** or the data ****/ bytes_this_page = min(bytes_this_page, - datalen); + datalen); bytes_this_seg += bytes_this_page; datalen -= bytes_this_page; /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; + thiskv = (thiskv & ~PGOFSET) + NBPG; if (datalen) thisphys = KVTOPHYS(thiskv); } - /* * next page isn't contiguous, finish the seg */ - if (scsi_debug & SHOWSCATGATH) - printf("(0x%x)", bytes_this_seg); + SC_DEBUGN(sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); sg->seg_len = bytes_this_seg; sg++; seg++; } - } /* end of iov/kv decision */ - ccb->data_length = seg * sizeof(struct bt_scat_gath); - if (scsi_debug & SHOWSCATGATH) - printf("\n"); - if (datalen) { - /* there's still data, must have run out of segs! */ - printf("bt_scsi_cmd%d: more than %d DMA segs\n", - unit, BT_NSEG); - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(unit, ccb, flags); - return (HAD_ERROR); } - } else { - /* No data xfer, use non S/G values */ + /* end of iov/kv decision */ + ccb->data_length = seg * sizeof(struct bt_scat_gath); + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); + if (datalen) { + /* + * there's still data, must have run out of segs! + */ + printf("%s: bt_scsi_cmd, more than %d DMA segs\n", + bt->sc_dev.dv_xname, BT_NSEG); + xs->error = XS_DRIVER_STUFFUP; + bt_free_ccb(bt, ccb, flags); + return HAD_ERROR; + } + } else { /* No data xfer, use non S/G values */ ccb->data_addr = (physaddr) 0; ccb->data_length = 0; } @@ -1146,270 +1352,168 @@ bt_scsi_cmd(xs) /* * Put the scsi command in the ccb and start it */ - if (!(flags & SCSI_RESET)) { + if (!(flags & SCSI_RESET)) bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length); + if (bt_send_mbo(bt, flags, BT_MBO_START, ccb) == (BT_MBO *) 0) { + xs->error = XS_DRIVER_STUFFUP; + bt_free_ccb(bt, ccb, flags); + return TRY_AGAIN_LATER; } - if (scsi_debug & SHOWCOMMANDS) { - u_char *b = ccb->scsi_cmd; - if (!(flags & SCSI_RESET)) { - int i = 0; - printf("bt%d:%d:%d-", unit, ccb->target, ccb->lun); - while (i < ccb->scsi_cmd_length) { - if (i) - printf(","); - printf("%x", b[i++]); - } - printf("-\n"); - } else - printf("bt%d:%d:%d-RESET- ", unit, ccb->target, ccb->lun); - } - bt_startmbx(ccb->mbx); /* * Usually return SUCCESSFULLY QUEUED */ - if (scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); if (!(flags & SCSI_NOMASK)) { - bt_add_timeout(ccb, xs->timeout); - return (SUCCESSFULLY_QUEUED); + timeout(bt_timeout, (caddr_t)ccb, (xs->timeout * hz) / 1000); + return SUCCESSFULLY_QUEUED; } /* * If we can't use interrupts, poll on completion */ - done = 0; - count = delaycount * xs->timeout / BT_SCSI_TIMEOUT_FUDGE; - - if (scsi_debug & TRACEINTERRUPTS) - printf("wait "); - while ((!done) && count) { - i = 0; - while (!done && i < BT_MBX_SIZE) { - struct bt_ccb *mbx_ccb = NULL; - int j; - - for (j = BT_MBX_SIZE - 1; j >= 0; j--) - if (bt_ccb_lut[unit][j].phys_addr == - bt->bt_mbx.mbi[i].ccb_addr) { - mbx_ccb = bt_ccb_lut[unit][j].kv_addr; - break; - } - if ((bt->bt_mbx.mbi[i].stat != BT_MBI_FREE) && - mbx_ccb == ccb) { - bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; - bt_done(unit, ccb); - done++; - } - i++; - } - count--; - } - if (!count) { - if (!(xs->flags & SCSI_SILENT)) - printf("cmd fail\n"); - bt_abortmbx(ccb->mbx); - count = delaycount * 2000 / BT_SCSI_TIMEOUT_FUDGE; - while (!done && count) { - i = 0; - while (!done && i < BT_MBX_SIZE) { - struct bt_ccb *mbx_ccb = NULL; - int j; - - for (j = BT_MBX_SIZE - 1; j >= 0; j--) - if (bt_ccb_lut[unit][j].phys_addr == - bt->bt_mbx.mbi[i].ccb_addr) { - mbx_ccb = bt_ccb_lut[unit][j].kv_addr; - break; - } - if ((bt->bt_mbx.mbi[i].stat != - BT_MBI_FREE) && mbx_ccb == ccb) { - bt->bt_mbx.mbi[i].stat = - BT_MBI_FREE; - bt_done(unit, ccb); - done++; - } - i++; - } - count--; - } - if (!count) { - printf("abort failed in wait\n"); - ccb->mbx->cmd = BT_MBO_FREE; - } - bt_free_ccb(unit, ccb, flags); - btintr(unit); - xs->error = XS_DRIVER_STUFFUP; - return (HAD_ERROR); - } - btintr(unit); - if (xs->error) - return (HAD_ERROR); - return (COMPLETE); + return bt_poll(bt, xs, ccb); } /* - * +----------+ +----------+ +----------+ - * bt_soonest--->| later |---->| later|---->| later|--->0 - * | [Delta] | | [Delta] | | [Delta] | - * 0<-----|sooner |<----|sooner |<----|sooner |<----bt_latest - * +----------+ +----------+ +----------+ - * - * bt_furthest = sum(Delta[1..n]) + * Poll a particular unit, looking for a particular xs */ -bt_add_timeout(ccb, time) - struct bt_ccb *ccb; - int time; -{ - int timeprev; - struct bt_ccb *prev; - int s = splbio(); - - prev = bt_latest; - if (prev) - timeprev = bt_furthest; - else - timeprev = 0; - - while (prev && (timeprev > time)) { - timeprev -= prev->delta; - prev = prev->sooner; - } - if (prev) { - ccb->delta = time - timeprev; - if (ccb->later = prev->later) { /* yes an assign */ - ccb->later->sooner = ccb; - ccb->later->delta -= ccb->delta; - } else { - bt_furthest = time; - bt_latest = ccb; - } - ccb->sooner = prev; - prev->later = ccb; - } else { - if (ccb->later = bt_soonest) { /* yes, an assign */ - ccb->later->sooner = ccb; - ccb->later->delta -= time; - } else { - bt_furthest = time; - bt_latest = ccb; - } - ccb->delta = time; - ccb->sooner = (struct bt_ccb *) 0; - bt_soonest = ccb; - } - splx(s); -} - -bt_remove_timeout(ccb) +int +bt_poll(bt, xs, ccb) + struct bt_softc *bt; + struct scsi_xfer *xs; struct bt_ccb *ccb; { - int s = splbio(); + int done = 0; + int count = xs->timeout; + u_char stat; - if (ccb->sooner) - ccb->sooner->later = ccb->later; - else - bt_soonest = ccb->later; - - if (ccb->later) { - ccb->later->sooner = ccb->sooner; - ccb->later->delta += ccb->delta; - } else { - bt_latest = ccb->sooner; - bt_furthest -= ccb->delta; - } - ccb->sooner = ccb->later = (struct bt_ccb *) 0; - splx(s); -} - - -extern int hz; -/* #define ONETICK 500 /* milliseconds */ -#define ONETICK 250 /* milliseconds */ -#define SLEEPTIME ((hz * 1000) / ONETICK) - -bt_timeout(arg) - int arg; -{ - struct bt_ccb *ccb; - int unit; - int s = splbio(); - - while (ccb = bt_soonest) { - if (ccb->delta <= ONETICK) { - /* - * It has timed out, we need to do some work - */ - unit = ccb->xfer->adapter; - btintr(unit); - printf("bt%d:%d device timed out\n", unit, - ccb->xfer->targ); - if (bt_debug & BT_SHOWCCBS) - tfs_print_active_ccbs(); - - /* - * Unlink it from the queue - */ - bt_remove_timeout(ccb); - - /* - * If The ccb's mbx is not free, then - * the board has gone south - */ - if (ccb->mbx->cmd != BT_MBO_FREE) { - printf("bt%d not taking commands!\n", unit); - printf("bt: ccb->mbx->cmd = %x\n", - ccb->mbx->cmd); - tfs_print_ccb(ccb); - Debugger(); - } - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if (ccb->flags == CCB_ABORTED) { /* abort timed out */ - printf("AGAIN"); - ccb->xfer->retries = 0; /* I MEAN IT ! */ - ccb->host_stat = BT_ABORTED; - bt_done(unit, ccb); - } else {/* abort the operation that has timed out */ - printf("abort mbx\n"); - bt_abortmbx(ccb->mbx); - /* 2 secs for the abort */ - bt_add_timeout(ccb, 2000 + ONETICK); - ccb->flags = CCB_ABORTED; - } - } else { - /* - * It has not timed out, adjust and leave - */ - ccb->delta -= ONETICK; - bt_furthest -= ONETICK; + /* timeouts are in msec, so we loop in 1000 usec cycles */ + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + stat = inb(BT_INTR_PORT); + if (stat & BT_ANY_INTR) + btintr(bt->sc_dev.dv_unit); + if (xs->flags & ITSDONE) break; + delay(1000); /* only happens in boot so ok */ + count--; + } + if (!count) { + /* + * We timed out, so call the timeout handler manually, + * accounting for the fact that the clock is not running yet + * by taking out the clock queue entry it makes. + */ + bt_timeout((caddr_t)ccb); + + /* + * because we are polling, take out the timeout entry + * bt_timeout made + */ + untimeout(bt_timeout, (caddr_t)ccb); + count = 2000; + while (count) { + /* + * Once again, wait for the int bit + */ + stat = inb(BT_INTR_PORT); + if (stat & BT_ANY_INTR) + btintr(bt->sc_dev.dv_unit); + if (xs->flags & ITSDONE) + break; + delay(1000); /* only happens in boot so ok */ + count--; + } + if (!count) { + /* + * We timed out again... This is bad. Notice that + * this time there is no clock queue entry to remove. + */ + bt_timeout((caddr_t)ccb); } } - splx(s); - timeout((timeout_t) bt_timeout, (caddr_t) arg, SLEEPTIME); + if (xs->error) + return HAD_ERROR; + return COMPLETE; } -tfs_print_ccb(ccb) +void +bt_timeout(arg) + caddr_t arg; +{ + int s = splbio(); + struct bt_ccb *ccb = (void *)arg; + struct bt_softc *bt; + + bt = ccb->xfer->sc_link->adapter_softc; + sc_print_addr(ccb->xfer->sc_link); + printf("timed out "); + +#ifdef UTEST + bt_print_active_ccbs(bt); +#endif + + /* + * If the ccb's mbx is not free, then the board has gone Far East? + */ + if (bt_ccb_phys_kv(bt, ccb->mbx->ccb_addr) == ccb && + ccb->mbx->cmd != BT_MBO_FREE) { + printf("%s: not taking commands!\n", bt->sc_dev.dv_xname); + Debugger(); + } + + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (ccb->flags == CCB_ABORTED) { + /* abort timed out */ + printf("AGAIN\n"); + ccb->xfer->retries = 0; /* I MEAN IT ! */ + ccb->host_stat = BT_ABORTED; + bt_done(bt, ccb); + } else { /* abort the operation that has timed out */ + printf("\n"); + bt_send_mbo(bt, ~SCSI_NOMASK, BT_MBO_ABORT, ccb); + /* 2 secs for the abort */ + timeout(bt_timeout, (caddr_t)ccb, 2 * hz); + ccb->flags = CCB_ABORTED; + } + splx(s); +} + +#ifdef UTEST +void +bt_print_ccb(ccb) struct bt_ccb *ccb; { - printf("ccb:%x op:%x cmdlen:%d senlen:%d\n", ccb, ccb->opcode, - ccb->scsi_cmd_length, ccb->req_sense_length); - printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n", - ccb->data_length, ccb->host_stat, ccb->target_stat, - ccb->delta, ccb->flags); + + printf("ccb:%x op:%x cmdlen:%d senlen:%d\n", + ccb, ccb->opcode, ccb->scsi_cmd_length, ccb->req_sense_length); + printf(" datlen:%d hstat:%x tstat:%x flags:%x\n", + ccb->data_length, ccb->host_stat, ccb->target_stat, ccb->flags); } -tfs_print_active_ccbs() +void +bt_print_active_ccbs(bt) + struct bt_softc *bt; { - struct bt_ccb *ccb = bt_soonest; + struct bt_ccb *ccb; + int i = 0; - while (ccb) { - tfs_print_ccb(ccb); - ccb = ccb->later; + while (i < CCB_HASH_SIZE) { + ccb = bt->ccbhash[i]; + while (ccb) { + if (ccb->flags != CCB_FREE) + bt_print_ccb(ccb); + ccb = ccb->nexthash; + } + i++; } - printf("Furthest = %d\n", bt_furthest); } +#endif /*UTEST */ diff --git a/sys/arch/i386/isa/ultra14f.c b/sys/arch/i386/isa/ultra14f.c index 7e314763fc7e..a8dba429d88e 100644 --- a/sys/arch/i386/isa/ultra14f.c +++ b/sys/arch/i386/isa/ultra14f.c @@ -1,8 +1,40 @@ +/* + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: ultra14f.c,v 1.25 1994/03/29 04:30:26 mycroft Exp $ + */ + /* * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu) + * Slight fixes to timeouts to run with the 34F * Thanks to Julian Elischer for advice and help with this port. * - * Written by Julian Elischer (julian@tfs.com) + * Originally written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -15,988 +47,967 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * $Id: ultra14f.c,v 1.24 1994/03/25 07:40:57 mycroft Exp $ + * commenced: Sun Sep 27 18:14:01 PDT 1992 + * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993 */ - -#include -#include +#include #include #include +#include #include #include +#include +#include #include #include #include -#ifdef MACH /* EITHER CMU OR OSF */ -#include -#include -#include - -#ifdef OSF /* OSF ONLY */ -#include -#include -#include -#include - -#else OSF /* CMU ONLY */ -#include -#include -#endif OSF -#endif MACH /* end of MACH specific */ - -#ifdef __NetBSD__ /* NetBSD specific */ -#include #include -#include + +#include +#include + #include #include -#endif __NetBSD__ - -/* */ #ifdef DDB -int Debugger(); -#else DDB -#define Debugger() panic("should call debugger here") +int Debugger(); +#else /* DDB */ +#define Debugger() #endif /* DDB */ -#ifdef MACH -int Debugger(); -#endif MACH +typedef struct { + u_char addr[4]; +} physaddr; +typedef struct { + u_char len[4]; +} physlen; -typedef struct {unsigned char addr[4]; } physaddr; -typedef struct {unsigned char len[4]; } physlen; +#define KVTOPHYS(x) vtophys(x) +#define UHA_MSCP_MAX 32 /* store up to 32MSCPs at any one time + * MAX = ? + */ +#define MSCP_HASH_SIZE 32 /* when we have a physical addr. for + * a mscp and need to find the mscp in + * space, look it up in the hash table + */ +#define MSCP_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define MSCP_HASH(x) ((((long)(x))>>MSCP_HASH_SHIFT) % MSCP_HASH_SIZE) -#ifdef MACH -extern physaddr kvtophys(); -#define PHYSTOKV(x) phystokv(x) -#define KVTOPHYS(x) kvtophys(x) -#endif MACH +#define UHA_NSEG 33 /* number of dma segments supported */ -#ifdef __NetBSD__ -#define PHYSTOKV(x) ((x) + KERNBASE) -#define KVTOPHYS(x) vtophys(x) -#endif __NetBSD__ - -extern int delaycount; /* from clock setup code */ -#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ -#define UHA_NSEG 33 /* number of dma segments supported */ -#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ -/* */ /************************** board definitions *******************************/ /* * I/O Port Interface -*/ - #define UHA_LMASK (0x000) /* local doorbell mask reg */ - #define UHA_LINT (0x001) /* local doorbell int/stat reg */ - #define UHA_SMASK (0x002) /* system doorbell mask reg */ - #define UHA_SINT (0x003) /* system doorbell int/stat reg */ - #define UHA_ID0 (0x004) /* product id reg 0 */ - #define UHA_ID1 (0x005) /* product id reg 1 */ - #define UHA_CONF1 (0x006) /* config reg 1 */ - #define UHA_CONF2 (0x007) /* config reg 2 */ - #define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */ - #define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */ - #define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */ - #define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */ - #define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */ - #define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */ - #define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */ - #define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */ - - /* -* UHA_LMASK bits (read only) -*/ - -#define UHA_LDIE 0x80 /* local doorbell int enabled */ -#define UHA_SRSTE 0x40 /* soft reset enabled */ -#define UHA_ABORTEN 0x10 /* abort MSCP enabled */ -#define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */ + */ +#define UHA_LMASK (0x000) /* local doorbell mask reg */ +#define UHA_LINT (0x001) /* local doorbell int/stat reg */ +#define UHA_SMASK (0x002) /* system doorbell mask reg */ +#define UHA_SINT (0x003) /* system doorbell int/stat reg */ +#define UHA_ID0 (0x004) /* product id reg 0 */ +#define UHA_ID1 (0x005) /* product id reg 1 */ +#define UHA_CONF1 (0x006) /* config reg 1 */ +#define UHA_CONF2 (0x007) /* config reg 2 */ +#define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */ +#define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */ +#define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */ +#define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */ +#define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */ +#define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */ +#define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */ +#define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */ /* -* UHA_LINT bits (read) -*/ - -#define UHA_LDIP 0x80 /* local doorbell int pending */ + * UHA_LMASK bits (read only) + */ +#define UHA_LDIE 0x80 /* local doorbell int enabled */ +#define UHA_SRSTE 0x40 /* soft reset enabled */ +#define UHA_ABORTEN 0x10 /* abort MSCP enabled */ +#define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */ /* -* UHA_LINT bits (write) -*/ - -#define UHA_ADRST 0x40 /* adapter soft reset */ -#define UHA_SBRST 0x20 /* scsi bus reset */ -#define UHA_ASRST 0x60 /* adapter and scsi reset */ -#define UHA_ABORT 0x10 /* abort MSCP */ -#define UHA_OGMINT 0x01 /* tell adapter to get mail */ + * UHA_LINT bits (read) + */ +#define UHA_LDIP 0x80 /* local doorbell int pending */ /* -* UHA_SMASK bits (read) -*/ - -#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */ -#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */ -#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled + * UHA_LINT bits (write) + */ +#define UHA_ADRST 0x40 /* adapter soft reset */ +#define UHA_SBRST 0x20 /* scsi bus reset */ +#define UHA_ASRST 0x60 /* adapter and scsi reset */ +#define UHA_ABORT 0x10 /* abort MSCP */ +#define UHA_OGMINT 0x01 /* tell adapter to get mail */ /* -* UHA_SMASK bits (write) -*/ - -#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */ -#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */ -#define UHA_ENICM 0x01 /* enable ICM interrupt */ + * UHA_SMASK bits (read) + */ +#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */ +#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */ +#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled */ /* -* UHA_SINT bits (read) -*/ - -#define UHA_SINTP 0x80 /* system doorbell int pending */ -#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */ -#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */ + * UHA_SMASK bits (write) + */ +#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */ +#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */ +#define UHA_ENICM 0x01 /* enable ICM interrupt */ /* -* UHA_SINT bits (write) -*/ + * UHA_SINT bits (read) + */ +#define UHA_SINTP 0x80 /* system doorbell int pending */ +#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */ +#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */ -#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */ -#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */ +/* + * UHA_SINT bits (write) + */ +#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */ +#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */ /* -* UHA_CONF1 bits (read only) -*/ + * UHA_CONF1 bits (read only) + */ +#define UHA_DMA_CH5 0x00 /* DMA channel 5 */ +#define UHA_DMA_CH6 0x40 /* 6 */ +#define UHA_DMA_CH7 0x80 /* 7 */ +#define UHA_IRQ15 0x00 /* IRQ 15 */ +#define UHA_IRQ14 0x10 /* 14 */ +#define UHA_IRQ11 0x20 /* 11 */ +#define UHA_IRQ10 0x30 /* 10 */ -#define UHA_DMA_CH5 0x00 /* DMA channel 5 */ -#define UHA_DMA_CH6 0x40 /* 6 */ -#define UHA_DMA_CH7 0x80 /* 7 */ -#define UHA_IRQ15 0x00 /* IRQ 15 */ -#define UHA_IRQ14 0x10 /* 14 */ -#define UHA_IRQ11 0x20 /* 11 */ -#define UHA_IRQ10 0x30 /* 10 */ +/* + * ha_status error codes + */ +#define UHA_NO_ERR 0x00 /* No error supposedly */ +#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */ +#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */ +#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */ +#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */ +#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */ +#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */ +#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */ -/*********************************** -* ha_status error codes -\***********************************/ - -#define UHA_NO_ERR 0x00 /* No error supposedly */ -#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */ -#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */ -#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */ -#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */ -#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */ -#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */ -#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */ - -/* */ - -struct uha_dma_seg -{ - physaddr addr; - physlen len; +struct uha_dma_seg { + physaddr addr; + physlen len; }; -/* */ -struct mscp -{ - unsigned char opcode:3; - #define U14_HAC 0x01 /*host adapter command*/ - #define U14_TSP 0x02 /*target scsi pass through command*/ - #define U14_SDR 0x04 /*scsi device reset*/ - unsigned char xdir:2; /*xfer direction*/ - #define U14_SDET 0x00 /*determined by scsi command*/ - #define U14_SDIN 0x01 /*scsi data in*/ - #define U14_SDOUT 0x02 /*scsi data out*/ - #define U14_NODATA 0x03 /*no data xfer*/ - unsigned char dcn:1; /*disable disconnect for this command*/ - unsigned char ca:1; /*Cache control*/ - unsigned char sgth:1; /*scatter gather flag*/ - unsigned char target:3; - unsigned char chan:2; /*scsi channel (always 0 for 14f)*/ - unsigned char lun:3; - physaddr data; - physlen datalen; - physaddr link; - unsigned char link_id; - unsigned char sg_num; /*number of scat gath segs */ - /*in s-g list if sg flag is*/ - /*set. starts at 1, 8bytes per*/ - unsigned char senselen; - unsigned char cdblen; - unsigned char cdb[12]; - unsigned char ha_status; - unsigned char targ_status; - physaddr sense; /* if 0 no auto sense */ +struct mscp { + u_char opcode:3; +#define U14_HAC 0x01 /* host adapter command */ +#define U14_TSP 0x02 /* target scsi pass through command */ +#define U14_SDR 0x04 /* scsi device reset */ + u_char xdir:2; /* xfer direction */ +#define U14_SDET 0x00 /* determined by scsi command */ +#define U14_SDIN 0x01 /* scsi data in */ +#define U14_SDOUT 0x02 /* scsi data out */ +#define U14_NODATA 0x03 /* no data xfer */ + u_char dcn:1; /* disable disconnect for this command */ + u_char ca:1; /* cache control */ + u_char sgth:1; /* scatter gather flag */ + u_char target:3; + u_char chan:2; /* scsi channel (always 0 for 14f) */ + u_char lun:3; + physaddr data; + physlen datalen; + physaddr link; + u_char link_id; + u_char sg_num; /*number of scat gath segs */ + /*in s-g list if sg flag is */ + /*set. starts at 1, 8bytes per */ + u_char senselen; + u_char cdblen; + u_char cdb[12]; + u_char ha_status; + u_char targ_status; + physaddr sense; /* if 0 no auto sense */ /*-----------------end of hardware supported fields----------------*/ - struct mscp *next; /* in free list */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - long int delta; /* difference from previous*/ - struct mscp *later,*sooner; - int flags; -#define MSCP_FREE 0 -#define MSCP_ACTIVE 1 -#define MSCP_ABORTED 2 - struct uha_dma_seg uha_dma[UHA_NSEG]; - struct scsi_sense_data mscp_sense; + struct mscp *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + int flags; +#define MSCP_FREE 0 +#define MSCP_ACTIVE 1 +#define MSCP_ABORTED 2 + struct uha_dma_seg uha_dma[UHA_NSEG]; + struct scsi_sense_data mscp_sense; + struct mscp *nexthash; + long hashkey; }; -struct mscp *uha_soonest = (struct mscp *)0; -struct mscp *uha_latest = (struct mscp *)0; -long int uha_furtherest = 0; /* longest time in the timeout queue */ -/* */ +struct uha_softc { + struct device sc_dev; + struct isadev sc_id; + struct intrhand sc_ih; -struct uha_data -{ - int flags; -#define UHA_INIT 0x01; - int baseport; - struct mscp mscps[NUM_CONCURRENT]; - struct mscp *free_mscp; - int vect; - int dma; -} uha_data[NUHA]; + u_short sc_iobase; -int uhaprobe(); -int uha_attach(); -int uhaintr(); -int uha_scsi_cmd(); -int uha_timeout(); -int uha_abort(); -struct mscp *cheat; -void uhaminphys(); -long int uha_adapter_info(); + struct mscp *mscphash[MSCP_HASH_SIZE]; + struct mscp *free_mscp; + int our_id; /* our scsi id */ + int vect; + int dma; + int nummscps; + struct scsi_link sc_link; +}; -unsigned long int scratch; +void uha_send_mbox __P((struct uha_softc *, struct mscp *)); +int uha_abort __P((struct uha_softc *, struct mscp *)); +int uha_poll __P((struct uha_softc *, int)); +u_int uha_adapter_info __P((struct uha_softc *)); +int uhaintr __P((int)); +void uha_done __P((struct uha_softc *, struct mscp *)); +void uha_free_mscp __P((struct uha_softc *, struct mscp *, int flags)); +struct mscp *uha_get_mscp __P((struct uha_softc *, int)); +struct mscp *uha_mscp_phys_kv __P((struct uha_softc *, u_long)); +int uha_find __P((struct uha_softc *)); +void uha_init __P((struct uha_softc *)); +void uhaminphys __P((struct buf *)); +int uha_scsi_cmd __P((struct scsi_xfer *)); +void uha_timeout __P((caddr_t)); +#ifdef UHADEBUG +void uha_print_mscp __P((struct mscp *)); +void uha_print_active_mscp __P((struct uha_softc *)); +#endif -#ifdef MACH -struct isa_driver uhadriver = { uhaprobe, 0, uha_attach, "uha", 0, 0, 0}; -int (*uhaintrs[])() = {uhaintr, 0}; -#endif MACH - -#ifdef __NetBSD__ -struct isa_driver uhadriver = { uhaprobe, uha_attach, "uha"}; -#endif __NetBSD__ - -static uha_unit = 0; -int uha_debug = 0; +u_long scratch; #define UHA_SHOWMSCPS 0x01 #define UHA_SHOWINTS 0x02 #define UHA_SHOWCMDS 0x04 #define UHA_SHOWMISC 0x08 -#define FAIL 1 -#define SUCCESS 0 -#define PAGESIZ 4096 -struct scsi_switch uha_switch[NUHA]; +struct scsi_adapter uha_switch = { + uha_scsi_cmd, + uhaminphys, + 0, + 0, + uha_adapter_info, + "uha" +}; -/* */ -/***********************************************************************\ -* Function to send a command out through a mailbox * -\***********************************************************************/ -uha_send_mbox( int unit - ,struct mscp *mscp) +/* the below structure is so we have a default dev struct for out link struct */ +struct scsi_device uha_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "uha", + 0 +}; + +int uhaprobe(); +void uhaattach(); + +struct cfdriver uhacd = { + NULL, "uha", uhaprobe, uhaattach, DV_DULL, sizeof(struct uha_softc) +}; + +/* + * Function to send a command out through a mailbox + */ +void +uha_send_mbox(uha, mscp) + struct uha_softc *uha; + struct mscp *mscp; { - int port = uha_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1000; /* 1s should be enough */ - int s = splbio(); - - while( ((inb(port + UHA_LINT) & (UHA_LDIP)) - != (0)) - && (spincount--)); - if(spincount == -1) - { - printf("uha%d: board not responding\n",unit); + u_short iobase = uha->sc_iobase; + int spincount = 100000; /* 1s should be enough */ + int s = splbio(); + + while (--spincount) { + if ((inb(iobase + UHA_LINT) & UHA_LDIP) == 0) + break; + delay(100); + } + if (!spincount) { + printf("%s: uha_send_mbox, board not responding\n", + uha->sc_dev.dv_xname); Debugger(); } - outl(port + UHA_OGM0,KVTOPHYS(mscp)); - outb(port + UHA_LINT, (UHA_OGMINT)); + outl(iobase + UHA_OGM0, KVTOPHYS(mscp)); + outb(iobase + UHA_LINT, UHA_OGMINT); + splx(s); } -/***********************************************************************\ -* Function to send abort to 14f * -\***********************************************************************/ - -uha_abort( int unit - ,struct mscp *mscp) +/* + * Function to send abort to 14f + */ +int +uha_abort(uha, mscp) + struct uha_softc *uha; + struct mscp *mscp; { - int port = uha_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; - int abortcount = FUDGE(delaycount) * 2000; - int s = splbio(); - - while(((inb(port + UHA_LINT) & (UHA_LDIP)) - != (0)) - && (spincount--)); - if(spincount == -1); - { - printf("uha%d: board not responding\n",unit); + u_short iobase = uha->sc_iobase; + int spincount = 100; /* 1 mSec */ + int abortcount = 200000; /*2 secs */ + int s = splbio(); + + while (--spincount) { + if ((inb(iobase + UHA_LINT) & UHA_LDIP) == 0) + break; + delay(10); + } + if (!spincount) { + printf("%s: uha_abort, board not responding\n", + uha->sc_dev.dv_xname); Debugger(); } - outl(port + UHA_OGM0,KVTOPHYS(mscp)); - outb(port + UHA_LINT,UHA_ABORT); + outl(iobase + UHA_OGM0, KVTOPHYS(mscp)); + outb(iobase + UHA_LINT, UHA_ABORT); - while((abortcount--) && (!(inb(port + UHA_SINT) & UHA_ABORT_FAIL))); - if(abortcount == -1) - { - printf("uha%d: board not responding\n",unit); + while (--abortcount) { + if (inb(iobase + UHA_SINT) & UHA_ABORT_FAIL) + break; + delay(10); + } + if (!abortcount) { + printf("%s: uha_abort, board not responding\n", + uha->sc_dev.dv_xname); Debugger(); } - if((inb(port + UHA_SINT) & 0x10) != 0) - { - outb(port + UHA_SINT,UHA_ABORT_ACK); - return(1); - } - else - { - outb(port + UHA_SINT,UHA_ABORT_ACK); - return(0); - } -} -/***********************************************************************\ -* Function to poll for command completion when in poll mode * -\***********************************************************************/ -uha_poll(int unit ,int wait) /* in msec */ -{ - int port = uha_data[unit].baseport; - int spincount = FUDGE(delaycount) * wait; /* in msec */ - int stport = port + UHA_SINT; - int start = spincount; - -retry: - while( (spincount--) && (!(inb(stport) & UHA_SINTP))); - if(spincount == -1) - { - printf("uha%d: board not responding\n",unit); - return(EIO); - } -if ((int)cheat != PHYSTOKV(inl(port + UHA_ICM0))) -{ - printf("discarding %x ",inl(port + UHA_ICM0)); - outb(port + UHA_SINT, UHA_ICM_ACK); - spinwait(50); - goto retry; -}/* don't know this will work */ - uhaintr(unit); - return(0); -} - -/*******************************************************\ -* Check if the device can be found at the port given * -* and if so, set it up ready for further work * -* as an argument, takes the isa_dev structure from * -* autoconf.c * -\*******************************************************/ -uhaprobe(dev) -struct isa_device *dev; -{ - int unit; - - if (dev->id_parent) + if ((inb(iobase + UHA_SINT) & UHA_ABORT_FAIL) == UHA_ABORT_SUCC) { + outb(iobase + UHA_SINT, UHA_ABORT_ACK); + splx(s); return 1; - - dev->id_unit = unit = uha_unit; - uha_data[unit].baseport = dev->id_iobase; - if(unit >= NUHA) - { - printf("uha: unit number (%d) too high\n",unit); - return(0); + } else { + outb(iobase + UHA_SINT, UHA_ABORT_ACK); + splx(s); + return 0; } - - /*try and initialize unit at this location*/ - if (uha_init(unit) != 0) - { - return(0); - } - - /* if its there put in it's interrupt and DRQ vectors */ - - dev->id_irq = (1 << uha_data[unit].vect); - dev->id_drq = uha_data[unit].dma; - - uha_unit ++; - return(8); } -/***********************************************\ -* Attach all the sub-devices we can find * -\***********************************************/ -uha_attach(dev) -struct isa_device *dev; +/* + * Function to poll for command completion when in poll mode. + * + * wait = timeout in msec + */ +int +uha_poll(uha, wait) + struct uha_softc *uha; + int wait; { - static int firsttime; - static int firstswitch[NUHA]; - int masunit; - int r; + u_short iobase = uha->sc_iobase; - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; + while (--wait) { + if (inb(iobase + UHA_SINT) & UHA_SINTP) + break; + delay(1000); /* 1 mSec per loop */ + } + if (!wait) { + printf("%s: uha_poll, board not responding\n", + uha->sc_dev.dv_xname); + return EIO; + } - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - uha_switch[masunit].name = "uha"; - uha_switch[masunit].scsi_cmd = uha_scsi_cmd; - uha_switch[masunit].scsi_minphys = uhaminphys; - uha_switch[masunit].open_target_lu = 0; - uha_switch[masunit].close_target_lu = 0; - uha_switch[masunit].adapter_info = uha_adapter_info; - for (r = 0; r < 8; r++) { - uha_switch[masunit].empty[r] = 0; - uha_switch[masunit].used[r] = 0; - uha_switch[masunit].printed[r] = 0; + uhaintr(uha->sc_dev.dv_unit); + return 0; +} + +/* + * Check if the device can be found at the port given and if so, set it up + * ready for further work as an argument, takes the isa_device structure + * from autoconf.c + */ +int +uhaprobe(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct uha_softc *uha = (void *)self; + struct isa_attach_args *ia = aux; + +#ifdef NEWCONFIG + if (ia->ia_iobase == IOBASEUNK) + return 0; +#endif + + uha->sc_iobase = ia->ia_iobase; + + /* + * Try initialise a unit at this location + * sets up dma and bus speed, loads uha->vect + */ + if (uha_find(uha) != 0) + return 0; + +#ifdef NEWCONFIG + if (ia->ia_irq == IRQUNK) { + ia->ia_irq = (1 << uha->vect); + } else { + if (ia->ia_irq != (1 << uha->vect)) { + printf("uha%d: irq mismatch, %x != %x\n", + uha->sc_dev.dv_unit, ia->ia_irq, + 1 << uha->vect); + return 0; } } - r = scsi_attach(masunit, &uha_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); - /* only one for all boards */ - if(firsttime==0) { - firsttime = 1; - uha_timeout(0); + if (ia->ia_drq == DRQUNK) { + ia->ia_drq = uha->dma; + } else { + if (ia->ia_drq != uha->dma) { + printf("uha%d: drq mismatch, %x != %x\n", + uha->sc_dev.dv_unit, ia->ia_drq, uha->dma); + return 0; + } } - return r; +#endif + + ia->ia_msize = 0; + ia->ia_iosize = 4; + return 1; } -/***********************************************\ -* Return some information to the caller about * -* the adapter and it's capabilities * -\***********************************************/ -long int uha_adapter_info(unit) -int unit; +uhaprint() { - return(2); /* 2 outstanding requests at a time per device */ + } -/***********************************************\ -* Catch an interrupt from the adaptor * -\***********************************************/ +/* + * Attach all the sub-devices we can find + */ +void +uhaattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct isa_attach_args *ia = aux; + struct uha_softc *uha = (void *)self; + + uha_init(uha); + + /* + * fill in the prototype scsi_link. + */ + uha->sc_link.adapter_softc = uha; + uha->sc_link.adapter_targ = uha->our_id; + uha->sc_link.adapter = &uha_switch; + uha->sc_link.device = &uha_dev; + + printf("\n"); + +#ifdef NEWCONFIG + isa_establish(&uha->sc_id, &uha->sc_dev); + uha->sc_ih.ih_fun = uhaintr; + uha->sc_ih.ih_arg = uha; + /* XXX and DV_TAPE, but either gives us splbio */ + intr_establish(ia->ia_irq, &uha->sc_ih, DV_DISK); +#endif + + /* + * ask the adapter what subunits are present + */ + config_found(self, &uha->sc_link, uhaprint); +} + +/* + * Return some information to the caller about + * the adapter and it's capabilities + */ +u_int +uha_adapter_info(uha) + struct uha_softc *uha; +{ + + return 2; /* 2 outstanding requests at a time per device */ +} + +/* + * Catch an interrupt from the adaptor + */ +int uhaintr(unit) + int unit; { - struct mscp *mscp; - u_char uhastat; - unsigned long int mboxval; + struct uha_softc *uha = uhacd.cd_devs[unit]; + struct mscp *mscp; + u_char uhastat; + u_long mboxval; + u_short iobase = uha->sc_iobase; - int port = uha_data[unit].baseport; +#ifdef UHADEBUG + printf("%s: uhaintr ", uha->sc_dev.dv_xname); +#endif /*UHADEBUG */ + if ((inb(iobase + UHA_SINT) & UHA_SINTP) == 0) + return 0; - if(scsi_debug & PRINTROUTINES) - printf("uhaintr "); + do { + /* + * First get all the information and then + * acknowledge the interrupt + */ + uhastat = inb(iobase + UHA_SINT); + mboxval = inl(iobase + UHA_ICM0); + outb(iobase + UHA_SINT, UHA_ICM_ACK); -#if defined(OSF) - if (!uha_attached[unit]) - { - return(1); - } -#endif /* defined(OSF) */ - while(inb(port + UHA_SINT) & UHA_SINTP) - { - /***********************************************\ - * First get all the information and then * - * acknowlege the interrupt * - \***********************************************/ - uhastat = inb(port + UHA_SINT); - mboxval = inl(port + UHA_ICM0); - outb(port + UHA_SINT,UHA_ICM_ACK); +#ifdef UHADEBUG + printf("status = 0x%x ", uhastat); +#endif /*UHADEBUG*/ - if(scsi_debug & TRACEINTERRUPTS) - printf("status = 0x%x ",uhastat); - /***********************************************\ - * Process the completed operation * - \***********************************************/ - - mscp = (struct mscp *)(PHYSTOKV(mboxval)); + /* + * Process the completed operation + */ + mscp = uha_mscp_phys_kv(uha, mboxval); + if (!mscp) { + printf("uha: BAD MSCP RETURNED\n"); + return 0; /* whatever it was, it'll timeout */ + } + untimeout(uha_timeout, (caddr_t)mscp); - if(uha_debug & UHA_SHOWCMDS ) - { - uha_show_scsi_cmd(mscp->xs); - } - if((uha_debug & UHA_SHOWMSCPS) && mscp) - printf("",mscp); - uha_remove_timeout(mscp); + uha_done(uha, mscp); + } while (inb(iobase + UHA_SINT) & UHA_SINTP); - uha_done(unit,mscp); - } - return(1); + return 1; } -/***********************************************\ -* We have a mscp which has been processed by the * -* adaptor, now we look to see how the operation * -* went. * -\***********************************************/ - -uha_done(unit,mscp) -int unit; -struct mscp *mscp; +/* + * We have a mscp which has been processed by the adaptor, now we look to see + * how the operation went. + */ +void +uha_done(uha, mscp) + struct uha_softc *uha; + struct mscp *mscp; { - struct scsi_sense_data *s1,*s2; - struct scsi_xfer *xs = mscp->xs; + struct scsi_sense_data *s1, *s2; + struct scsi_xfer *xs = mscp->xs; - if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("uha_done "); - /***********************************************\ - * Otherwise, put the results of the operation * - * into the xfer and call whoever started it * - \***********************************************/ - if ( (mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK)) - { /* All went correctly OR errors expected */ + SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); + /* + * Otherwise, put the results of the operation + * into the xfer and call whoever started it + */ + if ((mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK)) { + /* all went correctly OR errors expected */ xs->resid = 0; xs->error = 0; - } - else - { + } else { + s1 = &mscp->mscp_sense; + s2 = &xs->sense; - s1 = &(mscp->mscp_sense); - s2 = &(xs->sense); - - if(mscp->ha_status != UHA_NO_ERR) - { - switch(mscp->ha_status) - { - case UHA_SBUS_TIMEOUT: /* No response */ - if (uha_debug & UHA_SHOWMISC) - { - printf("timeout reported back\n"); - } + if (mscp->ha_status != UHA_NO_ERR) { + switch (mscp->ha_status) { + case UHA_SBUS_TIMEOUT: /* No response */ + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("timeout reported back\n")); xs->error = XS_TIMEOUT; break; - case UHA_SBUS_OVER_UNDER: - if (uha_debug & UHA_SHOWMISC) - { - printf("scsi bus xfer over/underrun\n"); - } + case UHA_SBUS_OVER_UNDER: + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("scsi bus xfer over/underrun\n")); xs->error = XS_DRIVER_STUFFUP; break; - case UHA_BAD_SG_LIST: - if (uha_debug & UHA_SHOWMISC) - { - printf("bad sg list reported back\n"); - } + case UHA_BAD_SG_LIST: + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("bad sg list reported back\n")); xs->error = XS_DRIVER_STUFFUP; break; - default: /* Other scsi protocol messes */ + default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; - if (uha_debug & UHA_SHOWMISC) - { - printf("unexpected ha_status: %x\n", - mscp->ha_status); - } + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected ha_status: %x\n", + mscp->ha_status)); } - - } - else - { - - if (mscp->targ_status != 0) -/**************************************************************************\ -* I have no information for any possible value of target status field * -* other than 0 means no error!! So I guess any error is unexpected in that * -* event!! * -\**************************************************************************/ - - { - if (uha_debug & UHA_SHOWMISC) - { - printf("unexpected targ_status: %x\n", - mscp->targ_status); - } + } else { + if (mscp->targ_status != 0) { + /* + * I have no information for any possible value + * of target status field other than 0 means no + * error!! So I guess any error is unexpected + * in that event!! + */ + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected targ_status: %x\n", + mscp->targ_status)); xs->error = XS_DRIVER_STUFFUP; } } } -done: xs->flags |= ITSDONE; - uha_free_mscp(unit,mscp, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + done: + xs->flags |= ITSDONE; + uha_free_mscp(uha, mscp, xs->flags); + scsi_done(xs); } -/***********************************************\ -* A mscp (and hence a mbx-out is put onto the * -* free list. * -\***********************************************/ -uha_free_mscp(unit,mscp, flags) -struct mscp *mscp; +/* + * A mscp (and hence a mbx-out) is put onto the free list. + */ +void +uha_free_mscp(uha, mscp, flags) + struct uha_softc *uha; + struct mscp *mscp; + int flags; { - unsigned int opri; - - if(scsi_debug & PRINTROUTINES) - printf("mscp%d(0x%x)> ",unit,flags); - if (!(flags & SCSI_NOMASK)) + int opri; + + if (!(flags & SCSI_NOMASK)) opri = splbio(); - mscp->next = uha_data[unit].free_mscp; - uha_data[unit].free_mscp = mscp; + mscp->next = uha->free_mscp; + uha->free_mscp = mscp; mscp->flags = MSCP_FREE; - /***********************************************\ - * If there were none, wake abybody waiting for * - * one to come free, starting with queued entries* - \***********************************************/ - if (!mscp->next) { - wakeup((caddr_t) &uha_data[unit].free_mscp); - } - if (!(flags & SCSI_NOMASK)) + + /* + * If there were none, wake abybody waiting for + * one to come free, starting with queued entries + */ + if (!mscp->next) + wakeup((caddr_t)&uha->free_mscp); + + if (!(flags & SCSI_NOMASK)) splx(opri); } -/***********************************************\ -* Get a free mscp (and hence mbox-out entry) * -\***********************************************/ +/* + * Get a free mscp + * + * If there are none, see if we can allocate a new one. If so, put it in the + * hash table too otherwise either return an error or sleep. + */ struct mscp * -uha_get_mscp(unit,flags) +uha_get_mscp(uha, flags) + struct uha_softc *uha; + int flags; { - unsigned opri; - struct mscp *rc; + int opri; + struct mscp *mscpp; + int hashnum; - if(scsi_debug & PRINTROUTINES) - printf("free_mscp)) { + if (uha->nummscps < UHA_MSCP_MAX) { + if (mscpp = (struct mscp *)malloc(sizeof(struct mscp), + M_TEMP, M_NOWAIT)) { + bzero(mscpp, sizeof(struct mscp)); + uha->nummscps++; + mscpp->flags = MSCP_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + mscpp->hashkey = KVTOPHYS(mscpp); + hashnum = MSCP_HASH(mscpp->hashkey); + mscpp->nexthash = uha->mscphash[hashnum]; + uha->mscphash[hashnum] = mscpp; + } else { + printf("%s: Can't malloc MSCP\n", + uha->sc_dev.dv_xname); + } + goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) + tsleep((caddr_t)&uha->free_mscp, PRIBIO, + "uhamsc", 0); + } } - if (rc) - { - uha_data[unit].free_mscp = rc->next; - rc->flags = MSCP_ACTIVE; + + if (mscpp) { + /* Get MSCP from the free list */ + uha->free_mscp = mscpp->next; + mscpp->flags = MSCP_ACTIVE; } - if (!(flags & SCSI_NOMASK)) + + gottit: + if (!(flags & SCSI_NOMASK)) splx(opri); - return(rc); + + return mscpp; } - +/* + * given a physical address, find the mscp that it corresponds to. + */ +struct mscp * +uha_mscp_phys_kv(uha, mscp_phys) + struct uha_softc *uha; + u_long mscp_phys; +{ + int hashnum = MSCP_HASH(mscp_phys); + struct mscp *mscpp = uha->mscphash[hashnum]; -/***********************************************\ -* Start the board, ready for normal operation * -\***********************************************/ + while (mscpp) { + if (mscpp->hashkey == mscp_phys) + break; + mscpp = mscpp->nexthash; + } + return mscpp; +} -uha_init(unit) -int unit; -{ - unsigned char ad[4]; - volatile unsigned char model; - volatile unsigned char submodel; - unsigned char config_reg1; - unsigned char config_reg2; - unsigned char dma_ch; - unsigned char irq_ch; - unsigned char uha_id; - int port = uha_data[unit].baseport; - int i; - int resetcount = FUDGE(delaycount) * 4000; +/* + * Start the board, ready for normal operation + */ +int +uha_find(uha) + struct uha_softc *uha; +{ + u_char ad[4]; + volatile u_char model; + volatile u_char submodel; + u_char config_reg1; + u_char config_reg2; + u_char dma_ch; + u_char irq_ch; + u_char uha_id; + u_short iobase = uha->sc_iobase; + int i; + int resetcount = 4000; /* 4 secs? */ - model = inb(port + UHA_ID0); - submodel = inb(port + UHA_ID1); - if ((model != 0x56) & (submodel != 0x40)) - { /* printf("ultrastor 14f not responding\n"); */ - return(ENXIO); } + model = inb(iobase + UHA_ID0); + submodel = inb(iobase + UHA_ID1); + if ((model != 0x56) & (submodel != 0x40)) + return ENXIO; - printf("uha%d reading board settings, ",unit); - - config_reg1 = inb(port + UHA_CONF1); - config_reg2 = inb(port + UHA_CONF2); + config_reg1 = inb(iobase + UHA_CONF1); + config_reg2 = inb(iobase + UHA_CONF2); dma_ch = (config_reg1 & 0xc0); irq_ch = (config_reg1 & 0x30); uha_id = (config_reg2 & 0x07); - switch(dma_ch) - { - case UHA_DMA_CH5: - uha_data[unit].dma = 5; - printf("dma=5 "); + switch (dma_ch) { + case UHA_DMA_CH5: + uha->dma = 5; break; - case UHA_DMA_CH6: - uha_data[unit].dma = 6; - printf("dma=6 "); + case UHA_DMA_CH6: + uha->dma = 6; break; - case UHA_DMA_CH7: - uha_data[unit].dma = 7; - printf("dma=7 "); + case UHA_DMA_CH7: + uha->dma = 7; break; default: - printf("illegal dma jumper setting\n"); - return(EIO); + printf("illegal dma setting %x\n", dma_ch); + return EIO; } - switch(irq_ch) - { - case UHA_IRQ10: - uha_data[unit].vect = 10; - printf("int=10 "); + + switch (irq_ch) { + case UHA_IRQ10: + uha->vect = 10; break; - case UHA_IRQ11: - uha_data[unit].vect = 11; - printf("int=11 "); + case UHA_IRQ11: + uha->vect = 11; break; - case UHA_IRQ14: - uha_data[unit].vect = 14; - printf("int=14 "); + case UHA_IRQ14: + uha->vect = 14; break; - case UHA_IRQ15: - uha_data[unit].vect = 15; - printf("int=15 "); + case UHA_IRQ15: + uha->vect = 15; break; default: - printf("illegal int jumper setting\n"); - return(EIO); + printf("illegal int setting %x\n", irq_ch); + return EIO; } + /* who are we on the scsi bus */ - printf("id=%x\n",uha_id); - uha_switch[unit].scsi_dev = uha_id; + uha->our_id = uha_id; - - /***********************************************\ - * link up all our MSCPs into a free list * - \***********************************************/ - for (i=0; i < NUM_CONCURRENT; i++) - { - uha_data[unit].mscps[i].next = uha_data[unit].free_mscp; - uha_data[unit].free_mscp = &uha_data[unit].mscps[i]; - uha_data[unit].free_mscp->flags = MSCP_FREE; + outb(iobase + UHA_LINT, UHA_ASRST); + + while (--resetcount) { + if (inb(iobase + UHA_LINT)) + break; + delay(1000); /* 1 mSec per loop */ + } + if (!resetcount) { + printf("%s: board timed out during reset\n", + uha->sc_dev.dv_xname); + return ENXIO; } - /***********************************************\ - * Note that we are going and return (to probe) * - \***********************************************/ - outb(port + UHA_LINT, UHA_ASRST); - while( (resetcount--) && (!(inb(port + UHA_LINT)))); - if(resetcount == -1) - { - printf("uha%d: board timed out during reset\n",unit); - return(ENXIO); - } - - outb(port + UHA_SMASK, 0x81); /* make sure interrupts are enabled */ - uha_data[unit].flags |= UHA_INIT; - return(0); + /* + * Note that we are going and return (to probe) + */ + return 0; } - - -#ifndef min -#define min(x,y) (x < y ? x : y) -#endif min - - -void uhaminphys(bp) -struct buf *bp; +void +uha_init(uha) + struct uha_softc *uha; { -#ifdef MACH -#if !defined(OSF) - bp->b_flags |= B_NPAGES; /* can support scat/gather */ -#endif /* defined(OSF) */ -#endif MACH - if(bp->b_bcount > ((UHA_NSEG-1) * PAGESIZ)) - { - bp->b_bcount = ((UHA_NSEG-1) * PAGESIZ); - } + u_short iobase = uha->sc_iobase; + + outb(iobase + UHA_SMASK, 0x81); /* make sure interrupts are enabled */ } -/***********************************************\ -* start a scsi operation given the command and * -* the data address. Also needs the unit, target * -* and lu * -\***********************************************/ -int uha_scsi_cmd(xs) -struct scsi_xfer *xs; +void +uhaminphys(bp) + struct buf *bp; { - struct scsi_sense_data *s1,*s2; + + if (bp->b_bcount > ((UHA_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((UHA_NSEG - 1) << PGSHIFT); +} + +/* + * start a scsi operation given the command and the data address. Also + * needs the unit, target and lu. + */ +int +uha_scsi_cmd(xs) + struct scsi_xfer *xs; +{ + struct scsi_link *sc_link = xs->sc_link; + struct uha_softc *uha = sc_link->adapter_softc; struct mscp *mscp; struct uha_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; - unsigned long int thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; - int s; - unsigned int stat; - int port = uha_data[unit].baseport; - unsigned long int templen; + int seg; /* scatter gather seg being worked on */ + u_long thiskv, thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + struct iovec *iovp; + int s; + u_long templen; - - if(scsi_debug & PRINTROUTINES) - printf("uha_scsi_cmd "); - /***********************************************\ - * get a mscp (mbox-out) to use. If the transfer * - * is from a buf (possibly from interrupt time) * - * then we can't allow it to sleep * - \***********************************************/ + SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); + /* + * get a mscp (mbox-out) to use. If the transfer + * is from a buf (possibly from interrupt time) + * then we can't allow it to sleep + */ flags = xs->flags; - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if(flags & ITSDONE) - { - printf("Already done?"); + if (xs->bp) + flags |= SCSI_NOSLEEP; /* just to be sure */ + if (flags & ITSDONE) { + printf("%s: already done?", uha->sc_dev.dv_xname); xs->flags &= ~ITSDONE; } - if(!(flags & INUSE)) - { - printf("Not in use?"); + if (!(flags & INUSE)) { + printf("%s: not in use?", uha->sc_dev.dv_xname); xs->flags |= INUSE; } - if (!(mscp = uha_get_mscp(unit,flags))) - { + if (!(mscp = uha_get_mscp(uha, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); - } - -cheat = mscp; - if(uha_debug & UHA_SHOWMSCPS) - printf("",mscp); - if(scsi_debug & SHOWCOMMANDS) - { - uha_show_scsi_cmd(xs); + return TRY_AGAIN_LATER; } + SC_DEBUG(sc_link, SDEV_DB3, ("start mscp(%x)\n", mscp)); mscp->xs = xs; - /***********************************************\ - * Put all the arguments for the xfer in the mscp * - \***********************************************/ - if (flags & SCSI_RESET) - { + /* + * Put all the arguments for the xfer in the mscp + */ + if (flags & SCSI_RESET) { mscp->opcode = 0x04; mscp->ca = 0x01; - } - else - { + } else { mscp->opcode = 0x02; mscp->ca = 0x01; - } - + } if (flags & SCSI_DATA_IN) - { mscp->xdir = 0x01; - } if (flags & SCSI_DATA_OUT) - { mscp->xdir = 0x02; - } - if (xs->lu != 0) - { - xs->error = XS_DRIVER_STUFFUP; - uha_free_mscp(unit,mscp,flags); - return(HAD_ERROR); - } - - mscp->dcn = 0x00; - mscp->chan = 0x00; - mscp->target = xs->targ; - mscp->lun = xs->lu; - mscp->link.addr[0] = 0x00; - mscp->link.addr[1] = 0x00; - mscp->link.addr[2] = 0x00; - mscp->link.addr[3] = 0x00; - mscp->link_id = 0x00; - mscp->cdblen = xs->cmdlen; - scratch = KVTOPHYS(&(mscp->mscp_sense)); - mscp->sense.addr[0] = (scratch & 0xff); - mscp->sense.addr[1] = ((scratch >> 8) & 0xff); - mscp->sense.addr[2] = ((scratch >> 16) & 0xff); - mscp->sense.addr[3] = ((scratch >> 24) & 0xff); - mscp->senselen = sizeof(mscp->mscp_sense); - mscp->ha_status = 0x00; - mscp->targ_status = 0x00; + mscp->dcn = 0x00; + mscp->chan = 0x00; + mscp->target = sc_link->target; + mscp->lun = sc_link->lun; + mscp->link.addr[0] = 0x00; + mscp->link.addr[1] = 0x00; + mscp->link.addr[2] = 0x00; + mscp->link.addr[3] = 0x00; + mscp->link_id = 0x00; + mscp->cdblen = xs->cmdlen; + scratch = KVTOPHYS(&mscp->mscp_sense); + mscp->sense.addr[0] = (scratch & 0xff); + mscp->sense.addr[1] = ((scratch >> 8) & 0xff); + mscp->sense.addr[2] = ((scratch >> 16) & 0xff); + mscp->sense.addr[3] = ((scratch >> 24) & 0xff); + mscp->senselen = sizeof(mscp->mscp_sense); + mscp->ha_status = 0x00; + mscp->targ_status = 0x00; - if(xs->datalen) - { /* should use S/G only if not zero length */ - scratch = KVTOPHYS(mscp->uha_dma); - mscp->data.addr[0] = (scratch & 0xff); - mscp->data.addr[1] = ((scratch >> 8) & 0xff); - mscp->data.addr[2] = ((scratch >> 16) & 0xff); - mscp->data.addr[3] = ((scratch >> 24) & 0xff); - sg = mscp->uha_dma ; - seg = 0; - mscp->sgth = 0x01; + if (xs->datalen) { /* should use S/G only if not zero length */ + scratch = KVTOPHYS(mscp->uha_dma); + mscp->data.addr[0] = (scratch & 0xff); + mscp->data.addr[1] = ((scratch >> 8) & 0xff); + mscp->data.addr[2] = ((scratch >> 16) & 0xff); + mscp->data.addr[3] = ((scratch >> 24) & 0xff); + sg = mscp->uha_dma; + seg = 0; + mscp->sgth = 0x01; - if(flags & SCSI_DATA_UIO) - { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; +#ifdef TFS + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while ((datalen) && (seg < UHA_NSEG)) - { - scratch = (unsigned long)iovp->iov_base; - sg->addr.addr[0] = (scratch & 0xff); + while (datalen && seg < UHA_NSEG) { + scratch = (u_long) iovp->iov_base; + sg->addr.addr[0] = (scratch & 0xff); sg->addr.addr[1] = ((scratch >> 8) & 0xff); sg->addr.addr[2] = ((scratch >> 16) & 0xff); sg->addr.addr[3] = ((scratch >> 24) & 0xff); - xs->datalen += *(unsigned long *)sg->len.len = iovp->iov_len; - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)" - ,iovp->iov_len - ,iovp->iov_base); + xs->datalen += *(u_long *) sg->len.len = iovp->iov_len; + SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } - else + } else +#endif /*TFS */ { - /***********************************************\ - * Set up the scatter gather block * - \***********************************************/ - - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ",xs->datalen,xs->data); - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - templen = 0; - - while ((datalen) && (seg < UHA_NSEG)) - { - bytes_this_seg = 0; - + /* + * Set up the scatter gather block + */ + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + datalen = xs->datalen; + thiskv = (int) xs->data; + thisphys = KVTOPHYS(thiskv); + templen = 0; + + while (datalen && seg < UHA_NSEG) { + bytes_this_seg = 0; + /* put in the base address */ sg->addr.addr[0] = (thisphys & 0xff); sg->addr.addr[1] = ((thisphys >> 8) & 0xff); sg->addr.addr[2] = ((thisphys >> 16) & 0xff); sg->addr.addr[3] = ((thisphys >> 24) & 0xff); - - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); - + + SC_DEBUGN(sc_link, SDEV_DB4, + ("0x%x", thisphys)); + /* do it at least once */ - nextphys = thisphys; - while ((datalen) && (thisphys == nextphys)) - /*********************************************\ - * This page is contiguous (physically) with * - * the the last, just extend the length * - \*********************************************/ - { + nextphys = thisphys; + while (datalen && thisphys == nextphys) { + /* + * This page is contiguous (physically) + * with the the last, just extend the + * length + */ /* how far to the end of the page */ - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; + nextphys = (thisphys & ~PGOFSET) + NBPG; bytes_this_page = nextphys - thisphys; /**** or the data ****/ - bytes_this_page = min(bytes_this_page - ,datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - + bytes_this_page = min(bytes_this_page, + datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + thiskv = (thiskv & ~PGOFSET) + NBPG; + if (datalen) thisphys = KVTOPHYS(thiskv); } - /********************************************\ - * next page isn't contiguous, finish the seg * - \********************************************/ - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); + /* + * next page isn't contiguous, finish the seg + */ + SC_DEBUGN(sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); sg->len.len[0] = (bytes_this_seg & 0xff); sg->len.len[1] = ((bytes_this_seg >> 8) & 0xff); sg->len.len[2] = ((bytes_this_seg >> 16) & 0xff); @@ -1005,27 +1016,24 @@ cheat = mscp; sg++; seg++; } - } /*end of iov/kv decision */ + } + + /* end of iov/kv decision */ mscp->datalen.len[0] = (templen & 0xff); mscp->datalen.len[1] = ((templen >> 8) & 0xff); mscp->datalen.len[2] = ((templen >> 16) & 0xff); mscp->datalen.len[3] = ((templen >> 24) & 0xff); mscp->sg_num = seg; + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); - if(scsi_debug & SHOWSCATGATH) - printf("\n"); - if (datalen) - { /* there's still data, must have run out of segs! */ - printf("uha_scsi_cmd%d: more than %d DMA segs\n", - unit,UHA_NSEG); + if (datalen) { /* there's still data, must have run out of segs! */ + printf("%s: uha_scsi_cmd, more than %d DMA segs\n", + uha->sc_dev.dv_xname, UHA_NSEG); xs->error = XS_DRIVER_STUFFUP; - uha_free_mscp(unit,mscp,flags); - return(HAD_ERROR); + uha_free_mscp(uha, mscp, flags); + return HAD_ERROR; } - - } - else - { /* No data xfer, use non S/G values */ + } else { /* No data xfer, use non S/G values */ mscp->data.addr[0] = 0x00; mscp->data.addr[1] = 0x00; mscp->data.addr[2] = 0x00; @@ -1036,259 +1044,104 @@ cheat = mscp; mscp->datalen.len[3] = 0x00; mscp->xdir = 0x03; mscp->sgth = 0x00; - mscp->sg_num = 0x00; + mscp->sg_num = 0x00; } - /***********************************************\ - * Put the scsi command in the mscp and start it * - \***********************************************/ - bcopy(xs->cmd, mscp->cdb, xs->cmdlen); + /* + * Put the scsi command in the mscp and start it + */ + bcopy(xs->cmd, mscp->cdb, xs->cmdlen); - /***********************************************\ - * Usually return SUCCESSFULLY QUEUED * - \***********************************************/ - if (!(flags & SCSI_NOMASK)) - { + /* + * Usually return SUCCESSFULLY QUEUED + */ + if (!(flags & SCSI_NOMASK)) { s = splbio(); - uha_send_mbox(unit,mscp); - uha_add_timeout(mscp,xs->timeout); + uha_send_mbox(uha, mscp); + timeout(uha_timeout, (caddr_t)mscp, (xs->timeout * hz) / 1000); splx(s); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); + return SUCCESSFULLY_QUEUED; } - /***********************************************\ - * If we can't use interrupts, poll on completion* - \***********************************************/ - uha_send_mbox(unit,mscp); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_wait "); - do - { - if(uha_poll(unit,xs->timeout)) - { - if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); - if(!(uha_abort(unit,mscp))) - { - printf("abort failed in wait\n"); - uha_free_mscp(unit,mscp,flags); + + /* + * If we can't use interrupts, poll on completion + */ + uha_send_mbox(uha, mscp); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_wait\n")); + do { + if (uha_poll(uha, xs->timeout)) { + if (!(xs->flags & SCSI_SILENT)) + printf("%s: cmd fail\n", uha->sc_dev.dv_xname); + if (!uha_abort(uha, mscp)) { + printf("%s: abort failed in wait\n", + uha->sc_dev.dv_xname); + uha_free_mscp(uha, mscp, flags); } xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); + return HAD_ERROR; } } while (!(xs->flags & ITSDONE));/* something (?) else finished */ -scsi_debug = 0;uha_debug = 0; - if(xs->error) - { - return(HAD_ERROR); - } - return(COMPLETE); + if (xs->error) + return HAD_ERROR; + return COMPLETE; } -/* - * +----------+ +----------+ +----------+ - * uha_soonest--->| later |--->| later|--->| later|--->0 - * | [Delta] | | [Delta] | | [Delta] | - * 0<---|sooner |<---|sooner |<---|sooner |<---uha_latest - * +----------+ +----------+ +----------+ - * - * uha_furtherest = sum(Delta[1..n]) - */ -uha_add_timeout(mscp,time) -struct mscp *mscp; -int time; -{ - int timeprev; - struct mscp *prev; - int s = splbio(); - - if(prev = uha_latest) /* yes, an assign */ - { - timeprev = uha_furtherest; - } - else - { - timeprev = 0; - } - while(prev && (timeprev > time)) - { - timeprev -= prev->delta; - prev = prev->sooner; - } - if(prev) - { - mscp->delta = time - timeprev; - if( mscp->later = prev->later) /* yes an assign */ - { - mscp->later->sooner = mscp; - mscp->later->delta -= mscp->delta; - } - else - { - uha_furtherest = time; - uha_latest = mscp; - } - mscp->sooner = prev; - prev->later = mscp; - } - else - { - if( mscp->later = uha_soonest) /* yes, an assign*/ - { - mscp->later->sooner = mscp; - mscp->later->delta -= time; - } - else - { - uha_furtherest = time; - uha_latest = mscp; - } - mscp->delta = time; - mscp->sooner = (struct mscp *)0; - uha_soonest = mscp; - } - splx(s); -} - -uha_remove_timeout(mscp) -struct mscp *mscp; -{ - int s = splbio(); - - if(mscp->sooner) - { - mscp->sooner->later = mscp->later; - } - else - { - uha_soonest = mscp->later; - } - if(mscp->later) - { - mscp->later->sooner = mscp->sooner; - mscp->later->delta += mscp->delta; - } - else - { - uha_latest = mscp->sooner; - uha_furtherest -= mscp->delta; - } - mscp->sooner = mscp->later = (struct mscp *)0; - splx(s); -} - - -extern int hz; -#define ONETICK 500 /* milliseconds */ -#define SLEEPTIME ((hz * 1000) / ONETICK) +void uha_timeout(arg) -int arg; + caddr_t arg; { - struct mscp *mscp; - int unit; - int s = splbio(); - unsigned int stat; - int port = uha_data[unit].baseport; + int s = splbio(); + struct mscp *mscp = (void *)arg; + struct uha_softc *uha = mscp->xs->sc_link->adapter_softc; - while( mscp = uha_soonest ) - { - if(mscp->delta <= ONETICK) - /***********************************************\ - * It has timed out, we need to do some work * - \***********************************************/ - { - unit = mscp->xs->adapter; - printf("uha%d:%d device timed out\n",unit - ,mscp->xs->targ); - if(uha_debug & UHA_SHOWMSCPS) - uha_print_active_mscp(); + sc_print_addr(mscp->xs->sc_link); + printf("timed out"); - /***************************************\ - * Unlink it from the queue * - \***************************************/ - uha_remove_timeout(mscp); +#ifdef UHADEBUG + uha_print_active_mscp(uha); +#endif /*UHADEBUG */ - if((uha_abort(unit,mscp) !=1) || (mscp->flags = MSCP_ABORTED)) - { - printf("AGAIN"); - mscp->xs->retries = 0; /* I MEAN IT ! */ - uha_done(unit,mscp,FAIL); - } - else /* abort the operation that has timed out */ - { - printf("\n"); - uha_add_timeout(mscp,2000 + ONETICK); - mscp->flags = MSCP_ABORTED; - } - } - else - /***********************************************\ - * It has not timed out, adjust and leave * - \***********************************************/ - { - mscp->delta -= ONETICK; - uha_furtherest -= ONETICK; - break; - } + if (!uha_abort(uha, mscp) || (mscp->flags == MSCP_ABORTED)) { + printf(" AGAIN\n"); + mscp->xs->retries = 0; /* I MEAN IT ! */ + uha_done(uha, mscp); + } else { /* abort the operation that has timed out */ + printf("\n"); + timeout(uha_timeout, (caddr_t)mscp, 2 * hz); + mscp->flags = MSCP_ABORTED; } splx(s); - timeout(uha_timeout,arg,SLEEPTIME); } -uha_show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *)xs->cmd; - int i = 0; - if(!(xs->flags & SCSI_RESET)) - { - printf("uha%d:%d:%d-" - ,xs->adapter - ,xs->targ - ,xs->lu); - while(i < xs->cmdlen ) - { - if(i) printf(","); - printf("%x",b[i++]); - } - printf("-\n"); - } - else - { - printf("uha%d:%d:%d-RESET-\n" - ,xs->adapter - ,xs->targ - ,xs->lu - ); - } -} +#ifdef UHADEBUG +void uha_print_mscp(mscp) -struct mscp *mscp; + struct mscp *mscp; { - printf("mscp:%x op:%x cmdlen:%d senlen:%d\n" - ,mscp - ,mscp->opcode - ,mscp->cdblen - ,mscp->senselen); - printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n" - ,mscp->sgth - ,mscp->sg_num - ,mscp->datalen - ,mscp->ha_status - ,mscp->targ_status - ,mscp->delta - ,mscp->flags); - uha_show_scsi_cmd(mscp->xs); + + printf("mscp:%x op:%x cmdlen:%d senlen:%d\n", + mscp, mscp->opcode, mscp->cdblen, mscp->senselen); + printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x flags:%x\n", + mscp->sgth, mscp->sg_num, mscp->datalen, mscp->ha_status, + mscp->targ_status, mscp->flags); + show_scsi_cmd(mscp->xs); } -uha_print_active_mscp() +void +uha_print_active_mscp(uha) + struct uha_softc *uha; { - struct mscp *mscp; - mscp = uha_soonest; + struct mscp *mscp; + int i = 0; - while(mscp) - { - uha_print_mscp(mscp); - mscp = mscp->later; + while (i++ < MSCP_HASH_SIZE) { + mscp = uha->mscphash[i]; + while (mscp) { + if (mscp->flags != MSCP_FREE) + uha_print_mscp(mscp); + mscp = mscp->nexthash; + } } - printf("Furtherest = %d\n",uha_furtherest); } +#endif /*UHADEBUG */ diff --git a/sys/dev/eisa/aha1742.c b/sys/dev/eisa/aha1742.c index 09e02ae74ad9..6da708734d8b 100644 --- a/sys/dev/eisa/aha1742.c +++ b/sys/dev/eisa/aha1742.c @@ -1,5 +1,36 @@ /* - * Written by Julian Elischer (julian@tfs.com) + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: aha1742.c,v 1.23 1994/03/29 04:30:18 mycroft Exp $ + */ + +/* + * Originally written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -12,63 +43,66 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * $Id: aha1742.c,v 1.22 1994/03/25 07:40:53 mycroft Exp $ + * commenced: Sun Sep 27 18:14:01 PDT 1992 */ -#include "ahb.h" - #include #include #include +#include #include #include +#include +#include #include #include #include -#include -#include -#include #include +#include +#include #include #include -#include - - #ifdef DDB -int Debugger(); -#else DDB -#define Debugger() panic("should call debugger here (adaptec.c)") -#endif DDB +int Debugger(); +#else /* DDB */ +#define Debugger() +#endif /* DDB */ -typedef unsigned long int physaddr; +typedef u_long physaddr; -#define PHYSTOKV(x) ((x) + KERNBASE) -#define KVTOPHYS(x) vtophys(x) +#define KVTOPHYS(x) vtophys(x) -extern int delaycount; /* from clock setup code */ -#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ -#define AHB_NSEG 33 /* number of dma segments supported */ -#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ +#define AHB_ECB_MAX 32 /* store up to 32ECBs at any one time */ + /* in aha1742 H/W ( Not MAX ? ) */ +#define ECB_HASH_SIZE 32 /* when we have a physical addr. for */ + /* a ecb and need to find the ecb in */ + /* space, look it up in the hash table */ +#define ECB_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define ECB_HASH(x) ((((long int)(x))>>ECB_HASH_SHIFT) % ECB_HASH_SIZE) +#define AHB_NSEG 33 /* number of dma segments supported */ /* * AHA1740 standard EISA Host ID regs (Offset from slot base) */ -#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ -#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ -#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ -#define HID3 0xC83 /* firmware revision */ +#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */ +#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */ +#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */ +#define HID3 0xC83 /* firmware revision */ #define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@') #define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@') #define CHAR3(B1,B2) ((B2 & 0x1F) | '@') -/* AHA1740 EISA board control registers (Offset from slot base) */ +/* + * AHA1740 EISA board control registers (Offset from slot base) + */ #define EBCTRL 0xC84 #define CDEN 0x01 + /* * AHA1740 EISA board mode registers (Offset from slot base) */ @@ -81,24 +115,21 @@ extern int delaycount; /* from clock setup code */ #define RESV0 0xCC5 #define RESV1 0xCC6 #define RESV2 0xCC7 - -/* bit definitions for INTDEF */ +/**** bit definitions for INTDEF ****/ #define INT9 0x00 #define INT10 0x01 #define INT11 0x02 #define INT12 0x03 #define INT14 0x05 #define INT15 0x06 -#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ +#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */ #define INTEN 0x10 - -/* bit definitions for SCSIDEF */ -#define HSCSIID 0x0F /* our SCSI ID */ -#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ - -/* bit definitions for BUSDEF */ -#define B0uS 0x00 /* give up bus immediatly */ -#define B4uS 0x01 /* delay 4uSec. */ +/**** bit definitions for SCSIDEF ****/ +#define HSCSIID 0x0F /* our SCSI ID */ +#define RSTPWR 0x10 /* reset scsi bus on power up or reset */ +/**** bit definitions for BUSDEF ****/ +#define B0uS 0x00 /* give up bus immediatly */ +#define B4uS 0x01 /* delay 4uSec. */ #define B8uS 0x02 /* @@ -151,225 +182,253 @@ extern int delaycount; /* from clock setup code */ #define G2STAT2_HOST_READY 0x01 - struct ahb_dma_seg { - physaddr addr; - long len; + physaddr addr; + long len; }; struct ahb_ecb_status { - u_short status; -# define ST_DON 0x0001 -# define ST_DU 0x0002 -# define ST_QF 0x0008 -# define ST_SC 0x0010 -# define ST_DO 0x0020 -# define ST_CH 0x0040 -# define ST_INT 0x0080 -# define ST_ASA 0x0100 -# define ST_SNS 0x0200 -# define ST_INI 0x0800 -# define ST_ME 0x1000 -# define ST_ECA 0x4000 - u_char ha_status; -# define HS_OK 0x00 -# define HS_CMD_ABORTED_HOST 0x04 -# define HS_CMD_ABORTED_ADAPTER 0x05 -# define HS_TIMED_OUT 0x11 -# define HS_HARDWARE_ERR 0x20 -# define HS_SCSI_RESET_ADAPTER 0x22 -# define HS_SCSI_RESET_INCOMING 0x23 - u_char targ_status; -# define TS_OK 0x00 -# define TS_CHECK_CONDITION 0x02 -# define TS_BUSY 0x08 - u_long resid_count; - u_long resid_addr; - u_short addit_status; - u_char sense_len; - u_char unused[9]; - u_char cdb[6]; + u_short status; +#define ST_DON 0x0001 +#define ST_DU 0x0002 +#define ST_QF 0x0008 +#define ST_SC 0x0010 +#define ST_DO 0x0020 +#define ST_CH 0x0040 +#define ST_INT 0x0080 +#define ST_ASA 0x0100 +#define ST_SNS 0x0200 +#define ST_INI 0x0800 +#define ST_ME 0x1000 +#define ST_ECA 0x4000 + u_char ha_status; +#define HS_OK 0x00 +#define HS_CMD_ABORTED_HOST 0x04 +#define HS_CMD_ABORTED_ADAPTER 0x05 +#define HS_TIMED_OUT 0x11 +#define HS_HARDWARE_ERR 0x20 +#define HS_SCSI_RESET_ADAPTER 0x22 +#define HS_SCSI_RESET_INCOMING 0x23 + u_char targ_status; +#define TS_OK 0x00 +#define TS_CHECK_CONDITION 0x02 +#define TS_BUSY 0x08 + u_long resid_count; + u_long resid_addr; + u_short addit_status; + u_char sense_len; + u_char unused[9]; + u_char cdb[6]; }; - struct ecb { - u_char opcode; -# define ECB_SCSI_OP 0x01 - u_char :4; - u_char options:3; - u_char :1; - short opt1; -# define ECB_CNE 0x0001 -# define ECB_DI 0x0080 -# define ECB_SES 0x0400 -# define ECB_S_G 0x1000 -# define ECB_DSB 0x4000 -# define ECB_ARS 0x8000 - short opt2; -# define ECB_LUN 0x0007 -# define ECB_TAG 0x0008 -# define ECB_TT 0x0030 -# define ECB_ND 0x0040 -# define ECB_DAT 0x0100 -# define ECB_DIR 0x0200 -# define ECB_ST 0x0400 -# define ECB_CHK 0x0800 -# define ECB_REC 0x4000 -# define ECB_NRB 0x8000 - u_short unused1; - physaddr data; - u_long datalen; - physaddr status; - physaddr chain; - short unused2; - short unused3; - physaddr sense; - u_char senselen; - u_char cdblen; - short cksum; - u_char cdb[12]; + u_char opcode; +#define ECB_SCSI_OP 0x01 + u_char:4; + u_char options:3; + u_char:1; + short opt1; +#define ECB_CNE 0x0001 +#define ECB_DI 0x0080 +#define ECB_SES 0x0400 +#define ECB_S_G 0x1000 +#define ECB_DSB 0x4000 +#define ECB_ARS 0x8000 + short opt2; +#define ECB_LUN 0x0007 +#define ECB_TAG 0x0008 +#define ECB_TT 0x0030 +#define ECB_ND 0x0040 +#define ECB_DAT 0x0100 +#define ECB_DIR 0x0200 +#define ECB_ST 0x0400 +#define ECB_CHK 0x0800 +#define ECB_REC 0x4000 +#define ECB_NRB 0x8000 + u_short unused1; + physaddr data; + u_long datalen; + physaddr status; + physaddr chain; + short unused2; + short unused3; + physaddr sense; + u_char senselen; + u_char cdblen; + short cksum; + u_char cdb[12]; /*-----------------end of hardware supported fields----------------*/ - struct ecb *next; /* in free list */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - long int delta; /* difference from previous*/ - struct ecb *later,*sooner; - int flags; + struct ecb *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + int flags; #define ECB_FREE 0 #define ECB_ACTIVE 1 #define ECB_ABORTED 2 #define ECB_IMMED 4 #define ECB_IMMED_FAIL 8 - struct ahb_dma_seg ahb_dma[AHB_NSEG]; - struct ahb_ecb_status ecb_status; - struct scsi_sense_data ecb_sense; + struct ahb_dma_seg ahb_dma[AHB_NSEG]; + struct ahb_ecb_status ecb_status; + struct scsi_sense_data ecb_sense; + struct ecb *nexthash; + physaddr hashkey; /* physaddr of this struct */ }; -struct ecb *ahb_soonest = (struct ecb *)0; -struct ecb *ahb_latest = (struct ecb *)0; -long int ahb_furtherest = 0; /* longest time in the timeout queue */ +struct ahb_softc { + struct device sc_dev; + struct isadev sc_id; + struct intrhand sc_ih; -struct ahb_data { - int flags; -#define AHB_INIT 0x01; - int baseport; - struct ecb ecbs[NUM_CONCURRENT]; + u_short baseport; + struct ecb *ecbhash[ECB_HASH_SIZE]; struct ecb *free_ecb; - int vect; - struct ecb *immed_ecb; /* an outstanding immediete command */ -} ahb_data[NAHB]; + int our_id; /* our scsi id */ + int vect; + struct ecb *immed_ecb; /* an outstanding immediete command */ + int numecbs; + struct scsi_link sc_link; +}; -struct ecb *cheat; +void ahb_send_mbox __P((struct ahb_softc *, int, int, struct ecb *)); +int ahb_poll __P((struct ahb_softc *, int)); +void ahb_send_immed __P((struct ahb_softc *, int, u_long)); +u_int ahb_adapter_info __P((struct ahb_softc *)); +int ahbintr __P((int)); +void ahb_done __P((struct ahb_softc *, struct ecb *, int)); +void ahb_free_ecb __P((struct ahb_softc *, struct ecb *, int)); +struct ecb *ahb_get_ecb __P((struct ahb_softc *, int)); +struct ecb *ahb_ecb_phys_kv __P((struct ahb_softc *, physaddr)); +int ahb_find __P((struct ahb_softc *)); +void ahb_init __P((struct ahb_softc *)); +void ahbminphys __P((struct buf *)); +int ahb_scsi_cmd __P((struct scsi_xfer *)); +void ahb_timeout __P((caddr_t)); +void ahb_print_ecb __P((struct ecb *)); +void ahb_print_active_ecb __P((struct ahb_softc *)); -#define MAX_SLOTS 8 -static ahb_slot = 0; /* slot last board was found in */ -static ahb_unit = 0; -int ahb_debug = 0; +struct ecb *cheat; + +#define MAX_SLOTS 15 +static ahb_slot = 0; /* slot last board was found in */ +int ahb_debug = 0; #define AHB_SHOWECBS 0x01 #define AHB_SHOWINTS 0x02 #define AHB_SHOWCMDS 0x04 #define AHB_SHOWMISC 0x08 -#define FAIL 1 -#define SUCCESS 0 -#define PAGESIZ 4096 - -int ahbprobe(struct isa_device *); -int ahbprobe1(struct isa_device *); -int ahb_attach(struct isa_device *); -long int ahb_adapter_info(int); -int ahbintr(int); -void ahb_done(int, struct ecb *, int); -void ahb_free_ecb(int, struct ecb *, int); -struct ecb * ahb_get_ecb(int, int); -int ahb_init(int); -void ahbminphys(struct buf *); -int ahb_scsi_cmd(struct scsi_xfer *); -void ahb_add_timeout(struct ecb *, int); -void ahb_remove_timeout(struct ecb *); -void ahb_timeout(int); -void ahb_show_scsi_cmd(struct scsi_xfer *); -void ahb_print_ecb(struct ecb *); -void ahb_print_active_ecb(void); - - -struct isa_driver ahbdriver = { - ahbprobe, - ahb_attach, +struct scsi_adapter ahb_switch = { + ahb_scsi_cmd, + ahbminphys, + 0, + 0, + ahb_adapter_info, "ahb" }; -struct scsi_switch ahb_switch[NAHB]; +/* the below structure is so we have a default dev struct for our link struct */ +struct scsi_device ahb_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "ahb", + 0 +}; + +int ahbprobe(); +int ahbprobe1 __P((struct ahb_softc *, struct isa_attach_args *)); +void ahbattach(); + +struct cfdriver ahbcd = { + NULL, "ahb", ahbprobe, ahbattach, DV_DULL, sizeof(struct ahb_softc) +}; /* * Function to send a command out through a mailbox */ void -ahb_send_mbox(int unit, int opcode, int target, struct ecb *ecb) +ahb_send_mbox(ahb, opcode, target, ecb) + struct ahb_softc *ahb; + int opcode, target; + struct ecb *ecb; { - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ - int stport = port + G2STAT, s; + u_short port = ahb->baseport; + u_short stport = port + G2STAT; + int wait = 100; /* 1ms should be enough */ + int s = splbio(); - s = splbio(); - while( ((inb(stport) & - (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) != G2STAT_MBOX_EMPTY) - && spincount--) - ; - if(spincount == -1) { - printf("ahb%d: board not responding\n",unit); + while (--wait) { + if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + == (G2STAT_MBOX_EMPTY)) + break; + delay(10); + } + if (!wait) { + printf("%s: board not responding\n", ahb->sc_dev.dv_xname); Debugger(); } - outl(port+MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */ - outb(port+ATTN, opcode|target); + outl(port + MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */ + outb(port + ATTN, opcode | target); + splx(s); } /* * Function to poll for command completion when in poll mode - * wait is in msec */ int -ahb_poll(int unit, int wait) -{ - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * wait; /* in msec */ - int stport = port + G2STAT; - int start = spincount; +ahb_poll(ahb, wait) + struct ahb_softc *ahb; + int wait; +{ /* in msec */ + u_short port = ahb->baseport; + u_short stport = port + G2STAT; -retry: - while( spincount-- && (!(inb(stport) & G2STAT_INT_PEND))) - ; - if(spincount == -1) { - printf("ahb%d: board not responding\n",unit); - return(EIO); + retry: + while (--wait) { + if (inb(stport) & G2STAT_INT_PEND) + break; + delay(1000); } - if( (int)cheat != PHYSTOKV(inl(port+MBOXIN0)) ) { - printf("discarding %x ", inl(port+MBOXIN0)); + if (!wait) { + printf("%s: board not responding\n", ahb->sc_dev.dv_xname); + return EIO; + } + + if (cheat != ahb_ecb_phys_kv(ahb, inl(port + MBOXIN0))) { + printf("discarding %x ", inl(port + MBOXIN0)); outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - spinwait(50); + delay(50000); goto retry; } - ahbintr(unit); - return(0); + + /* don't know this will work */ + ahbintr(ahb->sc_dev.dv_unit); + return 0; } + /* * Function to send an immediate type command to the adapter */ void -ahb_send_immed(int unit, int target, u_long cmd) +ahb_send_immed(ahb, target, cmd) + struct ahb_softc *ahb; + int target; + u_long cmd; { - int port = ahb_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; /* 1ms should be enough */ + u_short port = ahb->baseport; + u_short stport = port + G2STAT; + int wait = 100; /* 1 ms enough? */ int s = splbio(); - int stport = port + G2STAT; - while( ((inb(stport) & - (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) != (G2STAT_MBOX_EMPTY)) && - spincount--) - ; - if(spincount == -1) { - printf("ahb%d: board not responding\n",unit); + while (--wait) { + if ((inb(stport) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY)) + == (G2STAT_MBOX_EMPTY)) + break; + delay(10); + } + if (!wait) { + printf("%s: board not responding\n", ahb->sc_dev.dv_xname); Debugger(); } @@ -380,234 +439,257 @@ ahb_send_immed(int unit, int target, u_long cmd) } /* - * Check the slots looking for a board we recognise + * Check the slots looking for a board we recognise * If we find one, note it's address (slot) and call * the actual probe routine to check it out. */ int -ahbprobe(struct isa_device *dev) +ahbprobe(parent, self, aux) + struct device *parent, *self; + void *aux; { - int port; - u_char byte1,byte2,byte3; + struct ahb_softc *ahb = (void *)self; + struct isa_attach_args *ia = aux; + u_short port; + u_char byte1, byte2, byte3; - if (dev->id_parent) - return 1; +#ifdef NEWCONFIG + if (ia->ia_iobase != IOBASEUNK) + return ahbprobe1(ahb, ia); +#endif - ahb_slot++; - while (ahb_slot<8) { + while (ahb_slot < MAX_SLOTS) { + ahb_slot++; port = 0x1000 * ahb_slot; byte1 = inb(port + HID0); byte2 = inb(port + HID1); byte3 = inb(port + HID2); - if(byte1 == 0xff) { - ahb_slot++; + if (byte1 == 0xff) + continue; + if (CHAR1(byte1, byte2) != 'A' || + CHAR2(byte1, byte2) != 'D' || + CHAR3(byte1, byte2) != 'P' || + (byte3 != 0 && byte3 != 1)) { continue; } - if ((CHAR1(byte1,byte2) == 'A') - && (CHAR2(byte1,byte2) == 'D') - && (CHAR3(byte1,byte2) == 'P') - && ((byte3 == 0 ) || (byte3 == 1))) { - dev->id_iobase = port; - return ahbprobe1(dev); - } - ahb_slot++; + ia->ia_iobase = port; + if (ahbprobe1(ahb, ia)) + return 1; } + return 0; } /* - * Check if the device can be found at the port given * - * and if so, set it up ready for further work * - * as an argument, takes the isa_device structure from * - * autoconf.c * + * Check if the device can be found at the port given + * and if so, set it up ready for further work + * as an argument, takes the isa_device structure from + * autoconf.c. */ int -ahbprobe1(struct isa_device *dev) +ahbprobe1(ahb, ia) + struct ahb_softc *ahb; + struct isa_attach_args *ia; { - int unit = ahb_unit; - dev->id_unit = unit; - ahb_data[unit].baseport = dev->id_iobase; - if(unit >= NAHB) { - printf("ahb: unit number (%d) too high\n",unit); - return 0; - } + ahb->baseport = ia->ia_iobase; /* * Try initialise a unit at this location - * sets up dma and bus speed, loads ahb_data[unit].vect* + * sets up dma and bus speed, loads ahb->vect */ - if (ahb_init(unit) != 0) + if (ahb_find(ahb) != 0) return 0; - /* If it's there, put in it's interrupt vectors */ - dev->id_irq = (1 << ahb_data[unit].vect); - dev->id_drq = -1; /* using EISA dma */ - ahb_unit++; - return 0x1000; +#ifdef NEWCONFIG + if (ia->ia_irq == IRQUNK) { + ia->ia_irq = (1 << ahb->vect); + } else { + if (ia->ia_irq != (1 << ahb->vect)) { + printf("ahb%d: irq mismatch, %x != %x\n", + ahb->sc_dev.dv_unit, ia->ia_irq, + 1 << ahb->vect); + return 0; + } + } +#endif + + ia->ia_drq = DRQUNK; + ia->ia_msize = 0; + ia->ia_iosize = 0x1000; + return 1; +} + +ahbprint() +{ + } /* * Attach all the sub-devices we can find */ -int -ahb_attach(struct isa_device *dev) +void +ahbattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - static int firsttime; - static int firstswitch[NAHB]; - int masunit; - int r; + struct isa_attach_args *ia = aux; + struct ahb_softc *ahb = (void *)self; - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; + ahb_init(ahb); - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - ahb_switch[masunit].name = "ahb"; - ahb_switch[masunit].scsi_cmd = ahb_scsi_cmd; - ahb_switch[masunit].scsi_minphys = ahbminphys; - ahb_switch[masunit].open_target_lu = 0; - ahb_switch[masunit].close_target_lu = 0; - ahb_switch[masunit].adapter_info = ahb_adapter_info; - for (r = 0; r < 8; r++) { - ahb_switch[masunit].empty[r] = 0; - ahb_switch[masunit].used[r] = 0; - ahb_switch[masunit].printed[r] = 0; - } - } - r = scsi_attach(masunit, &ahb_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); + /* + * fill in the prototype scsi_link. + */ + ahb->sc_link.adapter_softc = ahb; + ahb->sc_link.adapter_targ = ahb->our_id; + ahb->sc_link.adapter = &ahb_switch; + ahb->sc_link.device = &ahb_dev; - /* only one for all boards */ - if(firsttime==0) { - firsttime = 1; - ahb_timeout(0); - } - return r; + printf("\n"); + +#ifdef NEWCONFIG + isa_establish(&ahb->sc_id, &ahb->sc_dev); + ahb->sc_ih.ih_fun = ahbintr; + ahb->sc_ih.ih_arg = ahb; + /* XXX and DV_TAPE, but either gives us splbio */ + intr_establish(ia->ia_irq, &ahb->sc_ih, DV_DISK); +#endif + + /* + * ask the adapter what subunits are present + */ + config_found(self, &ahb->sc_link, ahbprint); } /* - * Return some information to the caller about * - * the adapter and it's capabilities * - * 2 outstanding requests at a time per device + * Return some information to the caller about + * the adapter and it's capabilities */ -long int -ahb_adapter_info(int unit) +u_int +ahb_adapter_info(ahb) + struct ahb_softc *ahb; { - return 2; + + return 2; /* 2 outstanding requests at a time per device */ } /* * Catch an interrupt from the adaptor */ int -ahbintr(int unit) +ahbintr(unit) + int unit; { - struct ecb *ecb; - unsigned char stat; - register i; - u_char ahbstat; - int target; - long int mboxval; + struct ahb_softc *ahb = ahbcd.cd_devs[unit]; + struct ecb *ecb; + u_char stat, ahbstat; + u_long mboxval; + u_short port = ahb->baseport; - int port = ahb_data[unit].baseport; +#ifdef AHBDEBUG + printf("ahbintr "); +#endif /*AHBDEBUG */ - if(scsi_debug & PRINTROUTINES) - printf("ahbintr "); - - while(inb(port + G2STAT) & G2STAT_INT_PEND) { + while (inb(port + G2STAT) & G2STAT_INT_PEND) { /* * First get all the information and then * acknowlege the interrupt */ ahbstat = inb(port + G2INTST); - target = ahbstat & G2INTST_TARGET; stat = ahbstat & G2INTST_INT_STAT; - mboxval = inl(port + MBOXIN0);/* don't know this will work */ + mboxval = inl(port + MBOXIN0); /* don't know this will work */ outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - if(scsi_debug & TRACEINTERRUPTS) - printf("status = 0x%x ",stat); + +#ifdef AHBDEBUG + printf("status = 0x%x ", ahbstat); +#endif /*AHBDEBUG */ /* * Process the completed operation */ - if(stat == AHB_ECB_OK) - ecb = (struct ecb *)PHYSTOKV(mboxval); - else { - switch(stat) { + if (stat == AHB_ECB_OK) { /* common case is fast */ + ecb = ahb_ecb_phys_kv(ahb, mboxval); + } else { + switch (stat) { case AHB_IMMED_OK: - ecb = ahb_data[unit].immed_ecb; - ahb_data[unit].immed_ecb = 0; + ecb = ahb->immed_ecb; + ahb->immed_ecb = 0; break; case AHB_IMMED_ERR: - ecb = ahb_data[unit].immed_ecb; + ecb = ahb->immed_ecb; ecb->flags |= ECB_IMMED_FAIL; - ahb_data[unit].immed_ecb = 0; + ahb->immed_ecb = 0; break; case AHB_ASN: /* for target mode */ + printf("%s: Unexpected ASN interrupt(%x)\n", + ahb->sc_dev.dv_xname, mboxval); ecb = 0; break; case AHB_HW_ERR: + printf("%s: Hardware error interrupt(%x)\n", + ahb->sc_dev.dv_xname, mboxval); ecb = 0; break; case AHB_ECB_RECOVERED: - ecb = (struct ecb *)PHYSTOKV(mboxval); + ecb = ahb_ecb_phys_kv(ahb, mboxval); break; case AHB_ECB_ERR: - ecb = (struct ecb *)PHYSTOKV(mboxval); + ecb = ahb_ecb_phys_kv(ahb, mboxval); break; default: - printf(" Unknown return from ahb%d(%x)\n",unit,ahbstat); - ecb=0; + printf("%s: Unknown return %x\n", + ahb->sc_dev.dv_xname, ahbstat); + ecb = 0; } - } - if(ecb) { - if(ahb_debug & AHB_SHOWCMDS ) - ahb_show_scsi_cmd(ecb->xs); - if((ahb_debug & AHB_SHOWECBS) && ecb) - printf("",ecb); - ahb_remove_timeout(ecb); - ahb_done(unit, ecb, (stat==AHB_ECB_OK)? SUCCESS: FAIL); + } if (ecb) { +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWCMDS) + show_scsi_cmd(ecb->xs); + if ((ahb_debug & AHB_SHOWECBS) && ecb) + printf("", ecb); +#endif /*AHBDEBUG */ + untimeout((timeout_t)ahb_timeout, (caddr_t)ecb); + ahb_done(ahb, ecb, stat != AHB_ECB_OK); } } return 1; } /* - * We have a ecb which has been processed by the - * adaptor, now we look to see how the operation - * went. + * We have a ecb which has been processed by the adaptor, now we look to see + * how the operation went. */ void -ahb_done(int unit, struct ecb *ecb, int state) +ahb_done(ahb, ecb, failed) + struct ahb_softc *ahb; + struct ecb *ecb; + int failed; { - struct ahb_ecb_status *stat = &ecb->ecb_status; - struct scsi_sense_data *s1,*s2; + struct ahb_ecb_status *stat = &ecb->ecb_status; + struct scsi_sense_data *s1, *s2; struct scsi_xfer *xs = ecb->xs; - if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("ahb_done "); - + SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_done\n")); /* * Otherwise, put the results of the operation * into the xfer and call whoever started it */ - if(ecb->flags & ECB_IMMED) { - if(ecb->flags & ECB_IMMED_FAIL) + if (ecb->flags & ECB_IMMED) { + if (ecb->flags & ECB_IMMED_FAIL) xs->error = XS_DRIVER_STUFFUP; goto done; } - if ( (state == SUCCESS) || (xs->flags & SCSI_ERR_OK)) { - /* All went correctly OR errors expected */ + + if (!failed || (xs->flags & SCSI_ERR_OK)) { /* All went correctly OR errors expected */ xs->resid = 0; xs->error = 0; } else { s1 = &(ecb->ecb_sense); s2 = &(xs->sense); - if(stat->ha_status) { - switch(stat->ha_status) { + if (stat->ha_status) { + switch (stat->ha_status) { case HS_SCSI_RESET_ADAPTER: break; case HS_SCSI_RESET_INCOMING: @@ -615,22 +697,25 @@ ahb_done(int unit, struct ecb *ecb, int state) case HS_CMD_ABORTED_HOST: /* No response */ case HS_CMD_ABORTED_ADAPTER: /* No response */ break; - case HS_TIMED_OUT: /* No response */ + case HS_TIMED_OUT: /* No response */ +#ifdef AHBDEBUG if (ahb_debug & AHB_SHOWMISC) printf("timeout reported back\n"); +#endif /*AHBDEBUG */ xs->error = XS_TIMEOUT; break; - default: - /* Other scsi protocol messes */ + default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; +#ifdef AHBDEBUG if (ahb_debug & AHB_SHOWMISC) - printf("unexpected ha_status: %x\n", + printf("unexpected ha_status %x\n", stat->ha_status); +#endif /*AHBDEBUG */ } - } else { - switch(stat->targ_status) { + switch (stat->targ_status) { case TS_CHECK_CONDITION: + /* structure copy!!!!! */ *s2 = *s1; xs->error = XS_SENSE; break; @@ -638,19 +723,20 @@ ahb_done(int unit, struct ecb *ecb, int state) xs->error = XS_BUSY; break; default: - if (ahb_debug & AHB_SHOWMISC) - printf("unexpected targ_status: %x\n", +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWMISC) { + printf("unexpected targ_status %x\n", stat->targ_status); + } +#endif /*AHBDEBUG */ xs->error = XS_DRIVER_STUFFUP; } } } - -done: + done: xs->flags |= ITSDONE; - ahb_free_ecb(unit, ecb, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + ahb_free_ecb(ahb, ecb, xs->flags); + scsi_done(xs); } /* @@ -658,72 +744,122 @@ done: * free list. */ void -ahb_free_ecb(int unit, struct ecb *ecb, int flags) +ahb_free_ecb(ahb, ecb, flags) + struct ahb_softc *ahb; + struct ecb *ecb; + int flags; { - unsigned int opri; + int opri; - if(scsi_debug & PRINTROUTINES) - printf("ecb%d(0x%x)> ",unit,flags); - if (!(flags & SCSI_NOMASK)) - opri = splbio(); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); - ecb->next = ahb_data[unit].free_ecb; - ahb_data[unit].free_ecb = ecb; + ecb->next = ahb->free_ecb; + ahb->free_ecb = ecb; ecb->flags = ECB_FREE; - /* * If there were none, wake abybody waiting for - * one to come free, starting with queued entries* + * one to come free, starting with queued entries */ if (!ecb->next) - wakeup((caddr_t)&ahb_data[unit].free_ecb); + wakeup((caddr_t)&ahb->free_ecb); - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); } /* - * Get a free ecb (and hence mbox-out entry) + * Get a free ecb + * + * If there are none, see if we can allocate a new one. If so, put it in the + * hash table too otherwise either return an error or sleep. */ struct ecb * -ahb_get_ecb(int unit, int flags) +ahb_get_ecb(ahb, flags) + struct ahb_softc *ahb; + int flags; { - unsigned opri; - struct ecb *rc; + int opri; + struct ecb *ecbp; + int hashnum; - if(scsi_debug & PRINTROUTINES) - printf("next; - rc->flags = ECB_ACTIVE; + while (!(ecbp = ahb->free_ecb)) { + if (ahb->numecbs < AHB_ECB_MAX) { + if (ecbp = (struct ecb *) malloc(sizeof(struct ecb), + M_TEMP, + M_NOWAIT)) { + bzero(ecbp, sizeof(struct ecb)); + ahb->numecbs++; + ecbp->flags = ECB_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + ecbp->hashkey = KVTOPHYS(ecbp); + hashnum = ECB_HASH(ecbp->hashkey); + ecbp->nexthash = ahb->ecbhash[hashnum]; + ahb->ecbhash[hashnum] = ecbp; + } else { + printf("%s: Can't malloc ECB\n", + ahb->sc_dev.dv_xname); + } + goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) + tsleep((caddr_t)&ahb->free_ecb, PRIBIO, + "ahbecb", 0); + } } - - if (!(flags & SCSI_NOMASK)) + if (ecbp) { + /* Get ECB from from free list */ + ahb->free_ecb = ecbp->next; + ecbp->flags = ECB_ACTIVE; + } + gottit: + if (!(flags & SCSI_NOMASK)) splx(opri); - return rc; + + return ecbp; +} + +/* + * given a physical address, find the ecb that it corresponds to. + */ +struct ecb * +ahb_ecb_phys_kv(ahb, ecb_phys) + struct ahb_softc *ahb; + physaddr ecb_phys; +{ + int hashnum = ECB_HASH(ecb_phys); + struct ecb *ecbp = ahb->ecbhash[hashnum]; + + while (ecbp) { + if (ecbp->hashkey == ecb_phys) + break; + ecbp = ecbp->nexthash; + } + return ecbp; } /* * Start the board, ready for normal operation */ int -ahb_init(int unit) +ahb_find(ahb) + struct ahb_softc *ahb; { - int port = ahb_data[unit].baseport; - int intdef; - int spincount = FUDGE(delaycount) * 1000; /* 1 sec enough? */ + u_short port = ahb->baseport; + u_short stport = port + G2STAT; + u_char intdef; int i; - int stport = port + G2STAT; + int wait = 1000; /* 1 sec enough? */ #define NO_NO 1 #ifdef NO_NO @@ -731,497 +867,388 @@ ahb_init(int unit) * reset board, If it doesn't respond, assume * that it's not there.. good for the probe */ - outb(port + EBCTRL,CDEN); /* enable full card */ - outb(port + PORTADDR,PORTADDR_ENHANCED); + outb(port + EBCTRL, CDEN); /* enable full card */ + outb(port + PORTADDR, PORTADDR_ENHANCED); - outb(port + G2CNTRL,G2CNTRL_HARD_RESET); - spinwait(1); - outb(port + G2CNTRL,0); - spinwait(10); - while( (inb(stport) & G2STAT_BUSY ) && spincount--) - ; - if(spincount == -1) { - if (ahb_debug & AHB_SHOWMISC) - printf("ahb_init: No answer from bt742a board\n"); - return(ENXIO); + outb(port + G2CNTRL, G2CNTRL_HARD_RESET); + delay(1000); + outb(port + G2CNTRL, 0); + delay(10000); + while (--wait) { + if ((inb(stport) & G2STAT_BUSY) == 0) + break; + delay(1000); } - - i = inb(port + MBOXIN0) & 0xff; - if(i) { - printf("self test failed, val = 0x%x\n",i); - return(EIO); + if (!wait) { +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWMISC) + printf("ahb_find: No answer from aha1742 board\n"); +#endif /*AHBDEBUG */ + return ENXIO; + } + i = inb(port + MBOXIN0); + if (i) { + printf("self test failed, val = 0x%x\n", i); + return EIO; } #endif - while( inb(stport) & G2STAT_INT_PEND) { + while (inb(stport) & G2STAT_INT_PEND) { printf("."); outb(port + G2CNTRL, G2CNTRL_CLEAR_EISA_INT); - spinwait(10); + delay(10000); } - outb(port + EBCTRL,CDEN); /* enable full card */ - outb(port + PORTADDR,PORTADDR_ENHANCED); - - /* - * Assume we have a board at this stage - * setup dma channel from jumpers and save int - * level - */ + outb(port + EBCTRL, CDEN); /* enable full card */ + outb(port + PORTADDR, PORTADDR_ENHANCED); intdef = inb(port + INTDEF); - switch(intdef & 0x07) { + switch (intdef & 0x07) { case INT9: - ahb_data[unit].vect = 9; + ahb->vect = 9; break; case INT10: - ahb_data[unit].vect = 10; + ahb->vect = 10; break; case INT11: - ahb_data[unit].vect = 11; + ahb->vect = 11; break; case INT12: - ahb_data[unit].vect = 12; + ahb->vect = 12; break; case INT14: - ahb_data[unit].vect = 14; + ahb->vect = 14; break; case INT15: - ahb_data[unit].vect = 15; + ahb->vect = 15; break; default: - ahb_data[unit].vect = -1; - printf("ahb%d: illegal irq setting\n", unit); - return(EIO); + printf("illegal int setting %x\n", intdef); + return EIO; } - outb(port + INTDEF, intdef|INTEN); /* make sure we can interrupt */ - ahb_switch[unit].scsi_dev = (inb(port + SCSIDEF) & HSCSIID); + outb(port + INTDEF, (intdef | INTEN)); /* make sure we can interrupt */ - /* - * link up all our ECBs into a free list - */ - for (i=0; i < NUM_CONCURRENT; i++) { - ahb_data[unit].ecbs[i].next = ahb_data[unit].free_ecb; - ahb_data[unit].free_ecb = &ahb_data[unit].ecbs[i]; - ahb_data[unit].free_ecb->flags = ECB_FREE; - } + /* who are we on the scsi bus? */ + ahb->our_id = (inb(port + SCSIDEF) & HSCSIID); /* * Note that we are going and return (to probe) */ - ahb_data[unit].flags |= AHB_INIT; return 0; } void -ahbminphys(struct buf *bp) +ahb_init(ahb) + struct ahb_softc *ahb; { - if(bp->b_bcount > ((AHB_NSEG-1) * PAGESIZ)) - bp->b_bcount = ((AHB_NSEG-1) * PAGESIZ); + +} + +void +ahbminphys(bp) + struct buf *bp; +{ + + if (bp->b_bcount > ((AHB_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((AHB_NSEG - 1) << PGSHIFT); } /* - * start a scsi operation given the command and - * the data address. Also needs the unit, target - * and lu + * start a scsi operation given the command and the data address. Also needs + * the unit, target and lu. */ -int -ahb_scsi_cmd(struct scsi_xfer *xs) +int +ahb_scsi_cmd(xs) + struct scsi_xfer *xs; { - struct scsi_sense_data *s1,*s2; + struct scsi_link *sc_link = xs->sc_link; + struct ahb_softc *ahb = sc_link->adapter_softc; struct ecb *ecb; struct ahb_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; - physaddr thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; - int s; - if(scsi_debug & PRINTROUTINES) - printf("ahb_scsi_cmd "); + int seg; /* scatter gather seg being worked on */ + int thiskv; + physaddr thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + int s; + + SC_DEBUG(sc_link, SDEV_DB2, ("ahb_scsi_cmd\n")); /* * get a ecb (mbox-out) to use. If the transfer * is from a buf (possibly from interrupt time) * then we can't allow it to sleep */ flags = xs->flags; - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if(flags & ITSDONE) { - printf("Already done?"); + if (xs->bp) + flags |= SCSI_NOSLEEP; /* just to be sure */ + if (flags & ITSDONE) { + printf("%s: already done?", ahb->sc_dev.dv_xname); xs->flags &= ~ITSDONE; } - if( !(flags & INUSE) ) { - printf("Not in use?"); + if (!(flags & INUSE)) { + printf("%s: not in use?", ahb->sc_dev.dv_xname); xs->flags |= INUSE; } - if (!(ecb = ahb_get_ecb(unit,flags))) { + if (!(ecb = ahb_get_ecb(ahb, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return TRY_AGAIN_LATER; } - -cheat = ecb; - - if(ahb_debug & AHB_SHOWECBS) - printf("",ecb); - if(scsi_debug & SHOWCOMMANDS) - ahb_show_scsi_cmd(xs); - + cheat = ecb; + SC_DEBUG(sc_link, SDEV_DB3, ("start ecb(%x)\n", ecb)); ecb->xs = xs; + /* * If it's a reset, we need to do an 'immediate' - * command, and store it's ccb for later + * command, and store it's ecb for later * if there is already an immediate waiting, * then WE must wait */ - if(flags & SCSI_RESET) { + if (flags & SCSI_RESET) { ecb->flags |= ECB_IMMED; - if(ahb_data[unit].immed_ecb) - return(TRY_AGAIN_LATER); - - ahb_data[unit].immed_ecb = ecb; + if (ahb->immed_ecb) + return TRY_AGAIN_LATER; + ahb->immed_ecb = ecb; if (!(flags & SCSI_NOMASK)) { s = splbio(); - ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); - ahb_add_timeout(ecb,xs->timeout); + ahb_send_immed(ahb, sc_link->target, AHB_TARG_RESET); + timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000); splx(s); - return(SUCCESSFULLY_QUEUED); + return SUCCESSFULLY_QUEUED; } else { - ahb_send_immed(unit,xs->targ,AHB_TARG_RESET); + ahb_send_immed(ahb, sc_link->target, AHB_TARG_RESET); /* - * If we can't use interrupts, poll on completion* + * If we can't use interrupts, poll on completion */ - if(scsi_debug & TRACEINTERRUPTS) - printf("wait "); - if( ahb_poll(unit,xs->timeout)) { - ahb_free_ecb(unit,ecb,flags); + SC_DEBUG(sc_link, SDEV_DB3, ("wait\n")); + if (ahb_poll(ahb, xs->timeout)) { + ahb_free_ecb(ahb, ecb, flags); xs->error = XS_TIMEOUT; - return(HAD_ERROR); + return HAD_ERROR; } - return(COMPLETE); + return COMPLETE; } } /* * Put all the arguments for the xfer in the ecb */ ecb->opcode = ECB_SCSI_OP; - ecb->opt1 = ECB_SES|ECB_DSB|ECB_ARS; - if(xs->datalen) + ecb->opt1 = ECB_SES | ECB_DSB | ECB_ARS; + if (xs->datalen) ecb->opt1 |= ECB_S_G; - ecb->opt2 = xs->lu | ECB_NRB; - ecb->cdblen = xs->cmdlen; - ecb->sense = KVTOPHYS(&(ecb->ecb_sense)); - ecb->senselen = sizeof(ecb->ecb_sense); - ecb->status = KVTOPHYS(&(ecb->ecb_status)); + ecb->opt2 = sc_link->lun | ECB_NRB; + ecb->cdblen = xs->cmdlen; + ecb->sense = KVTOPHYS(&ecb->ecb_sense); + ecb->senselen = sizeof(ecb->ecb_sense); + ecb->status = KVTOPHYS(&ecb->ecb_status); - if(xs->datalen) { - /* should use S/G only if not zero length */ - ecb->data = KVTOPHYS(ecb->ahb_dma); - sg = ecb->ahb_dma ; - seg = 0; - if(flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; + if (xs->datalen) { /* should use S/G only if not zero length */ + ecb->data = KVTOPHYS(ecb->ahb_dma); + sg = ecb->ahb_dma; + seg = 0; + +#ifdef TFS + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while ((datalen) && (seg < AHB_NSEG)) { - sg->addr = (physaddr)iovp->iov_base; + while (datalen && seg < AHB_NSEG) { + sg->addr = (physaddr) iovp->iov_base; xs->datalen += sg->len = iovp->iov_len; - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)", iovp->iov_len, - iovp->iov_base); + SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } else { - /* Set up the scatter gather block */ + } + else +#endif /*TFS */ + { + /* + * Set up the scatter gather block + */ + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + datalen = xs->datalen; + thiskv = (int) xs->data; + thisphys = KVTOPHYS(thiskv); - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ", xs->datalen, xs->data); - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - - while ((datalen) && (seg < AHB_NSEG)) { - bytes_this_seg = 0; + while (datalen && seg < AHB_NSEG) { + bytes_this_seg = 0; /* put in the base address */ sg->addr = thisphys; - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); + SC_DEBUGN(sc_link, SDEV_DB4, + ("0x%x", thisphys)); /* do it at least once */ nextphys = thisphys; while ((datalen) && (thisphys == nextphys)) { - /* - * This page is contiguous (physically) with * - * the the last, just extend the length * - */ - nextphys= (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = min(nextphys - thisphys, - datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; + /* + * This page is contiguous (physically) + * with the the last, just extend the + * length + */ + /* how far to the end of the page */ + nextphys = (thisphys & ~PGOFSET) + NBPG; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page, + datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + thiskv = (thiskv & ~PGOFSET) + NBPG; + if (datalen) thisphys = KVTOPHYS(thiskv); } /* - * next page isn't contiguous, finish the seg * + * next page isn't contiguous, finish the seg */ - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); + SC_DEBUGN(sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); sg->len = bytes_this_seg; sg++; seg++; } } - ecb->datalen = seg * sizeof(struct ahb_dma_seg); - if(scsi_debug & SHOWSCATGATH) - printf("\n"); - if (datalen) { - /* there's still data, must have run out of segs! */ - printf("ahb_scsi_cmd%d: more than %d DMA segs\n", - unit, AHB_NSEG); - xs->error = XS_DRIVER_STUFFUP; - ahb_free_ecb(unit,ecb,flags); - return(HAD_ERROR); - } - } else { - /* No data xfer, use non S/G values */ - ecb->data = (physaddr)0; + /*end of iov/kv decision */ + ecb->datalen = seg * sizeof(struct ahb_dma_seg); + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); + + if (datalen) { + /* + * there's still data, must have run out of segs! + */ + printf("%s: ahb_scsi_cmd, more than %d DMA segs\n", + ahb->sc_dev.dv_xname, AHB_NSEG); + xs->error = XS_DRIVER_STUFFUP; + ahb_free_ecb(ahb, ecb, flags); + return HAD_ERROR; + } + } else { /* No data xfer, use non S/G values */ + ecb->data = (physaddr) 0; ecb->datalen = 0; } + ecb->chain = (physaddr) 0; - ecb->chain = (physaddr)0; /* * Put the scsi command in the ecb and start it */ bcopy(xs->cmd, ecb->cdb, xs->cmdlen); - /* Usually return SUCCESSFULLY QUEUED */ - if( !(flags & SCSI_NOMASK) ) { + /* + * Usually return SUCCESSFULLY QUEUED + */ + if (!(flags & SCSI_NOMASK)) { s = splbio(); - ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); - ahb_add_timeout(ecb,xs->timeout); + ahb_send_mbox(ahb, OP_START_ECB, sc_link->target, ecb); + timeout(ahb_timeout, (caddr_t)ecb, (xs->timeout * hz) / 1000); splx(s); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); + return SUCCESSFULLY_QUEUED; } - /* If we can't use interrupts, poll on completion */ - ahb_send_mbox(unit,OP_START_ECB,xs->targ,ecb); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_wait "); - + /* + * If we can't use interrupts, poll on completion + */ + ahb_send_mbox(ahb, OP_START_ECB, sc_link->target, ecb); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_wait\n")); do { - if(ahb_poll(unit,xs->timeout)) { - if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); - ahb_send_mbox(unit,OP_ABORT_ECB,xs->targ,ecb); - if(ahb_poll(unit, 2000)) { - printf("abort failed in wait\n"); - ahb_free_ecb(unit,ecb,flags); + if (ahb_poll(ahb, xs->timeout)) { + if (!(xs->flags & SCSI_SILENT)) + printf("%s: cmd fail\n", ahb->sc_dev.dv_xname); + ahb_send_mbox(ahb, OP_ABORT_ECB, sc_link->target, ecb); + if (ahb_poll(ahb, 2000)) { + printf("%s: abort failed in wait\n", + ahb->sc_dev.dv_xname); + ahb_free_ecb(ahb, ecb, flags); } xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); + return HAD_ERROR; } - } while (!(xs->flags & ITSDONE)); - - scsi_debug = 0; - ahb_debug = 0; - if(xs->error) + } while (!(xs->flags & ITSDONE));/* something (?) else finished */ + if (xs->error) return HAD_ERROR; return COMPLETE; } -/* - * +----------+ +----------+ +----------+ - * ahb_soonest--->| later |--->| later|--->| later|--->0 - * | [Delta] | | [Delta] | | [Delta] | - * 0<---|sooner |<---|sooner |<---|sooner |<---ahb_latest - * +----------+ +----------+ +----------+ - * - * ahb_furtherest = sum(Delta[1..n]) - */ void -ahb_add_timeout(struct ecb *ecb, int time) +ahb_timeout(arg) + caddr_t arg; { - int timeprev; - struct ecb *prev; - int s = splbio(); + int s = splbio(); + struct ecb *ecb = (void *)arg; + struct ahb_softc *ahb = ecb->xs->sc_link->adapter_softc; - prev = ahb_latest; - if(prev) - timeprev = ahb_furtherest; - else - timeprev = 0; + sc_print_addr(ecb->xs->sc_link); + printf("timed out "); - while(prev && (timeprev > time)) { - timeprev -= prev->delta; - prev = prev->sooner; +#ifdef AHBDEBUG + if (ahb_debug & AHB_SHOWECBS) + ahb_print_active_ecb(ahb); +#endif /*AHBDEBUG */ + + /* + * If it's immediate, don't try abort it + */ + if (ecb->flags & ECB_IMMED) { + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->flags |= ECB_IMMED_FAIL; + ahb_done(ahb, ecb, 1); + splx(s); + return; } - if(prev) { - ecb->delta = time - timeprev; - ecb->later = prev->later; - if(ecb->later) { - ecb->later->sooner = ecb; - ecb->later->delta -= ecb->delta; - } else { - ahb_furtherest = time; - ahb_latest = ecb; - } - ecb->sooner = prev; - prev->later = ecb; - } - else - { - ecb->later = ahb_soonest; - if(ahb_soonest) { - ecb->later->sooner = ecb; - ecb->later->delta -= time; - } else { - ahb_furtherest = time; - ahb_latest = ecb; - } - ecb->delta = time; - ecb->sooner = (struct ecb *)0; - ahb_soonest = ecb; + + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (ecb->flags == ECB_ABORTED) { + printf("AGAIN\n"); + ecb->xs->retries = 0; /* I MEAN IT ! */ + ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST; + ahb_done(ahb, ecb, 1); + } else { /* abort the operation that has timed out */ + printf("\n"); + ahb_send_mbox(ahb, OP_ABORT_ECB, ecb->xs->sc_link->target, ecb); + timeout(ahb_timeout, (caddr_t)ecb, 2 * hz); + ecb->flags = ECB_ABORTED; } splx(s); } +#ifdef AHBDEBUG void -ahb_remove_timeout(struct ecb *ecb) +ahb_print_ecb(ecb) + struct ecb *ecb; { - int s = splbio(); - - if(ecb->sooner) - ecb->sooner->later = ecb->later; - else - ahb_soonest = ecb->later; - - if(ecb->later) { - ecb->later->sooner = ecb->sooner; - ecb->later->delta += ecb->delta; - } else { - ahb_latest = ecb->sooner; - ahb_furtherest -= ecb->delta; - } - ecb->sooner = ecb->later = (struct ecb *)0; - splx(s); + printf("ecb:%x op:%x cmdlen:%d senlen:%d\n", + ecb, ecb->opcode, ecb->cdblen, ecb->senselen); + printf(" datlen:%d hstat:%x tstat:%x flags:%x\n", + ecb->datalen, ecb->ecb_status.ha_status, + ecb->ecb_status.targ_status, ecb->flags); + show_scsi_cmd(ecb->xs); } - -extern int hz; -#define ONETICK 500 /* milliseconds */ -#define SLEEPTIME ((hz * 1000) / ONETICK) - void -ahb_timeout(int arg) +ahb_print_active_ecb(ahb) + struct ahb_softc *ahb; { struct ecb *ecb; - int unit; - int s = splbio(); - - while( ecb = ahb_soonest ) { - if(ecb->delta <= ONETICK) { - /* It has timed out, we need to do some work */ - unit = ecb->xs->adapter; - printf("ahb%d targ %d: device timed out\n", unit, - ecb->xs->targ); - if(ahb_debug & AHB_SHOWECBS) - ahb_print_active_ecb(); - - /* Unlink it from the queue */ - ahb_remove_timeout(ecb); - - /* - * If it's immediate, don't try abort it * - */ - if(ecb->flags & ECB_IMMED) { - ecb->xs->retries = 0; /* I MEAN IT ! */ - ecb->flags |= ECB_IMMED_FAIL; - ahb_done(unit,ecb,FAIL); - continue; - } - - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if(ecb->flags == ECB_ABORTED) { - printf("AGAIN"); - ecb->xs->retries = 0; /* I MEAN IT ! */ - ecb->ecb_status.ha_status = HS_CMD_ABORTED_HOST; - ahb_done(unit,ecb,FAIL); - } else { - printf("\n"); - ahb_send_mbox(unit,OP_ABORT_ECB,ecb->xs->targ,ecb); - /* 2 secs for the abort */ - ahb_add_timeout(ecb,2000 + ONETICK); - ecb->flags = ECB_ABORTED; - } - } else { - ecb->delta -= ONETICK; - ahb_furtherest -= ONETICK; - break; - } - } - splx(s); - timeout((timeout_t)ahb_timeout,(caddr_t)arg,SLEEPTIME); -} - -void -ahb_show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *)xs->cmd; int i = 0; - if( !(xs->flags & SCSI_RESET) ) { - printf("ahb%d targ %d lun %d:", xs->adapter, - xs->targ, xs->lu); - while(i < xs->cmdlen ) { - if(i) - printf(","); - printf("%x", b[i++]); + while (i++ < ECB_HASH_SIZE) { + ecb = ahb->ecbhash[i]; + while (ecb) { + if (ecb->flags != ECB_FREE) + ahb_print_ecb(ecb); + ecb = ecb->nexthash; } - printf("\n"); - } else { - printf("ahb%d targ %d lun%d: RESET\n", xs->adapter, - xs->targ, xs->lu); } } - -void -ahb_print_ecb(struct ecb *ecb) -{ - printf("ecb:%x op:%x cmdlen:%d senlen:%d\n", ecb, ecb->opcode, - ecb->cdblen, ecb->senselen); - printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n", - ecb->datalen, ecb->ecb_status.ha_status, - ecb->ecb_status.targ_status, ecb->delta, ecb->flags); - ahb_show_scsi_cmd(ecb->xs); -} - -void -ahb_print_active_ecb(void) -{ - struct ecb *ecb; - ecb = ahb_soonest; - - while(ecb) { - ahb_print_ecb(ecb); - ecb = ecb->later; - } - printf("Furtherest = %d\n", ahb_furtherest); -} +#endif /* AHBDEBUG */ diff --git a/sys/dev/isa/aha1542.c b/sys/dev/isa/aha1542.c index 41da1a396f65..7a371f9fc22c 100644 --- a/sys/dev/isa/aha1542.c +++ b/sys/dev/isa/aha1542.c @@ -1,5 +1,36 @@ /* - * (Mostly) Written by Julian Elischer (julian@tfs.com) + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: aha1542.c,v 1.24 1994/03/29 04:30:15 mycroft Exp $ + */ + +/* + * Originally written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -11,81 +42,58 @@ * TFS supplies this software to be publicly redistributed * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. - * - * $Id: aha1542.c,v 1.23 1994/03/25 07:40:50 mycroft Exp $ */ /* - * a FEW lines in this driver come from a MACH adaptec-disk driver - * so the copyright below is included: - * - * Copyright 1990 by Open Software Foundation, - * Grenoble, FRANCE - * - * All Rights Reserved - * - * Permission to use, copy, modify, and distribute this software and - * its documentation for any purpose and without fee is hereby granted, - * provided that the above copyright notice appears in all copies and - * that both the copyright notice and this permission notice appear in - * supporting documentation, and that the name of OSF or Open Software - * Foundation not be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. - * - * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, - * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM - * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, - * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION - * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 */ -#include "aha.h" - #include #include #include +#include #include #include +#include +#include #include #include #include -#include -#include -#include -#include #include +#include +#include #include #include -#include - - -#ifdef DDB +#ifdef DDB int Debugger(); -#else DDB +#else /* NDDB */ #define Debugger() panic("should call debugger here (adaptec.c)") -#endif DDB +#endif /* NDDB */ -extern int delaycount; /* from clock setup code */ +/************************** board definitions *******************************/ -/* I/O Port Interface */ -#define AHA_BASE aha_base[unit] +/* + * I/O Port Interface + */ +#define AHA_BASE aha->aha_base #define AHA_CTRL_STAT_PORT (AHA_BASE + 0x0) /* control & status */ #define AHA_CMD_DATA_PORT (AHA_BASE + 0x1) /* cmds and datas */ #define AHA_INTR_PORT (AHA_BASE + 0x2) /* Intr. stat */ -/* AHA_CTRL_STAT bits (write) */ +/* + * AHA_CTRL_STAT bits (write) + */ #define AHA_HRST 0x80 /* Hardware reset */ #define AHA_SRST 0x40 /* Software reset */ #define AHA_IRST 0x20 /* Interrupt reset */ #define AHA_SCRST 0x10 /* SCSI bus reset */ -/* AHA_CTRL_STAT bits (read) */ +/* + * AHA_CTRL_STAT bits (read) + */ #define AHA_STST 0x80 /* Self test in Progress */ #define AHA_DIAGF 0x40 /* Diagnostic Failure */ #define AHA_INIT 0x20 /* Mbx Init required */ @@ -94,7 +102,9 @@ extern int delaycount; /* from clock setup code */ #define AHA_DF 0x04 /* Data in port full */ #define AHA_INVDCMD 0x01 /* Invalid command */ -/* AHA_CMD_DATA bits (write) */ +/* + * AHA_CMD_DATA bits (write) + */ #define AHA_NOP 0x00 /* No operation */ #define AHA_MBX_INIT 0x01 /* Mbx initialization */ #define AHA_START_SCSI 0x02 /* start scsi command */ @@ -114,95 +124,99 @@ extern int delaycount; /* from clock setup code */ #define AHA_WRITE_FIFO 0x1c /* write fifo buffer */ #define AHA_READ_FIFO 0x1d /* read fifo buffer */ #define AHA_ECHO 0x1e /* Echo command data */ +#define AHA_EXT_BIOS 0x28 /* return extended bios info */ +#define AHA_MBX_ENABLE 0x29 /* enable mail box interface */ struct aha_cmd_buf { - u_char byte[16]; + u_char byte[16]; }; -/* AHA_INTR_PORT bits (read) */ +/* + * AHA_INTR_PORT bits (read) + */ #define AHA_ANY_INTR 0x80 /* Any interrupt */ #define AHA_SCRD 0x08 /* SCSI reset detected */ #define AHA_HACC 0x04 /* Command complete */ #define AHA_MBOA 0x02 /* MBX out empty */ #define AHA_MBIF 0x01 /* MBX in full */ -/* Mail box defs */ +/* + * Mail box defs + */ #define AHA_MBX_SIZE 16 /* mail box size */ struct aha_mbx { struct aha_mbx_out { - unsigned char cmd; - unsigned char ccb_addr[3]; + u_char cmd; + u_char ccb_addr[3]; } mbo[AHA_MBX_SIZE]; - struct aha_mbx_in{ - unsigned char stat; - unsigned char ccb_addr[3]; + struct aha_mbx_in { + u_char stat; + u_char ccb_addr[3]; } mbi[AHA_MBX_SIZE]; }; -/* mbo.cmd values */ +/* + * mbo.cmd values + */ #define AHA_MBO_FREE 0x0 /* MBO entry is free */ #define AHA_MBO_START 0x1 /* MBO activate entry */ #define AHA_MBO_ABORT 0x2 /* MBO abort entry */ +/* + * mbi.stat values + */ #define AHA_MBI_FREE 0x0 /* MBI entry is free */ #define AHA_MBI_OK 0x1 /* completed without error */ #define AHA_MBI_ABORT 0x2 /* aborted ccb */ #define AHA_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ #define AHA_MBI_ERROR 0x4 /* Completed with error */ -extern struct aha_mbx aha_mbx[]; - /* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */ -/* Number of scatter gather segments <= 16, allow 64 K i/o (min) */ -#define AHA_NSEG 17 +#define AHA_NSEG 17 /* Number of scatter gather segments <= 16 */ + /* allow 64 K i/o (min) */ struct aha_ccb { - unsigned char opcode; - unsigned char lun:3; - unsigned char data_in:1; /* must be 0 */ - unsigned char data_out:1; /* must be 0 */ - unsigned char target:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; - unsigned char data_length[3]; - unsigned char data_addr[3]; - unsigned char link_addr[3]; - unsigned char link_id; - unsigned char host_stat; - unsigned char target_stat; - unsigned char reserved[2]; - struct scsi_generic scsi_cmd; - struct scsi_sense_data scsi_sense; - struct aha_scat_gath { - unsigned char seg_len[3]; - unsigned char seg_addr[3]; + u_char opcode; + u_char lun:3; + u_char data_in:1; /* must be 0 */ + u_char data_out:1; /* must be 0 */ + u_char target:3; + u_char scsi_cmd_length; + u_char req_sense_length; + u_char data_length[3]; + u_char data_addr[3]; + u_char link_addr[3]; + u_char link_id; + u_char host_stat; + u_char target_stat; + u_char reserved[2]; + struct scsi_generic scsi_cmd; + struct scsi_sense_data scsi_sense; + struct aha_scat_gath { + u_char seg_len[3]; + u_char seg_addr[3]; } scat_gath[AHA_NSEG]; - struct aha_ccb *next; - struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ - struct aha_mbx_out *mbx; /* pointer to mail box */ - long int delta; /* difference from previous*/ - struct aha_ccb *later,*sooner; - int flags; + struct aha_ccb *next; + struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ + struct aha_mbx_out *mbx; /* pointer to mail box */ + int flags; +#define CCB_FREE 0 +#define CCB_ACTIVE 1 +#define CCB_ABORTED 2 }; -/* flags value? */ -#define CCB_FREE 0 -#define CCB_ACTIVE 1 -#define CCB_ABORTED 2 - -struct aha_ccb *aha_soonest = (struct aha_ccb *)0; -struct aha_ccb *aha_latest = (struct aha_ccb *)0; -long int aha_furtherest = 0; /* longest time in the timeout queue */ - -/* opcode fields */ +/* + * opcode fields + */ #define AHA_INITIATOR_CCB 0x00 /* SCSI Initiator CCB */ #define AHA_TARGET_CCB 0x01 /* SCSI Target CCB */ -#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scattter gather*/ +#define AHA_INIT_SCAT_GATH_CCB 0x02 /* SCSI Initiator with scatter gather */ #define AHA_RESET_CCB 0x81 /* SCSI Bus reset */ - -/* aha_ccb.host_stat values */ +/* + * aha_ccb.host_stat values + */ #define AHA_OK 0x00 /* cmd ok */ #define AHA_LINK_OK 0x0a /* Link cmd ok */ #define AHA_LINK_IT 0x0b /* Link cmd ok + int */ @@ -216,30 +230,52 @@ long int aha_furtherest = 0; /* longest time in the timeout queue */ #define AHA_INV_TARGET 0x18 /* Invalid target direction */ #define AHA_CCB_DUP 0x19 /* Duplicate CCB received */ #define AHA_INV_CCB 0x1a /* Invalid CCB or segment list */ -#define AHA_ABORTED 42 +#define AHA_ABORTED 42 struct aha_setup { - u_char sync_neg:1; - u_char parity:1; - u_char :6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[3]; + u_char sync_neg:1; + u_char parity:1; + u_char:6; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[3]; struct { - u_char offset:4; - u_char period:3; - u_char valid:1; + u_char offset:4; + u_char period:3; + u_char valid:1; } sync[8]; - u_char disc_sts; + u_char disc_sts; }; -struct aha_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char :5; +struct aha_config { + u_char chan; + u_char intr; + u_char scsi_dev:3; + u_char:5; +}; + +struct aha_inquire { + u_char boardid; /* type of board */ + /* 0x20 = BusLogic 545, but it gets + the command wrong, only returns + one byte */ + /* 0x31 = AHA-1540 */ + /* 0x41 = AHA-1540A/1542A/1542B */ + /* 0x42 = AHA-1640 */ + /* 0x43 = AHA-1542C */ + /* 0x44 = AHA-1542CF */ + /* 0x45 = AHA-1542CF, BIOS v2.01 */ + u_char spec_opts; /* special options ID */ + /* 0x41 = Board is standard model */ + u_char revision_1; /* firmware revision [0-9A-Z] */ + u_char revision_2; /* firmware revision [0-9A-Z] */ +}; + +struct aha_extbios { + u_char flags; /* Bit 3 == 1 extended bios enabled */ + u_char mailboxlock; /* mail box lock code to unlock it */ }; #define INT9 0x01 @@ -254,30 +290,80 @@ struct aha_config { #define CHAN6 0x40 #define CHAN7 0x80 +/*********************************** end of board definitions***************/ - -#define PHYSTOKV(x) ((x) + KERNBASE) +#define PHYSTOKV(x) (((long int)(x)) ^ aha->kv_phys_xor) #define KVTOPHYS(x) vtophys(x) -#define AHA_DMA_PAGES AHA_NSEG -#define PAGESIZ 4096 -#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } +u_char aha_scratch_buf[256]; +#ifdef AHADEBUG +int aha_debug = 1; +#endif /*AHADEBUG */ -struct scsi_xfer aha_scsi_xfer[NAHA]; -struct isa_device *ahainfo[NAHA]; -struct aha_mbx aha_mbx[NAHA]; -struct aha_ccb *aha_ccb_free[NAHA]; -struct aha_ccb aha_ccb[NAHA][AHA_MBX_SIZE]; -struct aha_ccb *aha_get_ccb(); -u_char aha_scratch_buf[256]; -short aha_base[NAHA]; /* base port for each board */ -int speed[NAHA]; -int aha_int[NAHA]; -int aha_dma[NAHA]; -int aha_initialized[NAHA]; +struct aha_softc { + struct device sc_dev; + struct isadev sc_id; + struct intrhand sc_ih; -int aha_debug = 0; -static int ahaunit = 0; + u_short aha_base; /* base port for each board */ + /* + * xor this with a physaddr to get a kv addr and visa versa + * for items in THIS STRUCT only. + * Used to get the CCD's physical and kv addresses from each + * other. + */ + long int kv_phys_xor; + struct aha_mbx aha_mbx; /* all the mailboxes */ + struct aha_ccb *aha_ccb_free; /* the next free ccb */ + struct aha_ccb aha_ccb[AHA_MBX_SIZE]; /* all the CCBs */ + int aha_int; /* our irq level */ + int aha_dma; /* out DMA req channel */ + int aha_scsi_dev; /* ourscsi bus address */ + struct scsi_link sc_link; /* prototype for subdevs */ +}; + +int aha_cmd(); /* XXX must be varargs to prototype */ +u_int aha_adapter_info __P((struct aha_softc *)); +int ahaintr __P((int)); +void aha_free_ccb __P((struct aha_softc *, struct aha_ccb *, int)); +struct aha_ccb *aha_get_ccb __P((struct aha_softc *, int)); +void aha_done __P((struct aha_softc *, struct aha_ccb *)); +int aha_find __P((struct aha_softc *)); +void aha_init __P((struct aha_softc *)); +void ahaminphys __P((struct buf *)); +int aha_scsi_cmd __P((struct scsi_xfer *)); +int aha_poll __P((struct aha_softc *, struct scsi_xfer *, struct aha_ccb *)); +int aha_set_bus_speed __P((struct aha_softc *)); +int aha_bus_speed_check __P((struct aha_softc *, int)); +void aha_timeout __P((caddr_t)); + +struct scsi_adapter aha_switch = { + aha_scsi_cmd, + ahaminphys, + 0, + 0, + aha_adapter_info, + "aha" +}; + +/* the below structure is so we have a default dev struct for out link struct */ +struct scsi_device aha_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "aha", + 0 +}; + +int ahaprobe(); +void ahaattach(); + +struct cfdriver ahacd = { + NULL, "aha", ahaprobe, ahaattach, DV_DULL, sizeof(struct aha_softc) +}; + +void aha_init __P((struct aha_softc *)); #define aha_abortmbx(mbx) \ (mbx)->cmd = AHA_MBO_ABORT; \ @@ -286,154 +372,132 @@ static int ahaunit = 0; (mbx)->cmd = AHA_MBO_START; \ outb(AHA_CMD_DATA_PORT, AHA_START_SCSI); -#define AHA_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */ -#define AHA_RESET_TIMEOUT 1000000 /* time to wait for reset */ -#define AHA_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */ - - -int aha_cmd(int, int, int, int, u_char *, ...); -int ahaprobe(struct isa_device *); -int ahaattach(struct isa_device *); -long int aha_adapter_info(int); -int ahaintr(int); -void aha_free_ccb(int, struct aha_ccb *, int); -struct aha_ccb * aha_get_ccb(int, int); -int aha_done(int, struct aha_ccb *); -int aha_init(int); -void ahaminphys(struct buf *); -int aha_scsi_cmd(struct scsi_xfer *); -int aha_set_bus_speed(int); -int aha_bus_speed_check(int, int); -void aha_add_timeout(struct aha_ccb *, int); -void aha_remove_timeout(struct aha_ccb *); -void aha_timeout(int); - - -struct isa_driver ahadriver = { - ahaprobe, - ahaattach, - "aha" -}; - -struct scsi_switch aha_switch[NAHA]; +#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */ /* - * aha_cmd(unit, icnt, ocnt,wait, retval, ...) + * aha_cmd(aha,icnt, ocnt,wait, retval, opcode, args) * Activate Adapter command - * icnt: number of args (outbound bytes written after opcode) - * ocnt: number of expected returned bytes - * wait: number of seconds to wait for response - * retval: buffer where to place returned bytes - * ...: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI & parameters + * icnt: number of args (outbound bytes written after opcode) + * ocnt: number of expected returned bytes + * wait: number of seconds to wait for response + * retval: buffer where to place returned bytes + * opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ... + * args: parameters * * Performs an adapter command through the ports. Not to be confused - * with a scsi command, which is read in via the dma - * One of the adapter commands tells it to read in a scsi command + * with a scsi command, which is read in via the dma. One of the adapter + * commands tells it to read in a scsi command but that one is done + * separately. This is only called during set-up. */ int -aha_cmd(int unit, int icnt, int ocnt, int wait, u_char *retval, ...) +aha_cmd(aha, icnt, ocnt, wait, retval, opcode, args) + struct aha_softc *aha; + int icnt, ocnt, wait; + u_char *retval; + unsigned opcode; + u_char args; { - va_list ap; - int opc, sts; + unsigned *ic = &opcode; u_char oc; register i; - - va_start(ap, retval); - opc = (u_char)va_arg(ap, int); - /*printf("command: %08x %02x\n", opc, (u_char)opc);*/ + int sts; /* * multiply the wait argument by a big constant - * zero defaults to 1 + * zero defaults to 1 sec.. + * all wait loops are in 50uSec cycles */ - if(!wait) - wait = AHA_CMD_TIMEOUT_FUDGE * delaycount; + if (wait) + wait *= 20000; else - wait *= AHA_CMD_TIMEOUT_FUDGE * delaycount; + wait = 20000; /* * Wait for the adapter to go idle, unless it's one of * the commands which don't need this */ - if (opc != AHA_MBX_INIT && opc != AHA_START_SCSI) { - i = AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/ + if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI) { + i = 20000; /*do this for upto about a second */ while (--i) { sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_IDLE) + if (sts & AHA_IDLE) { break; + } + delay(50); } if (!i) { - printf("aha_cmd: aha1542 host not idle(0x%x)\n", sts); - return(ENXIO); + printf("%s: aha_cmd, host not idle(0x%x)\n", + aha->sc_dev.dv_xname, sts); + return ENXIO; } } /* - * Now that it is idle, if we expect output, preflush the* + * Now that it is idle, if we expect output, preflush the * queue feeding to us. */ if (ocnt) { - while((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) + while ((inb(AHA_CTRL_STAT_PORT)) & AHA_DF) inb(AHA_CMD_DATA_PORT); } - /* * Output the command and the number of arguments given * for each byte, first check the port is empty. */ - icnt++; /* include the command */ + icnt++; + /* include the command */ while (icnt--) { sts = inb(AHA_CTRL_STAT_PORT); - for (i=0; i< wait; i++) { + for (i = wait; i; i--) { sts = inb(AHA_CTRL_STAT_PORT); if (!(sts & AHA_CDF)) break; + delay(50); } - if (i >= wait) { - printf("aha_cmd: aha1542 cmd/data port full\n"); - outb(AHA_CTRL_STAT_PORT, AHA_SRST); - return(ENXIO); - } - outb(AHA_CMD_DATA_PORT, (u_char)opc); - if(icnt) { - opc = (u_char)va_arg(ap, int); - /*printf("extra: %08x %02x\n", opc, (u_char)opc);*/ + if (!i) { + printf("%s: aha_cmd, cmd/data port full\n", + aha->sc_dev.dv_xname); + outb(AHA_CTRL_STAT_PORT, AHA_SRST); + return ENXIO; } + outb(AHA_CMD_DATA_PORT, (u_char) (*ic++)); } - va_end(ap); - /* * If we expect input, loop that many times, each time, * looking for the data register to have valid data */ while (ocnt--) { sts = inb(AHA_CTRL_STAT_PORT); - for (i=0; i< wait; i++) { + for (i = wait; i; i--) { sts = inb(AHA_CTRL_STAT_PORT); - if (sts & AHA_DF) + if (sts & AHA_DF) break; + delay(50); } - if (i >= wait) { - printf("aha_cmd: aha1542 cmd/data port empty %d\n",ocnt); - return(ENXIO); + if (!i) { + printf("%s: aha_cmd, cmd/data port empty %d\n", + aha->sc_dev.dv_xname, ocnt); + return ENXIO; } oc = inb(AHA_CMD_DATA_PORT); if (retval) - *retval++ = oc; + *retval++ = oc; } /* * Wait for the board to report a finised instruction */ - i=AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ + i = 20000; while (--i) { sts = inb(AHA_INTR_PORT); if (sts & AHA_HACC) break; + delay(50); } if (!i) { - printf("aha_cmd: aha1542 host not finished(0x%x)\n",sts); - return(ENXIO); + printf("%s: aha_cmd, host not finished(0x%x)\n", + aha->sc_dev.dv_xname, sts); + return ENXIO; } outb(AHA_CTRL_STAT_PORT, AHA_IRST); - return(0); + return 0; } /* @@ -443,165 +507,208 @@ aha_cmd(int unit, int icnt, int ocnt, int wait, u_char *retval, ...) * autoconf.c */ int -ahaprobe(struct isa_device *dev) +ahaprobe(parent, self, aux) + struct device *parent, *self; + void *aux; { - int unit; + struct aha_softc *aha = (void *)self; + struct isa_attach_args *ia = aux; - if (dev->id_parent) - return 1; +#ifdef NEWCONFIG + if (ia->ia_iobase == IOBASEUNK) + return 0; +#endif - dev->id_unit = unit = ahaunit; - aha_base[unit] = dev->id_iobase; - if(unit >= NAHA) { - printf("aha: unit number (%d) too high\n",unit); - return(0); - } + aha->aha_base = ia->ia_iobase; /* * Try initialise a unit at this location - * sets up dma and bus speed, loads aha_int[unit] + * sets up dma and bus speed, loads aha->aha_int */ - if (aha_init(unit) != 0) - return(0); + if (aha_find(aha) != 0) + return 0; /* - * If it's there, put in it's interrupt vectors + * Calculate the xor product of the aha struct's + * physical and virtual address. This allows us + * to change addresses within the structure + * from physical to virtual easily, as long as + * the structure is less than 1 page in size. + * This is used to recognise CCBs which are in + * this struct and which are refered to by the + * hardware using physical addresses. + * (assumes malloc returns a chunk that doesn't + * span pages) + * eventually use the hash table in aha1742.c */ - dev->id_irq = (1 << aha_int[unit]); - dev->id_drq = aha_dma[unit]; - ahaunit++; - return(8); + aha->kv_phys_xor = (long int) aha ^ (KVTOPHYS(aha)); + +#ifdef NEWCONFIG + /* + * If it's there, put in it's interrupt vectors and dma channel + */ + if (ia->ia_irq == IRQUNK) { + ia->ia_irq = (1 << aha->aha_int); + } else { + if (ia->ia_irq != (1 << aha->aha_int)) { + printf("aha%d: irq mismatch, %x != %x\n", + aha->sc_dev.dv_unit, ia->ia_irq, + 1 << aha->aha_int); + return 0; + } + } + + if (ia->ia_drq == DRQUNK) { + ia->ia_drq = aha->aha_dma; + } else { + if (ia->ia_drq != aha->aha_dma) { + printf("aha%d: drq mismatch, %x != %x\n", + aha->sc_dev.dv_unit, ia->ia_drq, aha->aha_dma); + return 0; + } + } +#endif + + ia->ia_msize = 0; + ia->ia_iosize = 4; + return 1; +} + +ahaprint() +{ + } /* * Attach all the sub-devices we can find */ -int -ahaattach(struct isa_device *dev) +void +ahaattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - static int firsttime; - static int firstswitch[NAHA]; - static u_long speedprint; /* max 32 aha controllers */ - int masunit; - int r; + struct isa_attach_args *ia = aux; + struct aha_softc *aha = (void *)self; - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; + aha_init(aha); - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - aha_switch[masunit].name = "aha"; - aha_switch[masunit].scsi_cmd = aha_scsi_cmd; - aha_switch[masunit].scsi_minphys = ahaminphys; - aha_switch[masunit].open_target_lu = 0; - aha_switch[masunit].close_target_lu = 0; - aha_switch[masunit].adapter_info = aha_adapter_info; - for (r = 0; r < 8; r++) { - aha_switch[masunit].empty[r] = 0; - aha_switch[masunit].used[r] = 0; - aha_switch[masunit].printed[r] = 0; - } - } - if(!(speedprint & (1<sc_link.adapter_softc = aha; + aha->sc_link.adapter_targ = aha->aha_scsi_dev; + aha->sc_link.adapter = &aha_switch; + aha->sc_link.device = &aha_dev; - r = scsi_attach(masunit, &aha_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); + printf("\n"); - /* only one for all boards */ - if(firsttime==0) { - firsttime = 1; - aha_timeout(0); - } - return r; +#ifdef NEWCONFIG + isa_establish(&aha->sc_id, &aha->sc_dev); + aha->sc_ih.ih_fun = ahaintr; + aha->sc_ih.ih_arg = aha; + /* XXX and DV_TAPE, but either gives us splbio */ + intr_establish(ia->ia_irq, &aha->sc_ih, DV_DISK); +#endif + + /* + * ask the adapter what subunits are present + */ + config_found(self, &aha->sc_link, ahaprint); } - /* - * Return some information to the caller about - * the adapter and it's capabilities + * Return some information to the caller about the adapter and its + * capabilities. */ -long int -aha_adapter_info(int unit) +u_int +aha_adapter_info(aha) + struct aha_softc *aha; { - return(2); /* 2 outstanding requests at a time per device */ + + return 2; /* 2 outstanding requests at a time per device */ } /* * Catch an interrupt from the adaptor */ int -ahaintr(int unit) +ahaintr(unit) + int unit; { + struct aha_softc *aha = ahacd.cd_devs[unit]; struct aha_ccb *ccb; - unsigned char stat; + u_char stat; register i; - if(scsi_debug & PRINTROUTINES) - printf("ahaintr "); +#ifdef AHADEBUG + printf("ahaintr "); +#endif /*AHADEBUG */ /* - * First acknowlege the interrupt, Then if it's - * not telling about a completed operation - * just return. + * First acknowlege the interrupt, Then if it's not telling about + * a completed operation just return. */ stat = inb(AHA_INTR_PORT); outb(AHA_CTRL_STAT_PORT, AHA_IRST); - if(scsi_debug & TRACEINTERRUPTS) - printf("int "); - if (! (stat & AHA_MBIF)) - return(1); - if(scsi_debug & TRACEINTERRUPTS) - printf("b "); - + if (!(stat & AHA_MBIF)) + return 1; +#ifdef AHADEBUG + printf("mbxin "); +#endif /*AHADEBUG */ /* * If it IS then process the competed operation */ for (i = 0; i < AHA_MBX_SIZE; i++) { - if (aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE) { - ccb = (struct aha_ccb *)PHYSTOKV( - (_3btol(aha_mbx[unit].mbi[i].ccb_addr))); - if((stat = aha_mbx[unit].mbi[i].stat) != AHA_MBI_OK) { - switch(stat) { + if (aha->aha_mbx.mbi[i].stat != AHA_MBI_FREE) { + ccb = (struct aha_ccb *) PHYSTOKV( + (_3btol(aha->aha_mbx.mbi[i].ccb_addr))); + + if ((stat = aha->aha_mbx.mbi[i].stat) != AHA_MBI_OK) { + switch (stat) { case AHA_MBI_ABORT: - if(aha_debug) - printf("abort"); +#ifdef AHADEBUG + if (aha_debug) + printf("abort"); +#endif /*AHADEBUG */ ccb->host_stat = AHA_ABORTED; break; + case AHA_MBI_UNKNOWN: - ccb = (struct aha_ccb *)0; - if(aha_debug) - printf("unknown ccb for abort "); + ccb = (struct aha_ccb *) 0; +#ifdef AHADEBUG + if (aha_debug) + printf("unknown ccb for abort "); +#endif /*AHADEBUG */ /* may have missed it */ /* no such ccb known for abort */ - break; + case AHA_MBI_ERROR: break; + default: panic("Impossible mbxi status"); + } - if( aha_debug && ccb ) { - u_char *cp; - cp = (u_char *)(&(ccb->scsi_cmd)); - printf("op=%x %x %x %x %x %x\n", +#ifdef AHADEBUG + if (aha_debug && ccb) { + u_char *cp; + cp = (u_char *) (&(ccb->scsi_cmd)); + printf("op=%x %x %x %x %x %x\n", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); - printf("stat %x for mbi[%d]\n" - , aha_mbx[unit].mbi[i].stat, i); + printf("stat %x for mbi[%d]\n", + aha->aha_mbx.mbi[i].stat, i); printf("addr = 0x%x\n", ccb); } +#endif /*AHADEBUG */ } - if(ccb) { - aha_remove_timeout(ccb); - aha_done(unit,ccb); + if (ccb) { + untimeout(aha_timeout, (caddr_t)ccb); + aha_done(aha, ccb); } - aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE; + aha->aha_mbx.mbi[i].stat = AHA_MBI_FREE; } } - return(1); + return 1; } /* @@ -609,29 +716,27 @@ ahaintr(int unit) * free list. */ void -aha_free_ccb(int unit, struct aha_ccb *ccb, int flags) +aha_free_ccb(aha, ccb, flags) + struct aha_softc *aha; + struct aha_ccb *ccb; + int flags; { - unsigned int opri; + int opri; - if(scsi_debug & PRINTROUTINES) - printf("ccb%d(0x%x)> ",unit,flags); - if (!(flags & SCSI_NOMASK)) - opri = splbio(); + if (!(flags & SCSI_NOMASK)) + opri = splbio(); - ccb->next = aha_ccb_free[unit]; - aha_ccb_free[unit] = ccb; + ccb->next = aha->aha_ccb_free; + aha->aha_ccb_free = ccb; ccb->flags = CCB_FREE; - if(ccb->sooner || ccb->later) { - printf("yikes, still in timeout queue\n"); - aha_remove_timeout(ccb); - } /* - * If there were none, wake abybody waiting for - * one to come free, starting with queued entries* + * If there were none, wake anybody waiting for one to come free, + * starting with queued entries. */ if (!ccb->next) - wakeup( (caddr_t)&aha_ccb_free[unit]); - if (!(flags & SCSI_NOMASK)) + wakeup((caddr_t)&aha->aha_ccb_free); + + if (!(flags & SCSI_NOMASK)) splx(opri); } @@ -639,344 +744,387 @@ aha_free_ccb(int unit, struct aha_ccb *ccb, int flags) * Get a free ccb (and hence mbox-out entry) */ struct aha_ccb * -aha_get_ccb(int unit, int flags) +aha_get_ccb(aha, flags) + struct aha_softc *aha; + int flags; { - unsigned opri; + int opri; struct aha_ccb *rc; - if(scsi_debug & PRINTROUTINES) - printf("aha_ccb_free)) && (!(flags & SCSI_NOSLEEP))) + tsleep((caddr_t)&aha->aha_ccb_free, PRIBIO, "ahaccb", 0); if (rc) { - aha_ccb_free[unit] = aha_ccb_free[unit]->next; + aha->aha_ccb_free = aha->aha_ccb_free->next; rc->flags = CCB_ACTIVE; } - if (!(flags & SCSI_NOMASK)) + if (!(flags & SCSI_NOMASK)) splx(opri); - return(rc); + return rc; } - /* * We have a ccb which has been processed by the * adaptor, now we look to see how the operation * went. Wake up the owner if waiting */ -int -aha_done(int unit, struct aha_ccb *ccb) +void +aha_done(aha, ccb) + struct aha_softc *aha; + struct aha_ccb *ccb; { - struct scsi_sense_data *s1,*s2; - struct scsi_xfer *xs = ccb->xfer; + struct scsi_sense_data *s1, *s2; + struct scsi_xfer *xs = ccb->xfer; - if(scsi_debug & PRINTROUTINES ) - printf("aha_done "); + SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n")); /* * Otherwise, put the results of the operation * into the xfer and call whoever started it */ - if(!(xs->flags & INUSE)) { - printf("exiting but not in use! "); + if (!(xs->flags & INUSE)) { + printf("%s: exiting but not in use!\n", aha->sc_dev.dv_xname); Debugger(); } if ((ccb->host_stat != AHA_OK || ccb->target_stat != SCSI_OK) && (!(xs->flags & SCSI_ERR_OK))) { - s1 = (struct scsi_sense_data *)(((char *)(&ccb->scsi_cmd)) - + ccb->scsi_cmd_length); + /* + * We have an error, that we cannot ignore. + */ + s1 = (struct scsi_sense_data *) (((char *) (&ccb->scsi_cmd)) + + ccb->scsi_cmd_length); s2 = &(xs->sense); - if(ccb->host_stat) { - switch(ccb->host_stat) { + if (ccb->host_stat) { + SC_DEBUG(xs->sc_link, SDEV_DB3, ("host err 0x%x\n", + ccb->host_stat)); + switch (ccb->host_stat) { case AHA_ABORTED: case AHA_SEL_TIMEOUT: /* No response */ xs->error = XS_TIMEOUT; break; default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; - if (aha_debug > 1) - printf("host_stat%x\n", ccb->host_stat); + printf("%s: host_stat %x\n", + aha->sc_dev.dv_xname, ccb->host_stat); } - } else { - switch(ccb->target_stat) { + SC_DEBUG(xs->sc_link, SDEV_DB3, ("target err 0x%x\n", + ccb->target_stat)); + switch (ccb->target_stat) { case 0x02: - /* structure copy!!!!!*/ - *s2=*s1; + /* structure copy!!!!! */ + *s2 = *s1; xs->error = XS_SENSE; break; case 0x08: xs->error = XS_BUSY; break; default: - if (aha_debug > 1) - printf("target_stat%x\n", ccb->target_stat); + printf("%s: target_stat %x\n", + aha->sc_dev.dv_xname, ccb->target_stat); xs->error = XS_DRIVER_STUFFUP; } } - } else + } else { + /* All went correctly OR errors expected */ xs->resid = 0; - + } xs->flags |= ITSDONE; - aha_free_ccb(unit,ccb, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + aha_free_ccb(aha, ccb, xs->flags); + scsi_done(xs); } - /* - * Start the board, ready for normal operation + * Find the board and find its irq/drq */ int -aha_init(int unit) +aha_find(aha) + struct aha_softc *aha; { + u_char ad[3]; + volatile int i, sts; struct aha_config conf; - unsigned char ad[3]; - volatile int i,sts; + struct aha_inquire inquire; + struct aha_extbios extbios; /* - * reset board, If it doesn't respond, assume + * reset board, If it doesn't respond, assume * that it's not there.. good for the probe */ - outb(AHA_CTRL_STAT_PORT, AHA_HRST|AHA_SRST); + outb(AHA_CTRL_STAT_PORT, AHA_HRST | AHA_SRST); - for (i=0; i < AHA_RESET_TIMEOUT; i++) { - sts = inb(AHA_CTRL_STAT_PORT) ; - if(sts == (AHA_IDLE | AHA_INIT)) + for (i = AHA_RESET_TIMEOUT; i; i--) { + sts = inb(AHA_CTRL_STAT_PORT); + if (sts == (AHA_IDLE | AHA_INIT)) break; + delay(1000); /* calibrated in msec */ } - - if (i >= AHA_RESET_TIMEOUT) { + if (!i) { +#ifdef AHADEBUG if (aha_debug) - printf("aha_init: No answer from adaptec board\n"); - return(ENXIO); + printf("aha_find: No answer from adaptec board\n"); +#endif /*AHADEBUG */ + return ENXIO; } /* - * Assume we have a board at this stage - * setup dma channel from jumpers and save int level + * Assume we have a board at this stage, do an adapter inquire + * to find out what type of controller it is */ - delay(1000); - aha_cmd(unit, 0, sizeof(conf), 0, (u_char *)&conf, AHA_CONF_GET); - switch(conf.chan) { + aha_cmd(aha, 0, sizeof(inquire), 1 ,&inquire, AHA_INQUIRE); +#ifdef AHADEBUG + printf("%s: inquire %x, %x, %x, %x\n", + aha->sc_dev.dv_xname, + inquire.boardid, inquire.spec_opts, + inquire.revision_1, inquire.revision_2); +#endif /* AHADEBUG */ + /* + * XXX The Buslogic 545S gets the AHA_INQUIRE command wrong, + * they only return one byte which causes us to print an error, + * so if the boardid comes back as 0x20, tell the user why they + * get the "cmd/data port empty" message + */ + if (inquire.boardid == 0x20) { + /* looks like a Buslogic 545 */ + printf("%s: above cmd/data port empty due to Buslogic 545\n", + aha->sc_dev.dv_xname); + } + /* + * If we are a 1542C or 1542CF disable the extended bios so that the + * mailbox interface is unlocked. + * No need to check the extended bios flags as some of the + * extensions that cause us problems are not flagged in that byte. + */ + if (inquire.boardid == 0x43 || inquire.boardid == 0x44 || + inquire.boardid == 0x45) { + aha_cmd(aha, 0, sizeof(extbios), 0, &extbios, AHA_EXT_BIOS); +#ifdef AHADEBUG + printf("%s: extended bios flags %x\n", aha->sc_dev.dv_xname, + extbios.flags); +#endif /* AHADEBUG */ + printf("%s: 1542C/CF detected, unlocking mailbox\n", + aha->sc_dev.dv_xname); + aha_cmd(aha, 2, 0, 0, 0, AHA_MBX_ENABLE, + 0, extbios.mailboxlock); + } + + /* + * setup dma channel from jumpers and save int + * level + */ + delay(1000); /* for Bustek 545 */ + aha_cmd(aha, 0, sizeof(conf), 0, &conf, AHA_CONF_GET); + switch (conf.chan) { case CHAN0: outb(0x0b, 0x0c); outb(0x0a, 0x00); - aha_dma[unit] = 0; + aha->aha_dma = 0; break; case CHAN5: outb(0xd6, 0xc1); outb(0xd4, 0x01); - aha_dma[unit] = 5; + aha->aha_dma = 5; break; case CHAN6: outb(0xd6, 0xc2); outb(0xd4, 0x02); - aha_dma[unit] = 6; + aha->aha_dma = 6; break; case CHAN7: outb(0xd6, 0xc3); outb(0xd4, 0x03); - aha_dma[unit] = 7; + aha->aha_dma = 7; break; default: - printf("illegal dma jumper setting\n"); - return(EIO); + printf("illegal dma setting %x\n", conf.chan); + return EIO; } - switch(conf.intr) { + switch (conf.intr) { case INT9: - aha_int[unit] = 9; + aha->aha_int = 9; break; case INT10: - aha_int[unit] = 10; + aha->aha_int = 10; break; case INT11: - aha_int[unit] = 11; + aha->aha_int = 11; break; case INT12: - aha_int[unit] = 12; + aha->aha_int = 12; break; case INT14: - aha_int[unit] = 14; + aha->aha_int = 14; break; case INT15: - aha_int[unit] = 15; + aha->aha_int = 15; break; default: - printf("illegal int jumper setting\n"); - return(EIO); + printf("illegal int setting %x\n", conf.intr); + return EIO; } - /* who are we on the scsi bus */ - aha_switch[unit].scsi_dev = conf.scsi_dev; + /* who are we on the scsi bus? */ + aha->aha_scsi_dev = conf.scsi_dev; + /* + * Change the bus on/off times to not clash with other dma users. + */ + aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7); + aha_cmd(aha, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4); + +#ifdef TUNE_1542 /* * Initialize memory transfer speed + * Not compiled in by default because it breaks some machines */ - speed[unit] = aha_set_bus_speed(unit); - if(speed[unit] == 0) { - printf("aha%d found, but unable to talk to it correctly\n"); - return(EIO); - } + if (!(aha_set_bus_speed(aha))) + return EIO; +#endif /*TUNE_1542*/ + + return 0; +} + +/* + * Start the board, ready for normal operation + */ +void +aha_init(aha) + struct aha_softc *aha; +{ + u_char ad[4]; + volatile int i; /* - * Initialize bus-on time - * - * The default is 11ms, which can result in the fd driver becoming - * starved for data during simultaneous fd & scsi transfers. We - * set it to 9ms - if this still gives you trouble, set to 6 (ms) - * and work your way up. + * Initialize mail box */ - aha_cmd(unit,1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 9); - - /* - * Initialize mail box - */ - lto3b(KVTOPHYS(&aha_mbx[unit]), ad); - - aha_cmd(unit, 4, 0, 0, (u_char *)0, AHA_MBX_INIT, AHA_MBX_SIZE, - ad[0], ad[1], ad[2]); + lto3b(KVTOPHYS(&aha->aha_mbx), ad); + aha_cmd(aha, 4, 0, 0, 0, AHA_MBX_INIT, + AHA_MBX_SIZE, ad[0], ad[1], ad[2]); /* * link the ccb's with the mbox-out entries and * into a free-list + * this is a kludge but it works */ - for (i=0; i < AHA_MBX_SIZE; i++) { - aha_ccb[unit][i].next = aha_ccb_free[unit]; - aha_ccb_free[unit] = &aha_ccb[unit][i]; - aha_ccb_free[unit]->flags = CCB_FREE; - aha_ccb_free[unit]->mbx = &aha_mbx[unit].mbo[i]; - lto3b(KVTOPHYS(aha_ccb_free[unit]), aha_mbx[unit].mbo[i].ccb_addr); + for (i = 0; i < AHA_MBX_SIZE; i++) { + aha->aha_ccb[i].next = aha->aha_ccb_free; + aha->aha_ccb_free = &aha->aha_ccb[i]; + aha->aha_ccb_free->flags = CCB_FREE; + aha->aha_ccb_free->mbx = &aha->aha_mbx.mbo[i]; + lto3b(KVTOPHYS(aha->aha_ccb_free), aha->aha_mbx.mbo[i].ccb_addr); } +} - /* - * Note that we are going and return (to probe) - */ - aha_initialized[unit]++; - return(0); +void +ahaminphys(bp) + struct buf *bp; +{ + +/* aha seems to explode with 17 segs (64k may require 17 segs) */ +/* on old boards so use a max of 16 segs if you have problems here */ + if (bp->b_bcount > ((AHA_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((AHA_NSEG - 1) << PGSHIFT); } /* - * aha seems to explode with 17 segs (64k may require 17 segs) - * on old boards so use a max of 16 segs if you have problems - * here + * start a scsi operation given the command and the data address. Also needs + * the unit, target and lu. */ -void -ahaminphys(struct buf *bp) +int +aha_scsi_cmd(xs) + struct scsi_xfer *xs; { - if(bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ)) - bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ); -} - -/* - * start a scsi operation given the command and - * the data address. Also needs the unit, target - * and lu - */ -int -aha_scsi_cmd(struct scsi_xfer *xs) -{ - struct scsi_sense_data *s1,*s2; + struct scsi_link *sc_link = xs->sc_link; + struct aha_softc *aha = sc_link->adapter_softc; struct aha_ccb *ccb; struct aha_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; - int thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; - int s; + int seg; /* scatter gather seg being worked on */ + int thiskv; + int thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + struct iovec *iovp; + int s; - if(scsi_debug & PRINTROUTINES) - printf("aha_scsi_cmd "); + SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n")); /* * get a ccb (mbox-out) to use. If the transfer * is from a buf (possibly from interrupt time) * then we can't allow it to sleep */ flags = xs->flags; - if(!(flags & INUSE)) { - printf("not in use!"); - Debugger(); - xs->flags |= INUSE; - } - if(flags & ITSDONE) { - printf("Already done! check device retry code "); - Debugger(); - xs->flags &= ~ITSDONE; - } - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if (!(ccb = aha_get_ccb(unit,flags))) { + if (!(ccb = aha_get_ccb(aha, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); + return TRY_AGAIN_LATER; } - if (ccb->mbx->cmd != AHA_MBO_FREE) - printf("MBO not free\n"); + printf("%s: MBO not free\n", aha->sc_dev.dv_xname); /* * Put all the arguments for the xfer in the ccb - * (can't use S/G if zero length) */ ccb->xfer = xs; - if(flags & SCSI_RESET) + if (flags & SCSI_RESET) { ccb->opcode = AHA_RESET_CCB; - else - ccb->opcode = (xs->datalen ? AHA_INIT_SCAT_GATH_CCB : AHA_INITIATOR_CCB); - ccb->target = xs->targ;; + } else { + /* can't use S/G if zero length */ + ccb->opcode = (xs->datalen ? AHA_INIT_SCAT_GATH_CCB + : AHA_INITIATOR_CCB); + } + ccb->target = sc_link->target; ccb->data_out = 0; ccb->data_in = 0; - ccb->lun = xs->lu; + ccb->lun = sc_link->lun; ccb->scsi_cmd_length = xs->cmdlen; ccb->req_sense_length = sizeof(ccb->scsi_sense); - /* can use S/G only if not zero length */ - if((xs->datalen) && (!(flags & SCSI_RESET))) { + if ((xs->datalen) && (!(flags & SCSI_RESET))) { + /* can use S/G only if not zero length */ lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr); sg = ccb->scat_gath; seg = 0; - if(flags & SCSI_DATA_UIO) { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; +#ifdef TFS_ONLY + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; while ((datalen) && (seg < AHA_NSEG)) { - lto3b((u_long)iovp->iov_base, (u_char *)&sg->seg_addr); - lto3b(iovp->iov_len, (u_char *)&sg->seg_len); - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)", iovp->iov_len, - iovp->iov_base); + lto3b(iovp->iov_base, sg->seg_addr); + lto3b(iovp->iov_len, sg->seg_len); + SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } else { + } else +#endif /*TFS_ONLY */ + { /* * Set up the scatter gather block */ - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ", xs->datalen, xs->data); + + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); datalen = xs->datalen; - thiskv = (int)xs->data; + thiskv = (int) xs->data; thisphys = KVTOPHYS(thiskv); while ((datalen) && (seg < AHA_NSEG)) { - bytes_this_seg = 0; + bytes_this_seg = 0; /* put in the base address */ - lto3b(thisphys, (u_char *)&(sg->seg_addr)); + lto3b(thisphys, sg->seg_addr); - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); + SC_DEBUGN(sc_link, SDEV_DB4, + ("0x%x", thisphys)); /* do it at least once */ nextphys = thisphys; @@ -986,399 +1134,312 @@ aha_scsi_cmd(struct scsi_xfer *xs) * with the the last, just extend the * length */ - /* how far to the end of the page? */ - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; - bytes_this_page = - min(nextphys - thisphys, datalen); + /* check it fits on the ISA bus */ + if (thisphys > 0xFFFFFF) { + printf("%s: DMA beyond" + " end of ISA\n", + aha->sc_dev.dv_xname); + xs->error = XS_DRIVER_STUFFUP; + aha_free_ccb(aha, ccb, flags); + return HAD_ERROR; + } + /** how far to the end of the page ***/ + nextphys = (thisphys & ~PGOFSET) + NBPG; + bytes_this_page = nextphys - thisphys; + /**** or the data ****/ + bytes_this_page = min(bytes_this_page, + datalen); bytes_this_seg += bytes_this_page; datalen -= bytes_this_page; - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + /* get more ready for the next page */ + thiskv = (thiskv & ~PGOFSET) + NBPG; + if (datalen) thisphys = KVTOPHYS(thiskv); } /* * next page isn't contiguous, finish the seg */ - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); - lto3b(bytes_this_seg, (u_char *)&(sg->seg_len)); + SC_DEBUGN(sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); + lto3b(bytes_this_seg, sg->seg_len); sg++; seg++; } } lto3b(seg * sizeof(struct aha_scat_gath), ccb->data_length); - if(scsi_debug & SHOWSCATGATH) - printf("\n"); + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); + if (datalen) { - /* there's still data, must have run out of segs! */ - printf("aha_scsi_cmd%d: needed more than %d DMA segs, %d\n", - unit, AHA_NSEG, datalen); + /* + * there's still data, must have run out of segs! + */ + printf("%s: aha_scsi_cmd, more than %d DMA segs\n", + aha->sc_dev.dv_xname, AHA_NSEG); xs->error = XS_DRIVER_STUFFUP; - aha_free_ccb(unit, ccb, flags); - return(HAD_ERROR); + aha_free_ccb(aha, ccb, flags); + return HAD_ERROR; } - } else { /* No data xfer, use non S/G values */ - lto3b(0, ccb->data_addr ); + } else { /* No data xfer, use non S/G values */ + lto3b(0, ccb->data_addr); lto3b(0, ccb->data_length); } lto3b(0, ccb->link_addr); + /* * Put the scsi command in the ccb and start it */ - if(!(flags & SCSI_RESET)) + if (!(flags & SCSI_RESET)) bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length); - if(scsi_debug & SHOWCOMMANDS) - { - u_char *b = (u_char *)&ccb->scsi_cmd; - if(!(flags & SCSI_RESET)) - { - int i = 0; - printf("aha%d:%d:%d-" - ,unit - ,ccb->target - ,ccb->lun ); - while(i < ccb->scsi_cmd_length ) - { - if(i) printf(","); - printf("%x",b[i++]); - } - } - else - { - printf("aha%d:%d:%d-RESET- " - ,unit - ,ccb->target - ,ccb->lun - ); - } - } - if (!(flags & SCSI_NOMASK)) - { - s= splbio(); /* stop instant timeouts */ - aha_add_timeout(ccb,xs->timeout); + if (!(flags & SCSI_NOMASK)) { + s = splbio(); /* stop instant timeouts */ + timeout(aha_timeout, (caddr_t)ccb, (xs->timeout * hz) / 1000); aha_startmbx(ccb->mbx); /* * Usually return SUCCESSFULLY QUEUED */ splx(s); - if(scsi_debug & TRACEINTERRUPTS) - printf("sent "); - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(sc_link, SDEV_DB3, ("sent\n")); + return SUCCESSFULLY_QUEUED; } aha_startmbx(ccb->mbx); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent, waiting "); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd sent, waiting\n")); + /* - * If we can't use interrupts, poll on completion* + * If we can't use interrupts, poll on completion */ - { - int done = 0; - int count = delaycount * xs->timeout / AHA_SCSI_TIMEOUT_FUDGE; - while((!done) && count) - { - i=0; - while ( (!done) && iflags & SCSI_SILENT)) - printf("cmd fail\n"); - aha_abortmbx(ccb->mbx); - count = delaycount * 2000 / AHA_SCSI_TIMEOUT_FUDGE; - while((!done) && count) { - i=0; - while ( (!done) && imbx->cmd = AHA_MBO_FREE; - } - aha_free_ccb(unit,ccb,flags); - ahaintr(unit); - xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); - } - ahaintr(unit); - if(xs->error) return(HAD_ERROR); - return(COMPLETE); - } - /* return ??? */ + return aha_poll(aha, xs, ccb); /* only during boot */ } /* - * try each speed in turn, when we find one that works, use - * the NEXT one for a safety margin, unless that doesn't exist - * or doesn't work. returns the nsec value of the time used - * or 0 if it could get a working speed ( or the NEXT speed - * failed) - * Go one slower to be safe, unless eisa at 100 ns.. trust it + * Poll a particular unit, looking for a particular xs */ -int -aha_set_bus_speed(int unit) +int +aha_poll(aha, xs, ccb) + struct aha_softc *aha; + struct scsi_xfer *xs; + struct aha_ccb *ccb; { - int retval, retval2; - int speed; + int done = 0; + int count = xs->timeout; + u_char stat; -#ifdef EISA - speed = 0; /* start at the fastest */ -#else EISA - speed = 1; /* 100 ns can crash some ISA busses (!?!) */ -#endif EISA - while (1) { - retval = aha_bus_speed_check(unit, speed); - if(retval == HAD_ERROR) { - printf("no working bus speed!!!\n"); - return 0; + /* timeouts are in msec, so we loop in 1000 usec cycles */ + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + stat = inb(AHA_INTR_PORT); + if (stat & AHA_ANY_INTR) + ahaintr(aha->sc_dev.dv_unit); + if (xs->flags & ITSDONE) + break; + delay(1000); /* only happens in boot so ok */ + count--; + } + if (!count) { + /* + * We timed out, so call the timeout handler manually, + * accounting for the fact that the clock is not running yet + * by taking out the clock queue entry it makes. + */ + aha_timeout((caddr_t)ccb); + + /* + * because we are polling, take out the timeout entry + * aha_timeout made + */ + untimeout(aha_timeout, (caddr_t)ccb); + count = 2000; + while (count) { + /* + * Once again, wait for the int bit + */ + stat = inb(AHA_INTR_PORT); + if (stat & AHA_ANY_INTR) + ahaintr(aha->sc_dev.dv_unit); + if (xs->flags & ITSDONE) + break; + delay(1000); /* only happens in boot so ok */ + count--; } + if (!count) { + /* + * We timed out again.. this is bad + * Notice that this time there is no + * clock queue entry to remove + */ + aha_timeout((caddr_t)ccb); + } + } + if (xs->error) + return HAD_ERROR; + return COMPLETE; - if(retval == 0) - speed++; - else { - if(speed != 0) - speed++; +} - /*printf("%d nsec ok, but using ", retval);*/ - retval2 = aha_bus_speed_check(unit, speed); - if(retval2 == HAD_ERROR) { - /*printf("marginal ");*/ - retval2 = retval; - } - if(retval2) { - /*printf("%d nsec\n", retval2);*/ - return retval2; - } else { - /*printf(".. slower failed, abort.\n", retval);*/ +#ifdef TUNE_1542 +/* + * Try all the speeds from slowest to fastest.. if it finds a + * speed that fails, back off one notch from the last working + * speed (unless there is no other notch). + * Returns the nSEC value of the time used + * or 0 if it could get a working speed (or the NEXT speed + * failed) + */ +static struct bus_speed +{ + char arg; + int nsecs; +} aha_bus_speeds[] = +{ + {0x88,100}, + {0x99,150}, + {0xaa,200}, + {0xbb,250}, + {0xcc,300}, + {0xdd,350}, + {0xee,400}, + {0xff,450} +}; + +int +aha_set_bus_speed(aha) + struct aha_softc *aha; +{ + int speed; + int lastworking; + int retval,retval2; + + lastworking = -1; + speed = 7; + while (1) { + retval = aha_bus_speed_check(aha, speed); + if (retval != 0) + lastworking = speed; + if ((retval == 0) || (speed == 0)) { + if (lastworking == -1) { + printf("No working bus speed for aha154X\n"); return 0; } + printf("%d nSEC ok, using " + ,aha_bus_speeds[lastworking].nsecs); + if (lastworking == 7) /* is slowest already */ + printf("marginal "); + else + lastworking++; + retval2 = aha_bus_speed_check(aha, lastworking); + if (retval2 == 0) { + printf("test retry failed.. aborting.\n"); + return 0; + } + printf("%d nSEC\n",retval2); + return retval2 ; + } + speed--; } } /* * Set the DMA speed to the Nth speed and try an xfer. If it - * fails return 0, if it succeeds return the nsec value selected + * fails return 0, if it succeeds return the nSec value selected * If there is no such speed return HAD_ERROR. */ -static struct bus_speed { - char arg; - int nsecs; -} aha_bus_speeds[] = { - {0x88, 100}, - {0x99, 150}, - {0xaa, 200}, - {0xbb, 250}, - {0xcc, 300}, - {0xdd, 350}, - {0xee, 400}, - {0xff, 450} -}; -static char aha_test_string[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; +static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@"; -int -aha_bus_speed_check(int unit, int speed) +int +aha_bus_speed_check(aha, speed) + struct aha_softc *aha; + int speed; { - int numspeeds = sizeof(aha_bus_speeds)/sizeof(struct bus_speed); - u_char ad[3]; + int numspeeds = sizeof(aha_bus_speeds) / sizeof(struct bus_speed); + int loopcount; + u_char ad[3]; /* * Check we have such an entry */ - if(speed >= numspeeds) return(HAD_ERROR); /* illegal speed */ + if (speed >= numspeeds) + return HAD_ERROR; /* illegal speed */ /* * Set the dma-speed */ - aha_cmd(unit,1, 0, 0, (u_char *)0, AHA_SPEED_SET,aha_bus_speeds[speed].arg); + aha_cmd(aha, 1, 0, 0, 0, AHA_SPEED_SET, aha_bus_speeds[speed].arg); /* * put the test data into the buffer and calculate * it's address. Read it onto the board */ - strcpy((char *)aha_scratch_buf, (char *)aha_test_string); lto3b(KVTOPHYS(aha_scratch_buf), ad); + for (loopcount = 2000; loopcount; loopcount--) { + strcpy(aha_scratch_buf, aha_test_string); - aha_cmd(unit,3, 0, 0, (u_char *)0, AHA_WRITE_FIFO, - ad[0], ad[1], ad[2]); + aha_cmd(aha, 3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]); + + /* + * clear the buffer then copy the contents back from the + * board. + */ + bzero(aha_scratch_buf, 54); /* 54 bytes transfered by test */ + + aha_cmd(aha, 3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]); + + /* + * Compare the original data and the final data and + * return the correct value depending upon the result + */ + if (strcmp(aha_test_string, aha_scratch_buf)) + return 0; /* failed test */ + } + /* copy succeded assume speed ok */ + + return aha_bus_speeds[speed].nsecs; + +} +#endif /*TUNE_1542*/ + +void +aha_timeout(arg) + caddr_t arg; +{ + int s = splbio(); + struct aha_ccb *ccb = (void *)arg; + struct aha_softc *aha; + + aha = ccb->xfer->sc_link->adapter_softc; + sc_print_addr(ccb->xfer->sc_link); + printf("timed out "); /* - * clear the buffer then copy the contents back from the - * board. + * If The ccb's mbx is not free, then + * the board has gone south */ - bzero(aha_scratch_buf,54); /* 54 bytes transfered by test */ - - aha_cmd(unit,3, 0, 0, (u_char *)0, AHA_READ_FIFO, - ad[0], ad[1], ad[2]); + if (ccb->mbx->cmd != AHA_MBO_FREE) { + printf("\nadapter not taking commands.. frozen?!\n"); + Debugger(); + } /* - * Compare the original data and the final data and - * return the correct value depending upon the result - * if copy fails.. assume too fast + * If it has been through before, then + * a previous abort has failed, don't + * try abort again */ - if(strcmp(aha_test_string, (char *)aha_scratch_buf)) - return(0); - return(aha_bus_speeds[speed].nsecs); -} - - -/* - * +----------+ +----------+ +----------+ - * aha_soonest--->| later |--->| later|--->| later|-->0 - * | [Delta] | | [Delta] | | [Delta] | - * 0<---|sooner |<---|sooner |<---|sooner |<---aha_latest - * +----------+ +----------+ +----------+ - * - * aha_furtherest = sum(Delta[1..n]) - */ -void -aha_add_timeout(struct aha_ccb *ccb, int time) -{ - int timeprev; - struct aha_ccb *prev; - int s = splbio(); - - if(prev = aha_latest) /* yes, an assign */ - timeprev = aha_furtherest; - else - timeprev = 0; - - while(prev && (timeprev > time)) { - timeprev -= prev->delta; - prev = prev->sooner; - } - if(prev) { - ccb->delta = time - timeprev; - if( ccb->later = prev->later) { - ccb->later->sooner = ccb; - ccb->later->delta -= ccb->delta; - } else { - aha_furtherest = time; - aha_latest = ccb; - } - ccb->sooner = prev; - prev->later = ccb; + if (ccb->flags == CCB_ABORTED) { + /* abort timed out */ + printf("AGAIN\n"); + ccb->xfer->retries = 0; /* I MEAN IT ! */ + ccb->host_stat = AHA_ABORTED; + aha_done(aha, ccb); } else { - if( ccb->later = aha_soonest) { - ccb->later->sooner = ccb; - ccb->later->delta -= time; - } else { - aha_furtherest = time; - aha_latest = ccb; - } - ccb->delta = time; - ccb->sooner = (struct aha_ccb *)0; - aha_soonest = ccb; + /* abort the operation that has timed out */ + printf("\n"); + aha_abortmbx(ccb->mbx); + /* 4 secs for the abort */ + timeout(aha_timeout, (caddr_t)ccb, 2 * hz); + ccb->flags = CCB_ABORTED; } splx(s); } - -void -aha_remove_timeout(struct aha_ccb *ccb) -{ - int s = splbio(); - - if(ccb->sooner) - ccb->sooner->later = ccb->later; - else - aha_soonest = ccb->later; - - if(ccb->later) { - ccb->later->sooner = ccb->sooner; - ccb->later->delta += ccb->delta; - } else { - aha_latest = ccb->sooner; - aha_furtherest -= ccb->delta; - } - ccb->sooner = ccb->later = (struct aha_ccb *)0; - splx(s); -} - -extern int hz; -#define ONETICK 500 /* milliseconds */ -#define SLEEPTIME ((hz * 1000) / ONETICK) - -void -aha_timeout(int arg) -{ - struct aha_ccb *ccb; - int unit; - int s = splbio(); - - while( ccb = aha_soonest ) { - if(ccb->delta <= ONETICK) { - /* - * It has timed out, we need to do some work - */ - unit = ccb->xfer->adapter; - printf("aha%d: device %d timed out ", unit, - ccb->xfer->targ); - - /* - * Unlink it from the queue - */ - aha_remove_timeout(ccb); - - /* - * If The ccb's mbx is not free, then - * the board has gone south - */ - if(ccb->mbx->cmd != AHA_MBO_FREE) { - printf("aha%d not taking commands!\n", unit); - Debugger(); - } - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if(ccb->flags == CCB_ABORTED) { - /* abort timed out */ - printf(" AGAIN\n"); - ccb->xfer->retries = 0; /* I MEAN IT ! */ - ccb->host_stat = AHA_ABORTED; - aha_done(unit,ccb); - } else { - /* abort the operation that has timed out */ - printf("\n"); - aha_abortmbx(ccb->mbx); - /* 2 secs for the abort */ - aha_add_timeout(ccb,2000 + ONETICK); - ccb->flags = CCB_ABORTED; - } - } else { - /* - * It has not timed out, adjust and leave - */ - ccb->delta -= ONETICK; - aha_furtherest -= ONETICK; - break; - } - } - splx(s); - timeout((timeout_t)aha_timeout, (caddr_t)arg, SLEEPTIME); -} diff --git a/sys/dev/isa/bt742a.c b/sys/dev/isa/bt742a.c index 7318c3d06201..b5f8f4f23d98 100644 --- a/sys/dev/isa/bt742a.c +++ b/sys/dev/isa/bt742a.c @@ -1,5 +1,36 @@ /* - * Written by Julian Elischer (julian@tfs.com) + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: bt742a.c,v 1.21 1994/03/29 04:30:21 mycroft Exp $ + */ + +/* + * Originally written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -11,51 +42,46 @@ * TFS supplies this software to be publicly redistributed * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. - * - * $Id: bt742a.c,v 1.20 1994/03/25 07:40:55 mycroft Exp $ */ /* - * BusTech/BusLogic SCSI card driver (all cards) - * - * Modified to support round-robin mailbox allocation and page-aligned - * buffer allocation by Michael VanLoon (michaelv@iastate.edu) + * bt742a SCSI driver */ -#include "bt.h" - #include #include #include +#include #include #include +#include #include #include #include #include -#include -#include -#include +#include + +#include +#include #include #include #ifdef DDB int Debugger(); -#else -#define Debugger() panic("should call debugger here (bt742a.c)") -#endif +#else /* DDB */ +#define Debugger() +#endif /* DDB */ -extern int delaycount; /* from clock setup code */ -typedef unsigned long int physaddr; +typedef u_long physaddr; /* * I/O Port Interface */ -#define BT_BASE bt_base[unit] -#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ -#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ -#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ +#define BT_BASE bt->bt_base +#define BT_CTRL_STAT_PORT (BT_BASE + 0x0) /* control & status */ +#define BT_CMD_DATA_PORT (BT_BASE + 0x1) /* cmds and datas */ +#define BT_INTR_PORT (BT_BASE + 0x2) /* Intr. stat */ /* * BT_CTRL_STAT bits (write) @@ -101,6 +127,11 @@ typedef unsigned long int physaddr; #define BT_MBX_INIT_EXTENDED 0x81 /* Mbx initialization */ #define BT_INQUIRE_EXTENDED 0x8D /* Adapter Setup Inquiry */ +/* Follows command appeared at FirmWare 3.31 */ +#define BT_ROUND_ROBIN 0x8f /* Enable/Disable(default) round robin */ +#define BT_DISABLE 0x00 /* Parameter value for Disable */ +#define BT_ENABLE 0x01 /* Parameter value for Enable */ + struct bt_cmd_buf { u_char byte[16]; }; @@ -108,30 +139,51 @@ struct bt_cmd_buf { /* * BT_INTR_PORT bits (read) */ -#define BT_ANY_INTR 0x80 /* Any interrupt */ +#define BT_ANY_INTR 0x80 /* Any interrupt */ #define BT_SCRD 0x08 /* SCSI reset detected */ #define BT_HACC 0x04 /* Command complete */ #define BT_MBOA 0x02 /* MBX out empty */ #define BT_MBIF 0x01 /* MBX in full */ /* - * Mail box defs + * Mail box defs etc. + * these could be bigger but we need the bt_softc to fit on a single page.. */ -#define BT_MBX_SIZE 32 /* mail box size */ +#define BT_MBX_SIZE 16 /* mail box size (MAX 255 MBxs) */ + /* don't need that many really */ +#define BT_CCB_MAX 32 /* store up to 32CCBs at any one time */ + /* in bt742a H/W ( Not MAX ? ) */ +#define CCB_HASH_SIZE 32 /* when we have a physical addr. for */ + /* a ccb and need to find the ccb in */ + /* space, look it up in the hash table */ +#define CCB_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define CCB_HASH(x) ((((long int)(x))>>CCB_HASH_SHIFT) % CCB_HASH_SIZE) + +#define bt_nextmbx( wmb, mbx, mbio ) \ + if ( (wmb) == &((mbx)->mbio[BT_MBX_SIZE - 1 ]) ) \ + (wmb) = &((mbx)->mbio[0]); \ + else \ + (wmb)++; + +typedef struct bt_mbx_out { + physaddr ccb_addr; + u_char dummy[3]; + u_char cmd; +} BT_MBO; + +typedef struct bt_mbx_in { + physaddr ccb_addr; + u_char btstat; + u_char sdstat; + u_char dummy; + u_char stat; +} BT_MBI; struct bt_mbx { - struct bt_mbx_out { - physaddr ccb_addr; - unsigned char dummy[3]; - unsigned char cmd; - } mbo[BT_MBX_SIZE]; - struct bt_mbx_in { - physaddr ccb_addr; - unsigned char btstat; - unsigned char sdstat; - unsigned char dummy; - unsigned char stat; - } mbi[BT_MBX_SIZE]; + BT_MBO mbo[BT_MBX_SIZE]; + BT_MBI mbi[BT_MBX_SIZE]; + BT_MBO *tmbo; /* Target Mail Box out */ + BT_MBI *tmbi; /* Target Mail Box in */ }; /* @@ -141,43 +193,52 @@ struct bt_mbx { #define BT_MBO_START 0x1 /* MBO activate entry */ #define BT_MBO_ABORT 0x2 /* MBO abort entry */ +/* + * mbi.stat values + */ #define BT_MBI_FREE 0x0 /* MBI entry is free */ #define BT_MBI_OK 0x1 /* completed without error */ #define BT_MBI_ABORT 0x2 /* aborted ccb */ #define BT_MBI_UNKNOWN 0x3 /* Tried to abort invalid CCB */ #define BT_MBI_ERROR 0x4 /* Completed with error */ -#define BT_NSEG 32 +#if defined(BIG_DMA) +WARNING...THIS WON'T WORK(won't fit on 1 page) +/* #define BT_NSEG 2048 /* Number of scatter gather segments - to much vm */ +#define BT_NSEG 128 +#else +#define BT_NSEG 33 +#endif /* BIG_DMA */ struct bt_scat_gath { - unsigned long seg_len; + u_long seg_len; physaddr seg_addr; }; struct bt_ccb { - unsigned char opcode; - unsigned char:3, data_in:1, data_out:1,:3; - unsigned char scsi_cmd_length; - unsigned char req_sense_length; + u_char opcode; + u_char:3, data_in:1, data_out:1,:3; + u_char scsi_cmd_length; + u_char req_sense_length; /*------------------------------------longword boundary */ - unsigned long data_length; + u_long data_length; /*------------------------------------longword boundary */ physaddr data_addr; /*------------------------------------longword boundary */ - unsigned char dummy[2]; - unsigned char host_stat; - unsigned char target_stat; + u_char dummy[2]; + u_char host_stat; + u_char target_stat; /*------------------------------------longword boundary */ - unsigned char target; - unsigned char lun; - unsigned char scsi_cmd[12]; /* 12 bytes (bytes only) */ - unsigned char dummy2[1]; - unsigned char link_id; + u_char target; + u_char lun; + u_char scsi_cmd[12]; /* 12 bytes (bytes only) */ + u_char dummy2[1]; + u_char link_id; /*------------------------------------4 longword boundary */ physaddr link_addr; /*------------------------------------longword boundary */ physaddr sense_ptr; - /*------------------------------------longword boundary */ +/*-----end of HW fields-------------------------------longword boundary */ struct scsi_sense_data scsi_sense; /*------------------------------------longword boundary */ struct bt_scat_gath scat_gath[BT_NSEG]; @@ -188,19 +249,17 @@ struct bt_ccb { /*------------------------------------longword boundary */ struct bt_mbx_out *mbx; /* pointer to mail box */ /*------------------------------------longword boundary */ - long delta; /* difference from previous */ - struct bt_ccb *later, *sooner; int flags; #define CCB_FREE 0 #define CCB_ACTIVE 1 #define CCB_ABORTED 2 - unsigned char dummy3[24]; /* align struct to 32 bits */ + /*------------------------------------longword boundary */ + struct bt_ccb *nexthash; /* if two hash the same */ + /*------------------------------------longword boundary */ + physaddr hashkey; /*physaddr of this ccb */ + /*------------------------------------longword boundary */ }; -struct bt_ccb *bt_soonest = (struct bt_ccb *) 0; -struct bt_ccb *bt_latest = (struct bt_ccb *) 0; -long int bt_furthest = 0; /* longest time in the timeout queue */ - /* * opcode fields */ @@ -227,28 +286,36 @@ long int bt_furthest = 0; /* longest time in the timeout queue */ #define BT_INV_CCB 0x1a /* Invalid CCB or segment list */ #define BT_ABORTED 42 /* pseudo value from driver */ +struct bt_boardID { + u_char board_type; + u_char custom_feture; + char firm_revision; + u_char firm_version; +}; + struct bt_setup { - u_char sync_neg:1; - u_char parity:1; - u_char xxx:6; - u_char speed; - u_char bus_on; - u_char bus_off; - u_char num_mbx; - u_char mbx[4]; + u_char sync_neg:1; + u_char parity:1; + u_char :6; + u_char speed; + u_char bus_on; + u_char bus_off; + u_char num_mbx; + u_char mbx[3]; /*XXX */ + /* doesn't make sense with 32bit addresses */ struct { - u_char offset:4; - u_char period:3; - u_char valid:1; + u_char offset:4; + u_char period:3; + u_char valid:1; } sync[8]; - u_char disc_sts; + u_char disc_sts; }; struct bt_config { - u_char chan; - u_char intr; - u_char scsi_dev:3; - u_char xxx:5; + u_char chan; + u_char intr; + u_char scsi_dev:3; + u_char :5; }; #define INT9 0x01 @@ -266,33 +333,21 @@ struct bt_config { #define KVTOPHYS(x) vtophys(x) -#define PAGESIZ NBPG -#define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); } +struct bt_softc { + struct device sc_dev; + struct isadev sc_id; + struct intrhand sc_ih; -short bt_base[NBT]; /* base port for each board */ -struct isa_device *btinfo[NBT]; -struct bt_ccb *bt_get_ccb(); -int bt_int[NBT]; -int bt_dma[NBT]; -int bt_initialized[NBT]; - -/* we'll malloc memory for these in bt_init() */ -struct bt_data { - struct bt_mbx bt_mbx; - struct bt_ccb bt_ccb[BT_MBX_SIZE]; - struct scsi_xfer bt_scsi_xfer; - int sleepers; -} *btdata[NBT]; - -struct bt_ccb_lu { - struct bt_ccb *kv_addr; - physaddr phys_addr; -} bt_ccb_lut[NBT][BT_MBX_SIZE]; - -struct { /* mbo and mbi last used */ - u_char mbo; - u_char mbi; -} bt_last[NBT]; + u_short bt_base; /* base port for each board */ + struct bt_mbx bt_mbx; /* all our mailboxes */ + struct bt_ccb *bt_ccb_free; /* list of free CCBs */ + struct bt_ccb *ccbhash[CCB_HASH_SIZE]; /* phys to kv hash */ + int bt_int; /* int. read off board */ + int bt_dma; /* DMA channel read of board */ + int bt_scsi_dev; /* adapters scsi id */ + int numccbs; /* how many we have malloc'd */ + struct scsi_link sc_link; /* prototype for devs */ +}; /***********debug values *************/ #define BT_SHOWCCBS 0x01 @@ -301,87 +356,111 @@ struct { /* mbo and mbi last used */ #define BT_SHOWMISC 0x08 int bt_debug = 0; -int btprobe(), btattach(); -int btintr(); +int bt_cmd(); /* XXX must be varargs to prototype */ +u_int bt_adapter_info __P((struct bt_softc *)); +int btintr __P((int)); +void bt_free_ccb __P((struct bt_softc *, struct bt_ccb *, int)); +struct bt_ccb *bt_get_ccb __P((struct bt_softc *, int)); +struct bt_ccb *bt_ccb_phys_kv __P((struct bt_softc *, physaddr)); +BT_MBO *bt_send_mbo __P((struct bt_softc *, int, int, struct bt_ccb *)); +void bt_done __P((struct bt_softc *, struct bt_ccb *)); +int bt_find __P((struct bt_softc *)); +void bt_init __P((struct bt_softc *)); +void bt_inquire_setup_information __P((struct bt_softc *)); +void btminphys __P((struct buf *)); +int bt_scsi_cmd __P((struct scsi_xfer *)); +int bt_poll __P((struct bt_softc *, struct scsi_xfer *, struct bt_ccb *)); +void bt_timeout __P((caddr_t)); +#ifdef UTEST +void bt_print_ccb __P((struct bt_ccb *)); +void bt_print_active_ccbs __P((struct bt_softc *)); +#endif -struct isa_driver btdriver = { - btprobe, - btattach, +struct scsi_adapter bt_switch = { + bt_scsi_cmd, + btminphys, + 0, + 0, + bt_adapter_info, "bt" }; -static int btunit = 0; +/* the below structure is so we have a default dev struct for out link struct */ +struct scsi_device bt_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "bt", + 0 +}; -#define bt_abortmbx(mbx) \ - (mbx)->cmd = BT_MBO_ABORT; \ - outb(BT_CMD_DATA_PORT, BT_START_SCSI); -#define bt_startmbx(mbx) \ - (mbx)->cmd = BT_MBO_START; \ - outb(BT_CMD_DATA_PORT, BT_START_SCSI); +int btprobe(); +void btattach(); -int bt_scsi_cmd(); -int bt_timeout(); -void btminphys(); -long int bt_adapter_info(); +struct cfdriver btcd = { + NULL, "bt", btprobe, btattach, DV_DULL, sizeof(struct bt_softc) +}; -struct scsi_switch bt_switch[NBT]; - -#define BT_CMD_TIMEOUT_FUDGE 200 /* multiplied to get Secs */ -#define BT_RESET_TIMEOUT 1000000 /* */ -#define BT_SCSI_TIMEOUT_FUDGE 20 /* divided by for mSecs */ +#define BT_RESET_TIMEOUT 1000 /* - * Activate Adapter command - * icnt: number of args (outbound bytes written after opcode) - * ocnt: number of expected returned bytes - * wait: number of seconds to wait for response - * retval: buffer where to place returned bytes - * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... - * args: parameters + * bt_cmd(bt, icnt, ocnt,wait, retval, opcode, args) * - * Performs an adapter command through the ports. Not to be confused - * with a scsi command, which is read in via the dma - * One of the adapter commands tells it to read in a scsi command + * Activate Adapter command + * icnt: number of args (outbound bytes written after opcode) + * ocnt: number of expected returned bytes + * wait: number of seconds to wait for response + * retval: buffer where to place returned bytes + * opcode: opcode BT_NOP, BT_MBX_INIT, BT_START_SCSI ... + * args: parameters + * + * Performs an adapter command through the ports. Not to be confused with a + * scsi command, which is read in via the dma; one of the adapter commands + * tells it to read in a scsi command. */ -bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) +int +bt_cmd(bt, icnt, ocnt, wait, retval, opcode, args) + struct bt_softc *bt; + int icnt, ocnt, wait; u_char *retval; unsigned opcode; - u_char args; + u_char args; { unsigned *ic = &opcode; - u_char oc; + u_char oc; register i; - int sts; - struct bt_data *bt = btdata[unit]; + int sts; /* * multiply the wait argument by a big constant * zero defaults to 1 */ - if (!wait) - wait = BT_CMD_TIMEOUT_FUDGE * delaycount; + if (wait) + wait *= 100000; else - wait *= BT_CMD_TIMEOUT_FUDGE * delaycount; - + wait = 100000; /* * Wait for the adapter to go idle, unless it's one of * the commands which don't need this */ if (opcode != BT_MBX_INIT && opcode != BT_START_SCSI) { - i = BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ + i = 100000; /* 1 sec? */ while (--i) { sts = inb(BT_CTRL_STAT_PORT); if (sts & BT_IDLE) { break; } + delay(10); } if (!i) { - printf("bt_cmd: bt742a host not idle(0x%x)\n", sts); - return (ENXIO); + printf("%s: bt_cmd, host not idle(0x%x)\n", + bt->sc_dev.dv_xname, sts); + return ENXIO; } } /* - * Now that it is idle, if we expect output, preflush the* + * Now that it is idle, if we expect output, preflush the * queue feeding to us. */ if (ocnt) { @@ -392,18 +471,21 @@ bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) * Output the command and the number of arguments given * for each byte, first check the port is empty. */ - icnt++; /* include the command */ + icnt++; + /* include the command */ while (icnt--) { sts = inb(BT_CTRL_STAT_PORT); - for (i = 0; i < wait; i++) { + for (i = wait; i; i--) { sts = inb(BT_CTRL_STAT_PORT); if (!(sts & BT_CDF)) break; + delay(10); } - if (i >= wait) { - printf("bt_cmd: bt742a cmd/data port full\n"); + if (!i) { + printf("%s: bt_cmd, cmd/data port full\n", + bt->sc_dev.dv_xname); outb(BT_CTRL_STAT_PORT, BT_SRST); - return (ENXIO); + return ENXIO; } outb(BT_CMD_DATA_PORT, (u_char) (*ic++)); } @@ -413,14 +495,16 @@ bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) */ while (ocnt--) { sts = inb(BT_CTRL_STAT_PORT); - for (i = 0; i < wait; i++) { + for (i = wait; i; i--) { sts = inb(BT_CTRL_STAT_PORT); if (sts & BT_DF) break; + delay(10); } - if (i >= wait) { - printf("bt_cmd: bt742a cmd/data port empty %d\n", ocnt); - return (ENXIO); + if (!i) { + printf("bt%d: bt_cmd, cmd/data port empty %d\n", + bt->sc_dev.dv_xname, ocnt); + return ENXIO; } oc = inb(BT_CMD_DATA_PORT); if (retval) @@ -429,19 +513,20 @@ bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) /* * Wait for the board to report a finised instruction */ - i = BT_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec? */ + i = 100000; /* 1 sec? */ while (--i) { sts = inb(BT_INTR_PORT); - if (sts & BT_HACC) { + if (sts & BT_HACC) break; - } + delay(10); } if (!i) { - printf("bt_cmd: bt742a host not finished(0x%x)\n", sts); - return (ENXIO); + printf("%s: bt_cmd, host not finished(0x%x)\n", + bt->sc_dev.dv_xname, sts); + return ENXIO; } outb(BT_CTRL_STAT_PORT, BT_IRST); - return (0); + return 0; } /* @@ -450,301 +535,414 @@ bt_cmd(unit, icnt, ocnt, wait, retval, opcode, args) * as an argument, takes the isa_device structure from * autoconf.c */ -btprobe(dev) - struct isa_device *dev; +int +btprobe(parent, self, aux) + struct device *parent, *self; + void *aux; { - /* - * find unit and check we have that many defined - */ - int unit; - struct bt_data *bt; + struct bt_softc *bt = (void *)self; + register struct isa_attach_args *ia = aux; - if (dev->id_parent) - return 1; +#ifdef NEWCONFIG + if (ia->ia_iobase == IOBASEUNK) + return 0; +#endif + + bt->bt_base = ia->ia_iobase; - dev->id_unit = unit = btunit; - bt = btdata[unit]; - bt_base[unit] = dev->id_iobase; - if (unit >= NBT) { - printf("bt: unit number (%d) too high\n", unit); - return (0); - } /* * Try initialise a unit at this location - * sets up dma and bus speed, loads bt_int[unit]* + * sets up dma and bus speed, loads bt->bt_int */ - if (bt_init(unit) != 0) { - return (0); - } - /* - * If it's there, put in it's interrupt vectors - */ - dev->id_irq = (1 << bt_int[unit]); - dev->id_drq = bt_dma[unit]; + if (bt_find(bt) != 0) + return 0; + +#ifdef NEWCONFIG + /* + * If it's there, put in it's interrupt vectors and dma channel + */ + if (ia->ia_irq == IRQUNK) { + ia->ia_irq = (1 << bt->bt_int); + } else { + if (ia->ia_irq != (1 << bt->bt_int)) { + printf("bt%d: irq mismatch, %x != %x\n", + bt->sc_dev.dv_unit, ia->ia_irq, + 1 << bt->bt_int); + return 0; + } + } + + if (ia->ia_drq == DRQUNK) { + ia->ia_drq = bt->bt_dma; + } else { + if (ia->ia_drq != bt->bt_dma) { + printf("bt%d: drq mismatch, %x != %x\n", + bt->sc_dev.dv_unit, ia->ia_drq, bt->bt_dma); + return 0; + } + } +#endif + + ia->ia_msize = 0; + ia->ia_iosize = 4; + return 1; +} + +btprint() +{ - btunit++; - return (8); } /* * Attach all the sub-devices we can find */ -btattach(dev) - struct isa_device *dev; +void +btattach(parent, self, aux) + struct device *parent, *self; + void *aux; { - static int firsttime; - static int firstswitch[NBT]; - int masunit; - int r; + struct isa_attach_args *ia = aux; + struct bt_softc *bt = (void *)self; - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; + bt_init(bt); - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - bt_switch[masunit].name = "bt"; - bt_switch[masunit].scsi_cmd = bt_scsi_cmd; - bt_switch[masunit].scsi_minphys = btminphys; - bt_switch[masunit].open_target_lu = 0; - bt_switch[masunit].close_target_lu = 0; - bt_switch[masunit].adapter_info = bt_adapter_info; - for (r = 0; r < 8; r++) { - bt_switch[masunit].empty[r] = 0; - bt_switch[masunit].used[r] = 0; - bt_switch[masunit].printed[r] = 0; - } - } - r = scsi_attach(masunit, &bt_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); + /* + * fill in the prototype scsi_link. + */ + bt->sc_link.adapter_softc = bt; + bt->sc_link.adapter_targ = bt->bt_scsi_dev; + bt->sc_link.adapter = &bt_switch; + bt->sc_link.device = &bt_dev; - /* only one for all boards */ - if (firsttime == 0) { - firsttime = 1; - bt_timeout(0); - } - return r; + printf("\n"); + +#ifdef NEWCONFIG + isa_establish(&bt->sc_id, &bt->sc_dev); + bt->sc_ih.ih_fun = btintr; + bt->sc_ih.ih_arg = bt; + /* XXX and DV_TAPE, but either gives us splbio */ + intr_establish(ia->ia_irq, &bt->sc_ih, DV_DISK); +#endif + + /* + * ask the adapter what subunits are present + */ + config_found(self, &bt->sc_link, btprint); } /* - * Return some information to the caller about - * the adapter and it's capabilities + * Return some information to the caller about the adapter and its + * capabilities. */ -long -bt_adapter_info(unit) - int unit; +u_int +bt_adapter_info(bt) + struct bt_softc *bt; { - /* 2 outstanding requests at a time per device */ - return (2); -} + return 2; /* 2 outstanding requests at a time per device */ +} /* * Catch an interrupt from the adaptor */ +int btintr(unit) + int unit; { + struct bt_softc *bt = btcd.cd_devs[unit]; + BT_MBI *wmbi; + struct bt_mbx *wmbx; struct bt_ccb *ccb; - unsigned char stat; - register int i, j; - u_char found_one = 0, done = 0; - struct bt_data *bt = btdata[unit]; + u_char stat; + int i, wait; + int found = 0; - if ((scsi_debug & PRINTROUTINES) || bt_debug) - printf("btintr "); +#ifdef UTEST + printf("btintr "); +#endif /* * First acknowlege the interrupt, Then if it's * not telling about a completed operation - * just return. + * just return. */ stat = inb(BT_INTR_PORT); - outb(BT_CTRL_STAT_PORT, BT_IRST); - if ((scsi_debug & TRACEINTERRUPTS) || bt_debug) - printf("int = 0x%x ", stat); - if (!(stat & BT_MBIF)) - return 1; - if (scsi_debug & TRACEINTERRUPTS) - printf("mbxi "); + /* Mail Box out empty ? */ + if (stat & BT_MBOA) { + printf("%s: Available Free mbo post\n", bt->sc_dev.dv_xname); + /* Disable MBO available interrupt */ + outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN); + wait = 100000; /* 1 sec enough? */ + for (i = wait; i; i--) { + if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) + break; + delay(10); + } + if (i == 0) { + printf("%s: bt_intr, cmd/data port full\n", + bt->sc_dev.dv_xname); + outb(BT_CTRL_STAT_PORT, BT_SRST); + return 1; + } + outb(BT_CMD_DATA_PORT, 0x00); /* Disable */ + wakeup((caddr_t)&bt->bt_mbx); + outb(BT_CTRL_STAT_PORT, BT_IRST); + return 1; + } + if (!(stat & BT_MBIF)) { + outb(BT_CTRL_STAT_PORT, BT_IRST); + return 1; + } /* * If it IS then process the competed operation */ - for (i = bt_last[unit].mbi; !done && (i < BT_MBX_SIZE); i++) { - if (bt->bt_mbx.mbi[i].stat != BT_MBI_FREE) { - found_one++; - for (j = BT_MBX_SIZE - 1; j >= 0; j--) - if (bt_ccb_lut[unit][j].phys_addr == - bt->bt_mbx.mbi[i].ccb_addr) { - ccb = bt_ccb_lut[unit][j]. - kv_addr; - break; - } - if ((bt_debug & BT_SHOWCCBS) && ccb) - printf(" ", ccb, KVTOPHYS(ccb)); - if ((stat = bt->bt_mbx.mbi[i].stat) != BT_MBI_OK) { - switch (stat) { - case BT_MBI_ABORT: - if (bt_debug & BT_SHOWMISC) - printf("abort "); - ccb->host_stat = BT_ABORTED; - break; - case BT_MBI_UNKNOWN: - ccb = (struct bt_ccb *) 0; - if (bt_debug & BT_SHOWMISC) - printf("unknown ccb for abort"); - break; - case BT_MBI_ERROR: - break; - default: - printf("bad mbxi status %d, in mbx at 0x%x (0x%x)\n", - stat, &bt->bt_mbx.mbi[i], - KVTOPHYS(&bt->bt_mbx.mbi[i])); - Debugger(); - } - if ((bt_debug & BT_SHOWCMDS) && ccb) { - u_char *cp; - cp = ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi[%d]\n", - bt->bt_mbx.mbi[i].stat, i); - printf("addr = 0x%x\n", ccb); - } + wmbx = &bt->bt_mbx; + wmbi = wmbx->tmbi; + AGAIN: + while (wmbi->stat != BT_MBI_FREE) { + ccb = bt_ccb_phys_kv(bt, (wmbi->ccb_addr)); + if (!ccb) { + wmbi->stat = BT_MBI_FREE; + printf("bt: BAD CCB ADDR!\n"); + continue; + } + found++; + if ((stat = wmbi->stat) != BT_MBI_OK) { + switch (stat) { + case BT_MBI_ABORT: +#ifdef UTEST + if (bt_debug & BT_SHOWMISC) + printf("abort "); +#endif + ccb->host_stat = BT_ABORTED; + break; + + case BT_MBI_UNKNOWN: + ccb = (struct bt_ccb *) 0; +#ifdef UTEST + if (bt_debug & BT_SHOWMISC) + printf("unknown ccb for abort"); +#endif + break; + + case BT_MBI_ERROR: + break; + + default: + panic("Impossible mbxi status"); + } - if (ccb) { - bt_remove_timeout(ccb); - bt_done(unit, ccb); +#ifdef UTEST + if ((bt_debug & BT_SHOWCMDS) && ccb) { + u_char *cp; + cp = ccb->scsi_cmd; + printf("op=%x %x %x %x %x %x\n", + cp[0], cp[1], cp[2], + cp[3], cp[4], cp[5]); + printf("stat %x for mbi addr = 0x%08x\n" + ,wmbi->stat, wmbi); + printf("addr = 0x%x\n", ccb); } - bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; +#endif + } + wmbi->stat = BT_MBI_FREE; + if (ccb) { + untimeout(bt_timeout, (caddr_t)ccb); + bt_done(bt, ccb); + } + /* Set the IN mail Box pointer for next */ bt_nextmbx(wmbi, wmbx, mbi); + } + if (!found) { + for (i = 0; i < BT_MBX_SIZE; i++) { + if (wmbi->stat != BT_MBI_FREE) { + found++; + break; + } + bt_nextmbx(wmbi, wmbx, mbi); + } + if (!found) { + printf("%s: mbi at 0x%08x should be found, stat=%02x..resync\n", + bt->sc_dev.dv_xname, wmbi, stat); } else { - /* free mailbox -- done if following a used mbi */ - if (found_one) - done++; + found = 0; + goto AGAIN; } } - if (done) { - bt_last[unit].mbi = i % BT_MBX_SIZE; - return (1); - } - for (i = 0; !done && (i < bt_last[unit].mbi); i++) { - if (bt->bt_mbx.mbi[i].stat != BT_MBI_FREE) { - found_one++; - for (j = BT_MBX_SIZE - 1; j >= 0; j--) - if (bt_ccb_lut[unit][j].phys_addr == - bt->bt_mbx.mbi[i].ccb_addr) { - ccb = bt_ccb_lut[unit][j]. - kv_addr; - break; - } - if ((bt_debug & BT_SHOWCCBS) && ccb) - printf(" ", ccb, KVTOPHYS(ccb)); - if ((stat = bt->bt_mbx.mbi[i].stat) != BT_MBI_OK) { - switch (stat) { - case BT_MBI_ABORT: - if (bt_debug & BT_SHOWMISC) - printf("abort "); - ccb->host_stat = BT_ABORTED; - break; - case BT_MBI_UNKNOWN: - ccb = (struct bt_ccb *) 0; - if (bt_debug & BT_SHOWMISC) - printf("unknown ccb for abort"); - break; - case BT_MBI_ERROR: - break; - default: - printf("bad mbxi status %d, in mbx at 0x%x (0x%x)\n", - stat, &bt->bt_mbx.mbi[i], - KVTOPHYS(&bt->bt_mbx.mbi[i])); - Debugger(); - } - if ((bt_debug & BT_SHOWCMDS) && ccb) { - u_char *cp; - cp = ccb->scsi_cmd; - printf("op=%x %x %x %x %x %x\n", - cp[0], cp[1], cp[2], - cp[3], cp[4], cp[5]); - printf("stat %x for mbi[%d]\n", - bt->bt_mbx.mbi[i].stat, i); - printf("addr = 0x%x\n", ccb); - } - } - if (ccb) { - bt_remove_timeout(ccb); - bt_done(unit, ccb); - } - bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; - } else { - /* free mailbox -- done if following a used mbi */ - if (found_one) - done++; - } - } - bt_last[unit].mbi = i % BT_MBX_SIZE; - return (1); + wmbx->tmbi = wmbi; + outb(BT_CTRL_STAT_PORT, BT_IRST); + return 1; } /* - * A ccb (and hence a mbx-out is put onto the - * free list. + * A ccb is put onto the free list. */ -bt_free_ccb(unit, ccb, flags) +void +bt_free_ccb(bt, ccb, flags) + struct bt_softc *bt; struct bt_ccb *ccb; + int flags; { - unsigned int opri; - struct bt_data *bt = btdata[unit]; + int opri; - if (scsi_debug & PRINTROUTINES) - printf("ccb%d(0x%x)> ", unit, flags); if (!(flags & SCSI_NOMASK)) opri = splbio(); + ccb->next = bt->bt_ccb_free; + bt->bt_ccb_free = ccb; ccb->flags = CCB_FREE; /* - * If there were none, wake abybody waiting for - * one to come free, starting with queued entries + * If there were none, wake anybody waiting for one to come free, + * starting with queued entries. */ - if (bt->sleepers) { - bt->sleepers = 0; - wakeup((caddr_t) & bt->sleepers); - } + if (!ccb->next) + wakeup((caddr_t)&bt->bt_ccb_free); + if (!(flags & SCSI_NOMASK)) splx(opri); } /* - * Get a free ccb (and hence mbox-out entry) + * Get a free ccb + * + * If there are none, see if we can allocate a new one. If so, put it in + * the hash table too otherwise either return an error or sleep. */ struct bt_ccb * -bt_get_ccb(unit, flags) +bt_get_ccb(bt, flags) + struct bt_softc *bt; + int flags; { - unsigned int opri; - struct bt_ccb *rc = NULL; - struct bt_data *bt = btdata[unit]; - int next_mbx = bt_last[unit].mbo; + int opri; + struct bt_ccb *ccbp; + struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ + BT_MBO *wmbo; /* Out Mail Box pointer */ + int hashnum; - if (scsi_debug & PRINTROUTINES) - printf("bt_ccb[next_mbx].flags == CCB_FREE) && - !(flags & SCSI_NOSLEEP)) { - bt->sleepers = 1; - sleep((caddr_t) & bt->sleepers, PRIBIO); + while (!(ccbp = bt->bt_ccb_free)) { + if (bt->numccbs < BT_CCB_MAX) { + if (ccbp = (struct bt_ccb *) malloc(sizeof(struct bt_ccb), + M_TEMP, + M_NOWAIT)) { + bzero(ccbp, sizeof(struct bt_ccb)); + bt->numccbs++; + ccbp->flags = CCB_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + ccbp->hashkey = KVTOPHYS(ccbp); + hashnum = CCB_HASH(ccbp->hashkey); + ccbp->nexthash = bt->ccbhash[hashnum]; + bt->ccbhash[hashnum] = ccbp; + } else { + printf("%s: Can't malloc CCB\n", + bt->sc_dev.dv_xname); + } + goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) { + tsleep((caddr_t)&bt->bt_ccb_free, PRIBIO, + "btccb", 0); + } + } } - if (bt->bt_ccb[next_mbx].flags == CCB_FREE) { - rc = &bt->bt_ccb[next_mbx]; - bt_last[unit].mbo = (bt_last[unit].mbo + 1) % BT_MBX_SIZE; - rc->flags = CCB_ACTIVE; + if (ccbp) { + /* Get CCB from from free list */ + bt->bt_ccb_free = ccbp->next; + ccbp->flags = CCB_ACTIVE; } + gottit: + if (!(flags & SCSI_NOMASK)) + splx(opri); + + return ccbp; +} + +/* + * given a physical address, find the ccb that + * it corresponds to: + */ +struct bt_ccb * +bt_ccb_phys_kv(bt, ccb_phys) + struct bt_softc *bt; + physaddr ccb_phys; +{ + int hashnum = CCB_HASH(ccb_phys); + struct bt_ccb *ccbp = bt->ccbhash[hashnum]; + + while (ccbp) { + if (ccbp->hashkey == ccb_phys) + break; + ccbp = ccbp->nexthash; + } + return ccbp; +} + +/* + * Get a MBO and then Send it + */ +BT_MBO * +bt_send_mbo(bt, flags, cmd, ccb) + struct bt_softc *bt; + int flags, cmd; + struct bt_ccb *ccb; +{ + int opri; + BT_MBO *wmbo; /* Mail Box Out pointer */ + struct bt_mbx *wmbx; /* Mail Box pointer specified unit */ + int i, wait; + + wmbx = &bt->bt_mbx; + + if (!(flags & SCSI_NOMASK)) + opri = splbio(); + + /* Get the Target OUT mail Box pointer and move to Next */ + wmbo = wmbx->tmbo; + wmbx->tmbo = (wmbo == &(wmbx->mbo[BT_MBX_SIZE - 1]) ? + &(wmbx->mbo[0]) : wmbo + 1); + + /* + * Check the outmail box is free or not. + * Note: Under the normal operation, it shuld NOT happen to wait. + */ + while (wmbo->cmd != BT_MBO_FREE) { + wait = 100000; /* 1 sec enough? */ + /* Enable MBO available interrupt */ + outb(BT_CMD_DATA_PORT, BT_MBO_INTR_EN); + for (i = wait; i; i--) { + if (!(inb(BT_CTRL_STAT_PORT) & BT_CDF)) + break; + delay(10); + } + if (!i) { + printf("%s: bt_send_mbo, cmd/data port full\n", + bt->sc_dev.dv_xname); + outb(BT_CTRL_STAT_PORT, BT_SRST); + return NULL; + } + outb(BT_CMD_DATA_PORT, 0x01); /* Enable */ + tsleep((caddr_t)wmbx, PRIBIO, "btsnd", 0);/*XXX can't do this */ + /* May be servicing an int */ + } + /* Link CCB to the Mail Box */ + wmbo->ccb_addr = KVTOPHYS(ccb); + ccb->mbx = wmbo; + wmbo->cmd = cmd; + + /* Send it! */ + outb(BT_CMD_DATA_PORT, BT_START_SCSI); + if (!(flags & SCSI_NOMASK)) splx(opri); - return (rc); + + return wmbo; } /* @@ -752,21 +950,20 @@ bt_get_ccb(unit, flags) * adaptor, now we look to see how the operation * went. Wake up the owner if waiting */ -bt_done(unit, ccb) +void +bt_done(bt, ccb) + struct bt_softc *bt; struct bt_ccb *ccb; { struct scsi_sense_data *s1, *s2; struct scsi_xfer *xs = ccb->xfer; - struct bt_data *bt = btdata[unit]; - if (scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("bt_done "); + SC_DEBUG(xs->sc_link, SDEV_DB2, ("bt_done\n")); /* * Otherwise, put the results of the operation * into the xfer and call whoever started it */ - if ((ccb->host_stat != BT_OK - || ccb->target_stat != SCSI_OK) + if ((ccb->host_stat != BT_OK || ccb->target_stat != SCSI_OK) && (!(xs->flags & SCSI_ERR_OK))) { s1 = &(ccb->scsi_sense); @@ -776,19 +973,16 @@ bt_done(unit, ccb) switch (ccb->host_stat) { case BT_ABORTED: /* No response */ case BT_SEL_TIMEOUT: /* No response */ - if (bt_debug & BT_SHOWMISC) { - printf("timeout reported back\n"); - } + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("timeout reported back\n")); xs->error = XS_TIMEOUT; break; default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; - if (bt_debug & BT_SHOWMISC) { - printf("unexpected host_stat: %x\n", - ccb->host_stat); - } + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected host_stat: %x\n", + ccb->host_stat)); } - } else { switch (ccb->target_stat) { case 0x02: @@ -799,10 +993,9 @@ bt_done(unit, ccb) xs->error = XS_BUSY; break; default: - if (bt_debug & BT_SHOWMISC) { - printf("unexpected target_stat: %x\n", - ccb->target_stat); - } + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected target_stat: %x\n", + ccb->target_stat)); xs->error = XS_DRIVER_STUFFUP; } } @@ -810,201 +1003,218 @@ bt_done(unit, ccb) xs->resid = 0; } xs->flags |= ITSDONE; - bt_free_ccb(unit, ccb, xs->flags); - if (xs->when_done) - (*(xs->when_done)) (xs->done_arg, xs->done_arg2); + bt_free_ccb(bt, ccb, xs->flags); + scsi_done(xs); +} + +/* + * Find the board and find it's irq/drq + */ +int +bt_find(bt) + struct bt_softc *bt; +{ + u_char ad[4]; + volatile int i, sts; + struct bt_config conf; + + /* + * reset board, If it doesn't respond, assume + * that it's not there.. good for the probe + */ + + outb(BT_CTRL_STAT_PORT, BT_HRST | BT_SRST); + + for (i = BT_RESET_TIMEOUT; i; i--) { + sts = inb(BT_CTRL_STAT_PORT); + if (sts == (BT_IDLE | BT_INIT)) + break; + delay(1000); + } + if (!i) { +#ifdef UTEST + printf("bt_find: No answer from bt742a board\n"); +#endif + return ENXIO; + } + + /* + * Assume we have a board at this stage setup dma channel from + * jumpers and save int level + */ + delay(1000); + bt_cmd(bt, 0, sizeof(conf), 0, &conf, BT_CONF_GET); + switch (conf.chan) { + case EISADMA: + bt->bt_dma = -1; + break; + case CHAN0: + outb(0x0b, 0x0c); + outb(0x0a, 0x00); + bt->bt_dma = 0; + break; + case CHAN5: + outb(0xd6, 0xc1); + outb(0xd4, 0x01); + bt->bt_dma = 5; + break; + case CHAN6: + outb(0xd6, 0xc2); + outb(0xd4, 0x02); + bt->bt_dma = 6; + break; + case CHAN7: + outb(0xd6, 0xc3); + outb(0xd4, 0x03); + bt->bt_dma = 7; + break; + default: + printf("illegal dma setting %x\n", conf.chan); + return EIO; + } + + switch (conf.intr) { + case INT9: + bt->bt_int = 9; + break; + case INT10: + bt->bt_int = 10; + break; + case INT11: + bt->bt_int = 11; + break; + case INT12: + bt->bt_int = 12; + break; + case INT14: + bt->bt_int = 14; + break; + case INT15: + bt->bt_int = 15; + break; + default: + printf("illegal int setting %x\n", conf.intr); + return EIO; + } + + /* who are we on the scsi bus? */ + bt->bt_scsi_dev = conf.scsi_dev; + + return 0; } /* * Start the board, ready for normal operation */ -bt_init(unit) - int unit; +void +bt_init(bt) + struct bt_softc *bt; { - unsigned char ad[4]; - volatile int i, sts; - struct bt_config conf; - struct bt_data *bt; + u_char ad[4]; + volatile int i; /* - * reset board, If it doesn't respond, assume - * that it's not there.. good for the probe - */ - outb(BT_CTRL_STAT_PORT, BT_HRST | BT_SRST); - - for (i = 0; i < BT_RESET_TIMEOUT; i++) { - sts = inb(BT_CTRL_STAT_PORT); - if (sts == (BT_IDLE | BT_INIT)) - break; - } - if (i >= BT_RESET_TIMEOUT) { - if (bt_debug & BT_SHOWMISC) - printf("bt_init: No answer from bt742a board\n"); - return (ENXIO); - } - - /* - * Assume we have a board at this stage - * setup dma channel from jumpers and save int - * level - */ - delay(200); - - bt_cmd(unit, 0, sizeof(conf), 0, &conf, BT_CONF_GET); - switch (conf.chan) { - case EISADMA: - bt_dma[unit] = -1; - break; - case CHAN0: - outb(0x0b, 0x0c); - outb(0x0a, 0x00); - bt_dma[unit] = 0; - break; - case CHAN5: - outb(0xd6, 0xc1); - outb(0xd4, 0x01); - bt_dma[unit] = 5; - break; - case CHAN6: - outb(0xd6, 0xc2); - outb(0xd4, 0x02); - bt_dma[unit] = 6; - break; - case CHAN7: - outb(0xd6, 0xc3); - outb(0xd4, 0x03); - bt_dma[unit] = 7; - break; - default: - printf("illegal dma setting %x\n", conf.chan); - return (EIO); - } - switch (conf.intr) { - case INT9: - bt_int[unit] = 9; - break; - case INT10: - bt_int[unit] = 10; - break; - case INT11: - bt_int[unit] = 11; - break; - case INT12: - bt_int[unit] = 12; - break; - case INT14: - bt_int[unit] = 14; - break; - case INT15: - bt_int[unit] = 15; - break; - default: - printf("illegal int setting\n"); - return (EIO); - } - /* who are we on the scsi bus */ - bt_switch[unit].scsi_dev = conf.scsi_dev; - - printf("bt%d: mbx (%d@) %d, ccb %d * %d, xs %d, bt %d bytes\n", unit, - BT_MBX_SIZE, sizeof(struct bt_mbx), - BT_MBX_SIZE, sizeof(struct bt_ccb), - sizeof(struct scsi_xfer), sizeof(struct bt_data)); - bt = malloc(sizeof(struct bt_data), M_DEVBUF, M_NOWAIT); - if (!bt) { - printf("bt%d: cannot malloc buffers\n", unit); - return (0); - } - if (bt_debug) - printf("bt%d: buffer allocated at 0x%x (0x%x)\n", - unit, bt, KVTOPHYS(bt)); - bzero(bt, sizeof(struct bt_data)); - btdata[unit] = bt; - - /* - * Initialize mail box + * Initialize mail box */ *((physaddr *) ad) = KVTOPHYS(&bt->bt_mbx); - if (bt_debug) { - printf("bt%d: mailbox struct at 0x%x (0x%x)\n", - unit, &bt->bt_mbx, *(physaddr *) ad); - printf("bt%d: ccb struct at 0x%x (0x%x)\n", - unit, bt->bt_ccb, KVTOPHYS(bt->bt_ccb)); - printf("bt%d: xs struct at 0x%x (0x%x)\n", - unit, &bt->bt_scsi_xfer, KVTOPHYS(&bt->bt_scsi_xfer)); - printf("bt%d: sleepers at 0x%x (0x%x)\n", - unit, &bt->sleepers, KVTOPHYS(&bt->sleepers)); - } - bt_cmd(unit, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED, BT_MBX_SIZE, - ad[0], ad[1], ad[2], ad[3]); + + bt_cmd(bt, 5, 0, 0, 0, BT_MBX_INIT_EXTENDED, + BT_MBX_SIZE, ad[0], ad[1], ad[2], ad[3]); /* - * link the ccb's with the mbox-out entries and - * into a free-list + * Set Pointer chain null for just in case + * Link the ccb's into a free-list W/O mbox + * Initialize mail box status to free */ - bt_last[unit].mbo = bt_last[unit].mbi = 0; - for (i = 0; i < (BT_MBX_SIZE - 1); i++) { - bt->bt_ccb[i].next = &bt->bt_ccb[i + 1]; - bt->bt_ccb[i].flags = CCB_FREE; - bt->bt_ccb[i].mbx = &bt->bt_mbx.mbo[i]; - bt->bt_mbx.mbo[i].ccb_addr = KVTOPHYS(&bt->bt_ccb[i]); - bt_ccb_lut[unit][i].kv_addr = &bt->bt_ccb[i]; - bt_ccb_lut[unit][i].phys_addr = - bt->bt_mbx.mbo[i].ccb_addr; + if (bt->bt_ccb_free) { + printf("%s: bt_ccb_free is NOT initialized but init here\n", + bt->sc_dev.dv_xname); + bt->bt_ccb_free = NULL; + } + for (i = 0; i < BT_MBX_SIZE; i++) { + bt->bt_mbx.mbo[i].cmd = BT_MBO_FREE; + bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; } - bt->bt_ccb[i].next = &bt->bt_ccb[0]; /* loop around to first ccb */ - bt->bt_ccb[i].flags = CCB_FREE; - bt->bt_ccb[i].mbx = &bt->bt_mbx.mbo[i]; - bt->bt_mbx.mbo[i].ccb_addr = KVTOPHYS(&bt->bt_ccb[i]); - bt_ccb_lut[unit][i].kv_addr = &bt->bt_ccb[i]; - bt_ccb_lut[unit][i].phys_addr = - bt->bt_mbx.mbo[i].ccb_addr; /* - * Note that we are going and return (to probe) + * Set up initial mail box for round-robin operation. */ - bt_initialized[unit]++; - return (0); + bt->bt_mbx.tmbo = &bt->bt_mbx.mbo[0]; + bt->bt_mbx.tmbi = &bt->bt_mbx.mbi[0]; + bt_inquire_setup_information(bt); + + /* Enable round-robin scheme - appeared at firmware rev. 3.31 */ + bt_cmd(bt, 1, 0, 0, 0, BT_ROUND_ROBIN, BT_ENABLE); } - -#ifndef min -#define min(x,y) (x < y ? x : y) -#endif /* min */ - void +bt_inquire_setup_information(bt) + struct bt_softc *bt; +{ + struct bt_setup setup; + struct bt_boardID bID; + int i; + + /* Inquire Board ID to Bt742 for firmware version */ + bt_cmd(bt, 0, sizeof(bID), 0, &bID, BT_INQUIRE); + printf(": version %c.%c, ", bt->sc_dev.dv_xname, + bID.firm_revision, bID.firm_version); + + /* Obtain setup information from Bt742. */ + bt_cmd(bt, 1, sizeof(setup), 0, &setup, BT_SETUP_GET, sizeof(setup)); + + if (setup.sync_neg) + printf("sync, "); + else + printf("async, "); + if (setup.parity) + printf("parity, "); + else + printf("no parity, "); + printf("%d mbxs", setup.num_mbx); + + for (i = 0; i < 8; i++) { + if (!setup.sync[i].offset && + !setup.sync[i].period && + !setup.sync[i].valid) + continue; + + printf("%s: dev%02d Offset=%d, Transfer period=%d, Synchronous? %s", + bt->sc_dev.dv_xname, i, + setup.sync[i].offset, setup.sync[i].period, + setup.sync[i].valid ? "Yes" : "No"); + } +} + +void btminphys(bp) struct buf *bp; { - if (bp->b_bcount > ((BT_NSEG - 1) * PAGESIZ)) { - bp->b_bcount = ((BT_NSEG - 1) * PAGESIZ); - } + + if (bp->b_bcount > ((BT_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((BT_NSEG - 1) << PGSHIFT); } /* - * start a scsi operation given the command and the - * data address. Also needs the unit, target and lu + * start a scsi operation given the command and the data address. Also needs + * the unit, target and lu. */ -int +int bt_scsi_cmd(xs) struct scsi_xfer *xs; { - struct scsi_sense_data *s1, *s2; + struct scsi_link *sc_link = xs->sc_link; + struct bt_softc *bt = sc_link->adapter_softc; struct bt_ccb *ccb; struct bt_scat_gath *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; + int seg; /* scatter gather seg being worked on */ + int thiskv; physaddr thisphys, nextphys; - int unit = xs->adapter; - int bytes_this_seg, bytes_this_page, datalen, flags; + int bytes_this_seg, bytes_this_page, datalen, flags; struct iovec *iovp; - struct bt_data *bt = btdata[unit]; - int done, count; - - if (scsi_debug & PRINTROUTINES) - printf("bt_scsi_cmd "); + BT_MBO *mbo; + SC_DEBUG(sc_link, SDEV_DB2, ("bt_scsi_cmd\n")); /* * get a ccb (mbox-out) to use. If the transfer * is from a buf (possibly from interrupt time) @@ -1014,23 +1224,19 @@ bt_scsi_cmd(xs) if (xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ if (flags & ITSDONE) { - printf("Already done?"); + printf("%s: Already done?\n", bt->sc_dev.dv_xname); xs->flags &= ~ITSDONE; } if (!(flags & INUSE)) { - printf("Not in use?"); + printf("%s: Not in use?\n", bt->sc_dev.dv_xname); xs->flags |= INUSE; } - if (!(ccb = bt_get_ccb(unit, flags))) { + if (!(ccb = bt_get_ccb(bt, flags))) { xs->error = XS_DRIVER_STUFFUP; - return (TRY_AGAIN_LATER); + return TRY_AGAIN_LATER; } - if (bt_debug & BT_SHOWCCBS) - printf("", ccb, KVTOPHYS(ccb)); - if (ccb->mbx->cmd != BT_MBO_FREE) - printf("MBO not free (%x(%x))\n", - ccb->mbx, KVTOPHYS(ccb->mbx)); - + SC_DEBUG(sc_link, SDEV_DB3, + ("start ccb(%x)\n", ccb)); /* * Put all the arguments for the xfer in the ccb */ @@ -1039,44 +1245,45 @@ bt_scsi_cmd(xs) ccb->opcode = BT_RESET_CCB; } else { /* can't use S/G if zero length */ - ccb->opcode = (xs->datalen ? BT_INIT_SCAT_GATH_CCB : - BT_INITIATOR_CCB); + ccb->opcode = (xs->datalen ? BT_INIT_SCAT_GATH_CCB + : BT_INITIATOR_CCB); } - ccb->target = xs->targ;; + ccb->target = sc_link->target; ccb->data_out = 0; ccb->data_in = 0; - ccb->lun = xs->lu; + ccb->lun = sc_link->lun; ccb->scsi_cmd_length = xs->cmdlen; ccb->sense_ptr = KVTOPHYS(&(ccb->scsi_sense)); ccb->req_sense_length = sizeof(ccb->scsi_sense); if ((xs->datalen) && (!(flags & SCSI_RESET))) { - /* can use S/G only if not zero length */ ccb->data_addr = KVTOPHYS(ccb->scat_gath); sg = ccb->scat_gath; seg = 0; +#ifdef TFS if (flags & SCSI_DATA_UIO) { iovp = ((struct uio *) xs->data)->uio_iov; datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while (datalen && (seg < BT_NSEG)) { + while ((datalen) && (seg < BT_NSEG)) { sg->seg_addr = (physaddr) iovp->iov_base; xs->datalen += sg->seg_len = iovp->iov_len; - if (scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)", - iovp->iov_len, - iovp->iov_base); + SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } else { + } else +#endif /* TFS */ + { /* * Set up the scatter gather block */ - if (scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ", xs->datalen, xs->data); + + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); datalen = xs->datalen; thiskv = (int) xs->data; thisphys = KVTOPHYS(thiskv); @@ -1087,56 +1294,55 @@ bt_scsi_cmd(xs) /* put in the base address */ sg->seg_addr = thisphys; - if (scsi_debug & SHOWSCATGATH) - printf("0x%x", thisphys); + SC_DEBUGN(sc_link, SDEV_DB4, + ("0x%x", thisphys)); /* do it at least once */ nextphys = thisphys; while ((datalen) && (thisphys == nextphys)) { /* - * This page is contiguous (physically) with - * the the last, just extend the length - * how far to the end of the page + * This page is contiguous (physically) + * with the the last, just extend the + * length */ - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; + /* how far to the end of the page */ + nextphys = (thisphys & ~PGOFSET) + NBPG; bytes_this_page = nextphys - thisphys; /**** or the data ****/ bytes_this_page = min(bytes_this_page, - datalen); + datalen); bytes_this_seg += bytes_this_page; datalen -= bytes_this_page; /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; + thiskv = (thiskv & ~PGOFSET) + NBPG; if (datalen) thisphys = KVTOPHYS(thiskv); } - /* * next page isn't contiguous, finish the seg */ - if (scsi_debug & SHOWSCATGATH) - printf("(0x%x)", bytes_this_seg); + SC_DEBUGN(sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); sg->seg_len = bytes_this_seg; sg++; seg++; } - } /* end of iov/kv decision */ - ccb->data_length = seg * sizeof(struct bt_scat_gath); - if (scsi_debug & SHOWSCATGATH) - printf("\n"); - if (datalen) { - /* there's still data, must have run out of segs! */ - printf("bt_scsi_cmd%d: more than %d DMA segs\n", - unit, BT_NSEG); - xs->error = XS_DRIVER_STUFFUP; - bt_free_ccb(unit, ccb, flags); - return (HAD_ERROR); } - } else { - /* No data xfer, use non S/G values */ + /* end of iov/kv decision */ + ccb->data_length = seg * sizeof(struct bt_scat_gath); + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); + if (datalen) { + /* + * there's still data, must have run out of segs! + */ + printf("%s: bt_scsi_cmd, more than %d DMA segs\n", + bt->sc_dev.dv_xname, BT_NSEG); + xs->error = XS_DRIVER_STUFFUP; + bt_free_ccb(bt, ccb, flags); + return HAD_ERROR; + } + } else { /* No data xfer, use non S/G values */ ccb->data_addr = (physaddr) 0; ccb->data_length = 0; } @@ -1146,270 +1352,168 @@ bt_scsi_cmd(xs) /* * Put the scsi command in the ccb and start it */ - if (!(flags & SCSI_RESET)) { + if (!(flags & SCSI_RESET)) bcopy(xs->cmd, ccb->scsi_cmd, ccb->scsi_cmd_length); + if (bt_send_mbo(bt, flags, BT_MBO_START, ccb) == (BT_MBO *) 0) { + xs->error = XS_DRIVER_STUFFUP; + bt_free_ccb(bt, ccb, flags); + return TRY_AGAIN_LATER; } - if (scsi_debug & SHOWCOMMANDS) { - u_char *b = ccb->scsi_cmd; - if (!(flags & SCSI_RESET)) { - int i = 0; - printf("bt%d:%d:%d-", unit, ccb->target, ccb->lun); - while (i < ccb->scsi_cmd_length) { - if (i) - printf(","); - printf("%x", b[i++]); - } - printf("-\n"); - } else - printf("bt%d:%d:%d-RESET- ", unit, ccb->target, ccb->lun); - } - bt_startmbx(ccb->mbx); /* * Usually return SUCCESSFULLY QUEUED */ - if (scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); if (!(flags & SCSI_NOMASK)) { - bt_add_timeout(ccb, xs->timeout); - return (SUCCESSFULLY_QUEUED); + timeout(bt_timeout, (caddr_t)ccb, (xs->timeout * hz) / 1000); + return SUCCESSFULLY_QUEUED; } /* * If we can't use interrupts, poll on completion */ - done = 0; - count = delaycount * xs->timeout / BT_SCSI_TIMEOUT_FUDGE; - - if (scsi_debug & TRACEINTERRUPTS) - printf("wait "); - while ((!done) && count) { - i = 0; - while (!done && i < BT_MBX_SIZE) { - struct bt_ccb *mbx_ccb = NULL; - int j; - - for (j = BT_MBX_SIZE - 1; j >= 0; j--) - if (bt_ccb_lut[unit][j].phys_addr == - bt->bt_mbx.mbi[i].ccb_addr) { - mbx_ccb = bt_ccb_lut[unit][j].kv_addr; - break; - } - if ((bt->bt_mbx.mbi[i].stat != BT_MBI_FREE) && - mbx_ccb == ccb) { - bt->bt_mbx.mbi[i].stat = BT_MBI_FREE; - bt_done(unit, ccb); - done++; - } - i++; - } - count--; - } - if (!count) { - if (!(xs->flags & SCSI_SILENT)) - printf("cmd fail\n"); - bt_abortmbx(ccb->mbx); - count = delaycount * 2000 / BT_SCSI_TIMEOUT_FUDGE; - while (!done && count) { - i = 0; - while (!done && i < BT_MBX_SIZE) { - struct bt_ccb *mbx_ccb = NULL; - int j; - - for (j = BT_MBX_SIZE - 1; j >= 0; j--) - if (bt_ccb_lut[unit][j].phys_addr == - bt->bt_mbx.mbi[i].ccb_addr) { - mbx_ccb = bt_ccb_lut[unit][j].kv_addr; - break; - } - if ((bt->bt_mbx.mbi[i].stat != - BT_MBI_FREE) && mbx_ccb == ccb) { - bt->bt_mbx.mbi[i].stat = - BT_MBI_FREE; - bt_done(unit, ccb); - done++; - } - i++; - } - count--; - } - if (!count) { - printf("abort failed in wait\n"); - ccb->mbx->cmd = BT_MBO_FREE; - } - bt_free_ccb(unit, ccb, flags); - btintr(unit); - xs->error = XS_DRIVER_STUFFUP; - return (HAD_ERROR); - } - btintr(unit); - if (xs->error) - return (HAD_ERROR); - return (COMPLETE); + return bt_poll(bt, xs, ccb); } /* - * +----------+ +----------+ +----------+ - * bt_soonest--->| later |---->| later|---->| later|--->0 - * | [Delta] | | [Delta] | | [Delta] | - * 0<-----|sooner |<----|sooner |<----|sooner |<----bt_latest - * +----------+ +----------+ +----------+ - * - * bt_furthest = sum(Delta[1..n]) + * Poll a particular unit, looking for a particular xs */ -bt_add_timeout(ccb, time) - struct bt_ccb *ccb; - int time; -{ - int timeprev; - struct bt_ccb *prev; - int s = splbio(); - - prev = bt_latest; - if (prev) - timeprev = bt_furthest; - else - timeprev = 0; - - while (prev && (timeprev > time)) { - timeprev -= prev->delta; - prev = prev->sooner; - } - if (prev) { - ccb->delta = time - timeprev; - if (ccb->later = prev->later) { /* yes an assign */ - ccb->later->sooner = ccb; - ccb->later->delta -= ccb->delta; - } else { - bt_furthest = time; - bt_latest = ccb; - } - ccb->sooner = prev; - prev->later = ccb; - } else { - if (ccb->later = bt_soonest) { /* yes, an assign */ - ccb->later->sooner = ccb; - ccb->later->delta -= time; - } else { - bt_furthest = time; - bt_latest = ccb; - } - ccb->delta = time; - ccb->sooner = (struct bt_ccb *) 0; - bt_soonest = ccb; - } - splx(s); -} - -bt_remove_timeout(ccb) +int +bt_poll(bt, xs, ccb) + struct bt_softc *bt; + struct scsi_xfer *xs; struct bt_ccb *ccb; { - int s = splbio(); + int done = 0; + int count = xs->timeout; + u_char stat; - if (ccb->sooner) - ccb->sooner->later = ccb->later; - else - bt_soonest = ccb->later; - - if (ccb->later) { - ccb->later->sooner = ccb->sooner; - ccb->later->delta += ccb->delta; - } else { - bt_latest = ccb->sooner; - bt_furthest -= ccb->delta; - } - ccb->sooner = ccb->later = (struct bt_ccb *) 0; - splx(s); -} - - -extern int hz; -/* #define ONETICK 500 /* milliseconds */ -#define ONETICK 250 /* milliseconds */ -#define SLEEPTIME ((hz * 1000) / ONETICK) - -bt_timeout(arg) - int arg; -{ - struct bt_ccb *ccb; - int unit; - int s = splbio(); - - while (ccb = bt_soonest) { - if (ccb->delta <= ONETICK) { - /* - * It has timed out, we need to do some work - */ - unit = ccb->xfer->adapter; - btintr(unit); - printf("bt%d:%d device timed out\n", unit, - ccb->xfer->targ); - if (bt_debug & BT_SHOWCCBS) - tfs_print_active_ccbs(); - - /* - * Unlink it from the queue - */ - bt_remove_timeout(ccb); - - /* - * If The ccb's mbx is not free, then - * the board has gone south - */ - if (ccb->mbx->cmd != BT_MBO_FREE) { - printf("bt%d not taking commands!\n", unit); - printf("bt: ccb->mbx->cmd = %x\n", - ccb->mbx->cmd); - tfs_print_ccb(ccb); - Debugger(); - } - /* - * If it has been through before, then - * a previous abort has failed, don't - * try abort again - */ - if (ccb->flags == CCB_ABORTED) { /* abort timed out */ - printf("AGAIN"); - ccb->xfer->retries = 0; /* I MEAN IT ! */ - ccb->host_stat = BT_ABORTED; - bt_done(unit, ccb); - } else {/* abort the operation that has timed out */ - printf("abort mbx\n"); - bt_abortmbx(ccb->mbx); - /* 2 secs for the abort */ - bt_add_timeout(ccb, 2000 + ONETICK); - ccb->flags = CCB_ABORTED; - } - } else { - /* - * It has not timed out, adjust and leave - */ - ccb->delta -= ONETICK; - bt_furthest -= ONETICK; + /* timeouts are in msec, so we loop in 1000 usec cycles */ + while (count) { + /* + * If we had interrupts enabled, would we + * have got an interrupt? + */ + stat = inb(BT_INTR_PORT); + if (stat & BT_ANY_INTR) + btintr(bt->sc_dev.dv_unit); + if (xs->flags & ITSDONE) break; + delay(1000); /* only happens in boot so ok */ + count--; + } + if (!count) { + /* + * We timed out, so call the timeout handler manually, + * accounting for the fact that the clock is not running yet + * by taking out the clock queue entry it makes. + */ + bt_timeout((caddr_t)ccb); + + /* + * because we are polling, take out the timeout entry + * bt_timeout made + */ + untimeout(bt_timeout, (caddr_t)ccb); + count = 2000; + while (count) { + /* + * Once again, wait for the int bit + */ + stat = inb(BT_INTR_PORT); + if (stat & BT_ANY_INTR) + btintr(bt->sc_dev.dv_unit); + if (xs->flags & ITSDONE) + break; + delay(1000); /* only happens in boot so ok */ + count--; + } + if (!count) { + /* + * We timed out again... This is bad. Notice that + * this time there is no clock queue entry to remove. + */ + bt_timeout((caddr_t)ccb); } } - splx(s); - timeout((timeout_t) bt_timeout, (caddr_t) arg, SLEEPTIME); + if (xs->error) + return HAD_ERROR; + return COMPLETE; } -tfs_print_ccb(ccb) +void +bt_timeout(arg) + caddr_t arg; +{ + int s = splbio(); + struct bt_ccb *ccb = (void *)arg; + struct bt_softc *bt; + + bt = ccb->xfer->sc_link->adapter_softc; + sc_print_addr(ccb->xfer->sc_link); + printf("timed out "); + +#ifdef UTEST + bt_print_active_ccbs(bt); +#endif + + /* + * If the ccb's mbx is not free, then the board has gone Far East? + */ + if (bt_ccb_phys_kv(bt, ccb->mbx->ccb_addr) == ccb && + ccb->mbx->cmd != BT_MBO_FREE) { + printf("%s: not taking commands!\n", bt->sc_dev.dv_xname); + Debugger(); + } + + /* + * If it has been through before, then + * a previous abort has failed, don't + * try abort again + */ + if (ccb->flags == CCB_ABORTED) { + /* abort timed out */ + printf("AGAIN\n"); + ccb->xfer->retries = 0; /* I MEAN IT ! */ + ccb->host_stat = BT_ABORTED; + bt_done(bt, ccb); + } else { /* abort the operation that has timed out */ + printf("\n"); + bt_send_mbo(bt, ~SCSI_NOMASK, BT_MBO_ABORT, ccb); + /* 2 secs for the abort */ + timeout(bt_timeout, (caddr_t)ccb, 2 * hz); + ccb->flags = CCB_ABORTED; + } + splx(s); +} + +#ifdef UTEST +void +bt_print_ccb(ccb) struct bt_ccb *ccb; { - printf("ccb:%x op:%x cmdlen:%d senlen:%d\n", ccb, ccb->opcode, - ccb->scsi_cmd_length, ccb->req_sense_length); - printf(" datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n", - ccb->data_length, ccb->host_stat, ccb->target_stat, - ccb->delta, ccb->flags); + + printf("ccb:%x op:%x cmdlen:%d senlen:%d\n", + ccb, ccb->opcode, ccb->scsi_cmd_length, ccb->req_sense_length); + printf(" datlen:%d hstat:%x tstat:%x flags:%x\n", + ccb->data_length, ccb->host_stat, ccb->target_stat, ccb->flags); } -tfs_print_active_ccbs() +void +bt_print_active_ccbs(bt) + struct bt_softc *bt; { - struct bt_ccb *ccb = bt_soonest; + struct bt_ccb *ccb; + int i = 0; - while (ccb) { - tfs_print_ccb(ccb); - ccb = ccb->later; + while (i < CCB_HASH_SIZE) { + ccb = bt->ccbhash[i]; + while (ccb) { + if (ccb->flags != CCB_FREE) + bt_print_ccb(ccb); + ccb = ccb->nexthash; + } + i++; } - printf("Furthest = %d\n", bt_furthest); } +#endif /*UTEST */ diff --git a/sys/dev/isa/ultra14f.c b/sys/dev/isa/ultra14f.c index 7e314763fc7e..a8dba429d88e 100644 --- a/sys/dev/isa/ultra14f.c +++ b/sys/dev/isa/ultra14f.c @@ -1,8 +1,40 @@ +/* + * Copyright (c) 1994 Charles Hannum. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Charles Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: ultra14f.c,v 1.25 1994/03/29 04:30:26 mycroft Exp $ + */ + /* * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu) + * Slight fixes to timeouts to run with the 34F * Thanks to Julian Elischer for advice and help with this port. * - * Written by Julian Elischer (julian@tfs.com) + * Originally written by Julian Elischer (julian@tfs.com) * for TRW Financial Systems for use under the MACH(2.5) operating system. * * TRW Financial Systems, in accordance with their agreement with Carnegie @@ -15,988 +47,967 @@ * on the understanding that TFS is not responsible for the correct * functioning of this software in any circumstances. * - * $Id: ultra14f.c,v 1.24 1994/03/25 07:40:57 mycroft Exp $ + * commenced: Sun Sep 27 18:14:01 PDT 1992 + * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993 */ - -#include -#include +#include #include #include +#include #include #include +#include +#include #include #include #include -#ifdef MACH /* EITHER CMU OR OSF */ -#include -#include -#include - -#ifdef OSF /* OSF ONLY */ -#include -#include -#include -#include - -#else OSF /* CMU ONLY */ -#include -#include -#endif OSF -#endif MACH /* end of MACH specific */ - -#ifdef __NetBSD__ /* NetBSD specific */ -#include #include -#include + +#include +#include + #include #include -#endif __NetBSD__ - -/* */ #ifdef DDB -int Debugger(); -#else DDB -#define Debugger() panic("should call debugger here") +int Debugger(); +#else /* DDB */ +#define Debugger() #endif /* DDB */ -#ifdef MACH -int Debugger(); -#endif MACH +typedef struct { + u_char addr[4]; +} physaddr; +typedef struct { + u_char len[4]; +} physlen; -typedef struct {unsigned char addr[4]; } physaddr; -typedef struct {unsigned char len[4]; } physlen; +#define KVTOPHYS(x) vtophys(x) +#define UHA_MSCP_MAX 32 /* store up to 32MSCPs at any one time + * MAX = ? + */ +#define MSCP_HASH_SIZE 32 /* when we have a physical addr. for + * a mscp and need to find the mscp in + * space, look it up in the hash table + */ +#define MSCP_HASH_SHIFT 9 /* only hash on multiples of 512 */ +#define MSCP_HASH(x) ((((long)(x))>>MSCP_HASH_SHIFT) % MSCP_HASH_SIZE) -#ifdef MACH -extern physaddr kvtophys(); -#define PHYSTOKV(x) phystokv(x) -#define KVTOPHYS(x) kvtophys(x) -#endif MACH +#define UHA_NSEG 33 /* number of dma segments supported */ -#ifdef __NetBSD__ -#define PHYSTOKV(x) ((x) + KERNBASE) -#define KVTOPHYS(x) vtophys(x) -#endif __NetBSD__ - -extern int delaycount; /* from clock setup code */ -#define NUM_CONCURRENT 16 /* number of concurrent ops per board */ -#define UHA_NSEG 33 /* number of dma segments supported */ -#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */ -/* */ /************************** board definitions *******************************/ /* * I/O Port Interface -*/ - #define UHA_LMASK (0x000) /* local doorbell mask reg */ - #define UHA_LINT (0x001) /* local doorbell int/stat reg */ - #define UHA_SMASK (0x002) /* system doorbell mask reg */ - #define UHA_SINT (0x003) /* system doorbell int/stat reg */ - #define UHA_ID0 (0x004) /* product id reg 0 */ - #define UHA_ID1 (0x005) /* product id reg 1 */ - #define UHA_CONF1 (0x006) /* config reg 1 */ - #define UHA_CONF2 (0x007) /* config reg 2 */ - #define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */ - #define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */ - #define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */ - #define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */ - #define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */ - #define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */ - #define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */ - #define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */ - - /* -* UHA_LMASK bits (read only) -*/ - -#define UHA_LDIE 0x80 /* local doorbell int enabled */ -#define UHA_SRSTE 0x40 /* soft reset enabled */ -#define UHA_ABORTEN 0x10 /* abort MSCP enabled */ -#define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */ + */ +#define UHA_LMASK (0x000) /* local doorbell mask reg */ +#define UHA_LINT (0x001) /* local doorbell int/stat reg */ +#define UHA_SMASK (0x002) /* system doorbell mask reg */ +#define UHA_SINT (0x003) /* system doorbell int/stat reg */ +#define UHA_ID0 (0x004) /* product id reg 0 */ +#define UHA_ID1 (0x005) /* product id reg 1 */ +#define UHA_CONF1 (0x006) /* config reg 1 */ +#define UHA_CONF2 (0x007) /* config reg 2 */ +#define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */ +#define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */ +#define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */ +#define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */ +#define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */ +#define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */ +#define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */ +#define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */ /* -* UHA_LINT bits (read) -*/ - -#define UHA_LDIP 0x80 /* local doorbell int pending */ + * UHA_LMASK bits (read only) + */ +#define UHA_LDIE 0x80 /* local doorbell int enabled */ +#define UHA_SRSTE 0x40 /* soft reset enabled */ +#define UHA_ABORTEN 0x10 /* abort MSCP enabled */ +#define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */ /* -* UHA_LINT bits (write) -*/ - -#define UHA_ADRST 0x40 /* adapter soft reset */ -#define UHA_SBRST 0x20 /* scsi bus reset */ -#define UHA_ASRST 0x60 /* adapter and scsi reset */ -#define UHA_ABORT 0x10 /* abort MSCP */ -#define UHA_OGMINT 0x01 /* tell adapter to get mail */ + * UHA_LINT bits (read) + */ +#define UHA_LDIP 0x80 /* local doorbell int pending */ /* -* UHA_SMASK bits (read) -*/ - -#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */ -#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */ -#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled + * UHA_LINT bits (write) + */ +#define UHA_ADRST 0x40 /* adapter soft reset */ +#define UHA_SBRST 0x20 /* scsi bus reset */ +#define UHA_ASRST 0x60 /* adapter and scsi reset */ +#define UHA_ABORT 0x10 /* abort MSCP */ +#define UHA_OGMINT 0x01 /* tell adapter to get mail */ /* -* UHA_SMASK bits (write) -*/ - -#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */ -#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */ -#define UHA_ENICM 0x01 /* enable ICM interrupt */ + * UHA_SMASK bits (read) + */ +#define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */ +#define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */ +#define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled */ /* -* UHA_SINT bits (read) -*/ - -#define UHA_SINTP 0x80 /* system doorbell int pending */ -#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */ -#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */ + * UHA_SMASK bits (write) + */ +#define UHA_ENSINT 0x80 /* enable system doorbell interrupt */ +#define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */ +#define UHA_ENICM 0x01 /* enable ICM interrupt */ /* -* UHA_SINT bits (write) -*/ + * UHA_SINT bits (read) + */ +#define UHA_SINTP 0x80 /* system doorbell int pending */ +#define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */ +#define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */ -#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */ -#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */ +/* + * UHA_SINT bits (write) + */ +#define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */ +#define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */ /* -* UHA_CONF1 bits (read only) -*/ + * UHA_CONF1 bits (read only) + */ +#define UHA_DMA_CH5 0x00 /* DMA channel 5 */ +#define UHA_DMA_CH6 0x40 /* 6 */ +#define UHA_DMA_CH7 0x80 /* 7 */ +#define UHA_IRQ15 0x00 /* IRQ 15 */ +#define UHA_IRQ14 0x10 /* 14 */ +#define UHA_IRQ11 0x20 /* 11 */ +#define UHA_IRQ10 0x30 /* 10 */ -#define UHA_DMA_CH5 0x00 /* DMA channel 5 */ -#define UHA_DMA_CH6 0x40 /* 6 */ -#define UHA_DMA_CH7 0x80 /* 7 */ -#define UHA_IRQ15 0x00 /* IRQ 15 */ -#define UHA_IRQ14 0x10 /* 14 */ -#define UHA_IRQ11 0x20 /* 11 */ -#define UHA_IRQ10 0x30 /* 10 */ +/* + * ha_status error codes + */ +#define UHA_NO_ERR 0x00 /* No error supposedly */ +#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */ +#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */ +#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */ +#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */ +#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */ +#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */ +#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */ -/*********************************** -* ha_status error codes -\***********************************/ - -#define UHA_NO_ERR 0x00 /* No error supposedly */ -#define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */ -#define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */ -#define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */ -#define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */ -#define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */ -#define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */ -#define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */ - -/* */ - -struct uha_dma_seg -{ - physaddr addr; - physlen len; +struct uha_dma_seg { + physaddr addr; + physlen len; }; -/* */ -struct mscp -{ - unsigned char opcode:3; - #define U14_HAC 0x01 /*host adapter command*/ - #define U14_TSP 0x02 /*target scsi pass through command*/ - #define U14_SDR 0x04 /*scsi device reset*/ - unsigned char xdir:2; /*xfer direction*/ - #define U14_SDET 0x00 /*determined by scsi command*/ - #define U14_SDIN 0x01 /*scsi data in*/ - #define U14_SDOUT 0x02 /*scsi data out*/ - #define U14_NODATA 0x03 /*no data xfer*/ - unsigned char dcn:1; /*disable disconnect for this command*/ - unsigned char ca:1; /*Cache control*/ - unsigned char sgth:1; /*scatter gather flag*/ - unsigned char target:3; - unsigned char chan:2; /*scsi channel (always 0 for 14f)*/ - unsigned char lun:3; - physaddr data; - physlen datalen; - physaddr link; - unsigned char link_id; - unsigned char sg_num; /*number of scat gath segs */ - /*in s-g list if sg flag is*/ - /*set. starts at 1, 8bytes per*/ - unsigned char senselen; - unsigned char cdblen; - unsigned char cdb[12]; - unsigned char ha_status; - unsigned char targ_status; - physaddr sense; /* if 0 no auto sense */ +struct mscp { + u_char opcode:3; +#define U14_HAC 0x01 /* host adapter command */ +#define U14_TSP 0x02 /* target scsi pass through command */ +#define U14_SDR 0x04 /* scsi device reset */ + u_char xdir:2; /* xfer direction */ +#define U14_SDET 0x00 /* determined by scsi command */ +#define U14_SDIN 0x01 /* scsi data in */ +#define U14_SDOUT 0x02 /* scsi data out */ +#define U14_NODATA 0x03 /* no data xfer */ + u_char dcn:1; /* disable disconnect for this command */ + u_char ca:1; /* cache control */ + u_char sgth:1; /* scatter gather flag */ + u_char target:3; + u_char chan:2; /* scsi channel (always 0 for 14f) */ + u_char lun:3; + physaddr data; + physlen datalen; + physaddr link; + u_char link_id; + u_char sg_num; /*number of scat gath segs */ + /*in s-g list if sg flag is */ + /*set. starts at 1, 8bytes per */ + u_char senselen; + u_char cdblen; + u_char cdb[12]; + u_char ha_status; + u_char targ_status; + physaddr sense; /* if 0 no auto sense */ /*-----------------end of hardware supported fields----------------*/ - struct mscp *next; /* in free list */ - struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ - long int delta; /* difference from previous*/ - struct mscp *later,*sooner; - int flags; -#define MSCP_FREE 0 -#define MSCP_ACTIVE 1 -#define MSCP_ABORTED 2 - struct uha_dma_seg uha_dma[UHA_NSEG]; - struct scsi_sense_data mscp_sense; + struct mscp *next; /* in free list */ + struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ + int flags; +#define MSCP_FREE 0 +#define MSCP_ACTIVE 1 +#define MSCP_ABORTED 2 + struct uha_dma_seg uha_dma[UHA_NSEG]; + struct scsi_sense_data mscp_sense; + struct mscp *nexthash; + long hashkey; }; -struct mscp *uha_soonest = (struct mscp *)0; -struct mscp *uha_latest = (struct mscp *)0; -long int uha_furtherest = 0; /* longest time in the timeout queue */ -/* */ +struct uha_softc { + struct device sc_dev; + struct isadev sc_id; + struct intrhand sc_ih; -struct uha_data -{ - int flags; -#define UHA_INIT 0x01; - int baseport; - struct mscp mscps[NUM_CONCURRENT]; - struct mscp *free_mscp; - int vect; - int dma; -} uha_data[NUHA]; + u_short sc_iobase; -int uhaprobe(); -int uha_attach(); -int uhaintr(); -int uha_scsi_cmd(); -int uha_timeout(); -int uha_abort(); -struct mscp *cheat; -void uhaminphys(); -long int uha_adapter_info(); + struct mscp *mscphash[MSCP_HASH_SIZE]; + struct mscp *free_mscp; + int our_id; /* our scsi id */ + int vect; + int dma; + int nummscps; + struct scsi_link sc_link; +}; -unsigned long int scratch; +void uha_send_mbox __P((struct uha_softc *, struct mscp *)); +int uha_abort __P((struct uha_softc *, struct mscp *)); +int uha_poll __P((struct uha_softc *, int)); +u_int uha_adapter_info __P((struct uha_softc *)); +int uhaintr __P((int)); +void uha_done __P((struct uha_softc *, struct mscp *)); +void uha_free_mscp __P((struct uha_softc *, struct mscp *, int flags)); +struct mscp *uha_get_mscp __P((struct uha_softc *, int)); +struct mscp *uha_mscp_phys_kv __P((struct uha_softc *, u_long)); +int uha_find __P((struct uha_softc *)); +void uha_init __P((struct uha_softc *)); +void uhaminphys __P((struct buf *)); +int uha_scsi_cmd __P((struct scsi_xfer *)); +void uha_timeout __P((caddr_t)); +#ifdef UHADEBUG +void uha_print_mscp __P((struct mscp *)); +void uha_print_active_mscp __P((struct uha_softc *)); +#endif -#ifdef MACH -struct isa_driver uhadriver = { uhaprobe, 0, uha_attach, "uha", 0, 0, 0}; -int (*uhaintrs[])() = {uhaintr, 0}; -#endif MACH - -#ifdef __NetBSD__ -struct isa_driver uhadriver = { uhaprobe, uha_attach, "uha"}; -#endif __NetBSD__ - -static uha_unit = 0; -int uha_debug = 0; +u_long scratch; #define UHA_SHOWMSCPS 0x01 #define UHA_SHOWINTS 0x02 #define UHA_SHOWCMDS 0x04 #define UHA_SHOWMISC 0x08 -#define FAIL 1 -#define SUCCESS 0 -#define PAGESIZ 4096 -struct scsi_switch uha_switch[NUHA]; +struct scsi_adapter uha_switch = { + uha_scsi_cmd, + uhaminphys, + 0, + 0, + uha_adapter_info, + "uha" +}; -/* */ -/***********************************************************************\ -* Function to send a command out through a mailbox * -\***********************************************************************/ -uha_send_mbox( int unit - ,struct mscp *mscp) +/* the below structure is so we have a default dev struct for out link struct */ +struct scsi_device uha_dev = { + NULL, /* Use default error handler */ + NULL, /* have a queue, served by this */ + NULL, /* have no async handler */ + NULL, /* Use default 'done' routine */ + "uha", + 0 +}; + +int uhaprobe(); +void uhaattach(); + +struct cfdriver uhacd = { + NULL, "uha", uhaprobe, uhaattach, DV_DULL, sizeof(struct uha_softc) +}; + +/* + * Function to send a command out through a mailbox + */ +void +uha_send_mbox(uha, mscp) + struct uha_softc *uha; + struct mscp *mscp; { - int port = uha_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1000; /* 1s should be enough */ - int s = splbio(); - - while( ((inb(port + UHA_LINT) & (UHA_LDIP)) - != (0)) - && (spincount--)); - if(spincount == -1) - { - printf("uha%d: board not responding\n",unit); + u_short iobase = uha->sc_iobase; + int spincount = 100000; /* 1s should be enough */ + int s = splbio(); + + while (--spincount) { + if ((inb(iobase + UHA_LINT) & UHA_LDIP) == 0) + break; + delay(100); + } + if (!spincount) { + printf("%s: uha_send_mbox, board not responding\n", + uha->sc_dev.dv_xname); Debugger(); } - outl(port + UHA_OGM0,KVTOPHYS(mscp)); - outb(port + UHA_LINT, (UHA_OGMINT)); + outl(iobase + UHA_OGM0, KVTOPHYS(mscp)); + outb(iobase + UHA_LINT, UHA_OGMINT); + splx(s); } -/***********************************************************************\ -* Function to send abort to 14f * -\***********************************************************************/ - -uha_abort( int unit - ,struct mscp *mscp) +/* + * Function to send abort to 14f + */ +int +uha_abort(uha, mscp) + struct uha_softc *uha; + struct mscp *mscp; { - int port = uha_data[unit].baseport; - int spincount = FUDGE(delaycount) * 1; - int abortcount = FUDGE(delaycount) * 2000; - int s = splbio(); - - while(((inb(port + UHA_LINT) & (UHA_LDIP)) - != (0)) - && (spincount--)); - if(spincount == -1); - { - printf("uha%d: board not responding\n",unit); + u_short iobase = uha->sc_iobase; + int spincount = 100; /* 1 mSec */ + int abortcount = 200000; /*2 secs */ + int s = splbio(); + + while (--spincount) { + if ((inb(iobase + UHA_LINT) & UHA_LDIP) == 0) + break; + delay(10); + } + if (!spincount) { + printf("%s: uha_abort, board not responding\n", + uha->sc_dev.dv_xname); Debugger(); } - outl(port + UHA_OGM0,KVTOPHYS(mscp)); - outb(port + UHA_LINT,UHA_ABORT); + outl(iobase + UHA_OGM0, KVTOPHYS(mscp)); + outb(iobase + UHA_LINT, UHA_ABORT); - while((abortcount--) && (!(inb(port + UHA_SINT) & UHA_ABORT_FAIL))); - if(abortcount == -1) - { - printf("uha%d: board not responding\n",unit); + while (--abortcount) { + if (inb(iobase + UHA_SINT) & UHA_ABORT_FAIL) + break; + delay(10); + } + if (!abortcount) { + printf("%s: uha_abort, board not responding\n", + uha->sc_dev.dv_xname); Debugger(); } - if((inb(port + UHA_SINT) & 0x10) != 0) - { - outb(port + UHA_SINT,UHA_ABORT_ACK); - return(1); - } - else - { - outb(port + UHA_SINT,UHA_ABORT_ACK); - return(0); - } -} -/***********************************************************************\ -* Function to poll for command completion when in poll mode * -\***********************************************************************/ -uha_poll(int unit ,int wait) /* in msec */ -{ - int port = uha_data[unit].baseport; - int spincount = FUDGE(delaycount) * wait; /* in msec */ - int stport = port + UHA_SINT; - int start = spincount; - -retry: - while( (spincount--) && (!(inb(stport) & UHA_SINTP))); - if(spincount == -1) - { - printf("uha%d: board not responding\n",unit); - return(EIO); - } -if ((int)cheat != PHYSTOKV(inl(port + UHA_ICM0))) -{ - printf("discarding %x ",inl(port + UHA_ICM0)); - outb(port + UHA_SINT, UHA_ICM_ACK); - spinwait(50); - goto retry; -}/* don't know this will work */ - uhaintr(unit); - return(0); -} - -/*******************************************************\ -* Check if the device can be found at the port given * -* and if so, set it up ready for further work * -* as an argument, takes the isa_dev structure from * -* autoconf.c * -\*******************************************************/ -uhaprobe(dev) -struct isa_device *dev; -{ - int unit; - - if (dev->id_parent) + if ((inb(iobase + UHA_SINT) & UHA_ABORT_FAIL) == UHA_ABORT_SUCC) { + outb(iobase + UHA_SINT, UHA_ABORT_ACK); + splx(s); return 1; - - dev->id_unit = unit = uha_unit; - uha_data[unit].baseport = dev->id_iobase; - if(unit >= NUHA) - { - printf("uha: unit number (%d) too high\n",unit); - return(0); + } else { + outb(iobase + UHA_SINT, UHA_ABORT_ACK); + splx(s); + return 0; } - - /*try and initialize unit at this location*/ - if (uha_init(unit) != 0) - { - return(0); - } - - /* if its there put in it's interrupt and DRQ vectors */ - - dev->id_irq = (1 << uha_data[unit].vect); - dev->id_drq = uha_data[unit].dma; - - uha_unit ++; - return(8); } -/***********************************************\ -* Attach all the sub-devices we can find * -\***********************************************/ -uha_attach(dev) -struct isa_device *dev; +/* + * Function to poll for command completion when in poll mode. + * + * wait = timeout in msec + */ +int +uha_poll(uha, wait) + struct uha_softc *uha; + int wait; { - static int firsttime; - static int firstswitch[NUHA]; - int masunit; - int r; + u_short iobase = uha->sc_iobase; - if (!dev->id_parent) - return 1; - masunit = dev->id_parent->id_unit; + while (--wait) { + if (inb(iobase + UHA_SINT) & UHA_SINTP) + break; + delay(1000); /* 1 mSec per loop */ + } + if (!wait) { + printf("%s: uha_poll, board not responding\n", + uha->sc_dev.dv_xname); + return EIO; + } - if (!firstswitch[masunit]) { - firstswitch[masunit] = 1; - uha_switch[masunit].name = "uha"; - uha_switch[masunit].scsi_cmd = uha_scsi_cmd; - uha_switch[masunit].scsi_minphys = uhaminphys; - uha_switch[masunit].open_target_lu = 0; - uha_switch[masunit].close_target_lu = 0; - uha_switch[masunit].adapter_info = uha_adapter_info; - for (r = 0; r < 8; r++) { - uha_switch[masunit].empty[r] = 0; - uha_switch[masunit].used[r] = 0; - uha_switch[masunit].printed[r] = 0; + uhaintr(uha->sc_dev.dv_unit); + return 0; +} + +/* + * Check if the device can be found at the port given and if so, set it up + * ready for further work as an argument, takes the isa_device structure + * from autoconf.c + */ +int +uhaprobe(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct uha_softc *uha = (void *)self; + struct isa_attach_args *ia = aux; + +#ifdef NEWCONFIG + if (ia->ia_iobase == IOBASEUNK) + return 0; +#endif + + uha->sc_iobase = ia->ia_iobase; + + /* + * Try initialise a unit at this location + * sets up dma and bus speed, loads uha->vect + */ + if (uha_find(uha) != 0) + return 0; + +#ifdef NEWCONFIG + if (ia->ia_irq == IRQUNK) { + ia->ia_irq = (1 << uha->vect); + } else { + if (ia->ia_irq != (1 << uha->vect)) { + printf("uha%d: irq mismatch, %x != %x\n", + uha->sc_dev.dv_unit, ia->ia_irq, + 1 << uha->vect); + return 0; } } - r = scsi_attach(masunit, &uha_switch[masunit], &dev->id_physid, - &dev->id_unit, dev->id_flags); - /* only one for all boards */ - if(firsttime==0) { - firsttime = 1; - uha_timeout(0); + if (ia->ia_drq == DRQUNK) { + ia->ia_drq = uha->dma; + } else { + if (ia->ia_drq != uha->dma) { + printf("uha%d: drq mismatch, %x != %x\n", + uha->sc_dev.dv_unit, ia->ia_drq, uha->dma); + return 0; + } } - return r; +#endif + + ia->ia_msize = 0; + ia->ia_iosize = 4; + return 1; } -/***********************************************\ -* Return some information to the caller about * -* the adapter and it's capabilities * -\***********************************************/ -long int uha_adapter_info(unit) -int unit; +uhaprint() { - return(2); /* 2 outstanding requests at a time per device */ + } -/***********************************************\ -* Catch an interrupt from the adaptor * -\***********************************************/ +/* + * Attach all the sub-devices we can find + */ +void +uhaattach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct isa_attach_args *ia = aux; + struct uha_softc *uha = (void *)self; + + uha_init(uha); + + /* + * fill in the prototype scsi_link. + */ + uha->sc_link.adapter_softc = uha; + uha->sc_link.adapter_targ = uha->our_id; + uha->sc_link.adapter = &uha_switch; + uha->sc_link.device = &uha_dev; + + printf("\n"); + +#ifdef NEWCONFIG + isa_establish(&uha->sc_id, &uha->sc_dev); + uha->sc_ih.ih_fun = uhaintr; + uha->sc_ih.ih_arg = uha; + /* XXX and DV_TAPE, but either gives us splbio */ + intr_establish(ia->ia_irq, &uha->sc_ih, DV_DISK); +#endif + + /* + * ask the adapter what subunits are present + */ + config_found(self, &uha->sc_link, uhaprint); +} + +/* + * Return some information to the caller about + * the adapter and it's capabilities + */ +u_int +uha_adapter_info(uha) + struct uha_softc *uha; +{ + + return 2; /* 2 outstanding requests at a time per device */ +} + +/* + * Catch an interrupt from the adaptor + */ +int uhaintr(unit) + int unit; { - struct mscp *mscp; - u_char uhastat; - unsigned long int mboxval; + struct uha_softc *uha = uhacd.cd_devs[unit]; + struct mscp *mscp; + u_char uhastat; + u_long mboxval; + u_short iobase = uha->sc_iobase; - int port = uha_data[unit].baseport; +#ifdef UHADEBUG + printf("%s: uhaintr ", uha->sc_dev.dv_xname); +#endif /*UHADEBUG */ + if ((inb(iobase + UHA_SINT) & UHA_SINTP) == 0) + return 0; - if(scsi_debug & PRINTROUTINES) - printf("uhaintr "); + do { + /* + * First get all the information and then + * acknowledge the interrupt + */ + uhastat = inb(iobase + UHA_SINT); + mboxval = inl(iobase + UHA_ICM0); + outb(iobase + UHA_SINT, UHA_ICM_ACK); -#if defined(OSF) - if (!uha_attached[unit]) - { - return(1); - } -#endif /* defined(OSF) */ - while(inb(port + UHA_SINT) & UHA_SINTP) - { - /***********************************************\ - * First get all the information and then * - * acknowlege the interrupt * - \***********************************************/ - uhastat = inb(port + UHA_SINT); - mboxval = inl(port + UHA_ICM0); - outb(port + UHA_SINT,UHA_ICM_ACK); +#ifdef UHADEBUG + printf("status = 0x%x ", uhastat); +#endif /*UHADEBUG*/ - if(scsi_debug & TRACEINTERRUPTS) - printf("status = 0x%x ",uhastat); - /***********************************************\ - * Process the completed operation * - \***********************************************/ - - mscp = (struct mscp *)(PHYSTOKV(mboxval)); + /* + * Process the completed operation + */ + mscp = uha_mscp_phys_kv(uha, mboxval); + if (!mscp) { + printf("uha: BAD MSCP RETURNED\n"); + return 0; /* whatever it was, it'll timeout */ + } + untimeout(uha_timeout, (caddr_t)mscp); - if(uha_debug & UHA_SHOWCMDS ) - { - uha_show_scsi_cmd(mscp->xs); - } - if((uha_debug & UHA_SHOWMSCPS) && mscp) - printf("",mscp); - uha_remove_timeout(mscp); + uha_done(uha, mscp); + } while (inb(iobase + UHA_SINT) & UHA_SINTP); - uha_done(unit,mscp); - } - return(1); + return 1; } -/***********************************************\ -* We have a mscp which has been processed by the * -* adaptor, now we look to see how the operation * -* went. * -\***********************************************/ - -uha_done(unit,mscp) -int unit; -struct mscp *mscp; +/* + * We have a mscp which has been processed by the adaptor, now we look to see + * how the operation went. + */ +void +uha_done(uha, mscp) + struct uha_softc *uha; + struct mscp *mscp; { - struct scsi_sense_data *s1,*s2; - struct scsi_xfer *xs = mscp->xs; + struct scsi_sense_data *s1, *s2; + struct scsi_xfer *xs = mscp->xs; - if(scsi_debug & (PRINTROUTINES | TRACEINTERRUPTS)) - printf("uha_done "); - /***********************************************\ - * Otherwise, put the results of the operation * - * into the xfer and call whoever started it * - \***********************************************/ - if ( (mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK)) - { /* All went correctly OR errors expected */ + SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); + /* + * Otherwise, put the results of the operation + * into the xfer and call whoever started it + */ + if ((mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK)) { + /* all went correctly OR errors expected */ xs->resid = 0; xs->error = 0; - } - else - { + } else { + s1 = &mscp->mscp_sense; + s2 = &xs->sense; - s1 = &(mscp->mscp_sense); - s2 = &(xs->sense); - - if(mscp->ha_status != UHA_NO_ERR) - { - switch(mscp->ha_status) - { - case UHA_SBUS_TIMEOUT: /* No response */ - if (uha_debug & UHA_SHOWMISC) - { - printf("timeout reported back\n"); - } + if (mscp->ha_status != UHA_NO_ERR) { + switch (mscp->ha_status) { + case UHA_SBUS_TIMEOUT: /* No response */ + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("timeout reported back\n")); xs->error = XS_TIMEOUT; break; - case UHA_SBUS_OVER_UNDER: - if (uha_debug & UHA_SHOWMISC) - { - printf("scsi bus xfer over/underrun\n"); - } + case UHA_SBUS_OVER_UNDER: + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("scsi bus xfer over/underrun\n")); xs->error = XS_DRIVER_STUFFUP; break; - case UHA_BAD_SG_LIST: - if (uha_debug & UHA_SHOWMISC) - { - printf("bad sg list reported back\n"); - } + case UHA_BAD_SG_LIST: + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("bad sg list reported back\n")); xs->error = XS_DRIVER_STUFFUP; break; - default: /* Other scsi protocol messes */ + default: /* Other scsi protocol messes */ xs->error = XS_DRIVER_STUFFUP; - if (uha_debug & UHA_SHOWMISC) - { - printf("unexpected ha_status: %x\n", - mscp->ha_status); - } + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected ha_status: %x\n", + mscp->ha_status)); } - - } - else - { - - if (mscp->targ_status != 0) -/**************************************************************************\ -* I have no information for any possible value of target status field * -* other than 0 means no error!! So I guess any error is unexpected in that * -* event!! * -\**************************************************************************/ - - { - if (uha_debug & UHA_SHOWMISC) - { - printf("unexpected targ_status: %x\n", - mscp->targ_status); - } + } else { + if (mscp->targ_status != 0) { + /* + * I have no information for any possible value + * of target status field other than 0 means no + * error!! So I guess any error is unexpected + * in that event!! + */ + SC_DEBUG(xs->sc_link, SDEV_DB3, + ("unexpected targ_status: %x\n", + mscp->targ_status)); xs->error = XS_DRIVER_STUFFUP; } } } -done: xs->flags |= ITSDONE; - uha_free_mscp(unit,mscp, xs->flags); - if(xs->when_done) - (*(xs->when_done))(xs->done_arg,xs->done_arg2); + done: + xs->flags |= ITSDONE; + uha_free_mscp(uha, mscp, xs->flags); + scsi_done(xs); } -/***********************************************\ -* A mscp (and hence a mbx-out is put onto the * -* free list. * -\***********************************************/ -uha_free_mscp(unit,mscp, flags) -struct mscp *mscp; +/* + * A mscp (and hence a mbx-out) is put onto the free list. + */ +void +uha_free_mscp(uha, mscp, flags) + struct uha_softc *uha; + struct mscp *mscp; + int flags; { - unsigned int opri; - - if(scsi_debug & PRINTROUTINES) - printf("mscp%d(0x%x)> ",unit,flags); - if (!(flags & SCSI_NOMASK)) + int opri; + + if (!(flags & SCSI_NOMASK)) opri = splbio(); - mscp->next = uha_data[unit].free_mscp; - uha_data[unit].free_mscp = mscp; + mscp->next = uha->free_mscp; + uha->free_mscp = mscp; mscp->flags = MSCP_FREE; - /***********************************************\ - * If there were none, wake abybody waiting for * - * one to come free, starting with queued entries* - \***********************************************/ - if (!mscp->next) { - wakeup((caddr_t) &uha_data[unit].free_mscp); - } - if (!(flags & SCSI_NOMASK)) + + /* + * If there were none, wake abybody waiting for + * one to come free, starting with queued entries + */ + if (!mscp->next) + wakeup((caddr_t)&uha->free_mscp); + + if (!(flags & SCSI_NOMASK)) splx(opri); } -/***********************************************\ -* Get a free mscp (and hence mbox-out entry) * -\***********************************************/ +/* + * Get a free mscp + * + * If there are none, see if we can allocate a new one. If so, put it in the + * hash table too otherwise either return an error or sleep. + */ struct mscp * -uha_get_mscp(unit,flags) +uha_get_mscp(uha, flags) + struct uha_softc *uha; + int flags; { - unsigned opri; - struct mscp *rc; + int opri; + struct mscp *mscpp; + int hashnum; - if(scsi_debug & PRINTROUTINES) - printf("free_mscp)) { + if (uha->nummscps < UHA_MSCP_MAX) { + if (mscpp = (struct mscp *)malloc(sizeof(struct mscp), + M_TEMP, M_NOWAIT)) { + bzero(mscpp, sizeof(struct mscp)); + uha->nummscps++; + mscpp->flags = MSCP_ACTIVE; + /* + * put in the phystokv hash table + * Never gets taken out. + */ + mscpp->hashkey = KVTOPHYS(mscpp); + hashnum = MSCP_HASH(mscpp->hashkey); + mscpp->nexthash = uha->mscphash[hashnum]; + uha->mscphash[hashnum] = mscpp; + } else { + printf("%s: Can't malloc MSCP\n", + uha->sc_dev.dv_xname); + } + goto gottit; + } else { + if (!(flags & SCSI_NOSLEEP)) + tsleep((caddr_t)&uha->free_mscp, PRIBIO, + "uhamsc", 0); + } } - if (rc) - { - uha_data[unit].free_mscp = rc->next; - rc->flags = MSCP_ACTIVE; + + if (mscpp) { + /* Get MSCP from the free list */ + uha->free_mscp = mscpp->next; + mscpp->flags = MSCP_ACTIVE; } - if (!(flags & SCSI_NOMASK)) + + gottit: + if (!(flags & SCSI_NOMASK)) splx(opri); - return(rc); + + return mscpp; } - +/* + * given a physical address, find the mscp that it corresponds to. + */ +struct mscp * +uha_mscp_phys_kv(uha, mscp_phys) + struct uha_softc *uha; + u_long mscp_phys; +{ + int hashnum = MSCP_HASH(mscp_phys); + struct mscp *mscpp = uha->mscphash[hashnum]; -/***********************************************\ -* Start the board, ready for normal operation * -\***********************************************/ + while (mscpp) { + if (mscpp->hashkey == mscp_phys) + break; + mscpp = mscpp->nexthash; + } + return mscpp; +} -uha_init(unit) -int unit; -{ - unsigned char ad[4]; - volatile unsigned char model; - volatile unsigned char submodel; - unsigned char config_reg1; - unsigned char config_reg2; - unsigned char dma_ch; - unsigned char irq_ch; - unsigned char uha_id; - int port = uha_data[unit].baseport; - int i; - int resetcount = FUDGE(delaycount) * 4000; +/* + * Start the board, ready for normal operation + */ +int +uha_find(uha) + struct uha_softc *uha; +{ + u_char ad[4]; + volatile u_char model; + volatile u_char submodel; + u_char config_reg1; + u_char config_reg2; + u_char dma_ch; + u_char irq_ch; + u_char uha_id; + u_short iobase = uha->sc_iobase; + int i; + int resetcount = 4000; /* 4 secs? */ - model = inb(port + UHA_ID0); - submodel = inb(port + UHA_ID1); - if ((model != 0x56) & (submodel != 0x40)) - { /* printf("ultrastor 14f not responding\n"); */ - return(ENXIO); } + model = inb(iobase + UHA_ID0); + submodel = inb(iobase + UHA_ID1); + if ((model != 0x56) & (submodel != 0x40)) + return ENXIO; - printf("uha%d reading board settings, ",unit); - - config_reg1 = inb(port + UHA_CONF1); - config_reg2 = inb(port + UHA_CONF2); + config_reg1 = inb(iobase + UHA_CONF1); + config_reg2 = inb(iobase + UHA_CONF2); dma_ch = (config_reg1 & 0xc0); irq_ch = (config_reg1 & 0x30); uha_id = (config_reg2 & 0x07); - switch(dma_ch) - { - case UHA_DMA_CH5: - uha_data[unit].dma = 5; - printf("dma=5 "); + switch (dma_ch) { + case UHA_DMA_CH5: + uha->dma = 5; break; - case UHA_DMA_CH6: - uha_data[unit].dma = 6; - printf("dma=6 "); + case UHA_DMA_CH6: + uha->dma = 6; break; - case UHA_DMA_CH7: - uha_data[unit].dma = 7; - printf("dma=7 "); + case UHA_DMA_CH7: + uha->dma = 7; break; default: - printf("illegal dma jumper setting\n"); - return(EIO); + printf("illegal dma setting %x\n", dma_ch); + return EIO; } - switch(irq_ch) - { - case UHA_IRQ10: - uha_data[unit].vect = 10; - printf("int=10 "); + + switch (irq_ch) { + case UHA_IRQ10: + uha->vect = 10; break; - case UHA_IRQ11: - uha_data[unit].vect = 11; - printf("int=11 "); + case UHA_IRQ11: + uha->vect = 11; break; - case UHA_IRQ14: - uha_data[unit].vect = 14; - printf("int=14 "); + case UHA_IRQ14: + uha->vect = 14; break; - case UHA_IRQ15: - uha_data[unit].vect = 15; - printf("int=15 "); + case UHA_IRQ15: + uha->vect = 15; break; default: - printf("illegal int jumper setting\n"); - return(EIO); + printf("illegal int setting %x\n", irq_ch); + return EIO; } + /* who are we on the scsi bus */ - printf("id=%x\n",uha_id); - uha_switch[unit].scsi_dev = uha_id; + uha->our_id = uha_id; - - /***********************************************\ - * link up all our MSCPs into a free list * - \***********************************************/ - for (i=0; i < NUM_CONCURRENT; i++) - { - uha_data[unit].mscps[i].next = uha_data[unit].free_mscp; - uha_data[unit].free_mscp = &uha_data[unit].mscps[i]; - uha_data[unit].free_mscp->flags = MSCP_FREE; + outb(iobase + UHA_LINT, UHA_ASRST); + + while (--resetcount) { + if (inb(iobase + UHA_LINT)) + break; + delay(1000); /* 1 mSec per loop */ + } + if (!resetcount) { + printf("%s: board timed out during reset\n", + uha->sc_dev.dv_xname); + return ENXIO; } - /***********************************************\ - * Note that we are going and return (to probe) * - \***********************************************/ - outb(port + UHA_LINT, UHA_ASRST); - while( (resetcount--) && (!(inb(port + UHA_LINT)))); - if(resetcount == -1) - { - printf("uha%d: board timed out during reset\n",unit); - return(ENXIO); - } - - outb(port + UHA_SMASK, 0x81); /* make sure interrupts are enabled */ - uha_data[unit].flags |= UHA_INIT; - return(0); + /* + * Note that we are going and return (to probe) + */ + return 0; } - - -#ifndef min -#define min(x,y) (x < y ? x : y) -#endif min - - -void uhaminphys(bp) -struct buf *bp; +void +uha_init(uha) + struct uha_softc *uha; { -#ifdef MACH -#if !defined(OSF) - bp->b_flags |= B_NPAGES; /* can support scat/gather */ -#endif /* defined(OSF) */ -#endif MACH - if(bp->b_bcount > ((UHA_NSEG-1) * PAGESIZ)) - { - bp->b_bcount = ((UHA_NSEG-1) * PAGESIZ); - } + u_short iobase = uha->sc_iobase; + + outb(iobase + UHA_SMASK, 0x81); /* make sure interrupts are enabled */ } -/***********************************************\ -* start a scsi operation given the command and * -* the data address. Also needs the unit, target * -* and lu * -\***********************************************/ -int uha_scsi_cmd(xs) -struct scsi_xfer *xs; +void +uhaminphys(bp) + struct buf *bp; { - struct scsi_sense_data *s1,*s2; + + if (bp->b_bcount > ((UHA_NSEG - 1) << PGSHIFT)) + bp->b_bcount = ((UHA_NSEG - 1) << PGSHIFT); +} + +/* + * start a scsi operation given the command and the data address. Also + * needs the unit, target and lu. + */ +int +uha_scsi_cmd(xs) + struct scsi_xfer *xs; +{ + struct scsi_link *sc_link = xs->sc_link; + struct uha_softc *uha = sc_link->adapter_softc; struct mscp *mscp; struct uha_dma_seg *sg; - int seg; /* scatter gather seg being worked on */ - int i = 0; - int rc = 0; - int thiskv; - unsigned long int thisphys,nextphys; - int unit =xs->adapter; - int bytes_this_seg,bytes_this_page,datalen,flags; - struct iovec *iovp; - int s; - unsigned int stat; - int port = uha_data[unit].baseport; - unsigned long int templen; + int seg; /* scatter gather seg being worked on */ + u_long thiskv, thisphys, nextphys; + int bytes_this_seg, bytes_this_page, datalen, flags; + struct iovec *iovp; + int s; + u_long templen; - - if(scsi_debug & PRINTROUTINES) - printf("uha_scsi_cmd "); - /***********************************************\ - * get a mscp (mbox-out) to use. If the transfer * - * is from a buf (possibly from interrupt time) * - * then we can't allow it to sleep * - \***********************************************/ + SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); + /* + * get a mscp (mbox-out) to use. If the transfer + * is from a buf (possibly from interrupt time) + * then we can't allow it to sleep + */ flags = xs->flags; - if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */ - if(flags & ITSDONE) - { - printf("Already done?"); + if (xs->bp) + flags |= SCSI_NOSLEEP; /* just to be sure */ + if (flags & ITSDONE) { + printf("%s: already done?", uha->sc_dev.dv_xname); xs->flags &= ~ITSDONE; } - if(!(flags & INUSE)) - { - printf("Not in use?"); + if (!(flags & INUSE)) { + printf("%s: not in use?", uha->sc_dev.dv_xname); xs->flags |= INUSE; } - if (!(mscp = uha_get_mscp(unit,flags))) - { + if (!(mscp = uha_get_mscp(uha, flags))) { xs->error = XS_DRIVER_STUFFUP; - return(TRY_AGAIN_LATER); - } - -cheat = mscp; - if(uha_debug & UHA_SHOWMSCPS) - printf("",mscp); - if(scsi_debug & SHOWCOMMANDS) - { - uha_show_scsi_cmd(xs); + return TRY_AGAIN_LATER; } + SC_DEBUG(sc_link, SDEV_DB3, ("start mscp(%x)\n", mscp)); mscp->xs = xs; - /***********************************************\ - * Put all the arguments for the xfer in the mscp * - \***********************************************/ - if (flags & SCSI_RESET) - { + /* + * Put all the arguments for the xfer in the mscp + */ + if (flags & SCSI_RESET) { mscp->opcode = 0x04; mscp->ca = 0x01; - } - else - { + } else { mscp->opcode = 0x02; mscp->ca = 0x01; - } - + } if (flags & SCSI_DATA_IN) - { mscp->xdir = 0x01; - } if (flags & SCSI_DATA_OUT) - { mscp->xdir = 0x02; - } - if (xs->lu != 0) - { - xs->error = XS_DRIVER_STUFFUP; - uha_free_mscp(unit,mscp,flags); - return(HAD_ERROR); - } - - mscp->dcn = 0x00; - mscp->chan = 0x00; - mscp->target = xs->targ; - mscp->lun = xs->lu; - mscp->link.addr[0] = 0x00; - mscp->link.addr[1] = 0x00; - mscp->link.addr[2] = 0x00; - mscp->link.addr[3] = 0x00; - mscp->link_id = 0x00; - mscp->cdblen = xs->cmdlen; - scratch = KVTOPHYS(&(mscp->mscp_sense)); - mscp->sense.addr[0] = (scratch & 0xff); - mscp->sense.addr[1] = ((scratch >> 8) & 0xff); - mscp->sense.addr[2] = ((scratch >> 16) & 0xff); - mscp->sense.addr[3] = ((scratch >> 24) & 0xff); - mscp->senselen = sizeof(mscp->mscp_sense); - mscp->ha_status = 0x00; - mscp->targ_status = 0x00; + mscp->dcn = 0x00; + mscp->chan = 0x00; + mscp->target = sc_link->target; + mscp->lun = sc_link->lun; + mscp->link.addr[0] = 0x00; + mscp->link.addr[1] = 0x00; + mscp->link.addr[2] = 0x00; + mscp->link.addr[3] = 0x00; + mscp->link_id = 0x00; + mscp->cdblen = xs->cmdlen; + scratch = KVTOPHYS(&mscp->mscp_sense); + mscp->sense.addr[0] = (scratch & 0xff); + mscp->sense.addr[1] = ((scratch >> 8) & 0xff); + mscp->sense.addr[2] = ((scratch >> 16) & 0xff); + mscp->sense.addr[3] = ((scratch >> 24) & 0xff); + mscp->senselen = sizeof(mscp->mscp_sense); + mscp->ha_status = 0x00; + mscp->targ_status = 0x00; - if(xs->datalen) - { /* should use S/G only if not zero length */ - scratch = KVTOPHYS(mscp->uha_dma); - mscp->data.addr[0] = (scratch & 0xff); - mscp->data.addr[1] = ((scratch >> 8) & 0xff); - mscp->data.addr[2] = ((scratch >> 16) & 0xff); - mscp->data.addr[3] = ((scratch >> 24) & 0xff); - sg = mscp->uha_dma ; - seg = 0; - mscp->sgth = 0x01; + if (xs->datalen) { /* should use S/G only if not zero length */ + scratch = KVTOPHYS(mscp->uha_dma); + mscp->data.addr[0] = (scratch & 0xff); + mscp->data.addr[1] = ((scratch >> 8) & 0xff); + mscp->data.addr[2] = ((scratch >> 16) & 0xff); + mscp->data.addr[3] = ((scratch >> 24) & 0xff); + sg = mscp->uha_dma; + seg = 0; + mscp->sgth = 0x01; - if(flags & SCSI_DATA_UIO) - { - iovp = ((struct uio *)xs->data)->uio_iov; - datalen = ((struct uio *)xs->data)->uio_iovcnt; +#ifdef TFS + if (flags & SCSI_DATA_UIO) { + iovp = ((struct uio *) xs->data)->uio_iov; + datalen = ((struct uio *) xs->data)->uio_iovcnt; xs->datalen = 0; - while ((datalen) && (seg < UHA_NSEG)) - { - scratch = (unsigned long)iovp->iov_base; - sg->addr.addr[0] = (scratch & 0xff); + while (datalen && seg < UHA_NSEG) { + scratch = (u_long) iovp->iov_base; + sg->addr.addr[0] = (scratch & 0xff); sg->addr.addr[1] = ((scratch >> 8) & 0xff); sg->addr.addr[2] = ((scratch >> 16) & 0xff); sg->addr.addr[3] = ((scratch >> 24) & 0xff); - xs->datalen += *(unsigned long *)sg->len.len = iovp->iov_len; - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x@0x%x)" - ,iovp->iov_len - ,iovp->iov_base); + xs->datalen += *(u_long *) sg->len.len = iovp->iov_len; + SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)", + iovp->iov_len, iovp->iov_base)); sg++; iovp++; seg++; datalen--; } - } - else + } else +#endif /*TFS */ { - /***********************************************\ - * Set up the scatter gather block * - \***********************************************/ - - if(scsi_debug & SHOWSCATGATH) - printf("%d @0x%x:- ",xs->datalen,xs->data); - datalen = xs->datalen; - thiskv = (int)xs->data; - thisphys = KVTOPHYS(thiskv); - templen = 0; - - while ((datalen) && (seg < UHA_NSEG)) - { - bytes_this_seg = 0; - + /* + * Set up the scatter gather block + */ + SC_DEBUG(sc_link, SDEV_DB4, + ("%d @0x%x:- ", xs->datalen, xs->data)); + datalen = xs->datalen; + thiskv = (int) xs->data; + thisphys = KVTOPHYS(thiskv); + templen = 0; + + while (datalen && seg < UHA_NSEG) { + bytes_this_seg = 0; + /* put in the base address */ sg->addr.addr[0] = (thisphys & 0xff); sg->addr.addr[1] = ((thisphys >> 8) & 0xff); sg->addr.addr[2] = ((thisphys >> 16) & 0xff); sg->addr.addr[3] = ((thisphys >> 24) & 0xff); - - if(scsi_debug & SHOWSCATGATH) - printf("0x%x",thisphys); - + + SC_DEBUGN(sc_link, SDEV_DB4, + ("0x%x", thisphys)); + /* do it at least once */ - nextphys = thisphys; - while ((datalen) && (thisphys == nextphys)) - /*********************************************\ - * This page is contiguous (physically) with * - * the the last, just extend the length * - \*********************************************/ - { + nextphys = thisphys; + while (datalen && thisphys == nextphys) { + /* + * This page is contiguous (physically) + * with the the last, just extend the + * length + */ /* how far to the end of the page */ - nextphys = (thisphys & (~(PAGESIZ - 1))) - + PAGESIZ; + nextphys = (thisphys & ~PGOFSET) + NBPG; bytes_this_page = nextphys - thisphys; /**** or the data ****/ - bytes_this_page = min(bytes_this_page - ,datalen); - bytes_this_seg += bytes_this_page; - datalen -= bytes_this_page; - + bytes_this_page = min(bytes_this_page, + datalen); + bytes_this_seg += bytes_this_page; + datalen -= bytes_this_page; + /* get more ready for the next page */ - thiskv = (thiskv & (~(PAGESIZ - 1))) - + PAGESIZ; - if(datalen) + thiskv = (thiskv & ~PGOFSET) + NBPG; + if (datalen) thisphys = KVTOPHYS(thiskv); } - /********************************************\ - * next page isn't contiguous, finish the seg * - \********************************************/ - if(scsi_debug & SHOWSCATGATH) - printf("(0x%x)",bytes_this_seg); + /* + * next page isn't contiguous, finish the seg + */ + SC_DEBUGN(sc_link, SDEV_DB4, + ("(0x%x)", bytes_this_seg)); sg->len.len[0] = (bytes_this_seg & 0xff); sg->len.len[1] = ((bytes_this_seg >> 8) & 0xff); sg->len.len[2] = ((bytes_this_seg >> 16) & 0xff); @@ -1005,27 +1016,24 @@ cheat = mscp; sg++; seg++; } - } /*end of iov/kv decision */ + } + + /* end of iov/kv decision */ mscp->datalen.len[0] = (templen & 0xff); mscp->datalen.len[1] = ((templen >> 8) & 0xff); mscp->datalen.len[2] = ((templen >> 16) & 0xff); mscp->datalen.len[3] = ((templen >> 24) & 0xff); mscp->sg_num = seg; + SC_DEBUGN(sc_link, SDEV_DB4, ("\n")); - if(scsi_debug & SHOWSCATGATH) - printf("\n"); - if (datalen) - { /* there's still data, must have run out of segs! */ - printf("uha_scsi_cmd%d: more than %d DMA segs\n", - unit,UHA_NSEG); + if (datalen) { /* there's still data, must have run out of segs! */ + printf("%s: uha_scsi_cmd, more than %d DMA segs\n", + uha->sc_dev.dv_xname, UHA_NSEG); xs->error = XS_DRIVER_STUFFUP; - uha_free_mscp(unit,mscp,flags); - return(HAD_ERROR); + uha_free_mscp(uha, mscp, flags); + return HAD_ERROR; } - - } - else - { /* No data xfer, use non S/G values */ + } else { /* No data xfer, use non S/G values */ mscp->data.addr[0] = 0x00; mscp->data.addr[1] = 0x00; mscp->data.addr[2] = 0x00; @@ -1036,259 +1044,104 @@ cheat = mscp; mscp->datalen.len[3] = 0x00; mscp->xdir = 0x03; mscp->sgth = 0x00; - mscp->sg_num = 0x00; + mscp->sg_num = 0x00; } - /***********************************************\ - * Put the scsi command in the mscp and start it * - \***********************************************/ - bcopy(xs->cmd, mscp->cdb, xs->cmdlen); + /* + * Put the scsi command in the mscp and start it + */ + bcopy(xs->cmd, mscp->cdb, xs->cmdlen); - /***********************************************\ - * Usually return SUCCESSFULLY QUEUED * - \***********************************************/ - if (!(flags & SCSI_NOMASK)) - { + /* + * Usually return SUCCESSFULLY QUEUED + */ + if (!(flags & SCSI_NOMASK)) { s = splbio(); - uha_send_mbox(unit,mscp); - uha_add_timeout(mscp,xs->timeout); + uha_send_mbox(uha, mscp); + timeout(uha_timeout, (caddr_t)mscp, (xs->timeout * hz) / 1000); splx(s); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_sent "); - return(SUCCESSFULLY_QUEUED); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_sent\n")); + return SUCCESSFULLY_QUEUED; } - /***********************************************\ - * If we can't use interrupts, poll on completion* - \***********************************************/ - uha_send_mbox(unit,mscp); - if(scsi_debug & TRACEINTERRUPTS) - printf("cmd_wait "); - do - { - if(uha_poll(unit,xs->timeout)) - { - if (!(xs->flags & SCSI_SILENT)) printf("cmd fail\n"); - if(!(uha_abort(unit,mscp))) - { - printf("abort failed in wait\n"); - uha_free_mscp(unit,mscp,flags); + + /* + * If we can't use interrupts, poll on completion + */ + uha_send_mbox(uha, mscp); + SC_DEBUG(sc_link, SDEV_DB3, ("cmd_wait\n")); + do { + if (uha_poll(uha, xs->timeout)) { + if (!(xs->flags & SCSI_SILENT)) + printf("%s: cmd fail\n", uha->sc_dev.dv_xname); + if (!uha_abort(uha, mscp)) { + printf("%s: abort failed in wait\n", + uha->sc_dev.dv_xname); + uha_free_mscp(uha, mscp, flags); } xs->error = XS_DRIVER_STUFFUP; - return(HAD_ERROR); + return HAD_ERROR; } } while (!(xs->flags & ITSDONE));/* something (?) else finished */ -scsi_debug = 0;uha_debug = 0; - if(xs->error) - { - return(HAD_ERROR); - } - return(COMPLETE); + if (xs->error) + return HAD_ERROR; + return COMPLETE; } -/* - * +----------+ +----------+ +----------+ - * uha_soonest--->| later |--->| later|--->| later|--->0 - * | [Delta] | | [Delta] | | [Delta] | - * 0<---|sooner |<---|sooner |<---|sooner |<---uha_latest - * +----------+ +----------+ +----------+ - * - * uha_furtherest = sum(Delta[1..n]) - */ -uha_add_timeout(mscp,time) -struct mscp *mscp; -int time; -{ - int timeprev; - struct mscp *prev; - int s = splbio(); - - if(prev = uha_latest) /* yes, an assign */ - { - timeprev = uha_furtherest; - } - else - { - timeprev = 0; - } - while(prev && (timeprev > time)) - { - timeprev -= prev->delta; - prev = prev->sooner; - } - if(prev) - { - mscp->delta = time - timeprev; - if( mscp->later = prev->later) /* yes an assign */ - { - mscp->later->sooner = mscp; - mscp->later->delta -= mscp->delta; - } - else - { - uha_furtherest = time; - uha_latest = mscp; - } - mscp->sooner = prev; - prev->later = mscp; - } - else - { - if( mscp->later = uha_soonest) /* yes, an assign*/ - { - mscp->later->sooner = mscp; - mscp->later->delta -= time; - } - else - { - uha_furtherest = time; - uha_latest = mscp; - } - mscp->delta = time; - mscp->sooner = (struct mscp *)0; - uha_soonest = mscp; - } - splx(s); -} - -uha_remove_timeout(mscp) -struct mscp *mscp; -{ - int s = splbio(); - - if(mscp->sooner) - { - mscp->sooner->later = mscp->later; - } - else - { - uha_soonest = mscp->later; - } - if(mscp->later) - { - mscp->later->sooner = mscp->sooner; - mscp->later->delta += mscp->delta; - } - else - { - uha_latest = mscp->sooner; - uha_furtherest -= mscp->delta; - } - mscp->sooner = mscp->later = (struct mscp *)0; - splx(s); -} - - -extern int hz; -#define ONETICK 500 /* milliseconds */ -#define SLEEPTIME ((hz * 1000) / ONETICK) +void uha_timeout(arg) -int arg; + caddr_t arg; { - struct mscp *mscp; - int unit; - int s = splbio(); - unsigned int stat; - int port = uha_data[unit].baseport; + int s = splbio(); + struct mscp *mscp = (void *)arg; + struct uha_softc *uha = mscp->xs->sc_link->adapter_softc; - while( mscp = uha_soonest ) - { - if(mscp->delta <= ONETICK) - /***********************************************\ - * It has timed out, we need to do some work * - \***********************************************/ - { - unit = mscp->xs->adapter; - printf("uha%d:%d device timed out\n",unit - ,mscp->xs->targ); - if(uha_debug & UHA_SHOWMSCPS) - uha_print_active_mscp(); + sc_print_addr(mscp->xs->sc_link); + printf("timed out"); - /***************************************\ - * Unlink it from the queue * - \***************************************/ - uha_remove_timeout(mscp); +#ifdef UHADEBUG + uha_print_active_mscp(uha); +#endif /*UHADEBUG */ - if((uha_abort(unit,mscp) !=1) || (mscp->flags = MSCP_ABORTED)) - { - printf("AGAIN"); - mscp->xs->retries = 0; /* I MEAN IT ! */ - uha_done(unit,mscp,FAIL); - } - else /* abort the operation that has timed out */ - { - printf("\n"); - uha_add_timeout(mscp,2000 + ONETICK); - mscp->flags = MSCP_ABORTED; - } - } - else - /***********************************************\ - * It has not timed out, adjust and leave * - \***********************************************/ - { - mscp->delta -= ONETICK; - uha_furtherest -= ONETICK; - break; - } + if (!uha_abort(uha, mscp) || (mscp->flags == MSCP_ABORTED)) { + printf(" AGAIN\n"); + mscp->xs->retries = 0; /* I MEAN IT ! */ + uha_done(uha, mscp); + } else { /* abort the operation that has timed out */ + printf("\n"); + timeout(uha_timeout, (caddr_t)mscp, 2 * hz); + mscp->flags = MSCP_ABORTED; } splx(s); - timeout(uha_timeout,arg,SLEEPTIME); } -uha_show_scsi_cmd(struct scsi_xfer *xs) -{ - u_char *b = (u_char *)xs->cmd; - int i = 0; - if(!(xs->flags & SCSI_RESET)) - { - printf("uha%d:%d:%d-" - ,xs->adapter - ,xs->targ - ,xs->lu); - while(i < xs->cmdlen ) - { - if(i) printf(","); - printf("%x",b[i++]); - } - printf("-\n"); - } - else - { - printf("uha%d:%d:%d-RESET-\n" - ,xs->adapter - ,xs->targ - ,xs->lu - ); - } -} +#ifdef UHADEBUG +void uha_print_mscp(mscp) -struct mscp *mscp; + struct mscp *mscp; { - printf("mscp:%x op:%x cmdlen:%d senlen:%d\n" - ,mscp - ,mscp->opcode - ,mscp->cdblen - ,mscp->senselen); - printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x delta:%d flags:%x\n" - ,mscp->sgth - ,mscp->sg_num - ,mscp->datalen - ,mscp->ha_status - ,mscp->targ_status - ,mscp->delta - ,mscp->flags); - uha_show_scsi_cmd(mscp->xs); + + printf("mscp:%x op:%x cmdlen:%d senlen:%d\n", + mscp, mscp->opcode, mscp->cdblen, mscp->senselen); + printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x flags:%x\n", + mscp->sgth, mscp->sg_num, mscp->datalen, mscp->ha_status, + mscp->targ_status, mscp->flags); + show_scsi_cmd(mscp->xs); } -uha_print_active_mscp() +void +uha_print_active_mscp(uha) + struct uha_softc *uha; { - struct mscp *mscp; - mscp = uha_soonest; + struct mscp *mscp; + int i = 0; - while(mscp) - { - uha_print_mscp(mscp); - mscp = mscp->later; + while (i++ < MSCP_HASH_SIZE) { + mscp = uha->mscphash[i]; + while (mscp) { + if (mscp->flags != MSCP_FREE) + uha_print_mscp(mscp); + mscp = mscp->nexthash; + } } - printf("Furtherest = %d\n",uha_furtherest); } +#endif /*UHADEBUG */