diff options
author | scottl <scottl@FreeBSD.org> | 2007-12-12 05:55:03 +0000 |
---|---|---|
committer | scottl <scottl@FreeBSD.org> | 2007-12-12 05:55:03 +0000 |
commit | 08536bf15543e6d8bffef1874897e7b7f7145865 (patch) | |
tree | c6052c69e3483520de68c4fa40ccdc4fe660fc59 /sys/dev/amr | |
parent | 5929e7ecb673101b3cb117fc8af4281cc71b3d0d (diff) | |
download | FreeBSD-src-08536bf15543e6d8bffef1874897e7b7f7145865.zip FreeBSD-src-08536bf15543e6d8bffef1874897e7b7f7145865.tar.gz |
Rewrite the DMA code paths from being an impenitrable maze of special cases
to a much saner and simplier unified code path. Along the way, fix various
CAM nits and bugs so that the passthrough works correctly for all cases.
Diffstat (limited to 'sys/dev/amr')
-rw-r--r-- | sys/dev/amr/amr.c | 488 | ||||
-rw-r--r-- | sys/dev/amr/amr_cam.c | 91 | ||||
-rw-r--r-- | sys/dev/amr/amr_pci.c | 93 | ||||
-rw-r--r-- | sys/dev/amr/amrvar.h | 24 |
4 files changed, 260 insertions, 436 deletions
diff --git a/sys/dev/amr/amr.c b/sys/dev/amr/amr.c index c864d63..d65cdc1 100644 --- a/sys/dev/amr/amr.c +++ b/sys/dev/amr/amr.c @@ -140,9 +140,9 @@ static int amr_mapcmd(struct amr_command *ac); static void amr_unmapcmd(struct amr_command *ac); static int amr_start(struct amr_command *ac); static void amr_complete(void *context, int pending); -static void amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); -static void amr_setup_dma64map(void *arg, bus_dma_segment_t *segs, int nsegments, int error); -static void amr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); +static void amr_setup_sg(void *arg, bus_dma_segment_t *segs, int nsegments, int error); +static void amr_setup_data(void *arg, bus_dma_segment_t *segs, int nsegments, int error); +static void amr_setup_ccb(void *arg, bus_dma_segment_t *segs, int nsegments, int error); /* * Status monitoring @@ -572,9 +572,6 @@ amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, adapter = (ali.ui.fcs.adapno) ^ 'm' << 8; - ap = malloc(sizeof(struct amr_passthrough), - M_AMR, M_WAITOK | M_ZERO); - mb = (void *)&ali.mbox[0]; if ((ali.mbox[0] == FC_DEL_LOGDRV && ali.mbox[2] == OP_DEL_LOGDRV) || /* delete */ @@ -587,6 +584,12 @@ amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, } if (ali.mbox[0] == AMR_CMD_PASS) { + mtx_lock(&sc->amr_list_lock); + while ((ac = amr_alloccmd(sc)) == NULL) + msleep(sc, &sc->amr_list_lock, PPAUSE, "amrioc", hz); + mtx_unlock(&sc->amr_list_lock); + ap = &ac->ac_ccb->ccb_pthru; + error = copyin((void *)(uintptr_t)mb->mb_physaddr, ap, sizeof(struct amr_passthrough)); if (error) @@ -603,21 +606,16 @@ amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, break; } - mtx_lock(&sc->amr_list_lock); - while ((ac = amr_alloccmd(sc)) == NULL) - msleep(sc, &sc->amr_list_lock, PPAUSE, "amrioc", hz); - - ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT|AMR_CMD_CCB_DATAIN|AMR_CMD_CCB_DATAOUT; + ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT|AMR_CMD_CCB; bzero(&ac->ac_mailbox, sizeof(ac->ac_mailbox)); ac->ac_mailbox.mb_command = AMR_CMD_PASS; ac->ac_flags = ac_flags; - ac->ac_data = ap; - ac->ac_length = sizeof(struct amr_passthrough); - ac->ac_ccb_data = dp; - ac->ac_ccb_length = ap->ap_data_transfer_length; + ac->ac_data = dp; + ac->ac_length = ap->ap_data_transfer_length; temp = (void *)(uintptr_t)ap->ap_data_transfer_address; + mtx_lock(&sc->amr_list_lock); error = amr_wait_command(ac); mtx_unlock(&sc->amr_list_lock); if (error) @@ -706,8 +704,6 @@ amr_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, mtx_unlock(&sc->amr_list_lock); if (dp != NULL) free(dp, M_AMR); - if (ap != NULL) - free(ap, M_AMR); return(error); } @@ -729,7 +725,7 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t * unsigned long au_length; unsigned char *au_cmd; int *au_statusp, au_direction; - int error, ac_flags = 0; + int error; struct amr_passthrough *ap; /* 60 bytes */ int logical_drives_changed = 0; @@ -832,8 +828,6 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t * } /* Allocate this now before the mutex gets held */ - if (au_cmd[0] == AMR_CMD_PASS) - ap = malloc(sizeof(struct amr_passthrough), M_AMR, M_WAITOK|M_ZERO); mtx_lock(&sc->amr_list_lock); while ((ac = amr_alloccmd(sc)) == NULL) @@ -843,6 +837,9 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t * if (au_cmd[0] == AMR_CMD_PASS) { int len; + ap = &ac->ac_ccb->ccb_pthru; + bzero(ap, sizeof(struct amr_passthrough)); + /* copy cdb */ len = au_cmd[2]; ap->ap_cdb_length = len; @@ -860,13 +857,8 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t * /* XXX what about the request-sense area? does the caller want it? */ /* build command */ - ac->ac_data = ap; - ac->ac_length = sizeof(struct amr_passthrough); - ac->ac_ccb_data = dp; - ac->ac_ccb_length = au_length; - ac->ac_mailbox.mb_command = AMR_CMD_PASS; - ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT|AMR_CMD_CCB_DATAIN|AMR_CMD_CCB_DATAOUT; + ac->ac_flags = AMR_CMD_CCB; } else { /* direct command to controller */ @@ -878,14 +870,13 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t * mbi->mb_param = au_cmd[2]; mbi->mb_pad[0] = au_cmd[3]; mbi->mb_drive = au_cmd[4]; - - /* build the command */ - ac->ac_data = dp; - ac->ac_length = au_length; - ac_flags = AMR_CMD_DATAIN|AMR_CMD_DATAOUT; + ac->ac_flags = 0; } - ac->ac_flags = ac_flags; + /* build the command */ + ac->ac_data = dp; + ac->ac_length = au_length; + ac->ac_flags |= AMR_CMD_DATAIN|AMR_CMD_DATAOUT; /* run the command */ error = amr_wait_command(ac); @@ -899,7 +890,7 @@ amr_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int32_t flag, d_thread_t * } debug(2, "copyout %ld bytes from %p -> %p", au_length, dp, au_buffer); if (dp != NULL) - debug(2, "%jd", (uintptr_t)dp); + debug(2, "%p status 0x%x", dp, ac->ac_status); *au_statusp = ac->ac_status; out: @@ -913,8 +904,6 @@ out: mtx_unlock(&sc->amr_list_lock); if (dp != NULL) free(dp, M_AMR); - if (ap != NULL) - free(ap, M_AMR); #ifndef LSI if (logical_drives_changed) @@ -1420,21 +1409,24 @@ amr_setup_polled_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err) { struct amr_command *ac = arg; struct amr_softc *sc = ac->ac_sc; - int flags; + int mb_channel; - flags = 0; - if (ac->ac_flags & AMR_CMD_DATAIN) - flags |= BUS_DMASYNC_PREREAD; - if (ac->ac_flags & AMR_CMD_DATAOUT) - flags |= BUS_DMASYNC_PREWRITE; + amr_setup_sg(arg, segs, nsegs, err); + /* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */ + mb_channel = ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel; + if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG && + ((mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG) || + (mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG))) + ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param = ac->ac_nsegments; + + ac->ac_mailbox.mb_nsgelem = ac->ac_nsegments; + ac->ac_mailbox.mb_physaddr = ac->ac_mb_physaddr; if (AC_IS_SG64(ac)) { - amr_setup_dma64map(arg, segs, nsegs, err); - bus_dmamap_sync(sc->amr_buffer64_dmat,ac->ac_dma64map, flags); - } else { - amr_setup_dmamap(arg, segs, nsegs, err); - bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap, flags); + ac->ac_sg64_hi = 0; + ac->ac_sg64_lo = ac->ac_sgbusaddr; } + sc->amr_poll_command1(sc, ac); } @@ -1445,8 +1437,6 @@ amr_setup_polled_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err) static int amr_quartz_poll_command(struct amr_command *ac) { - bus_dma_tag_t tag; - bus_dmamap_t datamap; struct amr_softc *sc = ac->ac_sc; int error; @@ -1455,17 +1445,17 @@ amr_quartz_poll_command(struct amr_command *ac) error = 0; if (AC_IS_SG64(ac)) { - tag = sc->amr_buffer64_dmat; - datamap = ac->ac_dma64map; + ac->ac_tag = sc->amr_buffer64_dmat; + ac->ac_datamap = ac->ac_dma64map; } else { - tag = sc->amr_buffer_dmat; - datamap = ac->ac_dmamap; + ac->ac_tag = sc->amr_buffer_dmat; + ac->ac_datamap = ac->ac_dmamap; } /* now we have a slot, we can map the command (unmapped in amr_complete) */ if (ac->ac_data != 0) { - if (bus_dmamap_load(tag, datamap, ac->ac_data, ac->ac_length, - amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) { + if (bus_dmamap_load(ac->ac_tag, ac->ac_datamap, ac->ac_data, + ac->ac_length, amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) { error = 1; } } else { @@ -1494,10 +1484,7 @@ amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac) device_printf(sc->amr_dev, "adapter is busy\n"); mtx_unlock(&sc->amr_hw_lock); if (ac->ac_data != NULL) { - if (AC_IS_SG64(ac)) - bus_dmamap_unload(sc->amr_buffer64_dmat, ac->ac_dma64map); - else - bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); + bus_dmamap_unload(ac->ac_tag, ac->ac_datamap); } ac->ac_status=0; return(1); @@ -1535,17 +1522,12 @@ amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac) /* unmap the command's data buffer */ if (ac->ac_flags & AMR_CMD_DATAIN) { - bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap, - BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, BUS_DMASYNC_POSTREAD); } if (ac->ac_flags & AMR_CMD_DATAOUT) { - bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap, - BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, BUS_DMASYNC_POSTWRITE); } - if (AC_IS_SG64(ac)) - bus_dmamap_unload(sc->amr_buffer64_dmat, ac->ac_dma64map); - else - bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); + bus_dmamap_unload(ac->ac_tag, ac->ac_datamap); return(error); } @@ -1574,289 +1556,141 @@ amr_freeslot(struct amr_command *ac) * These functions may be safely called multiple times on a given command. */ static void -amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) +amr_setup_sg(void *arg, bus_dma_segment_t *segs, int nsegments, int error) { struct amr_command *ac = (struct amr_command *)arg; struct amr_sgentry *sg; - int i; - u_int8_t *sgc; + struct amr_sg64entry *sg64; + int flags, i; debug_called(3); - /* get base address of s/g table */ - sg = ac->ac_sg.sg32; - - /* save data physical address */ - - /* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */ - if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG && ( - ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG || - ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG)) { - sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param); - } else { - sgc = &ac->ac_mailbox.mb_nsgelem; - } - - /* decide whether we need to populate the s/g table */ - if (nsegments < 2) { - *sgc = 0; - ac->ac_mailbox.mb_nsgelem = 0; - ac->ac_mailbox.mb_physaddr = segs[0].ds_addr; - } else { - ac->ac_mailbox.mb_nsgelem = nsegments; - *sgc = nsegments; - /* XXX Setting these to 0 might not be needed. */ - ac->ac_sg64_lo = 0; - ac->ac_sg64_hi = 0; - ac->ac_mailbox.mb_physaddr = ac->ac_sgbusaddr; - for (i = 0; i < nsegments; i++, sg++) { - sg->sg_addr = segs[i].ds_addr; - sg->sg_count = segs[i].ds_len; - } - } - -} - -static void -amr_setup_dma64map(void *arg, bus_dma_segment_t *segs, int nsegments, int error) -{ - struct amr_command *ac = (struct amr_command *)arg; - struct amr_sg64entry *sg; - int i; - u_int8_t *sgc; - - debug_called(3); - - /* get base address of s/g table */ - sg = ac->ac_sg.sg64; - - /* save data physical address */ - - /* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */ - if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG && ( - ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG || - ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG)) { - sgc = &(((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param); - } else { - sgc = &ac->ac_mailbox.mb_nsgelem; - } - - ac->ac_mailbox.mb_nsgelem = nsegments; - *sgc = nsegments; - ac->ac_sg64_hi = 0; - ac->ac_sg64_lo = ac->ac_sgbusaddr; - ac->ac_mailbox.mb_physaddr = 0xffffffff; - for (i = 0; i < nsegments; i++, sg++) { - sg->sg_addr = segs[i].ds_addr; - sg->sg_count = segs[i].ds_len; - } -} - -static void -amr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) -{ - struct amr_command *ac = (struct amr_command *)arg; - struct amr_softc *sc = ac->ac_sc; - struct amr_sgentry *sg; - struct amr_passthrough *ap = (struct amr_passthrough *)ac->ac_data; - struct amr_ext_passthrough *aep = (struct amr_ext_passthrough *)ac->ac_data; - int i; + if (error) + printf("amr_setup_sg: error %d\n", error); /* get base address of s/g table */ sg = ac->ac_sg.sg32; + sg64 = ac->ac_sg.sg64; - /* decide whether we need to populate the s/g table */ - if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) { - if (nsegments < 2) { - aep->ap_no_sg_elements = 0; - aep->ap_data_transfer_address = segs[0].ds_addr; - } else { - /* save s/g table information in passthrough */ - aep->ap_no_sg_elements = nsegments; - aep->ap_data_transfer_address = ac->ac_sgbusaddr; - /* - * populate s/g table (overwrites previous call which mapped the - * passthrough) - */ - for (i = 0; i < nsegments; i++, sg++) { - sg->sg_addr = segs[i].ds_addr; - sg->sg_count = segs[i].ds_len; - debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count); - } + if (AC_IS_SG64(ac)) { + ac->ac_nsegments = nsegments; + ac->ac_mb_physaddr = 0xffffffff; + for (i = 0; i < nsegments; i++, sg64++) { + sg64->sg_addr = segs[i].ds_addr; + sg64->sg_count = segs[i].ds_len; } - debug(3, "slot %d %d segments at 0x%x\n", ac->ac_slot, - aep->ap_no_sg_elements, aep->ap_data_transfer_address); } else { + /* decide whether we need to populate the s/g table */ if (nsegments < 2) { - ap->ap_no_sg_elements = 0; - ap->ap_data_transfer_address = segs[0].ds_addr; + ac->ac_nsegments = 0; + ac->ac_mb_physaddr = segs[0].ds_addr; } else { - /* save s/g table information in passthrough */ - ap->ap_no_sg_elements = nsegments; - ap->ap_data_transfer_address = ac->ac_sgbusaddr; - /* - * populate s/g table (overwrites previous call which mapped the - * passthrough) - */ + ac->ac_nsegments = nsegments; + ac->ac_mb_physaddr = ac->ac_sgbusaddr; for (i = 0; i < nsegments; i++, sg++) { sg->sg_addr = segs[i].ds_addr; sg->sg_count = segs[i].ds_len; - debug(3, " %d: 0x%x/%d", i, sg->sg_addr, sg->sg_count); } } - debug(3, "slot %d %d segments at 0x%x\n", ac->ac_slot, - ap->ap_no_sg_elements, ap->ap_data_transfer_address); } - if (ac->ac_flags & AMR_CMD_CCB_DATAIN) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, - BUS_DMASYNC_PREREAD); - if (ac->ac_flags & AMR_CMD_CCB_DATAOUT) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, - BUS_DMASYNC_PREWRITE); - if ((ac->ac_flags & (AMR_CMD_CCB_DATAIN | AMR_CMD_CCB_DATAOUT)) == 0) - panic("no direction for ccb?\n"); + flags = 0; if (ac->ac_flags & AMR_CMD_DATAIN) - bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD); + flags |= BUS_DMASYNC_PREREAD; if (ac->ac_flags & AMR_CMD_DATAOUT) - bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE); - + flags |= BUS_DMASYNC_PREWRITE; + bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, flags); ac->ac_flags |= AMR_CMD_MAPPED; - - if (sc->amr_submit_command(ac) == EBUSY) { - amr_freeslot(ac); - amr_requeue_ready(ac); - } } static void -amr_setup_ccb64map(void *arg, bus_dma_segment_t *segs, int nsegments, int error) +amr_setup_data(void *arg, bus_dma_segment_t *segs, int nsegs, int err) { - struct amr_command *ac = (struct amr_command *)arg; - struct amr_softc *sc = ac->ac_sc; - struct amr_sg64entry *sg; - struct amr_passthrough *ap = (struct amr_passthrough *)ac->ac_data; - struct amr_ext_passthrough *aep = (struct amr_ext_passthrough *)ac->ac_data; - int i; + struct amr_command *ac = arg; + struct amr_softc *sc = ac->ac_sc; + int mb_channel; - /* get base address of s/g table */ - sg = ac->ac_sg.sg64; + amr_setup_sg(arg, segs, nsegs, err); - /* decide whether we need to populate the s/g table */ - if( ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS ) { - /* save s/g table information in passthrough */ - aep->ap_no_sg_elements = nsegments; - aep->ap_data_transfer_address = ac->ac_sgbusaddr; - /* - * populate s/g table (overwrites previous call which mapped the - * passthrough) - */ - for (i = 0; i < nsegments; i++, sg++) { - sg->sg_addr = segs[i].ds_addr; - sg->sg_count = segs[i].ds_len; - debug(3, " %d: 0x%lx/%d", i, (u_long)sg->sg_addr, sg->sg_count); - } - debug(3, "slot %d %d segments at 0x%x\n", ac->ac_slot, - aep->ap_no_sg_elements, aep->ap_data_transfer_address); - } else { - /* save s/g table information in passthrough */ - ap->ap_no_sg_elements = nsegments; - ap->ap_data_transfer_address = ac->ac_sgbusaddr; - /* - * populate s/g table (overwrites previous call which mapped the - * passthrough) - */ - for (i = 0; i < nsegments; i++, sg++) { - sg->sg_addr = segs[i].ds_addr; - sg->sg_count = segs[i].ds_len; - debug(3, " %d: 0x%lx/%d", i, (u_long)sg->sg_addr, sg->sg_count); - } - debug(3, "slot %d %d segments at 0x%x\n", ac->ac_slot, - ap->ap_no_sg_elements, ap->ap_data_transfer_address); + /* for AMR_CMD_CONFIG Read/Write the s/g count goes elsewhere */ + mb_channel = ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_channel; + if (ac->ac_mailbox.mb_command == AMR_CMD_CONFIG && + ((mb_channel == AMR_CONFIG_READ_NVRAM_CONFIG) || + (mb_channel == AMR_CONFIG_WRITE_NVRAM_CONFIG))) + ((struct amr_mailbox_ioctl *)&ac->ac_mailbox)->mb_param = ac->ac_nsegments; + + ac->ac_mailbox.mb_nsgelem = ac->ac_nsegments; + ac->ac_mailbox.mb_physaddr = ac->ac_mb_physaddr; + if (AC_IS_SG64(ac)) { + ac->ac_sg64_hi = 0; + ac->ac_sg64_lo = ac->ac_sgbusaddr; } - if (ac->ac_flags & AMR_CMD_CCB_DATAIN) - bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_ccb_dma64map, - BUS_DMASYNC_PREREAD); - if (ac->ac_flags & AMR_CMD_CCB_DATAOUT) - bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_ccb_dma64map, - BUS_DMASYNC_PREWRITE); - if ((ac->ac_flags & (AMR_CMD_CCB_DATAIN | AMR_CMD_CCB_DATAOUT)) == 0) - panic("no direction for ccb?\n"); - - if (ac->ac_flags & AMR_CMD_DATAIN) - bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_dma64map, - BUS_DMASYNC_PREREAD); - if (ac->ac_flags & AMR_CMD_DATAOUT) - bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_dma64map, - BUS_DMASYNC_PREWRITE); - - ac->ac_flags |= AMR_CMD_MAPPED; if (sc->amr_submit_command(ac) == EBUSY) { amr_freeslot(ac); amr_requeue_ready(ac); } } - + static void -amr_setup_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegments, - int error) +amr_setup_ccb(void *arg, bus_dma_segment_t *segs, int nsegs, int err) { - struct amr_command *ac = (struct amr_command *)arg; - struct amr_softc *sc = ac->ac_sc; - - amr_setup_dmamap(arg, segs, nsegments, error); - - if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, - ac->ac_ccb_data, ac->ac_ccb_length, amr_setup_ccbmap, ac, - 0) == EINPROGRESS) { - sc->amr_state |= AMR_STATE_QUEUE_FRZN; + struct amr_command *ac = arg; + struct amr_softc *sc = ac->ac_sc; + struct amr_passthrough *ap = &ac->ac_ccb->ccb_pthru; + struct amr_ext_passthrough *aep = &ac->ac_ccb->ccb_epthru; + + /* Set up the mailbox portion of the command to point at the ccb */ + ac->ac_mailbox.mb_nsgelem = 0; + ac->ac_mailbox.mb_physaddr = ac->ac_ccb_busaddr; + + amr_setup_sg(arg, segs, nsegs, err); + + switch (ac->ac_mailbox.mb_command) { + case AMR_CMD_EXTPASS: + aep->ap_no_sg_elements = ac->ac_nsegments; + aep->ap_data_transfer_address = ac->ac_mb_physaddr; + break; + case AMR_CMD_PASS: + ap->ap_no_sg_elements = ac->ac_nsegments; + ap->ap_data_transfer_address = ac->ac_mb_physaddr; + break; + default: + panic("Unknown ccb command"); } -} - -static void -amr_setup_dma64map_cb(void *arg, bus_dma_segment_t *segs, int nsegments, - int error) -{ - struct amr_command *ac = (struct amr_command *)arg; - struct amr_softc *sc = ac->ac_sc; - - amr_setup_dma64map(arg, segs, nsegments, error); - if (bus_dmamap_load(sc->amr_buffer64_dmat, ac->ac_ccb_dma64map, - ac->ac_ccb_data, ac->ac_ccb_length, amr_setup_ccb64map, ac, - 0) == EINPROGRESS) { - sc->amr_state |= AMR_STATE_QUEUE_FRZN; + if (sc->amr_submit_command(ac) == EBUSY) { + amr_freeslot(ac); + amr_requeue_ready(ac); } } static int amr_mapcmd(struct amr_command *ac) { - bus_dma_tag_t tag; - bus_dmamap_t datamap; bus_dmamap_callback_t *cb; struct amr_softc *sc = ac->ac_sc; debug_called(3); if (AC_IS_SG64(ac)) { - tag = sc->amr_buffer64_dmat; - datamap = ac->ac_dma64map; - cb = amr_setup_dma64map_cb; + ac->ac_tag = sc->amr_buffer64_dmat; + ac->ac_datamap = ac->ac_dma64map; } else { - tag = sc->amr_buffer_dmat; - datamap = ac->ac_dmamap; - cb = amr_setup_dmamap_cb; + ac->ac_tag = sc->amr_buffer_dmat; + ac->ac_datamap = ac->ac_dmamap; } + if (ac->ac_flags & AMR_CMD_CCB) + cb = amr_setup_ccb; + else + cb = amr_setup_data; + /* if the command involves data at all, and hasn't been mapped */ if ((ac->ac_flags & AMR_CMD_MAPPED) == 0 && (ac->ac_data != NULL)) { - if (ac->ac_ccb_data == NULL) - cb = amr_setup_data_dmamap; /* map the data buffers into bus space and build the s/g list */ - if (bus_dmamap_load(tag, datamap, ac->ac_data, ac->ac_length, - cb, ac, 0) == EINPROGRESS) { + if (bus_dmamap_load(ac->ac_tag, ac->ac_datamap, ac->ac_data, + ac->ac_length, cb, ac, 0) == EINPROGRESS) { sc->amr_state |= AMR_STATE_QUEUE_FRZN; } } else { @@ -1872,7 +1706,6 @@ amr_mapcmd(struct amr_command *ac) static void amr_unmapcmd(struct amr_command *ac) { - struct amr_softc *sc = ac->ac_sc; int flag; debug_called(3); @@ -1888,63 +1721,14 @@ amr_unmapcmd(struct amr_command *ac) if (ac->ac_flags & AMR_CMD_DATAOUT) flag |= BUS_DMASYNC_POSTWRITE; - if (AC_IS_SG64(ac)) { - bus_dmamap_sync(sc->amr_buffer64_dmat, ac->ac_dma64map, flag); - bus_dmamap_unload(sc->amr_buffer64_dmat, ac->ac_dma64map); - } else { - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, flag); - bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); - } + bus_dmamap_sync(ac->ac_tag, ac->ac_datamap, flag); + bus_dmamap_unload(ac->ac_tag, ac->ac_datamap); } - if (ac->ac_ccb_data != NULL) { - - flag = 0; - if (ac->ac_flags & AMR_CMD_CCB_DATAIN) - flag |= BUS_DMASYNC_POSTREAD; - if (ac->ac_flags & AMR_CMD_CCB_DATAOUT) - flag |= BUS_DMASYNC_POSTWRITE; - - if (AC_IS_SG64(ac)) { - bus_dmamap_sync(sc->amr_buffer64_dmat,ac->ac_ccb_dma64map,flag); - bus_dmamap_unload(sc->amr_buffer64_dmat, ac->ac_ccb_dma64map); - } else { - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, flag); - bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_ccb_dmamap); - } - } ac->ac_flags &= ~AMR_CMD_MAPPED; } } -static void -amr_setup_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegs, int err) -{ - struct amr_command *ac = arg; - struct amr_softc *sc = ac->ac_sc; - int flags; - - flags = 0; - if (ac->ac_flags & AMR_CMD_DATAIN) - flags |= BUS_DMASYNC_PREREAD; - if (ac->ac_flags & AMR_CMD_DATAOUT) - flags |= BUS_DMASYNC_PREWRITE; - - if (AC_IS_SG64(ac)) { - amr_setup_dma64map(arg, segs, nsegs, err); - bus_dmamap_sync(sc->amr_buffer64_dmat,ac->ac_dma64map, flags); - } else { - amr_setup_dmamap(arg, segs, nsegs, err); - bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap, flags); - } - ac->ac_flags |= AMR_CMD_MAPPED; - - if (sc->amr_submit_command(ac) == EBUSY) { - amr_freeslot(ac); - amr_requeue_ready(ac); - } -} - /******************************************************************************** * Take a command and give it to the controller, returns 0 if successful, or * EBUSY if the command should be retried later. @@ -2124,8 +1908,9 @@ amr_alloccmd(struct amr_softc *sc) ac->ac_flags = 0; ac->ac_bio = NULL; ac->ac_data = NULL; - ac->ac_ccb_data = NULL; ac->ac_complete = NULL; + ac->ac_tag = NULL; + ac->ac_datamap = NULL; return(ac); } @@ -2177,12 +1962,15 @@ amr_alloccmd_cluster(struct amr_softc *sc) ac->ac_sg.sg32 = sc->amr_sgtable + (ac->ac_slot * AMR_NSEG); } - if (bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap) || - bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_ccb_dmamap) || - (AMR_IS_SG64(sc) && - (bus_dmamap_create(sc->amr_buffer64_dmat, 0,&ac->ac_dma64map) || - bus_dmamap_create(sc->amr_buffer64_dmat, 0, &ac->ac_ccb_dma64map)))) - break; + ac->ac_ccb = sc->amr_ccb + ac->ac_slot; + ac->ac_ccb_busaddr = sc->amr_ccb_busaddr + + (ac->ac_slot * sizeof(union amr_ccb)); + + if (bus_dmamap_create(sc->amr_buffer_dmat, 0, &ac->ac_dmamap)) + break; + if (AMR_IS_SG64(sc) && + (bus_dmamap_create(sc->amr_buffer64_dmat, 0,&ac->ac_dma64map))) + break; amr_releasecmd(ac); if (++nextslot > sc->amr_maxio) break; @@ -2202,10 +1990,8 @@ amr_freecmd_cluster(struct amr_command_cluster *acc) for (i = 0; i < AMR_CMD_CLUSTERCOUNT; i++) { bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_dmamap); - bus_dmamap_destroy(sc->amr_buffer_dmat, acc->acc_command[i].ac_ccb_dmamap); if (AMR_IS_SG64(sc)) bus_dmamap_destroy(sc->amr_buffer64_dmat, acc->acc_command[i].ac_dma64map); - bus_dmamap_destroy(sc->amr_buffer64_dmat, acc->acc_command[i].ac_ccb_dma64map); } free(acc, M_AMR); } diff --git a/sys/dev/amr/amr_cam.c b/sys/dev/amr/amr_cam.c index 9ad465e..65913d1 100644 --- a/sys/dev/amr/amr_cam.c +++ b/sys/dev/amr/amr_cam.c @@ -222,16 +222,16 @@ amr_cam_action(struct cam_sim *sim, union ccb *ccb) /* check the CDB length */ if (csio->cdb_len > AMR_MAX_EXTCDB_LEN) - ccbh->status = CAM_REQ_CMP_ERR; + ccbh->status = CAM_REQ_INVALID; if ((csio->cdb_len > AMR_MAX_CDB_LEN) && (sc->support_ext_cdb == 0)) - ccbh->status = CAM_REQ_CMP_ERR; + ccbh->status = CAM_REQ_INVALID; /* check that the CDB pointer is not to a physical address */ if ((ccbh->flags & CAM_CDB_POINTER) && (ccbh->flags & CAM_CDB_PHYS)) - ccbh->status = CAM_REQ_CMP_ERR; + ccbh->status = CAM_REQ_INVALID; /* * if there is data transfer, it must be to/from a virtual * address @@ -239,10 +239,10 @@ amr_cam_action(struct cam_sim *sim, union ccb *ccb) if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) { if (ccbh->flags & CAM_DATA_PHYS) /* we can't map it */ - ccbh->status = CAM_REQ_CMP_ERR; + ccbh->status = CAM_REQ_INVALID; if (ccbh->flags & CAM_SCATTER_VALID) /* we want to do the s/g setup */ - ccbh->status = CAM_REQ_CMP_ERR; + ccbh->status = CAM_REQ_INVALID; } /* @@ -252,7 +252,7 @@ amr_cam_action(struct cam_sim *sim, union ccb *ccb) * devices appear echoed. */ if (csio->ccb_h.target_lun != 0) - ccbh->status = CAM_REQ_CMP_ERR; + ccbh->status = CAM_DEV_NOT_THERE; /* if we're happy with the request, queue it for attention */ if (ccbh->status == CAM_REQ_INPROG) { @@ -405,13 +405,15 @@ amr_cam_command(struct amr_softc *sc, struct amr_command **acp) * Build a passthrough command. */ + /* construct command */ + if ((ac = amr_alloccmd(sc)) == NULL) { + error = ENOMEM; + goto out; + } + /* construct passthrough */ if (sc->support_ext_cdb ) { - if ((aep = malloc(sizeof(*aep), M_AMRCAM, M_NOWAIT | M_ZERO)) - == NULL) { - error = ENOMEM; - goto out; - } + aep = &ac->ac_ccb->ccb_epthru; aep->ap_timeout = 2; aep->ap_ars = 1; aep->ap_request_sense_length = 14; @@ -437,11 +439,7 @@ amr_cam_command(struct amr_softc *sc, struct amr_command **acp) aep->ap_scsi_id, aep->ap_logical_drive_no); } else { - if ((ap = malloc(sizeof(*ap), M_AMRCAM, M_NOWAIT | M_ZERO)) - == NULL) { - error = ENOMEM; - goto out; - } + ap = &ac->ac_ccb->ccb_pthru; ap->ap_timeout = 0; ap->ap_ars = 1; ap->ap_request_sense_length = 14; @@ -467,30 +465,20 @@ amr_cam_command(struct amr_softc *sc, struct amr_command **acp) ap->ap_scsi_id, ap->ap_logical_drive_no); } - /* construct command */ - if ((ac = amr_alloccmd(sc)) == NULL) { - error = ENOMEM; - goto out; - } - - ac->ac_flags |= AMR_CMD_DATAOUT | AMR_CMD_DATAIN; + ac->ac_flags |= AMR_CMD_CCB; - ac->ac_ccb_data = csio->data_ptr; - ac->ac_ccb_length = csio->dxfer_len; + ac->ac_data = csio->data_ptr; + ac->ac_length = csio->dxfer_len; if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) - ac->ac_flags |= AMR_CMD_CCB_DATAIN; + ac->ac_flags |= AMR_CMD_DATAIN; if ((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT) - ac->ac_flags |= AMR_CMD_CCB_DATAOUT; + ac->ac_flags |= AMR_CMD_DATAOUT; ac->ac_private = csio; ac->ac_complete = amr_cam_complete; if ( sc->support_ext_cdb ) { - ac->ac_data = aep; - ac->ac_length = sizeof(*aep); ac->ac_mailbox.mb_command = AMR_CMD_EXTPASS; } else { - ac->ac_data = ap; - ac->ac_length = sizeof(*ap); ac->ac_mailbox.mb_command = AMR_CMD_PASS; } @@ -498,10 +486,6 @@ out: if (error != 0) { if (ac != NULL) amr_releasecmd(ac); - if (ap != NULL) - free(ap, M_AMRCAM); - if (aep != NULL) - free(aep, M_AMRCAM); if (csio != NULL) /* put it back and try again later */ amr_requeue_ccb(sc, (union ccb *)csio); @@ -532,19 +516,20 @@ amr_cam_complete(struct amr_command *ac) struct scsi_inquiry_data *inq; int scsi_status, cdb0; - ap = (struct amr_passthrough *)ac->ac_data; - aep = (struct amr_ext_passthrough *)ac->ac_data; + ap = &ac->ac_ccb->ccb_pthru; + aep = &ac->ac_ccb->ccb_epthru; csio = (struct ccb_scsiio *)ac->ac_private; inq = (struct scsi_inquiry_data *)csio->data_ptr; - if (ac->ac_length == sizeof(*ap)) - scsi_status = ap->ap_scsi_status; - else + if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS) scsi_status = aep->ap_scsi_status; + else + scsi_status = ap->ap_scsi_status; debug(1, "status 0x%x AP scsi_status 0x%x", ac->ac_status, scsi_status); - if (ac->ac_status != AMR_STATUS_SUCCESS) { + /* Make sure the status is sane */ + if ((ac->ac_status != AMR_STATUS_SUCCESS) && (scsi_status == 0)) { csio->ccb_h.status = CAM_REQ_CMP_ERR; goto out; } @@ -561,10 +546,10 @@ amr_cam_complete(struct amr_command *ac) /* handle passthrough SCSI status */ switch(scsi_status) { case 0: /* completed OK */ - if (ac->ac_length == sizeof(*ap)) - cdb0 = ap->ap_cdb[0]; - else + if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS) cdb0 = aep->ap_cdb[0]; + else + cdb0 = ap->ap_cdb[0]; if ((cdb0 == INQUIRY) && (SID_TYPE(inq) == T_DIRECT)) inq->device = (inq->device & 0xe0) | T_NODEVICE; csio->ccb_h.status = CAM_REQ_CMP; @@ -573,11 +558,11 @@ amr_cam_complete(struct amr_command *ac) case 0x02: csio->ccb_h.status = CAM_SCSI_STATUS_ERROR; csio->scsi_status = SCSI_STATUS_CHECK_COND; - if (ac->ac_length == sizeof(*ap)) - bcopy(ap->ap_request_sense_area, &csio->sense_data, + if (ac->ac_mailbox.mb_command == AMR_CMD_EXTPASS) + bcopy(aep->ap_request_sense_area, &csio->sense_data, AMR_MAX_REQ_SENSE_LEN); else - bcopy(aep->ap_request_sense_area, &csio->sense_data, + bcopy(ap->ap_request_sense_area, &csio->sense_data, AMR_MAX_REQ_SENSE_LEN); csio->sense_len = AMR_MAX_REQ_SENSE_LEN; csio->ccb_h.status |= CAM_AUTOSNS_VALID; @@ -590,20 +575,20 @@ amr_cam_complete(struct amr_command *ac) case 0xf0: case 0xf4: default: - csio->ccb_h.status = CAM_REQ_CMP_ERR; + /* + * Non-zero LUNs are already filtered, so there's no need + * to return CAM_DEV_NOT_THERE. + */ + csio->ccb_h.status = CAM_SEL_TIMEOUT; break; } out: - if (ac->ac_length == sizeof(*ap)) - free(ap, M_AMRCAM); - else - free(aep, M_AMRCAM); if ((csio->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) debug(2, "%*D\n", imin(csio->dxfer_len, 16), csio->data_ptr, " "); - mtx_unlock(&ac->ac_sc->amr_list_lock); + mtx_lock(&ac->ac_sc->amr_list_lock); xpt_done((union ccb *)csio); amr_releasecmd(ac); mtx_unlock(&ac->ac_sc->amr_list_lock); diff --git a/sys/dev/amr/amr_pci.c b/sys/dev/amr/amr_pci.c index dec96c0..d72a129 100644 --- a/sys/dev/amr/amr_pci.c +++ b/sys/dev/amr/amr_pci.c @@ -86,10 +86,10 @@ static int amr_pci_suspend(device_t dev); static int amr_pci_resume(device_t dev); static void amr_pci_intr(void *arg); static void amr_pci_free(struct amr_softc *sc); -static void amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); +static void amr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); static int amr_sglist_map(struct amr_softc *sc); -static void amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error); static int amr_setup_mbox(struct amr_softc *sc); +static int amr_ccb_map(struct amr_softc *sc); static u_int amr_force_sg32 = 0; TUNABLE_INT("hw.amr.force_sg32", &amr_force_sg32); @@ -303,7 +303,7 @@ amr_pci_attach(device_t dev) NULL, NULL, /* filter, filterarg */ MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ MAXBSIZE, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ + 0, /* flags */ busdma_lock_mutex, /* lockfunc */ &sc->amr_list_lock, /* lockarg */ &sc->amr_buffer_dmat)) { @@ -318,7 +318,7 @@ amr_pci_attach(device_t dev) NULL, NULL, /* filter, filterarg */ MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ MAXBSIZE, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ + 0, /* flags */ busdma_lock_mutex, /* lockfunc */ &sc->amr_list_lock, /* lockarg */ &sc->amr_buffer64_dmat)) { @@ -343,9 +343,13 @@ amr_pci_attach(device_t dev) */ if (amr_sglist_map(sc)) goto out; - debug(2, "s/g list mapped"); + if (amr_ccb_map(sc)) + goto out; + debug(2, "ccb mapped"); + + /* * Do bus-independant initialisation, bring controller online. */ @@ -469,7 +473,7 @@ amr_pci_intr(void *arg) { struct amr_softc *sc = (struct amr_softc *)arg; - debug_called(2); + debug_called(3); /* collect finished commands, queue anything waiting */ amr_done(sc); @@ -495,6 +499,12 @@ amr_pci_free(struct amr_softc *sc) if (sc->amr_buffer64_dmat) bus_dma_tag_destroy(sc->amr_buffer64_dmat); + /* free and destroy DMA memory and tag for passthrough pool */ + if (sc->amr_ccb) + bus_dmamem_free(sc->amr_ccb_dmat, sc->amr_ccb, sc->amr_ccb_dmamap); + if (sc->amr_ccb_dmat) + bus_dma_tag_destroy(sc->amr_ccb_dmat); + /* free and destroy DMA memory and tag for s/g lists */ if (sc->amr_sgtable) bus_dmamem_free(sc->amr_sg_dmat, sc->amr_sgtable, sc->amr_sg_dmamap); @@ -530,14 +540,14 @@ amr_pci_free(struct amr_softc *sc) * Allocate and map the scatter/gather table in bus space. */ static void -amr_sglist_map_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) +amr_sglist_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - struct amr_softc *sc = (struct amr_softc *)arg; + uint32_t *addr; debug_called(1); - /* save base of s/g table's address in bus space */ - sc->amr_sgbusaddr = segs->ds_addr; + addr = arg; + *addr = segs[0].ds_addr; } static int @@ -562,7 +572,7 @@ amr_sglist_map(struct amr_softc *sc) segsize = sizeof(struct amr_sgentry) * AMR_NSEG * AMR_MAXCMD; error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ - 1, 0, /* alignment,boundary */ + 512, 0, /* alignment,boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ @@ -597,7 +607,7 @@ retry: device_printf(sc->amr_dev, "can't allocate s/g table\n"); return(ENOMEM); } - bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, p, segsize, amr_sglist_map_helper, sc, 0); + bus_dmamap_load(sc->amr_sg_dmat, sc->amr_sg_dmamap, p, segsize, amr_sglist_helper, &sc->amr_sgbusaddr, 0); if (sc->amr_sgbusaddr < 0x2000) { debug(1, "s/g table too low (0x%x), reallocating\n", sc->amr_sgbusaddr); goto retry; @@ -613,25 +623,14 @@ retry: /******************************************************************************** * Allocate and set up mailbox areas for the controller (sc) * - * The basic mailbox structure should be 16-byte aligned. This means that the - * mailbox64 structure has 4 bytes hanging off the bottom. + * The basic mailbox structure should be 16-byte aligned. */ -static void -amr_setup_mbox_helper(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - struct amr_softc *sc = (struct amr_softc *)arg; - - debug_called(1); - - /* save phsyical base of the basic mailbox structure */ - sc->amr_mailboxphys = segs->ds_addr + offsetof(struct amr_mailbox64, mb); -} - static int amr_setup_mbox(struct amr_softc *sc) { int error; void *p; + uint32_t baddr; debug_called(1); @@ -666,13 +665,55 @@ amr_setup_mbox(struct amr_softc *sc) return(ENOMEM); } bus_dmamap_load(sc->amr_mailbox_dmat, sc->amr_mailbox_dmamap, p, - sizeof(struct amr_mailbox64), amr_setup_mbox_helper, sc, 0); + sizeof(struct amr_mailbox64), amr_sglist_helper, &baddr, 0); /* * Conventional mailbox is inside the mailbox64 region. */ + /* save physical base of the basic mailbox structure */ + sc->amr_mailboxphys = baddr + offsetof(struct amr_mailbox64, mb); bzero(p, sizeof(struct amr_mailbox64)); sc->amr_mailbox64 = (struct amr_mailbox64 *)p; sc->amr_mailbox = &sc->amr_mailbox64->mb; return(0); } + +static int +amr_ccb_map(struct amr_softc *sc) +{ + int ccbsize, error; + + /* + * Passthrough and Extended passthrough structures will share the same + * memory. + */ + ccbsize = sizeof(union amr_ccb) * AMR_MAXCMD; + error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ + 128, 0, /* alignment,boundary */ + BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + ccbsize, /* maxsize */ + 1, /* nsegments */ + ccbsize, /* maxsegsize */ + 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->amr_ccb_dmat); + if (error != 0) { + device_printf(sc->amr_dev, "can't allocate ccb tag\n"); + return (ENOMEM); + } + + error = bus_dmamem_alloc(sc->amr_ccb_dmat, (void **)&sc->amr_ccb, + BUS_DMA_NOWAIT, &sc->amr_ccb_dmamap); + if (error) { + device_printf(sc->amr_dev, "can't allocate ccb memory\n"); + return (ENOMEM); + } + bus_dmamap_load(sc->amr_ccb_dmat, sc->amr_ccb_dmamap, sc->amr_ccb, + ccbsize, amr_sglist_helper, &sc->amr_ccb_busaddr, 0); + bzero(sc->amr_ccb, ccbsize); + + return (0); +} + diff --git a/sys/dev/amr/amrvar.h b/sys/dev/amr/amrvar.h index 1fd78fd..0a39b1c 100644 --- a/sys/dev/amr/amrvar.h +++ b/sys/dev/amr/amrvar.h @@ -100,6 +100,12 @@ struct amr_logdrive #define AMR_CMD_CLUSTERSIZE (16 * 1024) +union amr_ccb { + struct amr_passthrough ccb_pthru; + struct amr_ext_passthrough ccb_epthru; + uint8_t bytes[128]; +}; + /* * Per-command control structure. */ @@ -121,8 +127,7 @@ struct amr_command int ac_flags; #define AMR_CMD_DATAIN (1<<0) #define AMR_CMD_DATAOUT (1<<1) -#define AMR_CMD_CCB_DATAIN (1<<2) -#define AMR_CMD_CCB_DATAOUT (1<<3) +#define AMR_CMD_CCB (1<<2) #define AMR_CMD_PRIORITY (1<<4) #define AMR_CMD_MAPPED (1<<5) #define AMR_CMD_SLEEP (1<<6) @@ -139,11 +144,13 @@ struct amr_command bus_dmamap_t ac_dmamap; bus_dmamap_t ac_dma64map; - void *ac_ccb_data; - size_t ac_ccb_length; - bus_dmamap_t ac_ccb_dmamap; - bus_dmamap_t ac_ccb_dma64map; + bus_dma_tag_t ac_tag; + bus_dmamap_t ac_datamap; + int ac_nsegments; + uint32_t ac_mb_physaddr; + union amr_ccb *ac_ccb; + uint32_t ac_ccb_busaddr; }; struct amr_command_cluster @@ -185,6 +192,11 @@ struct amr_softc bus_dma_tag_t amr_sg_dmat; /* s/g buffer DMA tag */ bus_dmamap_t amr_sg_dmamap; /* map for s/g buffers */ + union amr_ccb *amr_ccb; + uint32_t amr_ccb_busaddr; + bus_dma_tag_t amr_ccb_dmat; + bus_dmamap_t amr_ccb_dmamap; + /* controller limits and features */ int amr_nextslot; /* Next slot to use for newly allocated commands */ int amr_maxio; /* maximum number of I/O transactions */ |