2003-08-24 17:55:58 +00:00
|
|
|
/*-
|
1998-04-22 18:12:29 +00:00
|
|
|
*
|
2006-01-23 06:23:37 +00:00
|
|
|
* Copyright (c) 1997-2006 by Matthew Jacob
|
|
|
|
* All rights reserved.
|
1998-04-22 18:12:29 +00:00
|
|
|
*
|
|
|
|
* 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.
|
2000-09-21 20:16:04 +00:00
|
|
|
* 2. The name of the author may not be used to endorse or promote products
|
|
|
|
* derived from this software without specific prior written permission.
|
1998-04-22 18:12:29 +00:00
|
|
|
*
|
|
|
|
* 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.
|
2006-01-23 06:23:37 +00:00
|
|
|
*
|
1998-04-22 18:12:29 +00:00
|
|
|
*/
|
2006-07-16 20:11:50 +00:00
|
|
|
/*
|
|
|
|
* PCI specific probe and attach routines for Qlogic ISP SCSI adapters.
|
|
|
|
* FreeBSD Version.
|
|
|
|
*/
|
2003-08-24 17:55:58 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/module.h>
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
#if __FreeBSD_version >= 700000
|
|
|
|
#include <sys/linker.h>
|
|
|
|
#include <sys/firmware.h>
|
|
|
|
#endif
|
2000-02-11 19:45:17 +00:00
|
|
|
#include <sys/bus.h>
|
2006-04-21 18:30:01 +00:00
|
|
|
#if __FreeBSD_version < 500000
|
|
|
|
#include <pci/pcireg.h>
|
|
|
|
#include <pci/pcivar.h>
|
|
|
|
#include <machine/bus_memio.h>
|
|
|
|
#include <machine/bus_pio.h>
|
|
|
|
#else
|
2005-12-15 22:12:27 +00:00
|
|
|
#include <sys/stdint.h>
|
2003-08-22 06:00:27 +00:00
|
|
|
#include <dev/pci/pcireg.h>
|
|
|
|
#include <dev/pci/pcivar.h>
|
2006-04-21 18:30:01 +00:00
|
|
|
#endif
|
1998-09-15 10:06:23 +00:00
|
|
|
#include <machine/bus.h>
|
2000-02-11 19:45:17 +00:00
|
|
|
#include <machine/resource.h>
|
|
|
|
#include <sys/rman.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
|
|
|
|
#include <dev/isp/isp_freebsd.h>
|
1999-03-17 05:07:18 +00:00
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
#if __FreeBSD_version < 500000
|
|
|
|
#define BUS_PROBE_DEFAULT 0
|
|
|
|
#endif
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
static uint32_t isp_pci_rd_reg(ispsoftc_t *, int);
|
|
|
|
static void isp_pci_wr_reg(ispsoftc_t *, int, uint32_t);
|
|
|
|
static uint32_t isp_pci_rd_reg_1080(ispsoftc_t *, int);
|
|
|
|
static void isp_pci_wr_reg_1080(ispsoftc_t *, int, uint32_t);
|
|
|
|
static uint32_t isp_pci_rd_reg_2400(ispsoftc_t *, int);
|
|
|
|
static void isp_pci_wr_reg_2400(ispsoftc_t *, int, uint32_t);
|
2001-08-31 21:39:04 +00:00
|
|
|
static int
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_pci_rd_isr(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
|
2001-08-31 21:39:04 +00:00
|
|
|
static int
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_pci_rd_isr_2300(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
|
|
|
|
static int
|
|
|
|
isp_pci_rd_isr_2400(ispsoftc_t *, uint32_t *, uint16_t *, uint16_t *);
|
2006-04-21 18:30:01 +00:00
|
|
|
static int isp_pci_mbxdma(ispsoftc_t *);
|
2001-08-31 21:39:04 +00:00
|
|
|
static int
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_pci_dmasetup(ispsoftc_t *, XS_T *, ispreq_t *, uint32_t *, uint32_t);
|
1998-09-15 10:06:23 +00:00
|
|
|
static void
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_pci_dmateardown(ispsoftc_t *, XS_T *, uint32_t);
|
1998-04-22 18:12:29 +00:00
|
|
|
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
static void isp_pci_reset1(ispsoftc_t *);
|
|
|
|
static void isp_pci_dumpregs(ispsoftc_t *, const char *);
|
1998-04-22 18:12:29 +00:00
|
|
|
|
|
|
|
static struct ispmdvec mdvec = {
|
2001-08-31 21:39:04 +00:00
|
|
|
isp_pci_rd_isr,
|
1998-04-22 18:12:29 +00:00
|
|
|
isp_pci_rd_reg,
|
|
|
|
isp_pci_wr_reg,
|
|
|
|
isp_pci_mbxdma,
|
|
|
|
isp_pci_dmasetup,
|
1998-09-15 10:06:23 +00:00
|
|
|
isp_pci_dmateardown,
|
1998-04-22 18:12:29 +00:00
|
|
|
NULL,
|
|
|
|
isp_pci_reset1,
|
|
|
|
isp_pci_dumpregs,
|
2000-06-18 05:18:55 +00:00
|
|
|
NULL,
|
2000-08-01 05:16:49 +00:00
|
|
|
BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
|
1998-04-22 18:12:29 +00:00
|
|
|
};
|
|
|
|
|
1999-03-17 05:07:18 +00:00
|
|
|
static struct ispmdvec mdvec_1080 = {
|
2001-08-31 21:39:04 +00:00
|
|
|
isp_pci_rd_isr,
|
1999-03-17 05:07:18 +00:00
|
|
|
isp_pci_rd_reg_1080,
|
|
|
|
isp_pci_wr_reg_1080,
|
|
|
|
isp_pci_mbxdma,
|
|
|
|
isp_pci_dmasetup,
|
|
|
|
isp_pci_dmateardown,
|
|
|
|
NULL,
|
|
|
|
isp_pci_reset1,
|
|
|
|
isp_pci_dumpregs,
|
2000-06-18 05:18:55 +00:00
|
|
|
NULL,
|
2000-08-01 05:16:49 +00:00
|
|
|
BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
|
1999-03-17 05:07:18 +00:00
|
|
|
};
|
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
static struct ispmdvec mdvec_12160 = {
|
2001-08-31 21:39:04 +00:00
|
|
|
isp_pci_rd_isr,
|
2000-02-11 19:45:17 +00:00
|
|
|
isp_pci_rd_reg_1080,
|
|
|
|
isp_pci_wr_reg_1080,
|
|
|
|
isp_pci_mbxdma,
|
|
|
|
isp_pci_dmasetup,
|
|
|
|
isp_pci_dmateardown,
|
|
|
|
NULL,
|
|
|
|
isp_pci_reset1,
|
|
|
|
isp_pci_dumpregs,
|
2000-06-18 05:18:55 +00:00
|
|
|
NULL,
|
2000-08-01 05:16:49 +00:00
|
|
|
BIU_BURST_ENABLE|BIU_PCI_CONF1_FIFO_64
|
2000-02-11 19:45:17 +00:00
|
|
|
};
|
|
|
|
|
1998-04-22 18:12:29 +00:00
|
|
|
static struct ispmdvec mdvec_2100 = {
|
2001-08-31 21:39:04 +00:00
|
|
|
isp_pci_rd_isr,
|
1998-04-22 18:12:29 +00:00
|
|
|
isp_pci_rd_reg,
|
|
|
|
isp_pci_wr_reg,
|
|
|
|
isp_pci_mbxdma,
|
|
|
|
isp_pci_dmasetup,
|
1998-09-15 10:06:23 +00:00
|
|
|
isp_pci_dmateardown,
|
1998-04-22 18:12:29 +00:00
|
|
|
NULL,
|
|
|
|
isp_pci_reset1,
|
2000-08-01 05:16:49 +00:00
|
|
|
isp_pci_dumpregs
|
1998-04-22 18:12:29 +00:00
|
|
|
};
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
|
|
|
|
static struct ispmdvec mdvec_2200 = {
|
2001-08-31 21:39:04 +00:00
|
|
|
isp_pci_rd_isr,
|
|
|
|
isp_pci_rd_reg,
|
|
|
|
isp_pci_wr_reg,
|
|
|
|
isp_pci_mbxdma,
|
|
|
|
isp_pci_dmasetup,
|
|
|
|
isp_pci_dmateardown,
|
|
|
|
NULL,
|
|
|
|
isp_pci_reset1,
|
|
|
|
isp_pci_dumpregs
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct ispmdvec mdvec_2300 = {
|
|
|
|
isp_pci_rd_isr_2300,
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
isp_pci_rd_reg,
|
|
|
|
isp_pci_wr_reg,
|
|
|
|
isp_pci_mbxdma,
|
|
|
|
isp_pci_dmasetup,
|
|
|
|
isp_pci_dmateardown,
|
|
|
|
NULL,
|
|
|
|
isp_pci_reset1,
|
2000-08-01 05:16:49 +00:00
|
|
|
isp_pci_dumpregs
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
};
|
1999-02-09 01:12:52 +00:00
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
static struct ispmdvec mdvec_2400 = {
|
|
|
|
isp_pci_rd_isr_2400,
|
|
|
|
isp_pci_rd_reg_2400,
|
|
|
|
isp_pci_wr_reg_2400,
|
|
|
|
isp_pci_mbxdma,
|
|
|
|
isp_pci_dmasetup,
|
|
|
|
isp_pci_dmateardown,
|
|
|
|
NULL,
|
|
|
|
isp_pci_reset1,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
1998-04-22 18:12:29 +00:00
|
|
|
#ifndef PCIM_CMD_INVEN
|
1998-09-15 10:06:23 +00:00
|
|
|
#define PCIM_CMD_INVEN 0x10
|
1998-04-22 18:12:29 +00:00
|
|
|
#endif
|
|
|
|
#ifndef PCIM_CMD_BUSMASTEREN
|
1998-09-15 10:06:23 +00:00
|
|
|
#define PCIM_CMD_BUSMASTEREN 0x0004
|
1998-04-22 18:12:29 +00:00
|
|
|
#endif
|
1999-02-09 01:12:52 +00:00
|
|
|
#ifndef PCIM_CMD_PERRESPEN
|
|
|
|
#define PCIM_CMD_PERRESPEN 0x0040
|
|
|
|
#endif
|
|
|
|
#ifndef PCIM_CMD_SEREN
|
|
|
|
#define PCIM_CMD_SEREN 0x0100
|
|
|
|
#endif
|
2006-07-03 08:24:09 +00:00
|
|
|
#ifndef PCIM_CMD_INTX_DISABLE
|
|
|
|
#define PCIM_CMD_INTX_DISABLE 0x0400
|
|
|
|
#endif
|
1999-02-09 01:12:52 +00:00
|
|
|
|
|
|
|
#ifndef PCIR_COMMAND
|
|
|
|
#define PCIR_COMMAND 0x04
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef PCIR_CACHELNSZ
|
|
|
|
#define PCIR_CACHELNSZ 0x0c
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef PCIR_LATTIMER
|
|
|
|
#define PCIR_LATTIMER 0x0d
|
|
|
|
#endif
|
|
|
|
|
1999-04-04 01:14:02 +00:00
|
|
|
#ifndef PCIR_ROMADDR
|
|
|
|
#define PCIR_ROMADDR 0x30
|
|
|
|
#endif
|
|
|
|
|
1998-04-22 18:12:29 +00:00
|
|
|
#ifndef PCI_VENDOR_QLOGIC
|
2000-06-18 05:18:55 +00:00
|
|
|
#define PCI_VENDOR_QLOGIC 0x1077
|
1998-04-22 18:12:29 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP1020
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP1020 0x1020
|
|
|
|
#endif
|
|
|
|
|
1999-03-17 05:07:18 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP1080
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP1080 0x1080
|
|
|
|
#endif
|
|
|
|
|
2002-10-11 17:28:01 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP10160
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP10160 0x1016
|
|
|
|
#endif
|
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP12160
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP12160 0x1216
|
|
|
|
#endif
|
|
|
|
|
1999-03-17 05:07:18 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP1240
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP1240 0x1240
|
|
|
|
#endif
|
1998-04-22 18:12:29 +00:00
|
|
|
|
1999-12-16 05:42:02 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP1280
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP1280 0x1280
|
|
|
|
#endif
|
|
|
|
|
1998-04-22 18:12:29 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP2100
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP2100 0x2100
|
|
|
|
#endif
|
|
|
|
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP2200
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP2200 0x2200
|
|
|
|
#endif
|
|
|
|
|
2001-08-31 21:39:04 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP2300
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP2300 0x2300
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP2312
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP2312 0x2312
|
|
|
|
#endif
|
|
|
|
|
2006-01-23 06:23:37 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP2322
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP2322 0x2322
|
|
|
|
#endif
|
|
|
|
|
2006-01-26 05:04:35 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP2422
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP2422 0x2422
|
|
|
|
#endif
|
|
|
|
|
2005-01-23 06:23:55 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP6312
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP6312 0x6312
|
|
|
|
#endif
|
|
|
|
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
#ifndef PCI_PRODUCT_QLOGIC_ISP6322
|
|
|
|
#define PCI_PRODUCT_QLOGIC_ISP6322 0x6322
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2000-06-18 05:18:55 +00:00
|
|
|
#define PCI_QLOGIC_ISP1020 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP1020 << 16) | PCI_VENDOR_QLOGIC)
|
1999-03-17 05:07:18 +00:00
|
|
|
|
|
|
|
#define PCI_QLOGIC_ISP1080 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP1080 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
2002-10-11 17:28:01 +00:00
|
|
|
#define PCI_QLOGIC_ISP10160 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP10160 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
#define PCI_QLOGIC_ISP12160 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP12160 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
1999-03-17 05:07:18 +00:00
|
|
|
#define PCI_QLOGIC_ISP1240 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP1240 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
1999-12-16 05:42:02 +00:00
|
|
|
#define PCI_QLOGIC_ISP1280 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP1280 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
1998-04-22 18:12:29 +00:00
|
|
|
#define PCI_QLOGIC_ISP2100 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP2100 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
#define PCI_QLOGIC_ISP2200 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP2200 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
2001-08-31 21:39:04 +00:00
|
|
|
#define PCI_QLOGIC_ISP2300 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP2300 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
|
|
|
#define PCI_QLOGIC_ISP2312 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP2312 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
2006-01-23 06:23:37 +00:00
|
|
|
#define PCI_QLOGIC_ISP2322 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP2322 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
2006-01-26 06:15:58 +00:00
|
|
|
#define PCI_QLOGIC_ISP2422 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP2422 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
2005-01-23 06:23:55 +00:00
|
|
|
#define PCI_QLOGIC_ISP6312 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP6312 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
#define PCI_QLOGIC_ISP6322 \
|
|
|
|
((PCI_PRODUCT_QLOGIC_ISP6322 << 16) | PCI_VENDOR_QLOGIC)
|
|
|
|
|
2000-09-07 20:27:40 +00:00
|
|
|
/*
|
|
|
|
* Odd case for some AMI raid cards... We need to *not* attach to this.
|
|
|
|
*/
|
|
|
|
#define AMI_RAID_SUBVENDOR_ID 0x101e
|
|
|
|
|
1999-03-17 05:07:18 +00:00
|
|
|
#define IO_MAP_REG 0x10
|
|
|
|
#define MEM_MAP_REG 0x14
|
1998-04-22 18:12:29 +00:00
|
|
|
|
1999-02-09 01:12:52 +00:00
|
|
|
#define PCI_DFLT_LTNCY 0x40
|
|
|
|
#define PCI_DFLT_LNSZ 0x10
|
1998-04-22 18:12:29 +00:00
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
static int isp_pci_probe (device_t);
|
|
|
|
static int isp_pci_attach (device_t);
|
2006-11-02 03:21:32 +00:00
|
|
|
static int isp_pci_detach (device_t);
|
1998-04-22 18:12:29 +00:00
|
|
|
|
2002-04-02 23:36:14 +00:00
|
|
|
|
1998-04-22 18:12:29 +00:00
|
|
|
struct isp_pcisoftc {
|
2006-04-21 18:30:01 +00:00
|
|
|
ispsoftc_t pci_isp;
|
2000-02-11 19:45:17 +00:00
|
|
|
device_t pci_dev;
|
|
|
|
struct resource * pci_reg;
|
1998-09-15 10:06:23 +00:00
|
|
|
bus_space_tag_t pci_st;
|
|
|
|
bus_space_handle_t pci_sh;
|
2000-02-11 19:45:17 +00:00
|
|
|
void * ih;
|
1999-03-17 05:07:18 +00:00
|
|
|
int16_t pci_poff[_NREG_BLKS];
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_dma_tag_t dmat;
|
1999-10-17 19:03:11 +00:00
|
|
|
bus_dmamap_t *dmaps;
|
1998-04-22 18:12:29 +00:00
|
|
|
};
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
static device_method_t isp_pci_methods[] = {
|
|
|
|
/* Device interface */
|
|
|
|
DEVMETHOD(device_probe, isp_pci_probe),
|
|
|
|
DEVMETHOD(device_attach, isp_pci_attach),
|
2006-11-02 03:21:32 +00:00
|
|
|
DEVMETHOD(device_detach, isp_pci_detach),
|
2000-02-11 19:45:17 +00:00
|
|
|
{ 0, 0 }
|
1998-04-22 18:12:29 +00:00
|
|
|
};
|
2001-08-31 21:39:04 +00:00
|
|
|
static void isp_pci_intr(void *);
|
1998-04-22 18:12:29 +00:00
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
static driver_t isp_pci_driver = {
|
|
|
|
"isp", isp_pci_methods, sizeof (struct isp_pcisoftc)
|
|
|
|
};
|
|
|
|
static devclass_t isp_devclass;
|
|
|
|
DRIVER_MODULE(isp, pci, isp_pci_driver, isp_devclass, 0, 0);
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
#if __FreeBSD_version >= 700000
|
|
|
|
MODULE_DEPEND(isp, ispfw, 1, 1, 1);
|
|
|
|
MODULE_DEPEND(isp, firmware, 1, 1, 1);
|
|
|
|
#else
|
|
|
|
extern ispfwfunc *isp_get_firmware_p;
|
|
|
|
#endif
|
1998-04-22 18:12:29 +00:00
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
static int
|
|
|
|
isp_pci_probe(device_t dev)
|
1999-03-17 05:07:18 +00:00
|
|
|
{
|
2000-02-11 19:45:17 +00:00
|
|
|
switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) {
|
2000-06-18 05:18:55 +00:00
|
|
|
case PCI_QLOGIC_ISP1020:
|
2000-02-11 19:45:17 +00:00
|
|
|
device_set_desc(dev, "Qlogic ISP 1020/1040 PCI SCSI Adapter");
|
1999-03-17 05:07:18 +00:00
|
|
|
break;
|
|
|
|
case PCI_QLOGIC_ISP1080:
|
2000-02-11 19:45:17 +00:00
|
|
|
device_set_desc(dev, "Qlogic ISP 1080 PCI SCSI Adapter");
|
1999-05-11 04:53:57 +00:00
|
|
|
break;
|
|
|
|
case PCI_QLOGIC_ISP1240:
|
2000-02-11 19:45:17 +00:00
|
|
|
device_set_desc(dev, "Qlogic ISP 1240 PCI SCSI Adapter");
|
1998-04-22 18:12:29 +00:00
|
|
|
break;
|
1999-12-16 05:42:02 +00:00
|
|
|
case PCI_QLOGIC_ISP1280:
|
2000-02-11 19:45:17 +00:00
|
|
|
device_set_desc(dev, "Qlogic ISP 1280 PCI SCSI Adapter");
|
|
|
|
break;
|
2002-10-11 17:28:01 +00:00
|
|
|
case PCI_QLOGIC_ISP10160:
|
|
|
|
device_set_desc(dev, "Qlogic ISP 10160 PCI SCSI Adapter");
|
|
|
|
break;
|
2000-02-11 19:45:17 +00:00
|
|
|
case PCI_QLOGIC_ISP12160:
|
2000-09-07 20:27:40 +00:00
|
|
|
if (pci_get_subvendor(dev) == AMI_RAID_SUBVENDOR_ID) {
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
device_set_desc(dev, "Qlogic ISP 12160 PCI SCSI Adapter");
|
1999-12-16 05:42:02 +00:00
|
|
|
break;
|
1998-04-22 18:12:29 +00:00
|
|
|
case PCI_QLOGIC_ISP2100:
|
2000-02-11 19:45:17 +00:00
|
|
|
device_set_desc(dev, "Qlogic ISP 2100 PCI FC-AL Adapter");
|
1998-04-22 18:12:29 +00:00
|
|
|
break;
|
1999-07-05 20:24:46 +00:00
|
|
|
case PCI_QLOGIC_ISP2200:
|
2000-02-11 19:45:17 +00:00
|
|
|
device_set_desc(dev, "Qlogic ISP 2200 PCI FC-AL Adapter");
|
1999-07-05 20:24:46 +00:00
|
|
|
break;
|
2001-08-31 21:39:04 +00:00
|
|
|
case PCI_QLOGIC_ISP2300:
|
|
|
|
device_set_desc(dev, "Qlogic ISP 2300 PCI FC-AL Adapter");
|
|
|
|
break;
|
|
|
|
case PCI_QLOGIC_ISP2312:
|
|
|
|
device_set_desc(dev, "Qlogic ISP 2312 PCI FC-AL Adapter");
|
|
|
|
break;
|
2006-01-23 06:23:37 +00:00
|
|
|
case PCI_QLOGIC_ISP2322:
|
|
|
|
device_set_desc(dev, "Qlogic ISP 2322 PCI FC-AL Adapter");
|
|
|
|
break;
|
2006-01-26 05:04:35 +00:00
|
|
|
case PCI_QLOGIC_ISP2422:
|
|
|
|
device_set_desc(dev, "Qlogic ISP 2422 PCI FC-AL Adapter");
|
|
|
|
break;
|
2005-01-23 06:23:55 +00:00
|
|
|
case PCI_QLOGIC_ISP6312:
|
|
|
|
device_set_desc(dev, "Qlogic ISP 6312 PCI FC-AL Adapter");
|
|
|
|
break;
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
case PCI_QLOGIC_ISP6322:
|
|
|
|
device_set_desc(dev, "Qlogic ISP 6322 PCI FC-AL Adapter");
|
|
|
|
break;
|
1998-04-22 18:12:29 +00:00
|
|
|
default:
|
2000-02-11 19:45:17 +00:00
|
|
|
return (ENXIO);
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
2002-07-11 03:25:04 +00:00
|
|
|
if (isp_announced == 0 && bootverbose) {
|
2000-08-01 05:16:49 +00:00
|
|
|
printf("Qlogic ISP Driver, FreeBSD Version %d.%d, "
|
1999-10-17 19:03:11 +00:00
|
|
|
"Core Version %d.%d\n",
|
1998-09-15 10:06:23 +00:00
|
|
|
ISP_PLATFORM_VERSION_MAJOR, ISP_PLATFORM_VERSION_MINOR,
|
|
|
|
ISP_CORE_VERSION_MAJOR, ISP_CORE_VERSION_MINOR);
|
2002-07-11 03:25:04 +00:00
|
|
|
isp_announced++;
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
2000-06-18 05:18:55 +00:00
|
|
|
/*
|
|
|
|
* XXXX: Here is where we might load the f/w module
|
|
|
|
* XXXX: (or increase a reference count to it).
|
|
|
|
*/
|
2005-03-05 18:17:35 +00:00
|
|
|
return (BUS_PROBE_DEFAULT);
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
#if __FreeBSD_version < 500000
|
|
|
|
static void
|
|
|
|
isp_get_options(device_t dev, ispsoftc_t *isp)
|
1998-04-22 18:12:29 +00:00
|
|
|
{
|
2006-04-21 18:30:01 +00:00
|
|
|
uint64_t wwn;
|
|
|
|
int bitmap, unit;
|
|
|
|
|
|
|
|
unit = device_get_unit(dev);
|
|
|
|
if (getenv_int("isp_disable", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit)) {
|
|
|
|
isp->isp_osinfo.disabled = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getenv_int("isp_no_fwload", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit))
|
|
|
|
isp->isp_confopts |= ISP_CFG_NORELOAD;
|
|
|
|
}
|
|
|
|
if (getenv_int("isp_fwload", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit))
|
|
|
|
isp->isp_confopts &= ~ISP_CFG_NORELOAD;
|
|
|
|
}
|
|
|
|
if (getenv_int("isp_no_nvram", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit))
|
|
|
|
isp->isp_confopts |= ISP_CFG_NONVRAM;
|
|
|
|
}
|
|
|
|
if (getenv_int("isp_nvram", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit))
|
|
|
|
isp->isp_confopts &= ~ISP_CFG_NONVRAM;
|
|
|
|
}
|
|
|
|
if (getenv_int("isp_fcduplex", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit))
|
|
|
|
isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
|
|
|
|
}
|
|
|
|
if (getenv_int("isp_no_fcduplex", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit))
|
|
|
|
isp->isp_confopts &= ~ISP_CFG_FULL_DUPLEX;
|
|
|
|
}
|
|
|
|
if (getenv_int("isp_nport", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit))
|
|
|
|
isp->isp_confopts |= ISP_CFG_NPORT;
|
|
|
|
}
|
1998-04-22 18:12:29 +00:00
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
/*
|
|
|
|
* Because the resource_*_value functions can neither return
|
|
|
|
* 64 bit integer values, nor can they be directly coerced
|
|
|
|
* to interpret the right hand side of the assignment as
|
|
|
|
* you want them to interpret it, we have to force WWN
|
|
|
|
* hint replacement to specify WWN strings with a leading
|
|
|
|
* 'w' (e..g w50000000aaaa0001). Sigh.
|
|
|
|
*/
|
|
|
|
if (getenv_quad("isp_portwwn", &wwn)) {
|
|
|
|
isp->isp_osinfo.default_port_wwn = wwn;
|
|
|
|
isp->isp_confopts |= ISP_CFG_OWNWWPN;
|
|
|
|
}
|
|
|
|
if (isp->isp_osinfo.default_port_wwn == 0) {
|
|
|
|
isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (getenv_quad("isp_nodewwn", &wwn)) {
|
|
|
|
isp->isp_osinfo.default_node_wwn = wwn;
|
|
|
|
isp->isp_confopts |= ISP_CFG_OWNWWNN;
|
|
|
|
}
|
|
|
|
if (isp->isp_osinfo.default_node_wwn == 0) {
|
|
|
|
isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull;
|
|
|
|
}
|
|
|
|
|
|
|
|
bitmap = 0;
|
|
|
|
(void) getenv_int("isp_debug", &bitmap);
|
|
|
|
if (bitmap) {
|
|
|
|
isp->isp_dblev = bitmap;
|
|
|
|
} else {
|
|
|
|
isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
|
|
|
|
}
|
|
|
|
if (bootverbose) {
|
|
|
|
isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
|
|
|
|
}
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
bitmap = 0;
|
|
|
|
(void) getenv_int("isp_fabric_hysteresis", &bitmap);
|
|
|
|
if (bitmap >= 0 && bitmap < 256) {
|
|
|
|
isp->isp_osinfo.hysteresis = bitmap;
|
|
|
|
} else {
|
|
|
|
isp->isp_osinfo.hysteresis = isp_fabric_hysteresis;
|
|
|
|
}
|
|
|
|
|
|
|
|
bitmap = 0;
|
|
|
|
(void) getenv_int("isp_loop_down_limit", &bitmap);
|
|
|
|
if (bitmap >= 0 && bitmap < 0xffff) {
|
|
|
|
isp->isp_osinfo.loop_down_limit = bitmap;
|
|
|
|
} else {
|
|
|
|
isp->isp_osinfo.loop_down_limit = isp_loop_down_limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
#ifdef ISP_FW_CRASH_DUMP
|
|
|
|
bitmap = 0;
|
|
|
|
if (getenv_int("isp_fw_dump_enable", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit) {
|
|
|
|
size_t amt = 0;
|
|
|
|
if (IS_2200(isp)) {
|
|
|
|
amt = QLA2200_RISC_IMAGE_DUMP_SIZE;
|
|
|
|
} else if (IS_23XX(isp)) {
|
|
|
|
amt = QLA2300_RISC_IMAGE_DUMP_SIZE;
|
|
|
|
}
|
|
|
|
if (amt) {
|
|
|
|
FCPARAM(isp)->isp_dump_data =
|
|
|
|
malloc(amt, M_DEVBUF, M_WAITOK);
|
2006-05-22 06:51:48 +00:00
|
|
|
memset(FCPARAM(isp)->isp_dump_data, 0, amt);
|
2006-04-21 18:30:01 +00:00
|
|
|
} else {
|
|
|
|
device_printf(dev,
|
|
|
|
"f/w crash dumps not supported for card\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2006-08-21 00:46:10 +00:00
|
|
|
bitmap = 0;
|
|
|
|
if (getenv_int("role", &bitmap)) {
|
|
|
|
isp->isp_role = bitmap;
|
|
|
|
} else {
|
|
|
|
isp->isp_role = ISP_DEFAULT_ROLES;
|
|
|
|
}
|
2006-04-21 18:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
isp_get_pci_options(device_t dev, int *m1, int *m2)
|
|
|
|
{
|
|
|
|
int bitmap;
|
|
|
|
int unit = device_get_unit(dev);
|
|
|
|
|
|
|
|
*m1 = PCIM_CMD_MEMEN;
|
|
|
|
*m2 = PCIM_CMD_PORTEN;
|
|
|
|
if (getenv_int("isp_mem_map", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit)) {
|
|
|
|
*m1 = PCIM_CMD_MEMEN;
|
|
|
|
*m2 = PCIM_CMD_PORTEN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bitmap = 0;
|
|
|
|
if (getenv_int("isp_io_map", &bitmap)) {
|
|
|
|
if (bitmap & (1 << unit)) {
|
|
|
|
*m1 = PCIM_CMD_PORTEN;
|
|
|
|
*m2 = PCIM_CMD_MEMEN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static void
|
|
|
|
isp_get_options(device_t dev, ispsoftc_t *isp)
|
|
|
|
{
|
|
|
|
int tval;
|
|
|
|
const char *sptr;
|
1999-07-06 01:24:20 +00:00
|
|
|
/*
|
|
|
|
* Figure out if we're supposed to skip this one.
|
|
|
|
*/
|
2001-03-01 02:21:36 +00:00
|
|
|
|
|
|
|
tval = 0;
|
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"disable", &tval) == 0 && tval) {
|
2006-04-21 18:30:01 +00:00
|
|
|
device_printf(dev, "disabled at user request\n");
|
|
|
|
isp->isp_osinfo.disabled = 1;
|
|
|
|
return;
|
2001-02-11 03:53:23 +00:00
|
|
|
}
|
2001-03-01 02:21:36 +00:00
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
tval = -1;
|
2001-03-01 02:21:36 +00:00
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
2006-04-21 18:30:01 +00:00
|
|
|
"role", &tval) == 0 && tval != -1) {
|
|
|
|
tval &= (ISP_ROLE_INITIATOR|ISP_ROLE_TARGET);
|
|
|
|
isp->isp_role = tval;
|
|
|
|
device_printf(dev, "setting role to 0x%x\n", isp->isp_role);
|
2001-03-01 02:21:36 +00:00
|
|
|
} else {
|
2001-02-11 03:53:23 +00:00
|
|
|
#ifdef ISP_TARGET_MODE
|
2006-04-21 18:30:01 +00:00
|
|
|
isp->isp_role = ISP_ROLE_TARGET;
|
2001-02-11 03:53:23 +00:00
|
|
|
#else
|
2006-04-21 18:30:01 +00:00
|
|
|
isp->isp_role = ISP_DEFAULT_ROLES;
|
2001-02-11 03:53:23 +00:00
|
|
|
#endif
|
1999-07-06 01:24:20 +00:00
|
|
|
}
|
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
tval = 0;
|
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"fwload_disable", &tval) == 0 && tval != 0) {
|
|
|
|
isp->isp_confopts |= ISP_CFG_NORELOAD;
|
|
|
|
}
|
|
|
|
tval = 0;
|
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"ignore_nvram", &tval) == 0 && tval != 0) {
|
|
|
|
isp->isp_confopts |= ISP_CFG_NONVRAM;
|
|
|
|
}
|
|
|
|
tval = 0;
|
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"fullduplex", &tval) == 0 && tval != 0) {
|
|
|
|
isp->isp_confopts |= ISP_CFG_FULL_DUPLEX;
|
|
|
|
}
|
|
|
|
#ifdef ISP_FW_CRASH_DUMP
|
|
|
|
tval = 0;
|
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"fw_dump_enable", &tval) == 0 && tval != 0) {
|
|
|
|
size_t amt = 0;
|
|
|
|
if (IS_2200(isp)) {
|
|
|
|
amt = QLA2200_RISC_IMAGE_DUMP_SIZE;
|
|
|
|
} else if (IS_23XX(isp)) {
|
|
|
|
amt = QLA2300_RISC_IMAGE_DUMP_SIZE;
|
|
|
|
}
|
|
|
|
if (amt) {
|
|
|
|
FCPARAM(isp)->isp_dump_data =
|
|
|
|
malloc(amt, M_DEVBUF, M_WAITOK | M_ZERO);
|
|
|
|
} else {
|
|
|
|
device_printf(dev,
|
|
|
|
"f/w crash dumps not supported for this model\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
sptr = 0;
|
|
|
|
if (resource_string_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"topology", (const char **) &sptr) == 0 && sptr != 0) {
|
|
|
|
if (strcmp(sptr, "lport") == 0) {
|
|
|
|
isp->isp_confopts |= ISP_CFG_LPORT;
|
|
|
|
} else if (strcmp(sptr, "nport") == 0) {
|
|
|
|
isp->isp_confopts |= ISP_CFG_NPORT;
|
|
|
|
} else if (strcmp(sptr, "lport-only") == 0) {
|
|
|
|
isp->isp_confopts |= ISP_CFG_LPORT_ONLY;
|
|
|
|
} else if (strcmp(sptr, "nport-only") == 0) {
|
|
|
|
isp->isp_confopts |= ISP_CFG_NPORT_ONLY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Because the resource_*_value functions can neither return
|
|
|
|
* 64 bit integer values, nor can they be directly coerced
|
|
|
|
* to interpret the right hand side of the assignment as
|
|
|
|
* you want them to interpret it, we have to force WWN
|
|
|
|
* hint replacement to specify WWN strings with a leading
|
|
|
|
* 'w' (e..g w50000000aaaa0001). Sigh.
|
|
|
|
*/
|
|
|
|
sptr = 0;
|
|
|
|
tval = resource_string_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"portwwn", (const char **) &sptr);
|
|
|
|
if (tval == 0 && sptr != 0 && *sptr++ == 'w') {
|
|
|
|
char *eptr = 0;
|
|
|
|
isp->isp_osinfo.default_port_wwn = strtouq(sptr, &eptr, 16);
|
|
|
|
if (eptr < sptr + 16 || isp->isp_osinfo.default_port_wwn == 0) {
|
|
|
|
device_printf(dev, "mangled portwwn hint '%s'\n", sptr);
|
|
|
|
isp->isp_osinfo.default_port_wwn = 0;
|
|
|
|
} else {
|
|
|
|
isp->isp_confopts |= ISP_CFG_OWNWWPN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isp->isp_osinfo.default_port_wwn == 0) {
|
|
|
|
isp->isp_osinfo.default_port_wwn = 0x400000007F000009ull;
|
|
|
|
}
|
|
|
|
|
|
|
|
sptr = 0;
|
|
|
|
tval = resource_string_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"nodewwn", (const char **) &sptr);
|
|
|
|
if (tval == 0 && sptr != 0 && *sptr++ == 'w') {
|
|
|
|
char *eptr = 0;
|
|
|
|
isp->isp_osinfo.default_node_wwn = strtouq(sptr, &eptr, 16);
|
|
|
|
if (eptr < sptr + 16 || isp->isp_osinfo.default_node_wwn == 0) {
|
|
|
|
device_printf(dev, "mangled nodewwn hint '%s'\n", sptr);
|
|
|
|
isp->isp_osinfo.default_node_wwn = 0;
|
|
|
|
} else {
|
|
|
|
isp->isp_confopts |= ISP_CFG_OWNWWNN;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (isp->isp_osinfo.default_node_wwn == 0) {
|
|
|
|
isp->isp_osinfo.default_node_wwn = 0x400000007F000009ull;
|
|
|
|
}
|
|
|
|
|
|
|
|
isp->isp_osinfo.default_id = -1;
|
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"iid", &tval) == 0) {
|
|
|
|
isp->isp_osinfo.default_id = tval;
|
|
|
|
isp->isp_confopts |= ISP_CFG_OWNLOOPID;
|
|
|
|
}
|
|
|
|
if (isp->isp_osinfo.default_id == -1) {
|
|
|
|
if (IS_FC(isp)) {
|
|
|
|
isp->isp_osinfo.default_id = 109;
|
|
|
|
} else {
|
|
|
|
isp->isp_osinfo.default_id = 7;
|
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
}
|
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
/*
|
|
|
|
* Set up logging levels.
|
|
|
|
*/
|
|
|
|
tval = 0;
|
|
|
|
(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"debug", &tval);
|
|
|
|
if (tval) {
|
|
|
|
isp->isp_dblev = tval;
|
|
|
|
} else {
|
|
|
|
isp->isp_dblev = ISP_LOGWARN|ISP_LOGERR;
|
|
|
|
}
|
|
|
|
if (bootverbose) {
|
|
|
|
isp->isp_dblev |= ISP_LOGCONFIG|ISP_LOGINFO;
|
|
|
|
}
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
tval = 0;
|
|
|
|
(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"hysteresis", &tval);
|
|
|
|
if (tval >= 0 && tval < 256) {
|
|
|
|
isp->isp_osinfo.hysteresis = tval;
|
|
|
|
} else {
|
|
|
|
isp->isp_osinfo.hysteresis = isp_fabric_hysteresis;
|
|
|
|
}
|
|
|
|
|
|
|
|
tval = 0;
|
|
|
|
(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"loop_down_limit", &tval);
|
|
|
|
if (tval >= 0 && tval < 0xffff) {
|
|
|
|
isp->isp_osinfo.loop_down_limit = tval;
|
|
|
|
} else {
|
|
|
|
isp->isp_osinfo.loop_down_limit = isp_loop_down_limit;
|
|
|
|
}
|
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
isp_get_pci_options(device_t dev, int *m1, int *m2)
|
|
|
|
{
|
|
|
|
int tval;
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
/*
|
2004-09-23 05:25:22 +00:00
|
|
|
* Which we should try first - memory mapping or i/o mapping?
|
|
|
|
*
|
|
|
|
* We used to try memory first followed by i/o on alpha, otherwise
|
|
|
|
* the reverse, but we should just try memory first all the time now.
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
*/
|
2006-04-21 18:30:01 +00:00
|
|
|
*m1 = PCIM_CMD_MEMEN;
|
|
|
|
*m2 = PCIM_CMD_PORTEN;
|
2001-03-01 02:21:36 +00:00
|
|
|
|
|
|
|
tval = 0;
|
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"prefer_iomap", &tval) == 0 && tval != 0) {
|
2006-04-21 18:30:01 +00:00
|
|
|
*m1 = PCIM_CMD_PORTEN;
|
|
|
|
*m2 = PCIM_CMD_MEMEN;
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
}
|
2001-03-01 02:21:36 +00:00
|
|
|
tval = 0;
|
|
|
|
if (resource_int_value(device_get_name(dev), device_get_unit(dev),
|
|
|
|
"prefer_memmap", &tval) == 0 && tval != 0) {
|
2006-04-21 18:30:01 +00:00
|
|
|
*m1 = PCIM_CMD_MEMEN;
|
|
|
|
*m2 = PCIM_CMD_PORTEN;
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
}
|
2006-04-21 18:30:01 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int
|
|
|
|
isp_pci_attach(device_t dev)
|
|
|
|
{
|
|
|
|
struct resource *regs, *irq;
|
|
|
|
int rtp, rgd, iqd, m1, m2;
|
|
|
|
uint32_t data, cmd, linesz, psize, basetype;
|
|
|
|
struct isp_pcisoftc *pcs;
|
|
|
|
ispsoftc_t *isp = NULL;
|
|
|
|
struct ispmdvec *mdvp;
|
|
|
|
#if __FreeBSD_version >= 500000
|
|
|
|
int locksetup = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
pcs = device_get_softc(dev);
|
|
|
|
if (pcs == NULL) {
|
|
|
|
device_printf(dev, "cannot get softc\n");
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
|
|
|
memset(pcs, 0, sizeof (*pcs));
|
|
|
|
pcs->pci_dev = dev;
|
|
|
|
isp = &pcs->pci_isp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get Generic Options
|
|
|
|
*/
|
|
|
|
isp_get_options(dev, isp);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if options have us disabled
|
|
|
|
*/
|
|
|
|
if (isp->isp_osinfo.disabled) {
|
|
|
|
/*
|
|
|
|
* But return zero to preserve unit numbering
|
|
|
|
*/
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get PCI options- which in this case are just mapping preferences.
|
|
|
|
*/
|
|
|
|
isp_get_pci_options(dev, &m1, &m2);
|
|
|
|
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
|
1999-04-04 01:14:02 +00:00
|
|
|
linesz = PCI_DFLT_LNSZ;
|
2000-02-11 19:45:17 +00:00
|
|
|
irq = regs = NULL;
|
|
|
|
rgd = rtp = iqd = 0;
|
|
|
|
|
2005-05-11 03:00:50 +00:00
|
|
|
cmd = pci_read_config(dev, PCIR_COMMAND, 2);
|
2000-02-11 19:45:17 +00:00
|
|
|
if (cmd & m1) {
|
|
|
|
rtp = (m1 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
|
|
|
|
rgd = (m1 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
|
2004-03-17 17:50:55 +00:00
|
|
|
regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE);
|
1999-02-09 01:12:52 +00:00
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
if (regs == NULL && (cmd & m2)) {
|
|
|
|
rtp = (m2 == PCIM_CMD_MEMEN)? SYS_RES_MEMORY : SYS_RES_IOPORT;
|
|
|
|
rgd = (m2 == PCIM_CMD_MEMEN)? MEM_MAP_REG : IO_MAP_REG;
|
2004-03-17 17:50:55 +00:00
|
|
|
regs = bus_alloc_resource_any(dev, rtp, &rgd, RF_ACTIVE);
|
2000-02-11 19:45:17 +00:00
|
|
|
}
|
|
|
|
if (regs == NULL) {
|
|
|
|
device_printf(dev, "unable to map any ports\n");
|
|
|
|
goto bad;
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
2006-04-21 18:30:01 +00:00
|
|
|
if (bootverbose) {
|
2000-12-05 07:38:41 +00:00
|
|
|
device_printf(dev, "using %s space register mapping\n",
|
2000-02-11 19:45:17 +00:00
|
|
|
(rgd == IO_MAP_REG)? "I/O" : "Memory");
|
2006-04-21 18:30:01 +00:00
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
pcs->pci_dev = dev;
|
|
|
|
pcs->pci_reg = regs;
|
|
|
|
pcs->pci_st = rman_get_bustag(regs);
|
|
|
|
pcs->pci_sh = rman_get_bushandle(regs);
|
1998-04-22 18:12:29 +00:00
|
|
|
|
1999-03-17 05:07:18 +00:00
|
|
|
pcs->pci_poff[BIU_BLOCK >> _BLK_REG_SHFT] = BIU_REGS_OFF;
|
|
|
|
pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] = PCI_MBOX_REGS_OFF;
|
|
|
|
pcs->pci_poff[SXP_BLOCK >> _BLK_REG_SHFT] = PCI_SXP_REGS_OFF;
|
|
|
|
pcs->pci_poff[RISC_BLOCK >> _BLK_REG_SHFT] = PCI_RISC_REGS_OFF;
|
|
|
|
pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] = DMA_REGS_OFF;
|
1999-05-11 04:53:57 +00:00
|
|
|
mdvp = &mdvec;
|
|
|
|
basetype = ISP_HA_SCSI_UNKNOWN;
|
|
|
|
psize = sizeof (sdparam);
|
2000-06-18 05:18:55 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP1020) {
|
1999-05-11 04:53:57 +00:00
|
|
|
mdvp = &mdvec;
|
|
|
|
basetype = ISP_HA_SCSI_UNKNOWN;
|
|
|
|
psize = sizeof (sdparam);
|
1999-03-17 05:07:18 +00:00
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP1080) {
|
1999-05-11 04:53:57 +00:00
|
|
|
mdvp = &mdvec_1080;
|
|
|
|
basetype = ISP_HA_SCSI_1080;
|
|
|
|
psize = sizeof (sdparam);
|
|
|
|
pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
|
|
|
|
ISP1080_DMA_REGS_OFF;
|
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP1240) {
|
1999-05-11 04:53:57 +00:00
|
|
|
mdvp = &mdvec_1080;
|
1999-12-16 05:42:02 +00:00
|
|
|
basetype = ISP_HA_SCSI_1240;
|
|
|
|
psize = 2 * sizeof (sdparam);
|
|
|
|
pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
|
|
|
|
ISP1080_DMA_REGS_OFF;
|
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP1280) {
|
1999-12-16 05:42:02 +00:00
|
|
|
mdvp = &mdvec_1080;
|
|
|
|
basetype = ISP_HA_SCSI_1280;
|
1999-05-11 04:53:57 +00:00
|
|
|
psize = 2 * sizeof (sdparam);
|
1999-03-17 05:07:18 +00:00
|
|
|
pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
|
2002-10-11 17:28:01 +00:00
|
|
|
ISP1080_DMA_REGS_OFF;
|
|
|
|
}
|
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP10160) {
|
|
|
|
mdvp = &mdvec_12160;
|
|
|
|
basetype = ISP_HA_SCSI_10160;
|
|
|
|
psize = sizeof (sdparam);
|
|
|
|
pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
|
1999-03-17 05:07:18 +00:00
|
|
|
ISP1080_DMA_REGS_OFF;
|
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP12160) {
|
|
|
|
mdvp = &mdvec_12160;
|
|
|
|
basetype = ISP_HA_SCSI_12160;
|
|
|
|
psize = 2 * sizeof (sdparam);
|
|
|
|
pcs->pci_poff[DMA_BLOCK >> _BLK_REG_SHFT] =
|
|
|
|
ISP1080_DMA_REGS_OFF;
|
|
|
|
}
|
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP2100) {
|
1999-05-11 04:53:57 +00:00
|
|
|
mdvp = &mdvec_2100;
|
|
|
|
basetype = ISP_HA_FC_2100;
|
|
|
|
psize = sizeof (fcparam);
|
1999-03-17 05:07:18 +00:00
|
|
|
pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
|
|
|
|
PCI_MBOX_REGS2100_OFF;
|
2000-02-11 19:45:17 +00:00
|
|
|
if (pci_get_revid(dev) < 3) {
|
1999-04-04 01:14:02 +00:00
|
|
|
/*
|
|
|
|
* XXX: Need to get the actual revision
|
|
|
|
* XXX: number of the 2100 FB. At any rate,
|
|
|
|
* XXX: lower cache line size for early revision
|
|
|
|
* XXX; boards.
|
|
|
|
*/
|
|
|
|
linesz = 1;
|
|
|
|
}
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP2200) {
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
mdvp = &mdvec_2200;
|
|
|
|
basetype = ISP_HA_FC_2200;
|
|
|
|
psize = sizeof (fcparam);
|
|
|
|
pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
|
|
|
|
PCI_MBOX_REGS2100_OFF;
|
|
|
|
}
|
2002-02-04 21:04:25 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP2300) {
|
2001-08-31 21:39:04 +00:00
|
|
|
mdvp = &mdvec_2300;
|
|
|
|
basetype = ISP_HA_FC_2300;
|
|
|
|
psize = sizeof (fcparam);
|
|
|
|
pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
|
|
|
|
PCI_MBOX_REGS2300_OFF;
|
|
|
|
}
|
2005-01-23 06:23:55 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP2312 ||
|
|
|
|
pci_get_devid(dev) == PCI_QLOGIC_ISP6312) {
|
2002-02-04 21:04:25 +00:00
|
|
|
mdvp = &mdvec_2300;
|
|
|
|
basetype = ISP_HA_FC_2312;
|
|
|
|
psize = sizeof (fcparam);
|
|
|
|
pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
|
|
|
|
PCI_MBOX_REGS2300_OFF;
|
|
|
|
}
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP2322 ||
|
|
|
|
pci_get_devid(dev) == PCI_QLOGIC_ISP6322) {
|
2006-01-23 06:23:37 +00:00
|
|
|
mdvp = &mdvec_2300;
|
|
|
|
basetype = ISP_HA_FC_2322;
|
|
|
|
psize = sizeof (fcparam);
|
|
|
|
pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
|
|
|
|
PCI_MBOX_REGS2300_OFF;
|
|
|
|
}
|
2006-01-26 05:04:35 +00:00
|
|
|
if (pci_get_devid(dev) == PCI_QLOGIC_ISP2422) {
|
2006-11-02 03:21:32 +00:00
|
|
|
mdvp = &mdvec_2400;
|
|
|
|
basetype = ISP_HA_FC_2400;
|
2006-01-26 05:04:35 +00:00
|
|
|
psize = sizeof (fcparam);
|
|
|
|
pcs->pci_poff[MBOX_BLOCK >> _BLK_REG_SHFT] =
|
2006-11-02 03:21:32 +00:00
|
|
|
PCI_MBOX_REGS2400_OFF;
|
2006-01-26 05:04:35 +00:00
|
|
|
}
|
1999-05-11 04:53:57 +00:00
|
|
|
isp = &pcs->pci_isp;
|
2000-12-08 21:51:06 +00:00
|
|
|
isp->isp_param = malloc(psize, M_DEVBUF, M_NOWAIT | M_ZERO);
|
1999-05-11 04:53:57 +00:00
|
|
|
if (isp->isp_param == NULL) {
|
2000-02-11 19:45:17 +00:00
|
|
|
device_printf(dev, "cannot allocate parameter data\n");
|
|
|
|
goto bad;
|
1999-05-11 04:53:57 +00:00
|
|
|
}
|
|
|
|
isp->isp_mdvec = mdvp;
|
|
|
|
isp->isp_type = basetype;
|
2000-02-11 19:45:17 +00:00
|
|
|
isp->isp_revision = pci_get_revid(dev);
|
2001-03-01 02:21:36 +00:00
|
|
|
isp->isp_dev = dev;
|
1998-04-22 18:12:29 +00:00
|
|
|
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
#if __FreeBSD_version >= 700000
|
2000-06-18 05:18:55 +00:00
|
|
|
/*
|
|
|
|
* Try and find firmware for this device.
|
|
|
|
*/
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
{
|
|
|
|
char fwname[32];
|
|
|
|
unsigned int did = pci_get_device(dev);
|
2000-06-18 05:18:55 +00:00
|
|
|
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
/*
|
|
|
|
* Map a few pci ids to fw names
|
|
|
|
*/
|
|
|
|
switch (did) {
|
|
|
|
case PCI_PRODUCT_QLOGIC_ISP1020:
|
|
|
|
did = 0x1040;
|
|
|
|
break;
|
|
|
|
case PCI_PRODUCT_QLOGIC_ISP1240:
|
|
|
|
did = 0x1080;
|
|
|
|
break;
|
|
|
|
case PCI_PRODUCT_QLOGIC_ISP10160:
|
|
|
|
case PCI_PRODUCT_QLOGIC_ISP12160:
|
|
|
|
did = 0x12160;
|
|
|
|
break;
|
|
|
|
case PCI_PRODUCT_QLOGIC_ISP6312:
|
|
|
|
case PCI_PRODUCT_QLOGIC_ISP2312:
|
|
|
|
did = 0x2300;
|
|
|
|
break;
|
|
|
|
case PCI_PRODUCT_QLOGIC_ISP6322:
|
|
|
|
did = 0x2322;
|
|
|
|
break;
|
2006-11-02 03:21:32 +00:00
|
|
|
case PCI_PRODUCT_QLOGIC_ISP2422:
|
|
|
|
did = 0x2400;
|
|
|
|
break;
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
isp->isp_osinfo.fw = NULL;
|
|
|
|
if (isp->isp_role & ISP_ROLE_TARGET) {
|
|
|
|
snprintf(fwname, sizeof (fwname), "isp_%04x_it", did);
|
|
|
|
isp->isp_osinfo.fw = firmware_get(fwname);
|
|
|
|
}
|
|
|
|
if (isp->isp_osinfo.fw == NULL) {
|
|
|
|
snprintf(fwname, sizeof (fwname), "isp_%04x", did);
|
|
|
|
isp->isp_osinfo.fw = firmware_get(fwname);
|
|
|
|
}
|
|
|
|
if (isp->isp_osinfo.fw != NULL) {
|
|
|
|
union {
|
|
|
|
const void *fred;
|
|
|
|
uint16_t *bob;
|
|
|
|
} u;
|
|
|
|
u.fred = isp->isp_osinfo.fw->data;
|
|
|
|
isp->isp_mdvec->dv_ispfw = u.bob;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
2006-07-03 08:24:09 +00:00
|
|
|
if (isp_get_firmware_p) {
|
2000-06-18 05:18:55 +00:00
|
|
|
int device = (int) pci_get_device(dev);
|
|
|
|
#ifdef ISP_TARGET_MODE
|
|
|
|
(*isp_get_firmware_p)(0, 1, device, &mdvp->dv_ispfw);
|
|
|
|
#else
|
|
|
|
(*isp_get_firmware_p)(0, 0, device, &mdvp->dv_ispfw);
|
|
|
|
#endif
|
|
|
|
}
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
#endif
|
2000-06-18 05:18:55 +00:00
|
|
|
|
1999-02-09 01:12:52 +00:00
|
|
|
/*
|
|
|
|
* Make sure that SERR, PERR, WRITE INVALIDATE and BUSMASTER
|
|
|
|
* are set.
|
|
|
|
*/
|
2000-02-11 19:45:17 +00:00
|
|
|
cmd |= PCIM_CMD_SEREN | PCIM_CMD_PERRESPEN |
|
|
|
|
PCIM_CMD_BUSMASTEREN | PCIM_CMD_INVEN;
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
|
2002-02-04 21:04:25 +00:00
|
|
|
if (IS_2300(isp)) { /* per QLogic errata */
|
|
|
|
cmd &= ~PCIM_CMD_INVEN;
|
|
|
|
}
|
Convert isp(4) and ispfw(4) to use firmware(9) to manage firmware
loading for the QLogic cards.
Because isp(4) exists before the root is mounted, it's not really
possible for us to use the kernel's linker to load modules directly
from disk- that's really too bad.
However, the this is still a net win in in that the firmware has
been split up on a per chip (and in some cases, functionality)
basis, so the amount of stuff loaded *can* be substantially less
than the 1.5MB of firmware images that ispfw now manages. That is,
each specific f/w set is now also built as a module. For example,
QLogic 2322 f/w is built as isp_2322.ko and Initiator/Target 1080
firmware is built as isp_1080_it.ko.
For compatibility purposes (i.e., to perturb folks the least), we
also still build all of the firmware as one ispfw.ko module.
This allows us to let 'ispfw_LOAD' keep on working in existing
loader.conf files. If you now want to strip this down to just
the firmware for your h/w, you can then change loader.conf to
load the f/w you specifically want.
We also still allow for ispfw to be statically built (e.g., for
PAE and sparc64).
Future changes will look at f/w unloading and also role switching
that then uses the kernel linker to load different ips f/w sets.
MFC after: 2 months
2006-07-09 17:50:20 +00:00
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
if (IS_2322(isp) || pci_get_devid(dev) == PCI_QLOGIC_ISP6312) {
|
|
|
|
cmd &= ~PCIM_CMD_INTX_DISABLE;
|
2002-06-16 04:58:00 +00:00
|
|
|
}
|
2006-07-03 08:24:09 +00:00
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
if (IS_24XX(isp)) {
|
|
|
|
int reg;
|
|
|
|
|
2006-07-03 08:24:09 +00:00
|
|
|
cmd &= ~PCIM_CMD_INTX_DISABLE;
|
2006-11-02 03:21:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Is this a PCI-X card? If so, set max read byte count.
|
|
|
|
*/
|
|
|
|
if (pci_find_extcap(dev, PCIY_PCIX, ®) == 0) {
|
|
|
|
uint16_t pxcmd;
|
|
|
|
reg += 2;
|
|
|
|
|
|
|
|
pxcmd = pci_read_config(dev, reg, 2);
|
|
|
|
pxcmd &= ~0xc;
|
|
|
|
pxcmd |= 0x8;
|
|
|
|
pci_write_config(dev, reg, 2, pxcmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Is this a PCI Express card? If so, set max read byte count.
|
|
|
|
*/
|
|
|
|
if (pci_find_extcap(dev, PCIY_EXPRESS, ®) == 0) {
|
|
|
|
uint16_t pectl;
|
|
|
|
|
|
|
|
reg += 0x8;
|
|
|
|
pectl = pci_read_config(dev, reg, 2);
|
|
|
|
pectl &= ~0x7000;
|
|
|
|
pectl |= 0x4000;
|
|
|
|
pci_write_config(dev, reg, 2, pectl);
|
|
|
|
}
|
2006-07-03 08:24:09 +00:00
|
|
|
}
|
|
|
|
|
2005-05-11 03:00:50 +00:00
|
|
|
pci_write_config(dev, PCIR_COMMAND, cmd, 2);
|
1999-04-04 01:14:02 +00:00
|
|
|
|
1999-02-09 01:12:52 +00:00
|
|
|
/*
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
* Make sure the Cache Line Size register is set sensibly.
|
1999-02-09 01:12:52 +00:00
|
|
|
*/
|
2000-02-11 19:45:17 +00:00
|
|
|
data = pci_read_config(dev, PCIR_CACHELNSZ, 1);
|
1999-04-04 01:14:02 +00:00
|
|
|
if (data != linesz) {
|
1999-02-09 01:12:52 +00:00
|
|
|
data = PCI_DFLT_LNSZ;
|
2000-08-01 05:16:49 +00:00
|
|
|
isp_prt(isp, ISP_LOGCONFIG, "set PCI line size to %d", data);
|
2000-02-11 19:45:17 +00:00
|
|
|
pci_write_config(dev, PCIR_CACHELNSZ, data, 1);
|
1999-02-09 01:12:52 +00:00
|
|
|
}
|
1999-04-04 01:14:02 +00:00
|
|
|
|
1999-02-09 01:12:52 +00:00
|
|
|
/*
|
|
|
|
* Make sure the Latency Timer is sane.
|
|
|
|
*/
|
2000-02-11 19:45:17 +00:00
|
|
|
data = pci_read_config(dev, PCIR_LATTIMER, 1);
|
1999-02-09 01:12:52 +00:00
|
|
|
if (data < PCI_DFLT_LTNCY) {
|
|
|
|
data = PCI_DFLT_LTNCY;
|
2000-08-01 05:16:49 +00:00
|
|
|
isp_prt(isp, ISP_LOGCONFIG, "set PCI latency to %d", data);
|
2000-02-11 19:45:17 +00:00
|
|
|
pci_write_config(dev, PCIR_LATTIMER, data, 1);
|
1999-02-09 01:12:52 +00:00
|
|
|
}
|
1999-04-04 01:14:02 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure we've disabled the ROM.
|
|
|
|
*/
|
2000-02-11 19:45:17 +00:00
|
|
|
data = pci_read_config(dev, PCIR_ROMADDR, 4);
|
1999-04-04 01:14:02 +00:00
|
|
|
data &= ~1;
|
2000-02-11 19:45:17 +00:00
|
|
|
pci_write_config(dev, PCIR_ROMADDR, data, 4);
|
2000-07-18 06:40:22 +00:00
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
iqd = 0;
|
2004-03-17 17:50:55 +00:00
|
|
|
irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &iqd,
|
|
|
|
RF_ACTIVE | RF_SHAREABLE);
|
2000-02-11 19:45:17 +00:00
|
|
|
if (irq == NULL) {
|
|
|
|
device_printf(dev, "could not allocate interrupt\n");
|
|
|
|
goto bad;
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
#if __FreeBSD_version >= 500000
|
2000-12-29 19:10:16 +00:00
|
|
|
/* Make sure the lock is set up. */
|
2002-04-04 21:03:38 +00:00
|
|
|
mtx_init(&isp->isp_osinfo.lock, "isp", NULL, MTX_DEF);
|
2000-12-29 19:10:16 +00:00
|
|
|
locksetup++;
|
2006-04-21 18:30:01 +00:00
|
|
|
#endif
|
2000-12-29 19:10:16 +00:00
|
|
|
|
2002-07-25 16:02:09 +00:00
|
|
|
if (bus_setup_intr(dev, irq, ISP_IFLAGS, isp_pci_intr, isp, &pcs->ih)) {
|
2000-02-11 19:45:17 +00:00
|
|
|
device_printf(dev, "could not setup interrupt\n");
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
2002-02-04 21:04:25 +00:00
|
|
|
/*
|
|
|
|
* Last minute checks...
|
|
|
|
*/
|
2006-11-02 03:21:32 +00:00
|
|
|
if (IS_23XX(isp) || IS_24XX(isp)) {
|
2002-02-04 21:04:25 +00:00
|
|
|
isp->isp_port = pci_get_function(dev);
|
|
|
|
}
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
if (IS_23XX(isp)) {
|
|
|
|
/*
|
|
|
|
* Can't tell if ROM will hang on 'ABOUT FIRMWARE' command.
|
|
|
|
*/
|
|
|
|
isp->isp_touched = 1;
|
|
|
|
}
|
|
|
|
|
2000-07-18 06:40:22 +00:00
|
|
|
/*
|
|
|
|
* Make sure we're in reset state.
|
|
|
|
*/
|
2000-10-25 04:40:49 +00:00
|
|
|
ISP_LOCK(isp);
|
1998-04-22 18:12:29 +00:00
|
|
|
isp_reset(isp);
|
|
|
|
if (isp->isp_state != ISP_RESETSTATE) {
|
2000-10-25 04:40:49 +00:00
|
|
|
ISP_UNLOCK(isp);
|
2000-02-11 19:45:17 +00:00
|
|
|
goto bad;
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
|
|
|
isp_init(isp);
|
2001-02-11 03:53:23 +00:00
|
|
|
if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_INITSTATE) {
|
|
|
|
isp_uninit(isp);
|
|
|
|
ISP_UNLOCK(isp);
|
|
|
|
goto bad;
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
|
|
|
isp_attach(isp);
|
2001-02-11 03:53:23 +00:00
|
|
|
if (isp->isp_role != ISP_ROLE_NONE && isp->isp_state != ISP_RUNSTATE) {
|
|
|
|
isp_uninit(isp);
|
|
|
|
ISP_UNLOCK(isp);
|
|
|
|
goto bad;
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
2000-06-18 05:18:55 +00:00
|
|
|
/*
|
|
|
|
* XXXX: Here is where we might unload the f/w module
|
|
|
|
* XXXX: (or decrease the reference count to it).
|
|
|
|
*/
|
2000-10-25 04:40:49 +00:00
|
|
|
ISP_UNLOCK(isp);
|
2006-11-02 03:21:32 +00:00
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
bad:
|
|
|
|
|
|
|
|
if (pcs && pcs->ih) {
|
|
|
|
(void) bus_teardown_intr(dev, irq, pcs->ih);
|
|
|
|
}
|
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
#if __FreeBSD_version >= 500000
|
2000-10-25 04:40:49 +00:00
|
|
|
if (locksetup && isp) {
|
|
|
|
mtx_destroy(&isp->isp_osinfo.lock);
|
|
|
|
}
|
2006-04-21 18:30:01 +00:00
|
|
|
#endif
|
2000-10-25 04:40:49 +00:00
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
if (irq) {
|
|
|
|
(void) bus_release_resource(dev, SYS_RES_IRQ, iqd, irq);
|
|
|
|
}
|
2000-10-25 04:40:49 +00:00
|
|
|
|
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
if (regs) {
|
|
|
|
(void) bus_release_resource(dev, rtp, rgd, regs);
|
|
|
|
}
|
2000-10-25 04:40:49 +00:00
|
|
|
|
2000-02-11 19:45:17 +00:00
|
|
|
if (pcs) {
|
2006-04-21 18:30:01 +00:00
|
|
|
if (pcs->pci_isp.isp_param) {
|
|
|
|
#ifdef ISP_FW_CRASH_DUMP
|
|
|
|
if (IS_FC(isp) && FCPARAM(isp)->isp_dump_data) {
|
|
|
|
free(FCPARAM(isp)->isp_dump_data, M_DEVBUF);
|
|
|
|
}
|
|
|
|
#endif
|
2000-02-11 19:45:17 +00:00
|
|
|
free(pcs->pci_isp.isp_param, M_DEVBUF);
|
2006-04-21 18:30:01 +00:00
|
|
|
}
|
2000-02-11 19:45:17 +00:00
|
|
|
}
|
2000-10-25 04:40:49 +00:00
|
|
|
|
2000-06-18 05:18:55 +00:00
|
|
|
/*
|
|
|
|
* XXXX: Here is where we might unload the f/w module
|
|
|
|
* XXXX: (or decrease the reference count to it).
|
|
|
|
*/
|
2000-02-11 19:45:17 +00:00
|
|
|
return (ENXIO);
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
static int
|
|
|
|
isp_pci_detach(device_t dev)
|
|
|
|
{
|
|
|
|
struct isp_pcisoftc *pcs;
|
|
|
|
ispsoftc_t *isp;
|
|
|
|
|
|
|
|
pcs = device_get_softc(dev);
|
|
|
|
if (pcs == NULL) {
|
|
|
|
return (ENXIO);
|
|
|
|
}
|
|
|
|
isp = (ispsoftc_t *) pcs;
|
|
|
|
ISP_DISABLE_INTS(isp);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2000-12-29 19:10:16 +00:00
|
|
|
static void
|
|
|
|
isp_pci_intr(void *arg)
|
|
|
|
{
|
2006-04-21 18:30:01 +00:00
|
|
|
ispsoftc_t *isp = arg;
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t isr;
|
|
|
|
uint16_t sema, mbox;
|
2001-08-31 21:39:04 +00:00
|
|
|
|
2000-12-29 19:10:16 +00:00
|
|
|
ISP_LOCK(isp);
|
2001-08-31 21:39:04 +00:00
|
|
|
isp->isp_intcnt++;
|
|
|
|
if (ISP_READ_ISR(isp, &isr, &sema, &mbox) == 0) {
|
|
|
|
isp->isp_intbogus++;
|
|
|
|
} else {
|
|
|
|
isp_intr(isp, isr, sema, mbox);
|
|
|
|
}
|
2000-12-29 19:10:16 +00:00
|
|
|
ISP_UNLOCK(isp);
|
|
|
|
}
|
|
|
|
|
2001-08-31 21:39:04 +00:00
|
|
|
|
|
|
|
#define IspVirt2Off(a, x) \
|
|
|
|
(((struct isp_pcisoftc *)a)->pci_poff[((x) & _BLK_REG_MASK) >> \
|
2006-08-14 05:36:26 +00:00
|
|
|
_BLK_REG_SHFT] + ((x) & 0xfff))
|
2001-08-31 21:39:04 +00:00
|
|
|
|
|
|
|
#define BXR2(pcs, off) \
|
|
|
|
bus_space_read_2(pcs->pci_st, pcs->pci_sh, off)
|
|
|
|
#define BXW2(pcs, off, v) \
|
|
|
|
bus_space_write_2(pcs->pci_st, pcs->pci_sh, off, v)
|
2006-11-02 03:21:32 +00:00
|
|
|
#define BXR4(pcs, off) \
|
|
|
|
bus_space_read_4(pcs->pci_st, pcs->pci_sh, off)
|
|
|
|
#define BXW4(pcs, off, v) \
|
|
|
|
bus_space_write_4(pcs->pci_st, pcs->pci_sh, off, v)
|
2001-08-31 21:39:04 +00:00
|
|
|
|
|
|
|
|
2006-02-02 21:31:34 +00:00
|
|
|
static __inline int
|
2006-04-21 18:30:01 +00:00
|
|
|
isp_pci_rd_debounced(ispsoftc_t *isp, int off, uint16_t *rp)
|
2001-08-31 21:39:04 +00:00
|
|
|
{
|
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t val0, val1;
|
2001-08-31 21:39:04 +00:00
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
val0 = BXR2(pcs, IspVirt2Off(isp, off));
|
|
|
|
val1 = BXR2(pcs, IspVirt2Off(isp, off));
|
|
|
|
} while (val0 != val1 && ++i < 1000);
|
|
|
|
if (val0 != val1) {
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
*rp = val0;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_pci_rd_isr(ispsoftc_t *isp, uint32_t *isrp,
|
2006-02-15 00:31:48 +00:00
|
|
|
uint16_t *semap, uint16_t *mbp)
|
2001-08-31 21:39:04 +00:00
|
|
|
{
|
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
2006-02-15 00:31:48 +00:00
|
|
|
uint16_t isr, sema;
|
2001-08-31 21:39:04 +00:00
|
|
|
|
|
|
|
if (IS_2100(isp)) {
|
|
|
|
if (isp_pci_rd_debounced(isp, BIU_ISR, &isr)) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
if (isp_pci_rd_debounced(isp, BIU_SEMA, &sema)) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
isr = BXR2(pcs, IspVirt2Off(isp, BIU_ISR));
|
|
|
|
sema = BXR2(pcs, IspVirt2Off(isp, BIU_SEMA));
|
|
|
|
}
|
|
|
|
isp_prt(isp, ISP_LOGDEBUG3, "ISR 0x%x SEMA 0x%x", isr, sema);
|
|
|
|
isr &= INT_PENDING_MASK(isp);
|
|
|
|
sema &= BIU_SEMA_LOCK;
|
|
|
|
if (isr == 0 && sema == 0) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
*isrp = isr;
|
|
|
|
if ((*semap = sema) != 0) {
|
|
|
|
if (IS_2100(isp)) {
|
|
|
|
if (isp_pci_rd_debounced(isp, OUTMAILBOX0, mbp)) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*mbp = BXR2(pcs, IspVirt2Off(isp, OUTMAILBOX0));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_pci_rd_isr_2300(ispsoftc_t *isp, uint32_t *isrp,
|
2006-02-15 00:31:48 +00:00
|
|
|
uint16_t *semap, uint16_t *mbox0p)
|
2001-08-31 21:39:04 +00:00
|
|
|
{
|
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t hccr;
|
2006-02-15 00:31:48 +00:00
|
|
|
uint32_t r2hisr;
|
2001-08-31 21:39:04 +00:00
|
|
|
|
2001-10-06 19:34:43 +00:00
|
|
|
if (!(BXR2(pcs, IspVirt2Off(isp, BIU_ISR) & BIU2100_ISR_RISC_INT))) {
|
|
|
|
*isrp = 0;
|
2001-10-06 19:19:24 +00:00
|
|
|
return (0);
|
2001-10-06 19:34:43 +00:00
|
|
|
}
|
2006-11-02 03:21:32 +00:00
|
|
|
r2hisr = BXR4(pcs, IspVirt2Off(pcs, BIU_R2HSTSLO));
|
2001-08-31 21:39:04 +00:00
|
|
|
isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr);
|
|
|
|
if ((r2hisr & BIU_R2HST_INTR) == 0) {
|
|
|
|
*isrp = 0;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
switch (r2hisr & BIU_R2HST_ISTAT_MASK) {
|
|
|
|
case ISPR2HST_ROM_MBX_OK:
|
|
|
|
case ISPR2HST_ROM_MBX_FAIL:
|
|
|
|
case ISPR2HST_MBX_OK:
|
|
|
|
case ISPR2HST_MBX_FAIL:
|
|
|
|
case ISPR2HST_ASYNC_EVENT:
|
2002-08-17 17:21:54 +00:00
|
|
|
*isrp = r2hisr & 0xffff;
|
|
|
|
*mbox0p = (r2hisr >> 16);
|
|
|
|
*semap = 1;
|
|
|
|
return (1);
|
2002-02-04 21:04:25 +00:00
|
|
|
case ISPR2HST_RIO_16:
|
2002-08-17 17:21:54 +00:00
|
|
|
*isrp = r2hisr & 0xffff;
|
|
|
|
*mbox0p = ASYNC_RIO1;
|
|
|
|
*semap = 1;
|
|
|
|
return (1);
|
2001-08-31 21:39:04 +00:00
|
|
|
case ISPR2HST_FPOST:
|
2002-08-17 17:21:54 +00:00
|
|
|
*isrp = r2hisr & 0xffff;
|
|
|
|
*mbox0p = ASYNC_CMD_CMPLT;
|
|
|
|
*semap = 1;
|
|
|
|
return (1);
|
2001-08-31 21:39:04 +00:00
|
|
|
case ISPR2HST_FPOST_CTIO:
|
|
|
|
*isrp = r2hisr & 0xffff;
|
2002-08-17 17:21:54 +00:00
|
|
|
*mbox0p = ASYNC_CTIO_DONE;
|
2001-08-31 21:39:04 +00:00
|
|
|
*semap = 1;
|
|
|
|
return (1);
|
|
|
|
case ISPR2HST_RSPQ_UPDATE:
|
|
|
|
*isrp = r2hisr & 0xffff;
|
|
|
|
*mbox0p = 0;
|
|
|
|
*semap = 0;
|
|
|
|
return (1);
|
|
|
|
default:
|
2006-07-03 08:24:09 +00:00
|
|
|
hccr = ISP_READ(isp, HCCR);
|
|
|
|
if (hccr & HCCR_PAUSE) {
|
|
|
|
ISP_WRITE(isp, HCCR, HCCR_RESET);
|
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"RISC paused at interrupt (%x->%x\n", hccr,
|
|
|
|
ISP_READ(isp, HCCR));
|
|
|
|
} else {
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x\n",
|
2006-07-03 08:24:09 +00:00
|
|
|
r2hisr);
|
|
|
|
}
|
2001-08-31 21:39:04 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
static int
|
|
|
|
isp_pci_rd_isr_2400(ispsoftc_t *isp, uint32_t *isrp,
|
|
|
|
uint16_t *semap, uint16_t *mbox0p)
|
|
|
|
{
|
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
|
|
uint32_t r2hisr;
|
|
|
|
|
|
|
|
r2hisr = BXR4(pcs, IspVirt2Off(pcs, BIU2400_R2HSTSLO));
|
|
|
|
isp_prt(isp, ISP_LOGDEBUG3, "RISC2HOST ISR 0x%x", r2hisr);
|
|
|
|
if ((r2hisr & BIU2400_R2HST_INTR) == 0) {
|
|
|
|
*isrp = 0;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
switch (r2hisr & BIU2400_R2HST_ISTAT_MASK) {
|
|
|
|
case ISP2400R2HST_ROM_MBX_OK:
|
|
|
|
case ISP2400R2HST_ROM_MBX_FAIL:
|
|
|
|
case ISP2400R2HST_MBX_OK:
|
|
|
|
case ISP2400R2HST_MBX_FAIL:
|
|
|
|
case ISP2400R2HST_ASYNC_EVENT:
|
|
|
|
*isrp = r2hisr & 0xffff;
|
|
|
|
*mbox0p = (r2hisr >> 16);
|
|
|
|
*semap = 1;
|
|
|
|
return (1);
|
|
|
|
case ISP2400R2HST_RSPQ_UPDATE:
|
|
|
|
case ISP2400R2HST_ATIO_RSPQ_UPDATE:
|
|
|
|
case ISP2400R2HST_ATIO_RQST_UPDATE:
|
|
|
|
*isrp = r2hisr & 0xffff;
|
|
|
|
*mbox0p = 0;
|
|
|
|
*semap = 0;
|
|
|
|
return (1);
|
|
|
|
default:
|
|
|
|
ISP_WRITE(isp, BIU2400_HCCR, HCCR_2400_CMD_CLEAR_RISC_INT);
|
|
|
|
isp_prt(isp, ISP_LOGERR, "unknown interrupt 0x%x\n", r2hisr);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
2006-04-21 18:30:01 +00:00
|
|
|
isp_pci_rd_reg(ispsoftc_t *isp, int regoff)
|
1999-03-17 05:07:18 +00:00
|
|
|
{
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t rv;
|
1999-03-17 05:07:18 +00:00
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
2001-08-31 21:39:04 +00:00
|
|
|
int oldconf = 0;
|
1998-04-22 18:12:29 +00:00
|
|
|
|
1999-03-17 05:07:18 +00:00
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
|
|
|
|
/*
|
|
|
|
* We will assume that someone has paused the RISC processor.
|
|
|
|
*/
|
2001-08-31 21:39:04 +00:00
|
|
|
oldconf = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1),
|
|
|
|
oldconf | BIU_PCI_CONF1_SXP);
|
1999-03-17 05:07:18 +00:00
|
|
|
}
|
2001-08-31 21:39:04 +00:00
|
|
|
rv = BXR2(pcs, IspVirt2Off(isp, regoff));
|
1999-03-17 05:07:18 +00:00
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
|
2001-08-31 21:39:04 +00:00
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf);
|
1999-03-17 05:07:18 +00:00
|
|
|
}
|
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_pci_wr_reg(ispsoftc_t *isp, int regoff, uint32_t val)
|
1999-03-17 05:07:18 +00:00
|
|
|
{
|
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
2001-08-31 21:39:04 +00:00
|
|
|
int oldconf = 0;
|
2006-11-02 03:21:32 +00:00
|
|
|
volatile int junk;
|
1999-03-17 05:07:18 +00:00
|
|
|
|
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
|
|
|
|
/*
|
|
|
|
* We will assume that someone has paused the RISC processor.
|
|
|
|
*/
|
2001-08-31 21:39:04 +00:00
|
|
|
oldconf = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1),
|
|
|
|
oldconf | BIU_PCI_CONF1_SXP);
|
2006-11-02 03:21:32 +00:00
|
|
|
junk = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
1999-03-17 05:07:18 +00:00
|
|
|
}
|
2001-08-31 21:39:04 +00:00
|
|
|
BXW2(pcs, IspVirt2Off(isp, regoff), val);
|
2006-11-02 03:21:32 +00:00
|
|
|
junk = BXR2(pcs, IspVirt2Off(isp, regoff));
|
1999-03-17 05:07:18 +00:00
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK) {
|
2001-08-31 21:39:04 +00:00
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oldconf);
|
2006-11-02 03:21:32 +00:00
|
|
|
junk = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
1999-03-17 05:07:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
static uint32_t
|
2006-04-21 18:30:01 +00:00
|
|
|
isp_pci_rd_reg_1080(ispsoftc_t *isp, int regoff)
|
1998-04-22 18:12:29 +00:00
|
|
|
{
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t rv, oc = 0;
|
1998-04-22 18:12:29 +00:00
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
1999-03-17 05:07:18 +00:00
|
|
|
|
1999-12-16 05:42:02 +00:00
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
|
|
|
|
(regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t tc;
|
1998-04-22 18:12:29 +00:00
|
|
|
/*
|
|
|
|
* We will assume that someone has paused the RISC processor.
|
|
|
|
*/
|
2001-08-31 21:39:04 +00:00
|
|
|
oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
1999-12-16 05:42:02 +00:00
|
|
|
tc = oc & ~BIU_PCI1080_CONF1_DMA;
|
|
|
|
if (regoff & SXP_BANK1_SELECT)
|
|
|
|
tc |= BIU_PCI1080_CONF1_SXP1;
|
|
|
|
else
|
|
|
|
tc |= BIU_PCI1080_CONF1_SXP0;
|
2001-08-31 21:39:04 +00:00
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc);
|
1999-03-17 05:07:18 +00:00
|
|
|
} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
|
2001-08-31 21:39:04 +00:00
|
|
|
oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1),
|
|
|
|
oc | BIU_PCI1080_CONF1_DMA);
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
2001-08-31 21:39:04 +00:00
|
|
|
rv = BXR2(pcs, IspVirt2Off(isp, regoff));
|
1999-12-16 05:42:02 +00:00
|
|
|
if (oc) {
|
2001-08-31 21:39:04 +00:00
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc);
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_pci_wr_reg_1080(ispsoftc_t *isp, int regoff, uint32_t val)
|
1998-04-22 18:12:29 +00:00
|
|
|
{
|
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
2001-08-31 21:39:04 +00:00
|
|
|
int oc = 0;
|
2006-11-02 03:21:32 +00:00
|
|
|
volatile int junk;
|
1999-03-17 05:07:18 +00:00
|
|
|
|
1999-12-16 05:42:02 +00:00
|
|
|
if ((regoff & _BLK_REG_MASK) == SXP_BLOCK ||
|
|
|
|
(regoff & _BLK_REG_MASK) == (SXP_BLOCK|SXP_BANK1_SELECT)) {
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t tc;
|
1998-04-22 18:12:29 +00:00
|
|
|
/*
|
|
|
|
* We will assume that someone has paused the RISC processor.
|
|
|
|
*/
|
2001-08-31 21:39:04 +00:00
|
|
|
oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
1999-12-16 05:42:02 +00:00
|
|
|
tc = oc & ~BIU_PCI1080_CONF1_DMA;
|
|
|
|
if (regoff & SXP_BANK1_SELECT)
|
|
|
|
tc |= BIU_PCI1080_CONF1_SXP1;
|
|
|
|
else
|
|
|
|
tc |= BIU_PCI1080_CONF1_SXP0;
|
2001-08-31 21:39:04 +00:00
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), tc);
|
2006-11-02 03:21:32 +00:00
|
|
|
junk = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
1999-03-17 05:07:18 +00:00
|
|
|
} else if ((regoff & _BLK_REG_MASK) == DMA_BLOCK) {
|
2001-08-31 21:39:04 +00:00
|
|
|
oc = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1),
|
|
|
|
oc | BIU_PCI1080_CONF1_DMA);
|
2006-11-02 03:21:32 +00:00
|
|
|
junk = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
2001-08-31 21:39:04 +00:00
|
|
|
BXW2(pcs, IspVirt2Off(isp, regoff), val);
|
2006-11-02 03:21:32 +00:00
|
|
|
junk = BXR2(pcs, IspVirt2Off(isp, regoff));
|
1999-12-16 05:42:02 +00:00
|
|
|
if (oc) {
|
2001-08-31 21:39:04 +00:00
|
|
|
BXW2(pcs, IspVirt2Off(isp, BIU_CONF1), oc);
|
2006-11-02 03:21:32 +00:00
|
|
|
junk = BXR2(pcs, IspVirt2Off(isp, BIU_CONF1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
isp_pci_rd_reg_2400(ispsoftc_t *isp, int regoff)
|
|
|
|
{
|
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
|
|
uint32_t rv;
|
|
|
|
int block = regoff & _BLK_REG_MASK;
|
|
|
|
|
|
|
|
switch (block) {
|
|
|
|
case BIU_BLOCK:
|
|
|
|
break;
|
|
|
|
case MBOX_BLOCK:
|
|
|
|
return (BXR2(pcs, IspVirt2Off(pcs, regoff)));
|
|
|
|
case SXP_BLOCK:
|
|
|
|
isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK read at 0x%x", regoff);
|
|
|
|
return (0xffffffff);
|
|
|
|
case RISC_BLOCK:
|
|
|
|
isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK read at 0x%x", regoff);
|
|
|
|
return (0xffffffff);
|
|
|
|
case DMA_BLOCK:
|
|
|
|
isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK read at 0x%x", regoff);
|
|
|
|
return (0xffffffff);
|
|
|
|
default:
|
|
|
|
isp_prt(isp, ISP_LOGWARN, "unknown block read at 0x%x", regoff);
|
|
|
|
return (0xffffffff);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
switch (regoff) {
|
|
|
|
case BIU2400_FLASH_ADDR:
|
|
|
|
case BIU2400_FLASH_DATA:
|
|
|
|
case BIU2400_ICR:
|
|
|
|
case BIU2400_ISR:
|
|
|
|
case BIU2400_CSR:
|
|
|
|
case BIU2400_REQINP:
|
|
|
|
case BIU2400_REQOUTP:
|
|
|
|
case BIU2400_RSPINP:
|
|
|
|
case BIU2400_RSPOUTP:
|
|
|
|
case BIU2400_PRI_RQINP:
|
|
|
|
case BIU2400_PRI_RSPINP:
|
|
|
|
case BIU2400_ATIO_RSPINP:
|
|
|
|
case BIU2400_ATIO_REQINP:
|
|
|
|
case BIU2400_HCCR:
|
|
|
|
case BIU2400_GPIOD:
|
|
|
|
case BIU2400_GPIOE:
|
|
|
|
case BIU2400_HSEMA:
|
|
|
|
rv = BXR4(pcs, IspVirt2Off(pcs, regoff));
|
|
|
|
break;
|
|
|
|
case BIU2400_R2HSTSLO:
|
|
|
|
rv = BXR4(pcs, IspVirt2Off(pcs, regoff));
|
|
|
|
break;
|
|
|
|
case BIU2400_R2HSTSHI:
|
|
|
|
rv = BXR4(pcs, IspVirt2Off(pcs, regoff)) >> 16;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"isp_pci_rd_reg_2400: unknown offset %x", regoff);
|
|
|
|
rv = 0xffffffff;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
isp_pci_wr_reg_2400(ispsoftc_t *isp, int regoff, uint32_t val)
|
|
|
|
{
|
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *) isp;
|
|
|
|
int block = regoff & _BLK_REG_MASK;
|
|
|
|
volatile int junk;
|
|
|
|
|
|
|
|
switch (block) {
|
|
|
|
case BIU_BLOCK:
|
|
|
|
break;
|
|
|
|
case MBOX_BLOCK:
|
|
|
|
BXW2(pcs, IspVirt2Off(pcs, regoff), val);
|
|
|
|
junk = BXR2(pcs, IspVirt2Off(pcs, regoff));
|
|
|
|
return;
|
|
|
|
case SXP_BLOCK:
|
|
|
|
isp_prt(isp, ISP_LOGWARN, "SXP_BLOCK write at 0x%x", regoff);
|
|
|
|
return;
|
|
|
|
case RISC_BLOCK:
|
|
|
|
isp_prt(isp, ISP_LOGWARN, "RISC_BLOCK write at 0x%x", regoff);
|
|
|
|
return;
|
|
|
|
case DMA_BLOCK:
|
|
|
|
isp_prt(isp, ISP_LOGWARN, "DMA_BLOCK write at 0x%x", regoff);
|
|
|
|
return;
|
|
|
|
default:
|
|
|
|
isp_prt(isp, ISP_LOGWARN, "unknown block write at 0x%x",
|
|
|
|
regoff);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (regoff) {
|
|
|
|
case BIU2400_FLASH_ADDR:
|
|
|
|
case BIU2400_FLASH_DATA:
|
|
|
|
case BIU2400_ICR:
|
|
|
|
case BIU2400_ISR:
|
|
|
|
case BIU2400_CSR:
|
|
|
|
case BIU2400_REQINP:
|
|
|
|
case BIU2400_REQOUTP:
|
|
|
|
case BIU2400_RSPINP:
|
|
|
|
case BIU2400_RSPOUTP:
|
|
|
|
case BIU2400_PRI_RQINP:
|
|
|
|
case BIU2400_PRI_RSPINP:
|
|
|
|
case BIU2400_ATIO_RSPINP:
|
|
|
|
case BIU2400_ATIO_REQINP:
|
|
|
|
case BIU2400_HCCR:
|
|
|
|
case BIU2400_GPIOD:
|
|
|
|
case BIU2400_GPIOE:
|
|
|
|
case BIU2400_HSEMA:
|
|
|
|
BXW4(pcs, IspVirt2Off(pcs, regoff), val);
|
|
|
|
junk = BXR4(pcs, IspVirt2Off(pcs, regoff));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"isp_pci_wr_reg_2400: bad offset 0x%x", regoff);
|
|
|
|
break;
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-09-15 10:06:23 +00:00
|
|
|
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
struct imush {
|
2006-04-21 18:30:01 +00:00
|
|
|
ispsoftc_t *isp;
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
int error;
|
|
|
|
};
|
|
|
|
|
2002-04-02 23:36:14 +00:00
|
|
|
static void imc(void *, bus_dma_segment_t *, int, int);
|
1998-09-15 10:06:23 +00:00
|
|
|
|
|
|
|
static void
|
2002-04-02 23:36:14 +00:00
|
|
|
imc(void *arg, bus_dma_segment_t *segs, int nseg, int error)
|
1998-09-15 10:06:23 +00:00
|
|
|
{
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
struct imush *imushp = (struct imush *) arg;
|
|
|
|
if (error) {
|
|
|
|
imushp->error = error;
|
|
|
|
} else {
|
2006-04-21 18:30:01 +00:00
|
|
|
ispsoftc_t *isp =imushp->isp;
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_addr_t addr = segs->ds_addr;
|
1998-09-15 10:06:23 +00:00
|
|
|
|
2002-04-02 23:36:14 +00:00
|
|
|
isp->isp_rquest_dma = addr;
|
|
|
|
addr += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
|
|
|
|
isp->isp_result_dma = addr;
|
|
|
|
if (IS_FC(isp)) {
|
|
|
|
addr += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
|
|
|
|
FCPARAM(isp)->isp_scdma = addr;
|
|
|
|
}
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
}
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
|
2002-04-04 23:46:01 +00:00
|
|
|
/*
|
|
|
|
* Should be BUS_SPACE_MAXSIZE, but MAXPHYS is larger than BUS_SPACE_MAXSIZE
|
|
|
|
*/
|
|
|
|
#define ISP_NSEGS ((MAXPHYS / PAGE_SIZE) + 1)
|
2002-04-02 23:36:14 +00:00
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
#if __FreeBSD_version < 500000
|
2006-09-03 01:26:55 +00:00
|
|
|
#define BUS_DMA_ROOTARG NULL
|
|
|
|
#define isp_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z) \
|
|
|
|
bus_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z)
|
|
|
|
#elif __FreeBSD_version < 700020
|
|
|
|
#define BUS_DMA_ROOTARG NULL
|
|
|
|
#define isp_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z) \
|
|
|
|
bus_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, \
|
|
|
|
busdma_lock_mutex, &Giant, z)
|
2006-04-21 18:30:01 +00:00
|
|
|
#else
|
2006-09-03 01:26:55 +00:00
|
|
|
#define BUS_DMA_ROOTARG bus_get_dma_tag(pcs->pci_dev)
|
2006-04-21 18:30:01 +00:00
|
|
|
#define isp_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, z) \
|
|
|
|
bus_dma_tag_create(a, b, c, d, e, f, g, h, i, j, k, \
|
2006-09-03 01:26:55 +00:00
|
|
|
busdma_lock_mutex, &Giant, z)
|
2006-04-21 18:30:01 +00:00
|
|
|
#endif
|
|
|
|
|
1998-09-15 10:06:23 +00:00
|
|
|
static int
|
2006-04-21 18:30:01 +00:00
|
|
|
isp_pci_mbxdma(ispsoftc_t *isp)
|
1998-09-15 10:06:23 +00:00
|
|
|
{
|
2002-04-02 23:36:14 +00:00
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp;
|
1998-09-15 10:06:23 +00:00
|
|
|
caddr_t base;
|
2006-02-15 00:31:48 +00:00
|
|
|
uint32_t len;
|
2002-04-02 23:36:14 +00:00
|
|
|
int i, error, ns;
|
2006-02-02 21:31:34 +00:00
|
|
|
bus_size_t slim; /* segment size */
|
2006-02-04 03:41:48 +00:00
|
|
|
bus_addr_t llim; /* low limit of unavailable dma */
|
2006-02-04 08:39:02 +00:00
|
|
|
bus_addr_t hlim; /* high limit of unavailable dma */
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
struct imush im;
|
|
|
|
|
1999-10-17 19:03:11 +00:00
|
|
|
/*
|
|
|
|
* Already been here? If so, leave...
|
|
|
|
*/
|
|
|
|
if (isp->isp_rquest) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
if (isp->isp_maxcmds == 0) {
|
|
|
|
isp_prt(isp, ISP_LOGERR, "maxcmds not set");
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
2006-02-02 21:31:34 +00:00
|
|
|
hlim = BUS_SPACE_MAXADDR;
|
2002-04-02 23:36:14 +00:00
|
|
|
if (IS_ULTRA2(isp) || IS_FC(isp) || IS_1240(isp)) {
|
2006-02-02 21:31:34 +00:00
|
|
|
slim = (bus_size_t) (1ULL << 32);
|
2006-02-15 00:31:48 +00:00
|
|
|
llim = BUS_SPACE_MAXADDR;
|
2002-04-02 23:36:14 +00:00
|
|
|
} else {
|
2006-02-15 00:31:48 +00:00
|
|
|
llim = BUS_SPACE_MAXADDR_32BIT;
|
2006-02-02 21:31:34 +00:00
|
|
|
slim = (1 << 24);
|
2002-04-02 23:36:14 +00:00
|
|
|
}
|
|
|
|
|
2006-05-22 06:51:48 +00:00
|
|
|
/*
|
|
|
|
* XXX: We don't really support 64 bit target mode for parallel scsi yet
|
|
|
|
*/
|
|
|
|
#ifdef ISP_TARGET_MODE
|
|
|
|
if (IS_SCSI(isp) && sizeof (bus_addr_t) > 4) {
|
|
|
|
isp_prt(isp, ISP_LOGERR, "we cannot do DAC for SPI cards yet");
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2002-07-25 16:02:09 +00:00
|
|
|
ISP_UNLOCK(isp);
|
2006-09-03 01:26:55 +00:00
|
|
|
if (isp_dma_tag_create(BUS_DMA_ROOTARG, 1, slim, llim,
|
2006-09-03 00:27:42 +00:00
|
|
|
hlim, NULL, NULL, BUS_SPACE_MAXSIZE, ISP_NSEGS, slim, 0,
|
|
|
|
&pcs->dmat)) {
|
2002-04-02 23:36:14 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR, "could not create master dma tag");
|
2002-07-25 16:02:09 +00:00
|
|
|
ISP_LOCK(isp);
|
2006-05-22 06:51:48 +00:00
|
|
|
return (1);
|
2002-04-02 23:36:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-01 05:16:49 +00:00
|
|
|
len = sizeof (XS_T **) * isp->isp_maxcmds;
|
2003-02-19 05:47:46 +00:00
|
|
|
isp->isp_xflist = (XS_T **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
|
1999-10-17 19:03:11 +00:00
|
|
|
if (isp->isp_xflist == NULL) {
|
2000-08-01 05:16:49 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR, "cannot alloc xflist array");
|
2002-07-25 16:02:09 +00:00
|
|
|
ISP_LOCK(isp);
|
1999-10-17 19:03:11 +00:00
|
|
|
return (1);
|
|
|
|
}
|
2004-05-24 07:02:25 +00:00
|
|
|
#ifdef ISP_TARGET_MODE
|
|
|
|
len = sizeof (void **) * isp->isp_maxcmds;
|
|
|
|
isp->isp_tgtlist = (void **) malloc(len, M_DEVBUF, M_WAITOK | M_ZERO);
|
|
|
|
if (isp->isp_tgtlist == NULL) {
|
|
|
|
isp_prt(isp, ISP_LOGERR, "cannot alloc tgtlist array");
|
|
|
|
ISP_LOCK(isp);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
#endif
|
1999-10-17 19:03:11 +00:00
|
|
|
len = sizeof (bus_dmamap_t) * isp->isp_maxcmds;
|
2003-02-19 05:47:46 +00:00
|
|
|
pcs->dmaps = (bus_dmamap_t *) malloc(len, M_DEVBUF, M_WAITOK);
|
2002-04-02 23:36:14 +00:00
|
|
|
if (pcs->dmaps == NULL) {
|
|
|
|
isp_prt(isp, ISP_LOGERR, "can't alloc dma map storage");
|
1999-10-17 19:03:11 +00:00
|
|
|
free(isp->isp_xflist, M_DEVBUF);
|
2004-05-24 07:02:25 +00:00
|
|
|
#ifdef ISP_TARGET_MODE
|
|
|
|
free(isp->isp_tgtlist, M_DEVBUF);
|
|
|
|
#endif
|
2002-07-25 16:02:09 +00:00
|
|
|
ISP_LOCK(isp);
|
1999-10-17 19:03:11 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
1998-09-15 10:06:23 +00:00
|
|
|
/*
|
|
|
|
* Allocate and map the request, result queues, plus FC scratch area.
|
|
|
|
*/
|
2000-08-01 05:16:49 +00:00
|
|
|
len = ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
|
|
|
|
len += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
if (IS_FC(isp)) {
|
1998-09-15 10:06:23 +00:00
|
|
|
len += ISP2100_SCRLEN;
|
|
|
|
}
|
2002-04-02 23:36:14 +00:00
|
|
|
|
|
|
|
ns = (len / PAGE_SIZE) + 1;
|
2006-02-02 21:31:34 +00:00
|
|
|
/*
|
|
|
|
* Create a tag for the control spaces- force it to within 32 bits.
|
|
|
|
*/
|
2006-04-21 18:30:01 +00:00
|
|
|
if (isp_dma_tag_create(pcs->dmat, QENTRY_LEN, slim,
|
2006-02-02 21:31:34 +00:00
|
|
|
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
|
2006-04-21 18:30:01 +00:00
|
|
|
NULL, NULL, len, ns, slim, 0, &isp->isp_cdmat)) {
|
2000-12-05 07:38:41 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"cannot create a dma tag for control spaces");
|
2002-04-02 23:36:14 +00:00
|
|
|
free(pcs->dmaps, M_DEVBUF);
|
1999-10-17 19:03:11 +00:00
|
|
|
free(isp->isp_xflist, M_DEVBUF);
|
2004-05-24 07:02:25 +00:00
|
|
|
#ifdef ISP_TARGET_MODE
|
|
|
|
free(isp->isp_tgtlist, M_DEVBUF);
|
|
|
|
#endif
|
2002-07-25 16:02:09 +00:00
|
|
|
ISP_LOCK(isp);
|
1998-09-15 10:06:23 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
2002-04-02 23:36:14 +00:00
|
|
|
if (bus_dmamem_alloc(isp->isp_cdmat, (void **)&base, BUS_DMA_NOWAIT,
|
|
|
|
&isp->isp_cdmap) != 0) {
|
2000-12-05 07:38:41 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR,
|
2002-04-02 23:36:14 +00:00
|
|
|
"cannot allocate %d bytes of CCB memory", len);
|
|
|
|
bus_dma_tag_destroy(isp->isp_cdmat);
|
1999-10-17 19:03:11 +00:00
|
|
|
free(isp->isp_xflist, M_DEVBUF);
|
2004-05-24 07:02:25 +00:00
|
|
|
#ifdef ISP_TARGET_MODE
|
|
|
|
free(isp->isp_tgtlist, M_DEVBUF);
|
|
|
|
#endif
|
2002-04-02 23:36:14 +00:00
|
|
|
free(pcs->dmaps, M_DEVBUF);
|
2002-07-25 16:02:09 +00:00
|
|
|
ISP_LOCK(isp);
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
return (1);
|
|
|
|
}
|
1998-09-15 10:06:23 +00:00
|
|
|
|
1999-10-17 19:03:11 +00:00
|
|
|
for (i = 0; i < isp->isp_maxcmds; i++) {
|
2002-04-02 23:36:14 +00:00
|
|
|
error = bus_dmamap_create(pcs->dmat, 0, &pcs->dmaps[i]);
|
1998-09-15 10:06:23 +00:00
|
|
|
if (error) {
|
2000-12-05 07:38:41 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"error %d creating per-cmd DMA maps", error);
|
2002-04-02 23:36:14 +00:00
|
|
|
while (--i >= 0) {
|
|
|
|
bus_dmamap_destroy(pcs->dmat, pcs->dmaps[i]);
|
|
|
|
}
|
|
|
|
goto bad;
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
1999-10-17 19:03:11 +00:00
|
|
|
|
2002-04-02 23:36:14 +00:00
|
|
|
im.isp = isp;
|
|
|
|
im.error = 0;
|
|
|
|
bus_dmamap_load(isp->isp_cdmat, isp->isp_cdmap, base, len, imc, &im, 0);
|
|
|
|
if (im.error) {
|
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"error %d loading dma map for control areas", im.error);
|
|
|
|
goto bad;
|
|
|
|
}
|
|
|
|
|
|
|
|
isp->isp_rquest = base;
|
|
|
|
base += ISP_QUEUE_SIZE(RQUEST_QUEUE_LEN(isp));
|
|
|
|
isp->isp_result = base;
|
Remove pre-CAM code. Add in getenv_int calls for variables isp_mem_map,
isp_io_map, isp_no_fwload, isp_fwload, isp_no_nvram, isp_fcduplex
which are all bitmaps of isp instances that should or shouldn't
map memory space, I/O space, not load f/w, load f/w, ignore nvram,
not ignore nvarm, set full duplex mode. Also have an isp_seed value
that we can use to generate a pseudo seed for a synthetic WWN.
Other minor cosmetic cleanup. Add in support for the Qlogic ISP
2200. Very important change where we actually check now to see
whether we were successful in mapping request and response queues
(and fibre channel scratch space).
1999-07-02 23:18:03 +00:00
|
|
|
if (IS_FC(isp)) {
|
2002-04-02 23:36:14 +00:00
|
|
|
base += ISP_QUEUE_SIZE(RESULT_QUEUE_LEN(isp));
|
|
|
|
FCPARAM(isp)->isp_scratch = base;
|
1999-03-25 22:53:56 +00:00
|
|
|
}
|
2002-07-25 16:02:09 +00:00
|
|
|
ISP_LOCK(isp);
|
1998-09-15 10:06:23 +00:00
|
|
|
return (0);
|
2002-04-02 23:36:14 +00:00
|
|
|
|
|
|
|
bad:
|
|
|
|
bus_dmamem_free(isp->isp_cdmat, base, isp->isp_cdmap);
|
|
|
|
bus_dma_tag_destroy(isp->isp_cdmat);
|
|
|
|
free(isp->isp_xflist, M_DEVBUF);
|
2004-05-24 07:02:25 +00:00
|
|
|
#ifdef ISP_TARGET_MODE
|
|
|
|
free(isp->isp_tgtlist, M_DEVBUF);
|
|
|
|
#endif
|
2002-04-02 23:36:14 +00:00
|
|
|
free(pcs->dmaps, M_DEVBUF);
|
2002-07-25 16:02:09 +00:00
|
|
|
ISP_LOCK(isp);
|
2002-04-02 23:36:14 +00:00
|
|
|
isp->isp_rquest = NULL;
|
|
|
|
return (1);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct {
|
2006-04-21 18:30:01 +00:00
|
|
|
ispsoftc_t *isp;
|
2000-01-03 23:50:13 +00:00
|
|
|
void *cmd_token;
|
|
|
|
void *rq;
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t *nxtip;
|
|
|
|
uint32_t optr;
|
2006-02-15 00:31:48 +00:00
|
|
|
int error;
|
1998-09-15 10:06:23 +00:00
|
|
|
} mush_t;
|
|
|
|
|
1998-09-17 21:11:21 +00:00
|
|
|
#define MUSHERR_NOQENTRIES -2
|
|
|
|
|
2000-01-03 23:50:13 +00:00
|
|
|
#ifdef ISP_TARGET_MODE
|
|
|
|
/*
|
|
|
|
* We need to handle DMA for target mode differently from initiator mode.
|
|
|
|
*
|
|
|
|
* DMA mapping and construction and submission of CTIO Request Entries
|
|
|
|
* and rendevous for completion are very tightly coupled because we start
|
|
|
|
* out by knowing (per platform) how much data we have to move, but we
|
|
|
|
* don't know, up front, how many DMA mapping segments will have to be used
|
|
|
|
* cover that data, so we don't know how many CTIO Request Entries we
|
|
|
|
* will end up using. Further, for performance reasons we may want to
|
|
|
|
* (on the last CTIO for Fibre Channel), send status too (if all went well).
|
|
|
|
*
|
|
|
|
* The standard vector still goes through isp_pci_dmasetup, but the callback
|
|
|
|
* for the DMA mapping routines comes here instead with the whole transfer
|
|
|
|
* mapped and a pointer to a partially filled in already allocated request
|
|
|
|
* queue entry. We finish the job.
|
|
|
|
*/
|
2001-04-04 21:53:59 +00:00
|
|
|
static void tdma_mk(void *, bus_dma_segment_t *, int, int);
|
|
|
|
static void tdma_mkfc(void *, bus_dma_segment_t *, int, int);
|
|
|
|
|
|
|
|
#define STATUS_WITH_DATA 1
|
2000-01-03 23:50:13 +00:00
|
|
|
|
|
|
|
static void
|
2000-07-18 06:40:22 +00:00
|
|
|
tdma_mk(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
|
2000-01-03 23:50:13 +00:00
|
|
|
{
|
|
|
|
mush_t *mp;
|
|
|
|
struct ccb_scsiio *csio;
|
2006-04-21 18:30:01 +00:00
|
|
|
ispsoftc_t *isp;
|
2002-04-02 23:36:14 +00:00
|
|
|
struct isp_pcisoftc *pcs;
|
2000-01-03 23:50:13 +00:00
|
|
|
bus_dmamap_t *dp;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
ct_entry_t *cto, *qe;
|
2006-02-15 00:31:48 +00:00
|
|
|
uint8_t scsi_status;
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t curi, nxti, handle;
|
2006-02-15 00:31:48 +00:00
|
|
|
uint32_t sflags;
|
2000-07-18 06:40:22 +00:00
|
|
|
int32_t resid;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
int nth_ctio, nctios, send_status;
|
2000-01-03 23:50:13 +00:00
|
|
|
|
|
|
|
mp = (mush_t *) arg;
|
|
|
|
if (error) {
|
|
|
|
mp->error = error;
|
|
|
|
return;
|
|
|
|
}
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
|
|
|
|
isp = mp->isp;
|
2000-01-03 23:50:13 +00:00
|
|
|
csio = mp->cmd_token;
|
|
|
|
cto = mp->rq;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
curi = isp->isp_reqidx;
|
|
|
|
qe = (ct_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi);
|
2000-01-03 23:50:13 +00:00
|
|
|
|
2000-01-15 01:54:36 +00:00
|
|
|
cto->ct_xfrlen = 0;
|
|
|
|
cto->ct_seg_count = 0;
|
2000-07-18 06:40:22 +00:00
|
|
|
cto->ct_header.rqs_entry_count = 1;
|
|
|
|
MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
|
|
|
|
|
2000-01-15 01:54:36 +00:00
|
|
|
if (nseg == 0) {
|
2000-07-18 06:40:22 +00:00
|
|
|
cto->ct_header.rqs_seqno = 1;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
2001-04-04 21:53:59 +00:00
|
|
|
"CTIO[%x] lun%d iid%d tag %x flgs %x sts %x ssts %x res %d",
|
2001-03-02 06:28:55 +00:00
|
|
|
cto->ct_fwhandle, csio->ccb_h.target_lun, cto->ct_iid,
|
2001-04-04 21:53:59 +00:00
|
|
|
cto->ct_tag_val, cto->ct_flags, cto->ct_status,
|
|
|
|
cto->ct_scsi_status, cto->ct_resid);
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
ISP_TDQE(isp, "tdma_mk[no data]", curi, cto);
|
|
|
|
isp_put_ctio(isp, cto, qe);
|
2000-01-15 01:54:36 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-07-18 06:40:22 +00:00
|
|
|
nctios = nseg / ISP_RQDSEG;
|
|
|
|
if (nseg % ISP_RQDSEG) {
|
|
|
|
nctios++;
|
|
|
|
}
|
|
|
|
|
2000-01-03 23:50:13 +00:00
|
|
|
/*
|
2001-03-02 06:28:55 +00:00
|
|
|
* Save syshandle, and potentially any SCSI status, which we'll
|
|
|
|
* reinsert on the last CTIO we're going to send.
|
2000-01-03 23:50:13 +00:00
|
|
|
*/
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
|
2001-03-02 06:28:55 +00:00
|
|
|
handle = cto->ct_syshandle;
|
|
|
|
cto->ct_syshandle = 0;
|
2000-07-18 06:40:22 +00:00
|
|
|
cto->ct_header.rqs_seqno = 0;
|
|
|
|
send_status = (cto->ct_flags & CT_SENDSTATUS) != 0;
|
2000-01-03 23:50:13 +00:00
|
|
|
|
2000-07-18 06:40:22 +00:00
|
|
|
if (send_status) {
|
|
|
|
sflags = cto->ct_flags & (CT_SENDSTATUS | CT_CCINCR);
|
|
|
|
cto->ct_flags &= ~(CT_SENDSTATUS | CT_CCINCR);
|
|
|
|
/*
|
|
|
|
* Preserve residual.
|
|
|
|
*/
|
|
|
|
resid = cto->ct_resid;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save actual SCSI status.
|
|
|
|
*/
|
|
|
|
scsi_status = cto->ct_scsi_status;
|
|
|
|
|
2001-04-04 21:53:59 +00:00
|
|
|
#ifndef STATUS_WITH_DATA
|
|
|
|
sflags |= CT_NO_DATA;
|
2000-07-18 06:40:22 +00:00
|
|
|
/*
|
|
|
|
* We can't do a status at the same time as a data CTIO, so
|
|
|
|
* we need to synthesize an extra CTIO at this level.
|
|
|
|
*/
|
2000-01-15 01:54:36 +00:00
|
|
|
nctios++;
|
2001-03-21 00:49:37 +00:00
|
|
|
#endif
|
2000-07-18 06:40:22 +00:00
|
|
|
} else {
|
|
|
|
sflags = scsi_status = resid = 0;
|
2000-01-15 01:54:36 +00:00
|
|
|
}
|
|
|
|
|
2001-09-04 21:45:57 +00:00
|
|
|
cto->ct_resid = 0;
|
2000-07-18 06:40:22 +00:00
|
|
|
cto->ct_scsi_status = 0;
|
|
|
|
|
2002-04-02 23:36:14 +00:00
|
|
|
pcs = (struct isp_pcisoftc *)isp;
|
|
|
|
dp = &pcs->dmaps[isp_handle_index(handle)];
|
2000-01-03 23:50:13 +00:00
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD);
|
2000-01-03 23:50:13 +00:00
|
|
|
} else {
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE);
|
2000-01-03 23:50:13 +00:00
|
|
|
}
|
|
|
|
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
nxti = *mp->nxtip;
|
2000-01-03 23:50:13 +00:00
|
|
|
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
for (nth_ctio = 0; nth_ctio < nctios; nth_ctio++) {
|
2000-07-18 06:40:22 +00:00
|
|
|
int seglim;
|
2000-01-03 23:50:13 +00:00
|
|
|
|
|
|
|
seglim = nseg;
|
2000-07-18 06:40:22 +00:00
|
|
|
if (seglim) {
|
|
|
|
int seg;
|
|
|
|
|
|
|
|
if (seglim > ISP_RQDSEG)
|
|
|
|
seglim = ISP_RQDSEG;
|
|
|
|
|
|
|
|
for (seg = 0; seg < seglim; seg++, nseg--) {
|
|
|
|
/*
|
|
|
|
* Unlike normal initiator commands, we don't
|
|
|
|
* do any swizzling here.
|
|
|
|
*/
|
|
|
|
cto->ct_dataseg[seg].ds_count = dm_segs->ds_len;
|
|
|
|
cto->ct_dataseg[seg].ds_base = dm_segs->ds_addr;
|
|
|
|
cto->ct_xfrlen += dm_segs->ds_len;
|
|
|
|
dm_segs++;
|
|
|
|
}
|
|
|
|
cto->ct_seg_count = seg;
|
2000-01-03 23:50:13 +00:00
|
|
|
} else {
|
2000-07-18 06:40:22 +00:00
|
|
|
/*
|
|
|
|
* This case should only happen when we're sending an
|
|
|
|
* extra CTIO with final status.
|
|
|
|
*/
|
|
|
|
if (send_status == 0) {
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_prt(isp, ISP_LOGWARN,
|
2000-12-05 07:38:41 +00:00
|
|
|
"tdma_mk ran out of segments");
|
2000-07-18 06:40:22 +00:00
|
|
|
mp->error = EINVAL;
|
|
|
|
return;
|
|
|
|
}
|
2000-01-03 23:50:13 +00:00
|
|
|
}
|
|
|
|
|
2000-07-18 06:40:22 +00:00
|
|
|
/*
|
|
|
|
* At this point, the fields ct_lun, ct_iid, ct_tagval,
|
|
|
|
* ct_tagtype, and ct_timeout have been carried over
|
|
|
|
* unchanged from what our caller had set.
|
|
|
|
*
|
|
|
|
* The dataseg fields and the seg_count fields we just got
|
|
|
|
* through setting. The data direction we've preserved all
|
|
|
|
* along and only clear it if we're now sending status.
|
|
|
|
*/
|
|
|
|
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
if (nth_ctio == nctios - 1) {
|
2000-01-03 23:50:13 +00:00
|
|
|
/*
|
2000-07-18 06:40:22 +00:00
|
|
|
* We're the last in a sequence of CTIOs, so mark
|
|
|
|
* this CTIO and save the handle to the CCB such that
|
|
|
|
* when this CTIO completes we can free dma resources
|
|
|
|
* and do whatever else we need to do to finish the
|
2001-04-04 21:53:59 +00:00
|
|
|
* rest of the command. We *don't* give this to the
|
|
|
|
* firmware to work on- the caller will do that.
|
2000-01-03 23:50:13 +00:00
|
|
|
*/
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
|
2001-03-02 06:28:55 +00:00
|
|
|
cto->ct_syshandle = handle;
|
2000-07-18 06:40:22 +00:00
|
|
|
cto->ct_header.rqs_seqno = 1;
|
|
|
|
|
|
|
|
if (send_status) {
|
|
|
|
cto->ct_scsi_status = scsi_status;
|
2001-03-21 00:49:37 +00:00
|
|
|
cto->ct_flags |= sflags;
|
2000-07-18 06:40:22 +00:00
|
|
|
cto->ct_resid = resid;
|
|
|
|
}
|
2000-08-01 05:16:49 +00:00
|
|
|
if (send_status) {
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
2001-04-04 21:53:59 +00:00
|
|
|
"CTIO[%x] lun%d iid %d tag %x ct_flags %x "
|
2001-03-02 06:28:55 +00:00
|
|
|
"scsi status %x resid %d",
|
|
|
|
cto->ct_fwhandle, csio->ccb_h.target_lun,
|
2001-04-04 21:53:59 +00:00
|
|
|
cto->ct_iid, cto->ct_tag_val, cto->ct_flags,
|
2000-01-04 03:41:40 +00:00
|
|
|
cto->ct_scsi_status, cto->ct_resid);
|
2000-08-01 05:16:49 +00:00
|
|
|
} else {
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
2001-04-04 21:53:59 +00:00
|
|
|
"CTIO[%x] lun%d iid%d tag %x ct_flags 0x%x",
|
2001-03-02 06:28:55 +00:00
|
|
|
cto->ct_fwhandle, csio->ccb_h.target_lun,
|
2001-04-04 21:53:59 +00:00
|
|
|
cto->ct_iid, cto->ct_tag_val,
|
|
|
|
cto->ct_flags);
|
2000-01-04 03:41:40 +00:00
|
|
|
}
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_put_ctio(isp, cto, qe);
|
|
|
|
ISP_TDQE(isp, "last tdma_mk", curi, cto);
|
|
|
|
if (nctios > 1) {
|
|
|
|
MEMORYBARRIER(isp, SYNC_REQUEST,
|
|
|
|
curi, QENTRY_LEN);
|
|
|
|
}
|
2000-01-03 23:50:13 +00:00
|
|
|
} else {
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
ct_entry_t *oqe = qe;
|
2000-07-18 06:40:22 +00:00
|
|
|
|
|
|
|
/*
|
2001-03-02 06:28:55 +00:00
|
|
|
* Make sure syshandle fields are clean
|
2000-07-18 06:40:22 +00:00
|
|
|
*/
|
2001-03-02 06:28:55 +00:00
|
|
|
cto->ct_syshandle = 0;
|
2000-01-03 23:50:13 +00:00
|
|
|
cto->ct_header.rqs_seqno = 0;
|
2000-07-18 06:40:22 +00:00
|
|
|
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
2001-03-02 06:28:55 +00:00
|
|
|
"CTIO[%x] lun%d for ID%d ct_flags 0x%x",
|
|
|
|
cto->ct_fwhandle, csio->ccb_h.target_lun,
|
|
|
|
cto->ct_iid, cto->ct_flags);
|
2000-07-18 06:40:22 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get a new CTIO
|
|
|
|
*/
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
qe = (ct_entry_t *)
|
|
|
|
ISP_QUEUE_ENTRY(isp->isp_rquest, nxti);
|
|
|
|
nxti = ISP_NXT_QENTRY(nxti, RQUEST_QUEUE_LEN(isp));
|
|
|
|
if (nxti == mp->optr) {
|
|
|
|
isp_prt(isp, ISP_LOGTDEBUG0,
|
2000-12-05 07:38:41 +00:00
|
|
|
"Queue Overflow in tdma_mk");
|
2000-01-03 23:50:13 +00:00
|
|
|
mp->error = MUSHERR_NOQENTRIES;
|
|
|
|
return;
|
|
|
|
}
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now that we're done with the old CTIO,
|
|
|
|
* flush it out to the request queue.
|
|
|
|
*/
|
|
|
|
ISP_TDQE(isp, "dma_tgt_fc", curi, cto);
|
|
|
|
isp_put_ctio(isp, cto, oqe);
|
|
|
|
if (nth_ctio != 0) {
|
|
|
|
MEMORYBARRIER(isp, SYNC_REQUEST, curi,
|
|
|
|
QENTRY_LEN);
|
|
|
|
}
|
|
|
|
curi = ISP_NXT_QENTRY(curi, RQUEST_QUEUE_LEN(isp));
|
|
|
|
|
2000-01-03 23:50:13 +00:00
|
|
|
/*
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
* Reset some fields in the CTIO so we can reuse
|
|
|
|
* for the next one we'll flush to the request
|
|
|
|
* queue.
|
2000-01-03 23:50:13 +00:00
|
|
|
*/
|
|
|
|
cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
|
|
|
|
cto->ct_header.rqs_entry_count = 1;
|
|
|
|
cto->ct_header.rqs_flags = 0;
|
|
|
|
cto->ct_status = 0;
|
|
|
|
cto->ct_scsi_status = 0;
|
|
|
|
cto->ct_xfrlen = 0;
|
|
|
|
cto->ct_resid = 0;
|
|
|
|
cto->ct_seg_count = 0;
|
2000-07-18 06:40:22 +00:00
|
|
|
MEMZERO(cto->ct_dataseg, sizeof(cto->ct_dataseg));
|
2000-01-03 23:50:13 +00:00
|
|
|
}
|
|
|
|
}
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
*mp->nxtip = nxti;
|
2000-01-03 23:50:13 +00:00
|
|
|
}
|
|
|
|
|
2002-06-16 04:58:00 +00:00
|
|
|
/*
|
|
|
|
* We don't have to do multiple CTIOs here. Instead, we can just do
|
|
|
|
* continuation segments as needed. This greatly simplifies the code
|
|
|
|
* improves performance.
|
|
|
|
*/
|
|
|
|
|
2000-01-03 23:50:13 +00:00
|
|
|
static void
|
2000-07-18 06:40:22 +00:00
|
|
|
tdma_mkfc(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
|
2000-01-03 23:50:13 +00:00
|
|
|
{
|
|
|
|
mush_t *mp;
|
|
|
|
struct ccb_scsiio *csio;
|
2006-04-21 18:30:01 +00:00
|
|
|
ispsoftc_t *isp;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
ct2_entry_t *cto, *qe;
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t curi, nxti;
|
2006-05-22 06:51:48 +00:00
|
|
|
ispds_t *ds;
|
|
|
|
ispds64_t *ds64;
|
|
|
|
int segcnt, seglim;
|
2000-01-03 23:50:13 +00:00
|
|
|
|
|
|
|
mp = (mush_t *) arg;
|
|
|
|
if (error) {
|
|
|
|
mp->error = error;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp = mp->isp;
|
2000-01-15 01:54:36 +00:00
|
|
|
csio = mp->cmd_token;
|
|
|
|
cto = mp->rq;
|
2002-06-16 04:58:00 +00:00
|
|
|
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
curi = isp->isp_reqidx;
|
|
|
|
qe = (ct2_entry_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, curi);
|
2000-01-15 01:54:36 +00:00
|
|
|
|
|
|
|
if (nseg == 0) {
|
|
|
|
if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE1) {
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_prt(isp, ISP_LOGWARN,
|
2000-12-05 07:38:41 +00:00
|
|
|
"dma2_tgt_fc, a status CTIO2 without MODE1 "
|
|
|
|
"set (0x%x)", cto->ct_flags);
|
2000-01-15 01:54:36 +00:00
|
|
|
mp->error = EINVAL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* We preserve ct_lun, ct_iid, ct_rxid. We set the data
|
|
|
|
* flags to NO DATA and clear relative offset flags.
|
|
|
|
* We preserve the ct_resid and the response area.
|
|
|
|
*/
|
2002-06-16 04:58:00 +00:00
|
|
|
cto->ct_header.rqs_seqno = 1;
|
2000-01-15 01:54:36 +00:00
|
|
|
cto->ct_seg_count = 0;
|
|
|
|
cto->ct_reloff = 0;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
2001-03-02 06:28:55 +00:00
|
|
|
"CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts "
|
2000-08-01 05:16:49 +00:00
|
|
|
"0x%x res %d", cto->ct_rxid, csio->ccb_h.target_lun,
|
|
|
|
cto->ct_iid, cto->ct_flags, cto->ct_status,
|
|
|
|
cto->rsp.m1.ct_scsi_status, cto->ct_resid);
|
2006-11-02 03:21:32 +00:00
|
|
|
if (FCPARAM(isp)->isp_2klogin) {
|
2006-05-22 06:51:48 +00:00
|
|
|
isp_put_ctio2e(isp,
|
|
|
|
(ct2e_entry_t *)cto, (ct2e_entry_t *)qe);
|
|
|
|
} else {
|
|
|
|
isp_put_ctio2(isp, cto, qe);
|
|
|
|
}
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
ISP_TDQE(isp, "dma2_tgt_fc[no data]", curi, qe);
|
2000-01-03 23:50:13 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2000-01-15 01:54:36 +00:00
|
|
|
if ((cto->ct_flags & CT2_FLAG_MMASK) != CT2_FLAG_MODE0) {
|
2002-06-16 04:58:00 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR,
|
2000-12-05 07:38:41 +00:00
|
|
|
"dma2_tgt_fc, a data CTIO2 without MODE0 set "
|
|
|
|
"(0x%x)", cto->ct_flags);
|
2000-01-15 01:54:36 +00:00
|
|
|
mp->error = EINVAL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-06-16 04:58:00 +00:00
|
|
|
nxti = *mp->nxtip;
|
2000-01-15 01:54:36 +00:00
|
|
|
|
2006-05-22 06:51:48 +00:00
|
|
|
/*
|
|
|
|
* Check to see if we need to DAC addressing or not.
|
|
|
|
*
|
|
|
|
* Any address that's over the 4GB boundary causes this
|
|
|
|
* to happen.
|
|
|
|
*/
|
|
|
|
segcnt = nseg;
|
|
|
|
if (sizeof (bus_addr_t) > 4) {
|
|
|
|
for (segcnt = 0; segcnt < nseg; segcnt++) {
|
|
|
|
uint64_t addr = dm_segs[segcnt].ds_addr;
|
|
|
|
if (addr >= 0x100000000LL) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (segcnt != nseg) {
|
|
|
|
cto->ct_header.rqs_entry_type = RQSTYPE_CTIO3;
|
|
|
|
seglim = ISP_RQDSEG_T3;
|
2006-11-02 03:21:32 +00:00
|
|
|
ds64 = &cto->rsp.m0.u.ct_dataseg64[0];
|
2006-05-22 06:51:48 +00:00
|
|
|
ds = NULL;
|
|
|
|
} else {
|
|
|
|
seglim = ISP_RQDSEG_T2;
|
|
|
|
ds64 = NULL;
|
2006-11-02 03:21:32 +00:00
|
|
|
ds = &cto->rsp.m0.u.ct_dataseg[0];
|
2006-05-22 06:51:48 +00:00
|
|
|
}
|
|
|
|
cto->ct_seg_count = 0;
|
|
|
|
|
2000-01-03 23:50:13 +00:00
|
|
|
/*
|
2002-06-16 04:58:00 +00:00
|
|
|
* Set up the CTIO2 data segments.
|
2000-01-03 23:50:13 +00:00
|
|
|
*/
|
2006-05-22 06:51:48 +00:00
|
|
|
for (segcnt = 0; cto->ct_seg_count < seglim && segcnt < nseg;
|
2002-06-16 04:58:00 +00:00
|
|
|
cto->ct_seg_count++, segcnt++) {
|
2006-05-22 06:51:48 +00:00
|
|
|
if (ds64) {
|
|
|
|
ds64->ds_basehi =
|
|
|
|
((uint64_t) (dm_segs[segcnt].ds_addr) >> 32);
|
|
|
|
ds64->ds_base = dm_segs[segcnt].ds_addr;
|
|
|
|
ds64->ds_count = dm_segs[segcnt].ds_len;
|
|
|
|
ds64++;
|
|
|
|
} else {
|
|
|
|
ds->ds_base = dm_segs[segcnt].ds_addr;
|
|
|
|
ds->ds_count = dm_segs[segcnt].ds_len;
|
|
|
|
ds++;
|
|
|
|
}
|
2002-06-16 04:58:00 +00:00
|
|
|
cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len;
|
2006-04-21 18:30:01 +00:00
|
|
|
#if __FreeBSD_version < 500000
|
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
|
|
|
"isp_send_ctio2: ent0[%d]0x%llx:%llu",
|
|
|
|
cto->ct_seg_count, (uint64_t)dm_segs[segcnt].ds_addr,
|
|
|
|
(uint64_t)dm_segs[segcnt].ds_len);
|
|
|
|
#else
|
2003-01-02 04:21:52 +00:00
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
2005-12-15 22:12:27 +00:00
|
|
|
"isp_send_ctio2: ent0[%d]0x%jx:%ju",
|
|
|
|
cto->ct_seg_count, (uintmax_t)dm_segs[segcnt].ds_addr,
|
|
|
|
(uintmax_t)dm_segs[segcnt].ds_len);
|
2006-04-21 18:30:01 +00:00
|
|
|
#endif
|
2002-06-16 04:58:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
while (segcnt < nseg) {
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t curip;
|
2002-06-16 04:58:00 +00:00
|
|
|
int seg;
|
|
|
|
ispcontreq_t local, *crq = &local, *qep;
|
|
|
|
|
|
|
|
qep = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti);
|
|
|
|
curip = nxti;
|
|
|
|
nxti = ISP_NXT_QENTRY(curip, RQUEST_QUEUE_LEN(isp));
|
|
|
|
if (nxti == mp->optr) {
|
|
|
|
ISP_UNLOCK(isp);
|
|
|
|
isp_prt(isp, ISP_LOGTDEBUG0,
|
|
|
|
"tdma_mkfc: request queue overflow");
|
|
|
|
mp->error = MUSHERR_NOQENTRIES;
|
|
|
|
return;
|
2000-01-03 23:50:13 +00:00
|
|
|
}
|
2002-06-16 04:58:00 +00:00
|
|
|
cto->ct_header.rqs_entry_count++;
|
|
|
|
MEMZERO((void *)crq, sizeof (*crq));
|
|
|
|
crq->req_header.rqs_entry_count = 1;
|
2006-05-22 06:51:48 +00:00
|
|
|
if (cto->ct_header.rqs_entry_type == RQSTYPE_CTIO3) {
|
|
|
|
seglim = ISP_CDSEG64;
|
|
|
|
ds = NULL;
|
|
|
|
ds64 = &((ispcontreq64_t *)crq)->req_dataseg[0];
|
|
|
|
crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT;
|
|
|
|
} else {
|
|
|
|
seglim = ISP_CDSEG;
|
|
|
|
ds = &crq->req_dataseg[0];
|
|
|
|
ds64 = NULL;
|
|
|
|
crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
|
|
|
|
}
|
|
|
|
for (seg = 0; segcnt < nseg && seg < seglim;
|
2002-06-16 04:58:00 +00:00
|
|
|
segcnt++, seg++) {
|
2006-05-22 06:51:48 +00:00
|
|
|
if (ds64) {
|
|
|
|
ds64->ds_basehi =
|
|
|
|
((uint64_t) (dm_segs[segcnt].ds_addr) >> 32);
|
|
|
|
ds64->ds_base = dm_segs[segcnt].ds_addr;
|
|
|
|
ds64->ds_count = dm_segs[segcnt].ds_len;
|
|
|
|
ds64++;
|
|
|
|
} else {
|
|
|
|
ds->ds_base = dm_segs[segcnt].ds_addr;
|
|
|
|
ds->ds_count = dm_segs[segcnt].ds_len;
|
|
|
|
ds++;
|
|
|
|
}
|
2006-04-21 18:30:01 +00:00
|
|
|
#if __FreeBSD_version < 500000
|
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
|
|
|
"isp_send_ctio2: ent%d[%d]%llx:%llu",
|
|
|
|
cto->ct_header.rqs_entry_count-1, seg,
|
|
|
|
(uint64_t)dm_segs[segcnt].ds_addr,
|
|
|
|
(uint64_t)dm_segs[segcnt].ds_len);
|
|
|
|
#else
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
2005-12-15 22:12:27 +00:00
|
|
|
"isp_send_ctio2: ent%d[%d]%jx:%ju",
|
2002-06-16 04:58:00 +00:00
|
|
|
cto->ct_header.rqs_entry_count-1, seg,
|
2005-12-15 22:12:27 +00:00
|
|
|
(uintmax_t)dm_segs[segcnt].ds_addr,
|
|
|
|
(uintmax_t)dm_segs[segcnt].ds_len);
|
2006-04-21 18:30:01 +00:00
|
|
|
#endif
|
2002-06-16 04:58:00 +00:00
|
|
|
cto->rsp.m0.ct_xfrlen += dm_segs[segcnt].ds_len;
|
|
|
|
cto->ct_seg_count++;
|
2000-01-03 23:50:13 +00:00
|
|
|
}
|
2002-06-16 04:58:00 +00:00
|
|
|
MEMORYBARRIER(isp, SYNC_REQUEST, curip, QENTRY_LEN);
|
|
|
|
isp_put_cont_req(isp, crq, qep);
|
|
|
|
ISP_TDQE(isp, "cont entry", curi, qep);
|
2000-01-03 23:50:13 +00:00
|
|
|
}
|
2002-06-16 04:58:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* No do final twiddling for the CTIO itself.
|
|
|
|
*/
|
|
|
|
cto->ct_header.rqs_seqno = 1;
|
|
|
|
isp_prt(isp, ISP_LOGTDEBUG1,
|
|
|
|
"CTIO2[%x] lun %d->iid%d flgs 0x%x sts 0x%x ssts 0x%x resid %d",
|
|
|
|
cto->ct_rxid, csio->ccb_h.target_lun, (int) cto->ct_iid,
|
|
|
|
cto->ct_flags, cto->ct_status, cto->rsp.m1.ct_scsi_status,
|
|
|
|
cto->ct_resid);
|
2006-11-02 03:21:32 +00:00
|
|
|
if (FCPARAM(isp)->isp_2klogin) {
|
2006-05-22 06:51:48 +00:00
|
|
|
isp_put_ctio2e(isp, (ct2e_entry_t *)cto, (ct2e_entry_t *)qe);
|
2006-11-02 03:21:32 +00:00
|
|
|
} else {
|
2006-05-22 06:51:48 +00:00
|
|
|
isp_put_ctio2(isp, cto, qe);
|
2006-11-02 03:21:32 +00:00
|
|
|
}
|
2002-06-16 04:58:00 +00:00
|
|
|
ISP_TDQE(isp, "last dma2_tgt_fc", curi, qe);
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
*mp->nxtip = nxti;
|
2000-01-03 23:50:13 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
static void dma_2400(void *, bus_dma_segment_t *, int, int);
|
2006-02-15 00:31:48 +00:00
|
|
|
static void dma2_a64(void *, bus_dma_segment_t *, int, int);
|
2001-08-31 21:39:04 +00:00
|
|
|
static void dma2(void *, bus_dma_segment_t *, int, int);
|
2000-01-03 23:50:13 +00:00
|
|
|
|
2006-11-02 03:21:32 +00:00
|
|
|
static void
|
|
|
|
dma_2400(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
|
|
|
|
{
|
|
|
|
mush_t *mp;
|
|
|
|
ispsoftc_t *isp;
|
|
|
|
struct ccb_scsiio *csio;
|
|
|
|
struct isp_pcisoftc *pcs;
|
|
|
|
bus_dmamap_t *dp;
|
|
|
|
bus_dma_segment_t *eseg;
|
|
|
|
ispreqt7_t *rq;
|
|
|
|
int seglim, datalen;
|
|
|
|
uint32_t nxti;
|
|
|
|
|
|
|
|
mp = (mush_t *) arg;
|
|
|
|
if (error) {
|
|
|
|
mp->error = error;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nseg < 1) {
|
|
|
|
isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg);
|
|
|
|
mp->error = EFAULT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
csio = mp->cmd_token;
|
|
|
|
isp = mp->isp;
|
|
|
|
rq = mp->rq;
|
|
|
|
pcs = (struct isp_pcisoftc *)mp->isp;
|
|
|
|
dp = &pcs->dmaps[isp_handle_index(rq->req_handle)];
|
|
|
|
nxti = *mp->nxtip;
|
|
|
|
|
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD);
|
|
|
|
} else {
|
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE);
|
|
|
|
}
|
|
|
|
datalen = XS_XFRLEN(csio);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We're passed an initial partially filled in entry that
|
|
|
|
* has most fields filled in except for data transfer
|
|
|
|
* related values.
|
|
|
|
*
|
|
|
|
* Our job is to fill in the initial request queue entry and
|
|
|
|
* then to start allocating and filling in continuation entries
|
|
|
|
* until we've covered the entire transfer.
|
|
|
|
*/
|
|
|
|
|
|
|
|
rq->req_header.rqs_entry_type = RQSTYPE_T7RQS;
|
|
|
|
rq->req_dl = datalen;
|
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
|
|
|
rq->req_alen_datadir = 0x2;
|
|
|
|
} else {
|
|
|
|
rq->req_alen_datadir = 0x1;
|
|
|
|
}
|
|
|
|
|
|
|
|
eseg = dm_segs + nseg;
|
|
|
|
|
|
|
|
rq->req_dataseg.ds_base = DMA_LO32(dm_segs->ds_addr);
|
|
|
|
rq->req_dataseg.ds_basehi = DMA_HI32(dm_segs->ds_addr);
|
|
|
|
rq->req_dataseg.ds_count = dm_segs->ds_len;
|
|
|
|
|
|
|
|
datalen -= dm_segs->ds_len;
|
|
|
|
|
|
|
|
dm_segs++;
|
|
|
|
rq->req_seg_count++;
|
|
|
|
|
|
|
|
while (datalen > 0 && dm_segs != eseg) {
|
|
|
|
uint32_t onxti;
|
|
|
|
ispcontreq64_t local, *crq = &local, *cqe;
|
|
|
|
|
|
|
|
cqe = (ispcontreq64_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti);
|
|
|
|
onxti = nxti;
|
|
|
|
nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp));
|
|
|
|
if (nxti == mp->optr) {
|
|
|
|
isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++");
|
|
|
|
mp->error = MUSHERR_NOQENTRIES;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
rq->req_header.rqs_entry_count++;
|
|
|
|
MEMZERO((void *)crq, sizeof (*crq));
|
|
|
|
crq->req_header.rqs_entry_count = 1;
|
|
|
|
crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT;
|
|
|
|
|
|
|
|
seglim = 0;
|
|
|
|
while (datalen > 0 && seglim < ISP_CDSEG64 && dm_segs != eseg) {
|
|
|
|
crq->req_dataseg[seglim].ds_base =
|
|
|
|
DMA_LO32(dm_segs->ds_addr);
|
|
|
|
crq->req_dataseg[seglim].ds_basehi =
|
|
|
|
DMA_HI32(dm_segs->ds_addr);
|
|
|
|
crq->req_dataseg[seglim].ds_count =
|
|
|
|
dm_segs->ds_len;
|
|
|
|
rq->req_seg_count++;
|
|
|
|
dm_segs++;
|
|
|
|
seglim++;
|
|
|
|
datalen -= dm_segs->ds_len;
|
|
|
|
}
|
|
|
|
if (isp->isp_dblev & ISP_LOGDEBUG1) {
|
|
|
|
isp_print_bytes(isp, "Continuation", QENTRY_LEN, crq);
|
|
|
|
}
|
|
|
|
isp_put_cont64_req(isp, crq, cqe);
|
|
|
|
MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN);
|
|
|
|
}
|
|
|
|
*mp->nxtip = nxti;
|
|
|
|
}
|
|
|
|
|
2004-09-07 08:04:09 +00:00
|
|
|
static void
|
2006-02-15 00:31:48 +00:00
|
|
|
dma2_a64(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
|
2004-09-07 08:04:09 +00:00
|
|
|
{
|
|
|
|
mush_t *mp;
|
2006-04-21 18:30:01 +00:00
|
|
|
ispsoftc_t *isp;
|
2004-09-07 08:04:09 +00:00
|
|
|
struct ccb_scsiio *csio;
|
|
|
|
struct isp_pcisoftc *pcs;
|
|
|
|
bus_dmamap_t *dp;
|
|
|
|
bus_dma_segment_t *eseg;
|
|
|
|
ispreq64_t *rq;
|
|
|
|
int seglim, datalen;
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t nxti;
|
2004-09-07 08:04:09 +00:00
|
|
|
|
|
|
|
mp = (mush_t *) arg;
|
|
|
|
if (error) {
|
|
|
|
mp->error = error;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nseg < 1) {
|
|
|
|
isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg);
|
|
|
|
mp->error = EFAULT;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
csio = mp->cmd_token;
|
|
|
|
isp = mp->isp;
|
|
|
|
rq = mp->rq;
|
|
|
|
pcs = (struct isp_pcisoftc *)mp->isp;
|
|
|
|
dp = &pcs->dmaps[isp_handle_index(rq->req_handle)];
|
|
|
|
nxti = *mp->nxtip;
|
|
|
|
|
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD);
|
|
|
|
} else {
|
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE);
|
|
|
|
}
|
|
|
|
datalen = XS_XFRLEN(csio);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We're passed an initial partially filled in entry that
|
|
|
|
* has most fields filled in except for data transfer
|
|
|
|
* related values.
|
|
|
|
*
|
|
|
|
* Our job is to fill in the initial request queue entry and
|
|
|
|
* then to start allocating and filling in continuation entries
|
|
|
|
* until we've covered the entire transfer.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (IS_FC(isp)) {
|
2004-09-23 05:25:22 +00:00
|
|
|
rq->req_header.rqs_entry_type = RQSTYPE_T3RQS;
|
2004-09-07 08:04:09 +00:00
|
|
|
seglim = ISP_RQDSEG_T3;
|
|
|
|
((ispreqt3_t *)rq)->req_totalcnt = datalen;
|
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
|
|
|
((ispreqt3_t *)rq)->req_flags |= REQFLAG_DATA_IN;
|
|
|
|
} else {
|
|
|
|
((ispreqt3_t *)rq)->req_flags |= REQFLAG_DATA_OUT;
|
|
|
|
}
|
|
|
|
} else {
|
2004-09-23 05:25:22 +00:00
|
|
|
rq->req_header.rqs_entry_type = RQSTYPE_A64;
|
2004-09-07 08:04:09 +00:00
|
|
|
if (csio->cdb_len > 12) {
|
|
|
|
seglim = 0;
|
|
|
|
} else {
|
|
|
|
seglim = ISP_RQDSEG_A64;
|
|
|
|
}
|
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
|
|
|
rq->req_flags |= REQFLAG_DATA_IN;
|
|
|
|
} else {
|
|
|
|
rq->req_flags |= REQFLAG_DATA_OUT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
eseg = dm_segs + nseg;
|
|
|
|
|
|
|
|
while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
|
|
|
|
if (IS_FC(isp)) {
|
|
|
|
ispreqt3_t *rq3 = (ispreqt3_t *)rq;
|
|
|
|
rq3->req_dataseg[rq3->req_seg_count].ds_base =
|
2006-02-15 00:31:48 +00:00
|
|
|
DMA_LO32(dm_segs->ds_addr);
|
2004-09-23 05:25:22 +00:00
|
|
|
rq3->req_dataseg[rq3->req_seg_count].ds_basehi =
|
2006-02-15 00:31:48 +00:00
|
|
|
DMA_HI32(dm_segs->ds_addr);
|
2004-09-07 08:04:09 +00:00
|
|
|
rq3->req_dataseg[rq3->req_seg_count].ds_count =
|
|
|
|
dm_segs->ds_len;
|
|
|
|
} else {
|
|
|
|
rq->req_dataseg[rq->req_seg_count].ds_base =
|
2006-02-15 00:31:48 +00:00
|
|
|
DMA_LO32(dm_segs->ds_addr);
|
2004-09-23 05:25:22 +00:00
|
|
|
rq->req_dataseg[rq->req_seg_count].ds_basehi =
|
2006-02-15 00:31:48 +00:00
|
|
|
DMA_HI32(dm_segs->ds_addr);
|
2004-09-07 08:04:09 +00:00
|
|
|
rq->req_dataseg[rq->req_seg_count].ds_count =
|
2004-09-23 05:25:22 +00:00
|
|
|
dm_segs->ds_len;
|
2004-09-07 08:04:09 +00:00
|
|
|
}
|
|
|
|
datalen -= dm_segs->ds_len;
|
|
|
|
rq->req_seg_count++;
|
|
|
|
dm_segs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (datalen > 0 && dm_segs != eseg) {
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t onxti;
|
2004-09-07 08:04:09 +00:00
|
|
|
ispcontreq64_t local, *crq = &local, *cqe;
|
|
|
|
|
|
|
|
cqe = (ispcontreq64_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti);
|
|
|
|
onxti = nxti;
|
|
|
|
nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp));
|
|
|
|
if (nxti == mp->optr) {
|
|
|
|
isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++");
|
|
|
|
mp->error = MUSHERR_NOQENTRIES;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
rq->req_header.rqs_entry_count++;
|
|
|
|
MEMZERO((void *)crq, sizeof (*crq));
|
|
|
|
crq->req_header.rqs_entry_count = 1;
|
|
|
|
crq->req_header.rqs_entry_type = RQSTYPE_A64_CONT;
|
|
|
|
|
|
|
|
seglim = 0;
|
|
|
|
while (datalen > 0 && seglim < ISP_CDSEG64 && dm_segs != eseg) {
|
|
|
|
crq->req_dataseg[seglim].ds_base =
|
2006-02-15 00:31:48 +00:00
|
|
|
DMA_LO32(dm_segs->ds_addr);
|
2004-09-23 05:25:22 +00:00
|
|
|
crq->req_dataseg[seglim].ds_basehi =
|
2006-02-15 00:31:48 +00:00
|
|
|
DMA_HI32(dm_segs->ds_addr);
|
2004-09-07 08:04:09 +00:00
|
|
|
crq->req_dataseg[seglim].ds_count =
|
|
|
|
dm_segs->ds_len;
|
|
|
|
rq->req_seg_count++;
|
|
|
|
dm_segs++;
|
|
|
|
seglim++;
|
|
|
|
datalen -= dm_segs->ds_len;
|
|
|
|
}
|
2006-11-02 03:21:32 +00:00
|
|
|
if (isp->isp_dblev & ISP_LOGDEBUG1) {
|
|
|
|
isp_print_bytes(isp, "Continuation", QENTRY_LEN, crq);
|
|
|
|
}
|
2004-09-07 08:04:09 +00:00
|
|
|
isp_put_cont64_req(isp, crq, cqe);
|
|
|
|
MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN);
|
|
|
|
}
|
|
|
|
*mp->nxtip = nxti;
|
|
|
|
}
|
2006-02-15 00:31:48 +00:00
|
|
|
|
1998-09-15 10:06:23 +00:00
|
|
|
static void
|
1998-12-28 19:24:23 +00:00
|
|
|
dma2(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
|
1998-09-15 10:06:23 +00:00
|
|
|
{
|
|
|
|
mush_t *mp;
|
2006-04-21 18:30:01 +00:00
|
|
|
ispsoftc_t *isp;
|
2000-01-03 23:50:13 +00:00
|
|
|
struct ccb_scsiio *csio;
|
2002-04-02 23:36:14 +00:00
|
|
|
struct isp_pcisoftc *pcs;
|
1998-09-15 10:06:23 +00:00
|
|
|
bus_dmamap_t *dp;
|
|
|
|
bus_dma_segment_t *eseg;
|
|
|
|
ispreq_t *rq;
|
2000-01-03 23:50:13 +00:00
|
|
|
int seglim, datalen;
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t nxti;
|
1998-09-15 10:06:23 +00:00
|
|
|
|
|
|
|
mp = (mush_t *) arg;
|
|
|
|
if (error) {
|
|
|
|
mp->error = error;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nseg < 1) {
|
2000-12-05 07:38:41 +00:00
|
|
|
isp_prt(mp->isp, ISP_LOGERR, "bad segment count (%d)", nseg);
|
1998-09-15 10:06:23 +00:00
|
|
|
mp->error = EFAULT;
|
|
|
|
return;
|
|
|
|
}
|
2000-01-03 23:50:13 +00:00
|
|
|
csio = mp->cmd_token;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp = mp->isp;
|
1998-09-15 10:06:23 +00:00
|
|
|
rq = mp->rq;
|
2002-04-02 23:36:14 +00:00
|
|
|
pcs = (struct isp_pcisoftc *)mp->isp;
|
|
|
|
dp = &pcs->dmaps[isp_handle_index(rq->req_handle)];
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
nxti = *mp->nxtip;
|
1999-10-17 19:03:11 +00:00
|
|
|
|
2000-01-03 23:50:13 +00:00
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREREAD);
|
1998-09-15 10:06:23 +00:00
|
|
|
} else {
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_PREWRITE);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
|
2000-01-03 23:50:13 +00:00
|
|
|
datalen = XS_XFRLEN(csio);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We're passed an initial partially filled in entry that
|
|
|
|
* has most fields filled in except for data transfer
|
|
|
|
* related values.
|
|
|
|
*
|
|
|
|
* Our job is to fill in the initial request queue entry and
|
|
|
|
* then to start allocating and filling in continuation entries
|
|
|
|
* until we've covered the entire transfer.
|
|
|
|
*/
|
|
|
|
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
if (IS_FC(isp)) {
|
1998-09-15 10:06:23 +00:00
|
|
|
seglim = ISP_RQDSEG_T2;
|
|
|
|
((ispreqt2_t *)rq)->req_totalcnt = datalen;
|
2000-01-03 23:50:13 +00:00
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
|
|
|
((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_IN;
|
|
|
|
} else {
|
|
|
|
((ispreqt2_t *)rq)->req_flags |= REQFLAG_DATA_OUT;
|
|
|
|
}
|
1998-09-15 10:06:23 +00:00
|
|
|
} else {
|
2000-02-15 00:50:01 +00:00
|
|
|
if (csio->cdb_len > 12) {
|
|
|
|
seglim = 0;
|
|
|
|
} else {
|
|
|
|
seglim = ISP_RQDSEG;
|
|
|
|
}
|
2000-01-03 23:50:13 +00:00
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
|
|
|
rq->req_flags |= REQFLAG_DATA_IN;
|
|
|
|
} else {
|
|
|
|
rq->req_flags |= REQFLAG_DATA_OUT;
|
|
|
|
}
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
eseg = dm_segs + nseg;
|
|
|
|
|
|
|
|
while (datalen != 0 && rq->req_seg_count < seglim && dm_segs != eseg) {
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
if (IS_FC(isp)) {
|
1998-09-15 10:06:23 +00:00
|
|
|
ispreqt2_t *rq2 = (ispreqt2_t *)rq;
|
|
|
|
rq2->req_dataseg[rq2->req_seg_count].ds_base =
|
2006-02-15 00:31:48 +00:00
|
|
|
DMA_LO32(dm_segs->ds_addr);
|
1998-09-15 10:06:23 +00:00
|
|
|
rq2->req_dataseg[rq2->req_seg_count].ds_count =
|
|
|
|
dm_segs->ds_len;
|
|
|
|
} else {
|
|
|
|
rq->req_dataseg[rq->req_seg_count].ds_base =
|
2006-02-15 00:31:48 +00:00
|
|
|
DMA_LO32(dm_segs->ds_addr);
|
1998-09-15 10:06:23 +00:00
|
|
|
rq->req_dataseg[rq->req_seg_count].ds_count =
|
|
|
|
dm_segs->ds_len;
|
|
|
|
}
|
|
|
|
datalen -= dm_segs->ds_len;
|
|
|
|
rq->req_seg_count++;
|
|
|
|
dm_segs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (datalen > 0 && dm_segs != eseg) {
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t onxti;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
ispcontreq_t local, *crq = &local, *cqe;
|
|
|
|
|
|
|
|
cqe = (ispcontreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, nxti);
|
|
|
|
onxti = nxti;
|
|
|
|
nxti = ISP_NXT_QENTRY(onxti, RQUEST_QUEUE_LEN(isp));
|
|
|
|
if (nxti == mp->optr) {
|
|
|
|
isp_prt(isp, ISP_LOGDEBUG0, "Request Queue Overflow++");
|
1998-09-17 21:11:21 +00:00
|
|
|
mp->error = MUSHERR_NOQENTRIES;
|
1998-09-15 10:06:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
rq->req_header.rqs_entry_count++;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
MEMZERO((void *)crq, sizeof (*crq));
|
1998-09-15 10:06:23 +00:00
|
|
|
crq->req_header.rqs_entry_count = 1;
|
|
|
|
crq->req_header.rqs_entry_type = RQSTYPE_DATASEG;
|
|
|
|
|
|
|
|
seglim = 0;
|
|
|
|
while (datalen > 0 && seglim < ISP_CDSEG && dm_segs != eseg) {
|
|
|
|
crq->req_dataseg[seglim].ds_base =
|
2006-02-15 00:31:48 +00:00
|
|
|
DMA_LO32(dm_segs->ds_addr);
|
1998-09-15 10:06:23 +00:00
|
|
|
crq->req_dataseg[seglim].ds_count =
|
|
|
|
dm_segs->ds_len;
|
|
|
|
rq->req_seg_count++;
|
|
|
|
dm_segs++;
|
|
|
|
seglim++;
|
|
|
|
datalen -= dm_segs->ds_len;
|
|
|
|
}
|
2006-11-02 03:21:32 +00:00
|
|
|
if (isp->isp_dblev & ISP_LOGDEBUG1) {
|
|
|
|
isp_print_bytes(isp, "Continuation", QENTRY_LEN, crq);
|
|
|
|
}
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
isp_put_cont_req(isp, crq, cqe);
|
|
|
|
MEMORYBARRIER(isp, SYNC_REQUEST, onxti, QENTRY_LEN);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
*mp->nxtip = nxti;
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
/*
|
|
|
|
* We enter with ISP_LOCK held
|
|
|
|
*/
|
1998-09-15 10:06:23 +00:00
|
|
|
static int
|
2006-04-21 18:30:01 +00:00
|
|
|
isp_pci_dmasetup(ispsoftc_t *isp, struct ccb_scsiio *csio, ispreq_t *rq,
|
2006-11-02 03:21:32 +00:00
|
|
|
uint32_t *nxtip, uint32_t optr)
|
1998-09-15 10:06:23 +00:00
|
|
|
{
|
2002-04-02 23:36:14 +00:00
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
ispreq_t *qep;
|
1999-08-16 19:52:29 +00:00
|
|
|
bus_dmamap_t *dp = NULL;
|
1998-09-15 10:06:23 +00:00
|
|
|
mush_t mush, *mp;
|
2001-08-31 21:39:04 +00:00
|
|
|
void (*eptr)(void *, bus_dma_segment_t *, int, int);
|
1998-09-15 10:06:23 +00:00
|
|
|
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
qep = (ispreq_t *) ISP_QUEUE_ENTRY(isp->isp_rquest, isp->isp_reqidx);
|
2000-01-03 23:50:13 +00:00
|
|
|
#ifdef ISP_TARGET_MODE
|
|
|
|
if (csio->ccb_h.func_code == XPT_CONT_TARGET_IO) {
|
|
|
|
if (IS_FC(isp)) {
|
2000-07-18 06:40:22 +00:00
|
|
|
eptr = tdma_mkfc;
|
2000-01-03 23:50:13 +00:00
|
|
|
} else {
|
2000-07-18 06:40:22 +00:00
|
|
|
eptr = tdma_mk;
|
2000-01-03 23:50:13 +00:00
|
|
|
}
|
2000-07-18 06:40:22 +00:00
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
|
|
|
|
(csio->dxfer_len == 0)) {
|
2000-01-15 01:54:36 +00:00
|
|
|
mp = &mush;
|
|
|
|
mp->isp = isp;
|
|
|
|
mp->cmd_token = csio;
|
2001-04-04 21:53:59 +00:00
|
|
|
mp->rq = rq; /* really a ct_entry_t or ct2_entry_t */
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
mp->nxtip = nxtip;
|
2000-01-15 01:54:36 +00:00
|
|
|
mp->optr = optr;
|
|
|
|
mp->error = 0;
|
2006-04-21 18:30:01 +00:00
|
|
|
ISPLOCK_2_CAMLOCK(isp);
|
2000-01-15 01:54:36 +00:00
|
|
|
(*eptr)(mp, NULL, 0, 0);
|
2006-04-21 18:30:01 +00:00
|
|
|
CAMLOCK_2_ISPLOCK(isp);
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
goto mbxsync;
|
2000-01-15 01:54:36 +00:00
|
|
|
}
|
2000-01-03 23:50:13 +00:00
|
|
|
} else
|
|
|
|
#endif
|
2006-11-02 03:21:32 +00:00
|
|
|
if (IS_24XX(isp)) {
|
|
|
|
eptr = dma_2400;
|
|
|
|
} else if (sizeof (bus_addr_t) > 4) {
|
2006-02-15 00:31:48 +00:00
|
|
|
eptr = dma2_a64;
|
|
|
|
} else {
|
|
|
|
eptr = dma2;
|
|
|
|
}
|
1998-09-15 10:06:23 +00:00
|
|
|
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
|
2000-07-18 06:40:22 +00:00
|
|
|
if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE ||
|
|
|
|
(csio->dxfer_len == 0)) {
|
2000-01-15 01:54:36 +00:00
|
|
|
rq->req_seg_count = 1;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
goto mbxsync;
|
2000-01-15 01:54:36 +00:00
|
|
|
}
|
1998-09-15 10:06:23 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Do a virtual grapevine step to collect info for
|
1998-09-17 21:11:21 +00:00
|
|
|
* the callback dma allocation that we have to use...
|
1998-09-15 10:06:23 +00:00
|
|
|
*/
|
|
|
|
mp = &mush;
|
|
|
|
mp->isp = isp;
|
2000-01-03 23:50:13 +00:00
|
|
|
mp->cmd_token = csio;
|
1998-09-15 10:06:23 +00:00
|
|
|
mp->rq = rq;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
mp->nxtip = nxtip;
|
1998-09-15 10:06:23 +00:00
|
|
|
mp->optr = optr;
|
|
|
|
mp->error = 0;
|
|
|
|
|
2006-04-21 18:30:01 +00:00
|
|
|
ISPLOCK_2_CAMLOCK(isp);
|
2000-01-03 23:50:13 +00:00
|
|
|
if ((csio->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
|
|
|
|
if ((csio->ccb_h.flags & CAM_DATA_PHYS) == 0) {
|
1998-09-17 21:11:21 +00:00
|
|
|
int error, s;
|
2002-04-02 23:36:14 +00:00
|
|
|
dp = &pcs->dmaps[isp_handle_index(rq->req_handle)];
|
1998-09-15 10:06:23 +00:00
|
|
|
s = splsoftvm();
|
2002-04-02 23:36:14 +00:00
|
|
|
error = bus_dmamap_load(pcs->dmat, *dp,
|
2000-01-03 23:50:13 +00:00
|
|
|
csio->data_ptr, csio->dxfer_len, eptr, mp, 0);
|
1998-09-15 10:06:23 +00:00
|
|
|
if (error == EINPROGRESS) {
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_dmamap_unload(pcs->dmat, *dp);
|
1998-09-15 10:06:23 +00:00
|
|
|
mp->error = EINVAL;
|
2000-12-05 07:38:41 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"deferred dma allocation not supported");
|
1998-09-15 10:06:23 +00:00
|
|
|
} else if (error && mp->error == 0) {
|
1999-08-16 19:52:29 +00:00
|
|
|
#ifdef DIAGNOSTIC
|
2001-03-01 02:21:36 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"error %d in dma mapping code", error);
|
1999-08-16 19:52:29 +00:00
|
|
|
#endif
|
1998-09-15 10:06:23 +00:00
|
|
|
mp->error = error;
|
|
|
|
}
|
1998-09-17 21:11:21 +00:00
|
|
|
splx(s);
|
1998-09-15 10:06:23 +00:00
|
|
|
} else {
|
|
|
|
/* Pointer to physical buffer */
|
1999-03-17 05:07:18 +00:00
|
|
|
struct bus_dma_segment seg;
|
2004-09-07 08:04:09 +00:00
|
|
|
seg.ds_addr = (bus_addr_t)(vm_offset_t)csio->data_ptr;
|
1998-09-15 10:06:23 +00:00
|
|
|
seg.ds_len = csio->dxfer_len;
|
2000-01-03 23:50:13 +00:00
|
|
|
(*eptr)(mp, &seg, 1, 0);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
struct bus_dma_segment *segs;
|
|
|
|
|
2000-01-03 23:50:13 +00:00
|
|
|
if ((csio->ccb_h.flags & CAM_DATA_PHYS) != 0) {
|
2000-12-05 07:38:41 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"Physical segment pointers unsupported");
|
1998-09-15 10:06:23 +00:00
|
|
|
mp->error = EINVAL;
|
2000-01-03 23:50:13 +00:00
|
|
|
} else if ((csio->ccb_h.flags & CAM_SG_LIST_PHYS) == 0) {
|
2000-12-05 07:38:41 +00:00
|
|
|
isp_prt(isp, ISP_LOGERR,
|
|
|
|
"Virtual segment addresses unsupported");
|
1998-09-15 10:06:23 +00:00
|
|
|
mp->error = EINVAL;
|
|
|
|
} else {
|
|
|
|
/* Just use the segments provided */
|
|
|
|
segs = (struct bus_dma_segment *) csio->data_ptr;
|
2000-01-03 23:50:13 +00:00
|
|
|
(*eptr)(mp, segs, csio->sglist_cnt, 0);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
}
|
2006-04-21 18:30:01 +00:00
|
|
|
CAMLOCK_2_ISPLOCK(isp);
|
1998-09-15 10:06:23 +00:00
|
|
|
if (mp->error) {
|
1998-09-17 21:11:21 +00:00
|
|
|
int retval = CMD_COMPLETE;
|
|
|
|
if (mp->error == MUSHERR_NOQENTRIES) {
|
|
|
|
retval = CMD_EAGAIN;
|
|
|
|
} else if (mp->error == EFBIG) {
|
1999-08-16 19:52:29 +00:00
|
|
|
XS_SETERR(csio, CAM_REQ_TOO_BIG);
|
1998-09-15 10:06:23 +00:00
|
|
|
} else if (mp->error == EINVAL) {
|
1999-08-16 19:52:29 +00:00
|
|
|
XS_SETERR(csio, CAM_REQ_INVALID);
|
1998-09-15 10:06:23 +00:00
|
|
|
} else {
|
1999-08-16 19:52:29 +00:00
|
|
|
XS_SETERR(csio, CAM_UNREC_HBA_ERROR);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
1998-09-17 21:11:21 +00:00
|
|
|
return (retval);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
mbxsync:
|
2006-11-02 03:21:32 +00:00
|
|
|
if (isp->isp_dblev & ISP_LOGDEBUG1) {
|
|
|
|
isp_print_bytes(isp, "Request Queue Entry", QENTRY_LEN, rq);
|
|
|
|
}
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
switch (rq->req_header.rqs_entry_type) {
|
|
|
|
case RQSTYPE_REQUEST:
|
|
|
|
isp_put_request(isp, rq, qep);
|
|
|
|
break;
|
|
|
|
case RQSTYPE_CMDONLY:
|
|
|
|
isp_put_extended_request(isp, (ispextreq_t *)rq,
|
|
|
|
(ispextreq_t *)qep);
|
|
|
|
break;
|
|
|
|
case RQSTYPE_T2RQS:
|
|
|
|
isp_put_request_t2(isp, (ispreqt2_t *) rq, (ispreqt2_t *) qep);
|
|
|
|
break;
|
2004-09-07 08:04:09 +00:00
|
|
|
case RQSTYPE_A64:
|
|
|
|
case RQSTYPE_T3RQS:
|
|
|
|
isp_put_request_t3(isp, (ispreqt3_t *) rq, (ispreqt3_t *) qep);
|
|
|
|
break;
|
2006-11-02 03:21:32 +00:00
|
|
|
case RQSTYPE_T7RQS:
|
|
|
|
isp_put_request_t7(isp, (ispreqt7_t *) rq, (ispreqt7_t *) qep);
|
|
|
|
break;
|
Major restructuring for swizzling to the request queue and unswizzling from
the response queue. Instead of the ad hoc ISP_SWIZZLE_REQUEST, we now have
a complete set of inline functions in isp_inline.h. Each platform is
responsible for providing just one of a set of ISP_IOX_{GET,PUT}{8,16,32}
macros.
The reason this needs to be done is that we need to have a single set of
functions that will work correctly on multiple architectures for both little
and big endian machines. It also needs to work correctly in the case that
we have the request or response queues in memory that has to be treated
specially (e.g., have ddi_dma_sync called on it for Solaris after we update
it or before we read from it). It also has to handle the SBus cards (for
platforms that have them) which, while on a Big Endian machine, do *not*
require *most* of the request/response queue entry fields to be swizzled
or unswizzled.
One thing that falls out of this is that we no longer build requests in the
request queue itself. Instead, we build the request locally (e.g., on the
stack) and then as part of the swizzling operation, copy it to the request
queue entry we've allocated. I thought long and hard about whether this was
too expensive a change to make as it in a lot of cases requires an extra
copy. On balance, the flexbility is worth it. With any luck, the entry that
we build locally stays in a processor writeback cache (after all, it's only
64 bytes) so that the cost of actually flushing it to the memory area that is
the shared queue with the PCI device is not all that expensive. We may examine
this again and try to get clever in the future to try and avoid copies.
Another change that falls out of this is that MEMORYBARRIER should be taken
a lot more seriously. The macro ISP_ADD_REQUEST does a MEMORYBARRIER on the
entry being added. But there had been many other places this had been missing.
It's now very important that it be done.
Additional changes:
Fix a longstanding buglet of sorts. When we get an entry via isp_getrqentry,
the iptr value that gets returned is the value we intend to eventually plug
into the ISP registers as the entry *one past* the last one we've written-
*not* the current entry we're updating. All along we've been calling sync
functions on the wrong index value. Argh. The 'fix' here is to rename all
'iptr' variables as 'nxti' to remember that this is the 'next' pointer-
not the current pointer.
Devote a single bit to mboxbsy- and set aside bits for output mbox registers
that we need to pick up- we can have at least one command which does not
have any defined output registers (MBOX_EXECUTE_FIRMWARE).
MFC after: 2 weeks
2001-12-11 00:18:45 +00:00
|
|
|
}
|
|
|
|
return (CMD_QUEUED);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-11-02 03:21:32 +00:00
|
|
|
isp_pci_dmateardown(ispsoftc_t *isp, XS_T *xs, uint32_t handle)
|
1998-09-15 10:06:23 +00:00
|
|
|
{
|
2002-04-02 23:36:14 +00:00
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp;
|
|
|
|
bus_dmamap_t *dp = &pcs->dmaps[isp_handle_index(handle)];
|
1999-10-17 19:03:11 +00:00
|
|
|
if ((xs->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTREAD);
|
1998-09-15 10:06:23 +00:00
|
|
|
} else {
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_dmamap_sync(pcs->dmat, *dp, BUS_DMASYNC_POSTWRITE);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
2002-04-02 23:36:14 +00:00
|
|
|
bus_dmamap_unload(pcs->dmat, *dp);
|
1998-09-15 10:06:23 +00:00
|
|
|
}
|
|
|
|
|
1998-04-22 18:12:29 +00:00
|
|
|
|
|
|
|
static void
|
2006-04-21 18:30:01 +00:00
|
|
|
isp_pci_reset1(ispsoftc_t *isp)
|
1998-04-22 18:12:29 +00:00
|
|
|
{
|
2006-11-02 03:21:32 +00:00
|
|
|
if (!IS_24XX(isp)) {
|
|
|
|
/* Make sure the BIOS is disabled */
|
|
|
|
isp_pci_wr_reg(isp, HCCR, PCI_HCCR_CMD_BIOS);
|
|
|
|
}
|
2000-07-04 01:01:15 +00:00
|
|
|
/* and enable interrupts */
|
2006-11-02 03:21:32 +00:00
|
|
|
ISP_ENABLE_INTS(isp);
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2006-04-21 18:30:01 +00:00
|
|
|
isp_pci_dumpregs(ispsoftc_t *isp, const char *msg)
|
1998-04-22 18:12:29 +00:00
|
|
|
{
|
2002-04-02 23:36:14 +00:00
|
|
|
struct isp_pcisoftc *pcs = (struct isp_pcisoftc *)isp;
|
2000-08-01 05:16:49 +00:00
|
|
|
if (msg)
|
2001-03-01 02:21:36 +00:00
|
|
|
printf("%s: %s\n", device_get_nameunit(isp->isp_dev), msg);
|
|
|
|
else
|
|
|
|
printf("%s:\n", device_get_nameunit(isp->isp_dev));
|
2000-08-01 05:16:49 +00:00
|
|
|
if (IS_SCSI(isp))
|
|
|
|
printf(" biu_conf1=%x", ISP_READ(isp, BIU_CONF1));
|
|
|
|
else
|
|
|
|
printf(" biu_csr=%x", ISP_READ(isp, BIU2100_CSR));
|
|
|
|
printf(" biu_icr=%x biu_isr=%x biu_sema=%x ", ISP_READ(isp, BIU_ICR),
|
|
|
|
ISP_READ(isp, BIU_ISR), ISP_READ(isp, BIU_SEMA));
|
|
|
|
printf("risc_hccr=%x\n", ISP_READ(isp, HCCR));
|
|
|
|
|
|
|
|
|
|
|
|
if (IS_SCSI(isp)) {
|
|
|
|
ISP_WRITE(isp, HCCR, HCCR_CMD_PAUSE);
|
|
|
|
printf(" cdma_conf=%x cdma_sts=%x cdma_fifostat=%x\n",
|
|
|
|
ISP_READ(isp, CDMA_CONF), ISP_READ(isp, CDMA_STATUS),
|
|
|
|
ISP_READ(isp, CDMA_FIFO_STS));
|
|
|
|
printf(" ddma_conf=%x ddma_sts=%x ddma_fifostat=%x\n",
|
|
|
|
ISP_READ(isp, DDMA_CONF), ISP_READ(isp, DDMA_STATUS),
|
|
|
|
ISP_READ(isp, DDMA_FIFO_STS));
|
|
|
|
printf(" sxp_int=%x sxp_gross=%x sxp(scsi_ctrl)=%x\n",
|
|
|
|
ISP_READ(isp, SXP_INTERRUPT),
|
|
|
|
ISP_READ(isp, SXP_GROSS_ERR),
|
|
|
|
ISP_READ(isp, SXP_PINS_CTRL));
|
|
|
|
ISP_WRITE(isp, HCCR, HCCR_CMD_RELEASE);
|
|
|
|
}
|
|
|
|
printf(" mbox regs: %x %x %x %x %x\n",
|
|
|
|
ISP_READ(isp, OUTMAILBOX0), ISP_READ(isp, OUTMAILBOX1),
|
|
|
|
ISP_READ(isp, OUTMAILBOX2), ISP_READ(isp, OUTMAILBOX3),
|
|
|
|
ISP_READ(isp, OUTMAILBOX4));
|
|
|
|
printf(" PCI Status Command/Status=%x\n",
|
2002-04-02 23:36:14 +00:00
|
|
|
pci_read_config(pcs->pci_dev, PCIR_COMMAND, 1));
|
1998-04-22 18:12:29 +00:00
|
|
|
}
|