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

📄 sdmylex.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Mylex MultiMaster (Buslogic BT-*) SCSI Host Adapter * in both 24-bit and 32-bit mode. * 24-bit mode works for Adaptec AHA-154xx series too. * * To do: *	tidy the PCI probe and do EISA; *	allocate more Ccb's as needed, up to NMbox-1; *	add nmbox and nccb to Ctlr struct for the above; *	64-bit LUN/explicit wide support necessary? * */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "../port/error.h"#include "sd.h"#define K2BPA(va, tbdf)	PADDR(va)#define BPA2K(pa, tbdf)	KADDR(pa)extern SDifc sdmylexifc;enum {					/* registers */	Rcontrol	= 0x00,		/* WO: control register */	Rstatus		= 0x00,		/* RO: status register */	Rcpr		= 0x01,		/* WO: command/parameter register */	Rdatain		= 0x01,		/* RO: data-in register */	Rinterrupt	= 0x02,		/* RO: interrupt register */};enum {					/* Rcontrol */	Rsbus		= 0x10,		/* SCSI Bus Reset */	Rint		= 0x20,		/* Interrupt Reset */	Rsoft		= 0x40,		/* Soft Reset */	Rhard		= 0x80,		/* Hard Reset */};enum {					/* Rstatus */	Cmdinv		= 0x01,		/* Command Invalid */	Dirrdy		= 0x04,		/* Data In Register Ready */	Cprbsy		= 0x08,		/* Command/Parameter Register Busy */	Hardy		= 0x10,		/* Host Adapter Ready */	Inreq		= 0x20,		/* Initialisation Required */	Dfail		= 0x40,		/* Diagnostic Failure */	Dact		= 0x80,		/* Diagnostic Active */};enum {					/* Rcpr */	Cinitialise	= 0x01,		/* Initialise Mailbox */	Cstart		= 0x02,		/* Start Mailbox Command */	Cinquiry	= 0x04,		/* Adapter Anquiry */	Ceombri		= 0x05,		/* Enable OMBR Interrupt */	Cinquire	= 0x0B,		/* Inquire Configuration */	Cextbios	= 0x28,		/* AHA-1542: extended BIOS info. */	Cmbienable	= 0x29,		/* AHA-1542: Mailbox interface enable */	Ciem		= 0x81,		/* Initialise Extended Mailbox */	Ciesi		= 0x8D,		/* Inquire Extended Setup Information */	Cerrm		= 0x8F,		/* Enable strict round-robin mode */	Cwide		= 0x96,		/* Wide CCB */};enum {					/* Rinterrupt */	Imbl		= 0x01,		/* Incoming Mailbox Loaded */	Mbor		= 0x02,		/* Mailbox Out Ready */	Cmdc		= 0x04,		/* Command Complete */	Rsts		= 0x08,		/* SCSI Reset State */	Intv		= 0x80,		/* Interrupt Valid */};typedef struct {	uchar	code;			/* action/completion code */	uchar	ccb[3];			/* CCB pointer (MSB, ..., LSB) */} Mbox24;typedef struct {	uchar	ccb[4];			/* CCB pointer (LSB, ..., MSB) */	uchar	btstat;			/* BT-7[45]7[SD] status */	uchar	sdstat;			/* SCSI device status */	uchar	pad;	uchar	code;			/* action/completion code */} Mbox32;enum {					/* mailbox commands */	Mbfree		= 0x00,		/* Mailbox not in use */	Mbostart	= 0x01,		/* Start a mailbox command */	Mboabort	= 0x02,		/* Abort a mailbox command */	Mbiok		= 0x01,		/* CCB completed without error */	Mbiabort	= 0x02,		/* CCB aborted at request of host */	Mbinx		= 0x03,		/* Aborted CCB not found */	Mbierror	= 0x04,		/* CCB completed with error */};typedef struct Ccb24 Ccb24;typedef struct Ccb32 Ccb32;typedef union Ccb Ccb;typedef struct Ccb24 {	uchar	opcode;			/* Operation code */	uchar	datadir;		/* Data direction control */	uchar	cdblen;			/* Length of CDB */	uchar	senselen;		/* Length of sense area */	uchar	datalen[3];		/* Data length (MSB, ..., LSB) */	uchar	dataptr[3];		/* Data pointer (MSB, ..., LSB) */	uchar	linkptr[3];		/* Link pointer (MSB, ..., LSB) */	uchar	linkid;			/* command linking identifier */	uchar	btstat;			/* BT-* adapter status */	uchar	sdstat;			/* SCSI device status */	uchar	reserved[2];		/* */	uchar	cs[12+0xFF];		/* Command descriptor block + Sense */	void*	data;			/* buffer if address > 24-bits */	Rendez;	int	done;			/* command completed */	Ccb*	ccb;			/* link on free list */} Ccb24;typedef struct Ccb32 {	uchar	opcode;			/* Operation code */	uchar	datadir;		/* Data direction control */	uchar	cdblen;			/* Length of CDB */	uchar	senselen;		/* Length of sense area */	uchar	datalen[4];		/* Data length (LSB, ..., MSB) */	uchar	dataptr[4];		/* Data pointer (LSB, ..., MSB) */	uchar	reserved[2];	uchar	btstat;			/* BT-* adapter status */	uchar	sdstat;			/* SCSI device status */	uchar	targetid;		/* Target ID */	uchar	luntag;			/* LUN & tag */	uchar	cdb[12];		/* Command descriptor block */	uchar	ccbctl;			/* CCB control */	uchar	linkid;			/* command linking identifier */	uchar	linkptr[4];		/* Link pointer (LSB, ..., MSB) */	uchar	senseptr[4];		/* Sense pointer (LSB, ..., MSB) */	uchar	sense[0xFF];		/* Sense bytes */	Rendez;	int	done;			/* command completed */	Ccb*	ccb;			/* link on free list */} Ccb32;typedef union Ccb {	Ccb24;	Ccb32;} Ccb;enum {					/* opcode */	OInitiator	= 0x00,		/* initiator CCB */	Ordl		= 0x03,		/* initiator CCB with					 * residual data length returned					 */};enum {					/* datadir */	CCBdatain	= 0x08,		/* inbound, length is checked */	CCBdataout	= 0x10,		/* outbound, length is checked */};enum {					/* btstat */	Eok		= 0x00,		/* normal completion with no errors */};enum {					/* luntag */	TagEnable	= 0x20,		/* Tag enable */	SQTag		= 0x00,		/* Simple Queue Tag */	HQTag		= 0x40,		/* Head of Queue Tag */	OQTag		= 0x80,		/* Ordered Queue Tag */};enum {					/* CCB control */	NoDisc		= 0x08,		/* No disconnect */	NoUnd		= 0x10,		/* No underrrun error report */	NoData		= 0x20,		/* No data transfer */	NoStat		= 0x40,		/* No CCB status if zero */	NoIntr		= 0x80,		/* No Interrupts */};typedef struct {	int	port;			/* I/O port */	int	id;			/* adapter SCSI id */	int	bus;			/* 24 or 32 -bit */	int	irq;	int	wide;	Pcidev*	pcidev;	SDev*	sdev;	int	spurious;	Lock	issuelock;	Lock	ccblock;	QLock	ccbq;	Rendez	ccbr;	Lock	mboxlock;	void*	mb;			/* mailbox out + mailbox in */	int	mbox;			/* current mailbox out index into mb */	int	mbix;			/* current mailbox in index into mb */	Lock	cachelock;	Ccb*	ccb;			/* list of free Ccb's */	Ccb**	cache;			/* last completed Ccb */} Ctlr;/* * The number of mailboxes should be a multiple of 8 (4 for Mbox32) * to ensure the boundary between the out and in mailboxes doesn't * straddle a cache-line boundary. * The number of Ccb's should be less than the number of mailboxes to * ensure no queueing is necessary on mailbox allocation. */enum {	NMbox		= 8*8,		/* number of Mbox's */	NCcb		= NMbox-1,	/* number of Ccb's */};#define PADDR24(a, n)	(PADDR(a)+n <= (1<<24))static voidccbfree(Ctlr* ctlr, Ccb* ccb){	lock(&ctlr->ccblock);	if(ctlr->bus == 24)		((Ccb24*)ccb)->ccb = ctlr->ccb;	else		((Ccb32*)ccb)->ccb = ctlr->ccb;	if(ctlr->ccb == nil)		wakeup(&ctlr->ccbr);	ctlr->ccb = ccb;	unlock(&ctlr->ccblock);}static intccbavailable(void* a){	return ((Ctlr*)a)->ccb != nil;}static Ccb*ccballoc(Ctlr* ctlr){	Ccb *ccb;	for(;;){		lock(&ctlr->ccblock);		if(ccb = ctlr->ccb){			if(ctlr->bus == 24)				 ctlr->ccb = ((Ccb24*)ccb)->ccb;			else				 ctlr->ccb = ((Ccb32*)ccb)->ccb;			unlock(&ctlr->ccblock);			break;		}		unlock(&ctlr->ccblock);		qlock(&ctlr->ccbq);		if(waserror()){			qunlock(&ctlr->ccbq);			continue;		}		sleep(&ctlr->ccbr, ccbavailable, ctlr);		qunlock(&ctlr->ccbq);		poperror();	}	return ccb;}static intdone24(void* arg){	return ((Ccb24*)arg)->done;}static intmylex24rio(SDreq* r){	ulong p;	Ctlr *ctlr;	Ccb24 *ccb;	Mbox32 *mb;	uchar *data, lun, *sense;	int d, n, btstat, sdstat, target;	ctlr = r->unit->dev->ctlr;	target = r->unit->subno;	lun = (r->cmd[1]>>5) & 0x07;	/*	 * Ctlr->cache holds the last completed Ccb for this target if it	 * returned 'check condition'.	 * If this command is a request-sense and there is valid sense data	 * from the last completed Ccb, return it immediately.	 */	lock(&ctlr->cachelock);	if(ccb = ctlr->cache[target]){		ctlr->cache[target] = nil;		if(r->cmd[0] == 0x03		  && ccb->sdstat == SDcheck && lun == ((ccb->cs[1]>>5) & 0x07)){			unlock(&ctlr->cachelock);			if(r->dlen){				sense = &ccb->cs[ccb->cdblen];				n = 8+sense[7];				if(n > r->dlen)					n = r->dlen;				memmove(r->data, sense, n);				r->rlen = n;			}			ccbfree(ctlr, (Ccb*)ccb);			return SDok;		}	}	unlock(&ctlr->cachelock);	if(ccb == nil)		ccb = ccballoc(ctlr);	/*	 * Check if the transfer is to memory above the 24-bit limit the	 * controller can address. If it is, try to allocate a temporary	 * buffer as a staging area.	 */	n = r->dlen;	if(n && !PADDR24(r->data, n)){		ccb->data = r->data;		data = mallocz(n, 0);		if(data == nil || !PADDR24(data, n)){			if(data != nil){				free(data);				ccb->data = nil;			}			ccbfree(ctlr, (Ccb*)ccb);			return SDmalloc;		}		if(r->write)			memmove(data, ccb->data, n);	}	else		data = r->data;	/*	 * Fill in the ccb.	 */	ccb->opcode = Ordl;	ccb->datadir = (target<<5)|lun;	if(n == 0)		ccb->datadir |= CCBdataout|CCBdatain;	else if(!r->write)		ccb->datadir |= CCBdatain;	else		ccb->datadir |= CCBdataout;	ccb->cdblen = r->clen;	ccb->senselen = 0xFF;	ccb->datalen[0] = n>>16;	ccb->datalen[1] = n>>8;	ccb->datalen[2] = n;	p = PADDR(data);	ccb->dataptr[0] = p>>16;	ccb->dataptr[1] = p>>8;	ccb->dataptr[2] = p;	ccb->linkptr[0] = ccb->linkptr[1] = ccb->linkptr[2] = 0;	ccb->linkid = 0;	ccb->btstat = ccb->sdstat = 0;	ccb->reserved[0] = ccb->reserved[1] = 0;	memmove(ccb->cs, r->cmd, r->clen);	/*	 * There's one more mbox than there there is	 * ccb so there is always one free.	 */	lock(&ctlr->mboxlock);	mb = ctlr->mb;	mb += ctlr->mbox;	p = PADDR(ccb);	mb->ccb[0] = p>>16;	mb->ccb[1] = p>>8;	mb->ccb[2] = p;	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, done24, 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 be updated, so fix it here.	 */	sdstat = ccb->sdstat;	btstat = ccb->btstat;	d = ccb->datalen[0]<<16;	d |= ccb->datalen[1]<<8;	d |= ccb->datalen[2];	if(ccb->cs[0] == 0x25 && sdstat == SDok)		d = 0;	n -= d;	r->rlen = n;	/*	 * Tidy things up if a staging area was used for the data,	 */	if(ccb->data){		if(sdstat == SDok && btstat == 0 && !r->write)			memmove(ccb->data, data, n);		free(data);		ccb->data = nil;	}	/*	 * 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;		}		sense = &ccb->cs[ccb->cdblen];		n = 8+sense[7];		if(n > sizeof(r->sense)-1)			n = sizeof(r->sense)-1;		memmove(r->sense, sense, n);		r->flags |= SDvalidsense;	}	ccbfree(ctlr, (Ccb*)ccb);	if(btstat){		if(btstat == 0x11)			return SDtimeout;		return SDeio;	}	return sdstat;}static voidmylex24interrupt(Ureg*, void* arg){	ulong pa;	Ctlr *ctlr;	Ccb24 *ccb;	Mbox24 *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, save the status, free the mailbox	 * and wakeup whoever.	 */	mb = ctlr->mb;	for(mbox = &mb[ctlr->mbix]; mbox->code; mbox = &mb[ctlr->mbix]){		pa = (mbox->ccb[0]<<16)|(mbox->ccb[1]<<8)|mbox->ccb[2];		ccb = BPA2K(pa, BUSUNKNOWN);		mbox->code = 0;		ccb->done = 1;		wakeup(ccb);		ctlr->mbix++;		if(ctlr->mbix >= NMbox+NMbox)			ctlr->mbix = NMbox;	}}static intdone32(void* arg){	return ((Ccb32*)arg)->done;}static intmylex32rio(SDreq* r){	ulong p;	uchar lun;	Ctlr *ctlr;	Ccb32 *ccb;	Mbox32 *mb;	int d, n, btstat, sdstat, target;	ctlr = r->unit->dev->ctlr;	target = r->unit->subno;	lun = (r->cmd[1]>>5) & 0x07;	/*	 * Ctlr->cache holds the last completed Ccb for this target if it	 * returned 'check condition'.	 * If this command is a request-sense and there is valid sense data	 * from the last completed Ccb, return it immediately.	 */	lock(&ctlr->cachelock);	if(ccb = ctlr->cache[target]){		ctlr->cache[target] = nil;		if(r->cmd[0] == 0x03		  && ccb->sdstat == SDcheck && lun == (ccb->luntag & 0x07)){			unlock(&ctlr->cachelock);			if(r->dlen){				n = 8+ccb->sense[7];				if(n > r->dlen)					n = r->dlen;				memmove(r->data, ccb->sense, n);				r->rlen = n;			}			ccbfree(ctlr, (Ccb*)ccb);			return SDok;		}	}	unlock(&ctlr->cachelock);	if(ccb == nil)		ccb = ccballoc(ctlr);	/*	 * Fill in the ccb.	 */	ccb->opcode = Ordl;	n = r->dlen;	if(n == 0)		ccb->datadir |= CCBdataout|CCBdatain;	else if(!r->write)		ccb->datadir |= CCBdatain;	else		ccb->datadir |= CCBdataout;	ccb->cdblen = r->clen;	ccb->datalen[0] = n;	ccb->datalen[1] = n>>8;	ccb->datalen[2] = n>>16;	ccb->datalen[3] = n>>24;	p = PADDR(r->data);	ccb->dataptr[0] = p;	ccb->dataptr[1] = p>>8;	ccb->dataptr[2] = p>>16;	ccb->dataptr[3] = p>>24;	ccb->targetid = target;	ccb->luntag = lun;	if(r->unit->inquiry[7] & 0x02)		ccb->luntag |= SQTag|TagEnable;	memmove(ccb->cdb, r->cmd, r->clen);	ccb->btstat = ccb->sdstat = 0;	ccb->ccbctl = 0;	/*	 * There's one more mbox than there there is	 * ccb so there is always one free.	 */	lock(&ctlr->mboxlock);	mb = ctlr->mb;	mb += ctlr->mbox;	p = PADDR(ccb);	mb->ccb[0] = p;	mb->ccb[1] = p>>8;	mb->ccb[2] = p>>16;	mb->ccb[3] = p>>24;

⌨️ 快捷键说明

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