?? isp.c
字號(hào):
/* $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,
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -