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

📄 sdmylex.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
📖 第 1 页 / 共 2 页
字号:
	mb->code = Mbostart;	ctlr->mbox++;	if(ctlr->mbox >= NMbox)		ctlr->mbox = 0;	/*	 * This command does not require Hardy	 * and doesn't generate a Cmdc interrupt.	 */	ccb->done = 0;	outb(ctlr->port+Rcpr, Cstart);	unlock(&ctlr->mboxlock);	/*	 * Wait for the request to complete and return the status.	 * Since the buffer is not reference counted cannot return	 * until the DMA is done writing into the buffer so the caller	 * cannot free the buffer prematurely.	 */	while(waserror())		;	sleep(ccb, done32, ccb);	poperror();	/*	 * Save the status and patch up the number of	 * bytes actually transferred.	 * There's a firmware bug on some 956C controllers	 * which causes the return count from a successful	 * READ CAPACITY not to be updated, so fix it here.	 */	sdstat = ccb->sdstat;	btstat = ccb->btstat;	d = ccb->datalen[0];	d |= (ccb->datalen[1]<<8);	d |= (ccb->datalen[2]<<16);	d |= (ccb->datalen[3]<<24);	if(ccb->cdb[0] == 0x25 && sdstat == SDok)		d = 0;	n -= d;	r->rlen = n;	/*	 * If there was a check-condition, save the	 * ccb for a possible request-sense command.	 */	if(sdstat == SDcheck){		if(r->flags & SDnosense){			lock(&ctlr->cachelock);			if(ctlr->cache[target])				ccbfree(ctlr, ctlr->cache[target]);			ctlr->cache[target] = (Ccb*)ccb;			unlock(&ctlr->cachelock);			return SDcheck;		}		n = 8+ccb->sense[7];		if(n > sizeof(r->sense)-1)			n = sizeof(r->sense)-1;		memmove(r->sense, ccb->sense, n);		r->flags |= SDvalidsense;	}	ccbfree(ctlr, (Ccb*)ccb);	if(btstat){		if(btstat == 0x11)			return SDtimeout;		return SDeio;	}	return sdstat;}static voidmylex32interrupt(Ureg*, void* arg){	ulong pa;	Ctlr *ctlr;	Ccb32 *ccb;	Mbox32 *mb, *mbox;	int port, rinterrupt, rstatus;	ctlr = arg;	port = ctlr->port;	/*	 * Save and clear the interrupt(s). The only	 * interrupts expected are Cmdc, which is ignored,	 * and Imbl which means something completed.	 * There's one spurious interrupt left over from	 * initialisation, ignore it.	 */	rinterrupt = inb(port+Rinterrupt);	rstatus = inb(port+Rstatus);	outb(port+Rcontrol, Rint);	if((rinterrupt & ~(Cmdc|Imbl)) != Intv && ctlr->spurious++)		print("%s: interrupt 0x%2.2ux\n",			ctlr->sdev->name, rinterrupt);	if((rinterrupt & Cmdc) && (rstatus & Cmdinv))		print("%s: command invalid\n", ctlr->sdev->name);	/*	 * Look for something in the mail.	 * If there is, free the mailbox and wakeup whoever.	 */	mb = ctlr->mb;	for(mbox = &mb[ctlr->mbix]; mbox->code; mbox = &mb[ctlr->mbix]){		pa = (mbox->ccb[3]<<24)		    |(mbox->ccb[2]<<16)		    |(mbox->ccb[1]<<8)		    |mbox->ccb[0];		if(ctlr->pcidev)			ccb = BPA2K(pa, ctlr->pcidev->tbdf);		else			ccb = BPA2K(pa, BUSUNKNOWN);		mbox->code = 0;		ccb->done = 1;		wakeup(ccb);		ctlr->mbix++;		if(ctlr->mbix >= NMbox+NMbox)			ctlr->mbix = NMbox;	}}static intmylexrio(SDreq* r){	Ctlr *ctlr;	ctlr = r->unit->dev->ctlr;	if((r->unit->subno) == ctlr->id)		r->status = SDtimeout;	else if(ctlr->bus == 24)		r->status = mylex24rio(r);	else		r->status = mylex32rio(r);	return r->status;}/* * Issue a command to a controller. The command and its length is * contained in cmd and cmdlen. If any data is to be * returned, datalen should be non-zero, and the returned data * will be placed in data. * If Cmdc is set, bail out, the invalid command will be handled * when the interrupt is processed. */static voidissueio(int port, uchar* cmd, int cmdlen, uchar* data, int datalen){	int len;	if(cmd[0] != Cstart && cmd[0] != Ceombri){		while(!(inb(port+Rstatus) & Hardy))			;	}	outb(port+Rcpr, cmd[0]);	len = 1;	while(len < cmdlen){		if(!(inb(port+Rstatus) & Cprbsy)){			outb(port+Rcpr, cmd[len]);			len++;		}		if(inb(port+Rinterrupt) & Cmdc)			return;	}	if(datalen){		len = 0;		while(len < datalen){			if(inb(port+Rstatus) & Dirrdy){				data[len] = inb(port+Rdatain);				len++;			}			if(inb(port+Rinterrupt) & Cmdc)				return;		}	}}/* * Issue a command to a controller, wait for it to complete then * try to reset the interrupt. Should only be called at initialisation. */static intissue(Ctlr* ctlr, uchar* cmd, int cmdlen, uchar* data, int datalen){	int port;	uchar rinterrupt, rstatus;	static Lock mylexissuelock;	port = ctlr->port;	ilock(&ctlr->issuelock);	issueio(port, cmd, cmdlen, data, datalen);	while(!((rinterrupt = inb(port+Rinterrupt)) & Cmdc))		;	rstatus = inb(port+Rstatus);	outb(port+Rcontrol, Rint);	iunlock(&ctlr->issuelock);	if((rinterrupt & Cmdc) && (rstatus & Cmdinv))		return 0;	return 1;}static SDev*mylexprobe(int port, int irq){	SDev *sdev;	Ctlr *ctlr;	uchar cmd[6], data[256];	int clen, dlen, timeo;	if(ioalloc(port, 0x3, 0, "mylex") < 0)		return nil;	ctlr = nil;	/*	 * Attempt to hard-reset the board and reset	 * the SCSI bus. If the board state doesn't settle to	 * idle with mailbox initialisation required, either	 * it isn't a compatible board or it's broken.	 * If the controller has SCAM set this can take a while.	 */	outb(port+Rcontrol, Rhard|Rsbus);	for(timeo = 0; timeo < 100; timeo++){		if(inb(port+Rstatus) == (Inreq|Hardy))			break;		delay(100);	}	if(inb(port+Rstatus) != (Inreq|Hardy)){buggery:		if(ctlr != nil)			free(ctlr);		iofree(port);		return nil;	}	if((ctlr = malloc(sizeof(Ctlr))) == nil)		goto buggery;	ctlr->port = port;	ctlr->irq = irq;	ctlr->bus = 24;	ctlr->wide = 0;	/*	 * Try to determine if this is a 32-bit MultiMaster controller	 * by attempting to obtain the extended inquiry information;	 * this command is not implemented on Adaptec 154xx	 * controllers. If successful, the first byte of the returned	 * data is the host adapter bus type, 'E' for 32-bit EISA,	 * PCI and VLB buses.	 */	cmd[0] = Ciesi;	cmd[1] = 4;	clen = 2;	dlen = 256;	if(issue(ctlr, cmd, clen, data, dlen)){		if(data[0] == 'E')			ctlr->bus = 32;		ctlr->wide = data[0x0D] & 0x01;	}	else{		/*		 * Inconceivable though it may seem, a hard controller reset		 * is necessary here to clear out the command queue. Every		 * board seems to lock-up in a different way if you give an		 * invalid command and then try to clear out the		 * command/parameter and/or data-in register.		 * Soft reset doesn't do the job either. Fortunately no		 * serious initialisation has been done yet so there's nothing		 * to tidy up.		 */		outb(port+Rcontrol, Rhard);		for(timeo = 0; timeo < 100; timeo++){			if(inb(port+Rstatus) == (Inreq|Hardy))				break;			delay(100);		}		if(inb(port+Rstatus) != (Inreq|Hardy))			goto buggery;	}	/*	 * If the BIOS is enabled on the AHA-1542C/CF and BIOS options for	 * support of drives > 1Gb, dynamic scanning of the SCSI bus or more	 * than 2 drives under DOS 5.0 are enabled, the BIOS disables	 * accepting Cmbinit to protect against running with drivers which	 * don't support those options. In order to unlock the interface it	 * is necessary to read a lock-code using Cextbios and write it back	 * using Cmbienable; the lock-code is non-zero.	 */	cmd[0] = Cinquiry;	clen = 1;	dlen = 4;	if(issue(ctlr, cmd, clen, data, dlen) == 0)		goto buggery;	if(data[0] >= 0x43){		cmd[0] = Cextbios;		clen = 1;		dlen = 2;		if(issue(ctlr, cmd, clen, data, dlen) == 0)			goto buggery;		/*		 * Lock-code returned in data[1]. If it's non-zero write		 * it back along with bit 0 of byte 0 cleared to enable		 * mailbox initialisation.		 */		if(data[1]){			cmd[0] = Cmbienable;			cmd[1] = 0;			cmd[2] = data[1];			clen = 3;			if(issue(ctlr, cmd, clen, 0, 0) == 0)				goto buggery;		}	}	/*	 * Get the id, DMA and IRQ info from the board. This will	 * cause an interrupt which will hopefully not cause any	 * trouble because the interrupt number isn't known yet.	 * This is necessary as the DMA won't be set up if the	 * board has the BIOS disabled.	 *	 * If the IRQ is already known, this must be a 32-bit PCI	 * or EISA card, in which case the returned DMA and IRQ can	 * be ignored.	 */	cmd[0] = Cinquire;	clen = 1;	dlen = 3;	if(issue(ctlr, cmd, clen, data, dlen) == 0)		goto buggery;	ctlr->id = data[2] & 0x07;	if(ctlr->irq < 0){		switch(data[0]){		/* DMA Arbitration Priority */		case 0x80:			/* Channel 7 */			outb(0xD6, 0xC3);			outb(0xD4, 0x03);			break;		case 0x40:			/* Channel 6 */			outb(0xD6, 0xC2);			outb(0xD4, 0x02);			break;		case 0x20:			/* Channel 5 */			outb(0xD6, 0xC1);			outb(0xD4, 0x01);			break;		case 0x01:			/* Channel 0 */			outb(0x0B, 0xC0);			outb(0x0A, 0x00);			break;		default:			break;		}			switch(data[1]){		/* Interrupt Channel */		case 0x40:			ctlr->irq = 15;			break;		case 0x20:			ctlr->irq = 14;			break;		case 0x08:			ctlr->irq = 12;			break;		case 0x04:			ctlr->irq = 11;			break;		case 0x02:			ctlr->irq = 10;			break;		case 0x01:			ctlr->irq = 9;			break;		default:			goto buggery;		}	}	if((sdev = malloc(sizeof(SDev))) == nil)		goto buggery;	sdev->ifc = &sdmylexifc;	sdev->ctlr = ctlr;	ctlr->sdev = sdev;	if(!ctlr->wide)		sdev->nunit = 8;	else		sdev->nunit = 16;	return sdev;}static int mylexport[8] = {	0x330, 0x334, 0x230, 0x234, 0x130, 0x134, 0x000, 0x000,};static int mylexirq[8] = {	9, 10, 11, 12, 14, 15, 0, 0,};static SDev*mylexpnp(void){	Pcidev *p;	Ctlr *ctlr;	int cfg, i, x;	SDev *sdev, *head, *tail;	p = nil;	head = tail = nil;	while(p = pcimatch(p, 0x104B, 0)){		if((sdev = mylexprobe(p->mem[0].bar & ~0x01, p->intl)) == nil)			continue;		ctlr = sdev->ctlr;		ctlr->pcidev = p;		if(head != nil)			tail->next = sdev;		else			head = sdev;		tail = sdev;	}	if(strncmp(KADDR(0xFFFD9), "EISA", 4))		return head;	for(cfg = 0x1000; cfg < MaxEISA*0x1000; cfg += 0x1000){		x = 0;		for(i = 0; i < 4; i++)			x |= inb(cfg+CfgEISA+i)<<(i*8);		if(x != 0x0142B30A && x != 0x0242B30A)			continue;		x = inb(cfg+0xC8C);		if((sdev = mylexprobe(mylexport[x & 0x07], -1)) == nil)			continue;		if(head != nil)			tail->next = sdev;		else			head = sdev;		tail = sdev;	}	return head;}static SDev*mylexid(SDev* sdev){	return scsiid(sdev, &sdmylexifc);}static intmylex24enable(Ctlr* ctlr){	ulong p;	Ccb24 *ccb, *ccbp;	uchar cmd[6], *v;	int len;	len = (sizeof(Mbox24)*NMbox*2)+(sizeof(Ccb24)*NCcb);	v = xspanalloc(len, 32, 0);	if(!PADDR24(ctlr, sizeof(Ctlr)) || !PADDR24(v, len))		return 0;	ctlr->mb = v;	v += sizeof(Mbox24)*NMbox*2;	ccb = (Ccb24*)v;	for(ccbp = ccb; ccbp < &ccb[NCcb]; ccbp++){		ccbp->ccb = ctlr->ccb;		ctlr->ccb = (Ccb*)ccbp;	}	/*	 * Initialise the software controller and	 * set the board scanning the mailboxes.	 */	ctlr->mbix = NMbox;	cmd[0] = Cinitialise;	cmd[1] = NMbox;	p = K2BPA(ctlr->mb, BUSUNKNOWN);	cmd[2] = p>>16;	cmd[3] = p>>8;	cmd[4] = p;	len = 5;	return issue(ctlr, cmd, len, 0, 0);}static intmylex32enable(Ctlr* ctlr){	ulong p;	Ccb32 *ccb, *ccbp;	uchar cmd[6], *v;	v = xspanalloc((sizeof(Mbox32)*NMbox*2)+(sizeof(Ccb32)*NCcb), 32, 0);	ctlr->mb = v;	v += sizeof(Mbox32)*NMbox*2;	ccb = (Ccb32*)v;	for(ccbp = ccb; ccbp < &ccb[NCcb]; ccbp++){		/*		 * Fill in some stuff that doesn't change.		 */		ccbp->senselen = sizeof(ccbp->sense);		p = PADDR(ccbp->sense);		ccbp->senseptr[0] = p;		ccbp->senseptr[1] = p>>8;		ccbp->senseptr[2] = p>>16;		ccbp->senseptr[3] = p>>24;		ccbp->ccb = ctlr->ccb;		ctlr->ccb = (Ccb*)ccbp;	}	/*	 * Attempt wide mode setup.	 */	if(ctlr->wide){		cmd[0] = Cwide;		cmd[1] = 1;		if(!issue(ctlr, cmd, 2, 0, 0))			ctlr->wide = 0;	}	/*	 * Initialise the software controller and	 * set the board scanning the mailboxes.	 */	ctlr->mbix = NMbox;	cmd[0] = Ciem;	cmd[1] = NMbox;	if(ctlr->pcidev)		p = K2BPA(ctlr->mb, ctlr->tbdf);	else		p = K2BPA(ctlr->mb, BUSUNKNOWN);	cmd[2] = p;	cmd[3] = p>>8;	cmd[4] = p>>16;	cmd[5] = p>>24;	return issue(ctlr, cmd, 6, 0, 0);}static intmylexenable(SDev* sdev){	int tbdf;	Ctlr *ctlr;	void (*interrupt)(Ureg*, void*);	char name[NAMELEN];	ctlr = sdev->ctlr;	if(ctlr->cache == nil){		if((ctlr->cache = malloc(sdev->nunit*sizeof(Ccb*))) == nil)			return 0;	}	tbdf = BUSUNKNOWN;	if(ctlr->bus == 32){		if(ctlr->pcidev){			tbdf = ctlr->pcidev->tbdf;			pcisetbme(ctlr->pcidev);		}		if(!mylex32enable(ctlr))			return 0;		interrupt = mylex32interrupt;	}	else if(mylex24enable(ctlr))		interrupt = mylex24interrupt;	else		return 0;	snprint(name, NAMELEN, "sd%c (%s)", sdev->idno, sdev->ifc->name);	intrenable(ctlr->irq, interrupt, ctlr, tbdf, name);	return 1;}SDifc sdmylexifc = {	"mylex",			/* name */	mylexpnp,			/* pnp */	nil,				/* legacy */	mylexid,			/* id */	mylexenable,			/* enable */	nil,				/* disable */	scsiverify,			/* verify */	scsionline,			/* online */	mylexrio,			/* rio */	nil,				/* rctl */	nil,				/* wctl */	scsibio,			/* bio */};

⌨️ 快捷键说明

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