summaryrefslogtreecommitdiffstats
path: root/sys/dev/mfi
diff options
context:
space:
mode:
authorambrisko <ambrisko@FreeBSD.org>2006-11-14 16:48:00 +0000
committerambrisko <ambrisko@FreeBSD.org>2006-11-14 16:48:00 +0000
commitf41b8dc90c849db7e4700140266cedf63401f728 (patch)
treeeaf59f250c8df0a5c997819b44f87ed5ef1975be /sys/dev/mfi
parent91b011095b56adfb3334f4f2d674fa0022c493db (diff)
downloadFreeBSD-src-f41b8dc90c849db7e4700140266cedf63401f728.zip
FreeBSD-src-f41b8dc90c849db7e4700140266cedf63401f728.tar.gz
- Add in FreeBSD native ioctl that models the Linux version.
- Add a translation so the Linux ioctl's don't conflict with the FreeBSD definition. - Assume Linux 32bit emulation on amd64. This was tested on i386 and amd64 with the 32bit Linux MegaCli. Eventually we should do a 32bit native FreeBSD translation app.
Diffstat (limited to 'sys/dev/mfi')
-rw-r--r--sys/dev/mfi/mfi.c151
-rw-r--r--sys/dev/mfi/mfi_ioctl.h47
-rw-r--r--sys/dev/mfi/mfi_linux.c15
3 files changed, 206 insertions, 7 deletions
diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c
index 2fedec5..e0a79f6 100644
--- a/sys/dev/mfi/mfi.c
+++ b/sys/dev/mfi/mfi.c
@@ -1797,6 +1797,14 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
{
struct mfi_softc *sc;
union mfi_statrequest *ms;
+ struct mfi_ioc_packet *ioc;
+ struct mfi_ioc_aen *aen;
+ struct mfi_command *cm = NULL;
+ struct mfi_dcmd_frame *dcmd;
+ uint32_t context;
+ uint32_t *sense_ptr;
+ uint8_t *data = NULL, *temp;
+ int i;
int error;
sc = dev->si_drv1;
@@ -1818,7 +1826,133 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
break;
}
break;
- case 0xc1144d01: /* Firmware Linux ioctl shim */
+ case MFI_CMD:
+ ioc = (struct mfi_ioc_packet *)arg;
+
+ mtx_lock(&sc->mfi_io_lock);
+ if ((cm = mfi_dequeue_free(sc)) == NULL) {
+ mtx_unlock(&sc->mfi_io_lock);
+ return (EBUSY);
+ }
+ mtx_unlock(&sc->mfi_io_lock);
+
+ /*
+ * save off original context since copying from user
+ * will clobber some data
+ */
+ context = cm->cm_frame->header.context;
+
+ bcopy(ioc->mi_frame.raw, cm->cm_frame,
+ ioc->mi_sgl_off); /* Linux can do 2 frames ? */
+ cm->cm_total_frame_size = ioc->mi_sgl_off;
+ cm->cm_sg =
+ (union mfi_sgl *)&cm->cm_frame->bytes[ioc->mi_sgl_off];
+ cm->cm_flags = MFI_CMD_DATAIN | MFI_CMD_DATAOUT
+ | MFI_CMD_POLLED;
+ cm->cm_len = cm->cm_frame->header.data_len;
+ cm->cm_data = data = malloc(cm->cm_len, M_MFIBUF,
+ M_WAITOK | M_ZERO);
+
+ /* restore header context */
+ cm->cm_frame->header.context = context;
+ /* ioctl's are dcmd types */
+ dcmd = &cm->cm_frame->dcmd;
+
+ temp = data;
+ for (i = 0; i < ioc->mi_sge_count; i++) {
+ error = copyin(ioc->mi_sgl[i].iov_base,
+ temp,
+ ioc->mi_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy in failed");
+ goto out;
+ }
+ temp = &temp[ioc->mi_sgl[i].iov_len];
+ }
+
+ if (ioc->mi_sense_len) {
+ sense_ptr =
+ (void *)&cm->cm_frame->bytes[ioc->mi_sense_off];
+ *sense_ptr = cm->cm_sense_busaddr;
+ }
+
+ mtx_lock(&sc->mfi_io_lock);
+ if ((error = mfi_mapcmd(sc, cm)) != 0) {
+ device_printf(sc->mfi_dev,
+ "Controller info buffer map failed");
+ mtx_unlock(&sc->mfi_io_lock);
+ goto out;
+ }
+
+ if ((error = mfi_polled_command(sc, cm)) != 0) {
+ device_printf(sc->mfi_dev,
+ "Controller polled failed");
+ 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;
+ for (i = 0; i < ioc->mi_sge_count; i++) {
+ error = copyout(temp,
+ ioc->mi_sgl[i].iov_base,
+ ioc->mi_sgl[i].iov_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed");
+ goto out;
+ }
+ temp = &temp[ioc->mi_sgl[i].iov_len];
+ }
+
+ if (ioc->mi_sense_len) {
+ /* copy out sense */
+ sense_ptr = (void *)
+ &ioc->mi_frame.raw[ioc->mi_sense_off];
+ temp = 0;
+ temp += cm->cm_sense_busaddr;
+ error = copyout(temp, sense_ptr,
+ ioc->mi_sense_len);
+ if (error != 0) {
+ device_printf(sc->mfi_dev,
+ "Copy out failed");
+ goto out;
+ }
+ }
+
+ ioc->mi_frame.hdr.cmd_status = cm->cm_frame->header.cmd_status;
+ if (cm->cm_frame->header.cmd_status == MFI_STAT_OK) {
+ switch (dcmd->opcode) {
+ case MFI_DCMD_CFG_CLEAR:
+ case MFI_DCMD_CFG_ADD:
+/*
+ mfi_ldrescan(sc);
+*/
+ break;
+ }
+ }
+out:
+ if (data)
+ free(data, M_MFIBUF);
+ if (cm) {
+ mtx_lock(&sc->mfi_io_lock);
+ mfi_release_command(cm);
+ mtx_unlock(&sc->mfi_io_lock);
+ }
+
+ break;
+ case MFI_SET_AEN:
+ aen = (struct mfi_ioc_aen *)arg;
+ error = mfi_aen_register(sc, aen->aen_seq_num,
+ aen->aen_class_locale);
+
+ break;
+ case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
{
devclass_t devclass;
struct mfi_linux_ioc_packet l_ioc;
@@ -1839,7 +1973,7 @@ mfi_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
cmd, arg, flag, td));
break;
}
- case 0x400c4d03: /* AEN Linux ioctl shim */
+ case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
{
devclass_t devclass;
struct mfi_linux_ioc_aen l_aen;
@@ -1880,13 +2014,14 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
uint32_t *sense_ptr;
uint32_t context;
uint8_t *data = NULL, *temp;
+ void *temp_convert;
int i;
int error;
sc = dev->si_drv1;
error = 0;
switch (cmd) {
- case 0xc1144d01: /* Firmware Linux ioctl shim */
+ case MFI_LINUX_CMD_2: /* Firmware Linux ioctl shim */
error = copyin(arg, &l_ioc, sizeof(l_ioc));
if (error != 0)
return (error);
@@ -1924,7 +2059,9 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
temp = data;
for (i = 0; i < l_ioc.lioc_sge_count; i++) {
- error = copyin(l_ioc.lioc_sgl[i].iov_base,
+ 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) {
@@ -1963,8 +2100,10 @@ mfi_linux_ioctl_int(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_threa
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,
- l_ioc.lioc_sgl[i].iov_base,
+ temp_convert,
l_ioc.lioc_sgl[i].iov_len);
if (error != 0) {
device_printf(sc->mfi_dev,
@@ -2017,7 +2156,7 @@ out:
}
return (error);
- case 0x400c4d03: /* AEN Linux ioctl shim */
+ case MFI_LINUX_SET_AEN_2: /* AEN Linux ioctl shim */
error = copyin(arg, &l_aen, sizeof(l_aen));
if (error != 0)
return (error);
diff --git a/sys/dev/mfi/mfi_ioctl.h b/sys/dev/mfi/mfi_ioctl.h
index 7c4dae9..8b43a79 100644
--- a/sys/dev/mfi/mfi_ioctl.h
+++ b/sys/dev/mfi/mfi_ioctl.h
@@ -27,6 +27,13 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
+struct iovec32 {
+ u_int32_t iov_base;
+ int iov_len;
+};
+#endif
+
#define MFIQ_FREE 0
#define MFIQ_BIO 1
#define MFIQ_READY 2
@@ -43,6 +50,33 @@ union mfi_statrequest {
struct mfi_qstat ms_qstat;
};
+#define MAX_IOCTL_SGE 16
+
+struct mfi_ioc_packet {
+ uint16_t mi_adapter_no;
+ uint16_t mi_pad1;
+ uint32_t mi_sgl_off;
+ uint32_t mi_sge_count;
+ uint32_t mi_sense_off;
+ uint32_t mi_sense_len;
+ union {
+ uint8_t raw[128];
+ struct mfi_frame_header hdr;
+ } mi_frame;
+
+ struct iovec mi_sgl[MAX_IOCTL_SGE];
+} __packed;
+
+struct mfi_ioc_aen {
+ uint16_t aen_adapter_no;
+ uint16_t aen_pad1;
+ uint32_t aen_seq_num;
+ uint32_t aen_class_locale;
+} __packed;
+
+#define MFI_CMD _IOWR('M', 1, struct mfi_ioc_packet)
+#define MFI_SET_AEN _IOW('M', 3, struct mfi_ioc_aen)
+
#define MAX_LINUX_IOCTL_SGE 16
struct mfi_linux_ioc_packet {
@@ -57,7 +91,11 @@ struct mfi_linux_ioc_packet {
struct mfi_frame_header hdr;
} lioc_frame;
+#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
+ struct iovec32 lioc_sgl[MAX_LINUX_IOCTL_SGE];
+#else
struct iovec lioc_sgl[MAX_LINUX_IOCTL_SGE];
+#endif
} __packed;
#define MFIIO_STATS _IOWR('Q', 101, union mfi_statrequest)
@@ -68,3 +106,12 @@ struct mfi_linux_ioc_aen {
uint32_t laen_seq_num;
uint32_t laen_class_locale;
} __packed;
+
+/*
+ * Create a second set so the FreeBSD native ioctl doesn't
+ * conflict in FreeBSD ioctl handler. Translate in mfi_linux.c.
+ */
+#define MFI_LINUX_CMD 0xc1144d01
+#define MFI_LINUX_SET_AEN 0x400c4d03
+#define MFI_LINUX_CMD_2 0xc1144d02
+#define MFI_LINUX_SET_AEN_2 0x400c4d04
diff --git a/sys/dev/mfi/mfi_linux.c b/sys/dev/mfi/mfi_linux.c
index e12d606..911c02c 100644
--- a/sys/dev/mfi/mfi_linux.c
+++ b/sys/dev/mfi/mfi_linux.c
@@ -45,6 +45,9 @@ __FBSDID("$FreeBSD$");
#include <compat/linux/linux_ioctl.h>
#include <compat/linux/linux_util.h>
+#include <dev/mfi/mfireg.h>
+#include <dev/mfi/mfi_ioctl.h>
+
/* There are multiple ioctl number ranges that need to be handled */
#define MFI_LINUX_IOCTL_MIN 0x4d00
#define MFI_LINUX_IOCTL_MAX 0x4d04
@@ -81,10 +84,20 @@ mfi_linux_ioctl(d_thread_t *p, struct linux_ioctl_args *args)
{
struct file *fp;
int error;
+ u_long cmd = args->cmd;
+
+ switch (cmd) {
+ case MFI_LINUX_CMD:
+ cmd = MFI_LINUX_CMD_2;
+ break;
+ case MFI_LINUX_SET_AEN:
+ cmd = MFI_LINUX_SET_AEN_2;
+ break;
+ }
if ((error = fget(p, args->fd, &fp)) != 0)
return (error);
- error = fo_ioctl(fp, args->cmd, (caddr_t)args->arg, p->td_ucred, p);
+ error = fo_ioctl(fp, cmd, (caddr_t)args->arg, p->td_ucred, p);
fdrop(fp, p);
return (error);
}
OpenPOWER on IntegriCloud