1265555Sambrisko/* 2265555Sambrisko * Copyright (c) 2014, LSI Corp. 3265555Sambrisko * All rights reserved. 4265555Sambrisko * Author: Marian Choy 5265555Sambrisko * Support: freebsdraid@lsi.com 6265555Sambrisko * 7265555Sambrisko * Redistribution and use in source and binary forms, with or without 8265555Sambrisko * modification, are permitted provided that the following conditions 9265555Sambrisko * are met: 10265555Sambrisko * 11265555Sambrisko * 1. Redistributions of source code must retain the above copyright 12265555Sambrisko * notice, this list of conditions and the following disclaimer. 13265555Sambrisko * 2. Redistributions in binary form must reproduce the above copyright 14265555Sambrisko * notice, this list of conditions and the following disclaimer in 15265555Sambrisko * the documentation and/or other materials provided with the 16265555Sambrisko * distribution. 17265555Sambrisko * 3. Neither the name of the <ORGANIZATION> nor the names of its 18265555Sambrisko * contributors may be used to endorse or promote products derived 19265555Sambrisko * from this software without specific prior written permission. 20265555Sambrisko * 21265555Sambrisko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22265555Sambrisko * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23265555Sambrisko * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24265555Sambrisko * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25265555Sambrisko * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26265555Sambrisko * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27265555Sambrisko * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28265555Sambrisko * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29265555Sambrisko * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30265555Sambrisko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31265555Sambrisko * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32265555Sambrisko * POSSIBILITY OF SUCH DAMAGE. 33265555Sambrisko * 34265555Sambrisko * The views and conclusions contained in the software and documentation 35265555Sambrisko * are those of the authors and should not be interpreted as representing 36265555Sambrisko * official policies,either expressed or implied, of the FreeBSD Project. 37265555Sambrisko * 38265555Sambrisko * Send feedback to: <megaraidfbsd@lsi.com> 39265555Sambrisko * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 40265555Sambrisko * ATTN: MegaRaid FreeBSD 41265555Sambrisko * 42265555Sambrisko */ 43265555Sambrisko 44265555Sambrisko#include <sys/cdefs.h> 45265555Sambrisko__FBSDID("$FreeBSD$"); 46265555Sambrisko 47265555Sambrisko#include <dev/mrsas/mrsas.h> 48265555Sambrisko#include <dev/mrsas/mrsas_ioctl.h> 49265555Sambrisko 50265555Sambrisko/* 51265555Sambrisko * Function prototypes 52265555Sambrisko */ 53265555Sambriskoint mrsas_alloc_mfi_cmds(struct mrsas_softc *sc); 54265555Sambriskoint mrsas_passthru(struct mrsas_softc *sc, void *arg); 55265555Sambriskovoid mrsas_free_ioc_cmd(struct mrsas_softc *sc); 56265555Sambriskovoid mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); 57265555Sambriskovoid mrsas_dump_dcmd(struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd); 58265555Sambriskovoid mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc); 59265555Sambriskovoid * mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); 60265555Sambriskostatic int mrsas_create_frame_pool(struct mrsas_softc *sc); 61265555Sambriskostatic void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs, 62265555Sambrisko int nsegs, int error); 63265555Sambrisko 64265555Sambriskoextern struct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc); 65265555Sambriskoextern void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd); 66265555Sambriskoextern int mrsas_issue_blocked_cmd(struct mrsas_softc *sc, 67265555Sambrisko struct mrsas_mfi_cmd *cmd); 68265555Sambrisko 69265555Sambrisko 70265555Sambrisko/** 71265555Sambrisko * mrsas_dump_ioctl: Print debug output for DCMDs 72265555Sambrisko * input: Adapter instance soft state 73265555Sambrisko * DCMD frame structure 74265555Sambrisko * 75265555Sambrisko * This function is called from mrsas_passthru() to print out debug information 76265555Sambrisko * in the handling and routing of DCMD commands. 77265555Sambrisko */ 78265555Sambriskovoid mrsas_dump_dcmd( struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd ) 79265555Sambrisko{ 80265555Sambrisko int i; 81265555Sambrisko 82265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->cmd: 0x%02hhx\n", dcmd->cmd); 83265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->cmd_status: 0x%02hhx\n", dcmd->cmd_status); 84265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->sge_count: 0x%02hhx\n", dcmd->sge_count); 85265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->context: 0x%08x\n", dcmd->context); 86265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->flags: 0x%04hx\n", dcmd->flags); 87265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->timeout: 0x%04hx\n", dcmd->timeout); 88265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->data_xfer_len: 0x%08x\n", dcmd->data_xfer_len); 89265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->opcode: 0x%08x\n", dcmd->opcode); 90265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->mbox.w[0]: 0x%08x\n", dcmd->mbox.w[0]); 91265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->mbox.w[1]: 0x%08x\n", dcmd->mbox.w[1]); 92265555Sambrisko device_printf(sc->mrsas_dev, "dcmd->mbox.w[2]: 0x%08x\n", dcmd->mbox.w[2]); 93265555Sambrisko for (i=0; i< MIN(MAX_IOCTL_SGE, dcmd->sge_count); i++) { 94265555Sambrisko device_printf(sc->mrsas_dev, "sgl[%02d]\n", i); 95265555Sambrisko device_printf(sc->mrsas_dev, " sge32[%02d].phys_addr: 0x%08x\n", 96265555Sambrisko i, dcmd->sgl.sge32[i].phys_addr); 97265555Sambrisko device_printf(sc->mrsas_dev, " sge32[%02d].length: 0x%08x\n", 98265555Sambrisko i, dcmd->sgl.sge32[i].length); 99265555Sambrisko device_printf(sc->mrsas_dev, " sge64[%02d].phys_addr: 0x%08llx\n", 100265555Sambrisko i, (long long unsigned int) dcmd->sgl.sge64[i].phys_addr); 101265555Sambrisko device_printf(sc->mrsas_dev, " sge64[%02d].length: 0x%08x\n", 102265555Sambrisko i, dcmd->sgl.sge64[i].length); 103265555Sambrisko } 104265555Sambrisko} 105265555Sambrisko 106265555Sambrisko/** 107265555Sambrisko * mrsas_dump_ioctl: Print debug output for ioctl 108265555Sambrisko * input: Adapter instance soft state 109265555Sambrisko * iocpacket structure 110265555Sambrisko * 111265555Sambrisko * This function is called from mrsas_passthru() to print out debug information 112265555Sambrisko * in the handling and routing of ioctl commands. 113265555Sambrisko */ 114265555Sambriskovoid mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc) 115265555Sambrisko{ 116265555Sambrisko union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw); 117265555Sambrisko struct mrsas_dcmd_frame* dcmd = (struct mrsas_dcmd_frame *) &(in_cmd->dcmd); 118265555Sambrisko int i; 119265555Sambrisko 120265555Sambrisko device_printf(sc->mrsas_dev, 121265555Sambrisko "====== In %s() ======================================\n", __func__); 122265555Sambrisko device_printf(sc->mrsas_dev, "host_no: 0x%04hx\n", user_ioc->host_no); 123265555Sambrisko device_printf(sc->mrsas_dev, " __pad1: 0x%04hx\n", user_ioc->__pad1); 124265555Sambrisko device_printf(sc->mrsas_dev, "sgl_off: 0x%08x\n", user_ioc->sgl_off); 125265555Sambrisko device_printf(sc->mrsas_dev, "sge_count: 0x%08x\n", user_ioc->sge_count); 126265555Sambrisko device_printf(sc->mrsas_dev, "sense_off: 0x%08x\n", user_ioc->sense_off); 127265555Sambrisko device_printf(sc->mrsas_dev, "sense_len: 0x%08x\n", user_ioc->sense_len); 128265555Sambrisko 129265555Sambrisko mrsas_dump_dcmd(sc, dcmd); 130265555Sambrisko 131265555Sambrisko for (i=0; i< MIN(MAX_IOCTL_SGE, user_ioc->sge_count); i++) { 132265555Sambrisko device_printf(sc->mrsas_dev, "sge[%02d]\n", i); 133265555Sambrisko device_printf(sc->mrsas_dev, 134265555Sambrisko " iov_base: %p\n", user_ioc->sgl[i].iov_base); 135265555Sambrisko device_printf(sc->mrsas_dev, " iov_len: %p\n", 136265555Sambrisko (void*)user_ioc->sgl[i].iov_len); 137265555Sambrisko } 138265555Sambrisko device_printf(sc->mrsas_dev, 139265555Sambrisko "==================================================================\n"); 140265555Sambrisko} 141265555Sambrisko 142265555Sambrisko/** 143265555Sambrisko * mrsas_passthru: Handle pass-through commands 144265555Sambrisko * input: Adapter instance soft state 145265555Sambrisko * argument pointer 146265555Sambrisko * 147265555Sambrisko * This function is called from mrsas_ioctl() to handle pass-through and 148265555Sambrisko * ioctl commands to Firmware. 149265555Sambrisko */ 150265555Sambriskoint mrsas_passthru( struct mrsas_softc *sc, void *arg ) 151265555Sambrisko{ 152265555Sambrisko struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg; 153265555Sambrisko union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw); 154265555Sambrisko struct mrsas_mfi_cmd *cmd = NULL; 155265555Sambrisko bus_dma_tag_t ioctl_data_tag[MAX_IOCTL_SGE]; 156265555Sambrisko bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE]; 157265555Sambrisko void *ioctl_data_mem[MAX_IOCTL_SGE]; // ioctl data virtual addr 158265555Sambrisko bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE]; // ioctl data phys addr 159265555Sambrisko bus_dma_tag_t ioctl_sense_tag = 0; 160265555Sambrisko bus_dmamap_t ioctl_sense_dmamap = 0; 161265555Sambrisko void *ioctl_sense_mem = 0; 162265555Sambrisko bus_addr_t ioctl_sense_phys_addr = 0; 163265555Sambrisko int i, adapter, ioctl_data_size, ioctl_sense_size, ret=0; 164265555Sambrisko struct mrsas_sge32 *kern_sge32; 165265555Sambrisko unsigned long *sense_ptr; 166265555Sambrisko 167265555Sambrisko /* For debug - uncomment the following line for debug output */ 168265555Sambrisko //mrsas_dump_ioctl(sc, user_ioc); 169265555Sambrisko 170265555Sambrisko /* 171265555Sambrisko * Check for NOP from MegaCli... MegaCli can issue a DCMD of 0. In this 172265555Sambrisko * case do nothing and return 0 to it as status. 173265555Sambrisko */ 174265555Sambrisko if (in_cmd->dcmd.opcode == 0) { 175265555Sambrisko device_printf(sc->mrsas_dev, "In %s() Got a NOP\n", __func__); 176265555Sambrisko user_ioc->frame.hdr.cmd_status = MFI_STAT_OK; 177265555Sambrisko return (0); 178265555Sambrisko } 179265555Sambrisko 180265555Sambrisko /* Validate host_no */ 181265555Sambrisko adapter = user_ioc->host_no; 182265555Sambrisko if (adapter != device_get_unit(sc->mrsas_dev)) { 183265555Sambrisko device_printf(sc->mrsas_dev, "In %s() IOCTL not for me!\n", __func__); 184265555Sambrisko return(ENOENT); 185265555Sambrisko } 186265555Sambrisko 187265555Sambrisko /* Validate SGL length */ 188265555Sambrisko if (user_ioc->sge_count > MAX_IOCTL_SGE) { 189265555Sambrisko device_printf(sc->mrsas_dev, "In %s() SGL is too long (%d > 8).\n", 190265555Sambrisko __func__, user_ioc->sge_count); 191265555Sambrisko return(ENOENT); 192265555Sambrisko } 193265555Sambrisko 194265555Sambrisko /* Get a command */ 195265555Sambrisko cmd = mrsas_get_mfi_cmd(sc); 196265555Sambrisko if (!cmd) { 197265555Sambrisko device_printf(sc->mrsas_dev, "Failed to get a free cmd for IOCTL\n"); 198265555Sambrisko return(ENOMEM); 199265555Sambrisko } 200265555Sambrisko 201265555Sambrisko /* 202265555Sambrisko * User's IOCTL packet has 2 frames (maximum). Copy those two 203265555Sambrisko * frames into our cmd's frames. cmd->frame's context will get 204265555Sambrisko * overwritten when we copy from user's frames. So set that value 205265555Sambrisko * alone separately 206265555Sambrisko */ 207265555Sambrisko memcpy(cmd->frame, user_ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE); 208265555Sambrisko cmd->frame->hdr.context = cmd->index; 209265555Sambrisko cmd->frame->hdr.pad_0 = 0; 210265555Sambrisko cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 | 211265555Sambrisko MFI_FRAME_SENSE64); 212265555Sambrisko 213265555Sambrisko /* 214265555Sambrisko * The management interface between applications and the fw uses 215265555Sambrisko * MFI frames. E.g, RAID configuration changes, LD property changes 216265555Sambrisko * etc are accomplishes through different kinds of MFI frames. The 217265555Sambrisko * driver needs to care only about substituting user buffers with 218265555Sambrisko * kernel buffers in SGLs. The location of SGL is embedded in the 219265555Sambrisko * struct iocpacket itself. 220265555Sambrisko */ 221265555Sambrisko kern_sge32 = (struct mrsas_sge32 *) 222265555Sambrisko ((unsigned long)cmd->frame + user_ioc->sgl_off); 223265555Sambrisko 224265555Sambrisko /* 225265555Sambrisko * For each user buffer, create a mirror buffer and copy in 226265555Sambrisko */ 227265555Sambrisko for (i=0; i < user_ioc->sge_count; i++) { 228265555Sambrisko if (!user_ioc->sgl[i].iov_len) 229265555Sambrisko continue; 230265555Sambrisko ioctl_data_size = user_ioc->sgl[i].iov_len; 231265555Sambrisko if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent 232265555Sambrisko 1, 0, // algnmnt, boundary 233265555Sambrisko BUS_SPACE_MAXADDR_32BIT,// lowaddr 234265555Sambrisko BUS_SPACE_MAXADDR, // highaddr 235265555Sambrisko NULL, NULL, // filter, filterarg 236265555Sambrisko ioctl_data_size, // maxsize 237265555Sambrisko 1, // msegments 238265555Sambrisko ioctl_data_size, // maxsegsize 239265555Sambrisko BUS_DMA_ALLOCNOW, // flags 240265555Sambrisko NULL, NULL, // lockfunc, lockarg 241265555Sambrisko &ioctl_data_tag[i])) { 242265555Sambrisko device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n"); 243265555Sambrisko return (ENOMEM); 244265555Sambrisko } 245265555Sambrisko if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i], 246265555Sambrisko (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) { 247265555Sambrisko device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n"); 248265555Sambrisko return (ENOMEM); 249265555Sambrisko } 250265555Sambrisko if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i], 251265555Sambrisko ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb, 252265555Sambrisko &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) { 253265555Sambrisko device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n"); 254265555Sambrisko return (ENOMEM); 255265555Sambrisko } 256265555Sambrisko 257265555Sambrisko /* Save the physical address and length */ 258265555Sambrisko kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i]; 259265555Sambrisko kern_sge32[i].length = user_ioc->sgl[i].iov_len; 260265555Sambrisko 261265555Sambrisko /* Copy in data from user space */ 262265555Sambrisko ret = copyin(user_ioc->sgl[i].iov_base, ioctl_data_mem[i], 263265555Sambrisko user_ioc->sgl[i].iov_len); 264265555Sambrisko if (ret) { 265265555Sambrisko device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n"); 266265555Sambrisko goto out; 267265555Sambrisko } 268265555Sambrisko } 269265555Sambrisko 270265555Sambrisko ioctl_sense_size = user_ioc->sense_len; 271265555Sambrisko if (user_ioc->sense_len) { 272265555Sambrisko if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent 273265555Sambrisko 1, 0, // algnmnt, boundary 274265555Sambrisko BUS_SPACE_MAXADDR_32BIT,// lowaddr 275265555Sambrisko BUS_SPACE_MAXADDR, // highaddr 276265555Sambrisko NULL, NULL, // filter, filterarg 277265555Sambrisko ioctl_sense_size, // maxsize 278265555Sambrisko 1, // msegments 279265555Sambrisko ioctl_sense_size, // maxsegsize 280265555Sambrisko BUS_DMA_ALLOCNOW, // flags 281265555Sambrisko NULL, NULL, // lockfunc, lockarg 282265555Sambrisko &ioctl_sense_tag)) { 283265555Sambrisko device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense tag\n"); 284265555Sambrisko return (ENOMEM); 285265555Sambrisko } 286265555Sambrisko if (bus_dmamem_alloc(ioctl_sense_tag, (void **)&ioctl_sense_mem, 287265555Sambrisko (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_sense_dmamap)) { 288265555Sambrisko device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n"); 289265555Sambrisko return (ENOMEM); 290265555Sambrisko } 291265555Sambrisko if (bus_dmamap_load(ioctl_sense_tag, ioctl_sense_dmamap, 292265555Sambrisko ioctl_sense_mem, ioctl_sense_size, mrsas_alloc_cb, 293265555Sambrisko &ioctl_sense_phys_addr, BUS_DMA_NOWAIT)) { 294265555Sambrisko device_printf(sc->mrsas_dev, "Cannot load ioctl sense mem\n"); 295265555Sambrisko return (ENOMEM); 296265555Sambrisko } 297265555Sambrisko sense_ptr = 298265555Sambrisko (unsigned long *)((unsigned long)cmd->frame + user_ioc->sense_off); 299265555Sambrisko sense_ptr = ioctl_sense_mem; 300265555Sambrisko } 301265555Sambrisko 302265555Sambrisko /* 303265555Sambrisko * Set the sync_cmd flag so that the ISR knows not to complete this 304265555Sambrisko * cmd to the SCSI mid-layer 305265555Sambrisko */ 306265555Sambrisko cmd->sync_cmd = 1; 307265555Sambrisko mrsas_issue_blocked_cmd(sc, cmd); 308265555Sambrisko cmd->sync_cmd = 0; 309265555Sambrisko 310265555Sambrisko /* 311265555Sambrisko * copy out the kernel buffers to user buffers 312265555Sambrisko */ 313265555Sambrisko for (i = 0; i < user_ioc->sge_count; i++) { 314265555Sambrisko ret = copyout(ioctl_data_mem[i], user_ioc->sgl[i].iov_base, 315265555Sambrisko user_ioc->sgl[i].iov_len); 316265555Sambrisko if (ret) { 317265555Sambrisko device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n"); 318265555Sambrisko goto out; 319265555Sambrisko } 320265555Sambrisko } 321265555Sambrisko 322265555Sambrisko /* 323265555Sambrisko * copy out the sense 324265555Sambrisko */ 325265555Sambrisko if (user_ioc->sense_len) { 326265555Sambrisko /* 327265555Sambrisko * sense_buff points to the location that has the user 328265555Sambrisko * sense buffer address 329265555Sambrisko */ 330265555Sambrisko sense_ptr = (unsigned long *) ((unsigned long)user_ioc->frame.raw + 331265555Sambrisko user_ioc->sense_off); 332265555Sambrisko ret = copyout(ioctl_sense_mem, (unsigned long*)*sense_ptr, 333265555Sambrisko user_ioc->sense_len); 334265555Sambrisko if (ret) { 335265555Sambrisko device_printf(sc->mrsas_dev, "IOCTL sense copyout failed!\n"); 336265555Sambrisko goto out; 337265555Sambrisko } 338265555Sambrisko } 339265555Sambrisko 340265555Sambrisko /* 341265555Sambrisko * Return command status to user space 342265555Sambrisko */ 343265555Sambrisko memcpy(&user_ioc->frame.hdr.cmd_status, &cmd->frame->hdr.cmd_status, 344265555Sambrisko sizeof(u_int8_t)); 345265555Sambrisko 346265555Sambriskoout: 347265555Sambrisko /* 348265555Sambrisko * Release sense buffer 349265555Sambrisko */ 350265555Sambrisko if (ioctl_sense_phys_addr) 351265555Sambrisko bus_dmamap_unload(ioctl_sense_tag, ioctl_sense_dmamap); 352265555Sambrisko if (ioctl_sense_mem) 353265555Sambrisko bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, ioctl_sense_dmamap); 354265555Sambrisko if (ioctl_sense_tag) 355265555Sambrisko bus_dma_tag_destroy(ioctl_sense_tag); 356265555Sambrisko 357265555Sambrisko /* 358265555Sambrisko * Release data buffers 359265555Sambrisko */ 360265555Sambrisko for (i = 0; i < user_ioc->sge_count; i++) { 361265555Sambrisko if (!user_ioc->sgl[i].iov_len) 362265555Sambrisko continue; 363265555Sambrisko if (ioctl_data_phys_addr[i]) 364265555Sambrisko bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]); 365265555Sambrisko if (ioctl_data_mem[i] != NULL) 366265555Sambrisko bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i], 367265555Sambrisko ioctl_data_dmamap[i]); 368265555Sambrisko if (ioctl_data_tag[i] != NULL) 369265555Sambrisko bus_dma_tag_destroy(ioctl_data_tag[i]); 370265555Sambrisko } 371265555Sambrisko 372265555Sambrisko /* Free command */ 373265555Sambrisko mrsas_release_mfi_cmd(cmd); 374265555Sambrisko 375265555Sambrisko return(ret); 376265555Sambrisko} 377265555Sambrisko 378265555Sambrisko/** 379265555Sambrisko * mrsas_alloc_mfi_cmds: Allocates the command packets 380265555Sambrisko * input: Adapter instance soft state 381265555Sambrisko * 382265555Sambrisko * Each IOCTL or passthru command that is issued to the FW are wrapped in a 383265555Sambrisko * local data structure called mrsas_mfi_cmd. The frame embedded in this 384265555Sambrisko * mrsas_mfi is issued to FW. The array is used only to look up the 385265555Sambrisko * mrsas_mfi_cmd given the context. The free commands are maintained in a 386265555Sambrisko * linked list. 387265555Sambrisko */ 388265555Sambriskoint mrsas_alloc_mfi_cmds(struct mrsas_softc *sc) 389265555Sambrisko{ 390265555Sambrisko int i, j; 391265555Sambrisko u_int32_t max_cmd; 392265555Sambrisko struct mrsas_mfi_cmd *cmd; 393265555Sambrisko 394265555Sambrisko max_cmd = MRSAS_MAX_MFI_CMDS; 395265555Sambrisko 396265555Sambrisko /* 397265555Sambrisko * sc->mfi_cmd_list is an array of struct mrsas_mfi_cmd pointers. Allocate the 398265555Sambrisko * dynamic array first and then allocate individual commands. 399265555Sambrisko */ 400265555Sambrisko sc->mfi_cmd_list = malloc(sizeof(struct mrsas_mfi_cmd*)*max_cmd, M_MRSAS, M_NOWAIT); 401265555Sambrisko if (!sc->mfi_cmd_list) { 402265555Sambrisko device_printf(sc->mrsas_dev, "Cannot alloc memory for mfi_cmd cmd_list.\n"); 403265555Sambrisko return(ENOMEM); 404265555Sambrisko } 405265555Sambrisko memset(sc->mfi_cmd_list, 0, sizeof(struct mrsas_mfi_cmd *)*max_cmd); 406265555Sambrisko for (i = 0; i < max_cmd; i++) { 407265555Sambrisko sc->mfi_cmd_list[i] = malloc(sizeof(struct mrsas_mfi_cmd), 408265555Sambrisko M_MRSAS, M_NOWAIT); 409265555Sambrisko if (!sc->mfi_cmd_list[i]) { 410265555Sambrisko for (j = 0; j < i; j++) 411265555Sambrisko free(sc->mfi_cmd_list[j],M_MRSAS); 412265555Sambrisko free(sc->mfi_cmd_list, M_MRSAS); 413265555Sambrisko sc->mfi_cmd_list = NULL; 414265555Sambrisko return(ENOMEM); 415265555Sambrisko } 416265555Sambrisko } 417265555Sambrisko 418265555Sambrisko for (i = 0; i < max_cmd; i++) { 419265555Sambrisko cmd = sc->mfi_cmd_list[i]; 420265555Sambrisko memset(cmd, 0, sizeof(struct mrsas_mfi_cmd)); 421265555Sambrisko cmd->index = i; 422265555Sambrisko cmd->ccb_ptr = NULL; 423265555Sambrisko cmd->sc = sc; 424265555Sambrisko TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next); 425265555Sambrisko } 426265555Sambrisko 427265555Sambrisko /* create a frame pool and assign one frame to each command */ 428265555Sambrisko if (mrsas_create_frame_pool(sc)) { 429265555Sambrisko device_printf(sc->mrsas_dev, "Cannot allocate DMA frame pool.\n"); 430265555Sambrisko for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { // Free the frames 431265555Sambrisko cmd = sc->mfi_cmd_list[i]; 432265555Sambrisko mrsas_free_frame(sc, cmd); 433265555Sambrisko } 434265555Sambrisko if (sc->mficmd_frame_tag != NULL) 435265555Sambrisko bus_dma_tag_destroy(sc->mficmd_frame_tag); 436265555Sambrisko return(ENOMEM); 437265555Sambrisko } 438265555Sambrisko 439265555Sambrisko return(0); 440265555Sambrisko} 441265555Sambrisko 442265555Sambrisko/** 443265555Sambrisko * mrsas_create_frame_pool - Creates DMA pool for cmd frames 444265555Sambrisko * input: Adapter soft state 445265555Sambrisko * 446265555Sambrisko * Each command packet has an embedded DMA memory buffer that is used for 447265555Sambrisko * filling MFI frame and the SG list that immediately follows the frame. This 448265555Sambrisko * function creates those DMA memory buffers for each command packet by using 449265555Sambrisko * PCI pool facility. pad_0 is initialized to 0 to prevent corrupting value 450265555Sambrisko * of context and could cause FW crash. 451265555Sambrisko */ 452265555Sambriskostatic int mrsas_create_frame_pool(struct mrsas_softc *sc) 453265555Sambrisko{ 454265555Sambrisko int i; 455265555Sambrisko struct mrsas_mfi_cmd *cmd; 456265555Sambrisko 457265555Sambrisko if (bus_dma_tag_create( sc->mrsas_parent_tag, // parent 458265555Sambrisko 1, 0, // algnmnt, boundary 459265555Sambrisko BUS_SPACE_MAXADDR_32BIT,// lowaddr 460265555Sambrisko BUS_SPACE_MAXADDR, // highaddr 461265555Sambrisko NULL, NULL, // filter, filterarg 462265555Sambrisko MRSAS_MFI_FRAME_SIZE, // maxsize 463265555Sambrisko 1, // msegments 464265555Sambrisko MRSAS_MFI_FRAME_SIZE, // maxsegsize 465265555Sambrisko BUS_DMA_ALLOCNOW, // flags 466265555Sambrisko NULL, NULL, // lockfunc, lockarg 467265555Sambrisko &sc->mficmd_frame_tag)) { 468265555Sambrisko device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n"); 469265555Sambrisko return (ENOMEM); 470265555Sambrisko } 471265555Sambrisko 472265555Sambrisko for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { 473265555Sambrisko cmd = sc->mfi_cmd_list[i]; 474265555Sambrisko cmd->frame = mrsas_alloc_frame(sc, cmd); 475265555Sambrisko if (cmd->frame == NULL) { 476265555Sambrisko device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n"); 477265555Sambrisko return (ENOMEM); 478265555Sambrisko } 479265555Sambrisko memset(cmd->frame, 0, MRSAS_MFI_FRAME_SIZE); 480265555Sambrisko cmd->frame->io.context = cmd->index; 481265555Sambrisko cmd->frame->io.pad_0 = 0; 482265555Sambrisko } 483265555Sambrisko 484265555Sambrisko return(0); 485265555Sambrisko} 486265555Sambrisko 487265555Sambrisko/** 488265555Sambrisko * mrsas_alloc_frame - Allocates MFI Frames 489265555Sambrisko * input: Adapter soft state 490265555Sambrisko * 491265555Sambrisko * Create bus DMA memory tag and dmamap and load memory for MFI frames. 492265555Sambrisko * Returns virtual memory pointer to allocated region. 493265555Sambrisko */ 494265555Sambriskovoid *mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) 495265555Sambrisko{ 496265555Sambrisko u_int32_t frame_size = MRSAS_MFI_FRAME_SIZE; 497265555Sambrisko 498265555Sambrisko if (bus_dmamem_alloc(sc->mficmd_frame_tag, (void **)&cmd->frame_mem, 499265555Sambrisko BUS_DMA_NOWAIT, &cmd->frame_dmamap)) { 500265555Sambrisko device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n"); 501265555Sambrisko return (NULL); 502265555Sambrisko } 503265555Sambrisko if (bus_dmamap_load(sc->mficmd_frame_tag, cmd->frame_dmamap, 504265555Sambrisko cmd->frame_mem, frame_size, mrsas_alloc_cb, 505265555Sambrisko &cmd->frame_phys_addr, BUS_DMA_NOWAIT)) { 506265555Sambrisko device_printf(sc->mrsas_dev, "Cannot load IO request memory\n"); 507265555Sambrisko return (NULL); 508265555Sambrisko } 509265555Sambrisko 510265555Sambrisko return(cmd->frame_mem); 511265555Sambrisko} 512265555Sambrisko 513265555Sambrisko/* 514265555Sambrisko * mrsas_alloc_cb: Callback function of bus_dmamap_load() 515265555Sambrisko * input: callback argument, 516265555Sambrisko * machine dependent type that describes DMA segments, 517265555Sambrisko * number of segments, 518265555Sambrisko * error code. 519265555Sambrisko * 520265555Sambrisko * This function is for the driver to receive mapping information resultant 521265555Sambrisko * of the bus_dmamap_load(). The information is actually not being used, 522265555Sambrisko * but the address is saved anyway. 523265555Sambrisko */ 524265555Sambriskostatic void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs, 525265555Sambrisko int nsegs, int error) 526265555Sambrisko{ 527265555Sambrisko bus_addr_t *addr; 528265555Sambrisko 529265555Sambrisko addr = arg; 530265555Sambrisko *addr = segs[0].ds_addr; 531265555Sambrisko} 532265555Sambrisko 533265555Sambrisko/** 534265555Sambrisko * mrsas_free_frames: Frees memory for MFI frames 535265555Sambrisko * input: Adapter soft state 536265555Sambrisko * 537265555Sambrisko * Deallocates MFI frames memory. Called from mrsas_free_mem() during 538265555Sambrisko * detach and error case during creation of frame pool. 539265555Sambrisko */ 540265555Sambriskovoid mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) 541265555Sambrisko{ 542265555Sambrisko if (cmd->frame_phys_addr) 543265555Sambrisko bus_dmamap_unload(sc->mficmd_frame_tag, cmd->frame_dmamap); 544265555Sambrisko if (cmd->frame_mem != NULL) 545265555Sambrisko bus_dmamem_free(sc->mficmd_frame_tag, cmd->frame_mem, cmd->frame_dmamap); 546265555Sambrisko} 547