diff options
| author | Scott Long <scottl@FreeBSD.org> | 2004-12-05 23:48:17 +0000 |
|---|---|---|
| committer | Scott Long <scottl@FreeBSD.org> | 2004-12-05 23:48:17 +0000 |
| commit | dc0ff2140bedd8d151ca14867f4d0168fdbb7416 (patch) | |
| tree | 9eea5a1c633325715743c7bf5c0ce5678ab4b4c6 /sys/dev/amr | |
| parent | ec3724d9d012230086b02bf2db4e0841b00ff023 (diff) | |
Notes
Diffstat (limited to 'sys/dev/amr')
| -rw-r--r-- | sys/dev/amr/amr.c | 207 | ||||
| -rw-r--r-- | sys/dev/amr/amr_cam.c | 6 | ||||
| -rw-r--r-- | sys/dev/amr/amr_pci.c | 12 | ||||
| -rw-r--r-- | sys/dev/amr/amrvar.h | 2 |
4 files changed, 168 insertions, 59 deletions
diff --git a/sys/dev/amr/amr.c b/sys/dev/amr/amr.c index e5751439b2cf..8762a019159a 100644 --- a/sys/dev/amr/amr.c +++ b/sys/dev/amr/amr.c @@ -123,12 +123,15 @@ static void amr_freecmd_cluster(struct amr_command_cluster *acc); * Command processing. */ static int amr_bio_command(struct amr_softc *sc, struct amr_command **acp); -static int amr_wait_command(struct amr_command *ac); +static int amr_wait_command(struct amr_command *ac) __unused; static int amr_getslot(struct amr_command *ac); -static void amr_mapcmd(struct amr_command *ac); +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 int amr_start1(struct amr_softc *sc, 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_data_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error); /* * Status monitoring @@ -141,6 +144,7 @@ static void amr_periodic(void *data); static int amr_quartz_submit_command(struct amr_softc *sc); static int amr_quartz_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave); static int amr_quartz_poll_command(struct amr_command *ac); +static int amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac); static int amr_std_submit_command(struct amr_softc *sc); static int amr_std_get_work(struct amr_softc *sc, struct amr_mailbox *mbsave); @@ -208,6 +212,7 @@ amr_attach(struct amr_softc *sc) sc->amr_submit_command = amr_quartz_submit_command; sc->amr_get_work = amr_quartz_get_work; sc->amr_poll_command = amr_quartz_poll_command; + sc->amr_poll_command1 = amr_quartz_poll_command1; } else { sc->amr_submit_command = amr_std_submit_command; sc->amr_get_work = amr_std_get_work; @@ -705,9 +710,10 @@ amr_enquiry(struct amr_softc *sc, size_t bufsize, u_int8_t cmd, u_int8_t cmdsub, if ((ac = amr_alloccmd(sc)) == NULL) goto out; /* allocate the response structure */ - if ((result = malloc(bufsize, M_DEVBUF, M_NOWAIT)) == NULL) + if ((result = malloc(bufsize, M_DEVBUF, M_ZERO|M_NOWAIT)) == NULL) goto out; /* set command flags */ + ac->ac_flags |= AMR_CMD_PRIORITY | AMR_CMD_DATAIN; /* point the command at our data */ @@ -818,6 +824,10 @@ amr_startio(struct amr_softc *sc) /* spin until something prevents us from doing any work */ for (;;) { + /* Don't bother to queue commands no bounce buffers are available. */ + if (sc->amr_state & AMR_STATE_QUEUE_FRZN) + break; + /* try to get a ready command */ ac = amr_dequeue_ready(sc); @@ -991,6 +1001,17 @@ amr_std_poll_command(struct amr_command *ac) return(error); } +static void +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; + + amr_setup_dmamap(arg, segs, nsegs, err); + bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD); + sc->amr_poll_command1(sc, ac); +} + /******************************************************************************** * Take a command, submit it to the controller and busy-wait for it to return. * Returns nonzero on error. Can be safely called with interrupts enabled. @@ -999,15 +1020,31 @@ static int amr_quartz_poll_command(struct amr_command *ac) { struct amr_softc *sc = ac->ac_sc; - int s; - int error,count; + int s, error; debug_called(2); + s = splbio(); + error = 0; + /* now we have a slot, we can map the command (unmapped in amr_complete) */ - amr_mapcmd(ac); + if (ac->ac_data != 0) { + if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, + ac->ac_length, amr_setup_polled_dmamap, ac, BUS_DMA_NOWAIT) != 0) { + error = 1; + } + } else { + error = amr_quartz_poll_command1(sc, ac); + } - s = splbio(); + splx(s); + return (error); +} + +static int +amr_quartz_poll_command1(struct amr_softc *sc, struct amr_command *ac) +{ + int count, error; if ((sc->amr_state & AMR_STATE_CRASHDUMP) == 0) { count=0; @@ -1020,8 +1057,8 @@ amr_quartz_poll_command(struct amr_command *ac) if(sc->amr_busyslots) { device_printf(sc->amr_dev, "adapter is busy\n"); - splx(s); - amr_unmapcmd(ac); + if (ac->ac_data != NULL) + bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); ac->ac_status=0; return(1); } @@ -1051,10 +1088,9 @@ amr_quartz_poll_command(struct amr_command *ac) AMR_QPUT_IDB(sc, sc->amr_mailboxphys | AMR_QIDB_ACK); while(AMR_QGET_IDB(sc) & AMR_QIDB_ACK); - splx(s); - /* unmap the command's data buffer */ - amr_unmapcmd(ac); + bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); return(error); } @@ -1137,12 +1173,14 @@ amr_setup_dmamap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) } else { ac->ac_mailbox.mb_nsgelem = nsegments; *sgc = nsegments; - ac->ac_mailbox.mb_physaddr = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); + ac->ac_mailbox.mb_physaddr = sc->amr_sgbusaddr + + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); for (i = 0; i < nsegments; i++, sg++) { sg->sg_addr = segs[i].ds_addr; sg->sg_count = segs[i].ds_len; } } + } static void @@ -1166,16 +1204,21 @@ amr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) } else { /* save s/g table information in passthrough */ aep->ap_no_sg_elements = nsegments; - aep->ap_data_transfer_address = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); - /* populate s/g table (overwrites previous call which mapped the passthrough) */ + aep->ap_data_transfer_address = sc->amr_sgbusaddr + + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); + /* + * 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); } } - debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x", ac->ac_slot, - aep->ap_no_sg_elements, aep->ap_data_transfer_address, ac->ac_dataphys); + debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x\n", + ac->ac_slot, aep->ap_no_sg_elements, aep->ap_data_transfer_address, + ac->ac_dataphys); } else { if (nsegments < 2) { ap->ap_no_sg_elements = 0; @@ -1183,20 +1226,42 @@ amr_setup_ccbmap(void *arg, bus_dma_segment_t *segs, int nsegments, int error) } else { /* save s/g table information in passthrough */ ap->ap_no_sg_elements = nsegments; - ap->ap_data_transfer_address = sc->amr_sgbusaddr + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); - /* populate s/g table (overwrites previous call which mapped the passthrough) */ + ap->ap_data_transfer_address = sc->amr_sgbusaddr + + (ac->ac_slot * AMR_NSEG * sizeof(struct amr_sgentry)); + /* + * 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); } } - debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x", ac->ac_slot, - ap->ap_no_sg_elements, ap->ap_data_transfer_address, ac->ac_dataphys); + debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x", + ac->ac_slot, ap->ap_no_sg_elements, ap->ap_data_transfer_address, + ac->ac_dataphys); } + 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"); + + if (ac->ac_flags & AMR_CMD_DATAIN) + bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD); + if (ac->ac_flags & AMR_CMD_DATAOUT) + bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE); + + ac->ac_flags |= AMR_CMD_MAPPED; + + amr_start1(sc, ac); } -static void +static int amr_mapcmd(struct amr_command *ac) { struct amr_softc *sc = ac->ac_sc; @@ -1204,28 +1269,27 @@ amr_mapcmd(struct amr_command *ac) debug_called(3); /* if the command involves data at all, and hasn't been mapped */ - if (!(ac->ac_flags & AMR_CMD_MAPPED)) { - - if (ac->ac_data != NULL) { + if ((ac->ac_flags & AMR_CMD_MAPPED) == 0 && (ac->ac_data != NULL)) { + if (ac->ac_ccb_data == NULL) { /* map the data buffers into bus space and build the s/g list */ - bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, ac->ac_length, - amr_setup_dmamap, ac, 0); - if (ac->ac_flags & AMR_CMD_DATAIN) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREREAD); - if (ac->ac_flags & AMR_CMD_DATAOUT) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_PREWRITE); - } + if (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, + ac->ac_length, amr_setup_data_dmamap, ac, 0) == EINPROGRESS) { + sc->amr_state |= AMR_STATE_QUEUE_FRZN; + } + } else { - if (ac->ac_ccb_data != NULL) { - bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, ac->ac_ccb_data, ac->ac_ccb_length, - amr_setup_ccbmap, ac, 0); - 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 (bus_dmamap_load(sc->amr_buffer_dmat, ac->ac_dmamap, ac->ac_data, + ac->ac_length, amr_setup_dmamap, ac, BUS_DMA_NOWAIT) != 0){ + return (ENOMEM); + } + 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; + } } - ac->ac_flags |= AMR_CMD_MAPPED; } + return (0); } static void @@ -1240,23 +1304,47 @@ amr_unmapcmd(struct amr_command *ac) if (ac->ac_data != NULL) { if (ac->ac_flags & AMR_CMD_DATAIN) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_dmamap, + 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(sc->amr_buffer_dmat, ac->ac_dmamap, + BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_dmamap); } if (ac->ac_ccb_data != NULL) { if (ac->ac_flags & AMR_CMD_CCB_DATAIN) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_POSTREAD); + bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, + BUS_DMASYNC_POSTREAD); if (ac->ac_flags & AMR_CMD_CCB_DATAOUT) - bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, BUS_DMASYNC_POSTWRITE); + bus_dmamap_sync(sc->amr_buffer_dmat, ac->ac_ccb_dmamap, + BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(sc->amr_buffer_dmat, ac->ac_ccb_dmamap); + debug(3, "slot %d %d segments at 0x%x, passthrough at 0x%x\n", + ac->ac_slot, aep->ap_no_sg_elements, aep->ap_data_transfer_address, + ac->ac_dataphys); } 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; + + amr_setup_dmamap(arg, segs, nsegs, err); + + if (ac->ac_flags & AMR_CMD_DATAIN) + bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREREAD); + if (ac->ac_flags & AMR_CMD_DATAOUT) + bus_dmamap_sync(sc->amr_buffer_dmat,ac->ac_dmamap,BUS_DMASYNC_PREWRITE); + ac->ac_flags |= AMR_CMD_MAPPED; + + amr_start1(sc, ac); +} + /******************************************************************************** * Take a command and give it to the controller, returns 0 if successful, or * EBUSY if the command should be retried later. @@ -1264,20 +1352,37 @@ amr_unmapcmd(struct amr_command *ac) static int amr_start(struct amr_command *ac) { - struct amr_softc *sc = ac->ac_sc; - int done, s, i; + struct amr_softc *sc; + int error = 0; debug_called(3); /* mark command as busy so that polling consumer can tell */ + sc = ac->ac_sc; ac->ac_flags |= AMR_CMD_BUSY; /* get a command slot (freed in amr_done) */ if (amr_getslot(ac)) return(EBUSY); - /* now we have a slot, we can map the command (unmapped in amr_complete) */ - amr_mapcmd(ac); + /* Now we have a slot, we can map the command (unmapped in amr_complete). */ + if ((error = amr_mapcmd(ac)) == ENOMEM) { + /* + * Memroy resources are short, so free the slot and let this be tried + * later. + */ + sc->amr_busycmd[ac->ac_slot] = NULL; + sc->amr_busyslots--; + } + + return (error); +} + + +static int +amr_start1(struct amr_softc *sc, struct amr_command *ac) +{ + int done, s, i; /* mark the new mailbox we are going to copy in as busy */ ac->ac_mailbox.mb_busy = 1; @@ -1387,8 +1492,9 @@ amr_done(struct amr_softc *sc) break; /* no work */ } } - + /* if we've completed any commands, try posting some more */ + sc->amr_state &= ~AMR_STATE_QUEUE_FRZN; if (result) amr_startio(sc); @@ -1399,7 +1505,7 @@ amr_done(struct amr_softc *sc) else #endif amr_complete(sc, 0); - + return(result); } @@ -1443,6 +1549,7 @@ amr_complete(void *context, int pending) wakeup(sc); } } + amr_startio(sc); } /******************************************************************************** diff --git a/sys/dev/amr/amr_cam.c b/sys/dev/amr/amr_cam.c index a8c025223377..bd4cdb99c4fd 100644 --- a/sys/dev/amr/amr_cam.c +++ b/sys/dev/amr/amr_cam.c @@ -443,7 +443,7 @@ amr_cam_command(struct amr_softc *sc, struct amr_command **acp) goto out; } - ac->ac_flags |= AMR_CMD_DATAOUT; + ac->ac_flags |= AMR_CMD_DATAOUT | AMR_CMD_DATAIN; ac->ac_ccb_data = csio->data_ptr; ac->ac_ccb_length = csio->dxfer_len; @@ -501,7 +501,7 @@ amr_cam_complete(struct amr_command *ac) /* XXX note that we're ignoring ac->ac_status - good idea? */ - debug(1, "status 0x%x scsi_status 0x%x", ac->ac_status, ap->ap_scsi_status); + debug(1, "status 0x%x AP scsi_status 0x%x", ac->ac_status, ap->ap_scsi_status); /* * Hide disks from CAM so that they're not picked up and treated as 'normal' disks. @@ -564,7 +564,7 @@ amr_cam_complete_extcdb(struct amr_command *ac) /* XXX note that we're ignoring ac->ac_status - good idea? */ - debug(1, "status 0x%x scsi_status 0x%x", ac->ac_status, aep->ap_scsi_status); + debug(1, "status 0x%x AEP scsi_status 0x%x", ac->ac_status, aep->ap_scsi_status); /* * Hide disks from CAM so that they're not picked up and treated as 'normal' disks. diff --git a/sys/dev/amr/amr_pci.c b/sys/dev/amr/amr_pci.c index aa4094b5a7bf..f4cf4ac4356e 100644 --- a/sys/dev/amr/amr_pci.c +++ b/sys/dev/amr/amr_pci.c @@ -253,7 +253,7 @@ amr_pci_attach(device_t dev) NULL, NULL, /* filter, filterarg */ MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - BUS_DMA_ALLOCNOW, /* flags */ + 0, /* flags */ NULL, NULL, /* lockfunc, lockarg */ &sc->amr_parent_dmat)) { device_printf(dev, "can't allocate parent DMA tag\n"); @@ -265,12 +265,12 @@ amr_pci_attach(device_t dev) */ if (bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 1, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ MAXBSIZE, AMR_NSEG, /* maxsize, nsegments */ - BUS_SPACE_MAXSIZE_32BIT, /* maxsegsize */ - 0, /* flags */ + MAXBSIZE, /* maxsegsize */ + BUS_DMA_ALLOCNOW, /* flags */ busdma_lock_mutex, &Giant, /* lockfunc, lockarg */ &sc->amr_buffer_dmat)) { device_printf(sc->amr_dev, "can't allocate buffer DMA tag\n"); @@ -506,7 +506,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 */ - BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ segsize, 1, /* maxsize, nsegments */ @@ -578,7 +578,7 @@ amr_setup_mbox(struct amr_softc *sc) */ error = bus_dma_tag_create(sc->amr_parent_dmat, /* parent */ 16, 0, /* alignment, boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ sizeof(struct amr_mailbox) + 16, 1, /* maxsize, nsegments */ diff --git a/sys/dev/amr/amrvar.h b/sys/dev/amr/amrvar.h index 224ae44c7a21..ee0a27ca552c 100644 --- a/sys/dev/amr/amrvar.h +++ b/sys/dev/amr/amrvar.h @@ -188,6 +188,7 @@ struct amr_softc #define AMR_STATE_INTEN (1<<2) #define AMR_STATE_SHUTDOWN (1<<3) #define AMR_STATE_CRASHDUMP (1<<4) +#define AMR_STATE_QUEUE_FRZN (1<<5) /* per-controller queues */ struct bio_queue_head amr_bioq; /* pending I/O with no commands */ @@ -214,6 +215,7 @@ struct amr_softc int (* amr_submit_command)(struct amr_softc *sc); int (* amr_get_work)(struct amr_softc *sc, struct amr_mailbox *mbsave); int (*amr_poll_command)(struct amr_command *ac); + int (*amr_poll_command1)(struct amr_softc *sc, struct amr_command *ac); int support_ext_cdb; /* greater than 10 byte cdb support */ /* misc glue */ |
