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

📄 ide-scsi.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * 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. */#define IDESCSI_VERSION "0.9"#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/malloc.h>#include <linux/ide.h>#include <asm/io.h>#include <asm/bitops.h>#include <asm/uaccess.h>#include "scsi.h"#include "hosts.h"#include "sd.h"#include "ide-scsi.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 */	byte *buffer;				/* Data buffer */	byte *current_position;			/* Pointer into the above buffer */	struct scatterlist *sg;			/* Scatter gather table */	int b_count;				/* Bytes transferred from current entry */	Scsi_Cmnd *scsi_cmd;			/* SCSI command */	void (*done)(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_TRANSFORM			2	/* transform SCSI commands *//* *	SCSI command transformation layer */#define IDESCSI_TRANSFORM		0	/* Enable/Disable transformation */#define IDESCSI_SG_TRANSFORM		1	/* /dev/sg transformation *//* *	Log flags */#define IDESCSI_LOG_CMD			0	/* Log SCSI commands */typedef struct {	ide_drive_t *drive;	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;/* *	Per ATAPI device status bits. */#define IDESCSI_DRQ_INTERRUPT		0	/* DRQ interrupt device *//* *	ide-scsi requests. */#define IDESCSI_PC_RQ			90/* *	Bits of the interrupt reason register. */#define IDESCSI_IREASON_COD	0x1		/* Information transferred is command */#define IDESCSI_IREASON_IO	0x2		/* The device requests us to read */static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount){	while (bcount--)		IN_BYTE (IDE_DATA_REG);}static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount){	while (bcount--)		OUT_BYTE (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;	while (bcount) {		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {			printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");			idescsi_discard_data (drive, bcount);			return;		}		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);		atapi_input_bytes (drive, pc->sg->address + pc->b_count, count);		bcount -= count; pc->b_count += count;		if (pc->b_count == pc->sg->length) {			pc->sg++;			pc->b_count = 0;		}	}}static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount){	int count;	while (bcount) {		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {			printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");			idescsi_output_zeros (drive, bcount);			return;		}		count = IDE_MIN (pc->sg->length - pc->b_count, bcount);		atapi_output_bytes (drive, pc->sg->address + pc->b_count, count);		bcount -= count; pc->b_count += count;		if (pc->b_count == pc->sg->length) {			pc->sg++;			pc->b_count = 0;		}	}}/* *	Most of the SCSI commands are supported directly by ATAPI devices. *	idescsi_transform_pc handles the few exceptions. */static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc){	u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;	char *atapi_buf;	if (!test_bit(PC_TRANSFORM, &pc->flags))		return;	if (drive->media == ide_cdrom || drive->media == ide_optical) {		if (c[0] == READ_6 || c[0] == WRITE_6) {			c[8] = c[4];		c[5] = c[3];		c[4] = c[2];			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;			c[0] += (READ_10 - READ_6);		}		if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {			if (!scsi_buf)				return;			if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)				return;			memset(atapi_buf, 0, pc->buffer_size + 4);			memset (c, 0, 12);			c[0] = sc[0] | 0x40;	c[1] = sc[1];		c[2] = sc[2];			c[8] = sc[4] + 4;	c[9] = sc[5];			if (sc[4] + 4 > 255)				c[7] = sc[4] + 4 - 255;			if (c[0] == MODE_SELECT_10) {				atapi_buf[1] = scsi_buf[0];	/* Mode data length */				atapi_buf[2] = scsi_buf[1];	/* Medium type */				atapi_buf[3] = scsi_buf[2];	/* Device specific parameter */				atapi_buf[7] = scsi_buf[3];	/* Block descriptor length */				memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);			}			pc->buffer = atapi_buf;			pc->request_transfer += 4;			pc->buffer_size += 4;		}	}}static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc){	u8 *atapi_buf = pc->buffer;	u8 *sc = pc->scsi_cmd->cmnd;	u8 *scsi_buf = pc->scsi_cmd->request_buffer;	if (!test_bit(PC_TRANSFORM, &pc->flags))		return;	if (drive->media == ide_cdrom || drive->media == ide_optical) {		if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {			scsi_buf[0] = atapi_buf[1];		/* Mode data length */			scsi_buf[1] = atapi_buf[2];		/* Medium type */			scsi_buf[2] = atapi_buf[3];		/* Device specific parameter */			scsi_buf[3] = atapi_buf[7];		/* Block descriptor length */			memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);		}		if (pc->c[0] == INQUIRY) {			scsi_buf[2] |= 2;			/* ansi_revision */			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;	/* response data format */		}	}	if (atapi_buf && atapi_buf != scsi_buf)		kfree(atapi_buf);}static inline void idescsi_free_bh (struct buffer_head *bh){	struct buffer_head *bhp;	while (bh) {		bhp = bh;		bh = bh->b_reqnext;		kfree (bhp);	}}static void hexdump(u8 *x, int len){	int i;	printk("[ ");	for (i = 0; i < len; i++)		printk("%x ", x[i]);	printk("]\n");}static void idescsi_end_request (byte uptodate, ide_hwgroup_t *hwgroup){	ide_drive_t *drive = hwgroup->drive;	idescsi_scsi_t *scsi = drive->driver_data;	struct request *rq = hwgroup->rq;	idescsi_pc_t *pc = (idescsi_pc_t *) rq->buffer;	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);	u8 *scsi_buf;	unsigned long flags;	if (rq->cmd != IDESCSI_PC_RQ) {		ide_end_request (uptodate, hwgroup);		return;	}	ide_end_drive_cmd (drive, 0, 0);	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) {		pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);		if (log)			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);	} 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, IDE_MIN(16, pc->scsi_cmd->request_bufflen));			} else printk("\n");		}	}	spin_lock_irqsave(&io_request_lock,flags);		pc->done(pc->scsi_cmd);	spin_unlock_irqrestore(&io_request_lock,flags);	idescsi_free_bh (rq->bh);	kfree(pc); kfree(rq);	scsi->pc = NULL;}static inline unsigned long get_timeout(idescsi_pc_t *pc){	return IDE_MAX(WAIT_CMD, pc->timeout - jiffies);}/* *	Our interrupt handler. */static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive){	idescsi_scsi_t *scsi = drive->driver_data;	byte status, ireason;	int bcount;	idescsi_pc_t *pc=scsi->pc;	struct request *rq = pc->rq;	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_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)->dmaproc(ide_dma_end, drive));	}	status = GET_STAT();						/* Clear the interrupt */	if ((status & DRQ_STAT) == 0) {					/* No more interrupts */		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);		ide__sti();		if (status & ERR_STAT)			rq->errors++;		idescsi_end_request (1, HWGROUP(drive));		return ide_stopped;	}	bcount = IN_BYTE (IDE_BCOUNTH_REG) << 8 | IN_BYTE (IDE_BCOUNTL_REG);	ireason = IN_BYTE (IDE_IREASON_REG);	if (ireason & IDESCSI_IREASON_COD) {		printk (KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");		return ide_do_reset (drive);	}	if (ireason & IDESCSI_IREASON_IO) {		temp = pc->actually_transferred + bcount;		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);				}				pc->actually_transferred += temp;				pc->current_position += temp;				idescsi_discard_data (drive,bcount - temp);				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);				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 & IDESCSI_IREASON_IO) {		clear_bit(PC_WRITING, &pc->flags);		if (pc->sg)			idescsi_input_buffers (drive, pc, bcount);		else			atapi_input_bytes (drive,pc->current_position,bcount);	} else {		set_bit(PC_WRITING, &pc->flags);		if (pc->sg)			idescsi_output_buffers (drive, pc, bcount);		else			atapi_output_bytes (drive,pc->current_position,bcount);	}	pc->actually_transferred+=bcount;				/* Update the current position */	pc->current_position+=bcount;	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* And set the interrupt handler again */	return ide_started;}static ide_startstop_t idescsi_transfer_pc (ide_drive_t *drive){	idescsi_scsi_t *scsi = drive->driver_data;	idescsi_pc_t *pc = scsi->pc;	byte 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 = IN_BYTE (IDE_IREASON_REG);	if ((ireason & (IDESCSI_IREASON_IO | IDESCSI_IREASON_COD)) != IDESCSI_IREASON_COD) {		printk (KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while issuing a packet command\n");		return ide_do_reset (drive);	}	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);	/* Set the interrupt routine */	atapi_output_bytes (drive, scsi->pc->c, 12);			/* Send the actual packet */	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->driver_data;	int bcount;	struct request *rq = pc->rq;	int dma_ok = 0;	scsi->pc=pc;							/* Set the current packet command */	pc->actually_transferred=0;					/* We haven't transferred any data yet */

⌨️ 快捷键说明

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