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