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

📄 ide-scsi.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/drivers/scsi/ide-scsi.c	Version 0.9		Jul   4, 1999 * * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il> *//* * Emulation of a SCSI host adapter for IDE ATAPI devices. * * With this driver, one can use the Linux SCSI drivers instead of the * native IDE ATAPI drivers. * * Ver 0.1   Dec  3 96   Initial version. * Ver 0.2   Jan 26 97   Fixed bug in cleanup_module() and added emulation *                        of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks *                        to Janos Farkas for pointing this out. *                       Avoid using bitfields in structures for m68k. *                       Added Scatter/Gather and DMA support. * Ver 0.4   Dec  7 97   Add support for ATAPI PD/CD drives. *                       Use variable timeout for each command. * Ver 0.5   Jan  2 98   Fix previous PD/CD support. *                       Allow disabling of SCSI-6 to SCSI-10 transformation. * Ver 0.6   Jan 27 98   Allow disabling of SCSI command translation layer *                        for access through /dev/sg. *                       Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation. * Ver 0.7   Dec 04 98   Ignore commands where lun != 0 to avoid multiple *                        detection of devices with CONFIG_SCSI_MULTI_LUN * Ver 0.8   Feb 05 99   Optical media need translation too. Reverse 0.7. * Ver 0.9   Jul 04 99   Fix a bug in SG_SET_TRANSFORM. * Ver 0.91  Jun 10 02   Fix "off by one" error in transforms * Ver 0.92  Dec 31 02   Implement new SCSI mid level API */#define IDESCSI_VERSION "0.92"#include <linux/module.h>#include <linux/types.h>#include <linux/string.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/ioport.h>#include <linux/blkdev.h>#include <linux/errno.h>#include <linux/hdreg.h>#include <linux/slab.h>#include <linux/ide.h>#include <linux/scatterlist.h>#include <linux/delay.h>#include <linux/mutex.h>#include <linux/bitops.h>#include <asm/io.h>#include <asm/uaccess.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include <scsi/scsi_tcq.h>#include <scsi/sg.h>#define IDESCSI_DEBUG_LOG		0typedef struct idescsi_pc_s {	u8 c[12];				/* Actual packet bytes */	int request_transfer;			/* Bytes to transfer */	int actually_transferred;		/* Bytes actually transferred */	int buffer_size;			/* Size of our data buffer */	struct request *rq;			/* The corresponding request */	u8 *buffer;				/* Data buffer */	u8 *current_position;			/* Pointer into the above buffer */	struct scatterlist *sg;			/* Scatter gather table */	unsigned int sg_cnt;			/* Number of entries in sg */	int b_count;				/* Bytes transferred from current entry */	struct scsi_cmnd *scsi_cmd;		/* SCSI command */	void (*done)(struct scsi_cmnd *);	/* Scsi completion routine */	unsigned long flags;			/* Status/Action flags */	unsigned long timeout;			/* Command timeout */} idescsi_pc_t;/* *	Packet command status bits. */#define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */#define PC_WRITING			1	/* Data direction */#define PC_TIMEDOUT			3	/* command timed out */#define PC_DMA_OK			4	/* Use DMA *//* *	SCSI command transformation layer */#define IDESCSI_SG_TRANSFORM		1	/* /dev/sg transformation *//* *	Log flags */#define IDESCSI_LOG_CMD			0	/* Log SCSI commands */typedef struct ide_scsi_obj {	ide_drive_t		*drive;	ide_driver_t		*driver;	struct gendisk		*disk;	struct Scsi_Host	*host;	idescsi_pc_t *pc;			/* Current packet command */	unsigned long flags;			/* Status/Action flags */	unsigned long transform;		/* SCSI cmd translation layer */	unsigned long log;			/* log flags */} idescsi_scsi_t;static DEFINE_MUTEX(idescsi_ref_mutex);static int idescsi_nocd;			/* Set by module param to skip cd */#define ide_scsi_g(disk) \	container_of((disk)->private_data, struct ide_scsi_obj, driver)static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk){	struct ide_scsi_obj *scsi = NULL;	mutex_lock(&idescsi_ref_mutex);	scsi = ide_scsi_g(disk);	if (scsi)		scsi_host_get(scsi->host);	mutex_unlock(&idescsi_ref_mutex);	return scsi;}static void ide_scsi_put(struct ide_scsi_obj *scsi){	mutex_lock(&idescsi_ref_mutex);	scsi_host_put(scsi->host);	mutex_unlock(&idescsi_ref_mutex);}static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host){	return (idescsi_scsi_t*) (&host[1]);}static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive){	return scsihost_to_idescsi(ide_drive->driver_data);}/* *	Per ATAPI device status bits. */#define IDESCSI_DRQ_INTERRUPT		0	/* DRQ interrupt device *//* *	ide-scsi requests. */#define IDESCSI_PC_RQ			90static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount){	while (bcount--)		(void) HWIF(drive)->INB(IDE_DATA_REG);}static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount){	while (bcount--)		HWIF(drive)->OUTB(0, IDE_DATA_REG);}/* *	PIO data transfer routines using the scatter gather table. */static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount){	int count;	char *buf;	while (bcount) {		count = min(pc->sg->length - pc->b_count, bcount);		if (PageHighMem(sg_page(pc->sg))) {			unsigned long flags;			local_irq_save(flags);			buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +					pc->sg->offset;			drive->hwif->atapi_input_bytes(drive,						buf + pc->b_count, count);			kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);			local_irq_restore(flags);		} else {			buf = sg_virt(pc->sg);			drive->hwif->atapi_input_bytes(drive,						buf + pc->b_count, count);		}		bcount -= count; pc->b_count += count;		if (pc->b_count == pc->sg->length) {			if (!--pc->sg_cnt)				break;			pc->sg = sg_next(pc->sg);			pc->b_count = 0;		}	}	if (bcount) {		printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");		idescsi_discard_data (drive, bcount);	}}static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount){	int count;	char *buf;	while (bcount) {		count = min(pc->sg->length - pc->b_count, bcount);		if (PageHighMem(sg_page(pc->sg))) {			unsigned long flags;			local_irq_save(flags);			buf = kmap_atomic(sg_page(pc->sg), KM_IRQ0) +						pc->sg->offset;			drive->hwif->atapi_output_bytes(drive,						buf + pc->b_count, count);			kunmap_atomic(buf - pc->sg->offset, KM_IRQ0);			local_irq_restore(flags);		} else {			buf = sg_virt(pc->sg);			drive->hwif->atapi_output_bytes(drive,						buf + pc->b_count, count);		}		bcount -= count; pc->b_count += count;		if (pc->b_count == pc->sg->length) {			if (!--pc->sg_cnt)				break;			pc->sg = sg_next(pc->sg);			pc->b_count = 0;		}	}	if (bcount) {		printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");		idescsi_output_zeros (drive, bcount);	}}static void ide_scsi_hex_dump(u8 *data, int len){	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, data, len, 0);}static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_command){	idescsi_scsi_t *scsi = drive_to_idescsi(drive);	idescsi_pc_t   *pc;	struct request *rq;	u8             *buf;	/* stuff a sense request in front of our current request */	pc = kzalloc(sizeof(idescsi_pc_t), GFP_ATOMIC);	rq = kmalloc(sizeof(struct request), GFP_ATOMIC);	buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC);	if (!pc || !rq || !buf) {		kfree(buf);		kfree(rq);		kfree(pc);		return -ENOMEM;	}	ide_init_drive_cmd(rq);	rq->special = (char *) pc;	pc->rq = rq;	pc->buffer = buf;	pc->c[0] = REQUEST_SENSE;	pc->c[4] = pc->request_transfer = pc->buffer_size = SCSI_SENSE_BUFFERSIZE;	rq->cmd_type = REQ_TYPE_SENSE;	pc->timeout = jiffies + WAIT_READY;	/* NOTE! Save the failed packet command in "rq->buffer" */	rq->buffer = (void *) failed_command->special;	pc->scsi_cmd = ((idescsi_pc_t *) failed_command->special)->scsi_cmd;	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {		printk ("ide-scsi: %s: queue cmd = ", drive->name);		ide_scsi_hex_dump(pc->c, 6);	}	rq->rq_disk = scsi->disk;	return ide_do_drive_cmd(drive, rq, ide_preempt);}static int idescsi_end_request(ide_drive_t *, int, int);static ide_startstop_tidescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err){	if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))		/* force an abort */		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	rq->errors++;	idescsi_end_request(drive, 0, 0);	return ide_stopped;}static ide_startstop_tidescsi_atapi_abort(ide_drive_t *drive, struct request *rq){#if IDESCSI_DEBUG_LOG	printk(KERN_WARNING "idescsi_atapi_abort called for %lu\n",			((idescsi_pc_t *) rq->special)->scsi_cmd->serial_number);#endif	rq->errors |= ERROR_MAX;	idescsi_end_request(drive, 0, 0);	return ide_stopped;}static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs){	idescsi_scsi_t *scsi = drive_to_idescsi(drive);	struct request *rq = HWGROUP(drive)->rq;	idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);	struct Scsi_Host *host;	int errors = rq->errors;	unsigned long flags;	if (!blk_special_request(rq) && !blk_sense_request(rq)) {		ide_end_request(drive, uptodate, nrsecs);		return 0;	}	ide_end_drive_cmd (drive, 0, 0);	if (blk_sense_request(rq)) {		idescsi_pc_t *opc = (idescsi_pc_t *) rq->buffer;		if (log) {			printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number);			ide_scsi_hex_dump(pc->buffer, 16);		}		memcpy((void *) opc->scsi_cmd->sense_buffer, pc->buffer, SCSI_SENSE_BUFFERSIZE);		kfree(pc->buffer);		kfree(pc);		kfree(rq);		pc = opc;		rq = pc->rq;		pc->scsi_cmd->result = (CHECK_CONDITION << 1) |					((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 (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 (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);

⌨️ 快捷键说明

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