aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorKashyap D Desai <kadesai@FreeBSD.org>2014-10-08 09:19:35 +0000
committerKashyap D Desai <kadesai@FreeBSD.org>2014-10-08 09:19:35 +0000
commit536094dc79eb98d023bcfce564fc3cdc00787090 (patch)
tree0dc4d977f29d03202acc21f02fcd6143d5887553 /sys/dev
parentfdbf76c383df5ed9630dea35e3d6092513ba9e0f (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/mrsas/mrsas.c55
-rw-r--r--sys/dev/mrsas/mrsas.h8
-rw-r--r--sys/dev/mrsas/mrsas_ioctl.c151
-rw-r--r--sys/dev/mrsas/mrsas_ioctl.h34
-rw-r--r--sys/dev/mrsas/mrsas_linux.c134
5 files changed, 274 insertions, 108 deletions
diff --git a/sys/dev/mrsas/mrsas.c b/sys/dev/mrsas/mrsas.c
index 279ab7b48f53..7e327cdab814 100644
--- a/sys/dev/mrsas/mrsas.c
+++ b/sys/dev/mrsas/mrsas.c
@@ -65,6 +65,7 @@ static d_read_t mrsas_read;
static d_write_t mrsas_write;
static d_ioctl_t mrsas_ioctl;
+static struct mrsas_mgmt_info mrsas_mgmt_info;
static struct mrsas_ident *mrsas_find_ident(device_t);
static void mrsas_shutdown_ctlr(struct mrsas_softc *sc, u_int32_t opcode);
static void mrsas_flush_cache(struct mrsas_softc *sc);
@@ -137,7 +138,7 @@ extern void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
extern int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc);
extern void mrsas_release_mpt_cmd(struct mrsas_mpt_cmd *cmd);
extern struct mrsas_mpt_cmd *mrsas_get_mpt_cmd(struct mrsas_softc *sc);
-extern int mrsas_passthru(struct mrsas_softc *sc, void *arg);
+extern int mrsas_passthru(struct mrsas_softc *sc, void *arg, u_long ioctlCmd);
extern uint8_t MR_ValidateMapInfo(struct mrsas_softc *sc);
extern u_int16_t MR_GetLDTgtId(u_int32_t ld, MR_DRV_RAID_MAP_ALL *map);
extern MR_LD_RAID *MR_LdRaidGet(u_int32_t ld, MR_DRV_RAID_MAP_ALL *map);
@@ -657,7 +658,7 @@ mrsas_register_aen(struct mrsas_softc *sc, u_int32_t seq_num,
dcmd->data_xfer_len = sizeof(struct mrsas_evt_detail);
dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
dcmd->mbox.w[0] = seq_num;
- sc->last_seq_num = seq_num;
+ sc->last_seq_num = seq_num;
dcmd->mbox.w[1] = curr_aen.word;
dcmd->sgl.sge32[0].phys_addr = (u_int32_t) sc->evt_detail_phys_addr;
dcmd->sgl.sge32[0].length = sizeof(struct mrsas_evt_detail);
@@ -775,6 +776,8 @@ static int mrsas_attach(device_t dev)
sc->mrsas_cdev = make_dev(&mrsas_cdevsw, device_get_unit(dev), UID_ROOT,
GID_OPERATOR, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP), "mrsas%u",
device_get_unit(dev));
+ if (device_get_unit(dev) == 0)
+ make_dev_alias(sc->mrsas_cdev, "megaraid_sas_ioctl_node");
if (sc->mrsas_cdev)
sc->mrsas_cdev->si_drv1 = sc;
@@ -816,6 +819,17 @@ static int mrsas_attach(device_t dev)
goto fail_start_aen;
}
+ /*
+ * Add this controller to mrsas_mgmt_info structure so that it
+ * can be exported to management applications
+ */
+ if (device_get_unit(dev) == 0)
+ memset(&mrsas_mgmt_info, 0, sizeof(mrsas_mgmt_info));
+
+ mrsas_mgmt_info.count++;
+ mrsas_mgmt_info.sc_ptr[mrsas_mgmt_info.max_index] = sc;
+ mrsas_mgmt_info.max_index++;
+
return (0);
fail_start_aen:
@@ -858,6 +872,19 @@ static int mrsas_detach(device_t dev)
sc = device_get_softc(dev);
sc->remove_in_progress = 1;
+
+ /*
+ * Take the instance off the instance array. Note that we will not
+ * decrement the max_index. We let this array be sparse array
+ */
+ for (i = 0; i < mrsas_mgmt_info.max_index; i++) {
+ if (mrsas_mgmt_info.sc_ptr[i] == sc) {
+ mrsas_mgmt_info.count--;
+ mrsas_mgmt_info.sc_ptr[i] = NULL;
+ break;
+ }
+ }
+
if(sc->ocr_thread_active)
wakeup(&sc->ocr_chan);
while(sc->reset_in_progress){
@@ -1101,8 +1128,19 @@ mrsas_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
struct mrsas_softc *sc;
int ret = 0, i = 0;
- sc = (struct mrsas_softc *)(dev->si_drv1);
-
+ struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg;
+
+ /* get the Host number & the softc from data sent by the Application */
+ sc = mrsas_mgmt_info.sc_ptr[user_ioc->host_no];
+
+ if ((mrsas_mgmt_info.max_index == user_ioc->host_no) || (sc == NULL)) {
+ printf ("Please check the controller number\n");
+ if (sc == NULL)
+ printf ("There is NO such Host no. %d\n", user_ioc->host_no);
+
+ return ENOENT;
+ }
+
if (sc->remove_in_progress) {
mrsas_dprint(sc, MRSAS_INFO,
"Driver remove or shutdown called.\n");
@@ -1131,12 +1169,17 @@ mrsas_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, d_thread_t *td)
do_ioctl:
switch (cmd) {
- case MRSAS_IOC_FIRMWARE_PASS_THROUGH:
- ret = mrsas_passthru(sc, (void *)arg);
+ case MRSAS_IOC_FIRMWARE_PASS_THROUGH64:
+#ifdef COMPAT_FREEBSD32
+ case MRSAS_IOC_FIRMWARE_PASS_THROUGH32:
+#endif
+ ret = mrsas_passthru(sc, (void *)arg, cmd);
break;
case MRSAS_IOC_SCAN_BUS:
ret = mrsas_bus_scan(sc);
break;
+ default:
+ mrsas_dprint(sc, MRSAS_TRACE, "IOCTL command 0x%lx is not handled\n", cmd);
}
return (ret);
diff --git a/sys/dev/mrsas/mrsas.h b/sys/dev/mrsas/mrsas.h
index a925047ab76e..0798cc0c14cc 100644
--- a/sys/dev/mrsas/mrsas.h
+++ b/sys/dev/mrsas/mrsas.h
@@ -2419,6 +2419,14 @@ struct mrsas_evt_detail {
} __packed;
+/* Controller management info added to support Linux Emulator */
+#define MAX_MGMT_ADAPTERS 1024
+
+struct mrsas_mgmt_info {
+ u_int16_t count;
+ struct mrsas_softc *sc_ptr[MAX_MGMT_ADAPTERS];
+ int max_index;
+};
/*******************************************************************
* per-instance data
diff --git a/sys/dev/mrsas/mrsas_ioctl.c b/sys/dev/mrsas/mrsas_ioctl.c
index 6343aa595604..1e77fd87dec2 100644
--- a/sys/dev/mrsas/mrsas_ioctl.c
+++ b/sys/dev/mrsas/mrsas_ioctl.c
@@ -51,11 +51,9 @@ __FBSDID("$FreeBSD$");
* Function prototypes
*/
int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc);
-int mrsas_passthru(struct mrsas_softc *sc, void *arg);
+int mrsas_passthru(struct mrsas_softc *sc, void *arg, u_long ioctlCmd);
void mrsas_free_ioc_cmd(struct mrsas_softc *sc);
void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
-void mrsas_dump_dcmd(struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd);
-void mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc);
void * mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
static int mrsas_create_frame_pool(struct mrsas_softc *sc);
static void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
@@ -66,79 +64,6 @@ extern void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd);
extern int mrsas_issue_blocked_cmd(struct mrsas_softc *sc,
struct mrsas_mfi_cmd *cmd);
-
-/**
- * mrsas_dump_ioctl: Print debug output for DCMDs
- * input: Adapter instance soft state
- * DCMD frame structure
- *
- * This function is called from mrsas_passthru() to print out debug information
- * in the handling and routing of DCMD commands.
- */
-void mrsas_dump_dcmd( struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd )
-{
- int i;
-
- device_printf(sc->mrsas_dev, "dcmd->cmd: 0x%02hhx\n", dcmd->cmd);
- device_printf(sc->mrsas_dev, "dcmd->cmd_status: 0x%02hhx\n", dcmd->cmd_status);
- device_printf(sc->mrsas_dev, "dcmd->sge_count: 0x%02hhx\n", dcmd->sge_count);
- device_printf(sc->mrsas_dev, "dcmd->context: 0x%08x\n", dcmd->context);
- device_printf(sc->mrsas_dev, "dcmd->flags: 0x%04hx\n", dcmd->flags);
- device_printf(sc->mrsas_dev, "dcmd->timeout: 0x%04hx\n", dcmd->timeout);
- device_printf(sc->mrsas_dev, "dcmd->data_xfer_len: 0x%08x\n", dcmd->data_xfer_len);
- device_printf(sc->mrsas_dev, "dcmd->opcode: 0x%08x\n", dcmd->opcode);
- device_printf(sc->mrsas_dev, "dcmd->mbox.w[0]: 0x%08x\n", dcmd->mbox.w[0]);
- device_printf(sc->mrsas_dev, "dcmd->mbox.w[1]: 0x%08x\n", dcmd->mbox.w[1]);
- device_printf(sc->mrsas_dev, "dcmd->mbox.w[2]: 0x%08x\n", dcmd->mbox.w[2]);
- for (i=0; i< MIN(MAX_IOCTL_SGE, dcmd->sge_count); i++) {
- device_printf(sc->mrsas_dev, "sgl[%02d]\n", i);
- device_printf(sc->mrsas_dev, " sge32[%02d].phys_addr: 0x%08x\n",
- i, dcmd->sgl.sge32[i].phys_addr);
- device_printf(sc->mrsas_dev, " sge32[%02d].length: 0x%08x\n",
- i, dcmd->sgl.sge32[i].length);
- device_printf(sc->mrsas_dev, " sge64[%02d].phys_addr: 0x%08llx\n",
- i, (long long unsigned int) dcmd->sgl.sge64[i].phys_addr);
- device_printf(sc->mrsas_dev, " sge64[%02d].length: 0x%08x\n",
- i, dcmd->sgl.sge64[i].length);
- }
-}
-
-/**
- * mrsas_dump_ioctl: Print debug output for ioctl
- * input: Adapter instance soft state
- * iocpacket structure
- *
- * This function is called from mrsas_passthru() to print out debug information
- * in the handling and routing of ioctl commands.
- */
-void mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc)
-{
- union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw);
- struct mrsas_dcmd_frame* dcmd = (struct mrsas_dcmd_frame *) &(in_cmd->dcmd);
- int i;
-
- device_printf(sc->mrsas_dev,
- "====== In %s() ======================================\n", __func__);
- device_printf(sc->mrsas_dev, "host_no: 0x%04hx\n", user_ioc->host_no);
- device_printf(sc->mrsas_dev, " __pad1: 0x%04hx\n", user_ioc->__pad1);
- device_printf(sc->mrsas_dev, "sgl_off: 0x%08x\n", user_ioc->sgl_off);
- device_printf(sc->mrsas_dev, "sge_count: 0x%08x\n", user_ioc->sge_count);
- device_printf(sc->mrsas_dev, "sense_off: 0x%08x\n", user_ioc->sense_off);
- device_printf(sc->mrsas_dev, "sense_len: 0x%08x\n", user_ioc->sense_len);
-
- mrsas_dump_dcmd(sc, dcmd);
-
- for (i=0; i< MIN(MAX_IOCTL_SGE, user_ioc->sge_count); i++) {
- device_printf(sc->mrsas_dev, "sge[%02d]\n", i);
- device_printf(sc->mrsas_dev,
- " iov_base: %p\n", user_ioc->sgl[i].iov_base);
- device_printf(sc->mrsas_dev, " iov_len: %p\n",
- (void*)user_ioc->sgl[i].iov_len);
- }
- device_printf(sc->mrsas_dev,
- "==================================================================\n");
-}
-
/**
* mrsas_passthru: Handle pass-through commands
* input: Adapter instance soft state
@@ -147,9 +72,12 @@ void mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc)
* This function is called from mrsas_ioctl() to handle pass-through and
* ioctl commands to Firmware.
*/
-int mrsas_passthru( struct mrsas_softc *sc, void *arg )
+int mrsas_passthru( struct mrsas_softc *sc, void *arg, u_long ioctlCmd )
{
struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg;
+#ifdef COMPAT_FREEBSD32
+ struct mrsas_iocpacket32 *user_ioc32 = (struct mrsas_iocpacket32 *)arg;
+#endif
union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw);
struct mrsas_mfi_cmd *cmd = NULL;
bus_dma_tag_t ioctl_data_tag[MAX_IOCTL_SGE];
@@ -160,12 +88,11 @@ int mrsas_passthru( struct mrsas_softc *sc, void *arg )
bus_dmamap_t ioctl_sense_dmamap = 0;
void *ioctl_sense_mem = 0;
bus_addr_t ioctl_sense_phys_addr = 0;
- int i, adapter, ioctl_data_size, ioctl_sense_size, ret=0;
+ int i, ioctl_data_size=0, ioctl_sense_size, ret=0;
struct mrsas_sge32 *kern_sge32;
unsigned long *sense_ptr;
-
- /* For debug - uncomment the following line for debug output */
- //mrsas_dump_ioctl(sc, user_ioc);
+ uint8_t *iov_base_ptrin=NULL;
+ size_t iov_len=0;
/*
* Check for NOP from MegaCli... MegaCli can issue a DCMD of 0. In this
@@ -177,13 +104,6 @@ int mrsas_passthru( struct mrsas_softc *sc, void *arg )
return (0);
}
- /* Validate host_no */
- adapter = user_ioc->host_no;
- if (adapter != device_get_unit(sc->mrsas_dev)) {
- device_printf(sc->mrsas_dev, "In %s() IOCTL not for me!\n", __func__);
- return(ENOENT);
- }
-
/* Validate SGL length */
if (user_ioc->sge_count > MAX_IOCTL_SGE) {
device_printf(sc->mrsas_dev, "In %s() SGL is too long (%d > 8).\n",
@@ -225,9 +145,17 @@ int mrsas_passthru( struct mrsas_softc *sc, void *arg )
* For each user buffer, create a mirror buffer and copy in
*/
for (i=0; i < user_ioc->sge_count; i++) {
- if (!user_ioc->sgl[i].iov_len)
- continue;
- ioctl_data_size = user_ioc->sgl[i].iov_len;
+ if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) {
+ if (!user_ioc->sgl[i].iov_len)
+ continue;
+ ioctl_data_size = user_ioc->sgl[i].iov_len;
+#ifdef COMPAT_FREEBSD32
+ } else {
+ if (!user_ioc32->sgl[i].iov_len)
+ continue;
+ ioctl_data_size = user_ioc32->sgl[i].iov_len;
+#endif
+ }
if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent
1, 0, // algnmnt, boundary
BUS_SPACE_MAXADDR_32BIT,// lowaddr
@@ -239,8 +167,8 @@ int mrsas_passthru( struct mrsas_softc *sc, void *arg )
BUS_DMA_ALLOCNOW, // flags
NULL, NULL, // lockfunc, lockarg
&ioctl_data_tag[i])) {
- device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n");
- return (ENOMEM);
+ device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n");
+ return (ENOMEM);
}
if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i],
(BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) {
@@ -256,18 +184,31 @@ int mrsas_passthru( struct mrsas_softc *sc, void *arg )
/* Save the physical address and length */
kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i];
- kern_sge32[i].length = user_ioc->sgl[i].iov_len;
+
+ if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) {
+ kern_sge32[i].length = user_ioc->sgl[i].iov_len;
+
+ iov_base_ptrin = user_ioc->sgl[i].iov_base;
+ iov_len = user_ioc->sgl[i].iov_len;
+#ifdef COMPAT_FREEBSD32
+ } else {
+ kern_sge32[i].length = user_ioc32->sgl[i].iov_len;
+
+ iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base);
+ iov_len = user_ioc32->sgl[i].iov_len;
+#endif
+ }
/* Copy in data from user space */
- ret = copyin(user_ioc->sgl[i].iov_base, ioctl_data_mem[i],
- user_ioc->sgl[i].iov_len);
+ ret = copyin(iov_base_ptrin, ioctl_data_mem[i], iov_len);
if (ret) {
- device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n");
- goto out;
+ device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n");
+ goto out;
}
}
ioctl_sense_size = user_ioc->sense_len;
+
if (user_ioc->sense_len) {
if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent
1, 0, // algnmnt, boundary
@@ -311,8 +252,17 @@ int mrsas_passthru( struct mrsas_softc *sc, void *arg )
* copy out the kernel buffers to user buffers
*/
for (i = 0; i < user_ioc->sge_count; i++) {
- ret = copyout(ioctl_data_mem[i], user_ioc->sgl[i].iov_base,
- user_ioc->sgl[i].iov_len);
+ if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) {
+ iov_base_ptrin = user_ioc->sgl[i].iov_base;
+ iov_len = user_ioc->sgl[i].iov_len;
+#ifdef COMPAT_FREEBSD32
+ } else {
+ iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base);
+ iov_len = user_ioc32->sgl[i].iov_len;
+#endif
+ }
+
+ ret = copyout(ioctl_data_mem[i], iov_base_ptrin, iov_len);
if (ret) {
device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n");
goto out;
@@ -368,7 +318,6 @@ out:
if (ioctl_data_tag[i] != NULL)
bus_dma_tag_destroy(ioctl_data_tag[i]);
}
-
/* Free command */
mrsas_release_mfi_cmd(cmd);
diff --git a/sys/dev/mrsas/mrsas_ioctl.h b/sys/dev/mrsas/mrsas_ioctl.h
index 360484277678..ae0e2e10d732 100644
--- a/sys/dev/mrsas/mrsas_ioctl.h
+++ b/sys/dev/mrsas/mrsas_ioctl.h
@@ -51,6 +51,15 @@ __FBSDID("$FreeBSD$");
#include <sys/ioccom.h>
#endif /* !_IOWR */
+#ifdef COMPAT_FREEBSD32
+/* Compilation error FIX */
+#if (__FreeBSD_version <= 900000)
+#include <sys/socket.h>
+#endif
+#include <sys/mount.h>
+#include <compat/freebsd32/freebsd32.h>
+#endif
+
/*
* We need to use the same values as the mfi driver until MegaCli adds
* support for this (mrsas) driver:
@@ -61,10 +70,15 @@ __FBSDID("$FreeBSD$");
* These three values are encoded into a somewhat unique, 32-bit value.
*/
-#define MRSAS_IOC_FIRMWARE_PASS_THROUGH _IOWR('M', 1, struct mrsas_iocpacket)
+#define MRSAS_IOC_FIRMWARE_PASS_THROUGH64 _IOWR('M', 1, struct mrsas_iocpacket)
+#ifdef COMPAT_FREEBSD32
+#define MRSAS_IOC_FIRMWARE_PASS_THROUGH32 _IOWR('M', 1, struct mrsas_iocpacket32)
+#endif
#define MRSAS_IOC_SCAN_BUS _IO('M', 10)
+#define MRSAS_LINUX_CMD32 0xc1144d01
+
#define MAX_IOCTL_SGE 16
#define MFI_FRAME_DIR_READ 0x0010
#define MFI_CMD_LD_SCSI_IO 0x03
@@ -94,4 +108,22 @@ struct mrsas_iocpacket {
};
#pragma pack()
+#ifdef COMPAT_FREEBSD32
+#pragma pack(1)
+struct mrsas_iocpacket32 {
+ u_int16_t host_no;
+ u_int16_t __pad1;
+ u_int32_t sgl_off;
+ u_int32_t sge_count;
+ u_int32_t sense_off;
+ u_int32_t sense_len;
+ union {
+ u_int8_t raw[MEGAMFI_RAW_FRAME_SIZE];
+ struct mrsas_header hdr;
+ } frame;
+ struct iovec32 sgl[MAX_IOCTL_SGE];
+};
+#pragma pack()
+#endif /* COMPAT_FREEBSD32 */
+
#endif /* MRSAS_IOCTL_H */
diff --git a/sys/dev/mrsas/mrsas_linux.c b/sys/dev/mrsas/mrsas_linux.c
new file mode 100644
index 000000000000..fd1d7093f46c
--- /dev/null
+++ b/sys/dev/mrsas/mrsas_linux.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2014, LSI Corp.
+ * All rights reserved.
+ * Author: Kashyap Desai, Sibananda Sahu
+ * Support: freebsdraid@lsi.com
+ *
+ * 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.
+ * 3. Neither the name of the <ORGANIZATION> nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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
+ * COPYRIGHT HOLDER 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies,either expressed or implied, of the FreeBSD Project.
+ *
+ * Send feedback to: <megaraidfbsd@lsi.com>
+ * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
+ * ATTN: MegaRaid FreeBSD
+ *
+ */
+
+#include <sys/cdefs.h>
+<!-- $FreeBSD$ -->
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#if (__FreeBSD_version > 900000)
+#include <sys/capability.h>
+#endif
+
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/file.h>
+#include <sys/proc.h>
+#include <machine/bus.h>
+
+#if defined(__amd64__) /* Assume amd64 wants 32 bit Linux */
+#include <machine/../linux32/linux.h>
+#include <machine/../linux32/linux32_proto.h>
+#else
+#include <machine/../linux/linux.h>
+#include <machine/../linux/linux_proto.h>
+#endif
+#include <compat/linux/linux_ioctl.h>
+#include <compat/linux/linux_util.h>
+
+#include <dev/mrsas/mrsas.h>
+#include <dev/mrsas/mrsas_ioctl.h>
+
+/* There are multiple ioctl number ranges that need to be handled */
+#define MRSAS_LINUX_IOCTL_MIN 0x4d00
+#define MRSAS_LINUX_IOCTL_MAX 0x4d01
+
+static linux_ioctl_function_t mrsas_linux_ioctl;
+static struct linux_ioctl_handler mrsas_linux_handler = {mrsas_linux_ioctl,
+ MRSAS_LINUX_IOCTL_MIN,
+ MRSAS_LINUX_IOCTL_MAX};
+
+SYSINIT (mrsas_register, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_ioctl_register_handler, &mrsas_linux_handler);
+SYSUNINIT(mrsas_unregister, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_ioctl_unregister_handler, &mrsas_linux_handler);
+
+static struct linux_device_handler mrsas_device_handler =
+ { "mrsas", "megaraid_sas", "mrsas0", "megaraid_sas_ioctl_node", -1, 0, 1};
+
+SYSINIT (mrsas_register2, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_device_register_handler, &mrsas_device_handler);
+SYSUNINIT(mrsas_unregister2, SI_SUB_KLD, SI_ORDER_MIDDLE,
+ linux_device_unregister_handler, &mrsas_device_handler);
+
+static int
+mrsas_linux_modevent(module_t mod __unused, int cmd __unused, void *data __unused)
+{
+ return (0);
+}
+
+static int
+mrsas_linux_ioctl(struct thread *p, struct linux_ioctl_args *args)
+{
+ #if (__FreeBSD_version >= 1000000)
+ cap_rights_t rights;
+ #endif
+ struct file *fp;
+ int error;
+ u_long cmd = args->cmd;
+
+ if (cmd != MRSAS_LINUX_CMD32){
+ error = ENOTSUP;
+ goto END;
+ }
+
+ #if (__FreeBSD_version >= 1000000)
+ error = fget(p, args->fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ #elif (__FreeBSD_version <= 900000)
+ error = fget(p, args->fd, &fp);
+ #else /* For FreeBSD version greater than 9.0.0 but less than 10.0.0 */
+ error = fget(p, args->fd, CAP_IOCTL, &fp);
+ #endif
+ if (error != 0)
+ goto END;
+
+ error = fo_ioctl(fp, cmd, (caddr_t)args->arg, p->td_ucred, p);
+ fdrop(fp, p);
+END:
+ return (error);
+}
+
+DEV_MODULE(mrsas_linux, mrsas_linux_modevent, NULL);
+MODULE_DEPEND(mrsas, linux, 1, 1, 1);