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