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

📄 sym_hipd.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family  * of PCI-SCSI IO processors. * * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr> * Copyright (c) 2003-2005  Matthew Wilcox <matthew@wil.cx> * * This driver is derived from the Linux sym53c8xx driver. * Copyright (C) 1998-2000  Gerard Roudier * * The sym53c8xx driver is derived from the ncr53c8xx driver that had been  * a port of the FreeBSD ncr driver to Linux-1.2.13. * * The original ncr driver has been written for 386bsd and FreeBSD by *         Wolfgang Stanglmeier        <wolf@cologne.de> *         Stefan Esser                <se@mi.Uni-Koeln.de> * Copyright (C) 1994  Wolfgang Stanglmeier * * Other major contributions: * * NVRAM detection and reading. * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> * *----------------------------------------------------------------------------- * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */#include <linux/slab.h>#include <asm/param.h>		/* for timeouts in units of HZ */#include "sym_glue.h"#include "sym_nvram.h"#if 0#define SYM_DEBUG_GENERIC_SUPPORT#endif/* *  Needed function prototypes. */static void sym_int_ma (struct sym_hcb *np);static void sym_int_sir (struct sym_hcb *np);static struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np);static struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa);static void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln);static void sym_complete_error (struct sym_hcb *np, struct sym_ccb *cp);static void sym_complete_ok (struct sym_hcb *np, struct sym_ccb *cp);static int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp);/* *  Print a buffer in hexadecimal format with a ".\n" at end. */static void sym_printl_hex(u_char *p, int n){	while (n-- > 0)		printf (" %x", *p++);	printf (".\n");}/* *  Print out the content of a SCSI message. */static int sym_show_msg (u_char * msg){	u_char i;	printf ("%x",*msg);	if (*msg==M_EXTENDED) {		for (i=1;i<8;i++) {			if (i-1>msg[1]) break;			printf ("-%x",msg[i]);		}		return (i+1);	} else if ((*msg & 0xf0) == 0x20) {		printf ("-%x",msg[1]);		return (2);	}	return (1);}static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg){	sym_print_addr(cp->cmd, "%s: ", label);	sym_show_msg(msg);	printf(".\n");}static void sym_print_nego_msg(struct sym_hcb *np, int target, char *label, u_char *msg){	struct sym_tcb *tp = &np->target[target];	dev_info(&tp->starget->dev, "%s: ", label);	sym_show_msg(msg);	printf(".\n");}/* *  Print something that tells about extended errors. */void sym_print_xerr(struct scsi_cmnd *cmd, int x_status){	if (x_status & XE_PARITY_ERR) {		sym_print_addr(cmd, "unrecovered SCSI parity error.\n");	}	if (x_status & XE_EXTRA_DATA) {		sym_print_addr(cmd, "extraneous data discarded.\n");	}	if (x_status & XE_BAD_PHASE) {		sym_print_addr(cmd, "illegal scsi phase (4/5).\n");	}	if (x_status & XE_SODL_UNRUN) {		sym_print_addr(cmd, "ODD transfer in DATA OUT phase.\n");	}	if (x_status & XE_SWIDE_OVRUN) {		sym_print_addr(cmd, "ODD transfer in DATA IN phase.\n");	}}/* *  Return a string for SCSI BUS mode. */static char *sym_scsi_bus_mode(int mode){	switch(mode) {	case SMODE_HVD:	return "HVD";	case SMODE_SE:	return "SE";	case SMODE_LVD: return "LVD";	}	return "??";}/* *  Soft reset the chip. * *  Raising SRST when the chip is running may cause  *  problems on dual function chips (see below). *  On the other hand, LVD devices need some delay  *  to settle and report actual BUS mode in STEST4. */static void sym_chip_reset (struct sym_hcb *np){	OUTB(np, nc_istat, SRST);	INB(np, nc_mbox1);	udelay(10);	OUTB(np, nc_istat, 0);	INB(np, nc_mbox1);	udelay(2000);	/* For BUS MODE to settle */}/* *  Really soft reset the chip.:) * *  Some 896 and 876 chip revisions may hang-up if we set  *  the SRST (soft reset) bit at the wrong time when SCRIPTS  *  are running. *  So, we need to abort the current operation prior to  *  soft resetting the chip. */static void sym_soft_reset (struct sym_hcb *np){	u_char istat = 0;	int i;	if (!(np->features & FE_ISTAT1) || !(INB(np, nc_istat1) & SCRUN))		goto do_chip_reset;	OUTB(np, nc_istat, CABRT);	for (i = 100000 ; i ; --i) {		istat = INB(np, nc_istat);		if (istat & SIP) {			INW(np, nc_sist);		}		else if (istat & DIP) {			if (INB(np, nc_dstat) & ABRT)				break;		}		udelay(5);	}	OUTB(np, nc_istat, 0);	if (!i)		printf("%s: unable to abort current chip operation, "		       "ISTAT=0x%02x.\n", sym_name(np), istat);do_chip_reset:	sym_chip_reset(np);}/* *  Start reset process. * *  The interrupt handler will reinitialize the chip. */static void sym_start_reset(struct sym_hcb *np){	sym_reset_scsi_bus(np, 1);} int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int){	u32 term;	int retv = 0;	sym_soft_reset(np);	/* Soft reset the chip */	if (enab_int)		OUTW(np, nc_sien, RST);	/*	 *  Enable Tolerant, reset IRQD if present and 	 *  properly set IRQ mode, prior to resetting the bus.	 */	OUTB(np, nc_stest3, TE);	OUTB(np, nc_dcntl, (np->rv_dcntl & IRQM));	OUTB(np, nc_scntl1, CRST);	INB(np, nc_mbox1);	udelay(200);	if (!SYM_SETUP_SCSI_BUS_CHECK)		goto out;	/*	 *  Check for no terminators or SCSI bus shorts to ground.	 *  Read SCSI data bus, data parity bits and control signals.	 *  We are expecting RESET to be TRUE and other signals to be 	 *  FALSE.	 */	term =	INB(np, nc_sstat0);	term =	((term & 2) << 7) + ((term & 1) << 17);	/* rst sdp0 */	term |= ((INB(np, nc_sstat2) & 0x01) << 26) |	/* sdp1     */		((INW(np, nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */		((INW(np, nc_sbdl) & 0xff00) << 10) |	/* d15-8    */		INB(np, nc_sbcl);	/* req ack bsy sel atn msg cd io    */	if (!np->maxwide)		term &= 0x3ffff;	if (term != (2<<7)) {		printf("%s: suspicious SCSI data while resetting the BUS.\n",			sym_name(np));		printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "			"0x%lx, expecting 0x%lx\n",			sym_name(np),			(np->features & FE_WIDE) ? "dp1,d15-8," : "",			(u_long)term, (u_long)(2<<7));		if (SYM_SETUP_SCSI_BUS_CHECK == 1)			retv = 1;	}out:	OUTB(np, nc_scntl1, 0);	return retv;}/* *  Select SCSI clock frequency */static void sym_selectclock(struct sym_hcb *np, u_char scntl3){	/*	 *  If multiplier not present or not selected, leave here.	 */	if (np->multiplier <= 1) {		OUTB(np, nc_scntl3, scntl3);		return;	}	if (sym_verbose >= 2)		printf ("%s: enabling clock multiplier\n", sym_name(np));	OUTB(np, nc_stest1, DBLEN);	   /* Enable clock multiplier */	/*	 *  Wait for the LCKFRQ bit to be set if supported by the chip.	 *  Otherwise wait 50 micro-seconds (at least).	 */	if (np->features & FE_LCKFRQ) {		int i = 20;		while (!(INB(np, nc_stest4) & LCKFRQ) && --i > 0)			udelay(20);		if (!i)			printf("%s: the chip cannot lock the frequency\n",				sym_name(np));	} else {		INB(np, nc_mbox1);		udelay(50+10);	}	OUTB(np, nc_stest3, HSC);		/* Halt the scsi clock	*/	OUTB(np, nc_scntl3, scntl3);	OUTB(np, nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/	OUTB(np, nc_stest3, 0x00);		/* Restart scsi clock 	*/}/* *  Determine the chip's clock frequency. * *  This is essential for the negotiation of the synchronous  *  transfer rate. * *  Note: we have to return the correct value. *  THERE IS NO SAFE DEFAULT VALUE. * *  Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. *  53C860 and 53C875 rev. 1 support fast20 transfers but  *  do not have a clock doubler and so are provided with a  *  80 MHz clock. All other fast20 boards incorporate a doubler  *  and so should be delivered with a 40 MHz clock. *  The recent fast40 chips (895/896/895A/1010) use a 40 Mhz base  *  clock and provide a clock quadrupler (160 Mhz). *//* *  calculate SCSI clock frequency (in KHz) */static unsigned getfreq (struct sym_hcb *np, int gen){	unsigned int ms = 0;	unsigned int f;	/*	 * Measure GEN timer delay in order 	 * to calculate SCSI clock frequency	 *	 * This code will never execute too	 * many loop iterations (if DELAY is 	 * reasonably correct). It could get	 * too low a delay (too high a freq.)	 * if the CPU is slow executing the 	 * loop for some reason (an NMI, for	 * example). For this reason we will	 * if multiple measurements are to be 	 * performed trust the higher delay 	 * (lower frequency returned).	 */	OUTW(np, nc_sien, 0);	/* mask all scsi interrupts */	INW(np, nc_sist);	/* clear pending scsi interrupt */	OUTB(np, nc_dien, 0);	/* mask all dma interrupts */	INW(np, nc_sist);	/* another one, just to be sure :) */	/*	 * The C1010-33 core does not report GEN in SIST,	 * if this interrupt is masked in SIEN.	 * I don't know yet if the C1010-66 behaves the same way.	 */	if (np->features & FE_C10) {		OUTW(np, nc_sien, GEN);		OUTB(np, nc_istat1, SIRQD);	}	OUTB(np, nc_scntl3, 4);	   /* set pre-scaler to divide by 3 */	OUTB(np, nc_stime1, 0);	   /* disable general purpose timer */	OUTB(np, nc_stime1, gen);  /* set to nominal delay of 1<<gen * 125us */	while (!(INW(np, nc_sist) & GEN) && ms++ < 100000)		udelay(1000/4);    /* count in 1/4 of ms */	OUTB(np, nc_stime1, 0);    /* disable general purpose timer */	/*	 * Undo C1010-33 specific settings.	 */	if (np->features & FE_C10) {		OUTW(np, nc_sien, 0);		OUTB(np, nc_istat1, 0);	} 	/* 	 * set prescaler to divide by whatever 0 means 	 * 0 ought to choose divide by 2, but appears 	 * to set divide by 3.5 mode in my 53c810 ... 	 */ 	OUTB(np, nc_scntl3, 0);  	/* 	 * adjust for prescaler, and convert into KHz   	 */	f = ms ? ((1 << gen) * (4340*4)) / ms : 0;	/*	 * The C1010-33 result is biased by a factor 	 * of 2/3 compared to earlier chips.	 */	if (np->features & FE_C10)		f = (f * 2) / 3;	if (sym_verbose >= 2)		printf ("%s: Delay (GEN=%d): %u msec, %u KHz\n",			sym_name(np), gen, ms/4, f);	return f;}static unsigned sym_getfreq (struct sym_hcb *np){	u_int f1, f2;	int gen = 8;	getfreq (np, gen);	/* throw away first result */	f1 = getfreq (np, gen);	f2 = getfreq (np, gen);	if (f1 > f2) f1 = f2;		/* trust lower result	*/	return f1;}/* *  Get/probe chip SCSI clock frequency */static void sym_getclock (struct sym_hcb *np, int mult){	unsigned char scntl3 = np->sv_scntl3;	unsigned char stest1 = np->sv_stest1;	unsigned f1;	np->multiplier = 1;	f1 = 40000;	/*	 *  True with 875/895/896/895A with clock multiplier selected	 */	if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {		if (sym_verbose >= 2)			printf ("%s: clock multiplier found\n", sym_name(np));		np->multiplier = mult;	}	/*	 *  If multiplier not found or scntl3 not 7,5,3,	 *  reset chip and get frequency from general purpose timer.	 *  Otherwise trust scntl3 BIOS setting.	 */	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {		OUTB(np, nc_stest1, 0);		/* make sure doubler is OFF */		f1 = sym_getfreq (np);		if (sym_verbose)			printf ("%s: chip clock is %uKHz\n", sym_name(np), f1);		if	(f1 <	45000)		f1 =  40000;		else if (f1 <	55000)		f1 =  50000;		else				f1 =  80000;		if (f1 < 80000 && mult > 1) {			if (sym_verbose >= 2)				printf ("%s: clock multiplier assumed\n",					sym_name(np));			np->multiplier	= mult;		}	} else {		if	((scntl3 & 7) == 3)	f1 =  40000;		else if	((scntl3 & 7) == 5)	f1 =  80000;		else 				f1 = 160000;		f1 /= np->multiplier;	}	/*	 *  Compute controller synchronous parameters.	 */	f1		*= np->multiplier;	np->clock_khz	= f1;}/* *  Get/probe PCI clock frequency */static int sym_getpciclock (struct sym_hcb *np){	int f = 0;	/*	 *  For now, we only need to know about the actual 	 *  PCI BUS clock frequency for C1010-66 chips.	 */#if 1	if (np->features & FE_66MHZ) {#else	if (1) {#endif		OUTB(np, nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */		f = sym_getfreq(np);		OUTB(np, nc_stest1, 0);	}	np->pciclk_khz = f;	return f;}/* *  SYMBIOS chip clock divisor table. * *  Divisors are multiplied by 10,000,000 in order to make  *  calculations more simple. */#define _5M 5000000static u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};/* *  Get clock factor and sync divisor for a given  *  synchronous factor period. */static int sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fakp){	u32	clk = np->clock_khz;	/* SCSI clock frequency in kHz	*/	int	div = np->clock_divn;	/* Number of divisors supported	*/	u32	fak;			/* Sync factor in sxfer		*/	u32	per;			/* Period in tenths of ns	*/

⌨️ 快捷键说明

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