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> 89245275Simp#include <machine/atomic.h> 90207285Smarius 91207285Smarius#ifdef __sparc64__ 92207285Smarius#include <dev/ofw/openfirm.h> 93207285Smarius#include <machine/ofw_machdep.h> 94207285Smarius#endif 95207285Smarius 9653790Sobrien#include <sys/rman.h> 9753790Sobrien 9853790Sobrien#include <cam/cam.h> 9953790Sobrien#include <cam/cam_ccb.h> 10053790Sobrien#include <cam/cam_sim.h> 10153790Sobrien#include <cam/cam_xpt_sim.h> 10253790Sobrien#include <cam/cam_debug.h> 10353790Sobrien 10453790Sobrien#include <cam/scsi/scsi_all.h> 10553790Sobrien#include <cam/scsi/scsi_message.h> 10653790Sobrien 10753790Sobrien/* Short and quite clear integer types */ 10853790Sobrientypedef int8_t s8; 10953790Sobrientypedef int16_t s16; 11053790Sobrientypedef int32_t s32; 11153790Sobrientypedef u_int8_t u8; 11253790Sobrientypedef u_int16_t u16; 11353790Sobrientypedef u_int32_t u32; 11453790Sobrien 11561429Sgroudier/* 11661429Sgroudier * Driver definitions. 11761429Sgroudier */ 11853799Sobrien#include <dev/sym/sym_defs.h> 11959743Sgroudier#include <dev/sym/sym_fw.h> 12053790Sobrien 12153790Sobrien/* 12261429Sgroudier * IA32 architecture does not reorder STORES and prevents 123178466Smarius * LOADS from passing STORES. It is called `program order' 124178466Smarius * by Intel and allows device drivers to deal with memory 125178466Smarius * ordering by only ensuring that the code is not reordered 12661429Sgroudier * by the compiler when ordering is required. 127178466Smarius * Other architectures implement a weaker ordering that 128178466Smarius * requires memory barriers (and also IO barriers when they 12961429Sgroudier * make sense) to be used. 13053790Sobrien */ 131116857Speter#if defined __i386__ || defined __amd64__ 13261429Sgroudier#define MEMORY_BARRIER() do { ; } while(0) 13361429Sgroudier#elif defined __powerpc__ 13461429Sgroudier#define MEMORY_BARRIER() __asm__ volatile("eieio; sync" : : : "memory") 13561429Sgroudier#elif defined __ia64__ 13661429Sgroudier#define MEMORY_BARRIER() __asm__ volatile("mf.a; mf" : : : "memory") 13761429Sgroudier#elif defined __sparc64__ 13886850Sgroudier#define MEMORY_BARRIER() __asm__ volatile("membar #Sync" : : : "memory") 139244170Sgonzo#elif defined __arm__ 140245275Simp#define MEMORY_BARRIER() dmb() 14161429Sgroudier#else 14261429Sgroudier#error "Not supported platform" 14353793Sobrien#endif 14453790Sobrien 14553790Sobrien/* 14653790Sobrien * A la VMS/CAM-3 queue management. 14753790Sobrien */ 14853790Sobrientypedef struct sym_quehead { 14953790Sobrien struct sym_quehead *flink; /* Forward pointer */ 15053790Sobrien struct sym_quehead *blink; /* Backward pointer */ 15153790Sobrien} SYM_QUEHEAD; 15253790Sobrien 15353790Sobrien#define sym_que_init(ptr) do { \ 15453790Sobrien (ptr)->flink = (ptr); (ptr)->blink = (ptr); \ 15553790Sobrien} while (0) 15653790Sobrien 15753790Sobrienstatic __inline struct sym_quehead *sym_que_first(struct sym_quehead *head) 15853790Sobrien{ 159178466Smarius return (head->flink == head) ? NULL : head->flink; 16053790Sobrien} 16153790Sobrien 16253790Sobrienstatic __inline struct sym_quehead *sym_que_last(struct sym_quehead *head) 16353790Sobrien{ 164178466Smarius return (head->blink == head) ? NULL : head->blink; 16553790Sobrien} 16653790Sobrien 16753790Sobrienstatic __inline void __sym_que_add(struct sym_quehead * new, 16853790Sobrien struct sym_quehead * blink, 16953790Sobrien struct sym_quehead * flink) 17053790Sobrien{ 17153790Sobrien flink->blink = new; 17253790Sobrien new->flink = flink; 17353790Sobrien new->blink = blink; 17453790Sobrien blink->flink = new; 17553790Sobrien} 17653790Sobrien 17753790Sobrienstatic __inline void __sym_que_del(struct sym_quehead * blink, 17853790Sobrien struct sym_quehead * flink) 17953790Sobrien{ 18053790Sobrien flink->blink = blink; 18153790Sobrien blink->flink = flink; 18253790Sobrien} 18353790Sobrien 18453790Sobrienstatic __inline int sym_que_empty(struct sym_quehead *head) 18553790Sobrien{ 18653790Sobrien return head->flink == head; 18753790Sobrien} 18853790Sobrien 18953790Sobrienstatic __inline void sym_que_splice(struct sym_quehead *list, 19053790Sobrien struct sym_quehead *head) 19153790Sobrien{ 19253790Sobrien struct sym_quehead *first = list->flink; 19353790Sobrien 19453790Sobrien if (first != list) { 19553790Sobrien struct sym_quehead *last = list->blink; 19653790Sobrien struct sym_quehead *at = head->flink; 19753790Sobrien 19853790Sobrien first->blink = head; 19953790Sobrien head->flink = first; 20053790Sobrien 20153790Sobrien last->flink = at; 20253790Sobrien at->blink = last; 20353790Sobrien } 20453790Sobrien} 20553790Sobrien 20653790Sobrien#define sym_que_entry(ptr, type, member) \ 207170996Smjacob ((type *)((char *)(ptr)-(size_t)(&((type *)0)->member))) 20853790Sobrien 20953790Sobrien#define sym_insque(new, pos) __sym_que_add(new, pos, (pos)->flink) 21053790Sobrien 21153790Sobrien#define sym_remque(el) __sym_que_del((el)->blink, (el)->flink) 21253790Sobrien 21353790Sobrien#define sym_insque_head(new, head) __sym_que_add(new, head, (head)->flink) 21453790Sobrien 21553790Sobrienstatic __inline struct sym_quehead *sym_remque_head(struct sym_quehead *head) 21653790Sobrien{ 21753790Sobrien struct sym_quehead *elem = head->flink; 21853790Sobrien 21953790Sobrien if (elem != head) 22053790Sobrien __sym_que_del(head, elem->flink); 22153790Sobrien else 222178466Smarius elem = NULL; 22353790Sobrien return elem; 22453790Sobrien} 22553790Sobrien 22653790Sobrien#define sym_insque_tail(new, head) __sym_que_add(new, (head)->blink, head) 22753790Sobrien 22853790Sobrienstatic __inline struct sym_quehead *sym_remque_tail(struct sym_quehead *head) 22953790Sobrien{ 23053790Sobrien struct sym_quehead *elem = head->blink; 23153790Sobrien 23253790Sobrien if (elem != head) 23353790Sobrien __sym_que_del(elem->blink, head); 23453790Sobrien else 235178466Smarius elem = NULL; 23653790Sobrien return elem; 23753790Sobrien} 23853790Sobrien 23953790Sobrien/* 24062422Sgroudier * This one may be useful. 24153790Sobrien */ 24253790Sobrien#define FOR_EACH_QUEUED_ELEMENT(head, qp) \ 24353790Sobrien for (qp = (head)->flink; qp != (head); qp = qp->flink) 24453790Sobrien/* 24553790Sobrien * FreeBSD does not offer our kind of queue in the CAM CCB. 24653790Sobrien * So, we have to cast. 24753790Sobrien */ 24853790Sobrien#define sym_qptr(p) ((struct sym_quehead *) (p)) 24953790Sobrien 25053790Sobrien/* 25153790Sobrien * Simple bitmap operations. 252178466Smarius */ 25353790Sobrien#define sym_set_bit(p, n) (((u32 *)(p))[(n)>>5] |= (1<<((n)&0x1f))) 25453790Sobrien#define sym_clr_bit(p, n) (((u32 *)(p))[(n)>>5] &= ~(1<<((n)&0x1f))) 25553790Sobrien#define sym_is_bit(p, n) (((u32 *)(p))[(n)>>5] & (1<<((n)&0x1f))) 25653790Sobrien 25753790Sobrien/* 25853790Sobrien * Number of tasks per device we want to handle. 25953790Sobrien */ 26054690Sobrien#if SYM_CONF_MAX_TAG_ORDER > 8 26153790Sobrien#error "more than 256 tags per logical unit not allowed." 26253790Sobrien#endif 26354690Sobrien#define SYM_CONF_MAX_TASK (1<<SYM_CONF_MAX_TAG_ORDER) 26453790Sobrien 26553790Sobrien/* 26653790Sobrien * Donnot use more tasks that we can handle. 26753790Sobrien */ 26854690Sobrien#ifndef SYM_CONF_MAX_TAG 26954690Sobrien#define SYM_CONF_MAX_TAG SYM_CONF_MAX_TASK 27053790Sobrien#endif 27154690Sobrien#if SYM_CONF_MAX_TAG > SYM_CONF_MAX_TASK 27254690Sobrien#undef SYM_CONF_MAX_TAG 27354690Sobrien#define SYM_CONF_MAX_TAG SYM_CONF_MAX_TASK 27453790Sobrien#endif 27553790Sobrien 27653790Sobrien/* 27753790Sobrien * This one means 'NO TAG for this job' 27853790Sobrien */ 27953790Sobrien#define NO_TAG (256) 28053790Sobrien 28153790Sobrien/* 28253790Sobrien * Number of SCSI targets. 28353790Sobrien */ 28454690Sobrien#if SYM_CONF_MAX_TARGET > 16 28553790Sobrien#error "more than 16 targets not allowed." 28653790Sobrien#endif 28753790Sobrien 28853790Sobrien/* 28953790Sobrien * Number of logical units per target. 29053790Sobrien */ 29154690Sobrien#if SYM_CONF_MAX_LUN > 64 29253790Sobrien#error "more than 64 logical units per target not allowed." 29353790Sobrien#endif 29453790Sobrien 29553790Sobrien/* 296178466Smarius * Asynchronous pre-scaler (ns). Shall be 40 for 29753790Sobrien * the SCSI timings to be compliant. 29853790Sobrien */ 29954690Sobrien#define SYM_CONF_MIN_ASYNC (40) 30053790Sobrien 30153790Sobrien/* 30253790Sobrien * Number of entries in the START and DONE queues. 30353790Sobrien * 304178466Smarius * We limit to 1 PAGE in order to succeed allocation of 30553790Sobrien * these queues. Each entry is 8 bytes long (2 DWORDS). 30653790Sobrien */ 30754690Sobrien#ifdef SYM_CONF_MAX_START 30854690Sobrien#define SYM_CONF_MAX_QUEUE (SYM_CONF_MAX_START+2) 30953790Sobrien#else 31054690Sobrien#define SYM_CONF_MAX_QUEUE (7*SYM_CONF_MAX_TASK+2) 31154690Sobrien#define SYM_CONF_MAX_START (SYM_CONF_MAX_QUEUE-2) 31253790Sobrien#endif 31353790Sobrien 31454690Sobrien#if SYM_CONF_MAX_QUEUE > PAGE_SIZE/8 31554690Sobrien#undef SYM_CONF_MAX_QUEUE 31654690Sobrien#define SYM_CONF_MAX_QUEUE PAGE_SIZE/8 31754690Sobrien#undef SYM_CONF_MAX_START 31854690Sobrien#define SYM_CONF_MAX_START (SYM_CONF_MAX_QUEUE-2) 31953790Sobrien#endif 32053790Sobrien 32153790Sobrien/* 32253790Sobrien * For this one, we want a short name :-) 32353790Sobrien */ 32454690Sobrien#define MAX_QUEUE SYM_CONF_MAX_QUEUE 32553790Sobrien 32653790Sobrien/* 32753790Sobrien * Active debugging tags and verbosity. 32853790Sobrien */ 32953790Sobrien#define DEBUG_ALLOC (0x0001) 33053790Sobrien#define DEBUG_PHASE (0x0002) 33153790Sobrien#define DEBUG_POLL (0x0004) 33253790Sobrien#define DEBUG_QUEUE (0x0008) 33353790Sobrien#define DEBUG_RESULT (0x0010) 33453790Sobrien#define DEBUG_SCATTER (0x0020) 33553790Sobrien#define DEBUG_SCRIPT (0x0040) 33653790Sobrien#define DEBUG_TINY (0x0080) 33753790Sobrien#define DEBUG_TIMING (0x0100) 33853790Sobrien#define DEBUG_NEGO (0x0200) 33953790Sobrien#define DEBUG_TAGS (0x0400) 34053790Sobrien#define DEBUG_POINTER (0x0800) 34153790Sobrien 34253790Sobrien#if 0 34353790Sobrienstatic int sym_debug = 0; 34453790Sobrien #define DEBUG_FLAGS sym_debug 34553790Sobrien#else 34653790Sobrien/* #define DEBUG_FLAGS (0x0631) */ 34754690Sobrien #define DEBUG_FLAGS (0x0000) 34858927Sgroudier 34953790Sobrien#endif 35053790Sobrien#define sym_verbose (np->verbose) 35153790Sobrien 35253790Sobrien/* 35353790Sobrien * Insert a delay in micro-seconds and milli-seconds. 35453790Sobrien */ 35561051Sgroudierstatic void UDELAY(int us) { DELAY(us); } 35661051Sgroudierstatic void MDELAY(int ms) { while (ms--) UDELAY(1000); } 35753790Sobrien 35853790Sobrien/* 35953790Sobrien * Simple power of two buddy-like allocator. 36053790Sobrien * 361178466Smarius * This simple code is not intended to be fast, but to 36253790Sobrien * provide power of 2 aligned memory allocations. 363178466Smarius * Since the SCRIPTS processor only supplies 8 bit arithmetic, 364178466Smarius * this allocator allows simple and fast address calculations 365178466Smarius * from the SCRIPTS code. In addition, cache line alignment 36653790Sobrien * is guaranteed for power of 2 cache line size. 36753790Sobrien * 368220944Smarius * This allocator has been developed for the Linux sym53c8xx 369178466Smarius * driver, since this O/S does not provide naturally aligned 37053790Sobrien * allocations. 371178466Smarius * It has the advantage of allowing the driver to use private 372178466Smarius * pages of memory that will be useful if we ever need to deal 37362422Sgroudier * with IO MMUs for PCI. 37453790Sobrien */ 37553790Sobrien#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ 37658927Sgroudier#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */ 37753790Sobrien#if 0 37853790Sobrien#define MEMO_FREE_UNUSED /* Free unused pages immediately */ 37953790Sobrien#endif 38058927Sgroudier#define MEMO_WARN 1 38158927Sgroudier#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER) 38258927Sgroudier#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT) 38358927Sgroudier#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1) 38453790Sobrien 38558927Sgroudier#define get_pages() malloc(MEMO_CLUSTER_SIZE, M_DEVBUF, M_NOWAIT) 38658927Sgroudier#define free_pages(p) free((p), M_DEVBUF) 38753790Sobrien 38858927Sgroudiertypedef u_long m_addr_t; /* Enough bits to bit-hack addresses */ 38958927Sgroudier 39058927Sgroudiertypedef struct m_link { /* Link between free memory chunks */ 39158927Sgroudier struct m_link *next; 39258927Sgroudier} m_link_s; 39358927Sgroudier 39458927Sgroudiertypedef struct m_vtob { /* Virtual to Bus address translation */ 39558927Sgroudier struct m_vtob *next; 39658927Sgroudier bus_dmamap_t dmamap; /* Map for this chunk */ 39758927Sgroudier m_addr_t vaddr; /* Virtual address */ 39858927Sgroudier m_addr_t baddr; /* Bus physical address */ 39958927Sgroudier} m_vtob_s; 40058927Sgroudier/* Hash this stuff a bit to speed up translations */ 40158927Sgroudier#define VTOB_HASH_SHIFT 5 40258927Sgroudier#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT) 40358927Sgroudier#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1) 40458927Sgroudier#define VTOB_HASH_CODE(m) \ 40558927Sgroudier ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK) 40653790Sobrien 40758927Sgroudiertypedef struct m_pool { /* Memory pool of a given kind */ 40858927Sgroudier bus_dma_tag_t dev_dmat; /* Identifies the pool */ 40958927Sgroudier bus_dma_tag_t dmat; /* Tag for our fixed allocations */ 41058927Sgroudier m_addr_t (*getp)(struct m_pool *); 41158927Sgroudier#ifdef MEMO_FREE_UNUSED 41258927Sgroudier void (*freep)(struct m_pool *, m_addr_t); 41358927Sgroudier#endif 41458927Sgroudier#define M_GETP() mp->getp(mp) 41558927Sgroudier#define M_FREEP(p) mp->freep(mp, p) 41658927Sgroudier int nump; 41758927Sgroudier m_vtob_s *(vtob[VTOB_HASH_SIZE]); 41858927Sgroudier struct m_pool *next; 41958927Sgroudier struct m_link h[MEMO_CLUSTER_SHIFT - MEMO_SHIFT + 1]; 42058927Sgroudier} m_pool_s; 42153790Sobrien 42258927Sgroudierstatic void *___sym_malloc(m_pool_s *mp, int size) 42353790Sobrien{ 42453790Sobrien int i = 0; 42553790Sobrien int s = (1 << MEMO_SHIFT); 42653790Sobrien int j; 42758927Sgroudier m_addr_t a; 42858927Sgroudier m_link_s *h = mp->h; 42953790Sobrien 43058927Sgroudier if (size > MEMO_CLUSTER_SIZE) 431178466Smarius return NULL; 43253790Sobrien 43353790Sobrien while (size > s) { 43453790Sobrien s <<= 1; 43553790Sobrien ++i; 43653790Sobrien } 43753790Sobrien 43853790Sobrien j = i; 43953790Sobrien while (!h[j].next) { 44058927Sgroudier if (s == MEMO_CLUSTER_SIZE) { 44158927Sgroudier h[j].next = (m_link_s *) M_GETP(); 44253790Sobrien if (h[j].next) 443178466Smarius h[j].next->next = NULL; 44453790Sobrien break; 44553790Sobrien } 44653790Sobrien ++j; 44753790Sobrien s <<= 1; 44853790Sobrien } 44958927Sgroudier a = (m_addr_t) h[j].next; 45053790Sobrien if (a) { 45153790Sobrien h[j].next = h[j].next->next; 45253790Sobrien while (j > i) { 45353790Sobrien j -= 1; 45453790Sobrien s >>= 1; 45558927Sgroudier h[j].next = (m_link_s *) (a+s); 456178466Smarius h[j].next->next = NULL; 45753790Sobrien } 45853790Sobrien } 45953790Sobrien#ifdef DEBUG 46058927Sgroudier printf("___sym_malloc(%d) = %p\n", size, (void *) a); 46153790Sobrien#endif 46253790Sobrien return (void *) a; 46353790Sobrien} 46453790Sobrien 46558927Sgroudierstatic void ___sym_mfree(m_pool_s *mp, void *ptr, int size) 46653790Sobrien{ 46753790Sobrien int i = 0; 46853790Sobrien int s = (1 << MEMO_SHIFT); 46958927Sgroudier m_link_s *q; 47058927Sgroudier m_addr_t a, b; 47158927Sgroudier m_link_s *h = mp->h; 47253790Sobrien 47353790Sobrien#ifdef DEBUG 47458927Sgroudier printf("___sym_mfree(%p, %d)\n", ptr, size); 47553790Sobrien#endif 47653790Sobrien 47758927Sgroudier if (size > MEMO_CLUSTER_SIZE) 47853790Sobrien return; 47953790Sobrien 48053790Sobrien while (size > s) { 48153790Sobrien s <<= 1; 48253790Sobrien ++i; 48353790Sobrien } 48453790Sobrien 48558927Sgroudier a = (m_addr_t) ptr; 48653790Sobrien 48753790Sobrien while (1) { 48853790Sobrien#ifdef MEMO_FREE_UNUSED 48958927Sgroudier if (s == MEMO_CLUSTER_SIZE) { 49058927Sgroudier M_FREEP(a); 49153790Sobrien break; 49253790Sobrien } 49353790Sobrien#endif 49453790Sobrien b = a ^ s; 49553790Sobrien q = &h[i]; 49658927Sgroudier while (q->next && q->next != (m_link_s *) b) { 49753790Sobrien q = q->next; 49853790Sobrien } 49953790Sobrien if (!q->next) { 50058927Sgroudier ((m_link_s *) a)->next = h[i].next; 50158927Sgroudier h[i].next = (m_link_s *) a; 50253790Sobrien break; 50353790Sobrien } 50453790Sobrien q->next = q->next->next; 50553790Sobrien a = a & b; 50653790Sobrien s <<= 1; 50753790Sobrien ++i; 50853790Sobrien } 50953790Sobrien} 51053790Sobrien 51158927Sgroudierstatic void *__sym_calloc2(m_pool_s *mp, int size, char *name, int uflags) 51253790Sobrien{ 51353790Sobrien void *p; 51453790Sobrien 51558927Sgroudier p = ___sym_malloc(mp, size); 51653790Sobrien 51753790Sobrien if (DEBUG_FLAGS & DEBUG_ALLOC) 51853790Sobrien printf ("new %-10s[%4d] @%p.\n", name, size, p); 51953790Sobrien 52053790Sobrien if (p) 52153790Sobrien bzero(p, size); 52253790Sobrien else if (uflags & MEMO_WARN) 52358927Sgroudier printf ("__sym_calloc2: failed to allocate %s[%d]\n", name, size); 52453790Sobrien 52553790Sobrien return p; 52653790Sobrien} 52753790Sobrien 52858927Sgroudier#define __sym_calloc(mp, s, n) __sym_calloc2(mp, s, n, MEMO_WARN) 52953790Sobrien 53058927Sgroudierstatic void __sym_mfree(m_pool_s *mp, void *ptr, int size, char *name) 53153790Sobrien{ 53253790Sobrien if (DEBUG_FLAGS & DEBUG_ALLOC) 53353790Sobrien printf ("freeing %-10s[%4d] @%p.\n", name, size, ptr); 53453790Sobrien 53558927Sgroudier ___sym_mfree(mp, ptr, size); 53658927Sgroudier 53753790Sobrien} 53853790Sobrien 53953790Sobrien/* 54058927Sgroudier * Default memory pool we donnot need to involve in DMA. 54158927Sgroudier */ 54258927Sgroudier/* 543178466Smarius * With the `bus dma abstraction', we use a separate pool for 54458927Sgroudier * memory we donnot need to involve in DMA. 54558927Sgroudier */ 54658927Sgroudierstatic m_addr_t ___mp0_getp(m_pool_s *mp) 54758927Sgroudier{ 54858927Sgroudier m_addr_t m = (m_addr_t) get_pages(); 54958927Sgroudier if (m) 55058927Sgroudier ++mp->nump; 55158927Sgroudier return m; 55258927Sgroudier} 55358927Sgroudier 55458927Sgroudier#ifdef MEMO_FREE_UNUSED 55558927Sgroudierstatic void ___mp0_freep(m_pool_s *mp, m_addr_t m) 55658927Sgroudier{ 55758927Sgroudier free_pages(m); 55858927Sgroudier --mp->nump; 55958927Sgroudier} 56058927Sgroudier#endif 56158927Sgroudier 56258927Sgroudier#ifdef MEMO_FREE_UNUSED 56358927Sgroudierstatic m_pool_s mp0 = {0, 0, ___mp0_getp, ___mp0_freep}; 56458927Sgroudier#else 56558927Sgroudierstatic m_pool_s mp0 = {0, 0, ___mp0_getp}; 56658927Sgroudier#endif 56758927Sgroudier 56858927Sgroudier/* 56958927Sgroudier * Actual memory allocation routine for non-DMAed memory. 57058927Sgroudier */ 57158927Sgroudierstatic void *sym_calloc(int size, char *name) 57258927Sgroudier{ 57358927Sgroudier void *m; 57458927Sgroudier /* Lock */ 57558927Sgroudier m = __sym_calloc(&mp0, size, name); 57658927Sgroudier /* Unlock */ 57758927Sgroudier return m; 57858927Sgroudier} 57958927Sgroudier 58058927Sgroudier/* 58158927Sgroudier * Actual memory allocation routine for non-DMAed memory. 58258927Sgroudier */ 58358927Sgroudierstatic void sym_mfree(void *ptr, int size, char *name) 58458927Sgroudier{ 58558927Sgroudier /* Lock */ 58658927Sgroudier __sym_mfree(&mp0, ptr, size, name); 58758927Sgroudier /* Unlock */ 58858927Sgroudier} 58958927Sgroudier 59058927Sgroudier/* 59158927Sgroudier * DMAable pools. 59258927Sgroudier */ 59358927Sgroudier/* 594178466Smarius * With `bus dma abstraction', we use a separate pool per parent 595178466Smarius * BUS handle. A reverse table (hashed) is maintained for virtual 59658927Sgroudier * to BUS address translation. 59758927Sgroudier */ 598251402Smariusstatic void getbaddrcb(void *arg, bus_dma_segment_t *segs, int nseg __unused, 599251402Smarius int error) 60058927Sgroudier{ 60158927Sgroudier bus_addr_t *baddr; 602251402Smarius 603251402Smarius KASSERT(nseg == 1, ("%s: too many DMA segments (%d)", __func__, nseg)); 604251402Smarius 60558927Sgroudier baddr = (bus_addr_t *)arg; 606251402Smarius if (error) 607251402Smarius *baddr = 0; 608251402Smarius else 609251402Smarius *baddr = segs->ds_addr; 61058927Sgroudier} 61158927Sgroudier 61258927Sgroudierstatic m_addr_t ___dma_getp(m_pool_s *mp) 61358927Sgroudier{ 61458927Sgroudier m_vtob_s *vbp; 615178466Smarius void *vaddr = NULL; 616251403Smarius bus_addr_t baddr = 0; 61758927Sgroudier 61858927Sgroudier vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB"); 61958927Sgroudier if (!vbp) 62058927Sgroudier goto out_err; 62158927Sgroudier 62258927Sgroudier if (bus_dmamem_alloc(mp->dmat, &vaddr, 623178468Smarius BUS_DMA_COHERENT | BUS_DMA_WAITOK, &vbp->dmamap)) 62458927Sgroudier goto out_err; 62558927Sgroudier bus_dmamap_load(mp->dmat, vbp->dmamap, vaddr, 626171524Sse MEMO_CLUSTER_SIZE, getbaddrcb, &baddr, BUS_DMA_NOWAIT); 62758927Sgroudier if (baddr) { 62858927Sgroudier int hc = VTOB_HASH_CODE(vaddr); 62958927Sgroudier vbp->vaddr = (m_addr_t) vaddr; 63058927Sgroudier vbp->baddr = (m_addr_t) baddr; 63158927Sgroudier vbp->next = mp->vtob[hc]; 63258927Sgroudier mp->vtob[hc] = vbp; 63358927Sgroudier ++mp->nump; 63458927Sgroudier return (m_addr_t) vaddr; 63558927Sgroudier } 63658927Sgroudierout_err: 63758927Sgroudier if (baddr) 63858927Sgroudier bus_dmamap_unload(mp->dmat, vbp->dmamap); 63958927Sgroudier if (vaddr) 64058927Sgroudier bus_dmamem_free(mp->dmat, vaddr, vbp->dmamap); 641142515Ssam if (vbp) { 642142515Ssam if (vbp->dmamap) 643142515Ssam bus_dmamap_destroy(mp->dmat, vbp->dmamap); 64458927Sgroudier __sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB"); 645142515Ssam } 64658927Sgroudier return 0; 64758927Sgroudier} 64858927Sgroudier 64958927Sgroudier#ifdef MEMO_FREE_UNUSED 65058927Sgroudierstatic void ___dma_freep(m_pool_s *mp, m_addr_t m) 65158927Sgroudier{ 65258927Sgroudier m_vtob_s **vbpp, *vbp; 65358927Sgroudier int hc = VTOB_HASH_CODE(m); 65458927Sgroudier 65558927Sgroudier vbpp = &mp->vtob[hc]; 65658927Sgroudier while (*vbpp && (*vbpp)->vaddr != m) 65758927Sgroudier vbpp = &(*vbpp)->next; 65858927Sgroudier if (*vbpp) { 65958927Sgroudier vbp = *vbpp; 66058927Sgroudier *vbpp = (*vbpp)->next; 66158927Sgroudier bus_dmamap_unload(mp->dmat, vbp->dmamap); 66258927Sgroudier bus_dmamem_free(mp->dmat, (void *) vbp->vaddr, vbp->dmamap); 66358927Sgroudier bus_dmamap_destroy(mp->dmat, vbp->dmamap); 66458927Sgroudier __sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB"); 66558927Sgroudier --mp->nump; 66658927Sgroudier } 66758927Sgroudier} 66858927Sgroudier#endif 66958927Sgroudier 67062134Sgroudierstatic __inline m_pool_s *___get_dma_pool(bus_dma_tag_t dev_dmat) 67158927Sgroudier{ 67258927Sgroudier m_pool_s *mp; 67358927Sgroudier for (mp = mp0.next; mp && mp->dev_dmat != dev_dmat; mp = mp->next); 67458927Sgroudier return mp; 67558927Sgroudier} 67658927Sgroudier 67758927Sgroudierstatic m_pool_s *___cre_dma_pool(bus_dma_tag_t dev_dmat) 67858927Sgroudier{ 679178466Smarius m_pool_s *mp = NULL; 68058927Sgroudier 68158927Sgroudier mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL"); 68258927Sgroudier if (mp) { 68358927Sgroudier mp->dev_dmat = dev_dmat; 68458927Sgroudier if (!bus_dma_tag_create(dev_dmat, 1, MEMO_CLUSTER_SIZE, 68558927Sgroudier BUS_SPACE_MAXADDR_32BIT, 686171524Sse BUS_SPACE_MAXADDR, 68758927Sgroudier NULL, NULL, MEMO_CLUSTER_SIZE, 1, 688117126Sscottl MEMO_CLUSTER_SIZE, 0, 689178468Smarius NULL, NULL, &mp->dmat)) { 69058927Sgroudier mp->getp = ___dma_getp; 69158927Sgroudier#ifdef MEMO_FREE_UNUSED 69258927Sgroudier mp->freep = ___dma_freep; 69358927Sgroudier#endif 69458927Sgroudier mp->next = mp0.next; 69558927Sgroudier mp0.next = mp; 69658927Sgroudier return mp; 69758927Sgroudier } 69858927Sgroudier } 69958927Sgroudier if (mp) 70058927Sgroudier __sym_mfree(&mp0, mp, sizeof(*mp), "MPOOL"); 701178466Smarius return NULL; 70258927Sgroudier} 70358927Sgroudier 70458927Sgroudier#ifdef MEMO_FREE_UNUSED 70558927Sgroudierstatic void ___del_dma_pool(m_pool_s *p) 70658927Sgroudier{ 70758927Sgroudier struct m_pool **pp = &mp0.next; 70858927Sgroudier 70958927Sgroudier while (*pp && *pp != p) 71058927Sgroudier pp = &(*pp)->next; 71158927Sgroudier if (*pp) { 71258927Sgroudier *pp = (*pp)->next; 71358927Sgroudier bus_dma_tag_destroy(p->dmat); 71458927Sgroudier __sym_mfree(&mp0, p, sizeof(*p), "MPOOL"); 71558927Sgroudier } 71658927Sgroudier} 71758927Sgroudier#endif 71858927Sgroudier 71958927Sgroudierstatic void *__sym_calloc_dma(bus_dma_tag_t dev_dmat, int size, char *name) 72058927Sgroudier{ 72158927Sgroudier struct m_pool *mp; 722178466Smarius void *m = NULL; 72358927Sgroudier 72458927Sgroudier /* Lock */ 72558927Sgroudier mp = ___get_dma_pool(dev_dmat); 72658927Sgroudier if (!mp) 72758927Sgroudier mp = ___cre_dma_pool(dev_dmat); 72858927Sgroudier if (mp) 72958927Sgroudier m = __sym_calloc(mp, size, name); 73058927Sgroudier#ifdef MEMO_FREE_UNUSED 73158927Sgroudier if (mp && !mp->nump) 73258927Sgroudier ___del_dma_pool(mp); 73358927Sgroudier#endif 73458927Sgroudier /* Unlock */ 73558927Sgroudier 73658927Sgroudier return m; 73758927Sgroudier} 73858927Sgroudier 739178466Smariusstatic void 74058927Sgroudier__sym_mfree_dma(bus_dma_tag_t dev_dmat, void *m, int size, char *name) 74158927Sgroudier{ 74258927Sgroudier struct m_pool *mp; 74358927Sgroudier 74458927Sgroudier /* Lock */ 74558927Sgroudier mp = ___get_dma_pool(dev_dmat); 74658927Sgroudier if (mp) 74758927Sgroudier __sym_mfree(mp, m, size, name); 74858927Sgroudier#ifdef MEMO_FREE_UNUSED 74958927Sgroudier if (mp && !mp->nump) 75058927Sgroudier ___del_dma_pool(mp); 75158927Sgroudier#endif 75258927Sgroudier /* Unlock */ 75358927Sgroudier} 75458927Sgroudier 75558927Sgroudierstatic m_addr_t __vtobus(bus_dma_tag_t dev_dmat, void *m) 75658927Sgroudier{ 75758927Sgroudier m_pool_s *mp; 75858927Sgroudier int hc = VTOB_HASH_CODE(m); 759178466Smarius m_vtob_s *vp = NULL; 76058927Sgroudier m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK; 76158927Sgroudier 76258927Sgroudier /* Lock */ 76358927Sgroudier mp = ___get_dma_pool(dev_dmat); 76458927Sgroudier if (mp) { 76558927Sgroudier vp = mp->vtob[hc]; 76658927Sgroudier while (vp && (m_addr_t) vp->vaddr != a) 76758927Sgroudier vp = vp->next; 76858927Sgroudier } 76958927Sgroudier /* Unlock */ 77058927Sgroudier if (!vp) 77158927Sgroudier panic("sym: VTOBUS FAILED!\n"); 77258927Sgroudier return vp ? vp->baddr + (((m_addr_t) m) - a) : 0; 77358927Sgroudier} 77458927Sgroudier 77558927Sgroudier/* 77658927Sgroudier * Verbs for DMAable memory handling. 777178466Smarius * The _uvptv_ macro avoids a nasty warning about pointer to volatile 77858927Sgroudier * being discarded. 77958927Sgroudier */ 78058927Sgroudier#define _uvptv_(p) ((void *)((vm_offset_t)(p))) 78158927Sgroudier#define _sym_calloc_dma(np, s, n) __sym_calloc_dma(np->bus_dmat, s, n) 78258927Sgroudier#define _sym_mfree_dma(np, p, s, n) \ 78358927Sgroudier __sym_mfree_dma(np->bus_dmat, _uvptv_(p), s, n) 78458927Sgroudier#define sym_calloc_dma(s, n) _sym_calloc_dma(np, s, n) 78558927Sgroudier#define sym_mfree_dma(p, s, n) _sym_mfree_dma(np, p, s, n) 78658927Sgroudier#define _vtobus(np, p) __vtobus(np->bus_dmat, _uvptv_(p)) 78758927Sgroudier#define vtobus(p) _vtobus(np, p) 78858927Sgroudier 78958927Sgroudier/* 79053790Sobrien * Print a buffer in hexadecimal format. 79153790Sobrien */ 79253790Sobrienstatic void sym_printb_hex (u_char *p, int n) 79353790Sobrien{ 79453790Sobrien while (n-- > 0) 79553790Sobrien printf (" %x", *p++); 79653790Sobrien} 79753790Sobrien 79853790Sobrien/* 79953790Sobrien * Same with a label at beginning and .\n at end. 80053790Sobrien */ 80153790Sobrienstatic void sym_printl_hex (char *label, u_char *p, int n) 80253790Sobrien{ 80353790Sobrien printf ("%s", label); 80453790Sobrien sym_printb_hex (p, n); 80553790Sobrien printf (".\n"); 80653790Sobrien} 80753790Sobrien 80853790Sobrien/* 80955300Sgroudier * Return a string for SCSI BUS mode. 81055300Sgroudier */ 811179029Smariusstatic const char *sym_scsi_bus_mode(int mode) 81255300Sgroudier{ 81355300Sgroudier switch(mode) { 81455300Sgroudier case SMODE_HVD: return "HVD"; 81555300Sgroudier case SMODE_SE: return "SE"; 81655300Sgroudier case SMODE_LVD: return "LVD"; 81755300Sgroudier } 81855300Sgroudier return "??"; 81955300Sgroudier} 82055300Sgroudier 82155300Sgroudier/* 82261639Sgroudier * Some poor and bogus sync table that refers to Tekram NVRAM layout. 82353790Sobrien */ 82454690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 825179029Smariusstatic const u_char Tekram_sync[16] = 82653790Sobrien {25,31,37,43, 50,62,75,125, 12,15,18,21, 6,7,9,10}; 82753790Sobrien#endif 82853790Sobrien 82953790Sobrien/* 83053790Sobrien * Union of supported NVRAM formats. 83153790Sobrien */ 83253790Sobrienstruct sym_nvram { 83353790Sobrien int type; 83453790Sobrien#define SYM_SYMBIOS_NVRAM (1) 83553790Sobrien#define SYM_TEKRAM_NVRAM (2) 83654690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 83753790Sobrien union { 83853790Sobrien Symbios_nvram Symbios; 83953790Sobrien Tekram_nvram Tekram; 84053790Sobrien } data; 84153790Sobrien#endif 84253790Sobrien}; 84353790Sobrien 84453790Sobrien/* 84553790Sobrien * This one is hopefully useless, but actually useful. :-) 84653790Sobrien */ 84753790Sobrien#ifndef assert 84853790Sobrien#define assert(expression) { \ 84953790Sobrien if (!(expression)) { \ 85053790Sobrien (void)panic( \ 85153790Sobrien "assertion \"%s\" failed: file \"%s\", line %d\n", \ 85253790Sobrien #expression, \ 85353790Sobrien __FILE__, __LINE__); \ 85453790Sobrien } \ 85553790Sobrien} 85653790Sobrien#endif 85753790Sobrien 85853790Sobrien/* 859178466Smarius * Some provision for a possible big endian mode supported by 86061429Sgroudier * Symbios chips (never seen, by the way). 86153790Sobrien * For now, this stuff does not deserve any comments. :) 86253790Sobrien */ 86353790Sobrien#define sym_offb(o) (o) 86453790Sobrien#define sym_offw(o) (o) 86553790Sobrien 86661429Sgroudier/* 86761429Sgroudier * Some provision for support for BIG ENDIAN CPU. 86861429Sgroudier */ 869153145Sscottl#define cpu_to_scr(dw) htole32(dw) 870153145Sscottl#define scr_to_cpu(dw) le32toh(dw) 87153790Sobrien 87253790Sobrien/* 87361429Sgroudier * Access to the chip IO registers and on-chip RAM. 874178466Smarius * We use the `bus space' interface under FreeBSD-4 and 87561429Sgroudier * later kernel versions. 87653790Sobrien */ 87761429Sgroudier#if defined(SYM_CONF_IOMAPPED) 87861429Sgroudier 879178468Smarius#define INB_OFF(o) bus_read_1(np->io_res, (o)) 880178468Smarius#define INW_OFF(o) bus_read_2(np->io_res, (o)) 881178468Smarius#define INL_OFF(o) bus_read_4(np->io_res, (o)) 88261429Sgroudier 883178468Smarius#define OUTB_OFF(o, v) bus_write_1(np->io_res, (o), (v)) 884178468Smarius#define OUTW_OFF(o, v) bus_write_2(np->io_res, (o), (v)) 885178468Smarius#define OUTL_OFF(o, v) bus_write_4(np->io_res, (o), (v)) 88661429Sgroudier 88761429Sgroudier#else /* Memory mapped IO */ 88861429Sgroudier 889178468Smarius#define INB_OFF(o) bus_read_1(np->mmio_res, (o)) 890178468Smarius#define INW_OFF(o) bus_read_2(np->mmio_res, (o)) 891178468Smarius#define INL_OFF(o) bus_read_4(np->mmio_res, (o)) 89261429Sgroudier 893178468Smarius#define OUTB_OFF(o, v) bus_write_1(np->mmio_res, (o), (v)) 894178468Smarius#define OUTW_OFF(o, v) bus_write_2(np->mmio_res, (o), (v)) 895178468Smarius#define OUTL_OFF(o, v) bus_write_4(np->mmio_res, (o), (v)) 89661429Sgroudier 89761429Sgroudier#endif /* SYM_CONF_IOMAPPED */ 89861429Sgroudier 89961429Sgroudier#define OUTRAM_OFF(o, a, l) \ 900178468Smarius bus_write_region_1(np->ram_res, (o), (a), (l)) 90161429Sgroudier 90253790Sobrien/* 90361429Sgroudier * Common definitions for both bus space and legacy IO methods. 90453790Sobrien */ 90553790Sobrien#define INB(r) INB_OFF(offsetof(struct sym_reg,r)) 90653790Sobrien#define INW(r) INW_OFF(offsetof(struct sym_reg,r)) 90753790Sobrien#define INL(r) INL_OFF(offsetof(struct sym_reg,r)) 90853790Sobrien 90953790Sobrien#define OUTB(r, v) OUTB_OFF(offsetof(struct sym_reg,r), (v)) 91053790Sobrien#define OUTW(r, v) OUTW_OFF(offsetof(struct sym_reg,r), (v)) 91153790Sobrien#define OUTL(r, v) OUTL_OFF(offsetof(struct sym_reg,r), (v)) 91253790Sobrien 91353790Sobrien#define OUTONB(r, m) OUTB(r, INB(r) | (m)) 91453790Sobrien#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m)) 91553790Sobrien#define OUTONW(r, m) OUTW(r, INW(r) | (m)) 91653790Sobrien#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m)) 91753790Sobrien#define OUTONL(r, m) OUTL(r, INL(r) | (m)) 91853790Sobrien#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m)) 91953790Sobrien 92053790Sobrien/* 92161429Sgroudier * We normally want the chip to have a consistent view 92261429Sgroudier * of driver internal data structures when we restart it. 92361429Sgroudier * Thus these macros. 92461429Sgroudier */ 92561429Sgroudier#define OUTL_DSP(v) \ 92661429Sgroudier do { \ 92761429Sgroudier MEMORY_BARRIER(); \ 92861429Sgroudier OUTL (nc_dsp, (v)); \ 92961429Sgroudier } while (0) 93061429Sgroudier 93161429Sgroudier#define OUTONB_STD() \ 93261429Sgroudier do { \ 93361429Sgroudier MEMORY_BARRIER(); \ 93461429Sgroudier OUTONB (nc_dcntl, (STD|NOCOM)); \ 93561429Sgroudier } while (0) 93661429Sgroudier 93761429Sgroudier/* 93853790Sobrien * Command control block states. 93953790Sobrien */ 94053790Sobrien#define HS_IDLE (0) 94153790Sobrien#define HS_BUSY (1) 94253790Sobrien#define HS_NEGOTIATE (2) /* sync/wide data transfer*/ 94353790Sobrien#define HS_DISCONNECT (3) /* Disconnected by target */ 94458927Sgroudier#define HS_WAIT (4) /* waiting for resource */ 94553790Sobrien 94653790Sobrien#define HS_DONEMASK (0x80) 94753790Sobrien#define HS_COMPLETE (4|HS_DONEMASK) 94853790Sobrien#define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */ 94953790Sobrien#define HS_UNEXPECTED (6|HS_DONEMASK) /* Unexpected disconnect */ 95053790Sobrien#define HS_COMP_ERR (7|HS_DONEMASK) /* Completed with error */ 95153790Sobrien 95253790Sobrien/* 95353790Sobrien * Software Interrupt Codes 95453790Sobrien */ 95553790Sobrien#define SIR_BAD_SCSI_STATUS (1) 95653790Sobrien#define SIR_SEL_ATN_NO_MSG_OUT (2) 95753790Sobrien#define SIR_MSG_RECEIVED (3) 95853790Sobrien#define SIR_MSG_WEIRD (4) 95953790Sobrien#define SIR_NEGO_FAILED (5) 96053790Sobrien#define SIR_NEGO_PROTO (6) 96153790Sobrien#define SIR_SCRIPT_STOPPED (7) 96253790Sobrien#define SIR_REJECT_TO_SEND (8) 96353790Sobrien#define SIR_SWIDE_OVERRUN (9) 96453790Sobrien#define SIR_SODL_UNDERRUN (10) 96553790Sobrien#define SIR_RESEL_NO_MSG_IN (11) 96653790Sobrien#define SIR_RESEL_NO_IDENTIFY (12) 96753790Sobrien#define SIR_RESEL_BAD_LUN (13) 96853790Sobrien#define SIR_TARGET_SELECTED (14) 96953790Sobrien#define SIR_RESEL_BAD_I_T_L (15) 97053790Sobrien#define SIR_RESEL_BAD_I_T_L_Q (16) 97153790Sobrien#define SIR_ABORT_SENT (17) 97253790Sobrien#define SIR_RESEL_ABORTED (18) 97353790Sobrien#define SIR_MSG_OUT_DONE (19) 97453790Sobrien#define SIR_COMPLETE_ERROR (20) 97559252Sgroudier#define SIR_DATA_OVERRUN (21) 97659252Sgroudier#define SIR_BAD_PHASE (22) 97759252Sgroudier#define SIR_MAX (22) 97853790Sobrien 97953790Sobrien/* 98053790Sobrien * Extended error bit codes. 98153790Sobrien * xerr_status field of struct sym_ccb. 98253790Sobrien */ 98353790Sobrien#define XE_EXTRA_DATA (1) /* unexpected data phase */ 98453790Sobrien#define XE_BAD_PHASE (1<<1) /* illegal phase (4/5) */ 98553790Sobrien#define XE_PARITY_ERR (1<<2) /* unrecovered SCSI parity error */ 98653790Sobrien#define XE_SODL_UNRUN (1<<3) /* ODD transfer in DATA OUT phase */ 98753790Sobrien#define XE_SWIDE_OVRUN (1<<4) /* ODD transfer in DATA IN phase */ 98853790Sobrien 98953790Sobrien/* 99053790Sobrien * Negotiation status. 99153790Sobrien * nego_status field of struct sym_ccb. 99253790Sobrien */ 99353790Sobrien#define NS_SYNC (1) 99453790Sobrien#define NS_WIDE (2) 99553790Sobrien#define NS_PPR (3) 99653790Sobrien 99753790Sobrien/* 998178466Smarius * A CCB hashed table is used to retrieve CCB address 99953790Sobrien * from DSA value. 100053790Sobrien */ 100153790Sobrien#define CCB_HASH_SHIFT 8 100253790Sobrien#define CCB_HASH_SIZE (1UL << CCB_HASH_SHIFT) 100353790Sobrien#define CCB_HASH_MASK (CCB_HASH_SIZE-1) 100453790Sobrien#define CCB_HASH_CODE(dsa) (((dsa) >> 9) & CCB_HASH_MASK) 100553790Sobrien 100653790Sobrien/* 100753790Sobrien * Device flags. 100853790Sobrien */ 100953790Sobrien#define SYM_DISC_ENABLED (1) 101053790Sobrien#define SYM_TAGS_ENABLED (1<<1) 101153790Sobrien#define SYM_SCAN_BOOT_DISABLED (1<<2) 101253790Sobrien#define SYM_SCAN_LUNS_DISABLED (1<<3) 101353790Sobrien 101453790Sobrien/* 101555628Sgroudier * Host adapter miscellaneous flags. 101655628Sgroudier */ 101755628Sgroudier#define SYM_AVOID_BUS_RESET (1) 101855628Sgroudier#define SYM_SCAN_TARGETS_HILO (1<<1) 101955628Sgroudier 102055628Sgroudier/* 102153790Sobrien * Device quirks. 1022178466Smarius * Some devices, for example the CHEETAH 2 LVD, disconnects without 102362422Sgroudier * saving the DATA POINTER then reselects and terminates the IO. 1024178466Smarius * On reselection, the automatic RESTORE DATA POINTER makes the 102553790Sobrien * CURRENT DATA POINTER not point at the end of the IO. 102653790Sobrien * This behaviour just breaks our calculation of the residual. 1027178466Smarius * For now, we just force an AUTO SAVE on disconnection and will 102853790Sobrien * fix that in a further driver version. 102953790Sobrien */ 103053790Sobrien#define SYM_QUIRK_AUTOSAVE 1 103153790Sobrien 103253790Sobrien/* 103353790Sobrien * Misc. 103453790Sobrien */ 1035178468Smarius#define SYM_LOCK() mtx_lock(&np->mtx) 1036178468Smarius#define SYM_LOCK_ASSERT(_what) mtx_assert(&np->mtx, (_what)) 1037178468Smarius#define SYM_LOCK_DESTROY() mtx_destroy(&np->mtx) 1038178468Smarius#define SYM_LOCK_INIT() mtx_init(&np->mtx, "sym_lock", NULL, MTX_DEF) 1039178468Smarius#define SYM_LOCK_INITIALIZED() mtx_initialized(&np->mtx) 1040178468Smarius#define SYM_UNLOCK() mtx_unlock(&np->mtx) 1041178468Smarius 104253790Sobrien#define SYM_SNOOP_TIMEOUT (10000000) 1043119690Sjhb#define SYM_PCI_IO PCIR_BAR(0) 1044119690Sjhb#define SYM_PCI_MMIO PCIR_BAR(1) 1045119690Sjhb#define SYM_PCI_RAM PCIR_BAR(2) 1046119690Sjhb#define SYM_PCI_RAM64 PCIR_BAR(3) 104753790Sobrien 104853790Sobrien/* 104953790Sobrien * Back-pointer from the CAM CCB to our data structures. 105053790Sobrien */ 105153790Sobrien#define sym_hcb_ptr spriv_ptr0 105253790Sobrien/* #define sym_ccb_ptr spriv_ptr1 */ 105353790Sobrien 105453790Sobrien/* 105553790Sobrien * We mostly have to deal with pointers. 105653790Sobrien * Thus these typedef's. 105753790Sobrien */ 105853790Sobrientypedef struct sym_tcb *tcb_p; 105953790Sobrientypedef struct sym_lcb *lcb_p; 106053790Sobrientypedef struct sym_ccb *ccb_p; 106153790Sobrientypedef struct sym_hcb *hcb_p; 106253790Sobrien 106353790Sobrien/* 106453790Sobrien * Gather negotiable parameters value 106553790Sobrien */ 106653790Sobrienstruct sym_trans { 106774755Sgroudier u8 scsi_version; 106874755Sgroudier u8 spi_version; 106953790Sobrien u8 period; 107053790Sobrien u8 offset; 107153790Sobrien u8 width; 107253790Sobrien u8 options; /* PPR options */ 107353790Sobrien}; 107453790Sobrien 107553790Sobrienstruct sym_tinfo { 107653790Sobrien struct sym_trans current; 107753790Sobrien struct sym_trans goal; 107853790Sobrien struct sym_trans user; 107953790Sobrien}; 108053790Sobrien 108153790Sobrien#define BUS_8_BIT MSG_EXT_WDTR_BUS_8_BIT 108253790Sobrien#define BUS_16_BIT MSG_EXT_WDTR_BUS_16_BIT 108353790Sobrien 108453790Sobrien/* 108559743Sgroudier * Global TCB HEADER. 108659743Sgroudier * 108759743Sgroudier * Due to lack of indirect addressing on earlier NCR chips, 1088178466Smarius * this substructure is copied from the TCB to a global 108959743Sgroudier * address after selection. 1090178466Smarius * For SYMBIOS chips that support LOAD/STORE this copy is 109159743Sgroudier * not needed and thus not performed. 109253790Sobrien */ 109359743Sgroudierstruct sym_tcbh { 109453790Sobrien /* 109559743Sgroudier * Scripts bus addresses of LUN table accessed from scripts. 1096178466Smarius * LUN #0 is a special case, since multi-lun devices are rare, 1097178466Smarius * and we we want to speed-up the general case and not waste 109853790Sobrien * resources. 109953790Sobrien */ 110053790Sobrien u32 luntbl_sa; /* bus address of this table */ 110153790Sobrien u32 lun0_sa; /* bus address of LCB #0 */ 110259743Sgroudier /* 110359743Sgroudier * Actual SYNC/WIDE IO registers value for this target. 1104178466Smarius * 'sval', 'wval' and 'uval' are read from SCRIPTS and 110559743Sgroudier * so have alignment constraints. 110659743Sgroudier */ 110759743Sgroudier/*0*/ u_char uval; /* -> SCNTL4 register */ 110859743Sgroudier/*1*/ u_char sval; /* -> SXFER io register */ 110959743Sgroudier/*2*/ u_char filler1; 111059743Sgroudier/*3*/ u_char wval; /* -> SCNTL3 io register */ 111159743Sgroudier}; 111253790Sobrien 111359743Sgroudier/* 111459743Sgroudier * Target Control Block 111559743Sgroudier */ 111659743Sgroudierstruct sym_tcb { 111753790Sobrien /* 111859743Sgroudier * TCB header. 111959743Sgroudier * Assumed at offset 0. 112059743Sgroudier */ 112159743Sgroudier/*0*/ struct sym_tcbh head; 112259743Sgroudier 112359743Sgroudier /* 112459743Sgroudier * LUN table used by the SCRIPTS processor. 112559743Sgroudier * An array of bus addresses is used on reselection. 112659743Sgroudier */ 112759743Sgroudier u32 *luntbl; /* LCBs bus address table */ 112859743Sgroudier 112959743Sgroudier /* 113053790Sobrien * LUN table used by the C code. 113153790Sobrien */ 113253790Sobrien lcb_p lun0p; /* LCB of LUN #0 (usual case) */ 113354690Sobrien#if SYM_CONF_MAX_LUN > 1 113453790Sobrien lcb_p *lunmp; /* Other LCBs [1..MAX_LUN] */ 113553790Sobrien#endif 113653790Sobrien 113753790Sobrien /* 1138178466Smarius * Bitmap that tells about LUNs that succeeded at least 113953790Sobrien * 1 IO and therefore assumed to be a real device. 114053790Sobrien * Avoid useless allocation of the LCB structure. 114153790Sobrien */ 114254690Sobrien u32 lun_map[(SYM_CONF_MAX_LUN+31)/32]; 114353790Sobrien 114453790Sobrien /* 1145178466Smarius * Bitmap that tells about LUNs that haven't yet an LCB 114653790Sobrien * allocated (not discovered or LCB allocation failed). 114753790Sobrien */ 114854690Sobrien u32 busy0_map[(SYM_CONF_MAX_LUN+31)/32]; 114953790Sobrien 115053790Sobrien /* 115153790Sobrien * Transfer capabilities (SIP) 115253790Sobrien */ 115353790Sobrien struct sym_tinfo tinfo; 115453790Sobrien 115553790Sobrien /* 115653790Sobrien * Keep track of the CCB used for the negotiation in order 115753790Sobrien * to ensure that only 1 negotiation is queued at a time. 115853790Sobrien */ 115953790Sobrien ccb_p nego_cp; /* CCB used for the nego */ 116053790Sobrien 116153790Sobrien /* 116253790Sobrien * Set when we want to reset the device. 116353790Sobrien */ 116453790Sobrien u_char to_reset; 116553790Sobrien 116653790Sobrien /* 116753790Sobrien * Other user settable limits and options. 116853790Sobrien * These limits are read from the NVRAM if present. 116953790Sobrien */ 117053790Sobrien u_char usrflags; 117153790Sobrien u_short usrtags; 117253790Sobrien}; 117353790Sobrien 117453790Sobrien/* 1175251402Smarius * Assert some alignments required by the chip. 1176251402Smarius */ 1177251402SmariusCTASSERT(((offsetof(struct sym_reg, nc_sxfer) ^ 1178251402Smarius offsetof(struct sym_tcb, head.sval)) &3) == 0); 1179251402SmariusCTASSERT(((offsetof(struct sym_reg, nc_scntl3) ^ 1180251402Smarius offsetof(struct sym_tcb, head.wval)) &3) == 0); 1181251402Smarius 1182251402Smarius/* 118359743Sgroudier * Global LCB HEADER. 118459743Sgroudier * 118559743Sgroudier * Due to lack of indirect addressing on earlier NCR chips, 1186178466Smarius * this substructure is copied from the LCB to a global 118759743Sgroudier * address after selection. 1188178466Smarius * For SYMBIOS chips that support LOAD/STORE this copy is 118959743Sgroudier * not needed and thus not performed. 119053790Sobrien */ 119159743Sgroudierstruct sym_lcbh { 119253790Sobrien /* 119353790Sobrien * SCRIPTS address jumped by SCRIPTS on reselection. 1194178466Smarius * For not probed logical units, this address points to 1195178466Smarius * SCRIPTS that deal with bad LU handling (must be at 119659743Sgroudier * offset zero of the LCB for that reason). 119753790Sobrien */ 119853790Sobrien/*0*/ u32 resel_sa; 119953790Sobrien 120053790Sobrien /* 1201178466Smarius * Task (bus address of a CCB) read from SCRIPTS that points 120253790Sobrien * to the unique ITL nexus allowed to be disconnected. 120353790Sobrien */ 120453790Sobrien u32 itl_task_sa; 120553790Sobrien 120653790Sobrien /* 120759743Sgroudier * Task table bus address (read from SCRIPTS). 120859743Sgroudier */ 120959743Sgroudier u32 itlq_tbl_sa; 121059743Sgroudier}; 121159743Sgroudier 121259743Sgroudier/* 121359743Sgroudier * Logical Unit Control Block 121459743Sgroudier */ 121559743Sgroudierstruct sym_lcb { 121659743Sgroudier /* 121759743Sgroudier * TCB header. 121859743Sgroudier * Assumed at offset 0. 121959743Sgroudier */ 122059743Sgroudier/*0*/ struct sym_lcbh head; 122159743Sgroudier 122259743Sgroudier /* 1223178466Smarius * Task table read from SCRIPTS that contains pointers to 1224178466Smarius * ITLQ nexuses. The bus address read from SCRIPTS is 122559743Sgroudier * inside the header. 122653790Sobrien */ 122753790Sobrien u32 *itlq_tbl; /* Kernel virtual address */ 122853790Sobrien 122953790Sobrien /* 123053790Sobrien * Busy CCBs management. 123153790Sobrien */ 123253790Sobrien u_short busy_itlq; /* Number of busy tagged CCBs */ 123353790Sobrien u_short busy_itl; /* Number of busy untagged CCBs */ 123453790Sobrien 123553790Sobrien /* 123653790Sobrien * Circular tag allocation buffer. 123753790Sobrien */ 123853790Sobrien u_short ia_tag; /* Tag allocation index */ 123953790Sobrien u_short if_tag; /* Tag release index */ 124053790Sobrien u_char *cb_tags; /* Circular tags buffer */ 124153790Sobrien 124253790Sobrien /* 124353790Sobrien * Set when we want to clear all tasks. 124453790Sobrien */ 124553790Sobrien u_char to_clear; 124653790Sobrien 124753790Sobrien /* 124853790Sobrien * Capabilities. 124953790Sobrien */ 125053790Sobrien u_char user_flags; 125153790Sobrien u_char current_flags; 125253790Sobrien}; 125353790Sobrien 125453790Sobrien/* 125553790Sobrien * Action from SCRIPTS on a task. 1256178466Smarius * Is part of the CCB, but is also used separately to plug 125753790Sobrien * error handling action to perform from SCRIPTS. 125853790Sobrien */ 125953790Sobrienstruct sym_actscr { 126053790Sobrien u32 start; /* Jumped by SCRIPTS after selection */ 126153790Sobrien u32 restart; /* Jumped by SCRIPTS on relection */ 126253790Sobrien}; 126353790Sobrien 126453790Sobrien/* 126553790Sobrien * Phase mismatch context. 126653790Sobrien * 1267178466Smarius * It is part of the CCB and is used as parameters for the 1268178466Smarius * DATA pointer. We need two contexts to handle correctly the 126953790Sobrien * SAVED DATA POINTER. 127053790Sobrien */ 127153790Sobrienstruct sym_pmc { 127253790Sobrien struct sym_tblmove sg; /* Updated interrupted SG block */ 127353790Sobrien u32 ret; /* SCRIPT return address */ 127453790Sobrien}; 127553790Sobrien 127653790Sobrien/* 127753790Sobrien * LUN control block lookup. 1278178466Smarius * We use a direct pointer for LUN #0, and a table of 1279178466Smarius * pointers which is only allocated for devices that support 128053790Sobrien * LUN(s) > 0. 128153790Sobrien */ 128254690Sobrien#if SYM_CONF_MAX_LUN <= 1 1283251402Smarius#define sym_lp(tp, lun) (!lun) ? (tp)->lun0p : 0 128453790Sobrien#else 1285251402Smarius#define sym_lp(tp, lun) \ 128653790Sobrien (!lun) ? (tp)->lun0p : (tp)->lunmp ? (tp)->lunmp[(lun)] : 0 128753790Sobrien#endif 128853790Sobrien 128953790Sobrien/* 129053790Sobrien * Status are used by the host and the script processor. 129153790Sobrien * 1292178466Smarius * The last four bytes (status[4]) are copied to the 1293178466Smarius * scratchb register (declared as scr0..scr3) just after the 129453790Sobrien * select/reselect, and copied back just after disconnecting. 129553790Sobrien * Inside the script the XX_REG are used. 129653790Sobrien */ 129753790Sobrien 129853790Sobrien/* 129953790Sobrien * Last four bytes (script) 130053790Sobrien */ 130153790Sobrien#define QU_REG scr0 130253790Sobrien#define HS_REG scr1 130353790Sobrien#define HS_PRT nc_scr1 130453790Sobrien#define SS_REG scr2 130553790Sobrien#define SS_PRT nc_scr2 130653790Sobrien#define HF_REG scr3 130753790Sobrien#define HF_PRT nc_scr3 130853790Sobrien 130953790Sobrien/* 131053790Sobrien * Last four bytes (host) 131153790Sobrien */ 131259743Sgroudier#define actualquirks phys.head.status[0] 131359743Sgroudier#define host_status phys.head.status[1] 131459743Sgroudier#define ssss_status phys.head.status[2] 131559743Sgroudier#define host_flags phys.head.status[3] 131653790Sobrien 131753790Sobrien/* 131853790Sobrien * Host flags 131953790Sobrien */ 132053790Sobrien#define HF_IN_PM0 1u 132153790Sobrien#define HF_IN_PM1 (1u<<1) 132253790Sobrien#define HF_ACT_PM (1u<<2) 132353790Sobrien#define HF_DP_SAVED (1u<<3) 132453790Sobrien#define HF_SENSE (1u<<4) 132553790Sobrien#define HF_EXT_ERR (1u<<5) 132658927Sgroudier#define HF_DATA_IN (1u<<6) 132754690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 132853790Sobrien#define HF_HINT_IARB (1u<<7) 132953790Sobrien#endif 133053790Sobrien 133153790Sobrien/* 133259743Sgroudier * Global CCB HEADER. 133353790Sobrien * 133459743Sgroudier * Due to lack of indirect addressing on earlier NCR chips, 1335178466Smarius * this substructure is copied from the ccb to a global 1336178466Smarius * address after selection (or reselection) and copied back 133759743Sgroudier * before disconnect. 1338178466Smarius * For SYMBIOS chips that support LOAD/STORE this copy is 133959743Sgroudier * not needed and thus not performed. 134053790Sobrien */ 134159743Sgroudierstruct sym_ccbh { 134253790Sobrien /* 134353790Sobrien * Start and restart SCRIPTS addresses (must be at 0). 134453790Sobrien */ 134553790Sobrien/*0*/ struct sym_actscr go; 134653790Sobrien 134753790Sobrien /* 134853790Sobrien * SCRIPTS jump address that deal with data pointers. 1349178466Smarius * 'savep' points to the position in the script responsible 135059743Sgroudier * for the actual transfer of data. 135153790Sobrien * It's written on reception of a SAVE_DATA_POINTER message. 135253790Sobrien */ 135353790Sobrien u32 savep; /* Jump address to saved data pointer */ 135453790Sobrien u32 lastp; /* SCRIPTS address at end of data */ 135559743Sgroudier u32 goalp; /* Not accessed for now from SCRIPTS */ 135653790Sobrien 135753790Sobrien /* 135853790Sobrien * Status fields. 135953790Sobrien */ 136059252Sgroudier u8 status[4]; 136159743Sgroudier}; 136253790Sobrien 136359743Sgroudier/* 136459743Sgroudier * Data Structure Block 136559743Sgroudier * 1366178466Smarius * During execution of a ccb by the script processor, the 1367178466Smarius * DSA (data structure address) register points to this 136859743Sgroudier * substructure of the ccb. 136959743Sgroudier */ 137059743Sgroudierstruct sym_dsb { 137153790Sobrien /* 137259743Sgroudier * CCB header. 137362422Sgroudier * Also assumed at offset 0 of the sym_ccb structure. 137459743Sgroudier */ 137559743Sgroudier/*0*/ struct sym_ccbh head; 137659743Sgroudier 137759743Sgroudier /* 137859743Sgroudier * Phase mismatch contexts. 137959743Sgroudier * We need two to handle correctly the SAVED DATA POINTER. 1380178466Smarius * MUST BOTH BE AT OFFSET < 256, due to using 8 bit arithmetic 138159743Sgroudier * for address calculation from SCRIPTS. 138259743Sgroudier */ 138359743Sgroudier struct sym_pmc pm0; 138459743Sgroudier struct sym_pmc pm1; 138559743Sgroudier 138659743Sgroudier /* 138753790Sobrien * Table data for Script 138853790Sobrien */ 138953790Sobrien struct sym_tblsel select; 139053790Sobrien struct sym_tblmove smsg; 139153790Sobrien struct sym_tblmove smsg_ext; 139253790Sobrien struct sym_tblmove cmd; 139353790Sobrien struct sym_tblmove sense; 139457186Sgroudier struct sym_tblmove wresid; 139554690Sobrien struct sym_tblmove data [SYM_CONF_MAX_SG]; 139653790Sobrien}; 139753790Sobrien 139853790Sobrien/* 139953790Sobrien * Our Command Control Block 140053790Sobrien */ 140153790Sobrienstruct sym_ccb { 140253790Sobrien /* 1403178466Smarius * This is the data structure which is pointed by the DSA 140453790Sobrien * register when it is executed by the script processor. 140553790Sobrien * It must be the first entry. 140653790Sobrien */ 140759743Sgroudier struct sym_dsb phys; 140853790Sobrien 140953790Sobrien /* 141053790Sobrien * Pointer to CAM ccb and related stuff. 141153790Sobrien */ 1412178468Smarius struct callout ch; /* callout handle */ 141353790Sobrien union ccb *cam_ccb; /* CAM scsiio ccb */ 141458927Sgroudier u8 cdb_buf[16]; /* Copy of CDB */ 141558927Sgroudier u8 *sns_bbuf; /* Bounce buffer for sense data */ 141658927Sgroudier#define SYM_SNS_BBUF_LEN sizeof(struct scsi_sense_data) 141753790Sobrien int data_len; /* Total data length */ 141853790Sobrien int segments; /* Number of SG segments */ 141953790Sobrien 142053790Sobrien /* 142159252Sgroudier * Miscellaneous status'. 142259252Sgroudier */ 142359252Sgroudier u_char nego_status; /* Negotiation status */ 142459252Sgroudier u_char xerr_status; /* Extended error flags */ 142559252Sgroudier u32 extra_bytes; /* Extraneous bytes transferred */ 142659252Sgroudier 142759252Sgroudier /* 142853790Sobrien * Message areas. 142953790Sobrien * We prepare a message to be sent after selection. 1430178466Smarius * We may use a second one if the command is rescheduled 143153790Sobrien * due to CHECK_CONDITION or COMMAND TERMINATED. 143253790Sobrien * Contents are IDENTIFY and SIMPLE_TAG. 143353790Sobrien * While negotiating sync or wide transfer, 143453790Sobrien * a SDTR or WDTR message is appended. 143553790Sobrien */ 143653790Sobrien u_char scsi_smsg [12]; 143753790Sobrien u_char scsi_smsg2[12]; 143853790Sobrien 143953790Sobrien /* 144053790Sobrien * Auto request sense related fields. 144153790Sobrien */ 144253790Sobrien u_char sensecmd[6]; /* Request Sense command */ 144353790Sobrien u_char sv_scsi_status; /* Saved SCSI status */ 144453790Sobrien u_char sv_xerr_status; /* Saved extended status */ 144553790Sobrien int sv_resid; /* Saved residual */ 144658927Sgroudier 144753790Sobrien /* 144858927Sgroudier * Map for the DMA of user data. 144958927Sgroudier */ 145058927Sgroudier void *arg; /* Argument for some callback */ 145158927Sgroudier bus_dmamap_t dmamap; /* DMA map for user data */ 145258927Sgroudier u_char dmamapped; 145358927Sgroudier#define SYM_DMA_NONE 0 145458927Sgroudier#define SYM_DMA_READ 1 145558927Sgroudier#define SYM_DMA_WRITE 2 145658927Sgroudier /* 145753790Sobrien * Other fields. 145853790Sobrien */ 145961051Sgroudier u32 ccb_ba; /* BUS address of this CCB */ 146053790Sobrien u_short tag; /* Tag for this transfer */ 146153790Sobrien /* NO_TAG means no tag */ 146253790Sobrien u_char target; 146353790Sobrien u_char lun; 146453790Sobrien ccb_p link_ccbh; /* Host adapter CCB hash chain */ 146553790Sobrien SYM_QUEHEAD 146653790Sobrien link_ccbq; /* Link to free/busy CCB queue */ 146753790Sobrien u32 startp; /* Initial data pointer */ 146853790Sobrien int ext_sg; /* Extreme data pointer, used */ 146953790Sobrien int ext_ofs; /* to calculate the residual. */ 147053790Sobrien u_char to_abort; /* Want this IO to be aborted */ 147153790Sobrien}; 147253790Sobrien 147358927Sgroudier#define CCB_BA(cp,lbl) (cp->ccb_ba + offsetof(struct sym_ccb, lbl)) 147453790Sobrien 147553790Sobrien/* 147653790Sobrien * Host Control Block 147753790Sobrien */ 147853790Sobrienstruct sym_hcb { 1479178468Smarius struct mtx mtx; 1480178468Smarius 148153790Sobrien /* 148259743Sgroudier * Global headers. 1483178466Smarius * Due to poorness of addressing capabilities, earlier 1484178466Smarius * chips (810, 815, 825) copy part of the data structures 148559743Sgroudier * (CCB, TCB and LCB) in fixed areas. 148659743Sgroudier */ 148759743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 148859743Sgroudier struct sym_ccbh ccb_head; 148959743Sgroudier struct sym_tcbh tcb_head; 149059743Sgroudier struct sym_lcbh lcb_head; 149159743Sgroudier#endif 149259743Sgroudier /* 1493178466Smarius * Idle task and invalid task actions and 149453790Sobrien * their bus addresses. 149553790Sobrien */ 149653790Sobrien struct sym_actscr idletask, notask, bad_itl, bad_itlq; 149753790Sobrien vm_offset_t idletask_ba, notask_ba, bad_itl_ba, bad_itlq_ba; 149853790Sobrien 149953790Sobrien /* 1500178466Smarius * Dummy lun table to protect us against target 150153790Sobrien * returning bad lun number on reselection. 150253790Sobrien */ 150353790Sobrien u32 *badluntbl; /* Table physical address */ 150453790Sobrien u32 badlun_sa; /* SCRIPT handler BUS address */ 150553790Sobrien 150653790Sobrien /* 150758927Sgroudier * Bus address of this host control block. 150858927Sgroudier */ 150958927Sgroudier u32 hcb_ba; 151058927Sgroudier 151158927Sgroudier /* 151253790Sobrien * Bit 32-63 of the on-chip RAM bus address in LE format. 1513178466Smarius * The START_RAM64 script loads the MMRS and MMWS from this 151453790Sobrien * field. 151553790Sobrien */ 151653790Sobrien u32 scr_ram_seg; 151753790Sobrien 151853790Sobrien /* 151953790Sobrien * Chip and controller indentification. 152053790Sobrien */ 152153790Sobrien device_t device; 152253790Sobrien 152353790Sobrien /* 152453790Sobrien * Initial value of some IO register bits. 1525178466Smarius * These values are assumed to have been set by BIOS, and may 152653790Sobrien * be used to probe adapter implementation differences. 152753790Sobrien */ 152853790Sobrien u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4, 152953796Sobrien sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_scntl4, 153053796Sobrien sv_stest1; 153153790Sobrien 153253790Sobrien /* 1533178466Smarius * Actual initial value of IO register bits used by the 1534178466Smarius * driver. They are loaded at initialisation according to 153553790Sobrien * features that are to be enabled/disabled. 153653790Sobrien */ 1537178466Smarius u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, 153853790Sobrien rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4; 153953790Sobrien 154053790Sobrien /* 154162422Sgroudier * Target data. 154253790Sobrien */ 1543171524Sse#ifdef __amd64__ 1544171524Sse struct sym_tcb *target; 1545171524Sse#else 154654690Sobrien struct sym_tcb target[SYM_CONF_MAX_TARGET]; 1547171524Sse#endif 154853790Sobrien 154953790Sobrien /* 1550178466Smarius * Target control block bus address array used by the SCRIPT 155153790Sobrien * on reselection. 155253790Sobrien */ 155353790Sobrien u32 *targtbl; 155459743Sgroudier u32 targtbl_ba; 155553790Sobrien 155653790Sobrien /* 155753790Sobrien * CAM SIM information for this instance. 155853790Sobrien */ 155953790Sobrien struct cam_sim *sim; 156053790Sobrien struct cam_path *path; 156153790Sobrien 156253790Sobrien /* 156353790Sobrien * Allocated hardware resources. 156453790Sobrien */ 156553790Sobrien struct resource *irq_res; 156653790Sobrien struct resource *io_res; 156753790Sobrien struct resource *mmio_res; 156853790Sobrien struct resource *ram_res; 156953790Sobrien int ram_id; 157053790Sobrien void *intr; 157153790Sobrien 157253790Sobrien /* 157353790Sobrien * Bus stuff. 157453790Sobrien * 1575178466Smarius * My understanding of PCI is that all agents must share the 157653790Sobrien * same addressing range and model. 1577178466Smarius * But some hardware architecture guys provide complex and 157853790Sobrien * brain-deaded stuff that makes shit. 1579178466Smarius * This driver only support PCI compliant implementations and 1580178466Smarius * deals with part of the BUS stuff complexity only to fit O/S 158153790Sobrien * requirements. 158253790Sobrien */ 158353790Sobrien 158453790Sobrien /* 158558927Sgroudier * DMA stuff. 158658927Sgroudier */ 158758927Sgroudier bus_dma_tag_t bus_dmat; /* DMA tag from parent BUS */ 158858927Sgroudier bus_dma_tag_t data_dmat; /* DMA tag for user data */ 158958927Sgroudier /* 1590178468Smarius * BUS addresses of the chip 159153790Sobrien */ 159253790Sobrien vm_offset_t mmio_ba; /* MMIO BUS address */ 159353790Sobrien int mmio_ws; /* MMIO Window size */ 159453790Sobrien 159553790Sobrien vm_offset_t ram_ba; /* RAM BUS address */ 159653790Sobrien int ram_ws; /* RAM window size */ 159753790Sobrien 159853790Sobrien /* 159953790Sobrien * SCRIPTS virtual and physical bus addresses. 160053790Sobrien * 'script' is loaded in the on-chip RAM if present. 1601178466Smarius * 'scripth' stays in main memory for all chips except the 160253790Sobrien * 53C895A, 53C896 and 53C1010 that provide 8K on-chip RAM. 160353790Sobrien */ 160459743Sgroudier u_char *scripta0; /* Copies of script and scripth */ 160559743Sgroudier u_char *scriptb0; /* Copies of script and scripth */ 160659292Sgroudier vm_offset_t scripta_ba; /* Actual script and scripth */ 160759292Sgroudier vm_offset_t scriptb_ba; /* bus addresses. */ 160859292Sgroudier vm_offset_t scriptb0_ba; 160959743Sgroudier u_short scripta_sz; /* Actual size of script A */ 161059743Sgroudier u_short scriptb_sz; /* Actual size of script B */ 161153790Sobrien 161253790Sobrien /* 1613178466Smarius * Bus addresses, setup and patch methods for 161459743Sgroudier * the selected firmware. 161559743Sgroudier */ 161659743Sgroudier struct sym_fwa_ba fwa_bas; /* Useful SCRIPTA bus addresses */ 161759743Sgroudier struct sym_fwb_ba fwb_bas; /* Useful SCRIPTB bus addresses */ 1618179029Smarius void (*fw_setup)(hcb_p np, const struct sym_fw *fw); 161959743Sgroudier void (*fw_patch)(hcb_p np); 1620179029Smarius const char *fw_name; 162159743Sgroudier 162259743Sgroudier /* 162353790Sobrien * General controller parameters and configuration. 162453790Sobrien */ 162553790Sobrien u_short device_id; /* PCI device id */ 162653790Sobrien u_char revision_id; /* PCI device revision id */ 162753790Sobrien u_int features; /* Chip features map */ 162853790Sobrien u_char myaddr; /* SCSI id of the adapter */ 162953790Sobrien u_char maxburst; /* log base 2 of dwords burst */ 163053790Sobrien u_char maxwide; /* Maximum transfer width */ 163153790Sobrien u_char minsync; /* Min sync period factor (ST) */ 163253790Sobrien u_char maxsync; /* Max sync period factor (ST) */ 163360134Sgroudier u_char maxoffs; /* Max scsi offset (ST) */ 163453790Sobrien u_char minsync_dt; /* Min sync period factor (DT) */ 163553790Sobrien u_char maxsync_dt; /* Max sync period factor (DT) */ 163660134Sgroudier u_char maxoffs_dt; /* Max scsi offset (DT) */ 163753790Sobrien u_char multiplier; /* Clock multiplier (1,2,4) */ 163853790Sobrien u_char clock_divn; /* Number of clock divisors */ 163961051Sgroudier u32 clock_khz; /* SCSI clock frequency in KHz */ 164061051Sgroudier u32 pciclk_khz; /* Estimated PCI clock in KHz */ 164153790Sobrien /* 164253790Sobrien * Start queue management. 1643178466Smarius * It is filled up by the host processor and accessed by the 164453790Sobrien * SCRIPTS processor in order to start SCSI commands. 164553790Sobrien */ 164653790Sobrien volatile /* Prevent code optimizations */ 164758927Sgroudier u32 *squeue; /* Start queue virtual address */ 164858927Sgroudier u32 squeue_ba; /* Start queue BUS address */ 164953790Sobrien u_short squeueput; /* Next free slot of the queue */ 165053790Sobrien u_short actccbs; /* Number of allocated CCBs */ 165153790Sobrien 165253790Sobrien /* 165353790Sobrien * Command completion queue. 165453790Sobrien * It is the same size as the start queue to avoid overflow. 165553790Sobrien */ 165653790Sobrien u_short dqueueget; /* Next position to scan */ 165753790Sobrien volatile /* Prevent code optimizations */ 165853790Sobrien u32 *dqueue; /* Completion (done) queue */ 165959743Sgroudier u32 dqueue_ba; /* Done queue BUS address */ 166053790Sobrien 166153790Sobrien /* 166253790Sobrien * Miscellaneous buffers accessed by the scripts-processor. 1663178466Smarius * They shall be DWORD aligned, because they may be read or 166453790Sobrien * written with a script command. 166553790Sobrien */ 166653790Sobrien u_char msgout[8]; /* Buffer for MESSAGE OUT */ 166753790Sobrien u_char msgin [8]; /* Buffer for MESSAGE IN */ 166853790Sobrien u32 lastmsg; /* Last SCSI message sent */ 166953790Sobrien u_char scratch; /* Scratch for SCSI receive */ 167053790Sobrien 167153790Sobrien /* 167253790Sobrien * Miscellaneous configuration and status parameters. 167353790Sobrien */ 167455628Sgroudier u_char usrflags; /* Miscellaneous user flags */ 167553790Sobrien u_char scsi_mode; /* Current SCSI BUS mode */ 167653790Sobrien u_char verbose; /* Verbosity for this controller*/ 167753790Sobrien u32 cache; /* Used for cache test at init. */ 167853790Sobrien 167953790Sobrien /* 168053790Sobrien * CCB lists and queue. 168153790Sobrien */ 168253790Sobrien ccb_p ccbh[CCB_HASH_SIZE]; /* CCB hashed by DSA value */ 168353790Sobrien SYM_QUEHEAD free_ccbq; /* Queue of available CCBs */ 168453790Sobrien SYM_QUEHEAD busy_ccbq; /* Queue of busy CCBs */ 168553790Sobrien 168653790Sobrien /* 168753790Sobrien * During error handling and/or recovery, 1688178466Smarius * active CCBs that are to be completed with 168953790Sobrien * error or requeued are moved from the busy_ccbq 169053790Sobrien * to the comp_ccbq prior to completion. 169153790Sobrien */ 169253790Sobrien SYM_QUEHEAD comp_ccbq; 169353790Sobrien 169453790Sobrien /* 169553790Sobrien * CAM CCB pending queue. 169653790Sobrien */ 169753790Sobrien SYM_QUEHEAD cam_ccbq; 169853790Sobrien 169953790Sobrien /* 170053790Sobrien * IMMEDIATE ARBITRATION (IARB) control. 170153790Sobrien * 1702178466Smarius * We keep track in 'last_cp' of the last CCB that has been 1703178466Smarius * queued to the SCRIPTS processor and clear 'last_cp' when 1704178466Smarius * this CCB completes. If last_cp is not zero at the moment 1705178466Smarius * we queue a new CCB, we set a flag in 'last_cp' that is 170653790Sobrien * used by the SCRIPTS as a hint for setting IARB. 1707178466Smarius * We donnot set more than 'iarb_max' consecutive hints for 170853790Sobrien * IARB in order to leave devices a chance to reselect. 170953790Sobrien * By the way, any non zero value of 'iarb_max' is unfair. :) 171053790Sobrien */ 171154690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 171253790Sobrien u_short iarb_max; /* Max. # consecutive IARB hints*/ 171353790Sobrien u_short iarb_count; /* Actual # of these hints */ 171453790Sobrien ccb_p last_cp; 171553790Sobrien#endif 171653790Sobrien 171753790Sobrien /* 171853790Sobrien * Command abort handling. 1719178466Smarius * We need to synchronize tightly with the SCRIPTS 172053790Sobrien * processor in order to handle things correctly. 172153790Sobrien */ 172253790Sobrien u_char abrt_msg[4]; /* Message to send buffer */ 172353790Sobrien struct sym_tblmove abrt_tbl; /* Table for the MOV of it */ 172453790Sobrien struct sym_tblsel abrt_sel; /* Sync params for selection */ 172553790Sobrien u_char istat_sem; /* Tells the chip to stop (SEM) */ 172653790Sobrien}; 172753790Sobrien 172859743Sgroudier#define HCB_BA(np, lbl) (np->hcb_ba + offsetof(struct sym_hcb, lbl)) 172953790Sobrien 173053790Sobrien/* 173159743Sgroudier * Return the name of the controller. 173253790Sobrien */ 1733179029Smariusstatic __inline const char *sym_name(hcb_p np) 173459743Sgroudier{ 1735179029Smarius return device_get_nameunit(np->device); 173659743Sgroudier} 173753790Sobrien 173859743Sgroudier/*--------------------------------------------------------------------------*/ 173959743Sgroudier/*------------------------------ FIRMWARES ---------------------------------*/ 174059743Sgroudier/*--------------------------------------------------------------------------*/ 174159743Sgroudier 174253790Sobrien/* 174359743Sgroudier * This stuff will be moved to a separate source file when 174459743Sgroudier * the driver will be broken into several source modules. 174553790Sobrien */ 174653790Sobrien 174753790Sobrien/* 174859743Sgroudier * Macros used for all firmwares. 174953790Sobrien */ 175059743Sgroudier#define SYM_GEN_A(s, label) ((short) offsetof(s, label)), 175159743Sgroudier#define SYM_GEN_B(s, label) ((short) offsetof(s, label)), 175259743Sgroudier#define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label) 175359743Sgroudier#define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label) 175453790Sobrien 175559743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 175659743Sgroudier/* 175759743Sgroudier * Allocate firmware #1 script area. 175859743Sgroudier */ 175959743Sgroudier#define SYM_FWA_SCR sym_fw1a_scr 176059743Sgroudier#define SYM_FWB_SCR sym_fw1b_scr 176159743Sgroudier#include <dev/sym/sym_fw1.h> 1762179029Smariusstatic const struct sym_fwa_ofs sym_fw1a_ofs = { 176359743Sgroudier SYM_GEN_FW_A(struct SYM_FWA_SCR) 176453790Sobrien}; 1765179029Smariusstatic const struct sym_fwb_ofs sym_fw1b_ofs = { 176659743Sgroudier SYM_GEN_FW_B(struct SYM_FWB_SCR) 176759743Sgroudier}; 176859743Sgroudier#undef SYM_FWA_SCR 176959743Sgroudier#undef SYM_FWB_SCR 177059743Sgroudier#endif /* SYM_CONF_GENERIC_SUPPORT */ 177153790Sobrien 177253790Sobrien/* 177359743Sgroudier * Allocate firmware #2 script area. 177453790Sobrien */ 177559743Sgroudier#define SYM_FWA_SCR sym_fw2a_scr 177659743Sgroudier#define SYM_FWB_SCR sym_fw2b_scr 177759743Sgroudier#include <dev/sym/sym_fw2.h> 1778179029Smariusstatic const struct sym_fwa_ofs sym_fw2a_ofs = { 177959743Sgroudier SYM_GEN_FW_A(struct SYM_FWA_SCR) 178059743Sgroudier}; 1781179029Smariusstatic const struct sym_fwb_ofs sym_fw2b_ofs = { 178259743Sgroudier SYM_GEN_FW_B(struct SYM_FWB_SCR) 178359743Sgroudier SYM_GEN_B(struct SYM_FWB_SCR, start64) 178459743Sgroudier SYM_GEN_B(struct SYM_FWB_SCR, pm_handle) 178559743Sgroudier}; 178659743Sgroudier#undef SYM_FWA_SCR 178759743Sgroudier#undef SYM_FWB_SCR 178853790Sobrien 178959743Sgroudier#undef SYM_GEN_A 179059743Sgroudier#undef SYM_GEN_B 179159743Sgroudier#undef PADDR_A 179259743Sgroudier#undef PADDR_B 179353790Sobrien 179459743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 179553790Sobrien/* 179659743Sgroudier * Patch routine for firmware #1. 179753790Sobrien */ 179859743Sgroudierstatic void 179959743Sgroudiersym_fw1_patch(hcb_p np) 180053790Sobrien{ 180159743Sgroudier struct sym_fw1a_scr *scripta0; 180259743Sgroudier struct sym_fw1b_scr *scriptb0; 180353790Sobrien 180459743Sgroudier scripta0 = (struct sym_fw1a_scr *) np->scripta0; 180559743Sgroudier scriptb0 = (struct sym_fw1b_scr *) np->scriptb0; 180653790Sobrien 180753790Sobrien /* 180859743Sgroudier * Remove LED support if not needed. 180953790Sobrien */ 181059743Sgroudier if (!(np->features & FE_LED0)) { 181159743Sgroudier scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); 181259743Sgroudier scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); 181359743Sgroudier scripta0->start[0] = cpu_to_scr(SCR_NO_OP); 181459743Sgroudier } 181559743Sgroudier 181654690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 181753790Sobrien /* 181859743Sgroudier * If user does not want to use IMMEDIATE ARBITRATION 181959743Sgroudier * when we are reselected while attempting to arbitrate, 182059743Sgroudier * patch the SCRIPTS accordingly with a SCRIPT NO_OP. 182153790Sobrien */ 182259743Sgroudier if (!SYM_CONF_SET_IARB_ON_ARB_LOST) 182359743Sgroudier scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); 182453790Sobrien#endif 182553790Sobrien /* 182659743Sgroudier * Patch some data in SCRIPTS. 182759743Sgroudier * - start and done queue initial bus address. 182859743Sgroudier * - target bus address table bus address. 182953790Sobrien */ 183059743Sgroudier scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); 183159743Sgroudier scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); 183259743Sgroudier scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); 183359743Sgroudier} 183459743Sgroudier#endif /* SYM_CONF_GENERIC_SUPPORT */ 183559743Sgroudier 183659743Sgroudier/* 183762422Sgroudier * Patch routine for firmware #2. 183859743Sgroudier */ 183959743Sgroudierstatic void 184059743Sgroudiersym_fw2_patch(hcb_p np) 184159743Sgroudier{ 184259743Sgroudier struct sym_fw2a_scr *scripta0; 184359743Sgroudier struct sym_fw2b_scr *scriptb0; 184459743Sgroudier 184559743Sgroudier scripta0 = (struct sym_fw2a_scr *) np->scripta0; 184659743Sgroudier scriptb0 = (struct sym_fw2b_scr *) np->scriptb0; 184759743Sgroudier 184853790Sobrien /* 184959743Sgroudier * Remove LED support if not needed. 185053790Sobrien */ 185159743Sgroudier if (!(np->features & FE_LED0)) { 185259743Sgroudier scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); 185359743Sgroudier scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); 185459743Sgroudier scripta0->start[0] = cpu_to_scr(SCR_NO_OP); 185559743Sgroudier } 185659743Sgroudier 185754690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 185853790Sobrien /* 185959743Sgroudier * If user does not want to use IMMEDIATE ARBITRATION 186059743Sgroudier * when we are reselected while attempting to arbitrate, 186159743Sgroudier * patch the SCRIPTS accordingly with a SCRIPT NO_OP. 186253790Sobrien */ 186359743Sgroudier if (!SYM_CONF_SET_IARB_ON_ARB_LOST) 186459743Sgroudier scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); 186553790Sobrien#endif 186653790Sobrien /* 186759743Sgroudier * Patch some variable in SCRIPTS. 186859743Sgroudier * - start and done queue initial bus address. 186959743Sgroudier * - target bus address table bus address. 187053790Sobrien */ 187159743Sgroudier scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); 187259743Sgroudier scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); 187359743Sgroudier scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); 187459743Sgroudier 187553790Sobrien /* 187659743Sgroudier * Remove the load of SCNTL4 on reselection if not a C10. 187753790Sobrien */ 187859743Sgroudier if (!(np->features & FE_C10)) { 187959743Sgroudier scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP); 188059743Sgroudier scripta0->resel_scntl4[1] = cpu_to_scr(0); 188159743Sgroudier } 188259743Sgroudier 188353790Sobrien /* 1884178466Smarius * Remove a couple of work-arounds specific to C1010 if 188560134Sgroudier * they are not desirable. See `sym_fw2.h' for more details. 188660134Sgroudier */ 188761051Sgroudier if (!(np->device_id == PCI_ID_LSI53C1010_2 && 188871742Sgroudier np->revision_id < 0x1 && 188961051Sgroudier np->pciclk_khz < 60000)) { 189060134Sgroudier scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP); 189160134Sgroudier scripta0->datao_phase[1] = cpu_to_scr(0); 189260134Sgroudier } 189361051Sgroudier if (!(np->device_id == PCI_ID_LSI53C1010 && 189461051Sgroudier /* np->revision_id < 0xff */ 1)) { 189560134Sgroudier scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP); 189660134Sgroudier scripta0->sel_done[1] = cpu_to_scr(0); 189760134Sgroudier } 189860134Sgroudier 189960134Sgroudier /* 190059743Sgroudier * Patch some other variables in SCRIPTS. 190159743Sgroudier * These ones are loaded by the SCRIPTS processor. 190253790Sobrien */ 190359743Sgroudier scriptb0->pm0_data_addr[0] = 1904178466Smarius cpu_to_scr(np->scripta_ba + 190559743Sgroudier offsetof(struct sym_fw2a_scr, pm0_data)); 190659743Sgroudier scriptb0->pm1_data_addr[0] = 1907178466Smarius cpu_to_scr(np->scripta_ba + 190859743Sgroudier offsetof(struct sym_fw2a_scr, pm1_data)); 190959743Sgroudier} 191053790Sobrien 191153790Sobrien/* 191259743Sgroudier * Fill the data area in scripts. 191359743Sgroudier * To be done for all firmwares. 191453790Sobrien */ 191559743Sgroudierstatic void 191659743Sgroudiersym_fw_fill_data (u32 *in, u32 *out) 191759743Sgroudier{ 191859743Sgroudier int i; 191959743Sgroudier 192059743Sgroudier for (i = 0; i < SYM_CONF_MAX_SG; i++) { 192159743Sgroudier *in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN; 192259743Sgroudier *in++ = offsetof (struct sym_dsb, data[i]); 192359743Sgroudier *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT; 192459743Sgroudier *out++ = offsetof (struct sym_dsb, data[i]); 192559743Sgroudier } 192659743Sgroudier} 192759743Sgroudier 192853790Sobrien/* 192959743Sgroudier * Setup useful script bus addresses. 193059743Sgroudier * To be done for all firmwares. 193153790Sobrien */ 1932178466Smariusstatic void 1933179029Smariussym_fw_setup_bus_addresses(hcb_p np, const struct sym_fw *fw) 193459743Sgroudier{ 193559743Sgroudier u32 *pa; 1936179029Smarius const u_short *po; 193759743Sgroudier int i; 193859743Sgroudier 193953790Sobrien /* 1940178466Smarius * Build the bus address table for script A 194159743Sgroudier * from the script A offset table. 194253790Sobrien */ 1943179029Smarius po = (const u_short *) fw->a_ofs; 194459743Sgroudier pa = (u32 *) &np->fwa_bas; 194559743Sgroudier for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++) 194659743Sgroudier pa[i] = np->scripta_ba + po[i]; 194759743Sgroudier 194858927Sgroudier /* 194959743Sgroudier * Same for script B. 195058927Sgroudier */ 1951179029Smarius po = (const u_short *) fw->b_ofs; 195259743Sgroudier pa = (u32 *) &np->fwb_bas; 195359743Sgroudier for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++) 195459743Sgroudier pa[i] = np->scriptb_ba + po[i]; 195559743Sgroudier} 195659743Sgroudier 195759743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 195859743Sgroudier/* 195959743Sgroudier * Setup routine for firmware #1. 196059743Sgroudier */ 1961178466Smariusstatic void 1962179029Smariussym_fw1_setup(hcb_p np, const struct sym_fw *fw) 196359743Sgroudier{ 196459743Sgroudier struct sym_fw1a_scr *scripta0; 196559743Sgroudier 196659743Sgroudier scripta0 = (struct sym_fw1a_scr *) np->scripta0; 196759743Sgroudier 196858927Sgroudier /* 196959743Sgroudier * Fill variable parts in scripts. 197058927Sgroudier */ 197159743Sgroudier sym_fw_fill_data(scripta0->data_in, scripta0->data_out); 197253790Sobrien 197353790Sobrien /* 197459743Sgroudier * Setup bus addresses used from the C code.. 197553790Sobrien */ 197659743Sgroudier sym_fw_setup_bus_addresses(np, fw); 197759743Sgroudier} 197859743Sgroudier#endif /* SYM_CONF_GENERIC_SUPPORT */ 197953790Sobrien 198059743Sgroudier/* 198162422Sgroudier * Setup routine for firmware #2. 198259743Sgroudier */ 1983178466Smariusstatic void 1984179029Smariussym_fw2_setup(hcb_p np, const struct sym_fw *fw) 198559743Sgroudier{ 198659743Sgroudier struct sym_fw2a_scr *scripta0; 198759743Sgroudier 198859743Sgroudier scripta0 = (struct sym_fw2a_scr *) np->scripta0; 198959743Sgroudier 199053790Sobrien /* 199159743Sgroudier * Fill variable parts in scripts. 199253790Sobrien */ 199359743Sgroudier sym_fw_fill_data(scripta0->data_in, scripta0->data_out); 199453790Sobrien 199553790Sobrien /* 199659743Sgroudier * Setup bus addresses used from the C code.. 199753790Sobrien */ 199859743Sgroudier sym_fw_setup_bus_addresses(np, fw); 199959743Sgroudier} 200053790Sobrien 200153790Sobrien/* 200259743Sgroudier * Allocate firmware descriptors. 200353790Sobrien */ 200459743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 2005179029Smariusstatic const struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic"); 200659743Sgroudier#endif /* SYM_CONF_GENERIC_SUPPORT */ 2007179029Smariusstatic const struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based"); 200859743Sgroudier 200959743Sgroudier/* 201059743Sgroudier * Find the most appropriate firmware for a chip. 201159743Sgroudier */ 2012179029Smariusstatic const struct sym_fw * 2013179029Smariussym_find_firmware(const struct sym_pci_chip *chip) 201453790Sobrien{ 201559743Sgroudier if (chip->features & FE_LDSTR) 201659743Sgroudier return &sym_fw2; 201759743Sgroudier#ifdef SYM_CONF_GENERIC_SUPPORT 201865404Sgroudier else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC))) 201959743Sgroudier return &sym_fw1; 202059743Sgroudier#endif 202159743Sgroudier else 2022178466Smarius return NULL; 202353790Sobrien} 202453790Sobrien 202553790Sobrien/* 202659743Sgroudier * Bind a script to physical addresses. 202753790Sobrien */ 202859743Sgroudierstatic void sym_fw_bind_script (hcb_p np, u32 *start, int len) 202953790Sobrien{ 203053790Sobrien u32 opcode, new, old, tmp1, tmp2; 203159743Sgroudier u32 *end, *cur; 203253790Sobrien int relocs; 203353790Sobrien 203459743Sgroudier cur = start; 203559743Sgroudier end = start + len/4; 203653790Sobrien 203759743Sgroudier while (cur < end) { 203853790Sobrien 203959743Sgroudier opcode = *cur; 204053790Sobrien 204153790Sobrien /* 204253790Sobrien * If we forget to change the length 204353790Sobrien * in scripts, a field will be 204453790Sobrien * padded with 0. This is an illegal 204553790Sobrien * command. 204653790Sobrien */ 204753790Sobrien if (opcode == 0) { 204853790Sobrien printf ("%s: ERROR0 IN SCRIPT at %d.\n", 204959743Sgroudier sym_name(np), (int) (cur-start)); 205053790Sobrien MDELAY (10000); 205159743Sgroudier ++cur; 205253790Sobrien continue; 205353790Sobrien }; 205453790Sobrien 205553790Sobrien /* 205653790Sobrien * We use the bogus value 0xf00ff00f ;-) 205753790Sobrien * to reserve data area in SCRIPTS. 205853790Sobrien */ 205953790Sobrien if (opcode == SCR_DATA_ZERO) { 206059743Sgroudier *cur++ = 0; 206153790Sobrien continue; 206253790Sobrien } 206353790Sobrien 206453790Sobrien if (DEBUG_FLAGS & DEBUG_SCRIPT) 206562134Sgroudier printf ("%d: <%x>\n", (int) (cur-start), 206662134Sgroudier (unsigned)opcode); 206753790Sobrien 206853790Sobrien /* 206953790Sobrien * We don't have to decode ALL commands 207053790Sobrien */ 207153790Sobrien switch (opcode >> 28) { 207253790Sobrien case 0xf: 207353790Sobrien /* 207453790Sobrien * LOAD / STORE DSA relative, don't relocate. 207553790Sobrien */ 207653790Sobrien relocs = 0; 207753790Sobrien break; 207853790Sobrien case 0xe: 207953790Sobrien /* 208053790Sobrien * LOAD / STORE absolute. 208153790Sobrien */ 208253790Sobrien relocs = 1; 208353790Sobrien break; 208453790Sobrien case 0xc: 208553790Sobrien /* 208653790Sobrien * COPY has TWO arguments. 208753790Sobrien */ 208853790Sobrien relocs = 2; 208959743Sgroudier tmp1 = cur[1]; 209059743Sgroudier tmp2 = cur[2]; 209153790Sobrien if ((tmp1 ^ tmp2) & 3) { 209253790Sobrien printf ("%s: ERROR1 IN SCRIPT at %d.\n", 209359743Sgroudier sym_name(np), (int) (cur-start)); 209459743Sgroudier MDELAY (10000); 209553790Sobrien } 209653790Sobrien /* 2097178466Smarius * If PREFETCH feature not enabled, remove 209853790Sobrien * the NO FLUSH bit if present. 209953790Sobrien */ 210053790Sobrien if ((opcode & SCR_NO_FLUSH) && 210153790Sobrien !(np->features & FE_PFEN)) { 210259743Sgroudier opcode = (opcode & ~SCR_NO_FLUSH); 210353790Sobrien } 210453790Sobrien break; 210553790Sobrien case 0x0: 210653790Sobrien /* 210753790Sobrien * MOVE/CHMOV (absolute address) 210853790Sobrien */ 210953790Sobrien if (!(np->features & FE_WIDE)) 211059743Sgroudier opcode = (opcode | OPC_MOVE); 211153790Sobrien relocs = 1; 211253790Sobrien break; 211353790Sobrien case 0x1: 211453790Sobrien /* 211553790Sobrien * MOVE/CHMOV (table indirect) 211653790Sobrien */ 211753790Sobrien if (!(np->features & FE_WIDE)) 211859743Sgroudier opcode = (opcode | OPC_MOVE); 211953790Sobrien relocs = 0; 212053790Sobrien break; 212153790Sobrien case 0x8: 212253790Sobrien /* 212353790Sobrien * JUMP / CALL 212453790Sobrien * dont't relocate if relative :-) 212553790Sobrien */ 212653790Sobrien if (opcode & 0x00800000) 212753790Sobrien relocs = 0; 212853790Sobrien else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/ 212953790Sobrien relocs = 2; 213053790Sobrien else 213153790Sobrien relocs = 1; 213253790Sobrien break; 213353790Sobrien case 0x4: 213453790Sobrien case 0x5: 213553790Sobrien case 0x6: 213653790Sobrien case 0x7: 213753790Sobrien relocs = 1; 213853790Sobrien break; 213953790Sobrien default: 214053790Sobrien relocs = 0; 214153790Sobrien break; 214253790Sobrien }; 214353790Sobrien 214459743Sgroudier /* 214559743Sgroudier * Scriptify:) the opcode. 214659743Sgroudier */ 214759743Sgroudier *cur++ = cpu_to_scr(opcode); 214859743Sgroudier 214959743Sgroudier /* 2150178466Smarius * If no relocation, assume 1 argument 215159743Sgroudier * and just scriptize:) it. 215259743Sgroudier */ 215353790Sobrien if (!relocs) { 215459743Sgroudier *cur = cpu_to_scr(*cur); 215559743Sgroudier ++cur; 215653790Sobrien continue; 215753790Sobrien } 215859743Sgroudier 215959743Sgroudier /* 216059743Sgroudier * Otherwise performs all needed relocations. 216159743Sgroudier */ 216253790Sobrien while (relocs--) { 216359743Sgroudier old = *cur; 216453790Sobrien 216553790Sobrien switch (old & RELOC_MASK) { 216653790Sobrien case RELOC_REGISTER: 216753790Sobrien new = (old & ~RELOC_MASK) + np->mmio_ba; 216853790Sobrien break; 216959743Sgroudier case RELOC_LABEL_A: 217059292Sgroudier new = (old & ~RELOC_MASK) + np->scripta_ba; 217153790Sobrien break; 217259743Sgroudier case RELOC_LABEL_B: 217359292Sgroudier new = (old & ~RELOC_MASK) + np->scriptb_ba; 217453790Sobrien break; 217553790Sobrien case RELOC_SOFTC: 217658927Sgroudier new = (old & ~RELOC_MASK) + np->hcb_ba; 217753790Sobrien break; 217853790Sobrien case 0: 217959743Sgroudier /* 218059743Sgroudier * Don't relocate a 0 address. 2181178466Smarius * They are mostly used for patched or 218259743Sgroudier * script self-modified areas. 218359743Sgroudier */ 218453790Sobrien if (old == 0) { 218553790Sobrien new = old; 218653790Sobrien break; 218753790Sobrien } 218853790Sobrien /* fall through */ 218953790Sobrien default: 219059743Sgroudier new = 0; 219159743Sgroudier panic("sym_fw_bind_script: " 219253790Sobrien "weird relocation %x\n", old); 219353790Sobrien break; 219453790Sobrien } 219553790Sobrien 219659743Sgroudier *cur++ = cpu_to_scr(new); 219753790Sobrien } 219853790Sobrien }; 219953790Sobrien} 220053790Sobrien 2201167248Sthomas/*---------------------------------------------------------------------------*/ 2202167248Sthomas/*--------------------------- END OF FIRMWARES -----------------------------*/ 2203167248Sthomas/*---------------------------------------------------------------------------*/ 220459743Sgroudier 220553790Sobrien/* 220659743Sgroudier * Function prototypes. 220759743Sgroudier */ 220859743Sgroudierstatic void sym_save_initial_setting (hcb_p np); 220959743Sgroudierstatic int sym_prepare_setting (hcb_p np, struct sym_nvram *nvram); 221059743Sgroudierstatic int sym_prepare_nego (hcb_p np, ccb_p cp, int nego, u_char *msgptr); 221159743Sgroudierstatic void sym_put_start_queue (hcb_p np, ccb_p cp); 221259743Sgroudierstatic void sym_chip_reset (hcb_p np); 221359743Sgroudierstatic void sym_soft_reset (hcb_p np); 221459743Sgroudierstatic void sym_start_reset (hcb_p np); 221559743Sgroudierstatic int sym_reset_scsi_bus (hcb_p np, int enab_int); 221659743Sgroudierstatic int sym_wakeup_done (hcb_p np); 221759743Sgroudierstatic void sym_flush_busy_queue (hcb_p np, int cam_status); 221859743Sgroudierstatic void sym_flush_comp_queue (hcb_p np, int cam_status); 221959743Sgroudierstatic void sym_init (hcb_p np, int reason); 222059743Sgroudierstatic int sym_getsync(hcb_p np, u_char dt, u_char sfac, u_char *divp, 222159743Sgroudier u_char *fakp); 222259743Sgroudierstatic void sym_setsync (hcb_p np, ccb_p cp, u_char ofs, u_char per, 222359743Sgroudier u_char div, u_char fak); 222459743Sgroudierstatic void sym_setwide (hcb_p np, ccb_p cp, u_char wide); 222559743Sgroudierstatic void sym_setpprot(hcb_p np, ccb_p cp, u_char dt, u_char ofs, 222659743Sgroudier u_char per, u_char wide, u_char div, u_char fak); 222759743Sgroudierstatic void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs, 222859743Sgroudier u_char per, u_char wide, u_char div, u_char fak); 222959743Sgroudierstatic void sym_log_hard_error (hcb_p np, u_short sist, u_char dstat); 223059743Sgroudierstatic void sym_intr (void *arg); 223159743Sgroudierstatic void sym_poll (struct cam_sim *sim); 223259743Sgroudierstatic void sym_recover_scsi_int (hcb_p np, u_char hsts); 223359743Sgroudierstatic void sym_int_sto (hcb_p np); 223459743Sgroudierstatic void sym_int_udc (hcb_p np); 223559743Sgroudierstatic void sym_int_sbmc (hcb_p np); 223659743Sgroudierstatic void sym_int_par (hcb_p np, u_short sist); 223759743Sgroudierstatic void sym_int_ma (hcb_p np); 2238178466Smariusstatic int sym_dequeue_from_squeue(hcb_p np, int i, int target, int lun, 223959743Sgroudier int task); 2240251402Smariusstatic void sym_sir_bad_scsi_status (hcb_p np, ccb_p cp); 224159743Sgroudierstatic int sym_clear_tasks (hcb_p np, int status, int targ, int lun, int task); 224259743Sgroudierstatic void sym_sir_task_recovery (hcb_p np, int num); 224359743Sgroudierstatic int sym_evaluate_dp (hcb_p np, ccb_p cp, u32 scr, int *ofs); 2244251402Smariusstatic void sym_modify_dp(hcb_p np, ccb_p cp, int ofs); 224559743Sgroudierstatic int sym_compute_residual (hcb_p np, ccb_p cp); 224659743Sgroudierstatic int sym_show_msg (u_char * msg); 224759743Sgroudierstatic void sym_print_msg (ccb_p cp, char *label, u_char *msg); 224859743Sgroudierstatic void sym_sync_nego (hcb_p np, tcb_p tp, ccb_p cp); 224959743Sgroudierstatic void sym_ppr_nego (hcb_p np, tcb_p tp, ccb_p cp); 225059743Sgroudierstatic void sym_wide_nego (hcb_p np, tcb_p tp, ccb_p cp); 225159743Sgroudierstatic void sym_nego_default (hcb_p np, tcb_p tp, ccb_p cp); 225259743Sgroudierstatic void sym_nego_rejected (hcb_p np, tcb_p tp, ccb_p cp); 225359743Sgroudierstatic void sym_int_sir (hcb_p np); 225459743Sgroudierstatic void sym_free_ccb (hcb_p np, ccb_p cp); 225559743Sgroudierstatic ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order); 225659743Sgroudierstatic ccb_p sym_alloc_ccb (hcb_p np); 225761051Sgroudierstatic ccb_p sym_ccb_from_dsa (hcb_p np, u32 dsa); 225859743Sgroudierstatic lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln); 225959743Sgroudierstatic void sym_alloc_lcb_tags (hcb_p np, u_char tn, u_char ln); 226059743Sgroudierstatic int sym_snooptest (hcb_p np); 226159743Sgroudierstatic void sym_selectclock(hcb_p np, u_char scntl3); 226259743Sgroudierstatic void sym_getclock (hcb_p np, int mult); 226359743Sgroudierstatic int sym_getpciclock (hcb_p np); 226459743Sgroudierstatic void sym_complete_ok (hcb_p np, ccb_p cp); 226559743Sgroudierstatic void sym_complete_error (hcb_p np, ccb_p cp); 2266178468Smariusstatic void sym_callout (void *arg); 226759743Sgroudierstatic int sym_abort_scsiio (hcb_p np, union ccb *ccb, int timed_out); 226859743Sgroudierstatic void sym_reset_dev (hcb_p np, union ccb *ccb); 226959743Sgroudierstatic void sym_action (struct cam_sim *sim, union ccb *ccb); 227059743Sgroudierstatic int sym_setup_cdb (hcb_p np, struct ccb_scsiio *csio, ccb_p cp); 227159743Sgroudierstatic void sym_setup_data_and_start (hcb_p np, struct ccb_scsiio *csio, 227259743Sgroudier ccb_p cp); 2273178466Smariusstatic int sym_fast_scatter_sg_physical(hcb_p np, ccb_p cp, 227459743Sgroudier bus_dma_segment_t *psegs, int nsegs); 2275178466Smariusstatic int sym_scatter_sg_physical (hcb_p np, ccb_p cp, 227659743Sgroudier bus_dma_segment_t *psegs, int nsegs); 227759743Sgroudierstatic void sym_action2 (struct cam_sim *sim, union ccb *ccb); 2278251402Smariusstatic void sym_update_trans(hcb_p np, struct sym_trans *tip, 227959743Sgroudier struct ccb_trans_settings *cts); 228059743Sgroudierstatic void sym_update_dflags(hcb_p np, u_char *flags, 228159743Sgroudier struct ccb_trans_settings *cts); 228259743Sgroudier 2283179029Smariusstatic const struct sym_pci_chip *sym_find_pci_chip (device_t dev); 228459743Sgroudierstatic int sym_pci_probe (device_t dev); 228559743Sgroudierstatic int sym_pci_attach (device_t dev); 228659743Sgroudier 228759743Sgroudierstatic void sym_pci_free (hcb_p np); 228859743Sgroudierstatic int sym_cam_attach (hcb_p np); 228959743Sgroudierstatic void sym_cam_free (hcb_p np); 229059743Sgroudier 229159743Sgroudierstatic void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram); 229259743Sgroudierstatic void sym_nvram_setup_target (hcb_p np, int targ, struct sym_nvram *nvp); 229359743Sgroudierstatic int sym_read_nvram (hcb_p np, struct sym_nvram *nvp); 229459743Sgroudier 229559743Sgroudier/* 2296220944Smarius * Print something which allows to retrieve the controller type, 229753790Sobrien * unit, target, lun concerned by a kernel message. 229853790Sobrien */ 229953790Sobrienstatic void PRINT_TARGET (hcb_p np, int target) 230053790Sobrien{ 230153790Sobrien printf ("%s:%d:", sym_name(np), target); 230253790Sobrien} 230353790Sobrien 230453790Sobrienstatic void PRINT_LUN(hcb_p np, int target, int lun) 230553790Sobrien{ 230653790Sobrien printf ("%s:%d:%d:", sym_name(np), target, lun); 230753790Sobrien} 230853790Sobrien 230953790Sobrienstatic void PRINT_ADDR (ccb_p cp) 231053790Sobrien{ 231153790Sobrien if (cp && cp->cam_ccb) 231253790Sobrien xpt_print_path(cp->cam_ccb->ccb_h.path); 231353790Sobrien} 231453790Sobrien 231553790Sobrien/* 231653790Sobrien * Take into account this ccb in the freeze count. 2317178466Smarius */ 231853790Sobrienstatic void sym_freeze_cam_ccb(union ccb *ccb) 231953790Sobrien{ 232053790Sobrien if (!(ccb->ccb_h.flags & CAM_DEV_QFRZDIS)) { 232153790Sobrien if (!(ccb->ccb_h.status & CAM_DEV_QFRZN)) { 232253790Sobrien ccb->ccb_h.status |= CAM_DEV_QFRZN; 232353790Sobrien xpt_freeze_devq(ccb->ccb_h.path, 1); 232453790Sobrien } 232553790Sobrien } 232653790Sobrien} 232753790Sobrien 232853790Sobrien/* 232953790Sobrien * Set the status field of a CAM CCB. 233053790Sobrien */ 233153790Sobrienstatic __inline void sym_set_cam_status(union ccb *ccb, cam_status status) 233253790Sobrien{ 233353790Sobrien ccb->ccb_h.status &= ~CAM_STATUS_MASK; 233453790Sobrien ccb->ccb_h.status |= status; 233553790Sobrien} 233653790Sobrien 233753790Sobrien/* 233853790Sobrien * Get the status field of a CAM CCB. 233953790Sobrien */ 234053790Sobrienstatic __inline int sym_get_cam_status(union ccb *ccb) 234153790Sobrien{ 234253790Sobrien return ccb->ccb_h.status & CAM_STATUS_MASK; 234353790Sobrien} 234453790Sobrien 234553790Sobrien/* 234653790Sobrien * Enqueue a CAM CCB. 234753790Sobrien */ 2348178468Smariusstatic void sym_enqueue_cam_ccb(ccb_p cp) 234953790Sobrien{ 2350178468Smarius hcb_p np; 2351178468Smarius union ccb *ccb; 2352178468Smarius 2353178468Smarius ccb = cp->cam_ccb; 2354178468Smarius np = (hcb_p) cp->arg; 2355178468Smarius 235653790Sobrien assert(!(ccb->ccb_h.status & CAM_SIM_QUEUED)); 235753790Sobrien ccb->ccb_h.status = CAM_REQ_INPROG; 235853790Sobrien 2359178468Smarius callout_reset(&cp->ch, ccb->ccb_h.timeout * hz / 1000, sym_callout, 2360178468Smarius (caddr_t) ccb); 236153790Sobrien ccb->ccb_h.status |= CAM_SIM_QUEUED; 236253790Sobrien ccb->ccb_h.sym_hcb_ptr = np; 236353790Sobrien 236453790Sobrien sym_insque_tail(sym_qptr(&ccb->ccb_h.sim_links), &np->cam_ccbq); 236553790Sobrien} 236653790Sobrien 236753790Sobrien/* 236853790Sobrien * Complete a pending CAM CCB. 236953790Sobrien */ 2370178468Smarius 2371178468Smariusstatic void sym_xpt_done(hcb_p np, union ccb *ccb, ccb_p cp) 2372178468Smarius{ 2373251402Smarius 2374178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 2375178468Smarius 237653790Sobrien if (ccb->ccb_h.status & CAM_SIM_QUEUED) { 2377178468Smarius callout_stop(&cp->ch); 237853790Sobrien sym_remque(sym_qptr(&ccb->ccb_h.sim_links)); 237953790Sobrien ccb->ccb_h.status &= ~CAM_SIM_QUEUED; 2380178466Smarius ccb->ccb_h.sym_hcb_ptr = NULL; 238153790Sobrien } 2382251394Smarius xpt_done(ccb); 238353790Sobrien} 238453790Sobrien 238553790Sobrienstatic void sym_xpt_done2(hcb_p np, union ccb *ccb, int cam_status) 238653790Sobrien{ 2387251402Smarius 2388178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 2389178468Smarius 239053790Sobrien sym_set_cam_status(ccb, cam_status); 2391251394Smarius xpt_done(ccb); 239253790Sobrien} 239353790Sobrien 239453790Sobrien/* 239553790Sobrien * SYMBIOS chip clock divisor table. 239653790Sobrien * 2397178466Smarius * Divisors are multiplied by 10,000,000 in order to make 239853790Sobrien * calculations more simple. 239953790Sobrien */ 240053790Sobrien#define _5M 5000000 2401179029Smariusstatic const u32 div_10M[] = 2402179029Smarius {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; 240353790Sobrien 240453790Sobrien/* 240553790Sobrien * SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64, 2406178466Smarius * 128 transfers. All chips support at least 16 transfers 2407178466Smarius * bursts. The 825A, 875 and 895 chips support bursts of up 240853790Sobrien * to 128 transfers and the 895A and 896 support bursts of up 2409178466Smarius * to 64 transfers. All other chips support up to 16 241053790Sobrien * transfers bursts. 241153790Sobrien * 241253790Sobrien * For PCI 32 bit data transfers each transfer is a DWORD. 241353790Sobrien * It is a QUADWORD (8 bytes) for PCI 64 bit data transfers. 241453790Sobrien * 2415178466Smarius * We use log base 2 (burst length) as internal code, with 241653790Sobrien * value 0 meaning "burst disabled". 241753790Sobrien */ 241853790Sobrien 241953790Sobrien/* 242053790Sobrien * Burst length from burst code. 242153790Sobrien */ 242253790Sobrien#define burst_length(bc) (!(bc))? 0 : 1 << (bc) 242353790Sobrien 242453790Sobrien/* 242553790Sobrien * Burst code from io register bits. 242653790Sobrien */ 242753790Sobrien#define burst_code(dmode, ctest4, ctest5) \ 242853790Sobrien (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1 242953790Sobrien 243053790Sobrien/* 243153790Sobrien * Set initial io register bits from burst code. 243253790Sobrien */ 243353790Sobrienstatic __inline void sym_init_burst(hcb_p np, u_char bc) 243453790Sobrien{ 243553790Sobrien np->rv_ctest4 &= ~0x80; 243653790Sobrien np->rv_dmode &= ~(0x3 << 6); 243753790Sobrien np->rv_ctest5 &= ~0x4; 243853790Sobrien 243953790Sobrien if (!bc) { 244053790Sobrien np->rv_ctest4 |= 0x80; 244153790Sobrien } 244253790Sobrien else { 244353790Sobrien --bc; 244453790Sobrien np->rv_dmode |= ((bc & 0x3) << 6); 244553790Sobrien np->rv_ctest5 |= (bc & 0x4); 244653790Sobrien } 244753790Sobrien} 244853790Sobrien 244953790Sobrien/* 245053790Sobrien * Print out the list of targets that have some flag disabled by user. 245153790Sobrien */ 245253790Sobrienstatic void sym_print_targets_flag(hcb_p np, int mask, char *msg) 245353790Sobrien{ 245453790Sobrien int cnt; 245553790Sobrien int i; 245653790Sobrien 245754690Sobrien for (cnt = 0, i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 245853790Sobrien if (i == np->myaddr) 245953790Sobrien continue; 246053790Sobrien if (np->target[i].usrflags & mask) { 246153790Sobrien if (!cnt++) 246253790Sobrien printf("%s: %s disabled for targets", 246353790Sobrien sym_name(np), msg); 246453790Sobrien printf(" %d", i); 246553790Sobrien } 246653790Sobrien } 246753790Sobrien if (cnt) 246853790Sobrien printf(".\n"); 246953790Sobrien} 247053790Sobrien 247153790Sobrien/* 247253796Sobrien * Save initial settings of some IO registers. 247353796Sobrien * Assumed to have been set by BIOS. 2474178466Smarius * We cannot reset the chip prior to reading the 247553796Sobrien * IO registers, since informations will be lost. 2476178466Smarius * Since the SCRIPTS processor may be running, this 2477178466Smarius * is not safe on paper, but it seems to work quite 247853796Sobrien * well. :) 247953790Sobrien */ 248053796Sobrienstatic void sym_save_initial_setting (hcb_p np) 248153790Sobrien{ 248253790Sobrien np->sv_scntl0 = INB(nc_scntl0) & 0x0a; 248353790Sobrien np->sv_scntl3 = INB(nc_scntl3) & 0x07; 248453790Sobrien np->sv_dmode = INB(nc_dmode) & 0xce; 248553790Sobrien np->sv_dcntl = INB(nc_dcntl) & 0xa8; 248653790Sobrien np->sv_ctest3 = INB(nc_ctest3) & 0x01; 248753790Sobrien np->sv_ctest4 = INB(nc_ctest4) & 0x80; 248853790Sobrien np->sv_gpcntl = INB(nc_gpcntl); 248953796Sobrien np->sv_stest1 = INB(nc_stest1); 249053790Sobrien np->sv_stest2 = INB(nc_stest2) & 0x20; 249153790Sobrien np->sv_stest4 = INB(nc_stest4); 249253790Sobrien if (np->features & FE_C10) { /* Always large DMA fifo + ultra3 */ 249353790Sobrien np->sv_scntl4 = INB(nc_scntl4); 249453790Sobrien np->sv_ctest5 = INB(nc_ctest5) & 0x04; 249553790Sobrien } 249653790Sobrien else 249753790Sobrien np->sv_ctest5 = INB(nc_ctest5) & 0x24; 249853796Sobrien} 249953796Sobrien 250053796Sobrien/* 2501178466Smarius * Prepare io register values used by sym_init() according 250253796Sobrien * to selected and supported features. 250353796Sobrien */ 250453796Sobrienstatic int sym_prepare_setting(hcb_p np, struct sym_nvram *nvram) 250553796Sobrien{ 250653796Sobrien u_char burst_max; 250761051Sgroudier u32 period; 250853796Sobrien int i; 250953796Sobrien 251053790Sobrien /* 251153790Sobrien * Wide ? 251253790Sobrien */ 251353790Sobrien np->maxwide = (np->features & FE_WIDE)? 1 : 0; 251453790Sobrien 251553790Sobrien /* 251653790Sobrien * Get the frequency of the chip's clock. 251753790Sobrien */ 251853790Sobrien if (np->features & FE_QUAD) 251953790Sobrien np->multiplier = 4; 252053790Sobrien else if (np->features & FE_DBLR) 252153790Sobrien np->multiplier = 2; 252253790Sobrien else 252353790Sobrien np->multiplier = 1; 252453790Sobrien 252553790Sobrien np->clock_khz = (np->features & FE_CLK80)? 80000 : 40000; 252653790Sobrien np->clock_khz *= np->multiplier; 252753790Sobrien 252853790Sobrien if (np->clock_khz != 40000) 252953790Sobrien sym_getclock(np, np->multiplier); 253053790Sobrien 253153790Sobrien /* 253253790Sobrien * Divisor to be used for async (timer pre-scaler). 253353790Sobrien */ 253453790Sobrien i = np->clock_divn - 1; 253553790Sobrien while (--i >= 0) { 253654690Sobrien if (10ul * SYM_CONF_MIN_ASYNC * np->clock_khz > div_10M[i]) { 253753790Sobrien ++i; 253853790Sobrien break; 253953790Sobrien } 254053790Sobrien } 254153790Sobrien np->rv_scntl3 = i+1; 254253790Sobrien 254353790Sobrien /* 254453790Sobrien * The C1010 uses hardwired divisors for async. 254553790Sobrien * So, we just throw away, the async. divisor.:-) 254653790Sobrien */ 254753790Sobrien if (np->features & FE_C10) 254853790Sobrien np->rv_scntl3 = 0; 254953790Sobrien 255053790Sobrien /* 255153790Sobrien * Minimum synchronous period factor supported by the chip. 255253790Sobrien * Btw, 'period' is in tenths of nanoseconds. 255353790Sobrien */ 255453790Sobrien period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; 255553790Sobrien if (period <= 250) np->minsync = 10; 255653790Sobrien else if (period <= 303) np->minsync = 11; 255753790Sobrien else if (period <= 500) np->minsync = 12; 255853790Sobrien else np->minsync = (period + 40 - 1) / 40; 255953790Sobrien 256053790Sobrien /* 256153790Sobrien * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). 256253790Sobrien */ 256353790Sobrien if (np->minsync < 25 && 256453790Sobrien !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3))) 256553790Sobrien np->minsync = 25; 256653790Sobrien else if (np->minsync < 12 && 256753790Sobrien !(np->features & (FE_ULTRA2|FE_ULTRA3))) 256853790Sobrien np->minsync = 12; 256953790Sobrien 257053790Sobrien /* 257153790Sobrien * Maximum synchronous period factor supported by the chip. 257253790Sobrien */ 257353790Sobrien period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz); 257453790Sobrien np->maxsync = period > 2540 ? 254 : period / 10; 257553790Sobrien 257653790Sobrien /* 257753790Sobrien * If chip is a C1010, guess the sync limits in DT mode. 257853790Sobrien */ 257953790Sobrien if ((np->features & (FE_C10|FE_ULTRA3)) == (FE_C10|FE_ULTRA3)) { 258053790Sobrien if (np->clock_khz == 160000) { 258153790Sobrien np->minsync_dt = 9; 258253790Sobrien np->maxsync_dt = 50; 258360134Sgroudier np->maxoffs_dt = 62; 258453790Sobrien } 258553790Sobrien } 2586178466Smarius 258753790Sobrien /* 258865404Sgroudier * 64 bit addressing (895A/896/1010) ? 258953790Sobrien */ 2590153085Sru if (np->features & FE_DAC) 2591153085Sru#ifdef __LP64__ 2592153085Sru np->rv_ccntl1 |= (XTIMOD | EXTIBMV); 2593153085Sru#else 2594153085Sru np->rv_ccntl1 |= (DDAC); 2595153085Sru#endif 259653790Sobrien 259753790Sobrien /* 259853790Sobrien * Phase mismatch handled by SCRIPTS (895A/896/1010) ? 259953790Sobrien */ 260053790Sobrien if (np->features & FE_NOPM) 260153790Sobrien np->rv_ccntl0 |= (ENPMJ); 260253790Sobrien 260353790Sobrien /* 260453790Sobrien * C1010 Errata. 260553790Sobrien * In dual channel mode, contention occurs if internal cycles 260653790Sobrien * are used. Disable internal cycles. 260753790Sobrien */ 260861051Sgroudier if (np->device_id == PCI_ID_LSI53C1010 && 260971742Sgroudier np->revision_id < 0x2) 261053790Sobrien np->rv_ccntl0 |= DILS; 261153790Sobrien 261253790Sobrien /* 261353790Sobrien * Select burst length (dwords) 261453790Sobrien */ 261554690Sobrien burst_max = SYM_SETUP_BURST_ORDER; 261653790Sobrien if (burst_max == 255) 261753790Sobrien burst_max = burst_code(np->sv_dmode, np->sv_ctest4, 261853790Sobrien np->sv_ctest5); 261953790Sobrien if (burst_max > 7) 262053790Sobrien burst_max = 7; 262153790Sobrien if (burst_max > np->maxburst) 262253790Sobrien burst_max = np->maxburst; 262353790Sobrien 262453790Sobrien /* 262553790Sobrien * DEL 352 - 53C810 Rev x11 - Part Number 609-0392140 - ITEM 2. 2626178466Smarius * This chip and the 860 Rev 1 may wrongly use PCI cache line 2627178466Smarius * based transactions on LOAD/STORE instructions. So we have 2628178466Smarius * to prevent these chips from using such PCI transactions in 2629178466Smarius * this driver. The generic ncr driver that does not use 263053790Sobrien * LOAD/STORE instructions does not need this work-around. 263153790Sobrien */ 263253790Sobrien if ((np->device_id == PCI_ID_SYM53C810 && 263353790Sobrien np->revision_id >= 0x10 && np->revision_id <= 0x11) || 263453790Sobrien (np->device_id == PCI_ID_SYM53C860 && 263553790Sobrien np->revision_id <= 0x1)) 263653790Sobrien np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP); 263753790Sobrien 263853790Sobrien /* 263953790Sobrien * Select all supported special features. 2640178466Smarius * If we are using on-board RAM for scripts, prefetch (PFEN) 264153790Sobrien * does not help, but burst op fetch (BOF) does. 264253790Sobrien * Disabling PFEN makes sure BOF will be used. 264353790Sobrien */ 264453790Sobrien if (np->features & FE_ERL) 264553790Sobrien np->rv_dmode |= ERL; /* Enable Read Line */ 264653790Sobrien if (np->features & FE_BOF) 264753790Sobrien np->rv_dmode |= BOF; /* Burst Opcode Fetch */ 264853790Sobrien if (np->features & FE_ERMP) 264953790Sobrien np->rv_dmode |= ERMP; /* Enable Read Multiple */ 265053790Sobrien#if 1 265153790Sobrien if ((np->features & FE_PFEN) && !np->ram_ba) 265253790Sobrien#else 265353790Sobrien if (np->features & FE_PFEN) 265453790Sobrien#endif 265553790Sobrien np->rv_dcntl |= PFEN; /* Prefetch Enable */ 265653790Sobrien if (np->features & FE_CLSE) 265753790Sobrien np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ 265853790Sobrien if (np->features & FE_WRIE) 265953790Sobrien np->rv_ctest3 |= WRIE; /* Write and Invalidate */ 266053790Sobrien if (np->features & FE_DFS) 266153790Sobrien np->rv_ctest5 |= DFS; /* Dma Fifo Size */ 266253790Sobrien 266353790Sobrien /* 266453790Sobrien * Select some other 266553790Sobrien */ 266654690Sobrien if (SYM_SETUP_PCI_PARITY) 266753790Sobrien np->rv_ctest4 |= MPEE; /* Master parity checking */ 266854690Sobrien if (SYM_SETUP_SCSI_PARITY) 266953790Sobrien np->rv_scntl0 |= 0x0a; /* full arb., ena parity, par->ATN */ 267053790Sobrien 267153790Sobrien /* 267253790Sobrien * Get parity checking, host ID and verbose mode from NVRAM 267353790Sobrien */ 267453790Sobrien np->myaddr = 255; 267553790Sobrien sym_nvram_setup_host (np, nvram); 2676207285Smarius#ifdef __sparc64__ 2677207285Smarius np->myaddr = OF_getscsinitid(np->device); 2678207285Smarius#endif 267953790Sobrien 268053790Sobrien /* 268153790Sobrien * Get SCSI addr of host adapter (set by bios?). 268253790Sobrien */ 268353790Sobrien if (np->myaddr == 255) { 268453790Sobrien np->myaddr = INB(nc_scid) & 0x07; 268553790Sobrien if (!np->myaddr) 268654690Sobrien np->myaddr = SYM_SETUP_HOST_ID; 268753790Sobrien } 268853790Sobrien 268953790Sobrien /* 269053790Sobrien * Prepare initial io register bits for burst length 269153790Sobrien */ 269253790Sobrien sym_init_burst(np, burst_max); 269353790Sobrien 269453790Sobrien /* 269553790Sobrien * Set SCSI BUS mode. 2696178466Smarius * - LVD capable chips (895/895A/896/1010) report the 269753790Sobrien * current BUS mode through the STEST4 IO register. 2698178466Smarius * - For previous generation chips (825/825A/875), 2699178466Smarius * user has to tell us how to check against HVD, 270053790Sobrien * since a 100% safe algorithm is not possible. 270153790Sobrien */ 270253790Sobrien np->scsi_mode = SMODE_SE; 270353790Sobrien if (np->features & (FE_ULTRA2|FE_ULTRA3)) 270453790Sobrien np->scsi_mode = (np->sv_stest4 & SMODE); 270553790Sobrien else if (np->features & FE_DIFF) { 270654690Sobrien if (SYM_SETUP_SCSI_DIFF == 1) { 270753790Sobrien if (np->sv_scntl3) { 270853790Sobrien if (np->sv_stest2 & 0x20) 270953790Sobrien np->scsi_mode = SMODE_HVD; 271053790Sobrien } 271153790Sobrien else if (nvram->type == SYM_SYMBIOS_NVRAM) { 271271742Sgroudier if (!(INB(nc_gpreg) & 0x08)) 271353790Sobrien np->scsi_mode = SMODE_HVD; 271453790Sobrien } 271553790Sobrien } 271654690Sobrien else if (SYM_SETUP_SCSI_DIFF == 2) 271753790Sobrien np->scsi_mode = SMODE_HVD; 271853790Sobrien } 271953790Sobrien if (np->scsi_mode == SMODE_HVD) 272053790Sobrien np->rv_stest2 |= 0x20; 272153790Sobrien 272253790Sobrien /* 272353790Sobrien * Set LED support from SCRIPTS. 2724178466Smarius * Ignore this feature for boards known to use a 2725178466Smarius * specific GPIO wiring and for the 895A, 896 272662422Sgroudier * and 1010 that drive the LED directly. 272753790Sobrien */ 2728178466Smarius if ((SYM_SETUP_SCSI_LED || 272979042Sgroudier (nvram->type == SYM_SYMBIOS_NVRAM || 273079042Sgroudier (nvram->type == SYM_TEKRAM_NVRAM && 273179042Sgroudier np->device_id == PCI_ID_SYM53C895))) && 273253790Sobrien !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01)) 273353790Sobrien np->features |= FE_LED0; 273453790Sobrien 273553790Sobrien /* 273653790Sobrien * Set irq mode. 273753790Sobrien */ 273854690Sobrien switch(SYM_SETUP_IRQ_MODE & 3) { 273953790Sobrien case 2: 274053790Sobrien np->rv_dcntl |= IRQM; 274153790Sobrien break; 274253790Sobrien case 1: 274353790Sobrien np->rv_dcntl |= (np->sv_dcntl & IRQM); 274453790Sobrien break; 274553790Sobrien default: 274653790Sobrien break; 274753790Sobrien } 274853790Sobrien 274953790Sobrien /* 275053790Sobrien * Configure targets according to driver setup. 275153790Sobrien * If NVRAM present get targets setup from NVRAM. 275253790Sobrien */ 275354690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 275453790Sobrien tcb_p tp = &np->target[i]; 275553790Sobrien 275674755Sgroudier tp->tinfo.user.scsi_version = tp->tinfo.current.scsi_version= 2; 275774755Sgroudier tp->tinfo.user.spi_version = tp->tinfo.current.spi_version = 2; 275853790Sobrien tp->tinfo.user.period = np->minsync; 2759181399Smarius if (np->features & FE_ULTRA3) 2760181399Smarius tp->tinfo.user.period = np->minsync_dt; 276153790Sobrien tp->tinfo.user.offset = np->maxoffs; 276253790Sobrien tp->tinfo.user.width = np->maxwide ? BUS_16_BIT : BUS_8_BIT; 276353790Sobrien tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); 276454690Sobrien tp->usrtags = SYM_SETUP_MAX_TAG; 276553790Sobrien 276653790Sobrien sym_nvram_setup_target (np, i, nvram); 276753790Sobrien 276860134Sgroudier /* 2769178466Smarius * For now, guess PPR/DT support from the period 277061639Sgroudier * and BUS width. 277160134Sgroudier */ 277261639Sgroudier if (np->features & FE_ULTRA3) { 277361639Sgroudier if (tp->tinfo.user.period <= 9 && 277461639Sgroudier tp->tinfo.user.width == BUS_16_BIT) { 277561639Sgroudier tp->tinfo.user.options |= PPR_OPT_DT; 277661639Sgroudier tp->tinfo.user.offset = np->maxoffs_dt; 277774755Sgroudier tp->tinfo.user.spi_version = 3; 277861639Sgroudier } 277960134Sgroudier } 278060134Sgroudier 278153790Sobrien if (!tp->usrtags) 278253790Sobrien tp->usrflags &= ~SYM_TAGS_ENABLED; 278353790Sobrien } 278453790Sobrien 278553790Sobrien /* 278653790Sobrien * Let user know about the settings. 278753790Sobrien */ 278853790Sobrien i = nvram->type; 278955300Sgroudier printf("%s: %s NVRAM, ID %d, Fast-%d, %s, %s\n", sym_name(np), 279053790Sobrien i == SYM_SYMBIOS_NVRAM ? "Symbios" : 279153790Sobrien (i == SYM_TEKRAM_NVRAM ? "Tekram" : "No"), 279253790Sobrien np->myaddr, 2793178466Smarius (np->features & FE_ULTRA3) ? 80 : 2794178466Smarius (np->features & FE_ULTRA2) ? 40 : 279555300Sgroudier (np->features & FE_ULTRA) ? 20 : 10, 279655300Sgroudier sym_scsi_bus_mode(np->scsi_mode), 279755300Sgroudier (np->rv_scntl0 & 0xa) ? "parity checking" : "NO parity"); 279853790Sobrien /* 279953790Sobrien * Tell him more on demand. 280053790Sobrien */ 280155300Sgroudier if (sym_verbose) { 280253790Sobrien printf("%s: %s IRQ line driver%s\n", 280353790Sobrien sym_name(np), 280453790Sobrien np->rv_dcntl & IRQM ? "totem pole" : "open drain", 280553790Sobrien np->ram_ba ? ", using on-chip SRAM" : ""); 280659743Sgroudier printf("%s: using %s firmware.\n", sym_name(np), np->fw_name); 280755300Sgroudier if (np->features & FE_NOPM) 2808178466Smarius printf("%s: handling phase mismatch from SCRIPTS.\n", 280955300Sgroudier sym_name(np)); 281055300Sgroudier } 281153790Sobrien /* 281253790Sobrien * And still more. 281353790Sobrien */ 281453790Sobrien if (sym_verbose > 1) { 281553790Sobrien printf ("%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " 281653790Sobrien "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", 281753790Sobrien sym_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl, 281853790Sobrien np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); 281953790Sobrien 282053790Sobrien printf ("%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " 282153790Sobrien "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", 282253790Sobrien sym_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl, 282353790Sobrien np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); 282453790Sobrien } 282553790Sobrien /* 282653790Sobrien * Let user be aware of targets that have some disable flags set. 282753790Sobrien */ 282853790Sobrien sym_print_targets_flag(np, SYM_SCAN_BOOT_DISABLED, "SCAN AT BOOT"); 282953790Sobrien if (sym_verbose) 283053790Sobrien sym_print_targets_flag(np, SYM_SCAN_LUNS_DISABLED, 283153790Sobrien "SCAN FOR LUNS"); 283253790Sobrien 283353790Sobrien return 0; 283453790Sobrien} 283553790Sobrien 283653790Sobrien/* 283753790Sobrien * Prepare the next negotiation message if needed. 283853790Sobrien * 2839178466Smarius * Fill in the part of message buffer that contains the 284053790Sobrien * negotiation and the nego_status field of the CCB. 284153790Sobrien * Returns the size of the message in bytes. 284253790Sobrien */ 284353790Sobrienstatic int sym_prepare_nego(hcb_p np, ccb_p cp, int nego, u_char *msgptr) 284453790Sobrien{ 284553790Sobrien tcb_p tp = &np->target[cp->target]; 284653790Sobrien int msglen = 0; 284753790Sobrien 284853790Sobrien /* 2849178466Smarius * Early C1010 chips need a work-around for DT 285053796Sobrien * data transfer to work. 285153796Sobrien */ 285253790Sobrien if (!(np->features & FE_U3EN)) 285353790Sobrien tp->tinfo.goal.options = 0; 285453790Sobrien /* 285553790Sobrien * negotiate using PPR ? 285653790Sobrien */ 285753790Sobrien if (tp->tinfo.goal.options & PPR_OPT_MASK) 285853790Sobrien nego = NS_PPR; 285953790Sobrien /* 286053790Sobrien * negotiate wide transfers ? 286153790Sobrien */ 286253790Sobrien else if (tp->tinfo.current.width != tp->tinfo.goal.width) 286353790Sobrien nego = NS_WIDE; 286453790Sobrien /* 286553790Sobrien * negotiate synchronous transfers? 286653790Sobrien */ 286753790Sobrien else if (tp->tinfo.current.period != tp->tinfo.goal.period || 286853790Sobrien tp->tinfo.current.offset != tp->tinfo.goal.offset) 286953790Sobrien nego = NS_SYNC; 287053790Sobrien 287153790Sobrien switch (nego) { 287253790Sobrien case NS_SYNC: 287353790Sobrien msgptr[msglen++] = M_EXTENDED; 287453790Sobrien msgptr[msglen++] = 3; 287553790Sobrien msgptr[msglen++] = M_X_SYNC_REQ; 287653790Sobrien msgptr[msglen++] = tp->tinfo.goal.period; 287753790Sobrien msgptr[msglen++] = tp->tinfo.goal.offset; 287853790Sobrien break; 287953790Sobrien case NS_WIDE: 288053790Sobrien msgptr[msglen++] = M_EXTENDED; 288153790Sobrien msgptr[msglen++] = 2; 288253790Sobrien msgptr[msglen++] = M_X_WIDE_REQ; 288353790Sobrien msgptr[msglen++] = tp->tinfo.goal.width; 288453790Sobrien break; 288553790Sobrien case NS_PPR: 288653790Sobrien msgptr[msglen++] = M_EXTENDED; 288753790Sobrien msgptr[msglen++] = 6; 288853790Sobrien msgptr[msglen++] = M_X_PPR_REQ; 288953790Sobrien msgptr[msglen++] = tp->tinfo.goal.period; 289053790Sobrien msgptr[msglen++] = 0; 289153790Sobrien msgptr[msglen++] = tp->tinfo.goal.offset; 289253790Sobrien msgptr[msglen++] = tp->tinfo.goal.width; 289353790Sobrien msgptr[msglen++] = tp->tinfo.goal.options & PPR_OPT_DT; 289453790Sobrien break; 289553790Sobrien }; 289653790Sobrien 289753790Sobrien cp->nego_status = nego; 289853790Sobrien 289953790Sobrien if (nego) { 290053790Sobrien tp->nego_cp = cp; /* Keep track a nego will be performed */ 290153790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 290253809Sobrien sym_print_msg(cp, nego == NS_SYNC ? "sync msgout" : 290353809Sobrien nego == NS_WIDE ? "wide msgout" : 290453809Sobrien "ppr msgout", msgptr); 290553790Sobrien }; 290653790Sobrien }; 290753790Sobrien 290853790Sobrien return msglen; 290953790Sobrien} 291053790Sobrien 291153790Sobrien/* 291253790Sobrien * Insert a job into the start queue. 291353790Sobrien */ 291453790Sobrienstatic void sym_put_start_queue(hcb_p np, ccb_p cp) 291553790Sobrien{ 291653790Sobrien u_short qidx; 291753790Sobrien 291854690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 291953790Sobrien /* 2920178466Smarius * If the previously queued CCB is not yet done, 2921178466Smarius * set the IARB hint. The SCRIPTS will go with IARB 292253790Sobrien * for this job when starting the previous one. 2923178466Smarius * We leave devices a chance to win arbitration by 2924178466Smarius * not using more than 'iarb_max' consecutive 292553790Sobrien * immediate arbitrations. 292653790Sobrien */ 292753790Sobrien if (np->last_cp && np->iarb_count < np->iarb_max) { 292853790Sobrien np->last_cp->host_flags |= HF_HINT_IARB; 292953790Sobrien ++np->iarb_count; 293053790Sobrien } 293153790Sobrien else 293253790Sobrien np->iarb_count = 0; 293353790Sobrien np->last_cp = cp; 293453790Sobrien#endif 2935178466Smarius 293653790Sobrien /* 293753790Sobrien * Insert first the idle task and then our job. 293853790Sobrien * The MB should ensure proper ordering. 293953790Sobrien */ 294053790Sobrien qidx = np->squeueput + 2; 294153790Sobrien if (qidx >= MAX_QUEUE*2) qidx = 0; 294253790Sobrien 294353790Sobrien np->squeue [qidx] = cpu_to_scr(np->idletask_ba); 294453790Sobrien MEMORY_BARRIER(); 294553790Sobrien np->squeue [np->squeueput] = cpu_to_scr(cp->ccb_ba); 294653790Sobrien 294753790Sobrien np->squeueput = qidx; 294853790Sobrien 294953790Sobrien if (DEBUG_FLAGS & DEBUG_QUEUE) 295053790Sobrien printf ("%s: queuepos=%d.\n", sym_name (np), np->squeueput); 295153790Sobrien 295253790Sobrien /* 295353790Sobrien * Script processor may be waiting for reselect. 295453790Sobrien * Wake it up. 295553790Sobrien */ 295653790Sobrien MEMORY_BARRIER(); 295753790Sobrien OUTB (nc_istat, SIGP|np->istat_sem); 295853790Sobrien} 295953790Sobrien 296053790Sobrien/* 296153790Sobrien * Soft reset the chip. 296253790Sobrien * 2963178466Smarius * Raising SRST when the chip is running may cause 296455300Sgroudier * problems on dual function chips (see below). 2965178466Smarius * On the other hand, LVD devices need some delay 296655300Sgroudier * to settle and report actual BUS mode in STEST4. 296753796Sobrien */ 296853796Sobrienstatic void sym_chip_reset (hcb_p np) 296953796Sobrien{ 297053796Sobrien OUTB (nc_istat, SRST); 297153796Sobrien UDELAY (10); 297253796Sobrien OUTB (nc_istat, 0); 297355300Sgroudier UDELAY(2000); /* For BUS MODE to settle */ 297453796Sobrien} 297553796Sobrien 297653796Sobrien/* 297753796Sobrien * Soft reset the chip. 297853796Sobrien * 2979178466Smarius * Some 896 and 876 chip revisions may hang-up if we set 2980178466Smarius * the SRST (soft reset) bit at the wrong time when SCRIPTS 298153790Sobrien * are running. 2982178466Smarius * So, we need to abort the current operation prior to 298353790Sobrien * soft resetting the chip. 298453790Sobrien */ 298553790Sobrienstatic void sym_soft_reset (hcb_p np) 298653790Sobrien{ 298753790Sobrien u_char istat; 298853790Sobrien int i; 298953790Sobrien 299053790Sobrien OUTB (nc_istat, CABRT); 299153790Sobrien for (i = 1000000 ; i ; --i) { 299253790Sobrien istat = INB (nc_istat); 299353790Sobrien if (istat & SIP) { 299453790Sobrien INW (nc_sist); 299553790Sobrien continue; 299653790Sobrien } 299753790Sobrien if (istat & DIP) { 299853790Sobrien OUTB (nc_istat, 0); 299953790Sobrien INB (nc_dstat); 300053790Sobrien break; 300153790Sobrien } 300253790Sobrien } 300353790Sobrien if (!i) 300453790Sobrien printf("%s: unable to abort current chip operation.\n", 300553790Sobrien sym_name(np)); 300653796Sobrien sym_chip_reset (np); 300753790Sobrien} 300853790Sobrien 300953790Sobrien/* 301053790Sobrien * Start reset process. 301153790Sobrien * 301253790Sobrien * The interrupt handler will reinitialize the chip. 301353790Sobrien */ 301453790Sobrienstatic void sym_start_reset(hcb_p np) 301553790Sobrien{ 301653790Sobrien (void) sym_reset_scsi_bus(np, 1); 301753790Sobrien} 3018178466Smarius 301953790Sobrienstatic int sym_reset_scsi_bus(hcb_p np, int enab_int) 302053790Sobrien{ 302153790Sobrien u32 term; 302253790Sobrien int retv = 0; 302353790Sobrien 302453790Sobrien sym_soft_reset(np); /* Soft reset the chip */ 302553790Sobrien if (enab_int) 302653790Sobrien OUTW (nc_sien, RST); 302753790Sobrien /* 3028178466Smarius * Enable Tolerant, reset IRQD if present and 302953790Sobrien * properly set IRQ mode, prior to resetting the bus. 303053790Sobrien */ 303153790Sobrien OUTB (nc_stest3, TE); 303253790Sobrien OUTB (nc_dcntl, (np->rv_dcntl & IRQM)); 303353790Sobrien OUTB (nc_scntl1, CRST); 303453790Sobrien UDELAY (200); 303553790Sobrien 303654690Sobrien if (!SYM_SETUP_SCSI_BUS_CHECK) 303753790Sobrien goto out; 303853790Sobrien /* 303953790Sobrien * Check for no terminators or SCSI bus shorts to ground. 304053790Sobrien * Read SCSI data bus, data parity bits and control signals. 3041178466Smarius * We are expecting RESET to be TRUE and other signals to be 304253790Sobrien * FALSE. 304353790Sobrien */ 304455300Sgroudier term = INB(nc_sstat0); 304555300Sgroudier term = ((term & 2) << 7) + ((term & 1) << 17); /* rst sdp0 */ 304655300Sgroudier term |= ((INB(nc_sstat2) & 0x01) << 26) | /* sdp1 */ 304755300Sgroudier ((INW(nc_sbdl) & 0xff) << 9) | /* d7-0 */ 304855300Sgroudier ((INW(nc_sbdl) & 0xff00) << 10) | /* d15-8 */ 304955300Sgroudier INB(nc_sbcl); /* req ack bsy sel atn msg cd io */ 305053790Sobrien 305153790Sobrien if (!(np->features & FE_WIDE)) 305253790Sobrien term &= 0x3ffff; 305353790Sobrien 305453790Sobrien if (term != (2<<7)) { 305553790Sobrien printf("%s: suspicious SCSI data while resetting the BUS.\n", 305653790Sobrien sym_name(np)); 305753790Sobrien printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " 305853790Sobrien "0x%lx, expecting 0x%lx\n", 305953790Sobrien sym_name(np), 306053790Sobrien (np->features & FE_WIDE) ? "dp1,d15-8," : "", 306153790Sobrien (u_long)term, (u_long)(2<<7)); 306254690Sobrien if (SYM_SETUP_SCSI_BUS_CHECK == 1) 306353790Sobrien retv = 1; 306453790Sobrien } 306553790Sobrienout: 306653790Sobrien OUTB (nc_scntl1, 0); 306753790Sobrien /* MDELAY(100); */ 306853790Sobrien return retv; 306953790Sobrien} 307053790Sobrien 307153790Sobrien/* 307253790Sobrien * The chip may have completed jobs. Look at the DONE QUEUE. 307362422Sgroudier * 3074178466Smarius * On architectures that may reorder LOAD/STORE operations, 3075178466Smarius * a memory barrier may be needed after the reading of the 307662422Sgroudier * so-called `flag' and prior to dealing with the data. 307753790Sobrien */ 307853790Sobrienstatic int sym_wakeup_done (hcb_p np) 307953790Sobrien{ 308053790Sobrien ccb_p cp; 308153790Sobrien int i, n; 308261051Sgroudier u32 dsa; 308353790Sobrien 3084178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 3085178468Smarius 308653790Sobrien n = 0; 308753790Sobrien i = np->dqueueget; 308853790Sobrien while (1) { 308953790Sobrien dsa = scr_to_cpu(np->dqueue[i]); 309053790Sobrien if (!dsa) 309153790Sobrien break; 309253790Sobrien np->dqueue[i] = 0; 309353790Sobrien if ((i = i+2) >= MAX_QUEUE*2) 309453790Sobrien i = 0; 309553790Sobrien 309653790Sobrien cp = sym_ccb_from_dsa(np, dsa); 309753790Sobrien if (cp) { 309862422Sgroudier MEMORY_BARRIER(); 309953790Sobrien sym_complete_ok (np, cp); 310053790Sobrien ++n; 310153790Sobrien } 310253790Sobrien else 310361051Sgroudier printf ("%s: bad DSA (%x) in done queue.\n", 310461051Sgroudier sym_name(np), (u_int) dsa); 310553790Sobrien } 310653790Sobrien np->dqueueget = i; 310753790Sobrien 310853790Sobrien return n; 310953790Sobrien} 311053790Sobrien 311153790Sobrien/* 311253790Sobrien * Complete all active CCBs with error. 311353790Sobrien * Used on CHIP/SCSI RESET. 311453790Sobrien */ 311553790Sobrienstatic void sym_flush_busy_queue (hcb_p np, int cam_status) 311653790Sobrien{ 311753790Sobrien /* 3118178466Smarius * Move all active CCBs to the COMP queue 311953790Sobrien * and flush this queue. 312053790Sobrien */ 312153790Sobrien sym_que_splice(&np->busy_ccbq, &np->comp_ccbq); 312253790Sobrien sym_que_init(&np->busy_ccbq); 312353790Sobrien sym_flush_comp_queue(np, cam_status); 312453790Sobrien} 312553790Sobrien 312653790Sobrien/* 312753790Sobrien * Start chip. 312855300Sgroudier * 312955300Sgroudier * 'reason' means: 313055300Sgroudier * 0: initialisation. 313155300Sgroudier * 1: SCSI BUS RESET delivered or received. 313255300Sgroudier * 2: SCSI BUS MODE changed. 313353790Sobrien */ 313455300Sgroudierstatic void sym_init (hcb_p np, int reason) 313553790Sobrien{ 313653790Sobrien int i; 313761051Sgroudier u32 phys; 313853790Sobrien 3139178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 3140178468Smarius 314153790Sobrien /* 314253790Sobrien * Reset chip if asked, otherwise just clear fifos. 314353790Sobrien */ 314455300Sgroudier if (reason == 1) 314553790Sobrien sym_soft_reset(np); 314653790Sobrien else { 314753790Sobrien OUTB (nc_stest3, TE|CSF); 314853790Sobrien OUTONB (nc_ctest3, CLF); 314953790Sobrien } 3150178466Smarius 315153790Sobrien /* 315253790Sobrien * Clear Start Queue 315353790Sobrien */ 315458927Sgroudier phys = np->squeue_ba; 315553790Sobrien for (i = 0; i < MAX_QUEUE*2; i += 2) { 315653790Sobrien np->squeue[i] = cpu_to_scr(np->idletask_ba); 315753790Sobrien np->squeue[i+1] = cpu_to_scr(phys + (i+2)*4); 315853790Sobrien } 315953790Sobrien np->squeue[MAX_QUEUE*2-1] = cpu_to_scr(phys); 316053790Sobrien 316153790Sobrien /* 316253790Sobrien * Start at first entry. 316353790Sobrien */ 316453790Sobrien np->squeueput = 0; 316553790Sobrien 316653790Sobrien /* 316753790Sobrien * Clear Done Queue 316853790Sobrien */ 316959743Sgroudier phys = np->dqueue_ba; 317053790Sobrien for (i = 0; i < MAX_QUEUE*2; i += 2) { 317153790Sobrien np->dqueue[i] = 0; 317253790Sobrien np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4); 317353790Sobrien } 317453790Sobrien np->dqueue[MAX_QUEUE*2-1] = cpu_to_scr(phys); 317553790Sobrien 317653790Sobrien /* 317753790Sobrien * Start at first entry. 317853790Sobrien */ 317953790Sobrien np->dqueueget = 0; 318053790Sobrien 318153790Sobrien /* 318259743Sgroudier * Install patches in scripts. 3183178466Smarius * This also let point to first position the start 318459743Sgroudier * and done queue pointers used from SCRIPTS. 318559743Sgroudier */ 318659743Sgroudier np->fw_patch(np); 318759743Sgroudier 318859743Sgroudier /* 318953790Sobrien * Wakeup all pending jobs. 319053790Sobrien */ 319153790Sobrien sym_flush_busy_queue(np, CAM_SCSI_BUS_RESET); 319253790Sobrien 319353790Sobrien /* 319453790Sobrien * Init chip. 319553790Sobrien */ 319653790Sobrien OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */ 319753790Sobrien UDELAY (2000); /* The 895 needs time for the bus mode to settle */ 319853790Sobrien 319953790Sobrien OUTB (nc_scntl0, np->rv_scntl0 | 0xc0); 320053790Sobrien /* full arb., ena parity, par->ATN */ 320153790Sobrien OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ 320253790Sobrien 320353790Sobrien sym_selectclock(np, np->rv_scntl3); /* Select SCSI clock */ 320453790Sobrien 320553790Sobrien OUTB (nc_scid , RRE|np->myaddr); /* Adapter SCSI address */ 320653790Sobrien OUTW (nc_respid, 1ul<<np->myaddr); /* Id to respond to */ 320753790Sobrien OUTB (nc_istat , SIGP ); /* Signal Process */ 320853790Sobrien OUTB (nc_dmode , np->rv_dmode); /* Burst length, dma mode */ 320953790Sobrien OUTB (nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */ 321053790Sobrien 321153790Sobrien OUTB (nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */ 321253790Sobrien OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */ 321353790Sobrien OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */ 321453790Sobrien 321553790Sobrien /* Extended Sreq/Sack filtering not supported on the C10 */ 321653790Sobrien if (np->features & FE_C10) 321753790Sobrien OUTB (nc_stest2, np->rv_stest2); 321853790Sobrien else 321953790Sobrien OUTB (nc_stest2, EXT|np->rv_stest2); 322053790Sobrien 322153790Sobrien OUTB (nc_stest3, TE); /* TolerANT enable */ 322253790Sobrien OUTB (nc_stime0, 0x0c); /* HTH disabled STO 0.25 sec */ 322353790Sobrien 322453790Sobrien /* 322561051Sgroudier * For now, disable AIP generation on C1010-66. 322661051Sgroudier */ 322761051Sgroudier if (np->device_id == PCI_ID_LSI53C1010_2) 322861051Sgroudier OUTB (nc_aipcntl1, DISAIP); 322961051Sgroudier 323061051Sgroudier /* 323153790Sobrien * C10101 Errata. 323253790Sobrien * Errant SGE's when in narrow. Write bits 4 & 5 of 3233178466Smarius * STEST1 register to disable SGE. We probably should do 3234178466Smarius * that from SCRIPTS for each selection/reselection, but 323553790Sobrien * I just don't want. :) 323653790Sobrien */ 323761051Sgroudier if (np->device_id == PCI_ID_LSI53C1010 && 323861051Sgroudier /* np->revision_id < 0xff */ 1) 323953790Sobrien OUTB (nc_stest1, INB(nc_stest1) | 0x30); 324053790Sobrien 324153790Sobrien /* 324253790Sobrien * DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2. 3243178466Smarius * Disable overlapped arbitration for some dual function devices, 324453790Sobrien * regardless revision id (kind of post-chip-design feature. ;-)) 324553790Sobrien */ 324653790Sobrien if (np->device_id == PCI_ID_SYM53C875) 324753790Sobrien OUTB (nc_ctest0, (1<<5)); 324853790Sobrien else if (np->device_id == PCI_ID_SYM53C896) 324953790Sobrien np->rv_ccntl0 |= DPR; 325053790Sobrien 325153790Sobrien /* 3252178466Smarius * Write CCNTL0/CCNTL1 for chips capable of 64 bit addressing 3253178466Smarius * and/or hardware phase mismatch, since only such chips 325465404Sgroudier * seem to support those IO registers. 325553790Sobrien */ 325665404Sgroudier if (np->features & (FE_DAC|FE_NOPM)) { 325753790Sobrien OUTB (nc_ccntl0, np->rv_ccntl0); 325853790Sobrien OUTB (nc_ccntl1, np->rv_ccntl1); 325953790Sobrien } 326053790Sobrien 326153790Sobrien /* 326253790Sobrien * If phase mismatch handled by scripts (895A/896/1010), 326353790Sobrien * set PM jump addresses. 326453790Sobrien */ 326553790Sobrien if (np->features & FE_NOPM) { 326659292Sgroudier OUTL (nc_pmjad1, SCRIPTB_BA (np, pm_handle)); 326759292Sgroudier OUTL (nc_pmjad2, SCRIPTB_BA (np, pm_handle)); 326853790Sobrien } 326953790Sobrien 327053790Sobrien /* 327153790Sobrien * Enable GPIO0 pin for writing if LED support from SCRIPTS. 327253790Sobrien * Also set GPIO5 and clear GPIO6 if hardware LED control. 327353790Sobrien */ 327453790Sobrien if (np->features & FE_LED0) 327553790Sobrien OUTB(nc_gpcntl, INB(nc_gpcntl) & ~0x01); 327653790Sobrien else if (np->features & FE_LEDC) 327753790Sobrien OUTB(nc_gpcntl, (INB(nc_gpcntl) & ~0x41) | 0x20); 327853790Sobrien 327953790Sobrien /* 328053790Sobrien * enable ints 328153790Sobrien */ 328253790Sobrien OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR); 328353790Sobrien OUTB (nc_dien , MDPE|BF|SSI|SIR|IID); 328453790Sobrien 328553790Sobrien /* 328653790Sobrien * For 895/6 enable SBMC interrupt and save current SCSI bus mode. 3287178466Smarius * Try to eat the spurious SBMC interrupt that may occur when 328855300Sgroudier * we reset the chip but not the SCSI BUS (at initialization). 328953790Sobrien */ 329053790Sobrien if (np->features & (FE_ULTRA2|FE_ULTRA3)) { 329153790Sobrien OUTONW (nc_sien, SBMC); 329255300Sgroudier if (reason == 0) { 329355300Sgroudier MDELAY(100); 329455300Sgroudier INW (nc_sist); 329555300Sgroudier } 329653790Sobrien np->scsi_mode = INB (nc_stest4) & SMODE; 329753790Sobrien } 329853790Sobrien 329953790Sobrien /* 330053790Sobrien * Fill in target structure. 330153790Sobrien * Reinitialize usrsync. 330253790Sobrien * Reinitialize usrwide. 330353790Sobrien * Prepare sync negotiation according to actual SCSI bus mode. 330453790Sobrien */ 330554690Sobrien for (i=0;i<SYM_CONF_MAX_TARGET;i++) { 330653790Sobrien tcb_p tp = &np->target[i]; 330753790Sobrien 330859743Sgroudier tp->to_reset = 0; 330959743Sgroudier tp->head.sval = 0; 331059743Sgroudier tp->head.wval = np->rv_scntl3; 331159743Sgroudier tp->head.uval = 0; 331253790Sobrien 331353790Sobrien tp->tinfo.current.period = 0; 331453790Sobrien tp->tinfo.current.offset = 0; 331553790Sobrien tp->tinfo.current.width = BUS_8_BIT; 331653790Sobrien tp->tinfo.current.options = 0; 331753790Sobrien } 331853790Sobrien 331953790Sobrien /* 332053790Sobrien * Download SCSI SCRIPTS to on-chip RAM if present, 332153790Sobrien * and start script processor. 332253790Sobrien */ 332353790Sobrien if (np->ram_ba) { 332455300Sgroudier if (sym_verbose > 1) 332553790Sobrien printf ("%s: Downloading SCSI SCRIPTS.\n", 332653790Sobrien sym_name(np)); 332753790Sobrien if (np->ram_ws == 8192) { 332861429Sgroudier OUTRAM_OFF(4096, np->scriptb0, np->scriptb_sz); 332953790Sobrien OUTL (nc_mmws, np->scr_ram_seg); 333053790Sobrien OUTL (nc_mmrs, np->scr_ram_seg); 333153790Sobrien OUTL (nc_sfs, np->scr_ram_seg); 333259292Sgroudier phys = SCRIPTB_BA (np, start64); 333353790Sobrien } 333453790Sobrien else 333559292Sgroudier phys = SCRIPTA_BA (np, init); 333661429Sgroudier OUTRAM_OFF(0, np->scripta0, np->scripta_sz); 333753790Sobrien } 333853790Sobrien else 333959292Sgroudier phys = SCRIPTA_BA (np, init); 334053790Sobrien 334153790Sobrien np->istat_sem = 0; 334253790Sobrien 334358927Sgroudier OUTL (nc_dsa, np->hcb_ba); 334461429Sgroudier OUTL_DSP (phys); 334553790Sobrien 334653790Sobrien /* 334755300Sgroudier * Notify the XPT about the RESET condition. 334853790Sobrien */ 334955300Sgroudier if (reason != 0) 335055300Sgroudier xpt_async(AC_BUS_RESET, np->path, NULL); 335153790Sobrien} 335253790Sobrien 335353790Sobrien/* 3354178466Smarius * Get clock factor and sync divisor for a given 335553790Sobrien * synchronous factor period. 335653790Sobrien */ 3357178466Smariusstatic int 335853790Sobriensym_getsync(hcb_p np, u_char dt, u_char sfac, u_char *divp, u_char *fakp) 335953790Sobrien{ 336053790Sobrien u32 clk = np->clock_khz; /* SCSI clock frequency in kHz */ 336153790Sobrien int div = np->clock_divn; /* Number of divisors supported */ 336253790Sobrien u32 fak; /* Sync factor in sxfer */ 336353790Sobrien u32 per; /* Period in tenths of ns */ 336453790Sobrien u32 kpc; /* (per * clk) */ 336553790Sobrien int ret; 336653790Sobrien 336753790Sobrien /* 336853790Sobrien * Compute the synchronous period in tenths of nano-seconds 336953790Sobrien */ 337053790Sobrien if (dt && sfac <= 9) per = 125; 337153790Sobrien else if (sfac <= 10) per = 250; 337253790Sobrien else if (sfac == 11) per = 303; 337353790Sobrien else if (sfac == 12) per = 500; 337453790Sobrien else per = 40 * sfac; 337553790Sobrien ret = per; 337653790Sobrien 337753790Sobrien kpc = per * clk; 337853790Sobrien if (dt) 337953790Sobrien kpc <<= 1; 338053790Sobrien 338153790Sobrien /* 3382178466Smarius * For earliest C10 revision 0, we cannot use extra 338362422Sgroudier * clocks for the setting of the SCSI clocking. 3384178466Smarius * Note that this limits the lowest sync data transfer 338553790Sobrien * to 5 Mega-transfers per second and may result in 338653790Sobrien * using higher clock divisors. 338753790Sobrien */ 338853796Sobrien#if 1 338953790Sobrien if ((np->features & (FE_C10|FE_U3EN)) == FE_C10) { 339053790Sobrien /* 3391178466Smarius * Look for the lowest clock divisor that allows an 339253790Sobrien * output speed not faster than the period. 339353790Sobrien */ 339453796Sobrien while (div > 0) { 339553796Sobrien --div; 339653790Sobrien if (kpc > (div_10M[div] << 2)) { 339753790Sobrien ++div; 339853790Sobrien break; 339953790Sobrien } 340053790Sobrien } 340153790Sobrien fak = 0; /* No extra clocks */ 340253790Sobrien if (div == np->clock_divn) { /* Are we too fast ? */ 340353790Sobrien ret = -1; 340453790Sobrien } 340553790Sobrien *divp = div; 340653790Sobrien *fakp = fak; 340753790Sobrien return ret; 340853790Sobrien } 340953790Sobrien#endif 341053790Sobrien 341153790Sobrien /* 3412178466Smarius * Look for the greatest clock divisor that allows an 341353790Sobrien * input speed faster than the period. 341453790Sobrien */ 341553796Sobrien while (div-- > 0) 341653790Sobrien if (kpc >= (div_10M[div] << 2)) break; 341753790Sobrien 341853790Sobrien /* 3419178466Smarius * Calculate the lowest clock factor that allows an output 342053790Sobrien * speed not faster than the period, and the max output speed. 342153790Sobrien * If fak >= 1 we will set both XCLKH_ST and XCLKH_DT. 342253790Sobrien * If fak >= 2 we will also set XCLKS_ST and XCLKS_DT. 342353790Sobrien */ 342453790Sobrien if (dt) { 342553790Sobrien fak = (kpc - 1) / (div_10M[div] << 1) + 1 - 2; 342653790Sobrien /* ret = ((2+fak)*div_10M[div])/np->clock_khz; */ 342753790Sobrien } 342853790Sobrien else { 342953790Sobrien fak = (kpc - 1) / div_10M[div] + 1 - 4; 343053790Sobrien /* ret = ((4+fak)*div_10M[div])/np->clock_khz; */ 343153790Sobrien } 343253790Sobrien 343353790Sobrien /* 343453790Sobrien * Check against our hardware limits, or bugs :). 343553790Sobrien */ 343653790Sobrien if (fak > 2) {fak = 2; ret = -1;} 343753790Sobrien 343853790Sobrien /* 343953790Sobrien * Compute and return sync parameters. 344053790Sobrien */ 344153790Sobrien *divp = div; 344253790Sobrien *fakp = fak; 344353790Sobrien 344453790Sobrien return ret; 344553790Sobrien} 344653790Sobrien 344753790Sobrien/* 344874755Sgroudier * Tell the SCSI layer about the new transfer parameters. 344974755Sgroudier */ 3450178466Smariusstatic void 345174755Sgroudiersym_xpt_async_transfer_neg(hcb_p np, int target, u_int spi_valid) 345274755Sgroudier{ 345374755Sgroudier struct ccb_trans_settings cts; 345474755Sgroudier struct cam_path *path; 345574755Sgroudier int sts; 345674755Sgroudier tcb_p tp = &np->target[target]; 345774755Sgroudier 345874755Sgroudier sts = xpt_create_path(&path, NULL, cam_sim_path(np->sim), target, 345974755Sgroudier CAM_LUN_WILDCARD); 346074755Sgroudier if (sts != CAM_REQ_CMP) 346174755Sgroudier return; 346274755Sgroudier 346374755Sgroudier bzero(&cts, sizeof(cts)); 346474755Sgroudier 346574755Sgroudier#define cts__scsi (cts.proto_specific.scsi) 346674755Sgroudier#define cts__spi (cts.xport_specific.spi) 346774755Sgroudier 346874755Sgroudier cts.type = CTS_TYPE_CURRENT_SETTINGS; 346974755Sgroudier cts.protocol = PROTO_SCSI; 347074755Sgroudier cts.transport = XPORT_SPI; 347174755Sgroudier cts.protocol_version = tp->tinfo.current.scsi_version; 347274755Sgroudier cts.transport_version = tp->tinfo.current.spi_version; 347374755Sgroudier 347474755Sgroudier cts__spi.valid = spi_valid; 347574755Sgroudier if (spi_valid & CTS_SPI_VALID_SYNC_RATE) 347674755Sgroudier cts__spi.sync_period = tp->tinfo.current.period; 347774755Sgroudier if (spi_valid & CTS_SPI_VALID_SYNC_OFFSET) 347874755Sgroudier cts__spi.sync_offset = tp->tinfo.current.offset; 347974755Sgroudier if (spi_valid & CTS_SPI_VALID_BUS_WIDTH) 348074755Sgroudier cts__spi.bus_width = tp->tinfo.current.width; 348174755Sgroudier if (spi_valid & CTS_SPI_VALID_PPR_OPTIONS) 348274755Sgroudier cts__spi.ppr_options = tp->tinfo.current.options; 348374755Sgroudier#undef cts__spi 348474755Sgroudier#undef cts__scsi 348574755Sgroudier xpt_setup_ccb(&cts.ccb_h, path, /*priority*/1); 348674755Sgroudier xpt_async(AC_TRANSFER_NEG, path, &cts); 348774755Sgroudier xpt_free_path(path); 348874755Sgroudier} 348974755Sgroudier 349074755Sgroudier#define SYM_SPI_VALID_WDTR \ 349174755Sgroudier CTS_SPI_VALID_BUS_WIDTH | \ 349274755Sgroudier CTS_SPI_VALID_SYNC_RATE | \ 349374755Sgroudier CTS_SPI_VALID_SYNC_OFFSET 349474755Sgroudier#define SYM_SPI_VALID_SDTR \ 349574755Sgroudier CTS_SPI_VALID_SYNC_RATE | \ 349674755Sgroudier CTS_SPI_VALID_SYNC_OFFSET 349774755Sgroudier#define SYM_SPI_VALID_PPR \ 349874755Sgroudier CTS_SPI_VALID_PPR_OPTIONS | \ 349974755Sgroudier CTS_SPI_VALID_BUS_WIDTH | \ 350074755Sgroudier CTS_SPI_VALID_SYNC_RATE | \ 350174755Sgroudier CTS_SPI_VALID_SYNC_OFFSET 350274755Sgroudier 350374755Sgroudier/* 350453790Sobrien * We received a WDTR. 350553790Sobrien * Let everything be aware of the changes. 350653790Sobrien */ 350753790Sobrienstatic void sym_setwide(hcb_p np, ccb_p cp, u_char wide) 350853790Sobrien{ 350953790Sobrien tcb_p tp = &np->target[cp->target]; 351053790Sobrien 351153790Sobrien sym_settrans(np, cp, 0, 0, 0, wide, 0, 0); 351253790Sobrien 351353790Sobrien /* 351453790Sobrien * Tell the SCSI layer about the new transfer parameters. 351553790Sobrien */ 351653790Sobrien tp->tinfo.goal.width = tp->tinfo.current.width = wide; 351753796Sobrien tp->tinfo.current.offset = 0; 351853796Sobrien tp->tinfo.current.period = 0; 351953809Sobrien tp->tinfo.current.options = 0; 352074755Sgroudier 352174755Sgroudier sym_xpt_async_transfer_neg(np, cp->target, SYM_SPI_VALID_WDTR); 352253790Sobrien} 352353790Sobrien 352453790Sobrien/* 352553790Sobrien * We received a SDTR. 352653790Sobrien * Let everything be aware of the changes. 352753790Sobrien */ 352853790Sobrienstatic void 352953790Sobriensym_setsync(hcb_p np, ccb_p cp, u_char ofs, u_char per, u_char div, u_char fak) 353053790Sobrien{ 353153790Sobrien tcb_p tp = &np->target[cp->target]; 353253790Sobrien u_char wide = (cp->phys.select.sel_scntl3 & EWS) ? 1 : 0; 353353790Sobrien 353453790Sobrien sym_settrans(np, cp, 0, ofs, per, wide, div, fak); 353553790Sobrien 353653790Sobrien /* 353753790Sobrien * Tell the SCSI layer about the new transfer parameters. 353853790Sobrien */ 353953790Sobrien tp->tinfo.goal.period = tp->tinfo.current.period = per; 354053790Sobrien tp->tinfo.goal.offset = tp->tinfo.current.offset = ofs; 354153790Sobrien tp->tinfo.goal.options = tp->tinfo.current.options = 0; 354274755Sgroudier 354374755Sgroudier sym_xpt_async_transfer_neg(np, cp->target, SYM_SPI_VALID_SDTR); 354453790Sobrien} 354553790Sobrien 354653790Sobrien/* 354753790Sobrien * We received a PPR. 354853790Sobrien * Let everything be aware of the changes. 354953790Sobrien */ 355053790Sobrienstatic void sym_setpprot(hcb_p np, ccb_p cp, u_char dt, u_char ofs, 355153790Sobrien u_char per, u_char wide, u_char div, u_char fak) 355253790Sobrien{ 355353790Sobrien tcb_p tp = &np->target[cp->target]; 355453790Sobrien 355553790Sobrien sym_settrans(np, cp, dt, ofs, per, wide, div, fak); 355653790Sobrien 355753790Sobrien /* 355853790Sobrien * Tell the SCSI layer about the new transfer parameters. 355953790Sobrien */ 356053790Sobrien tp->tinfo.goal.width = tp->tinfo.current.width = wide; 356153790Sobrien tp->tinfo.goal.period = tp->tinfo.current.period = per; 356253790Sobrien tp->tinfo.goal.offset = tp->tinfo.current.offset = ofs; 356353809Sobrien tp->tinfo.goal.options = tp->tinfo.current.options = dt; 356474755Sgroudier 356574755Sgroudier sym_xpt_async_transfer_neg(np, cp->target, SYM_SPI_VALID_PPR); 356653790Sobrien} 356753790Sobrien 356853790Sobrien/* 356953790Sobrien * Switch trans mode for current job and it's target. 357053790Sobrien */ 357153790Sobrienstatic void sym_settrans(hcb_p np, ccb_p cp, u_char dt, u_char ofs, 357253790Sobrien u_char per, u_char wide, u_char div, u_char fak) 357353790Sobrien{ 357455300Sgroudier SYM_QUEHEAD *qp; 357553790Sobrien union ccb *ccb; 357653790Sobrien tcb_p tp; 357753790Sobrien u_char target = INB (nc_sdid) & 0x0f; 357853790Sobrien u_char sval, wval, uval; 357953790Sobrien 358053790Sobrien assert (cp); 358153790Sobrien if (!cp) return; 358253790Sobrien ccb = cp->cam_ccb; 358353790Sobrien assert (ccb); 358453790Sobrien if (!ccb) return; 358553790Sobrien assert (target == (cp->target & 0xf)); 358653790Sobrien tp = &np->target[target]; 358753790Sobrien 358859743Sgroudier sval = tp->head.sval; 358959743Sgroudier wval = tp->head.wval; 359059743Sgroudier uval = tp->head.uval; 359157186Sgroudier 359253790Sobrien#if 0 3593178466Smarius printf("XXXX sval=%x wval=%x uval=%x (%x)\n", 359453790Sobrien sval, wval, uval, np->rv_scntl3); 359553790Sobrien#endif 359653790Sobrien /* 359753790Sobrien * Set the offset. 359853790Sobrien */ 359953790Sobrien if (!(np->features & FE_C10)) 360053790Sobrien sval = (sval & ~0x1f) | ofs; 360153790Sobrien else 360253790Sobrien sval = (sval & ~0x3f) | ofs; 360353790Sobrien 360453790Sobrien /* 360553790Sobrien * Set the sync divisor and extra clock factor. 360653790Sobrien */ 360753790Sobrien if (ofs != 0) { 360853790Sobrien wval = (wval & ~0x70) | ((div+1) << 4); 360953790Sobrien if (!(np->features & FE_C10)) 361053790Sobrien sval = (sval & ~0xe0) | (fak << 5); 361153790Sobrien else { 361253790Sobrien uval = uval & ~(XCLKH_ST|XCLKH_DT|XCLKS_ST|XCLKS_DT); 361353790Sobrien if (fak >= 1) uval |= (XCLKH_ST|XCLKH_DT); 361453790Sobrien if (fak >= 2) uval |= (XCLKS_ST|XCLKS_DT); 361553790Sobrien } 361653790Sobrien } 361753790Sobrien 361853790Sobrien /* 361953790Sobrien * Set the bus width. 362053790Sobrien */ 362153790Sobrien wval = wval & ~EWS; 362253790Sobrien if (wide != 0) 362353790Sobrien wval |= EWS; 362453790Sobrien 362553790Sobrien /* 362653790Sobrien * Set misc. ultra enable bits. 362753790Sobrien */ 362853790Sobrien if (np->features & FE_C10) { 362961051Sgroudier uval = uval & ~(U3EN|AIPCKEN); 363053790Sobrien if (dt) { 363153790Sobrien assert(np->features & FE_U3EN); 363253790Sobrien uval |= U3EN; 363354690Sobrien } 363453790Sobrien } 363553790Sobrien else { 363653790Sobrien wval = wval & ~ULTRA; 363753790Sobrien if (per <= 12) wval |= ULTRA; 363853790Sobrien } 363953790Sobrien 364053790Sobrien /* 364153790Sobrien * Stop there if sync parameters are unchanged. 364253790Sobrien */ 3643178466Smarius if (tp->head.sval == sval && 364459743Sgroudier tp->head.wval == wval && 364559743Sgroudier tp->head.uval == uval) 364659743Sgroudier return; 364759743Sgroudier tp->head.sval = sval; 364859743Sgroudier tp->head.wval = wval; 364959743Sgroudier tp->head.uval = uval; 365053790Sobrien 365153790Sobrien /* 365253790Sobrien * Disable extended Sreq/Sack filtering if per < 50. 365353790Sobrien * Not supported on the C1010. 365453790Sobrien */ 365553790Sobrien if (per < 50 && !(np->features & FE_C10)) 365653790Sobrien OUTOFFB (nc_stest2, EXT); 365753790Sobrien 365853790Sobrien /* 365953790Sobrien * set actual value and sync_status 366053790Sobrien */ 366159743Sgroudier OUTB (nc_sxfer, tp->head.sval); 366259743Sgroudier OUTB (nc_scntl3, tp->head.wval); 366353790Sobrien 366453790Sobrien if (np->features & FE_C10) { 366559743Sgroudier OUTB (nc_scntl4, tp->head.uval); 366653790Sobrien } 366753790Sobrien 366853790Sobrien /* 366955300Sgroudier * patch ALL busy ccbs of this target. 367053790Sobrien */ 367155300Sgroudier FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 367255300Sgroudier cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 367353790Sobrien if (cp->target != target) 367453790Sobrien continue; 367559743Sgroudier cp->phys.select.sel_scntl3 = tp->head.wval; 367659743Sgroudier cp->phys.select.sel_sxfer = tp->head.sval; 367753790Sobrien if (np->features & FE_C10) { 367859743Sgroudier cp->phys.select.sel_scntl4 = tp->head.uval; 367953790Sobrien } 368053790Sobrien } 368153790Sobrien} 368253790Sobrien 368353790Sobrien/* 368453790Sobrien * log message for real hard errors 368553790Sobrien * 368653790Sobrien * sym0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc). 368753790Sobrien * reg: r0 r1 r2 r3 r4 r5 r6 ..... rf. 368853790Sobrien * 368953790Sobrien * exception register: 369053790Sobrien * ds: dstat 369153790Sobrien * si: sist 369253790Sobrien * 369353790Sobrien * SCSI bus lines: 369453790Sobrien * so: control lines as driven by chip. 369553790Sobrien * si: control lines as seen by chip. 369653790Sobrien * sd: scsi data lines as seen by chip. 369753790Sobrien * 369853790Sobrien * wide/fastmode: 369953790Sobrien * sxfer: (see the manual) 370053790Sobrien * scntl3: (see the manual) 370153790Sobrien * 370253790Sobrien * current script command: 370380203Skris * dsp: script address (relative to start of script). 370453790Sobrien * dbc: first word of script command. 370553790Sobrien * 370653790Sobrien * First 24 register of the chip: 370753790Sobrien * r0..rf 370853790Sobrien */ 370953790Sobrienstatic void sym_log_hard_error(hcb_p np, u_short sist, u_char dstat) 371053790Sobrien{ 371153790Sobrien u32 dsp; 371253790Sobrien int script_ofs; 371353790Sobrien int script_size; 371453790Sobrien char *script_name; 371553790Sobrien u_char *script_base; 371653790Sobrien int i; 371753790Sobrien 371853790Sobrien dsp = INL (nc_dsp); 371953790Sobrien 372059292Sgroudier if (dsp > np->scripta_ba && 372159743Sgroudier dsp <= np->scripta_ba + np->scripta_sz) { 372259292Sgroudier script_ofs = dsp - np->scripta_ba; 372359743Sgroudier script_size = np->scripta_sz; 372459292Sgroudier script_base = (u_char *) np->scripta0; 372559292Sgroudier script_name = "scripta"; 372653790Sobrien } 3727178466Smarius else if (np->scriptb_ba < dsp && 372859743Sgroudier dsp <= np->scriptb_ba + np->scriptb_sz) { 372959292Sgroudier script_ofs = dsp - np->scriptb_ba; 373059743Sgroudier script_size = np->scriptb_sz; 373159292Sgroudier script_base = (u_char *) np->scriptb0; 373259292Sgroudier script_name = "scriptb"; 373353790Sobrien } else { 373453790Sobrien script_ofs = dsp; 373553790Sobrien script_size = 0; 373653790Sobrien script_base = 0; 373753790Sobrien script_name = "mem"; 373853790Sobrien } 373953790Sobrien 374053790Sobrien printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n", 374153790Sobrien sym_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist, 374253790Sobrien (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), 374353790Sobrien (unsigned)INB (nc_sbdl), (unsigned)INB (nc_sxfer), 374453790Sobrien (unsigned)INB (nc_scntl3), script_name, script_ofs, 374553790Sobrien (unsigned)INL (nc_dbc)); 374653790Sobrien 374753790Sobrien if (((script_ofs & 3) == 0) && 374853790Sobrien (unsigned)script_ofs < script_size) { 374953790Sobrien printf ("%s: script cmd = %08x\n", sym_name(np), 375053790Sobrien scr_to_cpu((int) *(u32 *)(script_base + script_ofs))); 375153790Sobrien } 375253790Sobrien 375353790Sobrien printf ("%s: regdump:", sym_name(np)); 375453790Sobrien for (i=0; i<24;i++) 375553790Sobrien printf (" %02x", (unsigned)INB_OFF(i)); 375653790Sobrien printf (".\n"); 375753790Sobrien 375853790Sobrien /* 375953790Sobrien * PCI BUS error, read the PCI ststus register. 376053790Sobrien */ 376153790Sobrien if (dstat & (MDPE|BF)) { 376253790Sobrien u_short pci_sts; 376353790Sobrien pci_sts = pci_read_config(np->device, PCIR_STATUS, 2); 376453790Sobrien if (pci_sts & 0xf900) { 376553790Sobrien pci_write_config(np->device, PCIR_STATUS, pci_sts, 2); 376653790Sobrien printf("%s: PCI STATUS = 0x%04x\n", 376753790Sobrien sym_name(np), pci_sts & 0xf900); 376853790Sobrien } 376953790Sobrien } 377053790Sobrien} 377153790Sobrien 377253790Sobrien/* 377353790Sobrien * chip interrupt handler 377453790Sobrien * 3775178466Smarius * In normal situations, interrupt conditions occur one at 3776178466Smarius * a time. But when something bad happens on the SCSI BUS, 3777178466Smarius * the chip may raise several interrupt flags before 3778178466Smarius * stopping and interrupting the CPU. The additionnal 3779178466Smarius * interrupt flags are stacked in some extra registers 3780178466Smarius * after the SIP and/or DIP flag has been raised in the 3781178466Smarius * ISTAT. After the CPU has read the interrupt condition 3782178466Smarius * flag from SIST or DSTAT, the chip unstacks the other 3783178466Smarius * interrupt flags and sets the corresponding bits in 3784178466Smarius * SIST or DSTAT. Since the chip starts stacking once the 3785178466Smarius * SIP or DIP flag is set, there is a small window of time 378653790Sobrien * where the stacking does not occur. 378753790Sobrien * 3788178466Smarius * Typically, multiple interrupt conditions may happen in 378953790Sobrien * the following situations: 379053790Sobrien * 379153790Sobrien * - SCSI parity error + Phase mismatch (PAR|MA) 3792178466Smarius * When a parity error is detected in input phase 3793178466Smarius * and the device switches to msg-in phase inside a 379453790Sobrien * block MOV. 379553790Sobrien * - SCSI parity error + Unexpected disconnect (PAR|UDC) 3796178466Smarius * When a stupid device does not want to handle the 379753790Sobrien * recovery of an SCSI parity error. 379853790Sobrien * - Some combinations of STO, PAR, UDC, ... 3799178466Smarius * When using non compliant SCSI stuff, when user is 3800178466Smarius * doing non compliant hot tampering on the BUS, when 380153790Sobrien * something really bad happens to a device, etc ... 380253790Sobrien * 3803178466Smarius * The heuristic suggested by SYMBIOS to handle 3804178466Smarius * multiple interrupts is to try unstacking all 3805178466Smarius * interrupts conditions and to handle them on some 380653790Sobrien * priority based on error severity. 3807178466Smarius * This will work when the unstacking has been 3808178466Smarius * successful, but we cannot be 100 % sure of that, 3809178466Smarius * since the CPU may have been faster to unstack than 3810178466Smarius * the chip is able to stack. Hmmm ... But it seems that 381153790Sobrien * such a situation is very unlikely to happen. 381253790Sobrien * 3813178466Smarius * If this happen, for example STO caught by the CPU 3814178466Smarius * then UDC happenning before the CPU have restarted 3815178466Smarius * the SCRIPTS, the driver may wrongly complete the 3816178466Smarius * same command on UDC, since the SCRIPTS didn't restart 381753790Sobrien * and the DSA still points to the same command. 3818178466Smarius * We avoid this situation by setting the DSA to an 3819178466Smarius * invalid value when the CCB is completed and before 382053790Sobrien * restarting the SCRIPTS. 382153790Sobrien * 3822178466Smarius * Another issue is that we need some section of our 3823178466Smarius * recovery procedures to be somehow uninterruptible but 3824178466Smarius * the SCRIPTS processor does not provides such a 3825178466Smarius * feature. For this reason, we handle recovery preferently 3826178466Smarius * from the C code and check against some SCRIPTS critical 382753790Sobrien * sections from the C code. 382853790Sobrien * 3829178466Smarius * Hopefully, the interrupt handling of the driver is now 3830178466Smarius * able to resist to weird BUS error conditions, but donnot 383153790Sobrien * ask me for any guarantee that it will never fail. :-) 383253790Sobrien * Use at your own decision and risk. 383353790Sobrien */ 383453790Sobrienstatic void sym_intr1 (hcb_p np) 383553790Sobrien{ 383653790Sobrien u_char istat, istatc; 383753790Sobrien u_char dstat; 383853790Sobrien u_short sist; 383953790Sobrien 3840178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 3841178468Smarius 384253790Sobrien /* 384353790Sobrien * interrupt on the fly ? 384462422Sgroudier * 3845178466Smarius * A `dummy read' is needed to ensure that the 3846178466Smarius * clear of the INTF flag reaches the device 384762422Sgroudier * before the scanning of the DONE queue. 384853790Sobrien */ 384953790Sobrien istat = INB (nc_istat); 385053790Sobrien if (istat & INTF) { 385153790Sobrien OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem); 385253790Sobrien istat = INB (nc_istat); /* DUMMY READ */ 385353790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("F "); 385453790Sobrien (void)sym_wakeup_done (np); 385553790Sobrien }; 385653790Sobrien 385753790Sobrien if (!(istat & (SIP|DIP))) 385853790Sobrien return; 385953790Sobrien 386053790Sobrien#if 0 /* We should never get this one */ 386153790Sobrien if (istat & CABRT) 386253790Sobrien OUTB (nc_istat, CABRT); 386353790Sobrien#endif 386453790Sobrien 386553790Sobrien /* 386653790Sobrien * PAR and MA interrupts may occur at the same time, 3867178466Smarius * and we need to know of both in order to handle 3868178466Smarius * this situation properly. We try to unstack SCSI 3869178466Smarius * interrupts for that reason. BTW, I dislike a LOT 387053790Sobrien * such a loop inside the interrupt routine. 3871178466Smarius * Even if DMA interrupt stacking is very unlikely to 3872178466Smarius * happen, we also try unstacking these ones, since 387353790Sobrien * this has no performance impact. 387453790Sobrien */ 387553790Sobrien sist = 0; 387653790Sobrien dstat = 0; 387753790Sobrien istatc = istat; 387853790Sobrien do { 387953790Sobrien if (istatc & SIP) 388053790Sobrien sist |= INW (nc_sist); 388153790Sobrien if (istatc & DIP) 388253790Sobrien dstat |= INB (nc_dstat); 388353790Sobrien istatc = INB (nc_istat); 388453790Sobrien istat |= istatc; 388553790Sobrien } while (istatc & (SIP|DIP)); 388653790Sobrien 388753790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) 388853790Sobrien printf ("<%d|%x:%x|%x:%x>", 388953790Sobrien (int)INB(nc_scr0), 389053790Sobrien dstat,sist, 389153790Sobrien (unsigned)INL(nc_dsp), 389253790Sobrien (unsigned)INL(nc_dbc)); 389353790Sobrien /* 389462422Sgroudier * On paper, a memory barrier may be needed here. 389562422Sgroudier * And since we are paranoid ... :) 389662422Sgroudier */ 389762422Sgroudier MEMORY_BARRIER(); 389862422Sgroudier 389962422Sgroudier /* 390053790Sobrien * First, interrupts we want to service cleanly. 390153790Sobrien * 3902178466Smarius * Phase mismatch (MA) is the most frequent interrupt 3903178466Smarius * for chip earlier than the 896 and so we have to service 390453790Sobrien * it as quickly as possible. 3905178466Smarius * A SCSI parity error (PAR) may be combined with a phase 390653790Sobrien * mismatch condition (MA). 3907178466Smarius * Programmed interrupts (SIR) are used to call the C code 390853790Sobrien * from SCRIPTS. 3909178466Smarius * The single step interrupt (SSI) is not used in this 391053790Sobrien * driver. 391153790Sobrien */ 391253790Sobrien if (!(sist & (STO|GEN|HTH|SGE|UDC|SBMC|RST)) && 391353790Sobrien !(dstat & (MDPE|BF|ABRT|IID))) { 391453790Sobrien if (sist & PAR) sym_int_par (np, sist); 391553790Sobrien else if (sist & MA) sym_int_ma (np); 391653790Sobrien else if (dstat & SIR) sym_int_sir (np); 391761429Sgroudier else if (dstat & SSI) OUTONB_STD (); 391853790Sobrien else goto unknown_int; 391953790Sobrien return; 392053790Sobrien }; 392153790Sobrien 392253790Sobrien /* 3923178466Smarius * Now, interrupts that donnot happen in normal 392453790Sobrien * situations and that we may need to recover from. 392553790Sobrien * 392653790Sobrien * On SCSI RESET (RST), we reset everything. 3927178466Smarius * On SCSI BUS MODE CHANGE (SBMC), we complete all 3928178466Smarius * active CCBs with RESET status, prepare all devices 392953790Sobrien * for negotiating again and restart the SCRIPTS. 3930178466Smarius * On STO and UDC, we complete the CCB with the corres- 393153790Sobrien * ponding status and restart the SCRIPTS. 393253790Sobrien */ 393353790Sobrien if (sist & RST) { 393455300Sgroudier xpt_print_path(np->path); 393555300Sgroudier printf("SCSI BUS reset detected.\n"); 393655300Sgroudier sym_init (np, 1); 393753790Sobrien return; 393853790Sobrien }; 393953790Sobrien 394053790Sobrien OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ 394153790Sobrien OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ 394253790Sobrien 394353790Sobrien if (!(sist & (GEN|HTH|SGE)) && 394453790Sobrien !(dstat & (MDPE|BF|ABRT|IID))) { 394553790Sobrien if (sist & SBMC) sym_int_sbmc (np); 394653790Sobrien else if (sist & STO) sym_int_sto (np); 394753790Sobrien else if (sist & UDC) sym_int_udc (np); 394853790Sobrien else goto unknown_int; 394953790Sobrien return; 395053790Sobrien }; 395153790Sobrien 395253790Sobrien /* 395353790Sobrien * Now, interrupts we are not able to recover cleanly. 395453790Sobrien * 395553790Sobrien * Log message for hard errors. 395653790Sobrien * Reset everything. 395753790Sobrien */ 395853790Sobrien 395953790Sobrien sym_log_hard_error(np, sist, dstat); 396053790Sobrien 396153790Sobrien if ((sist & (GEN|HTH|SGE)) || 396253790Sobrien (dstat & (MDPE|BF|ABRT|IID))) { 396353790Sobrien sym_start_reset(np); 396453790Sobrien return; 396553790Sobrien }; 396653790Sobrien 396753790Sobrienunknown_int: 396853790Sobrien /* 396953790Sobrien * We just miss the cause of the interrupt. :( 397053790Sobrien * Print a message. The timeout will do the real work. 397153790Sobrien */ 397253790Sobrien printf( "%s: unknown interrupt(s) ignored, " 397353790Sobrien "ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n", 397453790Sobrien sym_name(np), istat, dstat, sist); 397553790Sobrien} 397653790Sobrien 397753790Sobrienstatic void sym_intr(void *arg) 397853790Sobrien{ 3979178468Smarius hcb_p np = arg; 3980178468Smarius 3981178468Smarius SYM_LOCK(); 3982179029Smarius 398353790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("["); 398453790Sobrien sym_intr1((hcb_p) arg); 398553790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("]"); 3986179029Smarius 3987178468Smarius SYM_UNLOCK(); 398853790Sobrien} 398953790Sobrien 399053790Sobrienstatic void sym_poll(struct cam_sim *sim) 399153790Sobrien{ 3992178468Smarius sym_intr1(cam_sim_softc(sim)); 399353790Sobrien} 399453790Sobrien 399553790Sobrien/* 399653790Sobrien * generic recovery from scsi interrupt 399753790Sobrien * 399853790Sobrien * The doc says that when the chip gets an SCSI interrupt, 3999178466Smarius * it tries to stop in an orderly fashion, by completing 4000178466Smarius * an instruction fetch that had started or by flushing 400153790Sobrien * the DMA fifo for a write to memory that was executing. 4002178466Smarius * Such a fashion is not enough to know if the instruction 4003178466Smarius * that was just before the current DSP value has been 400453790Sobrien * executed or not. 400553790Sobrien * 4006178466Smarius * There are some small SCRIPTS sections that deal with 4007178466Smarius * the start queue and the done queue that may break any 4008178466Smarius * assomption from the C code if we are interrupted 4009178466Smarius * inside, so we reset if this happens. Btw, since these 4010178466Smarius * SCRIPTS sections are executed while the SCRIPTS hasn't 401153790Sobrien * started SCSI operations, it is very unlikely to happen. 401253790Sobrien * 4013178466Smarius * All the driver data structures are supposed to be 4014178466Smarius * allocated from the same 4 GB memory window, so there 4015178466Smarius * is a 1 to 1 relationship between DSA and driver data 4016178466Smarius * structures. Since we are careful :) to invalidate the 4017178466Smarius * DSA when we complete a command or when the SCRIPTS 4018178466Smarius * pushes a DSA into a queue, we can trust it when it 401953790Sobrien * points to a CCB. 402053790Sobrien */ 402153790Sobrienstatic void sym_recover_scsi_int (hcb_p np, u_char hsts) 402253790Sobrien{ 402353790Sobrien u32 dsp = INL (nc_dsp); 402453790Sobrien u32 dsa = INL (nc_dsa); 402553790Sobrien ccb_p cp = sym_ccb_from_dsa(np, dsa); 402653790Sobrien 402753790Sobrien /* 4028178466Smarius * If we haven't been interrupted inside the SCRIPTS 4029178466Smarius * critical pathes, we can safely restart the SCRIPTS 403053790Sobrien * and trust the DSA value if it matches a CCB. 403153790Sobrien */ 403259292Sgroudier if ((!(dsp > SCRIPTA_BA (np, getjob_begin) && 403359292Sgroudier dsp < SCRIPTA_BA (np, getjob_end) + 1)) && 403459292Sgroudier (!(dsp > SCRIPTA_BA (np, ungetjob) && 403559292Sgroudier dsp < SCRIPTA_BA (np, reselect) + 1)) && 403659292Sgroudier (!(dsp > SCRIPTB_BA (np, sel_for_abort) && 403759292Sgroudier dsp < SCRIPTB_BA (np, sel_for_abort_1) + 1)) && 403859292Sgroudier (!(dsp > SCRIPTA_BA (np, done) && 403959292Sgroudier dsp < SCRIPTA_BA (np, done_end) + 1))) { 404053790Sobrien OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ 404153790Sobrien OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ 404253790Sobrien /* 4043178466Smarius * If we have a CCB, let the SCRIPTS call us back for 4044178466Smarius * the handling of the error with SCRATCHA filled with 4045178466Smarius * STARTPOS. This way, we will be able to freeze the 404653790Sobrien * device queue and requeue awaiting IOs. 404753790Sobrien */ 404853790Sobrien if (cp) { 404953790Sobrien cp->host_status = hsts; 405061429Sgroudier OUTL_DSP (SCRIPTA_BA (np, complete_error)); 405153790Sobrien } 405253790Sobrien /* 405353790Sobrien * Otherwise just restart the SCRIPTS. 405453790Sobrien */ 405553790Sobrien else { 405653790Sobrien OUTL (nc_dsa, 0xffffff); 405761429Sgroudier OUTL_DSP (SCRIPTA_BA (np, start)); 405853790Sobrien } 405953790Sobrien } 406053790Sobrien else 406153790Sobrien goto reset_all; 406253790Sobrien 406353790Sobrien return; 406453790Sobrien 406553790Sobrienreset_all: 406653790Sobrien sym_start_reset(np); 406753790Sobrien} 406853790Sobrien 406953790Sobrien/* 407053790Sobrien * chip exception handler for selection timeout 407153790Sobrien */ 4072105215Sphkstatic void sym_int_sto (hcb_p np) 407353790Sobrien{ 407453790Sobrien u32 dsp = INL (nc_dsp); 407553790Sobrien 407653790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("T"); 407753790Sobrien 407859292Sgroudier if (dsp == SCRIPTA_BA (np, wf_sel_done) + 8) 407953790Sobrien sym_recover_scsi_int(np, HS_SEL_TIMEOUT); 408053790Sobrien else 408153790Sobrien sym_start_reset(np); 408253790Sobrien} 408353790Sobrien 408453790Sobrien/* 408553790Sobrien * chip exception handler for unexpected disconnect 408653790Sobrien */ 4087105215Sphkstatic void sym_int_udc (hcb_p np) 408853790Sobrien{ 408953790Sobrien printf ("%s: unexpected disconnect\n", sym_name(np)); 409053790Sobrien sym_recover_scsi_int(np, HS_UNEXPECTED); 409153790Sobrien} 409253790Sobrien 409353790Sobrien/* 409453790Sobrien * chip exception handler for SCSI bus mode change 409553790Sobrien * 4096178466Smarius * spi2-r12 11.2.3 says a transceiver mode change must 4097178466Smarius * generate a reset event and a device that detects a reset 409853790Sobrien * event shall initiate a hard reset. It says also that a 4099178466Smarius * device that detects a mode change shall set data transfer 410053790Sobrien * mode to eight bit asynchronous, etc... 410153790Sobrien * So, just reinitializing all except chip should be enough. 410253790Sobrien */ 410353790Sobrienstatic void sym_int_sbmc (hcb_p np) 410453790Sobrien{ 410553790Sobrien u_char scsi_mode = INB (nc_stest4) & SMODE; 410653790Sobrien 410755300Sgroudier /* 410855300Sgroudier * Notify user. 410955300Sgroudier */ 411055300Sgroudier xpt_print_path(np->path); 411155300Sgroudier printf("SCSI BUS mode change from %s to %s.\n", 411255300Sgroudier sym_scsi_bus_mode(np->scsi_mode), sym_scsi_bus_mode(scsi_mode)); 411353790Sobrien 411453790Sobrien /* 4115178466Smarius * Should suspend command processing for a few seconds and 411653790Sobrien * reinitialize all except the chip. 411753790Sobrien */ 411855300Sgroudier sym_init (np, 2); 411953790Sobrien} 412053790Sobrien 412153790Sobrien/* 412253790Sobrien * chip exception handler for SCSI parity error. 412353790Sobrien * 4124178466Smarius * When the chip detects a SCSI parity error and is 4125178466Smarius * currently executing a (CH)MOV instruction, it does 4126178466Smarius * not interrupt immediately, but tries to finish the 4127178466Smarius * transfer of the current scatter entry before 412853790Sobrien * interrupting. The following situations may occur: 412953790Sobrien * 4130178466Smarius * - The complete scatter entry has been transferred 413153790Sobrien * without the device having changed phase. 4132178466Smarius * The chip will then interrupt with the DSP pointing 413353790Sobrien * to the instruction that follows the MOV. 413453790Sobrien * 4135178466Smarius * - A phase mismatch occurs before the MOV finished 413653790Sobrien * and phase errors are to be handled by the C code. 4137178466Smarius * The chip will then interrupt with both PAR and MA 413853790Sobrien * conditions set. 413953790Sobrien * 4140178466Smarius * - A phase mismatch occurs before the MOV finished and 414153790Sobrien * phase errors are to be handled by SCRIPTS. 4142178466Smarius * The chip will load the DSP with the phase mismatch 414353790Sobrien * JUMP address and interrupt the host processor. 414453790Sobrien */ 414553790Sobrienstatic void sym_int_par (hcb_p np, u_short sist) 414653790Sobrien{ 414753790Sobrien u_char hsts = INB (HS_PRT); 414853790Sobrien u32 dsp = INL (nc_dsp); 414953790Sobrien u32 dbc = INL (nc_dbc); 415053790Sobrien u32 dsa = INL (nc_dsa); 415153790Sobrien u_char sbcl = INB (nc_sbcl); 415253790Sobrien u_char cmd = dbc >> 24; 415353790Sobrien int phase = cmd & 7; 415453790Sobrien ccb_p cp = sym_ccb_from_dsa(np, dsa); 415553790Sobrien 415653790Sobrien printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n", 415753790Sobrien sym_name(np), hsts, dbc, sbcl); 415853790Sobrien 415953790Sobrien /* 416053790Sobrien * Check that the chip is connected to the SCSI BUS. 416153790Sobrien */ 416253790Sobrien if (!(INB (nc_scntl1) & ISCON)) { 416353790Sobrien sym_recover_scsi_int(np, HS_UNEXPECTED); 416453790Sobrien return; 416553790Sobrien } 416653790Sobrien 416753790Sobrien /* 416853790Sobrien * If the nexus is not clearly identified, reset the bus. 416953790Sobrien * We will try to do better later. 417053790Sobrien */ 417153790Sobrien if (!cp) 417253790Sobrien goto reset_all; 417353790Sobrien 417453790Sobrien /* 4175178466Smarius * Check instruction was a MOV, direction was INPUT and 417653790Sobrien * ATN is asserted. 417753790Sobrien */ 417853790Sobrien if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8)) 417953790Sobrien goto reset_all; 418053790Sobrien 418153790Sobrien /* 418253790Sobrien * Keep track of the parity error. 418353790Sobrien */ 418453790Sobrien OUTONB (HF_PRT, HF_EXT_ERR); 418553790Sobrien cp->xerr_status |= XE_PARITY_ERR; 418653790Sobrien 418753790Sobrien /* 418853790Sobrien * Prepare the message to send to the device. 418953790Sobrien */ 419053790Sobrien np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR; 419153790Sobrien 419253790Sobrien /* 419353790Sobrien * If the old phase was DATA IN phase, we have to deal with 419453790Sobrien * the 3 situations described above. 4195178466Smarius * For other input phases (MSG IN and STATUS), the device 4196178466Smarius * must resend the whole thing that failed parity checking 419753790Sobrien * or signal error. So, jumping to dispatcher should be OK. 419853790Sobrien */ 419962134Sgroudier if (phase == 1 || phase == 5) { 420053790Sobrien /* Phase mismatch handled by SCRIPTS */ 420159292Sgroudier if (dsp == SCRIPTB_BA (np, pm_handle)) 420261429Sgroudier OUTL_DSP (dsp); 420353790Sobrien /* Phase mismatch handled by the C code */ 420453790Sobrien else if (sist & MA) 420553790Sobrien sym_int_ma (np); 420653790Sobrien /* No phase mismatch occurred */ 420753790Sobrien else { 420853790Sobrien OUTL (nc_temp, dsp); 420961429Sgroudier OUTL_DSP (SCRIPTA_BA (np, dispatch)); 421053790Sobrien } 421153790Sobrien } 4212178466Smarius else 421361429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 421453790Sobrien return; 421553790Sobrien 421653790Sobrienreset_all: 421753790Sobrien sym_start_reset(np); 421853790Sobrien} 421953790Sobrien 422053790Sobrien/* 422153790Sobrien * chip exception handler for phase errors. 422253790Sobrien * 422353790Sobrien * We have to construct a new transfer descriptor, 422453790Sobrien * to transfer the rest of the current block. 422553790Sobrien */ 422653790Sobrienstatic void sym_int_ma (hcb_p np) 422753790Sobrien{ 422853790Sobrien u32 dbc; 422953790Sobrien u32 rest; 423053790Sobrien u32 dsp; 423153790Sobrien u32 dsa; 423253790Sobrien u32 nxtdsp; 423353790Sobrien u32 *vdsp; 423453790Sobrien u32 oadr, olen; 423553790Sobrien u32 *tblp; 423653790Sobrien u32 newcmd; 423753790Sobrien u_int delta; 423853790Sobrien u_char cmd; 423953790Sobrien u_char hflags, hflags0; 424053790Sobrien struct sym_pmc *pm; 424153790Sobrien ccb_p cp; 424253790Sobrien 424353790Sobrien dsp = INL (nc_dsp); 424453790Sobrien dbc = INL (nc_dbc); 424553790Sobrien dsa = INL (nc_dsa); 424653790Sobrien 424753790Sobrien cmd = dbc >> 24; 424853790Sobrien rest = dbc & 0xffffff; 424953790Sobrien delta = 0; 425053790Sobrien 425153790Sobrien /* 425253790Sobrien * locate matching cp if any. 425353790Sobrien */ 425453790Sobrien cp = sym_ccb_from_dsa(np, dsa); 425553790Sobrien 425653790Sobrien /* 4257178466Smarius * Donnot take into account dma fifo and various buffers in 4258178466Smarius * INPUT phase since the chip flushes everything before 425953790Sobrien * raising the MA interrupt for interrupted INPUT phases. 426053790Sobrien * For DATA IN phase, we will check for the SWIDE later. 426153790Sobrien */ 426262134Sgroudier if ((cmd & 7) != 1 && (cmd & 7) != 5) { 426353790Sobrien u_char ss0, ss2; 426453790Sobrien 426553790Sobrien if (np->features & FE_DFBC) 426653790Sobrien delta = INW (nc_dfbc); 426753790Sobrien else { 426853790Sobrien u32 dfifo; 426953790Sobrien 427053790Sobrien /* 427153790Sobrien * Read DFIFO, CTEST[4-6] using 1 PCI bus ownership. 427253790Sobrien */ 427353790Sobrien dfifo = INL(nc_dfifo); 427453790Sobrien 427553790Sobrien /* 427653790Sobrien * Calculate remaining bytes in DMA fifo. 427753790Sobrien * (CTEST5 = dfifo >> 16) 427853790Sobrien */ 427953790Sobrien if (dfifo & (DFS << 16)) 428053790Sobrien delta = ((((dfifo >> 8) & 0x300) | 428153790Sobrien (dfifo & 0xff)) - rest) & 0x3ff; 428253790Sobrien else 428353790Sobrien delta = ((dfifo & 0xff) - rest) & 0x7f; 428453790Sobrien } 428553790Sobrien 428653790Sobrien /* 4287220944Smarius * The data in the dma fifo has not been transferred to 428853790Sobrien * the target -> add the amount to the rest 428953790Sobrien * and clear the data. 429053790Sobrien * Check the sstat2 register in case of wide transfer. 429153790Sobrien */ 429253790Sobrien rest += delta; 429353790Sobrien ss0 = INB (nc_sstat0); 429453790Sobrien if (ss0 & OLF) rest++; 429553790Sobrien if (!(np->features & FE_C10)) 429653790Sobrien if (ss0 & ORF) rest++; 429753790Sobrien if (cp && (cp->phys.select.sel_scntl3 & EWS)) { 429853790Sobrien ss2 = INB (nc_sstat2); 429953790Sobrien if (ss2 & OLF1) rest++; 430053790Sobrien if (!(np->features & FE_C10)) 430153790Sobrien if (ss2 & ORF1) rest++; 430253790Sobrien }; 430353790Sobrien 430453790Sobrien /* 430553790Sobrien * Clear fifos. 430653790Sobrien */ 430753790Sobrien OUTB (nc_ctest3, np->rv_ctest3 | CLF); /* dma fifo */ 430853790Sobrien OUTB (nc_stest3, TE|CSF); /* scsi fifo */ 430953790Sobrien } 431053790Sobrien 431153790Sobrien /* 431253790Sobrien * log the information 431353790Sobrien */ 431453790Sobrien if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) 431553790Sobrien printf ("P%x%x RL=%d D=%d ", cmd&7, INB(nc_sbcl)&7, 431653790Sobrien (unsigned) rest, (unsigned) delta); 431753790Sobrien 431853790Sobrien /* 431953790Sobrien * try to find the interrupted script command, 432053790Sobrien * and the address at which to continue. 432153790Sobrien */ 432253790Sobrien vdsp = 0; 432353790Sobrien nxtdsp = 0; 432459292Sgroudier if (dsp > np->scripta_ba && 432559743Sgroudier dsp <= np->scripta_ba + np->scripta_sz) { 432659292Sgroudier vdsp = (u32 *)((char*)np->scripta0 + (dsp-np->scripta_ba-8)); 432753790Sobrien nxtdsp = dsp; 432853790Sobrien } 432959292Sgroudier else if (dsp > np->scriptb_ba && 433059743Sgroudier dsp <= np->scriptb_ba + np->scriptb_sz) { 433159292Sgroudier vdsp = (u32 *)((char*)np->scriptb0 + (dsp-np->scriptb_ba-8)); 433253790Sobrien nxtdsp = dsp; 433353790Sobrien } 433453790Sobrien 433553790Sobrien /* 433653790Sobrien * log the information 433753790Sobrien */ 433853790Sobrien if (DEBUG_FLAGS & DEBUG_PHASE) { 433953790Sobrien printf ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", 434053790Sobrien cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd); 434153790Sobrien }; 434253790Sobrien 434353790Sobrien if (!vdsp) { 4344178466Smarius printf ("%s: interrupted SCRIPT address not found.\n", 434553790Sobrien sym_name (np)); 434653790Sobrien goto reset_all; 434753790Sobrien } 434853790Sobrien 434953790Sobrien if (!cp) { 4350178466Smarius printf ("%s: SCSI phase error fixup: CCB already dequeued.\n", 435153790Sobrien sym_name (np)); 435253790Sobrien goto reset_all; 435353790Sobrien } 435453790Sobrien 435553790Sobrien /* 435653790Sobrien * get old startaddress and old length. 435753790Sobrien */ 435853790Sobrien oadr = scr_to_cpu(vdsp[1]); 435953790Sobrien 436053790Sobrien if (cmd & 0x10) { /* Table indirect */ 436153790Sobrien tblp = (u32 *) ((char*) &cp->phys + oadr); 436253790Sobrien olen = scr_to_cpu(tblp[0]); 436353790Sobrien oadr = scr_to_cpu(tblp[1]); 436453790Sobrien } else { 436553790Sobrien tblp = (u32 *) 0; 436653790Sobrien olen = scr_to_cpu(vdsp[0]) & 0xffffff; 436753790Sobrien }; 436853790Sobrien 436953790Sobrien if (DEBUG_FLAGS & DEBUG_PHASE) { 437053790Sobrien printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", 437153790Sobrien (unsigned) (scr_to_cpu(vdsp[0]) >> 24), 437253790Sobrien tblp, 437353790Sobrien (unsigned) olen, 437453790Sobrien (unsigned) oadr); 437553790Sobrien }; 437653790Sobrien 437753790Sobrien /* 437853790Sobrien * check cmd against assumed interrupted script command. 4379178466Smarius * If dt data phase, the MOVE instruction hasn't bit 4 of 438062134Sgroudier * the phase. 438153790Sobrien */ 438262134Sgroudier if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) { 438353790Sobrien PRINT_ADDR(cp); 438453790Sobrien printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", 438553790Sobrien (unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24); 438653790Sobrien 438753790Sobrien goto reset_all; 438853790Sobrien }; 438953790Sobrien 439053790Sobrien /* 439153790Sobrien * if old phase not dataphase, leave here. 439253790Sobrien */ 439362134Sgroudier if (cmd & 2) { 439453790Sobrien PRINT_ADDR(cp); 439553790Sobrien printf ("phase change %x-%x %d@%08x resid=%d.\n", 439653790Sobrien cmd&7, INB(nc_sbcl)&7, (unsigned)olen, 439753790Sobrien (unsigned)oadr, (unsigned)rest); 439853790Sobrien goto unexpected_phase; 439953790Sobrien }; 440053790Sobrien 440153790Sobrien /* 440253790Sobrien * Choose the correct PM save area. 440353790Sobrien * 4404178466Smarius * Look at the PM_SAVE SCRIPT if you want to understand 4405178466Smarius * this stuff. The equivalent code is implemented in 4406178466Smarius * SCRIPTS for the 895A, 896 and 1010 that are able to 440762422Sgroudier * handle PM from the SCRIPTS processor. 440853790Sobrien */ 440953790Sobrien hflags0 = INB (HF_PRT); 441053790Sobrien hflags = hflags0; 441153790Sobrien 441253790Sobrien if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) { 441353790Sobrien if (hflags & HF_IN_PM0) 441453790Sobrien nxtdsp = scr_to_cpu(cp->phys.pm0.ret); 441553790Sobrien else if (hflags & HF_IN_PM1) 441653790Sobrien nxtdsp = scr_to_cpu(cp->phys.pm1.ret); 441753790Sobrien 441853790Sobrien if (hflags & HF_DP_SAVED) 441953790Sobrien hflags ^= HF_ACT_PM; 442053790Sobrien } 442153790Sobrien 442253790Sobrien if (!(hflags & HF_ACT_PM)) { 442353790Sobrien pm = &cp->phys.pm0; 442459292Sgroudier newcmd = SCRIPTA_BA (np, pm0_data); 442553790Sobrien } 442653790Sobrien else { 442753790Sobrien pm = &cp->phys.pm1; 442859292Sgroudier newcmd = SCRIPTA_BA (np, pm1_data); 442953790Sobrien } 443053790Sobrien 443153790Sobrien hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED); 443253790Sobrien if (hflags != hflags0) 443353790Sobrien OUTB (HF_PRT, hflags); 443453790Sobrien 443553790Sobrien /* 443653790Sobrien * fillin the phase mismatch context 443753790Sobrien */ 443853790Sobrien pm->sg.addr = cpu_to_scr(oadr + olen - rest); 443953790Sobrien pm->sg.size = cpu_to_scr(rest); 444053790Sobrien pm->ret = cpu_to_scr(nxtdsp); 444153790Sobrien 444253790Sobrien /* 444353790Sobrien * If we have a SWIDE, 444453790Sobrien * - prepare the address to write the SWIDE from SCRIPTS, 444553790Sobrien * - compute the SCRIPTS address to restart from, 444653790Sobrien * - move current data pointer context by one byte. 444753790Sobrien */ 444859292Sgroudier nxtdsp = SCRIPTA_BA (np, dispatch); 444953790Sobrien if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) && 445053790Sobrien (INB (nc_scntl2) & WSR)) { 445157186Sgroudier u32 tmp; 445258927Sgroudier 445353790Sobrien /* 445457186Sgroudier * Set up the table indirect for the MOVE 4455178466Smarius * of the residual byte and adjust the data 445657186Sgroudier * pointer context. 445753790Sobrien */ 445857186Sgroudier tmp = scr_to_cpu(pm->sg.addr); 445957186Sgroudier cp->phys.wresid.addr = cpu_to_scr(tmp); 446057186Sgroudier pm->sg.addr = cpu_to_scr(tmp + 1); 446157186Sgroudier tmp = scr_to_cpu(pm->sg.size); 446257186Sgroudier cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1); 446357186Sgroudier pm->sg.size = cpu_to_scr(tmp - 1); 446457186Sgroudier 446553790Sobrien /* 4466178466Smarius * If only the residual byte is to be moved, 446757186Sgroudier * no PM context is needed. 446853790Sobrien */ 446957186Sgroudier if ((tmp&0xffffff) == 1) 447057186Sgroudier newcmd = pm->ret; 447157186Sgroudier 447257186Sgroudier /* 4473178466Smarius * Prepare the address of SCRIPTS that will 447457186Sgroudier * move the residual byte to memory. 447557186Sgroudier */ 447659292Sgroudier nxtdsp = SCRIPTB_BA (np, wsr_ma_helper); 447753790Sobrien } 447853790Sobrien 447953790Sobrien if (DEBUG_FLAGS & DEBUG_PHASE) { 448053790Sobrien PRINT_ADDR(cp); 448153790Sobrien printf ("PM %x %x %x / %x %x %x.\n", 448253790Sobrien hflags0, hflags, newcmd, 448353790Sobrien (unsigned)scr_to_cpu(pm->sg.addr), 448453790Sobrien (unsigned)scr_to_cpu(pm->sg.size), 448553790Sobrien (unsigned)scr_to_cpu(pm->ret)); 448653790Sobrien } 448753790Sobrien 448853790Sobrien /* 448953790Sobrien * Restart the SCRIPTS processor. 449053790Sobrien */ 449153790Sobrien OUTL (nc_temp, newcmd); 449261429Sgroudier OUTL_DSP (nxtdsp); 449353790Sobrien return; 449453790Sobrien 449553790Sobrien /* 4496178466Smarius * Unexpected phase changes that occurs when the current phase 449753790Sobrien * is not a DATA IN or DATA OUT phase are due to error conditions. 4498178466Smarius * Such event may only happen when the SCRIPTS is using a 449953790Sobrien * multibyte SCSI MOVE. 450053790Sobrien * 450153790Sobrien * Phase change Some possible cause 450253790Sobrien * 450353790Sobrien * COMMAND --> MSG IN SCSI parity error detected by target. 450453790Sobrien * COMMAND --> STATUS Bad command or refused by target. 450553790Sobrien * MSG OUT --> MSG IN Message rejected by target. 450653790Sobrien * MSG OUT --> COMMAND Bogus target that discards extended 450753790Sobrien * negotiation messages. 450853790Sobrien * 4509178466Smarius * The code below does not care of the new phase and so 451053790Sobrien * trusts the target. Why to annoy it ? 451153790Sobrien * If the interrupted phase is COMMAND phase, we restart at 451253790Sobrien * dispatcher. 4513178466Smarius * If a target does not get all the messages after selection, 4514178466Smarius * the code assumes blindly that the target discards extended 451553790Sobrien * messages and clears the negotiation status. 451653790Sobrien * If the target does not want all our response to negotiation, 4517178466Smarius * we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids 451853790Sobrien * bloat for such a should_not_happen situation). 451953790Sobrien * In all other situation, we reset the BUS. 452053790Sobrien * Are these assumptions reasonnable ? (Wait and see ...) 452153790Sobrien */ 452253790Sobrienunexpected_phase: 452353790Sobrien dsp -= 8; 452453790Sobrien nxtdsp = 0; 452553790Sobrien 452653790Sobrien switch (cmd & 7) { 452753790Sobrien case 2: /* COMMAND phase */ 452859292Sgroudier nxtdsp = SCRIPTA_BA (np, dispatch); 452953790Sobrien break; 453053790Sobrien#if 0 453153790Sobrien case 3: /* STATUS phase */ 453259292Sgroudier nxtdsp = SCRIPTA_BA (np, dispatch); 453353790Sobrien break; 453453790Sobrien#endif 453553790Sobrien case 6: /* MSG OUT phase */ 453653790Sobrien /* 4537178466Smarius * If the device may want to use untagged when we want 4538178466Smarius * tagged, we prepare an IDENTIFY without disc. granted, 453953790Sobrien * since we will not be able to handle reselect. 454053790Sobrien * Otherwise, we just don't care. 454153790Sobrien */ 454259292Sgroudier if (dsp == SCRIPTA_BA (np, send_ident)) { 454353790Sobrien if (cp->tag != NO_TAG && olen - rest <= 3) { 454453790Sobrien cp->host_status = HS_BUSY; 454553790Sobrien np->msgout[0] = M_IDENTIFY | cp->lun; 454659292Sgroudier nxtdsp = SCRIPTB_BA (np, ident_break_atn); 454753790Sobrien } 454853790Sobrien else 454959292Sgroudier nxtdsp = SCRIPTB_BA (np, ident_break); 455053790Sobrien } 455159292Sgroudier else if (dsp == SCRIPTB_BA (np, send_wdtr) || 455259292Sgroudier dsp == SCRIPTB_BA (np, send_sdtr) || 455359292Sgroudier dsp == SCRIPTB_BA (np, send_ppr)) { 455459292Sgroudier nxtdsp = SCRIPTB_BA (np, nego_bad_phase); 455553790Sobrien } 455653790Sobrien break; 455753790Sobrien#if 0 455853790Sobrien case 7: /* MSG IN phase */ 455959292Sgroudier nxtdsp = SCRIPTA_BA (np, clrack); 456053790Sobrien break; 456153790Sobrien#endif 456253790Sobrien } 456353790Sobrien 456453790Sobrien if (nxtdsp) { 456561429Sgroudier OUTL_DSP (nxtdsp); 456653790Sobrien return; 456753790Sobrien } 456853790Sobrien 456953790Sobrienreset_all: 457053790Sobrien sym_start_reset(np); 457153790Sobrien} 457253790Sobrien 457353790Sobrien/* 4574178466Smarius * Dequeue from the START queue all CCBs that match 457553790Sobrien * a given target/lun/task condition (-1 means all), 4576178466Smarius * and move them from the BUSY queue to the COMP queue 457753790Sobrien * with CAM_REQUEUE_REQ status condition. 457853790Sobrien * This function is used during error handling/recovery. 457953790Sobrien * It is called with SCRIPTS not running. 458053790Sobrien */ 458153790Sobrienstatic int 458253790Sobriensym_dequeue_from_squeue(hcb_p np, int i, int target, int lun, int task) 458353790Sobrien{ 458453790Sobrien int j; 458553790Sobrien ccb_p cp; 458653790Sobrien 458753790Sobrien /* 458853790Sobrien * Make sure the starting index is within range. 458953790Sobrien */ 459053790Sobrien assert((i >= 0) && (i < 2*MAX_QUEUE)); 459153790Sobrien 459253790Sobrien /* 4593178466Smarius * Walk until end of START queue and dequeue every job 459453790Sobrien * that matches the target/lun/task condition. 459553790Sobrien */ 459653790Sobrien j = i; 459753790Sobrien while (i != np->squeueput) { 459853790Sobrien cp = sym_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); 459953790Sobrien assert(cp); 460054690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 460153790Sobrien /* Forget hints for IARB, they may be no longer relevant */ 460253790Sobrien cp->host_flags &= ~HF_HINT_IARB; 460353790Sobrien#endif 460453790Sobrien if ((target == -1 || cp->target == target) && 460553790Sobrien (lun == -1 || cp->lun == lun) && 460653790Sobrien (task == -1 || cp->tag == task)) { 460753790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_REQUEUE_REQ); 460853790Sobrien sym_remque(&cp->link_ccbq); 460953790Sobrien sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); 461053790Sobrien } 461153790Sobrien else { 461253790Sobrien if (i != j) 461353790Sobrien np->squeue[j] = np->squeue[i]; 461453790Sobrien if ((j += 2) >= MAX_QUEUE*2) j = 0; 461553790Sobrien } 461653790Sobrien if ((i += 2) >= MAX_QUEUE*2) i = 0; 461753790Sobrien } 461853790Sobrien if (i != j) /* Copy back the idle task if needed */ 461953790Sobrien np->squeue[j] = np->squeue[i]; 462053790Sobrien np->squeueput = j; /* Update our current start queue pointer */ 462153790Sobrien 462253790Sobrien return (i - j) / 2; 462353790Sobrien} 462453790Sobrien 462553790Sobrien/* 462653790Sobrien * Complete all CCBs queued to the COMP queue. 462753790Sobrien * 462853790Sobrien * These CCBs are assumed: 4629178466Smarius * - Not to be referenced either by devices or 463053790Sobrien * SCRIPTS-related queues and datas. 4631178466Smarius * - To have to be completed with an error condition 463253790Sobrien * or requeued. 463353790Sobrien * 4634178466Smarius * The device queue freeze count is incremented 463553790Sobrien * for each CCB that does not prevent this. 4636178466Smarius * This function is called when all CCBs involved 463753790Sobrien * in error handling/recovery have been reaped. 463853790Sobrien */ 463953790Sobrienstatic void 464053790Sobriensym_flush_comp_queue(hcb_p np, int cam_status) 464153790Sobrien{ 464253790Sobrien SYM_QUEHEAD *qp; 464353790Sobrien ccb_p cp; 464453790Sobrien 4645179029Smarius while ((qp = sym_remque_head(&np->comp_ccbq)) != NULL) { 464653790Sobrien union ccb *ccb; 464753790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 464853790Sobrien sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); 464958927Sgroudier /* Leave quiet CCBs waiting for resources */ 465058927Sgroudier if (cp->host_status == HS_WAIT) 465158927Sgroudier continue; 465253790Sobrien ccb = cp->cam_ccb; 465353790Sobrien if (cam_status) 465453790Sobrien sym_set_cam_status(ccb, cam_status); 4655178468Smarius sym_freeze_cam_ccb(ccb); 4656178468Smarius sym_xpt_done(np, ccb, cp); 465753790Sobrien sym_free_ccb(np, cp); 465853790Sobrien } 465953790Sobrien} 466053790Sobrien 466153790Sobrien/* 466253790Sobrien * chip handler for bad SCSI status condition 466353790Sobrien * 4664178466Smarius * In case of bad SCSI status, we unqueue all the tasks 4665178466Smarius * currently queued to the controller but not yet started 466653790Sobrien * and then restart the SCRIPTS processor immediately. 466753790Sobrien * 466853790Sobrien * QUEUE FULL and BUSY conditions are handled the same way. 4669178466Smarius * Basically all the not yet started tasks are requeued in 467053790Sobrien * device queue and the queue is frozen until a completion. 467153790Sobrien * 4672178466Smarius * For CHECK CONDITION and COMMAND TERMINATED status, we use 4673178466Smarius * the CCB of the failed command to prepare a REQUEST SENSE 467453790Sobrien * SCSI command and queue it to the controller queue. 467553790Sobrien * 4676178466Smarius * SCRATCHA is assumed to have been loaded with STARTPOS 467753790Sobrien * before the SCRIPTS called the C code. 467853790Sobrien */ 4679251402Smariusstatic void sym_sir_bad_scsi_status(hcb_p np, ccb_p cp) 468053790Sobrien{ 468153790Sobrien tcb_p tp = &np->target[cp->target]; 468253790Sobrien u32 startp; 468353790Sobrien u_char s_status = cp->ssss_status; 468453790Sobrien u_char h_flags = cp->host_flags; 468553790Sobrien int msglen; 468653790Sobrien int nego; 468753790Sobrien int i; 468853790Sobrien 4689178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 4690178468Smarius 469153790Sobrien /* 469253790Sobrien * Compute the index of the next job to start from SCRIPTS. 469353790Sobrien */ 469458927Sgroudier i = (INL (nc_scratcha) - np->squeue_ba) / 4; 469553790Sobrien 469653790Sobrien /* 4697178466Smarius * The last CCB queued used for IARB hint may be 469853790Sobrien * no longer relevant. Forget it. 469953790Sobrien */ 470054690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 470153790Sobrien if (np->last_cp) 4702178466Smarius np->last_cp = NULL; 470353790Sobrien#endif 470453790Sobrien 470553790Sobrien /* 470653790Sobrien * Now deal with the SCSI status. 470753790Sobrien */ 470853790Sobrien switch(s_status) { 470953790Sobrien case S_BUSY: 471053790Sobrien case S_QUEUE_FULL: 471153790Sobrien if (sym_verbose >= 2) { 471253790Sobrien PRINT_ADDR(cp); 471353790Sobrien printf (s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n"); 471453790Sobrien } 471553790Sobrien default: /* S_INT, S_INT_COND_MET, S_CONFLICT */ 471653790Sobrien sym_complete_error (np, cp); 471753790Sobrien break; 471853790Sobrien case S_TERMINATED: 471953790Sobrien case S_CHECK_COND: 472053790Sobrien /* 472153790Sobrien * If we get an SCSI error when requesting sense, give up. 472253790Sobrien */ 472353790Sobrien if (h_flags & HF_SENSE) { 472453790Sobrien sym_complete_error (np, cp); 472553790Sobrien break; 472653790Sobrien } 472753790Sobrien 472853790Sobrien /* 472953790Sobrien * Dequeue all queued CCBs for that device not yet started, 473053790Sobrien * and restart the SCRIPTS processor immediately. 473153790Sobrien */ 473253790Sobrien (void) sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); 473361429Sgroudier OUTL_DSP (SCRIPTA_BA (np, start)); 473453790Sobrien 473553790Sobrien /* 473653790Sobrien * Save some info of the actual IO. 473753790Sobrien * Compute the data residual. 473853790Sobrien */ 473953790Sobrien cp->sv_scsi_status = cp->ssss_status; 474053790Sobrien cp->sv_xerr_status = cp->xerr_status; 474153790Sobrien cp->sv_resid = sym_compute_residual(np, cp); 474253790Sobrien 474353790Sobrien /* 4744178466Smarius * Prepare all needed data structures for 474553790Sobrien * requesting sense data. 474653790Sobrien */ 474753790Sobrien 474853790Sobrien /* 474953790Sobrien * identify message 475053790Sobrien */ 475153790Sobrien cp->scsi_smsg2[0] = M_IDENTIFY | cp->lun; 475253790Sobrien msglen = 1; 475353790Sobrien 475453790Sobrien /* 4755178466Smarius * If we are currently using anything different from 475653790Sobrien * async. 8 bit data transfers with that target, 4757178466Smarius * start a negotiation, since the device may want 4758178466Smarius * to report us a UNIT ATTENTION condition due to 4759178466Smarius * a cause we currently ignore, and we donnot want 476053790Sobrien * to be stuck with WIDE and/or SYNC data transfer. 476153790Sobrien * 476253790Sobrien * cp->nego_status is filled by sym_prepare_nego(). 476353790Sobrien */ 476453790Sobrien cp->nego_status = 0; 476553790Sobrien nego = 0; 476653790Sobrien if (tp->tinfo.current.options & PPR_OPT_MASK) 476753790Sobrien nego = NS_PPR; 476853790Sobrien else if (tp->tinfo.current.width != BUS_8_BIT) 476953790Sobrien nego = NS_WIDE; 477053790Sobrien else if (tp->tinfo.current.offset != 0) 477153790Sobrien nego = NS_SYNC; 477253790Sobrien if (nego) 477353790Sobrien msglen += 477453790Sobrien sym_prepare_nego (np,cp, nego, &cp->scsi_smsg2[msglen]); 477553790Sobrien /* 477653790Sobrien * Message table indirect structure. 477753790Sobrien */ 477858927Sgroudier cp->phys.smsg.addr = cpu_to_scr(CCB_BA (cp, scsi_smsg2)); 477953790Sobrien cp->phys.smsg.size = cpu_to_scr(msglen); 478053790Sobrien 478153790Sobrien /* 478253790Sobrien * sense command 478353790Sobrien */ 478458927Sgroudier cp->phys.cmd.addr = cpu_to_scr(CCB_BA (cp, sensecmd)); 478553790Sobrien cp->phys.cmd.size = cpu_to_scr(6); 478653790Sobrien 478753790Sobrien /* 478853790Sobrien * patch requested size into sense command 478953790Sobrien */ 479053790Sobrien cp->sensecmd[0] = 0x03; 479153790Sobrien cp->sensecmd[1] = cp->lun << 5; 479274755Sgroudier if (tp->tinfo.current.scsi_version > 2 || cp->lun > 7) 479374755Sgroudier cp->sensecmd[1] = 0; 479458927Sgroudier cp->sensecmd[4] = SYM_SNS_BBUF_LEN; 479558927Sgroudier cp->data_len = SYM_SNS_BBUF_LEN; 479653790Sobrien 479753790Sobrien /* 479853790Sobrien * sense data 479953790Sobrien */ 480058927Sgroudier bzero(cp->sns_bbuf, SYM_SNS_BBUF_LEN); 480158927Sgroudier cp->phys.sense.addr = cpu_to_scr(vtobus(cp->sns_bbuf)); 480258927Sgroudier cp->phys.sense.size = cpu_to_scr(SYM_SNS_BBUF_LEN); 480353790Sobrien 480453790Sobrien /* 480553790Sobrien * requeue the command. 480653790Sobrien */ 480759292Sgroudier startp = SCRIPTB_BA (np, sdata_in); 480853790Sobrien 480959743Sgroudier cp->phys.head.savep = cpu_to_scr(startp); 481059743Sgroudier cp->phys.head.goalp = cpu_to_scr(startp + 16); 481159743Sgroudier cp->phys.head.lastp = cpu_to_scr(startp); 481253790Sobrien cp->startp = cpu_to_scr(startp); 481353790Sobrien 481453790Sobrien cp->actualquirks = SYM_QUIRK_AUTOSAVE; 481553790Sobrien cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; 481653790Sobrien cp->ssss_status = S_ILLEGAL; 481758927Sgroudier cp->host_flags = (HF_SENSE|HF_DATA_IN); 481853790Sobrien cp->xerr_status = 0; 481959252Sgroudier cp->extra_bytes = 0; 482053790Sobrien 482159743Sgroudier cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, select)); 482253790Sobrien 482353790Sobrien /* 482453790Sobrien * Requeue the command. 482553790Sobrien */ 482653790Sobrien sym_put_start_queue(np, cp); 482753790Sobrien 482853790Sobrien /* 482953790Sobrien * Give back to upper layer everything we have dequeued. 483053790Sobrien */ 483153790Sobrien sym_flush_comp_queue(np, 0); 483253790Sobrien break; 483353790Sobrien } 483453790Sobrien} 483553790Sobrien 483653790Sobrien/* 4837178466Smarius * After a device has accepted some management message 4838178466Smarius * as BUS DEVICE RESET, ABORT TASK, etc ..., or when 4839178466Smarius * a device signals a UNIT ATTENTION condition, some 4840178466Smarius * tasks are thrown away by the device. We are required 4841178466Smarius * to reflect that on our tasks list since the device 484253790Sobrien * will never complete these tasks. 484353790Sobrien * 4844178466Smarius * This function move from the BUSY queue to the COMP 4845178466Smarius * queue all disconnected CCBs for a given target that 484653790Sobrien * match the following criteria: 484753790Sobrien * - lun=-1 means any logical UNIT otherwise a given one. 484853790Sobrien * - task=-1 means any task, otherwise a given one. 484953790Sobrien */ 4850178466Smariusstatic int 485153790Sobriensym_clear_tasks(hcb_p np, int cam_status, int target, int lun, int task) 485253790Sobrien{ 485353790Sobrien SYM_QUEHEAD qtmp, *qp; 485453790Sobrien int i = 0; 485553790Sobrien ccb_p cp; 485653790Sobrien 485753790Sobrien /* 485853790Sobrien * Move the entire BUSY queue to our temporary queue. 485953790Sobrien */ 486053790Sobrien sym_que_init(&qtmp); 486153790Sobrien sym_que_splice(&np->busy_ccbq, &qtmp); 486253790Sobrien sym_que_init(&np->busy_ccbq); 486353790Sobrien 486453790Sobrien /* 4865178466Smarius * Put all CCBs that matches our criteria into 4866178466Smarius * the COMP queue and put back other ones into 486753790Sobrien * the BUSY queue. 486853790Sobrien */ 4869179029Smarius while ((qp = sym_remque_head(&qtmp)) != NULL) { 487053790Sobrien union ccb *ccb; 487153790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 487253790Sobrien ccb = cp->cam_ccb; 487353790Sobrien if (cp->host_status != HS_DISCONNECT || 487453790Sobrien cp->target != target || 487553790Sobrien (lun != -1 && cp->lun != lun) || 4876178466Smarius (task != -1 && 487753790Sobrien (cp->tag != NO_TAG && cp->scsi_smsg[2] != task))) { 487853790Sobrien sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); 487953790Sobrien continue; 488053790Sobrien } 488153790Sobrien sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); 488253790Sobrien 488353790Sobrien /* Preserve the software timeout condition */ 488453790Sobrien if (sym_get_cam_status(ccb) != CAM_CMD_TIMEOUT) 488553790Sobrien sym_set_cam_status(ccb, cam_status); 488653790Sobrien ++i; 488753790Sobrien#if 0 488857186Sgroudierprintf("XXXX TASK @%p CLEARED\n", cp); 488953790Sobrien#endif 489053790Sobrien } 489153790Sobrien return i; 489253790Sobrien} 489353790Sobrien 489453790Sobrien/* 489553790Sobrien * chip handler for TASKS recovery 489653790Sobrien * 4897178466Smarius * We cannot safely abort a command, while the SCRIPTS 4898178466Smarius * processor is running, since we just would be in race 489953790Sobrien * with it. 490053790Sobrien * 4901178466Smarius * As long as we have tasks to abort, we keep the SEM 4902178466Smarius * bit set in the ISTAT. When this bit is set, the 4903178466Smarius * SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) 490453790Sobrien * each time it enters the scheduler. 490553790Sobrien * 490653790Sobrien * If we have to reset a target, clear tasks of a unit, 4907178466Smarius * or to perform the abort of a disconnected job, we 4908178466Smarius * restart the SCRIPTS for selecting the target. Once 490953790Sobrien * selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED). 4910178466Smarius * If it loses arbitration, the SCRIPTS will interrupt again 491153790Sobrien * the next time it will enter its scheduler, and so on ... 491253790Sobrien * 4913178466Smarius * On SIR_TARGET_SELECTED, we scan for the more 491453790Sobrien * appropriate thing to do: 491553790Sobrien * 4916178466Smarius * - If nothing, we just sent a M_ABORT message to the 491753790Sobrien * target to get rid of the useless SCSI bus ownership. 491853790Sobrien * According to the specs, no tasks shall be affected. 4919178466Smarius * - If the target is to be reset, we send it a M_RESET 492053790Sobrien * message. 4921178466Smarius * - If a logical UNIT is to be cleared , we send the 492253790Sobrien * IDENTIFY(lun) + M_ABORT. 4923178466Smarius * - If an untagged task is to be aborted, we send the 492453790Sobrien * IDENTIFY(lun) + M_ABORT. 4925178466Smarius * - If a tagged task is to be aborted, we send the 492653790Sobrien * IDENTIFY(lun) + task attributes + M_ABORT_TAG. 492753790Sobrien * 4928178466Smarius * Once our 'kiss of death' :) message has been accepted 4929178466Smarius * by the target, the SCRIPTS interrupts again 4930178466Smarius * (SIR_ABORT_SENT). On this interrupt, we complete 4931178466Smarius * all the CCBs that should have been aborted by the 493253790Sobrien * target according to our message. 493353790Sobrien */ 493453790Sobrienstatic void sym_sir_task_recovery(hcb_p np, int num) 493553790Sobrien{ 493653790Sobrien SYM_QUEHEAD *qp; 493753790Sobrien ccb_p cp; 493853790Sobrien tcb_p tp; 493953790Sobrien int target=-1, lun=-1, task; 494053790Sobrien int i, k; 494153790Sobrien 494253790Sobrien switch(num) { 494353790Sobrien /* 494453790Sobrien * The SCRIPTS processor stopped before starting 4945178466Smarius * the next command in order to allow us to perform 494653790Sobrien * some task recovery. 494753790Sobrien */ 494853790Sobrien case SIR_SCRIPT_STOPPED: 494953790Sobrien /* 495053790Sobrien * Do we have any target to reset or unit to clear ? 495153790Sobrien */ 495254690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 495353790Sobrien tp = &np->target[i]; 4954178466Smarius if (tp->to_reset || 495553790Sobrien (tp->lun0p && tp->lun0p->to_clear)) { 495653790Sobrien target = i; 495753790Sobrien break; 495853790Sobrien } 495953790Sobrien if (!tp->lunmp) 496053790Sobrien continue; 496154690Sobrien for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) { 496253790Sobrien if (tp->lunmp[k] && tp->lunmp[k]->to_clear) { 496353790Sobrien target = i; 496453790Sobrien break; 496553790Sobrien } 496653790Sobrien } 496753790Sobrien if (target != -1) 496853790Sobrien break; 496953790Sobrien } 497053790Sobrien 497153790Sobrien /* 4972178466Smarius * If not, walk the busy queue for any 497353790Sobrien * disconnected CCB to be aborted. 497453790Sobrien */ 497553790Sobrien if (target == -1) { 497653790Sobrien FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 497753790Sobrien cp = sym_que_entry(qp,struct sym_ccb,link_ccbq); 497853790Sobrien if (cp->host_status != HS_DISCONNECT) 497953790Sobrien continue; 498053790Sobrien if (cp->to_abort) { 498153790Sobrien target = cp->target; 498253790Sobrien break; 498353790Sobrien } 498453790Sobrien } 498553790Sobrien } 498653790Sobrien 498753790Sobrien /* 4988178466Smarius * If some target is to be selected, 498953790Sobrien * prepare and start the selection. 499053790Sobrien */ 499153790Sobrien if (target != -1) { 499253790Sobrien tp = &np->target[target]; 499353790Sobrien np->abrt_sel.sel_id = target; 499459743Sgroudier np->abrt_sel.sel_scntl3 = tp->head.wval; 499559743Sgroudier np->abrt_sel.sel_sxfer = tp->head.sval; 499658927Sgroudier OUTL(nc_dsa, np->hcb_ba); 499761429Sgroudier OUTL_DSP (SCRIPTB_BA (np, sel_for_abort)); 499853790Sobrien return; 499953790Sobrien } 500053790Sobrien 500153790Sobrien /* 500253790Sobrien * Now look for a CCB to abort that haven't started yet. 5003178466Smarius * Btw, the SCRIPTS processor is still stopped, so 500453790Sobrien * we are not in race. 500553790Sobrien */ 500653790Sobrien i = 0; 5007178466Smarius cp = NULL; 500853790Sobrien FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 500953790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 501053790Sobrien if (cp->host_status != HS_BUSY && 501153790Sobrien cp->host_status != HS_NEGOTIATE) 501253790Sobrien continue; 501353790Sobrien if (!cp->to_abort) 501453790Sobrien continue; 501554690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 501653790Sobrien /* 5017178466Smarius * If we are using IMMEDIATE ARBITRATION, we donnot 5018178466Smarius * want to cancel the last queued CCB, since the 501953790Sobrien * SCRIPTS may have anticipated the selection. 502053790Sobrien */ 502153790Sobrien if (cp == np->last_cp) { 502253790Sobrien cp->to_abort = 0; 502353790Sobrien continue; 502453790Sobrien } 502553790Sobrien#endif 502653790Sobrien i = 1; /* Means we have found some */ 502753790Sobrien break; 502853790Sobrien } 502953790Sobrien if (!i) { 503053790Sobrien /* 5031178466Smarius * We are done, so we donnot need 503253790Sobrien * to synchronize with the SCRIPTS anylonger. 503353790Sobrien * Remove the SEM flag from the ISTAT. 503453790Sobrien */ 503553790Sobrien np->istat_sem = 0; 503653790Sobrien OUTB (nc_istat, SIGP); 503753790Sobrien break; 503853790Sobrien } 503953790Sobrien /* 5040178466Smarius * Compute index of next position in the start 5041178466Smarius * queue the SCRIPTS intends to start and dequeue 504253790Sobrien * all CCBs for that device that haven't been started. 504353790Sobrien */ 504458927Sgroudier i = (INL (nc_scratcha) - np->squeue_ba) / 4; 504553790Sobrien i = sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); 504653790Sobrien 504753790Sobrien /* 504853790Sobrien * Make sure at least our IO to abort has been dequeued. 504953790Sobrien */ 505053790Sobrien assert(i && sym_get_cam_status(cp->cam_ccb) == CAM_REQUEUE_REQ); 505153790Sobrien 505253790Sobrien /* 505353790Sobrien * Keep track in cam status of the reason of the abort. 505453790Sobrien */ 505553790Sobrien if (cp->to_abort == 2) 505653790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_CMD_TIMEOUT); 505753790Sobrien else 505853790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_REQ_ABORTED); 505953790Sobrien 506053790Sobrien /* 506153790Sobrien * Complete with error everything that we have dequeued. 506253790Sobrien */ 506353790Sobrien sym_flush_comp_queue(np, 0); 506453790Sobrien break; 506553790Sobrien /* 5066178466Smarius * The SCRIPTS processor has selected a target 506753790Sobrien * we may have some manual recovery to perform for. 506853790Sobrien */ 506953790Sobrien case SIR_TARGET_SELECTED: 507053790Sobrien target = (INB (nc_sdid) & 0xf); 507153790Sobrien tp = &np->target[target]; 507253790Sobrien 507372361Sgroudier np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg)); 507453790Sobrien 507553790Sobrien /* 5076178466Smarius * If the target is to be reset, prepare a 5077178466Smarius * M_RESET message and clear the to_reset flag 507853790Sobrien * since we donnot expect this operation to fail. 507953790Sobrien */ 508053790Sobrien if (tp->to_reset) { 508153790Sobrien np->abrt_msg[0] = M_RESET; 508253790Sobrien np->abrt_tbl.size = 1; 508353790Sobrien tp->to_reset = 0; 508453790Sobrien break; 508553790Sobrien } 508653790Sobrien 508753790Sobrien /* 508853790Sobrien * Otherwise, look for some logical unit to be cleared. 508953790Sobrien */ 509053790Sobrien if (tp->lun0p && tp->lun0p->to_clear) 509153790Sobrien lun = 0; 509253790Sobrien else if (tp->lunmp) { 509354690Sobrien for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) { 509453790Sobrien if (tp->lunmp[k] && tp->lunmp[k]->to_clear) { 509553790Sobrien lun = k; 509653790Sobrien break; 509753790Sobrien } 509853790Sobrien } 509953790Sobrien } 510053790Sobrien 510153790Sobrien /* 5102178466Smarius * If a logical unit is to be cleared, prepare 510353790Sobrien * an IDENTIFY(lun) + ABORT MESSAGE. 510453790Sobrien */ 510553790Sobrien if (lun != -1) { 5106251402Smarius lcb_p lp = sym_lp(tp, lun); 510753790Sobrien lp->to_clear = 0; /* We donnot expect to fail here */ 510853790Sobrien np->abrt_msg[0] = M_IDENTIFY | lun; 510953790Sobrien np->abrt_msg[1] = M_ABORT; 511053790Sobrien np->abrt_tbl.size = 2; 511153790Sobrien break; 511253790Sobrien } 511353790Sobrien 511453790Sobrien /* 5115178466Smarius * Otherwise, look for some disconnected job to 511653790Sobrien * abort for this target. 511753790Sobrien */ 511853790Sobrien i = 0; 5119178466Smarius cp = NULL; 512053790Sobrien FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 512153790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 512253790Sobrien if (cp->host_status != HS_DISCONNECT) 512353790Sobrien continue; 512453790Sobrien if (cp->target != target) 512553790Sobrien continue; 512653790Sobrien if (!cp->to_abort) 512753790Sobrien continue; 512853790Sobrien i = 1; /* Means we have some */ 512953790Sobrien break; 513053790Sobrien } 513153790Sobrien 513253790Sobrien /* 5133178466Smarius * If we have none, probably since the device has 513453790Sobrien * completed the command before we won abitration, 513553790Sobrien * send a M_ABORT message without IDENTIFY. 5136178466Smarius * According to the specs, the device must just 513753790Sobrien * disconnect the BUS and not abort any task. 513853790Sobrien */ 513953790Sobrien if (!i) { 514053790Sobrien np->abrt_msg[0] = M_ABORT; 514153790Sobrien np->abrt_tbl.size = 1; 514253790Sobrien break; 514353790Sobrien } 514453790Sobrien 514553790Sobrien /* 514653790Sobrien * We have some task to abort. 514753790Sobrien * Set the IDENTIFY(lun) 514853790Sobrien */ 514953790Sobrien np->abrt_msg[0] = M_IDENTIFY | cp->lun; 515053790Sobrien 515153790Sobrien /* 5152178466Smarius * If we want to abort an untagged command, we 5153108533Sschweikh * will send an IDENTIFY + M_ABORT. 5154178466Smarius * Otherwise (tagged command), we will send 5155108533Sschweikh * an IDENTIFY + task attributes + ABORT TAG. 515653790Sobrien */ 515753790Sobrien if (cp->tag == NO_TAG) { 515853790Sobrien np->abrt_msg[1] = M_ABORT; 515953790Sobrien np->abrt_tbl.size = 2; 516053790Sobrien } 516153790Sobrien else { 516253790Sobrien np->abrt_msg[1] = cp->scsi_smsg[1]; 516353790Sobrien np->abrt_msg[2] = cp->scsi_smsg[2]; 516453790Sobrien np->abrt_msg[3] = M_ABORT_TAG; 516553790Sobrien np->abrt_tbl.size = 4; 516653790Sobrien } 516753790Sobrien /* 5168178466Smarius * Keep track of software timeout condition, since the 5169178466Smarius * peripheral driver may not count retries on abort 517053790Sobrien * conditions not due to timeout. 517153790Sobrien */ 517253790Sobrien if (cp->to_abort == 2) 517353790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_CMD_TIMEOUT); 517453790Sobrien cp->to_abort = 0; /* We donnot expect to fail here */ 517553790Sobrien break; 517653790Sobrien 517753790Sobrien /* 5178178466Smarius * The target has accepted our message and switched 517953790Sobrien * to BUS FREE phase as we expected. 518053790Sobrien */ 518153790Sobrien case SIR_ABORT_SENT: 518253790Sobrien target = (INB (nc_sdid) & 0xf); 518353790Sobrien tp = &np->target[target]; 5184178466Smarius 518553790Sobrien /* 518653790Sobrien ** If we didn't abort anything, leave here. 518753790Sobrien */ 518853790Sobrien if (np->abrt_msg[0] == M_ABORT) 518953790Sobrien break; 519053790Sobrien 519153790Sobrien /* 5192178466Smarius * If we sent a M_RESET, then a hardware reset has 519353790Sobrien * been performed by the target. 519453790Sobrien * - Reset everything to async 8 bit 519553790Sobrien * - Tell ourself to negotiate next time :-) 5196178466Smarius * - Prepare to clear all disconnected CCBs for 519753790Sobrien * this target from our task list (lun=task=-1) 519853790Sobrien */ 519953790Sobrien lun = -1; 520053790Sobrien task = -1; 520153790Sobrien if (np->abrt_msg[0] == M_RESET) { 520259743Sgroudier tp->head.sval = 0; 520359743Sgroudier tp->head.wval = np->rv_scntl3; 520459743Sgroudier tp->head.uval = 0; 520553790Sobrien tp->tinfo.current.period = 0; 520653790Sobrien tp->tinfo.current.offset = 0; 520753790Sobrien tp->tinfo.current.width = BUS_8_BIT; 520853790Sobrien tp->tinfo.current.options = 0; 520953790Sobrien } 521053790Sobrien 521153790Sobrien /* 5212178466Smarius * Otherwise, check for the LUN and TASK(s) 521353790Sobrien * concerned by the cancelation. 5214178466Smarius * If it is not ABORT_TAG then it is CLEAR_QUEUE 521553790Sobrien * or an ABORT message :-) 521653790Sobrien */ 521753790Sobrien else { 521853790Sobrien lun = np->abrt_msg[0] & 0x3f; 521953790Sobrien if (np->abrt_msg[1] == M_ABORT_TAG) 522053790Sobrien task = np->abrt_msg[2]; 522153790Sobrien } 522253790Sobrien 522353790Sobrien /* 5224178466Smarius * Complete all the CCBs the device should have 522553790Sobrien * aborted due to our 'kiss of death' message. 522653790Sobrien */ 522758927Sgroudier i = (INL (nc_scratcha) - np->squeue_ba) / 4; 522853790Sobrien (void) sym_dequeue_from_squeue(np, i, target, lun, -1); 522953790Sobrien (void) sym_clear_tasks(np, CAM_REQ_ABORTED, target, lun, task); 523053790Sobrien sym_flush_comp_queue(np, 0); 523153790Sobrien 523253790Sobrien /* 523353790Sobrien * If we sent a BDR, make uper layer aware of that. 523453790Sobrien */ 523553790Sobrien if (np->abrt_msg[0] == M_RESET) 523653790Sobrien xpt_async(AC_SENT_BDR, np->path, NULL); 523753790Sobrien break; 523853790Sobrien } 523953790Sobrien 524053790Sobrien /* 524153790Sobrien * Print to the log the message we intend to send. 524253790Sobrien */ 524353790Sobrien if (num == SIR_TARGET_SELECTED) { 524453790Sobrien PRINT_TARGET(np, target); 524553790Sobrien sym_printl_hex("control msgout:", np->abrt_msg, 524653790Sobrien np->abrt_tbl.size); 524753790Sobrien np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size); 524853790Sobrien } 524953790Sobrien 525053790Sobrien /* 525153790Sobrien * Let the SCRIPTS processor continue. 525253790Sobrien */ 525361429Sgroudier OUTONB_STD (); 525453790Sobrien} 525553790Sobrien 525653790Sobrien/* 5257178466Smarius * Gerard's alchemy:) that deals with with the data 525853790Sobrien * pointer for both MDP and the residual calculation. 525953790Sobrien * 5260178466Smarius * I didn't want to bloat the code by more than 200 526153790Sobrien * lignes for the handling of both MDP and the residual. 5262178466Smarius * This has been achieved by using a data pointer 5263178466Smarius * representation consisting in an index in the data 5264178466Smarius * array (dp_sg) and a negative offset (dp_ofs) that 526553790Sobrien * have the following meaning: 526653790Sobrien * 526754690Sobrien * - dp_sg = SYM_CONF_MAX_SG 526853790Sobrien * we are at the end of the data script. 526954690Sobrien * - dp_sg < SYM_CONF_MAX_SG 5270178466Smarius * dp_sg points to the next entry of the scatter array 527153790Sobrien * we want to transfer. 527253790Sobrien * - dp_ofs < 0 5273178466Smarius * dp_ofs represents the residual of bytes of the 527453790Sobrien * previous entry scatter entry we will send first. 527553790Sobrien * - dp_ofs = 0 527653790Sobrien * no residual to send first. 527753790Sobrien * 5278178466Smarius * The function sym_evaluate_dp() accepts an arbitray 5279178466Smarius * offset (basically from the MDP message) and returns 528053790Sobrien * the corresponding values of dp_sg and dp_ofs. 528153790Sobrien */ 528253790Sobrienstatic int sym_evaluate_dp(hcb_p np, ccb_p cp, u32 scr, int *ofs) 528353790Sobrien{ 528453790Sobrien u32 dp_scr; 528553790Sobrien int dp_ofs, dp_sg, dp_sgmin; 528653790Sobrien int tmp; 528753790Sobrien struct sym_pmc *pm; 528853790Sobrien 528953790Sobrien /* 5290178466Smarius * Compute the resulted data pointer in term of a script 529153790Sobrien * address within some DATA script and a signed byte offset. 529253790Sobrien */ 529353790Sobrien dp_scr = scr; 529453790Sobrien dp_ofs = *ofs; 529559292Sgroudier if (dp_scr == SCRIPTA_BA (np, pm0_data)) 529653790Sobrien pm = &cp->phys.pm0; 529759292Sgroudier else if (dp_scr == SCRIPTA_BA (np, pm1_data)) 529853790Sobrien pm = &cp->phys.pm1; 529953790Sobrien else 5300178466Smarius pm = NULL; 530153790Sobrien 530253790Sobrien if (pm) { 530353790Sobrien dp_scr = scr_to_cpu(pm->ret); 530453790Sobrien dp_ofs -= scr_to_cpu(pm->sg.size); 530553790Sobrien } 530653790Sobrien 530753790Sobrien /* 530853790Sobrien * If we are auto-sensing, then we are done. 530953790Sobrien */ 531053790Sobrien if (cp->host_flags & HF_SENSE) { 531153790Sobrien *ofs = dp_ofs; 531253790Sobrien return 0; 531353790Sobrien } 531453790Sobrien 531553790Sobrien /* 531653790Sobrien * Deduce the index of the sg entry. 531753790Sobrien * Keep track of the index of the first valid entry. 5318178466Smarius * If result is dp_sg = SYM_CONF_MAX_SG, then we are at the 531953790Sobrien * end of the data. 532053790Sobrien */ 532159743Sgroudier tmp = scr_to_cpu(cp->phys.head.goalp); 532254690Sobrien dp_sg = SYM_CONF_MAX_SG; 532356762Sgroudier if (dp_scr != tmp) 532453796Sobrien dp_sg -= (tmp - 8 - (int)dp_scr) / (2*4); 532554690Sobrien dp_sgmin = SYM_CONF_MAX_SG - cp->segments; 532653790Sobrien 532753790Sobrien /* 532853790Sobrien * Move to the sg entry the data pointer belongs to. 532953790Sobrien * 533053790Sobrien * If we are inside the data area, we expect result to be: 533153790Sobrien * 533253790Sobrien * Either, 533353790Sobrien * dp_ofs = 0 and dp_sg is the index of the sg entry 533453790Sobrien * the data pointer belongs to (or the end of the data) 533553790Sobrien * Or, 5336178466Smarius * dp_ofs < 0 and dp_sg is the index of the sg entry 533753790Sobrien * the data pointer belongs to + 1. 533853790Sobrien */ 533953790Sobrien if (dp_ofs < 0) { 534053790Sobrien int n; 534153790Sobrien while (dp_sg > dp_sgmin) { 534253790Sobrien --dp_sg; 534353790Sobrien tmp = scr_to_cpu(cp->phys.data[dp_sg].size); 534453790Sobrien n = dp_ofs + (tmp & 0xffffff); 534553790Sobrien if (n > 0) { 534653790Sobrien ++dp_sg; 534753790Sobrien break; 534853790Sobrien } 534953790Sobrien dp_ofs = n; 535053790Sobrien } 535153790Sobrien } 535253790Sobrien else if (dp_ofs > 0) { 535354690Sobrien while (dp_sg < SYM_CONF_MAX_SG) { 535453790Sobrien tmp = scr_to_cpu(cp->phys.data[dp_sg].size); 535553790Sobrien dp_ofs -= (tmp & 0xffffff); 535654690Sobrien ++dp_sg; 535753790Sobrien if (dp_ofs <= 0) 535853790Sobrien break; 535953790Sobrien } 536053790Sobrien } 536153790Sobrien 536253790Sobrien /* 536353790Sobrien * Make sure the data pointer is inside the data area. 536453790Sobrien * If not, return some error. 536553790Sobrien */ 536653790Sobrien if (dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0)) 536753790Sobrien goto out_err; 536854690Sobrien else if (dp_sg > SYM_CONF_MAX_SG || 536954690Sobrien (dp_sg == SYM_CONF_MAX_SG && dp_ofs > 0)) 537053790Sobrien goto out_err; 537153790Sobrien 537253790Sobrien /* 537353790Sobrien * Save the extreme pointer if needed. 537453790Sobrien */ 537553790Sobrien if (dp_sg > cp->ext_sg || 537653790Sobrien (dp_sg == cp->ext_sg && dp_ofs > cp->ext_ofs)) { 537753790Sobrien cp->ext_sg = dp_sg; 537853790Sobrien cp->ext_ofs = dp_ofs; 537953790Sobrien } 538053790Sobrien 538153790Sobrien /* 538253790Sobrien * Return data. 538353790Sobrien */ 538453790Sobrien *ofs = dp_ofs; 538553790Sobrien return dp_sg; 538653790Sobrien 538753790Sobrienout_err: 538853790Sobrien return -1; 538953790Sobrien} 539053790Sobrien 539153790Sobrien/* 539253790Sobrien * chip handler for MODIFY DATA POINTER MESSAGE 539353790Sobrien * 5394178466Smarius * We also call this function on IGNORE WIDE RESIDUE 539553790Sobrien * messages that do not match a SWIDE full condition. 5396178466Smarius * Btw, we assume in that situation that such a message 539753790Sobrien * is equivalent to a MODIFY DATA POINTER (offset=-1). 539853790Sobrien */ 5399251402Smariusstatic void sym_modify_dp(hcb_p np, ccb_p cp, int ofs) 540053790Sobrien{ 540153790Sobrien int dp_ofs = ofs; 540253790Sobrien u32 dp_scr = INL (nc_temp); 540353790Sobrien u32 dp_ret; 540453796Sobrien u32 tmp; 540553790Sobrien u_char hflags; 540653790Sobrien int dp_sg; 540753790Sobrien struct sym_pmc *pm; 540853790Sobrien 540953790Sobrien /* 541053790Sobrien * Not supported for auto-sense. 541153790Sobrien */ 541253790Sobrien if (cp->host_flags & HF_SENSE) 541353790Sobrien goto out_reject; 541453790Sobrien 541553790Sobrien /* 5416178466Smarius * Apply our alchemy:) (see comments in sym_evaluate_dp()), 541753790Sobrien * to the resulted data pointer. 541853790Sobrien */ 541953790Sobrien dp_sg = sym_evaluate_dp(np, cp, dp_scr, &dp_ofs); 542053790Sobrien if (dp_sg < 0) 542153790Sobrien goto out_reject; 542253790Sobrien 542353790Sobrien /* 5424178466Smarius * And our alchemy:) allows to easily calculate the data 542553790Sobrien * script address we want to return for the next data phase. 542653790Sobrien */ 542759743Sgroudier dp_ret = cpu_to_scr(cp->phys.head.goalp); 542854690Sobrien dp_ret = dp_ret - 8 - (SYM_CONF_MAX_SG - dp_sg) * (2*4); 542953790Sobrien 543053790Sobrien /* 5431178466Smarius * If offset / scatter entry is zero we donnot need 543253790Sobrien * a context for the new current data pointer. 543353790Sobrien */ 543453790Sobrien if (dp_ofs == 0) { 543553790Sobrien dp_scr = dp_ret; 543653790Sobrien goto out_ok; 543753790Sobrien } 543853790Sobrien 543953790Sobrien /* 544053790Sobrien * Get a context for the new current data pointer. 544153790Sobrien */ 544253790Sobrien hflags = INB (HF_PRT); 544353790Sobrien 544453790Sobrien if (hflags & HF_DP_SAVED) 544553790Sobrien hflags ^= HF_ACT_PM; 544653790Sobrien 544753790Sobrien if (!(hflags & HF_ACT_PM)) { 544853790Sobrien pm = &cp->phys.pm0; 544959292Sgroudier dp_scr = SCRIPTA_BA (np, pm0_data); 545053790Sobrien } 545153790Sobrien else { 545253790Sobrien pm = &cp->phys.pm1; 545359292Sgroudier dp_scr = SCRIPTA_BA (np, pm1_data); 545453790Sobrien } 545553790Sobrien 545653790Sobrien hflags &= ~(HF_DP_SAVED); 545753790Sobrien 545853790Sobrien OUTB (HF_PRT, hflags); 545953790Sobrien 546053790Sobrien /* 546153790Sobrien * Set up the new current data pointer. 5462178466Smarius * ofs < 0 there, and for the next data phase, we 5463178466Smarius * want to transfer part of the data of the sg entry 5464178466Smarius * corresponding to index dp_sg-1 prior to returning 546553790Sobrien * to the main data script. 546653790Sobrien */ 546753790Sobrien pm->ret = cpu_to_scr(dp_ret); 546853796Sobrien tmp = scr_to_cpu(cp->phys.data[dp_sg-1].addr); 546953796Sobrien tmp += scr_to_cpu(cp->phys.data[dp_sg-1].size) + dp_ofs; 547053796Sobrien pm->sg.addr = cpu_to_scr(tmp); 547153796Sobrien pm->sg.size = cpu_to_scr(-dp_ofs); 547253790Sobrien 547353790Sobrienout_ok: 547453790Sobrien OUTL (nc_temp, dp_scr); 547561429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 547653790Sobrien return; 547753790Sobrien 547853790Sobrienout_reject: 547961429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 548053790Sobrien} 548153790Sobrien 548253790Sobrien/* 548353790Sobrien * chip calculation of the data residual. 548453790Sobrien * 5485178466Smarius * As I used to say, the requirement of data residual 5486178466Smarius * in SCSI is broken, useless and cannot be achieved 548753790Sobrien * without huge complexity. 548853790Sobrien * But most OSes and even the official CAM require it. 5489178466Smarius * When stupidity happens to be so widely spread inside 549053790Sobrien * a community, it gets hard to convince. 549153790Sobrien * 5492178466Smarius * Anyway, I don't care, since I am not going to use 5493178466Smarius * any software that considers this data residual as 549453790Sobrien * a relevant information. :) 549553790Sobrien */ 549653790Sobrienstatic int sym_compute_residual(hcb_p np, ccb_p cp) 549753790Sobrien{ 549857186Sgroudier int dp_sg, dp_sgmin, resid = 0; 549953790Sobrien int dp_ofs = 0; 550053790Sobrien 550153790Sobrien /* 550253790Sobrien * Check for some data lost or just thrown away. 5503178466Smarius * We are not required to be quite accurate in this 5504178466Smarius * situation. Btw, if we are odd for output and the 5505178466Smarius * device claims some more data, it may well happen 550653790Sobrien * than our residual be zero. :-) 550753790Sobrien */ 550853790Sobrien if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) { 550953790Sobrien if (cp->xerr_status & XE_EXTRA_DATA) 551059252Sgroudier resid -= cp->extra_bytes; 551153790Sobrien if (cp->xerr_status & XE_SODL_UNRUN) 551253790Sobrien ++resid; 551353790Sobrien if (cp->xerr_status & XE_SWIDE_OVRUN) 551453790Sobrien --resid; 551553790Sobrien } 551653790Sobrien 551753790Sobrien /* 551853790Sobrien * If all data has been transferred, 551953790Sobrien * there is no residual. 552053790Sobrien */ 552159743Sgroudier if (cp->phys.head.lastp == cp->phys.head.goalp) 552257186Sgroudier return resid; 552353790Sobrien 552453790Sobrien /* 552553790Sobrien * If no data transfer occurs, or if the data 552653790Sobrien * pointer is weird, return full residual. 552753790Sobrien */ 552859743Sgroudier if (cp->startp == cp->phys.head.lastp || 552959743Sgroudier sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp), 553059743Sgroudier &dp_ofs) < 0) { 553153790Sobrien return cp->data_len; 553253790Sobrien } 553353790Sobrien 553453790Sobrien /* 553553790Sobrien * If we were auto-sensing, then we are done. 553653790Sobrien */ 553753790Sobrien if (cp->host_flags & HF_SENSE) { 553853790Sobrien return -dp_ofs; 553953790Sobrien } 554053790Sobrien 554153790Sobrien /* 5542178466Smarius * We are now full comfortable in the computation 554353790Sobrien * of the data residual (2's complement). 554453790Sobrien */ 554554690Sobrien dp_sgmin = SYM_CONF_MAX_SG - cp->segments; 554653790Sobrien resid = -cp->ext_ofs; 554754690Sobrien for (dp_sg = cp->ext_sg; dp_sg < SYM_CONF_MAX_SG; ++dp_sg) { 554861051Sgroudier u_int tmp = scr_to_cpu(cp->phys.data[dp_sg].size); 554953790Sobrien resid += (tmp & 0xffffff); 555053790Sobrien } 555153790Sobrien 555253790Sobrien /* 555353790Sobrien * Hopefully, the result is not too wrong. 555453790Sobrien */ 555553790Sobrien return resid; 555653790Sobrien} 555753790Sobrien 555853790Sobrien/* 555959743Sgroudier * Print out the content of a SCSI message. 556053790Sobrien */ 556153790Sobrienstatic int sym_show_msg (u_char * msg) 556253790Sobrien{ 556353790Sobrien u_char i; 556453790Sobrien printf ("%x",*msg); 556553790Sobrien if (*msg==M_EXTENDED) { 556653790Sobrien for (i=1;i<8;i++) { 556753790Sobrien if (i-1>msg[1]) break; 556853790Sobrien printf ("-%x",msg[i]); 556953790Sobrien }; 557053790Sobrien return (i+1); 557153790Sobrien } else if ((*msg & 0xf0) == 0x20) { 557253790Sobrien printf ("-%x",msg[1]); 557353790Sobrien return (2); 557453790Sobrien }; 557553790Sobrien return (1); 557653790Sobrien} 557753790Sobrien 557853790Sobrienstatic void sym_print_msg (ccb_p cp, char *label, u_char *msg) 557953790Sobrien{ 558053790Sobrien PRINT_ADDR(cp); 558153790Sobrien if (label) 558253790Sobrien printf ("%s: ", label); 558353790Sobrien 558453790Sobrien (void) sym_show_msg (msg); 558553790Sobrien printf (".\n"); 558653790Sobrien} 558753790Sobrien 558853790Sobrien/* 558953790Sobrien * Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER. 559053790Sobrien * 559153790Sobrien * When we try to negotiate, we append the negotiation message 559253790Sobrien * to the identify and (maybe) simple tag message. 559353790Sobrien * The host status field is set to HS_NEGOTIATE to mark this 559453790Sobrien * situation. 559553790Sobrien * 559653790Sobrien * If the target doesn't answer this message immediately 559753790Sobrien * (as required by the standard), the SIR_NEGO_FAILED interrupt 559853790Sobrien * will be raised eventually. 559953790Sobrien * The handler removes the HS_NEGOTIATE status, and sets the 560053790Sobrien * negotiated value to the default (async / nowide). 560153790Sobrien * 560253790Sobrien * If we receive a matching answer immediately, we check it 560353790Sobrien * for validity, and set the values. 560453790Sobrien * 560553790Sobrien * If we receive a Reject message immediately, we assume the 560653790Sobrien * negotiation has failed, and fall back to standard values. 560753790Sobrien * 560853790Sobrien * If we receive a negotiation message while not in HS_NEGOTIATE 560953790Sobrien * state, it's a target initiated negotiation. We prepare a 5610178466Smarius * (hopefully) valid answer, set our parameters, and send back 561153790Sobrien * this answer to the target. 561253790Sobrien * 561353790Sobrien * If the target doesn't fetch the answer (no message out phase), 561453790Sobrien * we assume the negotiation has failed, and fall back to default 561553790Sobrien * settings (SIR_NEGO_PROTO interrupt). 561653790Sobrien * 5617178466Smarius * When we set the values, we adjust them in all ccbs belonging 561853790Sobrien * to this target, in the controller's register, and in the "phys" 561953790Sobrien * field of the controller's struct sym_hcb. 562053790Sobrien */ 562153790Sobrien 562253790Sobrien/* 562353790Sobrien * chip handler for SYNCHRONOUS DATA TRANSFER REQUEST (SDTR) message. 562453790Sobrien */ 562553790Sobrienstatic void sym_sync_nego(hcb_p np, tcb_p tp, ccb_p cp) 562653790Sobrien{ 562753790Sobrien u_char chg, ofs, per, fak, div; 562853790Sobrien int req = 1; 562953790Sobrien 563053790Sobrien /* 563153790Sobrien * Synchronous request message received. 563253790Sobrien */ 563353790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 563453809Sobrien sym_print_msg(cp, "sync msgin", np->msgin); 563553790Sobrien }; 563653790Sobrien 563753790Sobrien /* 563853790Sobrien * request or answer ? 563953790Sobrien */ 564053790Sobrien if (INB (HS_PRT) == HS_NEGOTIATE) { 564153790Sobrien OUTB (HS_PRT, HS_BUSY); 564253790Sobrien if (cp->nego_status && cp->nego_status != NS_SYNC) 564353790Sobrien goto reject_it; 564453790Sobrien req = 0; 564553790Sobrien } 564653790Sobrien 564753790Sobrien /* 564853790Sobrien * get requested values. 564953790Sobrien */ 565053790Sobrien chg = 0; 565153790Sobrien per = np->msgin[3]; 565253790Sobrien ofs = np->msgin[4]; 565353790Sobrien 565453790Sobrien /* 565553790Sobrien * check values against our limits. 565653790Sobrien */ 565753790Sobrien if (ofs) { 565853790Sobrien if (ofs > np->maxoffs) 565953790Sobrien {chg = 1; ofs = np->maxoffs;} 566053790Sobrien if (req) { 566153790Sobrien if (ofs > tp->tinfo.user.offset) 566253790Sobrien {chg = 1; ofs = tp->tinfo.user.offset;} 566353790Sobrien } 566453790Sobrien } 566553790Sobrien 566653790Sobrien if (ofs) { 566753790Sobrien if (per < np->minsync) 566853790Sobrien {chg = 1; per = np->minsync;} 566953790Sobrien if (req) { 567053790Sobrien if (per < tp->tinfo.user.period) 567153790Sobrien {chg = 1; per = tp->tinfo.user.period;} 567253790Sobrien } 567353790Sobrien } 567453790Sobrien 567553790Sobrien div = fak = 0; 567653790Sobrien if (ofs && sym_getsync(np, 0, per, &div, &fak) < 0) 567753790Sobrien goto reject_it; 567853790Sobrien 567953790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 568053790Sobrien PRINT_ADDR(cp); 568153790Sobrien printf ("sdtr: ofs=%d per=%d div=%d fak=%d chg=%d.\n", 568253790Sobrien ofs, per, div, fak, chg); 568353790Sobrien } 568453790Sobrien 568553790Sobrien /* 568653790Sobrien * This was an answer message 568753790Sobrien */ 568853790Sobrien if (req == 0) { 568953790Sobrien if (chg) /* Answer wasn't acceptable. */ 569053790Sobrien goto reject_it; 569153790Sobrien sym_setsync (np, cp, ofs, per, div, fak); 569261429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 569353790Sobrien return; 569453790Sobrien } 569553790Sobrien 569653790Sobrien /* 569753790Sobrien * It was a request. Set value and 569853790Sobrien * prepare an answer message 569953790Sobrien */ 570053790Sobrien sym_setsync (np, cp, ofs, per, div, fak); 570153790Sobrien 570253790Sobrien np->msgout[0] = M_EXTENDED; 570353790Sobrien np->msgout[1] = 3; 570453790Sobrien np->msgout[2] = M_X_SYNC_REQ; 570553790Sobrien np->msgout[3] = per; 570653790Sobrien np->msgout[4] = ofs; 570753790Sobrien 570853790Sobrien cp->nego_status = NS_SYNC; 570953790Sobrien 571053790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 571153790Sobrien sym_print_msg(cp, "sync msgout", np->msgout); 571253790Sobrien } 571353790Sobrien 571453790Sobrien np->msgin [0] = M_NOOP; 571553790Sobrien 571661429Sgroudier OUTL_DSP (SCRIPTB_BA (np, sdtr_resp)); 571753790Sobrien return; 571853790Sobrienreject_it: 571953790Sobrien sym_setsync (np, cp, 0, 0, 0, 0); 572061429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 572153790Sobrien} 572253790Sobrien 572353790Sobrien/* 572453790Sobrien * chip handler for PARALLEL PROTOCOL REQUEST (PPR) message. 572553790Sobrien */ 572653790Sobrienstatic void sym_ppr_nego(hcb_p np, tcb_p tp, ccb_p cp) 572753790Sobrien{ 572853790Sobrien u_char chg, ofs, per, fak, dt, div, wide; 572953790Sobrien int req = 1; 573053790Sobrien 573153790Sobrien /* 573253790Sobrien * Synchronous request message received. 573353790Sobrien */ 573453790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 573553809Sobrien sym_print_msg(cp, "ppr msgin", np->msgin); 573653790Sobrien }; 573753790Sobrien 573853790Sobrien /* 573972361Sgroudier * get requested values. 574072361Sgroudier */ 574172361Sgroudier chg = 0; 574272361Sgroudier per = np->msgin[3]; 574372361Sgroudier ofs = np->msgin[5]; 574472361Sgroudier wide = np->msgin[6]; 574572361Sgroudier dt = np->msgin[7] & PPR_OPT_DT; 574672361Sgroudier 574772361Sgroudier /* 574853790Sobrien * request or answer ? 574953790Sobrien */ 575053790Sobrien if (INB (HS_PRT) == HS_NEGOTIATE) { 575153790Sobrien OUTB (HS_PRT, HS_BUSY); 575253790Sobrien if (cp->nego_status && cp->nego_status != NS_PPR) 575353790Sobrien goto reject_it; 575453790Sobrien req = 0; 575553790Sobrien } 575653790Sobrien 575753790Sobrien /* 575853790Sobrien * check values against our limits. 575953790Sobrien */ 576053790Sobrien if (wide > np->maxwide) 576153790Sobrien {chg = 1; wide = np->maxwide;} 576253790Sobrien if (!wide || !(np->features & FE_ULTRA3)) 576353790Sobrien dt &= ~PPR_OPT_DT; 576453790Sobrien if (req) { 576553790Sobrien if (wide > tp->tinfo.user.width) 576653790Sobrien {chg = 1; wide = tp->tinfo.user.width;} 576753790Sobrien } 576857186Sgroudier 576953790Sobrien if (!(np->features & FE_U3EN)) /* Broken U3EN bit not supported */ 577053790Sobrien dt &= ~PPR_OPT_DT; 577157186Sgroudier 577253790Sobrien if (dt != (np->msgin[7] & PPR_OPT_MASK)) chg = 1; 577353790Sobrien 577453790Sobrien if (ofs) { 577560134Sgroudier if (dt) { 577660134Sgroudier if (ofs > np->maxoffs_dt) 577760134Sgroudier {chg = 1; ofs = np->maxoffs_dt;} 577860134Sgroudier } 577960134Sgroudier else if (ofs > np->maxoffs) 578053790Sobrien {chg = 1; ofs = np->maxoffs;} 578153790Sobrien if (req) { 578253790Sobrien if (ofs > tp->tinfo.user.offset) 578353790Sobrien {chg = 1; ofs = tp->tinfo.user.offset;} 578453790Sobrien } 578553790Sobrien } 578653790Sobrien 578753790Sobrien if (ofs) { 578853809Sobrien if (dt) { 578953809Sobrien if (per < np->minsync_dt) 579053809Sobrien {chg = 1; per = np->minsync_dt;} 579153809Sobrien } 579253790Sobrien else if (per < np->minsync) 579353790Sobrien {chg = 1; per = np->minsync;} 579453790Sobrien if (req) { 579553790Sobrien if (per < tp->tinfo.user.period) 579653790Sobrien {chg = 1; per = tp->tinfo.user.period;} 579753790Sobrien } 579853790Sobrien } 579953790Sobrien 580053790Sobrien div = fak = 0; 580153790Sobrien if (ofs && sym_getsync(np, dt, per, &div, &fak) < 0) 580253790Sobrien goto reject_it; 5803178466Smarius 580453790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 580553790Sobrien PRINT_ADDR(cp); 580653790Sobrien printf ("ppr: " 580753790Sobrien "dt=%x ofs=%d per=%d wide=%d div=%d fak=%d chg=%d.\n", 580853790Sobrien dt, ofs, per, wide, div, fak, chg); 580953790Sobrien } 581053790Sobrien 581153790Sobrien /* 581253790Sobrien * It was an answer. 581353790Sobrien */ 581453790Sobrien if (req == 0) { 581553790Sobrien if (chg) /* Answer wasn't acceptable */ 581653790Sobrien goto reject_it; 581753790Sobrien sym_setpprot (np, cp, dt, ofs, per, wide, div, fak); 581861429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 581953790Sobrien return; 582053790Sobrien } 582153790Sobrien 582253790Sobrien /* 582353790Sobrien * It was a request. Set value and 582453790Sobrien * prepare an answer message 582553790Sobrien */ 582653790Sobrien sym_setpprot (np, cp, dt, ofs, per, wide, div, fak); 582753790Sobrien 582853790Sobrien np->msgout[0] = M_EXTENDED; 582953790Sobrien np->msgout[1] = 6; 583053790Sobrien np->msgout[2] = M_X_PPR_REQ; 583153790Sobrien np->msgout[3] = per; 583253790Sobrien np->msgout[4] = 0; 583353790Sobrien np->msgout[5] = ofs; 583453790Sobrien np->msgout[6] = wide; 583553790Sobrien np->msgout[7] = dt; 583653790Sobrien 583753790Sobrien cp->nego_status = NS_PPR; 583853790Sobrien 583953790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 584053809Sobrien sym_print_msg(cp, "ppr msgout", np->msgout); 584153790Sobrien } 584253790Sobrien 584353790Sobrien np->msgin [0] = M_NOOP; 584453790Sobrien 584561429Sgroudier OUTL_DSP (SCRIPTB_BA (np, ppr_resp)); 584653790Sobrien return; 584753790Sobrienreject_it: 584853790Sobrien sym_setpprot (np, cp, 0, 0, 0, 0, 0, 0); 584961429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 585072361Sgroudier /* 5851178466Smarius * If it was a device response that should result in 585272361Sgroudier * ST, we may want to try a legacy negotiation later. 585372361Sgroudier */ 585472361Sgroudier if (!req && !dt) { 585572361Sgroudier tp->tinfo.goal.options = 0; 585672361Sgroudier tp->tinfo.goal.width = wide; 585772361Sgroudier tp->tinfo.goal.period = per; 585872361Sgroudier tp->tinfo.goal.offset = ofs; 585972361Sgroudier } 586053790Sobrien} 586153790Sobrien 586253790Sobrien/* 586353790Sobrien * chip handler for WIDE DATA TRANSFER REQUEST (WDTR) message. 586453790Sobrien */ 586553790Sobrienstatic void sym_wide_nego(hcb_p np, tcb_p tp, ccb_p cp) 586653790Sobrien{ 586753790Sobrien u_char chg, wide; 586853790Sobrien int req = 1; 586953790Sobrien 587053790Sobrien /* 587153790Sobrien * Wide request message received. 587253790Sobrien */ 587353790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 587453790Sobrien sym_print_msg(cp, "wide msgin", np->msgin); 587553790Sobrien }; 587653790Sobrien 587753790Sobrien /* 5878108470Sschweikh * Is it a request from the device? 587953790Sobrien */ 588053790Sobrien if (INB (HS_PRT) == HS_NEGOTIATE) { 588153790Sobrien OUTB (HS_PRT, HS_BUSY); 588253790Sobrien if (cp->nego_status && cp->nego_status != NS_WIDE) 588353790Sobrien goto reject_it; 588453790Sobrien req = 0; 588553790Sobrien } 588653790Sobrien 588753790Sobrien /* 588853790Sobrien * get requested values. 588953790Sobrien */ 589053790Sobrien chg = 0; 589153790Sobrien wide = np->msgin[3]; 589253790Sobrien 589353790Sobrien /* 589453790Sobrien * check values against driver limits. 589553790Sobrien */ 589665404Sgroudier if (wide > np->maxwide) 589765404Sgroudier {chg = 1; wide = np->maxwide;} 589853790Sobrien if (req) { 589953790Sobrien if (wide > tp->tinfo.user.width) 590053790Sobrien {chg = 1; wide = tp->tinfo.user.width;} 590153790Sobrien } 590253790Sobrien 590353790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 590453790Sobrien PRINT_ADDR(cp); 590553790Sobrien printf ("wdtr: wide=%d chg=%d.\n", wide, chg); 590653790Sobrien } 590753790Sobrien 590853790Sobrien /* 590953790Sobrien * This was an answer message 591053790Sobrien */ 591153790Sobrien if (req == 0) { 591253790Sobrien if (chg) /* Answer wasn't acceptable. */ 591353790Sobrien goto reject_it; 591453790Sobrien sym_setwide (np, cp, wide); 591559743Sgroudier 591655628Sgroudier /* 591755628Sgroudier * Negotiate for SYNC immediately after WIDE response. 5918178466Smarius * This allows to negotiate for both WIDE and SYNC on 591955628Sgroudier * a single SCSI command (Suggested by Justin Gibbs). 592055628Sgroudier */ 592155628Sgroudier if (tp->tinfo.goal.offset) { 592255628Sgroudier np->msgout[0] = M_EXTENDED; 592355628Sgroudier np->msgout[1] = 3; 592455628Sgroudier np->msgout[2] = M_X_SYNC_REQ; 592555628Sgroudier np->msgout[3] = tp->tinfo.goal.period; 592655628Sgroudier np->msgout[4] = tp->tinfo.goal.offset; 592755628Sgroudier 592855628Sgroudier if (DEBUG_FLAGS & DEBUG_NEGO) { 592955628Sgroudier sym_print_msg(cp, "sync msgout", np->msgout); 593055628Sgroudier } 593155628Sgroudier 593255628Sgroudier cp->nego_status = NS_SYNC; 593355628Sgroudier OUTB (HS_PRT, HS_NEGOTIATE); 593461429Sgroudier OUTL_DSP (SCRIPTB_BA (np, sdtr_resp)); 593555628Sgroudier return; 593655628Sgroudier } 593759743Sgroudier 593861429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 593953790Sobrien return; 594053790Sobrien }; 594153790Sobrien 594253790Sobrien /* 594353790Sobrien * It was a request, set value and 594453790Sobrien * prepare an answer message 594553790Sobrien */ 594653790Sobrien sym_setwide (np, cp, wide); 594753790Sobrien 594853790Sobrien np->msgout[0] = M_EXTENDED; 594953790Sobrien np->msgout[1] = 2; 595053790Sobrien np->msgout[2] = M_X_WIDE_REQ; 595153790Sobrien np->msgout[3] = wide; 595253790Sobrien 595353790Sobrien np->msgin [0] = M_NOOP; 595453790Sobrien 595553790Sobrien cp->nego_status = NS_WIDE; 595653790Sobrien 595753790Sobrien if (DEBUG_FLAGS & DEBUG_NEGO) { 595853790Sobrien sym_print_msg(cp, "wide msgout", np->msgout); 595953790Sobrien } 596053790Sobrien 596161429Sgroudier OUTL_DSP (SCRIPTB_BA (np, wdtr_resp)); 596253790Sobrien return; 596353790Sobrienreject_it: 596461429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 596553790Sobrien} 596653790Sobrien 596753790Sobrien/* 596853790Sobrien * Reset SYNC or WIDE to default settings. 596953790Sobrien * 5970178466Smarius * Called when a negotiation does not succeed either 597153790Sobrien * on rejection or on protocol error. 597272361Sgroudier * 5973178466Smarius * If it was a PPR that made problems, we may want to 597472361Sgroudier * try a legacy negotiation later. 597553790Sobrien */ 597653790Sobrienstatic void sym_nego_default(hcb_p np, tcb_p tp, ccb_p cp) 597753790Sobrien{ 597853790Sobrien /* 597953790Sobrien * any error in negotiation: 598053790Sobrien * fall back to default mode. 598153790Sobrien */ 598253790Sobrien switch (cp->nego_status) { 598353790Sobrien case NS_PPR: 598472361Sgroudier#if 0 598553790Sobrien sym_setpprot (np, cp, 0, 0, 0, 0, 0, 0); 598672361Sgroudier#else 598772361Sgroudier tp->tinfo.goal.options = 0; 598872361Sgroudier if (tp->tinfo.goal.period < np->minsync) 598972361Sgroudier tp->tinfo.goal.period = np->minsync; 599072361Sgroudier if (tp->tinfo.goal.offset > np->maxoffs) 599172361Sgroudier tp->tinfo.goal.offset = np->maxoffs; 599272361Sgroudier#endif 599353790Sobrien break; 599453790Sobrien case NS_SYNC: 599553790Sobrien sym_setsync (np, cp, 0, 0, 0, 0); 599653790Sobrien break; 599753790Sobrien case NS_WIDE: 599853790Sobrien sym_setwide (np, cp, 0); 599953790Sobrien break; 600053790Sobrien }; 600153790Sobrien np->msgin [0] = M_NOOP; 600253790Sobrien np->msgout[0] = M_NOOP; 600353790Sobrien cp->nego_status = 0; 600453790Sobrien} 600553790Sobrien 600653790Sobrien/* 6007178466Smarius * chip handler for MESSAGE REJECT received in response to 600853790Sobrien * a WIDE or SYNCHRONOUS negotiation. 600953790Sobrien */ 601053790Sobrienstatic void sym_nego_rejected(hcb_p np, tcb_p tp, ccb_p cp) 601153790Sobrien{ 601253790Sobrien sym_nego_default(np, tp, cp); 601353790Sobrien OUTB (HS_PRT, HS_BUSY); 601453790Sobrien} 601553790Sobrien 601653790Sobrien/* 601753790Sobrien * chip exception handler for programmed interrupts. 601853790Sobrien */ 6019105215Sphkstatic void sym_int_sir (hcb_p np) 602053790Sobrien{ 602153790Sobrien u_char num = INB (nc_dsps); 602261051Sgroudier u32 dsa = INL (nc_dsa); 602353790Sobrien ccb_p cp = sym_ccb_from_dsa(np, dsa); 602453790Sobrien u_char target = INB (nc_sdid) & 0x0f; 602553790Sobrien tcb_p tp = &np->target[target]; 602653790Sobrien int tmp; 602753790Sobrien 6028178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 6029178468Smarius 603053790Sobrien if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num); 603153790Sobrien 603253790Sobrien switch (num) { 603353790Sobrien /* 6034178466Smarius * Command has been completed with error condition 603553790Sobrien * or has been auto-sensed. 603653790Sobrien */ 603753790Sobrien case SIR_COMPLETE_ERROR: 603853790Sobrien sym_complete_error(np, cp); 603953790Sobrien return; 604053790Sobrien /* 604153790Sobrien * The C code is currently trying to recover from something. 604253790Sobrien * Typically, user want to abort some command. 604353790Sobrien */ 604453790Sobrien case SIR_SCRIPT_STOPPED: 604553790Sobrien case SIR_TARGET_SELECTED: 604653790Sobrien case SIR_ABORT_SENT: 604753790Sobrien sym_sir_task_recovery(np, num); 604853790Sobrien return; 604953790Sobrien /* 6050178466Smarius * The device didn't go to MSG OUT phase after having 6051178466Smarius * been selected with ATN. We donnot want to handle 605253790Sobrien * that. 605353790Sobrien */ 605453790Sobrien case SIR_SEL_ATN_NO_MSG_OUT: 605553790Sobrien printf ("%s:%d: No MSG OUT phase after selection with ATN.\n", 605653790Sobrien sym_name (np), target); 605753790Sobrien goto out_stuck; 605853790Sobrien /* 6059178466Smarius * The device didn't switch to MSG IN phase after 606053790Sobrien * having reseleted the initiator. 606153790Sobrien */ 606253790Sobrien case SIR_RESEL_NO_MSG_IN: 606357186Sgroudier printf ("%s:%d: No MSG IN phase after reselection.\n", 606457186Sgroudier sym_name (np), target); 606557186Sgroudier goto out_stuck; 606653790Sobrien /* 6067178466Smarius * After reselection, the device sent a message that wasn't 606853790Sobrien * an IDENTIFY. 606953790Sobrien */ 607053790Sobrien case SIR_RESEL_NO_IDENTIFY: 607157186Sgroudier printf ("%s:%d: No IDENTIFY after reselection.\n", 607257186Sgroudier sym_name (np), target); 607357186Sgroudier goto out_stuck; 607453790Sobrien /* 607553790Sobrien * The device reselected a LUN we donnot know about. 607653790Sobrien */ 607753790Sobrien case SIR_RESEL_BAD_LUN: 607853790Sobrien np->msgout[0] = M_RESET; 607953790Sobrien goto out; 608053790Sobrien /* 6081178466Smarius * The device reselected for an untagged nexus and we 608253790Sobrien * haven't any. 608353790Sobrien */ 608453790Sobrien case SIR_RESEL_BAD_I_T_L: 608553790Sobrien np->msgout[0] = M_ABORT; 608653790Sobrien goto out; 608753790Sobrien /* 6088178466Smarius * The device reselected for a tagged nexus that we donnot 608953790Sobrien * have. 609053790Sobrien */ 609153790Sobrien case SIR_RESEL_BAD_I_T_L_Q: 609253790Sobrien np->msgout[0] = M_ABORT_TAG; 609353790Sobrien goto out; 609453790Sobrien /* 6095178466Smarius * The SCRIPTS let us know that the device has grabbed 609653790Sobrien * our message and will abort the job. 609753790Sobrien */ 609853790Sobrien case SIR_RESEL_ABORTED: 609953790Sobrien np->lastmsg = np->msgout[0]; 610053790Sobrien np->msgout[0] = M_NOOP; 610153790Sobrien printf ("%s:%d: message %x sent on bad reselection.\n", 610253790Sobrien sym_name (np), target, np->lastmsg); 610353790Sobrien goto out; 610453790Sobrien /* 6105178466Smarius * The SCRIPTS let us know that a message has been 610653790Sobrien * successfully sent to the device. 610753790Sobrien */ 610853790Sobrien case SIR_MSG_OUT_DONE: 610953790Sobrien np->lastmsg = np->msgout[0]; 611053790Sobrien np->msgout[0] = M_NOOP; 611153790Sobrien /* Should we really care of that */ 611253790Sobrien if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) { 611353790Sobrien if (cp) { 611453790Sobrien cp->xerr_status &= ~XE_PARITY_ERR; 611553790Sobrien if (!cp->xerr_status) 611653790Sobrien OUTOFFB (HF_PRT, HF_EXT_ERR); 611753790Sobrien } 611853790Sobrien } 611953790Sobrien goto out; 612053790Sobrien /* 612153790Sobrien * The device didn't send a GOOD SCSI status. 6122178466Smarius * We may have some work to do prior to allow 612353790Sobrien * the SCRIPTS processor to continue. 612453790Sobrien */ 612553790Sobrien case SIR_BAD_SCSI_STATUS: 612653790Sobrien if (!cp) 612753790Sobrien goto out; 6128251402Smarius sym_sir_bad_scsi_status(np, cp); 612953790Sobrien return; 613053790Sobrien /* 6131178466Smarius * We are asked by the SCRIPTS to prepare a 613253790Sobrien * REJECT message. 613353790Sobrien */ 613453790Sobrien case SIR_REJECT_TO_SEND: 613553790Sobrien sym_print_msg(cp, "M_REJECT to send for ", np->msgin); 613653790Sobrien np->msgout[0] = M_REJECT; 613753790Sobrien goto out; 613853790Sobrien /* 6139178466Smarius * We have been ODD at the end of a DATA IN 6140178466Smarius * transfer and the device didn't send a 614153790Sobrien * IGNORE WIDE RESIDUE message. 614253790Sobrien * It is a data overrun condition. 614353790Sobrien */ 614453790Sobrien case SIR_SWIDE_OVERRUN: 614553790Sobrien if (cp) { 614653790Sobrien OUTONB (HF_PRT, HF_EXT_ERR); 614753790Sobrien cp->xerr_status |= XE_SWIDE_OVRUN; 614853790Sobrien } 614953790Sobrien goto out; 615053790Sobrien /* 6151178466Smarius * We have been ODD at the end of a DATA OUT 615253790Sobrien * transfer. 615353790Sobrien * It is a data underrun condition. 615453790Sobrien */ 615553790Sobrien case SIR_SODL_UNDERRUN: 615653790Sobrien if (cp) { 615753790Sobrien OUTONB (HF_PRT, HF_EXT_ERR); 615853790Sobrien cp->xerr_status |= XE_SODL_UNRUN; 615953790Sobrien } 616053790Sobrien goto out; 616153790Sobrien /* 6162178466Smarius * The device wants us to tranfer more data than 616359252Sgroudier * expected or in the wrong direction. 616459252Sgroudier * The number of extra bytes is in scratcha. 616559252Sgroudier * It is a data overrun condition. 616659252Sgroudier */ 616759252Sgroudier case SIR_DATA_OVERRUN: 616859252Sgroudier if (cp) { 616959252Sgroudier OUTONB (HF_PRT, HF_EXT_ERR); 617059252Sgroudier cp->xerr_status |= XE_EXTRA_DATA; 617159252Sgroudier cp->extra_bytes += INL (nc_scratcha); 617259252Sgroudier } 617359252Sgroudier goto out; 617459252Sgroudier /* 617559252Sgroudier * The device switched to an illegal phase (4/5). 617659252Sgroudier */ 617759252Sgroudier case SIR_BAD_PHASE: 617859252Sgroudier if (cp) { 617959252Sgroudier OUTONB (HF_PRT, HF_EXT_ERR); 618059252Sgroudier cp->xerr_status |= XE_BAD_PHASE; 618159252Sgroudier } 618259252Sgroudier goto out; 618359252Sgroudier /* 618453790Sobrien * We received a message. 618553790Sobrien */ 618653790Sobrien case SIR_MSG_RECEIVED: 618753790Sobrien if (!cp) 618853790Sobrien goto out_stuck; 618953790Sobrien switch (np->msgin [0]) { 619053790Sobrien /* 619153790Sobrien * We received an extended message. 6192178466Smarius * We handle MODIFY DATA POINTER, SDTR, WDTR 619353790Sobrien * and reject all other extended messages. 619453790Sobrien */ 619553790Sobrien case M_EXTENDED: 619653790Sobrien switch (np->msgin [2]) { 619753790Sobrien case M_X_MODIFY_DP: 619853790Sobrien if (DEBUG_FLAGS & DEBUG_POINTER) 619953790Sobrien sym_print_msg(cp,"modify DP",np->msgin); 6200178466Smarius tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + 620153790Sobrien (np->msgin[5]<<8) + (np->msgin[6]); 6202251402Smarius sym_modify_dp(np, cp, tmp); 620353790Sobrien return; 620453790Sobrien case M_X_SYNC_REQ: 620553790Sobrien sym_sync_nego(np, tp, cp); 620653790Sobrien return; 620753790Sobrien case M_X_PPR_REQ: 620853790Sobrien sym_ppr_nego(np, tp, cp); 620953790Sobrien return; 621053790Sobrien case M_X_WIDE_REQ: 621153790Sobrien sym_wide_nego(np, tp, cp); 621253790Sobrien return; 621353790Sobrien default: 621453790Sobrien goto out_reject; 621553790Sobrien } 621653790Sobrien break; 621753790Sobrien /* 621853790Sobrien * We received a 1/2 byte message not handled from SCRIPTS. 6219178466Smarius * We are only expecting MESSAGE REJECT and IGNORE WIDE 6220178466Smarius * RESIDUE messages that haven't been anticipated by 6221178466Smarius * SCRIPTS on SWIDE full condition. Unanticipated IGNORE 622253790Sobrien * WIDE RESIDUE messages are aliased as MODIFY DP (-1). 622353790Sobrien */ 622453790Sobrien case M_IGN_RESIDUE: 622553790Sobrien if (DEBUG_FLAGS & DEBUG_POINTER) 622653790Sobrien sym_print_msg(cp,"ign wide residue", np->msgin); 6227251402Smarius sym_modify_dp(np, cp, -1); 622853790Sobrien return; 622953790Sobrien case M_REJECT: 623053790Sobrien if (INB (HS_PRT) == HS_NEGOTIATE) 623153790Sobrien sym_nego_rejected(np, tp, cp); 623253790Sobrien else { 623353790Sobrien PRINT_ADDR(cp); 623453790Sobrien printf ("M_REJECT received (%x:%x).\n", 623553790Sobrien scr_to_cpu(np->lastmsg), np->msgout[0]); 623653790Sobrien } 623753790Sobrien goto out_clrack; 623853790Sobrien break; 623953790Sobrien default: 624053790Sobrien goto out_reject; 624153790Sobrien } 624253790Sobrien break; 624353790Sobrien /* 624453790Sobrien * We received an unknown message. 624553790Sobrien * Ignore all MSG IN phases and reject it. 624653790Sobrien */ 624753790Sobrien case SIR_MSG_WEIRD: 624853790Sobrien sym_print_msg(cp, "WEIRD message received", np->msgin); 624961429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_weird)); 625053790Sobrien return; 625153790Sobrien /* 625253790Sobrien * Negotiation failed. 625353790Sobrien * Target does not send us the reply. 625453790Sobrien * Remove the HS_NEGOTIATE status. 625553790Sobrien */ 625653790Sobrien case SIR_NEGO_FAILED: 625753790Sobrien OUTB (HS_PRT, HS_BUSY); 625853790Sobrien /* 625953790Sobrien * Negotiation failed. 626053790Sobrien * Target does not want answer message. 626153790Sobrien */ 626253790Sobrien case SIR_NEGO_PROTO: 626353790Sobrien sym_nego_default(np, tp, cp); 626453790Sobrien goto out; 626553790Sobrien }; 626653790Sobrien 626753790Sobrienout: 626861429Sgroudier OUTONB_STD (); 626953790Sobrien return; 627053790Sobrienout_reject: 627161429Sgroudier OUTL_DSP (SCRIPTB_BA (np, msg_bad)); 627253790Sobrien return; 627353790Sobrienout_clrack: 627461429Sgroudier OUTL_DSP (SCRIPTA_BA (np, clrack)); 627553790Sobrien return; 627653790Sobrienout_stuck: 627792732Speter return; 627853790Sobrien} 627953790Sobrien 628053790Sobrien/* 628153790Sobrien * Acquire a control block 628253790Sobrien */ 628353790Sobrienstatic ccb_p sym_get_ccb (hcb_p np, u_char tn, u_char ln, u_char tag_order) 628453790Sobrien{ 628553790Sobrien tcb_p tp = &np->target[tn]; 6286251402Smarius lcb_p lp = sym_lp(tp, ln); 628753790Sobrien u_short tag = NO_TAG; 628853790Sobrien SYM_QUEHEAD *qp; 6289178466Smarius ccb_p cp = (ccb_p) NULL; 629053790Sobrien 629153790Sobrien /* 629253790Sobrien * Look for a free CCB 629353790Sobrien */ 629453790Sobrien if (sym_que_empty(&np->free_ccbq)) 6295178468Smarius goto out; 629653790Sobrien qp = sym_remque_head(&np->free_ccbq); 629753790Sobrien if (!qp) 629853790Sobrien goto out; 629953790Sobrien cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 630053790Sobrien 630153790Sobrien /* 630253790Sobrien * If the LCB is not yet available and the LUN 630353790Sobrien * has been probed ok, try to allocate the LCB. 630453790Sobrien */ 630553790Sobrien if (!lp && sym_is_bit(tp->lun_map, ln)) { 630653790Sobrien lp = sym_alloc_lcb(np, tn, ln); 630753790Sobrien if (!lp) 630853790Sobrien goto out_free; 630953790Sobrien } 631053790Sobrien 631153790Sobrien /* 6312178466Smarius * If the LCB is not available here, then the 6313178466Smarius * logical unit is not yet discovered. For those 6314178466Smarius * ones only accept 1 SCSI IO per logical unit, 631553790Sobrien * since we cannot allow disconnections. 631653790Sobrien */ 631753790Sobrien if (!lp) { 631853790Sobrien if (!sym_is_bit(tp->busy0_map, ln)) 631953790Sobrien sym_set_bit(tp->busy0_map, ln); 632053790Sobrien else 632153790Sobrien goto out_free; 632253790Sobrien } else { 632353790Sobrien /* 632453790Sobrien * If we have been asked for a tagged command. 632553790Sobrien */ 632653790Sobrien if (tag_order) { 632753790Sobrien /* 632853790Sobrien * Debugging purpose. 632953790Sobrien */ 633053790Sobrien assert(lp->busy_itl == 0); 633153790Sobrien /* 633253790Sobrien * Allocate resources for tags if not yet. 633353790Sobrien */ 633453790Sobrien if (!lp->cb_tags) { 633553790Sobrien sym_alloc_lcb_tags(np, tn, ln); 633653790Sobrien if (!lp->cb_tags) 633753790Sobrien goto out_free; 633853790Sobrien } 633953790Sobrien /* 634053790Sobrien * Get a tag for this SCSI IO and set up 6341178466Smarius * the CCB bus address for reselection, 634253790Sobrien * and count it for this LUN. 634355300Sgroudier * Toggle reselect path to tagged. 634453790Sobrien */ 634554690Sobrien if (lp->busy_itlq < SYM_CONF_MAX_TASK) { 634653790Sobrien tag = lp->cb_tags[lp->ia_tag]; 634754690Sobrien if (++lp->ia_tag == SYM_CONF_MAX_TASK) 634853790Sobrien lp->ia_tag = 0; 634953790Sobrien lp->itlq_tbl[tag] = cpu_to_scr(cp->ccb_ba); 635053790Sobrien ++lp->busy_itlq; 635159743Sgroudier lp->head.resel_sa = 635259292Sgroudier cpu_to_scr(SCRIPTA_BA (np, resel_tag)); 635353790Sobrien } 635453790Sobrien else 635553790Sobrien goto out_free; 635653790Sobrien } 635753790Sobrien /* 635853790Sobrien * This command will not be tagged. 6359178466Smarius * If we already have either a tagged or untagged 636053790Sobrien * one, refuse to overlap this untagged one. 636153790Sobrien */ 636253790Sobrien else { 636353790Sobrien /* 636453790Sobrien * Debugging purpose. 636553790Sobrien */ 636653790Sobrien assert(lp->busy_itl == 0 && lp->busy_itlq == 0); 636753790Sobrien /* 636853790Sobrien * Count this nexus for this LUN. 636953790Sobrien * Set up the CCB bus address for reselection. 637053790Sobrien * Toggle reselect path to untagged. 637153790Sobrien */ 637253790Sobrien if (++lp->busy_itl == 1) { 637359743Sgroudier lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba); 637459743Sgroudier lp->head.resel_sa = 637559743Sgroudier cpu_to_scr(SCRIPTA_BA (np, resel_no_tag)); 637653790Sobrien } 637753790Sobrien else 637853790Sobrien goto out_free; 637953790Sobrien } 638053790Sobrien } 638153790Sobrien /* 638253790Sobrien * Put the CCB into the busy queue. 638353790Sobrien */ 638453790Sobrien sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); 638553790Sobrien 638653790Sobrien /* 638753790Sobrien * Remember all informations needed to free this CCB. 638853790Sobrien */ 638953790Sobrien cp->to_abort = 0; 639053790Sobrien cp->tag = tag; 639153790Sobrien cp->target = tn; 639253790Sobrien cp->lun = ln; 639353790Sobrien 639453790Sobrien if (DEBUG_FLAGS & DEBUG_TAGS) { 639553790Sobrien PRINT_LUN(np, tn, ln); 639653790Sobrien printf ("ccb @%p using tag %d.\n", cp, tag); 639753790Sobrien } 639853790Sobrien 639953790Sobrienout: 640053790Sobrien return cp; 640153790Sobrienout_free: 640253790Sobrien sym_insque_head(&cp->link_ccbq, &np->free_ccbq); 6403178466Smarius return NULL; 640453790Sobrien} 640553790Sobrien 640653790Sobrien/* 640753790Sobrien * Release one control block 640853790Sobrien */ 6409251402Smariusstatic void sym_free_ccb(hcb_p np, ccb_p cp) 641053790Sobrien{ 641153790Sobrien tcb_p tp = &np->target[cp->target]; 6412251402Smarius lcb_p lp = sym_lp(tp, cp->lun); 641353790Sobrien 641453790Sobrien if (DEBUG_FLAGS & DEBUG_TAGS) { 641553790Sobrien PRINT_LUN(np, cp->target, cp->lun); 641653790Sobrien printf ("ccb @%p freeing tag %d.\n", cp, cp->tag); 641753790Sobrien } 641853790Sobrien 641953790Sobrien /* 642053790Sobrien * If LCB available, 642153790Sobrien */ 642253790Sobrien if (lp) { 642353790Sobrien /* 6424178466Smarius * If tagged, release the tag, set the relect path 642553790Sobrien */ 642653790Sobrien if (cp->tag != NO_TAG) { 642753790Sobrien /* 642853790Sobrien * Free the tag value. 642953790Sobrien */ 643053790Sobrien lp->cb_tags[lp->if_tag] = cp->tag; 643154690Sobrien if (++lp->if_tag == SYM_CONF_MAX_TASK) 643253790Sobrien lp->if_tag = 0; 643353790Sobrien /* 6434178466Smarius * Make the reselect path invalid, 643553790Sobrien * and uncount this CCB. 643653790Sobrien */ 643753790Sobrien lp->itlq_tbl[cp->tag] = cpu_to_scr(np->bad_itlq_ba); 643853790Sobrien --lp->busy_itlq; 643953790Sobrien } else { /* Untagged */ 644053790Sobrien /* 6441178466Smarius * Make the reselect path invalid, 644253790Sobrien * and uncount this CCB. 644353790Sobrien */ 644459743Sgroudier lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba); 644553790Sobrien --lp->busy_itl; 644653790Sobrien } 644753790Sobrien /* 644853790Sobrien * If no JOB active, make the LUN reselect path invalid. 644953790Sobrien */ 645053790Sobrien if (lp->busy_itlq == 0 && lp->busy_itl == 0) 645159743Sgroudier lp->head.resel_sa = 645259292Sgroudier cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun)); 645353790Sobrien } 645453790Sobrien /* 645553790Sobrien * Otherwise, we only accept 1 IO per LUN. 645653790Sobrien * Clear the bit that keeps track of this IO. 645753790Sobrien */ 645853790Sobrien else 645953790Sobrien sym_clr_bit(tp->busy0_map, cp->lun); 646053790Sobrien 646153790Sobrien /* 6462178466Smarius * We donnot queue more than 1 ccb per target 6463178466Smarius * with negotiation at any time. If this ccb was 646453790Sobrien * used for negotiation, clear this info in the tcb. 646553790Sobrien */ 646653790Sobrien if (cp == tp->nego_cp) 6467178466Smarius tp->nego_cp = NULL; 646853790Sobrien 646954690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 647053790Sobrien /* 647153790Sobrien * If we just complete the last queued CCB, 647253790Sobrien * clear this info that is no longer relevant. 647353790Sobrien */ 647453790Sobrien if (cp == np->last_cp) 6475178466Smarius np->last_cp = NULL; 647653790Sobrien#endif 647758927Sgroudier 647853790Sobrien /* 647958927Sgroudier * Unmap user data from DMA map if needed. 648058927Sgroudier */ 648158927Sgroudier if (cp->dmamapped) { 648258927Sgroudier bus_dmamap_unload(np->data_dmat, cp->dmamap); 648358927Sgroudier cp->dmamapped = 0; 648458927Sgroudier } 648558927Sgroudier 648658927Sgroudier /* 648753790Sobrien * Make this CCB available. 648853790Sobrien */ 6489178466Smarius cp->cam_ccb = NULL; 649053790Sobrien cp->host_status = HS_IDLE; 649153790Sobrien sym_remque(&cp->link_ccbq); 649253790Sobrien sym_insque_head(&cp->link_ccbq, &np->free_ccbq); 649353790Sobrien} 649453790Sobrien 649553790Sobrien/* 649653790Sobrien * Allocate a CCB from memory and initialize its fixed part. 649753790Sobrien */ 649853790Sobrienstatic ccb_p sym_alloc_ccb(hcb_p np) 649953790Sobrien{ 6500178466Smarius ccb_p cp = NULL; 650153790Sobrien int hcode; 650253790Sobrien 6503178468Smarius SYM_LOCK_ASSERT(MA_NOTOWNED); 6504178468Smarius 650553790Sobrien /* 6506178466Smarius * Prevent from allocating more CCBs than we can 650753790Sobrien * queue to the controller. 650853790Sobrien */ 650954690Sobrien if (np->actccbs >= SYM_CONF_MAX_START) 6510178466Smarius return NULL; 651153790Sobrien 651253790Sobrien /* 651353790Sobrien * Allocate memory for this CCB. 651453790Sobrien */ 651558927Sgroudier cp = sym_calloc_dma(sizeof(struct sym_ccb), "CCB"); 651653790Sobrien if (!cp) 6517178468Smarius return NULL; 651853790Sobrien 651953790Sobrien /* 652058927Sgroudier * Allocate a bounce buffer for sense data. 652158927Sgroudier */ 652258927Sgroudier cp->sns_bbuf = sym_calloc_dma(SYM_SNS_BBUF_LEN, "SNS_BBUF"); 652358927Sgroudier if (!cp->sns_bbuf) 652458927Sgroudier goto out_free; 652558927Sgroudier 652658927Sgroudier /* 652758927Sgroudier * Allocate a map for the DMA of user data. 652858927Sgroudier */ 652958927Sgroudier if (bus_dmamap_create(np->data_dmat, 0, &cp->dmamap)) 653058927Sgroudier goto out_free; 653158927Sgroudier /* 653253790Sobrien * Count it. 653353790Sobrien */ 653453790Sobrien np->actccbs++; 653553790Sobrien 653653790Sobrien /* 6537178468Smarius * Initialize the callout. 6538178468Smarius */ 6539178468Smarius callout_init(&cp->ch, 1); 6540178468Smarius 6541178468Smarius /* 654253790Sobrien * Compute the bus address of this ccb. 654353790Sobrien */ 654453790Sobrien cp->ccb_ba = vtobus(cp); 654553790Sobrien 654653790Sobrien /* 654753790Sobrien * Insert this ccb into the hashed list. 654853790Sobrien */ 654953790Sobrien hcode = CCB_HASH_CODE(cp->ccb_ba); 655053790Sobrien cp->link_ccbh = np->ccbh[hcode]; 655153790Sobrien np->ccbh[hcode] = cp; 655253790Sobrien 655353790Sobrien /* 6554178466Smarius * Initialize the start and restart actions. 655553790Sobrien */ 655659743Sgroudier cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 655759743Sgroudier cp->phys.head.go.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l)); 655853790Sobrien 655953790Sobrien /* 656053790Sobrien * Initilialyze some other fields. 656153790Sobrien */ 656258927Sgroudier cp->phys.smsg_ext.addr = cpu_to_scr(HCB_BA(np, msgin[2])); 656353790Sobrien 656453790Sobrien /* 656555300Sgroudier * Chain into free ccb queue. 656653790Sobrien */ 656753790Sobrien sym_insque_head(&cp->link_ccbq, &np->free_ccbq); 656853790Sobrien 656953790Sobrien return cp; 657058927Sgroudierout_free: 6571178468Smarius if (cp->sns_bbuf) 6572178468Smarius sym_mfree_dma(cp->sns_bbuf, SYM_SNS_BBUF_LEN, "SNS_BBUF"); 6573178468Smarius sym_mfree_dma(cp, sizeof(*cp), "CCB"); 6574178466Smarius return NULL; 657553790Sobrien} 657653790Sobrien 657753790Sobrien/* 657853790Sobrien * Look up a CCB from a DSA value. 657953790Sobrien */ 658061051Sgroudierstatic ccb_p sym_ccb_from_dsa(hcb_p np, u32 dsa) 658153790Sobrien{ 658253790Sobrien int hcode; 658353790Sobrien ccb_p cp; 658453790Sobrien 658553790Sobrien hcode = CCB_HASH_CODE(dsa); 658653790Sobrien cp = np->ccbh[hcode]; 658753790Sobrien while (cp) { 658853790Sobrien if (cp->ccb_ba == dsa) 658953790Sobrien break; 659053790Sobrien cp = cp->link_ccbh; 659153790Sobrien } 659253790Sobrien 659353790Sobrien return cp; 659453790Sobrien} 659553790Sobrien 659653790Sobrien/* 659753790Sobrien * Lun control block allocation and initialization. 659853790Sobrien */ 659953790Sobrienstatic lcb_p sym_alloc_lcb (hcb_p np, u_char tn, u_char ln) 660053790Sobrien{ 660153790Sobrien tcb_p tp = &np->target[tn]; 6602251402Smarius lcb_p lp = sym_lp(tp, ln); 660353790Sobrien 660453790Sobrien /* 660553790Sobrien * Already done, just return. 660653790Sobrien */ 660753790Sobrien if (lp) 660853790Sobrien return lp; 660953790Sobrien /* 661053790Sobrien * Check against some race. 661153790Sobrien */ 661253790Sobrien assert(!sym_is_bit(tp->busy0_map, ln)); 661353790Sobrien 661453790Sobrien /* 661553790Sobrien * Allocate the LCB bus address array. 661653790Sobrien * Compute the bus address of this table. 661753790Sobrien */ 661853790Sobrien if (ln && !tp->luntbl) { 661953790Sobrien int i; 662053790Sobrien 662158927Sgroudier tp->luntbl = sym_calloc_dma(256, "LUNTBL"); 662253790Sobrien if (!tp->luntbl) 662353790Sobrien goto fail; 662453790Sobrien for (i = 0 ; i < 64 ; i++) 662553790Sobrien tp->luntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa)); 662659743Sgroudier tp->head.luntbl_sa = cpu_to_scr(vtobus(tp->luntbl)); 662753790Sobrien } 662853790Sobrien 662953790Sobrien /* 663053790Sobrien * Allocate the table of pointers for LUN(s) > 0, if needed. 663153790Sobrien */ 663253790Sobrien if (ln && !tp->lunmp) { 663354690Sobrien tp->lunmp = sym_calloc(SYM_CONF_MAX_LUN * sizeof(lcb_p), 663453790Sobrien "LUNMP"); 663553790Sobrien if (!tp->lunmp) 663653790Sobrien goto fail; 663753790Sobrien } 663853790Sobrien 663953790Sobrien /* 664053790Sobrien * Allocate the lcb. 664153790Sobrien * Make it available to the chip. 664253790Sobrien */ 664358927Sgroudier lp = sym_calloc_dma(sizeof(struct sym_lcb), "LCB"); 664453790Sobrien if (!lp) 664553790Sobrien goto fail; 664653790Sobrien if (ln) { 664753790Sobrien tp->lunmp[ln] = lp; 664853790Sobrien tp->luntbl[ln] = cpu_to_scr(vtobus(lp)); 664953790Sobrien } 665053790Sobrien else { 665153790Sobrien tp->lun0p = lp; 665259743Sgroudier tp->head.lun0_sa = cpu_to_scr(vtobus(lp)); 665353790Sobrien } 665453790Sobrien 665553790Sobrien /* 665653790Sobrien * Let the itl task point to error handling. 665753790Sobrien */ 665859743Sgroudier lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba); 665953790Sobrien 666053790Sobrien /* 666153790Sobrien * Set the reselect pattern to our default. :) 666253790Sobrien */ 666359743Sgroudier lp->head.resel_sa = cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun)); 666453790Sobrien 666553790Sobrien /* 666653790Sobrien * Set user capabilities. 666753790Sobrien */ 666853790Sobrien lp->user_flags = tp->usrflags & (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); 666953790Sobrien 667053790Sobrienfail: 667153790Sobrien return lp; 667253790Sobrien} 667353790Sobrien 667453790Sobrien/* 667553790Sobrien * Allocate LCB resources for tagged command queuing. 667653790Sobrien */ 667753790Sobrienstatic void sym_alloc_lcb_tags (hcb_p np, u_char tn, u_char ln) 667853790Sobrien{ 667953790Sobrien tcb_p tp = &np->target[tn]; 6680251402Smarius lcb_p lp = sym_lp(tp, ln); 668153790Sobrien int i; 668253790Sobrien 668353790Sobrien /* 668453790Sobrien * If LCB not available, try to allocate it. 668553790Sobrien */ 668653790Sobrien if (!lp && !(lp = sym_alloc_lcb(np, tn, ln))) 6687178466Smarius return; 668853790Sobrien 668953790Sobrien /* 6690178466Smarius * Allocate the task table and and the tag allocation 669153790Sobrien * circular buffer. We want both or none. 669253790Sobrien */ 669358927Sgroudier lp->itlq_tbl = sym_calloc_dma(SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); 669453790Sobrien if (!lp->itlq_tbl) 6695178466Smarius return; 669654690Sobrien lp->cb_tags = sym_calloc(SYM_CONF_MAX_TASK, "CB_TAGS"); 669753790Sobrien if (!lp->cb_tags) { 669858927Sgroudier sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); 669953790Sobrien lp->itlq_tbl = 0; 6700178466Smarius return; 670153790Sobrien } 670253790Sobrien 670353790Sobrien /* 670453790Sobrien * Initialize the task table with invalid entries. 670553790Sobrien */ 670654690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++) 670753790Sobrien lp->itlq_tbl[i] = cpu_to_scr(np->notask_ba); 670853790Sobrien 670953790Sobrien /* 671053790Sobrien * Fill up the tag buffer with tag numbers. 671153790Sobrien */ 671254690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++) 671353790Sobrien lp->cb_tags[i] = i; 671453790Sobrien 671553790Sobrien /* 6716178466Smarius * Make the task table available to SCRIPTS, 671753790Sobrien * And accept tagged commands now. 671853790Sobrien */ 671959743Sgroudier lp->head.itlq_tbl_sa = cpu_to_scr(vtobus(lp->itlq_tbl)); 672053790Sobrien} 672153790Sobrien 672253790Sobrien/* 672353790Sobrien * Test the pci bus snoop logic :-( 672453790Sobrien * 672553790Sobrien * Has to be called with interrupts disabled. 672653790Sobrien */ 672754690Sobrien#ifndef SYM_CONF_IOMAPPED 672853790Sobrienstatic int sym_regtest (hcb_p np) 672953790Sobrien{ 673053790Sobrien register volatile u32 data; 673153790Sobrien /* 673253790Sobrien * chip registers may NOT be cached. 673353790Sobrien * write 0xffffffff to a read only register area, 673453790Sobrien * and try to read it back. 673553790Sobrien */ 673653790Sobrien data = 0xffffffff; 673753790Sobrien OUTL_OFF(offsetof(struct sym_reg, nc_dstat), data); 673853790Sobrien data = INL_OFF(offsetof(struct sym_reg, nc_dstat)); 673953790Sobrien#if 1 674053790Sobrien if (data == 0xffffffff) { 674153790Sobrien#else 674253790Sobrien if ((data & 0xe2f0fffd) != 0x02000080) { 674353790Sobrien#endif 674453790Sobrien printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", 674553790Sobrien (unsigned) data); 674653790Sobrien return (0x10); 674753790Sobrien }; 674853790Sobrien return (0); 674953790Sobrien} 675053790Sobrien#endif 675153790Sobrien 675253790Sobrienstatic int sym_snooptest (hcb_p np) 675353790Sobrien{ 675465404Sgroudier u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat; 675553790Sobrien int i, err=0; 675654690Sobrien#ifndef SYM_CONF_IOMAPPED 675753790Sobrien err |= sym_regtest (np); 675853790Sobrien if (err) return (err); 675953790Sobrien#endif 676065404Sgroudierrestart_test: 676153790Sobrien /* 6762178466Smarius * Enable Master Parity Checking as we intend 676365404Sgroudier * to enable it for normal operations. 676465404Sgroudier */ 676565404Sgroudier OUTB (nc_ctest4, (np->rv_ctest4 & MPEE)); 676665404Sgroudier /* 676753790Sobrien * init 676853790Sobrien */ 676959292Sgroudier pc = SCRIPTB0_BA (np, snooptest); 677053790Sobrien host_wr = 1; 677153790Sobrien sym_wr = 2; 677253790Sobrien /* 677353790Sobrien * Set memory and register. 677453790Sobrien */ 677553790Sobrien np->cache = cpu_to_scr(host_wr); 677653790Sobrien OUTL (nc_temp, sym_wr); 677753790Sobrien /* 677853790Sobrien * Start script (exchange values) 677953790Sobrien */ 678058927Sgroudier OUTL (nc_dsa, np->hcb_ba); 678161429Sgroudier OUTL_DSP (pc); 678253790Sobrien /* 678353790Sobrien * Wait 'til done (with timeout) 678453790Sobrien */ 678553790Sobrien for (i=0; i<SYM_SNOOP_TIMEOUT; i++) 678653790Sobrien if (INB(nc_istat) & (INTF|SIP|DIP)) 678753790Sobrien break; 678865404Sgroudier if (i>=SYM_SNOOP_TIMEOUT) { 678965404Sgroudier printf ("CACHE TEST FAILED: timeout.\n"); 679065404Sgroudier return (0x20); 679165404Sgroudier }; 679253790Sobrien /* 679365404Sgroudier * Check for fatal DMA errors. 679465404Sgroudier */ 679565404Sgroudier dstat = INB (nc_dstat); 679665404Sgroudier#if 1 /* Band aiding for broken hardwares that fail PCI parity */ 679765404Sgroudier if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) { 679865404Sgroudier printf ("%s: PCI DATA PARITY ERROR DETECTED - " 679965404Sgroudier "DISABLING MASTER DATA PARITY CHECKING.\n", 680065404Sgroudier sym_name(np)); 680165404Sgroudier np->rv_ctest4 &= ~MPEE; 680265404Sgroudier goto restart_test; 680365404Sgroudier } 680465404Sgroudier#endif 680565404Sgroudier if (dstat & (MDPE|BF|IID)) { 680665404Sgroudier printf ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat); 680765404Sgroudier return (0x80); 680865404Sgroudier } 680965404Sgroudier /* 681053790Sobrien * Save termination position. 681153790Sobrien */ 681253790Sobrien pc = INL (nc_dsp); 681353790Sobrien /* 681453790Sobrien * Read memory and register. 681553790Sobrien */ 681653790Sobrien host_rd = scr_to_cpu(np->cache); 681753790Sobrien sym_rd = INL (nc_scratcha); 681853790Sobrien sym_bk = INL (nc_temp); 681953790Sobrien 682053790Sobrien /* 682153790Sobrien * Check termination position. 682253790Sobrien */ 682359292Sgroudier if (pc != SCRIPTB0_BA (np, snoopend)+8) { 682453790Sobrien printf ("CACHE TEST FAILED: script execution failed.\n"); 6825178466Smarius printf ("start=%08lx, pc=%08lx, end=%08lx\n", 682659292Sgroudier (u_long) SCRIPTB0_BA (np, snooptest), (u_long) pc, 682759292Sgroudier (u_long) SCRIPTB0_BA (np, snoopend) +8); 682853790Sobrien return (0x40); 682953790Sobrien }; 683053790Sobrien /* 683153790Sobrien * Show results. 683253790Sobrien */ 683353790Sobrien if (host_wr != sym_rd) { 683453790Sobrien printf ("CACHE TEST FAILED: host wrote %d, chip read %d.\n", 683553790Sobrien (int) host_wr, (int) sym_rd); 683653790Sobrien err |= 1; 683753790Sobrien }; 683853790Sobrien if (host_rd != sym_wr) { 683953790Sobrien printf ("CACHE TEST FAILED: chip wrote %d, host read %d.\n", 684053790Sobrien (int) sym_wr, (int) host_rd); 684153790Sobrien err |= 2; 684253790Sobrien }; 684353790Sobrien if (sym_bk != sym_wr) { 684453790Sobrien printf ("CACHE TEST FAILED: chip wrote %d, read back %d.\n", 684553790Sobrien (int) sym_wr, (int) sym_bk); 684653790Sobrien err |= 4; 684753790Sobrien }; 684859743Sgroudier 684953790Sobrien return (err); 685053790Sobrien} 685153790Sobrien 685253790Sobrien/* 685353790Sobrien * Determine the chip's clock frequency. 685453790Sobrien * 6855178466Smarius * This is essential for the negotiation of the synchronous 685653790Sobrien * transfer rate. 685753790Sobrien * 685853790Sobrien * Note: we have to return the correct value. 685953790Sobrien * THERE IS NO SAFE DEFAULT VALUE. 686053790Sobrien * 686153790Sobrien * Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. 6862178466Smarius * 53C860 and 53C875 rev. 1 support fast20 transfers but 6863178466Smarius * do not have a clock doubler and so are provided with a 6864178466Smarius * 80 MHz clock. All other fast20 boards incorporate a doubler 686553790Sobrien * and so should be delivered with a 40 MHz clock. 6866178466Smarius * The recent fast40 chips (895/896/895A/1010) use a 40 Mhz base 686753790Sobrien * clock and provide a clock quadrupler (160 Mhz). 686853790Sobrien */ 686953790Sobrien 687053790Sobrien/* 687153790Sobrien * Select SCSI clock frequency 687253790Sobrien */ 687353790Sobrienstatic void sym_selectclock(hcb_p np, u_char scntl3) 687453790Sobrien{ 687553790Sobrien /* 687653790Sobrien * If multiplier not present or not selected, leave here. 687753790Sobrien */ 687853790Sobrien if (np->multiplier <= 1) { 687953790Sobrien OUTB(nc_scntl3, scntl3); 688053790Sobrien return; 688153790Sobrien } 688253790Sobrien 688353790Sobrien if (sym_verbose >= 2) 688453790Sobrien printf ("%s: enabling clock multiplier\n", sym_name(np)); 688553790Sobrien 688653790Sobrien OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ 688753790Sobrien /* 688853790Sobrien * Wait for the LCKFRQ bit to be set if supported by the chip. 688953790Sobrien * Otherwise wait 20 micro-seconds. 689053790Sobrien */ 689153790Sobrien if (np->features & FE_LCKFRQ) { 689253790Sobrien int i = 20; 689353790Sobrien while (!(INB(nc_stest4) & LCKFRQ) && --i > 0) 689453790Sobrien UDELAY (20); 689553790Sobrien if (!i) 689653790Sobrien printf("%s: the chip cannot lock the frequency\n", 689753790Sobrien sym_name(np)); 689853790Sobrien } else 689953790Sobrien UDELAY (20); 690053790Sobrien OUTB(nc_stest3, HSC); /* Halt the scsi clock */ 690153790Sobrien OUTB(nc_scntl3, scntl3); 690253790Sobrien OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ 690353790Sobrien OUTB(nc_stest3, 0x00); /* Restart scsi clock */ 690453790Sobrien} 690553790Sobrien 690653790Sobrien/* 690753790Sobrien * calculate SCSI clock frequency (in KHz) 690853790Sobrien */ 690953790Sobrienstatic unsigned getfreq (hcb_p np, int gen) 691053790Sobrien{ 691153790Sobrien unsigned int ms = 0; 691253790Sobrien unsigned int f; 691353790Sobrien 691453790Sobrien /* 6915178466Smarius * Measure GEN timer delay in order 691653790Sobrien * to calculate SCSI clock frequency 691753790Sobrien * 691853790Sobrien * This code will never execute too 6919178466Smarius * many loop iterations (if DELAY is 692053790Sobrien * reasonably correct). It could get 692153790Sobrien * too low a delay (too high a freq.) 6922178466Smarius * if the CPU is slow executing the 692353790Sobrien * loop for some reason (an NMI, for 692453790Sobrien * example). For this reason we will 6925178466Smarius * if multiple measurements are to be 6926178466Smarius * performed trust the higher delay 692753790Sobrien * (lower frequency returned). 692853790Sobrien */ 692953790Sobrien OUTW (nc_sien , 0); /* mask all scsi interrupts */ 693053790Sobrien (void) INW (nc_sist); /* clear pending scsi interrupt */ 693153790Sobrien OUTB (nc_dien , 0); /* mask all dma interrupts */ 693253790Sobrien (void) INW (nc_sist); /* another one, just to be sure :) */ 693353790Sobrien OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */ 693453790Sobrien OUTB (nc_stime1, 0); /* disable general purpose timer */ 693553790Sobrien OUTB (nc_stime1, gen); /* set to nominal delay of 1<<gen * 125us */ 693653790Sobrien while (!(INW(nc_sist) & GEN) && ms++ < 100000) 693753790Sobrien UDELAY (1000); /* count ms */ 693853790Sobrien OUTB (nc_stime1, 0); /* disable general purpose timer */ 693953790Sobrien /* 694053790Sobrien * set prescaler to divide by whatever 0 means 694153790Sobrien * 0 ought to choose divide by 2, but appears 694253790Sobrien * to set divide by 3.5 mode in my 53c810 ... 694353790Sobrien */ 694453790Sobrien OUTB (nc_scntl3, 0); 694553790Sobrien 694653790Sobrien /* 6947178466Smarius * adjust for prescaler, and convert into KHz 694853790Sobrien */ 694953790Sobrien f = ms ? ((1 << gen) * 4340) / ms : 0; 695053790Sobrien 695153790Sobrien if (sym_verbose >= 2) 695253790Sobrien printf ("%s: Delay (GEN=%d): %u msec, %u KHz\n", 695353790Sobrien sym_name(np), gen, ms, f); 695453790Sobrien 695553790Sobrien return f; 695653790Sobrien} 695753790Sobrien 695853790Sobrienstatic unsigned sym_getfreq (hcb_p np) 695953790Sobrien{ 696053790Sobrien u_int f1, f2; 696153790Sobrien int gen = 11; 696253790Sobrien 696353790Sobrien (void) getfreq (np, gen); /* throw away first result */ 696453790Sobrien f1 = getfreq (np, gen); 696553790Sobrien f2 = getfreq (np, gen); 696653790Sobrien if (f1 > f2) f1 = f2; /* trust lower result */ 696753790Sobrien return f1; 696853790Sobrien} 696953790Sobrien 697053790Sobrien/* 697153790Sobrien * Get/probe chip SCSI clock frequency 697253790Sobrien */ 697353790Sobrienstatic void sym_getclock (hcb_p np, int mult) 697453790Sobrien{ 697553796Sobrien unsigned char scntl3 = np->sv_scntl3; 697653796Sobrien unsigned char stest1 = np->sv_stest1; 697753790Sobrien unsigned f1; 697853790Sobrien 697953790Sobrien /* 698053790Sobrien * For the C10 core, assume 40 MHz. 698153790Sobrien */ 698253790Sobrien if (np->features & FE_C10) { 698353790Sobrien np->multiplier = mult; 698453790Sobrien np->clock_khz = 40000 * mult; 698553790Sobrien return; 698653790Sobrien } 698753790Sobrien 698853790Sobrien np->multiplier = 1; 698953790Sobrien f1 = 40000; 699053790Sobrien /* 699153790Sobrien * True with 875/895/896/895A with clock multiplier selected 699253790Sobrien */ 699353790Sobrien if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { 699453790Sobrien if (sym_verbose >= 2) 699553790Sobrien printf ("%s: clock multiplier found\n", sym_name(np)); 699653790Sobrien np->multiplier = mult; 699753790Sobrien } 699853790Sobrien 699953790Sobrien /* 700053790Sobrien * If multiplier not found or scntl3 not 7,5,3, 700153790Sobrien * reset chip and get frequency from general purpose timer. 700253790Sobrien * Otherwise trust scntl3 BIOS setting. 700353790Sobrien */ 700453790Sobrien if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { 700553790Sobrien OUTB (nc_stest1, 0); /* make sure doubler is OFF */ 700653790Sobrien f1 = sym_getfreq (np); 700753790Sobrien 700853790Sobrien if (sym_verbose) 700953790Sobrien printf ("%s: chip clock is %uKHz\n", sym_name(np), f1); 701053790Sobrien 701153790Sobrien if (f1 < 45000) f1 = 40000; 701253790Sobrien else if (f1 < 55000) f1 = 50000; 701353790Sobrien else f1 = 80000; 701453790Sobrien 701553790Sobrien if (f1 < 80000 && mult > 1) { 701653790Sobrien if (sym_verbose >= 2) 701753790Sobrien printf ("%s: clock multiplier assumed\n", 701853790Sobrien sym_name(np)); 701953790Sobrien np->multiplier = mult; 702053790Sobrien } 702153790Sobrien } else { 702253790Sobrien if ((scntl3 & 7) == 3) f1 = 40000; 702353790Sobrien else if ((scntl3 & 7) == 5) f1 = 80000; 702453790Sobrien else f1 = 160000; 702553790Sobrien 702653790Sobrien f1 /= np->multiplier; 702753790Sobrien } 702853790Sobrien 702953790Sobrien /* 703053790Sobrien * Compute controller synchronous parameters. 703153790Sobrien */ 703253790Sobrien f1 *= np->multiplier; 703353790Sobrien np->clock_khz = f1; 703453790Sobrien} 703553790Sobrien 703653790Sobrien/* 703753790Sobrien * Get/probe PCI clock frequency 703853790Sobrien */ 703953790Sobrienstatic int sym_getpciclock (hcb_p np) 704053790Sobrien{ 704161051Sgroudier int f = 0; 704253790Sobrien 704361051Sgroudier /* 704461051Sgroudier * For the C1010-33, this doesn't work. 7045178466Smarius * For the C1010-66, this will be tested when I'll have 704661051Sgroudier * such a beast to play with. 704761051Sgroudier */ 704861051Sgroudier if (!(np->features & FE_C10)) { 704953790Sobrien OUTB (nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */ 705053790Sobrien f = (int) sym_getfreq (np); 705153790Sobrien OUTB (nc_stest1, 0); 705253790Sobrien } 705361051Sgroudier np->pciclk_khz = f; 705461051Sgroudier 705553790Sobrien return f; 705653790Sobrien} 705753790Sobrien 705853790Sobrien/*============= DRIVER ACTION/COMPLETION ====================*/ 705953790Sobrien 706053790Sobrien/* 706153790Sobrien * Print something that tells about extended errors. 706253790Sobrien */ 706353790Sobrienstatic void sym_print_xerr(ccb_p cp, int x_status) 706453790Sobrien{ 706553790Sobrien if (x_status & XE_PARITY_ERR) { 706653790Sobrien PRINT_ADDR(cp); 706753790Sobrien printf ("unrecovered SCSI parity error.\n"); 706853790Sobrien } 706953790Sobrien if (x_status & XE_EXTRA_DATA) { 707053790Sobrien PRINT_ADDR(cp); 707153790Sobrien printf ("extraneous data discarded.\n"); 707253790Sobrien } 707353790Sobrien if (x_status & XE_BAD_PHASE) { 707453790Sobrien PRINT_ADDR(cp); 707553790Sobrien printf ("illegal scsi phase (4/5).\n"); 707653790Sobrien } 707753790Sobrien if (x_status & XE_SODL_UNRUN) { 707853790Sobrien PRINT_ADDR(cp); 707953790Sobrien printf ("ODD transfer in DATA OUT phase.\n"); 708053790Sobrien } 708153790Sobrien if (x_status & XE_SWIDE_OVRUN) { 708253790Sobrien PRINT_ADDR(cp); 708353790Sobrien printf ("ODD transfer in DATA IN phase.\n"); 708453790Sobrien } 708553790Sobrien} 708653790Sobrien 708753790Sobrien/* 7088178466Smarius * Choose the more appropriate CAM status if 708953790Sobrien * the IO encountered an extended error. 709053790Sobrien */ 709153790Sobrienstatic int sym_xerr_cam_status(int cam_status, int x_status) 709253790Sobrien{ 709353790Sobrien if (x_status) { 709453790Sobrien if (x_status & XE_PARITY_ERR) 709553790Sobrien cam_status = CAM_UNCOR_PARITY; 709653790Sobrien else if (x_status &(XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) 709753790Sobrien cam_status = CAM_DATA_RUN_ERR; 709853790Sobrien else if (x_status & XE_BAD_PHASE) 709953790Sobrien cam_status = CAM_REQ_CMP_ERR; 710053790Sobrien else 710153790Sobrien cam_status = CAM_REQ_CMP_ERR; 710253790Sobrien } 710353790Sobrien return cam_status; 710453790Sobrien} 710553790Sobrien 710653790Sobrien/* 7107178466Smarius * Complete execution of a SCSI command with extented 710853790Sobrien * error, SCSI status error, or having been auto-sensed. 710953790Sobrien * 7110178466Smarius * The SCRIPTS processor is not running there, so we 7111178466Smarius * can safely access IO registers and remove JOBs from 711253790Sobrien * the START queue. 7113178466Smarius * SCRATCHA is assumed to have been loaded with STARTPOS 711453790Sobrien * before the SCRIPTS called the C code. 711553790Sobrien */ 711653790Sobrienstatic void sym_complete_error (hcb_p np, ccb_p cp) 711753790Sobrien{ 711853790Sobrien struct ccb_scsiio *csio; 711953790Sobrien u_int cam_status; 7120226095Smarius int i, sense_returned; 712153790Sobrien 7122178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7123178468Smarius 712453790Sobrien /* 712553790Sobrien * Paranoid check. :) 712653790Sobrien */ 712753790Sobrien if (!cp || !cp->cam_ccb) 712853790Sobrien return; 712953790Sobrien 713053790Sobrien if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_RESULT)) { 713153790Sobrien printf ("CCB=%lx STAT=%x/%x/%x DEV=%d/%d\n", (unsigned long)cp, 713253790Sobrien cp->host_status, cp->ssss_status, cp->host_flags, 713353790Sobrien cp->target, cp->lun); 713453790Sobrien MDELAY(100); 713553790Sobrien } 713653790Sobrien 713753790Sobrien /* 713862422Sgroudier * Get CAM command pointer. 713953790Sobrien */ 714053790Sobrien csio = &cp->cam_ccb->csio; 714153790Sobrien 714253790Sobrien /* 714353790Sobrien * Check for extended errors. 714453790Sobrien */ 714553790Sobrien if (cp->xerr_status) { 714653790Sobrien if (sym_verbose) 714753790Sobrien sym_print_xerr(cp, cp->xerr_status); 714853790Sobrien if (cp->host_status == HS_COMPLETE) 714953790Sobrien cp->host_status = HS_COMP_ERR; 715053790Sobrien } 715153790Sobrien 715253790Sobrien /* 715353790Sobrien * Calculate the residual. 715453790Sobrien */ 715553790Sobrien csio->sense_resid = 0; 715653790Sobrien csio->resid = sym_compute_residual(np, cp); 715753790Sobrien 715854690Sobrien if (!SYM_CONF_RESIDUAL_SUPPORT) {/* If user does not want residuals */ 715953790Sobrien csio->resid = 0; /* throw them away. :) */ 716053790Sobrien cp->sv_resid = 0; 716153790Sobrien } 716253790Sobrien 716353790Sobrien if (cp->host_flags & HF_SENSE) { /* Auto sense */ 716453790Sobrien csio->scsi_status = cp->sv_scsi_status; /* Restore status */ 716553790Sobrien csio->sense_resid = csio->resid; /* Swap residuals */ 716653790Sobrien csio->resid = cp->sv_resid; 716753790Sobrien cp->sv_resid = 0; 716853790Sobrien if (sym_verbose && cp->sv_xerr_status) 716953790Sobrien sym_print_xerr(cp, cp->sv_xerr_status); 717053790Sobrien if (cp->host_status == HS_COMPLETE && 717153790Sobrien cp->ssss_status == S_GOOD && 717253790Sobrien cp->xerr_status == 0) { 717353790Sobrien cam_status = sym_xerr_cam_status(CAM_SCSI_STATUS_ERROR, 717453790Sobrien cp->sv_xerr_status); 717553790Sobrien cam_status |= CAM_AUTOSNS_VALID; 717658927Sgroudier /* 7177178466Smarius * Bounce back the sense data to user and 717858927Sgroudier * fix the residual. 717958927Sgroudier */ 7180226095Smarius bzero(&csio->sense_data, sizeof(csio->sense_data)); 7181226095Smarius sense_returned = SYM_SNS_BBUF_LEN - csio->sense_resid; 7182226095Smarius if (sense_returned < csio->sense_len) 7183226095Smarius csio->sense_resid = csio->sense_len - 7184226095Smarius sense_returned; 7185226095Smarius else 7186226095Smarius csio->sense_resid = 0; 718758927Sgroudier bcopy(cp->sns_bbuf, &csio->sense_data, 7188226095Smarius MIN(csio->sense_len, sense_returned)); 718953790Sobrien#if 0 719053790Sobrien /* 7191178466Smarius * If the device reports a UNIT ATTENTION condition 7192178466Smarius * due to a RESET condition, we should consider all 719353790Sobrien * disconnect CCBs for this unit as aborted. 719453790Sobrien */ 719553790Sobrien if (1) { 719653790Sobrien u_char *p; 719758927Sgroudier p = (u_char *) csio->sense_data; 719853790Sobrien if (p[0]==0x70 && p[2]==0x6 && p[12]==0x29) 719953790Sobrien sym_clear_tasks(np, CAM_REQ_ABORTED, 720053790Sobrien cp->target,cp->lun, -1); 720153790Sobrien } 720253790Sobrien#endif 720353790Sobrien } 720453790Sobrien else 720553790Sobrien cam_status = CAM_AUTOSENSE_FAIL; 720653790Sobrien } 720753790Sobrien else if (cp->host_status == HS_COMPLETE) { /* Bad SCSI status */ 720853790Sobrien csio->scsi_status = cp->ssss_status; 720953790Sobrien cam_status = CAM_SCSI_STATUS_ERROR; 721053790Sobrien } 721153790Sobrien else if (cp->host_status == HS_SEL_TIMEOUT) /* Selection timeout */ 721253790Sobrien cam_status = CAM_SEL_TIMEOUT; 721353790Sobrien else if (cp->host_status == HS_UNEXPECTED) /* Unexpected BUS FREE*/ 721453790Sobrien cam_status = CAM_UNEXP_BUSFREE; 721553790Sobrien else { /* Extended error */ 721653790Sobrien if (sym_verbose) { 721753790Sobrien PRINT_ADDR(cp); 721853790Sobrien printf ("COMMAND FAILED (%x %x %x).\n", 721953790Sobrien cp->host_status, cp->ssss_status, 722053790Sobrien cp->xerr_status); 722153790Sobrien } 722253790Sobrien csio->scsi_status = cp->ssss_status; 722353790Sobrien /* 722453790Sobrien * Set the most appropriate value for CAM status. 722553790Sobrien */ 722653790Sobrien cam_status = sym_xerr_cam_status(CAM_REQ_CMP_ERR, 722753790Sobrien cp->xerr_status); 722853790Sobrien } 722953790Sobrien 723053790Sobrien /* 7231178466Smarius * Dequeue all queued CCBs for that device 723253790Sobrien * not yet started by SCRIPTS. 723353790Sobrien */ 723458927Sgroudier i = (INL (nc_scratcha) - np->squeue_ba) / 4; 723553790Sobrien (void) sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); 723653790Sobrien 723753790Sobrien /* 723853790Sobrien * Restart the SCRIPTS processor. 723953790Sobrien */ 724061429Sgroudier OUTL_DSP (SCRIPTA_BA (np, start)); 724153790Sobrien 724253790Sobrien /* 724358927Sgroudier * Synchronize DMA map if needed. 724458927Sgroudier */ 724558927Sgroudier if (cp->dmamapped) { 724658927Sgroudier bus_dmamap_sync(np->data_dmat, cp->dmamap, 7247178466Smarius (cp->dmamapped == SYM_DMA_READ ? 724858927Sgroudier BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE)); 724958927Sgroudier } 725058927Sgroudier /* 725153790Sobrien * Add this one to the COMP queue. 7252178466Smarius * Complete all those commands with either error 725353790Sobrien * or requeue condition. 725453790Sobrien */ 725553790Sobrien sym_set_cam_status((union ccb *) csio, cam_status); 725653790Sobrien sym_remque(&cp->link_ccbq); 725753790Sobrien sym_insque_head(&cp->link_ccbq, &np->comp_ccbq); 725853790Sobrien sym_flush_comp_queue(np, 0); 725953790Sobrien} 726053790Sobrien 726153790Sobrien/* 726253790Sobrien * Complete execution of a successful SCSI command. 726353790Sobrien * 7264178466Smarius * Only successful commands go to the DONE queue, 7265178466Smarius * since we need to have the SCRIPTS processor 726653790Sobrien * stopped on any error condition. 7267178466Smarius * The SCRIPTS processor is running while we are 726853790Sobrien * completing successful commands. 726953790Sobrien */ 727053790Sobrienstatic void sym_complete_ok (hcb_p np, ccb_p cp) 727153790Sobrien{ 727253790Sobrien struct ccb_scsiio *csio; 727353790Sobrien tcb_p tp; 727453790Sobrien lcb_p lp; 727553790Sobrien 7276178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7277178468Smarius 727853790Sobrien /* 727953790Sobrien * Paranoid check. :) 728053790Sobrien */ 728153790Sobrien if (!cp || !cp->cam_ccb) 728253790Sobrien return; 728353790Sobrien assert (cp->host_status == HS_COMPLETE); 728453790Sobrien 728553790Sobrien /* 728653790Sobrien * Get command, target and lun pointers. 728753790Sobrien */ 728853790Sobrien csio = &cp->cam_ccb->csio; 728953790Sobrien tp = &np->target[cp->target]; 7290251402Smarius lp = sym_lp(tp, cp->lun); 729153790Sobrien 729253790Sobrien /* 729353790Sobrien * Assume device discovered on first success. 729453790Sobrien */ 729553790Sobrien if (!lp) 729653790Sobrien sym_set_bit(tp->lun_map, cp->lun); 729753790Sobrien 729853790Sobrien /* 729953790Sobrien * If all data have been transferred, given than no 730053790Sobrien * extended error did occur, there is no residual. 730153790Sobrien */ 730253790Sobrien csio->resid = 0; 730359743Sgroudier if (cp->phys.head.lastp != cp->phys.head.goalp) 730453790Sobrien csio->resid = sym_compute_residual(np, cp); 730553790Sobrien 730653790Sobrien /* 7307178466Smarius * Wrong transfer residuals may be worse than just always 7308178466Smarius * returning zero. User can disable this feature from 730953790Sobrien * sym_conf.h. Residual support is enabled by default. 731053790Sobrien */ 731154690Sobrien if (!SYM_CONF_RESIDUAL_SUPPORT) 731253790Sobrien csio->resid = 0; 731353790Sobrien 731453790Sobrien /* 731558927Sgroudier * Synchronize DMA map if needed. 731658927Sgroudier */ 731758927Sgroudier if (cp->dmamapped) { 731858927Sgroudier bus_dmamap_sync(np->data_dmat, cp->dmamap, 7319178466Smarius (cp->dmamapped == SYM_DMA_READ ? 732058927Sgroudier BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE)); 732158927Sgroudier } 732258927Sgroudier /* 732353790Sobrien * Set status and complete the command. 732453790Sobrien */ 732553790Sobrien csio->scsi_status = cp->ssss_status; 732653790Sobrien sym_set_cam_status((union ccb *) csio, CAM_REQ_CMP); 7327178468Smarius sym_xpt_done(np, (union ccb *) csio, cp); 7328178468Smarius sym_free_ccb(np, cp); 732953790Sobrien} 733053790Sobrien 733153790Sobrien/* 7332178468Smarius * Our callout handler 733353790Sobrien */ 7334178468Smariusstatic void sym_callout(void *arg) 733553790Sobrien{ 733653790Sobrien union ccb *ccb = (union ccb *) arg; 733753790Sobrien hcb_p np = ccb->ccb_h.sym_hcb_ptr; 733853790Sobrien 733953790Sobrien /* 734053790Sobrien * Check that the CAM CCB is still queued. 734153790Sobrien */ 734253790Sobrien if (!np) 734353790Sobrien return; 734453790Sobrien 7345178468Smarius SYM_LOCK(); 7346178468Smarius 734753790Sobrien switch(ccb->ccb_h.func_code) { 734853790Sobrien case XPT_SCSI_IO: 734953790Sobrien (void) sym_abort_scsiio(np, ccb, 1); 735053790Sobrien break; 735153790Sobrien default: 735253790Sobrien break; 735353790Sobrien } 735453790Sobrien 7355178468Smarius SYM_UNLOCK(); 735653790Sobrien} 735753790Sobrien 735853790Sobrien/* 735953790Sobrien * Abort an SCSI IO. 736053790Sobrien */ 736153790Sobrienstatic int sym_abort_scsiio(hcb_p np, union ccb *ccb, int timed_out) 736253790Sobrien{ 736353790Sobrien ccb_p cp; 736455300Sgroudier SYM_QUEHEAD *qp; 736553790Sobrien 7366178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7367178468Smarius 736853790Sobrien /* 736953790Sobrien * Look up our CCB control block. 737053790Sobrien */ 7371178466Smarius cp = NULL; 737255300Sgroudier FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 737355300Sgroudier ccb_p cp2 = sym_que_entry(qp, struct sym_ccb, link_ccbq); 737455300Sgroudier if (cp2->cam_ccb == ccb) { 737555300Sgroudier cp = cp2; 737653790Sobrien break; 737755300Sgroudier } 737853790Sobrien } 737958927Sgroudier if (!cp || cp->host_status == HS_WAIT) 738053790Sobrien return -1; 738153790Sobrien 738253790Sobrien /* 738353790Sobrien * If a previous abort didn't succeed in time, 738453790Sobrien * perform a BUS reset. 738553790Sobrien */ 738653790Sobrien if (cp->to_abort) { 738753790Sobrien sym_reset_scsi_bus(np, 1); 738853790Sobrien return 0; 738953790Sobrien } 739053790Sobrien 739153790Sobrien /* 739253790Sobrien * Mark the CCB for abort and allow time for. 739353790Sobrien */ 739453790Sobrien cp->to_abort = timed_out ? 2 : 1; 7395178468Smarius callout_reset(&cp->ch, 10 * hz, sym_callout, (caddr_t) ccb); 739653790Sobrien 739753790Sobrien /* 739853790Sobrien * Tell the SCRIPTS processor to stop and synchronize with us. 739953790Sobrien */ 740053790Sobrien np->istat_sem = SEM; 740153790Sobrien OUTB (nc_istat, SIGP|SEM); 740253790Sobrien return 0; 740353790Sobrien} 740453790Sobrien 740553790Sobrien/* 740653790Sobrien * Reset a SCSI device (all LUNs of a target). 740753790Sobrien */ 740853790Sobrienstatic void sym_reset_dev(hcb_p np, union ccb *ccb) 740953790Sobrien{ 741053790Sobrien tcb_p tp; 741153790Sobrien struct ccb_hdr *ccb_h = &ccb->ccb_h; 741253790Sobrien 7413178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7414178468Smarius 741553790Sobrien if (ccb_h->target_id == np->myaddr || 741654690Sobrien ccb_h->target_id >= SYM_CONF_MAX_TARGET || 741754690Sobrien ccb_h->target_lun >= SYM_CONF_MAX_LUN) { 741853790Sobrien sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE); 741953790Sobrien return; 742053790Sobrien } 742153790Sobrien 742253790Sobrien tp = &np->target[ccb_h->target_id]; 742353790Sobrien 742453790Sobrien tp->to_reset = 1; 742553790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 742653790Sobrien 742753790Sobrien np->istat_sem = SEM; 742853790Sobrien OUTB (nc_istat, SIGP|SEM); 742953790Sobrien} 743053790Sobrien 743153790Sobrien/* 743253790Sobrien * SIM action entry point. 743353790Sobrien */ 743453790Sobrienstatic void sym_action(struct cam_sim *sim, union ccb *ccb) 743553790Sobrien{ 743653790Sobrien hcb_p np; 743753790Sobrien tcb_p tp; 743853790Sobrien lcb_p lp; 743953790Sobrien ccb_p cp; 744053790Sobrien int tmp; 744153790Sobrien u_char idmsg, *msgptr; 744253790Sobrien u_int msglen; 744353790Sobrien struct ccb_scsiio *csio; 744453790Sobrien struct ccb_hdr *ccb_h; 744553790Sobrien 744653790Sobrien CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("sym_action\n")); 744753790Sobrien 744853790Sobrien /* 744953790Sobrien * Retrieve our controller data structure. 745053790Sobrien */ 745153790Sobrien np = (hcb_p) cam_sim_softc(sim); 745253790Sobrien 7453178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7454178468Smarius 745553790Sobrien /* 745653790Sobrien * The common case is SCSI IO. 745753790Sobrien * We deal with other ones elsewhere. 745853790Sobrien */ 745953790Sobrien if (ccb->ccb_h.func_code != XPT_SCSI_IO) { 746053790Sobrien sym_action2(sim, ccb); 746153790Sobrien return; 746253790Sobrien } 746353790Sobrien csio = &ccb->csio; 746453790Sobrien ccb_h = &csio->ccb_h; 746553790Sobrien 746653790Sobrien /* 746753790Sobrien * Work around races. 746853790Sobrien */ 746953790Sobrien if ((ccb_h->status & CAM_STATUS_MASK) != CAM_REQ_INPROG) { 747053790Sobrien xpt_done(ccb); 747153790Sobrien return; 747253790Sobrien } 747353790Sobrien 747453790Sobrien /* 7475178466Smarius * Minimal checkings, so that we will not 747653790Sobrien * go outside our tables. 747753790Sobrien */ 747853790Sobrien if (ccb_h->target_id == np->myaddr || 747954690Sobrien ccb_h->target_id >= SYM_CONF_MAX_TARGET || 748054690Sobrien ccb_h->target_lun >= SYM_CONF_MAX_LUN) { 748153790Sobrien sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE); 748253790Sobrien return; 748353790Sobrien } 748453790Sobrien 748553790Sobrien /* 7486220944Smarius * Retrieve the target and lun descriptors. 748753790Sobrien */ 748853790Sobrien tp = &np->target[ccb_h->target_id]; 7489251402Smarius lp = sym_lp(tp, ccb_h->target_lun); 749053790Sobrien 749153790Sobrien /* 7492178466Smarius * Complete the 1st INQUIRY command with error 7493178466Smarius * condition if the device is flagged NOSCAN 7494178466Smarius * at BOOT in the NVRAM. This may speed up 7495178466Smarius * the boot and maintain coherency with BIOS 7496178466Smarius * device numbering. Clearing the flag allows 749753790Sobrien * user to rescan skipped devices later. 7498178466Smarius * We also return error for devices not flagged 7499178466Smarius * for SCAN LUNS in the NVRAM since some mono-lun 7500178466Smarius * devices behave badly when asked for some non 750153790Sobrien * zero LUN. Btw, this is an absolute hack.:-) 750253790Sobrien */ 750353790Sobrien if (!(ccb_h->flags & CAM_CDB_PHYS) && 750453790Sobrien (0x12 == ((ccb_h->flags & CAM_CDB_POINTER) ? 750553790Sobrien csio->cdb_io.cdb_ptr[0] : csio->cdb_io.cdb_bytes[0]))) { 750653790Sobrien if ((tp->usrflags & SYM_SCAN_BOOT_DISABLED) || 7507178466Smarius ((tp->usrflags & SYM_SCAN_LUNS_DISABLED) && 750853790Sobrien ccb_h->target_lun != 0)) { 750953790Sobrien tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED; 751053790Sobrien sym_xpt_done2(np, ccb, CAM_DEV_NOT_THERE); 751153790Sobrien return; 751253790Sobrien } 751353790Sobrien } 751453790Sobrien 751553790Sobrien /* 751653790Sobrien * Get a control block for this IO. 751753790Sobrien */ 751853790Sobrien tmp = ((ccb_h->flags & CAM_TAG_ACTION_VALID) != 0); 751953790Sobrien cp = sym_get_ccb(np, ccb_h->target_id, ccb_h->target_lun, tmp); 752053790Sobrien if (!cp) { 752153790Sobrien sym_xpt_done2(np, ccb, CAM_RESRC_UNAVAIL); 752253790Sobrien return; 752353790Sobrien } 752453790Sobrien 752553790Sobrien /* 752658927Sgroudier * Keep track of the IO in our CCB. 752753790Sobrien */ 752853790Sobrien cp->cam_ccb = ccb; 752953790Sobrien 753053790Sobrien /* 753153790Sobrien * Build the IDENTIFY message. 753253790Sobrien */ 753353790Sobrien idmsg = M_IDENTIFY | cp->lun; 753453790Sobrien if (cp->tag != NO_TAG || (lp && (lp->current_flags & SYM_DISC_ENABLED))) 753553790Sobrien idmsg |= 0x40; 753653790Sobrien 753753790Sobrien msgptr = cp->scsi_smsg; 753853790Sobrien msglen = 0; 753953790Sobrien msgptr[msglen++] = idmsg; 754053790Sobrien 754153790Sobrien /* 754253790Sobrien * Build the tag message if present. 754353790Sobrien */ 754453790Sobrien if (cp->tag != NO_TAG) { 754553790Sobrien u_char order = csio->tag_action; 754653790Sobrien 754753790Sobrien switch(order) { 754853790Sobrien case M_ORDERED_TAG: 754953790Sobrien break; 755053790Sobrien case M_HEAD_TAG: 755153790Sobrien break; 755253790Sobrien default: 755353790Sobrien order = M_SIMPLE_TAG; 755453790Sobrien } 755553790Sobrien msgptr[msglen++] = order; 755653790Sobrien 755753790Sobrien /* 7558178466Smarius * For less than 128 tags, actual tags are numbered 7559178466Smarius * 1,3,5,..2*MAXTAGS+1,since we may have to deal 7560178466Smarius * with devices that have problems with #TAG 0 or too 7561178466Smarius * great #TAG numbers. For more tags (up to 256), 756253790Sobrien * we use directly our tag number. 756353790Sobrien */ 756454690Sobrien#if SYM_CONF_MAX_TASK > (512/4) 756553790Sobrien msgptr[msglen++] = cp->tag; 756653790Sobrien#else 756753790Sobrien msgptr[msglen++] = (cp->tag << 1) + 1; 756853790Sobrien#endif 756953790Sobrien } 757053790Sobrien 757153790Sobrien /* 757253790Sobrien * Build a negotiation message if needed. 757353790Sobrien * (nego_status is filled by sym_prepare_nego()) 757453790Sobrien */ 757553790Sobrien cp->nego_status = 0; 757653790Sobrien if (tp->tinfo.current.width != tp->tinfo.goal.width || 757753790Sobrien tp->tinfo.current.period != tp->tinfo.goal.period || 757853790Sobrien tp->tinfo.current.offset != tp->tinfo.goal.offset || 757953790Sobrien tp->tinfo.current.options != tp->tinfo.goal.options) { 758053790Sobrien if (!tp->nego_cp && lp) 758153790Sobrien msglen += sym_prepare_nego(np, cp, 0, msgptr + msglen); 758253790Sobrien } 758353790Sobrien 758453790Sobrien /* 758553790Sobrien * Fill in our ccb 758653790Sobrien */ 758753790Sobrien 758853790Sobrien /* 758953790Sobrien * Startqueue 759053790Sobrien */ 759159743Sgroudier cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA (np, select)); 759259743Sgroudier cp->phys.head.go.restart = cpu_to_scr(SCRIPTA_BA (np, resel_dsa)); 759353790Sobrien 759453790Sobrien /* 759553790Sobrien * select 759653790Sobrien */ 759753790Sobrien cp->phys.select.sel_id = cp->target; 759859743Sgroudier cp->phys.select.sel_scntl3 = tp->head.wval; 759959743Sgroudier cp->phys.select.sel_sxfer = tp->head.sval; 760059743Sgroudier cp->phys.select.sel_scntl4 = tp->head.uval; 760153790Sobrien 760253790Sobrien /* 760353790Sobrien * message 760453790Sobrien */ 760558927Sgroudier cp->phys.smsg.addr = cpu_to_scr(CCB_BA (cp, scsi_smsg)); 760653790Sobrien cp->phys.smsg.size = cpu_to_scr(msglen); 760753790Sobrien 760853790Sobrien /* 760953790Sobrien * command 761053790Sobrien */ 761153790Sobrien if (sym_setup_cdb(np, csio, cp) < 0) { 7612178468Smarius sym_xpt_done(np, ccb, cp); 761353790Sobrien sym_free_ccb(np, cp); 761453790Sobrien return; 761553790Sobrien } 761653790Sobrien 761753790Sobrien /* 761853790Sobrien * status 761953790Sobrien */ 762053790Sobrien#if 0 /* Provision */ 762153790Sobrien cp->actualquirks = tp->quirks; 762253790Sobrien#endif 762353790Sobrien cp->actualquirks = SYM_QUIRK_AUTOSAVE; 762453790Sobrien cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; 762553790Sobrien cp->ssss_status = S_ILLEGAL; 762653790Sobrien cp->xerr_status = 0; 762753790Sobrien cp->host_flags = 0; 762859252Sgroudier cp->extra_bytes = 0; 762953790Sobrien 763053790Sobrien /* 763153790Sobrien * extreme data pointer. 763253790Sobrien * shall be positive, so -1 is lower than lowest.:) 763353790Sobrien */ 763453790Sobrien cp->ext_sg = -1; 763553790Sobrien cp->ext_ofs = 0; 763653790Sobrien 763753790Sobrien /* 7638178466Smarius * Build the data descriptor block 763953790Sobrien * and start the IO. 764053790Sobrien */ 764158927Sgroudier sym_setup_data_and_start(np, csio, cp); 764253790Sobrien} 764353790Sobrien 764453790Sobrien/* 764558927Sgroudier * Setup buffers and pointers that address the CDB. 7646178466Smarius * I bet, physical CDBs will never be used on the planet, 764758927Sgroudier * since they can be bounced without significant overhead. 764853790Sobrien */ 764953790Sobrienstatic int sym_setup_cdb(hcb_p np, struct ccb_scsiio *csio, ccb_p cp) 765053790Sobrien{ 765153790Sobrien struct ccb_hdr *ccb_h; 765253790Sobrien u32 cmd_ba; 765353790Sobrien int cmd_len; 7654178466Smarius 7655178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7656178468Smarius 765753790Sobrien ccb_h = &csio->ccb_h; 765853790Sobrien 765953790Sobrien /* 766053790Sobrien * CDB is 16 bytes max. 766153790Sobrien */ 766258927Sgroudier if (csio->cdb_len > sizeof(cp->cdb_buf)) { 766353790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_REQ_INVALID); 766453790Sobrien return -1; 766553790Sobrien } 766653790Sobrien cmd_len = csio->cdb_len; 766753790Sobrien 766853790Sobrien if (ccb_h->flags & CAM_CDB_POINTER) { 766953790Sobrien /* CDB is a pointer */ 767053790Sobrien if (!(ccb_h->flags & CAM_CDB_PHYS)) { 767153790Sobrien /* CDB pointer is virtual */ 767258927Sgroudier bcopy(csio->cdb_io.cdb_ptr, cp->cdb_buf, cmd_len); 767358927Sgroudier cmd_ba = CCB_BA (cp, cdb_buf[0]); 767453790Sobrien } else { 767553790Sobrien /* CDB pointer is physical */ 767653790Sobrien#if 0 767753790Sobrien cmd_ba = ((u32)csio->cdb_io.cdb_ptr) & 0xffffffff; 767853790Sobrien#else 767953790Sobrien sym_set_cam_status(cp->cam_ccb, CAM_REQ_INVALID); 768053790Sobrien return -1; 768153790Sobrien#endif 768253790Sobrien } 768353790Sobrien } else { 768458927Sgroudier /* CDB is in the CAM ccb (buffer) */ 768558927Sgroudier bcopy(csio->cdb_io.cdb_bytes, cp->cdb_buf, cmd_len); 768658927Sgroudier cmd_ba = CCB_BA (cp, cdb_buf[0]); 768753790Sobrien } 768853790Sobrien 768953790Sobrien cp->phys.cmd.addr = cpu_to_scr(cmd_ba); 769053790Sobrien cp->phys.cmd.size = cpu_to_scr(cmd_len); 769153790Sobrien 769253790Sobrien return 0; 769353790Sobrien} 769453790Sobrien 769553790Sobrien/* 769658927Sgroudier * Set up data pointers used by SCRIPTS. 769758927Sgroudier */ 7698178466Smariusstatic void __inline 769958927Sgroudiersym_setup_data_pointers(hcb_p np, ccb_p cp, int dir) 770058927Sgroudier{ 770158927Sgroudier u32 lastp, goalp; 770258927Sgroudier 7703178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7704178468Smarius 770558927Sgroudier /* 770658927Sgroudier * No segments means no data. 770758927Sgroudier */ 770858927Sgroudier if (!cp->segments) 770958927Sgroudier dir = CAM_DIR_NONE; 771058927Sgroudier 771158927Sgroudier /* 771258927Sgroudier * Set the data pointer. 771358927Sgroudier */ 771458927Sgroudier switch(dir) { 771558927Sgroudier case CAM_DIR_OUT: 771659292Sgroudier goalp = SCRIPTA_BA (np, data_out2) + 8; 771758927Sgroudier lastp = goalp - 8 - (cp->segments * (2*4)); 771858927Sgroudier break; 771958927Sgroudier case CAM_DIR_IN: 772058927Sgroudier cp->host_flags |= HF_DATA_IN; 772159292Sgroudier goalp = SCRIPTA_BA (np, data_in2) + 8; 772258927Sgroudier lastp = goalp - 8 - (cp->segments * (2*4)); 772358927Sgroudier break; 772458927Sgroudier case CAM_DIR_NONE: 772558927Sgroudier default: 772659292Sgroudier lastp = goalp = SCRIPTB_BA (np, no_data); 772758927Sgroudier break; 772858927Sgroudier } 772958927Sgroudier 773059743Sgroudier cp->phys.head.lastp = cpu_to_scr(lastp); 773159743Sgroudier cp->phys.head.goalp = cpu_to_scr(goalp); 773259743Sgroudier cp->phys.head.savep = cpu_to_scr(lastp); 773359743Sgroudier cp->startp = cp->phys.head.savep; 773458927Sgroudier} 773558927Sgroudier 773658927Sgroudier/* 773758927Sgroudier * Call back routine for the DMA map service. 7738178466Smarius * If bounce buffers are used (why ?), we may sleep and then 773958927Sgroudier * be called there in another context. 774058927Sgroudier */ 774158927Sgroudierstatic void 774258927Sgroudiersym_execute_ccb(void *arg, bus_dma_segment_t *psegs, int nsegs, int error) 774358927Sgroudier{ 774458927Sgroudier ccb_p cp; 774558927Sgroudier hcb_p np; 774658927Sgroudier union ccb *ccb; 774758927Sgroudier 774858927Sgroudier cp = (ccb_p) arg; 774958927Sgroudier ccb = cp->cam_ccb; 775058927Sgroudier np = (hcb_p) cp->arg; 775158927Sgroudier 7752178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7753178468Smarius 775458927Sgroudier /* 775558927Sgroudier * Deal with weird races. 775658927Sgroudier */ 775758927Sgroudier if (sym_get_cam_status(ccb) != CAM_REQ_INPROG) 775858927Sgroudier goto out_abort; 775958927Sgroudier 776058927Sgroudier /* 776158927Sgroudier * Deal with weird errors. 776258927Sgroudier */ 776358927Sgroudier if (error) { 776458927Sgroudier cp->dmamapped = 0; 776558927Sgroudier sym_set_cam_status(cp->cam_ccb, CAM_REQ_ABORTED); 776658927Sgroudier goto out_abort; 776758927Sgroudier } 776858927Sgroudier 776958927Sgroudier /* 777058927Sgroudier * Build the data descriptor for the chip. 777158927Sgroudier */ 777258927Sgroudier if (nsegs) { 777358927Sgroudier int retv; 777458927Sgroudier /* 896 rev 1 requires to be careful about boundaries */ 777558927Sgroudier if (np->device_id == PCI_ID_SYM53C896 && np->revision_id <= 1) 777658927Sgroudier retv = sym_scatter_sg_physical(np, cp, psegs, nsegs); 777758927Sgroudier else 777858927Sgroudier retv = sym_fast_scatter_sg_physical(np,cp, psegs,nsegs); 777958927Sgroudier if (retv < 0) { 778058927Sgroudier sym_set_cam_status(cp->cam_ccb, CAM_REQ_TOO_BIG); 778158927Sgroudier goto out_abort; 778258927Sgroudier } 778358927Sgroudier } 778458927Sgroudier 778558927Sgroudier /* 7786178466Smarius * Synchronize the DMA map only if we have 778758927Sgroudier * actually mapped the data. 778858927Sgroudier */ 778958927Sgroudier if (cp->dmamapped) { 779058927Sgroudier bus_dmamap_sync(np->data_dmat, cp->dmamap, 7791178466Smarius (cp->dmamapped == SYM_DMA_READ ? 779258927Sgroudier BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE)); 779358927Sgroudier } 779458927Sgroudier 779558927Sgroudier /* 779658927Sgroudier * Set host status to busy state. 779758927Sgroudier * May have been set back to HS_WAIT to avoid a race. 779858927Sgroudier */ 779958927Sgroudier cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; 780058927Sgroudier 780158927Sgroudier /* 780258927Sgroudier * Set data pointers. 780358927Sgroudier */ 780458927Sgroudier sym_setup_data_pointers(np, cp, (ccb->ccb_h.flags & CAM_DIR_MASK)); 780558927Sgroudier 780658927Sgroudier /* 780758927Sgroudier * Enqueue this IO in our pending queue. 780858927Sgroudier */ 7809178468Smarius sym_enqueue_cam_ccb(cp); 781058927Sgroudier 781162422Sgroudier /* 7812178466Smarius * When `#ifed 1', the code below makes the driver 781362422Sgroudier * panic on the first attempt to write to a SCSI device. 7814178466Smarius * It is the first test we want to do after a driver 781562422Sgroudier * change that does not seem obviously safe. :) 781662422Sgroudier */ 781758927Sgroudier#if 0 781858927Sgroudier switch (cp->cdb_buf[0]) { 781958927Sgroudier case 0x0A: case 0x2A: case 0xAA: 782058927Sgroudier panic("XXXXXXXXXXXXX WRITE NOT YET ALLOWED XXXXXXXXXXXXXX\n"); 782158927Sgroudier MDELAY(10000); 782258927Sgroudier break; 782358927Sgroudier default: 782458927Sgroudier break; 782558927Sgroudier } 782658927Sgroudier#endif 782758927Sgroudier /* 782858927Sgroudier * Activate this job. 782958927Sgroudier */ 783058927Sgroudier sym_put_start_queue(np, cp); 783158927Sgroudier return; 783258927Sgroudierout_abort: 7833178468Smarius sym_xpt_done(np, ccb, cp); 783458927Sgroudier sym_free_ccb(np, cp); 783558927Sgroudier} 783658927Sgroudier 783758927Sgroudier/* 783853790Sobrien * How complex it gets to deal with the data in CAM. 783958927Sgroudier * The Bus Dma stuff makes things still more complex. 784053790Sobrien */ 7841178466Smariusstatic void 784258927Sgroudiersym_setup_data_and_start(hcb_p np, struct ccb_scsiio *csio, ccb_p cp) 784353790Sobrien{ 784453790Sobrien struct ccb_hdr *ccb_h; 784553790Sobrien int dir, retv; 7846178466Smarius 7847178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7848178468Smarius 784953790Sobrien ccb_h = &csio->ccb_h; 785053790Sobrien 785153790Sobrien /* 785253790Sobrien * Now deal with the data. 785353790Sobrien */ 785458927Sgroudier cp->data_len = csio->dxfer_len; 785558927Sgroudier cp->arg = np; 785658927Sgroudier 785758927Sgroudier /* 785858927Sgroudier * No direction means no data. 785958927Sgroudier */ 786058927Sgroudier dir = (ccb_h->flags & CAM_DIR_MASK); 786158927Sgroudier if (dir == CAM_DIR_NONE) { 786258927Sgroudier sym_execute_ccb(cp, NULL, 0, 0); 786358927Sgroudier return; 786458927Sgroudier } 786558927Sgroudier 7866246713Skib cp->dmamapped = (dir == CAM_DIR_IN) ? SYM_DMA_READ : SYM_DMA_WRITE; 7867246713Skib retv = bus_dmamap_load_ccb(np->data_dmat, cp->dmamap, 7868246713Skib (union ccb *)csio, sym_execute_ccb, cp, 0); 7869246713Skib if (retv == EINPROGRESS) { 7870246713Skib cp->host_status = HS_WAIT; 7871246713Skib xpt_freeze_simq(np->sim, 1); 7872246713Skib csio->ccb_h.status |= CAM_RELEASE_SIMQ; 787358927Sgroudier } 787458927Sgroudier} 787558927Sgroudier 787658927Sgroudier/* 787758927Sgroudier * Move the scatter list to our data block. 787858927Sgroudier */ 7879178466Smariusstatic int 7880178466Smariussym_fast_scatter_sg_physical(hcb_p np, ccb_p cp, 788158927Sgroudier bus_dma_segment_t *psegs, int nsegs) 788258927Sgroudier{ 788358927Sgroudier struct sym_tblmove *data; 788458927Sgroudier bus_dma_segment_t *psegs2; 788558927Sgroudier 7886178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7887178468Smarius 788858927Sgroudier if (nsegs > SYM_CONF_MAX_SG) 788958927Sgroudier return -1; 789058927Sgroudier 789158927Sgroudier data = &cp->phys.data[SYM_CONF_MAX_SG-1]; 789258927Sgroudier psegs2 = &psegs[nsegs-1]; 789358927Sgroudier cp->segments = nsegs; 789458927Sgroudier 789558927Sgroudier while (1) { 789658927Sgroudier data->addr = cpu_to_scr(psegs2->ds_addr); 789758927Sgroudier data->size = cpu_to_scr(psegs2->ds_len); 789858927Sgroudier if (DEBUG_FLAGS & DEBUG_SCATTER) { 789958927Sgroudier printf ("%s scatter: paddr=%lx len=%ld\n", 790058927Sgroudier sym_name(np), (long) psegs2->ds_addr, 790158927Sgroudier (long) psegs2->ds_len); 790258927Sgroudier } 790358927Sgroudier if (psegs2 != psegs) { 790458927Sgroudier --data; 790558927Sgroudier --psegs2; 790658927Sgroudier continue; 790758927Sgroudier } 790858927Sgroudier break; 790958927Sgroudier } 791058927Sgroudier return 0; 791158927Sgroudier} 791258927Sgroudier 791358927Sgroudier/* 791458927Sgroudier * Scatter a SG list with physical addresses into bus addressable chunks. 791558927Sgroudier */ 791658927Sgroudierstatic int 791758927Sgroudiersym_scatter_sg_physical(hcb_p np, ccb_p cp, bus_dma_segment_t *psegs, int nsegs) 791858927Sgroudier{ 791958927Sgroudier u_long ps, pe, pn; 7920178466Smarius u_long k; 792158927Sgroudier int s, t; 792258927Sgroudier 7923178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7924178468Smarius 792558927Sgroudier s = SYM_CONF_MAX_SG - 1; 792658927Sgroudier t = nsegs - 1; 792758927Sgroudier ps = psegs[t].ds_addr; 792858927Sgroudier pe = ps + psegs[t].ds_len; 792958927Sgroudier 793058927Sgroudier while (s >= 0) { 7931236061Smarius pn = (pe - 1) & ~(SYM_CONF_DMA_BOUNDARY - 1); 793258927Sgroudier if (pn <= ps) 793358927Sgroudier pn = ps; 793458927Sgroudier k = pe - pn; 793558927Sgroudier if (DEBUG_FLAGS & DEBUG_SCATTER) { 793658927Sgroudier printf ("%s scatter: paddr=%lx len=%ld\n", 793758927Sgroudier sym_name(np), pn, k); 793858927Sgroudier } 793958927Sgroudier cp->phys.data[s].addr = cpu_to_scr(pn); 794058927Sgroudier cp->phys.data[s].size = cpu_to_scr(k); 794158927Sgroudier --s; 794258927Sgroudier if (pn == ps) { 794358927Sgroudier if (--t < 0) 794458927Sgroudier break; 794558927Sgroudier ps = psegs[t].ds_addr; 794658927Sgroudier pe = ps + psegs[t].ds_len; 794758927Sgroudier } 794858927Sgroudier else 794958927Sgroudier pe = pn; 795058927Sgroudier } 795158927Sgroudier 795258927Sgroudier cp->segments = SYM_CONF_MAX_SG - 1 - s; 795358927Sgroudier 795458927Sgroudier return t >= 0 ? -1 : 0; 795558927Sgroudier} 795658927Sgroudier 795758927Sgroudier/* 795853790Sobrien * SIM action for non performance critical stuff. 795953790Sobrien */ 796053790Sobrienstatic void sym_action2(struct cam_sim *sim, union ccb *ccb) 796153790Sobrien{ 7962236061Smarius union ccb *abort_ccb; 7963236061Smarius struct ccb_hdr *ccb_h; 7964236061Smarius struct ccb_pathinq *cpi; 7965236061Smarius struct ccb_trans_settings *cts; 7966236061Smarius struct sym_trans *tip; 796753790Sobrien hcb_p np; 796853790Sobrien tcb_p tp; 796953790Sobrien lcb_p lp; 7970236061Smarius u_char dflags; 797153790Sobrien 797253790Sobrien /* 797353790Sobrien * Retrieve our controller data structure. 797453790Sobrien */ 797553790Sobrien np = (hcb_p) cam_sim_softc(sim); 797653790Sobrien 7977178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 7978178468Smarius 797953790Sobrien ccb_h = &ccb->ccb_h; 798053790Sobrien 798153790Sobrien switch (ccb_h->func_code) { 798253790Sobrien case XPT_SET_TRAN_SETTINGS: 798353790Sobrien cts = &ccb->cts; 798453790Sobrien tp = &np->target[ccb_h->target_id]; 798553790Sobrien 798653790Sobrien /* 798774755Sgroudier * Update SPI transport settings in TARGET control block. 798874755Sgroudier * Update SCSI device settings in LUN control block. 798953790Sobrien */ 7990251402Smarius lp = sym_lp(tp, ccb_h->target_lun); 799174755Sgroudier if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 7992251402Smarius sym_update_trans(np, &tp->tinfo.goal, cts); 799374755Sgroudier if (lp) 799453790Sobrien sym_update_dflags(np, &lp->current_flags, cts); 799553790Sobrien } 799674755Sgroudier if (cts->type == CTS_TYPE_USER_SETTINGS) { 7997251402Smarius sym_update_trans(np, &tp->tinfo.user, cts); 799874755Sgroudier if (lp) 799974755Sgroudier sym_update_dflags(np, &lp->user_flags, cts); 800074755Sgroudier } 800153790Sobrien 800253790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 800353790Sobrien break; 800453790Sobrien case XPT_GET_TRAN_SETTINGS: 800553790Sobrien cts = &ccb->cts; 800653790Sobrien tp = &np->target[ccb_h->target_id]; 8007251402Smarius lp = sym_lp(tp, ccb_h->target_lun); 800853790Sobrien 800974755Sgroudier#define cts__scsi (&cts->proto_specific.scsi) 801074755Sgroudier#define cts__spi (&cts->xport_specific.spi) 801174755Sgroudier if (cts->type == CTS_TYPE_CURRENT_SETTINGS) { 801274755Sgroudier tip = &tp->tinfo.current; 801374755Sgroudier dflags = lp ? lp->current_flags : 0; 801474755Sgroudier } 801574755Sgroudier else { 801674755Sgroudier tip = &tp->tinfo.user; 801774755Sgroudier dflags = lp ? lp->user_flags : tp->usrflags; 801874755Sgroudier } 801974755Sgroudier 802074755Sgroudier cts->protocol = PROTO_SCSI; 802174755Sgroudier cts->transport = XPORT_SPI; 802274755Sgroudier cts->protocol_version = tip->scsi_version; 802374755Sgroudier cts->transport_version = tip->spi_version; 8024178466Smarius 802574755Sgroudier cts__spi->sync_period = tip->period; 802674755Sgroudier cts__spi->sync_offset = tip->offset; 802774755Sgroudier cts__spi->bus_width = tip->width; 802874755Sgroudier cts__spi->ppr_options = tip->options; 802974755Sgroudier 803074755Sgroudier cts__spi->valid = CTS_SPI_VALID_SYNC_RATE 803174755Sgroudier | CTS_SPI_VALID_SYNC_OFFSET 803274755Sgroudier | CTS_SPI_VALID_BUS_WIDTH 803374755Sgroudier | CTS_SPI_VALID_PPR_OPTIONS; 8034178466Smarius 803574755Sgroudier cts__spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB; 803674755Sgroudier if (dflags & SYM_DISC_ENABLED) 803774755Sgroudier cts__spi->flags |= CTS_SPI_FLAGS_DISC_ENB; 803874755Sgroudier cts__spi->valid |= CTS_SPI_VALID_DISC; 803974755Sgroudier 804074755Sgroudier cts__scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB; 804174755Sgroudier if (dflags & SYM_TAGS_ENABLED) 804274755Sgroudier cts__scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB; 804374755Sgroudier cts__scsi->valid |= CTS_SCSI_VALID_TQ; 804474755Sgroudier#undef cts__spi 804574755Sgroudier#undef cts__scsi 804653790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 804753790Sobrien break; 804853790Sobrien case XPT_CALC_GEOMETRY: 8049116351Snjl cam_calc_geometry(&ccb->ccg, /*extended*/1); 805053790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 805153790Sobrien break; 805253790Sobrien case XPT_PATH_INQ: 8053236061Smarius cpi = &ccb->cpi; 805453790Sobrien cpi->version_num = 1; 805553790Sobrien cpi->hba_inquiry = PI_MDP_ABLE|PI_SDTR_ABLE|PI_TAG_ABLE; 805653790Sobrien if ((np->features & FE_WIDE) != 0) 805753790Sobrien cpi->hba_inquiry |= PI_WIDE_16; 805853790Sobrien cpi->target_sprt = 0; 8059251403Smarius cpi->hba_misc = PIM_UNMAPPED; 806055628Sgroudier if (np->usrflags & SYM_SCAN_TARGETS_HILO) 806155628Sgroudier cpi->hba_misc |= PIM_SCANHILO; 806255628Sgroudier if (np->usrflags & SYM_AVOID_BUS_RESET) 806355628Sgroudier cpi->hba_misc |= PIM_NOBUSRESET; 806453790Sobrien cpi->hba_eng_cnt = 0; 806553790Sobrien cpi->max_target = (np->features & FE_WIDE) ? 15 : 7; 806653790Sobrien /* Semantic problem:)LUN number max = max number of LUNs - 1 */ 806754690Sobrien cpi->max_lun = SYM_CONF_MAX_LUN-1; 806854690Sobrien if (SYM_SETUP_MAX_LUN < SYM_CONF_MAX_LUN) 806954690Sobrien cpi->max_lun = SYM_SETUP_MAX_LUN-1; 807053790Sobrien cpi->bus_id = cam_sim_bus(sim); 807153790Sobrien cpi->initiator_id = np->myaddr; 807253790Sobrien cpi->base_transfer_speed = 3300; 807354690Sobrien strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); 807453790Sobrien strncpy(cpi->hba_vid, "Symbios", HBA_IDLEN); 807553790Sobrien strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); 807653790Sobrien cpi->unit_number = cam_sim_unit(sim); 807774755Sgroudier 807874755Sgroudier cpi->protocol = PROTO_SCSI; 807974755Sgroudier cpi->protocol_version = SCSI_REV_2; 808074755Sgroudier cpi->transport = XPORT_SPI; 808174755Sgroudier cpi->transport_version = 2; 808274755Sgroudier cpi->xport_specific.spi.ppr_options = SID_SPI_CLOCK_ST; 808374755Sgroudier if (np->features & FE_ULTRA3) { 808474755Sgroudier cpi->transport_version = 3; 808574755Sgroudier cpi->xport_specific.spi.ppr_options = 808674755Sgroudier SID_SPI_CLOCK_DT_ST; 808774755Sgroudier } 8088237101Smarius cpi->maxio = SYM_CONF_MAX_SG * PAGE_SIZE; 808953790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 809053790Sobrien break; 809153790Sobrien case XPT_ABORT: 8092236061Smarius abort_ccb = ccb->cab.abort_ccb; 809353790Sobrien switch(abort_ccb->ccb_h.func_code) { 809453790Sobrien case XPT_SCSI_IO: 809553790Sobrien if (sym_abort_scsiio(np, abort_ccb, 0) == 0) { 809653790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 809753790Sobrien break; 809853790Sobrien } 809953790Sobrien default: 810053790Sobrien sym_xpt_done2(np, ccb, CAM_UA_ABORT); 810153790Sobrien break; 810253790Sobrien } 810353790Sobrien break; 810453790Sobrien case XPT_RESET_DEV: 810553790Sobrien sym_reset_dev(np, ccb); 810653790Sobrien break; 810753790Sobrien case XPT_RESET_BUS: 810853790Sobrien sym_reset_scsi_bus(np, 0); 810953790Sobrien if (sym_verbose) { 811053790Sobrien xpt_print_path(np->path); 811155300Sgroudier printf("SCSI BUS reset delivered.\n"); 811253790Sobrien } 811355300Sgroudier sym_init (np, 1); 811453790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_CMP); 811553790Sobrien break; 811653790Sobrien case XPT_ACCEPT_TARGET_IO: 811753790Sobrien case XPT_CONT_TARGET_IO: 811853790Sobrien case XPT_EN_LUN: 811953790Sobrien case XPT_NOTIFY_ACK: 812053790Sobrien case XPT_IMMED_NOTIFY: 812153790Sobrien case XPT_TERM_IO: 812253790Sobrien default: 812353790Sobrien sym_xpt_done2(np, ccb, CAM_REQ_INVALID); 812453790Sobrien break; 812553790Sobrien } 812653790Sobrien} 812753790Sobrien 812853790Sobrien/* 812962134Sgroudier * Asynchronous notification handler. 813062134Sgroudier */ 813162134Sgroudierstatic void 8132251402Smariussym_async(void *cb_arg, u32 code, struct cam_path *path, void *args __unused) 813362134Sgroudier{ 813462134Sgroudier hcb_p np; 813562134Sgroudier struct cam_sim *sim; 813662134Sgroudier u_int tn; 813762134Sgroudier tcb_p tp; 813862134Sgroudier 813962134Sgroudier sim = (struct cam_sim *) cb_arg; 814062134Sgroudier np = (hcb_p) cam_sim_softc(sim); 814162134Sgroudier 8142178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 8143178468Smarius 814462134Sgroudier switch (code) { 814562134Sgroudier case AC_LOST_DEVICE: 814662134Sgroudier tn = xpt_path_target_id(path); 814762134Sgroudier if (tn >= SYM_CONF_MAX_TARGET) 814862134Sgroudier break; 814962134Sgroudier 815062134Sgroudier tp = &np->target[tn]; 815162134Sgroudier 815262134Sgroudier tp->to_reset = 0; 815362134Sgroudier tp->head.sval = 0; 815462134Sgroudier tp->head.wval = np->rv_scntl3; 815562134Sgroudier tp->head.uval = 0; 815662134Sgroudier 815762134Sgroudier tp->tinfo.current.period = tp->tinfo.goal.period = 0; 815862134Sgroudier tp->tinfo.current.offset = tp->tinfo.goal.offset = 0; 815962134Sgroudier tp->tinfo.current.width = tp->tinfo.goal.width = BUS_8_BIT; 816062134Sgroudier tp->tinfo.current.options = tp->tinfo.goal.options = 0; 816162134Sgroudier 816262134Sgroudier break; 816362134Sgroudier default: 816462134Sgroudier break; 816562134Sgroudier } 816662134Sgroudier} 816762134Sgroudier 816862134Sgroudier/* 816953790Sobrien * Update transfer settings of a target. 817053790Sobrien */ 8171251402Smariusstatic void sym_update_trans(hcb_p np, struct sym_trans *tip, 8172251402Smarius struct ccb_trans_settings *cts) 817353790Sobrien{ 8174251402Smarius 8175178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 8176178468Smarius 817753790Sobrien /* 817853790Sobrien * Update the infos. 817953790Sobrien */ 818074755Sgroudier#define cts__spi (&cts->xport_specific.spi) 818174755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_BUS_WIDTH) != 0) 818274755Sgroudier tip->width = cts__spi->bus_width; 818374755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) 818474755Sgroudier tip->offset = cts__spi->sync_offset; 818574755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) 818674755Sgroudier tip->period = cts__spi->sync_period; 818774755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_PPR_OPTIONS) != 0) 818874755Sgroudier tip->options = (cts__spi->ppr_options & PPR_OPT_DT); 818974755Sgroudier if (cts->protocol_version != PROTO_VERSION_UNSPECIFIED && 819074755Sgroudier cts->protocol_version != PROTO_VERSION_UNKNOWN) 819174755Sgroudier tip->scsi_version = cts->protocol_version; 819274755Sgroudier if (cts->transport_version != XPORT_VERSION_UNSPECIFIED && 819374755Sgroudier cts->transport_version != XPORT_VERSION_UNKNOWN) 819474755Sgroudier tip->spi_version = cts->transport_version; 819574755Sgroudier#undef cts__spi 819653790Sobrien /* 819760134Sgroudier * Scale against driver configuration limits. 819853790Sobrien */ 819960134Sgroudier if (tip->width > SYM_SETUP_MAX_WIDE) tip->width = SYM_SETUP_MAX_WIDE; 8200247266Smjacob if (tip->period && tip->offset) { 8201247266Smjacob if (tip->offset > SYM_SETUP_MAX_OFFS) tip->offset = SYM_SETUP_MAX_OFFS; 8202247266Smjacob if (tip->period < SYM_SETUP_MIN_SYNC) tip->period = SYM_SETUP_MIN_SYNC; 8203247266Smjacob } else { 8204247266Smjacob tip->offset = 0; 8205247266Smjacob tip->period = 0; 8206247266Smjacob } 820760134Sgroudier 820860134Sgroudier /* 820960134Sgroudier * Scale against actual controller BUS width. 821060134Sgroudier */ 821160134Sgroudier if (tip->width > np->maxwide) 821260134Sgroudier tip->width = np->maxwide; 821360134Sgroudier 821460134Sgroudier /* 821574755Sgroudier * Only accept DT if controller supports and SYNC/WIDE asked. 821674755Sgroudier */ 821774755Sgroudier if (!((np->features & (FE_C10|FE_ULTRA3)) == (FE_C10|FE_ULTRA3)) || 821874755Sgroudier !(tip->width == BUS_16_BIT && tip->offset)) { 821974755Sgroudier tip->options &= ~PPR_OPT_DT; 822074755Sgroudier } 822160134Sgroudier 822260134Sgroudier /* 822360134Sgroudier * Scale period factor and offset against controller limits. 822460134Sgroudier */ 8225247266Smjacob if (tip->offset && tip->period) { 8226247266Smjacob if (tip->options & PPR_OPT_DT) { 8227247266Smjacob if (tip->period < np->minsync_dt) 8228247266Smjacob tip->period = np->minsync_dt; 8229247266Smjacob if (tip->period > np->maxsync_dt) 8230247266Smjacob tip->period = np->maxsync_dt; 8231247266Smjacob if (tip->offset > np->maxoffs_dt) 8232247266Smjacob tip->offset = np->maxoffs_dt; 8233247266Smjacob } 8234247266Smjacob else { 8235247266Smjacob if (tip->period < np->minsync) 8236247266Smjacob tip->period = np->minsync; 8237247266Smjacob if (tip->period > np->maxsync) 8238247266Smjacob tip->period = np->maxsync; 8239247266Smjacob if (tip->offset > np->maxoffs) 8240247266Smjacob tip->offset = np->maxoffs; 8241247266Smjacob } 824260134Sgroudier } 824353790Sobrien} 824453790Sobrien 824553790Sobrien/* 824653790Sobrien * Update flags for a device (logical unit). 824753790Sobrien */ 8248178466Smariusstatic void 824953790Sobriensym_update_dflags(hcb_p np, u_char *flags, struct ccb_trans_settings *cts) 825053790Sobrien{ 8251251402Smarius 8252178468Smarius SYM_LOCK_ASSERT(MA_OWNED); 8253178468Smarius 825474755Sgroudier#define cts__scsi (&cts->proto_specific.scsi) 825574755Sgroudier#define cts__spi (&cts->xport_specific.spi) 825674755Sgroudier if ((cts__spi->valid & CTS_SPI_VALID_DISC) != 0) { 825774755Sgroudier if ((cts__spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0) 825874755Sgroudier *flags |= SYM_DISC_ENABLED; 825974755Sgroudier else 826074755Sgroudier *flags &= ~SYM_DISC_ENABLED; 826174755Sgroudier } 826274755Sgroudier 826374755Sgroudier if ((cts__scsi->valid & CTS_SCSI_VALID_TQ) != 0) { 826474755Sgroudier if ((cts__scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0) 826574755Sgroudier *flags |= SYM_TAGS_ENABLED; 826674755Sgroudier else 826774755Sgroudier *flags &= ~SYM_TAGS_ENABLED; 826874755Sgroudier } 826974755Sgroudier#undef cts__spi 827074755Sgroudier#undef cts__scsi 827153790Sobrien} 827253790Sobrien 827353790Sobrien/*============= DRIVER INITIALISATION ==================*/ 827453790Sobrien 827553790Sobrienstatic device_method_t sym_pci_methods[] = { 827653790Sobrien DEVMETHOD(device_probe, sym_pci_probe), 827753790Sobrien DEVMETHOD(device_attach, sym_pci_attach), 8278236061Smarius DEVMETHOD_END 827953790Sobrien}; 828053790Sobrien 828153790Sobrienstatic driver_t sym_pci_driver = { 828253790Sobrien "sym", 828353790Sobrien sym_pci_methods, 8284178468Smarius 1 /* no softc */ 828553790Sobrien}; 828653790Sobrien 828753790Sobrienstatic devclass_t sym_devclass; 828853790Sobrien 8289236061SmariusDRIVER_MODULE(sym, pci, sym_pci_driver, sym_devclass, NULL, NULL); 8290135040SmjacobMODULE_DEPEND(sym, cam, 1, 1, 1); 8291135041SmjacobMODULE_DEPEND(sym, pci, 1, 1, 1); 829253790Sobrien 8293179029Smariusstatic const struct sym_pci_chip sym_pci_dev_table[] = { 829459743Sgroudier {PCI_ID_SYM53C810, 0x0f, "810", 4, 8, 4, 64, 829553809Sobrien FE_ERL} 829653809Sobrien , 829759743Sgroudier#ifdef SYM_DEBUG_GENERIC_SUPPORT 829854690Sobrien {PCI_ID_SYM53C810, 0xff, "810a", 4, 8, 4, 1, 829959743Sgroudier FE_BOF} 830059743Sgroudier , 830159743Sgroudier#else 830259743Sgroudier {PCI_ID_SYM53C810, 0xff, "810a", 4, 8, 4, 1, 830353790Sobrien FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF} 830453790Sobrien , 830559743Sgroudier#endif 830659743Sgroudier {PCI_ID_SYM53C815, 0xff, "815", 4, 8, 4, 64, 830759743Sgroudier FE_BOF|FE_ERL} 830859743Sgroudier , 830959743Sgroudier {PCI_ID_SYM53C825, 0x0f, "825", 6, 8, 4, 64, 831053809Sobrien FE_WIDE|FE_BOF|FE_ERL|FE_DIFF} 831153809Sobrien , 831254690Sobrien {PCI_ID_SYM53C825, 0xff, "825a", 6, 8, 4, 2, 831353790Sobrien FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF} 831453790Sobrien , 831554690Sobrien {PCI_ID_SYM53C860, 0xff, "860", 4, 8, 5, 1, 831653790Sobrien FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} 831753790Sobrien , 831854690Sobrien {PCI_ID_SYM53C875, 0x01, "875", 6, 16, 5, 2, 831953790Sobrien FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 832053790Sobrien FE_RAM|FE_DIFF} 832153790Sobrien , 832254690Sobrien {PCI_ID_SYM53C875, 0xff, "875", 6, 16, 5, 2, 832353790Sobrien FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 832453790Sobrien FE_RAM|FE_DIFF} 832553790Sobrien , 832654690Sobrien {PCI_ID_SYM53C875_2, 0xff, "875", 6, 16, 5, 2, 832753790Sobrien FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 832853790Sobrien FE_RAM|FE_DIFF} 832953790Sobrien , 833054690Sobrien {PCI_ID_SYM53C885, 0xff, "885", 6, 16, 5, 2, 833153790Sobrien FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 833253790Sobrien FE_RAM|FE_DIFF} 833353790Sobrien , 833459743Sgroudier#ifdef SYM_DEBUG_GENERIC_SUPPORT 833554690Sobrien {PCI_ID_SYM53C895, 0xff, "895", 6, 31, 7, 2, 833659743Sgroudier FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS| 833759743Sgroudier FE_RAM|FE_LCKFRQ} 833859743Sgroudier , 833959743Sgroudier#else 834059743Sgroudier {PCI_ID_SYM53C895, 0xff, "895", 6, 31, 7, 2, 834153790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 834253790Sobrien FE_RAM|FE_LCKFRQ} 834353790Sobrien , 834459743Sgroudier#endif 834554690Sobrien {PCI_ID_SYM53C896, 0xff, "896", 6, 31, 7, 4, 834653790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 834765404Sgroudier FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} 834853790Sobrien , 834954690Sobrien {PCI_ID_SYM53C895A, 0xff, "895a", 6, 31, 7, 4, 835053790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 835165404Sgroudier FE_RAM|FE_RAM8K|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} 835253790Sobrien , 835360134Sgroudier {PCI_ID_LSI53C1010, 0x00, "1010-33", 6, 31, 7, 8, 835453790Sobrien FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| 835565404Sgroudier FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC| 835653790Sobrien FE_C10} 835753790Sobrien , 835860134Sgroudier {PCI_ID_LSI53C1010, 0xff, "1010-33", 6, 31, 7, 8, 835953790Sobrien FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| 836065404Sgroudier FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC| 836155300Sgroudier FE_C10|FE_U3EN} 836255300Sgroudier , 836360134Sgroudier {PCI_ID_LSI53C1010_2, 0xff, "1010-66", 6, 31, 7, 8, 836455300Sgroudier FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| 836565404Sgroudier FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_66MHZ|FE_CRC| 836653790Sobrien FE_C10|FE_U3EN} 836753790Sobrien , 836854690Sobrien {PCI_ID_LSI53C1510D, 0xff, "1510d", 6, 31, 7, 4, 836953790Sobrien FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 837053790Sobrien FE_RAM|FE_IO256|FE_LEDC} 837153790Sobrien}; 837253790Sobrien 837353790Sobrien/* 837453790Sobrien * Look up the chip table. 837553790Sobrien * 8376178466Smarius * Return a pointer to the chip entry if found, 837753790Sobrien * zero otherwise. 837853790Sobrien */ 8379179029Smariusstatic const struct sym_pci_chip * 838053790Sobriensym_find_pci_chip(device_t dev) 838153790Sobrien{ 8382179029Smarius const struct sym_pci_chip *chip; 838353790Sobrien int i; 838453790Sobrien u_short device_id; 838553790Sobrien u_char revision; 838653790Sobrien 838753790Sobrien if (pci_get_vendor(dev) != PCI_VENDOR_NCR) 8388178466Smarius return NULL; 838953790Sobrien 839053790Sobrien device_id = pci_get_device(dev); 839153790Sobrien revision = pci_get_revid(dev); 839253790Sobrien 8393236488Smarius for (i = 0; i < nitems(sym_pci_dev_table); i++) { 839453790Sobrien chip = &sym_pci_dev_table[i]; 839553790Sobrien if (device_id != chip->device_id) 839653790Sobrien continue; 839753790Sobrien if (revision > chip->revision_id) 839853790Sobrien continue; 839959743Sgroudier return chip; 840053790Sobrien } 840153790Sobrien 8402178466Smarius return NULL; 840353790Sobrien} 840453790Sobrien 840553790Sobrien/* 840653790Sobrien * Tell upper layer if the chip is supported. 840753790Sobrien */ 840853790Sobrienstatic int 840953790Sobriensym_pci_probe(device_t dev) 841053790Sobrien{ 8411179029Smarius const struct sym_pci_chip *chip; 841253790Sobrien 841353790Sobrien chip = sym_find_pci_chip(dev); 841459743Sgroudier if (chip && sym_find_firmware(chip)) { 841553790Sobrien device_set_desc(dev, chip->name); 8416178466Smarius return (chip->lp_probe_bit & SYM_SETUP_LP_PROBE_MAP)? 8417143168Simp BUS_PROBE_LOW_PRIORITY : BUS_PROBE_DEFAULT; 841853790Sobrien } 841953790Sobrien return ENXIO; 842053790Sobrien} 842153790Sobrien 842253790Sobrien/* 842353790Sobrien * Attach a sym53c8xx device. 842453790Sobrien */ 842553790Sobrienstatic int 842653790Sobriensym_pci_attach(device_t dev) 842753790Sobrien{ 8428179029Smarius const struct sym_pci_chip *chip; 842953790Sobrien u_short command; 843053790Sobrien u_char cachelnsz; 8431178466Smarius struct sym_hcb *np = NULL; 843253790Sobrien struct sym_nvram nvram; 8433179029Smarius const struct sym_fw *fw = NULL; 843453790Sobrien int i; 843558927Sgroudier bus_dma_tag_t bus_dmat; 843653790Sobrien 8437166165Smarius bus_dmat = bus_get_dma_tag(dev); 843858927Sgroudier 843958927Sgroudier /* 844053790Sobrien * Only probed devices should be attached. 844153790Sobrien * We just enjoy being paranoid. :) 844253790Sobrien */ 844353790Sobrien chip = sym_find_pci_chip(dev); 844459743Sgroudier if (chip == NULL || (fw = sym_find_firmware(chip)) == NULL) 844553790Sobrien return (ENXIO); 844653790Sobrien 844753790Sobrien /* 8448178466Smarius * Allocate immediately the host control block, 844953790Sobrien * since we are only expecting to succeed. :) 8450178466Smarius * We keep track in the HCB of all the resources that 845153790Sobrien * are to be released on error. 845253790Sobrien */ 845358927Sgroudier np = __sym_calloc_dma(bus_dmat, sizeof(*np), "HCB"); 845458927Sgroudier if (np) 845558927Sgroudier np->bus_dmat = bus_dmat; 845658927Sgroudier else 8457178468Smarius return (ENXIO); 8458179029Smarius device_set_softc(dev, np); 845953790Sobrien 8460178468Smarius SYM_LOCK_INIT(); 8461178468Smarius 846253790Sobrien /* 846353790Sobrien * Copy some useful infos to the HCB. 846453790Sobrien */ 846558927Sgroudier np->hcb_ba = vtobus(np); 846653790Sobrien np->verbose = bootverbose; 846753790Sobrien np->device = dev; 846853790Sobrien np->device_id = pci_get_device(dev); 846953790Sobrien np->revision_id = pci_get_revid(dev); 847053790Sobrien np->features = chip->features; 847153790Sobrien np->clock_divn = chip->nr_divisor; 847253790Sobrien np->maxoffs = chip->offset_max; 847353790Sobrien np->maxburst = chip->burst_max; 847459743Sgroudier np->scripta_sz = fw->a_size; 847559743Sgroudier np->scriptb_sz = fw->b_size; 847659743Sgroudier np->fw_setup = fw->setup; 847759743Sgroudier np->fw_patch = fw->patch; 847859743Sgroudier np->fw_name = fw->name; 847953790Sobrien 8480171524Sse#ifdef __amd64__ 8481171524Sse np->target = sym_calloc_dma(SYM_CONF_MAX_TARGET * sizeof(*(np->target)), 8482171524Sse "TARGET"); 8483171524Sse if (!np->target) 8484171524Sse goto attach_failed; 8485171524Sse#endif 848653790Sobrien 848753790Sobrien /* 8488178466Smarius * Initialize the CCB free and busy queues. 848975329Smjacob */ 849075329Smjacob sym_que_init(&np->free_ccbq); 849175329Smjacob sym_que_init(&np->busy_ccbq); 849275329Smjacob sym_que_init(&np->comp_ccbq); 849375329Smjacob sym_que_init(&np->cam_ccbq); 849475329Smjacob 849575329Smjacob /* 849658927Sgroudier * Allocate a tag for the DMA of user data. 849758927Sgroudier */ 8498236061Smarius if (bus_dma_tag_create(np->bus_dmat, 1, SYM_CONF_DMA_BOUNDARY, 8499236061Smarius BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, 8500238621Smarius BUS_SPACE_MAXSIZE_32BIT, SYM_CONF_MAX_SG, SYM_CONF_DMA_BOUNDARY, 8501238621Smarius 0, busdma_lock_mutex, &np->mtx, &np->data_dmat)) { 850258927Sgroudier device_printf(dev, "failed to create DMA tag.\n"); 850358927Sgroudier goto attach_failed; 850458927Sgroudier } 8505236061Smarius 850658927Sgroudier /* 8507178466Smarius * Read and apply some fix-ups to the PCI COMMAND 850853790Sobrien * register. We want the chip to be enabled for: 850953790Sobrien * - BUS mastering 851053790Sobrien * - PCI parity checking (reporting would also be fine) 851153790Sobrien * - Write And Invalidate. 851253790Sobrien */ 851353790Sobrien command = pci_read_config(dev, PCIR_COMMAND, 2); 8514236061Smarius command |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_PERRESPEN | 8515236061Smarius PCIM_CMD_MWRICEN; 851653790Sobrien pci_write_config(dev, PCIR_COMMAND, command, 2); 851753790Sobrien 851853790Sobrien /* 8519178466Smarius * Let the device know about the cache line size, 852053790Sobrien * if it doesn't yet. 852153790Sobrien */ 852253790Sobrien cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); 852353790Sobrien if (!cachelnsz) { 852453790Sobrien cachelnsz = 8; 852553790Sobrien pci_write_config(dev, PCIR_CACHELNSZ, cachelnsz, 1); 852653790Sobrien } 852753790Sobrien 852853790Sobrien /* 852953790Sobrien * Alloc/get/map/retrieve everything that deals with MMIO. 853053790Sobrien */ 8531254263Sscottl i = SYM_PCI_MMIO; 8532254263Sscottl np->mmio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, 8533254263Sscottl RF_ACTIVE); 853453790Sobrien if (!np->mmio_res) { 853553790Sobrien device_printf(dev, "failed to allocate MMIO resources\n"); 853653790Sobrien goto attach_failed; 853753790Sobrien } 8538178468Smarius np->mmio_ba = rman_get_start(np->mmio_res); 853953790Sobrien 854053790Sobrien /* 854153790Sobrien * Allocate the IRQ. 854253790Sobrien */ 854353790Sobrien i = 0; 8544127135Snjl np->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, 8545127135Snjl RF_ACTIVE | RF_SHAREABLE); 854653790Sobrien if (!np->irq_res) { 854753790Sobrien device_printf(dev, "failed to allocate IRQ resource\n"); 854853790Sobrien goto attach_failed; 854953790Sobrien } 855053790Sobrien 855154690Sobrien#ifdef SYM_CONF_IOMAPPED 855253790Sobrien /* 855353790Sobrien * User want us to use normal IO with PCI. 855453790Sobrien * Alloc/get/map/retrieve everything that deals with IO. 855553790Sobrien */ 8556254263Sscottl i = SYM_PCI_IO; 8557254263Sscottl np->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &i, RF_ACTIVE); 855853790Sobrien if (!np->io_res) { 855953790Sobrien device_printf(dev, "failed to allocate IO resources\n"); 856053790Sobrien goto attach_failed; 856153790Sobrien } 856253790Sobrien 856354690Sobrien#endif /* SYM_CONF_IOMAPPED */ 856453790Sobrien 856553790Sobrien /* 856653790Sobrien * If the chip has RAM. 856753790Sobrien * Alloc/get/map/retrieve the corresponding resources. 856853790Sobrien */ 8569254263Sscottl if (np->features & (FE_RAM|FE_RAM8K)) { 857053790Sobrien int regs_id = SYM_PCI_RAM; 857153790Sobrien if (np->features & FE_64BIT) 857253790Sobrien regs_id = SYM_PCI_RAM64; 8573127135Snjl np->ram_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 8574127135Snjl ®s_id, RF_ACTIVE); 857553790Sobrien if (!np->ram_res) { 857653790Sobrien device_printf(dev,"failed to allocate RAM resources\n"); 857753790Sobrien goto attach_failed; 857853790Sobrien } 857953790Sobrien np->ram_id = regs_id; 8580178468Smarius np->ram_ba = rman_get_start(np->ram_res); 858153790Sobrien } 858253790Sobrien 858353790Sobrien /* 8584178466Smarius * Save setting of some IO registers, so we will 858553796Sobrien * be able to probe specific implementations. 858653796Sobrien */ 858753796Sobrien sym_save_initial_setting (np); 858853796Sobrien 858953796Sobrien /* 8590178466Smarius * Reset the chip now, since it has been reported 8591178466Smarius * that SCSI clock calibration may not work properly 859253796Sobrien * if the chip is currently active. 859353796Sobrien */ 859453796Sobrien sym_chip_reset (np); 859553796Sobrien 859653796Sobrien /* 859753790Sobrien * Try to read the user set-up. 859853790Sobrien */ 859953790Sobrien (void) sym_read_nvram(np, &nvram); 860053790Sobrien 860153790Sobrien /* 8602178466Smarius * Prepare controller and devices settings, according 860353790Sobrien * to chip features, user set-up and driver set-up. 860453790Sobrien */ 860553790Sobrien (void) sym_prepare_setting(np, &nvram); 860653790Sobrien 860753790Sobrien /* 860853790Sobrien * Check the PCI clock frequency. 8609178466Smarius * Must be performed after prepare_setting since it destroys 861053790Sobrien * STEST1 that is used to probe for the clock doubler. 861153790Sobrien */ 861253790Sobrien i = sym_getpciclock(np); 861353790Sobrien if (i > 37000) 861453790Sobrien device_printf(dev, "PCI BUS clock seems too high: %u KHz.\n",i); 861553790Sobrien 861653790Sobrien /* 861753790Sobrien * Allocate the start queue. 861853790Sobrien */ 861958927Sgroudier np->squeue = (u32 *) sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"SQUEUE"); 862053790Sobrien if (!np->squeue) 862153790Sobrien goto attach_failed; 862258927Sgroudier np->squeue_ba = vtobus(np->squeue); 862353790Sobrien 862453790Sobrien /* 862553790Sobrien * Allocate the done queue. 862653790Sobrien */ 862758927Sgroudier np->dqueue = (u32 *) sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"DQUEUE"); 862853790Sobrien if (!np->dqueue) 862953790Sobrien goto attach_failed; 863059743Sgroudier np->dqueue_ba = vtobus(np->dqueue); 863153790Sobrien 863253790Sobrien /* 863353790Sobrien * Allocate the target bus address array. 863453790Sobrien */ 863558927Sgroudier np->targtbl = (u32 *) sym_calloc_dma(256, "TARGTBL"); 863653790Sobrien if (!np->targtbl) 863753790Sobrien goto attach_failed; 863886850Sgroudier np->targtbl_ba = vtobus(np->targtbl); 863953790Sobrien 864053790Sobrien /* 864153790Sobrien * Allocate SCRIPTS areas. 864253790Sobrien */ 864359743Sgroudier np->scripta0 = sym_calloc_dma(np->scripta_sz, "SCRIPTA0"); 864459743Sgroudier np->scriptb0 = sym_calloc_dma(np->scriptb_sz, "SCRIPTB0"); 864559292Sgroudier if (!np->scripta0 || !np->scriptb0) 864653790Sobrien goto attach_failed; 864753790Sobrien 864853790Sobrien /* 8649178468Smarius * Allocate the CCBs. We need at least ONE. 865053790Sobrien */ 8651178468Smarius for (i = 0; sym_alloc_ccb(np) != NULL; i++) 8652178468Smarius ; 8653178468Smarius if (i < 1) 865453790Sobrien goto attach_failed; 865553790Sobrien 865653790Sobrien /* 8657178466Smarius * Calculate BUS addresses where we are going 865853790Sobrien * to load the SCRIPTS. 865953790Sobrien */ 866059292Sgroudier np->scripta_ba = vtobus(np->scripta0); 866159292Sgroudier np->scriptb_ba = vtobus(np->scriptb0); 866259292Sgroudier np->scriptb0_ba = np->scriptb_ba; 866353790Sobrien 866453790Sobrien if (np->ram_ba) { 866559292Sgroudier np->scripta_ba = np->ram_ba; 866653790Sobrien if (np->features & FE_RAM8K) { 866753790Sobrien np->ram_ws = 8192; 866859292Sgroudier np->scriptb_ba = np->scripta_ba + 4096; 8669153085Sru#ifdef __LP64__ 867059292Sgroudier np->scr_ram_seg = cpu_to_scr(np->scripta_ba >> 32); 8671153085Sru#endif 867253790Sobrien } 867353790Sobrien else 867453790Sobrien np->ram_ws = 4096; 867553790Sobrien } 867653790Sobrien 867753790Sobrien /* 867859743Sgroudier * Copy scripts to controller instance. 867953790Sobrien */ 868059743Sgroudier bcopy(fw->a_base, np->scripta0, np->scripta_sz); 868159743Sgroudier bcopy(fw->b_base, np->scriptb0, np->scriptb_sz); 868253790Sobrien 868353790Sobrien /* 868459743Sgroudier * Setup variable parts in scripts and compute 868559743Sgroudier * scripts bus addresses used from the C code. 868653790Sobrien */ 868759743Sgroudier np->fw_setup(np, fw); 868853790Sobrien 868953790Sobrien /* 8690178466Smarius * Bind SCRIPTS with physical addresses usable by the 869159743Sgroudier * SCRIPTS processor (as seen from the BUS = BUS addresses). 869253790Sobrien */ 869359743Sgroudier sym_fw_bind_script(np, (u32 *) np->scripta0, np->scripta_sz); 869459743Sgroudier sym_fw_bind_script(np, (u32 *) np->scriptb0, np->scriptb_sz); 869553793Sobrien 869654690Sobrien#ifdef SYM_CONF_IARB_SUPPORT 869753790Sobrien /* 8698178466Smarius * If user wants IARB to be set when we win arbitration 8699178466Smarius * and have other jobs, compute the max number of consecutive 8700178466Smarius * settings of IARB hints before we leave devices a chance to 870153790Sobrien * arbitrate for reselection. 870253790Sobrien */ 870354690Sobrien#ifdef SYM_SETUP_IARB_MAX 870454690Sobrien np->iarb_max = SYM_SETUP_IARB_MAX; 870553790Sobrien#else 870653790Sobrien np->iarb_max = 4; 870753790Sobrien#endif 870853790Sobrien#endif 870953790Sobrien 871053790Sobrien /* 871153790Sobrien * Prepare the idle and invalid task actions. 871253790Sobrien */ 871359292Sgroudier np->idletask.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 871459292Sgroudier np->idletask.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l)); 871553790Sobrien np->idletask_ba = vtobus(&np->idletask); 871653790Sobrien 871759292Sgroudier np->notask.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 871859292Sgroudier np->notask.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l)); 871953790Sobrien np->notask_ba = vtobus(&np->notask); 872053790Sobrien 872159292Sgroudier np->bad_itl.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 872259292Sgroudier np->bad_itl.restart = cpu_to_scr(SCRIPTB_BA (np, bad_i_t_l)); 872353790Sobrien np->bad_itl_ba = vtobus(&np->bad_itl); 872453790Sobrien 872559292Sgroudier np->bad_itlq.start = cpu_to_scr(SCRIPTA_BA (np, idle)); 872659292Sgroudier np->bad_itlq.restart = cpu_to_scr(SCRIPTB_BA (np,bad_i_t_l_q)); 872753790Sobrien np->bad_itlq_ba = vtobus(&np->bad_itlq); 872853790Sobrien 872953790Sobrien /* 8730178466Smarius * Allocate and prepare the lun JUMP table that is used 873153790Sobrien * for a target prior the probing of devices (bad lun table). 8732178466Smarius * A private table will be allocated for the target on the 873353790Sobrien * first INQUIRY response received. 873453790Sobrien */ 873558927Sgroudier np->badluntbl = sym_calloc_dma(256, "BADLUNTBL"); 873653790Sobrien if (!np->badluntbl) 873753790Sobrien goto attach_failed; 873853790Sobrien 873959292Sgroudier np->badlun_sa = cpu_to_scr(SCRIPTB_BA (np, resel_bad_lun)); 874053790Sobrien for (i = 0 ; i < 64 ; i++) /* 64 luns/target, no less */ 874153790Sobrien np->badluntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa)); 874253790Sobrien 874353790Sobrien /* 8744178466Smarius * Prepare the bus address array that contains the bus 874562422Sgroudier * address of each target control block. 874662422Sgroudier * For now, assume all logical units are wrong. :) 874753790Sobrien */ 874854690Sobrien for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 874953790Sobrien np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i])); 875059743Sgroudier np->target[i].head.luntbl_sa = 875159743Sgroudier cpu_to_scr(vtobus(np->badluntbl)); 875259743Sgroudier np->target[i].head.lun0_sa = 875359743Sgroudier cpu_to_scr(vtobus(&np->badlun_sa)); 875453790Sobrien } 875553790Sobrien 875653790Sobrien /* 875753790Sobrien * Now check the cache handling of the pci chipset. 875853790Sobrien */ 875953790Sobrien if (sym_snooptest (np)) { 876053790Sobrien device_printf(dev, "CACHE INCORRECTLY CONFIGURED.\n"); 876153790Sobrien goto attach_failed; 876253790Sobrien }; 876353790Sobrien 876453790Sobrien /* 876553790Sobrien * Now deal with CAM. 876653790Sobrien * Hopefully, we will succeed with that one.:) 876753790Sobrien */ 876853790Sobrien if (!sym_cam_attach(np)) 876953790Sobrien goto attach_failed; 877053790Sobrien 877153790Sobrien /* 877253790Sobrien * Sigh! we are done. 877353790Sobrien */ 877453790Sobrien return 0; 877553790Sobrien 877653790Sobrien /* 877753790Sobrien * We have failed. 8778178466Smarius * We will try to free all the resources we have 8779178466Smarius * allocated, but if we are a boot device, this 878053790Sobrien * will not help that much.;) 878153790Sobrien */ 878253790Sobrienattach_failed: 878353790Sobrien if (np) 878453790Sobrien sym_pci_free(np); 878553790Sobrien return ENXIO; 878653790Sobrien} 878753790Sobrien 878853790Sobrien/* 878953790Sobrien * Free everything that have been allocated for this device. 879053790Sobrien */ 879153790Sobrienstatic void sym_pci_free(hcb_p np) 879253790Sobrien{ 879355300Sgroudier SYM_QUEHEAD *qp; 879453790Sobrien ccb_p cp; 879553790Sobrien tcb_p tp; 879653790Sobrien lcb_p lp; 879753790Sobrien int target, lun; 879853790Sobrien 879953790Sobrien /* 880053790Sobrien * First free CAM resources. 880153790Sobrien */ 880253790Sobrien sym_cam_free(np); 880353790Sobrien 880453790Sobrien /* 8805178466Smarius * Now every should be quiet for us to 880653790Sobrien * free other resources. 880753790Sobrien */ 880853790Sobrien if (np->ram_res) 8809178466Smarius bus_release_resource(np->device, SYS_RES_MEMORY, 881053790Sobrien np->ram_id, np->ram_res); 881153790Sobrien if (np->mmio_res) 8812178466Smarius bus_release_resource(np->device, SYS_RES_MEMORY, 881353790Sobrien SYM_PCI_MMIO, np->mmio_res); 881453790Sobrien if (np->io_res) 8815178466Smarius bus_release_resource(np->device, SYS_RES_IOPORT, 881653790Sobrien SYM_PCI_IO, np->io_res); 881753790Sobrien if (np->irq_res) 8818178466Smarius bus_release_resource(np->device, SYS_RES_IRQ, 881953790Sobrien 0, np->irq_res); 882053790Sobrien 882159292Sgroudier if (np->scriptb0) 882259743Sgroudier sym_mfree_dma(np->scriptb0, np->scriptb_sz, "SCRIPTB0"); 882359292Sgroudier if (np->scripta0) 882459743Sgroudier sym_mfree_dma(np->scripta0, np->scripta_sz, "SCRIPTA0"); 882553790Sobrien if (np->squeue) 882658927Sgroudier sym_mfree_dma(np->squeue, sizeof(u32)*(MAX_QUEUE*2), "SQUEUE"); 882753790Sobrien if (np->dqueue) 882858927Sgroudier sym_mfree_dma(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE"); 882953790Sobrien 8830179029Smarius while ((qp = sym_remque_head(&np->free_ccbq)) != NULL) { 883155300Sgroudier cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 883258927Sgroudier bus_dmamap_destroy(np->data_dmat, cp->dmamap); 883358927Sgroudier sym_mfree_dma(cp->sns_bbuf, SYM_SNS_BBUF_LEN, "SNS_BBUF"); 883458927Sgroudier sym_mfree_dma(cp, sizeof(*cp), "CCB"); 883553790Sobrien } 883653790Sobrien 883753790Sobrien if (np->badluntbl) 883858927Sgroudier sym_mfree_dma(np->badluntbl, 256,"BADLUNTBL"); 883953790Sobrien 884054690Sobrien for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) { 884153790Sobrien tp = &np->target[target]; 884254690Sobrien for (lun = 0 ; lun < SYM_CONF_MAX_LUN ; lun++) { 8843251402Smarius lp = sym_lp(tp, lun); 884453790Sobrien if (!lp) 884553790Sobrien continue; 884653790Sobrien if (lp->itlq_tbl) 884758927Sgroudier sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, 884853790Sobrien "ITLQ_TBL"); 884953790Sobrien if (lp->cb_tags) 885054690Sobrien sym_mfree(lp->cb_tags, SYM_CONF_MAX_TASK, 885153790Sobrien "CB_TAGS"); 885258927Sgroudier sym_mfree_dma(lp, sizeof(*lp), "LCB"); 885353790Sobrien } 885454690Sobrien#if SYM_CONF_MAX_LUN > 1 885553790Sobrien if (tp->lunmp) 885654690Sobrien sym_mfree(tp->lunmp, SYM_CONF_MAX_LUN*sizeof(lcb_p), 885753790Sobrien "LUNMP"); 8858178466Smarius#endif 885953790Sobrien } 8860171524Sse#ifdef __amd64__ 8861171524Sse if (np->target) 8862171524Sse sym_mfree_dma(np->target, 8863171524Sse SYM_CONF_MAX_TARGET * sizeof(*(np->target)), "TARGET"); 8864171524Sse#endif 886558927Sgroudier if (np->targtbl) 886658927Sgroudier sym_mfree_dma(np->targtbl, 256, "TARGTBL"); 886758927Sgroudier if (np->data_dmat) 886858927Sgroudier bus_dma_tag_destroy(np->data_dmat); 8869178468Smarius if (SYM_LOCK_INITIALIZED() != 0) 8870178468Smarius SYM_LOCK_DESTROY(); 8871179029Smarius device_set_softc(np->device, NULL); 887258927Sgroudier sym_mfree_dma(np, sizeof(*np), "HCB"); 887353790Sobrien} 887453790Sobrien 887553790Sobrien/* 887653790Sobrien * Allocate CAM resources and register a bus to CAM. 887753790Sobrien */ 8878105215Sphkstatic int sym_cam_attach(hcb_p np) 887953790Sobrien{ 8880178466Smarius struct cam_devq *devq = NULL; 8881178466Smarius struct cam_sim *sim = NULL; 8882178466Smarius struct cam_path *path = NULL; 8883178468Smarius int err; 888453790Sobrien 888553790Sobrien /* 888653790Sobrien * Establish our interrupt handler. 888753790Sobrien */ 888873280Smarkm err = bus_setup_intr(np->device, np->irq_res, 8889178468Smarius INTR_ENTROPY | INTR_MPSAFE | INTR_TYPE_CAM, 8890178468Smarius NULL, sym_intr, np, &np->intr); 889153790Sobrien if (err) { 889253790Sobrien device_printf(np->device, "bus_setup_intr() failed: %d\n", 889353790Sobrien err); 889453790Sobrien goto fail; 889553790Sobrien } 889653790Sobrien 889753790Sobrien /* 889853790Sobrien * Create the device queue for our sym SIM. 889953790Sobrien */ 890054690Sobrien devq = cam_simq_alloc(SYM_CONF_MAX_START); 890153790Sobrien if (!devq) 890253790Sobrien goto fail; 890353790Sobrien 890453790Sobrien /* 890553790Sobrien * Construct our SIM entry. 890653790Sobrien */ 8907179029Smarius sim = cam_sim_alloc(sym_action, sym_poll, "sym", np, 8908179029Smarius device_get_unit(np->device), 8909178468Smarius &np->mtx, 1, SYM_SETUP_MAX_TAG, devq); 891053790Sobrien if (!sim) 891153790Sobrien goto fail; 891253790Sobrien 8913178468Smarius SYM_LOCK(); 8914178468Smarius 8915170872Sscottl if (xpt_bus_register(sim, np->device, 0) != CAM_SUCCESS) 891653790Sobrien goto fail; 891753790Sobrien np->sim = sim; 891853790Sobrien 8919251394Smarius if (xpt_create_path(&path, NULL, 892053790Sobrien cam_sim_path(np->sim), CAM_TARGET_WILDCARD, 892153790Sobrien CAM_LUN_WILDCARD) != CAM_REQ_CMP) { 892253790Sobrien goto fail; 892353790Sobrien } 892453790Sobrien np->path = path; 892553790Sobrien 892653793Sobrien /* 892753790Sobrien * Establish our async notification handler. 892853790Sobrien */ 8929183895Smarius if (xpt_register_async(AC_LOST_DEVICE, sym_async, sim, path) != 8930183895Smarius CAM_REQ_CMP) 8931183895Smarius goto fail; 893262134Sgroudier 893355300Sgroudier /* 8934178466Smarius * Start the chip now, without resetting the BUS, since 893555300Sgroudier * it seems that this must stay under control of CAM. 8936178466Smarius * With LVD/SE capable chips and BUS in SE mode, we may 893755300Sgroudier * get a spurious SMBC interrupt. 893855300Sgroudier */ 893955300Sgroudier sym_init (np, 0); 894053790Sobrien 8941178468Smarius SYM_UNLOCK(); 8942179029Smarius 894353790Sobrien return 1; 894453790Sobrienfail: 894553790Sobrien if (sim) 894653790Sobrien cam_sim_free(sim, FALSE); 894753790Sobrien if (devq) 894853790Sobrien cam_simq_free(devq); 894953790Sobrien 8950178468Smarius SYM_UNLOCK(); 8951178468Smarius 895253790Sobrien sym_cam_free(np); 895353790Sobrien 895453790Sobrien return 0; 895553790Sobrien} 895653790Sobrien 895753790Sobrien/* 895853790Sobrien * Free everything that deals with CAM. 895953790Sobrien */ 8960105215Sphkstatic void sym_cam_free(hcb_p np) 896153790Sobrien{ 8962251402Smarius 8963178468Smarius SYM_LOCK_ASSERT(MA_NOTOWNED); 8964178468Smarius 8965144147Ssam if (np->intr) { 896653790Sobrien bus_teardown_intr(np->device, np->irq_res, np->intr); 8967144147Ssam np->intr = NULL; 8968144147Ssam } 8969178466Smarius 8970178468Smarius SYM_LOCK(); 8971178468Smarius 897253790Sobrien if (np->sim) { 897353790Sobrien xpt_bus_deregister(cam_sim_path(np->sim)); 897453790Sobrien cam_sim_free(np->sim, /*free_devq*/ TRUE); 8975144147Ssam np->sim = NULL; 897653790Sobrien } 8977144147Ssam if (np->path) { 897853790Sobrien xpt_free_path(np->path); 8979144147Ssam np->path = NULL; 8980144147Ssam } 8981178468Smarius 8982178468Smarius SYM_UNLOCK(); 898353790Sobrien} 898453790Sobrien 898553790Sobrien/*============ OPTIONNAL NVRAM SUPPORT =================*/ 898653790Sobrien 898753790Sobrien/* 898853790Sobrien * Get host setup from NVRAM. 898953790Sobrien */ 899053790Sobrienstatic void sym_nvram_setup_host (hcb_p np, struct sym_nvram *nvram) 899153790Sobrien{ 899254690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 899353790Sobrien /* 8994178466Smarius * Get parity checking, host ID, verbose mode 899555628Sgroudier * and miscellaneous host flags from NVRAM. 899653790Sobrien */ 899753790Sobrien switch(nvram->type) { 899853790Sobrien case SYM_SYMBIOS_NVRAM: 899953790Sobrien if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE)) 900053790Sobrien np->rv_scntl0 &= ~0x0a; 900153790Sobrien np->myaddr = nvram->data.Symbios.host_id & 0x0f; 900253790Sobrien if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) 900353790Sobrien np->verbose += 1; 900455628Sgroudier if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO) 900555628Sgroudier np->usrflags |= SYM_SCAN_TARGETS_HILO; 900655628Sgroudier if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET) 900755628Sgroudier np->usrflags |= SYM_AVOID_BUS_RESET; 900853790Sobrien break; 900953790Sobrien case SYM_TEKRAM_NVRAM: 901053790Sobrien np->myaddr = nvram->data.Tekram.host_id & 0x0f; 901153790Sobrien break; 901253790Sobrien default: 901353790Sobrien break; 901453790Sobrien } 901553790Sobrien#endif 901653790Sobrien} 901753790Sobrien 901853790Sobrien/* 901953790Sobrien * Get target setup from NVRAM. 902053790Sobrien */ 902154690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 902253790Sobrienstatic void sym_Symbios_setup_target(hcb_p np,int target, Symbios_nvram *nvram); 902353790Sobrienstatic void sym_Tekram_setup_target(hcb_p np,int target, Tekram_nvram *nvram); 902453790Sobrien#endif 902553790Sobrien 902653790Sobrienstatic void 902753790Sobriensym_nvram_setup_target (hcb_p np, int target, struct sym_nvram *nvp) 902853790Sobrien{ 902954690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 903053790Sobrien switch(nvp->type) { 903153790Sobrien case SYM_SYMBIOS_NVRAM: 903253790Sobrien sym_Symbios_setup_target (np, target, &nvp->data.Symbios); 903353790Sobrien break; 903453790Sobrien case SYM_TEKRAM_NVRAM: 903553790Sobrien sym_Tekram_setup_target (np, target, &nvp->data.Tekram); 903653790Sobrien break; 903753790Sobrien default: 903853790Sobrien break; 903953790Sobrien } 904053790Sobrien#endif 904153790Sobrien} 904253790Sobrien 904354690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 904453790Sobrien/* 904553790Sobrien * Get target set-up from Symbios format NVRAM. 904653790Sobrien */ 904753790Sobrienstatic void 904853790Sobriensym_Symbios_setup_target(hcb_p np, int target, Symbios_nvram *nvram) 904953790Sobrien{ 905053790Sobrien tcb_p tp = &np->target[target]; 905153790Sobrien Symbios_target *tn = &nvram->target[target]; 905253790Sobrien 905353790Sobrien tp->tinfo.user.period = tn->sync_period ? (tn->sync_period + 3) / 4 : 0; 905453790Sobrien tp->tinfo.user.width = tn->bus_width == 0x10 ? BUS_16_BIT : BUS_8_BIT; 905553790Sobrien tp->usrtags = 905654690Sobrien (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0; 905753790Sobrien 905853790Sobrien if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE)) 905953790Sobrien tp->usrflags &= ~SYM_DISC_ENABLED; 906053790Sobrien if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)) 906153790Sobrien tp->usrflags |= SYM_SCAN_BOOT_DISABLED; 906253790Sobrien if (!(tn->flags & SYMBIOS_SCAN_LUNS)) 906353790Sobrien tp->usrflags |= SYM_SCAN_LUNS_DISABLED; 906453790Sobrien} 906553790Sobrien 906653790Sobrien/* 906753790Sobrien * Get target set-up from Tekram format NVRAM. 906853790Sobrien */ 906953790Sobrienstatic void 907053790Sobriensym_Tekram_setup_target(hcb_p np, int target, Tekram_nvram *nvram) 907153790Sobrien{ 907253790Sobrien tcb_p tp = &np->target[target]; 907353790Sobrien struct Tekram_target *tn = &nvram->target[target]; 907453790Sobrien int i; 907553790Sobrien 907653790Sobrien if (tn->flags & TEKRAM_SYNC_NEGO) { 907753790Sobrien i = tn->sync_index & 0xf; 907853790Sobrien tp->tinfo.user.period = Tekram_sync[i]; 907953790Sobrien } 908053790Sobrien 908153790Sobrien tp->tinfo.user.width = 908253790Sobrien (tn->flags & TEKRAM_WIDE_NEGO) ? BUS_16_BIT : BUS_8_BIT; 908353790Sobrien 908453790Sobrien if (tn->flags & TEKRAM_TAGGED_COMMANDS) { 908553790Sobrien tp->usrtags = 2 << nvram->max_tags_index; 908653790Sobrien } 908753790Sobrien 908853790Sobrien if (tn->flags & TEKRAM_DISCONNECT_ENABLE) 908953790Sobrien tp->usrflags |= SYM_DISC_ENABLED; 9090178466Smarius 909153790Sobrien /* If any device does not support parity, we will not use this option */ 909253790Sobrien if (!(tn->flags & TEKRAM_PARITY_CHECK)) 909353790Sobrien np->rv_scntl0 &= ~0x0a; /* SCSI parity checking disabled */ 909453790Sobrien} 909553790Sobrien 909654690Sobrien#ifdef SYM_CONF_DEBUG_NVRAM 909753790Sobrien/* 909853790Sobrien * Dump Symbios format NVRAM for debugging purpose. 909953790Sobrien */ 910061051Sgroudierstatic void sym_display_Symbios_nvram(hcb_p np, Symbios_nvram *nvram) 910153790Sobrien{ 910253790Sobrien int i; 910353790Sobrien 910453790Sobrien /* display Symbios nvram host data */ 910555628Sgroudier printf("%s: HOST ID=%d%s%s%s%s%s%s\n", 910653790Sobrien sym_name(np), nvram->host_id & 0x0f, 910753790Sobrien (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 910853790Sobrien (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", 9109178466Smarius (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", 9110178466Smarius (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", 911155628Sgroudier (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"", 911253790Sobrien (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); 911353790Sobrien 911453790Sobrien /* display Symbios nvram drive data */ 911553790Sobrien for (i = 0 ; i < 15 ; i++) { 911653790Sobrien struct Symbios_target *tn = &nvram->target[i]; 911753790Sobrien printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", 911853790Sobrien sym_name(np), i, 911953790Sobrien (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", 912053790Sobrien (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", 912153790Sobrien (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "", 912253790Sobrien (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "", 912353790Sobrien tn->bus_width, 912453790Sobrien tn->sync_period / 4, 912553790Sobrien tn->timeout); 912653790Sobrien } 912753790Sobrien} 912853790Sobrien 912953790Sobrien/* 913053790Sobrien * Dump TEKRAM format NVRAM for debugging purpose. 913153790Sobrien */ 9132179029Smariusstatic const u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120}; 913361051Sgroudierstatic void sym_display_Tekram_nvram(hcb_p np, Tekram_nvram *nvram) 913453790Sobrien{ 913553790Sobrien int i, tags, boot_delay; 913653790Sobrien char *rem; 913753790Sobrien 913853790Sobrien /* display Tekram nvram host data */ 913953790Sobrien tags = 2 << nvram->max_tags_index; 914053790Sobrien boot_delay = 0; 914153790Sobrien if (nvram->boot_delay_index < 6) 914253790Sobrien boot_delay = Tekram_boot_delay[nvram->boot_delay_index]; 914353790Sobrien switch((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) { 914453790Sobrien default: 914553790Sobrien case 0: rem = ""; break; 914653790Sobrien case 1: rem = " REMOVABLE=boot device"; break; 914753790Sobrien case 2: rem = " REMOVABLE=all"; break; 914853790Sobrien } 914953790Sobrien 915053790Sobrien printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", 915153790Sobrien sym_name(np), nvram->host_id & 0x0f, 915253790Sobrien (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", 915353790Sobrien (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES" :"", 915453790Sobrien (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"", 915553790Sobrien (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"", 915653790Sobrien (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"", 915753790Sobrien (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"", 915853790Sobrien (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"", 915953790Sobrien (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"", 916053790Sobrien rem, boot_delay, tags); 916153790Sobrien 916253790Sobrien /* display Tekram nvram drive data */ 916353790Sobrien for (i = 0; i <= 15; i++) { 916453790Sobrien int sync, j; 916553790Sobrien struct Tekram_target *tn = &nvram->target[i]; 916653790Sobrien j = tn->sync_index & 0xf; 916753790Sobrien sync = Tekram_sync[j]; 916853790Sobrien printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n", 916953790Sobrien sym_name(np), i, 917053790Sobrien (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", 917153790Sobrien (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", 917253790Sobrien (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "", 917353790Sobrien (tn->flags & TEKRAM_START_CMD) ? " START" : "", 917453790Sobrien (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "", 917553790Sobrien (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "", 917653790Sobrien sync); 917753790Sobrien } 917853790Sobrien} 917954690Sobrien#endif /* SYM_CONF_DEBUG_NVRAM */ 918054690Sobrien#endif /* SYM_CONF_NVRAM_SUPPORT */ 918153790Sobrien 918253790Sobrien/* 918353790Sobrien * Try reading Symbios or Tekram NVRAM 918453790Sobrien */ 918554690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 918653790Sobrienstatic int sym_read_Symbios_nvram (hcb_p np, Symbios_nvram *nvram); 918753790Sobrienstatic int sym_read_Tekram_nvram (hcb_p np, Tekram_nvram *nvram); 918853790Sobrien#endif 918953790Sobrien 9190105215Sphkstatic int sym_read_nvram(hcb_p np, struct sym_nvram *nvp) 919153790Sobrien{ 919254690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 919353790Sobrien /* 919453790Sobrien * Try to read SYMBIOS nvram. 919553790Sobrien * Try to read TEKRAM nvram if Symbios nvram not found. 919653790Sobrien */ 919754690Sobrien if (SYM_SETUP_SYMBIOS_NVRAM && 919861051Sgroudier !sym_read_Symbios_nvram (np, &nvp->data.Symbios)) { 919953790Sobrien nvp->type = SYM_SYMBIOS_NVRAM; 920061051Sgroudier#ifdef SYM_CONF_DEBUG_NVRAM 920161051Sgroudier sym_display_Symbios_nvram(np, &nvp->data.Symbios); 920261051Sgroudier#endif 920361051Sgroudier } 920454690Sobrien else if (SYM_SETUP_TEKRAM_NVRAM && 920561051Sgroudier !sym_read_Tekram_nvram (np, &nvp->data.Tekram)) { 920653790Sobrien nvp->type = SYM_TEKRAM_NVRAM; 920761051Sgroudier#ifdef SYM_CONF_DEBUG_NVRAM 920861051Sgroudier sym_display_Tekram_nvram(np, &nvp->data.Tekram); 920961051Sgroudier#endif 921061051Sgroudier } 921153790Sobrien else 921253790Sobrien nvp->type = 0; 921353790Sobrien#else 921453790Sobrien nvp->type = 0; 921553790Sobrien#endif 921653790Sobrien return nvp->type; 921753790Sobrien} 921853790Sobrien 921954690Sobrien#ifdef SYM_CONF_NVRAM_SUPPORT 922053790Sobrien/* 922153790Sobrien * 24C16 EEPROM reading. 922253790Sobrien * 922353790Sobrien * GPOI0 - data in/data out 922453790Sobrien * GPIO1 - clock 922553790Sobrien * Symbios NVRAM wiring now also used by Tekram. 922653790Sobrien */ 922753790Sobrien 922853790Sobrien#define SET_BIT 0 922953790Sobrien#define CLR_BIT 1 923053790Sobrien#define SET_CLK 2 923153790Sobrien#define CLR_CLK 3 923253790Sobrien 923353790Sobrien/* 923453790Sobrien * Set/clear data/clock bit in GPIO0 923553790Sobrien */ 9236178466Smariusstatic void S24C16_set_bit(hcb_p np, u_char write_bit, u_char *gpreg, 923753790Sobrien int bit_mode) 923853790Sobrien{ 923953790Sobrien UDELAY (5); 924053790Sobrien switch (bit_mode){ 924153790Sobrien case SET_BIT: 924253790Sobrien *gpreg |= write_bit; 924353790Sobrien break; 924453790Sobrien case CLR_BIT: 924553790Sobrien *gpreg &= 0xfe; 924653790Sobrien break; 924753790Sobrien case SET_CLK: 924853790Sobrien *gpreg |= 0x02; 924953790Sobrien break; 925053790Sobrien case CLR_CLK: 925153790Sobrien *gpreg &= 0xfd; 925253790Sobrien break; 925353790Sobrien 925453790Sobrien } 925553790Sobrien OUTB (nc_gpreg, *gpreg); 925653790Sobrien UDELAY (5); 925753790Sobrien} 925853790Sobrien 925953790Sobrien/* 926053790Sobrien * Send START condition to NVRAM to wake it up. 926153790Sobrien */ 926253790Sobrienstatic void S24C16_start(hcb_p np, u_char *gpreg) 926353790Sobrien{ 926453790Sobrien S24C16_set_bit(np, 1, gpreg, SET_BIT); 926553790Sobrien S24C16_set_bit(np, 0, gpreg, SET_CLK); 926653790Sobrien S24C16_set_bit(np, 0, gpreg, CLR_BIT); 926753790Sobrien S24C16_set_bit(np, 0, gpreg, CLR_CLK); 926853790Sobrien} 926953790Sobrien 927053790Sobrien/* 927153790Sobrien * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! 927253790Sobrien */ 927353790Sobrienstatic void S24C16_stop(hcb_p np, u_char *gpreg) 927453790Sobrien{ 927553790Sobrien S24C16_set_bit(np, 0, gpreg, SET_CLK); 927653790Sobrien S24C16_set_bit(np, 1, gpreg, SET_BIT); 927753790Sobrien} 927853790Sobrien 927953790Sobrien/* 928053790Sobrien * Read or write a bit to the NVRAM, 928153790Sobrien * read if GPIO0 input else write if GPIO0 output 928253790Sobrien */ 9283178466Smariusstatic void S24C16_do_bit(hcb_p np, u_char *read_bit, u_char write_bit, 928453790Sobrien u_char *gpreg) 928553790Sobrien{ 928653790Sobrien S24C16_set_bit(np, write_bit, gpreg, SET_BIT); 928753790Sobrien S24C16_set_bit(np, 0, gpreg, SET_CLK); 928853790Sobrien if (read_bit) 928953790Sobrien *read_bit = INB (nc_gpreg); 929053790Sobrien S24C16_set_bit(np, 0, gpreg, CLR_CLK); 929153790Sobrien S24C16_set_bit(np, 0, gpreg, CLR_BIT); 929253790Sobrien} 929353790Sobrien 929453790Sobrien/* 929553790Sobrien * Output an ACK to the NVRAM after reading, 929653790Sobrien * change GPIO0 to output and when done back to an input 929753790Sobrien */ 9298178466Smariusstatic void S24C16_write_ack(hcb_p np, u_char write_bit, u_char *gpreg, 929953790Sobrien u_char *gpcntl) 930053790Sobrien{ 930153790Sobrien OUTB (nc_gpcntl, *gpcntl & 0xfe); 930253790Sobrien S24C16_do_bit(np, 0, write_bit, gpreg); 930353790Sobrien OUTB (nc_gpcntl, *gpcntl); 930453790Sobrien} 930553790Sobrien 930653790Sobrien/* 930753790Sobrien * Input an ACK from NVRAM after writing, 930853790Sobrien * change GPIO0 to input and when done back to an output 930953790Sobrien */ 9310178466Smariusstatic void S24C16_read_ack(hcb_p np, u_char *read_bit, u_char *gpreg, 931153790Sobrien u_char *gpcntl) 931253790Sobrien{ 931353790Sobrien OUTB (nc_gpcntl, *gpcntl | 0x01); 931453790Sobrien S24C16_do_bit(np, read_bit, 1, gpreg); 931553790Sobrien OUTB (nc_gpcntl, *gpcntl); 931653790Sobrien} 931753790Sobrien 931853790Sobrien/* 931953790Sobrien * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, 932053790Sobrien * GPIO0 must already be set as an output 932153790Sobrien */ 9322178466Smariusstatic void S24C16_write_byte(hcb_p np, u_char *ack_data, u_char write_data, 932353790Sobrien u_char *gpreg, u_char *gpcntl) 932453790Sobrien{ 932553790Sobrien int x; 9326178466Smarius 932753790Sobrien for (x = 0; x < 8; x++) 932853790Sobrien S24C16_do_bit(np, 0, (write_data >> (7 - x)) & 0x01, gpreg); 9329178466Smarius 933053790Sobrien S24C16_read_ack(np, ack_data, gpreg, gpcntl); 933153790Sobrien} 933253790Sobrien 933353790Sobrien/* 933453790Sobrien * READ a byte from the NVRAM and then send an ACK to say we have got it, 933553790Sobrien * GPIO0 must already be set as an input 933653790Sobrien */ 9337178466Smariusstatic void S24C16_read_byte(hcb_p np, u_char *read_data, u_char ack_data, 933853790Sobrien u_char *gpreg, u_char *gpcntl) 933953790Sobrien{ 934053790Sobrien int x; 934153790Sobrien u_char read_bit; 934253790Sobrien 934353790Sobrien *read_data = 0; 934453790Sobrien for (x = 0; x < 8; x++) { 934553790Sobrien S24C16_do_bit(np, &read_bit, 1, gpreg); 934653790Sobrien *read_data |= ((read_bit & 0x01) << (7 - x)); 934753790Sobrien } 934853790Sobrien 934953790Sobrien S24C16_write_ack(np, ack_data, gpreg, gpcntl); 935053790Sobrien} 935153790Sobrien 935253790Sobrien/* 935353790Sobrien * Read 'len' bytes starting at 'offset'. 935453790Sobrien */ 935553790Sobrienstatic int sym_read_S24C16_nvram (hcb_p np, int offset, u_char *data, int len) 935653790Sobrien{ 935753790Sobrien u_char gpcntl, gpreg; 935853790Sobrien u_char old_gpcntl, old_gpreg; 935953790Sobrien u_char ack_data; 936053790Sobrien int retv = 1; 936153790Sobrien int x; 936253790Sobrien 936353790Sobrien /* save current state of GPCNTL and GPREG */ 936453790Sobrien old_gpreg = INB (nc_gpreg); 936553790Sobrien old_gpcntl = INB (nc_gpcntl); 936679042Sgroudier gpcntl = old_gpcntl & 0x1c; 936753790Sobrien 936853790Sobrien /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ 936953790Sobrien OUTB (nc_gpreg, old_gpreg); 937053790Sobrien OUTB (nc_gpcntl, gpcntl); 937153790Sobrien 937253790Sobrien /* this is to set NVRAM into a known state with GPIO0/1 both low */ 937353790Sobrien gpreg = old_gpreg; 937453790Sobrien S24C16_set_bit(np, 0, &gpreg, CLR_CLK); 937553790Sobrien S24C16_set_bit(np, 0, &gpreg, CLR_BIT); 9376178466Smarius 937753790Sobrien /* now set NVRAM inactive with GPIO0/1 both high */ 937853790Sobrien S24C16_stop(np, &gpreg); 9379178466Smarius 938053790Sobrien /* activate NVRAM */ 938153790Sobrien S24C16_start(np, &gpreg); 938253790Sobrien 938353790Sobrien /* write device code and random address MSB */ 938453790Sobrien S24C16_write_byte(np, &ack_data, 938553790Sobrien 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 938653790Sobrien if (ack_data & 0x01) 938753790Sobrien goto out; 938853790Sobrien 938953790Sobrien /* write random address LSB */ 939053790Sobrien S24C16_write_byte(np, &ack_data, 939155300Sgroudier offset & 0xff, &gpreg, &gpcntl); 939253790Sobrien if (ack_data & 0x01) 939353790Sobrien goto out; 939453790Sobrien 939553790Sobrien /* regenerate START state to set up for reading */ 939653790Sobrien S24C16_start(np, &gpreg); 9397178466Smarius 939853790Sobrien /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ 939953790Sobrien S24C16_write_byte(np, &ack_data, 940053790Sobrien 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); 940153790Sobrien if (ack_data & 0x01) 940253790Sobrien goto out; 940353790Sobrien 940453790Sobrien /* now set up GPIO0 for inputting data */ 940553790Sobrien gpcntl |= 0x01; 940653790Sobrien OUTB (nc_gpcntl, gpcntl); 9407178466Smarius 940853790Sobrien /* input all requested data - only part of total NVRAM */ 9409178466Smarius for (x = 0; x < len; x++) 941053790Sobrien S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl); 941153790Sobrien 941253790Sobrien /* finally put NVRAM back in inactive mode */ 941353790Sobrien gpcntl &= 0xfe; 941453790Sobrien OUTB (nc_gpcntl, gpcntl); 941553790Sobrien S24C16_stop(np, &gpreg); 941653790Sobrien retv = 0; 941753790Sobrienout: 941853790Sobrien /* return GPIO0/1 to original states after having accessed NVRAM */ 941953790Sobrien OUTB (nc_gpcntl, old_gpcntl); 942053790Sobrien OUTB (nc_gpreg, old_gpreg); 942153790Sobrien 942253790Sobrien return retv; 942353790Sobrien} 942453790Sobrien 942587796Sjhb#undef SET_BIT /* 0 */ 942687796Sjhb#undef CLR_BIT /* 1 */ 942787796Sjhb#undef SET_CLK /* 2 */ 942887796Sjhb#undef CLR_CLK /* 3 */ 942953790Sobrien 943053790Sobrien/* 943153790Sobrien * Try reading Symbios NVRAM. 943253790Sobrien * Return 0 if OK. 943353790Sobrien */ 943453790Sobrienstatic int sym_read_Symbios_nvram (hcb_p np, Symbios_nvram *nvram) 943553790Sobrien{ 943653790Sobrien static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; 943753790Sobrien u_char *data = (u_char *) nvram; 943853790Sobrien int len = sizeof(*nvram); 943953790Sobrien u_short csum; 944053790Sobrien int x; 944153790Sobrien 944253790Sobrien /* probe the 24c16 and read the SYMBIOS 24c16 area */ 944353790Sobrien if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len)) 944453790Sobrien return 1; 944553790Sobrien 944653790Sobrien /* check valid NVRAM signature, verify byte count and checksum */ 944753790Sobrien if (nvram->type != 0 || 944853796Sobrien bcmp(nvram->trailer, Symbios_trailer, 6) || 944953790Sobrien nvram->byte_count != len - 12) 945053790Sobrien return 1; 945153790Sobrien 945253790Sobrien /* verify checksum */ 945353790Sobrien for (x = 6, csum = 0; x < len - 6; x++) 945453790Sobrien csum += data[x]; 945553790Sobrien if (csum != nvram->checksum) 945653790Sobrien return 1; 945753790Sobrien 945853790Sobrien return 0; 945953790Sobrien} 946053790Sobrien 946153790Sobrien/* 946253790Sobrien * 93C46 EEPROM reading. 946353790Sobrien * 946453790Sobrien * GPOI0 - data in 946553790Sobrien * GPIO1 - data out 946653790Sobrien * GPIO2 - clock 946753790Sobrien * GPIO4 - chip select 946853790Sobrien * 946953790Sobrien * Used by Tekram. 947053790Sobrien */ 947153790Sobrien 947253790Sobrien/* 947353790Sobrien * Pulse clock bit in GPIO0 947453790Sobrien */ 947553790Sobrienstatic void T93C46_Clk(hcb_p np, u_char *gpreg) 947653790Sobrien{ 947753790Sobrien OUTB (nc_gpreg, *gpreg | 0x04); 947853790Sobrien UDELAY (2); 947953790Sobrien OUTB (nc_gpreg, *gpreg); 948053790Sobrien} 948153790Sobrien 9482178466Smarius/* 948353790Sobrien * Read bit from NVRAM 948453790Sobrien */ 948553790Sobrienstatic void T93C46_Read_Bit(hcb_p np, u_char *read_bit, u_char *gpreg) 948653790Sobrien{ 948753790Sobrien UDELAY (2); 948853790Sobrien T93C46_Clk(np, gpreg); 948953790Sobrien *read_bit = INB (nc_gpreg); 949053790Sobrien} 949153790Sobrien 949253790Sobrien/* 949353790Sobrien * Write bit to GPIO0 949453790Sobrien */ 949553790Sobrienstatic void T93C46_Write_Bit(hcb_p np, u_char write_bit, u_char *gpreg) 949653790Sobrien{ 949753790Sobrien if (write_bit & 0x01) 949853790Sobrien *gpreg |= 0x02; 949953790Sobrien else 950053790Sobrien *gpreg &= 0xfd; 9501178466Smarius 950253790Sobrien *gpreg |= 0x10; 9503178466Smarius 950453790Sobrien OUTB (nc_gpreg, *gpreg); 950553790Sobrien UDELAY (2); 950653790Sobrien 950753790Sobrien T93C46_Clk(np, gpreg); 950853790Sobrien} 950953790Sobrien 951053790Sobrien/* 951153790Sobrien * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! 951253790Sobrien */ 951353790Sobrienstatic void T93C46_Stop(hcb_p np, u_char *gpreg) 951453790Sobrien{ 951553790Sobrien *gpreg &= 0xef; 951653790Sobrien OUTB (nc_gpreg, *gpreg); 951753790Sobrien UDELAY (2); 951853790Sobrien 951953790Sobrien T93C46_Clk(np, gpreg); 952053790Sobrien} 952153790Sobrien 952253790Sobrien/* 952353790Sobrien * Send read command and address to NVRAM 952453790Sobrien */ 9525178466Smariusstatic void T93C46_Send_Command(hcb_p np, u_short write_data, 952653790Sobrien u_char *read_bit, u_char *gpreg) 952753790Sobrien{ 952853790Sobrien int x; 952953790Sobrien 953053790Sobrien /* send 9 bits, start bit (1), command (2), address (6) */ 953153790Sobrien for (x = 0; x < 9; x++) 953253790Sobrien T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); 953353790Sobrien 953453790Sobrien *read_bit = INB (nc_gpreg); 953553790Sobrien} 953653790Sobrien 953753790Sobrien/* 953853790Sobrien * READ 2 bytes from the NVRAM 953953790Sobrien */ 954053790Sobrienstatic void T93C46_Read_Word(hcb_p np, u_short *nvram_data, u_char *gpreg) 954153790Sobrien{ 954253790Sobrien int x; 954353790Sobrien u_char read_bit; 954453790Sobrien 954553790Sobrien *nvram_data = 0; 954653790Sobrien for (x = 0; x < 16; x++) { 954753790Sobrien T93C46_Read_Bit(np, &read_bit, gpreg); 954853790Sobrien 954953790Sobrien if (read_bit & 0x01) 955053790Sobrien *nvram_data |= (0x01 << (15 - x)); 955153790Sobrien else 955253790Sobrien *nvram_data &= ~(0x01 << (15 - x)); 955353790Sobrien } 955453790Sobrien} 955553790Sobrien 955653790Sobrien/* 955753790Sobrien * Read Tekram NvRAM data. 955853790Sobrien */ 955953790Sobrienstatic int T93C46_Read_Data(hcb_p np, u_short *data,int len,u_char *gpreg) 956053790Sobrien{ 956153790Sobrien u_char read_bit; 956253790Sobrien int x; 956353790Sobrien 956453790Sobrien for (x = 0; x < len; x++) { 956553790Sobrien 956653790Sobrien /* output read command and address */ 956753790Sobrien T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg); 956853790Sobrien if (read_bit & 0x01) 956953790Sobrien return 1; /* Bad */ 957053790Sobrien T93C46_Read_Word(np, &data[x], gpreg); 957153790Sobrien T93C46_Stop(np, gpreg); 957253790Sobrien } 957353790Sobrien 957453790Sobrien return 0; 957553790Sobrien} 957653790Sobrien 957753790Sobrien/* 957853790Sobrien * Try reading 93C46 Tekram NVRAM. 957953790Sobrien */ 958053790Sobrienstatic int sym_read_T93C46_nvram (hcb_p np, Tekram_nvram *nvram) 958153790Sobrien{ 958253790Sobrien u_char gpcntl, gpreg; 958353790Sobrien u_char old_gpcntl, old_gpreg; 958453790Sobrien int retv = 1; 958553790Sobrien 958653790Sobrien /* save current state of GPCNTL and GPREG */ 958753790Sobrien old_gpreg = INB (nc_gpreg); 958853790Sobrien old_gpcntl = INB (nc_gpcntl); 958953790Sobrien 959053790Sobrien /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, 959153790Sobrien 1/2/4 out */ 959253790Sobrien gpreg = old_gpreg & 0xe9; 959353790Sobrien OUTB (nc_gpreg, gpreg); 959453790Sobrien gpcntl = (old_gpcntl & 0xe9) | 0x09; 959553790Sobrien OUTB (nc_gpcntl, gpcntl); 959653790Sobrien 959753790Sobrien /* input all of NVRAM, 64 words */ 959853790Sobrien retv = T93C46_Read_Data(np, (u_short *) nvram, 959953790Sobrien sizeof(*nvram) / sizeof(short), &gpreg); 9600178466Smarius 960153790Sobrien /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ 960253790Sobrien OUTB (nc_gpcntl, old_gpcntl); 960353790Sobrien OUTB (nc_gpreg, old_gpreg); 960453790Sobrien 960553790Sobrien return retv; 960653790Sobrien} 960753790Sobrien 960853790Sobrien/* 960953790Sobrien * Try reading Tekram NVRAM. 961053790Sobrien * Return 0 if OK. 961153790Sobrien */ 961253790Sobrienstatic int sym_read_Tekram_nvram (hcb_p np, Tekram_nvram *nvram) 961353790Sobrien{ 961453790Sobrien u_char *data = (u_char *) nvram; 961553790Sobrien int len = sizeof(*nvram); 961653790Sobrien u_short csum; 961753790Sobrien int x; 961853790Sobrien 961953790Sobrien switch (np->device_id) { 962053790Sobrien case PCI_ID_SYM53C885: 962153790Sobrien case PCI_ID_SYM53C895: 962253790Sobrien case PCI_ID_SYM53C896: 962353790Sobrien x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 962453790Sobrien data, len); 962553790Sobrien break; 962653790Sobrien case PCI_ID_SYM53C875: 962753790Sobrien x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, 962853790Sobrien data, len); 962953790Sobrien if (!x) 963053790Sobrien break; 963153790Sobrien default: 963253790Sobrien x = sym_read_T93C46_nvram(np, nvram); 963353790Sobrien break; 963453790Sobrien } 963553790Sobrien if (x) 963653790Sobrien return 1; 963753790Sobrien 963853790Sobrien /* verify checksum */ 963953790Sobrien for (x = 0, csum = 0; x < len - 1; x += 2) 964053790Sobrien csum += data[x] + (data[x+1] << 8); 964153790Sobrien if (csum != 0x1234) 964253790Sobrien return 1; 964353790Sobrien 964453790Sobrien return 0; 964553790Sobrien} 964653790Sobrien 964754690Sobrien#endif /* SYM_CONF_NVRAM_SUPPORT */ 9648