Add a driver for ICP-Vortex GDT and Intel Storage RAID controllers. Parts

taken from OpenBSD. Test hardware kindly provided by Intel. This still needs
management bits, and doesn't support older controllers, but that shouldn't
be hard to fix.
This commit is contained in:
ad 2002-04-22 21:05:19 +00:00
parent 84b0f1e37d
commit 9a09578e25
19 changed files with 2908 additions and 14 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: mi,v 1.467 2002/04/19 09:47:10 wiz Exp $
# $NetBSD: mi,v 1.468 2002/04/22 21:05:20 ad Exp $
./usr/share/info/am-utils.info man-amd-info
./usr/share/info/as.info man-computil-info
./usr/share/info/awk.info man-util-info
@ -680,6 +680,7 @@
./usr/share/man/cat4/i386/pnpbios.0 man-sys-catman
./usr/share/man/cat4/icmp.0 man-sys-catman
./usr/share/man/cat4/icmp6.0 man-sys-catman
./usr/share/man/cat4/icp.0 man-sys-catman
./usr/share/man/cat4/icsphy.0 man-sys-catman
./usr/share/man/cat4/idp.0 man-sys-catman
./usr/share/man/cat4/ifmedia.0 man-sys-catman
@ -2370,6 +2371,7 @@
./usr/share/man/man4/i386/pnpbios.4 man-sys-man
./usr/share/man/man4/icmp.4 man-sys-man
./usr/share/man/man4/icmp6.4 man-sys-man
./usr/share/man/man4/icp.4 man-sys-man
./usr/share/man/man4/icsphy.4 man-sys-man
./usr/share/man/man4/idp.4 man-sys-man
./usr/share/man/man4/ifmedia.4 man-sys-man

View File

@ -1,4 +1,4 @@
# $NetBSD: Makefile,v 1.254 2002/04/02 20:45:40 augustss Exp $
# $NetBSD: Makefile,v 1.255 2002/04/22 21:05:19 ad Exp $
# @(#)Makefile 8.1 (Berkeley) 6/18/93
MAN= acphy.4 adv.4 adw.4 agp.4 ahb.4 ahc.4 amhphy.4 an.4 aria.4 \
@ -10,7 +10,7 @@ MAN= acphy.4 adv.4 adw.4 agp.4 ahb.4 ahc.4 amhphy.4 an.4 aria.4 \
ebus.4 edc.4 elmc.4 emuxki.4 en.4 envsys.4 ep.4 esh.4 esis.4 esa.4 \
esl.4 esm.4 eso.4 exphy.4 \
fd.4 fpa.4 fms.4 fxp.4 gentbi.4 glxtphy.4 gre.4 gphyter.4 gsip.4 hme.4 \
icmp.4 icsphy.4 idp.4 ifmedia.4 iha.4 inet.4 inphy.4 intersil7170.4 \
icmp.4 icp.4 icsphy.4 idp.4 ifmedia.4 iha.4 inet.4 inphy.4 intersil7170.4 \
ioasic.4 ioat.4 \
iop.4 iophy.4 iopsp.4 ip.4 ipkdb.4 iso.4 isp.4 joy.4 \
lc.4 ld.4 lkm.4 \
@ -105,6 +105,7 @@ MLINKS+=viaenv.4 viapm.4
MLINKS+=tty.4 dty.4
MLINKS+=rcons.4 rasterconsole.4
MLINKS+=irframe.4 irda.4
MLINKS+=icp.4 icpsp.4
# This is a hack
MLINKS+=edc.4 i386/ed.4

64
share/man/man4/icp.4 Normal file
View File

@ -0,0 +1,64 @@
.\" $NetBSD: icp.4,v 1.1 2002/04/22 21:05:19 ad Exp $
.\"
.\" from OpenBSD: gdt.4,v 1.14 2001/10/05 14:45:53 mpech Exp
.\"
.\" Copyright (c) 2000 Niklas Hallqvist. All rights reserved.
.\" Copyright (c) 2002 Andrew Doran. All rights reserved.
.\"
.Dd April 20, 2002
.Dt ICP 4
.Os
.Sh NAME
.Nm icp
.Nd ICP-Vortex and Intel Storage RAID driver
.Sh SYNOPSIS
.Cd "icp* at pci? dev ? function ?"
.Cd "ld* at icp? unit ?"
.Cd "icpsp* at icp? unit ?"
.Cd "scsibus* at icpsp?"
.Sh DESCRIPTION
The
.Nm
driver provides support for the newer (post 1997) ICP-Vortex GDT and Intel
Storage RAID controllers.
.Pp
The
.Nm ld
driver provides access to logical devices (disk arrays) presented by the
controller.
The
.Nm icpsp
driver provides direct access to other SCSI devices attched to the
controller, such as tape or CD-ROM drives.
.Sh DIAGNOSTICS
.Bl -tag
.It "pci_mem_find: expected mem type 00000000, found 00000002"
This message may be displayed during autoconfiguration if the controller's
memory is mapped below 1MB in physical address space.
This can be disabled either through changing a setting in the controller's
BIOS utility, or changing the position of a jumper on the board.
See your controller's documentation for more information.
.El
.Sh SEE ALSO
.Xr intro 4 ,
.Xr ld 4 ,
.Xr scsi 4
.Sh AUTHORS
The
.Nm
driver was written by
.An Andrew Doran
.Aq ad@netbsd.org .
It is derived in part from the
.Ox
.Nm gdt
driver, written by Niklas Hallqvist.
.Sh HISTORY
The
.Nm
driver first appeared in
.Nx 1.6 .
.Sh BUGS
ISA & EISA front-ends and a management interface are needed.
.Pp
Older PCI boards are not yet supported.

View File

@ -1,4 +1,4 @@
.\" $NetBSD: ld.4,v 1.6 2001/11/28 17:41:46 ad Exp $
.\" $NetBSD: ld.4,v 1.7 2002/04/22 21:05:20 ad Exp $
.\"
.\" Copyright (c) 2000 The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -42,6 +42,7 @@
.Nd logical disk driver
.Sh SYNOPSIS
.Cd ld* at cac? unit ?
.Cd ld* at icp? unit ?
.Cd ld* at iop? tid ?
.Cd ld* at mlx? unit ?
.Cd ld* at twe? unit ?
@ -66,6 +67,7 @@ partition
.El
.Sh SEE ALSO
.Xr cac 4 ,
.Xr icp 4 ,
.Xr intro 4 ,
.Xr iop 4 ,
.Xr mlx 4 ,

View File

@ -1,4 +1,4 @@
.\" $NetBSD: pci.4,v 1.65 2002/01/06 17:01:25 wiz Exp $
.\" $NetBSD: pci.4,v 1.66 2002/04/22 21:05:19 ad Exp $
.\"
.\" Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
.\" Copyright (c) 1997 Jonathan Stone
@ -122,6 +122,8 @@ interfaces.
.Bl -tag -width pcdisplay -offset indent
.It cac
Compaq array controllers.
.It icp
ICP Vortex GDT and Intel Storage RAID controllers.
.It mlx
Mylex DAC960 and DEC SWXCR RAID controllers.
.It pciide
@ -354,6 +356,7 @@ VGA graphics boards.
.Xr fxp 4 ,
.Xr gsip 4 ,
.Xr hme 4 ,
.Xr icp 4 ,
.Xr iha 4 ,
.Xr intro 4 ,
.Xr iop 4 ,

View File

@ -1,4 +1,4 @@
.\" $NetBSD: scsi.4,v 1.19 2001/11/07 16:45:50 tsutsui Exp $
.\" $NetBSD: scsi.4,v 1.20 2002/04/22 21:05:20 ad Exp $
.\" Copyright (c) 1996
.\" Julian Elischer <julian@freebsd.org>. All rights reserved.
.\"
@ -43,6 +43,7 @@
.Cd "scsibus* at cosc?"
.Cd "scsibus* at dpt?"
.Cd "scsibus* at esp?"
.Cd "scsibus* at icpsp?"
.Cd "scsibus* at iha?"
.Cd "scsibus* at iopsp?"
.Cd "scsibus* at isp?"

View File

@ -1,4 +1,4 @@
# $NetBSD: GENERIC,v 1.486 2002/04/18 12:54:13 wiz Exp $
# $NetBSD: GENERIC,v 1.487 2002/04/22 21:05:22 ad Exp $
#
# GENERIC machine description file
#
@ -20,7 +20,7 @@
include "arch/i386/conf/std.i386"
#ident "GENERIC-$Revision: 1.486 $"
#ident "GENERIC-$Revision: 1.487 $"
maxusers 32 # estimated number of users
@ -513,14 +513,19 @@ uk* at scsibus? target ? lun ? # SCSI unknown
# RAID controllers and devices
cac* at eisa? slot ? # Compaq EISA array controllers
cac* at pci? dev ? function ? # Compaq PCI array controllers
icp* at pci? dev ? function ? # ICP-Vortex GDT & Intel RAID
mlx* at pci? dev ? function ? # Mylex DAC960 & DEC SWXCR family
mlx* at eisa? slot ? # Mylex DAC960 & DEC SWXCR family
twe* at pci? dev ? function ? # 3ware Escalade RAID controllers
ld* at cac? unit ? # logical disk devices
ld* at icp? unit ?
ld* at twe? unit ?
ld* at mlx? unit ?
icpsp* at icp? unit ? # SCSI pass-through
scsibus* at icpsp?
# IDE and related devices
# PCI IDE controllers - see pciide(4) for supported hardware.
# The 0x0001 flag force the driver to use DMA, even if the driver doesn't know

View File

@ -1,4 +1,4 @@
# $NetBSD: INSTALL,v 1.193 2002/04/18 12:54:14 wiz Exp $
# $NetBSD: INSTALL,v 1.194 2002/04/22 21:05:23 ad Exp $
#
# INSTALL - Installation kernel.
#
@ -370,14 +370,19 @@ cd* at scsibus? target ? lun ? # SCSI CD-ROM drives
# RAID controllers and devices
cac* at eisa? slot ? # Compaq EISA array controllers
cac* at pci? dev ? function ? # Compaq PCI array controllers
icp* at pci? dev ? function ? # ICP-Vortex GDT & Intel RAID
mlx* at pci? dev ? function ? # Mylex DAC960 & DEC SWXCR family
mlx* at eisa? slot ? # Mylex DAC960 & DEC SWXCR family
twe* at pci? dev ? function ? # 3ware Escalade RAID controllers
ld* at cac? unit ? # logical disk devices
ld* at icp? unit ?
ld* at twe? unit ?
ld* at mlx? unit ?
icpsp* at icp? unit ? # SCSI pass-through
scsibus* at icpsp?
# IDE and related devices
# PCI IDE controllers - see pciide(4) for supported hardware.
# The 0x0001 flag force the driver to use DMA, even if the driver doesn't know

View File

@ -1,4 +1,4 @@
# $NetBSD: INSTALL_SMALL,v 1.82 2002/04/18 12:54:14 wiz Exp $
# $NetBSD: INSTALL_SMALL,v 1.83 2002/04/22 21:05:23 ad Exp $
#
# INSTALL_SMALL - Small Installation kernel.
#
@ -326,14 +326,19 @@ cd* at scsibus? target ? lun ? # SCSI CD-ROM drives
# RAID controllers and devices
#cac* at eisa? slot ? # Compaq EISA array controllers
#cac* at pci? dev ? function ? # Compaq PCI array controllers
#icp* at pci? dev ? function ? # ICP-Vortex GDT & Intel RAID
#mlx* at pci? dev ? function ? # Mylex DAC960 & DEC SWXCR family
#mlx* at eisa? slot ? # Mylex DAC960 & DEC SWXCR family
#twe* at pci? dev ? function ? # 3ware Escalade RAID controllers
#ld* at cac? unit ? # logical disk devices
#ld* at icp? unit ?
#ld* at twe? unit ?
#ld* at mlx? unit ?
#icpsp* at icp? unit ? # SCSI pass-through
#scsibus* at icpsp?
# IDE and related devices
# ST506, ESDI, and ISA IDE controllers

View File

