1119420Sobrien/*- 2178466Smarius * Device driver optimized for the Symbios/LSI 53C896/53C895A/53C1010 353790Sobrien * PCI-SCSI controllers. 453790Sobrien * 586266Sgroudier * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> 653790Sobrien * 753790Sobrien * This driver also supports the following Symbios/LSI PCI-SCSI chips: 859743Sgroudier * 53C810A, 53C825A, 53C860, 53C875, 53C876, 53C885, 53C895, 959743Sgroudier * 53C810, 53C815, 53C825 and the 53C1510D is 53C8XX mode. 1053790Sobrien * 11178466Smarius * 1253790Sobrien * This driver for FreeBSD-CAM is derived from the Linux sym53c8xx driver. 1353790Sobrien * Copyright (C) 1998-1999 Gerard Roudier 1453790Sobrien * 15178466Smarius * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 1653790Sobrien * a port of the FreeBSD ncr driver to Linux-1.2.13. 1753790Sobrien * 1853790Sobrien * The original ncr driver has been written for 386bsd and FreeBSD by 1953790Sobrien * Wolfgang Stanglmeier <wolf@cologne.de> 2053790Sobrien * Stefan Esser <se@mi.Uni-Koeln.de> 2153790Sobrien * Copyright (C) 1994 Wolfgang Stanglmeier 2253790Sobrien * 23178466Smarius * The initialisation code, and part of the code that addresses 24178466Smarius * FreeBSD-CAM services is based on the aic7xxx driver for FreeBSD-CAM 2553790Sobrien * written by Justin T. Gibbs. 2653790Sobrien * 2753790Sobrien * Other major contributions: 2853790Sobrien * 2953790Sobrien * NVRAM detection and reading. 3053790Sobrien * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> 3153790Sobrien * 3253790Sobrien *----------------------------------------------------------------------------- 3353790Sobrien * 3453790Sobrien * Redistribution and use in source and binary forms, with or without 3553790Sobrien * modification, are permitted provided that the following conditions 3653790Sobrien * are met: 3753790Sobrien * 1. Redistributions of source code must retain the above copyright 3853790Sobrien * notice, this list of conditions and the following disclaimer. 3953790Sobrien * 2. Redistributions in binary form must reproduce the above copyright 4053790Sobrien * notice, this list of conditions and the following disclaimer in the 4153790Sobrien * documentation and/or other materials provided with the distribution. 4253790Sobrien * 3. The name of the author may not be used to endorse or promote products 4353790Sobrien * derived from this software without specific prior written permission. 4453790Sobrien * 4553790Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 4653790Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4753790Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4853790Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 4953790Sobrien * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5053790Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5153790Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5253790Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5353790Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5453790Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5553790Sobrien * SUCH DAMAGE. 5653790Sobrien */ 5753790Sobrien 58119420Sobrien#include <sys/cdefs.h> 59119420Sobrien__FBSDID("$FreeBSD$"); 6055258Sobrien 6165404Sgroudier#define SYM_DRIVER_NAME "sym-1.6.5-20000902" 6253790Sobrien 6360134Sgroudier/* #define SYM_DEBUG_GENERIC_SUPPORT */ 6460134Sgroudier 6561429Sgroudier#include <sys/param.h> 6653790Sobrien 6753790Sobrien/* 6861429Sgroudier * Driver configuration options. 6961429Sgroudier */ 7061429Sgroudier#include "opt_sym.h" 7161429Sgroudier#include <dev/sym/sym_conf.h> 7261429Sgroudier 7353790Sobrien#include <sys/systm.h> 7453790Sobrien#include <sys/malloc.h> 7595533Smike#include <sys/endian.h> 7653790Sobrien#include <sys/kernel.h> 77117126Sscottl#include <sys/lock.h> 78117126Sscottl#include <sys/mutex.h> 7953790Sobrien#include <sys/module.h> 8053790Sobrien#include <sys/bus.h> 8153790Sobrien 8253790Sobrien#include <sys/proc.h> 8353790Sobrien 84119287Simp#include <dev/pci/pcireg.h> 85119287Simp#include <dev/pci/pcivar.h> 8653790Sobrien 8753790Sobrien#include <machine/bus.h> 8853790Sobrien#include <machine/resource.h> 89207285Smarius 90207285Smarius#ifdef __sparc64__ 91207285Smarius#include <dev/ofw/openfirm.h> 92207285Smarius#include <machine/ofw_machdep.h> 93207285Smarius#endif 94207285Smarius 9553790Sobrien#include <sys/rman.h> 9653790Sobrien 9753790Sobrien#include <cam/cam.h> 9853790Sobrien#include <cam/cam_ccb.h> 9953790Sobrien#include <cam/cam_sim.h> 10053790Sobrien#include <cam/cam_xpt_sim.h> 10153790Sobrien#include <cam/cam_debug.h> 10253790Sobrien 10353790Sobrien#include <cam/scsi/scsi_all.h> 10453790Sobrien#include <cam/scsi/scsi_message.h> 10553790Sobrien 10653790Sobrien/* Short and quite clear integer types */ 10753790Sobrientypedef int8_t s8; 10853790Sobrientypedef int16_t s16; 10953790Sobrientypedef int32_t s32; 11053790Sobrientypedef u_int8_t u8; 11153790Sobrientypedef u_int16_t u16; 11253790Sobrientypedef u_int32_t u32; 11353790Sobrien 11461429Sgroudier/* 11561429Sgroudier * Driver definitions. 11661429Sgroudier */ 11753799Sobrien#include <dev/sym/sym_defs.h> 11859743Sgroudier#include <dev/sym/sym_fw.h> 11953790Sobrien 12053790Sobrien/* 12161429Sgroudier * IA32 architecture does not reorder STORES and prevents 122178466Smarius * LOADS from passing STORES. It is called `program order' 123178466Smarius * by Intel and allows device drivers to deal with memory 124178466Smarius * ordering by only ensuring that the code is not reordered 12561429Sgroudier * by the compiler when ordering is required. 126178466Smarius * Other architectures implement a weaker ordering that 127178466Smarius * requires memory barriers (and also IO barriers when they 12861429Sgroudier * make sense) to be used. 12953790Sobrien */ 130116857Speter#if defined __i386__ || defined __amd64__ 13161429Sgroudier#define MEMORY_BARRIER() do { ; } while(0) 13261429Sgroudier#elif defined __powerpc__ 13361429Sgroudier#define MEMORY_BARRIER() __asm__ volatile("eieio; sync" : : : "memory") 13461429Sgroudier#elif defined __ia64__ 13561429Sgroudier#define MEMORY_BARRIER() __asm__ volatile("mf.a; mf" : : : "memory") 13661429Sgroudier#elif defined __sparc64__ 13786850Sgroudier#define MEMORY_BARRIER() __asm__ volatile("membar #Sync" : : : "memory") 13861429Sgroudier#else 13961429Sgroudier#error "Not supported platform" 14053793Sobrien#endif 14153790Sobrien 14253790Sobrien/* 14353790Sobrien * A la VMS/CAM-3 queue management. 14453790Sobrien */ 14553790Sobrientypedef struct sym_quehead { 14653790Sobrien struct sym_quehead *flink; /* Forward pointer */ 14753790Sobrien struct sym_quehead *blink; /* Backward pointer */ 14853790Sobrien} SYM_QUEHEAD; 14953790Sobrien 15053790Sobrien#define sym_que_init(ptr) do { \ 15153790Sobrien (ptr)->flink = (ptr); (ptr)->blink = (ptr); \ 15253790Sobrien} while (0) 15353790Sobrien 15453790Sobrienstatic __inline void __sym_que_add(struct sym_quehead * new, 15553790Sobrien struct sym_quehead * blink, 15653790Sobrien struct sym_quehead * flink) 15753790Sobrien{ 15853790Sobrien flink->blink = new; 15953790Sobrien new->flink = flink; 16053790Sobrien new->blink = blink; 16153790Sobrien blink->flink = new; 16253790Sobrien} 16353790Sobrien 16453790Sobrienstatic __inline void __sym_que_del(struct sym_quehead * blink, 16553790Sobrien struct sym_quehead * flink) 16653790Sobrien{ 16753790Sobrien flink->blink = blink; 16853790Sobrien blink->flink = flink; 16953790Sobrien} 17053790Sobrien 17153790Sobrienstatic __inline int sym_que_empty(struct sym_quehead *head) 17253790Sobrien{ 17353790Sobrien return head->flink == head; 17453790Sobrien} 17553790Sobrien 17653790Sobrienstatic __inline void sym_que_splice(struct sym_quehead *list, 17753790Sobrien struct sym_quehead *head) 17853790Sobrien{ 17953790Sobrien struct sym_quehead *first = list->flink; 18053790Sobrien 18153790Sobrien if (first != list) { 18253790Sobrien struct sym_quehead *last = list->blink; 18353790Sobrien struct sym_quehead *at = head->flink; 18453790Sobrien 18553790Sobrien first->blink = head; 18653790Sobrien head->flink = first; 18753790Sobrien 18853790Sobrien last->flink = at; 18953790Sobrien at->blink = last; 19053790Sobrien } 19153790Sobrien} 19253790Sobrien 19353790Sobrien#define sym_que_entry(ptr, type, member) \ 194170996Smjacob ((type *)((char *)(ptr)-(size_t)(&((type *)0)->member))) 19553790Sobrien 19653790Sobrien#define sym_insque(new, pos) __sym_que_add(new, pos, (pos)->flink) 19753790Sobrien 19853790Sobrien#define sym_remque(el) __sym_que_del((el)->blink, (el)->flink) 19953790Sobrien 20053790Sobrien#define sym_insque_head(new, head) __sym_que_add(new, head, (head)->flink) 20153790Sobrien 20253790Sobrienstatic __inline struct sym_quehead *sym_remque_head(struct sym_quehead *head) 20353790Sobrien{ 20453790Sobrien struct sym_quehead *elem = head->flink; 20553790Sobrien 20653790Sobrien if (elem != head) 20753790Sobrien __sym_que_del(head, elem->flink); 20853790Sobrien else 209178466Smarius elem = NULL; 21053790Sobrien return elem; 21153790Sobrien} 21253790Sobrien 21353790Sobrien#define sym_insque_tail(new, head) __sym_que_add(new, (head)->blink, head) 21453790Sobrien 21553790Sobrien/* 21662422Sgroudier * This one may be useful. 21753790Sobrien */ 21853790Sobrien#define FOR_EACH_QUEUED_ELEMENT(head, qp) \ 21953790Sobrien for (qp = (head)->flink; qp != (head); qp = qp->flink) 22053790Sobrien/* 22153790Sobrien * FreeBSD does not offer our kind of queue in the CAM CCB. 22253790Sobrien * So, we have to cast. 22353790Sobrien */ 22453790Sobrien#define sym_qptr(p) ((struct sym_quehead *) (p)) 22553790Sobrien 22653790Sobrien/* 22753790Sobrien * Simple bitmap operations. 228178466Smarius */ 22953790Sobrien#define sym_set_bit(p, n) (((u32 *)(p))[(n)>>5] |= (1<<((n)&0x1f))) 23053790Sobrien#define sym_clr_bit(p, n) (((u32 *)(p))[(n)>>5] &= ~(1<<((n)&0x1f))) 23153790Sobrien#define sym_is_bit(p, n) (((u32 *)(p))[(n)>>5] & (1<<((n)&0x1f))) 23253790Sobrien 23353790Sobrien/* 23453790Sobrien * Number of tasks per device we want to handle. 23553790Sobrien */ 23654690Sobrien#if SYM_CONF_MAX_TAG_ORDER > 8 23753790Sobrien#error "more than 256 tags per logical unit not allowed." 23853790Sobrien#endif 23954690Sobrien#define SYM_CONF_MAX_TASK (1<<SYM_CONF_MAX_TAG_ORDER) 24053790Sobrien 24153790Sobrien/* 24253790Sobrien * Donnot use more tasks that we can handle. 24353790Sobrien */ 24454690Sobrien#ifndef SYM_CONF_MAX_TAG 24554690Sobrien#define SYM_CONF_MAX_TAG SYM_CONF_MAX_TASK 24653790Sobrien#endif 24754690Sobrien#if SYM_CONF_MAX_TAG > SYM_CONF_MAX_TASK 24854690Sobrien#undef SYM_CONF_MAX_TAG 24954690Sobrien#define SYM_CONF_MAX_TAG SYM_CONF_MAX_TASK 25053790Sobrien#endif 25153790Sobrien 25253790Sobrien/* 25353790Sobrien * This one means 'NO TAG for this job' 25453790Sobrien */ 25553790Sobrien#define NO_TAG (256) 25653790Sobrien 25753790Sobrien/* 25853790Sobrien * Number of SCSI targets. 25953790Sobrien */ 26054690Sobrien#if SYM_CONF_MAX_TARGET > 16 26153790Sobrien#error "more than 16 targets not allowed." 26253790Sobrien#endif 26353790Sobrien 26453790Sobrien/* 26553790Sobrien * Number of logical units per target. 26653790Sobrien */ 26754690Sobrien#if SYM_CONF_MAX_LUN > 64 26853790Sobrien#error "more than 64 logical units per target not allowed." 26953790Sobrien#endif 27053790Sobrien 27153790Sobrien/* 272178466Smarius * Asynchronous pre-scaler (ns). Shall be 40 for 27353790Sobrien * the SCSI timings to be compliant. 27453790Sobrien */ 27554690Sobrien#define SYM_CONF_MIN_ASYNC (40) 27653790Sobrien 27753790Sobrien/* 27853790Sobrien * Number of entries in the START and DONE queues. 27953790Sobrien * 280178466Smarius * We limit to 1 PAGE in order to succeed allocation of 28153790Sobrien * these queues. Each entry is 8 bytes long (2 DWORDS). 28253790Sobrien */ 28354690Sobrien#ifdef SYM_CONF_MAX_START 28454690Sobrien#define SYM_CONF_MAX_QUEUE (SYM_CONF_MAX_START+2) 28553790Sobrien#else 28654690Sobrien#define SYM_CONF_MAX_QUEUE (7*SYM_CONF_MAX_TASK+2) 28754690Sobrien#define SYM_CONF_MAX_START (SYM_CONF_MAX_QUEUE-2) 28853790Sobrien#endif 28953790Sobrien 29054690Sobrien#if SYM_CONF_MAX_QUEUE > PAGE_SIZE/8 29154690Sobrien#undef SYM_CONF_MAX_QUEUE 29254690Sobrien#define SYM_CONF_MAX_QUEUE PAGE_SIZE/8 29354690Sobrien#undef SYM_CONF_MAX_START 29454690Sobrien#define SYM_CONF_MAX_START (SYM_CONF_MAX_QUEUE-2) 29553790Sobrien#endif 29653790Sobrien 29753790Sobrien/* 29853790Sobrien * For this one, we want a short name :-) 29953790Sobrien */ 30054690Sobrien#define MAX_QUEUE SYM_CONF_MAX_QUEUE 30153790Sobrien 30253790Sobrien/* 30353790Sobrien * Active debugging tags and verbosity. 30453790Sobrien */ 30553790Sobrien#define DEBUG_ALLOC (0x0001) 30653790Sobrien#define DEBUG_PHASE (0x0002) 30753790Sobrien#define DEBUG_POLL (0x0004) 30853790Sobrien#define DEBUG_QUEUE (0x0008) 30953790Sobrien#define DEBUG_RESULT (0x0010) 31053790Sobrien#define DEBUG_SCATTER (0x0020) 31153790Sobrien#define DEBUG_SCRIPT (0x0040) 31253790Sobrien#define DEBUG_TINY (0x0080) 31353790Sobrien#define DEBUG_TIMING (0x0100) 31453790Sobrien#define DEBUG_NEGO (0x0200) 31553790Sobrien#define DEBUG_TAGS (0x0400) 31653790Sobrien#define DEBUG_POINTER (0x0800) 31753790Sobrien 31853790Sobrien#if 0 31953790Sobrienstatic int sym_debug = 0; 32053790Sobrien #define DEBUG_FLAGS sym_debug 32153790Sobrien#else 32253790Sobrien/* #define DEBUG_FLAGS (0x0631) */ 32354690Sobrien #define DEBUG_FLAGS (0x0000) 32458927Sgroudier 32553790Sobrien#endif 32653790Sobrien#define sym_verbose (np->verbose) 32753790Sobrien 32853790Sobrien/* 32953790Sobrien * Insert a delay in micro-seconds and milli-seconds. 33053790Sobrien */ 33161051Sgroudierstatic void UDELAY(int us) { DELAY(us); } 33261051Sgroudierstatic void MDELAY(int ms) { while (ms--) UDELAY(1000); } 33353790Sobrien 33453790Sobrien/* 33553790Sobrien * Simple power of two buddy-like allocator. 33653790Sobrien * 337178466Smarius * This simple code is not intended to be fast, but to 33853790Sobrien * provide power of 2 aligned memory allocations. 339178466Smarius * Since the SCRIPTS processor only supplies 8 bit arithmetic, 340178466Smarius * this allocator allows simple and fast address calculations 341178466Smarius * from the SCRIPTS code. In addition, cache line alignment 34253790Sobrien * is guaranteed for power of 2 cache line size. 34353790Sobrien * 344220944Smarius * This allocator has been developed for the Linux sym53c8xx 345178466Smarius * driver, since this O/S does not provide naturally aligned 34653790Sobrien * allocations. 347178466Smarius * It has the advantage of allowing the driver to use private 348178466Smarius * pages of memory that will be useful if we ever need to deal 34962422Sgroudier * with IO MMUs for PCI. 35053790Sobrien */ 35153790Sobrien#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ 35258927Sgroudier#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */ 35353790Sobrien#if 0 35453790Sobrien#define MEMO_FREE_UNUSED /* Free unused pages immediately */ 35553790Sobrien#endif 35658927Sgroudier#define MEMO_WARN 1 35758927Sgroudier#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER) 35858927Sgroudier#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT) 35958927Sgroudier#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1) 36053790Sobrien 36158927Sgroudier#define get_pages() malloc(MEMO_CLUSTER_SIZE, M_DEVBUF, M_NOWAIT) 36258927Sgroudier#define free_pages(p) free((p), M_DEVBUF) 36353790Sobrien 36458927Sgroudiertypedef u_long m_addr_t; /* Enough bits to bit-hack addresses */ 36558927Sgroudier 36658927Sgroudiertypedef struct m_link { /* Link between free memory chunks */ 36758927Sgroudier struct m_link *next; 36858927Sgroudier} m_link_s; 36958927Sgroudier 37058927Sgroudiertypedef struct m_vtob { /* Virtual to Bus address translation */ 37158927Sgroudier struct m_vtob *next; 37258927Sgroudier bus_dmamap_t dmamap; /* Map for this chunk */ 37358927Sgroudier m_addr_t vaddr; /* Virtual address */ 37458927Sgroudier m_addr_t baddr; /* Bus physical address */ 37558927Sgroudier} m_vtob_s; 37658927Sgroudier/* Hash this stuff a bit to speed up translations */ 37758927Sgroudier#define VTOB_HASH_SHIFT 5 37858927Sgroudier#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT) 37958927Sgroudier#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1) 38058927Sgroudier#define VTOB_HASH_CODE(m) \ 38158927Sgroudier ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK) 38253790Sobrien 38358927Sgroudiertypedef struct m_pool { /* Memory pool of a given kind */ 38458927Sgroudier bus_dma_tag_t dev_dmat; /* Identifies the pool */ 38558927Sgroudier bus_dma_tag_t dmat; /* Tag for our fixed allocations */ 38658927Sgroudier m_addr_t (*getp)(struct m_pool *); 38758927Sgroudier#ifdef MEMO_FREE_UNUSED 38858927Sgroudier void (*freep)(struct m_pool *, m_addr_t); 38958927Sgroudier#endif 39058927Sgroudier#define M_GETP() mp->getp(mp) 39158927Sgroudier#define M_FREEP(p) mp->freep(mp, p) 39258927Sgroudier int nump; 39358927Sgroudier m_vtob_s *(vtob[VTOB_HASH_SIZE]); 39458927Sgroudier struct m_pool *next; 39558927Sgroudier struct m_link h[MEMO_CLUSTER_SHIFT - MEMO_SHIFT + 1]; 39658927Sgroudier} m_pool_s; 39753790Sobrien 39858927Sgroudierstatic void *___sym_malloc(m_pool_s *mp, int size) 39953790Sobrien{ 40053790Sobrien int i = 0; 40153790Sobrien int s = (1 << MEMO_SHIFT); 40253790Sobrien int j; 40358927Sgroudier m_addr_t a; 40458927Sgroudier m_link_s *h = mp->h; 40553790Sobrien 40658927Sgroudier if (size > MEMO_CLUSTER_SIZE) 407178466Smarius return NULL; 40853790Sobrien 40953790Sobrien while (size > s) { 41053790Sobrien s <<= 1; 41153790Sobrien ++i; 41253790Sobrien } 41353790Sobrien 41453790Sobrien j = i; 41553790Sobrien while (!h[j].next) { 41658927Sgroudier if (s == MEMO_CLUSTER_SIZE) { 41758927Sgroudier h[j].next = (m_link_s *) M_GETP(); 41853790Sobrien if (h[j].next) 419178466Smarius h[j].next->next = NULL; 42053790Sobrien break; 42153790Sobrien } 42253790Sobrien ++j; 42353790Sobrien s <<= 1; 42453790Sobrien } 42558927Sgroudier a = (m_addr_t) h[j].next; 42653790Sobrien if (a) { 42753790Sobrien h[j].next = h[j].next->next; 42853790Sobrien while (j > i) { 42953790Sobrien j -= 1; 43053790Sobrien s >>= 1; 43158927Sgroudier h[j].next = (m_link_s *) (a+s); 432178466Smarius h[j].next->next = NULL; 43353790Sobrien } 43453790Sobrien } 43553790Sobrien#ifdef DEBUG 43658927Sgroudier printf("___sym_malloc(%d) = %p\n", size, (void *) a); 43753790Sobrien#endif 43853790Sobrien return (void *) a; 43953790Sobrien} 44053790Sobrien 44158927Sgroudierstatic void ___sym_mfree(m_pool_s *mp, void *ptr, int size) 44253790Sobrien{ 44353790Sobrien int i = 0; 44453790Sobrien int s = (1 << MEMO_SHIFT); 44558927Sgroudier m_link_s *q; 44658927Sgroudier m_addr_t a, b; 44758927Sgroudier m_link_s *h = mp->h; 44853790Sobrien 44953790Sobrien#ifdef DEBUG 45058927Sgroudier printf("___sym_mfree(%p, %d)\n", ptr, size); 45153790Sobrien#endif 45253790Sobrien 45358927Sgroudier if (size > MEMO_CLUSTER_SIZE) 45453790Sobrien return; 45553790Sobrien 45653790Sobrien while (size > s) { 45753790Sobrien s <<= 1; 45853790Sobrien ++i; 45953790Sobrien } 46053790Sobrien 46158927Sgroudier a = (m_addr_t) ptr; 46253790Sobrien 46353790Sobrien while (1) { 46453790Sobrien#ifdef MEMO_FREE_UNUSED 46558927Sgroudier if (s == MEMO_CLUSTER_SIZE) { 46658927Sgroudier M_FREEP(a); 46753790Sobrien break; 46853790Sobrien } 46953790Sobrien#endif 47053790Sobrien b = a ^ s; 47153790Sobrien q = &h[i]; 47258927Sgroudier while (q->next && q->next != (m_link_s *) b) { 47353790Sobrien q = q->next; 47453790Sobrien } 47553790Sobrien if (!q->next) { 47658927Sgroudier ((m_link_s *) a)->next = h[i].next; 47758927Sgroudier h[i].next = (m_link_s *) a; 47853790Sobrien break; 47953790Sobrien } 48053790Sobrien q->next = q->next->next; 48153790Sobrien a = a & b; 48253790Sobrien s <<= 1; 48353790Sobrien ++i; 48453790Sobrien } 48553790Sobrien} 48653790Sobrien 48758927Sgroudierstatic void *__sym_calloc2(m_pool_s *mp, int size, char *name, int uflags) 48853790Sobrien{ 48953790Sobrien void *p; 49053790Sobrien 49158927Sgroudier p = ___sym_malloc(mp, size); 49253790Sobrien 49353790Sobrien if (DEBUG_FLAGS & DEBUG_ALLOC) 49453790Sobrien printf ("new %-10s[%4d] @%p.\n", name, size, p); 49553790Sobrien 49653790Sobrien if (p) 49753790Sobrien bzero(p, size); 49853790Sobrien else if (uflags & MEMO_WARN) 49958927Sgroudier printf ("__sym_calloc2: failed to allocate %s[%d]\n", name, size); 50053790Sobrien 50153790Sobrien return p; 50253790Sobrien} 50353790Sobrien 50458927Sgroudier#define __sym_calloc(mp, s, n) __sym_calloc2(mp, s, n, MEMO_WARN) 50553790Sobrien 50658927Sgroudierstatic void __sym_mfree(m_pool_s *mp, void *ptr, int size, char *name) 50753790Sobrien{ 50853790Sobrien if (DEBUG_FLAGS & DEBUG_ALLOC) 50953790Sobrien printf ("freeing %-10s[%4d] @%p.\n", name, size, ptr); 51053790Sobrien 51158927Sgroudier ___sym_mfree(mp, ptr, size); 51258927Sgroudier 51353790Sobrien} 51453790Sobrien 51553790Sobrien/* 51658927Sgroudier * Default memory pool we donnot need to involve in DMA. 51758927Sgroudier */ 51858927Sgroudier/* 519178466Smarius * With the `bus dma abstraction', we use a separate pool for 52058927Sgroudier * memory we donnot need to involve in DMA. 52158927Sgroudier */ 52258927Sgroudierstatic m_addr_t ___mp0_getp(m_pool_s *mp) 52358927Sgroudier{ 52458927Sgroudier m_addr_t m = (m_addr_t) get_pages(); 52558927Sgroudier if (m) 52658927Sgroudier ++mp->nump; 52758927Sgroudier return m; 52858927Sgroudier} 52958927Sgroudier 53058927Sgroudier#ifdef MEMO_FREE_UNUSED 53158927Sgroudierstatic void ___mp0_freep(m_pool_s *mp, m_addr_t m) 53258927Sgroudier{ 53358927Sgroudier free_pages(m); 53458927Sgroudier --mp->nump; 53558927Sgroudier} 53658927Sgroudier#endif 53758927Sgroudier 53858927Sgroudier#ifdef MEMO_FREE_UNUSED 53958927Sgroudierstatic m_pool_s mp0 = {0, 0, ___mp0_getp, ___mp0_freep}; 54058927Sgroudier#else 54158927Sgroudierstatic m_pool_s mp0 = {0, 0, ___mp0_getp}; 54258927Sgroudier#endif 54358927Sgroudier 54458927Sgroudier/* 54558927Sgroudier * Actual memory allocation routine for non-DMAed memory. 54658927Sgroudier */ 54758927Sgroudierstatic void *sym_calloc(int size, char *name) 54858927Sgroudier{ 54958927Sgroudier void *m; 55058927Sgroudier /* Lock */ 55158927Sgroudier m = __sym_calloc(&mp0, size, name); 55258927Sgroudier /* Unlock */ 55358927Sgroudier return m; 55458927Sgroudier} 55558927Sgroudier 55658927Sgroudier/* 55758927Sgroudier * Actual memory allocation routine for non-DMAed memory. 55858927Sgroudier */ 55958927Sgroudierstatic void sym_mfree(void *ptr, int size, char *name) 56058927Sgroudier{ 56158927Sgroudier /* Lock */ 56258927Sgroudier __sym_mfree(&mp0, ptr, size, name); 56358927Sgroudier /* Unlock */ 56458927Sgroudier} 56558927Sgroudier 56658927Sgroudier/* 56758927Sgroudier * DMAable pools. 56858927Sgroudier */ 56958927Sgroudier/* 570178466Smarius * With `bus dma abstraction', we use a separate pool per parent 571178466Smarius * BUS handle. A reverse table (hashed) is maintained for virtual 57258927Sgroudier * to BUS address translation. 57358927Sgroudier */ 574251572Smariusstatic void getbaddrcb(void *arg, bus_dma_segment_t *segs, int nseg __unused, 575251572Smarius int error) 57658927Sgroudier{ 57758927Sgroudier bus_addr_t *baddr; 578251572Smarius 579251572Smarius KASSERT(nseg == 1, ("%s: too many DMA segments (%d)", __func__, nseg)); 580251572Smarius 58158927Sgroudier baddr = (bus_addr_t *)arg; 582251572Smarius if (error) 583251572Smarius *baddr = 0; 584251572Smarius else 585251572Smarius *baddr = segs->ds_addr; 58658927Sgroudier} 58758927Sgroudier 58858927Sgroudierstatic m_addr_t ___dma_getp(m_pool_s *mp) 58958927Sgroudier{ 59058927Sgroudier m_vtob_s *vbp; 591178466Smarius void *vaddr = NULL; 59258927Sgroudier bus_addr_t baddr = 0; 59358927Sgroudier 59458927Sgroudier vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB"); 59558927Sgroudier if (!vbp) 59658927Sgroudier goto out_err; 59758927Sgroudier 59858927Sgroudier if (bus_dmamem_alloc(mp->dmat, &vaddr, 599178468Smarius BUS_DMA_COHERENT | BUS_DMA_WAITOK, &vbp->dmamap)) 60058927Sgroudier goto out_err; 60158927Sgroudier bus_dmamap_load(mp->dmat, vbp->dmamap, vaddr, 602171524Sse MEMO_CLUSTER_SIZE, getbaddrcb, &baddr, BUS_DMA_NOWAIT); 60358927Sgroudier if (baddr) { 60458927Sgroudier int hc = VTOB_HASH_CODE(vaddr); 60558927Sgroudier vbp->vaddr = (m_addr_t) vaddr; 60658927Sgroudier vbp->baddr = (m_addr_t) baddr; 60758927Sgroudier vbp->next = mp->vtob[hc]; 60858927Sgroudier mp->vtob[hc] = vbp; 60958927Sgroudier ++mp->nump; 61058927Sgroudier return (m_addr_t) vaddr; 61158927Sgroudier } 61258927Sgroudierout_err: 61358927Sgroudier if (baddr) 61458927Sgroudier bus_dmamap_unload(mp->dmat, vbp->dmamap); 61558927Sgroudier if (vaddr) 61658927Sgroudier bus_dmamem_free(mp->dmat, vaddr, vbp->dmamap); 617142515Ssam if (vbp) { 618142515Ssam if (vbp->dmamap) 619142515Ssam bus_dmamap_destroy(mp->dmat, vbp->dmamap); 62058927Sgroudier __sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB"); 621142515Ssam } 62258927Sgroudier return 0; 62358927Sgroudier} 62458927Sgroudier 62558927Sgroudier#ifdef MEMO_FREE_UNUSED 62658927Sgroudierstatic void ___dma_freep(m_pool_s *mp, m_addr_t m) 62758927Sgroudier{ 62858927Sgroudier m_vtob_s **vbpp, *vbp; 62958927Sgroudier int hc = VTOB_HASH_CODE(m); 63058927Sgroudier 63158927Sgroudier vbpp = &mp->vtob[hc]; 63258927Sgroudier while (*vbpp && (*vbpp)->vaddr != m) 63358927Sgroudier vbpp = &(*vbpp)->next; 63458927Sgroudier if (*vbpp) { 63558927Sgroudier vbp = *vbpp; 63658927Sgroudier *vbpp = (*vbpp)->next; 63758927Sgroudier bus_dmamap_unload(mp->dmat, vbp->dmamap); 63858927Sgroudier bus_dmamem_free(mp->dmat, (void *) vbp->vaddr, vbp->dmamap); 63958927Sgroudier bus_dmamap_destroy(mp->dmat, vbp->dmamap); 64058927Sgroudier __sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB"); 64158927Sgroudier --mp->nump; 64258927Sgroudier } 64358927Sgroudier} 64458927Sgroudier#endif 64558927Sgroudier 64662134Sgroudierstatic __inline m_pool_s *___get_dma_pool(bus_dma_tag_t dev_dmat) 64758927Sgroudier{ 64858927Sgroudier m_pool_s *mp; 64958927Sgroudier for (mp = mp0.next; mp && mp->dev_dmat != dev_dmat; mp = mp->next); 65058927Sgroudier return mp; 65158927Sgroudier} 65258927Sgroudier 65358927Sgroudierstatic m_pool_s *___cre_dma_pool(bus_dma_tag_t dev_dmat) 65458927Sgroudier{ 655178466Smarius m_pool_s *mp = NULL; 65658927Sgroudier 65758927Sgroudier mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL"); 65858927Sgroudier if (mp) { 65958927Sgroudier mp->dev_dmat = dev_dmat; 66058927Sgroudier if (!bus_dma_tag_create(dev_dmat, 1, MEMO_CLUSTER_SIZE, 66158927Sgroudier BUS_SPACE_MAXADDR_32BIT, 662171524Sse BUS_SPACE_MAXADDR, 66358927Sgroudier NULL, NULL, MEMO_CLUSTER_SIZE, 1, 664117126Sscottl MEMO_CLUSTER_SIZE, 0, 665178468Smarius NULL, NULL, &mp->dmat)) { 66658927Sgroudier mp->getp = ___dma_getp; 66758927Sgroudier#ifdef MEMO_FREE_UNUSED 66858927Sgroudier mp->freep = ___dma_freep; 66958927Sgroudier#endif 67058927Sgroudier mp->next = mp0.next; 67158927Sgroudier mp0.next = mp; 67258927Sgroudier return mp; 67358927Sgroudier } 67458927Sgroudier } 67558927Sgroudier if (mp) 67658927Sgroudier __sym_mfree(&mp0, mp, sizeof(*mp), "MPOOL"); 677178466Smarius return NULL; 67858927Sgroudier} 67958927Sgroudier 68058927Sgroudier#ifdef MEMO_FREE_UNUSED 68158927Sgroudierstatic void ___del_dma_pool(m_pool_s *p) 68258927Sgroudier{ 68358927Sgroudier struct m_pool **pp = &mp0.next; 68458927Sgroudier 68558927Sgroudier while (*pp && *pp != p) 68658927Sgroudier pp = &(*pp)->next; 68758927Sgroudier if (*pp) { 68858927Sgroudier *pp = (*pp)->next; 68958927Sgroudier bus_dma_tag_destroy(p->dmat); 69058927Sgroudier __sym_mfree(&mp0, p, sizeof(*p), "MPOOL"); 69158927Sgroudier } 69258927Sgroudier} 69358927Sgroudier#endif 69458927Sgroudier 69558927Sgroudierstatic void *__sym_calloc_dma(bus_dma_tag_t dev_dmat, int size, char *name) 69658927Sgroudier{ 69758927Sgroudier struct m_pool *mp; 698178466Smarius void *m = NULL; 69958927Sgroudier 70058927Sgroudier /* Lock */ 70158927Sgroudier mp = ___get_dma_pool(dev_dmat); 70258927Sgroudier if (!mp) 70358927Sgroudier mp = ___cre_dma_pool(dev_dmat); 70458927Sgroudier if (mp) 70558927Sgroudier m = __sym_calloc(mp, size, name); 70658927Sgroudier#ifdef MEMO_FREE_UNUSED 70758927Sgroudier if (mp && !mp->nump) 70858927Sgroudier ___del_dma_pool(mp); 70958927Sgroudier#endif 71058927Sgroudier /* Unlock */ 71158927Sgroudier 71258927Sgroudier return m; 71358927Sgroudier} 71458927Sgroudier 715178466Smariusstatic void 71658927Sgroudier__sym_mfree_dma(bus_dma_tag_t dev_dmat, void *m, int size, char *name) 71758927Sgroudier{ 71858927Sgroudier struct m_pool *mp; 71958927Sgroudier 72058927Sgroudier /* Lock */ 72158927Sgroudier mp = ___get_dma_pool(dev_dmat); 72258927Sgroudier if (mp) 72358927Sgroudier __sym_mfree(mp, m, size, name); 72458927Sgroudier#ifdef MEMO_FREE_UNUSED 72558927Sgroudier if (mp && !mp->nump) 72658927Sgroudier ___del_dma_pool(mp); 72758927Sgroudier#endif 72858927Sgroudier /* Unlock */ 72958927Sgroudier} 73058927Sgroudier 73158927Sgroudierstatic m_addr_t __vtobus(bus_dma_tag_t dev_dmat, void *m) 73258927Sgroudier{ 73358927Sgroudier m_pool_s *mp; 73458927Sgroudier int hc = VTOB_HASH_CODE(m); 735178466Smarius m_vtob_s *vp = NULL; 73658927Sgroudier m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK; 73758927Sgroudier 73858927Sgroudier /* Lock */ 73958927Sgroudier mp = ___get_dma_pool(dev_dmat); 74058927Sgroudier if (mp) { 74158927Sgroudier vp = mp->vtob[hc]; 74258927Sgroudier while (vp && (m_addr_t) vp->vaddr != a) 74358927Sgroudier vp = vp->next; 74458927Sgroudier } 74558927Sgroudier /* Unlock */ 74658927Sgroudier if (!vp) 74758927Sgroudier panic("sym: VTOBUS FAILED!\n"); 74858927Sgroudier return vp ? vp->baddr + (((m_addr_t) m) - a) : 0; 74958927Sgroudier} 75058927Sgroudier 75158927Sgroudier/* 75258927Sgroudier * Verbs for DMAable memory handling. 753178466Smarius * The _uvptv_ macro avoids a nasty warning about pointer to volatile 75458927Sgroudier * being discarded. 75558927Sgroudier */ 75658927Sgroudier#define _uvptv_(p) ((void *)((vm_offset_t)(p))) 75758927Sgroudier#define _sym_calloc_dma(np, s, n) __sym_calloc_dma(np->bus_dmat, s, n) 75858927Sgroudier#define _sym_mfree_dma(np, p, s, n) \ 75958927Sgroudier __sym_mfree_dma(np->bus_dmat, _uvptv_(p), s, n) 76058927Sgroudier#define sym_calloc_dma(s, n) _sym_calloc_dma(np, s, n) 76158927Sgroudier#define sym_mfree_dma(p, s, n) _sym_mfree_dma(np, p, s, n) 76258927Sgroudier#define _vtobus(np, p) __vtobus(np->bus_dmat, _uvptv_(p)) 76358927Sgroudier#define vtobus(p) _vtobus(np, p) 76458927Sgroudier 76558927Sgroudier/* 76653790Sobrien * Print a buffer in hexadecimal format. 76753790Sobrien */ 76853790Sobrienstatic void sym_printb_hex (u_char *p, int n) 76953790Sobrien{ 77053790Sobrien while (n-- > 0) 77153790Sobrien printf (" %x", *p++); 77253790Sobrien} 77353790Sobrien 77453790Sobrien/* 77553790Sobrien * Same with a label at beginning and .\n at end. 77653790Sobrien */ 77753790Sobrienstatic void sym_printl_hex (char *label, u_char *p, int n) 77853790Sobrien{ 77953790Sobrien printf ("%s", label); 78053790Sobrien sym_printb_hex (p, n); 78153790Sobrien printf (".\n"); 78253790Sobrien} 78353790Sobrien 78453790Sobrien/* 78555300Sgroudier * Return a string for SCSI BUS mode. 78655300Sgroudier */ 787179029Smariusstatic const char *sym_scsi_bus_mode(int mode) 78855300Sgroudier{ 78955300Sgroudier switch(mode) { 79055300Sgroudier case SMODE_HVD: return "HVD"; 79155300Sgroudier case SMODE_SE: return "SE"; 79255300Sgroudier case SMODE_LVD: return "LVD"; 79355300Sgroudier } 79455300Sgroudier return "??"; 79555300Sgroudier} 79655300Sgroudier 79755300Sgroudier/* 79861639Sgroudier * Some poor and bogus sync table that refers to Tekram NVRAM layout. 79953790Sobrien */ 80054690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 801179029Smariusstatic const u_char Tekram_sync[16] = 80253790Sobrien {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10}; 80353790Sobrien#endif 80453790Sobrien 80553790Sobrien/* 80653790Sobrien * Union of supported NVRAM formats. 80753790Sobrien */ 80853790Sobrienstruct sym_nvram { 80953790Sobrien int type; 81053790Sobrien#define SYM_SYMBIOS_NVRAM (1) 81153790Sobrien#define SYM_TEKRAM_NVRAM (2) 81254690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 81353790Sobrien union { 81453790Sobrien Symbios_nvram Symbios; 81553790Sobrien Tekram_nvram Tekram; 81653790Sobrien } data; 81753790Sobrien#endif 81853790Sobrien}; 81953790Sobrien 82053790Sobrien/* 82153790Sobrien * This one is hopefully useless, but actually useful. :-) 82253790Sobrien */ 82353790Sobrien#ifndef assert 82453790Sobrien#define assert(expression) { \ 82553790Sobrien if (!(expression)) { \ 82653790Sobrien (void)panic( \ 82753790Sobrien "assertion \"%s\" failed: file \"%s\", line %d\n", \ 82853790Sobrien #expression, \ 82953790Sobrien __FILE__, __LINE__); \ 83053790Sobrien } \ 83153790Sobrien} 83253790Sobrien#endif 83353790Sobrien 83453790Sobrien/* 835178466Smarius * Some provision for a possible big endian mode supported by 83661429Sgroudier * Symbios chips (never seen, by the way). 83753790Sobrien * For now, this stuff does not deserve any comments. :) 83853790Sobrien */ 83953790Sobrien#define sym_offb(o) (o) 84053790Sobrien#define sym_offw(o) (o) 84153790Sobrien 84261429Sgroudier/* 84361429Sgroudier * Some provision for support for BIG ENDIAN CPU. 84461429Sgroudier */ 845153145Sscottl#define cpu_to_scr(dw) htole32(dw) 846153145Sscottl#define scr_to_cpu(dw) le32toh(dw) 84753790Sobrien 84853790Sobrien/* 84961429Sgroudier * Access to the chip IO registers and on-chip RAM. 850178466Smarius * We use the `bus space' interface under FreeBSD-4 and 85161429Sgroudier * later kernel versions. 85253790Sobrien */ 85361429Sgroudier#if defined(SYM_CONF_IOMAPPED) 85461429Sgroudier 855178468Smarius#define INB_OFF(o) bus_read_1(np->io_res, (o)) 856178468Smarius#define INW_OFF(o) bus_read_2(np->io_res, (o)) 857178468Smarius#define INL_OFF(o) bus_read_4(np->io_res, (o)) 85861429Sgroudier 859178468Smarius#define OUTB_OFF(o, v) bus_write_1(np->io_res, (o), (v)) 860178468Smarius#define OUTW_OFF(o, v) bus_write_2(np->io_res, (o), (v)) 861178468Smarius#define OUTL_OFF(o, v) bus_write_4(np->io_res, (o), (v)) 86261429Sgroudier 86361429Sgroudier#else /* Memory mapped IO */ 86461429Sgroudier 865178468Smarius#define INB_OFF(o) bus_read_1(np->mmio_res, (o)) 866178468Smarius#define INW_OFF(o) bus_read_2(np->mmio_res, (o)) 867178468Smarius#define INL_OFF(o) bus_read_4(np->mmio_res, (o)) 86861429Sgroudier 869178468Smarius#define OUTB_OFF(o, v) bus_write_1(np->mmio_res, (o), (v)) 870178468Smarius#define OUTW_OFF(o, v) bus_write_2(np->mmio_res, (o), (v)) 871178468Smarius#define OUTL_OFF(o, v) bus_write_4(np->mmio_res, (o), (v)) 87261429Sgroudier 87361429Sgroudier#endif /* SYM_CONF_IOMAPPED */ 87461429Sgroudier 87561429Sgroudier#define OUTRAM_OFF(o, a, l) \ 876178468Smarius bus_write_region_1(np->ram_res, (o), (a), (l)) 87761429Sgroudier 87853790Sobrien/* 87961429Sgroudier * Common definitions for both bus space and legacy IO methods. 88053790Sobrien */ 88153790Sobrien#define INB(r) INB_OFF(offsetof(struct sym_reg,r)) 88253790Sobrien#define INW(r) INW_OFF(offsetof(struct sym_reg,r)) 88353790Sobrien#define INL(r) INL_OFF(offsetof(struct sym_reg,r)) 88453790Sobrien 88553790Sobrien#define OUTB(r, v) OUTB_OFF(offsetof(struct sym_reg,r), (v)) 88653790Sobrien#define OUTW(r, v) OUTW_OFF(offsetof(struct sym_reg,r), (v)) 88753790Sobrien#define OUTL(r, v) OUTL_OFF(offsetof(struct sym_reg,r), (v)) 88853790Sobrien 88953790Sobrien#define OUTONB(r, m) OUTB(r, INB(r) | (m)) 89053790Sobrien#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m)) 89153790Sobrien#define OUTONW(r, m) OUTW(r, INW(r) | (m)) 89253790Sobrien#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m)) 89353790Sobrien#define OUTONL(r, m) OUTL(r, INL(r) | (m)) 89453790Sobrien#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m)) 89553790Sobrien 89653790Sobrien/* 89761429Sgroudier * We normally want the chip to have a consistent view 89861429Sgroudier * of driver internal data structures when we restart it. 89961429Sgroudier * Thus these macros. 90061429Sgroudier */ 90161429Sgroudier#define OUTL_DSP(v) \ 90261429Sgroudier do { \ 90361429Sgroudier MEMORY_BARRIER(); \ 90461429Sgroudier OUTL (nc_dsp, (v)); \ 90561429Sgroudier } while (0) 90661429Sgroudier 90761429Sgroudier#define OUTONB_STD() \ 90861429Sgroudier do { \ 90961429Sgroudier MEMORY_BARRIER(); \ 91061429Sgroudier OUTONB (nc_dcntl, (STD|NOCOM)); \ 91161429Sgroudier } while (0) 91261429Sgroudier 91361429Sgroudier/* 91453790Sobrien * Command control block states. 91553790Sobrien */ 91653790Sobrien#define HS_IDLE (0) 91753790Sobrien#define HS_BUSY (1) 91853790Sobrien#define HS_NEGOTIATE (2) /* sync/wide data transfer*/ 91953790Sobrien#define HS_DISCONNECT (3) /* Disconnected by target */ 92058927Sgroudier#define HS_WAIT (4) /* waiting for resource */ 92153790Sobrien 92253790Sobrien#define HS_DONEMASK (0x80) 92353790Sobrien#define HS_COMPLETE (4|HS_DONEMASK) 92453790Sobrien#define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */ 92553790Sobrien#define HS_UNEXPECTED (6|HS_DONEMASK) /* Unexpected disconnect */ 92653790Sobrien#define HS_COMP_ERR (7|HS_DONEMASK) /* Completed with error */ 92753790Sobrien 92853790Sobrien/* 92953790Sobrien * Software Interrupt Codes 93053790Sobrien */ 93153790Sobrien#define SIR_BAD_SCSI_STATUS (1) 93253790Sobrien#define SIR_SEL_ATN_NO_MSG_OUT (2) 93353790Sobrien#define SIR_MSG_RECEIVED (3) 93453790Sobrien#define SIR_MSG_WEIRD (4) 93553790Sobrien#define SIR_NEGO_FAILED (5) 93653790Sobrien#define SIR_NEGO_PROTO (6) 93753790Sobrien#define SIR_SCRIPT_STOPPED (7) 93853790Sobrien#define SIR_REJECT_TO_SEND (8) 93953790Sobrien#define SIR_SWIDE_OVERRUN (9) 94053790Sobrien#define SIR_SODL_UNDERRUN (10) 94153790Sobrien#define SIR_RESEL_NO_MSG_IN (11) 94253790Sobrien#define SIR_RESEL_NO_IDENTIFY (12) 94353790Sobrien#define SIR_RESEL_BAD_LUN (13) 94453790Sobrien#define SIR_TARGET_SELECTED (14) 94553790Sobrien#define SIR_RESEL_BAD_I_T_L (15) 94653790Sobrien#define SIR_RESEL_BAD_I_T_L_Q (16) 94753790Sobrien#define SIR_ABORT_SENT (17) 94853790Sobrien#define SIR_RESEL_ABORTED (18) 94953790Sobrien#define SIR_MSG_OUT_DONE (19) 95053790Sobrien#define SIR_COMPLETE_ERROR (20) 95159252Sgroudier#define SIR_DATA_OVERRUN (21) 95259252Sgroudier#define SIR_BAD_PHASE (22) 95359252Sgroudier#define SIR_MAX (22) 95453790Sobrien 95553790Sobrien/* 95653790Sobrien * Extended error bit codes. 95753790Sobrien * xerr_status field of struct sym_ccb. 95853790Sobrien */ 95953790Sobrien#define XE_EXTRA_DATA (1) /* unexpected data phase */ 96053790Sobrien#define XE_BAD_PHASE (1<<1) /* illegal phase (4/5) */ 96153790Sobrien#define XE_PARITY_ERR (1<<2) /* unrecovered SCSI parity error */ 96253790Sobrien#define XE_SODL_UNRUN (1<<3) /* ODD transfer in DATA OUT phase */ 96353790Sobrien#define XE_SWIDE_OVRUN (1<<4) /* ODD transfer in DATA IN phase */ 96453790Sobrien 96553790Sobrien/* 96653790Sobrien * Negotiation status. 96753790Sobrien * nego_status field of struct sym_ccb. 96853790Sobrien */ 96953790Sobrien#define NS_SYNC (1) 97053790Sobrien#define NS_WIDE (2) 97153790Sobrien#define NS_PPR (3) 97253790Sobrien 97353790Sobrien/* 974178466Smarius * A CCB hashed table is used to retrieve CCB address 97553790Sobrien * from DSA value. 97653790Sobrien */ 97753790Sobrien#define CCB_HASH_SHIFT 8 97853790Sobrien#define CCB_HASH_SIZE (1UL << CCB_HASH_SHIFT) 97953790Sobrien#define CCB_HASH_MASK (CCB_HASH_SIZE-1) 98053790Sobrien#define CCB_HASH_CODE(dsa) (((dsa) >> 9) & CCB_HASH_MASK) 98153790Sobrien 98253790Sobrien/* 98353790Sobrien * Device flags. 98453790Sobrien */ 98553790Sobrien#define SYM_DISC_ENABLED (1) 98653790Sobrien#define SYM_TAGS_ENABLED (1<<1) 98753790Sobrien#define SYM_SCAN_BOOT_DISABLED (1<<2) 98853790Sobrien#define SYM_SCAN_LUNS_DISABLED (1<<3) 98953790Sobrien 99053790Sobrien/* 99155628Sgroudier * Host adapter miscellaneous flags. 99255628Sgroudier */ 99355628Sgroudier#define SYM_AVOID_BUS_RESET (1) 99455628Sgroudier#define SYM_SCAN_TARGETS_HILO (1<<1) 99555628Sgroudier 99655628Sgroudier/* 99753790Sobrien * Device quirks. 998178466Smarius * Some devices, for example the CHEETAH 2 LVD, disconnects without 99962422Sgroudier * saving the DATA POINTER then reselects and terminates the IO. 1000178466Smarius * On reselection, the automatic RESTORE DATA POINTER makes the 100153790Sobrien * CURRENT DATA POINTER not point at the end of the IO. 100253790Sobrien * This behaviour just breaks our calculation of the residual. 1003178466Smarius * For now, we just force an AUTO SAVE on disconnection and will 100453790Sobrien * fix that in a further driver version. 100553790Sobrien */ 100653790Sobrien#define SYM_QUIRK_AUTOSAVE 1 100753790Sobrien 100853790Sobrien/* 100953790Sobrien * Misc. 101053790Sobrien */ 1011178468Smarius#define SYM_LOCK() mtx_lock(&np->mtx) 1012178468Smarius#define SYM_LOCK_ASSERT(_what) mtx_assert(&np->mtx, (_what)) 1013178468Smarius#define SYM_LOCK_DESTROY() mtx_destroy(&np->mtx) 1014178468Smarius#define SYM_LOCK_INIT() mtx_init(&np->mtx, "sym_lock", NULL, MTX_DEF) 1015178468Smarius#define SYM_LOCK_INITIALIZED() mtx_initialized(&np->mtx) 1016178468Smarius#define SYM_UNLOCK() mtx_unlock(&np->mtx) 1017178468Smarius 101853790Sobrien#define SYM_SNOOP_TIMEOUT (10000000) 1019119690Sjhb#define SYM_PCI_IO PCIR_BAR(0) 1020119690Sjhb#define SYM_PCI_MMIO PCIR_BAR(1) 1021119690Sjhb#define SYM_PCI_RAM PCIR_BAR(2) 1022119690Sjhb#define SYM_PCI_RAM64 PCIR_BAR(3) 102353790Sobrien 102453790Sobrien/* 102553790Sobrien * Back-pointer from the CAM CCB to our data structures. 102653790Sobrien */ 102753790Sobrien#define sym_hcb_ptr spriv_ptr0 102853790Sobrien/* #define sym_ccb_ptr spriv_ptr1 */ 102953790Sobrien 103053790Sobrien/* 103153790Sobrien * We mostly have to deal with pointers. 103253790Sobrien * Thus these typedef's. 103353790Sobrien */ 103453790Sobrientypedef struct sym_tcb *tcb_p; 103553790Sobrientypedef struct sym_lcb *lcb_p; 103653790Sobrientypedef struct sym_ccb *ccb_p; 103753790Sobrientypedef struct sym_hcb *hcb_p; 103853790Sobrien 103953790Sobrien/* 104053790Sobrien * Gather negotiable parameters value 104153790Sobrien */ 104253790Sobrienstruct sym_trans { 104374755Sgroudier u8 scsi_version; 104474755Sgroudier u8 spi_version; 104553790Sobrien u8 period; 104653790Sobrien u8 offset; 104753790Sobrien u8 width; 104853790Sobrien u8 options; /* PPR options */ 104953790Sobrien}; 105053790Sobrien 105153790Sobrienstruct sym_tinfo { 105253790Sobrien struct sym_trans current; 105353790Sobrien struct sym_trans goal; 105453790Sobrien struct sym_trans user; 105553790Sobrien}; 105653790Sobrien 105753790Sobrien#define BUS_8_BIT MSG_EXT_WDTR_BUS_8_BIT 105853790Sobrien#define BUS_16_BIT MSG_EXT_WDTR_BUS_16_BIT 105953790Sobrien 106053790Sobrien/* 106159743Sgroudier * Global TCB HEADER. 106259743Sgroudier * 106359743Sgroudier * Due to lack of indirect addressing on earlier NCR chips, 1064178466Smarius * this substructure is copied from the TCB to a global 106559743Sgroudier * address after selection. 1066178466Smarius * For SYMBIOS chips that support LOAD/STORE this copy is 106759743Sgroudier * not needed and thus not performed. 106853790Sobrien */ 106959743Sgroudierstruct sym_tcbh { 107053790Sobrien /* 107159743Sgroudier * Scripts bus addresses of LUN table accessed from scripts. 1072178466Smarius * LUN #0 is a special case, since multi-lun devices are rare, 1073178466Smarius * and we we want to speed-up the general case and not waste 107453790Sobrien * resources. 107553790Sobrien */ 107653790Sobrien u32 luntbl_sa; /* bus address of this table */ 107753790Sobrien u32 lun0_sa; /* bus address of LCB #0 */ 107859743Sgroudier /* 107959743Sgroudier * Actual SYNC/WIDE IO registers value for this target. 1080178466Smarius * 'sval', 'wval' and 'uval' are read from SCRIPTS and 108159743Sgroudier * so have alignment constraints. 108259743Sgroudier */ 108359743Sgroudier/*0*/ u_char uval; /* -> SCNTL4 register */ 108459743Sgroudier/*1*/ u_char sval; /* -> SXFER io register */ 108559743Sgroudier/*2*/ u_char filler1; 108659743Sgroudier/*3*/ u_char wval; /* -> SCNTL3 io register */ 108759743Sgroudier}; 108853790Sobrien 108959743Sgroudier/* 109059743Sgroudier * Target Control Block 109159743Sgroudier */ 109259743Sgroudierstruct sym_tcb { 109353790Sobrien /* 109459743Sgroudier * TCB header. 109559743Sgroudier * Assumed at offset 0. 109659743Sgroudier */ 109759743Sgroudier/*0*/ struct sym_tcbh head; 109859743Sgroudier 109959743Sgroudier /* 110059743Sgroudier * LUN table used by the SCRIPTS processor. 110159743Sgroudier * An array of bus addresses is used on reselection. 110259743Sgroudier */ 110359743Sgroudier u32 *luntbl; /* LCBs bus address table */ 110459743Sgroudier 110559743Sgroudier /* 110653790Sobrien * LUN table used by the C code. 110753790Sobrien */ 110853790Sobrien lcb_p lun0p; /* LCB of LUN #0 (usual case) */ 110954690Sobrien#if SYM_CONF_MAX_LUN > 1 111053790Sobrien lcb_p *lunmp; /* Other LCBs [1..MAX_LUN] */ 111153790Sobrien#endif 111253790Sobrien 111353790Sobrien /* 1114178466Smarius * Bitmap that tells about LUNs that succeeded at least 111553790Sobrien * 1 IO and therefore assumed to be a real device. 111653790Sobrien * Avoid useless allocation of the LCB structure. 111753790Sobrien */ 111854690Sobrien u32 lun_map[(SYM_CONF_MAX_LUN+31)/32]; 111953790Sobrien 112053790Sobrien /* 1121178466Smarius * Bitmap that tells about LUNs that haven't yet an LCB 112253790Sobrien * allocated (not discovered or LCB allocation failed). 112353790Sobrien */ 112454690Sobrien u32 busy0_map[(SYM_CONF_MAX_LUN+31)/32]; 112553790Sobrien 112653790Sobrien /* 112753790Sobrien * Transfer capabilities (SIP) 112853790Sobrien */ 112953790Sobrien struct sym_tinfo tinfo; 113053790Sobrien 113153790Sobrien /* 113253790Sobrien * Keep track of the CCB used for the negotiation in order 113353790Sobrien * to ensure that only 1 negotiation is queued at a time. 113453790Sobrien */ 113553790Sobrien ccb_p nego_cp; /* CCB used for the nego */ 113653790Sobrien 113753790Sobrien /* 113853790Sobrien * Set when we want to reset the device. 113953790Sobrien */ 114053790Sobrien u_char to_reset; 114153790Sobrien 114253790Sobrien /* 114353790Sobrien * Other user settable limits and options. 114453790Sobrien * These limits are read from the NVRAM if present. 114553790Sobrien */ 114653790Sobrien u_char usrflags; 114753790Sobrien u_short usrtags; 114853790Sobrien}; 114953790Sobrien 115053790Sobrien/* 1151251572Smarius * Assert some alignments required by the chip. 1152251572Smarius */ 1153251572SmariusCTASSERT(((offsetof(struct sym_reg, nc_sxfer) ^ 1154251572Smarius offsetof(struct sym_tcb, head.sval)) &3) == 0); 1155251572SmariusCTASSERT(((offsetof(struct sym_reg, nc_scntl3) ^ 1156251572Smarius offsetof(struct sym_tcb, head.wval)) &3) == 0); 1157251572Smarius 1158251572Smarius/* 115959743Sgroudier * Global LCB HEADER. 116059743Sgroudier * 116159743Sgroudier * Due to lack of indirect addressing on earlier NCR chips, 1162178466Smarius * this substructure is copied from the LCB to a global 116359743Sgroudier * address after selection. 1164178466Smarius * For SYMBIOS chips that support LOAD/STORE this copy is 116559743Sgroudier * not needed and thus not performed. 116653790Sobrien */ 116759743Sgroudierstruct sym_lcbh { 116853790Sobrien /* 116953790Sobrien * SCRIPTS address jumped by SCRIPTS on reselection. 1170178466Smarius * For not probed logical units, this address points to 1171178466Smarius * SCRIPTS that deal with bad LU handling (must be at 117259743Sgroudier * offset zero of the LCB for that reason). 117353790Sobrien */ 117453790Sobrien/*0*/ u32 resel_sa; 117553790Sobrien 117653790Sobrien /* 1177178466Smarius * Task (bus address of a CCB) read from SCRIPTS that points 117853790Sobrien * to the unique ITL nexus allowed to be disconnected. 117953790Sobrien */ 118053790Sobrien u32 itl_task_sa; 118153790Sobrien 118253790Sobrien /* 118359743Sgroudier * Task table bus address (read from SCRIPTS). 118459743Sgroudier */ 118559743Sgroudier u32 itlq_tbl_sa; 118659743Sgroudier}; 118759743Sgroudier 118859743Sgroudier/* 118959743Sgroudier * Logical Unit Control Block 119059743Sgroudier */ 119159743Sgroudierstruct sym_lcb { 119259743Sgroudier /* 119359743Sgroudier * TCB header. 119459743Sgroudier * Assumed at offset 0. 119559743Sgroudier */ 119659743Sgroudier/*0*/ struct sym_lcbh head; 119759743Sgroudier 119859743Sgroudier /* 1199178466Smarius * Task table read from SCRIPTS that contains pointers to 1200178466Smarius * ITLQ nexuses. The bus address read from SCRIPTS is 120159743Sgroudier * inside the header. 120253790Sobrien */ 120353790Sobrien u32 *itlq_tbl; /* Kernel virtual address */ 120453790Sobrien 120553790Sobrien /* 120653790Sobrien * Busy CCBs management. 120753790Sobrien */ 120853790Sobrien u_short busy_itlq; /* Number of busy tagged CCBs */ 120953790Sobrien u_short busy_itl; /* Number of busy untagged CCBs */ 121053790Sobrien 121153790Sobrien /* 121253790Sobrien * Circular tag allocation buffer. 121353790Sobrien */ 121453790Sobrien u_short ia_tag; /* Tag allocation index */ 121553790Sobrien u_short if_tag; /* Tag release index */ 121653790Sobrien u_char *cb_tags; /* Circular tags buffer */ 121753790Sobrien 121853790Sobrien /* 121953790Sobrien * Set when we want to clear all tasks. 122053790Sobrien */ 122153790Sobrien u_char to_clear; 122253790Sobrien 122353790Sobrien /* 122453790Sobrien * Capabilities. 122553790Sobrien */ 122653790Sobrien u_char user_flags; 122753790Sobrien u_char current_flags; 122853790Sobrien}; 122953790Sobrien 123053790Sobrien/* 123153790Sobrien * Action from SCRIPTS on a task. 1232178466Smarius * Is part of the CCB, but is also used separately to plug 123353790Sobrien * error handling action to perform from SCRIPTS. 123453790Sobrien */ 123553790Sobrienstruct sym_actscr { 123653790Sobrien u32 start; /* Jumped by SCRIPTS after selection */ 123753790Sobrien u32 restart; /* Jumped by SCRIPTS on relection */ 123853790Sobrien}; 123953790Sobrien 124053790Sobrien/* 124153790Sobrien * Phase mismatch context. 124253790Sobrien * 1243178466Smarius * It is part of the CCB and is used as parameters for the 1244178466Smarius * DATA pointer. We need two contexts to handle correctly the 124553790Sobrien * SAVED DATA POINTER. 124653790Sobrien */ 124753790Sobrienstruct sym_pmc { 124853790Sobrien struct sym_tblmove sg; /* Updated interrupted SG block */ 124953790Sobrien u32 ret; /* SCRIPT return address */ 125053790Sobrien}; 125153790Sobrien 125253790Sobrien/* 125353790Sobrien * LUN control block lookup. 1254178466Smarius * We use a direct pointer for LUN #0, and a table of 1255178466Smarius * pointers which is only allocated for devices that support 125653790Sobrien * LUN(s) > 0. 125753790Sobrien */ 125854690Sobrien#if SYM_CONF_MAX_LUN <= 1 1259251572Smarius#define sym_lp(tp, lun) (!lun) ? (tp)->lun0p : 0 126053790Sobrien#else 1261251572Smarius#define sym_lp(tp, lun) \ 126253790Sobrien (!lun) ? (tp)->lun0p : (tp)->lunmp ? (tp)->lunmp[(lun)] : 0 126353790Sobrien#endif 126453790Sobrien 126553790Sobrien/* 126653790Sobrien * Status are used by the host and the script processor. 126753790Sobrien * 1268178466Smarius * The last four bytes (status[4]) are copied to the 1269178466Smarius * scratchb register (declared as scr0..scr3) just after the 127053790Sobrien * select/reselect, and copied back just after disconnecting. 127153790Sobrien * Inside the script the XX_REG are used. 127253790Sobrien */ 127353790Sobrien 127453790Sobrien/* 127553790Sobrien * Last four bytes (script) 127653790Sobrien */ 127753790Sobrien#define QU_REG scr0 127853790Sobrien#define HS_REG scr1 127953790Sobrien#define HS_PRT nc_scr1 128053790Sobrien#define SS_REG scr2 128153790Sobrien#define SS_PRT nc_scr2 128253790Sobrien#define HF_REG scr3 128353790Sobrien#define HF_PRT nc_scr3 128453790Sobrien 128553790Sobrien/* 128653790Sobrien * Last four bytes (host) 128753790Sobrien */ 128859743Sgroudier#define actualquirks phys.head.status[0] 128959743Sgroudier#define host_status phys.head.status[1] 129059743Sgroudier#define ssss_status phys.head.status[2] 129159743Sgroudier#define host_flags phys.head.status[3] 129253790Sobrien 129353790Sobrien/* 129453790Sobrien * Host flags 129553790Sobrien */ 129653790Sobrien#define HF_IN_PM0 1u 129753790Sobrien#define HF_IN_PM1 (1u<<1) 129853790Sobrien#define HF_ACT_PM (1u<<2) 129953790Sobrien#define HF_DP_SAVED (1u<<3) 130053790Sobrien#define HF_SENSE (1u<<4) 130153790Sobrien#define HF_EXT_ERR (1u<<5) 130258927Sgroudier#define HF_DATA_IN (1u<<6) 130354690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 130453790Sobrien#define HF_HINT_IARB (1u<<7) 130553790Sobrien#endif 130653790Sobrien 130753790Sobrien/* 130859743Sgroudier * Global CCB HEADER. 130953790Sobrien * 131059743Sgroudier * Due to lack of indirect addressing on earlier NCR chips, 1311178466Smarius * this substructure is copied from the ccb to a global 1312178466Smarius * address after selection (or reselection) and copied back 131359743Sgroudier * before disconnect. 1314178466Smarius * For SYMBIOS chips that support LOAD/STORE this copy is 131559743Sgroudier * not needed and thus not performed. 131653790Sobrien */ 131759743Sgroudierstruct sym_ccbh { 131853790Sobrien /* 131953790Sobrien * Start and restart SCRIPTS addresses (must be at 0). 132053790Sobrien */ 132153790Sobrien/*0*/ struct sym_actscr go; 132253790Sobrien 132353790Sobrien /* 132453790Sobrien * SCRIPTS jump address that deal with data pointers. 1325178466Smarius * 'savep' points to the position in the script responsible 132659743Sgroudier * for the actual transfer of data. 132753790Sobrien * It's written on reception of a SAVE_DATA_POINTER message. 132853790Sobrien */ 132953790Sobrien u32 savep; /* Jump address to saved data pointer */ 133053790Sobrien u32 lastp; /* SCRIPTS address at end of data */ 133159743Sgroudier u32 goalp; /* Not accessed for now from SCRIPTS */ 133253790Sobrien 133353790Sobrien /* 133453790Sobrien * Status fields. 133553790Sobrien */ 133659252Sgroudier u8 status[4]; 133759743Sgroudier}; 133853790Sobrien 133959743Sgroudier/* 134059743Sgroudier * Data Structure Block 134159743Sgroudier * 1342178466Smarius * During execution of a ccb by the script processor, the 1343178466Smarius * DSA (data structure address) register points to this 134459743Sgroudier * substructure of the ccb. 134559743Sgroudier */ 134659743Sgroudierstruct sym_dsb { 134753790Sobrien /* 134859743Sgroudier * CCB header. 134962422Sgroudier * Also assumed at offset 0 of the sym_ccb structure. 135059743Sgroudier */ 135159743Sgroudier/*0*/ struct sym_ccbh head; 135259743Sgroudier 135359743Sgroudier /* 135459743Sgroudier * Phase mismatch contexts. 135559743Sgroudier * We need two to handle correctly the SAVED DATA POINTER. 1356178466Smarius * MUST BOTH BE AT OFFSET < 256, due to using 8 bit arithmetic 135759743Sgroudier * for address calculation from SCRIPTS. 135859743Sgroudier */ 135959743Sgroudier struct sym_pmc pm0; 136059743Sgroudier struct sym_pmc pm1; 136159743Sgroudier 136259743Sgroudier /* 136353790Sobrien * Table data for Script 136453790Sobrien */ 136553790Sobrien struct sym_tblsel select; 136653790Sobrien struct sym_tblmove smsg; 136753790Sobrien struct sym_tblmove smsg_ext; 136853790Sobrien struct sym_tblmove cmd; 136953790Sobrien struct sym_tblmove sense; 137057186Sgroudier struct sym_tblmove wresid; 137154690Sobrien struct sym_tblmove data [SYM_CONF_MAX_SG]; 137253790Sobrien}; 137353790Sobrien 137453790Sobrien/* 137553790Sobrien * Our Command Control Block 137653790Sobrien */ 137753790Sobrienstruct sym_ccb { 137853790Sobrien /* 1379178466Smarius * This is the data structure which is pointed by the DSA 138053790Sobrien * register when it is executed by the script processor. 138153790Sobrien * It must be the first entry. 138253790Sobrien */ 138359743Sgroudier struct sym_dsb phys; 138453790Sobrien 138553790Sobrien /* 138653790Sobrien * Pointer to CAM ccb and related stuff. 138753790Sobrien */ 1388178468Smarius struct callout ch; /* callout handle */ 138953790Sobrien union ccb *cam_ccb; /* CAM scsiio ccb */ 139058927Sgroudier u8 cdb_buf[16]; /* Copy of CDB */ 139158927Sgroudier u8 *sns_bbuf; /* Bounce buffer for sense data */ 139258927Sgroudier#define SYM_SNS_BBUF_LEN sizeof(struct scsi_sense_data) 139353790Sobrien int data_len; /* Total data length */ 139453790Sobrien int segments; /* Number of SG segments */ 139553790Sobrien 139653790Sobrien /* 139759252Sgroudier * Miscellaneous status'. 139859252Sgroudier */ 139959252Sgroudier u_char nego_status; /* Negotiation status */ 140059252Sgroudier u_char xerr_status; /* Extended error flags */ 140159252Sgroudier u32 extra_bytes; /* Extraneous bytes transferred */ 140259252Sgroudier 140359252Sgroudier /* 140453790Sobrien * Message areas. 140553790Sobrien * We prepare a message to be sent after selection. 1406178466Smarius * We may use a second one if the command is rescheduled 140753790Sobrien * due to CHECK_CONDITION or COMMAND TERMINATED. 140853790Sobrien * Contents are IDENTIFY and SIMPLE_TAG. 140953790Sobrien * While negotiating sync or wide transfer, 141053790Sobrien * a SDTR or WDTR message is appended. 141153790Sobrien */ 141253790Sobrien u_char scsi_smsg [12]; 141353790Sobrien u_char scsi_smsg2[12]; 141453790Sobrien 141553790Sobrien /* 141653790Sobrien * Auto request sense related fields. 141753790Sobrien */ 141853790Sobrien u_char sensecmd[6]; /* Request Sense command */ 141953790Sobrien u_char sv_scsi_status; /* Saved SCSI status */ 142053790Sobrien u_char sv_xerr_status; /* Saved extended status */ 142153790Sobrien int sv_resid; /* Saved residual */ 142258927Sgroudier 142353790Sobrien /* 142458927Sgroudier * Map for the DMA of user data. 142558927Sgroudier */ 142658927Sgroudier void *arg; /* Argument for some callback */ 142758927Sgroudier bus_dmamap_t dmamap; /* DMA map for user data */ 142858927Sgroudier u_char dmamapped; 142958927Sgroudier#define SYM_DMA_NONE 0 143058927Sgroudier#define SYM_DMA_READ 1 143158927Sgroudier#define SYM_DMA_WRITE 2 143258927Sgroudier /* 143353790Sobrien * Other fields. 143453790Sobrien */ 143561051Sgroudier u32 ccb_ba; /* BUS address of this CCB */ 143653790Sobrien u_short tag; /* Tag for this transfer */ 143753790Sobrien /* NO_TAG means no tag */ 143853790Sobrien u_char target; 143953790Sobrien u_char lun; 144053790Sobrien ccb_p link_ccbh; /* Host adapter CCB hash chain */ 144153790Sobrien SYM_QUEHEAD 144253790Sobrien link_ccbq; /* Link to free/busy CCB queue */ 144353790Sobrien u32 startp; /* Initial data pointer */ 144453790Sobrien int ext_sg; /* Extreme data pointer, used */ 144553790Sobrien int ext_ofs; /* to calculate the residual. */ 144653790Sobrien u_char to_abort; /* Want this IO to be aborted */ 144753790Sobrien}; 144853790Sobrien 144958927Sgroudier#define CCB_BA(cp,lbl) (cp->ccb_ba + offsetof(struct sym_ccb, lbl)) 145053790Sobrien 145153790Sobrien/* 145253790Sobrien * Host Control Block 145353790Sobrien */ 145453790Sobrienstruct sym_hcb { 1455178468Smarius struct mtx mtx; 1456178468Smarius 145753790Sobrien /* 145859743Sgroudier * Global headers. 1459178466Smarius * Due to poorness of addressing capabilities, earlier 1460178466Smarius * chips (810, 815, 825) copy part of the data structures 146159743Sgroudier * (CCB, TCB and LCB) in fixed areas. 146259743Sgroudier */ 146359743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 146459743Sgroudier struct sym_ccbh ccb_head; 146559743Sgroudier struct sym_tcbh tcb_head; 146659743Sgroudier struct sym_lcbh lcb_head; 146759743Sgroudier#endif 146859743Sgroudier /* 1469178466Smarius * Idle task and invalid task actions and 147053790Sobrien * their bus addresses. 147153790Sobrien */ 147253790Sobrien struct sym_actscr idletask, notask, bad_itl, bad_itlq; 147353790Sobrien vm_offset_t idletask_ba, notask_ba, bad_itl_ba, bad_itlq_ba; 147453790Sobrien 147553790Sobrien /* 1476178466Smarius * Dummy lun table to protect us against target 147753790Sobrien * returning bad lun number on reselection. 147853790Sobrien */ 147953790Sobrien u32 *badluntbl; /* Table physical address */ 148053790Sobrien u32 badlun_sa; /* SCRIPT handler BUS address */ 148153790Sobrien 148253790Sobrien /* 148358927Sgroudier * Bus address of this host control block. 148458927Sgroudier */ 148558927Sgroudier u32 hcb_ba; 148658927Sgroudier 148758927Sgroudier /* 148853790Sobrien * Bit 32-63 of the on-chip RAM bus address in LE format. 1489178466Smarius * The START_RAM64 script loads the MMRS and MMWS from this 149053790Sobrien * field. 149153790Sobrien */ 149253790Sobrien u32 scr_ram_seg; 149353790Sobrien 149453790Sobrien /* 149553790Sobrien * Chip and controller indentification. 149653790Sobrien */ 149753790Sobrien device_t device; 149853790Sobrien 149953790Sobrien /* 150053790Sobrien * Initial value of some IO register bits. 1501178466Smarius * These values are assumed to have been set by BIOS, and may 150253790Sobrien * be used to probe adapter implementation differences. 150353790Sobrien */ 150453790Sobrien u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4, 150553796Sobrien sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_scntl4, 150653796Sobrien sv_stest1; 150753790Sobrien 150853790Sobrien /* 1509178466Smarius * Actual initial value of IO register bits used by the 1510178466Smarius * driver. They are loaded at initialisation according to 151153790Sobrien * features that are to be enabled/disabled. 151253790Sobrien */ 1513178466Smarius u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, 151453790Sobrien rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4; 151553790Sobrien 151653790Sobrien /* 151762422Sgroudier * Target data. 151853790Sobrien */ 1519171524Sse#ifdef __amd64__ 1520171524Sse struct sym_tcb *target; 1521171524Sse#else 152254690Sobrien struct sym_tcb target[SYM_CONF_MAX_TARGET]; 1523171524Sse#endif 152453790Sobrien 152553790Sobrien /* 1526178466Smarius * Target control block bus address array used by the SCRIPT 152753790Sobrien * on reselection. 152853790Sobrien */ 152953790Sobrien u32 *targtbl; 153059743Sgroudier u32 targtbl_ba; 153153790Sobrien 153253790Sobrien /* 153353790Sobrien * CAM SIM information for this instance. 153453790Sobrien */ 153553790Sobrien struct cam_sim *sim; 153653790Sobrien struct cam_path *path; 153753790Sobrien 153853790Sobrien /* 153953790Sobrien * Allocated hardware resources. 154053790Sobrien */ 154153790Sobrien struct resource *irq_res; 154253790Sobrien struct resource *io_res; 154353790Sobrien struct resource *mmio_res; 154453790Sobrien struct resource *ram_res; 154553790Sobrien int ram_id; 154653790Sobrien void *intr; 154753790Sobrien 154853790Sobrien /* 154953790Sobrien * Bus stuff. 155053790Sobrien * 1551178466Smarius * My understanding of PCI is that all agents must share the 155253790Sobrien * same addressing range and model. 1553178466Smarius * But some hardware architecture guys provide complex and 155453790Sobrien * brain-deaded stuff that makes shit. 1555178466Smarius * This driver only support PCI compliant implementations and 1556178466Smarius * deals with part of the BUS stuff complexity only to fit O/S 155753790Sobrien * requirements. 155853790Sobrien */ 155953790Sobrien 156053790Sobrien /* 156158927Sgroudier * DMA stuff. 156258927Sgroudier */ 156358927Sgroudier bus_dma_tag_t bus_dmat; /* DMA tag from parent BUS */ 156458927Sgroudier bus_dma_tag_t data_dmat; /* DMA tag for user data */ 156558927Sgroudier /* 1566178468Smarius * BUS addresses of the chip 156753790Sobrien */ 156853790Sobrien vm_offset_t mmio_ba; /* MMIO BUS address */ 156953790Sobrien int mmio_ws; /* MMIO Window size */ 157053790Sobrien 157153790Sobrien vm_offset_t ram_ba; /* RAM BUS address */ 157253790Sobrien int ram_ws; /* RAM window size */ 157353790Sobrien 157453790Sobrien /* 157553790Sobrien * SCRIPTS virtual and physical bus addresses. 157653790Sobrien * 'script' is loaded in the on-chip RAM if present. 1577178466Smarius * 'scripth' stays in main memory for all chips except the 157853790Sobrien * 53C895A, 53C896 and 53C1010 that provide 8K on-chip RAM. 157953790Sobrien */ 158059743Sgroudier u_char *scripta0; /* Copies of script and scripth */ 158159743Sgroudier u_char *scriptb0; /* Copies of script and scripth */ 158259292Sgroudier vm_offset_t scripta_ba; /* Actual script and scripth */ 158359292Sgroudier vm_offset_t scriptb_ba; /* bus addresses. */ 158459292Sgroudier vm_offset_t scriptb0_ba; 158559743Sgroudier u_short scripta_sz; /* Actual size of script A */ 158659743Sgroudier u_short scriptb_sz; /* Actual size of script B */ 158753790Sobrien 158853790Sobrien /* 1589178466Smarius * Bus addresses, setup and patch methods for 159059743Sgroudier * the selected firmware. 159159743Sgroudier */ 159259743Sgroudier struct sym_fwa_ba fwa_bas; /* Useful SCRIPTA bus addresses */ 159359743Sgroudier struct sym_fwb_ba fwb_bas; /* Useful SCRIPTB bus addresses */ 1594179029Smarius void (*fw_setup)(hcb_p np, const struct sym_fw *fw); 159559743Sgroudier void (*fw_patch)(hcb_p np); 1596179029Smarius const char *fw_name; 159759743Sgroudier 159859743Sgroudier /* 159953790Sobrien * General controller parameters and configuration. 160053790Sobrien */ 160153790Sobrien u_short device_id; /* PCI device id */ 160253790Sobrien u_char revision_id; /* PCI device revision id */ 160353790Sobrien u_int features; /* Chip features map */ 160453790Sobrien u_char myaddr; /* SCSI id of the adapter */ 160553790Sobrien u_char maxburst; /* log base 2 of dwords burst */ 160653790Sobrien u_char maxwide; /* Maximum transfer width */ 160753790Sobrien u_char minsync; /* Min sync period factor (ST) */ 160853790Sobrien u_char maxsync; /* Max sync period factor (ST) */ 160960134Sgroudier u_char maxoffs; /* Max scsi offset (ST) */ 161053790Sobrien u_char minsync_dt; /* Min sync period factor (DT) */ 161153790Sobrien u_char maxsync_dt; /* Max sync period factor (DT) */ 161260134Sgroudier u_char maxoffs_dt; /* Max scsi offset (DT) */ 161353790Sobrien u_char multiplier; /* Clock multiplier (1,2,4) */ 161453790Sobrien u_char clock_divn; /* Number of clock divisors */ 161561051Sgroudier u32 clock_khz; /* SCSI clock frequency in KHz */ 161661051Sgroudier u32 pciclk_khz; /* Estimated PCI clock in KHz */ 161753790Sobrien /* 161853790Sobrien * Start queue management. 1619178466Smarius * It is filled up by the host processor and accessed by the 162053790Sobrien * SCRIPTS processor in order to start SCSI commands. 162153790Sobrien */ 162253790Sobrien volatile /* Prevent code optimizations */ 162358927Sgroudier u32 *squeue; /* Start queue virtual address */ 162458927Sgroudier u32 squeue_ba; /* Start queue BUS address */ 162553790Sobrien u_short squeueput; /* Next free slot of the queue */ 162653790Sobrien u_short actccbs; /* Number of allocated CCBs */ 162753790Sobrien 162853790Sobrien /* 162953790Sobrien * Command completion queue. 163053790Sobrien * It is the same size as the start queue to avoid overflow. 163153790Sobrien */ 163253790Sobrien u_short dqueueget; /* Next position to scan */ 163353790Sobrien volatile /* Prevent code optimizations */ 163453790Sobrien u32 *dqueue; /* Completion (done) queue */ 163559743Sgroudier u32 dqueue_ba; /* Done queue BUS address */ 163653790Sobrien 163753790Sobrien /* 163853790Sobrien * Miscellaneous buffers accessed by the scripts-processor. 1639178466Smarius * They shall be DWORD aligned, because they may be read or 164053790Sobrien * written with a script command. 164153790Sobrien */ 164253790Sobrien u_char msgout[8]; /* Buffer for MESSAGE OUT */ 164353790Sobrien u_char msgin [8]; /* Buffer for MESSAGE IN */ 164453790Sobrien u32 lastmsg; /* Last SCSI message sent */ 164553790Sobrien u_char scratch; /* Scratch for SCSI receive */ 164653790Sobrien 164753790Sobrien /* 164853790Sobrien * Miscellaneous configuration and status parameters. 164953790Sobrien */ 165055628Sgroudier u_char usrflags; /* Miscellaneous user flags */ 165153790Sobrien u_char scsi_mode; /* Current SCSI BUS mode */ 165253790Sobrien u_char verbose; /* Verbosity for this controller*/ 165353790Sobrien u32 cache; /* Used for cache test at init. */ 165453790Sobrien 165553790Sobrien /* 165653790Sobrien * CCB lists and queue. 165753790Sobrien */ 165853790Sobrien ccb_p ccbh[CCB_HASH_SIZE]; /* CCB hashed by DSA value */ 165953790Sobrien SYM_QUEHEAD free_ccbq; /* Queue of available CCBs */ 166053790Sobrien SYM_QUEHEAD busy_ccbq; /* Queue of busy CCBs */ 166153790Sobrien 166253790Sobrien /* 166353790Sobrien * During error handling and/or recovery, 1664178466Smarius * active CCBs that are to be completed with 166553790Sobrien * error or requeued are moved from the busy_ccbq 166653790Sobrien * to the comp_ccbq prior to completion. 166753790Sobrien */ 166853790Sobrien SYM_QUEHEAD comp_ccbq; 166953790Sobrien 167053790Sobrien /* 167153790Sobrien * CAM CCB pending queue. 167253790Sobrien */ 167353790Sobrien SYM_QUEHEAD cam_ccbq; 167453790Sobrien 167553790Sobrien /* 167653790Sobrien * IMMEDIATE ARBITRATION (IARB) control. 167753790Sobrien * 1678178466Smarius * We keep track in 'last_cp' of the last CCB that has been 1679178466Smarius * queued to the SCRIPTS processor and clear 'last_cp' when 1680178466Smarius * this CCB completes. If last_cp is not zero at the moment 1681178466Smarius * we queue a new CCB, we set a flag in 'last_cp' that is 168253790Sobrien * used by the SCRIPTS as a hint for setting IARB. 1683178466Smarius * We donnot set more than 'iarb_max' consecutive hints for 168453790Sobrien * IARB in order to leave devices a chance to reselect. 168553790Sobrien * By the way, any non zero value of 'iarb_max' is unfair. :) 168653790Sobrien */ 168754690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 168853790Sobrien u_short iarb_max; /* Max. # consecutive IARB hints*/ 168953790Sobrien u_short iarb_count; /* Actual # of these hints */ 169053790Sobrien ccb_p last_cp; 169153790Sobrien#endif 169253790Sobrien 169353790Sobrien /* 169453790Sobrien * Command abort handling. 1695178466Smarius * We need to synchronize tightly with the SCRIPTS 169653790Sobrien * processor in order to handle things correctly. 169753790Sobrien */ 169853790Sobrien u_char abrt_msg[4]; /* Message to send buffer */ 169953790Sobrien struct sym_tblmove abrt_tbl; /* Table for the MOV of it */ 170053790Sobrien struct sym_tblsel abrt_sel; /* Sync params for selection */ 170153790Sobrien u_char istat_sem; /* Tells the chip to stop (SEM) */ 170253790Sobrien}; 170353790Sobrien 170459743Sgroudier#define HCB_BA(np, lbl) (np->hcb_ba + offsetof(struct sym_hcb, lbl)) 170553790Sobrien 170653790Sobrien/* 170759743Sgroudier * Return the name of the controller. 170853790Sobrien */ 1709179029Smariusstatic __inline const char *sym_name(hcb_p np) 171059743Sgroudier{ 1711179029Smarius return device_get_nameunit(np->device); 171259743Sgroudier} 171353790Sobrien 171459743Sgroudier/*--------------------------------------------------------------------------*/ 171559743Sgroudier/*------------------------------ FIRMWARES ---------------------------------*/ 171659743Sgroudier/*--------------------------------------------------------------------------*/ 171759743Sgroudier 171853790Sobrien/* 171959743Sgroudier * This stuff will be moved to a separate source file when 172059743Sgroudier * the driver will be broken into several source modules. 172153790Sobrien */ 172253790Sobrien 172353790Sobrien/* 172459743Sgroudier * Macros used for all firmwares. 172553790Sobrien */ 172659743Sgroudier#define SYM_GEN_A(s, label) ((short) offsetof(s, label)), 172759743Sgroudier#define SYM_GEN_B(s, label) ((short) offsetof(s, label)), 172859743Sgroudier#define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label) 172959743Sgroudier#define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label) 173053790Sobrien 173159743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 173259743Sgroudier/* 173359743Sgroudier * Allocate firmware #1 script area. 173459743Sgroudier */ 173559743Sgroudier#define SYM_FWA_SCR sym_fw1a_scr 173659743Sgroudier#define SYM_FWB_SCR sym_fw1b_scr 173759743Sgroudier#include <dev/sym/sym_fw1.h> 1738179029Smariusstatic const struct sym_fwa_ofs sym_fw1a_ofs = { 173959743Sgroudier SYM_GEN_FW_A(struct SYM_FWA_SCR) 174053790Sobrien}; 1741179029Smariusstatic const struct sym_fwb_ofs sym_fw1b_ofs = { 174259743Sgroudier SYM_GEN_FW_B(struct SYM_FWB_SCR) 174359743Sgroudier}; 174459743Sgroudier#undef SYM_FWA_SCR 174559743Sgroudier#undef SYM_FWB_SCR 174659743Sgroudier#endif /* SYM_CONF_GENERIC_SUPPORT */ 174753790Sobrien 174853790Sobrien/* 174959743Sgroudier * Allocate firmware #2 script area. 175053790Sobrien */ 175159743Sgroudier#define SYM_FWA_SCR sym_fw2a_scr 175259743Sgroudier#define SYM_FWB_SCR sym_fw2b_scr 175359743Sgroudier#include <dev/sym/sym_fw2.h> 1754179029Smariusstatic const struct sym_fwa_ofs sym_fw2a_ofs = { 175559743Sgroudier SYM_GEN_FW_A(struct SYM_FWA_SCR) 175659743Sgroudier}; 1757179029Smariusstatic const struct sym_fwb_ofs sym_fw2b_ofs = { 175859743Sgroudier SYM_GEN_FW_B(struct SYM_FWB_SCR) 175959743Sgroudier SYM_GEN_B(struct SYM_FWB_SCR, start64) 176059743Sgroudier SYM_GEN_B(struct SYM_FWB_SCR, pm_handle) 176159743Sgroudier}; 176259743Sgroudier#undef SYM_FWA_SCR 176359743Sgroudier#undef SYM_FWB_SCR 176453790Sobrien 176559743Sgroudier#undef SYM_GEN_A 176659743Sgroudier#undef SYM_GEN_B 176759743Sgroudier#undef PADDR_A 176859743Sgroudier#undef PADDR_B 176953790Sobrien 177059743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 177153790Sobrien/* 177259743Sgroudier * Patch routine for firmware #1. 177353790Sobrien */ 177459743Sgroudierstatic void 177559743Sgroudiersym_fw1_patch(hcb_p np) 177653790Sobrien{ 177759743Sgroudier struct sym_fw1a_scr *scripta0; 177859743Sgroudier struct sym_fw1b_scr *scriptb0; 177953790Sobrien 178059743Sgroudier scripta0 = (struct sym_fw1a_scr *) np->scripta0; 178159743Sgroudier scriptb0 = (struct sym_fw1b_scr *) np->scriptb0; 178253790Sobrien 178353790Sobrien /* 178459743Sgroudier * Remove LED support if not needed. 178553790Sobrien */ 178659743Sgroudier if (!(np->features & FE_LED0)) { 178759743Sgroudier scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); 178859743Sgroudier scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); 178959743Sgroudier scripta0->start[0] = cpu_to_scr(SCR_NO_OP); 179059743Sgroudier } 179159743Sgroudier 179254690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 179353790Sobrien /* 179459743Sgroudier * If user does not want to use IMMEDIATE ARBITRATION 179559743Sgroudier * when we are reselected while attempting to arbitrate, 179659743Sgroudier * patch the SCRIPTS accordingly with a SCRIPT NO_OP. 179753790Sobrien */ 179859743Sgroudier if (!SYM_CONF_SET_IARB_ON_ARB_LOST) 179959743Sgroudier scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); 180053790Sobrien#endif 180153790Sobrien /* 180259743Sgroudier * Patch some data in SCRIPTS. 180359743Sgroudier * - start and done queue initial bus address. 180459743Sgroudier * - target bus address table bus address. 180553790Sobrien */ 180659743Sgroudier scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); 180759743Sgroudier scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); 180859743Sgroudier scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); 180959743Sgroudier} 181059743Sgroudier#endif /* SYM_CONF_GENERIC_SUPPORT */ 181159743Sgroudier 181259743Sgroudier/* 181362422Sgroudier * Patch routine for firmware #2. 181459743Sgroudier */ 181559743Sgroudierstatic void 181659743Sgroudiersym_fw2_patch(hcb_p np) 181759743Sgroudier{ 181859743Sgroudier struct sym_fw2a_scr *scripta0; 181959743Sgroudier struct sym_fw2b_scr *scriptb0; 182059743Sgroudier 182159743Sgroudier scripta0 = (struct sym_fw2a_scr *) np->scripta0; 182259743Sgroudier scriptb0 = (struct sym_fw2b_scr *) np->scriptb0; 182359743Sgroudier 182453790Sobrien /* 182559743Sgroudier * Remove LED support if not needed. 182653790Sobrien */ 182759743Sgroudier if (!(np->features & FE_LED0)) { 182859743Sgroudier scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); 182959743Sgroudier scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); 183059743Sgroudier scripta0->start[0] = cpu_to_scr(SCR_NO_OP); 183159743Sgroudier } 183259743Sgroudier 183354690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 183453790Sobrien /* 183559743Sgroudier * If user does not want to use IMMEDIATE ARBITRATION 183659743Sgroudier * when we are reselected while attempting to arbitrate, 183759743Sgroudier * patch the SCRIPTS accordingly with a SCRIPT NO_OP. 183853790Sobrien */ 183959743Sgroudier if (!SYM_CONF_SET_IARB_ON_ARB_LOST) 184059743Sgroudier scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); 184153790Sobrien#endif 184253790Sobrien /* 184359743Sgroudier * Patch some variable in SCRIPTS. 184459743Sgroudier * - start and done queue initial bus address. 184559743Sgroudier * - target bus address table bus address. 184653790Sobrien */ 184759743Sgroudier scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); 184859743Sgroudier scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); 184959743Sgroudier scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); 185059743Sgroudier 185153790Sobrien /* 185259743Sgroudier * Remove the load of SCNTL4 on reselection if not a C10. 185353790Sobrien */ 185459743Sgroudier if (!(np->features & FE_C10)) { 185559743Sgroudier scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP); 185659743Sgroudier scripta0->resel_scntl4[1] = cpu_to_scr(0); 185759743Sgroudier } 185859743Sgroudier 185953790Sobrien /* 1860178466Smarius * Remove a couple of work-arounds specific to C1010 if 186160134Sgroudier * they are not desirable. See `sym_fw2.h' for more details. 186260134Sgroudier */ 186361051Sgroudier if (!(np->device_id == PCI_ID_LSI53C1010_2 && 186471742Sgroudier np->revision_id < 0x1 && 186561051Sgroudier np->pciclk_khz < 60000)) { 186660134Sgroudier scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP); 186760134Sgroudier scripta0->datao_phase[1] = cpu_to_scr(0); 186860134Sgroudier } 186961051Sgroudier if (!(np->device_id == PCI_ID_LSI53C1010 && 187061051Sgroudier /* np->revision_id < 0xff */ 1)) { 187160134Sgroudier scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP); 187260134Sgroudier scripta0->sel_done[1] = cpu_to_scr(0); 187360134Sgroudier } 187460134Sgroudier 187560134Sgroudier /* 187659743Sgroudier * Patch some other variables in SCRIPTS. 187759743Sgroudier * These ones are loaded by the SCRIPTS processor. 187853790Sobrien */ 187959743Sgroudier scriptb0->pm0_data_addr[0] = 1880178466Smarius cpu_to_scr(np->scripta_ba + 188159743Sgroudier offsetof(struct sym_fw2a_scr, pm0_data)); 188259743Sgroudier scriptb0->pm1_data_addr[0] = 1883178466Smarius cpu_to_scr(np->scripta_ba + 188459743Sgroudier offsetof(struct sym_fw2a_scr, pm1_data)); 188559743Sgroudier} 188653790Sobrien 188753790Sobrien/* 188859743Sgroudier * Fill the data area in scripts. 188959743Sgroudier * To be done for all firmwares. 189053790Sobrien */ 189159743Sgroudierstatic void 189259743Sgroudiersym_fw_fill_data (u32 *in, u32 *out) 189359743Sgroudier{ 189459743Sgroudier int i; 189559743Sgroudier 189659743Sgroudier for (i = 0; i < SYM_CONF_MAX_SG; i++) { 189759743Sgroudier *in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN; 189859743Sgroudier *in++ = offsetof (struct sym_dsb, data[i]); 189959743Sgroudier *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT; 190059743Sgroudier *out++ = offsetof (struct sym_dsb, data[i]); 190159743Sgroudier } 190259743Sgroudier} 190359743Sgroudier 190453790Sobrien/* 190559743Sgroudier * Setup useful script bus addresses. 190659743Sgroudier * To be done for all firmwares. 190753790Sobrien */ 1908178466Smariusstatic void 1909179029Smariussym_fw_setup_bus_addresses(hcb_p np, const struct sym_fw *fw) 191059743Sgroudier{ 191159743Sgroudier u32 *pa; 1912179029Smarius const u_short *po; 191359743Sgroudier int i; 191459743Sgroudier 191553790Sobrien /* 1916178466Smarius * Build the bus address table for script A 191759743Sgroudier * from the script A offset table. 191853790Sobrien */ 1919179029Smarius po = (const u_short *) fw->a_ofs; 192059743Sgroudier pa = (u32 *) &np->fwa_bas; 192159743Sgroudier for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++) 192259743Sgroudier pa[i] = np->scripta_ba + po[i]; 192359743Sgroudier 192458927Sgroudier /* 192559743Sgroudier * Same for script B. 192658927Sgroudier */ 1927179029Smarius po = (const u_short *) fw->b_ofs; 192859743Sgroudier pa = (u32 *) &np->fwb_bas; 192959743Sgroudier for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++) 193059743Sgroudier pa[i] = np->scriptb_ba + po[i]; 193159743Sgroudier} 193259743Sgroudier 193359743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 193459743Sgroudier/* 193559743Sgroudier * Setup routine for firmware #1. 193659743Sgroudier */ 1937178466Smariusstatic void 1938179029Smariussym_fw1_setup(hcb_p np, const struct sym_fw *fw) 193959743Sgroudier{ 194059743Sgroudier struct sym_fw1a_scr *scripta0; 194159743Sgroudier 194259743Sgroudier scripta0 = (struct sym_fw1a_scr *) np->scripta0; 194359743Sgroudier 194458927Sgroudier /* 194559743Sgroudier * Fill variable parts in scripts. 194658927Sgroudier */ 194759743Sgroudier sym_fw_fill_data(scripta0->data_in, scripta0->data_out); 194853790Sobrien 194953790Sobrien /* 195059743Sgroudier * Setup bus addresses used from the C code.. 195153790Sobrien */ 195259743Sgroudier sym_fw_setup_bus_addresses(np, fw); 195359743Sgroudier} 195459743Sgroudier#endif /* SYM_CONF_GENERIC_SUPPORT */ 195553790Sobrien 195659743Sgroudier/* 195762422Sgroudier * Setup routine for firmware #2. 195859743Sgroudier */ 1959178466Smariusstatic void 1960179029Smariussym_fw2_setup(hcb_p np, const struct sym_fw *fw) 196159743Sgroudier{ 196259743Sgroudier struct sym_fw2a_scr *scripta0; 196359743Sgroudier 196459743Sgroudier scripta0 = (struct sym_fw2a_scr *) np->scripta0; 196559743Sgroudier 196653790Sobrien /* 196759743Sgroudier * Fill variable parts in scripts. 196853790Sobrien */ 196959743Sgroudier sym_fw_fill_data(scripta0->data_in, scripta0->data_out); 197053790Sobrien 197153790Sobrien /* 197259743Sgroudier * Setup bus addresses used from the C code.. 197353790Sobrien */ 197459743Sgroudier sym_fw_setup_bus_addresses(np, fw); 197559743Sgroudier} 197653790Sobrien 197753790Sobrien/* 197859743Sgroudier * Allocate firmware descriptors. 197953790Sobrien */ 198059743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 1981179029Smariusstatic const struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic"); 198259743Sgroudier#endif /* SYM_CONF_GENERIC_SUPPORT */ 1983179029Smariusstatic const struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based"); 198459743Sgroudier 198559743Sgroudier/* 198659743Sgroudier * Find the most appropriate firmware for a chip. 198759743Sgroudier */ 1988179029Smariusstatic const struct sym_fw * 1989179029Smariussym_find_firmware(const struct sym_pci_chip *chip) 199053790Sobrien{ 199159743Sgroudier if (chip->features & FE_LDSTR) 199259743Sgroudier return &sym_fw2; 199359743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 199465404Sgroudier else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC))) 199559743Sgroudier return &sym_fw1; 199659743Sgroudier#endif 199759743Sgroudier else 1998178466Smarius return NULL; 199953790Sobrien} 200053790Sobrien 200153790Sobrien/* 200259743Sgroudier * Bind a script to physical addresses. 200353790Sobrien */ 200459743Sgroudierstatic void sym_fw_bind_script (hcb_p np, u32 *start, int len) 200553790Sobrien{ 200653790Sobrien u32 opcode, new, old, tmp1, tmp2; 200759743Sgroudier u32 *end, *cur; 200853790Sobrien int relocs; 200953790Sobrien 201059743Sgroudier cur = start; 201159743Sgroudier end = start + len/4; 201253790Sobrien 201359743Sgroudier while (cur < end) { 201453790Sobrien 201559743Sgroudier opcode = *cur; 201653790Sobrien 201753790Sobrien /* 201853790Sobrien * If we forget to change the length 201953790Sobrien * in scripts, a field will be 202053790Sobrien * padded with 0. This is an illegal 202153790Sobrien * command. 202253790Sobrien */ 202353790Sobrien if (opcode == 0) { 202453790Sobrien printf ("%s: ERROR0 IN SCRIPT at %d.\n", 202559743Sgroudier sym_name(np), (int) (cur-start)); 202653790Sobrien MDELAY (10000); 202759743Sgroudier ++cur; 202853790Sobrien continue; 202953790Sobrien }; 203053790Sobrien 203153790Sobrien /* 203253790Sobrien * We use the bogus value 0xf00ff00f ;-) 203353790Sobrien * to reserve data area in SCRIPTS. 203453790Sobrien */ 203553790Sobrien if (opcode == SCR_DATA_ZERO) { 203659743Sgroudier *cur++ = 0; 203753790Sobrien continue; 203853790Sobrien } 203953790Sobrien 204053790Sobrien if (DEBUG_FLAGS & DEBUG_SCRIPT) 204162134Sgroudier printf ("%d: <%x>\n", (int) (cur-start), 204262134Sgroudier (unsigned)opcode); 204353790Sobrien 204453790Sobrien /* 204553790Sobrien * We don't have to decode ALL commands 204653790Sobrien */ 204753790Sobrien switch (opcode >> 28) { 204853790Sobrien case 0xf: 204953790Sobrien /* 205053790Sobrien * LOAD / STORE DSA relative, don't relocate. 205153790Sobrien */ 205253790Sobrien relocs = 0; 205353790Sobrien break; 205453790Sobrien case 0xe: 205553790Sobrien /* 205653790Sobrien * LOAD / STORE absolute. 205753790Sobrien */ 205853790Sobrien relocs = 1; 205953790Sobrien break; 206053790Sobrien case 0xc: 206153790Sobrien /* 206253790Sobrien * COPY has TWO arguments. 206353790Sobrien */ 206453790Sobrien relocs = 2; 206559743Sgroudier tmp1 = cur[1]; 206659743Sgroudier tmp2 = cur[2]; 206753790Sobrien if ((tmp1 ^ tmp2) & 3) { 206853790Sobrien printf ("%s: ERROR1 IN SCRIPT at %d.\n", 206959743Sgroudier sym_name(np), (int) (cur-start)); 207059743Sgroudier MDELAY (10000); 207153790Sobrien } 207253790Sobrien /* 2073178466Smarius * If PREFETCH feature not enabled, remove 207453790Sobrien * the NO FLUSH bit if present. 207553790Sobrien */ 207653790Sobrien if ((opcode & SCR_NO_FLUSH) && 207753790Sobrien !(np->features & FE_PFEN)) { 207859743Sgroudier opcode = (opcode & ~SCR_NO_FLUSH); 207953790Sobrien } 208053790Sobrien break; 208153790Sobrien case 0x0: 208253790Sobrien /* 208353790Sobrien * MOVE/CHMOV (absolute address) 208453790Sobrien */ 208553790Sobrien if (!(np->features & FE_WIDE)) 208659743Sgroudier opcode = (opcode | OPC_MOVE); 208753790Sobrien relocs = 1; 208853790Sobrien break; 208953790Sobrien case 0x1: 209053790Sobrien /* 209153790Sobrien * MOVE/CHMOV (table indirect) 209253790Sobrien */ 209353790Sobrien if (!(np->features & FE_WIDE)) 209459743Sgroudier opcode = (opcode | OPC_MOVE); 209553790Sobrien relocs = 0; 209653790Sobrien break; 209753790Sobrien case 0x8: 209853790Sobrien /* 209953790Sobrien * JUMP / CALL 210053790Sobrien * dont't relocate if relative :-) 210153790Sobrien */ 210253790Sobrien if (opcode & 0x00800000) 210353790Sobrien relocs = 0; 210453790Sobrien else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/ 210553790Sobrien relocs = 2; 210653790Sobrien else 210753790Sobrien relocs = 1; 210853790Sobrien break; 210953790Sobrien case 0x4: 211053790Sobrien case 0x5: 211153790Sobrien case 0x6: 211253790Sobrien case 0x7: 211353790Sobrien relocs = 1; 211453790Sobrien break; 211553790Sobrien default: 211653790Sobrien relocs = 0; 211753790Sobrien break; 211853790Sobrien }; 211953790Sobrien 212059743Sgroudier /* 212159743Sgroudier * Scriptify:) the opcode. 212259743Sgroudier */ 212359743Sgroudier *cur++ = cpu_to_scr(opcode); 212459743Sgroudier 212559743Sgroudier /* 2126178466Smarius * If no relocation, assume 1 argument 212759743Sgroudier * and just scriptize:) it. 212859743Sgroudier */ 212953790Sobrien if (!relocs) { 213059743Sgroudier *cur = cpu_to_scr(*cur); 213159743Sgroudier ++cur; 213253790Sobrien continue; 213353790Sobrien } 213459743Sgroudier 213559743Sgroudier /* 213659743Sgroudier * Otherwise performs all needed relocations. 213759743Sgroudier */ 213853790Sobrien while (relocs--) { 213959743Sgroudier old = *cur; 214053790Sobrien 214153790Sobrien switch (old & RELOC_MASK) { 214253790Sobrien case RELOC_REGISTER: 214353790Sobrien new = (old & ~RELOC_MASK) + np->mmio_ba; 214453790Sobrien break; 214559743Sgroudier case RELOC_LABEL_A: 214659292Sgroudier new = (old & ~RELOC_MASK) + np->scripta_ba; 214753790Sobrien break; 214859743Sgroudier case RELOC_LABEL_B: 214959292Sgroudier new = (old & ~RELOC_MASK) + np->scriptb_ba; 215053790Sobrien break; 215153790Sobrien case RELOC_SOFTC: 215258927Sgroudier new = (old & ~RELOC_MASK) + np->hcb_ba; 215353790Sobrien break; 215453790Sobrien case 0: 215559743Sgroudier /* 215659743Sgroudier * Don't relocate a 0 address. 2157178466Smarius * They are mostly used for patched or 215859743Sgroudier * script self-modified areas. 215959743Sgroudier */ 216053790Sobrien if (old == 0) { 216153790Sobrien new = old; 216253790Sobrien break; 216353790Sobrien } 216453790Sobrien /* fall through */ 216553790Sobrien default: 216659743Sgroudier new = 0; 216759743Sgroudier panic("sym_fw_bind_script: " 216853790Sobrien "weird relocation %x\n", old); 216953790Sobrien break; 217053790Sobrien } 217153790Sobrien 217259743Sgroudier *cur++ = cpu_to_scr(new); 217353790Sobrien } 217453790Sobrien }; 217553790Sobrien} 217653790Sobrien 2177167248Sthomas/*---------------------------------------------------------------------------*/ 2178167248Sthomas/*--------------------------- END OF FIRMWARES -----------------------------*/ 2179167248Sthomas/*---------------------------------------------------------------------------*/ 218059743Sgroudier 218153790Sobrien/* 218259743Sgroudier * Function prototypes. 218359743Sgroudier */ 218459743Sgroudierstatic void sym_save_initial_setting (hcb_p np); 218559743Sgroudierstatic int sym_prepare_setting (hcb_p np, struct sym_nvram *nvram); 218659743Sgroudierstatic int sym_prepare_nego (hcb_p np, ccb_p cp, int nego, u_char *msgptr); 218759743Sgroudierstatic void sym_put_start_queue (hcb_p np, ccb_p cp); 218859743Sgroudierstatic void sym_chip_reset (hcb_p np); 218959743Sgroudierstatic void sym_soft_reset (hcb_p np); 219059743Sgroudierstatic void sym_start_reset (hcb_p np); 219159743Sgroudierstatic int sym_reset_scsi_bus (hcb_p np, int enab_int); 219259743Sgroudierstatic int sym_wakeup_done (hcb_p np); 219359743Sgroudierstatic void sym_flush_busy_queue (hcb_p np, int cam_status); 219459743Sgroudierstatic void sym_flush_comp_queue (hcb_p np, int cam_status); 219559743Sgroudierstatic void sym_init (hcb_p np, int reason); 219659743Sgroudierstatic int sym_getsync(hcb_p np, u_char dt, u_char sfac, u_char *divp, 219759743Sgroudier u_char *fakp); 219859743Sgroudierstatic void sym_setsync (hcb_p np, ccb_p cp, u_char ofs, u_char per, 219959743Sgroudier u_char div, u_char fak); 220059743Sgroudierstatic void sym_setwide (hcb_p np, ccb_p cp, u_char wide); 220159743Sgroudierstatic void sym_setpprot(hcb_p np, ccb_p cp, u_char dt, u_char ofs, 220259743Sgroudier u_char per, u_char wide, u_char div, u_char fak); 220359743Sgroudierstatic void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs, 220459743Sgroudier u_char per, u_char wide, u_char div, u_char fak); 220559743Sgroudierstatic void sym_log_hard_error (hcb_p np, u_short sist, u_char dstat); 220659743Sgroudierstatic void sym_intr (void *arg); 220759743Sgroudierstatic void sym_poll (struct cam_sim *sim); 220859743Sgroudierstatic void sym_recover_scsi_int (hcb_p np, u_char hsts); 220959743Sgroudierstatic void sym_int_sto (hcb_p np); 221059743Sgroudierstatic void sym_int_udc (hcb_p np); 221159743Sgroudierstatic void sym_int_sbmc (hcb_p np); 221259743Sgroudierstatic void sym_int_par (hcb_p np, u_short sist); 221359743Sgroudierstatic void sym_int_ma (hcb_p np); 2214178466Smariusstatic int sym_dequeue_from_squeue(hcb_p np, int i, int target, int lun, 221559743Sgroudier int task); 2216251572Smariusstatic void sym_sir_bad_scsi_status (hcb_p np, ccb_p cp); 221759743Sgroudierstatic int sym_clear_tasks (hcb_p np, int status, int targ, int lun, int task); 221859743Sgroudierstatic void sym_sir_task_recovery (hcb_p np, int num); 221959743Sgroudierstatic int sym_evaluate_dp (hcb_p np, ccb_p cp, u32 scr, int *ofs); 2220251572Smariusstatic void sym_modify_dp(hcb_p np, ccb_p cp, int ofs); 222159743Sgroudierstatic int sym_compute_residual (hcb_p np, ccb_p cp); 222259743Sgroudierstatic int sym_show_msg (u_char * msg); 222359743Sgroudierstatic void sym_print_msg (ccb_p cp, char *label, u_char *msg); 222459743Sgroudierstatic void sym_sync_nego (hcb_p np, tcb_p tp, ccb_p cp); 222559743Sgroudierstatic void sym_ppr_nego (hcb_p np, tcb_p tp, ccb_p cp); 222659743Sgroudierstatic void sym_wide_nego (hcb_p np, tcb_p tp, ccb_p cp); 222759743Sgroudierstatic void sym_nego_default (hcb_p np, tcb_p tp, ccb_p cp); 222859743Sgroudierstatic void sym_nego_rejected (hcb_p np, tcb_p tp, ccb_p cp); 222959743Sgroudierstatic void sym_int_sir (hcb_p np); 223059743Sgroudierstatic void sym_free_ccb (hcb_p np, ccb_p cp); 223159743Sgroudierstatic ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order); 223259743Sgroudierstatic ccb_p sym_alloc_ccb (hcb_p np); 223361051Sgroudierstatic ccb_p sym_ccb_from_dsa (hcb_p np, u32 dsa); 223459743Sgroudierstatic lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln); 223559743Sgroudierstatic void sym_alloc_lcb_tags (hcb_p np, u_char tn, u_char ln); 223659743Sgroudierstatic int sym_snooptest (hcb_p np); 223759743Sgroudierstatic void sym_selectclock(hcb_p np, u_char scntl3); 223859743Sgroudierstatic void sym_getclock (hcb_p np, int mult); 223959743Sgroudierstatic int sym_getpciclock (hcb_p np); 224059743Sgroudierstatic void sym_complete_ok (hcb_p np, ccb_p cp); 224159743Sgroudierstatic void sym_complete_error (hcb_p np, ccb_p cp); 2242178468Smariusstatic void sym_callout (void *arg); 224359743Sgroudierstatic int sym_abort_scsiio (hcb_p np, union ccb *ccb, int timed_out); 224459743Sgroudierstatic void sym_reset_dev (hcb_p np, union ccb *ccb); 224559743Sgroudierstatic void sym_action (struct cam_sim *sim, union ccb *ccb); 224659743Sgroudierstatic int sym_setup_cdb (hcb_p np, struct ccb_scsiio *csio, ccb_p cp); 224759743Sgroudierstatic void sym_setup_data_and_start (hcb_p np, struct ccb_scsiio *csio, 224859743Sgroudier ccb_p cp); 2249178466Smariusstatic int sym_fast_scatter_sg_physical(hcb_p np, ccb_p cp, 225059743Sgroudier bus_dma_segment_t *psegs, int nsegs); 2251178466Smariusstatic int sym_scatter_sg_physical (hcb_p np, ccb_p cp, 225259743Sgroudier bus_dma_segment_t *psegs, int nsegs); 225359743Sgroudierstatic void sym_action2 (struct cam_sim *sim, union ccb *ccb); 2254251572Smariusstatic void sym_update_trans(hcb_p np, struct sym_trans *tip, 225559743Sgroudier struct ccb_trans_settings *cts); 225659743Sgroudierstatic void sym_update_dflags(hcb_p np, u_char *flags, 225759743Sgroudier struct ccb_trans_settings *cts); 225859743Sgroudier 2259179029Smariusstatic const struct sym_pci_chip *sym_find_pci_chip (device_t dev); 226059743Sgroudierstatic int sym_pci_probe (device_t dev); 226159743Sgroudierstatic int sym_pci_attach (device_t dev); 226259743Sgroudier 226359743Sgroudierstatic void sym_pci_free (hcb_p np); 226459743Sgroudierstatic int sym_cam_attach (hcb_p np); 226559743Sgroudierstatic void sym_cam_free (hcb_p np); 226659743Sgroudier 226759743Sgroudierstatic void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram); 226859743Sgroudierstatic void sym_nvram_setup_target (hcb_p np, int targ, struct sym_nvram *nvp); 226959743Sgroudierstatic int sym_read_nvram (hcb_p np, struct sym_nvram *nvp); 227059743Sgroudier 227159743Sgroudier/* 2272220944Smarius * Print something which allows to retrieve the controller type, 227353790Sobrien * unit, target, lun concerned by a kernel message. 227453790Sobrien */ 227553790Sobrienstatic void PRINT_TARGET (hcb_p np, int target) 227653790Sobrien{ 227753790Sobrien printf ("%s:%d:", sym_name(np), target); 227853790Sobrien} 227953790Sobrien 228053790Sobrienstatic void PRINT_LUN(hcb_p np, int target, int lun) 228153790Sobrien{ 228253790Sobrien printf ("%s:%d:%d:", sym_name(np), target, lun); 228353790Sobrien} 228453790Sobrien 228553790Sobrienstatic void PRINT_ADDR (ccb_p cp) 228653790Sobrien{ 228753790Sobrien if (cp && cp->cam_ccb) 228853790Sobrien xpt_print_path(cp->cam_ccb->ccb_h.path); 228953790Sobrien} 229053790Sobrien 229153790Sobrien/* 229253790Sobrien * Take into account this ccb in the freeze count. 2293178466Smarius */ 229453790Sobrienstatic void sym_freeze_cam_ccb(union ccb *ccb) 229553790Sobrien{ 229653790Sobrien if (!(ccb->ccb_h.flags & CAM_DEV_QFRZDIS)) { 229753790Sobrien if (!(ccb->ccb_h.status & CAM_DEV_QFRZN)) { 229853790Sobrien ccb->ccb_h.status |= CAM_DEV_QFRZN; 229953790Sobrien xpt_freeze_devq(ccb->ccb_h.path, 1); 230053790Sobrien } 230153790Sobrien } 230253790Sobrien} 230353790Sobrien 230453790Sobrien/* 230553790Sobrien * Set the status field of a CAM CCB. 230653790Sobrien */ 230753790Sobrienstatic __inline void sym_set_cam_status(union ccb *ccb, cam_status status) 230853790Sobrien{ 230953790Sobrien ccb->ccb_h.status &= ~CAM_STATUS_MASK; 231053790Sobrien ccb->ccb_h.status |= status; 231153790Sobrien} 231253790Sobrien 231353790Sobrien/* 231453790Sobrien * Get the status field of a CAM CCB. 231553790Sobrien */ 231653790Sobrienstatic __inline int sym_get_cam_status(union ccb *ccb) 231753790Sobrien{ 231853790Sobrien return ccb->ccb_h.status & CAM_STATUS_MASK; 231953790Sobrien} 232053790Sobrien 232153790Sobrien/* 232253790Sobrien * Enqueue a CAM CCB. 232353790Sobrien */ 2324178468Smariusstatic void sym_enqueue_cam_ccb(ccb_p cp) 232553790Sobrien{ 2326178468Smarius hcb_p np; 2327178468Smarius union ccb *ccb; 2328178468Smarius 2329178468Smarius ccb = cp->cam_ccb; 2330178468Smarius np = (hcb_p) cp->arg; 2331178468Smarius 233253790Sobrien assert(!(ccb->ccb_h.status & CAM_SIM_QUEUED)); 233353790Sobrien ccb->ccb_h.status = CAM_REQ_INPROG; 233453790Sobrien 2335178468Smarius callout_reset(&cp->ch, ccb->ccb_h.timeout * hz / 1000, sym_callout, 2336178468Smarius (caddr_t) ccb); 233753790Sobrien ccb->ccb_h.status |= CAM_SIM_QUEUED; 233853790Sobrien ccb->ccb_h.sym_hcb_ptr = np; 233953790Sobrien 234053790Sobrien sym_insque_tail(sym_qptr(&ccb->ccb_h.sim_links), &np->cam_ccbq); 234153790Sobrien} 234253790Sobrien 234353790Sobrien/* 234453790Sobrien * Complete a pending CAM CCB. 234553790Sobrien */ 2346178468Smarius 2347178468Smariusstatic void sym_xpt_done(hcb_p np, union ccb *ccb, ccb_p cp) 2348178468Smarius{ 2349251572Smarius 2350178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 2351178468Smarius 235253790Sobrien if (ccb->ccb_h.status & CAM_SIM_QUEUED) { 2353178468Smarius callout_stop(&cp->ch); 235453790Sobrien sym_remque(sym_qptr(&ccb->ccb_h.sim_links)); 235553790Sobrien ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2356178466Smarius ccb->ccb_h.sym_hcb_ptr = NULL; 235753790Sobrien } 2358251571Smarius xpt_done(ccb); 235953790Sobrien} 236053790Sobrien 236153790Sobrienstatic void sym_xpt_done2(hcb_p np, union ccb *ccb, int cam_status) 236253790Sobrien{ 2363251572Smarius 2364178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 2365178468Smarius 236653790Sobrien sym_set_cam_status(ccb, cam_status); 2367251571Smarius xpt_done(ccb); 236853790Sobrien} 236953790Sobrien 237053790Sobrien/* 237153790Sobrien * SYMBIOS chip clock divisor table. 237253790Sobrien * 2373178466Smarius * Divisors are multiplied by 10,000,000 in order to make 237453790Sobrien * calculations more simple. 237553790Sobrien */ 237653790Sobrien#define _5M 5000000 2377179029Smariusstatic const u32 div_10M[] = 2378179029Smarius {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; 237953790Sobrien 238053790Sobrien/* 238153790Sobrien * SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64, 2382178466Smarius * 128 transfers. All chips support at least 16 transfers 2383178466Smarius * bursts. The 825A, 875 and 895 chips support bursts of up 238453790Sobrien * to 128 transfers and the 895A and 896 support bursts of up 2385178466Smarius * to 64 transfers. All other chips support up to 16 238653790Sobrien * transfers bursts. 238753790Sobrien * 238853790Sobrien * For PCI 32 bit data transfers each transfer is a DWORD. 238953790Sobrien * It is a QUADWORD (8 bytes) for PCI 64 bit data transfers. 239053790Sobrien * 2391178466Smarius * We use log base 2 (burst length) as internal code, with 239253790Sobrien * value 0 meaning "burst disabled". 239353790Sobrien */ 239453790Sobrien 239553790Sobrien/* 239653790Sobrien * Burst length from burst code. 239753790Sobrien */ 239853790Sobrien#define burst_length(bc) (!(bc))? 0 : 1 << (bc) 239953790Sobrien 240053790Sobrien/* 240153790Sobrien * Burst code from io register bits. 240253790Sobrien */ 240353790Sobrien#define burst_code(dmode, ctest4, ctest5) \ 240453790Sobrien (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1 240553790Sobrien 240653790Sobrien/* 240753790Sobrien * Set initial io register bits from burst code. 240853790Sobrien */ 240953790Sobrienstatic __inline void sym_init_burst(hcb_p np, u_char bc) 241053790Sobrien{ 241153790Sobrien np->rv_ctest4 &= ~0x80; 241253790Sobrien np->rv_dmode &= ~(0x3 << 6); 241353790Sobrien np->rv_ctest5 &= ~0x4; 241453790Sobrien 241553790Sobrien if (!bc) { 241653790Sobrien np->rv_ctest4 |= 0x80; 241753790Sobrien } 241853790Sobrien else { 241953790Sobrien --bc; 242053790Sobrien np->rv_dmode |= ((bc & 0x3) << 6); 242153790Sobrien np->rv_ctest5 |= (bc & 0x4); 242253790Sobrien } 242353790Sobrien} 242453790Sobrien 242553790Sobrien/* 242653790Sobrien * Print out the list of targets that have some flag disabled by user. 242753790Sobrien */ 242853790Sobrienstatic void sym_print_targets_flag(hcb_p np, int mask, char *msg) 242953790Sobrien{ 243053790Sobrien int cnt; 243153790Sobrien int i; 243253790Sobrien 243354690Sobrien for (cnt = 0, i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 243453790Sobrien if (i == np->myaddr) 243553790Sobrien continue; 243653790Sobrien if (np->target[i].usrflags & mask) { 243753790Sobrien if (!cnt++) 243853790Sobrien printf("%s: %s disabled for targets", 243953790Sobrien sym_name(np), msg); 244053790Sobrien printf(" %d", i); 244153790Sobrien } 244253790Sobrien } 244353790Sobrien if (cnt) 244453790Sobrien printf(".\n"); 244553790Sobrien} 244653790Sobrien 244753790Sobrien/* 244853796Sobrien * Save initial settings of some IO registers. 244953796Sobrien * Assumed to have been set by BIOS. 2450178466Smarius * We cannot reset the chip prior to reading the 245153796Sobrien * IO registers, since informations will be lost. 2452178466Smarius * Since the SCRIPTS processor may be running, this 2453178466Smarius * is not safe on paper, but it seems to work quite 245453796Sobrien * well. :) 245553790Sobrien */ 245653796Sobrienstatic void sym_save_initial_setting (hcb_p np) 245753790Sobrien{ 245853790Sobrien np->sv_scntl0 = INB(nc_scntl0) & 0x0a; 245953790Sobrien np->sv_scntl3 = INB(nc_scntl3) & 0x07; 246053790Sobrien np->sv_dmode = INB(nc_dmode) & 0xce; 246153790Sobrien np->sv_dcntl = INB(nc_dcntl) & 0xa8; 246253790Sobrien np->sv_ctest3 = INB(nc_ctest3) & 0x01; 246353790Sobrien np->sv_ctest4 = INB(nc_ctest4) & 0x80; 246453790Sobrien np->sv_gpcntl = INB(nc_gpcntl); 246553796Sobrien np->sv_stest1 = INB(nc_stest1); 246653790Sobrien np->sv_stest2 = INB(nc_stest2) & 0x20; 246753790Sobrien np->sv_stest4 = INB(nc_stest4); 246853790Sobrien if (np->features & FE_C10) { /* Always large DMA fifo + ultra3 */ 246953790Sobrien np->sv_scntl4 = INB(nc_scntl4); 247053790Sobrien np->sv_ctest5 = INB(nc_ctest5) & 0x04; 247153790Sobrien } 247253790Sobrien else 247353790Sobrien np->sv_ctest5 = INB(nc_ctest5) & 0x24; 247453796Sobrien} 247553796Sobrien 247653796Sobrien/* 2477178466Smarius * Prepare io register values used by sym_init() according 247853796Sobrien * to selected and supported features. 247953796Sobrien */ 248053796Sobrienstatic int sym_prepare_setting(hcb_p np, struct sym_nvram *nvram) 248153796Sobrien{ 248253796Sobrien u_char burst_max; 248361051Sgroudier u32 period; 248453796Sobrien int i; 248553796Sobrien 248653790Sobrien /* 248753790Sobrien * Wide ? 248853790Sobrien */ 248953790Sobrien np->maxwide = (np->features & FE_WIDE)? 1 : 0; 249053790Sobrien 249153790Sobrien /* 249253790Sobrien * Get the frequency of the chip's clock. 249353790Sobrien */ 249453790Sobrien if (np->features & FE_QUAD) 249553790Sobrien np->multiplier = 4; 249653790Sobrien else if (np->features & FE_DBLR) 249753790Sobrien np->multiplier = 2; 249853790Sobrien else 249953790Sobrien np->multiplier = 1; 250053790Sobrien 250153790Sobrien np->clock_khz = (np->features & FE_CLK80)? 80000 : 40000; 250253790Sobrien np->clock_khz *= np->multiplier; 250353790Sobrien 250453790Sobrien if (np->clock_khz != 40000) 250553790Sobrien sym_getclock(np, np->multiplier); 250653790Sobrien 250753790Sobrien /* 250853790Sobrien * Divisor to be used for async (timer pre-scaler). 250953790Sobrien */ 251053790Sobrien i = np->clock_divn - 1; 251153790Sobrien while (--i >= 0) { 251254690Sobrien if (10ul * SYM_CONF_MIN_ASYNC * np->clock_khz > div_10M[i]) { 251353790Sobrien ++i; 251453790Sobrien break; 251553790Sobrien } 251653790Sobrien } 251753790Sobrien np->rv_scntl3 = i+1; 251853790Sobrien 251953790Sobrien /* 252053790Sobrien * The C1010 uses hardwired divisors for async. 252153790Sobrien * So, we just throw away, the async. divisor.:-) 252253790Sobrien */ 252353790Sobrien if (np->features & FE_C10) 252453790Sobrien np->rv_scntl3 = 0; 252553790Sobrien 252653790Sobrien /* 252753790Sobrien * Minimum synchronous period factor supported by the chip. 252853790Sobrien * Btw, 'period' is in tenths of nanoseconds. 252953790Sobrien */ 253053790Sobrien period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; 253153790Sobrien if (period <= 250) np->minsync = 10; 253253790Sobrien else if (period <= 303) np->minsync = 11; 253353790Sobrien else if (period <= 500) np->minsync = 12; 253453790Sobrien else np->minsync = (period + 40 - 1) / 40; 253553790Sobrien 253653790Sobrien /* 253753790Sobrien * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). 253853790Sobrien */ 253953790Sobrien if (np->minsync < 25 && 254053790Sobrien !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3))) 254153790Sobrien np->minsync = 25; 254253790Sobrien else if (np->minsync < 12 && 254353790Sobrien !(np->features & (FE_ULTRA2|FE_ULTRA3))) 254453790Sobrien np->minsync = 12; 254553790Sobrien 254653790Sobrien /* 254753790Sobrien * Maximum synchronous period factor supported by the chip. 254853790Sobrien */ 254953790Sobrien period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz); 255053790Sobrien np->maxsync = period > 2540 ? 254 : period / 10; 255153790Sobrien 255253790Sobrien /* 255353790Sobrien * If chip is a C1010, guess the sync limits in DT mode. 255453790Sobrien */ 255553790Sobrien if ((np->features & (FE_C10|FE_ULTRA3)) == (FE_C10|FE_ULTRA3)) { 255653790Sobrien if (np->clock_khz == 160000) { 255753790Sobrien np->minsync_dt = 9; 255853790Sobrien np->maxsync_dt = 50; 255960134Sgroudier np->maxoffs_dt = 62; 256053790Sobrien } 256153790Sobrien } 2562178466Smarius 256353790Sobrien /* 256465404Sgroudier * 64 bit addressing (895A/896/1010) ? 256553790Sobrien */ 2566153085Sru if (np->features & FE_DAC) 2567153085Sru#ifdef __LP64__ 2568153085Sru np->rv_ccntl1 |= (XTIMOD | EXTIBMV); 2569153085Sru#else 2570153085Sru np->rv_ccntl1 |= (DDAC); 2571153085Sru#endif 257253790Sobrien 257353790Sobrien /* 257453790Sobrien * Phase mismatch handled by SCRIPTS (895A/896/1010) ? 257553790Sobrien */ 257653790Sobrien if (np->features & FE_NOPM) 257753790Sobrien np->rv_ccntl0 |= (ENPMJ); 257853790Sobrien 257953790Sobrien /* 258053790Sobrien * C1010 Errata. 258153790Sobrien * In dual channel mode, contention occurs if internal cycles 258253790Sobrien * are used. Disable internal cycles. 258353790Sobrien */ 258461051Sgroudier if (np->device_id == PCI_ID_LSI53C1010 && 258571742Sgroudier np->revision_id < 0x2) 258653790Sobrien np->rv_ccntl0 |= DILS; 258753790Sobrien 258853790Sobrien /* 258953790Sobrien * Select burst length (dwords) 259053790Sobrien */ 259154690Sobrien burst_max = SYM_SETUP_BURST_ORDER; 259253790Sobrien if (burst_max == 255) 259353790Sobrien burst_max = burst_code(np->sv_dmode, np->sv_ctest4, 259453790Sobrien np->sv_ctest5); 259553790Sobrien if (burst_max > 7) 259653790Sobrien burst_max = 7; 259753790Sobrien if (burst_max > np->maxburst) 259853790Sobrien burst_max = np->maxburst; 259953790Sobrien 260053790Sobrien /* 260153790Sobrien * DEL 352 - 53C810 Rev x11 - Part Number 609-0392140 - ITEM 2. 2602178466Smarius * This chip and the 860 Rev 1 may wrongly use PCI cache line 2603178466Smarius * based transactions on LOAD/STORE instructions. So we have 2604178466Smarius * to prevent these chips from using such PCI transactions in 2605178466Smarius * this driver. The generic ncr driver that does not use 260653790Sobrien * LOAD/STORE instructions does not need this work-around. 260753790Sobrien */ 260853790Sobrien if ((np->device_id == PCI_ID_SYM53C810 && 260953790Sobrien np->revision_id >= 0x10 && np->revision_id <= 0x11) || 261053790Sobrien (np->device_id == PCI_ID_SYM53C860 && 261153790Sobrien np->revision_id <= 0x1)) 261253790Sobrien np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP); 261353790Sobrien 261453790Sobrien /* 261553790Sobrien * Select all supported special features. 2616178466Smarius * If we are using on-board RAM for scripts, prefetch (PFEN) 261753790Sobrien * does not help, but burst op fetch (BOF) does. 261853790Sobrien * Disabling PFEN makes sure BOF will be used. 261953790Sobrien */ 262053790Sobrien if (np->features & FE_ERL) 262153790Sobrien np->rv_dmode |= ERL; /* Enable Read Line */ 262253790Sobrien if (np->features & FE_BOF) 262353790Sobrien np->rv_dmode |= BOF; /* Burst Opcode Fetch */ 262453790Sobrien if (np->features & FE_ERMP) 262553790Sobrien np->rv_dmode |= ERMP; /* Enable Read Multiple */ 262653790Sobrien#if 1 262753790Sobrien if ((np->features & FE_PFEN) && !np->ram_ba) 262853790Sobrien#else 262953790Sobrien if (np->features & FE_PFEN) 263053790Sobrien#endif 263153790Sobrien np->rv_dcntl |= PFEN; /* Prefetch Enable */ 263253790Sobrien if (np->features & FE_CLSE) 263353790Sobrien np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ 263453790Sobrien if (np->features & FE_WRIE) 263553790Sobrien np->rv_ctest3 |= WRIE; /* Write and Invalidate */ 263653790Sobrien if (np->features & FE_DFS) 263753790Sobrien np->rv_ctest5 |= DFS; /* Dma Fifo Size */ 263853790Sobrien 263953790Sobrien /* 264053790Sobrien * Select some other 264153790Sobrien */ 264254690Sobrien if (SYM_SETUP_PCI_PARITY) 264353790Sobrien np->rv_ctest4 |= MPEE; /* Master parity checking */ 264454690Sobrien if (SYM_SETUP_SCSI_PARITY) 264553790Sobrien np->rv_scntl0 |= 0x0a; /* full arb., ena parity, par->ATN */ 264653790Sobrien 264753790Sobrien /* 264853790Sobrien * Get parity checking, host ID and verbose mode from NVRAM 264953790Sobrien */ 265053790Sobrien np->myaddr = 255; 265153790Sobrien sym_nvram_setup_host (np, nvram); 2652207285Smarius#ifdef __sparc64__ 2653207285Smarius np->myaddr = OF_getscsinitid(np->device); 2654207285Smarius#endif 265553790Sobrien 265653790Sobrien /* 265753790Sobrien * Get SCSI addr of host adapter (set by bios?). 265853790Sobrien */ 265953790Sobrien if (np->myaddr == 255) { 266053790Sobrien np->myaddr = INB(nc_scid) & 0x07; 266153790Sobrien if (!np->myaddr) 266254690Sobrien np->myaddr = SYM_SETUP_HOST_ID; 266353790Sobrien } 266453790Sobrien 266553790Sobrien /* 266653790Sobrien * Prepare initial io register bits for burst length 266753790Sobrien */ 266853790Sobrien sym_init_burst(np, burst_max); 266953790Sobrien 267053790Sobrien /* 267153790Sobrien * Set SCSI BUS mode. 2672178466Smarius * - LVD capable chips (895/895A/896/1010) report the 267353790Sobrien * current BUS mode through the STEST4 IO register. 2674178466Smarius * - For previous generation chips (825/825A/875), 2675178466Smarius * user has to tell us how to check against HVD, 267653790Sobrien * since a 100% safe algorithm is not possible. 267753790Sobrien */ 267853790Sobrien np->scsi_mode = SMODE_SE; 267953790Sobrien if (np->features & (FE_ULTRA2|FE_ULTRA3)) 268053790Sobrien np->scsi_mode = (np->sv_stest4 & SMODE); 268153790Sobrien else if (np->features & FE_DIFF) { 268254690Sobrien if (SYM_SETUP_SCSI_DIFF == 1) { 268353790Sobrien if (np->sv_scntl3) { 268453790Sobrien if (np->sv_stest2 & 0x20) 268553790Sobrien np->scsi_mode = SMODE_HVD; 268653790Sobrien } 268753790Sobrien else if (nvram->type == SYM_SYMBIOS_NVRAM) { 268871742Sgroudier if (!(INB(nc_gpreg) & 0x08)) 268953790Sobrien np->scsi_mode = SMODE_HVD; 269053790Sobrien } 269153790Sobrien } 269254690Sobrien else if (SYM_SETUP_SCSI_DIFF == 2) 269353790Sobrien np->scsi_mode = SMODE_HVD; 269453790Sobrien } 269553790Sobrien if (np->scsi_mode == SMODE_HVD) 269653790Sobrien np->rv_stest2 |= 0x20; 269753790Sobrien 269853790Sobrien /* 269953790Sobrien * Set LED support from SCRIPTS. 2700178466Smarius * Ignore this feature for boards known to use a 2701178466Smarius * specific GPIO wiring and for the 895A, 896 270262422Sgroudier * and 1010 that drive the LED directly. 270353790Sobrien */ 2704178466Smarius if ((SYM_SETUP_SCSI_LED || 270579042Sgroudier (nvram->type == SYM_SYMBIOS_NVRAM || 270679042Sgroudier (nvram->type == SYM_TEKRAM_NVRAM && 270779042Sgroudier np->device_id == PCI_ID_SYM53C895))) && 270853790Sobrien !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01)) 270953790Sobrien np->features |= FE_LED0; 271053790Sobrien 271153790Sobrien /* 271253790Sobrien * Set irq mode. 271353790Sobrien */ 271454690Sobrien switch(SYM_SETUP_IRQ_MODE & 3) { 271553790Sobrien case 2: 271653790Sobrien np->rv_dcntl |= IRQM; 271753790Sobrien break; 271853790Sobrien case 1: 271953790Sobrien np->rv_dcntl |= (np->sv_dcntl & IRQM); 272053790Sobrien break; 272153790Sobrien default: 272253790Sobrien break; 272353790Sobrien } 272453790Sobrien 272553790Sobrien /* 272653790Sobrien * Configure targets according to driver setup. 272753790Sobrien * If NVRAM present get targets setup from NVRAM. 272853790Sobrien */ 272954690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 273053790Sobrien tcb_p tp = &np->target[i]; 273153790Sobrien 273274755Sgroudier tp->tinfo.user.scsi_version = tp->tinfo.current.scsi_version= 2; 273374755Sgroudier tp->tinfo.user.spi_version = tp->tinfo.current.spi_version = 2; 273453790Sobrien tp->tinfo.user.period = np->minsync; 2735181399Smarius if (np->features & FE_ULTRA3) 2736181399Smarius tp->tinfo.user.period = np->minsync_dt; 273753790Sobrien tp->tinfo.user.offset = np->maxoffs; 273853790Sobrien tp->tinfo.user.width = np->maxwide ? BUS_16_BIT : BUS_8_BIT; 273953790Sobrien tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); 274054690Sobrien tp->usrtags = SYM_SETUP_MAX_TAG; 274153790Sobrien 274253790Sobrien sym_nvram_setup_target (np, i, nvram); 274353790Sobrien 274460134Sgroudier /* 2745178466Smarius * For now, guess PPR/DT support from the period 274661639Sgroudier * and BUS width. 274760134Sgroudier */ 274861639Sgroudier if (np->features & FE_ULTRA3) { 274961639Sgroudier if (tp->tinfo.user.period <= 9 && 275061639Sgroudier tp->tinfo.user.width == BUS_16_BIT) { 275161639Sgroudier tp->tinfo.user.options |= PPR_OPT_DT; 275261639Sgroudier tp->tinfo.user.offset = np->maxoffs_dt; 275374755Sgroudier tp->tinfo.user.spi_version = 3; 275461639Sgroudier } 275560134Sgroudier } 275660134Sgroudier 275753790Sobrien if (!tp->usrtags) 275853790Sobrien tp->usrflags &= ~SYM_TAGS_ENABLED; 275953790Sobrien } 276053790Sobrien 276153790Sobrien /* 276253790Sobrien * Let user know about the settings. 276353790Sobrien */ 276453790Sobrien i = nvram->type; 276555300Sgroudier printf("%s: %s NVRAM, ID %d, Fast-%d, %s, %s\n", sym_name(np), 276653790Sobrien i == SYM_SYMBIOS_NVRAM ? "Symbios" : 276753790Sobrien (i == SYM_TEKRAM_NVRAM ? "Tekram" : "No"), 276853790Sobrien np->myaddr, 2769178466Smarius (np->features & FE_ULTRA3) ? 80 : 2770178466Smarius (np->features & FE_ULTRA2) ? 40 : 277155300Sgroudier (np->features & FE_ULTRA) ? 20 : 10, 277255300Sgroudier sym_scsi_bus_mode(np->scsi_mode), 277355300Sgroudier (np->rv_scntl0 & 0xa) ? "parity checking" : "NO parity"); 277453790Sobrien /* 277553790Sobrien * Tell him more on demand. 277653790Sobrien */ 277755300Sgroudier if (sym_verbose) { 277853790Sobrien printf("%s: %s IRQ line driver%s\n", 277953790Sobrien sym_name(np), 278053790Sobrien np->rv_dcntl & IRQM ? "totem pole" : "open drain", 278153790Sobrien np->ram_ba ? ", using on-chip SRAM" : ""); 278259743Sgroudier printf("%s: using %s firmware.\n", sym_name(np), np->fw_name); 278355300Sgroudier if (np->features & FE_NOPM) 2784178466Smarius printf("%s: handling phase mismatch from SCRIPTS.\n", 278555300Sgroudier sym_name(np)); 278655300Sgroudier } 278753790Sobrien /* 278853790Sobrien * And still more. 278953790Sobrien */ 279053790Sobrien if (sym_verbose > 1) { 279153790Sobrien printf ("%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " 279253790Sobrien "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", 279353790Sobrien sym_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl, 279453790Sobrien np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); 279553790Sobrien 279653790Sobrien printf ("%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " 279753790Sobrien "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", 279853790Sobrien sym_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl, 279953790Sobrien np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); 280053790Sobrien } 280153790Sobrien /* 280253790Sobrien * Let user be aware of targets that have some disable flags set. 280353790Sobrien */ 280453790Sobrien sym_print_targets_flag(np, SYM_SCAN_BOOT_DISABLED, "SCAN AT BOOT"); 280553790Sobrien if (sym_verbose) 280653790Sobrien sym_print_targets_flag(np, SYM_SCAN_LUNS_DISABLED, 280753790Sobrien "SCAN FOR LUNS"); 280853790Sobrien 280953790Sobrien return 0; 281053790Sobrien} 281153790Sobrien 281253790Sobrien/* 281353790Sobrien * Prepare the next negotiation message if needed. 281453790Sobrien * 2815178466Smarius * Fill in the part of message buffer that contains the 281653790Sobrien * negotiation and the nego_status field of the CCB. 281753790Sobrien * Returns the size of the message in bytes. 281853790Sobrien */ 281953790Sobrienstatic int sym_prepare_nego(hcb_p np, ccb_p cp, int nego, u_char *msgptr) 282053790Sobrien{ 282153790Sobrien tcb_p tp = &np->target[cp->target]; 282253790Sobrien int msglen = 0; 282353790Sobrien 282453790Sobrien /* 2825178466Smarius * Early C1010 chips need a work-around for DT 282653796Sobrien * data transfer to work. 282753796Sobrien */ 282853790Sobrien if (!(np->features & FE_U3EN)) 282953790Sobrien tp->tinfo.goal.options = 0; 283053790Sobrien /* 283153790Sobrien * negotiate using PPR ? 283253790Sobrien */ 283353790Sobrien if (tp->tinfo.goal.options & PPR_OPT_MASK) 283453790Sobrien nego = NS_PPR; 283553790Sobrien /* 283653790Sobrien * negotiate wide transfers ? 283753790Sobrien */ 283853790Sobrien else if (tp->tinfo.current.width != tp->tinfo.goal.width) 283953790Sobrien nego = NS_WIDE; 284053790Sobrien /* 284153790Sobrien * negotiate synchronous transfers? 284253790Sobrien */ 284353790Sobrien else if (tp->tinfo.current.period != tp->tinfo.goal.period || 284453790Sobrien tp->tinfo.current.offset != tp->tinfo.goal.offset) 284553790Sobrien nego = NS_SYNC; 284653790Sobrien 284753790Sobrien switch (nego) { 284853790Sobrien case NS_SYNC: 284953790Sobrien msgptr[msglen++] = M_EXTENDED; 285053790Sobrien msgptr[msglen++] = 3; 285153790Sobrien msgptr[msglen++] = M_X_SYNC_REQ; 285253790Sobrien msgptr[msglen++] = tp->tinfo.goal.period; 285353790Sobrien msgptr[msglen++] = tp->tinfo.goal.offset; 285453790Sobrien break; 285553790Sobrien case NS_WIDE: 285653790Sobrien msgptr[msglen++] = M_EXTENDED; 285753790Sobrien msgptr[msglen++] = 2; 285853790Sobrien msgptr[msglen++] = M_X_WIDE_REQ; 285953790Sobrien msgptr[msglen++] = tp->tinfo.goal.width; 286053790Sobrien break; 286153790Sobrien case NS_PPR: 286253790Sobrien msgptr[msglen++] = M_EXTENDED; 286353790Sobrien msgptr[msglen++] = 6; 286453790Sobrien msgptr[msglen++] = M_X_PPR_REQ; 286553790Sobrien msgptr[msglen++] = tp->tinfo.goal.period; 286653790Sobrien msgptr[msglen++] = 0; 286753790Sobrien msgptr[msglen++] = tp->tinfo.goal.offset; 286853790Sobrien msgptr[msglen++] = tp->tinfo.goal.width; 286953790Sobrien msgptr[msglen++] = tp->tinfo.goal.options & PPR_OPT_DT; 287053790Sobrien break; 287153790Sobrien }; 287253790Sobrien 287353790Sobrien cp->nego_status = nego; 287453790Sobrien 287553790Sobrien if (nego) { 287653790Sobrien tp->nego_cp = cp; /* Keep track a nego will be performed */ 287753790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 287853809Sobrien sym_print_msg(cp, nego == NS_SYNC ? "sync msgout" : 287953809Sobrien nego == NS_WIDE ? "wide msgout" : 288053809Sobrien "ppr msgout", msgptr); 288153790Sobrien }; 288253790Sobrien }; 288353790Sobrien 288453790Sobrien return msglen; 288553790Sobrien} 288653790Sobrien 288753790Sobrien/* 288853790Sobrien * Insert a job into the start queue. 288953790Sobrien */ 289053790Sobrienstatic void sym_put_start_queue(hcb_p np, ccb_p cp) 289153790Sobrien{ 289253790Sobrien u_short qidx; 289353790Sobrien 289454690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 289553790Sobrien /* 2896178466Smarius * If the previously queued CCB is not yet done, 2897178466Smarius * set the IARB hint. The SCRIPTS will go with IARB 289853790Sobrien * for this job when starting the previous one. 2899178466Smarius * We leave devices a chance to win arbitration by 2900178466Smarius * not using more than 'iarb_max' consecutive 290153790Sobrien * immediate arbitrations. 290253790Sobrien */ 290353790Sobrien if (np->last_cp && np->iarb_count < np->iarb_max) { 290453790Sobrien np->last_cp->host_flags |= HF_HINT_IARB; 290553790Sobrien ++np->iarb_count; 290653790Sobrien } 290753790Sobrien else 290853790Sobrien np->iarb_count = 0; 290953790Sobrien np->last_cp = cp; 291053790Sobrien#endif 2911178466Smarius 291253790Sobrien /* 291353790Sobrien * Insert first the idle task and then our job. 291453790Sobrien * The MB should ensure proper ordering. 291553790Sobrien */ 291653790Sobrien qidx = np->squeueput + 2; 291753790Sobrien if (qidx >= MAX_QUEUE*2) qidx = 0; 291853790Sobrien 291953790Sobrien np->squeue [qidx] = cpu_to_scr(np->idletask_ba); 292053790Sobrien MEMORY_BARRIER(); 292153790Sobrien np->squeue [np->squeueput] = cpu_to_scr(cp->ccb_ba); 292253790Sobrien 292353790Sobrien np->squeueput = qidx; 292453790Sobrien 292553790Sobrien if (DEBUG_FLAGS & DEBUG_QUEUE) 292653790Sobrien printf ("%s: queuepos=%d.\n", sym_name (np), np->squeueput); 292753790Sobrien 292853790Sobrien /* 292953790Sobrien * Script processor may be waiting for reselect. 293053790Sobrien * Wake it up. 293153790Sobrien */ 293253790Sobrien MEMORY_BARRIER(); 293353790Sobrien OUTB (nc_istat, SIGP|np->istat_sem); 293453790Sobrien} 293553790Sobrien 293653790Sobrien/* 293753790Sobrien * Soft reset the chip. 293853790Sobrien * 2939178466Smarius * Raising SRST when the chip is running may cause 294055300Sgroudier * problems on dual function chips (see below). 2941178466Smarius * On the other hand, LVD devices need some delay 294255300Sgroudier * to settle and report actual BUS mode in STEST4. 294353796Sobrien */ 294453796Sobrienstatic void sym_chip_reset (hcb_p np) 294553796Sobrien{ 294653796Sobrien OUTB (nc_istat, SRST); 294753796Sobrien UDELAY (10); 294853796Sobrien OUTB (nc_istat, 0); 294955300Sgroudier UDELAY(2000); /* For BUS MODE to settle */ 295053796Sobrien} 295153796Sobrien 295253796Sobrien/* 295353796Sobrien * Soft reset the chip. 295453796Sobrien * 2955178466Smarius * Some 896 and 876 chip revisions may hang-up if we set 2956178466Smarius * the SRST (soft reset) bit at the wrong time when SCRIPTS 295753790Sobrien * are running. 2958178466Smarius * So, we need to abort the current operation prior to 295953790Sobrien * soft resetting the chip. 296053790Sobrien */ 296153790Sobrienstatic void sym_soft_reset (hcb_p np) 296253790Sobrien{ 296353790Sobrien u_char istat; 296453790Sobrien int i; 296553790Sobrien 296653790Sobrien OUTB (nc_istat, CABRT); 296753790Sobrien for (i = 1000000 ; i ; --i) { 296853790Sobrien istat = INB (nc_istat); 296953790Sobrien if (istat & SIP) { 297053790Sobrien INW (nc_sist); 297153790Sobrien continue; 297253790Sobrien } 297353790Sobrien if (istat & DIP) { 297453790Sobrien OUTB (nc_istat, 0); 297553790Sobrien INB (nc_dstat); 297653790Sobrien break; 297753790Sobrien } 297853790Sobrien } 297953790Sobrien if (!i) 298053790Sobrien printf("%s: unable to abort current chip operation.\n", 298153790Sobrien sym_name(np)); 298253796Sobrien sym_chip_reset (np); 298353790Sobrien} 298453790Sobrien 298553790Sobrien/* 298653790Sobrien * Start reset process. 298753790Sobrien * 298853790Sobrien * The interrupt handler will reinitialize the chip. 298953790Sobrien */ 299053790Sobrienstatic void sym_start_reset(hcb_p np) 299153790Sobrien{ 299253790Sobrien (void) sym_reset_scsi_bus(np, 1); 299353790Sobrien} 2994178466Smarius 299553790Sobrienstatic int sym_reset_scsi_bus(hcb_p np, int enab_int) 299653790Sobrien{ 299753790Sobrien u32 term; 299853790Sobrien int retv = 0; 299953790Sobrien 300053790Sobrien sym_soft_reset(np); /* Soft reset the chip */ 300153790Sobrien if (enab_int) 300253790Sobrien OUTW (nc_sien, RST); 300353790Sobrien /* 3004178466Smarius * Enable Tolerant, reset IRQD if present and 300553790Sobrien * properly set IRQ mode, prior to resetting the bus. 300653790Sobrien */ 300753790Sobrien OUTB (nc_stest3, TE); 300853790Sobrien OUTB (nc_dcntl, (np->rv_dcntl & IRQM)); 300953790Sobrien OUTB (nc_scntl1, CRST); 301053790Sobrien UDELAY (200); 301153790Sobrien 301254690Sobrien if (!SYM_SETUP_SCSI_BUS_CHECK) 301353790Sobrien goto out; 301453790Sobrien /* 301553790Sobrien * Check for no terminators or SCSI bus shorts to ground. 301653790Sobrien * Read SCSI data bus, data parity bits and control signals. 3017178466Smarius * We are expecting RESET to be TRUE and other signals to be 301853790Sobrien * FALSE. 301953790Sobrien */ 302055300Sgroudier term = INB(nc_sstat0); 302155300Sgroudier term = ((term & 2) << 7) + ((term & 1) << 17); /* rst sdp0 */ 302255300Sgroudier term |= ((INB(nc_sstat2) & 0x01) << 26) | /* sdp1 */ 302355300Sgroudier ((INW(nc_sbdl) & 0xff) << 9) | /* d7-0 */ 302455300Sgroudier ((INW(nc_sbdl) & 0xff00) << 10) | /* d15-8 */ 302555300Sgroudier INB(nc_sbcl); /* req ack bsy sel atn msg cd io */ 302653790Sobrien 302753790Sobrien if (!(np->features & FE_WIDE)) 302853790Sobrien term &= 0x3ffff; 302953790Sobrien 303053790Sobrien if (term != (2<<7)) { 303153790Sobrien printf("%s: suspicious SCSI data while resetting the BUS.\n", 303253790Sobrien sym_name(np)); 303353790Sobrien printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " 303453790Sobrien "0x%lx, expecting 0x%lx\n", 303553790Sobrien sym_name(np), 303653790Sobrien (np->features & FE_WIDE) ? "dp1,d15-8," : "", 303753790Sobrien (u_long)term, (u_long)(2<<7)); 303854690Sobrien if (SYM_SETUP_SCSI_BUS_CHECK == 1) 303953790Sobrien retv = 1; 304053790Sobrien } 304153790Sobrienout: 304253790Sobrien OUTB (nc_scntl1, 0); 304353790Sobrien /* MDELAY(100); */ 304453790Sobrien return retv; 304553790Sobrien} 304653790Sobrien 304753790Sobrien/* 304853790Sobrien * The chip may have completed jobs. Look at the DONE QUEUE. 304962422Sgroudier * 3050178466Smarius * On architectures that may reorder LOAD/STORE operations, 3051178466Smarius * a memory barrier may be needed after the reading of the 305262422Sgroudier * so-called `flag' and prior to dealing with the data. 305353790Sobrien */ 305453790Sobrienstatic int sym_wakeup_done (hcb_p np) 305553790Sobrien{ 305653790Sobrien ccb_p cp; 305753790Sobrien int i, n; 305861051Sgroudier u32 dsa; 305953790Sobrien 3060178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 3061178468Smarius 306253790Sobrien n = 0; 306353790Sobrien i = np->dqueueget; 306453790Sobrien while (1) { 306553790Sobrien dsa = scr_to_cpu(np->dqueue[i]); 306653790Sobrien if (!dsa) 306753790Sobrien break; 306853790Sobrien np->dqueue[i] = 0; 306953790Sobrien if ((i = i+2) >= MAX_QUEUE*2) 307053790Sobrien i = 0; 307153790Sobrien 307253790Sobrien cp = sym_ccb_from_dsa(np, dsa); 307353790Sobrien if (cp) { 307462422Sgroudier MEMORY_BARRIER(); 307553790Sobrien sym_complete_ok (np, cp); 307653790Sobrien ++n; 307753790Sobrien } 307853790Sobrien else 307961051Sgroudier printf ("%s: bad DSA (%x) in done queue.\n", 308061051Sgroudier sym_name(np), (u_int) dsa); 308153790Sobrien } 308253790Sobrien np->dqueueget = i; 308353790Sobrien 308453790Sobrien return n; 308553790Sobrien} 308653790Sobrien 308753790Sobrien/* 308853790Sobrien * Complete all active CCBs with error. 308953790Sobrien * Used on CHIP/SCSI RESET. 309053790Sobrien */ 309153790Sobrienstatic void sym_flush_busy_queue (hcb_p np, int cam_status) 309253790Sobrien{ 309353790Sobrien /* 3094178466Smarius * Move all active CCBs to the COMP queue 309553790Sobrien * and flush this queue. 309653790Sobrien */ 309753790Sobrien sym_que_splice(&np->busy_ccbq, &np->comp_ccbq); 309853790Sobrien sym_que_init(&np->busy_ccbq); 309953790Sobrien sym_flush_comp_queue(np, cam_status); 310053790Sobrien} 310153790Sobrien 310253790Sobrien/* 310353790Sobrien * Start chip. 310455300Sgroudier * 310555300Sgroudier * 'reason' means: 310655300Sgroudier * 0: initialisation. 310755300Sgroudier * 1: SCSI BUS RESET delivered or received. 310855300Sgroudier * 2: SCSI BUS MODE changed. 310953790Sobrien */ 311055300Sgroudierstatic void sym_init (hcb_p np, int reason) 311153790Sobrien{ 311253790Sobrien int i; 311361051Sgroudier u32 phys; 311453790Sobrien 3115178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 3116178468Smarius 311753790Sobrien /* 311853790Sobrien * Reset chip if asked, otherwise just clear fifos. 311953790Sobrien */ 312055300Sgroudier if (reason == 1) 312153790Sobrien sym_soft_reset(np); 312253790Sobrien else { 312353790Sobrien OUTB (nc_stest3, TE|CSF); 312453790Sobrien OUTONB (nc_ctest3, CLF); 312553790Sobrien } 3126178466Smarius 312753790Sobrien /* 312853790Sobrien * Clear Start Queue 312953790Sobrien */ 313058927Sgroudier phys = np->squeue_ba; 313153790Sobrien for (i = 0; i < MAX_QUEUE*2; i += 2) { 313253790Sobrien np->squeue[i] = cpu_to_scr(np->idletask_ba); 313353790Sobrien np->squeue[i+1] = cpu_to_scr(phys + (i+2)*4); 313453790Sobrien } 313553790Sobrien np->squeue[MAX_QUEUE*2-1] = cpu_to_scr(phys); 313653790Sobrien 313753790Sobrien /* 313853790Sobrien * Start at first entry. 313953790Sobrien */ 314053790Sobrien np->squeueput = 0; 314153790Sobrien 314253790Sobrien /* 314353790Sobrien * Clear Done Queue 314453790Sobrien */ 314559743Sgroudier phys = np->dqueue_ba; 314653790Sobrien for (i = 0; i < MAX_QUEUE*2; i += 2) { 314753790Sobrien np->dqueue[i] = 0; 314853790Sobrien np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4); 314953790Sobrien } 315053790Sobrien np->dqueue[MAX_QUEUE*2-1] = cpu_to_scr(phys); 315153790Sobrien 315253790Sobrien /* 315353790Sobrien * Start at first entry. 315453790Sobrien */ 315553790Sobrien np->dqueueget = 0; 315653790Sobrien 315753790Sobrien /* 315859743Sgroudier * Install patches in scripts. 3159178466Smarius * This also let point to first position the start 316059743Sgroudier * and done queue pointers used from SCRIPTS. 316159743Sgroudier */ 316259743Sgroudier np->fw_patch(np); 316359743Sgroudier 316459743Sgroudier /* 316553790Sobrien * Wakeup all pending jobs. 316653790Sobrien */ 316753790Sobrien sym_flush_busy_queue(np, CAM_SCSI_BUS_RESET); 316853790Sobrien 316953790Sobrien /* 317053790Sobrien * Init chip. 317153790Sobrien */ 317253790Sobrien OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */ 317353790Sobrien UDELAY (2000); /* The 895 needs time for the bus mode to settle */ 317453790Sobrien 317553790Sobrien OUTB (nc_scntl0, np->rv_scntl0 | 0xc0); 317653790Sobrien /* full arb., ena parity, par->ATN */ 317753790Sobrien OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ 317853790Sobrien 317953790Sobrien sym_selectclock(np, np->rv_scntl3); /* Select SCSI clock */ 318053790Sobrien 318153790Sobrien OUTB (nc_scid , RRE|np->myaddr); /* Adapter SCSI address */ 318253790Sobrien OUTW (nc_respid, 1ul<<np->myaddr); /* Id to respond to */ 318353790Sobrien OUTB (nc_istat , SIGP ); /* Signal Process */ 318453790Sobrien OUTB (nc_dmode , np->rv_dmode); /* Burst length, dma mode */ 318553790Sobrien OUTB (nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */ 318653790Sobrien 318753790Sobrien OUTB (nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */ 318853790Sobrien OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */ 318953790Sobrien OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */ 319053790Sobrien 319153790Sobrien /* Extended Sreq/Sack filtering not supported on the C10 */ 319253790Sobrien if (np->features & FE_C10) 319353790Sobrien OUTB (nc_stest2, np->rv_stest2); 319453790Sobrien else 319553790Sobrien OUTB (nc_stest2, EXT|np->rv_stest2); 319653790Sobrien 319753790Sobrien OUTB (nc_stest3, TE); /* TolerANT enable */ 319853790Sobrien OUTB (nc_stime0, 0x0c); /* HTH disabled STO 0.25 sec */ 319953790Sobrien 320053790Sobrien /* 320161051Sgroudier * For now, disable AIP generation on C1010-66. 320261051Sgroudier */ 320361051Sgroudier if (np->device_id == PCI_ID_LSI53C1010_2) 320461051Sgroudier OUTB (nc_aipcntl1, DISAIP); 320561051Sgroudier 320661051Sgroudier /* 320753790Sobrien * C10101 Errata. 320853790Sobrien * Errant SGE's when in narrow. Write bits 4 & 5 of 3209178466Smarius * STEST1 register to disable SGE. We probably should do 3210178466Smarius * that from SCRIPTS for each selection/reselection, but 321153790Sobrien * I just don't want. :) 321253790Sobrien */ 321361051Sgroudier if (np->device_id == PCI_ID_LSI53C1010 && 321461051Sgroudier /* np->revision_id < 0xff */ 1) 321553790Sobrien OUTB (nc_stest1, INB(nc_stest1) | 0x30); 321653790Sobrien 321753790Sobrien /* 321853790Sobrien * DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2. 3219178466Smarius * Disable overlapped arbitration for some dual function devices, 322053790Sobrien * regardless revision id (kind of post-chip-design feature. ;-)) 322153790Sobrien */ 322253790Sobrien if (np->device_id == PCI_ID_SYM53C875) 322353790Sobrien OUTB (nc_ctest0, (1<<5)); 322453790Sobrien else if (np->device_id == PCI_ID_SYM53C896) 322553790Sobrien np->rv_ccntl0 |= DPR; 322653790Sobrien 322753790Sobrien /* 3228178466Smarius * Write CCNTL0/CCNTL1 for chips capable of 64 bit addressing 3229178466Smarius * and/or hardware phase mismatch, since only such chips 323065404Sgroudier * seem to support those IO registers. 323153790Sobrien */ 323265404Sgroudier if (np->features & (FE_DAC|FE_NOPM)) { 323353790Sobrien OUTB (nc_ccntl0, np->rv_ccntl0); 323453790Sobrien OUTB (nc_ccntl1, np->rv_ccntl1); 323553790Sobrien } 323653790Sobrien 323753790Sobrien /* 323853790Sobrien * If phase mismatch handled by scripts (895A/896/1010), 323953790Sobrien * set PM jump addresses. 324053790Sobrien */ 324153790Sobrien if (np->features & FE_NOPM) { 324259292Sgroudier OUTL (nc_pmjad1, SCRIPTB_BA (np, pm_handle)); 324359292Sgroudier OUTL (nc_pmjad2, SCRIPTB_BA (np, pm_handle)); 324453790Sobrien } 324553790Sobrien 324653790Sobrien /* 324753790Sobrien * Enable GPIO0 pin for writing if LED support from SCRIPTS. 324853790Sobrien * Also set GPIO5 and clear GPIO6 if hardware LED control. 324953790Sobrien */ 325053790Sobrien if (np->features & FE_LED0) 325153790Sobrien OUTB(nc_gpcntl, INB(nc_gpcntl) & ~0x01); 325253790Sobrien else if (np->features & FE_LEDC) 325353790Sobrien OUTB(nc_gpcntl, (INB(nc_gpcntl) & ~0x41) | 0x20); 325453790Sobrien 325553790Sobrien /* 325653790Sobrien * enable ints 325753790Sobrien */ 325853790Sobrien OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR); 325953790Sobrien OUTB (nc_dien , MDPE|BF|SSI|SIR|IID); 326053790Sobrien 326153790Sobrien /* 326253790Sobrien * For 895/6 enable SBMC interrupt and save current SCSI bus mode. 3263178466Smarius * Try to eat the spurious SBMC interrupt that may occur when 326455300Sgroudier * we reset the chip but not the SCSI BUS (at initialization). 326553790Sobrien */ 326653790Sobrien if (np->features & (FE_ULTRA2|FE_ULTRA3)) { 326753790Sobrien OUTONW (nc_sien, SBMC); 326855300Sgroudier if (reason == 0) { 326955300Sgroudier MDELAY(100); 327055300Sgroudier INW (nc_sist); 327155300Sgroudier } 327253790Sobrien np->scsi_mode = INB (nc_stest4) & SMODE; 327353790Sobrien } 327453790Sobrien 327553790Sobrien /* 327653790Sobrien * Fill in target structure. 327753790Sobrien * Reinitialize usrsync. 327853790Sobrien * Reinitialize usrwide. 327953790Sobrien * Prepare sync negotiation according to actual SCSI bus mode. 328053790Sobrien */ 328154690Sobrien for (i=0;i<SYM_CONF_MAX_TARGET;i++) { 328253790Sobrien tcb_p tp = &np->target[i]; 328353790Sobrien 328459743Sgroudier tp->to_reset = 0; 328559743Sgroudier tp->head.sval = 0; 328659743Sgroudier tp->head.wval = np->rv_scntl3; 328759743Sgroudier tp->head.uval = 0; 328853790Sobrien 328953790Sobrien tp->tinfo.current.period = 0; 329053790Sobrien tp->tinfo.current.offset = 0; 329153790Sobrien tp->tinfo.current.width = BUS_8_BIT; 329253790Sobrien tp->tinfo.current.options = 0; 329353790Sobrien } 329453790Sobrien 329553790Sobrien /* 329653790Sobrien * Download SCSI SCRIPTS to on-chip RAM if present, 329753790Sobrien * and start script processor. 329853790Sobrien */ 329953790Sobrien if (np->ram_ba) { 330055300Sgroudier if (sym_verbose > 1) 330153790Sobrien printf ("%s: Downloading SCSI SCRIPTS.\n", 330253790Sobrien sym_name(np)); 330353790Sobrien if (np->ram_ws == 8192) { 330461429Sgroudier OUTRAM_OFF(4096, np->scriptb0, np->scriptb_sz); 330553790Sobrien OUTL (nc_mmws, np->scr_ram_seg); 330653790Sobrien OUTL (nc_mmrs, np->scr_ram_seg); 330753790Sobrien OUTL (nc_sfs, np->scr_ram_seg); 330859292Sgroudier phys = SCRIPTB_BA (np, start64); 330953790Sobrien } 331053790Sobrien else 331159292Sgroudier phys = SCRIPTA_BA (np, init); 331261429Sgroudier OUTRAM_OFF(0, np->scripta0, np->scripta_sz); 331353790Sobrien } 331453790Sobrien else 331559292Sgroudier phys = SCRIPTA_BA (np, init); 331653790Sobrien 331753790Sobrien np->istat_sem = 0; 331853790Sobrien 331958927Sgroudier OUTL (nc_dsa, np->hcb_ba); 332061429Sgroudier OUTL_DSP (phys); 332153790Sobrien 332253790Sobrien /* 332355300Sgroudier * Notify the XPT about the RESET condition. 332453790Sobrien */ 332555300Sgroudier if (reason != 0) 332655300Sgroudier xpt_async(AC_BUS_RESET, np->path, NULL); 332753790Sobrien} 332853790Sobrien 332953790Sobrien/* 3330178466Smarius * Get clock factor and sync divisor for a given 333153790Sobrien * synchronous factor period. 333253790Sobrien */ 3333178466Smariusstatic int 333453790Sobriensym_getsync(hcb_p np, u_char dt, u_char sfac, u_char *divp, u_char *fakp) 333553790Sobrien{ 333653790Sobrien u32 clk = np->clock_khz; /* SCSI clock frequency in kHz */ 333753790Sobrien int div = np->clock_divn; /* Number of divisors supported */ 333853790Sobrien u32 fak; /* Sync factor in sxfer */ 333953790Sobrien u32 per; /* Period in tenths of ns */ 334053790Sobrien u32 kpc; /* (per * clk) */ 334153790Sobrien int ret; 334253790Sobrien 334353790Sobrien /* 334453790Sobrien * Compute the synchronous period in tenths of nano-seconds 334553790Sobrien */ 334653790Sobrien if (dt && sfac <= 9) per = 125; 334753790Sobrien else if (sfac <= 10) per = 250; 334853790Sobrien else if (sfac == 11) per = 303; 334953790Sobrien else if (sfac == 12) per = 500; 335053790Sobrien else per = 40 * sfac; 335153790Sobrien ret = per; 335253790Sobrien 335353790Sobrien kpc = per * clk; 335453790Sobrien if (dt) 335553790Sobrien kpc <<= 1; 335653790Sobrien 335753790Sobrien /* 3358178466Smarius * For earliest C10 revision 0, we cannot use extra 335962422Sgroudier * clocks for the setting of the SCSI clocking. 3360178466Smarius * Note that this limits the lowest sync data transfer 336153790Sobrien * to 5 Mega-transfers per second and may result in 336253790Sobrien * using higher clock divisors. 336353790Sobrien */ 336453796Sobrien#if 1 336553790Sobrien if ((np->features & (FE_C10|FE_U3EN)) == FE_C10) { 336653790Sobrien /* 3367178466Smarius * Look for the lowest clock divisor that allows an 336853790Sobrien * output speed not faster than the period. 336953790Sobrien */ 337053796Sobrien while (div > 0) { 337153796Sobrien --div; 337253790Sobrien if (kpc > (div_10M[div] << 2)) { 337353790Sobrien ++div; 337453790Sobrien break; 337553790Sobrien } 337653790Sobrien } 337753790Sobrien fak = 0; /* No extra clocks */ 337853790Sobrien if (div == np->clock_divn) { /* Are we too fast ? */ 337953790Sobrien ret = -1; 338053790Sobrien } 338153790Sobrien *divp = div; 338253790Sobrien *fakp = fak; 338353790Sobrien return ret; 338453790Sobrien } 338553790Sobrien#endif 338653790Sobrien 338753790Sobrien /* 3388178466Smarius * Look for the greatest clock divisor that allows an 338953790Sobrien * input speed faster than the period. 339053790Sobrien */ 339153796Sobrien while (div-- > 0) 339253790Sobrien if (kpc >= (div_10M[div] << 2)) break; 339353790Sobrien 339453790Sobrien /* 3395178466Smarius * Calculate the lowest clock factor that allows an output 339653790Sobrien * speed not faster than the period, and the max output speed. 339753790Sobrien * If fak >= 1 we will set both XCLKH_ST and XCLKH_DT. 339853790Sobrien * If fak >= 2 we will also set XCLKS_ST and XCLKS_DT. 339953790Sobrien */ 340053790Sobrien if (dt) { 340153790Sobrien fak = (kpc - 1) / (div_10M[div] << 1) + 1 - 2; 340253790Sobrien /* ret = ((2+fak)*div_10M[div])/np->clock_khz; */ 340353790Sobrien } 340453790Sobrien else { 340553790Sobrien fak = (kpc - 1) / div_10M[div] + 1 - 4; 340653790Sobrien /* ret = ((4+fak)*div_10M[div])/np->clock_khz; */ 340753790Sobrien } 340853790Sobrien 340953790Sobrien /* 341053790Sobrien * Check against our hardware limits, or bugs :). 341153790Sobrien */ 341253790Sobrien if (fak > 2) {fak = 2; ret = -1;} 341353790Sobrien 341453790Sobrien /* 341553790Sobrien * Compute and return sync parameters. 341653790Sobrien */ 341753790Sobrien *divp = div; 341853790Sobrien *fakp = fak; 341953790Sobrien 342053790Sobrien return ret; 342153790Sobrien} 342253790Sobrien 342353790Sobrien/* 342474755Sgroudier * Tell the SCSI layer about the new transfer parameters. 342574755Sgroudier */ 3426178466Smariusstatic void 342774755Sgroudiersym_xpt_async_transfer_neg(hcb_p np, int target, u_int spi_valid) 342874755Sgroudier{ 342974755Sgroudier struct ccb_trans_settings cts; 343074755Sgroudier struct cam_path *path; 343174755Sgroudier int sts; 343274755Sgroudier tcb_p tp = &np->target[target]; 343374755Sgroudier 343474755Sgroudier sts = xpt_create_path(&path, NULL, cam_sim_path(np->sim), target, 343574755Sgroudier CAM_LUN_WILDCARD); 343674755Sgroudier if (sts != CAM_REQ_CMP) 343774755Sgroudier return; 343874755Sgroudier 343974755Sgroudier bzero(&cts, sizeof(cts)); 344074755Sgroudier 344174755Sgroudier#define cts__scsi (cts.proto_specific.scsi) 344274755Sgroudier#define cts__spi (cts.xport_specific.spi) 344374755Sgroudier 344474755Sgroudier cts.type = CTS_TYPE_CURRENT_SETTINGS; 344574755Sgroudier cts.protocol = PROTO_SCSI; 344674755Sgroudier cts.transport = XPORT_SPI; 344774755Sgroudier cts.protocol_version = tp->tinfo.current.scsi_version; 344874755Sgroudier cts.transport_version = tp->tinfo.current.spi_version; 344974755Sgroudier 345074755Sgroudier cts__spi.valid = spi_valid; 345174755Sgroudier if (spi_valid & CTS_SPI_VALID_SYNC_RATE) 345274755Sgroudier cts__spi.sync_period = tp->tinfo.current.period; 345374755Sgroudier if (spi_valid & CTS_SPI_VALID_SYNC_OFFSET) 345474755Sgroudier cts__spi.sync_offset = tp->tinfo.current.offset; 345574755Sgroudier if (spi_valid & CTS_SPI_VALID_BUS_WIDTH) 345674755Sgroudier cts__spi.bus_width = tp->tinfo.current.width; 345774755Sgroudier if (spi_valid & CTS_SPI_VALID_PPR_OPTIONS) 345874755Sgroudier cts__spi.ppr_options = tp->tinfo.current.options; 345974755Sgroudier#undef cts__spi 346074755Sgroudier#undef cts__scsi 346174755Sgroudier xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 346274755Sgroudier xpt_async(AC_TRANSFER_NEG, path, &cts); 346374755Sgroudier xpt_free_path(path); 346474755Sgroudier} 346574755Sgroudier 346674755Sgroudier#define SYM_SPI_VALID_WDTR \ 346774755Sgroudier CTS_SPI_VALID_BUS_WIDTH | \ 346874755Sgroudier CTS_SPI_VALID_SYNC_RATE | \ 346974755Sgroudier CTS_SPI_VALID_SYNC_OFFSET 347074755Sgroudier#define SYM_SPI_VALID_SDTR \ 347174755Sgroudier CTS_SPI_VALID_SYNC_RATE | \ 347274755Sgroudier CTS_SPI_VALID_SYNC_OFFSET 347374755Sgroudier#define SYM_SPI_VALID_PPR \ 347474755Sgroudier CTS_SPI_VALID_PPR_OPTIONS | \ 347574755Sgroudier CTS_SPI_VALID_BUS_WIDTH | \ 347674755Sgroudier CTS_SPI_VALID_SYNC_RATE | \ 347774755Sgroudier CTS_SPI_VALID_SYNC_OFFSET 347874755Sgroudier 347974755Sgroudier/* 348053790Sobrien * We received a WDTR. 348153790Sobrien * Let everything be aware of the changes. 348253790Sobrien */ 348353790Sobrienstatic void sym_setwide(hcb_p np, ccb_p cp, u_char wide) 348453790Sobrien{ 348553790Sobrien tcb_p tp = &np->target[cp->target]; 348653790Sobrien 348753790Sobrien sym_settrans(np, cp, 0, 0, 0, wide, 0, 0); 348853790Sobrien 348953790Sobrien /* 349053790Sobrien * Tell the SCSI layer about the new transfer parameters. 349153790Sobrien */ 349253790Sobrien tp->tinfo.goal.width = tp->tinfo.current.width = wide; 349353796Sobrien tp->tinfo.current.offset = 0; 349453796Sobrien tp->tinfo.current.period = 0; 349553809Sobrien tp->tinfo.current.options = 0; 349674755Sgroudier 349774755Sgroudier sym_xpt_async_transfer_neg(np, cp->target, SYM_SPI_VALID_WDTR); 349853790Sobrien} 349953790Sobrien 350053790Sobrien/* 350153790Sobrien * We received a SDTR. 350253790Sobrien * Let everything be aware of the changes. 350353790Sobrien */ 350453790Sobrienstatic void 350553790Sobriensym_setsync(hcb_p np, ccb_p cp, u_char ofs, u_char per, u_char div, u_char fak) 350653790Sobrien{ 350753790Sobrien tcb_p tp = &np->target[cp->target]; 350853790Sobrien u_char wide = (cp->phys.select.sel_scntl3 & EWS) ? 1 : 0; 350953790Sobrien 351053790Sobrien sym_settrans(np, cp, 0, ofs, per, wide, div, fak); 351153790Sobrien 351253790Sobrien /* 351353790Sobrien * Tell the SCSI layer about the new transfer parameters. 351453790Sobrien */ 351553790Sobrien tp->tinfo.goal.period = tp->tinfo.current.period = per; 351653790Sobrien tp->tinfo.goal.offset = tp->tinfo.current.offset = ofs; 351753790Sobrien tp->tinfo.goal.options = tp->tinfo.current.options = 0; 351874755Sgroudier 351974755Sgroudier sym_xpt_async_transfer_neg(np, cp->target, SYM_SPI_VALID_SDTR); 352053790Sobrien} 352153790Sobrien 352253790Sobrien/* 352353790Sobrien * We received a PPR. 352453790Sobrien * Let everything be aware of the changes. 352553790Sobrien */ 352653790Sobrienstatic void sym_setpprot(hcb_p np, ccb_p cp, u_char dt, u_char ofs, 352753790Sobrien u_char per, u_char wide, u_char div, u_char fak) 352853790Sobrien{ 352953790Sobrien tcb_p tp = &np->target[cp->target]; 353053790Sobrien 353153790Sobrien sym_settrans(np, cp, dt, ofs, per, wide, div, fak); 353253790Sobrien 353353790Sobrien /* 353453790Sobrien * Tell the SCSI layer about the new transfer parameters. 353553790Sobrien */ 353653790Sobrien tp->tinfo.goal.width = tp->tinfo.current.width = wide; 353753790Sobrien tp->tinfo.goal.period = tp->tinfo.current.period = per; 353853790Sobrien tp->tinfo.goal.offset = tp->tinfo.current.offset = ofs; 353953809Sobrien tp->tinfo.goal.options = tp->tinfo.current.options = dt; 354074755Sgroudier 354174755Sgroudier sym_xpt_async_transfer_neg(np, cp->target, SYM_SPI_VALID_PPR); 354253790Sobrien} 354353790Sobrien 354453790Sobrien/* 354553790Sobrien * Switch trans mode for current job and it's target. 354653790Sobrien */ 354753790Sobrienstatic void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs, 354853790Sobrien u_char per, u_char wide, u_char div, u_char fak) 354953790Sobrien{ 355055300Sgroudier SYM_QUEHEAD *qp; 355153790Sobrien union ccb *ccb; 355253790Sobrien tcb_p tp; 355353790Sobrien u_char target = INB (nc_sdid) & 0x0f; 355453790Sobrien u_char sval, wval, uval; 355553790Sobrien 355653790Sobrien assert (cp); 355753790Sobrien if (!cp) return; 355853790Sobrien ccb = cp->cam_ccb; 355953790Sobrien assert (ccb); 356053790Sobrien if (!ccb) return; 356153790Sobrien assert (target == (cp->target & 0xf)); 356253790Sobrien tp = &np->target[target]; 356353790Sobrien 356459743Sgroudier sval = tp->head.sval; 356559743Sgroudier wval = tp->head.wval; 356659743Sgroudier uval = tp->head.uval; 356757186Sgroudier 356853790Sobrien#if 0 3569178466Smarius printf("XXXX sval=%x wval=%x uval=%x (%x)\n", 357053790Sobrien sval, wval, uval, np->rv_scntl3); 357153790Sobrien#endif 357253790Sobrien /* 357353790Sobrien * Set the offset. 357453790Sobrien */ 357553790Sobrien if (!(np->features & FE_C10)) 357653790Sobrien sval = (sval & ~0x1f) | ofs; 357753790Sobrien else 357853790Sobrien sval = (sval & ~0x3f) | ofs; 357953790Sobrien 358053790Sobrien /* 358153790Sobrien * Set the sync divisor and extra clock factor. 358253790Sobrien */ 358353790Sobrien if (ofs != 0) { 358453790Sobrien wval = (wval & ~0x70) | ((div+1) << 4); 358553790Sobrien if (!(np->features & FE_C10)) 358653790Sobrien sval = (sval & ~0xe0) | (fak << 5); 358753790Sobrien else { 358853790Sobrien uval = uval & ~(XCLKH_ST|XCLKH_DT|XCLKS_ST|XCLKS_DT); 358953790Sobrien if (fak >= 1) uval |= (XCLKH_ST|XCLKH_DT); 359053790Sobrien if (fak >= 2) uval |= (XCLKS_ST|XCLKS_DT); 359153790Sobrien } 359253790Sobrien } 359353790Sobrien 359453790Sobrien /* 359553790Sobrien * Set the bus width. 359653790Sobrien */ 359753790Sobrien wval = wval & ~EWS; 359853790Sobrien if (wide != 0) 359953790Sobrien wval |= EWS; 360053790Sobrien 360153790Sobrien /* 360253790Sobrien * Set misc. ultra enable bits. 360353790Sobrien */ 360453790Sobrien if (np->features & FE_C10) { 360561051Sgroudier uval = uval & ~(U3EN|AIPCKEN); 360653790Sobrien if (dt) { 360753790Sobrien assert(np->features & FE_U3EN); 360853790Sobrien uval |= U3EN; 360954690Sobrien } 361053790Sobrien } 361153790Sobrien else { 361253790Sobrien wval = wval & ~ULTRA; 361353790Sobrien if (per <= 12) wval |= ULTRA; 361453790Sobrien } 361553790Sobrien 361653790Sobrien /* 361753790Sobrien * Stop there if sync parameters are unchanged. 361853790Sobrien */ 3619178466Smarius if (tp->head.sval == sval && 362059743Sgroudier tp->head.wval == wval && 362159743Sgroudier tp->head.uval == uval) 362259743Sgroudier return; 362359743Sgroudier tp->head.sval = sval; 362459743Sgroudier tp->head.wval = wval; 362559743Sgroudier tp->head.uval = uval; 362653790Sobrien 362753790Sobrien /* 362853790Sobrien * Disable extended Sreq/Sack filtering if per < 50. 362953790Sobrien * Not supported on the C1010. 363053790Sobrien */ 363153790Sobrien if (per < 50 && !(np->features & FE_C10)) 363253790Sobrien OUTOFFB (nc_stest2, EXT); 363353790Sobrien 363453790Sobrien /* 363553790Sobrien * set actual value and sync_status 363653790Sobrien */ 363759743Sgroudier OUTB (nc_sxfer, tp->head.sval); 363859743Sgroudier OUTB (nc_scntl3, tp->head.wval); 363953790Sobrien 364053790Sobrien if (np->features & FE_C10) { 364159743Sgroudier OUTB (nc_scntl4, tp->head.uval); 364253790Sobrien } 364353790Sobrien 364453790Sobrien /* 364555300Sgroudier * patch ALL busy ccbs of this target. 364653790Sobrien */ 364755300Sgroudier FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 364855300Sgroudier cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 364953790Sobrien if (cp->target != target) 365053790Sobrien continue; 365159743Sgroudier cp->phys.select.sel_scntl3 = tp->head.wval; 365259743Sgroudier cp->phys.select.sel_sxfer = tp->head.sval; 365353790Sobrien if (np->features & FE_C10) { 365459743Sgroudier cp->phys.select.sel_scntl4 = tp->head.uval; 365553790Sobrien } 365653790Sobrien } 365753790Sobrien} 365853790Sobrien 365953790Sobrien/* 366053790Sobrien * log message for real hard errors 366153790Sobrien * 366253790Sobrien * sym0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc). 366353790Sobrien * reg: r0 r1 r2 r3 r4 r5 r6 ..... rf. 366453790Sobrien * 366553790Sobrien * exception register: 366653790Sobrien * ds: dstat 366753790Sobrien * si: sist 366853790Sobrien * 366953790Sobrien * SCSI bus lines: 367053790Sobrien * so: control lines as driven by chip. 367153790Sobrien * si: control lines as seen by chip. 367253790Sobrien * sd: scsi data lines as seen by chip. 367353790Sobrien * 367453790Sobrien * wide/fastmode: 367553790Sobrien * sxfer: (see the manual) 367653790Sobrien * scntl3: (see the manual) 367753790Sobrien * 367853790Sobrien * current script command: 367980203Skris * dsp: script address (relative to start of script). 368053790Sobrien * dbc: first word of script command. 368153790Sobrien * 368253790Sobrien * First 24 register of the chip: 368353790Sobrien * r0..rf 368453790Sobrien */ 368553790Sobrienstatic void sym_log_hard_error(hcb_p np, u_short sist, u_char dstat) 368653790Sobrien{ 368753790Sobrien u32 dsp; 368853790Sobrien int script_ofs; 368953790Sobrien int script_size; 369053790Sobrien char *script_name; 369153790Sobrien u_char *script_base; 369253790Sobrien int i; 369353790Sobrien 369453790Sobrien dsp = INL (nc_dsp); 369553790Sobrien 369659292Sgroudier if (dsp > np->scripta_ba && 369759743Sgroudier dsp <= np->scripta_ba + np->scripta_sz) { 369859292Sgroudier script_ofs = dsp - np->scripta_ba; 369959743Sgroudier script_size = np->scripta_sz; 370059292Sgroudier script_base = (u_char *) np->scripta0; 370159292Sgroudier script_name = "scripta"; 370253790Sobrien } 3703178466Smarius else if (np->scriptb_ba < dsp && 370459743Sgroudier dsp <= np->scriptb_ba + np->scriptb_sz) { 370559292Sgroudier script_ofs = dsp - np->scriptb_ba; 370659743Sgroudier script_size = np->scriptb_sz; 370759292Sgroudier script_base = (u_char *) np->scriptb0; 370859292Sgroudier script_name = "scriptb"; 370953790Sobrien } else { 371053790Sobrien script_ofs = dsp; 371153790Sobrien script_size = 0; 371253790Sobrien script_base = 0; 371353790Sobrien script_name = "mem"; 371453790Sobrien } 371553790Sobrien 371653790Sobrien printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n", 371753790Sobrien sym_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist, 371853790Sobrien (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), 371953790Sobrien (unsigned)INB (nc_sbdl), (unsigned)INB (nc_sxfer), 372053790Sobrien (unsigned)INB (nc_scntl3), script_name, script_ofs, 372153790Sobrien (unsigned)INL (nc_dbc)); 372253790Sobrien 372353790Sobrien if (((script_ofs & 3) == 0) && 372453790Sobrien (unsigned)script_ofs < script_size) { 372553790Sobrien printf ("%s: script cmd = %08x\n", sym_name(np), 372653790Sobrien scr_to_cpu((int) *(u32 *)(script_base + script_ofs))); 372753790Sobrien } 372853790Sobrien 372953790Sobrien printf ("%s: regdump:", sym_name(np)); 373053790Sobrien for (i=0; i<24;i++) 373153790Sobrien printf (" %02x", (unsigned)INB_OFF(i)); 373253790Sobrien printf (".\n"); 373353790Sobrien 373453790Sobrien /* 373553790Sobrien * PCI BUS error, read the PCI ststus register. 373653790Sobrien */ 373753790Sobrien if (dstat & (MDPE|BF)) { 373853790Sobrien u_short pci_sts; 373953790Sobrien pci_sts = pci_read_config(np->device, PCIR_STATUS, 2); 374053790Sobrien if (pci_sts & 0xf900) { 374153790Sobrien pci_write_config(np->device, PCIR_STATUS, pci_sts, 2); 374253790Sobrien printf("%s: PCI STATUS = 0x%04x\n", 374353790Sobrien sym_name(np), pci_sts & 0xf900); 374453790Sobrien } 374553790Sobrien } 374653790Sobrien} 374753790Sobrien 374853790Sobrien/* 374953790Sobrien * chip interrupt handler 375053790Sobrien * 3751178466Smarius * In normal situations, interrupt conditions occur one at 3752178466Smarius * a time. But when something bad happens on the SCSI BUS, 3753178466Smarius * the chip may raise several interrupt flags before 3754178466Smarius * stopping and interrupting the CPU. The additionnal 3755178466Smarius * interrupt flags are stacked in some extra registers 3756178466Smarius * after the SIP and/or DIP flag has been raised in the 3757178466Smarius * ISTAT. After the CPU has read the interrupt condition 3758178466Smarius * flag from SIST or DSTAT, the chip unstacks the other 3759178466Smarius * interrupt flags and sets the corresponding bits in 3760178466Smarius * SIST or DSTAT. Since the chip starts stacking once the 3761178466Smarius * SIP or DIP flag is set, there is a small window of time 376253790Sobrien * where the stacking does not occur. 376353790Sobrien * 3764178466Smarius * Typically, multiple interrupt conditions may happen in 376553790Sobrien * the following situations: 376653790Sobrien * 376753790Sobrien * - SCSI parity error + Phase mismatch (PAR|MA) 3768178466Smarius * When a parity error is detected in input phase 3769178466Smarius * and the device switches to msg-in phase inside a 377053790Sobrien * block MOV. 377153790Sobrien * - SCSI parity error + Unexpected disconnect (PAR|UDC) 3772178466Smarius * When a stupid device does not want to handle the 377353790Sobrien * recovery of an SCSI parity error. 377453790Sobrien * - Some combinations of STO, PAR, UDC, ... 3775178466Smarius * When using non compliant SCSI stuff, when user is 3776178466Smarius * doing non compliant hot tampering on the BUS, when 377753790Sobrien * something really bad happens to a device, etc ... 377853790Sobrien * 3779178466Smarius * The heuristic suggested by SYMBIOS to handle 3780178466Smarius * multiple interrupts is to try unstacking all 3781178466Smarius * interrupts conditions and to handle them on some 378253790Sobrien * priority based on error severity. 3783178466Smarius * This will work when the unstacking has been 3784178466Smarius * successful, but we cannot be 100 % sure of that, 3785178466Smarius * since the CPU may have been faster to unstack than 3786178466Smarius * the chip is able to stack. Hmmm ... But it seems that 378753790Sobrien * such a situation is very unlikely to happen. 378853790Sobrien * 3789178466Smarius * If this happen, for example STO caught by the CPU 3790178466Smarius * then UDC happenning before the CPU have restarted 3791178466Smarius * the SCRIPTS, the driver may wrongly complete the 3792178466Smarius * same command on UDC, since the SCRIPTS didn't restart 379353790Sobrien * and the DSA still points to the same command. 3794178466Smarius * We avoid this situation by setting the DSA to an 3795178466Smarius * invalid value when the CCB is completed and before 379653790Sobrien * restarting the SCRIPTS. 379753790Sobrien * 3798178466Smarius * Another issue is that we need some section of our 3799178466Smarius * recovery procedures to be somehow uninterruptible but 3800178466Smarius * the SCRIPTS processor does not provides such a 3801178466Smarius * feature. For this reason, we handle recovery preferently 3802178466Smarius * from the C code and check against some SCRIPTS critical 380353790Sobrien * sections from the C code. 380453790Sobrien * 3805178466Smarius * Hopefully, the interrupt handling of the driver is now 3806178466Smarius * able to resist to weird BUS error conditions, but donnot 380753790Sobrien * ask me for any guarantee that it will never fail. :-) 380853790Sobrien * Use at your own decision and risk. 380953790Sobrien */ 381053790Sobrienstatic void sym_intr1 (hcb_p np) 381153790Sobrien{ 381253790Sobrien u_char istat, istatc; 381353790Sobrien u_char dstat; 381453790Sobrien u_short sist; 381553790Sobrien 3816178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 3817178468Smarius 381853790Sobrien /* 381953790Sobrien * interrupt on the fly ? 382062422Sgroudier * 3821178466Smarius * A `dummy read' is needed to ensure that the 3822178466Smarius * clear of the INTF flag reaches the device 382362422Sgroudier * before the scanning of the DONE queue. 382453790Sobrien */ 382553790Sobrien istat = INB (nc_istat); 382653790Sobrien if (istat & INTF) { 382753790Sobrien OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem); 382853790Sobrien istat = INB (nc_istat); /* DUMMY READ */ 382953790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("F "); 383053790Sobrien (void)sym_wakeup_done (np); 383153790Sobrien }; 383253790Sobrien 383353790Sobrien if (!(istat & (SIP|DIP))) 383453790Sobrien return; 383553790Sobrien 383653790Sobrien#if 0 /* We should never get this one */ 383753790Sobrien if (istat & CABRT) 383853790Sobrien OUTB (nc_istat, CABRT); 383953790Sobrien#endif 384053790Sobrien 384153790Sobrien /* 384253790Sobrien * PAR and MA interrupts may occur at the same time, 3843178466Smarius * and we need to know of both in order to handle 3844178466Smarius * this situation properly. We try to unstack SCSI 3845178466Smarius * interrupts for that reason. BTW, I dislike a LOT 384653790Sobrien * such a loop inside the interrupt routine. 3847178466Smarius * Even if DMA interrupt stacking is very unlikely to 3848178466Smarius * happen, we also try unstacking these ones, since 384953790Sobrien * this has no performance impact. 385053790Sobrien */ 385153790Sobrien sist = 0; 385253790Sobrien dstat = 0; 385353790Sobrien istatc = istat; 385453790Sobrien do { 385553790Sobrien if (istatc & SIP) 385653790Sobrien sist |= INW (nc_sist); 385753790Sobrien if (istatc & DIP) 385853790Sobrien dstat |= INB (nc_dstat); 385953790Sobrien istatc = INB (nc_istat); 386053790Sobrien istat |= istatc; 386153790Sobrien } while (istatc & (SIP|DIP)); 386253790Sobrien 386353790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) 386453790Sobrien printf ("<%d|%x:%x|%x:%x>", 386553790Sobrien (int)INB(nc_scr0), 386653790Sobrien dstat,sist, 386753790Sobrien (unsigned)INL(nc_dsp), 386853790Sobrien (unsigned)INL(nc_dbc)); 386953790Sobrien /* 387062422Sgroudier * On paper, a memory barrier may be needed here. 387162422Sgroudier * And since we are paranoid ... :) 387262422Sgroudier */ 387362422Sgroudier MEMORY_BARRIER(); 387462422Sgroudier 387562422Sgroudier /* 387653790Sobrien * First, interrupts we want to service cleanly. 387753790Sobrien * 3878178466Smarius * Phase mismatch (MA) is the most frequent interrupt 3879178466Smarius * for chip earlier than the 896 and so we have to service 388053790Sobrien * it as quickly as possible. 3881178466Smarius * A SCSI parity error (PAR) may be combined with a phase 388253790Sobrien * mismatch condition (MA). 3883178466Smarius * Programmed interrupts (SIR) are used to call the C code 388453790Sobrien * from SCRIPTS. 3885178466Smarius * The single step interrupt (SSI) is not used in this 388653790Sobrien * driver. 388753790Sobrien */ 388853790Sobrien if (!(sist & (STO|GEN|HTH|SGE|UDC|SBMC|RST)) && 388953790Sobrien !(dstat & (MDPE|BF|ABRT|IID))) { 389053790Sobrien if (sist & PAR) sym_int_par (np, sist); 389153790Sobrien else if (sist & MA) sym_int_ma (np); 389253790Sobrien else if (dstat & SIR) sym_int_sir (np); 389361429Sgroudier else if (dstat & SSI) OUTONB_STD (); 389453790Sobrien else goto unknown_int; 389553790Sobrien return; 389653790Sobrien }; 389753790Sobrien 389853790Sobrien /* 3899178466Smarius * Now, interrupts that donnot happen in normal 390053790Sobrien * situations and that we may need to recover from. 390153790Sobrien * 390253790Sobrien * On SCSI RESET (RST), we reset everything. 3903178466Smarius * On SCSI BUS MODE CHANGE (SBMC), we complete all 3904178466Smarius * active CCBs with RESET status, prepare all devices 390553790Sobrien * for negotiating again and restart the SCRIPTS. 3906178466Smarius * On STO and UDC, we complete the CCB with the corres- 390753790Sobrien * ponding status and restart the SCRIPTS. 390853790Sobrien */ 390953790Sobrien if (sist & RST) { 391055300Sgroudier xpt_print_path(np->path); 391155300Sgroudier printf("SCSI BUS reset detected.\n"); 391255300Sgroudier sym_init (np, 1); 391353790Sobrien return; 391453790Sobrien }; 391553790Sobrien 391653790Sobrien OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ 391753790Sobrien OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ 391853790Sobrien 391953790Sobrien if (!(sist & (GEN|HTH|SGE)) && 392053790Sobrien !(dstat & (MDPE|BF|ABRT|IID))) { 392153790Sobrien if (sist & SBMC) sym_int_sbmc (np); 392253790Sobrien else if (sist & STO) sym_int_sto (np); 392353790Sobrien else if (sist & UDC) sym_int_udc (np); 392453790Sobrien else goto unknown_int; 392553790Sobrien return; 392653790Sobrien }; 392753790Sobrien 392853790Sobrien /* 392953790Sobrien * Now, interrupts we are not able to recover cleanly. 393053790Sobrien * 393153790Sobrien * Log message for hard errors. 393253790Sobrien * Reset everything. 393353790Sobrien */ 393453790Sobrien 393553790Sobrien sym_log_hard_error(np, sist, dstat); 393653790Sobrien 393753790Sobrien if ((sist & (GEN|HTH|SGE)) || 393853790Sobrien (dstat & (MDPE|BF|ABRT|IID))) { 393953790Sobrien sym_start_reset(np); 394053790Sobrien return; 394153790Sobrien }; 394253790Sobrien 394353790Sobrienunknown_int: 394453790Sobrien /* 394553790Sobrien * We just miss the cause of the interrupt. :( 394653790Sobrien * Print a message. The timeout will do the real work. 394753790Sobrien */ 394853790Sobrien printf( "%s: unknown interrupt(s) ignored, " 394953790Sobrien "ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n", 395053790Sobrien sym_name(np), istat, dstat, sist); 395153790Sobrien} 395253790Sobrien 395353790Sobrienstatic void sym_intr(void *arg) 395453790Sobrien{ 3955178468Smarius hcb_p np = arg; 3956178468Smarius 3957178468Smarius SYM_LOCK(); 3958179029Smarius 395953790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("["); 396053790Sobrien sym_intr1((hcb_p) arg); 396153790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("]"); 3962179029Smarius 3963178468Smarius SYM_UNLOCK(); 396453790Sobrien} 396553790Sobrien 396653790Sobrienstatic void sym_poll(struct cam_sim *sim) 396753790Sobrien{ 3968178468Smarius sym_intr1(cam_sim_softc(sim)); 396953790Sobrien} 397053790Sobrien 397153790Sobrien/* 397253790Sobrien * generic recovery from scsi interrupt 397353790Sobrien * 397453790Sobrien * The doc says that when the chip gets an SCSI interrupt, 3975178466Smarius * it tries to stop in an orderly fashion, by completing 3976178466Smarius * an instruction fetch that had started or by flushing 397753790Sobrien * the DMA fifo for a write to memory that was executing. 3978178466Smarius * Such a fashion is not enough to know if the instruction 3979178466Smarius * that was just before the current DSP value has been 398053790Sobrien * executed or not. 398153790Sobrien * 3982178466Smarius * There are some small SCRIPTS sections that deal with 3983178466Smarius * the start queue and the done queue that may break any 3984178466Smarius * assomption from the C code if we are interrupted 3985178466Smarius * inside, so we reset if this happens. Btw, since these 3986178466Smarius * SCRIPTS sections are executed while the SCRIPTS hasn't 398753790Sobrien * started SCSI operations, it is very unlikely to happen. 398853790Sobrien * 3989178466Smarius * All the driver data structures are supposed to be 3990178466Smarius * allocated from the same 4 GB memory window, so there 3991178466Smarius * is a 1 to 1 relationship between DSA and driver data 3992178466Smarius * structures. Since we are careful :) to invalidate the 3993178466Smarius * DSA when we complete a command or when the SCRIPTS 3994178466Smarius * pushes a DSA into a queue, we can trust it when it 399553790Sobrien * points to a CCB. 399653790Sobrien */ 399753790Sobrienstatic void sym_recover_scsi_int (hcb_p np, u_char hsts) 399853790Sobrien{ 399953790Sobrien u32 dsp = INL (nc_dsp); 400053790Sobrien u32 dsa = INL (nc_dsa); 400153790Sobrien ccb_p cp = sym_ccb_from_dsa(np, dsa); 400253790Sobrien 400353790Sobrien /* 4004178466Smarius * If we haven't been interrupted inside the SCRIPTS 4005178466Smarius * critical pathes, we can safely restart the SCRIPTS 400653790Sobrien * and trust the DSA value if it matches a CCB. 400753790Sobrien */ 400859292Sgroudier if ((!(dsp > SCRIPTA_BA (np, getjob_begin) && 400959292Sgroudier dsp < SCRIPTA_BA (np, getjob_end) + 1)) && 401059292Sgroudier (!(dsp > SCRIPTA_BA (np, ungetjob) && 401159292Sgroudier dsp < SCRIPTA_BA (np, reselect) + 1)) && 401259292Sgroudier (!(dsp > SCRIPTB_BA (np, sel_for_abort) && 401359292Sgroudier dsp < SCRIPTB_BA (np, sel_for_abort_1) + 1)) && 401459292Sgroudier (!(dsp > SCRIPTA_BA (np, done) && 401559292Sgroudier dsp < SCRIPTA_BA (np, done_end) + 1))) { 401653790Sobrien OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ 401753790Sobrien OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ 401853790Sobrien /* 4019178466Smarius * If we have a CCB, let the SCRIPTS call us back for 4020178466Smarius * the handling of the error with SCRATCHA filled with 4021178466Smarius * STARTPOS. This way, we will be able to freeze the 402253790Sobrien * device queue and requeue awaiting IOs. 402353790Sobrien */ 402453790Sobrien if (cp) { 402553790Sobrien cp->host_status = hsts; 402661429Sgroudier OUTL_DSP (SCRIPTA_BA (np, complete_error)); 402753790Sobrien } 402853790Sobrien /* 402953790Sobrien * Otherwise just restart the SCRIPTS. 403053790Sobrien */ 403153790Sobrien else { 403253790Sobrien OUTL (nc_dsa, 0xffffff); 403361429Sgroudier OUTL_DSP (SCRIPTA_BA (np, start)); 403453790Sobrien } 403553790Sobrien } 403653790Sobrien else 403753790Sobrien goto reset_all; 403853790Sobrien 403953790Sobrien return; 404053790Sobrien 404153790Sobrienreset_all: 404253790Sobrien sym_start_reset(np); 404353790Sobrien} 404453790Sobrien 404553790Sobrien/* 404653790Sobrien * chip exception handler for selection timeout 404753790Sobrien */ 4048105215Sphkstatic void sym_int_sto (hcb_p np) 404953790Sobrien{ 405053790Sobrien u32 dsp = INL (nc_dsp); 405153790Sobrien 405253790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("T"); 405353790Sobrien 405459292Sgroudier if (dsp == SCRIPTA_BA (np, wf_sel_done) + 8) 405553790Sobrien sym_recover_scsi_int(np, HS_SEL_TIMEOUT); 405653790Sobrien else 405753790Sobrien sym_start_reset(np); 405853790Sobrien} 405953790Sobrien 406053790Sobrien/* 406153790Sobrien * chip exception handler for unexpected disconnect 406253790Sobrien */ 4063105215Sphkstatic void sym_int_udc (hcb_p np) 406453790Sobrien{ 406553790Sobrien printf ("%s: unexpected disconnect\n", sym_name(np)); 406653790Sobrien sym_recover_scsi_int(np, HS_UNEXPECTED); 406753790Sobrien} 406853790Sobrien 406953790Sobrien/* 407053790Sobrien * chip exception handler for SCSI bus mode change 407153790Sobrien * 4072178466Smarius * spi2-r12 11.2.3 says a transceiver mode change must 4073178466Smarius * generate a reset event and a device that detects a reset 407453790Sobrien * event shall initiate a hard reset. It says also that a 4075178466Smarius * device that detects a mode change shall set data transfer 407653790Sobrien * mode to eight bit asynchronous, etc... 407753790Sobrien * So, just reinitializing all except chip should be enough. 407853790Sobrien */ 407953790Sobrienstatic void sym_int_sbmc (hcb_p np) 408053790Sobrien{ 408153790Sobrien u_char scsi_mode = INB (nc_stest4) & SMODE; 408253790Sobrien 408355300Sgroudier /* 408455300Sgroudier * Notify user. 408555300Sgroudier */ 408655300Sgroudier xpt_print_path(np->path); 408755300Sgroudier printf("SCSI BUS mode change from %s to %s.\n", 408855300Sgroudier sym_scsi_bus_mode(np->scsi_mode), sym_scsi_bus_mode(scsi_mode)); 408953790Sobrien 409053790Sobrien /* 4091178466Smarius * Should suspend command processing for a few seconds and 409253790Sobrien * reinitialize all except the chip. 409353790Sobrien */ 409455300Sgroudier sym_init (np, 2); 409553790Sobrien} 409653790Sobrien 409753790Sobrien/* 409853790Sobrien * chip exception handler for SCSI parity error. 409953790Sobrien * 4100178466Smarius * When the chip detects a SCSI parity error and is 4101178466Smarius * currently executing a (CH)MOV instruction, it does 4102178466Smarius * not interrupt immediately, but tries to finish the 4103178466Smarius * transfer of the current scatter entry before 410453790Sobrien * interrupting. The following situations may occur: 410553790Sobrien * 4106178466Smarius * - The complete scatter entry has been transferred 410753790Sobrien * without the device having changed phase. 4108178466Smarius * The chip will then interrupt with the DSP pointing 410953790Sobrien * to the instruction that follows the MOV. 411053790Sobrien * 4111178466Smarius * - A phase mismatch occurs before the MOV finished 411253790Sobrien * and phase errors are to be handled by the C code. 4113178466Smarius * The chip will then interrupt with both PAR and MA 411453790Sobrien * conditions set. 411553790Sobrien * 4116178466Smarius * - A phase mismatch occurs before the MOV finished and 411753790Sobrien * phase errors are to be handled by SCRIPTS. 4118178466Smarius * The chip will load the DSP with the phase mismatch 411953790Sobrien * JUMP address and interrupt the host processor. 412053790Sobrien */ 412153790Sobrienstatic void sym_int_par (hcb_p np, u_short sist) 412253790Sobrien{ 412353790Sobrien u_char hsts = INB (HS_PRT); 412453790Sobrien u32 dsp = INL (nc_dsp); 412553790Sobrien u32 dbc = INL (nc_dbc); 412653790Sobrien u32 dsa = INL (nc_dsa); 412753790Sobrien u_char sbcl = INB (nc_sbcl); 412853790Sobrien u_char cmd = dbc >> 24; 412953790Sobrien int phase = cmd & 7; 413053790Sobrien ccb_p cp = sym_ccb_from_dsa(np, dsa); 413153790Sobrien 413253790Sobrien printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n", 413353790Sobrien sym_name(np), hsts, dbc, sbcl); 413453790Sobrien 413553790Sobrien /* 413653790Sobrien * Check that the chip is connected to the SCSI BUS. 413753790Sobrien */ 413853790Sobrien if (!(INB (nc_scntl1) & ISCON)) { 413953790Sobrien sym_recover_scsi_int(np, HS_UNEXPECTED); 414053790Sobrien return; 414153790Sobrien } 414253790Sobrien 414353790Sobrien /* 414453790Sobrien * If the nexus is not clearly identified, reset the bus. 414553790Sobrien * We will try to do better later. 414653790Sobrien */ 414753790Sobrien if (!cp) 414853790Sobrien goto reset_all; 414953790Sobrien 415053790Sobrien /* 4151178466Smarius * Check instruction was a MOV, direction was INPUT and 415253790Sobrien * ATN is asserted. 415353790Sobrien */ 415453790Sobrien if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8)) 415553790Sobrien goto reset_all; 415653790Sobrien 415753790Sobrien /* 415853790Sobrien * Keep track of the parity error. 415953790Sobrien */ 416053790Sobrien OUTONB (HF_PRT, HF_EXT_ERR); 416153790Sobrien cp->xerr_status |= XE_PARITY_ERR; 416253790Sobrien 416353790Sobrien /* 416453790Sobrien * Prepare the message to send to the device. 416553790Sobrien */ 416653790Sobrien np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR; 416753790Sobrien 416853790Sobrien /* 416953790Sobrien * If the old phase was DATA IN phase, we have to deal with 417053790Sobrien * the 3 situations described above. 4171178466Smarius * For other input phases (MSG IN and STATUS), the device 4172178466Smarius * must resend the whole thing that failed parity checking 417353790Sobrien * or signal error. So, jumping to dispatcher should be OK. 417453790Sobrien */ 417562134Sgroudier if (phase == 1 || phase == 5) { 417653790Sobrien /* Phase mismatch handled by SCRIPTS */ 417759292Sgroudier if (dsp == SCRIPTB_BA (np, pm_handle)) 417861429Sgroudier OUTL_DSP (dsp); 417953790Sobrien /* Phase mismatch handled by the C code */ 418053790Sobrien else if (sist & MA) 418153790Sobrien sym_int_ma (np); 418253790Sobrien /* No phase mismatch occurred */ 418353790Sobrien else { 418453790Sobrien OUTL (nc_temp, dsp); 418561429Sgroudier OUTL_DSP (SCRIPTA_BA (np, dispatch)); 418653790Sobrien } 418753790Sobrien } 4188178466Smarius else 418961429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 419053790Sobrien return; 419153790Sobrien 419253790Sobrienreset_all: 419353790Sobrien sym_start_reset(np); 419453790Sobrien} 419553790Sobrien 419653790Sobrien/* 419753790Sobrien * chip exception handler for phase errors. 419853790Sobrien * 419953790Sobrien * We have to construct a new transfer descriptor, 420053790Sobrien * to transfer the rest of the current block. 420153790Sobrien */ 420253790Sobrienstatic void sym_int_ma (hcb_p np) 420353790Sobrien{ 420453790Sobrien u32 dbc; 420553790Sobrien u32 rest; 420653790Sobrien u32 dsp; 420753790Sobrien u32 dsa; 420853790Sobrien u32 nxtdsp; 420953790Sobrien u32 *vdsp; 421053790Sobrien u32 oadr, olen; 421153790Sobrien u32 *tblp; 421253790Sobrien u32 newcmd; 421353790Sobrien u_int delta; 421453790Sobrien u_char cmd; 421553790Sobrien u_char hflags, hflags0; 421653790Sobrien struct sym_pmc *pm; 421753790Sobrien ccb_p cp; 421853790Sobrien 421953790Sobrien dsp = INL (nc_dsp); 422053790Sobrien dbc = INL (nc_dbc); 422153790Sobrien dsa = INL (nc_dsa); 422253790Sobrien 422353790Sobrien cmd = dbc >> 24; 422453790Sobrien rest = dbc & 0xffffff; 422553790Sobrien delta = 0; 422653790Sobrien 422753790Sobrien /* 422853790Sobrien * locate matching cp if any. 422953790Sobrien */ 423053790Sobrien cp = sym_ccb_from_dsa(np, dsa); 423153790Sobrien 423253790Sobrien /* 4233178466Smarius * Donnot take into account dma fifo and various buffers in 4234178466Smarius * INPUT phase since the chip flushes everything before 423553790Sobrien * raising the MA interrupt for interrupted INPUT phases. 423653790Sobrien * For DATA IN phase, we will check for the SWIDE later. 423753790Sobrien */ 423862134Sgroudier if ((cmd & 7) != 1 && (cmd & 7) != 5) { 423953790Sobrien u_char ss0, ss2; 424053790Sobrien 424153790Sobrien if (np->features & FE_DFBC) 424253790Sobrien delta = INW (nc_dfbc); 424353790Sobrien else { 424453790Sobrien u32 dfifo; 424553790Sobrien 424653790Sobrien /* 424753790Sobrien * Read DFIFO, CTEST[4-6] using 1 PCI bus ownership. 424853790Sobrien */ 424953790Sobrien dfifo = INL(nc_dfifo); 425053790Sobrien 425153790Sobrien /* 425253790Sobrien * Calculate remaining bytes in DMA fifo. 425353790Sobrien * (CTEST5 = dfifo >> 16) 425453790Sobrien */ 425553790Sobrien if (dfifo & (DFS << 16)) 425653790Sobrien delta = ((((dfifo >> 8) & 0x300) | 425753790Sobrien (dfifo & 0xff)) - rest) & 0x3ff; 425853790Sobrien else 425953790Sobrien delta = ((dfifo & 0xff) - rest) & 0x7f; 426053790Sobrien } 426153790Sobrien 426253790Sobrien /* 4263220944Smarius * The data in the dma fifo has not been transferred to 426453790Sobrien * the target -> add the amount to the rest 426553790Sobrien * and clear the data. 426653790Sobrien * Check the sstat2 register in case of wide transfer. 426753790Sobrien */ 426853790Sobrien rest += delta; 426953790Sobrien ss0 = INB (nc_sstat0); 427053790Sobrien if (ss0 & OLF) rest++; 427153790Sobrien if (!(np->features & FE_C10)) 427253790Sobrien if (ss0 & ORF) rest++; 427353790Sobrien if (cp && (cp->phys.select.sel_scntl3 & EWS)) { 427453790Sobrien ss2 = INB (nc_sstat2); 427553790Sobrien if (ss2 & OLF1) rest++; 427653790Sobrien if (!(np->features & FE_C10)) 427753790Sobrien if (ss2 & ORF1) rest++; 427853790Sobrien }; 427953790Sobrien 428053790Sobrien /* 428153790Sobrien * Clear fifos. 428253790Sobrien */ 428353790Sobrien OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* dma fifo */ 428453790Sobrien OUTB (nc_stest3, TE|CSF); /* scsi fifo */ 428553790Sobrien } 428653790Sobrien 428753790Sobrien /* 428853790Sobrien * log the information 428953790Sobrien */ 429053790Sobrien if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) 429153790Sobrien printf ("P%x%x RL=%d D=%d ", cmd&7, INB(nc_sbcl)&7, 429253790Sobrien (unsigned) rest, (unsigned) delta); 429353790Sobrien 429453790Sobrien /* 429553790Sobrien * try to find the interrupted script command, 429653790Sobrien * and the address at which to continue. 429753790Sobrien */ 429853790Sobrien vdsp = 0; 429953790Sobrien nxtdsp = 0; 430059292Sgroudier if (dsp > np->scripta_ba && 430159743Sgroudier dsp <= np->scripta_ba + np->scripta_sz) { 430259292Sgroudier vdsp = (u32 *)((char*)np->scripta0 + (dsp-np->scripta_ba-8)); 430353790Sobrien nxtdsp = dsp; 430453790Sobrien } 430559292Sgroudier else if (dsp > np->scriptb_ba && 430659743Sgroudier dsp <= np->scriptb_ba + np->scriptb_sz) { 430759292Sgroudier vdsp = (u32 *)((char*)np->scriptb0 + (dsp-np->scriptb_ba-8)); 430853790Sobrien nxtdsp = dsp; 430953790Sobrien } 431053790Sobrien 431153790Sobrien /* 431253790Sobrien * log the information 431353790Sobrien */ 431453790Sobrien if (DEBUG_FLAGS & DEBUG_PHASE) { 431553790Sobrien printf ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", 431653790Sobrien cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd); 431753790Sobrien }; 431853790Sobrien 431953790Sobrien if (!vdsp) { 4320178466Smarius printf ("%s: interrupted SCRIPT address not found.\n", 432153790Sobrien sym_name (np)); 432253790Sobrien goto reset_all; 432353790Sobrien } 432453790Sobrien 432553790Sobrien if (!cp) { 4326178466Smarius printf ("%s: SCSI phase error fixup: CCB already dequeued.\n", 432753790Sobrien sym_name (np)); 432853790Sobrien goto reset_all; 432953790Sobrien } 433053790Sobrien 433153790Sobrien /* 433253790Sobrien * get old startaddress and old length. 433353790Sobrien */ 433453790Sobrien oadr = scr_to_cpu(vdsp[1]); 433553790Sobrien 433653790Sobrien if (cmd & 0x10) { /* Table indirect */ 433753790Sobrien tblp = (u32 *) ((char*) &cp->phys + oadr); 433853790Sobrien olen = scr_to_cpu(tblp[0]); 433953790Sobrien oadr = scr_to_cpu(tblp[1]); 434053790Sobrien } else { 434153790Sobrien tblp = (u32 *) 0; 434253790Sobrien olen = scr_to_cpu(vdsp[0]) & 0xffffff; 434353790Sobrien }; 434453790Sobrien 434553790Sobrien if (DEBUG_FLAGS & DEBUG_PHASE) { 434653790Sobrien printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", 434753790Sobrien (unsigned) (scr_to_cpu(vdsp[0]) >> 24), 434853790Sobrien tblp, 434953790Sobrien (unsigned) olen, 435053790Sobrien (unsigned) oadr); 435153790Sobrien }; 435253790Sobrien 435353790Sobrien /* 435453790Sobrien * check cmd against assumed interrupted script command. 4355178466Smarius * If dt data phase, the MOVE instruction hasn't bit 4 of 435662134Sgroudier * the phase. 435753790Sobrien */ 435862134Sgroudier if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) { 435953790Sobrien PRINT_ADDR(cp); 436053790Sobrien printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", 436153790Sobrien (unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24); 436253790Sobrien 436353790Sobrien goto reset_all; 436453790Sobrien }; 436553790Sobrien 436653790Sobrien /* 436753790Sobrien * if old phase not dataphase, leave here. 436853790Sobrien */ 436962134Sgroudier if (cmd & 2) { 437053790Sobrien PRINT_ADDR(cp); 437153790Sobrien printf ("phase change %x-%x %d@%08x resid=%d.\n", 437253790Sobrien cmd&7, INB(nc_sbcl)&7, (unsigned)olen, 437353790Sobrien (unsigned)oadr, (unsigned)rest); 437453790Sobrien goto unexpected_phase; 437553790Sobrien }; 437653790Sobrien 437753790Sobrien /* 437853790Sobrien * Choose the correct PM save area. 437953790Sobrien * 4380178466Smarius * Look at the PM_SAVE SCRIPT if you want to understand 4381178466Smarius * this stuff. The equivalent code is implemented in 4382178466Smarius * SCRIPTS for the 895A, 896 and 1010 that are able to 438362422Sgroudier * handle PM from the SCRIPTS processor. 438453790Sobrien */ 438553790Sobrien hflags0 = INB (HF_PRT); 438653790Sobrien hflags = hflags0; 438753790Sobrien 438853790Sobrien if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) { 438953790Sobrien if (hflags & HF_IN_PM0) 439053790Sobrien nxtdsp = scr_to_cpu(cp->phys.pm0.ret); 439153790Sobrien else if (hflags & HF_IN_PM1) 439253790Sobrien nxtdsp = scr_to_cpu(cp->phys.pm1.ret); 439353790Sobrien 439453790Sobrien if (hflags & HF_DP_SAVED) 439553790Sobrien hflags ^= HF_ACT_PM; 439653790Sobrien } 439753790Sobrien 439853790Sobrien if (!(hflags & HF_ACT_PM)) { 439953790Sobrien pm = &cp->phys.pm0; 440059292Sgroudier newcmd = SCRIPTA_BA (np, pm0_data); 440153790Sobrien } 440253790Sobrien else { 440353790Sobrien pm = &cp->phys.pm1; 440459292Sgroudier newcmd = SCRIPTA_BA (np, pm1_data); 440553790Sobrien } 440653790Sobrien 440753790Sobrien hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED); 440853790Sobrien if (hflags != hflags0) 440953790Sobrien OUTB (HF_PRT, hflags); 441053790Sobrien 441153790Sobrien /* 441253790Sobrien * fillin the phase mismatch context 441353790Sobrien */ 441453790Sobrien pm->sg.addr = cpu_to_scr(oadr + olen - rest); 441553790Sobrien pm->sg.size = cpu_to_scr(rest); 441653790Sobrien pm->ret = cpu_to_scr(nxtdsp); 441753790Sobrien 441853790Sobrien /* 441953790Sobrien * If we have a SWIDE, 442053790Sobrien * - prepare the address to write the SWIDE from SCRIPTS, 442153790Sobrien * - compute the SCRIPTS address to restart from, 442253790Sobrien * - move current data pointer context by one byte. 442353790Sobrien */ 442459292Sgroudier nxtdsp = SCRIPTA_BA (np, dispatch); 442553790Sobrien if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) && 442653790Sobrien (INB (nc_scntl2) & WSR)) { 442757186Sgroudier u32 tmp; 442858927Sgroudier 442953790Sobrien /* 443057186Sgroudier * Set up the table indirect for the MOVE 4431178466Smarius * of the residual byte and adjust the data 443257186Sgroudier * pointer context. 443353790Sobrien */ 443457186Sgroudier tmp = scr_to_cpu(pm->sg.addr); 443557186Sgroudier cp->phys.wresid.addr = cpu_to_scr(tmp); 443657186Sgroudier pm->sg.addr = cpu_to_scr(tmp + 1); 443757186Sgroudier tmp = scr_to_cpu(pm->sg.size); 443857186Sgroudier cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1); 443957186Sgroudier pm->sg.size = cpu_to_scr(tmp - 1); 444057186Sgroudier 444153790Sobrien /* 4442178466Smarius * If only the residual byte is to be moved, 444357186Sgroudier * no PM context is needed. 444453790Sobrien */ 444557186Sgroudier if ((tmp&0xffffff) == 1) 444657186Sgroudier newcmd = pm->ret; 444757186Sgroudier 444857186Sgroudier /* 4449178466Smarius * Prepare the address of SCRIPTS that will 445057186Sgroudier * move the residual byte to memory. 445157186Sgroudier */ 445259292Sgroudier nxtdsp = SCRIPTB_BA (np, wsr_ma_helper); 445353790Sobrien } 445453790Sobrien 445553790Sobrien if (DEBUG_FLAGS & DEBUG_PHASE) { 445653790Sobrien PRINT_ADDR(cp); 445753790Sobrien printf ("PM %x %x %x / %x %x %x.\n", 445853790Sobrien hflags0, hflags, newcmd, 445953790Sobrien (unsigned)scr_to_cpu(pm->sg.addr), 446053790Sobrien (unsigned)scr_to_cpu(pm->sg.size), 446153790Sobrien (unsigned)scr_to_cpu(pm->ret)); 446253790Sobrien } 446353790Sobrien 446453790Sobrien /* 446553790Sobrien * Restart the SCRIPTS processor. 446653790Sobrien */ 446753790Sobrien OUTL (nc_temp, newcmd); 446861429Sgroudier OUTL_DSP (nxtdsp); 446953790Sobrien return; 447053790Sobrien 447153790Sobrien /* 4472178466Smarius * Unexpected phase changes that occurs when the current phase 447353790Sobrien * is not a DATA IN or DATA OUT phase are due to error conditions. 4474178466Smarius * Such event may only happen when the SCRIPTS is using a 447553790Sobrien * multibyte SCSI MOVE. 447653790Sobrien * 447753790Sobrien * Phase change Some possible cause 447853790Sobrien * 447953790Sobrien * COMMAND --> MSG IN SCSI parity error detected by target. 448053790Sobrien * COMMAND --> STATUS Bad command or refused by target. 448153790Sobrien * MSG OUT --> MSG IN Message rejected by target. 448253790Sobrien * MSG OUT --> COMMAND Bogus target that discards extended 448353790Sobrien * negotiation messages. 448453790Sobrien * 4485178466Smarius * The code below does not care of the new phase and so 448653790Sobrien * trusts the target. Why to annoy it ? 448753790Sobrien * If the interrupted phase is COMMAND phase, we restart at 448853790Sobrien * dispatcher. 4489178466Smarius * If a target does not get all the messages after selection, 4490178466Smarius * the code assumes blindly that the target discards extended 449153790Sobrien * messages and clears the negotiation status. 449253790Sobrien * If the target does not want all our response to negotiation, 4493178466Smarius * we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids 449453790Sobrien * bloat for such a should_not_happen situation). 449553790Sobrien * In all other situation, we reset the BUS. 449653790Sobrien * Are these assumptions reasonnable ? (Wait and see ...) 449753790Sobrien */ 449853790Sobrienunexpected_phase: 449953790Sobrien dsp -= 8; 450053790Sobrien nxtdsp = 0; 450153790Sobrien 450253790Sobrien switch (cmd & 7) { 450353790Sobrien case 2: /* COMMAND phase */ 450459292Sgroudier nxtdsp = SCRIPTA_BA (np, dispatch); 450553790Sobrien break; 450653790Sobrien#if 0 450753790Sobrien case 3: /* STATUS phase */ 450859292Sgroudier nxtdsp = SCRIPTA_BA (np, dispatch); 450953790Sobrien break; 451053790Sobrien#endif 451153790Sobrien case 6: /* MSG OUT phase */ 451253790Sobrien /* 4513178466Smarius * If the device may want to use untagged when we want 4514178466Smarius * tagged, we prepare an IDENTIFY without disc. granted, 451553790Sobrien * since we will not be able to handle reselect. 451653790Sobrien * Otherwise, we just don't care. 451753790Sobrien */ 451859292Sgroudier if (dsp == SCRIPTA_BA (np, send_ident)) { 451953790Sobrien if (cp->tag != NO_TAG && olen - rest <= 3) { 452053790Sobrien cp->host_status = HS_BUSY; 452153790Sobrien np->msgout[0] = M_IDENTIFY | cp->lun; 452259292Sgroudier nxtdsp = SCRIPTB_BA (np, ident_break_atn); 452353790Sobrien } 452453790Sobrien else 452559292Sgroudier nxtdsp = SCRIPTB_BA (np, ident_break); 452653790Sobrien } 452759292Sgroudier else if (dsp == SCRIPTB_BA (np, send_wdtr) || 452859292Sgroudier dsp == SCRIPTB_BA (np, send_sdtr) || 452959292Sgroudier dsp == SCRIPTB_BA (np, send_ppr)) { 453059292Sgroudier nxtdsp = SCRIPTB_BA (np, nego_bad_phase); 453153790Sobrien } 453253790Sobrien break; 453353790Sobrien#if 0 453453790Sobrien case 7: /* MSG IN phase */ 453559292Sgroudier nxtdsp = SCRIPTA_BA (np, clrack); 453653790Sobrien break; 453753790Sobrien#endif 453853790Sobrien } 453953790Sobrien 454053790Sobrien if (nxtdsp) { 454161429Sgroudier OUTL_DSP (nxtdsp); 454253790Sobrien return; 454353790Sobrien } 454453790Sobrien 454553790Sobrienreset_all: 454653790Sobrien sym_start_reset(np); 454753790Sobrien} 454853790Sobrien 454953790Sobrien/* 4550178466Smarius * Dequeue from the START queue all CCBs that match 455153790Sobrien * a given target/lun/task condition (-1 means all), 4552178466Smarius * and move them from the BUSY queue to the COMP queue 455353790Sobrien * with CAM_REQUEUE_REQ status condition. 455453790Sobrien * This function is used during error handling/recovery. 455553790Sobrien * It is called with SCRIPTS not running. 455653790Sobrien */ 455753790Sobrienstatic int 455853790Sobriensym_dequeue_from_squeue(hcb_p np, int i, int target, int lun, int task) 455953790Sobrien{ 456053790Sobrien int j; 456153790Sobrien ccb_p cp; 456253790Sobrien 456353790Sobrien /* 456453790Sobrien * Make sure the starting index is within range. 456553790Sobrien */ 456653790Sobrien assert((i >= 0) && (i < 2*MAX_QUEUE)); 456753790Sobrien 456853790Sobrien /* 4569178466Smarius * Walk until end of START queue and dequeue every job 457053790Sobrien * that matches the target/lun/task condition. 457153790Sobrien */ 457253790Sobrien j = i; 457353790Sobrien while (i != np->squeueput) { 457453790Sobrien cp = sym_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); 457553790Sobrien assert(cp); 457654690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 457753790Sobrien /* Forget hints for IARB, they may be no longer relevant */ 457853790Sobrien cp->host_flags &= ~HF_HINT_IARB; 457953790Sobrien#endif 458053790Sobrien if ((target == -1 || cp->target == target) && 458153790Sobrien (lun == -1 || cp->lun == lun) && 458253790Sobrien (task == -1 || cp->tag == task)) { 458353790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_REQUEUE_REQ); 458453790Sobrien sym_remque(&cp->link_ccbq); 458553790Sobrien sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); 458653790Sobrien } 458753790Sobrien else { 458853790Sobrien if (i != j) 458953790Sobrien np->squeue[j] = np->squeue[i]; 459053790Sobrien if ((j += 2) >= MAX_QUEUE*2) j = 0; 459153790Sobrien } 459253790Sobrien if ((i += 2) >= MAX_QUEUE*2) i = 0; 459353790Sobrien } 459453790Sobrien if (i != j) /* Copy back the idle task if needed */ 459553790Sobrien np->squeue[j] = np->squeue[i]; 459653790Sobrien np->squeueput = j; /* Update our current start queue pointer */ 459753790Sobrien 459853790Sobrien return (i - j) / 2; 459953790Sobrien} 460053790Sobrien 460153790Sobrien/* 460253790Sobrien * Complete all CCBs queued to the COMP queue. 460353790Sobrien * 460453790Sobrien * These CCBs are assumed: 4605178466Smarius * - Not to be referenced either by devices or 460653790Sobrien * SCRIPTS-related queues and datas. 4607178466Smarius * - To have to be completed with an error condition 460853790Sobrien * or requeued. 460953790Sobrien * 4610178466Smarius * The device queue freeze count is incremented 461153790Sobrien * for each CCB that does not prevent this. 4612178466Smarius * This function is called when all CCBs involved 461353790Sobrien * in error handling/recovery have been reaped. 461453790Sobrien */ 461553790Sobrienstatic void 461653790Sobriensym_flush_comp_queue(hcb_p np, int cam_status) 461753790Sobrien{ 461853790Sobrien SYM_QUEHEAD *qp; 461953790Sobrien ccb_p cp; 462053790Sobrien 4621179029Smarius while ((qp = sym_remque_head(&np->comp_ccbq)) != NULL) { 462253790Sobrien union ccb *ccb; 462353790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 462453790Sobrien sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); 462558927Sgroudier /* Leave quiet CCBs waiting for resources */ 462658927Sgroudier if (cp->host_status == HS_WAIT) 462758927Sgroudier continue; 462853790Sobrien ccb = cp->cam_ccb; 462953790Sobrien if (cam_status) 463053790Sobrien sym_set_cam_status(ccb, cam_status); 4631178468Smarius sym_freeze_cam_ccb(ccb); 4632178468Smarius sym_xpt_done(np, ccb, cp); 463353790Sobrien sym_free_ccb(np, cp); 463453790Sobrien } 463553790Sobrien} 463653790Sobrien 463753790Sobrien/* 463853790Sobrien * chip handler for bad SCSI status condition 463953790Sobrien * 4640178466Smarius * In case of bad SCSI status, we unqueue all the tasks 4641178466Smarius * currently queued to the controller but not yet started 464253790Sobrien * and then restart the SCRIPTS processor immediately. 464353790Sobrien * 464453790Sobrien * QUEUE FULL and BUSY conditions are handled the same way. 4645178466Smarius * Basically all the not yet started tasks are requeued in 464653790Sobrien * device queue and the queue is frozen until a completion. 464753790Sobrien * 4648178466Smarius * For CHECK CONDITION and COMMAND TERMINATED status, we use 4649178466Smarius * the CCB of the failed command to prepare a REQUEST SENSE 465053790Sobrien * SCSI command and queue it to the controller queue. 465153790Sobrien * 4652178466Smarius * SCRATCHA is assumed to have been loaded with STARTPOS 465353790Sobrien * before the SCRIPTS called the C code. 465453790Sobrien */ 4655251572Smariusstatic void sym_sir_bad_scsi_status(hcb_p np, ccb_p cp) 465653790Sobrien{ 465753790Sobrien tcb_p tp = &np->target[cp->target]; 465853790Sobrien u32 startp; 465953790Sobrien u_char s_status = cp->ssss_status; 466053790Sobrien u_char h_flags = cp->host_flags; 466153790Sobrien int msglen; 466253790Sobrien int nego; 466353790Sobrien int i; 466453790Sobrien 4665178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 4666178468Smarius 466753790Sobrien /* 466853790Sobrien * Compute the index of the next job to start from SCRIPTS. 466953790Sobrien */ 467058927Sgroudier i = (INL (nc_scratcha) - np->squeue_ba) / 4; 467153790Sobrien 467253790Sobrien /* 4673178466Smarius * The last CCB queued used for IARB hint may be 467453790Sobrien * no longer relevant. Forget it. 467553790Sobrien */ 467654690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 467753790Sobrien if (np->last_cp) 4678178466Smarius np->last_cp = NULL; 467953790Sobrien#endif 468053790Sobrien 468153790Sobrien /* 468253790Sobrien * Now deal with the SCSI status. 468353790Sobrien */ 468453790Sobrien switch(s_status) { 468553790Sobrien case S_BUSY: 468653790Sobrien case S_QUEUE_FULL: 468753790Sobrien if (sym_verbose >= 2) { 468853790Sobrien PRINT_ADDR(cp); 468953790Sobrien printf (s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n"); 469053790Sobrien } 469153790Sobrien default: /* S_INT, S_INT_COND_MET, S_CONFLICT */ 469253790Sobrien sym_complete_error (np, cp); 469353790Sobrien break; 469453790Sobrien case S_TERMINATED: 469553790Sobrien case S_CHECK_COND: 469653790Sobrien /* 469753790Sobrien * If we get an SCSI error when requesting sense, give up. 469853790Sobrien */ 469953790Sobrien if (h_flags & HF_SENSE) { 470053790Sobrien sym_complete_error (np, cp); 470153790Sobrien break; 470253790Sobrien } 470353790Sobrien 470453790Sobrien /* 470553790Sobrien * Dequeue all queued CCBs for that device not yet started, 470653790Sobrien * and restart the SCRIPTS processor immediately. 470753790Sobrien */ 470853790Sobrien (void) sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); 470961429Sgroudier OUTL_DSP (SCRIPTA_BA (np, start)); 471053790Sobrien 471153790Sobrien /* 471253790Sobrien * Save some info of the actual IO. 471353790Sobrien * Compute the data residual. 471453790Sobrien */ 471553790Sobrien cp->sv_scsi_status = cp->ssss_status; 471653790Sobrien cp->sv_xerr_status = cp->xerr_status; 471753790Sobrien cp->sv_resid = sym_compute_residual(np, cp); 471853790Sobrien 471953790Sobrien /* 4720178466Smarius * Prepare all needed data structures for 472153790Sobrien * requesting sense data. 472253790Sobrien */ 472353790Sobrien 472453790Sobrien /* 472553790Sobrien * identify message 472653790Sobrien */ 472753790Sobrien cp->scsi_smsg2[0] = M_IDENTIFY | cp->lun; 472853790Sobrien msglen = 1; 472953790Sobrien 473053790Sobrien /* 4731178466Smarius * If we are currently using anything different from 473253790Sobrien * async. 8 bit data transfers with that target, 4733178466Smarius * start a negotiation, since the device may want 4734178466Smarius * to report us a UNIT ATTENTION condition due to 4735178466Smarius * a cause we currently ignore, and we donnot want 473653790Sobrien * to be stuck with WIDE and/or SYNC data transfer. 473753790Sobrien * 473853790Sobrien * cp->nego_status is filled by sym_prepare_nego(). 473953790Sobrien */ 474053790Sobrien cp->nego_status = 0; 474153790Sobrien nego = 0; 474253790Sobrien if (tp->tinfo.current.options & PPR_OPT_MASK) 474353790Sobrien nego = NS_PPR; 474453790Sobrien else if (tp->tinfo.current.width != BUS_8_BIT) 474553790Sobrien nego = NS_WIDE; 474653790Sobrien else if (tp->tinfo.current.offset != 0) 474753790Sobrien nego = NS_SYNC; 474853790Sobrien if (nego) 474953790Sobrien msglen += 475053790Sobrien sym_prepare_nego (np,cp, nego, &cp->scsi_smsg2[msglen]); 475153790Sobrien /* 475253790Sobrien * Message table indirect structure. 475353790Sobrien */ 475458927Sgroudier cp->phys.smsg.addr = cpu_to_scr(CCB_BA (cp, scsi_smsg2)); 475553790Sobrien cp->phys.smsg.size = cpu_to_scr(msglen); 475653790Sobrien 475753790Sobrien /* 475853790Sobrien * sense command 475953790Sobrien */ 476058927Sgroudier cp->phys.cmd.addr = cpu_to_scr(CCB_BA (cp, sensecmd)); 476153790Sobrien cp->phys.cmd.size = cpu_to_scr(6); 476253790Sobrien 476353790Sobrien /* 476453790Sobrien * patch requested size into sense command 476553790Sobrien */ 476653790Sobrien cp->sensecmd[0] = 0x03; 476753790Sobrien cp->sensecmd[1] = cp->lun << 5; 476874755Sgroudier if (tp->tinfo.current.scsi_version > 2 || cp->lun > 7) 476974755Sgroudier cp->sensecmd[1] = 0; 477058927Sgroudier cp->sensecmd[4] = SYM_SNS_BBUF_LEN; 477158927Sgroudier cp->data_len = SYM_SNS_BBUF_LEN; 477253790Sobrien 477353790Sobrien /* 477453790Sobrien * sense data 477553790Sobrien */ 477658927Sgroudier bzero(cp->sns_bbuf, SYM_SNS_BBUF_LEN); 477758927Sgroudier cp->phys.sense.addr = cpu_to_scr(vtobus(cp->sns_bbuf)); 477858927Sgroudier cp->phys.sense.size = cpu_to_scr(SYM_SNS_BBUF_LEN); 477953790Sobrien 478053790Sobrien /* 478153790Sobrien * requeue the command. 478253790Sobrien */ 478359292Sgroudier startp = SCRIPTB_BA (np, sdata_in); 478453790Sobrien 478559743Sgroudier cp->phys.head.savep = cpu_to_scr(startp); 478659743Sgroudier cp->phys.head.goalp = cpu_to_scr(startp + 16); 478759743Sgroudier cp->phys.head.lastp = cpu_to_scr(startp); 478853790Sobrien cp->startp = cpu_to_scr(startp); 478953790Sobrien 479053790Sobrien cp->actualquirks = SYM_QUIRK_AUTOSAVE; 479153790Sobrien cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; 479253790Sobrien cp->ssss_status = S_ILLEGAL; 479358927Sgroudier cp->host_flags = (HF_SENSE|HF_DATA_IN); 479453790Sobrien cp->xerr_status = 0; 479559252Sgroudier cp->extra_bytes = 0; 479653790Sobrien 479759743Sgroudier cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, select)); 479853790Sobrien 479953790Sobrien /* 480053790Sobrien * Requeue the command. 480153790Sobrien */ 480253790Sobrien sym_put_start_queue(np, cp); 480353790Sobrien 480453790Sobrien /* 480553790Sobrien * Give back to upper layer everything we have dequeued. 480653790Sobrien */ 480753790Sobrien sym_flush_comp_queue(np, 0); 480853790Sobrien break; 480953790Sobrien } 481053790Sobrien} 481153790Sobrien 481253790Sobrien/* 4813178466Smarius * After a device has accepted some management message 4814178466Smarius * as BUS DEVICE RESET, ABORT TASK, etc ..., or when 4815178466Smarius * a device signals a UNIT ATTENTION condition, some 4816178466Smarius * tasks are thrown away by the device. We are required 4817178466Smarius * to reflect that on our tasks list since the device 481853790Sobrien * will never complete these tasks. 481953790Sobrien * 4820178466Smarius * This function move from the BUSY queue to the COMP 4821178466Smarius * queue all disconnected CCBs for a given target that 482253790Sobrien * match the following criteria: 482353790Sobrien * - lun=-1 means any logical UNIT otherwise a given one. 482453790Sobrien * - task=-1 means any task, otherwise a given one. 482553790Sobrien */ 4826178466Smariusstatic int 482753790Sobriensym_clear_tasks(hcb_p np, int cam_status, int target, int lun, int task) 482853790Sobrien{ 482953790Sobrien SYM_QUEHEAD qtmp, *qp; 483053790Sobrien int i = 0; 483153790Sobrien ccb_p cp; 483253790Sobrien 483353790Sobrien /* 483453790Sobrien * Move the entire BUSY queue to our temporary queue. 483553790Sobrien */ 483653790Sobrien sym_que_init(&qtmp); 483753790Sobrien sym_que_splice(&np->busy_ccbq, &qtmp); 483853790Sobrien sym_que_init(&np->busy_ccbq); 483953790Sobrien 484053790Sobrien /* 4841178466Smarius * Put all CCBs that matches our criteria into 4842178466Smarius * the COMP queue and put back other ones into 484353790Sobrien * the BUSY queue. 484453790Sobrien */ 4845179029Smarius while ((qp = sym_remque_head(&qtmp)) != NULL) { 484653790Sobrien union ccb *ccb; 484753790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 484853790Sobrien ccb = cp->cam_ccb; 484953790Sobrien if (cp->host_status != HS_DISCONNECT || 485053790Sobrien cp->target != target || 485153790Sobrien (lun != -1 && cp->lun != lun) || 4852178466Smarius (task != -1 && 485353790Sobrien (cp->tag != NO_TAG && cp->scsi_smsg[2] != task))) { 485453790Sobrien sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); 485553790Sobrien continue; 485653790Sobrien } 485753790Sobrien sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); 485853790Sobrien 485953790Sobrien /* Preserve the software timeout condition */ 486053790Sobrien if (sym_get_cam_status(ccb) != CAM_CMD_TIMEOUT) 486153790Sobrien sym_set_cam_status(ccb, cam_status); 486253790Sobrien ++i; 486353790Sobrien#if 0 486457186Sgroudierprintf("XXXX TASK @%p CLEARED\n", cp); 486553790Sobrien#endif 486653790Sobrien } 486753790Sobrien return i; 486853790Sobrien} 486953790Sobrien 487053790Sobrien/* 487153790Sobrien * chip handler for TASKS recovery 487253790Sobrien * 4873178466Smarius * We cannot safely abort a command, while the SCRIPTS 4874178466Smarius * processor is running, since we just would be in race 487553790Sobrien * with it. 487653790Sobrien * 4877178466Smarius * As long as we have tasks to abort, we keep the SEM 4878178466Smarius * bit set in the ISTAT. When this bit is set, the 4879178466Smarius * SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) 488053790Sobrien * each time it enters the scheduler. 488153790Sobrien * 488253790Sobrien * If we have to reset a target, clear tasks of a unit, 4883178466Smarius * or to perform the abort of a disconnected job, we 4884178466Smarius * restart the SCRIPTS for selecting the target. Once 488553790Sobrien * selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED). 4886178466Smarius * If it loses arbitration, the SCRIPTS will interrupt again 488753790Sobrien * the next time it will enter its scheduler, and so on ... 488853790Sobrien * 4889178466Smarius * On SIR_TARGET_SELECTED, we scan for the more 489053790Sobrien * appropriate thing to do: 489153790Sobrien * 4892178466Smarius * - If nothing, we just sent a M_ABORT message to the 489353790Sobrien * target to get rid of the useless SCSI bus ownership. 489453790Sobrien * According to the specs, no tasks shall be affected. 4895178466Smarius * - If the target is to be reset, we send it a M_RESET 489653790Sobrien * message. 4897178466Smarius * - If a logical UNIT is to be cleared , we send the 489853790Sobrien * IDENTIFY(lun) + M_ABORT. 4899178466Smarius * - If an untagged task is to be aborted, we send the 490053790Sobrien * IDENTIFY(lun) + M_ABORT. 4901178466Smarius * - If a tagged task is to be aborted, we send the 490253790Sobrien * IDENTIFY(lun) + task attributes + M_ABORT_TAG. 490353790Sobrien * 4904178466Smarius * Once our 'kiss of death' :) message has been accepted 4905178466Smarius * by the target, the SCRIPTS interrupts again 4906178466Smarius * (SIR_ABORT_SENT). On this interrupt, we complete 4907178466Smarius * all the CCBs that should have been aborted by the 490853790Sobrien * target according to our message. 490953790Sobrien */ 491053790Sobrienstatic void sym_sir_task_recovery(hcb_p np, int num) 491153790Sobrien{ 491253790Sobrien SYM_QUEHEAD *qp; 491353790Sobrien ccb_p cp; 491453790Sobrien tcb_p tp; 491553790Sobrien int target=-1, lun=-1, task; 491653790Sobrien int i, k; 491753790Sobrien 491853790Sobrien switch(num) { 491953790Sobrien /* 492053790Sobrien * The SCRIPTS processor stopped before starting 4921178466Smarius * the next command in order to allow us to perform 492253790Sobrien * some task recovery. 492353790Sobrien */ 492453790Sobrien case SIR_SCRIPT_STOPPED: 492553790Sobrien /* 492653790Sobrien * Do we have any target to reset or unit to clear ? 492753790Sobrien */ 492854690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 492953790Sobrien tp = &np->target[i]; 4930178466Smarius if (tp->to_reset || 493153790Sobrien (tp->lun0p && tp->lun0p->to_clear)) { 493253790Sobrien target = i; 493353790Sobrien break; 493453790Sobrien } 493553790Sobrien if (!tp->lunmp) 493653790Sobrien continue; 493754690Sobrien for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) { 493853790Sobrien if (tp->lunmp[k] && tp->lunmp[k]->to_clear) { 493953790Sobrien target = i; 494053790Sobrien break; 494153790Sobrien } 494253790Sobrien } 494353790Sobrien if (target != -1) 494453790Sobrien break; 494553790Sobrien } 494653790Sobrien 494753790Sobrien /* 4948178466Smarius * If not, walk the busy queue for any 494953790Sobrien * disconnected CCB to be aborted. 495053790Sobrien */ 495153790Sobrien if (target == -1) { 495253790Sobrien FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 495353790Sobrien cp = sym_que_entry(qp,struct sym_ccb,link_ccbq); 495453790Sobrien if (cp->host_status != HS_DISCONNECT) 495553790Sobrien continue; 495653790Sobrien if (cp->to_abort) { 495753790Sobrien target = cp->target; 495853790Sobrien break; 495953790Sobrien } 496053790Sobrien } 496153790Sobrien } 496253790Sobrien 496353790Sobrien /* 4964178466Smarius * If some target is to be selected, 496553790Sobrien * prepare and start the selection. 496653790Sobrien */ 496753790Sobrien if (target != -1) { 496853790Sobrien tp = &np->target[target]; 496953790Sobrien np->abrt_sel.sel_id = target; 497059743Sgroudier np->abrt_sel.sel_scntl3 = tp->head.wval; 497159743Sgroudier np->abrt_sel.sel_sxfer = tp->head.sval; 497258927Sgroudier OUTL(nc_dsa, np->hcb_ba); 497361429Sgroudier OUTL_DSP (SCRIPTB_BA (np, sel_for_abort)); 497453790Sobrien return; 497553790Sobrien } 497653790Sobrien 497753790Sobrien /* 497853790Sobrien * Now look for a CCB to abort that haven't started yet. 4979178466Smarius * Btw, the SCRIPTS processor is still stopped, so 498053790Sobrien * we are not in race. 498153790Sobrien */ 498253790Sobrien i = 0; 4983178466Smarius cp = NULL; 498453790Sobrien FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 498553790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 498653790Sobrien if (cp->host_status != HS_BUSY && 498753790Sobrien cp->host_status != HS_NEGOTIATE) 498853790Sobrien continue; 498953790Sobrien if (!cp->to_abort) 499053790Sobrien continue; 499154690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 499253790Sobrien /* 4993178466Smarius * If we are using IMMEDIATE ARBITRATION, we donnot 4994178466Smarius * want to cancel the last queued CCB, since the 499553790Sobrien * SCRIPTS may have anticipated the selection. 499653790Sobrien */ 499753790Sobrien if (cp == np->last_cp) { 499853790Sobrien cp->to_abort = 0; 499953790Sobrien continue; 500053790Sobrien } 500153790Sobrien#endif 500253790Sobrien i = 1; /* Means we have found some */ 500353790Sobrien break; 500453790Sobrien } 500553790Sobrien if (!i) { 500653790Sobrien /* 5007178466Smarius * We are done, so we donnot need 500853790Sobrien * to synchronize with the SCRIPTS anylonger. 500953790Sobrien * Remove the SEM flag from the ISTAT. 501053790Sobrien */ 501153790Sobrien np->istat_sem = 0; 501253790Sobrien OUTB (nc_istat, SIGP); 501353790Sobrien break; 501453790Sobrien } 501553790Sobrien /* 5016178466Smarius * Compute index of next position in the start 5017178466Smarius * queue the SCRIPTS intends to start and dequeue 501853790Sobrien * all CCBs for that device that haven't been started. 501953790Sobrien */ 502058927Sgroudier i = (INL (nc_scratcha) - np->squeue_ba) / 4; 502153790Sobrien i = sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); 502253790Sobrien 502353790Sobrien /* 502453790Sobrien * Make sure at least our IO to abort has been dequeued. 502553790Sobrien */ 502653790Sobrien assert(i && sym_get_cam_status(cp->cam_ccb) == CAM_REQUEUE_REQ); 502753790Sobrien 502853790Sobrien /* 502953790Sobrien * Keep track in cam status of the reason of the abort. 503053790Sobrien */ 503153790Sobrien if (cp->to_abort == 2) 503253790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_CMD_TIMEOUT); 503353790Sobrien else 503453790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_REQ_ABORTED); 503553790Sobrien 503653790Sobrien /* 503753790Sobrien * Complete with error everything that we have dequeued. 503853790Sobrien */ 503953790Sobrien sym_flush_comp_queue(np, 0); 504053790Sobrien break; 504153790Sobrien /* 5042178466Smarius * The SCRIPTS processor has selected a target 504353790Sobrien * we may have some manual recovery to perform for. 504453790Sobrien */ 504553790Sobrien case SIR_TARGET_SELECTED: 504653790Sobrien target = (INB (nc_sdid) & 0xf); 504753790Sobrien tp = &np->target[target]; 504853790Sobrien 504972361Sgroudier np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg)); 505053790Sobrien 505153790Sobrien /* 5052178466Smarius * If the target is to be reset, prepare a 5053178466Smarius * M_RESET message and clear the to_reset flag 505453790Sobrien * since we donnot expect this operation to fail. 505553790Sobrien */ 505653790Sobrien if (tp->to_reset) { 505753790Sobrien np->abrt_msg[0] = M_RESET; 505853790Sobrien np->abrt_tbl.size = 1; 505953790Sobrien tp->to_reset = 0; 506053790Sobrien break; 506153790Sobrien } 506253790Sobrien 506353790Sobrien /* 506453790Sobrien * Otherwise, look for some logical unit to be cleared. 506553790Sobrien */ 506653790Sobrien if (tp->lun0p && tp->lun0p->to_clear) 506753790Sobrien lun = 0; 506853790Sobrien else if (tp->lunmp) { 506954690Sobrien for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) { 507053790Sobrien if (tp->lunmp[k] && tp->lunmp[k]->to_clear) { 507153790Sobrien lun = k; 507253790Sobrien break; 507353790Sobrien } 507453790Sobrien } 507553790Sobrien } 507653790Sobrien 507753790Sobrien /* 5078178466Smarius * If a logical unit is to be cleared, prepare 507953790Sobrien * an IDENTIFY(lun) + ABORT MESSAGE. 508053790Sobrien */ 508153790Sobrien if (lun != -1) { 5082251572Smarius lcb_p lp = sym_lp(tp, lun); 508353790Sobrien lp->to_clear = 0; /* We donnot expect to fail here */ 508453790Sobrien np->abrt_msg[0] = M_IDENTIFY | lun; 508553790Sobrien np->abrt_msg[1] = M_ABORT; 508653790Sobrien np->abrt_tbl.size = 2; 508753790Sobrien break; 508853790Sobrien } 508953790Sobrien 509053790Sobrien /* 5091178466Smarius * Otherwise, look for some disconnected job to 509253790Sobrien * abort for this target. 509353790Sobrien */ 509453790Sobrien i = 0; 5095178466Smarius cp = NULL; 509653790Sobrien FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 509753790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 509853790Sobrien if (cp->host_status != HS_DISCONNECT) 509953790Sobrien continue; 510053790Sobrien if (cp->target != target) 510153790Sobrien continue; 510253790Sobrien if (!cp->to_abort) 510353790Sobrien continue; 510453790Sobrien i = 1; /* Means we have some */ 510553790Sobrien break; 510653790Sobrien } 510753790Sobrien 510853790Sobrien /* 5109178466Smarius * If we have none, probably since the device has 511053790Sobrien * completed the command before we won abitration, 511153790Sobrien * send a M_ABORT message without IDENTIFY. 5112178466Smarius * According to the specs, the device must just 511353790Sobrien * disconnect the BUS and not abort any task. 511453790Sobrien */ 511553790Sobrien if (!i) { 511653790Sobrien np->abrt_msg[0] = M_ABORT; 511753790Sobrien np->abrt_tbl.size = 1; 511853790Sobrien break; 511953790Sobrien } 512053790Sobrien 512153790Sobrien /* 512253790Sobrien * We have some task to abort. 512353790Sobrien * Set the IDENTIFY(lun) 512453790Sobrien */ 512553790Sobrien np->abrt_msg[0] = M_IDENTIFY | cp->lun; 512653790Sobrien 512753790Sobrien /* 5128178466Smarius * If we want to abort an untagged command, we 5129108533Sschweikh * will send an IDENTIFY + M_ABORT. 5130178466Smarius * Otherwise (tagged command), we will send 5131108533Sschweikh * an IDENTIFY + task attributes + ABORT TAG. 513253790Sobrien */ 513353790Sobrien if (cp->tag == NO_TAG) { 513453790Sobrien np->abrt_msg[1] = M_ABORT; 513553790Sobrien np->abrt_tbl.size = 2; 513653790Sobrien } 513753790Sobrien else { 513853790Sobrien np->abrt_msg[1] = cp->scsi_smsg[1]; 513953790Sobrien np->abrt_msg[2] = cp->scsi_smsg[2]; 514053790Sobrien np->abrt_msg[3] = M_ABORT_TAG; 514153790Sobrien np->abrt_tbl.size = 4; 514253790Sobrien } 514353790Sobrien /* 5144178466Smarius * Keep track of software timeout condition, since the 5145178466Smarius * peripheral driver may not count retries on abort 514653790Sobrien * conditions not due to timeout. 514753790Sobrien */ 514853790Sobrien if (cp->to_abort == 2) 514953790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_CMD_TIMEOUT); 515053790Sobrien cp->to_abort = 0; /* We donnot expect to fail here */ 515153790Sobrien break; 515253790Sobrien 515353790Sobrien /* 5154178466Smarius * The target has accepted our message and switched 515553790Sobrien * to BUS FREE phase as we expected. 515653790Sobrien */ 515753790Sobrien case SIR_ABORT_SENT: 515853790Sobrien target = (INB (nc_sdid) & 0xf); 515953790Sobrien tp = &np->target[target]; 5160178466Smarius 516153790Sobrien /* 516253790Sobrien ** If we didn't abort anything, leave here. 516353790Sobrien */ 516453790Sobrien if (np->abrt_msg[0] == M_ABORT) 516553790Sobrien break; 516653790Sobrien 516753790Sobrien /* 5168178466Smarius * If we sent a M_RESET, then a hardware reset has 516953790Sobrien * been performed by the target. 517053790Sobrien * - Reset everything to async 8 bit 517153790Sobrien * - Tell ourself to negotiate next time :-) 5172178466Smarius * - Prepare to clear all disconnected CCBs for 517353790Sobrien * this target from our task list (lun=task=-1) 517453790Sobrien */ 517553790Sobrien lun = -1; 517653790Sobrien task = -1; 517753790Sobrien if (np->abrt_msg[0] == M_RESET) { 517859743Sgroudier tp->head.sval = 0; 517959743Sgroudier tp->head.wval = np->rv_scntl3; 518059743Sgroudier tp->head.uval = 0; 518153790Sobrien tp->tinfo.current.period = 0; 518253790Sobrien tp->tinfo.current.offset = 0; 518353790Sobrien tp->tinfo.current.width = BUS_8_BIT; 518453790Sobrien tp->tinfo.current.options = 0; 518553790Sobrien } 518653790Sobrien 518753790Sobrien /* 5188178466Smarius * Otherwise, check for the LUN and TASK(s) 518953790Sobrien * concerned by the cancelation. 5190178466Smarius * If it is not ABORT_TAG then it is CLEAR_QUEUE 519153790Sobrien * or an ABORT message :-) 519253790Sobrien */ 519353790Sobrien else { 519453790Sobrien lun = np->abrt_msg[0] & 0x3f; 519553790Sobrien if (np->abrt_msg[1] == M_ABORT_TAG) 519653790Sobrien task = np->abrt_msg[2]; 519753790Sobrien } 519853790Sobrien 519953790Sobrien /* 5200178466Smarius * Complete all the CCBs the device should have 520153790Sobrien * aborted due to our 'kiss of death' message. 520253790Sobrien */ 520358927Sgroudier i = (INL (nc_scratcha) - np->squeue_ba) / 4; 520453790Sobrien (void) sym_dequeue_from_squeue(np, i, target, lun, -1); 520553790Sobrien (void) sym_clear_tasks(np, CAM_REQ_ABORTED, target, lun, task); 520653790Sobrien sym_flush_comp_queue(np, 0); 520753790Sobrien 520853790Sobrien /* 520953790Sobrien * If we sent a BDR, make uper layer aware of that. 521053790Sobrien */ 521153790Sobrien if (np->abrt_msg[0] == M_RESET) 521253790Sobrien xpt_async(AC_SENT_BDR, np->path, NULL); 521353790Sobrien break; 521453790Sobrien } 521553790Sobrien 521653790Sobrien /* 521753790Sobrien * Print to the log the message we intend to send. 521853790Sobrien */ 521953790Sobrien if (num == SIR_TARGET_SELECTED) { 522053790Sobrien PRINT_TARGET(np, target); 522153790Sobrien sym_printl_hex("control msgout:", np->abrt_msg, 522253790Sobrien np->abrt_tbl.size); 522353790Sobrien np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size); 522453790Sobrien } 522553790Sobrien 522653790Sobrien /* 522753790Sobrien * Let the SCRIPTS processor continue. 522853790Sobrien */ 522961429Sgroudier OUTONB_STD (); 523053790Sobrien} 523153790Sobrien 523253790Sobrien/* 5233178466Smarius * Gerard's alchemy:) that deals with with the data 523453790Sobrien * pointer for both MDP and the residual calculation. 523553790Sobrien * 5236178466Smarius * I didn't want to bloat the code by more than 200 523753790Sobrien * lignes for the handling of both MDP and the residual. 5238178466Smarius * This has been achieved by using a data pointer 5239178466Smarius * representation consisting in an index in the data 5240178466Smarius * array (dp_sg) and a negative offset (dp_ofs) that 524153790Sobrien * have the following meaning: 524253790Sobrien * 524354690Sobrien * - dp_sg = SYM_CONF_MAX_SG 524453790Sobrien * we are at the end of the data script. 524554690Sobrien * - dp_sg < SYM_CONF_MAX_SG 5246178466Smarius * dp_sg points to the next entry of the scatter array 524753790Sobrien * we want to transfer. 524853790Sobrien * - dp_ofs < 0 5249178466Smarius * dp_ofs represents the residual of bytes of the 525053790Sobrien * previous entry scatter entry we will send first. 525153790Sobrien * - dp_ofs = 0 525253790Sobrien * no residual to send first. 525353790Sobrien * 5254178466Smarius * The function sym_evaluate_dp() accepts an arbitray 5255178466Smarius * offset (basically from the MDP message) and returns 525653790Sobrien * the corresponding values of dp_sg and dp_ofs. 525753790Sobrien */ 525853790Sobrienstatic int sym_evaluate_dp(hcb_p np, ccb_p cp, u32 scr, int *ofs) 525953790Sobrien{ 526053790Sobrien u32 dp_scr; 526153790Sobrien int dp_ofs, dp_sg, dp_sgmin; 526253790Sobrien int tmp; 526353790Sobrien struct sym_pmc *pm; 526453790Sobrien 526553790Sobrien /* 5266178466Smarius * Compute the resulted data pointer in term of a script 526753790Sobrien * address within some DATA script and a signed byte offset. 526853790Sobrien */ 526953790Sobrien dp_scr = scr; 527053790Sobrien dp_ofs = *ofs; 527159292Sgroudier if (dp_scr == SCRIPTA_BA (np, pm0_data)) 527253790Sobrien pm = &cp->phys.pm0; 527359292Sgroudier else if (dp_scr == SCRIPTA_BA (np, pm1_data)) 527453790Sobrien pm = &cp->phys.pm1; 527553790Sobrien else 5276178466Smarius pm = NULL; 527753790Sobrien 527853790Sobrien if (pm) { 527953790Sobrien dp_scr = scr_to_cpu(pm->ret); 528053790Sobrien dp_ofs -= scr_to_cpu(pm->sg.size); 528153790Sobrien } 528253790Sobrien 528353790Sobrien /* 528453790Sobrien * If we are auto-sensing, then we are done. 528553790Sobrien */ 528653790Sobrien if (cp->host_flags & HF_SENSE) { 528753790Sobrien *ofs = dp_ofs; 528853790Sobrien return 0; 528953790Sobrien } 529053790Sobrien 529153790Sobrien /* 529253790Sobrien * Deduce the index of the sg entry. 529353790Sobrien * Keep track of the index of the first valid entry. 5294178466Smarius * If result is dp_sg = SYM_CONF_MAX_SG, then we are at the 529553790Sobrien * end of the data. 529653790Sobrien */ 529759743Sgroudier tmp = scr_to_cpu(cp->phys.head.goalp); 529854690Sobrien dp_sg = SYM_CONF_MAX_SG; 529956762Sgroudier if (dp_scr != tmp) 530053796Sobrien dp_sg -= (tmp - 8 - (int)dp_scr) / (2*4); 530154690Sobrien dp_sgmin = SYM_CONF_MAX_SG - cp->segments; 530253790Sobrien 530353790Sobrien /* 530453790Sobrien * Move to the sg entry the data pointer belongs to. 530553790Sobrien * 530653790Sobrien * If we are inside the data area, we expect result to be: 530753790Sobrien * 530853790Sobrien * Either, 530953790Sobrien * dp_ofs = 0 and dp_sg is the index of the sg entry 531053790Sobrien * the data pointer belongs to (or the end of the data) 531153790Sobrien * Or, 5312178466Smarius * dp_ofs < 0 and dp_sg is the index of the sg entry 531353790Sobrien * the data pointer belongs to + 1. 531453790Sobrien */ 531553790Sobrien if (dp_ofs < 0) { 531653790Sobrien int n; 531753790Sobrien while (dp_sg > dp_sgmin) { 531853790Sobrien --dp_sg; 531953790Sobrien tmp = scr_to_cpu(cp->phys.data[dp_sg].size); 532053790Sobrien n = dp_ofs + (tmp & 0xffffff); 532153790Sobrien if (n > 0) { 532253790Sobrien ++dp_sg; 532353790Sobrien break; 532453790Sobrien } 532553790Sobrien dp_ofs = n; 532653790Sobrien } 532753790Sobrien } 532853790Sobrien else if (dp_ofs > 0) { 532954690Sobrien while (dp_sg < SYM_CONF_MAX_SG) { 533053790Sobrien tmp = scr_to_cpu(cp->phys.data[dp_sg].size); 533153790Sobrien dp_ofs -= (tmp & 0xffffff); 533254690Sobrien ++dp_sg; 533353790Sobrien if (dp_ofs <= 0) 533453790Sobrien break; 533553790Sobrien } 533653790Sobrien } 533753790Sobrien 533853790Sobrien /* 533953790Sobrien * Make sure the data pointer is inside the data area. 534053790Sobrien * If not, return some error. 534153790Sobrien */ 534253790Sobrien if (dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0)) 534353790Sobrien goto out_err; 534454690Sobrien else if (dp_sg > SYM_CONF_MAX_SG || 534554690Sobrien (dp_sg == SYM_CONF_MAX_SG && dp_ofs > 0)) 534653790Sobrien goto out_err; 534753790Sobrien 534853790Sobrien /* 534953790Sobrien * Save the extreme pointer if needed. 535053790Sobrien */ 535153790Sobrien if (dp_sg > cp->ext_sg || 535253790Sobrien (dp_sg == cp->ext_sg && dp_ofs > cp->ext_ofs)) { 535353790Sobrien cp->ext_sg = dp_sg; 535453790Sobrien cp->ext_ofs = dp_ofs; 535553790Sobrien } 535653790Sobrien 535753790Sobrien /* 535853790Sobrien * Return data. 535953790Sobrien */ 536053790Sobrien *ofs = dp_ofs; 536153790Sobrien return dp_sg; 536253790Sobrien 536353790Sobrienout_err: 536453790Sobrien return -1; 536553790Sobrien} 536653790Sobrien 536753790Sobrien/* 536853790Sobrien * chip handler for MODIFY DATA POINTER MESSAGE 536953790Sobrien * 5370178466Smarius * We also call this function on IGNORE WIDE RESIDUE 537153790Sobrien * messages that do not match a SWIDE full condition. 5372178466Smarius * Btw, we assume in that situation that such a message 537353790Sobrien * is equivalent to a MODIFY DATA POINTER (offset=-1). 537453790Sobrien */ 5375251572Smariusstatic void sym_modify_dp(hcb_p np, ccb_p cp, int ofs) 537653790Sobrien{ 537753790Sobrien int dp_ofs = ofs; 537853790Sobrien u32 dp_scr = INL (nc_temp); 537953790Sobrien u32 dp_ret; 538053796Sobrien u32 tmp; 538153790Sobrien u_char hflags; 538253790Sobrien int dp_sg; 538353790Sobrien struct sym_pmc *pm; 538453790Sobrien 538553790Sobrien /* 538653790Sobrien * Not supported for auto-sense. 538753790Sobrien */ 538853790Sobrien if (cp->host_flags & HF_SENSE) 538953790Sobrien goto out_reject; 539053790Sobrien 539153790Sobrien /* 5392178466Smarius * Apply our alchemy:) (see comments in sym_evaluate_dp()), 539353790Sobrien * to the resulted data pointer. 539453790Sobrien */ 539553790Sobrien dp_sg = sym_evaluate_dp(np, cp, dp_scr, &dp_ofs); 539653790Sobrien if (dp_sg < 0) 539753790Sobrien goto out_reject; 539853790Sobrien 539953790Sobrien /* 5400178466Smarius * And our alchemy:) allows to easily calculate the data 540153790Sobrien * script address we want to return for the next data phase. 540253790Sobrien */ 540359743Sgroudier dp_ret = cpu_to_scr(cp->phys.head.goalp); 540454690Sobrien dp_ret = dp_ret - 8 - (SYM_CONF_MAX_SG - dp_sg) * (2*4); 540553790Sobrien 540653790Sobrien /* 5407178466Smarius * If offset / scatter entry is zero we donnot need 540853790Sobrien * a context for the new current data pointer. 540953790Sobrien */ 541053790Sobrien if (dp_ofs == 0) { 541153790Sobrien dp_scr = dp_ret; 541253790Sobrien goto out_ok; 541353790Sobrien } 541453790Sobrien 541553790Sobrien /* 541653790Sobrien * Get a context for the new current data pointer. 541753790Sobrien */ 541853790Sobrien hflags = INB (HF_PRT); 541953790Sobrien 542053790Sobrien if (hflags & HF_DP_SAVED) 542153790Sobrien hflags ^= HF_ACT_PM; 542253790Sobrien 542353790Sobrien if (!(hflags & HF_ACT_PM)) { 542453790Sobrien pm = &cp->phys.pm0; 542559292Sgroudier dp_scr = SCRIPTA_BA (np, pm0_data); 542653790Sobrien } 542753790Sobrien else { 542853790Sobrien pm = &cp->phys.pm1; 542959292Sgroudier dp_scr = SCRIPTA_BA (np, pm1_data); 543053790Sobrien } 543153790Sobrien 543253790Sobrien hflags &= ~(HF_DP_SAVED); 543353790Sobrien 543453790Sobrien OUTB (HF_PRT, hflags); 543553790Sobrien 543653790Sobrien /* 543753790Sobrien * Set up the new current data pointer. 5438178466Smarius * ofs < 0 there, and for the next data phase, we 5439178466Smarius * want to transfer part of the data of the sg entry 5440178466Smarius * corresponding to index dp_sg-1 prior to returning 544153790Sobrien * to the main data script. 544253790Sobrien */ 544353790Sobrien pm->ret = cpu_to_scr(dp_ret); 544453796Sobrien tmp = scr_to_cpu(cp->phys.data[dp_sg-1].addr); 544553796Sobrien tmp += scr_to_cpu(cp->phys.data[dp_sg-1].size) + dp_ofs; 544653796Sobrien pm->sg.addr = cpu_to_scr(tmp); 544753796Sobrien pm->sg.size = cpu_to_scr(-dp_ofs); 544853790Sobrien 544953790Sobrienout_ok: 545053790Sobrien OUTL (nc_temp, dp_scr); 545161429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 545253790Sobrien return; 545353790Sobrien 545453790Sobrienout_reject: 545561429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 545653790Sobrien} 545753790Sobrien 545853790Sobrien/* 545953790Sobrien * chip calculation of the data residual. 546053790Sobrien * 5461178466Smarius * As I used to say, the requirement of data residual 5462178466Smarius * in SCSI is broken, useless and cannot be achieved 546353790Sobrien * without huge complexity. 546453790Sobrien * But most OSes and even the official CAM require it. 5465178466Smarius * When stupidity happens to be so widely spread inside 546653790Sobrien * a community, it gets hard to convince. 546753790Sobrien * 5468178466Smarius * Anyway, I don't care, since I am not going to use 5469178466Smarius * any software that considers this data residual as 547053790Sobrien * a relevant information. :) 547153790Sobrien */ 547253790Sobrienstatic int sym_compute_residual(hcb_p np, ccb_p cp) 547353790Sobrien{ 547457186Sgroudier int dp_sg, dp_sgmin, resid = 0; 547553790Sobrien int dp_ofs = 0; 547653790Sobrien 547753790Sobrien /* 547853790Sobrien * Check for some data lost or just thrown away. 5479178466Smarius * We are not required to be quite accurate in this 5480178466Smarius * situation. Btw, if we are odd for output and the 5481178466Smarius * device claims some more data, it may well happen 548253790Sobrien * than our residual be zero. :-) 548353790Sobrien */ 548453790Sobrien if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) { 548553790Sobrien if (cp->xerr_status & XE_EXTRA_DATA) 548659252Sgroudier resid -= cp->extra_bytes; 548753790Sobrien if (cp->xerr_status & XE_SODL_UNRUN) 548853790Sobrien ++resid; 548953790Sobrien if (cp->xerr_status & XE_SWIDE_OVRUN) 549053790Sobrien --resid; 549153790Sobrien } 549253790Sobrien 549353790Sobrien /* 549453790Sobrien * If all data has been transferred, 549553790Sobrien * there is no residual. 549653790Sobrien */ 549759743Sgroudier if (cp->phys.head.lastp == cp->phys.head.goalp) 549857186Sgroudier return resid; 549953790Sobrien 550053790Sobrien /* 550153790Sobrien * If no data transfer occurs, or if the data 550253790Sobrien * pointer is weird, return full residual. 550353790Sobrien */ 550459743Sgroudier if (cp->startp == cp->phys.head.lastp || 550559743Sgroudier sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp), 550659743Sgroudier &dp_ofs) < 0) { 550753790Sobrien return cp->data_len; 550853790Sobrien } 550953790Sobrien 551053790Sobrien /* 551153790Sobrien * If we were auto-sensing, then we are done. 551253790Sobrien */ 551353790Sobrien if (cp->host_flags & HF_SENSE) { 551453790Sobrien return -dp_ofs; 551553790Sobrien } 551653790Sobrien 551753790Sobrien /* 5518178466Smarius * We are now full comfortable in the computation 551953790Sobrien * of the data residual (2's complement). 552053790Sobrien */ 552154690Sobrien dp_sgmin = SYM_CONF_MAX_SG - cp->segments; 552253790Sobrien resid = -cp->ext_ofs; 552354690Sobrien for (dp_sg = cp->ext_sg; dp_sg < SYM_CONF_MAX_SG; ++dp_sg) { 552461051Sgroudier u_int tmp = scr_to_cpu(cp->phys.data[dp_sg].size); 552553790Sobrien resid += (tmp & 0xffffff); 552653790Sobrien } 552753790Sobrien 552853790Sobrien /* 552953790Sobrien * Hopefully, the result is not too wrong. 553053790Sobrien */ 553153790Sobrien return resid; 553253790Sobrien} 553353790Sobrien 553453790Sobrien/* 553559743Sgroudier * Print out the content of a SCSI message. 553653790Sobrien */ 553753790Sobrienstatic int sym_show_msg (u_char * msg) 553853790Sobrien{ 553953790Sobrien u_char i; 554053790Sobrien printf ("%x",*msg); 554153790Sobrien if (*msg==M_EXTENDED) { 554253790Sobrien for (i=1;i<8;i++) { 554353790Sobrien if (i-1>msg[1]) break; 554453790Sobrien printf ("-%x",msg[i]); 554553790Sobrien }; 554653790Sobrien return (i+1); 554753790Sobrien } else if ((*msg & 0xf0) == 0x20) { 554853790Sobrien printf ("-%x",msg[1]); 554953790Sobrien return (2); 555053790Sobrien }; 555153790Sobrien return (1); 555253790Sobrien} 555353790Sobrien 555453790Sobrienstatic void sym_print_msg (ccb_p cp, char *label, u_char *msg) 555553790Sobrien{ 555653790Sobrien PRINT_ADDR(cp); 555753790Sobrien if (label) 555853790Sobrien printf ("%s: ", label); 555953790Sobrien 556053790Sobrien (void) sym_show_msg (msg); 556153790Sobrien printf (".\n"); 556253790Sobrien} 556353790Sobrien 556453790Sobrien/* 556553790Sobrien * Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER. 556653790Sobrien * 556753790Sobrien * When we try to negotiate, we append the negotiation message 556853790Sobrien * to the identify and (maybe) simple tag message. 556953790Sobrien * The host status field is set to HS_NEGOTIATE to mark this 557053790Sobrien * situation. 557153790Sobrien * 557253790Sobrien * If the target doesn't answer this message immediately 557353790Sobrien * (as required by the standard), the SIR_NEGO_FAILED interrupt 557453790Sobrien * will be raised eventually. 557553790Sobrien * The handler removes the HS_NEGOTIATE status, and sets the 557653790Sobrien * negotiated value to the default (async / nowide). 557753790Sobrien * 557853790Sobrien * If we receive a matching answer immediately, we check it 557953790Sobrien * for validity, and set the values. 558053790Sobrien * 558153790Sobrien * If we receive a Reject message immediately, we assume the 558253790Sobrien * negotiation has failed, and fall back to standard values. 558353790Sobrien * 558453790Sobrien * If we receive a negotiation message while not in HS_NEGOTIATE 558553790Sobrien * state, it's a target initiated negotiation. We prepare a 5586178466Smarius * (hopefully) valid answer, set our parameters, and send back 558753790Sobrien * this answer to the target. 558853790Sobrien * 558953790Sobrien * If the target doesn't fetch the answer (no message out phase), 559053790Sobrien * we assume the negotiation has failed, and fall back to default 559153790Sobrien * settings (SIR_NEGO_PROTO interrupt). 559253790Sobrien * 5593178466Smarius * When we set the values, we adjust them in all ccbs belonging 559453790Sobrien * to this target, in the controller's register, and in the "phys" 559553790Sobrien * field of the controller's struct sym_hcb. 559653790Sobrien */ 559753790Sobrien 559853790Sobrien/* 559953790Sobrien * chip handler for SYNCHRONOUS DATA TRANSFER REQUEST (SDTR) message. 560053790Sobrien */ 560153790Sobrienstatic void sym_sync_nego(hcb_p np, tcb_p tp, ccb_p cp) 560253790Sobrien{ 560353790Sobrien u_char chg, ofs, per, fak, div; 560453790Sobrien int req = 1; 560553790Sobrien 560653790Sobrien /* 560753790Sobrien * Synchronous request message received. 560853790Sobrien */ 560953790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 561053809Sobrien sym_print_msg(cp, "sync msgin", np->msgin); 561153790Sobrien }; 561253790Sobrien 561353790Sobrien /* 561453790Sobrien * request or answer ? 561553790Sobrien */ 561653790Sobrien if (INB (HS_PRT) == HS_NEGOTIATE) { 561753790Sobrien OUTB (HS_PRT, HS_BUSY); 561853790Sobrien if (cp->nego_status && cp->nego_status != NS_SYNC) 561953790Sobrien goto reject_it; 562053790Sobrien req = 0; 562153790Sobrien } 562253790Sobrien 562353790Sobrien /* 562453790Sobrien * get requested values. 562553790Sobrien */ 562653790Sobrien chg = 0; 562753790Sobrien per = np->msgin[3]; 562853790Sobrien ofs = np->msgin[4]; 562953790Sobrien 563053790Sobrien /* 563153790Sobrien * check values against our limits. 563253790Sobrien */ 563353790Sobrien if (ofs) { 563453790Sobrien if (ofs > np->maxoffs) 563553790Sobrien {chg = 1; ofs = np->maxoffs;} 563653790Sobrien if (req) { 563753790Sobrien if (ofs > tp->tinfo.user.offset) 563853790Sobrien {chg = 1; ofs = tp->tinfo.user.offset;} 563953790Sobrien } 564053790Sobrien } 564153790Sobrien 564253790Sobrien if (ofs) { 564353790Sobrien if (per < np->minsync) 564453790Sobrien {chg = 1; per = np->minsync;} 564553790Sobrien if (req) { 564653790Sobrien if (per < tp->tinfo.user.period) 564753790Sobrien {chg = 1; per = tp->tinfo.user.period;} 564853790Sobrien } 564953790Sobrien } 565053790Sobrien 565153790Sobrien div = fak = 0; 565253790Sobrien if (ofs && sym_getsync(np, 0, per, &div, &fak) < 0) 565353790Sobrien goto reject_it; 565453790Sobrien 565553790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 565653790Sobrien PRINT_ADDR(cp); 565753790Sobrien printf ("sdtr: ofs=%d per=%d div=%d fak=%d chg=%d.\n", 565853790Sobrien ofs, per, div, fak, chg); 565953790Sobrien } 566053790Sobrien 566153790Sobrien /* 566253790Sobrien * This was an answer message 566353790Sobrien */ 566453790Sobrien if (req == 0) { 566553790Sobrien if (chg) /* Answer wasn't acceptable. */ 566653790Sobrien goto reject_it; 566753790Sobrien sym_setsync (np, cp, ofs, per, div, fak); 566861429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 566953790Sobrien return; 567053790Sobrien } 567153790Sobrien 567253790Sobrien /* 567353790Sobrien * It was a request. Set value and 567453790Sobrien * prepare an answer message 567553790Sobrien */ 567653790Sobrien sym_setsync (np, cp, ofs, per, div, fak); 567753790Sobrien 567853790Sobrien np->msgout[0] = M_EXTENDED; 567953790Sobrien np->msgout[1] = 3; 568053790Sobrien np->msgout[2] = M_X_SYNC_REQ; 568153790Sobrien np->msgout[3] = per; 568253790Sobrien np->msgout[4] = ofs; 568353790Sobrien 568453790Sobrien cp->nego_status = NS_SYNC; 568553790Sobrien 568653790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 568753790Sobrien sym_print_msg(cp, "sync msgout", np->msgout); 568853790Sobrien } 568953790Sobrien 569053790Sobrien np->msgin [0] = M_NOOP; 569153790Sobrien 569261429Sgroudier OUTL_DSP (SCRIPTB_BA (np, sdtr_resp)); 569353790Sobrien return; 569453790Sobrienreject_it: 569553790Sobrien sym_setsync (np, cp, 0, 0, 0, 0); 569661429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 569753790Sobrien} 569853790Sobrien 569953790Sobrien/* 570053790Sobrien * chip handler for PARALLEL PROTOCOL REQUEST (PPR) message. 570153790Sobrien */ 570253790Sobrienstatic void sym_ppr_nego(hcb_p np, tcb_p tp, ccb_p cp) 570353790Sobrien{ 570453790Sobrien u_char chg, ofs, per, fak, dt, div, wide; 570553790Sobrien int req = 1; 570653790Sobrien 570753790Sobrien /* 570853790Sobrien * Synchronous request message received. 570953790Sobrien */ 571053790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 571153809Sobrien sym_print_msg(cp, "ppr msgin", np->msgin); 571253790Sobrien }; 571353790Sobrien 571453790Sobrien /* 571572361Sgroudier * get requested values. 571672361Sgroudier */ 571772361Sgroudier chg = 0; 571872361Sgroudier per = np->msgin[3]; 571972361Sgroudier ofs = np->msgin[5]; 572072361Sgroudier wide = np->msgin[6]; 572172361Sgroudier dt = np->msgin[7] & PPR_OPT_DT; 572272361Sgroudier 572372361Sgroudier /* 572453790Sobrien * request or answer ? 572553790Sobrien */ 572653790Sobrien if (INB (HS_PRT) == HS_NEGOTIATE) { 572753790Sobrien OUTB (HS_PRT, HS_BUSY); 572853790Sobrien if (cp->nego_status && cp->nego_status != NS_PPR) 572953790Sobrien goto reject_it; 573053790Sobrien req = 0; 573153790Sobrien } 573253790Sobrien 573353790Sobrien /* 573453790Sobrien * check values against our limits. 573553790Sobrien */ 573653790Sobrien if (wide > np->maxwide) 573753790Sobrien {chg = 1; wide = np->maxwide;} 573853790Sobrien if (!wide || !(np->features & FE_ULTRA3)) 573953790Sobrien dt &= ~PPR_OPT_DT; 574053790Sobrien if (req) { 574153790Sobrien if (wide > tp->tinfo.user.width) 574253790Sobrien {chg = 1; wide = tp->tinfo.user.width;} 574353790Sobrien } 574457186Sgroudier 574553790Sobrien if (!(np->features & FE_U3EN)) /* Broken U3EN bit not supported */ 574653790Sobrien dt &= ~PPR_OPT_DT; 574757186Sgroudier 574853790Sobrien if (dt != (np->msgin[7] & PPR_OPT_MASK)) chg = 1; 574953790Sobrien 575053790Sobrien if (ofs) { 575160134Sgroudier if (dt) { 575260134Sgroudier if (ofs > np->maxoffs_dt) 575360134Sgroudier {chg = 1; ofs = np->maxoffs_dt;} 575460134Sgroudier } 575560134Sgroudier else if (ofs > np->maxoffs) 575653790Sobrien {chg = 1; ofs = np->maxoffs;} 575753790Sobrien if (req) { 575853790Sobrien if (ofs > tp->tinfo.user.offset) 575953790Sobrien {chg = 1; ofs = tp->tinfo.user.offset;} 576053790Sobrien } 576153790Sobrien } 576253790Sobrien 576353790Sobrien if (ofs) { 576453809Sobrien if (dt) { 576553809Sobrien if (per < np->minsync_dt) 576653809Sobrien {chg = 1; per = np->minsync_dt;} 576753809Sobrien } 576853790Sobrien else if (per < np->minsync) 576953790Sobrien {chg = 1; per = np->minsync;} 577053790Sobrien if (req) { 577153790Sobrien if (per < tp->tinfo.user.period) 577253790Sobrien {chg = 1; per = tp->tinfo.user.period;} 577353790Sobrien } 577453790Sobrien } 577553790Sobrien 577653790Sobrien div = fak = 0; 577753790Sobrien if (ofs && sym_getsync(np, dt, per, &div, &fak) < 0) 577853790Sobrien goto reject_it; 5779178466Smarius 578053790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 578153790Sobrien PRINT_ADDR(cp); 578253790Sobrien printf ("ppr: " 578353790Sobrien "dt=%x ofs=%d per=%d wide=%d div=%d fak=%d chg=%d.\n", 578453790Sobrien dt, ofs, per, wide, div, fak, chg); 578553790Sobrien } 578653790Sobrien 578753790Sobrien /* 578853790Sobrien * It was an answer. 578953790Sobrien */ 579053790Sobrien if (req == 0) { 579153790Sobrien if (chg) /* Answer wasn't acceptable */ 579253790Sobrien goto reject_it; 579353790Sobrien sym_setpprot (np, cp, dt, ofs, per, wide, div, fak); 579461429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 579553790Sobrien return; 579653790Sobrien } 579753790Sobrien 579853790Sobrien /* 579953790Sobrien * It was a request. Set value and 580053790Sobrien * prepare an answer message 580153790Sobrien */ 580253790Sobrien sym_setpprot (np, cp, dt, ofs, per, wide, div, fak); 580353790Sobrien 580453790Sobrien np->msgout[0] = M_EXTENDED; 580553790Sobrien np->msgout[1] = 6; 580653790Sobrien np->msgout[2] = M_X_PPR_REQ; 580753790Sobrien np->msgout[3] = per; 580853790Sobrien np->msgout[4] = 0; 580953790Sobrien np->msgout[5] = ofs; 581053790Sobrien np->msgout[6] = wide; 581153790Sobrien np->msgout[7] = dt; 581253790Sobrien 581353790Sobrien cp->nego_status = NS_PPR; 581453790Sobrien 581553790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 581653809Sobrien sym_print_msg(cp, "ppr msgout", np->msgout); 581753790Sobrien } 581853790Sobrien 581953790Sobrien np->msgin [0] = M_NOOP; 582053790Sobrien 582161429Sgroudier OUTL_DSP (SCRIPTB_BA (np, ppr_resp)); 582253790Sobrien return; 582353790Sobrienreject_it: 582453790Sobrien sym_setpprot (np, cp, 0, 0, 0, 0, 0, 0); 582561429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 582672361Sgroudier /* 5827178466Smarius * If it was a device response that should result in 582872361Sgroudier * ST, we may want to try a legacy negotiation later. 582972361Sgroudier */ 583072361Sgroudier if (!req && !dt) { 583172361Sgroudier tp->tinfo.goal.options = 0; 583272361Sgroudier tp->tinfo.goal.width = wide; 583372361Sgroudier tp->tinfo.goal.period = per; 583472361Sgroudier tp->tinfo.goal.offset = ofs; 583572361Sgroudier } 583653790Sobrien} 583753790Sobrien 583853790Sobrien/* 583953790Sobrien * chip handler for WIDE DATA TRANSFER REQUEST (WDTR) message. 584053790Sobrien */ 584153790Sobrienstatic void sym_wide_nego(hcb_p np, tcb_p tp, ccb_p cp) 584253790Sobrien{ 584353790Sobrien u_char chg, wide; 584453790Sobrien int req = 1; 584553790Sobrien 584653790Sobrien /* 584753790Sobrien * Wide request message received. 584853790Sobrien */ 584953790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 585053790Sobrien sym_print_msg(cp, "wide msgin", np->msgin); 585153790Sobrien }; 585253790Sobrien 585353790Sobrien /* 5854108470Sschweikh * Is it a request from the device? 585553790Sobrien */ 585653790Sobrien if (INB (HS_PRT) == HS_NEGOTIATE) { 585753790Sobrien OUTB (HS_PRT, HS_BUSY); 585853790Sobrien if (cp->nego_status && cp->nego_status != NS_WIDE) 585953790Sobrien goto reject_it; 586053790Sobrien req = 0; 586153790Sobrien } 586253790Sobrien 586353790Sobrien /* 586453790Sobrien * get requested values. 586553790Sobrien */ 586653790Sobrien chg = 0; 586753790Sobrien wide = np->msgin[3]; 586853790Sobrien 586953790Sobrien /* 587053790Sobrien * check values against driver limits. 587153790Sobrien */ 587265404Sgroudier if (wide > np->maxwide) 587365404Sgroudier {chg = 1; wide = np->maxwide;} 587453790Sobrien if (req) { 587553790Sobrien if (wide > tp->tinfo.user.width) 587653790Sobrien {chg = 1; wide = tp->tinfo.user.width;} 587753790Sobrien } 587853790Sobrien 587953790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 588053790Sobrien PRINT_ADDR(cp); 588153790Sobrien printf ("wdtr: wide=%d chg=%d.\n", wide, chg); 588253790Sobrien } 588353790Sobrien 588453790Sobrien /* 588553790Sobrien * This was an answer message 588653790Sobrien */ 588753790Sobrien if (req == 0) { 588853790Sobrien if (chg) /* Answer wasn't acceptable. */ 588953790Sobrien goto reject_it; 589053790Sobrien sym_setwide (np, cp, wide); 589159743Sgroudier 589255628Sgroudier /* 589355628Sgroudier * Negotiate for SYNC immediately after WIDE response. 5894178466Smarius * This allows to negotiate for both WIDE and SYNC on 589555628Sgroudier * a single SCSI command (Suggested by Justin Gibbs). 589655628Sgroudier */ 589755628Sgroudier if (tp->tinfo.goal.offset) { 589855628Sgroudier np->msgout[0] = M_EXTENDED; 589955628Sgroudier np->msgout[1] = 3; 590055628Sgroudier np->msgout[2] = M_X_SYNC_REQ; 590155628Sgroudier np->msgout[3] = tp->tinfo.goal.period; 590255628Sgroudier np->msgout[4] = tp->tinfo.goal.offset; 590355628Sgroudier 590455628Sgroudier if (DEBUG_FLAGS & DEBUG_NEGO) { 590555628Sgroudier sym_print_msg(cp, "sync msgout", np->msgout); 590655628Sgroudier } 590755628Sgroudier 590855628Sgroudier cp->nego_status = NS_SYNC; 590955628Sgroudier OUTB (HS_PRT, HS_NEGOTIATE); 591061429Sgroudier OUTL_DSP (SCRIPTB_BA (np, sdtr_resp)); 591155628Sgroudier return; 591255628Sgroudier } 591359743Sgroudier 591461429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 591553790Sobrien return; 591653790Sobrien }; 591753790Sobrien 591853790Sobrien /* 591953790Sobrien * It was a request, set value and 592053790Sobrien * prepare an answer message 592153790Sobrien */ 592253790Sobrien sym_setwide (np, cp, wide); 592353790Sobrien 592453790Sobrien np->msgout[0] = M_EXTENDED; 592553790Sobrien np->msgout[1] = 2; 592653790Sobrien np->msgout[2] = M_X_WIDE_REQ; 592753790Sobrien np->msgout[3] = wide; 592853790Sobrien 592953790Sobrien np->msgin [0] = M_NOOP; 593053790Sobrien 593153790Sobrien cp->nego_status = NS_WIDE; 593253790Sobrien 593353790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 593453790Sobrien sym_print_msg(cp, "wide msgout", np->msgout); 593553790Sobrien } 593653790Sobrien 593761429Sgroudier OUTL_DSP (SCRIPTB_BA (np, wdtr_resp)); 593853790Sobrien return; 593953790Sobrienreject_it: 594061429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 594153790Sobrien} 594253790Sobrien 594353790Sobrien/* 594453790Sobrien * Reset SYNC or WIDE to default settings. 594553790Sobrien * 5946178466Smarius * Called when a negotiation does not succeed either 594753790Sobrien * on rejection or on protocol error. 594872361Sgroudier * 5949178466Smarius * If it was a PPR that made problems, we may want to 595072361Sgroudier * try a legacy negotiation later. 595153790Sobrien */ 595253790Sobrienstatic void sym_nego_default(hcb_p np, tcb_p tp, ccb_p cp) 595353790Sobrien{ 595453790Sobrien /* 595553790Sobrien * any error in negotiation: 595653790Sobrien * fall back to default mode. 595753790Sobrien */ 595853790Sobrien switch (cp->nego_status) { 595953790Sobrien case NS_PPR: 596072361Sgroudier#if 0 596153790Sobrien sym_setpprot (np, cp, 0, 0, 0, 0, 0, 0); 596272361Sgroudier#else 596372361Sgroudier tp->tinfo.goal.options = 0; 596472361Sgroudier if (tp->tinfo.goal.period < np->minsync) 596572361Sgroudier tp->tinfo.goal.period = np->minsync; 596672361Sgroudier if (tp->tinfo.goal.offset > np->maxoffs) 596772361Sgroudier tp->tinfo.goal.offset = np->maxoffs; 596872361Sgroudier#endif 596953790Sobrien break; 597053790Sobrien case NS_SYNC: 597153790Sobrien sym_setsync (np, cp, 0, 0, 0, 0); 597253790Sobrien break; 597353790Sobrien case NS_WIDE: 597453790Sobrien sym_setwide (np, cp, 0); 597553790Sobrien break; 597653790Sobrien }; 597753790Sobrien np->msgin [0] = M_NOOP; 597853790Sobrien np->msgout[0] = M_NOOP; 597953790Sobrien cp->nego_status = 0; 598053790Sobrien} 598153790Sobrien 598253790Sobrien/* 5983178466Smarius * chip handler for MESSAGE REJECT received in response to 598453790Sobrien * a WIDE or SYNCHRONOUS negotiation. 598553790Sobrien */ 598653790Sobrienstatic void sym_nego_rejected(hcb_p np, tcb_p tp, ccb_p cp) 598753790Sobrien{ 598853790Sobrien sym_nego_default(np, tp, cp); 598953790Sobrien OUTB (HS_PRT, HS_BUSY); 599053790Sobrien} 599153790Sobrien 599253790Sobrien/* 599353790Sobrien * chip exception handler for programmed interrupts. 599453790Sobrien */ 5995105215Sphkstatic void sym_int_sir (hcb_p np) 599653790Sobrien{ 599753790Sobrien u_char num = INB (nc_dsps); 599861051Sgroudier u32 dsa = INL (nc_dsa); 599953790Sobrien ccb_p cp = sym_ccb_from_dsa(np, dsa); 600053790Sobrien u_char target = INB (nc_sdid) & 0x0f; 600153790Sobrien tcb_p tp = &np->target[target]; 600253790Sobrien int tmp; 600353790Sobrien 6004178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 6005178468Smarius 600653790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num); 600753790Sobrien 600853790Sobrien switch (num) { 600953790Sobrien /* 6010178466Smarius * Command has been completed with error condition 601153790Sobrien * or has been auto-sensed. 601253790Sobrien */ 601353790Sobrien case SIR_COMPLETE_ERROR: 601453790Sobrien sym_complete_error(np, cp); 601553790Sobrien return; 601653790Sobrien /* 601753790Sobrien * The C code is currently trying to recover from something. 601853790Sobrien * Typically, user want to abort some command. 601953790Sobrien */ 602053790Sobrien case SIR_SCRIPT_STOPPED: 602153790Sobrien case SIR_TARGET_SELECTED: 602253790Sobrien case SIR_ABORT_SENT: 602353790Sobrien sym_sir_task_recovery(np, num); 602453790Sobrien return; 602553790Sobrien /* 6026178466Smarius * The device didn't go to MSG OUT phase after having 6027178466Smarius * been selected with ATN. We donnot want to handle 602853790Sobrien * that. 602953790Sobrien */ 603053790Sobrien case SIR_SEL_ATN_NO_MSG_OUT: 603153790Sobrien printf ("%s:%d: No MSG OUT phase after selection with ATN.\n", 603253790Sobrien sym_name (np), target); 603353790Sobrien goto out_stuck; 603453790Sobrien /* 6035178466Smarius * The device didn't switch to MSG IN phase after 603653790Sobrien * having reseleted the initiator. 603753790Sobrien */ 603853790Sobrien case SIR_RESEL_NO_MSG_IN: 603957186Sgroudier printf ("%s:%d: No MSG IN phase after reselection.\n", 604057186Sgroudier sym_name (np), target); 604157186Sgroudier goto out_stuck; 604253790Sobrien /* 6043178466Smarius * After reselection, the device sent a message that wasn't 604453790Sobrien * an IDENTIFY. 604553790Sobrien */ 604653790Sobrien case SIR_RESEL_NO_IDENTIFY: 604757186Sgroudier printf ("%s:%d: No IDENTIFY after reselection.\n", 604857186Sgroudier sym_name (np), target); 604957186Sgroudier goto out_stuck; 605053790Sobrien /* 605153790Sobrien * The device reselected a LUN we donnot know about. 605253790Sobrien */ 605353790Sobrien case SIR_RESEL_BAD_LUN: 605453790Sobrien np->msgout[0] = M_RESET; 605553790Sobrien goto out; 605653790Sobrien /* 6057178466Smarius * The device reselected for an untagged nexus and we 605853790Sobrien * haven't any. 605953790Sobrien */ 606053790Sobrien case SIR_RESEL_BAD_I_T_L: 606153790Sobrien np->msgout[0] = M_ABORT; 606253790Sobrien goto out; 606353790Sobrien /* 6064178466Smarius * The device reselected for a tagged nexus that we donnot 606553790Sobrien * have. 606653790Sobrien */ 606753790Sobrien case SIR_RESEL_BAD_I_T_L_Q: 606853790Sobrien np->msgout[0] = M_ABORT_TAG; 606953790Sobrien goto out; 607053790Sobrien /* 6071178466Smarius * The SCRIPTS let us know that the device has grabbed 607253790Sobrien * our message and will abort the job. 607353790Sobrien */ 607453790Sobrien case SIR_RESEL_ABORTED: 607553790Sobrien np->lastmsg = np->msgout[0]; 607653790Sobrien np->msgout[0] = M_NOOP; 607753790Sobrien printf ("%s:%d: message %x sent on bad reselection.\n", 607853790Sobrien sym_name (np), target, np->lastmsg); 607953790Sobrien goto out; 608053790Sobrien /* 6081178466Smarius * The SCRIPTS let us know that a message has been 608253790Sobrien * successfully sent to the device. 608353790Sobrien */ 608453790Sobrien case SIR_MSG_OUT_DONE: 608553790Sobrien np->lastmsg = np->msgout[0]; 608653790Sobrien np->msgout[0] = M_NOOP; 608753790Sobrien /* Should we really care of that */ 608853790Sobrien if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) { 608953790Sobrien if (cp) { 609053790Sobrien cp->xerr_status &= ~XE_PARITY_ERR; 609153790Sobrien if (!cp->xerr_status) 609253790Sobrien OUTOFFB (HF_PRT, HF_EXT_ERR); 609353790Sobrien } 609453790Sobrien } 609553790Sobrien goto out; 609653790Sobrien /* 609753790Sobrien * The device didn't send a GOOD SCSI status. 6098178466Smarius * We may have some work to do prior to allow 609953790Sobrien * the SCRIPTS processor to continue. 610053790Sobrien */ 610153790Sobrien case SIR_BAD_SCSI_STATUS: 610253790Sobrien if (!cp) 610353790Sobrien goto out; 6104251572Smarius sym_sir_bad_scsi_status(np, cp); 610553790Sobrien return; 610653790Sobrien /* 6107178466Smarius * We are asked by the SCRIPTS to prepare a 610853790Sobrien * REJECT message. 610953790Sobrien */ 611053790Sobrien case SIR_REJECT_TO_SEND: 611153790Sobrien sym_print_msg(cp, "M_REJECT to send for ", np->msgin); 611253790Sobrien np->msgout[0] = M_REJECT; 611353790Sobrien goto out; 611453790Sobrien /* 6115178466Smarius * We have been ODD at the end of a DATA IN 6116178466Smarius * transfer and the device didn't send a 611753790Sobrien * IGNORE WIDE RESIDUE message. 611853790Sobrien * It is a data overrun condition. 611953790Sobrien */ 612053790Sobrien case SIR_SWIDE_OVERRUN: 612153790Sobrien if (cp) { 612253790Sobrien OUTONB (HF_PRT, HF_EXT_ERR); 612353790Sobrien cp->xerr_status |= XE_SWIDE_OVRUN; 612453790Sobrien } 612553790Sobrien goto out; 612653790Sobrien /* 6127178466Smarius * We have been ODD at the end of a DATA OUT 612853790Sobrien * transfer. 612953790Sobrien * It is a data underrun condition. 613053790Sobrien */ 613153790Sobrien case SIR_SODL_UNDERRUN: 613253790Sobrien if (cp) { 613353790Sobrien OUTONB (HF_PRT, HF_EXT_ERR); 613453790Sobrien cp->xerr_status |= XE_SODL_UNRUN; 613553790Sobrien } 613653790Sobrien goto out; 613753790Sobrien /* 6138178466Smarius * The device wants us to tranfer more data than 613959252Sgroudier * expected or in the wrong direction. 614059252Sgroudier * The number of extra bytes is in scratcha. 614159252Sgroudier * It is a data overrun condition. 614259252Sgroudier */ 614359252Sgroudier case SIR_DATA_OVERRUN: 614459252Sgroudier if (cp) { 614559252Sgroudier OUTONB (HF_PRT, HF_EXT_ERR); 614659252Sgroudier cp->xerr_status |= XE_EXTRA_DATA; 614759252Sgroudier cp->extra_bytes += INL (nc_scratcha); 614859252Sgroudier } 614959252Sgroudier goto out; 615059252Sgroudier /* 615159252Sgroudier * The device switched to an illegal phase (4/5). 615259252Sgroudier */ 615359252Sgroudier case SIR_BAD_PHASE: 615459252Sgroudier if (cp) { 615559252Sgroudier OUTONB (HF_PRT, HF_EXT_ERR); 615659252Sgroudier cp->xerr_status |= XE_BAD_PHASE; 615759252Sgroudier } 615859252Sgroudier goto out; 615959252Sgroudier /* 616053790Sobrien * We received a message. 616153790Sobrien */ 616253790Sobrien case SIR_MSG_RECEIVED: 616353790Sobrien if (!cp) 616453790Sobrien goto out_stuck; 616553790Sobrien switch (np->msgin [0]) { 616653790Sobrien /* 616753790Sobrien * We received an extended message. 6168178466Smarius * We handle MODIFY DATA POINTER, SDTR, WDTR 616953790Sobrien * and reject all other extended messages. 617053790Sobrien */ 617153790Sobrien case M_EXTENDED: 617253790Sobrien switch (np->msgin [2]) { 617353790Sobrien case M_X_MODIFY_DP: 617453790Sobrien if (DEBUG_FLAGS & DEBUG_POINTER) 617553790Sobrien sym_print_msg(cp,"modify DP",np->msgin); 6176178466Smarius tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + 617753790Sobrien (np->msgin[5]<<8) + (np->msgin[6]); 6178251572Smarius sym_modify_dp(np, cp, tmp); 617953790Sobrien return; 618053790Sobrien case M_X_SYNC_REQ: 618153790Sobrien sym_sync_nego(np, tp, cp); 618253790Sobrien return; 618353790Sobrien case M_X_PPR_REQ: 618453790Sobrien sym_ppr_nego(np, tp, cp); 618553790Sobrien return; 618653790Sobrien case M_X_WIDE_REQ: 618753790Sobrien sym_wide_nego(np, tp, cp); 618853790Sobrien return; 618953790Sobrien default: 619053790Sobrien goto out_reject; 619153790Sobrien } 619253790Sobrien break; 619353790Sobrien /* 619453790Sobrien * We received a 1/2 byte message not handled from SCRIPTS. 6195178466Smarius * We are only expecting MESSAGE REJECT and IGNORE WIDE 6196178466Smarius * RESIDUE messages that haven't been anticipated by 6197178466Smarius * SCRIPTS on SWIDE full condition. Unanticipated IGNORE 619853790Sobrien * WIDE RESIDUE messages are aliased as MODIFY DP (-1). 619953790Sobrien */ 620053790Sobrien case M_IGN_RESIDUE: 620153790Sobrien if (DEBUG_FLAGS & DEBUG_POINTER) 620253790Sobrien sym_print_msg(cp,"ign wide residue", np->msgin); 6203251572Smarius sym_modify_dp(np, cp, -1); 620453790Sobrien return; 620553790Sobrien case M_REJECT: 620653790Sobrien if (INB (HS_PRT) == HS_NEGOTIATE) 620753790Sobrien sym_nego_rejected(np, tp, cp); 620853790Sobrien else { 620953790Sobrien PRINT_ADDR(cp); 621053790Sobrien printf ("M_REJECT received (%x:%x).\n", 621153790Sobrien scr_to_cpu(np->lastmsg), np->msgout[0]); 621253790Sobrien } 621353790Sobrien goto out_clrack; 621453790Sobrien break; 621553790Sobrien default: 621653790Sobrien goto out_reject; 621753790Sobrien } 621853790Sobrien break; 621953790Sobrien /* 622053790Sobrien * We received an unknown message. 622153790Sobrien * Ignore all MSG IN phases and reject it. 622253790Sobrien */ 622353790Sobrien case SIR_MSG_WEIRD: 622453790Sobrien sym_print_msg(cp, "WEIRD message received", np->msgin); 622561429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_weird)); 622653790Sobrien return; 622753790Sobrien /* 622853790Sobrien * Negotiation failed. 622953790Sobrien * Target does not send us the reply. 623053790Sobrien * Remove the HS_NEGOTIATE status. 623153790Sobrien */ 623253790Sobrien case SIR_NEGO_FAILED: 623353790Sobrien OUTB (HS_PRT, HS_BUSY); 623453790Sobrien /* 623553790Sobrien * Negotiation failed. 623653790Sobrien * Target does not want answer message. 623753790Sobrien */ 623853790Sobrien case SIR_NEGO_PROTO: 623953790Sobrien sym_nego_default(np, tp, cp); 624053790Sobrien goto out; 624153790Sobrien }; 624253790Sobrien 624353790Sobrienout: 624461429Sgroudier OUTONB_STD (); 624553790Sobrien return; 624653790Sobrienout_reject: 624761429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 624853790Sobrien return; 624953790Sobrienout_clrack: 625061429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 625153790Sobrien return; 625253790Sobrienout_stuck: 625392732Speter return; 625453790Sobrien} 625553790Sobrien 625653790Sobrien/* 625753790Sobrien * Acquire a control block 625853790Sobrien */ 625953790Sobrienstatic ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order) 626053790Sobrien{ 626153790Sobrien tcb_p tp = &np->target[tn]; 6262251572Smarius lcb_p lp = sym_lp(tp, ln); 626353790Sobrien u_short tag = NO_TAG; 626453790Sobrien SYM_QUEHEAD *qp; 6265178466Smarius ccb_p cp = (ccb_p) NULL; 626653790Sobrien 626753790Sobrien /* 626853790Sobrien * Look for a free CCB 626953790Sobrien */ 627053790Sobrien if (sym_que_empty(&np->free_ccbq)) 6271178468Smarius goto out; 627253790Sobrien qp = sym_remque_head(&np->free_ccbq); 627353790Sobrien if (!qp) 627453790Sobrien goto out; 627553790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 627653790Sobrien 627753790Sobrien /* 627853790Sobrien * If the LCB is not yet available and the LUN 627953790Sobrien * has been probed ok, try to allocate the LCB. 628053790Sobrien */ 628153790Sobrien if (!lp && sym_is_bit(tp->lun_map, ln)) { 628253790Sobrien lp = sym_alloc_lcb(np, tn, ln); 628353790Sobrien if (!lp) 628453790Sobrien goto out_free; 628553790Sobrien } 628653790Sobrien 628753790Sobrien /* 6288178466Smarius * If the LCB is not available here, then the 6289178466Smarius * logical unit is not yet discovered. For those 6290178466Smarius * ones only accept 1 SCSI IO per logical unit, 629153790Sobrien * since we cannot allow disconnections. 629253790Sobrien */ 629353790Sobrien if (!lp) { 629453790Sobrien if (!sym_is_bit(tp->busy0_map, ln)) 629553790Sobrien sym_set_bit(tp->busy0_map, ln); 629653790Sobrien else 629753790Sobrien goto out_free; 629853790Sobrien } else { 629953790Sobrien /* 630053790Sobrien * If we have been asked for a tagged command. 630153790Sobrien */ 630253790Sobrien if (tag_order) { 630353790Sobrien /* 630453790Sobrien * Debugging purpose. 630553790Sobrien */ 630653790Sobrien assert(lp->busy_itl == 0); 630753790Sobrien /* 630853790Sobrien * Allocate resources for tags if not yet. 630953790Sobrien */ 631053790Sobrien if (!lp->cb_tags) { 631153790Sobrien sym_alloc_lcb_tags(np, tn, ln); 631253790Sobrien if (!lp->cb_tags) 631353790Sobrien goto out_free; 631453790Sobrien } 631553790Sobrien /* 631653790Sobrien * Get a tag for this SCSI IO and set up 6317178466Smarius * the CCB bus address for reselection, 631853790Sobrien * and count it for this LUN. 631955300Sgroudier * Toggle reselect path to tagged. 632053790Sobrien */ 632154690Sobrien if (lp->busy_itlq < SYM_CONF_MAX_TASK) { 632253790Sobrien tag = lp->cb_tags[lp->ia_tag]; 632354690Sobrien if (++lp->ia_tag == SYM_CONF_MAX_TASK) 632453790Sobrien lp->ia_tag = 0; 632553790Sobrien lp->itlq_tbl[tag] = cpu_to_scr(cp->ccb_ba); 632653790Sobrien ++lp->busy_itlq; 632759743Sgroudier lp->head.resel_sa = 632859292Sgroudier cpu_to_scr(SCRIPTA_BA (np, resel_tag)); 632953790Sobrien } 633053790Sobrien else 633153790Sobrien goto out_free; 633253790Sobrien } 633353790Sobrien /* 633453790Sobrien * This command will not be tagged. 6335178466Smarius * If we already have either a tagged or untagged 633653790Sobrien * one, refuse to overlap this untagged one. 633753790Sobrien */ 633853790Sobrien else { 633953790Sobrien /* 634053790Sobrien * Debugging purpose. 634153790Sobrien */ 634253790Sobrien assert(lp->busy_itl == 0 && lp->busy_itlq == 0); 634353790Sobrien /* 634453790Sobrien * Count this nexus for this LUN. 634553790Sobrien * Set up the CCB bus address for reselection. 634653790Sobrien * Toggle reselect path to untagged. 634753790Sobrien */ 634853790Sobrien if (++lp->busy_itl == 1) { 634959743Sgroudier lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba); 635059743Sgroudier lp->head.resel_sa = 635159743Sgroudier cpu_to_scr(SCRIPTA_BA (np, resel_no_tag)); 635253790Sobrien } 635353790Sobrien else 635453790Sobrien goto out_free; 635553790Sobrien } 635653790Sobrien } 635753790Sobrien /* 635853790Sobrien * Put the CCB into the busy queue. 635953790Sobrien */ 636053790Sobrien sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); 636153790Sobrien 636253790Sobrien /* 636353790Sobrien * Remember all informations needed to free this CCB. 636453790Sobrien */ 636553790Sobrien cp->to_abort = 0; 636653790Sobrien cp->tag = tag; 636753790Sobrien cp->target = tn; 636853790Sobrien cp->lun = ln; 636953790Sobrien 637053790Sobrien if (DEBUG_FLAGS & DEBUG_TAGS) { 637153790Sobrien PRINT_LUN(np, tn, ln); 637253790Sobrien printf ("ccb @%p using tag %d.\n", cp, tag); 637353790Sobrien } 637453790Sobrien 637553790Sobrienout: 637653790Sobrien return cp; 637753790Sobrienout_free: 637853790Sobrien sym_insque_head(&cp->link_ccbq, &np->free_ccbq); 6379178466Smarius return NULL; 638053790Sobrien} 638153790Sobrien 638253790Sobrien/* 638353790Sobrien * Release one control block 638453790Sobrien */ 6385251572Smariusstatic void sym_free_ccb(hcb_p np, ccb_p cp) 638653790Sobrien{ 638753790Sobrien tcb_p tp = &np->target[cp->target]; 6388251572Smarius lcb_p lp = sym_lp(tp, cp->lun); 638953790Sobrien 639053790Sobrien if (DEBUG_FLAGS & DEBUG_TAGS) { 639153790Sobrien PRINT_LUN(np, cp->target, cp->lun); 639253790Sobrien printf ("ccb @%p freeing tag %d.\n", cp, cp->tag); 639353790Sobrien } 639453790Sobrien 639553790Sobrien /* 639653790Sobrien * If LCB available, 639753790Sobrien */ 639853790Sobrien if (lp) { 639953790Sobrien /* 6400178466Smarius * If tagged, release the tag, set the relect path 640153790Sobrien */ 640253790Sobrien if (cp->tag != NO_TAG) { 640353790Sobrien /* 640453790Sobrien * Free the tag value. 640553790Sobrien */ 640653790Sobrien lp->cb_tags[lp->if_tag] = cp->tag; 640754690Sobrien if (++lp->if_tag == SYM_CONF_MAX_TASK) 640853790Sobrien lp->if_tag = 0; 640953790Sobrien /* 6410178466Smarius * Make the reselect path invalid, 641153790Sobrien * and uncount this CCB. 641253790Sobrien */ 641353790Sobrien lp->itlq_tbl[cp->tag] = cpu_to_scr(np->bad_itlq_ba); 641453790Sobrien --lp->busy_itlq; 641553790Sobrien } else { /* Untagged */ 641653790Sobrien /* 6417178466Smarius * Make the reselect path invalid, 641853790Sobrien * and uncount this CCB. 641953790Sobrien */ 642059743Sgroudier lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba); 642153790Sobrien --lp->busy_itl; 642253790Sobrien } 642353790Sobrien /* 642453790Sobrien * If no JOB active, make the LUN reselect path invalid. 642553790Sobrien */ 642653790Sobrien if (lp->busy_itlq == 0 && lp->busy_itl == 0) 642759743Sgroudier lp->head.resel_sa = 642859292Sgroudier cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun)); 642953790Sobrien } 643053790Sobrien /* 643153790Sobrien * Otherwise, we only accept 1 IO per LUN. 643253790Sobrien * Clear the bit that keeps track of this IO. 643353790Sobrien */ 643453790Sobrien else 643553790Sobrien sym_clr_bit(tp->busy0_map, cp->lun); 643653790Sobrien 643753790Sobrien /* 6438178466Smarius * We donnot queue more than 1 ccb per target 6439178466Smarius * with negotiation at any time. If this ccb was 644053790Sobrien * used for negotiation, clear this info in the tcb. 644153790Sobrien */ 644253790Sobrien if (cp == tp->nego_cp) 6443178466Smarius tp->nego_cp = NULL; 644453790Sobrien 644554690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 644653790Sobrien /* 644753790Sobrien * If we just complete the last queued CCB, 644853790Sobrien * clear this info that is no longer relevant. 644953790Sobrien */ 645053790Sobrien if (cp == np->last_cp) 6451178466Smarius np->last_cp = NULL; 645253790Sobrien#endif 645358927Sgroudier 645453790Sobrien /* 645558927Sgroudier * Unmap user data from DMA map if needed. 645658927Sgroudier */ 645758927Sgroudier if (cp->dmamapped) { 645858927Sgroudier bus_dmamap_unload(np->data_dmat, cp->dmamap); 645958927Sgroudier cp->dmamapped = 0; 646058927Sgroudier } 646158927Sgroudier 646258927Sgroudier /* 646353790Sobrien * Make this CCB available. 646453790Sobrien */ 6465178466Smarius cp->cam_ccb = NULL; 646653790Sobrien cp->host_status = HS_IDLE; 646753790Sobrien sym_remque(&cp->link_ccbq); 646853790Sobrien sym_insque_head(&cp->link_ccbq, &np->free_ccbq); 646953790Sobrien} 647053790Sobrien 647153790Sobrien/* 647253790Sobrien * Allocate a CCB from memory and initialize its fixed part. 647353790Sobrien */ 647453790Sobrienstatic ccb_p sym_alloc_ccb(hcb_p np) 647553790Sobrien{ 6476178466Smarius ccb_p cp = NULL; 647753790Sobrien int hcode; 647853790Sobrien 6479178468Smarius SYM_LOCK_ASSERT(MA_NOTOWNED); 6480178468Smarius 648153790Sobrien /* 6482178466Smarius * Prevent from allocating more CCBs than we can 648353790Sobrien * queue to the controller. 648453790Sobrien */ 648554690Sobrien if (np->actccbs >= SYM_CONF_MAX_START) 6486178466Smarius return NULL; 648753790Sobrien 648853790Sobrien /* 648953790Sobrien * Allocate memory for this CCB. 649053790Sobrien */ 649158927Sgroudier cp = sym_calloc_dma(sizeof(struct sym_ccb), "CCB"); 649253790Sobrien if (!cp) 6493178468Smarius return NULL; 649453790Sobrien 649553790Sobrien /* 649658927Sgroudier * Allocate a bounce buffer for sense data. 649758927Sgroudier */ 649858927Sgroudier cp->sns_bbuf = sym_calloc_dma(SYM_SNS_BBUF_LEN, "SNS_BBUF"); 649958927Sgroudier if (!cp->sns_bbuf) 650058927Sgroudier goto out_free; 650158927Sgroudier 650258927Sgroudier /* 650358927Sgroudier * Allocate a map for the DMA of user data. 650458927Sgroudier */ 650558927Sgroudier if (bus_dmamap_create(np->data_dmat, 0, &cp->dmamap)) 650658927Sgroudier goto out_free; 650758927Sgroudier /* 650853790Sobrien * Count it. 650953790Sobrien */ 651053790Sobrien np->actccbs++; 651153790Sobrien 651253790Sobrien /* 6513178468Smarius * Initialize the callout. 6514178468Smarius */ 6515178468Smarius callout_init(&cp->ch, 1); 6516178468Smarius 6517178468Smarius /* 651853790Sobrien * Compute the bus address of this ccb. 651953790Sobrien */ 652053790Sobrien cp->ccb_ba = vtobus(cp); 652153790Sobrien 652253790Sobrien /* 652353790Sobrien * Insert this ccb into the hashed list. 652453790Sobrien */ 652553790Sobrien hcode = CCB_HASH_CODE(cp->ccb_ba); 652653790Sobrien cp->link_ccbh = np->ccbh[hcode]; 652753790Sobrien np->ccbh[hcode] = cp; 652853790Sobrien 652953790Sobrien /* 6530178466Smarius * Initialize the start and restart actions. 653153790Sobrien */ 653259743Sgroudier cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 653359743Sgroudier cp->phys.head.go.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l)); 653453790Sobrien 653553790Sobrien /* 653653790Sobrien * Initilialyze some other fields. 653753790Sobrien */ 653858927Sgroudier cp->phys.smsg_ext.addr = cpu_to_scr(HCB_BA(np, msgin[2])); 653953790Sobrien 654053790Sobrien /* 654155300Sgroudier * Chain into free ccb queue. 654253790Sobrien */ 654353790Sobrien sym_insque_head(&cp->link_ccbq, &np->free_ccbq); 654453790Sobrien 654553790Sobrien return cp; 654658927Sgroudierout_free: 6547178468Smarius if (cp->sns_bbuf) 6548178468Smarius sym_mfree_dma(cp->sns_bbuf, SYM_SNS_BBUF_LEN, "SNS_BBUF"); 6549178468Smarius sym_mfree_dma(cp, sizeof(*cp), "CCB"); 6550178466Smarius return NULL; 655153790Sobrien} 655253790Sobrien 655353790Sobrien/* 655453790Sobrien * Look up a CCB from a DSA value. 655553790Sobrien */ 655661051Sgroudierstatic ccb_p sym_ccb_from_dsa(hcb_p np, u32 dsa) 655753790Sobrien{ 655853790Sobrien int hcode; 655953790Sobrien ccb_p cp; 656053790Sobrien 656153790Sobrien hcode = CCB_HASH_CODE(dsa); 656253790Sobrien cp = np->ccbh[hcode]; 656353790Sobrien while (cp) { 656453790Sobrien if (cp->ccb_ba == dsa) 656553790Sobrien break; 656653790Sobrien cp = cp->link_ccbh; 656753790Sobrien } 656853790Sobrien 656953790Sobrien return cp; 657053790Sobrien} 657153790Sobrien 657253790Sobrien/* 657353790Sobrien * Lun control block allocation and initialization. 657453790Sobrien */ 657553790Sobrienstatic lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln) 657653790Sobrien{ 657753790Sobrien tcb_p tp = &np->target[tn]; 6578251572Smarius lcb_p lp = sym_lp(tp, ln); 657953790Sobrien 658053790Sobrien /* 658153790Sobrien * Already done, just return. 658253790Sobrien */ 658353790Sobrien if (lp) 658453790Sobrien return lp; 658553790Sobrien /* 658653790Sobrien * Check against some race. 658753790Sobrien */ 658853790Sobrien assert(!sym_is_bit(tp->busy0_map, ln)); 658953790Sobrien 659053790Sobrien /* 659153790Sobrien * Allocate the LCB bus address array. 659253790Sobrien * Compute the bus address of this table. 659353790Sobrien */ 659453790Sobrien if (ln && !tp->luntbl) { 659553790Sobrien int i; 659653790Sobrien 659758927Sgroudier tp->luntbl = sym_calloc_dma(256, "LUNTBL"); 659853790Sobrien if (!tp->luntbl) 659953790Sobrien goto fail; 660053790Sobrien for (i = 0 ; i < 64 ; i++) 660153790Sobrien tp->luntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa)); 660259743Sgroudier tp->head.luntbl_sa = cpu_to_scr(vtobus(tp->luntbl)); 660353790Sobrien } 660453790Sobrien 660553790Sobrien /* 660653790Sobrien * Allocate the table of pointers for LUN(s) > 0, if needed. 660753790Sobrien */ 660853790Sobrien if (ln && !tp->lunmp) { 660954690Sobrien tp->lunmp = sym_calloc(SYM_CONF_MAX_LUN * sizeof(lcb_p), 661053790Sobrien "LUNMP"); 661153790Sobrien if (!tp->lunmp) 661253790Sobrien goto fail; 661353790Sobrien } 661453790Sobrien 661553790Sobrien /* 661653790Sobrien * Allocate the lcb. 661753790Sobrien * Make it available to the chip. 661853790Sobrien */ 661958927Sgroudier lp = sym_calloc_dma(sizeof(struct sym_lcb), "LCB"); 662053790Sobrien if (!lp) 662153790Sobrien goto fail; 662253790Sobrien if (ln) { 662353790Sobrien tp->lunmp[ln] = lp; 662453790Sobrien tp->luntbl[ln] = cpu_to_scr(vtobus(lp)); 662553790Sobrien } 662653790Sobrien else { 662753790Sobrien tp->lun0p = lp; 662859743Sgroudier tp->head.lun0_sa = cpu_to_scr(vtobus(lp)); 662953790Sobrien } 663053790Sobrien 663153790Sobrien /* 663253790Sobrien * Let the itl task point to error handling. 663353790Sobrien */ 663459743Sgroudier lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba); 663553790Sobrien 663653790Sobrien /* 663753790Sobrien * Set the reselect pattern to our default. :) 663853790Sobrien */ 663959743Sgroudier lp->head.resel_sa = cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun)); 664053790Sobrien 664153790Sobrien /* 664253790Sobrien * Set user capabilities. 664353790Sobrien */ 664453790Sobrien lp->user_flags = tp->usrflags & (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); 664553790Sobrien 664653790Sobrienfail: 664753790Sobrien return lp; 664853790Sobrien} 664953790Sobrien 665053790Sobrien/* 665153790Sobrien * Allocate LCB resources for tagged command queuing. 665253790Sobrien */ 665353790Sobrienstatic void sym_alloc_lcb_tags (hcb_p np, u_char tn, u_char ln) 665453790Sobrien{ 665553790Sobrien tcb_p tp = &np->target[tn]; 6656251572Smarius lcb_p lp = sym_lp(tp, ln); 665753790Sobrien int i; 665853790Sobrien 665953790Sobrien /* 666053790Sobrien * If LCB not available, try to allocate it. 666153790Sobrien */ 666253790Sobrien if (!lp && !(lp = sym_alloc_lcb(np, tn, ln))) 6663178466Smarius return; 666453790Sobrien 666553790Sobrien /* 6666178466Smarius * Allocate the task table and and the tag allocation 666753790Sobrien * circular buffer. We want both or none. 666853790Sobrien */ 666958927Sgroudier lp->itlq_tbl = sym_calloc_dma(SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); 667053790Sobrien if (!lp->itlq_tbl) 6671178466Smarius return; 667254690Sobrien lp->cb_tags = sym_calloc(SYM_CONF_MAX_TASK, "CB_TAGS"); 667353790Sobrien if (!lp->cb_tags) { 667458927Sgroudier sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); 667553790Sobrien lp->itlq_tbl = 0; 6676178466Smarius return; 667753790Sobrien } 667853790Sobrien 667953790Sobrien /* 668053790Sobrien * Initialize the task table with invalid entries. 668153790Sobrien */ 668254690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++) 668353790Sobrien lp->itlq_tbl[i] = cpu_to_scr(np->notask_ba); 668453790Sobrien 668553790Sobrien /* 668653790Sobrien * Fill up the tag buffer with tag numbers. 668753790Sobrien */ 668854690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++) 668953790Sobrien lp->cb_tags[i] = i; 669053790Sobrien 669153790Sobrien /* 6692178466Smarius * Make the task table available to SCRIPTS, 669353790Sobrien * And accept tagged commands now. 669453790Sobrien */ 669559743Sgroudier lp->head.itlq_tbl_sa = cpu_to_scr(vtobus(lp->itlq_tbl)); 669653790Sobrien} 669753790Sobrien 669853790Sobrien/* 669953790Sobrien * Test the pci bus snoop logic :-( 670053790Sobrien * 670153790Sobrien * Has to be called with interrupts disabled. 670253790Sobrien */ 670354690Sobrien#ifndef SYM_CONF_IOMAPPED 670453790Sobrienstatic int sym_regtest (hcb_p np) 670553790Sobrien{ 670653790Sobrien register volatile u32 data; 670753790Sobrien /* 670853790Sobrien * chip registers may NOT be cached. 670953790Sobrien * write 0xffffffff to a read only register area, 671053790Sobrien * and try to read it back. 671153790Sobrien */ 671253790Sobrien data = 0xffffffff; 671353790Sobrien OUTL_OFF(offsetof(struct sym_reg, nc_dstat), data); 671453790Sobrien data = INL_OFF(offsetof(struct sym_reg, nc_dstat)); 671553790Sobrien#if 1 671653790Sobrien if (data == 0xffffffff) { 671753790Sobrien#else 671853790Sobrien if ((data & 0xe2f0fffd) != 0x02000080) { 671953790Sobrien#endif 672053790Sobrien printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", 672153790Sobrien (unsigned) data); 672253790Sobrien return (0x10); 672353790Sobrien }; 672453790Sobrien return (0); 672553790Sobrien} 672653790Sobrien#endif 672753790Sobrien 672853790Sobrienstatic int sym_snooptest (hcb_p np) 672953790Sobrien{ 673065404Sgroudier u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat; 673153790Sobrien int i, err=0; 673254690Sobrien#ifndef SYM_CONF_IOMAPPED 673353790Sobrien err |= sym_regtest (np); 673453790Sobrien if (err) return (err); 673553790Sobrien#endif 673665404Sgroudierrestart_test: 673753790Sobrien /* 6738178466Smarius * Enable Master Parity Checking as we intend 673965404Sgroudier * to enable it for normal operations. 674065404Sgroudier */ 674165404Sgroudier OUTB (nc_ctest4, (np->rv_ctest4 & MPEE)); 674265404Sgroudier /* 674353790Sobrien * init 674453790Sobrien */ 674559292Sgroudier pc = SCRIPTB0_BA (np, snooptest); 674653790Sobrien host_wr = 1; 674753790Sobrien sym_wr = 2; 674853790Sobrien /* 674953790Sobrien * Set memory and register. 675053790Sobrien */ 675153790Sobrien np->cache = cpu_to_scr(host_wr); 675253790Sobrien OUTL (nc_temp, sym_wr); 675353790Sobrien /* 675453790Sobrien * Start script (exchange values) 675553790Sobrien */ 675658927Sgroudier OUTL (nc_dsa, np->hcb_ba); 675761429Sgroudier OUTL_DSP (pc); 675853790Sobrien /* 675953790Sobrien * Wait 'til done (with timeout) 676053790Sobrien */ 676153790Sobrien for (i=0; i<SYM_SNOOP_TIMEOUT; i++) 676253790Sobrien if (INB(nc_istat) & (INTF|SIP|DIP)) 676353790Sobrien break; 676465404Sgroudier if (i>=SYM_SNOOP_TIMEOUT) { 676565404Sgroudier printf ("CACHE TEST FAILED: timeout.\n"); 676665404Sgroudier return (0x20); 676765404Sgroudier }; 676853790Sobrien /* 676965404Sgroudier * Check for fatal DMA errors. 677065404Sgroudier */ 677165404Sgroudier dstat = INB (nc_dstat); 677265404Sgroudier#if 1 /* Band aiding for broken hardwares that fail PCI parity */ 677365404Sgroudier if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) { 677465404Sgroudier printf ("%s: PCI DATA PARITY ERROR DETECTED - " 677565404Sgroudier "DISABLING MASTER DATA PARITY CHECKING.\n", 677665404Sgroudier sym_name(np)); 677765404Sgroudier np->rv_ctest4 &= ~MPEE; 677865404Sgroudier goto restart_test; 677965404Sgroudier } 678065404Sgroudier#endif 678165404Sgroudier if (dstat & (MDPE|BF|IID)) { 678265404Sgroudier printf ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat); 678365404Sgroudier return (0x80); 678465404Sgroudier } 678565404Sgroudier /* 678653790Sobrien * Save termination position. 678753790Sobrien */ 678853790Sobrien pc = INL (nc_dsp); 678953790Sobrien /* 679053790Sobrien * Read memory and register. 679153790Sobrien */ 679253790Sobrien host_rd = scr_to_cpu(np->cache); 679353790Sobrien sym_rd = INL (nc_scratcha); 679453790Sobrien sym_bk = INL (nc_temp); 679553790Sobrien 679653790Sobrien /* 679753790Sobrien * Check termination position. 679853790Sobrien */ 679959292Sgroudier if (pc != SCRIPTB0_BA (np, snoopend)+8) { 680053790Sobrien printf ("CACHE TEST FAILED: script execution failed.\n"); 6801178466Smarius printf ("start=%08lx, pc=%08lx, end=%08lx\n", 680259292Sgroudier (u_long) SCRIPTB0_BA (np, snooptest), (u_long) pc, 680359292Sgroudier (u_long) SCRIPTB0_BA (np, snoopend) +8); 680453790Sobrien return (0x40); 680553790Sobrien }; 680653790Sobrien /* 680753790Sobrien * Show results. 680853790Sobrien */ 680953790Sobrien if (host_wr != sym_rd) { 681053790Sobrien printf ("CACHE TEST FAILED: host wrote %d, chip read %d.\n", 681153790Sobrien (int) host_wr, (int) sym_rd); 681253790Sobrien err |= 1; 681353790Sobrien }; 681453790Sobrien if (host_rd != sym_wr) { 681553790Sobrien printf ("CACHE TEST FAILED: chip wrote %d, host read %d.\n", 681653790Sobrien (int) sym_wr, (int) host_rd); 681753790Sobrien err |= 2; 681853790Sobrien }; 681953790Sobrien if (sym_bk != sym_wr) { 682053790Sobrien printf ("CACHE TEST FAILED: chip wrote %d, read back %d.\n", 682153790Sobrien (int) sym_wr, (int) sym_bk); 682253790Sobrien err |= 4; 682353790Sobrien }; 682459743Sgroudier 682553790Sobrien return (err); 682653790Sobrien} 682753790Sobrien 682853790Sobrien/* 682953790Sobrien * Determine the chip's clock frequency. 683053790Sobrien * 6831178466Smarius * This is essential for the negotiation of the synchronous 683253790Sobrien * transfer rate. 683353790Sobrien * 683453790Sobrien * Note: we have to return the correct value. 683553790Sobrien * THERE IS NO SAFE DEFAULT VALUE. 683653790Sobrien * 683753790Sobrien * Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. 6838178466Smarius * 53C860 and 53C875 rev. 1 support fast20 transfers but 6839178466Smarius * do not have a clock doubler and so are provided with a 6840178466Smarius * 80 MHz clock. All other fast20 boards incorporate a doubler 684153790Sobrien * and so should be delivered with a 40 MHz clock. 6842178466Smarius * The recent fast40 chips (895/896/895A/1010) use a 40 Mhz base 684353790Sobrien * clock and provide a clock quadrupler (160 Mhz). 684453790Sobrien */ 684553790Sobrien 684653790Sobrien/* 684753790Sobrien * Select SCSI clock frequency 684853790Sobrien */ 684953790Sobrienstatic void sym_selectclock(hcb_p np, u_char scntl3) 685053790Sobrien{ 685153790Sobrien /* 685253790Sobrien * If multiplier not present or not selected, leave here. 685353790Sobrien */ 685453790Sobrien if (np->multiplier <= 1) { 685553790Sobrien OUTB(nc_scntl3, scntl3); 685653790Sobrien return; 685753790Sobrien } 685853790Sobrien 685953790Sobrien if (sym_verbose >= 2) 686053790Sobrien printf ("%s: enabling clock multiplier\n", sym_name(np)); 686153790Sobrien 686253790Sobrien OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ 686353790Sobrien /* 686453790Sobrien * Wait for the LCKFRQ bit to be set if supported by the chip. 686553790Sobrien * Otherwise wait 20 micro-seconds. 686653790Sobrien */ 686753790Sobrien if (np->features & FE_LCKFRQ) { 686853790Sobrien int i = 20; 686953790Sobrien while (!(INB(nc_stest4) & LCKFRQ) && --i > 0) 687053790Sobrien UDELAY (20); 687153790Sobrien if (!i) 687253790Sobrien printf("%s: the chip cannot lock the frequency\n", 687353790Sobrien sym_name(np)); 687453790Sobrien } else 687553790Sobrien UDELAY (20); 687653790Sobrien OUTB(nc_stest3, HSC); /* Halt the scsi clock */ 687753790Sobrien OUTB(nc_scntl3, scntl3); 687853790Sobrien OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ 687953790Sobrien OUTB(nc_stest3, 0x00); /* Restart scsi clock */ 688053790Sobrien} 688153790Sobrien 688253790Sobrien/* 688353790Sobrien * calculate SCSI clock frequency (in KHz) 688453790Sobrien */ 688553790Sobrienstatic unsigned getfreq (hcb_p np, int gen) 688653790Sobrien{ 688753790Sobrien unsigned int ms = 0; 688853790Sobrien unsigned int f; 688953790Sobrien 689053790Sobrien /* 6891178466Smarius * Measure GEN timer delay in order 689253790Sobrien * to calculate SCSI clock frequency 689353790Sobrien * 689453790Sobrien * This code will never execute too 6895178466Smarius * many loop iterations (if DELAY is 689653790Sobrien * reasonably correct). It could get 689753790Sobrien * too low a delay (too high a freq.) 6898178466Smarius * if the CPU is slow executing the 689953790Sobrien * loop for some reason (an NMI, for 690053790Sobrien * example). For this reason we will 6901178466Smarius * if multiple measurements are to be 6902178466Smarius * performed trust the higher delay 690353790Sobrien * (lower frequency returned). 690453790Sobrien */ 690553790Sobrien OUTW (nc_sien , 0); /* mask all scsi interrupts */ 690653790Sobrien (void) INW (nc_sist); /* clear pending scsi interrupt */ 690753790Sobrien OUTB (nc_dien , 0); /* mask all dma interrupts */ 690853790Sobrien (void) INW (nc_sist); /* another one, just to be sure :) */ 690953790Sobrien OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */ 691053790Sobrien OUTB (nc_stime1, 0); /* disable general purpose timer */ 691153790Sobrien OUTB (nc_stime1, gen); /* set to nominal delay of 1<<gen * 125us */ 691253790Sobrien while (!(INW(nc_sist) & GEN) && ms++ < 100000) 691353790Sobrien UDELAY (1000); /* count ms */ 691453790Sobrien OUTB (nc_stime1, 0); /* disable general purpose timer */ 691553790Sobrien /* 691653790Sobrien * set prescaler to divide by whatever 0 means 691753790Sobrien * 0 ought to choose divide by 2, but appears 691853790Sobrien * to set divide by 3.5 mode in my 53c810 ... 691953790Sobrien */ 692053790Sobrien OUTB (nc_scntl3, 0); 692153790Sobrien 692253790Sobrien /* 6923178466Smarius * adjust for prescaler, and convert into KHz 692453790Sobrien */ 692553790Sobrien f = ms ? ((1 << gen) * 4340) / ms : 0; 692653790Sobrien 692753790Sobrien if (sym_verbose >= 2) 692853790Sobrien printf ("%s: Delay (GEN=%d): %u msec, %u KHz\n", 692953790Sobrien sym_name(np), gen, ms, f); 693053790Sobrien 693153790Sobrien return f; 693253790Sobrien} 693353790Sobrien 693453790Sobrienstatic unsigned sym_getfreq (hcb_p np) 693553790Sobrien{ 693653790Sobrien u_int f1, f2; 693753790Sobrien int gen = 11; 693853790Sobrien 693953790Sobrien (void) getfreq (np, gen); /* throw away first result */ 694053790Sobrien f1 = getfreq (np, gen); 694153790Sobrien f2 = getfreq (np, gen); 694253790Sobrien if (f1 > f2) f1 = f2; /* trust lower result */ 694353790Sobrien return f1; 694453790Sobrien} 694553790Sobrien 694653790Sobrien/* 694753790Sobrien * Get/probe chip SCSI clock frequency 694853790Sobrien */ 694953790Sobrienstatic void sym_getclock (hcb_p np, int mult) 695053790Sobrien{ 695153796Sobrien unsigned char scntl3 = np->sv_scntl3; 695253796Sobrien unsigned char stest1 = np->sv_stest1; 695353790Sobrien unsigned f1; 695453790Sobrien 695553790Sobrien /* 695653790Sobrien * For the C10 core, assume 40 MHz. 695753790Sobrien */ 695853790Sobrien if (np->features & FE_C10) { 695953790Sobrien np->multiplier = mult; 696053790Sobrien np->clock_khz = 40000 * mult; 696153790Sobrien return; 696253790Sobrien } 696353790Sobrien 696453790Sobrien np->multiplier = 1; 696553790Sobrien f1 = 40000; 696653790Sobrien /* 696753790Sobrien * True with 875/895/896/895A with clock multiplier selected 696853790Sobrien */ 696953790Sobrien if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { 697053790Sobrien if (sym_verbose >= 2) 697153790Sobrien printf ("%s: clock multiplier found\n", sym_name(np)); 697253790Sobrien np->multiplier = mult; 697353790Sobrien } 697453790Sobrien 697553790Sobrien /* 697653790Sobrien * If multiplier not found or scntl3 not 7,5,3, 697753790Sobrien * reset chip and get frequency from general purpose timer. 697853790Sobrien * Otherwise trust scntl3 BIOS setting. 697953790Sobrien */ 698053790Sobrien if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { 698153790Sobrien OUTB (nc_stest1, 0); /* make sure doubler is OFF */ 698253790Sobrien f1 = sym_getfreq (np); 698353790Sobrien 698453790Sobrien if (sym_verbose) 698553790Sobrien printf ("%s: chip clock is %uKHz\n", sym_name(np), f1); 698653790Sobrien 698753790Sobrien if (f1 < 45000) f1 = 40000; 698853790Sobrien else if (f1 < 55000) f1 = 50000; 698953790Sobrien else f1 = 80000; 699053790Sobrien 699153790Sobrien if (f1 < 80000 && mult > 1) { 699253790Sobrien if (sym_verbose >= 2) 699353790Sobrien printf ("%s: clock multiplier assumed\n", 699453790Sobrien sym_name(np)); 699553790Sobrien np->multiplier = mult; 699653790Sobrien } 699753790Sobrien } else { 699853790Sobrien if ((scntl3 & 7) == 3) f1 = 40000; 699953790Sobrien else if ((scntl3 & 7) == 5) f1 = 80000; 700053790Sobrien else f1 = 160000; 700153790Sobrien 700253790Sobrien f1 /= np->multiplier; 700353790Sobrien } 700453790Sobrien 700553790Sobrien /* 700653790Sobrien * Compute controller synchronous parameters. 700753790Sobrien */ 700853790Sobrien f1 *= np->multiplier; 700953790Sobrien np->clock_khz = f1; 701053790Sobrien} 701153790Sobrien 701253790Sobrien/* 701353790Sobrien * Get/probe PCI clock frequency 701453790Sobrien */ 701553790Sobrienstatic int sym_getpciclock (hcb_p np) 701653790Sobrien{ 701761051Sgroudier int f = 0; 701853790Sobrien 701961051Sgroudier /* 702061051Sgroudier * For the C1010-33, this doesn't work. 7021178466Smarius * For the C1010-66, this will be tested when I'll have 702261051Sgroudier * such a beast to play with. 702361051Sgroudier */ 702461051Sgroudier if (!(np->features & FE_C10)) { 702553790Sobrien OUTB (nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */ 702653790Sobrien f = (int) sym_getfreq (np); 702753790Sobrien OUTB (nc_stest1, 0); 702853790Sobrien } 702961051Sgroudier np->pciclk_khz = f; 703061051Sgroudier 703153790Sobrien return f; 703253790Sobrien} 703353790Sobrien 703453790Sobrien/*============= DRIVER ACTION/COMPLETION ====================*/ 703553790Sobrien 703653790Sobrien/* 703753790Sobrien * Print something that tells about extended errors. 703853790Sobrien */ 703953790Sobrienstatic void sym_print_xerr(ccb_p cp, int x_status) 704053790Sobrien{ 704153790Sobrien if (x_status & XE_PARITY_ERR) { 704253790Sobrien PRINT_ADDR(cp); 704353790Sobrien printf ("unrecovered SCSI parity error.\n"); 704453790Sobrien } 704553790Sobrien if (x_status & XE_EXTRA_DATA) { 704653790Sobrien PRINT_ADDR(cp); 704753790Sobrien printf ("extraneous data discarded.\n"); 704853790Sobrien } 704953790Sobrien if (x_status & XE_BAD_PHASE) { 705053790Sobrien PRINT_ADDR(cp); 705153790Sobrien printf ("illegal scsi phase (4/5).\n"); 705253790Sobrien } 705353790Sobrien if (x_status & XE_SODL_UNRUN) { 705453790Sobrien PRINT_ADDR(cp); 705553790Sobrien printf ("ODD transfer in DATA OUT phase.\n"); 705653790Sobrien } 705753790Sobrien if (x_status & XE_SWIDE_OVRUN) { 705853790Sobrien PRINT_ADDR(cp); 705953790Sobrien printf ("ODD transfer in DATA IN phase.\n"); 706053790Sobrien } 706153790Sobrien} 706253790Sobrien 706353790Sobrien/* 7064178466Smarius * Choose the more appropriate CAM status if 706553790Sobrien * the IO encountered an extended error. 706653790Sobrien */ 706753790Sobrienstatic int sym_xerr_cam_status(int cam_status, int x_status) 706853790Sobrien{ 706953790Sobrien if (x_status) { 707053790Sobrien if (x_status & XE_PARITY_ERR) 707153790Sobrien cam_status = CAM_UNCOR_PARITY; 707253790Sobrien else if (x_status &(XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) 707353790Sobrien cam_status = CAM_DATA_RUN_ERR; 707453790Sobrien else if (x_status & XE_BAD_PHASE) 707553790Sobrien cam_status = CAM_REQ_CMP_ERR; 707653790Sobrien else 707753790Sobrien cam_status = CAM_REQ_CMP_ERR; 707853790Sobrien } 707953790Sobrien return cam_status; 708053790Sobrien} 708153790Sobrien 708253790Sobrien/* 7083178466Smarius * Complete execution of a SCSI command with extented 708453790Sobrien * error, SCSI status error, or having been auto-sensed. 708553790Sobrien * 7086178466Smarius * The SCRIPTS processor is not running there, so we 7087178466Smarius * can safely access IO registers and remove JOBs from 708853790Sobrien * the START queue. 7089178466Smarius * SCRATCHA is assumed to have been loaded with STARTPOS 709053790Sobrien * before the SCRIPTS called the C code. 709153790Sobrien */ 709253790Sobrienstatic void sym_complete_error (hcb_p np, ccb_p cp) 709353790Sobrien{ 709453790Sobrien struct ccb_scsiio *csio; 709553790Sobrien u_int cam_status; 7096226288Smarius int i, sense_returned; 709753790Sobrien 7098178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7099178468Smarius 710053790Sobrien /* 710153790Sobrien * Paranoid check. :) 710253790Sobrien */ 710353790Sobrien if (!cp || !cp->cam_ccb) 710453790Sobrien return; 710553790Sobrien 710653790Sobrien if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_RESULT)) { 710753790Sobrien printf ("CCB=%lx STAT=%x/%x/%x DEV=%d/%d\n", (unsigned long)cp, 710853790Sobrien cp->host_status, cp->ssss_status, cp->host_flags, 710953790Sobrien cp->target, cp->lun); 711053790Sobrien MDELAY(100); 711153790Sobrien } 711253790Sobrien 711353790Sobrien /* 711462422Sgroudier * Get CAM command pointer. 711553790Sobrien */ 711653790Sobrien csio = &cp->cam_ccb->csio; 711753790Sobrien 711853790Sobrien /* 711953790Sobrien * Check for extended errors. 712053790Sobrien */ 712153790Sobrien if (cp->xerr_status) { 712253790Sobrien if (sym_verbose) 712353790Sobrien sym_print_xerr(cp, cp->xerr_status); 712453790Sobrien if (cp->host_status == HS_COMPLETE) 712553790Sobrien cp->host_status = HS_COMP_ERR; 712653790Sobrien } 712753790Sobrien 712853790Sobrien /* 712953790Sobrien * Calculate the residual. 713053790Sobrien */ 713153790Sobrien csio->sense_resid = 0; 713253790Sobrien csio->resid = sym_compute_residual(np, cp); 713353790Sobrien 713454690Sobrien if (!SYM_CONF_RESIDUAL_SUPPORT) {/* If user does not want residuals */ 713553790Sobrien csio->resid = 0; /* throw them away. :) */ 713653790Sobrien cp->sv_resid = 0; 713753790Sobrien } 713853790Sobrien 713953790Sobrien if (cp->host_flags & HF_SENSE) { /* Auto sense */ 714053790Sobrien csio->scsi_status = cp->sv_scsi_status; /* Restore status */ 714153790Sobrien csio->sense_resid = csio->resid; /* Swap residuals */ 714253790Sobrien csio->resid = cp->sv_resid; 714353790Sobrien cp->sv_resid = 0; 714453790Sobrien if (sym_verbose && cp->sv_xerr_status) 714553790Sobrien sym_print_xerr(cp, cp->sv_xerr_status); 714653790Sobrien if (cp->host_status == HS_COMPLETE && 714753790Sobrien cp->ssss_status == S_GOOD && 714853790Sobrien cp->xerr_status == 0) { 714953790Sobrien cam_status = sym_xerr_cam_status(CAM_SCSI_STATUS_ERROR, 715053790Sobrien cp->sv_xerr_status); 715153790Sobrien cam_status |= CAM_AUTOSNS_VALID; 715258927Sgroudier /* 7153178466Smarius * Bounce back the sense data to user and 715458927Sgroudier * fix the residual. 715558927Sgroudier */ 7156226288Smarius bzero(&csio->sense_data, sizeof(csio->sense_data)); 7157226288Smarius sense_returned = SYM_SNS_BBUF_LEN - csio->sense_resid; 7158226288Smarius if (sense_returned < csio->sense_len) 7159226288Smarius csio->sense_resid = csio->sense_len - 7160226288Smarius sense_returned; 7161226288Smarius else 7162226288Smarius csio->sense_resid = 0; 716358927Sgroudier bcopy(cp->sns_bbuf, &csio->sense_data, 7164226288Smarius MIN(csio->sense_len, sense_returned)); 716553790Sobrien#if 0 716653790Sobrien /* 7167178466Smarius * If the device reports a UNIT ATTENTION condition 7168178466Smarius * due to a RESET condition, we should consider all 716953790Sobrien * disconnect CCBs for this unit as aborted. 717053790Sobrien */ 717153790Sobrien if (1) { 717253790Sobrien u_char *p; 717358927Sgroudier p = (u_char *) csio->sense_data; 717453790Sobrien if (p[0]==0x70 && p[2]==0x6 && p[12]==0x29) 717553790Sobrien sym_clear_tasks(np, CAM_REQ_ABORTED, 717653790Sobrien cp->target,cp->lun, -1); 717753790Sobrien } 717853790Sobrien#endif 717953790Sobrien } 718053790Sobrien else 718153790Sobrien cam_status = CAM_AUTOSENSE_FAIL; 718253790Sobrien } 718353790Sobrien else if (cp->host_status == HS_COMPLETE) { /* Bad SCSI status */ 718453790Sobrien csio->scsi_status = cp->ssss_status; 718553790Sobrien cam_status = CAM_SCSI_STATUS_ERROR; 718653790Sobrien } 718753790Sobrien else if (cp->host_status == HS_SEL_TIMEOUT) /* Selection timeout */ 718853790Sobrien cam_status = CAM_SEL_TIMEOUT; 718953790Sobrien else if (cp->host_status == HS_UNEXPECTED) /* Unexpected BUS FREE*/ 719053790Sobrien cam_status = CAM_UNEXP_BUSFREE; 719153790Sobrien else { /* Extended error */ 719253790Sobrien if (sym_verbose) { 719353790Sobrien PRINT_ADDR(cp); 719453790Sobrien printf ("COMMAND FAILED (%x %x %x).\n", 719553790Sobrien cp->host_status, cp->ssss_status, 719653790Sobrien cp->xerr_status); 719753790Sobrien } 719853790Sobrien csio->scsi_status = cp->ssss_status; 719953790Sobrien /* 720053790Sobrien * Set the most appropriate value for CAM status. 720153790Sobrien */ 720253790Sobrien cam_status = sym_xerr_cam_status(CAM_REQ_CMP_ERR, 720353790Sobrien cp->xerr_status); 720453790Sobrien } 720553790Sobrien 720653790Sobrien /* 7207178466Smarius * Dequeue all queued CCBs for that device 720853790Sobrien * not yet started by SCRIPTS. 720953790Sobrien */ 721058927Sgroudier i = (INL (nc_scratcha) - np->squeue_ba) / 4; 721153790Sobrien (void) sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); 721253790Sobrien 721353790Sobrien /* 721453790Sobrien * Restart the SCRIPTS processor. 721553790Sobrien */ 721661429Sgroudier OUTL_DSP (SCRIPTA_BA (np, start)); 721753790Sobrien 721853790Sobrien /* 721958927Sgroudier * Synchronize DMA map if needed. 722058927Sgroudier */ 722158927Sgroudier if (cp->dmamapped) { 722258927Sgroudier bus_dmamap_sync(np->data_dmat, cp->dmamap, 7223178466Smarius (cp->dmamapped == SYM_DMA_READ ? 722458927Sgroudier BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE)); 722558927Sgroudier } 722658927Sgroudier /* 722753790Sobrien * Add this one to the COMP queue. 7228178466Smarius * Complete all those commands with either error 722953790Sobrien * or requeue condition. 723053790Sobrien */ 723153790Sobrien sym_set_cam_status((union ccb *) csio, cam_status); 723253790Sobrien sym_remque(&cp->link_ccbq); 723353790Sobrien sym_insque_head(&cp->link_ccbq, &np->comp_ccbq); 723453790Sobrien sym_flush_comp_queue(np, 0); 723553790Sobrien} 723653790Sobrien 723753790Sobrien/* 723853790Sobrien * Complete execution of a successful SCSI command. 723953790Sobrien * 7240178466Smarius * Only successful commands go to the DONE queue, 7241178466Smarius * since we need to have the SCRIPTS processor 724253790Sobrien * stopped on any error condition. 7243178466Smarius * The SCRIPTS processor is running while we are 724453790Sobrien * completing successful commands. 724553790Sobrien */ 724653790Sobrienstatic void sym_complete_ok (hcb_p np, ccb_p cp) 724753790Sobrien{ 724853790Sobrien struct ccb_scsiio *csio; 724953790Sobrien tcb_p tp; 725053790Sobrien lcb_p lp; 725153790Sobrien 7252178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7253178468Smarius 725453790Sobrien /* 725553790Sobrien * Paranoid check. :) 725653790Sobrien */ 725753790Sobrien if (!cp || !cp->cam_ccb) 725853790Sobrien return; 725953790Sobrien assert (cp->host_status == HS_COMPLETE); 726053790Sobrien 726153790Sobrien /* 726253790Sobrien * Get command, target and lun pointers. 726353790Sobrien */ 726453790Sobrien csio = &cp->cam_ccb->csio; 726553790Sobrien tp = &np->target[cp->target]; 7266251572Smarius lp = sym_lp(tp, cp->lun); 726753790Sobrien 726853790Sobrien /* 726953790Sobrien * Assume device discovered on first success. 727053790Sobrien */ 727153790Sobrien if (!lp) 727253790Sobrien sym_set_bit(tp->lun_map, cp->lun); 727353790Sobrien 727453790Sobrien /* 727553790Sobrien * If all data have been transferred, given than no 727653790Sobrien * extended error did occur, there is no residual. 727753790Sobrien */ 727853790Sobrien csio->resid = 0; 727959743Sgroudier if (cp->phys.head.lastp != cp->phys.head.goalp) 728053790Sobrien csio->resid = sym_compute_residual(np, cp); 728153790Sobrien 728253790Sobrien /* 7283178466Smarius * Wrong transfer residuals may be worse than just always 7284178466Smarius * returning zero. User can disable this feature from 728553790Sobrien * sym_conf.h. Residual support is enabled by default. 728653790Sobrien */ 728754690Sobrien if (!SYM_CONF_RESIDUAL_SUPPORT) 728853790Sobrien csio->resid = 0; 728953790Sobrien 729053790Sobrien /* 729158927Sgroudier * Synchronize DMA map if needed. 729258927Sgroudier */ 729358927Sgroudier if (cp->dmamapped) { 729458927Sgroudier bus_dmamap_sync(np->data_dmat, cp->dmamap, 7295178466Smarius (cp->dmamapped == SYM_DMA_READ ? 729658927Sgroudier BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE)); 729758927Sgroudier } 729858927Sgroudier /* 729953790Sobrien * Set status and complete the command. 730053790Sobrien */ 730153790Sobrien csio->scsi_status = cp->ssss_status; 730253790Sobrien sym_set_cam_status((union ccb *) csio, CAM_REQ_CMP); 7303178468Smarius sym_xpt_done(np, (union ccb *) csio, cp); 7304178468Smarius sym_free_ccb(np, cp); 730553790Sobrien} 730653790Sobrien 730753790Sobrien/* 7308178468Smarius * Our callout handler 730953790Sobrien */ 7310178468Smariusstatic void sym_callout(void *arg) 731153790Sobrien{ 731253790Sobrien union ccb *ccb = (union ccb *) arg; 731353790Sobrien hcb_p np = ccb->ccb_h.sym_hcb_ptr; 731453790Sobrien 731553790Sobrien /* 731653790Sobrien * Check that the CAM CCB is still queued. 731753790Sobrien */ 731853790Sobrien if (!np) 731953790Sobrien return; 732053790Sobrien 7321178468Smarius SYM_LOCK(); 7322178468Smarius 732353790Sobrien switch(ccb->ccb_h.func_code) { 732453790Sobrien case XPT_SCSI_IO: 732553790Sobrien (void) sym_abort_scsiio(np, ccb, 1); 732653790Sobrien break; 732753790Sobrien default: 732853790Sobrien break; 732953790Sobrien } 733053790Sobrien 7331178468Smarius SYM_UNLOCK(); 733253790Sobrien} 733353790Sobrien 733453790Sobrien/* 733553790Sobrien * Abort an SCSI IO. 733653790Sobrien */ 733753790Sobrienstatic int sym_abort_scsiio(hcb_p np, union ccb *ccb, int timed_out) 733853790Sobrien{ 733953790Sobrien ccb_p cp; 734055300Sgroudier SYM_QUEHEAD *qp; 734153790Sobrien 7342178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7343178468Smarius 734453790Sobrien /* 734553790Sobrien * Look up our CCB control block. 734653790Sobrien */ 7347178466Smarius cp = NULL; 734855300Sgroudier FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 734955300Sgroudier ccb_p cp2 = sym_que_entry(qp, struct sym_ccb, link_ccbq); 735055300Sgroudier if (cp2->cam_ccb == ccb) { 735155300Sgroudier cp = cp2; 735253790Sobrien break; 735355300Sgroudier } 735453790Sobrien } 735558927Sgroudier if (!cp || cp->host_status == HS_WAIT) 735653790Sobrien return -1; 735753790Sobrien 735853790Sobrien /* 735953790Sobrien * If a previous abort didn't succeed in time, 736053790Sobrien * perform a BUS reset. 736153790Sobrien */ 736253790Sobrien if (cp->to_abort) { 736353790Sobrien sym_reset_scsi_bus(np, 1); 736453790Sobrien return 0; 736553790Sobrien } 736653790Sobrien 736753790Sobrien /* 736853790Sobrien * Mark the CCB for abort and allow time for. 736953790Sobrien */ 737053790Sobrien cp->to_abort = timed_out ? 2 : 1; 7371178468Smarius callout_reset(&cp->ch, 10 * hz, sym_callout, (caddr_t) ccb); 737253790Sobrien 737353790Sobrien /* 737453790Sobrien * Tell the SCRIPTS processor to stop and synchronize with us. 737553790Sobrien */ 737653790Sobrien np->istat_sem = SEM; 737753790Sobrien OUTB (nc_istat, SIGP|SEM); 737853790Sobrien return 0; 737953790Sobrien} 738053790Sobrien 738153790Sobrien/* 738253790Sobrien * Reset a SCSI device (all LUNs of a target). 738353790Sobrien */ 738453790Sobrienstatic void sym_reset_dev(hcb_p np, union ccb *ccb) 738553790Sobrien{ 738653790Sobrien tcb_p tp; 738753790Sobrien struct ccb_hdr *ccb_h = &ccb->ccb_h; 738853790Sobrien 7389178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7390178468Smarius 739153790Sobrien if (ccb_h->target_id == np->myaddr || 739254690Sobrien ccb_h->target_id >= SYM_CONF_MAX_TARGET || 739354690Sobrien ccb_h->target_lun >= SYM_CONF_MAX_LUN) { 739453790Sobrien sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE); 739553790Sobrien return; 739653790Sobrien } 739753790Sobrien 739853790Sobrien tp = &np->target[ccb_h->target_id]; 739953790Sobrien 740053790Sobrien tp->to_reset = 1; 740153790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 740253790Sobrien 740353790Sobrien np->istat_sem = SEM; 740453790Sobrien OUTB (nc_istat, SIGP|SEM); 740553790Sobrien} 740653790Sobrien 740753790Sobrien/* 740853790Sobrien * SIM action entry point. 740953790Sobrien */ 741053790Sobrienstatic void sym_action(struct cam_sim *sim, union ccb *ccb) 741153790Sobrien{ 741253790Sobrien hcb_p np; 741353790Sobrien tcb_p tp; 741453790Sobrien lcb_p lp; 741553790Sobrien ccb_p cp; 741653790Sobrien int tmp; 741753790Sobrien u_char idmsg, *msgptr; 741853790Sobrien u_int msglen; 741953790Sobrien struct ccb_scsiio *csio; 742053790Sobrien struct ccb_hdr *ccb_h; 742153790Sobrien 742253790Sobrien CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("sym_action\n")); 742353790Sobrien 742453790Sobrien /* 742553790Sobrien * Retrieve our controller data structure. 742653790Sobrien */ 742753790Sobrien np = (hcb_p) cam_sim_softc(sim); 742853790Sobrien 7429178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7430178468Smarius 743153790Sobrien /* 743253790Sobrien * The common case is SCSI IO. 743353790Sobrien * We deal with other ones elsewhere. 743453790Sobrien */ 743553790Sobrien if (ccb->ccb_h.func_code != XPT_SCSI_IO) { 743653790Sobrien sym_action2(sim, ccb); 743753790Sobrien return; 743853790Sobrien } 743953790Sobrien csio = &ccb->csio; 744053790Sobrien ccb_h = &csio->ccb_h; 744153790Sobrien 744253790Sobrien /* 744353790Sobrien * Work around races. 744453790Sobrien */ 744553790Sobrien if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 744653790Sobrien xpt_done(ccb); 744753790Sobrien return; 744853790Sobrien } 744953790Sobrien 745053790Sobrien /* 7451178466Smarius * Minimal checkings, so that we will not 745253790Sobrien * go outside our tables. 745353790Sobrien */ 745453790Sobrien if (ccb_h->target_id == np->myaddr || 745554690Sobrien ccb_h->target_id >= SYM_CONF_MAX_TARGET || 745654690Sobrien ccb_h->target_lun >= SYM_CONF_MAX_LUN) { 745753790Sobrien sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE); 745853790Sobrien return; 745953790Sobrien } 746053790Sobrien 746153790Sobrien /* 7462220944Smarius * Retrieve the target and lun descriptors. 746353790Sobrien */ 746453790Sobrien tp = &np->target[ccb_h->target_id]; 7465251572Smarius lp = sym_lp(tp, ccb_h->target_lun); 746653790Sobrien 746753790Sobrien /* 7468178466Smarius * Complete the 1st INQUIRY command with error 7469178466Smarius * condition if the device is flagged NOSCAN 7470178466Smarius * at BOOT in the NVRAM. This may speed up 7471178466Smarius * the boot and maintain coherency with BIOS 7472178466Smarius * device numbering. Clearing the flag allows 747353790Sobrien * user to rescan skipped devices later. 7474178466Smarius * We also return error for devices not flagged 7475178466Smarius * for SCAN LUNS in the NVRAM since some mono-lun 7476178466Smarius * devices behave badly when asked for some non 747753790Sobrien * zero LUN. Btw, this is an absolute hack.:-) 747853790Sobrien */ 747953790Sobrien if (!(ccb_h->flags & CAM_CDB_PHYS) && 748053790Sobrien (0x12 == ((ccb_h->flags & CAM_CDB_POINTER) ? 748153790Sobrien csio->cdb_io.cdb_ptr[0] : csio->cdb_io.cdb_bytes[0]))) { 748253790Sobrien if ((tp->usrflags & SYM_SCAN_BOOT_DISABLED) || 7483178466Smarius ((tp->usrflags & SYM_SCAN_LUNS_DISABLED) && 748453790Sobrien ccb_h->target_lun != 0)) { 748553790Sobrien tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED; 748653790Sobrien sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE); 748753790Sobrien return; 748853790Sobrien } 748953790Sobrien } 749053790Sobrien 749153790Sobrien /* 749253790Sobrien * Get a control block for this IO. 749353790Sobrien */ 749453790Sobrien tmp = ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0); 749553790Sobrien cp = sym_get_ccb(np, ccb_h->target_id, ccb_h->target_lun, tmp); 749653790Sobrien if (!cp) { 749753790Sobrien sym_xpt_done2(np, ccb, CAM_RESRC_UNAVAIL); 749853790Sobrien return; 749953790Sobrien } 750053790Sobrien 750153790Sobrien /* 750258927Sgroudier * Keep track of the IO in our CCB. 750353790Sobrien */ 750453790Sobrien cp->cam_ccb = ccb; 750553790Sobrien 750653790Sobrien /* 750753790Sobrien * Build the IDENTIFY message. 750853790Sobrien */ 750953790Sobrien idmsg = M_IDENTIFY | cp->lun; 751053790Sobrien if (cp->tag != NO_TAG || (lp && (lp->current_flags & SYM_DISC_ENABLED))) 751153790Sobrien idmsg |= 0x40; 751253790Sobrien 751353790Sobrien msgptr = cp->scsi_smsg; 751453790Sobrien msglen = 0; 751553790Sobrien msgptr[msglen++] = idmsg; 751653790Sobrien 751753790Sobrien /* 751853790Sobrien * Build the tag message if present. 751953790Sobrien */ 752053790Sobrien if (cp->tag != NO_TAG) { 752153790Sobrien u_char order = csio->tag_action; 752253790Sobrien 752353790Sobrien switch(order) { 752453790Sobrien case M_ORDERED_TAG: 752553790Sobrien break; 752653790Sobrien case M_HEAD_TAG: 752753790Sobrien break; 752853790Sobrien default: 752953790Sobrien order = M_SIMPLE_TAG; 753053790Sobrien } 753153790Sobrien msgptr[msglen++] = order; 753253790Sobrien 753353790Sobrien /* 7534178466Smarius * For less than 128 tags, actual tags are numbered 7535178466Smarius * 1,3,5,..2*MAXTAGS+1,since we may have to deal 7536178466Smarius * with devices that have problems with #TAG 0 or too 7537178466Smarius * great #TAG numbers. For more tags (up to 256), 753853790Sobrien * we use directly our tag number. 753953790Sobrien */ 754054690Sobrien#if SYM_CONF_MAX_TASK > (512/4) 754153790Sobrien msgptr[msglen++] = cp->tag; 754253790Sobrien#else 754353790Sobrien msgptr[msglen++] = (cp->tag << 1) + 1; 754453790Sobrien#endif 754553790Sobrien } 754653790Sobrien 754753790Sobrien /* 754853790Sobrien * Build a negotiation message if needed. 754953790Sobrien * (nego_status is filled by sym_prepare_nego()) 755053790Sobrien */ 755153790Sobrien cp->nego_status = 0; 755253790Sobrien if (tp->tinfo.current.width != tp->tinfo.goal.width || 755353790Sobrien tp->tinfo.current.period != tp->tinfo.goal.period || 755453790Sobrien tp->tinfo.current.offset != tp->tinfo.goal.offset || 755553790Sobrien tp->tinfo.current.options != tp->tinfo.goal.options) { 755653790Sobrien if (!tp->nego_cp && lp) 755753790Sobrien msglen += sym_prepare_nego(np, cp, 0, msgptr + msglen); 755853790Sobrien } 755953790Sobrien 756053790Sobrien /* 756153790Sobrien * Fill in our ccb 756253790Sobrien */ 756353790Sobrien 756453790Sobrien /* 756553790Sobrien * Startqueue 756653790Sobrien */ 756759743Sgroudier cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, select)); 756859743Sgroudier cp->phys.head.go.restart = cpu_to_scr(SCRIPTA_BA (np, resel_dsa)); 756953790Sobrien 757053790Sobrien /* 757153790Sobrien * select 757253790Sobrien */ 757353790Sobrien cp->phys.select.sel_id = cp->target; 757459743Sgroudier cp->phys.select.sel_scntl3 = tp->head.wval; 757559743Sgroudier cp->phys.select.sel_sxfer = tp->head.sval; 757659743Sgroudier cp->phys.select.sel_scntl4 = tp->head.uval; 757753790Sobrien 757853790Sobrien /* 757953790Sobrien * message 758053790Sobrien */ 758158927Sgroudier cp->phys.smsg.addr = cpu_to_scr(CCB_BA (cp, scsi_smsg)); 758253790Sobrien cp->phys.smsg.size = cpu_to_scr(msglen); 758353790Sobrien 758453790Sobrien /* 758553790Sobrien * command 758653790Sobrien */ 758753790Sobrien if (sym_setup_cdb(np, csio, cp) < 0) { 7588178468Smarius sym_xpt_done(np, ccb, cp); 758953790Sobrien sym_free_ccb(np, cp); 759053790Sobrien return; 759153790Sobrien } 759253790Sobrien 759353790Sobrien /* 759453790Sobrien * status 759553790Sobrien */ 759653790Sobrien#if 0 /* Provision */ 759753790Sobrien cp->actualquirks = tp->quirks; 759853790Sobrien#endif 759953790Sobrien cp->actualquirks = SYM_QUIRK_AUTOSAVE; 760053790Sobrien cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; 760153790Sobrien cp->ssss_status = S_ILLEGAL; 760253790Sobrien cp->xerr_status = 0; 760353790Sobrien cp->host_flags = 0; 760459252Sgroudier cp->extra_bytes = 0; 760553790Sobrien 760653790Sobrien /* 760753790Sobrien * extreme data pointer. 760853790Sobrien * shall be positive, so -1 is lower than lowest.:) 760953790Sobrien */ 761053790Sobrien cp->ext_sg = -1; 761153790Sobrien cp->ext_ofs = 0; 761253790Sobrien 761353790Sobrien /* 7614178466Smarius * Build the data descriptor block 761553790Sobrien * and start the IO. 761653790Sobrien */ 761758927Sgroudier sym_setup_data_and_start(np, csio, cp); 761853790Sobrien} 761953790Sobrien 762053790Sobrien/* 762158927Sgroudier * Setup buffers and pointers that address the CDB. 7622178466Smarius * I bet, physical CDBs will never be used on the planet, 762358927Sgroudier * since they can be bounced without significant overhead. 762453790Sobrien */ 762553790Sobrienstatic int sym_setup_cdb(hcb_p np, struct ccb_scsiio *csio, ccb_p cp) 762653790Sobrien{ 762753790Sobrien struct ccb_hdr *ccb_h; 762853790Sobrien u32 cmd_ba; 762953790Sobrien int cmd_len; 7630178466Smarius 7631178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7632178468Smarius 763353790Sobrien ccb_h = &csio->ccb_h; 763453790Sobrien 763553790Sobrien /* 763653790Sobrien * CDB is 16 bytes max. 763753790Sobrien */ 763858927Sgroudier if (csio->cdb_len > sizeof(cp->cdb_buf)) { 763953790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_REQ_INVALID); 764053790Sobrien return -1; 764153790Sobrien } 764253790Sobrien cmd_len = csio->cdb_len; 764353790Sobrien 764453790Sobrien if (ccb_h->flags & CAM_CDB_POINTER) { 764553790Sobrien /* CDB is a pointer */ 764653790Sobrien if (!(ccb_h->flags & CAM_CDB_PHYS)) { 764753790Sobrien /* CDB pointer is virtual */ 764858927Sgroudier bcopy(csio->cdb_io.cdb_ptr, cp->cdb_buf, cmd_len); 764958927Sgroudier cmd_ba = CCB_BA (cp, cdb_buf[0]); 765053790Sobrien } else { 765153790Sobrien /* CDB pointer is physical */ 765253790Sobrien#if 0 765353790Sobrien cmd_ba = ((u32)csio->cdb_io.cdb_ptr) & 0xffffffff; 765453790Sobrien#else 765553790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_REQ_INVALID); 765653790Sobrien return -1; 765753790Sobrien#endif 765853790Sobrien } 765953790Sobrien } else { 766058927Sgroudier /* CDB is in the CAM ccb (buffer) */ 766158927Sgroudier bcopy(csio->cdb_io.cdb_bytes, cp->cdb_buf, cmd_len); 766258927Sgroudier cmd_ba = CCB_BA (cp, cdb_buf[0]); 766353790Sobrien } 766453790Sobrien 766553790Sobrien cp->phys.cmd.addr = cpu_to_scr(cmd_ba); 766653790Sobrien cp->phys.cmd.size = cpu_to_scr(cmd_len); 766753790Sobrien 766853790Sobrien return 0; 766953790Sobrien} 767053790Sobrien 767153790Sobrien/* 767258927Sgroudier * Set up data pointers used by SCRIPTS. 767358927Sgroudier */ 7674178466Smariusstatic void __inline 767558927Sgroudiersym_setup_data_pointers(hcb_p np, ccb_p cp, int dir) 767658927Sgroudier{ 767758927Sgroudier u32 lastp, goalp; 767858927Sgroudier 7679178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7680178468Smarius 768158927Sgroudier /* 768258927Sgroudier * No segments means no data. 768358927Sgroudier */ 768458927Sgroudier if (!cp->segments) 768558927Sgroudier dir = CAM_DIR_NONE; 768658927Sgroudier 768758927Sgroudier /* 768858927Sgroudier * Set the data pointer. 768958927Sgroudier */ 769058927Sgroudier switch(dir) { 769158927Sgroudier case CAM_DIR_OUT: 769259292Sgroudier goalp = SCRIPTA_BA (np, data_out2) + 8; 769358927Sgroudier lastp = goalp - 8 - (cp->segments * (2*4)); 769458927Sgroudier break; 769558927Sgroudier case CAM_DIR_IN: 769658927Sgroudier cp->host_flags |= HF_DATA_IN; 769759292Sgroudier goalp = SCRIPTA_BA (np, data_in2) + 8; 769858927Sgroudier lastp = goalp - 8 - (cp->segments * (2*4)); 769958927Sgroudier break; 770058927Sgroudier case CAM_DIR_NONE: 770158927Sgroudier default: 770259292Sgroudier lastp = goalp = SCRIPTB_BA (np, no_data); 770358927Sgroudier break; 770458927Sgroudier } 770558927Sgroudier 770659743Sgroudier cp->phys.head.lastp = cpu_to_scr(lastp); 770759743Sgroudier cp->phys.head.goalp = cpu_to_scr(goalp); 770859743Sgroudier cp->phys.head.savep = cpu_to_scr(lastp); 770959743Sgroudier cp->startp = cp->phys.head.savep; 771058927Sgroudier} 771158927Sgroudier 771258927Sgroudier/* 771358927Sgroudier * Call back routine for the DMA map service. 7714178466Smarius * If bounce buffers are used (why ?), we may sleep and then 771558927Sgroudier * be called there in another context. 771658927Sgroudier */ 771758927Sgroudierstatic void 771858927Sgroudiersym_execute_ccb(void *arg, bus_dma_segment_t *psegs, int nsegs, int error) 771958927Sgroudier{ 772058927Sgroudier ccb_p cp; 772158927Sgroudier hcb_p np; 772258927Sgroudier union ccb *ccb; 772358927Sgroudier 772458927Sgroudier cp = (ccb_p) arg; 772558927Sgroudier ccb = cp->cam_ccb; 772658927Sgroudier np = (hcb_p) cp->arg; 772758927Sgroudier 7728178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7729178468Smarius 773058927Sgroudier /* 773158927Sgroudier * Deal with weird races. 773258927Sgroudier */ 773358927Sgroudier if (sym_get_cam_status(ccb) != CAM_REQ_INPROG) 773458927Sgroudier goto out_abort; 773558927Sgroudier 773658927Sgroudier /* 773758927Sgroudier * Deal with weird errors. 773858927Sgroudier */ 773958927Sgroudier if (error) { 774058927Sgroudier cp->dmamapped = 0; 774158927Sgroudier sym_set_cam_status(cp->cam_ccb, CAM_REQ_ABORTED); 774258927Sgroudier goto out_abort; 774358927Sgroudier } 774458927Sgroudier 774558927Sgroudier /* 774658927Sgroudier * Build the data descriptor for the chip. 774758927Sgroudier */ 774858927Sgroudier if (nsegs) { 774958927Sgroudier int retv; 775058927Sgroudier /* 896 rev 1 requires to be careful about boundaries */ 775158927Sgroudier if (np->device_id == PCI_ID_SYM53C896 && np->revision_id <= 1) 775258927Sgroudier retv = sym_scatter_sg_physical(np, cp, psegs, nsegs); 775358927Sgroudier else 775458927Sgroudier retv = sym_fast_scatter_sg_physical(np,cp, psegs,nsegs); 775558927Sgroudier if (retv < 0) { 775658927Sgroudier sym_set_cam_status(cp->cam_ccb, CAM_REQ_TOO_BIG); 775758927Sgroudier goto out_abort; 775858927Sgroudier } 775958927Sgroudier } 776058927Sgroudier 776158927Sgroudier /* 7762178466Smarius * Synchronize the DMA map only if we have 776358927Sgroudier * actually mapped the data. 776458927Sgroudier */ 776558927Sgroudier if (cp->dmamapped) { 776658927Sgroudier bus_dmamap_sync(np->data_dmat, cp->dmamap, 7767178466Smarius (cp->dmamapped == SYM_DMA_READ ? 776858927Sgroudier BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE)); 776958927Sgroudier } 777058927Sgroudier 777158927Sgroudier /* 777258927Sgroudier * Set host status to busy state. 777358927Sgroudier * May have been set back to HS_WAIT to avoid a race. 777458927Sgroudier */ 777558927Sgroudier cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; 777658927Sgroudier 777758927Sgroudier /* 777858927Sgroudier * Set data pointers. 777958927Sgroudier */ 778058927Sgroudier sym_setup_data_pointers(np, cp, (ccb->ccb_h.flags & CAM_DIR_MASK)); 778158927Sgroudier 778258927Sgroudier /* 778358927Sgroudier * Enqueue this IO in our pending queue. 778458927Sgroudier */ 7785178468Smarius sym_enqueue_cam_ccb(cp); 778658927Sgroudier 778762422Sgroudier /* 7788178466Smarius * When `#ifed 1', the code below makes the driver 778962422Sgroudier * panic on the first attempt to write to a SCSI device. 7790178466Smarius * It is the first test we want to do after a driver 779162422Sgroudier * change that does not seem obviously safe. :) 779262422Sgroudier */ 779358927Sgroudier#if 0 779458927Sgroudier switch (cp->cdb_buf[0]) { 779558927Sgroudier case 0x0A: case 0x2A: case 0xAA: 779658927Sgroudier panic("XXXXXXXXXXXXX WRITE NOT YET ALLOWED XXXXXXXXXXXXXX\n"); 779758927Sgroudier MDELAY(10000); 779858927Sgroudier break; 779958927Sgroudier default: 780058927Sgroudier break; 780158927Sgroudier } 780258927Sgroudier#endif 780358927Sgroudier /* 780458927Sgroudier * Activate this job. 780558927Sgroudier */ 780658927Sgroudier sym_put_start_queue(np, cp); 780758927Sgroudier return; 780858927Sgroudierout_abort: 7809178468Smarius sym_xpt_done(np, ccb, cp); 781058927Sgroudier sym_free_ccb(np, cp); 781158927Sgroudier} 781258927Sgroudier 781358927Sgroudier/* 781453790Sobrien * How complex it gets to deal with the data in CAM. 781558927Sgroudier * The Bus Dma stuff makes things still more complex. 781653790Sobrien */ 7817178466Smariusstatic void 781858927Sgroudiersym_setup_data_and_start(hcb_p np, struct ccb_scsiio *csio, ccb_p cp) 781953790Sobrien{ 782053790Sobrien struct ccb_hdr *ccb_h; 782153790Sobrien int dir, retv; 7822178466Smarius 7823178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7824178468Smarius 782553790Sobrien ccb_h = &csio->ccb_h; 782653790Sobrien 782753790Sobrien /* 782853790Sobrien * Now deal with the data. 782953790Sobrien */ 783058927Sgroudier cp->data_len = csio->dxfer_len; 783158927Sgroudier cp->arg = np; 783258927Sgroudier 783358927Sgroudier /* 783458927Sgroudier * No direction means no data. 783558927Sgroudier */ 783658927Sgroudier dir = (ccb_h->flags & CAM_DIR_MASK); 783758927Sgroudier if (dir == CAM_DIR_NONE) { 783858927Sgroudier sym_execute_ccb(cp, NULL, 0, 0); 783958927Sgroudier return; 784058927Sgroudier } 784158927Sgroudier 7842251874Sscottl cp->dmamapped = (dir == CAM_DIR_IN) ? SYM_DMA_READ : SYM_DMA_WRITE; 7843251874Sscottl retv = bus_dmamap_load_ccb(np->data_dmat, cp->dmamap, 7844251874Sscottl (union ccb *)csio, sym_execute_ccb, cp, 0); 7845251874Sscottl if (retv == EINPROGRESS) { 7846251874Sscottl cp->host_status = HS_WAIT; 7847251874Sscottl xpt_freeze_simq(np->sim, 1); 7848251874Sscottl csio->ccb_h.status |= CAM_RELEASE_SIMQ; 784958927Sgroudier } 785058927Sgroudier} 785158927Sgroudier 785258927Sgroudier/* 785358927Sgroudier * Move the scatter list to our data block. 785458927Sgroudier */ 7855178466Smariusstatic int 7856178466Smariussym_fast_scatter_sg_physical(hcb_p np, ccb_p cp, 785758927Sgroudier bus_dma_segment_t *psegs, int nsegs) 785858927Sgroudier{ 785958927Sgroudier struct sym_tblmove *data; 786058927Sgroudier bus_dma_segment_t *psegs2; 786158927Sgroudier 7862178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7863178468Smarius 786458927Sgroudier if (nsegs > SYM_CONF_MAX_SG) 786558927Sgroudier return -1; 786658927Sgroudier 786758927Sgroudier data = &cp->phys.data[SYM_CONF_MAX_SG-1]; 786858927Sgroudier psegs2 = &psegs[nsegs-1]; 786958927Sgroudier cp->segments = nsegs; 787058927Sgroudier 787158927Sgroudier while (1) { 787258927Sgroudier data->addr = cpu_to_scr(psegs2->ds_addr); 787358927Sgroudier data->size = cpu_to_scr(psegs2->ds_len); 787458927Sgroudier if (DEBUG_FLAGS & DEBUG_SCATTER) { 787558927Sgroudier printf ("%s scatter: paddr=%lx len=%ld\n", 787658927Sgroudier sym_name(np), (long) psegs2->ds_addr, 787758927Sgroudier (long) psegs2->ds_len); 787858927Sgroudier } 787958927Sgroudier if (psegs2 != psegs) { 788058927Sgroudier --data; 788158927Sgroudier --psegs2; 788258927Sgroudier continue; 788358927Sgroudier } 788458927Sgroudier break; 788558927Sgroudier } 788658927Sgroudier return 0; 788758927Sgroudier} 788858927Sgroudier 788958927Sgroudier/* 789058927Sgroudier * Scatter a SG list with physical addresses into bus addressable chunks. 789158927Sgroudier */ 789258927Sgroudierstatic int 789358927Sgroudiersym_scatter_sg_physical(hcb_p np, ccb_p cp, bus_dma_segment_t *psegs, int nsegs) 789458927Sgroudier{ 789558927Sgroudier u_long ps, pe, pn; 7896178466Smarius u_long k; 789758927Sgroudier int s, t; 789858927Sgroudier 7899178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7900178468Smarius 790158927Sgroudier s = SYM_CONF_MAX_SG - 1; 790258927Sgroudier t = nsegs - 1; 790358927Sgroudier ps = psegs[t].ds_addr; 790458927Sgroudier pe = ps + psegs[t].ds_len; 790558927Sgroudier 790658927Sgroudier while (s >= 0) { 7907236468Smarius pn = (pe - 1) & ~(SYM_CONF_DMA_BOUNDARY - 1); 790858927Sgroudier if (pn <= ps) 790958927Sgroudier pn = ps; 791058927Sgroudier k = pe - pn; 791158927Sgroudier if (DEBUG_FLAGS & DEBUG_SCATTER) { 791258927Sgroudier printf ("%s scatter: paddr=%lx len=%ld\n", 791358927Sgroudier sym_name(np), pn, k); 791458927Sgroudier } 791558927Sgroudier cp->phys.data[s].addr = cpu_to_scr(pn); 791658927Sgroudier cp->phys.data[s].size = cpu_to_scr(k); 791758927Sgroudier --s; 791858927Sgroudier if (pn == ps) { 791958927Sgroudier if (--t < 0) 792058927Sgroudier break; 792158927Sgroudier ps = psegs[t].ds_addr; 792258927Sgroudier pe = ps + psegs[t].ds_len; 792358927Sgroudier } 792458927Sgroudier else 792558927Sgroudier pe = pn; 792658927Sgroudier } 792758927Sgroudier 792858927Sgroudier cp->segments = SYM_CONF_MAX_SG - 1 - s; 792958927Sgroudier 793058927Sgroudier return t >= 0 ? -1 : 0; 793158927Sgroudier} 793258927Sgroudier 793358927Sgroudier/* 793453790Sobrien * SIM action for non performance critical stuff. 793553790Sobrien */ 793653790Sobrienstatic void sym_action2(struct cam_sim *sim, union ccb *ccb) 793753790Sobrien{ 7938236468Smarius union ccb *abort_ccb; 7939236468Smarius struct ccb_hdr *ccb_h; 7940236468Smarius struct ccb_pathinq *cpi; 7941236468Smarius struct ccb_trans_settings *cts; 7942236468Smarius struct sym_trans *tip; 794353790Sobrien hcb_p np; 794453790Sobrien tcb_p tp; 794553790Sobrien lcb_p lp; 7946236468Smarius u_char dflags; 794753790Sobrien 794853790Sobrien /* 794953790Sobrien * Retrieve our controller data structure. 795053790Sobrien */ 795153790Sobrien np = (hcb_p) cam_sim_softc(sim); 795253790Sobrien 7953178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7954178468Smarius 795553790Sobrien ccb_h = &ccb->ccb_h; 795653790Sobrien 795753790Sobrien switch (ccb_h->func_code) { 795853790Sobrien case XPT_SET_TRAN_SETTINGS: 795953790Sobrien cts = &ccb->cts; 796053790Sobrien tp = &np->target[ccb_h->target_id]; 796153790Sobrien 796253790Sobrien /* 796374755Sgroudier * Update SPI transport settings in TARGET control block. 796474755Sgroudier * Update SCSI device settings in LUN control block. 796553790Sobrien */ 7966251572Smarius lp = sym_lp(tp, ccb_h->target_lun); 796774755Sgroudier if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 7968251572Smarius sym_update_trans(np, &tp->tinfo.goal, cts); 796974755Sgroudier if (lp) 797053790Sobrien sym_update_dflags(np, &lp->current_flags, cts); 797153790Sobrien } 797274755Sgroudier if (cts->type == CTS_TYPE_USER_SETTINGS) { 7973251572Smarius sym_update_trans(np, &tp->tinfo.user, cts); 797474755Sgroudier if (lp) 797574755Sgroudier sym_update_dflags(np, &lp->user_flags, cts); 797674755Sgroudier } 797753790Sobrien 797853790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 797953790Sobrien break; 798053790Sobrien case XPT_GET_TRAN_SETTINGS: 798153790Sobrien cts = &ccb->cts; 798253790Sobrien tp = &np->target[ccb_h->target_id]; 7983251572Smarius lp = sym_lp(tp, ccb_h->target_lun); 798453790Sobrien 798574755Sgroudier#define cts__scsi (&cts->proto_specific.scsi) 798674755Sgroudier#define cts__spi (&cts->xport_specific.spi) 798774755Sgroudier if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 798874755Sgroudier tip = &tp->tinfo.current; 798974755Sgroudier dflags = lp ? lp->current_flags : 0; 799074755Sgroudier } 799174755Sgroudier else { 799274755Sgroudier tip = &tp->tinfo.user; 799374755Sgroudier dflags = lp ? lp->user_flags : tp->usrflags; 799474755Sgroudier } 799574755Sgroudier 799674755Sgroudier cts->protocol = PROTO_SCSI; 799774755Sgroudier cts->transport = XPORT_SPI; 799874755Sgroudier cts->protocol_version = tip->scsi_version; 799974755Sgroudier cts->transport_version = tip->spi_version; 8000178466Smarius 800174755Sgroudier cts__spi->sync_period = tip->period; 800274755Sgroudier cts__spi->sync_offset = tip->offset; 800374755Sgroudier cts__spi->bus_width = tip->width; 800474755Sgroudier cts__spi->ppr_options = tip->options; 800574755Sgroudier 800674755Sgroudier cts__spi->valid = CTS_SPI_VALID_SYNC_RATE 800774755Sgroudier | CTS_SPI_VALID_SYNC_OFFSET 800874755Sgroudier | CTS_SPI_VALID_BUS_WIDTH 800974755Sgroudier | CTS_SPI_VALID_PPR_OPTIONS; 8010178466Smarius 801174755Sgroudier cts__spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 801274755Sgroudier if (dflags & SYM_DISC_ENABLED) 801374755Sgroudier cts__spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 801474755Sgroudier cts__spi->valid |= CTS_SPI_VALID_DISC; 801574755Sgroudier 801674755Sgroudier cts__scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 801774755Sgroudier if (dflags & SYM_TAGS_ENABLED) 801874755Sgroudier cts__scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 801974755Sgroudier cts__scsi->valid |= CTS_SCSI_VALID_TQ; 802074755Sgroudier#undef cts__spi 802174755Sgroudier#undef cts__scsi 802253790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 802353790Sobrien break; 802453790Sobrien case XPT_CALC_GEOMETRY: 8025116351Snjl cam_calc_geometry(&ccb->ccg, /*extended*/1); 802653790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 802753790Sobrien break; 802853790Sobrien case XPT_PATH_INQ: 8029236468Smarius cpi = &ccb->cpi; 803053790Sobrien cpi->version_num = 1; 803153790Sobrien cpi->hba_inquiry = PI_MDP_ABLE|PI_SDTR_ABLE|PI_TAG_ABLE; 803253790Sobrien if ((np->features & FE_WIDE) != 0) 803353790Sobrien cpi->hba_inquiry |= PI_WIDE_16; 803453790Sobrien cpi->target_sprt = 0; 8035251947Smarius cpi->hba_misc = PIM_UNMAPPED; 803655628Sgroudier if (np->usrflags & SYM_SCAN_TARGETS_HILO) 803755628Sgroudier cpi->hba_misc |= PIM_SCANHILO; 803855628Sgroudier if (np->usrflags & SYM_AVOID_BUS_RESET) 803955628Sgroudier cpi->hba_misc |= PIM_NOBUSRESET; 804053790Sobrien cpi->hba_eng_cnt = 0; 804153790Sobrien cpi->max_target = (np->features & FE_WIDE) ? 15 : 7; 804253790Sobrien /* Semantic problem:)LUN number max = max number of LUNs - 1 */ 804354690Sobrien cpi->max_lun = SYM_CONF_MAX_LUN-1; 804454690Sobrien if (SYM_SETUP_MAX_LUN < SYM_CONF_MAX_LUN) 804554690Sobrien cpi->max_lun = SYM_SETUP_MAX_LUN-1; 804653790Sobrien cpi->bus_id = cam_sim_bus(sim); 804753790Sobrien cpi->initiator_id = np->myaddr; 804853790Sobrien cpi->base_transfer_speed = 3300; 804954690Sobrien strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 805053790Sobrien strncpy(cpi->hba_vid, "Symbios", HBA_IDLEN); 805153790Sobrien strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 805253790Sobrien cpi->unit_number = cam_sim_unit(sim); 805374755Sgroudier 805474755Sgroudier cpi->protocol = PROTO_SCSI; 805574755Sgroudier cpi->protocol_version = SCSI_REV_2; 805674755Sgroudier cpi->transport = XPORT_SPI; 805774755Sgroudier cpi->transport_version = 2; 805874755Sgroudier cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_ST; 805974755Sgroudier if (np->features & FE_ULTRA3) { 806074755Sgroudier cpi->transport_version = 3; 806174755Sgroudier cpi->xport_specific.spi.ppr_options = 806274755Sgroudier SID_SPI_CLOCK_DT_ST; 806374755Sgroudier } 8064237186Smarius cpi->maxio = SYM_CONF_MAX_SG * PAGE_SIZE; 806553790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 806653790Sobrien break; 806753790Sobrien case XPT_ABORT: 8068236468Smarius abort_ccb = ccb->cab.abort_ccb; 806953790Sobrien switch(abort_ccb->ccb_h.func_code) { 807053790Sobrien case XPT_SCSI_IO: 807153790Sobrien if (sym_abort_scsiio(np, abort_ccb, 0) == 0) { 807253790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 807353790Sobrien break; 807453790Sobrien } 807553790Sobrien default: 807653790Sobrien sym_xpt_done2(np, ccb, CAM_UA_ABORT); 807753790Sobrien break; 807853790Sobrien } 807953790Sobrien break; 808053790Sobrien case XPT_RESET_DEV: 808153790Sobrien sym_reset_dev(np, ccb); 808253790Sobrien break; 808353790Sobrien case XPT_RESET_BUS: 808453790Sobrien sym_reset_scsi_bus(np, 0); 808553790Sobrien if (sym_verbose) { 808653790Sobrien xpt_print_path(np->path); 808755300Sgroudier printf("SCSI BUS reset delivered.\n"); 808853790Sobrien } 808955300Sgroudier sym_init (np, 1); 809053790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 809153790Sobrien break; 809253790Sobrien case XPT_ACCEPT_TARGET_IO: 809353790Sobrien case XPT_CONT_TARGET_IO: 809453790Sobrien case XPT_EN_LUN: 809553790Sobrien case XPT_NOTIFY_ACK: 809653790Sobrien case XPT_IMMED_NOTIFY: 809753790Sobrien case XPT_TERM_IO: 809853790Sobrien default: 809953790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_INVALID); 810053790Sobrien break; 810153790Sobrien } 810253790Sobrien} 810353790Sobrien 810453790Sobrien/* 810562134Sgroudier * Asynchronous notification handler. 810662134Sgroudier */ 810762134Sgroudierstatic void 8108251572Smariussym_async(void *cb_arg, u32 code, struct cam_path *path, void *args __unused) 810962134Sgroudier{ 811062134Sgroudier hcb_p np; 811162134Sgroudier struct cam_sim *sim; 811262134Sgroudier u_int tn; 811362134Sgroudier tcb_p tp; 811462134Sgroudier 811562134Sgroudier sim = (struct cam_sim *) cb_arg; 811662134Sgroudier np = (hcb_p) cam_sim_softc(sim); 811762134Sgroudier 8118178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 8119178468Smarius 812062134Sgroudier switch (code) { 812162134Sgroudier case AC_LOST_DEVICE: 812262134Sgroudier tn = xpt_path_target_id(path); 812362134Sgroudier if (tn >= SYM_CONF_MAX_TARGET) 812462134Sgroudier break; 812562134Sgroudier 812662134Sgroudier tp = &np->target[tn]; 812762134Sgroudier 812862134Sgroudier tp->to_reset = 0; 812962134Sgroudier tp->head.sval = 0; 813062134Sgroudier tp->head.wval = np->rv_scntl3; 813162134Sgroudier tp->head.uval = 0; 813262134Sgroudier 813362134Sgroudier tp->tinfo.current.period = tp->tinfo.goal.period = 0; 813462134Sgroudier tp->tinfo.current.offset = tp->tinfo.goal.offset = 0; 813562134Sgroudier tp->tinfo.current.width = tp->tinfo.goal.width = BUS_8_BIT; 813662134Sgroudier tp->tinfo.current.options = tp->tinfo.goal.options = 0; 813762134Sgroudier 813862134Sgroudier break; 813962134Sgroudier default: 814062134Sgroudier break; 814162134Sgroudier } 814262134Sgroudier} 814362134Sgroudier 814462134Sgroudier/* 814553790Sobrien * Update transfer settings of a target. 814653790Sobrien */ 8147251572Smariusstatic void sym_update_trans(hcb_p np, struct sym_trans *tip, 8148251572Smarius struct ccb_trans_settings *cts) 814953790Sobrien{ 8150251572Smarius 8151178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 8152178468Smarius 815353790Sobrien /* 815453790Sobrien * Update the infos. 815553790Sobrien */ 815674755Sgroudier#define cts__spi (&cts->xport_specific.spi) 815774755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) 815874755Sgroudier tip->width = cts__spi->bus_width; 815974755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 816074755Sgroudier tip->offset = cts__spi->sync_offset; 816174755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 816274755Sgroudier tip->period = cts__spi->sync_period; 816374755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_PPR_OPTIONS) != 0) 816474755Sgroudier tip->options = (cts__spi->ppr_options & PPR_OPT_DT); 816574755Sgroudier if (cts->protocol_version != PROTO_VERSION_UNSPECIFIED && 816674755Sgroudier cts->protocol_version != PROTO_VERSION_UNKNOWN) 816774755Sgroudier tip->scsi_version = cts->protocol_version; 816874755Sgroudier if (cts->transport_version != XPORT_VERSION_UNSPECIFIED && 816974755Sgroudier cts->transport_version != XPORT_VERSION_UNKNOWN) 817074755Sgroudier tip->spi_version = cts->transport_version; 817174755Sgroudier#undef cts__spi 817253790Sobrien /* 817360134Sgroudier * Scale against driver configuration limits. 817453790Sobrien */ 817560134Sgroudier if (tip->width > SYM_SETUP_MAX_WIDE) tip->width = SYM_SETUP_MAX_WIDE; 8176248831Smjacob if (tip->period && tip->offset) { 8177248831Smjacob if (tip->offset > SYM_SETUP_MAX_OFFS) tip->offset = SYM_SETUP_MAX_OFFS; 8178248831Smjacob if (tip->period < SYM_SETUP_MIN_SYNC) tip->period = SYM_SETUP_MIN_SYNC; 8179248831Smjacob } else { 8180248831Smjacob tip->offset = 0; 8181248831Smjacob tip->period = 0; 8182248831Smjacob } 818360134Sgroudier 818460134Sgroudier /* 818560134Sgroudier * Scale against actual controller BUS width. 818660134Sgroudier */ 818760134Sgroudier if (tip->width > np->maxwide) 818860134Sgroudier tip->width = np->maxwide; 818960134Sgroudier 819060134Sgroudier /* 819174755Sgroudier * Only accept DT if controller supports and SYNC/WIDE asked. 819274755Sgroudier */ 819374755Sgroudier if (!((np->features & (FE_C10|FE_ULTRA3)) == (FE_C10|FE_ULTRA3)) || 819474755Sgroudier !(tip->width == BUS_16_BIT && tip->offset)) { 819574755Sgroudier tip->options &= ~PPR_OPT_DT; 819674755Sgroudier } 819760134Sgroudier 819860134Sgroudier /* 819960134Sgroudier * Scale period factor and offset against controller limits. 820060134Sgroudier */ 8201248831Smjacob if (tip->offset && tip->period) { 8202248831Smjacob if (tip->options & PPR_OPT_DT) { 8203248831Smjacob if (tip->period < np->minsync_dt) 8204248831Smjacob tip->period = np->minsync_dt; 8205248831Smjacob if (tip->period > np->maxsync_dt) 8206248831Smjacob tip->period = np->maxsync_dt; 8207248831Smjacob if (tip->offset > np->maxoffs_dt) 8208248831Smjacob tip->offset = np->maxoffs_dt; 8209248831Smjacob } 8210248831Smjacob else { 8211248831Smjacob if (tip->period < np->minsync) 8212248831Smjacob tip->period = np->minsync; 8213248831Smjacob if (tip->period > np->maxsync) 8214248831Smjacob tip->period = np->maxsync; 8215248831Smjacob if (tip->offset > np->maxoffs) 8216248831Smjacob tip->offset = np->maxoffs; 8217248831Smjacob } 821860134Sgroudier } 821953790Sobrien} 822053790Sobrien 822153790Sobrien/* 822253790Sobrien * Update flags for a device (logical unit). 822353790Sobrien */ 8224178466Smariusstatic void 822553790Sobriensym_update_dflags(hcb_p np, u_char *flags, struct ccb_trans_settings *cts) 822653790Sobrien{ 8227251572Smarius 8228178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 8229178468Smarius 823074755Sgroudier#define cts__scsi (&cts->proto_specific.scsi) 823174755Sgroudier#define cts__spi (&cts->xport_specific.spi) 823274755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_DISC) != 0) { 823374755Sgroudier if ((cts__spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 823474755Sgroudier *flags |= SYM_DISC_ENABLED; 823574755Sgroudier else 823674755Sgroudier *flags &= ~SYM_DISC_ENABLED; 823774755Sgroudier } 823874755Sgroudier 823974755Sgroudier if ((cts__scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 824074755Sgroudier if ((cts__scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 824174755Sgroudier *flags |= SYM_TAGS_ENABLED; 824274755Sgroudier else 824374755Sgroudier *flags &= ~SYM_TAGS_ENABLED; 824474755Sgroudier } 824574755Sgroudier#undef cts__spi 824674755Sgroudier#undef cts__scsi 824753790Sobrien} 824853790Sobrien 824953790Sobrien/*============= DRIVER INITIALISATION ==================*/ 825053790Sobrien 825153790Sobrienstatic device_method_t sym_pci_methods[] = { 825253790Sobrien DEVMETHOD(device_probe, sym_pci_probe), 825353790Sobrien DEVMETHOD(device_attach, sym_pci_attach), 8254236468Smarius DEVMETHOD_END 825553790Sobrien}; 825653790Sobrien 825753790Sobrienstatic driver_t sym_pci_driver = { 825853790Sobrien "sym", 825953790Sobrien sym_pci_methods, 8260178468Smarius 1 /* no softc */ 826153790Sobrien}; 826253790Sobrien 826353790Sobrienstatic devclass_t sym_devclass; 826453790Sobrien 8265236468SmariusDRIVER_MODULE(sym, pci, sym_pci_driver, sym_devclass, NULL, NULL); 8266135040SmjacobMODULE_DEPEND(sym, cam, 1, 1, 1); 8267135041SmjacobMODULE_DEPEND(sym, pci, 1, 1, 1); 826853790Sobrien 8269179029Smariusstatic const struct sym_pci_chip sym_pci_dev_table[] = { 827059743Sgroudier {PCI_ID_SYM53C810, 0x0f, "810", 4, 8, 4, 64, 827153809Sobrien FE_ERL} 827253809Sobrien , 827359743Sgroudier#ifdef SYM_DEBUG_GENERIC_SUPPORT 827454690Sobrien {PCI_ID_SYM53C810, 0xff, "810a", 4, 8, 4, 1, 827559743Sgroudier FE_BOF} 827659743Sgroudier , 827759743Sgroudier#else 827859743Sgroudier {PCI_ID_SYM53C810, 0xff, "810a", 4, 8, 4, 1, 827953790Sobrien FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF} 828053790Sobrien , 828159743Sgroudier#endif 828259743Sgroudier {PCI_ID_SYM53C815, 0xff, "815", 4, 8, 4, 64, 828359743Sgroudier FE_BOF|FE_ERL} 828459743Sgroudier , 828559743Sgroudier {PCI_ID_SYM53C825, 0x0f, "825", 6, 8, 4, 64, 828653809Sobrien FE_WIDE|FE_BOF|FE_ERL|FE_DIFF} 828753809Sobrien , 828854690Sobrien {PCI_ID_SYM53C825, 0xff, "825a", 6, 8, 4, 2, 828953790Sobrien FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF} 829053790Sobrien , 829154690Sobrien {PCI_ID_SYM53C860, 0xff, "860", 4, 8, 5, 1, 829253790Sobrien FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} 829353790Sobrien , 829454690Sobrien {PCI_ID_SYM53C875, 0x01, "875", 6, 16, 5, 2, 829553790Sobrien FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 829653790Sobrien FE_RAM|FE_DIFF} 829753790Sobrien , 829854690Sobrien {PCI_ID_SYM53C875, 0xff, "875", 6, 16, 5, 2, 829953790Sobrien FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 830053790Sobrien FE_RAM|FE_DIFF} 830153790Sobrien , 830254690Sobrien {PCI_ID_SYM53C875_2, 0xff, "875", 6, 16, 5, 2, 830353790Sobrien FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 830453790Sobrien FE_RAM|FE_DIFF} 830553790Sobrien , 830654690Sobrien {PCI_ID_SYM53C885, 0xff, "885", 6, 16, 5, 2, 830753790Sobrien FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 830853790Sobrien FE_RAM|FE_DIFF} 830953790Sobrien , 831059743Sgroudier#ifdef SYM_DEBUG_GENERIC_SUPPORT 831154690Sobrien {PCI_ID_SYM53C895, 0xff, "895", 6, 31, 7, 2, 831259743Sgroudier FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS| 831359743Sgroudier FE_RAM|FE_LCKFRQ} 831459743Sgroudier , 831559743Sgroudier#else 831659743Sgroudier {PCI_ID_SYM53C895, 0xff, "895", 6, 31, 7, 2, 831753790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 831853790Sobrien FE_RAM|FE_LCKFRQ} 831953790Sobrien , 832059743Sgroudier#endif 832154690Sobrien {PCI_ID_SYM53C896, 0xff, "896", 6, 31, 7, 4, 832253790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 832365404Sgroudier FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} 832453790Sobrien , 832554690Sobrien {PCI_ID_SYM53C895A, 0xff, "895a", 6, 31, 7, 4, 832653790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 832765404Sgroudier FE_RAM|FE_RAM8K|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} 832853790Sobrien , 832960134Sgroudier {PCI_ID_LSI53C1010, 0x00, "1010-33", 6, 31, 7, 8, 833053790Sobrien FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| 833165404Sgroudier FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC| 833253790Sobrien FE_C10} 833353790Sobrien , 833460134Sgroudier {PCI_ID_LSI53C1010, 0xff, "1010-33", 6, 31, 7, 8, 833553790Sobrien FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| 833665404Sgroudier FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC| 833755300Sgroudier FE_C10|FE_U3EN} 833855300Sgroudier , 833960134Sgroudier {PCI_ID_LSI53C1010_2, 0xff, "1010-66", 6, 31, 7, 8, 834055300Sgroudier FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| 834165404Sgroudier FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_66MHZ|FE_CRC| 834253790Sobrien FE_C10|FE_U3EN} 834353790Sobrien , 834454690Sobrien {PCI_ID_LSI53C1510D, 0xff, "1510d", 6, 31, 7, 4, 834553790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 834653790Sobrien FE_RAM|FE_IO256|FE_LEDC} 834753790Sobrien}; 834853790Sobrien 834953790Sobrien/* 835053790Sobrien * Look up the chip table. 835153790Sobrien * 8352178466Smarius * Return a pointer to the chip entry if found, 835353790Sobrien * zero otherwise. 835453790Sobrien */ 8355179029Smariusstatic const struct sym_pci_chip * 835653790Sobriensym_find_pci_chip(device_t dev) 835753790Sobrien{ 8358179029Smarius const struct sym_pci_chip *chip; 835953790Sobrien int i; 836053790Sobrien u_short device_id; 836153790Sobrien u_char revision; 836253790Sobrien 836353790Sobrien if (pci_get_vendor(dev) != PCI_VENDOR_NCR) 8364178466Smarius return NULL; 836553790Sobrien 836653790Sobrien device_id = pci_get_device(dev); 836753790Sobrien revision = pci_get_revid(dev); 836853790Sobrien 8369236641Smarius for (i = 0; i < nitems(sym_pci_dev_table); i++) { 837053790Sobrien chip = &sym_pci_dev_table[i]; 837153790Sobrien if (device_id != chip->device_id) 837253790Sobrien continue; 837353790Sobrien if (revision > chip->revision_id) 837453790Sobrien continue; 837559743Sgroudier return chip; 837653790Sobrien } 837753790Sobrien 8378178466Smarius return NULL; 837953790Sobrien} 838053790Sobrien 838153790Sobrien/* 838253790Sobrien * Tell upper layer if the chip is supported. 838353790Sobrien */ 838453790Sobrienstatic int 838553790Sobriensym_pci_probe(device_t dev) 838653790Sobrien{ 8387179029Smarius const struct sym_pci_chip *chip; 838853790Sobrien 838953790Sobrien chip = sym_find_pci_chip(dev); 839059743Sgroudier if (chip && sym_find_firmware(chip)) { 839153790Sobrien device_set_desc(dev, chip->name); 8392178466Smarius return (chip->lp_probe_bit & SYM_SETUP_LP_PROBE_MAP)? 8393143168Simp BUS_PROBE_LOW_PRIORITY : BUS_PROBE_DEFAULT; 839453790Sobrien } 839553790Sobrien return ENXIO; 839653790Sobrien} 839753790Sobrien 839853790Sobrien/* 839953790Sobrien * Attach a sym53c8xx device. 840053790Sobrien */ 840153790Sobrienstatic int 840253790Sobriensym_pci_attach(device_t dev) 840353790Sobrien{ 8404179029Smarius const struct sym_pci_chip *chip; 840553790Sobrien u_short command; 840653790Sobrien u_char cachelnsz; 8407178466Smarius struct sym_hcb *np = NULL; 840853790Sobrien struct sym_nvram nvram; 8409179029Smarius const struct sym_fw *fw = NULL; 841053790Sobrien int i; 841158927Sgroudier bus_dma_tag_t bus_dmat; 841253790Sobrien 8413166165Smarius bus_dmat = bus_get_dma_tag(dev); 841458927Sgroudier 841558927Sgroudier /* 841653790Sobrien * Only probed devices should be attached. 841753790Sobrien * We just enjoy being paranoid. :) 841853790Sobrien */ 841953790Sobrien chip = sym_find_pci_chip(dev); 842059743Sgroudier if (chip == NULL || (fw = sym_find_firmware(chip)) == NULL) 842153790Sobrien return (ENXIO); 842253790Sobrien 842353790Sobrien /* 8424178466Smarius * Allocate immediately the host control block, 842553790Sobrien * since we are only expecting to succeed. :) 8426178466Smarius * We keep track in the HCB of all the resources that 842753790Sobrien * are to be released on error. 842853790Sobrien */ 842958927Sgroudier np = __sym_calloc_dma(bus_dmat, sizeof(*np), "HCB"); 843058927Sgroudier if (np) 843158927Sgroudier np->bus_dmat = bus_dmat; 843258927Sgroudier else 8433178468Smarius return (ENXIO); 8434179029Smarius device_set_softc(dev, np); 843553790Sobrien 8436178468Smarius SYM_LOCK_INIT(); 8437178468Smarius 843853790Sobrien /* 843953790Sobrien * Copy some useful infos to the HCB. 844053790Sobrien */ 844158927Sgroudier np->hcb_ba = vtobus(np); 844253790Sobrien np->verbose = bootverbose; 844353790Sobrien np->device = dev; 844453790Sobrien np->device_id = pci_get_device(dev); 844553790Sobrien np->revision_id = pci_get_revid(dev); 844653790Sobrien np->features = chip->features; 844753790Sobrien np->clock_divn = chip->nr_divisor; 844853790Sobrien np->maxoffs = chip->offset_max; 844953790Sobrien np->maxburst = chip->burst_max; 845059743Sgroudier np->scripta_sz = fw->a_size; 845159743Sgroudier np->scriptb_sz = fw->b_size; 845259743Sgroudier np->fw_setup = fw->setup; 845359743Sgroudier np->fw_patch = fw->patch; 845459743Sgroudier np->fw_name = fw->name; 845553790Sobrien 8456171524Sse#ifdef __amd64__ 8457171524Sse np->target = sym_calloc_dma(SYM_CONF_MAX_TARGET * sizeof(*(np->target)), 8458171524Sse "TARGET"); 8459171524Sse if (!np->target) 8460171524Sse goto attach_failed; 8461171524Sse#endif 846253790Sobrien 846353790Sobrien /* 8464178466Smarius * Initialize the CCB free and busy queues. 846575329Smjacob */ 846675329Smjacob sym_que_init(&np->free_ccbq); 846775329Smjacob sym_que_init(&np->busy_ccbq); 846875329Smjacob sym_que_init(&np->comp_ccbq); 846975329Smjacob sym_que_init(&np->cam_ccbq); 847075329Smjacob 847175329Smjacob /* 847258927Sgroudier * Allocate a tag for the DMA of user data. 847358927Sgroudier */ 8474236468Smarius if (bus_dma_tag_create(np->bus_dmat, 1, SYM_CONF_DMA_BOUNDARY, 8475236468Smarius BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 8476238689Smarius BUS_SPACE_MAXSIZE_32BIT, SYM_CONF_MAX_SG, SYM_CONF_DMA_BOUNDARY, 8477238689Smarius 0, busdma_lock_mutex, &np->mtx, &np->data_dmat)) { 847858927Sgroudier device_printf(dev, "failed to create DMA tag.\n"); 847958927Sgroudier goto attach_failed; 848058927Sgroudier } 8481236468Smarius 848258927Sgroudier /* 8483178466Smarius * Read and apply some fix-ups to the PCI COMMAND 848453790Sobrien * register. We want the chip to be enabled for: 848553790Sobrien * - BUS mastering 848653790Sobrien * - PCI parity checking (reporting would also be fine) 848753790Sobrien * - Write And Invalidate. 848853790Sobrien */ 848953790Sobrien command = pci_read_config(dev, PCIR_COMMAND, 2); 8490236468Smarius command |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_PERRESPEN | 8491236468Smarius PCIM_CMD_MWRICEN; 849253790Sobrien pci_write_config(dev, PCIR_COMMAND, command, 2); 849353790Sobrien 849453790Sobrien /* 8495178466Smarius * Let the device know about the cache line size, 849653790Sobrien * if it doesn't yet. 849753790Sobrien */ 849853790Sobrien cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); 849953790Sobrien if (!cachelnsz) { 850053790Sobrien cachelnsz = 8; 850153790Sobrien pci_write_config(dev, PCIR_CACHELNSZ, cachelnsz, 1); 850253790Sobrien } 850353790Sobrien 850453790Sobrien /* 850553790Sobrien * Alloc/get/map/retrieve everything that deals with MMIO. 850653790Sobrien */ 8507254306Sscottl i = SYM_PCI_MMIO; 8508254306Sscottl np->mmio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, 8509254306Sscottl RF_ACTIVE); 851053790Sobrien if (!np->mmio_res) { 851153790Sobrien device_printf(dev, "failed to allocate MMIO resources\n"); 851253790Sobrien goto attach_failed; 851353790Sobrien } 8514178468Smarius np->mmio_ba = rman_get_start(np->mmio_res); 851553790Sobrien 851653790Sobrien /* 851753790Sobrien * Allocate the IRQ. 851853790Sobrien */ 851953790Sobrien i = 0; 8520127135Snjl np->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, 8521127135Snjl RF_ACTIVE | RF_SHAREABLE); 852253790Sobrien if (!np->irq_res) { 852353790Sobrien device_printf(dev, "failed to allocate IRQ resource\n"); 852453790Sobrien goto attach_failed; 852553790Sobrien } 852653790Sobrien 852754690Sobrien#ifdef SYM_CONF_IOMAPPED 852853790Sobrien /* 852953790Sobrien * User want us to use normal IO with PCI. 853053790Sobrien * Alloc/get/map/retrieve everything that deals with IO. 853153790Sobrien */ 8532254306Sscottl i = SYM_PCI_IO; 8533254306Sscottl np->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &i, RF_ACTIVE); 853453790Sobrien if (!np->io_res) { 853553790Sobrien device_printf(dev, "failed to allocate IO resources\n"); 853653790Sobrien goto attach_failed; 853753790Sobrien } 853853790Sobrien 853954690Sobrien#endif /* SYM_CONF_IOMAPPED */ 854053790Sobrien 854153790Sobrien /* 854253790Sobrien * If the chip has RAM. 854353790Sobrien * Alloc/get/map/retrieve the corresponding resources. 854453790Sobrien */ 8545254306Sscottl if (np->features & (FE_RAM|FE_RAM8K)) { 854653790Sobrien int regs_id = SYM_PCI_RAM; 854753790Sobrien if (np->features & FE_64BIT) 854853790Sobrien regs_id = SYM_PCI_RAM64; 8549127135Snjl np->ram_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 8550127135Snjl ®s_id, RF_ACTIVE); 855153790Sobrien if (!np->ram_res) { 855253790Sobrien device_printf(dev,"failed to allocate RAM resources\n"); 855353790Sobrien goto attach_failed; 855453790Sobrien } 855553790Sobrien np->ram_id = regs_id; 8556178468Smarius np->ram_ba = rman_get_start(np->ram_res); 855753790Sobrien } 855853790Sobrien 855953790Sobrien /* 8560178466Smarius * Save setting of some IO registers, so we will 856153796Sobrien * be able to probe specific implementations. 856253796Sobrien */ 856353796Sobrien sym_save_initial_setting (np); 856453796Sobrien 856553796Sobrien /* 8566178466Smarius * Reset the chip now, since it has been reported 8567178466Smarius * that SCSI clock calibration may not work properly 856853796Sobrien * if the chip is currently active. 856953796Sobrien */ 857053796Sobrien sym_chip_reset (np); 857153796Sobrien 857253796Sobrien /* 857353790Sobrien * Try to read the user set-up. 857453790Sobrien */ 857553790Sobrien (void) sym_read_nvram(np, &nvram); 857653790Sobrien 857753790Sobrien /* 8578178466Smarius * Prepare controller and devices settings, according 857953790Sobrien * to chip features, user set-up and driver set-up. 858053790Sobrien */ 858153790Sobrien (void) sym_prepare_setting(np, &nvram); 858253790Sobrien 858353790Sobrien /* 858453790Sobrien * Check the PCI clock frequency. 8585178466Smarius * Must be performed after prepare_setting since it destroys 858653790Sobrien * STEST1 that is used to probe for the clock doubler. 858753790Sobrien */ 858853790Sobrien i = sym_getpciclock(np); 858953790Sobrien if (i > 37000) 859053790Sobrien device_printf(dev, "PCI BUS clock seems too high: %u KHz.\n",i); 859153790Sobrien 859253790Sobrien /* 859353790Sobrien * Allocate the start queue. 859453790Sobrien */ 859558927Sgroudier np->squeue = (u32 *) sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"SQUEUE"); 859653790Sobrien if (!np->squeue) 859753790Sobrien goto attach_failed; 859858927Sgroudier np->squeue_ba = vtobus(np->squeue); 859953790Sobrien 860053790Sobrien /* 860153790Sobrien * Allocate the done queue. 860253790Sobrien */ 860358927Sgroudier np->dqueue = (u32 *) sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"DQUEUE"); 860453790Sobrien if (!np->dqueue) 860553790Sobrien goto attach_failed; 860659743Sgroudier np->dqueue_ba = vtobus(np->dqueue); 860753790Sobrien 860853790Sobrien /* 860953790Sobrien * Allocate the target bus address array. 861053790Sobrien */ 861158927Sgroudier np->targtbl = (u32 *) sym_calloc_dma(256, "TARGTBL"); 861253790Sobrien if (!np->targtbl) 861353790Sobrien goto attach_failed; 861486850Sgroudier np->targtbl_ba = vtobus(np->targtbl); 861553790Sobrien 861653790Sobrien /* 861753790Sobrien * Allocate SCRIPTS areas. 861853790Sobrien */ 861959743Sgroudier np->scripta0 = sym_calloc_dma(np->scripta_sz, "SCRIPTA0"); 862059743Sgroudier np->scriptb0 = sym_calloc_dma(np->scriptb_sz, "SCRIPTB0"); 862159292Sgroudier if (!np->scripta0 || !np->scriptb0) 862253790Sobrien goto attach_failed; 862353790Sobrien 862453790Sobrien /* 8625178468Smarius * Allocate the CCBs. We need at least ONE. 862653790Sobrien */ 8627178468Smarius for (i = 0; sym_alloc_ccb(np) != NULL; i++) 8628178468Smarius ; 8629178468Smarius if (i < 1) 863053790Sobrien goto attach_failed; 863153790Sobrien 863253790Sobrien /* 8633178466Smarius * Calculate BUS addresses where we are going 863453790Sobrien * to load the SCRIPTS. 863553790Sobrien */ 863659292Sgroudier np->scripta_ba = vtobus(np->scripta0); 863759292Sgroudier np->scriptb_ba = vtobus(np->scriptb0); 863859292Sgroudier np->scriptb0_ba = np->scriptb_ba; 863953790Sobrien 864053790Sobrien if (np->ram_ba) { 864159292Sgroudier np->scripta_ba = np->ram_ba; 864253790Sobrien if (np->features & FE_RAM8K) { 864353790Sobrien np->ram_ws = 8192; 864459292Sgroudier np->scriptb_ba = np->scripta_ba + 4096; 8645153085Sru#ifdef __LP64__ 864659292Sgroudier np->scr_ram_seg = cpu_to_scr(np->scripta_ba >> 32); 8647153085Sru#endif 864853790Sobrien } 864953790Sobrien else 865053790Sobrien np->ram_ws = 4096; 865153790Sobrien } 865253790Sobrien 865353790Sobrien /* 865459743Sgroudier * Copy scripts to controller instance. 865553790Sobrien */ 865659743Sgroudier bcopy(fw->a_base, np->scripta0, np->scripta_sz); 865759743Sgroudier bcopy(fw->b_base, np->scriptb0, np->scriptb_sz); 865853790Sobrien 865953790Sobrien /* 866059743Sgroudier * Setup variable parts in scripts and compute 866159743Sgroudier * scripts bus addresses used from the C code. 866253790Sobrien */ 866359743Sgroudier np->fw_setup(np, fw); 866453790Sobrien 866553790Sobrien /* 8666178466Smarius * Bind SCRIPTS with physical addresses usable by the 866759743Sgroudier * SCRIPTS processor (as seen from the BUS = BUS addresses). 866853790Sobrien */ 866959743Sgroudier sym_fw_bind_script(np, (u32 *) np->scripta0, np->scripta_sz); 867059743Sgroudier sym_fw_bind_script(np, (u32 *) np->scriptb0, np->scriptb_sz); 867153793Sobrien 867254690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 867353790Sobrien /* 8674178466Smarius * If user wants IARB to be set when we win arbitration 8675178466Smarius * and have other jobs, compute the max number of consecutive 8676178466Smarius * settings of IARB hints before we leave devices a chance to 867753790Sobrien * arbitrate for reselection. 867853790Sobrien */ 867954690Sobrien#ifdef SYM_SETUP_IARB_MAX 868054690Sobrien np->iarb_max = SYM_SETUP_IARB_MAX; 868153790Sobrien#else 868253790Sobrien np->iarb_max = 4; 868353790Sobrien#endif 868453790Sobrien#endif 868553790Sobrien 868653790Sobrien /* 868753790Sobrien * Prepare the idle and invalid task actions. 868853790Sobrien */ 868959292Sgroudier np->idletask.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 869059292Sgroudier np->idletask.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l)); 869153790Sobrien np->idletask_ba = vtobus(&np->idletask); 869253790Sobrien 869359292Sgroudier np->notask.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 869459292Sgroudier np->notask.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l)); 869553790Sobrien np->notask_ba = vtobus(&np->notask); 869653790Sobrien 869759292Sgroudier np->bad_itl.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 869859292Sgroudier np->bad_itl.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l)); 869953790Sobrien np->bad_itl_ba = vtobus(&np->bad_itl); 870053790Sobrien 870159292Sgroudier np->bad_itlq.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 870259292Sgroudier np->bad_itlq.restart = cpu_to_scr(SCRIPTB_BA (np,bad_i_t_l_q)); 870353790Sobrien np->bad_itlq_ba = vtobus(&np->bad_itlq); 870453790Sobrien 870553790Sobrien /* 8706178466Smarius * Allocate and prepare the lun JUMP table that is used 870753790Sobrien * for a target prior the probing of devices (bad lun table). 8708178466Smarius * A private table will be allocated for the target on the 870953790Sobrien * first INQUIRY response received. 871053790Sobrien */ 871158927Sgroudier np->badluntbl = sym_calloc_dma(256, "BADLUNTBL"); 871253790Sobrien if (!np->badluntbl) 871353790Sobrien goto attach_failed; 871453790Sobrien 871559292Sgroudier np->badlun_sa = cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun)); 871653790Sobrien for (i = 0 ; i < 64 ; i++) /* 64 luns/target, no less */ 871753790Sobrien np->badluntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa)); 871853790Sobrien 871953790Sobrien /* 8720178466Smarius * Prepare the bus address array that contains the bus 872162422Sgroudier * address of each target control block. 872262422Sgroudier * For now, assume all logical units are wrong. :) 872353790Sobrien */ 872454690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 872553790Sobrien np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i])); 872659743Sgroudier np->target[i].head.luntbl_sa = 872759743Sgroudier cpu_to_scr(vtobus(np->badluntbl)); 872859743Sgroudier np->target[i].head.lun0_sa = 872959743Sgroudier cpu_to_scr(vtobus(&np->badlun_sa)); 873053790Sobrien } 873153790Sobrien 873253790Sobrien /* 873353790Sobrien * Now check the cache handling of the pci chipset. 873453790Sobrien */ 873553790Sobrien if (sym_snooptest (np)) { 873653790Sobrien device_printf(dev, "CACHE INCORRECTLY CONFIGURED.\n"); 873753790Sobrien goto attach_failed; 873853790Sobrien }; 873953790Sobrien 874053790Sobrien /* 874153790Sobrien * Now deal with CAM. 874253790Sobrien * Hopefully, we will succeed with that one.:) 874353790Sobrien */ 874453790Sobrien if (!sym_cam_attach(np)) 874553790Sobrien goto attach_failed; 874653790Sobrien 874753790Sobrien /* 874853790Sobrien * Sigh! we are done. 874953790Sobrien */ 875053790Sobrien return 0; 875153790Sobrien 875253790Sobrien /* 875353790Sobrien * We have failed. 8754178466Smarius * We will try to free all the resources we have 8755178466Smarius * allocated, but if we are a boot device, this 875653790Sobrien * will not help that much.;) 875753790Sobrien */ 875853790Sobrienattach_failed: 875953790Sobrien if (np) 876053790Sobrien sym_pci_free(np); 876153790Sobrien return ENXIO; 876253790Sobrien} 876353790Sobrien 876453790Sobrien/* 876553790Sobrien * Free everything that have been allocated for this device. 876653790Sobrien */ 876753790Sobrienstatic void sym_pci_free(hcb_p np) 876853790Sobrien{ 876955300Sgroudier SYM_QUEHEAD *qp; 877053790Sobrien ccb_p cp; 877153790Sobrien tcb_p tp; 877253790Sobrien lcb_p lp; 877353790Sobrien int target, lun; 877453790Sobrien 877553790Sobrien /* 877653790Sobrien * First free CAM resources. 877753790Sobrien */ 877853790Sobrien sym_cam_free(np); 877953790Sobrien 878053790Sobrien /* 8781178466Smarius * Now every should be quiet for us to 878253790Sobrien * free other resources. 878353790Sobrien */ 878453790Sobrien if (np->ram_res) 8785178466Smarius bus_release_resource(np->device, SYS_RES_MEMORY, 878653790Sobrien np->ram_id, np->ram_res); 878753790Sobrien if (np->mmio_res) 8788178466Smarius bus_release_resource(np->device, SYS_RES_MEMORY, 878953790Sobrien SYM_PCI_MMIO, np->mmio_res); 879053790Sobrien if (np->io_res) 8791178466Smarius bus_release_resource(np->device, SYS_RES_IOPORT, 879253790Sobrien SYM_PCI_IO, np->io_res); 879353790Sobrien if (np->irq_res) 8794178466Smarius bus_release_resource(np->device, SYS_RES_IRQ, 879553790Sobrien 0, np->irq_res); 879653790Sobrien 879759292Sgroudier if (np->scriptb0) 879859743Sgroudier sym_mfree_dma(np->scriptb0, np->scriptb_sz, "SCRIPTB0"); 879959292Sgroudier if (np->scripta0) 880059743Sgroudier sym_mfree_dma(np->scripta0, np->scripta_sz, "SCRIPTA0"); 880153790Sobrien if (np->squeue) 880258927Sgroudier sym_mfree_dma(np->squeue, sizeof(u32)*(MAX_QUEUE*2), "SQUEUE"); 880353790Sobrien if (np->dqueue) 880458927Sgroudier sym_mfree_dma(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE"); 880553790Sobrien 8806179029Smarius while ((qp = sym_remque_head(&np->free_ccbq)) != NULL) { 880755300Sgroudier cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 880858927Sgroudier bus_dmamap_destroy(np->data_dmat, cp->dmamap); 880958927Sgroudier sym_mfree_dma(cp->sns_bbuf, SYM_SNS_BBUF_LEN, "SNS_BBUF"); 881058927Sgroudier sym_mfree_dma(cp, sizeof(*cp), "CCB"); 881153790Sobrien } 881253790Sobrien 881353790Sobrien if (np->badluntbl) 881458927Sgroudier sym_mfree_dma(np->badluntbl, 256,"BADLUNTBL"); 881553790Sobrien 881654690Sobrien for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) { 881753790Sobrien tp = &np->target[target]; 881854690Sobrien for (lun = 0 ; lun < SYM_CONF_MAX_LUN ; lun++) { 8819251572Smarius lp = sym_lp(tp, lun); 882053790Sobrien if (!lp) 882153790Sobrien continue; 882253790Sobrien if (lp->itlq_tbl) 882358927Sgroudier sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, 882453790Sobrien "ITLQ_TBL"); 882553790Sobrien if (lp->cb_tags) 882654690Sobrien sym_mfree(lp->cb_tags, SYM_CONF_MAX_TASK, 882753790Sobrien "CB_TAGS"); 882858927Sgroudier sym_mfree_dma(lp, sizeof(*lp), "LCB"); 882953790Sobrien } 883054690Sobrien#if SYM_CONF_MAX_LUN > 1 883153790Sobrien if (tp->lunmp) 883254690Sobrien sym_mfree(tp->lunmp, SYM_CONF_MAX_LUN*sizeof(lcb_p), 883353790Sobrien "LUNMP"); 8834178466Smarius#endif 883553790Sobrien } 8836171524Sse#ifdef __amd64__ 8837171524Sse if (np->target) 8838171524Sse sym_mfree_dma(np->target, 8839171524Sse SYM_CONF_MAX_TARGET * sizeof(*(np->target)), "TARGET"); 8840171524Sse#endif 884158927Sgroudier if (np->targtbl) 884258927Sgroudier sym_mfree_dma(np->targtbl, 256, "TARGTBL"); 884358927Sgroudier if (np->data_dmat) 884458927Sgroudier bus_dma_tag_destroy(np->data_dmat); 8845178468Smarius if (SYM_LOCK_INITIALIZED() != 0) 8846178468Smarius SYM_LOCK_DESTROY(); 8847179029Smarius device_set_softc(np->device, NULL); 884858927Sgroudier sym_mfree_dma(np, sizeof(*np), "HCB"); 884953790Sobrien} 885053790Sobrien 885153790Sobrien/* 885253790Sobrien * Allocate CAM resources and register a bus to CAM. 885353790Sobrien */ 8854105215Sphkstatic int sym_cam_attach(hcb_p np) 885553790Sobrien{ 8856178466Smarius struct cam_devq *devq = NULL; 8857178466Smarius struct cam_sim *sim = NULL; 8858178466Smarius struct cam_path *path = NULL; 8859178468Smarius int err; 886053790Sobrien 886153790Sobrien /* 886253790Sobrien * Establish our interrupt handler. 886353790Sobrien */ 886473280Smarkm err = bus_setup_intr(np->device, np->irq_res, 8865178468Smarius INTR_ENTROPY | INTR_MPSAFE | INTR_TYPE_CAM, 8866178468Smarius NULL, sym_intr, np, &np->intr); 886753790Sobrien if (err) { 886853790Sobrien device_printf(np->device, "bus_setup_intr() failed: %d\n", 886953790Sobrien err); 887053790Sobrien goto fail; 887153790Sobrien } 887253790Sobrien 887353790Sobrien /* 887453790Sobrien * Create the device queue for our sym SIM. 887553790Sobrien */ 887654690Sobrien devq = cam_simq_alloc(SYM_CONF_MAX_START); 887753790Sobrien if (!devq) 887853790Sobrien goto fail; 887953790Sobrien 888053790Sobrien /* 888153790Sobrien * Construct our SIM entry. 888253790Sobrien */ 8883179029Smarius sim = cam_sim_alloc(sym_action, sym_poll, "sym", np, 8884179029Smarius device_get_unit(np->device), 8885178468Smarius &np->mtx, 1, SYM_SETUP_MAX_TAG, devq); 888653790Sobrien if (!sim) 888753790Sobrien goto fail; 888853790Sobrien 8889178468Smarius SYM_LOCK(); 8890178468Smarius 8891170872Sscottl if (xpt_bus_register(sim, np->device, 0) != CAM_SUCCESS) 889253790Sobrien goto fail; 889353790Sobrien np->sim = sim; 889453790Sobrien 8895251571Smarius if (xpt_create_path(&path, NULL, 889653790Sobrien cam_sim_path(np->sim), CAM_TARGET_WILDCARD, 889753790Sobrien CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 889853790Sobrien goto fail; 889953790Sobrien } 890053790Sobrien np->path = path; 890153790Sobrien 890253793Sobrien /* 890353790Sobrien * Establish our async notification handler. 890453790Sobrien */ 8905183895Smarius if (xpt_register_async(AC_LOST_DEVICE, sym_async, sim, path) != 8906183895Smarius CAM_REQ_CMP) 8907183895Smarius goto fail; 890862134Sgroudier 890955300Sgroudier /* 8910178466Smarius * Start the chip now, without resetting the BUS, since 891155300Sgroudier * it seems that this must stay under control of CAM. 8912178466Smarius * With LVD/SE capable chips and BUS in SE mode, we may 891355300Sgroudier * get a spurious SMBC interrupt. 891455300Sgroudier */ 891555300Sgroudier sym_init (np, 0); 891653790Sobrien 8917178468Smarius SYM_UNLOCK(); 8918179029Smarius 891953790Sobrien return 1; 892053790Sobrienfail: 892153790Sobrien if (sim) 892253790Sobrien cam_sim_free(sim, FALSE); 892353790Sobrien if (devq) 892453790Sobrien cam_simq_free(devq); 892553790Sobrien 8926178468Smarius SYM_UNLOCK(); 8927178468Smarius 892853790Sobrien sym_cam_free(np); 892953790Sobrien 893053790Sobrien return 0; 893153790Sobrien} 893253790Sobrien 893353790Sobrien/* 893453790Sobrien * Free everything that deals with CAM. 893553790Sobrien */ 8936105215Sphkstatic void sym_cam_free(hcb_p np) 893753790Sobrien{ 8938251572Smarius 8939178468Smarius SYM_LOCK_ASSERT(MA_NOTOWNED); 8940178468Smarius 8941144147Ssam if (np->intr) { 894253790Sobrien bus_teardown_intr(np->device, np->irq_res, np->intr); 8943144147Ssam np->intr = NULL; 8944144147Ssam } 8945178466Smarius 8946178468Smarius SYM_LOCK(); 8947178468Smarius 894853790Sobrien if (np->sim) { 894953790Sobrien xpt_bus_deregister(cam_sim_path(np->sim)); 895053790Sobrien cam_sim_free(np->sim, /*free_devq*/ TRUE); 8951144147Ssam np->sim = NULL; 895253790Sobrien } 8953144147Ssam if (np->path) { 895453790Sobrien xpt_free_path(np->path); 8955144147Ssam np->path = NULL; 8956144147Ssam } 8957178468Smarius 8958178468Smarius SYM_UNLOCK(); 895953790Sobrien} 896053790Sobrien 896153790Sobrien/*============ OPTIONNAL NVRAM SUPPORT =================*/ 896253790Sobrien 896353790Sobrien/* 896453790Sobrien * Get host setup from NVRAM. 896553790Sobrien */ 896653790Sobrienstatic void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram) 896753790Sobrien{ 896854690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 896953790Sobrien /* 8970178466Smarius * Get parity checking, host ID, verbose mode 897155628Sgroudier * and miscellaneous host flags from NVRAM. 897253790Sobrien */ 897353790Sobrien switch(nvram->type) { 897453790Sobrien case SYM_SYMBIOS_NVRAM: 897553790Sobrien if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE)) 897653790Sobrien np->rv_scntl0 &= ~0x0a; 897753790Sobrien np->myaddr = nvram->data.Symbios.host_id & 0x0f; 897853790Sobrien if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) 897953790Sobrien np->verbose += 1; 898055628Sgroudier if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO) 898155628Sgroudier np->usrflags |= SYM_SCAN_TARGETS_HILO; 898255628Sgroudier if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET) 898355628Sgroudier np->usrflags |= SYM_AVOID_BUS_RESET; 898453790Sobrien break; 898553790Sobrien case SYM_TEKRAM_NVRAM: 898653790Sobrien np->myaddr = nvram->data.Tekram.host_id & 0x0f; 898753790Sobrien break; 898853790Sobrien default: 898953790Sobrien break; 899053790Sobrien } 899153790Sobrien#endif 899253790Sobrien} 899353790Sobrien 899453790Sobrien/* 899553790Sobrien * Get target setup from NVRAM. 899653790Sobrien */ 899754690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 899853790Sobrienstatic void sym_Symbios_setup_target(hcb_p np,int target, Symbios_nvram *nvram); 899953790Sobrienstatic void sym_Tekram_setup_target(hcb_p np,int target, Tekram_nvram *nvram); 900053790Sobrien#endif 900153790Sobrien 900253790Sobrienstatic void 900353790Sobriensym_nvram_setup_target (hcb_p np, int target, struct sym_nvram *nvp) 900453790Sobrien{ 900554690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 900653790Sobrien switch(nvp->type) { 900753790Sobrien case SYM_SYMBIOS_NVRAM: 900853790Sobrien sym_Symbios_setup_target (np, target, &nvp->data.Symbios); 900953790Sobrien break; 901053790Sobrien case SYM_TEKRAM_NVRAM: 901153790Sobrien sym_Tekram_setup_target (np, target, &nvp->data.Tekram); 901253790Sobrien break; 901353790Sobrien default: 901453790Sobrien break; 901553790Sobrien } 901653790Sobrien#endif 901753790Sobrien} 901853790Sobrien 901954690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 902053790Sobrien/* 902153790Sobrien * Get target set-up from Symbios format NVRAM. 902253790Sobrien */ 902353790Sobrienstatic void 902453790Sobriensym_Symbios_setup_target(hcb_p np, int target, Symbios_nvram *nvram) 902553790Sobrien{ 902653790Sobrien tcb_p tp = &np->target[target]; 902753790Sobrien Symbios_target *tn = &nvram->target[target]; 902853790Sobrien 902953790Sobrien tp->tinfo.user.period = tn->sync_period ? (tn->sync_period + 3) / 4 : 0; 903053790Sobrien tp->tinfo.user.width = tn->bus_width == 0x10 ? BUS_16_BIT : BUS_8_BIT; 903153790Sobrien tp->usrtags = 903254690Sobrien (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0; 903353790Sobrien 903453790Sobrien if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE)) 903553790Sobrien tp->usrflags &= ~SYM_DISC_ENABLED; 903653790Sobrien if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)) 903753790Sobrien tp->usrflags |= SYM_SCAN_BOOT_DISABLED; 903853790Sobrien if (!(tn->flags & SYMBIOS_SCAN_LUNS)) 903953790Sobrien tp->usrflags |= SYM_SCAN_LUNS_DISABLED; 904053790Sobrien} 904153790Sobrien 904253790Sobrien/* 904353790Sobrien * Get target set-up from Tekram format NVRAM. 904453790Sobrien */ 904553790Sobrienstatic void 904653790Sobriensym_Tekram_setup_target(hcb_p np, int target, Tekram_nvram *nvram) 904753790Sobrien{ 904853790Sobrien tcb_p tp = &np->target[target]; 904953790Sobrien struct Tekram_target *tn = &nvram->target[target]; 905053790Sobrien int i; 905153790Sobrien 905253790Sobrien if (tn->flags & TEKRAM_SYNC_NEGO) { 905353790Sobrien i = tn->sync_index & 0xf; 905453790Sobrien tp->tinfo.user.period = Tekram_sync[i]; 905553790Sobrien } 905653790Sobrien 905753790Sobrien tp->tinfo.user.width = 905853790Sobrien (tn->flags & TEKRAM_WIDE_NEGO) ? BUS_16_BIT : BUS_8_BIT; 905953790Sobrien 906053790Sobrien if (tn->flags & TEKRAM_TAGGED_COMMANDS) { 906153790Sobrien tp->usrtags = 2 << nvram->max_tags_index; 906253790Sobrien } 906353790Sobrien 906453790Sobrien if (tn->flags & TEKRAM_DISCONNECT_ENABLE) 906553790Sobrien tp->usrflags |= SYM_DISC_ENABLED; 9066178466Smarius 906753790Sobrien /* If any device does not support parity, we will not use this option */ 906853790Sobrien if (!(tn->flags & TEKRAM_PARITY_CHECK)) 906953790Sobrien np->rv_scntl0 &= ~0x0a; /* SCSI parity checking disabled */ 907053790Sobrien} 907153790Sobrien 907254690Sobrien#ifdef SYM_CONF_DEBUG_NVRAM 907353790Sobrien/* 907453790Sobrien * Dump Symbios format NVRAM for debugging purpose. 907553790Sobrien */ 907661051Sgroudierstatic void sym_display_Symbios_nvram(hcb_p np, Symbios_nvram *nvram) 907753790Sobrien{ 907853790Sobrien int i; 907953790Sobrien 908053790Sobrien /* display Symbios nvram host data */ 908155628Sgroudier printf("%s: HOST ID=%d%s%s%s%s%s%s\n", 908253790Sobrien sym_name(np), nvram->host_id & 0x0f, 908353790Sobrien (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 908453790Sobrien (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", 9085178466Smarius (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", 9086178466Smarius (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", 908755628Sgroudier (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"", 908853790Sobrien (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); 908953790Sobrien 909053790Sobrien /* display Symbios nvram drive data */ 909153790Sobrien for (i = 0 ; i < 15 ; i++) { 909253790Sobrien struct Symbios_target *tn = &nvram->target[i]; 909353790Sobrien printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", 909453790Sobrien sym_name(np), i, 909553790Sobrien (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", 909653790Sobrien (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", 909753790Sobrien (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "", 909853790Sobrien (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "", 909953790Sobrien tn->bus_width, 910053790Sobrien tn->sync_period / 4, 910153790Sobrien tn->timeout); 910253790Sobrien } 910353790Sobrien} 910453790Sobrien 910553790Sobrien/* 910653790Sobrien * Dump TEKRAM format NVRAM for debugging purpose. 910753790Sobrien */ 9108179029Smariusstatic const u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120}; 910961051Sgroudierstatic void sym_display_Tekram_nvram(hcb_p np, Tekram_nvram *nvram) 911053790Sobrien{ 911153790Sobrien int i, tags, boot_delay; 911253790Sobrien char *rem; 911353790Sobrien 911453790Sobrien /* display Tekram nvram host data */ 911553790Sobrien tags = 2 << nvram->max_tags_index; 911653790Sobrien boot_delay = 0; 911753790Sobrien if (nvram->boot_delay_index < 6) 911853790Sobrien boot_delay = Tekram_boot_delay[nvram->boot_delay_index]; 911953790Sobrien switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) { 912053790Sobrien default: 912153790Sobrien case 0: rem = ""; break; 912253790Sobrien case 1: rem = " REMOVABLE=boot device"; break; 912353790Sobrien case 2: rem = " REMOVABLE=all"; break; 912453790Sobrien } 912553790Sobrien 912653790Sobrien printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", 912753790Sobrien sym_name(np), nvram->host_id & 0x0f, 912853790Sobrien (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 912953790Sobrien (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES" :"", 913053790Sobrien (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"", 913153790Sobrien (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"", 913253790Sobrien (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"", 913353790Sobrien (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"", 913453790Sobrien (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"", 913553790Sobrien (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"", 913653790Sobrien rem, boot_delay, tags); 913753790Sobrien 913853790Sobrien /* display Tekram nvram drive data */ 913953790Sobrien for (i = 0; i <= 15; i++) { 914053790Sobrien int sync, j; 914153790Sobrien struct Tekram_target *tn = &nvram->target[i]; 914253790Sobrien j = tn->sync_index & 0xf; 914353790Sobrien sync = Tekram_sync[j]; 914453790Sobrien printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n", 914553790Sobrien sym_name(np), i, 914653790Sobrien (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", 914753790Sobrien (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", 914853790Sobrien (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "", 914953790Sobrien (tn->flags & TEKRAM_START_CMD) ? " START" : "", 915053790Sobrien (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "", 915153790Sobrien (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "", 915253790Sobrien sync); 915353790Sobrien } 915453790Sobrien} 915554690Sobrien#endif /* SYM_CONF_DEBUG_NVRAM */ 915654690Sobrien#endif /* SYM_CONF_NVRAM_SUPPORT */ 915753790Sobrien 915853790Sobrien/* 915953790Sobrien * Try reading Symbios or Tekram NVRAM 916053790Sobrien */ 916154690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 916253790Sobrienstatic int sym_read_Symbios_nvram (hcb_p np, Symbios_nvram *nvram); 916353790Sobrienstatic int sym_read_Tekram_nvram (hcb_p np, Tekram_nvram *nvram); 916453790Sobrien#endif 916553790Sobrien 9166105215Sphkstatic int sym_read_nvram(hcb_p np, struct sym_nvram *nvp) 916753790Sobrien{ 916854690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 916953790Sobrien /* 917053790Sobrien * Try to read SYMBIOS nvram. 917153790Sobrien * Try to read TEKRAM nvram if Symbios nvram not found. 917253790Sobrien */ 917354690Sobrien if (SYM_SETUP_SYMBIOS_NVRAM && 917461051Sgroudier !sym_read_Symbios_nvram (np, &nvp->data.Symbios)) { 917553790Sobrien nvp->type = SYM_SYMBIOS_NVRAM; 917661051Sgroudier#ifdef SYM_CONF_DEBUG_NVRAM 917761051Sgroudier sym_display_Symbios_nvram(np, &nvp->data.Symbios); 917861051Sgroudier#endif 917961051Sgroudier } 918054690Sobrien else if (SYM_SETUP_TEKRAM_NVRAM && 918161051Sgroudier !sym_read_Tekram_nvram (np, &nvp->data.Tekram)) { 918253790Sobrien nvp->type = SYM_TEKRAM_NVRAM; 918361051Sgroudier#ifdef SYM_CONF_DEBUG_NVRAM 918461051Sgroudier sym_display_Tekram_nvram(np, &nvp->data.Tekram); 918561051Sgroudier#endif 918661051Sgroudier } 918753790Sobrien else 918853790Sobrien nvp->type = 0; 918953790Sobrien#else 919053790Sobrien nvp->type = 0; 919153790Sobrien#endif 919253790Sobrien return nvp->type; 919353790Sobrien} 919453790Sobrien 919554690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 919653790Sobrien/* 919753790Sobrien * 24C16 EEPROM reading. 919853790Sobrien * 919953790Sobrien * GPOI0 - data in/data out 920053790Sobrien * GPIO1 - clock 920153790Sobrien * Symbios NVRAM wiring now also used by Tekram. 920253790Sobrien */ 920353790Sobrien 920453790Sobrien#define SET_BIT 0 920553790Sobrien#define CLR_BIT 1 920653790Sobrien#define SET_CLK 2 920753790Sobrien#define CLR_CLK 3 920853790Sobrien 920953790Sobrien/* 921053790Sobrien * Set/clear data/clock bit in GPIO0 921153790Sobrien */ 9212178466Smariusstatic void S24C16_set_bit(hcb_p np, u_char write_bit, u_char *gpreg, 921353790Sobrien int bit_mode) 921453790Sobrien{ 921553790Sobrien UDELAY (5); 921653790Sobrien switch (bit_mode){ 921753790Sobrien case SET_BIT: 921853790Sobrien *gpreg |= write_bit; 921953790Sobrien break; 922053790Sobrien case CLR_BIT: 922153790Sobrien *gpreg &= 0xfe; 922253790Sobrien break; 922353790Sobrien case SET_CLK: 922453790Sobrien *gpreg |= 0x02; 922553790Sobrien break; 922653790Sobrien case CLR_CLK: 922753790Sobrien *gpreg &= 0xfd; 922853790Sobrien break; 922953790Sobrien 923053790Sobrien } 923153790Sobrien OUTB (nc_gpreg, *gpreg); 923253790Sobrien UDELAY (5); 923353790Sobrien} 923453790Sobrien 923553790Sobrien/* 923653790Sobrien * Send START condition to NVRAM to wake it up. 923753790Sobrien */ 923853790Sobrienstatic void S24C16_start(hcb_p np, u_char *gpreg) 923953790Sobrien{ 924053790Sobrien S24C16_set_bit(np, 1, gpreg, SET_BIT); 924153790Sobrien S24C16_set_bit(np, 0, gpreg, SET_CLK); 924253790Sobrien S24C16_set_bit(np, 0, gpreg, CLR_BIT); 924353790Sobrien S24C16_set_bit(np, 0, gpreg, CLR_CLK); 924453790Sobrien} 924553790Sobrien 924653790Sobrien/* 924753790Sobrien * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! 924853790Sobrien */ 924953790Sobrienstatic void S24C16_stop(hcb_p np, u_char *gpreg) 925053790Sobrien{ 925153790Sobrien S24C16_set_bit(np, 0, gpreg, SET_CLK); 925253790Sobrien S24C16_set_bit(np, 1, gpreg, SET_BIT); 925353790Sobrien} 925453790Sobrien 925553790Sobrien/* 925653790Sobrien * Read or write a bit to the NVRAM, 925753790Sobrien * read if GPIO0 input else write if GPIO0 output 925853790Sobrien */ 9259178466Smariusstatic void S24C16_do_bit(hcb_p np, u_char *read_bit, u_char write_bit, 926053790Sobrien u_char *gpreg) 926153790Sobrien{ 926253790Sobrien S24C16_set_bit(np, write_bit, gpreg, SET_BIT); 926353790Sobrien S24C16_set_bit(np, 0, gpreg, SET_CLK); 926453790Sobrien if (read_bit) 926553790Sobrien *read_bit = INB (nc_gpreg); 926653790Sobrien S24C16_set_bit(np, 0, gpreg, CLR_CLK); 926753790Sobrien S24C16_set_bit(np, 0, gpreg, CLR_BIT); 926853790Sobrien} 926953790Sobrien 927053790Sobrien/* 927153790Sobrien * Output an ACK to the NVRAM after reading, 927253790Sobrien * change GPIO0 to output and when done back to an input 927353790Sobrien */ 9274178466Smariusstatic void S24C16_write_ack(hcb_p np, u_char write_bit, u_char *gpreg, 927553790Sobrien u_char *gpcntl) 927653790Sobrien{ 927753790Sobrien OUTB (nc_gpcntl, *gpcntl & 0xfe); 927853790Sobrien S24C16_do_bit(np, 0, write_bit, gpreg); 927953790Sobrien OUTB (nc_gpcntl, *gpcntl); 928053790Sobrien} 928153790Sobrien 928253790Sobrien/* 928353790Sobrien * Input an ACK from NVRAM after writing, 928453790Sobrien * change GPIO0 to input and when done back to an output 928553790Sobrien */ 9286178466Smariusstatic void S24C16_read_ack(hcb_p np, u_char *read_bit, u_char *gpreg, 928753790Sobrien u_char *gpcntl) 928853790Sobrien{ 928953790Sobrien OUTB (nc_gpcntl, *gpcntl | 0x01); 929053790Sobrien S24C16_do_bit(np, read_bit, 1, gpreg); 929153790Sobrien OUTB (nc_gpcntl, *gpcntl); 929253790Sobrien} 929353790Sobrien 929453790Sobrien/* 929553790Sobrien * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, 929653790Sobrien * GPIO0 must already be set as an output 929753790Sobrien */ 9298178466Smariusstatic void S24C16_write_byte(hcb_p np, u_char *ack_data, u_char write_data, 929953790Sobrien u_char *gpreg, u_char *gpcntl) 930053790Sobrien{ 930153790Sobrien int x; 9302178466Smarius 930353790Sobrien for (x = 0; x < 8; x++) 930453790Sobrien S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg); 9305178466Smarius 930653790Sobrien S24C16_read_ack(np, ack_data, gpreg, gpcntl); 930753790Sobrien} 930853790Sobrien 930953790Sobrien/* 931053790Sobrien * READ a byte from the NVRAM and then send an ACK to say we have got it, 931153790Sobrien * GPIO0 must already be set as an input 931253790Sobrien */ 9313178466Smariusstatic void S24C16_read_byte(hcb_p np, u_char *read_data, u_char ack_data, 931453790Sobrien u_char *gpreg, u_char *gpcntl) 931553790Sobrien{ 931653790Sobrien int x; 931753790Sobrien u_char read_bit; 931853790Sobrien 931953790Sobrien *read_data = 0; 932053790Sobrien for (x = 0; x < 8; x++) { 932153790Sobrien S24C16_do_bit(np, &read_bit, 1, gpreg); 932253790Sobrien *read_data |= ((read_bit & 0x01) << (7 - x)); 932353790Sobrien } 932453790Sobrien 932553790Sobrien S24C16_write_ack(np, ack_data, gpreg, gpcntl); 932653790Sobrien} 932753790Sobrien 932853790Sobrien/* 932953790Sobrien * Read 'len' bytes starting at 'offset'. 933053790Sobrien */ 933153790Sobrienstatic int sym_read_S24C16_nvram (hcb_p np, int offset, u_char *data, int len) 933253790Sobrien{ 933353790Sobrien u_char gpcntl, gpreg; 933453790Sobrien u_char old_gpcntl, old_gpreg; 933553790Sobrien u_char ack_data; 933653790Sobrien int retv = 1; 933753790Sobrien int x; 933853790Sobrien 933953790Sobrien /* save current state of GPCNTL and GPREG */ 934053790Sobrien old_gpreg = INB (nc_gpreg); 934153790Sobrien old_gpcntl = INB (nc_gpcntl); 934279042Sgroudier gpcntl = old_gpcntl & 0x1c; 934353790Sobrien 934453790Sobrien /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ 934553790Sobrien OUTB (nc_gpreg, old_gpreg); 934653790Sobrien OUTB (nc_gpcntl, gpcntl); 934753790Sobrien 934853790Sobrien /* this is to set NVRAM into a known state with GPIO0/1 both low */ 934953790Sobrien gpreg = old_gpreg; 935053790Sobrien S24C16_set_bit(np, 0, &gpreg, CLR_CLK); 935153790Sobrien S24C16_set_bit(np, 0, &gpreg, CLR_BIT); 9352178466Smarius 935353790Sobrien /* now set NVRAM inactive with GPIO0/1 both high */ 935453790Sobrien S24C16_stop(np, &gpreg); 9355178466Smarius 935653790Sobrien /* activate NVRAM */ 935753790Sobrien S24C16_start(np, &gpreg); 935853790Sobrien 935953790Sobrien /* write device code and random address MSB */ 936053790Sobrien S24C16_write_byte(np, &ack_data, 936153790Sobrien 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 936253790Sobrien if (ack_data & 0x01) 936353790Sobrien goto out; 936453790Sobrien 936553790Sobrien /* write random address LSB */ 936653790Sobrien S24C16_write_byte(np, &ack_data, 936755300Sgroudier offset & 0xff, &gpreg, &gpcntl); 936853790Sobrien if (ack_data & 0x01) 936953790Sobrien goto out; 937053790Sobrien 937153790Sobrien /* regenerate START state to set up for reading */ 937253790Sobrien S24C16_start(np, &gpreg); 9373178466Smarius 937453790Sobrien /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ 937553790Sobrien S24C16_write_byte(np, &ack_data, 937653790Sobrien 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 937753790Sobrien if (ack_data & 0x01) 937853790Sobrien goto out; 937953790Sobrien 938053790Sobrien /* now set up GPIO0 for inputting data */ 938153790Sobrien gpcntl |= 0x01; 938253790Sobrien OUTB (nc_gpcntl, gpcntl); 9383178466Smarius 938453790Sobrien /* input all requested data - only part of total NVRAM */ 9385178466Smarius for (x = 0; x < len; x++) 938653790Sobrien S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl); 938753790Sobrien 938853790Sobrien /* finally put NVRAM back in inactive mode */ 938953790Sobrien gpcntl &= 0xfe; 939053790Sobrien OUTB (nc_gpcntl, gpcntl); 939153790Sobrien S24C16_stop(np, &gpreg); 939253790Sobrien retv = 0; 939353790Sobrienout: 939453790Sobrien /* return GPIO0/1 to original states after having accessed NVRAM */ 939553790Sobrien OUTB (nc_gpcntl, old_gpcntl); 939653790Sobrien OUTB (nc_gpreg, old_gpreg); 939753790Sobrien 939853790Sobrien return retv; 939953790Sobrien} 940053790Sobrien 940187796Sjhb#undef SET_BIT /* 0 */ 940287796Sjhb#undef CLR_BIT /* 1 */ 940387796Sjhb#undef SET_CLK /* 2 */ 940487796Sjhb#undef CLR_CLK /* 3 */ 940553790Sobrien 940653790Sobrien/* 940753790Sobrien * Try reading Symbios NVRAM. 940853790Sobrien * Return 0 if OK. 940953790Sobrien */ 941053790Sobrienstatic int sym_read_Symbios_nvram (hcb_p np, Symbios_nvram *nvram) 941153790Sobrien{ 941253790Sobrien static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; 941353790Sobrien u_char *data = (u_char *) nvram; 941453790Sobrien int len = sizeof(*nvram); 941553790Sobrien u_short csum; 941653790Sobrien int x; 941753790Sobrien 941853790Sobrien /* probe the 24c16 and read the SYMBIOS 24c16 area */ 941953790Sobrien if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len)) 942053790Sobrien return 1; 942153790Sobrien 942253790Sobrien /* check valid NVRAM signature, verify byte count and checksum */ 942353790Sobrien if (nvram->type != 0 || 942453796Sobrien bcmp(nvram->trailer, Symbios_trailer, 6) || 942553790Sobrien nvram->byte_count != len - 12) 942653790Sobrien return 1; 942753790Sobrien 942853790Sobrien /* verify checksum */ 942953790Sobrien for (x = 6, csum = 0; x < len - 6; x++) 943053790Sobrien csum += data[x]; 943153790Sobrien if (csum != nvram->checksum) 943253790Sobrien return 1; 943353790Sobrien 943453790Sobrien return 0; 943553790Sobrien} 943653790Sobrien 943753790Sobrien/* 943853790Sobrien * 93C46 EEPROM reading. 943953790Sobrien * 944053790Sobrien * GPOI0 - data in 944153790Sobrien * GPIO1 - data out 944253790Sobrien * GPIO2 - clock 944353790Sobrien * GPIO4 - chip select 944453790Sobrien * 944553790Sobrien * Used by Tekram. 944653790Sobrien */ 944753790Sobrien 944853790Sobrien/* 944953790Sobrien * Pulse clock bit in GPIO0 945053790Sobrien */ 945153790Sobrienstatic void T93C46_Clk(hcb_p np, u_char *gpreg) 945253790Sobrien{ 945353790Sobrien OUTB (nc_gpreg, *gpreg | 0x04); 945453790Sobrien UDELAY (2); 945553790Sobrien OUTB (nc_gpreg, *gpreg); 945653790Sobrien} 945753790Sobrien 9458178466Smarius/* 945953790Sobrien * Read bit from NVRAM 946053790Sobrien */ 946153790Sobrienstatic void T93C46_Read_Bit(hcb_p np, u_char *read_bit, u_char *gpreg) 946253790Sobrien{ 946353790Sobrien UDELAY (2); 946453790Sobrien T93C46_Clk(np, gpreg); 946553790Sobrien *read_bit = INB (nc_gpreg); 946653790Sobrien} 946753790Sobrien 946853790Sobrien/* 946953790Sobrien * Write bit to GPIO0 947053790Sobrien */ 947153790Sobrienstatic void T93C46_Write_Bit(hcb_p np, u_char write_bit, u_char *gpreg) 947253790Sobrien{ 947353790Sobrien if (write_bit & 0x01) 947453790Sobrien *gpreg |= 0x02; 947553790Sobrien else 947653790Sobrien *gpreg &= 0xfd; 9477178466Smarius 947853790Sobrien *gpreg |= 0x10; 9479178466Smarius 948053790Sobrien OUTB (nc_gpreg, *gpreg); 948153790Sobrien UDELAY (2); 948253790Sobrien 948353790Sobrien T93C46_Clk(np, gpreg); 948453790Sobrien} 948553790Sobrien 948653790Sobrien/* 948753790Sobrien * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! 948853790Sobrien */ 948953790Sobrienstatic void T93C46_Stop(hcb_p np, u_char *gpreg) 949053790Sobrien{ 949153790Sobrien *gpreg &= 0xef; 949253790Sobrien OUTB (nc_gpreg, *gpreg); 949353790Sobrien UDELAY (2); 949453790Sobrien 949553790Sobrien T93C46_Clk(np, gpreg); 949653790Sobrien} 949753790Sobrien 949853790Sobrien/* 949953790Sobrien * Send read command and address to NVRAM 950053790Sobrien */ 9501178466Smariusstatic void T93C46_Send_Command(hcb_p np, u_short write_data, 950253790Sobrien u_char *read_bit, u_char *gpreg) 950353790Sobrien{ 950453790Sobrien int x; 950553790Sobrien 950653790Sobrien /* send 9 bits, start bit (1), command (2), address (6) */ 950753790Sobrien for (x = 0; x < 9; x++) 950853790Sobrien T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); 950953790Sobrien 951053790Sobrien *read_bit = INB (nc_gpreg); 951153790Sobrien} 951253790Sobrien 951353790Sobrien/* 951453790Sobrien * READ 2 bytes from the NVRAM 951553790Sobrien */ 951653790Sobrienstatic void T93C46_Read_Word(hcb_p np, u_short *nvram_data, u_char *gpreg) 951753790Sobrien{ 951853790Sobrien int x; 951953790Sobrien u_char read_bit; 952053790Sobrien 952153790Sobrien *nvram_data = 0; 952253790Sobrien for (x = 0; x < 16; x++) { 952353790Sobrien T93C46_Read_Bit(np, &read_bit, gpreg); 952453790Sobrien 952553790Sobrien if (read_bit & 0x01) 952653790Sobrien *nvram_data |= (0x01 << (15 - x)); 952753790Sobrien else 952853790Sobrien *nvram_data &= ~(0x01 << (15 - x)); 952953790Sobrien } 953053790Sobrien} 953153790Sobrien 953253790Sobrien/* 953353790Sobrien * Read Tekram NvRAM data. 953453790Sobrien */ 953553790Sobrienstatic int T93C46_Read_Data(hcb_p np, u_short *data,int len,u_char *gpreg) 953653790Sobrien{ 953753790Sobrien u_char read_bit; 953853790Sobrien int x; 953953790Sobrien 954053790Sobrien for (x = 0; x < len; x++) { 954153790Sobrien 954253790Sobrien /* output read command and address */ 954353790Sobrien T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg); 954453790Sobrien if (read_bit & 0x01) 954553790Sobrien return 1; /* Bad */ 954653790Sobrien T93C46_Read_Word(np, &data[x], gpreg); 954753790Sobrien T93C46_Stop(np, gpreg); 954853790Sobrien } 954953790Sobrien 955053790Sobrien return 0; 955153790Sobrien} 955253790Sobrien 955353790Sobrien/* 955453790Sobrien * Try reading 93C46 Tekram NVRAM. 955553790Sobrien */ 955653790Sobrienstatic int sym_read_T93C46_nvram (hcb_p np, Tekram_nvram *nvram) 955753790Sobrien{ 955853790Sobrien u_char gpcntl, gpreg; 955953790Sobrien u_char old_gpcntl, old_gpreg; 956053790Sobrien int retv = 1; 956153790Sobrien 956253790Sobrien /* save current state of GPCNTL and GPREG */ 956353790Sobrien old_gpreg = INB (nc_gpreg); 956453790Sobrien old_gpcntl = INB (nc_gpcntl); 956553790Sobrien 956653790Sobrien /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, 956753790Sobrien 1/2/4 out */ 956853790Sobrien gpreg = old_gpreg & 0xe9; 956953790Sobrien OUTB (nc_gpreg, gpreg); 957053790Sobrien gpcntl = (old_gpcntl & 0xe9) | 0x09; 957153790Sobrien OUTB (nc_gpcntl, gpcntl); 957253790Sobrien 957353790Sobrien /* input all of NVRAM, 64 words */ 957453790Sobrien retv = T93C46_Read_Data(np, (u_short *) nvram, 957553790Sobrien sizeof(*nvram) / sizeof(short), &gpreg); 9576178466Smarius 957753790Sobrien /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ 957853790Sobrien OUTB (nc_gpcntl, old_gpcntl); 957953790Sobrien OUTB (nc_gpreg, old_gpreg); 958053790Sobrien 958153790Sobrien return retv; 958253790Sobrien} 958353790Sobrien 958453790Sobrien/* 958553790Sobrien * Try reading Tekram NVRAM. 958653790Sobrien * Return 0 if OK. 958753790Sobrien */ 958853790Sobrienstatic int sym_read_Tekram_nvram (hcb_p np, Tekram_nvram *nvram) 958953790Sobrien{ 959053790Sobrien u_char *data = (u_char *) nvram; 959153790Sobrien int len = sizeof(*nvram); 959253790Sobrien u_short csum; 959353790Sobrien int x; 959453790Sobrien 959553790Sobrien switch (np->device_id) { 959653790Sobrien case PCI_ID_SYM53C885: 959753790Sobrien case PCI_ID_SYM53C895: 959853790Sobrien case PCI_ID_SYM53C896: 959953790Sobrien x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 960053790Sobrien data, len); 960153790Sobrien break; 960253790Sobrien case PCI_ID_SYM53C875: 960353790Sobrien x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 960453790Sobrien data, len); 960553790Sobrien if (!x) 960653790Sobrien break; 960753790Sobrien default: 960853790Sobrien x = sym_read_T93C46_nvram(np, nvram); 960953790Sobrien break; 961053790Sobrien } 961153790Sobrien if (x) 961253790Sobrien return 1; 961353790Sobrien 961453790Sobrien /* verify checksum */ 961553790Sobrien for (x = 0, csum = 0; x < len - 1; x += 2) 961653790Sobrien csum += data[x] + (data[x+1] << 8); 961753790Sobrien if (csum != 0x1234) 961853790Sobrien return 1; 961953790Sobrien 962053790Sobrien return 0; 962153790Sobrien} 962253790Sobrien 962354690Sobrien#endif /* SYM_CONF_NVRAM_SUPPORT */ 9624