1 /* 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2020-2023, Broadcom Inc. All rights reserved. 5 * Support: <fbsd-storage-driver.pdl@broadcom.com> 6 * 7 * Authors: Sumit Saxena <sumit.saxena@broadcom.com> 8 * Chandrakanth Patil <chandrakanth.patil@broadcom.com> 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 BUS_SPACE_MAXADDR_32BIT, /* 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 0); 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 548 if (dma_buffers->kern_buf_len % MPI3MR_IOCTL_SGE_SIZE) 549 needed_desc++; 550 551 if ((needed_desc + desc_count) > MPI3MR_NUM_IOCTL_SGE) { 552 printf("%s: DMA descriptor mapping error %d:%d:%d\n", 553 __func__, needed_desc, desc_count, MPI3MR_NUM_IOCTL_SGE); 554 return -1; 555 } 556 557 dma_buffers->dma_desc = malloc(sizeof(*dma_buffers->dma_desc) * needed_desc, 558 M_MPI3MR, M_NOWAIT | M_ZERO); 559 if (!dma_buffers->dma_desc) 560 return -1; 561 562 for (i = 0; i < needed_desc; i++, desc_count++) { 563 564 dma_buffers->dma_desc[i].addr = sc->ioctl_sge[desc_count].addr; 565 dma_buffers->dma_desc[i].dma_addr = sc->ioctl_sge[desc_count].dma_addr; 566 567 if (buf_len < sc->ioctl_sge[desc_count].size) 568 dma_buffers->dma_desc[i].size = buf_len; 569 else 570 dma_buffers->dma_desc[i].size = sc->ioctl_sge[desc_count].size; 571 572 buf_len -= dma_buffers->dma_desc[i].size; 573 memset(dma_buffers->dma_desc[i].addr, 0, sc->ioctl_sge[desc_count].size); 574 575 if (dma_buffers->data_dir == MPI3MR_APP_DDO) { 576 copyin(((U8 *)dma_buffers->user_buf + copied_len), 577 dma_buffers->dma_desc[i].addr, 578 dma_buffers->dma_desc[i].size); 579 copied_len += dma_buffers->dma_desc[i].size; 580 } 581 } 582 583 dma_buffers->num_dma_desc = needed_desc; 584 585 return 0; 586 } 587 588 static unsigned int 589 mpi3mr_app_get_nvme_data_fmt(Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request) 590 { 591 U8 format = 0; 592 593 format = ((nvme_encap_request->Command[0] & 0xc000) >> 14); 594 return format; 595 } 596 597 static inline U16 mpi3mr_total_num_ioctl_sges(struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, 598 U8 bufcnt) 599 { 600 U16 i, sge_count = 0; 601 for (i=0; i < bufcnt; i++, dma_buffers++) { 602 if ((dma_buffers->data_dir == MPI3MR_APP_DDN) || 603 dma_buffers->kern_buf) 604 continue; 605 sge_count += dma_buffers->num_dma_desc; 606 if (!dma_buffers->num_dma_desc) 607 sge_count++; 608 } 609 return sge_count; 610 } 611 612 static int 613 mpi3mr_app_construct_sgl(struct mpi3mr_softc *sc, U8 *mpi_request, U32 sgl_offset, 614 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, 615 U8 bufcnt, U8 is_rmc, U8 is_rmr, U8 num_datasges) 616 { 617 U8 *sgl = (mpi_request + sgl_offset), count = 0; 618 Mpi3RequestHeader_t *mpi_header = (Mpi3RequestHeader_t *)mpi_request; 619 Mpi3MgmtPassthroughRequest_t *rmgmt_req = 620 (Mpi3MgmtPassthroughRequest_t *)mpi_request; 621 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; 622 U8 flag, sgl_flags, sgl_flags_eob, sgl_flags_last, last_chain_sgl_flags; 623 U16 available_sges, i, sges_needed; 624 U32 sge_element_size = sizeof(struct _MPI3_SGE_COMMON); 625 bool chain_used = false; 626 627 sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | 628 MPI3_SGE_FLAGS_DLAS_SYSTEM ; 629 sgl_flags_eob = sgl_flags | MPI3_SGE_FLAGS_END_OF_BUFFER; 630 sgl_flags_last = sgl_flags_eob | MPI3_SGE_FLAGS_END_OF_LIST; 631 last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | 632 MPI3_SGE_FLAGS_DLAS_SYSTEM; 633 634 sges_needed = mpi3mr_total_num_ioctl_sges(dma_buffers, bufcnt); 635 636 if (is_rmc) { 637 mpi3mr_add_sg_single(&rmgmt_req->CommandSGL, 638 sgl_flags_last, dma_buff->kern_buf_len, 639 dma_buff->kern_buf_dma); 640 sgl = (U8 *) dma_buff->kern_buf + dma_buff->user_buf_len; 641 available_sges = (dma_buff->kern_buf_len - 642 dma_buff->user_buf_len) / sge_element_size; 643 if (sges_needed > available_sges) 644 return -1; 645 chain_used = true; 646 dma_buff++; 647 count++; 648 if (is_rmr) { 649 mpi3mr_add_sg_single(&rmgmt_req->ResponseSGL, 650 sgl_flags_last, dma_buff->kern_buf_len, 651 dma_buff->kern_buf_dma); 652 dma_buff++; 653 count++; 654 } else 655 mpi3mr_build_zero_len_sge( 656 &rmgmt_req->ResponseSGL); 657 if (num_datasges) { 658 i = 0; 659 goto build_sges; 660 } 661 } else { 662 if (sgl_offset >= MPI3MR_AREQ_FRAME_SZ) 663 return -1; 664 available_sges = (MPI3MR_AREQ_FRAME_SZ - sgl_offset) / 665 sge_element_size; 666 if (!available_sges) 667 return -1; 668 } 669 670 if (!num_datasges) { 671 mpi3mr_build_zero_len_sge(sgl); 672 return 0; 673 } 674 675 if (mpi_header->Function == MPI3_FUNCTION_SMP_PASSTHROUGH) { 676 if ((sges_needed > 2) || (sges_needed > available_sges)) 677 return -1; 678 for (; count < bufcnt; count++, dma_buff++) { 679 if ((dma_buff->data_dir == MPI3MR_APP_DDN) || 680 !dma_buff->num_dma_desc) 681 continue; 682 mpi3mr_add_sg_single(sgl, sgl_flags_last, 683 dma_buff->dma_desc[0].size, 684 dma_buff->dma_desc[0].dma_addr); 685 sgl += sge_element_size; 686 } 687 return 0; 688 } 689 i = 0; 690 691 build_sges: 692 for (; count < bufcnt; count++, dma_buff++) { 693 if (dma_buff->data_dir == MPI3MR_APP_DDN) 694 continue; 695 if (!dma_buff->num_dma_desc) { 696 if (chain_used && !available_sges) 697 return -1; 698 if (!chain_used && (available_sges == 1) && 699 (sges_needed > 1)) 700 goto setup_chain; 701 flag = sgl_flags_eob; 702 if (num_datasges == 1) 703 flag = sgl_flags_last; 704 mpi3mr_add_sg_single(sgl, flag, 0, 0); 705 sgl += sge_element_size; 706 available_sges--; 707 sges_needed--; 708 num_datasges--; 709 continue; 710 } 711 for (; i < dma_buff->num_dma_desc; i++) { 712 if (chain_used && !available_sges) 713 return -1; 714 if (!chain_used && (available_sges == 1) && 715 (sges_needed > 1)) 716 goto setup_chain; 717 flag = sgl_flags; 718 if (i == (dma_buff->num_dma_desc - 1)) { 719 if (num_datasges == 1) 720 flag = sgl_flags_last; 721 else 722 flag = sgl_flags_eob; 723 } 724 725 mpi3mr_add_sg_single(sgl, flag, 726 dma_buff->dma_desc[i].size, 727 dma_buff->dma_desc[i].dma_addr); 728 sgl += sge_element_size; 729 available_sges--; 730 sges_needed--; 731 } 732 num_datasges--; 733 i = 0; 734 } 735 return 0; 736 737 setup_chain: 738 available_sges = sc->ioctl_chain_sge.size / sge_element_size; 739 if (sges_needed > available_sges) 740 return -1; 741 mpi3mr_add_sg_single(sgl, last_chain_sgl_flags, 742 (sges_needed * sge_element_size), sc->ioctl_chain_sge.dma_addr); 743 memset(sc->ioctl_chain_sge.addr, 0, sc->ioctl_chain_sge.size); 744 sgl = (U8 *)sc->ioctl_chain_sge.addr; 745 chain_used = true; 746 goto build_sges; 747 } 748 749 750 /** 751 * mpi3mr_app_mptcmds - MPI Pass through IOCTL handler 752 * @dev: char device 753 * @cmd: IOCTL command 754 * @arg: User data payload buffer for the IOCTL 755 * @flag: flags 756 * @thread: threads 757 * 758 * This function is the top level handler for MPI Pass through 759 * IOCTL, this does basic validation of the input data buffers, 760 * identifies the given buffer types and MPI command, allocates 761 * DMAable memory for user given buffers, construstcs SGL 762 * properly and passes the command to the firmware. 763 * 764 * Once the MPI command is completed the driver copies the data 765 * if any and reply, sense information to user provided buffers. 766 * If the command is timed out then issues controller reset 767 * prior to returning. 768 * 769 * Return: 0 on success and proper error codes on failure 770 */ 771 static long 772 mpi3mr_app_mptcmds(struct cdev *dev, u_long cmd, void *uarg, 773 int flag, struct thread *td) 774 { 775 long rval = EINVAL; 776 U8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0, din_cnt = 0, dout_cnt = 0; 777 U8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF; 778 U16 desc_count = 0; 779 U8 nvme_fmt = 0; 780 U32 tmplen = 0, erbsz = MPI3MR_SENSEBUF_SZ, din_sz = 0, dout_sz = 0; 781 U8 *kern_erb = NULL; 782 U8 *mpi_request = NULL; 783 Mpi3RequestHeader_t *mpi_header = NULL; 784 Mpi3PELReqActionGetCount_t *pel = NULL; 785 Mpi3StatusReplyDescriptor_t *status_desc = NULL; 786 struct mpi3mr_softc *sc = NULL; 787 struct mpi3mr_ioctl_buf_entry_list *buffer_list = NULL; 788 struct mpi3mr_buf_entry *buf_entries = NULL; 789 struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers = NULL, *dma_buff = NULL; 790 struct mpi3mr_ioctl_mpirepbuf *mpirepbuf = NULL; 791 struct mpi3mr_ioctl_mptcmd *karg = (struct mpi3mr_ioctl_mptcmd *)uarg; 792 793 794 sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); 795 if (!sc) 796 return ENODEV; 797 798 if (!sc->ioctl_sges_allocated) { 799 printf("%s: DMA memory was not allocated\n", __func__); 800 return ENOMEM; 801 } 802 803 if (karg->timeout < MPI3MR_IOCTL_DEFAULT_TIMEOUT) 804 karg->timeout = MPI3MR_IOCTL_DEFAULT_TIMEOUT; 805 806 if (!karg->mpi_msg_size || !karg->buf_entry_list_size) { 807 printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 808 __func__, __LINE__); 809 return rval; 810 } 811 if ((karg->mpi_msg_size * 4) > MPI3MR_AREQ_FRAME_SZ) { 812 printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 813 __func__, __LINE__); 814 return rval; 815 } 816 817 mpi_request = malloc(MPI3MR_AREQ_FRAME_SZ, M_MPI3MR, M_NOWAIT | M_ZERO); 818 if (!mpi_request) { 819 printf(IOCNAME "%s: memory allocation failed for mpi_request\n", sc->name, 820 __func__); 821 return ENOMEM; 822 } 823 824 mpi_header = (Mpi3RequestHeader_t *)mpi_request; 825 pel = (Mpi3PELReqActionGetCount_t *)mpi_request; 826 if (copyin(karg->mpi_msg_buf, mpi_request, (karg->mpi_msg_size * 4))) { 827 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 828 __FILE__, __LINE__, __func__); 829 rval = EFAULT; 830 goto out; 831 } 832 833 buffer_list = malloc(karg->buf_entry_list_size, M_MPI3MR, M_NOWAIT | M_ZERO); 834 if (!buffer_list) { 835 printf(IOCNAME "%s: memory allocation failed for buffer_list\n", sc->name, 836 __func__); 837 rval = ENOMEM; 838 goto out; 839 } 840 if (copyin(karg->buf_entry_list, buffer_list, karg->buf_entry_list_size)) { 841 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 842 __FILE__, __LINE__, __func__); 843 rval = EFAULT; 844 goto out; 845 } 846 if (!buffer_list->num_of_buf_entries) { 847 printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 848 __func__, __LINE__); 849 rval = EINVAL; 850 goto out; 851 } 852 bufcnt = buffer_list->num_of_buf_entries; 853 dma_buffers = malloc((sizeof(*dma_buffers) * bufcnt), M_MPI3MR, M_NOWAIT | M_ZERO); 854 if (!dma_buffers) { 855 printf(IOCNAME "%s: memory allocation failed for dma_buffers\n", sc->name, 856 __func__); 857 rval = ENOMEM; 858 goto out; 859 } 860 buf_entries = buffer_list->buf_entry; 861 dma_buff = dma_buffers; 862 for (count = 0; count < bufcnt; count++, buf_entries++, dma_buff++) { 863 memset(dma_buff, 0, sizeof(*dma_buff)); 864 dma_buff->user_buf = buf_entries->buffer; 865 dma_buff->user_buf_len = buf_entries->buf_len; 866 867 switch (buf_entries->buf_type) { 868 case MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_CMD: 869 is_rmcb = 1; 870 if ((count != 0) || !buf_entries->buf_len) 871 invalid_be = 1; 872 dma_buff->data_dir = MPI3MR_APP_DDO; 873 break; 874 case MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_RESP: 875 is_rmrb = 1; 876 if (count != 1 || !is_rmcb || !buf_entries->buf_len) 877 invalid_be = 1; 878 dma_buff->data_dir = MPI3MR_APP_DDI; 879 break; 880 case MPI3MR_IOCTL_BUFTYPE_DATA_IN: 881 din_sz = dma_buff->user_buf_len; 882 din_cnt++; 883 if ((din_cnt > 1) && !is_rmcb) 884 invalid_be = 1; 885 dma_buff->data_dir = MPI3MR_APP_DDI; 886 break; 887 case MPI3MR_IOCTL_BUFTYPE_DATA_OUT: 888 dout_sz = dma_buff->user_buf_len; 889 dout_cnt++; 890 if ((dout_cnt > 1) && !is_rmcb) 891 invalid_be = 1; 892 dma_buff->data_dir = MPI3MR_APP_DDO; 893 break; 894 case MPI3MR_IOCTL_BUFTYPE_MPI_REPLY: 895 mpirep_offset = count; 896 dma_buff->data_dir = MPI3MR_APP_DDN; 897 if (!buf_entries->buf_len) 898 invalid_be = 1; 899 break; 900 case MPI3MR_IOCTL_BUFTYPE_ERR_RESPONSE: 901 erb_offset = count; 902 dma_buff->data_dir = MPI3MR_APP_DDN; 903 if (!buf_entries->buf_len) 904 invalid_be = 1; 905 break; 906 default: 907 invalid_be = 1; 908 break; 909 } 910 if (invalid_be) 911 break; 912 } 913 if (invalid_be) { 914 printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 915 __func__, __LINE__); 916 rval = EINVAL; 917 goto out; 918 } 919 920 if (is_rmcb && ((din_sz + dout_sz) > MPI3MR_MAX_IOCTL_TRANSFER_SIZE)) { 921 printf("%s:%d: invalid data transfer size passed for function 0x%x" 922 "din_sz = %d, dout_size = %d\n", __func__, __LINE__, 923 mpi_header->Function, din_sz, dout_sz); 924 rval = EINVAL; 925 goto out; 926 } 927 928 if ((din_sz > MPI3MR_MAX_IOCTL_TRANSFER_SIZE) || 929 (dout_sz > MPI3MR_MAX_IOCTL_TRANSFER_SIZE)) { 930 printf("%s:%d: invalid data transfer size passed for function 0x%x" 931 "din_size=%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 (mpi_header->Function == MPI3_FUNCTION_SMP_PASSTHROUGH) { 938 if ((din_sz > MPI3MR_IOCTL_SGE_SIZE) || 939 (dout_sz > MPI3MR_IOCTL_SGE_SIZE)) { 940 printf("%s:%d: invalid message size passed:%d:%d:%d:%d\n", 941 __func__, __LINE__, din_cnt, dout_cnt, din_sz, dout_sz); 942 rval = EINVAL; 943 goto out; 944 } 945 } 946 947 dma_buff = dma_buffers; 948 for (count = 0; count < bufcnt; count++, dma_buff++) { 949 950 dma_buff->kern_buf_len = dma_buff->user_buf_len; 951 952 if (is_rmcb && !count) { 953 dma_buff->kern_buf = sc->ioctl_chain_sge.addr; 954 dma_buff->kern_buf_len = sc->ioctl_chain_sge.size; 955 dma_buff->kern_buf_dma = sc->ioctl_chain_sge.dma_addr; 956 dma_buff->dma_desc = NULL; 957 dma_buff->num_dma_desc = 0; 958 memset(dma_buff->kern_buf, 0, dma_buff->kern_buf_len); 959 tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); 960 if (copyin(dma_buff->user_buf, dma_buff->kern_buf, tmplen)) { 961 mpi3mr_dprint(sc, MPI3MR_ERROR, "failure at %s() line: %d", 962 __func__, __LINE__); 963 rval = EFAULT; 964 goto out; 965 } 966 } else if (is_rmrb && (count == 1)) { 967 dma_buff->kern_buf = sc->ioctl_resp_sge.addr; 968 dma_buff->kern_buf_len = sc->ioctl_resp_sge.size; 969 dma_buff->kern_buf_dma = sc->ioctl_resp_sge.dma_addr; 970 dma_buff->dma_desc = NULL; 971 dma_buff->num_dma_desc = 0; 972 memset(dma_buff->kern_buf, 0, dma_buff->kern_buf_len); 973 tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); 974 dma_buff->kern_buf_len = tmplen; 975 } else { 976 if (!dma_buff->kern_buf_len) 977 continue; 978 if (mpi3mr_map_data_buffer_dma(sc, dma_buff, desc_count)) { 979 rval = ENOMEM; 980 mpi3mr_dprint(sc, MPI3MR_ERROR, "mapping data buffers failed" 981 "at %s() line: %d\n", __func__, __LINE__); 982 goto out; 983 } 984 desc_count += dma_buff->num_dma_desc; 985 } 986 } 987 988 if (erb_offset != 0xFF) { 989 kern_erb = malloc(erbsz, M_MPI3MR, M_NOWAIT | M_ZERO); 990 if (!kern_erb) { 991 printf(IOCNAME "%s:%d Cannot allocate memory for sense buffer\n", sc->name, 992 __func__, __LINE__); 993 rval = ENOMEM; 994 goto out; 995 } 996 } 997 998 if (sc->ioctl_cmds.state & MPI3MR_CMD_PENDING) { 999 printf(IOCNAME "Issue IOCTL: Ioctl command is in use/previous command is pending\n", 1000 sc->name); 1001 rval = EAGAIN; 1002 goto out; 1003 } 1004 1005 if (sc->unrecoverable) { 1006 printf(IOCNAME "Issue IOCTL: controller is in unrecoverable state\n", sc->name); 1007 rval = EFAULT; 1008 goto out; 1009 } 1010 1011 if (sc->reset_in_progress) { 1012 printf(IOCNAME "Issue IOCTL: reset in progress\n", sc->name); 1013 rval = EAGAIN; 1014 goto out; 1015 } 1016 if (sc->block_ioctls) { 1017 printf(IOCNAME "Issue IOCTL: IOCTLs are blocked\n", sc->name); 1018 rval = EAGAIN; 1019 goto out; 1020 } 1021 1022 if (mpi_header->Function != MPI3_FUNCTION_NVME_ENCAPSULATED) { 1023 if (mpi3mr_app_construct_sgl(sc, mpi_request, (karg->mpi_msg_size * 4), dma_buffers, 1024 bufcnt, is_rmcb, is_rmrb, (dout_cnt + din_cnt))) { 1025 printf(IOCNAME "Issue IOCTL: sgl build failed\n", sc->name); 1026 rval = EAGAIN; 1027 goto out; 1028 } 1029 1030 } else { 1031 nvme_fmt = mpi3mr_app_get_nvme_data_fmt( 1032 (Mpi3NVMeEncapsulatedRequest_t *)mpi_request); 1033 if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_PRP) { 1034 if (mpi3mr_app_build_nvme_prp(sc, 1035 (Mpi3NVMeEncapsulatedRequest_t *) mpi_request, 1036 dma_buffers, bufcnt)) { 1037 rval = ENOMEM; 1038 goto out; 1039 } 1040 } else if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL1 || 1041 nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL2) { 1042 if (mpi3mr_app_construct_nvme_sgl(sc, (Mpi3NVMeEncapsulatedRequest_t *) mpi_request, 1043 dma_buffers, bufcnt)) { 1044 rval = EINVAL; 1045 goto out; 1046 } 1047 } else { 1048 printf(IOCNAME "%s: Invalid NVMe Command Format\n", sc->name, 1049 __func__); 1050 rval = EINVAL; 1051 goto out; 1052 } 1053 } 1054 1055 sc->ioctl_cmds.state = MPI3MR_CMD_PENDING; 1056 sc->ioctl_cmds.is_waiting = 1; 1057 sc->ioctl_cmds.callback = NULL; 1058 sc->ioctl_cmds.is_senseprst = 0; 1059 sc->ioctl_cmds.sensebuf = kern_erb; 1060 memset((sc->ioctl_cmds.reply), 0, sc->reply_sz); 1061 mpi_header->HostTag = MPI3MR_HOSTTAG_IOCTLCMDS; 1062 init_completion(&sc->ioctl_cmds.completion); 1063 rval = mpi3mr_submit_admin_cmd(sc, mpi_request, MPI3MR_AREQ_FRAME_SZ); 1064 if (rval) { 1065 printf(IOCNAME "Issue IOCTL: Admin Post failed\n", sc->name); 1066 goto out_failed; 1067 } 1068 wait_for_completion_timeout(&sc->ioctl_cmds.completion, karg->timeout); 1069 1070 if (!(sc->ioctl_cmds.state & MPI3MR_CMD_COMPLETE)) { 1071 sc->ioctl_cmds.is_waiting = 0; 1072 printf(IOCNAME "Issue IOCTL: command timed out\n", sc->name); 1073 rval = EAGAIN; 1074 if (sc->ioctl_cmds.state & MPI3MR_CMD_RESET) 1075 goto out_failed; 1076 1077 sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; 1078 sc->reset.reason = MPI3MR_RESET_FROM_IOCTL_TIMEOUT; 1079 goto out_failed; 1080 } 1081 1082 if (sc->nvme_encap_prp_list && sc->nvme_encap_prp_list_dma) { 1083 bus_dmamap_unload(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap); 1084 bus_dmamem_free(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list, sc->nvme_encap_prp_list_dma_dmamap); 1085 bus_dma_tag_destroy(sc->nvme_encap_prp_list_dmatag); 1086 sc->nvme_encap_prp_list = NULL; 1087 } 1088 1089 if (((sc->ioctl_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 1090 != MPI3_IOCSTATUS_SUCCESS) && 1091 (sc->mpi3mr_debug & MPI3MR_DEBUG_IOCTL)) { 1092 printf(IOCNAME "Issue IOCTL: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n", sc->name, 1093 (sc->ioctl_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 1094 sc->ioctl_cmds.ioc_loginfo); 1095 } 1096 1097 if ((mpirep_offset != 0xFF) && 1098 dma_buffers[mpirep_offset].user_buf_len) { 1099 dma_buff = &dma_buffers[mpirep_offset]; 1100 dma_buff->kern_buf_len = (sizeof(*mpirepbuf) - 1 + 1101 sc->reply_sz); 1102 mpirepbuf = malloc(dma_buff->kern_buf_len, M_MPI3MR, M_NOWAIT | M_ZERO); 1103 1104 if (!mpirepbuf) { 1105 printf(IOCNAME "%s: failed obtaining a memory for mpi reply\n", sc->name, 1106 __func__); 1107 rval = ENOMEM; 1108 goto out_failed; 1109 } 1110 if (sc->ioctl_cmds.state & MPI3MR_CMD_REPLYVALID) { 1111 mpirepbuf->mpirep_type = 1112 MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_ADDRESS; 1113 memcpy(mpirepbuf->repbuf, sc->ioctl_cmds.reply, sc->reply_sz); 1114 } else { 1115 mpirepbuf->mpirep_type = 1116 MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_STATUS; 1117 status_desc = (Mpi3StatusReplyDescriptor_t *) 1118 mpirepbuf->repbuf; 1119 status_desc->IOCStatus = sc->ioctl_cmds.ioc_status; 1120 status_desc->IOCLogInfo = sc->ioctl_cmds.ioc_loginfo; 1121 } 1122 tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); 1123 if (copyout(mpirepbuf, dma_buff->user_buf, tmplen)) { 1124 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1125 __FILE__, __LINE__, __func__); 1126 rval = EFAULT; 1127 goto out_failed; 1128 } 1129 } 1130 1131 if (erb_offset != 0xFF && sc->ioctl_cmds.sensebuf && 1132 sc->ioctl_cmds.is_senseprst) { 1133 dma_buff = &dma_buffers[erb_offset]; 1134 tmplen = min(erbsz, dma_buff->user_buf_len); 1135 if (copyout(kern_erb, dma_buff->user_buf, tmplen)) { 1136 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1137 __FILE__, __LINE__, __func__); 1138 rval = EFAULT; 1139 goto out_failed; 1140 } 1141 } 1142 1143 dma_buff = dma_buffers; 1144 for (count = 0; count < bufcnt; count++, dma_buff++) { 1145 if ((count == 1) && is_rmrb) { 1146 if (copyout(dma_buff->kern_buf, dma_buff->user_buf,dma_buff->kern_buf_len)) { 1147 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1148 __FILE__, __LINE__, __func__); 1149 rval = EFAULT; 1150 goto out_failed; 1151 } 1152 } else if (dma_buff->data_dir == MPI3MR_APP_DDI) { 1153 tmplen = 0; 1154 for (desc_count = 0; desc_count < dma_buff->num_dma_desc; desc_count++) { 1155 if (copyout(dma_buff->dma_desc[desc_count].addr, 1156 (U8 *)dma_buff->user_buf+tmplen, 1157 dma_buff->dma_desc[desc_count].size)) { 1158 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1159 __FILE__, __LINE__, __func__); 1160 rval = EFAULT; 1161 goto out_failed; 1162 } 1163 tmplen += dma_buff->dma_desc[desc_count].size; 1164 } 1165 } 1166 } 1167 1168 if ((pel->Function == MPI3_FUNCTION_PERSISTENT_EVENT_LOG) && 1169 (pel->Action == MPI3_PEL_ACTION_GET_COUNT)) 1170 sc->mpi3mr_aen_triggered = 0; 1171 1172 out_failed: 1173 sc->ioctl_cmds.is_senseprst = 0; 1174 sc->ioctl_cmds.sensebuf = NULL; 1175 sc->ioctl_cmds.state = MPI3MR_CMD_NOTUSED; 1176 out: 1177 if (kern_erb) 1178 free(kern_erb, M_MPI3MR); 1179 if (buffer_list) 1180 free(buffer_list, M_MPI3MR); 1181 if (mpi_request) 1182 free(mpi_request, M_MPI3MR); 1183 if (dma_buffers) { 1184 dma_buff = dma_buffers; 1185 for (count = 0; count < bufcnt; count++, dma_buff++) { 1186 free(dma_buff->dma_desc, M_MPI3MR); 1187 } 1188 free(dma_buffers, M_MPI3MR); 1189 } 1190 if (mpirepbuf) 1191 free(mpirepbuf, M_MPI3MR); 1192 return rval; 1193 } 1194 1195 /** 1196 * mpi3mr_soft_reset_from_app - Trigger controller reset 1197 * @sc: Adapter instance reference 1198 * 1199 * This function triggers the controller reset from the 1200 * watchdog context and wait for it to complete. It will 1201 * come out of wait upon completion or timeout exaustion. 1202 * 1203 * Return: 0 on success and proper error codes on failure 1204 */ 1205 static long 1206 mpi3mr_soft_reset_from_app(struct mpi3mr_softc *sc) 1207 { 1208 1209 U32 timeout; 1210 1211 /* if reset is not in progress, trigger soft reset from watchdog context */ 1212 if (!sc->reset_in_progress) { 1213 sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; 1214 sc->reset.reason = MPI3MR_RESET_FROM_IOCTL; 1215 1216 /* Wait for soft reset to start */ 1217 timeout = 50; 1218 while (timeout--) { 1219 if (sc->reset_in_progress == 1) 1220 break; 1221 DELAY(100 * 1000); 1222 } 1223 if (!timeout) 1224 return EFAULT; 1225 } 1226 1227 /* Wait for soft reset to complete */ 1228 int i = 0; 1229 timeout = sc->ready_timeout; 1230 while (timeout--) { 1231 if (sc->reset_in_progress == 0) 1232 break; 1233 i++; 1234 if (!(i % 5)) { 1235 mpi3mr_dprint(sc, MPI3MR_INFO, 1236 "[%2ds]waiting for controller reset to be finished from %s\n", i, __func__); 1237 } 1238 DELAY(1000 * 1000); 1239 } 1240 1241 /* 1242 * In case of soft reset failure or not completed within stipulated time, 1243 * fail back to application. 1244 */ 1245 if ((!timeout || sc->reset.status)) 1246 return EFAULT; 1247 1248 return 0; 1249 } 1250 1251 1252 /** 1253 * mpi3mr_adp_reset - Issue controller reset 1254 * @sc: Adapter instance reference 1255 * @data_out_buf: User buffer with reset type 1256 * @data_out_sz: length of the user buffer. 1257 * 1258 * This function identifies the user provided reset type and 1259 * issues approporiate reset to the controller and wait for that 1260 * to complete and reinitialize the controller and then returns. 1261 * 1262 * Return: 0 on success and proper error codes on failure 1263 */ 1264 static long 1265 mpi3mr_adp_reset(struct mpi3mr_softc *sc, 1266 void *data_out_buf, U32 data_out_sz) 1267 { 1268 long rval = EINVAL; 1269 struct mpi3mr_ioctl_adpreset adpreset; 1270 1271 memset(&adpreset, 0, sizeof(adpreset)); 1272 1273 if (data_out_sz != sizeof(adpreset)) { 1274 printf(IOCNAME "Invalid user adpreset buffer size %s() line: %d\n", sc->name, 1275 __func__, __LINE__); 1276 goto out; 1277 } 1278 1279 if (copyin(data_out_buf, &adpreset, sizeof(adpreset))) { 1280 printf(IOCNAME "failure at %s() line:%d\n", sc->name, 1281 __func__, __LINE__); 1282 rval = EFAULT; 1283 goto out; 1284 } 1285 1286 switch (adpreset.reset_type) { 1287 case MPI3MR_IOCTL_ADPRESET_SOFT: 1288 sc->reset.ioctl_reset_snapdump = false; 1289 break; 1290 case MPI3MR_IOCTL_ADPRESET_DIAG_FAULT: 1291 sc->reset.ioctl_reset_snapdump = true; 1292 break; 1293 default: 1294 printf(IOCNAME "Unknown reset_type(0x%x) issued\n", sc->name, 1295 adpreset.reset_type); 1296 goto out; 1297 } 1298 rval = mpi3mr_soft_reset_from_app(sc); 1299 if (rval) 1300 printf(IOCNAME "reset handler returned error (0x%lx) for reset type 0x%x\n", 1301 sc->name, rval, adpreset.reset_type); 1302 1303 out: 1304 return rval; 1305 } 1306 1307 void 1308 mpi3mr_app_send_aen(struct mpi3mr_softc *sc) 1309 { 1310 sc->mpi3mr_aen_triggered = 1; 1311 if (sc->mpi3mr_poll_waiting) { 1312 selwakeup(&sc->mpi3mr_select); 1313 sc->mpi3mr_poll_waiting = 0; 1314 } 1315 return; 1316 } 1317 1318 void 1319 mpi3mr_pel_wait_complete(struct mpi3mr_softc *sc, 1320 struct mpi3mr_drvr_cmd *drvr_cmd) 1321 { 1322 U8 retry = 0; 1323 Mpi3PELReply_t *pel_reply = NULL; 1324 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1325 1326 if (drvr_cmd->state & MPI3MR_CMD_RESET) 1327 goto cleanup_drvrcmd; 1328 1329 if (!(drvr_cmd->state & MPI3MR_CMD_REPLYVALID)) { 1330 printf(IOCNAME "%s: PELGetSeqNum Failed, No Reply\n", sc->name, __func__); 1331 goto out_failed; 1332 } 1333 pel_reply = (Mpi3PELReply_t *)drvr_cmd->reply; 1334 1335 if (((GET_IOC_STATUS(drvr_cmd->ioc_status)) != MPI3_IOCSTATUS_SUCCESS) 1336 || ((le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_SUCCESS) 1337 && (le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_ABORTED))){ 1338 printf(IOCNAME "%s: PELGetSeqNum Failed, IOCStatus(0x%04x) Loginfo(0x%08x) PEL_LogStatus(0x%04x)\n", 1339 sc->name, __func__, GET_IOC_STATUS(drvr_cmd->ioc_status), 1340 drvr_cmd->ioc_loginfo, le16toh(pel_reply->PELogStatus)); 1341 retry = 1; 1342 } 1343 1344 if (retry) { 1345 if (drvr_cmd->retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 1346 drvr_cmd->retry_count++; 1347 printf(IOCNAME "%s : PELWaitretry=%d\n", sc->name, 1348 __func__, drvr_cmd->retry_count); 1349 mpi3mr_issue_pel_wait(sc, drvr_cmd); 1350 return; 1351 } 1352 1353 printf(IOCNAME "%s :PELWait failed after all retries\n", sc->name, 1354 __func__); 1355 goto out_failed; 1356 } 1357 1358 mpi3mr_app_send_aen(sc); 1359 1360 if (!sc->pel_abort_requested) { 1361 sc->pel_cmds.retry_count = 0; 1362 mpi3mr_send_pel_getseq(sc, &sc->pel_cmds); 1363 } 1364 1365 return; 1366 out_failed: 1367 sc->pel_wait_pend = 0; 1368 cleanup_drvrcmd: 1369 drvr_cmd->state = MPI3MR_CMD_NOTUSED; 1370 drvr_cmd->callback = NULL; 1371 drvr_cmd->retry_count = 0; 1372 } 1373 1374 void 1375 mpi3mr_issue_pel_wait(struct mpi3mr_softc *sc, 1376 struct mpi3mr_drvr_cmd *drvr_cmd) 1377 { 1378 U8 retry_count = 0; 1379 Mpi3PELReqActionWait_t pel_wait; 1380 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1381 1382 sc->pel_abort_requested = 0; 1383 1384 memset(&pel_wait, 0, sizeof(pel_wait)); 1385 drvr_cmd->state = MPI3MR_CMD_PENDING; 1386 drvr_cmd->is_waiting = 0; 1387 drvr_cmd->callback = mpi3mr_pel_wait_complete; 1388 drvr_cmd->ioc_status = 0; 1389 drvr_cmd->ioc_loginfo = 0; 1390 pel_wait.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 1391 pel_wait.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 1392 pel_wait.Action = MPI3_PEL_ACTION_WAIT; 1393 pel_wait.StartingSequenceNumber = htole32(sc->newest_seqnum); 1394 pel_wait.Locale = htole16(sc->pel_locale); 1395 pel_wait.Class = htole16(sc->pel_class); 1396 pel_wait.WaitTime = MPI3_PEL_WAITTIME_INFINITE_WAIT; 1397 printf(IOCNAME "Issuing PELWait: seqnum %u class %u locale 0x%08x\n", 1398 sc->name, sc->newest_seqnum, sc->pel_class, sc->pel_locale); 1399 retry_pel_wait: 1400 if (mpi3mr_submit_admin_cmd(sc, &pel_wait, sizeof(pel_wait))) { 1401 printf(IOCNAME "%s: Issue PELWait IOCTL: Admin Post failed\n", sc->name, __func__); 1402 if (retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 1403 retry_count++; 1404 goto retry_pel_wait; 1405 } 1406 goto out_failed; 1407 } 1408 return; 1409 out_failed: 1410 drvr_cmd->state = MPI3MR_CMD_NOTUSED; 1411 drvr_cmd->callback = NULL; 1412 drvr_cmd->retry_count = 0; 1413 sc->pel_wait_pend = 0; 1414 return; 1415 } 1416 1417 void 1418 mpi3mr_send_pel_getseq(struct mpi3mr_softc *sc, 1419 struct mpi3mr_drvr_cmd *drvr_cmd) 1420 { 1421 U8 retry_count = 0; 1422 U8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 1423 Mpi3PELReqActionGetSequenceNumbers_t pel_getseq_req; 1424 1425 memset(&pel_getseq_req, 0, sizeof(pel_getseq_req)); 1426 sc->pel_cmds.state = MPI3MR_CMD_PENDING; 1427 sc->pel_cmds.is_waiting = 0; 1428 sc->pel_cmds.ioc_status = 0; 1429 sc->pel_cmds.ioc_loginfo = 0; 1430 sc->pel_cmds.callback = mpi3mr_pel_getseq_complete; 1431 pel_getseq_req.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 1432 pel_getseq_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 1433 pel_getseq_req.Action = MPI3_PEL_ACTION_GET_SEQNUM; 1434 mpi3mr_add_sg_single(&pel_getseq_req.SGL, sgl_flags, 1435 sc->pel_seq_number_sz, sc->pel_seq_number_dma); 1436 1437 retry_pel_getseq: 1438 if (mpi3mr_submit_admin_cmd(sc, &pel_getseq_req, sizeof(pel_getseq_req))) { 1439 printf(IOCNAME "%s: Issuing PEL GetSeq IOCTL: Admin Post failed\n", sc->name, __func__); 1440 if (retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 1441 retry_count++; 1442 goto retry_pel_getseq; 1443 } 1444 goto out_failed; 1445 } 1446 return; 1447 out_failed: 1448 drvr_cmd->state = MPI3MR_CMD_NOTUSED; 1449 drvr_cmd->callback = NULL; 1450 drvr_cmd->retry_count = 0; 1451 sc->pel_wait_pend = 0; 1452 } 1453 1454 void 1455 mpi3mr_pel_getseq_complete(struct mpi3mr_softc *sc, 1456 struct mpi3mr_drvr_cmd *drvr_cmd) 1457 { 1458 U8 retry = 0; 1459 Mpi3PELReply_t *pel_reply = NULL; 1460 Mpi3PELSeq_t *pel_seq_num = (Mpi3PELSeq_t *)sc->pel_seq_number; 1461 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1462 1463 if (drvr_cmd->state & MPI3MR_CMD_RESET) 1464 goto cleanup_drvrcmd; 1465 1466 if (!(drvr_cmd->state & MPI3MR_CMD_REPLYVALID)) { 1467 printf(IOCNAME "%s: PELGetSeqNum Failed, No Reply\n", sc->name, __func__); 1468 goto out_failed; 1469 } 1470 pel_reply = (Mpi3PELReply_t *)drvr_cmd->reply; 1471 1472 if (((GET_IOC_STATUS(drvr_cmd->ioc_status)) != MPI3_IOCSTATUS_SUCCESS) 1473 || (le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_SUCCESS)){ 1474 printf(IOCNAME "%s: PELGetSeqNum Failed, IOCStatus(0x%04x) Loginfo(0x%08x) PEL_LogStatus(0x%04x)\n", 1475 sc->name, __func__, GET_IOC_STATUS(drvr_cmd->ioc_status), 1476 drvr_cmd->ioc_loginfo, le16toh(pel_reply->PELogStatus)); 1477 retry = 1; 1478 } 1479 1480 if (retry) { 1481 if (drvr_cmd->retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 1482 drvr_cmd->retry_count++; 1483 printf(IOCNAME "%s : PELGetSeqNUM retry=%d\n", sc->name, 1484 __func__, drvr_cmd->retry_count); 1485 mpi3mr_send_pel_getseq(sc, drvr_cmd); 1486 return; 1487 } 1488 printf(IOCNAME "%s :PELGetSeqNUM failed after all retries\n", 1489 sc->name, __func__); 1490 goto out_failed; 1491 } 1492 1493 sc->newest_seqnum = le32toh(pel_seq_num->Newest) + 1; 1494 drvr_cmd->retry_count = 0; 1495 mpi3mr_issue_pel_wait(sc, drvr_cmd); 1496 return; 1497 out_failed: 1498 sc->pel_wait_pend = 0; 1499 cleanup_drvrcmd: 1500 drvr_cmd->state = MPI3MR_CMD_NOTUSED; 1501 drvr_cmd->callback = NULL; 1502 drvr_cmd->retry_count = 0; 1503 } 1504 1505 static int 1506 mpi3mr_pel_getseq(struct mpi3mr_softc *sc) 1507 { 1508 int rval = 0; 1509 U8 sgl_flags = 0; 1510 Mpi3PELReqActionGetSequenceNumbers_t pel_getseq_req; 1511 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1512 1513 if (sc->reset_in_progress || sc->block_ioctls) { 1514 printf(IOCNAME "%s: IOCTL failed: reset in progress: %u ioctls blocked: %u\n", 1515 sc->name, __func__, sc->reset_in_progress, sc->block_ioctls); 1516 return -1; 1517 } 1518 1519 memset(&pel_getseq_req, 0, sizeof(pel_getseq_req)); 1520 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 1521 sc->pel_cmds.state = MPI3MR_CMD_PENDING; 1522 sc->pel_cmds.is_waiting = 0; 1523 sc->pel_cmds.retry_count = 0; 1524 sc->pel_cmds.ioc_status = 0; 1525 sc->pel_cmds.ioc_loginfo = 0; 1526 sc->pel_cmds.callback = mpi3mr_pel_getseq_complete; 1527 pel_getseq_req.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 1528 pel_getseq_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 1529 pel_getseq_req.Action = MPI3_PEL_ACTION_GET_SEQNUM; 1530 mpi3mr_add_sg_single(&pel_getseq_req.SGL, sgl_flags, 1531 sc->pel_seq_number_sz, sc->pel_seq_number_dma); 1532 1533 if ((rval = mpi3mr_submit_admin_cmd(sc, &pel_getseq_req, sizeof(pel_getseq_req)))) 1534 printf(IOCNAME "%s: Issue IOCTL: Admin Post failed\n", sc->name, __func__); 1535 1536 return rval; 1537 } 1538 1539 int 1540 mpi3mr_pel_abort(struct mpi3mr_softc *sc) 1541 { 1542 int retval = 0; 1543 U16 pel_log_status; 1544 Mpi3PELReqActionAbort_t pel_abort_req; 1545 Mpi3PELReply_t *pel_reply = NULL; 1546 1547 if (sc->reset_in_progress || sc->block_ioctls) { 1548 printf(IOCNAME "%s: IOCTL failed: reset in progress: %u ioctls blocked: %u\n", 1549 sc->name, __func__, sc->reset_in_progress, sc->block_ioctls); 1550 return -1; 1551 } 1552 1553 memset(&pel_abort_req, 0, sizeof(pel_abort_req)); 1554 1555 mtx_lock(&sc->pel_abort_cmd.completion.lock); 1556 if (sc->pel_abort_cmd.state & MPI3MR_CMD_PENDING) { 1557 printf(IOCNAME "%s: PEL Abort command is in use\n", sc->name, __func__); 1558 mtx_unlock(&sc->pel_abort_cmd.completion.lock); 1559 return -1; 1560 } 1561 1562 sc->pel_abort_cmd.state = MPI3MR_CMD_PENDING; 1563 sc->pel_abort_cmd.is_waiting = 1; 1564 sc->pel_abort_cmd.callback = NULL; 1565 pel_abort_req.HostTag = htole16(MPI3MR_HOSTTAG_PELABORT); 1566 pel_abort_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 1567 pel_abort_req.Action = MPI3_PEL_ACTION_ABORT; 1568 pel_abort_req.AbortHostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 1569 1570 sc->pel_abort_requested = 1; 1571 1572 init_completion(&sc->pel_abort_cmd.completion); 1573 retval = mpi3mr_submit_admin_cmd(sc, &pel_abort_req, sizeof(pel_abort_req)); 1574 if (retval) { 1575 printf(IOCNAME "%s: Issue IOCTL: Admin Post failed\n", sc->name, __func__); 1576 sc->pel_abort_requested = 0; 1577 retval = -1; 1578 goto out_unlock; 1579 } 1580 wait_for_completion_timeout(&sc->pel_abort_cmd.completion, MPI3MR_INTADMCMD_TIMEOUT); 1581 1582 if (!(sc->pel_abort_cmd.state & MPI3MR_CMD_COMPLETE)) { 1583 printf(IOCNAME "%s: PEL Abort command timedout\n",sc->name, __func__); 1584 sc->pel_abort_cmd.is_waiting = 0; 1585 retval = -1; 1586 sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; 1587 sc->reset.reason = MPI3MR_RESET_FROM_PELABORT_TIMEOUT; 1588 goto out_unlock; 1589 } 1590 if (((GET_IOC_STATUS(sc->pel_abort_cmd.ioc_status)) != MPI3_IOCSTATUS_SUCCESS) 1591 || (!(sc->pel_abort_cmd.state & MPI3MR_CMD_REPLYVALID))) { 1592 printf(IOCNAME "%s: PEL Abort command failed, ioc_status(0x%04x) log_info(0x%08x)\n", 1593 sc->name, __func__, GET_IOC_STATUS(sc->pel_abort_cmd.ioc_status), 1594 sc->pel_abort_cmd.ioc_loginfo); 1595 retval = -1; 1596 goto out_unlock; 1597 } 1598 1599 pel_reply = (Mpi3PELReply_t *)sc->pel_abort_cmd.reply; 1600 pel_log_status = le16toh(pel_reply->PELogStatus); 1601 if (pel_log_status != MPI3_PEL_STATUS_SUCCESS) { 1602 printf(IOCNAME "%s: PEL abort command failed, pel_status(0x%04x)\n", 1603 sc->name, __func__, pel_log_status); 1604 retval = -1; 1605 } 1606 1607 out_unlock: 1608 mtx_unlock(&sc->pel_abort_cmd.completion.lock); 1609 sc->pel_abort_cmd.state = MPI3MR_CMD_NOTUSED; 1610 return retval; 1611 } 1612 1613 /** 1614 * mpi3mr_pel_enable - Handler for PEL enable 1615 * @sc: Adapter instance reference 1616 * @data_out_buf: User buffer containing PEL enable data 1617 * @data_out_sz: length of the user buffer. 1618 * 1619 * This function is the handler for PEL enable driver IOCTL. 1620 * Validates the application given class and locale and if 1621 * requires aborts the existing PEL wait request and/or issues 1622 * new PEL wait request to the firmware and returns. 1623 * 1624 * Return: 0 on success and proper error codes on failure. 1625 */ 1626 static long 1627 mpi3mr_pel_enable(struct mpi3mr_softc *sc, 1628 void *data_out_buf, U32 data_out_sz) 1629 { 1630 long rval = EINVAL; 1631 U8 tmp_class; 1632 U16 tmp_locale; 1633 struct mpi3mr_ioctl_pel_enable pel_enable; 1634 mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 1635 1636 1637 if ((data_out_sz != sizeof(pel_enable) || 1638 (pel_enable.pel_class > MPI3_PEL_CLASS_FAULT))) { 1639 printf(IOCNAME "%s: Invalid user pel_enable buffer size %u\n", 1640 sc->name, __func__, data_out_sz); 1641 goto out; 1642 } 1643 memset(&pel_enable, 0, sizeof(pel_enable)); 1644 if (copyin(data_out_buf, &pel_enable, sizeof(pel_enable))) { 1645 printf(IOCNAME "failure at %s() line:%d\n", sc->name, 1646 __func__, __LINE__); 1647 rval = EFAULT; 1648 goto out; 1649 } 1650 if (pel_enable.pel_class > MPI3_PEL_CLASS_FAULT) { 1651 printf(IOCNAME "%s: out of range class %d\n", 1652 sc->name, __func__, pel_enable.pel_class); 1653 goto out; 1654 } 1655 1656 if (sc->pel_wait_pend) { 1657 if ((sc->pel_class <= pel_enable.pel_class) && 1658 !((sc->pel_locale & pel_enable.pel_locale) ^ 1659 pel_enable.pel_locale)) { 1660 rval = 0; 1661 goto out; 1662 } else { 1663 pel_enable.pel_locale |= sc->pel_locale; 1664 if (sc->pel_class < pel_enable.pel_class) 1665 pel_enable.pel_class = sc->pel_class; 1666 1667 if (mpi3mr_pel_abort(sc)) { 1668 printf(IOCNAME "%s: pel_abort failed, status(%ld)\n", 1669 sc->name, __func__, rval); 1670 goto out; 1671 } 1672 } 1673 } 1674 1675 tmp_class = sc->pel_class; 1676 tmp_locale = sc->pel_locale; 1677 sc->pel_class = pel_enable.pel_class; 1678 sc->pel_locale = pel_enable.pel_locale; 1679 sc->pel_wait_pend = 1; 1680 1681 if ((rval = mpi3mr_pel_getseq(sc))) { 1682 sc->pel_class = tmp_class; 1683 sc->pel_locale = tmp_locale; 1684 sc->pel_wait_pend = 0; 1685 printf(IOCNAME "%s: pel get sequence number failed, status(%ld)\n", 1686 sc->name, __func__, rval); 1687 } 1688 1689 out: 1690 return rval; 1691 } 1692 1693 void 1694 mpi3mr_app_save_logdata(struct mpi3mr_softc *sc, char *event_data, 1695 U16 event_data_size) 1696 { 1697 struct mpi3mr_log_data_entry *entry; 1698 U32 index = sc->log_data_buffer_index, sz; 1699 1700 if (!(sc->log_data_buffer)) 1701 return; 1702 1703 entry = (struct mpi3mr_log_data_entry *) 1704 (sc->log_data_buffer + (index * sc->log_data_entry_size)); 1705 entry->valid_entry = 1; 1706 sz = min(sc->log_data_entry_size, event_data_size); 1707 memcpy(entry->data, event_data, sz); 1708 sc->log_data_buffer_index = 1709 ((++index) % MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES); 1710 mpi3mr_app_send_aen(sc); 1711 } 1712 1713 /** 1714 * mpi3mr_get_logdata - Handler for get log data 1715 * @sc: Adapter instance reference 1716 * @data_in_buf: User buffer to copy the logdata entries 1717 * @data_in_sz: length of the user buffer. 1718 * 1719 * This function copies the log data entries to the user buffer 1720 * when log caching is enabled in the driver. 1721 * 1722 * Return: 0 on success and proper error codes on failure 1723 */ 1724 static long 1725 mpi3mr_get_logdata(struct mpi3mr_softc *sc, 1726 void *data_in_buf, U32 data_in_sz) 1727 { 1728 long rval = EINVAL; 1729 U16 num_entries = 0; 1730 U16 entry_sz = sc->log_data_entry_size; 1731 1732 if ((!sc->log_data_buffer) || (data_in_sz < entry_sz)) 1733 return rval; 1734 1735 num_entries = data_in_sz / entry_sz; 1736 if (num_entries > MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES) 1737 num_entries = MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES; 1738 1739 if ((rval = copyout(sc->log_data_buffer, data_in_buf, (num_entries * entry_sz)))) { 1740 printf(IOCNAME "%s: copy to user failed\n", sc->name, __func__); 1741 rval = EFAULT; 1742 } 1743 1744 return rval; 1745 } 1746 1747 /** 1748 * mpi3mr_logdata_enable - Handler for log data enable 1749 * @sc: Adapter instance reference 1750 * @data_in_buf: User buffer to copy the max logdata entry count 1751 * @data_in_sz: length of the user buffer. 1752 * 1753 * This function enables log data caching in the driver if not 1754 * already enabled and return the maximum number of log data 1755 * entries that can be cached in the driver. 1756 * 1757 * Return: 0 on success and proper error codes on failure 1758 */ 1759 static long 1760 mpi3mr_logdata_enable(struct mpi3mr_softc *sc, 1761 void *data_in_buf, U32 data_in_sz) 1762 { 1763 long rval = EINVAL; 1764 struct mpi3mr_ioctl_logdata_enable logdata_enable; 1765 1766 if (data_in_sz < sizeof(logdata_enable)) 1767 return rval; 1768 1769 if (sc->log_data_buffer) 1770 goto copy_data; 1771 1772 sc->log_data_entry_size = (sc->reply_sz - (sizeof(Mpi3EventNotificationReply_t) - 4)) 1773 + MPI3MR_IOCTL_LOGDATA_ENTRY_HEADER_SZ; 1774 1775 sc->log_data_buffer = malloc((MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES * sc->log_data_entry_size), 1776 M_MPI3MR, M_NOWAIT | M_ZERO); 1777 if (!sc->log_data_buffer) { 1778 printf(IOCNAME "%s log data buffer memory allocation failed\n", sc->name, __func__); 1779 return ENOMEM; 1780 } 1781 1782 sc->log_data_buffer_index = 0; 1783 1784 copy_data: 1785 memset(&logdata_enable, 0, sizeof(logdata_enable)); 1786 logdata_enable.max_entries = MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES; 1787 1788 if ((rval = copyout(&logdata_enable, data_in_buf, sizeof(logdata_enable)))) { 1789 printf(IOCNAME "%s: copy to user failed\n", sc->name, __func__); 1790 rval = EFAULT; 1791 } 1792 1793 return rval; 1794 } 1795 1796 /** 1797 * mpi3mr_get_change_count - Get topology change count 1798 * @sc: Adapter instance reference 1799 * @data_in_buf: User buffer to copy the change count 1800 * @data_in_sz: length of the user buffer. 1801 * 1802 * This function copies the toplogy change count provided by the 1803 * driver in events and cached in the driver to the user 1804 * provided buffer for the specific controller. 1805 * 1806 * Return: 0 on success and proper error codes on failure 1807 */ 1808 static long 1809 mpi3mr_get_change_count(struct mpi3mr_softc *sc, 1810 void *data_in_buf, U32 data_in_sz) 1811 { 1812 long rval = EINVAL; 1813 struct mpi3mr_ioctl_chgcnt chg_count; 1814 memset(&chg_count, 0, sizeof(chg_count)); 1815 1816 chg_count.change_count = sc->change_count; 1817 if (data_in_sz >= sizeof(chg_count)) { 1818 if ((rval = copyout(&chg_count, data_in_buf, sizeof(chg_count)))) { 1819 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 1820 __LINE__, __func__); 1821 rval = EFAULT; 1822 } 1823 } 1824 return rval; 1825 } 1826 1827 /** 1828 * mpi3mr_get_alltgtinfo - Get all targets information 1829 * @sc: Adapter instance reference 1830 * @data_in_buf: User buffer to copy the target information 1831 * @data_in_sz: length of the user buffer. 1832 * 1833 * This function copies the driver managed target devices device 1834 * handle, persistent ID, bus ID and taret ID to the user 1835 * provided buffer for the specific controller. This function 1836 * also provides the number of devices managed by the driver for 1837 * the specific controller. 1838 * 1839 * Return: 0 on success and proper error codes on failure 1840 */ 1841 static long 1842 mpi3mr_get_alltgtinfo(struct mpi3mr_softc *sc, 1843 void *data_in_buf, U32 data_in_sz) 1844 { 1845 long rval = EINVAL; 1846 U8 get_count = 0; 1847 U16 i = 0, num_devices = 0; 1848 U32 min_entrylen = 0, kern_entrylen = 0, user_entrylen = 0; 1849 struct mpi3mr_target *tgtdev = NULL; 1850 struct mpi3mr_device_map_info *devmap_info = NULL; 1851 struct mpi3mr_cam_softc *cam_sc = sc->cam_sc; 1852 struct mpi3mr_ioctl_all_tgtinfo *all_tgtinfo = (struct mpi3mr_ioctl_all_tgtinfo *)data_in_buf; 1853 1854 if (data_in_sz < sizeof(uint32_t)) { 1855 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 1856 __LINE__, __func__); 1857 goto out; 1858 } 1859 if (data_in_sz == sizeof(uint32_t)) 1860 get_count = 1; 1861 1862 if (TAILQ_EMPTY(&cam_sc->tgt_list)) { 1863 get_count = 1; 1864 goto copy_usrbuf; 1865 } 1866 1867 mtx_lock_spin(&cam_sc->sc->target_lock); 1868 TAILQ_FOREACH(tgtdev, &cam_sc->tgt_list, tgt_next) { 1869 num_devices++; 1870 } 1871 mtx_unlock_spin(&cam_sc->sc->target_lock); 1872 1873 if (get_count) 1874 goto copy_usrbuf; 1875 1876 kern_entrylen = num_devices * sizeof(*devmap_info); 1877 1878 devmap_info = malloc(kern_entrylen, M_MPI3MR, M_NOWAIT | M_ZERO); 1879 if (!devmap_info) { 1880 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 1881 __LINE__, __func__); 1882 rval = ENOMEM; 1883 goto out; 1884 } 1885 memset((U8*)devmap_info, 0xFF, kern_entrylen); 1886 1887 mtx_lock_spin(&cam_sc->sc->target_lock); 1888 TAILQ_FOREACH(tgtdev, &cam_sc->tgt_list, tgt_next) { 1889 if (i < num_devices) { 1890 devmap_info[i].handle = tgtdev->dev_handle; 1891 devmap_info[i].per_id = tgtdev->per_id; 1892 /*n 1893 * For hidden/ugood device the target_id and bus_id should be 0xFFFFFFFF and 0xFF 1894 */ 1895 if (!tgtdev->exposed_to_os) { 1896 devmap_info[i].target_id = 0xFFFFFFFF; 1897 devmap_info[i].bus_id = 0xFF; 1898 } else { 1899 devmap_info[i].target_id = tgtdev->tid; 1900 devmap_info[i].bus_id = 0; 1901 } 1902 i++; 1903 } 1904 } 1905 num_devices = i; 1906 mtx_unlock_spin(&cam_sc->sc->target_lock); 1907 1908 copy_usrbuf: 1909 if (copyout(&num_devices, &all_tgtinfo->num_devices, sizeof(num_devices))) { 1910 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 1911 __LINE__, __func__); 1912 rval = EFAULT; 1913 goto out; 1914 } 1915 user_entrylen = (data_in_sz - sizeof(uint32_t))/sizeof(*devmap_info); 1916 user_entrylen *= sizeof(*devmap_info); 1917 min_entrylen = min(user_entrylen, kern_entrylen); 1918 if (min_entrylen && (copyout(devmap_info, &all_tgtinfo->dmi, min_entrylen))) { 1919 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 1920 __FILE__, __LINE__, __func__); 1921 rval = EFAULT; 1922 goto out; 1923 } 1924 rval = 0; 1925 out: 1926 if (devmap_info) 1927 free(devmap_info, M_MPI3MR); 1928 1929 return rval; 1930 } 1931 1932 /** 1933 * mpi3mr_get_tgtinfo - Get specific target information 1934 * @sc: Adapter instance reference 1935 * @karg: driver ponter to users payload buffer 1936 * 1937 * This function copies the driver managed specific target device 1938 * info like handle, persistent ID, bus ID and taret ID to the user 1939 * provided buffer for the specific controller. 1940 * 1941 * Return: 0 on success and proper error codes on failure 1942 */ 1943 static long 1944 mpi3mr_get_tgtinfo(struct mpi3mr_softc *sc, 1945 struct mpi3mr_ioctl_drvcmd *karg) 1946 { 1947 long rval = EINVAL; 1948 struct mpi3mr_target *tgtdev = NULL; 1949 struct mpi3mr_ioctl_tgtinfo tgtinfo; 1950 1951 memset(&tgtinfo, 0, sizeof(tgtinfo)); 1952 1953 if ((karg->data_out_size != sizeof(struct mpi3mr_ioctl_tgtinfo)) || 1954 (karg->data_in_size != sizeof(struct mpi3mr_ioctl_tgtinfo))) { 1955 printf(IOCNAME "Invalid user tgtinfo buffer size %s() line: %d\n", sc->name, 1956 __func__, __LINE__); 1957 goto out; 1958 } 1959 1960 if (copyin(karg->data_out_buf, &tgtinfo, sizeof(tgtinfo))) { 1961 printf(IOCNAME "failure at %s() line:%d\n", sc->name, 1962 __func__, __LINE__); 1963 rval = EFAULT; 1964 goto out; 1965 } 1966 1967 if ((tgtinfo.bus_id != 0xFF) && (tgtinfo.target_id != 0xFFFFFFFF)) { 1968 if ((tgtinfo.persistent_id != 0xFFFF) || 1969 (tgtinfo.dev_handle != 0xFFFF)) 1970 goto out; 1971 tgtdev = mpi3mr_find_target_by_per_id(sc->cam_sc, tgtinfo.target_id); 1972 } else if (tgtinfo.persistent_id != 0xFFFF) { 1973 if ((tgtinfo.bus_id != 0xFF) || 1974 (tgtinfo.dev_handle !=0xFFFF) || 1975 (tgtinfo.target_id != 0xFFFFFFFF)) 1976 goto out; 1977 tgtdev = mpi3mr_find_target_by_per_id(sc->cam_sc, tgtinfo.persistent_id); 1978 } else if (tgtinfo.dev_handle !=0xFFFF) { 1979 if ((tgtinfo.bus_id != 0xFF) || 1980 (tgtinfo.target_id != 0xFFFFFFFF) || 1981 (tgtinfo.persistent_id != 0xFFFF)) 1982 goto out; 1983 tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, tgtinfo.dev_handle); 1984 } 1985 if (!tgtdev) 1986 goto out; 1987 1988 tgtinfo.target_id = tgtdev->per_id; 1989 tgtinfo.bus_id = 0; 1990 tgtinfo.dev_handle = tgtdev->dev_handle; 1991 tgtinfo.persistent_id = tgtdev->per_id; 1992 tgtinfo.seq_num = 0; 1993 1994 if (copyout(&tgtinfo, karg->data_in_buf, sizeof(tgtinfo))) { 1995 printf(IOCNAME "failure at %s() line:%d\n", sc->name, 1996 __func__, __LINE__); 1997 rval = EFAULT; 1998 } 1999 2000 out: 2001 return rval; 2002 } 2003 2004 /** 2005 * mpi3mr_get_pciinfo - Get PCI info IOCTL handler 2006 * @sc: Adapter instance reference 2007 * @data_in_buf: User buffer to hold adapter information 2008 * @data_in_sz: length of the user buffer. 2009 * 2010 * This function provides the PCI spec information for the 2011 * given controller 2012 * 2013 * Return: 0 on success and proper error codes on failure 2014 */ 2015 static long 2016 mpi3mr_get_pciinfo(struct mpi3mr_softc *sc, 2017 void *data_in_buf, U32 data_in_sz) 2018 { 2019 long rval = EINVAL; 2020 U8 i; 2021 struct mpi3mr_ioctl_pciinfo pciinfo; 2022 memset(&pciinfo, 0, sizeof(pciinfo)); 2023 2024 for (i = 0; i < 64; i++) 2025 pciinfo.config_space[i] = pci_read_config(sc->mpi3mr_dev, (i * 4), 4); 2026 2027 if (data_in_sz >= sizeof(pciinfo)) { 2028 if ((rval = copyout(&pciinfo, data_in_buf, sizeof(pciinfo)))) { 2029 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 2030 __FILE__, __LINE__, __func__); 2031 rval = EFAULT; 2032 } 2033 } 2034 return rval; 2035 } 2036 2037 /** 2038 * mpi3mr_get_adpinfo - Get adapter info IOCTL handler 2039 * @sc: Adapter instance reference 2040 * @data_in_buf: User buffer to hold adapter information 2041 * @data_in_sz: length of the user buffer. 2042 * 2043 * This function provides adapter information for the given 2044 * controller 2045 * 2046 * Return: 0 on success and proper error codes on failure 2047 */ 2048 static long 2049 mpi3mr_get_adpinfo(struct mpi3mr_softc *sc, 2050 void *data_in_buf, U32 data_in_sz) 2051 { 2052 long rval = EINVAL; 2053 struct mpi3mr_ioctl_adpinfo adpinfo; 2054 enum mpi3mr_iocstate ioc_state; 2055 memset(&adpinfo, 0, sizeof(adpinfo)); 2056 2057 adpinfo.adp_type = MPI3MR_IOCTL_ADPTYPE_AVGFAMILY; 2058 adpinfo.pci_dev_id = pci_get_device(sc->mpi3mr_dev); 2059 adpinfo.pci_dev_hw_rev = pci_read_config(sc->mpi3mr_dev, PCIR_REVID, 1); 2060 adpinfo.pci_subsys_dev_id = pci_get_subdevice(sc->mpi3mr_dev); 2061 adpinfo.pci_subsys_ven_id = pci_get_subvendor(sc->mpi3mr_dev); 2062 adpinfo.pci_bus = pci_get_bus(sc->mpi3mr_dev);; 2063 adpinfo.pci_dev = pci_get_slot(sc->mpi3mr_dev); 2064 adpinfo.pci_func = pci_get_function(sc->mpi3mr_dev); 2065 adpinfo.pci_seg_id = pci_get_domain(sc->mpi3mr_dev); 2066 adpinfo.ioctl_ver = MPI3MR_IOCTL_VERSION; 2067 memcpy((U8 *)&adpinfo.driver_info, (U8 *)&sc->driver_info, sizeof(adpinfo.driver_info)); 2068 2069 ioc_state = mpi3mr_get_iocstate(sc); 2070 2071 if (ioc_state == MRIOC_STATE_UNRECOVERABLE) 2072 adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_UNRECOVERABLE; 2073 else if (sc->reset_in_progress || sc->block_ioctls) 2074 adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_IN_RESET; 2075 else if (ioc_state == MRIOC_STATE_FAULT) 2076 adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_FAULT; 2077 else 2078 adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_OPERATIONAL; 2079 2080 if (data_in_sz >= sizeof(adpinfo)) { 2081 if ((rval = copyout(&adpinfo, data_in_buf, sizeof(adpinfo)))) { 2082 printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 2083 __FILE__, __LINE__, __func__); 2084 rval = EFAULT; 2085 } 2086 } 2087 return rval; 2088 } 2089 /** 2090 * mpi3mr_app_drvrcmds - Driver IOCTL handler 2091 * @dev: char device 2092 * @cmd: IOCTL command 2093 * @arg: User data payload buffer for the IOCTL 2094 * @flag: flags 2095 * @thread: threads 2096 * 2097 * This function is the top level handler for driver commands, 2098 * this does basic validation of the buffer and identifies the 2099 * opcode and switches to correct sub handler. 2100 * 2101 * Return: 0 on success and proper error codes on failure 2102 */ 2103 2104 static int 2105 mpi3mr_app_drvrcmds(struct cdev *dev, u_long cmd, 2106 void *uarg, int flag, struct thread *td) 2107 { 2108 long rval = EINVAL; 2109 struct mpi3mr_softc *sc = NULL; 2110 struct mpi3mr_ioctl_drvcmd *karg = (struct mpi3mr_ioctl_drvcmd *)uarg; 2111 2112 sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); 2113 if (!sc) 2114 return ENODEV; 2115 2116 mtx_lock(&sc->ioctl_cmds.completion.lock); 2117 switch (karg->opcode) { 2118 case MPI3MR_DRVRIOCTL_OPCODE_ADPINFO: 2119 rval = mpi3mr_get_adpinfo(sc, karg->data_in_buf, karg->data_in_size); 2120 break; 2121 case MPI3MR_DRVRIOCTL_OPCODE_GETPCIINFO: 2122 rval = mpi3mr_get_pciinfo(sc, karg->data_in_buf, karg->data_in_size); 2123 break; 2124 case MPI3MR_DRVRIOCTL_OPCODE_TGTDEVINFO: 2125 rval = mpi3mr_get_tgtinfo(sc, karg); 2126 break; 2127 case MPI3MR_DRVRIOCTL_OPCODE_ALLTGTDEVINFO: 2128 rval = mpi3mr_get_alltgtinfo(sc, karg->data_in_buf, karg->data_in_size); 2129 break; 2130 case MPI3MR_DRVRIOCTL_OPCODE_GETCHGCNT: 2131 rval = mpi3mr_get_change_count(sc, karg->data_in_buf, karg->data_in_size); 2132 break; 2133 case MPI3MR_DRVRIOCTL_OPCODE_LOGDATAENABLE: 2134 rval = mpi3mr_logdata_enable(sc, karg->data_in_buf, karg->data_in_size); 2135 break; 2136 case MPI3MR_DRVRIOCTL_OPCODE_GETLOGDATA: 2137 rval = mpi3mr_get_logdata(sc, karg->data_in_buf, karg->data_in_size); 2138 break; 2139 case MPI3MR_DRVRIOCTL_OPCODE_PELENABLE: 2140 rval = mpi3mr_pel_enable(sc, karg->data_out_buf, karg->data_out_size); 2141 break; 2142 case MPI3MR_DRVRIOCTL_OPCODE_ADPRESET: 2143 rval = mpi3mr_adp_reset(sc, karg->data_out_buf, karg->data_out_size); 2144 break; 2145 case MPI3MR_DRVRIOCTL_OPCODE_UNKNOWN: 2146 default: 2147 printf("Unsupported drvr ioctl opcode 0x%x\n", karg->opcode); 2148 break; 2149 } 2150 mtx_unlock(&sc->ioctl_cmds.completion.lock); 2151 return rval; 2152 } 2153 /** 2154 * mpi3mr_ioctl - IOCTL Handler 2155 * @dev: char device 2156 * @cmd: IOCTL command 2157 * @arg: User data payload buffer for the IOCTL 2158 * @flag: flags 2159 * @thread: threads 2160 * 2161 * This is the IOCTL entry point which checks the command type and 2162 * executes proper sub handler specific for the command. 2163 * 2164 * Return: 0 on success and proper error codes on failure 2165 */ 2166 static int 2167 mpi3mr_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 2168 { 2169 int rval = EINVAL; 2170 2171 struct mpi3mr_softc *sc = NULL; 2172 struct mpi3mr_ioctl_drvcmd *karg = (struct mpi3mr_ioctl_drvcmd *)arg; 2173 2174 sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); 2175 2176 if (!sc) 2177 return ENODEV; 2178 2179 mpi3mr_atomic_inc(&sc->pend_ioctls); 2180 2181 2182 if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) { 2183 mpi3mr_dprint(sc, MPI3MR_INFO, 2184 "Return back IOCTL, shutdown is in progress\n"); 2185 mpi3mr_atomic_dec(&sc->pend_ioctls); 2186 return ENODEV; 2187 } 2188 2189 switch (cmd) { 2190 case MPI3MRDRVCMD: 2191 rval = mpi3mr_app_drvrcmds(dev, cmd, arg, flag, td); 2192 break; 2193 case MPI3MRMPTCMD: 2194 mtx_lock(&sc->ioctl_cmds.completion.lock); 2195 rval = mpi3mr_app_mptcmds(dev, cmd, arg, flag, td); 2196 mtx_unlock(&sc->ioctl_cmds.completion.lock); 2197 break; 2198 default: 2199 printf("%s:Unsupported ioctl cmd (0x%08lx)\n", MPI3MR_DRIVER_NAME, cmd); 2200 break; 2201 } 2202 2203 mpi3mr_atomic_dec(&sc->pend_ioctls); 2204 2205 return rval; 2206 } 2207