?? isp.c
字號:
/* @(#)isp.c 1.67 *//* * Machine and OS Independent (well, as best as possible) * code for the Qlogic ISP SCSI adapters. * * Copyright (c) 1997, 1998, 1999, 2000, 2001 by Matthew Jacob * Feral Software * 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. 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#ifdef __svr4__#include "isp_solaris.h"#endif/* * General defines */#define MBOX_DELAY_COUNT 1000000 / 100/* * Local static data */static const char portshift[] = "Target %d Loop ID 0x%x (Port 0x%x) => Loop 0x%x (Port 0x%x)";static const char portdup[] = "Target %d duplicates Target %d- killing off both";static const char retained[] = "Retaining Loop ID 0x%x for Target %d (Port 0x%x)";static const char lretained[] = "Retained login of Target %d (Loop ID 0x%x) Port 0x%x";static const char plogout[] = "Logging out Target %d at Loop ID 0x%x (Port 0x%x)";static const char plogierr[] = "Command Error in PLOGI for Port 0x%x (0x%x)";static const char nopdb[] = "Could not get PDB for Device @ Port 0x%x";static const char pdbmfail1[] = "PDB Loop ID info for Device @ Port 0x%x does not match up (0x%x)";static const char pdbmfail2[] = "PDB Port info for Device @ Port 0x%x does not match up (0x%x)";static const char ldumped[] = "Target %d (Loop ID 0x%x) Port 0x%x dumped after login info mismatch";static const char notresp[] = "Not RESPONSE in RESPONSE Queue (type 0x%x) @ idx %d (next %d) nlooked %d";static const char xact1[] = "HBA attempted queued transaction with disconnect not set for %d.%d.%d";static const char xact2[] = "HBA attempted queued transaction to target routine %d on target %d bus %d";static const char xact3[] = "HBA attempted queued cmd for %d.%d.%d when queueing disabled";static const char pskip[] = "SCSI phase skipped for target %d.%d.%d";static const char topology[] = "Loop ID %d, AL_PA 0x%x, Port ID 0x%x, Loop State 0x%x, Topology '%s'";static const char swrej[] = "Fabric Nameserver rejected %s (Reason=0x%x Expl=0x%x) for Port ID 0x%x";static const char finmsg[] = "(%d.%d.%d): FIN dl%d resid %d STS 0x%x SKEY %c XS_ERR=0x%x";static const char sc0[] = "%s CHAN %d FTHRSH %d IID %d RESETD %d RETRYC %d RETRYD %d ASD 0x%x";static const char sc1[] = "%s RAAN 0x%x DLAN 0x%x DDMAB 0x%x CDMAB 0x%x SELTIME %d MQD %d";static const char sc2[] = "%s CHAN %d TGT %d FLAGS 0x%x 0x%x/0x%x";static const char sc3[] = "Generated";static const char sc4[] = "NVRAM";/* * Local function prototypes. */static int isp_parse_async(struct ispsoftc *, u_int16_t);static int isp_handle_other_response(struct ispsoftc *, int, isphdr_t *, u_int16_t *);static voidisp_parse_status(struct ispsoftc *, ispstatusreq_t *, XS_T *);static void isp_fastpost_complete(struct ispsoftc *, u_int16_t);static int isp_mbox_continue(struct ispsoftc *);static void isp_scsi_init(struct ispsoftc *);static void isp_scsi_channel_init(struct ispsoftc *, int);static void isp_fibre_init(struct ispsoftc *);static void isp_mark_getpdb_all(struct ispsoftc *);static int isp_getmap(struct ispsoftc *, fcpos_map_t *);static int isp_getpdb(struct ispsoftc *, int, isp_pdb_t *);static u_int64_t isp_get_portname(struct ispsoftc *, int, int);static int isp_fclink_test(struct ispsoftc *, int);static char *isp2100_fw_statename(int);static int isp_pdb_sync(struct ispsoftc *);static int isp_scan_loop(struct ispsoftc *);static int isp_fabric_mbox_cmd(struct ispsoftc *, mbreg_t *);static int isp_scan_fabric(struct ispsoftc *, int);static void isp_register_fc4_type(struct ispsoftc *);static void isp_fw_state(struct ispsoftc *);static void isp_mboxcmd_qnw(struct ispsoftc *, mbreg_t *, int);static void isp_mboxcmd(struct ispsoftc *, mbreg_t *, int);static void isp_update(struct ispsoftc *);static void isp_update_bus(struct ispsoftc *, int);static void isp_setdfltparm(struct ispsoftc *, int);static int isp_read_nvram(struct ispsoftc *);static void isp_rdnvram_word(struct ispsoftc *, int, u_int16_t *);static void isp_parse_nvram_1020(struct ispsoftc *, u_int8_t *);static void isp_parse_nvram_1080(struct ispsoftc *, int, u_int8_t *);static void isp_parse_nvram_12160(struct ispsoftc *, int, u_int8_t *);static void isp_parse_nvram_2100(struct ispsoftc *, u_int8_t *);/* * Reset Hardware. * * Hit the chip over the head, download new f/w if available and set it running. * * Locking done elsewhere. */voidisp_reset(struct ispsoftc *isp){ mbreg_t mbs; u_int16_t code_org; int loops, i, touched, dodnld = 1; char *btype = "????"; 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. Possibly more refined types based upon PCI * identification. Chip revision has been gathered. * * After we've fired this chip up, zero out the conf1 register * for SCSI adapters and do 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 ((touched = isp->isp_touched) == 0) { /* * First see whether or not we're sitting in the ISP PROM. * If we've just been reset, we'll have the string "ISP " * spread through outgoing mailbox registers 1-3. We do * this for PCI cards because otherwise we really don't * know what state the card is in and we could hang if * we try this command otherwise. * * For SBus cards, we just do this because they almost * certainly will be running firmware by now. */ if (ISP_READ(isp, OUTMAILBOX1) != 0x4953 || ISP_READ(isp, OUTMAILBOX2) != 0x5020 || ISP_READ(isp, OUTMAILBOX3) != 0x2020) { /* * Just in case it was paused... */ ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); mbs.param[0] = MBOX_ABOUT_FIRMWARE; isp_mboxcmd(isp, &mbs, MBLOGNONE); 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_touched = 1; } DISABLE_INTS(isp); /* * Set up default request/response queue in-pointer/out-pointer * register indices. */ if (IS_23XX(isp)) { isp->isp_rqstinrp = BIU_REQINP; isp->isp_rqstoutrp = BIU_REQOUTP; isp->isp_respinrp = BIU_RSPINP; isp->isp_respoutrp = BIU_RSPOUTP; } else { isp->isp_rqstinrp = INMAILBOX4; isp->isp_rqstoutrp = OUTMAILBOX4; isp->isp_respinrp = OUTMAILBOX5; isp->isp_respoutrp = INMAILBOX5; } /* * Put the board into PAUSE mode (so we can read the SXP registers * or write FPM/FBM registers). */ ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE); if (IS_FC(isp)) { switch (isp->isp_type) { case ISP_HA_FC_2100: btype = "2100"; break; case ISP_HA_FC_2200: btype = "2200"; break; case ISP_HA_FC_2300: btype = "2300"; break; case ISP_HA_FC_2312: btype = "2312"; break; default: break; } /* * While we're paused, reset the FPM module and FBM fifos. */ ISP_WRITE(isp, BIU2100_CSR, BIU2100_FPM0_REGS); ISP_WRITE(isp, FPM_DIAG_CONFIG, FPM_SOFT_RESET); ISP_WRITE(isp, BIU2100_CSR, BIU2100_FB_REGS); ISP_WRITE(isp, FBM_CMD, FBMCMD_FIFO_RESET_ALL); ISP_WRITE(isp, BIU2100_CSR, BIU2100_RISC_REGS); } else if (IS_1240(isp)) { sdparam *sdp = isp->isp_param; btype = "1240"; isp->isp_clock = 60; sdp->isp_ultramode = 1; sdp++; sdp->isp_ultramode = 1; /* * XXX: Should probably do some bus sensing. */ } else if (IS_ULTRA2(isp)) { static const char m[] = "bus %d is in %s Mode"; u_int16_t l; sdparam *sdp = isp->isp_param; isp->isp_clock = 100; if (IS_1280(isp)) btype = "1280"; else if (IS_1080(isp)) btype = "1080"; else if (IS_12160(isp)) btype = "12160"; else btype = "<UNKLVD>"; l = ISP_READ(isp, SXP_PINS_DIFF) & ISP1080_MODE_MASK; switch (l) { case ISP1080_LVD_MODE: sdp->isp_lvdmode = 1; isp_prt(isp, ISP_LOGCONFIG, m, 0, "LVD"); break; case ISP1080_HVD_MODE: sdp->isp_diffmode = 1; isp_prt(isp, ISP_LOGCONFIG, m, 0, "Differential"); break; case ISP1080_SE_MODE: sdp->isp_ultramode = 1; isp_prt(isp, ISP_LOGCONFIG, m, 0, "Single-Ended"); break; default: isp_prt(isp, ISP_LOGERR, "unknown mode on bus %d (0x%x)", 0, l); break; } if (IS_DUALBUS(isp)) { sdp++; l = ISP_READ(isp, SXP_PINS_DIFF|SXP_BANK1_SELECT); l &= ISP1080_MODE_MASK; switch(l) { case ISP1080_LVD_MODE: sdp->isp_lvdmode = 1; isp_prt(isp, ISP_LOGCONFIG, m, 1, "LVD"); break; case ISP1080_HVD_MODE: sdp->isp_diffmode = 1; isp_prt(isp, ISP_LOGCONFIG, m, 1, "Differential"); break; case ISP1080_SE_MODE: sdp->isp_ultramode = 1; isp_prt(isp, ISP_LOGCONFIG, m, 1, "Single-Ended"); break; default: isp_prt(isp, ISP_LOGERR, "unknown mode on bus %d (0x%x)", 1, l); break; } } } else { sdparam *sdp = isp->isp_param; i = ISP_READ(isp, BIU_CONF0) & BIU_CONF0_HW_MASK; switch (i) { default: isp_prt(isp, ISP_LOGALL, "Unknown Chip Type 0x%x", i); /* FALLTHROUGH */ case 1: btype = "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. */ btype = "1020A"; isp->isp_type = ISP_HA_SCSI_1020A; isp->isp_clock = 40; break; case 3: btype = "1040"; isp->isp_type = ISP_HA_SCSI_1040; isp->isp_clock = 60; break; case 4: btype = "1040A"; isp->isp_type = ISP_HA_SCSI_1040A; isp->isp_clock = 60; break; case 5: btype = "1040B"; isp->isp_type = ISP_HA_SCSI_1040B; isp->isp_clock = 60; break; case 6: btype = "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) { isp_prt(isp, ISP_LOGCONFIG, "Differential Mode"); 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) { isp_prt(isp, ISP_LOGCONFIG, "Ultra Mode Capable"); 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; } } } /* * Clear instrumentation */ isp->isp_intcnt = isp->isp_intbogus = 0; /* * 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... */ USEC_DELAY(100); /* * 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... */ USEC_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 (IS_SCSI(isp)) { if (!(ISP_READ(isp, BIU_ICR) & BIU_ICR_SOFT_RESET)) break; } else { if (!(ISP_READ(isp, BIU2100_CSR) & BIU2100_SOFT_RESET)) break; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -