Home | History | Annotate | Line # | Download | only in dev
mesh.c revision 1.12.6.3
      1  1.12.6.3  nathanw /*	$NetBSD: mesh.c,v 1.12.6.3 2002/10/18 02:38:35 nathanw Exp $	*/
      2  1.12.6.2  nathanw 
      3  1.12.6.2  nathanw /*-
      4  1.12.6.2  nathanw  * Copyright (c) 2000	Tsubai Masanari.
      5  1.12.6.2  nathanw  * Copyright (c) 1999	Internet Research Institute, Inc.
      6  1.12.6.2  nathanw  * All rights reserved.
      7  1.12.6.2  nathanw  *
      8  1.12.6.2  nathanw  * Redistribution and use in source and binary forms, with or without
      9  1.12.6.2  nathanw  * modification, are permitted provided that the following conditions
     10  1.12.6.2  nathanw  * are met:
     11  1.12.6.2  nathanw  * 1. Redistributions of source code must retain the above copyright
     12  1.12.6.2  nathanw  *    notice, this list of conditions and the following disclaimer.
     13  1.12.6.2  nathanw  * 2. Redistributions in binary form must reproduce the above copyright
     14  1.12.6.2  nathanw  *    notice, this list of conditions and the following disclaimer in the
     15  1.12.6.2  nathanw  *    documentation and/or other materials provided with the distribution.
     16  1.12.6.2  nathanw  * 3. All advertising materials mentioning features or use of this software
     17  1.12.6.2  nathanw  *    must display the following acknowledgement:
     18  1.12.6.2  nathanw  *	This product includes software developed by
     19  1.12.6.2  nathanw  *	Internet Research Institute, Inc.
     20  1.12.6.2  nathanw  * 4. The name of the author may not be used to endorse or promote products
     21  1.12.6.2  nathanw  *    derived from this software without specific prior written permission.
     22  1.12.6.2  nathanw  *
     23  1.12.6.2  nathanw  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     24  1.12.6.2  nathanw  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     25  1.12.6.2  nathanw  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     26  1.12.6.2  nathanw  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     27  1.12.6.2  nathanw  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     28  1.12.6.2  nathanw  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     29  1.12.6.2  nathanw  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     30  1.12.6.2  nathanw  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     31  1.12.6.2  nathanw  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     32  1.12.6.2  nathanw  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     33  1.12.6.2  nathanw  */
     34  1.12.6.2  nathanw 
     35  1.12.6.2  nathanw #include <sys/param.h>
     36  1.12.6.2  nathanw #include <sys/buf.h>
     37  1.12.6.2  nathanw #include <sys/device.h>
     38  1.12.6.2  nathanw #include <sys/errno.h>
     39  1.12.6.2  nathanw #include <sys/kernel.h>
     40  1.12.6.2  nathanw #include <sys/malloc.h>
     41  1.12.6.2  nathanw #include <sys/queue.h>
     42  1.12.6.2  nathanw #include <sys/systm.h>
     43  1.12.6.2  nathanw 
     44  1.12.6.2  nathanw #include <uvm/uvm_extern.h>
     45  1.12.6.2  nathanw 
     46  1.12.6.2  nathanw #include <dev/scsipi/scsi_all.h>
     47  1.12.6.2  nathanw #include <dev/scsipi/scsipi_all.h>
     48  1.12.6.2  nathanw #include <dev/scsipi/scsiconf.h>
     49  1.12.6.2  nathanw #include <dev/scsipi/scsi_message.h>
     50  1.12.6.2  nathanw 
     51  1.12.6.2  nathanw #include <dev/ofw/openfirm.h>
     52  1.12.6.2  nathanw 
     53  1.12.6.2  nathanw #include <machine/autoconf.h>
     54  1.12.6.2  nathanw #include <machine/cpu.h>
     55  1.12.6.2  nathanw #include <machine/pio.h>
     56  1.12.6.2  nathanw 
     57  1.12.6.2  nathanw #include <macppc/dev/dbdma.h>
     58  1.12.6.2  nathanw #include <macppc/dev/meshreg.h>
     59  1.12.6.2  nathanw 
     60  1.12.6.2  nathanw #ifdef MESH_DEBUG
     61  1.12.6.2  nathanw # define DPRINTF printf
     62  1.12.6.2  nathanw #else
     63  1.12.6.2  nathanw # define DPRINTF while (0) printf
     64  1.12.6.2  nathanw #endif
     65  1.12.6.2  nathanw 
     66  1.12.6.2  nathanw #define T_SYNCMODE 0x01		/* target uses sync mode */
     67  1.12.6.2  nathanw #define T_SYNCNEGO 0x02		/* sync negotiation done */
     68  1.12.6.2  nathanw 
     69  1.12.6.2  nathanw struct mesh_tinfo {
     70  1.12.6.2  nathanw 	int flags;
     71  1.12.6.2  nathanw 	int period;
     72  1.12.6.2  nathanw 	int offset;
     73  1.12.6.2  nathanw };
     74  1.12.6.2  nathanw 
     75  1.12.6.2  nathanw /* scb flags */
     76  1.12.6.2  nathanw #define MESH_POLL	0x01
     77  1.12.6.2  nathanw #define MESH_CHECK	0x02
     78  1.12.6.2  nathanw #define MESH_READ	0x80
     79  1.12.6.2  nathanw 
     80  1.12.6.2  nathanw struct mesh_scb {
     81  1.12.6.2  nathanw 	TAILQ_ENTRY(mesh_scb) chain;
     82  1.12.6.2  nathanw 	int flags;
     83  1.12.6.2  nathanw 	struct scsipi_xfer *xs;
     84  1.12.6.2  nathanw 	struct scsi_generic cmd;
     85  1.12.6.2  nathanw 	int cmdlen;
     86  1.12.6.2  nathanw 	int target;			/* target SCSI ID */
     87  1.12.6.2  nathanw 	int resid;
     88  1.12.6.2  nathanw 	vaddr_t daddr;
     89  1.12.6.2  nathanw 	vsize_t dlen;
     90  1.12.6.2  nathanw 	int status;
     91  1.12.6.2  nathanw };
     92  1.12.6.2  nathanw 
     93  1.12.6.2  nathanw /* sc_flags value */
     94  1.12.6.2  nathanw #define MESH_DMA_ACTIVE	0x01
     95  1.12.6.2  nathanw 
     96  1.12.6.2  nathanw struct mesh_softc {
     97  1.12.6.2  nathanw 	struct device sc_dev;		/* us as a device */
     98  1.12.6.2  nathanw 	struct scsipi_channel sc_channel;
     99  1.12.6.2  nathanw 	struct scsipi_adapter sc_adapter;
    100  1.12.6.2  nathanw 
    101  1.12.6.2  nathanw 	u_char *sc_reg;			/* MESH base address */
    102  1.12.6.2  nathanw 	dbdma_regmap_t *sc_dmareg;	/* DMA register address */
    103  1.12.6.2  nathanw 	dbdma_command_t *sc_dmacmd;	/* DMA command area */
    104  1.12.6.2  nathanw 
    105  1.12.6.2  nathanw 	int sc_flags;
    106  1.12.6.2  nathanw 	int sc_cfflags;			/* copy of config flags */
    107  1.12.6.2  nathanw 	int sc_meshid;			/* MESH version */
    108  1.12.6.2  nathanw 	int sc_minsync;			/* minimum sync period */
    109  1.12.6.2  nathanw 	int sc_irq;
    110  1.12.6.2  nathanw 	int sc_freq;			/* SCSI bus frequency in MHz */
    111  1.12.6.2  nathanw 	int sc_id;			/* our SCSI ID */
    112  1.12.6.2  nathanw 	struct mesh_tinfo sc_tinfo[8];	/* target information */
    113  1.12.6.2  nathanw 
    114  1.12.6.2  nathanw 	int sc_nextstate;
    115  1.12.6.2  nathanw 	int sc_prevphase;
    116  1.12.6.2  nathanw 	struct mesh_scb *sc_nexus;	/* current command */
    117  1.12.6.2  nathanw 
    118  1.12.6.2  nathanw 	int sc_msgout;
    119  1.12.6.2  nathanw 	int sc_imsglen;
    120  1.12.6.2  nathanw 	u_char sc_imsg[16];
    121  1.12.6.2  nathanw 	u_char sc_omsg[16];
    122  1.12.6.2  nathanw 
    123  1.12.6.2  nathanw 	TAILQ_HEAD(, mesh_scb) free_scb;
    124  1.12.6.2  nathanw 	TAILQ_HEAD(, mesh_scb) ready_scb;
    125  1.12.6.2  nathanw 	struct mesh_scb sc_scb[16];
    126  1.12.6.2  nathanw };
    127  1.12.6.2  nathanw 
    128  1.12.6.2  nathanw /* mesh_msgout() values */
    129  1.12.6.2  nathanw #define SEND_REJECT	1
    130  1.12.6.2  nathanw #define SEND_IDENTIFY	2
    131  1.12.6.2  nathanw #define SEND_SDTR	4
    132  1.12.6.2  nathanw 
    133  1.12.6.2  nathanw static __inline int mesh_read_reg __P((struct mesh_softc *, int));
    134  1.12.6.2  nathanw static __inline void mesh_set_reg __P((struct mesh_softc *, int, int));
    135  1.12.6.2  nathanw 
    136  1.12.6.2  nathanw int mesh_match __P((struct device *, struct cfdata *, void *));
    137  1.12.6.2  nathanw void mesh_attach __P((struct device *, struct device *, void *));
    138  1.12.6.2  nathanw void mesh_shutdownhook __P((void *));
    139  1.12.6.2  nathanw int mesh_intr __P((void *));
    140  1.12.6.2  nathanw void mesh_error __P((struct mesh_softc *, struct mesh_scb *, int, int));
    141  1.12.6.2  nathanw void mesh_select __P((struct mesh_softc *, struct mesh_scb *));
    142  1.12.6.2  nathanw void mesh_identify __P((struct mesh_softc *, struct mesh_scb *));
    143  1.12.6.2  nathanw void mesh_command __P((struct mesh_softc *, struct mesh_scb *));
    144  1.12.6.2  nathanw void mesh_dma_setup __P((struct mesh_softc *, struct mesh_scb *));
    145  1.12.6.2  nathanw void mesh_dataio __P((struct mesh_softc *, struct mesh_scb *));
    146  1.12.6.2  nathanw void mesh_status __P((struct mesh_softc *, struct mesh_scb *));
    147  1.12.6.2  nathanw void mesh_msgin __P((struct mesh_softc *, struct mesh_scb *));
    148  1.12.6.2  nathanw void mesh_msgout __P((struct mesh_softc *, int));
    149  1.12.6.2  nathanw void mesh_bus_reset __P((struct mesh_softc *));
    150  1.12.6.2  nathanw void mesh_reset __P((struct mesh_softc *));
    151  1.12.6.2  nathanw int mesh_stp __P((struct mesh_softc *, int));
    152  1.12.6.2  nathanw void mesh_setsync __P((struct mesh_softc *, struct mesh_tinfo *));
    153  1.12.6.2  nathanw struct mesh_scb *mesh_get_scb __P((struct mesh_softc *));
    154  1.12.6.2  nathanw void mesh_free_scb __P((struct mesh_softc *, struct mesh_scb *));
    155  1.12.6.2  nathanw void mesh_scsi_request __P((struct scsipi_channel *,
    156  1.12.6.2  nathanw 				scsipi_adapter_req_t, void *));
    157  1.12.6.2  nathanw void mesh_sched __P((struct mesh_softc *));
    158  1.12.6.2  nathanw int mesh_poll __P((struct mesh_softc *, struct scsipi_xfer *));
    159  1.12.6.2  nathanw void mesh_done __P((struct mesh_softc *, struct mesh_scb *));
    160  1.12.6.2  nathanw void mesh_timeout __P((void *));
    161  1.12.6.2  nathanw void mesh_minphys __P((struct buf *));
    162  1.12.6.2  nathanw 
    163  1.12.6.2  nathanw 
    164  1.12.6.2  nathanw #define MESH_DATAOUT	0
    165  1.12.6.2  nathanw #define MESH_DATAIN	MESH_STATUS0_IO
    166  1.12.6.2  nathanw #define MESH_COMMAND	MESH_STATUS0_CD
    167  1.12.6.2  nathanw #define MESH_STATUS	(MESH_STATUS0_CD | MESH_STATUS0_IO)
    168  1.12.6.2  nathanw #define MESH_MSGOUT	(MESH_STATUS0_MSG | MESH_STATUS0_CD)
    169  1.12.6.2  nathanw #define MESH_MSGIN	(MESH_STATUS0_MSG | MESH_STATUS0_CD | MESH_STATUS0_IO)
    170  1.12.6.2  nathanw 
    171  1.12.6.2  nathanw #define MESH_SELECTING	8
    172  1.12.6.2  nathanw #define MESH_IDENTIFY	9
    173  1.12.6.2  nathanw #define MESH_COMPLETE	10
    174  1.12.6.2  nathanw #define MESH_BUSFREE	11
    175  1.12.6.2  nathanw #define MESH_UNKNOWN	-1
    176  1.12.6.2  nathanw 
    177  1.12.6.2  nathanw #define MESH_PHASE_MASK	(MESH_STATUS0_MSG | MESH_STATUS0_CD | MESH_STATUS0_IO)
    178  1.12.6.2  nathanw 
    179  1.12.6.3  nathanw CFATTACH_DECL(mesh, sizeof(struct mesh_softc),
    180  1.12.6.3  nathanw     mesh_match, mesh_attach, NULL, NULL);
    181  1.12.6.2  nathanw 
    182  1.12.6.2  nathanw int
    183  1.12.6.2  nathanw mesh_match(parent, cf, aux)
    184  1.12.6.2  nathanw 	struct device *parent;
    185  1.12.6.2  nathanw 	struct cfdata *cf;
    186  1.12.6.2  nathanw 	void *aux;
    187  1.12.6.2  nathanw {
    188  1.12.6.2  nathanw 	struct confargs *ca = aux;
    189  1.12.6.2  nathanw 	char compat[32];
    190  1.12.6.2  nathanw 
    191  1.12.6.2  nathanw 	if (strcmp(ca->ca_name, "mesh") == 0)
    192  1.12.6.2  nathanw 		return 1;
    193  1.12.6.2  nathanw 
    194  1.12.6.2  nathanw 	memset(compat, 0, sizeof(compat));
    195  1.12.6.2  nathanw 	OF_getprop(ca->ca_node, "compatible", compat, sizeof(compat));
    196  1.12.6.2  nathanw 	if (strcmp(compat, "chrp,mesh0") == 0)
    197  1.12.6.2  nathanw 		return 1;
    198  1.12.6.2  nathanw 
    199  1.12.6.2  nathanw 	return 0;
    200  1.12.6.2  nathanw }
    201  1.12.6.2  nathanw 
    202  1.12.6.2  nathanw void
    203  1.12.6.2  nathanw mesh_attach(parent, self, aux)
    204  1.12.6.2  nathanw 	struct device *parent, *self;
    205  1.12.6.2  nathanw 	void *aux;
    206  1.12.6.2  nathanw {
    207  1.12.6.2  nathanw 	struct mesh_softc *sc = (void *)self;
    208  1.12.6.2  nathanw 	struct confargs *ca = aux;
    209  1.12.6.2  nathanw 	int i;
    210  1.12.6.2  nathanw 	u_int *reg;
    211  1.12.6.2  nathanw 
    212  1.12.6.2  nathanw 	reg = ca->ca_reg;
    213  1.12.6.2  nathanw 	reg[0] += ca->ca_baseaddr;
    214  1.12.6.2  nathanw 	reg[2] += ca->ca_baseaddr;
    215  1.12.6.2  nathanw 	sc->sc_reg = mapiodev(reg[0], reg[1]);
    216  1.12.6.2  nathanw 	sc->sc_irq = ca->ca_intr[0];
    217  1.12.6.2  nathanw 	sc->sc_dmareg = mapiodev(reg[2], reg[3]);
    218  1.12.6.2  nathanw 
    219  1.12.6.2  nathanw 	sc->sc_cfflags = self->dv_cfdata->cf_flags;
    220  1.12.6.2  nathanw 	sc->sc_meshid = mesh_read_reg(sc, MESH_MESH_ID) & 0x1f;
    221  1.12.6.2  nathanw #if 0
    222  1.12.6.2  nathanw 	if (sc->sc_meshid != (MESH_SIGNATURE & 0x1f) {
    223  1.12.6.2  nathanw 		printf(": unknown MESH ID (0x%x)\n", sc->sc_meshid);
    224  1.12.6.2  nathanw 		return;
    225  1.12.6.2  nathanw 	}
    226  1.12.6.2  nathanw #endif
    227  1.12.6.2  nathanw 	if (OF_getprop(ca->ca_node, "clock-frequency", &sc->sc_freq, 4) != 4) {
    228  1.12.6.2  nathanw 		printf(": cannot get clock-frequency\n");
    229  1.12.6.2  nathanw 		return;
    230  1.12.6.2  nathanw 	}
    231  1.12.6.2  nathanw 	sc->sc_freq /= 1000000;	/* in MHz */
    232  1.12.6.2  nathanw 	sc->sc_minsync = 25;	/* maximum sync rate = 10MB/sec */
    233  1.12.6.2  nathanw 	sc->sc_id = 7;
    234  1.12.6.2  nathanw 
    235  1.12.6.2  nathanw 	TAILQ_INIT(&sc->free_scb);
    236  1.12.6.2  nathanw 	TAILQ_INIT(&sc->ready_scb);
    237  1.12.6.2  nathanw 	for (i = 0; i < sizeof(sc->sc_scb)/sizeof(sc->sc_scb[0]); i++)
    238  1.12.6.2  nathanw 		TAILQ_INSERT_TAIL(&sc->free_scb, &sc->sc_scb[i], chain);
    239  1.12.6.2  nathanw 
    240  1.12.6.2  nathanw 	sc->sc_dmacmd = dbdma_alloc(sizeof(dbdma_command_t) * 20);
    241  1.12.6.2  nathanw 
    242  1.12.6.2  nathanw 	mesh_reset(sc);
    243  1.12.6.2  nathanw 	mesh_bus_reset(sc);
    244  1.12.6.2  nathanw 
    245  1.12.6.2  nathanw 	printf(" irq %d: %dMHz, SCSI ID %d\n",
    246  1.12.6.2  nathanw 		sc->sc_irq, sc->sc_freq, sc->sc_id);
    247  1.12.6.2  nathanw 
    248  1.12.6.2  nathanw 	sc->sc_adapter.adapt_dev = &sc->sc_dev;
    249  1.12.6.2  nathanw 	sc->sc_adapter.adapt_nchannels = 1;
    250  1.12.6.2  nathanw 	sc->sc_adapter.adapt_openings = 7;
    251  1.12.6.2  nathanw 	sc->sc_adapter.adapt_max_periph = 1;
    252  1.12.6.2  nathanw 	sc->sc_adapter.adapt_ioctl = NULL;
    253  1.12.6.2  nathanw 	sc->sc_adapter.adapt_minphys = mesh_minphys;
    254  1.12.6.2  nathanw 	sc->sc_adapter.adapt_request = mesh_scsi_request;
    255  1.12.6.2  nathanw 
    256  1.12.6.2  nathanw 	sc->sc_channel.chan_adapter = &sc->sc_adapter;
    257  1.12.6.2  nathanw 	sc->sc_channel.chan_bustype = &scsi_bustype;
    258  1.12.6.2  nathanw 	sc->sc_channel.chan_channel = 0;
    259  1.12.6.2  nathanw 	sc->sc_channel.chan_ntargets = 8;
    260  1.12.6.2  nathanw 	sc->sc_channel.chan_nluns = 8;
    261  1.12.6.2  nathanw 	sc->sc_channel.chan_id = sc->sc_id;
    262  1.12.6.2  nathanw 
    263  1.12.6.2  nathanw 	config_found(&sc->sc_dev, &sc->sc_channel, scsiprint);
    264  1.12.6.2  nathanw 
    265  1.12.6.2  nathanw 	intr_establish(sc->sc_irq, IST_LEVEL, IPL_BIO, mesh_intr, sc);
    266  1.12.6.2  nathanw 
    267  1.12.6.2  nathanw 	/* Reset SCSI bus when halt. */
    268  1.12.6.2  nathanw 	shutdownhook_establish(mesh_shutdownhook, sc);
    269  1.12.6.2  nathanw }
    270  1.12.6.2  nathanw 
    271  1.12.6.2  nathanw #define MESH_SET_XFER(sc, count) do {					\
    272  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_XFER_COUNT0, count);			\
    273  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_XFER_COUNT1, count >> 8);			\
    274  1.12.6.2  nathanw } while (0)
    275  1.12.6.2  nathanw 
    276  1.12.6.2  nathanw #define MESH_GET_XFER(sc) ((mesh_read_reg(sc, MESH_XFER_COUNT1) << 8) |	\
    277  1.12.6.2  nathanw 			   mesh_read_reg(sc, MESH_XFER_COUNT0))
    278  1.12.6.2  nathanw 
    279  1.12.6.2  nathanw int
    280  1.12.6.2  nathanw mesh_read_reg(sc, reg)
    281  1.12.6.2  nathanw 	struct mesh_softc *sc;
    282  1.12.6.2  nathanw 	int reg;
    283  1.12.6.2  nathanw {
    284  1.12.6.2  nathanw 	return in8(sc->sc_reg + reg);
    285  1.12.6.2  nathanw }
    286  1.12.6.2  nathanw 
    287  1.12.6.2  nathanw void
    288  1.12.6.2  nathanw mesh_set_reg(sc, reg, val)
    289  1.12.6.2  nathanw 	struct mesh_softc *sc;
    290  1.12.6.2  nathanw 	int reg, val;
    291  1.12.6.2  nathanw {
    292  1.12.6.2  nathanw 	out8(sc->sc_reg + reg, val);
    293  1.12.6.2  nathanw }
    294  1.12.6.2  nathanw 
    295  1.12.6.2  nathanw void
    296  1.12.6.2  nathanw mesh_shutdownhook(arg)
    297  1.12.6.2  nathanw 	void *arg;
    298  1.12.6.2  nathanw {
    299  1.12.6.2  nathanw 	struct mesh_softc *sc = arg;
    300  1.12.6.2  nathanw 
    301  1.12.6.2  nathanw 	/* Set to async mode. */
    302  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SYNC_PARAM, 2);
    303  1.12.6.2  nathanw }
    304  1.12.6.2  nathanw 
    305  1.12.6.2  nathanw #ifdef MESH_DEBUG
    306  1.12.6.2  nathanw static char scsi_phase[][8] = {
    307  1.12.6.2  nathanw 	"DATAOUT",
    308  1.12.6.2  nathanw 	"DATAIN",
    309  1.12.6.2  nathanw 	"COMMAND",
    310  1.12.6.2  nathanw 	"STATUS",
    311  1.12.6.2  nathanw 	"",
    312  1.12.6.2  nathanw 	"",
    313  1.12.6.2  nathanw 	"MSGOUT",
    314  1.12.6.2  nathanw 	"MSGIN"
    315  1.12.6.2  nathanw };
    316  1.12.6.2  nathanw #endif
    317  1.12.6.2  nathanw 
    318  1.12.6.2  nathanw int
    319  1.12.6.2  nathanw mesh_intr(arg)
    320  1.12.6.2  nathanw 	void *arg;
    321  1.12.6.2  nathanw {
    322  1.12.6.2  nathanw 	struct mesh_softc *sc = arg;
    323  1.12.6.2  nathanw 	struct mesh_scb *scb;
    324  1.12.6.2  nathanw 	int fifocnt;
    325  1.12.6.2  nathanw 	u_char intr, exception, error, status0, status1;
    326  1.12.6.2  nathanw 
    327  1.12.6.2  nathanw 	intr = mesh_read_reg(sc, MESH_INTERRUPT);
    328  1.12.6.2  nathanw 	if (intr == 0) {
    329  1.12.6.2  nathanw 		DPRINTF("%s: stray interrupt\n", sc->sc_dev.dv_xname);
    330  1.12.6.2  nathanw 		return 0;
    331  1.12.6.2  nathanw 	}
    332  1.12.6.2  nathanw 
    333  1.12.6.2  nathanw 	exception = mesh_read_reg(sc, MESH_EXCEPTION);
    334  1.12.6.2  nathanw 	error = mesh_read_reg(sc, MESH_ERROR);
    335  1.12.6.2  nathanw 	status0 = mesh_read_reg(sc, MESH_BUS_STATUS0);
    336  1.12.6.2  nathanw 	status1 = mesh_read_reg(sc, MESH_BUS_STATUS1);
    337  1.12.6.2  nathanw 
    338  1.12.6.2  nathanw 	/* clear interrupt */
    339  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_INTERRUPT, intr);
    340  1.12.6.2  nathanw 
    341  1.12.6.2  nathanw #ifdef MESH_DEBUG
    342  1.12.6.2  nathanw {
    343  1.12.6.2  nathanw 	char buf1[64], buf2[64];
    344  1.12.6.2  nathanw 
    345  1.12.6.2  nathanw 	bitmask_snprintf(status0, MESH_STATUS0_BITMASK, buf1, sizeof buf1);
    346  1.12.6.2  nathanw 	bitmask_snprintf(exception, MESH_EXC_BITMASK, buf2, sizeof buf2);
    347  1.12.6.2  nathanw 	printf("mesh_intr status0 = 0x%s (%s), exc = 0x%s\n",
    348  1.12.6.2  nathanw 	    buf1, scsi_phase[status0 & 7], buf2);
    349  1.12.6.2  nathanw }
    350  1.12.6.2  nathanw #endif
    351  1.12.6.2  nathanw 
    352  1.12.6.2  nathanw 	scb = sc->sc_nexus;
    353  1.12.6.2  nathanw 	if (scb == NULL) {
    354  1.12.6.2  nathanw 		DPRINTF("%s: NULL nexus\n", sc->sc_dev.dv_xname);
    355  1.12.6.2  nathanw 		return 1;
    356  1.12.6.2  nathanw 	}
    357  1.12.6.2  nathanw 
    358  1.12.6.2  nathanw 	if (sc->sc_flags & MESH_DMA_ACTIVE) {
    359  1.12.6.2  nathanw 		dbdma_stop(sc->sc_dmareg);
    360  1.12.6.2  nathanw 
    361  1.12.6.2  nathanw 		sc->sc_flags &= ~MESH_DMA_ACTIVE;
    362  1.12.6.2  nathanw 		scb->resid = MESH_GET_XFER(sc);
    363  1.12.6.2  nathanw 
    364  1.12.6.2  nathanw 		fifocnt = mesh_read_reg(sc, MESH_FIFO_COUNT);
    365  1.12.6.2  nathanw 		if (fifocnt != 0 && (scb->flags & MESH_READ)) {
    366  1.12.6.2  nathanw 			char *cp = (char *)scb->daddr + scb->dlen - fifocnt;
    367  1.12.6.2  nathanw 
    368  1.12.6.2  nathanw 			DPRINTF("fifocnt = %d, resid = %d\n", fifocnt,
    369  1.12.6.2  nathanw 				scb->resid);
    370  1.12.6.2  nathanw 			while (fifocnt > 0) {
    371  1.12.6.2  nathanw 				*cp++ = mesh_read_reg(sc, MESH_FIFO);
    372  1.12.6.2  nathanw 				fifocnt--;
    373  1.12.6.2  nathanw 			}
    374  1.12.6.2  nathanw 		} else
    375  1.12.6.2  nathanw 			mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_FLUSH_FIFO);
    376  1.12.6.2  nathanw 	}
    377  1.12.6.2  nathanw 
    378  1.12.6.2  nathanw 	if (intr & MESH_INTR_ERROR) {
    379  1.12.6.2  nathanw 		mesh_error(sc, scb, error, 0);
    380  1.12.6.2  nathanw 		return 1;
    381  1.12.6.2  nathanw 	}
    382  1.12.6.2  nathanw 
    383  1.12.6.2  nathanw 	if (intr & MESH_INTR_EXCEPTION) {
    384  1.12.6.2  nathanw 		/* selection timeout */
    385  1.12.6.2  nathanw 		if (exception & MESH_EXC_SELTO) {
    386  1.12.6.2  nathanw 			mesh_error(sc, scb, 0, exception);
    387  1.12.6.2  nathanw 			return 1;
    388  1.12.6.2  nathanw 		}
    389  1.12.6.2  nathanw 
    390  1.12.6.2  nathanw 		/* phase mismatch */
    391  1.12.6.2  nathanw 		if (exception & MESH_EXC_PHASEMM) {
    392  1.12.6.2  nathanw 			DPRINTF("%s: PHASE MISMATCH; nextstate = %d -> ",
    393  1.12.6.2  nathanw 				sc->sc_dev.dv_xname, sc->sc_nextstate);
    394  1.12.6.2  nathanw 			sc->sc_nextstate = status0 & MESH_PHASE_MASK;
    395  1.12.6.2  nathanw 
    396  1.12.6.2  nathanw 			DPRINTF("%d, resid = %d\n",
    397  1.12.6.2  nathanw 				sc->sc_nextstate, scb->resid);
    398  1.12.6.2  nathanw 		}
    399  1.12.6.2  nathanw 	}
    400  1.12.6.2  nathanw 
    401  1.12.6.2  nathanw 	if (sc->sc_nextstate == MESH_UNKNOWN)
    402  1.12.6.2  nathanw 		sc->sc_nextstate = status0 & MESH_PHASE_MASK;
    403  1.12.6.2  nathanw 
    404  1.12.6.2  nathanw 	switch (sc->sc_nextstate) {
    405  1.12.6.2  nathanw 
    406  1.12.6.2  nathanw 	case MESH_IDENTIFY:
    407  1.12.6.2  nathanw 		mesh_identify(sc, scb);
    408  1.12.6.2  nathanw 		break;
    409  1.12.6.2  nathanw 	case MESH_COMMAND:
    410  1.12.6.2  nathanw 		mesh_command(sc, scb);
    411  1.12.6.2  nathanw 		break;
    412  1.12.6.2  nathanw 	case MESH_DATAIN:
    413  1.12.6.2  nathanw 	case MESH_DATAOUT:
    414  1.12.6.2  nathanw 		mesh_dataio(sc, scb);
    415  1.12.6.2  nathanw 		break;
    416  1.12.6.2  nathanw 	case MESH_STATUS:
    417  1.12.6.2  nathanw 		mesh_status(sc, scb);
    418  1.12.6.2  nathanw 		break;
    419  1.12.6.2  nathanw 	case MESH_MSGIN:
    420  1.12.6.2  nathanw 		mesh_msgin(sc, scb);
    421  1.12.6.2  nathanw 		break;
    422  1.12.6.2  nathanw 	case MESH_COMPLETE:
    423  1.12.6.2  nathanw 		mesh_done(sc, scb);
    424  1.12.6.2  nathanw 		break;
    425  1.12.6.2  nathanw 
    426  1.12.6.2  nathanw 	default:
    427  1.12.6.2  nathanw 		printf("%s: unknown state (%d)\n", sc->sc_dev.dv_xname,
    428  1.12.6.2  nathanw 		    sc->sc_nextstate);
    429  1.12.6.2  nathanw 		scb->xs->error = XS_DRIVER_STUFFUP;
    430  1.12.6.2  nathanw 		mesh_done(sc, scb);
    431  1.12.6.2  nathanw 	}
    432  1.12.6.2  nathanw 
    433  1.12.6.2  nathanw 	return 1;
    434  1.12.6.2  nathanw }
    435  1.12.6.2  nathanw 
    436  1.12.6.2  nathanw void
    437  1.12.6.2  nathanw mesh_error(sc, scb, error, exception)
    438  1.12.6.2  nathanw 	struct mesh_softc *sc;
    439  1.12.6.2  nathanw 	struct mesh_scb *scb;
    440  1.12.6.2  nathanw 	int error, exception;
    441  1.12.6.2  nathanw {
    442  1.12.6.2  nathanw 	if (error & MESH_ERR_SCSI_RESET) {
    443  1.12.6.2  nathanw 		printf("%s: SCSI RESET\n", sc->sc_dev.dv_xname);
    444  1.12.6.2  nathanw 
    445  1.12.6.2  nathanw 		/* Wait until the RST signal is deasserted. */
    446  1.12.6.2  nathanw 		while (mesh_read_reg(sc, MESH_BUS_STATUS1) & MESH_STATUS1_RST);
    447  1.12.6.2  nathanw 		mesh_reset(sc);
    448  1.12.6.2  nathanw 		return;
    449  1.12.6.2  nathanw 	}
    450  1.12.6.2  nathanw 
    451  1.12.6.2  nathanw 	if (error & MESH_ERR_PARITY_ERR0) {
    452  1.12.6.2  nathanw 		printf("%s: parity error\n", sc->sc_dev.dv_xname);
    453  1.12.6.2  nathanw 		scb->xs->error = XS_DRIVER_STUFFUP;
    454  1.12.6.2  nathanw 	}
    455  1.12.6.2  nathanw 
    456  1.12.6.2  nathanw 	if (error & MESH_ERR_DISCONNECT) {
    457  1.12.6.2  nathanw 		printf("%s: unexpected disconnect\n", sc->sc_dev.dv_xname);
    458  1.12.6.2  nathanw 		if (sc->sc_nextstate != MESH_COMPLETE)
    459  1.12.6.2  nathanw 			scb->xs->error = XS_DRIVER_STUFFUP;
    460  1.12.6.2  nathanw 	}
    461  1.12.6.2  nathanw 
    462  1.12.6.2  nathanw 	if (exception & MESH_EXC_SELTO) {
    463  1.12.6.2  nathanw 		/* XXX should reset bus here? */
    464  1.12.6.2  nathanw 		scb->xs->error = XS_SELTIMEOUT;
    465  1.12.6.2  nathanw 	}
    466  1.12.6.2  nathanw 
    467  1.12.6.2  nathanw 	mesh_done(sc, scb);
    468  1.12.6.2  nathanw }
    469  1.12.6.2  nathanw 
    470  1.12.6.2  nathanw void
    471  1.12.6.2  nathanw mesh_select(sc, scb)
    472  1.12.6.2  nathanw 	struct mesh_softc *sc;
    473  1.12.6.2  nathanw 	struct mesh_scb *scb;
    474  1.12.6.2  nathanw {
    475  1.12.6.2  nathanw 	struct mesh_tinfo *ti = &sc->sc_tinfo[scb->target];
    476  1.12.6.2  nathanw 	int timeout;
    477  1.12.6.2  nathanw 
    478  1.12.6.2  nathanw 	DPRINTF("mesh_select\n");
    479  1.12.6.2  nathanw 
    480  1.12.6.2  nathanw 	mesh_setsync(sc, ti);
    481  1.12.6.2  nathanw 	MESH_SET_XFER(sc, 0);
    482  1.12.6.2  nathanw 
    483  1.12.6.2  nathanw 	/* arbitration */
    484  1.12.6.2  nathanw 
    485  1.12.6.2  nathanw 	/*
    486  1.12.6.2  nathanw 	 * MESH mistakenly asserts TARGET ID bit along with its own ID bit
    487  1.12.6.2  nathanw 	 * in arbitration phase (like selection).  So we should load
    488  1.12.6.2  nathanw 	 * initiator ID to DestID register temporarily.
    489  1.12.6.2  nathanw 	 */
    490  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_DEST_ID, sc->sc_id);
    491  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_INTR_MASK, 0);	/* disable intr. */
    492  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_ARBITRATE);
    493  1.12.6.2  nathanw 
    494  1.12.6.2  nathanw 	while (mesh_read_reg(sc, MESH_INTERRUPT) == 0);
    495  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_INTERRUPT, 1);
    496  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_INTR_MASK, 7);
    497  1.12.6.2  nathanw 
    498  1.12.6.2  nathanw 	/* selection */
    499  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_DEST_ID, scb->target);
    500  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_SELECT | MESH_SEQ_ATN);
    501  1.12.6.2  nathanw 
    502  1.12.6.2  nathanw 	sc->sc_prevphase = MESH_SELECTING;
    503  1.12.6.2  nathanw 	sc->sc_nextstate = MESH_IDENTIFY;
    504  1.12.6.2  nathanw 
    505  1.12.6.2  nathanw 	timeout = mstohz(scb->xs->timeout);
    506  1.12.6.2  nathanw 	if (timeout == 0)
    507  1.12.6.2  nathanw 		timeout = 1;
    508  1.12.6.2  nathanw 
    509  1.12.6.2  nathanw 	callout_reset(&scb->xs->xs_callout, timeout, mesh_timeout, scb);
    510  1.12.6.2  nathanw }
    511  1.12.6.2  nathanw 
    512  1.12.6.2  nathanw void
    513  1.12.6.2  nathanw mesh_identify(sc, scb)
    514  1.12.6.2  nathanw 	struct mesh_softc *sc;
    515  1.12.6.2  nathanw 	struct mesh_scb *scb;
    516  1.12.6.2  nathanw {
    517  1.12.6.2  nathanw 	struct mesh_tinfo *ti = &sc->sc_tinfo[scb->target];
    518  1.12.6.2  nathanw 
    519  1.12.6.2  nathanw 	DPRINTF("mesh_identify\n");
    520  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_FLUSH_FIFO);
    521  1.12.6.2  nathanw 
    522  1.12.6.2  nathanw 	if ((ti->flags & T_SYNCNEGO) == 0) {
    523  1.12.6.2  nathanw 		ti->period = sc->sc_minsync;
    524  1.12.6.2  nathanw 		ti->offset = 15;
    525  1.12.6.2  nathanw 		mesh_msgout(sc, SEND_IDENTIFY | SEND_SDTR);
    526  1.12.6.2  nathanw 		sc->sc_nextstate = MESH_MSGIN;
    527  1.12.6.2  nathanw 	} else {
    528  1.12.6.2  nathanw 		mesh_msgout(sc, SEND_IDENTIFY);
    529  1.12.6.2  nathanw 		sc->sc_nextstate = MESH_COMMAND;
    530  1.12.6.2  nathanw 	}
    531  1.12.6.2  nathanw }
    532  1.12.6.2  nathanw 
    533  1.12.6.2  nathanw void
    534  1.12.6.2  nathanw mesh_command(sc, scb)
    535  1.12.6.2  nathanw 	struct mesh_softc *sc;
    536  1.12.6.2  nathanw 	struct mesh_scb *scb;
    537  1.12.6.2  nathanw {
    538  1.12.6.2  nathanw 	int i;
    539  1.12.6.2  nathanw 	char *cmdp;
    540  1.12.6.2  nathanw 
    541  1.12.6.2  nathanw #ifdef MESH_DEBUG
    542  1.12.6.2  nathanw 	printf("mesh_command cdb = %02x", scb->cmd.opcode);
    543  1.12.6.2  nathanw 	for (i = 0; i < 5; i++)
    544  1.12.6.2  nathanw 		printf(" %02x", scb->cmd.bytes[i]);
    545  1.12.6.2  nathanw 	printf("\n");
    546  1.12.6.2  nathanw #endif
    547  1.12.6.2  nathanw 
    548  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_FLUSH_FIFO);
    549  1.12.6.2  nathanw 
    550  1.12.6.2  nathanw 	MESH_SET_XFER(sc, scb->cmdlen);
    551  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_COMMAND);
    552  1.12.6.2  nathanw 
    553  1.12.6.2  nathanw 	cmdp = (char *)&scb->cmd;
    554  1.12.6.2  nathanw 	for (i = 0; i < scb->cmdlen; i++)
    555  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_FIFO, *cmdp++);
    556  1.12.6.2  nathanw 
    557  1.12.6.2  nathanw 	if (scb->resid == 0)
    558  1.12.6.2  nathanw 		sc->sc_nextstate = MESH_STATUS;		/* no data xfer */
    559  1.12.6.2  nathanw 	else
    560  1.12.6.2  nathanw 		sc->sc_nextstate = MESH_DATAIN;
    561  1.12.6.2  nathanw }
    562  1.12.6.2  nathanw 
    563  1.12.6.2  nathanw void
    564  1.12.6.2  nathanw mesh_dma_setup(sc, scb)
    565  1.12.6.2  nathanw 	struct mesh_softc *sc;
    566  1.12.6.2  nathanw 	struct mesh_scb *scb;
    567  1.12.6.2  nathanw {
    568  1.12.6.2  nathanw 	int datain = scb->flags & MESH_READ;
    569  1.12.6.2  nathanw 	dbdma_command_t *cmdp;
    570  1.12.6.2  nathanw 	u_int cmd;
    571  1.12.6.2  nathanw 	vaddr_t va;
    572  1.12.6.2  nathanw 	int count, offset;
    573  1.12.6.2  nathanw 
    574  1.12.6.2  nathanw 	cmdp = sc->sc_dmacmd;
    575  1.12.6.2  nathanw 	cmd = datain ? DBDMA_CMD_IN_MORE : DBDMA_CMD_OUT_MORE;
    576  1.12.6.2  nathanw 
    577  1.12.6.2  nathanw 	count = scb->dlen;
    578  1.12.6.2  nathanw 
    579  1.12.6.2  nathanw 	if (count / NBPG > 32)
    580  1.12.6.2  nathanw 		panic("mesh: transfer size >= 128k");
    581  1.12.6.2  nathanw 
    582  1.12.6.2  nathanw 	va = scb->daddr;
    583  1.12.6.2  nathanw 	offset = va & PGOFSET;
    584  1.12.6.2  nathanw 
    585  1.12.6.2  nathanw 	/* if va is not page-aligned, setup the first page */
    586  1.12.6.2  nathanw 	if (offset != 0) {
    587  1.12.6.2  nathanw 		int rest = NBPG - offset;	/* the rest in the page */
    588  1.12.6.2  nathanw 
    589  1.12.6.2  nathanw 		if (count > rest) {		/* if continues to next page */
    590  1.12.6.2  nathanw 			DBDMA_BUILD(cmdp, cmd, 0, rest, vtophys(va),
    591  1.12.6.2  nathanw 				DBDMA_INT_NEVER, DBDMA_WAIT_NEVER,
    592  1.12.6.2  nathanw 				DBDMA_BRANCH_NEVER);
    593  1.12.6.2  nathanw 			count -= rest;
    594  1.12.6.2  nathanw 			va += rest;
    595  1.12.6.2  nathanw 			cmdp++;
    596  1.12.6.2  nathanw 		}
    597  1.12.6.2  nathanw 	}
    598  1.12.6.2  nathanw 
    599  1.12.6.2  nathanw 	/* now va is page-aligned */
    600  1.12.6.2  nathanw 	while (count > NBPG) {
    601  1.12.6.2  nathanw 		DBDMA_BUILD(cmdp, cmd, 0, NBPG, vtophys(va),
    602  1.12.6.2  nathanw 			DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
    603  1.12.6.2  nathanw 		count -= NBPG;
    604  1.12.6.2  nathanw 		va += NBPG;
    605  1.12.6.2  nathanw 		cmdp++;
    606  1.12.6.2  nathanw 	}
    607  1.12.6.2  nathanw 
    608  1.12.6.2  nathanw 	/* the last page (count <= NBPG here) */
    609  1.12.6.2  nathanw 	cmd = datain ? DBDMA_CMD_IN_LAST : DBDMA_CMD_OUT_LAST;
    610  1.12.6.2  nathanw 	DBDMA_BUILD(cmdp, cmd , 0, count, vtophys(va),
    611  1.12.6.2  nathanw 		DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
    612  1.12.6.2  nathanw 	cmdp++;
    613  1.12.6.2  nathanw 
    614  1.12.6.2  nathanw 	DBDMA_BUILD(cmdp, DBDMA_CMD_STOP, 0, 0, 0,
    615  1.12.6.2  nathanw 		DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
    616  1.12.6.2  nathanw }
    617  1.12.6.2  nathanw 
    618  1.12.6.2  nathanw void
    619  1.12.6.2  nathanw mesh_dataio(sc, scb)
    620  1.12.6.2  nathanw 	struct mesh_softc *sc;
    621  1.12.6.2  nathanw 	struct mesh_scb *scb;
    622  1.12.6.2  nathanw {
    623  1.12.6.2  nathanw 	DPRINTF("mesh_dataio len = %ld (%s)\n", scb->dlen,
    624  1.12.6.2  nathanw 		scb->flags & MESH_READ ? "read" : "write");
    625  1.12.6.2  nathanw 
    626  1.12.6.2  nathanw 	mesh_dma_setup(sc, scb);
    627  1.12.6.2  nathanw 
    628  1.12.6.2  nathanw 	if (scb->dlen == 65536)
    629  1.12.6.2  nathanw 		MESH_SET_XFER(sc, 0);	/* TC = 0 means 64KB transfer */
    630  1.12.6.2  nathanw 	else
    631  1.12.6.2  nathanw 		MESH_SET_XFER(sc, scb->dlen);
    632  1.12.6.2  nathanw 
    633  1.12.6.2  nathanw 	if (scb->flags & MESH_READ)
    634  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_DATAIN | MESH_SEQ_DMA);
    635  1.12.6.2  nathanw 	else
    636  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_DATAOUT | MESH_SEQ_DMA);
    637  1.12.6.2  nathanw 	dbdma_start(sc->sc_dmareg, sc->sc_dmacmd);
    638  1.12.6.2  nathanw 	sc->sc_flags |= MESH_DMA_ACTIVE;
    639  1.12.6.2  nathanw 	sc->sc_nextstate = MESH_STATUS;
    640  1.12.6.2  nathanw }
    641  1.12.6.2  nathanw 
    642  1.12.6.2  nathanw void
    643  1.12.6.2  nathanw mesh_status(sc, scb)
    644  1.12.6.2  nathanw 	struct mesh_softc *sc;
    645  1.12.6.2  nathanw 	struct mesh_scb *scb;
    646  1.12.6.2  nathanw {
    647  1.12.6.2  nathanw 	if (mesh_read_reg(sc, MESH_FIFO_COUNT) == 0) {	/* XXX cheat */
    648  1.12.6.2  nathanw 		DPRINTF("mesh_status(0)\n");
    649  1.12.6.2  nathanw 		MESH_SET_XFER(sc, 1);
    650  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_STATUS);
    651  1.12.6.2  nathanw 		sc->sc_nextstate = MESH_STATUS;
    652  1.12.6.2  nathanw 		return;
    653  1.12.6.2  nathanw 	}
    654  1.12.6.2  nathanw 
    655  1.12.6.2  nathanw 	scb->status = mesh_read_reg(sc, MESH_FIFO);
    656  1.12.6.2  nathanw 	DPRINTF("mesh_status(1): status = 0x%x\n", scb->status);
    657  1.12.6.2  nathanw 	if (mesh_read_reg(sc, MESH_FIFO_COUNT) != 0)
    658  1.12.6.2  nathanw 		DPRINTF("FIFO_COUNT=%d\n", mesh_read_reg(sc, MESH_FIFO_COUNT));
    659  1.12.6.2  nathanw 
    660  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_FLUSH_FIFO);
    661  1.12.6.2  nathanw 	MESH_SET_XFER(sc, 1);
    662  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGIN);
    663  1.12.6.2  nathanw 
    664  1.12.6.2  nathanw 	sc->sc_nextstate = MESH_MSGIN;
    665  1.12.6.2  nathanw }
    666  1.12.6.2  nathanw 
    667  1.12.6.2  nathanw void
    668  1.12.6.2  nathanw mesh_msgin(sc, scb)
    669  1.12.6.2  nathanw 	struct mesh_softc *sc;
    670  1.12.6.2  nathanw 	struct mesh_scb *scb;
    671  1.12.6.2  nathanw {
    672  1.12.6.2  nathanw 	DPRINTF("mesh_msgin\n");
    673  1.12.6.2  nathanw 
    674  1.12.6.2  nathanw 	if (mesh_read_reg(sc, MESH_FIFO_COUNT) == 0) {	/* XXX cheat */
    675  1.12.6.2  nathanw 		MESH_SET_XFER(sc, 1);
    676  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGIN);
    677  1.12.6.2  nathanw 		sc->sc_imsglen = 0;
    678  1.12.6.2  nathanw 		sc->sc_nextstate = MESH_MSGIN;
    679  1.12.6.2  nathanw 		return;
    680  1.12.6.2  nathanw 	}
    681  1.12.6.2  nathanw 
    682  1.12.6.2  nathanw 	sc->sc_imsg[sc->sc_imsglen++] = mesh_read_reg(sc, MESH_FIFO);
    683  1.12.6.2  nathanw 
    684  1.12.6.2  nathanw 	if (sc->sc_imsglen == 1 && MSG_IS1BYTE(sc->sc_imsg[0]))
    685  1.12.6.2  nathanw 		goto gotit;
    686  1.12.6.2  nathanw 	if (sc->sc_imsglen == 2 && MSG_IS2BYTE(sc->sc_imsg[0]))
    687  1.12.6.2  nathanw 		goto gotit;
    688  1.12.6.2  nathanw 	if (sc->sc_imsglen >= 3 && MSG_ISEXTENDED(sc->sc_imsg[0]) &&
    689  1.12.6.2  nathanw 	    sc->sc_imsglen == sc->sc_imsg[1] + 2)
    690  1.12.6.2  nathanw 		goto gotit;
    691  1.12.6.2  nathanw 
    692  1.12.6.2  nathanw 	sc->sc_nextstate = MESH_MSGIN;
    693  1.12.6.2  nathanw 	MESH_SET_XFER(sc, 1);
    694  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGIN);
    695  1.12.6.2  nathanw 	return;
    696  1.12.6.2  nathanw 
    697  1.12.6.2  nathanw gotit:
    698  1.12.6.2  nathanw #ifdef MESH_DEBUG
    699  1.12.6.2  nathanw 	printf("msgin:");
    700  1.12.6.2  nathanw 	for (i = 0; i < sc->sc_imsglen; i++)
    701  1.12.6.2  nathanw 		printf(" 0x%02x", sc->sc_imsg[i]);
    702  1.12.6.2  nathanw 	printf("\n");
    703  1.12.6.2  nathanw #endif
    704  1.12.6.2  nathanw 
    705  1.12.6.2  nathanw 	switch (sc->sc_imsg[0]) {
    706  1.12.6.2  nathanw 	case MSG_CMDCOMPLETE:
    707  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_BUSFREE);
    708  1.12.6.2  nathanw 		sc->sc_nextstate = MESH_COMPLETE;
    709  1.12.6.2  nathanw 		sc->sc_imsglen = 0;
    710  1.12.6.2  nathanw 		return;
    711  1.12.6.2  nathanw 
    712  1.12.6.2  nathanw 	case MSG_MESSAGE_REJECT:
    713  1.12.6.2  nathanw 		if (sc->sc_msgout & SEND_SDTR) {
    714  1.12.6.2  nathanw 			printf("SDTR rejected\n");
    715  1.12.6.2  nathanw 			printf("using async mode\n");
    716  1.12.6.2  nathanw 			sc->sc_tinfo[scb->target].period = 0;
    717  1.12.6.2  nathanw 			sc->sc_tinfo[scb->target].offset = 0;
    718  1.12.6.2  nathanw 			mesh_setsync(sc, &sc->sc_tinfo[scb->target]);
    719  1.12.6.2  nathanw 			break;
    720  1.12.6.2  nathanw 		}
    721  1.12.6.2  nathanw 		break;
    722  1.12.6.2  nathanw 
    723  1.12.6.2  nathanw 	case MSG_NOOP:
    724  1.12.6.2  nathanw 		break;
    725  1.12.6.2  nathanw 
    726  1.12.6.2  nathanw 	case MSG_EXTENDED:
    727  1.12.6.2  nathanw 		goto extended_msg;
    728  1.12.6.2  nathanw 
    729  1.12.6.2  nathanw 	default:
    730  1.12.6.2  nathanw 		scsipi_printaddr(scb->xs->xs_periph);
    731  1.12.6.2  nathanw 		printf("unrecognized MESSAGE(0x%02x); sending REJECT\n",
    732  1.12.6.2  nathanw 			sc->sc_imsg[0]);
    733  1.12.6.2  nathanw 
    734  1.12.6.2  nathanw 	reject:
    735  1.12.6.2  nathanw 		mesh_msgout(sc, SEND_REJECT);
    736  1.12.6.2  nathanw 		return;
    737  1.12.6.2  nathanw 	}
    738  1.12.6.2  nathanw 	goto done;
    739  1.12.6.2  nathanw 
    740  1.12.6.2  nathanw extended_msg:
    741  1.12.6.2  nathanw 	/* process an extended message */
    742  1.12.6.2  nathanw 	switch (sc->sc_imsg[2]) {
    743  1.12.6.2  nathanw 	case MSG_EXT_SDTR:
    744  1.12.6.2  nathanw 	  {
    745  1.12.6.2  nathanw 		struct mesh_tinfo *ti = &sc->sc_tinfo[scb->target];
    746  1.12.6.2  nathanw 		int period = sc->sc_imsg[3];
    747  1.12.6.2  nathanw 		int offset = sc->sc_imsg[4];
    748  1.12.6.2  nathanw 		int r = 250 / period;
    749  1.12.6.2  nathanw 		int s = (100*250) / period - 100 * r;
    750  1.12.6.2  nathanw 
    751  1.12.6.2  nathanw 		if (period < sc->sc_minsync) {
    752  1.12.6.2  nathanw 			ti->period = sc->sc_minsync;
    753  1.12.6.2  nathanw 			ti->offset = 15;
    754  1.12.6.2  nathanw 			mesh_msgout(sc, SEND_SDTR);
    755  1.12.6.2  nathanw 			return;
    756  1.12.6.2  nathanw 		}
    757  1.12.6.2  nathanw 		scsipi_printaddr(scb->xs->xs_periph);
    758  1.12.6.2  nathanw 		/* XXX if (offset != 0) ... */
    759  1.12.6.2  nathanw 		printf("max sync rate %d.%02dMb/s\n", r, s);
    760  1.12.6.2  nathanw 		ti->period = period;
    761  1.12.6.2  nathanw 		ti->offset = offset;
    762  1.12.6.2  nathanw 		ti->flags |= T_SYNCNEGO;
    763  1.12.6.2  nathanw 		ti->flags |= T_SYNCMODE;
    764  1.12.6.2  nathanw 		mesh_setsync(sc, ti);
    765  1.12.6.2  nathanw 		goto done;
    766  1.12.6.2  nathanw 	  }
    767  1.12.6.2  nathanw 	default:
    768  1.12.6.2  nathanw 		printf("%s target %d: rejecting extended message 0x%x\n",
    769  1.12.6.2  nathanw 			sc->sc_dev.dv_xname, scb->target, sc->sc_imsg[0]);
    770  1.12.6.2  nathanw 		goto reject;
    771  1.12.6.2  nathanw 	}
    772  1.12.6.2  nathanw 
    773  1.12.6.2  nathanw done:
    774  1.12.6.2  nathanw 	sc->sc_imsglen = 0;
    775  1.12.6.2  nathanw 	sc->sc_nextstate = MESH_UNKNOWN;
    776  1.12.6.2  nathanw 
    777  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_BUSFREE); /* XXX really? */
    778  1.12.6.2  nathanw }
    779  1.12.6.2  nathanw 
    780  1.12.6.2  nathanw void
    781  1.12.6.2  nathanw mesh_msgout(sc, msg)
    782  1.12.6.2  nathanw 	struct mesh_softc *sc;
    783  1.12.6.2  nathanw 	int msg;
    784  1.12.6.2  nathanw {
    785  1.12.6.2  nathanw 	struct mesh_scb *scb = sc->sc_nexus;
    786  1.12.6.2  nathanw 	struct mesh_tinfo *ti;
    787  1.12.6.2  nathanw 	int lun, len, i;
    788  1.12.6.2  nathanw 
    789  1.12.6.2  nathanw 	DPRINTF("mesh_msgout: sending");
    790  1.12.6.2  nathanw 
    791  1.12.6.2  nathanw 	sc->sc_msgout = msg;
    792  1.12.6.2  nathanw 	len = 0;
    793  1.12.6.2  nathanw 
    794  1.12.6.2  nathanw 	if (msg & SEND_REJECT) {
    795  1.12.6.2  nathanw 		DPRINTF(" REJECT");
    796  1.12.6.2  nathanw 		sc->sc_omsg[len++] = MSG_MESSAGE_REJECT;
    797  1.12.6.2  nathanw 	}
    798  1.12.6.2  nathanw 	if (msg & SEND_IDENTIFY) {
    799  1.12.6.2  nathanw 		DPRINTF(" IDENTIFY");
    800  1.12.6.2  nathanw 		lun = scb->xs->xs_periph->periph_lun;
    801  1.12.6.2  nathanw 		sc->sc_omsg[len++] = MSG_IDENTIFY(lun, 0);
    802  1.12.6.2  nathanw 	}
    803  1.12.6.2  nathanw 	if (msg & SEND_SDTR) {
    804  1.12.6.2  nathanw 		DPRINTF(" SDTR");
    805  1.12.6.2  nathanw 		ti = &sc->sc_tinfo[scb->target];
    806  1.12.6.2  nathanw 		sc->sc_omsg[len++] = MSG_EXTENDED;
    807  1.12.6.2  nathanw 		sc->sc_omsg[len++] = 3;
    808  1.12.6.2  nathanw 		sc->sc_omsg[len++] = MSG_EXT_SDTR;
    809  1.12.6.2  nathanw 		sc->sc_omsg[len++] = ti->period;
    810  1.12.6.2  nathanw 		sc->sc_omsg[len++] = ti->offset;
    811  1.12.6.2  nathanw 	}
    812  1.12.6.2  nathanw 	DPRINTF("\n");
    813  1.12.6.2  nathanw 
    814  1.12.6.2  nathanw 	MESH_SET_XFER(sc, len);
    815  1.12.6.2  nathanw 	if (len == 1) {
    816  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGOUT);
    817  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_FIFO, sc->sc_omsg[0]);
    818  1.12.6.2  nathanw 	} else {
    819  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_MSGOUT | MESH_SEQ_ATN);
    820  1.12.6.2  nathanw 
    821  1.12.6.2  nathanw 		for (i = 0; i < len - 1; i++)
    822  1.12.6.2  nathanw 			mesh_set_reg(sc, MESH_FIFO, sc->sc_omsg[i]);
    823  1.12.6.2  nathanw 
    824  1.12.6.2  nathanw 		/* Wait for the FIFO empty... */
    825  1.12.6.2  nathanw 		while (mesh_read_reg(sc, MESH_FIFO_COUNT) > 0);
    826  1.12.6.2  nathanw 
    827  1.12.6.2  nathanw 		/* ...then write the last byte. */
    828  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_FIFO, sc->sc_omsg[i]);
    829  1.12.6.2  nathanw 	}
    830  1.12.6.2  nathanw 	sc->sc_nextstate = MESH_UNKNOWN;
    831  1.12.6.2  nathanw }
    832  1.12.6.2  nathanw 
    833  1.12.6.2  nathanw void
    834  1.12.6.2  nathanw mesh_bus_reset(sc)
    835  1.12.6.2  nathanw 	struct mesh_softc *sc;
    836  1.12.6.2  nathanw {
    837  1.12.6.2  nathanw 	DPRINTF("mesh_bus_reset\n");
    838  1.12.6.2  nathanw 
    839  1.12.6.2  nathanw 	/* Disable interrupts. */
    840  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_INTR_MASK, 0);
    841  1.12.6.2  nathanw 
    842  1.12.6.2  nathanw 	/* Assert RST line. */
    843  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_BUS_STATUS1, MESH_STATUS1_RST);
    844  1.12.6.2  nathanw 	delay(50);
    845  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_BUS_STATUS1, 0);
    846  1.12.6.2  nathanw 
    847  1.12.6.2  nathanw 	mesh_reset(sc);
    848  1.12.6.2  nathanw }
    849  1.12.6.2  nathanw 
    850  1.12.6.2  nathanw void
    851  1.12.6.2  nathanw mesh_reset(sc)
    852  1.12.6.2  nathanw 	struct mesh_softc *sc;
    853  1.12.6.2  nathanw {
    854  1.12.6.2  nathanw 	int i;
    855  1.12.6.2  nathanw 
    856  1.12.6.2  nathanw 	DPRINTF("mesh_reset\n");
    857  1.12.6.2  nathanw 
    858  1.12.6.2  nathanw 	/* Reset DMA first. */
    859  1.12.6.2  nathanw 	dbdma_reset(sc->sc_dmareg);
    860  1.12.6.2  nathanw 
    861  1.12.6.2  nathanw 	/* Disable interrupts. */
    862  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_INTR_MASK, 0);
    863  1.12.6.2  nathanw 
    864  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_RESET_MESH);
    865  1.12.6.2  nathanw 	delay(1);
    866  1.12.6.2  nathanw 
    867  1.12.6.2  nathanw 	/* Wait for reset done. */
    868  1.12.6.2  nathanw 	while (mesh_read_reg(sc, MESH_INTERRUPT) == 0);
    869  1.12.6.2  nathanw 
    870  1.12.6.2  nathanw 	/* Clear interrupts */
    871  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_INTERRUPT, 0x7);
    872  1.12.6.2  nathanw 
    873  1.12.6.2  nathanw 	/* Set SCSI ID */
    874  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SOURCE_ID, sc->sc_id);
    875  1.12.6.2  nathanw 
    876  1.12.6.2  nathanw 	/* Set to async mode by default. */
    877  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SYNC_PARAM, 2);
    878  1.12.6.2  nathanw 
    879  1.12.6.2  nathanw 	/* Set selection timeout to 250ms. */
    880  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEL_TIMEOUT, 250 * sc->sc_freq / 500);
    881  1.12.6.2  nathanw 
    882  1.12.6.2  nathanw 	/* Enable parity check. */
    883  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_ENABLE_PARITY);
    884  1.12.6.2  nathanw 
    885  1.12.6.2  nathanw 	/* Enable all interrupts. */
    886  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_INTR_MASK, 0x7);
    887  1.12.6.2  nathanw 
    888  1.12.6.2  nathanw 	for (i = 0; i < 7; i++) {
    889  1.12.6.2  nathanw 		struct mesh_tinfo *ti = &sc->sc_tinfo[i];
    890  1.12.6.2  nathanw 
    891  1.12.6.2  nathanw 		ti->flags = 0;
    892  1.12.6.2  nathanw 		ti->period = ti->offset = 0;
    893  1.12.6.2  nathanw 		if (sc->sc_cfflags & (0x100 << i))
    894  1.12.6.2  nathanw 			ti->flags |= T_SYNCNEGO;
    895  1.12.6.2  nathanw 	}
    896  1.12.6.2  nathanw 	sc->sc_nexus = NULL;
    897  1.12.6.2  nathanw }
    898  1.12.6.2  nathanw 
    899  1.12.6.2  nathanw int
    900  1.12.6.2  nathanw mesh_stp(sc, v)
    901  1.12.6.2  nathanw 	struct mesh_softc *sc;
    902  1.12.6.2  nathanw 	int v;
    903  1.12.6.2  nathanw {
    904  1.12.6.2  nathanw 	/*
    905  1.12.6.2  nathanw 	 * stp(v) = 5 * clock_period         (v == 0)
    906  1.12.6.2  nathanw 	 *        = (v + 2) * 2 clock_period (v > 0)
    907  1.12.6.2  nathanw 	 */
    908  1.12.6.2  nathanw 
    909  1.12.6.2  nathanw 	if (v == 0)
    910  1.12.6.2  nathanw 		return 5 * 250 / sc->sc_freq;
    911  1.12.6.2  nathanw 	else
    912  1.12.6.2  nathanw 		return (v + 2) * 2 * 250 / sc->sc_freq;
    913  1.12.6.2  nathanw }
    914  1.12.6.2  nathanw 
    915  1.12.6.2  nathanw void
    916  1.12.6.2  nathanw mesh_setsync(sc, ti)
    917  1.12.6.2  nathanw 	struct mesh_softc *sc;
    918  1.12.6.2  nathanw 	struct mesh_tinfo *ti;
    919  1.12.6.2  nathanw {
    920  1.12.6.2  nathanw 	int period = ti->period;
    921  1.12.6.2  nathanw 	int offset = ti->offset;
    922  1.12.6.2  nathanw 	int v;
    923  1.12.6.2  nathanw 
    924  1.12.6.2  nathanw 	if ((ti->flags & T_SYNCMODE) == 0)
    925  1.12.6.2  nathanw 		offset = 0;
    926  1.12.6.2  nathanw 
    927  1.12.6.2  nathanw 	if (offset == 0) {	/* async mode */
    928  1.12.6.2  nathanw 		mesh_set_reg(sc, MESH_SYNC_PARAM, 2);
    929  1.12.6.2  nathanw 		return;
    930  1.12.6.2  nathanw 	}
    931  1.12.6.2  nathanw 
    932  1.12.6.2  nathanw 	v = period * sc->sc_freq / 250 / 2 - 2;
    933  1.12.6.2  nathanw 	if (v < 0)
    934  1.12.6.2  nathanw 		v = 0;
    935  1.12.6.2  nathanw 	if (mesh_stp(sc, v) < period)
    936  1.12.6.2  nathanw 		v++;
    937  1.12.6.2  nathanw 	if (v > 15)
    938  1.12.6.2  nathanw 		v = 15;
    939  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SYNC_PARAM, (offset << 4) | v);
    940  1.12.6.2  nathanw }
    941  1.12.6.2  nathanw 
    942  1.12.6.2  nathanw struct mesh_scb *
    943  1.12.6.2  nathanw mesh_get_scb(sc)
    944  1.12.6.2  nathanw 	struct mesh_softc *sc;
    945  1.12.6.2  nathanw {
    946  1.12.6.2  nathanw 	struct mesh_scb *scb;
    947  1.12.6.2  nathanw 	int s;
    948  1.12.6.2  nathanw 
    949  1.12.6.2  nathanw 	s = splbio();
    950  1.12.6.2  nathanw 	if ((scb = sc->free_scb.tqh_first) != NULL)
    951  1.12.6.2  nathanw 		TAILQ_REMOVE(&sc->free_scb, scb, chain);
    952  1.12.6.2  nathanw 	splx(s);
    953  1.12.6.2  nathanw 
    954  1.12.6.2  nathanw 	return scb;
    955  1.12.6.2  nathanw }
    956  1.12.6.2  nathanw 
    957  1.12.6.2  nathanw void
    958  1.12.6.2  nathanw mesh_free_scb(sc, scb)
    959  1.12.6.2  nathanw 	struct mesh_softc *sc;
    960  1.12.6.2  nathanw 	struct mesh_scb *scb;
    961  1.12.6.2  nathanw {
    962  1.12.6.2  nathanw 	int s;
    963  1.12.6.2  nathanw 
    964  1.12.6.2  nathanw 	s = splbio();
    965  1.12.6.2  nathanw 	TAILQ_INSERT_HEAD(&sc->free_scb, scb, chain);
    966  1.12.6.2  nathanw 	splx(s);
    967  1.12.6.2  nathanw }
    968  1.12.6.2  nathanw 
    969  1.12.6.2  nathanw void
    970  1.12.6.2  nathanw mesh_scsi_request(chan, req, arg)
    971  1.12.6.2  nathanw 	struct scsipi_channel *chan;
    972  1.12.6.2  nathanw 	scsipi_adapter_req_t req;
    973  1.12.6.2  nathanw 	void *arg;
    974  1.12.6.2  nathanw {
    975  1.12.6.2  nathanw 	struct scsipi_xfer *xs;
    976  1.12.6.2  nathanw 	struct scsipi_periph *periph;
    977  1.12.6.2  nathanw 	struct mesh_softc *sc = (void *)chan->chan_adapter->adapt_dev;
    978  1.12.6.2  nathanw 	struct mesh_scb *scb;
    979  1.12.6.2  nathanw 	u_int flags;
    980  1.12.6.2  nathanw 	int s;
    981  1.12.6.2  nathanw 
    982  1.12.6.2  nathanw 	switch (req) {
    983  1.12.6.2  nathanw 	case ADAPTER_REQ_RUN_XFER:
    984  1.12.6.2  nathanw 		xs = arg;
    985  1.12.6.2  nathanw 		periph = xs->xs_periph;
    986  1.12.6.2  nathanw 		flags = xs->xs_control;
    987  1.12.6.2  nathanw 
    988  1.12.6.2  nathanw 
    989  1.12.6.2  nathanw 		if ((scb = mesh_get_scb(sc)) == NULL) {
    990  1.12.6.2  nathanw 			xs->error = XS_RESOURCE_SHORTAGE;
    991  1.12.6.2  nathanw 			scsipi_done(xs);
    992  1.12.6.2  nathanw 			return;
    993  1.12.6.2  nathanw 		}
    994  1.12.6.2  nathanw 		scb->xs = xs;
    995  1.12.6.2  nathanw 		scb->flags = 0;
    996  1.12.6.2  nathanw 		scb->status = 0;
    997  1.12.6.2  nathanw 		scb->daddr = (vaddr_t)xs->data;
    998  1.12.6.2  nathanw 		scb->dlen = xs->datalen;
    999  1.12.6.2  nathanw 		scb->resid = xs->datalen;
   1000  1.12.6.2  nathanw 		memcpy(&scb->cmd, xs->cmd, xs->cmdlen);
   1001  1.12.6.2  nathanw 		scb->cmdlen = xs->cmdlen;
   1002  1.12.6.2  nathanw 		scb->target = periph->periph_target;
   1003  1.12.6.2  nathanw 		sc->sc_imsglen = 0;	/* XXX ? */
   1004  1.12.6.2  nathanw 
   1005  1.12.6.2  nathanw #ifdef MESH_DEBUG
   1006  1.12.6.2  nathanw {
   1007  1.12.6.2  nathanw 		int i;
   1008  1.12.6.2  nathanw 		printf("mesh_scsi_cmd: target = %d, cdb = %02x",
   1009  1.12.6.2  nathanw 		       scb->target, scb->cmd.opcode);
   1010  1.12.6.2  nathanw 		for (i = 0; i < 5; i++)
   1011  1.12.6.2  nathanw 			printf(" %02x", scb->cmd.bytes[i]);
   1012  1.12.6.2  nathanw 		printf("\n");
   1013  1.12.6.2  nathanw }
   1014  1.12.6.2  nathanw #endif
   1015  1.12.6.2  nathanw 
   1016  1.12.6.2  nathanw 		if (flags & XS_CTL_POLL)
   1017  1.12.6.2  nathanw 			scb->flags |= MESH_POLL;
   1018  1.12.6.2  nathanw #if 0
   1019  1.12.6.2  nathanw 		if (flags & XS_CTL_DATA_OUT)
   1020  1.12.6.2  nathanw 			scb->flags &= ~MESH_READ;
   1021  1.12.6.2  nathanw #endif
   1022  1.12.6.2  nathanw 		if (flags & XS_CTL_DATA_IN)
   1023  1.12.6.2  nathanw 			scb->flags |= MESH_READ;
   1024  1.12.6.2  nathanw 
   1025  1.12.6.2  nathanw 		s = splbio();
   1026  1.12.6.2  nathanw 
   1027  1.12.6.2  nathanw 		TAILQ_INSERT_TAIL(&sc->ready_scb, scb, chain);
   1028  1.12.6.2  nathanw 
   1029  1.12.6.2  nathanw 		if (sc->sc_nexus == NULL)	/* IDLE */
   1030  1.12.6.2  nathanw 			mesh_sched(sc);
   1031  1.12.6.2  nathanw 
   1032  1.12.6.2  nathanw 		splx(s);
   1033  1.12.6.2  nathanw 
   1034  1.12.6.2  nathanw 		if ((flags & XS_CTL_POLL) == 0)
   1035  1.12.6.2  nathanw 			return;
   1036  1.12.6.2  nathanw 
   1037  1.12.6.2  nathanw 		if (mesh_poll(sc, xs)) {
   1038  1.12.6.2  nathanw 			printf("%s: timeout\n", sc->sc_dev.dv_xname);
   1039  1.12.6.2  nathanw 			if (mesh_poll(sc, xs))
   1040  1.12.6.2  nathanw 				printf("%s: timeout again\n", sc->sc_dev.dv_xname);
   1041  1.12.6.2  nathanw 		}
   1042  1.12.6.2  nathanw 		return;
   1043  1.12.6.2  nathanw 
   1044  1.12.6.2  nathanw 	case ADAPTER_REQ_GROW_RESOURCES:
   1045  1.12.6.2  nathanw 		/* XXX Not supported. */
   1046  1.12.6.2  nathanw 		return;
   1047  1.12.6.2  nathanw 
   1048  1.12.6.2  nathanw 	case ADAPTER_REQ_SET_XFER_MODE:
   1049  1.12.6.2  nathanw 		/* XXX Not supported. */
   1050  1.12.6.2  nathanw 		return;
   1051  1.12.6.2  nathanw 	}
   1052  1.12.6.2  nathanw 
   1053  1.12.6.2  nathanw }
   1054  1.12.6.2  nathanw 
   1055  1.12.6.2  nathanw void
   1056  1.12.6.2  nathanw mesh_sched(sc)
   1057  1.12.6.2  nathanw 	struct mesh_softc *sc;
   1058  1.12.6.2  nathanw {
   1059  1.12.6.2  nathanw 	struct scsipi_xfer *xs;
   1060  1.12.6.2  nathanw 	struct mesh_scb *scb;
   1061  1.12.6.2  nathanw 
   1062  1.12.6.2  nathanw 	scb = sc->ready_scb.tqh_first;
   1063  1.12.6.2  nathanw start:
   1064  1.12.6.2  nathanw 	if (scb == NULL)
   1065  1.12.6.2  nathanw 		return;
   1066  1.12.6.2  nathanw 
   1067  1.12.6.2  nathanw 	xs = scb->xs;
   1068  1.12.6.2  nathanw 
   1069  1.12.6.2  nathanw 	if (sc->sc_nexus == NULL) {
   1070  1.12.6.2  nathanw 		TAILQ_REMOVE(&sc->ready_scb, scb, chain);
   1071  1.12.6.2  nathanw 		sc->sc_nexus = scb;
   1072  1.12.6.2  nathanw 		mesh_select(sc, scb);
   1073  1.12.6.2  nathanw 		return;
   1074  1.12.6.2  nathanw 	}
   1075  1.12.6.2  nathanw 
   1076  1.12.6.2  nathanw 	scb = scb->chain.tqe_next;
   1077  1.12.6.2  nathanw 	goto start;
   1078  1.12.6.2  nathanw }
   1079  1.12.6.2  nathanw 
   1080  1.12.6.2  nathanw int
   1081  1.12.6.2  nathanw mesh_poll(sc, xs)
   1082  1.12.6.2  nathanw 	struct mesh_softc *sc;
   1083  1.12.6.2  nathanw 	struct scsipi_xfer *xs;
   1084  1.12.6.2  nathanw {
   1085  1.12.6.2  nathanw 	int count = xs->timeout;
   1086  1.12.6.2  nathanw 
   1087  1.12.6.2  nathanw 	while (count) {
   1088  1.12.6.2  nathanw 		if (mesh_read_reg(sc, MESH_INTERRUPT))
   1089  1.12.6.2  nathanw 			mesh_intr(sc);
   1090  1.12.6.2  nathanw 
   1091  1.12.6.2  nathanw 		if (xs->xs_status & XS_STS_DONE)
   1092  1.12.6.2  nathanw 			return 0;
   1093  1.12.6.2  nathanw 		delay(1000);
   1094  1.12.6.2  nathanw 		count--;
   1095  1.12.6.2  nathanw 	};
   1096  1.12.6.2  nathanw 	return 1;
   1097  1.12.6.2  nathanw }
   1098  1.12.6.2  nathanw 
   1099  1.12.6.2  nathanw void
   1100  1.12.6.2  nathanw mesh_done(sc, scb)
   1101  1.12.6.2  nathanw 	struct mesh_softc *sc;
   1102  1.12.6.2  nathanw 	struct mesh_scb *scb;
   1103  1.12.6.2  nathanw {
   1104  1.12.6.2  nathanw 	struct scsipi_xfer *xs = scb->xs;
   1105  1.12.6.2  nathanw 
   1106  1.12.6.2  nathanw 	DPRINTF("mesh_done\n");
   1107  1.12.6.2  nathanw 
   1108  1.12.6.2  nathanw 	sc->sc_nextstate = MESH_BUSFREE;
   1109  1.12.6.2  nathanw 	sc->sc_nexus = NULL;
   1110  1.12.6.2  nathanw 
   1111  1.12.6.2  nathanw 	callout_stop(&scb->xs->xs_callout);
   1112  1.12.6.2  nathanw 
   1113  1.12.6.2  nathanw 	if (scb->status == SCSI_BUSY) {
   1114  1.12.6.2  nathanw 		xs->error = XS_BUSY;
   1115  1.12.6.2  nathanw 		printf("Target busy\n");
   1116  1.12.6.2  nathanw 	}
   1117  1.12.6.2  nathanw 
   1118  1.12.6.2  nathanw 	xs->xs_status = scb->status;
   1119  1.12.6.2  nathanw 	xs->resid = scb->resid;
   1120  1.12.6.2  nathanw 	if (scb->status == SCSI_CHECK) {
   1121  1.12.6.2  nathanw 		xs->error = XS_BUSY;
   1122  1.12.6.2  nathanw 	}
   1123  1.12.6.2  nathanw 
   1124  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SYNC_PARAM, 2);
   1125  1.12.6.2  nathanw 
   1126  1.12.6.2  nathanw 	if ((xs->xs_control & XS_CTL_POLL) == 0)
   1127  1.12.6.2  nathanw 		mesh_sched(sc);
   1128  1.12.6.2  nathanw 
   1129  1.12.6.2  nathanw 	scsipi_done(xs);
   1130  1.12.6.2  nathanw 	mesh_free_scb(sc, scb);
   1131  1.12.6.2  nathanw }
   1132  1.12.6.2  nathanw 
   1133  1.12.6.2  nathanw void
   1134  1.12.6.2  nathanw mesh_timeout(arg)
   1135  1.12.6.2  nathanw 	void *arg;
   1136  1.12.6.2  nathanw {
   1137  1.12.6.2  nathanw 	struct mesh_scb *scb = arg;
   1138  1.12.6.2  nathanw 	struct mesh_softc *sc =
   1139  1.12.6.2  nathanw 	    (void *)scb->xs->xs_periph->periph_channel->chan_adapter->adapt_dev;
   1140  1.12.6.2  nathanw 	int s;
   1141  1.12.6.2  nathanw 	int status0, status1;
   1142  1.12.6.2  nathanw 	int intr, error, exception;
   1143  1.12.6.2  nathanw 
   1144  1.12.6.2  nathanw 	printf("%s: timeout state %d\n", sc->sc_dev.dv_xname, sc->sc_nextstate);
   1145  1.12.6.2  nathanw 
   1146  1.12.6.2  nathanw 	intr = mesh_read_reg(sc, MESH_INTERRUPT);
   1147  1.12.6.2  nathanw 	exception = mesh_read_reg(sc, MESH_EXCEPTION);
   1148  1.12.6.2  nathanw 	error = mesh_read_reg(sc, MESH_ERROR);
   1149  1.12.6.2  nathanw 	status0 = mesh_read_reg(sc, MESH_BUS_STATUS0);
   1150  1.12.6.2  nathanw 	status1 = mesh_read_reg(sc, MESH_BUS_STATUS1);
   1151  1.12.6.2  nathanw 
   1152  1.12.6.2  nathanw 	s = splbio();
   1153  1.12.6.2  nathanw 	if (sc->sc_flags & MESH_DMA_ACTIVE) {
   1154  1.12.6.2  nathanw 		printf("mesh: resetting dma\n");
   1155  1.12.6.2  nathanw 		dbdma_reset(sc->sc_dmareg);
   1156  1.12.6.2  nathanw 	}
   1157  1.12.6.2  nathanw 	scb->xs->error = XS_TIMEOUT;
   1158  1.12.6.2  nathanw 
   1159  1.12.6.2  nathanw 	mesh_set_reg(sc, MESH_SEQUENCE, MESH_CMD_BUSFREE);
   1160  1.12.6.2  nathanw 	sc->sc_nextstate = MESH_COMPLETE;
   1161  1.12.6.2  nathanw 
   1162  1.12.6.2  nathanw 	splx(s);
   1163  1.12.6.2  nathanw }
   1164  1.12.6.2  nathanw 
   1165  1.12.6.2  nathanw void
   1166  1.12.6.2  nathanw mesh_minphys(bp)
   1167  1.12.6.2  nathanw 	struct buf *bp;
   1168  1.12.6.2  nathanw {
   1169  1.12.6.2  nathanw 	if (bp->b_bcount > 64*1024)
   1170  1.12.6.2  nathanw 		bp->b_bcount = 64*1024;
   1171  1.12.6.2  nathanw 
   1172  1.12.6.2  nathanw 	minphys(bp);
   1173  1.12.6.2  nathanw }
   1174