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

📄 sdata.c

📁 著名操作系统Plan 9的第三版的部分核心源代码。现在很难找到了。Plan 9是bell实验室开发的Unix后继者。
💻 C
📖 第 1 页 / 共 3 页
字号:
			drive->c = drive->info[Ilcyl];			drive->h = drive->info[Ilhead];			drive->s = drive->info[Ilsec];		}		else{			drive->c = drive->info[Iccyl];			drive->h = drive->info[Ichead];			drive->s = drive->info[Icsec];		}		if(drive->info[Icapabilities] & 0x0200){			drive->sectors = (drive->info[Ilba1]<<16)					 |drive->info[Ilba0];			drive->dev |= Lba;		}		else			drive->sectors = drive->c*drive->h*drive->s;		atasetrwmode(drive, cmdport, ctlport, dev);	}		drive->dma = 0;	if(DEBUG & DbgCONFIG){		print("dev %2.2uX capabilities %4.4uX config %4.4uX",			dev, drive->info[Icapabilities], drive->info[Iconfig]);		print(" mwdma %4.4uX dma %8.8uX", 			drive->info[Imwdma], drive->dma);		if(drive->info[Ivalid] & 0x04)			print(" udma %4.4uX", drive->info[Iudma]);		print("\n");	}	return drive;}static voidatasrst(int ctlport){	/*	 * Srst is a big stick and may cause problems if further	 * commands are tried before the drives become ready again.	 * Also, there will be problems here if overlapped commands	 * are ever supported.	 */	microdelay(5);	outb(ctlport+Dc, Srst);	microdelay(5);	outb(ctlport+Dc, 0);	microdelay(2*1000);}static SDev*ataprobe(int cmdport, int ctlport, int irq){	Ctlr* ctlr;	SDev *sdev;	Drive *drive;	int dev, error, rhi, rlo;	/*	 * Try to detect a floating bus.	 * Bsy should be cleared. If not, see if the cylinder registers	 * are read/write capable.	 * If the master fails, try the slave to catch slave-only	 * configurations.	 * There's no need to restore the tested registers as they will	 * be reset on any detected drives by the Cedd command.	 * All this indicates is that there is at least one drive on the	 * controller; when the non-existent drive is selected in a	 * single-drive configuration the registers of the existing drive	 * are often seen, only command execution fails.	 */	dev = Dev0;	if(inb(ctlport+As) & Bsy){		outb(cmdport+Dh, dev);trydev1:		atadebug(cmdport, ctlport, "ataprobe bsy");		outb(cmdport+Cyllo, 0xAA);		outb(cmdport+Cylhi, 0x55);		outb(cmdport+Sector, 0xFF);		rlo = inb(cmdport+Cyllo);		rhi = inb(cmdport+Cylhi);		if(rlo != 0xAA && (rlo == 0xFF || rhi != 0x55)){			if(dev == Dev1){release:				return nil;			}			dev = Dev1;			if(ataready(cmdport, ctlport, dev, Bsy, 0, 20*1000) < 0)				goto trydev1;		}	}	/*	 * Disable interrupts on any detected controllers.	 */	outb(ctlport+Dc, Nien);tryedd1:	if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 100*1000) < 0){		/*		 * There's something there, but it didn't come up clean,		 * so try hitting it with a big stick. The timing here is		 * wrong but this is a last-ditch effort and it sometimes		 * gets some marginal hardware back online.		 */		atasrst(ctlport);		if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 100*1000) < 0)			goto release;	}	/*	 * Can only get here if controller is not busy.	 * If there are drives Bsy will be set within 400nS,	 * must wait 2mS before testing Status.	 * Wait for the command to complete (6 seconds max).	 */	outb(cmdport+Command, Cedd);	delay(2);	if(ataready(cmdport, ctlport, dev, Bsy|Drq, 0, 6*1000*1000) < 0)		goto release;	/*	 * If bit 0 of the error register is set then the selected drive	 * exists. This is enough to detect single-drive configurations.	 * However, if the master exists there is no way short of executing	 * a command to determine if a slave is present.	 * It appears possible to get here testing Dev0 although it doesn't	 * exist and the EDD won't take, so try again with Dev1.	 */	error = inb(cmdport+Error);	atadebug(cmdport, ctlport, "ataprobe: dev %uX", dev);	if((error & ~0x80) != 0x01){		if(dev == Dev1)			goto release;		dev = Dev1;		goto tryedd1;	}	/*	 * At least one drive is known to exist, try to	 * identify it. If that fails, don't bother checking	 * any further.	 * If the one drive found is Dev0 and the EDD command	 * didn't indicate Dev1 doesn't exist, check for it.	 */	if((drive = ataidentify(cmdport, ctlport, dev)) == nil)		goto release;	if((ctlr = malloc(sizeof(Ctlr))) == nil){		free(drive);		goto release;	}	if((sdev = malloc(sizeof(SDev))) == nil){		free(ctlr);		free(drive);		goto release;	}	drive->ctlr = ctlr;	if(dev == Dev0){		ctlr->drive[0] = drive;		if(!(error & 0x80)){			/*			 * Always leave Dh pointing to a valid drive,			 * otherwise a subsequent call to ataready on			 * this controller may try to test a bogus Status.			 * Ataprobe is the only place possibly invalid			 * drives should be selected.			 */			drive = ataidentify(cmdport, ctlport, Dev1);			if(drive != nil){				drive->ctlr = ctlr;				ctlr->drive[1] = drive;			}			else				outb(cmdport+Dh, Dev0);		}	}	else		ctlr->drive[1] = drive;	ctlr->cmdport = cmdport;	ctlr->ctlport = ctlport;	ctlr->irq = irq;	sdev->ifc = &sdataifc;	sdev->ctlr = ctlr;	sdev->nunit = 2;	return sdev;}static intatasetsense(Drive* drive, int status, int key, int asc, int ascq){	drive->sense[2] = key;	drive->sense[12] = asc;	drive->sense[13] = ascq;	return status;}static intatamodesense(Drive* drive, uchar* cmd){	int len;	/*	 * Fake a vendor-specific request with page code 0,	 * return the drive info.	 */	if((cmd[2] & 0x3F) != 0 && (cmd[2] & 0x3F) != 0x3F)		return atasetsense(drive, SDcheck, 0x05, 0x24, 0);	len = (cmd[7]<<8)|cmd[8];	if(len == 0)		return SDok;	if(len < 8+sizeof(drive->info))		return atasetsense(drive, SDcheck, 0x05, 0x1A, 0);	if(drive->data == nil || drive->dlen < len)		return atasetsense(drive, SDcheck, 0x05, 0x20, 1);	memset(drive->data, 0, 8);	drive->data[0] = sizeof(drive->info)>>8;	drive->data[1] = sizeof(drive->info);	memmove(drive->data+8, drive->info, sizeof(drive->info));	drive->data += 8+sizeof(drive->info);	return SDok;}static voidatanop(Drive* drive, int subcommand){	Ctlr* ctlr;	int as, cmdport, ctlport, timeo;	/*	 * Attempt to abort a command by using NOP.	 * In response, the drive is supposed to set Abrt	 * in the Error register, set (Drdy|Err) in Status	 * and clear Bsy when done. However, some drives	 * (e.g. ATAPI Zip) just go Bsy then clear Status	 * when done, hence the timeout loop only on Bsy	 * and the forced setting of drive->error.	 */	ctlr = drive->ctlr;	cmdport = ctlr->cmdport;	outb(cmdport+Features, subcommand);	outb(cmdport+Dh, drive->dev);	outb(cmdport+Command, 0);	microdelay(1);	ctlport = ctlr->ctlport;	for(timeo = 0; timeo < 1000; timeo++){		as = inb(ctlport+As);		if(!(as & Bsy))			break;		microdelay(1);	}	drive->error |= Abrt;}static intatapktiodone(void* arg){	return ((Ctlr*)arg)->done;}static voidatapktinterrupt(Drive* drive){	Ctlr* ctlr;	int cmdport, len;	ctlr = drive->ctlr;	cmdport = ctlr->cmdport;	switch(inb(cmdport+Ir) & (/*Rel|*/Io|Cd)){	case Cd:		outss(cmdport+Data, drive->pktcmd, drive->pkt/2);		break;	case 0:		len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo);		if(drive->data+len > drive->limit){			atanop(drive, 0);			break;		}		outss(cmdport+Data, drive->data, len/2);		drive->data += len;		break;	case Io:		len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo);		if(drive->data+len > drive->limit){			atanop(drive, 0);			break;		}		inss(cmdport+Data, drive->data, len/2);		drive->data += len;		break;	case Io|Cd:ctlr->done=1;		break;	}}static intatapktio(Drive* drive, uchar* cmd, int clen){	Ctlr *ctlr;	int as, cmdport, ctlport, len, r;	if(cmd[0] == 0x5A && (cmd[2] & 0x3F) == 0)		return atamodesense(drive, cmd);	r = SDok;	drive->command = Cpkt;	memmove(drive->pktcmd, cmd, clen);	memset(drive->pktcmd+clen, 0, drive->pkt-clen);	drive->limit = drive->data+drive->dlen;	ctlr = drive->ctlr;	cmdport = ctlr->cmdport;	ctlport = ctlr->ctlport;	qlock(ctlr);	if(ataready(cmdport, ctlport, drive->dev, Bsy|Drq, 0, 100*1000) < 0)		return -1;	ilock(ctlr);drive->pktdma = 0;	outb(cmdport+Features, drive->pktdma);	outb(cmdport+Count, 0);	outb(cmdport+Sector, 0);	len = 16*drive->secsize;	outb(cmdport+Bytelo, len);	outb(cmdport+Bytehi, len>>8);	outb(cmdport+Dh, drive->dev);	ctlr->done = 0;	outb(cmdport+Command, Cpkt);	if((drive->info[Iconfig] & 0x0060) != 0x0020){		as = ataready(cmdport, ctlport,			drive->dev, Bsy, Drq|Chk, 4*1000);		if(as < 0)			r = SDtimeout;		else if(as & Chk)			r = SDcheck;		else			atapktinterrupt(drive);	}	ctlr->curdrive = drive;	iunlock(ctlr);	tsleep(ctlr, atapktiodone, ctlr, 10*1000);	if(!ctlr->done)		panic("atapktiodone");	qunlock(ctlr);	if(drive->status & Chk)		r = SDcheck;	return r;}static intatageniodone(void* arg){	return ((Ctlr*)arg)->done;}static intatageniostart(Drive* drive, int lba){	Ctlr *ctlr;	int as, c, cmdport, ctlport, h, len, s;	if(drive->dev & Lba){		c = (lba>>8) & 0xFFFF;		h = (lba>>24) & 0x0F;		s = lba & 0xFF;	}	else{		c = lba/(drive->s*drive->h);		h = ((lba/drive->s) % drive->h);		s = (lba % drive->s) + 1;	}	ctlr = drive->ctlr;	cmdport = ctlr->cmdport;	ctlport = ctlr->ctlport;	if(ataready(cmdport, ctlport, drive->dev, Bsy|Drq, 0, 100*1000) < 0)		return -1;	ilock(ctlr);	if(drive->write)		drive->command = drive->piow;	else		drive->command = drive->pior;	outb(cmdport+Count, drive->count);	outb(cmdport+Sector, s);	outb(cmdport+Dh, drive->dev|h);	outb(cmdport+Cyllo, c);	outb(cmdport+Cylhi, c>>8);	ctlr->done = 0;	outb(cmdport+Command, drive->command);	microdelay(1);	switch(drive->command){	case Cws:	case Cwsm:		as = ataready(cmdport, ctlport, drive->dev, Bsy, Drq|Err, 1000);		if(as < 0 || (as & Err)){			iunlock(ctlr);			return -1;		}		len = drive->block;		if(drive->data+len > drive->limit)			len = drive->limit-drive->data;		outss(cmdport+Data, drive->data, len/2);		break;	case Crd:	case Cwd:panic("atadmastart");		break;	}	ctlr->curdrive = drive;	iunlock(ctlr);	return 0;}static intatagenio(Drive* drive, uchar* cmd, int){	uchar *p;	Ctlr *ctlr;	int count, lba, len;	/*	 * Map SCSI commands into ATA commands for discs.	 * Fail any command with a LUN except INQUIRY which	 * will return 'logical unit not supported'.	 */	if((cmd[1]>>5) && cmd[0] != 0x12)		return atasetsense(drive, SDcheck, 0x05, 0x25, 0);	switch(cmd[0]){	default:		return atasetsense(drive, SDcheck, 0x05, 0x20, 0);	case 0x00:			/* test unit ready */		return SDok;	case 0x03:			/* request sense */		if(cmd[4] < sizeof(drive->sense))			len = cmd[4];		else			len = sizeof(drive->sense);		if(drive->data && drive->dlen >= len){			memmove(drive->data, drive->sense, len);			drive->data += len;

⌨️ 快捷键说明

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