@ -1,4 +1,4 @@
# $NetBSD: INSTALL_TINY,v 1.50 2002/04/18 12:54:14 wiz Exp $
# $NetBSD: INSTALL_TINY,v 1.51 2002/04/22 21:05:23 ad Exp $
#
# INSTALL_TINY - Tiny Installation kernel, suitable for 4M machines.
#
@ -327,14 +327,19 @@ pc0 at isa? port 0x60 irq 1 # pccons generic PC console driver
# RAID controllers and devices
#cac* at eisa? slot ? # Compaq EISA array controllers
#cac* at pci? dev ? function ? # Compaq PCI array controllers
#icp* at pci? dev ? function ? # ICP-Vortex GDT & Intel RAID
#mlx* at pci? dev ? function ? # Mylex DAC960 & DEC SWXCR family
#mlx* at eisa? slot ? # Mylex DAC960 & DEC SWXCR family
#twe* at pci? dev ? function ? # 3ware Escalade RAID controllers
#ld* at cac? unit ? # logical disk devices
#ld* at icp? unit ?
#ld* at twe? unit ?
#ld* at mlx? unit ?
#icpsp* at icp? unit ? # SCSI pass-through
#scsibus* at icpsp?
# IDE and related devices

View File

@ -1,4 +1,4 @@
# $NetBSD: files,v 1.520 2002/04/22 13:03:06 augustss Exp $
# $NetBSD: files,v 1.521 2002/04/22 21:05:22 ad Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
@ -298,6 +298,18 @@ file dev/ic/mlx.c mlx needs-flag
attach ld at mlx with ld_mlx
file dev/ic/ld_mlx.c ld_mlx
# ICP-Vortex/Intel RAID controllers
#
device icp {unit = -1}
file dev/ic/icp.c icp needs-flag
attach ld at icp with ld_icp
file dev/ic/ld_icp.c ld_icp
device icpsp: scsi
file dev/ic/icpsp.c icpsp
attach icpsp at icp
# AdvanSys 1200A, 1200B and ULTRA SCSI controllers
#
device adv: scsi

View File

@ -1,4 +1,4 @@
# $NetBSD: DEVNAMES,v 1.109 2002/04/22 12:43:50 augustss Exp $
# $NetBSD: DEVNAMES,v 1.110 2002/04/22 21:05:22 ad Exp $
#
# This file contains all used device names and defined attributes in
# alphabetical order. New devices added to the system somewhere should first
@ -462,6 +462,8 @@ i8042 arm32 Attribute
i82586 MI Attribute
ibus pmax
ibus vax
icp MI
icpsp MI
ics2101 MI Attribute
icside arm32
icsphy MI

776
sys/dev/ic/icp.c Normal file
View File

