Pull thorpej-bus-dma branch into mainline.

This commit is contained in:
thorpej 1997-06-06 23:30:02 +00:00
parent ef7d5776d0
commit fbc0df0a1a
15 changed files with 1083 additions and 434 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ahb.c,v 1.8 1997/03/28 23:47:14 mycroft Exp $ */
/* $NetBSD: ahb.c,v 1.9 1997/06/06 23:30:02 thorpej Exp $ */
#undef AHBDEBUG
#ifdef DDB
@ -7,6 +7,43 @@
#define integrate static inline
#endif
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
*
@ -83,13 +120,14 @@
#define ECB_HASH_SHIFT 9
#define ECB_HASH(x) ((((long)(x))>>ECB_HASH_SHIFT) & (ECB_HASH_SIZE - 1))
#define KVTOPHYS(x) vtophys(x)
#define AHB_MAXXFER ((AHB_NSEG - 1) << PGSHIFT)
struct ahb_softc {
struct device sc_dev;
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
void *sc_ih;
struct ahb_ecb *sc_ecbhash[ECB_HASH_SIZE];
@ -117,6 +155,7 @@ void ahbminphys __P((struct buf *));
int ahb_scsi_cmd __P((struct scsi_xfer *));
int ahb_poll __P((struct ahb_softc *, struct scsi_xfer *, int));
void ahb_timeout __P((void *));
int ahb_create_ecbs __P((struct ahb_softc *));
integrate void ahb_reset_ecb __P((struct ahb_softc *, struct ahb_ecb *));
integrate void ahb_init_ecb __P((struct ahb_softc *, struct ahb_ecb *));
@ -136,7 +175,11 @@ struct scsi_device ahb_dev = {
NULL, /* Use default 'done' routine */
};
#ifdef __BROKEN_INDIRECT_CONFIG
int ahbmatch __P((struct device *, void *, void *));
#else
int ahbmatch __P((struct device *, struct cfdata *, void *));
#endif
void ahbattach __P((struct device *, struct device *, void *));
struct cfattach ahb_ca = {
@ -149,6 +192,9 @@ struct cfdriver ahb_cd = {
#define AHB_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
/* XXX Should put this in a better place. */
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
/*
* Check the slots looking for a board we recognise
* If we find one, note it's address (slot) and call
@ -157,7 +203,12 @@ struct cfdriver ahb_cd = {
int
ahbmatch(parent, match, aux)
struct device *parent;
void *match, *aux;
#ifdef __BROKEN_INDIRECT_CONFIG
void *match;
#else
struct cfdata *match;
#endif
void *aux;
{
struct eisa_attach_args *ea = aux;
bus_space_tag_t iot = ea->ea_iot;
@ -217,6 +268,7 @@ ahbattach(parent, self, aux)
sc->sc_iot = iot;
sc->sc_ioh = ioh;
sc->sc_dmat = ea->ea_dmat;
if (ahb_find(iot, ioh, &apd))
panic("ahbattach: ahb_find failed!");
@ -284,7 +336,12 @@ ahb_send_mbox(sc, opcode, ecb)
Debugger();
}
bus_space_write_4(iot, ioh, MBOXOUT0, KVTOPHYS(ecb)); /* don't know this will work */
/*
* don't know if this will work.
* XXX WHAT DOES THIS COMMENT MEAN?! --thorpej
*/
bus_space_write_4(iot, ioh, MBOXOUT0,
ecb->dmamap_self->dm_segs[0].ds_addr);
bus_space_write_1(iot, ioh, ATTN, opcode | ecb->xs->sc_link->target);
if ((ecb->xs->flags & SCSI_POLL) == 0)
@ -433,25 +490,87 @@ ahb_free_ecb(sc, ecb)
splx(s);
}
/*
* Create a set of ecbs and add them to the free list.
*/
integrate void
ahb_init_ecb(sc, ecb)
struct ahb_softc *sc;
struct ahb_ecb *ecb;
{
bus_dma_tag_t dmat = sc->sc_dmat;
int hashnum;
/*
* XXX Should we put a DIAGNOSTIC check for multiple
* XXX ECB inits here?
*/
bzero(ecb, sizeof(struct ahb_ecb));
/*
* Create the DMA maps for this ECB.
*/
if (bus_dmamap_create(dmat, sizeof(struct ahb_ecb), 1,
sizeof(struct ahb_ecb), 0, BUS_DMA_NOWAIT, &ecb->dmamap_self) ||
/* XXX What's a good value for this? */
bus_dmamap_create(dmat, AHB_MAXXFER, AHB_NSEG, AHB_MAXXFER,
0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &ecb->dmamap_xfer))
panic("ahb_init_ecb: can't create DMA maps");
/*
* Load the permanent DMA maps.
*/
if (bus_dmamap_load(dmat, ecb->dmamap_self, ecb,
sizeof(struct ahb_ecb), NULL, BUS_DMA_NOWAIT))
panic("ahb_init_ecb: can't load permanent maps");
/*
* put in the phystokv hash table
* Never gets taken out.
*/
ecb->hashkey = KVTOPHYS(ecb);
ecb->hashkey = ecb->dmamap_self->dm_segs[0].ds_addr;
hashnum = ECB_HASH(ecb->hashkey);
ecb->nexthash = sc->sc_ecbhash[hashnum];
sc->sc_ecbhash[hashnum] = ecb;
ahb_reset_ecb(sc, ecb);
}
int
ahb_create_ecbs(sc)
struct ahb_softc *sc;
{
bus_dma_segment_t seg;
bus_size_t size;
struct ahb_ecb *ecb;
int rseg, error;
size = NBPG;
error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg,
BUS_DMA_NOWAIT);
if (error)
return (error);
error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
(caddr_t *)&ecb, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC);
if (error) {
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
return (error);
}
bzero(ecb, size);
while (size > sizeof(struct ahb_ecb)) {
ahb_init_ecb(sc, ecb);
sc->sc_numecbs++;
TAILQ_INSERT_TAIL(&sc->sc_free_ecb, ecb, chain);
(caddr_t)ecb += ALIGN(sizeof(struct ahb_ecb));
size -= ALIGN(sizeof(struct ahb_ecb));
}
return (0);
}
/*
* Get a free ecb
*
@ -479,16 +598,12 @@ ahb_get_ecb(sc, flags)
break;
}
if (sc->sc_numecbs < AHB_ECB_MAX) {
ecb = (struct ahb_ecb *) malloc(sizeof(struct ahb_ecb),
M_TEMP, M_NOWAIT);
if (!ecb) {
printf("%s: can't malloc ecb\n",
if (ahb_create_ecbs(sc)) {
printf("%s: can't allocate ecbs\n",
sc->sc_dev.dv_xname);
goto out;
}
ahb_init_ecb(sc, ecb);
sc->sc_numecbs++;
break;
continue;
}
if ((flags & SCSI_NOSLEEP) != 0)
goto out;
@ -530,10 +645,23 @@ ahb_done(sc, ecb)
struct ahb_softc *sc;
struct ahb_ecb *ecb;
{
bus_dma_tag_t dmat = sc->sc_dmat;
struct scsi_sense_data *s1, *s2;
struct scsi_xfer *xs = ecb->xs;
SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahb_done\n"));
/*
* If we were a data transfer, unload the map that described
* the data buffer.
*/
if (xs->datalen) {
bus_dmamap_sync(dmat, ecb->dmamap_xfer,
(xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(dmat, ecb->dmamap_xfer);
}
/*
* Otherwise, put the results of the operation
* into the xfer and call whoever started it
@ -689,8 +817,8 @@ ahbminphys(bp)
struct buf *bp;
{
if (bp->b_bcount > ((AHB_NSEG - 1) << PGSHIFT))
bp->b_bcount = ((AHB_NSEG - 1) << PGSHIFT);
if (bp->b_bcount > AHB_MAXXFER)
bp->b_bcount = AHB_MAXXFER;
minphys(bp);
}
@ -704,14 +832,12 @@ ahb_scsi_cmd(xs)
{
struct scsi_link *sc_link = xs->sc_link;
struct ahb_softc *sc = sc_link->adapter_softc;
bus_dma_tag_t dmat = sc->sc_dmat;
struct ahb_ecb *ecb;
struct ahb_dma_seg *sg;
int seg; /* scatter gather seg being worked on */
u_long thiskv, thisphys, nextphys;
int bytes_this_seg, bytes_this_page, datalen, flags;
int s;
int error, seg, flags, s;
SC_DEBUG(sc_link, SDEV_DB2, ("ahb_scsi_cmd\n"));
/*
* get a ecb (mbox-out) to use. If the transfer
* is from a buf (possibly from interrupt time)
@ -759,96 +885,65 @@ ahb_scsi_cmd(xs)
ecb->opt1 = ECB_SES /*| ECB_DSB*/ | ECB_ARS;
ecb->opt2 = sc_link->lun | ECB_NRB;
bcopy(xs->cmd, &ecb->scsi_cmd, ecb->scsi_cmd_length = xs->cmdlen);
ecb->sense_ptr = KVTOPHYS(&ecb->ecb_sense);
ecb->sense_ptr = ecb->dmamap_self->dm_segs[0].ds_addr +
offsetof(struct ahb_ecb, ecb_sense);
ecb->req_sense_length = sizeof(ecb->ecb_sense);
ecb->status = KVTOPHYS(&ecb->ecb_status);
ecb->status = ecb->dmamap_self->dm_segs[0].ds_addr +
offsetof(struct ahb_ecb, ecb_status);
ecb->ecb_status.host_stat = 0x00;
ecb->ecb_status.target_stat = 0x00;
if (xs->datalen) {
sg = ecb->ahb_dma;
seg = 0;
#ifdef TFS
/*
* Map the DMA transfer.
*/
#ifdef TFS
if (flags & SCSI_DATA_UIO) {
struct iovec *iovp = ((struct uio *) xs->data)->uio_iov;
datalen = ((struct uio *) xs->data)->uio_iovcnt;
xs->datalen = 0;
while (datalen && seg < AHB_NSEG) {
sg->seg_addr = (physaddr)iovp->iov_base;
sg->seg_len = iovp->iov_len;
xs->datalen += iovp->iov_len;
SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)",
iovp->iov_len, iovp->iov_base));
sg++;
iovp++;
seg++;
datalen--;
}
}
else
#endif /*TFS */
error = bus_dmamap_load_uio(sc->sc_dmat,
ecb->dmamap_xfer, (struct uio *)xs->data,
(flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
} else
#endif /* TFS */
{
/*
* Set up the scatter gather block
*/
SC_DEBUG(sc_link, SDEV_DB4,
("%d @0x%x:- ", xs->datalen, xs->data));
datalen = xs->datalen;
thiskv = (long) xs->data;
thisphys = KVTOPHYS(thiskv);
while (datalen && seg < AHB_NSEG) {
bytes_this_seg = 0;
/* put in the base address */
sg->seg_addr = thisphys;
SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
/* do it at least once */
nextphys = thisphys;
while (datalen && thisphys == nextphys) {
/*
* This page is contiguous (physically)
* with the the last, just extend the
* length
*/
/* how far to the end of the page */
nextphys = (thisphys & ~PGOFSET) + NBPG;
bytes_this_page = nextphys - thisphys;
/**** or the data ****/
bytes_this_page = min(bytes_this_page,
datalen);
bytes_this_seg += bytes_this_page;
datalen -= bytes_this_page;
/* get more ready for the next page */
thiskv = (thiskv & ~PGOFSET) + NBPG;
if (datalen)
thisphys = KVTOPHYS(thiskv);
}
/*
* next page isn't contiguous, finish the seg
*/
SC_DEBUGN(sc_link, SDEV_DB4,
("(0x%x)", bytes_this_seg));
sg->seg_len = bytes_this_seg;
sg++;
seg++;
}
error = bus_dmamap_load(sc->sc_dmat,
ecb->dmamap_xfer, xs->data, xs->datalen, NULL,
(flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
}
/*end of iov/kv decision */
SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
if (datalen) {
/*
* there's still data, must have run out of segs!
*/
printf("%s: ahb_scsi_cmd, more than %d dma segs\n",
sc->sc_dev.dv_xname, AHB_NSEG);
if (error) {
if (error == EFBIG) {
printf("%s: ahb_scsi_cmd, more than %d"
" dma segments\n",
sc->sc_dev.dv_xname, AHB_NSEG);
} else {
printf("%s: ahb_scsi_cmd, error %d loading"
" dma map\n",
sc->sc_dev.dv_xname, error);
}
goto bad;
}
ecb->data_addr = KVTOPHYS(ecb->ahb_dma);
ecb->data_length = seg * sizeof(struct ahb_dma_seg);
bus_dmamap_sync(dmat, ecb->dmamap_xfer,
(flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
BUS_DMASYNC_PREWRITE);
/*
* Load the hardware scatter/gather map with the
* contents of the DMA map.
*/
for (seg = 0; seg < ecb->dmamap_xfer->dm_nsegs; seg++) {
ecb->ahb_dma[seg].seg_addr =
ecb->dmamap_xfer->dm_segs[seg].ds_addr;
ecb->ahb_dma[seg].seg_len =
ecb->dmamap_xfer->dm_segs[seg].ds_len;
}
ecb->data_addr = ecb->dmamap_self->dm_segs[0].ds_addr +
offsetof(struct ahb_ecb, ahb_dma);
ecb->data_length = ecb->dmamap_xfer->dm_nsegs *
sizeof(struct ahb_dma_seg);
ecb->opt1 |= ECB_S_G;
} else { /* No data xfer, use non S/G values */
ecb->data_addr = (physaddr)0;

View File

@ -1,4 +1,41 @@
/* $NetBSD: ahbreg.h,v 1.2 1996/09/01 00:54:34 mycroft Exp $ */
/* $NetBSD: ahbreg.h,v 1.3 1997/06/06 23:30:03 thorpej Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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) 1994, 1996 Charles M. Hannum. All rights reserved.
@ -215,4 +252,21 @@ struct ahb_ecb {
#define ECB_IMMED 0x04
#define ECB_IMMED_FAIL 0x08
int timeout;
/*
* DMA maps used by the ECB. These maps are created
* in ahb_init_ecb().
*/
/*
* This DMA map maps an individual ECB. This map is
* permanently loaded in ahb_init_ecb().
*/
bus_dmamap_t dmamap_self;
/*
* This DMA map maps the buffer involved in the transfer.
* Its contents are loaded into "ahb_dma" above.
*/
bus_dmamap_t dmamap_xfer;
};

View File

@ -1,4 +1,4 @@
/* $NetBSD: bha_eisa.c,v 1.7 1997/03/28 23:47:15 mycroft Exp $ */
/* $NetBSD: bha_eisa.c,v 1.8 1997/06/06 23:30:04 thorpej Exp $ */
/*
* Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
@ -127,9 +127,12 @@ bha_eisa_attach(parent, self, aux)
sc->sc_iot = iot;
sc->sc_ioh = ioh;
sc->sc_dmat = ea->ea_dmat;
if (!bha_find(iot, ioh, &bpd))
panic("bha_eisa_attach: bha_find failed");
sc->sc_dmaflags = 0;
if (eisa_intr_map(ec, bpd.sc_irq, &ih)) {
printf("%s: couldn't map interrupt (%d)\n",
sc->sc_dev.dv_xname, bpd.sc_irq);

View File

@ -1,4 +1,4 @@
/* $NetBSD: eisa.c,v 1.16 1996/12/05 01:25:36 cgd Exp $ */
/* $NetBSD: eisa.c,v 1.17 1997/06/06 23:30:06 thorpej Exp $ */
/*
* Copyright (c) 1995, 1996 Christopher G. Demetriou
@ -146,6 +146,7 @@ eisaattach(parent, self, aux)
{
struct eisabus_attach_args *eba = aux;
bus_space_tag_t iot, memt;
bus_dma_tag_t dmat;
eisa_chipset_tag_t ec;
int slot, maxnslots;
@ -155,6 +156,7 @@ eisaattach(parent, self, aux)
iot = eba->eba_iot;
memt = eba->eba_memt;
ec = eba->eba_ec;
dmat = eba->eba_dmat;
/*
* Search for and attach subdevices.
@ -172,6 +174,7 @@ eisaattach(parent, self, aux)
ea.ea_iot = iot;
ea.ea_memt = memt;
ea.ea_ec = ec;
ea.ea_dmat = dmat;
ea.ea_slot = slot;
slotaddr = EISA_SLOT_ADDR(slot);

View File

@ -1,4 +1,4 @@
/* $NetBSD: eisavar.h,v 1.10 1996/10/21 22:31:03 thorpej Exp $ */
/* $NetBSD: eisavar.h,v 1.11 1997/06/06 23:30:07 thorpej Exp $ */
/*
* Copyright (c) 1995, 1996 Christopher G. Demetriou
@ -72,6 +72,7 @@ struct eisabus_attach_args {
char *eba_busname; /* XXX should be common */
bus_space_tag_t eba_iot; /* eisa i/o space tag */
bus_space_tag_t eba_memt; /* eisa mem space tag */
bus_dma_tag_t eba_dmat; /* DMA tag */
eisa_chipset_tag_t eba_ec;
};
@ -81,6 +82,7 @@ struct eisabus_attach_args {
struct eisa_attach_args {
bus_space_tag_t ea_iot; /* eisa i/o space tag */
bus_space_tag_t ea_memt; /* eisa mem space tag */
bus_dma_tag_t ea_dmat; /* DMA tag */
eisa_chipset_tag_t ea_ec;
eisa_slot_t ea_slot;

View File

@ -1,4 +1,4 @@
/* $NetBSD: uha_eisa.c,v 1.7 1997/03/29 02:32:30 mycroft Exp $ */
/* $NetBSD: uha_eisa.c,v 1.8 1997/06/06 23:30:09 thorpej Exp $ */
/*
* Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
@ -52,7 +52,11 @@
#define UHA_EISA_SLOT_OFFSET 0xc80
#define UHA_EISA_IOSIZE 0x020
#ifdef __BROKEN_INDIRECT_CONFIG
int uha_eisa_match __P((struct device *, void *, void *));
#else
int uha_eisa_match __P((struct device *, struct cfdata *, void *));
#endif
void uha_eisa_attach __P((struct device *, struct device *, void *));
struct cfattach uha_eisa_ca = {
@ -62,7 +66,6 @@ struct cfattach uha_eisa_ca = {
#ifndef DDB
#define Debugger() panic("should call debugger here (uha_eisa.c)")
#endif /* ! DDB */
#define KVTOPHYS(x) vtophys(x)
int u24_find __P((bus_space_tag_t, bus_space_handle_t,
struct uha_probe_data *));
@ -79,7 +82,12 @@ void u24_init __P((struct uha_softc *));
int
uha_eisa_match(parent, match, aux)
struct device *parent;
void *match, *aux;
#ifdef __BROKEN_INDIRECT_CONFIG
void *match;
#else
struct cfdata *match;
#endif
void *aux;
{
struct eisa_attach_args *ea = aux;
bus_space_tag_t iot = ea->ea_iot;
@ -112,6 +120,7 @@ uha_eisa_attach(parent, self, aux)
struct eisa_attach_args *ea = aux;
struct uha_softc *sc = (void *)self;
bus_space_tag_t iot = ea->ea_iot;
bus_dma_tag_t dmat = ea->ea_dmat;
bus_space_handle_t ioh;
struct uha_probe_data upd;
eisa_chipset_tag_t ec = ea->ea_ec;
@ -130,9 +139,12 @@ uha_eisa_attach(parent, self, aux)
sc->sc_iot = iot;
sc->sc_ioh = ioh;
sc->sc_dmat = dmat;
if (!u24_find(iot, ioh, &upd))
panic("uha_eisa_attach: u24_find failed!");
sc->sc_dmaflags = 0;
if (eisa_intr_map(ec, upd.sc_irq, &ih)) {
printf("%s: couldn't map interrupt (%d)\n",
sc->sc_dev.dv_xname, upd.sc_irq);
@ -239,7 +251,8 @@ u24_start_mbox(sc, mscp)
Debugger();
}
bus_space_write_4(iot, ioh, U24_OGMPTR, KVTOPHYS(mscp));
bus_space_write_4(iot, ioh, U24_OGMPTR,
mscp->dmamap_self->dm_segs[0].ds_addr);
if (mscp->flags & MSCP_ABORT)
bus_space_write_1(iot, ioh, U24_OGMCMD, 0x80);
else

View File

@ -1,4 +1,4 @@
/* $NetBSD: aha.c,v 1.4 1997/03/28 23:47:08 mycroft Exp $ */
/* $NetBSD: aha.c,v 1.5 1997/06/06 23:30:58 thorpej Exp $ */
#undef AHADIAG
#ifdef DDB
@ -7,6 +7,43 @@
#define integrate static inline
#endif
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
*
@ -76,7 +113,7 @@
#define Debugger() panic("should call debugger here (aha1542.c)")
#endif /* ! DDB */
#define KVTOPHYS(x) vtophys(x)
#define AHA_MAXXFER ((AHA_NSEG - 1) << PGSHIFT)
#ifdef AHADEBUG
int aha_debug = 1;
@ -100,6 +137,7 @@ void ahaminphys __P((struct buf *));
int aha_scsi_cmd __P((struct scsi_xfer *));
int aha_poll __P((struct aha_softc *, struct scsi_xfer *, int));
void aha_timeout __P((void *arg));
int aha_create_ccbs __P((struct aha_softc *, void *, size_t));
struct scsi_adapter aha_switch = {
aha_scsi_cmd,
@ -123,6 +161,9 @@ struct cfdriver aha_cd = {
#define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
#define AHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
/* XXX Should put this in a better place. */
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
/*
* aha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf)
*
@ -261,11 +302,12 @@ aha_attach(sc, apd)
struct aha_probe_data *apd;
{
aha_inquire_setup_information(sc);
aha_init(sc);
TAILQ_INIT(&sc->sc_free_ccb);
TAILQ_INIT(&sc->sc_waiting_ccb);
aha_inquire_setup_information(sc);
aha_init(sc);
/*
* fill in the prototype scsi_link.
*/
@ -458,20 +500,92 @@ aha_init_ccb(sc, ccb)
struct aha_softc *sc;
struct aha_ccb *ccb;
{
bus_dma_tag_t dmat = sc->sc_dmat;
int hashnum;
/*
* XXX Should we put a DIAGNOSTIC check for multiple
* XXX CCB inits here?
*/
bzero(ccb, sizeof(struct aha_ccb));
/*
* Create DMA maps for this CCB.
*/
if (bus_dmamap_create(dmat, sizeof(struct aha_ccb), 1,
sizeof(struct aha_ccb), 0, BUS_DMA_NOWAIT, &ccb->dmamap_self) ||
/* XXX What's a good value for this? */
bus_dmamap_create(dmat, AHA_MAXXFER, AHA_NSEG, AHA_MAXXFER,
0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &ccb->dmamap_xfer))
panic("aha_init_ccb: can't create DMA maps");
/*
* Load the permanent DMA maps.
*/
if (bus_dmamap_load(dmat, ccb->dmamap_self, ccb,
sizeof(struct aha_ccb), NULL, BUS_DMA_NOWAIT))
panic("aha_init_ccb: can't load permanent maps");
/*
* put in the phystokv hash table
* Never gets taken out.
*/
ccb->hashkey = KVTOPHYS(ccb);
ccb->hashkey = ccb->dmamap_self->dm_segs[0].ds_addr;
hashnum = CCB_HASH(ccb->hashkey);
ccb->nexthash = sc->sc_ccbhash[hashnum];
sc->sc_ccbhash[hashnum] = ccb;
aha_reset_ccb(sc, ccb);
}
/*
* Create a set of ccbs and add them to the free list.
*/
int
aha_create_ccbs(sc, mem, size)
struct aha_softc *sc;
void *mem;
size_t size;
{
bus_dma_segment_t seg;
struct aha_ccb *ccb;
int rseg, error;
if (sc->sc_numccbs >= AHA_CCB_MAX)
return (0);
if ((ccb = mem) != NULL)
goto have_mem;
size = NBPG;
error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg,
BUS_DMA_NOWAIT);
if (error)
return (error);
error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
(caddr_t *)&ccb, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC);
if (error) {
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
return (error);
}
have_mem:
bzero(ccb, size);
while (size > sizeof(struct aha_ccb)) {
aha_init_ccb(sc, ccb);
sc->sc_numccbs++;
if (sc->sc_numccbs >= AHA_CCB_MAX)
break;
TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain);
(caddr_t)ccb += ALIGN(sizeof(struct aha_ccb));
size -= ALIGN(sizeof(struct aha_ccb));
}
return (0);
}
/*
* Get a free ccb
*
@ -499,16 +613,12 @@ aha_get_ccb(sc, flags)
break;
}
if (sc->sc_numccbs < AHA_CCB_MAX) {
ccb = (struct aha_ccb *) malloc(sizeof(struct aha_ccb),
M_TEMP, M_NOWAIT);
if (!ccb) {
printf("%s: can't malloc ccb\n",
if (aha_create_ccbs(sc, NULL, 0)) {
printf("%s: can't allocate ccbs\n",
sc->sc_dev.dv_xname);
goto out;
}
aha_init_ccb(sc, ccb);
sc->sc_numccbs++;
break;
continue;
}
if ((flags & SCSI_NOSLEEP) != 0)
goto out;
@ -619,7 +729,7 @@ aha_start_ccbs(sc)
#endif
/* Link ccb to mbo. */
ltophys(KVTOPHYS(ccb), wmbo->ccb_addr);
ltophys(ccb->dmamap_self->dm_segs[0].ds_addr, wmbo->ccb_addr);
if (ccb->flags & CCB_ABORT)
wmbo->cmd = AHA_MBO_ABORT;
else
@ -648,10 +758,23 @@ aha_done(sc, ccb)
struct aha_softc *sc;
struct aha_ccb *ccb;
{
bus_dma_tag_t dmat = sc->sc_dmat;
struct scsi_sense_data *s1, *s2;
struct scsi_xfer *xs = ccb->xs;
SC_DEBUG(xs->sc_link, SDEV_DB2, ("aha_done\n"));
/*
* If we were a data transfer, unload the map that described
* the data buffer.
*/
if (xs->datalen) {
bus_dmamap_sync(dmat, ccb->dmamap_xfer,
(xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(dmat, ccb->dmamap_xfer);
}
/*
* Otherwise, put the results of the operation
* into the xfer and call whoever started it
@ -814,10 +937,11 @@ aha_init(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
bus_dma_segment_t seg;
struct aha_devices devices;
struct aha_setup setup;
struct aha_mailbox mailbox;
int i;
int i, rseg;
/*
* XXX
@ -885,6 +1009,33 @@ aha_init(sc)
setup.reply.sync[i].offset, setup.reply.sync[i].period * 50 + 200);
}
/*
* Allocate the mailbox.
*/
if (bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1,
&rseg, BUS_DMA_NOWAIT) ||
bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
(caddr_t *)&wmbx, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC))
panic("aha_init: can't create or map mailbox");
/*
* Since DMA memory allocation is always rounded up to a
* page size, create some ccbs from the leftovers.
*/
if (aha_create_ccbs(sc, ((caddr_t)wmbx) +
ALIGN(sizeof(struct aha_mbx)),
NBPG - ALIGN(sizeof(struct aha_mbx))))
panic("aha_init: can't create ccbs");
/*
* Create and load the mailbox DMA map.
*/
if (bus_dmamap_create(sc->sc_dmat, sizeof(struct aha_mbx), 1,
sizeof(struct aha_mbx), 0, BUS_DMA_NOWAIT, &sc->sc_dmamap_mbox) ||
bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_mbox, wmbx,
sizeof(struct aha_mbx), NULL, BUS_DMA_NOWAIT))
panic("aha_init: can't create or load mailbox dma map");
/*
* Set up initial mail box for round-robin operation.
*/
@ -899,7 +1050,7 @@ aha_init(sc)
/* Initialize mail box. */
mailbox.cmd.opcode = AHA_MBX_INIT;
mailbox.cmd.nmbx = AHA_MBX_SIZE;
ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr);
ltophys(sc->sc_dmamap_mbox->dm_segs[0].ds_addr, mailbox.cmd.addr);
aha_cmd(iot, ioh, sc,
sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
0, (u_char *)0);
@ -996,8 +1147,8 @@ ahaminphys(bp)
struct buf *bp;
{
if (bp->b_bcount > ((AHA_NSEG - 1) << PGSHIFT))
bp->b_bcount = ((AHA_NSEG - 1) << PGSHIFT);
if (bp->b_bcount > AHA_MAXXFER)
bp->b_bcount = AHA_MAXXFER;
minphys(bp);
}
@ -1011,15 +1162,9 @@ aha_scsi_cmd(xs)
{
struct scsi_link *sc_link = xs->sc_link;
struct aha_softc *sc = sc_link->adapter_softc;
bus_dma_tag_t dmat = sc->sc_dmat;
struct aha_ccb *ccb;
struct aha_scat_gath *sg;
int seg; /* scatter gather seg being worked on */
u_long thiskv, thisphys, nextphys;
int bytes_this_seg, bytes_this_page, datalen, flags;
#ifdef TFS
struct iovec *iovp;
#endif
int s;
int error, seg, flags, s;
SC_DEBUG(sc_link, SDEV_DB2, ("aha_scsi_cmd\n"));
/*
@ -1050,97 +1195,60 @@ aha_scsi_cmd(xs)
}
if (xs->datalen) {
sg = ccb->scat_gath;
seg = 0;
#ifdef TFS
/*
* Map the DMA transfer.
*/
#ifdef TFS
if (flags & SCSI_DATA_UIO) {
iovp = ((struct uio *)xs->data)->uio_iov;
datalen = ((struct uio *)xs->data)->uio_iovcnt;
xs->datalen = 0;
while (datalen && seg < AHA_NSEG) {
ltophys(iovp->iov_base, sg->seg_addr);
ltophys(iovp->iov_len, sg->seg_len);
xs->datalen += iovp->iov_len;
SC_DEBUGN(sc_link, SDEV_DB4, ("UIO(0x%x@0x%x)",
iovp->iov_len, iovp->iov_base));
sg++;
iovp++;
seg++;
datalen--;
}
error = bus_dmamap_load_uio(dmat,
ccb->dmamap_xfer, (struct uio *)xs->data,
(flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
} else
#endif /* TFS */
#endif
{
/*
* Set up the scatter-gather block.
*/
SC_DEBUG(sc_link, SDEV_DB4,
("%d @0x%x:- ", xs->datalen, xs->data));
datalen = xs->datalen;
thiskv = (int)xs->data;
thisphys = KVTOPHYS(thiskv);
while (datalen && seg < AHA_NSEG) {
bytes_this_seg = 0;
/* put in the base address */
ltophys(thisphys, sg->seg_addr);
SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
/* do it at least once */
nextphys = thisphys;
while (datalen && thisphys == nextphys) {
/*
* This page is contiguous (physically)
* with the the last, just extend the
* length
*/
/* check it fits on the ISA bus */
if (thisphys > 0xFFFFFF) {
printf("%s: DMA beyond"
" end of ISA\n",
sc->sc_dev.dv_xname);
goto bad;
}
/* how far to the end of the page */
nextphys = (thisphys & ~PGOFSET) + NBPG;
bytes_this_page = nextphys - thisphys;
/**** or the data ****/
bytes_this_page = min(bytes_this_page,
datalen);
bytes_this_seg += bytes_this_page;
datalen -= bytes_this_page;
/* get more ready for the next page */
thiskv = (thiskv & ~PGOFSET) + NBPG;
if (datalen)
thisphys = KVTOPHYS(thiskv);
}
/*
* next page isn't contiguous, finish the seg
*/
SC_DEBUGN(sc_link, SDEV_DB4,
("(0x%x)", bytes_this_seg));
ltophys(bytes_this_seg, sg->seg_len);
sg++;
seg++;
}
error = bus_dmamap_load(dmat,
ccb->dmamap_xfer, xs->data, xs->datalen, NULL,
(flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
}
/* end of iov/kv decision */
SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
if (datalen) {
/*
* there's still data, must have run out of segs!
*/
printf("%s: aha_scsi_cmd, more than %d dma segs\n",
sc->sc_dev.dv_xname, AHA_NSEG);
if (error) {
if (error == EFBIG) {
printf("%s: aha_scsi_cmd, more than %d"
" dma segments\n",
sc->sc_dev.dv_xname, AHA_NSEG);
} else {
printf("%s: aha_scsi_cmd, error %d loading"
" dma map\n",
sc->sc_dev.dv_xname, error);
}
goto bad;
}
ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
ltophys(seg * sizeof(struct aha_scat_gath), ccb->data_length);
} else { /* No data xfer, use non S/G values */
bus_dmamap_sync(dmat, ccb->dmamap_xfer,
(flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
BUS_DMASYNC_PREWRITE);
/*
* Load the hardware scatter/gather map with the
* contents of the DMA map.
*/
for (seg = 0; seg < ccb->dmamap_xfer->dm_nsegs; seg++) {
ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_addr,
ccb->scat_gath[seg].seg_addr);
ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_len,
ccb->scat_gath[seg].seg_len);
}
ltophys(ccb->dmamap_self->dm_segs[0].ds_addr +
offsetof(struct aha_ccb, scat_gath), ccb->data_addr);
ltophys(ccb->dmamap_xfer->dm_nsegs *
sizeof(struct aha_scat_gath), ccb->data_length);
} else {
/*
* No data xfer, use non S/G values.
*/
ltophys(0, ccb->data_addr);
ltophys(0, ccb->data_length);
}

View File

@ -1,4 +1,41 @@
/* $NetBSD: ahareg.h,v 1.2 1997/03/15 18:11:23 is Exp $ */
/* $NetBSD: ahareg.h,v 1.3 1997/06/06 23:30:59 thorpej Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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) 1994, 1996 Charles M. Hannum. All rights reserved.
@ -174,6 +211,23 @@ struct aha_ccb {
#define CCB_SENDING 0x04
#endif
int timeout;
/*
* DMA maps used by the CCB. These maps are created
* in aha_init_ccb().
*/
/*
* This DMA map maps an individual CCB. This map is permanently
* loaded in aha_init_ccb().
*/
bus_dmamap_t dmamap_self;
/*
* This DMA map maps the buffer involved in the transfer.
* Its contents are loaded into "scat_gath" above.
*/
bus_dmamap_t dmamap_xfer;
};
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: ahavar.h,v 1.3 1997/03/28 23:47:10 mycroft Exp $ */
/* $NetBSD: ahavar.h,v 1.4 1997/06/06 23:31:00 thorpej Exp $ */
/*
* Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
@ -59,10 +59,12 @@ struct aha_softc {
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
bus_dmamap_t sc_dmamap_mbox; /* maps the mailbox */
void *sc_ih;
struct aha_mbx sc_mbx; /* all our mailboxes */
#define wmbx (&sc->sc_mbx)
struct aha_mbx *sc_mbx; /* all our mailboxes */
#define wmbx (sc->sc_mbx)
struct aha_ccb *sc_ccbhash[CCB_HASH_SIZE];
TAILQ_HEAD(, aha_ccb) sc_free_ccb, sc_waiting_ccb;
int sc_numccbs, sc_mbofull;

View File

@ -1,4 +1,4 @@
/* $NetBSD: bha.c,v 1.12 1997/04/11 01:34:25 thorpej Exp $ */
/* $NetBSD: bha.c,v 1.13 1997/06/06 23:31:01 thorpej Exp $ */
#undef BHADIAG
#ifdef DDB
@ -7,6 +7,43 @@
#define integrate static inline
#endif
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
*
@ -76,14 +113,7 @@
#define Debugger() panic("should call debugger here (bha.c)")
#endif /* ! DDB */
#ifdef alpha /* XXX */
/* XXX XXX NEED REAL DMA MAPPING SUPPORT XXX XXX */
extern vm_offset_t alpha_XXX_dmamap(vm_offset_t);
#undef vtophys
#define vtophys(va) alpha_XXX_dmamap((vm_offset_t) va)
#endif /* alpha */
#define KVTOPHYS(x) vtophys(x)
#define BHA_MAXXFER ((BHA_NSEG - 1) << PGSHIFT)
#ifdef BHADEBUG
int bha_debug = 0;
@ -102,11 +132,11 @@ void bha_collect_mbo __P((struct bha_softc *));
void bha_start_ccbs __P((struct bha_softc *));
void bha_done __P((struct bha_softc *, struct bha_ccb *));
void bha_init __P((struct bha_softc *));
void bha_inquire_setup_information __P((struct bha_softc *));
void bhaminphys __P((struct buf *));
int bha_scsi_cmd __P((struct scsi_xfer *));
int bha_poll __P((struct bha_softc *, struct scsi_xfer *, int));
void bha_timeout __P((void *arg));
int bha_create_ccbs __P((struct bha_softc *, void *, size_t));
struct scsi_adapter bha_switch = {
bha_scsi_cmd,
@ -130,6 +160,9 @@ struct cfdriver bha_cd = {
#define BHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
#define BHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
/* XXX Should put this in a better place. */
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
/*
* bha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf)
*
@ -287,11 +320,16 @@ bha_attach(sc, bpd)
sc->sc_link.openings = 4;
sc->sc_link.max_target = bpd->sc_iswide ? 15 : 7;
bha_inquire_setup_information(sc);
bha_init(sc);
TAILQ_INIT(&sc->sc_free_ccb);
TAILQ_INIT(&sc->sc_waiting_ccb);
bha_inquire_setup_information(sc);
printf("%s: model BT-%s, firmware %s\n", sc->sc_dev.dv_xname,
sc->sc_model, sc->sc_firmware);
bha_init(sc);
/*
* ask the adapter what subunits are present
*/
@ -473,20 +511,94 @@ bha_init_ccb(sc, ccb)
struct bha_softc *sc;
struct bha_ccb *ccb;
{
bus_dma_tag_t dmat = sc->sc_dmat;
int hashnum;
/*
* XXX Should we put a DIAGNOSTIC check for multiple
* XXX CCB inits here?
*/
bzero(ccb, sizeof(struct bha_ccb));
/*
* Create DMA maps for this CCB.
*/
if (bus_dmamap_create(dmat, sizeof(struct bha_ccb), 1,
sizeof(struct bha_ccb), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags,
&ccb->dmamap_self) ||
/* XXX What's a good value for this? */
bus_dmamap_create(dmat, BHA_MAXXFER, BHA_NSEG, BHA_MAXXFER,
0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags,
&ccb->dmamap_xfer))
panic("bha_init_ccb: can't create DMA maps");
/*
* Load the permanent DMA maps.
*/
if (bus_dmamap_load(dmat, ccb->dmamap_self, ccb,
sizeof(struct bha_ccb), NULL, BUS_DMA_NOWAIT))
panic("bha_init_ccb: can't load permanent maps");
/*
* put in the phystokv hash table
* Never gets taken out.
*/
ccb->hashkey = KVTOPHYS(ccb);
ccb->hashkey = ccb->dmamap_self->dm_segs[0].ds_addr;
hashnum = CCB_HASH(ccb->hashkey);
ccb->nexthash = sc->sc_ccbhash[hashnum];
sc->sc_ccbhash[hashnum] = ccb;
bha_reset_ccb(sc, ccb);
}
/*
* Create a set of ccbs and add them to the free list.
*/
int
bha_create_ccbs(sc, mem, size)
struct bha_softc *sc;
void *mem;
size_t size;
{
bus_dma_segment_t seg;
struct bha_ccb *ccb;
int rseg, error;
if (sc->sc_numccbs >= BHA_CCB_MAX)
return (0);
if ((ccb = mem) != NULL)
goto have_mem;
size = NBPG;
error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg,
BUS_DMA_NOWAIT);
if (error)
return (error);
error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
(caddr_t *)&ccb, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC);
if (error) {
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
return (error);
}
have_mem:
bzero(ccb, size);
while (size > sizeof(struct bha_ccb)) {
bha_init_ccb(sc, ccb);
sc->sc_numccbs++;
if (sc->sc_numccbs >= BHA_CCB_MAX)
break;
TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain);
(caddr_t)ccb += ALIGN(sizeof(struct bha_ccb));
size -= ALIGN(sizeof(struct bha_ccb));
}
return (0);
}
/*
* Get a free ccb
*
@ -514,16 +626,12 @@ bha_get_ccb(sc, flags)
break;
}
if (sc->sc_numccbs < BHA_CCB_MAX) {
ccb = (struct bha_ccb *) malloc(sizeof(struct bha_ccb),
M_TEMP, M_NOWAIT);
if (!ccb) {
printf("%s: can't malloc ccb\n",
if (bha_create_ccbs(sc, NULL, 0)) {
printf("%s: can't allocate ccbs\n",
sc->sc_dev.dv_xname);
goto out;
}
bha_init_ccb(sc, ccb);
sc->sc_numccbs++;
break;
continue;
}
if ((flags & SCSI_NOSLEEP) != 0)
goto out;
@ -634,7 +742,7 @@ bha_start_ccbs(sc)
#endif
/* Link ccb to mbo. */
ltophys(KVTOPHYS(ccb), wmbo->ccb_addr);
ltophys(ccb->dmamap_self->dm_segs[0].ds_addr, wmbo->ccb_addr);
if (ccb->flags & CCB_ABORT)
wmbo->cmd = BHA_MBO_ABORT;
else
@ -663,10 +771,23 @@ bha_done(sc, ccb)
struct bha_softc *sc;
struct bha_ccb *ccb;
{
bus_dma_tag_t dmat = sc->sc_dmat;
struct scsi_sense_data *s1, *s2;
struct scsi_xfer *xs = ccb->xs;
SC_DEBUG(xs->sc_link, SDEV_DB2, ("bha_done\n"));
/*
* If we were a data transfer, unload the map that described
* the data buffer.
*/
if (xs->datalen) {
bus_dmamap_sync(dmat, ccb->dmamap_xfer,
(xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(dmat, ccb->dmamap_xfer);
}
/*
* Otherwise, put the results of the operation
* into the xfer and call whoever started it
@ -921,11 +1042,12 @@ bha_init(sc)
{
bus_space_tag_t iot = sc->sc_iot;
bus_space_handle_t ioh = sc->sc_ioh;
bus_dma_segment_t seg;
struct bha_devices devices;
struct bha_setup setup;
struct bha_mailbox mailbox;
struct bha_period period;
int i, rlen;
int i, rlen, rseg;
/* Enable round-robin scheme - appeared at firmware rev. 3.31. */
if (strcmp(sc->sc_firmware, "3.31") >= 0) {
@ -1014,6 +1136,34 @@ bha_init(sc)
}
}
/*
* Allocate the mailbox.
*/
if (bus_dmamem_alloc(sc->sc_dmat, NBPG, NBPG, 0, &seg, 1,
&rseg, BUS_DMA_NOWAIT) ||
bus_dmamem_map(sc->sc_dmat, &seg, rseg, NBPG,
(caddr_t *)&wmbx, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC))
panic("bha_init: can't create or map mailbox");
/*
* Since DMA memory allocation is always rounded up to a
* page size, create some ccbs from the leftovers.
*/
if (bha_create_ccbs(sc, ((caddr_t)wmbx) +
ALIGN(sizeof(struct bha_mbx)),
NBPG - ALIGN(sizeof(struct bha_mbx))))
panic("bha_init: can't create ccbs");
/*
* Create and load the mailbox DMA map.
*/
if (bus_dmamap_create(sc->sc_dmat, sizeof(struct bha_mbx), 1,
sizeof(struct bha_mbx), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags,
&sc->sc_dmamap_mbox) ||
bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_mbox, wmbx,
sizeof(struct bha_mbx), NULL, BUS_DMA_NOWAIT))
panic("bha_init: can't create or load mailbox dma map");
/*
* Set up initial mail box for round-robin operation.
*/
@ -1028,7 +1178,7 @@ bha_init(sc)
/* Initialize mail box. */
mailbox.cmd.opcode = BHA_MBX_INIT_EXTENDED;
mailbox.cmd.nmbx = BHA_MBX_SIZE;
ltophys(KVTOPHYS(wmbx), mailbox.cmd.addr);
ltophys(sc->sc_dmamap_mbox->dm_segs[0].ds_addr, mailbox.cmd.addr);
bha_cmd(iot, ioh, sc,
sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
0, (u_char *)0);
@ -1097,9 +1247,6 @@ bha_inquire_setup_information(sc)
*p = '\0';
} else
strcpy(sc->sc_model, "542B");
printf("%s: model BT-%s, firmware %s\n", sc->sc_dev.dv_xname,
sc->sc_model, sc->sc_firmware);
}
void
@ -1107,8 +1254,8 @@ bhaminphys(bp)
struct buf *bp;
{
if (bp->b_bcount > ((BHA_NSEG - 1) << PGSHIFT))
bp->b_bcount = ((BHA_NSEG - 1) << PGSHIFT);
if (bp->b_bcount > BHA_MAXXFER)
bp->b_bcount = BHA_MAXXFER;
minphys(bp);
}
@ -1122,15 +1269,9 @@ bha_scsi_cmd(xs)
{
struct scsi_link *sc_link = xs->sc_link;
struct bha_softc *sc = sc_link->adapter_softc;
bus_dma_tag_t dmat = sc->sc_dmat;
struct bha_ccb *ccb;
struct bha_scat_gath *sg;
int seg; /* scatter gather seg being worked on */
u_long thiskv, thisphys, nextphys;
int bytes_this_seg, bytes_this_page, datalen, flags;
#ifdef TFS
struct iovec *iovp;
#endif
int s;
int error, seg, flags, s;
SC_DEBUG(sc_link, SDEV_DB2, ("bha_scsi_cmd\n"));
/*
@ -1161,92 +1302,60 @@ bha_scsi_cmd(xs)
}
if (xs->datalen) {
sg = ccb->scat_gath;
seg = 0;
#ifdef TFS
/*
* Map the DMA transfer.
*/
#ifdef TFS
if (flags & SCSI_DATA_UIO) {
iovp = ((struct uio *)xs->data)->uio_iov;
datalen = ((struct uio *)xs->data)->uio_iovcnt;
xs->datalen = 0;
while (datalen && seg < BHA_NSEG) {
ltophys(iovp->iov_base, sg->seg_addr);
ltophys(iovp->iov_len, sg->seg_len);
xs->datalen += iovp->iov_len;
SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)",
iovp->iov_len, iovp->iov_base));
sg++;
iovp++;
seg++;
datalen--;
}
error = bus_dmamap_load_uio(dmat,
ccb->dmamap_xfer, (struct uio *)xs->data,
(flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
} else
#endif /* TFS */
#endif /* TFS */
{
/*
* Set up the scatter-gather block.
*/
SC_DEBUG(sc_link, SDEV_DB4,
("%d @0x%x:- ", xs->datalen, xs->data));
datalen = xs->datalen;
thiskv = (u_long)xs->data;
thisphys = KVTOPHYS(thiskv);
while (datalen && seg < BHA_NSEG) {
bytes_this_seg = 0;
/* put in the base address */
ltophys(thisphys, sg->seg_addr);
SC_DEBUGN(sc_link, SDEV_DB4,
("0x%x", thisphys));
/* do it at least once */
nextphys = thisphys;
while (datalen && thisphys == nextphys) {
/*
* This page is contiguous (physically)
* with the the last, just extend the
* length
*/
/* how far to the end of the page */
nextphys =
(thisphys & ~PGOFSET) + NBPG;
bytes_this_page = nextphys - thisphys;
/**** or the data ****/
bytes_this_page = min(bytes_this_page,
datalen);
bytes_this_seg += bytes_this_page;
datalen -= bytes_this_page;
/* get more ready for the next page */
thiskv = (thiskv & ~PGOFSET) + NBPG;
if (datalen)
thisphys = KVTOPHYS(thiskv);
}
/*
* next page isn't contiguous, finish the seg
*/
SC_DEBUGN(sc_link, SDEV_DB4,
("(0x%x)", bytes_this_seg));
ltophys(bytes_this_seg, sg->seg_len);
sg++;
seg++;
}
error = bus_dmamap_load(dmat,
ccb->dmamap_xfer, xs->data, xs->datalen, NULL,
(flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
}
/* end of iov/kv decision */
SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
if (datalen) {
/*
* there's still data, must have run out of segs!
*/
printf("%s: bha_scsi_cmd, more than %d dma segs\n",
sc->sc_dev.dv_xname, BHA_NSEG);
if (error) {
if (error == EFBIG) {
printf("%s: bha_scsi_cmd, more than %d"
" dma segments\n",
sc->sc_dev.dv_xname, BHA_NSEG);
} else {
printf("%s: bha_scsi_cmd, error %d loading"
" dma map\n",
sc->sc_dev.dv_xname, error);
}
goto bad;
}
ltophys(KVTOPHYS(ccb->scat_gath), ccb->data_addr);
ltophys(seg * sizeof(struct bha_scat_gath), ccb->data_length);
} else { /* No data xfer, use non S/G values */
bus_dmamap_sync(dmat, ccb->dmamap_xfer,
(flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
BUS_DMASYNC_PREWRITE);
/*
* Load the hardware scatter/gather map with the
* contents of the DMA map.
*/
for (seg = 0; seg < ccb->dmamap_xfer->dm_nsegs; seg++) {
ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_addr,
ccb->scat_gath[seg].seg_addr);
ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_len,
ccb->scat_gath[seg].seg_len);
}
ltophys(ccb->dmamap_self->dm_segs[0].ds_addr +
offsetof(struct bha_ccb, scat_gath), ccb->data_addr);
ltophys(ccb->dmamap_xfer->dm_nsegs *
sizeof(struct bha_scat_gath), ccb->data_length);
} else {
/*
* No data xfer, use non S/G values.
*/
ltophys(0, ccb->data_addr);
ltophys(0, ccb->data_length);
}
@ -1255,7 +1364,8 @@ bha_scsi_cmd(xs)
ccb->data_in = 0;
ccb->target = sc_link->target;
ccb->lun = sc_link->lun;
ltophys(KVTOPHYS(&ccb->scsi_sense), ccb->sense_ptr);
ltophys(ccb->dmamap_self->dm_segs[0].ds_addr +
offsetof(struct bha_ccb, scsi_sense), ccb->sense_ptr);
ccb->req_sense_length = sizeof(ccb->scsi_sense);
ccb->host_stat = 0x00;
ccb->target_stat = 0x00;

View File

@ -1,4 +1,41 @@
/* $NetBSD: bhareg.h,v 1.6 1997/01/04 16:47:03 jonathan Exp $ */
/* $NetBSD: bhareg.h,v 1.7 1997/06/06 23:31:03 thorpej Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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) 1994, 1996 Charles M. Hannum. All rights reserved.
@ -199,6 +236,23 @@ struct bha_ccb {
#define CCB_SENDING 0x04
#endif
int timeout;
/*
* DMA maps used by the CCB. These maps are created
* in bha_init_ccb().
*/
/*
* This DMA map maps an individual CCB. This map is
* permanently loaded in bha_init_ccb().
*/
bus_dmamap_t dmamap_self;
/*
* This DMA map maps the buffer involved in the transfer.
* Its contents are loaded into "scat_gath" above.
*/
bus_dmamap_t dmamap_xfer;
};
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: bhavar.h,v 1.6 1997/03/28 23:47:11 mycroft Exp $ */
/* $NetBSD: bhavar.h,v 1.7 1997/06/06 23:31:04 thorpej Exp $ */
/*
* Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
@ -59,10 +59,13 @@ struct bha_softc {
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
bus_dmamap_t sc_dmamap_mbox; /* maps the mailbox */
int sc_dmaflags; /* bus-specific dma map flags */
void *sc_ih;
struct bha_mbx sc_mbx; /* all our mailboxes */
#define wmbx (&sc->sc_mbx)
struct bha_mbx *sc_mbx; /* all our mailboxes */
#define wmbx (sc->sc_mbx)
struct bha_ccb *sc_ccbhash[CCB_HASH_SIZE];
TAILQ_HEAD(, bha_ccb) sc_free_ccb, sc_waiting_ccb;
int sc_numccbs, sc_mbofull;
@ -86,3 +89,4 @@ void bha_attach __P((struct bha_softc *, struct bha_probe_data *));
int bha_intr __P((void *));
int bha_disable_isacompat __P((struct bha_softc *));
void bha_inquire_setup_information __P((struct bha_softc *));

View File

@ -1,4 +1,4 @@
/* $NetBSD: uha.c,v 1.7 1997/03/29 02:32:31 mycroft Exp $ */
/* $NetBSD: uha.c,v 1.8 1997/06/06 23:31:05 thorpej Exp $ */
#undef UHADEBUG
#ifdef DDB
@ -7,6 +7,43 @@
#define integrate static inline
#endif
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
*
@ -83,7 +120,7 @@
#define Debugger() panic("should call debugger here (uha.c)")
#endif /* ! DDB */
#define KVTOPHYS(x) vtophys(x)
#define UHA_MAXXFER ((UHA_NSEG - 1) << PGSHIFT)
integrate void uha_reset_mscp __P((struct uha_softc *, struct uha_mscp *));
void uha_free_mscp __P((struct uha_softc *, struct uha_mscp *));
@ -91,6 +128,7 @@ integrate void uha_init_mscp __P((struct uha_softc *, struct uha_mscp *));
struct uha_mscp *uha_get_mscp __P((struct uha_softc *, int));
void uhaminphys __P((struct buf *));
int uha_scsi_cmd __P((struct scsi_xfer *));
int uha_create_mscps __P((struct uha_softc *, void *, size_t));
struct scsi_adapter uha_switch = {
uha_scsi_cmd,
@ -113,6 +151,9 @@ struct cfdriver uha_cd = {
#define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
/* XXX Should put this in a better place. */
#define offsetof(type, member) ((size_t)(&((type *)0)->member))
/*
* Attach all the sub-devices we can find
*/
@ -122,9 +163,10 @@ uha_attach(sc, upd)
struct uha_probe_data *upd;
{
(sc->init)(sc);
TAILQ_INIT(&sc->sc_free_mscp);
(sc->init)(sc);
/*
* fill in the prototype scsi_link.
*/
@ -181,20 +223,94 @@ uha_init_mscp(sc, mscp)
struct uha_softc *sc;
struct uha_mscp *mscp;
{
bus_dma_tag_t dmat = sc->sc_dmat;
int hashnum;
/*
* XXX Should we put a DIAGNOSTIC check for multiple
* XXX MSCP inits here?
*/
bzero(mscp, sizeof(struct uha_mscp));
/*
* Create the DMA maps for this MSCP.
*/
if (bus_dmamap_create(dmat, sizeof(struct uha_mscp), 1,
sizeof(struct uha_mscp), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags,
&mscp->dmamap_self) ||
/* XXX What's a good value for this? */
bus_dmamap_create(dmat, UHA_MAXXFER, UHA_NSEG, UHA_MAXXFER,
0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags,
&mscp->dmamap_xfer))
panic("uha_init_mscp: can't create DMA maps");
/*
* Load the permanent DMA maps.
*/
if (bus_dmamap_load(dmat, mscp->dmamap_self, mscp,
sizeof(struct uha_mscp), NULL, BUS_DMA_NOWAIT))
panic("uha_init_mscp: can't load permanent maps");
/*
* put in the phystokv hash table
* Never gets taken out.
*/
mscp->hashkey = KVTOPHYS(mscp);
mscp->hashkey = mscp->dmamap_self->dm_segs[0].ds_addr;
hashnum = MSCP_HASH(mscp->hashkey);
mscp->nexthash = sc->sc_mscphash[hashnum];
sc->sc_mscphash[hashnum] = mscp;
uha_reset_mscp(sc, mscp);
}
/*
* Create a set of MSCPs and add them to the free list.
*/
int
uha_create_mscps(sc, mem, size)
struct uha_softc *sc;
void *mem;
size_t size;
{
bus_dma_segment_t seg;
struct uha_mscp *mscp;
int rseg, error;
if (sc->sc_nummscps >= UHA_MSCP_MAX)
return (0);
if ((mscp = mem) != NULL)
goto have_mem;
size = NBPG;
error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg,
BUS_DMA_NOWAIT);
if (error)
return (error);
error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
(caddr_t *)&mscp, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC);
if (error) {
bus_dmamem_free(sc->sc_dmat, &seg, rseg);
return (error);
}
have_mem:
bzero(mscp, size);
while (size > sizeof(struct uha_mscp)) {
uha_init_mscp(sc, mscp);
sc->sc_nummscps++;
TAILQ_INSERT_TAIL(&sc->sc_free_mscp, mscp, chain);
(caddr_t)mscp += ALIGN(sizeof(struct uha_mscp));
size -= ALIGN(sizeof(struct uha_mscp));
if (sc->sc_nummscps >= UHA_MSCP_MAX)
break;
}
return (0);
}
/*
* Get a free mscp
*
@ -222,16 +338,12 @@ uha_get_mscp(sc, flags)
break;
}
if (sc->sc_nummscps < UHA_MSCP_MAX) {
mscp = (struct uha_mscp *) malloc(sizeof(struct uha_mscp),
M_TEMP, M_NOWAIT);
if (!mscp) {
printf("%s: can't malloc mscp\n",
if (uha_create_mscps(sc, NULL, 0)) {
printf("%s: can't allocate mscps\n",
sc->sc_dev.dv_xname);
goto out;
}
uha_init_mscp(sc, mscp);
sc->sc_nummscps++;
break;
continue;
}
if ((flags & SCSI_NOSLEEP) != 0)
goto out;
@ -273,10 +385,23 @@ uha_done(sc, mscp)
struct uha_softc *sc;
struct uha_mscp *mscp;
{
bus_dma_tag_t dmat = sc->sc_dmat;
struct scsi_sense_data *s1, *s2;
struct scsi_xfer *xs = mscp->xs;
SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n"));
/*
* If we were a data transfer, unload the map that described
* the data buffer.
*/
if (xs->datalen) {
bus_dmamap_sync(dmat, mscp->dmamap_xfer,
(xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(dmat, mscp->dmamap_xfer);
}
/*
* Otherwise, put the results of the operation
* into the xfer and call whoever started it
@ -326,8 +451,8 @@ uhaminphys(bp)
struct buf *bp;
{
if (bp->b_bcount > ((UHA_NSEG - 1) << PGSHIFT))
bp->b_bcount = ((UHA_NSEG - 1) << PGSHIFT);
if (bp->b_bcount > UHA_MAXXFER)
bp->b_bcount = UHA_MAXXFER;
minphys(bp);
}
@ -341,12 +466,10 @@ uha_scsi_cmd(xs)
{
struct scsi_link *sc_link = xs->sc_link;
struct uha_softc *sc = sc_link->adapter_softc;
bus_dma_tag_t dmat = sc->sc_dmat;
struct uha_mscp *mscp;
struct uha_dma_seg *sg;
int seg; /* scatter gather seg being worked on */
u_long thiskv, thisphys, nextphys;
int bytes_this_seg, bytes_this_page, datalen, flags;
int s;
int error, seg, flags, s;
SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n"));
/*
@ -380,7 +503,8 @@ uha_scsi_cmd(xs)
mscp->target = sc_link->target;
mscp->lun = sc_link->lun;
mscp->scsi_cmd_length = xs->cmdlen;
mscp->sense_ptr = KVTOPHYS(&mscp->mscp_sense);
mscp->sense_ptr = mscp->dmamap_self->dm_segs[0].ds_addr +
offsetof(struct uha_mscp, mscp_sense);
mscp->req_sense_length = sizeof(mscp->mscp_sense);
mscp->host_stat = 0x00;
mscp->target_stat = 0x00;
@ -390,84 +514,49 @@ uha_scsi_cmd(xs)
seg = 0;
#ifdef TFS
if (flags & SCSI_DATA_UIO) {
struct iovec *iovp;
iovp = ((struct uio *) xs->data)->uio_iov;
datalen = ((struct uio *) xs->data)->uio_iovcnt;
xs->datalen = 0;
while (datalen && seg < UHA_NSEG) {
sg->seg_addr = (physaddr)iovp->iov_base;
sg->seg_len = iovp->iov_len;
xs->datalen += iovp->iov_len;
SC_DEBUGN(sc_link, SDEV_DB4, ("(0x%x@0x%x)",
iovp->iov_len, iovp->iov_base));
sg++;
iovp++;
seg++;
datalen--;
}
error = bus_dmamap_load_uio(dmat,
mscp->dmamap_xfer, (struct uio *)xs->data,
(flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
} else
#endif /*TFS */
{
/*
* Set up the scatter gather block
*/
SC_DEBUG(sc_link, SDEV_DB4,
("%d @0x%x:- ", xs->datalen, xs->data));
datalen = xs->datalen;
thiskv = (int) xs->data;
thisphys = KVTOPHYS(thiskv);
while (datalen && seg < UHA_NSEG) {
bytes_this_seg = 0;
/* put in the base address */
sg->seg_addr = thisphys;
SC_DEBUGN(sc_link, SDEV_DB4, ("0x%x", thisphys));
/* do it at least once */
nextphys = thisphys;
while (datalen && thisphys == nextphys) {
/*
* This page is contiguous (physically)
* with the the last, just extend the
* length
*/
/* how far to the end of the page */
nextphys = (thisphys & ~PGOFSET) + NBPG;
bytes_this_page = nextphys - thisphys;
/**** or the data ****/
bytes_this_page = min(bytes_this_page,
datalen);
bytes_this_seg += bytes_this_page;
datalen -= bytes_this_page;
/* get more ready for the next page */
thiskv = (thiskv & ~PGOFSET) + NBPG;
if (datalen)
thisphys = KVTOPHYS(thiskv);
}
/*
* next page isn't contiguous, finish the seg
*/
SC_DEBUGN(sc_link, SDEV_DB4,
("(0x%x)", bytes_this_seg));
sg->seg_len = bytes_this_seg;
sg++;
seg++;
}
error = bus_dmamap_load(dmat,
mscp->dmamap_xfer, xs->data, xs->datalen, NULL,
(flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
BUS_DMA_WAITOK);
}
/* end of iov/kv decision */
SC_DEBUGN(sc_link, SDEV_DB4, ("\n"));
if (datalen) {
/*
* there's still data, must have run out of segs!
*/
printf("%s: uha_scsi_cmd, more than %d dma segs\n",
sc->sc_dev.dv_xname, UHA_NSEG);
if (error) {
if (error == EFBIG) {
printf("%s: uha_scsi_cmd, more than %d"
" dma segments\n",
sc->sc_dev.dv_xname, UHA_NSEG);
} else {
printf("%s: uha_scsi_cmd, error %d loading"
" dma map\n",
sc->sc_dev.dv_xname, error);
}
goto bad;
}
mscp->data_addr = KVTOPHYS(mscp->uha_dma);
bus_dmamap_sync(dmat, mscp->dmamap_xfer,
(flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
BUS_DMASYNC_PREWRITE);
/*
* Load the hardware scatter/gather map with the
* contents of the DMA map.
*/
for (seg = 0; seg < mscp->dmamap_xfer->dm_nsegs; seg++) {
mscp->uha_dma[seg].seg_addr =
mscp->dmamap_xfer->dm_segs[seg].ds_addr;
mscp->uha_dma[seg].seg_len =
mscp->dmamap_xfer->dm_segs[seg].ds_len;
}
mscp->data_addr = mscp->dmamap_self->dm_segs[0].ds_addr +
offsetof(struct uha_mscp, uha_dma);
mscp->data_length = xs->datalen;
mscp->sgth = 0x01;
mscp->sg_num = seg;

View File

@ -1,4 +1,41 @@
/* $NetBSD: uhareg.h,v 1.2 1996/09/01 00:54:41 mycroft Exp $ */
/* $NetBSD: uhareg.h,v 1.3 1997/06/06 23:31:06 thorpej Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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) 1994, 1996 Charles M. Hannum. All rights reserved.
@ -226,6 +263,24 @@ struct uha_mscp {
#define MSCP_ALLOC 0x01
#define MSCP_ABORT 0x02
int timeout;
/*
* DMA maps used by the MSCP. These maps are created
* in uha_init_mscp().
*/
/*
* This DMA map maps an individual MSCP. This map is
* permanently loaded in uha_init_mscp().
*/
bus_dmamap_t dmamap_self;
/*
* This DMA map maps the buffer involved in the transfer.
* It's contents are loaded into "uha_dma" above.
*/
bus_dmamap_t dmamap_xfer;
};
#pragma pack(4)

View File

@ -1,4 +1,4 @@
/* $NetBSD: uhavar.h,v 1.4 1997/03/29 02:32:32 mycroft Exp $ */
/* $NetBSD: uhavar.h,v 1.5 1997/06/06 23:31:07 thorpej Exp $ */
/*
* Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
@ -39,8 +39,11 @@ struct uha_softc {
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
bus_dma_tag_t sc_dmat;
void *sc_ih;
int sc_dmaflags; /* bus-specific DMA map creation flags */
void (*start_mbox) __P((struct uha_softc *, struct uha_mscp *));
int (*poll) __P((struct uha_softc *, struct scsi_xfer *, int));
void (*init) __P((struct uha_softc *));