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 } 506