@ -0,0 +1,776 @@
/* $NetBSD: icp.c,v 1.1 2002/04/22 21:05:21 ad Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niklas Hallqvist.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
* from OpenBSD: gdt_common.c,v 1.12 2001/07/04 06:43:18 niklas Exp
*/
/*
* This driver would not have written if it was not for the hardware donations
* from both ICP-Vortex and Öko.neT. I want to thank them for their support.
*
* Re-worked for NetBSD by Andrew Doran. Test hardware kindly supplied by
* Intel.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icp.c,v 1.1 2002/04/22 21:05:21 ad Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/queue.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/disk.h>
#include <uvm/uvm_extern.h>
#include <machine/bswap.h>
#include <machine/bus.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/ic/icpreg.h>
#include <dev/ic/icpvar.h>
int icp_async_event(struct icp_softc *, int);
void icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic);
void icp_chain(struct icp_softc *);
int icp_print(void *, const char *);
int icp_submatch(struct device *, struct cfdata *, void *);
void icp_watchdog(void *);
int
icp_init(struct icp_softc *icp, const char *intrstr)
{
struct icp_attach_args icpa;
struct icp_binfo binfo;
struct icp_ccb *ic;
u_int16_t cdev_cnt;
int i, j, state, feat, nsegs, rv, noscsi, nocache;
noscsi = 0;
nocache = 0;
if (intrstr != NULL)
printf("%s: interrupting at %s\n", icp->icp_dv.dv_xname,
intrstr);
SIMPLEQ_INIT(&icp->icp_ccb_queue);
SIMPLEQ_INIT(&icp->icp_ccb_freelist);
callout_init(&icp->icp_wdog_callout);
/*
* Allocate a scratch area.
*/
if (bus_dmamap_create(icp->icp_dmat, ICP_SCRATCH_SIZE, 1,
ICP_SCRATCH_SIZE, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
&icp->icp_scr_dmamap) != 0) {
printf("%s: cannot create scratch dmamap\n",
icp->icp_dv.dv_xname);
return (1);
}
state++;
if (bus_dmamem_alloc(icp->icp_dmat, ICP_SCRATCH_SIZE, PAGE_SIZE, 0,
icp->icp_scr_seg, 1, &nsegs, BUS_DMA_NOWAIT) != 0) {
printf("%s: cannot alloc scratch dmamem\n",
icp->icp_dv.dv_xname);
goto bail_out;
}
state++;
if (bus_dmamem_map(icp->icp_dmat, icp->icp_scr_seg, nsegs,
ICP_SCRATCH_SIZE, &icp->icp_scr, 0)) {
printf("%s: cannot map scratch dmamem\n", icp->icp_dv.dv_xname);
goto bail_out;
}
state++;
if (bus_dmamap_load(icp->icp_dmat, icp->icp_scr_dmamap, icp->icp_scr,
ICP_SCRATCH_SIZE, NULL, BUS_DMA_NOWAIT)) {
printf("%s: cannot load scratch dmamap\n", icp->icp_dv.dv_xname);
goto bail_out;
}
state++;
/*
* Allocate and initialize the command control blocks.
*/
ic = malloc(sizeof(*ic) * ICP_NCCBS, M_DEVBUF, M_NOWAIT | M_ZERO);
if ((icp->icp_ccbs = ic) == NULL) {
printf("%s: malloc() failed\n", icp->icp_dv.dv_xname);
goto bail_out;
}
state++;
for (i = 0; i < ICP_NCCBS; i++, ic++) {
/*
* The first two command indexes have special meanings, so
* we can't use them.
*/
ic->ic_ident = i + 2;
rv = bus_dmamap_create(icp->icp_dmat, ICP_MAX_XFER,
ICP_MAXSG, ICP_MAX_XFER, 0,
BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
&ic->ic_xfer_map);
if (rv != 0)
break;
icp->icp_nccbs++;
icp_ccb_free(icp, ic);
}
#ifdef DIAGNOSTIC
if (icp->icp_nccbs != ICP_NCCBS)
printf("%s: %d/%d CCBs usable\n", icp->icp_dv.dv_xname,
icp->icp_nccbs, ICP_NCCBS);
#endif
/*
* Initalize the controller.
*/
if (!icp_cmd(icp, ICP_SCREENSERVICE, ICP_INIT, 0, 0, 0)) {
printf("%s: screen service init error %d\n",
icp->icp_dv.dv_xname, icp->icp_status);
goto bail_out;
}
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
printf("%s: cache service init error %d\n",
icp->icp_dv.dv_xname, icp->icp_status);
goto bail_out;
}
icp_cmd(icp, ICP_CACHESERVICE, ICP_UNFREEZE_IO, 0, 0, 0);
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_MOUNT, 0xffff, 1, 0)) {
printf("%s: cache service mount error %d\n",
icp->icp_dv.dv_xname, icp->icp_status);
goto bail_out;
}
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INIT, ICP_LINUX_OS, 0, 0)) {
printf("%s: cache service post-mount init error %d\n",
icp->icp_dv.dv_xname, icp->icp_status);
goto bail_out;
}
cdev_cnt = (u_int16_t)icp->icp_info;
if (!icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_INIT, 0, 0, 0)) {
printf("%s: raw service init error %d\n",
icp->icp_dv.dv_xname, icp->icp_status);
goto bail_out;
}
/*
* Set/get raw service features (scatter/gather).
*/
feat = 0;
if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_SET_FEAT, ICP_SCATTER_GATHER,
0, 0))
if (icp_cmd(icp, ICP_SCSIRAWSERVICE, ICP_GET_FEAT, 0, 0, 0))
feat = icp->icp_info;
if ((feat & ICP_SCATTER_GATHER) == 0) {
#ifdef DIAGNOSTIC
printf("%s: scatter/gather not supported (raw service)\n",
icp->icp_dv.dv_xname);
#endif
noscsi = 1;
}
/*
* Set/get cache service features (scatter/gather).
*/
feat = 0;
if (icp_cmd(icp, ICP_CACHESERVICE, ICP_SET_FEAT, 0,
ICP_SCATTER_GATHER, 0))
if (icp_cmd(icp, ICP_CACHESERVICE, ICP_GET_FEAT, 0, 0, 0))
feat = icp->icp_info;
if ((feat & ICP_SCATTER_GATHER) == 0) {
#ifdef DIAGNOSTIC
printf("%s: scatter/gather not supported (cache service)\n",
icp->icp_dv.dv_xname);
#endif
nocache = 1;
}
/*
* Pull some information from the board and dump.
*/
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, ICP_BOARD_INFO,
ICP_INVALID_CHANNEL, sizeof(struct icp_binfo))) {
printf("%s: unable to retrive board info\n",
icp->icp_dv.dv_xname);
goto bail_out;
}
memcpy(&binfo, icp->icp_scr, sizeof(binfo));
printf("%s: model <%s>, firmware <%s>, %d channel(s), %dMB memory\n",
icp->icp_dv.dv_xname, binfo.bi_type_string, binfo.bi_raid_string,
binfo.bi_chan_count, le32toh(binfo.bi_memsize) >> 20);
/*
* Determine the number of devices, and number of openings per
* device.
*/
if (!nocache) {
for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_INFO, j, 0,
0))
continue;
icp->icp_cdr[j].cd_size = icp->icp_info;
icp->icp_ndevs++;
if (icp_cmd(icp, ICP_CACHESERVICE, ICP_DEVTYPE, j, 0,
0))
icp->icp_cdr[j].cd_type = icp->icp_info;
}
}
if (!noscsi)
icp->icp_ndevs += binfo.bi_chan_count;
if (icp->icp_ndevs != 0)
icp->icp_openings =
(icp->icp_nccbs - ICP_NCCB_RESERVE) / icp->icp_ndevs;
#ifdef ICP_DEBUG
printf("%s: %d openings per device\n", icp->icp_dv.dv_xname,
icp->icp_openings);
#endif
/*
* Attach SCSI channels.
*/
if (!noscsi) {
struct icp_ioc_version *iv;
struct icp_rawioc *ri;
struct icp_getch *gc;
iv = (struct icp_ioc_version *)icp->icp_scr;
iv->iv_version = htole32(ICP_IOC_NEWEST);
iv->iv_listents = ICP_MAXBUS;
iv->iv_firstchan = 0;
iv->iv_lastchan = ICP_MAXBUS - 1;
iv->iv_listoffset = htole32(sizeof(*iv));
if (icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
ICP_IOCHAN_RAW_DESC, ICP_INVALID_CHANNEL,
sizeof(*iv) + ICP_MAXBUS * sizeof(*ri))) {
ri = (struct icp_rawioc *)(iv + 1);
for (j = 0; j < binfo.bi_chan_count; j++, ri++)
icp->icp_bus_id[j] = ri->ri_procid;
} else {
/*
* Fall back to the old method.
*/
gc = (struct icp_getch *)icp->icp_scr;
for (i = 0; j < binfo.bi_chan_count; j++) {
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL,
ICP_SCSI_CHAN_CNT | ICP_L_CTRL_PATTERN,
ICP_IO_CHANNEL | ICP_INVALID_CHANNEL,
sizeof(*gc))) {
printf("%s: unable to get chan info",
icp->icp_dv.dv_xname);
goto bail_out;
}
icp->icp_bus_id[j] = gc->gc_scsiid;
}
}
for (j = 0; j < binfo.bi_chan_count; j++) {
if (icp->icp_bus_id[j] > ICP_MAXID_FC)
icp->icp_bus_id[j] = ICP_MAXID_FC;
icpa.icpa_unit = j + ICPA_UNIT_SCSI;
config_found_sm(&icp->icp_dv, &icpa, icp_print,
icp_submatch);
}
}
/*
* Attach cache devices.
*/
if (!nocache) {
for (j = 0; j < cdev_cnt && j < ICP_MAX_HDRIVES; j++) {
if (icp->icp_cdr[j].cd_size == 0)
continue;
icpa.icpa_unit = j;
config_found_sm(&icp->icp_dv, &icpa, icp_print,
icp_submatch);
}
}
/*
* Start the watchdog.
*/
icp_watchdog(icp);
return (0);
bail_out:
if (state > 4)
for (j = 0; j < i; j++)
bus_dmamap_destroy(icp->icp_dmat,
icp->icp_ccbs[j].ic_xfer_map);
if (state > 3)
free(icp->icp_ccbs, M_DEVBUF);
if (state > 2)
bus_dmamap_unload(icp->icp_dmat, icp->icp_scr_dmamap);
if (state > 1)
bus_dmamem_unmap(icp->icp_dmat, icp->icp_scr,
ICP_SCRATCH_SIZE);
if (state > 0)
bus_dmamem_free(icp->icp_dmat, icp->icp_scr_seg, nsegs);
bus_dmamap_destroy(icp->icp_dmat, icp->icp_scr_dmamap);
return (1);
}
void
icp_watchdog(void *cookie)
{
struct icp_softc *icp;
int s;
icp = cookie;
s = splbio();
icp_intr(icp);
if (SIMPLEQ_FIRST(&icp->icp_ccb_queue) != NULL)
icp_ccb_enqueue(icp, NULL);
splx(s);
callout_reset(&icp->icp_wdog_callout, hz * ICP_WATCHDOG_FREQ,
icp_watchdog, icp);
}
int
icp_print(void *aux, const char *pnp)
{
struct icp_attach_args *icpa;
const char *str;
icpa = (struct icp_attach_args *)aux;
if (pnp != NULL) {
if (icpa->icpa_unit < ICPA_UNIT_SCSI)
str = "block device";
else
str = "SCSI channel";
printf("%s at %s", str, pnp);
}
printf(" unit %d", icpa->icpa_unit);
return (UNCONF);
}
int
icp_submatch(struct device *parent, struct cfdata *cf, void *aux)
{
struct icp_attach_args *icpa;
icpa = (struct icp_attach_args *)aux;
if (cf->icpacf_unit != ICPCF_UNIT_DEFAULT &&
cf->icpacf_unit != icpa->icpa_unit)
return (0);
return ((*cf->cf_attach->ca_match)(parent, cf, aux));
}
int
icp_async_event(struct icp_softc *icp, int val)
{
/* XXX */
return (1);
}
int
icp_intr(void *cookie)
{
struct icp_softc *icp;
struct icp_intr_ctx ctx;
struct icp_ccb *ic;
icp = cookie;
ctx.istatus = (*icp->icp_get_status)(icp);
if (!ctx.istatus) {
icp->icp_status = ICP_S_NO_STATUS;
return (0);
}
(*icp->icp_intr)(icp, &ctx);
icp->icp_status = ctx.cmd_status;
icp->icp_info = ctx.info;
icp->icp_info2 = ctx.info2;
switch (ctx.istatus) {
case ICP_ASYNCINDEX:
icp_async_event(icp, ctx.service);
return (1);
case ICP_SPEZINDEX:
printf("%s: uninitialized or unknown service (%d/%d)\n",
icp->icp_dv.dv_xname, ctx.info, ctx.info2);
return (1);
}
if ((ctx.istatus - 2) > icp->icp_nccbs)
panic("icp_intr: bad command index returned");
ic = &icp->icp_ccbs[ctx.istatus - 2];
ic->ic_status = icp->icp_status;
if ((ic->ic_flags & IC_ALLOCED) == 0)
panic("icp_intr: inactive CCB identified");
switch (icp->icp_status) {
case ICP_S_BSY:
#ifdef ICP_DEBUG
printf("%s: ICP_S_BSY received\n", icp->icp_dv.dv_xname);
#endif
SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_queue, ic, ic_chain);
break;
default:
ic->ic_flags |= IC_COMPLETE;
if ((ic->ic_flags & IC_WAITING) != 0)
wakeup(ic);
else if (ic->ic_intr != NULL)
(*ic->ic_intr)(ic);
if (SIMPLEQ_FIRST(&icp->icp_ccb_queue) != NULL)
icp_ccb_enqueue(icp, NULL);
break;
}
return (1);
}
int
icp_cmd(struct icp_softc *icp, u_int8_t service, u_int16_t opcode,
u_int32_t arg1, u_int32_t arg2, u_int32_t arg3)
{
struct icp_ioctlcmd *icmd;
struct icp_cachecmd *cc;
struct icp_rawcmd *rc;
int retries, rv;
struct icp_ccb *ic;
retries = ICP_RETRIES;
do {
ic = icp_ccb_alloc(icp);
memset(&ic->ic_cmd, 0, sizeof(ic->ic_cmd));
ic->ic_cmd.cmd_opcode = htole16(opcode);
switch (service) {
case ICP_CACHESERVICE:
if (opcode == ICP_IOCTL) {
icmd = &ic->ic_cmd.cmd_packet.ic;
icmd->ic_subfunc = htole16(arg1);
icmd->ic_channel = htole32(arg2);
icmd->ic_bufsize = htole32(arg3);
icmd->ic_addr =
htole32(icp->icp_scr_seg[0].ds_addr);
bus_dmamap_sync(icp->icp_dmat,
icp->icp_scr_dmamap, 0, arg3,
BUS_DMASYNC_PREWRITE |
BUS_DMASYNC_PREREAD);
} else {
cc = &ic->ic_cmd.cmd_packet.cc;
cc->cc_deviceno = htole16(arg1);
cc->cc_blockno = htole32(arg2);
}
break;
case ICP_SCSIRAWSERVICE:
rc = &ic->ic_cmd.cmd_packet.rc;
rc->rc_direction = htole32(arg1);
rc->rc_bus = arg2;
rc->rc_target = arg3;
rc->rc_lun = arg3 >> 8;
break;
}
ic->ic_service = service;
ic->ic_cmdlen = sizeof(ic->ic_cmd);
rv = icp_ccb_poll(icp, ic, 10000);
switch (service) {
case ICP_CACHESERVICE:
if (opcode == ICP_IOCTL) {
bus_dmamap_sync(icp->icp_dmat,
icp->icp_scr_dmamap, 0, arg3,
BUS_DMASYNC_POSTWRITE |
BUS_DMASYNC_POSTREAD);
}
break;
}
icp_ccb_free(icp, ic);
} while (rv != 0 && --retries > 0);
return (icp->icp_status == ICP_S_OK);
}
struct icp_ccb *
icp_ccb_alloc(struct icp_softc *icp)
{
struct icp_ccb *ic;
int s;
s = splbio();
ic = SIMPLEQ_FIRST(&icp->icp_ccb_freelist);
SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_freelist, ic, ic_chain);
splx(s);
ic->ic_flags = IC_ALLOCED;
return (ic);
}
void
icp_ccb_free(struct icp_softc *icp, struct icp_ccb *ic)
{
int s;
s = splbio();
ic->ic_flags = 0;
ic->ic_intr = NULL;
SIMPLEQ_INSERT_HEAD(&icp->icp_ccb_freelist, ic, ic_chain);
splx(s);
}
void
icp_ccb_enqueue(struct icp_softc *icp, struct icp_ccb *ic)
{
int s;
s = splbio();
if (ic != NULL)
SIMPLEQ_INSERT_TAIL(&icp->icp_ccb_queue, ic, ic_chain);
while ((ic = SIMPLEQ_FIRST(&icp->icp_ccb_queue)) != NULL) {
if ((*icp->icp_test_busy)(icp))
break;
icp_ccb_submit(icp, ic);
SIMPLEQ_REMOVE_HEAD(&icp->icp_ccb_queue, ic, ic_chain);
}
splx(s);
}
int
icp_ccb_map(struct icp_softc *icp, struct icp_ccb *ic, void *data, int size,
int dir)
{
struct icp_sg *sg;
int nsegs, i, rv;
bus_dmamap_t xfer;
xfer = ic->ic_xfer_map;
rv = bus_dmamap_load(icp->icp_dmat, xfer, data, size, NULL,
BUS_DMA_NOWAIT | BUS_DMA_STREAMING |
((dir & IC_XFER_IN) ? BUS_DMA_READ : BUS_DMA_WRITE));
if (rv != 0)
return (rv);
nsegs = xfer->dm_nsegs;
ic->ic_xfer_size = size;
ic->ic_nsgent = nsegs;
ic->ic_flags |= dir;
sg = ic->ic_sg;
if (sg != NULL) {
for (i = 0; i < nsegs; i++, sg++) {
sg->sg_addr = htole32(xfer->dm_segs[i].ds_addr);
sg->sg_len = htole32(xfer->dm_segs[i].ds_len);
}
} else if (nsegs > 1)
panic("icp_ccb_map: no SG list specified, but nsegs > 1\n");
if ((dir & IC_XFER_OUT) != 0)
i = BUS_DMASYNC_PREWRITE;
else /* if ((dir & IC_XFER_IN) != 0) */
i = BUS_DMASYNC_PREREAD;
bus_dmamap_sync(icp->icp_dmat, xfer, 0, ic->ic_xfer_size, i);
return (0);
}
void
icp_ccb_unmap(struct icp_softc *icp, struct icp_ccb *ic)
{
int i;
if ((ic->ic_flags & IC_XFER_OUT) != 0)
i = BUS_DMASYNC_POSTWRITE;
else /* if ((ic->ic_flags & IC_XFER_IN) != 0) */
i = BUS_DMASYNC_POSTREAD;
bus_dmamap_sync(icp->icp_dmat, ic->ic_xfer_map, 0, ic->ic_xfer_size, i);
bus_dmamap_unload(icp->icp_dmat, ic->ic_xfer_map);
}
int
icp_ccb_poll(struct icp_softc *icp, struct icp_ccb *ic, int timo)
{
int rv;
for (timo = ICP_BUSY_WAIT_MS * 100; timo != 0; timo--) {
if (!(*icp->icp_test_busy)(icp))
break;
DELAY(10);
}
if (timo == 0) {
printf("%s: submit: busy\n", icp->icp_dv.dv_xname);
return (EAGAIN);
}
icp_ccb_submit(icp, ic);
for (timo *= 10; timo != 0; timo--) {
DELAY(100);
icp_intr(icp);
if ((ic->ic_flags & IC_COMPLETE) != 0)
break;
}
if (timo != 0) {
if (ic->ic_status != ICP_S_OK) {
#ifdef ICP_DEBUG
printf("%s: request failed; status=0x%04x\n",
icp->icp_dv.dv_xname, ic->ic_status);
#endif
rv = EIO;
} else
rv = 0;
} else {
printf("%s: command timed out\n", icp->icp_dv.dv_xname);
rv = EIO;
}
while ((*icp->icp_test_busy)(icp) != 0)
DELAY(10);
return (rv);
}
int
icp_ccb_wait(struct icp_softc *icp, struct icp_ccb *ic, int timo)
{
int s, rv;
ic->ic_flags |= IC_WAITING;
s = splbio();
icp_ccb_enqueue(icp, ic);
if ((rv = tsleep(ic, PRIBIO, "icpwccb", mstohz(timo))) != 0) {
splx(s);
return (rv);
}
splx(s);
if (ic->ic_status != ICP_S_OK) {
printf("%s: command failed; status=%x\n", icp->icp_dv.dv_xname,
ic->ic_status);
return (EIO);
}
return (0);
}
void
icp_ccb_submit(struct icp_softc *icp, struct icp_ccb *ic)
{
ic->ic_cmdlen = (ic->ic_cmdlen + 3) & ~3;
(*icp->icp_set_sema0)(icp);
DELAY(10);
ic->ic_cmd.cmd_boardnode = htole32(ICP_LOCALBOARD);
ic->ic_cmd.cmd_cmdindex = htole32(ic->ic_ident);
(*icp->icp_copy_cmd)(icp, ic);
(*icp->icp_release_event)(icp, ic);
}

371
sys/dev/ic/icpreg.h Normal file
View File

