1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-19 10:53:58 +00:00

Chain the bus_dmamap_load() calls when mapping a command with a data CCB

instead of doing the first load with the BUS_DMA_NOWAIT flag.  On 4.x with
PAE and > 4gb of RAM this proved disastrous if there weren't enough bounce
pages as amr_mapcmd() would return failure but the callback would later
fire once enough bounce pages were available and would then overwrite
another command's S/G list.

MFC after:	3 days
Submitted by:	scottl (4.x version)
Reviewed by:	scottl (port from 4.x to HEAD)
This commit is contained in:
John Baldwin 2006-07-17 19:45:47 +00:00
parent 99f08b7740
commit 44daafbccc
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=160443

View File

@ -1785,13 +1785,44 @@ amr_setup_ccb64map(void *arg, bus_dma_segment_t *segs, int nsegments, int error)
}
}
static void
amr_setup_dmamap_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_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;
}
}
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;
}
}
static int
amr_mapcmd(struct amr_command *ac)
{
bus_dma_tag_t tag;
bus_dmamap_t datamap, ccbmap;
bus_dmamap_t datamap;
bus_dmamap_callback_t *cb;
bus_dmamap_callback_t *ccb_cb;
struct amr_softc *sc = ac->ac_sc;
debug_called(3);
@ -1799,35 +1830,22 @@ amr_mapcmd(struct amr_command *ac)
if (AC_IS_SG64(ac)) {
tag = sc->amr_buffer64_dmat;
datamap = ac->ac_dma64map;
ccbmap = ac->ac_ccb_dma64map;
cb = amr_setup_dma64map;
ccb_cb = amr_setup_ccb64map;
cb = amr_setup_dma64map_cb;
} else {
tag = sc->amr_buffer_dmat;
datamap = ac->ac_dmamap;
ccbmap = ac->ac_ccb_dmamap;
cb = amr_setup_dmamap;
ccb_cb = amr_setup_ccbmap;
cb = amr_setup_dmamap_cb;
}
/* 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) {
/* 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,
amr_setup_data_dmamap, ac, 0) == EINPROGRESS) {
sc->amr_state |= AMR_STATE_QUEUE_FRZN;
}
} else {
if (bus_dmamap_load(tag, datamap, ac->ac_data, ac->ac_length,
cb, ac, BUS_DMA_NOWAIT) != 0) {
return (ENOMEM);
}
if (bus_dmamap_load(tag, ccbmap, ac->ac_ccb_data,
ac->ac_ccb_length, ccb_cb, ac, 0) == EINPROGRESS) {
sc->amr_state |= AMR_STATE_QUEUE_FRZN;
}
}
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) {
sc->amr_state |= AMR_STATE_QUEUE_FRZN;
}
} else {
if (sc->amr_submit_command(ac) == EBUSY) {
amr_freeslot(ac);