HomeFreeBSD

Diagnostic buffer fixes for the mps(4) and mpr(4) drivers.

Description

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

Details

Provenance
kenAuthored on
Reviewer
mav
Differential Revision
D13453: mpr(4) and mps(4) diagnostic path fixes
Parents
rS328935: crossbuild: Make the CHECK_TIME variable work on Linux
Branches
Unknown
Tags
Unknown