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

📄 seagate.c

📁 linux0.99源代码用于研究linux操作系统
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	seagate.c Copyright (C) 1992 Drew Eckhardt  *	low level scsi driver for ST01/ST02 by *		Drew Eckhardt  * *	<drew@colorado.edu> */#include <linux/config.h>#if defined(CONFIG_SCSI_SEAGATE) || defined(CONFIG_SCSI_FD_88x) #include <asm/io.h>#include <asm/system.h>#include <linux/signal.h>#include <linux/sched.h>#include "../blk.h"#include "scsi.h"#include "hosts.h"#include "seagate.h"static int internal_command(unsigned char target, unsigned char lun,			    const void *cmnd,			 void *buff, int bufflen, int reselect);static int incommand;			/*						set if arbitration has finished and we are 						in some command phase.					*/static void *base_address = NULL;	/*						Where the card ROM starts,						used to calculate memory mapped						register location.					*/static volatile int abort_confirm = 0;static volatile void *st0x_cr_sr;       /*						control register write,						status register read.						256 bytes in length.						Read is status of SCSI BUS,						as per STAT masks.					*/static volatile void *st0x_dr;         /*						data register, read write						256 bytes in length.					*/static volatile int st0x_aborted=0;	/* 						set when we are aborted, ie by a time out, etc.					*/					/*						In theory, we have a nice auto						detect routine - but this 						overides it. 					*/			#define retcode(result) (((result) << 16) | (message << 8) | status) 			#define STATUS (*(unsigned char *) st0x_cr_sr)#define CONTROL STATUS #define DATA (*(unsigned char *) st0x_dr)#ifndef OVERRIDE		static const char *  seagate_bases[] = {(char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000, (char *) 0xce000, (char *) 0xce000,				        (char *) 0xdc000, (char *) 0xde000};typedef struct 	{	char *signature ;	unsigned offset;	unsigned length;	} Signature;	static const Signature signatures[] = {#ifdef CONFIG_SCSI_SEAGATE{"SCSI BIOS 2.00  (C) Copyright 1987 Seagate", 15, 40},/*	The following two lines are NOT mistakes.  One detects  	ROM revision 3.0.0, the other 3.2.  Since seagate	has only one type of SCSI adapter, and this is not 	going to change, the "SEAGATE" and "SCSI" together	are probably "good enough"*/{"SEAGATE SCSI BIOS ",16, 17},{"SEAGATE SCSI BIOS ",17, 17},#endif/*	This is for the Future Domain 88x series.  I've been told that	the Seagate controllers are just repackages of these, and seeing	early seagate BIOS bearing the Future Domain copyright,	I believe it.*/#ifdef CONFIG_SCSI_FD_88x{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/90", 5, 46},#endif};/*	Note that the last signature handles BIOS revisions 3.0.0 and 	3.2 - the real ID's are SEAGATE SCSI BIOS REVISION 3.0.0SEAGATE SCSI BIOS REVISION 3.2*/#define NUM_SIGNATURES (sizeof(signatures) / sizeof(Signature))#endif/* * hostno stores the hostnumber, as told to us by the init routine. */static int hostno = -1;static void seagate_reconnect_intr(int);int seagate_st0x_detect (int hostnum)	{#ifndef OVERRIDE	int i,j;#endifstatic struct sigaction seagate_sigaction = {	&seagate_reconnect_intr,	0,	SA_INTERRUPT,	NULL};/* *	First, we try for the manual override. */#ifdef DEBUG 	printk("Autodetecting seagate ST0x\n");#endif		if (hostno != -1)		{		printk ("ERROR : seagate_st0x_detect() called twice.\n");		return 0;		}		base_address = NULL;#ifdef OVERRIDE	base_address = (void *) OVERRIDE;	#ifdef DEBUG	printk("Base address overridden to %x\n", base_address);#endif#else	/* *	To detect this card, we simply look for the signature *	from the BIOS version notice in all the possible locations *	of the ROM's.  This has a nice sideeffect of not trashing * 	any register locations that might be used by something else. */	for (i = 0; i < (sizeof (seagate_bases) / sizeof (char  * )); ++i)		for (j = 0; !base_address && j < NUM_SIGNATURES; ++j)		if (!memcmp ((void *) (seagate_bases[i] +		    signatures[j].offset), (void *) signatures[j].signature,		    signatures[j].length))			base_address = (void *) seagate_bases[i]; #endif 	if (base_address)		{		st0x_cr_sr =(void *) (((unsigned char *) base_address) + 0x1a00); 		st0x_dr = (void *) (((unsigned char *) base_address )+ 0x1c00);#ifdef DEBUG		printk("ST0x detected. Base address = %x, cr = %x, dr = %x\n", base_address, st0x_cr_sr, st0x_dr);#endif/* *	At all times, we will use IRQ 5.   */		hostno = hostnum;		if (irqaction(5, &seagate_sigaction)) {			printk("Unable to allocate IRQ5 for ST0x driver\n");			return 0;		}		return -1;		}	else		{#ifdef DEBUG		printk("ST0x not detected.\n");#endif		return 0;		}	}	 const char *seagate_st0x_info(void){	static char buffer[] = "Seagate ST-0X SCSI driver by Drew Eckhardt \n""$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/seagate.c,v 1.1 1992/07/24 06:27:38 root Exp root $\n";	return buffer;}/* * These are our saved pointers for the outstanding command that is  * waiting for a reconnect */static unsigned char current_target, current_lun;static unsigned char *current_cmnd, *current_data;static int current_bufflen;static void (*done_fn)(Scsi_Cmnd *) = NULL;static Scsi_Cmnd * SCint = NULL;/* * These control whether or not disconnect / reconnect will be attempted, * or are being attempted. */#define NO_RECONNECT 	0#define RECONNECT_NOW 	1#define CAN_RECONNECT	2/* * This determines if we are expecting to reconnect or not. */static int should_reconnect = 0;/* * The seagate_reconnect_intr routine is called when a target reselects the  * host adapter.  This occurs on the interrupt triggered by the target  * asserting SEL. */static void seagate_reconnect_intr (int unused)	{	int temp;/* enable all other interrupts. */		sti();#if (DEBUG & PHASE_RESELECT)	printk("scsi%d : seagate_reconnect_intr() called\n", hostno);#endif	if (!should_reconnect)	    printk("scsi%d: unexpected interrupt.\n", hostno);	else		{		should_reconnect = 0;#if (DEBUG & PHASE_RESELECT)		printk("scsi%d : internal_command("		       "%d, %08x, %08x, %d, RECONNECT_NOW\n", hostno, 			current_target, current_data, current_bufflen);#endif			temp =  internal_command (current_target, current_lun,			current_cmnd, current_data, current_bufflen,			RECONNECT_NOW);		if (msg_byte(temp) != DISCONNECT)			{			if (done_fn)				{#if (DEBUG & PHASE_RESELECT)				printk("scsi%d : done_fn(%d,%08x)", hostno, 				hostno, temp);#endif				SCint->result = temp;				done_fn (SCint);				}			else				printk("done_fn() not defined.\n");			}		}	} /*  * The seagate_st0x_queue_command() function provides a queued interface * to the seagate SCSI driver.  Basically, it just passes control onto the * seagate_command() function, after fixing it so that the done_fn() * is set to the one passed to the function. */int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt,  void (*done)(Scsi_Cmnd *))	{	int result;	done_fn = done;	current_target = SCpnt->target;	current_lun = SCpnt->lun;	(const void *) current_cmnd = SCpnt->cmnd;	current_data = SCpnt->request_buffer;	current_bufflen = SCpnt->request_bufflen;	SCint = SCpnt;	result = internal_command (SCpnt->target, SCpnt->lun, SCpnt->cmnd, SCpnt->request_buffer,				   SCpnt->request_bufflen, 				   CAN_RECONNECT);	if (msg_byte(result) == DISCONNECT)		return 0;	else 		{		  SCpnt->result = result;		done_fn (SCpnt); 		return 1; 		}	}int seagate_st0x_command (Scsi_Cmnd * SCpnt)	{	return internal_command (SCpnt->target, SCpnt->lun, SCpnt->cmnd, SCpnt->request_buffer,				 SCpnt->request_bufflen, 				 (int) NO_RECONNECT);	}	static int internal_command(unsigned char target, unsigned char lun, const void *cmnd,			 void *buff, int bufflen, int reselect)	{	int len;				unsigned char *data;		int clock;				int temp;#if ((DEBUG & PHASE_ETC) || (DEBUG & PRINT_COMMAND) || (DEBUG & PHASE_EXIT))		int i;#endif#if (DEBUG & PHASE_ETC)	int phase=0, newphase;#endif	int done = 0;	unsigned char status = 0;		unsigned char message = 0;	register unsigned char status_read;	len=bufflen;	data=(unsigned char *) buff;	incommand = 0;	st0x_aborted = 0;#if (DEBUG & PRINT_COMMAND)	printk ("scsi%d : target = %d, command = ", hostno, target);	for (i = 0; i < COMMAND_SIZE(((unsigned char *)cmnd)[0]); ++i)		printk("%02x ",  ((unsigned char *) cmnd)[i]);	printk("\n");#endif#if (DEBUG & PHASE_RESELECT)	switch (reselect)	{	case RECONNECT_NOW :		printk("scsi%d : reconnecting\n", hostno);		break;	case CAN_RECONNECT :		printk("scsi%d : allowed to reconnect\n", hostno);		break;	default :		printk("scsi%d : not allowed to reconnect\n", hostno);	}#endif		if (target > 6)		return DID_BAD_TARGET;/* *	We work it differently depending on if this is is "the first time," *	or a reconnect.  If this is a reselct phase, then SEL will  *	be asserted, and we must skip selection / arbitration phases. */	if (reselect == RECONNECT_NOW) 		{#if (DEBUG & PHASE_RESELECT)		printk("scsi%d : phase RESELECT \n", hostno);#endif/* *	At this point, we should find the logical or of our ID and the original *	target's ID on the BUS, with BSY, SEL, and I/O signals asserted. * *	After ARBITRATION phase is completed, only SEL, BSY, and the  *	target ID are asserted.  A valid initator ID is not on the bus *	until IO is asserted, so we must wait for that. */				for (clock = jiffies + 10, temp = 0; (jiffies < clock) &&		     !(STATUS & STAT_IO););				if (jiffies >= clock)			{#if (DEBUG & PHASE_RESELECT)			printk("scsi%d : RESELECT timed out while waiting for IO .\n",				hostno);#endif			return (DID_BAD_INTR << 16);			}/*  * 	After I/O is asserted by the target, we can read our ID and its *	ID off of the BUS. */ 		if (!((temp = DATA) & 0x80))			{#if (DEBUG & PHASE_RESELECT)			printk("scsi%d : detected reconnect request to different target.\n" 			       "\tData bus = %d\n", hostno, temp);#endif			return (DID_BAD_INTR << 16);			}		if (!(temp & (1 << current_target)))			{			printk("scsi%d : Unexpected reselect interrupt.  Data bus = %d\n",				hostno, temp);			return (DID_BAD_INTR << 16);			}                data=current_data;      /* WDE add */                cmnd=current_cmnd;      /* WDE add */                len=current_bufflen;    /* WDE add *//* * 	We have determined that we have been selected.  At this point,  *	we must respond to the reselection by asserting BSY ourselves */		CONTROL = (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);/* *	The target will drop SEL, and raise BSY, at which time we must drop *	BSY. */		for (clock = jiffies + 10; (jiffies < clock) &&  (STATUS & STAT_SEL););		if (jiffies >= clock)			{ 			CONTROL = (BASE_CMD | CMD_INTR);#if (DEBUG & PHASE_RESELECT)			printk("scsi%d : RESELECT timed out while waiting for SEL.\n",				hostno);#endif			return (DID_BAD_INTR << 16);				 			}		CONTROL = BASE_CMD;/* *	At this point, we have connected with the target and can get  *	on with our lives. */	 		}  		else 		{	#if (DEBUG & PHASE_BUS_FREE)		printk ("scsi%d : phase = BUS FREE \n", hostno);#endif/* *	BUS FREE PHASE * * 	On entry, we make sure that the BUS is in a BUS FREE *	phase, by insuring that both BSY and SEL are low for *	at least one bus settle delay.  Several reads help *	eliminate wire glitch. */		clock = jiffies + ST0X_BUS_FREE_DELAY;			while (((STATUS |  STATUS | STATUS) & 		         (STAT_BSY | STAT_SEL)) && 			 (!st0x_aborted) && (jiffies < clock));		if (jiffies > clock)			return retcode(DID_BUS_BUSY);		else if (st0x_aborted)			return retcode(st0x_aborted);/* *	Bus free has been detected, within BUS settle.  I used to  *	support an arbitration phase - however, on the Seagate, this 

⌨️ 快捷键说明

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