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

📄 ncr53c9x.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* NCR53C9x.c:  Generic SCSI driver code for NCR53C9x chips. * * Originally esp.c : EnhancedScsiProcessor Sun SCSI driver code. * * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu) * * Most DMA dependencies put in driver specific files by  * Jesper Skov (jskov@cygnus.co.uk) * * Set up to use esp_read/esp_write (preprocessor macros in NCR53c9x.h) by * Tymm Twillman (tymm@coe.missouri.edu) *//* TODO: * * 1) Maybe disable parity checking in config register one for SCSI1 *    targets.  (Gilmore says parity error on the SBus can lock up *    old sun4c's) * 2) Add support for DMA2 pipelining. * 3) Add tagged queueing. * 4) Maybe change use of "esp" to something more "NCR"'ish. */#ifdef MODULE#include <linux/module.h>#endif#include <linux/config.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/types.h>#include <linux/string.h>#include <linux/malloc.h>#include <linux/blk.h>#include <linux/proc_fs.h>#include <linux/stat.h>#include <linux/init.h>#include "scsi.h"#include "hosts.h"#include "NCR53C9x.h"#include <asm/system.h>#include <asm/ptrace.h>#include <asm/pgtable.h>#include <asm/io.h>#include <asm/irq.h>/* Command phase enumeration. */enum {	not_issued    = 0x00,  /* Still in the issue_SC queue.          */	/* Various forms of selecting a target. */#define in_slct_mask    0x10	in_slct_norm  = 0x10,  /* ESP is arbitrating, normal selection  */	in_slct_stop  = 0x11,  /* ESP will select, then stop with IRQ   */	in_slct_msg   = 0x12,  /* select, then send a message           */	in_slct_tag   = 0x13,  /* select and send tagged queue msg      */	in_slct_sneg  = 0x14,  /* select and acquire sync capabilities  */	/* Any post selection activity. */#define in_phases_mask  0x20	in_datain     = 0x20,  /* Data is transferring from the bus     */	in_dataout    = 0x21,  /* Data is transferring to the bus       */	in_data_done  = 0x22,  /* Last DMA data operation done (maybe)  */	in_msgin      = 0x23,  /* Eating message from target            */	in_msgincont  = 0x24,  /* Eating more msg bytes from target     */	in_msgindone  = 0x25,  /* Decide what to do with what we got    */	in_msgout     = 0x26,  /* Sending message to target             */	in_msgoutdone = 0x27,  /* Done sending msg out                  */	in_cmdbegin   = 0x28,  /* Sending cmd after abnormal selection  */	in_cmdend     = 0x29,  /* Done sending slow cmd                 */	in_status     = 0x2a,  /* Was in status phase, finishing cmd    */	in_freeing    = 0x2b,  /* freeing the bus for cmd cmplt or disc */	in_the_dark   = 0x2c,  /* Don't know what bus phase we are in   */	/* Special states, ie. not normal bus transitions... */#define in_spec_mask    0x80	in_abortone   = 0x80,  /* Aborting one command currently        */	in_abortall   = 0x81,  /* Blowing away all commands we have     */	in_resetdev   = 0x82,  /* SCSI target reset in progress         */	in_resetbus   = 0x83,  /* SCSI bus reset in progress            */	in_tgterror   = 0x84,  /* Target did something stupid           */};enum {	/* Zero has special meaning, see skipahead[12]. *//*0*/	do_never,/*1*/	do_phase_determine,/*2*/	do_reset_bus,/*3*/	do_reset_complete,/*4*/	do_work_bus,/*5*/	do_intr_end};/* The master ring of all esp hosts we are managing in this driver. */struct NCR_ESP *espchain = 0;int nesps = 0, esps_in_use = 0, esps_running = 0;void esp_intr(int irq, void *dev_id, struct pt_regs *pregs);/* Debugging routines */struct esp_cmdstrings {	unchar cmdchar;	char *text;} esp_cmd_strings[] = {	/* Miscellaneous */	{ ESP_CMD_NULL, "ESP_NOP", },	{ ESP_CMD_FLUSH, "FIFO_FLUSH", },	{ ESP_CMD_RC, "RSTESP", },	{ ESP_CMD_RS, "RSTSCSI", },	/* Disconnected State Group */	{ ESP_CMD_RSEL, "RESLCTSEQ", },	{ ESP_CMD_SEL, "SLCTNATN", },	{ ESP_CMD_SELA, "SLCTATN", },	{ ESP_CMD_SELAS, "SLCTATNSTOP", },	{ ESP_CMD_ESEL, "ENSLCTRESEL", },	{ ESP_CMD_DSEL, "DISSELRESEL", },	{ ESP_CMD_SA3, "SLCTATN3", },	{ ESP_CMD_RSEL3, "RESLCTSEQ", },	/* Target State Group */	{ ESP_CMD_SMSG, "SNDMSG", },	{ ESP_CMD_SSTAT, "SNDSTATUS", },	{ ESP_CMD_SDATA, "SNDDATA", },	{ ESP_CMD_DSEQ, "DISCSEQ", },	{ ESP_CMD_TSEQ, "TERMSEQ", },	{ ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", },	{ ESP_CMD_DCNCT, "DISC", },	{ ESP_CMD_RMSG, "RCVMSG", },	{ ESP_CMD_RCMD, "RCVCMD", },	{ ESP_CMD_RDATA, "RCVDATA", },	{ ESP_CMD_RCSEQ, "RCVCMDSEQ", },	/* Initiator State Group */	{ ESP_CMD_TI, "TRANSINFO", },	{ ESP_CMD_ICCSEQ, "INICMDSEQCOMP", },	{ ESP_CMD_MOK, "MSGACCEPTED", },	{ ESP_CMD_TPAD, "TPAD", },	{ ESP_CMD_SATN, "SATN", },	{ ESP_CMD_RATN, "RATN", },};#define NUM_ESP_COMMANDS  ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))/* Print textual representation of an ESP command */static inline void esp_print_cmd(unchar espcmd){	unchar dma_bit = espcmd & ESP_CMD_DMA;	int i;	espcmd &= ~dma_bit;	for(i=0; i<NUM_ESP_COMMANDS; i++)		if(esp_cmd_strings[i].cmdchar == espcmd)			break;	if(i==NUM_ESP_COMMANDS)		printk("ESP_Unknown");	else		printk("%s%s", esp_cmd_strings[i].text,		       ((dma_bit) ? "+DMA" : ""));}/* Print the status register's value */static inline void esp_print_statreg(unchar statreg){	unchar phase;	printk("STATUS<");	phase = statreg & ESP_STAT_PMASK;	printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :		       (phase == ESP_DIP ? "DATA-IN" :			(phase == ESP_CMDP ? "COMMAND" :			 (phase == ESP_STATP ? "STATUS" :			  (phase == ESP_MOP ? "MSG-OUT" :			   (phase == ESP_MIP ? "MSG_IN" :			    "unknown")))))));	if(statreg & ESP_STAT_TDONE)		printk("TRANS_DONE,");	if(statreg & ESP_STAT_TCNT)		printk("TCOUNT_ZERO,");	if(statreg & ESP_STAT_PERR)		printk("P_ERROR,");	if(statreg & ESP_STAT_SPAM)		printk("SPAM,");	if(statreg & ESP_STAT_INTR)		printk("IRQ,");	printk(">");}/* Print the interrupt register's value */static inline void esp_print_ireg(unchar intreg){	printk("INTREG< ");	if(intreg & ESP_INTR_S)		printk("SLCT_NATN ");	if(intreg & ESP_INTR_SATN)		printk("SLCT_ATN ");	if(intreg & ESP_INTR_RSEL)		printk("RSLCT ");	if(intreg & ESP_INTR_FDONE)		printk("FDONE ");	if(intreg & ESP_INTR_BSERV)		printk("BSERV ");	if(intreg & ESP_INTR_DC)		printk("DISCNCT ");	if(intreg & ESP_INTR_IC)		printk("ILL_CMD ");	if(intreg & ESP_INTR_SR)		printk("SCSI_BUS_RESET ");	printk(">");}/* Print the sequence step registers contents */static inline void esp_print_seqreg(unchar stepreg){	stepreg &= ESP_STEP_VBITS;	printk("STEP<%s>",	       (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" :		(stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :		 (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :		  (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :		   (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :		    "UNKNOWN"))))));}static char *phase_string(int phase){	switch(phase) {	case not_issued:		return "UNISSUED";	case in_slct_norm:		return "SLCTNORM";	case in_slct_stop:		return "SLCTSTOP";	case in_slct_msg:		return "SLCTMSG";	case in_slct_tag:		return "SLCTTAG";	case in_slct_sneg:		return "SLCTSNEG";	case in_datain:		return "DATAIN";	case in_dataout:		return "DATAOUT";	case in_data_done:		return "DATADONE";	case in_msgin:		return "MSGIN";	case in_msgincont:		return "MSGINCONT";	case in_msgindone:		return "MSGINDONE";	case in_msgout:		return "MSGOUT";	case in_msgoutdone:		return "MSGOUTDONE";	case in_cmdbegin:		return "CMDBEGIN";	case in_cmdend:		return "CMDEND";	case in_status:		return "STATUS";	case in_freeing:		return "FREEING";	case in_the_dark:		return "CLUELESS";	case in_abortone:		return "ABORTONE";	case in_abortall:		return "ABORTALL";	case in_resetdev:		return "RESETDEV";	case in_resetbus:		return "RESETBUS";	case in_tgterror:		return "TGTERROR";	default:		return "UNKNOWN";	};}#ifdef DEBUG_STATE_MACHINEstatic inline void esp_advance_phase(Scsi_Cmnd *s, int newphase){	ESPLOG(("<%s>", phase_string(newphase)));	s->SCp.sent_command = s->SCp.phase;	s->SCp.phase = newphase;}#else#define esp_advance_phase(__s, __newphase) \	(__s)->SCp.sent_command = (__s)->SCp.phase; \	(__s)->SCp.phase = (__newphase);#endif#ifdef DEBUG_ESP_CMDSextern inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,			   unchar cmd){	esp->espcmdlog[esp->espcmdent] = cmd;	esp->espcmdent = (esp->espcmdent + 1) & 31;	esp_write(eregs->esp_cmnd, cmd);}#else#define esp_cmd(__esp, __eregs, __cmd)	esp_write((__eregs)->esp_cmnd, (__cmd))#endif/* How we use the various Linux SCSI data structures for operation. * * struct scsi_cmnd: * *   We keep track of the syncronous capabilities of a target *   in the device member, using sync_min_period and *   sync_max_offset.  These are the values we directly write *   into the ESP registers while running a command.  If offset *   is zero the ESP will use asynchronous transfers. *   If the borken flag is set we assume we shouldn't even bother *   trying to negotiate for synchronous transfer as this target *   is really stupid.  If we notice the target is dropping the *   bus, and we have been allowing it to disconnect, we clear *   the disconnect flag. *//* Manipulation of the ESP command queues.  Thanks to the aha152x driver * and its author, Juergen E. Fischer, for the methods used here. * Note that these are per-ESP queues, not global queues like * the aha152x driver uses. */static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC){	Scsi_Cmnd *end;	new_SC->host_scribble = (unsigned char *) NULL;	if(!*SC)		*SC = new_SC;	else {		for(end=*SC;end->host_scribble;end=(Scsi_Cmnd *)end->host_scribble)			;		end->host_scribble = (unsigned char *) new_SC;	}}static inline void prepend_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC){	new_SC->host_scribble = (unsigned char *) *SC;	*SC = new_SC;}static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC){	Scsi_Cmnd *ptr;	ptr = *SC;	if(ptr)		*SC = (Scsi_Cmnd *) (*SC)->host_scribble;	return ptr;}static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun){	Scsi_Cmnd *ptr, *prev;	for(ptr = *SC, prev = NULL;	    ptr && ((ptr->target != target) || (ptr->lun != lun));	    prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble)		;	if(ptr) {		if(prev)			prev->host_scribble=ptr->host_scribble;		else			*SC=(Scsi_Cmnd *)ptr->host_scribble;	}	return ptr;}/* Resetting various pieces of the ESP scsi driver chipset *//* Reset the ESP chip, _not_ the SCSI bus. */static void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs){	int family_code, version, i;	volatile int trash;	/* Now reset the ESP chip */	esp_cmd(esp, eregs, ESP_CMD_RC);	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);	if(esp->erev == fast)		esp_write(eregs->esp_cfg2, ESP_CONFIG2_FENAB);	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);	/* This is the only point at which it is reliable to read	 * the ID-code for a fast ESP chip variant.	 */	esp->max_period = ((35 * esp->ccycle) / 1000);	if(esp->erev == fast) {		char *erev2string[] = {			"Emulex FAS236",			"Emulex FPESP100A",			"fast",			"QLogic FAS366",			"Emulex FAS216",			"Symbios Logic 53CF9x-2",			"unknown!"		};					version = esp_read(eregs->esp_uid);		family_code = (version & 0xf8) >> 3;		if(family_code == 0x02) {		        if ((version & 7) == 2)			        esp->erev = fas216;	                        else			        esp->erev = fas236;		} else if(family_code == 0x0a)			esp->erev = fas366; /* Version is usually '5'. */		else if(family_code == 0x00) {			if ((version & 7) == 2)				esp->erev = fas100a; /* NCR53C9X */			else				esp->erev = espunknown;		} else if(family_code == 0x14) {			if ((version & 7) == 2)				esp->erev = fsc;		        else				esp->erev = espunknown;		} else if(family_code == 0x00) {			if ((version & 7) == 2)				esp->erev = fas100a; /* NCR53C9X */			else				esp->erev = espunknown;		} else			esp->erev = espunknown;		ESPLOG(("esp%d: FAST chip is %s (family=%d, version=%d)\n",			esp->esp_id, erev2string[esp->erev - fas236],			family_code, (version & 7)));		esp->min_period = ((4 * esp->ccycle) / 1000);	} else {		esp->min_period = ((5 * esp->ccycle) / 1000);	}	/* Reload the configuration registers */	esp_write(eregs->esp_cfact, esp->cfact);	esp->prev_stp = 0;	esp_write(eregs->esp_stp, 0);	esp->prev_soff = 0;	esp_write(eregs->esp_soff, 0);	esp_write(eregs->esp_timeo, esp->neg_defp);	esp->max_period = (esp->max_period + 3)>>2;	esp->min_period = (esp->min_period + 3)>>2;	esp_write(eregs->esp_cfg1, esp->config1);	switch(esp->erev) {	case esp100:		/* nothing to do */		break;	case esp100a:		esp_write(eregs->esp_cfg2, esp->config2);		break;	case esp236:		/* Slow 236 */		esp_write(eregs->esp_cfg2, esp->config2);		esp->prev_cfg3 = esp->config3[0];		esp_write(eregs->esp_cfg3, esp->prev_cfg3);		break;	case fas366:		panic("esp: FAS366 support not present, please notify "		      "jongk@cs.utwente.nl");

⌨️ 快捷键说明

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