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

📄 sdata.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 5 页
字号:
		return SDok;	case 0x9E:			/* long 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>>56;		*p++ = len>>48;		*p++ = len>>40;		*p++ = len>>32;		*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);	if(ctlr->maxio)		maxio = ctlr->maxio;	else if(drive->flags & Lba48)		maxio = 65536;	else		maxio = 256;	while(count){		if(count > maxio)			drive->count = maxio;		else			drive->count = count;		if(atageniostart(drive, lba)){			ilock(ctlr);			atanop(drive, 0);			iunlock(ctlr);			qunlock(ctlr);			return atagenioretry(drive);		}		while(waserror())			;		tsleep(ctlr, atadone, ctlr, 60*1000);		poperror();		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.			 */			atadumpstate(drive, cmd, lba, count);			ataabort(drive, 1);			qunlock(ctlr);			return atagenioretry(drive);		}		if(drive->status & Err){			qunlock(ctlr);			return atasetsense(drive, SDcheck, 4, 8, drive->error);		}		count -= drive->count;		lba += 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);retry:	drive->write = r->write;	drive->data = r->data;	drive->dlen = r->dlen;	drive->status = 0;	drive->error = 0;	if(drive->pkt)		status = atapktio(drive, cmdp, clen);	else		status = atagenio(drive, cmdp, clen);	if(status == SDretry){		if(DEBUG & 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 & DbgBsy)			print("IBsy+");		return;	}	cmdport = ctlr->cmdport;	status = inb(cmdport+Status);	if((drive = ctlr->curdrive) == nil){		iunlock(ctlr);		if((DEBUG & DbgINL) && ctlr->command != Cedd)			print("Inil%2.2uX+", ctlr->command);		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);	}}static SDev*atapnp(void){	Ctlr *ctlr;	Pcidev *p;	SDev *legacy[2], *sdev, *head, *tail;	int channel, ispc87415, maxio, pi, r, span;	static int done;	if (done)		return nil;	done = 1;	legacy[0] = legacy[1] = head = tail = nil;	if(sdev = ataprobe(Ctlr0cmd, Ctlr0ctl, IrqATA0)){		head = tail = sdev;		legacy[0] = sdev;	}	if(sdev = ataprobe(Ctlr1cmd, Ctlr1ctl, 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).		 * Sub-class code 0x04 is 'RAID controller', e.g. VIA VT8237.		 */		if(p->ccrb != 0x01)			continue;		/*		 * file server special: ccru is a short in the FS kernel,		 * thus the cast to uchar.		 */		switch ((uchar)p->ccru) {		case 1:		case 4:		case 0x80:			break;		default:			continue;		}		pi = p->ccrp;		ispc87415 = 0;		maxio = 0;		span = BMspan;		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 (0x1000<<16)|0x1042:	/* PC-Tech RZ1000 */			/*			 * Turn off prefetch. Overkill, but cheap.			 */			r = pcicfgr32(p, 0x40);			r &= ~0x2000;			pcicfgw32(p, 0x40, r);			break;		case (0x4D38<<16)|0x105A:	/* Promise PDC20262 */		case (0x4D30<<16)|0x105A:	/* Promise PDC202xx */		case (0x4D68<<16)|0x105A:	/* Promise PDC20268 */		case (0x4D69<<16)|0x105A:	/* Promise Ultra/133 TX2 */		case (0x3373<<16)|0x105A:	/* Promise 20378 RAID */		case (0x3149<<16)|0x1106:	/* VIA VT8237 SATA/RAID */		case (0x3112<<16)|0x1095:   	/* SiI 3112 SATA/RAID */			maxio = 15;			span = 8*1024;			/*FALLTHROUGH*/		case (0x3114<<16)|0x1095:	/* SiI 3114 SATA/RAID */			pi = 0x85;			break;		case (0x0004<<16)|0x1103:	/* HighPoint HPT366 */			pi = 0x85;			/*			 * Turn off fast interrupt prediction.			 */			if((r = pcicfgr8(p, 0x51)) & 0x80)				pcicfgw8(p, 0x51, r & ~0x80);			if((r = pcicfgr8(p, 0x55)) & 0x80)				pcicfgw8(p, 0x55, r & ~0x80);			break;		case (0x0640<<16)|0x1095:	/* CMD 640B */			/*			 * Bugfix code here...			 */			break;		case (0x7441<<16)|0x1022:	/* AMD 768 */			/*			 * Set:			 *	0x41	prefetch, postwrite;			 *	0x43	FIFO configuration 1/2 and 1/2;			 *	0x44	status register read retry;			 *	0x46	DMA read and end of sector flush.			 */			r = pcicfgr8(p, 0x41);			pcicfgw8(p, 0x41, r|0xF0);			r = pcicfgr8(p, 0x43);			pcicfgw8(p, 0x43, (r & 0x90)|0x2A);			r = pcicfgr8(p, 0x44);			pcicfgw8(p, 0x44, r|0x08);			r = pcicfgr8(p, 0x46);			pcicfgw8(p, 0x46, (r & 0x0C)|0xF0);		case (0x7469<<16)|0x1022:	/* AMD 3111 */			/*			 * This can probably be lumped in with the 768 above.			 */			/*FALLTHROUGH*/		case (0x01BC<<16)|0x10DE:	/* nVidia nForce1 */		case (0x0065<<16)|0x10DE:	/* nVidia nForce2 */		case (0x0085<<16)|0x10DE:	/* nVidia nForce2 MCP */		case (0x00D5<<16)|0x10DE:	/* nVidia nForce3 */		case (0x00E5<<16)|0x10DE:	/* nVidia nForce3 Pro */		case (0x0035<<16)|0x10DE:	/* nVidia nForce3 MCP */		case (0x0053<<16)|0x10DE:	/* nVidia nForce4 */			/*			 * Ditto, although it may have a different base			 * address for the registers (0x50?).			 */			/*FALLTHROUGH*/		case (0x4376<<16)|0x1002:	/* ATI Radeon Xpress 200M */			break;		case (0x0211<<16)|0x1166:	/* ServerWorks IB6566 */			{				Pcidev *sb;				sb = pcimatch(nil, 0x1166, 0x0200);				if(sb == nil)					break;				r = pcicfgr32(sb, 0x64);				r &= ~0x2000;				pcicfgw32(sb, 0x64, r);			}			span = 32*1024;			break;		case (0x5513<<16)|0x1039:	/* SiS 962 */		case (0x0646<<16)|0x1095:	/* CMD 646 */		case (0x0571<<16)|0x1106:	/* VIA 82C686 */		case (0x1230<<16)|0x8086:	/* 82371FB (PIIX) */		case (0x7010<<16)|0x8086:	/* 82371SB (PIIX3) */		case (0x7111<<16)|0x8086:	/* 82371[AE]B (PIIX4[E]) */		case (0x2411<<16)|0x8086:	/* 82801AA (ICH) */		case (0x2421<<16)|0x8086:	/* 82801AB (ICH0) */		case (0x244A<<16)|0x8086:	/* 82801BA (ICH2, Mobile) */		case (0x244B<<16)|0x8086:	/* 82801BA (ICH2, High-End) */		case (0x248A<<16)|0x8086:	/* 82801CA (ICH3, Mobile) */		case (0x248B<<16)|0x8086:	/* 82801CA (ICH3, High-End) */		case (0x24CA<<16)|0x8086:	/* 82801DBM (ICH4, Mobile) */		case (0x24CB<<16)|0x8086:	/* 82801DB (ICH4, High-End) */		case (0x24DB<<16)|0x8086:	/* 82801EB (ICH5) */		case (0x266F<<16)|0x8086:	/* 82801FB (ICH6) */			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;					print("pc87415disable: not yet implemented\n");				}				if(head != nil)					tail->next = sdev;				else					head = sdev;				tail = sdev;				ctlr->tbdf = p->tbdf;			}			else if((sdev = legacy[channel]) == nil)				continue;			else				ctlr = sdev->ctlr;			ctlr->pcidev = p;			ctlr->maxio = maxio;			ctlr->span = span;			if(!(pi & 0x80))				continue;			ctlr->bmiba = (p->mem[4].bar & ~0x01) + channel*8;		}	}	return head;}static SDev*atalegacy(int port, int irq){	return ataprobe(port, port+Ctl2cmd, irq);}static SDev*ataid(SDev* sdev){	int i;	Ctlr *ctlr;	char name[32];	/*	 * 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'.	 */	if(sdev == nil)		return nil;	ctlr = sdev->ctlr;	if(ctlr->cmdport == Ctlr0cmd || ctlr->cmdport == Ctlr1cmd)		i = 2;	else		i = 0;	while(sdev){		if(sdev->ifc == &sdataifc){			ctlr = sdev->ctlr;			if(ctlr->cmdport == Ctlr0cmd)				sdev->idno = 'C';			else if(ctlr->cmdport == Ctlr1cmd)				sdev->idno = 'D';			else{				sdev->idno = 'C'+i;				i++;			}			snprint(name, sizeof(name), "sd%c", sdev->idno);			kstrdup(&sdev->name, name);		}		sdev = sdev->next;	}	return nil;}static int

⌨️ 快捷键说明

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