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