From 405e2ed76987008c9283af7e5e8f94106999dca9 Mon Sep 17 00:00:00 2001 From: gibbs Date: Fri, 23 Apr 1999 23:27:31 +0000 Subject: Complete conversion to bus dma. This driver now works on the alpha. aicasm_symbol.c: Correct an unaligned access problem. You can't rely on DB to store your data in an aligned fashion. --- sys/dev/aic7xxx/aic7xxx.c | 956 ++++++++++++++++++++------------- sys/dev/aic7xxx/aic7xxx.h | 142 +++-- sys/dev/aic7xxx/aicasm/aicasm_symbol.c | 20 +- sys/dev/aic7xxx/aicasm_symbol.c | 20 +- 4 files changed, 703 insertions(+), 435 deletions(-) diff --git a/sys/dev/aic7xxx/aic7xxx.c b/sys/dev/aic7xxx/aic7xxx.c index 5e0ccab..672b60e 100644 --- a/sys/dev/aic7xxx/aic7xxx.c +++ b/sys/dev/aic7xxx/aic7xxx.c @@ -36,7 +36,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aic7xxx.c,v 1.21 1999/04/07 23:02:45 gibbs Exp $ + * $Id: aic7xxx.c,v 1.22 1999/04/19 21:28:15 gibbs Exp $ */ /* * A few notes on features of the driver. @@ -114,6 +114,7 @@ #include #include #include +#include #include #include @@ -192,8 +193,6 @@ typedef enum { SEARCH_REMOVE } ahc_search_action; -u_long ahc_unit = 0; - #ifdef AHC_DEBUG static int ahc_debug = AHC_DEBUG; #endif @@ -202,6 +201,11 @@ static int ahc_debug = AHC_DEBUG; void ahc_pci_intr(struct ahc_softc *ahc); #endif +static int ahcinitscbdata(struct ahc_softc *ahc); +static void ahcfiniscbdata(struct ahc_softc *ahc); + +static bus_dmamap_callback_t ahcdmamapcb; + #if UNUSED static void ahc_dump_targcmd(struct target_cmd *cmd); #endif @@ -221,11 +225,7 @@ static void ahc_poll(struct cam_sim *sim); static void ahc_setup_data(struct ahc_softc *ahc, struct ccb_scsiio *csio, struct scb *scb); static void ahc_freeze_devq(struct ahc_softc *ahc, struct cam_path *path); -static struct scb * - ahc_get_scb(struct ahc_softc *ahc); -static void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb); -static struct scb * - ahc_alloc_scb(struct ahc_softc *ahc); +static void ahcallocscbs(struct ahc_softc *ahc); static void ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); @@ -350,8 +350,8 @@ static __inline void ahc_busy_tcl(struct ahc_softc *ahc, struct scb *scb); static __inline void ahc_freeze_ccb(union ccb* ccb); static __inline cam_status ahc_ccb_status(union ccb* ccb); -static __inline void ahc_set_ccb_status(union ccb* ccb, - cam_status status); +static __inline void ahcsetccbstatus(union ccb* ccb, + cam_status status); static __inline void ahc_run_tqinfifo(struct ahc_softc *ahc); static __inline struct ahc_initiator_tinfo * @@ -359,11 +359,16 @@ static __inline struct ahc_initiator_tinfo * char channel, u_int our_id, u_int target, struct tmode_tstate **tstate); +static __inline void + ahcfreescb(struct ahc_softc *ahc, struct scb *scb); +static __inline struct scb * + ahcgetscb(struct ahc_softc *ahc); static __inline u_int32_t ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index) { - return (ahc->hscb_busaddr + (sizeof(struct hardware_scb) * index)); + return (ahc->scb_data->hscb_busaddr + + (sizeof(struct hardware_scb) * index)); } #define AHC_BUSRESET_DELAY 25 /* Reset delay in us */ @@ -440,7 +445,7 @@ ahc_ccb_status(union ccb* ccb) } static __inline void -ahc_set_ccb_status(union ccb* ccb, cam_status status) +ahcsetccbstatus(union ccb* ccb, cam_status status) { ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= status; @@ -491,6 +496,62 @@ ahc_run_tqinfifo(struct ahc_softc *ahc) } } +/* + * An scb (and hence an scb entry on the board) is put onto the + * free list. + */ +static __inline void +ahcfreescb(struct ahc_softc *ahc, struct scb *scb) +{ + struct hardware_scb *hscb; + int opri; + + hscb = scb->hscb; + + opri = splcam(); + + if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0 + && (scb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { + scb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; + ahc->flags &= ~AHC_RESOURCE_SHORTAGE; + } + + /* Clean up for the next user */ + scb->flags = SCB_FREE; + hscb->control = 0; + hscb->status = 0; + + SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links); + splx(opri); +} + +/* + * Get a free scb, either one already assigned to a hardware slot + * on the adapter or one that will require an SCB to be paged out before + * use. If there are none, see if we can allocate a new SCB. Otherwise + * either return an error or sleep. + */ +static __inline struct scb * +ahcgetscb(struct ahc_softc *ahc) +{ + struct scb *scbp; + int opri; + + opri = splcam(); + if ((scbp = SLIST_FIRST(&ahc->scb_data->free_scbs))) { + SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links); + } else { + ahcallocscbs(ahc); + scbp = SLIST_FIRST(&ahc->scb_data->free_scbs); + if (scbp != NULL) + SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links); + } + + splx(opri); + + return (scbp); +} + char * ahc_name(struct ahc_softc *ahc) { @@ -518,8 +579,8 @@ ahc_print_scb(struct scb *scb) hscb->SG_count, hscb->SG_pointer); printf(" sg_addr:%lx sg_len:%ld\n", - scb->ahc_dma[0].addr, - scb->ahc_dma[0].len); + scb->sg_list[0].addr, + scb->sg_list[0].len); printf(" cdb:%x %x %x %x %x %x %x %x %x %x %x %x\n", hscb->cmdstore[0], hscb->cmdstore[1], hscb->cmdstore[2], hscb->cmdstore[3], hscb->cmdstore[4], hscb->cmdstore[5], @@ -573,8 +634,9 @@ static struct ahc_syncrate ahc_syncrates[] = { * Allocate a controller structure for a new device and initialize it. */ struct ahc_softc * -ahc_alloc(int unit, u_int32_t iobase, vm_offset_t maddr, ahc_chip chip, - ahc_feature features, ahc_flag flags, struct scb_data *scb_data) +ahc_alloc(device_t dev, struct resource *regs, int regs_type, int regs_id, + bus_dma_tag_t parent_dmat, ahc_chip chip, ahc_feature features, + ahc_flag flags, struct scb_data *scb_data) { /* * find unit and check we have that many defined @@ -595,41 +657,33 @@ ahc_alloc(int unit, u_int32_t iobase, vm_offset_t maddr, ahc_chip chip, alloc_size = sizeof(struct ahc_softc); ahc = malloc(alloc_size, M_DEVBUF, M_NOWAIT); if (!ahc) { - printf("ahc%d: cannot malloc!\n", unit); + device_printf(dev, "cannot malloc softc!\n"); return NULL; } bzero(ahc, alloc_size); + LIST_INIT(&ahc->pending_ccbs); + ahc->device = dev; + ahc->unit = device_get_unit(dev); + ahc->regs_res_type = regs_type; + ahc->regs_res_id = regs_id; + ahc->regs = regs; + ahc->tag = rman_get_bustag(regs); + ahc->bsh = rman_get_bushandle(regs); + ahc->parent_dmat = parent_dmat; + ahc->chip = chip; + ahc->features = features; + ahc->flags = flags; if (scb_data == NULL) { struct full_ahc_softc* full_softc = (struct full_ahc_softc*)ahc; ahc->scb_data = &full_softc->scb_data_storage; - STAILQ_INIT(&ahc->scb_data->free_scbs); } else ahc->scb_data = scb_data; - LIST_INIT(&ahc->pending_ccbs); - ahc->unit = unit; - /* - * XXX This should be done by the bus specific probe stubs with - * the bus layer providing the bsh and tag. Unfortunately, - * we need to clean up how we configure things before this - * can happen. - */ - if (maddr != NULL) { - ahc->tag = I386_BUS_SPACE_MEM; - ahc->bsh = (bus_space_handle_t)maddr; - } else { - ahc->tag = I386_BUS_SPACE_IO; - ahc->bsh = (bus_space_handle_t)iobase; - } - ahc->chip = chip; - ahc->features = features; - ahc->flags = flags; ahc->unpause = (ahc_inb(ahc, HCNTRL) & IRQMS) | INTEN; /* The IRQMS bit is only valid on VL and EISA chips */ if ((ahc->chip & AHC_PCI) != 0) ahc->unpause &= ~IRQMS; ahc->pause = ahc->unpause | PAUSE; - return (ahc); } @@ -637,10 +691,241 @@ void ahc_free(ahc) struct ahc_softc *ahc; { + ahcfiniscbdata(ahc); + switch (ahc->init_level) { + case 3: + bus_dmamap_unload(ahc->shared_data_dmat, + ahc->shared_data_dmamap); + case 2: + bus_dmamem_free(ahc->shared_data_dmat, ahc->qoutfifo, + ahc->shared_data_dmamap); + bus_dmamap_destroy(ahc->shared_data_dmat, + ahc->shared_data_dmamap); + case 1: + bus_dma_tag_destroy(ahc->buffer_dmat); + break; + } + + if (ahc->regs != NULL) + bus_release_resource(ahc->device, ahc->regs_res_type, + ahc->regs_res_id, ahc->regs); + if (ahc->irq != NULL) + bus_release_resource(ahc->device, ahc->irq_res_type, + 0, ahc->irq); + free(ahc, M_DEVBUF); return; } +static int +ahcinitscbdata(struct ahc_softc *ahc) +{ + struct scb_data *scb_data; + int i; + + scb_data = ahc->scb_data; + SLIST_INIT(&scb_data->free_scbs); + SLIST_INIT(&scb_data->sg_maps); + + /* Allocate SCB resources */ + scb_data->scbarray = + (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX, + M_DEVBUF, M_NOWAIT); + if (scb_data->scbarray == NULL) + return (ENOMEM); + bzero(scb_data->scbarray, sizeof(struct scb) * AHC_SCB_MAX); + + /* Determine the number of hardware SCBs and initialize them */ + + scb_data->maxhscbs = ahc_probe_scbs(ahc); + /* SCB 0 heads the free list */ + ahc_outb(ahc, FREE_SCBH, 0); + for (i = 0; i < ahc->scb_data->maxhscbs; i++) { + ahc_outb(ahc, SCBPTR, i); + + /* Clear the control byte. */ + ahc_outb(ahc, SCB_CONTROL, 0); + + /* Set the next pointer */ + ahc_outb(ahc, SCB_NEXT, i+1); + + /* Make the tag number invalid */ + ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); + } + + /* Make sure that the last SCB terminates the free list */ + ahc_outb(ahc, SCBPTR, i-1); + ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); + + /* Ensure we clear the 0 SCB's control byte. */ + ahc_outb(ahc, SCBPTR, 0); + ahc_outb(ahc, SCB_CONTROL, 0); + + scb_data->maxhscbs = i; + + if (ahc->scb_data->maxhscbs == 0) + panic("%s: No SCB space found", ahc_name(ahc)); + + /* + * Create our DMA tags. These tags define the kinds of device + * accessable memory allocations and memory mappings we will + * need to perform during normal operation. + * + * Unless we need to further restrict the allocation, we rely + * on the restrictions of the parent dmat, hence the common + * use of MAXADDR and MAXSIZE. + */ + + /* DMA tag for our hardware scb structures */ + if (bus_dma_tag_create(ahc->parent_dmat, /*alignment*/0, /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + AHC_SCB_MAX * sizeof(struct hardware_scb), + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &scb_data->hscb_dmat) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* Allocation for our ccbs */ + if (bus_dmamem_alloc(scb_data->hscb_dmat, (void **)&scb_data->hscbs, + BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* And permanently map them */ + bus_dmamap_load(scb_data->hscb_dmat, scb_data->hscb_dmamap, + scb_data->hscbs, + AHC_SCB_MAX * sizeof(struct hardware_scb), + ahcdmamapcb, &scb_data->hscb_busaddr, /*flags*/0); + + scb_data->init_level++; + + /* DMA tag for our sense buffers */ + if (bus_dma_tag_create(ahc->parent_dmat, /*alignment*/0, /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + AHC_SCB_MAX * sizeof(struct scsi_sense_data), + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &scb_data->sense_dmat) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* Allocate them */ + if (bus_dmamem_alloc(scb_data->sense_dmat, (void **)&scb_data->sense, + BUS_DMA_NOWAIT, &scb_data->sense_dmamap) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* And permanently map them */ + bus_dmamap_load(scb_data->sense_dmat, scb_data->sense_dmamap, + scb_data->sense, + AHC_SCB_MAX * sizeof(struct scsi_sense_data), + ahcdmamapcb, &scb_data->sense_busaddr, /*flags*/0); + + scb_data->init_level++; + + /* DMA tag for our S/G structures. We allocate in page sized chunks */ + if (bus_dma_tag_create(ahc->parent_dmat, /*alignment*/0, /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + PAGE_SIZE, /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &scb_data->sg_dmat) != 0) { + goto error_exit; + } + + scb_data->init_level++; + + /* Perform initial CCB allocation */ + bzero(scb_data->hscbs, AHC_SCB_MAX * sizeof(struct hardware_scb)); + ahcallocscbs(ahc); + + if (scb_data->numscbs == 0) { + printf("%s: ahc_init_scb_data - " + "Unable to allocate initial scbs\n", + ahc_name(ahc)); + goto error_exit; + } + + /* + * Note that we were successfull + */ + return 0; + +error_exit: + + return ENOMEM; +} + +static void +ahcfiniscbdata(struct ahc_softc *ahc) +{ + struct scb_data *scb_data; + + scb_data = ahc->scb_data; + + switch (scb_data->init_level) { + default: + case 7: + { + struct sg_map_node *sg_map; + + while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) { + SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); + bus_dmamap_unload(scb_data->sg_dmat, + sg_map->sg_dmamap); + bus_dmamem_free(scb_data->sg_dmat, sg_map->sg_vaddr, + sg_map->sg_dmamap); + free(sg_map, M_DEVBUF); + } + bus_dma_tag_destroy(scb_data->sg_dmat); + } + case 6: + bus_dmamap_unload(scb_data->sense_dmat, + scb_data->sense_dmamap); + case 5: + bus_dmamem_free(scb_data->sense_dmat, scb_data->sense, + scb_data->sense_dmamap); + bus_dmamap_destroy(scb_data->sense_dmat, + scb_data->sense_dmamap); + case 4: + bus_dma_tag_destroy(scb_data->sense_dmat); + case 3: + bus_dmamap_unload(scb_data->hscb_dmat, scb_data->hscb_dmamap); + case 2: + bus_dmamem_free(scb_data->hscb_dmat, scb_data->hscbs, + scb_data->hscb_dmamap); + bus_dmamap_destroy(scb_data->hscb_dmat, scb_data->hscb_dmamap); + case 1: + bus_dma_tag_destroy(scb_data->hscb_dmat); + break; + } + if (scb_data->scbarray != NULL) + free(scb_data->scbarray, M_DEVBUF); +} + +static void +ahcdmamapcb(void *arg, bus_dma_segment_t *segs, int nseg, int error) +{ + bus_addr_t *baddr; + + baddr = (bus_addr_t *)arg; + *baddr = segs->ds_addr; +} + int ahc_reset(struct ahc_softc *ahc) { @@ -1082,11 +1367,22 @@ ahc_attach(struct ahc_softc *ahc) struct cam_path *path; struct cam_path *path2; int count; + int s; + int error; count = 0; sim = NULL; sim2 = NULL; + s = splcam(); + /* Hook up our interrupt handler */ + if ((error = bus_setup_intr(ahc->device, ahc->irq, ahc_intr, + ahc, &ahc->ih)) != 0) { + device_printf(ahc->device, "bus_setup_intr() failed: %d\n", + error); + goto fail; + } + /* * Attach secondary channel first if the user has * declared it the primary channel. @@ -1102,7 +1398,7 @@ ahc_attach(struct ahc_softc *ahc) /* * Create the device queue for our SIM(s). */ - devq = cam_simq_alloc(ahc->scb_data->maxscbs); + devq = cam_simq_alloc(AHC_SCB_MAX); if (devq == NULL) goto fail; @@ -1110,7 +1406,7 @@ ahc_attach(struct ahc_softc *ahc) * Construct our first channel SIM entry */ sim = cam_sim_alloc(ahc_action, ahc_poll, "ahc", ahc, ahc->unit, - 1, ahc->scb_data->maxscbs, devq); + 1, AHC_SCB_MAX, devq); if (sim == NULL) { cam_simq_free(devq); goto fail; @@ -1142,7 +1438,7 @@ ahc_attach(struct ahc_softc *ahc) if (ahc->features & AHC_TWIN) { sim2 = cam_sim_alloc(ahc_action, ahc_poll, "ahc", ahc, ahc->unit, 1, - ahc->scb_data->maxscbs, devq); + AHC_SCB_MAX, devq); if (sim2 == NULL) { printf("ahc_attach: Unable to attach second " @@ -1178,6 +1474,7 @@ ahc_attach(struct ahc_softc *ahc) xpt_action((union ccb *)&csa); count++; } + fail: if ((ahc->flags & AHC_CHANNEL_B_PRIMARY) != 0) { ahc->sim_b = sim; @@ -1190,6 +1487,7 @@ fail: ahc->sim_b = sim2; ahc->path_b = path2; } + splx(s); return (count); } @@ -1298,8 +1596,9 @@ ahc_intr(void *arg) scb_index = ahc->qoutfifo[ahc->qoutfifonext]; ahc->qoutfifo[ahc->qoutfifonext++] = SCB_LIST_NULL; - scb = ahc->scb_data->scbarray[scb_index]; - if (!scb || !(scb->flags & SCB_ACTIVE)) { + scb = &ahc->scb_data->scbarray[scb_index]; + if (scb_index >= ahc->scb_data->numscbs + || (scb->flags & SCB_ACTIVE) == 0) { printf("%s: WARNING no command for scb %d " "(cmdcmplt)\nQOUTPOS = %d\n", ahc_name(ahc), scb_index, @@ -1843,7 +2142,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * the in kernel copy directly. */ scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; + scb = &ahc->scb_data->scbarray[scb_index]; hscb = scb->hscb; /* @@ -1852,7 +2151,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * this if needed. */ ahc_outb(ahc, RETURN_1, 0); - if (!(scb && (scb->flags & SCB_ACTIVE))) { + if (!(scb_index < ahc->scb_data->numscbs + && (scb->flags & SCB_ACTIVE) != 0)) { printf("%s:%c:%d: ahc_intr - referenced scb " "not valid during seqint 0x%x scb(%d)\n", ahc_name(ahc), devinfo.channel, @@ -1868,10 +2168,10 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * complete. */ scb->flags &= ~SCB_SENSE; - ahc_set_ccb_status(scb->ccb, CAM_AUTOSENSE_FAIL); + ahcsetccbstatus(scb->ccb, CAM_AUTOSENSE_FAIL); break; } - ahc_set_ccb_status(scb->ccb, CAM_SCSI_STATUS_ERROR); + ahcsetccbstatus(scb->ccb, CAM_SCSI_STATUS_ERROR); /* Freeze the queue unit the client sees the error. */ ahc_freeze_devq(ahc, scb->ccb->ccb_h.path); ahc_freeze_ccb(scb->ccb); @@ -1893,12 +2193,13 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) #endif if ((csio->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) { - struct ahc_dma_seg *sg = scb->ahc_dma; - struct scsi_sense *sc = - (struct scsi_sense *)(&hscb->cmdstore); + struct ahc_dma_seg *sg; + struct scsi_sense *sc; struct ahc_initiator_tinfo *tinfo; struct tmode_tstate *tstate; + sg = scb->sg_list; + sc = (struct scsi_sense *)(&hscb->cmdstore); /* * Save off the residual if there is one. */ @@ -1911,24 +2212,18 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) printf("Sending Sense\n"); } #endif - /* - * bzero from the sense data before having - * the drive fill it. The SCSI spec mandates - * that any untransfered data should be - * assumed to be zero. - */ - bzero(&csio->sense_data, - sizeof(csio->sense_data)); + sg->addr = ahc->scb_data->sense_busaddr + + (hscb->tag*sizeof(struct scsi_sense_data)); + sg->len = MIN(sizeof(struct scsi_sense_data), + csio->sense_len); + sc->opcode = REQUEST_SENSE; sc->byte2 = SCB_LUN(scb) << 5; sc->unused[0] = 0; sc->unused[1] = 0; - sc->length = csio->sense_len; + sc->length = sg->len; sc->control = 0; - sg->addr = vtophys(&csio->sense_data); - sg->len = csio->sense_len; - /* * Would be nice to preserve DISCENB here, * but due to the way we page SCBs, we can't. @@ -1952,7 +2247,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) /*paused*/TRUE); hscb->status = 0; hscb->SG_count = 1; - hscb->SG_pointer = scb->ahc_dmaphys; + hscb->SG_pointer = scb->sg_list_phys; hscb->data = sg->addr; hscb->datalen = sg->len; hscb->cmdpointer = hscb->cmdstore_busaddr; @@ -2032,7 +2327,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) u_int scb_index; scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; + scb = &ahc->scb_data->scbarray[scb_index]; if (bus_phase == P_MESGOUT) ahc_setup_initiator_msgout(ahc, @@ -2072,7 +2367,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) u_int lastphase = ahc_inb(ahc, LASTPHASE); int i; - scb = ahc->scb_data->scbarray[scbindex]; + scb = &ahc->scb_data->scbarray[scbindex]; xpt_print_path(scb->ccb->ccb_h.path); printf("data overrun detected in %s phase." " Tag == 0x%x.\n", @@ -2086,8 +2381,8 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) for (i = 0; i < scb->sg_count - 1; i++) { printf("sg[%d] - Addr 0x%x : Length %d\n", i, - scb->ahc_dma[i].addr, - scb->ahc_dma[i].len); + scb->sg_list[i].addr, + scb->sg_list[i].len); } } /* @@ -2095,7 +2390,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) * target does a command complete. */ ahc_freeze_devq(ahc, scb->ccb->ccb_h.path); - ahc_set_ccb_status(scb->ccb, CAM_DATA_RUN_ERR); + ahcsetccbstatus(scb->ccb, CAM_DATA_RUN_ERR); ahc_freeze_ccb(scb->ccb); break; } @@ -2179,7 +2474,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) scb_index = ahc_inb(ahc, SCB_TAG); if (scb_index < ahc->scb_data->numscbs) { - scb = ahc->scb_data->scbarray[scb_index]; + scb = &ahc->scb_data->scbarray[scb_index]; if ((scb->flags & SCB_ACTIVE) == 0) scb = NULL; } else @@ -2221,8 +2516,8 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) scb->hscb->tag, tag == SCB_LIST_NULL ? "" : "Tag"); if ((scb->flags & SCB_RECOVERY_SCB) != 0) { - ahc_set_ccb_status(scb->ccb, - CAM_REQ_ABORTED); + ahcsetccbstatus(scb->ccb, + CAM_REQ_ABORTED); ahc_done(ahc, scb); } printerror = 0; @@ -2283,7 +2578,7 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) scb_index = ahc_inb(ahc, SCB_TAG); if (scb_index < ahc->scb_data->numscbs) { - scb = ahc->scb_data->scbarray[scb_index]; + scb = &ahc->scb_data->scbarray[scb_index]; if ((scb->flags & SCB_ACTIVE) == 0) scb = NULL; } else @@ -2531,7 +2826,7 @@ ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) int response = 0; scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; + scb = &ahc->scb_data->scbarray[scb_index]; /* Might be necessary */ last_msg = ahc_inb(ahc, LAST_MSG); @@ -3181,7 +3476,7 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) struct scb *scb; scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc->scb_data->scbarray[scb_index]; + scb = &ahc->scb_data->scbarray[scb_index]; if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0 || (scb->ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_IN) { /* @@ -3227,18 +3522,18 @@ ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) sg_index = scb->sg_count - resid_sgcnt; /* - * scb->ahc_dma starts with the second S/G entry. + * scb->sg_list starts with the second S/G entry. */ if (sg_index-- != 0 - && (scb->ahc_dma[sg_index].len < data_cnt)) { + && (scb->sg_list[sg_index].len < data_cnt)) { u_int sg_addr; data_cnt = 1; - data_addr = scb->ahc_dma[sg_index - 1].addr - + scb->ahc_dma[sg_index - 1].len - 1; + data_addr = scb->sg_list[sg_index - 1].addr + + scb->sg_list[sg_index - 1].len - 1; - sg_addr = scb->ahc_dmaphys - + (sg_index * sizeof(*scb->ahc_dma)); + sg_addr = scb->sg_list_phys + + (sg_index * sizeof(*scb->sg_list)); ahc_outb(ahc, SG_NEXT + 3, sg_addr >> 24); ahc_outb(ahc, SG_NEXT + 2, sg_addr >> 16); ahc_outb(ahc, SG_NEXT + 1, sg_addr >> 8); @@ -3317,8 +3612,8 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) op = BUS_DMASYNC_POSTREAD; else op = BUS_DMASYNC_POSTWRITE; - bus_dmamap_sync(ahc->dmat, scb->dmamap, op); - bus_dmamap_unload(ahc->dmat, scb->dmamap); + bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op); + bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap); } /* @@ -3330,7 +3625,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { ccb->ccb_h.status = CAM_REQ_CMP; - ahc_free_scb(ahc, scb); + ahcfreescb(ahc, scb); xpt_done(ccb); return; } @@ -3367,7 +3662,7 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) SCB_LUN(scb), scb->hscb->tag, /*status*/0, SEARCH_REMOVE); if (ahc_ccb_status(ccb) == CAM_BDR_SENT) - ahc_set_ccb_status(ccb, CAM_CMD_TIMEOUT); + ahcsetccbstatus(ccb, CAM_CMD_TIMEOUT); xpt_print_path(ccb->ccb_h.path); printf("no longer in timeout, status = %x\n", ccb->ccb_h.status); @@ -3377,11 +3672,24 @@ ahc_done(struct ahc_softc *ahc, struct scb *scb) if (ahc_ccb_status(ccb) == CAM_REQ_INPROG) { ccb->ccb_h.status |= CAM_REQ_CMP; } else if ((scb->flags & SCB_SENSE) != 0) { - /* We performed autosense retrieval */ + /* + * We performed autosense retrieval. + * + * bzero from the sense data before having + * the drive fill it. The SCSI spec mandates + * that any untransfered data should be + * assumed to be zero. Complete the 'bounce' + * of sense information through buffers accessible + * via bus-space by copying it into the clients + * csio. + */ + bzero(&ccb->csio.sense_data, sizeof(ccb->csio.sense_data)); + bcopy(&ahc->scb_data->sense[scb->hscb->tag], + &ccb->csio.sense_data, scb->sg_list->len); scb->ccb->ccb_h.status |= CAM_AUTOSNS_VALID; } ccb->ccb_h.status &= ~CAM_SIM_QUEUED; - ahc_free_scb(ahc, scb); + ahcfreescb(ahc, scb); xpt_done(ccb); } @@ -3411,14 +3719,16 @@ ahc_probe_scbs(struct ahc_softc *ahc) { int ahc_init(struct ahc_softc *ahc) { - int max_targ = 15; - int i; - int term; - u_int scsi_conf; - u_int scsiseq_template; - u_int ultraenb; - u_int discenable; - u_int tagenable; + int max_targ = 15; + int i; + int term; + u_int scsi_conf; + u_int scsiseq_template; + u_int ultraenb; + u_int discenable; + u_int tagenable; + size_t driver_data_size; + u_int32_t physaddr; #ifdef AHC_PRINT_SRAM printf("Scratch Ram:"); @@ -3469,6 +3779,120 @@ ahc_init(struct ahc_softc *ahc) ahc->flags &= ~AHC_INITIATORMODE; } + /* DMA tag for mapping buffers into device visible space. */ + if (bus_dma_tag_create(ahc->parent_dmat, /*alignment*/0, /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + /*maxsize*/MAXBSIZE, /*nsegments*/AHC_NSEG, + /*maxsegsz*/AHC_MAXTRANSFER_SIZE, + /*flags*/BUS_DMA_ALLOCNOW, + &ahc->buffer_dmat) != 0) { + return (ENOMEM); + } + + ahc->init_level++; + + /* + * DMA tag for our command fifos and other data in system memory + * the card's sequencer must be able to access. For initiator + * roles, we need to allocate space for the qinfifo, qoutfifo, + * and untagged_scb arrays each of which are composed of 256 + * 1 byte elements. When providing for the target mode role, + * we additionally must provide space for the incoming target + * command fifo. + */ + driver_data_size = 3 * 256 * sizeof(u_int8_t); + if ((ahc->flags & AHC_TARGETMODE) != 0) + driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd); + if (bus_dma_tag_create(ahc->parent_dmat, /*alignment*/0, /*boundary*/0, + /*lowaddr*/BUS_SPACE_MAXADDR, + /*highaddr*/BUS_SPACE_MAXADDR, + /*filter*/NULL, /*filterarg*/NULL, + driver_data_size, + /*nsegments*/1, + /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, + /*flags*/0, &ahc->shared_data_dmat) != 0) { + return (ENOMEM); + } + + ahc->init_level++; + + /* Allocation of driver data */ + if (bus_dmamem_alloc(ahc->shared_data_dmat, (void **)&ahc->qoutfifo, + BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) { + return (ENOMEM); + } + + ahc->init_level++; + + /* And permanently map it in */ + bus_dmamap_load(ahc->shared_data_dmat, ahc->shared_data_dmamap, + ahc->qoutfifo, driver_data_size, + ahcdmamapcb, &ahc->shared_data_busaddr, /*flags*/0); + + ahc->init_level++; + + /* Allocate SCB data now that buffer_dmat is initialized) */ + if (ahc->scb_data->maxhscbs == 0) + if (ahcinitscbdata(ahc) != 0) + return (ENOMEM); + + ahc->qinfifo = &ahc->qoutfifo[256]; + ahc->untagged_scbs = &ahc->qinfifo[256]; + /* There are no untagged SCBs active yet. */ + for (i = 0; i < 256; i++) + ahc->untagged_scbs[i] = SCB_LIST_NULL; + + /* All of our queues are empty */ + for (i = 0; i < 256; i++) + ahc->qoutfifo[i] = SCB_LIST_NULL; + ahc_outb(ahc, KERNEL_QINPOS, 0); + ahc_outb(ahc, QINPOS, 0); + ahc_outb(ahc, QOUTPOS, 0); + + if ((ahc->flags & AHC_TARGETMODE) != 0) { + ahc->targetcmds = (struct target_cmd *)&ahc->untagged_scbs[256]; + + /* All target command blocks start out invalid. */ + for (i = 0; i < AHC_TMODE_CMDS; i++) + ahc->targetcmds[i].cmd_valid = 0; + ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); + ahc_outb(ahc, TQINPOS, 0); + } + + /* + * Tell the sequencer where it can find the our arrays in memory. + */ + physaddr = ahc->scb_data->hscb_busaddr; + ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF); + + physaddr = ahc->shared_data_busaddr; + ahc_outb(ahc, SCBID_ADDR, physaddr & 0xFF); + ahc_outb(ahc, SCBID_ADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, SCBID_ADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, SCBID_ADDR + 3, (physaddr >> 24) & 0xFF); + + /* Target mode incomding command fifo */ + physaddr += 3 * 256 * sizeof(u_int8_t); + ahc_outb(ahc, TMODE_CMDADDR, physaddr & 0xFF); + ahc_outb(ahc, TMODE_CMDADDR + 1, (physaddr >> 8) & 0xFF); + ahc_outb(ahc, TMODE_CMDADDR + 2, (physaddr >> 16) & 0xFF); + ahc_outb(ahc, TMODE_CMDADDR + 3, (physaddr >> 24) & 0xFF); + + /* Initialize the group code to command length table */ + ahc_outb(ahc, CMDSIZE_TABLE, 5); + ahc_outb(ahc, CMDSIZE_TABLE + 1, 9); + ahc_outb(ahc, CMDSIZE_TABLE + 2, 9); + ahc_outb(ahc, CMDSIZE_TABLE + 3, 0); + ahc_outb(ahc, CMDSIZE_TABLE + 4, 15); + ahc_outb(ahc, CMDSIZE_TABLE + 5, 11); + ahc_outb(ahc, CMDSIZE_TABLE + 6, 0); + ahc_outb(ahc, CMDSIZE_TABLE + 7, 0); + /* * Allocate a tstate to house information for our * initiator presence on the bus as well as the user @@ -3500,46 +3924,10 @@ ahc_init(struct ahc_softc *ahc) ahc_outb(ahc, SEQ_FLAGS, 0); - /* Determine the number of SCBs and initialize them */ - - if (ahc->scb_data->maxhscbs == 0) { - ahc->scb_data->maxhscbs = ahc_probe_scbs(ahc); - /* SCB 0 heads the free list */ - ahc_outb(ahc, FREE_SCBH, 0); - for (i = 0; i < ahc->scb_data->maxhscbs; i++) { - ahc_outb(ahc, SCBPTR, i); - - /* Clear the control byte. */ - ahc_outb(ahc, SCB_CONTROL, 0); - - /* Set the next pointer */ - ahc_outb(ahc, SCB_NEXT, i+1); - - /* Make the tag number invalid */ - ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - } - - /* Make that the last SCB terminates the free list */ - ahc_outb(ahc, SCBPTR, i-1); - ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); - - /* Ensure we clear the 0 SCB's control byte. */ - ahc_outb(ahc, SCBPTR, 0); - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc->scb_data->maxhscbs = i; - } - - if (ahc->scb_data->maxhscbs == 0) - panic("%s: No SCB space found", ahc_name(ahc)); - if (ahc->scb_data->maxhscbs < AHC_SCB_MAX) { ahc->flags |= AHC_PAGESCBS; - ahc->scb_data->maxscbs = AHC_SCB_MAX; - printf("%d/%d SCBs\n", ahc->scb_data->maxhscbs, - ahc->scb_data->maxscbs); + printf("%d/%d SCBs\n", ahc->scb_data->maxhscbs, AHC_SCB_MAX); } else { - ahc->scb_data->maxscbs = ahc->scb_data->maxhscbs; ahc->flags &= ~AHC_PAGESCBS; printf("%d SCBs\n", ahc->scb_data->maxhscbs); } @@ -3722,111 +4110,6 @@ ahc_init(struct ahc_softc *ahc) ahc->needsdtr_orig, ahc->needwdtr_orig, discenable, ultraenb); #endif - /* - * Allocate enough "hardware scbs" to handle - * the maximum number of concurrent transactions - * we can have active. We have to use contigmalloc - * if this array crosses a page boundary since the - * sequencer depends on this array being physically - * contiguous. - */ - if (ahc->scb_data->hscbs == NULL) { - size_t array_size; - - array_size = ahc->scb_data->maxscbs*sizeof(struct hardware_scb); - if (array_size > PAGE_SIZE) { - ahc->scb_data->hscbs = (struct hardware_scb *) - contigmalloc(array_size, M_DEVBUF, - M_NOWAIT, 0ul, 0xffffffff, - PAGE_SIZE, 0x10000); - } else { - ahc->scb_data->hscbs = (struct hardware_scb *) - malloc(array_size, M_DEVBUF, M_NOWAIT); - } - - if (ahc->scb_data->hscbs == NULL) { - printf("%s: unable to allocate hardware SCB array. " - "Failing attach\n", ahc_name(ahc)); - return (-1); - } - /* At least the control byte of each hscb needs to be zeroed */ - bzero(ahc->scb_data->hscbs, array_size); - } - - if ((ahc->flags & AHC_TARGETMODE) != 0) { - size_t array_size; - - array_size = AHC_TMODE_CMDS * sizeof(struct target_cmd); - ahc->targetcmds = contigmalloc(array_size, M_DEVBUF, - M_NOWAIT, 0ul, 0xffffffff, - PAGE_SIZE, 0x10000); - - if (ahc->targetcmds == NULL) { - printf("%s: unable to allocate targetcmd array. " - "Failing attach\n", ahc_name(ahc)); - return (-1); - } - - /* All target command blocks start out invalid. */ - for (i = 0; i < AHC_TMODE_CMDS; i++) - ahc->targetcmds[i].cmd_valid = 0; - ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); - ahc_outb(ahc, TQINPOS, 0); - } - - /* - * Tell the sequencer where it can find the our arrays in memory. - */ - { - u_int32_t physaddr; - - /* Tell the sequencer where it can find the hscb array. */ - physaddr = vtophys(ahc->scb_data->hscbs); - ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF); - ahc->hscb_busaddr = physaddr; - - physaddr = vtophys(ahc->qoutfifo); - ahc_outb(ahc, SCBID_ADDR, physaddr & 0xFF); - ahc_outb(ahc, SCBID_ADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, SCBID_ADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, SCBID_ADDR + 3, (physaddr >> 24) & 0xFF); - - if ((ahc->flags & AHC_TARGETMODE) != 0) { - physaddr = vtophys(ahc->targetcmds); - ahc_outb(ahc, TMODE_CMDADDR, physaddr & 0xFF); - ahc_outb(ahc, TMODE_CMDADDR + 1, - (physaddr >> 8) & 0xFF); - ahc_outb(ahc, TMODE_CMDADDR + 2, - (physaddr >> 16) & 0xFF); - ahc_outb(ahc, TMODE_CMDADDR + 3, - (physaddr >> 24) & 0xFF); - - ahc_outb(ahc, CMDSIZE_TABLE, 5); - ahc_outb(ahc, CMDSIZE_TABLE + 1, 9); - ahc_outb(ahc, CMDSIZE_TABLE + 2, 9); - ahc_outb(ahc, CMDSIZE_TABLE + 3, 0); - ahc_outb(ahc, CMDSIZE_TABLE + 4, 15); - ahc_outb(ahc, CMDSIZE_TABLE + 5, 11); - ahc_outb(ahc, CMDSIZE_TABLE + 6, 0); - ahc_outb(ahc, CMDSIZE_TABLE + 7, 0); - } - - /* There are no untagged SCBs active yet. */ - for (i = 0; i < sizeof(ahc->untagged_scbs); i++) { - ahc->untagged_scbs[i] = SCB_LIST_NULL; - } - for (i = 0; i < sizeof(ahc->qoutfifo); i++) { - ahc->qoutfifo[i] = SCB_LIST_NULL; - } - } - - /* Our Q FIFOs are empty. */ - ahc_outb(ahc, KERNEL_QINPOS, 0); - ahc_outb(ahc, QINPOS, 0); - ahc_outb(ahc, QOUTPOS, 0); /* Don't have any special messages to send to targets */ ahc_outb(ahc, TARGET_MSG_REQUEST, 0); @@ -4028,14 +4311,14 @@ ahc_action(struct cam_sim *sim, union ccb *ccb) /* * get an scb to use. */ - if ((scb = ahc_get_scb(ahc)) == NULL) { + if ((scb = ahcgetscb(ahc)) == NULL) { int s; s = splcam(); ahc->flags |= AHC_RESOURCE_SHORTAGE; splx(s); xpt_freeze_simq(ahc->sim, /*count*/1); - ahc_set_ccb_status(ccb, CAM_REQUEUE_REQ); + ahcsetccbstatus(ccb, CAM_REQUEUE_REQ); xpt_done(ccb); return; } @@ -4434,13 +4717,13 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, end_seg = dm_segs + nsegments; /* Copy the first SG into the data pointer area */ - scb->hscb->SG_pointer = scb->ahc_dmaphys; + scb->hscb->SG_pointer = scb->sg_list_phys; scb->hscb->data = dm_segs->ds_addr; scb->hscb->datalen = dm_segs->ds_len; dm_segs++; /* Copy the remaining segments into our SG list */ - sg = scb->ahc_dma; + sg = scb->sg_list; while (dm_segs < end_seg) { sg->addr = dm_segs->ds_addr; sg->len = dm_segs->ds_len; @@ -4453,7 +4736,7 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, else op = BUS_DMASYNC_PREWRITE; - bus_dmamap_sync(ahc->dmat, scb->dmamap, op); + bus_dmamap_sync(ahc->buffer_dmat, scb->dmamap, op); if (ccb->ccb_h.func_code == XPT_CONT_TARGET_IO) { scb->hscb->cmdpointer |= DPHASE_PENDING; @@ -4476,8 +4759,8 @@ ahc_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nsegments, */ if (ahc_ccb_status(ccb) != CAM_REQ_INPROG) { if (nsegments != 0) - bus_dmamap_unload(ahc->dmat, scb->dmamap); - ahc_free_scb(ahc, scb); + bus_dmamap_unload(ahc->buffer_dmat, scb->dmamap); + ahcfreescb(ahc, scb); xpt_done(ccb); splx(s); return; @@ -4550,12 +4833,16 @@ ahc_setup_data(struct ahc_softc *ahc, struct ccb_scsiio *csio, hscb->cmdlen); hscb->cmdpointer = hscb->cmdstore_busaddr; - } else - hscb->cmdpointer = - vtophys(csio->cdb_io.cdb_ptr); + } else { + ahcsetccbstatus(scb->ccb, + CAM_REQ_INVALID); + xpt_done(scb->ccb); + ahcfreescb(ahc, scb); + return; + } else hscb->cmdpointer = - (u_int32_t)csio->cdb_io.cdb_ptr; + ((intptr_t)csio->cdb_io.cdb_ptr) & 0xffffffff; } else { /* * CCB CDB Data Storage area is only 16 bytes @@ -4576,7 +4863,7 @@ ahc_setup_data(struct ahc_softc *ahc, struct ccb_scsiio *csio, int error; s = splsoftvm(); - error = bus_dmamap_load(ahc->dmat, + error = bus_dmamap_load(ahc->buffer_dmat, scb->dmamap, csio->data_ptr, csio->dxfer_len, @@ -4643,124 +4930,67 @@ ahc_freeze_devq(struct ahc_softc *ahc, struct cam_path *path) SEARCH_COMPLETE); } -/* - * An scb (and hence an scb entry on the board) is put onto the - * free list. - */ static void -ahc_free_scb(struct ahc_softc *ahc, struct scb *scb) -{ - struct hardware_scb *hscb; - int opri; - - hscb = scb->hscb; - - opri = splcam(); +ahcallocscbs(struct ahc_softc *ahc) +{ + struct scb_data *scb_data; + struct scb *next_scb; + struct sg_map_node *sg_map; + bus_addr_t physaddr; + struct ahc_dma_seg *segs; + int newcount; + int i; - if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0 - && (scb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) { - scb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ; - ahc->flags &= ~AHC_RESOURCE_SHORTAGE; - } + scb_data = ahc->scb_data; + if (scb_data->numscbs >= AHC_SCB_MAX) + /* Can't allocate any more */ + return; - /* Clean up for the next user */ - scb->flags = SCB_FREE; - hscb->control = 0; - hscb->status = 0; + next_scb = &scb_data->scbarray[scb_data->numscbs]; - STAILQ_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links); - splx(opri); -} + sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT); -/* - * Get a free scb, either one already assigned to a hardware slot - * on the adapter or one that will require an SCB to be paged out before - * use. If there are none, see if we can allocate a new SCB. Otherwise - * either return an error or sleep. - */ -static struct scb * -ahc_get_scb(struct ahc_softc *ahc) -{ - struct scb *scbp; - int opri; + if (sg_map == NULL) + return; - opri = splcam(); - if ((scbp = STAILQ_FIRST(&ahc->scb_data->free_scbs))) { - STAILQ_REMOVE_HEAD(&ahc->scb_data->free_scbs, links); - } else if (ahc->scb_data->numscbs < ahc->scb_data->maxscbs) { - scbp = ahc_alloc_scb(ahc); - if (scbp == NULL) - printf("%s: Can't malloc SCB\n", ahc_name(ahc)); + /* Allocate S/G space for the next batch of SCBS */ + if (bus_dmamem_alloc(scb_data->sg_dmat, (void **)&sg_map->sg_vaddr, + BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { + free(sg_map, M_DEVBUF); + return; } - splx(opri); + SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); - return (scbp); -} + bus_dmamap_load(scb_data->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr, + PAGE_SIZE, ahcdmamapcb, &sg_map->sg_physaddr, + /*flags*/0); + segs = sg_map->sg_vaddr; + physaddr = sg_map->sg_physaddr; -static struct scb * -ahc_alloc_scb(struct ahc_softc *ahc) -{ - static struct ahc_dma_seg *next_sg_array = NULL; - static int sg_arrays_free = 0; - struct scb *newscb; - int error; - - newscb = (struct scb *) malloc(sizeof(struct scb), M_DEVBUF, M_NOWAIT); - if (newscb != NULL) { - bzero(newscb, sizeof(struct scb)); - error = bus_dmamap_create(ahc->dmat, /*flags*/0, - &newscb->dmamap); + newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg))); + for (i = 0; scb_data->numscbs < AHC_SCB_MAX && i < newcount; i++) { + int error; + + next_scb->sg_list = segs; + next_scb->sg_list_phys = physaddr; + next_scb->flags = SCB_FREE; + error = bus_dmamap_create(ahc->buffer_dmat, /*flags*/0, + &next_scb->dmamap); if (error != 0) - printf("%s: Unable to allocate SCB dmamap - error %d\n", - ahc_name(ahc), error); - - if (error == 0 && next_sg_array == NULL) { - size_t alloc_size = sizeof(struct ahc_dma_seg) - * AHC_NSEG; - sg_arrays_free = PAGE_SIZE / alloc_size; - alloc_size *= sg_arrays_free; - if (alloc_size == 0) - panic("%s: SG list doesn't fit in a page", - ahc_name(ahc)); - next_sg_array = (struct ahc_dma_seg *) - malloc(alloc_size, M_DEVBUF, M_NOWAIT); - } - if (error == 0 && next_sg_array != NULL) { - struct hardware_scb *hscb; - - newscb->ahc_dma = next_sg_array; - newscb->ahc_dmaphys = vtophys(next_sg_array); - sg_arrays_free--; - if (sg_arrays_free == 0) - next_sg_array = NULL; - else - next_sg_array = &next_sg_array[AHC_NSEG]; - hscb = &ahc->scb_data->hscbs[ahc->scb_data->numscbs]; - newscb->hscb = hscb; - hscb->control = 0; - hscb->status = 0; - hscb->tag = ahc->scb_data->numscbs; - hscb->residual_data_count[2] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_SG_count = 0; - hscb->cmdstore_busaddr = - ahc_hscb_busaddr(ahc, hscb->tag) - + offsetof(struct hardware_scb, cmdstore); - /* - * Place in the scbarray - * Never is removed. - */ - ahc->scb_data->scbarray[hscb->tag] = newscb; - ahc->scb_data->numscbs++; - } else { - free(newscb, M_DEVBUF); - newscb = NULL; - } + break; + next_scb->hscb = &scb_data->hscbs[scb_data->numscbs]; + next_scb->hscb->tag = ahc->scb_data->numscbs; + next_scb->hscb->cmdstore_busaddr = + ahc_hscb_busaddr(ahc, next_scb->hscb->tag) + + offsetof(struct hardware_scb, cmdstore); + SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, next_scb, links); + segs += AHC_NSEG; + physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg)); + next_scb++; + ahc->scb_data->numscbs++; } - return newscb; } static void @@ -5082,7 +5312,7 @@ ahc_timeout(void *arg) * Do a full bus reset. */ bus_reset: - ahc_set_ccb_status(scb->ccb, CAM_CMD_TIMEOUT); + ahcsetccbstatus(scb->ccb, CAM_CMD_TIMEOUT); found = ahc_reset_channel(ahc, channel, /*Initiate Reset*/TRUE); printf("%s: Issued Channel %c Bus Reset. " "%d SCBs aborted\n", ahc_name(ahc), channel, found); @@ -5123,7 +5353,7 @@ bus_reset: * and wait for it's timeout to expire before * taking additional action. */ - active_scb = ahc->scb_data->scbarray[active_scb_index]; + active_scb = &ahc->scb_data->scbarray[active_scb_index]; if (active_scb->hscb->tcl != scb->hscb->tcl && (scb->flags & SCB_OTHERTCL_TIMEOUT) == 0) { struct ccb_hdr *ccbh; @@ -5150,7 +5380,7 @@ bus_reset: * and properly record the error condition. */ ahc_freeze_devq(ahc, scb->ccb->ccb_h.path); - ahc_set_ccb_status(scb->ccb, CAM_CMD_TIMEOUT); + ahcsetccbstatus(scb->ccb, CAM_CMD_TIMEOUT); ahc_freeze_ccb(scb->ccb); ahc_done(ahc, scb); @@ -5273,7 +5503,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, ahc->qinfifonext = qinpos; while (qinpos != qintail) { - scbp = ahc->scb_data->scbarray[ahc->qinfifo[qinpos]]; + scbp = &ahc->scb_data->scbarray[ahc->qinfifo[qinpos]]; if (ahc_match_scb(scbp, target, channel, lun, tag)) { /* * We found an scb that needs to be removed. @@ -5281,7 +5511,7 @@ ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, switch (action) { case SEARCH_COMPLETE: if (ahc_ccb_status(scbp->ccb) == CAM_REQ_INPROG) - ahc_set_ccb_status(scbp->ccb, status); + ahcsetccbstatus(scbp->ccb, status); ahc_freeze_ccb(scbp->ccb); ahc_done(ahc, scbp); break; @@ -5431,7 +5661,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, "SCB index == %d, yet numscbs == %d.", scb_index, ahc->scb_data->numscbs); } - scbp = ahc->scb_data->scbarray[scb_index]; + scbp = &ahc->scb_data->scbarray[scb_index]; if (ahc_match_scb(scbp, target, channel, lun, tag)) { next = ahc_abort_wscb(ahc, next, prev); @@ -5458,7 +5688,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, ahc_outb(ahc, SCBPTR, i); scbid = ahc_inb(ahc, SCB_TAG); if (scbid < ahc->scb_data->numscbs) { - scbp = ahc->scb_data->scbarray[scbid]; + scbp = &ahc->scb_data->scbarray[scbid]; if (ahc_match_scb(scbp, target, channel, lun, tag)) { ahc_add_curscb_to_free_list(ahc); } @@ -5481,7 +5711,7 @@ ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, ccb_h = ccb_h->sim_links.le.le_next; if (ahc_match_scb(scbp, target, channel, lun, tag)) { if (ahc_ccb_status(scbp->ccb) == CAM_REQ_INPROG) - ahc_set_ccb_status(scbp->ccb, status); + ahcsetccbstatus(scbp->ccb, status); ahc_freeze_ccb(scbp->ccb); ahc_done(ahc, scbp); found++; @@ -5519,7 +5749,7 @@ ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel, "SCB index == %d, yet numscbs == %d.", scb_index, ahc->scb_data->numscbs); } - scbp = ahc->scb_data->scbarray[scb_index]; + scbp = &ahc->scb_data->scbarray[scb_index]; if (ahc_match_scb(scbp, target, channel, lun, tag)) { next = ahc_rem_scb_from_disc_list(ahc, prev, next); @@ -5806,7 +6036,7 @@ ahc_calc_residual(struct scb *scb) sg = scb->sg_count - resid_sgs - 1/*first SG*/; while (resid_sgs > 0) { - resid += scb->ahc_dma[sg].len; + resid += scb->sg_list[sg].len; sg++; resid_sgs--; } @@ -5905,7 +6135,7 @@ ahc_update_pending_syncrates(struct ahc_softc *ahc) u_int our_id, remote_id; u_int control; - pending_scb = ahc->scb_data->scbarray[scb_tag]; + pending_scb = &ahc->scb_data->scbarray[scb_tag]; if (pending_scb->flags == SCB_FREE) continue; pending_hscb = pending_scb->hscb; diff --git a/sys/dev/aic7xxx/aic7xxx.h b/sys/dev/aic7xxx/aic7xxx.h index cf3037a..5f1bb86 100644 --- a/sys/dev/aic7xxx/aic7xxx.h +++ b/sys/dev/aic7xxx/aic7xxx.h @@ -34,7 +34,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aic7xxx.h,v 1.5 1999/01/14 06:14:15 gibbs Exp $ + * $Id: aic7xxx.h,v 1.6 1999/03/05 23:35:47 gibbs Exp $ */ #ifndef _AIC7XXX_H_ @@ -43,22 +43,31 @@ #include "ahc.h" /* for NAHC from config */ #include "opt_aic7xxx.h" /* for config options */ -#include /* for pcici_t */ +#include /* For device_t */ +#ifndef MAX +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +/* + * The maximum transfer per S/G segment. + */ #define AHC_MAXTRANSFER_SIZE 0x00ffffff /* limited by 24bit counter */ -#define AHC_NSEG 32 /* The number of dma segments supported. - * AHC_NSEG can be maxed out at 256 entries, - * but the kernel will never need to transfer - * such a large (1MB) request. To reduce the - * driver's memory consumption, we reduce the - * max to 32. 16 would work if all transfers - * are paged alined since the kernel will only - * generate at most a 64k transfer, but to - * handle non-page aligned transfers, you need - * 17, so we round to the next power of two - * to make allocating SG space easy and - * efficient. - */ + +/* + * The number of dma segments supported. The current implementation limits + * us to 255 S/G entries (this may change to be unlimited at some point). + * To reduce the driver's memory consumption, we further limit the number + * supported to be sufficient to handle the largest mapping supported by + * the kernel, MAXPHYS. Assuming the transfer is as fragmented as possible + * and unaligned, this turns out to be the number of paged sized transfers + * in MAXPHYS plus an extra element to handle any unaligned residual. + */ +#define AHC_NSEG (MIN(btoc(MAXPHYS) + 1, 255)) #define AHC_SCB_MAX 255 /* * Up to 255 SCBs on some types of aic7xxx @@ -75,10 +84,6 @@ * wrap point of an 8bit counter. */ -#if defined(__FreeBSD__) -extern u_long ahc_unit; -#endif - struct ahc_dma_seg { u_int32_t addr; u_int32_t len; @@ -138,7 +143,6 @@ typedef enum { * SRAM, we use the default target * settings. */ - AHC_INDIRECT_PAGING = 0x008, AHC_SHARED_SRAM = 0x010, AHC_LARGE_SEEPROM = 0x020,/* Uses C56_66 not C46 */ AHC_RESET_BUS_A = 0x040, @@ -228,28 +232,13 @@ struct hardware_scb { struct scb { struct hardware_scb *hscb; - STAILQ_ENTRY(scb) links; /* for chaining */ + SLIST_ENTRY(scb) links; /* for chaining */ union ccb *ccb; /* the ccb for this cmd */ - scb_flag flags; - bus_dmamap_t dmamap; - struct ahc_dma_seg *ahc_dma;/* Pointer to SG segments */ - u_int32_t ahc_dmaphys;/* Phsical address of SG list */ - u_int sg_count;/* How full ahc_dma_seg is */ -}; - -struct scb_data { - struct hardware_scb *hscbs; /* Array of hardware SCBs */ - struct scb *scbarray[AHC_SCB_MAX]; /* Array of kernel SCBs */ - STAILQ_HEAD(, scb) free_scbs; /* - * Pool of SCBs ready to be assigned - * commands to execute. - */ - u_int8_t numscbs; - u_int8_t maxhscbs; /* Number of SCBs on the card */ - u_int8_t maxscbs; /* - * Max SCBs we allocate total including - * any that will force us to page SCBs - */ + scb_flag flags; + bus_dmamap_t dmamap; + struct ahc_dma_seg *sg_list; + bus_addr_t sg_list_phys; + u_int sg_count;/* How full ahc_dma_seg is */ }; /* @@ -402,10 +391,45 @@ typedef enum { MSG_TYPE_TARGET_MSGIN = 0x04 } ahc_msg_type; +struct sg_map_node { + bus_dmamap_t sg_dmamap; + bus_addr_t sg_physaddr; + struct ahc_dma_seg* sg_vaddr; + SLIST_ENTRY(sg_map_node) links; +}; + +struct scb_data { + struct hardware_scb *hscbs; /* Array of hardware SCBs */ + struct scb *scbarray; /* Array of kernel SCBs */ + SLIST_HEAD(, scb) free_scbs; /* + * Pool of SCBs ready to be assigned + * commands to execute. + */ + struct scsi_sense_data *sense; /* Per SCB sense data */ + + /* + * "Bus" addresses of our data structures. + */ + bus_dma_tag_t hscb_dmat; /* dmat for our hardware SCB array */ + bus_dmamap_t hscb_dmamap; + bus_addr_t hscb_busaddr; + bus_dma_tag_t sense_dmat; + bus_dmamap_t sense_dmamap; + bus_addr_t sense_busaddr; + bus_dma_tag_t sg_dmat; /* dmat for our sg segments */ + SLIST_HEAD(, sg_map_node) sg_maps; + u_int8_t numscbs; + u_int8_t maxhscbs; /* Number of SCBs on the card */ + u_int8_t init_level; /* + * How far we've initialized + * this structure. + */ +}; + struct ahc_softc { bus_space_tag_t tag; bus_space_handle_t bsh; - bus_dma_tag_t dmat; + bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */ struct scb_data *scb_data; /* @@ -447,14 +471,14 @@ struct ahc_softc { /* Command Queues */ u_int8_t qoutfifonext; u_int8_t qinfifonext; - u_int8_t qoutfifo[256]; - u_int8_t qinfifo[256]; + u_int8_t *qoutfifo; + u_int8_t *qinfifo; /* * 256 byte array storing the SCBID of outstanding * untagged SCBs indexed by TCL. */ - u_int8_t untagged_scbs[256]; + u_int8_t *untagged_scbs; /* * Hooks into the XPT. @@ -482,7 +506,7 @@ struct ahc_softc { * PCI error interrupt handler. */ int unsolicited_ints; - pcici_t pci_config_id; + device_t device; /* * Target incoming command FIFO. @@ -501,13 +525,22 @@ struct ahc_softc { u_int msgout_index; /* Current index in msgout */ u_int msgin_index; /* Current index in msgin */ + int regs_res_type; + int regs_res_id; + int irq_res_type; + struct resource *regs; + struct resource *irq; + void *ih; + bus_dma_tag_t parent_dmat; + bus_dma_tag_t shared_data_dmat; + bus_dmamap_t shared_data_dmamap; + bus_addr_t shared_data_busaddr; + /* Number of enabled target mode device on this card */ u_int enabled_luns; - /* - * "Bus" addresses of our data structures. - */ - u_int32_t hscb_busaddr; + /* Initialization level of this data structure */ + u_int init_level; }; struct full_ahc_softc { @@ -530,10 +563,11 @@ extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */ char *ahc_name(struct ahc_softc *ahc); -struct ahc_softc *ahc_alloc(int unit, u_int32_t io_base, - vm_offset_t maddr, ahc_chip chip, - ahc_feature features, ahc_flag flags, - struct scb_data *scb_data); +struct ahc_softc* + ahc_alloc(device_t dev, struct resource *regs, int regs_type, + int regs_id, bus_dma_tag_t parent_dmat, ahc_chip chip, + ahc_feature features, ahc_flag flags, + struct scb_data *scb_data); int ahc_reset(struct ahc_softc *ahc); void ahc_free(struct ahc_softc *); int ahc_probe_scbs(struct ahc_softc *); diff --git a/sys/dev/aic7xxx/aicasm/aicasm_symbol.c b/sys/dev/aic7xxx/aicasm/aicasm_symbol.c index f808e89..0704baa 100644 --- a/sys/dev/aic7xxx/aicasm/aicasm_symbol.c +++ b/sys/dev/aic7xxx/aicasm/aicasm_symbol.c @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aicasm_symbol.c,v 1.4 1997/09/27 19:37:30 gibbs Exp $ + * $Id: aicasm_symbol.c,v 1.5 1998/09/15 07:24:17 gibbs Exp $ */ @@ -128,10 +128,10 @@ symtable_close() DBT data; while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) { - symbol_t *cursym; + symbol_t *stored_ptr; - cursym = *(symbol_t **)data.data; - symbol_delete(cursym); + memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); + symbol_delete(stored_ptr); } symtable->close(symtable); } @@ -145,9 +145,10 @@ symbol_t * symtable_get(name) char *name; { - DBT key; - DBT data; - int retval; + symbol_t *stored_ptr; + DBT key; + DBT data; + int retval; key.data = (void *)name; key.size = strlen(name); @@ -176,7 +177,8 @@ symtable_get(name) /* NOTREACHED */ } } - return (*(symbol_t **)data.data); + memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); + return (stored_ptr); } symbol_node_t * @@ -327,7 +329,7 @@ symtable_dump(ofile) while (symtable->seq(symtable, &key, &data, flag) == 0) { symbol_t *cursym; - cursym = *(symbol_t **)data.data; + memcpy(&cursym, data.data, sizeof(cursym)); switch(cursym->type) { case REGISTER: case SCBLOC: diff --git a/sys/dev/aic7xxx/aicasm_symbol.c b/sys/dev/aic7xxx/aicasm_symbol.c index f808e89..0704baa 100644 --- a/sys/dev/aic7xxx/aicasm_symbol.c +++ b/sys/dev/aic7xxx/aicasm_symbol.c @@ -25,7 +25,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: aicasm_symbol.c,v 1.4 1997/09/27 19:37:30 gibbs Exp $ + * $Id: aicasm_symbol.c,v 1.5 1998/09/15 07:24:17 gibbs Exp $ */ @@ -128,10 +128,10 @@ symtable_close() DBT data; while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) { - symbol_t *cursym; + symbol_t *stored_ptr; - cursym = *(symbol_t **)data.data; - symbol_delete(cursym); + memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); + symbol_delete(stored_ptr); } symtable->close(symtable); } @@ -145,9 +145,10 @@ symbol_t * symtable_get(name) char *name; { - DBT key; - DBT data; - int retval; + symbol_t *stored_ptr; + DBT key; + DBT data; + int retval; key.data = (void *)name; key.size = strlen(name); @@ -176,7 +177,8 @@ symtable_get(name) /* NOTREACHED */ } } - return (*(symbol_t **)data.data); + memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); + return (stored_ptr); } symbol_node_t * @@ -327,7 +329,7 @@ symtable_dump(ofile) while (symtable->seq(symtable, &key, &data, flag) == 0) { symbol_t *cursym; - cursym = *(symbol_t **)data.data; + memcpy(&cursym, data.data, sizeof(cursym)); switch(cursym->type) { case REGISTER: case SCBLOC: -- cgit v1.1