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

📄 sdmv50xx.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Marvell 88SX[56]0[48][01] Serial ATA (SATA) driver * * See MV-S101357-00 Rev B Marvell PCI/PCI-X to 8-Port/4-Port * SATA Host Controller, ATA-5 ANSI NCITS 340-2000. * * This is a heavily-modified version of a driver written by Coraid, Inc. * The original copyright notice appears at the end of this file. */#ifdef FS#include "all.h"#include "io.h"#include "mem.h"#include "sd.h"#include "compat.h"#else#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"#endifenum {	DEBUGPR = 0,	IDEBUG = 0,	/* old stuff carried forward */	NCtlr=		8,	NCtlrdrv=	8,	NDrive=		NCtlr*NCtlrdrv,	Maxxfer=	16*1024,	/* maximum transfer size/cmd */	Read = 0,	Write,	Drvmagic =  0xcafebabeUL,	Ctlrmagic = 0xfeedfaceUL,};#define DPRINT	if(DEBUGPR)print#define IDPRINT if(IDEBUG)printenum {	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),	/* drive states */	Dnull = 0,	Dnew,	Dident,	Dready,	Derror,	Dmissing,	Dunconfig,	/* drive flags */	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];	ulong	magic;	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;	/* added for file server */	/* for ata* routines */	int	online;	Devsize	offset;	int	driveno;		/* ctlr*NCtlrdrv + unit */	/*	 * old stuff carried forward.  it's in Drive not Ctlr to maximise	 * possible concurrency.	 */	uchar	buf[RBUFSIZE];};struct Ctlr		/* a single PCI card */{	Lock;	int		irq;	int		tbdf;	ulong	magic;	int		enabled;	SDev		*sdev;	Pcidev	*pcidev;	uchar	*mmio;	Chip		chip[2];	int		nchip;	Drive	drive[NCtlrdrv];	int		ndrive;	Target	target[NTarget];	/* contains filters for stats */	/* old stuff carried forward */	QLock	idelock;	/* make seek & i/o atomic in ide* routines */};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 */};/* file-server-specific data */static Ctlr *mvsatactlr[NCtlr];static SDev *sdevs[NCtlr];static Drive *mvsatadrive[NDrive];static SDunit *sdunits[NDrive];static Drive	*mvsatadriveprobe(int driveno);static void	statsinit(void);/* * 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. */static 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->driveno < 0)		panic("mv50xx: configdrive: unset driveno\n");	sdunits[d->driveno] = unit;	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 (edma == nil) {		print("setudamode(m%d): zero d->edma\m", d->driveno);		return 0;	}	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;		print("mvsata: m%d: LLBA %lld sectors\n",			d->driveno, (Wideoff)d->sectors);	} else		d->state = Derror;	return;

⌨️ 快捷键说明

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