xref: /dragonfly/sys/dev/raid/mrsas/mrsas_ioctl.c (revision f9993810)
1 /*
2  * Copyright (c) 2014, LSI Corp.
3  * All rights reserved.
4  * Author: Marian Choy
5  * Support: freebsdraid@lsi.com
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of the <ORGANIZATION> nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * The views and conclusions contained in the software and documentation
35  * are those of the authors and should not be interpreted as representing
36  * official policies,either expressed or implied, of the FreeBSD Project.
37  *
38  * Send feedback to: <megaraidfbsd@lsi.com>
39  * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
40  *    ATTN: MegaRaid FreeBSD
41  *
42  * $FreeBSD: head/sys/dev/mrsas/mrsas_ioctl.c 265555 2014-05-07 16:16:49Z ambrisko $
43  */
44 
45 #include <dev/raid/mrsas/mrsas.h>
46 #include <dev/raid/mrsas/mrsas_ioctl.h>
47 
48 /*
49  * Function prototypes
50  */
51 int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc);
52 int mrsas_passthru(struct mrsas_softc *sc, void *arg);
53 void mrsas_free_ioc_cmd(struct mrsas_softc *sc);
54 void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
55 void mrsas_dump_dcmd(struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd);
56 void mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc);
57 void * mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
58 static int mrsas_create_frame_pool(struct mrsas_softc *sc);
59 static void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
60         int nsegs, int error);
61 
62 extern struct mrsas_mfi_cmd* mrsas_get_mfi_cmd(struct mrsas_softc *sc);
63 extern void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd);
64 extern int mrsas_issue_blocked_cmd(struct mrsas_softc *sc,
65     struct mrsas_mfi_cmd *cmd);
66 
67 
68 /**
69  * mrsas_dump_ioctl:       Print debug output for DCMDs
70  * input:                  Adapter instance soft state
71  *                         DCMD frame structure
72  *
73  * This function is called from mrsas_passthru() to print out debug information
74  * in the handling and routing of DCMD commands.
75  */
76 void mrsas_dump_dcmd( struct mrsas_softc *sc, struct mrsas_dcmd_frame* dcmd )
77 {
78     int i;
79 
80     device_printf(sc->mrsas_dev, "dcmd->cmd:           0x%02hhx\n", dcmd->cmd);
81     device_printf(sc->mrsas_dev, "dcmd->cmd_status:    0x%02hhx\n", dcmd->cmd_status);
82     device_printf(sc->mrsas_dev, "dcmd->sge_count:     0x%02hhx\n", dcmd->sge_count);
83     device_printf(sc->mrsas_dev, "dcmd->context:       0x%08x\n", dcmd->context);
84     device_printf(sc->mrsas_dev, "dcmd->flags:         0x%04hx\n", dcmd->flags);
85     device_printf(sc->mrsas_dev, "dcmd->timeout:       0x%04hx\n", dcmd->timeout);
86     device_printf(sc->mrsas_dev, "dcmd->data_xfer_len: 0x%08x\n", dcmd->data_xfer_len);
87     device_printf(sc->mrsas_dev, "dcmd->opcode:        0x%08x\n", dcmd->opcode);
88     device_printf(sc->mrsas_dev, "dcmd->mbox.w[0]:     0x%08x\n", dcmd->mbox.w[0]);
89     device_printf(sc->mrsas_dev, "dcmd->mbox.w[1]:     0x%08x\n", dcmd->mbox.w[1]);
90     device_printf(sc->mrsas_dev, "dcmd->mbox.w[2]:     0x%08x\n", dcmd->mbox.w[2]);
91     for (i=0; i< MIN(MAX_IOCTL_SGE, dcmd->sge_count); i++) {
92         device_printf(sc->mrsas_dev, "sgl[%02d]\n", i);
93         device_printf(sc->mrsas_dev, "    sge32[%02d].phys_addr: 0x%08x\n",
94             i, dcmd->sgl.sge32[i].phys_addr);
95         device_printf(sc->mrsas_dev, "    sge32[%02d].length:    0x%08x\n",
96             i, dcmd->sgl.sge32[i].length);
97         device_printf(sc->mrsas_dev, "    sge64[%02d].phys_addr: 0x%08llx\n",
98             i, (unsigned long long) dcmd->sgl.sge64[i].phys_addr);
99         device_printf(sc->mrsas_dev, "    sge64[%02d].length:    0x%08x\n",
100             i, dcmd->sgl.sge64[i].length);
101     }
102 }
103 
104 /**
105  * mrsas_dump_ioctl:       Print debug output for ioctl
106  * input:                  Adapter instance soft state
107  *                         iocpacket structure
108  *
109  * This function is called from mrsas_passthru() to print out debug information
110  * in the handling and routing of ioctl commands.
111  */
112 void mrsas_dump_ioctl(struct mrsas_softc *sc, struct mrsas_iocpacket *user_ioc)
113 {
114     union mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw);
115     struct mrsas_dcmd_frame* dcmd = (struct mrsas_dcmd_frame *) &(in_cmd->dcmd);
116     int i;
117 
118     device_printf(sc->mrsas_dev,
119         "====== In %s() ======================================\n", __func__);
120     device_printf(sc->mrsas_dev, "host_no:    0x%04hx\n", user_ioc->host_no);
121     device_printf(sc->mrsas_dev, " __pad1:    0x%04hx\n", user_ioc->__pad1);
122     device_printf(sc->mrsas_dev, "sgl_off:    0x%08x\n",  user_ioc->sgl_off);
123     device_printf(sc->mrsas_dev, "sge_count:  0x%08x\n",  user_ioc->sge_count);
124     device_printf(sc->mrsas_dev, "sense_off:  0x%08x\n",  user_ioc->sense_off);
125     device_printf(sc->mrsas_dev, "sense_len:  0x%08x\n",  user_ioc->sense_len);
126 
127     mrsas_dump_dcmd(sc, dcmd);
128 
129     for (i=0; i< MIN(MAX_IOCTL_SGE, user_ioc->sge_count); i++) {
130         device_printf(sc->mrsas_dev, "sge[%02d]\n", i);
131         device_printf(sc->mrsas_dev,
132             "    iov_base: %p\n", user_ioc->sgl[i].iov_base);
133         device_printf(sc->mrsas_dev, "    iov_len:  %p\n",
134             (void*)user_ioc->sgl[i].iov_len);
135     }
136     device_printf(sc->mrsas_dev,
137         "==================================================================\n");
138 }
139 
140 /**
141  * mrsas_passthru:        Handle pass-through commands
142  * input:                 Adapter instance soft state
143  *                        argument pointer
144  *
145  * This function is called from mrsas_ioctl() to handle pass-through and
146  * ioctl commands to Firmware.
147  */
148 int mrsas_passthru( struct mrsas_softc *sc, void *arg )
149 {
150     struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg;
151     union  mrsas_frame *in_cmd = (union mrsas_frame *) &(user_ioc->frame.raw);
152     struct mrsas_mfi_cmd *cmd = NULL;
153     bus_dma_tag_t ioctl_data_tag[MAX_IOCTL_SGE];
154     bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE];
155     void *ioctl_data_mem[MAX_IOCTL_SGE];  // ioctl data virtual addr
156     bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE]; // ioctl data phys addr
157     bus_dma_tag_t ioctl_sense_tag = 0;
158     bus_dmamap_t ioctl_sense_dmamap = 0;
159     void *ioctl_sense_mem = NULL;
160     bus_addr_t ioctl_sense_phys_addr = 0;
161     int i, adapter, ioctl_data_size, ioctl_sense_size, ret=0;
162     struct mrsas_sge32 *kern_sge32;
163     unsigned long *sense_ptr;
164 
165     /* For debug - uncomment the following line for debug output */
166     //mrsas_dump_ioctl(sc, user_ioc);
167 
168     /*
169      * Check for NOP from MegaCli... MegaCli can issue a DCMD of 0.  In this
170      * case do nothing and return 0 to it as status.
171      */
172     if (in_cmd->dcmd.opcode == 0) {
173         device_printf(sc->mrsas_dev, "In %s() Got a NOP\n", __func__);
174         user_ioc->frame.hdr.cmd_status = MFI_STAT_OK;
175         return (0);
176     }
177 
178     /* Validate host_no */
179     adapter = user_ioc->host_no;
180     if (adapter != device_get_unit(sc->mrsas_dev)) {
181         device_printf(sc->mrsas_dev, "In %s() IOCTL not for me!\n", __func__);
182         return(ENOENT);
183     }
184 
185     /* Validate SGL length */
186     if (user_ioc->sge_count > MAX_IOCTL_SGE) {
187         device_printf(sc->mrsas_dev, "In %s() SGL is too long (%d > 8).\n",
188             __func__, user_ioc->sge_count);
189         return(ENOENT);
190     }
191 
192     /* Get a command */
193     cmd = mrsas_get_mfi_cmd(sc);
194     if (!cmd) {
195         device_printf(sc->mrsas_dev, "Failed to get a free cmd for IOCTL\n");
196         return(ENOMEM);
197     }
198 
199     /*
200      * User's IOCTL packet has 2 frames (maximum). Copy those two
201      * frames into our cmd's frames. cmd->frame's context will get
202      * overwritten when we copy from user's frames. So set that value
203      * alone separately
204      */
205     memcpy(cmd->frame, user_ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
206     cmd->frame->hdr.context = cmd->index;
207     cmd->frame->hdr.pad_0 = 0;
208     cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 |
209                                MFI_FRAME_SENSE64);
210 
211     /*
212      * The management interface between applications and the fw uses
213      * MFI frames. E.g, RAID configuration changes, LD property changes
214      * etc are accomplishes through different kinds of MFI frames. The
215      * driver needs to care only about substituting user buffers with
216      * kernel buffers in SGLs. The location of SGL is embedded in the
217      * struct iocpacket itself.
218      */
219     kern_sge32 = (struct mrsas_sge32 *)
220         ((unsigned long)cmd->frame + user_ioc->sgl_off);
221 
222     /*
223      * For each user buffer, create a mirror buffer and copy in
224      */
225     for (i=0; i < user_ioc->sge_count; i++) {
226         if (!user_ioc->sgl[i].iov_len)
227             continue;
228         ioctl_data_size = user_ioc->sgl[i].iov_len;
229         if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
230                                 1, 0,                   // algnmnt, boundary
231                                 BUS_SPACE_MAXADDR_32BIT,// lowaddr
232                                 BUS_SPACE_MAXADDR,      // highaddr
233                                 ioctl_data_size,        // maxsize
234                                 1,                      // msegments
235                                 ioctl_data_size,        // maxsegsize
236                                 BUS_DMA_ALLOCNOW,       // flags
237                                 &ioctl_data_tag[i])) {
238             device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n");
239             return (ENOMEM);
240         }
241         if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i],
242                 (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) {
243             device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n");
244             return (ENOMEM);
245         }
246         if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i],
247                 ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb,
248                 &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) {
249             device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n");
250             return (ENOMEM);
251         }
252 
253         /* Save the physical address and length */
254         kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i];
255         kern_sge32[i].length = user_ioc->sgl[i].iov_len;
256 
257         /* Copy in data from user space */
258         ret = copyin(user_ioc->sgl[i].iov_base, ioctl_data_mem[i],
259                         user_ioc->sgl[i].iov_len);
260         if (ret) {
261             device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n");
262             goto out;
263         }
264     }
265 
266     ioctl_sense_size = user_ioc->sense_len;
267     if (user_ioc->sense_len) {
268         if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
269                                 1, 0,                   // algnmnt, boundary
270                                 BUS_SPACE_MAXADDR_32BIT,// lowaddr
271                                 BUS_SPACE_MAXADDR,      // highaddr
272                                 ioctl_sense_size,       // maxsize
273                                 1,                      // msegments
274                                 ioctl_sense_size,       // maxsegsize
275                                 BUS_DMA_ALLOCNOW,       // flags
276                                 &ioctl_sense_tag)) {
277             device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense tag\n");
278             return (ENOMEM);
279         }
280         if (bus_dmamem_alloc(ioctl_sense_tag, (void **)&ioctl_sense_mem,
281                 (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_sense_dmamap)) {
282             device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n");
283             return (ENOMEM);
284         }
285         if (bus_dmamap_load(ioctl_sense_tag, ioctl_sense_dmamap,
286                 ioctl_sense_mem, ioctl_sense_size, mrsas_alloc_cb,
287                 &ioctl_sense_phys_addr, BUS_DMA_NOWAIT)) {
288             device_printf(sc->mrsas_dev, "Cannot load ioctl sense mem\n");
289             return (ENOMEM);
290         }
291         sense_ptr =
292             (unsigned long *)((unsigned long)cmd->frame + user_ioc->sense_off);
293 	*sense_ptr = ioctl_sense_phys_addr;
294     }
295 
296     /*
297      * Set the sync_cmd flag so that the ISR knows not to complete this
298      * cmd to the SCSI mid-layer
299      */
300     cmd->sync_cmd = 1;
301     mrsas_issue_blocked_cmd(sc, cmd);
302     cmd->sync_cmd = 0;
303 
304     /*
305      * copy out the kernel buffers to user buffers
306      */
307     for (i = 0; i < user_ioc->sge_count; i++) {
308         ret = copyout(ioctl_data_mem[i], user_ioc->sgl[i].iov_base,
309             user_ioc->sgl[i].iov_len);
310         if (ret) {
311             device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n");
312             goto out;
313         }
314     }
315 
316     /*
317      * copy out the sense
318      */
319     if (user_ioc->sense_len) {
320         /*
321          * sense_buff points to the location that has the user
322          * sense buffer address
323          */
324         sense_ptr = (unsigned long *) ((unsigned long)user_ioc->frame.raw +
325                       user_ioc->sense_off);
326         ret = copyout(ioctl_sense_mem, (unsigned long*)*sense_ptr,
327                       user_ioc->sense_len);
328         if (ret) {
329             device_printf(sc->mrsas_dev, "IOCTL sense copyout failed!\n");
330             goto out;
331         }
332     }
333 
334     /*
335      * Return command status to user space
336      */
337     memcpy(&user_ioc->frame.hdr.cmd_status, &cmd->frame->hdr.cmd_status,
338             sizeof(u_int8_t));
339 
340 out:
341     /*
342      * Release sense buffer
343      */
344     if (ioctl_sense_phys_addr)
345         bus_dmamap_unload(ioctl_sense_tag, ioctl_sense_dmamap);
346     if (ioctl_sense_mem)
347         bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, ioctl_sense_dmamap);
348     if (ioctl_sense_tag)
349         bus_dma_tag_destroy(ioctl_sense_tag);
350 
351     /*
352      * Release data buffers
353      */
354     for (i = 0; i < user_ioc->sge_count; i++) {
355         if (!user_ioc->sgl[i].iov_len)
356             continue;
357         if (ioctl_data_phys_addr[i])
358             bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]);
359         if (ioctl_data_mem[i] != NULL)
360             bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i],
361                 ioctl_data_dmamap[i]);
362         if (ioctl_data_tag[i] != NULL)
363             bus_dma_tag_destroy(ioctl_data_tag[i]);
364     }
365 
366     /* Free command */
367     mrsas_release_mfi_cmd(cmd);
368 
369     return(ret);
370 }
371 
372 /**
373  * mrsas_alloc_mfi_cmds:  Allocates the command packets
374  * input:                 Adapter instance soft state
375  *
376  * Each IOCTL or passthru command that is issued to the FW are wrapped in a
377  * local data structure called mrsas_mfi_cmd.  The frame embedded in this
378  * mrsas_mfi is issued to FW. The array is used only to look up the
379  * mrsas_mfi_cmd given the context. The free commands are maintained in a
380  * linked list.
381  */
382 int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc)
383 {
384     int i, j;
385     u_int32_t max_cmd;
386     struct mrsas_mfi_cmd *cmd;
387 
388     max_cmd = MRSAS_MAX_MFI_CMDS;
389 
390     /*
391      * sc->mfi_cmd_list is an array of struct mrsas_mfi_cmd pointers. Allocate the
392      * dynamic array first and then allocate individual commands.
393      */
394     sc->mfi_cmd_list = kmalloc(sizeof(struct mrsas_mfi_cmd*)*max_cmd, M_MRSAS, M_NOWAIT);
395     if (!sc->mfi_cmd_list) {
396         device_printf(sc->mrsas_dev, "Cannot alloc memory for mfi_cmd cmd_list.\n");
397         return(ENOMEM);
398     }
399     memset(sc->mfi_cmd_list, 0, sizeof(struct mrsas_mfi_cmd *)*max_cmd);
400     for (i = 0; i < max_cmd; i++) {
401         sc->mfi_cmd_list[i] = kmalloc(sizeof(struct mrsas_mfi_cmd),
402                                  M_MRSAS, M_NOWAIT);
403         if (!sc->mfi_cmd_list[i]) {
404             for (j = 0; j < i; j++)
405                 kfree(sc->mfi_cmd_list[j],M_MRSAS);
406             kfree(sc->mfi_cmd_list, M_MRSAS);
407             sc->mfi_cmd_list = NULL;
408             return(ENOMEM);
409         }
410     }
411 
412     for (i = 0; i < max_cmd; i++) {
413         cmd = sc->mfi_cmd_list[i];
414         memset(cmd, 0, sizeof(struct mrsas_mfi_cmd));
415         cmd->index = i;
416         cmd->ccb_ptr = NULL;
417         cmd->sc = sc;
418         TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next);
419     }
420 
421     /* create a frame pool and assign one frame to each command */
422     if (mrsas_create_frame_pool(sc)) {
423         device_printf(sc->mrsas_dev, "Cannot allocate DMA frame pool.\n");
424         for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { // Free the frames
425             cmd = sc->mfi_cmd_list[i];
426             mrsas_free_frame(sc, cmd);
427         }
428         if (sc->mficmd_frame_tag != NULL)
429             bus_dma_tag_destroy(sc->mficmd_frame_tag);
430         return(ENOMEM);
431     }
432 
433     return(0);
434 }
435 
436 /**
437  * mrsas_create_frame_pool -   Creates DMA pool for cmd frames
438  * input:                      Adapter soft state
439  *
440  * Each command packet has an embedded DMA memory buffer that is used for
441  * filling MFI frame and the SG list that immediately follows the frame. This
442  * function creates those DMA memory buffers for each command packet by using
443  * PCI pool facility. pad_0 is initialized to 0 to prevent corrupting value
444  * of context and could cause FW crash.
445  */
446 static int mrsas_create_frame_pool(struct mrsas_softc *sc)
447 {
448     int i;
449     struct mrsas_mfi_cmd *cmd;
450 
451     if (bus_dma_tag_create( sc->mrsas_parent_tag,   // parent
452                             1, 0,                   // algnmnt, boundary
453                             BUS_SPACE_MAXADDR_32BIT,// lowaddr
454                             BUS_SPACE_MAXADDR,      // highaddr
455                             MRSAS_MFI_FRAME_SIZE,   // maxsize
456                             1,                      // msegments
457                             MRSAS_MFI_FRAME_SIZE,   // maxsegsize
458                             BUS_DMA_ALLOCNOW,       // flags
459                             &sc->mficmd_frame_tag)) {
460         device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n");
461         return (ENOMEM);
462     }
463 
464     for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
465         cmd = sc->mfi_cmd_list[i];
466         cmd->frame = mrsas_alloc_frame(sc, cmd);
467         if (cmd->frame == NULL) {
468             device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
469             return (ENOMEM);
470         }
471         memset(cmd->frame, 0, MRSAS_MFI_FRAME_SIZE);
472         cmd->frame->io.context = cmd->index;
473         cmd->frame->io.pad_0 = 0;
474     }
475 
476     return(0);
477 }
478 
479 /**
480  * mrsas_alloc_frame -   Allocates MFI Frames
481  * input:                Adapter soft state
482  *
483  * Create bus DMA memory tag and dmamap and load memory for MFI frames.
484  * Returns virtual memory pointer to allocated region.
485  */
486 void *mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
487 {
488     u_int32_t frame_size = MRSAS_MFI_FRAME_SIZE;
489 
490     if (bus_dmamem_alloc(sc->mficmd_frame_tag, (void **)&cmd->frame_mem,
491                     BUS_DMA_NOWAIT, &cmd->frame_dmamap)) {
492         device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
493         return (NULL);
494     }
495     if (bus_dmamap_load(sc->mficmd_frame_tag, cmd->frame_dmamap,
496                         cmd->frame_mem, frame_size, mrsas_alloc_cb,
497                         &cmd->frame_phys_addr, BUS_DMA_NOWAIT)) {
498         device_printf(sc->mrsas_dev, "Cannot load IO request memory\n");
499         return (NULL);
500     }
501 
502     return(cmd->frame_mem);
503 }
504 
505 /*
506  * mrsas_alloc_cb:  Callback function of bus_dmamap_load()
507  * input:           callback argument,
508  *                  machine dependent type that describes DMA segments,
509  *                  number of segments,
510  *                  error code.
511  *
512  * This function is for the driver to receive mapping information resultant
513  * of the bus_dmamap_load(). The information is actually not being used,
514  * but the address is saved anyway.
515  */
516 static void mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
517         int nsegs, int error)
518 {
519     bus_addr_t *addr;
520 
521     addr = arg;
522     *addr = segs[0].ds_addr;
523 }
524 
525 /**
526  * mrsas_free_frames:    Frees memory for  MFI frames
527  * input:                Adapter soft state
528  *
529  * Deallocates MFI frames memory.  Called from mrsas_free_mem() during
530  * detach and error case during creation of frame pool.
531  */
532 void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
533 {
534     if (cmd->frame_phys_addr)
535         bus_dmamap_unload(sc->mficmd_frame_tag, cmd->frame_dmamap);
536     if (cmd->frame_mem != NULL)
537         bus_dmamem_free(sc->mficmd_frame_tag, cmd->frame_mem, cmd->frame_dmamap);
538 }
539