1130293Sscottl/*-
2130293Sscottl * Copyright (c) 2004 Scott Long
3182876Smarius * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>
4130293Sscottl * All rights reserved.
5130293Sscottl *
6130293Sscottl * Redistribution and use in source and binary forms, with or without
7130293Sscottl * modification, are permitted provided that the following conditions
8130293Sscottl * are met:
9130293Sscottl * 1. Redistributions of source code must retain the above copyright
10130293Sscottl *    notice, this list of conditions and the following disclaimer.
11130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright
12130293Sscottl *    notice, this list of conditions and the following disclaimer in the
13130293Sscottl *    documentation and/or other materials provided with the distribution.
14130293Sscottl *
15130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16130293Sscottl * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17130293Sscottl * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18130293Sscottl * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19130293Sscottl * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20130293Sscottl * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21130293Sscottl * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22130293Sscottl * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23130293Sscottl * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24130293Sscottl * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25130293Sscottl * SUCH DAMAGE.
26130293Sscottl *
27130293Sscottl */
28130293Sscottl
29226381Smarius/*	$NetBSD: esp_sbus.c,v 1.51 2009/09/17 16:28:12 tsutsui Exp $	*/
30130293Sscottl
31130293Sscottl/*-
32130293Sscottl * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
33130293Sscottl * All rights reserved.
34130293Sscottl *
35130293Sscottl * This code is derived from software contributed to The NetBSD Foundation
36130293Sscottl * by Charles M. Hannum; Jason R. Thorpe of the Numerical Aerospace
37130293Sscottl * Simulation Facility, NASA Ames Research Center; Paul Kranenburg.
38130293Sscottl *
39130293Sscottl * Redistribution and use in source and binary forms, with or without
40130293Sscottl * modification, are permitted provided that the following conditions
41130293Sscottl * are met:
42130293Sscottl * 1. Redistributions of source code must retain the above copyright
43130293Sscottl *    notice, this list of conditions and the following disclaimer.
44130293Sscottl * 2. Redistributions in binary form must reproduce the above copyright
45130293Sscottl *    notice, this list of conditions and the following disclaimer in the
46130293Sscottl *    documentation and/or other materials provided with the distribution.
47130293Sscottl *
48130293Sscottl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
49130293Sscottl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50130293Sscottl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51130293Sscottl * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
52130293Sscottl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53130293Sscottl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54130293Sscottl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55130293Sscottl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56130293Sscottl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57130293Sscottl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58130293Sscottl * POSSIBILITY OF SUCH DAMAGE.
59130293Sscottl */
60130293Sscottl
61130293Sscottl#include <sys/cdefs.h>
62130293Sscottl__FBSDID("$FreeBSD$");
63130293Sscottl
64130293Sscottl#include <sys/param.h>
65130293Sscottl#include <sys/systm.h>
66130293Sscottl#include <sys/bus.h>
67130293Sscottl#include <sys/kernel.h>
68182876Smarius#include <sys/lock.h>
69130833Sscottl#include <sys/module.h>
70182876Smarius#include <sys/mutex.h>
71226947Smarius#include <sys/rman.h>
72130293Sscottl
73133589Smarius#include <dev/ofw/ofw_bus.h>
74133589Smarius#include <dev/ofw/openfirm.h>
75130293Sscottl#include <machine/bus.h>
76207885Smarius#include <machine/ofw_machdep.h>
77130293Sscottl#include <machine/resource.h>
78130293Sscottl
79130293Sscottl#include <cam/cam.h>
80130293Sscottl#include <cam/cam_ccb.h>
81130293Sscottl#include <cam/scsi/scsi_all.h>
82182876Smarius#include <cam/scsi/scsi_message.h>
83130293Sscottl
84137533Strhodes#include <sparc64/sbus/lsi64854reg.h>
85137533Strhodes#include <sparc64/sbus/lsi64854var.h>
86137533Strhodes#include <sparc64/sbus/sbusvar.h>
87130293Sscottl
88130293Sscottl#include <dev/esp/ncr53c9xreg.h>
89130293Sscottl#include <dev/esp/ncr53c9xvar.h>
90130293Sscottl
91130293Sscottl/* #define ESP_SBUS_DEBUG */
92130293Sscottl
93130293Sscottlstruct esp_softc {
94130293Sscottl	struct ncr53c9x_softc	sc_ncr53c9x;	/* glue to MI code */
95226947Smarius	device_t		sc_dev;
96130293Sscottl
97130293Sscottl	struct resource		*sc_res;
98130293Sscottl
99130293Sscottl	struct resource		*sc_irqres;
100130293Sscottl	void			*sc_irq;
101130293Sscottl
102133039Strhodes	struct lsi64854_softc	*sc_dma;	/* pointer to my DMA */
103130293Sscottl};
104130293Sscottl
105146392Smariusstatic int	esp_probe(device_t);
106146392Smariusstatic int	esp_dma_attach(device_t);
107146392Smariusstatic int	esp_dma_detach(device_t);
108130293Sscottlstatic int	esp_sbus_attach(device_t);
109130293Sscottlstatic int	esp_sbus_detach(device_t);
110146392Smariusstatic int	esp_suspend(device_t);
111146392Smariusstatic int	esp_resume(device_t);
112130293Sscottl
113146392Smariusstatic device_method_t esp_dma_methods[] = {
114146392Smarius	DEVMETHOD(device_probe,		esp_probe),
115146392Smarius	DEVMETHOD(device_attach,	esp_dma_attach),
116146392Smarius	DEVMETHOD(device_detach,	esp_dma_detach),
117146392Smarius	DEVMETHOD(device_suspend,	esp_suspend),
118146392Smarius	DEVMETHOD(device_resume,	esp_resume),
119226947Smarius
120227848Smarius	DEVMETHOD_END
121146392Smarius};
122146392Smarius
123146392Smariusstatic driver_t esp_dma_driver = {
124146392Smarius	"esp",
125146392Smarius	esp_dma_methods,
126146392Smarius	sizeof(struct esp_softc)
127146392Smarius};
128146392Smarius
129146392SmariusDRIVER_MODULE(esp, dma, esp_dma_driver, esp_devclass, 0, 0);
130165102SmjacobMODULE_DEPEND(esp, dma, 1, 1, 1);
131146392Smarius
132130293Sscottlstatic device_method_t esp_sbus_methods[] = {
133146392Smarius	DEVMETHOD(device_probe,		esp_probe),
134130293Sscottl	DEVMETHOD(device_attach,	esp_sbus_attach),
135130293Sscottl	DEVMETHOD(device_detach,	esp_sbus_detach),
136146392Smarius	DEVMETHOD(device_suspend,	esp_suspend),
137146392Smarius	DEVMETHOD(device_resume,	esp_resume),
138226947Smarius
139227848Smarius	DEVMETHOD_END
140130293Sscottl};
141130293Sscottl
142130293Sscottlstatic driver_t esp_sbus_driver = {
143130293Sscottl	"esp",
144130293Sscottl	esp_sbus_methods,
145130293Sscottl	sizeof(struct esp_softc)
146130293Sscottl};
147130293Sscottl
148130293SscottlDRIVER_MODULE(esp, sbus, esp_sbus_driver, esp_devclass, 0, 0);
149165102SmjacobMODULE_DEPEND(esp, sbus, 1, 1, 1);
150130293Sscottl
151130293Sscottl/*
152180692Smarius * Functions and the switch for the MI code
153130293Sscottl */
154226381Smariusstatic uint8_t	esp_read_reg(struct ncr53c9x_softc *sc, int reg);
155226381Smariusstatic void	esp_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t v);
156180692Smariusstatic int	esp_dma_isintr(struct ncr53c9x_softc *sc);
157180692Smariusstatic void	esp_dma_reset(struct ncr53c9x_softc *sc);
158180692Smariusstatic int	esp_dma_intr(struct ncr53c9x_softc *sc);
159226381Smariusstatic int	esp_dma_setup(struct ncr53c9x_softc *sc, void **addr,
160180692Smarius		    size_t *len, int datain, size_t *dmasize);
161180692Smariusstatic void	esp_dma_go(struct ncr53c9x_softc *sc);
162180692Smariusstatic void	esp_dma_stop(struct ncr53c9x_softc *sc);
163180692Smariusstatic int	esp_dma_isactive(struct ncr53c9x_softc *sc);
164182876Smariusstatic int	espattach(struct esp_softc *esc,
165182876Smarius		    const struct ncr53c9x_glue *gluep);
166182876Smariusstatic int	espdetach(struct esp_softc *esc);
167130293Sscottl
168263763Sdimstatic const struct ncr53c9x_glue esp_sbus_glue = {
169130293Sscottl	esp_read_reg,
170130293Sscottl	esp_write_reg,
171130293Sscottl	esp_dma_isintr,
172130293Sscottl	esp_dma_reset,
173130293Sscottl	esp_dma_intr,
174130293Sscottl	esp_dma_setup,
175130293Sscottl	esp_dma_go,
176130293Sscottl	esp_dma_stop,
177130293Sscottl	esp_dma_isactive,
178130293Sscottl};
179130293Sscottl
180130293Sscottlstatic int
181146392Smariusesp_probe(device_t dev)
182130293Sscottl{
183133589Smarius	const char *name;
184130293Sscottl
185133589Smarius	name = ofw_bus_get_name(dev);
186130293Sscottl	if (strcmp("SUNW,fas", name) == 0) {
187130293Sscottl		device_set_desc(dev, "Sun FAS366 Fast-Wide SCSI");
188145201Smarius	        return (BUS_PROBE_DEFAULT);
189146392Smarius	} else if (strcmp("esp", name) == 0) {
190146392Smarius		device_set_desc(dev, "Sun ESP SCSI/Sun FAS Fast-SCSI");
191146392Smarius	        return (BUS_PROBE_DEFAULT);
192130293Sscottl	}
193130293Sscottl
194130293Sscottl	return (ENXIO);
195130293Sscottl}
196130293Sscottl
197130293Sscottlstatic int
198130293Sscottlesp_sbus_attach(device_t dev)
199130293Sscottl{
200145201Smarius	struct esp_softc *esc;
201145201Smarius	struct ncr53c9x_softc *sc;
202130293Sscottl	struct lsi64854_softc *lsc;
203146392Smarius	device_t *children;
204182876Smarius	int error, i, nchildren;
205130293Sscottl
206145201Smarius	esc = device_get_softc(dev);
207145201Smarius	sc = &esc->sc_ncr53c9x;
208145201Smarius
209146392Smarius	lsc = NULL;
210130293Sscottl	esc->sc_dev = dev;
211146392Smarius	sc->sc_freq = sbus_get_clockfreq(dev);
212130293Sscottl
213182876Smarius	if (strcmp(ofw_bus_get_name(dev), "SUNW,fas") == 0) {
214146392Smarius		/*
215146392Smarius		 * Allocate space for DMA, in SUNW,fas there are no
216146392Smarius		 * separate DMA devices.
217146392Smarius		 */
218146392Smarius		lsc = malloc(sizeof (struct lsi64854_softc), M_DEVBUF,
219146392Smarius		    M_NOWAIT | M_ZERO);
220146392Smarius		if (lsc == NULL) {
221146392Smarius			device_printf(dev, "out of memory (lsi64854_softc)\n");
222146392Smarius			return (ENOMEM);
223146392Smarius		}
224146392Smarius		esc->sc_dma = lsc;
225146392Smarius
226146392Smarius		/*
227146392Smarius		 * SUNW,fas have 2 register spaces: DMA (lsi64854) and
228146392Smarius		 * SCSI core (ncr53c9x).
229146392Smarius		 */
230146392Smarius
231146392Smarius		/* Allocate DMA registers. */
232182876Smarius		i = 0;
233146392Smarius		if ((lsc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
234182876Smarius		    &i, RF_ACTIVE)) == NULL) {
235146392Smarius			device_printf(dev, "cannot allocate DMA registers\n");
236146392Smarius			error = ENXIO;
237146392Smarius			goto fail_sbus_lsc;
238146392Smarius		}
239146392Smarius
240146392Smarius		/* Create a parent DMA tag based on this bus. */
241146392Smarius		error = bus_dma_tag_create(
242166165Smarius		    bus_get_dma_tag(dev),	/* parent */
243182876Smarius		    1, 0,			/* alignment, boundary */
244146392Smarius		    BUS_SPACE_MAXADDR,		/* lowaddr */
245146392Smarius		    BUS_SPACE_MAXADDR,		/* highaddr */
246146392Smarius		    NULL, NULL,			/* filter, filterarg */
247226947Smarius		    BUS_SPACE_MAXSIZE,		/* maxsize */
248226947Smarius		    BUS_SPACE_UNRESTRICTED,	/* nsegments */
249226947Smarius		    BUS_SPACE_MAXSIZE,		/* maxsegsize */
250146392Smarius		    0,				/* flags */
251146392Smarius		    NULL, NULL,			/* no locking */
252146392Smarius		    &lsc->sc_parent_dmat);
253146392Smarius		if (error != 0) {
254146392Smarius			device_printf(dev, "cannot allocate parent DMA tag\n");
255146392Smarius			goto fail_sbus_lres;
256146392Smarius		}
257146392Smarius
258182876Smarius		i = sbus_get_burstsz(dev);
259182876Smarius
260146392Smarius#ifdef ESP_SBUS_DEBUG
261182876Smarius		printf("%s: burst 0x%x\n", __func__, i);
262146392Smarius#endif
263146392Smarius
264182876Smarius		lsc->sc_burst = (i & SBUS_BURST_32) ? 32 :
265182876Smarius		    (i & SBUS_BURST_16) ? 16 : 0;
266146392Smarius
267146392Smarius		lsc->sc_channel = L64854_CHANNEL_SCSI;
268146392Smarius		lsc->sc_client = sc;
269146392Smarius		lsc->sc_dev = dev;
270146392Smarius
271146392Smarius		/*
272146392Smarius		 * Allocate SCSI core registers.
273146392Smarius		 */
274182876Smarius		i = 1;
275146392Smarius		if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
276182876Smarius		    &i, RF_ACTIVE)) == NULL) {
277146392Smarius			device_printf(dev,
278146392Smarius			    "cannot allocate SCSI core registers\n");
279146392Smarius			error = ENXIO;
280182876Smarius			goto fail_sbus_lpdma;
281146392Smarius		}
282146392Smarius	} else {
283146392Smarius		/*
284180692Smarius		 * Search accompanying DMA engine.  It should have been
285146392Smarius		 * already attached otherwise there isn't much we can do.
286146392Smarius		 */
287146392Smarius		if (device_get_children(device_get_parent(dev), &children,
288146392Smarius		    &nchildren) != 0) {
289146392Smarius			device_printf(dev, "cannot determine siblings\n");
290146392Smarius			return (ENXIO);
291146392Smarius		}
292146392Smarius		for (i = 0; i < nchildren; i++) {
293146392Smarius			if (device_is_attached(children[i]) &&
294226947Smarius			    sbus_get_slot(children[i]) ==
295226947Smarius			    sbus_get_slot(dev) &&
296226947Smarius			    strcmp(ofw_bus_get_name(children[i]),
297226947Smarius			    "dma") == 0) {
298146392Smarius				/* XXX hackery */
299146392Smarius				esc->sc_dma = (struct lsi64854_softc *)
300146392Smarius				    device_get_softc(children[i]);
301146392Smarius				break;
302146392Smarius			}
303146392Smarius		}
304146392Smarius		free(children, M_TEMP);
305146392Smarius		if (esc->sc_dma == NULL) {
306146392Smarius			device_printf(dev, "cannot find DMA engine\n");
307146392Smarius			return (ENXIO);
308146392Smarius		}
309146392Smarius		esc->sc_dma->sc_client = sc;
310146392Smarius
311146392Smarius		/*
312146392Smarius		 * Allocate SCSI core registers.
313146392Smarius		 */
314182876Smarius		i = 0;
315146392Smarius		if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
316182876Smarius		    &i, RF_ACTIVE)) == NULL) {
317146392Smarius			device_printf(dev,
318146392Smarius			    "cannot allocate SCSI core registers\n");
319146392Smarius			return (ENXIO);
320146392Smarius		}
321130293Sscottl	}
322130293Sscottl
323146392Smarius	error = espattach(esc, &esp_sbus_glue);
324146392Smarius	if (error != 0) {
325146392Smarius		device_printf(dev, "espattach failed\n");
326146392Smarius		goto fail_sbus_eres;
327146392Smarius	}
328130293Sscottl
329146392Smarius	return (0);
330146392Smarius
331146392Smarius fail_sbus_eres:
332182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(esc->sc_res),
333182876Smarius	    esc->sc_res);
334182876Smarius	if (strcmp(ofw_bus_get_name(dev), "SUNW,fas") != 0)
335146392Smarius		return (error);
336146392Smarius fail_sbus_lpdma:
337146392Smarius	bus_dma_tag_destroy(lsc->sc_parent_dmat);
338146392Smarius fail_sbus_lres:
339182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lsc->sc_res),
340182876Smarius	    lsc->sc_res);
341146392Smarius fail_sbus_lsc:
342146392Smarius	free(lsc, M_DEVBUF);
343146392Smarius	return (error);
344146392Smarius}
345146392Smarius
346146392Smariusstatic int
347146392Smariusesp_sbus_detach(device_t dev)
348146392Smarius{
349146392Smarius	struct esp_softc *esc;
350146392Smarius	struct lsi64854_softc *lsc;
351146392Smarius	int error;
352146392Smarius
353146392Smarius	esc = device_get_softc(dev);
354146392Smarius	lsc = esc->sc_dma;
355146392Smarius
356182876Smarius	error = espdetach(esc);
357146392Smarius	if (error != 0)
358146392Smarius		return (error);
359182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(esc->sc_res),
360182876Smarius		esc->sc_res);
361146392Smarius	if (strcmp(ofw_bus_get_name(dev), "SUNW,fas") != 0)
362146392Smarius		return (0);
363146392Smarius	bus_dma_tag_destroy(lsc->sc_parent_dmat);
364182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(lsc->sc_res),
365182876Smarius	    lsc->sc_res);
366146392Smarius	free(lsc, M_DEVBUF);
367146392Smarius
368146392Smarius	return (0);
369146392Smarius}
370146392Smarius
371146392Smariusstatic int
372146392Smariusesp_dma_attach(device_t dev)
373146392Smarius{
374146392Smarius	struct esp_softc *esc;
375146392Smarius	struct ncr53c9x_softc *sc;
376182876Smarius	int error, i;
377146392Smarius
378146392Smarius	esc = device_get_softc(dev);
379146392Smarius	sc = &esc->sc_ncr53c9x;
380146392Smarius
381146392Smarius	esc->sc_dev = dev;
382182876Smarius	if (OF_getprop(ofw_bus_get_node(dev), "clock-frequency",
383182876Smarius	    &sc->sc_freq, sizeof(sc->sc_freq)) == -1) {
384146392Smarius		printf("failed to query OFW for clock-frequency\n");
385130293Sscottl		return (ENXIO);
386130293Sscottl	}
387130293Sscottl
388146392Smarius	/* XXX hackery */
389146392Smarius	esc->sc_dma = (struct lsi64854_softc *)
390146392Smarius	    device_get_softc(device_get_parent(dev));
391146392Smarius	esc->sc_dma->sc_client = sc;
392130293Sscottl
393130293Sscottl	/*
394146392Smarius	 * Allocate SCSI core registers.
395130293Sscottl	 */
396182876Smarius	i = 0;
397130293Sscottl	if ((esc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
398182876Smarius	    &i, RF_ACTIVE)) == NULL) {
399145201Smarius		device_printf(dev, "cannot allocate SCSI core registers\n");
400130293Sscottl		return (ENXIO);
401130293Sscottl	}
402130293Sscottl
403146392Smarius	error = espattach(esc, &esp_sbus_glue);
404146392Smarius	if (error != 0) {
405146392Smarius		device_printf(dev, "espattach failed\n");
406146392Smarius		goto fail_dma_eres;
407146392Smarius	}
408130293Sscottl
409130293Sscottl	return (0);
410146392Smarius
411146392Smarius fail_dma_eres:
412182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(esc->sc_res),
413182876Smarius	    esc->sc_res);
414146392Smarius	return (error);
415130293Sscottl}
416130293Sscottl
417130293Sscottlstatic int
418146392Smariusesp_dma_detach(device_t dev)
419130293Sscottl{
420146392Smarius	struct esp_softc *esc;
421146392Smarius	int error;
422130293Sscottl
423130293Sscottl	esc = device_get_softc(dev);
424146392Smarius
425182876Smarius	error = espdetach(esc);
426146392Smarius	if (error != 0)
427146392Smarius		return (error);
428182876Smarius	bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(esc->sc_res),
429182876Smarius	    esc->sc_res);
430146392Smarius
431146392Smarius	return (0);
432130293Sscottl}
433130293Sscottl
434130293Sscottlstatic int
435146392Smariusesp_suspend(device_t dev)
436130293Sscottl{
437145201Smarius
438130293Sscottl	return (ENXIO);
439130293Sscottl}
440130293Sscottl
441130293Sscottlstatic int
442146392Smariusesp_resume(device_t dev)
443130293Sscottl{
444145201Smarius
445130293Sscottl	return (ENXIO);
446130293Sscottl}
447130293Sscottl
448146392Smariusstatic int
449182876Smariusespattach(struct esp_softc *esc, const struct ncr53c9x_glue *gluep)
450130293Sscottl{
451130293Sscottl	struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
452130293Sscottl	unsigned int uid = 0;
453182876Smarius	int error, i;
454130293Sscottl
455182876Smarius	NCR_LOCK_INIT(sc);
456182876Smarius
457207281Smarius	sc->sc_id = OF_getscsinitid(esc->sc_dev);
458182876Smarius
459182876Smarius#ifdef ESP_SBUS_DEBUG
460182876Smarius	device_printf(esc->sc_dev, "%s: sc_id %d, freq %d\n",
461182876Smarius	    __func__, sc->sc_id, sc->sc_freq);
462182876Smarius#endif
463182876Smarius
464130293Sscottl	/*
465146392Smarius	 * The `ESC' DMA chip must be reset before we can access
466146392Smarius	 * the ESP registers.
467146392Smarius	 */
468146392Smarius	if (esc->sc_dma->sc_rev == DMAREV_ESC)
469146392Smarius		DMA_RESET(esc->sc_dma);
470146392Smarius
471146392Smarius	/*
472130293Sscottl	 * Set up glue for MI code early; we use some of it here.
473130293Sscottl	 */
474130293Sscottl	sc->sc_glue = gluep;
475130293Sscottl
476130293Sscottl	/* gimme MHz */
477130293Sscottl	sc->sc_freq /= 1000000;
478130293Sscottl
479130293Sscottl	/*
480130293Sscottl	 * XXX More of this should be in ncr53c9x_attach(), but
481130293Sscottl	 * XXX should we really poke around the chip that much in
482130293Sscottl	 * XXX the MI code?  Think about this more...
483130293Sscottl	 */
484130293Sscottl
485130293Sscottl	/*
486180692Smarius	 * Read the part-unique ID code of the SCSI chip.  The contained
487146392Smarius	 * value is only valid if all of the following conditions are met:
488146392Smarius	 * - After power-up or chip reset.
489146392Smarius	 * - Before any value is written to this register.
490146392Smarius	 * - The NCRCFG2_FE bit is set.
491146392Smarius	 * - A (NCRCMD_NOP | NCRCMD_DMA) command has been issued.
492146392Smarius	 */
493146392Smarius	NCRCMD(sc, NCRCMD_RSTCHIP);
494146392Smarius	NCRCMD(sc, NCRCMD_NOP);
495146392Smarius	sc->sc_cfg2 = NCRCFG2_FE;
496146392Smarius	NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
497146392Smarius	NCRCMD(sc, NCRCMD_NOP | NCRCMD_DMA);
498146392Smarius	uid = NCR_READ_REG(sc, NCR_UID);
499146392Smarius
500146392Smarius	/*
501130293Sscottl	 * It is necessary to try to load the 2nd config register here,
502130293Sscottl	 * to find out what rev the esp chip is, else the ncr53c9x_reset
503130293Sscottl	 * will not set up the defaults correctly.
504130293Sscottl	 */
505130293Sscottl	sc->sc_cfg1 = sc->sc_id | NCRCFG1_PARENB;
506146392Smarius	NCR_WRITE_REG(sc, NCR_CFG1, sc->sc_cfg1);
507146392Smarius	sc->sc_cfg2 = 0;
508146392Smarius	NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
509130293Sscottl	sc->sc_cfg2 = NCRCFG2_SCSI2 | NCRCFG2_RPE;
510130293Sscottl	NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
511130293Sscottl
512130293Sscottl	if ((NCR_READ_REG(sc, NCR_CFG2) & ~NCRCFG2_RSVD) !=
513226947Smarius	    (NCRCFG2_SCSI2 | NCRCFG2_RPE))
514130293Sscottl		sc->sc_rev = NCR_VARIANT_ESP100;
515226947Smarius	else {
516130293Sscottl		sc->sc_cfg2 = NCRCFG2_SCSI2;
517130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG2, sc->sc_cfg2);
518130293Sscottl		sc->sc_cfg3 = 0;
519130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
520130293Sscottl		sc->sc_cfg3 = (NCRCFG3_CDB | NCRCFG3_FCLK);
521130293Sscottl		NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
522130293Sscottl		if (NCR_READ_REG(sc, NCR_CFG3) !=
523226947Smarius		    (NCRCFG3_CDB | NCRCFG3_FCLK))
524130293Sscottl			sc->sc_rev = NCR_VARIANT_ESP100A;
525226947Smarius		else {
526180692Smarius			/* NCRCFG2_FE enables > 64K transfers. */
527130293Sscottl			sc->sc_cfg2 |= NCRCFG2_FE;
528130293Sscottl			sc->sc_cfg3 = 0;
529130293Sscottl			NCR_WRITE_REG(sc, NCR_CFG3, sc->sc_cfg3);
530146392Smarius			if (sc->sc_freq <= 25)
531146392Smarius				sc->sc_rev = NCR_VARIANT_ESP200;
532146392Smarius			else {
533146392Smarius				switch ((uid & 0xf8) >> 3) {
534146392Smarius				case 0x00:
535146392Smarius					sc->sc_rev = NCR_VARIANT_FAS100A;
536146392Smarius					break;
537180692Smarius
538146392Smarius				case 0x02:
539146392Smarius					if ((uid & 0x07) == 0x02)
540226947Smarius						sc->sc_rev =
541226947Smarius						    NCR_VARIANT_FAS216;
542146392Smarius					else
543226947Smarius						sc->sc_rev =
544226947Smarius						    NCR_VARIANT_FAS236;
545146392Smarius					break;
546180692Smarius
547146392Smarius				case 0x0a:
548146392Smarius					sc->sc_rev = NCR_VARIANT_FAS366;
549146392Smarius					break;
550180692Smarius
551146392Smarius				default:
552146392Smarius					/*
553146392Smarius					 * We could just treat unknown chips
554146392Smarius					 * as ESP200 but then we would most
555146392Smarius					 * likely drive them out of specs.
556146392Smarius					 */
557146392Smarius					device_printf(esc->sc_dev,
558146392Smarius					    "Unknown chip\n");
559226947Smarius					error = ENXIO;
560226947Smarius					goto fail_lock;
561146392Smarius				}
562146392Smarius			}
563130293Sscottl		}
564130293Sscottl	}
565130293Sscottl
566130293Sscottl#ifdef ESP_SBUS_DEBUG
567145201Smarius	printf("%s: revision %d, uid 0x%x\n", __func__, sc->sc_rev, uid);
568130293Sscottl#endif
569130293Sscottl
570130293Sscottl	/*
571130293Sscottl	 * This is the value used to start sync negotiations
572130293Sscottl	 * Note that the NCR register "SYNCTP" is programmed
573130293Sscottl	 * in "clocks per byte", and has a minimum value of 4.
574130293Sscottl	 * The SCSI period used in negotiation is one-fourth
575130293Sscottl	 * of the time (in nanoseconds) needed to transfer one byte.
576130293Sscottl	 * Since the chip's clock is given in MHz, we have the following
577130293Sscottl	 * formula: 4 * period = (1000 / freq) * 4
578130293Sscottl	 */
579130293Sscottl	sc->sc_minsync = 1000 / sc->sc_freq;
580130293Sscottl
581226947Smarius	/*
582226947Smarius	 * Except for some variants the maximum transfer size is 64k.
583226947Smarius	 */
584226947Smarius	sc->sc_maxxfer = 64 * 1024;
585130293Sscottl	sc->sc_maxoffset = 15;
586130370Sscottl	sc->sc_extended_geom = 1;
587130349Sscottl
588130293Sscottl	/*
589130293Sscottl	 * Alas, we must now modify the value a bit, because it's
590226947Smarius	 * only valid when we can switch on FASTCLK and FASTSCSI bits
591226947Smarius	 * in the config register 3...
592130293Sscottl	 */
593130293Sscottl	switch (sc->sc_rev) {
594130293Sscottl	case NCR_VARIANT_ESP100:
595182876Smarius		sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT;
596130293Sscottl		sc->sc_minsync = 0;	/* No synch on old chip? */
597130293Sscottl		break;
598130293Sscottl
599130293Sscottl	case NCR_VARIANT_ESP100A:
600130293Sscottl	case NCR_VARIANT_ESP200:
601182876Smarius		sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT;
602146392Smarius		/* Min clocks/byte is 5 */
603146392Smarius		sc->sc_minsync = ncr53c9x_cpb2stp(sc, 5);
604146392Smarius		break;
605146392Smarius
606146392Smarius	case NCR_VARIANT_FAS100A:
607146392Smarius	case NCR_VARIANT_FAS216:
608146392Smarius	case NCR_VARIANT_FAS236:
609146392Smarius		/*
610146392Smarius		 * The onboard SCSI chips in Sun Ultra 1 are actually
611146392Smarius		 * documented to be NCR53C9X which use NCRCFG3_FCLK and
612180692Smarius		 * NCRCFG3_FSCSI.  BSD/OS however probes these chips as
613146392Smarius		 * FAS100A and uses NCRF9XCFG3_FCLK and NCRF9XCFG3_FSCSI
614146392Smarius		 * instead which seems to be correct as otherwise sync
615180692Smarius		 * negotiation just doesn't work.  Using NCRF9XCFG3_FCLK
616146392Smarius		 * and NCRF9XCFG3_FSCSI with these chips in fact also
617146392Smarius		 * yields Fast-SCSI speed.
618146392Smarius		 */
619146392Smarius		sc->sc_features = NCR_F_FASTSCSI;
620146392Smarius		sc->sc_cfg3 = NCRF9XCFG3_FCLK;
621146392Smarius		sc->sc_cfg3_fscsi = NCRF9XCFG3_FSCSI;
622182876Smarius		sc->sc_maxwidth = MSG_EXT_WDTR_BUS_8_BIT;
623146392Smarius		sc->sc_maxxfer = 16 * 1024 * 1024;
624146392Smarius		break;
625146392Smarius
626130293Sscottl	case NCR_VARIANT_FAS366:
627182876Smarius		sc->sc_maxwidth = MSG_EXT_WDTR_BUS_16_BIT;
628130293Sscottl		sc->sc_maxxfer = 16 * 1024 * 1024;
629130293Sscottl		break;
630130293Sscottl	}
631130293Sscottl
632226947Smarius	/*
633226947Smarius	 * Given that we allocate resources based on sc->sc_maxxfer it doesn't
634226947Smarius	 * make sense to supply a value higher than the maximum actually used.
635226947Smarius	 */
636226947Smarius	sc->sc_maxxfer = min(sc->sc_maxxfer, MAXPHYS);
637226947Smarius
638226947Smarius	/* Attach the DMA engine. */
639226947Smarius	error = lsi64854_attach(esc->sc_dma);
640226947Smarius	if (error != 0) {
641226947Smarius		device_printf(esc->sc_dev, "lsi64854_attach failed\n");
642226947Smarius		goto fail_lock;
643226947Smarius	}
644226947Smarius
645180692Smarius	/* Establish interrupt channel. */
646182876Smarius	i = 0;
647130293Sscottl	if ((esc->sc_irqres = bus_alloc_resource_any(esc->sc_dev, SYS_RES_IRQ,
648182876Smarius	    &i, RF_SHAREABLE|RF_ACTIVE)) == NULL) {
649146392Smarius		device_printf(esc->sc_dev, "cannot allocate interrupt\n");
650182876Smarius		goto fail_lsi;
651130293Sscottl	}
652130293Sscottl	if (bus_setup_intr(esc->sc_dev, esc->sc_irqres,
653182876Smarius	    INTR_MPSAFE | INTR_TYPE_CAM, NULL, ncr53c9x_intr, sc,
654182876Smarius	    &esc->sc_irq)) {
655146392Smarius		device_printf(esc->sc_dev, "cannot set up interrupt\n");
656146392Smarius		error = ENXIO;
657146392Smarius		goto fail_ires;
658130293Sscottl	}
659130293Sscottl
660180692Smarius	/* Turn on target selection using the `DMA' method. */
661130293Sscottl	if (sc->sc_rev != NCR_VARIANT_FAS366)
662130293Sscottl		sc->sc_features |= NCR_F_DMASELECT;
663130293Sscottl
664130293Sscottl	/* Do the common parts of attachment. */
665130293Sscottl	sc->sc_dev = esc->sc_dev;
666146392Smarius	error = ncr53c9x_attach(sc);
667146392Smarius	if (error != 0) {
668146392Smarius		device_printf(esc->sc_dev, "ncr53c9x_attach failed\n");
669146392Smarius		goto fail_intr;
670146392Smarius	}
671146392Smarius
672146392Smarius	return (0);
673146392Smarius
674146392Smarius fail_intr:
675146392Smarius	bus_teardown_intr(esc->sc_dev, esc->sc_irqres, esc->sc_irq);
676146392Smarius fail_ires:
677182876Smarius	bus_release_resource(esc->sc_dev, SYS_RES_IRQ,
678182876Smarius	    rman_get_rid(esc->sc_irqres), esc->sc_irqres);
679182876Smarius fail_lsi:
680182876Smarius	lsi64854_detach(esc->sc_dma);
681182876Smarius fail_lock:
682182876Smarius	NCR_LOCK_DESTROY(sc);
683146392Smarius	return (error);
684130293Sscottl}
685130293Sscottl
686182876Smariusstatic int
687182876Smariusespdetach(struct esp_softc *esc)
688182876Smarius{
689182876Smarius	struct ncr53c9x_softc *sc = &esc->sc_ncr53c9x;
690182876Smarius	int error;
691182876Smarius
692182876Smarius	bus_teardown_intr(esc->sc_dev, esc->sc_irqres, esc->sc_irq);
693182876Smarius	error = ncr53c9x_detach(sc);
694182876Smarius	if (error != 0)
695182876Smarius		return (error);
696182876Smarius	error = lsi64854_detach(esc->sc_dma);
697182876Smarius	if (error != 0)
698182876Smarius		return (error);
699182876Smarius	NCR_LOCK_DESTROY(sc);
700182876Smarius	bus_release_resource(esc->sc_dev, SYS_RES_IRQ,
701182876Smarius	    rman_get_rid(esc->sc_irqres), esc->sc_irqres);
702182876Smarius
703182876Smarius	return (0);
704182876Smarius}
705182876Smarius
706130293Sscottl/*
707180692Smarius * Glue functions
708130293Sscottl */
709130293Sscottl
710130293Sscottl#ifdef ESP_SBUS_DEBUG
711182876Smariusstatic int esp_sbus_debug = 0;
712130293Sscottl
713182876Smariusstatic const struct {
714226381Smarius	const char *r_name;
715226381Smarius	int r_flag;
716226381Smarius} const esp__read_regnames [] = {
717130293Sscottl	{ "TCL", 0},			/* 0/00 */
718130293Sscottl	{ "TCM", 0},			/* 1/04 */
719130293Sscottl	{ "FIFO", 0},			/* 2/08 */
720130293Sscottl	{ "CMD", 0},			/* 3/0c */
721130293Sscottl	{ "STAT", 0},			/* 4/10 */
722130293Sscottl	{ "INTR", 0},			/* 5/14 */
723130293Sscottl	{ "STEP", 0},			/* 6/18 */
724130293Sscottl	{ "FFLAGS", 1},			/* 7/1c */
725130293Sscottl	{ "CFG1", 1},			/* 8/20 */
726130293Sscottl	{ "STAT2", 0},			/* 9/24 */
727130293Sscottl	{ "CFG4", 1},			/* a/28 */
728130293Sscottl	{ "CFG2", 1},			/* b/2c */
729130293Sscottl	{ "CFG3", 1},			/* c/30 */
730130293Sscottl	{ "-none", 1},			/* d/34 */
731130293Sscottl	{ "TCH", 1},			/* e/38 */
732130293Sscottl	{ "TCX", 1},			/* f/3c */
733130293Sscottl};
734130293Sscottl
735226381Smariusstatic const const struct {
736226381Smarius	const char *r_name;
737226381Smarius	int r_flag;
738226381Smarius} const esp__write_regnames[] = {
739130293Sscottl	{ "TCL", 1},			/* 0/00 */
740130293Sscottl	{ "TCM", 1},			/* 1/04 */
741130293Sscottl	{ "FIFO", 0},			/* 2/08 */
742130293Sscottl	{ "CMD", 0},			/* 3/0c */
743130293Sscottl	{ "SELID", 1},			/* 4/10 */
744130293Sscottl	{ "TIMEOUT", 1},		/* 5/14 */
745130293Sscottl	{ "SYNCTP", 1},			/* 6/18 */
746130293Sscottl	{ "SYNCOFF", 1},		/* 7/1c */
747130293Sscottl	{ "CFG1", 1},			/* 8/20 */
748130293Sscottl	{ "CCF", 1},			/* 9/24 */
749130293Sscottl	{ "TEST", 1},			/* a/28 */
750130293Sscottl	{ "CFG2", 1},			/* b/2c */
751130293Sscottl	{ "CFG3", 1},			/* c/30 */
752130293Sscottl	{ "-none", 1},			/* d/34 */
753130293Sscottl	{ "TCH", 1},			/* e/38 */
754130293Sscottl	{ "TCX", 1},			/* f/3c */
755130293Sscottl};
756130293Sscottl#endif
757130293Sscottl
758226381Smariusstatic uint8_t
759130293Sscottlesp_read_reg(struct ncr53c9x_softc *sc, int reg)
760130293Sscottl{
761130293Sscottl	struct esp_softc *esc = (struct esp_softc *)sc;
762226381Smarius	uint8_t v;
763130293Sscottl
764182876Smarius	v = bus_read_1(esc->sc_res, reg * 4);
765182876Smarius
766130293Sscottl#ifdef ESP_SBUS_DEBUG
767130293Sscottl	if (esp_sbus_debug && (reg < 0x10) && esp__read_regnames[reg].r_flag)
768182876Smarius		printf("RD:%x <%s> %x\n", reg * 4, ((unsigned)reg < 0x10) ?
769182876Smarius		    esp__read_regnames[reg].r_name : "<***>", v);
770130293Sscottl#endif
771182876Smarius
772182876Smarius	return (v);
773130293Sscottl}
774130293Sscottl
775145201Smariusstatic void
776226381Smariusesp_write_reg(struct ncr53c9x_softc *sc, int reg, uint8_t v)
777130293Sscottl{
778130293Sscottl	struct esp_softc *esc = (struct esp_softc *)sc;
779130293Sscottl
780130293Sscottl#ifdef ESP_SBUS_DEBUG
781130293Sscottl	if (esp_sbus_debug && (reg < 0x10) && esp__write_regnames[reg].r_flag)
782182876Smarius		printf("WR:%x <%s> %x\n", reg * 4, ((unsigned)reg < 0x10) ?
783182876Smarius		    esp__write_regnames[reg].r_name : "<***>", v);
784130293Sscottl#endif
785182876Smarius
786182876Smarius	bus_write_1(esc->sc_res, reg * 4, v);
787130293Sscottl}
788130293Sscottl
789145201Smariusstatic int
790130293Sscottlesp_dma_isintr(struct ncr53c9x_softc *sc)
791130293Sscottl{
792130293Sscottl	struct esp_softc *esc = (struct esp_softc *)sc;
793130293Sscottl
794130293Sscottl	return (DMA_ISINTR(esc->sc_dma));
795130293Sscottl}
796130293Sscottl
797145201Smariusstatic void
798130293Sscottlesp_dma_reset(struct ncr53c9x_softc *sc)
799130293Sscottl{
800130293Sscottl	struct esp_softc *esc = (struct esp_softc *)sc;
801130293Sscottl
802130293Sscottl	DMA_RESET(esc->sc_dma);
803130293Sscottl}
804130293Sscottl
805145201Smariusstatic int
806130293Sscottlesp_dma_intr(struct ncr53c9x_softc *sc)
807130293Sscottl{
808130293Sscottl	struct esp_softc *esc = (struct esp_softc *)sc;
809130293Sscottl
810130293Sscottl	return (DMA_INTR(esc->sc_dma));
811130293Sscottl}
812130293Sscottl
813145201Smariusstatic int
814226381Smariusesp_dma_setup(struct ncr53c9x_softc *sc, void **addr, size_t *len,
815226381Smarius    int datain, size_t *dmasize)
816130293Sscottl{
817130293Sscottl	struct esp_softc *esc = (struct esp_softc *)sc;
818130293Sscottl
819130293Sscottl	return (DMA_SETUP(esc->sc_dma, addr, len, datain, dmasize));
820130293Sscottl}
821130293Sscottl
822145201Smariusstatic void
823130293Sscottlesp_dma_go(struct ncr53c9x_softc *sc)
824130293Sscottl{
825130293Sscottl	struct esp_softc *esc = (struct esp_softc *)sc;
826130293Sscottl
827130293Sscottl	DMA_GO(esc->sc_dma);
828130293Sscottl}
829130293Sscottl
830145201Smariusstatic void
831130293Sscottlesp_dma_stop(struct ncr53c9x_softc *sc)
832130293Sscottl{
833130293Sscottl	struct esp_softc *esc = (struct esp_softc *)sc;
834130293Sscottl
835180692Smarius	L64854_SCSR(esc->sc_dma, L64854_GCSR(esc->sc_dma) & ~D_EN_DMA);
836130293Sscottl}
837130293Sscottl
838145201Smariusstatic int
839130293Sscottlesp_dma_isactive(struct ncr53c9x_softc *sc)
840130293Sscottl{
841130293Sscottl	struct esp_softc *esc = (struct esp_softc *)sc;
842130293Sscottl
843130293Sscottl	return (DMA_ISACTIVE(esc->sc_dma));
844130293Sscottl}
845