From: <vl...@us...> - 2007-06-25 16:32:57
|
Revision: 135 http://svn.sourceforge.net/scst/?rev=135&view=rev Author: vlnb Date: 2007-06-25 09:32:46 -0700 (Mon, 25 Jun 2007) Log Message: ----------- Patch from Stanislaw Gruszka <sta...@op...> This is SCST driver for ISP Qlogic chipsets commonly used in many SCSI and FC host bus adapters. Supported chipset are listed in README file, incomplete list of supported HBA's is in doc/Hardware.txt . It is based on Matthew Jacob's multiplatform driver for ISP chipsets, which can be download from ftp://ftp.feral.com/pub/isp/isp_dist.tgz Added Paths: ----------- trunk/qla_isp/ trunk/qla_isp/LICENSE trunk/qla_isp/Makefile trunk/qla_isp/README trunk/qla_isp/README.scst trunk/qla_isp/common/ trunk/qla_isp/common/isp.c trunk/qla_isp/common/isp_library.c trunk/qla_isp/common/isp_library.h trunk/qla_isp/common/isp_stds.h trunk/qla_isp/common/isp_target.c trunk/qla_isp/common/isp_target.h trunk/qla_isp/common/isp_tpublic.h trunk/qla_isp/common/ispmbox.h trunk/qla_isp/common/ispreg.h trunk/qla_isp/common/ispvar.h trunk/qla_isp/doc/ trunk/qla_isp/doc/DriverManual.txt trunk/qla_isp/doc/Hardware.txt trunk/qla_isp/firmware/ trunk/qla_isp/firmware/asm_1000.h trunk/qla_isp/firmware/asm_1040.h trunk/qla_isp/firmware/asm_1080.h trunk/qla_isp/firmware/asm_12160.h trunk/qla_isp/firmware/asm_2100.h trunk/qla_isp/firmware/asm_2200.h trunk/qla_isp/firmware/asm_2300.h trunk/qla_isp/firmware/asm_2322.h trunk/qla_isp/firmware/asm_2400.h trunk/qla_isp/linux/ trunk/qla_isp/linux/LINUX_BUILD_INSTRUCTIONS trunk/qla_isp/linux/LINUX_TARGET_MODE_HOWTO trunk/qla_isp/linux/Makefile trunk/qla_isp/linux/Makefile.alpha trunk/qla_isp/linux/Makefile.i386 trunk/qla_isp/linux/Makefile.ppc trunk/qla_isp/linux/Makefile.sparc trunk/qla_isp/linux/Makefile.sparc64 trunk/qla_isp/linux/Makefile.x86_64 trunk/qla_isp/linux/exioct.h trunk/qla_isp/linux/exioctln.h trunk/qla_isp/linux/isp_cb_ops.c trunk/qla_isp/linux/isp_ioctl.h trunk/qla_isp/linux/isp_linux.c trunk/qla_isp/linux/isp_linux.h trunk/qla_isp/linux/isp_pci.c trunk/qla_isp/linux/isp_scst.c trunk/qla_isp/linux/scsi_target.c trunk/qla_isp/linux/scsi_target.h trunk/qla_isp/linux/scsi_target_ctl.c trunk/qla_isp/linux-2.6/ trunk/qla_isp/linux-2.6/Makefile trunk/qla_isp/linux-2.6/build/ trunk/qla_isp/linux-2.6/build/Makefile Added: trunk/qla_isp/LICENSE =================================================================== --- trunk/qla_isp/LICENSE (rev 0) +++ trunk/qla_isp/LICENSE 2007-06-25 16:32:46 UTC (rev 135) @@ -0,0 +1,53 @@ +Copyright (c) 1997-2007 by Matthew Jacob +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, 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. + +THIS SOFTWARE IS PROVIDED BY 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 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. + + +Alternatively, this software may be distributed under the terms of the +the GNU Public License ("GPL") with platforms where the prevalant license +is the GNU Public License: + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + +Matthew Jacob +Feral Software +421 Laurel Avenue +Menlo Park, CA 94025 +USA + +gplbsd at feral com + Added: trunk/qla_isp/Makefile =================================================================== --- trunk/qla_isp/Makefile (rev 0) +++ trunk/qla_isp/Makefile 2007-06-25 16:32:46 UTC (rev 135) @@ -0,0 +1,15 @@ +ifndef KDIR +KDIR := /lib/modules/$(shell uname -r)/build +endif + +export KDIR + +all: + $(MAKE) -C linux-2.6 tgt + +clean: + $(MAKE) -C linux-2.6 clean + +install: + $(MAKE) -C linux-2.6 install + Added: trunk/qla_isp/README =================================================================== --- trunk/qla_isp/README (rev 0) +++ trunk/qla_isp/README 2007-06-25 16:32:46 UTC (rev 135) @@ -0,0 +1,30 @@ +$Id: README,v 1.30 2007/03/05 19:10:52 mjacob Exp $ +------------------------------------------------------------------------------ + +Supported Cards: + +SBus ISP1000 && ISP1000U +PCI SCSI ISP1020 +PCI Ultra SCSI ISP1040, ISP1240 (dual bus) +PCI Ultra2 SCSI ISP1080, ISP1280 (dual bus) +PCI Ultra3 SCSI ISP12160 (dual bus) +PCI Fibre Channel + 1-Gbit: + ISP2100, ISP2102 + ISP2200, ISP2202, ISP2204 + + 2-Gbit: + ISP2300, ISP2312, ISP2324, 2340, 2342 + ISP2322, ISP6322 + ISP200 + 4-Gbit: + ISP2422, ISP2432 + +You should note that some old non-Qlogic (or very old Qlogic) 2100 cards may +have trouble loading firmware. The newer f/w for 2100s is > 0x8000 words, +which PROM code on some cards has trouble loading- define the token +USE_SMALLER_2100_FIRMWARE to select 1.15.37 f/w for the 2100. + +For 23XX (but not 2322) 2K Login firmware is available and is recommended. + +------------------------------------------------------------------------------ Added: trunk/qla_isp/README.scst =================================================================== --- trunk/qla_isp/README.scst (rev 0) +++ trunk/qla_isp/README.scst 2007-06-25 16:32:46 UTC (rev 135) @@ -0,0 +1,48 @@ +WARNING: This driver is not finished, USE ONLY FOR TESTING. + +This is SCST driver for ISP Qlogic chipsets commonly used in many SCSI and FC +host bus adapters. Supported chipset are listed in README file, incomplete +list of supported HBA's is in doc/Hardware.txt . + +It is based on Matthew Jacob's multiplatform driver for ISP chipsets, +which can be download from ftp://ftp.feral.com/pub/isp/isp_dist.tgz. The +update for SCST was made and supported by Stanislaw Gruszka +<sta...@op...>. + +Driver operate same hardware as qla2x00tgt, but have one adventage over it: +support of 24xx series of Qlogic adapters. + +INSTALLATION: + +Build driver with command +$ make +Then install isp_mod, isp_scst modules +$ make install + +Other Qlogic drivers can not coexist in system, unload all other qla modules + +$ rmmod qla2x00tgt +$ rmmod qla2400 +$ rmmod qla2300 +$ rmmod qla2200 +$ rmmod qla2xxx + +Load isp modules + +$ modprobe isp_scst +$ modprobe isp_mod + +Enable all logical units to work in target mode + +$ echo 1 > /proc/scsi_tgt/qla_isp/0 + +(to unload isp_mod.ko module you must write 0 to this file). +This is not switching target/initiator role. If you have more then one device, +role of each you can set using isp_roles parameter, like in example: + +$ modprobe isp_mode isp_roles="b0300=initiator" + +Magic number "b0300" is DEVID value, which you can find in /proc/scsi/isp/X + +To attach logical units continue with normal SCST setup + Added: trunk/qla_isp/common/isp.c =================================================================== --- trunk/qla_isp/common/isp.c (rev 0) +++ trunk/qla_isp/common/isp.c 2007-06-25 16:32:46 UTC (rev 135) @@ -0,0 +1,8340 @@ +/* $Id: isp.c,v 1.166 2007/06/01 17:19:31 mjacob Exp $ */ +/*- + * Copyright (c) 1997-2007 by Matthew Jacob + * 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, 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. + * + * THIS SOFTWARE IS PROVIDED BY 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 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. + * + * + * Alternatively, this software may be distributed under the terms of the + * the GNU Public License ("GPL") with platforms where the prevalant license + * is the GNU Public License: + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * Matthew Jacob + * Feral Software + * 421 Laurel Avenue + * Menlo Park, CA 94025 + * USA + * + * gplbsd at feral com + */ + +/* + * Machine and OS Independent (well, as best as possible) + * code for the Qlogic ISP SCSI and FC-SCSI adapters. + */ + +/* + * 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 <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD$"); +#include <dev/ic/isp_netbsd.h> +#endif +#ifdef __FreeBSD__ +#include <sys/cdefs.h> +__FBSDID("$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 +#define ISP_MARK_PORTDB(a, b, c) \ + isp_prt(isp, ISP_LOGSANCFG, "line %d: markportdb", __LINE__); \ + isp_mark_portdb(a, b, c) + +/* + * Local static data + */ +static const char fconf[] = + "PortDB[%d] changed:\n current =(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)\n" + " database=(0x%x@0x%06x 0x%08x%08x 0x%08x%08x)"; +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[] = + "HBA PortID 0x%06x N-Port Handle %d, Connection Topology '%s'"; +static const char ourwwn[] = + "HBA WWNN 0x%08x%08x HBA WWPN 0x%08x%08x"; +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"; +static const char bun[] = + "bad underrun for %d.%d (count %d, resid %d, status %s)"; + +/* + * Local function prototypes. + */ +static int isp_parse_async(ispsoftc_t *, uint16_t); +static int isp_handle_other_response(ispsoftc_t *, int, isphdr_t *, + uint32_t *); +static void +isp_parse_status(ispsoftc_t *, ispstatusreq_t *, XS_T *, long *); +static void +isp_parse_status_24xx(ispsoftc_t *, isp24xx_statusreq_t *, XS_T *, long *); +static void isp_fastpost_complete(ispsoftc_t *, uint16_t); +static int isp_mbox_continue(ispsoftc_t *); +static void isp_scsi_init(ispsoftc_t *); +static void isp_scsi_channel_init(ispsoftc_t *, int); +static void isp_fibre_init(ispsoftc_t *, int); +static void isp_fibre_init_2400(ispsoftc_t *, int); +static void isp_mark_portdb(ispsoftc_t *, int, int); +static int isp_plogx(ispsoftc_t *, int, uint16_t, uint32_t, int, int); +static int isp_port_login(ispsoftc_t *, uint16_t, uint32_t); +static int isp_port_logout(ispsoftc_t *, uint16_t, uint32_t); +static int isp_getpdb(ispsoftc_t *, int, uint16_t, isp_pdb_t *, int); +static uint64_t isp_get_portname(ispsoftc_t *, int, int, int); +static int isp_fclink_test(ispsoftc_t *, int, int); +static const char *ispfc_fw_statename(int); +static int isp_pdb_sync(ispsoftc_t *, int); +static int isp_scan_loop(ispsoftc_t *, int); +static int isp_gid_ft_sns(ispsoftc_t *, int); +static int isp_gid_ft_ct_passthru(ispsoftc_t *, int); +static int isp_scan_fabric(ispsoftc_t *, int); +static int isp_login_device(ispsoftc_t *, int, uint32_t, isp_pdb_t *, uint16_t *); +static int isp_register_fc4_type(ispsoftc_t *, int); +static int isp_register_fc4_type_24xx(ispsoftc_t *, int); +static uint16_t isp_nxt_handle(ispsoftc_t *, int, uint16_t); +static void isp_fw_state(ispsoftc_t *, int); +static void isp_mboxcmd_qnw(ispsoftc_t *, mbreg_t *, int); +static void isp_mboxcmd(ispsoftc_t *, mbreg_t *); + +static void isp_update(ispsoftc_t *); +static void isp_update_bus(ispsoftc_t *, int); +static void isp_setdfltparm(ispsoftc_t *, int); +static void isp_setdfltfcparm(ispsoftc_t *, int); +static int isp_read_nvram(ispsoftc_t *); +static int isp_read_nvram_2400(ispsoftc_t *, uint8_t *); +static void isp_rdnvram_word(ispsoftc_t *, int, uint16_t *); +static void isp_rd_2400_nvram(ispsoftc_t *, uint32_t, uint32_t *); +static void isp_parse_nvram_1020(ispsoftc_t *, uint8_t *); +static void isp_parse_nvram_1080(ispsoftc_t *, int, uint8_t *); +static void isp_parse_nvram_12160(ispsoftc_t *, int, uint8_t *); +static void isp_fix_nvram_wwns(ispsoftc_t *, int); +static void isp_parse_nvram_2100(ispsoftc_t *, uint8_t *); +static void isp_parse_nvram_2400(ispsoftc_t *, uint8_t *); + +/* + * Reset Hardware. + * + * Hit the chip over the head, download new f/w if available and set it running. + * + * Locking done elsewhere. + */ + +void +isp_reset(ispsoftc_t *isp) +{ + mbreg_t mbs; + uint32_t code_org, val; + int loops, i, dodnld = 1; + static const char *btype = "????"; + static const char dcrc[] = "Downloaded RISC Code Checksum Failure"; + + 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 (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... + */ + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, + HCCR_2400_CMD_RELEASE); + } else { + ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); + } + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_ABOUT_FIRMWARE; + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + 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; + } + + ISP_DISABLE_INTS(isp); + + /* + * Pick an initial maxcmds value which will be used + * to allocate xflist pointer space. It may be changed + * later by the firmware. + */ + if (IS_24XX(isp)) { + isp->isp_maxcmds = 4096; + } else if (IS_2322(isp)) { + isp->isp_maxcmds = 2048; + } else if (IS_23XX(isp) || IS_2200(isp)) { + isp->isp_maxcmds = 1024; + } else { + isp->isp_maxcmds = 512; + } + + /* + * Set up DMA for the request and result queues. + * + * We do this now so we can use the request queue + * for a dma + */ + if (ISP_MBOXDMASETUP(isp) != 0) { + isp_prt(isp, ISP_LOGERR, "Cannot setup DMA"); + return; + } + + + /* + * Set up default request/response queue in-pointer/out-pointer + * register indices. + */ + if (IS_24XX(isp)) { + isp->isp_rqstinrp = BIU2400_REQINP; + isp->isp_rqstoutrp = BIU2400_REQOUTP; + isp->isp_respinrp = BIU2400_RSPINP; + isp->isp_respoutrp = BIU2400_RSPOUTP; + isp->isp_atioinrp = BIU2400_ATIO_RSPINP; + isp->isp_atiooutrp = BIU2400_ATIO_REQINP; + } else 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). + */ + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_HOST_INT); + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT); + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_PAUSE); + } else { + 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; + case ISP_HA_FC_2322: + btype = "2322"; + break; + case ISP_HA_FC_2400: + btype = "2422"; + break; + default: + break; + } + + if (!IS_24XX(isp)) { + /* + * 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; + + btype = "1240"; + isp->isp_clock = 60; + sdp = SDPARAM(isp, 0); + sdp->isp_ultramode = 1; + sdp = SDPARAM(isp, 1); + 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"; + uint16_t l; + sdparam *sdp = SDPARAM(isp, 0); + + isp->isp_clock = 100; + + if (IS_1280(isp)) + btype = "1280"; + else if (IS_1080(isp)) + btype = "1080"; + else if (IS_10160(isp)) + btype = "10160"; + 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 = SDPARAM(isp, 1); + 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 = SDPARAM(isp, 0); + 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); + + /* + * 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 if (IS_24XX(isp)) { + /* + * Stop DMA and wait for it to stop. + */ + ISP_WRITE(isp, BIU2400_CSR, BIU2400_DMA_STOP|(3 << 4)); + for (val = loops = 0; loops < 30000; loops++) { + USEC_DELAY(10); + val = ISP_READ(isp, BIU2400_CSR); + if ((val & BIU2400_DMA_ACTIVE) == 0) { + break; + } + } + if (val & BIU2400_DMA_ACTIVE) { + ISP_RESET0(isp); + isp_prt(isp, ISP_LOGERR, "DMA Failed to Stop on Reset"); + return; + } + /* + * Hold it in SOFT_RESET and STOP state for 100us. + */ + ISP_WRITE(isp, BIU2400_CSR, + BIU2400_SOFT_RESET|BIU2400_DMA_STOP|(3 << 4)); + USEC_DELAY(100); + for (loops = 0; loops < 10000; loops++) { + USEC_DELAY(5); + val = ISP_READ(isp, OUTMAILBOX0); + } + for (val = loops = 0; loops < 500000; loops ++) { + val = ISP_READ(isp, BIU2400_CSR); + if ((val & BIU2400_SOFT_RESET) == 0) { + break; + } + } + if (val & BIU2400_SOFT_RESET) { + ISP_RESET0(isp); + isp_prt(isp, ISP_LOGERR, "Failed to come out of reset"); + return; + } + } 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 (IS_24XX(isp)) { + if (ISP_READ(isp, OUTMAILBOX0) == 0) { + break; + } + } else { + if (!(ISP_READ(isp, BIU2100_CSR) & BIU2100_SOFT_RESET)) + break; + } + USEC_DELAY(100); + if (--loops < 0) { + ISP_DUMPREGS(isp, "chip reset timed out"); + ISP_RESET0(isp); + 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 if (!IS_24XX(isp)) { + ISP_WRITE(isp, BIU2100_CSR, 0); + } + + /* + * Reset RISC Processor + */ + if (IS_24XX(isp)) { + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RESET); + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_RELEASE); + ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RESET); + } else { + ISP_WRITE(isp, HCCR, HCCR_CMD_RESET); + USEC_DELAY(100); + ISP_WRITE(isp, BIU_SEMA, 0); + } + + + /* + * Post-RISC Reset stuff. + */ + if (IS_24XX(isp)) { + for (val = loops = 0; loops < 5000000; loops++) { + USEC_DELAY(5); + val = ISP_READ(isp, OUTMAILBOX0); + if (val == 0) { + break; + } + } + if (val != 0) { + ISP_RESET0(isp); + isp_prt(isp, ISP_LOGERR, "reset didn't clear"); + return; + } + } else if (IS_SCSI(isp)) { + uint16_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); + } + if (SDPARAM(isp, 0)->isp_ptisp) { + if (SDPARAM(isp, 0)->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); + } + ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); + } else { + ISP_WRITE(isp, RISC_MTR2100, 0x1212); + if (IS_2200(isp) || IS_23XX(isp)) { + ISP_WRITE(isp, HCCR, HCCR_2X00_DISABLE_PARITY_PAUSE); + } + ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE); + } + + ISP_WRITE(isp, isp->isp_rqstinrp, 0); + ISP_WRITE(isp, isp->isp_rqstoutrp, 0); + ISP_WRITE(isp, isp->isp_respinrp, 0); + ISP_WRITE(isp, isp->isp_respoutrp, 0); + + + /* + * Do MD specific post initialization + */ + ISP_RESET1(isp); + + /* + * Wait for everything to finish firing up. + * + * Avoid doing this on the 2312 because you can generate a PCI + * parity error (chip breakage). + */ + if (IS_2312(isp)) { + USEC_DELAY(100); + } else { + loops = MBOX_DELAY_COUNT; + while (ISP_READ(isp, OUTMAILBOX0) == MBOX_BUSY) { + USEC_DELAY(100); + if (--loops < 0) { + ISP_RESET0(isp); + isp_prt(isp, ISP_LOGERR, + "MBOX_BUSY never cleared on reset"); + 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. + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_NO_OP; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + ISP_RESET0(isp); + return; + } + + if (IS_SCSI(isp) || IS_24XX(isp)) { + MEMZERO(&mbs, sizeof (mbs)); + 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; + mbs.param[6] = 0x0000; + mbs.param[7] = 0x0000; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + ISP_RESET0(isp); + return; + } + if (mbs.param[1] != 0xdead || mbs.param[2] != 0xbeef || + mbs.param[3] != 0xffff || mbs.param[4] != 0x1111 || + mbs.param[5] != 0xa5a5) { + ISP_RESET0(isp); + isp_prt(isp, ISP_LOGERR, + "Register Test Failed (0x%x 0x%x 0x%x 0x%x 0x%x)", + mbs.param[1], mbs.param[2], mbs.param[3], + mbs.param[4], mbs.param[5]); + return; + } + + } + + /* + * Download new Firmware, unless requested not to do so. + * This is made slightly trickier in some cases where the + * firmware of the ROM revision is newer than the revision + * compiled into the driver. So, where we used to compare + * versions of our f/w and the ROM f/w, now we just see + * whether we have f/w at all and whether a config flag + * has disabled our download. + */ + if ((isp->isp_mdvec->dv_ispfw == NULL) || + (isp->isp_confopts & ISP_CFG_NORELOAD)) { + dodnld = 0; + } + + if (IS_24XX(isp)) { + code_org = ISP_CODE_ORG_2400; + } else if (IS_23XX(isp)) { + code_org = ISP_CODE_ORG_2300; + } else { + code_org = ISP_CODE_ORG; + } + + if (dodnld && IS_24XX(isp)) { + const uint32_t *ptr = isp->isp_mdvec->dv_ispfw; + + /* + * NB: Whatever you do do, do *not* issue the VERIFY FIRMWARE + * NB: command to the 2400 while loading new firmware. This + * NB: causes the new f/w to start and immediately crash back + * NB: to the ROM. + */ + + /* + * Keep loading until we run out of f/w. + */ + code_org = ptr[2]; /* 1st load address is our start addr */ + + for (;;) { + uint32_t la, wi, wl; + + isp_prt(isp, ISP_LOGDEBUG0, + "load 0x%x words of code at load address 0x%x", + ptr[3], ptr[2]); + + wi = 0; + la = ptr[2]; + wl = ptr[3]; + + while (wi < ptr[3]) { + uint32_t *cp; + uint32_t nw; + + nw = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) >> 2; + if (nw > wl) { + nw = wl; + } + cp = isp->isp_rquest; + for (i = 0; i < nw; i++) { + cp[i] = ptr[wi++]; + wl--; + } + MEMORYBARRIER(isp, SYNC_REQUEST, + 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp))); + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_LOAD_RISC_RAM; + mbs.param[1] = la; + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[4] = nw >> 16; + mbs.param[5] = nw; + mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); + mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); + mbs.param[8] = la >> 16; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, + "F/W Risc Ram Load Failed"); + ISP_RESET0(isp); + return; + } + la += nw; + } + + if (ptr[1] == 0) { + break; + } + ptr += ptr[3]; + } + isp->isp_loaded_fw = 1; + } else if (dodnld && IS_23XX(isp)) { + const uint16_t *ptr = isp->isp_mdvec->dv_ispfw; + uint16_t wi, wl, segno; + uint32_t la; + + la = code_org; + segno = 0; + + for (;;) { + uint32_t nxtaddr; + + isp_prt(isp, ISP_LOGDEBUG0, + "load 0x%x words of code at load address 0x%x", + ptr[3], la); + + wi = 0; + wl = ptr[3]; + + while (wi < ptr[3]) { + uint16_t *cp; + uint32_t nw; + + nw = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp)) >> 1; + if (nw > wl) { + nw = wl; + } + if (nw > (1 << 15)) { + nw = 1 << 15; + } + cp = isp->isp_rquest; + for (i = 0; i < nw; i++) { + cp[i] = ptr[wi++]; + wl--; + } + MEMORYBARRIER(isp, SYNC_REQUEST, + 0, ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp))); + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_LOAD_RISC_RAM; + mbs.param[1] = la; + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[4] = nw; + mbs.param[6] = DMA_WD3(isp->isp_rquest_dma); + mbs.param[7] = DMA_WD2(isp->isp_rquest_dma); + mbs.param[8] = la >> 16; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, + "F/W Risc Ram Load Failed"); + ISP_RESET0(isp); + return; + } + la += nw; + } + + if (!IS_2322(isp)) { + /* + * Verify that it downloaded correctly. + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_VERIFY_CHECKSUM; + mbs.param[1] = code_org; + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, dcrc); + ISP_RESET0(isp); + return; + } + break; + } + + if (++segno == 3) { + break; + } + + /* + * If we're a 2322, the firmware actually comes in + * three chunks. We loaded the first at the code_org + * address. The other two chunks, which follow right + * after each other in memory here, get loaded at + * addresses specfied at offset 0x9..0xB. + */ + + nxtaddr = ptr[3]; + ptr = &ptr[nxtaddr]; + la = ptr[5] | ((ptr[4] & 0x3f) << 16); + } + isp->isp_loaded_fw = 1; + } else if (dodnld) { + union { + const uint16_t *cp; + uint16_t *np; + } u; + u.cp = isp->isp_mdvec->dv_ispfw; + isp->isp_mbxworkp = &u.np[1]; + isp->isp_mbxwrk0 = u.np[3] - 1; + isp->isp_mbxwrk1 = code_org + 1; + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_WRITE_RAM_WORD; + mbs.param[1] = code_org; + mbs.param[2] = u.np[0]; + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, + "F/W download failed at word %d", + isp->isp_mbxwrk1 - code_org); + ISP_RESET0(isp); + return; + } + /* + * Verify that it downloaded correctly. + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_VERIFY_CHECKSUM; + mbs.param[1] = code_org; + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, dcrc); + ISP_RESET0(isp); + return; + } + isp->isp_loaded_fw = 1; + } else { + isp->isp_loaded_fw = 0; + isp_prt(isp, ISP_LOGDEBUG2, "skipping f/w download"); + } + + /* + * Now start it rolling. + * + * If we didn't actually download f/w, + * we still need to (re)start it. + */ + + + MEMZERO(&mbs, sizeof (mbs)); + mbs.timeout = 1000000; + mbs.param[0] = MBOX_EXEC_FIRMWARE; + if (IS_24XX(isp)) { + mbs.param[1] = code_org >> 16; + mbs.param[2] = code_org; + if (isp->isp_loaded_fw) { + mbs.param[3] = 0; + } else { + mbs.param[3] = 1; + } + } else if (IS_2322(isp)) { + mbs.param[1] = code_org; + if (isp->isp_loaded_fw) { + mbs.param[2] = 0; + } else { + mbs.param[2] = 1; + } + } else { + mbs.param[1] = code_org; + } + + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (IS_2322(isp) || IS_24XX(isp)) { + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + ISP_RESET0(isp); + return; + } + } + + /* + * Give it a chance to finish starting up. + */ + USEC_DELAY(250000); + + if (IS_SCSI(isp)) { + /* + * Set CLOCK RATE, but only if asked to. + */ + if (isp->isp_clock) { + mbs.param[0] = MBOX_SET_CLOCK_RATE; + mbs.param[1] = isp->isp_clock; + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + /* we will try not to care if this fails */ + } + } + + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_ABOUT_FIRMWARE; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + ISP_RESET0(isp); + return; + } + + if (IS_24XX(isp) && mbs.param[1] == 0xdead) { + isp_prt(isp, ISP_LOGERR, "f/w didn't *really* start"); + ISP_RESET0(isp); + return; + } + + /* + * The SBus firmware that we are using apparently does not return + * major, minor, micro revisions in the mailbox registers, which + * is really, really, annoying. + */ + if (ISP_SBUS_SUPPORTED && isp->isp_bustype == ISP_BT_SBUS) { + if (dodnld) { +#ifdef ISP_TARGET_MODE + isp->isp_fwrev[0] = 7; + isp->isp_fwrev[1] = 55; +#else + isp->isp_fwrev[0] = 1; + isp->isp_fwrev[1] = 37; +#endif + isp->isp_fwrev[2] = 0; + } + } else { + isp->isp_fwrev[0] = mbs.param[1]; + isp->isp_fwrev[1] = mbs.param[2]; + isp->isp_fwrev[2] = mbs.param[3]; + } + + isp_prt(isp, ISP_LOGALL, + "Board Type %s, Chip Revision 0x%x, %s F/W Revision %d.%d.%d", + btype, isp->isp_revision, dodnld? "loaded" : "resident", + isp->isp_fwrev[0], isp->isp_fwrev[1], isp->isp_fwrev[2]); + + if (IS_FC(isp)) { + /* + * We do not believe firmware attributes for 2100 code less + * than 1.17.0, unless it's the firmware we specifically + * are loading. + * + * Note that all 22XX and later f/w is greater than 1.X.0. + */ + if ((ISP_FW_OLDER_THAN(isp, 1, 17, 1))) { +#ifdef USE_SMALLER_2100_FIRMWARE + isp->isp_fwattr = ISP_FW_ATTR_SCCLUN; +#else + isp->isp_fwattr = 0; +#endif + } else { + isp->isp_fwattr = mbs.param[6]; + isp_prt(isp, ISP_LOGDEBUG0, + "Firmware Attributes = 0x%x", mbs.param[6]); + } + } else { +#ifndef ISP_TARGET_MODE + isp->isp_fwattr = ISP_FW_ATTR_TMODE; +#else + isp->isp_fwattr = 0; +#endif + } + + if (isp->isp_romfw_rev[0] || isp->isp_romfw_rev[1] || + isp->isp_romfw_rev[2]) { + isp_prt(isp, ISP_LOGCONFIG, "Last F/W revision was %d.%d.%d", + isp->isp_romfw_rev[0], isp->isp_romfw_rev[1], + isp->isp_romfw_rev[2]); + } + + if (!IS_24XX(isp)) { + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_GET_FIRMWARE_STATUS; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + ISP_RESET0(isp); + return; + } + if (isp->isp_maxcmds >= mbs.param[2]) { + isp->isp_maxcmds = mbs.param[2]; + } + } + isp_prt(isp, ISP_LOGCONFIG, + "%d max I/O command limit set", isp->isp_maxcmds); + for (i = 0; i < isp->isp_nchan; i++) { + isp_fw_state(isp, i); + } + + isp->isp_state = ISP_RESETSTATE; + + /* + * Okay- now that we have new firmware running, we now (re)set our + * notion of how many luns we support. This is somewhat tricky because + * if we haven't loaded firmware, we sometimes do not have an easy way + * of knowing how many luns we support. + * + * Expanded lun firmware gives you 32 luns for SCSI cards and + * 16384 luns for Fibre Channel cards. + * + * It turns out that even for QLogic 2100s with ROM 1.10 and above + * we do get a firmware attributes word returned in mailbox register 6. + * + * Because the lun is in a different position in the Request Queue + * Entry structure for Fibre Channel with expanded lun firmware, we + * can only support one lun (lun zero) when we don't know what kind + * of firmware we're running. + */ + if (IS_SCSI(isp)) { + if (dodnld) { + if (IS_ULTRA2(isp) || IS_ULTRA3(isp)) { + isp->isp_maxluns = 32; + } else { + isp->isp_maxluns = 8; + } + } else { + isp->isp_maxluns = 8; + } + } else { + if (ISP_CAP_SCCFW(isp)) { + isp->isp_maxluns = 16384; + } else { + isp->isp_maxluns = 16; + } + } + /* + * Must do this first to get defaults established. + */ + if (IS_SCSI(isp)) { + for (i = 0; i < isp->isp_nchan; i++) { + isp_setdfltparm(isp, i); + } + } else { + for (i = 0; i < isp->isp_nchan; i++) { + isp_setdfltfcparm(isp, i); + } + } + +} + +/* + * Initialize Parameters of Hardware to a known state. + * + * Locks are held before coming here. + */ + +void +isp_init(ispsoftc_t *isp) +{ + if (IS_FC(isp)) { + int i; + for (i = 0; i < isp->isp_nchan; i++) { + ISP_MARK_PORTDB(isp, i, 0); + FCPARAM(isp, i)->isp_fwstate = FW_CONFIG_WAIT; + FCPARAM(isp, i)->isp_loopstate = LOOP_NIL; + if (isp->isp_role != ISP_ROLE_NONE) { + if (IS_24XX(isp)) { + isp_fibre_init_2400(isp, i); + } else { + isp_fibre_init(isp, i); + } + } + } + } else { + isp_scsi_init(isp); + } +} + +static void +isp_scsi_init(ispsoftc_t *isp) +{ + sdparam *sdp_chan0, *sdp_chan1; + mbreg_t mbs; + + sdp_chan0 = SDPARAM(isp, 0); + sdp_chan1 = sdp_chan0; + if (IS_DUALBUS(isp)) { + sdp_chan1 = SDPARAM(isp, 1); + } + + /* + * If we have no role (neither target nor initiator), return. + */ + if (isp->isp_role == ISP_ROLE_NONE) { + return; + } + + /* First do overall per-card settings. */ + + /* + * If we have fast memory timing enabled, turn it on. + */ + if (sdp_chan0->isp_fast_mttr) { + ISP_WRITE(isp, RISC_MTR, 0x1313); + } + + /* + * Set Retry Delay and Count. + * You set both channels at the same time. + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_RETRY_COUNT; + mbs.param[1] = sdp_chan0->isp_retry_count; + mbs.param[2] = sdp_chan0->isp_retry_delay; + mbs.param[6] = sdp_chan1->isp_retry_count; + mbs.param[7] = sdp_chan1->isp_retry_delay; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + + /* + * Set ASYNC DATA SETUP time. This is very important. + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME; + mbs.param[1] = sdp_chan0->isp_async_data_setup; + mbs.param[2] = sdp_chan1->isp_async_data_setup; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + + /* + * Set ACTIVE Negation State. + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_ACT_NEG_STATE; + mbs.param[1] = + (sdp_chan0->isp_req_ack_active_neg << 4) | + (sdp_chan0->isp_data_line_active_neg << 5); + mbs.param[2] = + (sdp_chan1->isp_req_ack_active_neg << 4) | + (sdp_chan1->isp_data_line_active_neg << 5); + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, + "failed to set active negation state (%d,%d), (%d,%d)", + sdp_chan0->isp_req_ack_active_neg, + sdp_chan0->isp_data_line_active_neg, + sdp_chan1->isp_req_ack_active_neg, + sdp_chan1->isp_data_line_active_neg); + /* + * But don't return. + */ + } + + /* + * Set the Tag Aging limit + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_TAG_AGE_LIMIT; + mbs.param[1] = sdp_chan0->isp_tag_aging; + mbs.param[2] = sdp_chan1->isp_tag_aging; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGERR, "failed to set tag age limit (%d,%d)", + sdp_chan0->isp_tag_aging, sdp_chan1->isp_tag_aging); + return; + } + + /* + * Set selection timeout. + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_SELECT_TIMEOUT; + mbs.param[1] = sdp_chan0->isp_selection_timeout; + mbs.param[2] = sdp_chan1->isp_selection_timeout; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + + /* now do per-channel settings */ + isp_scsi_channel_init(isp, 0); + if (IS_DUALBUS(isp)) + isp_scsi_channel_init(isp, 1); + + /* + * Now enable request/response queues + */ + + if (IS_ULTRA2(isp) || IS_1240(isp)) { + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_INIT_RES_QUEUE_A64; + mbs.param[1] = RESULT_QUEUE_LEN(isp); + mbs.param[2] = DMA_WD1(isp->isp_result_dma); + mbs.param[3] = DMA_WD0(isp->isp_result_dma); + mbs.param[4] = 0; + mbs.param[6] = DMA_WD3(isp->isp_result_dma); + mbs.param[7] = DMA_WD2(isp->isp_result_dma); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + isp->isp_residx = mbs.param[5]; + + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_INIT_REQ_QUEUE_A64; + mbs.param[1] = RQUEST_QUEUE_LEN(isp); + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[5] = 0; + mbs.param[6] = DMA_WD3(isp->isp_result_dma); + mbs.param[7] = DMA_WD2(isp->isp_result_dma); + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + isp->isp_reqidx = isp->isp_reqodx = mbs.param[4]; + } else { + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_INIT_RES_QUEUE; + mbs.param[1] = RESULT_QUEUE_LEN(isp); + mbs.param[2] = DMA_WD1(isp->isp_result_dma); + mbs.param[3] = DMA_WD0(isp->isp_result_dma); + mbs.param[4] = 0; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + isp->isp_residx = mbs.param[5]; + + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_INIT_REQ_QUEUE; + mbs.param[1] = RQUEST_QUEUE_LEN(isp); + mbs.param[2] = DMA_WD1(isp->isp_rquest_dma); + mbs.param[3] = DMA_WD0(isp->isp_rquest_dma); + mbs.param[5] = 0; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + isp->isp_reqidx = isp->isp_reqodx = mbs.param[4]; + } + + /* + * Turn on Fast Posting, LVD transitions + * + * Ultra2 F/W always has had fast posting (and LVD transitions) + * + * Ultra and older (i.e., SBus) cards may not. It's just safer + * to assume not for them. + */ + + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_FW_FEATURES; + mbs.param[1] = 0; + if (IS_ULTRA2(isp)) + mbs.param[1] |= FW_FEATURE_LVD_NOTIFY; +#ifndef ISP_NO_RIO + if (IS_ULTRA2(isp) || IS_1240(isp)) + mbs.param[1] |= FW_FEATURE_RIO_16BIT; +#else + if (IS_ULTRA2(isp) || IS_1240(isp)) + mbs.param[1] |= FW_FEATURE_FAST_POST; +#endif + if (mbs.param[1] != 0) { + uint16_t sfeat = mbs.param[1]; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] == MBOX_COMMAND_COMPLETE) { + isp_prt(isp, ISP_LOGINFO, + "Enabled FW features (0x%x)", sfeat); + } + } + + /* + * Let the outer layers decide whether to issue a SCSI bus reset. + */ + isp->isp_state = ISP_INITSTATE; +} + +static void +isp_scsi_channel_init(ispsoftc_t *isp, int channel) +{ + sdparam *sdp; + mbreg_t mbs; + int tgt; + + sdp = SDPARAM(isp, channel); + + /* + * Set (possibly new) Initiator ID. + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_INIT_SCSI_ID; + mbs.param[1] = (channel << 7) | sdp->isp_initiator_id; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + isp_prt(isp, ISP_LOGINFO, "Initiator ID is %d on Channel %d", + sdp->isp_initiator_id, channel); + + + /* + * Set current per-target parameters to an initial safe minimum. + */ + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + int lun; + uint16_t sdf; + + if (sdp->isp_devparam[tgt].dev_enable == 0) { + continue; + } +#ifndef ISP_TARGET_MODE + sdf = sdp->isp_devparam[tgt].goal_flags; + sdf &= DPARM_SAFE_DFLT; + /* + * It is not quite clear when this changed over so that + * we could force narrow and async for 1000/1020 cards, + * but assume that this is only the case for loaded + * firmware. + */ + if (isp->isp_loaded_fw) { + sdf |= DPARM_NARROW | DPARM_ASYNC; + } +#else + /* + * The !$*!)$!$)* f/w uses the same index into some + * internal table to decide how to respond to negotiations, + * so if we've said "let's be safe" for ID X, and ID X + * selects *us*, the negotiations will back to 'safe' + * (as in narrow/async). What the f/w *should* do is + * use the initiator id settings to decide how to respond. + */ + sdp->isp_devparam[tgt].goal_flags = sdf = DPARM_DEFAULT; +#endif + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_TARGET_PARAMS; + mbs.param[1] = (channel << 15) | (tgt << 8); + mbs.param[2] = sdf; + if ((sdf & DPARM_SYNC) == 0) { + mbs.param[3] = 0; + } else { + mbs.param[3] = + (sdp->isp_devparam[tgt].goal_offset << 8) | + (sdp->isp_devparam[tgt].goal_period); + } + isp_prt(isp, ISP_LOGDEBUG0, + "Initial Settings bus%d tgt%d flags 0x%x off 0x%x per 0x%x", + channel, tgt, mbs.param[2], mbs.param[3] >> 8, + mbs.param[3] & 0xff); + mbs.logval = MBLOGNONE; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + sdf = DPARM_SAFE_DFLT; + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_TARGET_PARAMS; + mbs.param[1] = (tgt << 8) | (channel << 15); + mbs.param[2] = sdf; + mbs.param[3] = 0; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + continue; + } + } + + /* + * We don't update any information directly from the f/w + * because we need to run at least one command to cause a + * new state to be latched up. So, we just assume that we + * converge to the values we just had set. + * + * Ensure that we don't believe tagged queuing is enabled yet. + * It turns out that sometimes the ISP just ignores our + * attempts to set parameters for devices that it hasn't + * seen yet. + */ + sdp->isp_devparam[tgt].actv_flags = sdf & ~DPARM_TQING; + for (lun = 0; lun < (int) isp->isp_maxluns; lun++) { + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_DEV_QUEUE_PARAMS; + mbs.param[1] = (channel << 15) | (tgt << 8) | lun; + mbs.param[2] = sdp->isp_max_queue_depth; + mbs.param[3] = sdp->isp_devparam[tgt].exc_throttle; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + break; + } + } + } + for (tgt = 0; tgt < MAX_TARGETS; tgt++) { + if (sdp->isp_devparam[tgt].dev_refresh) { + isp->isp_sendmarker |= (1 << channel); + isp->isp_update |= (1 << channel); + break; + } + } +} + +/* + * Fibre Channel specific initialization. + */ +static void +isp_fibre_init(ispsoftc_t *isp, int chan) +{ + fcparam *fcp; + isp_icb_t local, *icbp = &local; + mbreg_t mbs; + int ownloopid; + uint64_t nwwn, pwwn; + + fcp = FCPARAM(isp, chan); + + MEMZERO(icbp, sizeof (*icbp)); + icbp->icb_version = ICB_VERSION1; + icbp->icb_fwoptions = fcp->isp_fwoptions; + + /* + * Firmware Options are either retrieved from NVRAM or + * are patched elsewhere. We check them for sanity here + * and make changes based on board revision, but otherwise + * let others decide policy. + */ + + /* + * If this is a 2100 < revision 5, we have to turn off FAIRNESS. + */ + if (IS_2100(isp) && isp->isp_revision < 5) { + icbp->icb_fwoptions &= ~ICBOPT_FAIRNESS; + } + + /* + * We have to use FULL LOGIN even though it resets the loop too much + * because otherwise port database entries don't get updated after + * a LIP- this is a known f/w bug for 2100 f/w less than 1.17.0. + */ + if (!ISP_FW_NEWER_THAN(isp, 1, 17, 0)) { + icbp->icb_fwoptions |= ICBOPT_FULL_LOGIN; + } + + /* + * Insist on Port Database Update Async notifications + */ + icbp->icb_fwoptions |= ICBOPT_PDBCHANGE_AE; + + /* + * Make sure that target role reflects into fwoptions. + */ + if (isp->isp_role & ISP_ROLE_TARGET) { + icbp->icb_fwoptions |= ICBOPT_TGT_ENABLE; + } else { + icbp->icb_fwoptions &= ~ICBOPT_TGT_ENABLE; + } + + if (isp->isp_role & ISP_ROLE_INITIATOR) { + icbp->icb_fwoptions &= ~ICBOPT_INI_DISABLE; + } else { + icbp->icb_fwoptions |= ICBOPT_INI_DISABLE; + } + + icbp->icb_maxfrmlen = fcp->isp_maxfrmlen; + if (icbp->icb_maxfrmlen < ICB_MIN_FRMLEN || + icbp->icb_maxfrmlen > ICB_MAX_FRMLEN) { + isp_prt(isp, ISP_LOGERR, + "bad frame length (%d) from NVRAM- using %d", + fcp->isp_maxfrmlen, ICB_DFLT_FRMLEN); + icbp->icb_maxfrmlen = ICB_DFLT_FRMLEN; + } + icbp->icb_maxalloc = fcp->isp_maxalloc; + if (icbp->icb_maxalloc < 1) { + isp_prt(isp, ISP_LOGERR, + "bad maximum allocation (%d)- using 16", fcp->isp_maxalloc); + icbp->icb_maxalloc = 16; + } + icbp->icb_execthrottle = fcp->isp_execthrottle; + if (icbp->icb_execthrottle < 1) { + isp_prt(isp, ISP_LOGERR, + "bad execution throttle of %d- using 16", + fcp->isp_execthrottle); + icbp->icb_execthrottle = ICB_DFLT_THROTTLE; + } + icbp->icb_retry_delay = fcp->isp_retry_delay; + icbp->icb_retry_count = fcp->isp_retry_count; + icbp->icb_hardaddr = fcp->isp_loopid; + ownloopid = (isp->isp_confopts & ISP_CFG_OWNLOOPID) != 0; + if (icbp->icb_hardaddr > 125) { + icbp->icb_hardaddr = 0; + ownloopid = 0; + } + + /* + * Our life seems so much better with 2200s and later with + * the latest f/w if we set Hard Address. + */ + if (ownloopid || ISP_FW_NEWER_THAN(isp, 2, 2, 5)) { + icbp->icb_fwoptions |= ICBOPT_HARD_ADDRESS; + } + + /* + * Right now we just set extended options to prefer point-to-point + * over loop based upon some soft config options. + * + * NB: for the 2300, ICBOPT_EXTENDED is required. + */ + if (IS_2200(isp) || IS_23XX(isp)) { + icbp->icb_fwoptions |= ICBOPT_EXTENDED; + /* + * Prefer or force Point-To-Point instead Loop? + */ + switch(isp->isp_confopts & ISP_CFG_PORT_PREF) { + case ISP_CFG_NPORT: + icbp->icb_xfwoptions |= ICBXOPT_PTP_2_LOOP; + break; + case ISP_CFG_NPORT_ONLY: + icbp->icb_xfwoptions |= ICBXOPT_PTP_ONLY; + break; + case ISP_CFG_LPORT_ONLY: + icbp->icb_xfwoptions |= ICBXOPT_LOOP_ONLY; + break; + default: + icbp->icb_xfwoptions |= ICBXOPT_LOOP_2_PTP; + break; + } + if (IS_2200(isp)) { + if (ISP_FW_NEWER_THAN(isp, 1, 17, 0)) { + icbp->icb_xfwoptions |= ICBXOPT_RIO_16BIT; + icbp->icb_racctimer = 4; + icbp->icb_idelaytimer = 8; + } + icbp->icb_fwoptions |= ICBOPT_FAST_POST; + } else { + /* + * QLogic recommends that FAST Posting be turned + * off for 23XX cards and instead allow the HBA + * to write response queue entries and interrupt + * after a delay (ZIO). + */ + icbp->icb_fwoptions &= ~ICBOPT_FAST_POST; + if ((fcp->isp_xfwoptions & ICBXOPT_TIMER_MASK) == + ICBXOPT_ZIO) { + icbp->icb_xfwoptions |= ICBXOPT_ZIO; + icbp->icb_idelaytimer = 10; + } + if (isp->isp_confopts & ISP_CFG_ONEGB) { + icbp->icb_zfwoptions |= ICBZOPT_RATE_ONEGB; + } else if (isp->isp_confopts & ISP_CFG_TWOGB) { + icbp->icb_zfwoptions |= ICBZOPT_RATE_TWOGB; + } else { + icbp->icb_zfwoptions |= ICBZOPT_RATE_AUTO; + } + if (fcp->isp_zfwoptions & ICBZOPT_50_OHM) { + icbp->icb_zfwoptions |= ICBZOPT_50_OHM; + } + } + } + + + /* + * For 22XX > 2.1.26 && 23XX, set some options. + * XXX: Probably okay for newer 2100 f/w too. + */ + if (ISP_FW_NEWER_THAN(isp, 2, 26, 0)) { + /* + * Turn on LIP F8 async event (1) + * Turn on generate AE 8013 on all LIP Resets (2) + * Disable LIP F7 switching (8) + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_FIRMWARE_OPTIONS; + mbs.param[1] = 0xb; + mbs.param[2] = 0; + mbs.param[3] = 0; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + } + icbp->icb_logintime = ICB_LOGIN_TOV; + icbp->icb_lunetimeout = ICB_LUN_ENABLE_TOV; + + nwwn = ISP_NODEWWN(isp); + pwwn = ISP_PORTWWN(isp); + if (nwwn && pwwn) { + icbp->icb_fwoptions |= ICBOPT_BOTH_WWNS; + MAKE_NODE_NAME_FROM_WWN(icbp->icb_nodename, nwwn); + MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, pwwn); + isp_prt(isp, ISP_LOGDEBUG1, + "Setting ICB Node 0x%08x%08x Port 0x%08x%08x", + ((uint32_t) (nwwn >> 32)), + ((uint32_t) (nwwn & 0xffffffff)), + ((uint32_t) (pwwn >> 32)), + ((uint32_t) (pwwn & 0xffffffff))); + } else if (pwwn) { + icbp->icb_fwoptions &= ~ICBOPT_BOTH_WWNS; + MAKE_NODE_NAME_FROM_WWN(icbp->icb_portname, pwwn); + isp_prt(isp, ISP_LOGDEBUG1, + "Setting ICB Port 0x%08x%08x", + ((uint32_t) (pwwn >> 32)), + ((uint32_t) (pwwn & 0xffffffff))); + } else { + isp_prt(isp, ISP_LOGERR, "No valid WWNs to use"); + return; + } + icbp->icb_rqstqlen = RQUEST_QUEUE_LEN(isp); + if (icbp->icb_rqstqlen < 1) { + isp_prt(isp, ISP_LOGERR, "bad request queue length"); + } + icbp->icb_rsltqlen = RESULT_QUEUE_LEN(isp); + if (icbp->icb_rsltqlen < 1) { + isp_prt(isp, ISP_LOGERR, "bad result queue length"); + } + icbp->icb_rqstaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_rquest_dma); + icbp->icb_rqstaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_rquest_dma); + icbp->icb_rqstaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_rquest_dma); + icbp->icb_rqstaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_rquest_dma); + icbp->icb_respaddr[RQRSP_ADDR0015] = DMA_WD0(isp->isp_result_dma); + icbp->icb_respaddr[RQRSP_ADDR1631] = DMA_WD1(isp->isp_result_dma); + icbp->icb_respaddr[RQRSP_ADDR3247] = DMA_WD2(isp->isp_result_dma); + icbp->icb_respaddr[RQRSP_ADDR4863] = DMA_WD3(isp->isp_result_dma); + + isp_prt(isp, ISP_LOGDEBUG0, + "isp_fibre_init: fwopt 0x%x xfwopt 0x%x zfwopt 0x%x", + icbp->icb_fwoptions, icbp->icb_xfwoptions, icbp->icb_zfwoptions); + + FC_SCRATCH_ACQUIRE(isp, chan); + isp_put_icb(isp, icbp, (isp_icb_t *)fcp->isp_scratch); + + /* + * Init the firmware + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_INIT_FIRMWARE; + mbs.param[2] = DMA_WD1(fcp->isp_scdma); + mbs.param[3] = DMA_WD0(fcp->isp_scdma); + mbs.param[6] = DMA_WD3(fcp->isp_scdma); + mbs.param[7] = DMA_WD2(fcp->isp_scdma); + mbs.logval = MBLOGALL; + mbs.timeout = 30 * 1000000; + isp_prt(isp, ISP_LOGDEBUG0, "INIT F/W from %p (%08x%08x)", + fcp->isp_scratch, (uint32_t) ((uint64_t)fcp->isp_scdma >> 32), + (uint32_t) fcp->isp_scdma); + MEMORYBARRIER(isp, SYNC_SFORDEV, 0, sizeof (*icbp)); + isp_mboxcmd(isp, &mbs); + FC_SCRATCH_RELEASE(isp, chan); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + isp_print_bytes(isp, "isp_fibre_init", sizeof (*icbp), icbp); + return; + } + isp->isp_reqidx = 0; + isp->isp_reqodx = 0; + isp->isp_residx = 0; + + /* + * Whatever happens, we're now committed to being here. + */ + isp->isp_state = ISP_INITSTATE; +} + +static void +isp_fibre_init_2400(ispsoftc_t *isp, int chan) +{ + fcparam *fcp; + isp_icb_2400_t local, *icbp = &local; + mbreg_t mbs; + int ownloopid; + uint64_t nwwn, pwwn; + + fcp = FCPARAM(isp, chan); + + /* + * Turn on LIP F8 async event (1) + */ + MEMZERO(&mbs, sizeof (mbs)); + mbs.param[0] = MBOX_SET_FIRMWARE_OPTIONS; + mbs.param[1] = 1; + mbs.logval = MBLOGALL; + isp_mboxcmd(isp, &mbs); + if (mbs.param[0] != MBOX_COMMAND_COMPLETE) { + return; + } + + /* + * XXX: This should be applied to icb- not fwoptions + */ + if (isp->isp_role & ISP_ROLE_TARGET) { + fcp->isp_fwoptions |= ICB2400_OPT1_TGT_ENABLE; + } else { + fcp->isp_fwoptions &= ~ICB2400_OPT1_TGT_ENABLE; + } + + if (isp-... [truncated message content] |