diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2000-02-05 22:20:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2000-02-05 22:20:40 +0000 |
commit | 1be6b642c8029081cd4100963cf7fe29e5302433 (patch) | |
tree | 1e27b6f913d1da40cc90528e8c7e1a15bba25254 /sys/dev/ic/adw.c | |
parent | 456fb07557d109ce9616d179ed46717eeaa06b50 (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.c | 634 |
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; + } +} |