ide-scsi.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,160 行 · 第 1/3 页

C
1,160
字号
					((test_bit(PC_TIMEDOUT, &pc->flags)?DID_TIME_OUT:DID_OK) << 16);	} else if (test_bit(PC_TIMEDOUT, &pc->flags)) {		if (log)			printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n",					drive->name, pc->scsi_cmd->serial_number);		pc->scsi_cmd->result = DID_TIME_OUT << 16;	} else if (rq->errors >= ERROR_MAX) {		pc->scsi_cmd->result = DID_ERROR << 16;		if (log)			printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);	} else if (rq->errors) {		if (log)			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);		if (!idescsi_check_condition(drive, rq))			/* we started a request sense, so we'll be back, exit for now */			return 0;		pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);	} else {		pc->scsi_cmd->result = DID_OK << 16;		idescsi_transform_pc2 (drive, pc);		if (log) {			printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);			if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {				printk(", rst = ");				scsi_buf = pc->scsi_cmd->request_buffer;				hexdump(scsi_buf, min_t(unsigned, 16, pc->scsi_cmd->request_bufflen));			} else printk("\n");		}	}	host = pc->scsi_cmd->device->host;	spin_lock_irqsave(host->host_lock, flags);	pc->done(pc->scsi_cmd);	spin_unlock_irqrestore(host->host_lock, flags);	idescsi_free_bio(rq->bio);	kfree(pc);	kfree(rq);	scsi->pc = NULL;	return 0;}static inline unsigned long get_timeout(idescsi_pc_t *pc){	return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies);}static int idescsi_expiry(ide_drive_t *drive){	idescsi_scsi_t *scsi = drive->driver_data;	idescsi_pc_t   *pc   = scsi->pc;#if IDESCSI_DEBUG_LOG	printk(KERN_WARNING "idescsi_expiry called for %lu at %lu\n", pc->scsi_cmd->serial_number, jiffies);#endif	set_bit(PC_TIMEDOUT, &pc->flags);	return 0;					/* we do not want the ide subsystem to retry */}/* *	Our interrupt handler. */static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive){	idescsi_scsi_t *scsi = drive_to_idescsi(drive);	idescsi_pc_t *pc=scsi->pc;	struct request *rq = pc->rq;	atapi_bcount_t bcount;	atapi_status_t status;	atapi_ireason_t ireason;	atapi_feature_t feature;	unsigned int temp;#if IDESCSI_DEBUG_LOG	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");#endif /* IDESCSI_DEBUG_LOG */	if (test_bit(PC_TIMEDOUT, &pc->flags)){#if IDESCSI_DEBUG_LOG		printk(KERN_WARNING "idescsi_pc_intr: got timed out packet  %lu at %lu\n",				pc->scsi_cmd->serial_number, jiffies);#endif		/* end this request now - scsi should retry it*/		idescsi_end_request (drive, 1, 0);		return ide_stopped;	}	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {#if IDESCSI_DEBUG_LOG		printk ("ide-scsi: %s: DMA complete\n", drive->name);#endif /* IDESCSI_DEBUG_LOG */		pc->actually_transferred=pc->request_transfer;		(void) HWIF(drive)->ide_dma_end(drive);	}	feature.all = 0;	/* Clear the interrupt */	status.all = HWIF(drive)->INB(IDE_STATUS_REG);	if (!status.b.drq) {		/* No more interrupts */		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);		local_irq_enable();		if (status.b.check)			rq->errors++;		idescsi_end_request (drive, 1, 0);		return ide_stopped;	}	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);	if (ireason.b.cod) {		printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");		return ide_do_reset (drive);	}	if (ireason.b.io) {		temp = pc->actually_transferred + bcount.all;		if (temp > pc->request_transfer) {			if (temp > pc->buffer_size) {				printk(KERN_ERR "ide-scsi: The scsi wants to "					"send us more data than expected "					"- discarding data\n");				temp = pc->buffer_size - pc->actually_transferred;				if (temp) {					clear_bit(PC_WRITING, &pc->flags);					if (pc->sg)						idescsi_input_buffers(drive, pc, temp);					else						atapi_input_bytes(drive, pc->current_position, temp);					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all);				}				pc->actually_transferred += temp;				pc->current_position += temp;				idescsi_discard_data(drive, bcount.all - temp);				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);				return ide_started;			}#if IDESCSI_DEBUG_LOG			printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");#endif /* IDESCSI_DEBUG_LOG */		}	}	if (ireason.b.io) {		clear_bit(PC_WRITING, &pc->flags);		if (pc->sg)			idescsi_input_buffers(drive, pc, bcount.all);		else			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);	} else {		set_bit(PC_WRITING, &pc->flags);		if (pc->sg)			idescsi_output_buffers (drive, pc, bcount.all);		else			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);	}	/* Update the current position */	pc->actually_transferred += bcount.all;	pc->current_position += bcount.all;	/* And set the interrupt handler again */	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);	return ide_started;}static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive){	idescsi_scsi_t *scsi = drive_to_idescsi(drive);	idescsi_pc_t *pc = scsi->pc;	atapi_ireason_t ireason;	ide_startstop_t startstop;	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {		printk(KERN_ERR "ide-scsi: Strange, packet command "			"initiated yet DRQ isn't asserted\n");		return startstop;	}	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);	if (!ireason.b.cod || ireason.b.io) {		printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "				"issuing a packet command\n");		return ide_do_reset (drive);	}	if (HWGROUP(drive)->handler != NULL)		BUG();	/* Set the interrupt routine */	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);	/* Send the actual packet */	atapi_output_bytes(drive, scsi->pc->c, 12);	if (test_bit (PC_DMA_OK, &pc->flags)) {		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);		(void) (HWIF(drive)->ide_dma_begin(drive));	}	return ide_started;}/* *	Issue a packet command */static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc){	idescsi_scsi_t *scsi = drive_to_idescsi(drive);	atapi_feature_t feature;	atapi_bcount_t bcount;	struct request *rq = pc->rq;	scsi->pc=pc;							/* Set the current packet command */	pc->actually_transferred=0;					/* We haven't transferred any data yet */	pc->current_position=pc->buffer;	bcount.all = min(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */	feature.all = 0;	if (drive->using_dma && rq->bio) {		if (test_bit(PC_WRITING, &pc->flags))			feature.b.dma = !HWIF(drive)->ide_dma_write(drive);		else			feature.b.dma = !HWIF(drive)->ide_dma_read(drive);	}	SELECT_DRIVE(drive);	if (IDE_CONTROL_REG)		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);	if (feature.b.dma)		set_bit(PC_DMA_OK, &pc->flags);	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {		if (HWGROUP(drive)->handler != NULL)			BUG();		ide_set_handler(drive, &idescsi_transfer_pc,				get_timeout(pc), idescsi_expiry);		/* Issue the packet command */		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);		return ide_started;	} else {		/* Issue the packet command */		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);		return idescsi_transfer_pc(drive);	}}/* *	idescsi_do_request is our request handling function. */static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block){#if IDESCSI_DEBUG_LOG	printk (KERN_INFO "rq_status: %d, dev: %s, cmd: %x, errors: %d\n",rq->rq_status, rq->rq_disk->disk_name,rq->cmd[0],rq->errors);	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);#endif /* IDESCSI_DEBUG_LOG */	if (rq->flags & (REQ_SPECIAL|REQ_SENSE)) {		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special);	}	blk_dump_rq_flags(rq, "ide-scsi: unsup command");	idescsi_end_request (drive, 0, 0);	return ide_stopped;}static void idescsi_add_settings(ide_drive_t *drive){	idescsi_scsi_t *scsi = drive_to_idescsi(drive);/* *			drive	setting name	read/write	ioctl	ioctl		data type	min	max	mul_factor	div_factor	data pointer		set function */	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);	ide_add_setting(drive,	"bios_head",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	255,	1,		1,		&drive->bios_head,	NULL);	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	63,	1,		1,		&drive->bios_sect,	NULL);	ide_add_setting(drive,	"transform",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	3,	1,		1,		&scsi->transform,	NULL);	ide_add_setting(drive,	"log",		SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1,	1,		1,		&scsi->log,		NULL);}/* *	Driver initialization. */static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi){	DRIVER(drive)->busy++;	drive->ready_stat = 0;	if (drive->id && (drive->id->config & 0x0060) == 0x20)		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);	set_bit(IDESCSI_TRANSFORM, &scsi->transform);	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);#if IDESCSI_DEBUG_LOG	set_bit(IDESCSI_LOG_CMD, &scsi->log);#endif /* IDESCSI_DEBUG_LOG */	idescsi_add_settings(drive);	DRIVER(drive)->busy--;}static int idescsi_cleanup (ide_drive_t *drive){	struct Scsi_Host *scsihost = drive->driver_data;	if (ide_unregister_subdriver(drive))		return 1;		/* FIXME?: Are these two statements necessary? */	drive->driver_data = NULL;	drive->disk->fops = ide_fops;	scsi_remove_host(scsihost);	scsi_host_put(scsihost);	return 0;}static int idescsi_attach(ide_drive_t *drive);/* *	IDE subdriver functions, registered with ide.c */static ide_driver_t idescsi_driver = {	.owner			= THIS_MODULE,	.name			= "ide-scsi",	.version		= IDESCSI_VERSION,	.media			= ide_scsi,	.busy			= 0,	.supports_dsc_overlap	= 0,	.attach			= idescsi_attach,	.cleanup		= idescsi_cleanup,	.do_request		= idescsi_do_request,	.end_request		= idescsi_end_request,	.error                  = idescsi_atapi_error,	.abort                  = idescsi_atapi_abort,	.drives			= LIST_HEAD_INIT(idescsi_driver.drives),};static int idescsi_ide_open(struct inode *inode, struct file *filp){	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;	drive->usage++;	return 0;}static int idescsi_ide_release(struct inode *inode, struct file *filp){	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;	drive->usage--;	return 0;}static int idescsi_ide_ioctl(struct inode *inode, struct file *file,			unsigned int cmd, unsigned long arg){	struct block_device *bdev = inode->i_bdev;	return generic_ide_ioctl(file, bdev, cmd, arg);}static struct block_device_operations idescsi_ops = {	.owner		= THIS_MODULE,	.open		= idescsi_ide_open,	.release	= idescsi_ide_release,	.ioctl		= idescsi_ide_ioctl,};static int idescsi_attach(ide_drive_t *drive);static int idescsi_slave_configure(Scsi_Device * sdp){	/* Configure detected device */	scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun);	return 0;}static const char *idescsi_info (struct Scsi_Host *host){	return "SCSI host adapter emulation for IDE ATAPI devices";}static int idescsi_ioctl (Scsi_Device *dev, int cmd, void __user *arg){	idescsi_scsi_t *scsi = scsihost_to_idescsi(dev->host);	if (cmd == SG_SET_TRANSFORM) {		if (arg)			set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);		else			clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);		return 0;	} else if (cmd == SG_GET_TRANSFORM)		return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int __user *) arg);	return -EINVAL;

⌨️ 快捷键说明

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