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, ®s_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, ®s_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, ®s_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