summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDoug Ambrisko <ambrisko@FreeBSD.org>2008-02-04 14:54:21 +0000
committerDoug Ambrisko <ambrisko@FreeBSD.org>2008-02-04 14:54:21 +0000
commit93d9a654b31355fc2cd1be0886cce561b93e5f8b (patch)
tree3c1e3b6af40977a42484e4b9c347b5b20fc9941c
parentf9c29669241f2305720f8edb8814e83bd539ee7a (diff)
MFC: Fix some bugs in dealing with DCMD's without data. MegaCli was sending
down some DCMD's without any data. Thanks to Dell and LSI for helping to provide clues to figure out this problem. Now MegaCli can upgrade the firmware and should work identical when run on Linux. Approved by: re (kensmith)
Notes
svn path=/releng/7.0/; revision=175970
-rw-r--r--sys/dev/mfi/mfi.c150
-rw-r--r--sys/dev/mfi/mfireg.h2
2 files changed, 94 insertions, 58 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c
index 592aa00e6d1d..2e9f4e7b47eb 100644
--- a/sys/dev/mfi/mfi.c
+++ b/sys/dev/mfi/mfi.c
@@ -573,7 +573,7 @@ mfi_release_command(struct mfi_command *cm)
* as 32 bit words. Clear out the first S/G entry too for safety.
*/
hdr = &cm->cm_frame->header;
- if (hdr->sg_count) {
+ if (cm->cm_data != NULL && hdr->sg_count) {
cm->cm_sg->sg32[0].len = 0;
cm->cm_sg->sg32[0].addr = 0;
}
@@ -2096,33 +2096,48 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
context = cm->cm_frame->header.context;
bcopy(ioc->mfi_frame.raw, cm->cm_frame,
- ioc->mfi_sgl_off); /* Linux can do 2 frames ? */
- 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;
+ 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */
+ cm->cm_total_frame_size = (sizeof(union mfi_sgl) * ioc->mfi_sge_count) + ioc->mfi_sgl_off;
+ if (ioc->mfi_sge_count) {
+ cm->cm_sg =
+ (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mfi_sgl_off];
+ }
+ cm->cm_flags = 0;
+ if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
+ cm->cm_flags |= MFI_CMD_DATAIN;
+ if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
+ cm->cm_flags |= MFI_CMD_DATAOUT;
+ /* Legacy app shim */
+ if (cm->cm_flags == 0)
+ 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);
- if (cm->cm_data == NULL) {
- device_printf(sc->mfi_dev, "Malloc failed\n");
- goto out;
+ if (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT)) {
+ cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
+ M_WAITOK | M_ZERO);
+ if (cm->cm_data == NULL) {
+ device_printf(sc->mfi_dev, "Malloc failed\n");
+ goto out;
+ }
+ } else {
+ cm->cm_data = 0;
}
/* restore header context */
cm->cm_frame->header.context = context;
temp = data;
- for (i = 0; i < ioc->mfi_sge_count; i++) {
- error = copyin(ioc->mfi_sgl[i].iov_base,
- temp,
- ioc->mfi_sgl[i].iov_len);
- if (error != 0) {
- device_printf(sc->mfi_dev,
- "Copy in failed\n");
- goto out;
+ if (cm->cm_flags & MFI_CMD_DATAOUT) {
+ for (i = 0; i < ioc->mfi_sge_count; i++) {
+ error = copyin(ioc->mfi_sgl[i].iov_base,
+ temp,
+ ioc->mfi_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy in failed\n");
+ goto out;
+ }
+ temp = &temp[ioc->mfi_sgl[i].iov_len];
}
- temp = &temp[ioc->mfi_sgl[i].iov_len];
}
if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
@@ -2146,16 +2161,18 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
mtx_unlock(&sc->mfi_io_lock);
temp = data;
- for (i = 0; i < ioc->mfi_sge_count; i++) {
- error = copyout(temp,
- ioc->mfi_sgl[i].iov_base,
- ioc->mfi_sgl[i].iov_len);
- if (error != 0) {
- device_printf(sc->mfi_dev,
- "Copy out failed\n");
- goto out;
+ if (cm->cm_flags & MFI_CMD_DATAIN) {
+ for (i = 0; i < ioc->mfi_sge_count; i++) {
+ error = copyout(temp,
+ ioc->mfi_sgl[i].iov_base,
+ ioc->mfi_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed\n");
+ goto out;
+ }
+ temp = &temp[ioc->mfi_sgl[i].iov_len];
}
- temp = &temp[ioc->mfi_sgl[i].iov_len];
}
if (ioc->mfi_sense_len) {
@@ -2282,31 +2299,46 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
context = cm->cm_frame->header.context;
bcopy(l_ioc.lioc_frame.raw, cm->cm_frame,
- l_ioc.lioc_sgl_off); /* Linux can do 2 frames ? */
- 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;
+ 2 * MFI_DCMD_FRAME_SIZE); /* this isn't quite right */
+ cm->cm_total_frame_size = (sizeof(union mfi_sgl) * l_ioc.lioc_sge_count) + l_ioc.lioc_sgl_off;
+ if (l_ioc.lioc_sge_count)
+ cm->cm_sg =
+ (union mfi_sgl *)&cm->cm_frame->bytes[l_ioc.lioc_sgl_off];
+ cm->cm_flags = 0;
+ if (cm->cm_frame->header.flags & MFI_FRAME_DATAIN)
+ cm->cm_flags |= MFI_CMD_DATAIN;
+ if (cm->cm_frame->header.flags & MFI_FRAME_DATAOUT)
+ cm->cm_flags |= 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);
+ if (cm->cm_flags & (MFI_CMD_DATAIN | MFI_CMD_DATAOUT)) {
+ cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
+ M_WAITOK | M_ZERO);
+ if (cm->cm_data == NULL) {
+ device_printf(sc->mfi_dev, "Malloc failed\n");
+ goto out;
+ }
+ } else {
+ cm->cm_data = 0;
+ }
/* restore header context */
cm->cm_frame->header.context = context;
temp = data;
- for (i = 0; i < l_ioc.lioc_sge_count; i++) {
- temp_convert =
- (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
- error = copyin(temp_convert,
- temp,
- l_ioc.lioc_sgl[i].iov_len);
- if (error != 0) {
- device_printf(sc->mfi_dev,
- "Copy in failed\n");
- goto out;
+ if (cm->cm_flags & MFI_CMD_DATAOUT) {
+ for (i = 0; i < l_ioc.lioc_sge_count; i++) {
+ temp_convert =
+ (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
+ error = copyin(temp_convert,
+ temp,
+ l_ioc.lioc_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy in failed\n");
+ goto out;
+ }
+ temp = &temp[l_ioc.lioc_sgl[i].iov_len];
}
- temp = &temp[l_ioc.lioc_sgl[i].iov_len];
}
if (cm->cm_frame->header.cmd == MFI_CMD_DCMD)
@@ -2330,18 +2362,20 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
mtx_unlock(&sc->mfi_io_lock);
temp = data;
- for (i = 0; i < l_ioc.lioc_sge_count; i++) {
- temp_convert =
- (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
- error = copyout(temp,
- temp_convert,
- l_ioc.lioc_sgl[i].iov_len);
- if (error != 0) {
- device_printf(sc->mfi_dev,
- "Copy out failed\n");
- goto out;
+ if (cm->cm_flags & MFI_CMD_DATAIN) {
+ for (i = 0; i < l_ioc.lioc_sge_count; i++) {
+ temp_convert =
+ (void *)(uintptr_t)l_ioc.lioc_sgl[i].iov_base;
+ error = copyout(temp,
+ temp_convert,
+ l_ioc.lioc_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed\n");
+ goto out;
+ }
+ temp = &temp[l_ioc.lioc_sgl[i].iov_len];
}
- temp = &temp[l_ioc.lioc_sgl[i].iov_len];
}
if (l_ioc.lioc_sense_len) {
diff --git a/sys/dev/mfi/mfireg.h b/sys/dev/mfi/mfireg.h
index 2bd8a51d3a9a..c54602664003 100644
--- a/sys/dev/mfi/mfireg.h
+++ b/sys/dev/mfi/mfireg.h
@@ -352,6 +352,8 @@ struct mfi_frame_header {
uint32_t context;
uint32_t pad0;
uint16_t flags;
+#define MFI_FRAME_DATAOUT 0x08
+#define MFI_FRAME_DATAIN 0x10
uint16_t timeout;
uint32_t data_len;
} __packed;