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

📄 sdmv50xx.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
Error:	DPRINT("error...");	d->state = Derror;}static void abortallsrb(Drive*);/* NB: d->unit and d->edma can be nil, empirically */static voidupdatedrive(Drive *d, ulong cause){	int x;	Edma *edma;	if(cause == 0)		return;	/* can't check this, cuz we have to run before identifydrive() */	if (0 && d->magic != Drvmagic) {		print("updatedrive: bad drive magic 0x%lux\n", d->magic);		return;	}	if (d == nil) {		DPRINT("nil d: updatedrive %#lux\n", cause);		return;	} else if (d->unit == nil)		DPRINT("nil d->unit: updatedrive %#lux\n", cause);	else if (d->unit->name == nil)		DPRINT("nil d->unit->name: updatedrive %#lux\n", cause);	else		DPRINT("%s: updatedrive %#lux\n", d->unit->name, cause);	edma = d->edma;	if (edma == nil)		print("mv50xx: updatedrive(m%d): zero d->edma\n", d->driveno);	if(cause & eDevDis){		d->state = Dmissing;		if (edma)			edma->ctl |= eAtaRst;		microdelay(25);		if (edma)			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;	if (edma)		edma->iec = 0;	d->sectors = 0;	if (d->unit)		d->unit->sectors = 0;	abortallsrb(d);	SET(x);	if (edma)		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 voidmvsatarequest(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);	}else{		*cmd++ = CMD(ARlba0, srb->lba[0]);		*cmd++ = CMD(ARlba1, srb->lba[1]);		*cmd++ = CMD(ARlba2, srb->lba[2]);		*cmd++ = CMD(ARdev, srb->lba[3] | 0xE0);	}	*cmd++ = CMD(ARcmd, srb->cmd) | (1<<15);	USED(cmd);}static voidstartsrb(Drive *d, Srb *srb){	int i;	Edma *edma;	Prd *prd;	Tx *tx;	if(d->nsrb >= nelem(d->srb)){		srb->next = nil;		if(d->srbhead)			d->srbtail->next = srb;		else			d->srbhead = srb;		d->srbtail = srb;		return;	}	d->nsrb++;	for(i=0; i<nelem(d->srb); i++)		if(d->srb[i] == nil)			break;	if(i == nelem(d->srb))		panic("sdmv50xx: no free srbs");	d->srb[i] = srb;	edma = d->edma;	tx = (Tx*)KADDR(edma->txi);	tx->flag = (i<<1) | (srb->req == SRBread);	prd = KADDR(tx->prdpa);	prd->pa = PADDR(srb->data);	prd->count = srb->count;	prd->flag = PRDeot;	mvsatarequest(tx->regs, srb, d->flag&Dext);	coherence();	edma->txi = advance(edma->txi, 5);}static voidcompletesrb(Drive *d){	Edma *edma;	Rx *rx;	Srb *srb;	edma = d->edma;	if (edma == 0)		print("mv50xx: completesrb(m%d): zero d->edma\n", d->driveno);	if(edma == 0 || (edma->ctl & eEnEDMA) == 0)		return;	while((edma->rxo & (0x1F<<3)) != (edma->rxi & (0x1F<<3))){		rx = (Rx*)KADDR(edma->rxo);		if(srb = d->srb[rx->cid]){			d->srb[rx->cid] = nil;			d->nsrb--;			if(rx->cDevSts & (ATAerr|ATAdf))				srb->flag |= SFerror;			srb->flag |= SFdone;			srb->sta = rx->cDevSts;			wakeup(srb);		}else			iprint("srb missing\n");		edma->rxo = advance(edma->rxo, 3);		if(srb = d->srbhead){			d->srbhead = srb->next;			startsrb(d, srb);		}	}}static voidabortallsrb(Drive *d){	int i;	Srb *srb;	for(i=0; i<nelem(d->srb); i++){		if(srb = d->srb[i]){			d->srb[i] = nil;			d->nsrb--;			srb->flag |= SFerror|SFdone;			wakeup(srb);		}	}	while(srb = d->srbhead){		d->srbhead = srb->next;		srb->flag |= SFerror|SFdone;		wakeup(srb);	}}static intsrbdone(void *v){	Srb *srb;	srb = v;	return srb->flag & SFdone;}/* * Interrupts */static voidmv50interrupt(Ureg*, void *a){	int i;	ulong cause;	Ctlr *ctlr;	Drive *drive;	ctlr = a;	if (ctlr == nil)		panic("mv50interrupt: nil ctlr");	if (ctlr->magic != Ctlrmagic)		panic("mv50interrupt: ctlr %p: bad controller magic 0x%lux",			ctlr, ctlr->magic);	ilock(ctlr);	cause = *(ulong*)(ctlr->mmio + 0x1D60);//	DPRINT("sd%c: mv50interrupt: 0x%lux\n", ctlr->sdev->idno, cause);	for(i=0; i<ctlr->ndrive; i++)		if(cause & (3<<(i*2+i/4))){			drive = &ctlr->drive[i];			if (drive->magic != Drvmagic) {				print("mv50xx: interrupt for unconfigured drive %d\n",					i);				// continue;			}			ilock(drive);			updatedrive(drive, drive->edma->iec);			while(ctlr->chip[i/4].arb->ic & (0x0101 << (i%4))){				ctlr->chip[i/4].arb->ic = ~(0x101 << (i%4));				completesrb(drive);			}			iunlock(drive);		}	iunlock(ctlr);}/* our Drives are statically allocated in the Ctlr */static Drive*mvsatagetdrive(Ctlr *ctlr, int subno, int driveno){	Drive *drive = &ctlr->drive[subno];	memset(drive, 0, sizeof *drive);	USED(driveno);	drive->driveno = -1;				/* unset */	drive->sectors = 0;	return drive;}/* * Device discovery */static SDev*mv50pnp(void){	int i, nunit;	uchar *base;	ulong io;	void *mem;	Ctlr *ctlr;	Pcidev *p;	SDev *head, *tail, *sdev;	static int ctlrno, done;	DPRINT("mv50pnp\n");	if (done)		return nil;	done = 1;	p = nil;	head = nil;	tail = nil;	while((p = pcimatch(p, 0x11AB, 0)) != nil){		switch(p->did){		case 0x5040:		case 0x5041:		case 0x5080:		case 0x5081:		case 0x6041:		case 0x6081:			break;		default:			print("unknown Marvell controller %ux; ignoring\n",				(ushort)p->did);			continue;		}		if (ctlrno >= NCtlr) {			print("mv50pnp: too many controllers\n");			break;		}		nunit = (p->did&0xf0) >> 4;		print("Marvell 88SX%ux: %d SATA-%s ports with%s flash\n",			(ushort)p->did, nunit,			((p->did&0xf000)==0x6000? "II": "I"),			(p->did&1? "": "out"));		if((sdev = malloc(sizeof(SDev))) == nil)			continue;		if((ctlr = malloc(sizeof(Ctlr))) == nil){			free(sdev);			continue;		}		io = p->mem[0].bar & ~0x0F;		mem = (void *)vmap(io, p->mem[0].size);		if(mem == 0){			print("sdmv50xx: address 0x%luX in use\n", io);			free(sdev);			free(ctlr);			continue;		}		sdev->ifc = &sdmv50xxifc;		sdev->ctlr = ctlr;		sdev->nunit = nunit;		sdev->idno = 'E' + ctlrno;		sdevs[ctlrno] = sdev;		ctlr->sdev = sdev;		ctlr->irq = p->intl;		ctlr->tbdf = p->tbdf;		ctlr->pcidev = p;		ctlr->mmio = mem;		ctlr->nchip = (nunit+3)/4;		ctlr->ndrive = nunit;		ctlr->magic = Ctlrmagic;		ctlr->enabled = 0;		for(i=0; i<ctlr->nchip; i++){			base = ctlr->mmio+0x20000+0x10000*i;			ctlr->chip[i].arb = (Arb*)base;			ctlr->chip[i].edma = (Edma*)(base + 0x2000);		}		for (i = 0; i < nunit; i++) {			Drive *drive =				mvsatagetdrive(ctlr, i, ctlrno*NCtlrdrv +i);			if(drive == nil)				continue;			drive->ctlr = ctlr;			drive->driveno = ctlrno*NCtlrdrv + i;			mvsatactlr[ctlrno] = ctlr;			mvsatadrive[drive->driveno] = drive;			drive->magic = Drvmagic;		}		ctlrno++;		if(head)			tail->next = sdev;		else			head = sdev;		tail = sdev;	}	return head;}/* * Enable the controller.  Each disk has its own interrupt mask, * and those get enabled as the disks are brought online. */static intmv50enable(SDev *sdev){	char name[32];	Ctlr *ctlr;	DPRINT("sd%c: enable\n", sdev->idno);	ctlr = sdev->ctlr;	if (ctlr == nil)		panic("mv50enable: nil sdev->ctlr");	if (ctlr->enabled)		return 1;	snprint(name, sizeof name, "%s (%s)", sdev->name, sdev->ifc->name);	DPRINT("sd%c: irq %d\n", sdev->idno, ctlr->irq);	if (ctlr->magic != Ctlrmagic)		panic("mv50enable: bad controller magic 0x%lux", ctlr->magic);	intrenable(ctlr->irq, mv50interrupt, ctlr, ctlr->tbdf, name);	ctlr->enabled = 1;	return 1;}/* * Disable the controller. */static intmv50disable(SDev *sdev){	char name[32];	int i;	Ctlr *ctlr;	Drive *drive;	DPRINT("sd%c: disable\n", sdev->idno);	ctlr = sdev->ctlr;	ilock(ctlr);	for(i=0; i<ctlr->sdev->nunit; i++){		drive = &ctlr->drive[i];		ilock(drive);		disabledrive(drive);		iunlock(drive);	}	iunlock(ctlr);	snprint(name, sizeof name, "%s (%s)", sdev->name, sdev->ifc->name);	intrdisable(ctlr->irq, mv50interrupt, ctlr, ctlr->tbdf, name);	return 0;}/* * Clean up all disk structures.  Already disabled. * Could keep count of number of allocated controllers * and free the srblist when it drops to zero. */static voidmv50clear(SDev *sdev){	int i;	Ctlr *ctlr;	Drive *d;	DPRINT("sd%c: clear\n", sdev->idno);	ctlr = sdev->ctlr;	for(i=0; i<ctlr->ndrive; i++){		d = &ctlr->drive[i];		free(d->tx);		free(d->rx);		free(d->prd);	}	free(ctlr);}/* * Check that there is a disk or at least a hot swap bay in the drive. */static intmv50verify(SDunit *unit){	Ctlr *ctlr;	Drive *drive;	DPRINT("%s: verify\n", unit->name);	/*	 * First access of unit.	 */	ctlr = unit->dev->ctlr;	drive = &ctlr->drive[unit->subno];	ilock(ctlr);	ilock(drive);	if(!configdrive(ctlr, drive, unit) || !enabledrive(drive)){		iunlock(drive);		iunlock(ctlr);		return 0;	}	/*	 * Need to reset the drive before the first call to	 * identifydrive, or else the satawait in setudma will	 * freeze the machine when accessing edma->cmdstat.	 * I do not understand this.		-rsc	 */	updatedrive(drive, eDevDis);	iunlock(drive);	iunlock(ctlr);	return 1;}/* * Check whether the disk is online. */static intmv50online(SDunit *unit){	Ctlr *ctlr;	Drive *drive;	ctlr = unit->dev->ctlr;	drive = &ctlr->drive[unit->subno];	if (drive->magic != Drvmagic)		print("mv50online: bad drive magic 0x%lux\n", drive->magic);	ilock(drive);	if(drive->state == Dready){		unit->sectors = drive->sectors;		unit->secsize = 512;		iunlock(drive);		return 1;	}	DPRINT("%s: online %s\n", unit->name, diskstates[drive->state]);	if(drive->state == Dnew || drive->state == Dmissing){		identifydrive(drive);		if(drive->state == Dready){			unit->sectors = drive->sectors;			unit->secsize = 512;			iunlock(drive);			return 2;	/* media changed */		}		else			print("mv50online: %s did not come ready, now %s\n",				unit->name, diskstates[drive->state]);	}	iunlock(drive);	return 0;}/* * Register dumps */typedef struct Regs Regs;struct Regs{	ulong offset;	char *name;};static Regs regsctlr[] ={	0x0C28, "pci serr# mask",	0x1D40, "pci err addr low",	0x1D44, "pci err addr hi",	0x1D48, "pci err attr",	0x1D50, "pci err cmd",	0x1D58, "pci intr cause",	0x1D5C, "pci mask cause",	0x1D60, "device micr",	0x1D64, "device mimr",};static Regs regsarb[] ={	0x0004,	"arb rqop",	0x0008,	"arb rqip",	0x000C,	"arb ict",	0x0010,	"arb itt",	0x0014,	"arb ic",	0x0018,	"arb btc",	0x001C,	"arb bts",	0x0020,	"arb bpc",};static Regs regsbridge[] ={	0x0000,	"bridge status",	0x0004,	"bridge serror",	0x0008,	"bridge sctrl",	0x000C,	"bridge phyctrl",	0x003C,	"bridge ctrl",	0x0074,	"bridge phymode",};static Regs regsedma[] ={	0x0000,	"edma config",	0x0004,	"edma timer",	0x0008,	"edma iec",	0x000C,	"edma iem",	0x0010,	"edma txbasehi",	0x0014,	"edma txi",	0x0018,	"edma txo",	0x001C,	"edma rxbasehi",	0x0020,	"edma rxi",	0x0024,	"edma rxo",	0x0028,	"edma c",	0x002C,	"edma tc",	0x0030,	"edma status",	0x0034,	"edma iordyto",/*	0x0100,	"edma pio",	0x0104,	"edma err",	0x0108,	"edma sectors",	0x010C,	"edma lba0",	0x0110,	"edma lba1",	0x0114,	"edma lba2",	0x0118,	"edma lba3",	0x011C,	"edma cmdstat",	0x0120,	"edma altstat",*/};static char*rdregs(char *p, char *e, void *base, Regs *r, int n, char *prefix){	int i;	for(i=0; i<n; i++)		p = seprint(p, e, "%s%s%-19s %.8ux\n",			prefix ? prefix : "", prefix ? ": " : "",			r[i].name, *(u32int*)((uchar*)base+r[i].offset));	return p;}static char*rdinfo(char *p, char *e, ushort *info){	int i;	p = seprint(p, e, "info");	for(i=0; i<256; i++){		p = seprint(p, e, "%s%.4ux%s",			i%8==0 ? "\t" : "",			info[i],			i%8==7 ? "\n" : "");	}	return p;}#ifndef FSstatic intmv50rctl(SDunit *unit, char *p, int l){	char *e, *op;	Ctlr *ctlr;	Drive *drive;	if((ctlr = unit->dev->ctlr) == nil)

⌨️ 快捷键说明

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