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