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