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