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 */
mrsas_dump_dcmd(struct mrsas_softc * sc,struct mrsas_dcmd_frame * dcmd)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 */
mrsas_dump_ioctl(struct mrsas_softc * sc,struct mrsas_iocpacket * user_ioc)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 */
mrsas_passthru(struct mrsas_softc * sc,void * arg)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 */
mrsas_alloc_mfi_cmds(struct mrsas_softc * sc)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 */
mrsas_create_frame_pool(struct mrsas_softc * sc)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 */
mrsas_alloc_frame(struct mrsas_softc * sc,struct mrsas_mfi_cmd * cmd)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 */
mrsas_alloc_cb(void * arg,bus_dma_segment_t * segs,int nsegs,int error)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 */
mrsas_free_frame(struct mrsas_softc * sc,struct mrsas_mfi_cmd * cmd)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