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

📄 ide-scsi.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
	pc->current_position=pc->buffer;	bcount = IDE_MIN (pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */	if (drive->using_dma && rq->bh)		dma_ok=!HWIF(drive)->dmaproc(test_bit (PC_WRITING, &pc->flags) ? ide_dma_write : ide_dma_read, drive);	SELECT_DRIVE(HWIF(drive), drive);	if (IDE_CONTROL_REG)		OUT_BYTE (drive->ctl,IDE_CONTROL_REG);	OUT_BYTE (dma_ok,IDE_FEATURE_REG);	OUT_BYTE (bcount >> 8,IDE_BCOUNTH_REG);	OUT_BYTE (bcount & 0xff,IDE_BCOUNTL_REG);	if (dma_ok) {		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);		(void) (HWIF(drive)->dmaproc(ide_dma_begin, drive));	}	if (test_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {		ide_set_handler (drive, &idescsi_transfer_pc, get_timeout(pc), NULL);		OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG);		/* Issue the packet command */		return ide_started;	} else {		OUT_BYTE (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, unsigned long block){#if IDESCSI_DEBUG_LOG	printk (KERN_INFO "rq_status: %d, rq_dev: %u, cmd: %d, errors: %d\n",rq->rq_status,(unsigned int) rq->rq_dev,rq->cmd,rq->errors);	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %ld\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);#endif /* IDESCSI_DEBUG_LOG */	if (rq->cmd == IDESCSI_PC_RQ) {		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->buffer);	}	printk (KERN_ERR "ide-scsi: %s: unsupported command in request queue (%x)\n", drive->name, rq->cmd);	idescsi_end_request (0,HWGROUP (drive));	return ide_stopped;}static int idescsi_open (struct inode *inode, struct file *filp, ide_drive_t *drive){	MOD_INC_USE_COUNT;	return 0;}static void idescsi_ide_release (struct inode *inode, struct file *filp, ide_drive_t *drive){	MOD_DEC_USE_COUNT;}static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES];static int idescsi_initialized = 0;static void idescsi_add_settings(ide_drive_t *drive){	idescsi_scsi_t *scsi = drive->driver_data;/* *			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, int id){	DRIVER(drive)->busy++;	idescsi_drives[id] = drive;	drive->driver_data = scsi;	drive->ready_stat = 0;	memset (scsi, 0, sizeof (idescsi_scsi_t));	scsi->drive = drive;	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);}static int idescsi_cleanup (ide_drive_t *drive){	idescsi_scsi_t *scsi = drive->driver_data;	if (ide_unregister_subdriver (drive))		return 1;	drive->driver_data = NULL;	kfree (scsi);	return 0;}/* *	IDE subdriver functions, registered with ide.c */static ide_driver_t idescsi_driver = {	"ide-scsi",		/* name */	IDESCSI_VERSION,	/* version */	ide_scsi,		/* media */	0,			/* busy */	1,			/* supports_dma */	0,			/* supports_dsc_overlap */	idescsi_cleanup,	/* cleanup */	idescsi_do_request,	/* do_request */	idescsi_end_request,	/* end_request */	NULL,			/* ioctl */	idescsi_open,		/* open */	idescsi_ide_release,	/* release */	NULL,			/* media_change */	NULL,			/* revalidate */	NULL,			/* pre_reset */	NULL,			/* capacity */	NULL,			/* special */	NULL			/* proc */};int idescsi_init (void);static ide_module_t idescsi_module = {	IDE_DRIVER_MODULE,	idescsi_init,	&idescsi_driver,	NULL};/* *	idescsi_init will register the driver for each scsi. */int idescsi_init (void){	ide_drive_t *drive;	idescsi_scsi_t *scsi;	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};	int i, failed, id;	if (idescsi_initialized)		return 0;	idescsi_initialized = 1;	for (i = 0; i < MAX_HWIFS * MAX_DRIVES; i++)		idescsi_drives[i] = NULL;	MOD_INC_USE_COUNT;	for (i = 0; media[i] != 255; i++) {		failed = 0;		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {			if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {				printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);				continue;			}			if (ide_register_subdriver (drive, &idescsi_driver, IDE_SUBDRIVER_VERSION)) {				printk (KERN_ERR "ide-scsi: %s: Failed to register the driver with ide.c\n", drive->name);				kfree (scsi);				continue;			}			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++);			idescsi_setup (drive, scsi, id);			failed--;		}	}	ide_register_module(&idescsi_module);	MOD_DEC_USE_COUNT;	return 0;}int idescsi_detect (Scsi_Host_Template *host_template){	struct Scsi_Host *host;	int id;	int last_lun = 0;	host_template->proc_name = "ide-scsi";	host = scsi_register(host_template, 0);	if(host == NULL)		return 0;			for (id = 0; id < MAX_HWIFS * MAX_DRIVES && idescsi_drives[id]; id++)		last_lun = IDE_MAX(last_lun, idescsi_drives[id]->last_lun);	host->max_id = id;	host->max_lun = last_lun + 1;	host->can_queue = host->cmd_per_lun * id;	return 1;}int idescsi_release (struct Scsi_Host *host){	ide_drive_t *drive;	int id;	for (id = 0; id < MAX_HWIFS * MAX_DRIVES; id++) {		drive = idescsi_drives[id];		if (drive)			DRIVER(drive)->busy--;	}	return 0;}const char *idescsi_info (struct Scsi_Host *host){	return "SCSI host adapter emulation for IDE ATAPI devices";}int idescsi_ioctl (Scsi_Device *dev, int cmd, void *arg){	ide_drive_t *drive = idescsi_drives[dev->id];	idescsi_scsi_t *scsi = drive->driver_data;	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 *) arg);	return -EINVAL;}static inline struct buffer_head *idescsi_kmalloc_bh (int count){	struct buffer_head *bh, *bhp, *first_bh;	if ((first_bh = bhp = bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)		goto abort;	memset (bh, 0, sizeof (struct buffer_head));	bh->b_reqnext = NULL;	while (--count) {		if ((bh = kmalloc (sizeof(struct buffer_head), GFP_ATOMIC)) == NULL)			goto abort;		memset (bh, 0, sizeof (struct buffer_head));		bhp->b_reqnext = bh;		bhp = bh;		bh->b_reqnext = NULL;	}	return first_bh;abort:	idescsi_free_bh (first_bh);	return NULL;}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 inline struct buffer_head *idescsi_dma_bh (ide_drive_t *drive, idescsi_pc_t *pc){	struct buffer_head *bh = NULL, *first_bh = NULL;	int segments = pc->scsi_cmd->use_sg;	struct scatterlist *sg = pc->scsi_cmd->request_buffer;	if (!drive->using_dma || !pc->request_transfer || pc->request_transfer % 1024)		return NULL;	if (idescsi_set_direction(pc))		return NULL;	if (segments) {		if ((first_bh = bh = idescsi_kmalloc_bh (segments)) == NULL)			return NULL;#if IDESCSI_DEBUG_LOG		printk ("ide-scsi: %s: building DMA table, %d segments, %dkB total\n", drive->name, segments, pc->request_transfer >> 10);#endif /* IDESCSI_DEBUG_LOG */		while (segments--) {			bh->b_data = sg->address;			bh->b_size = sg->length;			bh = bh->b_reqnext;			sg++;		}	} else {		if ((first_bh = bh = idescsi_kmalloc_bh (1)) == NULL)			return NULL;#if IDESCSI_DEBUG_LOG		printk ("ide-scsi: %s: building DMA table for a single buffer (%dkB)\n", drive->name, pc->request_transfer >> 10);#endif /* IDESCSI_DEBUG_LOG */		bh->b_data = pc->scsi_cmd->request_buffer;		bh->b_size = pc->request_transfer;	}	return first_bh;}static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd){	idescsi_scsi_t *scsi = drive->driver_data;	if (MAJOR(cmd->request.rq_dev) == SCSI_GENERIC_MAJOR)		return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);	return test_bit(IDESCSI_TRANSFORM, &scsi->transform);}int idescsi_queue (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)){	ide_drive_t *drive = idescsi_drives[cmd->target];	idescsi_scsi_t *scsi;	struct request *rq = NULL;	idescsi_pc_t *pc = NULL;	if (!drive) {		printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->target);		goto abort;	}	scsi = drive->driver_data;	pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);	rq = kmalloc (sizeof (struct request), GFP_ATOMIC);	if (rq == NULL || pc == NULL) {		printk (KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);		goto abort;	}	memset (pc->c, 0, 12);	pc->flags = 0;	pc->rq = rq;	memcpy (pc->c, cmd->cmnd, cmd->cmd_len);	if (cmd->use_sg) {		pc->buffer = NULL;		pc->sg = cmd->request_buffer;	} else {		pc->buffer = cmd->request_buffer;		pc->sg = NULL;	}	pc->b_count = 0;	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;	pc->scsi_cmd = cmd;	pc->done = done;	pc->timeout = jiffies + cmd->timeout_per_command;	if (should_transform(drive, cmd))		set_bit(PC_TRANSFORM, &pc->flags);	idescsi_transform_pc1 (drive, pc);	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);		hexdump(cmd->cmnd, cmd->cmd_len);		if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {			printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);			hexdump(pc->c, 12);		}	}	ide_init_drive_cmd (rq);	rq->buffer = (char *) pc;	rq->bh = idescsi_dma_bh (drive, pc);	rq->cmd = IDESCSI_PC_RQ;	spin_unlock(&io_request_lock);	(void) ide_do_drive_cmd (drive, rq, ide_end);	spin_lock_irq(&io_request_lock);	return 0;abort:	if (pc) kfree (pc);	if (rq) kfree (rq);	cmd->result = DID_ERROR << 16;	done(cmd);	return 0;}int idescsi_abort (Scsi_Cmnd *cmd){	return SCSI_ABORT_SNOOZE;}int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags){	return SCSI_RESET_SUCCESS;}int idescsi_bios (Disk *disk, kdev_t dev, int *parm){	ide_drive_t *drive = idescsi_drives[disk->device->id];	if (drive->bios_cyl && drive->bios_head && drive->bios_sect) {		parm[0] = drive->bios_head;		parm[1] = drive->bios_sect;		parm[2] = drive->bios_cyl;	}	return 0;}static Scsi_Host_Template idescsi_template = IDESCSI;static int __init init_idescsi_module(void){	idescsi_init();	idescsi_template.module = THIS_MODULE;	scsi_register_module (MODULE_SCSI_HA, &idescsi_template);	return 0;}static void __exit exit_idescsi_module(void){	ide_drive_t *drive;	byte media[] = {TYPE_DISK, TYPE_TAPE, TYPE_PROCESSOR, TYPE_WORM, TYPE_ROM, TYPE_SCANNER, TYPE_MOD, 255};	int i, failed;	scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template);	for (i = 0; media[i] != 255; i++) {		failed = 0;		while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)			if (idescsi_cleanup (drive)) {				printk ("%s: exit_idescsi_module() called while still busy\n", drive->name);				failed++;			}	}	ide_unregister_module(&idescsi_module);}module_init(init_idescsi_module);module_exit(exit_idescsi_module);

⌨️ 快捷键说明

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