📄 sd53c8xx.c
字号:
/* * NCR 53c8xx driver for Plan 9 * Nigel Roles (ngr@cotswold.demon.co.uk) * * 08/07/99 Ultra2 fixed. Brazil #ifdefs added. Fixed script error 6 diagnostics. * * 09/06/99 Enhancements to support 895 and 896 correctly. Attempt at Ultra 2 negotiation, * though no device to test with yet. * Variant now contains the number of valid chip registers to assist * dumpncrregs() * * 06/10/98 Various bug fixes and Brazil compiler inspired changes from jmk * * 05/10/98 Small fix to handle command length being greater than expected by device * * 04/08/98 Added missing locks to interrupt handler. Marked places where * multiple controller extensions could go * * 18/05/97 Fixed overestimate in size of local SCRIPT RAM * * 17/05/97 Bug fix to return status * * 06/10/96 Enhanced list of chip IDs. 875 revision 1 has no clock doubler, so assume it * is shipped with 80MHz crystal. Use bit 3 of the GPREG to recognise differential * boards. This is Symbios specific, but since they are about the only suppliers of * differential cards. * * 23/9/96 Wide and Ultra supported. 825A and 860 added to variants. Dual compiling * version for fileserver and cpu. 80MHz default clock for 860 * * 5/8/96 Waits for an Inquiry message before initiating synchronous negotiation * in case capabilities byte [7] indicates device does not support it. Devices * which do target initiated negotiation will typically get in first; a few * bugs in handling this have been fixed * * 3/8/96 Added differential support (put scsi0=diff in plan9.ini) * Split exec() into exec() and io(). Exec() is small, and Io() does not * use any Plan 9 specific data structures, so alternate exec() functions * may be done for other environments, such as the fileserver * * GENERAL * * Works on 810 and 875 * Should work on 815, 825, 810A, 825A, 860A * Uses local RAM, large FIFO, prefetch, burst opcode fetch, and 16 byte synch. offset * where applicable * Supports multi-target, wide, Ultra * Differential mode can be enabled by putting scsi0=diff in plan9.ini * NO SUPPORT FOR tagged queuing (yet) * * Known problems */#define MAXTARGET 16 /* can be 8 or 16 */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "sd.h"extern SDifc sd53c8xxifc;/**********************************//* Portable configuration macros *//**********************************///#define BOOTDEBUG//#define ASYNC_ONLY//#define INTERNAL_SCLK//#define ALWAYS_DO_WDTR#define WMR_DEBUG/**********************************//* CPU specific macros *//**********************************/#ifdef BOOTDEBUG#define KPRINT oprint#define IPRINT intrprint#define DEBUG(n) 0#define IFLUSH() iflush()#else#define KPRINT if(0)print#define IPRINT if(0)print#define DEBUG(n) (0)#define IFLUSH()#endif /* BOOTDEBUG *//*******************************//* General *//*******************************/#ifndef DMASEG#define DMASEG(x) PADDR(x)#define legetl(x) (*(ulong*)(x))#define lesetl(x,v) (*(ulong*)(x) = (v))#define swabl(a,b,c)#else#endif /*DMASEG */#define DMASEG_TO_KADDR(x) KADDR(PADDR(x))#define KPTR(x) ((x) == 0 ? 0 : DMASEG_TO_KADDR(x))#define MEGA 1000000L#ifdef INTERNAL_SCLK#define SCLK (33 * MEGA)#else#define SCLK (40 * MEGA)#endif /* INTERNAL_SCLK */#define ULTRA_NOCLOCKDOUBLE_SCLK (80 * MEGA)#define MAXSYNCSCSIRATE (5 * MEGA)#define MAXFASTSYNCSCSIRATE (10 * MEGA)#define MAXULTRASYNCSCSIRATE (20 * MEGA)#define MAXULTRA2SYNCSCSIRATE (40 * MEGA)#define MAXASYNCCORERATE (25 * MEGA)#define MAXSYNCCORERATE (25 * MEGA)#define MAXFASTSYNCCORERATE (50 * MEGA)#define MAXULTRASYNCCORERATE (80 * MEGA)#define MAXULTRA2SYNCCORERATE (160 * MEGA)#define X_MSG 1#define X_MSG_SDTR 1#define X_MSG_WDTR 3struct na_patch { unsigned lwoff; unsigned char type;};typedef struct Ncr { uchar scntl0; /* 00 */ uchar scntl1; uchar scntl2; uchar scntl3; uchar scid; /* 04 */ uchar sxfer; uchar sdid; uchar gpreg; uchar sfbr; /* 08 */ uchar socl; uchar ssid; uchar sbcl; uchar dstat; /* 0c */ uchar sstat0; uchar sstat1; uchar sstat2; uchar dsa[4]; /* 10 */ uchar istat; /* 14 */ uchar istatpad[3]; uchar ctest0; /* 18 */ uchar ctest1; uchar ctest2; uchar ctest3; uchar temp[4]; /* 1c */ uchar dfifo; /* 20 */ uchar ctest4; uchar ctest5; uchar ctest6; uchar dbc[3]; /* 24 */ uchar dcmd; /* 27 */ uchar dnad[4]; /* 28 */ uchar dsp[4]; /* 2c */ uchar dsps[4]; /* 30 */ uchar scratcha[4]; /* 34 */ uchar dmode; /* 38 */ uchar dien; uchar dwt; uchar dcntl; uchar adder[4]; /* 3c */ uchar sien0; /* 40 */ uchar sien1; uchar sist0; uchar sist1; uchar slpar; /* 44 */ uchar slparpad0; uchar macntl; uchar gpcntl; uchar stime0; /* 48 */ uchar stime1; uchar respid; uchar respidpad0; uchar stest0; /* 4c */ uchar stest1; uchar stest2; uchar stest3; uchar sidl; /* 50 */ uchar sidlpad[3]; uchar sodl; /* 54 */ uchar sodlpad[3]; uchar sbdl; /* 58 */ uchar sbdlpad[3]; uchar scratchb[4]; /* 5c */} Ncr;typedef struct Movedata { uchar dbc[4]; uchar pa[4];} Movedata;typedef enum NegoState { NeitherDone, WideInit, WideResponse, WideDone, SyncInit, SyncResponse, BothDone} NegoState;typedef enum State { Allocated, Queued, Active, Done} State;typedef struct Dsa { union { uchar state[4]; struct { uchar stateb; uchar result; uchar dmablks; uchar flag; /* setbyte(state,3,...) */ }; }; union { ulong dmancr; /* For block transfer: NCR order (little-endian) */ uchar dmaaddr[4]; }; uchar target; /* Target */ uchar pad0[3]; uchar lun; /* Logical Unit Number */ uchar pad1[3]; uchar scntl3; uchar sxfer; uchar pad2[2]; uchar next[4]; /* chaining for SCRIPT (NCR byte order) */ struct Dsa *freechain; /* chaining for freelist */ Rendez; uchar scsi_id_buf[4]; Movedata msg_out_buf; Movedata cmd_buf; Movedata data_buf; Movedata status_buf; uchar msg_out[10]; /* enough to include SDTR */ uchar status; int p9status; uchar parityerror;} Dsa;typedef enum Feature { BigFifo = 1, /* 536 byte fifo */ BurstOpCodeFetch = 2, /* burst fetch opcodes */ Prefetch = 4, /* prefetch 8 longwords */ LocalRAM = 8, /* 4K longwords of local RAM */ Differential = 16, /* Differential support */ Wide = 32, /* Wide capable */ Ultra = 64, /* Ultra capable */ ClockDouble = 128, /* Has clock doubler */ ClockQuad = 256, /* Has clock quadrupler (same as Ultra2) */ Ultra2 = 256,} Feature;typedef enum Burst { Burst2 = 0, Burst4 = 1, Burst8 = 2, Burst16 = 3, Burst32 = 4, Burst64 = 5, Burst128 = 6} Burst;typedef struct Variant { ushort did; uchar maxrid; /* maximum allowed revision ID */ char *name; Burst burst; /* codings for max burst */ uchar maxsyncoff; /* max synchronous offset */ uchar registers; /* number of 32 bit registers */ unsigned feature;} Variant;static unsigned char cf2[] = { 6, 2, 3, 4, 6, 8, 12, 16 };#define NULTRA2SCF (sizeof(cf2)/sizeof(cf2[0]))#define NULTRASCF (NULTRA2SCF - 2)#define NSCF (NULTRASCF - 1)typedef struct Controller { Lock; uchar synctab[NULTRA2SCF - 1][8];/* table of legal tpfs */ NegoState s[MAXTARGET]; uchar scntl3[MAXTARGET]; uchar sxfer[MAXTARGET]; uchar cap[MAXTARGET]; /* capabilities byte from Identify */ ushort capvalid; /* bit per target for validity of cap[] */ ushort wide; /* bit per target set if wide negotiated */ ulong sclk; /* clock speed of controller */ uchar clockmult; /* set by synctabinit */ uchar ccf; /* CCF bits */ uchar tpf; /* best tpf value for this controller */ uchar feature; /* requested features */ int running; /* is the script processor running? */ int ssm; /* single step mode */ Ncr *n; /* pointer to registers */ Variant *v; /* pointer to variant type */ ulong *script; /* where the real script is */ ulong scriptpa; /* where the real script is */ Pcidev* pcidev; SDev* sdev; struct { Lock; uchar head[4]; /* head of free list (NCR byte order) */ Dsa *tail; Dsa *free; } dsalist; QLock q[MAXTARGET]; /* queues for each target */} Controller;static Controller controller;/* ISTAT */enum { Abrt = 0x80, Srst = 0x40, Sigp = 0x20, Sem = 0x10, Con = 0x08, Intf = 0x04, Sip = 0x02, Dip = 0x01 };/* DSTAT */enum { Dfe = 0x80, Mdpe = 0x40, Bf = 0x20, Abrted = 0x10, Ssi = 0x08, Sir = 0x04, Iid = 0x01 };/* SSTAT */enum { DataOut, DataIn, Cmd, Status, ReservedOut, ReservedIn, MessageOut, MessageIn };static void setmovedata(Movedata*, ulong, ulong);static void advancedata(Movedata*, long);static char *phase[] = { "data out", "data in", "command", "status", "reserved out", "reserved in", "message out", "message in"};#ifdef BOOTDEBUG#define DEBUGSIZE 10240char debugbuf[DEBUGSIZE];char *debuglast;static voidintrprint(char *format, ...){ if (debuglast == 0) debuglast = debugbuf; debuglast = doprint(debuglast, debugbuf + (DEBUGSIZE - 1), format, (&format + 1));}static voidiflush(){ int s; char *endp; s = splhi(); if (debuglast == 0) debuglast = debugbuf; if (debuglast == debugbuf) { splx(s); return; } endp = debuglast; splx(s); screenputs(debugbuf, endp - debugbuf); s = splhi(); memmove(debugbuf, endp, debuglast - endp); debuglast -= endp - debugbuf; splx(s);}static voidoprint(char *format, ...){ int s; iflush(); s = splhi(); if (debuglast == 0) debuglast = debugbuf; debuglast = doprint(debuglast, debugbuf + (DEBUGSIZE - 1), format, (&format + 1)); splx(s); iflush(); }#endif#include "sd53c8xx.i"static Dsa *dsaalloc(Controller *c, int target, int lun){ Dsa *d; ilock(&c->dsalist); if ((d = c->dsalist.free) == 0) { d = xalloc(sizeof(*d)); if (DEBUG(1)) KPRINT("sd53c8xx: %d/%d: allocated new dsa %lux\n", target, lun, d); lesetl(d->next, 0); lesetl(d->state, A_STATE_ALLOCATED); if (legetl(c->dsalist.head) == 0) lesetl(c->dsalist.head, DMASEG(d)); /* ATOMIC?!? */ else lesetl(c->dsalist.tail->next, DMASEG(d)); /* ATOMIC?!? */ c->dsalist.tail = d; } else { if (DEBUG(1)) KPRINT("sd53c8xx: %d/%d: reused dsa %lux\n", target, lun, d); c->dsalist.free = d->freechain; lesetl(d->state, A_STATE_ALLOCATED); } iunlock(&c->dsalist); d->target = target; d->lun = lun; return d;}static voiddsafree(Controller *c, Dsa *d){ ilock(&c->dsalist); d->freechain = c->dsalist.free; c->dsalist.free = d; lesetl(d->state, A_STATE_FREE); iunlock(&c->dsalist);}static Dsa *dsafind(Controller *c, uchar target, uchar lun, uchar state){ Dsa *d; for (d = KPTR(legetl(c->dsalist.head)); d; d = KPTR(legetl(d->next))) { if (d->target != 0xff && d->target != target) continue; if (lun != 0xff && d->lun != lun) continue; if (state != 0xff && d->stateb != state) continue; break; } return d;}static voiddumpncrregs(Controller *c, int intr){ int i; Ncr *n = c->n; int depth = c->v->registers / 4; KPRINT("sa = %.8lux\n", c->scriptpa); for (i = 0; i < depth; i++) { int j; for (j = 0; j < 4; j++) { int k = j * depth + i; uchar *p; /* display little-endian to make 32-bit values readable */ p = (uchar*)n+k*4; if (intr) IPRINT(" %.2x%.2x%.2x%.2x %.2x %.2x", p[3], p[2], p[1], p[0], k * 4, (k * 4) + 0x80); else KPRINT(" %.2x%.2x%.2x%.2x %.2x %.2x", p[3], p[2], p[1], p[0], k * 4, (k * 4) + 0x80); USED(p); } if (intr) IPRINT("\n"); else KPRINT("\n"); }} static intchooserate(Controller *c, int tpf, int *scfp, int *xferpp){ /* find lowest entry >= tpf */ int besttpf = 1000; int bestscfi = 0; int bestxferp = 0; int scf, xferp; int maxscf; if (c->v->feature & Ultra2) maxscf = NULTRA2SCF; else if (c->v->feature & Ultra) maxscf = NULTRASCF;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -