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

📄 ide.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (nsect > mcount)			nsect = mcount;		mcount -= nsect;		ide_output_data(drive, rq->buffer, nsect<<7);#ifdef DEBUG		printk("%s: multwrite: sector %ld, buffer=0x%08lx, count=%d, remaining=%ld\n",			drive->name, rq->sector, (unsigned long) rq->buffer,			nsect, rq->nr_sectors - nsect);#endif		if ((rq->nr_sectors -= nsect) <= 0)			break;		if ((rq->current_nr_sectors -= nsect) == 0) {			if ((rq->bh = rq->bh->b_reqnext) != NULL) {				rq->current_nr_sectors = rq->bh->b_size>>9;				rq->buffer             = rq->bh->b_data;			} else {				panic("%s: buffer list corrupted\n", drive->name);				break;			}		} else {			rq->buffer += nsect << 9;		}	} while (mcount);}/* * multwrite_intr() is the handler for disk multwrite interrupts */static void multwrite_intr (ide_drive_t *drive){	byte stat;	int i;	ide_hwgroup_t *hwgroup = HWGROUP(drive);	struct request *rq = &hwgroup->wrq;	if (OK_STAT(stat=GET_STAT(),DRIVE_READY,drive->bad_wstat)) {		if (stat & DRQ_STAT) {			if (rq->nr_sectors) {				ide_multwrite(drive, drive->mult_count);				ide_set_handler (drive, &multwrite_intr, WAIT_CMD);				return;			}		} else {			if (!rq->nr_sectors) {	/* all done? */				rq = hwgroup->rq;				for (i = rq->nr_sectors; i > 0;){					i -= rq->current_nr_sectors;					ide_end_request(1, hwgroup);				}				return;			}		}	}	ide_error(drive, "multwrite_intr", stat);}/* * Issue a simple drive command * The drive must be selected beforehand. */static void ide_cmd(ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler){	ide_set_handler (drive, handler, WAIT_CMD);	OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	OUT_BYTE(nsect,IDE_NSECTOR_REG);	OUT_BYTE(cmd,IDE_COMMAND_REG);}/* * set_multmode_intr() is invoked on completion of a WIN_SETMULT cmd. */static void set_multmode_intr (ide_drive_t *drive){	byte stat = GET_STAT();	sti();	if (OK_STAT(stat,READY_STAT,BAD_STAT)) {		drive->mult_count = drive->mult_req;	} else {		drive->mult_req = drive->mult_count = 0;		drive->special.b.recalibrate = 1;		(void) ide_dump_status(drive, "set_multmode", stat);	}}/* * set_geometry_intr() is invoked on completion of a WIN_SPECIFY cmd. */static void set_geometry_intr (ide_drive_t *drive){	byte stat = GET_STAT();	sti();	if (!OK_STAT(stat,READY_STAT,BAD_STAT))		ide_error(drive, "set_geometry_intr", stat);}/* * recal_intr() is invoked on completion of a WIN_RESTORE (recalibrate) cmd. */static void recal_intr (ide_drive_t *drive){	byte stat = GET_STAT();	sti();	if (!OK_STAT(stat,READY_STAT,BAD_STAT))		ide_error(drive, "recal_intr", stat);}/* * mc_intr() is invoked on completion of a WIN_ACKMC cmd. */static void mc_intr (ide_drive_t *drive){	byte stat = GET_STAT();	sti();	if (!OK_STAT(stat,READY_STAT,BAD_STAT))		ide_error(drive, "mc_intr", stat);	drive->special.b.mc = 0;}/* * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. */static void drive_cmd_intr (ide_drive_t *drive){	struct request *rq = HWGROUP(drive)->rq;	byte *args = (byte *) rq->buffer;	byte stat = GET_STAT();	sti();	if ((stat & DRQ_STAT) && args && args[3]) {		byte io_32bit = drive->io_32bit;		drive->io_32bit = 0;		ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS);		drive->io_32bit = io_32bit;		stat = GET_STAT();	}	if (OK_STAT(stat,READY_STAT,BAD_STAT))		ide_end_drive_cmd (drive, stat, GET_ERR());	else		ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */}/* * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT * commands to a drive.  It used to do much more, but has been scaled back. */static inline void do_special (ide_drive_t *drive){	special_t *s = &drive->special;#ifdef DEBUG	printk("%s: do_special: 0x%02x\n", drive->name, s->all);#endif	if (s->b.set_geometry) {		s->b.set_geometry = 0;		if (drive->media == ide_disk && !drive->no_geom) {			OUT_BYTE(drive->sect,IDE_SECTOR_REG);			OUT_BYTE(drive->cyl,IDE_LCYL_REG);			OUT_BYTE(drive->cyl>>8,IDE_HCYL_REG);			OUT_BYTE(((drive->head-1)|drive->select.all)&0xBF,IDE_SELECT_REG);			if (!IS_PROMISE_DRIVE)				ide_cmd(drive, WIN_SPECIFY, drive->sect, &set_geometry_intr);		}	} else if (s->b.recalibrate) {		s->b.recalibrate = 0;		if (drive->media == ide_disk && !IS_PROMISE_DRIVE)			ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr);	} else if (s->b.set_tune) {		ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc;		s->b.set_tune = 0;		if (tuneproc != NULL)			tuneproc(drive, drive->tune_req);	} else if (s->b.set_multmode) {		s->b.set_multmode = 0;		if (drive->media == ide_disk) {			if (drive->id && drive->mult_req > drive->id->max_multsect)				drive->mult_req = drive->id->max_multsect;			if (!IS_PROMISE_DRIVE)				ide_cmd(drive, WIN_SETMULT, drive->mult_req, &set_multmode_intr);		} else			drive->mult_req = 0;	} else if (s->b.mc) {		s->b.mc = 0;		if (drive->media == ide_disk && !IS_PROMISE_DRIVE)			ide_cmd(drive, WIN_ACKMC, drive->sect, &mc_intr);	} else if (s->all) {		int special = s->all;		s->all = 0;		printk("%s: bad special flag: 0x%02x\n", drive->name, special);	}}/* * This routine busy-waits for the drive status to be not "busy". * It then checks the status for all of the "good" bits and none * of the "bad" bits, and if all is okay it returns 0.  All other * cases return 1 after invoking ide_error() -- caller should just return. * * This routine should get fixed to not hog the cpu during extra long waits.. * That could be done by busy-waiting for the first jiffy or two, and then * setting a timer to wake up at half second intervals thereafter, * until timeout is achieved, before timing out. */int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout){	byte stat;	unsigned long flags;	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */	if ((stat = GET_STAT()) & BUSY_STAT) {		save_flags(flags);		sti();		timeout += jiffies;		while ((stat = GET_STAT()) & BUSY_STAT) {			if (jiffies > timeout) {				restore_flags(flags);				ide_error(drive, "status timeout", stat);				return 1;			}		}		restore_flags(flags);	}	udelay(1);	/* allow status to settle, then read it again */	if (OK_STAT((stat = GET_STAT()), good, bad))		return 0;	ide_error(drive, "status error", stat);	return 1;}/* * do_rw_disk() issues READ and WRITE commands to a disk, * using LBA if supported, or CHS otherwise, to address sectors. * It also takes care of issuing special DRIVE_CMDs. */static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block){	ide_hwif_t *hwif = HWIF(drive);	unsigned short io_base = hwif->io_base;#ifdef CONFIG_BLK_DEV_PROMISE	int use_promise_io = 0;#endif /* CONFIG_BLK_DEV_PROMISE */	OUT_BYTE(drive->ctl,IDE_CONTROL_REG);	OUT_BYTE(rq->nr_sectors,io_base+IDE_NSECTOR_OFFSET);#ifdef CONFIG_BLK_DEV_PROMISE	if (IS_PROMISE_DRIVE) {		if (hwif->is_promise2 || rq->cmd == READ) {			use_promise_io = 1;		}	}	if (drive->select.b.lba || use_promise_io) {#else /* !CONFIG_BLK_DEV_PROMISE */	if (drive->select.b.lba) {#endif /* CONFIG_BLK_DEV_PROMISE */#ifdef DEBUG		printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",			drive->name, (rq->cmd==READ)?"read":"writ",			block, rq->nr_sectors, (unsigned long) rq->buffer);#endif		OUT_BYTE(block,io_base+IDE_SECTOR_OFFSET);		OUT_BYTE(block>>=8,io_base+IDE_LCYL_OFFSET);		OUT_BYTE(block>>=8,io_base+IDE_HCYL_OFFSET);		OUT_BYTE(((block>>8)&0x0f)|drive->select.all,io_base+IDE_SELECT_OFFSET);	} else {		unsigned int sect,head,cyl,track;		track = block / drive->sect;		sect  = block % drive->sect + 1;		OUT_BYTE(sect,io_base+IDE_SECTOR_OFFSET);		head  = track % drive->head;		cyl   = track / drive->head;		OUT_BYTE(cyl,io_base+IDE_LCYL_OFFSET);		OUT_BYTE(cyl>>8,io_base+IDE_HCYL_OFFSET);		OUT_BYTE(head|drive->select.all,io_base+IDE_SELECT_OFFSET);#ifdef DEBUG		printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",			drive->name, (rq->cmd==READ)?"read":"writ", cyl,			head, sect, rq->nr_sectors, (unsigned long) rq->buffer);#endif	}#ifdef CONFIG_BLK_DEV_PROMISE	if (use_promise_io) {		do_promise_io (drive, rq);		return;	}#endif /* CONFIG_BLK_DEV_PROMISE */	if (rq->cmd == READ) {#ifdef CONFIG_BLK_DEV_TRITON		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_read, drive)))			return;#endif /* CONFIG_BLK_DEV_TRITON */		ide_set_handler(drive, &read_intr, WAIT_CMD);		OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, io_base+IDE_COMMAND_OFFSET);		return;	}	if (rq->cmd == WRITE) {#ifdef CONFIG_BLK_DEV_TRITON		if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))			return;#endif /* CONFIG_BLK_DEV_TRITON */		OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, io_base+IDE_COMMAND_OFFSET);		if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {			printk("%s: no DRQ after issuing %s\n", drive->name,				drive->mult_count ? "MULTWRITE" : "WRITE");			return;		}		if (!drive->unmask)			cli();		if (drive->mult_count) {			HWGROUP(drive)->wrq = *rq; /* scratchpad */			ide_set_handler (drive, &multwrite_intr, WAIT_CMD);			ide_multwrite(drive, drive->mult_count);		} else {			ide_set_handler (drive, &write_intr, WAIT_CMD);			ide_output_data(drive, rq->buffer, SECTOR_WORDS);		}		return;	}	printk("%s: bad command: %d\n", drive->name, rq->cmd);	ide_end_request(0, HWGROUP(drive));}/* * execute_drive_cmd() issues a special drive command, * usually initiated by ioctl() from the external hdparm program. */static void execute_drive_cmd (ide_drive_t *drive, struct request *rq){	byte *args = rq->buffer;	if (args) {#ifdef DEBUG		printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n",		 drive->name, args[0], args[1], args[2], args[3]);#endif		OUT_BYTE(args[2],IDE_FEATURE_REG);		ide_cmd(drive, args[0], args[1], &drive_cmd_intr);		return;	} else {		/*		 * NULL is actually a valid way of waiting for		 * all current requests to be flushed from the queue.		 */#ifdef DEBUG		printk("%s: DRIVE_CMD (null)\n", drive->name);#endif		ide_end_drive_cmd(drive, GET_STAT(), GET_ERR());		return;	}}/* * do_request() initiates handling of a new I/O request */static inline void do_request (ide_hwif_t *hwif, struct request *rq){	unsigned int minor, unit;	unsigned long block, blockend;	ide_drive_t *drive;	sti();#ifdef DEBUG	printk("%s: do_request: current=0x%08lx\n", hwif->name, (unsigned long) rq);#endif	minor = MINOR(rq->rq_dev);	unit = minor >> PARTN_BITS;	if (MAJOR(rq->rq_dev) != hwif->major || unit >= MAX_DRIVES) {		printk("%s: bad device number: %s\n",		       hwif->name, kdevname(rq->rq_dev));		goto kill_rq;	}	drive = &hwif->drives[unit];#ifdef DEBUG	if (rq->bh && !buffer_locked(rq->bh)) {		printk("%s: block not locked\n", drive->name);		goto kill_rq;	}#endif	block    = rq->sector;	blockend = block + rq->nr_sectors;	if ((blockend < block) || (blockend > drive->part[minor&PARTN_MASK].nr_sects)) {#ifdef MACH	  printk ("%s%c: bad access: block=%ld, count=%ld, blockend=%ld, nr_sects%ld\n",		  drive->name, (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ',		  block, rq->nr_sectors, blockend, drive->part[minor&PARTN_MASK].nr_sects);#else		printk("%s%c: bad access: block=%ld, count=%ld\n", drive->name,		 (minor&PARTN_MASK)?'0'+(minor&PARTN_MASK):' ', block, rq->nr_sectors);#endif		goto kill_rq;	}	block += drive->part[minor&PARTN_MASK].start_sect + drive->sect0;#if FAKE_FDISK_FOR_EZDRIVE	if (block == 0 && drive->remap_0_to_1)		block = 1;  /* redirect MBR access to EZ-Drive partn table */#endif /* FAKE_FDISK_FOR_EZDRIVE */

⌨️ 快捷键说明

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