@ -0,0 +1,371 @@
/* $NetBSD: icpreg.h,v 1.1 2002/04/22 21:05:21 ad Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niklas Hallqvist.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
* from OpenBSD: gdtreg.h,v 1.1 2000/02/07 00:33:03 niklas Exp
*/
#ifndef _IC_ICPREG_H_
#define _IC_ICPREG_H_
#define ICP_MAXBUS 6 /* XXX Why not 5? */
#define ICP_MAX_HDRIVES 35 /* 5 busses * 7 targets XXX correct? */
#define ICP_MAXID_FC 127 /* Fibre-channel maximum ID */
#define ICP_MAXOFFSETS 128
#define ICP_MAXSG 17 /* Max. s/g elements; actually 128 */
#define ICP_PROTOCOL_VERSION 1
#define ICP_LINUX_OS 8 /* Used for cache optimization */
#define ICP_SCATTER_GATHER 1 /* s/g feature */
#define ICP_SECS32 0x1f /* round capacity */
#define ICP_LOCALBOARD 0 /* Board node always 0 */
#define ICP_MAX_CMDS 124
#define ICP_SECTOR_SIZE 0x200 /* Always 512 bytes for cache devs */
/* DPMEM constants */
#define ICP_MPR_MAGIC 0xc0ffee11
#define ICP_IC_HEADER_BYTES 48
#define ICP_IC_QUEUE_BYTES 4
/* Cache/raw service commands */
#define ICP_INIT 0 /* service initialization */
#define ICP_READ 1 /* read command */
#define ICP_WRITE 2 /* write command */
#define ICP_INFO 3 /* information about devices */
#define ICP_FLUSH 4 /* flush dirty cache buffers */
#define ICP_IOCTL 5 /* ioctl command */
#define ICP_DEVTYPE 9 /* additional information */
#define ICP_MOUNT 10 /* mount cache device */
#define ICP_UNMOUNT 11 /* unmount cache device */
#define ICP_SET_FEAT 12 /* set features (scatter/gather) */
#define ICP_GET_FEAT 13 /* get features */
#define ICP_WRITE_THR 16 /* write through */
#define ICP_READ_THR 17 /* read through */
#define ICP_EXT_INFO 18 /* extended info */
#define ICP_RESET 19 /* controller reset */
#define ICP_FREEZE_IO 25 /* freeze all IOs */
#define ICP_UNFREEZE_IO 26 /* unfreeze all IOs */
/* Additional raw service commands */
#define ICP_RESERVE 14 /* reserve device to raw service */
#define ICP_RELEASE 15 /* release device */
#define ICP_RESERVE_ALL 16 /* reserve all devices */
#define ICP_RELEASE_ALL 17 /* release all devices */
#define ICP_RESET_BUS 18 /* reset bus */
#define ICP_SCAN_START 19 /* start device scan */
#define ICP_SCAN_END 20 /* stop device scan */
/* IOCTL command defines */
#define ICP_SCSI_DR_INFO 0x00 /* SCSI drive info */
#define ICP_SCSI_CHAN_CNT 0x05 /* SCSI channel count */
#define ICP_SCSI_DR_LIST 0x06 /* SCSI drive list */
#define ICP_SCSI_DEF_CNT 0x15 /* grown/primary defects */
#define ICP_DSK_STATISTICS 0x4b /* SCSI disk statistics */
#define ICP_IOCHAN_DESC 0x5d /* description of IO channel */
#define ICP_IOCHAN_RAW_DESC 0x5e /* description of raw IO channel */
#define ICP_L_CTRL_PATTERN 0x20000000 /* SCSI IOCTL mask */
#define ICP_ARRAY_INFO 0x12 /* array drive info */
#define ICP_ARRAY_DRV_LIST 0x0f /* array drive list */
#define ICP_LA_CTRL_PATTERN 0x10000000 /* array IOCTL mask */
#define ICP_CACHE_DRV_CNT 0x01 /* cache drive count */
#define ICP_CACHE_DRV_LIST 0x02 /* cache drive list */
#define ICP_CACHE_INFO 0x04 /* cache info */
#define ICP_CACHE_CONFIG 0x05 /* cache configuration */
#define ICP_CACHE_DRV_INFO 0x07 /* cache drive info */
#define ICP_BOARD_FEATURES 0x15 /* controller features */
#define ICP_BOARD_INFO 0x28 /* controller info */
#define ICP_HOST_GET 0x10001 /* get host drive list */
#define ICP_IO_CHANNEL 0x20000 /* default IO channel */
#define ICP_INVALID_CHANNEL 0xffff /* invalid channel */
/* IOCTLs */
#define ICPIOCTL_MASK ('J' << 8)
#define ICPIOCTL_GENERAL (ICPIOCTL_MASK | 0) /* general IOCTL */
#define ICPIOCTL_DRVERS (ICPIOCTL_MASK | 1) /* get driver version */
#define ICPIOCTL_CTRTYPE (ICPIOCTL_MASK | 2) /* get controller type */
#define ICPIOCTL_CTRCNT (ICPIOCTL_MASK | 5) /* get controller count */
#define ICPIOCTL_LOCKDRV (ICPIOCTL_MASK | 6) /* lock host drive */
#define ICPIOCTL_LOCKCHN (ICPIOCTL_MASK | 7) /* lock channel */
#define ICPIOCTL_EVENT (ICPIOCTL_MASK | 8) /* read controller events */
/* Service errors */
#define ICP_S_OK 1 /* no error */
#define ICP_S_BSY 7 /* controller busy */
#define ICP_S_RAW_SCSI 12 /* raw service: target error */
#define ICP_S_RAW_ILL 0xff /* raw service: illegal */
#define ICP_S_NO_STATUS 0x1000 /* got no status (driver-generated) */
/* Controller services */
#define ICP_SCSIRAWSERVICE 3
#define ICP_CACHESERVICE 9
#define ICP_SCREENSERVICE 11
/* Data direction raw service. */
#define ICP_DATA_IN 0x01000000
#define ICP_DATA_OUT 0x00000000
/* Command queue entries */
#define ICP_OFFSET 0x00 /* u_int16_t, command offset in the DP RAM */
#define ICP_SERV_ID 0x02 /* u_int16_t, service */
#define ICP_COMM_Q_SZ 0x04
/* Interface area */
#define ICP_S_CMD_INDX 0x00 /* u_int8_t, special command */
#define ICP_S_STATUS 0x01 /* volatile u_int8_t, status special command */
#define ICP_S_INFO 0x04 /* u_int32_t [4], add. info special command */
#define ICP_SEMA0 0x14 /* volatile u_int8_t, command semaphore */
#define ICP_CMD_INDEX 0x18 /* u_int8_t, command number */
#define ICP_STATUS 0x1c /* volatile u_int16_t, command status */
#define ICP_SERVICE 0x1e /* u_int16_t, service (for asynch. events) */
#define ICP_DPR_INFO 0x20 /* u_int32_t [2], additional info */
#define ICP_COMM_QUEUE 0x28 /* command queue */
#define ICP_DPR_CMD (0x30 + ICP_MAXOFFSETS * ICP_COMM_Q_SZ)
/* u_int8_t [], commands */
#define ICP_DPR_IF_SZ ICP_DPR_CMD
/* Get cache info */
#define ICP_CINFO_CPAR 0x00
#define ICP_CINFO_CSTAT 0x0c
/* Other defines */
#define ICP_ASYNCINDEX 0 /* command index asynchronous event */
#define ICP_SPEZINDEX 1 /* command index unknown service */
/* I/O channel header */
struct icp_ioc_version {
u_int32_t iv_version; /* version (~0: newest) */
u_int8_t iv_listents; /* list entry count */
u_int8_t iv_firstchan; /* first channel number */
u_int8_t iv_lastchan; /* last channel number */
u_int8_t iv_chancount; /* channel count */
u_int32_t iv_listoffset; /* offset of list[0] */
} __attribute__ ((__packed__));
#define ICP_IOC_NEWEST 0xffffffff
/* Get I/O channel description */
struct icp_ioc {
u_int32_t io_addr; /* channel address */
u_int8_t io_type; /* type (SCSI/FCAL) */
u_int8_t io_localno; /* local number */
u_int16_t io_features; /* channel features */
} __attribute__ ((__packed__));
/* Get raw I/O channel description */
struct icp_rawioc {
u_int8_t ri_procid; /* processor ID */
u_int8_t ri_defect; /* defect? */
u_int16_t ri_padding;
} __attribute__ ((__packed__));
/* Get SCSI channel count */
struct icp_getch {
u_int32_t gc_channo; /* channel number */
u_int32_t gc_drivecnt; /* drive count */
u_int8_t gc_scsiid; /* SCSI initiator ID */
u_int8_t gc_scsistate; /* SCSI processor state */
} __attribute__ ((__packed__));
/* Cache info/config IOCTL structures */
struct icp_cpar {
u_int32_t cp_version; /* firmware version */
u_int16_t cp_state; /* cache state (on/off) */
u_int16_t cp_strategy; /* cache strategy */
u_int16_t cp_write_back; /* write back (on/off) */
u_int16_t cp_block_size; /* cache block size */
} __attribute__ ((__packed__));
struct icp_cstat {
u_int32_t cs_size; /* cache size */
u_int32_t cs_readcnt; /* read counter */
u_int32_t cs_writecnt; /* write counter */
u_int32_t cs_trhits; /* track hits */
u_int32_t cs_sechits; /* sector hits */
u_int32_t cs_secmiss; /* sector misses */
} __attribute__ ((__packed__));
/* Board information. */
struct icp_binfo {
u_int32_t bi_ser_no; /* serial number */
u_int8_t bi_oem_id[2]; /* OEM ID */
u_int16_t bi_ep_flags; /* eprom flags */
u_int32_t bi_proc_id; /* processor ID */
u_int32_t bi_memsize; /* memory size (bytes) */
u_int8_t bi_mem_banks; /* memory banks */
u_int8_t bi_chan_type; /* channel type */
u_int8_t bi_chan_count; /* channel count */
u_int8_t bi_rdongle_pres; /* dongle present */
u_int32_t bi_epr_fw_ver; /* (eprom) firmware ver */
u_int32_t bi_upd_fw_ver; /* (update) firmware ver */
u_int32_t bi_upd_revision; /* update revision */
char bi_type_string[16]; /* char controller name */
char bi_raid_string[16]; /* char RAID firmware name */
u_int8_t bi_update_pres; /* update present? */
u_int8_t bi_xor_pres; /* XOR engine present */
u_int8_t bi_prom_type; /* ROM type (eprom/flash) */
u_int8_t bi_prom_count; /* number of ROM devices */
u_int32_t bi_dup_pres; /* duplexing module pres? */
u_int32_t bi_chan_pres; /* # of exp. channels */
u_int32_t bi_mem_pres; /* memory expansion inst? */
u_int8_t bi_ft_bus_system; /* fault bus supported? */
u_int8_t bi_subtype_valid; /* board_subtype valid */
u_int8_t bi_board_subtype; /* subtype/hardware level */
u_int8_t bi_rampar_pres; /* RAM parity check hw? */
} __attribute__ ((__packed__));
/* Board features. */
struct icp_bfeat {
u_int8_t bf_chaining; /* chaining supported */
u_int8_t bf_striping; /* striping (RAID-0) supported */
u_int8_t bf_mirroring; /* mirroring (RAID-1) supported */
u_int8_t bf_raid; /* RAID-4/5/10 supported */
} __attribute__ ((__packed__));
/* Cache drive information. */
struct icp_cdevinfo {
char cd_name[8];
u_int32_t cd_devtype;
u_int32_t cd_ldcnt;
u_int32_t cd_last_error;
u_int8_t cd_initialized;
u_int8_t cd_removable;
u_int8_t cd_write_protected;
u_int8_t cd_flags;
u_int32_t ld_blkcnt;
u_int32_t ld_blksize;
u_int32_t ld_dcnt;
u_int32_t ld_slave;
u_int32_t ld_dtype;
u_int32_t ld_last_error;
char ld_name[8];
u_int8_t ld_error;
} __attribute__ ((__packed__));
struct icp_sg {
u_int32_t sg_addr;
u_int32_t sg_len;
} __attribute__ ((__packed__));
struct icp_cachecmd {
u_int16_t cc_deviceno;
u_int32_t cc_blockno;
u_int32_t cc_blockcnt;
u_int32_t cc_addr; /* ~0 == s/g */
u_int32_t cc_nsgent;
struct icp_sg cc_sg[ICP_MAXSG];
} __attribute__ ((__packed__));
struct icp_ioctlcmd {
u_int16_t ic_bufsize;
u_int32_t ic_subfunc;
u_int32_t ic_channel;
u_int32_t ic_addr;
} __attribute__ ((__packed__));
struct icp_screencmd {
u_int32_t sc_msghandle;
u_int32_t sc_msgaddr;
} __attribute__ ((__packed__));
struct icp_rawcmd {
u_int16_t rc_padding0; /* unused */
u_int32_t rc_direction; /* data direction */
u_int32_t rc_mdisc_time; /* disc. time (0: none) */
u_int32_t rc_mcon_time; /* conn. time (0: none) */
u_int32_t rc_sdata; /* dest address */
u_int32_t rc_sdlen; /* data length */
u_int32_t rc_clen; /* CDB length */
u_int8_t rc_cdb[12]; /* SCSI CDB */
u_int8_t rc_target; /* target ID */
u_int8_t rc_lun; /* LUN */
u_int8_t rc_bus; /* channel */
u_int8_t rc_priority; /* priority; 0 only */
u_int32_t rc_sense_len; /* sense length */
u_int32_t rc_sense_addr; /* sense address */
u_int32_t rc_padding1; /* unused */
u_int32_t rc_nsgent; /* s/g element count */
struct icp_sg rc_sg[ICP_MAXSG]; /* s/g list */
} __attribute__ ((__packed__));
struct icp_cmdhdr {
u_int32_t cmd_boardnode; /* always 0 */
u_int32_t cmd_cmdindex; /* command identifier */
u_int16_t cmd_opcode;
} __attribute__ ((__packed__));
struct icp_cmd {
u_int32_t cmd_boardnode; /* always 0 */
u_int32_t cmd_cmdindex; /* command identifier */
u_int16_t cmd_opcode;
union {
struct icp_rawcmd rc;
struct icp_screencmd sc;
struct icp_ioctlcmd ic;
struct icp_cachecmd cc;
} cmd_packet;
} __attribute__ ((__packed__));
#endif /* !_IC_ICPREG_H_ */

