Index: head/sys/dev/mpr/mpr.c =================================================================== --- head/sys/dev/mpr/mpr.c +++ head/sys/dev/mpr/mpr.c @@ -1183,6 +1183,42 @@ *addr = segs[0].ds_addr; } +void +mpr_memaddr_wait_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct mpr_busdma_context *ctx; + int need_unload, need_free; + + ctx = (struct mpr_busdma_context *)arg; + need_unload = 0; + need_free = 0; + + mpr_lock(ctx->softc); + ctx->error = error; + ctx->completed = 1; + if ((error == 0) && (ctx->abandoned == 0)) { + *ctx->addr = segs[0].ds_addr; + } else { + if (nsegs != 0) + need_unload = 1; + if (ctx->abandoned != 0) + need_free = 1; + } + if (need_free == 0) + wakeup(ctx); + + mpr_unlock(ctx->softc); + + if (need_unload != 0) { + bus_dmamap_unload(ctx->buffer_dmat, + ctx->buffer_dmamap); + *ctx->addr = 0; + } + + if (need_free != 0) + free(ctx, M_MPR); +} + static int mpr_alloc_queues(struct mpr_softc *sc) { Index: head/sys/dev/mpr/mpr_user.c =================================================================== --- head/sys/dev/mpr/mpr_user.c +++ head/sys/dev/mpr/mpr_user.c @@ -1314,6 +1314,13 @@ * Process POST reply. */ reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply; + if (reply == NULL) { + mpr_printf(sc, "%s: reply is NULL, probably due to " + "reinitialization", __func__); + status = MPR_DIAG_FAILURE; + goto done; + } + if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) { status = MPR_DIAG_FAILURE; @@ -1401,6 +1408,12 @@ * Process RELEASE reply. */ reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply; + if (reply == NULL) { + mpr_printf(sc, "%s: reply is NULL, probably due to " + "reinitialization", __func__); + status = MPR_DIAG_FAILURE; + goto done; + } if (((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) || pBuffer->owned_by_firmware) { status = MPR_DIAG_FAILURE; @@ -1436,15 +1449,19 @@ uint32_t *return_code) { mpr_fw_diagnostic_buffer_t *pBuffer; + struct mpr_busdma_context *ctx; uint8_t extended_type, buffer_type, i; uint32_t buffer_size; uint32_t unique_id; int status; + int error; extended_type = diag_register->ExtendedType; buffer_type = diag_register->BufferType; buffer_size = diag_register->RequestedBufferSize; unique_id = diag_register->UniqueId; + ctx = NULL; + error = 0; /* * Check for valid buffer type @@ -1493,7 +1510,7 @@ *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER; return (MPR_DIAG_FAILURE); } - if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ + if (bus_dma_tag_create( sc->mpr_parent_dmat, /* parent */ 1, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ @@ -1506,17 +1523,83 @@ &sc->fw_diag_dmat)) { mpr_dprint(sc, MPR_ERROR, "Cannot allocate FW diag buffer DMA tag\n"); - return (ENOMEM); - } + *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER; + status = MPR_DIAG_FAILURE; + goto bailout; + } if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer, BUS_DMA_NOWAIT, &sc->fw_diag_map)) { mpr_dprint(sc, MPR_ERROR, "Cannot allocate FW diag buffer memory\n"); - return (ENOMEM); - } - bzero(sc->fw_diag_buffer, buffer_size); - bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, sc->fw_diag_buffer, - buffer_size, mpr_memaddr_cb, &sc->fw_diag_busaddr, 0); + *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER; + status = MPR_DIAG_FAILURE; + goto bailout; + } + bzero(sc->fw_diag_buffer, buffer_size); + + ctx = malloc(sizeof(*ctx), M_MPR, M_WAITOK | M_ZERO); + if (ctx == NULL) { + device_printf(sc->mpr_dev, "%s: context malloc failed\n", + __func__); + *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER; + status = MPR_DIAG_FAILURE; + goto bailout; + } + ctx->addr = &sc->fw_diag_busaddr; + ctx->buffer_dmat = sc->fw_diag_dmat; + ctx->buffer_dmamap = sc->fw_diag_map; + ctx->softc = sc; + error = bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, + sc->fw_diag_buffer, buffer_size, mpr_memaddr_wait_cb, + ctx, 0); + if (error == EINPROGRESS) { + + /* XXX KDM */ + device_printf(sc->mpr_dev, "%s: Deferred bus_dmamap_load\n", + __func__); + /* + * Wait for the load to complete. If we're interrupted, + * bail out. + */ + mpr_lock(sc); + if (ctx->completed == 0) { + error = msleep(ctx, &sc->mpr_mtx, PCATCH, "mprwait", 0); + if (error != 0) { + /* + * We got an error from msleep(9). This is + * most likely due to a signal. Tell + * mpr_memaddr_wait_cb() that we've abandoned + * the context, so it needs to clean up when + * it is called. + */ + ctx->abandoned = 1; + + /* The callback will free this memory */ + ctx = NULL; + mpr_unlock(sc); + + device_printf(sc->mpr_dev, "Cannot " + "bus_dmamap_load FW diag buffer, error = " + "%d returned from msleep\n", error); + *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER; + status = MPR_DIAG_FAILURE; + goto bailout; + } + } + mpr_unlock(sc); + } + + if ((error != 0) || (ctx->error != 0)) { + device_printf(sc->mpr_dev, "Cannot bus_dmamap_load FW diag " + "buffer, %serror = %d\n", error ? "" : "callback ", + error ? error : ctx->error); + *return_code = MPR_FW_DIAG_ERROR_NO_BUFFER; + status = MPR_DIAG_FAILURE; + goto bailout; + } + + bus_dmamap_sync(sc->fw_diag_dmat, sc->fw_diag_map, BUS_DMASYNC_PREREAD); + pBuffer->size = buffer_size; /* @@ -1535,19 +1618,30 @@ pBuffer->unique_id = unique_id; status = mpr_post_fw_diag_buffer(sc, pBuffer, return_code); +bailout: + /* * In case there was a failure, free the DMA buffer. */ if (status == MPR_DIAG_FAILURE) { - if (sc->fw_diag_busaddr != 0) + if (sc->fw_diag_busaddr != 0) { bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); - if (sc->fw_diag_buffer != NULL) + sc->fw_diag_busaddr = 0; + } + if (sc->fw_diag_buffer != NULL) { bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, sc->fw_diag_map); - if (sc->fw_diag_dmat != NULL) + sc->fw_diag_buffer = NULL; + } + if (sc->fw_diag_dmat != NULL) { bus_dma_tag_destroy(sc->fw_diag_dmat); + sc->fw_diag_dmat = NULL; + } } + if (ctx != NULL) + free(ctx, M_MPR); + return (status); } @@ -1592,13 +1686,19 @@ */ pBuffer->unique_id = MPR_FW_DIAG_INVALID_UID; if (status == MPR_DIAG_SUCCESS) { - if (sc->fw_diag_busaddr != 0) + if (sc->fw_diag_busaddr != 0) { bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); - if (sc->fw_diag_buffer != NULL) + sc->fw_diag_busaddr = 0; + } + if (sc->fw_diag_buffer != NULL) { bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, sc->fw_diag_map); - if (sc->fw_diag_dmat != NULL) + sc->fw_diag_buffer = NULL; + } + if (sc->fw_diag_dmat != NULL) { bus_dma_tag_destroy(sc->fw_diag_dmat); + sc->fw_diag_dmat = NULL; + } } return (status); @@ -1707,6 +1807,10 @@ *return_code = MPR_FW_DIAG_ERROR_INVALID_PARAMETER; return (MPR_DIAG_FAILURE); } + + /* Sync the DMA map before we copy to userland. */ + bus_dmamap_sync(sc->fw_diag_dmat, sc->fw_diag_map, + BUS_DMASYNC_POSTREAD); /* * Copy the requested data from DMA to the diag_read_buffer. The DMA Index: head/sys/dev/mpr/mprvar.h =================================================================== --- head/sys/dev/mpr/mprvar.h +++ head/sys/dev/mpr/mprvar.h @@ -265,6 +265,16 @@ uint8_t mask[16]; }; +struct mpr_busdma_context { + int completed; + int abandoned; + int error; + bus_addr_t *addr; + struct mpr_softc *softc; + bus_dmamap_t buffer_dmamap; + bus_dma_tag_t buffer_dmat; +}; + struct mpr_queue { struct mpr_softc *sc; int qnum; @@ -752,6 +762,7 @@ int mpr_read_config_page(struct mpr_softc *, struct mpr_config_params *); int mpr_write_config_page(struct mpr_softc *, struct mpr_config_params *); void mpr_memaddr_cb(void *, bus_dma_segment_t *, int , int ); +void mpr_memaddr_wait_cb(void *, bus_dma_segment_t *, int , int ); void mpr_init_sge(struct mpr_command *cm, void *req, void *sge); int mpr_attach_user(struct mpr_softc *); void mpr_detach_user(struct mpr_softc *); Index: head/sys/dev/mps/mps.c =================================================================== --- head/sys/dev/mps/mps.c +++ head/sys/dev/mps/mps.c @@ -111,6 +111,7 @@ SYSCTL_NODE(_hw, OID_AUTO, mps, CTLFLAG_RD, 0, "MPS Driver Parameters"); MALLOC_DEFINE(M_MPT2, "mps", "mpt2 driver memory"); +MALLOC_DECLARE(M_MPSUSER); /* * Do a "Diagnostic Reset" aka a hard reset. This should get the chip out of @@ -1158,6 +1159,42 @@ addr = arg; *addr = segs[0].ds_addr; +} + +void +mps_memaddr_wait_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + struct mps_busdma_context *ctx; + int need_unload, need_free; + + ctx = (struct mps_busdma_context *)arg; + need_unload = 0; + need_free = 0; + + mps_lock(ctx->softc); + ctx->error = error; + ctx->completed = 1; + if ((error == 0) && (ctx->abandoned == 0)) { + *ctx->addr = segs[0].ds_addr; + } else { + if (nsegs != 0) + need_unload = 1; + if (ctx->abandoned != 0) + need_free = 1; + } + if (need_free == 0) + wakeup(ctx); + + mps_unlock(ctx->softc); + + if (need_unload != 0) { + bus_dmamap_unload(ctx->buffer_dmat, + ctx->buffer_dmamap); + *ctx->addr = 0; + } + + if (need_free != 0) + free(ctx, M_MPSUSER); } static int Index: head/sys/dev/mps/mps_user.c =================================================================== --- head/sys/dev/mps/mps_user.c +++ head/sys/dev/mps/mps_user.c @@ -180,7 +180,7 @@ static int mps_user_reg_access(struct mps_softc *sc, mps_reg_access_t *data); static int mps_user_btdh(struct mps_softc *sc, mps_btdh_mapping_t *data); -static MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls"); +MALLOC_DEFINE(M_MPSUSER, "mps_user", "Buffers for mps(4) ioctls"); /* Macros from compat/freebsd32/freebsd32.h */ #define PTRIN(v) (void *)(uintptr_t)(v) @@ -1222,6 +1222,12 @@ * Process POST reply. */ reply = (MPI2_DIAG_BUFFER_POST_REPLY *)cm->cm_reply; + if (reply == NULL) { + mps_printf(sc, "%s: reply is NULL, probably due to " + "reinitialization\n", __func__); + status = MPS_DIAG_FAILURE; + goto done; + } if ((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) { status = MPS_DIAG_FAILURE; @@ -1309,6 +1315,12 @@ * Process RELEASE reply. */ reply = (MPI2_DIAG_RELEASE_REPLY *)cm->cm_reply; + if (reply == NULL) { + mps_printf(sc, "%s: reply is NULL, probably due to " + "reinitialization\n", __func__); + status = MPS_DIAG_FAILURE; + goto done; + } if (((le16toh(reply->IOCStatus) & MPI2_IOCSTATUS_MASK) != MPI2_IOCSTATUS_SUCCESS) || pBuffer->owned_by_firmware) { status = MPS_DIAG_FAILURE; @@ -1344,15 +1356,19 @@ uint32_t *return_code) { mps_fw_diagnostic_buffer_t *pBuffer; + struct mps_busdma_context *ctx; uint8_t extended_type, buffer_type, i; uint32_t buffer_size; uint32_t unique_id; int status; + int error; extended_type = diag_register->ExtendedType; buffer_type = diag_register->BufferType; buffer_size = diag_register->RequestedBufferSize; unique_id = diag_register->UniqueId; + ctx = NULL; + error = 0; /* * Check for valid buffer type @@ -1401,7 +1417,7 @@ *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; return (MPS_DIAG_FAILURE); } - if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ + if (bus_dma_tag_create( sc->mps_parent_dmat, /* parent */ 1, 0, /* algnmnt, boundary */ BUS_SPACE_MAXADDR_32BIT,/* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ @@ -1414,17 +1430,84 @@ &sc->fw_diag_dmat)) { mps_dprint(sc, MPS_ERROR, "Cannot allocate FW diag buffer DMA tag\n"); - return (ENOMEM); - } - if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer, + *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; + status = MPS_DIAG_FAILURE; + goto bailout; + } + if (bus_dmamem_alloc(sc->fw_diag_dmat, (void **)&sc->fw_diag_buffer, BUS_DMA_NOWAIT, &sc->fw_diag_map)) { mps_dprint(sc, MPS_ERROR, "Cannot allocate FW diag buffer memory\n"); - return (ENOMEM); + *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; + status = MPS_DIAG_FAILURE; + goto bailout; } bzero(sc->fw_diag_buffer, buffer_size); - bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, sc->fw_diag_buffer, - buffer_size, mps_memaddr_cb, &sc->fw_diag_busaddr, 0); + + ctx = malloc(sizeof(*ctx), M_MPSUSER, M_WAITOK | M_ZERO); + if (ctx == NULL) { + device_printf(sc->mps_dev, "%s: context malloc failed\n", + __func__); + *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; + status = MPS_DIAG_FAILURE; + goto bailout; + } + ctx->addr = &sc->fw_diag_busaddr; + ctx->buffer_dmat = sc->fw_diag_dmat; + ctx->buffer_dmamap = sc->fw_diag_map; + ctx->softc = sc; + error = bus_dmamap_load(sc->fw_diag_dmat, sc->fw_diag_map, + sc->fw_diag_buffer, buffer_size, mps_memaddr_wait_cb, + ctx, 0); + + if (error == EINPROGRESS) { + + /* XXX KDM */ + device_printf(sc->mps_dev, "%s: Deferred bus_dmamap_load\n", + __func__); + /* + * Wait for the load to complete. If we're interrupted, + * bail out. + */ + mps_lock(sc); + if (ctx->completed == 0) { + error = msleep(ctx, &sc->mps_mtx, PCATCH, "mpswait", 0); + if (error != 0) { + /* + * We got an error from msleep(9). This is + * most likely due to a signal. Tell + * mpr_memaddr_wait_cb() that we've abandoned + * the context, so it needs to clean up when + * it is called. + */ + ctx->abandoned = 1; + + /* The callback will free this memory */ + ctx = NULL; + mps_unlock(sc); + + device_printf(sc->mps_dev, "Cannot " + "bus_dmamap_load FW diag buffer, error = " + "%d returned from msleep\n", error); + *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; + status = MPS_DIAG_FAILURE; + goto bailout; + } + } + mps_unlock(sc); + } + + if ((error != 0) || (ctx->error != 0)) { + device_printf(sc->mps_dev, "Cannot bus_dmamap_load FW diag " + "buffer, %serror = %d\n", error ? "" : "callback ", + error ? error : ctx->error); + *return_code = MPS_FW_DIAG_ERROR_NO_BUFFER; + status = MPS_DIAG_FAILURE; + goto bailout; + } + + bus_dmamap_sync(sc->fw_diag_dmat, sc->fw_diag_map, BUS_DMASYNC_PREREAD); + pBuffer->size = buffer_size; /* @@ -1443,19 +1526,29 @@ pBuffer->unique_id = unique_id; status = mps_post_fw_diag_buffer(sc, pBuffer, return_code); +bailout: /* * In case there was a failure, free the DMA buffer. */ if (status == MPS_DIAG_FAILURE) { - if (sc->fw_diag_busaddr != 0) + if (sc->fw_diag_busaddr != 0) { bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); - if (sc->fw_diag_buffer != NULL) + sc->fw_diag_busaddr = 0; + } + if (sc->fw_diag_buffer != NULL) { bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, sc->fw_diag_map); - if (sc->fw_diag_dmat != NULL) + sc->fw_diag_buffer = NULL; + } + if (sc->fw_diag_dmat != NULL) { bus_dma_tag_destroy(sc->fw_diag_dmat); + sc->fw_diag_dmat = NULL; + } } + if (ctx != NULL) + free(ctx, M_MPSUSER); + return (status); } @@ -1500,13 +1593,19 @@ */ pBuffer->unique_id = MPS_FW_DIAG_INVALID_UID; if (status == MPS_DIAG_SUCCESS) { - if (sc->fw_diag_busaddr != 0) + if (sc->fw_diag_busaddr != 0) { bus_dmamap_unload(sc->fw_diag_dmat, sc->fw_diag_map); - if (sc->fw_diag_buffer != NULL) + sc->fw_diag_busaddr = 0; + } + if (sc->fw_diag_buffer != NULL) { bus_dmamem_free(sc->fw_diag_dmat, sc->fw_diag_buffer, sc->fw_diag_map); - if (sc->fw_diag_dmat != NULL) + sc->fw_diag_buffer = NULL; + } + if (sc->fw_diag_dmat != NULL) { bus_dma_tag_destroy(sc->fw_diag_dmat); + sc->fw_diag_dmat = NULL; + } } return (status); @@ -1615,6 +1714,10 @@ *return_code = MPS_FW_DIAG_ERROR_INVALID_PARAMETER; return (MPS_DIAG_FAILURE); } + + /* Sync the DMA map before we copy to userland. */ + bus_dmamap_sync(sc->fw_diag_dmat, sc->fw_diag_map, + BUS_DMASYNC_POSTREAD); /* * Copy the requested data from DMA to the diag_read_buffer. The DMA Index: head/sys/dev/mps/mpsvar.h =================================================================== --- head/sys/dev/mps/mpsvar.h +++ head/sys/dev/mps/mpsvar.h @@ -263,6 +263,16 @@ u32 mask[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; }; +struct mps_busdma_context { + int completed; + int abandoned; + int error; + bus_addr_t *addr; + struct mps_softc *softc; + bus_dmamap_t buffer_dmamap; + bus_dma_tag_t buffer_dmat; +}; + struct mps_queue { struct mps_softc *sc; int qnum; @@ -719,6 +729,7 @@ int mps_read_config_page(struct mps_softc *, struct mps_config_params *); int mps_write_config_page(struct mps_softc *, struct mps_config_params *); void mps_memaddr_cb(void *, bus_dma_segment_t *, int , int ); +void mps_memaddr_wait_cb(void *, bus_dma_segment_t *, int , int ); void mpi_init_sge(struct mps_command *cm, void *req, void *sge); int mps_attach_user(struct mps_softc *); void mps_detach_user(struct mps_softc *);