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

📄 fas216.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  linux/drivers/acorn/scsi/fas216.c * *  Copyright (C) 1997-2003 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. */#include <linux/module.h>#include <linux/blkdev.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/proc_fs.h>#include <linux/delay.h>#include <linux/bitops.h>#include <linux/init.h>#include <linux/interrupt.h>#include <asm/dma.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/ecard.h>#include "../scsi.h"#include <scsi/scsi_dbg.h>#include <scsi/scsi_host.h>#include "fas216.h"#include "scsi.h"/* 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_TAG#undef DEBUG_CONNECT#undef DEBUG_MESSAGES#undef CHECK_STRUCTURE#define LOG_CONNECT		(1 << 0)#define LOG_BUSSERVICE		(1 << 1)#define LOG_FUNCTIONDONE	(1 << 2)#define LOG_MESSAGES		(1 << 3)#define LOG_BUFFER		(1 << 4)#define LOG_ERROR		(1 << 8)static int level_mask = LOG_ERROR;module_param(level_mask, int, 0644);static int __init fas216_log_setup(char *str){	char *s;	level_mask = 0;	while ((s = strsep(&str, ",")) != NULL) {		switch (s[0]) {		case 'a':			if (strcmp(s, "all") == 0)				level_mask |= -1;			break;		case 'b':			if (strncmp(s, "bus", 3) == 0)				level_mask |= LOG_BUSSERVICE;			if (strncmp(s, "buf", 3) == 0)				level_mask |= LOG_BUFFER;			break;		case 'c':			level_mask |= LOG_CONNECT;			break;		case 'e':			level_mask |= LOG_ERROR;			break;		case 'm':			level_mask |= LOG_MESSAGES;			break;		case 'n':			if (strcmp(s, "none") == 0)				level_mask = 0;			break;		case 's':			level_mask |= LOG_FUNCTIONDONE;			break;		}	}	return 1;}__setup("fas216_logging=", fas216_log_setup);static inline unsigned char fas216_readb(FAS216_Info *info, unsigned int reg){	unsigned int off = reg << info->scsi.io_shift;	return readb(info->scsi.io_base + off);}static inline void fas216_writeb(FAS216_Info *info, unsigned int reg, unsigned int val){	unsigned int off = reg << info->scsi.io_shift;	writeb(val, info->scsi.io_base + off);}static void fas216_dumpstate(FAS216_Info *info){	unsigned char is, stat, inst;	is   = fas216_readb(info, REG_IS);	stat = fas216_readb(info, REG_STAT);	inst = fas216_readb(info, REG_INST);		printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X"	       " INST=%02X IS=%02X CFIS=%02X",		fas216_readb(info, REG_CTCL),		fas216_readb(info, REG_CTCM),		fas216_readb(info, REG_CMD),  stat, inst, is,		fas216_readb(info, REG_CFIS));	printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n",		fas216_readb(info, REG_CNTL1),		fas216_readb(info, REG_CNTL2),		fas216_readb(info, REG_CNTL3),		fas216_readb(info, REG_CTCH));}static void print_SCp(struct scsi_pointer *SCp, const char *prefix, const char *suffix){	printk("%sptr %p this_residual 0x%x buffer %p buffers_residual 0x%x%s",		prefix, SCp->ptr, SCp->this_residual, SCp->buffer,		SCp->buffers_residual, suffix);}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_shift=%X irq=%X cfg={ %X %X %X %X }\n",		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\n",		info->scsi.type, info->scsi.phase);	print_SCp(&info->scsi.SCp, "           SCp={ ", " }\n");	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]=%08lx 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){	static const char *phases[] = {		[PHASE_IDLE]		= "idle",		[PHASE_SELECTION]	= "selection",		[PHASE_COMMAND]		= "command",		[PHASE_DATAOUT]		= "data out",		[PHASE_DATAIN]		= "data in",		[PHASE_MSGIN]		= "message in",		[PHASE_MSGIN_DISCONNECT]= "disconnect",		[PHASE_MSGOUT_EXPECT]	= "expect message out",		[PHASE_MSGOUT]		= "message out",		[PHASE_STATUS]		= "status",		[PHASE_DONE]		= "done",	};	if (info->scsi.phase < ARRAY_SIZE(phases) &&	    phases[info->scsi.phase])		return phases[info->scsi.phase];	return "???";}static char fas216_target(FAS216_Info *info){	if (info->SCpnt)		return '0' + info->SCpnt->device->id;	else		return 'H';}static voidfas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap){	static char buf[1024];	vsnprintf(buf, sizeof(buf), fmt, ap);	printk("scsi%d.%c: %s", info->host->host_no, target, buf);}static voidfas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...){	va_list args;	if (level != 0 && !(level & level_mask))		return;	va_start(args, fmt);	fas216_do_log(info, '0' + SCpnt->device->id, fmt, args);	va_end(args);	printk(" CDB: ");	__scsi_print_command(SCpnt->cmnd);}static voidfas216_log_target(FAS216_Info *info, int level, int target, char *fmt, ...){	va_list args;	if (level != 0 && !(level & level_mask))		return;	if (target < 0)		target = 'H';	else		target += '0';	va_start(args, fmt);	fas216_do_log(info, target, fmt, args);	va_end(args);	printk("\n");}static void fas216_log(FAS216_Info *info, int level, char *fmt, ...){	va_list args;	if (level != 0 && !(level & level_mask))		return;	va_start(args, fmt);	fas216_do_log(info, fas216_target(info), fmt, args);	va_end(args);	printk("\n");}#define PH_SIZE	32static struct { int stat, ssr, isr, ph; } ph_list[PH_SIZE];static int ph_ptr;static void add_debug_list(int stat, int ssr, int isr, int ph){	ph_list[ph_ptr].stat = stat;	ph_list[ph_ptr].ssr = ssr;	ph_list[ph_ptr].isr = isr;	ph_list[ph_ptr].ph = ph;	ph_ptr = (ph_ptr + 1) & (PH_SIZE-1);}static struct { int command; void *from; } cmd_list[8];static int cmd_ptr;static void fas216_cmd(FAS216_Info *info, unsigned int command){	cmd_list[cmd_ptr].command = command;	cmd_list[cmd_ptr].from = __builtin_return_address(0);	cmd_ptr = (cmd_ptr + 1) & 7;	fas216_writeb(info, REG_CMD, command);}static void print_debug_list(void){	int i;	i = ph_ptr;	printk(KERN_ERR "SCSI IRQ trail\n");	do {		printk(" %02x:%02x:%02x:%1x",			ph_list[i].stat, ph_list[i].ssr,			ph_list[i].isr, ph_list[i].ph);		i = (i + 1) & (PH_SIZE - 1);		if (((i ^ ph_ptr) & 7) == 0)			printk("\n");	} while (i != ph_ptr);	if ((i ^ ph_ptr) & 7)		printk("\n");	i = cmd_ptr;	printk(KERN_ERR "FAS216 commands: ");	do {		printk("%02x:%p ", cmd_list[i].command, cmd_list[i].from);		i = (i + 1) & 7;	} while (i != cmd_ptr);	printk("\n");}static void fas216_done(FAS216_Info *info, unsigned int result);/** * fas216_get_last_msg - retrive last message from the list * @info: interface to search * @pos: current fifo position * * Retrieve a last message from the list, using position in fifo. */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];	}	fas216_log(info, LOG_MESSAGES,		"Message: %04x found at position %02x\n", packed_msg, pos);	return packed_msg;}/** * fas216_syncperiod - calculate STP register value * @info: state structure for interface connected to device * @ns: period in ns (between subsequent bytes) * * Calculate value to be loaded into the STP register for a given period * in ns. Returns a value suitable for REG_STP. */static int fas216_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;}/** * fas216_set_sync - setup FAS216 chip for specified transfer period. * @info: state structure for interface connected to device * @target: target * * Correctly setup FAS216 chip for specified transfer period. * 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 void fas216_set_sync(FAS216_Info *info, int target){	unsigned int cntl3;	fas216_writeb(info, REG_SOF, info->device[target].sof);	fas216_writeb(info, REG_STP, info->device[target].stp);	cntl3 = info->scsi.cfg[2];	if (info->device[target].period >= (200 / 4))		cntl3 = cntl3 & ~CNTL3_FASTSCSI;	fas216_writeb(info, REG_CNTL3, cntl3);}/* 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

⌨️ 快捷键说明

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