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