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

📄 ide-cd.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		rq->buffer += SECTOR_SIZE;		--rq->current_nr_sectors;		--rq->nr_sectors;		++rq->sector;	}	/* If we've satisfied the current request,	   terminate it successfully. */	if (rq->nr_sectors == 0) {		cdrom_end_request(drive, 1);		return -1;	}	/* Move on to the next buffer if needed. */	if (rq->current_nr_sectors == 0)		cdrom_end_request(drive, 1);	/* If this condition does not hold, then the kluge i use to	   represent the number of sectors to skip at the start of a transfer	   will fail.  I think that this will never happen, but let's be	   paranoid and check. */	if (rq->current_nr_sectors < bio_cur_sectors(rq->bio) &&	    (rq->sector & (sectors_per_frame - 1))) {		printk(KERN_ERR "%s: cdrom_read_from_buffer: buffer botch (%ld)\n",			drive->name, (long)rq->sector);		cdrom_end_request(drive, 0);		return -1;	}	return 0;}/* * Routine to send a read packet command to the drive. * This is usually called directly from cdrom_start_read. * However, for drq_interrupt devices, it is called from an interrupt * when the drive is ready to accept the command. */static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive){	struct request *rq = HWGROUP(drive)->rq;	unsigned short sectors_per_frame;	int nskip;	sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;	/* If the requested sector doesn't start on a cdrom block boundary,	   we must adjust the start of the transfer so that it does,	   and remember to skip the first few sectors.	   If the CURRENT_NR_SECTORS field is larger than the size	   of the buffer, it will mean that we're to skip a number	   of sectors equal to the amount by which CURRENT_NR_SECTORS	   is larger than the buffer size. */	nskip = rq->sector & (sectors_per_frame - 1);	if (nskip > 0) {		/* Sanity check... */		if (rq->current_nr_sectors != bio_cur_sectors(rq->bio) &&			(rq->sector & (sectors_per_frame - 1))) {			printk(KERN_ERR "%s: cdrom_start_read_continuation: buffer botch (%u)\n",				drive->name, rq->current_nr_sectors);			cdrom_end_request(drive, 0);			return ide_stopped;		}		rq->current_nr_sectors += nskip;	}	/* Set up the command */	rq->timeout = ATAPI_WAIT_PC;	/* Send the command to the drive and return. */	return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr);}#define IDECD_SEEK_THRESHOLD	(1000)			/* 1000 blocks */#define IDECD_SEEK_TIMER	(5 * WAIT_MIN_SLEEP)	/* 100 ms */#define IDECD_SEEK_TIMEOUT	(2 * WAIT_CMD)		/* 20 sec */static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive){	struct cdrom_info *info = drive->driver_data;	int stat;	static int retry = 10;	if (cdrom_decode_status(drive, 0, &stat))		return ide_stopped;	CDROM_CONFIG_FLAGS(drive)->seeking = 1;	if (retry && time_after(jiffies, info->start_seek + IDECD_SEEK_TIMER)) {		if (--retry == 0) {			/*			 * this condition is far too common, to bother			 * users about it			 */			/* printk("%s: disabled DSC seek overlap\n", drive->name);*/ 			drive->dsc_overlap = 0;		}	}	return ide_stopped;}static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive){	struct request *rq = HWGROUP(drive)->rq;	sector_t frame = rq->sector;	sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);	memset(rq->cmd, 0, sizeof(rq->cmd));	rq->cmd[0] = GPCMD_SEEK;	put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]);	rq->timeout = ATAPI_WAIT_PC;	return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr);}static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block){	struct cdrom_info *info = drive->driver_data;	info->dma = 0;	info->start_seek = jiffies;	return cdrom_start_packet_command(drive, 0, cdrom_start_seek_continuation);}/* Fix up a possibly partially-processed request so that we can   start it over entirely, or even put it back on the request queue. */static void restore_request (struct request *rq){	if (rq->buffer != bio_data(rq->bio)) {		sector_t n = (rq->buffer - (char *) bio_data(rq->bio)) / SECTOR_SIZE;		rq->buffer = bio_data(rq->bio);		rq->nr_sectors += n;		rq->sector -= n;	}	rq->hard_cur_sectors = rq->current_nr_sectors = bio_cur_sectors(rq->bio);	rq->hard_nr_sectors = rq->nr_sectors;	rq->hard_sector = rq->sector;	rq->q->prep_rq_fn(rq->q, rq);}/* * Start a read request from the CD-ROM. */static ide_startstop_t cdrom_start_read (ide_drive_t *drive, unsigned int block){	struct cdrom_info *info = drive->driver_data;	struct request *rq = HWGROUP(drive)->rq;	unsigned short sectors_per_frame;	sectors_per_frame = queue_hardsect_size(drive->queue) >> SECTOR_BITS;	/* We may be retrying this request after an error.  Fix up	   any weirdness which might be present in the request packet. */	restore_request(rq);	/* Satisfy whatever we can of this request from our cached sector. */	if (cdrom_read_from_buffer(drive))		return ide_stopped;	/* Clear the local sector buffer. */	info->nsectors_buffered = 0;	/* use dma, if possible. */	info->dma = drive->using_dma;	if ((rq->sector & (sectors_per_frame - 1)) ||	    (rq->nr_sectors & (sectors_per_frame - 1)))		info->dma = 0;	/* Start sending the read request to the drive. */	return cdrom_start_packet_command(drive, 32768, cdrom_start_read_continuation);}/**************************************************************************** * Execute all other packet commands. *//* Interrupt routine for packet command completion. */static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive){	int ireason, len, thislen;	struct request *rq = HWGROUP(drive)->rq;	u8 lowcyl = 0, highcyl = 0;	int stat;	/* Check for errors. */	if (cdrom_decode_status(drive, 0, &stat))		return ide_stopped;	/* Read the interrupt reason and the transfer length. */	ireason = HWIF(drive)->INB(IDE_IREASON_REG) & 0x3;	lowcyl  = HWIF(drive)->INB(IDE_BCOUNTL_REG);	highcyl = HWIF(drive)->INB(IDE_BCOUNTH_REG);	len = lowcyl + (256 * highcyl);	/* If DRQ is clear, the command has completed.	   Complain if we still have data left to transfer. */	if ((stat & DRQ_STAT) == 0) {		/* Some of the trailing request sense fields are optional, and		   some drives don't send them.  Sigh. */		if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&		    rq->data_len > 0 &&		    rq->data_len <= 5) {			while (rq->data_len > 0) {				*(unsigned char *)rq->data++ = 0;				--rq->data_len;			}		}		if (rq->data_len == 0)			cdrom_end_request(drive, 1);		else {			/* Comment this out, because this always happens 			   right after a reset occurs, and it is annoying to 			   always print expected stuff.  */			/*			printk ("%s: cdrom_pc_intr: data underrun %d\n",				drive->name, pc->buflen);			*/			rq->cmd_flags |= REQ_FAILED;			cdrom_end_request(drive, 0);		}		return ide_stopped;	}	/* Figure out how much data to transfer. */	thislen = rq->data_len;	if (thislen > len) thislen = len;	/* The drive wants to be written to. */	if (ireason == 0) {		if (!rq->data) {			blk_dump_rq_flags(rq, "cdrom_pc_intr, write");			goto confused;		}		/* Transfer the data. */		HWIF(drive)->atapi_output_bytes(drive, rq->data, thislen);		/* If we haven't moved enough data to satisfy the drive,		   add some padding. */		while (len > thislen) {			int dum = 0;			HWIF(drive)->atapi_output_bytes(drive, &dum, sizeof(dum));			len -= sizeof(dum);		}		/* Keep count of how much data we've moved. */		rq->data += thislen;		rq->data_len -= thislen;	}	/* Same drill for reading. */	else if (ireason == 2) {		if (!rq->data) {			blk_dump_rq_flags(rq, "cdrom_pc_intr, read");			goto confused;		}		/* Transfer the data. */		HWIF(drive)->atapi_input_bytes(drive, rq->data, thislen);		/* If we haven't moved enough data to satisfy the drive,		   add some padding. */		while (len > thislen) {			int dum = 0;			HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));			len -= sizeof(dum);		}		/* Keep count of how much data we've moved. */		rq->data += thislen;		rq->data_len -= thislen;		if (blk_sense_request(rq))			rq->sense_len += thislen;	} else {confused:		printk (KERN_ERR "%s: cdrom_pc_intr: The drive "			"appears confused (ireason = 0x%02x). "			"Trying to recover by ending request.\n",			drive->name, ireason);		rq->cmd_flags |= REQ_FAILED;		cdrom_end_request(drive, 0);		return ide_stopped;	}	/* Now we wait for another interrupt. */	ide_set_handler(drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry);	return ide_started;}static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive){	struct request *rq = HWGROUP(drive)->rq;	if (!rq->timeout)		rq->timeout = ATAPI_WAIT_PC;	/* Send the command to the drive and return. */	return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr);}static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive){	int len;	struct request *rq = HWGROUP(drive)->rq;	struct cdrom_info *info = drive->driver_data;	info->dma = 0;	rq->cmd_flags &= ~REQ_FAILED;	len = rq->data_len;	/* Start sending the command to the drive. */	return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);}static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq){	struct request_sense sense;	int retries = 10;	unsigned int flags = rq->cmd_flags;	if (rq->sense == NULL)		rq->sense = &sense;	/* Start of retry loop. */	do {		int error;		unsigned long time = jiffies;		rq->cmd_flags = flags;		error = ide_do_drive_cmd(drive, rq, ide_wait);		time = jiffies - time;		/* FIXME: we should probably abort/retry or something 		 * in case of failure */		if (rq->cmd_flags & REQ_FAILED) {			/* The request failed.  Retry if it was due to a unit			   attention status			   (usually means media was changed). */			struct request_sense *reqbuf = rq->sense;			if (reqbuf->sense_key == UNIT_ATTENTION)				cdrom_saw_media_change(drive);			else if (reqbuf->sense_key == NOT_READY &&				 reqbuf->asc == 4 && reqbuf->ascq != 4) {				/* The drive is in the process of loading				   a disk.  Retry, but wait a little to give				   the drive time to complete the load. */				ssleep(2);			} else {				/* Otherwise, don't retry. */				retries = 0;			}			--retries;		}		/* End of retry loop. */	} while ((rq->cmd_flags & REQ_FAILED) && retries >= 0);	/* Return an error if the command failed. */	return (rq->cmd_flags & REQ_FAILED) ? -EIO : 0;}/* * Write handling */static int cdrom_write_check_ireason(ide_drive_t *drive, int len, int ireason){	/* Two notes about IDE interrupt reason here - 0 means that	 * the drive wants to receive data from us, 2 means that	 * the drive is expecting to transfer data to us.	 */	if (ireason == 0)		return 0;	else if (ireason == 2) {		/* Whoops... The drive wants to send data. */		printk(KERN_ERR "%s: %s: wrong transfer direction!\n",				drive->name, __FUNCTION__);		while (len > 0) {			int dum = 0;			HWIF(drive)->atapi_input_bytes(drive, &dum, sizeof(dum));			len -= sizeof(dum);		}	} else {		/* Drive wants a command packet, or invalid ireason... */		printk(KERN_ERR "%s: %s: bad interrupt reason 0x%02x\n",				drive->name, __FUNCTION__, ireason);	}	cdrom_end_request(drive, 0);	return 1;}typedef void (xfer_func_t)(ide_drive_t *, void *, u32);/* * best way to deal with dma that is not sector aligned right now... note * that in this path we are not using ->data or ->buffer at all. this irs * can replace cdrom_pc_intr, cdrom_read_intr, and cdrom_write_intr in the * future. */static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive){	struct cdrom_info *info = drive->driver_data;	struct request *rq = HWGROUP(drive)->rq;	int dma_error, dma, stat, ireason, len, thislen;	u8 lowcyl, highcyl;	xfer_func_t *xferfunc;	unsigned long flags;	/* Check for errors. */	dma_error = 0;	dma = info->dma;	if (dma) {

⌨️ 快捷键说明

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