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

📄 fas216.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  linux/arch/arm/drivers/scsi/fas216.c * *  Copyright (C) 1997-2000 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and * other sources, including: *   the AMD Am53CF94 data sheet *   the AMD Am53C94 data sheet  * * This is a generic driver.  To use it, have a look at cumana_2.c.  You * should define your own structure that overlays FAS216_Info, eg: * struct my_host_data { *    FAS216_Info info; *    ... my host specific data ... * }; * * Changelog: *  30-08-1997	RMK	Created *  14-09-1997	RMK	Started disconnect support *  08-02-1998	RMK	Corrected real DMA support *  15-02-1998	RMK	Started sync xfer support *  06-04-1998	RMK	Tightened conditions for printing incomplete *			transfers *  02-05-1998	RMK	Added extra checks in fas216_reset *  24-05-1998	RMK	Fixed synchronous transfers with period >= 200ns *  27-06-1998	RMK	Changed asm/delay.h to linux/delay.h *  26-08-1998	RMK	Improved message support wrt MESSAGE_REJECT *  02-04-2000	RMK	Converted to use the new error handling, and *			automatically request sense data upon check *			condition status from targets. * * Todo: *  - allow individual devices to enable sync xfers. */#include <linux/module.h>#include <linux/blk.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <linux/unistd.h>#include <linux/stat.h>#include <linux/delay.h>#include <linux/init.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/ecard.h>#define FAS216_C#include "../../scsi/scsi.h"#include "../../scsi/hosts.h"#include "fas216.h"#define VER_MAJOR	0#define VER_MINOR	0#define VER_PATCH	5/* NOTE: SCSI2 Synchronous transfers *require* DMA according to *  the data sheet.  This restriction is crazy, especially when *  you only want to send 16 bytes!  What were the guys who *  designed this chip on at that time?  Did they read the SCSI2 *  spec at all?  The following sections are taken from the SCSI2 *  standard (s2r10) concerning this: * * > IMPLEMENTORS NOTES: * >   (1)  Re-negotiation at every selection is not recommended, since a * >   significant performance impact is likely. * * >  The implied synchronous agreement shall remain in effect until a BUS DEVICE * >  RESET message is received, until a hard reset condition occurs, or until one * >  of the two SCSI devices elects to modify the agreement.  The default data * >  transfer mode is asynchronous data transfer mode.  The default data transfer * >  mode is entered at power on, after a BUS DEVICE RESET message, or after a hard * >  reset condition. * *  In total, this means that once you have elected to use synchronous *  transfers, you must always use DMA. * *  I was thinking that this was a good chip until I found this restriction ;( */#define SCSI2_SYNC#undef  SCSI2_WIDE#undef  SCSI2_TAG#undef DEBUG_CONNECT#undef DEBUG_BUSSERVICE#undef DEBUG_FUNCTIONDONE#undef DEBUG_MESSAGES#undef CHECK_STRUCTUREstatic struct { int stat, ssr, isr, ph; } list[8];static int ptr;static void fas216_dumpstate(FAS216_Info *info){	unsigned char is, stat, inst;	is   = inb(REG_IS(info));	stat = inb(REG_STAT(info));	inst = inb(REG_INST(info));		printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X"	       " INST=%02X IS=%02X CFIS=%02X",		inb(REG_CTCL(info)), inb(REG_CTCM(info)),		inb(REG_CMD(info)),  stat, inst, is,		inb(REG_CFIS(info)));	printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n",		inb(REG_CNTL1(info)), inb(REG_CNTL2(info)),		inb(REG_CNTL3(info)), inb(REG_CTCH(info)));}static void fas216_dumpinfo(FAS216_Info *info){	static int used = 0;	int i;	if (used++)		return;	printk("FAS216_Info=\n");	printk("  { magic_start=%lX host=%p SCpnt=%p origSCpnt=%p\n",		info->magic_start, info->host, info->SCpnt,		info->origSCpnt);	printk("    scsi={ io_port=%X io_shift=%X irq=%X cfg={ %X %X %X %X }\n",		info->scsi.io_port, info->scsi.io_shift, info->scsi.irq,		info->scsi.cfg[0], info->scsi.cfg[1], info->scsi.cfg[2],		info->scsi.cfg[3]);	printk("           type=%p phase=%X reconnected={ target=%d lun=%d tag=%d }\n",		info->scsi.type, info->scsi.phase,		info->scsi.reconnected.target,		info->scsi.reconnected.lun, info->scsi.reconnected.tag);	printk("           SCp={ ptr=%p this_residual=%X buffer=%p buffers_residual=%X }\n",		info->scsi.SCp.ptr, info->scsi.SCp.this_residual,		info->scsi.SCp.buffer, info->scsi.SCp.buffers_residual);	printk("      msgs async_stp=%X disconnectable=%d aborting=%d }\n",		info->scsi.async_stp,		info->scsi.disconnectable, info->scsi.aborting);	printk("    stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"	       "            disconnects=%X aborts=%X bus_resets=%X host_resets=%X}\n",		info->stats.queues, info->stats.removes, info->stats.fins,		info->stats.reads, info->stats.writes, info->stats.miscs,		info->stats.disconnects, info->stats.aborts, info->stats.bus_resets,		info->stats.host_resets);	printk("    ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n",		info->ifcfg.clockrate, info->ifcfg.select_timeout,		info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);	for (i = 0; i < 8; i++) {		printk("    busyluns[%d]=%X dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n",			i, info->busyluns[i], i,			info->device[i].disconnect_ok, info->device[i].stp,			info->device[i].sof, info->device[i].sync_state);	}	printk("    dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n",		info->dma.transfer_type, info->dma.setup,		info->dma.pseudo, info->dma.stop);	printk("    internal_done=%X magic_end=%lX }\n",		info->internal_done, info->magic_end);}#ifdef CHECK_STRUCTUREstatic void __fas216_checkmagic(FAS216_Info *info, const char *func){	int corruption = 0;	if (info->magic_start != MAGIC) {		printk(KERN_CRIT "FAS216 Error: magic at start corrupted\n");		corruption++;	}	if (info->magic_end != MAGIC) {		printk(KERN_CRIT "FAS216 Error: magic at end corrupted\n");		corruption++;	}	if (corruption) {		fas216_dumpinfo(info);		panic("scsi memory space corrupted in %s", func);	}}#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)#else#define fas216_checkmagic(info)#endifstatic const char *fas216_bus_phase(int stat){	static const char *phases[] = {		"DATA OUT", "DATA IN",		"COMMAND", "STATUS",		"MISC OUT", "MISC IN",		"MESG OUT", "MESG IN"	};	return phases[stat & STAT_BUSMASK];}static const char *fas216_drv_phase(FAS216_Info *info){	switch (info->scsi.phase) {	case PHASE_IDLE:		return "idle";	case PHASE_SELECTION:		return "selection";	case PHASE_COMMAND:		return "command";	case PHASE_RECONNECTED:		return "reconnected";	case PHASE_DATAOUT:		return "data out";	case PHASE_DATAIN:		return "data in";	case PHASE_MSGIN:		return "message in";	case PHASE_MSGIN_DISCONNECT:	return "disconnect";	case PHASE_MSGOUT_EXPECT:	return "expect message out";	case PHASE_MSGOUT:		return "message out";	case PHASE_STATUS:		return "status";	case PHASE_DONE:		return "done";	default:			return "???";	}}static char fas216_target(FAS216_Info *info){	if (info->SCpnt)		return '0' + info->SCpnt->target;	else		return 'H';}static void add_debug_list(int stat, int ssr, int isr, int ph){	list[ptr].stat = stat;	list[ptr].ssr = ssr;	list[ptr].isr = isr;	list[ptr].ph = ph;	ptr = (ptr + 1) & 7;}static void print_debug_list(void){	int i;	i = ptr;	printk(KERN_ERR "SCSI IRQ trail: ");	do {		printk("%02X:%02X:%02X:%1X ",			list[i].stat, list[i].ssr,			list[i].isr, list[i].ph);		i = (i + 1) & 7;	} while (i != ptr);	printk("\n");}static void fas216_done(FAS216_Info *info, unsigned int result);/* Function: int fas216_clockrate(unsigned int clock) * Purpose : calculate correct value to be written into clock conversion *	     factor register. * Params  : clock - clock speed in MHz * Returns : CLKF_ value */static int fas216_clockrate(int clock){	if (clock <= 10 || clock > 40) {		printk(KERN_CRIT		       "fas216: invalid clock rate: check your driver!\n");		clock = -1;	} else		clock = ((clock - 1) / 5 + 1) & 7;	return clock;}/* Function: unsigned short fas216_get_last_msg(FAS216_Info *info, int pos) * Purpose : retrieve a last message from the list, using position in fifo * Params  : info - interface to search *         : pos  - current fifo position */static inline unsigned shortfas216_get_last_msg(FAS216_Info *info, int pos){	unsigned short packed_msg = NOP;	struct message *msg;	int msgnr = 0;	while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {		if (pos >= msg->fifo)			break;	}	if (msg) {		if (msg->msg[0] == EXTENDED_MESSAGE)			packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8;		else			packed_msg = msg->msg[0];	}#ifdef DEBUG_MESSAGES	printk("Message: %04X found at position %02X\n",		packed_msg, pos);#endif	return packed_msg;}/* Function: int fas216_syncperiod(FAS216_Info *info, int ns) * Purpose : Calculate value to be loaded into the STP register *           for a given period in ns * Params  : info - state structure for interface connected to device *         : ns   - period in ns (between subsequent bytes) * Returns : Value suitable for REG_STP */static intfas216_syncperiod(FAS216_Info *info, int ns){	int value = (info->ifcfg.clockrate * ns) / 1000;	fas216_checkmagic(info);	if (value < 4)		value = 4;	else if (value > 35)		value = 35;	return value & 31;}/* Function: void fas216_set_sync(FAS216_Info *info, int target) * Purpose : Correctly setup FAS216 chip for specified transfer period. * Params  : info   - state structure for interface *         : target - target * Notes   : we need to switch the chip out of FASTSCSI mode if we have *           a transfer period >= 200ns - otherwise the chip will violate *           the SCSI timings. */static voidfas216_set_sync(FAS216_Info *info, int target){	outb(info->device[target].sof, REG_SOF(info));	outb(info->device[target].stp, REG_STP(info));	if (info->device[target].period >= (200 / 4))		outb(info->scsi.cfg[2] & ~CNTL3_FASTSCSI, REG_CNTL3(info));	else		outb(info->scsi.cfg[2], REG_CNTL3(info));}/* Synchronous transfer support * * Note: The SCSI II r10 spec says (5.6.12): * *  (2)  Due to historical problems with early host adapters that could *  not accept an SDTR message, some targets may not initiate synchronous *  negotiation after a power cycle as required by this standard.  Host *  adapters that support synchronous mode may avoid the ensuing failure *  modes when the target is independently power cycled by initiating a *  synchronous negotiation on each REQUEST SENSE and INQUIRY command. *  This approach increases the SCSI bus overhead and is not recommended *  for new implementations.  The correct method is to respond to an *  SDTR message with a MESSAGE REJECT message if the either the *  initiator or target devices does not support synchronous transfers *  or does not want to negotiate for synchronous transfers at the time. *  Using the correct method assures compatibility with wide data *  transfers and future enhancements. * * We will always initiate a synchronous transfer negociation request on * every INQUIRY or REQUEST SENSE message, unless the target itself has * at some point performed a synchronous transfer negociation request, or * we have synchronous transfers disabled for this device. *//* Function: void fas216_handlesync(FAS216_Info *info, char *msg) * Purpose : Handle a synchronous transfer message from the target * Params  : info - state structure for interface *         : msg  - message from target */static voidfas216_handlesync(FAS216_Info *info, char *msg){	struct fas216_device *dev = &info->device[info->SCpnt->target];	enum { sync, async, none, reject } res = none;#ifdef SCSI2_SYNC	switch (msg[0]) {	case MESSAGE_REJECT:		/* Synchronous transfer request failed.		 * Note: SCSI II r10:		 *		 *  SCSI devices that are capable of synchronous		 *  data transfers shall not respond to an SDTR		 *  message with a MESSAGE REJECT message.		 *		 * Hence, if we get this condition, we disable		 * negociation for this device.		 */		if (dev->sync_state == neg_inprogress) {			dev->sync_state = neg_invalid;			res = async;		}		break;	case EXTENDED_MESSAGE:		switch (dev->sync_state) {		/* We don't accept synchronous transfer requests.		 * Respond with a MESSAGE_REJECT to prevent a		 * synchronous transfer agreement from being reached.		 */		case neg_invalid:			res = reject;			break;		/* We were not negociating a synchronous transfer,		 * but the device sent us a negociation request.		 * Honour the request by sending back a SDTR		 * message containing our capability, limited by		 * the targets capability.		 */		default:			outb(CMD_SETATN, REG_CMD(info));			if (msg[4] > info->ifcfg.sync_max_depth)				msg[4] = info->ifcfg.sync_max_depth;			if (msg[3] < 1000 / info->ifcfg.clockrate)				msg[3] = 1000 / info->ifcfg.clockrate;			msgqueue_flush(&info->scsi.msgs);			msgqueue_addmsg(&info->scsi.msgs, 5,					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,					msg[3], msg[4]);			info->scsi.phase = PHASE_MSGOUT_EXPECT;			/* This is wrong.  The agreement is not in effect			 * until this message is accepted by the device			 */			dev->sync_state = neg_targcomplete;			res = sync;			break;		/* We initiated the synchronous transfer negociation,		 * and have successfully received a response from the		 * target.  The synchronous transfer agreement has been		 * reached.  Note: if the values returned are out of our		 * bounds, we must reject the message.		 */		case neg_inprogress:			res = reject;			if (msg[4] <= info->ifcfg.sync_max_depth &&			    msg[3] >= 1000 / info->ifcfg.clockrate) {				dev->sync_state = neg_complete;				res = sync;			}			break;		}	}#else	res = reject;#endif	switch (res) {	case sync:		dev->period = msg[3];		dev->sof    = msg[4];		dev->stp    = fas216_syncperiod(info, msg[3] * 4);		fas216_set_sync(info, info->SCpnt->target);

⌨️ 快捷键说明

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