318
sys/dev/ic/icpsp.c Normal file
View File

@ -0,0 +1,318 @@
/* $NetBSD: icpsp.c,v 1.1 2002/04/22 21:05:21 ad Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icpsp.c,v 1.1 2002/04/22 21:05:21 ad Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/queue.h>
#include <sys/proc.h>
#include <sys/buf.h>
#include <sys/endian.h>
#include <sys/malloc.h>
#include <sys/scsiio.h>
#include <sys/lock.h>
#include <machine/bswap.h>
#include <machine/bus.h>
#include <uvm/uvm_extern.h>
#include <dev/scsipi/scsi_all.h>
#include <dev/scsipi/scsi_disk.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsiconf.h>
#include <dev/scsipi/scsi_message.h>
#include <dev/ic/icpreg.h>
#include <dev/ic/icpvar.h>
struct icpsp_softc {
struct device sc_dv;
struct scsipi_adapter sc_adapter;
struct scsipi_channel sc_channel;
int sc_busno;
};
void icpsp_attach(struct device *, struct device *, void *);
void icpsp_intr(struct icp_ccb *);
int icpsp_match(struct device *, struct cfdata *, void *);
void icpsp_scsipi_request(struct scsipi_channel *, scsipi_adapter_req_t,
void *);
struct cfattach icpsp_ca = {
sizeof(struct icpsp_softc), icpsp_match, icpsp_attach
};
int
icpsp_match(struct device *parent, struct cfdata *match, void *aux)
{
struct icp_attach_args *icpa;
icpa = aux;
return (icpa->icpa_unit >= ICPA_UNIT_SCSI);
}
void
icpsp_attach(struct device *parent, struct device *self, void *aux)
{
struct icp_attach_args *icpa;
struct icpsp_softc *sc;
struct icp_softc *icp;
icpa = (struct icp_attach_args *)aux;
sc = (struct icpsp_softc *)self;
icp = (struct icp_softc *)parent;
sc->sc_busno = icpa->icpa_unit - ICPA_UNIT_SCSI;
printf(": physical SCSI channel %d\n", sc->sc_busno);
sc->sc_adapter.adapt_dev = &sc->sc_dv;
sc->sc_adapter.adapt_nchannels = 1;
sc->sc_adapter.adapt_openings = icp->icp_openings;
sc->sc_adapter.adapt_max_periph = icp->icp_openings;
sc->sc_adapter.adapt_minphys = minphys;
sc->sc_adapter.adapt_request = icpsp_scsipi_request;
sc->sc_channel.chan_adapter = &sc->sc_adapter;
sc->sc_channel.chan_bustype = &scsi_bustype;
sc->sc_channel.chan_channel = 0;
sc->sc_channel.chan_ntargets = ((icp->icp_class & ICP_FC) != 0 ?
127 : 16); /* XXX bogus check */
sc->sc_channel.chan_nluns = 7;
sc->sc_channel.chan_id = icp->icp_bus_id[sc->sc_busno];
sc->sc_channel.chan_flags = SCSIPI_CHAN_NOSETTLE;
config_found(self, &sc->sc_channel, scsiprint);
}
void
icpsp_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
void *arg)
{
struct scsipi_xfer *xs;
struct scsipi_periph *periph;
struct icpsp_softc *sc;
struct icp_rawcmd *rc;
struct icp_softc *icp;
struct icp_ccb *ic;
int rv, flags, s, soff;
sc = (void *)chan->chan_adapter->adapt_dev;
icp = (struct icp_softc *)sc->sc_dv.dv_parent;
switch (req) {
case ADAPTER_REQ_RUN_XFER:
xs = arg;
periph = xs->xs_periph;
flags = xs->xs_control;
SC_DEBUG(periph, SCSIPI_DB2, ("icpsp_scsi_request run_xfer\n"));
if ((flags & XS_CTL_RESET) != 0) {
/* XXX Unimplemented. */
xs->error = XS_DRIVER_STUFFUP;
scsipi_done(xs);
return;
}
#if defined(ICP_DEBUG) || defined(SCSIDEBUG)
if (xs->cmdlen > sizeof(rc->rc_cdb))
panic("%s: CDB too large\n", sc->sc_dv.dv_xname);
#endif
/*
* Allocate a CCB.
*/
ic = icp_ccb_alloc(icp);
rc = &ic->ic_cmd.cmd_packet.rc;
ic->ic_sg = rc->rc_sg;
ic->ic_service = ICP_SCSIRAWSERVICE;
soff = ICP_SCRATCH_SENSE + ic->ic_ident *
sizeof(struct scsipi_sense_data);
/*
* Build the command. We don't need to actively prevent
* access to array components, since the controller kindly
* takes care of that for us.
*/
ic->ic_cmd.cmd_opcode = htole16(ICP_WRITE);
memcpy(rc->rc_cdb, xs->cmd, xs->cmdlen);
rc->rc_padding0 = 0;
rc->rc_direction = htole32((flags & XS_CTL_DATA_IN) != 0 ?
ICP_DATA_IN : ICP_DATA_OUT);
rc->rc_mdisc_time = 0;
rc->rc_mcon_time = 0;
rc->rc_clen = htole32(xs->cmdlen);
rc->rc_target = periph->periph_target;
rc->rc_lun = periph->periph_lun;
rc->rc_bus = sc->sc_busno;
rc->rc_priority = 0;
rc->rc_sense_len = htole32(sizeof(xs->sense.scsi_sense));
rc->rc_sense_addr =
htole32(soff + icp->icp_scr_seg[0].ds_addr);
rc->rc_padding1 = 0;
if (xs->datalen != 0) {
rv = icp_ccb_map(icp, ic, xs->data, xs->datalen,
(flags & XS_CTL_DATA_IN) != 0 ? IC_XFER_IN :
IC_XFER_OUT);
if (rv != 0) {
icp_ccb_free(icp, ic);
xs->error = XS_DRIVER_STUFFUP;
scsipi_done(xs);
return;
}
rc->rc_nsgent = htole32(ic->ic_nsgent);
rc->rc_sdata = ~0;
rc->rc_sdlen = htole32(xs->datalen);
} else {
rc->rc_nsgent = 0;
rc->rc_sdata = 0;
rc->rc_sdlen = 0;
}
ic->ic_cmdlen = (u_long)ic->ic_sg - (u_long)&ic->ic_cmd +
ic->ic_nsgent * sizeof(*ic->ic_sg);
bus_dmamap_sync(icp->icp_dmat, icp->icp_scr_dmamap, soff,
sizeof(xs->sense.scsi_sense), BUS_DMASYNC_PREREAD);
/*
* Fire it off to the controller.
*/
ic->ic_intr = icpsp_intr;
ic->ic_context = xs;
ic->ic_dv = &sc->sc_dv;
if ((flags & XS_CTL_POLL) != 0) {
s = splbio();
rv = icp_ccb_poll(icp, ic, xs->timeout);
if (rv != 0) {
if (xs->datalen != 0)
icp_ccb_unmap(icp, ic);
icp_ccb_free(icp, ic);
xs->error = XS_TIMEOUT;
scsipi_done(xs);
/*
* XXX We're now in a bad way, because we
* don't know how to abort the command.
* That shouldn't matter too much, since
* polled commands won't be used while the
* system is running.
*/
}
splx(s);
} else
icp_ccb_enqueue(icp, ic);
break;
case ADAPTER_REQ_GROW_RESOURCES:
case ADAPTER_REQ_SET_XFER_MODE:
/*
* Neither of these cases are supported, and neither of them
* is particulatly relevant, since we have an abstract view
* of the bus; the controller takes care of all the nitty
* gritty.
*/
break;
}
}
void
icpsp_intr(struct icp_ccb *ic)
{
struct scsipi_xfer *xs;
struct icpsp_softc *sc;
struct icp_softc *icp;
int soff;
sc = (struct icpsp_softc *)ic->ic_dv;
xs = (struct scsipi_xfer *)ic->ic_context;
icp = (struct icp_softc *)ic->ic_dv->dv_parent;
soff = ICP_SCRATCH_SENSE + ic->ic_ident *
sizeof(struct scsipi_sense_data);
SC_DEBUG(xs->xs_periph, SCSIPI_DB2, ("icpsp_intr\n"));
bus_dmamap_sync(icp->icp_dmat, icp->icp_scr_dmamap, soff,
sizeof(xs->sense.scsi_sense), BUS_DMASYNC_POSTREAD);
if (ic->ic_status == ICP_S_OK) {
xs->status = SCSI_OK;
xs->resid = 0;
} else if (ic->ic_status != ICP_S_RAW_SCSI || icp->icp_info >= 0x100) {
xs->error = XS_SELTIMEOUT;
xs->resid = xs->datalen;
} else {
xs->status = icp->icp_info;
switch (xs->status) {
case SCSI_OK:
#ifdef DIAGNOSTIC
printf("%s: error return (%d), but SCSI_OK?\n",
sc->sc_dv.dv_xname, icp->icp_info);
#endif
xs->resid = 0;
break;
case SCSI_CHECK:
memcpy(&xs->sense.scsi_sense, icp->icp_scr + soff,
sizeof(xs->sense.scsi_sense));
/* FALLTHROUGH */
default:
/*
* XXX Don't know how to get residual count.
*/
xs->resid = xs->datalen;
break;
}
}
if (xs->datalen != 0)
icp_ccb_unmap(icp, ic);
icp_ccb_free(icp, ic);
scsipi_done(xs);
}

180
sys/dev/ic/icpvar.h Normal file
View File

