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

📄 isp.c

📁 基于组件方式开发操作系统的OSKIT源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $Id: isp.c,v 1.11.2.1 1999/05/11 05:47:40 mjacob Exp $ *//* release_5_11_99 *//* * Machine and OS Independent (well, as best as possible) * code for the Qlogic ISP SCSI adapters. * *--------------------------------------- * Copyright (c) 1997, 1998 by Matthew Jacob * NASA/Ames Research Center * All rights reserved. *--------------------------------------- * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice immediately at the beginning of the file, without modification, *    this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. *//* * Inspiration and ideas about this driver are from Erik Moe's Linux driver * (qlogicisp.c) and Dave Miller's SBus version of same (qlogicisp.c). Some * ideas dredged from the Solaris driver. *//* * Include header file appropriate for platform we're building on. */#ifdef	__NetBSD__#include <dev/ic/isp_netbsd.h>#endif#ifdef	__FreeBSD__#include <dev/isp/isp_freebsd.h>#endif#ifdef	__OpenBSD__#include <dev/ic/isp_openbsd.h>#endif#ifdef	__linux__#include "isp_linux.h"#endif/* * General defines */#define	MBOX_DELAY_COUNT	1000000 / 100/* * Local static data */#ifdef	ISP_TARGET_MODEstatic const char tgtiqd[36] = {	0x03, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,	0x51, 0x4C, 0x4F, 0x47, 0x49, 0x43, 0x20, 0x20,#ifdef	__NetBSD__	0x4E, 0x45, 0x54, 0x42, 0x53, 0x44, 0x20, 0x20,#else# ifdef	__FreeBSD__	0x46, 0x52, 0x45, 0x45, 0x42, 0x52, 0x44, 0x20,# else#  ifdef __OpenBSD__	0x4F, 0x50, 0x45, 0x4E, 0x42, 0x52, 0x44, 0x20,#  else#   ifdef linux	0x4C, 0x49, 0x4E, 0x55, 0x58, 0x20, 0x20, 0x20,#   else#   endif#  endif# endif#endif	0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x20, 0x20,	0x20, 0x20, 0x20, 0x31};#endif/* * Local function prototypes. */static int isp_parse_async __P((struct ispsoftc *, int));static int isp_handle_other_response__P((struct ispsoftc *, ispstatusreq_t *, u_int8_t *));#ifdef	ISP_TARGET_MODEstatic int isp_modify_lun __P((struct ispsoftc *, int, int, int));static void isp_notify_ack __P((struct ispsoftc *, void *));static void isp_handle_atio __P((struct ispsoftc *, void *));static void isp_handle_atio2 __P((struct ispsoftc *, void *));static void isp_handle_ctio __P((struct ispsoftc *, void *));static void isp_handle_ctio2 __P((struct ispsoftc *, void *));#endifstatic void isp_parse_status__P((struct ispsoftc *, ispstatusreq_t *, ISP_SCSI_XFER_T *));static void isp_fastpost_complete __P((struct ispsoftc *, int));static void isp_scsi_init __P((struct ispsoftc *));static void isp_scsi_channel_init __P((struct ispsoftc *, int));static void isp_fibre_init __P((struct ispsoftc *));static void isp_mark_getpdb_all __P((struct ispsoftc *));static int isp_getpdb __P((struct ispsoftc *, int, isp_pdb_t *));static int isp_fclink_test __P((struct ispsoftc *, int));static void isp_fw_state __P((struct ispsoftc *));static void isp_dumpregs __P((struct ispsoftc *, const char *));static void isp_dumpxflist __P((struct ispsoftc *));static void isp_mboxcmd __P((struct ispsoftc *, mbreg_t *));static void isp_update __P((struct ispsoftc *));static void isp_update_bus __P((struct ispsoftc *, int));static void isp_setdfltparm __P((struct ispsoftc *, int));static int isp_read_nvram __P((struct ispsoftc *));static void isp_rdnvram_word __P((struct ispsoftc *, int, u_int16_t *));/* * Reset Hardware. * * Hit the chip over the head, download new f/w and set it running. * * Locking done elsewhere. */voidisp_reset(isp)	struct ispsoftc *isp;{	mbreg_t mbs;	int loops, i, dodnld = 1;	char *revname;	isp->isp_state = ISP_NILSTATE;	/*	 * Basic types (SCSI, FibreChannel and PCI or SBus)	 * have been set in the MD code. We figure out more	 * here.	 */	isp->isp_dblev = DFLT_DBLEVEL;	/*	 * After we've fired this chip up, zero out the conf1 register	 * for SCSI adapters and other settings for the 2100.	 */	/*	 * Get the current running firmware revision out of the	 * chip before we hit it over the head (if this is our	 * first time through). Note that we store this as the	 * 'ROM' firmware revision- which it may not be. In any	 * case, we don't really use this yet, but we may in	 * the future.	 */	if (isp->isp_used == 0) {		/*		 * Just in case it was paused...		 */		ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);		mbs.param[0] = MBOX_ABOUT_FIRMWARE;		isp_mboxcmd(isp, &mbs);		/*		 * If this fails, it probably means we're running		 * an old prom, if anything at all...		 */		if (mbs.param[0] == MBOX_COMMAND_COMPLETE) {			isp->isp_romfw_rev[0] = mbs.param[1];			isp->isp_romfw_rev[1] = mbs.param[2];			isp->isp_romfw_rev[2] = mbs.param[3];		}		isp->isp_used = 1;	}	DISABLE_INTS(isp);	/*	 * Put it into PAUSE mode.	 */	ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);#if	0	/*	 * Do a little register testing.	 */	ISP_WRITE(isp, CDMA_COUNT, 0);	ISP_WRITE(isp, CDMA_ADDR0, 0xdead);	ISP_WRITE(isp, CDMA_ADDR1, 0xbeef);	ISP_WRITE(isp, CDMA_ADDR2, 0xffff);	ISP_WRITE(isp, CDMA_ADDR3, 0x1111);	PRINTF("%s: (0,dead,beef,ffff,1111):\n", isp->isp_name);	PRINTF("0x%x 0x%x 0x%x 0x%x 0x%x\n", ISP_READ(isp, CDMA_COUNT),	    ISP_READ(isp, CDMA_ADDR0), ISP_READ(isp, CDMA_ADDR1),	    ISP_READ(isp, CDMA_ADDR2), ISP_READ(isp, CDMA_ADDR3));#endif	if (IS_FC(isp)) {		revname = "2100";	} else if (IS_12X0(isp)) {		revname = "12X0";		isp->isp_clock = 60;	} else if (IS_1080(isp)) {		u_int16_t l;		sdparam *sdp = isp->isp_param;		revname = "1080";		isp->isp_clock = 100;		l = ISP_READ(isp, SXP_PINS_DIFF) & ISP1080_MODE_MASK;		switch (l) {		case ISP1080_LVD_MODE:			sdp->isp_lvdmode = 1;			PRINTF("%s: LVD Mode\n", isp->isp_name);			break;		case ISP1080_HVD_MODE:			sdp->isp_diffmode = 1;			PRINTF("%s: Differential Mode\n", isp->isp_name);			break;		case ISP1080_SE_MODE:			sdp->isp_ultramode = 1;			PRINTF("%s: Single-Ended Mode\n", isp->isp_name);			break;		default:			/*			 * Hmm. Up in a wierd mode. This means all SCSI I/O			 * buffer lines are tristated, so we're in a lot of			 * trouble if we don't set things up right.			 */			PRINTF("%s: Illegal Mode 0x%x\n", isp->isp_name, l);			break;		}	} else {		sdparam *sdp = isp->isp_param;		i = ISP_READ(isp, BIU_CONF0) & BIU_CONF0_HW_MASK;		switch (i) {		default:			PRINTF("%s: unknown chip rev. 0x%x- assuming a 1020\n",			    isp->isp_name, i);			/* FALLTHROUGH */		case 1:			revname = "1020";			isp->isp_type = ISP_HA_SCSI_1020;			isp->isp_clock = 40;			break;		case 2:			/*			 * Some 1020A chips are Ultra Capable, but don't			 * run the clock rate up for that unless told to			 * do so by the Ultra Capable bits being set.			 */			revname = "1020A";			isp->isp_type = ISP_HA_SCSI_1020A;			isp->isp_clock = 40;			break;		case 3:			revname = "1040";			isp->isp_type = ISP_HA_SCSI_1040;			isp->isp_clock = 60;			break;		case 4:			revname = "1040A";			isp->isp_type = ISP_HA_SCSI_1040A;			isp->isp_clock = 60;			break;		case 5:			revname = "1040B";			isp->isp_type = ISP_HA_SCSI_1040B;			isp->isp_clock = 60;			break;		case 6: 			revname = "1040C(?)";			isp->isp_type = ISP_HA_SCSI_1040C;			isp->isp_clock = 60;                        break; 		}		/*		 * Now, while we're at it, gather info about ultra		 * and/or differential mode.		 */		if (ISP_READ(isp, SXP_PINS_DIFF) & SXP_PINS_DIFF_MODE) {			PRINTF("%s: Differential Mode\n", isp->isp_name);			sdp->isp_diffmode = 1;		} else {			sdp->isp_diffmode = 0;		}		i = ISP_READ(isp, RISC_PSR);		if (isp->isp_bustype == ISP_BT_SBUS) {			i &= RISC_PSR_SBUS_ULTRA;		} else {			i &= RISC_PSR_PCI_ULTRA;		}		if (i != 0) {			PRINTF("%s: Ultra Mode Capable\n", isp->isp_name);			sdp->isp_ultramode = 1;			/*			 * If we're in Ultra Mode, we have to be 60Mhz clock-			 * even for the SBus version.			 */			isp->isp_clock = 60;		} else {			sdp->isp_ultramode = 0;			/*			 * Clock is known. Gronk.			 */		}		/*		 * Machine dependent clock (if set) overrides		 * our generic determinations.		 */		if (isp->isp_mdvec->dv_clock) {			if (isp->isp_mdvec->dv_clock < isp->isp_clock) {				isp->isp_clock = isp->isp_mdvec->dv_clock;			}		}	}	/*	 * Do MD specific pre initialization	 */	ISP_RESET0(isp);again:	/*	 * Hit the chip over the head with hammer,	 * and give the ISP a chance to recover.	 */	if (IS_SCSI(isp)) {		ISP_WRITE(isp, BIU_ICR, BIU_ICR_SOFT_RESET);		/*		 * A slight delay...		 */		SYS_DELAY(100);#if	0		PRINTF("%s: mbox0-5: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",		    isp->isp_name, ISP_READ(isp, OUTMAILBOX0),		    ISP_READ(isp, OUTMAILBOX1), ISP_READ(isp, OUTMAILBOX2),		    ISP_READ(isp, OUTMAILBOX3), ISP_READ(isp, OUTMAILBOX4),		    ISP_READ(isp, OUTMAILBOX5));#endif		/*		 * Clear data && control DMA engines.		 */		ISP_WRITE(isp, CDMA_CONTROL,		    DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT);		ISP_WRITE(isp, DDMA_CONTROL,		    DMA_CNTRL_CLEAR_CHAN | DMA_CNTRL_RESET_INT);	} else {		ISP_WRITE(isp, BIU2100_CSR, BIU2100_SOFT_RESET);		/*		 * A slight delay...		 */		SYS_DELAY(100);		/*		 * Clear data && control DMA engines.		 */		ISP_WRITE(isp, CDMA2100_CONTROL,			DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT);		ISP_WRITE(isp, TDMA2100_CONTROL,			DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT);		ISP_WRITE(isp, RDMA2100_CONTROL,			DMA_CNTRL2100_CLEAR_CHAN | DMA_CNTRL2100_RESET_INT);	}	/*	 * Wait for ISP to be ready to go...	 */	loops = MBOX_DELAY_COUNT;	for (;;) {		if (isp->isp_type & ISP_HA_SCSI) {			if (!(ISP_READ(isp, BIU_ICR) & BIU_ICR_SOFT_RESET))				break;		} else {			if (!(ISP_READ(isp, BIU2100_CSR) & BIU2100_SOFT_RESET))				break;		}		SYS_DELAY(100);		if (--loops < 0) {			isp_dumpregs(isp, "chip reset timed out");			return;		}	}	/*	 * After we've fired this chip up, zero out the conf1 register	 * for SCSI adapters and other settings for the 2100.	 */	if (IS_SCSI(isp)) {		ISP_WRITE(isp, BIU_CONF1, 0);	} else {		ISP_WRITE(isp, BIU2100_CSR, 0);	}	/*	 * Reset RISC Processor	 */	ISP_WRITE(isp, HCCR, HCCR_CMD_RESET);	SYS_DELAY(100);	/*	 * Establish some initial burst rate stuff.	 * (only for the 1XX0 boards). This really should	 * be done later after fetching from NVRAM.	 */	if (IS_SCSI(isp)) {		u_int16_t tmp = isp->isp_mdvec->dv_conf1;		/*		 * Busted FIFO. Turn off all but burst enables.		 */		if (isp->isp_type == ISP_HA_SCSI_1040A) {			tmp &= BIU_BURST_ENABLE;		}		ISP_SETBITS(isp, BIU_CONF1, tmp);		if (tmp & BIU_BURST_ENABLE) {			ISP_SETBITS(isp, CDMA_CONF, DMA_ENABLE_BURST);			ISP_SETBITS(isp, DDMA_CONF, DMA_ENABLE_BURST);		}#ifdef	PTI_CARDS		if (((sdparam *) isp->isp_param)->isp_ultramode) {			while (ISP_READ(isp, RISC_MTR) != 0x1313) {				ISP_WRITE(isp, RISC_MTR, 0x1313);				ISP_WRITE(isp, HCCR, HCCR_CMD_STEP);			}		} else {			ISP_WRITE(isp, RISC_MTR, 0x1212);		}		/*		 * PTI specific register		 */		ISP_WRITE(isp, RISC_EMB, DUAL_BANK)#else		ISP_WRITE(isp, RISC_MTR, 0x1212);#endif	} else {		ISP_WRITE(isp, RISC_MTR2100, 0x1212);	}	ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); /* release paused processor */	/*	 * Do MD specific post initialization	 */	ISP_RESET1(isp);#if	0	/*	 * Enable interrupts	 */	ENABLE_INTS(isp);#endif	/*	 * Wait for everything to finish firing up...	 */	loops = MBOX_DELAY_COUNT;	while (ISP_READ(isp, OUTMAILBOX0) == MBOX_BUSY) {		SYS_DELAY(100);		if (--loops < 0) {			PRINTF("%s: MBOX_BUSY never cleared on reset\n",			    isp->isp_name);			return;		}	}	/*	 * Up until this point we've done everything by just reading or	 * setting registers. From this point on we rely on at least *some*	 * kind of firmware running in the card.	 */	/*	 * Do some sanity checking.	 */	mbs.param[0] = MBOX_NO_OP;	isp_mboxcmd(isp, &mbs);	if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {		isp_dumpregs(isp, "NOP test failed");		return;	}	if (isp->isp_type & ISP_HA_SCSI) {		mbs.param[0] = MBOX_MAILBOX_REG_TEST;		mbs.param[1] = 0xdead;		mbs.param[2] = 0xbeef;		mbs.param[3] = 0xffff;		mbs.param[4] = 0x1111;		mbs.param[5] = 0xa5a5;		isp_mboxcmd(isp, &mbs);		if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {			isp_dumpregs(isp,

⌨️ 快捷键说明

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