sym_hipd.c revision 55628
153790Sobrien/*
253790Sobrien *  Device driver optimized for the Symbios/LSI 53C896/53C895A/53C1010
353790Sobrien *  PCI-SCSI controllers.
453790Sobrien *
555628Sgroudier *  Copyright (C) 1999-2000  Gerard Roudier <groudier@club-internet.fr>
653790Sobrien *
753790Sobrien *  This driver also supports the following Symbios/LSI PCI-SCSI chips:
853790Sobrien *	53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895.
953790Sobrien *
1053790Sobrien *  but does not support earlier chips as the following ones:
1153790Sobrien *	53C810, 53C815, 53C825.
1253790Sobrien *
1353790Sobrien *  This driver for FreeBSD-CAM is derived from the Linux sym53c8xx driver.
1453790Sobrien *  Copyright (C) 1998-1999  Gerard Roudier
1553790Sobrien *
1653790Sobrien *  The sym53c8xx driver is derived from the ncr53c8xx driver that had been
1753790Sobrien *  a port of the FreeBSD ncr driver to Linux-1.2.13.
1853790Sobrien *
1953790Sobrien *  The original ncr driver has been written for 386bsd and FreeBSD by
2053790Sobrien *          Wolfgang Stanglmeier        <wolf@cologne.de>
2153790Sobrien *          Stefan Esser                <se@mi.Uni-Koeln.de>
2253790Sobrien *  Copyright (C) 1994  Wolfgang Stanglmeier
2353790Sobrien *
2453790Sobrien *  The initialisation code, and part of the code that addresses
2553790Sobrien *  FreeBSD-CAM services is based on the aic7xxx driver for FreeBSD-CAM
2653790Sobrien *  written by Justin T. Gibbs.
2753790Sobrien *
2853790Sobrien *  Other major contributions:
2953790Sobrien *
3053790Sobrien *  NVRAM detection and reading.
3153790Sobrien *  Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
3253790Sobrien *
3353790Sobrien *-----------------------------------------------------------------------------
3453790Sobrien *
3553790Sobrien * Redistribution and use in source and binary forms, with or without
3653790Sobrien * modification, are permitted provided that the following conditions
3753790Sobrien * are met:
3853790Sobrien * 1. Redistributions of source code must retain the above copyright
3953790Sobrien *    notice, this list of conditions and the following disclaimer.
4053790Sobrien * 2. Redistributions in binary form must reproduce the above copyright
4153790Sobrien *    notice, this list of conditions and the following disclaimer in the
4253790Sobrien *    documentation and/or other materials provided with the distribution.
4353790Sobrien * 3. The name of the author may not be used to endorse or promote products
4453790Sobrien *    derived from this software without specific prior written permission.
4553790Sobrien *
4653790Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
4753790Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4853790Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4953790Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
5053790Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5153790Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5253790Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5353790Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5453790Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5553790Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5653790Sobrien * SUCH DAMAGE.
5753790Sobrien */
5853790Sobrien
5955258Sobrien/* $FreeBSD: head/sys/dev/sym/sym_hipd.c 55628 2000-01-08 19:58:17Z groudier $ */
6055258Sobrien
6155628Sgroudier#define SYM_DRIVER_NAME	"sym-1.2.0-20000108"
6253790Sobrien
6353790Sobrien#include <pci.h>
6453790Sobrien#include <stddef.h>	/* For offsetof */
6553790Sobrien
6653790Sobrien#include <sys/param.h>
6753790Sobrien/*
6853790Sobrien *  Only use the BUS stuff for PCI under FreeBSD 4 and later versions.
6953790Sobrien *  Note that the old BUS stuff also works for FreeBSD 4 and spares
7053790Sobrien *  about 1.5KB for the driver objet file.
7153790Sobrien */
7253790Sobrien#if 	__FreeBSD_version >= 400000
7353790Sobrien#define	FreeBSD_4_Bus
7453790Sobrien#endif
7553790Sobrien
7653790Sobrien#include <sys/systm.h>
7753790Sobrien#include <sys/malloc.h>
7853790Sobrien#include <sys/kernel.h>
7953790Sobrien#ifdef FreeBSD_4_Bus
8053790Sobrien#include <sys/module.h>
8153790Sobrien#include <sys/bus.h>
8253790Sobrien#endif
8353790Sobrien
8453790Sobrien#include <sys/buf.h>
8553790Sobrien#include <sys/proc.h>
8653790Sobrien
8753790Sobrien#include <pci/pcireg.h>
8853790Sobrien#include <pci/pcivar.h>
8953790Sobrien
9053790Sobrien#include <machine/bus_memio.h>
9153790Sobrien#include <machine/bus_pio.h>
9253790Sobrien#include <machine/bus.h>
9353790Sobrien#ifdef FreeBSD_4_Bus
9453790Sobrien#include <machine/resource.h>
9553790Sobrien#include <sys/rman.h>
9653790Sobrien#endif
9753790Sobrien#include <machine/clock.h>
9853790Sobrien
9953790Sobrien#include <cam/cam.h>
10053790Sobrien#include <cam/cam_ccb.h>
10153790Sobrien#include <cam/cam_sim.h>
10253790Sobrien#include <cam/cam_xpt_sim.h>
10353790Sobrien#include <cam/cam_debug.h>
10453790Sobrien
10553790Sobrien#include <cam/scsi/scsi_all.h>
10653790Sobrien#include <cam/scsi/scsi_message.h>
10753790Sobrien
10853790Sobrien#include <vm/vm.h>
10953790Sobrien#include <vm/vm_param.h>
11053790Sobrien#include <vm/pmap.h>
11153790Sobrien
11253790Sobrien#if 0
11353790Sobrien#include <sys/kernel.h>
11453790Sobrien#include <sys/sysctl.h>
11553790Sobrien#include <vm/vm_extern.h>
11653790Sobrien#endif
11753790Sobrien
11853790Sobrien/* Short and quite clear integer types */
11953790Sobrientypedef int8_t    s8;
12053790Sobrientypedef int16_t   s16;
12153790Sobrientypedef	int32_t   s32;
12253790Sobrientypedef u_int8_t  u8;
12353790Sobrientypedef u_int16_t u16;
12453790Sobrientypedef	u_int32_t u32;
12553790Sobrien
12653790Sobrien/* Driver configuration and definitions */
12754690Sobrien#include "opt_sym.h"
12853799Sobrien#include <dev/sym/sym_conf.h>
12953799Sobrien#include <dev/sym/sym_defs.h>
13053790Sobrien
13153790Sobrien/*
13253790Sobrien *  On x86 architecture, write buffers management does not
13353790Sobrien *  reorder writes to memory. So, preventing compiler from
13453790Sobrien *  optimizing the code is enough to guarantee some ordering
13553790Sobrien *  when the CPU is writing data accessed by the PCI chip.
13653790Sobrien *  On Alpha architecture, explicit barriers are to be used.
13753790Sobrien *  By the way, the *BSD semantic associates the barrier
13853790Sobrien *  with some window on the BUS and the corresponding verbs
13953790Sobrien *  are for now unused. What a strangeness. The driver must
14053790Sobrien *  ensure that accesses from the CPU to the start and done
14153790Sobrien *  queues are not reordered by either the compiler or the
14253790Sobrien *  CPU and uses 'volatile' for this purpose.
14353790Sobrien */
14453790Sobrien
14553793Sobrien#ifdef	__alpha__
14653793Sobrien#define MEMORY_BARRIER()	alpha_mb()
14753793Sobrien#else /*__i386__*/
14853790Sobrien#define MEMORY_BARRIER()	do { ; } while(0)
14953793Sobrien#endif
15053790Sobrien
15153790Sobrien/*
15253790Sobrien *  A la VMS/CAM-3 queue management.
15353790Sobrien */
15453790Sobrien
15553790Sobrientypedef struct sym_quehead {
15653790Sobrien	struct sym_quehead *flink;	/* Forward  pointer */
15753790Sobrien	struct sym_quehead *blink;	/* Backward pointer */
15853790Sobrien} SYM_QUEHEAD;
15953790Sobrien
16053790Sobrien#define sym_que_init(ptr) do { \
16153790Sobrien	(ptr)->flink = (ptr); (ptr)->blink = (ptr); \
16253790Sobrien} while (0)
16353790Sobrien
16453790Sobrienstatic __inline struct sym_quehead *sym_que_first(struct sym_quehead *head)
16553790Sobrien{
16653790Sobrien	return (head->flink == head) ? 0 : head->flink;
16753790Sobrien}
16853790Sobrien
16953790Sobrienstatic __inline struct sym_quehead *sym_que_last(struct sym_quehead *head)
17053790Sobrien{
17153790Sobrien	return (head->blink == head) ? 0 : head->blink;
17253790Sobrien}
17353790Sobrien
17453790Sobrienstatic __inline void __sym_que_add(struct sym_quehead * new,
17553790Sobrien	struct sym_quehead * blink,
17653790Sobrien	struct sym_quehead * flink)
17753790Sobrien{
17853790Sobrien	flink->blink	= new;
17953790Sobrien	new->flink	= flink;
18053790Sobrien	new->blink	= blink;
18153790Sobrien	blink->flink	= new;
18253790Sobrien}
18353790Sobrien
18453790Sobrienstatic __inline void __sym_que_del(struct sym_quehead * blink,
18553790Sobrien	struct sym_quehead * flink)
18653790Sobrien{
18753790Sobrien	flink->blink = blink;
18853790Sobrien	blink->flink = flink;
18953790Sobrien}
19053790Sobrien
19153790Sobrienstatic __inline int sym_que_empty(struct sym_quehead *head)
19253790Sobrien{
19353790Sobrien	return head->flink == head;
19453790Sobrien}
19553790Sobrien
19653790Sobrienstatic __inline void sym_que_splice(struct sym_quehead *list,
19753790Sobrien	struct sym_quehead *head)
19853790Sobrien{
19953790Sobrien	struct sym_quehead *first = list->flink;
20053790Sobrien
20153790Sobrien	if (first != list) {
20253790Sobrien		struct sym_quehead *last = list->blink;
20353790Sobrien		struct sym_quehead *at   = head->flink;
20453790Sobrien
20553790Sobrien		first->blink = head;
20653790Sobrien		head->flink  = first;
20753790Sobrien
20853790Sobrien		last->flink = at;
20953790Sobrien		at->blink   = last;
21053790Sobrien	}
21153790Sobrien}
21253790Sobrien
21353790Sobrien#define sym_que_entry(ptr, type, member) \
21453790Sobrien	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
21553790Sobrien
21653790Sobrien
21753790Sobrien#define sym_insque(new, pos)		__sym_que_add(new, pos, (pos)->flink)
21853790Sobrien
21953790Sobrien#define sym_remque(el)			__sym_que_del((el)->blink, (el)->flink)
22053790Sobrien
22153790Sobrien#define sym_insque_head(new, head)	__sym_que_add(new, head, (head)->flink)
22253790Sobrien
22353790Sobrienstatic __inline struct sym_quehead *sym_remque_head(struct sym_quehead *head)
22453790Sobrien{
22553790Sobrien	struct sym_quehead *elem = head->flink;
22653790Sobrien
22753790Sobrien	if (elem != head)
22853790Sobrien		__sym_que_del(head, elem->flink);
22953790Sobrien	else
23053790Sobrien		elem = 0;
23153790Sobrien	return elem;
23253790Sobrien}
23353790Sobrien
23453790Sobrien#define sym_insque_tail(new, head)	__sym_que_add(new, (head)->blink, head)
23553790Sobrien
23653790Sobrienstatic __inline struct sym_quehead *sym_remque_tail(struct sym_quehead *head)
23753790Sobrien{
23853790Sobrien	struct sym_quehead *elem = head->blink;
23953790Sobrien
24053790Sobrien	if (elem != head)
24153790Sobrien		__sym_que_del(elem->blink, head);
24253790Sobrien	else
24353790Sobrien		elem = 0;
24453790Sobrien	return elem;
24553790Sobrien}
24653790Sobrien
24753790Sobrien/*
24853790Sobrien *  This one may be usefull.
24953790Sobrien */
25053790Sobrien#define FOR_EACH_QUEUED_ELEMENT(head, qp) \
25153790Sobrien	for (qp = (head)->flink; qp != (head); qp = qp->flink)
25253790Sobrien/*
25353790Sobrien *  FreeBSD does not offer our kind of queue in the CAM CCB.
25453790Sobrien *  So, we have to cast.
25553790Sobrien */
25653790Sobrien#define sym_qptr(p)	((struct sym_quehead *) (p))
25753790Sobrien
25853790Sobrien/*
25953790Sobrien *  Simple bitmap operations.
26053790Sobrien */
26153790Sobrien#define sym_set_bit(p, n)	(((u32 *)(p))[(n)>>5] |=  (1<<((n)&0x1f)))
26253790Sobrien#define sym_clr_bit(p, n)	(((u32 *)(p))[(n)>>5] &= ~(1<<((n)&0x1f)))
26353790Sobrien#define sym_is_bit(p, n)	(((u32 *)(p))[(n)>>5] &   (1<<((n)&0x1f)))
26453790Sobrien
26553790Sobrien/*
26653790Sobrien *  Number of tasks per device we want to handle.
26753790Sobrien */
26854690Sobrien#if	SYM_CONF_MAX_TAG_ORDER > 8
26953790Sobrien#error	"more than 256 tags per logical unit not allowed."
27053790Sobrien#endif
27154690Sobrien#define	SYM_CONF_MAX_TASK	(1<<SYM_CONF_MAX_TAG_ORDER)
27253790Sobrien
27353790Sobrien/*
27453790Sobrien *  Donnot use more tasks that we can handle.
27553790Sobrien */
27654690Sobrien#ifndef	SYM_CONF_MAX_TAG
27754690Sobrien#define	SYM_CONF_MAX_TAG	SYM_CONF_MAX_TASK
27853790Sobrien#endif
27954690Sobrien#if	SYM_CONF_MAX_TAG > SYM_CONF_MAX_TASK
28054690Sobrien#undef	SYM_CONF_MAX_TAG
28154690Sobrien#define	SYM_CONF_MAX_TAG	SYM_CONF_MAX_TASK
28253790Sobrien#endif
28353790Sobrien
28453790Sobrien/*
28553790Sobrien *    This one means 'NO TAG for this job'
28653790Sobrien */
28753790Sobrien#define NO_TAG	(256)
28853790Sobrien
28953790Sobrien/*
29053790Sobrien *  Number of SCSI targets.
29153790Sobrien */
29254690Sobrien#if	SYM_CONF_MAX_TARGET > 16
29353790Sobrien#error	"more than 16 targets not allowed."
29453790Sobrien#endif
29553790Sobrien
29653790Sobrien/*
29753790Sobrien *  Number of logical units per target.
29853790Sobrien */
29954690Sobrien#if	SYM_CONF_MAX_LUN > 64
30053790Sobrien#error	"more than 64 logical units per target not allowed."
30153790Sobrien#endif
30253790Sobrien
30353790Sobrien/*
30453790Sobrien *    Asynchronous pre-scaler (ns). Shall be 40 for
30553790Sobrien *    the SCSI timings to be compliant.
30653790Sobrien */
30754690Sobrien#define	SYM_CONF_MIN_ASYNC (40)
30853790Sobrien
30953790Sobrien/*
31053790Sobrien *  Number of entries in the START and DONE queues.
31153790Sobrien *
31253790Sobrien *  We limit to 1 PAGE in order to succeed allocation of
31353790Sobrien *  these queues. Each entry is 8 bytes long (2 DWORDS).
31453790Sobrien */
31554690Sobrien#ifdef	SYM_CONF_MAX_START
31654690Sobrien#define	SYM_CONF_MAX_QUEUE (SYM_CONF_MAX_START+2)
31753790Sobrien#else
31854690Sobrien#define	SYM_CONF_MAX_QUEUE (7*SYM_CONF_MAX_TASK+2)
31954690Sobrien#define	SYM_CONF_MAX_START (SYM_CONF_MAX_QUEUE-2)
32053790Sobrien#endif
32153790Sobrien
32254690Sobrien#if	SYM_CONF_MAX_QUEUE > PAGE_SIZE/8
32354690Sobrien#undef	SYM_CONF_MAX_QUEUE
32454690Sobrien#define	SYM_CONF_MAX_QUEUE   PAGE_SIZE/8
32554690Sobrien#undef	SYM_CONF_MAX_START
32654690Sobrien#define	SYM_CONF_MAX_START (SYM_CONF_MAX_QUEUE-2)
32753790Sobrien#endif
32853790Sobrien
32953790Sobrien/*
33053790Sobrien *  For this one, we want a short name :-)
33153790Sobrien */
33254690Sobrien#define MAX_QUEUE	SYM_CONF_MAX_QUEUE
33353790Sobrien
33453790Sobrien/*
33553790Sobrien *  This one should have been already defined.
33653790Sobrien */
33753790Sobrien#ifndef offsetof
33853790Sobrien#define offsetof(t, m)	((size_t) (&((t *)0)->m))
33953790Sobrien#endif
34053790Sobrien
34153790Sobrien/*
34253790Sobrien *  Active debugging tags and verbosity.
34353790Sobrien */
34453790Sobrien#define DEBUG_ALLOC	(0x0001)
34553790Sobrien#define DEBUG_PHASE	(0x0002)
34653790Sobrien#define DEBUG_POLL	(0x0004)
34753790Sobrien#define DEBUG_QUEUE	(0x0008)
34853790Sobrien#define DEBUG_RESULT	(0x0010)
34953790Sobrien#define DEBUG_SCATTER	(0x0020)
35053790Sobrien#define DEBUG_SCRIPT	(0x0040)
35153790Sobrien#define DEBUG_TINY	(0x0080)
35253790Sobrien#define DEBUG_TIMING	(0x0100)
35353790Sobrien#define DEBUG_NEGO	(0x0200)
35453790Sobrien#define DEBUG_TAGS	(0x0400)
35553790Sobrien#define DEBUG_POINTER	(0x0800)
35653790Sobrien
35753790Sobrien#if 0
35853790Sobrienstatic int sym_debug = 0;
35953790Sobrien	#define DEBUG_FLAGS sym_debug
36053790Sobrien#else
36153790Sobrien/*	#define DEBUG_FLAGS (0x0631) */
36254690Sobrien	#define DEBUG_FLAGS (0x0000)
36353790Sobrien#endif
36453790Sobrien#define sym_verbose	(np->verbose)
36553790Sobrien
36653790Sobrien/*
36753790Sobrien *  Virtual to bus address translation.
36853790Sobrien */
36953793Sobrien#ifdef	__alpha__
37053793Sobrien#define	vtobus(p)	alpha_XXX_dmamap((vm_offset_t)(p))
37153793Sobrien#else /*__i386__*/
37253790Sobrien#define vtobus(p)	vtophys(p)
37353793Sobrien#endif
37453790Sobrien
37553790Sobrien/*
37653790Sobrien *  Copy from main memory to PCI memory space.
37753790Sobrien */
37853793Sobrien#ifdef	__alpha__
37953793Sobrien#define memcpy_to_pci(d, s, n)	memcpy_toio((u32)(d), (void *)(s), (n))
38053793Sobrien#else /*__i386__*/
38153790Sobrien#define memcpy_to_pci(d, s, n)	bcopy((s), (void *)(d), (n))
38253793Sobrien#endif
38353790Sobrien
38453790Sobrien/*
38553790Sobrien *  Insert a delay in micro-seconds and milli-seconds.
38653790Sobrien */
38753790Sobrienstatic void UDELAY(long us) { DELAY(us); }
38853790Sobrienstatic void MDELAY(long ms) { while (ms--) UDELAY(1000); }
38953790Sobrien
39053790Sobrien/*
39153790Sobrien *  Memory allocation/allocator.
39253790Sobrien *  We assume allocations are naturally aligned and if it is
39353790Sobrien *  not guaranteed, we may use our internal allocator.
39453790Sobrien */
39554690Sobrien#ifdef	SYM_CONF_USE_INTERNAL_ALLOCATOR
39653790Sobrien/*
39753790Sobrien *  Simple power of two buddy-like allocator.
39853790Sobrien *
39953790Sobrien *  This simple code is not intended to be fast, but to
40053790Sobrien *  provide power of 2 aligned memory allocations.
40153790Sobrien *  Since the SCRIPTS processor only supplies 8 bit arithmetic,
40253790Sobrien *  this allocator allows simple and fast address calculations
40353790Sobrien *  from the SCRIPTS code. In addition, cache line alignment
40453790Sobrien *  is guaranteed for power of 2 cache line size.
40553790Sobrien *
40653790Sobrien *  This allocator has been developped for the Linux sym53c8xx
40753790Sobrien *  driver, since this O/S does not provide naturally aligned
40853790Sobrien *  allocations.
40953790Sobrien *  It has the vertue to allow the driver to use private pages
41053790Sobrien *  of memory that will be useful if we ever need to deal with
41153790Sobrien *  IO MMU for PCI.
41253790Sobrien */
41353790Sobrien
41453790Sobrien#define MEMO_SHIFT	4	/* 16 bytes minimum memory chunk */
41553790Sobrien#define MEMO_PAGE_ORDER	0	/* 1 PAGE maximum (for now (ever?) */
41653790Sobrientypedef unsigned long addr;	/* Enough bits to bit-hack addresses */
41753790Sobrien
41853790Sobrien#if 0
41953790Sobrien#define MEMO_FREE_UNUSED	/* Free unused pages immediately */
42053790Sobrien#endif
42153790Sobrien
42253790Sobrienstruct m_link {
42353790Sobrien	struct m_link *next;	/* Simple links are enough */
42453790Sobrien};
42553790Sobrien
42653790Sobrien#ifndef M_DMA_32BIT
42753790Sobrien#define M_DMA_32BIT	0	/* Will this flag ever exist */
42853790Sobrien#endif
42953790Sobrien
43053790Sobrien#define get_pages() \
43153790Sobrien	malloc(PAGE_SIZE<<MEMO_PAGE_ORDER, M_DEVBUF, M_NOWAIT)
43253790Sobrien#define free_pages(p) \
43353790Sobrien	free((p), M_DEVBUF)
43453790Sobrien
43553790Sobrien/*
43653790Sobrien *  Lists of available memory chunks.
43753790Sobrien *  Starts with 16 bytes chunks until 1 PAGE chunks.
43853790Sobrien */
43953790Sobrienstatic struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
44053790Sobrien
44153790Sobrien/*
44253790Sobrien *  Allocate a memory area aligned on the lowest power of 2
44353790Sobrien *  greater than the requested size.
44453790Sobrien */
44553790Sobrienstatic void *__sym_malloc(int size)
44653790Sobrien{
44753790Sobrien	int i = 0;
44853790Sobrien	int s = (1 << MEMO_SHIFT);
44953790Sobrien	int j;
45053790Sobrien	addr a ;
45153790Sobrien
45253790Sobrien	if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
45353790Sobrien		return 0;
45453790Sobrien
45553790Sobrien	while (size > s) {
45653790Sobrien		s <<= 1;
45753790Sobrien		++i;
45853790Sobrien	}
45953790Sobrien
46053790Sobrien	j = i;
46153790Sobrien	while (!h[j].next) {
46253790Sobrien		if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
46353790Sobrien			h[j].next = (struct m_link *)get_pages();
46453790Sobrien			if (h[j].next)
46553790Sobrien				h[j].next->next = 0;
46653790Sobrien			break;
46753790Sobrien		}
46853790Sobrien		++j;
46953790Sobrien		s <<= 1;
47053790Sobrien	}
47153790Sobrien	a = (addr) h[j].next;
47253790Sobrien	if (a) {
47353790Sobrien		h[j].next = h[j].next->next;
47453790Sobrien		while (j > i) {
47553790Sobrien			j -= 1;
47653790Sobrien			s >>= 1;
47753790Sobrien			h[j].next = (struct m_link *) (a+s);
47853790Sobrien			h[j].next->next = 0;
47953790Sobrien		}
48053790Sobrien	}
48153790Sobrien#ifdef DEBUG
48253790Sobrien	printf("__sym_malloc(%d) = %p\n", size, (void *) a);
48353790Sobrien#endif
48453790Sobrien	return (void *) a;
48553790Sobrien}
48653790Sobrien
48753790Sobrien/*
48853790Sobrien *  Free a memory area allocated using sym_malloc().
48953790Sobrien *  Coalesce buddies.
49053790Sobrien *  Free pages that become unused if MEMO_FREE_UNUSED is
49153790Sobrien *  defined.
49253790Sobrien */
49353790Sobrienstatic void __sym_mfree(void *ptr, int size)
49453790Sobrien{
49553790Sobrien	int i = 0;
49653790Sobrien	int s = (1 << MEMO_SHIFT);
49753790Sobrien	struct m_link *q;
49853790Sobrien	addr a, b;
49953790Sobrien
50053790Sobrien#ifdef DEBUG
50153790Sobrien	printf("sym_mfree(%p, %d)\n", ptr, size);
50253790Sobrien#endif
50353790Sobrien
50453790Sobrien	if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
50553790Sobrien		return;
50653790Sobrien
50753790Sobrien	while (size > s) {
50853790Sobrien		s <<= 1;
50953790Sobrien		++i;
51053790Sobrien	}
51153790Sobrien
51253790Sobrien	a = (addr) ptr;
51353790Sobrien
51453790Sobrien	while (1) {
51553790Sobrien#ifdef MEMO_FREE_UNUSED
51653790Sobrien		if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
51753790Sobrien			free_pages(a);
51853790Sobrien			break;
51953790Sobrien		}
52053790Sobrien#endif
52153790Sobrien		b = a ^ s;
52253790Sobrien		q = &h[i];
52353790Sobrien		while (q->next && q->next != (struct m_link *) b) {
52453790Sobrien			q = q->next;
52553790Sobrien		}
52653790Sobrien		if (!q->next) {
52753790Sobrien			((struct m_link *) a)->next = h[i].next;
52853790Sobrien			h[i].next = (struct m_link *) a;
52953790Sobrien			break;
53053790Sobrien		}
53153790Sobrien		q->next = q->next->next;
53253790Sobrien		a = a & b;
53353790Sobrien		s <<= 1;
53453790Sobrien		++i;
53553790Sobrien	}
53653790Sobrien}
53753790Sobrien
53853790Sobrien#else	/* !defined SYSCONF_USE_INTERNAL_ALLOCATOR */
53953790Sobrien
54053790Sobrien/*
54153790Sobrien *  Using directly the system memory allocator.
54253790Sobrien */
54353790Sobrien
54453790Sobrien#define	__sym_mfree(ptr, size)		free((ptr), M_DEVBUF)
54553790Sobrien#define	__sym_malloc(size)		malloc((size), M_DEVBUF, M_NOWAIT)
54653790Sobrien
54754690Sobrien#endif	/* SYM_CONF_USE_INTERNAL_ALLOCATOR */
54853790Sobrien
54953790Sobrien#define MEMO_WARN	1
55053790Sobrien
55153790Sobrienstatic void *sym_calloc2(int size, char *name, int uflags)
55253790Sobrien{
55353790Sobrien	void *p;
55453790Sobrien
55553790Sobrien	p = __sym_malloc(size);
55653790Sobrien
55753790Sobrien	if (DEBUG_FLAGS & DEBUG_ALLOC)
55853790Sobrien		printf ("new %-10s[%4d] @%p.\n", name, size, p);
55953790Sobrien
56053790Sobrien	if (p)
56153790Sobrien		bzero(p, size);
56253790Sobrien	else if (uflags & MEMO_WARN)
56353790Sobrien		printf ("sym_calloc: failed to allocate %s[%d]\n", name, size);
56453790Sobrien
56553790Sobrien	return p;
56653790Sobrien}
56753790Sobrien
56853790Sobrien#define sym_calloc(s, n)	sym_calloc2(s, n, MEMO_WARN)
56953790Sobrien
57053790Sobrienstatic void sym_mfree(void *ptr, int size, char *name)
57153790Sobrien{
57253790Sobrien	if (DEBUG_FLAGS & DEBUG_ALLOC)
57353790Sobrien		printf ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
57453790Sobrien
57553790Sobrien	__sym_mfree(ptr, size);
57653790Sobrien}
57753790Sobrien
57853790Sobrien/*
57953790Sobrien *  Print a buffer in hexadecimal format.
58053790Sobrien */
58153790Sobrienstatic void sym_printb_hex (u_char *p, int n)
58253790Sobrien{
58353790Sobrien	while (n-- > 0)
58453790Sobrien		printf (" %x", *p++);
58553790Sobrien}
58653790Sobrien
58753790Sobrien/*
58853790Sobrien *  Same with a label at beginning and .\n at end.
58953790Sobrien */
59053790Sobrienstatic void sym_printl_hex (char *label, u_char *p, int n)
59153790Sobrien{
59253790Sobrien	printf ("%s", label);
59353790Sobrien	sym_printb_hex (p, n);
59453790Sobrien	printf (".\n");
59553790Sobrien}
59653790Sobrien
59753790Sobrien/*
59855300Sgroudier *  Return a string for SCSI BUS mode.
59955300Sgroudier */
60055300Sgroudierstatic char *sym_scsi_bus_mode(int mode)
60155300Sgroudier{
60255300Sgroudier	switch(mode) {
60355300Sgroudier	case SMODE_HVD:	return "HVD";
60455300Sgroudier	case SMODE_SE:	return "SE";
60555300Sgroudier	case SMODE_LVD: return "LVD";
60655300Sgroudier	}
60755300Sgroudier	return "??";
60855300Sgroudier}
60955300Sgroudier
61055300Sgroudier/*
61153790Sobrien *  Some poor sync table that refers to Tekram NVRAM layout.
61253790Sobrien */
61354690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT
61453790Sobrienstatic u_char Tekram_sync[16] =
61553790Sobrien	{25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10};
61653790Sobrien#endif
61753790Sobrien
61853790Sobrien/*
61953790Sobrien *  Union of supported NVRAM formats.
62053790Sobrien */
62153790Sobrienstruct sym_nvram {
62253790Sobrien	int type;
62353790Sobrien#define	SYM_SYMBIOS_NVRAM	(1)
62453790Sobrien#define	SYM_TEKRAM_NVRAM	(2)
62554690Sobrien#ifdef	SYM_CONF_NVRAM_SUPPORT
62653790Sobrien	union {
62753790Sobrien		Symbios_nvram Symbios;
62853790Sobrien		Tekram_nvram Tekram;
62953790Sobrien	} data;
63053790Sobrien#endif
63153790Sobrien};
63253790Sobrien
63353790Sobrien/*
63453790Sobrien *  This one is hopefully useless, but actually useful. :-)
63553790Sobrien */
63653790Sobrien#ifndef assert
63753790Sobrien#define	assert(expression) { \
63853790Sobrien	if (!(expression)) { \
63953790Sobrien		(void)panic( \
64053790Sobrien			"assertion \"%s\" failed: file \"%s\", line %d\n", \
64153790Sobrien			#expression, \
64253790Sobrien			__FILE__, __LINE__); \
64353790Sobrien	} \
64453790Sobrien}
64553790Sobrien#endif
64653790Sobrien
64753790Sobrien/*
64853790Sobrien *  Some provision for a possible big endian support.
64953790Sobrien *  By the way some Symbios chips also may support some kind
65053790Sobrien *  of big endian byte ordering.
65153790Sobrien *  For now, this stuff does not deserve any comments. :)
65253790Sobrien */
65353790Sobrien
65453790Sobrien#define sym_offb(o)	(o)
65553790Sobrien#define sym_offw(o)	(o)
65653790Sobrien
65753790Sobrien#define cpu_to_scr(dw)	(dw)
65853790Sobrien#define scr_to_cpu(dw)	(dw)
65953790Sobrien
66053790Sobrien/*
66153790Sobrien *  Access to the controller chip.
66253790Sobrien *
66354690Sobrien *  If SYM_CONF_IOMAPPED is defined, the driver will use
66453790Sobrien *  normal IOs instead of the MEMORY MAPPED IO method
66553790Sobrien *  recommended by PCI specifications.
66653790Sobrien */
66753790Sobrien
66853790Sobrien/*
66953790Sobrien *  Define some understable verbs so we will not suffer of
67053790Sobrien *  having to deal with the stupid PC tokens for IO.
67153790Sobrien */
67253790Sobrien#define io_read8(p)	 scr_to_cpu(inb((p)))
67353790Sobrien#define	io_read16(p)	 scr_to_cpu(inw((p)))
67453790Sobrien#define io_read32(p)	 scr_to_cpu(inl((p)))
67553790Sobrien#define	io_write8(p, v)	 outb((p), cpu_to_scr(v))
67653790Sobrien#define io_write16(p, v) outw((p), cpu_to_scr(v))
67753790Sobrien#define io_write32(p, v) outl((p), cpu_to_scr(v))
67853790Sobrien
67953793Sobrien#ifdef	__alpha__
68053790Sobrien
68153793Sobrien#define mmio_read8(a)	     readb(a)
68253793Sobrien#define mmio_read16(a)	     readw(a)
68353793Sobrien#define mmio_read32(a)	     readl(a)
68453793Sobrien#define mmio_write8(a, b)    writeb(a, b)
68553793Sobrien#define mmio_write16(a, b)   writew(a, b)
68653793Sobrien#define mmio_write32(a, b)   writel(a, b)
68753790Sobrien
68853793Sobrien#else /*__i386__*/
68953793Sobrien
69053793Sobrien#define mmio_read8(a)	     scr_to_cpu((*(volatile unsigned char *) (a)))
69153793Sobrien#define mmio_read16(a)	     scr_to_cpu((*(volatile unsigned short *) (a)))
69253793Sobrien#define mmio_read32(a)	     scr_to_cpu((*(volatile unsigned int *) (a)))
69353793Sobrien#define mmio_write8(a, b)   (*(volatile unsigned char *) (a)) = cpu_to_scr(b)
69453793Sobrien#define mmio_write16(a, b)  (*(volatile unsigned short *) (a)) = cpu_to_scr(b)
69553793Sobrien#define mmio_write32(a, b)  (*(volatile unsigned int *) (a)) = cpu_to_scr(b)
69653793Sobrien
69753793Sobrien#endif
69853793Sobrien
69953790Sobrien/*
70053790Sobrien *  Normal IO
70153790Sobrien */
70254690Sobrien#if defined(SYM_CONF_IOMAPPED)
70353790Sobrien
70453790Sobrien#define	INB_OFF(o)	io_read8(np->io_port + sym_offb(o))
70553790Sobrien#define	OUTB_OFF(o, v)	io_write8(np->io_port + sym_offb(o), (v))
70653790Sobrien
70753790Sobrien#define	INW_OFF(o)	io_read16(np->io_port + sym_offw(o))
70853790Sobrien#define	OUTW_OFF(o, v)	io_write16(np->io_port + sym_offw(o), (v))
70953790Sobrien
71053790Sobrien#define	INL_OFF(o)	io_read32(np->io_port + (o))
71153793Sobrien#define	OUTL_OFF(o, v)	io_write32(np->io_port + (o), (v))
71253790Sobrien
71353790Sobrien#else	/* Memory mapped IO */
71453790Sobrien
71553790Sobrien#define	INB_OFF(o)	mmio_read8(np->mmio_va + sym_offb(o))
71653790Sobrien#define	OUTB_OFF(o, v)	mmio_write8(np->mmio_va + sym_offb(o), (v))
71753790Sobrien
71853790Sobrien#define	INW_OFF(o)	mmio_read16(np->mmio_va + sym_offw(o))
71953790Sobrien#define	OUTW_OFF(o, v)	mmio_write16(np->mmio_va + sym_offw(o), (v))
72053790Sobrien
72153790Sobrien#define	INL_OFF(o)	mmio_read32(np->mmio_va + (o))
72253790Sobrien#define	OUTL_OFF(o, v)	mmio_write32(np->mmio_va + (o), (v))
72353790Sobrien
72453790Sobrien#endif
72553790Sobrien
72653790Sobrien/*
72753790Sobrien *  Common to both normal IO and MMIO.
72853790Sobrien */
72953790Sobrien#define INB(r)		INB_OFF(offsetof(struct sym_reg,r))
73053790Sobrien#define INW(r)		INW_OFF(offsetof(struct sym_reg,r))
73153790Sobrien#define INL(r)		INL_OFF(offsetof(struct sym_reg,r))
73253790Sobrien
73353790Sobrien#define OUTB(r, v)	OUTB_OFF(offsetof(struct sym_reg,r), (v))
73453790Sobrien#define OUTW(r, v)	OUTW_OFF(offsetof(struct sym_reg,r), (v))
73553790Sobrien#define OUTL(r, v)	OUTL_OFF(offsetof(struct sym_reg,r), (v))
73653790Sobrien
73753790Sobrien#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
73853790Sobrien#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
73953790Sobrien#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
74053790Sobrien#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
74153790Sobrien#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
74253790Sobrien#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
74353790Sobrien
74453790Sobrien/*
74553790Sobrien *  Command control block states.
74653790Sobrien */
74753790Sobrien#define HS_IDLE		(0)
74853790Sobrien#define HS_BUSY		(1)
74953790Sobrien#define HS_NEGOTIATE	(2)	/* sync/wide data transfer*/
75053790Sobrien#define HS_DISCONNECT	(3)	/* Disconnected by target */
75153790Sobrien
75253790Sobrien#define HS_DONEMASK	(0x80)
75353790Sobrien#define HS_COMPLETE	(4|HS_DONEMASK)
75453790Sobrien#define HS_SEL_TIMEOUT	(5|HS_DONEMASK)	/* Selection timeout      */
75553790Sobrien#define HS_UNEXPECTED	(6|HS_DONEMASK)	/* Unexpected disconnect  */
75653790Sobrien#define HS_COMP_ERR	(7|HS_DONEMASK)	/* Completed with error	  */
75753790Sobrien
75853790Sobrien/*
75953790Sobrien *  Software Interrupt Codes
76053790Sobrien */
76153790Sobrien#define	SIR_BAD_SCSI_STATUS	(1)
76253790Sobrien#define	SIR_SEL_ATN_NO_MSG_OUT	(2)
76353790Sobrien#define	SIR_MSG_RECEIVED	(3)
76453790Sobrien#define	SIR_MSG_WEIRD		(4)
76553790Sobrien#define	SIR_NEGO_FAILED		(5)
76653790Sobrien#define	SIR_NEGO_PROTO		(6)
76753790Sobrien#define	SIR_SCRIPT_STOPPED	(7)
76853790Sobrien#define	SIR_REJECT_TO_SEND	(8)
76953790Sobrien#define	SIR_SWIDE_OVERRUN	(9)
77053790Sobrien#define	SIR_SODL_UNDERRUN	(10)
77153790Sobrien#define	SIR_RESEL_NO_MSG_IN	(11)
77253790Sobrien#define	SIR_RESEL_NO_IDENTIFY	(12)
77353790Sobrien#define	SIR_RESEL_BAD_LUN	(13)
77453790Sobrien#define	SIR_TARGET_SELECTED	(14)
77553790Sobrien#define	SIR_RESEL_BAD_I_T_L	(15)
77653790Sobrien#define	SIR_RESEL_BAD_I_T_L_Q	(16)
77753790Sobrien#define	SIR_ABORT_SENT		(17)
77853790Sobrien#define	SIR_RESEL_ABORTED	(18)
77953790Sobrien#define	SIR_MSG_OUT_DONE	(19)
78053790Sobrien#define	SIR_COMPLETE_ERROR	(20)
78153790Sobrien#define	SIR_MAX			(20)
78253790Sobrien
78353790Sobrien/*
78453790Sobrien *  Extended error bit codes.
78553790Sobrien *  xerr_status field of struct sym_ccb.
78653790Sobrien */
78753790Sobrien#define	XE_EXTRA_DATA	(1)	/* unexpected data phase	 */
78853790Sobrien#define	XE_BAD_PHASE	(1<<1)	/* illegal phase (4/5)		 */
78953790Sobrien#define	XE_PARITY_ERR	(1<<2)	/* unrecovered SCSI parity error */
79053790Sobrien#define	XE_SODL_UNRUN	(1<<3)	/* ODD transfer in DATA OUT phase */
79153790Sobrien#define	XE_SWIDE_OVRUN	(1<<4)	/* ODD transfer in DATA IN phase */
79253790Sobrien
79353790Sobrien/*
79453790Sobrien *  Negotiation status.
79553790Sobrien *  nego_status field of struct sym_ccb.
79653790Sobrien */
79753790Sobrien#define NS_SYNC		(1)
79853790Sobrien#define NS_WIDE		(2)
79953790Sobrien#define NS_PPR		(3)
80053790Sobrien
80153790Sobrien/*
80253790Sobrien *  A CCB hashed table is used to retrieve CCB address
80353790Sobrien *  from DSA value.
80453790Sobrien */
80553790Sobrien#define CCB_HASH_SHIFT		8
80653790Sobrien#define CCB_HASH_SIZE		(1UL << CCB_HASH_SHIFT)
80753790Sobrien#define CCB_HASH_MASK		(CCB_HASH_SIZE-1)
80853790Sobrien#define CCB_HASH_CODE(dsa)	(((dsa) >> 9) & CCB_HASH_MASK)
80953790Sobrien
81053790Sobrien/*
81153790Sobrien *  Device flags.
81253790Sobrien */
81353790Sobrien#define SYM_DISC_ENABLED	(1)
81453790Sobrien#define SYM_TAGS_ENABLED	(1<<1)
81553790Sobrien#define SYM_SCAN_BOOT_DISABLED	(1<<2)
81653790Sobrien#define SYM_SCAN_LUNS_DISABLED	(1<<3)
81753790Sobrien
81853790Sobrien/*
81955628Sgroudier *  Host adapter miscellaneous flags.
82055628Sgroudier */
82155628Sgroudier#define SYM_AVOID_BUS_RESET	(1)
82255628Sgroudier#define SYM_SCAN_TARGETS_HILO	(1<<1)
82355628Sgroudier
82455628Sgroudier/*
82553790Sobrien *  Device quirks.
82653790Sobrien *  Some devices, for example the CHEETAH 2 LVD, disconnects without
82753790Sobrien *  saving the DATA POINTER then reconnect and terminates the IO.
82853790Sobrien *  On reselection, the automatic RESTORE DATA POINTER makes the
82953790Sobrien *  CURRENT DATA POINTER not point at the end of the IO.
83053790Sobrien *  This behaviour just breaks our calculation of the residual.
83153790Sobrien *  For now, we just force an AUTO SAVE on disconnection and will
83253790Sobrien *  fix that in a further driver version.
83353790Sobrien */
83453790Sobrien#define SYM_QUIRK_AUTOSAVE 1
83553790Sobrien
83653790Sobrien/*
83753790Sobrien *  Misc.
83853790Sobrien */
83953790Sobrien#define SYM_SNOOP_TIMEOUT (10000000)
84053790Sobrien#define SYM_PCI_IO	PCIR_MAPS
84153790Sobrien#define SYM_PCI_MMIO	(PCIR_MAPS + 4)
84253790Sobrien#define SYM_PCI_RAM	(PCIR_MAPS + 8)
84353790Sobrien#define SYM_PCI_RAM64	(PCIR_MAPS + 12)
84453790Sobrien
84553790Sobrien/*
84653790Sobrien *  Back-pointer from the CAM CCB to our data structures.
84753790Sobrien */
84853790Sobrien#define sym_hcb_ptr	spriv_ptr0
84953790Sobrien/* #define sym_ccb_ptr	spriv_ptr1 */
85053790Sobrien
85153790Sobrien/*
85253790Sobrien *  We mostly have to deal with pointers.
85353790Sobrien *  Thus these typedef's.
85453790Sobrien */
85553790Sobrientypedef struct sym_tcb *tcb_p;
85653790Sobrientypedef struct sym_lcb *lcb_p;
85753790Sobrientypedef struct sym_ccb *ccb_p;
85853790Sobrientypedef struct sym_hcb *hcb_p;
85953790Sobrientypedef struct sym_scr  *script_p;
86053790Sobrientypedef struct sym_scrh *scripth_p;
86153790Sobrien
86253790Sobrien/*
86353790Sobrien *  Gather negotiable parameters value
86453790Sobrien */
86553790Sobrienstruct sym_trans {
86653790Sobrien	u8 period;
86753790Sobrien	u8 offset;
86853790Sobrien	u8 width;
86953790Sobrien	u8 options;	/* PPR options */
87053790Sobrien};
87153790Sobrien
87253790Sobrienstruct sym_tinfo {
87353790Sobrien	struct sym_trans current;
87453790Sobrien	struct sym_trans goal;
87553790Sobrien	struct sym_trans user;
87653790Sobrien};
87753790Sobrien
87853790Sobrien#define BUS_8_BIT	MSG_EXT_WDTR_BUS_8_BIT
87953790Sobrien#define BUS_16_BIT	MSG_EXT_WDTR_BUS_16_BIT
88053790Sobrien
88153790Sobrien/*
88253790Sobrien *  Target Control Block
88353790Sobrien */
88453790Sobrienstruct sym_tcb {
88553790Sobrien	/*
88653790Sobrien	 *  LUN table used by the SCRIPTS processor.
88753790Sobrien	 *  An array of bus addresses is used on reselection.
88853790Sobrien	 *  LUN #0 is a special case, since multi-lun devices are rare,
88953790Sobrien	 *  and we we want to speed-up the general case and not waste
89053790Sobrien	 *  resources.
89153790Sobrien	 */
89253790Sobrien	u32	*luntbl;	/* LCBs bus address table	*/
89353790Sobrien	u32	luntbl_sa;	/* bus address of this table	*/
89453790Sobrien	u32	lun0_sa;	/* bus address of LCB #0	*/
89553790Sobrien
89653790Sobrien	/*
89753790Sobrien	 *  LUN table used by the C code.
89853790Sobrien	 */
89953790Sobrien	lcb_p	lun0p;		/* LCB of LUN #0 (usual case)	*/
90054690Sobrien#if SYM_CONF_MAX_LUN > 1
90153790Sobrien	lcb_p	*lunmp;		/* Other LCBs [1..MAX_LUN]	*/
90253790Sobrien#endif
90353790Sobrien
90453790Sobrien	/*
90553790Sobrien	 *  Bitmap that tells about LUNs that succeeded at least
90653790Sobrien	 *  1 IO and therefore assumed to be a real device.
90753790Sobrien	 *  Avoid useless allocation of the LCB structure.
90853790Sobrien	 */
90954690Sobrien	u32	lun_map[(SYM_CONF_MAX_LUN+31)/32];
91053790Sobrien
91153790Sobrien	/*
91253790Sobrien	 *  Bitmap that tells about LUNs that haven't yet an LCB
91353790Sobrien	 *  allocated (not discovered or LCB allocation failed).
91453790Sobrien	 */
91554690Sobrien	u32	busy0_map[(SYM_CONF_MAX_LUN+31)/32];
91653790Sobrien
91753790Sobrien	/*
91853790Sobrien	 *  Actual SYNC/WIDE IO registers value for this target.
91953790Sobrien	 *  'sval', 'wval' and 'uval' are read from SCRIPTS and
92053790Sobrien	 *  so have alignment constraints.
92153790Sobrien	 */
92253790Sobrien/*0*/	u_char	uval;		/* -> SCNTL4 register		*/
92353790Sobrien/*1*/	u_char	sval;		/* -> SXFER  io register	*/
92453790Sobrien/*2*/	u_char	filler1;
92553790Sobrien/*3*/	u_char	wval;		/* -> SCNTL3 io register	*/
92653790Sobrien
92753790Sobrien	/*
92853790Sobrien	 *  Transfer capabilities (SIP)
92953790Sobrien	 */
93053790Sobrien	struct sym_tinfo tinfo;
93153790Sobrien
93253790Sobrien	/*
93353790Sobrien	 * Keep track of the CCB used for the negotiation in order
93453790Sobrien	 * to ensure that only 1 negotiation is queued at a time.
93553790Sobrien	 */
93653790Sobrien	ccb_p   nego_cp;	/* CCB used for the nego		*/
93753790Sobrien
93853790Sobrien	/*
93953790Sobrien	 *  Set when we want to reset the device.
94053790Sobrien	 */
94153790Sobrien	u_char	to_reset;
94253790Sobrien
94353790Sobrien	/*
94453790Sobrien	 *  Other user settable limits and options.
94553790Sobrien	 *  These limits are read from the NVRAM if present.
94653790Sobrien	 */
94753790Sobrien	u_char	usrflags;
94853790Sobrien	u_short	usrtags;
94953790Sobrien};
95053790Sobrien
95153790Sobrien/*
95253790Sobrien *  Logical Unit Control Block
95353790Sobrien */
95453790Sobrienstruct sym_lcb {
95553790Sobrien	/*
95653790Sobrien	 *  SCRIPTS address jumped by SCRIPTS on reselection.
95753790Sobrien	 *  For not probed logical units, this address points to
95853790Sobrien	 *  SCRIPTS that deal with bad LU handling (must be at
95953790Sobrien	 *  offset zero for that reason).
96053790Sobrien	 */
96153790Sobrien/*0*/	u32	resel_sa;
96253790Sobrien
96353790Sobrien	/*
96453790Sobrien	 *  Task (bus address of a CCB) read from SCRIPTS that points
96553790Sobrien	 *  to the unique ITL nexus allowed to be disconnected.
96653790Sobrien	 */
96753790Sobrien	u32	itl_task_sa;
96853790Sobrien
96953790Sobrien	/*
97053790Sobrien	 *  Task table read from SCRIPTS that contains pointers to
97153790Sobrien	 *  ITLQ nexuses (bus addresses read from SCRIPTS).
97253790Sobrien	 */
97353790Sobrien	u32	*itlq_tbl;	/* Kernel virtual address	*/
97453790Sobrien	u32	itlq_tbl_sa;	/* Bus address used by SCRIPTS	*/
97553790Sobrien
97653790Sobrien	/*
97753790Sobrien	 *  Busy CCBs management.
97853790Sobrien	 */
97953790Sobrien	u_short	busy_itlq;	/* Number of busy tagged CCBs	*/
98053790Sobrien	u_short	busy_itl;	/* Number of busy untagged CCBs	*/
98153790Sobrien
98253790Sobrien	/*
98353790Sobrien	 *  Circular tag allocation buffer.
98453790Sobrien	 */
98553790Sobrien	u_short	ia_tag;		/* Tag allocation index		*/
98653790Sobrien	u_short	if_tag;		/* Tag release index		*/
98753790Sobrien	u_char	*cb_tags;	/* Circular tags buffer		*/
98853790Sobrien
98953790Sobrien	/*
99053790Sobrien	 *  Set when we want to clear all tasks.
99153790Sobrien	 */
99253790Sobrien	u_char to_clear;
99353790Sobrien
99453790Sobrien	/*
99553790Sobrien	 *  Capabilities.
99653790Sobrien	 */
99753790Sobrien	u_char	user_flags;
99853790Sobrien	u_char	current_flags;
99953790Sobrien};
100053790Sobrien
100153790Sobrien/*
100253790Sobrien *  Action from SCRIPTS on a task.
100353790Sobrien *  Is part of the CCB, but is also used separately to plug
100453790Sobrien *  error handling action to perform from SCRIPTS.
100553790Sobrien */
100653790Sobrienstruct sym_actscr {
100753790Sobrien	u32	start;		/* Jumped by SCRIPTS after selection	*/
100853790Sobrien	u32	restart;	/* Jumped by SCRIPTS on relection	*/
100953790Sobrien};
101053790Sobrien
101153790Sobrien/*
101253790Sobrien *  Phase mismatch context.
101353790Sobrien *
101453790Sobrien *  It is part of the CCB and is used as parameters for the
101553790Sobrien *  DATA pointer. We need two contexts to handle correctly the
101653790Sobrien *  SAVED DATA POINTER.
101753790Sobrien */
101853790Sobrienstruct sym_pmc {
101953790Sobrien	struct	sym_tblmove sg;	/* Updated interrupted SG block	*/
102053790Sobrien	u32	ret;		/* SCRIPT return address	*/
102153790Sobrien};
102253790Sobrien
102353790Sobrien/*
102453790Sobrien *  LUN control block lookup.
102553790Sobrien *  We use a direct pointer for LUN #0, and a table of
102653790Sobrien *  pointers which is only allocated for devices that support
102753790Sobrien *  LUN(s) > 0.
102853790Sobrien */
102954690Sobrien#if SYM_CONF_MAX_LUN <= 1
103053790Sobrien#define sym_lp(np, tp, lun) (!lun) ? (tp)->lun0p : 0
103153790Sobrien#else
103253790Sobrien#define sym_lp(np, tp, lun) \
103353790Sobrien	(!lun) ? (tp)->lun0p : (tp)->lunmp ? (tp)->lunmp[(lun)] : 0
103453790Sobrien#endif
103553790Sobrien
103653790Sobrien/*
103753790Sobrien *  Status are used by the host and the script processor.
103853790Sobrien *
103953790Sobrien *  The last four bytes (status[4]) are copied to the
104053790Sobrien *  scratchb register (declared as scr0..scr3) just after the
104153790Sobrien *  select/reselect, and copied back just after disconnecting.
104253790Sobrien *  Inside the script the XX_REG are used.
104353790Sobrien *
104453790Sobrien *  The first four bytes (scr_st[4]) are used inside the
104553790Sobrien *  script by "LOAD/STORE" commands.
104653790Sobrien *  Because source and destination must have the same alignment
104753790Sobrien *  in a DWORD, the fields HAVE to be at the choosen offsets.
104853790Sobrien *  	xerr_st		0	(0x34)	scratcha
104953790Sobrien *  	nego_st		2
105053790Sobrien */
105153790Sobrien
105253790Sobrien/*
105353790Sobrien *  Last four bytes (script)
105453790Sobrien */
105553790Sobrien#define  QU_REG	scr0
105653790Sobrien#define  HS_REG	scr1
105753790Sobrien#define  HS_PRT	nc_scr1
105853790Sobrien#define  SS_REG	scr2
105953790Sobrien#define  SS_PRT	nc_scr2
106053790Sobrien#define  HF_REG	scr3
106153790Sobrien#define  HF_PRT	nc_scr3
106253790Sobrien
106353790Sobrien/*
106453790Sobrien *  Last four bytes (host)
106553790Sobrien */
106653790Sobrien#define  actualquirks  phys.status[0]
106753790Sobrien#define  host_status   phys.status[1]
106853790Sobrien#define  ssss_status   phys.status[2]
106953790Sobrien#define  host_flags    phys.status[3]
107053790Sobrien
107153790Sobrien/*
107253790Sobrien *  Host flags
107353790Sobrien */
107453790Sobrien#define HF_IN_PM0	1u
107553790Sobrien#define HF_IN_PM1	(1u<<1)
107653790Sobrien#define HF_ACT_PM	(1u<<2)
107753790Sobrien#define HF_DP_SAVED	(1u<<3)
107853790Sobrien#define HF_SENSE	(1u<<4)
107953790Sobrien#define HF_EXT_ERR	(1u<<5)
108054690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
108153790Sobrien#define HF_HINT_IARB	(1u<<7)
108253790Sobrien#endif
108353790Sobrien
108453790Sobrien/*
108553790Sobrien *  First four bytes (script)
108653790Sobrien */
108753790Sobrien#define  xerr_st       scr_st[0]
108853790Sobrien#define  nego_st       scr_st[2]
108953790Sobrien
109053790Sobrien/*
109153790Sobrien *  First four bytes (host)
109253790Sobrien */
109353790Sobrien#define  xerr_status   phys.xerr_st
109453790Sobrien#define  nego_status   phys.nego_st
109553790Sobrien
109653790Sobrien/*
109753790Sobrien *  Data Structure Block
109853790Sobrien *
109953790Sobrien *  During execution of a ccb by the script processor, the
110053790Sobrien *  DSA (data structure address) register points to this
110153790Sobrien *  substructure of the ccb.
110253790Sobrien */
110353790Sobrienstruct dsb {
110453790Sobrien	/*
110553790Sobrien	 *  Start and restart SCRIPTS addresses (must be at 0).
110653790Sobrien	 */
110753790Sobrien/*0*/	struct sym_actscr go;
110853790Sobrien
110953790Sobrien	/*
111053790Sobrien	 *  SCRIPTS jump address that deal with data pointers.
111153790Sobrien	 *  'savep' points to the position in the script responsible
111253790Sobrien	 *  for the	actual transfer of data.
111353790Sobrien	 *  It's written on reception of a SAVE_DATA_POINTER message.
111453790Sobrien	 */
111553790Sobrien	u32	savep;		/* Jump address to saved data pointer	*/
111653790Sobrien	u32	lastp;		/* SCRIPTS address at end of data	*/
111753790Sobrien	u32	goalp;		/* Not used for now			*/
111853790Sobrien
111953790Sobrien	/*
112053790Sobrien	 *  Status fields.
112153790Sobrien	 */
112253790Sobrien	u8	scr_st[4];	/* script status		*/
112353790Sobrien	u8	status[4];	/* host status			*/
112453790Sobrien
112553790Sobrien	/*
112653790Sobrien	 *  Table data for Script
112753790Sobrien	 */
112853790Sobrien	struct sym_tblsel  select;
112953790Sobrien	struct sym_tblmove smsg;
113053790Sobrien	struct sym_tblmove smsg_ext;
113153790Sobrien	struct sym_tblmove cmd;
113253790Sobrien	struct sym_tblmove sense;
113354690Sobrien	struct sym_tblmove data [SYM_CONF_MAX_SG];
113453790Sobrien
113553790Sobrien	/*
113653790Sobrien	 *  Phase mismatch contexts.
113753790Sobrien	 *  We need two to handle correctly the SAVED DATA POINTER.
113853790Sobrien	 */
113953790Sobrien	struct sym_pmc pm0;
114053790Sobrien	struct sym_pmc pm1;
114153790Sobrien
114253790Sobrien	/*
114353790Sobrien	 *  Extra bytes count transferred in case of data overrun.
114453790Sobrien	 */
114553790Sobrien	u32	extra_bytes;
114653790Sobrien};
114753790Sobrien
114853790Sobrien/*
114953790Sobrien *  Our Command Control Block
115053790Sobrien */
115153790Sobrienstruct sym_ccb {
115253790Sobrien	/*
115353790Sobrien	 *  This is the data structure which is pointed by the DSA
115453790Sobrien	 *  register when it is executed by the script processor.
115553790Sobrien	 *  It must be the first entry.
115653790Sobrien	 */
115753790Sobrien	struct dsb phys;
115853790Sobrien
115953790Sobrien	/*
116053790Sobrien	 *  Pointer to CAM ccb and related stuff.
116153790Sobrien	 */
116253790Sobrien	union ccb *cam_ccb;	/* CAM scsiio ccb		*/
116353790Sobrien	int	data_len;	/* Total data length		*/
116453790Sobrien	int	segments;	/* Number of SG segments	*/
116553790Sobrien
116653790Sobrien	/*
116753790Sobrien	 *  Message areas.
116853790Sobrien	 *  We prepare a message to be sent after selection.
116953790Sobrien	 *  We may use a second one if the command is rescheduled
117053790Sobrien	 *  due to CHECK_CONDITION or COMMAND TERMINATED.
117153790Sobrien	 *  Contents are IDENTIFY and SIMPLE_TAG.
117253790Sobrien	 *  While negotiating sync or wide transfer,
117353790Sobrien	 *  a SDTR or WDTR message is appended.
117453790Sobrien	 */
117553790Sobrien	u_char	scsi_smsg [12];
117653790Sobrien	u_char	scsi_smsg2[12];
117753790Sobrien
117853790Sobrien	/*
117953790Sobrien	 *  Auto request sense related fields.
118053790Sobrien	 */
118153790Sobrien	u_char	sensecmd[6];	/* Request Sense command	*/
118253790Sobrien	u_char	sv_scsi_status;	/* Saved SCSI status 		*/
118353790Sobrien	u_char	sv_xerr_status;	/* Saved extended status	*/
118453790Sobrien	int	sv_resid;	/* Saved residual		*/
118553790Sobrien
118653790Sobrien	/*
118753790Sobrien	 *  Other fields.
118853790Sobrien	 */
118953790Sobrien	u_long	ccb_ba;		/* BUS address of this CCB	*/
119053790Sobrien	u_short	tag;		/* Tag for this transfer	*/
119153790Sobrien				/*  NO_TAG means no tag		*/
119253790Sobrien	u_char	target;
119353790Sobrien	u_char	lun;
119453790Sobrien	ccb_p	link_ccbh;	/* Host adapter CCB hash chain	*/
119553790Sobrien	SYM_QUEHEAD
119653790Sobrien		link_ccbq;	/* Link to free/busy CCB queue	*/
119753790Sobrien	u32	startp;		/* Initial data pointer		*/
119853790Sobrien	int	ext_sg;		/* Extreme data pointer, used	*/
119953790Sobrien	int	ext_ofs;	/*  to calculate the residual.	*/
120053790Sobrien	u_char	to_abort;	/* Want this IO to be aborted	*/
120153790Sobrien};
120253790Sobrien
120353790Sobrien#define CCB_PHYS(cp,lbl)	(cp->ccb_ba + offsetof(struct sym_ccb, lbl))
120453790Sobrien
120553790Sobrien/*
120653790Sobrien *  Host Control Block
120753790Sobrien */
120853790Sobrienstruct sym_hcb {
120953790Sobrien	/*
121053790Sobrien	 *  Idle task and invalid task actions and
121153790Sobrien	 *  their bus addresses.
121253790Sobrien	 */
121353790Sobrien	struct sym_actscr idletask, notask, bad_itl, bad_itlq;
121453790Sobrien	vm_offset_t idletask_ba, notask_ba, bad_itl_ba, bad_itlq_ba;
121553790Sobrien
121653790Sobrien	/*
121753790Sobrien	 *  Dummy lun table to protect us against target
121853790Sobrien	 *  returning bad lun number on reselection.
121953790Sobrien	 */
122053790Sobrien	u32	*badluntbl;	/* Table physical address	*/
122153790Sobrien	u32	badlun_sa;	/* SCRIPT handler BUS address	*/
122253790Sobrien
122353790Sobrien	/*
122453790Sobrien	 *  Bit 32-63 of the on-chip RAM bus address in LE format.
122553790Sobrien	 *  The START_RAM64 script loads the MMRS and MMWS from this
122653790Sobrien	 *  field.
122753790Sobrien	 */
122853790Sobrien	u32	scr_ram_seg;
122953790Sobrien
123053790Sobrien	/*
123153790Sobrien	 *  Chip and controller indentification.
123253790Sobrien	 */
123353790Sobrien#ifdef FreeBSD_4_Bus
123453790Sobrien	device_t device;
123553790Sobrien#else
123653790Sobrien	pcici_t	pci_tag;
123753790Sobrien#endif
123853790Sobrien	int	unit;
123953790Sobrien	char	inst_name[8];
124053790Sobrien
124153790Sobrien	/*
124253790Sobrien	 *  Initial value of some IO register bits.
124353790Sobrien	 *  These values are assumed to have been set by BIOS, and may
124453790Sobrien	 *  be used to probe adapter implementation differences.
124553790Sobrien	 */
124653790Sobrien	u_char	sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4,
124753796Sobrien		sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_scntl4,
124853796Sobrien		sv_stest1;
124953790Sobrien
125053790Sobrien	/*
125153790Sobrien	 *  Actual initial value of IO register bits used by the
125253790Sobrien	 *  driver. They are loaded at initialisation according to
125353790Sobrien	 *  features that are to be enabled/disabled.
125453790Sobrien	 */
125553790Sobrien	u_char	rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4,
125653790Sobrien		rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4;
125753790Sobrien
125853790Sobrien	/*
125953790Sobrien	 *  Target data used by the CPU.
126053790Sobrien	 */
126154690Sobrien	struct sym_tcb	target[SYM_CONF_MAX_TARGET];
126253790Sobrien
126353790Sobrien	/*
126453790Sobrien	 *  Target control block bus address array used by the SCRIPT
126553790Sobrien	 *  on reselection.
126653790Sobrien	 */
126753790Sobrien	u32		*targtbl;
126853790Sobrien
126953790Sobrien	/*
127053790Sobrien	 *  CAM SIM information for this instance.
127153790Sobrien	 */
127253790Sobrien	struct		cam_sim  *sim;
127353790Sobrien	struct		cam_path *path;
127453790Sobrien
127553790Sobrien	/*
127653790Sobrien	 *  Allocated hardware resources.
127753790Sobrien	 */
127853790Sobrien#ifdef FreeBSD_4_Bus
127953790Sobrien	struct resource	*irq_res;
128053790Sobrien	struct resource	*io_res;
128153790Sobrien	struct resource	*mmio_res;
128253790Sobrien	struct resource	*ram_res;
128353790Sobrien	int		ram_id;
128453790Sobrien	void *intr;
128553790Sobrien#endif
128653790Sobrien
128753790Sobrien	/*
128853790Sobrien	 *  Bus stuff.
128953790Sobrien	 *
129053790Sobrien	 *  My understanding of PCI is that all agents must share the
129153790Sobrien	 *  same addressing range and model.
129253790Sobrien	 *  But some hardware architecture guys provide complex and
129353790Sobrien	 *  brain-deaded stuff that makes shit.
129453790Sobrien	 *  This driver only support PCI compliant implementations and
129553790Sobrien	 *  deals with part of the BUS stuff complexity only to fit O/S
129653790Sobrien	 *  requirements.
129753790Sobrien	 */
129853790Sobrien#ifdef FreeBSD_4_Bus
129953790Sobrien	bus_space_handle_t	io_bsh;
130053790Sobrien	bus_space_tag_t		io_tag;
130153790Sobrien	bus_space_handle_t	mmio_bsh;
130253790Sobrien	bus_space_tag_t		mmio_tag;
130353790Sobrien	bus_space_handle_t	ram_bsh;
130453790Sobrien	bus_space_tag_t		ram_tag;
130553790Sobrien#endif
130653790Sobrien
130753790Sobrien	/*
130853790Sobrien	 *  Virtual and physical bus addresses of the chip.
130953790Sobrien	 */
131053790Sobrien	vm_offset_t	mmio_va;	/* MMIO kernel virtual address	*/
131153790Sobrien	vm_offset_t	mmio_pa;	/* MMIO CPU physical address	*/
131253790Sobrien	vm_offset_t	mmio_ba;	/* MMIO BUS address		*/
131353790Sobrien	int		mmio_ws;	/* MMIO Window size		*/
131453790Sobrien
131553790Sobrien	vm_offset_t	ram_va;		/* RAM kernel virtual address	*/
131653790Sobrien	vm_offset_t	ram_pa;		/* RAM CPU physical address	*/
131753790Sobrien	vm_offset_t	ram_ba;		/* RAM BUS address		*/
131853790Sobrien	int		ram_ws;		/* RAM window size		*/
131953790Sobrien	u32		io_port;	/* IO port address		*/
132053790Sobrien
132153790Sobrien	/*
132253790Sobrien	 *  SCRIPTS virtual and physical bus addresses.
132353790Sobrien	 *  'script'  is loaded in the on-chip RAM if present.
132453790Sobrien	 *  'scripth' stays in main memory for all chips except the
132553790Sobrien	 *  53C895A, 53C896 and 53C1010 that provide 8K on-chip RAM.
132653790Sobrien	 */
132753790Sobrien	struct sym_scr	*script0;	/* Copies of script and scripth	*/
132853790Sobrien	struct sym_scrh	*scripth0;	/*  relocated for this host.	*/
132953790Sobrien	vm_offset_t	script_ba;	/* Actual script and scripth	*/
133053790Sobrien	vm_offset_t	scripth_ba;	/*  bus addresses.		*/
133153790Sobrien	vm_offset_t	scripth0_ba;
133253790Sobrien
133353790Sobrien	/*
133453790Sobrien	 *  General controller parameters and configuration.
133553790Sobrien	 */
133653790Sobrien	u_short	device_id;	/* PCI device id		*/
133753790Sobrien	u_char	revision_id;	/* PCI device revision id	*/
133853790Sobrien	u_int	features;	/* Chip features map		*/
133953790Sobrien	u_char	myaddr;		/* SCSI id of the adapter	*/
134053790Sobrien	u_char	maxburst;	/* log base 2 of dwords burst	*/
134153790Sobrien	u_char	maxwide;	/* Maximum transfer width	*/
134253790Sobrien	u_char	minsync;	/* Min sync period factor (ST)	*/
134353790Sobrien	u_char	maxsync;	/* Max sync period factor (ST)	*/
134453790Sobrien	u_char	minsync_dt;	/* Min sync period factor (DT)	*/
134553790Sobrien	u_char	maxsync_dt;	/* Max sync period factor (DT)	*/
134653790Sobrien	u_char	maxoffs;	/* Max scsi offset		*/
134753790Sobrien	u_char	multiplier;	/* Clock multiplier (1,2,4)	*/
134853790Sobrien	u_char	clock_divn;	/* Number of clock divisors	*/
134953790Sobrien	u_long	clock_khz;	/* SCSI clock frequency in KHz	*/
135053790Sobrien
135153790Sobrien	/*
135253790Sobrien	 *  Start queue management.
135353790Sobrien	 *  It is filled up by the host processor and accessed by the
135453790Sobrien	 *  SCRIPTS processor in order to start SCSI commands.
135553790Sobrien	 */
135653790Sobrien	volatile		/* Prevent code optimizations	*/
135753790Sobrien	u32	*squeue;	/* Start queue			*/
135853790Sobrien	u_short	squeueput;	/* Next free slot of the queue	*/
135953790Sobrien	u_short	actccbs;	/* Number of allocated CCBs	*/
136053790Sobrien
136153790Sobrien	/*
136253790Sobrien	 *  Command completion queue.
136353790Sobrien	 *  It is the same size as the start queue to avoid overflow.
136453790Sobrien	 */
136553790Sobrien	u_short	dqueueget;	/* Next position to scan	*/
136653790Sobrien	volatile		/* Prevent code optimizations	*/
136753790Sobrien	u32	*dqueue;	/* Completion (done) queue	*/
136853790Sobrien
136953790Sobrien	/*
137053790Sobrien	 *  Miscellaneous buffers accessed by the scripts-processor.
137153790Sobrien	 *  They shall be DWORD aligned, because they may be read or
137253790Sobrien	 *  written with a script command.
137353790Sobrien	 */
137453790Sobrien	u_char		msgout[8];	/* Buffer for MESSAGE OUT 	*/
137553790Sobrien	u_char		msgin [8];	/* Buffer for MESSAGE IN	*/
137653790Sobrien	u32		lastmsg;	/* Last SCSI message sent	*/
137753790Sobrien	u_char		scratch;	/* Scratch for SCSI receive	*/
137853790Sobrien
137953790Sobrien	/*
138053790Sobrien	 *  Miscellaneous configuration and status parameters.
138153790Sobrien	 */
138255628Sgroudier	u_char		usrflags;	/* Miscellaneous user flags	*/
138353790Sobrien	u_char		scsi_mode;	/* Current SCSI BUS mode	*/
138453790Sobrien	u_char		verbose;	/* Verbosity for this controller*/
138553790Sobrien	u32		cache;		/* Used for cache test at init.	*/
138653790Sobrien
138753790Sobrien	/*
138853790Sobrien	 *  CCB lists and queue.
138953790Sobrien	 */
139053790Sobrien	ccb_p ccbh[CCB_HASH_SIZE];	/* CCB hashed by DSA value	*/
139153790Sobrien	SYM_QUEHEAD	free_ccbq;	/* Queue of available CCBs	*/
139253790Sobrien	SYM_QUEHEAD	busy_ccbq;	/* Queue of busy CCBs		*/
139353790Sobrien
139453790Sobrien	/*
139553790Sobrien	 *  During error handling and/or recovery,
139653790Sobrien	 *  active CCBs that are to be completed with
139753790Sobrien	 *  error or requeued are moved from the busy_ccbq
139853790Sobrien	 *  to the comp_ccbq prior to completion.
139953790Sobrien	 */
140053790Sobrien	SYM_QUEHEAD	comp_ccbq;
140153790Sobrien
140253790Sobrien	/*
140353790Sobrien	 *  CAM CCB pending queue.
140453790Sobrien	 */
140553790Sobrien	SYM_QUEHEAD	cam_ccbq;
140653790Sobrien
140753790Sobrien	/*
140853790Sobrien	 *  IMMEDIATE ARBITRATION (IARB) control.
140953790Sobrien	 *
141053790Sobrien	 *  We keep track in 'last_cp' of the last CCB that has been
141153790Sobrien	 *  queued to the SCRIPTS processor and clear 'last_cp' when
141253790Sobrien	 *  this CCB completes. If last_cp is not zero at the moment
141353790Sobrien	 *  we queue a new CCB, we set a flag in 'last_cp' that is
141453790Sobrien	 *  used by the SCRIPTS as a hint for setting IARB.
141553790Sobrien	 *  We donnot set more than 'iarb_max' consecutive hints for
141653790Sobrien	 *  IARB in order to leave devices a chance to reselect.
141753790Sobrien	 *  By the way, any non zero value of 'iarb_max' is unfair. :)
141853790Sobrien	 */
141954690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
142053790Sobrien	u_short		iarb_max;	/* Max. # consecutive IARB hints*/
142153790Sobrien	u_short		iarb_count;	/* Actual # of these hints	*/
142253790Sobrien	ccb_p		last_cp;
142353790Sobrien#endif
142453790Sobrien
142553790Sobrien	/*
142653790Sobrien	 *  Command abort handling.
142753790Sobrien	 *  We need to synchronize tightly with the SCRIPTS
142853790Sobrien	 *  processor in order to handle things correctly.
142953790Sobrien	 */
143053790Sobrien	u_char		abrt_msg[4];	/* Message to send buffer	*/
143153790Sobrien	struct sym_tblmove abrt_tbl;	/* Table for the MOV of it 	*/
143253790Sobrien	struct sym_tblsel  abrt_sel;	/* Sync params for selection	*/
143353790Sobrien	u_char		istat_sem;	/* Tells the chip to stop (SEM)	*/
143453790Sobrien};
143553790Sobrien
143653790Sobrien#define SCRIPT_BA(np,lbl)   (np->script_ba   + offsetof(struct sym_scr, lbl))
143753790Sobrien#define SCRIPTH_BA(np,lbl)  (np->scripth_ba  + offsetof(struct sym_scrh,lbl))
143853790Sobrien#define SCRIPTH0_BA(np,lbl) (np->scripth0_ba + offsetof(struct sym_scrh,lbl))
143953790Sobrien
144053790Sobrien/*
144153790Sobrien *  Scripts for SYMBIOS-Processor
144253790Sobrien *
144353790Sobrien *  Use sym_fill_scripts() to create the variable parts.
144453790Sobrien *  Use sym_bind_script()  to make a copy and bind to
144553790Sobrien *  physical bus addresses.
144653790Sobrien *  We have to know the offsets of all labels before we reach
144753790Sobrien *  them (for forward jumps). Therefore we declare a struct
144853790Sobrien *  here. If you make changes inside the script,
144953790Sobrien *
145053790Sobrien *  DONT FORGET TO CHANGE THE LENGTHS HERE!
145153790Sobrien */
145253790Sobrien
145353790Sobrien/*
145453790Sobrien *  Script fragments which are loaded into the on-chip RAM
145553790Sobrien *  of 825A, 875, 876, 895, 895A, 896 and 1010 chips.
145653790Sobrien *  Must not exceed 4K bytes.
145753790Sobrien */
145853790Sobrienstruct sym_scr {
145953790Sobrien	u32 start		[ 14];
146053790Sobrien	u32 getjob_begin	[  4];
146153790Sobrien	u32 getjob_end		[  4];
146253790Sobrien	u32 select		[  8];
146353790Sobrien	u32 wf_sel_done		[  2];
146453790Sobrien	u32 send_ident		[  2];
146554690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
146653790Sobrien	u32 select2		[  8];
146753790Sobrien#else
146853790Sobrien	u32 select2		[  2];
146953790Sobrien#endif
147053790Sobrien	u32 command		[  2];
147154690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
147253790Sobrien	u32 dispatch		[ 18];
147353790Sobrien#else
147453790Sobrien	u32 dispatch		[ 30];
147553790Sobrien#endif
147653790Sobrien	u32 sel_no_cmd		[ 10];
147753790Sobrien	u32 init		[  6];
147853790Sobrien	u32 clrack		[  4];
147953790Sobrien	u32 disp_msg_in		[  2];
148053790Sobrien	u32 disp_status		[  4];
148153790Sobrien	u32 datai_done		[ 16];
148253790Sobrien	u32 datao_done		[ 10];
148353790Sobrien	u32 ign_i_w_r_msg	[  4];
148453790Sobrien	u32 dataphase		[  2];
148553790Sobrien	u32 msg_in		[  2];
148653790Sobrien	u32 msg_in2		[ 10];
148754690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
148853790Sobrien	u32 status		[ 14];
148953790Sobrien#else
149053790Sobrien	u32 status		[ 10];
149153790Sobrien#endif
149253790Sobrien	u32 complete		[  8];
149353790Sobrien	u32 complete2		[ 12];
149453790Sobrien	u32 complete_error	[  4];
149553790Sobrien	u32 done		[ 14];
149653790Sobrien	u32 done_end		[  2];
149753790Sobrien	u32 save_dp		[  8];
149853790Sobrien	u32 restore_dp		[  4];
149953790Sobrien	u32 disconnect		[ 20];
150054690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
150153790Sobrien	u32 idle		[  4];
150253790Sobrien#else
150353790Sobrien	u32 idle		[  2];
150453790Sobrien#endif
150554690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
150653790Sobrien	u32 ungetjob		[  6];
150753790Sobrien#else
150853790Sobrien	u32 ungetjob		[  4];
150953790Sobrien#endif
151053790Sobrien	u32 reselect		[  4];
151153790Sobrien	u32 reselected		[ 20];
151253790Sobrien	u32 resel_scntl4	[ 28];
151354690Sobrien#if   SYM_CONF_MAX_TASK*4 > 512
151453790Sobrien	u32 resel_tag		[ 24];
151554690Sobrien#elif SYM_CONF_MAX_TASK*4 > 256
151653790Sobrien	u32 resel_tag		[ 18];
151753790Sobrien#else
151853790Sobrien	u32 resel_tag		[ 14];
151953790Sobrien#endif
152053790Sobrien	u32 resel_dsa		[  2];
152153790Sobrien	u32 resel_dsa1		[  6];
152253790Sobrien	u32 resel_no_tag	[  8];
152354690Sobrien	u32 data_in		[SYM_CONF_MAX_SG * 2];
152453790Sobrien	u32 data_in2		[  4];
152554690Sobrien	u32 data_out		[SYM_CONF_MAX_SG * 2];
152653790Sobrien	u32 data_out2		[  4];
152754690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
152853790Sobrien	u32 pm0_data		[ 28];
152953790Sobrien	u32 pm1_data		[ 28];
153053790Sobrien#else
153153790Sobrien	u32 pm0_data		[ 16];
153253790Sobrien	u32 pm1_data		[ 16];
153353790Sobrien#endif
153453790Sobrien};
153553790Sobrien
153653790Sobrien/*
153753790Sobrien *  Script fragments which stay in main memory for all chips
153853790Sobrien *  except for chips that support 8K on-chip RAM.
153953790Sobrien */
154053790Sobrienstruct sym_scrh {
154153790Sobrien	u32 start64		[  2];
154253790Sobrien	u32 sel_for_abort	[ 18];
154353790Sobrien	u32 sel_for_abort_1	[  2];
154453790Sobrien	u32 select_no_atn	[  8];
154553790Sobrien	u32 wf_sel_done_no_atn	[  4];
154653790Sobrien
154753790Sobrien	u32 msg_in_etc		[ 14];
154853790Sobrien	u32 msg_received	[  4];
154953790Sobrien	u32 msg_weird_seen	[  4];
155053790Sobrien	u32 msg_extended	[ 20];
155153790Sobrien	u32 msg_bad		[  6];
155253790Sobrien	u32 msg_weird		[  4];
155353790Sobrien	u32 msg_weird1		[  8];
155453790Sobrien
155553790Sobrien	u32 wdtr_resp		[  6];
155653790Sobrien	u32 send_wdtr		[  4];
155753790Sobrien	u32 sdtr_resp		[  6];
155853790Sobrien	u32 send_sdtr		[  4];
155953790Sobrien	u32 ppr_resp		[  6];
156053790Sobrien	u32 send_ppr		[  4];
156153790Sobrien	u32 nego_bad_phase	[  4];
156253790Sobrien	u32 msg_out		[  4];
156353790Sobrien	u32 msg_out_done	[  4];
156454690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
156553790Sobrien	u32 no_data		[ 36];
156653790Sobrien#else
156753790Sobrien	u32 no_data		[ 28];
156853790Sobrien#endif
156953790Sobrien	u32 abort_resel		[ 16];
157053790Sobrien	u32 resend_ident	[  4];
157153790Sobrien	u32 ident_break		[  4];
157253790Sobrien	u32 ident_break_atn	[  4];
157354690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
157453790Sobrien	u32 sdata_in		[ 12];
157553790Sobrien#else
157653790Sobrien	u32 sdata_in		[  6];
157753790Sobrien#endif
157853790Sobrien	u32 resel_bad_lun	[  4];
157953790Sobrien	u32 bad_i_t_l		[  4];
158053790Sobrien	u32 bad_i_t_l_q		[  4];
158153790Sobrien	u32 bad_status		[  6];
158253790Sobrien	u32 pm_handle		[ 20];
158353790Sobrien	u32 pm_handle1		[  4];
158453790Sobrien	u32 pm_save		[  4];
158553790Sobrien	u32 pm0_save		[ 14];
158653790Sobrien	u32 pm1_save		[ 14];
158753790Sobrien
158853790Sobrien	/* SWIDE handling */
158953790Sobrien	u32 swide_ma_32		[  4];
159053790Sobrien	u32 swide_ma_64		[  6];
159153790Sobrien	u32 swide_scr_64	[ 26];
159253790Sobrien	u32 swide_scr_64_1	[ 12];
159353790Sobrien	u32 swide_com_64	[  6];
159453790Sobrien	u32 swide_common	[ 10];
159553790Sobrien	u32 swide_fin_32	[ 24];
159653790Sobrien
159754690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
159854690Sobrien	u32 dt_data_in		[SYM_CONF_MAX_SG * 2];
159953790Sobrien	u32 dt_data_in2		[  4];
160054690Sobrien	u32 dt_data_out		[SYM_CONF_MAX_SG * 2];
160153790Sobrien	u32 dt_data_out2	[  4];
160253790Sobrien#endif
160353790Sobrien
160453790Sobrien	/* Data area */
160553790Sobrien	u32 zero		[  1];
160653790Sobrien	u32 scratch		[  1];
160753790Sobrien	u32 scratch1		[  1];
160853790Sobrien	u32 pm0_data_addr	[  1];
160953790Sobrien	u32 pm1_data_addr	[  1];
161053790Sobrien	u32 saved_dsa		[  1];
161153790Sobrien	u32 saved_drs		[  1];
161253790Sobrien	u32 done_pos		[  1];
161353790Sobrien	u32 startpos		[  1];
161453790Sobrien	u32 targtbl		[  1];
161553790Sobrien	/* End of data area */
161653790Sobrien
161753790Sobrien	u32 snooptest		[  6];
161853790Sobrien	u32 snoopend		[  2];
161953790Sobrien};
162053790Sobrien
162153790Sobrien/*
162253790Sobrien *  Function prototypes.
162353790Sobrien */
162453790Sobrienstatic void sym_fill_scripts (script_p scr, scripth_p scrh);
162553790Sobrienstatic void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len);
162653796Sobrienstatic void sym_save_initial_setting (hcb_p np);
162753790Sobrienstatic int  sym_prepare_setting (hcb_p np, struct sym_nvram *nvram);
162853790Sobrienstatic int  sym_prepare_nego (hcb_p np, ccb_p cp, int nego, u_char *msgptr);
162953790Sobrienstatic void sym_put_start_queue (hcb_p np, ccb_p cp);
163053796Sobrienstatic void sym_chip_reset (hcb_p np);
163153790Sobrienstatic void sym_soft_reset (hcb_p np);
163253790Sobrienstatic void sym_start_reset (hcb_p np);
163353790Sobrienstatic int  sym_reset_scsi_bus (hcb_p np, int enab_int);
163453790Sobrienstatic int  sym_wakeup_done (hcb_p np);
163553790Sobrienstatic void sym_flush_busy_queue (hcb_p np, int cam_status);
163653790Sobrienstatic void sym_flush_comp_queue (hcb_p np, int cam_status);
163755300Sgroudierstatic void sym_init (hcb_p np, int reason);
163853790Sobrienstatic int  sym_getsync(hcb_p np, u_char dt, u_char sfac, u_char *divp,
163953790Sobrien		        u_char *fakp);
164053790Sobrienstatic void sym_setsync (hcb_p np, ccb_p cp, u_char ofs, u_char per,
164153790Sobrien			 u_char div, u_char fak);
164253790Sobrienstatic void sym_setwide (hcb_p np, ccb_p cp, u_char wide);
164353790Sobrienstatic void sym_setpprot(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
164453790Sobrien			 u_char per, u_char wide, u_char div, u_char fak);
164553790Sobrienstatic void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
164653790Sobrien			 u_char per, u_char wide, u_char div, u_char fak);
164753790Sobrienstatic void sym_log_hard_error (hcb_p np, u_short sist, u_char dstat);
164853790Sobrienstatic void sym_intr (void *arg);
164953790Sobrienstatic void sym_poll (struct cam_sim *sim);
165053790Sobrienstatic void sym_recover_scsi_int (hcb_p np, u_char hsts);
165153790Sobrienstatic void sym_int_sto (hcb_p np);
165253790Sobrienstatic void sym_int_udc (hcb_p np);
165353790Sobrienstatic void sym_int_sbmc (hcb_p np);
165453790Sobrienstatic void sym_int_par (hcb_p np, u_short sist);
165553790Sobrienstatic void sym_int_ma (hcb_p np);
165653790Sobrienstatic int  sym_dequeue_from_squeue(hcb_p np, int i, int target, int lun,
165753790Sobrien				    int task);
165853790Sobrienstatic void sym_sir_bad_scsi_status (hcb_p np, int num, ccb_p cp);
165953790Sobrienstatic int  sym_clear_tasks (hcb_p np, int status, int targ, int lun, int task);
166053790Sobrienstatic void sym_sir_task_recovery (hcb_p np, int num);
166153790Sobrienstatic int  sym_evaluate_dp (hcb_p np, ccb_p cp, u32 scr, int *ofs);
166253790Sobrienstatic void sym_modify_dp (hcb_p np, tcb_p tp, ccb_p cp, int ofs);
166353790Sobrienstatic int  sym_compute_residual (hcb_p np, ccb_p cp);
166453790Sobrienstatic int  sym_show_msg (u_char * msg);
166553790Sobrienstatic void sym_print_msg (ccb_p cp, char *label, u_char *msg);
166653790Sobrienstatic void sym_sync_nego (hcb_p np, tcb_p tp, ccb_p cp);
166753790Sobrienstatic void sym_ppr_nego (hcb_p np, tcb_p tp, ccb_p cp);
166853790Sobrienstatic void sym_wide_nego (hcb_p np, tcb_p tp, ccb_p cp);
166953790Sobrienstatic void sym_nego_default (hcb_p np, tcb_p tp, ccb_p cp);
167053790Sobrienstatic void sym_nego_rejected (hcb_p np, tcb_p tp, ccb_p cp);
167153790Sobrienstatic void sym_int_sir (hcb_p np);
167253790Sobrienstatic void sym_free_ccb (hcb_p np, ccb_p cp);
167353790Sobrienstatic ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order);
167453790Sobrienstatic ccb_p sym_alloc_ccb (hcb_p np);
167553790Sobrienstatic ccb_p sym_ccb_from_dsa (hcb_p np, u_long dsa);
167653790Sobrienstatic lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln);
167753790Sobrienstatic void sym_alloc_lcb_tags (hcb_p np, u_char tn, u_char ln);
167853790Sobrienstatic int  sym_snooptest (hcb_p np);
167953790Sobrienstatic void sym_selectclock(hcb_p np, u_char scntl3);
168053790Sobrienstatic void sym_getclock (hcb_p np, int mult);
168153790Sobrienstatic int  sym_getpciclock (hcb_p np);
168253790Sobrienstatic void sym_complete_ok (hcb_p np, ccb_p cp);
168353790Sobrienstatic void sym_complete_error (hcb_p np, ccb_p cp);
168453790Sobrienstatic void sym_timeout (void *arg);
168553790Sobrienstatic int  sym_abort_scsiio (hcb_p np, union ccb *ccb, int timed_out);
168653790Sobrienstatic void sym_reset_dev (hcb_p np, union ccb *ccb);
168753790Sobrienstatic void sym_action (struct cam_sim *sim, union ccb *ccb);
168853790Sobrienstatic void sym_action1 (struct cam_sim *sim, union ccb *ccb);
168953790Sobrienstatic int  sym_setup_cdb (hcb_p np, struct ccb_scsiio *csio, ccb_p cp);
169053790Sobrienstatic int  sym_setup_data(hcb_p np, struct ccb_scsiio *csio, ccb_p cp);
169153790Sobrienstatic int  sym_scatter_virtual (hcb_p np, ccb_p cp, vm_offset_t vaddr,
169253790Sobrien				 vm_size_t len);
169353790Sobrienstatic int  sym_scatter_physical (hcb_p np, ccb_p cp, vm_offset_t vaddr,
169453790Sobrien				 vm_size_t len);
169553790Sobrienstatic void sym_action2 (struct cam_sim *sim, union ccb *ccb);
169653790Sobrienstatic void sym_update_trans (hcb_p np, tcb_p tp, struct sym_trans *tip,
169753790Sobrien			      struct ccb_trans_settings *cts);
169853790Sobrienstatic void sym_update_dflags(hcb_p np, u_char *flags,
169953790Sobrien			      struct ccb_trans_settings *cts);
170053790Sobrien
170153790Sobrien#ifdef FreeBSD_4_Bus
170253790Sobrienstatic struct sym_pci_chip *sym_find_pci_chip (device_t dev);
170353790Sobrienstatic int  sym_pci_probe (device_t dev);
170453790Sobrienstatic int  sym_pci_attach (device_t dev);
170553790Sobrien#else
170653790Sobrienstatic struct sym_pci_chip *sym_find_pci_chip (pcici_t tag);
170753790Sobrienstatic const char *sym_pci_probe (pcici_t tag, pcidi_t type);
170853790Sobrienstatic void sym_pci_attach (pcici_t tag, int unit);
170953790Sobrienstatic int sym_pci_attach2 (pcici_t tag, int unit);
171053790Sobrien#endif
171153790Sobrien
171253790Sobrienstatic void sym_pci_free (hcb_p np);
171353790Sobrienstatic int  sym_cam_attach (hcb_p np);
171453790Sobrienstatic void sym_cam_free (hcb_p np);
171553790Sobrien
171653790Sobrienstatic void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram);
171753790Sobrienstatic void sym_nvram_setup_target (hcb_p np, int targ, struct sym_nvram *nvp);
171853790Sobrienstatic int sym_read_nvram (hcb_p np, struct sym_nvram *nvp);
171953790Sobrien
172053790Sobrien/*
172153790Sobrien *  Return the name of the controller.
172253790Sobrien */
172353790Sobrienstatic __inline char *sym_name(hcb_p np)
172453790Sobrien{
172553790Sobrien	return np->inst_name;
172653790Sobrien}
172753790Sobrien
172853790Sobrien/*
172953790Sobrien *  Scripts for SYMBIOS-Processor
173053790Sobrien *
173153790Sobrien *  Use sym_bind_script for binding to physical addresses.
173253790Sobrien *
173353790Sobrien *  NADDR generates a reference to a field of the controller data.
173453790Sobrien *  PADDR generates a reference to another part of the script.
173553790Sobrien *  RADDR generates a reference to a script processor register.
173653790Sobrien *  FADDR generates a reference to a script processor register
173753790Sobrien *        with offset.
173853790Sobrien *
173953790Sobrien */
174053790Sobrien#define	RELOC_SOFTC	0x40000000
174153790Sobrien#define	RELOC_LABEL	0x50000000
174253790Sobrien#define	RELOC_REGISTER	0x60000000
174353790Sobrien#if 0
174453790Sobrien#define	RELOC_KVAR	0x70000000
174553790Sobrien#endif
174653790Sobrien#define	RELOC_LABELH	0x80000000
174753790Sobrien#define	RELOC_MASK	0xf0000000
174853790Sobrien
174953790Sobrien#define	NADDR(label)	(RELOC_SOFTC  | offsetof(struct sym_hcb, label))
175053790Sobrien#define PADDR(label)    (RELOC_LABEL  | offsetof(struct sym_scr, label))
175153790Sobrien#define PADDRH(label)   (RELOC_LABELH | offsetof(struct sym_scrh, label))
175253790Sobrien#define	RADDR(label)	(RELOC_REGISTER | REG(label))
175353790Sobrien#define	FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs)))
175453790Sobrien#define	KVAR(which)	(RELOC_KVAR | (which))
175553790Sobrien
175653790Sobrien#define SCR_DATA_ZERO	0xf00ff00f
175753790Sobrien
175853790Sobrien#ifdef	RELOC_KVAR
175953790Sobrien#define	SCRIPT_KVAR_JIFFIES	(0)
176053790Sobrien#define	SCRIPT_KVAR_FIRST	SCRIPT_KVAR_XXXXXXX
176153790Sobrien#define	SCRIPT_KVAR_LAST	SCRIPT_KVAR_XXXXXXX
176253790Sobrien/*
176353790Sobrien * Kernel variables referenced in the scripts.
176453790Sobrien * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
176553790Sobrien */
176653790Sobrienstatic void *script_kvars[] =
176753790Sobrien	{ (void *)&xxxxxxx };
176853790Sobrien#endif
176953790Sobrien
177053790Sobrienstatic struct sym_scr script0 = {
177153790Sobrien/*--------------------------< START >-----------------------*/ {
177253790Sobrien	/*
177353790Sobrien	 *  This NOP will be patched with LED ON
177453790Sobrien	 *  SCR_REG_REG (gpreg, SCR_AND, 0xfe)
177553790Sobrien	 */
177653790Sobrien	SCR_NO_OP,
177753790Sobrien		0,
177853790Sobrien	/*
177953790Sobrien	 *      Clear SIGP.
178053790Sobrien	 */
178153790Sobrien	SCR_FROM_REG (ctest2),
178253790Sobrien		0,
178353790Sobrien	/*
178453790Sobrien	 *  Stop here if the C code wants to perform
178553790Sobrien	 *  some error recovery procedure manually.
178653790Sobrien	 *  (Indicate this by setting SEM in ISTAT)
178753790Sobrien	 */
178853790Sobrien	SCR_FROM_REG (istat),
178953790Sobrien		0,
179053790Sobrien	/*
179153790Sobrien	 *  Report to the C code the next position in
179253790Sobrien	 *  the start queue the SCRIPTS will schedule.
179353790Sobrien	 *  The C code must not change SCRATCHA.
179453790Sobrien	 */
179553790Sobrien	SCR_LOAD_ABS (scratcha, 4),
179653790Sobrien		PADDRH (startpos),
179753790Sobrien	SCR_INT ^ IFTRUE (MASK (SEM, SEM)),
179853790Sobrien		SIR_SCRIPT_STOPPED,
179953790Sobrien	/*
180053790Sobrien	 *  Start the next job.
180153790Sobrien	 *
180253790Sobrien	 *  @DSA	 = start point for this job.
180353790Sobrien	 *  SCRATCHA = address of this job in the start queue.
180453790Sobrien	 *
180553790Sobrien	 *  We will restore startpos with SCRATCHA if we fails the
180653790Sobrien	 *  arbitration or if it is the idle job.
180753790Sobrien	 *
180853790Sobrien	 *  The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS
180953790Sobrien	 *  is a critical path. If it is partially executed, it then
181053790Sobrien	 *  may happen that the job address is not yet in the DSA
181153790Sobrien	 *  and the the next queue position points to the next JOB.
181253790Sobrien	 */
181353790Sobrien	SCR_LOAD_ABS (dsa, 4),
181453790Sobrien		PADDRH (startpos),
181553790Sobrien	SCR_LOAD_REL (temp, 4),
181653790Sobrien		4,
181753790Sobrien}/*-------------------------< GETJOB_BEGIN >------------------*/,{
181853790Sobrien	SCR_STORE_ABS (temp, 4),
181953790Sobrien		PADDRH (startpos),
182053790Sobrien	SCR_LOAD_REL (dsa, 4),
182153790Sobrien		0,
182253790Sobrien}/*-------------------------< GETJOB_END >--------------------*/,{
182353790Sobrien	SCR_LOAD_REL (temp, 4),
182453790Sobrien		0,
182553790Sobrien	SCR_RETURN,
182653790Sobrien		0,
182753790Sobrien}/*-------------------------< SELECT >----------------------*/,{
182853790Sobrien	/*
182953790Sobrien	 *  DSA	contains the address of a scheduled
183053790Sobrien	 *  	data structure.
183153790Sobrien	 *
183253790Sobrien	 *  SCRATCHA contains the address of the start queue
183353790Sobrien	 *  	entry which points to the next job.
183453790Sobrien	 *
183553790Sobrien	 *  Set Initiator mode.
183653790Sobrien	 *
183753790Sobrien	 *  (Target mode is left as an exercise for the reader)
183853790Sobrien	 */
183953790Sobrien	SCR_CLR (SCR_TRG),
184053790Sobrien		0,
184153790Sobrien	/*
184253790Sobrien	 *      And try to select this target.
184353790Sobrien	 */
184453790Sobrien	SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
184553790Sobrien		PADDR (ungetjob),
184653790Sobrien	/*
184753790Sobrien	 *  Now there are 4 possibilities:
184853790Sobrien	 *
184953790Sobrien	 *  (1) The chip looses arbitration.
185053790Sobrien	 *  This is ok, because it will try again,
185153790Sobrien	 *  when the bus becomes idle.
185253790Sobrien	 *  (But beware of the timeout function!)
185353790Sobrien	 *
185453790Sobrien	 *  (2) The chip is reselected.
185553790Sobrien	 *  Then the script processor takes the jump
185653790Sobrien	 *  to the RESELECT label.
185753790Sobrien	 *
185853790Sobrien	 *  (3) The chip wins arbitration.
185953790Sobrien	 *  Then it will execute SCRIPTS instruction until
186053790Sobrien	 *  the next instruction that checks SCSI phase.
186153790Sobrien	 *  Then will stop and wait for selection to be
186253790Sobrien	 *  complete or selection time-out to occur.
186353790Sobrien	 *
186453790Sobrien	 *  After having won arbitration, the SCRIPTS
186553790Sobrien	 *  processor is able to execute instructions while
186653790Sobrien	 *  the SCSI core is performing SCSI selection.
186753790Sobrien	 */
186853790Sobrien	/*
186953790Sobrien	 *      load the savep (saved data pointer) into
187053790Sobrien	 *      the actual data pointer.
187153790Sobrien	 */
187253790Sobrien	SCR_LOAD_REL (temp, 4),
187353790Sobrien		offsetof (struct sym_ccb, phys.savep),
187453790Sobrien	/*
187553790Sobrien	 *      Initialize the status registers
187653790Sobrien	 */
187753790Sobrien	SCR_LOAD_REL (scr0, 4),
187853790Sobrien		offsetof (struct sym_ccb, phys.status),
187953790Sobrien}/*-------------------------< WF_SEL_DONE >----------------------*/,{
188053790Sobrien	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
188153790Sobrien		SIR_SEL_ATN_NO_MSG_OUT,
188253790Sobrien}/*-------------------------< SEND_IDENT >----------------------*/,{
188353790Sobrien	/*
188453790Sobrien	 *  Selection complete.
188553790Sobrien	 *  Send the IDENTIFY and possibly the TAG message
188653790Sobrien	 *  and negotiation message if present.
188753790Sobrien	 */
188853790Sobrien	SCR_MOVE_TBL ^ SCR_MSG_OUT,
188953790Sobrien		offsetof (struct dsb, smsg),
189053790Sobrien}/*-------------------------< SELECT2 >----------------------*/,{
189154690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
189253790Sobrien	/*
189353790Sobrien	 *  Set IMMEDIATE ARBITRATION if we have been given
189453790Sobrien	 *  a hint to do so. (Some job to do after this one).
189553790Sobrien	 */
189653790Sobrien	SCR_FROM_REG (HF_REG),
189753790Sobrien		0,
189853790Sobrien	SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
189953790Sobrien		8,
190053790Sobrien	SCR_REG_REG (scntl1, SCR_OR, IARB),
190153790Sobrien		0,
190253790Sobrien#endif
190353790Sobrien	/*
190453790Sobrien	 *  Anticipate the COMMAND phase.
190553790Sobrien	 *  This is the PHASE we expect at this point.
190653790Sobrien	 */
190753790Sobrien	SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
190853790Sobrien		PADDR (sel_no_cmd),
190953790Sobrien}/*-------------------------< COMMAND >--------------------*/,{
191053790Sobrien	/*
191153790Sobrien	 *  ... and send the command
191253790Sobrien	 */
191353790Sobrien	SCR_MOVE_TBL ^ SCR_COMMAND,
191453790Sobrien		offsetof (struct dsb, cmd),
191553790Sobrien}/*-----------------------< DISPATCH >----------------------*/,{
191653790Sobrien	/*
191753790Sobrien	 *  MSG_IN is the only phase that shall be
191853790Sobrien	 *  entered at least once for each (re)selection.
191953790Sobrien	 *  So we test it first.
192053790Sobrien	 */
192153790Sobrien	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
192253790Sobrien		PADDR (msg_in),
192353790Sobrien	SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)),
192453790Sobrien		PADDR (dataphase),
192553790Sobrien	SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)),
192653790Sobrien		PADDR (dataphase),
192753790Sobrien	SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
192853790Sobrien		PADDR (status),
192953790Sobrien	SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
193053790Sobrien		PADDR (command),
193153790Sobrien	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
193253790Sobrien		PADDRH (msg_out),
193353790Sobrien
193454690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
193553790Sobrien	SCR_JUMP ^ IFTRUE (IF (SCR_DT_DATA_OUT)),
193653790Sobrien		PADDR (dataphase),
193753790Sobrien	SCR_JUMP ^ IFTRUE (IF (SCR_DT_DATA_IN)),
193853790Sobrien		PADDR (dataphase),
193953790Sobrien#else
194053790Sobrien	/*
194153790Sobrien	 *  Set the extended error flag.
194253790Sobrien	 */
194353790Sobrien	SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR),
194453790Sobrien		0,
194553790Sobrien	/*
194653790Sobrien	 *  Discard one illegal phase byte, if required.
194753790Sobrien	 */
194853790Sobrien	SCR_LOAD_REL (scratcha, 1),
194953790Sobrien		offsetof (struct sym_ccb, xerr_status),
195053790Sobrien	SCR_REG_REG (scratcha,  SCR_OR,  XE_BAD_PHASE),
195153790Sobrien		0,
195253790Sobrien	SCR_STORE_REL (scratcha, 1),
195353790Sobrien		offsetof (struct sym_ccb, xerr_status),
195453790Sobrien	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)),
195553790Sobrien		8,
195653790Sobrien	SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
195753790Sobrien		NADDR (scratch),
195853790Sobrien	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)),
195953790Sobrien		8,
196053790Sobrien	SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
196153790Sobrien		NADDR (scratch),
196254690Sobrien#endif	/* SYM_CONF_BROKEN_U3EN_SUPPORT */
196353790Sobrien
196453790Sobrien	SCR_JUMP,
196553790Sobrien		PADDR (dispatch),
196653790Sobrien}/*---------------------< SEL_NO_CMD >----------------------*/,{
196753790Sobrien	/*
196853790Sobrien	 *  The target does not switch to command
196953790Sobrien	 *  phase after IDENTIFY has been sent.
197053790Sobrien	 *
197153790Sobrien	 *  If it stays in MSG OUT phase send it
197253790Sobrien	 *  the IDENTIFY again.
197353790Sobrien	 */
197453790Sobrien	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
197553790Sobrien		PADDRH (resend_ident),
197653790Sobrien	/*
197753790Sobrien	 *  If target does not switch to MSG IN phase
197853790Sobrien	 *  and we sent a negotiation, assert the
197953790Sobrien	 *  failure immediately.
198053790Sobrien	 */
198153790Sobrien	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
198253790Sobrien		PADDR (dispatch),
198353790Sobrien	SCR_FROM_REG (HS_REG),
198453790Sobrien		0,
198553790Sobrien	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
198653790Sobrien		SIR_NEGO_FAILED,
198753790Sobrien	/*
198853790Sobrien	 *  Jump to dispatcher.
198953790Sobrien	 */
199053790Sobrien	SCR_JUMP,
199153790Sobrien		PADDR (dispatch),
199253790Sobrien}/*-------------------------< INIT >------------------------*/,{
199353790Sobrien	/*
199453790Sobrien	 *  Wait for the SCSI RESET signal to be
199553790Sobrien	 *  inactive before restarting operations,
199653790Sobrien	 *  since the chip may hang on SEL_ATN
199753790Sobrien	 *  if SCSI RESET is active.
199853790Sobrien	 */
199953790Sobrien	SCR_FROM_REG (sstat0),
200053790Sobrien		0,
200153790Sobrien	SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
200253790Sobrien		-16,
200353790Sobrien	SCR_JUMP,
200453790Sobrien		PADDR (start),
200553790Sobrien}/*-------------------------< CLRACK >----------------------*/,{
200653790Sobrien	/*
200753790Sobrien	 *  Terminate possible pending message phase.
200853790Sobrien	 */
200953790Sobrien	SCR_CLR (SCR_ACK),
201053790Sobrien		0,
201153790Sobrien	SCR_JUMP,
201253790Sobrien		PADDR (dispatch),
201353790Sobrien}/*-------------------------< DISP_MSG_IN >----------------------*/,{
201453790Sobrien	/*
201553790Sobrien	 *  Anticipate MSG_IN phase then STATUS phase.
201653790Sobrien	 *
201753790Sobrien	 *  May spare 2 SCRIPTS instructions when we have
201853790Sobrien	 *  completed the OUTPUT of the data and the device
201953790Sobrien	 *  goes directly to STATUS phase.
202053790Sobrien	 */
202153790Sobrien	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
202253790Sobrien		PADDR (msg_in),
202353790Sobrien}/*-------------------------< DISP_STATUS >----------------------*/,{
202453790Sobrien	/*
202553790Sobrien	 *  Anticipate STATUS phase.
202653790Sobrien	 *
202753790Sobrien	 *  Does spare 3 SCRIPTS instructions when we have
202853790Sobrien	 *  completed the INPUT of the data.
202953790Sobrien	 */
203053790Sobrien	SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
203153790Sobrien		PADDR (status),
203253790Sobrien	SCR_JUMP,
203353790Sobrien		PADDR (dispatch),
203453790Sobrien}/*-------------------------< DATAI_DONE >-------------------*/,{
203553790Sobrien	/*
203653790Sobrien	 *  If the SWIDE is not full, jump to dispatcher.
203753790Sobrien	 *  We anticipate a STATUS phase.
203853790Sobrien	 *  If we get later an IGNORE WIDE RESIDUE, we
203953790Sobrien	 *  will alias it as a MODIFY DP (-1).
204053790Sobrien	 */
204153790Sobrien	SCR_FROM_REG (scntl2),
204253790Sobrien		0,
204353790Sobrien	SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
204453790Sobrien		PADDR (disp_status),
204553790Sobrien	/*
204653790Sobrien	 *  The SWIDE is full.
204753790Sobrien	 *  Clear this condition.
204853790Sobrien	 */
204953790Sobrien	SCR_REG_REG (scntl2, SCR_OR, WSR),
205053790Sobrien		0,
205153790Sobrien	/*
205253790Sobrien	 *  Since the device is required to send any
205353790Sobrien	 *  IGNORE WIDE RESIDUE message prior to any
205453790Sobrien	 *  other information, we just snoop the SCSI
205553790Sobrien	 *  BUS to check for such a message.
205653790Sobrien	 */
205753790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
205853790Sobrien		16,
205953790Sobrien	SCR_FROM_REG (sbdl),
206053790Sobrien		0,
206153790Sobrien	SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
206253790Sobrien		PADDR (disp_msg_in),
206353790Sobrien	/*
206453790Sobrien	 *  We have been ODD at the end of the transfer,
206553790Sobrien	 *  but the device hasn't be so.
206653790Sobrien	 *  Signal a DATA OVERRUN condition to the C code.
206753790Sobrien	 */
206853790Sobrien	SCR_INT,
206953790Sobrien		SIR_SWIDE_OVERRUN,
207053790Sobrien	SCR_JUMP,
207153790Sobrien		PADDR (dispatch),
207253790Sobrien}/*-------------------------< DATAO_DONE >-------------------*/,{
207353790Sobrien	/*
207453790Sobrien	 *  If the SODL is not full jump to dispatcher.
207553790Sobrien	 *  We anticipate a MSG IN phase or a STATUS phase.
207653790Sobrien	 */
207753790Sobrien	SCR_FROM_REG (scntl2),
207853790Sobrien		0,
207953790Sobrien	SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
208053790Sobrien		PADDR (disp_status),
208153790Sobrien	/*
208253790Sobrien	 *  The SODL is full, clear this condition.
208353790Sobrien	 */
208453790Sobrien	SCR_REG_REG (scntl2, SCR_OR, WSS),
208553790Sobrien		0,
208653790Sobrien	/*
208753790Sobrien	 *  And signal a DATA UNDERRUN condition
208853790Sobrien	 *  to the C code.
208953790Sobrien	 */
209053790Sobrien	SCR_INT,
209153790Sobrien		SIR_SODL_UNDERRUN,
209253790Sobrien	SCR_JUMP,
209353790Sobrien		PADDR (dispatch),
209453790Sobrien}/*-------------------------< IGN_I_W_R_MSG >--------------*/,{
209553790Sobrien	/*
209653790Sobrien	 *  We jump here from the phase mismatch interrupt,
209753790Sobrien	 *  When we have a SWIDE and the device has presented
209853790Sobrien	 *  a IGNORE WIDE RESIDUE message on the BUS.
209953790Sobrien	 *  We just have to throw away this message and then
210053790Sobrien	 *  to jump to dispatcher.
210153790Sobrien	 */
210253790Sobrien	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
210353790Sobrien		NADDR (scratch),
210453790Sobrien	/*
210553790Sobrien	 *  Clear ACK and jump to dispatcher.
210653790Sobrien	 */
210753790Sobrien	SCR_JUMP,
210853790Sobrien		PADDR (clrack),
210953790Sobrien}/*-------------------------< DATAPHASE >------------------*/,{
211053790Sobrien	SCR_RETURN,
211153790Sobrien 		0,
211253790Sobrien}/*-------------------------< MSG_IN >--------------------*/,{
211353790Sobrien	/*
211453790Sobrien	 *  Get the first byte of the message.
211553790Sobrien	 *
211653790Sobrien	 *  The script processor doesn't negate the
211753790Sobrien	 *  ACK signal after this transfer.
211853790Sobrien	 */
211953790Sobrien	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
212053790Sobrien		NADDR (msgin[0]),
212153790Sobrien}/*-------------------------< MSG_IN2 >--------------------*/,{
212253790Sobrien	/*
212353790Sobrien	 *  Check first against 1 byte messages
212453790Sobrien	 *  that we handle from SCRIPTS.
212553790Sobrien	 */
212653790Sobrien	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
212753790Sobrien		PADDR (complete),
212853790Sobrien	SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
212953790Sobrien		PADDR (disconnect),
213053790Sobrien	SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
213153790Sobrien		PADDR (save_dp),
213253790Sobrien	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
213353790Sobrien		PADDR (restore_dp),
213453790Sobrien	/*
213553790Sobrien	 *  We handle all other messages from the
213653790Sobrien	 *  C code, so no need to waste on-chip RAM
213753790Sobrien	 *  for those ones.
213853790Sobrien	 */
213953790Sobrien	SCR_JUMP,
214053790Sobrien		PADDRH (msg_in_etc),
214153790Sobrien}/*-------------------------< STATUS >--------------------*/,{
214253790Sobrien	/*
214353790Sobrien	 *  get the status
214453790Sobrien	 */
214553790Sobrien	SCR_MOVE_ABS (1) ^ SCR_STATUS,
214653790Sobrien		NADDR (scratch),
214754690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
214853790Sobrien	/*
214953790Sobrien	 *  If STATUS is not GOOD, clear IMMEDIATE ARBITRATION,
215053790Sobrien	 *  since we may have to tamper the start queue from
215153790Sobrien	 *  the C code.
215253790Sobrien	 */
215353790Sobrien	SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
215453790Sobrien		8,
215553790Sobrien	SCR_REG_REG (scntl1, SCR_AND, ~IARB),
215653790Sobrien		0,
215753790Sobrien#endif
215853790Sobrien	/*
215953790Sobrien	 *  save status to scsi_status.
216053790Sobrien	 *  mark as complete.
216153790Sobrien	 */
216253790Sobrien	SCR_TO_REG (SS_REG),
216353790Sobrien		0,
216453790Sobrien	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
216553790Sobrien		0,
216653790Sobrien	/*
216753790Sobrien	 *  Anticipate the MESSAGE PHASE for
216853790Sobrien	 *  the TASK COMPLETE message.
216953790Sobrien	 */
217053790Sobrien	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
217153790Sobrien		PADDR (msg_in),
217253790Sobrien	SCR_JUMP,
217353790Sobrien		PADDR (dispatch),
217453790Sobrien}/*-------------------------< COMPLETE >-----------------*/,{
217553790Sobrien	/*
217653790Sobrien	 *  Complete message.
217753790Sobrien	 *
217853790Sobrien	 *  Copy the data pointer to LASTP.
217953790Sobrien	 */
218053790Sobrien	SCR_STORE_REL (temp, 4),
218153790Sobrien		offsetof (struct sym_ccb, phys.lastp),
218253790Sobrien	/*
218353790Sobrien	 *  When we terminate the cycle by clearing ACK,
218453790Sobrien	 *  the target may disconnect immediately.
218553790Sobrien	 *
218653790Sobrien	 *  We don't want to be told of an "unexpected disconnect",
218753790Sobrien	 *  so we disable this feature.
218853790Sobrien	 */
218953790Sobrien	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
219053790Sobrien		0,
219153790Sobrien	/*
219253790Sobrien	 *  Terminate cycle ...
219353790Sobrien	 */
219453790Sobrien	SCR_CLR (SCR_ACK|SCR_ATN),
219553790Sobrien		0,
219653790Sobrien	/*
219753790Sobrien	 *  ... and wait for the disconnect.
219853790Sobrien	 */
219953790Sobrien	SCR_WAIT_DISC,
220053790Sobrien		0,
220153790Sobrien}/*-------------------------< COMPLETE2 >-----------------*/,{
220253790Sobrien	/*
220353790Sobrien	 *  Save host status.
220453790Sobrien	 */
220553790Sobrien	SCR_STORE_REL (scr0, 4),
220653790Sobrien		offsetof (struct sym_ccb, phys.status),
220753790Sobrien	/*
220853790Sobrien	 *  Some bridges may reorder DMA writes to memory.
220953790Sobrien	 *  We donnot want the CPU to deal with completions
221053790Sobrien	 *  without all the posted write having been flushed
221153790Sobrien	 *  to memory. This DUMMY READ should flush posted
221253790Sobrien	 *  buffers prior to the CPU having to deal with
221353790Sobrien	 *  completions.
221453790Sobrien	 */
221553790Sobrien	SCR_LOAD_REL (scr0, 4),	/* DUMMY READ */
221653790Sobrien		offsetof (struct sym_ccb, phys.status),
221753790Sobrien
221853790Sobrien	/*
221953790Sobrien	 *  If command resulted in not GOOD status,
222053790Sobrien	 *  call the C code if needed.
222153790Sobrien	 */
222253790Sobrien	SCR_FROM_REG (SS_REG),
222353790Sobrien		0,
222453790Sobrien	SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
222553790Sobrien		PADDRH (bad_status),
222653790Sobrien	/*
222753790Sobrien	 *  If we performed an auto-sense, call
222853790Sobrien	 *  the C code to synchronyze task aborts
222953790Sobrien	 *  with UNIT ATTENTION conditions.
223053790Sobrien	 */
223153790Sobrien	SCR_FROM_REG (HF_REG),
223253790Sobrien		0,
223353790Sobrien	SCR_JUMPR ^ IFTRUE (MASK (0 ,(HF_SENSE|HF_EXT_ERR))),
223453790Sobrien		16,
223553790Sobrien}/*-------------------------< COMPLETE_ERROR >-----------------*/,{
223653790Sobrien	SCR_LOAD_ABS (scratcha, 4),
223753790Sobrien		PADDRH (startpos),
223853790Sobrien	SCR_INT,
223953790Sobrien		SIR_COMPLETE_ERROR,
224053790Sobrien}/*------------------------< DONE >-----------------*/,{
224153790Sobrien	/*
224253790Sobrien	 *  Copy the DSA to the DONE QUEUE and
224353790Sobrien	 *  signal completion to the host.
224453790Sobrien	 *  If we are interrupted between DONE
224553790Sobrien	 *  and DONE_END, we must reset, otherwise
224653790Sobrien	 *  the completed CCB may be lost.
224753790Sobrien	 */
224853790Sobrien	SCR_STORE_ABS (dsa, 4),
224953790Sobrien		PADDRH (saved_dsa),
225053790Sobrien	SCR_LOAD_ABS (dsa, 4),
225153790Sobrien		PADDRH (done_pos),
225253790Sobrien	SCR_LOAD_ABS (scratcha, 4),
225353790Sobrien		PADDRH (saved_dsa),
225453790Sobrien	SCR_STORE_REL (scratcha, 4),
225553790Sobrien		0,
225653790Sobrien	/*
225753790Sobrien	 *  The instruction below reads the DONE QUEUE next
225853790Sobrien	 *  free position from memory.
225953790Sobrien	 *  In addition it ensures that all PCI posted writes
226053790Sobrien	 *  are flushed and so the DSA value of the done
226153790Sobrien	 *  CCB is visible by the CPU before INTFLY is raised.
226253790Sobrien	 */
226353790Sobrien	SCR_LOAD_REL (temp, 4),
226453790Sobrien		4,
226553790Sobrien	SCR_INT_FLY,
226653790Sobrien		0,
226753790Sobrien	SCR_STORE_ABS (temp, 4),
226853790Sobrien		PADDRH (done_pos),
226953790Sobrien}/*------------------------< DONE_END >-----------------*/,{
227053790Sobrien	SCR_JUMP,
227153790Sobrien		PADDR (start),
227253790Sobrien}/*-------------------------< SAVE_DP >------------------*/,{
227353790Sobrien	/*
227453790Sobrien	 *  Clear ACK immediately.
227553790Sobrien	 *  No need to delay it.
227653790Sobrien	 */
227753790Sobrien	SCR_CLR (SCR_ACK),
227853790Sobrien		0,
227953790Sobrien	/*
228053790Sobrien	 *  Keep track we received a SAVE DP, so
228153790Sobrien	 *  we will switch to the other PM context
228253790Sobrien	 *  on the next PM since the DP may point
228353790Sobrien	 *  to the current PM context.
228453790Sobrien	 */
228553790Sobrien	SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
228653790Sobrien		0,
228753790Sobrien	/*
228853790Sobrien	 *  SAVE_DP message:
228953790Sobrien	 *  Copy the data pointer to SAVEP.
229053790Sobrien	 */
229153790Sobrien	SCR_STORE_REL (temp, 4),
229253790Sobrien		offsetof (struct sym_ccb, phys.savep),
229353790Sobrien	SCR_JUMP,
229453790Sobrien		PADDR (dispatch),
229553790Sobrien}/*-------------------------< RESTORE_DP >---------------*/,{
229653790Sobrien	/*
229753790Sobrien	 *  RESTORE_DP message:
229853790Sobrien	 *  Copy SAVEP to actual data pointer.
229953790Sobrien	 */
230053790Sobrien	SCR_LOAD_REL  (temp, 4),
230153790Sobrien		offsetof (struct sym_ccb, phys.savep),
230253790Sobrien	SCR_JUMP,
230353790Sobrien		PADDR (clrack),
230453790Sobrien}/*-------------------------< DISCONNECT >---------------*/,{
230553790Sobrien	/*
230653790Sobrien	 *  DISCONNECTing  ...
230753790Sobrien	 *
230853790Sobrien	 *  disable the "unexpected disconnect" feature,
230953790Sobrien	 *  and remove the ACK signal.
231053790Sobrien	 */
231153790Sobrien	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
231253790Sobrien		0,
231353790Sobrien	SCR_CLR (SCR_ACK|SCR_ATN),
231453790Sobrien		0,
231553790Sobrien	/*
231653790Sobrien	 *  Wait for the disconnect.
231753790Sobrien	 */
231853790Sobrien	SCR_WAIT_DISC,
231953790Sobrien		0,
232053790Sobrien	/*
232153790Sobrien	 *  Status is: DISCONNECTED.
232253790Sobrien	 */
232353790Sobrien	SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
232453790Sobrien		0,
232553790Sobrien	/*
232653790Sobrien	 *  Save host status.
232753790Sobrien	 */
232853790Sobrien	SCR_STORE_REL (scr0, 4),
232953790Sobrien		offsetof (struct sym_ccb, phys.status),
233053790Sobrien	/*
233153790Sobrien	 *  If QUIRK_AUTOSAVE is set,
233253790Sobrien	 *  do an "save pointer" operation.
233353790Sobrien	 */
233453790Sobrien	SCR_FROM_REG (QU_REG),
233553790Sobrien		0,
233653790Sobrien	SCR_JUMP ^ IFFALSE (MASK (SYM_QUIRK_AUTOSAVE, SYM_QUIRK_AUTOSAVE)),
233753790Sobrien		PADDR (start),
233853790Sobrien	/*
233953790Sobrien	 *  like SAVE_DP message:
234053790Sobrien	 *  Remember we saved the data pointer.
234153790Sobrien	 *  Copy data pointer to SAVEP.
234253790Sobrien	 */
234353790Sobrien	SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
234453790Sobrien		0,
234553790Sobrien	SCR_STORE_REL (temp, 4),
234653790Sobrien		offsetof (struct sym_ccb, phys.savep),
234753790Sobrien	SCR_JUMP,
234853790Sobrien		PADDR (start),
234953790Sobrien}/*-------------------------< IDLE >------------------------*/,{
235053790Sobrien	/*
235153790Sobrien	 *  Nothing to do?
235253790Sobrien	 *  Wait for reselect.
235353790Sobrien	 *  This NOP will be patched with LED OFF
235453790Sobrien	 *  SCR_REG_REG (gpreg, SCR_OR, 0x01)
235553790Sobrien	 */
235653790Sobrien	SCR_NO_OP,
235753790Sobrien		0,
235854690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
235953790Sobrien	SCR_JUMPR,
236053790Sobrien		8,
236153790Sobrien#endif
236253790Sobrien}/*-------------------------< UNGETJOB >-----------------*/,{
236354690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
236453790Sobrien	/*
236553790Sobrien	 *  Set IMMEDIATE ARBITRATION, for the next time.
236653790Sobrien	 *  This will give us better chance to win arbitration
236753790Sobrien	 *  for the job we just wanted to do.
236853790Sobrien	 */
236953790Sobrien	SCR_REG_REG (scntl1, SCR_OR, IARB),
237053790Sobrien		0,
237153790Sobrien#endif
237253790Sobrien	/*
237353790Sobrien	 *  We are not able to restart the SCRIPTS if we are
237453790Sobrien	 *  interrupted and these instruction haven't been
237553790Sobrien	 *  all executed. BTW, this is very unlikely to
237653790Sobrien	 *  happen, but we check that from the C code.
237753790Sobrien	 */
237853790Sobrien	SCR_LOAD_REG (dsa, 0xff),
237953790Sobrien		0,
238053790Sobrien	SCR_STORE_ABS (scratcha, 4),
238153790Sobrien		PADDRH (startpos),
238253790Sobrien}/*-------------------------< RESELECT >--------------------*/,{
238353790Sobrien	/*
238453790Sobrien	 *  Make sure we are in initiator mode.
238553790Sobrien	 */
238653790Sobrien	SCR_CLR (SCR_TRG),
238753790Sobrien		0,
238853790Sobrien	/*
238953790Sobrien	 *  Sleep waiting for a reselection.
239053790Sobrien	 */
239153790Sobrien	SCR_WAIT_RESEL,
239253790Sobrien		PADDR(start),
239353790Sobrien}/*-------------------------< RESELECTED >------------------*/,{
239453790Sobrien	/*
239553790Sobrien	 *  This NOP will be patched with LED ON
239653790Sobrien	 *  SCR_REG_REG (gpreg, SCR_AND, 0xfe)
239753790Sobrien	 */
239853790Sobrien	SCR_NO_OP,
239953790Sobrien		0,
240053790Sobrien	/*
240153790Sobrien	 *  load the target id into the sdid
240253790Sobrien	 */
240353790Sobrien	SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
240453790Sobrien		0,
240553790Sobrien	SCR_TO_REG (sdid),
240653790Sobrien		0,
240753790Sobrien	/*
240853790Sobrien	 *  Load the target control block address
240953790Sobrien	 */
241053790Sobrien	SCR_LOAD_ABS (dsa, 4),
241153790Sobrien		PADDRH (targtbl),
241253790Sobrien	SCR_SFBR_REG (dsa, SCR_SHL, 0),
241353790Sobrien		0,
241453790Sobrien	SCR_REG_REG (dsa, SCR_SHL, 0),
241553790Sobrien		0,
241653790Sobrien	SCR_REG_REG (dsa, SCR_AND, 0x3c),
241753790Sobrien		0,
241853790Sobrien	SCR_LOAD_REL (dsa, 4),
241953790Sobrien		0,
242053790Sobrien	/*
242153790Sobrien	 *  Load the legacy synchronous transfer registers.
242253790Sobrien	 */
242353790Sobrien	SCR_LOAD_REL (scntl3, 1),
242453790Sobrien		offsetof(struct sym_tcb, wval),
242553790Sobrien	SCR_LOAD_REL (sxfer, 1),
242653790Sobrien		offsetof(struct sym_tcb, sval),
242753790Sobrien}/*-------------------------< RESEL_SCNTL4 >------------------*/,{
242853790Sobrien	/*
242953790Sobrien	 *  If C1010, patched with the load of SCNTL4 that
243053790Sobrien	 *  allows a new synchronous timing scheme.
243153790Sobrien	 *
243253790Sobrien	 *	SCR_LOAD_REL (scntl4, 1),
243353790Sobrien	 * 		offsetof(struct tcb, uval),
243453790Sobrien	 */
243553790Sobrien	SCR_NO_OP,
243653790Sobrien		0,
243753790Sobrien	/*
243853790Sobrien	 *  If MESSAGE IN phase as expected,
243953790Sobrien	 *  Read the data directly from the BUS DATA lines.
244053790Sobrien	 *  This helps to support very old SCSI devices that
244153790Sobrien	 *  may reselect without sending an IDENTIFY.
244253790Sobrien	 */
244353790Sobrien	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
244453790Sobrien		SIR_RESEL_NO_MSG_IN,
244553790Sobrien	SCR_FROM_REG (sbdl),
244653790Sobrien		0,
244753790Sobrien	/*
244853790Sobrien	 *  If message phase but not an IDENTIFY,
244953790Sobrien	 *  get some help from the C code.
245053790Sobrien	 *  Old SCSI device may behave so.
245153790Sobrien	 */
245253790Sobrien	SCR_INT ^ IFFALSE (MASK (0x80, 0x80)),
245353790Sobrien		SIR_RESEL_NO_IDENTIFY,
245453790Sobrien	/*
245553790Sobrien	 *  It is an IDENTIFY message,
245653790Sobrien	 *  Load the LUN control block address.
245753790Sobrien	 *  If LUN 0, avoid a PCI BUS ownership by loading
245853790Sobrien	 *  directly 'lun0_sa' from the TCB.
245953790Sobrien	 */
246053790Sobrien	SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
246153790Sobrien		48,
246253790Sobrien	SCR_LOAD_REL (dsa, 4),
246353790Sobrien		offsetof(struct sym_tcb, luntbl_sa),
246453790Sobrien	SCR_SFBR_REG (dsa, SCR_SHL, 0),
246553790Sobrien		0,
246653790Sobrien	SCR_REG_REG (dsa, SCR_SHL, 0),
246753790Sobrien		0,
246853790Sobrien	SCR_REG_REG (dsa, SCR_AND, 0xfc),
246953790Sobrien		0,
247053790Sobrien	SCR_LOAD_REL (dsa, 4),
247153790Sobrien		0,
247253790Sobrien	SCR_JUMPR,
247353790Sobrien		8,
247453790Sobrien	/*
247553790Sobrien	 *  LUN 0 special case (but usual one :))
247653790Sobrien	 */
247753790Sobrien	SCR_LOAD_REL (dsa, 4),
247853790Sobrien		offsetof(struct sym_tcb, lun0_sa),
247953790Sobrien	/*
248053790Sobrien	 *  Jump indirectly to the reselect action for this LUN.
248153790Sobrien	 */
248253790Sobrien	SCR_LOAD_REL (temp, 4),
248353790Sobrien		offsetof(struct sym_lcb, resel_sa),
248453790Sobrien	SCR_RETURN,
248553790Sobrien		0,
248653790Sobrien	/* In normal situations, we jump to RESEL_TAG or RESEL_NO_TAG */
248753790Sobrien}/*-------------------------< RESEL_TAG >-------------------*/,{
248853790Sobrien	/*
248953790Sobrien	 *  It shall be a tagged command.
249053790Sobrien	 *  Read IDENTIFY+SIMPLE+TAG.
249153790Sobrien	 *  The C code will deal with errors.
249253790Sobrien	 *  Agressive optimization, is'nt it? :)
249353790Sobrien	 */
249453790Sobrien	SCR_MOVE_ABS (3) ^ SCR_MSG_IN,
249553790Sobrien		NADDR (msgin),
249653790Sobrien	/*
249753790Sobrien	 *  Load the pointer to the tagged task
249853790Sobrien	 *  table for this LUN.
249953790Sobrien	 */
250053790Sobrien	SCR_LOAD_REL (dsa, 4),
250153790Sobrien		offsetof(struct sym_lcb, itlq_tbl_sa),
250253790Sobrien	/*
250353790Sobrien	 *  The SIDL still contains the TAG value.
250453790Sobrien	 *  Agressive optimization, isn't it? :):)
250553790Sobrien	 */
250653790Sobrien	SCR_REG_SFBR (sidl, SCR_SHL, 0),
250753790Sobrien		0,
250854690Sobrien#if SYM_CONF_MAX_TASK*4 > 512
250953790Sobrien	SCR_JUMPR ^ IFFALSE (CARRYSET),
251053790Sobrien		8,
251153790Sobrien	SCR_REG_REG (dsa1, SCR_OR, 2),
251253790Sobrien		0,
251353790Sobrien	SCR_REG_REG (sfbr, SCR_SHL, 0),
251453790Sobrien		0,
251553790Sobrien	SCR_JUMPR ^ IFFALSE (CARRYSET),
251653790Sobrien		8,
251753790Sobrien	SCR_REG_REG (dsa1, SCR_OR, 1),
251853790Sobrien		0,
251954690Sobrien#elif SYM_CONF_MAX_TASK*4 > 256
252053790Sobrien	SCR_JUMPR ^ IFFALSE (CARRYSET),
252153790Sobrien		8,
252253790Sobrien	SCR_REG_REG (dsa1, SCR_OR, 1),
252353790Sobrien		0,
252453790Sobrien#endif
252553790Sobrien	/*
252653790Sobrien	 *  Retrieve the DSA of this task.
252753790Sobrien	 *  JUMP indirectly to the restart point of the CCB.
252853790Sobrien	 */
252953790Sobrien	SCR_SFBR_REG (dsa, SCR_AND, 0xfc),
253053790Sobrien		0,
253153790Sobrien	SCR_LOAD_REL (dsa, 4),
253253790Sobrien		0,
253353790Sobrien	SCR_LOAD_REL (temp, 4),
253453790Sobrien		offsetof(struct sym_ccb, phys.go.restart),
253553790Sobrien	SCR_RETURN,
253653790Sobrien		0,
253753790Sobrien	/* In normal situations we branch to RESEL_DSA */
253853790Sobrien}/*-------------------------< RESEL_DSA >-------------------*/,{
253953790Sobrien	/*
254053790Sobrien	 *  ACK the IDENTIFY or TAG previously received.
254153790Sobrien	 */
254253790Sobrien	SCR_CLR (SCR_ACK),
254353790Sobrien		0,
254453790Sobrien}/*-------------------------< RESEL_DSA1 >------------------*/,{
254553790Sobrien	/*
254653790Sobrien	 *      load the savep (saved pointer) into
254753790Sobrien	 *      the actual data pointer.
254853790Sobrien	 */
254953790Sobrien	SCR_LOAD_REL (temp, 4),
255053790Sobrien		offsetof (struct sym_ccb, phys.savep),
255153790Sobrien	/*
255253790Sobrien	 *      Initialize the status registers
255353790Sobrien	 */
255453790Sobrien	SCR_LOAD_REL (scr0, 4),
255553790Sobrien		offsetof (struct sym_ccb, phys.status),
255653790Sobrien	/*
255753790Sobrien	 *  Jump to dispatcher.
255853790Sobrien	 */
255953790Sobrien	SCR_JUMP,
256053790Sobrien		PADDR (dispatch),
256153790Sobrien}/*-------------------------< RESEL_NO_TAG >-------------------*/,{
256253790Sobrien	/*
256353790Sobrien	 *  Throw away the IDENTIFY.
256453790Sobrien	 */
256553790Sobrien	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
256653790Sobrien		NADDR (msgin),
256753790Sobrien	/*
256853790Sobrien	 *  Load the DSA with the unique ITL task.
256953790Sobrien	 */
257053790Sobrien	SCR_LOAD_REL (dsa, 4),
257153790Sobrien		offsetof(struct sym_lcb, itl_task_sa),
257253790Sobrien	/*
257353790Sobrien	 *  JUMP indirectly to the restart point of the CCB.
257453790Sobrien	 */
257553790Sobrien	SCR_LOAD_REL (temp, 4),
257653790Sobrien		offsetof(struct sym_ccb, phys.go.restart),
257753790Sobrien	SCR_RETURN,
257853790Sobrien		0,
257953790Sobrien	/* In normal situations we branch to RESEL_DSA */
258053790Sobrien}/*-------------------------< DATA_IN >--------------------*/,{
258153790Sobrien/*
258253790Sobrien *  Because the size depends on the
258354690Sobrien *  #define SYM_CONF_MAX_SG parameter,
258453790Sobrien *  it is filled in at runtime.
258553790Sobrien *
258654690Sobrien *  ##===========< i=0; i<SYM_CONF_MAX_SG >=========
258753790Sobrien *  ||	SCR_CHMOV_TBL ^ SCR_DATA_IN,
258853790Sobrien *  ||		offsetof (struct dsb, data[ i]),
258953790Sobrien *  ##==========================================
259053790Sobrien */
259153790Sobrien0
259253790Sobrien}/*-------------------------< DATA_IN2 >-------------------*/,{
259353790Sobrien	SCR_CALL,
259453790Sobrien		PADDR (datai_done),
259553790Sobrien	SCR_JUMP,
259653790Sobrien		PADDRH (no_data),
259753790Sobrien}/*-------------------------< DATA_OUT >--------------------*/,{
259853790Sobrien/*
259953790Sobrien *  Because the size depends on the
260054690Sobrien *  #define SYM_CONF_MAX_SG parameter,
260153790Sobrien *  it is filled in at runtime.
260253790Sobrien *
260354690Sobrien *  ##===========< i=0; i<SYM_CONF_MAX_SG >=========
260453790Sobrien *  ||	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
260553790Sobrien *  ||		offsetof (struct dsb, data[ i]),
260653790Sobrien *  ##==========================================
260753790Sobrien */
260853790Sobrien0
260953790Sobrien}/*-------------------------< DATA_OUT2 >-------------------*/,{
261053790Sobrien	SCR_CALL,
261153790Sobrien		PADDR (datao_done),
261253790Sobrien	SCR_JUMP,
261353790Sobrien		PADDRH (no_data),
261453790Sobrien}/*-------------------------< PM0_DATA >--------------------*/,{
261553790Sobrien	/*
261653790Sobrien	 *  Keep track we are executing the PM0 DATA
261753790Sobrien	 *  mini-script.
261853790Sobrien	 */
261953790Sobrien	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
262053790Sobrien		0,
262153790Sobrien	/*
262253790Sobrien	 *  MOVE the data according to the actual
262353790Sobrien	 *  DATA direction.
262453790Sobrien	 */
262554690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
262653790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
262753790Sobrien		16,
262853790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_IN,
262953790Sobrien		offsetof (struct sym_ccb, phys.pm0.sg),
263053790Sobrien	SCR_JUMPR,
263153790Sobrien		56,
263253790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
263353790Sobrien		16,
263453790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
263553790Sobrien		offsetof (struct sym_ccb, phys.pm0.sg),
263653790Sobrien	SCR_JUMPR,
263753790Sobrien		32,
263853790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DT_DATA_IN)),
263953790Sobrien		16,
264053790Sobrien	SCR_CHMOV_TBL ^ SCR_DT_DATA_IN,
264153790Sobrien		offsetof (struct sym_ccb, phys.pm0.sg),
264253790Sobrien	SCR_JUMPR,
264353790Sobrien		8,
264453790Sobrien	SCR_CHMOV_TBL ^ SCR_DT_DATA_OUT,
264553790Sobrien		offsetof (struct sym_ccb, phys.pm0.sg),
264653790Sobrien#else
264753790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
264853790Sobrien		16,
264953790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_IN,
265053790Sobrien		offsetof (struct sym_ccb, phys.pm0.sg),
265153790Sobrien	SCR_JUMPR,
265253790Sobrien		8,
265353790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
265453790Sobrien		offsetof (struct sym_ccb, phys.pm0.sg),
265553790Sobrien#endif
265653790Sobrien	/*
265753790Sobrien	 *  Clear the flag that told we were in
265853790Sobrien	 *  the PM0 DATA mini-script.
265953790Sobrien	 */
266053790Sobrien	SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)),
266153790Sobrien		0,
266253790Sobrien	/*
266353790Sobrien	 *  Return to the previous DATA script which
266453790Sobrien	 *  is guaranteed by design (if no bug) to be
266553790Sobrien	 *  the main DATA script for this transfer.
266653790Sobrien	 */
266753790Sobrien	SCR_LOAD_REL (temp, 4),
266853790Sobrien		offsetof (struct sym_ccb, phys.pm0.ret),
266953790Sobrien	SCR_RETURN,
267053790Sobrien		0,
267153790Sobrien}/*-------------------------< PM1_DATA >--------------------*/,{
267253790Sobrien	/*
267353790Sobrien	 *  Keep track we are executing the PM1 DATA
267453790Sobrien	 *  mini-script.
267553790Sobrien	 */
267653790Sobrien	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
267753790Sobrien		0,
267853790Sobrien	/*
267953790Sobrien	 *  MOVE the data according to the actual
268053790Sobrien	 *  DATA direction.
268153790Sobrien	 */
268254690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
268353790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
268453790Sobrien		16,
268553790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_IN,
268653790Sobrien		offsetof (struct sym_ccb, phys.pm1.sg),
268753790Sobrien	SCR_JUMPR,
268853790Sobrien		56,
268953790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
269053790Sobrien		16,
269153790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
269253790Sobrien		offsetof (struct sym_ccb, phys.pm1.sg),
269353790Sobrien	SCR_JUMPR,
269453790Sobrien		32,
269553790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DT_DATA_IN)),
269653790Sobrien		16,
269753790Sobrien	SCR_CHMOV_TBL ^ SCR_DT_DATA_IN,
269853790Sobrien		offsetof (struct sym_ccb, phys.pm1.sg),
269953790Sobrien	SCR_JUMPR,
270053790Sobrien		8,
270153790Sobrien	SCR_CHMOV_TBL ^ SCR_DT_DATA_OUT,
270253790Sobrien		offsetof (struct sym_ccb, phys.pm1.sg),
270353790Sobrien#else
270453790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
270553790Sobrien		16,
270653790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_IN,
270753790Sobrien		offsetof (struct sym_ccb, phys.pm1.sg),
270853790Sobrien	SCR_JUMPR,
270953790Sobrien		8,
271053790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
271153790Sobrien		offsetof (struct sym_ccb, phys.pm1.sg),
271253790Sobrien#endif
271353790Sobrien	/*
271453790Sobrien	 *  Clear the flag that told we were in
271553790Sobrien	 *  the PM1 DATA mini-script.
271653790Sobrien	 */
271753790Sobrien	SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)),
271853790Sobrien		0,
271953790Sobrien	/*
272053790Sobrien	 *  Return to the previous DATA script which
272153790Sobrien	 *  is guaranteed by design (if no bug) to be
272253790Sobrien	 *  the main DATA script for this transfer.
272353790Sobrien	 */
272453790Sobrien	SCR_LOAD_REL (temp, 4),
272553790Sobrien		offsetof (struct sym_ccb, phys.pm1.ret),
272653790Sobrien	SCR_RETURN,
272753790Sobrien		0,
272853790Sobrien}/*---------------------------------------------------------*/
272953790Sobrien};
273053790Sobrien
273153790Sobrienstatic struct sym_scrh scripth0 = {
273253790Sobrien/*------------------------< START64 >-----------------------*/{
273353790Sobrien	/*
273453790Sobrien	 *  SCRIPT entry point for the 895A, 896 and 1010.
273553790Sobrien	 *  For now, there is no specific stuff for those
273653790Sobrien	 *  chips at this point, but this may come.
273753790Sobrien	 */
273853790Sobrien	SCR_JUMP,
273953790Sobrien		PADDR (init),
274053790Sobrien}/*-----------------------< SEL_FOR_ABORT >------------------*/,{
274153790Sobrien	/*
274253790Sobrien	 *  We are jumped here by the C code, if we have
274353790Sobrien	 *  some target to reset or some disconnected
274453790Sobrien	 *  job to abort. Since error recovery is a serious
274553790Sobrien	 *  busyness, we will really reset the SCSI BUS, if
274653790Sobrien	 *  case of a SCSI interrupt occuring in this path.
274753790Sobrien	 */
274853790Sobrien
274953790Sobrien	/*
275053790Sobrien	 *  Set initiator mode.
275153790Sobrien	 */
275253790Sobrien	SCR_CLR (SCR_TRG),
275353790Sobrien		0,
275453790Sobrien	/*
275553790Sobrien	 *      And try to select this target.
275653790Sobrien	 */
275753790Sobrien	SCR_SEL_TBL_ATN ^ offsetof (struct sym_hcb, abrt_sel),
275853790Sobrien		PADDR (reselect),
275953790Sobrien	/*
276053790Sobrien	 *  Wait for the selection to complete or
276153790Sobrien	 *  the selection to time out.
276253790Sobrien	 */
276353790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
276453790Sobrien		-8,
276553790Sobrien	/*
276653790Sobrien	 *  Call the C code.
276753790Sobrien	 */
276853790Sobrien	SCR_INT,
276953790Sobrien		SIR_TARGET_SELECTED,
277053790Sobrien	/*
277153790Sobrien	 *  The C code should let us continue here.
277253790Sobrien	 *  Send the 'kiss of death' message.
277353790Sobrien	 *  We expect an immediate disconnect once
277453790Sobrien	 *  the target has eaten the message.
277553790Sobrien	 */
277653790Sobrien	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
277753790Sobrien		0,
277853790Sobrien	SCR_MOVE_TBL ^ SCR_MSG_OUT,
277953790Sobrien		offsetof (struct sym_hcb, abrt_tbl),
278053790Sobrien	SCR_CLR (SCR_ACK|SCR_ATN),
278153790Sobrien		0,
278253790Sobrien	SCR_WAIT_DISC,
278353790Sobrien		0,
278453790Sobrien	/*
278553790Sobrien	 *  Tell the C code that we are done.
278653790Sobrien	 */
278753790Sobrien	SCR_INT,
278853790Sobrien		SIR_ABORT_SENT,
278953790Sobrien}/*-----------------------< SEL_FOR_ABORT_1 >--------------*/,{
279053790Sobrien	/*
279153790Sobrien	 *  Jump at scheduler.
279253790Sobrien	 */
279353790Sobrien	SCR_JUMP,
279453790Sobrien		PADDR (start),
279553790Sobrien
279653790Sobrien}/*------------------------< SELECT_NO_ATN >-----------------*/,{
279753790Sobrien	/*
279853790Sobrien	 *  Set Initiator mode.
279953790Sobrien	 *  And try to select this target without ATN.
280053790Sobrien	 */
280153790Sobrien	SCR_CLR (SCR_TRG),
280253790Sobrien		0,
280353790Sobrien	SCR_SEL_TBL ^ offsetof (struct dsb, select),
280453790Sobrien		PADDR (ungetjob),
280553790Sobrien	/*
280653790Sobrien	 *  load the savep (saved pointer) into
280753790Sobrien	 *  the actual data pointer.
280853790Sobrien	 */
280953790Sobrien	SCR_LOAD_REL (temp, 4),
281053790Sobrien		offsetof (struct sym_ccb, phys.savep),
281153790Sobrien	/*
281253790Sobrien	 *  Initialize the status registers
281353790Sobrien	 */
281453790Sobrien	SCR_LOAD_REL (scr0, 4),
281553790Sobrien		offsetof (struct sym_ccb, phys.status),
281653790Sobrien}/*------------------------< WF_SEL_DONE_NO_ATN >-----------------*/,{
281753790Sobrien	/*
281853790Sobrien	 *  Wait immediately for the next phase or
281953790Sobrien	 *  the selection to complete or time-out.
282053790Sobrien	 */
282153790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
282253790Sobrien		0,
282353790Sobrien	SCR_JUMP,
282453790Sobrien		PADDR (select2),
282553790Sobrien}/*-------------------------< MSG_IN_ETC >--------------------*/,{
282653790Sobrien	/*
282753790Sobrien	 *  If it is an EXTENDED (variable size message)
282853790Sobrien	 *  Handle it.
282953790Sobrien	 */
283053790Sobrien	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
283153790Sobrien		PADDRH (msg_extended),
283253790Sobrien	/*
283353790Sobrien	 *  Let the C code handle any other
283453790Sobrien	 *  1 byte message.
283553790Sobrien	 */
283653790Sobrien	SCR_INT ^ IFTRUE (MASK (0x00, 0xf0)),
283753790Sobrien		SIR_MSG_RECEIVED,
283853790Sobrien	SCR_INT ^ IFTRUE (MASK (0x10, 0xf0)),
283953790Sobrien		SIR_MSG_RECEIVED,
284053790Sobrien	/*
284153790Sobrien	 *  We donnot handle 2 bytes messages from SCRIPTS.
284253790Sobrien	 *  So, let the C code deal with these ones too.
284353790Sobrien	 */
284453790Sobrien	SCR_INT ^ IFFALSE (MASK (0x20, 0xf0)),
284553790Sobrien		SIR_MSG_WEIRD,
284653790Sobrien	SCR_CLR (SCR_ACK),
284753790Sobrien		0,
284853790Sobrien	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
284953790Sobrien		NADDR (msgin[1]),
285053790Sobrien	SCR_INT,
285153790Sobrien		SIR_MSG_RECEIVED,
285253790Sobrien
285353790Sobrien}/*-------------------------< MSG_RECEIVED >--------------------*/,{
285453790Sobrien	SCR_LOAD_REL (scratcha, 4),	/* DUMMY READ */
285553790Sobrien		0,
285653790Sobrien	SCR_INT,
285753790Sobrien		SIR_MSG_RECEIVED,
285853790Sobrien
285953790Sobrien}/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{
286053790Sobrien	SCR_LOAD_REL (scratcha, 4),	/* DUMMY READ */
286153790Sobrien		0,
286253790Sobrien	SCR_INT,
286353790Sobrien		SIR_MSG_WEIRD,
286453790Sobrien
286553790Sobrien}/*-------------------------< MSG_EXTENDED >--------------------*/,{
286653790Sobrien	/*
286753790Sobrien	 *  Clear ACK and get the next byte
286853790Sobrien	 *  assumed to be the message length.
286953790Sobrien	 */
287053790Sobrien	SCR_CLR (SCR_ACK),
287153790Sobrien		0,
287253790Sobrien	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
287353790Sobrien		NADDR (msgin[1]),
287453790Sobrien	/*
287553790Sobrien	 *  Try to catch some unlikely situations as 0 length
287653790Sobrien	 *  or too large the length.
287753790Sobrien	 */
287853790Sobrien	SCR_JUMP ^ IFTRUE (DATA (0)),
287953790Sobrien		PADDRH (msg_weird_seen),
288053790Sobrien	SCR_TO_REG (scratcha),
288153790Sobrien		0,
288253790Sobrien	SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
288353790Sobrien		0,
288453790Sobrien	SCR_JUMP ^ IFTRUE (CARRYSET),
288553790Sobrien		PADDRH (msg_weird_seen),
288653790Sobrien	/*
288753790Sobrien	 *  We donnot handle extended messages from SCRIPTS.
288853790Sobrien	 *  Read the amount of data correponding to the
288953790Sobrien	 *  message length and call the C code.
289053790Sobrien	 */
289153790Sobrien	SCR_STORE_REL (scratcha, 1),
289253790Sobrien		offsetof (struct dsb, smsg_ext.size),
289353790Sobrien	SCR_CLR (SCR_ACK),
289453790Sobrien		0,
289553790Sobrien	SCR_MOVE_TBL ^ SCR_MSG_IN,
289653790Sobrien		offsetof (struct dsb, smsg_ext),
289753790Sobrien	SCR_JUMP,
289853790Sobrien		PADDRH (msg_received),
289953790Sobrien
290053790Sobrien}/*-------------------------< MSG_BAD >------------------*/,{
290153790Sobrien	/*
290253790Sobrien	 *  unimplemented message - reject it.
290353790Sobrien	 */
290453790Sobrien	SCR_INT,
290553790Sobrien		SIR_REJECT_TO_SEND,
290653790Sobrien	SCR_SET (SCR_ATN),
290753790Sobrien		0,
290853790Sobrien	SCR_JUMP,
290953790Sobrien		PADDR (clrack),
291053790Sobrien}/*-------------------------< MSG_WEIRD >--------------------*/,{
291153790Sobrien	/*
291253790Sobrien	 *  weird message received
291353790Sobrien	 *  ignore all MSG IN phases and reject it.
291453790Sobrien	 */
291553790Sobrien	SCR_INT,
291653790Sobrien		SIR_REJECT_TO_SEND,
291753790Sobrien	SCR_SET (SCR_ATN),
291853790Sobrien		0,
291953790Sobrien}/*-------------------------< MSG_WEIRD1 >--------------------*/,{
292053790Sobrien	SCR_CLR (SCR_ACK),
292153790Sobrien		0,
292253790Sobrien	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
292353790Sobrien		PADDR (dispatch),
292453790Sobrien	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
292553790Sobrien		NADDR (scratch),
292653790Sobrien	SCR_JUMP,
292753790Sobrien		PADDRH (msg_weird1),
292853790Sobrien}/*-------------------------< WDTR_RESP >----------------*/,{
292953790Sobrien	/*
293053790Sobrien	 *  let the target fetch our answer.
293153790Sobrien	 */
293253790Sobrien	SCR_SET (SCR_ATN),
293353790Sobrien		0,
293453790Sobrien	SCR_CLR (SCR_ACK),
293553790Sobrien		0,
293653790Sobrien	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
293753790Sobrien		PADDRH (nego_bad_phase),
293853790Sobrien}/*-------------------------< SEND_WDTR >----------------*/,{
293953790Sobrien	/*
294053790Sobrien	 *  Send the M_X_WIDE_REQ
294153790Sobrien	 */
294253790Sobrien	SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
294353790Sobrien		NADDR (msgout),
294453790Sobrien	SCR_JUMP,
294553790Sobrien		PADDRH (msg_out_done),
294653790Sobrien}/*-------------------------< SDTR_RESP >-------------*/,{
294753790Sobrien	/*
294853790Sobrien	 *  let the target fetch our answer.
294953790Sobrien	 */
295053790Sobrien	SCR_SET (SCR_ATN),
295153790Sobrien		0,
295253790Sobrien	SCR_CLR (SCR_ACK),
295353790Sobrien		0,
295453790Sobrien	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
295553790Sobrien		PADDRH (nego_bad_phase),
295653790Sobrien}/*-------------------------< SEND_SDTR >-------------*/,{
295753790Sobrien	/*
295853790Sobrien	 *  Send the M_X_SYNC_REQ
295953790Sobrien	 */
296053790Sobrien	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
296153790Sobrien		NADDR (msgout),
296253790Sobrien	SCR_JUMP,
296353790Sobrien		PADDRH (msg_out_done),
296453790Sobrien}/*-------------------------< PPR_RESP >-------------*/,{
296553790Sobrien	/*
296653790Sobrien	 *  let the target fetch our answer.
296753790Sobrien	 */
296853790Sobrien	SCR_SET (SCR_ATN),
296953790Sobrien		0,
297053790Sobrien	SCR_CLR (SCR_ACK),
297153790Sobrien		0,
297253790Sobrien	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
297353790Sobrien		PADDRH (nego_bad_phase),
297453790Sobrien}/*-------------------------< SEND_PPR >-------------*/,{
297553790Sobrien	/*
297653790Sobrien	 *  Send the M_X_PPR_REQ
297753790Sobrien	 */
297853790Sobrien	SCR_MOVE_ABS (8) ^ SCR_MSG_OUT,
297953790Sobrien		NADDR (msgout),
298053790Sobrien	SCR_JUMP,
298153790Sobrien		PADDRH (msg_out_done),
298253790Sobrien}/*-------------------------< NEGO_BAD_PHASE >------------*/,{
298353790Sobrien	SCR_INT,
298453790Sobrien		SIR_NEGO_PROTO,
298553790Sobrien	SCR_JUMP,
298653790Sobrien		PADDR (dispatch),
298753790Sobrien}/*-------------------------< MSG_OUT >-------------------*/,{
298853790Sobrien	/*
298953790Sobrien	 *  The target requests a message.
299053790Sobrien	 *  We donnot send messages that may
299153790Sobrien	 *  require the device to go to bus free.
299253790Sobrien	 */
299353790Sobrien	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
299453790Sobrien		NADDR (msgout),
299553790Sobrien	/*
299653790Sobrien	 *  ... wait for the next phase
299753790Sobrien	 *  if it's a message out, send it again, ...
299853790Sobrien	 */
299953790Sobrien	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
300053790Sobrien		PADDRH (msg_out),
300153790Sobrien}/*-------------------------< MSG_OUT_DONE >--------------*/,{
300253790Sobrien	/*
300353790Sobrien	 *  Let the C code be aware of the
300453790Sobrien	 *  sent message and clear the message.
300553790Sobrien	 */
300653790Sobrien	SCR_INT,
300753790Sobrien		SIR_MSG_OUT_DONE,
300853790Sobrien	/*
300953790Sobrien	 *  ... and process the next phase
301053790Sobrien	 */
301153790Sobrien	SCR_JUMP,
301253790Sobrien		PADDR (dispatch),
301353790Sobrien
301453790Sobrien}/*-------------------------< NO_DATA >--------------------*/,{
301553790Sobrien	/*
301653790Sobrien	 *  The target wants to tranfer too much data
301753790Sobrien	 *  or in the wrong direction.
301853790Sobrien	 *  Discard one data byte, if required.
301953790Sobrien	 *  Count all discarded bytes.
302053790Sobrien	 */
302153790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
302253790Sobrien		8,
302353790Sobrien	SCR_MOVE_ABS (1) ^ SCR_DATA_OUT,
302453790Sobrien		NADDR (scratch),
302553790Sobrien	SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
302653790Sobrien		8,
302753790Sobrien	SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
302853790Sobrien		NADDR (scratch),
302954690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
303053790Sobrien	SCR_JUMPR ^ IFFALSE (IF (SCR_DT_DATA_OUT)),
303153790Sobrien		8,
303253790Sobrien	SCR_MOVE_ABS (1) ^ SCR_DT_DATA_OUT,
303353790Sobrien		NADDR (scratch),
303453790Sobrien	SCR_JUMPR ^ IFFALSE (IF (SCR_DT_DATA_IN)),
303553790Sobrien		8,
303653790Sobrien	SCR_MOVE_ABS (1) ^ SCR_DT_DATA_IN,
303753790Sobrien		NADDR (scratch),
303853790Sobrien#endif
303953790Sobrien	/*
304053790Sobrien	 *  Set the extended error flag.
304153790Sobrien	 */
304253790Sobrien	SCR_REG_REG (HF_REG, SCR_OR, HF_EXT_ERR),
304353790Sobrien		0,
304453790Sobrien	SCR_LOAD_REL (scratcha, 1),
304553790Sobrien		offsetof (struct sym_ccb, xerr_status),
304653790Sobrien	SCR_REG_REG (scratcha,  SCR_OR,  XE_EXTRA_DATA),
304753790Sobrien		0,
304853790Sobrien	/*
304953790Sobrien	 *  Count this byte.
305053790Sobrien	 *  This will allow to return a positive
305153790Sobrien	 *  residual to user.
305253790Sobrien	 */
305353790Sobrien	SCR_LOAD_REL (scratcha, 4),
305453790Sobrien		offsetof (struct sym_ccb, phys.extra_bytes),
305553790Sobrien	SCR_REG_REG (scratcha,  SCR_ADD,  0x01),
305653790Sobrien		0,
305753790Sobrien	SCR_REG_REG (scratcha1, SCR_ADDC, 0),
305853790Sobrien		0,
305953790Sobrien	SCR_REG_REG (scratcha2, SCR_ADDC, 0),
306053790Sobrien		0,
306153790Sobrien	SCR_STORE_REL (scratcha, 4),
306253790Sobrien		offsetof (struct sym_ccb, phys.extra_bytes),
306353790Sobrien	/*
306453790Sobrien	 *  .. and repeat as required.
306553790Sobrien	 */
306653790Sobrien	SCR_CALL,
306753790Sobrien		PADDR (dispatch),
306853790Sobrien	SCR_JUMP,
306953790Sobrien		PADDRH (no_data),
307053790Sobrien
307153790Sobrien}/*-------------------------< ABORT_RESEL >----------------*/,{
307253790Sobrien	SCR_SET (SCR_ATN),
307353790Sobrien		0,
307453790Sobrien	SCR_CLR (SCR_ACK),
307553790Sobrien		0,
307653790Sobrien	/*
307753790Sobrien	 *  send the abort/abortag/reset message
307853790Sobrien	 *  we expect an immediate disconnect
307953790Sobrien	 */
308053790Sobrien	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
308153790Sobrien		0,
308253790Sobrien	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
308353790Sobrien		NADDR (msgout),
308453790Sobrien	SCR_CLR (SCR_ACK|SCR_ATN),
308553790Sobrien		0,
308653790Sobrien	SCR_WAIT_DISC,
308753790Sobrien		0,
308853790Sobrien	SCR_INT,
308953790Sobrien		SIR_RESEL_ABORTED,
309053790Sobrien	SCR_JUMP,
309153790Sobrien		PADDR (start),
309253790Sobrien}/*-------------------------< RESEND_IDENT >-------------------*/,{
309353790Sobrien	/*
309453790Sobrien	 *  The target stays in MSG OUT phase after having acked
309553790Sobrien	 *  Identify [+ Tag [+ Extended message ]]. Targets shall
309653790Sobrien	 *  behave this way on parity error.
309753790Sobrien	 *  We must send it again all the messages.
309853790Sobrien	 */
309953790Sobrien	SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the  */
310053790Sobrien		0,         /* 1rst ACK = 90 ns. Hope the chip isn't too fast */
310153790Sobrien	SCR_JUMP,
310253790Sobrien		PADDR (send_ident),
310353790Sobrien}/*-------------------------< IDENT_BREAK >-------------------*/,{
310453790Sobrien	SCR_CLR (SCR_ATN),
310553790Sobrien		0,
310653790Sobrien	SCR_JUMP,
310753790Sobrien		PADDR (select2),
310853790Sobrien}/*-------------------------< IDENT_BREAK_ATN >----------------*/,{
310953790Sobrien	SCR_SET (SCR_ATN),
311053790Sobrien		0,
311153790Sobrien	SCR_JUMP,
311253790Sobrien		PADDR (select2),
311353790Sobrien}/*-------------------------< SDATA_IN >-------------------*/,{
311454690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
311553790Sobrien	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
311653790Sobrien		16,
311753790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_IN,
311853790Sobrien		offsetof (struct dsb, sense),
311953790Sobrien	SCR_JUMPR,
312053790Sobrien		8,
312153790Sobrien	SCR_CHMOV_TBL ^ SCR_DT_DATA_IN,
312253790Sobrien		offsetof (struct dsb, sense),
312353790Sobrien#else
312453790Sobrien	SCR_CHMOV_TBL ^ SCR_DATA_IN,
312553790Sobrien		offsetof (struct dsb, sense),
312653790Sobrien#endif
312753790Sobrien	SCR_CALL,
312853790Sobrien		PADDR (dispatch),
312953790Sobrien	SCR_JUMP,
313053790Sobrien		PADDRH (no_data),
313153790Sobrien
313253790Sobrien}/*-------------------------< RESEL_BAD_LUN >---------------*/,{
313353790Sobrien	/*
313453790Sobrien	 *  Message is an IDENTIFY, but lun is unknown.
313553790Sobrien	 *  Signal problem to C code for logging the event.
313653790Sobrien	 *  Send a M_ABORT to clear all pending tasks.
313753790Sobrien	 */
313853790Sobrien	SCR_INT,
313953790Sobrien		SIR_RESEL_BAD_LUN,
314053790Sobrien	SCR_JUMP,
314153790Sobrien		PADDRH (abort_resel),
314253790Sobrien}/*-------------------------< BAD_I_T_L >------------------*/,{
314353790Sobrien	/*
314453790Sobrien	 *  We donnot have a task for that I_T_L.
314553790Sobrien	 *  Signal problem to C code for logging the event.
314653790Sobrien	 *  Send a M_ABORT message.
314753790Sobrien	 */
314853790Sobrien	SCR_INT,
314953790Sobrien		SIR_RESEL_BAD_I_T_L,
315053790Sobrien	SCR_JUMP,
315153790Sobrien		PADDRH (abort_resel),
315253790Sobrien}/*-------------------------< BAD_I_T_L_Q >----------------*/,{
315353790Sobrien	/*
315453790Sobrien	 *  We donnot have a task that matches the tag.
315553790Sobrien	 *  Signal problem to C code for logging the event.
315653790Sobrien	 *  Send a M_ABORTTAG message.
315753790Sobrien	 */
315853790Sobrien	SCR_INT,
315953790Sobrien		SIR_RESEL_BAD_I_T_L_Q,
316053790Sobrien	SCR_JUMP,
316153790Sobrien		PADDRH (abort_resel),
316253790Sobrien}/*-------------------------< BAD_STATUS >-----------------*/,{
316353790Sobrien	/*
316453790Sobrien	 *  Anything different from INTERMEDIATE
316553790Sobrien	 *  CONDITION MET should be a bad SCSI status,
316653790Sobrien	 *  given that GOOD status has already been tested.
316753790Sobrien	 *  Call the C code.
316853790Sobrien	 */
316953790Sobrien	SCR_LOAD_ABS (scratcha, 4),
317053790Sobrien		PADDRH (startpos),
317153790Sobrien	SCR_INT ^ IFFALSE (DATA (S_COND_MET)),
317253790Sobrien		SIR_BAD_SCSI_STATUS,
317353790Sobrien	SCR_RETURN,
317453790Sobrien		0,
317553790Sobrien
317653790Sobrien}/*-------------------------< PM_HANDLE >------------------*/,{
317753790Sobrien	/*
317853790Sobrien	 *  Phase mismatch handling.
317953790Sobrien	 *
318053790Sobrien	 *  Since we have to deal with 2 SCSI data pointers
318153790Sobrien	 *  (current and saved), we need at least 2 contexts.
318253790Sobrien	 *  Each context (pm0 and pm1) has a saved area, a
318353790Sobrien	 *  SAVE mini-script and a DATA phase mini-script.
318453790Sobrien	 */
318553790Sobrien	/*
318653790Sobrien	 *  Get the PM handling flags.
318753790Sobrien	 */
318853790Sobrien	SCR_FROM_REG (HF_REG),
318953790Sobrien		0,
319053790Sobrien	/*
319153790Sobrien	 *  If no flags (1rst PM for example), avoid
319253790Sobrien	 *  all the below heavy flags testing.
319353790Sobrien	 *  This makes the normal case a bit faster.
319453790Sobrien	 */
319553790Sobrien	SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED))),
319653790Sobrien		PADDRH (pm_handle1),
319753790Sobrien	/*
319853790Sobrien	 *  If we received a SAVE DP, switch to the
319953790Sobrien	 *  other PM context since the savep may point
320053790Sobrien	 *  to the current PM context.
320153790Sobrien	 */
320253790Sobrien	SCR_JUMPR ^ IFFALSE (MASK (HF_DP_SAVED, HF_DP_SAVED)),
320353790Sobrien		8,
320453790Sobrien	SCR_REG_REG (sfbr, SCR_XOR, HF_ACT_PM),
320553790Sobrien		0,
320653790Sobrien	/*
320753790Sobrien	 *  If we have been interrupt in a PM DATA mini-script,
320853790Sobrien	 *  we take the return address from the corresponding
320953790Sobrien	 *  saved area.
321053790Sobrien	 *  This ensure the return address always points to the
321153790Sobrien	 *  main DATA script for this transfer.
321253790Sobrien	 */
321353790Sobrien	SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1))),
321453790Sobrien		PADDRH (pm_handle1),
321553790Sobrien	SCR_JUMPR ^ IFFALSE (MASK (HF_IN_PM0, HF_IN_PM0)),
321653790Sobrien		16,
321753790Sobrien	SCR_LOAD_REL (ia, 4),
321853790Sobrien		offsetof(struct sym_ccb, phys.pm0.ret),
321953790Sobrien	SCR_JUMP,
322053790Sobrien		PADDRH (pm_save),
322153790Sobrien	SCR_LOAD_REL (ia, 4),
322253790Sobrien		offsetof(struct sym_ccb, phys.pm1.ret),
322353790Sobrien	SCR_JUMP,
322453790Sobrien		PADDRH (pm_save),
322553790Sobrien}/*-------------------------< PM_HANDLE1 >-----------------*/,{
322653790Sobrien	/*
322753790Sobrien	 *  Normal case.
322853790Sobrien	 *  Update the return address so that it
322953790Sobrien	 *  will point after the interrupted MOVE.
323053790Sobrien	 */
323153790Sobrien	SCR_REG_REG (ia, SCR_ADD, 8),
323253790Sobrien		0,
323353790Sobrien	SCR_REG_REG (ia1, SCR_ADDC, 0),
323453790Sobrien		0,
323553790Sobrien}/*-------------------------< PM_SAVE >--------------------*/,{
323653790Sobrien	/*
323753790Sobrien	 *  Clear all the flags that told us if we were
323853790Sobrien	 *  interrupted in a PM DATA mini-script and/or
323953790Sobrien	 *  we received a SAVE DP.
324053790Sobrien	 */
324153790Sobrien	SCR_SFBR_REG (HF_REG, SCR_AND, (~(HF_IN_PM0|HF_IN_PM1|HF_DP_SAVED))),
324253790Sobrien		0,
324353790Sobrien	/*
324453790Sobrien	 *  Choose the current PM context.
324553790Sobrien	 */
324653790Sobrien	SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)),
324753790Sobrien		PADDRH (pm1_save),
324853790Sobrien}/*-------------------------< PM0_SAVE >-------------------*/,{
324953790Sobrien	SCR_STORE_REL (ia, 4),
325053790Sobrien		offsetof(struct sym_ccb, phys.pm0.ret),
325153790Sobrien	/*
325253790Sobrien	 *  If WSR bit is set, either UA and RBC may
325353790Sobrien	 *  have to be changed whether the device wants
325453790Sobrien	 *  to ignore this residue ot not.
325553790Sobrien	 */
325653790Sobrien	SCR_FROM_REG (scntl2),
325753790Sobrien		0,
325853790Sobrien	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
325953790Sobrien		PADDRH (swide_scr_64),
326053790Sobrien	/*
326153790Sobrien	 *  Save the remaining byte count, the updated
326253790Sobrien	 *  address and the return address.
326353790Sobrien	 */
326453790Sobrien	SCR_STORE_REL (rbc, 4),
326553790Sobrien		offsetof(struct sym_ccb, phys.pm0.sg.size),
326653790Sobrien	SCR_STORE_REL (ua, 4),
326753790Sobrien		offsetof(struct sym_ccb, phys.pm0.sg.addr),
326853790Sobrien	/*
326953790Sobrien	 *  Set the current pointer at the PM0 DATA mini-script.
327053790Sobrien	 */
327153790Sobrien	SCR_LOAD_ABS (temp, 4),
327253790Sobrien		PADDRH (pm0_data_addr),
327353790Sobrien	SCR_JUMP,
327453790Sobrien		PADDR (dispatch),
327553790Sobrien}/*-------------------------< PM1_SAVE >-------------------*/,{
327653790Sobrien	SCR_STORE_REL (ia, 4),
327753790Sobrien		offsetof(struct sym_ccb, phys.pm1.ret),
327853790Sobrien	/*
327953790Sobrien	 *  If WSR bit is set, either UA and RBC may
328053790Sobrien	 *  have been changed whether the device wants
328153790Sobrien	 *  to ignore this residue or not.
328253790Sobrien	 */
328353790Sobrien	SCR_FROM_REG (scntl2),
328453790Sobrien		0,
328553790Sobrien	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
328653790Sobrien		PADDRH (swide_scr_64),
328753790Sobrien	/*
328853790Sobrien	 *  Save the remaining byte count, the updated
328953790Sobrien	 *  address and the return address.
329053790Sobrien	 */
329153790Sobrien	SCR_STORE_REL (rbc, 4),
329253790Sobrien		offsetof(struct sym_ccb, phys.pm1.sg.size),
329353790Sobrien	SCR_STORE_REL (ua, 4),
329453790Sobrien		offsetof(struct sym_ccb, phys.pm1.sg.addr),
329553790Sobrien	/*
329653790Sobrien	 *  Set the current pointer at the PM1 DATA mini-script.
329753790Sobrien	 */
329853790Sobrien	SCR_LOAD_ABS (temp, 4),
329953790Sobrien		PADDRH (pm1_data_addr),
330053790Sobrien	SCR_JUMP,
330153790Sobrien		PADDR (dispatch),
330253790Sobrien}/*--------------------------< SWIDE_MA_32 >-----------------------*/,{
330353790Sobrien	/*
330453790Sobrien	 *  Handling of the SWIDE for 32 bit chips.
330553790Sobrien	 *
330653790Sobrien	 *  We jump here from the C code with SCRATCHA
330753790Sobrien	 *  containing the address to write the SWIDE.
330853790Sobrien	 *  - Save 32 bit address in <scratch>.
330953790Sobrien	 */
331053790Sobrien	SCR_STORE_ABS (scratcha, 4),
331153790Sobrien		PADDRH (scratch),
331253790Sobrien	SCR_JUMP,
331353790Sobrien		PADDRH (swide_common),
331453790Sobrien}/*--------------------------< SWIDE_MA_64 >-----------------------*/,{
331553790Sobrien	/*
331653790Sobrien	 *  Handling of the SWIDE for 64 bit chips when the
331753790Sobrien	 *  hardware handling of phase mismatch is disabled.
331853790Sobrien	 *
331953790Sobrien	 *  We jump here from the C code with SCRATCHA
332053790Sobrien	 *  containing the address to write the SWIDE and
332153790Sobrien	 *  SBR containing bit 32..39 of this address.
332253790Sobrien	 *  - Save 32 bit address in <scratch>.
332353790Sobrien	 *  - Move address bit 32..39 to SFBR.
332453790Sobrien	 */
332553790Sobrien	SCR_STORE_ABS (scratcha, 4),
332653790Sobrien		PADDRH (scratch),
332753790Sobrien	SCR_FROM_REG (sbr),
332853790Sobrien		0,
332953790Sobrien	SCR_JUMP,
333053790Sobrien		PADDRH (swide_com_64),
333153790Sobrien}/*--------------------------< SWIDE_SCR_64 >-----------------------*/,{
333253790Sobrien	/*
333353790Sobrien	 *  Handling of the SWIDE for 64 bit chips when
333453790Sobrien	 *  hardware phase mismatch is enabled.
333553790Sobrien	 *  We are entered with a SCR_CALL from PMO_SAVE
333653790Sobrien	 *  and PM1_SAVE sub-scripts.
333753790Sobrien	 *
333853790Sobrien	 *  Snoop the SCSI BUS in case of the device
333953790Sobrien	 *  willing to ignore this residue.
334053790Sobrien	 *  If it does, we must only increment the RBC,
334153790Sobrien	 *  since this register does reflect all bytes
334253790Sobrien	 *  received from the SCSI BUS including the SWIDE.
334353790Sobrien	 */
334453790Sobrien	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
334553790Sobrien		PADDRH (swide_scr_64_1),
334653790Sobrien	SCR_FROM_REG (sbdl),
334753790Sobrien		0,
334853790Sobrien	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
334953790Sobrien		PADDRH (swide_scr_64_1),
335053790Sobrien	SCR_REG_REG (rbc, SCR_ADD, 1),
335153790Sobrien		0,
335253790Sobrien	SCR_REG_REG (rbc1, SCR_ADDC, 0),
335353790Sobrien		0,
335453790Sobrien	SCR_REG_REG (rbc2, SCR_ADDC, 0),
335553790Sobrien		0,
335653790Sobrien	/*
335753790Sobrien	 *  Save UA and RBC, since the PM0/1_SAVE
335853790Sobrien	 *  sub-scripts haven't moved them to the
335953790Sobrien	 *  context yet and the below MOV may just
336053790Sobrien	 *  change their value.
336153790Sobrien	 */
336253790Sobrien	SCR_STORE_ABS (ua, 4),
336353790Sobrien		PADDRH (scratch),
336453790Sobrien	SCR_STORE_ABS (rbc, 4),
336553790Sobrien		PADDRH (scratch1),
336653790Sobrien	/*
336753790Sobrien	 *  Throw away the IGNORE WIDE RESIDUE message.
336853790Sobrien	 *  since we just did take care of it.
336953790Sobrien	 */
337053790Sobrien	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
337153790Sobrien		NADDR (scratch),
337253790Sobrien	SCR_CLR (SCR_ACK),
337353790Sobrien		0,
337453790Sobrien	/*
337553790Sobrien	 *  Restore UA and RBC registers and return.
337653790Sobrien	 */
337753790Sobrien	SCR_LOAD_ABS (ua, 4),
337853790Sobrien		PADDRH (scratch),
337953790Sobrien	SCR_LOAD_ABS (rbc, 4),
338053790Sobrien		PADDRH (scratch1),
338153790Sobrien	SCR_RETURN,
338253790Sobrien		0,
338353790Sobrien}/*--------------------------< SWIDE_SCR_64_1 >---------------------*/,{
338453790Sobrien	/*
338553790Sobrien	 *  We must grab the SWIDE and move it to
338653790Sobrien	 *  memory.
338753790Sobrien	 *
338853790Sobrien	 *  - Save UA (32 bit address) in <scratch>.
338953790Sobrien	 *  - Move address bit 32..39 to SFBR.
339053790Sobrien	 *  - Increment UA (updated address).
339153790Sobrien	 */
339253790Sobrien	SCR_STORE_ABS (ua, 4),
339353790Sobrien		PADDRH (scratch),
339453790Sobrien	SCR_FROM_REG (rbc3),
339553790Sobrien		0,
339653790Sobrien	SCR_REG_REG (ua, SCR_ADD, 1),
339753790Sobrien		0,
339853790Sobrien	SCR_REG_REG (ua1, SCR_ADDC, 0),
339953790Sobrien		0,
340053790Sobrien	SCR_REG_REG (ua2, SCR_ADDC, 0),
340153790Sobrien		0,
340253790Sobrien	SCR_REG_REG (ua3, SCR_ADDC, 0),
340353790Sobrien		0,
340453790Sobrien}/*--------------------------< SWIDE_COM_64 >-----------------------*/,{
340553790Sobrien	/*
340653790Sobrien	 *  - Save DRS.
340753790Sobrien	 *  - Load DRS with address bit 32..39 of the
340853790Sobrien	 *    location to write the SWIDE.
340953790Sobrien	 *    SFBR has been loaded with these bits.
341053790Sobrien	 *    (Look above).
341153790Sobrien	 */
341253790Sobrien	SCR_STORE_ABS (drs, 4),
341353790Sobrien		PADDRH (saved_drs),
341453790Sobrien	SCR_LOAD_ABS (drs, 4),
341553790Sobrien		PADDRH (zero),
341653790Sobrien	SCR_TO_REG (drs),
341753790Sobrien		0,
341853790Sobrien}/*--------------------------< SWIDE_COMMON >-----------------------*/,{
341953790Sobrien	/*
342053790Sobrien	 *  - Save current DSA
342153790Sobrien	 *  - Load DSA with bit 0..31 of the memory
342253790Sobrien	 *    location to write the SWIDE.
342353790Sobrien	 */
342453790Sobrien	SCR_STORE_ABS (dsa, 4),
342553790Sobrien		PADDRH (saved_dsa),
342653790Sobrien	SCR_LOAD_ABS (dsa, 4),
342753790Sobrien		PADDRH (scratch),
342853790Sobrien	/*
342953790Sobrien	 *  Move the SWIDE to memory.
343053790Sobrien	 *  Clear the WSR bit.
343153790Sobrien	 */
343253790Sobrien	SCR_STORE_REL (swide, 1),
343353790Sobrien		0,
343453790Sobrien	SCR_REG_REG (scntl2, SCR_OR, WSR),
343553790Sobrien		0,
343653790Sobrien	/*
343753790Sobrien	 *  Restore the original DSA.
343853790Sobrien	 */
343953790Sobrien	SCR_LOAD_ABS (dsa, 4),
344053790Sobrien		PADDRH (saved_dsa),
344153790Sobrien}/*--------------------------< SWIDE_FIN_32 >-----------------------*/,{
344253790Sobrien	/*
344353790Sobrien	 *  For 32 bit chip, the following SCRIPTS
344453790Sobrien	 *  instruction is patched with a JUMP to dispatcher.
344553790Sobrien	 *  (Look into the C code).
344653790Sobrien	 */
344753790Sobrien	SCR_LOAD_ABS (drs, 4),
344853790Sobrien		PADDRH (saved_drs),
344953790Sobrien	/*
345053790Sobrien	 *  64 bit chip only.
345153790Sobrien	 *  If PM handling from SCRIPTS, we are just
345253790Sobrien	 *  a helper for the C code, so jump to
345353790Sobrien	 *  dispatcher now.
345453790Sobrien	 */
345553790Sobrien	SCR_FROM_REG (ccntl0),
345653790Sobrien		0,
345753790Sobrien	SCR_JUMP ^ IFFALSE (MASK (ENPMJ, ENPMJ)),
345853790Sobrien		PADDR (dispatch),
345953790Sobrien	/*
346053790Sobrien	 *  64 bit chip with hardware PM handling enabled.
346153790Sobrien	 *
346253790Sobrien	 *  Since we are paranoid:), we donnot want
346353790Sobrien	 *  a SWIDE followed by a CHMOV(1) to lead to
346453790Sobrien	 *  a CHMOV(0) in our PM context.
346553790Sobrien	 *  We check against such a condition.
346653790Sobrien	 *  Also does the C code.
346753790Sobrien	 */
346853790Sobrien	SCR_FROM_REG (rbc),
346953790Sobrien		0,
347053790Sobrien	SCR_RETURN ^ IFFALSE (DATA (0)),
347153790Sobrien		0,
347253790Sobrien	SCR_FROM_REG (rbc1),
347353790Sobrien		0,
347453790Sobrien	SCR_RETURN ^ IFFALSE (DATA (0)),
347553790Sobrien		0,
347653790Sobrien	SCR_FROM_REG (rbc2),
347753790Sobrien		0,
347853790Sobrien	SCR_RETURN ^ IFFALSE (DATA (0)),
347953790Sobrien		0,
348053790Sobrien	/*
348153790Sobrien	 *  If we are there, RBC(0..23) is zero,
348253790Sobrien	 *  and we just have to load the current
348353790Sobrien	 *  DATA SCRIPTS address (register TEMP)
348453790Sobrien	 *  with the IA and go to dispatch.
348553790Sobrien	 *  No PM context is needed.
348653790Sobrien	 */
348753790Sobrien	SCR_STORE_ABS (ia, 4),
348853790Sobrien		PADDRH (scratch),
348953790Sobrien	SCR_LOAD_ABS (temp, 4),
349053790Sobrien		PADDRH (scratch),
349153790Sobrien	SCR_JUMP,
349253790Sobrien		PADDR (dispatch),
349354690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
349453790Sobrien}/*-------------------------< DT_DATA_IN >--------------------*/,{
349553790Sobrien/*
349653790Sobrien *  Because the size depends on the
349754690Sobrien *  #define SYM_CONF_MAX_SG parameter,
349853790Sobrien *  it is filled in at runtime.
349953790Sobrien *
350054690Sobrien *  ##===========< i=0; i<SYM_CONF_MAX_SG >=========
350153790Sobrien *  ||	SCR_CHMOV_TBL ^ SCR_DT_DATA_IN,
350253790Sobrien *  ||		offsetof (struct dsb, data[ i]),
350353790Sobrien *  ##==========================================
350453790Sobrien */
350553790Sobrien0
350653790Sobrien}/*-------------------------< DT_DATA_IN2 >-------------------*/,{
350753790Sobrien	SCR_CALL,
350853790Sobrien		PADDR (datai_done),
350953790Sobrien	SCR_JUMP,
351053790Sobrien		PADDRH (no_data),
351153790Sobrien}/*-------------------------< DT_DATA_OUT >--------------------*/,{
351253790Sobrien/*
351353790Sobrien *  Because the size depends on the
351454690Sobrien *  #define SYM_CONF_MAX_SG parameter,
351553790Sobrien *  it is filled in at runtime.
351653790Sobrien *
351754690Sobrien *  ##===========< i=0; i<SYM_CONF_MAX_SG >=========
351853790Sobrien *  ||	SCR_CHMOV_TBL ^ SCR_DT_DATA_OUT,
351953790Sobrien *  ||		offsetof (struct dsb, data[ i]),
352053790Sobrien *  ##==========================================
352153790Sobrien */
352253790Sobrien0
352353790Sobrien}/*-------------------------< DT_DATA_OUT2 >-------------------*/,{
352453790Sobrien	SCR_CALL,
352553790Sobrien		PADDR (datao_done),
352653790Sobrien	SCR_JUMP,
352753790Sobrien		PADDRH (no_data),
352853790Sobrien
352954690Sobrien#endif	/* SYM_CONF_BROKEN_U3EN_SUPPORT */
353053790Sobrien
353153790Sobrien}/*-------------------------< ZERO >------------------------*/,{
353253790Sobrien	SCR_DATA_ZERO,
353353790Sobrien}/*-------------------------< SCRATCH >---------------------*/,{
353453790Sobrien	SCR_DATA_ZERO,
353553790Sobrien}/*-------------------------< SCRATCH1 >--------------------*/,{
353653790Sobrien	SCR_DATA_ZERO,
353753790Sobrien}/*-------------------------< PM0_DATA_ADDR >---------------*/,{
353853790Sobrien	SCR_DATA_ZERO,
353953790Sobrien}/*-------------------------< PM1_DATA_ADDR >---------------*/,{
354053790Sobrien	SCR_DATA_ZERO,
354153790Sobrien}/*-------------------------< SAVED_DSA >-------------------*/,{
354253790Sobrien	SCR_DATA_ZERO,
354353790Sobrien}/*-------------------------< SAVED_DRS >-------------------*/,{
354453790Sobrien	SCR_DATA_ZERO,
354553790Sobrien}/*-------------------------< DONE_POS >--------------------*/,{
354653790Sobrien	SCR_DATA_ZERO,
354753790Sobrien}/*-------------------------< STARTPOS >--------------------*/,{
354853790Sobrien	SCR_DATA_ZERO,
354953790Sobrien}/*-------------------------< TARGTBL >---------------------*/,{
355053790Sobrien	SCR_DATA_ZERO,
355153790Sobrien
355253790Sobrien}/*-------------------------< SNOOPTEST >-------------------*/,{
355353790Sobrien	/*
355453790Sobrien	 *  Read the variable.
355553790Sobrien	 */
355653790Sobrien	SCR_LOAD_REL (scratcha, 4),
355753790Sobrien		offsetof(struct sym_hcb, cache),
355853790Sobrien	SCR_STORE_REL (temp, 4),
355953790Sobrien		offsetof(struct sym_hcb, cache),
356053790Sobrien	SCR_LOAD_REL (temp, 4),
356153790Sobrien		offsetof(struct sym_hcb, cache),
356253790Sobrien}/*-------------------------< SNOOPEND >-------------------*/,{
356353790Sobrien	/*
356453790Sobrien	 *  And stop.
356553790Sobrien	 */
356653790Sobrien	SCR_INT,
356753790Sobrien		99,
356853790Sobrien}/*--------------------------------------------------------*/
356953790Sobrien};
357053790Sobrien
357153790Sobrien/*
357253790Sobrien *  Fill in #define dependent parts of the scripts
357353790Sobrien */
357453790Sobrienstatic void sym_fill_scripts (script_p scr, scripth_p scrh)
357553790Sobrien{
357653790Sobrien	int	i;
357753790Sobrien	u32	*p;
357853790Sobrien
357953790Sobrien	p = scr->data_in;
358054690Sobrien	for (i=0; i<SYM_CONF_MAX_SG; i++) {
358153790Sobrien		*p++ =SCR_CHMOV_TBL ^ SCR_DATA_IN;
358253790Sobrien		*p++ =offsetof (struct dsb, data[i]);
358353790Sobrien	};
358453790Sobrien	assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
358553790Sobrien
358653790Sobrien	p = scr->data_out;
358754690Sobrien	for (i=0; i<SYM_CONF_MAX_SG; i++) {
358853790Sobrien		*p++ =SCR_CHMOV_TBL ^ SCR_DATA_OUT;
358953790Sobrien		*p++ =offsetof (struct dsb, data[i]);
359053790Sobrien	};
359153790Sobrien	assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out));
359253790Sobrien
359354690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
359453790Sobrien	p = scrh->dt_data_in;
359554690Sobrien	for (i=0; i<SYM_CONF_MAX_SG; i++) {
359653790Sobrien		*p++ =SCR_CHMOV_TBL ^ SCR_DT_DATA_IN;
359753790Sobrien		*p++ =offsetof (struct dsb, data[i]);
359853790Sobrien	};
359953790Sobrien	assert ((u_long)p ==
360053790Sobrien		(u_long)&scrh->dt_data_in + sizeof (scrh->dt_data_in));
360153790Sobrien
360253790Sobrien	p = scrh->dt_data_out;
360354690Sobrien	for (i=0; i<SYM_CONF_MAX_SG; i++) {
360453790Sobrien		*p++ =SCR_CHMOV_TBL ^ SCR_DATA_OUT;
360553790Sobrien		*p++ =offsetof (struct dsb, data[i]);
360653790Sobrien	};
360753790Sobrien	assert ((u_long)p ==
360853790Sobrien		(u_long)&scrh->dt_data_out + sizeof (scrh->dt_data_out));
360953790Sobrien#endif
361053790Sobrien}
361153790Sobrien
361253790Sobrien/*
361353790Sobrien *  Copy and bind a script.
361453790Sobrien */
361553790Sobrienstatic void sym_bind_script (hcb_p np, u32 *src, u32 *dst, int len)
361653790Sobrien{
361753790Sobrien	u32 opcode, new, old, tmp1, tmp2;
361853790Sobrien	u32 *start, *end;
361953790Sobrien	int relocs;
362053790Sobrien	int opchanged = 0;
362153790Sobrien
362253790Sobrien	start = src;
362353790Sobrien	end = src + len/4;
362453790Sobrien
362553790Sobrien	while (src < end) {
362653790Sobrien
362753790Sobrien		opcode = *src++;
362853790Sobrien		*dst++ = cpu_to_scr(opcode);
362953790Sobrien
363053790Sobrien		/*
363153790Sobrien		 *  If we forget to change the length
363253790Sobrien		 *  in scripts, a field will be
363353790Sobrien		 *  padded with 0. This is an illegal
363453790Sobrien		 *  command.
363553790Sobrien		 */
363653790Sobrien		if (opcode == 0) {
363753790Sobrien			printf ("%s: ERROR0 IN SCRIPT at %d.\n",
363853790Sobrien				sym_name(np), (int) (src-start-1));
363953790Sobrien			MDELAY (10000);
364053790Sobrien			continue;
364153790Sobrien		};
364253790Sobrien
364353790Sobrien		/*
364453790Sobrien		 *  We use the bogus value 0xf00ff00f ;-)
364553790Sobrien		 *  to reserve data area in SCRIPTS.
364653790Sobrien		 */
364753790Sobrien		if (opcode == SCR_DATA_ZERO) {
364853790Sobrien			dst[-1] = 0;
364953790Sobrien			continue;
365053790Sobrien		}
365153790Sobrien
365253790Sobrien		if (DEBUG_FLAGS & DEBUG_SCRIPT)
365353790Sobrien			printf ("%p:  <%x>\n", (src-1), (unsigned)opcode);
365453790Sobrien
365553790Sobrien		/*
365653790Sobrien		 *  We don't have to decode ALL commands
365753790Sobrien		 */
365853790Sobrien		switch (opcode >> 28) {
365953790Sobrien		case 0xf:
366053790Sobrien			/*
366153790Sobrien			 *  LOAD / STORE DSA relative, don't relocate.
366253790Sobrien			 */
366353790Sobrien			relocs = 0;
366453790Sobrien			break;
366553790Sobrien		case 0xe:
366653790Sobrien			/*
366753790Sobrien			 *  LOAD / STORE absolute.
366853790Sobrien			 */
366953790Sobrien			relocs = 1;
367053790Sobrien			break;
367153790Sobrien		case 0xc:
367253790Sobrien			/*
367353790Sobrien			 *  COPY has TWO arguments.
367453790Sobrien			 */
367553790Sobrien			relocs = 2;
367653790Sobrien			tmp1 = src[0];
367753790Sobrien			tmp2 = src[1];
367853790Sobrien#ifdef	RELOC_KVAR
367953790Sobrien			if ((tmp1 & RELOC_MASK) == RELOC_KVAR)
368053790Sobrien				tmp1 = 0;
368153790Sobrien			if ((tmp2 & RELOC_MASK) == RELOC_KVAR)
368253790Sobrien				tmp2 = 0;
368353790Sobrien#endif
368453790Sobrien			if ((tmp1 ^ tmp2) & 3) {
368553790Sobrien				printf ("%s: ERROR1 IN SCRIPT at %d.\n",
368653790Sobrien					sym_name(np), (int) (src-start-1));
368753790Sobrien				MDELAY (1000);
368853790Sobrien			}
368953790Sobrien			/*
369053790Sobrien			 *  If PREFETCH feature not enabled, remove
369153790Sobrien			 *  the NO FLUSH bit if present.
369253790Sobrien			 */
369353790Sobrien			if ((opcode & SCR_NO_FLUSH) &&
369453790Sobrien			    !(np->features & FE_PFEN)) {
369553790Sobrien				dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH);
369653790Sobrien				++opchanged;
369753790Sobrien			}
369853790Sobrien			break;
369953790Sobrien		case 0x0:
370053790Sobrien			/*
370153790Sobrien			 *  MOVE/CHMOV (absolute address)
370253790Sobrien			 */
370353790Sobrien			if (!(np->features & FE_WIDE))
370453790Sobrien				dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
370553790Sobrien			relocs = 1;
370653790Sobrien			break;
370753790Sobrien		case 0x1:
370853790Sobrien			/*
370953790Sobrien			 *  MOVE/CHMOV (table indirect)
371053790Sobrien			 */
371153790Sobrien			if (!(np->features & FE_WIDE))
371253790Sobrien				dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
371353790Sobrien			relocs = 0;
371453790Sobrien			break;
371553790Sobrien		case 0x8:
371653790Sobrien			/*
371753790Sobrien			 *  JUMP / CALL
371853790Sobrien			 *  dont't relocate if relative :-)
371953790Sobrien			 */
372053790Sobrien			if (opcode & 0x00800000)
372153790Sobrien				relocs = 0;
372253790Sobrien			else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
372353790Sobrien				relocs = 2;
372453790Sobrien			else
372553790Sobrien				relocs = 1;
372653790Sobrien			break;
372753790Sobrien		case 0x4:
372853790Sobrien		case 0x5:
372953790Sobrien		case 0x6:
373053790Sobrien		case 0x7:
373153790Sobrien			relocs = 1;
373253790Sobrien			break;
373353790Sobrien		default:
373453790Sobrien			relocs = 0;
373553790Sobrien			break;
373653790Sobrien		};
373753790Sobrien
373853790Sobrien		if (!relocs) {
373953790Sobrien			*dst++ = cpu_to_scr(*src++);
374053790Sobrien			continue;
374153790Sobrien		}
374253790Sobrien		while (relocs--) {
374353790Sobrien			old = *src++;
374453790Sobrien
374553790Sobrien			switch (old & RELOC_MASK) {
374653790Sobrien			case RELOC_REGISTER:
374753790Sobrien				new = (old & ~RELOC_MASK) + np->mmio_ba;
374853790Sobrien				break;
374953790Sobrien			case RELOC_LABEL:
375053790Sobrien				new = (old & ~RELOC_MASK) + np->script_ba;
375153790Sobrien				break;
375253790Sobrien			case RELOC_LABELH:
375353790Sobrien				new = (old & ~RELOC_MASK) + np->scripth_ba;
375453790Sobrien				break;
375553790Sobrien			case RELOC_SOFTC:
375653790Sobrien				new = (old & ~RELOC_MASK) + vtobus(np);
375753790Sobrien				break;
375853790Sobrien#ifdef	RELOC_KVAR
375953790Sobrien			case RELOC_KVAR:
376053790Sobrien				if (((old & ~RELOC_MASK) < SCRIPT_KVAR_FIRST) ||
376153790Sobrien				    ((old & ~RELOC_MASK) > SCRIPT_KVAR_LAST))
376253790Sobrien					panic("KVAR out of range");
376353790Sobrien				new = vtobus(script_kvars[old & ~RELOC_MASK]);
376453790Sobrien#endif
376553790Sobrien				break;
376653790Sobrien			case 0:
376753790Sobrien				/* Don't relocate a 0 address. */
376853790Sobrien				if (old == 0) {
376953790Sobrien					new = old;
377053790Sobrien					break;
377153790Sobrien				}
377253790Sobrien				/* fall through */
377353790Sobrien			default:
377453790Sobrien				new = 0;	/* For 'cc' not to complain */
377553790Sobrien				panic("sym_bind_script: "
377653790Sobrien				      "weird relocation %x\n", old);
377753790Sobrien				break;
377853790Sobrien			}
377953790Sobrien
378053790Sobrien			*dst++ = cpu_to_scr(new);
378153790Sobrien		}
378253790Sobrien	};
378353790Sobrien}
378453790Sobrien
378553790Sobrien/*
378653790Sobrien *  Print something which allows to retrieve the controler type,
378753790Sobrien *  unit, target, lun concerned by a kernel message.
378853790Sobrien */
378953790Sobrienstatic void PRINT_TARGET (hcb_p np, int target)
379053790Sobrien{
379153790Sobrien	printf ("%s:%d:", sym_name(np), target);
379253790Sobrien}
379353790Sobrien
379453790Sobrienstatic void PRINT_LUN(hcb_p np, int target, int lun)
379553790Sobrien{
379653790Sobrien	printf ("%s:%d:%d:", sym_name(np), target, lun);
379753790Sobrien}
379853790Sobrien
379953790Sobrienstatic void PRINT_ADDR (ccb_p cp)
380053790Sobrien{
380153790Sobrien	if (cp && cp->cam_ccb)
380253790Sobrien		xpt_print_path(cp->cam_ccb->ccb_h.path);
380353790Sobrien}
380453790Sobrien
380553790Sobrien/*
380653790Sobrien *  Take into account this ccb in the freeze count.
380753790Sobrien *  The flag that tells user about avoids doing that
380853790Sobrien *  more than once for a ccb.
380953790Sobrien */
381053790Sobrienstatic void sym_freeze_cam_ccb(union ccb *ccb)
381153790Sobrien{
381253790Sobrien	if (!(ccb->ccb_h.flags & CAM_DEV_QFRZDIS)) {
381353790Sobrien		if (!(ccb->ccb_h.status & CAM_DEV_QFRZN)) {
381453790Sobrien			ccb->ccb_h.status |= CAM_DEV_QFRZN;
381553790Sobrien			xpt_freeze_devq(ccb->ccb_h.path, 1);
381653790Sobrien		}
381753790Sobrien	}
381853790Sobrien}
381953790Sobrien
382053790Sobrien/*
382153790Sobrien *  Set the status field of a CAM CCB.
382253790Sobrien */
382353790Sobrienstatic __inline void sym_set_cam_status(union ccb *ccb, cam_status status)
382453790Sobrien{
382553790Sobrien	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
382653790Sobrien	ccb->ccb_h.status |= status;
382753790Sobrien}
382853790Sobrien
382953790Sobrien/*
383053790Sobrien *  Get the status field of a CAM CCB.
383153790Sobrien */
383253790Sobrienstatic __inline int sym_get_cam_status(union ccb *ccb)
383353790Sobrien{
383453790Sobrien	return ccb->ccb_h.status & CAM_STATUS_MASK;
383553790Sobrien}
383653790Sobrien
383753790Sobrien/*
383853790Sobrien *  Enqueue a CAM CCB.
383953790Sobrien */
384053790Sobrienstatic void sym_enqueue_cam_ccb(hcb_p np, union ccb *ccb)
384153790Sobrien{
384253790Sobrien	assert(!(ccb->ccb_h.status & CAM_SIM_QUEUED));
384353790Sobrien	ccb->ccb_h.status = CAM_REQ_INPROG;
384453790Sobrien
384553790Sobrien	ccb->ccb_h.timeout_ch = timeout(sym_timeout, (caddr_t) ccb,
384653790Sobrien				       ccb->ccb_h.timeout*hz/1000);
384753790Sobrien	ccb->ccb_h.status |= CAM_SIM_QUEUED;
384853790Sobrien	ccb->ccb_h.sym_hcb_ptr = np;
384953790Sobrien
385053790Sobrien	sym_insque_tail(sym_qptr(&ccb->ccb_h.sim_links), &np->cam_ccbq);
385153790Sobrien}
385253790Sobrien
385353790Sobrien/*
385453790Sobrien *  Complete a pending CAM CCB.
385553790Sobrien */
385653790Sobrienstatic void sym_xpt_done(hcb_p np, union ccb *ccb)
385753790Sobrien{
385853790Sobrien	if (ccb->ccb_h.status & CAM_SIM_QUEUED) {
385953790Sobrien		untimeout(sym_timeout, (caddr_t) ccb, ccb->ccb_h.timeout_ch);
386053790Sobrien		sym_remque(sym_qptr(&ccb->ccb_h.sim_links));
386153790Sobrien		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
386253790Sobrien		ccb->ccb_h.sym_hcb_ptr = 0;
386353790Sobrien	}
386453790Sobrien	if (ccb->ccb_h.flags & CAM_DEV_QFREEZE)
386553790Sobrien		sym_freeze_cam_ccb(ccb);
386653790Sobrien	xpt_done(ccb);
386753790Sobrien}
386853790Sobrien
386953790Sobrienstatic void sym_xpt_done2(hcb_p np, union ccb *ccb, int cam_status)
387053790Sobrien{
387153790Sobrien	sym_set_cam_status(ccb, cam_status);
387253790Sobrien	sym_xpt_done(np, ccb);
387353790Sobrien}
387453790Sobrien
387553790Sobrien/*
387653790Sobrien *  SYMBIOS chip clock divisor table.
387753790Sobrien *
387853790Sobrien *  Divisors are multiplied by 10,000,000 in order to make
387953790Sobrien *  calculations more simple.
388053790Sobrien */
388153790Sobrien#define _5M 5000000
388253790Sobrienstatic u_long div_10M[] =
388353790Sobrien	{2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
388453790Sobrien
388553790Sobrien/*
388653790Sobrien *  SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64,
388753790Sobrien *  128 transfers. All chips support at least 16 transfers
388853790Sobrien *  bursts. The 825A, 875 and 895 chips support bursts of up
388953790Sobrien *  to 128 transfers and the 895A and 896 support bursts of up
389053790Sobrien *  to 64 transfers. All other chips support up to 16
389153790Sobrien *  transfers bursts.
389253790Sobrien *
389353790Sobrien *  For PCI 32 bit data transfers each transfer is a DWORD.
389453790Sobrien *  It is a QUADWORD (8 bytes) for PCI 64 bit data transfers.
389553790Sobrien *  Only the 896 is able to perform 64 bit data transfers.
389653790Sobrien *
389753790Sobrien *  We use log base 2 (burst length) as internal code, with
389853790Sobrien *  value 0 meaning "burst disabled".
389953790Sobrien */
390053790Sobrien
390153790Sobrien/*
390253790Sobrien *  Burst length from burst code.
390353790Sobrien */
390453790Sobrien#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
390553790Sobrien
390653790Sobrien/*
390753790Sobrien *  Burst code from io register bits.
390853790Sobrien */
390953790Sobrien#define burst_code(dmode, ctest4, ctest5) \
391053790Sobrien	(ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
391153790Sobrien
391253790Sobrien/*
391353790Sobrien *  Set initial io register bits from burst code.
391453790Sobrien */
391553790Sobrienstatic __inline void sym_init_burst(hcb_p np, u_char bc)
391653790Sobrien{
391753790Sobrien	np->rv_ctest4	&= ~0x80;
391853790Sobrien	np->rv_dmode	&= ~(0x3 << 6);
391953790Sobrien	np->rv_ctest5	&= ~0x4;
392053790Sobrien
392153790Sobrien	if (!bc) {
392253790Sobrien		np->rv_ctest4	|= 0x80;
392353790Sobrien	}
392453790Sobrien	else {
392553790Sobrien		--bc;
392653790Sobrien		np->rv_dmode	|= ((bc & 0x3) << 6);
392753790Sobrien		np->rv_ctest5	|= (bc & 0x4);
392853790Sobrien	}
392953790Sobrien}
393053790Sobrien
393153790Sobrien
393253790Sobrien/*
393353790Sobrien * Print out the list of targets that have some flag disabled by user.
393453790Sobrien */
393553790Sobrienstatic void sym_print_targets_flag(hcb_p np, int mask, char *msg)
393653790Sobrien{
393753790Sobrien	int cnt;
393853790Sobrien	int i;
393953790Sobrien
394054690Sobrien	for (cnt = 0, i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
394153790Sobrien		if (i == np->myaddr)
394253790Sobrien			continue;
394353790Sobrien		if (np->target[i].usrflags & mask) {
394453790Sobrien			if (!cnt++)
394553790Sobrien				printf("%s: %s disabled for targets",
394653790Sobrien					sym_name(np), msg);
394753790Sobrien			printf(" %d", i);
394853790Sobrien		}
394953790Sobrien	}
395053790Sobrien	if (cnt)
395153790Sobrien		printf(".\n");
395253790Sobrien}
395353790Sobrien
395453790Sobrien/*
395553796Sobrien *  Save initial settings of some IO registers.
395653796Sobrien *  Assumed to have been set by BIOS.
395753796Sobrien *  We cannot reset the chip prior to reading the
395853796Sobrien *  IO registers, since informations will be lost.
395953796Sobrien *  Since the SCRIPTS processor may be running, this
396053796Sobrien *  is not safe on paper, but it seems to work quite
396153796Sobrien *  well. :)
396253790Sobrien */
396353796Sobrienstatic void sym_save_initial_setting (hcb_p np)
396453790Sobrien{
396553790Sobrien	np->sv_scntl0	= INB(nc_scntl0) & 0x0a;
396653790Sobrien	np->sv_scntl3	= INB(nc_scntl3) & 0x07;
396753790Sobrien	np->sv_dmode	= INB(nc_dmode)  & 0xce;
396853790Sobrien	np->sv_dcntl	= INB(nc_dcntl)  & 0xa8;
396953790Sobrien	np->sv_ctest3	= INB(nc_ctest3) & 0x01;
397053790Sobrien	np->sv_ctest4	= INB(nc_ctest4) & 0x80;
397153790Sobrien	np->sv_gpcntl	= INB(nc_gpcntl);
397253796Sobrien	np->sv_stest1	= INB(nc_stest1);
397353790Sobrien	np->sv_stest2	= INB(nc_stest2) & 0x20;
397453790Sobrien	np->sv_stest4	= INB(nc_stest4);
397553790Sobrien	if (np->features & FE_C10) {	/* Always large DMA fifo + ultra3 */
397653790Sobrien		np->sv_scntl4	= INB(nc_scntl4);
397753790Sobrien		np->sv_ctest5	= INB(nc_ctest5) & 0x04;
397853790Sobrien	}
397953790Sobrien	else
398053790Sobrien		np->sv_ctest5	= INB(nc_ctest5) & 0x24;
398153796Sobrien}
398253796Sobrien
398353796Sobrien/*
398453796Sobrien *  Prepare io register values used by sym_init() according
398553796Sobrien *  to selected and supported features.
398653796Sobrien */
398753796Sobrienstatic int sym_prepare_setting(hcb_p np, struct sym_nvram *nvram)
398853796Sobrien{
398953796Sobrien	u_char	burst_max;
399053796Sobrien	u_long	period;
399153796Sobrien	int i;
399253796Sobrien
399353790Sobrien	/*
399453790Sobrien	 *  Wide ?
399553790Sobrien	 */
399653790Sobrien	np->maxwide	= (np->features & FE_WIDE)? 1 : 0;
399753790Sobrien
399853790Sobrien	/*
399953790Sobrien	 *  Get the frequency of the chip's clock.
400053790Sobrien	 */
400153790Sobrien	if	(np->features & FE_QUAD)
400253790Sobrien		np->multiplier	= 4;
400353790Sobrien	else if	(np->features & FE_DBLR)
400453790Sobrien		np->multiplier	= 2;
400553790Sobrien	else
400653790Sobrien		np->multiplier	= 1;
400753790Sobrien
400853790Sobrien	np->clock_khz	= (np->features & FE_CLK80)? 80000 : 40000;
400953790Sobrien	np->clock_khz	*= np->multiplier;
401053790Sobrien
401153790Sobrien	if (np->clock_khz != 40000)
401253790Sobrien		sym_getclock(np, np->multiplier);
401353790Sobrien
401453790Sobrien	/*
401553790Sobrien	 * Divisor to be used for async (timer pre-scaler).
401653790Sobrien	 */
401753790Sobrien	i = np->clock_divn - 1;
401853790Sobrien	while (--i >= 0) {
401954690Sobrien		if (10ul * SYM_CONF_MIN_ASYNC * np->clock_khz > div_10M[i]) {
402053790Sobrien			++i;
402153790Sobrien			break;
402253790Sobrien		}
402353790Sobrien	}
402453790Sobrien	np->rv_scntl3 = i+1;
402553790Sobrien
402653790Sobrien	/*
402753790Sobrien	 * The C1010 uses hardwired divisors for async.
402853790Sobrien	 * So, we just throw away, the async. divisor.:-)
402953790Sobrien	 */
403053790Sobrien	if (np->features & FE_C10)
403153790Sobrien		np->rv_scntl3 = 0;
403253790Sobrien
403353790Sobrien	/*
403453790Sobrien	 * Minimum synchronous period factor supported by the chip.
403553790Sobrien	 * Btw, 'period' is in tenths of nanoseconds.
403653790Sobrien	 */
403753790Sobrien	period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz;
403853790Sobrien	if	(period <= 250)		np->minsync = 10;
403953790Sobrien	else if	(period <= 303)		np->minsync = 11;
404053790Sobrien	else if	(period <= 500)		np->minsync = 12;
404153790Sobrien	else				np->minsync = (period + 40 - 1) / 40;
404253790Sobrien
404353790Sobrien	/*
404453790Sobrien	 * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2).
404553790Sobrien	 */
404653790Sobrien	if	(np->minsync < 25 &&
404753790Sobrien		 !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3)))
404853790Sobrien		np->minsync = 25;
404953790Sobrien	else if	(np->minsync < 12 &&
405053790Sobrien		 !(np->features & (FE_ULTRA2|FE_ULTRA3)))
405153790Sobrien		np->minsync = 12;
405253790Sobrien
405353790Sobrien	/*
405453790Sobrien	 * Maximum synchronous period factor supported by the chip.
405553790Sobrien	 */
405653790Sobrien	period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz);
405753790Sobrien	np->maxsync = period > 2540 ? 254 : period / 10;
405853790Sobrien
405953790Sobrien	/*
406053790Sobrien	 * If chip is a C1010, guess the sync limits in DT mode.
406153790Sobrien	 */
406253790Sobrien	if ((np->features & (FE_C10|FE_ULTRA3)) == (FE_C10|FE_ULTRA3)) {
406353790Sobrien		if (np->clock_khz == 160000) {
406453790Sobrien			np->minsync_dt = 9;
406553790Sobrien			np->maxsync_dt = 50;
406653790Sobrien		}
406753790Sobrien	}
406853790Sobrien
406953790Sobrien	/*
407053790Sobrien	 *  64 bit (53C895A or 53C896) ?
407153790Sobrien	 */
407253790Sobrien	if (np->features & FE_64BIT)
407353790Sobrien#if BITS_PER_LONG > 32
407453790Sobrien		np->rv_ccntl1	|= (XTIMOD | EXTIBMV);
407553790Sobrien#else
407653790Sobrien		np->rv_ccntl1	|= (DDAC);
407753790Sobrien#endif
407853790Sobrien
407953790Sobrien	/*
408053790Sobrien	 *  Phase mismatch handled by SCRIPTS (895A/896/1010) ?
408153790Sobrien  	 */
408253790Sobrien	if (np->features & FE_NOPM)
408353790Sobrien		np->rv_ccntl0	|= (ENPMJ);
408453790Sobrien
408553790Sobrien 	/*
408653790Sobrien	 *  C1010 Errata.
408753790Sobrien	 *  In dual channel mode, contention occurs if internal cycles
408853790Sobrien	 *  are used. Disable internal cycles.
408953790Sobrien	 */
409053790Sobrien	if (np->device_id == PCI_ID_LSI53C1010 && np->revision_id < 0x45)
409153790Sobrien		np->rv_ccntl0	|=  DILS;
409253790Sobrien
409353790Sobrien	/*
409453790Sobrien	 *  Select burst length (dwords)
409553790Sobrien	 */
409654690Sobrien	burst_max	= SYM_SETUP_BURST_ORDER;
409753790Sobrien	if (burst_max == 255)
409853790Sobrien		burst_max = burst_code(np->sv_dmode, np->sv_ctest4,
409953790Sobrien				       np->sv_ctest5);
410053790Sobrien	if (burst_max > 7)
410153790Sobrien		burst_max = 7;
410253790Sobrien	if (burst_max > np->maxburst)
410353790Sobrien		burst_max = np->maxburst;
410453790Sobrien
410553790Sobrien	/*
410653790Sobrien	 *  DEL 352 - 53C810 Rev x11 - Part Number 609-0392140 - ITEM 2.
410753790Sobrien	 *  This chip and the 860 Rev 1 may wrongly use PCI cache line
410853790Sobrien	 *  based transactions on LOAD/STORE instructions. So we have
410953790Sobrien	 *  to prevent these chips from using such PCI transactions in
411053790Sobrien	 *  this driver. The generic ncr driver that does not use
411153790Sobrien	 *  LOAD/STORE instructions does not need this work-around.
411253790Sobrien	 */
411353790Sobrien	if ((np->device_id == PCI_ID_SYM53C810 &&
411453790Sobrien	     np->revision_id >= 0x10 && np->revision_id <= 0x11) ||
411553790Sobrien	    (np->device_id == PCI_ID_SYM53C860 &&
411653790Sobrien	     np->revision_id <= 0x1))
411753790Sobrien		np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP);
411853790Sobrien
411953790Sobrien	/*
412053790Sobrien	 *  Select all supported special features.
412153790Sobrien	 *  If we are using on-board RAM for scripts, prefetch (PFEN)
412253790Sobrien	 *  does not help, but burst op fetch (BOF) does.
412353790Sobrien	 *  Disabling PFEN makes sure BOF will be used.
412453790Sobrien	 */
412553790Sobrien	if (np->features & FE_ERL)
412653790Sobrien		np->rv_dmode	|= ERL;		/* Enable Read Line */
412753790Sobrien	if (np->features & FE_BOF)
412853790Sobrien		np->rv_dmode	|= BOF;		/* Burst Opcode Fetch */
412953790Sobrien	if (np->features & FE_ERMP)
413053790Sobrien		np->rv_dmode	|= ERMP;	/* Enable Read Multiple */
413153790Sobrien#if 1
413253790Sobrien	if ((np->features & FE_PFEN) && !np->ram_ba)
413353790Sobrien#else
413453790Sobrien	if (np->features & FE_PFEN)
413553790Sobrien#endif
413653790Sobrien		np->rv_dcntl	|= PFEN;	/* Prefetch Enable */
413753790Sobrien	if (np->features & FE_CLSE)
413853790Sobrien		np->rv_dcntl	|= CLSE;	/* Cache Line Size Enable */
413953790Sobrien	if (np->features & FE_WRIE)
414053790Sobrien		np->rv_ctest3	|= WRIE;	/* Write and Invalidate */
414153790Sobrien	if (np->features & FE_DFS)
414253790Sobrien		np->rv_ctest5	|= DFS;		/* Dma Fifo Size */
414353790Sobrien
414453790Sobrien	/*
414553790Sobrien	 *  Select some other
414653790Sobrien	 */
414754690Sobrien	if (SYM_SETUP_PCI_PARITY)
414853790Sobrien		np->rv_ctest4	|= MPEE; /* Master parity checking */
414954690Sobrien	if (SYM_SETUP_SCSI_PARITY)
415053790Sobrien		np->rv_scntl0	|= 0x0a; /*  full arb., ena parity, par->ATN  */
415153790Sobrien
415253790Sobrien	/*
415353790Sobrien	 *  Get parity checking, host ID and verbose mode from NVRAM
415453790Sobrien	 */
415553790Sobrien	np->myaddr = 255;
415653790Sobrien	sym_nvram_setup_host (np, nvram);
415753790Sobrien
415853790Sobrien	/*
415953790Sobrien	 *  Get SCSI addr of host adapter (set by bios?).
416053790Sobrien	 */
416153790Sobrien	if (np->myaddr == 255) {
416253790Sobrien		np->myaddr = INB(nc_scid) & 0x07;
416353790Sobrien		if (!np->myaddr)
416454690Sobrien			np->myaddr = SYM_SETUP_HOST_ID;
416553790Sobrien	}
416653790Sobrien
416753790Sobrien	/*
416853790Sobrien	 *  Prepare initial io register bits for burst length
416953790Sobrien	 */
417053790Sobrien	sym_init_burst(np, burst_max);
417153790Sobrien
417253790Sobrien	/*
417353790Sobrien	 *  Set SCSI BUS mode.
417453790Sobrien	 *  - LVD capable chips (895/895A/896/1010) report the
417553790Sobrien	 *    current BUS mode through the STEST4 IO register.
417653790Sobrien	 *  - For previous generation chips (825/825A/875),
417753790Sobrien	 *    user has to tell us how to check against HVD,
417853790Sobrien	 *    since a 100% safe algorithm is not possible.
417953790Sobrien	 */
418053790Sobrien	np->scsi_mode = SMODE_SE;
418153790Sobrien	if (np->features & (FE_ULTRA2|FE_ULTRA3))
418253790Sobrien		np->scsi_mode = (np->sv_stest4 & SMODE);
418353790Sobrien	else if	(np->features & FE_DIFF) {
418454690Sobrien		if (SYM_SETUP_SCSI_DIFF == 1) {
418553790Sobrien			if (np->sv_scntl3) {
418653790Sobrien				if (np->sv_stest2 & 0x20)
418753790Sobrien					np->scsi_mode = SMODE_HVD;
418853790Sobrien			}
418953790Sobrien			else if (nvram->type == SYM_SYMBIOS_NVRAM) {
419053790Sobrien				if (INB(nc_gpreg) & 0x08)
419153790Sobrien					np->scsi_mode = SMODE_HVD;
419253790Sobrien			}
419353790Sobrien		}
419454690Sobrien		else if	(SYM_SETUP_SCSI_DIFF == 2)
419553790Sobrien			np->scsi_mode = SMODE_HVD;
419653790Sobrien	}
419753790Sobrien	if (np->scsi_mode == SMODE_HVD)
419853790Sobrien		np->rv_stest2 |= 0x20;
419953790Sobrien
420053790Sobrien	/*
420153790Sobrien	 *  Set LED support from SCRIPTS.
420253790Sobrien	 *  Ignore this feature for boards known to use a
420353790Sobrien	 *  specific GPIO wiring and for the 895A or 896
420453790Sobrien	 *  that drive the LED directly.
420553790Sobrien	 */
420654690Sobrien	if ((SYM_SETUP_SCSI_LED || nvram->type == SYM_SYMBIOS_NVRAM) &&
420753790Sobrien	    !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
420853790Sobrien		np->features |= FE_LED0;
420953790Sobrien
421053790Sobrien	/*
421153790Sobrien	 *  Set irq mode.
421253790Sobrien	 */
421354690Sobrien	switch(SYM_SETUP_IRQ_MODE & 3) {
421453790Sobrien	case 2:
421553790Sobrien		np->rv_dcntl	|= IRQM;
421653790Sobrien		break;
421753790Sobrien	case 1:
421853790Sobrien		np->rv_dcntl	|= (np->sv_dcntl & IRQM);
421953790Sobrien		break;
422053790Sobrien	default:
422153790Sobrien		break;
422253790Sobrien	}
422353790Sobrien
422453790Sobrien	/*
422553790Sobrien	 *  Configure targets according to driver setup.
422653790Sobrien	 *  If NVRAM present get targets setup from NVRAM.
422753790Sobrien	 */
422854690Sobrien	for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
422953790Sobrien		tcb_p tp = &np->target[i];
423053790Sobrien
423153790Sobrien		tp->tinfo.user.period = np->minsync;
423253790Sobrien		tp->tinfo.user.offset = np->maxoffs;
423353790Sobrien		tp->tinfo.user.width  = np->maxwide ? BUS_16_BIT : BUS_8_BIT;
423453790Sobrien		tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED);
423554690Sobrien		tp->usrtags = SYM_SETUP_MAX_TAG;
423653790Sobrien
423753790Sobrien		sym_nvram_setup_target (np, i, nvram);
423853790Sobrien
423953790Sobrien		if (!tp->usrtags)
424053790Sobrien			tp->usrflags &= ~SYM_TAGS_ENABLED;
424153790Sobrien	}
424253790Sobrien
424353790Sobrien	/*
424453790Sobrien	 *  Let user know about the settings.
424553790Sobrien	 */
424653790Sobrien	i = nvram->type;
424755300Sgroudier	printf("%s: %s NVRAM, ID %d, Fast-%d, %s, %s\n", sym_name(np),
424853790Sobrien		i  == SYM_SYMBIOS_NVRAM ? "Symbios" :
424953790Sobrien		(i == SYM_TEKRAM_NVRAM  ? "Tekram" : "No"),
425053790Sobrien		np->myaddr,
425155300Sgroudier		(np->features & FE_ULTRA3) ? 80 :
425255300Sgroudier		(np->features & FE_ULTRA2) ? 40 :
425355300Sgroudier		(np->features & FE_ULTRA)  ? 20 : 10,
425455300Sgroudier		sym_scsi_bus_mode(np->scsi_mode),
425555300Sgroudier		(np->rv_scntl0 & 0xa)	? "parity checking" : "NO parity");
425653790Sobrien	/*
425753790Sobrien	 *  Tell him more on demand.
425853790Sobrien	 */
425955300Sgroudier	if (sym_verbose) {
426053790Sobrien		printf("%s: %s IRQ line driver%s\n",
426153790Sobrien			sym_name(np),
426253790Sobrien			np->rv_dcntl & IRQM ? "totem pole" : "open drain",
426353790Sobrien			np->ram_ba ? ", using on-chip SRAM" : "");
426455300Sgroudier		if (np->features & FE_NOPM)
426555300Sgroudier			printf("%s: handling phase mismatch from SCRIPTS.\n",
426655300Sgroudier			       sym_name(np));
426755300Sgroudier	}
426853790Sobrien	/*
426953790Sobrien	 *  And still more.
427053790Sobrien	 */
427153790Sobrien	if (sym_verbose > 1) {
427253790Sobrien		printf ("%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
427353790Sobrien			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
427453790Sobrien			sym_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl,
427553790Sobrien			np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
427653790Sobrien
427753790Sobrien		printf ("%s: final   SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
427853790Sobrien			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
427953790Sobrien			sym_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl,
428053790Sobrien			np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
428153790Sobrien	}
428253790Sobrien	/*
428353790Sobrien	 *  Let user be aware of targets that have some disable flags set.
428453790Sobrien	 */
428553790Sobrien	sym_print_targets_flag(np, SYM_SCAN_BOOT_DISABLED, "SCAN AT BOOT");
428653790Sobrien	if (sym_verbose)
428753790Sobrien		sym_print_targets_flag(np, SYM_SCAN_LUNS_DISABLED,
428853790Sobrien				       "SCAN FOR LUNS");
428953790Sobrien
429053790Sobrien	return 0;
429153790Sobrien}
429253790Sobrien
429353790Sobrien/*
429453790Sobrien *  Prepare the next negotiation message if needed.
429553790Sobrien *
429653790Sobrien *  Fill in the part of message buffer that contains the
429753790Sobrien *  negotiation and the nego_status field of the CCB.
429853790Sobrien *  Returns the size of the message in bytes.
429953790Sobrien */
430053790Sobrien
430153790Sobrienstatic int sym_prepare_nego(hcb_p np, ccb_p cp, int nego, u_char *msgptr)
430253790Sobrien{
430353790Sobrien	tcb_p tp = &np->target[cp->target];
430453790Sobrien	int msglen = 0;
430553790Sobrien
430653790Sobrien#if 1
430753790Sobrien	/*
430853790Sobrien	 *  For now, only use PPR with DT option if period factor = 9.
430953790Sobrien	 */
431053809Sobrien	if (tp->tinfo.goal.period == 9) {
431153809Sobrien		tp->tinfo.goal.width = BUS_16_BIT;
431253809Sobrien		tp->tinfo.goal.options |= PPR_OPT_DT;
431353809Sobrien	}
431453809Sobrien	else
431553809Sobrien		tp->tinfo.goal.options &= ~PPR_OPT_DT;
431653790Sobrien#endif
431753796Sobrien	/*
431853796Sobrien	 *  Early C1010 chips need a work-around for DT
431953796Sobrien	 *  data transfer to work.
432053796Sobrien	 */
432154690Sobrien#ifndef	SYM_CONF_BROKEN_U3EN_SUPPORT
432253790Sobrien	if (!(np->features & FE_U3EN))
432353790Sobrien		tp->tinfo.goal.options = 0;
432453790Sobrien#endif
432553790Sobrien	/*
432653790Sobrien	 *  negotiate using PPR ?
432753790Sobrien	 */
432853790Sobrien	if (tp->tinfo.goal.options & PPR_OPT_MASK)
432953790Sobrien		nego = NS_PPR;
433053790Sobrien	/*
433153790Sobrien	 *  negotiate wide transfers ?
433253790Sobrien	 */
433353790Sobrien	else if (tp->tinfo.current.width != tp->tinfo.goal.width)
433453790Sobrien		nego = NS_WIDE;
433553790Sobrien	/*
433653790Sobrien	 *  negotiate synchronous transfers?
433753790Sobrien	 */
433853790Sobrien	else if (tp->tinfo.current.period != tp->tinfo.goal.period ||
433953790Sobrien		 tp->tinfo.current.offset != tp->tinfo.goal.offset)
434053790Sobrien		nego = NS_SYNC;
434153790Sobrien
434253790Sobrien	switch (nego) {
434353790Sobrien	case NS_SYNC:
434453790Sobrien		msgptr[msglen++] = M_EXTENDED;
434553790Sobrien		msgptr[msglen++] = 3;
434653790Sobrien		msgptr[msglen++] = M_X_SYNC_REQ;
434753790Sobrien		msgptr[msglen++] = tp->tinfo.goal.period;
434853790Sobrien		msgptr[msglen++] = tp->tinfo.goal.offset;
434953790Sobrien		break;
435053790Sobrien	case NS_WIDE:
435153790Sobrien		msgptr[msglen++] = M_EXTENDED;
435253790Sobrien		msgptr[msglen++] = 2;
435353790Sobrien		msgptr[msglen++] = M_X_WIDE_REQ;
435453790Sobrien		msgptr[msglen++] = tp->tinfo.goal.width;
435553790Sobrien		break;
435653790Sobrien	case NS_PPR:
435753790Sobrien		msgptr[msglen++] = M_EXTENDED;
435853790Sobrien		msgptr[msglen++] = 6;
435953790Sobrien		msgptr[msglen++] = M_X_PPR_REQ;
436053790Sobrien		msgptr[msglen++] = tp->tinfo.goal.period;
436153790Sobrien		msgptr[msglen++] = 0;
436253790Sobrien		msgptr[msglen++] = tp->tinfo.goal.offset;
436353790Sobrien		msgptr[msglen++] = tp->tinfo.goal.width;
436453790Sobrien		msgptr[msglen++] = tp->tinfo.goal.options & PPR_OPT_DT;
436553790Sobrien		break;
436653790Sobrien	};
436753790Sobrien
436853790Sobrien	cp->nego_status = nego;
436953790Sobrien
437053790Sobrien	if (nego) {
437153790Sobrien		tp->nego_cp = cp; /* Keep track a nego will be performed */
437253790Sobrien		if (DEBUG_FLAGS & DEBUG_NEGO) {
437353809Sobrien			sym_print_msg(cp, nego == NS_SYNC ? "sync msgout" :
437453809Sobrien					  nego == NS_WIDE ? "wide msgout" :
437553809Sobrien					  "ppr msgout", msgptr);
437653790Sobrien		};
437753790Sobrien	};
437853790Sobrien
437953790Sobrien	return msglen;
438053790Sobrien}
438153790Sobrien
438253790Sobrien/*
438353790Sobrien *  Insert a job into the start queue.
438453790Sobrien */
438553790Sobrienstatic void sym_put_start_queue(hcb_p np, ccb_p cp)
438653790Sobrien{
438753790Sobrien	u_short	qidx;
438853790Sobrien
438954690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
439053790Sobrien	/*
439153790Sobrien	 *  If the previously queued CCB is not yet done,
439253790Sobrien	 *  set the IARB hint. The SCRIPTS will go with IARB
439353790Sobrien	 *  for this job when starting the previous one.
439453790Sobrien	 *  We leave devices a chance to win arbitration by
439553790Sobrien	 *  not using more than 'iarb_max' consecutive
439653790Sobrien	 *  immediate arbitrations.
439753790Sobrien	 */
439853790Sobrien	if (np->last_cp && np->iarb_count < np->iarb_max) {
439953790Sobrien		np->last_cp->host_flags |= HF_HINT_IARB;
440053790Sobrien		++np->iarb_count;
440153790Sobrien	}
440253790Sobrien	else
440353790Sobrien		np->iarb_count = 0;
440453790Sobrien	np->last_cp = cp;
440553790Sobrien#endif
440653790Sobrien
440753790Sobrien	/*
440853790Sobrien	 *  Insert first the idle task and then our job.
440953790Sobrien	 *  The MB should ensure proper ordering.
441053790Sobrien	 */
441153790Sobrien	qidx = np->squeueput + 2;
441253790Sobrien	if (qidx >= MAX_QUEUE*2) qidx = 0;
441353790Sobrien
441453790Sobrien	np->squeue [qidx]	   = cpu_to_scr(np->idletask_ba);
441553790Sobrien	MEMORY_BARRIER();
441653790Sobrien	np->squeue [np->squeueput] = cpu_to_scr(cp->ccb_ba);
441753790Sobrien
441853790Sobrien	np->squeueput = qidx;
441953790Sobrien
442053790Sobrien	if (DEBUG_FLAGS & DEBUG_QUEUE)
442153790Sobrien		printf ("%s: queuepos=%d.\n", sym_name (np), np->squeueput);
442253790Sobrien
442353790Sobrien	/*
442453790Sobrien	 *  Script processor may be waiting for reselect.
442553790Sobrien	 *  Wake it up.
442653790Sobrien	 */
442753790Sobrien	MEMORY_BARRIER();
442853790Sobrien	OUTB (nc_istat, SIGP|np->istat_sem);
442953790Sobrien}
443053790Sobrien
443153790Sobrien
443253790Sobrien/*
443353790Sobrien *  Soft reset the chip.
443453790Sobrien *
443553796Sobrien *  Raising SRST when the chip is running may cause
443655300Sgroudier *  problems on dual function chips (see below).
443755300Sgroudier *  On the other hand, LVD devices need some delay
443855300Sgroudier *  to settle and report actual BUS mode in STEST4.
443953796Sobrien */
444053796Sobrienstatic void sym_chip_reset (hcb_p np)
444153796Sobrien{
444253796Sobrien	OUTB (nc_istat, SRST);
444353796Sobrien	UDELAY (10);
444453796Sobrien	OUTB (nc_istat, 0);
444555300Sgroudier	UDELAY(2000);	/* For BUS MODE to settle */
444653796Sobrien}
444753796Sobrien
444853796Sobrien/*
444953796Sobrien *  Soft reset the chip.
445053796Sobrien *
445153790Sobrien *  Some 896 and 876 chip revisions may hang-up if we set
445253790Sobrien *  the SRST (soft reset) bit at the wrong time when SCRIPTS
445353790Sobrien *  are running.
445453790Sobrien *  So, we need to abort the current operation prior to
445553790Sobrien *  soft resetting the chip.
445653790Sobrien */
445753790Sobrienstatic void sym_soft_reset (hcb_p np)
445853790Sobrien{
445953790Sobrien	u_char istat;
446053790Sobrien	int i;
446153790Sobrien
446253790Sobrien	OUTB (nc_istat, CABRT);
446353790Sobrien	for (i = 1000000 ; i ; --i) {
446453790Sobrien		istat = INB (nc_istat);
446553790Sobrien		if (istat & SIP) {
446653790Sobrien			INW (nc_sist);
446753790Sobrien			continue;
446853790Sobrien		}
446953790Sobrien		if (istat & DIP) {
447053790Sobrien			OUTB (nc_istat, 0);
447153790Sobrien			INB (nc_dstat);
447253790Sobrien			break;
447353790Sobrien		}
447453790Sobrien	}
447553790Sobrien	if (!i)
447653790Sobrien		printf("%s: unable to abort current chip operation.\n",
447753790Sobrien			sym_name(np));
447853796Sobrien	sym_chip_reset (np);
447953790Sobrien}
448053790Sobrien
448153790Sobrien/*
448253790Sobrien *  Start reset process.
448353790Sobrien *
448453790Sobrien *  The interrupt handler will reinitialize the chip.
448553790Sobrien */
448653790Sobrienstatic void sym_start_reset(hcb_p np)
448753790Sobrien{
448853790Sobrien	(void) sym_reset_scsi_bus(np, 1);
448953790Sobrien}
449053790Sobrien
449153790Sobrienstatic int sym_reset_scsi_bus(hcb_p np, int enab_int)
449253790Sobrien{
449353790Sobrien	u32 term;
449453790Sobrien	int retv = 0;
449553790Sobrien
449653790Sobrien	sym_soft_reset(np);	/* Soft reset the chip */
449753790Sobrien	if (enab_int)
449853790Sobrien		OUTW (nc_sien, RST);
449953790Sobrien	/*
450053790Sobrien	 *  Enable Tolerant, reset IRQD if present and
450153790Sobrien	 *  properly set IRQ mode, prior to resetting the bus.
450253790Sobrien	 */
450353790Sobrien	OUTB (nc_stest3, TE);
450453790Sobrien	OUTB (nc_dcntl, (np->rv_dcntl & IRQM));
450553790Sobrien	OUTB (nc_scntl1, CRST);
450653790Sobrien	UDELAY (200);
450753790Sobrien
450854690Sobrien	if (!SYM_SETUP_SCSI_BUS_CHECK)
450953790Sobrien		goto out;
451053790Sobrien	/*
451153790Sobrien	 *  Check for no terminators or SCSI bus shorts to ground.
451253790Sobrien	 *  Read SCSI data bus, data parity bits and control signals.
451353790Sobrien	 *  We are expecting RESET to be TRUE and other signals to be
451453790Sobrien	 *  FALSE.
451553790Sobrien	 */
451655300Sgroudier	term =	INB(nc_sstat0);
451755300Sgroudier	term =	((term & 2) << 7) + ((term & 1) << 17);	/* rst sdp0 */
451855300Sgroudier	term |= ((INB(nc_sstat2) & 0x01) << 26) |	/* sdp1     */
451955300Sgroudier		((INW(nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */
452055300Sgroudier		((INW(nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
452155300Sgroudier		INB(nc_sbcl);	/* req ack bsy sel atn msg cd io    */
452253790Sobrien
452353790Sobrien	if (!(np->features & FE_WIDE))
452453790Sobrien		term &= 0x3ffff;
452553790Sobrien
452653790Sobrien	if (term != (2<<7)) {
452753790Sobrien		printf("%s: suspicious SCSI data while resetting the BUS.\n",
452853790Sobrien			sym_name(np));
452953790Sobrien		printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "
453053790Sobrien			"0x%lx, expecting 0x%lx\n",
453153790Sobrien			sym_name(np),
453253790Sobrien			(np->features & FE_WIDE) ? "dp1,d15-8," : "",
453353790Sobrien			(u_long)term, (u_long)(2<<7));
453454690Sobrien		if (SYM_SETUP_SCSI_BUS_CHECK == 1)
453553790Sobrien			retv = 1;
453653790Sobrien	}
453753790Sobrienout:
453853790Sobrien	OUTB (nc_scntl1, 0);
453953790Sobrien	/* MDELAY(100); */
454053790Sobrien	return retv;
454153790Sobrien}
454253790Sobrien
454353790Sobrien/*
454453790Sobrien *  The chip may have completed jobs. Look at the DONE QUEUE.
454553790Sobrien */
454653790Sobrienstatic int sym_wakeup_done (hcb_p np)
454753790Sobrien{
454853790Sobrien	ccb_p cp;
454953790Sobrien	int i, n;
455053790Sobrien	u_long dsa;
455153790Sobrien
455253790Sobrien	n = 0;
455353790Sobrien	i = np->dqueueget;
455453790Sobrien	while (1) {
455553790Sobrien		dsa = scr_to_cpu(np->dqueue[i]);
455653790Sobrien		if (!dsa)
455753790Sobrien			break;
455853790Sobrien		np->dqueue[i] = 0;
455953790Sobrien		if ((i = i+2) >= MAX_QUEUE*2)
456053790Sobrien			i = 0;
456153790Sobrien
456253790Sobrien		cp = sym_ccb_from_dsa(np, dsa);
456353790Sobrien		if (cp) {
456453790Sobrien			sym_complete_ok (np, cp);
456553790Sobrien			++n;
456653790Sobrien		}
456753790Sobrien		else
456853790Sobrien			printf ("%s: bad DSA (%lx) in done queue.\n",
456953790Sobrien				sym_name(np), dsa);
457053790Sobrien	}
457153790Sobrien	np->dqueueget = i;
457253790Sobrien
457353790Sobrien	return n;
457453790Sobrien}
457553790Sobrien
457653790Sobrien/*
457753790Sobrien *  Complete all active CCBs with error.
457853790Sobrien *  Used on CHIP/SCSI RESET.
457953790Sobrien */
458053790Sobrienstatic void sym_flush_busy_queue (hcb_p np, int cam_status)
458153790Sobrien{
458253790Sobrien	/*
458353790Sobrien	 *  Move all active CCBs to the COMP queue
458453790Sobrien	 *  and flush this queue.
458553790Sobrien	 */
458653790Sobrien	sym_que_splice(&np->busy_ccbq, &np->comp_ccbq);
458753790Sobrien	sym_que_init(&np->busy_ccbq);
458853790Sobrien	sym_flush_comp_queue(np, cam_status);
458953790Sobrien}
459053790Sobrien
459153790Sobrien/*
459253790Sobrien *  Start chip.
459355300Sgroudier *
459455300Sgroudier *  'reason' means:
459555300Sgroudier *     0: initialisation.
459655300Sgroudier *     1: SCSI BUS RESET delivered or received.
459755300Sgroudier *     2: SCSI BUS MODE changed.
459853790Sobrien */
459955300Sgroudierstatic void sym_init (hcb_p np, int reason)
460053790Sobrien{
460153790Sobrien 	int	i;
460253790Sobrien	u_long	phys;
460353790Sobrien
460453790Sobrien 	/*
460553790Sobrien	 *  Reset chip if asked, otherwise just clear fifos.
460653790Sobrien 	 */
460755300Sgroudier	if (reason == 1)
460853790Sobrien		sym_soft_reset(np);
460953790Sobrien	else {
461053790Sobrien		OUTB (nc_stest3, TE|CSF);
461153790Sobrien		OUTONB (nc_ctest3, CLF);
461253790Sobrien	}
461353790Sobrien
461453790Sobrien	/*
461553790Sobrien	 *  Clear Start Queue
461653790Sobrien	 */
461753790Sobrien	phys = vtobus(np->squeue);
461853790Sobrien	for (i = 0; i < MAX_QUEUE*2; i += 2) {
461953790Sobrien		np->squeue[i]   = cpu_to_scr(np->idletask_ba);
462053790Sobrien		np->squeue[i+1] = cpu_to_scr(phys + (i+2)*4);
462153790Sobrien	}
462253790Sobrien	np->squeue[MAX_QUEUE*2-1] = cpu_to_scr(phys);
462353790Sobrien
462453790Sobrien	/*
462553790Sobrien	 *  Start at first entry.
462653790Sobrien	 */
462753790Sobrien	np->squeueput = 0;
462853790Sobrien	np->scripth0->startpos[0] = cpu_to_scr(phys);
462953790Sobrien
463053790Sobrien	/*
463153790Sobrien	 *  Clear Done Queue
463253790Sobrien	 */
463353790Sobrien	phys = vtobus(np->dqueue);
463453790Sobrien	for (i = 0; i < MAX_QUEUE*2; i += 2) {
463553790Sobrien		np->dqueue[i]   = 0;
463653790Sobrien		np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4);
463753790Sobrien	}
463853790Sobrien	np->dqueue[MAX_QUEUE*2-1] = cpu_to_scr(phys);
463953790Sobrien
464053790Sobrien	/*
464153790Sobrien	 *  Start at first entry.
464253790Sobrien	 */
464353790Sobrien	np->scripth0->done_pos[0] = cpu_to_scr(phys);
464453790Sobrien	np->dqueueget = 0;
464553790Sobrien
464653790Sobrien	/*
464753790Sobrien	 *  Wakeup all pending jobs.
464853790Sobrien	 */
464953790Sobrien	sym_flush_busy_queue(np, CAM_SCSI_BUS_RESET);
465053790Sobrien
465153790Sobrien	/*
465253790Sobrien	 *  Init chip.
465353790Sobrien	 */
465453790Sobrien	OUTB (nc_istat,  0x00   );	/*  Remove Reset, abort */
465553790Sobrien	UDELAY (2000);	/* The 895 needs time for the bus mode to settle */
465653790Sobrien
465753790Sobrien	OUTB (nc_scntl0, np->rv_scntl0 | 0xc0);
465853790Sobrien					/*  full arb., ena parity, par->ATN  */
465953790Sobrien	OUTB (nc_scntl1, 0x00);		/*  odd parity, and remove CRST!! */
466053790Sobrien
466153790Sobrien	sym_selectclock(np, np->rv_scntl3);	/* Select SCSI clock */
466253790Sobrien
466353790Sobrien	OUTB (nc_scid  , RRE|np->myaddr);	/* Adapter SCSI address */
466453790Sobrien	OUTW (nc_respid, 1ul<<np->myaddr);	/* Id to respond to */
466553790Sobrien	OUTB (nc_istat , SIGP	);		/*  Signal Process */
466653790Sobrien	OUTB (nc_dmode , np->rv_dmode);		/* Burst length, dma mode */
466753790Sobrien	OUTB (nc_ctest5, np->rv_ctest5);	/* Large fifo + large burst */
466853790Sobrien
466953790Sobrien	OUTB (nc_dcntl , NOCOM|np->rv_dcntl);	/* Protect SFBR */
467053790Sobrien	OUTB (nc_ctest3, np->rv_ctest3);	/* Write and invalidate */
467153790Sobrien	OUTB (nc_ctest4, np->rv_ctest4);	/* Master parity checking */
467253790Sobrien
467353790Sobrien	/* Extended Sreq/Sack filtering not supported on the C10 */
467453790Sobrien	if (np->features & FE_C10)
467553790Sobrien		OUTB (nc_stest2, np->rv_stest2);
467653790Sobrien	else
467753790Sobrien		OUTB (nc_stest2, EXT|np->rv_stest2);
467853790Sobrien
467953790Sobrien	OUTB (nc_stest3, TE);			/* TolerANT enable */
468053790Sobrien	OUTB (nc_stime0, 0x0c);			/* HTH disabled  STO 0.25 sec */
468153790Sobrien
468253790Sobrien	/*
468353790Sobrien	 *  C10101 Errata.
468453790Sobrien	 *  Errant SGE's when in narrow. Write bits 4 & 5 of
468553790Sobrien	 *  STEST1 register to disable SGE. We probably should do
468653790Sobrien	 *  that from SCRIPTS for each selection/reselection, but
468753790Sobrien	 *  I just don't want. :)
468853790Sobrien	 */
468953790Sobrien	if (np->device_id == PCI_ID_LSI53C1010 && np->revision_id < 0x45)
469053790Sobrien		OUTB (nc_stest1, INB(nc_stest1) | 0x30);
469153790Sobrien
469253790Sobrien	/*
469353790Sobrien	 *  DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2.
469453790Sobrien	 *  Disable overlapped arbitration for some dual function devices,
469553790Sobrien	 *  regardless revision id (kind of post-chip-design feature. ;-))
469653790Sobrien	 */
469753790Sobrien	if (np->device_id == PCI_ID_SYM53C875)
469853790Sobrien		OUTB (nc_ctest0, (1<<5));
469953790Sobrien	else if (np->device_id == PCI_ID_SYM53C896)
470053790Sobrien		np->rv_ccntl0 |= DPR;
470153790Sobrien
470253790Sobrien	/*
470353790Sobrien	 *  If 64 bit (895A/896/1010) write CCNTL1 to enable 40 bit
470453790Sobrien	 *  address table indirect addressing for MOVE.
470553790Sobrien	 *  Also write CCNTL0 if 64 bit chip, since this register seems
470653790Sobrien	 *  to only be used by 64 bit cores.
470753790Sobrien	 */
470853790Sobrien	if (np->features & FE_64BIT) {
470953790Sobrien		OUTB (nc_ccntl0, np->rv_ccntl0);
471053790Sobrien		OUTB (nc_ccntl1, np->rv_ccntl1);
471153790Sobrien	}
471253790Sobrien
471353790Sobrien	/*
471453790Sobrien	 *  If phase mismatch handled by scripts (895A/896/1010),
471553790Sobrien	 *  set PM jump addresses.
471653790Sobrien	 */
471753790Sobrien	if (np->features & FE_NOPM) {
471853790Sobrien		OUTL (nc_pmjad1, SCRIPTH_BA (np, pm_handle));
471953790Sobrien		OUTL (nc_pmjad2, SCRIPTH_BA (np, pm_handle));
472053790Sobrien	}
472153790Sobrien
472253790Sobrien	/*
472353790Sobrien	 *    Enable GPIO0 pin for writing if LED support from SCRIPTS.
472453790Sobrien	 *    Also set GPIO5 and clear GPIO6 if hardware LED control.
472553790Sobrien	 */
472653790Sobrien	if (np->features & FE_LED0)
472753790Sobrien		OUTB(nc_gpcntl, INB(nc_gpcntl) & ~0x01);
472853790Sobrien	else if (np->features & FE_LEDC)
472953790Sobrien		OUTB(nc_gpcntl, (INB(nc_gpcntl) & ~0x41) | 0x20);
473053790Sobrien
473153790Sobrien	/*
473253790Sobrien	 *      enable ints
473353790Sobrien	 */
473453790Sobrien	OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR);
473553790Sobrien	OUTB (nc_dien , MDPE|BF|SSI|SIR|IID);
473653790Sobrien
473753790Sobrien	/*
473853790Sobrien	 *  For 895/6 enable SBMC interrupt and save current SCSI bus mode.
473955300Sgroudier	 *  Try to eat the spurious SBMC interrupt that may occur when
474055300Sgroudier	 *  we reset the chip but not the SCSI BUS (at initialization).
474153790Sobrien	 */
474253790Sobrien	if (np->features & (FE_ULTRA2|FE_ULTRA3)) {
474353790Sobrien		OUTONW (nc_sien, SBMC);
474455300Sgroudier		if (reason == 0) {
474555300Sgroudier			MDELAY(100);
474655300Sgroudier			INW (nc_sist);
474755300Sgroudier		}
474853790Sobrien		np->scsi_mode = INB (nc_stest4) & SMODE;
474953790Sobrien	}
475053790Sobrien
475153790Sobrien	/*
475253790Sobrien	 *  Fill in target structure.
475353790Sobrien	 *  Reinitialize usrsync.
475453790Sobrien	 *  Reinitialize usrwide.
475553790Sobrien	 *  Prepare sync negotiation according to actual SCSI bus mode.
475653790Sobrien	 */
475754690Sobrien	for (i=0;i<SYM_CONF_MAX_TARGET;i++) {
475853790Sobrien		tcb_p tp = &np->target[i];
475953790Sobrien
476053790Sobrien		tp->to_reset = 0;
476153790Sobrien		tp->sval    = 0;
476253790Sobrien		tp->wval    = np->rv_scntl3;
476353790Sobrien		tp->uval    = 0;
476453790Sobrien
476553790Sobrien		tp->tinfo.current.period = 0;
476653790Sobrien		tp->tinfo.current.offset = 0;
476753790Sobrien		tp->tinfo.current.width  = BUS_8_BIT;
476853790Sobrien		tp->tinfo.current.options = 0;
476953790Sobrien	}
477053790Sobrien
477153790Sobrien	/*
477253790Sobrien	 *  Download SCSI SCRIPTS to on-chip RAM if present,
477353790Sobrien	 *  and start script processor.
477453790Sobrien	 */
477553790Sobrien	if (np->ram_ba) {
477655300Sgroudier		if (sym_verbose > 1)
477753790Sobrien			printf ("%s: Downloading SCSI SCRIPTS.\n",
477853790Sobrien				sym_name(np));
477953790Sobrien		if (np->ram_ws == 8192) {
478053790Sobrien			memcpy_to_pci(np->ram_va + 4096,
478153790Sobrien					np->scripth0, sizeof(struct sym_scrh));
478253790Sobrien			OUTL (nc_mmws, np->scr_ram_seg);
478353790Sobrien			OUTL (nc_mmrs, np->scr_ram_seg);
478453790Sobrien			OUTL (nc_sfs,  np->scr_ram_seg);
478553790Sobrien			phys = SCRIPTH_BA (np, start64);
478653790Sobrien		}
478753790Sobrien		else
478853790Sobrien			phys = SCRIPT_BA (np, init);
478953790Sobrien		memcpy_to_pci(np->ram_va,np->script0,sizeof(struct sym_scr));
479053790Sobrien	}
479153790Sobrien	else
479253790Sobrien		phys = SCRIPT_BA (np, init);
479353790Sobrien
479453790Sobrien	np->istat_sem = 0;
479553790Sobrien
479653790Sobrien	MEMORY_BARRIER();
479753790Sobrien	OUTL (nc_dsa, vtobus(np));
479853790Sobrien	OUTL (nc_dsp, phys);
479953790Sobrien
480053790Sobrien	/*
480155300Sgroudier	 *  Notify the XPT about the RESET condition.
480253790Sobrien	 */
480355300Sgroudier	if (reason != 0)
480455300Sgroudier		xpt_async(AC_BUS_RESET, np->path, NULL);
480553790Sobrien}
480653790Sobrien
480753790Sobrien/*
480853790Sobrien *  Get clock factor and sync divisor for a given
480953790Sobrien *  synchronous factor period.
481053790Sobrien */
481153790Sobrienstatic int
481253790Sobriensym_getsync(hcb_p np, u_char dt, u_char sfac, u_char *divp, u_char *fakp)
481353790Sobrien{
481453790Sobrien	u32	clk = np->clock_khz;	/* SCSI clock frequency in kHz	*/
481553790Sobrien	int	div = np->clock_divn;	/* Number of divisors supported	*/
481653790Sobrien	u32	fak;			/* Sync factor in sxfer		*/
481753790Sobrien	u32	per;			/* Period in tenths of ns	*/
481853790Sobrien	u32	kpc;			/* (per * clk)			*/
481953790Sobrien	int	ret;
482053790Sobrien
482153790Sobrien	/*
482253790Sobrien	 *  Compute the synchronous period in tenths of nano-seconds
482353790Sobrien	 */
482453790Sobrien	if (dt && sfac <= 9)	per = 125;
482553790Sobrien	else if	(sfac <= 10)	per = 250;
482653790Sobrien	else if	(sfac == 11)	per = 303;
482753790Sobrien	else if	(sfac == 12)	per = 500;
482853790Sobrien	else			per = 40 * sfac;
482953790Sobrien	ret = per;
483053790Sobrien
483153790Sobrien	kpc = per * clk;
483253790Sobrien	if (dt)
483353790Sobrien		kpc <<= 1;
483453790Sobrien
483553790Sobrien	/*
483653790Sobrien	 *  For earliest C10, the extra clocks does not apply
483753790Sobrien	 *  to CRC cycles, so it may be safe not to use them.
483853790Sobrien	 *  Note that this limits the lowest sync data transfer
483953790Sobrien	 *  to 5 Mega-transfers per second and may result in
484053790Sobrien	 *  using higher clock divisors.
484153790Sobrien	 */
484253796Sobrien#if 1
484353790Sobrien	if ((np->features & (FE_C10|FE_U3EN)) == FE_C10) {
484453790Sobrien		/*
484553790Sobrien		 *  Look for the lowest clock divisor that allows an
484653790Sobrien		 *  output speed not faster than the period.
484753790Sobrien		 */
484853796Sobrien		while (div > 0) {
484953796Sobrien			--div;
485053790Sobrien			if (kpc > (div_10M[div] << 2)) {
485153790Sobrien				++div;
485253790Sobrien				break;
485353790Sobrien			}
485453790Sobrien		}
485553790Sobrien		fak = 0;			/* No extra clocks */
485653790Sobrien		if (div == np->clock_divn) {	/* Are we too fast ? */
485753790Sobrien			ret = -1;
485853790Sobrien		}
485953790Sobrien		*divp = div;
486053790Sobrien		*fakp = fak;
486153790Sobrien		return ret;
486253790Sobrien	}
486353790Sobrien#endif
486453790Sobrien
486553790Sobrien	/*
486653790Sobrien	 *  Look for the greatest clock divisor that allows an
486753790Sobrien	 *  input speed faster than the period.
486853790Sobrien	 */
486953796Sobrien	while (div-- > 0)
487053790Sobrien		if (kpc >= (div_10M[div] << 2)) break;
487153790Sobrien
487253790Sobrien	/*
487353790Sobrien	 *  Calculate the lowest clock factor that allows an output
487453790Sobrien	 *  speed not faster than the period, and the max output speed.
487553790Sobrien	 *  If fak >= 1 we will set both XCLKH_ST and XCLKH_DT.
487653790Sobrien	 *  If fak >= 2 we will also set XCLKS_ST and XCLKS_DT.
487753790Sobrien	 */
487853790Sobrien	if (dt) {
487953790Sobrien		fak = (kpc - 1) / (div_10M[div] << 1) + 1 - 2;
488053790Sobrien		/* ret = ((2+fak)*div_10M[div])/np->clock_khz; */
488153790Sobrien	}
488253790Sobrien	else {
488353790Sobrien		fak = (kpc - 1) / div_10M[div] + 1 - 4;
488453790Sobrien		/* ret = ((4+fak)*div_10M[div])/np->clock_khz; */
488553790Sobrien	}
488653790Sobrien
488753790Sobrien	/*
488853790Sobrien	 *  Check against our hardware limits, or bugs :).
488953790Sobrien	 */
489053790Sobrien	if (fak < 0)	{fak = 0; ret = -1;}
489153790Sobrien	if (fak > 2)	{fak = 2; ret = -1;}
489253790Sobrien
489353790Sobrien	/*
489453790Sobrien	 *  Compute and return sync parameters.
489553790Sobrien	 */
489653790Sobrien	*divp = div;
489753790Sobrien	*fakp = fak;
489853790Sobrien
489953790Sobrien	return ret;
490053790Sobrien}
490153790Sobrien
490253790Sobrien/*
490353790Sobrien *  We received a WDTR.
490453790Sobrien *  Let everything be aware of the changes.
490553790Sobrien */
490653790Sobrienstatic void sym_setwide(hcb_p np, ccb_p cp, u_char wide)
490753790Sobrien{
490853790Sobrien	struct	ccb_trans_settings neg;
490953790Sobrien	union ccb *ccb = cp->cam_ccb;
491053790Sobrien	tcb_p tp = &np->target[cp->target];
491153790Sobrien
491253790Sobrien	sym_settrans(np, cp, 0, 0, 0, wide, 0, 0);
491353790Sobrien
491453790Sobrien	/*
491553790Sobrien	 *  Tell the SCSI layer about the new transfer parameters.
491653790Sobrien	 */
491753790Sobrien	tp->tinfo.goal.width = tp->tinfo.current.width = wide;
491853796Sobrien	tp->tinfo.current.offset = 0;
491953796Sobrien	tp->tinfo.current.period = 0;
492053809Sobrien	tp->tinfo.current.options = 0;
492153790Sobrien	neg.bus_width = wide ? BUS_16_BIT : BUS_8_BIT;
492253796Sobrien	neg.sync_period = tp->tinfo.current.period;
492353796Sobrien	neg.sync_offset = tp->tinfo.current.offset;
492453790Sobrien	neg.valid = CCB_TRANS_BUS_WIDTH_VALID
492553790Sobrien		  | CCB_TRANS_SYNC_RATE_VALID
492653790Sobrien		  | CCB_TRANS_SYNC_OFFSET_VALID;
492753790Sobrien	xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1);
492853790Sobrien	xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
492953790Sobrien}
493053790Sobrien
493153790Sobrien/*
493253790Sobrien *  We received a SDTR.
493353790Sobrien *  Let everything be aware of the changes.
493453790Sobrien */
493553790Sobrienstatic void
493653790Sobriensym_setsync(hcb_p np, ccb_p cp, u_char ofs, u_char per, u_char div, u_char fak)
493753790Sobrien{
493853790Sobrien	struct	ccb_trans_settings neg;
493953790Sobrien	union ccb *ccb = cp->cam_ccb;
494053790Sobrien	tcb_p tp = &np->target[cp->target];
494153790Sobrien	u_char wide = (cp->phys.select.sel_scntl3 & EWS) ? 1 : 0;
494253790Sobrien
494353790Sobrien	sym_settrans(np, cp, 0, ofs, per, wide, div, fak);
494453790Sobrien
494553790Sobrien	/*
494653790Sobrien	 *  Tell the SCSI layer about the new transfer parameters.
494753790Sobrien	 */
494853790Sobrien	tp->tinfo.goal.period	= tp->tinfo.current.period  = per;
494953790Sobrien	tp->tinfo.goal.offset	= tp->tinfo.current.offset  = ofs;
495053790Sobrien	tp->tinfo.goal.options	= tp->tinfo.current.options = 0;
495153790Sobrien	neg.sync_period = tp->tinfo.current.period;
495253790Sobrien	neg.sync_offset = tp->tinfo.current.offset;
495353790Sobrien	neg.valid = CCB_TRANS_SYNC_RATE_VALID
495453790Sobrien		  | CCB_TRANS_SYNC_OFFSET_VALID;
495553790Sobrien	xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1);
495653790Sobrien	xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
495753790Sobrien}
495853790Sobrien
495953790Sobrien/*
496053790Sobrien *  We received a PPR.
496153790Sobrien *  Let everything be aware of the changes.
496253790Sobrien */
496353790Sobrienstatic void sym_setpprot(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
496453790Sobrien			 u_char per, u_char wide, u_char div, u_char fak)
496553790Sobrien{
496653790Sobrien	struct	ccb_trans_settings neg;
496753790Sobrien	union ccb *ccb = cp->cam_ccb;
496853790Sobrien	tcb_p tp = &np->target[cp->target];
496953790Sobrien
497053790Sobrien	sym_settrans(np, cp, dt, ofs, per, wide, div, fak);
497153790Sobrien
497253790Sobrien	/*
497353790Sobrien	 *  Tell the SCSI layer about the new transfer parameters.
497453790Sobrien	 */
497553790Sobrien	tp->tinfo.goal.width	= tp->tinfo.current.width  = wide;
497653790Sobrien	tp->tinfo.goal.period	= tp->tinfo.current.period = per;
497753790Sobrien	tp->tinfo.goal.offset	= tp->tinfo.current.offset = ofs;
497853809Sobrien	tp->tinfo.goal.options	= tp->tinfo.current.options = dt;
497953790Sobrien	neg.sync_period = tp->tinfo.current.period;
498053790Sobrien	neg.sync_offset = tp->tinfo.current.offset;
498153790Sobrien	neg.bus_width = wide ? BUS_16_BIT : BUS_8_BIT;
498253790Sobrien	neg.valid = CCB_TRANS_BUS_WIDTH_VALID
498353790Sobrien		  | CCB_TRANS_SYNC_RATE_VALID
498453790Sobrien		  | CCB_TRANS_SYNC_OFFSET_VALID;
498553790Sobrien	xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1);
498653790Sobrien	xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
498753790Sobrien}
498853790Sobrien
498954690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
499053790Sobrien/*
499153790Sobrien *  Patch a script address if it points to a data script to
499253790Sobrien *  the same position within another data script.
499353790Sobrien *  Accept up to endp + 8, due to the SCR_CALL
499453790Sobrien *  after end data script that moves to goalp.
499553790Sobrien */
499653790Sobrienstatic u32 sym_chgp(u32 scrp, u32 old_endp, u32 new_endp)
499753790Sobrien{
499853790Sobrien	scrp = scr_to_cpu(scrp);
499953790Sobrien	if (old_endp != new_endp &&
500054690Sobrien	    old_endp + 8 - scrp <= SYM_CONF_MAX_SG*8 + 8)
500153790Sobrien		scrp = new_endp + 8 - (old_endp + 8 - scrp);
500253790Sobrien	return cpu_to_scr(scrp);
500353790Sobrien}
500453790Sobrien
500553790Sobrien/*
500653790Sobrien *  Called on negotiation, since the device may have
500753790Sobrien *  changed mind about DT versus ST data transfers.
500853790Sobrien *  Patches all data scripts address for a CCB, to fit
500953790Sobrien *  the new data script, if needed.
501053790Sobrien */
501153790Sobrienstatic u32 sym_chg_ccb_scrp(hcb_p np, u_char dt, ccb_p cp, u32 scrp)
501253790Sobrien{
501353790Sobrien	u32 old_endp  = scr_to_cpu(cp->phys.goalp) - 8;
501453790Sobrien	u32 new_endp  = 0;
501553790Sobrien
501653790Sobrien	/*
501753790Sobrien	 *  Locate the data script we have to move to:
501853790Sobrien	 *  Given the end data script pointer value (old)
501953790Sobrien	 *  and the new type of transfert (DT/ST) deduce
502053790Sobrien	 *  the new end data script pointer(s).
502153790Sobrien	 */
502253790Sobrien	if (dt) {
502353790Sobrien		if	(old_endp == SCRIPT_BA(np, data_in2))
502453790Sobrien			new_endp  =  SCRIPTH_BA(np, dt_data_in2);
502553790Sobrien		else if	(old_endp == SCRIPT_BA(np, data_out2))
502653790Sobrien			new_endp  =  SCRIPTH_BA(np, dt_data_out2);
502753790Sobrien	}
502853790Sobrien	else {
502953790Sobrien		if	(old_endp == SCRIPTH_BA(np, dt_data_in2))
503053790Sobrien			new_endp  =  SCRIPT_BA(np, data_in2);
503153790Sobrien		else if	(old_endp == SCRIPTH_BA(np, dt_data_out2))
503253790Sobrien			new_endp  =  SCRIPT_BA(np, data_out2);
503353790Sobrien	}
503453790Sobrien	/*
503553790Sobrien	 *  If the end data script pointer was not
503653790Sobrien	 *  inside a data script or if we must stay
503753790Sobrien	 *  in the same data script, we are done.
503853790Sobrien	 */
503953790Sobrien	if (!new_endp || new_endp == old_endp)
504053790Sobrien		goto out;
504153790Sobrien
504253790Sobrien	/*
504353790Sobrien	 *  Move to new data script all data script pointers
504453790Sobrien	 *  that point inside the previous data script.
504553790Sobrien	 */
504653790Sobrien	cp->phys.savep	 = sym_chgp(cp->phys.savep,   old_endp, new_endp);
504753790Sobrien	cp->phys.lastp	 = sym_chgp(cp->phys.lastp,   old_endp, new_endp);
504853790Sobrien	cp->phys.goalp	 = sym_chgp(cp->phys.goalp,   old_endp, new_endp);
504953790Sobrien	cp->phys.pm0.ret = sym_chgp(cp->phys.pm0.ret, old_endp, new_endp);
505053790Sobrien	cp->phys.pm1.ret = sym_chgp(cp->phys.pm1.ret, old_endp, new_endp);
505153790Sobrien	cp->startp	 = sym_chgp(cp->startp,	      old_endp, new_endp);
505253790Sobrien
505353790Sobrien	/*
505453790Sobrien	 *  Also move an additionnal script pointer
505553790Sobrien	 *  if passed by user. For the current CCB,
505653790Sobrien	 *  this is useful to know the new value for
505753790Sobrien	 *  TEMP register (current data script address).
505853790Sobrien	 */
505953790Sobrien	if (scrp)
506053790Sobrien		scrp = scr_to_cpu(sym_chgp(scrp, old_endp, new_endp));
506153790Sobrienout:
506253790Sobrien	return scrp;
506353790Sobrien}
506454690Sobrien#endif	/* SYM_CONF_BROKEN_U3EN_SUPPORT */
506553790Sobrien
506653790Sobrien/*
506753790Sobrien *  Switch trans mode for current job and it's target.
506853790Sobrien */
506953790Sobrienstatic void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs,
507053790Sobrien			 u_char per, u_char wide, u_char div, u_char fak)
507153790Sobrien{
507255300Sgroudier	SYM_QUEHEAD *qp;
507353790Sobrien	union	ccb *ccb;
507453790Sobrien	tcb_p tp;
507553790Sobrien	u_char target = INB (nc_sdid) & 0x0f;
507653790Sobrien	u_char sval, wval, uval;
507753790Sobrien
507853790Sobrien	assert (cp);
507953790Sobrien	if (!cp) return;
508053790Sobrien	ccb = cp->cam_ccb;
508153790Sobrien	assert (ccb);
508253790Sobrien	if (!ccb) return;
508353790Sobrien	assert (target == (cp->target & 0xf));
508453790Sobrien	tp = &np->target[target];
508553790Sobrien
508653790Sobrien	sval = tp->sval;
508753790Sobrien	wval = tp->wval;
508853790Sobrien	uval = tp->uval;
508953790Sobrien#if 0
509053790Sobrien	printf("XXXXX sval=%x wval=%x uval=%x (%x)\n",
509153790Sobrien		sval, wval, uval, np->rv_scntl3);
509253790Sobrien#endif
509353790Sobrien	/*
509453790Sobrien	 *  Set the offset.
509553790Sobrien	 */
509653790Sobrien	if (!(np->features & FE_C10))
509753790Sobrien		sval = (sval & ~0x1f) | ofs;
509853790Sobrien	else
509953790Sobrien		sval = (sval & ~0x3f) | ofs;
510053790Sobrien
510153790Sobrien	/*
510253790Sobrien	 *  Set the sync divisor and extra clock factor.
510353790Sobrien	 */
510453790Sobrien	if (ofs != 0) {
510553790Sobrien		wval = (wval & ~0x70) | ((div+1) << 4);
510653790Sobrien		if (!(np->features & FE_C10))
510753790Sobrien			sval = (sval & ~0xe0) | (fak << 5);
510853790Sobrien		else {
510953790Sobrien			uval = uval & ~(XCLKH_ST|XCLKH_DT|XCLKS_ST|XCLKS_DT);
511053790Sobrien			if (fak >= 1) uval |= (XCLKH_ST|XCLKH_DT);
511153790Sobrien			if (fak >= 2) uval |= (XCLKS_ST|XCLKS_DT);
511253790Sobrien		}
511353790Sobrien	}
511453790Sobrien
511553790Sobrien	/*
511653790Sobrien	 *  Set the bus width.
511753790Sobrien	 */
511853790Sobrien	wval = wval & ~EWS;
511953790Sobrien	if (wide != 0)
512053790Sobrien		wval |= EWS;
512153790Sobrien
512253790Sobrien	/*
512353790Sobrien	 *  Set misc. ultra enable bits.
512453790Sobrien	 */
512553790Sobrien	if (np->features & FE_C10) {
512653790Sobrien		uval = uval & ~U3EN;
512754690Sobrien#ifndef	SYM_CONF_BROKEN_U3EN_SUPPORT
512853790Sobrien		if (dt)	{
512953790Sobrien			assert(np->features & FE_U3EN);
513053790Sobrien			uval |= U3EN;
513154690Sobrien		}
513253790Sobrien#endif
513353790Sobrien	}
513453790Sobrien	else {
513553790Sobrien		wval = wval & ~ULTRA;
513653790Sobrien		if (per <= 12)	wval |= ULTRA;
513753790Sobrien	}
513853790Sobrien
513953790Sobrien	/*
514053790Sobrien	 *   Stop there if sync parameters are unchanged.
514153790Sobrien	 */
514253790Sobrien	if (tp->sval == sval && tp->wval == wval && tp->uval == uval) return;
514353790Sobrien	tp->sval = sval;
514453790Sobrien	tp->wval = wval;
514553790Sobrien	tp->uval = uval;
514653790Sobrien
514753790Sobrien	/*
514853790Sobrien	 *  Disable extended Sreq/Sack filtering if per < 50.
514953790Sobrien	 *  Not supported on the C1010.
515053790Sobrien	 */
515153790Sobrien	if (per < 50 && !(np->features & FE_C10))
515253790Sobrien		OUTOFFB (nc_stest2, EXT);
515353790Sobrien
515453790Sobrien	/*
515553790Sobrien	 *  set actual value and sync_status
515653790Sobrien	 */
515753790Sobrien	OUTB (nc_sxfer, tp->sval);
515853790Sobrien	OUTB (nc_scntl3, tp->wval);
515953790Sobrien
516053790Sobrien	if (np->features & FE_C10) {
516154690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
516253790Sobrien		if (!(np->features & FE_U3EN)) {
516353790Sobrien			u32 temp = INL (nc_temp);
516453790Sobrien			temp = sym_chg_ccb_scrp(np, dt, cp, temp);
516553790Sobrien			OUTL (nc_temp, temp);
516653790Sobrien		}
516753790Sobrien#endif
516853790Sobrien		OUTB (nc_scntl4, tp->uval);
516953790Sobrien	}
517053790Sobrien
517153790Sobrien	/*
517255300Sgroudier	 *  patch ALL busy ccbs of this target.
517353790Sobrien	 */
517455300Sgroudier	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
517555300Sgroudier		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
517653790Sobrien		if (cp->target != target)
517753790Sobrien			continue;
517853790Sobrien		cp->phys.select.sel_scntl3 = tp->wval;
517953790Sobrien		cp->phys.select.sel_sxfer  = tp->sval;
518053790Sobrien		if (np->features & FE_C10) {
518153790Sobrien			cp->phys.select.sel_scntl4 = tp->uval;
518254690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
518353790Sobrien			if (!(np->features & FE_U3EN))
518453790Sobrien				(void) sym_chg_ccb_scrp(np, dt, cp, 0);
518553790Sobrien#endif
518653790Sobrien		}
518753790Sobrien	}
518853790Sobrien}
518953790Sobrien
519053790Sobrien/*
519153790Sobrien *  log message for real hard errors
519253790Sobrien *
519353790Sobrien *  sym0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc).
519453790Sobrien *  	      reg: r0 r1 r2 r3 r4 r5 r6 ..... rf.
519553790Sobrien *
519653790Sobrien *  exception register:
519753790Sobrien *  	ds:	dstat
519853790Sobrien *  	si:	sist
519953790Sobrien *
520053790Sobrien *  SCSI bus lines:
520153790Sobrien *  	so:	control lines as driven by chip.
520253790Sobrien *  	si:	control lines as seen by chip.
520353790Sobrien *  	sd:	scsi data lines as seen by chip.
520453790Sobrien *
520553790Sobrien *  wide/fastmode:
520653790Sobrien *  	sxfer:	(see the manual)
520753790Sobrien *  	scntl3:	(see the manual)
520853790Sobrien *
520953790Sobrien *  current script command:
521053790Sobrien *  	dsp:	script adress (relative to start of script).
521153790Sobrien *  	dbc:	first word of script command.
521253790Sobrien *
521353790Sobrien *  First 24 register of the chip:
521453790Sobrien *  	r0..rf
521553790Sobrien */
521653790Sobrienstatic void sym_log_hard_error(hcb_p np, u_short sist, u_char dstat)
521753790Sobrien{
521853790Sobrien	u32	dsp;
521953790Sobrien	int	script_ofs;
522053790Sobrien	int	script_size;
522153790Sobrien	char	*script_name;
522253790Sobrien	u_char	*script_base;
522353790Sobrien	int	i;
522453790Sobrien
522553790Sobrien	dsp	= INL (nc_dsp);
522653790Sobrien
522753790Sobrien	if (dsp > np->script_ba &&
522853790Sobrien	    dsp <= np->script_ba + sizeof(struct sym_scr)) {
522953790Sobrien		script_ofs	= dsp - np->script_ba;
523053790Sobrien		script_size	= sizeof(struct sym_scr);
523153790Sobrien		script_base	= (u_char *) np->script0;
523253790Sobrien		script_name	= "script";
523353790Sobrien	}
523453790Sobrien	else if (np->scripth_ba < dsp &&
523553790Sobrien		 dsp <= np->scripth_ba + sizeof(struct sym_scrh)) {
523653790Sobrien		script_ofs	= dsp - np->scripth_ba;
523753790Sobrien		script_size	= sizeof(struct sym_scrh);
523853790Sobrien		script_base	= (u_char *) np->scripth0;
523953790Sobrien		script_name	= "scripth";
524053790Sobrien	} else {
524153790Sobrien		script_ofs	= dsp;
524253790Sobrien		script_size	= 0;
524353790Sobrien		script_base	= 0;
524453790Sobrien		script_name	= "mem";
524553790Sobrien	}
524653790Sobrien
524753790Sobrien	printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n",
524853790Sobrien		sym_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist,
524953790Sobrien		(unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl),
525053790Sobrien		(unsigned)INB (nc_sbdl), (unsigned)INB (nc_sxfer),
525153790Sobrien		(unsigned)INB (nc_scntl3), script_name, script_ofs,
525253790Sobrien		(unsigned)INL (nc_dbc));
525353790Sobrien
525453790Sobrien	if (((script_ofs & 3) == 0) &&
525553790Sobrien	    (unsigned)script_ofs < script_size) {
525653790Sobrien		printf ("%s: script cmd = %08x\n", sym_name(np),
525753790Sobrien			scr_to_cpu((int) *(u32 *)(script_base + script_ofs)));
525853790Sobrien	}
525953790Sobrien
526053790Sobrien        printf ("%s: regdump:", sym_name(np));
526153790Sobrien        for (i=0; i<24;i++)
526253790Sobrien            printf (" %02x", (unsigned)INB_OFF(i));
526353790Sobrien        printf (".\n");
526453790Sobrien
526553790Sobrien	/*
526653790Sobrien	 *  PCI BUS error, read the PCI ststus register.
526753790Sobrien	 */
526853790Sobrien	if (dstat & (MDPE|BF)) {
526953790Sobrien		u_short pci_sts;
527053790Sobrien#ifdef FreeBSD_4_Bus
527153790Sobrien		pci_sts = pci_read_config(np->device, PCIR_STATUS, 2);
527253790Sobrien#else
527353790Sobrien		pci_sts = pci_cfgread(np->pci_tag, PCIR_STATUS, 2);
527453790Sobrien#endif
527553790Sobrien		if (pci_sts & 0xf900) {
527653790Sobrien#ifdef FreeBSD_4_Bus
527753790Sobrien			pci_write_config(np->device, PCIR_STATUS, pci_sts, 2);
527853790Sobrien#else
527953790Sobrien			pci_cfgwrite(np->pci_tag, PCIR_STATUS, pci_sts, 2);
528053790Sobrien#endif
528153790Sobrien			printf("%s: PCI STATUS = 0x%04x\n",
528253790Sobrien				sym_name(np), pci_sts & 0xf900);
528353790Sobrien		}
528453790Sobrien	}
528553790Sobrien}
528653790Sobrien
528753790Sobrien/*
528853790Sobrien *  chip interrupt handler
528953790Sobrien *
529053790Sobrien *  In normal situations, interrupt conditions occur one at
529153790Sobrien *  a time. But when something bad happens on the SCSI BUS,
529253790Sobrien *  the chip may raise several interrupt flags before
529353790Sobrien *  stopping and interrupting the CPU. The additionnal
529453790Sobrien *  interrupt flags are stacked in some extra registers
529553790Sobrien *  after the SIP and/or DIP flag has been raised in the
529653790Sobrien *  ISTAT. After the CPU has read the interrupt condition
529753790Sobrien *  flag from SIST or DSTAT, the chip unstacks the other
529853790Sobrien *  interrupt flags and sets the corresponding bits in
529953790Sobrien *  SIST or DSTAT. Since the chip starts stacking once the
530053790Sobrien *  SIP or DIP flag is set, there is a small window of time
530153790Sobrien *  where the stacking does not occur.
530253790Sobrien *
530353790Sobrien *  Typically, multiple interrupt conditions may happen in
530453790Sobrien *  the following situations:
530553790Sobrien *
530653790Sobrien *  - SCSI parity error + Phase mismatch  (PAR|MA)
530753790Sobrien *    When an parity error is detected in input phase
530853790Sobrien *    and the device switches to msg-in phase inside a
530953790Sobrien *    block MOV.
531053790Sobrien *  - SCSI parity error + Unexpected disconnect (PAR|UDC)
531153790Sobrien *    When a stupid device does not want to handle the
531253790Sobrien *    recovery of an SCSI parity error.
531353790Sobrien *  - Some combinations of STO, PAR, UDC, ...
531453790Sobrien *    When using non compliant SCSI stuff, when user is
531553790Sobrien *    doing non compliant hot tampering on the BUS, when
531653790Sobrien *    something really bad happens to a device, etc ...
531753790Sobrien *
531853790Sobrien *  The heuristic suggested by SYMBIOS to handle
531953790Sobrien *  multiple interrupts is to try unstacking all
532053790Sobrien *  interrupts conditions and to handle them on some
532153790Sobrien *  priority based on error severity.
532253790Sobrien *  This will work when the unstacking has been
532353790Sobrien *  successful, but we cannot be 100 % sure of that,
532453790Sobrien *  since the CPU may have been faster to unstack than
532553790Sobrien *  the chip is able to stack. Hmmm ... But it seems that
532653790Sobrien *  such a situation is very unlikely to happen.
532753790Sobrien *
532853790Sobrien *  If this happen, for example STO caught by the CPU
532953790Sobrien *  then UDC happenning before the CPU have restarted
533053790Sobrien *  the SCRIPTS, the driver may wrongly complete the
533153790Sobrien *  same command on UDC, since the SCRIPTS didn't restart
533253790Sobrien *  and the DSA still points to the same command.
533353790Sobrien *  We avoid this situation by setting the DSA to an
533453790Sobrien *  invalid value when the CCB is completed and before
533553790Sobrien *  restarting the SCRIPTS.
533653790Sobrien *
533753790Sobrien *  Another issue is that we need some section of our
533853790Sobrien *  recovery procedures to be somehow uninterruptible but
533953790Sobrien *  the SCRIPTS processor does not provides such a
534053790Sobrien *  feature. For this reason, we handle recovery preferently
534153790Sobrien *  from the C code and check against some SCRIPTS critical
534253790Sobrien *  sections from the C code.
534353790Sobrien *
534453790Sobrien *  Hopefully, the interrupt handling of the driver is now
534553790Sobrien *  able to resist to weird BUS error conditions, but donnot
534653790Sobrien *  ask me for any guarantee that it will never fail. :-)
534753790Sobrien *  Use at your own decision and risk.
534853790Sobrien */
534953790Sobrien
535053790Sobrienstatic void sym_intr1 (hcb_p np)
535153790Sobrien{
535253790Sobrien	u_char	istat, istatc;
535353790Sobrien	u_char	dstat;
535453790Sobrien	u_short	sist;
535553790Sobrien
535653790Sobrien	/*
535753790Sobrien	 *  interrupt on the fly ?
535853790Sobrien	 */
535953790Sobrien	istat = INB (nc_istat);
536053790Sobrien	if (istat & INTF) {
536153790Sobrien		OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem);
536253790Sobrien#if 1
536353790Sobrien		istat = INB (nc_istat);		/* DUMMY READ */
536453790Sobrien#endif
536553790Sobrien		if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
536653790Sobrien		(void)sym_wakeup_done (np);
536753790Sobrien	};
536853790Sobrien
536953790Sobrien	if (!(istat & (SIP|DIP)))
537053790Sobrien		return;
537153790Sobrien
537253790Sobrien#if 0	/* We should never get this one */
537353790Sobrien	if (istat & CABRT)
537453790Sobrien		OUTB (nc_istat, CABRT);
537553790Sobrien#endif
537653790Sobrien
537753790Sobrien	/*
537853790Sobrien	 *  PAR and MA interrupts may occur at the same time,
537953790Sobrien	 *  and we need to know of both in order to handle
538053790Sobrien	 *  this situation properly. We try to unstack SCSI
538153790Sobrien	 *  interrupts for that reason. BTW, I dislike a LOT
538253790Sobrien	 *  such a loop inside the interrupt routine.
538353790Sobrien	 *  Even if DMA interrupt stacking is very unlikely to
538453790Sobrien	 *  happen, we also try unstacking these ones, since
538553790Sobrien	 *  this has no performance impact.
538653790Sobrien	 */
538753790Sobrien	sist	= 0;
538853790Sobrien	dstat	= 0;
538953790Sobrien	istatc	= istat;
539053790Sobrien	do {
539153790Sobrien		if (istatc & SIP)
539253790Sobrien			sist  |= INW (nc_sist);
539353790Sobrien		if (istatc & DIP)
539453790Sobrien			dstat |= INB (nc_dstat);
539553790Sobrien		istatc = INB (nc_istat);
539653790Sobrien		istat |= istatc;
539753790Sobrien	} while (istatc & (SIP|DIP));
539853790Sobrien
539953790Sobrien	if (DEBUG_FLAGS & DEBUG_TINY)
540053790Sobrien		printf ("<%d|%x:%x|%x:%x>",
540153790Sobrien			(int)INB(nc_scr0),
540253790Sobrien			dstat,sist,
540353790Sobrien			(unsigned)INL(nc_dsp),
540453790Sobrien			(unsigned)INL(nc_dbc));
540553790Sobrien	/*
540653790Sobrien	 *  First, interrupts we want to service cleanly.
540753790Sobrien	 *
540853790Sobrien	 *  Phase mismatch (MA) is the most frequent interrupt
540953790Sobrien	 *  for chip earlier than the 896 and so we have to service
541053790Sobrien	 *  it as quickly as possible.
541153790Sobrien	 *  A SCSI parity error (PAR) may be combined with a phase
541253790Sobrien	 *  mismatch condition (MA).
541353790Sobrien	 *  Programmed interrupts (SIR) are used to call the C code
541453790Sobrien	 *  from SCRIPTS.
541553790Sobrien	 *  The single step interrupt (SSI) is not used in this
541653790Sobrien	 *  driver.
541753790Sobrien	 */
541853790Sobrien	if (!(sist  & (STO|GEN|HTH|SGE|UDC|SBMC|RST)) &&
541953790Sobrien	    !(dstat & (MDPE|BF|ABRT|IID))) {
542053790Sobrien		if	(sist & PAR)	sym_int_par (np, sist);
542153790Sobrien		else if (sist & MA)	sym_int_ma (np);
542253790Sobrien		else if (dstat & SIR)	sym_int_sir (np);
542353790Sobrien		else if (dstat & SSI)	OUTONB (nc_dcntl, (STD|NOCOM));
542453790Sobrien		else			goto unknown_int;
542553790Sobrien		return;
542653790Sobrien	};
542753790Sobrien
542853790Sobrien	/*
542953790Sobrien	 *  Now, interrupts that donnot happen in normal
543053790Sobrien	 *  situations and that we may need to recover from.
543153790Sobrien	 *
543253790Sobrien	 *  On SCSI RESET (RST), we reset everything.
543353790Sobrien	 *  On SCSI BUS MODE CHANGE (SBMC), we complete all
543453790Sobrien	 *  active CCBs with RESET status, prepare all devices
543553790Sobrien	 *  for negotiating again and restart the SCRIPTS.
543653790Sobrien	 *  On STO and UDC, we complete the CCB with the corres-
543753790Sobrien	 *  ponding status and restart the SCRIPTS.
543853790Sobrien	 */
543953790Sobrien	if (sist & RST) {
544055300Sgroudier		xpt_print_path(np->path);
544155300Sgroudier		printf("SCSI BUS reset detected.\n");
544255300Sgroudier		sym_init (np, 1);
544353790Sobrien		return;
544453790Sobrien	};
544553790Sobrien
544653790Sobrien	OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* clear dma fifo  */
544753790Sobrien	OUTB (nc_stest3, TE|CSF);		/* clear scsi fifo */
544853790Sobrien
544953790Sobrien	if (!(sist  & (GEN|HTH|SGE)) &&
545053790Sobrien	    !(dstat & (MDPE|BF|ABRT|IID))) {
545153790Sobrien		if	(sist & SBMC)	sym_int_sbmc (np);
545253790Sobrien		else if (sist & STO)	sym_int_sto (np);
545353790Sobrien		else if (sist & UDC)	sym_int_udc (np);
545453790Sobrien		else			goto unknown_int;
545553790Sobrien		return;
545653790Sobrien	};
545753790Sobrien
545853790Sobrien	/*
545953790Sobrien	 *  Now, interrupts we are not able to recover cleanly.
546053790Sobrien	 *
546153790Sobrien	 *  Log message for hard errors.
546253790Sobrien	 *  Reset everything.
546353790Sobrien	 */
546453790Sobrien
546553790Sobrien	sym_log_hard_error(np, sist, dstat);
546653790Sobrien
546753790Sobrien	if ((sist & (GEN|HTH|SGE)) ||
546853790Sobrien		(dstat & (MDPE|BF|ABRT|IID))) {
546953790Sobrien		sym_start_reset(np);
547053790Sobrien		return;
547153790Sobrien	};
547253790Sobrien
547353790Sobrienunknown_int:
547453790Sobrien	/*
547553790Sobrien	 *  We just miss the cause of the interrupt. :(
547653790Sobrien	 *  Print a message. The timeout will do the real work.
547753790Sobrien	 */
547853790Sobrien	printf(	"%s: unknown interrupt(s) ignored, "
547953790Sobrien		"ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n",
548053790Sobrien		sym_name(np), istat, dstat, sist);
548153790Sobrien}
548253790Sobrien
548353790Sobrienstatic void sym_intr(void *arg)
548453790Sobrien{
548553790Sobrien	if (DEBUG_FLAGS & DEBUG_TINY) printf ("[");
548653790Sobrien	sym_intr1((hcb_p) arg);
548753790Sobrien	if (DEBUG_FLAGS & DEBUG_TINY) printf ("]");
548853790Sobrien	return;
548953790Sobrien}
549053790Sobrien
549153790Sobrienstatic void sym_poll(struct cam_sim *sim)
549253790Sobrien{
549353790Sobrien	int s = splcam();
549453790Sobrien	sym_intr(cam_sim_softc(sim));
549553790Sobrien	splx(s);
549653790Sobrien}
549753790Sobrien
549853790Sobrien
549953790Sobrien/*
550053790Sobrien *  generic recovery from scsi interrupt
550153790Sobrien *
550253790Sobrien *  The doc says that when the chip gets an SCSI interrupt,
550353790Sobrien *  it tries to stop in an orderly fashion, by completing
550453790Sobrien *  an instruction fetch that had started or by flushing
550553790Sobrien *  the DMA fifo for a write to memory that was executing.
550653790Sobrien *  Such a fashion is not enough to know if the instruction
550753790Sobrien *  that was just before the current DSP value has been
550853790Sobrien *  executed or not.
550953790Sobrien *
551053790Sobrien *  There are some small SCRIPTS sections that deal with
551153790Sobrien *  the start queue and the done queue that may break any
551253790Sobrien *  assomption from the C code if we are interrupted
551353790Sobrien *  inside, so we reset if this happens. Btw, since these
551453790Sobrien *  SCRIPTS sections are executed while the SCRIPTS hasn't
551553790Sobrien *  started SCSI operations, it is very unlikely to happen.
551653790Sobrien *
551753790Sobrien *  All the driver data structures are supposed to be
551853790Sobrien *  allocated from the same 4 GB memory window, so there
551953790Sobrien *  is a 1 to 1 relationship between DSA and driver data
552053790Sobrien *  structures. Since we are careful :) to invalidate the
552153790Sobrien *  DSA when we complete a command or when the SCRIPTS
552253790Sobrien *  pushes a DSA into a queue, we can trust it when it
552353790Sobrien *  points to a CCB.
552453790Sobrien */
552553790Sobrienstatic void sym_recover_scsi_int (hcb_p np, u_char hsts)
552653790Sobrien{
552753790Sobrien	u32	dsp	= INL (nc_dsp);
552853790Sobrien	u32	dsa	= INL (nc_dsa);
552953790Sobrien	ccb_p cp	= sym_ccb_from_dsa(np, dsa);
553053790Sobrien
553153790Sobrien	/*
553253790Sobrien	 *  If we haven't been interrupted inside the SCRIPTS
553353790Sobrien	 *  critical pathes, we can safely restart the SCRIPTS
553453790Sobrien	 *  and trust the DSA value if it matches a CCB.
553553790Sobrien	 */
553653790Sobrien	if ((!(dsp > SCRIPT_BA (np, getjob_begin) &&
553753790Sobrien	       dsp < SCRIPT_BA (np, getjob_end) + 1)) &&
553853790Sobrien	    (!(dsp > SCRIPT_BA (np, ungetjob) &&
553953790Sobrien	       dsp < SCRIPT_BA (np, reselect) + 1)) &&
554053790Sobrien	    (!(dsp > SCRIPTH_BA (np, sel_for_abort) &&
554153790Sobrien	       dsp < SCRIPTH_BA (np, sel_for_abort_1) + 1)) &&
554253790Sobrien	    (!(dsp > SCRIPT_BA (np, done) &&
554353790Sobrien	       dsp < SCRIPT_BA (np, done_end) + 1))) {
554453790Sobrien		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* clear dma fifo  */
554553790Sobrien		OUTB (nc_stest3, TE|CSF);		/* clear scsi fifo */
554653790Sobrien		/*
554753790Sobrien		 *  If we have a CCB, let the SCRIPTS call us back for
554853790Sobrien		 *  the handling of the error with SCRATCHA filled with
554953790Sobrien		 *  STARTPOS. This way, we will be able to freeze the
555053790Sobrien		 *  device queue and requeue awaiting IOs.
555153790Sobrien		 */
555253790Sobrien		if (cp) {
555353790Sobrien			cp->host_status = hsts;
555453790Sobrien			OUTL (nc_dsp, SCRIPT_BA (np, complete_error));
555553790Sobrien		}
555653790Sobrien		/*
555753790Sobrien		 *  Otherwise just restart the SCRIPTS.
555853790Sobrien		 */
555953790Sobrien		else {
556053790Sobrien			OUTL (nc_dsa, 0xffffff);
556153790Sobrien			OUTL (nc_dsp, SCRIPT_BA (np, start));
556253790Sobrien		}
556353790Sobrien	}
556453790Sobrien	else
556553790Sobrien		goto reset_all;
556653790Sobrien
556753790Sobrien	return;
556853790Sobrien
556953790Sobrienreset_all:
557053790Sobrien	sym_start_reset(np);
557153790Sobrien}
557253790Sobrien
557353790Sobrien/*
557453790Sobrien *  chip exception handler for selection timeout
557553790Sobrien */
557653790Sobrienvoid sym_int_sto (hcb_p np)
557753790Sobrien{
557853790Sobrien	u32 dsp	= INL (nc_dsp);
557953790Sobrien
558053790Sobrien	if (DEBUG_FLAGS & DEBUG_TINY) printf ("T");
558153790Sobrien
558253790Sobrien	if (dsp == SCRIPT_BA (np, wf_sel_done) + 8)
558353790Sobrien		sym_recover_scsi_int(np, HS_SEL_TIMEOUT);
558453790Sobrien	else
558553790Sobrien		sym_start_reset(np);
558653790Sobrien}
558753790Sobrien
558853790Sobrien/*
558953790Sobrien *  chip exception handler for unexpected disconnect
559053790Sobrien */
559153790Sobrienvoid sym_int_udc (hcb_p np)
559253790Sobrien{
559353790Sobrien	printf ("%s: unexpected disconnect\n", sym_name(np));
559453790Sobrien	sym_recover_scsi_int(np, HS_UNEXPECTED);
559553790Sobrien}
559653790Sobrien
559753790Sobrien/*
559853790Sobrien *  chip exception handler for SCSI bus mode change
559953790Sobrien *
560053790Sobrien *  spi2-r12 11.2.3 says a transceiver mode change must
560153790Sobrien *  generate a reset event and a device that detects a reset
560253790Sobrien *  event shall initiate a hard reset. It says also that a
560353790Sobrien *  device that detects a mode change shall set data transfer
560453790Sobrien *  mode to eight bit asynchronous, etc...
560553790Sobrien *  So, just reinitializing all except chip should be enough.
560653790Sobrien */
560753790Sobrienstatic void sym_int_sbmc (hcb_p np)
560853790Sobrien{
560953790Sobrien	u_char scsi_mode = INB (nc_stest4) & SMODE;
561053790Sobrien
561155300Sgroudier	/*
561255300Sgroudier	 *  Notify user.
561355300Sgroudier	 */
561455300Sgroudier	xpt_print_path(np->path);
561555300Sgroudier	printf("SCSI BUS mode change from %s to %s.\n",
561655300Sgroudier		sym_scsi_bus_mode(np->scsi_mode), sym_scsi_bus_mode(scsi_mode));
561753790Sobrien
561853790Sobrien	/*
561955300Sgroudier	 *  Should suspend command processing for a few seconds and
562053790Sobrien	 *  reinitialize all except the chip.
562153790Sobrien	 */
562255300Sgroudier	sym_init (np, 2);
562353790Sobrien}
562453790Sobrien
562553790Sobrien/*
562653790Sobrien *  chip exception handler for SCSI parity error.
562753790Sobrien *
562853790Sobrien *  When the chip detects a SCSI parity error and is
562953790Sobrien *  currently executing a (CH)MOV instruction, it does
563053790Sobrien *  not interrupt immediately, but tries to finish the
563153790Sobrien *  transfer of the current scatter entry before
563253790Sobrien *  interrupting. The following situations may occur:
563353790Sobrien *
563453790Sobrien *  - The complete scatter entry has been transferred
563553790Sobrien *    without the device having changed phase.
563653790Sobrien *    The chip will then interrupt with the DSP pointing
563753790Sobrien *    to the instruction that follows the MOV.
563853790Sobrien *
563953790Sobrien *  - A phase mismatch occurs before the MOV finished
564053790Sobrien *    and phase errors are to be handled by the C code.
564153790Sobrien *    The chip will then interrupt with both PAR and MA
564253790Sobrien *    conditions set.
564353790Sobrien *
564453790Sobrien *  - A phase mismatch occurs before the MOV finished and
564553790Sobrien *    phase errors are to be handled by SCRIPTS.
564653790Sobrien *    The chip will load the DSP with the phase mismatch
564753790Sobrien *    JUMP address and interrupt the host processor.
564853790Sobrien */
564953790Sobrienstatic void sym_int_par (hcb_p np, u_short sist)
565053790Sobrien{
565153790Sobrien	u_char	hsts	= INB (HS_PRT);
565253790Sobrien	u32	dsp	= INL (nc_dsp);
565353790Sobrien	u32	dbc	= INL (nc_dbc);
565453790Sobrien	u32	dsa	= INL (nc_dsa);
565553790Sobrien	u_char	sbcl	= INB (nc_sbcl);
565653790Sobrien	u_char	cmd	= dbc >> 24;
565753790Sobrien	int phase	= cmd & 7;
565853790Sobrien	ccb_p	cp	= sym_ccb_from_dsa(np, dsa);
565953790Sobrien
566053790Sobrien	printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
566153790Sobrien		sym_name(np), hsts, dbc, sbcl);
566253790Sobrien
566353790Sobrien	/*
566453790Sobrien	 *  Check that the chip is connected to the SCSI BUS.
566553790Sobrien	 */
566653790Sobrien	if (!(INB (nc_scntl1) & ISCON)) {
566753790Sobrien		sym_recover_scsi_int(np, HS_UNEXPECTED);
566853790Sobrien		return;
566953790Sobrien	}
567053790Sobrien
567153790Sobrien	/*
567253790Sobrien	 *  If the nexus is not clearly identified, reset the bus.
567353790Sobrien	 *  We will try to do better later.
567453790Sobrien	 */
567553790Sobrien	if (!cp)
567653790Sobrien		goto reset_all;
567753790Sobrien
567853790Sobrien	/*
567953790Sobrien	 *  Check instruction was a MOV, direction was INPUT and
568053790Sobrien	 *  ATN is asserted.
568153790Sobrien	 */
568253790Sobrien	if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8))
568353790Sobrien		goto reset_all;
568453790Sobrien
568553790Sobrien	/*
568653790Sobrien	 *  Keep track of the parity error.
568753790Sobrien	 */
568853790Sobrien	OUTONB (HF_PRT, HF_EXT_ERR);
568953790Sobrien	cp->xerr_status |= XE_PARITY_ERR;
569053790Sobrien
569153790Sobrien	/*
569253790Sobrien	 *  Prepare the message to send to the device.
569353790Sobrien	 */
569453790Sobrien	np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR;
569553790Sobrien
569653790Sobrien	/*
569753790Sobrien	 *  If the old phase was DATA IN phase, we have to deal with
569853790Sobrien	 *  the 3 situations described above.
569953790Sobrien	 *  For other input phases (MSG IN and STATUS), the device
570053790Sobrien	 *  must resend the whole thing that failed parity checking
570153790Sobrien	 *  or signal error. So, jumping to dispatcher should be OK.
570253790Sobrien	 */
570353790Sobrien	if (phase == 1) {
570453790Sobrien		/* Phase mismatch handled by SCRIPTS */
570553790Sobrien		if (dsp == SCRIPTH_BA (np, pm_handle))
570653790Sobrien			OUTL (nc_dsp, dsp);
570753790Sobrien		/* Phase mismatch handled by the C code */
570853790Sobrien		else if (sist & MA)
570953790Sobrien			sym_int_ma (np);
571053790Sobrien		/* No phase mismatch occurred */
571153790Sobrien		else {
571253790Sobrien			OUTL (nc_temp, dsp);
571353790Sobrien			OUTL (nc_dsp, SCRIPT_BA (np, dispatch));
571453790Sobrien		}
571553790Sobrien	}
571653790Sobrien	else
571753790Sobrien		OUTL (nc_dsp, SCRIPT_BA (np, clrack));
571853790Sobrien	return;
571953790Sobrien
572053790Sobrienreset_all:
572153790Sobrien	sym_start_reset(np);
572253790Sobrien	return;
572353790Sobrien}
572453790Sobrien
572553790Sobrien/*
572653790Sobrien *  chip exception handler for phase errors.
572753790Sobrien *
572853790Sobrien *  We have to construct a new transfer descriptor,
572953790Sobrien *  to transfer the rest of the current block.
573053790Sobrien */
573153790Sobrienstatic void sym_int_ma (hcb_p np)
573253790Sobrien{
573353790Sobrien	u32	dbc;
573453790Sobrien	u32	rest;
573553790Sobrien	u32	dsp;
573653790Sobrien	u32	dsa;
573753790Sobrien	u32	nxtdsp;
573853790Sobrien	u32	*vdsp;
573953790Sobrien	u32	oadr, olen;
574053790Sobrien	u32	*tblp;
574153790Sobrien        u32	newcmd;
574253790Sobrien	u_int	delta;
574353790Sobrien	u_char	cmd;
574453790Sobrien	u_char	hflags, hflags0;
574553790Sobrien	struct	sym_pmc *pm;
574653790Sobrien	ccb_p	cp;
574753790Sobrien
574853790Sobrien	dsp	= INL (nc_dsp);
574953790Sobrien	dbc	= INL (nc_dbc);
575053790Sobrien	dsa	= INL (nc_dsa);
575153790Sobrien
575253790Sobrien	cmd	= dbc >> 24;
575353790Sobrien	rest	= dbc & 0xffffff;
575453790Sobrien	delta	= 0;
575553790Sobrien
575653790Sobrien	/*
575753790Sobrien	 *  locate matching cp if any.
575853790Sobrien	 */
575953790Sobrien	cp = sym_ccb_from_dsa(np, dsa);
576053790Sobrien
576153790Sobrien	/*
576253790Sobrien	 *  Donnot take into account dma fifo and various buffers in
576353790Sobrien	 *  INPUT phase since the chip flushes everything before
576453790Sobrien	 *  raising the MA interrupt for interrupted INPUT phases.
576553790Sobrien	 *  For DATA IN phase, we will check for the SWIDE later.
576653790Sobrien	 */
576753790Sobrien	if ((cmd & 7) != 1) {
576853790Sobrien		u_char ss0, ss2;
576953790Sobrien
577053790Sobrien		if (np->features & FE_DFBC)
577153790Sobrien			delta = INW (nc_dfbc);
577253790Sobrien		else {
577353790Sobrien			u32 dfifo;
577453790Sobrien
577553790Sobrien			/*
577653790Sobrien			 * Read DFIFO, CTEST[4-6] using 1 PCI bus ownership.
577753790Sobrien			 */
577853790Sobrien			dfifo = INL(nc_dfifo);
577953790Sobrien
578053790Sobrien			/*
578153790Sobrien			 *  Calculate remaining bytes in DMA fifo.
578253790Sobrien			 *  (CTEST5 = dfifo >> 16)
578353790Sobrien			 */
578453790Sobrien			if (dfifo & (DFS << 16))
578553790Sobrien				delta = ((((dfifo >> 8) & 0x300) |
578653790Sobrien				          (dfifo & 0xff)) - rest) & 0x3ff;
578753790Sobrien			else
578853790Sobrien				delta = ((dfifo & 0xff) - rest) & 0x7f;
578953790Sobrien		}
579053790Sobrien
579153790Sobrien		/*
579253790Sobrien		 *  The data in the dma fifo has not been transfered to
579353790Sobrien		 *  the target -> add the amount to the rest
579453790Sobrien		 *  and clear the data.
579553790Sobrien		 *  Check the sstat2 register in case of wide transfer.
579653790Sobrien		 */
579753790Sobrien		rest += delta;
579853790Sobrien		ss0  = INB (nc_sstat0);
579953790Sobrien		if (ss0 & OLF) rest++;
580053790Sobrien		if (!(np->features & FE_C10))
580153790Sobrien			if (ss0 & ORF) rest++;
580253790Sobrien		if (cp && (cp->phys.select.sel_scntl3 & EWS)) {
580353790Sobrien			ss2 = INB (nc_sstat2);
580453790Sobrien			if (ss2 & OLF1) rest++;
580553790Sobrien			if (!(np->features & FE_C10))
580653790Sobrien				if (ss2 & ORF1) rest++;
580753790Sobrien		};
580853790Sobrien
580953790Sobrien		/*
581053790Sobrien		 *  Clear fifos.
581153790Sobrien		 */
581253790Sobrien		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* dma fifo  */
581353790Sobrien		OUTB (nc_stest3, TE|CSF);		/* scsi fifo */
581453790Sobrien	}
581553790Sobrien
581653790Sobrien	/*
581753790Sobrien	 *  log the information
581853790Sobrien	 */
581953790Sobrien	if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
582053790Sobrien		printf ("P%x%x RL=%d D=%d ", cmd&7, INB(nc_sbcl)&7,
582153790Sobrien			(unsigned) rest, (unsigned) delta);
582253790Sobrien
582353790Sobrien	/*
582453790Sobrien	 *  try to find the interrupted script command,
582553790Sobrien	 *  and the address at which to continue.
582653790Sobrien	 */
582753790Sobrien	vdsp	= 0;
582853790Sobrien	nxtdsp	= 0;
582953790Sobrien	if	(dsp >  np->script_ba &&
583053790Sobrien		 dsp <= np->script_ba + sizeof(struct sym_scr)) {
583153790Sobrien		vdsp = (u32 *)((char*)np->script0 + (dsp-np->script_ba-8));
583253790Sobrien		nxtdsp = dsp;
583353790Sobrien	}
583453790Sobrien	else if	(dsp >  np->scripth_ba &&
583553790Sobrien		 dsp <= np->scripth_ba + sizeof(struct sym_scrh)) {
583653790Sobrien		vdsp = (u32 *)((char*)np->scripth0 + (dsp-np->scripth_ba-8));
583753790Sobrien		nxtdsp = dsp;
583853790Sobrien	}
583953790Sobrien
584053790Sobrien	/*
584153790Sobrien	 *  log the information
584253790Sobrien	 */
584353790Sobrien	if (DEBUG_FLAGS & DEBUG_PHASE) {
584453790Sobrien		printf ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
584553790Sobrien			cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd);
584653790Sobrien	};
584753790Sobrien
584853790Sobrien	if (!vdsp) {
584953790Sobrien		printf ("%s: interrupted SCRIPT address not found.\n",
585053790Sobrien			sym_name (np));
585153790Sobrien		goto reset_all;
585253790Sobrien	}
585353790Sobrien
585453790Sobrien	if (!cp) {
585553790Sobrien		printf ("%s: SCSI phase error fixup: CCB already dequeued.\n",
585653790Sobrien			sym_name (np));
585753790Sobrien		goto reset_all;
585853790Sobrien	}
585953790Sobrien
586053790Sobrien	/*
586153790Sobrien	 *  get old startaddress and old length.
586253790Sobrien	 */
586353790Sobrien	oadr = scr_to_cpu(vdsp[1]);
586453790Sobrien
586553790Sobrien	if (cmd & 0x10) {	/* Table indirect */
586653790Sobrien		tblp = (u32 *) ((char*) &cp->phys + oadr);
586753790Sobrien		olen = scr_to_cpu(tblp[0]);
586853790Sobrien		oadr = scr_to_cpu(tblp[1]);
586953790Sobrien	} else {
587053790Sobrien		tblp = (u32 *) 0;
587153790Sobrien		olen = scr_to_cpu(vdsp[0]) & 0xffffff;
587253790Sobrien	};
587353790Sobrien
587453790Sobrien	if (DEBUG_FLAGS & DEBUG_PHASE) {
587553790Sobrien		printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
587653790Sobrien			(unsigned) (scr_to_cpu(vdsp[0]) >> 24),
587753790Sobrien			tblp,
587853790Sobrien			(unsigned) olen,
587953790Sobrien			(unsigned) oadr);
588053790Sobrien	};
588153790Sobrien
588253790Sobrien	/*
588353790Sobrien	 *  check cmd against assumed interrupted script command.
588453790Sobrien	 */
588553790Sobrien	if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) {
588653790Sobrien		PRINT_ADDR(cp);
588753790Sobrien		printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
588853790Sobrien			(unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24);
588953790Sobrien
589053790Sobrien		goto reset_all;
589153790Sobrien	};
589253790Sobrien
589353790Sobrien	/*
589453790Sobrien	 *  if old phase not dataphase, leave here.
589553790Sobrien	 */
589653790Sobrien	if ((cmd & 5) != (cmd & 7)) {
589753790Sobrien		PRINT_ADDR(cp);
589853790Sobrien		printf ("phase change %x-%x %d@%08x resid=%d.\n",
589953790Sobrien			cmd&7, INB(nc_sbcl)&7, (unsigned)olen,
590053790Sobrien			(unsigned)oadr, (unsigned)rest);
590153790Sobrien		goto unexpected_phase;
590253790Sobrien	};
590353790Sobrien
590453790Sobrien	/*
590553790Sobrien	 *  Choose the correct PM save area.
590653790Sobrien	 *
590753790Sobrien	 *  Look at the PM_SAVE SCRIPT if you want to understand
590853790Sobrien	 *  this stuff. The equivalent code is implemented in
590953790Sobrien	 *  SCRIPTS for the 895A and 896 that are able to handle
591053790Sobrien	 *  PM from the SCRIPTS processor.
591153790Sobrien	 */
591253790Sobrien	hflags0 = INB (HF_PRT);
591353790Sobrien	hflags = hflags0;
591453790Sobrien
591553790Sobrien	if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) {
591653790Sobrien		if (hflags & HF_IN_PM0)
591753790Sobrien			nxtdsp = scr_to_cpu(cp->phys.pm0.ret);
591853790Sobrien		else if	(hflags & HF_IN_PM1)
591953790Sobrien			nxtdsp = scr_to_cpu(cp->phys.pm1.ret);
592053790Sobrien
592153790Sobrien		if (hflags & HF_DP_SAVED)
592253790Sobrien			hflags ^= HF_ACT_PM;
592353790Sobrien	}
592453790Sobrien
592553790Sobrien	if (!(hflags & HF_ACT_PM)) {
592653790Sobrien		pm = &cp->phys.pm0;
592753790Sobrien		newcmd = SCRIPT_BA(np, pm0_data);
592853790Sobrien	}
592953790Sobrien	else {
593053790Sobrien		pm = &cp->phys.pm1;
593153790Sobrien		newcmd = SCRIPT_BA(np, pm1_data);
593253790Sobrien	}
593353790Sobrien
593453790Sobrien	hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED);
593553790Sobrien	if (hflags != hflags0)
593653790Sobrien		OUTB (HF_PRT, hflags);
593753790Sobrien
593853790Sobrien	/*
593953790Sobrien	 *  fillin the phase mismatch context
594053790Sobrien	 */
594153790Sobrien	pm->sg.addr = cpu_to_scr(oadr + olen - rest);
594253790Sobrien	pm->sg.size = cpu_to_scr(rest);
594353790Sobrien	pm->ret     = cpu_to_scr(nxtdsp);
594453790Sobrien
594553790Sobrien	/*
594653790Sobrien	 *  If we have a SWIDE,
594753790Sobrien	 *  - prepare the address to write the SWIDE from SCRIPTS,
594853790Sobrien	 *  - compute the SCRIPTS address to restart from,
594953790Sobrien	 *  - move current data pointer context by one byte.
595053790Sobrien	 */
595153790Sobrien	nxtdsp = SCRIPT_BA (np, dispatch);
595253790Sobrien	if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) &&
595353790Sobrien	    (INB (nc_scntl2) & WSR)) {
595453790Sobrien		/*
595553790Sobrien		 *  Hmmm... The device may want to also ignore
595653790Sobrien		 *  this residue but it must send immediately the
595753790Sobrien		 *  appropriate message. We snoop the SCSI BUS
595853790Sobrien		 *  and will just throw away this message from
595953790Sobrien		 *  SCRIPTS if the SWIDE is to be ignored.
596053790Sobrien		 */
596153790Sobrien		if ((INB (nc_sbcl) & 7) == 7 &&
596253790Sobrien		    INB (nc_sbdl) == M_IGN_RESIDUE) {
596353790Sobrien			nxtdsp = SCRIPT_BA (np, ign_i_w_r_msg);
596453790Sobrien		}
596553790Sobrien		/*
596653790Sobrien		 *  We must grab the SWIDE.
596753790Sobrien		 *  We will use some complex SCRIPTS for that.
596853790Sobrien		 */
596953790Sobrien		else {
597053790Sobrien			OUTL (nc_scratcha, pm->sg.addr);
597153790Sobrien			nxtdsp = SCRIPTH_BA (np, swide_ma_32);
597253790Sobrien			if (np->features & FE_64BIT) {
597353790Sobrien				OUTB (nc_sbr, (pm->sg.size >> 24));
597453790Sobrien				nxtdsp = SCRIPTH_BA (np, swide_ma_64);
597553790Sobrien			}
597653790Sobrien			/*
597753790Sobrien			 *  Adjust our data pointer context.
597853790Sobrien			 */
597953790Sobrien			++pm->sg.addr;
598053790Sobrien			--pm->sg.size;
598153790Sobrien			/*
598253790Sobrien			 *  Hmmm... Could it be possible that a SWIDE that
598353790Sobrien			 *  is followed by a 1 byte CHMOV would lead to
598453790Sobrien			 *  a CHMOV(0). Anyway, we handle it by just
598553790Sobrien			 *  skipping context that would attempt a CHMOV(0).
598653790Sobrien			 */
598753790Sobrien			if (!pm->sg.size)
598853790Sobrien				newcmd = pm->ret;
598953790Sobrien		}
599053790Sobrien	}
599153790Sobrien
599253790Sobrien	if (DEBUG_FLAGS & DEBUG_PHASE) {
599353790Sobrien		PRINT_ADDR(cp);
599453790Sobrien		printf ("PM %x %x %x / %x %x %x.\n",
599553790Sobrien			hflags0, hflags, newcmd,
599653790Sobrien			(unsigned)scr_to_cpu(pm->sg.addr),
599753790Sobrien			(unsigned)scr_to_cpu(pm->sg.size),
599853790Sobrien			(unsigned)scr_to_cpu(pm->ret));
599953790Sobrien	}
600053790Sobrien
600153790Sobrien	/*
600253790Sobrien	 *  Restart the SCRIPTS processor.
600353790Sobrien	 */
600453790Sobrien	OUTL (nc_temp, newcmd);
600553790Sobrien	OUTL (nc_dsp,  nxtdsp);
600653790Sobrien	return;
600753790Sobrien
600853790Sobrien	/*
600953790Sobrien	 *  Unexpected phase changes that occurs when the current phase
601053790Sobrien	 *  is not a DATA IN or DATA OUT phase are due to error conditions.
601153790Sobrien	 *  Such event may only happen when the SCRIPTS is using a
601253790Sobrien	 *  multibyte SCSI MOVE.
601353790Sobrien	 *
601453790Sobrien	 *  Phase change		Some possible cause
601553790Sobrien	 *
601653790Sobrien	 *  COMMAND  --> MSG IN	SCSI parity error detected by target.
601753790Sobrien	 *  COMMAND  --> STATUS	Bad command or refused by target.
601853790Sobrien	 *  MSG OUT  --> MSG IN     Message rejected by target.
601953790Sobrien	 *  MSG OUT  --> COMMAND    Bogus target that discards extended
602053790Sobrien	 *  			negotiation messages.
602153790Sobrien	 *
602253790Sobrien	 *  The code below does not care of the new phase and so
602353790Sobrien	 *  trusts the target. Why to annoy it ?
602453790Sobrien	 *  If the interrupted phase is COMMAND phase, we restart at
602553790Sobrien	 *  dispatcher.
602653790Sobrien	 *  If a target does not get all the messages after selection,
602753790Sobrien	 *  the code assumes blindly that the target discards extended
602853790Sobrien	 *  messages and clears the negotiation status.
602953790Sobrien	 *  If the target does not want all our response to negotiation,
603053790Sobrien	 *  we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids
603153790Sobrien	 *  bloat for such a should_not_happen situation).
603253790Sobrien	 *  In all other situation, we reset the BUS.
603353790Sobrien	 *  Are these assumptions reasonnable ? (Wait and see ...)
603453790Sobrien	 */
603553790Sobrienunexpected_phase:
603653790Sobrien	dsp -= 8;
603753790Sobrien	nxtdsp = 0;
603853790Sobrien
603953790Sobrien	switch (cmd & 7) {
604053790Sobrien	case 2:	/* COMMAND phase */
604153790Sobrien		nxtdsp = SCRIPT_BA (np, dispatch);
604253790Sobrien		break;
604353790Sobrien#if 0
604453790Sobrien	case 3:	/* STATUS  phase */
604553790Sobrien		nxtdsp = SCRIPT_BA (np, dispatch);
604653790Sobrien		break;
604753790Sobrien#endif
604853790Sobrien	case 6:	/* MSG OUT phase */
604953790Sobrien		/*
605053790Sobrien		 *  If the device may want to use untagged when we want
605153790Sobrien		 *  tagged, we prepare an IDENTIFY without disc. granted,
605253790Sobrien		 *  since we will not be able to handle reselect.
605353790Sobrien		 *  Otherwise, we just don't care.
605453790Sobrien		 */
605553790Sobrien		if	(dsp == SCRIPT_BA (np, send_ident)) {
605653790Sobrien			if (cp->tag != NO_TAG && olen - rest <= 3) {
605753790Sobrien				cp->host_status = HS_BUSY;
605853790Sobrien				np->msgout[0] = M_IDENTIFY | cp->lun;
605953790Sobrien				nxtdsp = SCRIPTH_BA (np, ident_break_atn);
606053790Sobrien			}
606153790Sobrien			else
606253790Sobrien				nxtdsp = SCRIPTH_BA (np, ident_break);
606353790Sobrien		}
606453790Sobrien		else if	(dsp == SCRIPTH_BA (np, send_wdtr) ||
606553790Sobrien			 dsp == SCRIPTH_BA (np, send_sdtr) ||
606653790Sobrien			 dsp == SCRIPTH_BA (np, send_ppr)) {
606753790Sobrien			nxtdsp = SCRIPTH_BA (np, nego_bad_phase);
606853790Sobrien		}
606953790Sobrien		break;
607053790Sobrien#if 0
607153790Sobrien	case 7:	/* MSG IN  phase */
607253790Sobrien		nxtdsp = SCRIPT_BA (np, clrack);
607353790Sobrien		break;
607453790Sobrien#endif
607553790Sobrien	}
607653790Sobrien
607753790Sobrien	if (nxtdsp) {
607853790Sobrien		OUTL (nc_dsp, nxtdsp);
607953790Sobrien		return;
608053790Sobrien	}
608153790Sobrien
608253790Sobrienreset_all:
608353790Sobrien	sym_start_reset(np);
608453790Sobrien}
608553790Sobrien
608653790Sobrien/*
608753790Sobrien *  Dequeue from the START queue all CCBs that match
608853790Sobrien *  a given target/lun/task condition (-1 means all),
608953790Sobrien *  and move them from the BUSY queue to the COMP queue
609053790Sobrien *  with CAM_REQUEUE_REQ status condition.
609153790Sobrien *  This function is used during error handling/recovery.
609253790Sobrien *  It is called with SCRIPTS not running.
609353790Sobrien */
609453790Sobrienstatic int
609553790Sobriensym_dequeue_from_squeue(hcb_p np, int i, int target, int lun, int task)
609653790Sobrien{
609753790Sobrien	int j;
609853790Sobrien	ccb_p cp;
609953790Sobrien
610053790Sobrien	/*
610153790Sobrien	 *  Make sure the starting index is within range.
610253790Sobrien	 */
610353790Sobrien	assert((i >= 0) && (i < 2*MAX_QUEUE));
610453790Sobrien
610553790Sobrien	/*
610653790Sobrien	 *  Walk until end of START queue and dequeue every job
610753790Sobrien	 *  that matches the target/lun/task condition.
610853790Sobrien	 */
610953790Sobrien	j = i;
611053790Sobrien	while (i != np->squeueput) {
611153790Sobrien		cp = sym_ccb_from_dsa(np, scr_to_cpu(np->squeue[i]));
611253790Sobrien		assert(cp);
611354690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
611453790Sobrien		/* Forget hints for IARB, they may be no longer relevant */
611553790Sobrien		cp->host_flags &= ~HF_HINT_IARB;
611653790Sobrien#endif
611753790Sobrien		if ((target == -1 || cp->target == target) &&
611853790Sobrien		    (lun    == -1 || cp->lun    == lun)    &&
611953790Sobrien		    (task   == -1 || cp->tag    == task)) {
612053790Sobrien			sym_set_cam_status(cp->cam_ccb, CAM_REQUEUE_REQ);
612153790Sobrien			sym_remque(&cp->link_ccbq);
612253790Sobrien			sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
612353790Sobrien		}
612453790Sobrien		else {
612553790Sobrien			if (i != j)
612653790Sobrien				np->squeue[j] = np->squeue[i];
612753790Sobrien			if ((j += 2) >= MAX_QUEUE*2) j = 0;
612853790Sobrien		}
612953790Sobrien		if ((i += 2) >= MAX_QUEUE*2) i = 0;
613053790Sobrien	}
613153790Sobrien	if (i != j)		/* Copy back the idle task if needed */
613253790Sobrien		np->squeue[j] = np->squeue[i];
613353790Sobrien	np->squeueput = j;	/* Update our current start queue pointer */
613453790Sobrien
613553790Sobrien	return (i - j) / 2;
613653790Sobrien}
613753790Sobrien
613853790Sobrien/*
613953790Sobrien *  Complete all CCBs queued to the COMP queue.
614053790Sobrien *
614153790Sobrien *  These CCBs are assumed:
614253790Sobrien *  - Not to be referenced either by devices or
614353790Sobrien *    SCRIPTS-related queues and datas.
614453790Sobrien *  - To have to be completed with an error condition
614553790Sobrien *    or requeued.
614653790Sobrien *
614753790Sobrien *  The device queue freeze count is incremented
614853790Sobrien *  for each CCB that does not prevent this.
614953790Sobrien *  This function is called when all CCBs involved
615053790Sobrien *  in error handling/recovery have been reaped.
615153790Sobrien */
615253790Sobrienstatic void
615353790Sobriensym_flush_comp_queue(hcb_p np, int cam_status)
615453790Sobrien{
615553790Sobrien	SYM_QUEHEAD *qp;
615653790Sobrien	ccb_p cp;
615753790Sobrien
615853790Sobrien	while ((qp = sym_remque_head(&np->comp_ccbq)) != 0) {
615953790Sobrien		union ccb *ccb;
616053790Sobrien		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
616153790Sobrien		sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq);
616253790Sobrien		ccb = cp->cam_ccb;
616353790Sobrien		if (cam_status)
616453790Sobrien			sym_set_cam_status(ccb, cam_status);
616553790Sobrien		sym_free_ccb(np, cp);
616653790Sobrien		sym_freeze_cam_ccb(ccb);
616753790Sobrien		sym_xpt_done(np, ccb);
616853790Sobrien	}
616953790Sobrien}
617053790Sobrien
617153790Sobrien/*
617253790Sobrien *  chip handler for bad SCSI status condition
617353790Sobrien *
617453790Sobrien *  In case of bad SCSI status, we unqueue all the tasks
617553790Sobrien *  currently queued to the controller but not yet started
617653790Sobrien *  and then restart the SCRIPTS processor immediately.
617753790Sobrien *
617853790Sobrien *  QUEUE FULL and BUSY conditions are handled the same way.
617953790Sobrien *  Basically all the not yet started tasks are requeued in
618053790Sobrien *  device queue and the queue is frozen until a completion.
618153790Sobrien *
618253790Sobrien *  For CHECK CONDITION and COMMAND TERMINATED status, we use
618353790Sobrien *  the CCB of the failed command to prepare a REQUEST SENSE
618453790Sobrien *  SCSI command and queue it to the controller queue.
618553790Sobrien *
618653790Sobrien *  SCRATCHA is assumed to have been loaded with STARTPOS
618753790Sobrien *  before the SCRIPTS called the C code.
618853790Sobrien */
618953790Sobrienstatic void sym_sir_bad_scsi_status(hcb_p np, int num, ccb_p cp)
619053790Sobrien{
619153790Sobrien	tcb_p tp	= &np->target[cp->target];
619253790Sobrien	u32		startp;
619353790Sobrien	u_char		s_status = cp->ssss_status;
619453790Sobrien	u_char		h_flags  = cp->host_flags;
619553790Sobrien	int		msglen;
619653790Sobrien	int		nego;
619753790Sobrien	int		i;
619853790Sobrien
619953790Sobrien	/*
620053790Sobrien	 *  Compute the index of the next job to start from SCRIPTS.
620153790Sobrien	 */
620253790Sobrien	i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
620353790Sobrien
620453790Sobrien	/*
620553790Sobrien	 *  The last CCB queued used for IARB hint may be
620653790Sobrien	 *  no longer relevant. Forget it.
620753790Sobrien	 */
620854690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
620953790Sobrien	if (np->last_cp)
621053790Sobrien		np->last_cp = 0;
621153790Sobrien#endif
621253790Sobrien
621353790Sobrien	/*
621453790Sobrien	 *  Now deal with the SCSI status.
621553790Sobrien	 */
621653790Sobrien	switch(s_status) {
621753790Sobrien	case S_BUSY:
621853790Sobrien	case S_QUEUE_FULL:
621953790Sobrien		if (sym_verbose >= 2) {
622053790Sobrien			PRINT_ADDR(cp);
622153790Sobrien			printf (s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n");
622253790Sobrien		}
622353790Sobrien	default:	/* S_INT, S_INT_COND_MET, S_CONFLICT */
622453790Sobrien		sym_complete_error (np, cp);
622553790Sobrien		break;
622653790Sobrien	case S_TERMINATED:
622753790Sobrien	case S_CHECK_COND:
622853790Sobrien		/*
622953790Sobrien		 *  If we get an SCSI error when requesting sense, give up.
623053790Sobrien		 */
623153790Sobrien		if (h_flags & HF_SENSE) {
623253790Sobrien			sym_complete_error (np, cp);
623353790Sobrien			break;
623453790Sobrien		}
623553790Sobrien
623653790Sobrien		/*
623753790Sobrien		 *  Dequeue all queued CCBs for that device not yet started,
623853790Sobrien		 *  and restart the SCRIPTS processor immediately.
623953790Sobrien		 */
624053790Sobrien		(void) sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1);
624153790Sobrien		OUTL (nc_dsp, SCRIPT_BA (np, start));
624253790Sobrien
624353790Sobrien 		/*
624453790Sobrien		 *  Save some info of the actual IO.
624553790Sobrien		 *  Compute the data residual.
624653790Sobrien		 */
624753790Sobrien		cp->sv_scsi_status = cp->ssss_status;
624853790Sobrien		cp->sv_xerr_status = cp->xerr_status;
624953790Sobrien		cp->sv_resid = sym_compute_residual(np, cp);
625053790Sobrien
625153790Sobrien		/*
625253790Sobrien		 *  Prepare all needed data structures for
625353790Sobrien		 *  requesting sense data.
625453790Sobrien		 */
625553790Sobrien
625653790Sobrien		/*
625753790Sobrien		 *  identify message
625853790Sobrien		 */
625953790Sobrien		cp->scsi_smsg2[0] = M_IDENTIFY | cp->lun;
626053790Sobrien		msglen = 1;
626153790Sobrien
626253790Sobrien		/*
626353790Sobrien		 *  If we are currently using anything different from
626453790Sobrien		 *  async. 8 bit data transfers with that target,
626553790Sobrien		 *  start a negotiation, since the device may want
626653790Sobrien		 *  to report us a UNIT ATTENTION condition due to
626753790Sobrien		 *  a cause we currently ignore, and we donnot want
626853790Sobrien		 *  to be stuck with WIDE and/or SYNC data transfer.
626953790Sobrien		 *
627053790Sobrien		 *  cp->nego_status is filled by sym_prepare_nego().
627153790Sobrien		 */
627253790Sobrien		cp->nego_status = 0;
627353790Sobrien		nego = 0;
627453790Sobrien		if	(tp->tinfo.current.options & PPR_OPT_MASK)
627553790Sobrien			nego = NS_PPR;
627653790Sobrien		else if	(tp->tinfo.current.width != BUS_8_BIT)
627753790Sobrien			nego = NS_WIDE;
627853790Sobrien		else if (tp->tinfo.current.offset != 0)
627953790Sobrien			nego = NS_SYNC;
628053790Sobrien		if (nego)
628153790Sobrien			msglen +=
628253790Sobrien			sym_prepare_nego (np,cp, nego, &cp->scsi_smsg2[msglen]);
628353790Sobrien		/*
628453790Sobrien		 *  Message table indirect structure.
628553790Sobrien		 */
628653790Sobrien		cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
628753790Sobrien		cp->phys.smsg.size	= cpu_to_scr(msglen);
628853790Sobrien
628953790Sobrien		/*
629053790Sobrien		 *  sense command
629153790Sobrien		 */
629253790Sobrien		cp->phys.cmd.addr	= cpu_to_scr(CCB_PHYS (cp, sensecmd));
629353790Sobrien		cp->phys.cmd.size	= cpu_to_scr(6);
629453790Sobrien
629553790Sobrien		/*
629653790Sobrien		 *  patch requested size into sense command
629753790Sobrien		 */
629853790Sobrien		cp->sensecmd[0]		= 0x03;
629953790Sobrien		cp->sensecmd[1]		= cp->lun << 5;
630053790Sobrien		cp->sensecmd[4]		= cp->cam_ccb->csio.sense_len;
630153790Sobrien		cp->data_len		= cp->cam_ccb->csio.sense_len;
630253790Sobrien
630353790Sobrien		/*
630453790Sobrien		 *  sense data
630553790Sobrien		 */
630653790Sobrien		cp->phys.sense.addr	=
630753790Sobrien			cpu_to_scr(vtobus(&cp->cam_ccb->csio.sense_data));
630853790Sobrien		cp->phys.sense.size	=
630953790Sobrien			cpu_to_scr(cp->cam_ccb->csio.sense_len);
631053790Sobrien
631153790Sobrien		/*
631253790Sobrien		 *  requeue the command.
631353790Sobrien		 */
631453790Sobrien		startp = SCRIPTH_BA (np, sdata_in);
631553790Sobrien
631653790Sobrien		cp->phys.savep	= cpu_to_scr(startp);
631754690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
631853790Sobrien		cp->phys.goalp	= cpu_to_scr(startp + 40);
631953790Sobrien#else
632053790Sobrien		cp->phys.goalp	= cpu_to_scr(startp + 16);
632153790Sobrien#endif
632253790Sobrien		cp->phys.lastp	= cpu_to_scr(startp);
632353790Sobrien		cp->startp	= cpu_to_scr(startp);
632453790Sobrien
632553790Sobrien		cp->actualquirks = SYM_QUIRK_AUTOSAVE;
632653790Sobrien		cp->host_status	= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
632753790Sobrien		cp->ssss_status = S_ILLEGAL;
632853790Sobrien		cp->host_flags	= HF_SENSE;
632953790Sobrien		cp->xerr_status = 0;
633053790Sobrien		cp->phys.extra_bytes = 0;
633153790Sobrien
633253790Sobrien		cp->phys.go.start =
633353790Sobrien			cpu_to_scr(SCRIPT_BA (np, select));
633453790Sobrien
633553790Sobrien		/*
633653790Sobrien		 *  Requeue the command.
633753790Sobrien		 */
633853790Sobrien		sym_put_start_queue(np, cp);
633953790Sobrien
634053790Sobrien		/*
634153790Sobrien		 *  Give back to upper layer everything we have dequeued.
634253790Sobrien		 */
634353790Sobrien		sym_flush_comp_queue(np, 0);
634453790Sobrien		break;
634553790Sobrien	}
634653790Sobrien}
634753790Sobrien
634853790Sobrien/*
634953790Sobrien *  After a device has accepted some management message
635053790Sobrien *  as BUS DEVICE RESET, ABORT TASK, etc ..., or when
635153790Sobrien *  a device signals a UNIT ATTENTION condition, some
635253790Sobrien *  tasks are thrown away by the device. We are required
635353790Sobrien *  to reflect that on our tasks list since the device
635453790Sobrien *  will never complete these tasks.
635553790Sobrien *
635653790Sobrien *  This function move from the BUSY queue to the COMP
635753790Sobrien *  queue all disconnected CCBs for a given target that
635853790Sobrien *  match the following criteria:
635953790Sobrien *  - lun=-1  means any logical UNIT otherwise a given one.
636053790Sobrien *  - task=-1 means any task, otherwise a given one.
636153790Sobrien */
636253790Sobrienstatic int
636353790Sobriensym_clear_tasks(hcb_p np, int cam_status, int target, int lun, int task)
636453790Sobrien{
636553790Sobrien	SYM_QUEHEAD qtmp, *qp;
636653790Sobrien	int i = 0;
636753790Sobrien	ccb_p cp;
636853790Sobrien
636953790Sobrien	/*
637053790Sobrien	 *  Move the entire BUSY queue to our temporary queue.
637153790Sobrien	 */
637253790Sobrien	sym_que_init(&qtmp);
637353790Sobrien	sym_que_splice(&np->busy_ccbq, &qtmp);
637453790Sobrien	sym_que_init(&np->busy_ccbq);
637553790Sobrien
637653790Sobrien	/*
637753790Sobrien	 *  Put all CCBs that matches our criteria into
637853790Sobrien	 *  the COMP queue and put back other ones into
637953790Sobrien	 *  the BUSY queue.
638053790Sobrien	 */
638153790Sobrien	while ((qp = sym_remque_head(&qtmp)) != 0) {
638253790Sobrien		union ccb *ccb;
638353790Sobrien		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
638453790Sobrien		ccb = cp->cam_ccb;
638553790Sobrien		if (cp->host_status != HS_DISCONNECT ||
638653790Sobrien		    cp->target != target	     ||
638753790Sobrien		    (lun  != -1 && cp->lun != lun)   ||
638853790Sobrien		    (task != -1 &&
638953790Sobrien			(cp->tag != NO_TAG && cp->scsi_smsg[2] != task))) {
639053790Sobrien			sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq);
639153790Sobrien			continue;
639253790Sobrien		}
639353790Sobrien		sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
639453790Sobrien
639553790Sobrien		/* Preserve the software timeout condition */
639653790Sobrien		if (sym_get_cam_status(ccb) != CAM_CMD_TIMEOUT)
639753790Sobrien			sym_set_cam_status(ccb, cam_status);
639853790Sobrien		++i;
639953790Sobrien#if 0
640053790Sobrienprintf("XXXXX TASK @%p CLEARED\n", cp);
640153790Sobrien#endif
640253790Sobrien	}
640353790Sobrien	return i;
640453790Sobrien}
640553790Sobrien
640653790Sobrien/*
640753790Sobrien *  chip handler for TASKS recovery
640853790Sobrien *
640953790Sobrien *  We cannot safely abort a command, while the SCRIPTS
641053790Sobrien *  processor is running, since we just would be in race
641153790Sobrien *  with it.
641253790Sobrien *
641353790Sobrien *  As long as we have tasks to abort, we keep the SEM
641453790Sobrien *  bit set in the ISTAT. When this bit is set, the
641553790Sobrien *  SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED)
641653790Sobrien *  each time it enters the scheduler.
641753790Sobrien *
641853790Sobrien *  If we have to reset a target, clear tasks of a unit,
641953790Sobrien *  or to perform the abort of a disconnected job, we
642053790Sobrien *  restart the SCRIPTS for selecting the target. Once
642153790Sobrien *  selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED).
642253790Sobrien *  If it loses arbitration, the SCRIPTS will interrupt again
642353790Sobrien *  the next time it will enter its scheduler, and so on ...
642453790Sobrien *
642553790Sobrien *  On SIR_TARGET_SELECTED, we scan for the more
642653790Sobrien *  appropriate thing to do:
642753790Sobrien *
642853790Sobrien *  - If nothing, we just sent a M_ABORT message to the
642953790Sobrien *    target to get rid of the useless SCSI bus ownership.
643053790Sobrien *    According to the specs, no tasks shall be affected.
643153790Sobrien *  - If the target is to be reset, we send it a M_RESET
643253790Sobrien *    message.
643353790Sobrien *  - If a logical UNIT is to be cleared , we send the
643453790Sobrien *    IDENTIFY(lun) + M_ABORT.
643553790Sobrien *  - If an untagged task is to be aborted, we send the
643653790Sobrien *    IDENTIFY(lun) + M_ABORT.
643753790Sobrien *  - If a tagged task is to be aborted, we send the
643853790Sobrien *    IDENTIFY(lun) + task attributes + M_ABORT_TAG.
643953790Sobrien *
644053790Sobrien *  Once our 'kiss of death' :) message has been accepted
644153790Sobrien *  by the target, the SCRIPTS interrupts again
644253790Sobrien *  (SIR_ABORT_SENT). On this interrupt, we complete
644353790Sobrien *  all the CCBs that should have been aborted by the
644453790Sobrien *  target according to our message.
644553790Sobrien */
644653790Sobrienstatic void sym_sir_task_recovery(hcb_p np, int num)
644753790Sobrien{
644853790Sobrien	SYM_QUEHEAD *qp;
644953790Sobrien	ccb_p cp;
645053790Sobrien	tcb_p tp;
645153790Sobrien	int target=-1, lun=-1, task;
645253790Sobrien	int i, k;
645353790Sobrien
645453790Sobrien	switch(num) {
645553790Sobrien	/*
645653790Sobrien	 *  The SCRIPTS processor stopped before starting
645753790Sobrien	 *  the next command in order to allow us to perform
645853790Sobrien	 *  some task recovery.
645953790Sobrien	 */
646053790Sobrien	case SIR_SCRIPT_STOPPED:
646153790Sobrien		/*
646253790Sobrien		 *  Do we have any target to reset or unit to clear ?
646353790Sobrien		 */
646454690Sobrien		for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
646553790Sobrien			tp = &np->target[i];
646653790Sobrien			if (tp->to_reset ||
646753790Sobrien			    (tp->lun0p && tp->lun0p->to_clear)) {
646853790Sobrien				target = i;
646953790Sobrien				break;
647053790Sobrien			}
647153790Sobrien			if (!tp->lunmp)
647253790Sobrien				continue;
647354690Sobrien			for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) {
647453790Sobrien				if (tp->lunmp[k] && tp->lunmp[k]->to_clear) {
647553790Sobrien					target	= i;
647653790Sobrien					break;
647753790Sobrien				}
647853790Sobrien			}
647953790Sobrien			if (target != -1)
648053790Sobrien				break;
648153790Sobrien		}
648253790Sobrien
648353790Sobrien		/*
648453790Sobrien		 *  If not, walk the busy queue for any
648553790Sobrien		 *  disconnected CCB to be aborted.
648653790Sobrien		 */
648753790Sobrien		if (target == -1) {
648853790Sobrien			FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
648953790Sobrien				cp = sym_que_entry(qp,struct sym_ccb,link_ccbq);
649053790Sobrien				if (cp->host_status != HS_DISCONNECT)
649153790Sobrien					continue;
649253790Sobrien				if (cp->to_abort) {
649353790Sobrien					target = cp->target;
649453790Sobrien					break;
649553790Sobrien				}
649653790Sobrien			}
649753790Sobrien		}
649853790Sobrien
649953790Sobrien		/*
650053790Sobrien		 *  If some target is to be selected,
650153790Sobrien		 *  prepare and start the selection.
650253790Sobrien		 */
650353790Sobrien		if (target != -1) {
650453790Sobrien			tp = &np->target[target];
650553790Sobrien			np->abrt_sel.sel_id	= target;
650653790Sobrien			np->abrt_sel.sel_scntl3 = tp->wval;
650753790Sobrien			np->abrt_sel.sel_sxfer  = tp->sval;
650853790Sobrien			OUTL(nc_dsa, vtobus(np));
650953790Sobrien			OUTL (nc_dsp, SCRIPTH_BA (np, sel_for_abort));
651053790Sobrien			return;
651153790Sobrien		}
651253790Sobrien
651353790Sobrien		/*
651453790Sobrien		 *  Now look for a CCB to abort that haven't started yet.
651553790Sobrien		 *  Btw, the SCRIPTS processor is still stopped, so
651653790Sobrien		 *  we are not in race.
651753790Sobrien		 */
651853790Sobrien		i = 0;
651953790Sobrien		cp = 0;
652053790Sobrien		FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
652153790Sobrien			cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
652253790Sobrien			if (cp->host_status != HS_BUSY &&
652353790Sobrien			    cp->host_status != HS_NEGOTIATE)
652453790Sobrien				continue;
652553790Sobrien			if (!cp->to_abort)
652653790Sobrien				continue;
652754690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
652853790Sobrien			/*
652953790Sobrien			 *    If we are using IMMEDIATE ARBITRATION, we donnot
653053790Sobrien			 *    want to cancel the last queued CCB, since the
653153790Sobrien			 *    SCRIPTS may have anticipated the selection.
653253790Sobrien			 */
653353790Sobrien			if (cp == np->last_cp) {
653453790Sobrien				cp->to_abort = 0;
653553790Sobrien				continue;
653653790Sobrien			}
653753790Sobrien#endif
653853790Sobrien			i = 1;	/* Means we have found some */
653953790Sobrien			break;
654053790Sobrien		}
654153790Sobrien		if (!i) {
654253790Sobrien			/*
654353790Sobrien			 *  We are done, so we donnot need
654453790Sobrien			 *  to synchronize with the SCRIPTS anylonger.
654553790Sobrien			 *  Remove the SEM flag from the ISTAT.
654653790Sobrien			 */
654753790Sobrien			np->istat_sem = 0;
654853790Sobrien			OUTB (nc_istat, SIGP);
654953790Sobrien			break;
655053790Sobrien		}
655153790Sobrien		/*
655253790Sobrien		 *  Compute index of next position in the start
655353790Sobrien		 *  queue the SCRIPTS intends to start and dequeue
655453790Sobrien		 *  all CCBs for that device that haven't been started.
655553790Sobrien		 */
655653790Sobrien		i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
655753790Sobrien		i = sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1);
655853790Sobrien
655953790Sobrien		/*
656053790Sobrien		 *  Make sure at least our IO to abort has been dequeued.
656153790Sobrien		 */
656253790Sobrien		assert(i && sym_get_cam_status(cp->cam_ccb) == CAM_REQUEUE_REQ);
656353790Sobrien
656453790Sobrien		/*
656553790Sobrien		 *  Keep track in cam status of the reason of the abort.
656653790Sobrien		 */
656753790Sobrien		if (cp->to_abort == 2)
656853790Sobrien			sym_set_cam_status(cp->cam_ccb, CAM_CMD_TIMEOUT);
656953790Sobrien		else
657053790Sobrien			sym_set_cam_status(cp->cam_ccb, CAM_REQ_ABORTED);
657153790Sobrien
657253790Sobrien		/*
657353790Sobrien		 *  Complete with error everything that we have dequeued.
657453790Sobrien	 	 */
657553790Sobrien		sym_flush_comp_queue(np, 0);
657653790Sobrien		break;
657753790Sobrien	/*
657853790Sobrien	 *  The SCRIPTS processor has selected a target
657953790Sobrien	 *  we may have some manual recovery to perform for.
658053790Sobrien	 */
658153790Sobrien	case SIR_TARGET_SELECTED:
658253790Sobrien		target = (INB (nc_sdid) & 0xf);
658353790Sobrien		tp = &np->target[target];
658453790Sobrien
658553790Sobrien		np->abrt_tbl.addr = vtobus(np->abrt_msg);
658653790Sobrien
658753790Sobrien		/*
658853790Sobrien		 *  If the target is to be reset, prepare a
658953790Sobrien		 *  M_RESET message and clear the to_reset flag
659053790Sobrien		 *  since we donnot expect this operation to fail.
659153790Sobrien		 */
659253790Sobrien		if (tp->to_reset) {
659353790Sobrien			np->abrt_msg[0] = M_RESET;
659453790Sobrien			np->abrt_tbl.size = 1;
659553790Sobrien			tp->to_reset = 0;
659653790Sobrien			break;
659753790Sobrien		}
659853790Sobrien
659953790Sobrien		/*
660053790Sobrien		 *  Otherwise, look for some logical unit to be cleared.
660153790Sobrien		 */
660253790Sobrien		if (tp->lun0p && tp->lun0p->to_clear)
660353790Sobrien			lun = 0;
660453790Sobrien		else if (tp->lunmp) {
660554690Sobrien			for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) {
660653790Sobrien				if (tp->lunmp[k] && tp->lunmp[k]->to_clear) {
660753790Sobrien					lun = k;
660853790Sobrien					break;
660953790Sobrien				}
661053790Sobrien			}
661153790Sobrien		}
661253790Sobrien
661353790Sobrien		/*
661453790Sobrien		 *  If a logical unit is to be cleared, prepare
661553790Sobrien		 *  an IDENTIFY(lun) + ABORT MESSAGE.
661653790Sobrien		 */
661753790Sobrien		if (lun != -1) {
661853790Sobrien			lcb_p lp = sym_lp(np, tp, lun);
661953790Sobrien			lp->to_clear = 0; /* We donnot expect to fail here */
662053790Sobrien			np->abrt_msg[0] = M_IDENTIFY | lun;
662153790Sobrien			np->abrt_msg[1] = M_ABORT;
662253790Sobrien			np->abrt_tbl.size = 2;
662353790Sobrien			break;
662453790Sobrien		}
662553790Sobrien
662653790Sobrien		/*
662753790Sobrien		 *  Otherwise, look for some disconnected job to
662853790Sobrien		 *  abort for this target.
662953790Sobrien		 */
663053790Sobrien		i = 0;
663153790Sobrien		cp = 0;
663253790Sobrien		FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
663353790Sobrien			cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
663453790Sobrien			if (cp->host_status != HS_DISCONNECT)
663553790Sobrien				continue;
663653790Sobrien			if (cp->target != target)
663753790Sobrien				continue;
663853790Sobrien			if (!cp->to_abort)
663953790Sobrien				continue;
664053790Sobrien			i = 1;	/* Means we have some */
664153790Sobrien			break;
664253790Sobrien		}
664353790Sobrien
664453790Sobrien		/*
664553790Sobrien		 *  If we have none, probably since the device has
664653790Sobrien		 *  completed the command before we won abitration,
664753790Sobrien		 *  send a M_ABORT message without IDENTIFY.
664853790Sobrien		 *  According to the specs, the device must just
664953790Sobrien		 *  disconnect the BUS and not abort any task.
665053790Sobrien		 */
665153790Sobrien		if (!i) {
665253790Sobrien			np->abrt_msg[0] = M_ABORT;
665353790Sobrien			np->abrt_tbl.size = 1;
665453790Sobrien			break;
665553790Sobrien		}
665653790Sobrien
665753790Sobrien		/*
665853790Sobrien		 *  We have some task to abort.
665953790Sobrien		 *  Set the IDENTIFY(lun)
666053790Sobrien		 */
666153790Sobrien		np->abrt_msg[0] = M_IDENTIFY | cp->lun;
666253790Sobrien
666353790Sobrien		/*
666453790Sobrien		 *  If we want to abort an untagged command, we
666553790Sobrien		 *  will send a IDENTIFY + M_ABORT.
666653790Sobrien		 *  Otherwise (tagged command), we will send
666753790Sobrien		 *  a IDENTITFY + task attributes + ABORT TAG.
666853790Sobrien		 */
666953790Sobrien		if (cp->tag == NO_TAG) {
667053790Sobrien			np->abrt_msg[1] = M_ABORT;
667153790Sobrien			np->abrt_tbl.size = 2;
667253790Sobrien		}
667353790Sobrien		else {
667453790Sobrien			np->abrt_msg[1] = cp->scsi_smsg[1];
667553790Sobrien			np->abrt_msg[2] = cp->scsi_smsg[2];
667653790Sobrien			np->abrt_msg[3] = M_ABORT_TAG;
667753790Sobrien			np->abrt_tbl.size = 4;
667853790Sobrien		}
667953790Sobrien		/*
668053790Sobrien		 *  Keep track of software timeout condition, since the
668153790Sobrien		 *  peripheral driver may not count retries on abort
668253790Sobrien		 *  conditions not due to timeout.
668353790Sobrien		 */
668453790Sobrien		if (cp->to_abort == 2)
668553790Sobrien			sym_set_cam_status(cp->cam_ccb, CAM_CMD_TIMEOUT);
668653790Sobrien		cp->to_abort = 0; /* We donnot expect to fail here */
668753790Sobrien		break;
668853790Sobrien
668953790Sobrien	/*
669053790Sobrien	 *  The target has accepted our message and switched
669153790Sobrien	 *  to BUS FREE phase as we expected.
669253790Sobrien	 */
669353790Sobrien	case SIR_ABORT_SENT:
669453790Sobrien		target = (INB (nc_sdid) & 0xf);
669553790Sobrien		tp = &np->target[target];
669653790Sobrien
669753790Sobrien		/*
669853790Sobrien		**  If we didn't abort anything, leave here.
669953790Sobrien		*/
670053790Sobrien		if (np->abrt_msg[0] == M_ABORT)
670153790Sobrien			break;
670253790Sobrien
670353790Sobrien		/*
670453790Sobrien		 *  If we sent a M_RESET, then a hardware reset has
670553790Sobrien		 *  been performed by the target.
670653790Sobrien		 *  - Reset everything to async 8 bit
670753790Sobrien		 *  - Tell ourself to negotiate next time :-)
670853790Sobrien		 *  - Prepare to clear all disconnected CCBs for
670953790Sobrien		 *    this target from our task list (lun=task=-1)
671053790Sobrien		 */
671153790Sobrien		lun = -1;
671253790Sobrien		task = -1;
671353790Sobrien		if (np->abrt_msg[0] == M_RESET) {
671453790Sobrien			tp->sval = 0;
671553790Sobrien			tp->wval = np->rv_scntl3;
671653790Sobrien			tp->uval = 0;
671753790Sobrien			tp->tinfo.current.period = 0;
671853790Sobrien			tp->tinfo.current.offset = 0;
671953790Sobrien			tp->tinfo.current.width  = BUS_8_BIT;
672053790Sobrien			tp->tinfo.current.options = 0;
672153790Sobrien		}
672253790Sobrien
672353790Sobrien		/*
672453790Sobrien		 *  Otherwise, check for the LUN and TASK(s)
672553790Sobrien		 *  concerned by the cancelation.
672653790Sobrien		 *  If it is not ABORT_TAG then it is CLEAR_QUEUE
672753790Sobrien		 *  or an ABORT message :-)
672853790Sobrien		 */
672953790Sobrien		else {
673053790Sobrien			lun = np->abrt_msg[0] & 0x3f;
673153790Sobrien			if (np->abrt_msg[1] == M_ABORT_TAG)
673253790Sobrien				task = np->abrt_msg[2];
673353790Sobrien		}
673453790Sobrien
673553790Sobrien		/*
673653790Sobrien		 *  Complete all the CCBs the device should have
673753790Sobrien		 *  aborted due to our 'kiss of death' message.
673853790Sobrien		 */
673953790Sobrien		i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
674053790Sobrien		(void) sym_dequeue_from_squeue(np, i, target, lun, -1);
674153790Sobrien		(void) sym_clear_tasks(np, CAM_REQ_ABORTED, target, lun, task);
674253790Sobrien		sym_flush_comp_queue(np, 0);
674353790Sobrien
674453790Sobrien		/*
674553790Sobrien		 *  If we sent a BDR, make uper layer aware of that.
674653790Sobrien		 */
674753790Sobrien		if (np->abrt_msg[0] == M_RESET)
674853790Sobrien			xpt_async(AC_SENT_BDR, np->path, NULL);
674953790Sobrien		break;
675053790Sobrien	}
675153790Sobrien
675253790Sobrien	/*
675353790Sobrien	 *  Print to the log the message we intend to send.
675453790Sobrien	 */
675553790Sobrien	if (num == SIR_TARGET_SELECTED) {
675653790Sobrien		PRINT_TARGET(np, target);
675753790Sobrien		sym_printl_hex("control msgout:", np->abrt_msg,
675853790Sobrien			      np->abrt_tbl.size);
675953790Sobrien		np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size);
676053790Sobrien	}
676153790Sobrien
676253790Sobrien	/*
676353790Sobrien	 *  Let the SCRIPTS processor continue.
676453790Sobrien	 */
676553790Sobrien	OUTONB (nc_dcntl, (STD|NOCOM));
676653790Sobrien}
676753790Sobrien
676853790Sobrien/*
676953790Sobrien *  Gerard's alchemy:) that deals with with the data
677053790Sobrien *  pointer for both MDP and the residual calculation.
677153790Sobrien *
677253790Sobrien *  I didn't want to bloat the code by more than 200
677353790Sobrien *  lignes for the handling of both MDP and the residual.
677453790Sobrien *  This has been achieved by using a data pointer
677553790Sobrien *  representation consisting in an index in the data
677653790Sobrien *  array (dp_sg) and a negative offset (dp_ofs) that
677753790Sobrien *  have the following meaning:
677853790Sobrien *
677954690Sobrien *  - dp_sg = SYM_CONF_MAX_SG
678053790Sobrien *    we are at the end of the data script.
678154690Sobrien *  - dp_sg < SYM_CONF_MAX_SG
678253790Sobrien *    dp_sg points to the next entry of the scatter array
678353790Sobrien *    we want to transfer.
678453790Sobrien *  - dp_ofs < 0
678553790Sobrien *    dp_ofs represents the residual of bytes of the
678653790Sobrien *    previous entry scatter entry we will send first.
678753790Sobrien *  - dp_ofs = 0
678853790Sobrien *    no residual to send first.
678953790Sobrien *
679053790Sobrien *  The function sym_evaluate_dp() accepts an arbitray
679153790Sobrien *  offset (basically from the MDP message) and returns
679253790Sobrien *  the corresponding values of dp_sg and dp_ofs.
679353790Sobrien */
679453790Sobrien
679553790Sobrienstatic int sym_evaluate_dp(hcb_p np, ccb_p cp, u32 scr, int *ofs)
679653790Sobrien{
679753790Sobrien	u32	dp_scr;
679853790Sobrien	int	dp_ofs, dp_sg, dp_sgmin;
679953790Sobrien	int	tmp;
680053790Sobrien	struct sym_pmc *pm;
680153790Sobrien
680253790Sobrien	/*
680353790Sobrien	 *  Compute the resulted data pointer in term of a script
680453790Sobrien	 *  address within some DATA script and a signed byte offset.
680553790Sobrien	 */
680653790Sobrien	dp_scr = scr;
680753790Sobrien	dp_ofs = *ofs;
680853790Sobrien	if	(dp_scr == SCRIPT_BA (np, pm0_data))
680953790Sobrien		pm = &cp->phys.pm0;
681053790Sobrien	else if (dp_scr == SCRIPT_BA (np, pm1_data))
681153790Sobrien		pm = &cp->phys.pm1;
681253790Sobrien	else
681353790Sobrien		pm = 0;
681453790Sobrien
681553790Sobrien	if (pm) {
681653790Sobrien		dp_scr  = scr_to_cpu(pm->ret);
681753790Sobrien		dp_ofs -= scr_to_cpu(pm->sg.size);
681853790Sobrien	}
681953790Sobrien
682053790Sobrien	/*
682153790Sobrien	 *  If we are auto-sensing, then we are done.
682253790Sobrien	 */
682353790Sobrien	if (cp->host_flags & HF_SENSE) {
682453790Sobrien		*ofs = dp_ofs;
682553790Sobrien		return 0;
682653790Sobrien	}
682753790Sobrien
682853790Sobrien	/*
682953790Sobrien	 *  Deduce the index of the sg entry.
683053790Sobrien	 *  Keep track of the index of the first valid entry.
683154690Sobrien	 *  If result is dp_sg = SYM_CONF_MAX_SG, then we are at the
683253790Sobrien	 *  end of the data.
683353790Sobrien	 */
683453790Sobrien	tmp = scr_to_cpu(cp->phys.goalp);
683554690Sobrien	dp_sg = SYM_CONF_MAX_SG;
683653796Sobrien	if (dp_sg != tmp)
683753796Sobrien		dp_sg -= (tmp - 8 - (int)dp_scr) / (2*4);
683854690Sobrien	dp_sgmin = SYM_CONF_MAX_SG - cp->segments;
683953790Sobrien
684053790Sobrien	/*
684153790Sobrien	 *  Move to the sg entry the data pointer belongs to.
684253790Sobrien	 *
684353790Sobrien	 *  If we are inside the data area, we expect result to be:
684453790Sobrien	 *
684553790Sobrien	 *  Either,
684653790Sobrien	 *      dp_ofs = 0 and dp_sg is the index of the sg entry
684753790Sobrien	 *      the data pointer belongs to (or the end of the data)
684853790Sobrien	 *  Or,
684953790Sobrien	 *      dp_ofs < 0 and dp_sg is the index of the sg entry
685053790Sobrien	 *      the data pointer belongs to + 1.
685153790Sobrien	 */
685253790Sobrien	if (dp_ofs < 0) {
685353790Sobrien		int n;
685453790Sobrien		while (dp_sg > dp_sgmin) {
685553790Sobrien			--dp_sg;
685653790Sobrien			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
685753790Sobrien			n = dp_ofs + (tmp & 0xffffff);
685853790Sobrien			if (n > 0) {
685953790Sobrien				++dp_sg;
686053790Sobrien				break;
686153790Sobrien			}
686253790Sobrien			dp_ofs = n;
686353790Sobrien		}
686453790Sobrien	}
686553790Sobrien	else if (dp_ofs > 0) {
686654690Sobrien		while (dp_sg < SYM_CONF_MAX_SG) {
686753790Sobrien			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
686853790Sobrien			dp_ofs -= (tmp & 0xffffff);
686954690Sobrien			++dp_sg;
687053790Sobrien			if (dp_ofs <= 0)
687153790Sobrien				break;
687253790Sobrien		}
687353790Sobrien	}
687453790Sobrien
687553790Sobrien	/*
687653790Sobrien	 *  Make sure the data pointer is inside the data area.
687753790Sobrien	 *  If not, return some error.
687853790Sobrien	 */
687953790Sobrien	if	(dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0))
688053790Sobrien		goto out_err;
688154690Sobrien	else if	(dp_sg > SYM_CONF_MAX_SG ||
688254690Sobrien		 (dp_sg == SYM_CONF_MAX_SG && dp_ofs > 0))
688353790Sobrien		goto out_err;
688453790Sobrien
688553790Sobrien	/*
688653790Sobrien	 *  Save the extreme pointer if needed.
688753790Sobrien	 */
688853790Sobrien	if (dp_sg > cp->ext_sg ||
688953790Sobrien            (dp_sg == cp->ext_sg && dp_ofs > cp->ext_ofs)) {
689053790Sobrien		cp->ext_sg  = dp_sg;
689153790Sobrien		cp->ext_ofs = dp_ofs;
689253790Sobrien	}
689353790Sobrien
689453790Sobrien	/*
689553790Sobrien	 *  Return data.
689653790Sobrien	 */
689753790Sobrien	*ofs = dp_ofs;
689853790Sobrien	return dp_sg;
689953790Sobrien
690053790Sobrienout_err:
690153790Sobrien	return -1;
690253790Sobrien}
690353790Sobrien
690453790Sobrien/*
690553790Sobrien *  chip handler for MODIFY DATA POINTER MESSAGE
690653790Sobrien *
690753790Sobrien *  We also call this function on IGNORE WIDE RESIDUE
690853790Sobrien *  messages that do not match a SWIDE full condition.
690953790Sobrien *  Btw, we assume in that situation that such a message
691053790Sobrien *  is equivalent to a MODIFY DATA POINTER (offset=-1).
691153790Sobrien */
691253790Sobrien
691353790Sobrienstatic void sym_modify_dp(hcb_p np, tcb_p tp, ccb_p cp, int ofs)
691453790Sobrien{
691553790Sobrien	int dp_ofs	= ofs;
691653790Sobrien	u32	dp_scr	= INL (nc_temp);
691753790Sobrien	u32	dp_ret;
691853796Sobrien	u32	tmp;
691953790Sobrien	u_char	hflags;
692053790Sobrien	int	dp_sg;
692153790Sobrien	struct	sym_pmc *pm;
692253790Sobrien
692353790Sobrien	/*
692453790Sobrien	 *  Not supported for auto-sense.
692553790Sobrien	 */
692653790Sobrien	if (cp->host_flags & HF_SENSE)
692753790Sobrien		goto out_reject;
692853790Sobrien
692953790Sobrien	/*
693053790Sobrien	 *  Apply our alchemy:) (see comments in sym_evaluate_dp()),
693153790Sobrien	 *  to the resulted data pointer.
693253790Sobrien	 */
693353790Sobrien	dp_sg = sym_evaluate_dp(np, cp, dp_scr, &dp_ofs);
693453790Sobrien	if (dp_sg < 0)
693553790Sobrien		goto out_reject;
693653790Sobrien
693753790Sobrien	/*
693853790Sobrien	 *  And our alchemy:) allows to easily calculate the data
693953790Sobrien	 *  script address we want to return for the next data phase.
694053790Sobrien	 */
694153790Sobrien	dp_ret = cpu_to_scr(cp->phys.goalp);
694254690Sobrien	dp_ret = dp_ret - 8 - (SYM_CONF_MAX_SG - dp_sg) * (2*4);
694353790Sobrien
694453790Sobrien	/*
694553790Sobrien	 *  If offset / scatter entry is zero we donnot need
694653790Sobrien	 *  a context for the new current data pointer.
694753790Sobrien	 */
694853790Sobrien	if (dp_ofs == 0) {
694953790Sobrien		dp_scr = dp_ret;
695053790Sobrien		goto out_ok;
695153790Sobrien	}
695253790Sobrien
695353790Sobrien	/*
695453790Sobrien	 *  Get a context for the new current data pointer.
695553790Sobrien	 */
695653790Sobrien	hflags = INB (HF_PRT);
695753790Sobrien
695853790Sobrien	if (hflags & HF_DP_SAVED)
695953790Sobrien		hflags ^= HF_ACT_PM;
696053790Sobrien
696153790Sobrien	if (!(hflags & HF_ACT_PM)) {
696253790Sobrien		pm  = &cp->phys.pm0;
696353790Sobrien		dp_scr = SCRIPT_BA (np, pm0_data);
696453790Sobrien	}
696553790Sobrien	else {
696653790Sobrien		pm = &cp->phys.pm1;
696753790Sobrien		dp_scr = SCRIPT_BA (np, pm1_data);
696853790Sobrien	}
696953790Sobrien
697053790Sobrien	hflags &= ~(HF_DP_SAVED);
697153790Sobrien
697253790Sobrien	OUTB (HF_PRT, hflags);
697353790Sobrien
697453790Sobrien	/*
697553790Sobrien	 *  Set up the new current data pointer.
697653790Sobrien	 *  ofs < 0 there, and for the next data phase, we
697753790Sobrien	 *  want to transfer part of the data of the sg entry
697853790Sobrien	 *  corresponding to index dp_sg-1 prior to returning
697953790Sobrien	 *  to the main data script.
698053790Sobrien	 */
698153790Sobrien	pm->ret = cpu_to_scr(dp_ret);
698253796Sobrien	tmp  = scr_to_cpu(cp->phys.data[dp_sg-1].addr);
698353796Sobrien	tmp += scr_to_cpu(cp->phys.data[dp_sg-1].size) + dp_ofs;
698453796Sobrien	pm->sg.addr = cpu_to_scr(tmp);
698553796Sobrien	pm->sg.size = cpu_to_scr(-dp_ofs);
698653790Sobrien
698753790Sobrienout_ok:
698853790Sobrien	OUTL (nc_temp, dp_scr);
698953790Sobrien	OUTL (nc_dsp, SCRIPT_BA (np, clrack));
699053790Sobrien	return;
699153790Sobrien
699253790Sobrienout_reject:
699353790Sobrien	OUTL (nc_dsp, SCRIPTH_BA (np, msg_bad));
699453790Sobrien}
699553790Sobrien
699653790Sobrien
699753790Sobrien/*
699853790Sobrien *  chip calculation of the data residual.
699953790Sobrien *
700053790Sobrien *  As I used to say, the requirement of data residual
700153790Sobrien *  in SCSI is broken, useless and cannot be achieved
700253790Sobrien *  without huge complexity.
700353790Sobrien *  But most OSes and even the official CAM require it.
700453790Sobrien *  When stupidity happens to be so widely spread inside
700553790Sobrien *  a community, it gets hard to convince.
700653790Sobrien *
700753790Sobrien *  Anyway, I don't care, since I am not going to use
700853790Sobrien *  any software that considers this data residual as
700953790Sobrien *  a relevant information. :)
701053790Sobrien */
701153790Sobrien
701253790Sobrienstatic int sym_compute_residual(hcb_p np, ccb_p cp)
701353790Sobrien{
701453790Sobrien	int dp_sg, dp_sgmin, resid;
701553790Sobrien	int dp_ofs = 0;
701653790Sobrien
701753790Sobrien	/*
701853790Sobrien	 *  Check for some data lost or just thrown away.
701953790Sobrien	 *  We are not required to be quite accurate in this
702053790Sobrien	 *  situation. Btw, if we are odd for output and the
702153790Sobrien	 *  device claims some more data, it may well happen
702253790Sobrien	 *  than our residual be zero. :-)
702353790Sobrien	 */
702453790Sobrien	if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) {
702553790Sobrien		resid = 0;
702653790Sobrien		if (cp->xerr_status & XE_EXTRA_DATA)
702753790Sobrien			resid -= scr_to_cpu(cp->phys.extra_bytes);
702853790Sobrien		if (cp->xerr_status & XE_SODL_UNRUN)
702953790Sobrien			++resid;
703053790Sobrien		if (cp->xerr_status & XE_SWIDE_OVRUN)
703153790Sobrien			--resid;
703253790Sobrien	}
703353790Sobrien
703453790Sobrien	/*
703553790Sobrien	 *  If all data has been transferred,
703653790Sobrien	 *  there is no residual.
703753790Sobrien	 */
703853790Sobrien	if (cp->phys.lastp == cp->phys.goalp)
703953790Sobrien		return 0;
704053790Sobrien
704153790Sobrien	/*
704253790Sobrien	 *  If no data transfer occurs, or if the data
704353790Sobrien	 *  pointer is weird, return full residual.
704453790Sobrien	 */
704553790Sobrien	if (cp->startp == cp->phys.lastp ||
704653790Sobrien	    sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.lastp), &dp_ofs) < 0) {
704753790Sobrien		return cp->data_len;
704853790Sobrien	}
704953790Sobrien
705053790Sobrien	/*
705153790Sobrien	 *  If we were auto-sensing, then we are done.
705253790Sobrien	 */
705353790Sobrien	if (cp->host_flags & HF_SENSE) {
705453790Sobrien		return -dp_ofs;
705553790Sobrien	}
705653790Sobrien
705753790Sobrien	/*
705853790Sobrien	 *  We are now full comfortable in the computation
705953790Sobrien	 *  of the data residual (2's complement).
706053790Sobrien	 */
706154690Sobrien	dp_sgmin = SYM_CONF_MAX_SG - cp->segments;
706253790Sobrien	resid = -cp->ext_ofs;
706354690Sobrien	for (dp_sg = cp->ext_sg; dp_sg < SYM_CONF_MAX_SG; ++dp_sg) {
706453790Sobrien		u_long tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
706553790Sobrien		resid += (tmp & 0xffffff);
706653790Sobrien	}
706753790Sobrien
706853790Sobrien	/*
706953790Sobrien	 *  Hopefully, the result is not too wrong.
707053790Sobrien	 */
707153790Sobrien	return resid;
707253790Sobrien}
707353790Sobrien
707453790Sobrien/*
707553790Sobrien *  Print out the containt of a SCSI message.
707653790Sobrien */
707753790Sobrien
707853790Sobrienstatic int sym_show_msg (u_char * msg)
707953790Sobrien{
708053790Sobrien	u_char i;
708153790Sobrien	printf ("%x",*msg);
708253790Sobrien	if (*msg==M_EXTENDED) {
708353790Sobrien		for (i=1;i<8;i++) {
708453790Sobrien			if (i-1>msg[1]) break;
708553790Sobrien			printf ("-%x",msg[i]);
708653790Sobrien		};
708753790Sobrien		return (i+1);
708853790Sobrien	} else if ((*msg & 0xf0) == 0x20) {
708953790Sobrien		printf ("-%x",msg[1]);
709053790Sobrien		return (2);
709153790Sobrien	};
709253790Sobrien	return (1);
709353790Sobrien}
709453790Sobrien
709553790Sobrienstatic void sym_print_msg (ccb_p cp, char *label, u_char *msg)
709653790Sobrien{
709753790Sobrien	PRINT_ADDR(cp);
709853790Sobrien	if (label)
709953790Sobrien		printf ("%s: ", label);
710053790Sobrien
710153790Sobrien	(void) sym_show_msg (msg);
710253790Sobrien	printf (".\n");
710353790Sobrien}
710453790Sobrien
710553790Sobrien/*
710653790Sobrien *  Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER.
710753790Sobrien *
710853790Sobrien *  We try to negotiate sync and wide transfer only after
710953790Sobrien *  a successfull inquire command. We look at byte 7 of the
711053790Sobrien *  inquire data to determine the capabilities of the target.
711153790Sobrien *
711253790Sobrien *  When we try to negotiate, we append the negotiation message
711353790Sobrien *  to the identify and (maybe) simple tag message.
711453790Sobrien *  The host status field is set to HS_NEGOTIATE to mark this
711553790Sobrien *  situation.
711653790Sobrien *
711753790Sobrien *  If the target doesn't answer this message immediately
711853790Sobrien *  (as required by the standard), the SIR_NEGO_FAILED interrupt
711953790Sobrien *  will be raised eventually.
712053790Sobrien *  The handler removes the HS_NEGOTIATE status, and sets the
712153790Sobrien *  negotiated value to the default (async / nowide).
712253790Sobrien *
712353790Sobrien *  If we receive a matching answer immediately, we check it
712453790Sobrien *  for validity, and set the values.
712553790Sobrien *
712653790Sobrien *  If we receive a Reject message immediately, we assume the
712753790Sobrien *  negotiation has failed, and fall back to standard values.
712853790Sobrien *
712953790Sobrien *  If we receive a negotiation message while not in HS_NEGOTIATE
713053790Sobrien *  state, it's a target initiated negotiation. We prepare a
713153790Sobrien *  (hopefully) valid answer, set our parameters, and send back
713253790Sobrien *  this answer to the target.
713353790Sobrien *
713453790Sobrien *  If the target doesn't fetch the answer (no message out phase),
713553790Sobrien *  we assume the negotiation has failed, and fall back to default
713653790Sobrien *  settings (SIR_NEGO_PROTO interrupt).
713753790Sobrien *
713853790Sobrien *  When we set the values, we adjust them in all ccbs belonging
713953790Sobrien *  to this target, in the controller's register, and in the "phys"
714053790Sobrien *  field of the controller's struct sym_hcb.
714153790Sobrien */
714253790Sobrien
714353790Sobrien/*
714453790Sobrien *  chip handler for SYNCHRONOUS DATA TRANSFER REQUEST (SDTR) message.
714553790Sobrien */
714653790Sobrienstatic void sym_sync_nego(hcb_p np, tcb_p tp, ccb_p cp)
714753790Sobrien{
714853790Sobrien	u_char	chg, ofs, per, fak, div;
714953790Sobrien	int	req = 1;
715053790Sobrien
715153790Sobrien	/*
715253790Sobrien	 *  Synchronous request message received.
715353790Sobrien	 */
715453790Sobrien	if (DEBUG_FLAGS & DEBUG_NEGO) {
715553809Sobrien		sym_print_msg(cp, "sync msgin", np->msgin);
715653790Sobrien	};
715753790Sobrien
715853790Sobrien	/*
715953790Sobrien	 * request or answer ?
716053790Sobrien	 */
716153790Sobrien	if (INB (HS_PRT) == HS_NEGOTIATE) {
716253790Sobrien		OUTB (HS_PRT, HS_BUSY);
716353790Sobrien		if (cp->nego_status && cp->nego_status != NS_SYNC)
716453790Sobrien			goto reject_it;
716553790Sobrien		req = 0;
716653790Sobrien	}
716753790Sobrien
716853790Sobrien	/*
716953790Sobrien	 *  get requested values.
717053790Sobrien	 */
717153790Sobrien	chg = 0;
717253790Sobrien	per = np->msgin[3];
717353790Sobrien	ofs = np->msgin[4];
717453790Sobrien
717553790Sobrien	/*
717653790Sobrien	 *  check values against our limits.
717753790Sobrien	 */
717853790Sobrien	if (ofs) {
717953790Sobrien		if (ofs > np->maxoffs)
718053790Sobrien			{chg = 1; ofs = np->maxoffs;}
718153790Sobrien		if (req) {
718253790Sobrien			if (ofs > tp->tinfo.user.offset)
718353790Sobrien				{chg = 1; ofs = tp->tinfo.user.offset;}
718453790Sobrien		}
718553790Sobrien	}
718653790Sobrien
718753790Sobrien	if (ofs) {
718853790Sobrien		if (per < np->minsync)
718953790Sobrien			{chg = 1; per = np->minsync;}
719053790Sobrien		if (req) {
719153790Sobrien			if (per < tp->tinfo.user.period)
719253790Sobrien				{chg = 1; per = tp->tinfo.user.period;}
719353790Sobrien		}
719453790Sobrien	}
719553790Sobrien
719653790Sobrien	div = fak = 0;
719753790Sobrien	if (ofs && sym_getsync(np, 0, per, &div, &fak) < 0)
719853790Sobrien		goto reject_it;
719953790Sobrien
720053790Sobrien	if (DEBUG_FLAGS & DEBUG_NEGO) {
720153790Sobrien		PRINT_ADDR(cp);
720253790Sobrien		printf ("sdtr: ofs=%d per=%d div=%d fak=%d chg=%d.\n",
720353790Sobrien			ofs, per, div, fak, chg);
720453790Sobrien	}
720553790Sobrien
720653790Sobrien	/*
720753790Sobrien	 *  This was an answer message
720853790Sobrien	 */
720953790Sobrien	if (req == 0) {
721053790Sobrien		if (chg) 	/* Answer wasn't acceptable. */
721153790Sobrien			goto reject_it;
721253790Sobrien		sym_setsync (np, cp, ofs, per, div, fak);
721353790Sobrien		OUTL (nc_dsp, SCRIPT_BA (np, clrack));
721453790Sobrien		return;
721553790Sobrien	}
721653790Sobrien
721753790Sobrien	/*
721853790Sobrien	 *  It was a request. Set value and
721953790Sobrien	 *  prepare an answer message
722053790Sobrien	 */
722153790Sobrien	sym_setsync (np, cp, ofs, per, div, fak);
722253790Sobrien
722353790Sobrien	np->msgout[0] = M_EXTENDED;
722453790Sobrien	np->msgout[1] = 3;
722553790Sobrien	np->msgout[2] = M_X_SYNC_REQ;
722653790Sobrien	np->msgout[3] = per;
722753790Sobrien	np->msgout[4] = ofs;
722853790Sobrien
722953790Sobrien	cp->nego_status = NS_SYNC;
723053790Sobrien
723153790Sobrien	if (DEBUG_FLAGS & DEBUG_NEGO) {
723253790Sobrien		sym_print_msg(cp, "sync msgout", np->msgout);
723353790Sobrien	}
723453790Sobrien
723553790Sobrien	np->msgin [0] = M_NOOP;
723653790Sobrien
723753790Sobrien	OUTL (nc_dsp, SCRIPTH_BA (np, sdtr_resp));
723853790Sobrien	return;
723953790Sobrienreject_it:
724053790Sobrien	sym_setsync (np, cp, 0, 0, 0, 0);
724153790Sobrien	OUTL (nc_dsp, SCRIPTH_BA (np, msg_bad));
724253790Sobrien}
724353790Sobrien
724453790Sobrien/*
724553790Sobrien *  chip handler for PARALLEL PROTOCOL REQUEST (PPR) message.
724653790Sobrien */
724753790Sobrienstatic void sym_ppr_nego(hcb_p np, tcb_p tp, ccb_p cp)
724853790Sobrien{
724953790Sobrien	u_char	chg, ofs, per, fak, dt, div, wide;
725053790Sobrien	int	req = 1;
725153790Sobrien
725253790Sobrien	/*
725353790Sobrien	 * Synchronous request message received.
725453790Sobrien	 */
725553790Sobrien	if (DEBUG_FLAGS & DEBUG_NEGO) {
725653809Sobrien		sym_print_msg(cp, "ppr msgin", np->msgin);
725753790Sobrien	};
725853790Sobrien
725953790Sobrien	/*
726053790Sobrien	 * request or answer ?
726153790Sobrien	 */
726253790Sobrien	if (INB (HS_PRT) == HS_NEGOTIATE) {
726353790Sobrien		OUTB (HS_PRT, HS_BUSY);
726453790Sobrien		if (cp->nego_status && cp->nego_status != NS_PPR)
726553790Sobrien			goto reject_it;
726653790Sobrien		req = 0;
726753790Sobrien	}
726853790Sobrien
726953790Sobrien	/*
727053790Sobrien	 *  get requested values.
727153790Sobrien	 */
727253790Sobrien	chg  = 0;
727353790Sobrien	per  = np->msgin[3];
727453790Sobrien	ofs  = np->msgin[5];
727553790Sobrien	wide = np->msgin[6];
727653790Sobrien	dt   = np->msgin[7] & PPR_OPT_DT;
727753790Sobrien
727853790Sobrien	/*
727953790Sobrien	 *  check values against our limits.
728053790Sobrien	 */
728153790Sobrien	if (wide > np->maxwide)
728253790Sobrien		{chg = 1; wide = np->maxwide;}
728353790Sobrien	if (!wide || !(np->features & FE_ULTRA3))
728453790Sobrien		dt &= ~PPR_OPT_DT;
728553790Sobrien	if (req) {
728653790Sobrien		if (wide > tp->tinfo.user.width)
728753790Sobrien			{chg = 1; wide = tp->tinfo.user.width;}
728853790Sobrien	}
728954690Sobrien#ifndef	SYM_CONF_BROKEN_U3EN_SUPPORT
729053790Sobrien	if (!(np->features & FE_U3EN))	/* Broken U3EN bit not supported */
729153790Sobrien		dt &= ~PPR_OPT_DT;
729253790Sobrien#endif
729353790Sobrien	if (dt != (np->msgin[7] & PPR_OPT_MASK)) chg = 1;
729453790Sobrien
729553790Sobrien	if (ofs) {
729653790Sobrien		if (ofs > np->maxoffs)
729753790Sobrien			{chg = 1; ofs = np->maxoffs;}
729853790Sobrien		if (req) {
729953790Sobrien			if (ofs > tp->tinfo.user.offset)
730053790Sobrien				{chg = 1; ofs = tp->tinfo.user.offset;}
730153790Sobrien		}
730253790Sobrien	}
730353790Sobrien
730453790Sobrien	if (ofs) {
730553809Sobrien		if (dt) {
730653809Sobrien			if (per < np->minsync_dt)
730753809Sobrien				{chg = 1; per = np->minsync_dt;}
730853809Sobrien		}
730953790Sobrien		else if (per < np->minsync)
731053790Sobrien			{chg = 1; per = np->minsync;}
731153790Sobrien		if (req) {
731253790Sobrien			if (per < tp->tinfo.user.period)
731353790Sobrien				{chg = 1; per = tp->tinfo.user.period;}
731453790Sobrien		}
731553790Sobrien	}
731653790Sobrien
731753790Sobrien	div = fak = 0;
731853790Sobrien	if (ofs && sym_getsync(np, dt, per, &div, &fak) < 0)
731953790Sobrien		goto reject_it;
732053790Sobrien
732153790Sobrien	if (DEBUG_FLAGS & DEBUG_NEGO) {
732253790Sobrien		PRINT_ADDR(cp);
732353790Sobrien		printf ("ppr: "
732453790Sobrien			"dt=%x ofs=%d per=%d wide=%d div=%d fak=%d chg=%d.\n",
732553790Sobrien			dt, ofs, per, wide, div, fak, chg);
732653790Sobrien	}
732753790Sobrien
732853790Sobrien	/*
732953790Sobrien	 *  It was an answer.
733053790Sobrien	 */
733153790Sobrien	if (req == 0) {
733253790Sobrien		if (chg) 	/* Answer wasn't acceptable */
733353790Sobrien			goto reject_it;
733453790Sobrien		sym_setpprot (np, cp, dt, ofs, per, wide, div, fak);
733553790Sobrien		OUTL (nc_dsp, SCRIPT_BA (np, clrack));
733653790Sobrien		return;
733753790Sobrien	}
733853790Sobrien
733953790Sobrien	/*
734053790Sobrien	 *  It was a request. Set value and
734153790Sobrien	 *  prepare an answer message
734253790Sobrien	 */
734353790Sobrien	sym_setpprot (np, cp, dt, ofs, per, wide, div, fak);
734453790Sobrien
734553790Sobrien	np->msgout[0] = M_EXTENDED;
734653790Sobrien	np->msgout[1] = 6;
734753790Sobrien	np->msgout[2] = M_X_PPR_REQ;
734853790Sobrien	np->msgout[3] = per;
734953790Sobrien	np->msgout[4] = 0;
735053790Sobrien	np->msgout[5] = ofs;
735153790Sobrien	np->msgout[6] = wide;
735253790Sobrien	np->msgout[7] = dt;
735353790Sobrien
735453790Sobrien	cp->nego_status = NS_PPR;
735553790Sobrien
735653790Sobrien	if (DEBUG_FLAGS & DEBUG_NEGO) {
735753809Sobrien		sym_print_msg(cp, "ppr msgout", np->msgout);
735853790Sobrien	}
735953790Sobrien
736053790Sobrien	np->msgin [0] = M_NOOP;
736153790Sobrien
736253790Sobrien	OUTL (nc_dsp, SCRIPTH_BA (np, ppr_resp));
736353790Sobrien	return;
736453790Sobrienreject_it:
736553790Sobrien	sym_setpprot (np, cp, 0, 0, 0, 0, 0, 0);
736653790Sobrien	OUTL (nc_dsp, SCRIPTH_BA (np, msg_bad));
736753790Sobrien}
736853790Sobrien
736953790Sobrien/*
737053790Sobrien *  chip handler for WIDE DATA TRANSFER REQUEST (WDTR) message.
737153790Sobrien */
737253790Sobrienstatic void sym_wide_nego(hcb_p np, tcb_p tp, ccb_p cp)
737353790Sobrien{
737453790Sobrien	u_char	chg, wide;
737553790Sobrien	int	req = 1;
737653790Sobrien
737753790Sobrien	/*
737853790Sobrien	 *  Wide request message received.
737953790Sobrien	 */
738053790Sobrien	if (DEBUG_FLAGS & DEBUG_NEGO) {
738153790Sobrien		sym_print_msg(cp, "wide msgin", np->msgin);
738253790Sobrien	};
738353790Sobrien
738453790Sobrien	/*
738553790Sobrien	 * Is it an request from the device?
738653790Sobrien	 */
738753790Sobrien	if (INB (HS_PRT) == HS_NEGOTIATE) {
738853790Sobrien		OUTB (HS_PRT, HS_BUSY);
738953790Sobrien		if (cp->nego_status && cp->nego_status != NS_WIDE)
739053790Sobrien			goto reject_it;
739153790Sobrien		req = 0;
739253790Sobrien	}
739353790Sobrien
739453790Sobrien	/*
739553790Sobrien	 *  get requested values.
739653790Sobrien	 */
739753790Sobrien	chg  = 0;
739853790Sobrien	wide = np->msgin[3];
739953790Sobrien
740053790Sobrien	/*
740153790Sobrien	 *  check values against driver limits.
740253790Sobrien	 */
740353790Sobrien	if (wide > np->maxoffs)
740453790Sobrien		{chg = 1; wide = np->maxoffs;}
740553790Sobrien	if (req) {
740653790Sobrien		if (wide > tp->tinfo.user.width)
740753790Sobrien			{chg = 1; wide = tp->tinfo.user.width;}
740853790Sobrien	}
740953790Sobrien
741053790Sobrien	if (DEBUG_FLAGS & DEBUG_NEGO) {
741153790Sobrien		PRINT_ADDR(cp);
741253790Sobrien		printf ("wdtr: wide=%d chg=%d.\n", wide, chg);
741353790Sobrien	}
741453790Sobrien
741553790Sobrien	/*
741653790Sobrien	 * This was an answer message
741753790Sobrien	 */
741853790Sobrien	if (req == 0) {
741953790Sobrien		if (chg)	/*  Answer wasn't acceptable. */
742053790Sobrien			goto reject_it;
742153790Sobrien		sym_setwide (np, cp, wide);
742255628Sgroudier#if 1
742355628Sgroudier		/*
742455628Sgroudier		 * Negotiate for SYNC immediately after WIDE response.
742555628Sgroudier		 * This allows to negotiate for both WIDE and SYNC on
742655628Sgroudier		 * a single SCSI command (Suggested by Justin Gibbs).
742755628Sgroudier		 */
742855628Sgroudier		if (tp->tinfo.goal.offset) {
742955628Sgroudier			np->msgout[0] = M_EXTENDED;
743055628Sgroudier			np->msgout[1] = 3;
743155628Sgroudier			np->msgout[2] = M_X_SYNC_REQ;
743255628Sgroudier			np->msgout[3] = tp->tinfo.goal.period;
743355628Sgroudier			np->msgout[4] = tp->tinfo.goal.offset;
743455628Sgroudier
743555628Sgroudier			if (DEBUG_FLAGS & DEBUG_NEGO) {
743655628Sgroudier				sym_print_msg(cp, "sync msgout", np->msgout);
743755628Sgroudier			}
743855628Sgroudier
743955628Sgroudier			cp->nego_status = NS_SYNC;
744055628Sgroudier			OUTB (HS_PRT, HS_NEGOTIATE);
744155628Sgroudier			OUTL (nc_dsp, SCRIPTH_BA (np, sdtr_resp));
744255628Sgroudier			return;
744355628Sgroudier		}
744455628Sgroudier#endif
744553790Sobrien		OUTL (nc_dsp, SCRIPT_BA (np, clrack));
744653790Sobrien		return;
744753790Sobrien	};
744853790Sobrien
744953790Sobrien	/*
745053790Sobrien	 *  It was a request, set value and
745153790Sobrien	 *  prepare an answer message
745253790Sobrien	 */
745353790Sobrien	sym_setwide (np, cp, wide);
745453790Sobrien
745553790Sobrien	np->msgout[0] = M_EXTENDED;
745653790Sobrien	np->msgout[1] = 2;
745753790Sobrien	np->msgout[2] = M_X_WIDE_REQ;
745853790Sobrien	np->msgout[3] = wide;
745953790Sobrien
746053790Sobrien	np->msgin [0] = M_NOOP;
746153790Sobrien
746253790Sobrien	cp->nego_status = NS_WIDE;
746353790Sobrien
746453790Sobrien	if (DEBUG_FLAGS & DEBUG_NEGO) {
746553790Sobrien		sym_print_msg(cp, "wide msgout", np->msgout);
746653790Sobrien	}
746753790Sobrien
746853790Sobrien	OUTL (nc_dsp, SCRIPTH_BA (np, wdtr_resp));
746953790Sobrien	return;
747053790Sobrienreject_it:
747153790Sobrien	OUTL (nc_dsp, SCRIPTH_BA (np, msg_bad));
747253790Sobrien}
747353790Sobrien
747453790Sobrien/*
747553790Sobrien *  Reset SYNC or WIDE to default settings.
747653790Sobrien *
747753790Sobrien *  Called when a negotiation does not succeed either
747853790Sobrien *  on rejection or on protocol error.
747953790Sobrien */
748053790Sobrienstatic void sym_nego_default(hcb_p np, tcb_p tp, ccb_p cp)
748153790Sobrien{
748253790Sobrien	/*
748353790Sobrien	 *  any error in negotiation:
748453790Sobrien	 *  fall back to default mode.
748553790Sobrien	 */
748653790Sobrien	switch (cp->nego_status) {
748753790Sobrien	case NS_PPR:
748853790Sobrien		sym_setpprot (np, cp, 0, 0, 0, 0, 0, 0);
748953790Sobrien		break;
749053790Sobrien	case NS_SYNC:
749153790Sobrien		sym_setsync (np, cp, 0, 0, 0, 0);
749253790Sobrien		break;
749353790Sobrien	case NS_WIDE:
749453790Sobrien		sym_setwide (np, cp, 0);
749553790Sobrien		break;
749653790Sobrien	};
749753790Sobrien	np->msgin [0] = M_NOOP;
749853790Sobrien	np->msgout[0] = M_NOOP;
749953790Sobrien	cp->nego_status = 0;
750053790Sobrien}
750153790Sobrien
750253790Sobrien/*
750353790Sobrien *  chip handler for MESSAGE REJECT received in response to
750453790Sobrien *  a WIDE or SYNCHRONOUS negotiation.
750553790Sobrien */
750653790Sobrienstatic void sym_nego_rejected(hcb_p np, tcb_p tp, ccb_p cp)
750753790Sobrien{
750853790Sobrien	sym_nego_default(np, tp, cp);
750953790Sobrien	OUTB (HS_PRT, HS_BUSY);
751053790Sobrien}
751153790Sobrien
751253790Sobrien/*
751353790Sobrien *  chip exception handler for programmed interrupts.
751453790Sobrien */
751553790Sobrienvoid sym_int_sir (hcb_p np)
751653790Sobrien{
751753790Sobrien	u_char	num	= INB (nc_dsps);
751853790Sobrien	u_long	dsa	= INL (nc_dsa);
751953790Sobrien	ccb_p	cp	= sym_ccb_from_dsa(np, dsa);
752053790Sobrien	u_char	target	= INB (nc_sdid) & 0x0f;
752153790Sobrien	tcb_p	tp	= &np->target[target];
752253790Sobrien	int	tmp;
752353790Sobrien
752453790Sobrien	if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num);
752553790Sobrien
752653790Sobrien	switch (num) {
752753790Sobrien	/*
752853790Sobrien	 *  Command has been completed with error condition
752953790Sobrien	 *  or has been auto-sensed.
753053790Sobrien	 */
753153790Sobrien	case SIR_COMPLETE_ERROR:
753253790Sobrien		sym_complete_error(np, cp);
753353790Sobrien		return;
753453790Sobrien	/*
753553790Sobrien	 *  The C code is currently trying to recover from something.
753653790Sobrien	 *  Typically, user want to abort some command.
753753790Sobrien	 */
753853790Sobrien	case SIR_SCRIPT_STOPPED:
753953790Sobrien	case SIR_TARGET_SELECTED:
754053790Sobrien	case SIR_ABORT_SENT:
754153790Sobrien		sym_sir_task_recovery(np, num);
754253790Sobrien		return;
754353790Sobrien	/*
754453790Sobrien	 *  The device didn't go to MSG OUT phase after having
754553790Sobrien	 *  been selected with ATN. We donnot want to handle
754653790Sobrien	 *  that.
754753790Sobrien	 */
754853790Sobrien	case SIR_SEL_ATN_NO_MSG_OUT:
754953790Sobrien		printf ("%s:%d: No MSG OUT phase after selection with ATN.\n",
755053790Sobrien			sym_name (np), target);
755153790Sobrien		goto out_stuck;
755253790Sobrien	/*
755353790Sobrien	 *  The device didn't switch to MSG IN phase after
755453790Sobrien	 *  having reseleted the initiator.
755553790Sobrien	 */
755653790Sobrien	case SIR_RESEL_NO_MSG_IN:
755753790Sobrien	/*
755853790Sobrien	 *  After reselection, the device sent a message that wasn't
755953790Sobrien	 *  an IDENTIFY.
756053790Sobrien	 */
756153790Sobrien	case SIR_RESEL_NO_IDENTIFY:
756253790Sobrien		/*
756353790Sobrien		 *  If devices reselecting without sending an IDENTIFY
756453790Sobrien		 *  message still exist, this should help.
756553790Sobrien		 *  We just assume lun=0, 1 CCB, no tag.
756653790Sobrien		 */
756753790Sobrien		if (tp->lun0p) {
756853790Sobrien			OUTL (nc_dsa, scr_to_cpu(tp->lun0p->itl_task_sa));
756953790Sobrien			OUTL (nc_dsp, SCRIPT_BA (np, resel_dsa1));
757053790Sobrien			return;
757153790Sobrien		}
757253790Sobrien	/*
757353790Sobrien	 *  The device reselected a LUN we donnot know about.
757453790Sobrien	 */
757553790Sobrien	case SIR_RESEL_BAD_LUN:
757653790Sobrien		np->msgout[0] = M_RESET;
757753790Sobrien		goto out;
757853790Sobrien	/*
757953790Sobrien	 *  The device reselected for an untagged nexus and we
758053790Sobrien	 *  haven't any.
758153790Sobrien	 */
758253790Sobrien	case SIR_RESEL_BAD_I_T_L:
758353790Sobrien		np->msgout[0] = M_ABORT;
758453790Sobrien		goto out;
758553790Sobrien	/*
758653790Sobrien	 *  The device reselected for a tagged nexus that we donnot
758753790Sobrien	 *  have.
758853790Sobrien	 */
758953790Sobrien	case SIR_RESEL_BAD_I_T_L_Q:
759053790Sobrien		np->msgout[0] = M_ABORT_TAG;
759153790Sobrien		goto out;
759253790Sobrien	/*
759353790Sobrien	 *  The SCRIPTS let us know that the device has grabbed
759453790Sobrien	 *  our message and will abort the job.
759553790Sobrien	 */
759653790Sobrien	case SIR_RESEL_ABORTED:
759753790Sobrien		np->lastmsg = np->msgout[0];
759853790Sobrien		np->msgout[0] = M_NOOP;
759953790Sobrien		printf ("%s:%d: message %x sent on bad reselection.\n",
760053790Sobrien			sym_name (np), target, np->lastmsg);
760153790Sobrien		goto out;
760253790Sobrien	/*
760353790Sobrien	 *  The SCRIPTS let us know that a message has been
760453790Sobrien	 *  successfully sent to the device.
760553790Sobrien	 */
760653790Sobrien	case SIR_MSG_OUT_DONE:
760753790Sobrien		np->lastmsg = np->msgout[0];
760853790Sobrien		np->msgout[0] = M_NOOP;
760953790Sobrien		/* Should we really care of that */
761053790Sobrien		if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) {
761153790Sobrien			if (cp) {
761253790Sobrien				cp->xerr_status &= ~XE_PARITY_ERR;
761353790Sobrien				if (!cp->xerr_status)
761453790Sobrien					OUTOFFB (HF_PRT, HF_EXT_ERR);
761553790Sobrien			}
761653790Sobrien		}
761753790Sobrien		goto out;
761853790Sobrien	/*
761953790Sobrien	 *  The device didn't send a GOOD SCSI status.
762053790Sobrien	 *  We may have some work to do prior to allow
762153790Sobrien	 *  the SCRIPTS processor to continue.
762253790Sobrien	 */
762353790Sobrien	case SIR_BAD_SCSI_STATUS:
762453790Sobrien		if (!cp)
762553790Sobrien			goto out;
762653790Sobrien		sym_sir_bad_scsi_status(np, num, cp);
762753790Sobrien		return;
762853790Sobrien	/*
762953790Sobrien	 *  We are asked by the SCRIPTS to prepare a
763053790Sobrien	 *  REJECT message.
763153790Sobrien	 */
763253790Sobrien	case SIR_REJECT_TO_SEND:
763353790Sobrien		sym_print_msg(cp, "M_REJECT to send for ", np->msgin);
763453790Sobrien		np->msgout[0] = M_REJECT;
763553790Sobrien		goto out;
763653790Sobrien	/*
763753790Sobrien	 *  We have been ODD at the end of a DATA IN
763853790Sobrien	 *  transfer and the device didn't send a
763953790Sobrien	 *  IGNORE WIDE RESIDUE message.
764053790Sobrien	 *  It is a data overrun condition.
764153790Sobrien	 */
764253790Sobrien	case SIR_SWIDE_OVERRUN:
764353790Sobrien		if (cp) {
764453790Sobrien			OUTONB (HF_PRT, HF_EXT_ERR);
764553790Sobrien			cp->xerr_status |= XE_SWIDE_OVRUN;
764653790Sobrien		}
764753790Sobrien		goto out;
764853790Sobrien	/*
764953790Sobrien	 *  We have been ODD at the end of a DATA OUT
765053790Sobrien	 *  transfer.
765153790Sobrien	 *  It is a data underrun condition.
765253790Sobrien	 */
765353790Sobrien	case SIR_SODL_UNDERRUN:
765453790Sobrien		if (cp) {
765553790Sobrien			OUTONB (HF_PRT, HF_EXT_ERR);
765653790Sobrien			cp->xerr_status |= XE_SODL_UNRUN;
765753790Sobrien		}
765853790Sobrien		goto out;
765953790Sobrien	/*
766053790Sobrien	 *  We received a message.
766153790Sobrien	 */
766253790Sobrien	case SIR_MSG_RECEIVED:
766353790Sobrien		if (!cp)
766453790Sobrien			goto out_stuck;
766553790Sobrien		switch (np->msgin [0]) {
766653790Sobrien		/*
766753790Sobrien		 *  We received an extended message.
766853790Sobrien		 *  We handle MODIFY DATA POINTER, SDTR, WDTR
766953790Sobrien		 *  and reject all other extended messages.
767053790Sobrien		 */
767153790Sobrien		case M_EXTENDED:
767253790Sobrien			switch (np->msgin [2]) {
767353790Sobrien			case M_X_MODIFY_DP:
767453790Sobrien				if (DEBUG_FLAGS & DEBUG_POINTER)
767553790Sobrien					sym_print_msg(cp,"modify DP",np->msgin);
767653790Sobrien				tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) +
767753790Sobrien				      (np->msgin[5]<<8)  + (np->msgin[6]);
767853790Sobrien				sym_modify_dp(np, tp, cp, tmp);
767953790Sobrien				return;
768053790Sobrien			case M_X_SYNC_REQ:
768153790Sobrien				sym_sync_nego(np, tp, cp);
768253790Sobrien				return;
768353790Sobrien			case M_X_PPR_REQ:
768453790Sobrien				sym_ppr_nego(np, tp, cp);
768553790Sobrien				return;
768653790Sobrien			case M_X_WIDE_REQ:
768753790Sobrien				sym_wide_nego(np, tp, cp);
768853790Sobrien				return;
768953790Sobrien			default:
769053790Sobrien				goto out_reject;
769153790Sobrien			}
769253790Sobrien			break;
769353790Sobrien		/*
769453790Sobrien		 *  We received a 1/2 byte message not handled from SCRIPTS.
769553790Sobrien		 *  We are only expecting MESSAGE REJECT and IGNORE WIDE
769653790Sobrien		 *  RESIDUE messages that haven't been anticipated by
769753790Sobrien		 *  SCRIPTS on SWIDE full condition. Unanticipated IGNORE
769853790Sobrien		 *  WIDE RESIDUE messages are aliased as MODIFY DP (-1).
769953790Sobrien		 */
770053790Sobrien		case M_IGN_RESIDUE:
770153790Sobrien			if (DEBUG_FLAGS & DEBUG_POINTER)
770253790Sobrien				sym_print_msg(cp,"ign wide residue", np->msgin);
770353790Sobrien			sym_modify_dp(np, tp, cp, -1);
770453790Sobrien			return;
770553790Sobrien		case M_REJECT:
770653790Sobrien			if (INB (HS_PRT) == HS_NEGOTIATE)
770753790Sobrien				sym_nego_rejected(np, tp, cp);
770853790Sobrien			else {
770953790Sobrien				PRINT_ADDR(cp);
771053790Sobrien				printf ("M_REJECT received (%x:%x).\n",
771153790Sobrien					scr_to_cpu(np->lastmsg), np->msgout[0]);
771253790Sobrien			}
771353790Sobrien			goto out_clrack;
771453790Sobrien			break;
771553790Sobrien		default:
771653790Sobrien			goto out_reject;
771753790Sobrien		}
771853790Sobrien		break;
771953790Sobrien	/*
772053790Sobrien	 *  We received an unknown message.
772153790Sobrien	 *  Ignore all MSG IN phases and reject it.
772253790Sobrien	 */
772353790Sobrien	case SIR_MSG_WEIRD:
772453790Sobrien		sym_print_msg(cp, "WEIRD message received", np->msgin);
772553790Sobrien		OUTL (nc_dsp, SCRIPTH_BA (np, msg_weird));
772653790Sobrien		return;
772753790Sobrien	/*
772853790Sobrien	 *  Negotiation failed.
772953790Sobrien	 *  Target does not send us the reply.
773053790Sobrien	 *  Remove the HS_NEGOTIATE status.
773153790Sobrien	 */
773253790Sobrien	case SIR_NEGO_FAILED:
773353790Sobrien		OUTB (HS_PRT, HS_BUSY);
773453790Sobrien	/*
773553790Sobrien	 *  Negotiation failed.
773653790Sobrien	 *  Target does not want answer message.
773753790Sobrien	 */
773853790Sobrien	case SIR_NEGO_PROTO:
773953790Sobrien		sym_nego_default(np, tp, cp);
774053790Sobrien		goto out;
774153790Sobrien	};
774253790Sobrien
774353790Sobrienout:
774453790Sobrien	OUTONB (nc_dcntl, (STD|NOCOM));
774553790Sobrien	return;
774653790Sobrienout_reject:
774753790Sobrien	OUTL (nc_dsp, SCRIPTH_BA (np, msg_bad));
774853790Sobrien	return;
774953790Sobrienout_clrack:
775053790Sobrien	OUTL (nc_dsp, SCRIPT_BA (np, clrack));
775153790Sobrien	return;
775253790Sobrienout_stuck:
775353790Sobrien}
775453790Sobrien
775553790Sobrien/*
775653790Sobrien *  Acquire a control block
775753790Sobrien */
775853790Sobrienstatic	ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order)
775953790Sobrien{
776053790Sobrien	tcb_p tp = &np->target[tn];
776153790Sobrien	lcb_p lp = sym_lp(np, tp, ln);
776253790Sobrien	u_short tag = NO_TAG;
776353790Sobrien	SYM_QUEHEAD *qp;
776453790Sobrien	ccb_p cp = (ccb_p) 0;
776553790Sobrien
776653790Sobrien	/*
776753790Sobrien	 *  Look for a free CCB
776853790Sobrien	 */
776953790Sobrien	if (sym_que_empty(&np->free_ccbq))
777053790Sobrien		(void) sym_alloc_ccb(np);
777153790Sobrien	qp = sym_remque_head(&np->free_ccbq);
777253790Sobrien	if (!qp)
777353790Sobrien		goto out;
777453790Sobrien	cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
777553790Sobrien
777653790Sobrien	/*
777753790Sobrien	 *  If the LCB is not yet available and the LUN
777853790Sobrien	 *  has been probed ok, try to allocate the LCB.
777953790Sobrien	 */
778053790Sobrien	if (!lp && sym_is_bit(tp->lun_map, ln)) {
778153790Sobrien		lp = sym_alloc_lcb(np, tn, ln);
778253790Sobrien		if (!lp)
778353790Sobrien			goto out_free;
778453790Sobrien	}
778553790Sobrien
778653790Sobrien	/*
778753790Sobrien	 *  If the LCB is not available here, then the
778853790Sobrien	 *  logical unit is not yet discovered. For those
778953790Sobrien	 *  ones only accept 1 SCSI IO per logical unit,
779053790Sobrien	 *  since we cannot allow disconnections.
779153790Sobrien	 */
779253790Sobrien	if (!lp) {
779353790Sobrien		if (!sym_is_bit(tp->busy0_map, ln))
779453790Sobrien			sym_set_bit(tp->busy0_map, ln);
779553790Sobrien		else
779653790Sobrien			goto out_free;
779753790Sobrien	} else {
779853790Sobrien		/*
779953790Sobrien		 *  If we have been asked for a tagged command.
780053790Sobrien		 */
780153790Sobrien		if (tag_order) {
780253790Sobrien			/*
780353790Sobrien			 *  Debugging purpose.
780453790Sobrien			 */
780553790Sobrien			assert(lp->busy_itl == 0);
780653790Sobrien			/*
780753790Sobrien			 *  Allocate resources for tags if not yet.
780853790Sobrien			 */
780953790Sobrien			if (!lp->cb_tags) {
781053790Sobrien				sym_alloc_lcb_tags(np, tn, ln);
781153790Sobrien				if (!lp->cb_tags)
781253790Sobrien					goto out_free;
781353790Sobrien			}
781453790Sobrien			/*
781553790Sobrien			 *  Get a tag for this SCSI IO and set up
781653790Sobrien			 *  the CCB bus address for reselection,
781753790Sobrien			 *  and count it for this LUN.
781855300Sgroudier			 *  Toggle reselect path to tagged.
781953790Sobrien			 */
782054690Sobrien			if (lp->busy_itlq < SYM_CONF_MAX_TASK) {
782153790Sobrien				tag = lp->cb_tags[lp->ia_tag];
782254690Sobrien				if (++lp->ia_tag == SYM_CONF_MAX_TASK)
782353790Sobrien					lp->ia_tag = 0;
782453790Sobrien				lp->itlq_tbl[tag] = cpu_to_scr(cp->ccb_ba);
782553790Sobrien				++lp->busy_itlq;
782653790Sobrien				lp->resel_sa =
782753790Sobrien					cpu_to_scr(SCRIPT_BA (np, resel_tag));
782853790Sobrien			}
782953790Sobrien			else
783053790Sobrien				goto out_free;
783153790Sobrien		}
783253790Sobrien		/*
783353790Sobrien		 *  This command will not be tagged.
783453790Sobrien		 *  If we already have either a tagged or untagged
783553790Sobrien		 *  one, refuse to overlap this untagged one.
783653790Sobrien		 */
783753790Sobrien		else {
783853790Sobrien			/*
783953790Sobrien			 *  Debugging purpose.
784053790Sobrien			 */
784153790Sobrien			assert(lp->busy_itl == 0 && lp->busy_itlq == 0);
784253790Sobrien			/*
784353790Sobrien			 *  Count this nexus for this LUN.
784453790Sobrien			 *  Set up the CCB bus address for reselection.
784553790Sobrien			 *  Toggle reselect path to untagged.
784653790Sobrien			 */
784753790Sobrien			if (++lp->busy_itl == 1) {
784853790Sobrien				lp->itl_task_sa = cpu_to_scr(cp->ccb_ba);
784953790Sobrien				lp->resel_sa =
785053790Sobrien					cpu_to_scr(SCRIPT_BA (np,resel_no_tag));
785153790Sobrien			}
785253790Sobrien			else
785353790Sobrien				goto out_free;
785453790Sobrien		}
785553790Sobrien	}
785653790Sobrien	/*
785753790Sobrien	 *  Put the CCB into the busy queue.
785853790Sobrien	 */
785953790Sobrien	sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq);
786053790Sobrien
786153790Sobrien	/*
786253790Sobrien	 *  Remember all informations needed to free this CCB.
786353790Sobrien	 */
786453790Sobrien	cp->to_abort = 0;
786553790Sobrien	cp->tag	   = tag;
786653790Sobrien	cp->target = tn;
786753790Sobrien	cp->lun    = ln;
786853790Sobrien
786953790Sobrien	if (DEBUG_FLAGS & DEBUG_TAGS) {
787053790Sobrien		PRINT_LUN(np, tn, ln);
787153790Sobrien		printf ("ccb @%p using tag %d.\n", cp, tag);
787253790Sobrien	}
787353790Sobrien
787453790Sobrienout:
787553790Sobrien	return cp;
787653790Sobrienout_free:
787753790Sobrien	sym_insque_head(&cp->link_ccbq, &np->free_ccbq);
787853790Sobrien	return (ccb_p) 0;
787953790Sobrien}
788053790Sobrien
788153790Sobrien/*
788253790Sobrien *  Release one control block
788353790Sobrien */
788453790Sobrienstatic void sym_free_ccb (hcb_p np, ccb_p cp)
788553790Sobrien{
788653790Sobrien	tcb_p tp = &np->target[cp->target];
788753790Sobrien	lcb_p lp = sym_lp(np, tp, cp->lun);
788853790Sobrien
788953790Sobrien	if (DEBUG_FLAGS & DEBUG_TAGS) {
789053790Sobrien		PRINT_LUN(np, cp->target, cp->lun);
789153790Sobrien		printf ("ccb @%p freeing tag %d.\n", cp, cp->tag);
789253790Sobrien	}
789353790Sobrien
789453790Sobrien	/*
789553790Sobrien	 *  If LCB available,
789653790Sobrien	 */
789753790Sobrien	if (lp) {
789853790Sobrien		/*
789953790Sobrien		 *  If tagged, release the tag, set the relect path
790053790Sobrien		 */
790153790Sobrien		if (cp->tag != NO_TAG) {
790253790Sobrien			/*
790353790Sobrien			 *  Free the tag value.
790453790Sobrien			 */
790553790Sobrien			lp->cb_tags[lp->if_tag] = cp->tag;
790654690Sobrien			if (++lp->if_tag == SYM_CONF_MAX_TASK)
790753790Sobrien				lp->if_tag = 0;
790853790Sobrien			/*
790953790Sobrien			 *  Make the reselect path invalid,
791053790Sobrien			 *  and uncount this CCB.
791153790Sobrien			 */
791253790Sobrien			lp->itlq_tbl[cp->tag] = cpu_to_scr(np->bad_itlq_ba);
791353790Sobrien			--lp->busy_itlq;
791453790Sobrien		} else {	/* Untagged */
791553790Sobrien			/*
791653790Sobrien			 *  Make the reselect path invalid,
791753790Sobrien			 *  and uncount this CCB.
791853790Sobrien			 */
791953790Sobrien			lp->itl_task_sa = cpu_to_scr(np->bad_itl_ba);
792053790Sobrien			--lp->busy_itl;
792153790Sobrien		}
792253790Sobrien		/*
792353790Sobrien		 *  If no JOB active, make the LUN reselect path invalid.
792453790Sobrien		 */
792553790Sobrien		if (lp->busy_itlq == 0 && lp->busy_itl == 0)
792653790Sobrien			lp->resel_sa = cpu_to_scr(SCRIPTH_BA(np,resel_bad_lun));
792753790Sobrien	}
792853790Sobrien	/*
792953790Sobrien	 *  Otherwise, we only accept 1 IO per LUN.
793053790Sobrien	 *  Clear the bit that keeps track of this IO.
793153790Sobrien	 */
793253790Sobrien	else
793353790Sobrien		sym_clr_bit(tp->busy0_map, cp->lun);
793453790Sobrien
793553790Sobrien	/*
793653790Sobrien	 *  We donnot queue more than 1 ccb per target
793753790Sobrien	 *  with negotiation at any time. If this ccb was
793853790Sobrien	 *  used for negotiation, clear this info in the tcb.
793953790Sobrien	 */
794053790Sobrien	if (cp == tp->nego_cp)
794153790Sobrien		tp->nego_cp = 0;
794253790Sobrien
794354690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
794453790Sobrien	/*
794553790Sobrien	 *  If we just complete the last queued CCB,
794653790Sobrien	 *  clear this info that is no longer relevant.
794753790Sobrien	 */
794853790Sobrien	if (cp == np->last_cp)
794953790Sobrien		np->last_cp = 0;
795053790Sobrien#endif
795153790Sobrien	/*
795253790Sobrien	 *  Make this CCB available.
795353790Sobrien	 */
795453790Sobrien	cp->cam_ccb = 0;
795553790Sobrien	cp->host_status = HS_IDLE;
795653790Sobrien	sym_remque(&cp->link_ccbq);
795753790Sobrien	sym_insque_head(&cp->link_ccbq, &np->free_ccbq);
795853790Sobrien}
795953790Sobrien
796053790Sobrien/*
796153790Sobrien *  Allocate a CCB from memory and initialize its fixed part.
796253790Sobrien */
796353790Sobrienstatic ccb_p sym_alloc_ccb(hcb_p np)
796453790Sobrien{
796553790Sobrien	ccb_p cp = 0;
796653790Sobrien	int hcode;
796753790Sobrien
796853790Sobrien	/*
796953790Sobrien	 *  Prevent from allocating more CCBs than we can
797053790Sobrien	 *  queue to the controller.
797153790Sobrien	 */
797254690Sobrien	if (np->actccbs >= SYM_CONF_MAX_START)
797353790Sobrien		return 0;
797453790Sobrien
797553790Sobrien	/*
797653790Sobrien	 *  Allocate memory for this CCB.
797753790Sobrien	 */
797853790Sobrien	cp = sym_calloc(sizeof(struct sym_ccb), "CCB");
797953790Sobrien	if (!cp)
798053790Sobrien		return 0;
798153790Sobrien
798253790Sobrien	/*
798353790Sobrien	 *  Count it.
798453790Sobrien	 */
798553790Sobrien	np->actccbs++;
798653790Sobrien
798753790Sobrien	/*
798853790Sobrien	 *  Compute the bus address of this ccb.
798953790Sobrien	 */
799053790Sobrien	cp->ccb_ba = vtobus(cp);
799153790Sobrien
799253790Sobrien	/*
799353790Sobrien	 *  Insert this ccb into the hashed list.
799453790Sobrien	 */
799553790Sobrien	hcode = CCB_HASH_CODE(cp->ccb_ba);
799653790Sobrien	cp->link_ccbh = np->ccbh[hcode];
799753790Sobrien	np->ccbh[hcode] = cp;
799853790Sobrien
799953790Sobrien	/*
800053790Sobrien	 *  Initialyze the start and restart actions.
800153790Sobrien	 */
800253790Sobrien	cp->phys.go.start   = cpu_to_scr(SCRIPT_BA (np, idle));
800353790Sobrien	cp->phys.go.restart = cpu_to_scr(SCRIPTH_BA(np, bad_i_t_l));
800453790Sobrien
800553790Sobrien 	/*
800653790Sobrien	 *  Initilialyze some other fields.
800753790Sobrien	 */
800853790Sobrien	cp->phys.smsg_ext.addr = cpu_to_scr(vtobus(&np->msgin[2]));
800953790Sobrien
801053790Sobrien	/*
801155300Sgroudier	 *  Chain into free ccb queue.
801253790Sobrien	 */
801353790Sobrien	sym_insque_head(&cp->link_ccbq, &np->free_ccbq);
801453790Sobrien
801553790Sobrien	return cp;
801653790Sobrien}
801753790Sobrien
801853790Sobrien/*
801953790Sobrien *  Look up a CCB from a DSA value.
802053790Sobrien */
802153790Sobrienstatic ccb_p sym_ccb_from_dsa(hcb_p np, u_long dsa)
802253790Sobrien{
802353790Sobrien	int hcode;
802453790Sobrien	ccb_p cp;
802553790Sobrien
802653790Sobrien	hcode = CCB_HASH_CODE(dsa);
802753790Sobrien	cp = np->ccbh[hcode];
802853790Sobrien	while (cp) {
802953790Sobrien		if (cp->ccb_ba == dsa)
803053790Sobrien			break;
803153790Sobrien		cp = cp->link_ccbh;
803253790Sobrien	}
803353790Sobrien
803453790Sobrien	return cp;
803553790Sobrien}
803653790Sobrien
803753790Sobrien/*
803853790Sobrien *  Target control block initialisation.
803953790Sobrien *  Nothing important to do at the moment.
804053790Sobrien */
804153790Sobrienstatic void sym_init_tcb (hcb_p np, u_char tn)
804253790Sobrien{
804353790Sobrien	/*
804453790Sobrien	 *  Check some alignments required by the chip.
804553790Sobrien	 */
804653790Sobrien	assert (((offsetof(struct sym_reg, nc_sxfer) ^
804753790Sobrien		offsetof(struct sym_tcb, sval)) &3) == 0);
804853790Sobrien	assert (((offsetof(struct sym_reg, nc_scntl3) ^
804953790Sobrien		offsetof(struct sym_tcb, wval)) &3) == 0);
805053790Sobrien}
805153790Sobrien
805253790Sobrien/*
805353790Sobrien *  Lun control block allocation and initialization.
805453790Sobrien */
805553790Sobrienstatic lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln)
805653790Sobrien{
805753790Sobrien	tcb_p tp = &np->target[tn];
805853790Sobrien	lcb_p lp = sym_lp(np, tp, ln);
805953790Sobrien
806053790Sobrien	/*
806153790Sobrien	 *  Already done, just return.
806253790Sobrien	 */
806353790Sobrien	if (lp)
806453790Sobrien		return lp;
806553790Sobrien	/*
806653790Sobrien	 *  Check against some race.
806753790Sobrien	 */
806853790Sobrien	assert(!sym_is_bit(tp->busy0_map, ln));
806953790Sobrien
807053790Sobrien	/*
807153790Sobrien	 *  Initialize the target control block if not yet.
807253790Sobrien	 */
807353790Sobrien	sym_init_tcb (np, tn);
807453790Sobrien
807553790Sobrien	/*
807653790Sobrien	 *  Allocate the LCB bus address array.
807753790Sobrien	 *  Compute the bus address of this table.
807853790Sobrien	 */
807953790Sobrien	if (ln && !tp->luntbl) {
808053790Sobrien		int i;
808153790Sobrien
808253790Sobrien		tp->luntbl = sym_calloc(256, "LUNTBL");
808353790Sobrien		if (!tp->luntbl)
808453790Sobrien			goto fail;
808553790Sobrien		for (i = 0 ; i < 64 ; i++)
808653790Sobrien			tp->luntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa));
808753790Sobrien		tp->luntbl_sa = cpu_to_scr(vtobus(tp->luntbl));
808853790Sobrien	}
808953790Sobrien
809053790Sobrien	/*
809153790Sobrien	 *  Allocate the table of pointers for LUN(s) > 0, if needed.
809253790Sobrien	 */
809353790Sobrien	if (ln && !tp->lunmp) {
809454690Sobrien		tp->lunmp = sym_calloc(SYM_CONF_MAX_LUN * sizeof(lcb_p),
809553790Sobrien				   "LUNMP");
809653790Sobrien		if (!tp->lunmp)
809753790Sobrien			goto fail;
809853790Sobrien	}
809953790Sobrien
810053790Sobrien	/*
810153790Sobrien	 *  Allocate the lcb.
810253790Sobrien	 *  Make it available to the chip.
810353790Sobrien	 */
810453790Sobrien	lp = sym_calloc(sizeof(struct sym_lcb), "LCB");
810553790Sobrien	if (!lp)
810653790Sobrien		goto fail;
810753790Sobrien	if (ln) {
810853790Sobrien		tp->lunmp[ln] = lp;
810953790Sobrien		tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
811053790Sobrien	}
811153790Sobrien	else {
811253790Sobrien		tp->lun0p = lp;
811353790Sobrien		tp->lun0_sa = cpu_to_scr(vtobus(lp));
811453790Sobrien	}
811553790Sobrien
811653790Sobrien	/*
811753790Sobrien	 *  Let the itl task point to error handling.
811853790Sobrien	 */
811953790Sobrien	lp->itl_task_sa = cpu_to_scr(np->bad_itl_ba);
812053790Sobrien
812153790Sobrien	/*
812253790Sobrien	 *  Set the reselect pattern to our default. :)
812353790Sobrien	 */
812453790Sobrien	lp->resel_sa = cpu_to_scr(SCRIPTH_BA(np, resel_bad_lun));
812553790Sobrien
812653790Sobrien	/*
812753790Sobrien	 *  Set user capabilities.
812853790Sobrien	 */
812953790Sobrien	lp->user_flags = tp->usrflags & (SYM_DISC_ENABLED | SYM_TAGS_ENABLED);
813053790Sobrien
813153790Sobrienfail:
813253790Sobrien	return lp;
813353790Sobrien}
813453790Sobrien
813553790Sobrien/*
813653790Sobrien *  Allocate LCB resources for tagged command queuing.
813753790Sobrien */
813853790Sobrienstatic void sym_alloc_lcb_tags (hcb_p np, u_char tn, u_char ln)
813953790Sobrien{
814053790Sobrien	tcb_p tp = &np->target[tn];
814153790Sobrien	lcb_p lp = sym_lp(np, tp, ln);
814253790Sobrien	int i;
814353790Sobrien
814453790Sobrien	/*
814553790Sobrien	 *  If LCB not available, try to allocate it.
814653790Sobrien	 */
814753790Sobrien	if (!lp && !(lp = sym_alloc_lcb(np, tn, ln)))
814853790Sobrien		goto fail;
814953790Sobrien
815053790Sobrien	/*
815153790Sobrien	 *  Allocate the task table and and the tag allocation
815253790Sobrien	 *  circular buffer. We want both or none.
815353790Sobrien	 */
815454690Sobrien	lp->itlq_tbl = sym_calloc(SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
815553790Sobrien	if (!lp->itlq_tbl)
815653790Sobrien		goto fail;
815754690Sobrien	lp->cb_tags = sym_calloc(SYM_CONF_MAX_TASK, "CB_TAGS");
815853790Sobrien	if (!lp->cb_tags) {
815954690Sobrien		sym_mfree(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
816053790Sobrien		lp->itlq_tbl = 0;
816153790Sobrien		goto fail;
816253790Sobrien	}
816353790Sobrien
816453790Sobrien	/*
816553790Sobrien	 *  Initialize the task table with invalid entries.
816653790Sobrien	 */
816754690Sobrien	for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++)
816853790Sobrien		lp->itlq_tbl[i] = cpu_to_scr(np->notask_ba);
816953790Sobrien
817053790Sobrien	/*
817153790Sobrien	 *  Fill up the tag buffer with tag numbers.
817253790Sobrien	 */
817354690Sobrien	for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++)
817453790Sobrien		lp->cb_tags[i] = i;
817553790Sobrien
817653790Sobrien	/*
817753790Sobrien	 *  Make the task table available to SCRIPTS,
817853790Sobrien	 *  And accept tagged commands now.
817953790Sobrien	 */
818053790Sobrien	lp->itlq_tbl_sa = cpu_to_scr(vtobus(lp->itlq_tbl));
818153790Sobrien
818253790Sobrien	return;
818353790Sobrienfail:
818453790Sobrien}
818553790Sobrien
818653790Sobrien/*
818753790Sobrien *  Test the pci bus snoop logic :-(
818853790Sobrien *
818953790Sobrien *  Has to be called with interrupts disabled.
819053790Sobrien */
819154690Sobrien#ifndef SYM_CONF_IOMAPPED
819253790Sobrienstatic int sym_regtest (hcb_p np)
819353790Sobrien{
819453790Sobrien	register volatile u32 data;
819553790Sobrien	/*
819653790Sobrien	 *  chip registers may NOT be cached.
819753790Sobrien	 *  write 0xffffffff to a read only register area,
819853790Sobrien	 *  and try to read it back.
819953790Sobrien	 */
820053790Sobrien	data = 0xffffffff;
820153790Sobrien	OUTL_OFF(offsetof(struct sym_reg, nc_dstat), data);
820253790Sobrien	data = INL_OFF(offsetof(struct sym_reg, nc_dstat));
820353790Sobrien#if 1
820453790Sobrien	if (data == 0xffffffff) {
820553790Sobrien#else
820653790Sobrien	if ((data & 0xe2f0fffd) != 0x02000080) {
820753790Sobrien#endif
820853790Sobrien		printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
820953790Sobrien			(unsigned) data);
821053790Sobrien		return (0x10);
821153790Sobrien	};
821253790Sobrien	return (0);
821353790Sobrien}
821453790Sobrien#endif
821553790Sobrien
821653790Sobrienstatic int sym_snooptest (hcb_p np)
821753790Sobrien{
821853790Sobrien	u32	sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc;
821953790Sobrien	int	i, err=0;
822054690Sobrien#ifndef SYM_CONF_IOMAPPED
822153790Sobrien	err |= sym_regtest (np);
822253790Sobrien	if (err) return (err);
822353790Sobrien#endif
822453790Sobrien	/*
822553790Sobrien	 *  init
822653790Sobrien	 */
822753790Sobrien	pc  = SCRIPTH0_BA (np, snooptest);
822853790Sobrien	host_wr = 1;
822953790Sobrien	sym_wr  = 2;
823053790Sobrien	/*
823153790Sobrien	 *  Set memory and register.
823253790Sobrien	 */
823353790Sobrien	np->cache = cpu_to_scr(host_wr);
823453790Sobrien	OUTL (nc_temp, sym_wr);
823553790Sobrien	/*
823653790Sobrien	 *  Start script (exchange values)
823753790Sobrien	 */
823853790Sobrien	OUTL (nc_dsa, vtobus(np));
823953790Sobrien	OUTL (nc_dsp, pc);
824053790Sobrien	/*
824153790Sobrien	 *  Wait 'til done (with timeout)
824253790Sobrien	 */
824353790Sobrien	for (i=0; i<SYM_SNOOP_TIMEOUT; i++)
824453790Sobrien		if (INB(nc_istat) & (INTF|SIP|DIP))
824553790Sobrien			break;
824653790Sobrien	/*
824753790Sobrien	 *  Save termination position.
824853790Sobrien	 */
824953790Sobrien	pc = INL (nc_dsp);
825053790Sobrien	/*
825153790Sobrien	 *  Read memory and register.
825253790Sobrien	 */
825353790Sobrien	host_rd = scr_to_cpu(np->cache);
825453790Sobrien	sym_rd  = INL (nc_scratcha);
825553790Sobrien	sym_bk  = INL (nc_temp);
825653790Sobrien
825753790Sobrien	/*
825853790Sobrien	 *  check for timeout
825953790Sobrien	 */
826053790Sobrien	if (i>=SYM_SNOOP_TIMEOUT) {
826153790Sobrien		printf ("CACHE TEST FAILED: timeout.\n");
826253790Sobrien		return (0x20);
826353790Sobrien	};
826453790Sobrien	/*
826553790Sobrien	 *  Check termination position.
826653790Sobrien	 */
826753790Sobrien	if (pc != SCRIPTH0_BA (np, snoopend)+8) {
826853790Sobrien		printf ("CACHE TEST FAILED: script execution failed.\n");
826953790Sobrien		printf ("start=%08lx, pc=%08lx, end=%08lx\n",
827053790Sobrien			(u_long) SCRIPTH0_BA (np, snooptest), (u_long) pc,
827153790Sobrien			(u_long) SCRIPTH0_BA (np, snoopend) +8);
827253790Sobrien		return (0x40);
827353790Sobrien	};
827453790Sobrien	/*
827553790Sobrien	 *  Show results.
827653790Sobrien	 */
827753790Sobrien	if (host_wr != sym_rd) {
827853790Sobrien		printf ("CACHE TEST FAILED: host wrote %d, chip read %d.\n",
827953790Sobrien			(int) host_wr, (int) sym_rd);
828053790Sobrien		err |= 1;
828153790Sobrien	};
828253790Sobrien	if (host_rd != sym_wr) {
828353790Sobrien		printf ("CACHE TEST FAILED: chip wrote %d, host read %d.\n",
828453790Sobrien			(int) sym_wr, (int) host_rd);
828553790Sobrien		err |= 2;
828653790Sobrien	};
828753790Sobrien	if (sym_bk != sym_wr) {
828853790Sobrien		printf ("CACHE TEST FAILED: chip wrote %d, read back %d.\n",
828953790Sobrien			(int) sym_wr, (int) sym_bk);
829053790Sobrien		err |= 4;
829153790Sobrien	};
829253790Sobrien	return (err);
829353790Sobrien}
829453790Sobrien
829553790Sobrien/*
829653790Sobrien *  Determine the chip's clock frequency.
829753790Sobrien *
829853790Sobrien *  This is essential for the negotiation of the synchronous
829953790Sobrien *  transfer rate.
830053790Sobrien *
830153790Sobrien *  Note: we have to return the correct value.
830253790Sobrien *  THERE IS NO SAFE DEFAULT VALUE.
830353790Sobrien *
830453790Sobrien *  Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
830553790Sobrien *  53C860 and 53C875 rev. 1 support fast20 transfers but
830653790Sobrien *  do not have a clock doubler and so are provided with a
830753790Sobrien *  80 MHz clock. All other fast20 boards incorporate a doubler
830853790Sobrien *  and so should be delivered with a 40 MHz clock.
830953790Sobrien *  The recent fast40 chips (895/896/895A/1010) use a 40 Mhz base
831053790Sobrien *  clock and provide a clock quadrupler (160 Mhz).
831153790Sobrien */
831253790Sobrien
831353790Sobrien/*
831453790Sobrien *  Select SCSI clock frequency
831553790Sobrien */
831653790Sobrienstatic void sym_selectclock(hcb_p np, u_char scntl3)
831753790Sobrien{
831853790Sobrien	/*
831953790Sobrien	 *  If multiplier not present or not selected, leave here.
832053790Sobrien	 */
832153790Sobrien	if (np->multiplier <= 1) {
832253790Sobrien		OUTB(nc_scntl3,	scntl3);
832353790Sobrien		return;
832453790Sobrien	}
832553790Sobrien
832653790Sobrien	if (sym_verbose >= 2)
832753790Sobrien		printf ("%s: enabling clock multiplier\n", sym_name(np));
832853790Sobrien
832953790Sobrien	OUTB(nc_stest1, DBLEN);	   /* Enable clock multiplier		  */
833053790Sobrien	/*
833153790Sobrien	 *  Wait for the LCKFRQ bit to be set if supported by the chip.
833253790Sobrien	 *  Otherwise wait 20 micro-seconds.
833353790Sobrien	 */
833453790Sobrien	if (np->features & FE_LCKFRQ) {
833553790Sobrien		int i = 20;
833653790Sobrien		while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
833753790Sobrien			UDELAY (20);
833853790Sobrien		if (!i)
833953790Sobrien			printf("%s: the chip cannot lock the frequency\n",
834053790Sobrien				sym_name(np));
834153790Sobrien	} else
834253790Sobrien		UDELAY (20);
834353790Sobrien	OUTB(nc_stest3, HSC);		/* Halt the scsi clock		*/
834453790Sobrien	OUTB(nc_scntl3,	scntl3);
834553790Sobrien	OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
834653790Sobrien	OUTB(nc_stest3, 0x00);		/* Restart scsi clock 		*/
834753790Sobrien}
834853790Sobrien
834953790Sobrien/*
835053790Sobrien *  calculate SCSI clock frequency (in KHz)
835153790Sobrien */
835253790Sobrienstatic unsigned getfreq (hcb_p np, int gen)
835353790Sobrien{
835453790Sobrien	unsigned int ms = 0;
835553790Sobrien	unsigned int f;
835653790Sobrien
835753790Sobrien	/*
835853790Sobrien	 * Measure GEN timer delay in order
835953790Sobrien	 * to calculate SCSI clock frequency
836053790Sobrien	 *
836153790Sobrien	 * This code will never execute too
836253790Sobrien	 * many loop iterations (if DELAY is
836353790Sobrien	 * reasonably correct). It could get
836453790Sobrien	 * too low a delay (too high a freq.)
836553790Sobrien	 * if the CPU is slow executing the
836653790Sobrien	 * loop for some reason (an NMI, for
836753790Sobrien	 * example). For this reason we will
836853790Sobrien	 * if multiple measurements are to be
836953790Sobrien	 * performed trust the higher delay
837053790Sobrien	 * (lower frequency returned).
837153790Sobrien	 */
837253790Sobrien	OUTW (nc_sien , 0);	/* mask all scsi interrupts */
837353790Sobrien	(void) INW (nc_sist);	/* clear pending scsi interrupt */
837453790Sobrien	OUTB (nc_dien , 0);	/* mask all dma interrupts */
837553790Sobrien	(void) INW (nc_sist);	/* another one, just to be sure :) */
837653790Sobrien	OUTB (nc_scntl3, 4);	/* set pre-scaler to divide by 3 */
837753790Sobrien	OUTB (nc_stime1, 0);	/* disable general purpose timer */
837853790Sobrien	OUTB (nc_stime1, gen);	/* set to nominal delay of 1<<gen * 125us */
837953790Sobrien	while (!(INW(nc_sist) & GEN) && ms++ < 100000)
838053790Sobrien		UDELAY (1000);	/* count ms */
838153790Sobrien	OUTB (nc_stime1, 0);	/* disable general purpose timer */
838253790Sobrien 	/*
838353790Sobrien 	 * set prescaler to divide by whatever 0 means
838453790Sobrien 	 * 0 ought to choose divide by 2, but appears
838553790Sobrien 	 * to set divide by 3.5 mode in my 53c810 ...
838653790Sobrien 	 */
838753790Sobrien 	OUTB (nc_scntl3, 0);
838853790Sobrien
838953790Sobrien  	/*
839053790Sobrien 	 * adjust for prescaler, and convert into KHz
839153790Sobrien  	 */
839253790Sobrien	f = ms ? ((1 << gen) * 4340) / ms : 0;
839353790Sobrien
839453790Sobrien	if (sym_verbose >= 2)
839553790Sobrien		printf ("%s: Delay (GEN=%d): %u msec, %u KHz\n",
839653790Sobrien			sym_name(np), gen, ms, f);
839753790Sobrien
839853790Sobrien	return f;
839953790Sobrien}
840053790Sobrien
840153790Sobrienstatic unsigned sym_getfreq (hcb_p np)
840253790Sobrien{
840353790Sobrien	u_int f1, f2;
840453790Sobrien	int gen = 11;
840553790Sobrien
840653790Sobrien	(void) getfreq (np, gen);	/* throw away first result */
840753790Sobrien	f1 = getfreq (np, gen);
840853790Sobrien	f2 = getfreq (np, gen);
840953790Sobrien	if (f1 > f2) f1 = f2;		/* trust lower result	*/
841053790Sobrien	return f1;
841153790Sobrien}
841253790Sobrien
841353790Sobrien/*
841453790Sobrien *  Get/probe chip SCSI clock frequency
841553790Sobrien */
841653790Sobrienstatic void sym_getclock (hcb_p np, int mult)
841753790Sobrien{
841853796Sobrien	unsigned char scntl3 = np->sv_scntl3;
841953796Sobrien	unsigned char stest1 = np->sv_stest1;
842053790Sobrien	unsigned f1;
842153790Sobrien
842253790Sobrien	/*
842353790Sobrien	 *  For the C10 core, assume 40 MHz.
842453790Sobrien	 */
842553790Sobrien	if (np->features & FE_C10) {
842653790Sobrien		np->multiplier = mult;
842753790Sobrien		np->clock_khz = 40000 * mult;
842853790Sobrien		return;
842953790Sobrien	}
843053790Sobrien
843153790Sobrien	np->multiplier = 1;
843253790Sobrien	f1 = 40000;
843353790Sobrien	/*
843453790Sobrien	 *  True with 875/895/896/895A with clock multiplier selected
843553790Sobrien	 */
843653790Sobrien	if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
843753790Sobrien		if (sym_verbose >= 2)
843853790Sobrien			printf ("%s: clock multiplier found\n", sym_name(np));
843953790Sobrien		np->multiplier = mult;
844053790Sobrien	}
844153790Sobrien
844253790Sobrien	/*
844353790Sobrien	 *  If multiplier not found or scntl3 not 7,5,3,
844453790Sobrien	 *  reset chip and get frequency from general purpose timer.
844553790Sobrien	 *  Otherwise trust scntl3 BIOS setting.
844653790Sobrien	 */
844753790Sobrien	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
844853790Sobrien		OUTB (nc_stest1, 0);		/* make sure doubler is OFF */
844953790Sobrien		f1 = sym_getfreq (np);
845053790Sobrien
845153790Sobrien		if (sym_verbose)
845253790Sobrien			printf ("%s: chip clock is %uKHz\n", sym_name(np), f1);
845353790Sobrien
845453790Sobrien		if	(f1 <	45000)		f1 =  40000;
845553790Sobrien		else if (f1 <	55000)		f1 =  50000;
845653790Sobrien		else				f1 =  80000;
845753790Sobrien
845853790Sobrien		if (f1 < 80000 && mult > 1) {
845953790Sobrien			if (sym_verbose >= 2)
846053790Sobrien				printf ("%s: clock multiplier assumed\n",
846153790Sobrien					sym_name(np));
846253790Sobrien			np->multiplier	= mult;
846353790Sobrien		}
846453790Sobrien	} else {
846553790Sobrien		if	((scntl3 & 7) == 3)	f1 =  40000;
846653790Sobrien		else if	((scntl3 & 7) == 5)	f1 =  80000;
846753790Sobrien		else 				f1 = 160000;
846853790Sobrien
846953790Sobrien		f1 /= np->multiplier;
847053790Sobrien	}
847153790Sobrien
847253790Sobrien	/*
847353790Sobrien	 *  Compute controller synchronous parameters.
847453790Sobrien	 */
847553790Sobrien	f1		*= np->multiplier;
847653790Sobrien	np->clock_khz	= f1;
847753790Sobrien}
847853790Sobrien
847953790Sobrien/*
848053790Sobrien *  Get/probe PCI clock frequency
848153790Sobrien */
848253790Sobrienstatic int sym_getpciclock (hcb_p np)
848353790Sobrien{
848453790Sobrien	static int f = 0;
848553790Sobrien
848653790Sobrien	/* For the C10, this will not work */
848753790Sobrien	if (!f && !(np->features & FE_C10)) {
848853790Sobrien		OUTB (nc_stest1, SCLK);	/* Use the PCI clock as SCSI clock */
848953790Sobrien		f = (int) sym_getfreq (np);
849053790Sobrien		OUTB (nc_stest1, 0);
849153790Sobrien	}
849253790Sobrien	return f;
849353790Sobrien}
849453790Sobrien
849553790Sobrien/*============= DRIVER ACTION/COMPLETION ====================*/
849653790Sobrien
849753790Sobrien/*
849853790Sobrien *  Print something that tells about extended errors.
849953790Sobrien */
850053790Sobrienstatic void sym_print_xerr(ccb_p cp, int x_status)
850153790Sobrien{
850253790Sobrien	if (x_status & XE_PARITY_ERR) {
850353790Sobrien		PRINT_ADDR(cp);
850453790Sobrien		printf ("unrecovered SCSI parity error.\n");
850553790Sobrien	}
850653790Sobrien	if (x_status & XE_EXTRA_DATA) {
850753790Sobrien		PRINT_ADDR(cp);
850853790Sobrien		printf ("extraneous data discarded.\n");
850953790Sobrien	}
851053790Sobrien	if (x_status & XE_BAD_PHASE) {
851153790Sobrien		PRINT_ADDR(cp);
851253790Sobrien		printf ("illegal scsi phase (4/5).\n");
851353790Sobrien	}
851453790Sobrien	if (x_status & XE_SODL_UNRUN) {
851553790Sobrien		PRINT_ADDR(cp);
851653790Sobrien		printf ("ODD transfer in DATA OUT phase.\n");
851753790Sobrien	}
851853790Sobrien	if (x_status & XE_SWIDE_OVRUN) {
851953790Sobrien		PRINT_ADDR(cp);
852053790Sobrien		printf ("ODD transfer in DATA IN phase.\n");
852153790Sobrien	}
852253790Sobrien}
852353790Sobrien
852453790Sobrien/*
852553790Sobrien *  Choose the more appropriate CAM status if
852653790Sobrien *  the IO encountered an extended error.
852753790Sobrien */
852853790Sobrienstatic int sym_xerr_cam_status(int cam_status, int x_status)
852953790Sobrien{
853053790Sobrien	if (x_status) {
853153790Sobrien		if	(x_status & XE_PARITY_ERR)
853253790Sobrien			cam_status = CAM_UNCOR_PARITY;
853353790Sobrien		else if	(x_status &(XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN))
853453790Sobrien			cam_status = CAM_DATA_RUN_ERR;
853553790Sobrien		else if	(x_status & XE_BAD_PHASE)
853653790Sobrien			cam_status = CAM_REQ_CMP_ERR;
853753790Sobrien		else
853853790Sobrien			cam_status = CAM_REQ_CMP_ERR;
853953790Sobrien	}
854053790Sobrien	return cam_status;
854153790Sobrien}
854253790Sobrien
854353790Sobrien/*
854453790Sobrien *  Complete execution of a SCSI command with extented
854553790Sobrien *  error, SCSI status error, or having been auto-sensed.
854653790Sobrien *
854753790Sobrien *  The SCRIPTS processor is not running there, so we
854853790Sobrien *  can safely access IO registers and remove JOBs from
854953790Sobrien *  the START queue.
855053790Sobrien *  SCRATCHA is assumed to have been loaded with STARTPOS
855153790Sobrien *  before the SCRIPTS called the C code.
855253790Sobrien */
855353790Sobrienstatic void sym_complete_error (hcb_p np, ccb_p cp)
855453790Sobrien{
855553790Sobrien	struct ccb_scsiio *csio;
855653790Sobrien	u_int cam_status;
855753790Sobrien	int i;
855853790Sobrien
855953790Sobrien	/*
856053790Sobrien	 *  Paranoid check. :)
856153790Sobrien	 */
856253790Sobrien	if (!cp || !cp->cam_ccb)
856353790Sobrien		return;
856453790Sobrien
856553790Sobrien	if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_RESULT)) {
856653790Sobrien		printf ("CCB=%lx STAT=%x/%x/%x DEV=%d/%d\n", (unsigned long)cp,
856753790Sobrien			cp->host_status, cp->ssss_status, cp->host_flags,
856853790Sobrien			cp->target, cp->lun);
856953790Sobrien		MDELAY(100);
857053790Sobrien	}
857153790Sobrien
857253790Sobrien	/*
857353790Sobrien	 *  Get command, target and lun pointers.
857453790Sobrien	 */
857553790Sobrien	csio = &cp->cam_ccb->csio;
857653790Sobrien
857753790Sobrien	/*
857853790Sobrien	 *  Check for extended errors.
857953790Sobrien	 */
858053790Sobrien	if (cp->xerr_status) {
858153790Sobrien		if (sym_verbose)
858253790Sobrien			sym_print_xerr(cp, cp->xerr_status);
858353790Sobrien		if (cp->host_status == HS_COMPLETE)
858453790Sobrien			cp->host_status = HS_COMP_ERR;
858553790Sobrien	}
858653790Sobrien
858753790Sobrien	/*
858853790Sobrien	 *  Calculate the residual.
858953790Sobrien	 */
859053790Sobrien	csio->sense_resid = 0;
859153790Sobrien	csio->resid = sym_compute_residual(np, cp);
859253790Sobrien
859354690Sobrien	if (!SYM_CONF_RESIDUAL_SUPPORT) {/* If user does not want residuals */
859453790Sobrien		csio->resid  = 0;	/* throw them away. :)		   */
859553790Sobrien		cp->sv_resid = 0;
859653790Sobrien	}
859753790Sobrien
859853790Sobrien	if (cp->host_flags & HF_SENSE) {		/* Auto sense     */
859953790Sobrien		csio->scsi_status = cp->sv_scsi_status;	/* Restore status */
860053790Sobrien		csio->sense_resid = csio->resid;	/* Swap residuals */
860153790Sobrien		csio->resid       = cp->sv_resid;
860253790Sobrien		cp->sv_resid	  = 0;
860353790Sobrien		if (sym_verbose && cp->sv_xerr_status)
860453790Sobrien			sym_print_xerr(cp, cp->sv_xerr_status);
860553790Sobrien		if (cp->host_status == HS_COMPLETE &&
860653790Sobrien		    cp->ssss_status == S_GOOD &&
860753790Sobrien		    cp->xerr_status == 0) {
860853790Sobrien			cam_status = sym_xerr_cam_status(CAM_SCSI_STATUS_ERROR,
860953790Sobrien							 cp->sv_xerr_status);
861053790Sobrien			cam_status |= CAM_AUTOSNS_VALID;
861153790Sobrien#if 0
861253790Sobrien			/*
861353790Sobrien			 *  If the device reports a UNIT ATTENTION condition
861453790Sobrien			 *  due to a RESET condition, we should consider all
861553790Sobrien			 *  disconnect CCBs for this unit as aborted.
861653790Sobrien			 */
861753790Sobrien			if (1) {
861853790Sobrien				u_char *p;
861953790Sobrien				p  = (u_char *) &cp->cam_ccb->csio.sense_data;
862053790Sobrien				if (p[0]==0x70 && p[2]==0x6 && p[12]==0x29)
862153790Sobrien					sym_clear_tasks(np, CAM_REQ_ABORTED,
862253790Sobrien							cp->target,cp->lun, -1);
862353790Sobrien			}
862453790Sobrien#endif
862553790Sobrien		}
862653790Sobrien		else
862753790Sobrien			cam_status = CAM_AUTOSENSE_FAIL;
862853790Sobrien	}
862953790Sobrien	else if (cp->host_status == HS_COMPLETE) {	/* Bad SCSI status */
863053790Sobrien		csio->scsi_status = cp->ssss_status;
863153790Sobrien		cam_status = CAM_SCSI_STATUS_ERROR;
863253790Sobrien	}
863353790Sobrien	else if (cp->host_status == HS_SEL_TIMEOUT)	/* Selection timeout */
863453790Sobrien		cam_status = CAM_SEL_TIMEOUT;
863553790Sobrien	else if (cp->host_status == HS_UNEXPECTED)	/* Unexpected BUS FREE*/
863653790Sobrien		cam_status = CAM_UNEXP_BUSFREE;
863753790Sobrien	else {						/* Extended error */
863853790Sobrien		if (sym_verbose) {
863953790Sobrien			PRINT_ADDR(cp);
864053790Sobrien			printf ("COMMAND FAILED (%x %x %x).\n",
864153790Sobrien				cp->host_status, cp->ssss_status,
864253790Sobrien				cp->xerr_status);
864353790Sobrien		}
864453790Sobrien		csio->scsi_status = cp->ssss_status;
864553790Sobrien		/*
864653790Sobrien		 *  Set the most appropriate value for CAM status.
864753790Sobrien		 */
864853790Sobrien		cam_status = sym_xerr_cam_status(CAM_REQ_CMP_ERR,
864953790Sobrien						 cp->xerr_status);
865053790Sobrien	}
865153790Sobrien
865253790Sobrien	/*
865353790Sobrien	 *  Dequeue all queued CCBs for that device
865453790Sobrien	 *  not yet started by SCRIPTS.
865553790Sobrien	 */
865653790Sobrien	i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
865753790Sobrien	(void) sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1);
865853790Sobrien
865953790Sobrien	/*
866053790Sobrien	 *  Restart the SCRIPTS processor.
866153790Sobrien	 */
866253790Sobrien	OUTL (nc_dsp, SCRIPT_BA (np, start));
866353790Sobrien
866453790Sobrien	/*
866553790Sobrien	 *  Add this one to the COMP queue.
866653790Sobrien	 *  Complete all those commands with either error
866753790Sobrien	 *  or requeue condition.
866853790Sobrien	 */
866953790Sobrien	sym_set_cam_status((union ccb *) csio, cam_status);
867053790Sobrien	sym_remque(&cp->link_ccbq);
867153790Sobrien	sym_insque_head(&cp->link_ccbq, &np->comp_ccbq);
867253790Sobrien	sym_flush_comp_queue(np, 0);
867353790Sobrien}
867453790Sobrien
867553790Sobrien/*
867653790Sobrien *  Complete execution of a successful SCSI command.
867753790Sobrien *
867853790Sobrien *  Only successful commands go to the DONE queue,
867953790Sobrien *  since we need to have the SCRIPTS processor
868053790Sobrien *  stopped on any error condition.
868153790Sobrien *  The SCRIPTS processor is running while we are
868253790Sobrien *  completing successful commands.
868353790Sobrien */
868453790Sobrienstatic void sym_complete_ok (hcb_p np, ccb_p cp)
868553790Sobrien{
868653790Sobrien	struct ccb_scsiio *csio;
868753790Sobrien	tcb_p tp;
868853790Sobrien	lcb_p lp;
868953790Sobrien
869053790Sobrien	/*
869153790Sobrien	 *  Paranoid check. :)
869253790Sobrien	 */
869353790Sobrien	if (!cp || !cp->cam_ccb)
869453790Sobrien		return;
869553790Sobrien	assert (cp->host_status == HS_COMPLETE);
869653790Sobrien
869753790Sobrien	/*
869853790Sobrien	 *  Get command, target and lun pointers.
869953790Sobrien	 */
870053790Sobrien	csio = &cp->cam_ccb->csio;
870153790Sobrien	tp = &np->target[cp->target];
870253790Sobrien	lp = sym_lp(np, tp, cp->lun);
870353790Sobrien
870453790Sobrien	/*
870553790Sobrien	 *  Assume device discovered on first success.
870653790Sobrien	 */
870753790Sobrien	if (!lp)
870853790Sobrien		sym_set_bit(tp->lun_map, cp->lun);
870953790Sobrien
871053790Sobrien	/*
871153790Sobrien	 *  If all data have been transferred, given than no
871253790Sobrien	 *  extended error did occur, there is no residual.
871353790Sobrien	 */
871453790Sobrien	csio->resid = 0;
871553790Sobrien	if (cp->phys.lastp != cp->phys.goalp)
871653790Sobrien		csio->resid = sym_compute_residual(np, cp);
871753790Sobrien
871853790Sobrien	/*
871953790Sobrien	 *  Wrong transfer residuals may be worse than just always
872053790Sobrien	 *  returning zero. User can disable this feature from
872153790Sobrien	 *  sym_conf.h. Residual support is enabled by default.
872253790Sobrien	 */
872354690Sobrien	if (!SYM_CONF_RESIDUAL_SUPPORT)
872453790Sobrien		csio->resid  = 0;
872553790Sobrien
872653790Sobrien	/*
872753790Sobrien	 *  Set status and complete the command.
872853790Sobrien	 */
872953790Sobrien	csio->scsi_status = cp->ssss_status;
873053790Sobrien	sym_set_cam_status((union ccb *) csio, CAM_REQ_CMP);
873153790Sobrien	sym_free_ccb (np, cp);
873253790Sobrien	sym_xpt_done(np, (union ccb *) csio);
873353790Sobrien}
873453790Sobrien
873553790Sobrien/*
873653790Sobrien *  Our timeout handler.
873753790Sobrien */
873853790Sobrienstatic void sym_timeout1(void *arg)
873953790Sobrien{
874053790Sobrien	union ccb *ccb = (union ccb *) arg;
874153790Sobrien	hcb_p np = ccb->ccb_h.sym_hcb_ptr;
874253790Sobrien
874353790Sobrien	/*
874453790Sobrien	 *  Check that the CAM CCB is still queued.
874553790Sobrien	 */
874653790Sobrien	if (!np)
874753790Sobrien		return;
874853790Sobrien
874953790Sobrien	switch(ccb->ccb_h.func_code) {
875053790Sobrien	case XPT_SCSI_IO:
875153790Sobrien		(void) sym_abort_scsiio(np, ccb, 1);
875253790Sobrien		break;
875353790Sobrien	default:
875453790Sobrien		break;
875553790Sobrien	}
875653790Sobrien}
875753790Sobrien
875853790Sobrienstatic void sym_timeout(void *arg)
875953790Sobrien{
876053790Sobrien	int s = splcam();
876153790Sobrien	sym_timeout1(arg);
876253790Sobrien	splx(s);
876353790Sobrien}
876453790Sobrien
876553790Sobrien/*
876653790Sobrien *  Abort an SCSI IO.
876753790Sobrien */
876853790Sobrienstatic int sym_abort_scsiio(hcb_p np, union ccb *ccb, int timed_out)
876953790Sobrien{
877053790Sobrien	ccb_p cp;
877155300Sgroudier	SYM_QUEHEAD *qp;
877253790Sobrien
877353790Sobrien	/*
877453790Sobrien	 *  Look up our CCB control block.
877553790Sobrien	 */
877655300Sgroudier	cp = 0;
877755300Sgroudier	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
877855300Sgroudier		ccb_p cp2 = sym_que_entry(qp, struct sym_ccb, link_ccbq);
877955300Sgroudier		if (cp2->cam_ccb == ccb) {
878055300Sgroudier			cp = cp2;
878153790Sobrien			break;
878255300Sgroudier		}
878353790Sobrien	}
878453790Sobrien	if (!cp)
878553790Sobrien		return -1;
878653790Sobrien
878753790Sobrien	/*
878853790Sobrien	 *  If a previous abort didn't succeed in time,
878953790Sobrien	 *  perform a BUS reset.
879053790Sobrien	 */
879153790Sobrien	if (cp->to_abort) {
879253790Sobrien		sym_reset_scsi_bus(np, 1);
879353790Sobrien		return 0;
879453790Sobrien	}
879553790Sobrien
879653790Sobrien	/*
879753790Sobrien	 *  Mark the CCB for abort and allow time for.
879853790Sobrien	 */
879953790Sobrien	cp->to_abort = timed_out ? 2 : 1;
880053790Sobrien	ccb->ccb_h.timeout_ch = timeout(sym_timeout, (caddr_t) ccb, 10*hz);
880153790Sobrien
880253790Sobrien	/*
880353790Sobrien	 *  Tell the SCRIPTS processor to stop and synchronize with us.
880453790Sobrien	 */
880553790Sobrien	np->istat_sem = SEM;
880653790Sobrien	OUTB (nc_istat, SIGP|SEM);
880753790Sobrien	return 0;
880853790Sobrien}
880953790Sobrien
881053790Sobrien/*
881153790Sobrien *  Reset a SCSI device (all LUNs of a target).
881253790Sobrien */
881353790Sobrienstatic void sym_reset_dev(hcb_p np, union ccb *ccb)
881453790Sobrien{
881553790Sobrien	tcb_p tp;
881653790Sobrien	struct ccb_hdr *ccb_h = &ccb->ccb_h;
881753790Sobrien
881853790Sobrien	if (ccb_h->target_id   == np->myaddr ||
881954690Sobrien	    ccb_h->target_id   >= SYM_CONF_MAX_TARGET ||
882054690Sobrien	    ccb_h->target_lun  >= SYM_CONF_MAX_LUN) {
882153790Sobrien		sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE);
882253790Sobrien		return;
882353790Sobrien	}
882453790Sobrien
882553790Sobrien	tp = &np->target[ccb_h->target_id];
882653790Sobrien
882753790Sobrien	tp->to_reset = 1;
882853790Sobrien	sym_xpt_done2(np, ccb, CAM_REQ_CMP);
882953790Sobrien
883053790Sobrien	np->istat_sem = SEM;
883153790Sobrien	OUTB (nc_istat, SIGP|SEM);
883253790Sobrien	return;
883353790Sobrien}
883453790Sobrien
883553790Sobrien/*
883653790Sobrien *  SIM action entry point.
883753790Sobrien */
883853790Sobrienstatic void sym_action(struct cam_sim *sim, union ccb *ccb)
883953790Sobrien{
884053790Sobrien	int s = splcam();
884153790Sobrien	sym_action1(sim, ccb);
884253790Sobrien	splx(s);
884353790Sobrien}
884453790Sobrien
884553790Sobrienstatic void sym_action1(struct cam_sim *sim, union ccb *ccb)
884653790Sobrien{
884753790Sobrien	hcb_p	np;
884853790Sobrien	tcb_p	tp;
884953790Sobrien	lcb_p	lp;
885053790Sobrien	ccb_p	cp;
885153790Sobrien	int 	tmp;
885253790Sobrien	u_char	idmsg, *msgptr;
885353790Sobrien	u_int   msglen;
885453790Sobrien	struct	ccb_scsiio *csio;
885553790Sobrien	struct	ccb_hdr  *ccb_h;
885653790Sobrien
885753790Sobrien	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("sym_action\n"));
885853790Sobrien
885953790Sobrien	/*
886053790Sobrien	 *  Retrieve our controller data structure.
886153790Sobrien	 */
886253790Sobrien	np = (hcb_p) cam_sim_softc(sim);
886353790Sobrien
886453790Sobrien	/*
886553790Sobrien	 *  The common case is SCSI IO.
886653790Sobrien	 *  We deal with other ones elsewhere.
886753790Sobrien	 */
886853790Sobrien	if (ccb->ccb_h.func_code != XPT_SCSI_IO) {
886953790Sobrien		sym_action2(sim, ccb);
887053790Sobrien		return;
887153790Sobrien	}
887253790Sobrien	csio  = &ccb->csio;
887353790Sobrien	ccb_h = &csio->ccb_h;
887453790Sobrien
887553790Sobrien	/*
887653790Sobrien	 *  Work around races.
887753790Sobrien	 */
887853790Sobrien	if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) {
887953790Sobrien		xpt_done(ccb);
888053790Sobrien		return;
888153790Sobrien	}
888253790Sobrien
888353790Sobrien	/*
888453790Sobrien	 *  Minimal checkings, so that we will not
888553790Sobrien	 *  go outside our tables.
888653790Sobrien	 */
888753790Sobrien	if (ccb_h->target_id   == np->myaddr ||
888854690Sobrien	    ccb_h->target_id   >= SYM_CONF_MAX_TARGET ||
888954690Sobrien	    ccb_h->target_lun  >= SYM_CONF_MAX_LUN) {
889053790Sobrien		sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE);
889153790Sobrien		return;
889253790Sobrien        }
889353790Sobrien
889453790Sobrien	/*
889553790Sobrien	 *  Retreive the target and lun descriptors.
889653790Sobrien	 */
889753790Sobrien	tp = &np->target[ccb_h->target_id];
889853790Sobrien	lp = sym_lp(np, tp, ccb_h->target_lun);
889953790Sobrien
890053790Sobrien	/*
890153790Sobrien	 *  Complete the 1st INQUIRY command with error
890253790Sobrien	 *  condition if the device is flagged NOSCAN
890353790Sobrien	 *  at BOOT in the NVRAM. This may speed up
890453790Sobrien	 *  the boot and maintain coherency with BIOS
890553790Sobrien	 *  device numbering. Clearing the flag allows
890653790Sobrien	 *  user to rescan skipped devices later.
890753790Sobrien	 *  We also return error for devices not flagged
890853790Sobrien	 *  for SCAN LUNS in the NVRAM since some mono-lun
890953790Sobrien	 *  devices behave badly when asked for some non
891053790Sobrien	 *  zero LUN. Btw, this is an absolute hack.:-)
891153790Sobrien	 */
891253790Sobrien	if (!(ccb_h->flags & CAM_CDB_PHYS) &&
891353790Sobrien	    (0x12 == ((ccb_h->flags & CAM_CDB_POINTER) ?
891453790Sobrien		  csio->cdb_io.cdb_ptr[0] : csio->cdb_io.cdb_bytes[0]))) {
891553790Sobrien		if ((tp->usrflags & SYM_SCAN_BOOT_DISABLED) ||
891653790Sobrien		    ((tp->usrflags & SYM_SCAN_LUNS_DISABLED) &&
891753790Sobrien		     ccb_h->target_lun != 0)) {
891853790Sobrien			tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
891953790Sobrien			sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE);
892053790Sobrien			return;
892153790Sobrien		}
892253790Sobrien	}
892353790Sobrien
892453790Sobrien	/*
892553790Sobrien	 *  Get a control block for this IO.
892653790Sobrien	 */
892753790Sobrien	tmp = ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0);
892853790Sobrien	cp = sym_get_ccb(np, ccb_h->target_id, ccb_h->target_lun, tmp);
892953790Sobrien	if (!cp) {
893053790Sobrien		sym_xpt_done2(np, ccb, CAM_RESRC_UNAVAIL);
893153790Sobrien		return;
893253790Sobrien	}
893353790Sobrien
893453790Sobrien	/*
893553790Sobrien	 *  Enqueue this IO in our pending queue.
893653790Sobrien	 */
893753790Sobrien	cp->cam_ccb = ccb;
893853790Sobrien	sym_enqueue_cam_ccb(np, ccb);
893953790Sobrien
894053790Sobrien	/*
894153790Sobrien	 *  Build the IDENTIFY message.
894253790Sobrien	 */
894353790Sobrien	idmsg = M_IDENTIFY | cp->lun;
894453790Sobrien	if (cp->tag != NO_TAG || (lp && (lp->current_flags & SYM_DISC_ENABLED)))
894553790Sobrien		idmsg |= 0x40;
894653790Sobrien
894753790Sobrien	msgptr = cp->scsi_smsg;
894853790Sobrien	msglen = 0;
894953790Sobrien	msgptr[msglen++] = idmsg;
895053790Sobrien
895153790Sobrien	/*
895253790Sobrien	 *  Build the tag message if present.
895353790Sobrien	 */
895453790Sobrien	if (cp->tag != NO_TAG) {
895553790Sobrien		u_char order = csio->tag_action;
895653790Sobrien
895753790Sobrien		switch(order) {
895853790Sobrien		case M_ORDERED_TAG:
895953790Sobrien			break;
896053790Sobrien		case M_HEAD_TAG:
896153790Sobrien			break;
896253790Sobrien		default:
896353790Sobrien			order = M_SIMPLE_TAG;
896453790Sobrien		}
896553790Sobrien		msgptr[msglen++] = order;
896653790Sobrien
896753790Sobrien		/*
896853790Sobrien		 *  For less than 128 tags, actual tags are numbered
896953790Sobrien		 *  1,3,5,..2*MAXTAGS+1,since we may have to deal
897053790Sobrien		 *  with devices that have problems with #TAG 0 or too
897153790Sobrien		 *  great #TAG numbers. For more tags (up to 256),
897253790Sobrien		 *  we use directly our tag number.
897353790Sobrien		 */
897454690Sobrien#if SYM_CONF_MAX_TASK > (512/4)
897553790Sobrien		msgptr[msglen++] = cp->tag;
897653790Sobrien#else
897753790Sobrien		msgptr[msglen++] = (cp->tag << 1) + 1;
897853790Sobrien#endif
897953790Sobrien	}
898053790Sobrien
898153790Sobrien	/*
898253790Sobrien	 *  Build a negotiation message if needed.
898353790Sobrien	 *  (nego_status is filled by sym_prepare_nego())
898453790Sobrien	 */
898553790Sobrien	cp->nego_status = 0;
898653790Sobrien	if (tp->tinfo.current.width   != tp->tinfo.goal.width  ||
898753790Sobrien	    tp->tinfo.current.period  != tp->tinfo.goal.period ||
898853790Sobrien	    tp->tinfo.current.offset  != tp->tinfo.goal.offset ||
898953790Sobrien#if 0 /* For now only renegotiate, based on width, period and offset */
899053790Sobrien	    tp->tinfo.current.options != tp->tinfo.goal.options) {
899153790Sobrien#else
899253790Sobrien	    0) {
899353790Sobrien#endif
899453790Sobrien		if (!tp->nego_cp && lp)
899553790Sobrien			msglen += sym_prepare_nego(np, cp, 0, msgptr + msglen);
899653790Sobrien	}
899753790Sobrien
899853790Sobrien	/*
899953790Sobrien	 *  Fill in our ccb
900053790Sobrien	 */
900153790Sobrien
900253790Sobrien	/*
900353790Sobrien	 *  Startqueue
900453790Sobrien	 */
900553790Sobrien	cp->phys.go.start   = cpu_to_scr(SCRIPT_BA (np, select));
900653790Sobrien	cp->phys.go.restart = cpu_to_scr(SCRIPT_BA (np, resel_dsa));
900753790Sobrien
900853790Sobrien	/*
900953790Sobrien	 *  select
901053790Sobrien	 */
901153790Sobrien	cp->phys.select.sel_id		= cp->target;
901253790Sobrien	cp->phys.select.sel_scntl3	= tp->wval;
901353790Sobrien	cp->phys.select.sel_sxfer	= tp->sval;
901453790Sobrien	cp->phys.select.sel_scntl4	= tp->uval;
901553790Sobrien
901653790Sobrien	/*
901753790Sobrien	 *  message
901853790Sobrien	 */
901953790Sobrien	cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
902053790Sobrien	cp->phys.smsg.size	= cpu_to_scr(msglen);
902153790Sobrien
902253790Sobrien	/*
902353790Sobrien	 *  command
902453790Sobrien	 */
902553790Sobrien	if (sym_setup_cdb(np, csio, cp) < 0) {
902653790Sobrien		sym_free_ccb(np, cp);
902753790Sobrien		sym_xpt_done(np, ccb);
902853790Sobrien		return;
902953790Sobrien	}
903053790Sobrien
903153790Sobrien	/*
903253790Sobrien	 *  status
903353790Sobrien	 */
903453790Sobrien#if	0	/* Provision */
903553790Sobrien	cp->actualquirks	= tp->quirks;
903653790Sobrien#endif
903753790Sobrien	cp->actualquirks	= SYM_QUIRK_AUTOSAVE;
903853790Sobrien	cp->host_status		= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
903953790Sobrien	cp->ssss_status		= S_ILLEGAL;
904053790Sobrien	cp->xerr_status		= 0;
904153790Sobrien	cp->host_flags		= 0;
904253790Sobrien	cp->phys.extra_bytes	= 0;
904353790Sobrien
904453790Sobrien	/*
904553790Sobrien	 *  extreme data pointer.
904653790Sobrien	 *  shall be positive, so -1 is lower than lowest.:)
904753790Sobrien	 */
904853790Sobrien	cp->ext_sg  = -1;
904953790Sobrien	cp->ext_ofs = 0;
905053790Sobrien
905153790Sobrien	/*
905253790Sobrien	 *  Build the data descriptor block
905353790Sobrien	 *  and start the IO.
905453790Sobrien	 */
905553790Sobrien	if (sym_setup_data(np, csio, cp) < 0) {
905653790Sobrien		sym_free_ccb(np, cp);
905753790Sobrien		sym_xpt_done(np, ccb);
905853790Sobrien		return;
905953790Sobrien	}
906053790Sobrien}
906153790Sobrien
906253790Sobrien/*
906353790Sobrien *  How complex it gets to deal with the CDB in CAM.
906453790Sobrien *  I bet, physical CDBs will never be used on the planet.
906553790Sobrien */
906653790Sobrienstatic int sym_setup_cdb(hcb_p np, struct ccb_scsiio *csio, ccb_p cp)
906753790Sobrien{
906853790Sobrien	struct ccb_hdr *ccb_h;
906953790Sobrien	u32	cmd_ba;
907053790Sobrien	int	cmd_len;
907153790Sobrien
907253790Sobrien	ccb_h = &csio->ccb_h;
907353790Sobrien
907453790Sobrien	/*
907553790Sobrien	 *  CDB is 16 bytes max.
907653790Sobrien	 */
907753790Sobrien	if (csio->cdb_len > 16) {
907853790Sobrien		sym_set_cam_status(cp->cam_ccb, CAM_REQ_INVALID);
907953790Sobrien		return -1;
908053790Sobrien	}
908153790Sobrien	cmd_len = csio->cdb_len;
908253790Sobrien
908353790Sobrien	if (ccb_h->flags & CAM_CDB_POINTER) {
908453790Sobrien		/* CDB is a pointer */
908553790Sobrien		if (!(ccb_h->flags & CAM_CDB_PHYS)) {
908653790Sobrien			/* CDB pointer is virtual */
908753790Sobrien			cmd_ba = vtobus(csio->cdb_io.cdb_ptr);
908853790Sobrien		} else {
908953790Sobrien			/* CDB pointer is physical */
909053790Sobrien#if 0
909153790Sobrien			cmd_ba = ((u32)csio->cdb_io.cdb_ptr) & 0xffffffff;
909253790Sobrien#else
909353790Sobrien			sym_set_cam_status(cp->cam_ccb, CAM_REQ_INVALID);
909453790Sobrien			return -1;
909553790Sobrien#endif
909653790Sobrien		}
909753790Sobrien	} else {
909853790Sobrien		/* CDB is in the ccb (buffer) */
909953790Sobrien		cmd_ba = vtobus(csio->cdb_io.cdb_bytes);
910053790Sobrien	}
910153790Sobrien
910253790Sobrien	cp->phys.cmd.addr	= cpu_to_scr(cmd_ba);
910353790Sobrien	cp->phys.cmd.size	= cpu_to_scr(cmd_len);
910453790Sobrien
910553790Sobrien	return 0;
910653790Sobrien}
910753790Sobrien
910853790Sobrien/*
910953790Sobrien *  How complex it gets to deal with the data in CAM.
911053790Sobrien *  I bet physical data will never be used in our galaxy.
911153790Sobrien */
911253790Sobrienstatic int sym_setup_data(hcb_p np, struct ccb_scsiio *csio, ccb_p cp)
911353790Sobrien{
911453790Sobrien	struct ccb_hdr *ccb_h;
911553790Sobrien	int dir, retv;
911653790Sobrien	u32 lastp, goalp;
911753790Sobrien
911853790Sobrien	ccb_h = &csio->ccb_h;
911953790Sobrien
912053790Sobrien	/*
912153790Sobrien	 *  Now deal with the data.
912253790Sobrien	 */
912353790Sobrien	cp->data_len = 0;
912453790Sobrien	cp->segments = 0;
912553790Sobrien
912653790Sobrien	/*
912753790Sobrien	 *  No direction means no data.
912853790Sobrien	 */
912953790Sobrien	dir = (ccb_h->flags & CAM_DIR_MASK);
913053790Sobrien	if (dir == CAM_DIR_NONE)
913153790Sobrien		goto end_scatter;
913253790Sobrien
913353790Sobrien	if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
913453790Sobrien		/* Single buffer */
913553790Sobrien		if (!(ccb_h->flags & CAM_DATA_PHYS)) {
913653790Sobrien			/* Buffer is virtual */
913753790Sobrien			retv = sym_scatter_virtual(np, cp,
913853790Sobrien						(vm_offset_t) csio->data_ptr,
913953790Sobrien						(vm_size_t) csio->dxfer_len);
914053790Sobrien		} else {
914153790Sobrien			/* Buffer is physical */
914253790Sobrien			retv = sym_scatter_physical(np, cp,
914353790Sobrien						(vm_offset_t) csio->data_ptr,
914453790Sobrien						(vm_size_t) csio->dxfer_len);
914553790Sobrien		}
914653790Sobrien		if (retv < 0)
914753790Sobrien			goto too_big;
914853790Sobrien	} else {
914953790Sobrien		/* Scatter/gather list */
915053790Sobrien		int i;
915153790Sobrien		struct bus_dma_segment *segs;
915253790Sobrien		segs = (struct bus_dma_segment *)csio->data_ptr;
915353790Sobrien
915453790Sobrien		if ((ccb_h->flags & CAM_SG_LIST_PHYS) != 0) {
915553790Sobrien			/* The SG list pointer is physical */
915653790Sobrien			sym_set_cam_status(cp->cam_ccb, CAM_REQ_INVALID);
915753790Sobrien			return -1;
915853790Sobrien		}
915953790Sobrien		retv = 0;
916053790Sobrien		if (!(ccb_h->flags & CAM_DATA_PHYS)) {
916153790Sobrien			/* SG buffer pointers are virtual */
916253790Sobrien			for (i = csio->sglist_cnt - 1 ;  i >= 0 ; --i) {
916353790Sobrien				retv = sym_scatter_virtual(np, cp,
916453790Sobrien							   segs[i].ds_addr,
916553790Sobrien							   segs[i].ds_len);
916653790Sobrien				if (retv < 0)
916753790Sobrien					break;
916853790Sobrien			}
916953790Sobrien		} else {
917053790Sobrien			/* SG buffer pointers are physical */
917153790Sobrien			for (i = csio->sglist_cnt - 1 ;  i >= 0 ; --i) {
917253790Sobrien				retv = sym_scatter_physical(np, cp,
917353790Sobrien							    segs[i].ds_addr,
917453790Sobrien							    segs[i].ds_len);
917553790Sobrien				if (retv < 0)
917653790Sobrien					break;
917753790Sobrien			}
917853790Sobrien		}
917953790Sobrien		if (retv < 0)
918053790Sobrien			goto too_big;
918153790Sobrien	}
918253790Sobrien
918353790Sobrienend_scatter:
918453790Sobrien	/*
918553790Sobrien	 *  No segments means no data.
918653790Sobrien	 */
918753790Sobrien	if (!cp->segments)
918853790Sobrien		dir = CAM_DIR_NONE;
918953790Sobrien
919053790Sobrien	/*
919153790Sobrien	 *  Set the data pointer.
919253790Sobrien	 */
919353790Sobrien	switch(dir) {
919453790Sobrien	case CAM_DIR_OUT:
919553790Sobrien		goalp = SCRIPT_BA (np, data_out2) + 8;
919654690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
919753790Sobrien		if ((np->features & (FE_C10|FE_U3EN)) == FE_C10) {
919853790Sobrien			tcb_p tp = &np->target[cp->target];
919953790Sobrien			if (tp->tinfo.current.options & PPR_OPT_DT)
920053790Sobrien				goalp = SCRIPTH_BA (np, dt_data_out2) + 8;
920153790Sobrien		}
920253790Sobrien#endif
920353790Sobrien		lastp = goalp - 8 - (cp->segments * (2*4));
920453790Sobrien		break;
920553790Sobrien	case CAM_DIR_IN:
920653790Sobrien		goalp = SCRIPT_BA (np, data_in2) + 8;
920754690Sobrien#ifdef	SYM_CONF_BROKEN_U3EN_SUPPORT
920853790Sobrien		if ((np->features & (FE_C10|FE_U3EN)) == FE_C10) {
920953790Sobrien			tcb_p tp = &np->target[cp->target];
921053790Sobrien			if (tp->tinfo.current.options & PPR_OPT_DT)
921153790Sobrien				goalp = SCRIPTH_BA (np, dt_data_in2) + 8;
921253790Sobrien		}
921353790Sobrien#endif
921453790Sobrien		lastp = goalp - 8 - (cp->segments * (2*4));
921553790Sobrien		break;
921653790Sobrien	case CAM_DIR_NONE:
921753790Sobrien	default:
921853790Sobrien		lastp = goalp = SCRIPTH_BA (np, no_data);
921953790Sobrien		break;
922053790Sobrien	}
922153790Sobrien
922253790Sobrien	cp->phys.lastp = cpu_to_scr(lastp);
922353790Sobrien	cp->phys.goalp = cpu_to_scr(goalp);
922453790Sobrien	cp->phys.savep = cpu_to_scr(lastp);
922553790Sobrien	cp->startp     = cp->phys.savep;
922653790Sobrien
922753790Sobrien	/*
922853790Sobrien	 *  Activate this job.
922953790Sobrien	 */
923053790Sobrien	sym_put_start_queue(np, cp);
923153790Sobrien
923253790Sobrien	/*
923353790Sobrien	 *  Command is successfully queued.
923453790Sobrien	 */
923553790Sobrien	return 0;
923653790Sobrientoo_big:
923753790Sobrien	sym_set_cam_status(cp->cam_ccb, CAM_REQ_TOO_BIG);
923853790Sobrien	return -1;
923953790Sobrien}
924053790Sobrien
924153790Sobrien/*
924253790Sobrien *  Scatter a virtual buffer into bus addressable chunks.
924353790Sobrien */
924453790Sobrienstatic int
924553790Sobriensym_scatter_virtual(hcb_p np, ccb_p cp, vm_offset_t vaddr, vm_size_t len)
924653790Sobrien{
924753790Sobrien	u_long	pe, pn;
924853790Sobrien	u_long	n, k;
924953790Sobrien	int s;
925053790Sobrien
925153790Sobrien	cp->data_len += len;
925253790Sobrien
925353790Sobrien	pe = vaddr + len;
925453790Sobrien	n  = len;
925554690Sobrien	s  = SYM_CONF_MAX_SG - 1 - cp->segments;
925653790Sobrien
925753790Sobrien	while (n && s >= 0) {
925853790Sobrien		pn = (pe - 1) & ~PAGE_MASK;
925953790Sobrien		k = pe - pn;
926053790Sobrien		if (k > n) {
926153790Sobrien			k  = n;
926253790Sobrien			pn = pe - n;
926353790Sobrien		}
926453790Sobrien		if (DEBUG_FLAGS & DEBUG_SCATTER) {
926553790Sobrien			printf ("%s scatter: va=%lx pa=%lx siz=%lx\n",
926653790Sobrien				sym_name(np), pn, (u_long) vtobus(pn), k);
926753790Sobrien		}
926853790Sobrien		cp->phys.data[s].addr = cpu_to_scr(vtobus(pn));
926953790Sobrien		cp->phys.data[s].size = cpu_to_scr(k);
927053790Sobrien		pe = pn;
927153790Sobrien		n -= k;
927253790Sobrien		--s;
927353790Sobrien	}
927454690Sobrien	cp->segments = SYM_CONF_MAX_SG - 1 - s;
927553790Sobrien
927653790Sobrien	return n ? -1 : 0;
927753790Sobrien}
927853790Sobrien
927953790Sobrien/*
928053790Sobrien *  Will stay so forever, in my opinion.
928153790Sobrien */
928253790Sobrienstatic int
928353790Sobriensym_scatter_physical(hcb_p np, ccb_p cp, vm_offset_t vaddr, vm_size_t len)
928453790Sobrien{
928553790Sobrien	return -1;
928653790Sobrien}
928753790Sobrien
928853790Sobrien/*
928953790Sobrien *  SIM action for non performance critical stuff.
929053790Sobrien */
929153790Sobrienstatic void sym_action2(struct cam_sim *sim, union ccb *ccb)
929253790Sobrien{
929353790Sobrien	hcb_p	np;
929453790Sobrien	tcb_p	tp;
929553790Sobrien	lcb_p	lp;
929653790Sobrien	struct	ccb_hdr  *ccb_h;
929753790Sobrien
929853790Sobrien	/*
929953790Sobrien	 *  Retrieve our controller data structure.
930053790Sobrien	 */
930153790Sobrien	np = (hcb_p) cam_sim_softc(sim);
930253790Sobrien
930353790Sobrien	ccb_h = &ccb->ccb_h;
930453790Sobrien
930553790Sobrien	switch (ccb_h->func_code) {
930653790Sobrien	case XPT_SET_TRAN_SETTINGS:
930753790Sobrien	{
930853790Sobrien		struct ccb_trans_settings *cts;
930953790Sobrien
931053790Sobrien		cts  = &ccb->cts;
931153790Sobrien		tp = &np->target[ccb_h->target_id];
931253790Sobrien
931353790Sobrien		/*
931455628Sgroudier		 *  Update our transfer settings (basically WIDE/SYNC).
931555628Sgroudier		 *  These features are to be handled in a per target
931655628Sgroudier		 *  basis according to SCSI specifications.
931753790Sobrien		 */
931853790Sobrien		if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
931953790Sobrien			sym_update_trans(np, tp, &tp->tinfo.user, cts);
932053790Sobrien
932153790Sobrien		if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
932253790Sobrien			sym_update_trans(np, tp, &tp->tinfo.goal, cts);
932353790Sobrien
932453790Sobrien		/*
932555628Sgroudier		 *  Update our disconnect and tag settings.
932655628Sgroudier		 *  SCSI requires CmdQue feature to be handled in a per
932755628Sgroudier		 *  device (logical unit) basis.
932853790Sobrien		 */
932953790Sobrien		lp = sym_lp(np, tp, ccb_h->target_lun);
933053790Sobrien		if (lp) {
933153790Sobrien			if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0)
933253790Sobrien				sym_update_dflags(np, &lp->user_flags, cts);
933353790Sobrien			if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0)
933453790Sobrien				sym_update_dflags(np, &lp->current_flags, cts);
933553790Sobrien		}
933653790Sobrien
933753790Sobrien		sym_xpt_done2(np, ccb, CAM_REQ_CMP);
933853790Sobrien		break;
933953790Sobrien	}
934053790Sobrien	case XPT_GET_TRAN_SETTINGS:
934153790Sobrien	{
934253790Sobrien		struct ccb_trans_settings *cts;
934353790Sobrien		struct sym_trans *tip;
934453790Sobrien		u_char dflags;
934553790Sobrien
934653790Sobrien		cts = &ccb->cts;
934753790Sobrien		tp = &np->target[ccb_h->target_id];
934853790Sobrien		lp = sym_lp(np, tp, ccb_h->target_lun);
934953790Sobrien
935053790Sobrien		if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
935153790Sobrien			tip = &tp->tinfo.current;
935253790Sobrien			dflags = lp ? lp->current_flags : 0;
935353790Sobrien		}
935453790Sobrien		else {
935553790Sobrien			tip = &tp->tinfo.user;
935653790Sobrien			dflags = lp ? lp->user_flags : tp->usrflags;
935753790Sobrien		}
935853790Sobrien
935953790Sobrien		cts->sync_period = tip->period;
936053790Sobrien		cts->sync_offset = tip->offset;
936153790Sobrien		cts->bus_width   = tip->width;
936253790Sobrien
936353790Sobrien		cts->valid = CCB_TRANS_SYNC_RATE_VALID
936453790Sobrien			   | CCB_TRANS_SYNC_OFFSET_VALID
936553790Sobrien			   | CCB_TRANS_BUS_WIDTH_VALID;
936653790Sobrien
936753790Sobrien		if (lp) {
936853790Sobrien			cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
936953790Sobrien
937053790Sobrien			if (dflags & SYM_DISC_ENABLED)
937153790Sobrien				cts->flags |= CCB_TRANS_DISC_ENB;
937253790Sobrien
937353790Sobrien			if (dflags & SYM_TAGS_ENABLED)
937453790Sobrien				cts->flags |= CCB_TRANS_TAG_ENB;
937553790Sobrien
937653790Sobrien			cts->valid |= CCB_TRANS_DISC_VALID;
937753790Sobrien			cts->valid |= CCB_TRANS_TQ_VALID;
937853790Sobrien		}
937953790Sobrien
938053790Sobrien		sym_xpt_done2(np, ccb, CAM_REQ_CMP);
938153790Sobrien		break;
938253790Sobrien	}
938353790Sobrien	case XPT_CALC_GEOMETRY:
938453790Sobrien	{
938553790Sobrien		struct ccb_calc_geometry *ccg;
938653790Sobrien		u32 size_mb;
938753790Sobrien		u32 secs_per_cylinder;
938853790Sobrien		int extended;
938953790Sobrien
939053790Sobrien		/*
939153790Sobrien		 *  Silly DOS geometry.
939253790Sobrien		 */
939353790Sobrien		ccg = &ccb->ccg;
939453790Sobrien		size_mb = ccg->volume_size
939553790Sobrien			/ ((1024L * 1024L) / ccg->block_size);
939653790Sobrien		extended = 1;
939753790Sobrien
939853790Sobrien		if (size_mb > 1024 && extended) {
939953790Sobrien			ccg->heads = 255;
940053790Sobrien			ccg->secs_per_track = 63;
940153790Sobrien		} else {
940253790Sobrien			ccg->heads = 64;
940353790Sobrien			ccg->secs_per_track = 32;
940453790Sobrien		}
940553790Sobrien		secs_per_cylinder = ccg->heads * ccg->secs_per_track;
940653790Sobrien		ccg->cylinders = ccg->volume_size / secs_per_cylinder;
940753790Sobrien		sym_xpt_done2(np, ccb, CAM_REQ_CMP);
940853790Sobrien		break;
940953790Sobrien	}
941053790Sobrien	case XPT_PATH_INQ:
941153790Sobrien	{
941253790Sobrien		struct ccb_pathinq *cpi = &ccb->cpi;
941353790Sobrien		cpi->version_num = 1;
941453790Sobrien		cpi->hba_inquiry = PI_MDP_ABLE|PI_SDTR_ABLE|PI_TAG_ABLE;
941553790Sobrien		if ((np->features & FE_WIDE) != 0)
941653790Sobrien			cpi->hba_inquiry |= PI_WIDE_16;
941753790Sobrien		cpi->target_sprt = 0;
941853790Sobrien		cpi->hba_misc = 0;
941955628Sgroudier		if (np->usrflags & SYM_SCAN_TARGETS_HILO)
942055628Sgroudier			cpi->hba_misc |= PIM_SCANHILO;
942155628Sgroudier		if (np->usrflags & SYM_AVOID_BUS_RESET)
942255628Sgroudier			cpi->hba_misc |= PIM_NOBUSRESET;
942353790Sobrien		cpi->hba_eng_cnt = 0;
942453790Sobrien		cpi->max_target = (np->features & FE_WIDE) ? 15 : 7;
942553790Sobrien		/* Semantic problem:)LUN number max = max number of LUNs - 1 */
942654690Sobrien		cpi->max_lun = SYM_CONF_MAX_LUN-1;
942754690Sobrien		if (SYM_SETUP_MAX_LUN < SYM_CONF_MAX_LUN)
942854690Sobrien			cpi->max_lun = SYM_SETUP_MAX_LUN-1;
942953790Sobrien		cpi->bus_id = cam_sim_bus(sim);
943053790Sobrien		cpi->initiator_id = np->myaddr;
943153790Sobrien		cpi->base_transfer_speed = 3300;
943254690Sobrien		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
943353790Sobrien		strncpy(cpi->hba_vid, "Symbios", HBA_IDLEN);
943453790Sobrien		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
943553790Sobrien		cpi->unit_number = cam_sim_unit(sim);
943653790Sobrien		sym_xpt_done2(np, ccb, CAM_REQ_CMP);
943753790Sobrien		break;
943853790Sobrien	}
943953790Sobrien	case XPT_ABORT:
944053790Sobrien	{
944153790Sobrien		union ccb *abort_ccb = ccb->cab.abort_ccb;
944253790Sobrien		switch(abort_ccb->ccb_h.func_code) {
944353790Sobrien		case XPT_SCSI_IO:
944453790Sobrien			if (sym_abort_scsiio(np, abort_ccb, 0) == 0) {
944553790Sobrien				sym_xpt_done2(np, ccb, CAM_REQ_CMP);
944653790Sobrien				break;
944753790Sobrien			}
944853790Sobrien		default:
944953790Sobrien			sym_xpt_done2(np, ccb, CAM_UA_ABORT);
945053790Sobrien			break;
945153790Sobrien		}
945253790Sobrien		break;
945353790Sobrien	}
945453790Sobrien	case XPT_RESET_DEV:
945553790Sobrien	{
945653790Sobrien		sym_reset_dev(np, ccb);
945753790Sobrien		break;
945853790Sobrien	}
945953790Sobrien	case XPT_RESET_BUS:
946053790Sobrien	{
946153790Sobrien		sym_reset_scsi_bus(np, 0);
946253790Sobrien		if (sym_verbose) {
946353790Sobrien			xpt_print_path(np->path);
946455300Sgroudier			printf("SCSI BUS reset delivered.\n");
946553790Sobrien		}
946655300Sgroudier		sym_init (np, 1);
946753790Sobrien		sym_xpt_done2(np, ccb, CAM_REQ_CMP);
946853790Sobrien		break;
946953790Sobrien	}
947053790Sobrien	case XPT_ACCEPT_TARGET_IO:
947153790Sobrien	case XPT_CONT_TARGET_IO:
947253790Sobrien	case XPT_EN_LUN:
947353790Sobrien	case XPT_NOTIFY_ACK:
947453790Sobrien	case XPT_IMMED_NOTIFY:
947553790Sobrien	case XPT_TERM_IO:
947653790Sobrien	default:
947753790Sobrien		sym_xpt_done2(np, ccb, CAM_REQ_INVALID);
947853790Sobrien		break;
947953790Sobrien	}
948053790Sobrien}
948153790Sobrien
948253790Sobrien/*
948353790Sobrien *  Update transfer settings of a target.
948453790Sobrien */
948553790Sobrienstatic void sym_update_trans(hcb_p np, tcb_p tp, struct sym_trans *tip,
948653790Sobrien			    struct ccb_trans_settings *cts)
948753790Sobrien{
948853790Sobrien	/*
948953790Sobrien	 *  Update the infos.
949053790Sobrien	 */
949153790Sobrien	if ((cts->valid & CCB_TRANS_BUS_WIDTH_VALID) != 0)
949253790Sobrien		tip->width = cts->bus_width;
949353790Sobrien	if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0)
949453790Sobrien		tip->offset = cts->sync_offset;
949553790Sobrien	if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0)
949653790Sobrien		tip->period = cts->sync_period;
949753790Sobrien
949853790Sobrien	/*
949953790Sobrien	 *  Scale against out limits.
950053790Sobrien	 */
950155628Sgroudier	if (tip->width  > SYM_SETUP_MAX_WIDE)	tip->width  =SYM_SETUP_MAX_WIDE;
950253790Sobrien	if (tip->width  > np->maxwide)		tip->width  = np->maxwide;
950355628Sgroudier	if (tip->offset > SYM_SETUP_MAX_OFFS)	tip->offset =SYM_SETUP_MAX_OFFS;
950453790Sobrien	if (tip->offset > np->maxoffs)		tip->offset = np->maxoffs;
950553790Sobrien	if (tip->period) {
950654690Sobrien		if (tip->period < SYM_SETUP_MIN_SYNC)
950754690Sobrien			tip->period = SYM_SETUP_MIN_SYNC;
950853790Sobrien		if (np->features & FE_ULTRA3) {
950953790Sobrien			if (tip->period < np->minsync_dt)
951053790Sobrien				tip->period = np->minsync_dt;
951153790Sobrien		}
951253790Sobrien		else {
951353790Sobrien			if (tip->period < np->minsync)
951453790Sobrien				tip->period = np->minsync;
951553790Sobrien		}
951653790Sobrien		if (tip->period > np->maxsync)
951753790Sobrien			tip->period = np->maxsync;
951853790Sobrien	}
951953790Sobrien}
952053790Sobrien
952153790Sobrien/*
952253790Sobrien *  Update flags for a device (logical unit).
952353790Sobrien */
952453790Sobrienstatic void
952553790Sobriensym_update_dflags(hcb_p np, u_char *flags, struct ccb_trans_settings *cts)
952653790Sobrien{
952753790Sobrien	if ((cts->valid & CCB_TRANS_DISC_VALID) != 0) {
952853790Sobrien		if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
952953790Sobrien			*flags |= SYM_DISC_ENABLED;
953053790Sobrien		else
953153790Sobrien			*flags &= ~SYM_DISC_ENABLED;
953253790Sobrien	}
953353790Sobrien
953453790Sobrien	if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
953553790Sobrien		if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
953653790Sobrien			*flags |= SYM_TAGS_ENABLED;
953753790Sobrien		else
953853790Sobrien			*flags &= ~SYM_TAGS_ENABLED;
953953790Sobrien	}
954053790Sobrien}
954153790Sobrien
954253790Sobrien
954353790Sobrien/*============= DRIVER INITIALISATION ==================*/
954453790Sobrien
954553790Sobrien#ifdef FreeBSD_4_Bus
954653790Sobrien
954753790Sobrienstatic device_method_t sym_pci_methods[] = {
954853790Sobrien	DEVMETHOD(device_probe,	 sym_pci_probe),
954953790Sobrien	DEVMETHOD(device_attach, sym_pci_attach),
955053790Sobrien	{ 0, 0 }
955153790Sobrien};
955253790Sobrien
955353790Sobrienstatic driver_t sym_pci_driver = {
955453790Sobrien	"sym",
955553790Sobrien	sym_pci_methods,
955653790Sobrien	sizeof(struct sym_hcb)
955753790Sobrien};
955853790Sobrien
955953790Sobrienstatic devclass_t sym_devclass;
956053790Sobrien
956153790SobrienDRIVER_MODULE(sym, pci, sym_pci_driver, sym_devclass, 0, 0);
956253790Sobrien
956353790Sobrien#else	/* Pre-FreeBSD_4_Bus */
956453790Sobrien
956553790Sobrienstatic u_long sym_unit;
956653790Sobrien
956753790Sobrienstatic struct	pci_device sym_pci_driver = {
956853790Sobrien	"sym",
956953790Sobrien	sym_pci_probe,
957053790Sobrien	sym_pci_attach,
957153790Sobrien	&sym_unit,
957253790Sobrien	NULL
957353790Sobrien};
957453790Sobrien
957553790SobrienDATA_SET (pcidevice_set, sym_pci_driver);
957653790Sobrien
957753790Sobrien#endif /* FreeBSD_4_Bus */
957853790Sobrien
957953790Sobrienstatic struct sym_pci_chip sym_pci_dev_table[] = {
958054690Sobrien {PCI_ID_SYM53C810, 0x0f, "810", 4, 8, 4, 0,
958153809Sobrien FE_ERL}
958253809Sobrien ,
958354690Sobrien {PCI_ID_SYM53C810, 0xff, "810a", 4,  8, 4, 1,
958453790Sobrien FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF}
958553790Sobrien ,
958654690Sobrien {PCI_ID_SYM53C825, 0x0f, "825", 6,  8, 4, 0,
958753809Sobrien FE_WIDE|FE_BOF|FE_ERL|FE_DIFF}
958853809Sobrien ,
958954690Sobrien {PCI_ID_SYM53C825, 0xff, "825a", 6,  8, 4, 2,
959053790Sobrien FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF}
959153790Sobrien ,
959254690Sobrien {PCI_ID_SYM53C860, 0xff, "860", 4,  8, 5, 1,
959353790Sobrien FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN}
959453790Sobrien ,
959554690Sobrien {PCI_ID_SYM53C875, 0x01, "875", 6, 16, 5, 2,
959653790Sobrien FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
959753790Sobrien FE_RAM|FE_DIFF}
959853790Sobrien ,
959954690Sobrien {PCI_ID_SYM53C875, 0xff, "875", 6, 16, 5, 2,
960053790Sobrien FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
960153790Sobrien FE_RAM|FE_DIFF}
960253790Sobrien ,
960354690Sobrien {PCI_ID_SYM53C875_2, 0xff, "875", 6, 16, 5, 2,
960453790Sobrien FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
960553790Sobrien FE_RAM|FE_DIFF}
960653790Sobrien ,
960754690Sobrien {PCI_ID_SYM53C885, 0xff, "885", 6, 16, 5, 2,
960853790Sobrien FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
960953790Sobrien FE_RAM|FE_DIFF}
961053790Sobrien ,
961154690Sobrien {PCI_ID_SYM53C895, 0xff, "895", 6, 31, 7, 2,
961253790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
961353790Sobrien FE_RAM|FE_LCKFRQ}
961453790Sobrien ,
961554690Sobrien {PCI_ID_SYM53C896, 0xff, "896", 6, 31, 7, 4,
961653790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
961753790Sobrien FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ}
961853790Sobrien ,
961954690Sobrien {PCI_ID_SYM53C895A, 0xff, "895a", 6, 31, 7, 4,
962053790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
962153790Sobrien FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ}
962253790Sobrien ,
962354690Sobrien {PCI_ID_LSI53C1010, 0x00, "1010", 6, 62, 7, 8,
962453790Sobrien FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN|
962553790Sobrien FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_PCI66|FE_CRC|
962653790Sobrien FE_C10}
962753790Sobrien ,
962854690Sobrien {PCI_ID_LSI53C1010, 0xff, "1010", 6, 62, 7, 8,
962953790Sobrien FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN|
963055300Sgroudier FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC|
963155300Sgroudier FE_C10|FE_U3EN}
963255300Sgroudier ,
963355300Sgroudier {PCI_ID_LSI53C1010_2, 0xff, "1010", 6, 62, 7, 8,
963455300Sgroudier FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN|
963553790Sobrien FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_PCI66|FE_CRC|
963653790Sobrien FE_C10|FE_U3EN}
963753790Sobrien ,
963854690Sobrien {PCI_ID_LSI53C1510D, 0xff, "1510d", 6, 31, 7, 4,
963953790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
964053790Sobrien FE_RAM|FE_IO256|FE_LEDC}
964153790Sobrien};
964253790Sobrien
964353790Sobrien#define sym_pci_num_devs \
964453790Sobrien	(sizeof(sym_pci_dev_table) / sizeof(sym_pci_dev_table[0]))
964553790Sobrien
964653790Sobrien/*
964753790Sobrien *  Look up the chip table.
964853790Sobrien *
964953790Sobrien *  Return a pointer to the chip entry if found,
965053790Sobrien *  zero otherwise.
965153790Sobrien */
965253790Sobrienstatic struct sym_pci_chip *
965353790Sobrien#ifdef FreeBSD_4_Bus
965453790Sobriensym_find_pci_chip(device_t dev)
965553790Sobrien#else
965653790Sobriensym_find_pci_chip(pcici_t pci_tag)
965753790Sobrien#endif
965853790Sobrien{
965953790Sobrien	struct	sym_pci_chip *chip;
966053790Sobrien	int	i;
966153790Sobrien	u_short	device_id;
966253790Sobrien	u_char	revision;
966353790Sobrien
966453790Sobrien#ifdef FreeBSD_4_Bus
966553790Sobrien	if (pci_get_vendor(dev) != PCI_VENDOR_NCR)
966653790Sobrien		return 0;
966753790Sobrien
966853790Sobrien	device_id = pci_get_device(dev);
966953790Sobrien	revision  = pci_get_revid(dev);
967053790Sobrien#else
967153790Sobrien	if (pci_cfgread(pci_tag, PCIR_VENDOR, 2) != PCI_VENDOR_NCR)
967253790Sobrien		return 0;
967353790Sobrien
967453790Sobrien	device_id = pci_cfgread(pci_tag, PCIR_DEVICE, 2);
967553790Sobrien	revision  = pci_cfgread(pci_tag, PCIR_REVID,  1);
967653790Sobrien#endif
967753790Sobrien
967853790Sobrien	for (i = 0; i < sym_pci_num_devs; i++) {
967953790Sobrien		chip = &sym_pci_dev_table[i];
968053790Sobrien		if (device_id != chip->device_id)
968153790Sobrien			continue;
968253790Sobrien		if (revision > chip->revision_id)
968353790Sobrien			continue;
968453790Sobrien		if (FE_LDSTR & chip->features)
968553790Sobrien			return chip;
968653809Sobrien		break;
968753790Sobrien	}
968853790Sobrien
968953790Sobrien	return 0;
969053790Sobrien}
969153790Sobrien
969253790Sobrien/*
969353790Sobrien *  Tell upper layer if the chip is supported.
969453790Sobrien */
969553790Sobrien#ifdef FreeBSD_4_Bus
969653790Sobrienstatic int
969753790Sobriensym_pci_probe(device_t dev)
969853790Sobrien{
969953790Sobrien	struct	sym_pci_chip *chip;
970053790Sobrien
970153790Sobrien	chip = sym_find_pci_chip(dev);
970253790Sobrien	if (chip) {
970353790Sobrien		device_set_desc(dev, chip->name);
970455300Sgroudier		return (chip->lp_probe_bit & SYM_SETUP_LP_PROBE_MAP)? -2000 : 0;
970553790Sobrien	}
970653790Sobrien	return ENXIO;
970753790Sobrien}
970853790Sobrien#else /* Pre-FreeBSD_4_Bus */
970953790Sobrienstatic const char *
971053790Sobriensym_pci_probe(pcici_t pci_tag, pcidi_t type)
971153790Sobrien{
971253790Sobrien	struct	sym_pci_chip *chip;
971353790Sobrien
971453790Sobrien	chip = sym_find_pci_chip(pci_tag);
971553790Sobrien	if (chip)
971653790Sobrien		return chip->name;
971753790Sobrien	return 0;
971853790Sobrien}
971953790Sobrien#endif
972053790Sobrien
972153790Sobrien/*
972253790Sobrien *  Attach a sym53c8xx device.
972353790Sobrien */
972453790Sobrien#ifdef FreeBSD_4_Bus
972553790Sobrienstatic int
972653790Sobriensym_pci_attach(device_t dev)
972753790Sobrien#else
972853790Sobrienstatic void
972953790Sobriensym_pci_attach(pcici_t pci_tag, int unit)
973053790Sobrien{
973153790Sobrien	int err = sym_pci_attach2(pci_tag, unit);
973253790Sobrien	if (err)
973353790Sobrien		printf("sym: failed to attach unit %d - err=%d.\n", unit, err);
973453790Sobrien}
973553790Sobrienstatic int
973653790Sobriensym_pci_attach2(pcici_t pci_tag, int unit)
973753790Sobrien#endif
973853790Sobrien{
973953790Sobrien	struct	sym_pci_chip *chip;
974053790Sobrien	u_short	command;
974153790Sobrien	u_char	cachelnsz;
974253790Sobrien	struct	sym_hcb *np = 0;
974353790Sobrien	struct	sym_nvram nvram;
974453790Sobrien	int 	i;
974553790Sobrien
974653790Sobrien	/*
974753790Sobrien	 *  Only probed devices should be attached.
974853790Sobrien	 *  We just enjoy being paranoid. :)
974953790Sobrien	 */
975053790Sobrien#ifdef FreeBSD_4_Bus
975153790Sobrien	chip = sym_find_pci_chip(dev);
975253790Sobrien#else
975353790Sobrien	chip = sym_find_pci_chip(pci_tag);
975453790Sobrien#endif
975553790Sobrien	if (chip == NULL)
975653790Sobrien		return (ENXIO);
975753790Sobrien
975853790Sobrien	/*
975953790Sobrien	 *  Allocate immediately the host control block,
976053790Sobrien	 *  since we are only expecting to succeed. :)
976153790Sobrien	 *  We keep track in the HCB of all the resources that
976253790Sobrien	 *  are to be released on error.
976353790Sobrien	 */
976453790Sobrien	np = sym_calloc(sizeof(*np), "HCB");
976553790Sobrien	if (!np)
976653790Sobrien		goto attach_failed;
976753790Sobrien
976853790Sobrien	/*
976953790Sobrien	 *  Copy some useful infos to the HCB.
977053790Sobrien	 */
977153790Sobrien	np->verbose	 = bootverbose;
977253790Sobrien#ifdef FreeBSD_4_Bus
977353790Sobrien	np->device	 = dev;
977453790Sobrien	np->unit	 = device_get_unit(dev);
977553790Sobrien	np->device_id	 = pci_get_device(dev);
977653790Sobrien	np->revision_id  = pci_get_revid(dev);
977753790Sobrien#else
977853790Sobrien	np->pci_tag	 = pci_tag;
977953790Sobrien	np->unit	 = unit;
978053790Sobrien	np->device_id	 = pci_cfgread(pci_tag, PCIR_DEVICE, 2);
978153790Sobrien	np->revision_id  = pci_cfgread(pci_tag, PCIR_REVID,  1);
978253790Sobrien#endif
978353790Sobrien	np->features	 = chip->features;
978453790Sobrien	np->clock_divn	 = chip->nr_divisor;
978553790Sobrien	np->maxoffs	 = chip->offset_max;
978653790Sobrien	np->maxburst	 = chip->burst_max;
978753790Sobrien
978853790Sobrien	/*
978953790Sobrien	 * Edit its name.
979053790Sobrien	 */
979153790Sobrien	snprintf(np->inst_name, sizeof(np->inst_name), "sym%d", np->unit);
979253790Sobrien
979353790Sobrien	/*
979453790Sobrien	 *  Read and apply some fix-ups to the PCI COMMAND
979553790Sobrien	 *  register. We want the chip to be enabled for:
979653790Sobrien	 *  - BUS mastering
979753790Sobrien	 *  - PCI parity checking (reporting would also be fine)
979853790Sobrien	 *  - Write And Invalidate.
979953790Sobrien	 */
980053790Sobrien#ifdef FreeBSD_4_Bus
980153790Sobrien	command = pci_read_config(dev, PCIR_COMMAND, 2);
980253790Sobrien#else
980353790Sobrien	command = pci_cfgread(pci_tag, PCIR_COMMAND, 2);
980453790Sobrien#endif
980553790Sobrien	command |= PCIM_CMD_BUSMASTEREN;
980653790Sobrien	command |= PCIM_CMD_PERRESPEN;
980753790Sobrien	command |= /* PCIM_CMD_MWIEN */ 0x0010;
980853790Sobrien#ifdef FreeBSD_4_Bus
980953790Sobrien	pci_write_config(dev, PCIR_COMMAND, command, 2);
981053790Sobrien#else
981153790Sobrien	pci_cfgwrite(pci_tag, PCIR_COMMAND, command, 2);
981253790Sobrien#endif
981353790Sobrien
981453790Sobrien	/*
981553790Sobrien	 *  Let the device know about the cache line size,
981653790Sobrien	 *  if it doesn't yet.
981753790Sobrien	 */
981853790Sobrien#ifdef FreeBSD_4_Bus
981953790Sobrien	cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1);
982053790Sobrien#else
982153790Sobrien	cachelnsz = pci_cfgread(pci_tag, PCIR_CACHELNSZ, 1);
982253790Sobrien#endif
982353790Sobrien	if (!cachelnsz) {
982453790Sobrien		cachelnsz = 8;
982553790Sobrien#ifdef FreeBSD_4_Bus
982653790Sobrien		pci_write_config(dev, PCIR_CACHELNSZ, cachelnsz, 1);
982753790Sobrien#else
982853790Sobrien		pci_cfgwrite(pci_tag, PCIR_CACHELNSZ, cachelnsz, 1);
982953790Sobrien#endif
983053790Sobrien	}
983153790Sobrien
983253790Sobrien	/*
983353790Sobrien	 *  Alloc/get/map/retrieve everything that deals with MMIO.
983453790Sobrien	 */
983553790Sobrien#ifdef FreeBSD_4_Bus
983653790Sobrien	if ((command & PCIM_CMD_MEMEN) != 0) {
983753790Sobrien		int regs_id = SYM_PCI_MMIO;
983853790Sobrien		np->mmio_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &regs_id,
983953790Sobrien						  0, ~0, 1, RF_ACTIVE);
984053790Sobrien	}
984153790Sobrien	if (!np->mmio_res) {
984253790Sobrien		device_printf(dev, "failed to allocate MMIO resources\n");
984353790Sobrien		goto attach_failed;
984453790Sobrien	}
984553790Sobrien	np->mmio_bsh = rman_get_bushandle(np->mmio_res);
984653790Sobrien	np->mmio_tag = rman_get_bustag(np->mmio_res);
984753790Sobrien	np->mmio_pa  = rman_get_start(np->mmio_res);
984853790Sobrien	np->mmio_va  = (vm_offset_t) rman_get_virtual(np->mmio_res);
984953790Sobrien	np->mmio_ba  = np->mmio_pa;
985053790Sobrien#else
985153790Sobrien	if ((command & PCIM_CMD_MEMEN) != 0) {
985253790Sobrien		vm_offset_t vaddr, paddr;
985353790Sobrien		if (!pci_map_mem(pci_tag, SYM_PCI_MMIO, &vaddr, &paddr)) {
985453790Sobrien			printf("%s: failed to map MMIO window\n", sym_name(np));
985553790Sobrien			goto attach_failed;
985653790Sobrien		}
985753790Sobrien		np->mmio_va = vaddr;
985853790Sobrien		np->mmio_pa = paddr;
985953790Sobrien		np->mmio_ba = paddr;
986053790Sobrien	}
986153790Sobrien#endif
986253790Sobrien
986353790Sobrien	/*
986453790Sobrien	 *  Allocate the IRQ.
986553790Sobrien	 */
986653790Sobrien#ifdef FreeBSD_4_Bus
986753790Sobrien	i = 0;
986853790Sobrien	np->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &i,
986953790Sobrien					 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
987053790Sobrien	if (!np->irq_res) {
987153790Sobrien		device_printf(dev, "failed to allocate IRQ resource\n");
987253790Sobrien		goto attach_failed;
987353790Sobrien	}
987453790Sobrien#endif
987553790Sobrien
987654690Sobrien#ifdef	SYM_CONF_IOMAPPED
987753790Sobrien	/*
987853790Sobrien	 *  User want us to use normal IO with PCI.
987953790Sobrien	 *  Alloc/get/map/retrieve everything that deals with IO.
988053790Sobrien	 */
988153790Sobrien#ifdef FreeBSD_4_Bus
988253790Sobrien	if ((command & PCI_COMMAND_IO_ENABLE) != 0) {
988353790Sobrien		int regs_id = SYM_PCI_IO;
988453790Sobrien		np->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &regs_id,
988553790Sobrien						0, ~0, 1, RF_ACTIVE);
988653790Sobrien	}
988753790Sobrien	if (!np->io_res) {
988853790Sobrien		device_printf(dev, "failed to allocate IO resources\n");
988953790Sobrien		goto attach_failed;
989053790Sobrien	}
989153790Sobrien	np->io_bsh  = rman_get_bushandle(np->io_res);
989253790Sobrien	np->io_tag  = rman_get_bustag(np->io_res);
989353790Sobrien	np->io_port = rman_get_start(np->io_res);
989453790Sobrien#else
989553790Sobrien	if ((command & PCI_COMMAND_IO_ENABLE) != 0) {
989653790Sobrien		pci_port_t io_port;
989753793Sobrien		if (!pci_map_port (pci_tag, SYM_PCI_IO, &io_port)) {
989853790Sobrien			printf("%s: failed to map IO window\n", sym_name(np));
989953790Sobrien			goto attach_failed;
990053790Sobrien		}
990153790Sobrien		np->io_port = io_port;
990253790Sobrien	}
990353790Sobrien#endif
990453790Sobrien
990554690Sobrien#endif /* SYM_CONF_IOMAPPED */
990653790Sobrien
990753790Sobrien	/*
990853790Sobrien	 *  If the chip has RAM.
990953790Sobrien	 *  Alloc/get/map/retrieve the corresponding resources.
991053790Sobrien	 */
991153790Sobrien	if ((np->features & (FE_RAM|FE_RAM8K)) &&
991253790Sobrien	    (command & PCIM_CMD_MEMEN) != 0) {
991353790Sobrien#ifdef FreeBSD_4_Bus
991453790Sobrien		int regs_id = SYM_PCI_RAM;
991553790Sobrien		if (np->features & FE_64BIT)
991653790Sobrien			regs_id = SYM_PCI_RAM64;
991753790Sobrien		np->ram_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &regs_id,
991853790Sobrien						 0, ~0, 1, RF_ACTIVE);
991953790Sobrien		if (!np->ram_res) {
992053790Sobrien			device_printf(dev,"failed to allocate RAM resources\n");
992153790Sobrien			goto attach_failed;
992253790Sobrien		}
992353790Sobrien		np->ram_id  = regs_id;
992453790Sobrien		np->ram_bsh = rman_get_bushandle(np->ram_res);
992553790Sobrien		np->ram_tag = rman_get_bustag(np->ram_res);
992653790Sobrien		np->ram_pa  = rman_get_start(np->ram_res);
992753790Sobrien		np->ram_va  = (vm_offset_t) rman_get_virtual(np->ram_res);
992853790Sobrien		np->ram_ba  = np->ram_pa;
992953790Sobrien#else
993053790Sobrien		vm_offset_t vaddr, paddr;
993153790Sobrien		int regs_id = SYM_PCI_RAM;
993253790Sobrien		if (np->features & FE_64BIT)
993353790Sobrien			regs_id = SYM_PCI_RAM64;
993453790Sobrien		if (!pci_map_mem(pci_tag, regs_id, &vaddr, &paddr)) {
993553790Sobrien			printf("%s: failed to map RAM window\n", sym_name(np));
993653790Sobrien			goto attach_failed;
993753790Sobrien		}
993853790Sobrien		np->ram_va = vaddr;
993953790Sobrien		np->ram_pa = paddr;
994053790Sobrien		np->ram_ba = paddr;
994153790Sobrien#endif
994253790Sobrien	}
994353790Sobrien
994453790Sobrien	/*
994553796Sobrien	 *  Save setting of some IO registers, so we will
994653796Sobrien	 *  be able to probe specific implementations.
994753796Sobrien	 */
994853796Sobrien	sym_save_initial_setting (np);
994953796Sobrien
995053796Sobrien	/*
995153796Sobrien	 *  Reset the chip now, since it has been reported
995253796Sobrien	 *  that SCSI clock calibration may not work properly
995353796Sobrien	 *  if the chip is currently active.
995453796Sobrien	 */
995553796Sobrien	sym_chip_reset (np);
995653796Sobrien
995753796Sobrien	/*
995853790Sobrien	 *  Try to read the user set-up.
995953790Sobrien	 */
996053790Sobrien	(void) sym_read_nvram(np, &nvram);
996153790Sobrien
996253790Sobrien	/*
996353790Sobrien	 *  Prepare controller and devices settings, according
996453790Sobrien	 *  to chip features, user set-up and driver set-up.
996553790Sobrien	 */
996653790Sobrien	(void) sym_prepare_setting(np, &nvram);
996753790Sobrien
996853790Sobrien	/*
996953790Sobrien	 *  Check the PCI clock frequency.
997053790Sobrien	 *  Must be performed after prepare_setting since it destroys
997153790Sobrien	 *  STEST1 that is used to probe for the clock doubler.
997253790Sobrien	 */
997353790Sobrien	i = sym_getpciclock(np);
997453790Sobrien	if (i > 37000)
997553790Sobrien#ifdef FreeBSD_4_Bus
997653790Sobrien		device_printf(dev, "PCI BUS clock seems too high: %u KHz.\n",i);
997753790Sobrien#else
997853790Sobrien		printf("%s: PCI BUS clock seems too high: %u KHz.\n",
997953790Sobrien			sym_name(np), i);
998053790Sobrien#endif
998153790Sobrien
998253790Sobrien	/*
998353790Sobrien	 *  Allocate the start queue.
998453790Sobrien	 */
998553790Sobrien	np->squeue = (u32 *) sym_calloc(sizeof(u32)*(MAX_QUEUE*2), "SQUEUE");
998653790Sobrien	if (!np->squeue)
998753790Sobrien		goto attach_failed;
998853790Sobrien
998953790Sobrien	/*
999053790Sobrien	 *  Allocate the done queue.
999153790Sobrien	 */
999253790Sobrien	np->dqueue = (u32 *) sym_calloc(sizeof(u32)*(MAX_QUEUE*2), "DQUEUE");
999353790Sobrien	if (!np->dqueue)
999453790Sobrien		goto attach_failed;
999553790Sobrien
999653790Sobrien	/*
999753790Sobrien	 *  Allocate the target bus address array.
999853790Sobrien	 */
999953790Sobrien	np->targtbl = (u32 *) sym_calloc(256, "TARGTBL");
1000053790Sobrien	if (!np->targtbl)
1000153790Sobrien		goto attach_failed;
1000253790Sobrien
1000353790Sobrien	/*
1000453790Sobrien	 *  Allocate SCRIPTS areas.
1000553790Sobrien	 */
1000653790Sobrien	np->script0  = (struct sym_scr *)
1000753790Sobrien			sym_calloc(sizeof(struct sym_scr), "SCRIPT0");
1000853790Sobrien	np->scripth0 = (struct sym_scrh *)
1000953790Sobrien			sym_calloc(sizeof(struct sym_scrh), "SCRIPTH0");
1001053790Sobrien	if (!np->script0 || !np->scripth0)
1001153790Sobrien		goto attach_failed;
1001253790Sobrien
1001353790Sobrien	/*
1001453790Sobrien	 *  Initialyze the CCB free and busy queues.
1001553790Sobrien	 *  Allocate some CCB. We need at least ONE.
1001653790Sobrien	 */
1001753790Sobrien	sym_que_init(&np->free_ccbq);
1001853790Sobrien	sym_que_init(&np->busy_ccbq);
1001953790Sobrien	sym_que_init(&np->comp_ccbq);
1002053790Sobrien	if (!sym_alloc_ccb(np))
1002153790Sobrien		goto attach_failed;
1002253790Sobrien
1002353790Sobrien	/*
1002453790Sobrien	 * Initialyze the CAM CCB pending queue.
1002553790Sobrien	 */
1002653790Sobrien	sym_que_init(&np->cam_ccbq);
1002753790Sobrien
1002853790Sobrien	/*
1002953790Sobrien	 *  Fill-up variable-size parts of the SCRIPTS.
1003053790Sobrien	 */
1003153790Sobrien	sym_fill_scripts(&script0, &scripth0);
1003253790Sobrien
1003353790Sobrien	/*
1003453790Sobrien	 *  Calculate BUS addresses where we are going
1003553790Sobrien	 *  to load the SCRIPTS.
1003653790Sobrien	 */
1003753790Sobrien	np->script_ba	= vtobus(np->script0);
1003853790Sobrien	np->scripth_ba	= vtobus(np->scripth0);
1003953790Sobrien	np->scripth0_ba	= np->scripth_ba;
1004053790Sobrien
1004153790Sobrien	if (np->ram_ba) {
1004253790Sobrien		np->script_ba	= np->ram_ba;
1004353790Sobrien		if (np->features & FE_RAM8K) {
1004453790Sobrien			np->ram_ws = 8192;
1004553790Sobrien			np->scripth_ba = np->script_ba + 4096;
1004653790Sobrien#if BITS_PER_LONG > 32
1004753790Sobrien			np->scr_ram_seg = cpu_to_scr(np->script_ba >> 32);
1004853790Sobrien#endif
1004953790Sobrien		}
1005053790Sobrien		else
1005153790Sobrien			np->ram_ws = 4096;
1005253790Sobrien	}
1005353790Sobrien
1005453790Sobrien	/*
1005553790Sobrien	 *  Bind SCRIPTS with physical addresses usable by the
1005653790Sobrien	 *  SCRIPTS processor (as seen from the BUS = BUS addresses).
1005753790Sobrien	 */
1005853790Sobrien	sym_bind_script(np, (u32 *) &script0,
1005953790Sobrien			    (u32 *) np->script0, sizeof(struct sym_scr));
1006053790Sobrien	sym_bind_script(np, (u32 *) &scripth0,
1006153790Sobrien			    (u32 *) np->scripth0, sizeof(struct sym_scrh));
1006253790Sobrien
1006353790Sobrien	/*
1006453790Sobrien	 *  If not 64 bit chip, patch some places in SCRIPTS.
1006553790Sobrien	 */
1006653790Sobrien	if (!(np->features & FE_64BIT)) {
1006753790Sobrien		np->scripth0->swide_fin_32[0] = cpu_to_scr(SCR_JUMP);
1006853790Sobrien		np->scripth0->swide_fin_32[1] =
1006953790Sobrien				cpu_to_scr(SCRIPT_BA(np, dispatch));
1007053790Sobrien	}
1007153790Sobrien
1007253790Sobrien	/*
1007353790Sobrien	 *  Patch some variables in SCRIPTS.
1007453790Sobrien	 *  These ones are loaded by the SCRIPTS processor.
1007553790Sobrien	 */
1007653790Sobrien	np->scripth0->pm0_data_addr[0] = cpu_to_scr(SCRIPT_BA(np,pm0_data));
1007753790Sobrien	np->scripth0->pm1_data_addr[0] = cpu_to_scr(SCRIPT_BA(np,pm1_data));
1007853790Sobrien
1007953793Sobrien
1008053790Sobrien	/*
1008153790Sobrien	 *  Still some for LED support.
1008253790Sobrien	 */
1008353790Sobrien	if (np->features & FE_LED0) {
1008453790Sobrien		np->script0->idle[0]  =
1008553790Sobrien				cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR,  0x01));
1008653790Sobrien		np->script0->reselected[0] =
1008753790Sobrien				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
1008853790Sobrien		np->script0->start[0] =
1008953790Sobrien				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
1009053790Sobrien	}
1009153793Sobrien
1009253790Sobrien	/*
1009353790Sobrien	 *  Load SCNTL4 on reselection for the C10.
1009453790Sobrien	 */
1009553790Sobrien	if (np->features & FE_C10) {
1009653790Sobrien		np->script0->resel_scntl4[0] =
1009753790Sobrien				cpu_to_scr(SCR_LOAD_REL (scntl4, 1));
1009853790Sobrien		np->script0->resel_scntl4[1] =
1009953790Sobrien				cpu_to_scr(offsetof(struct sym_tcb, uval));
1010053790Sobrien	}
1010153790Sobrien
1010254690Sobrien#ifdef SYM_CONF_IARB_SUPPORT
1010353790Sobrien	/*
1010453790Sobrien	 *    If user does not want to use IMMEDIATE ARBITRATION
1010553790Sobrien	 *    when we are reselected while attempting to arbitrate,
1010653790Sobrien	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
1010753790Sobrien	 */
1010854690Sobrien	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
1010953790Sobrien		np->script0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
1011053790Sobrien
1011153790Sobrien	/*
1011253790Sobrien	 *    If user wants IARB to be set when we win arbitration
1011353790Sobrien	 *    and have other jobs, compute the max number of consecutive
1011453790Sobrien	 *    settings of IARB hints before we leave devices a chance to
1011553790Sobrien	 *    arbitrate for reselection.
1011653790Sobrien	 */
1011754690Sobrien#ifdef	SYM_SETUP_IARB_MAX
1011854690Sobrien	np->iarb_max = SYM_SETUP_IARB_MAX;
1011953790Sobrien#else
1012053790Sobrien	np->iarb_max = 4;
1012153790Sobrien#endif
1012253790Sobrien#endif
1012353790Sobrien
1012453790Sobrien	/*
1012553790Sobrien	 *  Prepare the idle and invalid task actions.
1012653790Sobrien	 */
1012753790Sobrien	np->idletask.start	= cpu_to_scr(SCRIPT_BA(np, idle));
1012853790Sobrien	np->idletask.restart	= cpu_to_scr(SCRIPTH_BA(np, bad_i_t_l));
1012953790Sobrien	np->idletask_ba		= vtobus(&np->idletask);
1013053790Sobrien
1013153790Sobrien	np->notask.start	= cpu_to_scr(SCRIPT_BA(np, idle));
1013253790Sobrien	np->notask.restart	= cpu_to_scr(SCRIPTH_BA(np, bad_i_t_l));
1013353790Sobrien	np->notask_ba		= vtobus(&np->notask);
1013453790Sobrien
1013553790Sobrien	np->bad_itl.start	= cpu_to_scr(SCRIPT_BA(np, idle));
1013653790Sobrien	np->bad_itl.restart	= cpu_to_scr(SCRIPTH_BA(np, bad_i_t_l));
1013753790Sobrien	np->bad_itl_ba		= vtobus(&np->bad_itl);
1013853790Sobrien
1013953790Sobrien	np->bad_itlq.start	= cpu_to_scr(SCRIPT_BA(np, idle));
1014053790Sobrien	np->bad_itlq.restart	= cpu_to_scr(SCRIPTH_BA (np,bad_i_t_l_q));
1014153790Sobrien	np->bad_itlq_ba		= vtobus(&np->bad_itlq);
1014253790Sobrien
1014353790Sobrien	/*
1014453790Sobrien	 *  Allocate and prepare the lun JUMP table that is used
1014553790Sobrien	 *  for a target prior the probing of devices (bad lun table).
1014653790Sobrien	 *  A private table will be allocated for the target on the
1014753790Sobrien	 *  first INQUIRY response received.
1014853790Sobrien	 */
1014953790Sobrien	np->badluntbl = sym_calloc(256, "BADLUNTBL");
1015053790Sobrien	if (!np->badluntbl)
1015153790Sobrien		goto attach_failed;
1015253790Sobrien
1015353790Sobrien	np->badlun_sa = cpu_to_scr(SCRIPTH_BA(np, resel_bad_lun));
1015453790Sobrien	for (i = 0 ; i < 64 ; i++)	/* 64 luns/target, no less */
1015553790Sobrien		np->badluntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa));
1015653790Sobrien
1015753790Sobrien	/*
1015853790Sobrien	 *  Prepare the bus address array that contains the bus
1015953790Sobrien	 *  address of each target control bloc.
1016053790Sobrien	 *  For now, assume all logical unit are wrong. :)
1016153790Sobrien	 */
1016253790Sobrien	np->scripth0->targtbl[0] = cpu_to_scr(vtobus(np->targtbl));
1016354690Sobrien	for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
1016453790Sobrien		np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i]));
1016553790Sobrien		np->target[i].luntbl_sa = cpu_to_scr(vtobus(np->badluntbl));
1016653790Sobrien		np->target[i].lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa));
1016753790Sobrien	}
1016853790Sobrien
1016953790Sobrien	/*
1017053790Sobrien	 *  Now check the cache handling of the pci chipset.
1017153790Sobrien	 */
1017253790Sobrien	if (sym_snooptest (np)) {
1017353790Sobrien#ifdef FreeBSD_4_Bus
1017453790Sobrien		device_printf(dev, "CACHE INCORRECTLY CONFIGURED.\n");
1017553790Sobrien#else
1017653790Sobrien		printf("%s: CACHE INCORRECTLY CONFIGURED.\n", sym_name(np));
1017753790Sobrien#endif
1017853790Sobrien		goto attach_failed;
1017953790Sobrien	};
1018053790Sobrien
1018153790Sobrien	/*
1018253790Sobrien	 *  Now deal with CAM.
1018353790Sobrien	 *  Hopefully, we will succeed with that one.:)
1018453790Sobrien	 */
1018553790Sobrien	if (!sym_cam_attach(np))
1018653790Sobrien		goto attach_failed;
1018753790Sobrien
1018853790Sobrien	/*
1018953790Sobrien	 *  Sigh! we are done.
1019053790Sobrien	 */
1019153790Sobrien	return 0;
1019253790Sobrien
1019353790Sobrien	/*
1019453790Sobrien	 *  We have failed.
1019553790Sobrien	 *  We will try to free all the resources we have
1019653790Sobrien	 *  allocated, but if we are a boot device, this
1019753790Sobrien	 *  will not help that much.;)
1019853790Sobrien	 */
1019953790Sobrienattach_failed:
1020053790Sobrien	if (np)
1020153790Sobrien		sym_pci_free(np);
1020253790Sobrien	return ENXIO;
1020353790Sobrien}
1020453790Sobrien
1020553790Sobrien/*
1020653790Sobrien *  Free everything that have been allocated for this device.
1020753790Sobrien */
1020853790Sobrienstatic void sym_pci_free(hcb_p np)
1020953790Sobrien{
1021055300Sgroudier	SYM_QUEHEAD *qp;
1021153790Sobrien	ccb_p cp;
1021253790Sobrien	tcb_p tp;
1021353790Sobrien	lcb_p lp;
1021453790Sobrien	int target, lun;
1021553790Sobrien	int s;
1021653790Sobrien
1021753790Sobrien	/*
1021853790Sobrien	 *  First free CAM resources.
1021953790Sobrien	 */
1022053790Sobrien	s = splcam();
1022153790Sobrien	sym_cam_free(np);
1022253790Sobrien	splx(s);
1022353790Sobrien
1022453790Sobrien	/*
1022553790Sobrien	 *  Now every should be quiet for us to
1022653790Sobrien	 *  free other resources.
1022753790Sobrien	 */
1022853790Sobrien#ifdef FreeBSD_4_Bus
1022953790Sobrien	if (np->ram_res)
1023053790Sobrien		bus_release_resource(np->device, SYS_RES_MEMORY,
1023153790Sobrien				     np->ram_id, np->ram_res);
1023253790Sobrien	if (np->mmio_res)
1023353790Sobrien		bus_release_resource(np->device, SYS_RES_MEMORY,
1023453790Sobrien				     SYM_PCI_MMIO, np->mmio_res);
1023553790Sobrien	if (np->io_res)
1023653790Sobrien		bus_release_resource(np->device, SYS_RES_IOPORT,
1023753790Sobrien				     SYM_PCI_IO, np->io_res);
1023853790Sobrien	if (np->irq_res)
1023953790Sobrien		bus_release_resource(np->device, SYS_RES_IRQ,
1024053790Sobrien				     0, np->irq_res);
1024153790Sobrien#else
1024253790Sobrien	/*
1024353790Sobrien	 *  YEAH!!!
1024453790Sobrien	 *  It seems there is no means to free MMIO resources.
1024553790Sobrien	 */
1024653790Sobrien#endif
1024753790Sobrien
1024853790Sobrien	if (np->scripth0)
1024953790Sobrien		sym_mfree(np->scripth0, sizeof(struct sym_scrh), "SCRIPTH0");
1025053790Sobrien	if (np->script0)
1025153790Sobrien		sym_mfree(np->script0, sizeof(struct sym_scr), "SCRIPT0");
1025253790Sobrien	if (np->squeue)
1025353790Sobrien		sym_mfree(np->squeue, sizeof(u32)*(MAX_QUEUE*2), "SQUEUE");
1025453790Sobrien	if (np->dqueue)
1025553790Sobrien		sym_mfree(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE");
1025653790Sobrien
1025755300Sgroudier	while ((qp = sym_remque_head(&np->free_ccbq)) != 0) {
1025855300Sgroudier		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
1025953790Sobrien		sym_mfree(cp, sizeof(*cp), "CCB");
1026053790Sobrien	}
1026153790Sobrien
1026253790Sobrien	if (np->badluntbl)
1026353790Sobrien		sym_mfree(np->badluntbl, 256,"BADLUNTBL");
1026453790Sobrien
1026554690Sobrien	for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) {
1026653790Sobrien		tp = &np->target[target];
1026754690Sobrien		for (lun = 0 ; lun < SYM_CONF_MAX_LUN ; lun++) {
1026853790Sobrien			lp = sym_lp(np, tp, lun);
1026953790Sobrien			if (!lp)
1027053790Sobrien				continue;
1027153790Sobrien			if (lp->itlq_tbl)
1027254690Sobrien				sym_mfree(lp->itlq_tbl, SYM_CONF_MAX_TASK*4,
1027353790Sobrien				       "ITLQ_TBL");
1027453790Sobrien			if (lp->cb_tags)
1027554690Sobrien				sym_mfree(lp->cb_tags, SYM_CONF_MAX_TASK,
1027653790Sobrien				       "CB_TAGS");
1027753790Sobrien			sym_mfree(lp, sizeof(*lp), "LCB");
1027853790Sobrien		}
1027954690Sobrien#if SYM_CONF_MAX_LUN > 1
1028053790Sobrien		if (tp->lunmp)
1028154690Sobrien			sym_mfree(tp->lunmp, SYM_CONF_MAX_LUN*sizeof(lcb_p),
1028253790Sobrien			       "LUNMP");
1028353790Sobrien#endif
1028453790Sobrien	}
1028553790Sobrien
1028653790Sobrien	sym_mfree(np, sizeof(*np), "HCB");
1028753790Sobrien}
1028853790Sobrien
1028953790Sobrien/*
1029053790Sobrien *  Allocate CAM resources and register a bus to CAM.
1029153790Sobrien */
1029253790Sobrienint sym_cam_attach(hcb_p np)
1029353790Sobrien{
1029453790Sobrien	struct cam_devq *devq = 0;
1029553790Sobrien	struct cam_sim *sim = 0;
1029653790Sobrien	struct cam_path *path = 0;
1029753790Sobrien	int err, s;
1029853790Sobrien
1029953790Sobrien	s = splcam();
1030053790Sobrien
1030153790Sobrien	/*
1030253790Sobrien	 *  Establish our interrupt handler.
1030353790Sobrien	 */
1030453790Sobrien#ifdef FreeBSD_4_Bus
1030553790Sobrien	err = bus_setup_intr(np->device, np->irq_res, INTR_TYPE_CAM,
1030653790Sobrien			     sym_intr, np, &np->intr);
1030753790Sobrien	if (err) {
1030853790Sobrien		device_printf(np->device, "bus_setup_intr() failed: %d\n",
1030953790Sobrien			      err);
1031053790Sobrien		goto fail;
1031153790Sobrien	}
1031253790Sobrien#else
1031353790Sobrien	if (!pci_map_int (np->pci_tag, sym_intr, np, &cam_imask)) {
1031453790Sobrien		printf("%s: failed to map interrupt\n", sym_name(np));
1031553790Sobrien		goto fail;
1031653790Sobrien	}
1031753790Sobrien#endif
1031853790Sobrien
1031953790Sobrien	/*
1032053790Sobrien	 *  Create the device queue for our sym SIM.
1032153790Sobrien	 */
1032254690Sobrien	devq = cam_simq_alloc(SYM_CONF_MAX_START);
1032353790Sobrien	if (!devq)
1032453790Sobrien		goto fail;
1032553790Sobrien
1032653790Sobrien	/*
1032753790Sobrien	 *  Construct our SIM entry.
1032853790Sobrien	 */
1032953790Sobrien	sim = cam_sim_alloc(sym_action, sym_poll, "sym", np, np->unit,
1033054690Sobrien			    1, SYM_SETUP_MAX_TAG, devq);
1033153790Sobrien	if (!sim)
1033253790Sobrien		goto fail;
1033353790Sobrien	devq = 0;
1033453790Sobrien
1033553790Sobrien	if (xpt_bus_register(sim, 0) != CAM_SUCCESS)
1033653790Sobrien		goto fail;
1033753790Sobrien	np->sim = sim;
1033853790Sobrien	sim = 0;
1033953790Sobrien
1034053790Sobrien	if (xpt_create_path(&path, 0,
1034153790Sobrien			    cam_sim_path(np->sim), CAM_TARGET_WILDCARD,
1034253790Sobrien			    CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1034353790Sobrien		goto fail;
1034453790Sobrien	}
1034553790Sobrien	np->path = path;
1034653790Sobrien
1034753793Sobrien	/*
1034853793Sobrien	 *  Hmmm... This should be useful, but I donnot want to
1034953793Sobrien	 *  know about.
1035053793Sobrien	 */
1035153796Sobrien#if 	__FreeBSD_version < 400000
1035253793Sobrien#ifdef	__alpha__
1035353793Sobrien#ifdef	FreeBSD_4_Bus
1035453793Sobrien	alpha_register_pci_scsi(pci_get_bus(np->device),
1035553793Sobrien				pci_get_slot(np->device), np->sim);
1035653796Sobrien#else
1035753793Sobrien	alpha_register_pci_scsi(pci_tag->bus, pci_tag->slot, np->sim);
1035853793Sobrien#endif
1035953793Sobrien#endif
1036053796Sobrien#endif
1036153793Sobrien
1036253790Sobrien#if 0
1036353790Sobrien	/*
1036453790Sobrien	 *  Establish our async notification handler.
1036553790Sobrien	 */
1036653790Sobrien	{
1036753790Sobrien	struct ccb_setasync csa;
1036853790Sobrien	xpt_setup_ccb(&csa.ccb_h, np->path, 5);
1036953790Sobrien	csa.ccb_h.func_code = XPT_SASYNC_CB;
1037053790Sobrien	csa.event_enable    = AC_LOST_DEVICE;
1037153790Sobrien	csa.callback	    = sym_async;
1037253790Sobrien	csa.callback_arg    = np->sim;
1037353790Sobrien	xpt_action((union ccb *)&csa);
1037453790Sobrien	}
1037553790Sobrien#endif
1037655300Sgroudier	/*
1037755300Sgroudier	 *  Start the chip now, without resetting the BUS, since
1037855300Sgroudier	 *  it seems that this must stay under control of CAM.
1037955300Sgroudier	 *  With LVD/SE capable chips and BUS in SE mode, we may
1038055300Sgroudier	 *  get a spurious SMBC interrupt.
1038155300Sgroudier	 */
1038255300Sgroudier	sym_init (np, 0);
1038353790Sobrien
1038453790Sobrien	splx(s);
1038553790Sobrien	return 1;
1038653790Sobrienfail:
1038753790Sobrien	if (sim)
1038853790Sobrien		cam_sim_free(sim, FALSE);
1038953790Sobrien	if (devq)
1039053790Sobrien		cam_simq_free(devq);
1039153790Sobrien
1039253790Sobrien	sym_cam_free(np);
1039353790Sobrien
1039453790Sobrien	splx(s);
1039553790Sobrien	return 0;
1039653790Sobrien}
1039753790Sobrien
1039853790Sobrien/*
1039953790Sobrien *  Free everything that deals with CAM.
1040053790Sobrien */
1040153790Sobrienvoid sym_cam_free(hcb_p np)
1040253790Sobrien{
1040353790Sobrien#ifdef FreeBSD_4_Bus
1040453790Sobrien	if (np->intr)
1040553790Sobrien		bus_teardown_intr(np->device, np->irq_res, np->intr);
1040653790Sobrien#else
1040753790Sobrien	/* pci_unmap_int(np->pci_tag); */	/* Does nothing */
1040853790Sobrien#endif
1040953790Sobrien
1041053790Sobrien	if (np->sim) {
1041153790Sobrien		xpt_bus_deregister(cam_sim_path(np->sim));
1041253790Sobrien		cam_sim_free(np->sim, /*free_devq*/ TRUE);
1041353790Sobrien	}
1041453790Sobrien	if (np->path)
1041553790Sobrien		xpt_free_path(np->path);
1041653790Sobrien}
1041753790Sobrien
1041853790Sobrien/*============ OPTIONNAL NVRAM SUPPORT =================*/
1041953790Sobrien
1042053790Sobrien/*
1042153790Sobrien *  Get host setup from NVRAM.
1042253790Sobrien */
1042353790Sobrienstatic void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram)
1042453790Sobrien{
1042554690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT
1042653790Sobrien	/*
1042755628Sgroudier	 *  Get parity checking, host ID, verbose mode
1042855628Sgroudier	 *  and miscellaneous host flags from NVRAM.
1042953790Sobrien	 */
1043053790Sobrien	switch(nvram->type) {
1043153790Sobrien	case SYM_SYMBIOS_NVRAM:
1043253790Sobrien		if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
1043353790Sobrien			np->rv_scntl0  &= ~0x0a;
1043453790Sobrien		np->myaddr = nvram->data.Symbios.host_id & 0x0f;
1043553790Sobrien		if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
1043653790Sobrien			np->verbose += 1;
1043755628Sgroudier		if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
1043855628Sgroudier			np->usrflags |= SYM_SCAN_TARGETS_HILO;
1043955628Sgroudier		if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
1044055628Sgroudier			np->usrflags |= SYM_AVOID_BUS_RESET;
1044153790Sobrien		break;
1044253790Sobrien	case SYM_TEKRAM_NVRAM:
1044353790Sobrien		np->myaddr = nvram->data.Tekram.host_id & 0x0f;
1044453790Sobrien		break;
1044553790Sobrien	default:
1044653790Sobrien		break;
1044753790Sobrien	}
1044853790Sobrien#endif
1044953790Sobrien}
1045053790Sobrien
1045153790Sobrien/*
1045253790Sobrien *  Get target setup from NVRAM.
1045353790Sobrien */
1045454690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT
1045553790Sobrienstatic void sym_Symbios_setup_target(hcb_p np,int target, Symbios_nvram *nvram);
1045653790Sobrienstatic void sym_Tekram_setup_target(hcb_p np,int target, Tekram_nvram *nvram);
1045753790Sobrien#endif
1045853790Sobrien
1045953790Sobrienstatic void
1046053790Sobriensym_nvram_setup_target (hcb_p np, int target, struct sym_nvram *nvp)
1046153790Sobrien{
1046254690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT
1046353790Sobrien	switch(nvp->type) {
1046453790Sobrien	case SYM_SYMBIOS_NVRAM:
1046553790Sobrien		sym_Symbios_setup_target (np, target, &nvp->data.Symbios);
1046653790Sobrien		break;
1046753790Sobrien	case SYM_TEKRAM_NVRAM:
1046853790Sobrien		sym_Tekram_setup_target (np, target, &nvp->data.Tekram);
1046953790Sobrien		break;
1047053790Sobrien	default:
1047153790Sobrien		break;
1047253790Sobrien	}
1047353790Sobrien#endif
1047453790Sobrien}
1047553790Sobrien
1047654690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT
1047753790Sobrien/*
1047853790Sobrien *  Get target set-up from Symbios format NVRAM.
1047953790Sobrien */
1048053790Sobrienstatic void
1048153790Sobriensym_Symbios_setup_target(hcb_p np, int target, Symbios_nvram *nvram)
1048253790Sobrien{
1048353790Sobrien	tcb_p tp = &np->target[target];
1048453790Sobrien	Symbios_target *tn = &nvram->target[target];
1048553790Sobrien
1048653790Sobrien	tp->tinfo.user.period = tn->sync_period ? (tn->sync_period + 3) / 4 : 0;
1048753790Sobrien	tp->tinfo.user.width  = tn->bus_width == 0x10 ? BUS_16_BIT : BUS_8_BIT;
1048853790Sobrien	tp->usrtags =
1048954690Sobrien		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0;
1049053790Sobrien
1049153790Sobrien	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
1049253790Sobrien		tp->usrflags &= ~SYM_DISC_ENABLED;
1049353790Sobrien	if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
1049453790Sobrien		tp->usrflags |= SYM_SCAN_BOOT_DISABLED;
1049553790Sobrien	if (!(tn->flags & SYMBIOS_SCAN_LUNS))
1049653790Sobrien		tp->usrflags |= SYM_SCAN_LUNS_DISABLED;
1049753790Sobrien}
1049853790Sobrien
1049953790Sobrien/*
1050053790Sobrien *  Get target set-up from Tekram format NVRAM.
1050153790Sobrien */
1050253790Sobrienstatic void
1050353790Sobriensym_Tekram_setup_target(hcb_p np, int target, Tekram_nvram *nvram)
1050453790Sobrien{
1050553790Sobrien	tcb_p tp = &np->target[target];
1050653790Sobrien	struct Tekram_target *tn = &nvram->target[target];
1050753790Sobrien	int i;
1050853790Sobrien
1050953790Sobrien	if (tn->flags & TEKRAM_SYNC_NEGO) {
1051053790Sobrien		i = tn->sync_index & 0xf;
1051153790Sobrien		tp->tinfo.user.period = Tekram_sync[i];
1051253790Sobrien	}
1051353790Sobrien
1051453790Sobrien	tp->tinfo.user.width =
1051553790Sobrien		(tn->flags & TEKRAM_WIDE_NEGO) ? BUS_16_BIT : BUS_8_BIT;
1051653790Sobrien
1051753790Sobrien	if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
1051853790Sobrien		tp->usrtags = 2 << nvram->max_tags_index;
1051953790Sobrien	}
1052053790Sobrien
1052153790Sobrien	if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
1052253790Sobrien		tp->usrflags |= SYM_DISC_ENABLED;
1052353790Sobrien
1052453790Sobrien	/* If any device does not support parity, we will not use this option */
1052553790Sobrien	if (!(tn->flags & TEKRAM_PARITY_CHECK))
1052653790Sobrien		np->rv_scntl0  &= ~0x0a; /* SCSI parity checking disabled */
1052753790Sobrien}
1052853790Sobrien
1052954690Sobrien#ifdef	SYM_CONF_DEBUG_NVRAM
1053053790Sobrien/*
1053153790Sobrien *  Dump Symbios format NVRAM for debugging purpose.
1053253790Sobrien */
1053353790Sobrienvoid sym_display_Symbios_nvram(hcb_p np, Symbios_nvram *nvram)
1053453790Sobrien{
1053553790Sobrien	int i;
1053653790Sobrien
1053753790Sobrien	/* display Symbios nvram host data */
1053855628Sgroudier	printf("%s: HOST ID=%d%s%s%s%s%s%s\n",
1053953790Sobrien		sym_name(np), nvram->host_id & 0x0f,
1054053790Sobrien		(nvram->flags  & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
1054153790Sobrien		(nvram->flags  & SYMBIOS_PARITY_ENABLE)	? " PARITY"	:"",
1054253790Sobrien		(nvram->flags  & SYMBIOS_VERBOSE_MSGS)	? " VERBOSE"	:"",
1054353790Sobrien		(nvram->flags  & SYMBIOS_CHS_MAPPING)	? " CHS_ALT"	:"",
1054455628Sgroudier		(nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET"	:"",
1054553790Sobrien		(nvram->flags1 & SYMBIOS_SCAN_HI_LO)	? " HI_LO"	:"");
1054653790Sobrien
1054753790Sobrien	/* display Symbios nvram drive data */
1054853790Sobrien	for (i = 0 ; i < 15 ; i++) {
1054953790Sobrien		struct Symbios_target *tn = &nvram->target[i];
1055053790Sobrien		printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
1055153790Sobrien		sym_name(np), i,
1055253790Sobrien		(tn->flags & SYMBIOS_DISCONNECT_ENABLE)	? " DISC"	: "",
1055353790Sobrien		(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)	? " SCAN_BOOT"	: "",
1055453790Sobrien		(tn->flags & SYMBIOS_SCAN_LUNS)		? " SCAN_LUNS"	: "",
1055553790Sobrien		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ"	: "",
1055653790Sobrien		tn->bus_width,
1055753790Sobrien		tn->sync_period / 4,
1055853790Sobrien		tn->timeout);
1055953790Sobrien	}
1056053790Sobrien}
1056153790Sobrien
1056253790Sobrien/*
1056353790Sobrien *  Dump TEKRAM format NVRAM for debugging purpose.
1056453790Sobrien */
1056553790Sobrienstatic u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120};
1056653790Sobrienvoid sym_display_Tekram_nvram(hcb_p np, Tekram_nvram *nvram)
1056753790Sobrien{
1056853790Sobrien	int i, tags, boot_delay;
1056953790Sobrien	char *rem;
1057053790Sobrien
1057153790Sobrien	/* display Tekram nvram host data */
1057253790Sobrien	tags = 2 << nvram->max_tags_index;
1057353790Sobrien	boot_delay = 0;
1057453790Sobrien	if (nvram->boot_delay_index < 6)
1057553790Sobrien		boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
1057653790Sobrien	switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
1057753790Sobrien	default:
1057853790Sobrien	case 0:	rem = "";			break;
1057953790Sobrien	case 1: rem = " REMOVABLE=boot device";	break;
1058053790Sobrien	case 2: rem = " REMOVABLE=all";		break;
1058153790Sobrien	}
1058253790Sobrien
1058353790Sobrien	printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
1058453790Sobrien		sym_name(np), nvram->host_id & 0x0f,
1058553790Sobrien		(nvram->flags1 & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
1058653790Sobrien		(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES"	:"",
1058753790Sobrien		(nvram->flags & TEKRAM_DRIVES_SUP_1GB)	? " >1GB"	:"",
1058853790Sobrien		(nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET"	:"",
1058953790Sobrien		(nvram->flags & TEKRAM_ACTIVE_NEGATION)	? " ACT_NEG"	:"",
1059053790Sobrien		(nvram->flags & TEKRAM_IMMEDIATE_SEEK)	? " IMM_SEEK"	:"",
1059153790Sobrien		(nvram->flags & TEKRAM_SCAN_LUNS)	? " SCAN_LUNS"	:"",
1059253790Sobrien		(nvram->flags1 & TEKRAM_F2_F6_ENABLED)	? " F2_F6"	:"",
1059353790Sobrien		rem, boot_delay, tags);
1059453790Sobrien
1059553790Sobrien	/* display Tekram nvram drive data */
1059653790Sobrien	for (i = 0; i <= 15; i++) {
1059753790Sobrien		int sync, j;
1059853790Sobrien		struct Tekram_target *tn = &nvram->target[i];
1059953790Sobrien		j = tn->sync_index & 0xf;
1060053790Sobrien		sync = Tekram_sync[j];
1060153790Sobrien		printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
1060253790Sobrien		sym_name(np), i,
1060353790Sobrien		(tn->flags & TEKRAM_PARITY_CHECK)	? " PARITY"	: "",
1060453790Sobrien		(tn->flags & TEKRAM_SYNC_NEGO)		? " SYNC"	: "",
1060553790Sobrien		(tn->flags & TEKRAM_DISCONNECT_ENABLE)	? " DISC"	: "",
1060653790Sobrien		(tn->flags & TEKRAM_START_CMD)		? " START"	: "",
1060753790Sobrien		(tn->flags & TEKRAM_TAGGED_COMMANDS)	? " TCQ"	: "",
1060853790Sobrien		(tn->flags & TEKRAM_WIDE_NEGO)		? " WIDE"	: "",
1060953790Sobrien		sync);
1061053790Sobrien	}
1061153790Sobrien}
1061254690Sobrien#endif	/* SYM_CONF_DEBUG_NVRAM */
1061354690Sobrien#endif	/* SYM_CONF_NVRAM_SUPPORT */
1061453790Sobrien
1061553790Sobrien
1061653790Sobrien/*
1061753790Sobrien *  Try reading Symbios or Tekram NVRAM
1061853790Sobrien */
1061954690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT
1062053790Sobrienstatic int sym_read_Symbios_nvram (hcb_p np, Symbios_nvram *nvram);
1062153790Sobrienstatic int sym_read_Tekram_nvram  (hcb_p np, Tekram_nvram *nvram);
1062253790Sobrien#endif
1062353790Sobrien
1062453790Sobrienint sym_read_nvram(hcb_p np, struct sym_nvram *nvp)
1062553790Sobrien{
1062654690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT
1062753790Sobrien	/*
1062853790Sobrien	 *  Try to read SYMBIOS nvram.
1062953790Sobrien	 *  Try to read TEKRAM nvram if Symbios nvram not found.
1063053790Sobrien	 */
1063154690Sobrien	if	(SYM_SETUP_SYMBIOS_NVRAM &&
1063253790Sobrien		 !sym_read_Symbios_nvram (np, &nvp->data.Symbios))
1063353790Sobrien		nvp->type = SYM_SYMBIOS_NVRAM;
1063454690Sobrien	else if	(SYM_SETUP_TEKRAM_NVRAM &&
1063553790Sobrien		 !sym_read_Tekram_nvram (np, &nvp->data.Tekram))
1063653790Sobrien		nvp->type = SYM_TEKRAM_NVRAM;
1063753790Sobrien	else
1063853790Sobrien		nvp->type = 0;
1063953790Sobrien#else
1064053790Sobrien	nvp->type = 0;
1064153790Sobrien#endif
1064253790Sobrien	return nvp->type;
1064353790Sobrien}
1064453790Sobrien
1064553790Sobrien
1064654690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT
1064753790Sobrien/*
1064853790Sobrien *  24C16 EEPROM reading.
1064953790Sobrien *
1065053790Sobrien *  GPOI0 - data in/data out
1065153790Sobrien *  GPIO1 - clock
1065253790Sobrien *  Symbios NVRAM wiring now also used by Tekram.
1065353790Sobrien */
1065453790Sobrien
1065553790Sobrien#define SET_BIT 0
1065653790Sobrien#define CLR_BIT 1
1065753790Sobrien#define SET_CLK 2
1065853790Sobrien#define CLR_CLK 3
1065953790Sobrien
1066053790Sobrien/*
1066153790Sobrien *  Set/clear data/clock bit in GPIO0
1066253790Sobrien */
1066353790Sobrienstatic void S24C16_set_bit(hcb_p np, u_char write_bit, u_char *gpreg,
1066453790Sobrien			  int bit_mode)
1066553790Sobrien{
1066653790Sobrien	UDELAY (5);
1066753790Sobrien	switch (bit_mode){
1066853790Sobrien	case SET_BIT:
1066953790Sobrien		*gpreg |= write_bit;
1067053790Sobrien		break;
1067153790Sobrien	case CLR_BIT:
1067253790Sobrien		*gpreg &= 0xfe;
1067353790Sobrien		break;
1067453790Sobrien	case SET_CLK:
1067553790Sobrien		*gpreg |= 0x02;
1067653790Sobrien		break;
1067753790Sobrien	case CLR_CLK:
1067853790Sobrien		*gpreg &= 0xfd;
1067953790Sobrien		break;
1068053790Sobrien
1068153790Sobrien	}
1068253790Sobrien	OUTB (nc_gpreg, *gpreg);
1068353790Sobrien	UDELAY (5);
1068453790Sobrien}
1068553790Sobrien
1068653790Sobrien/*
1068753790Sobrien *  Send START condition to NVRAM to wake it up.
1068853790Sobrien */
1068953790Sobrienstatic void S24C16_start(hcb_p np, u_char *gpreg)
1069053790Sobrien{
1069153790Sobrien	S24C16_set_bit(np, 1, gpreg, SET_BIT);
1069253790Sobrien	S24C16_set_bit(np, 0, gpreg, SET_CLK);
1069353790Sobrien	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
1069453790Sobrien	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
1069553790Sobrien}
1069653790Sobrien
1069753790Sobrien/*
1069853790Sobrien *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
1069953790Sobrien */
1070053790Sobrienstatic void S24C16_stop(hcb_p np, u_char *gpreg)
1070153790Sobrien{
1070253790Sobrien	S24C16_set_bit(np, 0, gpreg, SET_CLK);
1070353790Sobrien	S24C16_set_bit(np, 1, gpreg, SET_BIT);
1070453790Sobrien}
1070553790Sobrien
1070653790Sobrien/*
1070753790Sobrien *  Read or write a bit to the NVRAM,
1070853790Sobrien *  read if GPIO0 input else write if GPIO0 output
1070953790Sobrien */
1071053790Sobrienstatic void S24C16_do_bit(hcb_p np, u_char *read_bit, u_char write_bit,
1071153790Sobrien			 u_char *gpreg)
1071253790Sobrien{
1071353790Sobrien	S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
1071453790Sobrien	S24C16_set_bit(np, 0, gpreg, SET_CLK);
1071553790Sobrien	if (read_bit)
1071653790Sobrien		*read_bit = INB (nc_gpreg);
1071753790Sobrien	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
1071853790Sobrien	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
1071953790Sobrien}
1072053790Sobrien
1072153790Sobrien/*
1072253790Sobrien *  Output an ACK to the NVRAM after reading,
1072353790Sobrien *  change GPIO0 to output and when done back to an input
1072453790Sobrien */
1072553790Sobrienstatic void S24C16_write_ack(hcb_p np, u_char write_bit, u_char *gpreg,
1072653790Sobrien			    u_char *gpcntl)
1072753790Sobrien{
1072853790Sobrien	OUTB (nc_gpcntl, *gpcntl & 0xfe);
1072953790Sobrien	S24C16_do_bit(np, 0, write_bit, gpreg);
1073053790Sobrien	OUTB (nc_gpcntl, *gpcntl);
1073153790Sobrien}
1073253790Sobrien
1073353790Sobrien/*
1073453790Sobrien *  Input an ACK from NVRAM after writing,
1073553790Sobrien *  change GPIO0 to input and when done back to an output
1073653790Sobrien */
1073753790Sobrienstatic void S24C16_read_ack(hcb_p np, u_char *read_bit, u_char *gpreg,
1073853790Sobrien			   u_char *gpcntl)
1073953790Sobrien{
1074053790Sobrien	OUTB (nc_gpcntl, *gpcntl | 0x01);
1074153790Sobrien	S24C16_do_bit(np, read_bit, 1, gpreg);
1074253790Sobrien	OUTB (nc_gpcntl, *gpcntl);
1074353790Sobrien}
1074453790Sobrien
1074553790Sobrien/*
1074653790Sobrien *  WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
1074753790Sobrien *  GPIO0 must already be set as an output
1074853790Sobrien */
1074953790Sobrienstatic void S24C16_write_byte(hcb_p np, u_char *ack_data, u_char write_data,
1075053790Sobrien			     u_char *gpreg, u_char *gpcntl)
1075153790Sobrien{
1075253790Sobrien	int x;
1075353790Sobrien
1075453790Sobrien	for (x = 0; x < 8; x++)
1075553790Sobrien		S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg);
1075653790Sobrien
1075753790Sobrien	S24C16_read_ack(np, ack_data, gpreg, gpcntl);
1075853790Sobrien}
1075953790Sobrien
1076053790Sobrien/*
1076153790Sobrien *  READ a byte from the NVRAM and then send an ACK to say we have got it,
1076253790Sobrien *  GPIO0 must already be set as an input
1076353790Sobrien */
1076453790Sobrienstatic void S24C16_read_byte(hcb_p np, u_char *read_data, u_char ack_data,
1076553790Sobrien			    u_char *gpreg, u_char *gpcntl)
1076653790Sobrien{
1076753790Sobrien	int x;
1076853790Sobrien	u_char read_bit;
1076953790Sobrien
1077053790Sobrien	*read_data = 0;
1077153790Sobrien	for (x = 0; x < 8; x++) {
1077253790Sobrien		S24C16_do_bit(np, &read_bit, 1, gpreg);
1077353790Sobrien		*read_data |= ((read_bit & 0x01) << (7 - x));
1077453790Sobrien	}
1077553790Sobrien
1077653790Sobrien	S24C16_write_ack(np, ack_data, gpreg, gpcntl);
1077753790Sobrien}
1077853790Sobrien
1077953790Sobrien/*
1078053790Sobrien *  Read 'len' bytes starting at 'offset'.
1078153790Sobrien */
1078253790Sobrienstatic int sym_read_S24C16_nvram (hcb_p np, int offset, u_char *data, int len)
1078353790Sobrien{
1078453790Sobrien	u_char	gpcntl, gpreg;
1078553790Sobrien	u_char	old_gpcntl, old_gpreg;
1078653790Sobrien	u_char	ack_data;
1078753790Sobrien	int	retv = 1;
1078853790Sobrien	int	x;
1078953790Sobrien
1079053790Sobrien	/* save current state of GPCNTL and GPREG */
1079153790Sobrien	old_gpreg	= INB (nc_gpreg);
1079253790Sobrien	old_gpcntl	= INB (nc_gpcntl);
1079353790Sobrien	gpcntl		= old_gpcntl & 0xfc;
1079453790Sobrien
1079553790Sobrien	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
1079653790Sobrien	OUTB (nc_gpreg,  old_gpreg);
1079753790Sobrien	OUTB (nc_gpcntl, gpcntl);
1079853790Sobrien
1079953790Sobrien	/* this is to set NVRAM into a known state with GPIO0/1 both low */
1080053790Sobrien	gpreg = old_gpreg;
1080153790Sobrien	S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
1080253790Sobrien	S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
1080353790Sobrien
1080453790Sobrien	/* now set NVRAM inactive with GPIO0/1 both high */
1080553790Sobrien	S24C16_stop(np, &gpreg);
1080653790Sobrien
1080753790Sobrien	/* activate NVRAM */
1080853790Sobrien	S24C16_start(np, &gpreg);
1080953790Sobrien
1081053790Sobrien	/* write device code and random address MSB */
1081153790Sobrien	S24C16_write_byte(np, &ack_data,
1081253790Sobrien		0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
1081353790Sobrien	if (ack_data & 0x01)
1081453790Sobrien		goto out;
1081553790Sobrien
1081653790Sobrien	/* write random address LSB */
1081753790Sobrien	S24C16_write_byte(np, &ack_data,
1081855300Sgroudier		offset & 0xff, &gpreg, &gpcntl);
1081953790Sobrien	if (ack_data & 0x01)
1082053790Sobrien		goto out;
1082153790Sobrien
1082253790Sobrien	/* regenerate START state to set up for reading */
1082353790Sobrien	S24C16_start(np, &gpreg);
1082453790Sobrien
1082553790Sobrien	/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
1082653790Sobrien	S24C16_write_byte(np, &ack_data,
1082753790Sobrien		0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
1082853790Sobrien	if (ack_data & 0x01)
1082953790Sobrien		goto out;
1083053790Sobrien
1083153790Sobrien	/* now set up GPIO0 for inputting data */
1083253790Sobrien	gpcntl |= 0x01;
1083353790Sobrien	OUTB (nc_gpcntl, gpcntl);
1083453790Sobrien
1083553790Sobrien	/* input all requested data - only part of total NVRAM */
1083653790Sobrien	for (x = 0; x < len; x++)
1083753790Sobrien		S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
1083853790Sobrien
1083953790Sobrien	/* finally put NVRAM back in inactive mode */
1084053790Sobrien	gpcntl &= 0xfe;
1084153790Sobrien	OUTB (nc_gpcntl, gpcntl);
1084253790Sobrien	S24C16_stop(np, &gpreg);
1084353790Sobrien	retv = 0;
1084453790Sobrienout:
1084553790Sobrien	/* return GPIO0/1 to original states after having accessed NVRAM */
1084653790Sobrien	OUTB (nc_gpcntl, old_gpcntl);
1084753790Sobrien	OUTB (nc_gpreg,  old_gpreg);
1084853790Sobrien
1084953790Sobrien	return retv;
1085053790Sobrien}
1085153790Sobrien
1085253790Sobrien#undef SET_BIT 0
1085353790Sobrien#undef CLR_BIT 1
1085453790Sobrien#undef SET_CLK 2
1085553790Sobrien#undef CLR_CLK 3
1085653790Sobrien
1085753790Sobrien/*
1085853790Sobrien *  Try reading Symbios NVRAM.
1085953790Sobrien *  Return 0 if OK.
1086053790Sobrien */
1086153790Sobrienstatic int sym_read_Symbios_nvram (hcb_p np, Symbios_nvram *nvram)
1086253790Sobrien{
1086353790Sobrien	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
1086453790Sobrien	u_char *data = (u_char *) nvram;
1086553790Sobrien	int len  = sizeof(*nvram);
1086653790Sobrien	u_short	csum;
1086753790Sobrien	int x;
1086853790Sobrien
1086953790Sobrien	/* probe the 24c16 and read the SYMBIOS 24c16 area */
1087053790Sobrien	if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
1087153790Sobrien		return 1;
1087253790Sobrien
1087353790Sobrien	/* check valid NVRAM signature, verify byte count and checksum */
1087453790Sobrien	if (nvram->type != 0 ||
1087553796Sobrien	    bcmp(nvram->trailer, Symbios_trailer, 6) ||
1087653790Sobrien	    nvram->byte_count != len - 12)
1087753790Sobrien		return 1;
1087853790Sobrien
1087953790Sobrien	/* verify checksum */
1088053790Sobrien	for (x = 6, csum = 0; x < len - 6; x++)
1088153790Sobrien		csum += data[x];
1088253790Sobrien	if (csum != nvram->checksum)
1088353790Sobrien		return 1;
1088453790Sobrien
1088553790Sobrien	return 0;
1088653790Sobrien}
1088753790Sobrien
1088853790Sobrien/*
1088953790Sobrien *  93C46 EEPROM reading.
1089053790Sobrien *
1089153790Sobrien *  GPOI0 - data in
1089253790Sobrien *  GPIO1 - data out
1089353790Sobrien *  GPIO2 - clock
1089453790Sobrien *  GPIO4 - chip select
1089553790Sobrien *
1089653790Sobrien *  Used by Tekram.
1089753790Sobrien */
1089853790Sobrien
1089953790Sobrien/*
1090053790Sobrien *  Pulse clock bit in GPIO0
1090153790Sobrien */
1090253790Sobrienstatic void T93C46_Clk(hcb_p np, u_char *gpreg)
1090353790Sobrien{
1090453790Sobrien	OUTB (nc_gpreg, *gpreg | 0x04);
1090553790Sobrien	UDELAY (2);
1090653790Sobrien	OUTB (nc_gpreg, *gpreg);
1090753790Sobrien}
1090853790Sobrien
1090953790Sobrien/*
1091053790Sobrien *  Read bit from NVRAM
1091153790Sobrien */
1091253790Sobrienstatic void T93C46_Read_Bit(hcb_p np, u_char *read_bit, u_char *gpreg)
1091353790Sobrien{
1091453790Sobrien	UDELAY (2);
1091553790Sobrien	T93C46_Clk(np, gpreg);
1091653790Sobrien	*read_bit = INB (nc_gpreg);
1091753790Sobrien}
1091853790Sobrien
1091953790Sobrien/*
1092053790Sobrien *  Write bit to GPIO0
1092153790Sobrien */
1092253790Sobrienstatic void T93C46_Write_Bit(hcb_p np, u_char write_bit, u_char *gpreg)
1092353790Sobrien{
1092453790Sobrien	if (write_bit & 0x01)
1092553790Sobrien		*gpreg |= 0x02;
1092653790Sobrien	else
1092753790Sobrien		*gpreg &= 0xfd;
1092853790Sobrien
1092953790Sobrien	*gpreg |= 0x10;
1093053790Sobrien
1093153790Sobrien	OUTB (nc_gpreg, *gpreg);
1093253790Sobrien	UDELAY (2);
1093353790Sobrien
1093453790Sobrien	T93C46_Clk(np, gpreg);
1093553790Sobrien}
1093653790Sobrien
1093753790Sobrien/*
1093853790Sobrien *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
1093953790Sobrien */
1094053790Sobrienstatic void T93C46_Stop(hcb_p np, u_char *gpreg)
1094153790Sobrien{
1094253790Sobrien	*gpreg &= 0xef;
1094353790Sobrien	OUTB (nc_gpreg, *gpreg);
1094453790Sobrien	UDELAY (2);
1094553790Sobrien
1094653790Sobrien	T93C46_Clk(np, gpreg);
1094753790Sobrien}
1094853790Sobrien
1094953790Sobrien/*
1095053790Sobrien *  Send read command and address to NVRAM
1095153790Sobrien */
1095253790Sobrienstatic void T93C46_Send_Command(hcb_p np, u_short write_data,
1095353790Sobrien				u_char *read_bit, u_char *gpreg)
1095453790Sobrien{
1095553790Sobrien	int x;
1095653790Sobrien
1095753790Sobrien	/* send 9 bits, start bit (1), command (2), address (6)  */
1095853790Sobrien	for (x = 0; x < 9; x++)
1095953790Sobrien		T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
1096053790Sobrien
1096153790Sobrien	*read_bit = INB (nc_gpreg);
1096253790Sobrien}
1096353790Sobrien
1096453790Sobrien/*
1096553790Sobrien *  READ 2 bytes from the NVRAM
1096653790Sobrien */
1096753790Sobrienstatic void T93C46_Read_Word(hcb_p np, u_short *nvram_data, u_char *gpreg)
1096853790Sobrien{
1096953790Sobrien	int x;
1097053790Sobrien	u_char read_bit;
1097153790Sobrien
1097253790Sobrien	*nvram_data = 0;
1097353790Sobrien	for (x = 0; x < 16; x++) {
1097453790Sobrien		T93C46_Read_Bit(np, &read_bit, gpreg);
1097553790Sobrien
1097653790Sobrien		if (read_bit & 0x01)
1097753790Sobrien			*nvram_data |=  (0x01 << (15 - x));
1097853790Sobrien		else
1097953790Sobrien			*nvram_data &= ~(0x01 << (15 - x));
1098053790Sobrien	}
1098153790Sobrien}
1098253790Sobrien
1098353790Sobrien/*
1098453790Sobrien *  Read Tekram NvRAM data.
1098553790Sobrien */
1098653790Sobrienstatic int T93C46_Read_Data(hcb_p np, u_short *data,int len,u_char *gpreg)
1098753790Sobrien{
1098853790Sobrien	u_char	read_bit;
1098953790Sobrien	int	x;
1099053790Sobrien
1099153790Sobrien	for (x = 0; x < len; x++)  {
1099253790Sobrien
1099353790Sobrien		/* output read command and address */
1099453790Sobrien		T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
1099553790Sobrien		if (read_bit & 0x01)
1099653790Sobrien			return 1; /* Bad */
1099753790Sobrien		T93C46_Read_Word(np, &data[x], gpreg);
1099853790Sobrien		T93C46_Stop(np, gpreg);
1099953790Sobrien	}
1100053790Sobrien
1100153790Sobrien	return 0;
1100253790Sobrien}
1100353790Sobrien
1100453790Sobrien/*
1100553790Sobrien *  Try reading 93C46 Tekram NVRAM.
1100653790Sobrien */
1100753790Sobrienstatic int sym_read_T93C46_nvram (hcb_p np, Tekram_nvram *nvram)
1100853790Sobrien{
1100953790Sobrien	u_char gpcntl, gpreg;
1101053790Sobrien	u_char old_gpcntl, old_gpreg;
1101153790Sobrien	int retv = 1;
1101253790Sobrien
1101353790Sobrien	/* save current state of GPCNTL and GPREG */
1101453790Sobrien	old_gpreg	= INB (nc_gpreg);
1101553790Sobrien	old_gpcntl	= INB (nc_gpcntl);
1101653790Sobrien
1101753790Sobrien	/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
1101853790Sobrien	   1/2/4 out */
1101953790Sobrien	gpreg = old_gpreg & 0xe9;
1102053790Sobrien	OUTB (nc_gpreg, gpreg);
1102153790Sobrien	gpcntl = (old_gpcntl & 0xe9) | 0x09;
1102253790Sobrien	OUTB (nc_gpcntl, gpcntl);
1102353790Sobrien
1102453790Sobrien	/* input all of NVRAM, 64 words */
1102553790Sobrien	retv = T93C46_Read_Data(np, (u_short *) nvram,
1102653790Sobrien				sizeof(*nvram) / sizeof(short), &gpreg);
1102753790Sobrien
1102853790Sobrien	/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
1102953790Sobrien	OUTB (nc_gpcntl, old_gpcntl);
1103053790Sobrien	OUTB (nc_gpreg,  old_gpreg);
1103153790Sobrien
1103253790Sobrien	return retv;
1103353790Sobrien}
1103453790Sobrien
1103553790Sobrien/*
1103653790Sobrien *  Try reading Tekram NVRAM.
1103753790Sobrien *  Return 0 if OK.
1103853790Sobrien */
1103953790Sobrienstatic int sym_read_Tekram_nvram (hcb_p np, Tekram_nvram *nvram)
1104053790Sobrien{
1104153790Sobrien	u_char *data = (u_char *) nvram;
1104253790Sobrien	int len = sizeof(*nvram);
1104353790Sobrien	u_short	csum;
1104453790Sobrien	int x;
1104553790Sobrien
1104653790Sobrien	switch (np->device_id) {
1104753790Sobrien	case PCI_ID_SYM53C885:
1104853790Sobrien	case PCI_ID_SYM53C895:
1104953790Sobrien	case PCI_ID_SYM53C896:
1105053790Sobrien		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
1105153790Sobrien					  data, len);
1105253790Sobrien		break;
1105353790Sobrien	case PCI_ID_SYM53C875:
1105453790Sobrien		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
1105553790Sobrien					  data, len);
1105653790Sobrien		if (!x)
1105753790Sobrien			break;
1105853790Sobrien	default:
1105953790Sobrien		x = sym_read_T93C46_nvram(np, nvram);
1106053790Sobrien		break;
1106153790Sobrien	}
1106253790Sobrien	if (x)
1106353790Sobrien		return 1;
1106453790Sobrien
1106553790Sobrien	/* verify checksum */
1106653790Sobrien	for (x = 0, csum = 0; x < len - 1; x += 2)
1106753790Sobrien		csum += data[x] + (data[x+1] << 8);
1106853790Sobrien	if (csum != 0x1234)
1106953790Sobrien		return 1;
1107053790Sobrien
1107153790Sobrien	return 0;
1107253790Sobrien}
1107353790Sobrien
1107454690Sobrien#endif	/* SYM_CONF_NVRAM_SUPPORT */
11075