summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorambrisko <ambrisko@FreeBSD.org>2007-06-04 16:39:22 +0000
committerambrisko <ambrisko@FreeBSD.org>2007-06-04 16:39:22 +0000
commit7261dfb6565a4be5ae3898d377820496ee90bfe3 (patch)
treef3672f1ac2d63131707571540fee279fd099d9e2 /sys
parent2f12bfb53bf6e3f5bcca552f363c6b8e040a3d84 (diff)
downloadFreeBSD-src-7261dfb6565a4be5ae3898d377820496ee90bfe3.zip
FreeBSD-src-7261dfb6565a4be5ae3898d377820496ee90bfe3.tar.gz
Add in a couple of things:
- In the ioctl path let command get queued up and return when complete _without_ blocking the driving waiting for the response. This way the driver doesn't "lock up" for ~30s during a flash command. Submitted by scottl. - Add a guard so that if a DCMD of 0 is sent down the ioctl path don't send it to the controller. Return with a status of OK. This is a little strange since MegaCli doesn't seem to like something and will issue some DCMD of 0. This doesn't happen under Linux. So the emulation needs to be improved but I'm not sure what. Another strange thing is that when a DCMD of 0 gets issued under i386 the controller returns OK but in amd64 the context is messed up. - Add a guard so the context has to be with-in the legal limit so we get a reasonable error assertion versus random panic. It's going to be a challenge to figure out why MegaCli is not totally happy and then sends some bogus commands. This means that flashing firmware via the Linux tool won't work since it generates a DCMD of 0 when it should be opening the firmware for a flash update. Without this problem flashing works fine. This means there is no publicly available tool to upgrade the RAID firmware under FreeBSD right now. I plan to MFC all of the mfi changes to 6.X shortly. This might not include the SCSI pass-through changes. Submitted by: scottl Reviewed by: scottl MFC after: 3 days
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/mfi/mfi.c51
-rw-r--r--sys/dev/mfi/mfivar.h1
2 files changed, 33 insertions, 19 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c
index 7bc7e41..583ecad 100644
--- a/sys/dev/mfi/mfi.c
+++ b/sys/dev/mfi/mfi.c
@@ -679,9 +679,21 @@ mfi_wait_command(struct mfi_softc *sc, struct mfi_command *cm)
mtx_assert(&sc->mfi_io_lock, MA_OWNED);
cm->cm_complete = NULL;
+
+ /*
+ * MegaCli can issue a DCMD of 0. In this case do nothing
+ * and return 0 to it as status
+ */
+ if (cm->cm_frame->dcmd.opcode == 0) {
+ cm->cm_frame->header.cmd_status = MFI_STAT_OK;
+ cm->cm_error = 0;
+ return (cm->cm_error);
+ }
mfi_enqueue_ready(cm);
mfi_startio(sc);
- return (msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0));
+ if ((cm->cm_flags & MFI_CMD_COMPLETED) == 0)
+ msleep(cm, &sc->mfi_io_lock, PRIBIO, "mfiwait", 0);
+ return (cm->cm_error);
}
void
@@ -779,9 +791,12 @@ mfi_intr(void *arg)
mtx_lock(&sc->mfi_io_lock);
while (ci != pi) {
context = sc->mfi_comms->hw_reply_q[ci];
- cm = &sc->mfi_commands[context];
- mfi_remove_busy(cm);
- mfi_complete(sc, cm);
+ if (context < sc->mfi_max_fw_cmds) {
+ cm = &sc->mfi_commands[context];
+ mfi_remove_busy(cm);
+ cm->cm_error = 0;
+ mfi_complete(sc, cm);
+ }
if (++ci == (sc->mfi_max_fw_cmds + 1)) {
ci = 0;
}
@@ -1537,14 +1552,18 @@ mfi_data_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
struct mfi_softc *sc;
int i, dir;
- if (error)
- return;
-
cm = (struct mfi_command *)arg;
sc = cm->cm_sc;
hdr = &cm->cm_frame->header;
sgl = cm->cm_sg;
+ if (error) {
+ printf("error %d in callback\n", error);
+ cm->cm_error = error;
+ mfi_complete(sc, cm);
+ return;
+ }
+
if ((sc->mfi_flags & MFI_FLAGS_SG64) == 0) {
for (i = 0; i < nsegs; i++) {
sgl->sg32[i].addr = segs[i].ds_addr;
@@ -1656,6 +1675,8 @@ mfi_complete(struct mfi_softc *sc, struct mfi_command *cm)
cm->cm_flags &= ~MFI_CMD_MAPPED;
}
+ cm->cm_flags |= MFI_CMD_COMPLETED;
+
if (cm->cm_complete != NULL)
cm->cm_complete(cm);
else
@@ -1846,8 +1867,7 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
cm->cm_total_frame_size = ioc->mfi_sgl_off;
cm->cm_sg =
(union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
- cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT
- | MFI_CMD_POLLED;
+ cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
cm->cm_len = cm->cm_frame->header.data_len;
cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
M_WAITOK | M_ZERO);
@@ -1873,16 +1893,13 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
}
mtx_lock(&sc->mfi_io_lock);
- if ((error = mfi_mapcmd(sc, cm)) != 0) {
+ if ((error = mfi_wait_command(sc, cm)) != 0) {
device_printf(sc->mfi_dev,
"Controller polled failed\n");
mtx_unlock(&sc->mfi_io_lock);
goto out;
}
- bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
- BUS_DMASYNC_POSTREAD);
- bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
mtx_unlock(&sc->mfi_io_lock);
temp = data;
@@ -2034,8 +2051,7 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
cm->cm_total_frame_size = l_ioc.lioc_sgl_off;
cm->cm_sg =
(union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
- cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT
- | MFI_CMD_POLLED;
+ cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT;
cm->cm_len = cm->cm_frame->header.data_len;
cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
M_WAITOK | M_ZERO);
@@ -2059,16 +2075,13 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
}
mtx_lock(&sc->mfi_io_lock);
- if ((error = mfi_mapcmd(sc, cm)) != 0) {
+ if ((error = mfi_wait_command(sc, cm)) != 0) {
device_printf(sc->mfi_dev,
"Controller polled failed\n");
mtx_unlock(&sc->mfi_io_lock);
goto out;
}
- bus_dmamap_sync(sc->mfi_buffer_dmat, cm->cm_dmamap,
- BUS_DMASYNC_POSTREAD);
- bus_dmamap_unload(sc->mfi_buffer_dmat, cm->cm_dmamap);
mtx_unlock(&sc->mfi_io_lock);
temp = data;
diff --git a/sys/dev/mfi/mfivar.h b/sys/dev/mfi/mfivar.h
index 1230033..874ae1f 100644
--- a/sys/dev/mfi/mfivar.h
+++ b/sys/dev/mfi/mfivar.h
@@ -74,6 +74,7 @@ struct mfi_command {
void (* cm_complete)(struct mfi_command *cm);
void *cm_private;
int cm_index;
+ int cm_error;
};
struct mfi_disk {
OpenPOWER on IntegriCloud