pdc4030.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 794 行 · 第 1/2 页

C
794
字号
					NULL);#ifdef DEBUG_READ			printk(KERN_DEBUG "%s: promise_read: waiting for"			       "interrupt\n", drive->name);#endif /* DEBUG_READ */			return ide_started;		}		printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left "		       "!DRQ !BUSY\n", drive->name);		return DRIVER(drive)->error(drive,				"promise read intr", status.all);	}	return ide_stopped;}/* * promise_complete_pollfunc() * This is the polling function for waiting (nicely!) until drive stops * being busy. It is invoked at the end of a write, after the previous poll * has finished. * * Once not busy, the end request is called. */static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive){	ide_hwgroup_t *hwgroup = HWGROUP(drive);#ifdef CONFIG_IDE_TASKFILE_IO	struct request *rq = hwgroup->rq;#else	struct request *rq = &hwgroup->wrq;	struct bio *bio = rq->bio;#endif	if ((HWIF(drive)->INB(IDE_STATUS_REG)) & BUSY_STAT) {		if (time_before(jiffies, hwgroup->poll_timeout)) {			if (hwgroup->handler != NULL)				BUG();			ide_set_handler(drive,					&promise_complete_pollfunc,					HZ/100,					NULL);			return ide_started; /* continue polling... */		}		hwgroup->poll_timeout = 0;		printk(KERN_ERR "%s: completion timeout - still busy!\n",		       drive->name);		return DRIVER(drive)->error(drive, "busy timeout",				HWIF(drive)->INB(IDE_STATUS_REG));	}	hwgroup->poll_timeout = 0;#ifdef DEBUG_WRITE	printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);#endif /* DEBUG_WRITE */#ifdef CONFIG_IDE_TASKFILE_IO	/* Complete previously submitted bios. */	while (rq->bio != rq->cbio)		(void) DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio));#else	bio->bi_idx = bio->bi_vcnt - rq->nr_cbio_segments;	rq = hwgroup->rq;	DRIVER(drive)->end_request(drive, 1, rq->hard_nr_sectors);#endif	return ide_stopped;}/* * promise_multwrite() transfers a block of up to mcount sectors of data * to a drive as part of a disk multiple-sector write operation. */#ifdef CONFIG_IDE_TASKFILE_IOstatic void promise_multwrite (ide_drive_t *drive, unsigned int msect){	struct request* rq = HWGROUP(drive)->rq;	unsigned int nsect;	rq->errors = 0;	do {		nsect = rq->current_nr_sectors;		if (nsect > msect)			nsect = msect;		task_bio_sectors(drive, rq, nsect, IDE_PIO_OUT);		if (!rq->nr_sectors)			msect = 0;		else			msect -= nsect;	} while (msect);}#else /* CONFIG_IDE_TASKFILE_IO */static void promise_multwrite (ide_drive_t *drive, unsigned int mcount){	ide_hwgroup_t *hwgroup	= HWGROUP(drive);	struct request *rq	= &hwgroup->wrq;	do {		char *buffer;		int nsect = rq->current_nr_sectors;		if (nsect > mcount)			nsect = mcount;		mcount -= nsect;		buffer = rq->buffer;		rq->sector += nsect;		rq->buffer += nsect << 9;		rq->nr_sectors -= nsect;		rq->current_nr_sectors -= nsect;		/* Do we move to the next bh after this? */		if (!rq->current_nr_sectors) {			struct bio *bio = rq->bio;			/*			 * only move to next bio, when we have processed			 * all bvecs in this one.			 */			if (++bio->bi_idx >= bio->bi_vcnt) {				bio->bi_idx = bio->bi_vcnt - rq->nr_cbio_segments;				bio = bio->bi_next;			}			/* end early early we ran out of requests */			if (!bio) {				mcount = 0;			} else {				rq->bio = bio;				rq->nr_cbio_segments = bio_segments(bio);				rq->current_nr_sectors = bio_cur_sectors(bio);				rq->hard_cur_sectors = rq->current_nr_sectors;			}		}		/*		 * Ok, we're all setup for the interrupt		 * re-entering us on the last transfer.		 */		taskfile_output_data(drive, buffer, nsect<<7);	} while (mcount);}#endif/* * promise_write_pollfunc() is the handler for disk write completion polling. */static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive){	ide_hwgroup_t *hwgroup = HWGROUP(drive);#ifdef CONFIG_IDE_TASKFILE_IO	struct request *rq = hwgroup->rq;#else	struct request *rq = &hwgroup->wrq;	struct bio *bio = rq->bio;#endif	if (HWIF(drive)->INB(IDE_NSECTOR_REG) != 0) {		if (time_before(jiffies, hwgroup->poll_timeout)) {			if (hwgroup->handler != NULL)				BUG();			ide_set_handler(drive,					&promise_write_pollfunc,					HZ/100,					NULL);			return ide_started; /* continue polling... */		}		hwgroup->poll_timeout = 0;		printk(KERN_ERR "%s: write timed-out!\n",drive->name);#ifndef CONFIG_IDE_TASKFILE_IO		bio->bi_idx = bio->bi_vcnt - rq->nr_cbio_segments;#endif		return DRIVER(drive)->error(drive, "write timeout",				HWIF(drive)->INB(IDE_STATUS_REG));	}#ifdef CONFIG_IDE_TASKFILE_IO	/* Complete previously submitted bios. */	while (rq->bio != rq->cbio)		(void) DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio));#endif	/*	 * Now write out last 4 sectors and poll for not BUSY	 */	promise_multwrite(drive, 4);	hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;	if (hwgroup->handler != NULL)		BUG();	ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);#ifdef DEBUG_WRITE	printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n",		drive->name, HWIF(drive)->INB(IDE_STATUS_REG));#endif /* DEBUG_WRITE */	return ide_started;}/* * promise_write() transfers a block of one or more sectors of data to a * drive as part of a disk write operation. All but 4 sectors are transferred * in the first attempt, then the interface is polled (nicely!) for completion * before the final 4 sectors are transferred. There is no interrupt generated * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY. */static ide_startstop_t promise_write (ide_drive_t *drive){	ide_hwgroup_t *hwgroup = HWGROUP(drive);#ifdef CONFIG_IDE_TASKFILE_IO	struct request *rq = hwgroup->rq;#else	struct request *rq = &hwgroup->wrq;#endif#ifdef DEBUG_WRITE	printk(KERN_DEBUG "%s: %s: sectors(%lu-%lu)\n",			  drive->name, __FUNCTION__,			  (unsigned long)rq->sector,			  (unsigned long)rq->sector + rq->nr_sectors - 1);#endif /* DEBUG_WRITE */	/*	 * If there are more than 4 sectors to transfer, do n-4 then go into	 * the polling strategy as defined above.	 */	if (rq->nr_sectors > 4) {		promise_multwrite(drive, rq->nr_sectors - 4);		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;		if (hwgroup->handler != NULL)	/* paranoia check */			BUG();		ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL);		return ide_started;	} else {	/*	 * There are 4 or fewer sectors to transfer, do them all in one go	 * and wait for NOT BUSY.	 */		promise_multwrite(drive, rq->nr_sectors);		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;		if (hwgroup->handler != NULL)			BUG();		ide_set_handler(drive,				&promise_complete_pollfunc,				HZ/100,				NULL);#ifdef DEBUG_WRITE		printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, "			"status = %02x\n", drive->name,			HWIF(drive)->INB(IDE_STATUS_REG));#endif /* DEBUG_WRITE */		return ide_started;	}}/* * do_pdc4030_io() is called from promise_rw_disk, having had the block number * already set up. It issues a READ or WRITE command to the Promise * controller, assuming LBA has been used to set up the block number. */#ifndef CONFIG_IDE_TASKFILE_IOide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq){	ide_startstop_t startstop;	unsigned long timeout;	u8 stat = 0;#elsestatic ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task){	struct request *rq	= HWGROUP(drive)->rq;	task_struct_t *taskfile = (task_struct_t *) task->tfRegister;	ide_startstop_t startstop;	unsigned long timeout;	u8 stat = 0;	if (IDE_CONTROL_REG)		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);	/* clear nIEN */	SELECT_MASK(drive, 0);	HWIF(drive)->OUTB(taskfile->feature, IDE_FEATURE_REG);	HWIF(drive)->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);	/* refers to number of sectors to transfer */	HWIF(drive)->OUTB(taskfile->sector_number, IDE_SECTOR_REG);	/* refers to sector offset or start sector */	HWIF(drive)->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);	HWIF(drive)->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);	HWIF(drive)->OUTB(taskfile->device_head, IDE_SELECT_REG);	HWIF(drive)->OUTB(taskfile->command, IDE_COMMAND_REG);#endif	if (rq_data_dir(rq) == READ) {#ifndef CONFIG_IDE_TASKFILE_IO		HWIF(drive)->OUTB(PROMISE_READ, IDE_COMMAND_REG);#endif/* * The card's behaviour is odd at this point. If the data is * available, DRQ will be true, and no interrupt will be * generated by the card. If this is the case, we need to call the  * "interrupt" handler (promise_read_intr) directly. Otherwise, if * an interrupt is going to occur, bit0 of the SELECT register will * be high, so we can set the handler the just return and be interrupted. * If neither of these is the case, we wait for up to 50ms (badly I'm * afraid!) until one of them is. */		timeout = jiffies + HZ/20; /* 50ms wait */		do {			stat = HWIF(drive)->INB(IDE_STATUS_REG);			if (stat & DRQ_STAT) {				udelay(1);				return promise_read_intr(drive);			}			if (HWIF(drive)->INB(IDE_SELECT_REG) & 0x01) {#ifdef DEBUG_READ				printk(KERN_DEBUG "%s: read: waiting for "						"interrupt\n", drive->name);#endif /* DEBUG_READ */				ide_set_handler(drive,						&promise_read_intr,						WAIT_CMD,						NULL);				return ide_started;			}			udelay(1);		} while (time_before(jiffies, timeout));		printk(KERN_ERR "%s: reading: No DRQ and not "				"waiting - Odd!\n", drive->name);		return ide_stopped;	} else {#ifndef CONFIG_IDE_TASKFILE_IO		HWIF(drive)->OUTB(PROMISE_WRITE, IDE_COMMAND_REG);#endif		if (ide_wait_stat(&startstop, drive, DATA_READY,				drive->bad_wstat, WAIT_DRQ)) {			printk(KERN_ERR "%s: no DRQ after issuing "				"PROMISE_WRITE\n", drive->name);			return startstop;	    	}		if (!drive->unmask)			local_irq_disable();#ifndef CONFIG_IDE_TASKFILE_IO		HWGROUP(drive)->wrq = *rq; /* scratchpad */#endif		return promise_write(drive);	}}static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block){	/* The four drives on the two logical (one physical) interfaces	   are distinguished by writing the drive number (0-3) to the	   Feature register.	   FIXME: Is promise_selectproc now redundant??	*/	ide_hwif_t *hwif = HWIF(drive);	int drive_number = (hwif->channel << 1) + drive->select.b.unit;#ifdef CONFIG_IDE_TASKFILE_IO	struct hd_drive_task_hdr taskfile;	ide_task_t args;#endif	BUG_ON(rq->nr_sectors > 127);#ifndef CONFIG_IDE_TASKFILE_IO	if (IDE_CONTROL_REG)		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);	hwif->OUTB(drive_number, IDE_FEATURE_REG);	hwif->OUTB(rq->nr_sectors, IDE_NSECTOR_REG);	hwif->OUTB(block,IDE_SECTOR_REG);	hwif->OUTB(block>>=8,IDE_LCYL_REG);	hwif->OUTB(block>>=8,IDE_HCYL_REG);	hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);	return do_pdc4030_io(drive, rq);#else /* !CONFIG_IDE_TASKFILE_IO */	memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));	taskfile.feature	= drive_number;	taskfile.sector_count	= rq->nr_sectors;	taskfile.sector_number	= block;	taskfile.low_cylinder	= (block>>=8);	taskfile.high_cylinder	= (block>>=8);	taskfile.device_head	= ((block>>8)&0x0f)|drive->select.all;	taskfile.command	= (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE;	memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr));	memset(args.hobRegister, 0, sizeof(struct hd_drive_hob_hdr));	/*	 * Setup the bits of args that we do need.	 * Note that we don't use the generic interrupt handlers.	 */	args.handler		= NULL;	args.rq			= (struct request *) rq;	rq->special		= (ide_task_t *)&args;	return do_pdc4030_io(drive, &args);#endif /* !CONFIG_IDE_TASKFILE_IO */}

⌨️ 快捷键说明

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