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