Driver for Compaq array controllers and disks (cac(4)/ca(4)).
This commit is contained in:
parent
415cbeb83f
commit
70063dc527
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files,v 1.354 2000/03/15 02:10:09 fvdl Exp $
|
||||
# $NetBSD: files,v 1.355 2000/03/16 14:52:23 ad Exp $
|
||||
|
||||
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
|
||||
|
||||
@ -211,6 +211,14 @@ file dev/ic/aic77xx.c ahc_aic77xx
|
||||
device dpt: scsi
|
||||
file dev/ic/dpt.c dpt
|
||||
|
||||
# Compaq Smart ARRAY controllers
|
||||
device cac {unit = -1}
|
||||
file dev/ic/cac.c cac
|
||||
|
||||
device ca: disk
|
||||
attach ca at cac
|
||||
file dev/ic/ca.c ca needs-flag
|
||||
|
||||
# AdvanSys 1200A, 1200B and ULTRA SCSI controllers
|
||||
device adv: scsi
|
||||
file dev/ic/adv.c adv
|
||||
|
701
sys/dev/ic/ca.c
Normal file
701
sys/dev/ic/ca.c
Normal file
@ -0,0 +1,701 @@
|
||||
/* $NetBSD: ca.c,v 1.1 2000/03/16 14:52:23 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Charles M. Hannum and Andy 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Originally written by Julian Elischer (julian@dialix.oz.au)
|
||||
* for TRW Financial Systems for use under the MACH(2.5) operating system.
|
||||
*
|
||||
* TRW Financial Systems, in accordance with their agreement with Carnegie
|
||||
* Mellon University, makes this software available to CMU to distribute
|
||||
* or use in any manner that they see fit as long as this message is kept with
|
||||
* the software. For this reason TFS also grants any other persons or
|
||||
* organisations permission to use or modify this software.
|
||||
*
|
||||
* TFS supplies this software to be publicly redistributed
|
||||
* on the understanding that TFS is not responsible for the correct
|
||||
* functioning of this software in any circumstances.
|
||||
*
|
||||
* Ported to run under 386BSD by Julian Elischer (julian@dialix.oz.au) Sept 1992
|
||||
*/
|
||||
|
||||
/*
|
||||
* Disk driver for Compaq arrays, based on sd.c (revision 1.157).
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: ca.c,v 1.1 2000/03/16 14:52:23 ad Exp $");
|
||||
|
||||
#include "rnd.h"
|
||||
|
||||
#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/disklabel.h>
|
||||
#include <sys/disk.h>
|
||||
#include <sys/dkio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/fcntl.h>
|
||||
#if NRND > 0
|
||||
#include <sys/rnd.h>
|
||||
#endif
|
||||
|
||||
#include <machine/bswap.h>
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/ic/cacreg.h>
|
||||
#include <dev/ic/cacvar.h>
|
||||
|
||||
#define CAUNIT(dev) DISKUNIT(dev)
|
||||
#define CAPART(dev) DISKPART(dev)
|
||||
#define CAMINOR(unit, part) DISKMINOR(unit, part)
|
||||
#define CAMAKEDEV(maj, unit, part) MAKEDISKDEV(maj, unit, part)
|
||||
|
||||
#define CALABELDEV(dev) (CAMAKEDEV(major(dev), CAUNIT(dev), RAW_PART))
|
||||
|
||||
struct ca_softc {
|
||||
struct device sc_dv;
|
||||
int sc_unit;
|
||||
int sc_flags;
|
||||
struct cac_softc *sc_cac;
|
||||
struct disk sc_dk;
|
||||
#if NRND > 0
|
||||
rndsource_element_t sc_rnd_source;
|
||||
#endif
|
||||
|
||||
/* Parameters from controller. */
|
||||
int sc_ncylinders;
|
||||
int sc_nheads;
|
||||
int sc_nsectors;
|
||||
int sc_secsize;
|
||||
int sc_secperunit;
|
||||
int sc_mirror;
|
||||
};
|
||||
|
||||
#define CAF_ENABLED 0x01 /* device enabled */
|
||||
#define CAF_LOCKED 0x02 /* lock held */
|
||||
#define CAF_WANTED 0x04 /* lock wanted */
|
||||
#define CAF_WLABEL 0x08 /* label is writable */
|
||||
#define CAF_LABELLING 0x10 /* writing label */
|
||||
|
||||
static int calock __P((struct ca_softc *));
|
||||
static void caunlock __P((struct ca_softc *));
|
||||
static int camatch __P((struct device *, struct cfdata *, void *));
|
||||
static void cacttach __P((struct device *, struct device *, void *));
|
||||
static void cadone __P((struct cac_ccb *, int));
|
||||
static void cagetdisklabel __P((struct ca_softc *));
|
||||
static void cagetdefaultlabel __P((struct ca_softc *, struct disklabel *));
|
||||
|
||||
struct cfattach ca_ca = {
|
||||
sizeof(struct ca_softc), camatch, cacttach
|
||||
};
|
||||
|
||||
extern struct cfdriver ca_cd;
|
||||
|
||||
struct dkdriver cadkdriver = { castrategy };
|
||||
|
||||
static int
|
||||
camatch(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
{
|
||||
#if 0
|
||||
struct cac_attach_args *caca;
|
||||
|
||||
caca = (struct cac_attach_args *)aux;
|
||||
|
||||
/* Unit 0 is the controller */
|
||||
return (caca->caca_unit != 0);
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
cacttach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
struct cac_drive_info dinfo;
|
||||
struct cac_attach_args *caca;
|
||||
struct ca_softc *sc;
|
||||
char *type;
|
||||
int mb;
|
||||
|
||||
sc = (struct ca_softc *)self;
|
||||
caca = (struct cac_attach_args *)aux;
|
||||
sc->sc_cac = (struct cac_softc *)parent;
|
||||
sc->sc_unit = caca->caca_unit;
|
||||
|
||||
if (cac_cmd(sc->sc_cac, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo),
|
||||
sc->sc_unit, 0, CAC_CCB_DATA_IN, NULL)) {
|
||||
printf("%s: CMD_GET_LOG_DRV_INFO failed\n",
|
||||
sc->sc_dv.dv_xname);
|
||||
return;
|
||||
}
|
||||
|
||||
sc->sc_ncylinders = CAC_GET2(dinfo.ncylinders);
|
||||
sc->sc_nheads = CAC_GET1(dinfo.nheads);
|
||||
sc->sc_nsectors = CAC_GET1(dinfo.nsectors);
|
||||
sc->sc_secsize = CAC_GET2(dinfo.secsize);
|
||||
sc->sc_mirror = CAC_GET1(dinfo.mirror);
|
||||
sc->sc_secperunit = sc->sc_ncylinders * sc->sc_nheads * sc->sc_nsectors;
|
||||
|
||||
switch (sc->sc_mirror) {
|
||||
case 0:
|
||||
type = "standalone disk or RAID0";
|
||||
break;
|
||||
case 1:
|
||||
type = "RAID4";
|
||||
break;
|
||||
case 2:
|
||||
type = "RAID1";
|
||||
break;
|
||||
case 3:
|
||||
type = "RAID5";
|
||||
break;
|
||||
default:
|
||||
type = "unknown type of";
|
||||
break;
|
||||
}
|
||||
|
||||
printf(": %s array\n", type);
|
||||
|
||||
mb = sc->sc_secperunit / (1048576 / sc->sc_secsize);
|
||||
printf("%s: %uMB, %u cyl, %u head, %u sec, %d bytes/sect "
|
||||
"x %d sectors\n", sc->sc_dv.dv_xname, mb, sc->sc_ncylinders,
|
||||
sc->sc_nheads, sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit);
|
||||
|
||||
/* Initialize and attach the disk structure */
|
||||
sc->sc_dk.dk_driver = &cadkdriver;
|
||||
sc->sc_dk.dk_name = sc->sc_dv.dv_xname;
|
||||
disk_attach(&sc->sc_dk);
|
||||
sc->sc_flags |= CAF_ENABLED;
|
||||
|
||||
#if !defined(__i386__) && !defined(__vax__)
|
||||
dk_establish(&sc->sc_dk, &sc->sc_dv); /* XXX */
|
||||
#endif
|
||||
|
||||
#if NRND > 0
|
||||
/* Attach the device into the rnd source list. */
|
||||
rnd_attach_source(&sc->sc_rnd_source, sc->sc_dv.dv_xname,
|
||||
RND_TYPE_DISK, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
caopen(dev, flags, fmt, p)
|
||||
dev_t dev;
|
||||
int flags;
|
||||
int fmt;
|
||||
struct proc *p;
|
||||
{
|
||||
struct ca_softc *sc;
|
||||
int unit, part;
|
||||
|
||||
unit = CAUNIT(dev);
|
||||
if (unit >= ca_cd.cd_ndevs)
|
||||
return (ENXIO);
|
||||
if ((sc = ca_cd.cd_devs[unit]) == NULL)
|
||||
return (ENXIO);
|
||||
if ((sc->sc_flags & CAF_ENABLED) == 0)
|
||||
return (ENODEV);
|
||||
part = CAPART(dev);
|
||||
calock(sc);
|
||||
|
||||
if (sc->sc_dk.dk_openmask == 0)
|
||||
cagetdisklabel(sc);
|
||||
|
||||
/* Check that the partition exists. */
|
||||
if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions ||
|
||||
sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
|
||||
caunlock(sc);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Insure only one open at a time. */
|
||||
switch (fmt) {
|
||||
case S_IFCHR:
|
||||
sc->sc_dk.dk_copenmask |= (1 << part);
|
||||
break;
|
||||
case S_IFBLK:
|
||||
sc->sc_dk.dk_bopenmask |= (1 << part);
|
||||
break;
|
||||
}
|
||||
sc->sc_dk.dk_openmask =
|
||||
sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
|
||||
|
||||
caunlock(sc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
caclose(dev, flags, fmt, p)
|
||||
dev_t dev;
|
||||
int flags;
|
||||
int fmt;
|
||||
struct proc *p;
|
||||
{
|
||||
struct ca_softc *sc;
|
||||
int part, unit;
|
||||
|
||||
unit = CAUNIT(dev);
|
||||
part = CAPART(dev);
|
||||
sc = ca_cd.cd_devs[unit];
|
||||
calock(sc);
|
||||
|
||||
switch (fmt) {
|
||||
case S_IFCHR:
|
||||
sc->sc_dk.dk_copenmask &= ~(1 << part);
|
||||
break;
|
||||
case S_IFBLK:
|
||||
sc->sc_dk.dk_bopenmask &= ~(1 << part);
|
||||
break;
|
||||
}
|
||||
sc->sc_dk.dk_openmask =
|
||||
sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
|
||||
|
||||
caunlock(sc);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
caread(dev, uio, ioflag)
|
||||
dev_t dev;
|
||||
struct uio *uio;
|
||||
int ioflag;
|
||||
{
|
||||
|
||||
return (physio(castrategy, NULL, dev, B_READ, cac_minphys, uio));
|
||||
}
|
||||
|
||||
int
|
||||
cawrite(dev, uio, ioflag)
|
||||
dev_t dev;
|
||||
struct uio *uio;
|
||||
int ioflag;
|
||||
{
|
||||
|
||||
return (physio(castrategy, NULL, dev, B_WRITE, cac_minphys, uio));
|
||||
}
|
||||
|
||||
int
|
||||
caioctl(dev, cmd, addr, flag, p)
|
||||
dev_t dev;
|
||||
u_long cmd;
|
||||
caddr_t addr;
|
||||
int32_t flag;
|
||||
struct proc *p;
|
||||
{
|
||||
struct ca_softc *sc;
|
||||
int part, unit, error;
|
||||
|
||||
unit = CAUNIT(dev);
|
||||
part = CAPART(dev);
|
||||
sc = ca_cd.cd_devs[unit];
|
||||
error = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case DIOCGDINFO:
|
||||
memcpy(addr, sc->sc_dk.dk_label, sizeof(struct disklabel));
|
||||
return (0);
|
||||
|
||||
case DIOCGPART:
|
||||
((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
|
||||
((struct partinfo *)addr)->part =
|
||||
&sc->sc_dk.dk_label->d_partitions[part];
|
||||
break;
|
||||
|
||||
case DIOCWDINFO:
|
||||
case DIOCSDINFO:
|
||||
if ((flag & FWRITE) == 0)
|
||||
return (EBADF);
|
||||
|
||||
if ((error = calock(sc)) != 0)
|
||||
return (error);
|
||||
sc->sc_flags |= CAF_LABELLING;
|
||||
|
||||
error = setdisklabel(sc->sc_dk.dk_label,
|
||||
(struct disklabel *)addr, /*sc->sc_dk.dk_openmask : */0,
|
||||
sc->sc_dk.dk_cpulabel);
|
||||
if (error == 0 && cmd == DIOCWDINFO)
|
||||
error = writedisklabel(CALABELDEV(dev), castrategy,
|
||||
sc->sc_dk.dk_label, sc->sc_dk.dk_cpulabel);
|
||||
|
||||
sc->sc_flags &= ~CAF_LABELLING;
|
||||
caunlock(sc);
|
||||
break;
|
||||
|
||||
case DIOCKLABEL:
|
||||
/* XXX */
|
||||
break;
|
||||
|
||||
case DIOCWLABEL:
|
||||
if ((flag & FWRITE) == 0)
|
||||
return (EBADF);
|
||||
if (*(int *)addr)
|
||||
sc->sc_flags |= CAF_WLABEL;
|
||||
else
|
||||
sc->sc_flags &= ~CAF_WLABEL;
|
||||
break;
|
||||
|
||||
case DIOCGDEFLABEL:
|
||||
cagetdefaultlabel(sc, (struct disklabel *)addr);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read/write a buffer.
|
||||
*/
|
||||
void
|
||||
castrategy(bp)
|
||||
struct buf *bp;
|
||||
{
|
||||
struct cac_context cc;
|
||||
struct disklabel *lp;
|
||||
struct ca_softc *sc;
|
||||
int part, unit, blkno, flg, cmd;
|
||||
|
||||
unit = CAUNIT(bp->b_dev);
|
||||
part = CAPART(bp->b_dev);
|
||||
sc = ca_cd.cd_devs[unit];
|
||||
|
||||
lp = sc->sc_dk.dk_label;
|
||||
|
||||
/*
|
||||
* The transfer must be a whole number of blocks, offset must not be
|
||||
* negative.
|
||||
*/
|
||||
if ((bp->b_bcount % lp->d_secsize) != 0 || bp->b_blkno < 0) {
|
||||
bp->b_flags |= B_ERROR;
|
||||
biodone(bp);
|
||||
}
|
||||
|
||||
/*
|
||||
* If it's a null transfer, return immediatly.
|
||||
*/
|
||||
if (bp->b_bcount == 0) {
|
||||
bp->b_resid = bp->b_bcount;
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do bounds checking, adjust transfer. If error, process.
|
||||
* If end of partition, just return.
|
||||
*/
|
||||
if (part != RAW_PART &&
|
||||
bounds_check_with_label(bp, lp,
|
||||
(sc->sc_flags & (CAF_WLABEL | CAF_LABELLING)) != 0) <= 0) {
|
||||
bp->b_resid = bp->b_bcount;
|
||||
biodone(bp);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now convert the block number to absolute and put it in
|
||||
* terms of the device's logical block size.
|
||||
*/
|
||||
if (lp->d_secsize >= DEV_BSIZE)
|
||||
blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
|
||||
else
|
||||
blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize);
|
||||
|
||||
if (bp->b_dev != RAW_PART)
|
||||
blkno += lp->d_partitions[part].p_offset;
|
||||
|
||||
bp->b_rawblkno = blkno;
|
||||
|
||||
/*
|
||||
* Which command to issue. Don't let synchronous writes linger in
|
||||
* the controller's cache.
|
||||
*/
|
||||
if ((bp->b_flags & B_READ) != 0) {
|
||||
cmd = CAC_CMD_READ;
|
||||
flg = CAC_CCB_DATA_IN;
|
||||
} else if ((bp->b_flags & B_ASYNC) != 0) {
|
||||
cmd = CAC_CMD_WRITE;
|
||||
flg = CAC_CCB_DATA_OUT;
|
||||
} else {
|
||||
cmd = CAC_CMD_WRITE_MEDIA;
|
||||
flg = CAC_CCB_DATA_OUT;
|
||||
}
|
||||
|
||||
cc.cc_context = bp;
|
||||
cc.cc_handler = cadone;
|
||||
cc.cc_dv = &sc->sc_dv;
|
||||
|
||||
disk_busy(&sc->sc_dk);
|
||||
cac_cmd(sc->sc_cac, cmd, bp->b_data, bp->b_bcount, sc->sc_unit, blkno,
|
||||
flg, &cc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle completed transfers.
|
||||
*/
|
||||
static void
|
||||
cadone(ccb, error)
|
||||
struct cac_ccb *ccb;
|
||||
int error;
|
||||
{
|
||||
struct buf *bp;
|
||||
struct ca_softc *sc;
|
||||
|
||||
sc = (struct ca_softc *)ccb->ccb_context.cc_dv;
|
||||
bp = (struct buf *)ccb->ccb_context.cc_context;
|
||||
cac_ccb_free(sc->sc_cac, ccb);
|
||||
|
||||
if (error) {
|
||||
bp->b_flags |= B_ERROR;
|
||||
bp->b_error = EIO;
|
||||
bp->b_resid = bp->b_bcount;
|
||||
} else
|
||||
bp->b_resid = 0;
|
||||
|
||||
disk_unbusy(&sc->sc_dk, 0);
|
||||
#if NRND > 0
|
||||
rnd_add_uint32(&sc->sc_rnd_source, bp->b_rawblkno);
|
||||
#endif
|
||||
biodone(bp);
|
||||
}
|
||||
|
||||
int
|
||||
casize(dev)
|
||||
dev_t dev;
|
||||
{
|
||||
struct ca_softc *sc;
|
||||
int part, unit, omask, size;
|
||||
|
||||
unit = CAUNIT(dev);
|
||||
if (unit >= ca_cd.cd_ndevs)
|
||||
return (ENXIO);
|
||||
if ((sc = ca_cd.cd_devs[unit]) == NULL)
|
||||
return (ENXIO);
|
||||
if ((sc->sc_flags & CAF_ENABLED) == 0)
|
||||
return (ENODEV);
|
||||
part = CAPART(dev);
|
||||
|
||||
omask = sc->sc_dk.dk_openmask & (1 << part);
|
||||
|
||||
if (omask == 0 && caopen(dev, 0, S_IFBLK, NULL) != 0)
|
||||
return (-1);
|
||||
else if (sc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
|
||||
size = -1;
|
||||
else
|
||||
size = sc->sc_dk.dk_label->d_partitions[part].p_size *
|
||||
(sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
|
||||
if (omask == 0 && caclose(dev, 0, S_IFBLK, NULL) != 0)
|
||||
return (-1);
|
||||
|
||||
return (size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the label information from the specified device.
|
||||
*/
|
||||
static void
|
||||
cagetdisklabel(sc)
|
||||
struct ca_softc *sc;
|
||||
{
|
||||
struct disklabel *lp;
|
||||
char *errstring;
|
||||
|
||||
lp = sc->sc_dk.dk_label;
|
||||
|
||||
memset(sc->sc_dk.dk_cpulabel, 0, sizeof(struct cpu_disklabel));
|
||||
cagetdefaultlabel(sc, lp);
|
||||
|
||||
if (lp->d_secpercyl == 0) {
|
||||
lp->d_secpercyl = 100;
|
||||
/* as long as it's not 0 - readdisklabel divides by it (?) */
|
||||
}
|
||||
|
||||
/* Call the generic disklabel extraction routine. */
|
||||
errstring = readdisklabel(CAMAKEDEV(0, sc->sc_dv.dv_unit, RAW_PART),
|
||||
castrategy, lp, sc->sc_dk.dk_cpulabel);
|
||||
if (errstring != NULL)
|
||||
printf("%s: %s\n", sc->sc_dv.dv_xname, errstring);
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct a ficticious label.
|
||||
*/
|
||||
static void
|
||||
cagetdefaultlabel(sc, lp)
|
||||
struct ca_softc *sc;
|
||||
struct disklabel *lp;
|
||||
{
|
||||
|
||||
memset(lp, 0, sizeof(struct disklabel));
|
||||
|
||||
lp->d_secsize = sc->sc_secsize;
|
||||
lp->d_ntracks = sc->sc_nheads;
|
||||
lp->d_nsectors = sc->sc_nsectors;
|
||||
lp->d_ncylinders = sc->sc_ncylinders;
|
||||
lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
|
||||
lp->d_type = DTYPE_SCSI; /* XXX */
|
||||
strcpy(lp->d_typename, "unknown");
|
||||
strcpy(lp->d_packname, "fictitious");
|
||||
lp->d_secperunit = sc->sc_secperunit;
|
||||
lp->d_rpm = 7200;
|
||||
lp->d_interleave = 1;
|
||||
lp->d_flags = 0;
|
||||
|
||||
lp->d_partitions[RAW_PART].p_offset = 0;
|
||||
lp->d_partitions[RAW_PART].p_size =
|
||||
lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
|
||||
lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
|
||||
lp->d_npartitions = RAW_PART + 1;
|
||||
|
||||
lp->d_magic = DISKMAGIC;
|
||||
lp->d_magic2 = DISKMAGIC;
|
||||
lp->d_checksum = dkcksum(lp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait interruptibly for an exclusive lock.
|
||||
*
|
||||
* XXX
|
||||
* Several drivers do this; it should be abstracted and made MP-safe.
|
||||
*/
|
||||
static int
|
||||
calock(sc)
|
||||
struct ca_softc *sc;
|
||||
{
|
||||
int error;
|
||||
|
||||
while ((sc->sc_flags & CAF_LOCKED) != 0) {
|
||||
sc->sc_flags |= CAF_WANTED;
|
||||
if ((error = tsleep(sc, PRIBIO | PCATCH, "idlck", 0)) != 0)
|
||||
return (error);
|
||||
}
|
||||
sc->sc_flags |= CAF_LOCKED;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlock and wake up any waiters.
|
||||
*/
|
||||
static void
|
||||
caunlock(sc)
|
||||
struct ca_softc *sc;
|
||||
{
|
||||
|
||||
sc->sc_flags &= ~CAF_LOCKED;
|
||||
if ((sc->sc_flags & CAF_WANTED) != 0) {
|
||||
sc->sc_flags &= ~CAF_WANTED;
|
||||
wakeup(sc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Take a dump.
|
||||
*/
|
||||
int
|
||||
cadump(dev, blkno, va, size)
|
||||
dev_t dev;
|
||||
daddr_t blkno;
|
||||
caddr_t va;
|
||||
size_t size;
|
||||
{
|
||||
struct ca_softc *sc;
|
||||
struct disklabel *lp;
|
||||
int unit, part, nsects, sectoff, totwrt, nwrt;
|
||||
static int dumping;
|
||||
|
||||
/* Check if recursive dump; if so, punt. */
|
||||
if (dumping)
|
||||
return (EFAULT);
|
||||
dumping = 1;
|
||||
|
||||
unit = CAUNIT(dev);
|
||||
if (unit >= ca_cd.cd_ndevs)
|
||||
return (ENXIO);
|
||||
if ((sc = ca_cd.cd_devs[unit]) == NULL)
|
||||
return (ENXIO);
|
||||
if ((sc->sc_flags & CAF_ENABLED) == 0)
|
||||
return (ENODEV);
|
||||
part = CAPART(dev);
|
||||
|
||||
/* Convert to disk sectors. Request must be a multiple of size. */
|
||||
lp = sc->sc_dk.dk_label;
|
||||
if ((size % lp->d_secsize) != 0)
|
||||
return (EFAULT);
|
||||
totwrt = size / lp->d_secsize;
|
||||
blkno = dbtob(blkno) / lp->d_secsize; /* blkno in DEV_BSIZE units */
|
||||
|
||||
nsects = lp->d_partitions[part].p_size;
|
||||
sectoff = lp->d_partitions[part].p_offset;
|
||||
|
||||
/* Check transfer bounds against partition size. */
|
||||
if ((blkno < 0) || ((blkno + totwrt) > nsects))
|
||||
return (EINVAL);
|
||||
|
||||
/* Offset block number to start of partition. */
|
||||
blkno += sectoff;
|
||||
|
||||
while (totwrt > 0) {
|
||||
nwrt = max(65536 / lp->d_secsize, totwrt); /* XXX */
|
||||
|
||||
if (cac_cmd(sc->sc_cac, CAC_CMD_WRITE_MEDIA, va,
|
||||
nwrt * lp->d_secsize, sc->sc_unit, blkno,
|
||||
CAC_CCB_DATA_OUT, NULL))
|
||||
return (ENXIO);
|
||||
|
||||
totwrt -= nwrt;
|
||||
blkno += nwrt;
|
||||
va += lp->d_secsize * nwrt;
|
||||
}
|
||||
|
||||
dumping = 0;
|
||||
return (0);
|
||||
}
|
499
sys/dev/ic/cac.c
Normal file
499
sys/dev/ic/cac.c
Normal file
@ -0,0 +1,499 @@
|
||||
/* $NetBSD: cac.c,v 1.1 2000/03/16 14:52:24 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Andy 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Driver for Compaq array controllers.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: cac.c,v 1.1 2000/03/16 14:52:24 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/pool.h>
|
||||
|
||||
#include <machine/bswap.h>
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/ic/cacreg.h>
|
||||
#include <dev/ic/cacvar.h>
|
||||
|
||||
static void cac_ccb_done __P((struct cac_softc *, struct cac_ccb *));
|
||||
static int cac_print __P((void *, const char *));
|
||||
static int cac_submatch __P((struct device *, struct cfdata *, void *));
|
||||
static void cac_ccb_poll __P((struct cac_softc *, struct cac_ccb *, int));
|
||||
static void cac_shutdown __P((void *));
|
||||
|
||||
static SIMPLEQ_HEAD(, cac_softc) cac_hba; /* tailq of HBA softc's */
|
||||
static void *cac_sdh; /* shutdown hook */
|
||||
|
||||
/*
|
||||
* Initialise our interface to the controller.
|
||||
*/
|
||||
int
|
||||
cac_init(sc, intrstr)
|
||||
struct cac_softc *sc;
|
||||
const char *intrstr;
|
||||
{
|
||||
struct cac_controller_info cinfo;
|
||||
struct cac_attach_args caca;
|
||||
int error, rseg, size, i;
|
||||
bus_dma_segment_t seg;
|
||||
struct cac_ccb *ccb;
|
||||
|
||||
printf("Compaq %s\n", sc->sc_typestr);
|
||||
if (intrstr != NULL)
|
||||
printf("%s: interrupting at %s\n", sc->sc_dv.dv_xname, intrstr);
|
||||
|
||||
SIMPLEQ_INIT(&sc->sc_ccb_free);
|
||||
SIMPLEQ_INIT(&sc->sc_ccb_queue);
|
||||
|
||||
size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
|
||||
|
||||
if ((error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1,
|
||||
&rseg, BUS_DMA_NOWAIT)) != 0) {
|
||||
printf("%s: unable to allocate CCBs, error = %d\n",
|
||||
sc->sc_dv.dv_xname, error);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
|
||||
(caddr_t *)&sc->sc_ccbs, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
|
||||
printf("%s: unable to map CCBs, error = %d\n",
|
||||
sc->sc_dv.dv_xname, error);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((error = bus_dmamap_create(sc->sc_dmat, size, size, 1, 0,
|
||||
BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
|
||||
printf("%s: unable to create CCB DMA map, error = %d\n",
|
||||
sc->sc_dv.dv_xname, error);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
|
||||
size, NULL, BUS_DMA_NOWAIT)) != 0) {
|
||||
printf("%s: unable to load CCB DMA map, error = %d\n",
|
||||
sc->sc_dv.dv_xname, error);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
|
||||
memset(sc->sc_ccbs, 0, size);
|
||||
ccb = (struct cac_ccb *)sc->sc_ccbs;
|
||||
|
||||
for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
|
||||
/* Create the DMA map for this CCB's data */
|
||||
error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
|
||||
CAC_SG_SIZE, CAC_MAX_XFER, 0,
|
||||
BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap_xfer);
|
||||
|
||||
if (error) {
|
||||
printf("%s: can't create ccb dmamap (%d)\n",
|
||||
sc->sc_dv.dv_xname, error);
|
||||
break;
|
||||
}
|
||||
|
||||
ccb->ccb_flags = 0;
|
||||
ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
|
||||
SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
|
||||
}
|
||||
|
||||
if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
|
||||
CAC_CCB_DATA_IN, NULL)) {
|
||||
printf("%s: CAC_CMD_GET_CTRL_INFO failed\n",
|
||||
sc->sc_dv.dv_xname);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
for (i = 0; i < cinfo.num_drvs; i++) {
|
||||
caca.caca_unit = i;
|
||||
config_found_sm(&sc->sc_dv, &caca, cac_print, cac_submatch);
|
||||
}
|
||||
|
||||
/* Set shutdownhook before we start any device activity. */
|
||||
if (cac_sdh == NULL) {
|
||||
SIMPLEQ_INIT(&cac_hba);
|
||||
cac_sdh = shutdownhook_establish(cac_shutdown, NULL);
|
||||
}
|
||||
|
||||
sc->sc_cl->cl_intr_enable(sc, CAC_INT_ENABLE);
|
||||
SIMPLEQ_INSERT_HEAD(&cac_hba, sc, sc_chain);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown the controller.
|
||||
*/
|
||||
static void
|
||||
cac_shutdown(cookie)
|
||||
void *cookie;
|
||||
{
|
||||
struct cac_softc *sc;
|
||||
char buf[512];
|
||||
|
||||
printf("shutting down cac devices...");
|
||||
|
||||
for (sc = SIMPLEQ_FIRST(&cac_hba); sc != NULL;
|
||||
sc = SIMPLEQ_NEXT(sc, sc_chain)) {
|
||||
/* XXX documentation on this is a bit fuzzy. */
|
||||
memset(buf, 0, sizeof (buf));
|
||||
buf[0] = 1;
|
||||
cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0,
|
||||
CAC_CCB_DATA_OUT, NULL);
|
||||
}
|
||||
|
||||
DELAY(5000*1000);
|
||||
printf(" done\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print attach message for a subdevice.
|
||||
*/
|
||||
static int
|
||||
cac_print(aux, pnp)
|
||||
void *aux;
|
||||
const char *pnp;
|
||||
{
|
||||
struct cac_attach_args *caca;
|
||||
|
||||
caca = (struct cac_attach_args *)aux;
|
||||
|
||||
if (pnp)
|
||||
printf("block device at %s", pnp);
|
||||
printf(" unit %d", caca->caca_unit);
|
||||
return (UNCONF);
|
||||
}
|
||||
|
||||
/*
|
||||
* Match a subdevice.
|
||||
*/
|
||||
static int
|
||||
cac_submatch(parent, cf, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *cf;
|
||||
void *aux;
|
||||
{
|
||||
struct cac_attach_args *caca;
|
||||
|
||||
caca = (struct cac_attach_args *)aux;
|
||||
|
||||
if (cf->cacacf_unit != CACACF_UNIT_UNKNOWN &&
|
||||
cf->cacacf_unit != caca->caca_unit)
|
||||
return (0);
|
||||
|
||||
return (cf->cf_attach->ca_match(parent, cf, aux));
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle an interrupt from the controller: process finished CCBs and
|
||||
* dequeue any waiting CCBs.
|
||||
*/
|
||||
int
|
||||
cac_intr(xxx_sc)
|
||||
void *xxx_sc;
|
||||
{
|
||||
struct cac_softc *sc;
|
||||
struct cac_ccb *ccb;
|
||||
paddr_t completed;
|
||||
int off;
|
||||
|
||||
sc = (struct cac_softc *)xxx_sc;
|
||||
|
||||
if (!sc->sc_cl->cl_intr_pending(sc))
|
||||
return (0);
|
||||
|
||||
while ((completed = sc->sc_cl->cl_completed(sc)) != 0) {
|
||||
off = (completed & ~3) - sc->sc_ccbs_paddr;
|
||||
ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, off,
|
||||
sizeof(struct cac_ccb),
|
||||
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
||||
|
||||
cac_ccb_done(sc, ccb);
|
||||
}
|
||||
|
||||
cac_ccb_start(sc, NULL);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Execute a [polled] command.
|
||||
*/
|
||||
int
|
||||
cac_cmd(sc, command, data, datasize, drive, blkno, flags, context)
|
||||
struct cac_softc *sc;
|
||||
int command;
|
||||
void *data;
|
||||
int datasize;
|
||||
int drive;
|
||||
int blkno;
|
||||
int flags;
|
||||
struct cac_context *context;
|
||||
{
|
||||
struct cac_ccb *ccb;
|
||||
struct cac_sgb *sgb;
|
||||
int s, i, rv;
|
||||
|
||||
if ((ccb = cac_ccb_alloc(sc, 0)) == NULL) {
|
||||
printf("%s: unable to alloc CCB", sc->sc_dv.dv_xname);
|
||||
return (1);
|
||||
}
|
||||
|
||||
if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
|
||||
bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer, (void *)data,
|
||||
datasize, NULL, BUS_DMA_NOWAIT);
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0, datasize,
|
||||
(flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
|
||||
BUS_DMASYNC_PREWRITE);
|
||||
|
||||
sgb = ccb->ccb_seg;
|
||||
|
||||
for (i = 0; i < ccb->ccb_dmamap_xfer->dm_nsegs; i++, sgb++) {
|
||||
sgb->length =
|
||||
htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
|
||||
sgb->addr =
|
||||
htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
|
||||
}
|
||||
}
|
||||
|
||||
ccb->ccb_hdr.drive = drive;
|
||||
ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
|
||||
sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
|
||||
|
||||
ccb->ccb_req.bcount = htole16(howmany(datasize, DEV_BSIZE));
|
||||
ccb->ccb_req.command = command;
|
||||
ccb->ccb_req.sgcount = i;
|
||||
ccb->ccb_req.blkno = htole32(blkno);
|
||||
|
||||
ccb->ccb_flags = flags;
|
||||
ccb->ccb_datasize = datasize;
|
||||
|
||||
if (context == NULL) {
|
||||
memset(&ccb->ccb_context, 0, sizeof(struct cac_context));
|
||||
s = splbio();
|
||||
if (cac_ccb_start(sc, ccb)) {
|
||||
cac_ccb_free(sc, ccb);
|
||||
rv = -1;
|
||||
} else {
|
||||
cac_ccb_poll(sc, ccb, 2000);
|
||||
cac_ccb_free(sc, ccb);
|
||||
rv = 0;
|
||||
}
|
||||
splx(s);
|
||||
} else {
|
||||
memcpy(&ccb->ccb_context, context, sizeof(struct cac_context));
|
||||
rv = cac_ccb_start(sc, ccb);
|
||||
}
|
||||
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait for the specified CCB to complete. Must be called at splbio.
|
||||
*/
|
||||
static void
|
||||
cac_ccb_poll(sc, ccb, timo)
|
||||
struct cac_softc *sc;
|
||||
struct cac_ccb *ccb;
|
||||
int timo;
|
||||
{
|
||||
struct cac_ccb *ccb_done = NULL;
|
||||
paddr_t completed;
|
||||
int off;
|
||||
|
||||
for (;;) {
|
||||
for (; timo != 0; timo--) {
|
||||
if ((completed = sc->sc_cl->cl_completed(sc)) != 0)
|
||||
break;
|
||||
DELAY(100);
|
||||
}
|
||||
|
||||
if (timo == 0)
|
||||
panic("%s: cac_ccb_poll: timeout", sc->sc_dv.dv_xname);
|
||||
|
||||
off = (completed & ~3) - sc->sc_ccbs_paddr;
|
||||
ccb_done = (struct cac_ccb *)(sc->sc_ccbs + off);
|
||||
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, off,
|
||||
sizeof(struct cac_ccb),
|
||||
BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
|
||||
|
||||
cac_ccb_done(sc, ccb_done);
|
||||
if (ccb_done == ccb)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enqueue the specifed command (if any) and attempt to start all enqueued
|
||||
* commands. Must be called at splbio.
|
||||
*/
|
||||
int
|
||||
cac_ccb_start(sc, ccb)
|
||||
struct cac_softc *sc;
|
||||
struct cac_ccb *ccb;
|
||||
{
|
||||
int s;
|
||||
|
||||
s = splbio();
|
||||
|
||||
if (ccb != NULL)
|
||||
SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
|
||||
|
||||
while ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue)) != NULL) {
|
||||
if (sc->sc_cl->cl_fifo_full(sc)) {
|
||||
splx(s);
|
||||
return (-1);
|
||||
}
|
||||
SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb, ccb_chain);
|
||||
bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap,
|
||||
(caddr_t)ccb - sc->sc_ccbs, sizeof(struct cac_ccb),
|
||||
BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
|
||||
sc->sc_cl->cl_submit(sc, ccb->ccb_paddr);
|
||||
}
|
||||
|
||||
splx(s);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process a finished CCB.
|
||||
*/
|
||||
static void
|
||||
cac_ccb_done(sc, ccb)
|
||||
struct cac_softc *sc;
|
||||
struct cac_ccb *ccb;
|
||||
{
|
||||
int error;
|
||||
|
||||
error = 0;
|
||||
|
||||
if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
|
||||
bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
|
||||
ccb->ccb_datasize, ccb->ccb_flags & CAC_CCB_DATA_IN ?
|
||||
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
|
||||
bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
|
||||
}
|
||||
|
||||
if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0)
|
||||
printf("%s: soft error\n", sc->sc_dv.dv_xname);
|
||||
if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) {
|
||||
error = 1;
|
||||
printf("%s: hard error\n", sc->sc_dv.dv_xname);
|
||||
}
|
||||
if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) {
|
||||
error = 1;
|
||||
printf("%s: invalid request\n", sc->sc_dv.dv_xname);
|
||||
}
|
||||
|
||||
if (ccb->ccb_context.cc_handler != NULL)
|
||||
ccb->ccb_context.cc_handler(ccb, error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a free CCB.
|
||||
*/
|
||||
struct cac_ccb *
|
||||
cac_ccb_alloc(sc, nosleep)
|
||||
struct cac_softc *sc;
|
||||
int nosleep;
|
||||
{
|
||||
struct cac_ccb *ccb;
|
||||
int s;
|
||||
|
||||
s = splbio();
|
||||
|
||||
for (;;) {
|
||||
if ((ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free)) != NULL) {
|
||||
SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
|
||||
break;
|
||||
}
|
||||
if (nosleep) {
|
||||
ccb = NULL;
|
||||
break;
|
||||
}
|
||||
tsleep(&sc->sc_ccb_free, PRIBIO, "cacccb", 0);
|
||||
}
|
||||
|
||||
splx(s);
|
||||
if (ccb != NULL)
|
||||
memset(ccb, 0, 276); /* XXX */
|
||||
return (ccb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put a CCB onto the freelist.
|
||||
*/
|
||||
void
|
||||
cac_ccb_free(sc, ccb)
|
||||
struct cac_softc *sc;
|
||||
struct cac_ccb *ccb;
|
||||
{
|
||||
int s;
|
||||
|
||||
s = splbio();
|
||||
ccb->ccb_flags = 0;
|
||||
SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
|
||||
|
||||
/* Wake anybody waiting for a free ccb */
|
||||
if (SIMPLEQ_NEXT(ccb, ccb_chain) == NULL)
|
||||
wakeup(&sc->sc_ccb_free);
|
||||
splx(s);
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the size of a transfer.
|
||||
*/
|
||||
void
|
||||
cac_minphys(bp)
|
||||
struct buf *bp;
|
||||
{
|
||||
|
||||
if (bp->b_bcount > CAC_MAX_XFER / DEV_BSIZE) /* XXX */
|
||||
bp->b_bcount = CAC_MAX_XFER / DEV_BSIZE; /* XXX */
|
||||
}
|
171
sys/dev/ic/cacreg.h
Normal file
171
sys/dev/ic/cacreg.h
Normal file
@ -0,0 +1,171 @@
|
||||
/* $NetBSD: cacreg.h,v 1.1 2000/03/16 14:52:24 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Andy 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 Jonathan Lemon
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY 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.
|
||||
*
|
||||
* FreeBSD: src/sys/dev/ida/idareg.h,v 1.2 1999/08/28 00:41:55 peter Exp
|
||||
*/
|
||||
|
||||
#ifndef _IC_CACREG_H_
|
||||
#define _IC_CACREG_H_
|
||||
|
||||
#define cac_inl(sc, port) \
|
||||
bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, port)
|
||||
#define cac_outl(sc, port, val) \
|
||||
bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, port, val)
|
||||
|
||||
/* Board register offsets */
|
||||
#define CAC_REG_CMD_FIFO 0x04
|
||||
#define CAC_REG_DONE_FIFO 0x08
|
||||
#define CAC_REG_INT_MASK 0x0C
|
||||
#define CAC_REG_STATUS 0x10
|
||||
#define CAC_REG_INT_PENDING 0x14
|
||||
|
||||
#define CAC_42REG_CMD_FIFO 0x40
|
||||
#define CAC_42REG_DONE_FIFO 0x44
|
||||
#define CAC_42REG_INT_MASK 0x34
|
||||
#define CAC_42REG_STATUS 0x30
|
||||
#define CAC_42REG_INT_PENDING 0x08
|
||||
|
||||
/* Interrupt mask values */
|
||||
#define CAC_INT_DISABLE 0x00
|
||||
#define CAC_INT_ENABLE 0x01
|
||||
|
||||
/* Command types */
|
||||
#define CAC_CMD_GET_LOG_DRV_INFO 0x10
|
||||
#define CAC_CMD_GET_CTRL_INFO 0x11
|
||||
#define CAC_CMD_SENSE_DRV_STATUS 0x12
|
||||
#define CAC_CMD_START_RECOVERY 0x13
|
||||
#define CAC_CMD_GET_PHYS_DRV_INFO 0x15
|
||||
#define CAC_CMD_BLINK_DRV_LEDS 0x16
|
||||
#define CAC_CMD_SENSE_DRV_LEDS 0x17
|
||||
#define CAC_CMD_GET_LOG_DRV_EXT 0x18
|
||||
#define CAC_CMD_GET_CTRL_INFO 0x11
|
||||
#define CAC_CMD_READ 0x20
|
||||
#define CAC_CMD_WRITE 0x30
|
||||
#define CAC_CMD_WRITE_MEDIA 0x31
|
||||
#define CAC_CMD_GET_CONFIG 0x50
|
||||
#define CAC_CMD_SET_CONFIG 0x51
|
||||
#define CAC_CMD_FLUSH_CACHE 0xc2
|
||||
|
||||
/* Return status codes */
|
||||
#define CAC_RET_SOFT_ERROR 0x02
|
||||
#define CAC_RET_HARD_ERROR 0x04
|
||||
#define CAC_RET_CMD_REJECTED 0x14
|
||||
|
||||
struct cac_drive_info {
|
||||
u_int16_t secsize __attribute__ ((packed));
|
||||
u_int32_t secperunit __attribute__ ((packed));
|
||||
u_int16_t ncylinders __attribute__ ((packed));
|
||||
u_int8_t nheads __attribute__ ((packed));
|
||||
u_int8_t signature __attribute__ ((packed));
|
||||
u_int8_t psectors __attribute__ ((packed));
|
||||
u_int16_t wprecomp __attribute__ ((packed));
|
||||
u_int8_t max_acc __attribute__ ((packed));
|
||||
u_int8_t control __attribute__ ((packed));
|
||||
u_int16_t pcylinders __attribute__ ((packed));
|
||||
u_int8_t ptracks __attribute__ ((packed));
|
||||
u_int16_t landing_zone __attribute__ ((packed));
|
||||
u_int8_t nsectors __attribute__ ((packed));
|
||||
u_int8_t checksum __attribute__ ((packed));
|
||||
u_int8_t mirror __attribute__ ((packed));
|
||||
};
|
||||
|
||||
struct cac_controller_info {
|
||||
u_int8_t num_drvs __attribute__ ((packed));
|
||||
u_int32_t signature __attribute__ ((packed));
|
||||
u_int8_t firm_rev[4] __attribute__ ((packed));
|
||||
};
|
||||
|
||||
struct cac_hdr {
|
||||
u_int8_t drive; /* logical drive */
|
||||
u_int8_t priority; /* block priority */
|
||||
u_int16_t size; /* size of request, in words */
|
||||
};
|
||||
|
||||
struct cac_req {
|
||||
u_int16_t next; /* offset of next request */
|
||||
u_int8_t command; /* command */
|
||||
u_int8_t error; /* return error code */
|
||||
u_int32_t blkno; /* block number */
|
||||
u_int16_t bcount; /* block count */
|
||||
u_int8_t sgcount; /* number of scatter/gather entries */
|
||||
u_int8_t reserved; /* reserved */
|
||||
};
|
||||
|
||||
struct cac_sgb {
|
||||
u_int32_t length; /* length of S/G segment */
|
||||
u_int32_t addr; /* physical address of block */
|
||||
};
|
||||
|
||||
/*
|
||||
* Stupid macros to deal with alignment/endianness issues.
|
||||
*/
|
||||
|
||||
#define CAC_GET1(x) \
|
||||
(((u_char *)&(x))[0])
|
||||
#define CAC_GET2(x) \
|
||||
(((u_char *)&(x))[0] | (((u_char *)&(x))[1] << 8))
|
||||
#define CAC_GET4(x) \
|
||||
((((u_char *)&(x))[0] | (((u_char *)&(x))[1] << 8)) | \
|
||||
(((u_char *)&(x))[0] << 16 | (((u_char *)&(x))[1] << 24)))
|
||||
|
||||
#endif /* !_IC_CACREG_H_ */
|
119
sys/dev/ic/cacvar.h
Normal file
119
sys/dev/ic/cacvar.h
Normal file
@ -0,0 +1,119 @@
|
||||
/* $NetBSD: cacvar.h,v 1.1 2000/03/16 14:52:24 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Andy 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_CACVAR_H_
|
||||
#define _IC_CACVAR_H_
|
||||
|
||||
#include "locators.h"
|
||||
|
||||
#define CAC_MAX_CCBS 64
|
||||
#define CAC_MAX_XFER 1048576
|
||||
#define CAC_SG_SIZE 32
|
||||
|
||||
struct cac_softc;
|
||||
struct cac_ccb;
|
||||
|
||||
struct cac_context {
|
||||
void (*cc_handler) __P((struct cac_ccb *, int));
|
||||
struct device *cc_dv;
|
||||
void *cc_context;
|
||||
};
|
||||
|
||||
struct cac_ccb {
|
||||
/* Data the controller will touch - 276 bytes */
|
||||
struct cac_hdr ccb_hdr;
|
||||
struct cac_req ccb_req;
|
||||
struct cac_sgb ccb_seg[CAC_SG_SIZE];
|
||||
u_int32_t ccb_junk_context;
|
||||
|
||||
/* Data the controller won't touch */
|
||||
int ccb_flags;
|
||||
int ccb_datasize;
|
||||
paddr_t ccb_paddr;
|
||||
bus_dmamap_t ccb_dmamap_xfer;
|
||||
SIMPLEQ_ENTRY(cac_ccb) ccb_chain;
|
||||
struct cac_context ccb_context;
|
||||
};
|
||||
|
||||
#define CAC_CCB_DATA_IN 0x0001
|
||||
#define CAC_CCB_DATA_OUT 0x0002
|
||||
|
||||
struct cac_linkage {
|
||||
void (*cl_submit) __P((struct cac_softc *, paddr_t));
|
||||
paddr_t (*cl_completed) __P((struct cac_softc *));
|
||||
int (*cl_intr_pending) __P((struct cac_softc *));
|
||||
void (*cl_intr_enable) __P((struct cac_softc *, int));
|
||||
int (*cl_fifo_full) __P((struct cac_softc *));
|
||||
};
|
||||
|
||||
struct cac_softc {
|
||||
struct device sc_dv;
|
||||
bus_space_tag_t sc_iot;
|
||||
bus_space_handle_t sc_ioh;
|
||||
bus_dma_tag_t sc_dmat;
|
||||
bus_dmamap_t sc_dmamap;
|
||||
void *sc_ih;
|
||||
struct cac_linkage *sc_cl;
|
||||
char *sc_typestr;
|
||||
caddr_t sc_ccbs;
|
||||
paddr_t sc_ccbs_paddr;
|
||||
SIMPLEQ_HEAD(, cac_ccb) sc_ccb_free;
|
||||
SIMPLEQ_HEAD(, cac_ccb) sc_ccb_queue;
|
||||
SIMPLEQ_ENTRY(cac_softc) sc_chain;
|
||||
};
|
||||
|
||||
struct cac_attach_args {
|
||||
int caca_unit;
|
||||
};
|
||||
|
||||
#define CACACF_UNIT 0
|
||||
|
||||
#define cacacf_unit cf_loc[CACACF_UNIT]
|
||||
|
||||
#define CACACF_UNIT_UNKNOWN -1
|
||||
|
||||
int cac_cmd __P((struct cac_softc *, int, void *, int, int, int, int,
|
||||
struct cac_context *));
|
||||
void cac_minphys __P((struct buf *));
|
||||
int cac_intr __P((void *));
|
||||
int cac_init __P((struct cac_softc *, const char *));
|
||||
void cac_ccb_free __P((struct cac_softc *, struct cac_ccb *));
|
||||
int cac_ccb_start __P((struct cac_softc *, struct cac_ccb *));
|
||||
struct cac_ccb *cac_ccb_alloc __P((struct cac_softc *, int));
|
||||
|
||||
#endif /* !_IC_CACVAR_H_ */
|
290
sys/dev/pci/cac_pci.c
Normal file
290
sys/dev/pci/cac_pci.c
Normal file
@ -0,0 +1,290 @@
|
||||
/* $NetBSD: cac_pci.c,v 1.1 2000/03/16 14:52:23 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Andy 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* PCI front-end for cac(4) driver.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: cac_pci.c,v 1.1 2000/03/16 14:52:23 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 <machine/endian.h>
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/pci/pcidevs.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
#include <dev/ic/cacreg.h>
|
||||
#include <dev/ic/cacvar.h>
|
||||
|
||||
#define PCI_CBIO 0x10 /* Configuration base I/O address */
|
||||
#define PCI_CBMA 0x14 /* Configuration base memory address */
|
||||
|
||||
static int cac_pci_match __P((struct device *, struct cfdata *, void *));
|
||||
static void cac_pci_attach __P((struct device *, struct device *, void *));
|
||||
|
||||
static void cac_pci_l0_submit __P((struct cac_softc *, paddr_t));
|
||||
static paddr_t cac_pci_l0_completed __P((struct cac_softc *));
|
||||
static int cac_pci_l0_intr_pending __P((struct cac_softc *));
|
||||
static void cac_pci_l0_intr_enable __P((struct cac_softc *, int));
|
||||
static int cac_pci_l0_fifo_full __P((struct cac_softc *));
|
||||
|
||||
static void cac_pci_l1_submit __P((struct cac_softc *, paddr_t));
|
||||
static paddr_t cac_pci_l1_completed __P((struct cac_softc *));
|
||||
static int cac_pci_l1_intr_pending __P((struct cac_softc *));
|
||||
static void cac_pci_l1_intr_enable __P((struct cac_softc *, int));
|
||||
static int cac_pci_l1_fifo_full __P((struct cac_softc *));
|
||||
|
||||
struct cfattach cac_pci_ca = {
|
||||
sizeof(struct cac_softc), cac_pci_match, cac_pci_attach
|
||||
};
|
||||
|
||||
static struct cac_linkage cac_pci_l0 = {
|
||||
cac_pci_l0_submit,
|
||||
cac_pci_l0_completed,
|
||||
cac_pci_l0_intr_pending,
|
||||
cac_pci_l0_intr_enable,
|
||||
cac_pci_l0_fifo_full
|
||||
};
|
||||
|
||||
static struct cac_linkage cac_pci_l1 = {
|
||||
cac_pci_l1_submit,
|
||||
cac_pci_l1_completed,
|
||||
cac_pci_l1_intr_pending,
|
||||
cac_pci_l1_intr_enable,
|
||||
cac_pci_l1_fifo_full
|
||||
};
|
||||
|
||||
/* This block of code inspired by Compaq's Linux driver. */
|
||||
struct cac_type {
|
||||
int ct_id; /* PCI ID */
|
||||
struct cac_linkage *ct_linkage; /* Command interface */
|
||||
char *ct_typestr; /* Textual description */
|
||||
} static cac_type[] = {
|
||||
#ifdef notdef
|
||||
{ 0x0040110e, &cac_pci_lX, "IDA" },
|
||||
{ 0x0140110e, &cac_pci_lX, "IDA 2" },
|
||||
{ 0x1040110e, &cac_pci_lX, "IAES" },
|
||||
{ 0x2040110e, &cac_pci_lX, "SMART" },
|
||||
#endif
|
||||
{ 0x3040110E, &cac_pci_l0, "SMART-2/E" },
|
||||
{ 0xae100e11, &cac_pci_l0, "SMART-2/P" }, /* XXX also SA 211? */
|
||||
{ 0x40300e11, &cac_pci_l0, "SMART-2/P" },
|
||||
{ 0x40310e11, &cac_pci_l0, "SMART-2SL" },
|
||||
{ 0x40320e11, &cac_pci_l0, "Smart Array 3200" },
|
||||
{ 0x40330e11, &cac_pci_l0, "Smart Array 3100ES" },
|
||||
{ 0x40340e11, &cac_pci_l0, "Smart Array 221" },
|
||||
{ 0x40400e11, &cac_pci_l1, "Integrated Array" },
|
||||
{ 0x40500e11, &cac_pci_l1, "Smart Array 4200" },
|
||||
{ 0x40510e11, &cac_pci_l1, "Smart Array 4200ES" },
|
||||
{ 0xffffffff, NULL, NULL },
|
||||
};
|
||||
|
||||
static int
|
||||
cac_pci_match(parent, match, aux)
|
||||
struct device *parent;
|
||||
struct cfdata *match;
|
||||
void *aux;
|
||||
{
|
||||
struct pci_attach_args *pa;
|
||||
int i;
|
||||
|
||||
pa = (struct pci_attach_args *)aux;
|
||||
|
||||
for (i = 0; cac_type[i].ct_linkage != NULL; i++)
|
||||
if (pa->pa_id == cac_type[i].ct_id)
|
||||
return (1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
cac_pci_attach(parent, self, aux)
|
||||
struct device *parent;
|
||||
struct device *self;
|
||||
void *aux;
|
||||
{
|
||||
struct pci_attach_args *pa;
|
||||
struct cac_softc *sc;
|
||||
pci_chipset_tag_t pc;
|
||||
pci_intr_handle_t ih;
|
||||
const char *intrstr;
|
||||
pcireg_t csr;
|
||||
int i;
|
||||
|
||||
sc = (struct cac_softc *)self;
|
||||
pa = (struct pci_attach_args *)aux;
|
||||
pc = pa->pa_pc;
|
||||
|
||||
printf(": ");
|
||||
|
||||
if (pci_mapreg_map(pa, PCI_CBIO, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot,
|
||||
&sc->sc_ioh, NULL, NULL)) {
|
||||
printf("can't map i/o space\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sc->sc_dmat = pa->pa_dmat;
|
||||
|
||||
/* Enable the device. */
|
||||
csr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG);
|
||||
pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG,
|
||||
csr | PCI_COMMAND_MASTER_ENABLE);
|
||||
|
||||
/* Map and establish the interrupt. */
|
||||
if (pci_intr_map(pc, pa->pa_intrtag, pa->pa_intrpin,
|
||||
pa->pa_intrline, &ih)) {
|
||||
printf("can't map interrupt\n");
|
||||
return;
|
||||
}
|
||||
intrstr = pci_intr_string(pc, ih);
|
||||
sc->sc_ih = pci_intr_establish(pc, ih, IPL_BIO, cac_intr, sc);
|
||||
if (sc->sc_ih == NULL) {
|
||||
printf("can't establish interrupt");
|
||||
if (intrstr != NULL)
|
||||
printf(" at %s", intrstr);
|
||||
printf("\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now attach to the bus-independent code */
|
||||
for (i = 0; cac_type[i].ct_linkage != NULL; i++)
|
||||
if (pa->pa_id == cac_type[i].ct_id)
|
||||
break;
|
||||
sc->sc_typestr = cac_type[i].ct_typestr;
|
||||
sc->sc_cl = cac_type[i].ct_linkage;
|
||||
cac_init(sc, intrstr);
|
||||
}
|
||||
|
||||
static void
|
||||
cac_pci_l0_submit(sc, addr)
|
||||
struct cac_softc *sc;
|
||||
paddr_t addr;
|
||||
{
|
||||
|
||||
cac_outl(sc, CAC_REG_CMD_FIFO, addr);
|
||||
}
|
||||
|
||||
static paddr_t
|
||||
cac_pci_l0_completed(sc)
|
||||
struct cac_softc *sc;
|
||||
{
|
||||
|
||||
return (cac_inl(sc, CAC_REG_DONE_FIFO));
|
||||
}
|
||||
|
||||
static int
|
||||
cac_pci_l0_intr_pending(sc)
|
||||
struct cac_softc *sc;
|
||||
{
|
||||
|
||||
return (cac_inl(sc, CAC_REG_INT_PENDING));
|
||||
}
|
||||
|
||||
static void
|
||||
cac_pci_l0_intr_enable(sc, state)
|
||||
struct cac_softc *sc;
|
||||
int state;
|
||||
{
|
||||
|
||||
cac_outl(sc, CAC_REG_INT_MASK, state);
|
||||
}
|
||||
|
||||
static int
|
||||
cac_pci_l0_fifo_full(sc)
|
||||
struct cac_softc *sc;
|
||||
{
|
||||
|
||||
return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
|
||||
}
|
||||
|
||||
static void
|
||||
cac_pci_l1_submit(sc, addr)
|
||||
struct cac_softc *sc;
|
||||
paddr_t addr;
|
||||
{
|
||||
|
||||
cac_outl(sc, CAC_42REG_CMD_FIFO, addr);
|
||||
}
|
||||
|
||||
static paddr_t
|
||||
cac_pci_l1_completed(sc)
|
||||
struct cac_softc *sc;
|
||||
{
|
||||
int32_t val;
|
||||
|
||||
if ((val = cac_inl(sc, CAC_42REG_DONE_FIFO)) == -1)
|
||||
return (0);
|
||||
|
||||
cac_outl(sc, CAC_42REG_DONE_FIFO, 0);
|
||||
return ((paddr_t)val);
|
||||
}
|
||||
|
||||
static int
|
||||
cac_pci_l1_intr_pending(sc)
|
||||
struct cac_softc *sc;
|
||||
{
|
||||
|
||||
return (cac_inl(sc, CAC_42REG_INT_PENDING) &
|
||||
cac_inl(sc, CAC_42REG_STATUS));
|
||||
}
|
||||
|
||||
static void
|
||||
cac_pci_l1_intr_enable(sc, state)
|
||||
struct cac_softc *sc;
|
||||
int state;
|
||||
{
|
||||
|
||||
cac_outl(sc, CAC_REG_INT_MASK, (state ? 0 : 8)); /* XXX */
|
||||
}
|
||||
|
||||
static int
|
||||
cac_pci_l1_fifo_full(sc)
|
||||
struct cac_softc *sc;
|
||||
{
|
||||
|
||||
return (~cac_inl(sc, CAC_42REG_CMD_FIFO));
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.pci,v 1.77 2000/03/04 10:27:59 elric Exp $
|
||||
# $NetBSD: files.pci,v 1.78 2000/03/16 14:52:23 ad Exp $
|
||||
#
|
||||
# Config file and device description for machine-independent PCI code.
|
||||
# Included by ports that need it. Requires that the SCSI files be
|
||||
@ -18,6 +18,10 @@ file dev/pci/pci_subr.c pci
|
||||
attach ahc at pci with ahc_pci: ahc_seeprom, smc93cx6
|
||||
file dev/pci/ahc_pci.c ahc_pci
|
||||
|
||||
# Compaq RAID controllers
|
||||
attach cac at pci with cac_pci
|
||||
file dev/pci/cac_pci.c cac_pci
|
||||
|
||||
# DPT EATA SCSI controllers
|
||||
attach dpt at pci with dpt_pci
|
||||
file dev/pci/dpt_pci.c dpt_pci
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: conf.h,v 1.72 2000/02/22 21:11:28 tls Exp $ */
|
||||
/* $NetBSD: conf.h,v 1.73 2000/03/16 14:52:22 ad Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990, 1993
|
||||
@ -469,6 +469,12 @@ cdev_decl(ss);
|
||||
bdev_decl(uk);
|
||||
cdev_decl(uk);
|
||||
|
||||
/*
|
||||
* [bc]dev_decl()s for Compaq RAID devices.
|
||||
*/
|
||||
bdev_decl(ca);
|
||||
cdev_decl(ca);
|
||||
|
||||
/*
|
||||
* [bc]dev_decl()s for 'fake' network devices.
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user