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

📄 sdata.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
	drive->status = 0;	drive->error = 0;	if(drive->pkt)		status = atapktio(drive, cmdp, clen);	else		status = atagenio(drive, cmdp, clen);	if(status == SDretry){		if(DbgDEBUG)			print("%s: retry: dma %8.8uX rwm %4.4uX\n",				unit->name, drive->dmactl, drive->rwmctl);		goto retry;	}	if(status == SDok){		atasetsense(drive, SDok, 0, 0, 0);		if(drive->data){			p = r->data;			r->rlen = drive->data - p;		}		else			r->rlen = 0;	}	else if(status == SDcheck && !(r->flags & SDnosense)){		drive->write = 0;		memset(cmd10, 0, sizeof(cmd10));		cmd10[0] = 0x03;		cmd10[1] = r->lun<<5;		cmd10[4] = sizeof(r->sense)-1;		drive->data = r->sense;		drive->dlen = sizeof(r->sense)-1;		drive->status = 0;		drive->error = 0;		if(drive->pkt)			reqstatus = atapktio(drive, cmd10, 6);		else			reqstatus = atagenio(drive, cmd10, 6);		if(reqstatus == SDok){			r->flags |= SDvalidsense;			atasetsense(drive, SDok, 0, 0, 0);		}	}	qunlock(drive);	r->status = status;	if(status != SDok)		return status;	/*	 * Fix up any results.	 * Many ATAPI CD-ROMs ignore the LUN field completely and	 * return valid INQUIRY data. Patch the response to indicate	 * 'logical unit not supported' if the LUN is non-zero.	 */	switch(cmdp[0]){	case 0x12:			/* inquiry */		if((p = r->data) == nil)			break;		if((cmdp[1]>>5) && (!drive->pkt || (p[0] & 0x1F) == 0x05))			p[0] = 0x7F;		/*FALLTHROUGH*/	default:		break;	}	return SDok;}static voidatainterrupt(Ureg*, void*arg ){	Ctlr *ctlr;	Drive *drive;	int cmdport, len, status;	ctlr = arg;	ilock(ctlr);	if(inb(ctlr->ctlport+As) & Bsy){		iunlock(ctlr);		if(DEBUG & DbgDEBUG)			print("IBsy+");		return;	}	cmdport = ctlr->cmdport;	status = inb(cmdport+Status);	if((drive = ctlr->curdrive) == nil){		iunlock(ctlr);		if((DEBUG & DbgDEBUG) && ctlr->command != Cedd)			print("Inil%2.2uX/%2.2uX+", ctlr->command, status);		return;	}	if(status & Err)		drive->error = inb(cmdport+Error);	else switch(drive->command){	default:		drive->error = Abrt;		break;	case Crs:	case Crsm:		if(!(status & Drq)){			drive->error = Abrt;			break;		}		len = drive->block;		if(drive->data+len > drive->limit)			len = drive->limit-drive->data;		inss(cmdport+Data, drive->data, len/2);		drive->data += len;		if(drive->data >= drive->limit)			ctlr->done = 1;		break;	case Cws:	case Cwsm:		len = drive->block;		if(drive->data+len > drive->limit)			len = drive->limit-drive->data;		drive->data += len;		if(drive->data >= drive->limit){			ctlr->done = 1;			break;		}		if(!(status & Drq)){			drive->error = Abrt;			break;		}		len = drive->block;		if(drive->data+len > drive->limit)			len = drive->limit-drive->data;		outss(cmdport+Data, drive->data, len/2);		break;	case Cpkt:		atapktinterrupt(drive);		break;	case Crd:	case Cwd:		atadmainterrupt(drive, drive->count*drive->secsize);		break;	case Cstandby:		ctlr->done = 1;		break;	}	iunlock(ctlr);	if(drive->error){		status |= Err;		ctlr->done = 1;	}	if(ctlr->done){		ctlr->curdrive = nil;		drive->status = status;		wakeup(ctlr);	}}#ifdef notdefstatic SDev*atapnp(void){	int	cmdport;	int	ctlport;	int	irq;	cmdport = 0x200;	ctlport = cmdport + 0x0C;	irq = 10;	return ataprobe(cmdport, ctlport, irq);}#endifstatic SDev*atalegacy(int port, int irq){	return ataprobe(port, port+0x204, irq);}static int ataitype;static int atairq;static intataenable(SDev* sdev){	Ctlr *ctlr;	char name[KNAMELEN];	ctlr = sdev->ctlr;	if(ctlr->bmiba){		ctlr->prdt = xspanalloc(Nprd*sizeof(Prd), 4, 4*1024);	}	snprint(name, KNAMELEN, "%s (%s)", sdev->name, sdev->ifc->name);//	intrenable(ctlr->irq, atainterrupt, ctlr, ctlr->tbdf, name);	outb(ctlr->ctlport+Dc, 0);	intrenable(ataitype, atairq, atainterrupt, ctlr, name);	if(ctlr->ienable)		ctlr->ienable(ctlr);	return 1;}static intatarctl(SDunit* unit, char* p, int l){	int n;	Ctlr *ctlr;	Drive *drive;	if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil)		return 0;	drive = ctlr->drive[unit->subno];	qlock(drive);	n = snprint(p, l, "config %4.4uX capabilities %4.4uX",		drive->info[Iconfig], drive->info[Icapabilities]);	if(drive->dma)		n += snprint(p+n, l-n, " dma %8.8uX dmactl %8.8uX",			drive->dma, drive->dmactl);	if(drive->rwm)		n += snprint(p+n, l-n, " rwm %ud rwmctl %ud",			drive->rwm, drive->rwmctl);	n += snprint(p+n, l-n, "\n");	if(unit->sectors){		n += snprint(p+n, l-n, "geometry %ld %ld",			unit->sectors, unit->secsize);		if(drive->pkt == 0)			n += snprint(p+n, l-n, " %d %d %d",				drive->c, drive->h, drive->s);		n += snprint(p+n, l-n, "\n");	}	qunlock(drive);	return n;}static intatawctl(SDunit* unit, Cmdbuf* cb){	int period;	Ctlr *ctlr;	Drive *drive;	if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil)		return 0;	drive = ctlr->drive[unit->subno];	qlock(drive);	if(waserror()){		qunlock(drive);		nexterror();	}	/*	 * Dma and rwm control is passive at the moment,	 * i.e. it is assumed that the hardware is set up	 * correctly already either by the BIOS or when	 * the drive was initially identified.	 */	if(strcmp(cb->f[0], "dma") == 0){		if(cb->nf != 2 || drive->dma == 0)			error(Ebadctl);		if(strcmp(cb->f[1], "on") == 0)			drive->dmactl = drive->dma;		else if(strcmp(cb->f[1], "off") == 0)			drive->dmactl = 0;		else			error(Ebadctl);	}	else if(strcmp(cb->f[0], "rwm") == 0){		if(cb->nf != 2 || drive->rwm == 0)			error(Ebadctl);		if(strcmp(cb->f[1], "on") == 0)			drive->rwmctl = drive->rwm;		else if(strcmp(cb->f[1], "off") == 0)			drive->rwmctl = 0;		else			error(Ebadctl);	}	else if(strcmp(cb->f[0], "standby") == 0){		switch(cb->nf){		default:			error(Ebadctl);		case 2:			period = strtol(cb->f[1], 0, 0);			if(period && (period < 30 || period > 240*5))				error(Ebadctl);			period /= 5;			break;		}		if(atastandby(drive, period) != SDok)			error(Ebadctl);	}	else		error(Ebadctl);	qunlock(drive);	poperror();	return 0;}static intscsitest(SDreq* r){	r->write = 0;	memset(r->cmd, 0, sizeof(r->cmd));	r->cmd[1] = r->lun<<5;	r->clen = 6;	r->data = nil;	r->dlen = 0;	r->flags = 0;	r->status = ~0;	return r->unit->dev->ifc->rio(r);}static intscsirio(SDreq* r){	/*	 * Perform an I/O request, returning	 *	-1	failure	 *	 0	ok	 *	 1	no medium present	 *	 2	retry	 * The contents of r may be altered so the	 * caller should re-initialise if necesary.	 */	r->status = ~0;	switch(r->unit->dev->ifc->rio(r)){	default:		return -1;	case SDcheck:		if(!(r->flags & SDvalidsense))			return -1;		switch(r->sense[2] & 0x0F){		case 0x00:		/* no sense */		case 0x01:		/* recovered error */			return 2;		case 0x06:		/* check condition */			/*			 * 0x28 - not ready to ready transition,			 *	  medium may have changed.			 * 0x29 - power on or some type of reset.			 */			if(r->sense[12] == 0x28 && r->sense[13] == 0)				return 2;			if(r->sense[12] == 0x29)				return 2;			return -1;		case 0x02:		/* not ready */			/*			 * If no medium present, bail out.			 * If unit is becoming ready, rather than not			 * not ready, wait a little then poke it again. 				 */			if(r->sense[12] == 0x3A)				return 1;			if(r->sense[12] != 0x04 || r->sense[13] != 0x01)				return -1;			while(waserror())				;			tsleep(&up->sleep, return0, 0, 500);			poperror();			scsitest(r);			return 2;		default:			return -1;		}		return -1;	case SDok:		return 0;	}	return -1;}static intataverify(SDunit* unit){	SDreq *r;	int i, status;	uchar *inquiry;	if((r = malloc(sizeof(SDreq))) == nil)		return 0;	if((inquiry = sdmalloc(sizeof(unit->inquiry))) == nil){		free(r);		return 0;	}	r->unit = unit;	r->lun = 0;		/* ??? */	memset(unit->inquiry, 0, sizeof(unit->inquiry));	r->write = 0;	r->cmd[0] = 0x12;	r->cmd[1] = r->lun<<5;	r->cmd[4] = sizeof(unit->inquiry)-1;	r->clen = 6;	r->data = inquiry;	r->dlen = sizeof(unit->inquiry)-1;	r->flags = 0;	r->status = ~0;	if(unit->dev->ifc->rio(r) != SDok){		free(r);		return 0;	}	memmove(unit->inquiry, inquiry, r->dlen);	free(inquiry); 	SET(status);	for(i = 0; i < 3; i++){		while((status = scsitest(r)) == SDbusy)			;		if(status == SDok || status != SDcheck)			break;		if(!(r->flags & SDvalidsense))			break;		if((r->sense[2] & 0x0F) != 0x02)			continue;		/*		 * Unit is 'not ready'.		 * If it needs an initialising command, set status		 * so it will be spun-up below.		 * If there's no medium, that's OK too, but don't		 * try to spin it up.		 */		if(r->sense[12] == 0x04 && r->sense[13] == 0x02){			status = SDok;			break;		}		if(r->sense[12] == 0x3A)			break;	}	if(status == SDok){		/*		 * Try to ensure a direct-access device is spinning.		 * Don't wait for completion, ignore the result.		 */		if((unit->inquiry[0] & 0x1F) == 0){			memset(r->cmd, 0, sizeof(r->cmd));			r->write = 0;			r->cmd[0] = 0x1B;			r->cmd[1] = (r->lun<<5)|0x01;			r->cmd[4] = 1;			r->clen = 6;			r->data = nil;			r->dlen = 0;			r->flags = 0;			r->status = ~0;			unit->dev->ifc->rio(r);		}	}	free(r);	if(status == SDok || status == SDcheck)		return 1;	return 0;}static intataonline(SDunit* unit){	SDreq *r;	uchar *p;	int ok, retries;	if((r = malloc(sizeof(SDreq))) == nil)		return 0;	if((p = sdmalloc(8)) == nil){		free(r);		return 0;	}	ok = 0;	r->unit = unit;	r->lun = 0;				/* ??? */	for(retries = 0; retries < 10; retries++){		/*		 * Read-capacity is mandatory for DA, WORM, CD-ROM and		 * MO. It may return 'not ready' if type DA is not		 * spun up, type MO or type CD-ROM are not loaded or just		 * plain slow getting their act together after a reset.		 */		r->write = 0;		memset(r->cmd, 0, sizeof(r->cmd));		r->cmd[0] = 0x25;		r->cmd[1] = r->lun<<5;		r->clen = 10;		r->data = p;		r->dlen = 8;		r->flags = 0;			r->status = ~0;		switch(scsirio(r)){		default:			break;		case 0:			unit->sectors = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];			/*			 * Read-capacity returns the LBA of the last sector,			 * therefore the number of sectors must be incremented.			 */			unit->sectors++;			unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];			/*			 * Some ATAPI CD readers lie about the block size.			 * Since we don't read audio via this interface			 * it's okay to always fudge this.			 */			if(unit->secsize == 2352)				unit->secsize = 2048;			ok = 1;			break;		case 1:			ok = 1;			break;		case 2:			continue;		}		break;	}	free(p);	free(r);	if(ok)		return ok+retries;	else		return 0;}static longatabio(SDunit* unit, int lun, int write, void* data, long nb, long bno){	SDreq *r;	long rlen;	if((r = malloc(sizeof(SDreq))) == nil)		error(Enomem);	r->unit = unit;	r->lun = lun;again:	r->write = write;	if(write == 0)		r->cmd[0] = 0x28;	else		r->cmd[0] = 0x2A;	r->cmd[1] = (lun<<5);	r->cmd[2] = bno>>24;	r->cmd[3] = bno>>16;	r->cmd[4] = bno>>8;	r->cmd[5] = bno;	r->cmd[6] = 0;	r->cmd[7] = nb>>8;	r->cmd[8] = nb;	r->cmd[9] = 0;	r->clen = 10;	r->data = data;	r->dlen = nb*unit->secsize;	r->flags = 0;	r->status = ~0;	switch(scsirio(r)){	default:		rlen = -1;		break;	case 0:		rlen = r->rlen;		break;	case 2:		rlen = -1;		if(!(r->flags & SDvalidsense))			break;		switch(r->sense[2] & 0x0F){		default:			break;		case 0x06:		/* check condition */			/*			 * Check for a removeable media change.			 * If so, mark it by zapping the geometry info			 * to force an online request.			 */			if(r->sense[12] != 0x28 || r->sense[13] != 0)				break;			if(unit->inquiry[1] & 0x80)				unit->sectors = 0;			break;		case 0x02:		/* not ready */			/*			 * If unit is becoming ready,			 * rather than not not ready, try again.			 */			if(r->sense[12] == 0x04 && r->sense[13] == 0x01)				goto again;			break;		}		break;	}	free(r);	return rlen;}struct Try {	int p;	int c;} tries[] = {		   { 0, 0x0c },		   { 0, 0 }, };static SDev*ataprobew(DevConf *cf){	int	cmdport;	int	ctlport;	int	irq;	SDev*	rc;	struct Try *try;	rc = nil;	for (try = &tries[0]; try->p != 0 || try->c != 0; try++){		ataitype = cf->itype;		atairq  = cf->intnum;		cmdport = cf->ports[0].port + try->p;		ctlport = cmdport + try->c;		irq = cf->intnum;		rc = ataprobe(cmdport, ctlport, irq);		if (rc)			break;	}	return rc;}static voidataclear(SDev *sdev){	Ctlr* ctlr;	ctlr = sdev->ctlr;	if (ctlr->drive[0])		free(ctlr->drive[0]);	if (ctlr->drive[1])		free(ctlr->drive[1]);	if (sdev->name)		free(sdev->name);	if (sdev->unitflg)		free(sdev->unitflg);	if (sdev->unit)		free(sdev->unit);	free(ctlr);	free(sdev);}static char *atastat(SDev *sdev, char *p, char *e){	Ctlr *ctlr = sdev->ctlr;	return seprint(p, e, "%s ata port %X ctl %X irq %d\n", 		    	       sdev->name, ctlr->cmdport, ctlr->ctlport, ctlr->irq);}SDifc sdataifc = {	"ata",				/* name */	nil,				/* pnp */	atalegacy,			/* legacy */	ataenable,			/* enable */	nil,				/* disable */	ataverify,			/* verify */	ataonline,			/* online */	atario,				/* rio */	atarctl,			/* rctl */	atawctl,			/* wctl */	atabio,				/* bio */	ataprobew,			/* probew */	ataclear,			/* clear */	atastat,			/* stat */};

⌨️ 快捷键说明

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