⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdmv50xx.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Marvell 88SX5040, 5041, 5080, 5081 driver * This is a heavily-modified version of a driver written by Coraid, Inc. * The original copyright notice appears at the end of this file. */ #include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include 	"io.h"#include	"../port/error.h"#include	"../port/sd.h"#define DPRINT	if(0)iprintenum {	SrbRing = 32,		/* Addresses of ATA register */	ARcmd		= 027,	ARdev		= 026,	ARerr		= 021,	ARfea		= 021,	ARlba2		= 025,	ARlba1		= 024,	ARlba0		= 023,	ARseccnt		= 022,	ARstat		= 027,		ATAerr	= (1<<0),	ATAdrq	= (1<<3),	ATAdf 	= (1<<5),	ATAdrdy 	= (1<<6),	ATAbusy 	= (1<<7),	ATAabort	= (1<<2),	ATAeIEN	= (1<<1),	ATAsrst	= (1<<2),	ATAhob	= (1<<7),	SFdone = (1<<0),	SFerror = (1<<1),	SRBident = 0,	SRBread,	SRBwrite,	SRBsmart,	SRBnodata = 0,	SRBdatain,	SRBdataout,		RQread	= 1,			/* data coming IN from device */		PRDeot	= (1<<15),		/* EDMA interrupt error cause register */	ePrtDataErr	= (1<<0),	ePrtPRDErr	= (1<<1),	eDevErr		= (1<<2),	eDevDis		= (1<<3),	eDevCon		= (1<<4),	eOverrun		= (1<<5),	eUnderrun	= (1<<6),	eSelfDis		= (1<<8),	ePrtCRQBErr	= (1<<9),	ePrtCRPBErr	= (1<<10),	ePrtIntErr		= (1<<11),	eIORdyErr		= (1<<12),	/* EDMA Command Register */	eEnEDMA		= (1<<0),	eDsEDMA 	= (1<<1),	eAtaRst 		= (1<<2),	/* Interrupt mask for errors we care about */	IEM			= (eDevDis | eDevCon | eSelfDis),		Dnull = 0,	Dnew,	Dident,	Dready,	Derror,	Dmissing,	Dunconfig,	Dext	 	= (1<<0),		/* use ext commands */	Dpio		= (1<<1),		/* doing pio */	Dwanted	= (1<<2),		/* someone wants an srb entry */	Dedma	= (1<<3),		/* device in edma mode */	Dpiowant	= (1<<4),		/* some wants to use the pio mode */};static char* diskstates[] ={	"null",	"new",	"ident",	"ready",	"error",	"missing",	"unconfigured",};extern SDifc sdmv50xxifc;typedef struct Arb Arb;typedef struct Bridge Bridge;typedef struct Chip Chip;typedef struct Ctlr Ctlr;typedef struct Drive Drive;typedef struct Edma Edma;typedef struct Prd Prd;typedef struct Rx Rx;typedef struct Srb Srb;typedef struct Tx Tx;struct Chip	/* pointers to per-Chip mmio */{	Arb		*arb;	Edma	*edma;	/* array of 4 */};struct Drive	/* a single disk */{	Lock;	Ctlr		*ctlr;	SDunit	*unit;	int		subno;	char		name[10];	Bridge	*bridge;	Edma	*edma;	Chip		*chip;	int		chipx;		int		state;	int		flag;	uvlong	sectors;	char		serial[20+1];	char		firmware[8+1];	char		model[40+1];	ushort	info[256];		Srb		*srb[SrbRing-1];	int		nsrb;	Prd		*prd;	Tx		*tx;	Rx		*rx;		Srb		*srbhead;	Srb		*srbtail;};struct Ctlr		/* a single PCI card */{	Lock;	int		irq;	int		tbdf;	SDev		*sdev;	Pcidev	*pcidev;	uchar	*mmio;	Chip		chip[2];	int		nchip;	Drive	drive[8];	int		ndrive;};struct Srb		/* request buffer */{	Lock;	Rendez;	Srb		*next;	Drive	*drive;	uvlong	blockno;	int		count;	int		req;	int		flag;	uchar	*data;		uchar	cmd;	uchar	lba[6];	uchar	sectors;	int		sta;	int		err;};/* * Memory-mapped I/O registers in many forms. */struct Bridge	/* memory-mapped per-Drive registers */{	ulong	status;	ulong	serror;	ulong	sctrl;	ulong	phyctrl;	char		fill1[0x2c];	ulong	ctrl;	char		fill2[0x34];	ulong	phymode;	char		fill3[0x88];	/* pad to 0x100 in length */};struct Arb		/* memory-mapped per-Chip registers */{	ulong	fill0;	ulong	rqop;	/* request queue out-pointer */	ulong	rqip;		/* response queue in pointer */	ulong	ict;		/* inerrupt caolescing threshold */	ulong	itt;		/* interrupt timer threshold */	ulong	ic;		/* interrupt cause */	ulong	btc;		/* bridges test control */	ulong	bts;		/* bridges test status */	ulong	bpc;		/* bridges pin configuration */	char		fill1[0xdc];	Bridge	bridge[4];};struct Edma	/* memory-mapped per-Drive DMA-related registers */{	ulong		config;		/* configuration register */	ulong		timer;	ulong		iec;			/* interrupt error cause */	ulong		iem;			/* interrupt error mask */	ulong		txbasehi;		/* request queue base address high */	ulong		txi;			/* request queue in pointer */	ulong		txo;			/* request queue out pointer */	ulong		rxbasehi;		/* response queue base address high */	ulong		rxi;			/* response queue in pointer */	ulong		rxo;			/* response queue out pointer */		ulong		ctl;			/* command register */	ulong		testctl;		/* test control */	ulong		status;	ulong		iordyto;		/* IORDY timeout */	char			fill[0xc8];	ushort		pio;			/* data register */	char			pad0[2];	uchar		err;			/* features and error */	char			pad1[3];	uchar		seccnt;		/* sector count */	char			pad2[3];	uchar		lba0;	char			pad3[3];	uchar		lba1;	char			pad4[3];	uchar		lba2;	char			pad5[3];	uchar		lba3;	char			pad6[3];	uchar		cmdstat;		/* cmd/status */	char			pad7[3];	uchar		altstat;		/* alternate status */	char			fill2[0x1edc];	/* pad to 0x2000 bytes */};/* * Memory structures shared with card. */struct Prd		/* physical region descriptor */{	ulong	pa;		/* byte address of physical memory */	ushort	count;		/* byte count (bit0 must be 0) */	ushort	flag;	ulong	zero;			/* high long of 64 bit address */	ulong	reserved;};struct Tx		/* command request block */{	ulong	prdpa;		/* physical region descriptor table structures */	ulong	zero;			/* must be zero (high long of prd address) */	ushort	flag;			/* control flags */	ushort	regs[11];};struct Rx		/* command response block */{	ushort	cid;			/* cID of response */	uchar	cEdmaSts;		/* EDMA status */	uchar	cDevSts;		/* status from disk */	ulong	ts;			/* time stamp */};/* * Little-endian parsing for drive data. */static ushortlhgets(void *p){	uchar *a = p;	return ((ushort) a[1] << 8) | a[0];}static ulonglhgetl(void *p){	uchar *a = p;	return ((ulong) lhgets(a+2) << 16) | lhgets(a);}static uvlonglhgetv(void *p){	uchar *a = p;	return ((uvlong) lhgetl(a+4) << 32) | lhgetl(a);}static voididmove(char *p, ushort *a, int n){	char *op;	int i;		op = p;	for(i=0; i<n/2; i++){		*p++ = a[i]>>8;		*p++ = a[i];	}	while(p>op && *--p == ' ')		*p = 0;}/* * Request buffers. */struct {	Lock;	Srb *freechain;	int nalloc;} srblist;static Srb*allocsrb(void){	Srb *p;		ilock(&srblist);	if((p = srblist.freechain) == nil){		srblist.nalloc++;		iunlock(&srblist);		p = smalloc(sizeof *p);	}else{		srblist.freechain = p->next;		iunlock(&srblist);	}	return p;}static voidfreesrb(Srb *p){	ilock(&srblist);	p->next = srblist.freechain;	srblist.freechain = p;	iunlock(&srblist);}/* * Wait for a byte to be a particular value. */static intsatawait(uchar *p, uchar mask, uchar v, int ms){	int i;//	DPRINT("satawait %p %#x %#x %d...", p, mask, v, ms);//	DPRINT("!%#x...", *p);	for(i=0; i<ms && (*p & mask) != v; i++){		if(i%1000 == 0)			DPRINT("!%#x", *p);		microdelay(1000);	}	return (*p & mask) == v;}/* * Drive initialization */static intconfigdrive(Ctlr *ctlr, Drive *d, SDunit *unit){	int i;	ulong *r;		DPRINT("%s: configdrive\n", unit->name);	d->unit = unit;	d->ctlr = ctlr;	d->chipx = unit->subno%4;	d->chip = &ctlr->chip[unit->subno/4];	d->bridge = &d->chip->arb->bridge[d->chipx];	d->edma = &d->chip->edma[d->chipx];	if(d->tx == nil){		d->tx = mallocalign(32*sizeof(Tx), 1024, 0, 0);		d->rx = mallocalign(32*sizeof(Rx), 256, 0, 0);		d->prd = mallocalign(32*sizeof(Prd), 32, 0, 0);		if(d->tx == nil || d->rx == nil || d->prd == nil){			iprint("%s: out of memory allocating ring buffers\n",				unit->name);			free(d->tx);			d->tx = nil;			free(d->rx);			d->rx = nil;			free(d->prd);			d->prd = nil;			d->state = Dunconfig;			return 0;		}		for(i=0; i<32; i++)			d->tx[i].prdpa = PADDR(&d->prd[i]);		coherence();	}		/* leave disk interrupts turned off until we use it ... */	d->edma->iem = 0;		/* ... but enable them on the controller */	r = (ulong*)(d->ctlr->mmio + 0x1D64);	if(d->unit->subno < 4)		*r |= 3 << (d->chipx*2);	else		*r |= 3 << (d->chipx*2+9);	return 1;}static intenabledrive(Drive *d){	Edma *edma;		DPRINT("%s: enabledrive\n", d->unit->name);	if((d->bridge->status & 0xF) != 0x3){	/* Det */		DPRINT("%s: not present\n", d->unit->name);		d->state = Dmissing;		return 0;	}	edma = d->edma;	if(satawait(&edma->cmdstat, ATAbusy, 0, 10*1000) == 0){		print("%s: busy timeout\n", d->unit->name);		d->state = Dmissing;		return 0;	}	edma->iec = 0;	d->chip->arb->ic &= ~(0x101 << d->chipx);	edma->config = 0x11F;	edma->txi = PADDR(d->tx);	edma->txo = (ulong)d->tx & 0x3E0;	edma->rxi = (ulong)d->rx & 0xF8;	edma->rxo = PADDR(d->rx);	edma->ctl |= 1;		/* enable dma */	DPRINT("%s: enable interrupts\n", d->unit->name);	if(d->bridge->status = 0x113)		d->state = Dnew;	d->edma->iem = IEM;	return 1;}static voiddisabledrive(Drive *d){	int i;	ulong *r;	DPRINT("%s: disabledrive\n", d->unit->name);	if(d->tx == nil)	/* never enabled */		return;	d->edma->ctl = 0;	d->edma->iem = 0;	r = (ulong*)(d->ctlr->mmio + 0x1D64);	i = d->chipx;	if(d->chipx < 4)		*r &= ~(3 << (i*2));	else		*r |= ~(3 << (i*2+9));}static intsetudmamode(Drive *d, uchar mode){	Edma *edma;		DPRINT("%s: setudmamode %d\n", d->unit->name, mode);	edma = d->edma;	if(satawait(&edma->cmdstat, ATAerr|ATAdrq|ATAdf|ATAdrdy|ATAbusy, ATAdrdy, 15*1000) == 0){		iprint("%s: cmdstat 0x%.2ux ready timeout\n",			d->unit->name, edma->cmdstat);		return 0;	}	edma->altstat = ATAeIEN;	edma->err = 3;	edma->seccnt = 0x40 | mode;	edma->cmdstat = 0xEF;	microdelay(1);	if(satawait(&edma->cmdstat, ATAbusy, 0, 15*1000) == 0){		iprint("%s: cmdstat 0x%.2ux busy timeout\n", 			d->unit->name, edma->cmdstat);		return 0;	}	return 1;}static voididentifydrive(Drive *d){	int i;	ushort *id;	Edma *edma;	SDunit *unit;		DPRINT("%s: identifydrive\n", d->unit->name);	if(setudmamode(d, 5) == 0)	/* do all SATA support 5? */		goto Error;	id = d->info;	memset(d->info, 0, sizeof d->info);	edma = d->edma;	if(satawait(&edma->cmdstat, 0xE9, 0x40, 15*1000) == 0)		goto Error;	edma->altstat = ATAeIEN;	/* no interrupts */	edma->cmdstat = 0xEC;	microdelay(1);	if(satawait(&edma->cmdstat, ATAbusy, 0, 15*1000) == 0)		goto Error;	for(i=0; i<256; i++)		id[i] = edma->pio;	if(edma->cmdstat & (ATAerr|ATAdf))		goto Error;	i = lhgets(id+83) | lhgets(id+86);	if(i & (1<<10)){		d->flag |= Dext;		d->sectors = lhgetv(id+100);	}else{		d->flag &= ~Dext;		d->sectors = lhgetl(id+60);	}	idmove(d->serial, id+10, 20);	idmove(d->firmware, id+23, 8);	idmove(d->model, id+27, 40);		unit = d->unit;	memset(unit->inquiry, 0, sizeof unit->inquiry);	unit->inquiry[2] = 2;	unit->inquiry[3] = 2;	unit->inquiry[4] = sizeof(unit->inquiry)-4;	idmove((char*)unit->inquiry+8, id+27, 40);	if(enabledrive(d))		d->state = Dready;	else		d->state = Derror;	return;Error:	DPRINT("error...");	d->state = Derror;}static void abortallsrb(Drive*);static voidupdatedrive(Drive *d, ulong cause){	int x;	Edma *edma;		if(cause == 0)		return;	DPRINT("%s: updatedrive %#lux\n", d->unit->name, cause);	edma = d->edma;	if(cause & eDevDis){		d->state = Dmissing;		edma->ctl |= eAtaRst;		microdelay(25);		edma->ctl &= ~eAtaRst;		microdelay(25);	}	if(cause & eDevCon){		d->bridge->sctrl = (d->bridge->sctrl & ~0xF) | 1;		d->state = Dnew;	}	if(cause & eSelfDis)		d->state = Derror;	edma->iec = 0;	d->sectors = 0;	d->unit->sectors = 0;	abortallsrb(d);	x = edma->cmdstat;	USED(x);}/* * Requests */static Srb*srbrw(int req, Drive *d, uchar *data, uint sectors, uvlong lba){	int i;	Srb *srb;	static uchar cmd[2][2] = { 0xC8, 0x25, 0xCA, 0x35 };	switch(req){	case SRBread:	case SRBwrite:		break;	default:		return nil;	}		srb = allocsrb();	srb->req = req;	srb->drive = d;	srb->blockno = lba;	srb->sectors = sectors;	srb->count = sectors*512;	srb->flag = 0;	srb->data = data;	for(i=0; i<6; i++)		srb->lba[i] = lba >> (8*i);	srb->cmd = cmd[srb->req!=SRBread][(d->flag&Dext)!=0];	return srb;}static uintptradvance(uintptr pa, int shift){	int n, mask;		mask = 0x1F<<shift;	n = (pa & mask) + (1<<shift);	return (pa & ~mask) | (n & mask);}#define CMD(r, v) (((r)<<8) | ((v)&0xFF))static voidatarequest(ushort *cmd, Srb *srb, int ext){	*cmd++ = CMD(ARseccnt, 0);	*cmd++ = CMD(ARseccnt, srb->sectors);	*cmd++ = CMD(ARfea, 0);	if(ext){		*cmd++ = CMD(ARlba0, srb->lba[3]);		*cmd++ = CMD(ARlba0, srb->lba[0]);		*cmd++ = CMD(ARlba1, srb->lba[4]);		*cmd++ = CMD(ARlba1, srb->lba[1]);		*cmd++ = CMD(ARlba2, srb->lba[5]);		*cmd++ = CMD(ARlba2, srb->lba[2]);		*cmd++ = CMD(ARdev, 0xE0);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -