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 = 0; 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 ((unsigned long)cmd->frame + user_ioc->sgl_off); 140 141 /* 142 * For each user buffer, create a mirror buffer and copy in 143 */ 144 for (i = 0; i < user_ioc->sge_count; i++) { 145 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 146 if (!user_ioc->sgl[i].iov_len) 147 continue; 148 ioctl_data_size = user_ioc->sgl[i].iov_len; 149 #ifdef COMPAT_FREEBSD32 150 } else { 151 if (!user_ioc32->sgl[i].iov_len) 152 continue; 153 ioctl_data_size = user_ioc32->sgl[i].iov_len; 154 #endif 155 } 156 if (bus_dma_tag_create(sc->mrsas_parent_tag, 157 1, 0, 158 BUS_SPACE_MAXADDR_32BIT, 159 BUS_SPACE_MAXADDR, 160 NULL, NULL, 161 ioctl_data_size, 162 1, 163 ioctl_data_size, 164 BUS_DMA_ALLOCNOW, 165 NULL, NULL, 166 &ioctl_data_tag[i])) { 167 device_printf(sc->mrsas_dev, "Cannot allocate ioctl data tag\n"); 168 ret = ENOMEM; 169 goto out; 170 } 171 if (bus_dmamem_alloc(ioctl_data_tag[i], (void **)&ioctl_data_mem[i], 172 (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_data_dmamap[i])) { 173 device_printf(sc->mrsas_dev, "Cannot allocate ioctl data mem\n"); 174 ret = ENOMEM; 175 goto out; 176 } 177 if (bus_dmamap_load(ioctl_data_tag[i], ioctl_data_dmamap[i], 178 ioctl_data_mem[i], ioctl_data_size, mrsas_alloc_cb, 179 &ioctl_data_phys_addr[i], BUS_DMA_NOWAIT)) { 180 device_printf(sc->mrsas_dev, "Cannot load ioctl data mem\n"); 181 ret = ENOMEM; 182 goto out; 183 } 184 /* Save the physical address and length */ 185 kern_sge32[i].phys_addr = (u_int32_t)ioctl_data_phys_addr[i]; 186 187 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 188 kern_sge32[i].length = user_ioc->sgl[i].iov_len; 189 190 iov_base_ptrin = user_ioc->sgl[i].iov_base; 191 iov_len = user_ioc->sgl[i].iov_len; 192 #ifdef COMPAT_FREEBSD32 193 } else { 194 kern_sge32[i].length = user_ioc32->sgl[i].iov_len; 195 196 iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base); 197 iov_len = user_ioc32->sgl[i].iov_len; 198 #endif 199 } 200 201 /* Copy in data from user space */ 202 ret = copyin(iov_base_ptrin, ioctl_data_mem[i], iov_len); 203 if (ret) { 204 device_printf(sc->mrsas_dev, "IOCTL copyin failed!\n"); 205 goto out; 206 } 207 } 208 209 ioctl_sense_size = user_ioc->sense_len; 210 211 if (user_ioc->sense_len) { 212 if (bus_dma_tag_create(sc->mrsas_parent_tag, 213 1, 0, 214 BUS_SPACE_MAXADDR_32BIT, 215 BUS_SPACE_MAXADDR, 216 NULL, NULL, 217 ioctl_sense_size, 218 1, 219 ioctl_sense_size, 220 BUS_DMA_ALLOCNOW, 221 NULL, NULL, 222 &ioctl_sense_tag)) { 223 device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense tag\n"); 224 ret = ENOMEM; 225 goto out; 226 } 227 if (bus_dmamem_alloc(ioctl_sense_tag, (void **)&ioctl_sense_mem, 228 (BUS_DMA_NOWAIT | BUS_DMA_ZERO), &ioctl_sense_dmamap)) { 229 device_printf(sc->mrsas_dev, "Cannot allocate ioctl sense mem\n"); 230 ret = ENOMEM; 231 goto out; 232 } 233 if (bus_dmamap_load(ioctl_sense_tag, ioctl_sense_dmamap, 234 ioctl_sense_mem, ioctl_sense_size, mrsas_alloc_cb, 235 &ioctl_sense_phys_addr, BUS_DMA_NOWAIT)) { 236 device_printf(sc->mrsas_dev, "Cannot load ioctl sense mem\n"); 237 ret = ENOMEM; 238 goto out; 239 } 240 sense_ptr = 241 (unsigned long *)((unsigned long)cmd->frame + user_ioc->sense_off); 242 *sense_ptr = ioctl_sense_phys_addr; 243 } 244 /* 245 * Set the sync_cmd flag so that the ISR knows not to complete this 246 * cmd to the SCSI mid-layer 247 */ 248 cmd->sync_cmd = 1; 249 mrsas_issue_blocked_cmd(sc, cmd); 250 cmd->sync_cmd = 0; 251 252 /* 253 * copy out the kernel buffers to user buffers 254 */ 255 for (i = 0; i < user_ioc->sge_count; i++) { 256 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 257 iov_base_ptrin = user_ioc->sgl[i].iov_base; 258 iov_len = user_ioc->sgl[i].iov_len; 259 #ifdef COMPAT_FREEBSD32 260 } else { 261 iov_base_ptrin = PTRIN(user_ioc32->sgl[i].iov_base); 262 iov_len = user_ioc32->sgl[i].iov_len; 263 #endif 264 } 265 266 ret = copyout(ioctl_data_mem[i], iov_base_ptrin, iov_len); 267 if (ret) { 268 device_printf(sc->mrsas_dev, "IOCTL copyout failed!\n"); 269 goto out; 270 } 271 } 272 273 /* 274 * copy out the sense 275 */ 276 if (user_ioc->sense_len) { 277 /* 278 * sense_buff points to the location that has the user sense 279 * buffer address 280 */ 281 sense_ptr = (unsigned long *)((unsigned long)user_ioc->frame.raw + 282 user_ioc->sense_off); 283 ret = copyout(ioctl_sense_mem, (unsigned long *)*sense_ptr, 284 user_ioc->sense_len); 285 if (ret) { 286 device_printf(sc->mrsas_dev, "IOCTL sense copyout failed!\n"); 287 goto out; 288 } 289 } 290 /* 291 * Return command status to user space 292 */ 293 memcpy(&user_ioc->frame.hdr.cmd_status, &cmd->frame->hdr.cmd_status, 294 sizeof(u_int8_t)); 295 296 out: 297 /* 298 * Release sense buffer 299 */ 300 if (user_ioc->sense_len) { 301 if (ioctl_sense_phys_addr) 302 bus_dmamap_unload(ioctl_sense_tag, ioctl_sense_dmamap); 303 if (ioctl_sense_mem != NULL) 304 bus_dmamem_free(ioctl_sense_tag, ioctl_sense_mem, ioctl_sense_dmamap); 305 if (ioctl_sense_tag != NULL) 306 bus_dma_tag_destroy(ioctl_sense_tag); 307 } 308 /* 309 * Release data buffers 310 */ 311 for (i = 0; i < user_ioc->sge_count; i++) { 312 if (ioctlCmd == MRSAS_IOC_FIRMWARE_PASS_THROUGH64) { 313 if (!user_ioc->sgl[i].iov_len) 314 continue; 315 #ifdef COMPAT_FREEBSD32 316 } else { 317 if (!user_ioc32->sgl[i].iov_len) 318 continue; 319 #endif 320 } 321 if (ioctl_data_phys_addr[i]) 322 bus_dmamap_unload(ioctl_data_tag[i], ioctl_data_dmamap[i]); 323 if (ioctl_data_mem[i] != NULL) 324 bus_dmamem_free(ioctl_data_tag[i], ioctl_data_mem[i], 325 ioctl_data_dmamap[i]); 326 if (ioctl_data_tag[i] != NULL) 327 bus_dma_tag_destroy(ioctl_data_tag[i]); 328 } 329 /* Free command */ 330 mrsas_release_mfi_cmd(cmd); 331 332 return (ret); 333 } 334 335 /* 336 * mrsas_alloc_mfi_cmds: Allocates the command packets 337 * input: Adapter instance soft state 338 * 339 * Each IOCTL or passthru command that is issued to the FW are wrapped in a 340 * local data structure called mrsas_mfi_cmd. The frame embedded in this 341 * mrsas_mfi is issued to FW. The array is used only to look up the 342 * mrsas_mfi_cmd given the context. The free commands are maintained in a 343 * linked list. 344 */ 345 int 346 mrsas_alloc_mfi_cmds(struct mrsas_softc *sc) 347 { 348 int i, j; 349 u_int32_t max_cmd; 350 struct mrsas_mfi_cmd *cmd; 351 352 max_cmd = MRSAS_MAX_MFI_CMDS; 353 354 /* 355 * sc->mfi_cmd_list is an array of struct mrsas_mfi_cmd pointers. 356 * Allocate the dynamic array first and then allocate individual 357 * commands. 358 */ 359 sc->mfi_cmd_list = malloc(sizeof(struct mrsas_mfi_cmd *) * max_cmd, M_MRSAS, M_NOWAIT); 360 if (!sc->mfi_cmd_list) { 361 device_printf(sc->mrsas_dev, "Cannot alloc memory for mfi_cmd cmd_list.\n"); 362 return (ENOMEM); 363 } 364 memset(sc->mfi_cmd_list, 0, sizeof(struct mrsas_mfi_cmd *) * max_cmd); 365 for (i = 0; i < max_cmd; i++) { 366 sc->mfi_cmd_list[i] = malloc(sizeof(struct mrsas_mfi_cmd), 367 M_MRSAS, M_NOWAIT); 368 if (!sc->mfi_cmd_list[i]) { 369 for (j = 0; j < i; j++) 370 free(sc->mfi_cmd_list[j], M_MRSAS); 371 free(sc->mfi_cmd_list, M_MRSAS); 372 sc->mfi_cmd_list = NULL; 373 return (ENOMEM); 374 } 375 } 376 377 for (i = 0; i < max_cmd; i++) { 378 cmd = sc->mfi_cmd_list[i]; 379 memset(cmd, 0, sizeof(struct mrsas_mfi_cmd)); 380 cmd->index = i; 381 cmd->ccb_ptr = NULL; 382 cmd->sc = sc; 383 TAILQ_INSERT_TAIL(&(sc->mrsas_mfi_cmd_list_head), cmd, next); 384 } 385 386 /* create a frame pool and assign one frame to each command */ 387 if (mrsas_create_frame_pool(sc)) { 388 device_printf(sc->mrsas_dev, "Cannot allocate DMA frame pool.\n"); 389 /* Free the frames */ 390 for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { 391 cmd = sc->mfi_cmd_list[i]; 392 mrsas_free_frame(sc, cmd); 393 } 394 if (sc->mficmd_frame_tag != NULL) 395 bus_dma_tag_destroy(sc->mficmd_frame_tag); 396 return (ENOMEM); 397 } 398 return (0); 399 } 400 401 /* 402 * mrsas_create_frame_pool: Creates DMA pool for cmd frames 403 * input: Adapter soft state 404 * 405 * Each command packet has an embedded DMA memory buffer that is used for 406 * filling MFI frame and the SG list that immediately follows the frame. This 407 * function creates those DMA memory buffers for each command packet by using 408 * PCI pool facility. pad_0 is initialized to 0 to prevent corrupting value 409 * of context and could cause FW crash. 410 */ 411 static int 412 mrsas_create_frame_pool(struct mrsas_softc *sc) 413 { 414 int i; 415 struct mrsas_mfi_cmd *cmd; 416 417 if (bus_dma_tag_create(sc->mrsas_parent_tag, 418 1, 0, 419 BUS_SPACE_MAXADDR_32BIT, 420 BUS_SPACE_MAXADDR, 421 NULL, NULL, 422 MRSAS_MFI_FRAME_SIZE, 423 1, 424 MRSAS_MFI_FRAME_SIZE, 425 BUS_DMA_ALLOCNOW, 426 NULL, NULL, 427 &sc->mficmd_frame_tag)) { 428 device_printf(sc->mrsas_dev, "Cannot create MFI frame tag\n"); 429 return (ENOMEM); 430 } 431 for (i = 0; i < MRSAS_MAX_MFI_CMDS; i++) { 432 cmd = sc->mfi_cmd_list[i]; 433 cmd->frame = mrsas_alloc_frame(sc, cmd); 434 if (cmd->frame == NULL) { 435 device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n"); 436 return (ENOMEM); 437 } 438 memset(cmd->frame, 0, MRSAS_MFI_FRAME_SIZE); 439 cmd->frame->io.context = cmd->index; 440 cmd->frame->io.pad_0 = 0; 441 } 442 443 return (0); 444 } 445 446 /* 447 * mrsas_alloc_frame: Allocates MFI Frames 448 * input: Adapter soft state 449 * 450 * Create bus DMA memory tag and dmamap and load memory for MFI frames. Returns 451 * virtual memory pointer to allocated region. 452 */ 453 void * 454 mrsas_alloc_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) 455 { 456 u_int32_t frame_size = MRSAS_MFI_FRAME_SIZE; 457 458 if (bus_dmamem_alloc(sc->mficmd_frame_tag, (void **)&cmd->frame_mem, 459 BUS_DMA_NOWAIT, &cmd->frame_dmamap)) { 460 device_printf(sc->mrsas_dev, "Cannot alloc MFI frame memory\n"); 461 return (NULL); 462 } 463 if (bus_dmamap_load(sc->mficmd_frame_tag, cmd->frame_dmamap, 464 cmd->frame_mem, frame_size, mrsas_alloc_cb, 465 &cmd->frame_phys_addr, BUS_DMA_NOWAIT)) { 466 device_printf(sc->mrsas_dev, "Cannot load IO request memory\n"); 467 return (NULL); 468 } 469 return (cmd->frame_mem); 470 } 471 472 /* 473 * mrsas_alloc_cb: Callback function of bus_dmamap_load() 474 * input: callback argument, 475 * machine dependent type that describes DMA segments, 476 * number of segments, 477 * error code. 478 * 479 * This function is for the driver to receive mapping information resultant of 480 * the bus_dmamap_load(). The information is actually not being used, but the 481 * address is saved anyway. 482 */ 483 static void 484 mrsas_alloc_cb(void *arg, bus_dma_segment_t *segs, 485 int nsegs, int error) 486 { 487 bus_addr_t *addr; 488 489 addr = arg; 490 *addr = segs[0].ds_addr; 491 } 492 493 /* 494 * mrsas_free_frames: Frees memory for MFI frames 495 * input: Adapter soft state 496 * 497 * Deallocates MFI frames memory. Called from mrsas_free_mem() during detach 498 * and error case during creation of frame pool. 499 */ 500 void 501 mrsas_free_frame(struct mrsas_softc *sc, struct mrsas_mfi_cmd *cmd) 502 { 503 if (cmd->frame_phys_addr) 504 bus_dmamap_unload(sc->mficmd_frame_tag, cmd->frame_dmamap); 505 if (cmd->frame_mem != NULL) 506 bus_dmamem_free(sc->mficmd_frame_tag, cmd->frame_mem, cmd->frame_dmamap); 507 } 508