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 #include <sys/abi_compat.h>
42 #include <dev/mrsas/mrsas.h>
43 #include <dev/mrsas/mrsas_ioctl.h>
44
45 struct mrsas_passthru_cmd {
46 struct mrsas_sge64 *kern_sge;
47 struct mrsas_softc *sc;
48 struct mrsas_mfi_cmd *cmd;
49 bus_dma_tag_t ioctl_data_tag;
50 bus_dmamap_t ioctl_data_dmamap;
51
52 u_int32_t error_code;
53 u_int32_t sge_count;
54 int complete;
55 };
56
57 /*
58 * Function prototypes
59 */
60 int mrsas_alloc_mfi_cmds(struct mrsas_softc *sc);
61 int mrsas_passthru(struct mrsas_softc *sc, void *arg, u_long ioctlCmd);
62 void mrsas_free_ioc_cmd(struct mrsas_softc *sc);
63 void mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
64 void *mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd);
65 static int mrsas_create_frame_pool(struct mrsas_softc *sc);
66 static void
67 mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
68 int nsegs, int error);
69
70 extern struct mrsas_mfi_cmd *mrsas_get_mfi_cmd(struct mrsas_softc *sc);
71 extern void mrsas_release_mfi_cmd(struct mrsas_mfi_cmd *cmd);
72 extern int
73 mrsas_issue_blocked_cmd(struct mrsas_softc *sc,
74 struct mrsas_mfi_cmd *cmd);
75
76 /*
77 * mrsas_data_load_cb: Callback entry point
78 * input: Pointer to command packet as argument
79 * Pointer to segment
80 * Number of segments Error
81 *
82 * This is the callback function of the bus dma map load. It builds the SG
83 * list.
84 */
85 static void
mrsas_passthru_load_cb(void * arg,bus_dma_segment_t * segs,int nseg,int error)86 mrsas_passthru_load_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
87 {
88 struct mrsas_passthru_cmd *cb = (struct mrsas_passthru_cmd *)arg;
89 struct mrsas_softc *sc = cb->sc;
90 int i = 0;
91
92 if (error) {
93 cb->error_code = error;
94 if (error == EFBIG) {
95 device_printf(sc->mrsas_dev, "mrsas_passthru_load_cb: "
96 "error=%d EFBIG\n", error);
97 cb->complete = 1;
98 return;
99 } else {
100 device_printf(sc->mrsas_dev, "mrsas_passthru_load_cb: "
101 "error=%d UNKNOWN\n", error);
102 }
103 }
104 if (nseg > MAX_IOCTL_SGE) {
105 cb->error_code = EFBIG;
106 device_printf(sc->mrsas_dev, "mrsas_passthru_load_cb: "
107 "too many segments: %d\n", nseg);
108 cb->complete = 1;
109 return;
110 }
111
112 for (i = 0; i < nseg; i++) {
113 cb->kern_sge[i].phys_addr = htole64(segs[i].ds_addr);
114 cb->kern_sge[i].length = htole32(segs[i].ds_len);
115 }
116 cb->sge_count = nseg;
117
118 bus_dmamap_sync(cb->ioctl_data_tag, cb->ioctl_data_dmamap,
119 BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
120
121 cb->complete = 1;
122 }
123
124 /*
125 * mrsas_passthru: Handle pass-through commands
126 * input: Adapter instance soft state argument pointer
127 *
128 * This function is called from mrsas_ioctl() to handle pass-through and ioctl
129 * commands to Firmware.
130 */
131 int
mrsas_passthru(struct mrsas_softc * sc,void * arg,u_long ioctlCmd)132 mrsas_passthru(struct mrsas_softc *sc, void *arg, u_long ioctlCmd)
133 {
134 struct mrsas_iocpacket *user_ioc = (struct mrsas_iocpacket *)arg;
135
136 #ifdef COMPAT_FREEBSD32
137 struct mrsas_iocpacket32 *user_ioc32 = (struct mrsas_iocpacket32 *)arg;
138
139 #endif
140 union mrsas_frame *in_cmd = (union mrsas_frame *)&(user_ioc->frame.raw);
141 struct mrsas_mfi_cmd *cmd = NULL;
142 bus_dma_tag_t ioctl_data_tag[MAX_IOCTL_SGE];
143 bus_dmamap_t ioctl_data_dmamap[MAX_IOCTL_SGE];
144 void *ioctl_data_mem[MAX_IOCTL_SGE];
145 bus_addr_t ioctl_data_phys_addr[MAX_IOCTL_SGE];
146 bus_dma_tag_t ioctl_sense_tag = 0;
147 bus_dmamap_t ioctl_sense_dmamap = 0;
148 void *ioctl_sense_mem = NULL;
149 bus_addr_t ioctl_sense_phys_addr = 0;
150 int i, ioctl_data_size = 0, ioctl_sense_size, ret = 0;
151 struct mrsas_sge32 *kern_sge32;
152 unsigned long *sense_ptr;
153 uint8_t *iov_base_ptrin = NULL;
154 size_t iov_len = 0;
155
156 /*
157 * Check for NOP from MegaCli... MegaCli can issue a DCMD of 0. In
158 * this case do nothing and return 0 to it as status.
159 */
160 if (in_cmd->dcmd.opcode == 0) {
161 device_printf(sc->mrsas_dev, "In %s() Got a NOP\n", __func__);
162 user_ioc->frame.hdr.cmd_status = MFI_STAT_OK;
163 return (0);
164 }
165 /* Validate SGL length */
166 if (user_ioc->sge_count > MAX_IOCTL_SGE) {
167 device_printf(sc->mrsas_dev, "In %s() SGL is too long (%d > 8).\n",
168 __func__, user_ioc->sge_count);
169 return (ENOENT);
170 }
171 /* Get a command */
172 cmd = mrsas_get_mfi_cmd(sc);
173 if (!cmd) {
174 device_printf(sc->mrsas_dev, "Failed to get a free cmd for IOCTL\n");
175 return (ENOMEM);
176 }
177 /*
178 * User's IOCTL packet has 2 frames (maximum). Copy those two frames
179 * into our cmd's frames. cmd->frame's context will get overwritten
180 * when we copy from user's frames. So set that value alone
181 * separately
182 */
183 memcpy(cmd->frame, user_ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
184 cmd->frame->hdr.context = cmd->index;
185 cmd->frame->hdr.pad_0 = 0;
186 cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 |
187 MFI_FRAME_SENSE64);
188
189 /*
190 * The management interface between applications and the fw uses MFI
191 * frames. E.g, RAID configuration changes, LD property changes etc
192 * are accomplishes through different kinds of MFI frames. The driver
193 * needs to care only about substituting user buffers with kernel
194 * buffers in SGLs. The location of SGL is embedded in the struct
195 * iocpacket itself.
196 */
197 kern_sge32 = (struct mrsas_sge32 *)
198 ((uintptr_t)cmd->frame + user_ioc->sgl_off);
199
200 memset(ioctl_data_tag, 0, (sizeof(bus_dma_tag_t) * MAX_IOCTL_SGE));
201 memset(ioctl_data_dmamap, 0, (sizeof(bus_dmamap_t) * MAX_IOCTL_SGE));
202 memset(ioctl_data_mem, 0, (sizeof(void *) * MAX_IOCTL_SGE));
203 memset(ioctl_data_phys_addr, 0, (sizeof(bus_addr_t) * MAX_IOCTL_SGE));
204
205 /*
206 * For each user buffer, create a mirror buffer and copy in
207 */
208 for (i = 0; i < user_ioc->sge_count; i++) {
209 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) {
210 if (!user_ioc->sgl[i].iov_len)
211 continue;
212 ioctl_data_size = user_ioc->sgl[i].iov_len;
213 #ifdef COMPAT_FREEBSD32
214 } else {
215 if (!user_ioc32->sgl[i].iov_len)
216 continue;
217 ioctl_data_size = user_ioc32->sgl[i].iov_len;
218 #endif
219 }
220 if (bus_dma_tag_create(sc->mrsas_parent_tag,
221 1, 0,
222 BUS_SPACE_MAXADDR_32BIT,
223 BUS_SPACE_MAXADDR,
224 NULL, NULL,
225 ioctl_data_size,
226 1,
227 ioctl_data_size,
228 BUS_DMA_ALLOCNOW,
229 NULL, NULL,
230 &ioctl_data_tag[i])) {
231 device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n");
232 ret = ENOMEM;
233 goto out;
234 }
235 if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i],
236 (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) {
237 device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n");
238 ret = ENOMEM;
239 goto out;
240 }
241 if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i],
242 ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb,
243 &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) {
244 device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n");
245 ret = ENOMEM;
246 goto out;
247 }
248 /* Save the physical address and length */
249 kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i];
250
251 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) {
252 kern_sge32[i].length = user_ioc->sgl[i].iov_len;
253
254 iov_base_ptrin = user_ioc->sgl[i].iov_base;
255 iov_len = user_ioc->sgl[i].iov_len;
256 #ifdef COMPAT_FREEBSD32
257 } else {
258 kern_sge32[i].length = user_ioc32->sgl[i].iov_len;
259
260 iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base);
261 iov_len = user_ioc32->sgl[i].iov_len;
262 #endif
263 }
264
265 /* Copy in data from user space */
266 ret = copyin(iov_base_ptrin, ioctl_data_mem[i], iov_len);
267 if (ret) {
268 device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n");
269 goto out;
270 }
271 }
272
273 ioctl_sense_size = user_ioc->sense_len;
274
275 if (user_ioc->sense_len) {
276 if (bus_dma_tag_create(sc->mrsas_parent_tag,
277 1, 0,
278 BUS_SPACE_MAXADDR_32BIT,
279 BUS_SPACE_MAXADDR,
280 NULL, NULL,
281 ioctl_sense_size,
282 1,
283 ioctl_sense_size,
284 BUS_DMA_ALLOCNOW,
285 NULL, NULL,
286 &ioctl_sense_tag)) {
287 device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense tag\n");
288 ret = ENOMEM;
289 goto out;
290 }
291 if (bus_dmamem_alloc(ioctl_sense_tag, (void **)&ioctl_sense_mem,
292 (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_sense_dmamap)) {
293 device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense mem\n");
294 ret = ENOMEM;
295 goto out;
296 }
297 if (bus_dmamap_load(ioctl_sense_tag, ioctl_sense_dmamap,
298 ioctl_sense_mem, ioctl_sense_size, mrsas_alloc_cb,
299 &ioctl_sense_phys_addr, BUS_DMA_NOWAIT)) {
300 device_printf(sc->mrsas_dev, "Cannot load ioctl sense mem\n");
301 ret = ENOMEM;
302 goto out;
303 }
304 sense_ptr =
305 (unsigned long *)((uintptr_t)cmd->frame + user_ioc->sense_off);
306 *sense_ptr = ioctl_sense_phys_addr;
307 }
308 /*
309 * Set the sync_cmd flag so that the ISR knows not to complete this
310 * cmd to the SCSI mid-layer
311 */
312 cmd->sync_cmd = 1;
313 ret = mrsas_issue_blocked_cmd(sc, cmd);
314 if (ret == ETIMEDOUT) {
315 mrsas_dprint(sc, MRSAS_OCR,
316 "IOCTL command is timed out, initiating OCR\n");
317 sc->do_timedout_reset = MFI_DCMD_TIMEOUT_OCR;
318 ret = EAGAIN;
319 goto out;
320 }
321 cmd->sync_cmd = 0;
322
323 /*
324 * copy out the kernel buffers to user buffers
325 */
326 for (i = 0; i < user_ioc->sge_count; i++) {
327 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) {
328 iov_base_ptrin = user_ioc->sgl[i].iov_base;
329 iov_len = user_ioc->sgl[i].iov_len;
330 #ifdef COMPAT_FREEBSD32
331 } else {
332 iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base);
333 iov_len = user_ioc32->sgl[i].iov_len;
334 #endif
335 }
336
337 ret = copyout(ioctl_data_mem[i], iov_base_ptrin, iov_len);
338 if (ret) {
339 device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n");
340 goto out;
341 }
342 }
343
344 /*
345 * copy out the sense
346 */
347 if (user_ioc->sense_len) {
348 /*
349 * sense_buff points to the location that has the user sense
350 * buffer address
351 */
352 sense_ptr = (unsigned long *)((uintptr_t)user_ioc->frame.raw +
353 user_ioc->sense_off);
354 ret = copyout(ioctl_sense_mem, (unsigned long *)(uintptr_t)*sense_ptr,
355 user_ioc->sense_len);
356 if (ret) {
357 device_printf(sc->mrsas_dev, "IOCTL sense copyout failed!\n");
358 goto out;
359 }
360 }
361 /*
362 * Return command status to user space
363 */
364 memcpy(&user_ioc->frame.hdr.cmd_status, &cmd->frame->hdr.cmd_status,
365 sizeof(u_int8_t));
366
367 out:
368 /*
369 * Release sense buffer
370 */
371 if (user_ioc->sense_len) {
372 if (ioctl_sense_phys_addr)
373 bus_dmamap_unload(ioctl_sense_tag, ioctl_sense_dmamap);
374 if (ioctl_sense_mem != NULL)
375 bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, ioctl_sense_dmamap);
376 if (ioctl_sense_tag != NULL)
377 bus_dma_tag_destroy(ioctl_sense_tag);
378 }
379 /*
380 * Release data buffers
381 */
382 for (i = 0; i < user_ioc->sge_count; i++) {
383 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) {
384 if (!user_ioc->sgl[i].iov_len)
385 continue;
386 #ifdef COMPAT_FREEBSD32
387 } else {
388 if (!user_ioc32->sgl[i].iov_len)
389 continue;
390 #endif
391 }
392 if (ioctl_data_phys_addr[i])
393 bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]);
394 if (ioctl_data_mem[i] != NULL)
395 bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i],
396 ioctl_data_dmamap[i]);
397 if (ioctl_data_tag[i] != NULL)
398 bus_dma_tag_destroy(ioctl_data_tag[i]);
399 }
400 /* Free command */
401 mrsas_release_mfi_cmd(cmd);
402
403 return (ret);
404 }
405
406 /**
407 * mrsas_user_command: Handle user mode DCMD and buffer
408 * input: Adapter instance soft state
409 * argument pointer
410 *
411 * This function is called from mrsas_ioctl() DCMDs to firmware for mfiutil
412 */
413 int
mrsas_user_command(struct mrsas_softc * sc,struct mfi_ioc_passthru * ioc)414 mrsas_user_command(struct mrsas_softc *sc, struct mfi_ioc_passthru *ioc)
415 {
416 struct mrsas_mfi_cmd *cmd;
417 struct mrsas_dcmd_frame *dcmd;
418 struct mrsas_passthru_cmd *passcmd;
419 bus_dma_tag_t ioctl_data_tag;
420 bus_dmamap_t ioctl_data_dmamap;
421 bus_addr_t ioctl_data_phys_addr;
422 struct mrsas_sge64 *kern_sge;
423 int ret, ioctl_data_size;
424 char *ioctl_temp_data_mem;
425
426 ret = 0;
427 ioctl_temp_data_mem = NULL;
428 passcmd = NULL;
429 ioctl_data_phys_addr = 0;
430 dcmd = NULL;
431 cmd = NULL;
432 ioctl_data_tag = NULL;
433 ioctl_data_dmamap = NULL;
434 ioctl_data_dmamap = NULL;
435
436 /* Get a command */
437 cmd = mrsas_get_mfi_cmd(sc);
438 if (!cmd) {
439 device_printf(sc->mrsas_dev,
440 "Failed to get a free cmd for IOCTL\n");
441 return(ENOMEM);
442 }
443
444 /*
445 * Frame is DCMD
446 */
447 dcmd = (struct mrsas_dcmd_frame *)cmd->frame;
448 memcpy(dcmd, &ioc->ioc_frame, sizeof(struct mrsas_dcmd_frame));
449
450 ioctl_data_size = ioc->buf_size;
451
452 cmd->frame->hdr.context = cmd->index;
453 cmd->frame->hdr.pad_0 = 0;
454 cmd->frame->hdr.flags = MFI_FRAME_DIR_BOTH;
455 if (sizeof(bus_addr_t) == 8)
456 cmd->frame->hdr.flags |= MFI_FRAME_SGL64 | MFI_FRAME_SENSE64;
457
458 kern_sge = (struct mrsas_sge64 *)(&dcmd->sgl);
459
460 if (ioctl_data_size == 0) {
461 kern_sge[0].phys_addr = 0;
462 kern_sge[0].length = 0;
463 } else {
464 ioctl_temp_data_mem = malloc(ioc->buf_size, M_MRSAS, M_WAITOK);
465
466 /* Copy in data from user space */
467 ret = copyin(ioc->buf, ioctl_temp_data_mem, ioc->buf_size);
468 if (ret) {
469 device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n");
470 goto out;
471 }
472
473 /*
474 * Allocate a temporary struct to hold parameters for the
475 * callback
476 */
477 passcmd = malloc(sizeof(struct mrsas_passthru_cmd), M_MRSAS,
478 M_WAITOK);
479 passcmd->complete = 0;
480 passcmd->sc = sc;
481 passcmd->cmd = cmd;
482 passcmd->kern_sge = kern_sge;
483
484 /*
485 * Create a dma tag for passthru buffers
486 */
487 if (bus_dma_tag_create(sc->mrsas_parent_tag, /* parent */
488 1, 0, /* algnmnt, boundary */
489 BUS_SPACE_MAXADDR, /* lowaddr */
490 BUS_SPACE_MAXADDR, /* highaddr */
491 NULL, NULL, /* filter, filterarg */
492 ioctl_data_size, /* maxsize */
493 MAX_IOCTL_SGE, /* msegments */
494 ioctl_data_size, /* maxsegsize */
495 BUS_DMA_ALLOCNOW, /* flags */
496 busdma_lock_mutex, /* lockfunc */
497 &sc->ioctl_lock, /* lockarg */
498 &ioctl_data_tag)) {
499 device_printf(sc->mrsas_dev,
500 "Cannot allocate ioctl data tag %d\n",
501 ioc->buf_size);
502 ret = ENOMEM;
503 goto out;
504 }
505
506 /* Create memmap */
507 if (bus_dmamap_create(ioctl_data_tag, 0, &ioctl_data_dmamap)) {
508 device_printf(sc->mrsas_dev, "Cannot create ioctl "
509 "passthru dmamap\n");
510 ret = ENOMEM;
511 goto out;
512 }
513
514 passcmd->ioctl_data_tag = ioctl_data_tag;
515 passcmd->ioctl_data_dmamap = ioctl_data_dmamap;
516
517 /* Map data buffer into bus space */
518 if (bus_dmamap_load(ioctl_data_tag, ioctl_data_dmamap,
519 ioctl_temp_data_mem, ioc->buf_size, mrsas_passthru_load_cb,
520 passcmd, BUS_DMA_NOWAIT)) {
521 device_printf(sc->mrsas_dev, "Cannot load ioctl "
522 "passthru data mem%s %d\n", curproc->p_comm, ioctl_data_size);
523 ret = ENOMEM;
524 goto out;
525 }
526
527 while (passcmd->complete == 0) {
528 pause("mrsas_passthru", hz);
529 }
530
531 cmd->frame->dcmd.sge_count = passcmd->sge_count;
532 }
533
534 /*
535 * Set the sync_cmd flag so that the ISR knows not to complete this
536 * cmd to the SCSI mid-layer
537 */
538 cmd->sync_cmd = 1;
539 mrsas_issue_blocked_cmd(sc, cmd);
540 cmd->sync_cmd = 0;
541
542 if (ioctl_data_size != 0) {
543 bus_dmamap_sync(ioctl_data_tag, ioctl_data_dmamap,
544 BUS_DMASYNC_POSTREAD);
545 /*
546 * copy out the kernel buffers to user buffers
547 */
548 ret = copyout(ioctl_temp_data_mem, ioc->buf, ioc->buf_size);
549 if (ret) {
550 device_printf(sc->mrsas_dev,
551 "IOCTL copyout failed!\n");
552 goto out;
553 }
554 }
555
556 /*
557 * Return command status to user space
558 */
559 memcpy(&ioc->ioc_frame.cmd_status, &cmd->frame->hdr.cmd_status,
560 sizeof(u_int8_t));
561
562 out:
563 /*
564 * Release temporary passthrough ioctl
565 */
566 if (ioctl_temp_data_mem)
567 free(ioctl_temp_data_mem, M_MRSAS);
568 if (passcmd)
569 free(passcmd, M_MRSAS);
570
571 /*
572 * Release data buffers
573 */
574 if (ioctl_data_phys_addr) {
575 bus_dmamap_unload(ioctl_data_tag, ioctl_data_dmamap);
576 bus_dmamap_destroy(ioctl_data_tag, ioctl_data_dmamap);
577 }
578 if (ioctl_data_tag != NULL)
579 bus_dma_tag_destroy(ioctl_data_tag);
580 /* Free command */
581 mrsas_release_mfi_cmd(cmd);
582
583 return(ret);
584 }
585
586
587 /*
588 * mrsas_alloc_mfi_cmds: Allocates the command packets
589 * input: Adapter instance soft state
590 *
591 * Each IOCTL or passthru command that is issued to the FW are wrapped in a
592 * local data structure called mrsas_mfi_cmd. The frame embedded in this
593 * mrsas_mfi is issued to FW. The array is used only to look up the
594 * mrsas_mfi_cmd given the context. The free commands are maintained in a
595 * linked list.
596 */
597 int
mrsas_alloc_mfi_cmds(struct mrsas_softc * sc)598 mrsas_alloc_mfi_cmds(struct mrsas_softc *sc)
599 {
600 int i, j;
601 u_int32_t max_cmd;
602 struct mrsas_mfi_cmd *cmd;
603
604 max_cmd = MRSAS_MAX_MFI_CMDS;
605
606 /*
607 * sc->mfi_cmd_list is an array of struct mrsas_mfi_cmd pointers.
608 * Allocate the dynamic array first and then allocate individual
609 * commands.
610 */
611 sc->mfi_cmd_list = malloc(sizeof(struct mrsas_mfi_cmd *) * max_cmd, M_MRSAS, M_NOWAIT);
612 if (!sc->mfi_cmd_list) {
613 device_printf(sc->mrsas_dev, "Cannot alloc memory for mfi_cmd cmd_list.\n");
614 return (ENOMEM);
615 }
616 memset(sc->mfi_cmd_list, 0, sizeof(struct mrsas_mfi_cmd *) * max_cmd);
617 for (i = 0; i < max_cmd; i++) {
618 sc->mfi_cmd_list[i] = malloc(sizeof(struct mrsas_mfi_cmd),
619 M_MRSAS, M_NOWAIT);
620 if (!sc->mfi_cmd_list[i]) {
621 for (j = 0; j < i; j++)
622 free(sc->mfi_cmd_list[j], M_MRSAS);
623 free(sc->mfi_cmd_list, M_MRSAS);
624 sc->mfi_cmd_list = NULL;
625 return (ENOMEM);
626 }
627 }
628
629 for (i = 0; i < max_cmd; i++) {
630 cmd = sc->mfi_cmd_list[i];
631 memset(cmd, 0, sizeof(struct mrsas_mfi_cmd));
632 cmd->index = i;
633 cmd->ccb_ptr = NULL;
634 cmd->sc = sc;
635 TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next);
636 }
637
638 /* create a frame pool and assign one frame to each command */
639 if (mrsas_create_frame_pool(sc)) {
640 device_printf(sc->mrsas_dev, "Cannot allocate DMA frame pool.\n");
641 /* Free the frames */
642 for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
643 cmd = sc->mfi_cmd_list[i];
644 mrsas_free_frame(sc, cmd);
645 }
646 if (sc->mficmd_frame_tag != NULL)
647 bus_dma_tag_destroy(sc->mficmd_frame_tag);
648 return (ENOMEM);
649 }
650 return (0);
651 }
652
653 /*
654 * mrsas_create_frame_pool: Creates DMA pool for cmd frames
655 * input: Adapter soft state
656 *
657 * Each command packet has an embedded DMA memory buffer that is used for
658 * filling MFI frame and the SG list that immediately follows the frame. This
659 * function creates those DMA memory buffers for each command packet by using
660 * PCI pool facility. pad_0 is initialized to 0 to prevent corrupting value
661 * of context and could cause FW crash.
662 */
663 static int
mrsas_create_frame_pool(struct mrsas_softc * sc)664 mrsas_create_frame_pool(struct mrsas_softc *sc)
665 {
666 int i;
667 struct mrsas_mfi_cmd *cmd;
668
669 if (bus_dma_tag_create(sc->mrsas_parent_tag,
670 1, 0,
671 BUS_SPACE_MAXADDR_32BIT,
672 BUS_SPACE_MAXADDR,
673 NULL, NULL,
674 MRSAS_MFI_FRAME_SIZE,
675 1,
676 MRSAS_MFI_FRAME_SIZE,
677 BUS_DMA_ALLOCNOW,
678 NULL, NULL,
679 &sc->mficmd_frame_tag)) {
680 device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n");
681 return (ENOMEM);
682 }
683 for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
684 cmd = sc->mfi_cmd_list[i];
685 cmd->frame = mrsas_alloc_frame(sc, cmd);
686 if (cmd->frame == NULL) {
687 device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
688 return (ENOMEM);
689 }
690 /*
691 * For MFI controllers.
692 * max_num_sge = 60
693 * max_sge_sz = 16 byte (sizeof megasas_sge_skinny)
694 * Totl 960 byte (15 MFI frame of 64 byte)
695 *
696 * Fusion adapter require only 3 extra frame.
697 * max_num_sge = 16 (defined as MAX_IOCTL_SGE)
698 * max_sge_sz = 12 byte (sizeof megasas_sge64)
699 * Total 192 byte (3 MFI frame of 64 byte)
700 */
701 memset(cmd->frame, 0, MRSAS_MFI_FRAME_SIZE);
702 cmd->frame->io.context = cmd->index;
703 cmd->frame->io.pad_0 = 0;
704 }
705
706 return (0);
707 }
708
709 /*
710 * mrsas_alloc_frame: Allocates MFI Frames
711 * input: Adapter soft state
712 *
713 * Create bus DMA memory tag and dmamap and load memory for MFI frames. Returns
714 * virtual memory pointer to allocated region.
715 */
716 void *
mrsas_alloc_frame(struct mrsas_softc * sc,struct mrsas_mfi_cmd * cmd)717 mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
718 {
719 u_int32_t frame_size = MRSAS_MFI_FRAME_SIZE;
720
721 if (bus_dmamem_alloc(sc->mficmd_frame_tag, (void **)&cmd->frame_mem,
722 BUS_DMA_NOWAIT, &cmd->frame_dmamap)) {
723 device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
724 return (NULL);
725 }
726 if (bus_dmamap_load(sc->mficmd_frame_tag, cmd->frame_dmamap,
727 cmd->frame_mem, frame_size, mrsas_alloc_cb,
728 &cmd->frame_phys_addr, BUS_DMA_NOWAIT)) {
729 device_printf(sc->mrsas_dev, "Cannot load IO request memory\n");
730 return (NULL);
731 }
732 return (cmd->frame_mem);
733 }
734
735 /*
736 * mrsas_alloc_cb: Callback function of bus_dmamap_load()
737 * input: callback argument,
738 * machine dependent type that describes DMA segments,
739 * number of segments,
740 * error code.
741 *
742 * This function is for the driver to receive mapping information resultant of
743 * the bus_dmamap_load(). The information is actually not being used, but the
744 * address is saved anyway.
745 */
746 static void
mrsas_alloc_cb(void * arg,bus_dma_segment_t * segs,int nsegs,int error)747 mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
748 int nsegs, int error)
749 {
750 bus_addr_t *addr;
751
752 addr = arg;
753 *addr = segs[0].ds_addr;
754 }
755
756 /*
757 * mrsas_free_frames: Frees memory for MFI frames
758 * input: Adapter soft state
759 *
760 * Deallocates MFI frames memory. Called from mrsas_free_mem() during detach
761 * and error case during creation of frame pool.
762 */
763 void
mrsas_free_frame(struct mrsas_softc * sc,struct mrsas_mfi_cmd * cmd)764 mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
765 {
766 if (cmd->frame_phys_addr)
767 bus_dmamap_unload(sc->mficmd_frame_tag, cmd->frame_dmamap);
768 if (cmd->frame_mem != NULL)
769 bus_dmamem_free(sc->mficmd_frame_tag, cmd->frame_mem, cmd->frame_dmamap);
770 }
771