@ -0,0 +1,180 @@
/* $NetBSD: icpvar.h,v 1.1 2002/04/22 21:05:21 ad Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
#ifndef _IC_ICPVAR_H_
#define _IC_ICPVAR_H_
#include "locators.h"
/*
* Miscellaneous constants.
*/
#define ICP_RETRIES 6
#define ICP_WATCHDOG_FREQ 5
#define ICP_BUSY_WAIT_MS 2500
#define ICP_MAX_XFER 65536
#define ICP_SCRATCH_SIZE 8192
#define ICP_SCRATCH_SENSE \
(ICP_SCRATCH_SIZE - sizeof(struct scsipi_sense_data) * ICP_NCCBS)
#define ICP_NCCBS ICP_MAX_CMDS
#define ICP_NCCB_RESERVE 4
/*
* Context structure for interrupt service.
*/
struct icp_intr_ctx {
u_int32_t info;
u_int32_t info2;
u_int16_t cmd_status;
u_int16_t service;
u_int8_t istatus;
};
/*
* Command control block.
*/
struct icp_ccb {
SIMPLEQ_ENTRY(icp_ccb) ic_chain;
u_int ic_service;
u_int ic_flags;
u_int ic_status;
u_int ic_ident;
u_int ic_nsgent;
u_int ic_cmdlen;
u_int ic_xfer_size;
bus_dmamap_t ic_xfer_map;
struct icp_sg *ic_sg;
struct device *ic_dv;
void *ic_context;
void (*ic_intr)(struct icp_ccb *);
struct icp_cmd ic_cmd;
};
#define IC_XFER_IN 0x01 /* Map describes inbound xfer */
#define IC_XFER_OUT 0x02 /* Map describes outbound xfer */
#define IC_WAITING 0x04 /* We have waiters */
#define IC_COMPLETE 0x08 /* Command completed */
#define IC_ALLOCED 0x10 /* CCB allocated */
/*
* Logical drive information.
*/
struct icp_cachedrv {
u_int cd_size;
u_int cd_type;
};
/*
* Per-controller context.
*/
struct icp_softc {
struct device icp_dv;
void *icp_ih;
bus_dma_tag_t icp_dmat;
bus_space_tag_t icp_dpmemt;
bus_space_handle_t icp_dpmemh;
bus_addr_t icp_dpmembase;
bus_space_tag_t icp_iot;
bus_space_handle_t icp_ioh;
bus_addr_t icp_iobase;
int icp_class;
u_int16_t icp_ic_all_size;
u_int8_t icp_bus_cnt;
u_int8_t icp_bus_id[ICP_MAXBUS];
struct icp_cachedrv icp_cdr[ICP_MAX_HDRIVES];
int icp_ndevs;
int icp_openings;
u_int32_t icp_info;
u_int32_t icp_info2;
u_int16_t icp_status;
bus_dmamap_t icp_scr_dmamap;
bus_dma_segment_t icp_scr_seg[1];
caddr_t icp_scr;
struct icp_ccb *icp_ccbs;
u_int icp_nccbs;
SIMPLEQ_HEAD(,icp_ccb) icp_ccb_freelist;
SIMPLEQ_HEAD(,icp_ccb) icp_ccb_queue;
struct callout icp_wdog_callout;
void (*icp_copy_cmd)(struct icp_softc *, struct icp_ccb *);
u_int8_t (*icp_get_status)(struct icp_softc *);
void (*icp_intr)(struct icp_softc *, struct icp_intr_ctx *);
void (*icp_release_event)(struct icp_softc *,
struct icp_ccb *);
void (*icp_set_sema0)(struct icp_softc *);
int (*icp_test_busy)(struct icp_softc *);
};
#define ICP_ISA 0x01
#define ICP_EISA 0x02
#define ICP_PCI 0x03
#define ICP_PCINEW 0x04
#define ICP_MPR 0x05
#define ICP_CLASS_MASK 0x07
#define ICP_FC 0x10
#define ICP_CLASS(icp) ((icp)->icp_class & ICP_CLASS_MASK)
int icp_init(struct icp_softc *, const char *);
int icp_intr(void *);
/*
* Consumer interface.
*/
struct icp_attach_args {
int icpa_unit;
};
#define icpacf_unit cf_loc[ICPCF_UNIT]
#define ICPA_UNIT_SCSI 100
struct icp_ccb *icp_ccb_alloc(struct icp_softc *);
void icp_ccb_enqueue(struct icp_softc *, struct icp_ccb *);
void icp_ccb_free(struct icp_softc *, struct icp_ccb *);
int icp_ccb_map(struct icp_softc *, struct icp_ccb *, void *, int, int);
int icp_ccb_poll(struct icp_softc *, struct icp_ccb *, int);
void icp_ccb_unmap(struct icp_softc *, struct icp_ccb *);
int icp_ccb_wait(struct icp_softc *, struct icp_ccb *, int);
int icp_cmd(struct icp_softc *, u_int8_t, u_int16_t, u_int32_t, u_int32_t,
u_int32_t);
#endif /* !_IC_ICPVAR_H_ */

306
sys/dev/ic/ld_icp.c Normal file
View File

@ -0,0 +1,306 @@
/* $NetBSD: ld_icp.c,v 1.1 2002/04/22 21:05:21 ad Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* ICP-Vortex "GDT" front-end for ld(4) driver.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ld_icp.c,v 1.1 2002/04/22 21:05:21 ad Exp $");
#include "rnd.h"
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/buf.h>
#include <sys/endian.h>
#include <sys/dkio.h>
#include <sys/disk.h>
#if NRND > 0
#include <sys/rnd.h>
#endif
#include <uvm/uvm_extern.h>
#include <machine/bus.h>
#include <dev/ldvar.h>
#include <dev/ic/icpreg.h>
#include <dev/ic/icpvar.h>
struct ld_icp_softc {
struct ld_softc sc_ld;
int sc_hwunit;
};
void ld_icp_attach(struct device *, struct device *, void *);
int ld_icp_dobio(struct ld_icp_softc *, void *, int, int, int,
struct buf *);
int ld_icp_dump(struct ld_softc *, void *, int, int);
int ld_icp_flush(struct ld_softc *);
void ld_icp_intr(struct icp_ccb *);
int ld_icp_match(struct device *, struct cfdata *, void *);
int ld_icp_start(struct ld_softc *, struct buf *);
struct cfattach ld_icp_ca = {
sizeof(struct ld_icp_softc), ld_icp_match, ld_icp_attach,
};
int
ld_icp_match(struct device *parent, struct cfdata *match, void *aux)
{
struct icp_attach_args *icpa;
icpa = aux;
return (icpa->icpa_unit < ICPA_UNIT_SCSI);
}
void
ld_icp_attach(struct device *parent, struct device *self, void *aux)
{
struct icp_attach_args *icpa;
struct ld_icp_softc *sc;
struct ld_softc *ld;
struct icp_softc *icp;
struct icp_cachedrv *cd;
struct icp_cdevinfo *cdi;
const char *str;
int t;
sc = (struct ld_icp_softc *)self;
ld = &sc->sc_ld;
icp = (struct icp_softc *)parent;
icpa = aux;
cd = &icp->icp_cdr[icpa->icpa_unit];
sc->sc_hwunit = icpa->icpa_unit;
ld->sc_maxxfer = ICP_MAX_XFER;
ld->sc_secsize = ICP_SECTOR_SIZE;
ld->sc_start = ld_icp_start;
ld->sc_dump = ld_icp_dump;
ld->sc_flush = ld_icp_flush;
ld->sc_secperunit = cd->cd_size;
ld->sc_flags = LDF_ENABLED;
ld->sc_maxqueuecnt = icp->icp_openings;
if (!icp_cmd(icp, ICP_CACHESERVICE, ICP_IOCTL, ICP_CACHE_DRV_INFO,
sc->sc_hwunit, sizeof(struct icp_cdevinfo))) {
printf(": unable to retrieve device info\n",
ld->sc_dv.dv_xname);
ld->sc_flags = LDF_ENABLED;
goto out;
}
cdi = (struct icp_cdevinfo *)icp->icp_scr;
printf(": <%.8s>, ", cdi->ld_name);
t = le32toh(cdi->ld_dtype) >> 16;
/*
* Print device type.
*/
if (le32toh(cdi->ld_dcnt) > 1 || le32toh(cdi->ld_slave) != -1)
str = "RAID-1";
else if (t == 0)
str = "JBOD";
else if (t == 1)
str = "RAID-0";
else if (t == 2)
str = "Chain";
else
str = "unknown type";
printf("type: %s, ", str);
/*
* Print device status.
*/
if (t > 2)
str = "missing";
else if ((cdi->ld_error & 1) != 0) {
str = "fault";
ld->sc_flags = LDF_ENABLED;
} else if ((cdi->ld_error & 2) != 0)
str = "invalid";
else {
str = "optimal";
ld->sc_flags = LDF_ENABLED;
}
printf("status: %s\n", str);
out:
ldattach(ld);
}
int
ld_icp_dobio(struct ld_icp_softc *sc, void *data, int datasize, int blkno,
int dowrite, struct buf *bp)
{
struct icp_cachecmd *cc;
struct icp_ccb *ic;
struct icp_softc *icp;
int s, rv;
icp = (struct icp_softc *)sc->sc_ld.sc_dv.dv_parent;
/*
* Allocate a command control block.
*/
ic = icp_ccb_alloc(icp);
/*
* Map the data transfer.
*/
cc = &ic->ic_cmd.cmd_packet.cc;
ic->ic_sg = cc->cc_sg;
ic->ic_service = ICP_CACHESERVICE;
rv = icp_ccb_map(icp, ic, data, datasize,
dowrite ? IC_XFER_OUT : IC_XFER_IN);
if (rv != 0) {
icp_ccb_free(icp, ic);
return (rv);
}
/*
* Build the command.
*/
ic->ic_cmd.cmd_opcode = htole16((dowrite ? ICP_WRITE : ICP_READ));
cc->cc_deviceno = htole16(sc->sc_hwunit);
cc->cc_blockno = htole32(blkno);
cc->cc_blockcnt = htole32(datasize / ICP_SECTOR_SIZE);
cc->cc_addr = ~0; /* scatter gather */
cc->cc_nsgent = htole32(ic->ic_nsgent);
ic->ic_cmdlen = (u_long)ic->ic_sg - (u_long)&ic->ic_cmd +
ic->ic_nsgent * sizeof(*ic->ic_sg);
/*
* Fire it off to the controller.
*/
if (bp == NULL) {
s = splbio();
rv = icp_ccb_poll(icp, ic, 10000);
icp_ccb_unmap(icp, ic);
icp_ccb_free(icp, ic);
splx(s);
} else {
ic->ic_intr = ld_icp_intr;
ic->ic_context = bp;
ic->ic_dv = &sc->sc_ld.sc_dv;
icp_ccb_enqueue(icp, ic);
}
return (rv);
}
int
ld_icp_start(struct ld_softc *ld, struct buf *bp)
{
return (ld_icp_dobio((struct ld_icp_softc *)ld, bp->b_data,
bp->b_bcount, bp->b_rawblkno, (bp->b_flags & B_READ) == 0, bp));
}
int
ld_icp_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt)
{
return (ld_icp_dobio((struct ld_icp_softc *)ld, data,
blkcnt * ld->sc_secsize, blkno, 1, NULL));
}
int
ld_icp_flush(struct ld_softc *ld)
{
struct ld_icp_softc *sc;
struct icp_softc *icp;
struct icp_cachecmd *cc;
struct icp_ccb *ic;
int rv;
sc = (struct ld_icp_softc *)ld;
icp = (struct icp_softc *)ld->sc_dv.dv_parent;
ic = icp_ccb_alloc(icp);
ic->ic_cmd.cmd_opcode = htole16(ICP_FLUSH);
cc = &ic->ic_cmd.cmd_packet.cc;
cc->cc_deviceno = htole16(sc->sc_hwunit);
cc->cc_blockno = htole32(1);
cc->cc_blockcnt = 0;
cc->cc_addr = 0;
cc->cc_nsgent = 0;
ic->ic_cmdlen = (u_long)&cc->cc_sg - (u_long)&ic->ic_cmd;
ic->ic_service = ICP_CACHESERVICE;
rv = icp_ccb_wait(icp, ic, 30000);
icp_ccb_free(icp, ic);
return (rv);
}
void
ld_icp_intr(struct icp_ccb *ic)
{
struct buf *bp;
struct ld_icp_softc *sc;
struct icp_softc *icp;
bp = ic->ic_context;
sc = (struct ld_icp_softc *)ic->ic_dv;
icp = (struct icp_softc *)sc->sc_ld.sc_dv.dv_parent;
if (ic->ic_status != ICP_S_OK) {
printf("%s: request failed; status=0x%04x\n",
ic->ic_dv->dv_xname, ic->ic_status);
bp->b_flags |= B_ERROR;
bp->b_error = EIO;
bp->b_resid = bp->b_bcount;
} else
bp->b_resid = 0;
icp_ccb_unmap(icp, ic);
icp_ccb_free(icp, ic);
lddone(&sc->sc_ld, bp);
}

View File

@ -1,4 +1,4 @@
# $NetBSD: files.pci,v 1.169 2002/04/22 15:45:19 bouyer Exp $
# $NetBSD: files.pci,v 1.170 2002/04/22 21:05:20 ad Exp $
#
# Config file and device description for machine-independent PCI code.
# Included by ports that need it. Requires that the SCSI files be
@ -73,6 +73,10 @@ device mly: scsi
attach mly at pci
file dev/pci/mly.c mly needs-flag
# ICP-Vortex/Intel RAID controllers
attach icp at pci with icp_pci
file dev/pci/icp_pci.c icp_pci
# DPT EATA SCSI controllers
attach dpt at pci with dpt_pci
file dev/pci/dpt_pci.c dpt_pci

832
sys/dev/pci/icp_pci.c Normal file
View File

