tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: pass-through linux ioctl for mfi(4)
Hello,
so it seems we can't do much better in compat_linux.
Here's an updated patch, which checks the size before malloc in mfifioctl(),
and I also removed a debug printf in compat_linux.
I intend to commit this next weekend.
--
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
NetBSD: 26 ans d'experience feront toujours la difference
--
Index: dev/ic/mfi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/mfi.c,v
retrieving revision 1.46
diff -u -p -u -r1.46 mfi.c
--- dev/ic/mfi.c 26 Aug 2012 16:22:32 -0000 1.46
+++ dev/ic/mfi.c 18 Sep 2012 22:35:38 -0000
@@ -86,6 +86,8 @@ __KERNEL_RCSID(0, "$NetBSD: mfi.c,v 1.46
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/cpu.h>
+#include <sys/conf.h>
+#include <sys/kauth.h>
#include <uvm/uvm_param.h>
@@ -100,6 +102,7 @@ __KERNEL_RCSID(0, "$NetBSD: mfi.c,v 1.46
#include <dev/ic/mfireg.h>
#include <dev/ic/mfivar.h>
+#include <dev/ic/mfiio.h>
#if NBIO > 0
#include <dev/biovar.h>
@@ -177,6 +180,16 @@ static bool mfi_shutdown(device_t, int)
static bool mfi_suspend(device_t, const pmf_qual_t *);
static bool mfi_resume(device_t, const pmf_qual_t *);
+static dev_type_open(mfifopen);
+static dev_type_close(mfifclose);
+static dev_type_ioctl(mfifioctl);
+const struct cdevsw mfi_cdevsw = {
+ mfifopen, mfifclose, noread, nowrite, mfifioctl,
+ nostop, notty, nopoll, nommap, nokqfilter, D_OTHER
+};
+
+extern struct cfdriver mfi_cd;
+
static uint32_t mfi_xscale_fw_state(struct mfi_softc *sc);
static void mfi_xscale_intr_ena(struct mfi_softc *sc);
static void mfi_xscale_intr_dis(struct mfi_softc *sc);
@@ -3472,3 +3485,151 @@ mfi_sync_map_complete(struct mfi_ccb *cc
workqueue_enqueue(sc->sc_ldsync_wq, &sc->sc_ldsync_wk, NULL);
}
}
+
+static int
+mfifopen(dev_t dev, int flag, int mode, struct lwp *l)
+{
+ struct mfi_softc *sc;
+
+ if ((sc = device_lookup_private(&mfi_cd, minor(dev))) == NULL)
+ return (ENXIO);
+ return (0);
+}
+
+static int
+mfifclose(dev_t dev, int flag, int mode, struct lwp *l)
+{
+ struct mfi_softc *sc;
+
+ sc = device_lookup_private(&mfi_cd, minor(dev));
+ return (0);
+}
+
+static int
+mfifioctl(dev_t dev, u_long cmd, void *data, int flag,
+ struct lwp *l)
+{
+ struct mfi_softc *sc;
+ struct mfi_ioc_packet *ioc = data;
+ uint8_t *udata;
+ struct mfi_ccb *ccb = NULL;
+ int ctx, i, s, error;
+ union mfi_sense_ptr sense_ptr;
+
+ switch(cmd) {
+ case MFI_CMD:
+ sc = device_lookup_private(&mfi_cd, ioc->mfi_adapter_no);
+ break;
+ default:
+ return ENOTTY;
+ }
+ if (sc == NULL)
+ return (ENXIO);
+ if (sc->sc_opened)
+ return (EBUSY);
+
+ switch(cmd) {
+ case MFI_CMD:
+ error = kauth_authorize_device_passthru(l->l_cred, dev,
+ KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL, data);
+ if (error)
+ return error;
+ if (ioc->mfi_sge_count > MAX_IOCTL_SGE)
+ return EINVAL;
+ s = splbio();
+ if ((ccb = mfi_get_ccb(sc)) == NULL)
+ return ENOMEM;
+ ccb->ccb_data = NULL;
+ ctx = ccb->ccb_frame->mfr_header.mfh_context;
+ memcpy(ccb->ccb_frame, ioc->mfi_frame.raw,
+ sizeof(*ccb->ccb_frame));
+ ccb->ccb_frame->mfr_header.mfh_context = ctx;
+ ccb->ccb_frame->mfr_header.mfh_scsi_status = 0;
+ ccb->ccb_frame->mfr_header.mfh_pad0 = 0;
+ ccb->ccb_frame_size =
+ (sizeof(union mfi_sgl) * ioc->mfi_sge_count) +
+ ioc->mfi_sgl_off;
+ if (ioc->mfi_sge_count > 0) {
+ ccb->ccb_sgl = (union mfi_sgl *)
+ &ccb->ccb_frame->mfr_bytes[ioc->mfi_sgl_off];
+ }
+ if (ccb->ccb_frame->mfr_header.mfh_flags & MFI_FRAME_DIR_READ)
+ ccb->ccb_direction = MFI_DATA_IN;
+ if (ccb->ccb_frame->mfr_header.mfh_flags & MFI_FRAME_DIR_WRITE)
+ ccb->ccb_direction = MFI_DATA_OUT;
+ ccb->ccb_len = ccb->ccb_frame->mfr_header.mfh_data_len;
+ if (ccb->ccb_len > MAXPHYS) {
+ error = ENOMEM;
+ goto out;
+ }
+ if (ccb->ccb_len &&
+ (ccb->ccb_direction & (MFI_DATA_IN | MFI_DATA_OUT)) != 0) {
+ udata = malloc(ccb->ccb_len, M_DEVBUF, M_WAITOK|M_ZERO);
+ if (udata == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ ccb->ccb_data = udata;
+ if (ccb->ccb_direction & MFI_DATA_OUT) {
+ for (i = 0; i < ioc->mfi_sge_count; i++) {
+ error = copyin(ioc->mfi_sgl[i].iov_base,
+ udata, ioc->mfi_sgl[i].iov_len);
+ if (error)
+ goto out;
+ udata = &udata[
+ ioc->mfi_sgl[i].iov_len];
+ }
+ }
+ if (mfi_create_sgl(ccb, BUS_DMA_WAITOK)) {
+ error = EIO;
+ goto out;
+ }
+ }
+ if (ccb->ccb_frame->mfr_header.mfh_cmd == MFI_CMD_PD_SCSI_IO) {
+ ccb->ccb_frame->mfr_io.mif_sense_addr_lo =
+ htole32(ccb->ccb_psense);
+ ccb->ccb_frame->mfr_io.mif_sense_addr_hi = 0;
+ }
+ ccb->ccb_done = mfi_mgmt_done;
+ mfi_post(sc, ccb);
+ while (ccb->ccb_state != MFI_CCB_DONE)
+ tsleep(ccb, PRIBIO, "mfi_fioc", 0);
+
+ if (ccb->ccb_direction & MFI_DATA_IN) {
+ udata = ccb->ccb_data;
+ for (i = 0; i < ioc->mfi_sge_count; i++) {
+ error = copyout(udata,
+ ioc->mfi_sgl[i].iov_base,
+ ioc->mfi_sgl[i].iov_len);
+ if (error)
+ goto out;
+ udata = &udata[
+ ioc->mfi_sgl[i].iov_len];
+ }
+ }
+ if (ioc->mfi_sense_len) {
+ memcpy(&sense_ptr.sense_ptr_data[0],
+ &ioc->mfi_frame.raw[ioc->mfi_sense_off],
+ sizeof(sense_ptr.sense_ptr_data));
+ error = copyout(ccb->ccb_sense,
+ sense_ptr.user_space,
+ sizeof(sense_ptr.sense_ptr_data));
+ if (error)
+ goto out;
+ }
+ memcpy(ioc->mfi_frame.raw, ccb->ccb_frame,
+ sizeof(*ccb->ccb_frame));
+ break;
+ default:
+ printf("mfifioctl unhandled cmd 0x%lx\n", cmd);
+ return ENOTTY;
+ }
+
+out:
+ if (ccb->ccb_data)
+ free(ccb->ccb_data, M_DEVBUF);
+ if (ccb)
+ mfi_put_ccb(ccb);
+ splx(s);
+ return error;
+}
Index: dev/ic/mfiio.h
===================================================================
RCS file: dev/ic/mfiio.h
diff -N dev/ic/mfiio.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ dev/ic/mfiio.h 18 Sep 2012 22:35:38 -0000
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2006 IronPort Systems
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <dev/ic/mfireg.h>
+#include <sys/ioctl.h>
+
+/*
+ * these structures are used for LSI's MegaCli on both FreeBSD and Linux
+ * We will also use them in the NetBSD driver.
+ */
+
+#define MAX_SPACE_FOR_SENSE_PTR 32
+union mfi_sense_ptr {
+ uint8_t sense_ptr_data[MAX_SPACE_FOR_SENSE_PTR];
+ void *user_space;
+ struct {
+ uint32_t low;
+ uint32_t high;
+ } addr;
+} __packed;
+
+
+#define MAX_IOCTL_SGE 16
+
+struct mfi_ioc_packet {
+ uint16_t mfi_adapter_no;
+ uint16_t mfi_pad1;
+ uint32_t mfi_sgl_off;
+ uint32_t mfi_sge_count;
+ uint32_t mfi_sense_off;
+ uint32_t mfi_sense_len;
+ union {
+ uint8_t raw[128];
+ struct mfi_frame_header hdr;
+ } mfi_frame;
+
+ struct iovec mfi_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)
+
+#ifdef _LP64
+struct iovec32 {
+ u_int32_t iov_base;
+ int iov_len;
+};
+
+struct mfi_ioc_packet32 {
+ uint16_t mfi_adapter_no;
+ uint16_t mfi_pad1;
+ uint32_t mfi_sgl_off;
+ uint32_t mfi_sge_count;
+ uint32_t mfi_sense_off;
+ uint32_t mfi_sense_len;
+ union {
+ uint8_t raw[128];
+ struct mfi_frame_header hdr;
+ } mfi_frame;
+
+ struct iovec32 mfi_sgl[MAX_IOCTL_SGE];
+} __packed;
+#define MFI_CMD32 _IOWR('M', 1, struct mfi_ioc_packet32)
+#endif
Index: dev/ic/mfireg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/mfireg.h,v
retrieving revision 1.7
diff -u -p -u -r1.7 mfireg.h
--- dev/ic/mfireg.h 26 Aug 2012 16:05:29 -0000 1.7
+++ dev/ic/mfireg.h 18 Sep 2012 22:35:38 -0000
@@ -43,6 +43,9 @@
* SUCH DAMAGE.
*/
+#ifndef _DEV_IC_MFIREG_H_
+#define _DEV_IC_MFIREG_H_
+
/* management interface constants */
#define MFI_MGMT_VD 0x01
#define MFI_MGMT_SD 0x02
@@ -1703,3 +1706,5 @@ typedef union _mfi_address {
#define MEGASAS_MAX_NAME 32
#define MEGASAS_VERSION "4.23"
+
+#endif /* _DEV_IC_MFIREG_H_ */
Index: dev/ic/mfivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/mfivar.h,v
retrieving revision 1.19
diff -u -p -u -r1.19 mfivar.h
--- dev/ic/mfivar.h 26 Aug 2012 16:05:29 -0000 1.19
+++ dev/ic/mfivar.h 18 Sep 2012 22:35:38 -0000
@@ -210,6 +210,9 @@ struct mfi_softc {
bool sc_running;
device_t sc_child;
+
+ /* for ioctl interface */
+ bool sc_opened;
};
int mfi_rescan(device_t, const char *, const int *);
Index: compat/linux/common/linux_ioctl.c
===================================================================
RCS file: /cvsroot/src/sys/compat/linux/common/linux_ioctl.c,v
retrieving revision 1.56
diff -u -p -u -r1.56 linux_ioctl.c
--- compat/linux/common/linux_ioctl.c 14 Oct 2011 09:23:28 -0000 1.56
+++ compat/linux/common/linux_ioctl.c 18 Sep 2012 22:35:38 -0000
@@ -63,6 +63,10 @@ __KERNEL_RCSID(0, "$NetBSD: linux_ioctl.
#include <compat/ossaudio/ossaudio.h>
#define LINUX_TO_OSS(v) ((const void *)(v)) /* do nothing, same ioctl()
encoding */
+#include <dev/ic/mfiio.h>
+#define LINUX_MEGARAID_CMD _LINUX_IOWR('M', 1, struct mfi_ioc_packet)
+#define LINUX_MEGARAID_GET_AEN _LINUX_IOW('M', 3, struct mfi_ioc_aen)
+
/*
* Most ioctl command are just converted to their NetBSD values,
* and passed on. The ones that take structure pointers and (flag)
@@ -80,7 +84,28 @@ linux_sys_ioctl(struct lwp *l, const str
switch (LINUX_IOCGROUP(SCARG(uap, com))) {
case 'M':
- error = oss_ioctl_mixer(l, LINUX_TO_OSS(uap), retval);
+ switch(SCARG(uap, com)) {
+ case LINUX_MEGARAID_CMD:
+ case LINUX_MEGARAID_GET_AEN:
+ {
+ struct sys_ioctl_args ua;
+ u_long com = 0;
+ if (SCARG(uap, com) & IOC_IN)
+ com |= IOC_OUT;
+ if (SCARG(uap, com) & IOC_OUT)
+ com |= IOC_IN;
+ SCARG(&ua, fd) = SCARG(uap, fd);
+ SCARG(&ua, com) = SCARG(uap, com);
+ SCARG(&ua, com) &= ~IOC_DIRMASK;
+ SCARG(&ua, com) |= com;
+ SCARG(&ua, data) = SCARG(uap, data);
+ error = sys_ioctl(l, (const void *)&ua, retval);
+ break;
+ }
+ default:
+ error = oss_ioctl_mixer(l, LINUX_TO_OSS(uap), retval);
+ break;
+ }
break;
case 'Q':
error = oss_ioctl_sequencer(l, LINUX_TO_OSS(uap), retval);
Home |
Main Index |
Thread Index |
Old Index