svn commit: r328936 - in head/sys/dev: mpr mps
Kenneth D. Merry
ken at FreeBSD.org
Tue Feb 6 15:58:24 UTC 2018
Author: ken
Date: Tue Feb 6 15:58:22 2018
New Revision: 328936
URL: https://svnweb.freebsd.org/changeset/base/328936
Log:
Diagnostic buffer fixes for the mps(4) and mpr(4) drivers.
In mp{r,s}_diag_register(), which is used to register diagnostic
buffers with the mp{r,s}(4) firmware, we allocate DMAable memory.
There were several issues here:
o No checking of the bus_dmamap_load() return value. If the load
failed or got deferred, mp{r,s}_diag_register() continued on as if
nothing had happened. We now check the return value and bail
out if it fails.
o No waiting for a deferred load callback. bus_dmamap_load()
calls a supplied callback when the mapping is done. This is
generally done immediately, but it can be deferred.
mp{r,s}_diag_register() did not check to see whether the callback
was already done before proceeding on. We now sleep until the
callback is done if it is deferred.
o No call to bus_dmamap_sync(... BUS_DMASYNC_PREREAD) after the
memory is allocated and loaded. This is necessary on some
platforms to synchronize host memory that is going to be updated
by a device.
Both drivers would also panic if the firmware was reinitialized while
a diagnostic buffer operation was in progress. This fixes that problem
as well. (The driver will reinitialize the firmware in various
circumstances, but the problem I ran into was that the firmware would
generate an IOC Fault due to a PCIe error.)
mp{r,s}var.h:
Add a new structure, struct mpr_busdma_context, that is
used for deferred busdma load callbacks.
Add a prototype for mp{r,s}_memaddr_wait_cb().
mp{r,s}.c:
Add a new busdma callback function, mp{r,s}_memaddr_wait_cb().
This provides synchronization for callers that want to
wait on a deferred bus_dmamap_load() callback.
mp{r,s}_user.c:
In bus_dmamap_register(), add a call to bus_dmamap_sync()
with the BUS_DMASYNC_PREREAD flag set after an allocation
is loaded.
Also, check the return value of bus_dmamap_load(). If it
fails, bail out. If it is EINPROGRESS, wait for the
callback to happen. We use an interruptible sleep (msleep
with PCATCH) and let the callback clean things up if we get
interrupted.
In mpr_diag_read_buffer() and mps_diag_read_buffer(), call
bus_dmamap_sync(..., BUS_DMASYNC_POSTREAD) before copying
the data out to make sure the data is in stable storage.
In mp{r,s}_post_fw_diag_buffer() and
mp{r,s}_release_fw_diag_buffer(), check the reply to see
whether it is NULL. It can be NULL (and the command non-NULL)
if the controller gets reinitialized while we're waiting for
the command to complete but the driver structures aren't
reallocated. The driver structures generally won't be
reallocated unless there is a firmware upgrade that changes
one of the IOCFacts.
When freeing diagnostic buffers in mp{r,s}_diag_register()
and mp{r,s}_diag_unregister(), zero/NULL out the buffer after
freeing it. This will prevent a duplicate free in some
situations.
Sponsored by: Spectra Logic
Reviewed by: mav, scottl
MFC after: 1 week
Differential Revision: D13453
Modified:
head/sys/dev/mpr/mpr.c
head/sys/dev/mpr/mpr_user.c
head/sys/dev/mpr/mprvar.h
head/sys/dev/mps/mps.c
head/sys/dev/mps/mps_user.c
head/sys/dev/mps/mpsvar.h
Modified: head/sys/dev/mpr/mpr.c
==============================================================================
--- head/sys/dev/mpr/mpr.c Tue Feb 6 15:41:45 2018 (r328935)
+++ head/sys/dev/mpr/mpr.c Tue Feb 6 15:58:22 2018 (r328936)
@@ -1183,6 +1183,42 @@ mpr_memaddr_cb(void *arg, bus_dma_segment_t *segs, int
*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)
{
Modified: head/sys/dev/mpr/mpr_user.c
==============================================================================
--- head/sys/dev/mpr/mpr_user.c Tue Feb 6 15:41:45 2018 (r328935)
+++ head/sys/dev/mpr/mpr_user.c Tue Feb 6 15:58:22 2018 (r328936)
@@ -1314,6 +1314,13 @@ mpr_post_fw_diag_buffer(struct mpr_softc *sc,
* 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 @@ mpr_release_fw_diag_buffer(struct mpr_softc *sc,
* 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 @@ mpr_diag_register(struct mpr_softc *sc, mpr_fw_diag_re
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 @@ mpr_diag_register(struct mpr_softc *sc, mpr_fw_diag_re
*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 @@ mpr_diag_register(struct mpr_softc *sc, mpr_fw_diag_re
&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 @@ mpr_diag_register(struct mpr_softc *sc, mpr_fw_diag_re
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 @@ mpr_diag_unregister(struct mpr_softc *sc,
*/
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 @@ mpr_diag_read_buffer(struct mpr_softc *sc,
*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
Modified: head/sys/dev/mpr/mprvar.h
==============================================================================
--- head/sys/dev/mpr/mprvar.h Tue Feb 6 15:41:45 2018 (r328935)
+++ head/sys/dev/mpr/mprvar.h Tue Feb 6 15:58:22 2018 (r328936)
@@ -265,6 +265,16 @@ struct mpr_event_handle {
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_detach_sas(struct mpr_softc *sc);
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 *);
Modified: head/sys/dev/mps/mps.c
==============================================================================
--- head/sys/dev/mps/mps.c Tue Feb 6 15:41:45 2018 (r328935)
+++ head/sys/dev/mps/mps.c Tue Feb 6 15:58:22 2018 (r328936)
@@ -111,6 +111,7 @@ static void mps_parse_debug(struct mps_softc *sc, char
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 @@ mps_memaddr_cb(void *arg, bus_dma_segment_t *segs, int
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
Modified: head/sys/dev/mps/mps_user.c
==============================================================================
--- head/sys/dev/mps/mps_user.c Tue Feb 6 15:41:45 2018 (r328935)
+++ head/sys/dev/mps/mps_user.c Tue Feb 6 15:58:22 2018 (r328936)
@@ -180,7 +180,7 @@ static int mps_user_event_report(struct mps_softc *sc,
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 @@ mps_post_fw_diag_buffer(struct mps_softc *sc,
* 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 @@ mps_release_fw_diag_buffer(struct mps_softc *sc,
* 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 @@ mps_diag_register(struct mps_softc *sc, mps_fw_diag_re
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 @@ mps_diag_register(struct mps_softc *sc, mps_fw_diag_re
*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 @@ mps_diag_register(struct mps_softc *sc, mps_fw_diag_re
&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 @@ mps_diag_register(struct mps_softc *sc, mps_fw_diag_re
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 @@ mps_diag_unregister(struct mps_softc *sc,
*/
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 @@ mps_diag_read_buffer(struct mps_softc *sc,
*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
Modified: head/sys/dev/mps/mpsvar.h
==============================================================================
--- head/sys/dev/mps/mpsvar.h Tue Feb 6 15:41:45 2018 (r328935)
+++ head/sys/dev/mps/mpsvar.h Tue Feb 6 15:58:22 2018 (r328936)
@@ -263,6 +263,16 @@ struct mps_event_handle {
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_detach_sas(struct mps_softc *sc);
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 *);
More information about the svn-src-head
mailing list