@ -0,0 +1,832 @@
/* $NetBSD: icp_pci.c,v 1.1 2002/04/22 21:05:21 ad Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Andrew Doran.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
*/
/*
* Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Niklas Hallqvist.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
*
* from OpenBSD: icp_pci.c,v 1.11 2001/06/12 15:40:30 niklas Exp
*/
/*
* This driver would not have written if it was not for the hardware donations
* from both ICP-Vortex and Öko.neT. I want to thank them for their support.
*
* Re-worked for NetBSD by Andrew Doran. Test hardware kindly supplied by
* Intel.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icp_pci.c,v 1.1 2002/04/22 21:05:21 ad Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/queue.h>
#include <sys/buf.h>
#include <sys/endian.h>
#include <sys/conf.h>
#include <uvm/uvm_extern.h>
#include <machine/bus.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <dev/ic/icpreg.h>
#include <dev/ic/icpvar.h>
/* Product numbers for Fibre-Channel are greater than or equal to 0x200 */
#define ICP_PCI_PRODUCT_FC 0x200
/* Mapping registers for various areas */
#define ICP_PCI_DPMEM 0x10
#define ICP_PCINEW_IOMEM 0x10
#define ICP_PCINEW_IO 0x14
#define ICP_PCINEW_DPMEM 0x18
/* PCI SRAM structure */
#define ICP_MAGIC 0x00 /* u_int32_t, controller ID from BIOS */
#define ICP_NEED_DEINIT 0x04 /* u_int16_t, switch between BIOS/driver */
#define ICP_SWITCH_SUPPORT 0x06 /* u_int8_t, see ICP_NEED_DEINIT */
#define ICP_OS_USED 0x10 /* u_int8_t [16], OS code per service */
#define ICP_FW_MAGIC 0x3c /* u_int8_t, controller ID from firmware */
#define ICP_SRAM_SZ 0x40
/* DPRAM PCI controllers */
#define ICP_DPR_IF 0x00 /* interface area */
#define ICP_6SR (0xff0 - ICP_SRAM_SZ)
#define ICP_SEMA1 0xff1 /* volatile u_int8_t, command semaphore */
#define ICP_IRQEN 0xff5 /* u_int8_t, board interrupts enable */
#define ICP_EVENT 0xff8 /* u_int8_t, release event */
#define ICP_IRQDEL 0xffc /* u_int8_t, acknowledge board interrupt */
#define ICP_DPRAM_SZ 0x1000
/* PLX register structure (new PCI controllers) */
#define ICP_CFG_REG 0x00 /* u_int8_t, DPRAM cfg. (2: < 1MB, 0: any) */
#define ICP_SEMA0_REG 0x40 /* volatile u_int8_t, command semaphore */
#define ICP_SEMA1_REG 0x41 /* volatile u_int8_t, status semaphore */
#define ICP_PLX_STATUS 0x44 /* volatile u_int16_t, command status */
#define ICP_PLX_SERVICE 0x46 /* u_int16_t, service */
#define ICP_PLX_INFO 0x48 /* u_int32_t [2], additional info */
#define ICP_LDOOR_REG 0x60 /* u_int8_t, PCI to local doorbell */
#define ICP_EDOOR_REG 0x64 /* volatile u_int8_t, local to PCI doorbell */
#define ICP_CONTROL0 0x68 /* u_int8_t, control0 register (unused) */
#define ICP_CONTROL1 0x69 /* u_int8_t, board interrupts enable */
#define ICP_PLX_SZ 0x80
/* DPRAM new PCI controllers */
#define ICP_IC 0x00 /* interface */
#define ICP_PCINEW_6SR (0x4000 - ICP_SRAM_SZ)
/* SRAM structure */
#define ICP_PCINEW_SZ 0x4000
/* i960 register structure (PCI MPR controllers) */
#define ICP_MPR_SEMA0 0x10 /* volatile u_int8_t, command semaphore */
#define ICP_MPR_SEMA1 0x12 /* volatile u_int8_t, status semaphore */
#define ICP_MPR_STATUS 0x14 /* volatile u_int16_t, command status */
#define ICP_MPR_SERVICE 0x16 /* u_int16_t, service */
#define ICP_MPR_INFO 0x18 /* u_int32_t [2], additional info */
#define ICP_MPR_LDOOR 0x20 /* u_int8_t, PCI to local doorbell */
#define ICP_MPR_EDOOR 0x2c /* volatile u_int8_t, locl to PCI doorbell */
#define ICP_EDOOR_EN 0x34 /* u_int8_t, board interrupts enable */
#define ICP_I960_SZ 0x1000
/* DPRAM PCI MPR controllers */
#define ICP_I960R 0x00 /* 4KB i960 registers */
#define ICP_MPR_IC ICP_I960_SZ
/* interface area */
#define ICP_MPR_6SR (ICP_I960_SZ + 0x3000 - ICP_SRAM_SZ)
/* SRAM structure */
#define ICP_MPR_SZ 0x4000
int icp_pci_match(struct device *, struct cfdata *, void *);
void icp_pci_attach(struct device *, struct device *, void *);
void icp_pci_enable_intr(struct icp_softc *);
const struct icp_pci_ident *icp_pci_find_ident(struct pci_attach_args *);
void icp_pci_copy_cmd(struct icp_softc *, struct icp_ccb *);
u_int8_t icp_pci_get_status(struct icp_softc *);
void icp_pci_intr(struct icp_softc *, struct icp_intr_ctx *);
void icp_pci_release_event(struct icp_softc *, struct icp_ccb *);
void icp_pci_set_sema0(struct icp_softc *);
int icp_pci_test_busy(struct icp_softc *);
void icp_pcinew_copy_cmd(struct icp_softc *, struct icp_ccb *);
u_int8_t icp_pcinew_get_status(struct icp_softc *);
void icp_pcinew_intr(struct icp_softc *, struct icp_intr_ctx *);
void icp_pcinew_release_event(struct icp_softc *, struct icp_ccb *);
void icp_pcinew_set_sema0(struct icp_softc *);
int icp_pcinew_test_busy(struct icp_softc *);
void icp_mpr_copy_cmd(struct icp_softc *, struct icp_ccb *);
u_int8_t icp_mpr_get_status(struct icp_softc *);
void icp_mpr_intr(struct icp_softc *, struct icp_intr_ctx *);
void icp_mpr_release_event(struct icp_softc *, struct icp_ccb *);
void icp_mpr_set_sema0(struct icp_softc *);
int icp_mpr_test_busy(struct icp_softc *);
struct cfattach icp_pci_ca = {
sizeof(struct icp_softc), icp_pci_match, icp_pci_attach
};
struct icp_pci_ident {
u_short gpi_vendor;
u_short gpi_product;
u_short gpi_class;
} const icp_pci_ident[] = {
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_60x0, ICP_PCI },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6000B, ICP_PCI },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x10, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x20, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6530, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6550, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x17, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x27, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6537, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6557, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x15, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x25, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6535, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6555, ICP_PCINEW },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x17RP, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x27RP, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6537RP, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6557RP, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x11RP, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x21RP, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x17RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x27RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6537RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6557RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x11RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x21RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x18RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x28RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x38RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x58RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6518RS, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x18RN, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x28RN, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x38RN, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x58RN, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x19RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_6x29RD, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x19RN, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x29RN, ICP_MPR },
{ PCI_VENDOR_VORTEX, PCI_PRODUCT_VORTEX_GDT_7x43RN, ICP_MPR },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GDT_RAID1, ICP_MPR },
{ PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_GDT_RAID2, ICP_MPR },
};
const struct icp_pci_ident *
icp_pci_find_ident(struct pci_attach_args *pa)
{
const struct icp_pci_ident *gpi, *maxgpi;
gpi = icp_pci_ident;
maxgpi = gpi + sizeof(icp_pci_ident) / sizeof(icp_pci_ident[0]);
for (; gpi < maxgpi; gpi++)
if (PCI_VENDOR(pa->pa_id) == gpi->gpi_vendor &&
PCI_PRODUCT(pa->pa_id) == gpi->gpi_product)
return (gpi);
return (NULL);
}
int
icp_pci_match(struct device *parent, struct cfdata *match, void *aux)
{
struct pci_attach_args *pa;
pa = aux;
if (PCI_CLASS(pa->pa_class) == PCI_CLASS_I2O)
return (0);
return (icp_pci_find_ident(pa) != NULL);
}
void
icp_pci_attach(struct device *parent, struct device *self, void *aux)
{
struct pci_attach_args *pa;
struct icp_softc *icp;
bus_space_tag_t dpmemt, iomemt, iot;
bus_space_handle_t dpmemh, iomemh, ioh;
bus_addr_t dpmembase, iomembase, iobase;
bus_size_t dpmemsize, iomemsize, iosize;
u_int16_t prod;
u_int32_t status = 0;
#define DPMEM_MAPPED 1
#define IOMEM_MAPPED 2
#define IO_MAPPED 4
#define INTR_ESTABLISHED 8
int retries;
u_int8_t protocol;
pci_intr_handle_t ih;
const char *intrstr;
const struct icp_pci_ident *gpi;
printf(": ");
pa = aux;
icp = (struct icp_softc *)self;
prod = PCI_PRODUCT(pa->pa_id);
gpi = icp_pci_find_ident(pa);
icp->icp_class = gpi->gpi_class;
/* If we don't recognize it, determine class heuristically. */
if (icp->icp_class == 0)
icp->icp_class = prod < 0x100 ? ICP_PCINEW : ICP_MPR;
if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_INTEL &&
prod >= ICP_PCI_PRODUCT_FC)
icp->icp_class |= ICP_FC;
if (pci_mapreg_map(pa,
ICP_CLASS(icp) == ICP_PCINEW ? ICP_PCINEW_DPMEM : ICP_PCI_DPMEM,
PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, &dpmemt,
&dpmemh, &dpmembase, &dpmemsize)) {
if (pci_mapreg_map(pa,
ICP_CLASS(icp) == ICP_PCINEW ? ICP_PCINEW_DPMEM :
ICP_PCI_DPMEM,
PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT_1M, 0,
&dpmemt, &dpmemh, &dpmembase, &dpmemsize)) {
printf("cannot map DPMEM\n");
goto bail_out;
}
}
status |= DPMEM_MAPPED;
icp->icp_dpmemt = dpmemt;
icp->icp_dpmemh = dpmemh;
icp->icp_dpmembase = dpmembase;
icp->icp_dmat = pa->pa_dmat;
/*
* The ICP_PCINEW series also has two other regions to map.
*/
if (ICP_CLASS(icp) == ICP_PCINEW) {
if (pci_mapreg_map(pa, ICP_PCINEW_IOMEM, PCI_MAPREG_TYPE_MEM,
0, &iomemt, &iomemh, &iomembase, &iomemsize)) {
printf("cannot map memory mapped I/O ports\n");
goto bail_out;
}
status |= IOMEM_MAPPED;
if (pci_mapreg_map(pa, ICP_PCINEW_IO, PCI_MAPREG_TYPE_IO, 0,
&iot, &ioh, &iobase, &iosize)) {
printf("cannot map I/O ports\n");
goto bail_out;
}
status |= IO_MAPPED;
icp->icp_iot = iot;
icp->icp_ioh = ioh;
icp->icp_iobase = iobase;
}
switch (ICP_CLASS(icp)) {
case ICP_PCI:
bus_space_set_region_4(dpmemt, dpmemh, 0, 0,
ICP_DPR_IF_SZ >> 2);
if (bus_space_read_1(dpmemt, dpmemh, 0) != 0) {
printf("cannot write to DPMEM\n");
goto bail_out;
}
#if 0
/* disable board interrupts, deinit services */
icph_writeb(0xff, &dp6_ptr->io.irqdel);
icph_writeb(0x00, &dp6_ptr->io.irqen);;
icph_writeb(0x00, &dp6_ptr->u.ic.S_Status);
icph_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
icph_writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
icph_writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
icph_writeb(0, &dp6_ptr->io.event);
retries = INIT_RETRIES;
icph_delay(20);
while (icph_readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("initialization error (DEINIT failed)\n");
icph_munmap(ha->brd);
return 0;
}
icph_delay(1);
}
prot_ver = (unchar)icph_readl(&dp6_ptr->u.ic.S_Info[0]);
icph_writeb(0, &dp6_ptr->u.ic.S_Status);
icph_writeb(0xff, &dp6_ptr->io.irqdel);
if (prot_ver != PROTOCOL_VERSION) {
printk("illegal protocol version\n");
icph_munmap(ha->brd);
return 0;
}
ha->type = ICP_PCI;
ha->ic_all_size = sizeof(dp6_ptr->u);
/* special command to controller BIOS */
icph_writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
icph_writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
icph_writel(0x01, &dp6_ptr->u.ic.S_Info[2]);
icph_writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
icph_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
icph_writeb(0, &dp6_ptr->io.event);
retries = INIT_RETRIES;
icph_delay(20);
while (icph_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("initialization error\n");
icph_munmap(ha->brd);
return 0;
}
icph_delay(1);
}
icph_writeb(0, &dp6_ptr->u.ic.S_Status);
icph_writeb(0xff, &dp6_ptr->io.irqdel);
#endif
icp->icp_ic_all_size = ICP_DPRAM_SZ;
icp->icp_copy_cmd = icp_pci_copy_cmd;
icp->icp_get_status = icp_pci_get_status;
icp->icp_intr = icp_pci_intr;
icp->icp_release_event = icp_pci_release_event;
icp->icp_set_sema0 = icp_pci_set_sema0;
icp->icp_test_busy = icp_pci_test_busy;
break;
case ICP_PCINEW:
bus_space_set_region_4(dpmemt, dpmemh, 0, 0,
ICP_DPR_IF_SZ >> 2);
if (bus_space_read_1(dpmemt, dpmemh, 0) != 0) {
printf("cannot write to DPMEM\n");
goto bail_out;
}
#if 0
/* disable board interrupts, deinit services */
outb(0x00,PTR2USHORT(&ha->plx->control1));
outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
icph_writeb(0x00, &dp6c_ptr->u.ic.S_Status);
icph_writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
icph_writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
icph_writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
retries = INIT_RETRIES;
icph_delay(20);
while (icph_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
if (--retries == 0) {
printk("initialization error (DEINIT failed)\n");
icph_munmap(ha->brd);
return 0;
}
icph_delay(1);
}
prot_ver = (unchar)icph_readl(&dp6c_ptr->u.ic.S_Info[0]);
icph_writeb(0, &dp6c_ptr->u.ic.Status);
if (prot_ver != PROTOCOL_VERSION) {
printk("illegal protocol version\n");
icph_munmap(ha->brd);
return 0;
}
ha->type = ICP_PCINEW;
ha->ic_all_size = sizeof(dp6c_ptr->u);
/* special command to controller BIOS */
icph_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
icph_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
icph_writel(0x01, &dp6c_ptr->u.ic.S_Info[2]);
icph_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
icph_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
retries = INIT_RETRIES;
icph_delay(20);
while (icph_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
if (--retries == 0) {
printk("initialization error\n");
icph_munmap(ha->brd);
return 0;
}
icph_delay(1);
}
icph_writeb(0, &dp6c_ptr->u.ic.S_Status);
#endif
icp->icp_ic_all_size = ICP_PCINEW_SZ;
icp->icp_copy_cmd = icp_pcinew_copy_cmd;
icp->icp_get_status = icp_pcinew_get_status;
icp->icp_intr = icp_pcinew_intr;
icp->icp_release_event = icp_pcinew_release_event;
icp->icp_set_sema0 = icp_pcinew_set_sema0;
icp->icp_test_busy = icp_pcinew_test_busy;
break;
case ICP_MPR:
bus_space_write_4(dpmemt, dpmemh, ICP_MPR_IC, ICP_MPR_MAGIC);
if (bus_space_read_4(dpmemt, dpmemh, ICP_MPR_IC) !=
ICP_MPR_MAGIC) {
printf("cannot access DPMEM at 0x%lx (shadowed?)\n",
(u_long)dpmembase);
goto bail_out;
}
/*
* XXX Here the Linux driver has a weird remapping logic I
* don't understand. My controller does not need it, and I
* cannot see what purpose it serves, therefore I did not
* do anything similar.
*/
bus_space_set_region_4(dpmemt, dpmemh, ICP_I960_SZ, 0,
ICP_DPR_IF_SZ >> 2);
/* Disable everything. */
bus_space_write_1(dpmemt, dpmemh, ICP_EDOOR_EN,
bus_space_read_1(dpmemt, dpmemh, ICP_EDOOR_EN) | 4);
bus_space_write_1(dpmemt, dpmemh, ICP_MPR_EDOOR, 0xff);
bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_STATUS,
0);
bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_CMD_INDEX,
0);
bus_space_write_4(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_INFO,
htole32(dpmembase));
bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_CMD_INDX,
0xff);
bus_space_write_1(dpmemt, dpmemh, ICP_MPR_LDOOR, 1);
DELAY(20);
retries = 1000000;
while (bus_space_read_1(dpmemt, dpmemh,
ICP_MPR_IC + ICP_S_STATUS) != 0xff) {
if (--retries == 0) {
printf("DEINIT failed\n");
goto bail_out;
}
DELAY(1);
}
protocol = (u_int8_t)bus_space_read_4(dpmemt, dpmemh,
ICP_MPR_IC + ICP_S_INFO);
bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_STATUS,
0);
if (protocol != ICP_PROTOCOL_VERSION) {
printf("unsupported protocol %d\n", protocol);
goto bail_out;
}
/* special commnd to controller BIOS */
bus_space_write_4(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_INFO, 0);
bus_space_write_4(dpmemt, dpmemh,
ICP_MPR_IC + ICP_S_INFO + sizeof(u_int32_t), 0);
bus_space_write_4(dpmemt, dpmemh,
ICP_MPR_IC + ICP_S_INFO + 2 * sizeof(u_int32_t), 1);
bus_space_write_4(dpmemt, dpmemh,
ICP_MPR_IC + ICP_S_INFO + 3 * sizeof(u_int32_t), 0);
bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_CMD_INDX,
0xfe);
bus_space_write_1(dpmemt, dpmemh, ICP_MPR_LDOOR, 1);
DELAY(20);
retries = 1000000;
while (bus_space_read_1(dpmemt, dpmemh,
ICP_MPR_IC + ICP_S_STATUS) != 0xfe) {
if (--retries == 0) {
printf("initialization error\n");
goto bail_out;
}
DELAY(1);
}
bus_space_write_1(dpmemt, dpmemh, ICP_MPR_IC + ICP_S_STATUS,
0);
icp->icp_copy_cmd = icp_mpr_copy_cmd;
icp->icp_get_status = icp_mpr_get_status;
icp->icp_intr = icp_mpr_intr;
icp->icp_release_event = icp_mpr_release_event;
icp->icp_set_sema0 = icp_mpr_set_sema0;
icp->icp_test_busy = icp_mpr_test_busy;
break;
}
if (pci_intr_map(pa, &ih)) {
printf("couldn't map interrupt\n");
goto bail_out;
}
intrstr = pci_intr_string(pa->pa_pc, ih);
icp->icp_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, icp_intr, icp);
if (icp->icp_ih == NULL) {
printf("couldn't establish interrupt");
if (intrstr != NULL)
printf(" at %s", intrstr);
printf("\n");
goto bail_out;
}
status |= INTR_ESTABLISHED;
if (gpi->gpi_vendor == PCI_VENDOR_INTEL)
printf("Intel Storage RAID controller\n");
else
printf("ICP-Vortex RAID controller\n");
if (icp_init(icp, intrstr))
goto bail_out;
icp_pci_enable_intr(icp);
return;
bail_out:
if ((status & DPMEM_MAPPED) != 0)
bus_space_unmap(dpmemt, dpmemh, dpmemsize);
if ((status & IOMEM_MAPPED) != 0)
bus_space_unmap(iomemt, iomemh, iomembase);
if ((status & IO_MAPPED) != 0)
bus_space_unmap(iot, ioh, iosize);
if ((status & INTR_ESTABLISHED) != 0)
pci_intr_disestablish(pa->pa_pc, icp->icp_ih);
}
/*
* Enable interrupts.
*/
void
icp_pci_enable_intr(struct icp_softc *icp)
{
switch (ICP_CLASS(icp)) {
case ICP_PCI:
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_IRQDEL,
1);
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_CMD_INDEX, 0);
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_IRQEN,
1);
break;
case ICP_PCINEW:
bus_space_write_1(icp->icp_iot, icp->icp_ioh, ICP_EDOOR_REG,
0xff);
bus_space_write_1(icp->icp_iot, icp->icp_ioh, ICP_CONTROL1, 3);
break;
case ICP_MPR:
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_EDOOR, 0xff);
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_EDOOR_EN,
bus_space_read_1(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_EDOOR_EN) & ~4);
break;
}
}
/*
* "Old" PCI controller-specific functions.
*/
void
icp_pci_copy_cmd(struct icp_softc *icp, struct icp_ccb *ccb)
{
/* XXX Not yet implemented */
}
u_int8_t
icp_pci_get_status(struct icp_softc *icp)
{
/* XXX Not yet implemented */
return (0);
}
void
icp_pci_intr(struct icp_softc *icp, struct icp_intr_ctx *ctx)
{
/* XXX Not yet implemented */
}
void
icp_pci_release_event(struct icp_softc *icp, struct icp_ccb *ccb)
{
/* XXX Not yet implemented */
}
void
icp_pci_set_sema0(struct icp_softc *icp)
{
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_SEMA0, 1);
}
int
icp_pci_test_busy(struct icp_softc *icp)
{
/* XXX Not yet implemented */
return (0);
}
/*
* "New" PCI controller-specific functions.
*/
void
icp_pcinew_copy_cmd(struct icp_softc *icp, struct icp_ccb *ccb)
{
/* XXX Not yet implemented */
}
u_int8_t
icp_pcinew_get_status(struct icp_softc *icp)
{
/* XXX Not yet implemented */
return (0);
}
void
icp_pcinew_intr(struct icp_softc *icp, struct icp_intr_ctx *ctx)
{
/* XXX Not yet implemented */
}
void
icp_pcinew_release_event(struct icp_softc *icp, struct icp_ccb *ccb)
{
/* XXX Not yet implemented */
}
void
icp_pcinew_set_sema0(struct icp_softc *icp)
{
bus_space_write_1(icp->icp_iot, icp->icp_ioh, ICP_SEMA0_REG, 1);
}
int
icp_pcinew_test_busy(struct icp_softc *icp)
{
/* XXX Not yet implemented */
return (0);
}
/*
* MPR PCI controller-specific functions
*/
void
icp_mpr_copy_cmd(struct icp_softc *icp, struct icp_ccb *ic)
{
bus_space_write_2(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_IC + ICP_COMM_QUEUE + 0 * ICP_COMM_Q_SZ + ICP_OFFSET,
ICP_DPR_CMD);
bus_space_write_2(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_IC + ICP_COMM_QUEUE + 0 * ICP_COMM_Q_SZ + ICP_SERV_ID,
ic->ic_service);
bus_space_write_region_4(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_IC + ICP_DPR_CMD, (u_int32_t *)&ic->ic_cmd,
ic->ic_cmdlen >> 2);
}
u_int8_t
icp_mpr_get_status(struct icp_softc *icp)
{
return (bus_space_read_1(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_EDOOR));
}
void
icp_mpr_intr(struct icp_softc *icp, struct icp_intr_ctx *ctx)
{
if ((ctx->istatus & 0x80) != 0) { /* error flag */
ctx->istatus &= ~0x80;
ctx->cmd_status = bus_space_read_2(icp->icp_dpmemt,
icp->icp_dpmemh, ICP_MPR_STATUS);
} else
ctx->cmd_status = ICP_S_OK;
ctx->service = bus_space_read_2(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_SERVICE);
ctx->info = bus_space_read_4(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_INFO);
ctx->info2 = bus_space_read_4(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_INFO + sizeof(u_int32_t));
/*
* XXX Read async event string here.
*/
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_MPR_EDOOR,
0xff);
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_MPR_SEMA1, 0);
}
void
icp_mpr_release_event(struct icp_softc *icp, struct icp_ccb *ic)
{
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_MPR_LDOOR, 1);
}
void
icp_mpr_set_sema0(struct icp_softc *icp)
{
bus_space_write_1(icp->icp_dpmemt, icp->icp_dpmemh, ICP_MPR_SEMA0, 1);
}
int
icp_mpr_test_busy(struct icp_softc *icp)
{
return (bus_space_read_1(icp->icp_dpmemt, icp->icp_dpmemh,
ICP_MPR_SEMA0) & 1);
}