summaryrefslogtreecommitdiffstats
path: root/sys/dev/mrsas/mrsas_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/mrsas/mrsas_ioctl.c')
-rw-r--r--sys/dev/mrsas/mrsas_ioctl.c921
1 files changed, 440 insertions, 481 deletions
diff --git a/sys/dev/mrsas/mrsas_ioctl.c b/sys/dev/mrsas/mrsas_ioctl.c
index 6343aa5..8e2aead 100644
--- a/sys/dev/mrsas/mrsas_ioctl.c
+++ b/sys/dev/mrsas/mrsas_ioctl.c
@@ -1,43 +1,38 @@
/*
- * Copyright (c) 2014, LSI Corp.
- * All rights reserved.
- * Author: Marian Choy
+ * Copyright (c) 2014, LSI Corp. All rights reserved. Author: Marian Choy
* 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:
+ * 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.
+ * 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
+ * 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
+ * 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
+ * Send feedback to: <megaraidfbsd@lsi.com> Mail to: LSI Corporation, 1621
+ * Barber Lane, Milpitas, CA 95035 ATTN: MegaRaid FreeBSD
*
*/
@@ -47,500 +42,464 @@ __FBSDID("$FreeBSD$");
#include <dev/mrsas/mrsas.h>
#include <dev/mrsas/mrsas_ioctl.h>
-/*
- * Function prototypes
+/*
+ * Function prototypes
*/
-int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc);
-int mrsas_passthru(struct mrsas_softc *sc, void *arg);
-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);
+int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc);
+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_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,
- int nsegs, int error);
+static void
+mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
+ int nsegs, int error);
-extern struct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc);
+extern struct mrsas_mfi_cmd *mrsas_get_mfi_cmd(struct mrsas_softc *sc);
extern void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd);
-extern int mrsas_issue_blocked_cmd(struct mrsas_softc *sc,
+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
- * argument pointer
+/*
+ * mrsas_passthru: Handle pass-through commands
+ * input: Adapter instance soft state argument pointer
*
- * This function is called from mrsas_ioctl() to handle pass-through and
- * ioctl commands to Firmware.
+ * 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;
- 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];
- bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE];
- void *ioctl_data_mem[MAX_IOCTL_SGE]; // ioctl data virtual addr
- bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE]; // ioctl data phys addr
- bus_dma_tag_t ioctl_sense_tag = 0;
- 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;
- struct mrsas_sge32 *kern_sge32;
- unsigned long *sense_ptr;
-
- /* For debug - uncomment the following line for debug output */
- //mrsas_dump_ioctl(sc, user_ioc);
-
- /*
- * Check for NOP from MegaCli... MegaCli can issue a DCMD of 0. In this
- * case do nothing and return 0 to it as status.
- */
- if (in_cmd->dcmd.opcode == 0) {
- device_printf(sc->mrsas_dev, "In %s() Got a NOP\n", __func__);
- user_ioc->frame.hdr.cmd_status = MFI_STAT_OK;
- 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",
- __func__, user_ioc->sge_count);
- return(ENOENT);
- }
-
- /* Get a command */
- cmd = mrsas_get_mfi_cmd(sc);
- if (!cmd) {
- device_printf(sc->mrsas_dev, "Failed to get a free cmd for IOCTL\n");
- return(ENOMEM);
- }
-
- /*
- * User's IOCTL packet has 2 frames (maximum). Copy those two
- * frames into our cmd's frames. cmd->frame's context will get
- * overwritten when we copy from user's frames. So set that value
- * alone separately
- */
- memcpy(cmd->frame, user_ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
- cmd->frame->hdr.context = cmd->index;
- cmd->frame->hdr.pad_0 = 0;
- cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 |
- MFI_FRAME_SENSE64);
-
- /*
- * The management interface between applications and the fw uses
- * MFI frames. E.g, RAID configuration changes, LD property changes
- * etc are accomplishes through different kinds of MFI frames. The
- * driver needs to care only about substituting user buffers with
- * kernel buffers in SGLs. The location of SGL is embedded in the
- * struct iocpacket itself.
- */
- kern_sge32 = (struct mrsas_sge32 *)
- ((unsigned long)cmd->frame + user_ioc->sgl_off);
-
- /*
- * 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 (bus_dma_tag_create( sc->mrsas_parent_tag, // parent
- 1, 0, // algnmnt, boundary
- BUS_SPACE_MAXADDR_32BIT,// lowaddr
- BUS_SPACE_MAXADDR, // highaddr
- NULL, NULL, // filter, filterarg
- ioctl_data_size, // maxsize
- 1, // msegments
- ioctl_data_size, // maxsegsize
- 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);
- }
- if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i],
- (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) {
- device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n");
- return (ENOMEM);
- }
- if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i],
- ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb,
- &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) {
- device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n");
- return (ENOMEM);
- }
-
- /* 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;
-
- /* Copy in data from user space */
- ret = copyin(user_ioc->sgl[i].iov_base, ioctl_data_mem[i],
- user_ioc->sgl[i].iov_len);
- if (ret) {
- 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
- BUS_SPACE_MAXADDR_32BIT,// lowaddr
- BUS_SPACE_MAXADDR, // highaddr
- NULL, NULL, // filter, filterarg
- ioctl_sense_size, // maxsize
- 1, // msegments
- ioctl_sense_size, // maxsegsize
- BUS_DMA_ALLOCNOW, // flags
- NULL, NULL, // lockfunc, lockarg
- &ioctl_sense_tag)) {
- device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense tag\n");
- return (ENOMEM);
- }
- if (bus_dmamem_alloc(ioctl_sense_tag, (void **)&ioctl_sense_mem,
- (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_sense_dmamap)) {
- device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n");
- return (ENOMEM);
- }
- if (bus_dmamap_load(ioctl_sense_tag, ioctl_sense_dmamap,
- ioctl_sense_mem, ioctl_sense_size, mrsas_alloc_cb,
- &ioctl_sense_phys_addr, BUS_DMA_NOWAIT)) {
- device_printf(sc->mrsas_dev, "Cannot load ioctl sense mem\n");
- return (ENOMEM);
- }
- sense_ptr =
- (unsigned long *)((unsigned long)cmd->frame + user_ioc->sense_off);
- sense_ptr = ioctl_sense_mem;
- }
-
- /*
- * Set the sync_cmd flag so that the ISR knows not to complete this
- * cmd to the SCSI mid-layer
- */
- cmd->sync_cmd = 1;
- mrsas_issue_blocked_cmd(sc, cmd);
- cmd->sync_cmd = 0;
-
- /*
- * 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 (ret) {
- device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n");
- goto out;
- }
- }
-
- /*
- * copy out the sense
- */
- if (user_ioc->sense_len) {
- /*
- * sense_buff points to the location that has the user
- * sense buffer address
- */
- sense_ptr = (unsigned long *) ((unsigned long)user_ioc->frame.raw +
- user_ioc->sense_off);
- ret = copyout(ioctl_sense_mem, (unsigned long*)*sense_ptr,
- user_ioc->sense_len);
- if (ret) {
- device_printf(sc->mrsas_dev, "IOCTL sense copyout failed!\n");
- goto out;
- }
- }
-
- /*
- * Return command status to user space
- */
- memcpy(&user_ioc->frame.hdr.cmd_status, &cmd->frame->hdr.cmd_status,
- sizeof(u_int8_t));
+ 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];
+ bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE];
+ void *ioctl_data_mem[MAX_IOCTL_SGE];
+ bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE];
+ bus_dma_tag_t ioctl_sense_tag = 0;
+ bus_dmamap_t ioctl_sense_dmamap = 0;
+ void *ioctl_sense_mem = 0;
+ bus_addr_t ioctl_sense_phys_addr = 0;
+ int i, ioctl_data_size = 0, ioctl_sense_size, ret = 0;
+ struct mrsas_sge32 *kern_sge32;
+ unsigned long *sense_ptr;
+ 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 case do nothing and return 0 to it as status.
+ */
+ if (in_cmd->dcmd.opcode == 0) {
+ device_printf(sc->mrsas_dev, "In %s() Got a NOP\n", __func__);
+ user_ioc->frame.hdr.cmd_status = MFI_STAT_OK;
+ return (0);
+ }
+ /* 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",
+ __func__, user_ioc->sge_count);
+ return (ENOENT);
+ }
+ /* Get a command */
+ cmd = mrsas_get_mfi_cmd(sc);
+ if (!cmd) {
+ device_printf(sc->mrsas_dev, "Failed to get a free cmd for IOCTL\n");
+ return (ENOMEM);
+ }
+ /*
+ * User's IOCTL packet has 2 frames (maximum). Copy those two frames
+ * into our cmd's frames. cmd->frame's context will get overwritten
+ * when we copy from user's frames. So set that value alone
+ * separately
+ */
+ memcpy(cmd->frame, user_ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
+ cmd->frame->hdr.context = cmd->index;
+ cmd->frame->hdr.pad_0 = 0;
+ cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 |
+ MFI_FRAME_SENSE64);
+
+ /*
+ * The management interface between applications and the fw uses MFI
+ * frames. E.g, RAID configuration changes, LD property changes etc
+ * are accomplishes through different kinds of MFI frames. The driver
+ * needs to care only about substituting user buffers with kernel
+ * buffers in SGLs. The location of SGL is embedded in the struct
+ * iocpacket itself.
+ */
+ kern_sge32 = (struct mrsas_sge32 *)
+ ((unsigned long)cmd->frame + user_ioc->sgl_off);
+
+ /*
+ * For each user buffer, create a mirror buffer and copy in
+ */
+ for (i = 0; i < user_ioc->sge_count; i++) {
+ 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,
+ 1, 0,
+ BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR,
+ NULL, NULL,
+ ioctl_data_size,
+ 1,
+ ioctl_data_size,
+ BUS_DMA_ALLOCNOW,
+ NULL, NULL,
+ &ioctl_data_tag[i])) {
+ device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n");
+ ret = ENOMEM;
+ goto out;
+ }
+ if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i],
+ (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) {
+ device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n");
+ ret = ENOMEM;
+ goto out;
+ }
+ if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i],
+ ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb,
+ &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) {
+ device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n");
+ ret = ENOMEM;
+ goto out;
+ }
+ /* Save the physical address and length */
+ kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i];
+
+ 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(iov_base_ptrin, ioctl_data_mem[i], iov_len);
+ if (ret) {
+ 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,
+ 1, 0,
+ BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR,
+ NULL, NULL,
+ ioctl_sense_size,
+ 1,
+ ioctl_sense_size,
+ BUS_DMA_ALLOCNOW,
+ NULL, NULL,
+ &ioctl_sense_tag)) {
+ device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense tag\n");
+ ret = ENOMEM;
+ goto out;
+ }
+ if (bus_dmamem_alloc(ioctl_sense_tag, (void **)&ioctl_sense_mem,
+ (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_sense_dmamap)) {
+ device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense mem\n");
+ ret = ENOMEM;
+ goto out;
+ }
+ if (bus_dmamap_load(ioctl_sense_tag, ioctl_sense_dmamap,
+ ioctl_sense_mem, ioctl_sense_size, mrsas_alloc_cb,
+ &ioctl_sense_phys_addr, BUS_DMA_NOWAIT)) {
+ device_printf(sc->mrsas_dev, "Cannot load ioctl sense mem\n");
+ ret = ENOMEM;
+ goto out;
+ }
+ sense_ptr =
+ (unsigned long *)((unsigned long)cmd->frame + user_ioc->sense_off);
+ sense_ptr = ioctl_sense_mem;
+ }
+ /*
+ * Set the sync_cmd flag so that the ISR knows not to complete this
+ * cmd to the SCSI mid-layer
+ */
+ cmd->sync_cmd = 1;
+ mrsas_issue_blocked_cmd(sc, cmd);
+ cmd->sync_cmd = 0;
+
+ /*
+ * copy out the kernel buffers to user buffers
+ */
+ for (i = 0; i < user_ioc->sge_count; i++) {
+ 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;
+ }
+ }
+
+ /*
+ * copy out the sense
+ */
+ if (user_ioc->sense_len) {
+ /*
+ * sense_buff points to the location that has the user sense
+ * buffer address
+ */
+ sense_ptr = (unsigned long *)((unsigned long)user_ioc->frame.raw +
+ user_ioc->sense_off);
+ ret = copyout(ioctl_sense_mem, (unsigned long *)*sense_ptr,
+ user_ioc->sense_len);
+ if (ret) {
+ device_printf(sc->mrsas_dev, "IOCTL sense copyout failed!\n");
+ goto out;
+ }
+ }
+ /*
+ * Return command status to user space
+ */
+ memcpy(&user_ioc->frame.hdr.cmd_status, &cmd->frame->hdr.cmd_status,
+ sizeof(u_int8_t));
out:
- /*
- * Release sense buffer
- */
- if (ioctl_sense_phys_addr)
- bus_dmamap_unload(ioctl_sense_tag, ioctl_sense_dmamap);
- if (ioctl_sense_mem)
- bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, ioctl_sense_dmamap);
- if (ioctl_sense_tag)
- bus_dma_tag_destroy(ioctl_sense_tag);
-
- /*
- * Release data buffers
- */
- for (i = 0; i < user_ioc->sge_count; i++) {
- if (!user_ioc->sgl[i].iov_len)
- continue;
- if (ioctl_data_phys_addr[i])
- bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]);
- if (ioctl_data_mem[i] != NULL)
- bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i],
- ioctl_data_dmamap[i]);
- if (ioctl_data_tag[i] != NULL)
- bus_dma_tag_destroy(ioctl_data_tag[i]);
- }
-
- /* Free command */
- mrsas_release_mfi_cmd(cmd);
-
- return(ret);
+ /*
+ * Release sense buffer
+ */
+ if (ioctl_sense_phys_addr)
+ bus_dmamap_unload(ioctl_sense_tag, ioctl_sense_dmamap);
+ if (ioctl_sense_mem != NULL)
+ bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, ioctl_sense_dmamap);
+ if (ioctl_sense_tag != NULL)
+ bus_dma_tag_destroy(ioctl_sense_tag);
+
+ /*
+ * Release data buffers
+ */
+ for (i = 0; i < user_ioc->sge_count; i++) {
+ if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) {
+ if (!user_ioc->sgl[i].iov_len)
+ continue;
+#ifdef COMPAT_FREEBSD32
+ } else {
+ if (!user_ioc32->sgl[i].iov_len)
+ continue;
+#endif
+ }
+ if (ioctl_data_phys_addr[i])
+ bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]);
+ if (ioctl_data_mem[i] != NULL)
+ bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i],
+ ioctl_data_dmamap[i]);
+ if (ioctl_data_tag[i] != NULL)
+ bus_dma_tag_destroy(ioctl_data_tag[i]);
+ }
+ /* Free command */
+ mrsas_release_mfi_cmd(cmd);
+
+ return (ret);
}
-/**
- * mrsas_alloc_mfi_cmds: Allocates the command packets
- * input: Adapter instance soft state
+/*
+ * mrsas_alloc_mfi_cmds: Allocates the command packets
+ * input: Adapter instance soft state
*
* Each IOCTL or passthru command that is issued to the FW are wrapped in a
- * local data structure called mrsas_mfi_cmd. The frame embedded in this
- * mrsas_mfi is issued to FW. The array is used only to look up the
+ * local data structure called mrsas_mfi_cmd. The frame embedded in this
+ * mrsas_mfi is issued to FW. The array is used only to look up the
* mrsas_mfi_cmd given the context. The free commands are maintained in a
* linked list.
*/
-int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc)
+int
+mrsas_alloc_mfi_cmds(struct mrsas_softc *sc)
{
- int i, j;
- u_int32_t max_cmd;
- struct mrsas_mfi_cmd *cmd;
-
- max_cmd = MRSAS_MAX_MFI_CMDS;
-
- /*
- * sc->mfi_cmd_list is an array of struct mrsas_mfi_cmd pointers. Allocate the
- * dynamic array first and then allocate individual commands.
- */
- sc->mfi_cmd_list = malloc(sizeof(struct mrsas_mfi_cmd*)*max_cmd, M_MRSAS, M_NOWAIT);
- if (!sc->mfi_cmd_list) {
- device_printf(sc->mrsas_dev, "Cannot alloc memory for mfi_cmd cmd_list.\n");
- return(ENOMEM);
- }
- memset(sc->mfi_cmd_list, 0, sizeof(struct mrsas_mfi_cmd *)*max_cmd);
- for (i = 0; i < max_cmd; i++) {
- sc->mfi_cmd_list[i] = malloc(sizeof(struct mrsas_mfi_cmd),
- M_MRSAS, M_NOWAIT);
- if (!sc->mfi_cmd_list[i]) {
- for (j = 0; j < i; j++)
- free(sc->mfi_cmd_list[j],M_MRSAS);
- free(sc->mfi_cmd_list, M_MRSAS);
- sc->mfi_cmd_list = NULL;
- return(ENOMEM);
- }
- }
-
- for (i = 0; i < max_cmd; i++) {
- cmd = sc->mfi_cmd_list[i];
- memset(cmd, 0, sizeof(struct mrsas_mfi_cmd));
- cmd->index = i;
- cmd->ccb_ptr = NULL;
- cmd->sc = sc;
- TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next);
- }
-
- /* create a frame pool and assign one frame to each command */
- if (mrsas_create_frame_pool(sc)) {
- device_printf(sc->mrsas_dev, "Cannot allocate DMA frame pool.\n");
- for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { // Free the frames
- cmd = sc->mfi_cmd_list[i];
- mrsas_free_frame(sc, cmd);
- }
- if (sc->mficmd_frame_tag != NULL)
- bus_dma_tag_destroy(sc->mficmd_frame_tag);
- return(ENOMEM);
- }
-
- return(0);
+ int i, j;
+ u_int32_t max_cmd;
+ struct mrsas_mfi_cmd *cmd;
+
+ max_cmd = MRSAS_MAX_MFI_CMDS;
+
+ /*
+ * sc->mfi_cmd_list is an array of struct mrsas_mfi_cmd pointers.
+ * Allocate the dynamic array first and then allocate individual
+ * commands.
+ */
+ sc->mfi_cmd_list = malloc(sizeof(struct mrsas_mfi_cmd *) * max_cmd, M_MRSAS, M_NOWAIT);
+ if (!sc->mfi_cmd_list) {
+ device_printf(sc->mrsas_dev, "Cannot alloc memory for mfi_cmd cmd_list.\n");
+ return (ENOMEM);
+ }
+ memset(sc->mfi_cmd_list, 0, sizeof(struct mrsas_mfi_cmd *) * max_cmd);
+ for (i = 0; i < max_cmd; i++) {
+ sc->mfi_cmd_list[i] = malloc(sizeof(struct mrsas_mfi_cmd),
+ M_MRSAS, M_NOWAIT);
+ if (!sc->mfi_cmd_list[i]) {
+ for (j = 0; j < i; j++)
+ free(sc->mfi_cmd_list[j], M_MRSAS);
+ free(sc->mfi_cmd_list, M_MRSAS);
+ sc->mfi_cmd_list = NULL;
+ return (ENOMEM);
+ }
+ }
+
+ for (i = 0; i < max_cmd; i++) {
+ cmd = sc->mfi_cmd_list[i];
+ memset(cmd, 0, sizeof(struct mrsas_mfi_cmd));
+ cmd->index = i;
+ cmd->ccb_ptr = NULL;
+ cmd->sc = sc;
+ TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next);
+ }
+
+ /* create a frame pool and assign one frame to each command */
+ if (mrsas_create_frame_pool(sc)) {
+ device_printf(sc->mrsas_dev, "Cannot allocate DMA frame pool.\n");
+ /* Free the frames */
+ for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
+ cmd = sc->mfi_cmd_list[i];
+ mrsas_free_frame(sc, cmd);
+ }
+ if (sc->mficmd_frame_tag != NULL)
+ bus_dma_tag_destroy(sc->mficmd_frame_tag);
+ return (ENOMEM);
+ }
+ return (0);
}
-/**
- * mrsas_create_frame_pool - Creates DMA pool for cmd frames
- * input: Adapter soft state
+/*
+ * mrsas_create_frame_pool: Creates DMA pool for cmd frames
+ * input: Adapter soft state
*
* Each command packet has an embedded DMA memory buffer that is used for
* filling MFI frame and the SG list that immediately follows the frame. This
* function creates those DMA memory buffers for each command packet by using
- * PCI pool facility. pad_0 is initialized to 0 to prevent corrupting value
+ * PCI pool facility. pad_0 is initialized to 0 to prevent corrupting value
* of context and could cause FW crash.
*/
-static int mrsas_create_frame_pool(struct mrsas_softc *sc)
+static int
+mrsas_create_frame_pool(struct mrsas_softc *sc)
{
- int i;
- struct mrsas_mfi_cmd *cmd;
-
- if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent
- 1, 0, // algnmnt, boundary
- BUS_SPACE_MAXADDR_32BIT,// lowaddr
- BUS_SPACE_MAXADDR, // highaddr
- NULL, NULL, // filter, filterarg
- MRSAS_MFI_FRAME_SIZE, // maxsize
- 1, // msegments
- MRSAS_MFI_FRAME_SIZE, // maxsegsize
- BUS_DMA_ALLOCNOW, // flags
- NULL, NULL, // lockfunc, lockarg
- &sc->mficmd_frame_tag)) {
- device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n");
- return (ENOMEM);
- }
-
- for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
- cmd = sc->mfi_cmd_list[i];
- cmd->frame = mrsas_alloc_frame(sc, cmd);
- if (cmd->frame == NULL) {
- device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
- return (ENOMEM);
- }
- memset(cmd->frame, 0, MRSAS_MFI_FRAME_SIZE);
- cmd->frame->io.context = cmd->index;
- cmd->frame->io.pad_0 = 0;
- }
-
- return(0);
+ int i;
+ struct mrsas_mfi_cmd *cmd;
+
+ if (bus_dma_tag_create(sc->mrsas_parent_tag,
+ 1, 0,
+ BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR,
+ NULL, NULL,
+ MRSAS_MFI_FRAME_SIZE,
+ 1,
+ MRSAS_MFI_FRAME_SIZE,
+ BUS_DMA_ALLOCNOW,
+ NULL, NULL,
+ &sc->mficmd_frame_tag)) {
+ device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n");
+ return (ENOMEM);
+ }
+ for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
+ cmd = sc->mfi_cmd_list[i];
+ cmd->frame = mrsas_alloc_frame(sc, cmd);
+ if (cmd->frame == NULL) {
+ device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
+ return (ENOMEM);
+ }
+ memset(cmd->frame, 0, MRSAS_MFI_FRAME_SIZE);
+ cmd->frame->io.context = cmd->index;
+ cmd->frame->io.pad_0 = 0;
+ }
+
+ return (0);
}
-/**
- * mrsas_alloc_frame - Allocates MFI Frames
- * input: Adapter soft state
+/*
+ * mrsas_alloc_frame: Allocates MFI Frames
+ * input: Adapter soft state
*
- * Create bus DMA memory tag and dmamap and load memory for MFI frames.
- * Returns virtual memory pointer to allocated region.
+ * Create bus DMA memory tag and dmamap and load memory for MFI frames. Returns
+ * virtual memory pointer to allocated region.
*/
-void *mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
+void *
+mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
{
- u_int32_t frame_size = MRSAS_MFI_FRAME_SIZE;
-
- if (bus_dmamem_alloc(sc->mficmd_frame_tag, (void **)&cmd->frame_mem,
- BUS_DMA_NOWAIT, &cmd->frame_dmamap)) {
- device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
- return (NULL);
- }
- if (bus_dmamap_load(sc->mficmd_frame_tag, cmd->frame_dmamap,
- cmd->frame_mem, frame_size, mrsas_alloc_cb,
- &cmd->frame_phys_addr, BUS_DMA_NOWAIT)) {
- device_printf(sc->mrsas_dev, "Cannot load IO request memory\n");
- return (NULL);
- }
-
- return(cmd->frame_mem);
+ u_int32_t frame_size = MRSAS_MFI_FRAME_SIZE;
+
+ if (bus_dmamem_alloc(sc->mficmd_frame_tag, (void **)&cmd->frame_mem,
+ BUS_DMA_NOWAIT, &cmd->frame_dmamap)) {
+ device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
+ return (NULL);
+ }
+ if (bus_dmamap_load(sc->mficmd_frame_tag, cmd->frame_dmamap,
+ cmd->frame_mem, frame_size, mrsas_alloc_cb,
+ &cmd->frame_phys_addr, BUS_DMA_NOWAIT)) {
+ device_printf(sc->mrsas_dev, "Cannot load IO request memory\n");
+ return (NULL);
+ }
+ return (cmd->frame_mem);
}
/*
- * mrsas_alloc_cb: Callback function of bus_dmamap_load()
- * input: callback argument,
- * machine dependent type that describes DMA segments,
- * number of segments,
- * error code.
+ * mrsas_alloc_cb: Callback function of bus_dmamap_load()
+ * input: callback argument,
+ * machine dependent type that describes DMA segments,
+ * number of segments,
+ * error code.
*
- * This function is for the driver to receive mapping information resultant
- * of the bus_dmamap_load(). The information is actually not being used,
- * but the address is saved anyway.
+ * This function is for the driver to receive mapping information resultant of
+ * the bus_dmamap_load(). The information is actually not being used, but the
+ * address is saved anyway.
*/
-static void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
- int nsegs, int error)
+static void
+mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
+ int nsegs, int error)
{
- bus_addr_t *addr;
+ bus_addr_t *addr;
- addr = arg;
- *addr = segs[0].ds_addr;
+ addr = arg;
+ *addr = segs[0].ds_addr;
}
-/**
- * mrsas_free_frames: Frees memory for MFI frames
- * input: Adapter soft state
+/*
+ * mrsas_free_frames: Frees memory for MFI frames
+ * input: Adapter soft state
*
- * Deallocates MFI frames memory. Called from mrsas_free_mem() during
- * detach and error case during creation of frame pool.
+ * Deallocates MFI frames memory. Called from mrsas_free_mem() during detach
+ * and error case during creation of frame pool.
*/
-void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
+void
+mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
{
- if (cmd->frame_phys_addr)
- bus_dmamap_unload(sc->mficmd_frame_tag, cmd->frame_dmamap);
- if (cmd->frame_mem != NULL)
- bus_dmamem_free(sc->mficmd_frame_tag, cmd->frame_mem, cmd->frame_dmamap);
+ if (cmd->frame_phys_addr)
+ bus_dmamap_unload(sc->mficmd_frame_tag, cmd->frame_dmamap);
+ if (cmd->frame_mem != NULL)
+ bus_dmamem_free(sc->mficmd_frame_tag, cmd->frame_mem, cmd->frame_dmamap);
}
OpenPOWER on IntegriCloud