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 if (ioctl_temp_data_mem == NULL) {
466 device_printf(sc->mrsas_dev, "Could not allocate "
467 "%d memory for temporary passthrough ioctl\n",
468 ioc->buf_size);
469 ret = ENOMEM;
470 goto out;
471 }
472
473 /* Copy in data from user space */
474 ret = copyin(ioc->buf, ioctl_temp_data_mem, ioc->buf_size);
475 if (ret) {
476 device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n");
477 goto out;
478 }
479
480 /*
481 * Allocate a temporary struct to hold parameters for the
482 * callback
483 */
484 passcmd = malloc(sizeof(struct mrsas_passthru_cmd), M_MRSAS,
485 M_WAITOK);
486 if (passcmd == NULL) {
487 device_printf(sc->mrsas_dev, "Could not allocate "
488 "memory for temporary passthrough cb struct\n");
489 ret = ENOMEM;
490 goto out;
491 }
492 passcmd->complete = 0;
493 passcmd->sc = sc;
494 passcmd->cmd = cmd;
495 passcmd->kern_sge = kern_sge;
496
497 /*
498 * Create a dma tag for passthru buffers
499 */
500 if (bus_dma_tag_create(sc->mrsas_parent_tag, /* parent */
501 1, 0, /* algnmnt, boundary */
502 BUS_SPACE_MAXADDR, /* lowaddr */
503 BUS_SPACE_MAXADDR, /* highaddr */
504 NULL, NULL, /* filter, filterarg */
505 ioctl_data_size, /* maxsize */
506 MAX_IOCTL_SGE, /* msegments */
507 ioctl_data_size, /* maxsegsize */
508 BUS_DMA_ALLOCNOW, /* flags */
509 busdma_lock_mutex, /* lockfunc */
510 &sc->ioctl_lock, /* lockarg */
511 &ioctl_data_tag)) {
512 device_printf(sc->mrsas_dev,
513 "Cannot allocate ioctl data tag %d\n",
514 ioc->buf_size);
515 ret = ENOMEM;
516 goto out;
517 }
518
519 /* Create memmap */
520 if (bus_dmamap_create(ioctl_data_tag, 0, &ioctl_data_dmamap)) {
521 device_printf(sc->mrsas_dev, "Cannot create ioctl "
522 "passthru dmamap\n");
523 ret = ENOMEM;
524 goto out;
525 }
526
527 passcmd->ioctl_data_tag = ioctl_data_tag;
528 passcmd->ioctl_data_dmamap = ioctl_data_dmamap;
529
530 /* Map data buffer into bus space */
531 if (bus_dmamap_load(ioctl_data_tag, ioctl_data_dmamap,
532 ioctl_temp_data_mem, ioc->buf_size, mrsas_passthru_load_cb,
533 passcmd, BUS_DMA_NOWAIT)) {
534 device_printf(sc->mrsas_dev, "Cannot load ioctl "
535 "passthru data mem%s %d\n", curproc->p_comm, ioctl_data_size);
536 ret = ENOMEM;
537 goto out;
538 }
539
540 while (passcmd->complete == 0) {
541 pause("mrsas_passthru", hz);
542 }
543
544 cmd->frame->dcmd.sge_count = passcmd->sge_count;
545 }
546
547 /*
548 * Set the sync_cmd flag so that the ISR knows not to complete this
549 * cmd to the SCSI mid-layer
550 */
551 cmd->sync_cmd = 1;
552 mrsas_issue_blocked_cmd(sc, cmd);
553 cmd->sync_cmd = 0;
554
555 if (ioctl_data_size != 0) {
556 bus_dmamap_sync(ioctl_data_tag, ioctl_data_dmamap,
557 BUS_DMASYNC_POSTREAD);
558 /*
559 * copy out the kernel buffers to user buffers
560 */
561 ret = copyout(ioctl_temp_data_mem, ioc->buf, ioc->buf_size);
562 if (ret) {
563 device_printf(sc->mrsas_dev,
564 "IOCTL copyout failed!\n");
565 goto out;
566 }
567 }
568
569 /*
570 * Return command status to user space
571 */
572 memcpy(&ioc->ioc_frame.cmd_status, &cmd->frame->hdr.cmd_status,
573 sizeof(u_int8_t));
574
575 out:
576 /*
577 * Release temporary passthrough ioctl
578 */
579 if (ioctl_temp_data_mem)
580 free(ioctl_temp_data_mem, M_MRSAS);
581 if (passcmd)
582 free(passcmd, M_MRSAS);
583
584 /*
585 * Release data buffers
586 */
587 if (ioctl_data_phys_addr) {
588 bus_dmamap_unload(ioctl_data_tag, ioctl_data_dmamap);
589 bus_dmamap_destroy(ioctl_data_tag, ioctl_data_dmamap);
590 }
591 if (ioctl_data_tag != NULL)
592 bus_dma_tag_destroy(ioctl_data_tag);
593 /* Free command */
594 mrsas_release_mfi_cmd(cmd);
595
596 return(ret);
597 }
598
599
600 /*
601 * mrsas_alloc_mfi_cmds: Allocates the command packets
602 * input: Adapter instance soft state
603 *
604 * Each IOCTL or passthru command that is issued to the FW are wrapped in a
605 * local data structure called mrsas_mfi_cmd. The frame embedded in this
606 * mrsas_mfi is issued to FW. The array is used only to look up the
607 * mrsas_mfi_cmd given the context. The free commands are maintained in a
608 * linked list.
609 */
610 int
mrsas_alloc_mfi_cmds(struct mrsas_softc * sc)611 mrsas_alloc_mfi_cmds(struct mrsas_softc *sc)
612 {
613 int i, j;
614 u_int32_t max_cmd;
615 struct mrsas_mfi_cmd *cmd;
616
617 max_cmd = MRSAS_MAX_MFI_CMDS;
618
619 /*
620 * sc->mfi_cmd_list is an array of struct mrsas_mfi_cmd pointers.
621 * Allocate the dynamic array first and then allocate individual
622 * commands.
623 */
624 sc->mfi_cmd_list = malloc(sizeof(struct mrsas_mfi_cmd *) * max_cmd, M_MRSAS, M_NOWAIT);
625 if (!sc->mfi_cmd_list) {
626 device_printf(sc->mrsas_dev, "Cannot alloc memory for mfi_cmd cmd_list.\n");
627 return (ENOMEM);
628 }
629 memset(sc->mfi_cmd_list, 0, sizeof(struct mrsas_mfi_cmd *) * max_cmd);
630 for (i = 0; i < max_cmd; i++) {
631 sc->mfi_cmd_list[i] = malloc(sizeof(struct mrsas_mfi_cmd),
632 M_MRSAS, M_NOWAIT);
633 if (!sc->mfi_cmd_list[i]) {
634 for (j = 0; j < i; j++)
635 free(sc->mfi_cmd_list[j], M_MRSAS);
636 free(sc->mfi_cmd_list, M_MRSAS);
637 sc->mfi_cmd_list = NULL;
638 return (ENOMEM);
639 }
640 }
641
642 for (i = 0; i < max_cmd; i++) {
643 cmd = sc->mfi_cmd_list[i];
644 memset(cmd, 0, sizeof(struct mrsas_mfi_cmd));
645 cmd->index = i;
646 cmd->ccb_ptr = NULL;
647 cmd->sc = sc;
648 TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next);
649 }
650
651 /* create a frame pool and assign one frame to each command */
652 if (mrsas_create_frame_pool(sc)) {
653 device_printf(sc->mrsas_dev, "Cannot allocate DMA frame pool.\n");
654 /* Free the frames */
655 for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
656 cmd = sc->mfi_cmd_list[i];
657 mrsas_free_frame(sc, cmd);
658 }
659 if (sc->mficmd_frame_tag != NULL)
660 bus_dma_tag_destroy(sc->mficmd_frame_tag);
661 return (ENOMEM);
662 }
663 return (0);
664 }
665
666 /*
667 * mrsas_create_frame_pool: Creates DMA pool for cmd frames
668 * input: Adapter soft state
669 *
670 * Each command packet has an embedded DMA memory buffer that is used for
671 * filling MFI frame and the SG list that immediately follows the frame. This
672 * function creates those DMA memory buffers for each command packet by using
673 * PCI pool facility. pad_0 is initialized to 0 to prevent corrupting value
674 * of context and could cause FW crash.
675 */
676 static int
mrsas_create_frame_pool(struct mrsas_softc * sc)677 mrsas_create_frame_pool(struct mrsas_softc *sc)
678 {
679 int i;
680 struct mrsas_mfi_cmd *cmd;
681
682 if (bus_dma_tag_create(sc->mrsas_parent_tag,
683 1, 0,
684 BUS_SPACE_MAXADDR_32BIT,
685 BUS_SPACE_MAXADDR,
686 NULL, NULL,
687 MRSAS_MFI_FRAME_SIZE,
688 1,
689 MRSAS_MFI_FRAME_SIZE,
690 BUS_DMA_ALLOCNOW,
691 NULL, NULL,
692 &sc->mficmd_frame_tag)) {
693 device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n");
694 return (ENOMEM);
695 }
696 for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) {
697 cmd = sc->mfi_cmd_list[i];
698 cmd->frame = mrsas_alloc_frame(sc, cmd);
699 if (cmd->frame == NULL) {
700 device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
701 return (ENOMEM);
702 }
703 /*
704 * For MFI controllers.
705 * max_num_sge = 60
706 * max_sge_sz = 16 byte (sizeof megasas_sge_skinny)
707 * Totl 960 byte (15 MFI frame of 64 byte)
708 *
709 * Fusion adapter require only 3 extra frame.
710 * max_num_sge = 16 (defined as MAX_IOCTL_SGE)
711 * max_sge_sz = 12 byte (sizeof megasas_sge64)
712 * Total 192 byte (3 MFI frame of 64 byte)
713 */
714 memset(cmd->frame, 0, MRSAS_MFI_FRAME_SIZE);
715 cmd->frame->io.context = cmd->index;
716 cmd->frame->io.pad_0 = 0;
717 }
718
719 return (0);
720 }
721
722 /*
723 * mrsas_alloc_frame: Allocates MFI Frames
724 * input: Adapter soft state
725 *
726 * Create bus DMA memory tag and dmamap and load memory for MFI frames. Returns
727 * virtual memory pointer to allocated region.
728 */
729 void *
mrsas_alloc_frame(struct mrsas_softc * sc,struct mrsas_mfi_cmd * cmd)730 mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
731 {
732 u_int32_t frame_size = MRSAS_MFI_FRAME_SIZE;
733
734 if (bus_dmamem_alloc(sc->mficmd_frame_tag, (void **)&cmd->frame_mem,
735 BUS_DMA_NOWAIT, &cmd->frame_dmamap)) {
736 device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n");
737 return (NULL);
738 }
739 if (bus_dmamap_load(sc->mficmd_frame_tag, cmd->frame_dmamap,
740 cmd->frame_mem, frame_size, mrsas_alloc_cb,
741 &cmd->frame_phys_addr, BUS_DMA_NOWAIT)) {
742 device_printf(sc->mrsas_dev, "Cannot load IO request memory\n");
743 return (NULL);
744 }
745 return (cmd->frame_mem);
746 }
747
748 /*
749 * mrsas_alloc_cb: Callback function of bus_dmamap_load()
750 * input: callback argument,
751 * machine dependent type that describes DMA segments,
752 * number of segments,
753 * error code.
754 *
755 * This function is for the driver to receive mapping information resultant of
756 * the bus_dmamap_load(). The information is actually not being used, but the
757 * address is saved anyway.
758 */
759 static void
mrsas_alloc_cb(void * arg,bus_dma_segment_t * segs,int nsegs,int error)760 mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs,
761 int nsegs, int error)
762 {
763 bus_addr_t *addr;
764
765 addr = arg;
766 *addr = segs[0].ds_addr;
767 }
768
769 /*
770 * mrsas_free_frames: Frees memory for MFI frames
771 * input: Adapter soft state
772 *
773 * Deallocates MFI frames memory. Called from mrsas_free_mem() during detach
774 * and error case during creation of frame pool.
775 */
776 void
mrsas_free_frame(struct mrsas_softc * sc,struct mrsas_mfi_cmd * cmd)777 mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd)
778 {
779 if (cmd->frame_phys_addr)
780 bus_dmamap_unload(sc->mficmd_frame_tag, cmd->frame_dmamap);
781 if (cmd->frame_mem != NULL)
782 bus_dmamem_free(sc->mficmd_frame_tag, cmd->frame_mem, cmd->frame_dmamap);
783 }
784