diff options
Diffstat (limited to 'sys/dev/mrsas/mrsas_ioctl.c')
-rw-r--r-- | sys/dev/mrsas/mrsas_ioctl.c | 921 |
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); } |