Annotation of Net2/arch/i386/isa/aha1542.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * (Mostly) Written by Julian Elischer ([email protected])
        !             3:  * for TRW Financial Systems for use under the MACH(2.5) operating system.
        !             4:  *
        !             5:  * TRW Financial Systems, in accordance with their agreement with Carnegie
        !             6:  * Mellon University, makes this software available to CMU to distribute
        !             7:  * or use in any manner that they see fit as long as this message is kept with
        !             8:  * the software. For this reason TFS also grants any other persons or
        !             9:  * organisations permission to use or modify this software.
        !            10:  *
        !            11:  * TFS supplies this software to be publicly redistributed
        !            12:  * on the understanding that TFS is not responsible for the correct
        !            13:  * functioning of this software in any circumstances.
        !            14:  *
        !            15:  *
        !            16:  * PATCHES MAGIC                LEVEL   PATCH THAT GOT US HERE
        !            17:  * --------------------         -----   ----------------------
        !            18:  * CURRENT PATCH LEVEL:         1       00098
        !            19:  * --------------------         -----   ----------------------
        !            20:  *
        !            21:  * 16 Feb 93   Julian Elischer         ADDED for SCSI system
        !            22:  */
        !            23: 
        !            24: /*
        !            25:  * Ported to run under 386BSD by Julian Elischer ([email protected]) Sept 1992
        !            26:  */
        !            27: 
        !            28: /*
        !            29:  * HISTORY
        !            30:  * $Log: aha1542.c,v $
        !            31:  * Revision 1.3  1993/04/10 12:05:04  glass
        !            32:  * fixed to be compliant, subservient, and to take advantage of the newly
        !            33:  * hacked config(8)
        !            34:  *
        !            35:  * Revision 1.2  1993/04/08  08:26:46  deraadt
        !            36:  * dmesg output at boottime now tries to print out information as
        !            37:  * soon as it is available. The output looks much more like Sunos.
        !            38:  *
        !            39:  * Revision 1.1  1993/03/21  18:09:54  cgd
        !            40:  * after 0.2.2 "stable" patches applied
        !            41:  * 
        !            42:  * Revision 1.6  1992/08/24  21:01:58  jason
        !            43:  * many changes and bugfixes for osf1
        !            44:  *
        !            45:  * Revision 1.5  1992/07/31  01:22:03  julian
        !            46:  * support improved scsi.h layout
        !            47:  *
        !            48:  * Revision 1.4  1992/07/25  03:11:26  julian
        !            49:  * check each request fro sane flags.
        !            50:  *
        !            51:  * Revision 1.3  1992/07/24  00:52:45  julian
        !            52:  * improved timeout handling.
        !            53:  * added support for two arguments to the sd_done (or equiv) call so that
        !            54:  * they can pre-queue several arguments.
        !            55:  * slightly clean up error handling
        !            56:  *
        !            57:  * Revision 1.2  1992/07/17  22:03:54  julian
        !            58:  * upgraded the timeout code.
        !            59:  * added support for UIO-based i/o (as used for pmem operations)
        !            60:  *
        !            61:  * Revision 1.1  1992/05/27  00:51:12  balsup
        !            62:  * machkern/cor merge
        !            63:  */
        !            64: 
        !            65: /*
        !            66:  * a FEW lines in this driver come from a MACH adaptec-disk driver
        !            67:  * so the copyright below is included:
        !            68:  *
        !            69:  * Copyright 1990 by Open Software Foundation,
        !            70:  * Grenoble, FRANCE
        !            71:  *
        !            72:  *             All Rights Reserved
        !            73:  * 
        !            74:  *   Permission to use, copy, modify, and distribute this software and
        !            75:  * its documentation for any purpose and without fee is hereby granted,
        !            76:  * provided that the above copyright notice appears in all copies and
        !            77:  * that both the copyright notice and this permission notice appear in
        !            78:  * supporting documentation, and that the name of OSF or Open Software
        !            79:  * Foundation not be used in advertising or publicity pertaining to
        !            80:  * distribution of the software without specific, written prior
        !            81:  * permission.
        !            82:  * 
        !            83:  *   OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
        !            84:  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
        !            85:  * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
        !            86:  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
        !            87:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
        !            88:  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
        !            89:  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            90:  */
        !            91: 
        !            92: 
        !            93: #include <sys/types.h>
        !            94: #include <aha.h>
        !            95: 
        !            96: #include <sys/param.h>
        !            97: #include <sys/systm.h>
        !            98: #include <sys/errno.h>
        !            99: #include <sys/ioctl.h>
        !           100: #include <sys/buf.h>
        !           101: #include <sys/proc.h>
        !           102: #include <sys/user.h>
        !           103: 
        !           104: #ifdef  MACH    /* EITHER CMU OR OSF */
        !           105: #include <i386/ipl.h>
        !           106: #include <i386at/scsi.h>
        !           107: #include <i386at/scsiconf.h>
        !           108: 
        !           109: #ifdef  OSF     /* OSF ONLY */
        !           110: #include <sys/table.h>
        !           111: #include <i386/handler.h>
        !           112: #include <i386/dispatcher.h>
        !           113: #include <i386/AT386/atbus.h>
        !           114: 
        !           115: #else   OSF     /* CMU ONLY */
        !           116: #include <i386at/atbus.h>
        !           117: #include <i386/pio.h>
        !           118: #endif  OSF
        !           119: #endif  MACH    /* end of MACH specific */
        !           120: 
        !           121: #ifdef  __386BSD__      /* 386BSD specific */
        !           122: #define isa_dev isa_device
        !           123: #define dev_unit id_unit
        !           124: #define dev_addr id_iobase
        !           125: 
        !           126: #include <i386/isa/isa_device.h>
        !           127: #include <scsi/scsi_all.h>
        !           128: #include <scsi/scsiconf.h>
        !           129: 
        !           130: #ifdef DDB
        !           131: int    Debugger();
        !           132: #else
        !           133: #define Debugger() panic("should call debugger here (adaptec.c)")
        !           134: #endif /*!DDB*/
        !           135: 
        !           136: #endif /*__386BSD__*/
        !           137: extern int delaycount;  /* from clock setup code */
        !           138: 
        !           139: /************************** board definitions *******************************/
        !           140: /*
        !           141:  * I/O Port Interface
        !           142:  */
        !           143: 
        !           144: #define        AHA_BASE                aha_base[unit]
        !           145: #define        AHA_CTRL_STAT_PORT      (AHA_BASE + 0x0)        /* control & status */
        !           146: #define        AHA_CMD_DATA_PORT       (AHA_BASE + 0x1)        /* cmds and datas */
        !           147: #define        AHA_INTR_PORT           (AHA_BASE + 0x2)        /* Intr. stat */
        !           148: 
        !           149: /*
        !           150:  * AHA_CTRL_STAT bits (write)
        !           151:  */
        !           152: 
        !           153: #define AHA_HRST               0x80    /* Hardware reset */
        !           154: #define AHA_SRST               0x40    /* Software reset */
        !           155: #define AHA_IRST               0x20    /* Interrupt reset */
        !           156: #define AHA_SCRST              0x10    /* SCSI bus reset */
        !           157: 
        !           158: /*
        !           159:  * AHA_CTRL_STAT bits (read)
        !           160:  */
        !           161: 
        !           162: #define AHA_STST               0x80    /* Self test in Progress */
        !           163: #define AHA_DIAGF              0x40    /* Diagnostic Failure */
        !           164: #define AHA_INIT               0x20    /* Mbx Init required */
        !           165: #define AHA_IDLE               0x10    /* Host Adapter Idle */
        !           166: #define AHA_CDF                        0x08    /* cmd/data out port full */
        !           167: #define AHA_DF                 0x04    /* Data in port full */
        !           168: #define AHA_INVDCMD            0x01    /* Invalid command */
        !           169: 
        !           170: /*
        !           171:  * AHA_CMD_DATA bits (write)
        !           172:  */
        !           173: 
        !           174: #define        AHA_NOP                 0x00    /* No operation */
        !           175: #define AHA_MBX_INIT           0x01    /* Mbx initialization */
        !           176: #define AHA_START_SCSI         0x02    /* start scsi command */
        !           177: #define AHA_START_BIOS         0x03    /* start bios command */
        !           178: #define AHA_INQUIRE            0x04    /* Adapter Inquiry */
        !           179: #define AHA_MBO_INTR_EN                0x05    /* Enable MBO available interrupt */
        !           180: #define AHA_SEL_TIMEOUT_SET    0x06    /* set selection time-out */
        !           181: #define AHA_BUS_ON_TIME_SET    0x07    /* set bus-on time */
        !           182: #define AHA_BUS_OFF_TIME_SET   0x08    /* set bus-off time */
        !           183: #define AHA_SPEED_SET          0x09    /* set transfer speed */
        !           184: #define AHA_DEV_GET            0x0a    /* return installed devices */
        !           185: #define AHA_CONF_GET           0x0b    /* return configuration data */
        !           186: #define AHA_TARGET_EN          0x0c    /* enable target mode */
        !           187: #define AHA_SETUP_GET          0x0d    /* return setup data */
        !           188: #define AHA_WRITE_CH2          0x1a    /* write channel 2 buffer */
        !           189: #define AHA_READ_CH2           0x1b    /* read channel 2 buffer */
        !           190: #define AHA_WRITE_FIFO         0x1c    /* write fifo buffer */
        !           191: #define AHA_READ_FIFO          0x1d    /* read fifo buffer */
        !           192: #define AHA_ECHO               0x1e    /* Echo command data */
        !           193: 
        !           194: struct aha_cmd_buf {
        !           195:         u_char byte[16];       
        !           196: };
        !           197: 
        !           198: /*
        !           199:  * AHA_INTR_PORT bits (read)
        !           200:  */
        !           201: 
        !           202: #define AHA_ANY_INTR           0x80    /* Any interrupt */
        !           203: #define AHA_SCRD               0x08    /* SCSI reset detected */
        !           204: #define AHA_HACC               0x04    /* Command complete */
        !           205: #define AHA_MBOA               0x02    /* MBX out empty */
        !           206: #define AHA_MBIF               0x01    /* MBX in full */
        !           207: 
        !           208: /*
        !           209:  * Mail box defs 
        !           210:  */
        !           211: 
        !           212: #define AHA_MBX_SIZE           16      /* mail box size */
        !           213: 
        !           214: struct aha_mbx {
        !           215:        struct aha_mbx_out {
        !           216:                unsigned char cmd;
        !           217:                unsigned char ccb_addr[3];
        !           218:        } mbo [AHA_MBX_SIZE];
        !           219:        struct aha_mbx_in{
        !           220:                unsigned char stat;
        !           221:                unsigned char ccb_addr[3];
        !           222:        } mbi[AHA_MBX_SIZE];
        !           223: };
        !           224: 
        !           225: /*
        !           226:  * mbo.cmd values
        !           227:  */
        !           228: 
        !           229: #define AHA_MBO_FREE   0x0     /* MBO entry is free */
        !           230: #define AHA_MBO_START  0x1     /* MBO activate entry */
        !           231: #define AHA_MBO_ABORT  0x2     /* MBO abort entry */
        !           232: 
        !           233: #define AHA_MBI_FREE   0x0     /* MBI entry is free */
        !           234: #define AHA_MBI_OK     0x1     /* completed without error */
        !           235: #define AHA_MBI_ABORT  0x2     /* aborted ccb */
        !           236: #define AHA_MBI_UNKNOWN        0x3     /* Tried to abort invalid CCB */
        !           237: #define AHA_MBI_ERROR  0x4     /* Completed with error */
        !           238: 
        !           239: extern struct aha_mbx aha_mbx[];
        !           240: 
        !           241: /* FOR OLD VERSIONS OF THE !%$@ this may have to be 16 (yuk) */
        !           242: #define        AHA_NSEG        17      /* Number of scatter gather segments <= 16 */
        !           243:                                /* allow 64 K i/o (min) */
        !           244: 
        !           245: struct aha_ccb {
        !           246:        unsigned char   opcode;
        !           247:        unsigned char   lun:3;
        !           248:        unsigned char   data_in:1;              /* must be 0 */
        !           249:        unsigned char   data_out:1;             /* must be 0 */
        !           250:        unsigned char   target:3;
        !           251:        unsigned char   scsi_cmd_length;
        !           252:        unsigned char   req_sense_length;
        !           253:        unsigned char   data_length[3];
        !           254:        unsigned char   data_addr[3];
        !           255:        unsigned char   link_addr[3];
        !           256:        unsigned char   link_id;
        !           257:        unsigned char   host_stat;
        !           258:        unsigned char   target_stat;
        !           259:        unsigned char   reserved[2];
        !           260:        struct  scsi_generic    scsi_cmd;
        !           261:        struct  scsi_sense_data scsi_sense;
        !           262:        struct  aha_scat_gath {
        !           263:                unsigned char seg_len[3];
        !           264:                unsigned char seg_addr[3];
        !           265:        } scat_gath[AHA_NSEG];
        !           266:        struct  aha_ccb *next;
        !           267:        struct  scsi_xfer       *xfer;          /* the scsi_xfer for this cmd */
        !           268:        struct  aha_mbx_out     *mbx;           /* pointer to mail box */
        !           269:        long int        delta;  /* difference from previous*/
        !           270:        struct  aha_ccb *later,*sooner;
        !           271:        int     flags;
        !           272: #define CCB_FREE        0
        !           273: #define CCB_ACTIVE      1
        !           274: #define CCB_ABORTED     2
        !           275: 
        !           276: };
        !           277: 
        !           278: struct aha_ccb *aha_soonest = (struct  aha_ccb *)0;
        !           279: struct aha_ccb *aha_latest = (struct  aha_ccb *)0;
        !           280: long int       aha_furtherest = 0;     /* longest time in the timeout queue */
        !           281: 
        !           282: /*
        !           283:  * opcode fields
        !           284:  */
        !           285: 
        !           286: #define AHA_INITIATOR_CCB      0x00    /* SCSI Initiator CCB */
        !           287: #define AHA_TARGET_CCB         0x01    /* SCSI Target CCB */
        !           288: #define AHA_INIT_SCAT_GATH_CCB 0x02    /* SCSI Initiator with scattter gather*/
        !           289: #define AHA_RESET_CCB          0x81    /* SCSI Bus reset */
        !           290: 
        !           291: 
        !           292: /*
        !           293:  * aha_ccb.host_stat values
        !           294:  */
        !           295: 
        !           296: #define AHA_OK         0x00    /* cmd ok */
        !           297: #define AHA_LINK_OK    0x0a    /* Link cmd ok */
        !           298: #define AHA_LINK_IT    0x0b    /* Link cmd ok + int */
        !           299: #define AHA_SEL_TIMEOUT        0x11    /* Selection time out */
        !           300: #define AHA_OVER_UNDER 0x12    /* Data over/under run */
        !           301: #define AHA_BUS_FREE   0x13    /* Bus dropped at unexpected time */
        !           302: #define AHA_INV_BUS    0x14    /* Invalid bus phase/sequence */
        !           303: #define AHA_BAD_MBO    0x15    /* Incorrect MBO cmd */
        !           304: #define AHA_BAD_CCB    0x16    /* Incorrect ccb opcode */
        !           305: #define AHA_BAD_LINK   0x17    /* Not same values of LUN for links */
        !           306: #define AHA_INV_TARGET 0x18    /* Invalid target direction */
        !           307: #define AHA_CCB_DUP    0x19    /* Duplicate CCB received */
        !           308: #define AHA_INV_CCB    0x1a    /* Invalid CCB or segment list */
        !           309: #define AHA_ABORTED      42
        !           310: 
        !           311: 
        !           312: 
        !           313: 
        !           314: struct aha_setup
        !           315: {
        !           316:        u_char  sync_neg:1;
        !           317:        u_char  parity:1;
        !           318:        u_char  :6;
        !           319:        u_char  speed;
        !           320:        u_char  bus_on;
        !           321:        u_char  bus_off;
        !           322:        u_char  num_mbx;
        !           323:        u_char  mbx[3];
        !           324:        struct
        !           325:        {
        !           326:                u_char  offset:4;
        !           327:                u_char  period:3;
        !           328:                u_char  valid:1;
        !           329:        }sync[8];
        !           330:        u_char  disc_sts;
        !           331: };
        !           332: 
        !           333: struct aha_config
        !           334: {
        !           335:        u_char  chan;
        !           336:        u_char  intr;
        !           337:        u_char  scsi_dev:3;
        !           338:        u_char  :5;
        !           339: };
        !           340: 
        !           341: #define INT9   0x01
        !           342: #define INT10  0x02
        !           343: #define INT11  0x04
        !           344: #define INT12  0x08
        !           345: #define INT14  0x20
        !           346: #define INT15  0x40
        !           347: 
        !           348: #define CHAN0  0x01
        !           349: #define CHAN5  0x20
        !           350: #define CHAN6  0x40
        !           351: #define CHAN7  0x80
        !           352: 
        !           353: 
        !           354: /*********************************** end of board definitions***************/
        !           355: 
        !           356: 
        !           357: #ifdef MACH
        !           358: #define PHYSTOKV(x)    phystokv(x)
        !           359: #define KVTOPHYS(x)    kvtophys(x)
        !           360: #else  MACH
        !           361: #ifdef __386BSD__
        !           362: #define PHYSTOKV(x)    (x | 0xFE000000)
        !           363: #define KVTOPHYS(x)    vtophys(x)
        !           364: #else  __386BSD__
        !           365: #endif __386BSD__
        !           366: #endif MACH
        !           367: #define        AHA_DMA_PAGES   AHA_NSEG
        !           368: 
        !           369: #define PAGESIZ        4096
        !           370: #define INVALIDATE_CACHE {asm volatile( ".byte 0x0F ;.byte 0x08" ); }
        !           371: 
        !           372: 
        !           373: u_char                 aha_scratch_buf[256];
        !           374: #ifdef MACH
        !           375: caddr_t                        aha_base[NAHA];         /* base port for each board */
        !           376: #else
        !           377: short                  aha_base[NAHA];         /* base port for each board */
        !           378: #endif
        !           379: struct aha_mbx         aha_mbx[NAHA];
        !           380: struct aha_ccb         *aha_ccb_free[NAHA];
        !           381: struct aha_ccb         aha_ccb[NAHA][AHA_MBX_SIZE];
        !           382: struct scsi_xfer       aha_scsi_xfer[NAHA];
        !           383: struct isa_dev         *ahainfo[NAHA];
        !           384: struct aha_ccb         *aha_get_ccb();
        !           385: int                    aha_int[NAHA];
        !           386: int                    aha_dma[NAHA];
        !           387: int                    aha_scsi_dev[NAHA];
        !           388: int                    aha_initialized[NAHA];
        !           389: #ifdef OSF
        !           390: int                    aha_attached[NAHA];
        !           391: #endif OSF
        !           392: int                    aha_debug = 0;
        !           393: 
        !           394: int ahaprobe(), ahaattach(), ahaintr();
        !           395: #ifdef MACH
        !           396: struct isa_driver      ahadriver = { ahaprobe, 0, ahaattach, "aha", 0, 0, 0};
        !           397: int                    (*ahaintrs[])() = {ahaintr, 0};
        !           398: #endif
        !           399: #ifdef __386BSD__
        !           400: struct isa_driver      ahadriver = { ahaprobe, ahaattach, "aha",};
        !           401: #endif __386BSD__
        !           402: static int             ahaunit = 0;
        !           403: 
        !           404: 
        !           405: #define aha_abortmbx(mbx) \
        !           406:        (mbx)->cmd = AHA_MBO_ABORT; \
        !           407:        outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
        !           408: #define aha_startmbx(mbx) \
        !           409:        (mbx)->cmd = AHA_MBO_START; \
        !           410:        outb(AHA_CMD_DATA_PORT, AHA_START_SCSI);
        !           411: 
        !           412: 
        !           413: 
        !           414: int    aha_scsi_cmd();
        !           415: int    aha_timeout();
        !           416: void   ahaminphys();
        !           417: long int       aha_adapter_info();
        !           418: 
        !           419: struct scsi_switch     aha_switch =
        !           420: {
        !           421:        aha_scsi_cmd,
        !           422:        ahaminphys,
        !           423:        0,
        !           424:        0,
        !           425:        aha_adapter_info,
        !           426:        0,0,0
        !           427: };     
        !           428: #define AHA_CMD_TIMEOUT_FUDGE  200     /* multiplied to get Secs       */
        !           429: #define AHA_RESET_TIMEOUT      1000000 /* time to wait for reset       */
        !           430: #define AHA_SCSI_TIMEOUT_FUDGE 20      /* divided by for mSecs         */
        !           431: 
        !           432: 
        !           433: /***********************************************************************\
        !           434: * aha_cmd(unit,icnt, ocnt,wait, retval, opcode, args)                  *
        !           435: * Activate Adapter command                                             *
        !           436: *      icnt:   number of args (outbound bytes written after opcode)    *
        !           437: *      ocnt:   number of expected returned bytes                       *
        !           438: *      wait:   number of seconds to wait for response                  *
        !           439: *      retval: buffer where to place returned bytes                    *
        !           440: *      opcode: opcode AHA_NOP, AHA_MBX_INIT, AHA_START_SCSI ...        *
        !           441: *      args:   parameters                                              *
        !           442: *                                                                      *
        !           443: * Performs an adapter command through the ports. Not to be confused    *
        !           444: *      with a scsi command, which is read in via the dma               *
        !           445: * One of the adapter commands tells it to read in a scsi command       *
        !           446: \***********************************************************************/
        !           447: 
        !           448: 
        !           449: aha_cmd(unit,icnt, ocnt, wait,retval, opcode, args)
        !           450: 
        !           451: u_char *retval;
        !           452: unsigned opcode;
        !           453: u_char args;
        !           454: {
        !           455:        unsigned *ic = &opcode;
        !           456:        u_char oc;
        !           457:        register i;
        !           458:        int     sts;
        !           459: 
        !           460:        /*******************************************************\
        !           461:        * multiply the wait argument by a big constant          *
        !           462:        * zero defaults to 1                                    *
        !           463:        \*******************************************************/
        !           464:        if(!wait) 
        !           465:                wait = AHA_CMD_TIMEOUT_FUDGE * delaycount; 
        !           466:        else
        !           467:                wait *= AHA_CMD_TIMEOUT_FUDGE * delaycount; 
        !           468:        /*******************************************************\
        !           469:        * Wait for the adapter to go idle, unless it's one of   *
        !           470:        * the commands which don't need this                    *
        !           471:        \*******************************************************/
        !           472:        if (opcode != AHA_MBX_INIT && opcode != AHA_START_SCSI)
        !           473:        {
        !           474:                i = AHA_CMD_TIMEOUT_FUDGE * delaycount; /* 1 sec?*/
        !           475:                while (--i)
        !           476:                {
        !           477:                        sts = inb(AHA_CTRL_STAT_PORT);
        !           478:                        if (sts & AHA_IDLE)
        !           479:                        {
        !           480:                                break;
        !           481:                        }
        !           482:                }
        !           483:                if (!i)
        !           484:                {
        !           485:                        printf("aha_cmd: aha1542 host not idle(0x%x)\n",sts);
        !           486:                        return(ENXIO);
        !           487:                }
        !           488:        }
        !           489:        /*******************************************************\
        !           490:        * Now that it is idle, if we expect output, preflush the*
        !           491:        * queue feeding to us.                                  *
        !           492:        \*******************************************************/
        !           493:        if (ocnt)
        !           494:        {
        !           495:                while((inb(AHA_CTRL_STAT_PORT)) & AHA_DF)
        !           496:                        inb(AHA_CMD_DATA_PORT);
        !           497:        }
        !           498:                        
        !           499:        /*******************************************************\
        !           500:        * Output the command and the number of arguments given  *
        !           501:        * for each byte, first check the port is empty.         *
        !           502:        \*******************************************************/
        !           503:        icnt++;         /* include the command */
        !           504:        while (icnt--)
        !           505:        {
        !           506:                sts = inb(AHA_CTRL_STAT_PORT);
        !           507:                for (i=0; i< wait; i++)
        !           508:                {
        !           509:                        sts = inb(AHA_CTRL_STAT_PORT);
        !           510:                        if (!(sts & AHA_CDF))
        !           511:                                break;
        !           512:                }
        !           513:                if (i >=  wait)
        !           514:                {
        !           515:                        printf("aha_cmd: aha1542 cmd/data port full\n");
        !           516:                        outb(AHA_CTRL_STAT_PORT, AHA_SRST); 
        !           517:                        return(ENXIO);
        !           518:                }
        !           519:                outb(AHA_CMD_DATA_PORT, (u_char)(*ic++));
        !           520:        }
        !           521:        /*******************************************************\
        !           522:        * If we expect input, loop that many times, each time,  *
        !           523:        * looking for the data register to have valid data      *
        !           524:        \*******************************************************/
        !           525:        while (ocnt--)
        !           526:        {
        !           527:                sts = inb(AHA_CTRL_STAT_PORT);
        !           528:                for (i=0; i< wait; i++)
        !           529:                {
        !           530:                        sts = inb(AHA_CTRL_STAT_PORT);
        !           531:                        if (sts  & AHA_DF)
        !           532:                                break;
        !           533:                }
        !           534:                if (i >=  wait)
        !           535:                {
        !           536:                        printf("aha_cmd: aha1542 cmd/data port empty %d\n",ocnt);
        !           537:                        return(ENXIO);
        !           538:                }
        !           539:                oc = inb(AHA_CMD_DATA_PORT);
        !           540:                if (retval)
        !           541:                        *retval++ = oc;
        !           542:        }
        !           543:        /*******************************************************\
        !           544:        * Wait for the board to report a finised instruction    *
        !           545:        \*******************************************************/
        !           546:        i=AHA_CMD_TIMEOUT_FUDGE * delaycount;   /* 1 sec? */
        !           547:        while (--i)
        !           548:        {
        !           549:                sts = inb(AHA_INTR_PORT);
        !           550:                if (sts & AHA_HACC)
        !           551:                {
        !           552:                        break;
        !           553:                }
        !           554:        }
        !           555:        if (!i)
        !           556:        {
        !           557:                printf("aha_cmd: aha1542 host not finished(0x%x)\n",sts);
        !           558:                return(ENXIO);
        !           559:        }
        !           560:        outb(AHA_CTRL_STAT_PORT, AHA_IRST);
        !           561:        return(0);
        !           562: }
        !           563: 
        !           564: /*******************************************************\
        !           565: * Check if the device can be found at the port given   *
        !           566: * and if so, set it up ready for further work          *
        !           567: * as an argument, takes the isa_dev structure from     *
        !           568: * autoconf.c                                           *
        !           569: \*******************************************************/
        !           570: ahaprobe(dev)
        !           571: struct isa_dev *dev;
        !           572: {
        !           573:        int     unit = ahaunit;
        !           574: #if defined(OSF)
        !           575:        static ihandler_t aha_handler[NAHA];
        !           576:        static ihandler_id_t *aha_handler_id[NAHA];
        !           577:        register ihandler_t *chp = &aha_handler[unit];;
        !           578: #endif /* defined(OSF) */
        !           579: 
        !           580:        /***********************************************\
        !           581:        /***********************************************\
        !           582:        * find unit and check we have that many defined *
        !           583:        \***********************************************/
        !           584:        dev->dev_unit = unit;
        !           585:        aha_base[unit] = dev->dev_addr;
        !           586:        if(unit >= NAHA) 
        !           587:        {
        !           588:                printf("aha: unit number (%d) too high\n",unit);
        !           589:                return(0);
        !           590:        }
        !           591:        /***********************************************\
        !           592:        * Try initialise a unit at this location        *
        !           593:        * sets up dma and bus speed, loads aha_int[unit]*
        !           594:        \***********************************************/
        !           595:        if (aha_init(unit) != 0)
        !           596:        {
        !           597:                return(0);
        !           598:        }
        !           599: 
        !           600:        /***********************************************\
        !           601:        * If it's there, put in it's interrupt vectors  *
        !           602:        \***********************************************/
        !           603: #if !defined(OSF)
        !           604: #if    defined MACH
        !           605:        iunit[aha_int[unit]] =unit;
        !           606:        ivect[aha_int[unit]] = ahaintr;
        !           607:        intpri[aha_int[unit]] = dev->dev_spl;
        !           608:        form_pic_mask();
        !           609:        /*take_dev_irq(dev);*/
        !           610: #else
        !           611: #ifdef __386BSD__
        !           612:        dev->id_irq = (1 << aha_int[unit]);
        !           613:        dev->id_drq = aha_dma[unit];
        !           614: #endif __386BSD__
        !           615: #endif
        !           616: #else /* !defined(OSF) */
        !           617:  
        !           618:        chp->ih_level = dev->dev_pic;
        !           619:        chp->ih_handler = dev->dev_intr[0];
        !           620:        chp->ih_resolver = i386_resolver;
        !           621:        chp->ih_rdev = dev;
        !           622:        chp->ih_stats.intr_type = INTR_DEVICE;
        !           623:        chp->ih_stats.intr_cnt = 0;
        !           624:        chp->ih_hparam[0].intparam = unit;
        !           625:        if ((aha_handler_id[unit] = handler_add(chp)) != NULL)
        !           626:                handler_enable(aha_handler_id[unit]);
        !           627:        else
        !           628:                panic("Unable to add aha interrupt handler");
        !           629: #endif /* !defined(OSF) */
        !           630: #ifdef __386BSD__
        !           631:        printf("\n  **");
        !           632: #else  __386BSD__
        !           633:        printf("port=%x spl=%d\n",
        !           634:           dev->dev_addr, dev->dev_spl);
        !           635: #endif __386BSD__
        !           636:        ahaunit ++;
        !           637:        return(1);
        !           638: }
        !           639: 
        !           640: /***********************************************\
        !           641: * Attach all the sub-devices we can find       *
        !           642: \***********************************************/
        !           643: ahaattach(dev)
        !           644: struct isa_dev *dev;
        !           645: {
        !           646:        int     unit = dev->dev_unit;
        !           647: 
        !           648: #ifdef __386BSD__
        !           649:        printf("aha%d: probing for scsi devices..\n", unit);
        !           650: #endif __386BSD__
        !           651:        /***********************************************\
        !           652:        * ask the adapter what subunits are present     *
        !           653:        \***********************************************/
        !           654:        scsi_attachdevs( unit, aha_scsi_dev[unit], &aha_switch);
        !           655: #if defined(OSF)
        !           656:        aha_attached[unit]=1;
        !           657: #endif /* defined(OSF) */
        !           658:        if(!unit) /* only one for all boards */
        !           659:        {
        !           660:                aha_timeout(0);
        !           661:        }
        !           662:        return;
        !           663: }
        !           664: 
        !           665: 
        !           666: /***********************************************\
        !           667: * Return some information to the caller about  *
        !           668: * the adapter and it's capabilities            *
        !           669: \***********************************************/
        !           670: long int aha_adapter_info(unit)
        !           671: int    unit;
        !           672: {
        !           673:        return(2);      /* 2 outstanding requests at a time per device */
        !           674: }
        !           675: 
        !           676: /***********************************************\
        !           677: * Catch an interrupt from the adaptor          *
        !           678: \***********************************************/
        !           679: ahaintr(unit)
        !           680: {
        !           681:        struct aha_ccb *ccb;
        !           682:        unsigned char stat;
        !           683:        register i;
        !           684: 
        !           685:        if(scsi_debug & PRINTROUTINES)
        !           686:                printf("ahaintr ");
        !           687:        /***********************************************\
        !           688:        * First acknowlege the interrupt, Then if it's  *
        !           689:        * not telling about a completed operation       *
        !           690:        * just return.                                  *
        !           691:        \***********************************************/
        !           692:        stat = inb(AHA_INTR_PORT);
        !           693:        outb(AHA_CTRL_STAT_PORT, AHA_IRST);
        !           694:        if(scsi_debug & TRACEINTERRUPTS)
        !           695:                printf("int ");
        !           696:        if (! (stat & AHA_MBIF))
        !           697:                return(1);
        !           698:        if(scsi_debug & TRACEINTERRUPTS)
        !           699:                printf("b ");
        !           700: #if defined(OSF)
        !           701:        if (!aha_attached[unit])
        !           702:        {
        !           703:                return(1);
        !           704:        }
        !           705: #endif /* defined(OSF) */
        !           706:        /***********************************************\
        !           707:        * If it IS then process the competed operation  *
        !           708:        \***********************************************/
        !           709:        for (i = 0; i < AHA_MBX_SIZE; i++)
        !           710:        {
        !           711:                if (aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE) 
        !           712:                {
        !           713:                        ccb = (struct aha_ccb *)PHYSTOKV(
        !           714:                                (_3btol(aha_mbx[unit].mbi[i].ccb_addr)));
        !           715: 
        !           716:                        if((stat =  aha_mbx[unit].mbi[i].stat) != AHA_MBI_OK)
        !           717:                        {
        !           718:                                switch(stat)
        !           719:                                {
        !           720:                                case    AHA_MBI_ABORT:
        !           721:                                        if(aha_debug)
        !           722:                                            printf("abort");
        !           723:                                        ccb->host_stat = AHA_ABORTED;
        !           724:                                        break;
        !           725: 
        !           726:                                case    AHA_MBI_UNKNOWN:
        !           727:                                        ccb = (struct aha_ccb *)0;
        !           728:                                        if(aha_debug)
        !           729:                                             printf("unknown ccb for abort ");
        !           730:                                        /* may have missed it */
        !           731:                                        /* no such ccb known for abort */
        !           732: 
        !           733:                                case    AHA_MBI_ERROR:
        !           734:                                        break;
        !           735: 
        !           736:                                default:
        !           737:                                        panic("Impossible mbxi status");
        !           738: 
        !           739:                                }
        !           740:                                if( aha_debug && ccb )
        !           741:                                {
        !           742:                                        u_char  *cp;
        !           743:                                        cp = (u_char *)(&(ccb->scsi_cmd));
        !           744:                                        printf("op=%x %x %x %x %x %x\n", 
        !           745:                                                cp[0], cp[1], cp[2],
        !           746:                                                cp[3], cp[4], cp[5]);
        !           747:                                        printf("stat %x for mbi[%d]\n"
        !           748:                                                , aha_mbx[unit].mbi[i].stat, i);
        !           749:                                        printf("addr = 0x%x\n", ccb);
        !           750:                                }
        !           751:                        }
        !           752:                        if(ccb)
        !           753:                        {
        !           754:                                aha_remove_timeout(ccb);
        !           755:                                aha_done(unit,ccb);
        !           756:                        }
        !           757:                        aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE;
        !           758:                }
        !           759:        }
        !           760:        return(1);
        !           761: }
        !           762: 
        !           763: /***********************************************\
        !           764: * A ccb (and hence a mbx-out is put onto the   *
        !           765: * free list.                                   *
        !           766: \***********************************************/
        !           767: aha_free_ccb(unit,ccb, flags)
        !           768: struct aha_ccb *ccb;
        !           769: {
        !           770:        unsigned int opri;
        !           771:        
        !           772:        if(scsi_debug & PRINTROUTINES)
        !           773:                printf("ccb%d(0x%x)> ",unit,flags);
        !           774:        if (!(flags & SCSI_NOMASK)) 
        !           775:                opri = splbio();
        !           776: 
        !           777:        ccb->next = aha_ccb_free[unit];
        !           778:        aha_ccb_free[unit] = ccb;
        !           779:        ccb->flags = CCB_FREE;
        !           780:        if(ccb->sooner || ccb->later)
        !           781:        {
        !           782:                printf("yikes, still in timeout queue\n");
        !           783:                aha_remove_timeout(ccb);
        !           784:        }
        !           785:        /***********************************************\
        !           786:        * If there were none, wake abybody waiting for  *
        !           787:        * one to come free, starting with queued entries*
        !           788:        \***********************************************/
        !           789:        if (!ccb->next) {
        !           790:                wakeup(&aha_ccb_free[unit]);
        !           791:        }
        !           792:        if (!(flags & SCSI_NOMASK)) 
        !           793:                splx(opri);
        !           794: }
        !           795: 
        !           796: /***********************************************\
        !           797: * Get a free ccb (and hence mbox-out entry)    *
        !           798: \***********************************************/
        !           799: struct aha_ccb *
        !           800: aha_get_ccb(unit,flags)
        !           801: {
        !           802:        unsigned opri;
        !           803:        struct aha_ccb *rc;
        !           804: 
        !           805:        if(scsi_debug & PRINTROUTINES)
        !           806:                printf("<ccb%d(0x%x) ",unit,flags);
        !           807:        if (!(flags & SCSI_NOMASK)) 
        !           808:                opri = splbio();
        !           809:        /***********************************************\
        !           810:        * If we can and have to, sleep waiting for one  *
        !           811:        * to come free                                  *
        !           812:        \***********************************************/
        !           813:        while ((!(rc = aha_ccb_free[unit])) && (!(flags & SCSI_NOSLEEP)))
        !           814:        {
        !           815:                sleep(&aha_ccb_free[unit], PRIBIO);
        !           816:        }
        !           817:        if (rc) 
        !           818:        {
        !           819:                aha_ccb_free[unit] = aha_ccb_free[unit]->next;
        !           820:                rc->flags = CCB_ACTIVE;
        !           821:        }
        !           822:        if (!(flags & SCSI_NOMASK)) 
        !           823:                splx(opri);
        !           824:        return(rc);
        !           825: }
        !           826:                
        !           827: 
        !           828: /***********************************************\
        !           829: * We have a ccb which has been processed by the        *
        !           830: * adaptor, now we look to see how the operation        *
        !           831: * went. Wake up the owner if waiting           *
        !           832: \***********************************************/
        !           833: aha_done(unit,ccb)
        !           834: struct aha_ccb *ccb;
        !           835: {
        !           836:        struct  scsi_sense_data *s1,*s2;
        !           837:        struct  scsi_xfer *xs = ccb->xfer;
        !           838: 
        !           839:        if(scsi_debug & PRINTROUTINES )
        !           840:                printf("aha_done ");
        !           841:        /***********************************************\
        !           842:        * Otherwise, put the results of the operation   *
        !           843:        * into the xfer and call whoever started it     *
        !           844:        \***********************************************/
        !           845:        if(!(xs->flags & INUSE))
        !           846:        {
        !           847:                printf("exiting but not in use! ");
        !           848:                Debugger();
        !           849:        }
        !           850:        if (    (       ccb->host_stat != AHA_OK 
        !           851:                        || ccb->target_stat != SCSI_OK)
        !           852:              && (!(xs->flags & SCSI_ERR_OK)))
        !           853:        {
        !           854:                s1 = (struct scsi_sense_data *)(((char *)(&ccb->scsi_cmd)) 
        !           855:                                + ccb->scsi_cmd_length);
        !           856:                s2 = &(xs->sense);
        !           857: 
        !           858:                if(ccb->host_stat)
        !           859:                {
        !           860:                        switch(ccb->host_stat)
        !           861:                        {
        !           862:                        case    AHA_ABORTED:
        !           863:                        case    AHA_SEL_TIMEOUT:        /* No response */
        !           864:                                xs->error = XS_TIMEOUT;
        !           865:                                break;
        !           866:                        default:        /* Other scsi protocol messes */
        !           867:                                xs->error = XS_DRIVER_STUFFUP;
        !           868:                                if (aha_debug > 1)
        !           869:                                {
        !           870:                                        printf("host_stat%x\n",
        !           871:                                                ccb->host_stat);
        !           872:                                }
        !           873:                        }
        !           874: 
        !           875:                }
        !           876:                else
        !           877:                {
        !           878:                        switch(ccb->target_stat)
        !           879:                        {
        !           880:                        case 0x02:
        !           881:                                /* structure copy!!!!!*/
        !           882:                                *s2=*s1;
        !           883:                                xs->error = XS_SENSE;
        !           884:                                break;
        !           885:                        case 0x08:
        !           886:                                xs->error = XS_BUSY;
        !           887:                                break;
        !           888:                        default:
        !           889:                                if (aha_debug > 1)
        !           890:                                {
        !           891:                                        printf("target_stat%x\n",
        !           892:                                                ccb->target_stat);
        !           893:                                }
        !           894:                                xs->error = XS_DRIVER_STUFFUP;
        !           895:                        }
        !           896:                }
        !           897:        }
        !           898:        else            /* All went correctly  OR errors expected */
        !           899:        {
        !           900:                xs->resid = 0;
        !           901:        }
        !           902:        xs->flags |= ITSDONE;
        !           903:        aha_free_ccb(unit,ccb, xs->flags);
        !           904:        if(xs->when_done)
        !           905:                (*(xs->when_done))(xs->done_arg,xs->done_arg2);
        !           906: }
        !           907: 
        !           908: 
        !           909: /***********************************************\
        !           910: * Start the board, ready for normal operation  *
        !           911: \***********************************************/
        !           912: aha_init(unit)
        !           913: int    unit;
        !           914: {
        !           915:        unsigned char ad[3];
        !           916:        volatile int i,sts;
        !           917:        struct  aha_config conf;
        !           918: 
        !           919:        /***********************************************\
        !           920:        * reset board, If it doesn't respond, assume    *
        !           921:        * that it's not there.. good for the probe      *
        !           922:        \***********************************************/
        !           923: 
        !           924:        outb(AHA_CTRL_STAT_PORT, AHA_HRST|AHA_SRST);
        !           925: 
        !           926:        for (i=0; i < AHA_RESET_TIMEOUT; i++)
        !           927:        {
        !           928:                sts = inb(AHA_CTRL_STAT_PORT) ;
        !           929:                if ( sts == (AHA_IDLE | AHA_INIT))
        !           930:                        break;
        !           931:        }
        !           932:        if (i >= AHA_RESET_TIMEOUT)
        !           933:        {
        !           934:                if (aha_debug)
        !           935:                        printf("aha_init: No answer from adaptec board\n");
        !           936:                return(ENXIO);
        !           937:        }
        !           938: 
        !           939:        /***********************************************\
        !           940:        * Assume we have a board at this stage          *
        !           941:        * setup dma channel from jumpers and save int   *
        !           942:        * level                                         *
        !           943:        \***********************************************/
        !           944: #ifdef __386BSD__
        !           945:        printf("aha%d reading board settings, ",unit);
        !           946: #define        PRNT(x)
        !           947: #else  __386BSD__
        !           948:        printf("aha%d:",unit);
        !           949: #define        PRNT(x) printf(x)
        !           950: #endif __386BSD__
        !           951:        aha_cmd(unit,0, sizeof(conf), 0 ,&conf, AHA_CONF_GET);
        !           952:        switch(conf.chan)
        !           953:        {
        !           954:        case    CHAN0:
        !           955:                outb(0x0b, 0x0c);
        !           956:                outb(0x0a, 0x00);
        !           957:                aha_dma[unit] = 0;
        !           958:                PRNT("dma=0 ");
        !           959:                break;
        !           960:        case    CHAN5:
        !           961:                outb(0xd6, 0xc1);
        !           962:                outb(0xd4, 0x01);
        !           963:                aha_dma[unit] = 5;
        !           964:                PRNT("dma=5 ");
        !           965:                break;
        !           966:        case    CHAN6:
        !           967:                outb(0xd6, 0xc2);
        !           968:                outb(0xd4, 0x02);
        !           969:                aha_dma[unit] = 6;
        !           970:                PRNT("dma=6 ");
        !           971:                break;
        !           972:        case    CHAN7:
        !           973:                outb(0xd6, 0xc3);
        !           974:                outb(0xd4, 0x03);
        !           975:                aha_dma[unit] = 7;
        !           976:                PRNT("dma=7 ");
        !           977:                break;
        !           978:        default:
        !           979:                printf("illegal dma jumper setting\n");
        !           980:                return(EIO);
        !           981:        }
        !           982:        switch(conf.intr)
        !           983:        {
        !           984:        case    INT9:
        !           985:                aha_int[unit] = 9;
        !           986:                PRNT("int=9 ");
        !           987:                break;
        !           988:        case    INT10:
        !           989:                aha_int[unit] = 10;
        !           990:                PRNT("int=10 ");
        !           991:                break;
        !           992:        case    INT11:
        !           993:                aha_int[unit] = 11;
        !           994:                PRNT("int=11 ");
        !           995:                break;
        !           996:        case    INT12:
        !           997:                aha_int[unit] = 12;
        !           998:                PRNT("int=12 ");
        !           999:                break;
        !          1000:        case    INT14:
        !          1001:                aha_int[unit] = 14;
        !          1002:                PRNT("int=14 ");
        !          1003:                break;
        !          1004:        case    INT15:
        !          1005:                aha_int[unit] = 15;
        !          1006:                PRNT("int=15 ");
        !          1007:                break;
        !          1008:        default:
        !          1009:                printf("illegal int jumper setting\n");
        !          1010:                return(EIO);
        !          1011:        }
        !          1012:        /* who are we on the scsi bus */
        !          1013:        aha_scsi_dev[unit] = conf.scsi_dev;
        !          1014: 
        !          1015: 
        !          1016:        /***********************************************\
        !          1017:        * Initialize memory transfer speed              *
        !          1018:        \***********************************************/
        !          1019:        if(!(aha_set_bus_speed(unit)))
        !          1020:        {
        !          1021:                return(EIO);
        !          1022:        }
        !          1023:        
        !          1024: 
        !          1025:        /***********************************************\
        !          1026:        * Initialize mail box                           *
        !          1027:        \***********************************************/
        !          1028: 
        !          1029:        lto3b(KVTOPHYS(&aha_mbx[unit]), ad);
        !          1030: 
        !          1031:        aha_cmd(unit,4, 0, 0, 0, AHA_MBX_INIT,
        !          1032:                        AHA_MBX_SIZE,
        !          1033:                        ad[0],
        !          1034:                        ad[1],
        !          1035:                        ad[2]);
        !          1036: 
        !          1037: 
        !          1038:        /***********************************************\
        !          1039:        * link the ccb's with the mbox-out entries and  *
        !          1040:        * into a free-list                              *
        !          1041:        \***********************************************/
        !          1042:        for (i=0; i < AHA_MBX_SIZE; i++) {
        !          1043:                aha_ccb[unit][i].next = aha_ccb_free[unit];
        !          1044:                aha_ccb_free[unit] = &aha_ccb[unit][i];
        !          1045:                aha_ccb_free[unit]->flags = CCB_FREE;
        !          1046:                aha_ccb_free[unit]->mbx = &aha_mbx[unit].mbo[i];
        !          1047:                lto3b(KVTOPHYS(aha_ccb_free[unit]), aha_mbx[unit].mbo[i].ccb_addr);
        !          1048:        }
        !          1049: 
        !          1050:        /***********************************************\
        !          1051:        * Note that we are going and return (to probe)  *
        !          1052:        \***********************************************/
        !          1053:        aha_initialized[unit]++;
        !          1054:        return(0);
        !          1055: }
        !          1056: 
        !          1057: 
        !          1058: 
        !          1059: 
        !          1060: 
        !          1061: void ahaminphys(bp)
        !          1062: struct buf *bp;
        !          1063: {
        !          1064: #ifdef MACH
        !          1065: #if !defined(OSF)
        !          1066:        bp->b_flags |= B_NPAGES;                /* can support scat/gather */
        !          1067: #endif /* !defined(OSF) */
        !          1068: #endif MACH
        !          1069: /*     aha seems to explode with 17 segs (64k may require 17 segs) */
        !          1070: /*     on old boards so use a max of 16 segs if you have problems here*/
        !          1071:        if(bp->b_bcount > ((AHA_NSEG - 1) * PAGESIZ))
        !          1072:        {
        !          1073:                bp->b_bcount = ((AHA_NSEG - 1) * PAGESIZ);
        !          1074:        }
        !          1075: }
        !          1076:        
        !          1077: /***********************************************\
        !          1078: * start a scsi operation given the command and *
        !          1079: * the data address. Also needs the unit, target        *
        !          1080: * and lu                                       *
        !          1081: \***********************************************/
        !          1082: int    aha_scsi_cmd(xs)
        !          1083: struct scsi_xfer *xs;
        !          1084: {
        !          1085:        struct  scsi_sense_data *s1,*s2;
        !          1086:        struct aha_ccb *ccb;
        !          1087:        struct aha_scat_gath *sg;
        !          1088:        int     seg;    /* scatter gather seg being worked on */
        !          1089:        int i   = 0;
        !          1090:        int rc  =  0;
        !          1091:        int     thiskv;
        !          1092:        int     thisphys,nextphys;
        !          1093:        int     unit =xs->adapter;
        !          1094:        int     bytes_this_seg,bytes_this_page,datalen,flags;
        !          1095:        struct  iovec   *iovp;
        !          1096:        int     s;
        !          1097: 
        !          1098:        if(scsi_debug & PRINTROUTINES)
        !          1099:                printf("aha_scsi_cmd ");
        !          1100:        /***********************************************\
        !          1101:        * get a ccb (mbox-out) to use. If the transfer  *
        !          1102:        * is from a buf (possibly from interrupt time)  *
        !          1103:        * then we can't allow it to sleep               *
        !          1104:        \***********************************************/
        !          1105:        flags = xs->flags;
        !          1106:        if(!(flags & INUSE))
        !          1107:        {
        !          1108:                printf("not in use!");
        !          1109:                Debugger();
        !          1110:                xs->flags |= INUSE;
        !          1111:        }
        !          1112:        if(flags & ITSDONE)
        !          1113:        {
        !          1114:                printf("Already done! check device retry code ");
        !          1115:                Debugger();
        !          1116:                xs->flags &= ~ITSDONE;
        !          1117:        }
        !          1118:        if(xs->bp) flags |= (SCSI_NOSLEEP); /* just to be sure */
        !          1119:        if (!(ccb = aha_get_ccb(unit,flags)))
        !          1120:        {
        !          1121:                xs->error = XS_DRIVER_STUFFUP;
        !          1122:                return(TRY_AGAIN_LATER);
        !          1123:        }
        !          1124: 
        !          1125:        if (ccb->mbx->cmd != AHA_MBO_FREE)
        !          1126:                printf("MBO not free\n");
        !          1127: 
        !          1128:        /***********************************************\
        !          1129:        * Put all the arguments for the xfer in the ccb *
        !          1130:        \***********************************************/
        !          1131:        ccb->xfer               =       xs;
        !          1132:        if(flags & SCSI_RESET)
        !          1133:        {
        !          1134:                ccb->opcode     =       AHA_RESET_CCB;
        !          1135:        }
        !          1136:        else
        !          1137:        {
        !          1138:                /* can't use S/G if zero length */
        !          1139:                ccb->opcode     =       (xs->datalen?
        !          1140:                                                AHA_INIT_SCAT_GATH_CCB
        !          1141:                                                :AHA_INITIATOR_CCB);
        !          1142:        }
        !          1143:        ccb->target             =       xs->targ;;
        !          1144:        ccb->data_out           =       0;
        !          1145:        ccb->data_in            =       0;
        !          1146:        ccb->lun                =       xs->lu;
        !          1147:        ccb->scsi_cmd_length    =       xs->cmdlen;
        !          1148:        ccb->req_sense_length   =       sizeof(ccb->scsi_sense);
        !          1149: 
        !          1150:        if((xs->datalen) && (!(flags & SCSI_RESET)))
        !          1151:        { /* can use S/G only if not zero length */
        !          1152:                lto3b(KVTOPHYS(ccb->scat_gath), ccb->data_addr );
        !          1153:                sg              =       ccb->scat_gath ;
        !          1154:                seg             =       0;
        !          1155:                if(flags & SCSI_DATA_UIO)
        !          1156:                {
        !          1157:                        iovp = ((struct uio *)xs->data)->uio_iov;
        !          1158:                        datalen = ((struct uio *)xs->data)->uio_iovcnt;
        !          1159:                        while ((datalen) && (seg < AHA_NSEG))
        !          1160:                        {
        !          1161:                                lto3b(iovp->iov_base,&(sg->seg_addr));
        !          1162:                                lto3b(iovp->iov_len,&(sg->seg_len));
        !          1163:                                if(scsi_debug & SHOWSCATGATH)
        !          1164:                                        printf("(0x%x@0x%x)"
        !          1165:                                                        ,iovp->iov_len
        !          1166:                                                        ,iovp->iov_base);
        !          1167:                                sg++;
        !          1168:                                iovp++;
        !          1169:                                seg++;
        !          1170:                                datalen--;
        !          1171:                        }
        !          1172:                }
        !          1173:                else
        !          1174:                {
        !          1175:                        /***********************************************\
        !          1176:                        * Set up the scatter gather block               *
        !          1177:                        \***********************************************/
        !          1178:                
        !          1179:                        if(scsi_debug & SHOWSCATGATH)
        !          1180:                                printf("%d @0x%x:- ",xs->datalen,xs->data);
        !          1181:                        datalen         =       xs->datalen;
        !          1182:                        thiskv          =       (int)xs->data;
        !          1183:                        thisphys        =       KVTOPHYS(thiskv);
        !          1184:                
        !          1185:                        while ((datalen) && (seg < AHA_NSEG))
        !          1186:                        {
        !          1187:                                bytes_this_seg  = 0;
        !          1188:        
        !          1189:                                /* put in the base address */
        !          1190:                                lto3b(thisphys,&(sg->seg_addr));
        !          1191:                
        !          1192:                                if(scsi_debug & SHOWSCATGATH)
        !          1193:                                        printf("0x%x",thisphys);
        !          1194:        
        !          1195:                                /* do it at least once */
        !          1196:                                nextphys = thisphys;    
        !          1197:                                while ((datalen) && (thisphys == nextphys))
        !          1198:                                /***************************************\
        !          1199:                                * This page is contiguous (physically)  *
        !          1200:                                * with the the last, just extend the    *
        !          1201:                                * length                                *
        !          1202:                                \***************************************/
        !          1203:                                {
        !          1204:                                        /** how far to the end of the page ***/
        !          1205:                                        nextphys = (thisphys & (~(PAGESIZ - 1)))
        !          1206:                                                                + PAGESIZ;
        !          1207:                                        bytes_this_page = nextphys - thisphys;
        !          1208:                                        /**** or the data ****/
        !          1209:                                        bytes_this_page = min(bytes_this_page
        !          1210:                                                                ,datalen);
        !          1211:                                        bytes_this_seg  += bytes_this_page;
        !          1212:                                        datalen         -= bytes_this_page;
        !          1213:                
        !          1214:                                        /**** get more ready for the next page ****/
        !          1215:                                        thiskv  = (thiskv & (~(PAGESIZ - 1)))
        !          1216:                                                                + PAGESIZ;
        !          1217:                                        if(datalen)
        !          1218:                                                thisphys = KVTOPHYS(thiskv);
        !          1219:                                }
        !          1220:                                /***************************************\
        !          1221:                                * next page isn't contiguous, finish the seg*
        !          1222:                                \***************************************/
        !          1223:                                if(scsi_debug & SHOWSCATGATH)
        !          1224:                                        printf("(0x%x)",bytes_this_seg);
        !          1225:                                lto3b(bytes_this_seg,&(sg->seg_len));   
        !          1226:                                sg++;
        !          1227:                                seg++;
        !          1228:                        }
        !          1229:                }
        !          1230:                lto3b(seg * sizeof(struct aha_scat_gath),ccb->data_length);
        !          1231:                if(scsi_debug & SHOWSCATGATH)
        !          1232:                        printf("\n");
        !          1233:                if (datalen)
        !          1234:                { /* there's still data, must have run out of segs! */
        !          1235:                        printf("aha_scsi_cmd%d: more than %d DMA segs\n",
        !          1236:                                unit,AHA_NSEG);
        !          1237:                        xs->error = XS_DRIVER_STUFFUP;
        !          1238:                        aha_free_ccb(unit,ccb,flags);
        !          1239:                        return(HAD_ERROR);
        !          1240:                }
        !          1241: 
        !          1242:        }
        !          1243:        else
        !          1244:        {       /* No data xfer, use non S/G values */
        !          1245:                lto3b(0, ccb->data_addr );
        !          1246:                lto3b(0,ccb->data_length);
        !          1247:        }
        !          1248:        lto3b(0, ccb->link_addr );
        !          1249:        /***********************************************\
        !          1250:        * Put the scsi command in the ccb and start it  *
        !          1251:        \***********************************************/
        !          1252:        if(!(flags & SCSI_RESET))
        !          1253:                bcopy(xs->cmd, &ccb->scsi_cmd, ccb->scsi_cmd_length);
        !          1254:        if(scsi_debug & SHOWCOMMANDS)
        !          1255:        {
        !          1256:                u_char  *b = (u_char *)&ccb->scsi_cmd;
        !          1257:                if(!(flags & SCSI_RESET))
        !          1258:                {
        !          1259:                        int i = 0;
        !          1260:                        printf("aha%d:%d:%d-"
        !          1261:                                ,unit
        !          1262:                                ,ccb->target
        !          1263:                                ,ccb->lun );
        !          1264:                                while(i < ccb->scsi_cmd_length )
        !          1265:                                {
        !          1266:                                        if(i) printf(",");
        !          1267:                                         printf("%x",b[i++]);
        !          1268:                                }
        !          1269:                }
        !          1270:                else
        !          1271:                {
        !          1272:                        printf("aha%d:%d:%d-RESET- " 
        !          1273:                                ,unit 
        !          1274:                                ,ccb->target
        !          1275:                                ,ccb->lun
        !          1276:                        );
        !          1277:                }
        !          1278:        }
        !          1279:        if (!(flags & SCSI_NOMASK))
        !          1280:        {
        !          1281:                s= splbio(); /* stop instant timeouts */
        !          1282:                aha_add_timeout(ccb,xs->timeout);
        !          1283:                aha_startmbx(ccb->mbx);
        !          1284:                /***********************************************\
        !          1285:                * Usually return SUCCESSFULLY QUEUED            *
        !          1286:                \***********************************************/
        !          1287:                splx(s);
        !          1288:                if(scsi_debug & TRACEINTERRUPTS)
        !          1289:                        printf("sent ");
        !          1290:                return(SUCCESSFULLY_QUEUED);
        !          1291:        }
        !          1292:        aha_startmbx(ccb->mbx);
        !          1293:        if(scsi_debug & TRACEINTERRUPTS)
        !          1294:                printf("cmd_sent, waiting ");
        !          1295:        /***********************************************\
        !          1296:        * If we can't use interrupts, poll on completion*
        !          1297:        \***********************************************/
        !          1298:        {
        !          1299:                int done = 0;
        !          1300:                int count = delaycount * xs->timeout / AHA_SCSI_TIMEOUT_FUDGE;
        !          1301:                while((!done) && count)
        !          1302:                {
        !          1303:                        i=0;
        !          1304:                        while ( (!done) && i<AHA_MBX_SIZE)
        !          1305:                        {
        !          1306:                                if ((aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE )
        !          1307:                                   && (PHYSTOKV(_3btol(aha_mbx[unit].mbi[i].ccb_addr)
        !          1308:                                        == (int)ccb)))
        !          1309:                                {
        !          1310:                                        aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE;
        !          1311:                                        aha_done(unit,ccb);
        !          1312:                                        done++;
        !          1313:                                }
        !          1314:                                i++;
        !          1315:                        }
        !          1316:                        count--;
        !          1317:                }
        !          1318:                if (!count)
        !          1319:                {
        !          1320:                        if (!(xs->flags & SCSI_SILENT))
        !          1321:                                printf("cmd fail\n");
        !          1322:                        aha_abortmbx(ccb->mbx);
        !          1323:                        count = delaycount * 2000 / AHA_SCSI_TIMEOUT_FUDGE;
        !          1324:                        while((!done) && count)
        !          1325:                        {
        !          1326:                                i=0;
        !          1327:                                while ( (!done) && i<AHA_MBX_SIZE)
        !          1328:                                {
        !          1329:                                        if ((aha_mbx[unit].mbi[i].stat != AHA_MBI_FREE )
        !          1330:                                        && (PHYSTOKV(_3btol(aha_mbx[unit].mbi[i].ccb_addr)
        !          1331:                                                == (int)ccb)))
        !          1332:                                        {
        !          1333:                                                aha_mbx[unit].mbi[i].stat = AHA_MBI_FREE;
        !          1334:                                                aha_done(unit,ccb);
        !          1335:                                                done++;
        !          1336:                                        }
        !          1337:                                        i++;
        !          1338:                                }
        !          1339:                                count--;
        !          1340:                        }
        !          1341:                        if(!count)
        !          1342:                        {
        !          1343:                                printf("abort failed in wait\n");
        !          1344:                                ccb->mbx->cmd = AHA_MBO_FREE;
        !          1345:                        }
        !          1346:                        aha_free_ccb(unit,ccb,flags);
        !          1347:                        ahaintr(unit);
        !          1348:                        xs->error = XS_DRIVER_STUFFUP;
        !          1349:                        return(HAD_ERROR);
        !          1350:                }
        !          1351:                ahaintr(unit);
        !          1352:                if(xs->error) return(HAD_ERROR);
        !          1353:                return(COMPLETE);
        !          1354: 
        !          1355:        } 
        !          1356: }
        !          1357: /***************************************************************\
        !          1358: * try each speed in turn, when we find one that works, use     *
        !          1359: * the NEXT one for a safety margin, unless that doesn't exist  *
        !          1360: * or doesn't work. returns the nSEC value of the time used     *
        !          1361: * or 0 if it could get a working speed ( or the NEXT speed     *
        !          1362: * failed)                                                      *
        !          1363: \***************************************************************/
        !          1364: 
        !          1365: int    aha_set_bus_speed(unit)
        !          1366: int    unit;
        !          1367: {
        !          1368:        int     speed;
        !          1369:        int     retval,retval2;
        !          1370: 
        !          1371: #ifdef EISA
        !          1372:        speed = 0; /* start at the fastest */
        !          1373: #else  EISA
        !          1374:        speed = 1; /* 100 ns can crash some ISA busses (!?!) */
        !          1375: #endif EISA
        !          1376:        while (1)
        !          1377:        {
        !          1378:                retval = aha_bus_speed_check(unit,speed);
        !          1379:                if(retval == HAD_ERROR) 
        !          1380:                {
        !          1381:                        printf("no working bus speed!!!\n");
        !          1382:                        return(0);
        !          1383:                }
        !          1384:                if(retval == 0)
        !          1385:                {
        !          1386:                        speed++;
        !          1387:                }
        !          1388:                else    /* Go one slower to be safe */
        !          1389:                {       /* unless eisa at 100 ns.. trust it */
        !          1390:                        if(speed != 0)
        !          1391:                        {
        !          1392:                                speed++;
        !          1393:                        }
        !          1394:                        printf("%d nSEC ok, use ",retval);
        !          1395:                        retval2 = aha_bus_speed_check(unit,speed);
        !          1396:                        if(retval2 == HAD_ERROR) /* retval is slowest already */
        !          1397:                        {
        !          1398:                                printf("marginal ");
        !          1399:                                retval2 = retval;
        !          1400:                        }
        !          1401:                        if(retval2)
        !          1402:                        {
        !          1403:                                printf("%d nSEC ",retval2);
        !          1404:                                return(retval2);
        !          1405:                        }
        !          1406:                        else
        !          1407:                        {
        !          1408:                                printf(".. slower failed, abort.\n",retval);
        !          1409:                                return(0);
        !          1410:                        }
        !          1411: 
        !          1412:                }
        !          1413:        }
        !          1414: }
        !          1415: 
        !          1416: /***************************************************************\
        !          1417: * Set the DMA speed to the Nth speed and try an xfer. If it    *
        !          1418: * fails return 0, if it succeeds return the nSec value selected        *
        !          1419: * If there is no such speed return HAD_ERROR.                  *
        !          1420: \***************************************************************/
        !          1421: static struct bus_speed
        !          1422: {
        !          1423:        char    arg;
        !          1424:        int     nsecs;
        !          1425: }aha_bus_speeds[] =
        !          1426: {
        !          1427:        {0x88,100},
        !          1428:        {0x99,150},
        !          1429:        {0xaa,200},
        !          1430:        {0xbb,250},
        !          1431:        {0xcc,300},
        !          1432:        {0xdd,350},
        !          1433:        {0xee,400},
        !          1434:        {0xff,450}
        !          1435: };
        !          1436: static char aha_test_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz!@";
        !          1437: 
        !          1438: int aha_bus_speed_check(unit,speed)
        !          1439: int    unit,speed;
        !          1440: {
        !          1441:        int     numspeeds = sizeof(aha_bus_speeds)/sizeof(struct bus_speed);
        !          1442:        u_char  ad[3];
        !          1443: 
        !          1444:        /*******************************************************\
        !          1445:        * Check we have such an entry                           *
        !          1446:        \*******************************************************/
        !          1447:        if(speed >= numspeeds) return(HAD_ERROR);       /* illegal speed */
        !          1448:        
        !          1449:        /*******************************************************\
        !          1450:        * Set the dma-speed                                     *
        !          1451:        \*******************************************************/
        !          1452:        aha_cmd(unit,1, 0, 0, 0, AHA_SPEED_SET,aha_bus_speeds[speed].arg);
        !          1453: 
        !          1454:        /*******************************************************\
        !          1455:        * put the test data into the buffer and calculate       *
        !          1456:        * it's address. Read it onto the board                  *
        !          1457:        \*******************************************************/
        !          1458:        strcpy(aha_scratch_buf,aha_test_string);
        !          1459:        lto3b(KVTOPHYS(aha_scratch_buf),ad);
        !          1460: 
        !          1461:        aha_cmd(unit,3, 0, 0, 0, AHA_WRITE_FIFO, ad[0], ad[1], ad[2]);
        !          1462: 
        !          1463:        /*******************************************************\
        !          1464:        * clear the buffer then copy the contents back from the *
        !          1465:        * board.                                                *
        !          1466:        \*******************************************************/
        !          1467:        bzero(aha_scratch_buf,54);      /* 54 bytes transfered by test */
        !          1468: 
        !          1469:        aha_cmd(unit,3, 0, 0, 0, AHA_READ_FIFO, ad[0], ad[1], ad[2]);
        !          1470: 
        !          1471:        /*******************************************************\
        !          1472:        * Compare the original data and the final data and      *
        !          1473:        * return the correct value depending upon the result    *
        !          1474:        \*******************************************************/
        !          1475:        if(strcmp(aha_test_string,aha_scratch_buf))
        !          1476:        {       /* copy failed.. assume too fast */
        !          1477:                return(0);
        !          1478:        }
        !          1479:        else
        !          1480:        {       /* copy succeded assume speed ok */
        !          1481:                return(aha_bus_speeds[speed].nsecs);
        !          1482:        }
        !          1483: }
        !          1484: 
        !          1485: 
        !          1486: /*
        !          1487:  *                +----------+    +----------+    +----------+
        !          1488:  * aha_soonest--->|    later |--->|     later|--->|     later|-->0
        !          1489:  *                | [Delta]  |    | [Delta]  |    | [Delta]  |
        !          1490:  *           0<---|sooner    |<---|sooner    |<---|sooner    |<---aha_latest
        !          1491:  *                +----------+    +----------+    +----------+
        !          1492:  *
        !          1493:  *     aha_furtherest = sum(Delta[1..n])
        !          1494:  */
        !          1495: aha_add_timeout(ccb,time)
        !          1496: struct aha_ccb *ccb;
        !          1497: int    time;
        !          1498: {
        !          1499:        int     timeprev;
        !          1500:        struct aha_ccb *prev;
        !          1501:        int     s = splbio();
        !          1502: 
        !          1503:        if(prev = aha_latest) /* yes, an assign */
        !          1504:        {
        !          1505:                timeprev = aha_furtherest;
        !          1506:        }
        !          1507:        else
        !          1508:        {
        !          1509:                timeprev = 0;
        !          1510:        }
        !          1511:        while(prev && (timeprev > time)) 
        !          1512:        {
        !          1513:                timeprev -= prev->delta;
        !          1514:                prev = prev->sooner;
        !          1515:        }
        !          1516:        if(prev)
        !          1517:        {
        !          1518:                ccb->delta = time - timeprev;
        !          1519:                if( ccb->later = prev->later) /* yes an assign */
        !          1520:                {
        !          1521:                        ccb->later->sooner = ccb;
        !          1522:                        ccb->later->delta -= ccb->delta;
        !          1523:                }
        !          1524:                else
        !          1525:                {
        !          1526:                        aha_furtherest = time;
        !          1527:                        aha_latest = ccb;
        !          1528:                }
        !          1529:                ccb->sooner = prev;
        !          1530:                prev->later = ccb;
        !          1531:        }
        !          1532:        else
        !          1533:        {
        !          1534:                if( ccb->later = aha_soonest) /* yes, an assign*/
        !          1535:                {
        !          1536:                        ccb->later->sooner = ccb;
        !          1537:                        ccb->later->delta -= time;
        !          1538:                }
        !          1539:                else
        !          1540:                {
        !          1541:                        aha_furtherest = time;
        !          1542:                        aha_latest = ccb;
        !          1543:                }
        !          1544:                ccb->delta = time;
        !          1545:                ccb->sooner = (struct aha_ccb *)0;
        !          1546:                aha_soonest = ccb;
        !          1547:        }
        !          1548:        splx(s);
        !          1549: }
        !          1550: 
        !          1551: aha_remove_timeout(ccb)
        !          1552: struct aha_ccb *ccb;
        !          1553: {
        !          1554:        int     s = splbio();
        !          1555: 
        !          1556:        if(ccb->sooner)
        !          1557:        {
        !          1558:                ccb->sooner->later = ccb->later;
        !          1559:        }
        !          1560:        else
        !          1561:        {
        !          1562:                aha_soonest = ccb->later;
        !          1563:        }
        !          1564:        if(ccb->later)
        !          1565:        {
        !          1566:                ccb->later->sooner = ccb->sooner;
        !          1567:                ccb->later->delta += ccb->delta;
        !          1568:        }
        !          1569:        else
        !          1570:        {
        !          1571:                aha_latest = ccb->sooner;
        !          1572:                aha_furtherest -= ccb->delta;
        !          1573:        }
        !          1574:        ccb->sooner = ccb->later = (struct aha_ccb *)0;
        !          1575:        splx(s);
        !          1576: }
        !          1577: 
        !          1578: 
        !          1579: extern int     hz;
        !          1580: #define ONETICK 500 /* milliseconds */
        !          1581: #define SLEEPTIME ((hz * 1000) / ONETICK)
        !          1582: aha_timeout(arg)
        !          1583: int    arg;
        !          1584: {
        !          1585:        struct  aha_ccb  *ccb;
        !          1586:        int     unit;
        !          1587:        int     s       = splbio();
        !          1588: 
        !          1589:        while( ccb = aha_soonest )
        !          1590:        {
        !          1591:                if(ccb->delta <= ONETICK)
        !          1592:                /***********************************************\
        !          1593:                * It has timed out, we need to do some work     *
        !          1594:                \***********************************************/
        !          1595:                {
        !          1596:                        unit = ccb->xfer->adapter;
        !          1597:                        printf("aha%d: device %d timed out ",unit
        !          1598:                                ,ccb->xfer->targ);
        !          1599: 
        !          1600:                        /***************************************\
        !          1601:                        * Unlink it from the queue              *
        !          1602:                        \***************************************/
        !          1603:                        aha_remove_timeout(ccb);
        !          1604: 
        !          1605:                        /***************************************\
        !          1606:                        * If The ccb's mbx is not free, then    *
        !          1607:                        * the board has gone south              *
        !          1608:                        \***************************************/
        !          1609:                        if(ccb->mbx->cmd != AHA_MBO_FREE)
        !          1610:                        {
        !          1611:                                printf("aha%d not taking commands!\n"
        !          1612:                                                        ,unit);
        !          1613:                                Debugger();
        !          1614:                        }
        !          1615:                        /***************************************\
        !          1616:                        * If it has been through before, then   *
        !          1617:                        * a previous abort has failed, don't    *
        !          1618:                        * try abort again                       *
        !          1619:                        \***************************************/
        !          1620:                        if(ccb->flags == CCB_ABORTED) /* abort timed out */
        !          1621:                        {
        !          1622:                                printf(" AGAIN\n");
        !          1623:                                ccb->xfer->retries = 0; /* I MEAN IT ! */
        !          1624:                                ccb->host_stat = AHA_ABORTED;
        !          1625:                                aha_done(unit,ccb);
        !          1626:                        }
        !          1627:                        else    /* abort the operation that has timed out */
        !          1628:                        {
        !          1629:                                printf("\n");
        !          1630:                                aha_abortmbx(ccb->mbx);
        !          1631:                                                /* 2 secs for the abort */
        !          1632:                                aha_add_timeout(ccb,2000 + ONETICK);
        !          1633:                                ccb->flags = CCB_ABORTED;
        !          1634:                        }
        !          1635:                }
        !          1636:                else
        !          1637:                /***********************************************\
        !          1638:                * It has not timed out, adjust and leave        *
        !          1639:                \***********************************************/
        !          1640:                {
        !          1641:                        ccb->delta -= ONETICK;
        !          1642:                        aha_furtherest -= ONETICK;
        !          1643:                        break;
        !          1644:                }
        !          1645:        }
        !          1646:        splx(s);
        !          1647:        timeout(aha_timeout,arg,SLEEPTIME);
        !          1648: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.