1 /* 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved. 5 * Support: <[email protected]> 6 * 7 * Authors: Sumit Saxena <[email protected]> 8 * Chandrakanth Patil <[email protected]> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions are 12 * met: 13 * 14 * 1. Redistributions of source code must retain the above copyright notice, 15 * this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright notice, 17 * this list of conditions and the following disclaimer in the documentation and/or other 18 * materials provided with the distribution. 19 * 3. Neither the name of the Broadcom Inc. nor the names of its contributors 20 * may be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 * 35 * The views and conclusions contained in the software and documentation are 36 * those of the authors and should not be interpreted as representing 37 * official policies,either expressed or implied, of the FreeBSD Project. 38 * 39 * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 40 * 41 * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD 42 */ 43 44 #include <sys/cdefs.h> 45 #include <sys/param.h> 46 #include <sys/proc.h> 47 #include <cam/cam.h> 48 #include <cam/cam_ccb.h> 49 #include "mpi3mr_cam.h" 50 #include "mpi3mr_app.h" 51 #include "mpi3mr.h" 52 53 static d_open_t mpi3mr_open; 54 static d_close_t mpi3mr_close; 55 static d_ioctl_t mpi3mr_ioctl; 56 static d_poll_t mpi3mr_poll; 57 58 static struct cdevsw mpi3mr_cdevsw = { 59 .d_version = D_VERSION, 60 .d_flags = 0, 61 .d_open = mpi3mr_open, 62 .d_close = mpi3mr_close, 63 .d_ioctl = mpi3mr_ioctl, 64 .d_poll = mpi3mr_poll, 65 .d_name = "mpi3mr", 66 }; 67 68 static struct mpi3mr_mgmt_info mpi3mr_mgmt_info; 69 70 static int 71 mpi3mr_open(struct cdev *dev, int flags, int fmt, struct thread *td) 72 { 73 74 return (0); 75 } 76 77 static int 78 mpi3mr_close(struct cdev *dev, int flags, int fmt, struct thread *td) 79 { 80 81 return (0); 82 } 83 84 /* 85 * mpi3mr_app_attach - Char device registration 86 * @sc: Adapter reference 87 * 88 * This function does char device registration. 89 * 90 * Return: 0 on success and proper error codes on failure 91 */ 92 int 93 mpi3mr_app_attach(struct mpi3mr_softc *sc) 94 { 95 96 /* Create a /dev entry for Avenger controller */ 97 sc->mpi3mr_cdev = make_dev(&mpi3mr_cdevsw, device_get_unit(sc->mpi3mr_dev), 98 UID_ROOT, GID_OPERATOR, 0640, "mpi3mr%d", 99 device_get_unit(sc->mpi3mr_dev)); 100 101 if (sc->mpi3mr_cdev == NULL) 102 return (ENOMEM); 103 104 sc->mpi3mr_cdev->si_drv1 = sc; 105 106 /* Assign controller instance to mgmt_info structure */ 107 if (device_get_unit(sc->mpi3mr_dev) == 0) 108 memset(&mpi3mr_mgmt_info, 0, sizeof(mpi3mr_mgmt_info)); 109 mpi3mr_mgmt_info.count++; 110 mpi3mr_mgmt_info.sc_ptr[mpi3mr_mgmt_info.max_index] = sc; 111 mpi3mr_mgmt_info.max_index++; 112 113 return (0); 114 } 115 116 void 117 mpi3mr_app_detach(struct mpi3mr_softc *sc) 118 { 119 U8 i = 0; 120 121 if (sc->mpi3mr_cdev == NULL) 122 return; 123 124 destroy_dev(sc->mpi3mr_cdev); 125 for (i = 0; i < mpi3mr_mgmt_info.max_index; i++) { 126 if (mpi3mr_mgmt_info.sc_ptr[i] == sc) { 127 mpi3mr_mgmt_info.count--; 128 mpi3mr_mgmt_info.sc_ptr[i] = NULL; 129 break; 130 } 131 } 132 return; 133 } 134 135 static int 136 mpi3mr_poll(struct cdev *dev, int poll_events, struct thread *td) 137 { 138 int revents = 0; 139 struct mpi3mr_softc *sc = NULL; 140 sc = dev->si_drv1; 141 142 if ((poll_events & (POLLIN | POLLRDNORM)) && 143 (sc->mpi3mr_aen_triggered)) 144 revents |= poll_events & (POLLIN | POLLRDNORM); 145 146 if (revents == 0) { 147 if (poll_events & (POLLIN | POLLRDNORM)) { 148 sc->mpi3mr_poll_waiting = 1; 149 selrecord(td, &sc->mpi3mr_select); 150 } 151 } 152 return revents; 153 } 154 155 /** 156 * mpi3mr_app_get_adp_instancs - Get Adapter instance 157 * @mrioc_id: Adapter ID 158 * 159 * This fucnction searches the Adapter reference with mrioc_id 160 * upon found, returns the adapter reference otherwise returns 161 * the NULL 162 * 163 * Return: Adapter reference on success and NULL on failure 164 */ 165 static struct mpi3mr_softc * 166 mpi3mr_app_get_adp_instance(U8 mrioc_id) 167 { 168 struct mpi3mr_softc *sc = NULL; 169 170 if (mrioc_id >= mpi3mr_mgmt_info.max_index) 171 return NULL; 172 173 sc = mpi3mr_mgmt_info.sc_ptr[mrioc_id]; 174 return sc; 175 } 176 177 static int 178 mpi3mr_app_construct_nvme_sgl(struct mpi3mr_softc *sc, 179 Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request, 180 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, U8 bufcnt) 181 { 182 struct mpi3mr_nvme_pt_sge *nvme_sgl; 183 U64 sgl_dma; 184 U8 count; 185 U16 available_sges = 0, i; 186 U32 sge_element_size = sizeof(struct mpi3mr_nvme_pt_sge); 187 size_t length = 0; 188 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; 189 U64 sgemod_mask = ((U64)((sc->facts.sge_mod_mask) << 190 sc->facts.sge_mod_shift) << 32); 191 U64 sgemod_val = ((U64)(sc->facts.sge_mod_value) << 192 sc->facts.sge_mod_shift) << 32; 193 194 U32 size; 195 196 nvme_sgl = (struct mpi3mr_nvme_pt_sge *) 197 ((U8 *)(nvme_encap_request->Command) + MPI3MR_NVME_CMD_SGL_OFFSET); 198 199 /* 200 * Not all commands require a data transfer. If no data, just return 201 * without constructing any SGL. 202 */ 203 for (count = 0; count < bufcnt; count++, dma_buff++) { 204 if ((dma_buff->data_dir == MPI3MR_APP_DDI) || 205 (dma_buff->data_dir == MPI3MR_APP_DDO)) { 206 length = dma_buff->kern_buf_len; 207 break; 208 } 209 } 210 if (!length || !dma_buff->num_dma_desc) 211 return 0; 212 213 if (dma_buff->num_dma_desc == 1) { 214 available_sges = 1; 215 goto build_sges; 216 } 217 sgl_dma = (U64)sc->ioctl_chain_sge.dma_addr; 218 219 if (sgl_dma & sgemod_mask) { 220 printf(IOCNAME "NVMe SGL address collides with SGEModifier\n",sc->name); 221 return -1; 222 } 223 224 sgl_dma &= ~sgemod_mask; 225 sgl_dma |= sgemod_val; 226 227 memset(sc->ioctl_chain_sge.addr, 0, sc->ioctl_chain_sge.size); 228 available_sges = sc->ioctl_chain_sge.size / sge_element_size; 229 if (available_sges < dma_buff->num_dma_desc) 230 return -1; 231 memset(nvme_sgl, 0, sizeof(struct mpi3mr_nvme_pt_sge)); 232 nvme_sgl->base_addr = sgl_dma; 233 size = dma_buff->num_dma_desc * sizeof(struct mpi3mr_nvme_pt_sge); 234 nvme_sgl->length = htole32(size); 235 nvme_sgl->type = MPI3MR_NVMESGL_LAST_SEGMENT; 236 237 nvme_sgl = (struct mpi3mr_nvme_pt_sge *) sc->ioctl_chain_sge.addr; 238 239 build_sges: 240 for (i = 0; i < dma_buff->num_dma_desc; i++) { 241 sgl_dma = htole64(dma_buff->dma_desc[i].dma_addr); 242 if (sgl_dma & sgemod_mask) { 243 printf("%s: SGL address collides with SGE modifier\n", 244 __func__); 245 return -1; 246 } 247 248 sgl_dma &= ~sgemod_mask; 249 sgl_dma |= sgemod_val; 250 251 nvme_sgl->base_addr = sgl_dma; 252 nvme_sgl->length = htole32(dma_buff->dma_desc[i].size); 253 nvme_sgl->type = MPI3MR_NVMESGL_DATA_SEGMENT; 254 nvme_sgl++; 255 available_sges--; 256 } 257 258 return 0; 259 } 260 261 static int 262 mpi3mr_app_build_nvme_prp(struct mpi3mr_softc *sc, 263 Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request, 264 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, U8 bufcnt) 265 { 266 int prp_size = MPI3MR_NVME_PRP_SIZE; 267 U64 *prp_entry, *prp1_entry, *prp2_entry; 268 U64 *prp_page; 269 bus_addr_t prp_entry_dma, prp_page_dma, dma_addr; 270 U32 offset, entry_len, dev_pgsz; 271 U32 page_mask_result, page_mask; 272 size_t length = 0, desc_len; 273 U8 count; 274 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; 275 U64 sgemod_mask = ((U64)((sc->facts.sge_mod_mask) << 276 sc->facts.sge_mod_shift) << 32); 277 U64 sgemod_val = ((U64)(sc->facts.sge_mod_value) << 278 sc->facts.sge_mod_shift) << 32; 279 U16 dev_handle = nvme_encap_request->DevHandle; 280 struct mpi3mr_target *tgtdev; 281 U16 desc_count = 0; 282 283 tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle); 284 if (!tgtdev) { 285 printf(IOCNAME "EncapNVMe Error: Invalid DevHandle 0x%02x\n", sc->name, 286 dev_handle); 287 return -1; 288 } 289 if (tgtdev->dev_spec.pcie_inf.pgsz == 0) { 290 printf(IOCNAME "%s: NVME device page size is zero for handle 0x%04x\n", 291 sc->name, __func__, dev_handle); 292 return -1; 293 } 294 dev_pgsz = 1 << (tgtdev->dev_spec.pcie_inf.pgsz); 295 296 page_mask = dev_pgsz - 1; 297 298 if (dev_pgsz > MPI3MR_IOCTL_SGE_SIZE){ 299 printf("%s: NVMe device page size(%d) is greater than ioctl data sge size(%d) for handle 0x%04x\n", 300 __func__, dev_pgsz, MPI3MR_IOCTL_SGE_SIZE, dev_handle); 301 return -1; 302 } 303 304 if (MPI3MR_IOCTL_SGE_SIZE % dev_pgsz){ 305 printf("%s: ioctl data sge size(%d) is not a multiple of NVMe device page size(%d) for handle 0x%04x\n", 306 __func__, MPI3MR_IOCTL_SGE_SIZE, dev_pgsz, dev_handle); 307 return -1; 308 } 309 310 /* 311 * Not all commands require a data transfer. If no data, just return 312 * without constructing any PRP. 313 */ 314 for (count = 0; count < bufcnt; count++, dma_buff++) { 315 if ((dma_buff->data_dir == MPI3MR_APP_DDI) || 316 (dma_buff->data_dir == MPI3MR_APP_DDO)) { 317 length = dma_buff->kern_buf_len; 318 break; 319 } 320 } 321 if (!length || !dma_buff->num_dma_desc) 322 return 0; 323 324 for (count = 0; count < dma_buff->num_dma_desc; count++) { 325 dma_addr = dma_buff->dma_desc[count].dma_addr; 326 if (dma_addr & page_mask) { 327 printf("%s:dma_addr 0x%lu is not aligned with page size 0x%x\n", 328 __func__, dma_addr, dev_pgsz); 329 return -1; 330 } 331 } 332 333 dma_addr = dma_buff->dma_desc[0].dma_addr; 334 desc_len = dma_buff->dma_desc[0].size; 335 336 sc->nvme_encap_prp_sz = 0; 337 if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ 338 4, 0, /* algnmnt, boundary */ 339 sc->dma_loaddr, /* lowaddr */ 340 BUS_SPACE_MAXADDR, /* highaddr */ 341 NULL, NULL, /* filter, filterarg */ 342 dev_pgsz, /* maxsize */ 343 1, /* nsegments */ 344 dev_pgsz, /* maxsegsize */ 345 0, /* flags */ 346 NULL, NULL, /* lockfunc, lockarg */ 347 &sc->nvme_encap_prp_list_dmatag)) { 348 mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot create ioctl NVME kernel buffer dma tag\n"); 349 return (ENOMEM); 350 } 351 352 if (bus_dmamem_alloc(sc->nvme_encap_prp_list_dmatag, (void **)&sc->nvme_encap_prp_list, 353 BUS_DMA_NOWAIT, &sc->nvme_encap_prp_list_dma_dmamap)) { 354 mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate ioctl NVME dma memory\n"); 355 return (ENOMEM); 356 } 357 358 bzero(sc->nvme_encap_prp_list, dev_pgsz); 359 bus_dmamap_load(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap, 360 sc->nvme_encap_prp_list, dev_pgsz, mpi3mr_memaddr_cb, &sc->nvme_encap_prp_list_dma, 361 BUS_DMA_NOWAIT); 362 363 if (!sc->nvme_encap_prp_list) { 364 printf(IOCNAME "%s:%d Cannot load ioctl NVME dma memory for size: %d\n", sc->name, 365 __func__, __LINE__, dev_pgsz); 366 goto err_out; 367 } 368 sc->nvme_encap_prp_sz = dev_pgsz; 369 370 /* 371 * Set pointers to PRP1 and PRP2, which are in the NVMe command. 372 * PRP1 is located at a 24 byte offset from the start of the NVMe 373 * command. Then set the current PRP entry pointer to PRP1. 374 */ 375 prp1_entry = (U64 *)((U8 *)(nvme_encap_request->Command) + MPI3MR_NVME_CMD_PRP1_OFFSET); 376 prp2_entry = (U64 *)((U8 *)(nvme_encap_request->Command) + MPI3MR_NVME_CMD_PRP2_OFFSET); 377 prp_entry = prp1_entry; 378 /* 379 * For the PRP entries, use the specially allocated buffer of 380 * contiguous memory. 381 */ 382 prp_page = sc->nvme_encap_prp_list; 383 prp_page_dma = sc->nvme_encap_prp_list_dma; 384 385 /* 386 * Check if we are within 1 entry of a page boundary we don't 387 * want our first entry to be a PRP List entry. 388 */ 389 page_mask_result = (uintptr_t)((U8 *)prp_page + prp_size) & page_mask; 390 if (!page_mask_result) { 391 printf(IOCNAME "PRP Page is not page aligned\n", sc->name); 392 goto err_out; 393 } 394 395 /* 396 * Set PRP physical pointer, which initially points to the current PRP 397 * DMA memory page. 398 */ 399 prp_entry_dma = prp_page_dma; 400 401 402 /* Loop while the length is not zero. */ 403 while (length) { 404 page_mask_result = (prp_entry_dma + prp_size) & page_mask; 405 if (!page_mask_result && (length > dev_pgsz)) { 406 printf(IOCNAME "Single PRP page is not sufficient\n", sc->name); 407 goto err_out; 408 } 409 410 /* Need to handle if entry will be part of a page. */ 411 offset = dma_addr & page_mask; 412 entry_len = dev_pgsz - offset; 413 414 if (prp_entry == prp1_entry) { 415 /* 416 * Must fill in the first PRP pointer (PRP1) before 417 * moving on. 418 */ 419 *prp1_entry = dma_addr; 420 if (*prp1_entry & sgemod_mask) { 421 printf(IOCNAME "PRP1 address collides with SGEModifier\n", sc->name); 422 goto err_out; 423 } 424 *prp1_entry &= ~sgemod_mask; 425 *prp1_entry |= sgemod_val; 426 427 /* 428 * Now point to the second PRP entry within the 429 * command (PRP2). 430 */ 431 prp_entry = prp2_entry; 432 } else if (prp_entry == prp2_entry) { 433 /* 434 * Should the PRP2 entry be a PRP List pointer or just 435 * a regular PRP pointer? If there is more than one 436 * more page of data, must use a PRP List pointer. 437 */ 438 if (length > dev_pgsz) { 439 /* 440 * PRP2 will contain a PRP List pointer because 441 * more PRP's are needed with this command. The 442 * list will start at the beginning of the 443 * contiguous buffer. 444 */ 445 *prp2_entry = prp_entry_dma; 446 if (*prp2_entry & sgemod_mask) { 447 printf(IOCNAME "PRP list address collides with SGEModifier\n", sc->name); 448 goto err_out; 449 } 450 *prp2_entry &= ~sgemod_mask; 451 *prp2_entry |= sgemod_val; 452 453 /* 454 * The next PRP Entry will be the start of the 455 * first PRP List. 456 */ 457 prp_entry = prp_page; 458 continue; 459 } else { 460 /* 461 * After this, the PRP Entries are complete. 462 * This command uses 2 PRP's and no PRP list. 463 */ 464 *prp2_entry = dma_addr; 465 if (*prp2_entry & sgemod_mask) { 466 printf(IOCNAME "PRP2 address collides with SGEModifier\n", sc->name); 467 goto err_out; 468 } 469 *prp2_entry &= ~sgemod_mask; 470 *prp2_entry |= sgemod_val; 471 } 472 } else { 473 /* 474 * Put entry in list and bump the addresses. 475 * 476 * After PRP1 and PRP2 are filled in, this will fill in 477 * all remaining PRP entries in a PRP List, one per 478 * each time through the loop. 479 */ 480 *prp_entry = dma_addr; 481 if (*prp_entry & sgemod_mask) { 482 printf(IOCNAME "PRP address collides with SGEModifier\n", sc->name); 483 goto err_out; 484 } 485 *prp_entry &= ~sgemod_mask; 486 *prp_entry |= sgemod_val; 487 prp_entry++; 488 prp_entry_dma += prp_size; 489 } 490 491 /* Decrement length accounting for last partial page. */ 492 if (entry_len >= length) 493 length = 0; 494 else { 495 if (entry_len <= desc_len) { 496 dma_addr += entry_len; 497 desc_len -= entry_len; 498 } 499 if (!desc_len) { 500 if ((++desc_count) >= 501 dma_buff->num_dma_desc) { 502 printf("%s: Invalid len %ld while building PRP\n", 503 __func__, length); 504 goto err_out; 505 } 506 dma_addr = 507 dma_buff->dma_desc[desc_count].dma_addr; 508 desc_len = 509 dma_buff->dma_desc[desc_count].size; 510 } 511 length -= entry_len; 512 } 513 } 514 return 0; 515 err_out: 516 if (sc->nvme_encap_prp_list && sc->nvme_encap_prp_list_dma) { 517 bus_dmamap_unload(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap); 518 bus_dmamem_free(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list, sc->nvme_encap_prp_list_dma_dmamap); 519 bus_dma_tag_destroy(sc->nvme_encap_prp_list_dmatag); 520 sc->nvme_encap_prp_list = NULL; 521 } 522 return -1; 523 } 524 525 /** 526 + * mpi3mr_map_data_buffer_dma - build dma descriptors for data 527 + * buffers 528 + * @sc: Adapter instance reference 529 + * @dma_buff: buffer map descriptor 530 + * @desc_count: Number of already consumed dma descriptors 531 + * 532 + * This function computes how many pre-allocated DMA descriptors 533 + * are required for the given data buffer and if those number of 534 + * descriptors are free, then setup the mapping of the scattered 535 + * DMA address to the given data buffer, if the data direction 536 + * of the buffer is DATA_OUT then the actual data is copied to 537 + * the DMA buffers 538 + * 539 + * Return: 0 on success, -1 on failure 540 + */ 541 static int mpi3mr_map_data_buffer_dma(struct mpi3mr_softc *sc, 542 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, 543 U8 desc_count) 544 { 545 U16 i, needed_desc = (dma_buffers->kern_buf_len / MPI3MR_IOCTL_SGE_SIZE); 546 U32 buf_len = dma_buffers->kern_buf_len, copied_len = 0; 547 int error; 548 549 if (dma_buffers->kern_buf_len % MPI3MR_IOCTL_SGE_SIZE) 550 needed_desc++; 551 552 if ((needed_desc + desc_count) > MPI3MR_NUM_IOCTL_SGE) { 553 printf("%s: DMA descriptor mapping error %d:%d:%d\n", 554 __func__, needed_desc, desc_count, MPI3MR_NUM_IOCTL_SGE); 555 return -1; 556 } 557 558 dma_buffers->dma_desc = malloc(sizeof(*dma_buffers->dma_desc) * needed_desc, 559 M_MPI3MR, M_NOWAIT | M_ZERO); 560 if (!dma_buffers->dma_desc) 561 return -1; 562 563 error = 0; 564 for (i = 0; i < needed_desc; i++, desc_count++) { 565 566 dma_buffers->dma_desc[i].addr = sc->ioctl_sge[desc_count].addr; 567 dma_buffers->dma_desc[i].dma_addr = sc->ioctl_sge[desc_count].dma_addr; 568 569 if (buf_len < sc->ioctl_sge[desc_count].size) 570 dma_buffers->dma_desc[i].size = buf_len; 571 else 572 dma_buffers->dma_desc[i].size = sc->ioctl_sge[desc_count].size; 573 574 buf_len -= dma_buffers->dma_desc[i].size; 575 memset(dma_buffers->dma_desc[i].addr, 0, sc->ioctl_sge[desc_count].size); 576 577 if (dma_buffers->data_dir == MPI3MR_APP_DDO) { 578 error = copyin(((U8 *)dma_buffers->user_buf + copied_len), 579 dma_buffers->dma_desc[i].addr, 580 dma_buffers->dma_desc[i].size); 581 if (error != 0) 582 break; 583 copied_len += dma_buffers->dma_desc[i].size; 584 } 585 } 586 if (error != 0) { 587 printf("%s: DMA copyin error %d\n", __func__, error); 588 free(dma_buffers->dma_desc, M_MPI3MR); 589 return -1; 590 } 591 592 dma_buffers->num_dma_desc = needed_desc; 593 594 return 0; 595 } 596 597 static unsigned int 598 mpi3mr_app_get_nvme_data_fmt(Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request) 599 { 600 U8 format = 0; 601 602 format = ((nvme_encap_request->Command[0] & 0xc000) >> 14); 603 return format; 604 } 605 606 static inline U16 mpi3mr_total_num_ioctl_sges(struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, 607 U8 bufcnt) 608 { 609 U16 i, sge_count = 0; 610 for (i=0; i < bufcnt; i++, dma_buffers++) { 611 if ((dma_buffers->data_dir == MPI3MR_APP_DDN) || 612 dma_buffers->kern_buf) 613 continue; 614 sge_count += dma_buffers->num_dma_desc; 615 if (!dma_buffers->num_dma_desc) 616 sge_count++; 617 } 618 return sge_count; 619 } 620 621 static int 622 mpi3mr_app_construct_sgl(struct mpi3mr_softc *sc, U8 *mpi_request, U32 sgl_offset, 623 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, 624 U8 bufcnt, U8 is_rmc, U8 is_rmr, U8 num_datasges) 625 { 626 U8 *sgl = (mpi_request + sgl_offset), count = 0; 627 Mpi3RequestHeader_t *mpi_header = (Mpi3RequestHeader_t *)mpi_request; 628 Mpi3MgmtPassthroughRequest_t *rmgmt_req = 629 (Mpi3MgmtPassthroughRequest_t *)mpi_request; 630 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; 631 U8 flag, sgl_flags, sgl_flags_eob, sgl_flags_last, last_chain_sgl_flags; 632 U16 available_sges, i, sges_needed; 633 U32 sge_element_size = sizeof(struct _MPI3_SGE_COMMON); 634 bool chain_used = false; 635 636 sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | 637 MPI3_SGE_FLAGS_DLAS_SYSTEM ; 638 sgl_flags_eob = sgl_flags | MPI3_SGE_FLAGS_END_OF_BUFFER; 639 sgl_flags_last = sgl_flags_eob | MPI3_SGE_FLAGS_END_OF_LIST; 640 last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | 641 MPI3_SGE_FLAGS_DLAS_SYSTEM; 642 643 sges_needed = mpi3mr_total_num_ioctl_sges(dma_buffers, bufcnt); 644 645 if (is_rmc) { 646 mpi3mr_add_sg_single(&rmgmt_req->CommandSGL, 647 sgl_flags_last, dma_buff->kern_buf_len, 648 dma_buff->kern_buf_dma); 649 sgl = (U8 *) dma_buff->kern_buf + dma_buff->user_buf_len; 650 available_sges = (dma_buff->kern_buf_len - 651 dma_buff->user_buf_len) / sge_element_size; 652 if (sges_needed > available_sges) 653 return -1; 654 chain_used = true; 655 dma_buff++; 656 count++; 657 if (is_rmr) { 658 mpi3mr_add_sg_single(&rmgmt_req->ResponseSGL, 659 sgl_flags_last, dma_buff->kern_buf_len, 660 dma_buff->kern_buf_dma); 661 dma_buff++; 662 count++; 663 } else 664 mpi3mr_build_zero_len_sge( 665 &rmgmt_req->ResponseSGL); 666 if (num_datasges) { 667 i = 0; 668 goto build_sges; 669 } 670 } else { 671 if (sgl_offset >= MPI3MR_AREQ_FRAME_SZ) 672 return -1; 673 available_sges = (MPI3MR_AREQ_FRAME_SZ - sgl_offset) / 674 sge_element_size; 675 if (!available_sges) 676 return -1; 677 } 678 679 if (!num_datasges) { 680 mpi3mr_build_zero_len_sge(sgl); 681 return 0; 682 } 683 684 if (mpi_header->Function == MPI3_FUNCTION_SMP_PASSTHROUGH) { 685 if ((sges_needed > 2) || (sges_needed > available_sges)) 686 return -1; 687 for (; count < bufcnt; count++, dma_buff++) { 688 if ((dma_buff->data_dir == MPI3MR_APP_DDN) || 689 !dma_buff->num_dma_desc) 690 continue; 691 mpi3mr_add_sg_single(sgl, sgl_flags_last, 692 dma_buff->dma_desc[0].size, 693 dma_buff->dma_desc[0].dma_addr); 694 sgl += sge_element_size; 695 } 696 return 0; 697 } 698 i = 0; 699 700 build_sges: 701 for (; count < bufcnt; count++, dma_buff++) { 702 if (dma_buff->data_dir == MPI3MR_APP_DDN) 703 continue; 704 if (!dma_buff->num_dma_desc) { 705 if (chain_used && !available_sges) 706 return -1; 707 if (!chain_used && (available_sges == 1) && 708 (sges_needed > 1)) 709 goto setup_chain; 710 flag = sgl_flags_eob; 711 if (num_datasges == 1) 712 flag = sgl_flags_last; 713 mpi3mr_add_sg_single(sgl, flag, 0, 0); 714 sgl += sge_element_size; 715 available_sges--; 716 sges_needed--; 717 num_datasges--; 718 continue; 719 } 720 for (; i < dma_buff->num_dma_desc; i++) { 721 if (chain_used && !available_sges) 722 return -1; 723 if (!chain_used && (available_sges == 1) && 724 (sges_needed > 1)) 725 goto setup_chain; 726 flag = sgl_flags; 727 if (i == (dma_buff->num_dma_desc - 1)) { 728 if (num_datasges == 1) 729 flag = sgl_flags_last; 730 else 731 flag = sgl_flags_eob; 732 } 733 734 mpi3mr_add_sg_single(sgl, flag, 735 dma_buff->dma_desc[i].size, 736 dma_buff->dma_desc[i].dma_addr); 737 sgl += sge_element_size; 738 available_sges--; 739 sges_needed--; 740 } 741 num_datasges--; 742 i = 0; 743 } 744 return 0; 745 746 setup_chain: 747 available_sges = sc->ioctl_chain_sge.size / sge_element_size; 748 if (sges_needed > available_sges) 749 return -1; 750 mpi3mr_add_sg_single(sgl, last_chain_sgl_flags, 751 (sges_needed * sge_element_size), sc->ioctl_chain_sge.dma_addr); 752 memset(sc->ioctl_chain_sge.addr, 0, sc->ioctl_chain_sge.size); 753 sgl = (U8 *)sc->ioctl_chain_sge.addr; 754 chain_used = true; 755 goto build_sges; 756 } 757 758 759 /** 760 * mpi3mr_app_mptcmds - MPI Pass through IOCTL handler 761 * @dev: char device 762 * @cmd: IOCTL command 763 * @arg: User data payload buffer for the IOCTL 764 * @flag: flags 765 * @thread: threads 766 * 767 * This function is the top level handler for MPI Pass through 768 * IOCTL, this does basic validation of the input data buffers, 769 * identifies the given buffer types and MPI command, allocates 770 * DMAable memory for user given buffers, construstcs SGL 771 * properly and passes the command to the firmware. 772 * 773 * Once the MPI command is completed the driver copies the data 774 * if any and reply, sense information to user provided buffers. 775 * If the command is timed out then issues controller reset 776 * prior to returning. 777 * 778 * Return: 0 on success and proper error codes on failure 779 */ 780 static long 781 mpi3mr_app_mptcmds(struct cdev *dev, u_long cmd, void *uarg, 782 int flag, struct thread *td) 783 { 784 long rval = EINVAL; 785 U8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0, din_cnt = 0, dout_cnt = 0; 786 U8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF; 787 U16 desc_count = 0; 788 U8 nvme_fmt = 0; 789 U32 tmplen = 0, erbsz = MPI3MR_SENSEBUF_SZ, din_sz = 0, dout_sz = 0; 790 U8 *kern_erb = NULL; 791 U8 *mpi_request = NULL; 792 Mpi3RequestHeader_t *mpi_header = NULL; 793 Mpi3PELReqActionGetCount_t *pel = NULL; 794 Mpi3StatusReplyDescriptor_t *status_desc = NULL; 795 struct mpi3mr_softc *sc = NULL; 796 struct mpi3mr_ioctl_buf_entry_list *buffer_list = NULL; 797 struct mpi3mr_buf_entry *buf_entries = NULL; 798 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers = NULL, *dma_buff = NULL; 799 struct mpi3mr_ioctl_mpirepbuf *mpirepbuf = NULL; 800 struct mpi3mr_ioctl_mptcmd *karg = (struct mpi3mr_ioctl_mptcmd *)uarg; 801 802 803 sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); 804 if (!sc) 805 return ENODEV; 806 807 if (!sc->ioctl_sges_allocated) { 808 printf("%s: DMA memory was not allocated\n", __func__); 809 return ENOMEM; 810 } 811 812 if (karg->timeout < MPI3MR_IOCTL_DEFAULT_TIMEOUT) 813 karg->timeout = MPI3MR_IOCTL_DEFAULT_TIMEOUT; 814 815 if (!karg->mpi_msg_size || !karg->buf_entry_list_size) { 816 printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 817 __func__, __LINE__); 818 return rval; 819 } 820 if ((karg->mpi_msg_size * 4) > MPI3MR_AREQ_FRAME_SZ) { 821 printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 822 __func__, __LINE__); 823 return rval; 824 } 825 826 mpi_request = malloc(MPI3MR_AREQ_FRAME_SZ, M_MPI3MR, M_NOWAIT | M_ZERO); 827 if (!mpi_request) { 828 printf(IOCNAME "%s: memory allocation failed for mpi_request\n", sc->name, 829 __func__); 830 return ENOMEM; 831 } 832 833 mpi_header = (Mpi3RequestHeader_t *)mpi_request; 834 pel = (Mpi3PELReqActionGetCount_t *)mpi_request; 835 if (copyin(karg->mpi_msg_buf, mpi_request, (karg->mpi_msg_size * 4))) { 836 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 837 __FILE__, __LINE__, __func__); 838 rval = EFAULT; 839 goto out; 840 } 841 842 buffer_list = malloc(karg->buf_entry_list_size, M_MPI3MR, M_NOWAIT | M_ZERO); 843 if (!buffer_list) { 844 printf(IOCNAME "%s: memory allocation failed for buffer_list\n", sc->name, 845 __func__); 846 rval = ENOMEM; 847 goto out; 848 } 849 if (copyin(karg->buf_entry_list, buffer_list, karg->buf_entry_list_size)) { 850 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 851 __FILE__, __LINE__, __func__); 852 rval = EFAULT; 853 goto out; 854 } 855 if (!buffer_list->num_of_buf_entries) { 856 printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 857 __func__, __LINE__); 858 rval = EINVAL; 859 goto out; 860 } 861 bufcnt = buffer_list->num_of_buf_entries; 862 dma_buffers = malloc((sizeof(*dma_buffers) * bufcnt), M_MPI3MR, M_NOWAIT | M_ZERO); 863 if (!dma_buffers) { 864 printf(IOCNAME "%s: memory allocation failed for dma_buffers\n", sc->name, 865 __func__); 866 rval = ENOMEM; 867 goto out; 868 } 869 buf_entries = buffer_list->buf_entry; 870 dma_buff = dma_buffers; 871 for (count = 0; count < bufcnt; count++, buf_entries++, dma_buff++) { 872 memset(dma_buff, 0, sizeof(*dma_buff)); 873 dma_buff->user_buf = buf_entries->buffer; 874 dma_buff->user_buf_len = buf_entries->buf_len; 875 876 switch (buf_entries->buf_type) { 877 case MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_CMD: 878 is_rmcb = 1; 879 if ((count != 0) || !buf_entries->buf_len) 880 invalid_be = 1; 881 dma_buff->data_dir = MPI3MR_APP_DDO; 882 break; 883 case MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_RESP: 884 is_rmrb = 1; 885 if (count != 1 || !is_rmcb || !buf_entries->buf_len) 886 invalid_be = 1; 887 dma_buff->data_dir = MPI3MR_APP_DDI; 888 break; 889 case MPI3MR_IOCTL_BUFTYPE_DATA_IN: 890 din_sz = dma_buff->user_buf_len; 891 din_cnt++; 892 if ((din_cnt > 1) && !is_rmcb) 893 invalid_be = 1; 894 dma_buff->data_dir = MPI3MR_APP_DDI; 895 break; 896 case MPI3MR_IOCTL_BUFTYPE_DATA_OUT: 897 dout_sz = dma_buff->user_buf_len; 898 dout_cnt++; 899 if ((dout_cnt > 1) && !is_rmcb) 900 invalid_be = 1; 901 dma_buff->data_dir = MPI3MR_APP_DDO; 902 break; 903 case MPI3MR_IOCTL_BUFTYPE_MPI_REPLY: 904 mpirep_offset = count; 905 dma_buff->data_dir = MPI3MR_APP_DDN; 906 if (!buf_entries->buf_len) 907 invalid_be = 1; 908 break; 909 case MPI3MR_IOCTL_BUFTYPE_ERR_RESPONSE: 910 erb_offset = count; 911 dma_buff->data_dir = MPI3MR_APP_DDN; 912 if (!buf_entries->buf_len) 913 invalid_be = 1; 914 break; 915 default: 916 invalid_be = 1; 917 break; 918 } 919 if (invalid_be) 920 break; 921 } 922 if (invalid_be) { 923 printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 924 __func__, __LINE__); 925 rval = EINVAL; 926 goto out; 927 } 928 929 if (is_rmcb && ((din_sz + dout_sz) > MPI3MR_MAX_IOCTL_TRANSFER_SIZE)) { 930 printf("%s:%d: invalid data transfer size passed for function 0x%x" 931 "din_sz = %d, dout_size = %d\n", __func__, __LINE__, 932 mpi_header->Function, din_sz, dout_sz); 933 rval = EINVAL; 934 goto out; 935 } 936 937 if ((din_sz > MPI3MR_MAX_IOCTL_TRANSFER_SIZE) || 938 (dout_sz > MPI3MR_MAX_IOCTL_TRANSFER_SIZE)) { 939 printf("%s:%d: invalid data transfer size passed for function 0x%x" 940 "din_size=%d dout_size=%d\n", __func__, __LINE__, 941 mpi_header->Function, din_sz, dout_sz); 942 rval = EINVAL; 943 goto out; 944 } 945 946 if (mpi_header->Function == MPI3_FUNCTION_SMP_PASSTHROUGH) { 947 if ((din_sz > MPI3MR_IOCTL_SGE_SIZE) || 948 (dout_sz > MPI3MR_IOCTL_SGE_SIZE)) { 949 printf("%s:%d: invalid message size passed:%d:%d:%d:%d\n", 950 __func__, __LINE__, din_cnt, dout_cnt, din_sz, dout_sz); 951 rval = EINVAL; 952 goto out; 953 } 954 } 955 956 dma_buff = dma_buffers; 957 for (count = 0; count < bufcnt; count++, dma_buff++) { 958 959 dma_buff->kern_buf_len = dma_buff->user_buf_len; 960 961 if (is_rmcb && !count) { 962 dma_buff->kern_buf = sc->ioctl_chain_sge.addr; 963 dma_buff->kern_buf_len = sc->ioctl_chain_sge.size; 964 dma_buff->kern_buf_dma = sc->ioctl_chain_sge.dma_addr; 965 dma_buff->dma_desc = NULL; 966 dma_buff->num_dma_desc = 0; 967 memset(dma_buff->kern_buf, 0, dma_buff->kern_buf_len); 968 tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); 969 if (copyin(dma_buff->user_buf, dma_buff->kern_buf, tmplen)) { 970 mpi3mr_dprint(sc, MPI3MR_ERROR, "failure at %s() line: %d", 971 __func__, __LINE__); 972 rval = EFAULT; 973 goto out; 974 } 975 } else if (is_rmrb && (count == 1)) { 976 dma_buff->kern_buf = sc->ioctl_resp_sge.addr; 977 dma_buff->kern_buf_len = sc->ioctl_resp_sge.size; 978 dma_buff->kern_buf_dma = sc->ioctl_resp_sge.dma_addr; 979 dma_buff->dma_desc = NULL; 980 dma_buff->num_dma_desc = 0; 981 memset(dma_buff->kern_buf, 0, dma_buff->kern_buf_len); 982 tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); 983 dma_buff->kern_buf_len = tmplen; 984 } else { 985 if (!dma_buff->kern_buf_len) 986 continue; 987 if (mpi3mr_map_data_buffer_dma(sc, dma_buff, desc_count)) { 988 rval = ENOMEM; 989 mpi3mr_dprint(sc, MPI3MR_ERROR, "mapping data buffers failed" 990 "at %s() line: %d\n", __func__, __LINE__); 991 goto out; 992 } 993 desc_count += dma_buff->num_dma_desc; 994 } 995 } 996 997 if (erb_offset != 0xFF) { 998 kern_erb = malloc(erbsz, M_MPI3MR, M_NOWAIT | M_ZERO); 999 if (!kern_erb) { 1000 printf(IOCNAME "%s:%d Cannot allocate memory for sense buffer\n", sc->name, 1001 __func__, __LINE__); 1002 rval = ENOMEM; 1003 goto out; 1004 } 1005 } 1006 1007 if (sc->ioctl_cmds.state & MPI3MR_CMD_PENDING) { 1008 printf(IOCNAME "Issue IOCTL: Ioctl command is in use/previous command is pending\n", 1009 sc->name); 1010 rval = EAGAIN; 1011 goto out; 1012 } 1013 1014 if (sc->unrecoverable) { 1015 printf(IOCNAME "Issue IOCTL: controller is in unrecoverable state\n", sc->name); 1016 rval = EFAULT; 1017 goto out; 1018 } 1019 1020 if (sc->reset_in_progress) { 1021 printf(IOCNAME "Issue IOCTL: reset in progress\n", sc->name); 1022 rval = EAGAIN; 1023 goto out; 1024 } 1025 if (sc->block_ioctls) { 1026 printf(IOCNAME "Issue IOCTL: IOCTLs are blocked\n", sc->name); 1027 rval = EAGAIN; 1028 goto out; 1029 } 1030 1031 if (mpi_header->Function != MPI3_FUNCTION_NVME_ENCAPSULATED) { 1032 if (mpi3mr_app_construct_sgl(sc, mpi_request, (karg->mpi_msg_size * 4), dma_buffers, 1033 bufcnt, is_rmcb, is_rmrb, (dout_cnt + din_cnt))) { 1034 printf(IOCNAME "Issue IOCTL: sgl build failed\n", sc->name); 1035 rval = EAGAIN; 1036 goto out; 1037 } 1038 1039 } else { 1040 nvme_fmt = mpi3mr_app_get_nvme_data_fmt( 1041 (Mpi3NVMeEncapsulatedRequest_t *)mpi_request); 1042 if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_PRP) { 1043 if (mpi3mr_app_build_nvme_prp(sc, 1044 (Mpi3NVMeEncapsulatedRequest_t *) mpi_request, 1045 dma_buffers, bufcnt)) { 1046 rval = ENOMEM; 1047 goto out; 1048 } 1049 } else if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL1 || 1050 nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL2) { 1051 if (mpi3mr_app_construct_nvme_sgl(sc, (Mpi3NVMeEncapsulatedRequest_t *) mpi_request, 1052 dma_buffers, bufcnt)) { 1053 rval = EINVAL; 1054 goto out; 1055 } 1056 } else { 1057 printf(IOCNAME "%s: Invalid NVMe Command Format\n", sc->name, 1058 __func__); 1059 rval = EINVAL; 1060 goto out; 1061 } 1062 } 1063 1064 sc->ioctl_cmds.state = MPI3MR_CMD_PENDING; 1065 sc->ioctl_cmds.is_waiting = 1; 1066 sc->ioctl_cmds.callback = NULL; 1067 sc->ioctl_cmds.is_senseprst = 0; 1068 sc->ioctl_cmds.sensebuf = kern_erb; 1069 memset((sc->ioctl_cmds.reply), 0, sc->reply_sz); 1070 mpi_header->HostTag = MPI3MR_HOSTTAG_IOCTLCMDS; 1071 init_completion(&sc->ioctl_cmds.completion); 1072 rval = mpi3mr_submit_admin_cmd(sc, mpi_request, MPI3MR_AREQ_FRAME_SZ); 1073 if (rval) { 1074 printf(IOCNAME "Issue IOCTL: Admin Post failed\n", sc->name); 1075 goto out_failed; 1076 } 1077 wait_for_completion_timeout(&sc->ioctl_cmds.completion, karg->timeout); 1078 1079 if (!(sc->ioctl_cmds.state & MPI3MR_CMD_COMPLETE)) { 1080 sc->ioctl_cmds.is_waiting = 0; 1081 printf(IOCNAME "Issue IOCTL: command timed out\n", sc->name); 1082 rval = EAGAIN; 1083 if (sc->ioctl_cmds.state & MPI3MR_CMD_RESET) 1084 goto out_failed; 1085 1086 sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; 1087 sc->reset.reason = MPI3MR_RESET_FROM_IOCTL_TIMEOUT; 1088 goto out_failed; 1089 } 1090 1091 if (sc->nvme_encap_prp_list && sc->nvme_encap_prp_list_dma) { 1092 bus_dmamap_unload(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap); 1093 bus_dmamem_free(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list, sc->nvme_encap_prp_list_dma_dmamap); 1094 bus_dma_tag_destroy(sc->nvme_encap_prp_list_dmatag); 1095 sc->nvme_encap_prp_list = NULL; 1096 } 1097 1098 if (((sc->ioctl_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1099 != MPI3_IOCSTATUS_SUCCESS) && 1100 (sc->mpi3mr_debug & MPI3MR_DEBUG_IOCTL)) { 1101 printf(IOCNAME "Issue IOCTL: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n", sc->name, 1102 (sc->ioctl_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1103 sc->ioctl_cmds.ioc_loginfo); 1104 } 1105 1106 if ((mpirep_offset != 0xFF) && 1107 dma_buffers[mpirep_offset].user_buf_len) { 1108 dma_buff = &dma_buffers[mpirep_offset]; 1109 dma_buff->kern_buf_len = (sizeof(*mpirepbuf) - 1 + 1110 sc->reply_sz); 1111 mpirepbuf = malloc(dma_buff->kern_buf_len, M_MPI3MR, M_NOWAIT | M_ZERO); 1112 1113 if (!mpirepbuf) { 1114 printf(IOCNAME "%s: failed obtaining a memory for mpi reply\n", sc->name, 1115 __func__); 1116 rval = ENOMEM; 1117 goto out_failed; 1118 } 1119 if (sc->ioctl_cmds.state & MPI3MR_CMD_REPLYVALID) { 1120 mpirepbuf->mpirep_type = 1121 MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_ADDRESS; 1122 memcpy(mpirepbuf->repbuf, sc->ioctl_cmds.reply, sc->reply_sz); 1123 } else { 1124 mpirepbuf->mpirep_type = 1125 MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_STATUS; 1126 status_desc = (Mpi3StatusReplyDescriptor_t *) 1127 mpirepbuf->repbuf; 1128 status_desc->IOCStatus = sc->ioctl_cmds.ioc_status; 1129 status_desc->IOCLogInfo = sc->ioctl_cmds.ioc_loginfo; 1130 } 1131 tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); 1132 if (copyout(mpirepbuf, dma_buff->user_buf, tmplen)) { 1133 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1134 __FILE__, __LINE__, __func__); 1135 rval = EFAULT; 1136 goto out_failed; 1137 } 1138 } 1139 1140 if (erb_offset != 0xFF && sc->ioctl_cmds.sensebuf && 1141 sc->ioctl_cmds.is_senseprst) { 1142 dma_buff = &dma_buffers[erb_offset]; 1143 tmplen = min(erbsz, dma_buff->user_buf_len); 1144 if (copyout(kern_erb, dma_buff->user_buf, tmplen)) { 1145 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1146 __FILE__, __LINE__, __func__); 1147 rval = EFAULT; 1148 goto out_failed; 1149 } 1150 } 1151 1152 dma_buff = dma_buffers; 1153 for (count = 0; count < bufcnt; count++, dma_buff++) { 1154 if ((count == 1) && is_rmrb) { 1155 if (copyout(dma_buff->kern_buf, dma_buff->user_buf,dma_buff->kern_buf_len)) { 1156 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1157 __FILE__, __LINE__, __func__); 1158 rval = EFAULT; 1159 goto out_failed; 1160 } 1161 } else if (dma_buff->data_dir == MPI3MR_APP_DDI) { 1162 tmplen = 0; 1163 for (desc_count = 0; desc_count < dma_buff->num_dma_desc; desc_count++) { 1164 if (copyout(dma_buff->dma_desc[desc_count].addr, 1165 (U8 *)dma_buff->user_buf+tmplen, 1166 dma_buff->dma_desc[desc_count].size)) { 1167 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1168 __FILE__, __LINE__, __func__); 1169 rval = EFAULT; 1170 goto out_failed; 1171 } 1172 tmplen += dma_buff->dma_desc[desc_count].size; 1173 } 1174 } 1175 } 1176 1177 if ((pel->Function == MPI3_FUNCTION_PERSISTENT_EVENT_LOG) && 1178 (pel->Action == MPI3_PEL_ACTION_GET_COUNT)) 1179 sc->mpi3mr_aen_triggered = 0; 1180 1181 out_failed: 1182 sc->ioctl_cmds.is_senseprst = 0; 1183 sc->ioctl_cmds.sensebuf = NULL; 1184 sc->ioctl_cmds.state = MPI3MR_CMD_NOTUSED; 1185 out: 1186 if (kern_erb) 1187 free(kern_erb, M_MPI3MR); 1188 if (buffer_list) 1189 free(buffer_list, M_MPI3MR); 1190 if (mpi_request) 1191 free(mpi_request, M_MPI3MR); 1192 if (dma_buffers) { 1193 dma_buff = dma_buffers; 1194 for (count = 0; count < bufcnt; count++, dma_buff++) { 1195 free(dma_buff->dma_desc, M_MPI3MR); 1196 } 1197 free(dma_buffers, M_MPI3MR); 1198 } 1199 if (mpirepbuf) 1200 free(mpirepbuf, M_MPI3MR); 1201 return rval; 1202 } 1203 1204 /** 1205 * mpi3mr_soft_reset_from_app - Trigger controller reset 1206 * @sc: Adapter instance reference 1207 * 1208 * This function triggers the controller reset from the 1209 * watchdog context and wait for it to complete. It will 1210 * come out of wait upon completion or timeout exaustion. 1211 * 1212 * Return: 0 on success and proper error codes on failure 1213 */ 1214 static long 1215 mpi3mr_soft_reset_from_app(struct mpi3mr_softc *sc) 1216 { 1217 1218 U32 timeout; 1219 1220 /* if reset is not in progress, trigger soft reset from watchdog context */ 1221 if (!sc->reset_in_progress) { 1222 sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; 1223 sc->reset.reason = MPI3MR_RESET_FROM_IOCTL; 1224 1225 /* Wait for soft reset to start */ 1226 timeout = 50; 1227 while (timeout--) { 1228 if (sc->reset_in_progress == 1) 1229 break; 1230 DELAY(100 * 1000); 1231 } 1232 if (!timeout) 1233 return EFAULT; 1234 } 1235 1236 /* Wait for soft reset to complete */ 1237 int i = 0; 1238 timeout = sc->ready_timeout; 1239 while (timeout--) { 1240 if (sc->reset_in_progress == 0) 1241 break; 1242 i++; 1243 if (!(i % 5)) { 1244 mpi3mr_dprint(sc, MPI3MR_INFO, 1245 "[%2ds]waiting for controller reset to be finished from %s\n", i, __func__); 1246 } 1247 DELAY(1000 * 1000); 1248 } 1249 1250 /* 1251 * In case of soft reset failure or not completed within stipulated time, 1252 * fail back to application. 1253 */ 1254 if ((!timeout || sc->reset.status)) 1255 return EFAULT; 1256 1257 return 0; 1258 } 1259 1260 1261 /** 1262 * mpi3mr_adp_reset - Issue controller reset 1263 * @sc: Adapter instance reference 1264 * @data_out_buf: User buffer with reset type 1265 * @data_out_sz: length of the user buffer. 1266 * 1267 * This function identifies the user provided reset type and 1268 * issues approporiate reset to the controller and wait for that 1269 * to complete and reinitialize the controller and then returns. 1270 * 1271 * Return: 0 on success and proper error codes on failure 1272 */ 1273 static long 1274 mpi3mr_adp_reset(struct mpi3mr_softc *sc, 1275 void *data_out_buf, U32 data_out_sz) 1276 { 1277 long rval = EINVAL; 1278 struct mpi3mr_ioctl_adpreset adpreset; 1279 1280 memset(&adpreset, 0, sizeof(adpreset)); 1281 1282 if (data_out_sz != sizeof(adpreset)) { 1283 printf(IOCNAME "Invalid user adpreset buffer size %s() line: %d\n", sc->name, 1284 __func__, __LINE__); 1285 goto out; 1286 } 1287 1288 if (copyin(data_out_buf, &adpreset, sizeof(adpreset))) { 1289 printf(IOCNAME "failure at %s() line:%d\n", sc->name, 1290 __func__, __LINE__); 1291 rval = EFAULT; 1292 goto out; 1293 } 1294 1295 switch (adpreset.reset_type) { 1296 case MPI3MR_IOCTL_ADPRESET_SOFT: 1297 sc->reset.ioctl_reset_snapdump = false; 1298 break; 1299 case MPI3MR_IOCTL_ADPRESET_DIAG_FAULT: 1300 sc->reset.ioctl_reset_snapdump = true; 1301 break; 1302 default: 1303 printf(IOCNAME "Unknown reset_type(0x%x) issued\n", sc->name, 1304 adpreset.reset_type); 1305 goto out; 1306 } 1307 rval = mpi3mr_soft_reset_from_app(sc); 1308 if (rval) 1309 printf(IOCNAME "reset handler returned error (0x%lx) for reset type 0x%x\n", 1310 sc->name, rval, adpreset.reset_type); 1311 1312 out: 1313 return rval; 1314 } 1315 1316 void 1317 mpi3mr_app_send_aen(struct mpi3mr_softc *sc) 1318 { 1319 sc->mpi3mr_aen_triggered = 1; 1320 if (sc->mpi3mr_poll_waiting) { 1321 selwakeup(&sc->mpi3mr_select); 1322 sc->mpi3mr_poll_waiting = 0; 1323 } 1324 return; 1325 } 1326 1327 void 1328 mpi3mr_pel_wait_complete(struct mpi3mr_softc *sc, 1329 struct mpi3mr_drvr_cmd *drvr_cmd) 1330 { 1331 U8 retry = 0; 1332 Mpi3PELReply_t *pel_reply = NULL; 1333 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1334 1335 if (drvr_cmd->state & MPI3MR_CMD_RESET) 1336 goto cleanup_drvrcmd; 1337 1338 if (!(drvr_cmd->state & MPI3MR_CMD_REPLYVALID)) { 1339 printf(IOCNAME "%s: PELGetSeqNum Failed, No Reply\n", sc->name, __func__); 1340 goto out_failed; 1341 } 1342 pel_reply = (Mpi3PELReply_t *)drvr_cmd->reply; 1343 1344 if (((GET_IOC_STATUS(drvr_cmd->ioc_status)) != MPI3_IOCSTATUS_SUCCESS) 1345 || ((le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_SUCCESS) 1346 && (le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_ABORTED))){ 1347 printf(IOCNAME "%s: PELGetSeqNum Failed, IOCStatus(0x%04x) Loginfo(0x%08x) PEL_LogStatus(0x%04x)\n", 1348 sc->name, __func__, GET_IOC_STATUS(drvr_cmd->ioc_status), 1349 drvr_cmd->ioc_loginfo, le16toh(pel_reply->PELogStatus)); 1350 retry = 1; 1351 } 1352 1353 if (retry) { 1354 if (drvr_cmd->retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 1355 drvr_cmd->retry_count++; 1356 printf(IOCNAME "%s : PELWaitretry=%d\n", sc->name, 1357 __func__, drvr_cmd->retry_count); 1358 mpi3mr_issue_pel_wait(sc, drvr_cmd); 1359 return; 1360 } 1361 1362 printf(IOCNAME "%s :PELWait failed after all retries\n", sc->name, 1363 __func__); 1364 goto out_failed; 1365 } 1366 1367 mpi3mr_app_send_aen(sc); 1368 1369 if (!sc->pel_abort_requested) { 1370 sc->pel_cmds.retry_count = 0; 1371 mpi3mr_send_pel_getseq(sc, &sc->pel_cmds); 1372 } 1373 1374 return; 1375 out_failed: 1376 sc->pel_wait_pend = 0; 1377 cleanup_drvrcmd: 1378 drvr_cmd->state = MPI3MR_CMD_NOTUSED; 1379 drvr_cmd->callback = NULL; 1380 drvr_cmd->retry_count = 0; 1381 } 1382 1383 void 1384 mpi3mr_issue_pel_wait(struct mpi3mr_softc *sc, 1385 struct mpi3mr_drvr_cmd *drvr_cmd) 1386 { 1387 U8 retry_count = 0; 1388 Mpi3PELReqActionWait_t pel_wait; 1389 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1390 1391 sc->pel_abort_requested = 0; 1392 1393 memset(&pel_wait, 0, sizeof(pel_wait)); 1394 drvr_cmd->state = MPI3MR_CMD_PENDING; 1395 drvr_cmd->is_waiting = 0; 1396 drvr_cmd->callback = mpi3mr_pel_wait_complete; 1397 drvr_cmd->ioc_status = 0; 1398 drvr_cmd->ioc_loginfo = 0; 1399 pel_wait.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 1400 pel_wait.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 1401 pel_wait.Action = MPI3_PEL_ACTION_WAIT; 1402 pel_wait.StartingSequenceNumber = htole32(sc->newest_seqnum); 1403 pel_wait.Locale = htole16(sc->pel_locale); 1404 pel_wait.Class = htole16(sc->pel_class); 1405 pel_wait.WaitTime = MPI3_PEL_WAITTIME_INFINITE_WAIT; 1406 printf(IOCNAME "Issuing PELWait: seqnum %u class %u locale 0x%08x\n", 1407 sc->name, sc->newest_seqnum, sc->pel_class, sc->pel_locale); 1408 retry_pel_wait: 1409 if (mpi3mr_submit_admin_cmd(sc, &pel_wait, sizeof(pel_wait))) { 1410 printf(IOCNAME "%s: Issue PELWait IOCTL: Admin Post failed\n", sc->name, __func__); 1411 if (retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 1412 retry_count++; 1413 goto retry_pel_wait; 1414 } 1415 goto out_failed; 1416 } 1417 return; 1418 out_failed: 1419 drvr_cmd->state = MPI3MR_CMD_NOTUSED; 1420 drvr_cmd->callback = NULL; 1421 drvr_cmd->retry_count = 0; 1422 sc->pel_wait_pend = 0; 1423 return; 1424 } 1425 1426 void 1427 mpi3mr_send_pel_getseq(struct mpi3mr_softc *sc, 1428 struct mpi3mr_drvr_cmd *drvr_cmd) 1429 { 1430 U8 retry_count = 0; 1431 U8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 1432 Mpi3PELReqActionGetSequenceNumbers_t pel_getseq_req; 1433 1434 memset(&pel_getseq_req, 0, sizeof(pel_getseq_req)); 1435 sc->pel_cmds.state = MPI3MR_CMD_PENDING; 1436 sc->pel_cmds.is_waiting = 0; 1437 sc->pel_cmds.ioc_status = 0; 1438 sc->pel_cmds.ioc_loginfo = 0; 1439 sc->pel_cmds.callback = mpi3mr_pel_getseq_complete; 1440 pel_getseq_req.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 1441 pel_getseq_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 1442 pel_getseq_req.Action = MPI3_PEL_ACTION_GET_SEQNUM; 1443 mpi3mr_add_sg_single(&pel_getseq_req.SGL, sgl_flags, 1444 sc->pel_seq_number_sz, sc->pel_seq_number_dma); 1445 1446 retry_pel_getseq: 1447 if (mpi3mr_submit_admin_cmd(sc, &pel_getseq_req, sizeof(pel_getseq_req))) { 1448 printf(IOCNAME "%s: Issuing PEL GetSeq IOCTL: Admin Post failed\n", sc->name, __func__); 1449 if (retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 1450 retry_count++; 1451 goto retry_pel_getseq; 1452 } 1453 goto out_failed; 1454 } 1455 return; 1456 out_failed: 1457 drvr_cmd->state = MPI3MR_CMD_NOTUSED; 1458 drvr_cmd->callback = NULL; 1459 drvr_cmd->retry_count = 0; 1460 sc->pel_wait_pend = 0; 1461 } 1462 1463 void 1464 mpi3mr_pel_getseq_complete(struct mpi3mr_softc *sc, 1465 struct mpi3mr_drvr_cmd *drvr_cmd) 1466 { 1467 U8 retry = 0; 1468 Mpi3PELReply_t *pel_reply = NULL; 1469 Mpi3PELSeq_t *pel_seq_num = (Mpi3PELSeq_t *)sc->pel_seq_number; 1470 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1471 1472 if (drvr_cmd->state & MPI3MR_CMD_RESET) 1473 goto cleanup_drvrcmd; 1474 1475 if (!(drvr_cmd->state & MPI3MR_CMD_REPLYVALID)) { 1476 printf(IOCNAME "%s: PELGetSeqNum Failed, No Reply\n", sc->name, __func__); 1477 goto out_failed; 1478 } 1479 pel_reply = (Mpi3PELReply_t *)drvr_cmd->reply; 1480 1481 if (((GET_IOC_STATUS(drvr_cmd->ioc_status)) != MPI3_IOCSTATUS_SUCCESS) 1482 || (le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_SUCCESS)){ 1483 printf(IOCNAME "%s: PELGetSeqNum Failed, IOCStatus(0x%04x) Loginfo(0x%08x) PEL_LogStatus(0x%04x)\n", 1484 sc->name, __func__, GET_IOC_STATUS(drvr_cmd->ioc_status), 1485 drvr_cmd->ioc_loginfo, le16toh(pel_reply->PELogStatus)); 1486 retry = 1; 1487 } 1488 1489 if (retry) { 1490 if (drvr_cmd->retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 1491 drvr_cmd->retry_count++; 1492 printf(IOCNAME "%s : PELGetSeqNUM retry=%d\n", sc->name, 1493 __func__, drvr_cmd->retry_count); 1494 mpi3mr_send_pel_getseq(sc, drvr_cmd); 1495 return; 1496 } 1497 printf(IOCNAME "%s :PELGetSeqNUM failed after all retries\n", 1498 sc->name, __func__); 1499 goto out_failed; 1500 } 1501 1502 sc->newest_seqnum = le32toh(pel_seq_num->Newest) + 1; 1503 drvr_cmd->retry_count = 0; 1504 mpi3mr_issue_pel_wait(sc, drvr_cmd); 1505 return; 1506 out_failed: 1507 sc->pel_wait_pend = 0; 1508 cleanup_drvrcmd: 1509 drvr_cmd->state = MPI3MR_CMD_NOTUSED; 1510 drvr_cmd->callback = NULL; 1511 drvr_cmd->retry_count = 0; 1512 } 1513 1514 static int 1515 mpi3mr_pel_getseq(struct mpi3mr_softc *sc) 1516 { 1517 int rval = 0; 1518 U8 sgl_flags = 0; 1519 Mpi3PELReqActionGetSequenceNumbers_t pel_getseq_req; 1520 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1521 1522 if (sc->reset_in_progress || sc->block_ioctls) { 1523 printf(IOCNAME "%s: IOCTL failed: reset in progress: %u ioctls blocked: %u\n", 1524 sc->name, __func__, sc->reset_in_progress, sc->block_ioctls); 1525 return -1; 1526 } 1527 1528 memset(&pel_getseq_req, 0, sizeof(pel_getseq_req)); 1529 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 1530 sc->pel_cmds.state = MPI3MR_CMD_PENDING; 1531 sc->pel_cmds.is_waiting = 0; 1532 sc->pel_cmds.retry_count = 0; 1533 sc->pel_cmds.ioc_status = 0; 1534 sc->pel_cmds.ioc_loginfo = 0; 1535 sc->pel_cmds.callback = mpi3mr_pel_getseq_complete; 1536 pel_getseq_req.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 1537 pel_getseq_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 1538 pel_getseq_req.Action = MPI3_PEL_ACTION_GET_SEQNUM; 1539 mpi3mr_add_sg_single(&pel_getseq_req.SGL, sgl_flags, 1540 sc->pel_seq_number_sz, sc->pel_seq_number_dma); 1541 1542 if ((rval = mpi3mr_submit_admin_cmd(sc, &pel_getseq_req, sizeof(pel_getseq_req)))) 1543 printf(IOCNAME "%s: Issue IOCTL: Admin Post failed\n", sc->name, __func__); 1544 1545 return rval; 1546 } 1547 1548 int 1549 mpi3mr_pel_abort(struct mpi3mr_softc *sc) 1550 { 1551 int retval = 0; 1552 U16 pel_log_status; 1553 Mpi3PELReqActionAbort_t pel_abort_req; 1554 Mpi3PELReply_t *pel_reply = NULL; 1555 1556 if (sc->reset_in_progress || sc->block_ioctls) { 1557 printf(IOCNAME "%s: IOCTL failed: reset in progress: %u ioctls blocked: %u\n", 1558 sc->name, __func__, sc->reset_in_progress, sc->block_ioctls); 1559 return -1; 1560 } 1561 1562 memset(&pel_abort_req, 0, sizeof(pel_abort_req)); 1563 1564 mtx_lock(&sc->pel_abort_cmd.completion.lock); 1565 if (sc->pel_abort_cmd.state & MPI3MR_CMD_PENDING) { 1566 printf(IOCNAME "%s: PEL Abort command is in use\n", sc->name, __func__); 1567 mtx_unlock(&sc->pel_abort_cmd.completion.lock); 1568 return -1; 1569 } 1570 1571 sc->pel_abort_cmd.state = MPI3MR_CMD_PENDING; 1572 sc->pel_abort_cmd.is_waiting = 1; 1573 sc->pel_abort_cmd.callback = NULL; 1574 pel_abort_req.HostTag = htole16(MPI3MR_HOSTTAG_PELABORT); 1575 pel_abort_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 1576 pel_abort_req.Action = MPI3_PEL_ACTION_ABORT; 1577 pel_abort_req.AbortHostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 1578 1579 sc->pel_abort_requested = 1; 1580 1581 init_completion(&sc->pel_abort_cmd.completion); 1582 retval = mpi3mr_submit_admin_cmd(sc, &pel_abort_req, sizeof(pel_abort_req)); 1583 if (retval) { 1584 printf(IOCNAME "%s: Issue IOCTL: Admin Post failed\n", sc->name, __func__); 1585 sc->pel_abort_requested = 0; 1586 retval = -1; 1587 goto out_unlock; 1588 } 1589 wait_for_completion_timeout(&sc->pel_abort_cmd.completion, MPI3MR_INTADMCMD_TIMEOUT); 1590 1591 if (!(sc->pel_abort_cmd.state & MPI3MR_CMD_COMPLETE)) { 1592 printf(IOCNAME "%s: PEL Abort command timedout\n",sc->name, __func__); 1593 sc->pel_abort_cmd.is_waiting = 0; 1594 retval = -1; 1595 sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; 1596 sc->reset.reason = MPI3MR_RESET_FROM_PELABORT_TIMEOUT; 1597 goto out_unlock; 1598 } 1599 if (((GET_IOC_STATUS(sc->pel_abort_cmd.ioc_status)) != MPI3_IOCSTATUS_SUCCESS) 1600 || (!(sc->pel_abort_cmd.state & MPI3MR_CMD_REPLYVALID))) { 1601 printf(IOCNAME "%s: PEL Abort command failed, ioc_status(0x%04x) log_info(0x%08x)\n", 1602 sc->name, __func__, GET_IOC_STATUS(sc->pel_abort_cmd.ioc_status), 1603 sc->pel_abort_cmd.ioc_loginfo); 1604 retval = -1; 1605 goto out_unlock; 1606 } 1607 1608 pel_reply = (Mpi3PELReply_t *)sc->pel_abort_cmd.reply; 1609 pel_log_status = le16toh(pel_reply->PELogStatus); 1610 if (pel_log_status != MPI3_PEL_STATUS_SUCCESS) { 1611 printf(IOCNAME "%s: PEL abort command failed, pel_status(0x%04x)\n", 1612 sc->name, __func__, pel_log_status); 1613 retval = -1; 1614 } 1615 1616 out_unlock: 1617 mtx_unlock(&sc->pel_abort_cmd.completion.lock); 1618 sc->pel_abort_cmd.state = MPI3MR_CMD_NOTUSED; 1619 return retval; 1620 } 1621 1622 /** 1623 * mpi3mr_pel_enable - Handler for PEL enable 1624 * @sc: Adapter instance reference 1625 * @data_out_buf: User buffer containing PEL enable data 1626 * @data_out_sz: length of the user buffer. 1627 * 1628 * This function is the handler for PEL enable driver IOCTL. 1629 * Validates the application given class and locale and if 1630 * requires aborts the existing PEL wait request and/or issues 1631 * new PEL wait request to the firmware and returns. 1632 * 1633 * Return: 0 on success and proper error codes on failure. 1634 */ 1635 static long 1636 mpi3mr_pel_enable(struct mpi3mr_softc *sc, 1637 void *data_out_buf, U32 data_out_sz) 1638 { 1639 long rval = EINVAL; 1640 U8 tmp_class; 1641 U16 tmp_locale; 1642 struct mpi3mr_ioctl_pel_enable pel_enable; 1643 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1644 1645 1646 if ((data_out_sz != sizeof(pel_enable) || 1647 (pel_enable.pel_class > MPI3_PEL_CLASS_FAULT))) { 1648 printf(IOCNAME "%s: Invalid user pel_enable buffer size %u\n", 1649 sc->name, __func__, data_out_sz); 1650 goto out; 1651 } 1652 memset(&pel_enable, 0, sizeof(pel_enable)); 1653 if (copyin(data_out_buf, &pel_enable, sizeof(pel_enable))) { 1654 printf(IOCNAME "failure at %s() line:%d\n", sc->name, 1655 __func__, __LINE__); 1656 rval = EFAULT; 1657 goto out; 1658 } 1659 if (pel_enable.pel_class > MPI3_PEL_CLASS_FAULT) { 1660 printf(IOCNAME "%s: out of range class %d\n", 1661 sc->name, __func__, pel_enable.pel_class); 1662 goto out; 1663 } 1664 1665 if (sc->pel_wait_pend) { 1666 if ((sc->pel_class <= pel_enable.pel_class) && 1667 !((sc->pel_locale & pel_enable.pel_locale) ^ 1668 pel_enable.pel_locale)) { 1669 rval = 0; 1670 goto out; 1671 } else { 1672 pel_enable.pel_locale |= sc->pel_locale; 1673 if (sc->pel_class < pel_enable.pel_class) 1674 pel_enable.pel_class = sc->pel_class; 1675 1676 if (mpi3mr_pel_abort(sc)) { 1677 printf(IOCNAME "%s: pel_abort failed, status(%ld)\n", 1678 sc->name, __func__, rval); 1679 goto out; 1680 } 1681 } 1682 } 1683 1684 tmp_class = sc->pel_class; 1685 tmp_locale = sc->pel_locale; 1686 sc->pel_class = pel_enable.pel_class; 1687 sc->pel_locale = pel_enable.pel_locale; 1688 sc->pel_wait_pend = 1; 1689 1690 if ((rval = mpi3mr_pel_getseq(sc))) { 1691 sc->pel_class = tmp_class; 1692 sc->pel_locale = tmp_locale; 1693 sc->pel_wait_pend = 0; 1694 printf(IOCNAME "%s: pel get sequence number failed, status(%ld)\n", 1695 sc->name, __func__, rval); 1696 } 1697 1698 out: 1699 return rval; 1700 } 1701 1702 void 1703 mpi3mr_app_save_logdata(struct mpi3mr_softc *sc, char *event_data, 1704 U16 event_data_size) 1705 { 1706 struct mpi3mr_log_data_entry *entry; 1707 U32 index = sc->log_data_buffer_index, sz; 1708 1709 if (!(sc->log_data_buffer)) 1710 return; 1711 1712 entry = (struct mpi3mr_log_data_entry *) 1713 (sc->log_data_buffer + (index * sc->log_data_entry_size)); 1714 entry->valid_entry = 1; 1715 sz = min(sc->log_data_entry_size, event_data_size); 1716 memcpy(entry->data, event_data, sz); 1717 sc->log_data_buffer_index = 1718 ((++index) % MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES); 1719 mpi3mr_app_send_aen(sc); 1720 } 1721 1722 /** 1723 * mpi3mr_get_logdata - Handler for get log data 1724 * @sc: Adapter instance reference 1725 * @data_in_buf: User buffer to copy the logdata entries 1726 * @data_in_sz: length of the user buffer. 1727 * 1728 * This function copies the log data entries to the user buffer 1729 * when log caching is enabled in the driver. 1730 * 1731 * Return: 0 on success and proper error codes on failure 1732 */ 1733 static long 1734 mpi3mr_get_logdata(struct mpi3mr_softc *sc, 1735 void *data_in_buf, U32 data_in_sz) 1736 { 1737 long rval = EINVAL; 1738 U16 num_entries = 0; 1739 U16 entry_sz = sc->log_data_entry_size; 1740 1741 if ((!sc->log_data_buffer) || (data_in_sz < entry_sz)) 1742 return rval; 1743 1744 num_entries = data_in_sz / entry_sz; 1745 if (num_entries > MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES) 1746 num_entries = MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES; 1747 1748 if ((rval = copyout(sc->log_data_buffer, data_in_buf, (num_entries * entry_sz)))) { 1749 printf(IOCNAME "%s: copy to user failed\n", sc->name, __func__); 1750 rval = EFAULT; 1751 } 1752 1753 return rval; 1754 } 1755 1756 /** 1757 * mpi3mr_logdata_enable - Handler for log data enable 1758 * @sc: Adapter instance reference 1759 * @data_in_buf: User buffer to copy the max logdata entry count 1760 * @data_in_sz: length of the user buffer. 1761 * 1762 * This function enables log data caching in the driver if not 1763 * already enabled and return the maximum number of log data 1764 * entries that can be cached in the driver. 1765 * 1766 * Return: 0 on success and proper error codes on failure 1767 */ 1768 static long 1769 mpi3mr_logdata_enable(struct mpi3mr_softc *sc, 1770 void *data_in_buf, U32 data_in_sz) 1771 { 1772 long rval = EINVAL; 1773 struct mpi3mr_ioctl_logdata_enable logdata_enable; 1774 1775 if (data_in_sz < sizeof(logdata_enable)) 1776 return rval; 1777 1778 if (sc->log_data_buffer) 1779 goto copy_data; 1780 1781 sc->log_data_entry_size = (sc->reply_sz - (sizeof(Mpi3EventNotificationReply_t) - 4)) 1782 + MPI3MR_IOCTL_LOGDATA_ENTRY_HEADER_SZ; 1783 1784 sc->log_data_buffer = malloc((MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES * sc->log_data_entry_size), 1785 M_MPI3MR, M_NOWAIT | M_ZERO); 1786 if (!sc->log_data_buffer) { 1787 printf(IOCNAME "%s log data buffer memory allocation failed\n", sc->name, __func__); 1788 return ENOMEM; 1789 } 1790 1791 sc->log_data_buffer_index = 0; 1792 1793 copy_data: 1794 memset(&logdata_enable, 0, sizeof(logdata_enable)); 1795 logdata_enable.max_entries = MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES; 1796 1797 if ((rval = copyout(&logdata_enable, data_in_buf, sizeof(logdata_enable)))) { 1798 printf(IOCNAME "%s: copy to user failed\n", sc->name, __func__); 1799 rval = EFAULT; 1800 } 1801 1802 return rval; 1803 } 1804 1805 /** 1806 * mpi3mr_get_change_count - Get topology change count 1807 * @sc: Adapter instance reference 1808 * @data_in_buf: User buffer to copy the change count 1809 * @data_in_sz: length of the user buffer. 1810 * 1811 * This function copies the toplogy change count provided by the 1812 * driver in events and cached in the driver to the user 1813 * provided buffer for the specific controller. 1814 * 1815 * Return: 0 on success and proper error codes on failure 1816 */ 1817 static long 1818 mpi3mr_get_change_count(struct mpi3mr_softc *sc, 1819 void *data_in_buf, U32 data_in_sz) 1820 { 1821 long rval = EINVAL; 1822 struct mpi3mr_ioctl_chgcnt chg_count; 1823 memset(&chg_count, 0, sizeof(chg_count)); 1824 1825 chg_count.change_count = sc->change_count; 1826 if (data_in_sz >= sizeof(chg_count)) { 1827 if ((rval = copyout(&chg_count, data_in_buf, sizeof(chg_count)))) { 1828 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 1829 __LINE__, __func__); 1830 rval = EFAULT; 1831 } 1832 } 1833 return rval; 1834 } 1835 1836 /** 1837 * mpi3mr_get_alltgtinfo - Get all targets information 1838 * @sc: Adapter instance reference 1839 * @data_in_buf: User buffer to copy the target information 1840 * @data_in_sz: length of the user buffer. 1841 * 1842 * This function copies the driver managed target devices device 1843 * handle, persistent ID, bus ID and taret ID to the user 1844 * provided buffer for the specific controller. This function 1845 * also provides the number of devices managed by the driver for 1846 * the specific controller. 1847 * 1848 * Return: 0 on success and proper error codes on failure 1849 */ 1850 static long 1851 mpi3mr_get_alltgtinfo(struct mpi3mr_softc *sc, 1852 void *data_in_buf, U32 data_in_sz) 1853 { 1854 long rval = EINVAL; 1855 U8 get_count = 0; 1856 U16 i = 0, num_devices = 0; 1857 U32 min_entrylen = 0, kern_entrylen = 0, user_entrylen = 0; 1858 struct mpi3mr_target *tgtdev = NULL; 1859 struct mpi3mr_device_map_info *devmap_info = NULL; 1860 struct mpi3mr_cam_softc *cam_sc = sc->cam_sc; 1861 struct mpi3mr_ioctl_all_tgtinfo *all_tgtinfo = (struct mpi3mr_ioctl_all_tgtinfo *)data_in_buf; 1862 1863 if (data_in_sz < sizeof(uint32_t)) { 1864 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 1865 __LINE__, __func__); 1866 goto out; 1867 } 1868 if (data_in_sz == sizeof(uint32_t)) 1869 get_count = 1; 1870 1871 if (TAILQ_EMPTY(&cam_sc->tgt_list)) { 1872 get_count = 1; 1873 goto copy_usrbuf; 1874 } 1875 1876 mtx_lock_spin(&cam_sc->sc->target_lock); 1877 TAILQ_FOREACH(tgtdev, &cam_sc->tgt_list, tgt_next) { 1878 num_devices++; 1879 } 1880 mtx_unlock_spin(&cam_sc->sc->target_lock); 1881 1882 if (get_count) 1883 goto copy_usrbuf; 1884 1885 kern_entrylen = num_devices * sizeof(*devmap_info); 1886 1887 devmap_info = malloc(kern_entrylen, M_MPI3MR, M_NOWAIT | M_ZERO); 1888 if (!devmap_info) { 1889 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 1890 __LINE__, __func__); 1891 rval = ENOMEM; 1892 goto out; 1893 } 1894 memset((U8*)devmap_info, 0xFF, kern_entrylen); 1895 1896 mtx_lock_spin(&cam_sc->sc->target_lock); 1897 TAILQ_FOREACH(tgtdev, &cam_sc->tgt_list, tgt_next) { 1898 if (i < num_devices) { 1899 devmap_info[i].handle = tgtdev->dev_handle; 1900 devmap_info[i].per_id = tgtdev->per_id; 1901 /*n 1902 * For hidden/ugood device the target_id and bus_id should be 0xFFFFFFFF and 0xFF 1903 */ 1904 if (!tgtdev->exposed_to_os) { 1905 devmap_info[i].target_id = 0xFFFFFFFF; 1906 devmap_info[i].bus_id = 0xFF; 1907 } else { 1908 devmap_info[i].target_id = tgtdev->tid; 1909 devmap_info[i].bus_id = 0; 1910 } 1911 i++; 1912 } 1913 } 1914 num_devices = i; 1915 mtx_unlock_spin(&cam_sc->sc->target_lock); 1916 1917 copy_usrbuf: 1918 if (copyout(&num_devices, &all_tgtinfo->num_devices, sizeof(num_devices))) { 1919 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 1920 __LINE__, __func__); 1921 rval = EFAULT; 1922 goto out; 1923 } 1924 user_entrylen = (data_in_sz - sizeof(uint32_t))/sizeof(*devmap_info); 1925 user_entrylen *= sizeof(*devmap_info); 1926 min_entrylen = min(user_entrylen, kern_entrylen); 1927 if (min_entrylen && (copyout(devmap_info, &all_tgtinfo->dmi, min_entrylen))) { 1928 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1929 __FILE__, __LINE__, __func__); 1930 rval = EFAULT; 1931 goto out; 1932 } 1933 rval = 0; 1934 out: 1935 if (devmap_info) 1936 free(devmap_info, M_MPI3MR); 1937 1938 return rval; 1939 } 1940 1941 /** 1942 * mpi3mr_get_tgtinfo - Get specific target information 1943 * @sc: Adapter instance reference 1944 * @karg: driver ponter to users payload buffer 1945 * 1946 * This function copies the driver managed specific target device 1947 * info like handle, persistent ID, bus ID and taret ID to the user 1948 * provided buffer for the specific controller. 1949 * 1950 * Return: 0 on success and proper error codes on failure 1951 */ 1952 static long 1953 mpi3mr_get_tgtinfo(struct mpi3mr_softc *sc, 1954 struct mpi3mr_ioctl_drvcmd *karg) 1955 { 1956 long rval = EINVAL; 1957 struct mpi3mr_target *tgtdev = NULL; 1958 struct mpi3mr_ioctl_tgtinfo tgtinfo; 1959 1960 memset(&tgtinfo, 0, sizeof(tgtinfo)); 1961 1962 if ((karg->data_out_size != sizeof(struct mpi3mr_ioctl_tgtinfo)) || 1963 (karg->data_in_size != sizeof(struct mpi3mr_ioctl_tgtinfo))) { 1964 printf(IOCNAME "Invalid user tgtinfo buffer size %s() line: %d\n", sc->name, 1965 __func__, __LINE__); 1966 goto out; 1967 } 1968 1969 if (copyin(karg->data_out_buf, &tgtinfo, sizeof(tgtinfo))) { 1970 printf(IOCNAME "failure at %s() line:%d\n", sc->name, 1971 __func__, __LINE__); 1972 rval = EFAULT; 1973 goto out; 1974 } 1975 1976 if ((tgtinfo.bus_id != 0xFF) && (tgtinfo.target_id != 0xFFFFFFFF)) { 1977 if ((tgtinfo.persistent_id != 0xFFFF) || 1978 (tgtinfo.dev_handle != 0xFFFF)) 1979 goto out; 1980 tgtdev = mpi3mr_find_target_by_per_id(sc->cam_sc, tgtinfo.target_id); 1981 } else if (tgtinfo.persistent_id != 0xFFFF) { 1982 if ((tgtinfo.bus_id != 0xFF) || 1983 (tgtinfo.dev_handle !=0xFFFF) || 1984 (tgtinfo.target_id != 0xFFFFFFFF)) 1985 goto out; 1986 tgtdev = mpi3mr_find_target_by_per_id(sc->cam_sc, tgtinfo.persistent_id); 1987 } else if (tgtinfo.dev_handle !=0xFFFF) { 1988 if ((tgtinfo.bus_id != 0xFF) || 1989 (tgtinfo.target_id != 0xFFFFFFFF) || 1990 (tgtinfo.persistent_id != 0xFFFF)) 1991 goto out; 1992 tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, tgtinfo.dev_handle); 1993 } 1994 if (!tgtdev) 1995 goto out; 1996 1997 tgtinfo.target_id = tgtdev->per_id; 1998 tgtinfo.bus_id = 0; 1999 tgtinfo.dev_handle = tgtdev->dev_handle; 2000 tgtinfo.persistent_id = tgtdev->per_id; 2001 tgtinfo.seq_num = 0; 2002 2003 if (copyout(&tgtinfo, karg->data_in_buf, sizeof(tgtinfo))) { 2004 printf(IOCNAME "failure at %s() line:%d\n", sc->name, 2005 __func__, __LINE__); 2006 rval = EFAULT; 2007 } 2008 2009 out: 2010 return rval; 2011 } 2012 2013 /** 2014 * mpi3mr_get_pciinfo - Get PCI info IOCTL handler 2015 * @sc: Adapter instance reference 2016 * @data_in_buf: User buffer to hold adapter information 2017 * @data_in_sz: length of the user buffer. 2018 * 2019 * This function provides the PCI spec information for the 2020 * given controller 2021 * 2022 * Return: 0 on success and proper error codes on failure 2023 */ 2024 static long 2025 mpi3mr_get_pciinfo(struct mpi3mr_softc *sc, 2026 void *data_in_buf, U32 data_in_sz) 2027 { 2028 long rval = EINVAL; 2029 U8 i; 2030 struct mpi3mr_ioctl_pciinfo pciinfo; 2031 memset(&pciinfo, 0, sizeof(pciinfo)); 2032 2033 for (i = 0; i < 64; i++) 2034 pciinfo.config_space[i] = pci_read_config(sc->mpi3mr_dev, (i * 4), 4); 2035 2036 if (data_in_sz >= sizeof(pciinfo)) { 2037 if ((rval = copyout(&pciinfo, data_in_buf, sizeof(pciinfo)))) { 2038 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 2039 __FILE__, __LINE__, __func__); 2040 rval = EFAULT; 2041 } 2042 } 2043 return rval; 2044 } 2045 2046 /** 2047 * mpi3mr_get_adpinfo - Get adapter info IOCTL handler 2048 * @sc: Adapter instance reference 2049 * @data_in_buf: User buffer to hold adapter information 2050 * @data_in_sz: length of the user buffer. 2051 * 2052 * This function provides adapter information for the given 2053 * controller 2054 * 2055 * Return: 0 on success and proper error codes on failure 2056 */ 2057 static long 2058 mpi3mr_get_adpinfo(struct mpi3mr_softc *sc, 2059 void *data_in_buf, U32 data_in_sz) 2060 { 2061 long rval = EINVAL; 2062 struct mpi3mr_ioctl_adpinfo adpinfo; 2063 enum mpi3mr_iocstate ioc_state; 2064 memset(&adpinfo, 0, sizeof(adpinfo)); 2065 2066 adpinfo.adp_type = MPI3MR_IOCTL_ADPTYPE_AVGFAMILY; 2067 adpinfo.pci_dev_id = pci_get_device(sc->mpi3mr_dev); 2068 adpinfo.pci_dev_hw_rev = pci_read_config(sc->mpi3mr_dev, PCIR_REVID, 1); 2069 adpinfo.pci_subsys_dev_id = pci_get_subdevice(sc->mpi3mr_dev); 2070 adpinfo.pci_subsys_ven_id = pci_get_subvendor(sc->mpi3mr_dev); 2071 adpinfo.pci_bus = pci_get_bus(sc->mpi3mr_dev);; 2072 adpinfo.pci_dev = pci_get_slot(sc->mpi3mr_dev); 2073 adpinfo.pci_func = pci_get_function(sc->mpi3mr_dev); 2074 adpinfo.pci_seg_id = pci_get_domain(sc->mpi3mr_dev); 2075 adpinfo.ioctl_ver = MPI3MR_IOCTL_VERSION; 2076 memcpy((U8 *)&adpinfo.driver_info, (U8 *)&sc->driver_info, sizeof(adpinfo.driver_info)); 2077 2078 ioc_state = mpi3mr_get_iocstate(sc); 2079 2080 if (ioc_state == MRIOC_STATE_UNRECOVERABLE) 2081 adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_UNRECOVERABLE; 2082 else if (sc->reset_in_progress || sc->block_ioctls) 2083 adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_IN_RESET; 2084 else if (ioc_state == MRIOC_STATE_FAULT) 2085 adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_FAULT; 2086 else 2087 adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_OPERATIONAL; 2088 2089 if (data_in_sz >= sizeof(adpinfo)) { 2090 if ((rval = copyout(&adpinfo, data_in_buf, sizeof(adpinfo)))) { 2091 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 2092 __FILE__, __LINE__, __func__); 2093 rval = EFAULT; 2094 } 2095 } 2096 return rval; 2097 } 2098 /** 2099 * mpi3mr_app_drvrcmds - Driver IOCTL handler 2100 * @dev: char device 2101 * @cmd: IOCTL command 2102 * @arg: User data payload buffer for the IOCTL 2103 * @flag: flags 2104 * @thread: threads 2105 * 2106 * This function is the top level handler for driver commands, 2107 * this does basic validation of the buffer and identifies the 2108 * opcode and switches to correct sub handler. 2109 * 2110 * Return: 0 on success and proper error codes on failure 2111 */ 2112 2113 static int 2114 mpi3mr_app_drvrcmds(struct cdev *dev, u_long cmd, 2115 void *uarg, int flag, struct thread *td) 2116 { 2117 long rval = EINVAL; 2118 struct mpi3mr_softc *sc = NULL; 2119 struct mpi3mr_ioctl_drvcmd *karg = (struct mpi3mr_ioctl_drvcmd *)uarg; 2120 2121 sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); 2122 if (!sc) 2123 return ENODEV; 2124 2125 mtx_lock(&sc->ioctl_cmds.completion.lock); 2126 switch (karg->opcode) { 2127 case MPI3MR_DRVRIOCTL_OPCODE_ADPINFO: 2128 rval = mpi3mr_get_adpinfo(sc, karg->data_in_buf, karg->data_in_size); 2129 break; 2130 case MPI3MR_DRVRIOCTL_OPCODE_GETPCIINFO: 2131 rval = mpi3mr_get_pciinfo(sc, karg->data_in_buf, karg->data_in_size); 2132 break; 2133 case MPI3MR_DRVRIOCTL_OPCODE_TGTDEVINFO: 2134 rval = mpi3mr_get_tgtinfo(sc, karg); 2135 break; 2136 case MPI3MR_DRVRIOCTL_OPCODE_ALLTGTDEVINFO: 2137 rval = mpi3mr_get_alltgtinfo(sc, karg->data_in_buf, karg->data_in_size); 2138 break; 2139 case MPI3MR_DRVRIOCTL_OPCODE_GETCHGCNT: 2140 rval = mpi3mr_get_change_count(sc, karg->data_in_buf, karg->data_in_size); 2141 break; 2142 case MPI3MR_DRVRIOCTL_OPCODE_LOGDATAENABLE: 2143 rval = mpi3mr_logdata_enable(sc, karg->data_in_buf, karg->data_in_size); 2144 break; 2145 case MPI3MR_DRVRIOCTL_OPCODE_GETLOGDATA: 2146 rval = mpi3mr_get_logdata(sc, karg->data_in_buf, karg->data_in_size); 2147 break; 2148 case MPI3MR_DRVRIOCTL_OPCODE_PELENABLE: 2149 rval = mpi3mr_pel_enable(sc, karg->data_out_buf, karg->data_out_size); 2150 break; 2151 case MPI3MR_DRVRIOCTL_OPCODE_ADPRESET: 2152 rval = mpi3mr_adp_reset(sc, karg->data_out_buf, karg->data_out_size); 2153 break; 2154 case MPI3MR_DRVRIOCTL_OPCODE_UNKNOWN: 2155 default: 2156 printf("Unsupported drvr ioctl opcode 0x%x\n", karg->opcode); 2157 break; 2158 } 2159 mtx_unlock(&sc->ioctl_cmds.completion.lock); 2160 return rval; 2161 } 2162 /** 2163 * mpi3mr_ioctl - IOCTL Handler 2164 * @dev: char device 2165 * @cmd: IOCTL command 2166 * @arg: User data payload buffer for the IOCTL 2167 * @flag: flags 2168 * @thread: threads 2169 * 2170 * This is the IOCTL entry point which checks the command type and 2171 * executes proper sub handler specific for the command. 2172 * 2173 * Return: 0 on success and proper error codes on failure 2174 */ 2175 static int 2176 mpi3mr_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2177 { 2178 int rval = EINVAL; 2179 2180 struct mpi3mr_softc *sc = NULL; 2181 struct mpi3mr_ioctl_drvcmd *karg = (struct mpi3mr_ioctl_drvcmd *)arg; 2182 2183 sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); 2184 2185 if (!sc) 2186 return ENODEV; 2187 2188 mpi3mr_atomic_inc(&sc->pend_ioctls); 2189 2190 2191 if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) { 2192 mpi3mr_dprint(sc, MPI3MR_INFO, 2193 "Return back IOCTL, shutdown is in progress\n"); 2194 mpi3mr_atomic_dec(&sc->pend_ioctls); 2195 return ENODEV; 2196 } 2197 2198 switch (cmd) { 2199 case MPI3MRDRVCMD: 2200 rval = mpi3mr_app_drvrcmds(dev, cmd, arg, flag, td); 2201 break; 2202 case MPI3MRMPTCMD: 2203 mtx_lock(&sc->ioctl_cmds.completion.lock); 2204 rval = mpi3mr_app_mptcmds(dev, cmd, arg, flag, td); 2205 mtx_unlock(&sc->ioctl_cmds.completion.lock); 2206 break; 2207 default: 2208 printf("%s:Unsupported ioctl cmd (0x%08lx)\n", MPI3MR_DRIVER_NAME, cmd); 2209 break; 2210 } 2211 2212 mpi3mr_atomic_dec(&sc->pend_ioctls); 2213 2214 return rval; 2215 } 2216