summaryrefslogtreecommitdiff
path: root/sys/dev/ic/adw.c
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2000-02-05 22:20:40 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2000-02-05 22:20:40 +0000
commit1be6b642c8029081cd4100963cf7fe29e5302433 (patch)
tree1e27b6f913d1da40cc90528e8c7e1a15bba25254 /sys/dev/ic/adw.c
parent456fb07557d109ce9616d179ed46717eeaa06b50 (diff)
support new u2w cards; dante@mclink.it, merged by kwesterback@home.com
Diffstat (limited to 'sys/dev/ic/adw.c')
-rw-r--r--sys/dev/ic/adw.c634
1 files changed, 446 insertions, 188 deletions
diff --git a/sys/dev/ic/adw.c b/sys/dev/ic/adw.c
index bd5c15860c3..e5f5272fca7 100644
--- a/sys/dev/ic/adw.c
+++ b/sys/dev/ic/adw.c
@@ -1,10 +1,9 @@
-/* $OpenBSD: adw.c,v 1.2 1999/08/04 23:27:48 niklas Exp $ */
-/* $NetBSD: adw.c,v 1.3 1998/10/10 00:28:33 thorpej Exp $ */
+/* $NetBSD: adw.c,v 1.13 2000/02/03 20:29:15 dante Exp $ */
/*
* Generic driver for the Advanced Systems Inc. SCSI controllers
*
- * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * Copyright (c) 1998, 1999, 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* Author: Baldassare Dante Profeta <dante@mclink.it>
@@ -64,7 +63,7 @@
#include <dev/ic/adw.h>
#ifndef DDB
-#define Debugger() panic("should call debugger here (adv.c)")
+#define Debugger() panic("should call debugger here (adw.c)")
#endif /* ! DDB */
/******************************************************************************/
@@ -73,24 +72,26 @@
static void adw_enqueue __P((ADW_SOFTC *, struct scsi_xfer *, int));
static struct scsi_xfer *adw_dequeue __P((ADW_SOFTC *));
-static int adw_alloc_ccbs __P((ADW_SOFTC *));
+static int adw_alloc_controls __P((ADW_SOFTC *));
+static int adw_alloc_carriers __P((ADW_SOFTC *));
+static int adw_create_carriers __P((ADW_SOFTC *));
+static int adw_init_carrier __P((ADW_SOFTC *, ADW_CARRIER *));
static int adw_create_ccbs __P((ADW_SOFTC *, ADW_CCB *, int));
static void adw_free_ccb __P((ADW_SOFTC *, ADW_CCB *));
static void adw_reset_ccb __P((ADW_CCB *));
static int adw_init_ccb __P((ADW_SOFTC *, ADW_CCB *));
static ADW_CCB *adw_get_ccb __P((ADW_SOFTC *, int));
-static void adw_queue_ccb __P((ADW_SOFTC *, ADW_CCB *));
-static void adw_start_ccbs __P((ADW_SOFTC *));
+static int adw_queue_ccb __P((ADW_SOFTC *, ADW_CCB *, int));
static int adw_scsi_cmd __P((struct scsi_xfer *));
static int adw_build_req __P((struct scsi_xfer *, ADW_CCB *));
-static void adw_build_sglist __P((ADW_CCB *, ADW_SCSI_REQ_Q *));
+static void adw_build_sglist __P((ADW_CCB *, ADW_SCSI_REQ_Q *, ADW_SG_BLOCK *));
static void adwminphys __P((struct buf *));
-static void adw_wide_isr_callback __P((ADW_SOFTC *, ADW_SCSI_REQ_Q *));
+static void adw_isr_callback __P((ADW_SOFTC *, ADW_SCSI_REQ_Q *));
+static void adw_async_callback __P((ADW_SOFTC *, u_int8_t));
static int adw_poll __P((ADW_SOFTC *, struct scsi_xfer *, int));
static void adw_timeout __P((void *));
-static void adw_watchdog __P((void *));
/******************************************************************************/
@@ -100,16 +101,6 @@ struct cfdriver adw_cd = {
NULL, "adw", DV_DULL
};
-
-struct scsi_adapter adw_switch =
-{
- adw_scsi_cmd, /* called to start/enqueue a SCSI command */
- adwminphys, /* to limit the transfer to max device can do */
- 0,
- 0,
-};
-
-
/* the below structure is so we have a default dev struct for out link struct */
struct scsi_device adw_dev =
{
@@ -125,7 +116,7 @@ struct scsi_device adw_dev =
/******************************************************************************/
-/* scsi_xfer queue routines */
+/* scsi_xfer queue routines */
/******************************************************************************/
/*
@@ -169,21 +160,20 @@ adw_dequeue(sc)
return (xs);
}
-
/******************************************************************************/
-/* Control Blocks routines */
+/* Control Blocks routines */
/******************************************************************************/
static int
-adw_alloc_ccbs(sc)
+adw_alloc_controls(sc)
ADW_SOFTC *sc;
{
bus_dma_segment_t seg;
int error, rseg;
/*
- * Allocate the control blocks.
+ * Allocate the control structure.
*/
if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct adw_control),
NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
@@ -198,6 +188,7 @@ adw_alloc_ccbs(sc)
sc->sc_dev.dv_xname, error);
return (error);
}
+
/*
* Create and load the DMA map used for the control blocks.
*/
@@ -215,11 +206,164 @@ adw_alloc_ccbs(sc)
sc->sc_dev.dv_xname, error);
return (error);
}
+
+ return (0);
+}
+
+
+static int
+adw_alloc_carriers(sc)
+ ADW_SOFTC *sc;
+{
+ bus_dma_segment_t seg;
+ int error, rseg;
+
+ /*
+ * Allocate the control structure.
+ */
+ sc->sc_control->carriers = malloc(ADW_CARRIER_SIZE * ADW_MAX_CARRIER,
+ M_DEVBUF, M_WAITOK);
+ if(!sc->sc_control->carriers) {
+ printf("%s: malloc() failed in allocating carrier structures,"
+ " error = %d\n", sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+
+ if ((error = bus_dmamem_alloc(sc->sc_dmat,
+ ADW_CARRIER_SIZE * ADW_MAX_CARRIER,
+ NBPG, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to allocate carrier structures,"
+ " error = %d\n", sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+ if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
+ ADW_CARRIER_SIZE * ADW_MAX_CARRIER,
+ (caddr_t *) &sc->sc_control->carriers,
+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
+ printf("%s: unable to map carrier structures,"
+ " error = %d\n", sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+
+ /*
+ * Create and load the DMA map used for the control blocks.
+ */
+ if ((error = bus_dmamap_create(sc->sc_dmat,
+ ADW_CARRIER_SIZE * ADW_MAX_CARRIER, 1,
+ ADW_CARRIER_SIZE * ADW_MAX_CARRIER, 0, BUS_DMA_NOWAIT,
+ &sc->sc_dmamap_carrier)) != 0) {
+ printf("%s: unable to create carriers DMA map,"
+ " error = %d\n", sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+ if ((error = bus_dmamap_load(sc->sc_dmat,
+ sc->sc_dmamap_carrier, sc->sc_control->carriers,
+ ADW_CARRIER_SIZE * ADW_MAX_CARRIER, NULL,
+ BUS_DMA_NOWAIT)) != 0) {
+ printf("%s: unable to load carriers DMA map,"
+ " error = %d\n", sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+
+ error = bus_dmamap_create(sc->sc_dmat, ADW_CARRIER_SIZE* ADW_MAX_CARRIER,
+ 1, ADW_CARRIER_SIZE * ADW_MAX_CARRIER,
+ 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+ &sc->sc_control->dmamap_xfer);
+ if (error) {
+ printf("%s: unable to create Carrier DMA map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+
return (0);
}
/*
+ * Create a set of Carriers and add them to the free list. Called once
+ * by adw_init(). We return the number of Carriers successfully created.
+ */
+static int
+adw_create_carriers(sc)
+ ADW_SOFTC *sc;
+{
+ ADW_CARRIER *carr;
+ u_int32_t carr_next = NULL;
+ int i, error;
+
+ for(i=0; i < ADW_MAX_CARRIER; i++) {
+ carr = (ADW_CARRIER *)(((u_int8_t *)sc->sc_control->carriers) +
+ (ADW_CARRIER_SIZE * i));
+ if ((error = adw_init_carrier(sc, carr)) != 0) {
+ printf("%s: unable to initialize carrier, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return (i);
+ }
+ carr->next_vpa = carr_next;
+ carr_next = carr->carr_pa;
+carr->id = i;
+ }
+ sc->carr_freelist = carr;
+ return (i);
+}
+
+
+static int
+adw_init_carrier(sc, carr)
+ ADW_SOFTC *sc;
+ ADW_CARRIER *carr;
+{
+ u_int32_t carr_pa;
+ int /*error, */hashnum;
+
+ /*
+ * Create the DMA map for all of the Carriers.
+ */
+/* error = bus_dmamap_create(sc->sc_dmat, ADW_CARRIER_SIZE,
+ 1, ADW_CARRIER_SIZE,
+ 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
+ &carr->dmamap_xfer);
+ if (error) {
+ printf("%s: unable to create Carrier DMA map, error = %d\n",
+ sc->sc_dev.dv_xname, error);
+ return (error);
+ }
+*/
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ carr_pa = ADW_CARRIER_ADDR(sc, carr);
+ carr->carr_pa = carr_pa;
+ hashnum = CARRIER_HASH(carr_pa);
+ carr->nexthash = sc->sc_carrhash[hashnum];
+ sc->sc_carrhash[hashnum] = carr;
+
+ return(0);
+}
+
+
+/*
+ * Given a physical address, find the Carrier that it corresponds to.
+ */
+ADW_CARRIER *
+adw_carrier_phys_kv(sc, carr_phys)
+ ADW_SOFTC *sc;
+ u_int32_t carr_phys;
+{
+ int hashnum = CARRIER_HASH(carr_phys);
+ ADW_CARRIER *carr = sc->sc_carrhash[hashnum];
+
+ while (carr) {
+ if (carr->carr_pa == carr_phys)
+ break;
+ carr = carr->nexthash;
+ }
+ return (carr);
+}
+
+
+/*
* Create a set of ccbs and add them to the free list. Called once
* by adw_init(). We return the number of CCBs successfully created.
*/
@@ -232,7 +376,6 @@ adw_create_ccbs(sc, ccbstore, count)
ADW_CCB *ccb;
int i, error;
- bzero(ccbstore, sizeof(ADW_CCB) * count);
for (i = 0; i < count; i++) {
ccb = &ccbstore[i];
if ((error = adw_init_ccb(sc, ccb)) != 0) {
@@ -287,7 +430,7 @@ adw_init_ccb(sc, ccb)
ADW_SOFTC *sc;
ADW_CCB *ccb;
{
- int error;
+ int hashnum, error;
/*
* Create the DMA map for this CCB.
@@ -297,10 +440,20 @@ adw_init_ccb(sc, ccb)
ADW_MAX_SG_LIST, (ADW_MAX_SG_LIST - 1) * PAGE_SIZE,
0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->dmamap_xfer);
if (error) {
- printf("%s: unable to create DMA map, error = %d\n",
+ printf("%s: unable to create CCB DMA map, error = %d\n",
sc->sc_dev.dv_xname, error);
return (error);
}
+
+ /*
+ * put in the phystokv hash table
+ * Never gets taken out.
+ */
+ ccb->hashkey = sc->sc_dmamap_control->dm_segs[0].ds_addr +
+ ADW_CCB_OFF(ccb);
+ hashnum = CCB_HASH(ccb->hashkey);
+ ccb->nexthash = sc->sc_ccbhash[hashnum];
+ sc->sc_ccbhash[hashnum] = ccb;
adw_reset_ccb(ccb);
return (0);
}
@@ -346,46 +499,68 @@ out:
/*
- * Queue a CCB to be sent to the controller, and send it if possible.
+ * Given a physical address, find the ccb that it corresponds to.
*/
-static void
-adw_queue_ccb(sc, ccb)
- ADW_SOFTC *sc;
- ADW_CCB *ccb;
+ADW_CCB *
+adw_ccb_phys_kv(sc, ccb_phys)
+ ADW_SOFTC *sc;
+ u_int32_t ccb_phys;
{
+ int hashnum = CCB_HASH(ccb_phys);
+ ADW_CCB *ccb = sc->sc_ccbhash[hashnum];
- TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
-
- adw_start_ccbs(sc);
+ while (ccb) {
+ if (ccb->hashkey == ccb_phys)
+ break;
+ ccb = ccb->nexthash;
+ }
+ return (ccb);
}
-static void
-adw_start_ccbs(sc)
+/*
+ * Queue a CCB to be sent to the controller, and send it if possible.
+ */
+static int
+adw_queue_ccb(sc, ccb, retry)
ADW_SOFTC *sc;
-{
ADW_CCB *ccb;
+ int retry;
+{
+ int errcode;
+
+ if(!retry)
+ TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
while ((ccb = sc->sc_waiting_ccb.tqh_first) != NULL) {
- if (ccb->flags & CCB_WATCHDOG)
- untimeout(adw_watchdog, ccb);
- if (AdvExeScsiQueue(sc, &ccb->scsiq) == ADW_BUSY) {
- ccb->flags |= CCB_WATCHDOG;
- timeout(adw_watchdog, ccb,
- (ADW_WATCH_TIMEOUT * hz) / 1000);
+ errcode = AdvExeScsiQueue(sc, &ccb->scsiq);
+ switch(errcode) {
+ case ADW_SUCCESS:
break;
+
+ case ADW_BUSY:
+ printf("ADW_BUSY\n");
+ return(ADW_BUSY);
+
+ case ADW_ERROR:
+ printf("ADW_ERROR\n");
+ TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
+ return(ADW_ERROR);
}
+
TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
if ((ccb->xs->flags & SCSI_POLL) == 0)
timeout(adw_timeout, ccb, (ccb->timeout * hz) / 1000);
}
+
+ return(errcode);
}
/******************************************************************************/
-/* SCSI layer interfacing routines */
+/* SCSI layer interfacing routines */
/******************************************************************************/
@@ -409,7 +584,10 @@ adw_init(sc)
} else {
AdvResetChip(sc->sc_iot, sc->sc_ioh);
- warn_code = AdvInitFromEEP(sc);
+ warn_code = (sc->chip_type == ADV_CHIP_ASC3550)?
+ AdvInitFrom3550EEP(sc) :
+ AdvInitFrom38C0800EEP(sc);
+
if (warn_code & ASC_WARN_EEPROM_CHKSUM)
printf("%s: Bad checksum found. "
"Setting default values\n",
@@ -418,16 +596,10 @@ adw_init(sc)
printf("%s: Bad bus termination setting."
"Using automatic termination.\n",
sc->sc_dev.dv_xname);
-
- /*
- * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
- * Resets should be performed.
- */
- if (sc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
- AdvResetSCSIBus(sc);
}
- sc->isr_callback = (ulong) adw_wide_isr_callback;
+ sc->isr_callback = (ADW_CALLBACK) adw_isr_callback;
+ sc->async_callback = (ADW_CALLBACK) adw_async_callback;
return (0);
}
@@ -440,10 +612,61 @@ adw_attach(sc)
int i, error;
+ TAILQ_INIT(&sc->sc_free_ccb);
+ TAILQ_INIT(&sc->sc_waiting_ccb);
+ LIST_INIT(&sc->sc_queue);
+
+
+ /*
+ * Allocate the Control Blocks.
+ */
+ error = adw_alloc_controls(sc);
+ if (error)
+ return; /* (error) */ ;
+
+ bzero(sc->sc_control, sizeof(struct adw_control));
+
+ /*
+ * Create and initialize the Control Blocks.
+ */
+ i = adw_create_ccbs(sc, sc->sc_control->ccbs, ADW_MAX_CCB);
+ if (i == 0) {
+ printf("%s: unable to create Control Blocks\n",
+ sc->sc_dev.dv_xname);
+ return; /* (ENOMEM) */ ;
+ } else if (i != ADW_MAX_CCB) {
+ printf("%s: WARNING: only %d of %d Control Blocks"
+ " created\n",
+ sc->sc_dev.dv_xname, i, ADW_MAX_CCB);
+ }
+
+ /*
+ * Create and initialize the Carriers.
+ */
+ error = adw_alloc_carriers(sc);
+ if (error)
+ return; /* (error) */ ;
+
+ bzero(sc->sc_control->carriers, ADW_CARRIER_SIZE * ADW_MAX_CARRIER);
+
+ i = adw_create_carriers(sc);
+ if (i == 0) {
+ printf("%s: unable to create Carriers\n",
+ sc->sc_dev.dv_xname);
+ return; /* (ENOMEM) */ ;
+ } else if (i != ADW_MAX_CARRIER) {
+ printf("%s: WARNING: only %d of %d Carriers created\n",
+ sc->sc_dev.dv_xname, i, ADW_MAX_CARRIER);
+ }
+
+
/*
* Initialize the ASC3550.
*/
- switch (AdvInitAsc3550Driver(sc)) {
+ error = (sc->chip_type == ADV_CHIP_ASC3550)?
+ AdvInitAsc3550Driver(sc) :
+ AdvInitAsc38C0800Driver(sc);
+ switch (error) {
case ASC_IERR_MCODE_CHKSUM:
panic("%s: Microcode checksum error",
sc->sc_dev.dv_xname);
@@ -464,45 +687,34 @@ adw_attach(sc)
" one of the connectors",
sc->sc_dev.dv_xname);
break;
+
+ case ASC_IERR_NO_CARRIER:
+ panic("%s: no carrier",
+ sc->sc_dev.dv_xname);
+ break;
+
+ case ASC_WARN_BUSRESET_ERROR:
+ printf("%s: WARNING: Bus Reset Error\n",
+ sc->sc_dev.dv_xname);
+ break;
}
+ /*
+ * Fill in the adapter.
+ */
+ sc->sc_adapter.scsi_cmd = adw_scsi_cmd;
+ sc->sc_adapter.scsi_minphys = adwminphys;
/*
* fill in the prototype scsi_link.
*/
sc->sc_link.adapter_softc = sc;
sc->sc_link.adapter_target = sc->chip_scsi_id;
- sc->sc_link.adapter = &adw_switch;
+ sc->sc_link.adapter = &sc->sc_adapter;
sc->sc_link.device = &adw_dev;
sc->sc_link.openings = 4;
- sc->sc_link.adapter_buswidth = ADW_MAX_TID;
-
-
- TAILQ_INIT(&sc->sc_free_ccb);
- TAILQ_INIT(&sc->sc_waiting_ccb);
- LIST_INIT(&sc->sc_queue);
-
-
- /*
- * Allocate the Control Blocks.
- */
- error = adw_alloc_ccbs(sc);
- if (error)
- return; /* (error) */ ;
+ sc->sc_link.adapter_buswidth = ADW_MAX_TID+1;
- /*
- * Create and initialize the Control Blocks.
- */
- i = adw_create_ccbs(sc, sc->sc_control->ccbs, ADW_MAX_CCB);
- if (i == 0) {
- printf("%s: unable to create control blocks\n",
- sc->sc_dev.dv_xname);
- return; /* (ENOMEM) */ ;
- } else if (i != ADW_MAX_CCB) {
- printf("%s: WARNING: only %d of %d control blocks"
- " created\n",
- sc->sc_dev.dv_xname, i, ADW_MAX_CCB);
- }
config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
}
@@ -529,7 +741,7 @@ adw_scsi_cmd(xs)
struct scsi_link *sc_link = xs->sc_link;
ADW_SOFTC *sc = sc_link->adapter_softc;
ADW_CCB *ccb;
- int s, fromqueue = 1, dontqueue = 0;
+ int s, fromqueue = 1, dontqueue = 0, retry = 0;
s = splbio(); /* protect the queue */
@@ -597,10 +809,21 @@ adw_scsi_cmd(xs)
ccb->timeout = xs->timeout;
if (adw_build_req(xs, ccb)) {
+retryagain:
s = splbio();
- adw_queue_ccb(sc, ccb);
+ retry = adw_queue_ccb(sc, ccb, retry);
splx(s);
+ switch(retry) {
+ case ADW_BUSY:
+ goto retryagain;
+
+ case ADW_ERROR:
+ xs->error = XS_DRIVER_STUFFUP;
+ return (COMPLETE);
+
+ }
+
/*
* Usually return SUCCESSFULLY QUEUED
*/
@@ -638,10 +861,10 @@ adw_build_req(xs, ccb)
bzero(scsiqp, sizeof(ADW_SCSI_REQ_Q));
/*
- * Set the ADW_SCSI_REQ_Q 'ccb_ptr' to point to the CCB structure.
+ * Set the ADW_SCSI_REQ_Q 'ccb_ptr' to point to the
+ * physical CCB structure.
*/
- scsiqp->ccb_ptr = (ulong) ccb;
-
+ scsiqp->ccb_ptr = ccb->hashkey;
/*
* Build the ADW_SCSI_REQ_Q request.
@@ -655,10 +878,12 @@ adw_build_req(xs, ccb)
scsiqp->target_id = sc_link->target;
scsiqp->target_lun = sc_link->lun;
- scsiqp->vsense_addr = (ulong) & ccb->scsi_sense;
+ scsiqp->vsense_addr = & ccb->scsi_sense;
scsiqp->sense_addr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
- ADW_CCB_OFF(ccb) + offsetof(struct adw_ccb, scsi_sense);
- scsiqp->sense_len = sizeof(struct scsi_sense_data);
+ ADW_CCB_OFF(ccb) + offsetof(struct adw_ccb, scsi_sense);
+/* scsiqp->sense_addr = ccb->hashkey +
+ offsetof(struct adw_ccb, scsi_sense);
+*/ scsiqp->sense_len = sizeof(struct scsi_sense_data);
/*
* Build ADW_SCSI_REQ_Q for a scatter-gather buffer command.
@@ -671,15 +896,15 @@ adw_build_req(xs, ccb)
if (xs->flags & SCSI_DATA_UIO) {
error = bus_dmamap_load_uio(dmat,
ccb->dmamap_xfer, (struct uio *) xs->data,
- (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
- BUS_DMA_WAITOK);
+ (xs->flags & SCSI_NOSLEEP) ?
+ BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
} else
-#endif /* TFS */
+#endif /* TFS */
{
error = bus_dmamap_load(dmat,
ccb->dmamap_xfer, xs->data, xs->datalen, NULL,
- (xs->flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
- BUS_DMA_WAITOK);
+ (xs->flags & SCSI_NOSLEEP) ?
+ BUS_DMA_NOWAIT : BUS_DMA_WAITOK);
}
if (error) {
@@ -698,19 +923,17 @@ adw_build_req(xs, ccb)
return (0);
}
bus_dmamap_sync(dmat, ccb->dmamap_xfer,
- (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
- BUS_DMASYNC_PREWRITE);
+ (xs->flags & SCSI_DATA_IN) ?
+ BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
/*
* Build scatter-gather list.
*/
scsiqp->data_cnt = xs->datalen;
- scsiqp->vdata_addr = (ulong) xs->data;
+ scsiqp->vdata_addr = xs->data;
scsiqp->data_addr = ccb->dmamap_xfer->dm_segs[0].ds_addr;
- scsiqp->sg_list_ptr = &ccb->sg_block[0];
- bzero(scsiqp->sg_list_ptr,
- sizeof(ADW_SG_BLOCK) * ADW_NUM_SG_BLOCK);
- adw_build_sglist(ccb, scsiqp);
+ bzero(ccb->sg_block, sizeof(ADW_SG_BLOCK) * ADW_NUM_SG_BLOCK);
+ adw_build_sglist(ccb, scsiqp, ccb->sg_block);
} else {
/*
* No data xfer, use non S/G values.
@@ -718,7 +941,6 @@ adw_build_req(xs, ccb)
scsiqp->data_cnt = 0;
scsiqp->vdata_addr = 0;
scsiqp->data_addr = 0;
- scsiqp->sg_list_ptr = NULL;
}
return (1);
@@ -729,23 +951,21 @@ adw_build_req(xs, ccb)
* Build scatter-gather list for Wide Boards.
*/
static void
-adw_build_sglist(ccb, scsiqp)
+adw_build_sglist(ccb, scsiqp, sg_block)
ADW_CCB *ccb;
ADW_SCSI_REQ_Q *scsiqp;
+ ADW_SG_BLOCK *sg_block;
{
- struct scsi_xfer *xs = ccb->xs;
- ADW_SOFTC *sc = xs->sc_link->adapter_softc;
- ADW_SG_BLOCK *sg_block = scsiqp->sg_list_ptr;
- ulong sg_block_next_addr; /* block and its next */
- ulong sg_block_physical_addr;
- int sg_block_index, i; /* how many SG entries */
+ u_long sg_block_next_addr; /* block and its next */
+ u_int32_t sg_block_physical_addr;
+ int i; /* how many SG entries */
bus_dma_segment_t *sg_list = &ccb->dmamap_xfer->dm_segs[0];
int sg_elem_cnt = ccb->dmamap_xfer->dm_nsegs;
- sg_block_next_addr = (ulong) sg_block; /* allow math operation */
- sg_block_physical_addr = sc->sc_dmamap_control->dm_segs[0].ds_addr +
- ADW_CCB_OFF(ccb) + offsetof(struct adw_ccb, sg_block[0]);
+ sg_block_next_addr = (u_long) sg_block; /* allow math operation */
+ sg_block_physical_addr = ccb->hashkey +
+ offsetof(struct adw_ccb, sg_block[0]);
scsiqp->sg_real_addr = sg_block_physical_addr;
/*
@@ -753,17 +973,14 @@ adw_build_sglist(ccb, scsiqp)
* then split the request into multiple sg-list blocks.
*/
- sg_block_index = 0;
do {
- sg_block->first_entry_no = sg_block_index;
for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) {
sg_block->sg_list[i].sg_addr = sg_list->ds_addr;
sg_block->sg_list[i].sg_count = sg_list->ds_len;
if (--sg_elem_cnt == 0) {
/* last entry, get out */
- scsiqp->sg_entry_cnt = sg_block_index + i + 1;
- sg_block->last_entry_no = sg_block_index + i;
+ sg_block->sg_cnt = i + i;
sg_block->sg_ptr = NULL; /* next link = NULL */
return;
}
@@ -772,12 +989,10 @@ adw_build_sglist(ccb, scsiqp)
sg_block_next_addr += sizeof(ADW_SG_BLOCK);
sg_block_physical_addr += sizeof(ADW_SG_BLOCK);
- sg_block_index += NO_OF_SG_PER_BLOCK;
- sg_block->sg_ptr = (ADW_SG_BLOCK *) sg_block_physical_addr;
- sg_block->last_entry_no = sg_block_index - 1;
+ sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
+ sg_block->sg_ptr = sg_block_physical_addr;
sg_block = (ADW_SG_BLOCK *) sg_block_next_addr; /* virt. addr */
- }
- while (1);
+ } while (1);
}
@@ -789,18 +1004,18 @@ adw_intr(arg)
struct scsi_xfer *xs;
- AdvISR(sc);
-
- /*
- * If there are queue entries in the software queue, try to
- * run the first one. We should be more or less guaranteed
- * to succeed, since we just freed a CCB.
- *
- * NOTE: adw_scsi_cmd() relies on our calling it with
- * the first entry in the queue.
- */
- if ((xs = sc->sc_queue.lh_first) != NULL)
- (void) adw_scsi_cmd(xs);
+ if(AdvISR(sc) != ADW_FALSE) {
+ /*
+ * If there are queue entries in the software queue, try to
+ * run the first one. We should be more or less guaranteed
+ * to succeed, since we just freed a CCB.
+ *
+ * NOTE: adw_scsi_cmd() relies on our calling it with
+ * the first entry in the queue.
+ */
+ if ((xs = sc->sc_queue.lh_first) != NULL)
+ (void) adw_scsi_cmd(xs);
+ }
return (1);
}
@@ -847,78 +1062,76 @@ adw_timeout(arg)
* If it has been through before, then a previous abort has failed,
* don't try abort again, reset the bus instead.
*/
- if (ccb->flags & CCB_ABORT) {
- /* abort timed out */
- printf(" AGAIN. Resetting Bus\n");
- /* Lets try resetting the bus! */
+ if (ccb->flags & CCB_ABORTED) {
+ /*
+ * Abort Timed Out
+ * Lets try resetting the bus!
+ */
+ printf(" AGAIN. Resetting SCSI Bus\n");
+ ccb->flags &= ~CCB_ABORTED;
+ /* AdvResetSCSIBus() will call sbreset_callback() */
AdvResetSCSIBus(sc);
- ccb->timeout = ADW_ABORT_TIMEOUT;
- adw_queue_ccb(sc, ccb);
} else {
- /* abort the operation that has timed out */
+ /*
+ * Abort the operation that has timed out
+ */
printf("\n");
- ADW_ABORT_CCB(sc, ccb);
xs->error = XS_TIMEOUT;
- ccb->timeout = ADW_ABORT_TIMEOUT;
- ccb->flags |= CCB_ABORT;
- adw_queue_ccb(sc, ccb);
+ ccb->flags |= CCB_ABORTING;
+ /* ADW_ABORT_CCB() will implicitly call isr_callback() */
+ ADW_ABORT_CCB(sc, ccb);
}
splx(s);
}
-static void
-adw_watchdog(arg)
- void *arg;
-{
- ADW_CCB *ccb = arg;
- struct scsi_xfer *xs = ccb->xs;
- struct scsi_link *sc_link = xs->sc_link;
- ADW_SOFTC *sc = sc_link->adapter_softc;
- int s;
-
- s = splbio();
-
- ccb->flags &= ~CCB_WATCHDOG;
- adw_start_ccbs(sc);
-
- splx(s);
-}
-
-
/******************************************************************************/
-/* NARROW and WIDE boards Interrupt callbacks */
+/* WIDE boards Interrupt callbacks */
/******************************************************************************/
/*
- * adw_wide_isr_callback() - Second Level Interrupt Handler called by AdvISR()
+ * adw__isr_callback() - Second Level Interrupt Handler called by AdvISR()
*
* Interrupt callback function for the Wide SCSI Adv Library.
*/
static void
-adw_wide_isr_callback(sc, scsiq)
+adw_isr_callback(sc, scsiq)
ADW_SOFTC *sc;
ADW_SCSI_REQ_Q *scsiq;
{
bus_dma_tag_t dmat = sc->sc_dmat;
- ADW_CCB *ccb = (ADW_CCB *) scsiq->ccb_ptr;
- struct scsi_xfer *xs = ccb->xs;
+ ADW_CCB *ccb;
+ struct scsi_xfer *xs;
struct scsi_sense_data *s1, *s2;
- //int underrun = ASC_FALSE;
+// int s;
+ ccb = adw_ccb_phys_kv(sc, scsiq->ccb_ptr);
+
untimeout(adw_timeout, ccb);
+/* if(ccb->flags & CCB_ABORTING) {
+ printf("Retrying request\n");
+ ccb->flags &= ~CCB_ABORTING;
+ ccb->flags |= CCB_ABORTED;
+ s = splbio();
+ adw_queue_ccb(sc, ccb);
+ splx(s);
+ return;
+ }
+*/
+ xs = ccb->xs;
+
/*
* 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);
+ (xs->flags & SCSI_DATA_IN) ?
+ BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(dmat, ccb->dmamap_xfer);
}
if ((ccb->flags & CCB_ALLOC) == 0) {
@@ -949,31 +1162,38 @@ adw_wide_isr_callback(sc, scsiq)
xs->error = XS_DRIVER_STUFFUP;
break;
}
- /*
- * If there was an underrun without any other error,
- * set DID_ERROR to indicate the underrun error.
- *
- * Note: There is no way yet to indicate the number
- * of underrun bytes.
- */
- /*
- * if (xs->error == XS_NOERROR && underrun == ASC_TRUE) {
- * scp->result = HOST_BYTE(DID_UNDERRUN); }
- */ break;
+ break;
case QD_WITH_ERROR:
switch (scsiq->host_status) {
case QHSTA_NO_ERROR:
- if (scsiq->scsi_status == SS_CHK_CONDITION) {
+ switch(scsiq->scsi_status) {
+ case SS_CHK_CONDITION:
+ case SS_CMD_TERMINATED:
s1 = &ccb->scsi_sense;
s2 = &xs->sense;
*s2 = *s1;
xs->error = XS_SENSE;
- } else {
+ break;
+ case SS_TARGET_BUSY:
+ case SS_RSERV_CONFLICT:
+ case SS_QUEUE_FULL:
xs->error = XS_DRIVER_STUFFUP;
+ break;
+ case SS_CONDITION_MET:
+ case SS_INTERMID:
+ case SS_INTERMID_COND_MET:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+ case SS_GOOD:
+ break;
}
break;
+ case QHSTA_M_SEL_TIMEOUT:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
default:
/* Some other QHSTA error occurred. */
xs->error = XS_DRIVER_STUFFUP;
@@ -982,13 +1202,51 @@ adw_wide_isr_callback(sc, scsiq)
break;
case QD_ABORTED_BY_HOST:
+ xs->error = XS_DRIVER_STUFFUP;
+ break;
+
default:
xs->error = XS_DRIVER_STUFFUP;
break;
}
-
adw_free_ccb(sc, ccb);
xs->flags |= ITSDONE;
scsi_done(xs);
}
+
+
+/*
+ * adv_async_callback() - Adv Library asynchronous event callback function.
+ */
+static void
+adw_async_callback(sc, code)
+ ADW_SOFTC *sc;
+ u_int8_t code;
+{
+ switch (code) {
+ case ADV_ASYNC_SCSI_BUS_RESET_DET:
+ /*
+ * The firmware detected a SCSI Bus reset.
+ */
+ break;
+
+ case ADV_ASYNC_RDMA_FAILURE:
+ /*
+ * Handle RDMA failure by resetting the SCSI Bus and
+ * possibly the chip if it is unresponsive. Log the error
+ * with a unique code.
+ */
+ AdvResetSCSIBus(sc);
+ break;
+
+ case ADV_HOST_SCSI_BUS_RESET:
+ /*
+ * Host generated SCSI bus reset occurred.
+ */
+ break;
+
+ default:
+ break;
+ }
+}