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

📄 ide-scsi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	} else {		pc->scsi_cmd->result = DID_OK << 16;	}	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);	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_to_idescsi(drive);	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_in_hardirq();		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						drive->hwif->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){	ide_hwif_t *hwif = drive->hwif;	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);	}	BUG_ON(HWGROUP(drive)->handler != NULL);	/* Set the interrupt routine */	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);	/* Send the actual packet */	drive->hwif->atapi_output_bytes(drive, scsi->pc->c, 12);	if (test_bit (PC_DMA_OK, &pc->flags)) {		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);		hwif->dma_start(drive);	}	return ide_started;}static inline int idescsi_set_direction(idescsi_pc_t *pc){	switch (pc->c[0]) {		case READ_6: case READ_10: case READ_12:			clear_bit(PC_WRITING, &pc->flags);			return 0;		case WRITE_6: case WRITE_10: case WRITE_12:			set_bit(PC_WRITING, &pc->flags);			return 0;		default:			return 1;	}}static int idescsi_map_sg(ide_drive_t *drive, idescsi_pc_t *pc){	ide_hwif_t *hwif = drive->hwif;	struct scatterlist *sg, *scsi_sg;	int segments;	if (!pc->request_transfer || pc->request_transfer % 1024)		return 1;	if (idescsi_set_direction(pc))		return 1;	sg = hwif->sg_table;	scsi_sg = scsi_sglist(pc->scsi_cmd);	segments = scsi_sg_count(pc->scsi_cmd);	if (segments > hwif->sg_max_nents)		return 1;	hwif->sg_nents = segments;	memcpy(sg, scsi_sg, sizeof(*sg) * segments);	return 0;}/* *	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);	ide_hwif_t *hwif = drive->hwif;	atapi_feature_t feature;	atapi_bcount_t bcount;	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 && !idescsi_map_sg(drive, pc)) {		hwif->sg_mapped = 1;		feature.b.dma = !hwif->dma_setup(drive);		hwif->sg_mapped = 0;	}	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)) {		BUG_ON(HWGROUP(drive)->handler != NULL);		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 "dev: %s, cmd: %x, errors: %d\n", 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 (blk_sense_request(rq) || blk_special_request(rq)) {		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;}#ifdef CONFIG_IDE_PROC_FSstatic void idescsi_add_settings(ide_drive_t *drive){	idescsi_scsi_t *scsi = drive_to_idescsi(drive);/* *			drive	setting name	read/write	data type	min	max	mul_factor	div_factor	data pointer		set function */	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	TYPE_INT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);	ide_add_setting(drive,	"bios_head",	SETTING_RW,	TYPE_BYTE,	0,	255,	1,		1,		&drive->bios_head,	NULL);	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	TYPE_BYTE,	0,	63,	1,		1,		&drive->bios_sect,	NULL);	ide_add_setting(drive,	"transform",	SETTING_RW,	TYPE_INT,	0,	3,	1,		1,		&scsi->transform,	NULL);	ide_add_setting(drive,	"log",		SETTING_RW,	TYPE_INT,	0,	1,	1,		1,		&scsi->log,		NULL);}#elsestatic inline void idescsi_add_settings(ide_drive_t *drive) { ; }#endif/* *	Driver initialization. */static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi){	if (drive->id && (drive->id->config & 0x0060) == 0x20)		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);	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);}static void ide_scsi_remove(ide_drive_t *drive){	struct Scsi_Host *scsihost = drive->driver_data;	struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);	struct gendisk *g = scsi->disk;	scsi_remove_host(scsihost);	ide_proc_unregister_driver(drive, scsi->driver);	ide_unregister_region(g);	drive->driver_data = NULL;	g->private_data = NULL;	put_disk(g);	ide_scsi_put(scsi);}static int ide_scsi_probe(ide_drive_t *);#ifdef CONFIG_IDE_PROC_FSstatic ide_proc_entry_t idescsi_proc[] = {	{ "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },	{ NULL, 0, NULL, NULL }};#endifstatic ide_driver_t idescsi_driver = {	.gen_driver = {		.owner		= THIS_MODULE,		.name		= "ide-scsi",		.bus		= &ide_bus_type,	},	.probe			= ide_scsi_probe,	.remove			= ide_scsi_remove,	.version		= IDESCSI_VERSION,	.media			= ide_scsi,	.supports_dsc_overlap	= 0,	.do_request		= idescsi_do_request,	.end_request		= idescsi_end_request,	.error                  = idescsi_atapi_error,	.abort                  = idescsi_atapi_abort,#ifdef CONFIG_IDE_PROC_FS	.proc			= idescsi_proc,#endif};static int idescsi_ide_open(struct inode *inode, struct file *filp){	struct gendisk *disk = inode->i_bdev->bd_disk;	struct ide_scsi_obj *scsi;	if (!(scsi = ide_scsi_get(disk)))		return -ENXIO;

⌨️ 快捷键说明

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