1265555Sambrisko/* 2282531Skadesai * Copyright (c) 2015, AVAGO Tech. All rights reserved. Author: Marian Choy 3272744Skadesai * Copyright (c) 2014, LSI Corp. All rights reserved. Author: Marian Choy 4282531Skadesai * Support: freebsdraid@avagotech.com 5265555Sambrisko * 6265555Sambrisko * Redistribution and use in source and binary forms, with or without 7272744Skadesai * modification, are permitted provided that the following conditions are 8272744Skadesai * met: 9265555Sambrisko * 10272744Skadesai * 1. Redistributions of source code must retain the above copyright notice, 11272744Skadesai * this list of conditions and the following disclaimer. 2. Redistributions 12272744Skadesai * in binary form must reproduce the above copyright notice, this list of 13272744Skadesai * conditions and the following disclaimer in the documentation and/or other 14272744Skadesai * materials provided with the distribution. 3. Neither the name of the 15272744Skadesai * <ORGANIZATION> nor the names of its contributors may be used to endorse or 16272744Skadesai * promote products derived from this software without specific prior written 17272744Skadesai * permission. 18265555Sambrisko * 19272744Skadesai * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20272744Skadesai * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21272744Skadesai * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22272744Skadesai * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23272744Skadesai * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24272744Skadesai * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25272744Skadesai * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26272744Skadesai * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27272744Skadesai * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28272744Skadesai * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29265555Sambrisko * POSSIBILITY OF SUCH DAMAGE. 30265555Sambrisko * 31272744Skadesai * The views and conclusions contained in the software and documentation are 32272744Skadesai * those of the authors and should not be interpreted as representing 33265555Sambrisko * official policies,either expressed or implied, of the FreeBSD Project. 34265555Sambrisko * 35282531Skadesai * Send feedback to: <megaraidfbsd@avagotech.com> Mail to: AVAGO TECHNOLOGIES, 1621 36272744Skadesai * Barber Lane, Milpitas, CA 95035 ATTN: MegaRaid FreeBSD 37265555Sambrisko * 38265555Sambrisko */ 39265555Sambrisko 40265555Sambrisko#include <sys/cdefs.h> 41265555Sambrisko__FBSDID("$FreeBSD$"); 42265555Sambrisko 43265555Sambrisko#include <dev/mrsas/mrsas.h> 44265555Sambrisko#include <dev/mrsas/mrsas_ioctl.h> 45265555Sambrisko 46272744Skadesai/* 47272744Skadesai * Function prototypes 48265555Sambrisko */ 49272744Skadesaiint mrsas_alloc_mfi_cmds(struct mrsas_softc *sc); 50272744Skadesaiint mrsas_passthru(struct mrsas_softc *sc, void *arg, u_long ioctlCmd); 51272744Skadesaivoid mrsas_free_ioc_cmd(struct mrsas_softc *sc); 52272744Skadesaivoid mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); 53272744Skadesaivoid *mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd); 54265555Sambriskostatic int mrsas_create_frame_pool(struct mrsas_softc *sc); 55272744Skadesaistatic void 56272744Skadesaimrsas_alloc_cb(void *arg, bus_dma_segment_t *segs, 57272744Skadesai int nsegs, int error); 58265555Sambrisko 59272744Skadesaiextern struct mrsas_mfi_cmd *mrsas_get_mfi_cmd(struct mrsas_softc *sc); 60265555Sambriskoextern void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd); 61272744Skadesaiextern int 62272744Skadesaimrsas_issue_blocked_cmd(struct mrsas_softc *sc, 63265555Sambrisko struct mrsas_mfi_cmd *cmd); 64265555Sambrisko 65272744Skadesai/* 66272744Skadesai * mrsas_passthru: Handle pass-through commands 67272744Skadesai * input: Adapter instance soft state argument pointer 68265555Sambrisko * 69272744Skadesai * This function is called from mrsas_ioctl() to handle pass-through and ioctl 70272744Skadesai * commands to Firmware. 71265555Sambrisko */ 72272744Skadesaiint 73272744Skadesaimrsas_passthru(struct mrsas_softc *sc, void *arg, u_long ioctlCmd) 74265555Sambrisko{ 75272744Skadesai struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg; 76272744Skadesai 77272737Skadesai#ifdef COMPAT_FREEBSD32 78272744Skadesai struct mrsas_iocpacket32 *user_ioc32 = (struct mrsas_iocpacket32 *)arg; 79272744Skadesai 80272737Skadesai#endif 81272744Skadesai union mrsas_frame *in_cmd = (union mrsas_frame *)&(user_ioc->frame.raw); 82272744Skadesai struct mrsas_mfi_cmd *cmd = NULL; 83272744Skadesai bus_dma_tag_t ioctl_data_tag[MAX_IOCTL_SGE]; 84272744Skadesai bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE]; 85272744Skadesai void *ioctl_data_mem[MAX_IOCTL_SGE]; 86272744Skadesai bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE]; 87272744Skadesai bus_dma_tag_t ioctl_sense_tag = 0; 88272744Skadesai bus_dmamap_t ioctl_sense_dmamap = 0; 89297862Spfg void *ioctl_sense_mem = NULL; 90272744Skadesai bus_addr_t ioctl_sense_phys_addr = 0; 91272744Skadesai int i, ioctl_data_size = 0, ioctl_sense_size, ret = 0; 92272744Skadesai struct mrsas_sge32 *kern_sge32; 93272744Skadesai unsigned long *sense_ptr; 94272744Skadesai uint8_t *iov_base_ptrin = NULL; 95272744Skadesai size_t iov_len = 0; 96265555Sambrisko 97272744Skadesai /* 98272744Skadesai * Check for NOP from MegaCli... MegaCli can issue a DCMD of 0. In 99272744Skadesai * this case do nothing and return 0 to it as status. 100272744Skadesai */ 101272744Skadesai if (in_cmd->dcmd.opcode == 0) { 102272744Skadesai device_printf(sc->mrsas_dev, "In %s() Got a NOP\n", __func__); 103272744Skadesai user_ioc->frame.hdr.cmd_status = MFI_STAT_OK; 104272744Skadesai return (0); 105272744Skadesai } 106272744Skadesai /* Validate SGL length */ 107272744Skadesai if (user_ioc->sge_count > MAX_IOCTL_SGE) { 108272744Skadesai device_printf(sc->mrsas_dev, "In %s() SGL is too long (%d > 8).\n", 109272744Skadesai __func__, user_ioc->sge_count); 110272744Skadesai return (ENOENT); 111272744Skadesai } 112272744Skadesai /* Get a command */ 113272744Skadesai cmd = mrsas_get_mfi_cmd(sc); 114272744Skadesai if (!cmd) { 115272744Skadesai device_printf(sc->mrsas_dev, "Failed to get a free cmd for IOCTL\n"); 116272744Skadesai return (ENOMEM); 117272744Skadesai } 118272744Skadesai /* 119272744Skadesai * User's IOCTL packet has 2 frames (maximum). Copy those two frames 120272744Skadesai * into our cmd's frames. cmd->frame's context will get overwritten 121272744Skadesai * when we copy from user's frames. So set that value alone 122272744Skadesai * separately 123272744Skadesai */ 124272744Skadesai memcpy(cmd->frame, user_ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE); 125272744Skadesai cmd->frame->hdr.context = cmd->index; 126272744Skadesai cmd->frame->hdr.pad_0 = 0; 127272744Skadesai cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 | 128272744Skadesai MFI_FRAME_SENSE64); 129265555Sambrisko 130272744Skadesai /* 131272744Skadesai * The management interface between applications and the fw uses MFI 132272744Skadesai * frames. E.g, RAID configuration changes, LD property changes etc 133272744Skadesai * are accomplishes through different kinds of MFI frames. The driver 134272744Skadesai * needs to care only about substituting user buffers with kernel 135272744Skadesai * buffers in SGLs. The location of SGL is embedded in the struct 136272744Skadesai * iocpacket itself. 137272744Skadesai */ 138272744Skadesai kern_sge32 = (struct mrsas_sge32 *) 139272744Skadesai ((unsigned long)cmd->frame + user_ioc->sgl_off); 140265555Sambrisko 141299671Skadesai memset(ioctl_data_tag, 0, (sizeof(bus_dma_tag_t) * MAX_IOCTL_SGE)); 142299671Skadesai memset(ioctl_data_dmamap, 0, (sizeof(bus_dmamap_t) * MAX_IOCTL_SGE)); 143299671Skadesai memset(ioctl_data_mem, 0, (sizeof(void *) * MAX_IOCTL_SGE)); 144299671Skadesai memset(ioctl_data_phys_addr, 0, (sizeof(bus_addr_t) * MAX_IOCTL_SGE)); 145299671Skadesai 146272744Skadesai /* 147272744Skadesai * For each user buffer, create a mirror buffer and copy in 148272744Skadesai */ 149272744Skadesai for (i = 0; i < user_ioc->sge_count; i++) { 150272744Skadesai if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 151272744Skadesai if (!user_ioc->sgl[i].iov_len) 152272744Skadesai continue; 153272744Skadesai ioctl_data_size = user_ioc->sgl[i].iov_len; 154272737Skadesai#ifdef COMPAT_FREEBSD32 155272744Skadesai } else { 156272744Skadesai if (!user_ioc32->sgl[i].iov_len) 157272744Skadesai continue; 158272744Skadesai ioctl_data_size = user_ioc32->sgl[i].iov_len; 159272737Skadesai#endif 160272744Skadesai } 161272744Skadesai if (bus_dma_tag_create(sc->mrsas_parent_tag, 162272744Skadesai 1, 0, 163272744Skadesai BUS_SPACE_MAXADDR_32BIT, 164272744Skadesai BUS_SPACE_MAXADDR, 165272744Skadesai NULL, NULL, 166272744Skadesai ioctl_data_size, 167272744Skadesai 1, 168272744Skadesai ioctl_data_size, 169272744Skadesai BUS_DMA_ALLOCNOW, 170272744Skadesai NULL, NULL, 171272744Skadesai &ioctl_data_tag[i])) { 172272744Skadesai device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n"); 173272741Skadesai ret = ENOMEM; 174272741Skadesai goto out; 175272744Skadesai } 176272744Skadesai if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i], 177272744Skadesai (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) { 178272744Skadesai device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n"); 179272741Skadesai ret = ENOMEM; 180272741Skadesai goto out; 181272744Skadesai } 182272744Skadesai if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i], 183272744Skadesai ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb, 184272744Skadesai &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) { 185272744Skadesai device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n"); 186272744Skadesai ret = ENOMEM; 187272744Skadesai goto out; 188272744Skadesai } 189272744Skadesai /* Save the physical address and length */ 190272744Skadesai kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i]; 191265555Sambrisko 192272744Skadesai if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 193272744Skadesai kern_sge32[i].length = user_ioc->sgl[i].iov_len; 194265555Sambrisko 195272744Skadesai iov_base_ptrin = user_ioc->sgl[i].iov_base; 196272744Skadesai iov_len = user_ioc->sgl[i].iov_len; 197272737Skadesai#ifdef COMPAT_FREEBSD32 198272744Skadesai } else { 199272744Skadesai kern_sge32[i].length = user_ioc32->sgl[i].iov_len; 200272737Skadesai 201272744Skadesai iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base); 202272744Skadesai iov_len = user_ioc32->sgl[i].iov_len; 203272737Skadesai#endif 204272744Skadesai } 205272744Skadesai 206272744Skadesai /* Copy in data from user space */ 207272744Skadesai ret = copyin(iov_base_ptrin, ioctl_data_mem[i], iov_len); 208272744Skadesai if (ret) { 209272744Skadesai device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n"); 210272744Skadesai goto out; 211272744Skadesai } 212272737Skadesai } 213272737Skadesai 214272744Skadesai ioctl_sense_size = user_ioc->sense_len; 215265555Sambrisko 216272744Skadesai if (user_ioc->sense_len) { 217272744Skadesai if (bus_dma_tag_create(sc->mrsas_parent_tag, 218272744Skadesai 1, 0, 219272744Skadesai BUS_SPACE_MAXADDR_32BIT, 220272744Skadesai BUS_SPACE_MAXADDR, 221272744Skadesai NULL, NULL, 222272744Skadesai ioctl_sense_size, 223272744Skadesai 1, 224272744Skadesai ioctl_sense_size, 225272744Skadesai BUS_DMA_ALLOCNOW, 226272744Skadesai NULL, NULL, 227272744Skadesai &ioctl_sense_tag)) { 228272744Skadesai device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense tag\n"); 229272744Skadesai ret = ENOMEM; 230272741Skadesai goto out; 231272744Skadesai } 232272744Skadesai if (bus_dmamem_alloc(ioctl_sense_tag, (void **)&ioctl_sense_mem, 233272744Skadesai (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_sense_dmamap)) { 234272744Skadesai device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense mem\n"); 235272744Skadesai ret = ENOMEM; 236272741Skadesai goto out; 237272744Skadesai } 238272744Skadesai if (bus_dmamap_load(ioctl_sense_tag, ioctl_sense_dmamap, 239272744Skadesai ioctl_sense_mem, ioctl_sense_size, mrsas_alloc_cb, 240272744Skadesai &ioctl_sense_phys_addr, BUS_DMA_NOWAIT)) { 241272744Skadesai device_printf(sc->mrsas_dev, "Cannot load ioctl sense mem\n"); 242272744Skadesai ret = ENOMEM; 243272741Skadesai goto out; 244272744Skadesai } 245272744Skadesai sense_ptr = 246272744Skadesai (unsigned long *)((unsigned long)cmd->frame + user_ioc->sense_off); 247282531Skadesai *sense_ptr = ioctl_sense_phys_addr; 248272744Skadesai } 249272744Skadesai /* 250272744Skadesai * Set the sync_cmd flag so that the ISR knows not to complete this 251272744Skadesai * cmd to the SCSI mid-layer 252272744Skadesai */ 253272744Skadesai cmd->sync_cmd = 1; 254299666Skadesai ret = mrsas_issue_blocked_cmd(sc, cmd); 255299666Skadesai if (ret == ETIMEDOUT) { 256299666Skadesai mrsas_dprint(sc, MRSAS_OCR, 257299666Skadesai "IOCTL command is timed out, initiating OCR\n"); 258299666Skadesai sc->do_timedout_reset = MFI_DCMD_TIMEOUT_OCR; 259299666Skadesai ret = EAGAIN; 260299666Skadesai goto out; 261299666Skadesai } 262272744Skadesai cmd->sync_cmd = 0; 263265555Sambrisko 264272744Skadesai /* 265272744Skadesai * copy out the kernel buffers to user buffers 266272744Skadesai */ 267272744Skadesai for (i = 0; i < user_ioc->sge_count; i++) { 268272744Skadesai if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 269272744Skadesai iov_base_ptrin = user_ioc->sgl[i].iov_base; 270272744Skadesai iov_len = user_ioc->sgl[i].iov_len; 271272737Skadesai#ifdef COMPAT_FREEBSD32 272272744Skadesai } else { 273272744Skadesai iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base); 274272744Skadesai iov_len = user_ioc32->sgl[i].iov_len; 275272737Skadesai#endif 276272744Skadesai } 277272737Skadesai 278272744Skadesai ret = copyout(ioctl_data_mem[i], iov_base_ptrin, iov_len); 279272744Skadesai if (ret) { 280272744Skadesai device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n"); 281272744Skadesai goto out; 282272744Skadesai } 283272744Skadesai } 284265555Sambrisko 285272744Skadesai /* 286272744Skadesai * copy out the sense 287272744Skadesai */ 288272744Skadesai if (user_ioc->sense_len) { 289272744Skadesai /* 290272744Skadesai * sense_buff points to the location that has the user sense 291272744Skadesai * buffer address 292272744Skadesai */ 293272744Skadesai sense_ptr = (unsigned long *)((unsigned long)user_ioc->frame.raw + 294272744Skadesai user_ioc->sense_off); 295272744Skadesai ret = copyout(ioctl_sense_mem, (unsigned long *)*sense_ptr, 296272744Skadesai user_ioc->sense_len); 297272744Skadesai if (ret) { 298272744Skadesai device_printf(sc->mrsas_dev, "IOCTL sense copyout failed!\n"); 299272744Skadesai goto out; 300272744Skadesai } 301272744Skadesai } 302272744Skadesai /* 303272744Skadesai * Return command status to user space 304272744Skadesai */ 305272744Skadesai memcpy(&user_ioc->frame.hdr.cmd_status, &cmd->frame->hdr.cmd_status, 306272744Skadesai sizeof(u_int8_t)); 307265555Sambrisko 308265555Sambriskoout: 309272744Skadesai /* 310272744Skadesai * Release sense buffer 311272744Skadesai */ 312282531Skadesai if (user_ioc->sense_len) { 313282531Skadesai if (ioctl_sense_phys_addr) 314282531Skadesai bus_dmamap_unload(ioctl_sense_tag, ioctl_sense_dmamap); 315282531Skadesai if (ioctl_sense_mem != NULL) 316282531Skadesai bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, ioctl_sense_dmamap); 317282531Skadesai if (ioctl_sense_tag != NULL) 318282531Skadesai bus_dma_tag_destroy(ioctl_sense_tag); 319282531Skadesai } 320272744Skadesai /* 321272744Skadesai * Release data buffers 322272744Skadesai */ 323272744Skadesai for (i = 0; i < user_ioc->sge_count; i++) { 324272744Skadesai if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 325272744Skadesai if (!user_ioc->sgl[i].iov_len) 326272744Skadesai continue; 327272741Skadesai#ifdef COMPAT_FREEBSD32 328272744Skadesai } else { 329272744Skadesai if (!user_ioc32->sgl[i].iov_len) 330272744Skadesai continue; 331272741Skadesai#endif 332272744Skadesai } 333272744Skadesai if (ioctl_data_phys_addr[i]) 334272744Skadesai bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]); 335272744Skadesai if (ioctl_data_mem[i] != NULL) 336272744Skadesai bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i], 337272744Skadesai ioctl_data_dmamap[i]); 338272744Skadesai if (ioctl_data_tag[i] != NULL) 339272744Skadesai bus_dma_tag_destroy(ioctl_data_tag[i]); 340272744Skadesai } 341272744Skadesai /* Free command */ 342272744Skadesai mrsas_release_mfi_cmd(cmd); 343265555Sambrisko 344272744Skadesai return (ret); 345265555Sambrisko} 346265555Sambrisko 347272744Skadesai/* 348272744Skadesai * mrsas_alloc_mfi_cmds: Allocates the command packets 349272744Skadesai * input: Adapter instance soft state 350265555Sambrisko * 351265555Sambrisko * Each IOCTL or passthru command that is issued to the FW are wrapped in a 352272744Skadesai * local data structure called mrsas_mfi_cmd. The frame embedded in this 353272744Skadesai * mrsas_mfi is issued to FW. The array is used only to look up the 354265555Sambrisko * mrsas_mfi_cmd given the context. The free commands are maintained in a 355265555Sambrisko * linked list. 356265555Sambrisko */ 357272744Skadesaiint 358272744Skadesaimrsas_alloc_mfi_cmds(struct mrsas_softc *sc) 359265555Sambrisko{ 360272744Skadesai int i, j; 361272744Skadesai u_int32_t max_cmd; 362272744Skadesai struct mrsas_mfi_cmd *cmd; 363265555Sambrisko 364272744Skadesai max_cmd = MRSAS_MAX_MFI_CMDS; 365265555Sambrisko 366272744Skadesai /* 367272744Skadesai * sc->mfi_cmd_list is an array of struct mrsas_mfi_cmd pointers. 368272744Skadesai * Allocate the dynamic array first and then allocate individual 369272744Skadesai * commands. 370272744Skadesai */ 371272744Skadesai sc->mfi_cmd_list = malloc(sizeof(struct mrsas_mfi_cmd *) * max_cmd, M_MRSAS, M_NOWAIT); 372272744Skadesai if (!sc->mfi_cmd_list) { 373272744Skadesai device_printf(sc->mrsas_dev, "Cannot alloc memory for mfi_cmd cmd_list.\n"); 374272744Skadesai return (ENOMEM); 375272744Skadesai } 376272744Skadesai memset(sc->mfi_cmd_list, 0, sizeof(struct mrsas_mfi_cmd *) * max_cmd); 377272744Skadesai for (i = 0; i < max_cmd; i++) { 378272744Skadesai sc->mfi_cmd_list[i] = malloc(sizeof(struct mrsas_mfi_cmd), 379272744Skadesai M_MRSAS, M_NOWAIT); 380272744Skadesai if (!sc->mfi_cmd_list[i]) { 381272744Skadesai for (j = 0; j < i; j++) 382272744Skadesai free(sc->mfi_cmd_list[j], M_MRSAS); 383272744Skadesai free(sc->mfi_cmd_list, M_MRSAS); 384272744Skadesai sc->mfi_cmd_list = NULL; 385272744Skadesai return (ENOMEM); 386272744Skadesai } 387272744Skadesai } 388265555Sambrisko 389272744Skadesai for (i = 0; i < max_cmd; i++) { 390272744Skadesai cmd = sc->mfi_cmd_list[i]; 391272744Skadesai memset(cmd, 0, sizeof(struct mrsas_mfi_cmd)); 392272744Skadesai cmd->index = i; 393272744Skadesai cmd->ccb_ptr = NULL; 394272744Skadesai cmd->sc = sc; 395272744Skadesai TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next); 396272744Skadesai } 397265555Sambrisko 398272744Skadesai /* create a frame pool and assign one frame to each command */ 399272744Skadesai if (mrsas_create_frame_pool(sc)) { 400272744Skadesai device_printf(sc->mrsas_dev, "Cannot allocate DMA frame pool.\n"); 401272744Skadesai /* Free the frames */ 402272744Skadesai for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { 403272744Skadesai cmd = sc->mfi_cmd_list[i]; 404272744Skadesai mrsas_free_frame(sc, cmd); 405272744Skadesai } 406272744Skadesai if (sc->mficmd_frame_tag != NULL) 407272744Skadesai bus_dma_tag_destroy(sc->mficmd_frame_tag); 408272744Skadesai return (ENOMEM); 409272744Skadesai } 410272744Skadesai return (0); 411265555Sambrisko} 412265555Sambrisko 413272744Skadesai/* 414272744Skadesai * mrsas_create_frame_pool: Creates DMA pool for cmd frames 415272744Skadesai * input: Adapter soft state 416265555Sambrisko * 417265555Sambrisko * Each command packet has an embedded DMA memory buffer that is used for 418265555Sambrisko * filling MFI frame and the SG list that immediately follows the frame. This 419265555Sambrisko * function creates those DMA memory buffers for each command packet by using 420272744Skadesai * PCI pool facility. pad_0 is initialized to 0 to prevent corrupting value 421265555Sambrisko * of context and could cause FW crash. 422265555Sambrisko */ 423272744Skadesaistatic int 424272744Skadesaimrsas_create_frame_pool(struct mrsas_softc *sc) 425265555Sambrisko{ 426272744Skadesai int i; 427272744Skadesai struct mrsas_mfi_cmd *cmd; 428265555Sambrisko 429272744Skadesai if (bus_dma_tag_create(sc->mrsas_parent_tag, 430272744Skadesai 1, 0, 431272744Skadesai BUS_SPACE_MAXADDR_32BIT, 432272744Skadesai BUS_SPACE_MAXADDR, 433272744Skadesai NULL, NULL, 434272744Skadesai MRSAS_MFI_FRAME_SIZE, 435272744Skadesai 1, 436272744Skadesai MRSAS_MFI_FRAME_SIZE, 437272744Skadesai BUS_DMA_ALLOCNOW, 438272744Skadesai NULL, NULL, 439272744Skadesai &sc->mficmd_frame_tag)) { 440272744Skadesai device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n"); 441272744Skadesai return (ENOMEM); 442272744Skadesai } 443272744Skadesai for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { 444272744Skadesai cmd = sc->mfi_cmd_list[i]; 445272744Skadesai cmd->frame = mrsas_alloc_frame(sc, cmd); 446272744Skadesai if (cmd->frame == NULL) { 447272744Skadesai device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n"); 448272744Skadesai return (ENOMEM); 449272744Skadesai } 450299671Skadesai /* 451299671Skadesai * For MFI controllers. 452299671Skadesai * max_num_sge = 60 453299671Skadesai * max_sge_sz = 16 byte (sizeof megasas_sge_skinny) 454299671Skadesai * Totl 960 byte (15 MFI frame of 64 byte) 455299671Skadesai * 456299671Skadesai * Fusion adapter require only 3 extra frame. 457299671Skadesai * max_num_sge = 16 (defined as MAX_IOCTL_SGE) 458299671Skadesai * max_sge_sz = 12 byte (sizeof megasas_sge64) 459299671Skadesai * Total 192 byte (3 MFI frame of 64 byte) 460299671Skadesai */ 461272744Skadesai memset(cmd->frame, 0, MRSAS_MFI_FRAME_SIZE); 462272744Skadesai cmd->frame->io.context = cmd->index; 463272744Skadesai cmd->frame->io.pad_0 = 0; 464272744Skadesai } 465265555Sambrisko 466272744Skadesai return (0); 467265555Sambrisko} 468265555Sambrisko 469272744Skadesai/* 470272744Skadesai * mrsas_alloc_frame: Allocates MFI Frames 471272744Skadesai * input: Adapter soft state 472265555Sambrisko * 473272744Skadesai * Create bus DMA memory tag and dmamap and load memory for MFI frames. Returns 474272744Skadesai * virtual memory pointer to allocated region. 475265555Sambrisko */ 476272744Skadesaivoid * 477272744Skadesaimrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) 478265555Sambrisko{ 479272744Skadesai u_int32_t frame_size = MRSAS_MFI_FRAME_SIZE; 480265555Sambrisko 481272744Skadesai if (bus_dmamem_alloc(sc->mficmd_frame_tag, (void **)&cmd->frame_mem, 482272744Skadesai BUS_DMA_NOWAIT, &cmd->frame_dmamap)) { 483272744Skadesai device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n"); 484272744Skadesai return (NULL); 485272744Skadesai } 486272744Skadesai if (bus_dmamap_load(sc->mficmd_frame_tag, cmd->frame_dmamap, 487272744Skadesai cmd->frame_mem, frame_size, mrsas_alloc_cb, 488272744Skadesai &cmd->frame_phys_addr, BUS_DMA_NOWAIT)) { 489272744Skadesai device_printf(sc->mrsas_dev, "Cannot load IO request memory\n"); 490272744Skadesai return (NULL); 491272744Skadesai } 492272744Skadesai return (cmd->frame_mem); 493265555Sambrisko} 494265555Sambrisko 495265555Sambrisko/* 496272744Skadesai * mrsas_alloc_cb: Callback function of bus_dmamap_load() 497272744Skadesai * input: callback argument, 498272744Skadesai * machine dependent type that describes DMA segments, 499272744Skadesai * number of segments, 500272744Skadesai * error code. 501265555Sambrisko * 502272744Skadesai * This function is for the driver to receive mapping information resultant of 503272744Skadesai * the bus_dmamap_load(). The information is actually not being used, but the 504272744Skadesai * address is saved anyway. 505265555Sambrisko */ 506272744Skadesaistatic void 507272744Skadesaimrsas_alloc_cb(void *arg, bus_dma_segment_t *segs, 508272744Skadesai int nsegs, int error) 509265555Sambrisko{ 510272744Skadesai bus_addr_t *addr; 511265555Sambrisko 512272744Skadesai addr = arg; 513272744Skadesai *addr = segs[0].ds_addr; 514265555Sambrisko} 515265555Sambrisko 516272744Skadesai/* 517272744Skadesai * mrsas_free_frames: Frees memory for MFI frames 518272744Skadesai * input: Adapter soft state 519265555Sambrisko * 520272744Skadesai * Deallocates MFI frames memory. Called from mrsas_free_mem() during detach 521272744Skadesai * and error case during creation of frame pool. 522265555Sambrisko */ 523272744Skadesaivoid 524272744Skadesaimrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) 525265555Sambrisko{ 526272744Skadesai if (cmd->frame_phys_addr) 527272744Skadesai bus_dmamap_unload(sc->mficmd_frame_tag, cmd->frame_dmamap); 528272744Skadesai if (cmd->frame_mem != NULL) 529272744Skadesai bus_dmamem_free(sc->mficmd_frame_tag, cmd->frame_mem, cmd->frame_dmamap); 530265555Sambrisko} 531