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

📄 sdata.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
📖 第 1 页 / 共 3 页
字号:
		}		return SDok;	case 0x12:			/* inquiry */		if(cmd[4] < sizeof(drive->inquiry))			len = cmd[4];		else			len = sizeof(drive->inquiry);		if(drive->data && drive->dlen >= len){			memmove(drive->data, drive->inquiry, len);			drive->data += len;		}		return SDok;	case 0x1B:			/* start/stop unit */		/*		 * NOP for now, can use the power management feature		 * set later.		 */		return SDok;	case 0x25:			/* read capacity */		if((cmd[1] & 0x01) || cmd[2] || cmd[3])			return atasetsense(drive, SDcheck, 0x05, 0x24, 0);		if(drive->data == nil || drive->dlen < 8)			return atasetsense(drive, SDcheck, 0x05, 0x20, 1);		/*		 * Read capacity returns the LBA of the last sector.		 */		len = drive->sectors-1;		p = drive->data;		*p++ = len>>24;		*p++ = len>>16;		*p++ = len>>8;		*p++ = len;		len = drive->secsize;		*p++ = len>>24;		*p++ = len>>16;		*p++ = len>>8;		*p = len;		drive->data += 8;		return SDok;	case 0x28:			/* read */	case 0x2A:			/* write */		break;	case 0x5A:		return atamodesense(drive, cmd);	}	ctlr = drive->ctlr;	lba = (cmd[2]<<24)|(cmd[3]<<16)|(cmd[4]<<8)|cmd[5];	count = (cmd[7]<<8)|cmd[8];	if(drive->data == nil)		return SDok;	if(drive->dlen < count*drive->secsize)		count = drive->dlen/drive->secsize;	qlock(ctlr);	while(count){		if(count > 256)			drive->count = 256;		else			drive->count = count;		drive->limit += drive->count*drive->secsize;		if(atageniostart(drive, lba)){			qunlock(ctlr);			return atasetsense(drive, SDcheck, 2, 5, 0);		}		lba += drive->count;		tsleep(ctlr, atageniodone, ctlr, 10*1000);		if(!ctlr->done){			/*			 * What should the above timeout be? In			 * standby and sleep modes it could take as			 * long as 30 seconds for a drive to respond.			 * Very hard to get out of this cleanly.			 * Let's see if it ever happens first...			 */			panic("atagenio");		}		if(drive->status & Err){			qunlock(ctlr);			return atasetsense(drive, SDcheck, 4, 8, drive->error);		}		if(drive->data != drive->limit)			print("atagenio: %d != %d\n",				(int)drive->data, (int)drive->limit);		count -= drive->count;	}	qunlock(ctlr);	return SDok;}static intatario(SDreq* r){	Ctlr *ctlr;	Drive *drive;	SDunit *unit;	uchar cmd10[10], *cmdp, *p;	int clen, reqstatus, status;	unit = r->unit;	if((ctlr = unit->dev->ctlr) == nil || ctlr->drive[unit->subno] == nil){		r->status = SDtimeout;		return SDtimeout;	}	drive = ctlr->drive[unit->subno];	/*	 * Most SCSI commands can be passed unchanged except for	 * the padding on the end. The few which require munging	 * are not used internally. Mode select/sense(6) could be	 * converted to the 10-byte form but it's not worth the	 * effort. Read/write(6) are easy.	 */	switch(r->cmd[0]){	case 0x08:			/* read */	case 0x0A:			/* write */		cmdp = cmd10;		memset(cmdp, 0, sizeof(cmd10));		cmdp[0] = r->cmd[0]|0x20;		cmdp[1] = r->cmd[1] & 0xE0;		cmdp[5] = r->cmd[3];		cmdp[4] = r->cmd[2];		cmdp[3] = r->cmd[1] & 0x0F;		cmdp[8] = r->cmd[4];		clen = sizeof(cmd10);		break;	default:		cmdp = r->cmd;		clen = r->clen;		break;	}	qlock(drive);	drive->write = r->write;	drive->data = r->data;	drive->dlen = r->dlen;	drive->limit = r->data;	drive->status = 0;	drive->error = 0;	if(drive->pkt)		status = atapktio(drive, cmdp, clen);	else		status = atagenio(drive, cmdp, clen);	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->limit = r->sense;		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);		return;	}	cmdport = ctlr->cmdport;	status = inb(cmdport+Status);	if((drive = ctlr->curdrive) == nil){		iunlock(ctlr);		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:		panic("atadmainterrupt");		break;	}	iunlock(ctlr);	if(drive->error){		status |= Err;		ctlr->done = 1;	}	if(ctlr->done){		ctlr->curdrive = nil;		drive->status = status;		wakeup(ctlr);	}}static SDev*atapnp(void){	Ctlr *ctlr;	Pcidev *p;	int channel, ispc87415, pi;	SDev *legacy[2], *sdev, *head, *tail;	legacy[0] = legacy[1] = head = tail = nil;	if(sdev = ataprobe(0x1F0, 0x3F4, IrqATA0)){		head = tail = sdev;		legacy[0] = sdev;	}	if(sdev = ataprobe(0x170, 0x374, IrqATA1)){		if(head != nil)			tail->next = sdev;		else			head = sdev;		tail = sdev;		legacy[1] = sdev;	}	p = nil;	while(p = pcimatch(p, 0, 0)){		/*		 * Look for devices with the correct class and sub-class		 * code and known device and vendor ID; add native-mode		 * channels to the list to be probed, save info for the		 * compatibility mode channels.		 * Note that the legacy devices should not be considered		 * PCI devices by the interrupt controller.		 * For both native and legacy, save info for busmastering		 * if capable.		 * Promise Ultra ATA/66 (PDC20262) appears to		 * 1) give a sub-class of 'other mass storage controller'		 *    instead of 'IDE controller', regardless of whether it's		 *    the only controller or not;		 * 2) put 0 in the programming interface byte (probably		 *    as a consequence of 1) above).		 */		if(p->ccrb != 0x01 || (p->ccru != 0x01 && p->ccru != 0x80))			continue;		pi = p->ccrp;		ispc87415 = 0;		switch((p->did<<16)|p->vid){		default:			continue;		case (0x0002<<16)|0x100B:	/* NS PC87415 */			/*			 * Disable interrupts on both channels until			 * after they are probed for drives.			 * This must be called before interrupts are			 * enabled because the IRQ may be shared.			 */			ispc87415 = 1;			pcicfgw32(p, 0x40, 0x00000300);			break;		case (0x4D38<<16)|0x105A:	/* Promise PDC20262 */			pi = 0x85;			/*FALLTHROUGH*/		case (0x1230<<16)|0x8086:	/* 82371FB (PIIX) */		case (0x7010<<16)|0x8086:	/* 82371SB (PIIX3) */		case (0x7111<<16)|0x8086:	/* 82371[AE]B (PIIX4[E]) */		case (0x0646<<16)|0x1095:	/* CMD 646 */		case (0x0571<<16)|0x1106:	/* VIA 82C686 */			break;		}		for(channel = 0; channel < 2; channel++){			if(pi & (1<<(2*channel))){				sdev = ataprobe(p->mem[0+2*channel].bar & ~0x01,						p->mem[1+2*channel].bar & ~0x01,						p->intl);				if(sdev == nil)					continue;				ctlr = sdev->ctlr;				if(ispc87415)					ctlr->ienable = pc87415ienable;				if(head != nil)					tail->next = sdev;				else					head = sdev;				tail = sdev;				ctlr->pcidev = p;			}		}	}	return head;}static SDev*atalegacy(int port, int irq){	return ataprobe(port, port+0x204, irq);}static SDev*ataid(SDev* sdev){	int i;	Ctlr *ctlr;	/*	 * Legacy controllers are always 'C' and 'D' and if	 * they exist and have drives will be first in the list.	 * If there are no active legacy controllers, native	 * controllers start at 'C'.	 */	ctlr = sdev->ctlr;	if(ctlr->cmdport == 0x1F0 || ctlr->cmdport == 0x170)		i = 2;	else		i = 0;	while(sdev){		if(sdev->ifc != &sdataifc)			continue;		ctlr = sdev->ctlr;		if(ctlr->cmdport == 0x1F0)			sdev->idno = 'C';		else if(ctlr->cmdport == 0x170)			sdev->idno = 'D';		else{			sdev->idno = 'C'+i;			i++;		}		sdev = sdev->next;	}	return nil;}static intataenable(SDev* sdev){	Ctlr *ctlr;	ctlr = sdev->ctlr;	setvec(ctlr->irq+VectorPIC, atainterrupt, ctlr);	outb(ctlr->ctlport+Dc, 0);	if(ctlr->ienable)		ctlr->ienable(ctlr);	return 1;}SDifc sdataifc = {	"ata",				/* name */	atapnp,				/* pnp */	atalegacy,			/* legacy */	ataid,				/* id */	ataenable,			/* enable */	nil,				/* disable */	scsiverify,			/* verify */	scsionline,			/* online */	atario,				/* rio */	nil,				/* rctl */	nil,				/* wctl */	scsibio,			/* bio */};

⌨️ 快捷键说明

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