12d1d418eSSumit Saxena /* 22d1d418eSSumit Saxena * SPDX-License-Identifier: BSD-2-Clause 32d1d418eSSumit Saxena * 4945c3ce4SChandrakanth patil * Copyright (c) 2020-2024, Broadcom Inc. All rights reserved. 52d1d418eSSumit Saxena * Support: <fbsd-storage-driver.pdl@broadcom.com> 62d1d418eSSumit Saxena * 72d1d418eSSumit Saxena * Authors: Sumit Saxena <sumit.saxena@broadcom.com> 82d1d418eSSumit Saxena * Chandrakanth Patil <chandrakanth.patil@broadcom.com> 92d1d418eSSumit Saxena * 102d1d418eSSumit Saxena * Redistribution and use in source and binary forms, with or without 112d1d418eSSumit Saxena * modification, are permitted provided that the following conditions are 122d1d418eSSumit Saxena * met: 132d1d418eSSumit Saxena * 142d1d418eSSumit Saxena * 1. Redistributions of source code must retain the above copyright notice, 152d1d418eSSumit Saxena * this list of conditions and the following disclaimer. 162d1d418eSSumit Saxena * 2. Redistributions in binary form must reproduce the above copyright notice, 172d1d418eSSumit Saxena * this list of conditions and the following disclaimer in the documentation and/or other 182d1d418eSSumit Saxena * materials provided with the distribution. 192d1d418eSSumit Saxena * 3. Neither the name of the Broadcom Inc. nor the names of its contributors 202d1d418eSSumit Saxena * may be used to endorse or promote products derived from this software without 212d1d418eSSumit Saxena * specific prior written permission. 222d1d418eSSumit Saxena * 232d1d418eSSumit Saxena * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 242d1d418eSSumit Saxena * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 252d1d418eSSumit Saxena * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 262d1d418eSSumit Saxena * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 272d1d418eSSumit Saxena * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 282d1d418eSSumit Saxena * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 292d1d418eSSumit Saxena * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 302d1d418eSSumit Saxena * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 312d1d418eSSumit Saxena * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 322d1d418eSSumit Saxena * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 332d1d418eSSumit Saxena * POSSIBILITY OF SUCH DAMAGE. 342d1d418eSSumit Saxena * 352d1d418eSSumit Saxena * The views and conclusions contained in the software and documentation are 362d1d418eSSumit Saxena * those of the authors and should not be interpreted as representing 372d1d418eSSumit Saxena * official policies,either expressed or implied, of the FreeBSD Project. 382d1d418eSSumit Saxena * 392d1d418eSSumit Saxena * Mail to: Broadcom Inc 1320 Ridder Park Dr, San Jose, CA 95131 402d1d418eSSumit Saxena * 412d1d418eSSumit Saxena * Broadcom Inc. (Broadcom) MPI3MR Adapter FreeBSD 422d1d418eSSumit Saxena */ 432d1d418eSSumit Saxena 442d1d418eSSumit Saxena #include <sys/param.h> 452d1d418eSSumit Saxena #include <sys/proc.h> 462d1d418eSSumit Saxena #include <cam/cam.h> 472d1d418eSSumit Saxena #include <cam/cam_ccb.h> 482d1d418eSSumit Saxena #include "mpi3mr_cam.h" 492d1d418eSSumit Saxena #include "mpi3mr_app.h" 502d1d418eSSumit Saxena #include "mpi3mr.h" 512d1d418eSSumit Saxena 522d1d418eSSumit Saxena static d_open_t mpi3mr_open; 532d1d418eSSumit Saxena static d_close_t mpi3mr_close; 542d1d418eSSumit Saxena static d_ioctl_t mpi3mr_ioctl; 552d1d418eSSumit Saxena static d_poll_t mpi3mr_poll; 562d1d418eSSumit Saxena 572d1d418eSSumit Saxena static struct cdevsw mpi3mr_cdevsw = { 582d1d418eSSumit Saxena .d_version = D_VERSION, 592d1d418eSSumit Saxena .d_flags = 0, 602d1d418eSSumit Saxena .d_open = mpi3mr_open, 612d1d418eSSumit Saxena .d_close = mpi3mr_close, 622d1d418eSSumit Saxena .d_ioctl = mpi3mr_ioctl, 632d1d418eSSumit Saxena .d_poll = mpi3mr_poll, 642d1d418eSSumit Saxena .d_name = "mpi3mr", 652d1d418eSSumit Saxena }; 662d1d418eSSumit Saxena 677a91ccd2SEd Maste static struct mpi3mr_mgmt_info mpi3mr_mgmt_info; 687a91ccd2SEd Maste 692d1d418eSSumit Saxena static int 702d1d418eSSumit Saxena mpi3mr_open(struct cdev *dev, int flags, int fmt, struct thread *td) 712d1d418eSSumit Saxena { 722d1d418eSSumit Saxena 732d1d418eSSumit Saxena return (0); 742d1d418eSSumit Saxena } 752d1d418eSSumit Saxena 762d1d418eSSumit Saxena static int 772d1d418eSSumit Saxena mpi3mr_close(struct cdev *dev, int flags, int fmt, struct thread *td) 782d1d418eSSumit Saxena { 792d1d418eSSumit Saxena 802d1d418eSSumit Saxena return (0); 812d1d418eSSumit Saxena } 822d1d418eSSumit Saxena 832d1d418eSSumit Saxena /* 842d1d418eSSumit Saxena * mpi3mr_app_attach - Char device registration 852d1d418eSSumit Saxena * @sc: Adapter reference 862d1d418eSSumit Saxena * 872d1d418eSSumit Saxena * This function does char device registration. 882d1d418eSSumit Saxena * 892d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 902d1d418eSSumit Saxena */ 912d1d418eSSumit Saxena int 922d1d418eSSumit Saxena mpi3mr_app_attach(struct mpi3mr_softc *sc) 932d1d418eSSumit Saxena { 942d1d418eSSumit Saxena 952d1d418eSSumit Saxena /* Create a /dev entry for Avenger controller */ 962d1d418eSSumit Saxena sc->mpi3mr_cdev = make_dev(&mpi3mr_cdevsw, device_get_unit(sc->mpi3mr_dev), 972d1d418eSSumit Saxena UID_ROOT, GID_OPERATOR, 0640, "mpi3mr%d", 982d1d418eSSumit Saxena device_get_unit(sc->mpi3mr_dev)); 992d1d418eSSumit Saxena 1002d1d418eSSumit Saxena if (sc->mpi3mr_cdev == NULL) 1012d1d418eSSumit Saxena return (ENOMEM); 1022d1d418eSSumit Saxena 1032d1d418eSSumit Saxena sc->mpi3mr_cdev->si_drv1 = sc; 1042d1d418eSSumit Saxena 1052d1d418eSSumit Saxena /* Assign controller instance to mgmt_info structure */ 1062d1d418eSSumit Saxena if (device_get_unit(sc->mpi3mr_dev) == 0) 1072d1d418eSSumit Saxena memset(&mpi3mr_mgmt_info, 0, sizeof(mpi3mr_mgmt_info)); 1082d1d418eSSumit Saxena mpi3mr_mgmt_info.count++; 1092d1d418eSSumit Saxena mpi3mr_mgmt_info.sc_ptr[mpi3mr_mgmt_info.max_index] = sc; 1102d1d418eSSumit Saxena mpi3mr_mgmt_info.max_index++; 1112d1d418eSSumit Saxena 1122d1d418eSSumit Saxena return (0); 1132d1d418eSSumit Saxena } 1142d1d418eSSumit Saxena 1152d1d418eSSumit Saxena void 1162d1d418eSSumit Saxena mpi3mr_app_detach(struct mpi3mr_softc *sc) 1172d1d418eSSumit Saxena { 1182d1d418eSSumit Saxena U8 i = 0; 1192d1d418eSSumit Saxena 1202d1d418eSSumit Saxena if (sc->mpi3mr_cdev == NULL) 1212d1d418eSSumit Saxena return; 1222d1d418eSSumit Saxena 1232d1d418eSSumit Saxena destroy_dev(sc->mpi3mr_cdev); 1242d1d418eSSumit Saxena for (i = 0; i < mpi3mr_mgmt_info.max_index; i++) { 1252d1d418eSSumit Saxena if (mpi3mr_mgmt_info.sc_ptr[i] == sc) { 1262d1d418eSSumit Saxena mpi3mr_mgmt_info.count--; 1272d1d418eSSumit Saxena mpi3mr_mgmt_info.sc_ptr[i] = NULL; 1282d1d418eSSumit Saxena break; 1292d1d418eSSumit Saxena } 1302d1d418eSSumit Saxena } 1312d1d418eSSumit Saxena return; 1322d1d418eSSumit Saxena } 1332d1d418eSSumit Saxena 1342d1d418eSSumit Saxena static int 1352d1d418eSSumit Saxena mpi3mr_poll(struct cdev *dev, int poll_events, struct thread *td) 1362d1d418eSSumit Saxena { 1372d1d418eSSumit Saxena int revents = 0; 1382d1d418eSSumit Saxena struct mpi3mr_softc *sc = NULL; 1392d1d418eSSumit Saxena sc = dev->si_drv1; 1402d1d418eSSumit Saxena 1412d1d418eSSumit Saxena if ((poll_events & (POLLIN | POLLRDNORM)) && 1422d1d418eSSumit Saxena (sc->mpi3mr_aen_triggered)) 1432d1d418eSSumit Saxena revents |= poll_events & (POLLIN | POLLRDNORM); 1442d1d418eSSumit Saxena 1452d1d418eSSumit Saxena if (revents == 0) { 1462d1d418eSSumit Saxena if (poll_events & (POLLIN | POLLRDNORM)) { 1472d1d418eSSumit Saxena sc->mpi3mr_poll_waiting = 1; 1482d1d418eSSumit Saxena selrecord(td, &sc->mpi3mr_select); 1492d1d418eSSumit Saxena } 1502d1d418eSSumit Saxena } 1512d1d418eSSumit Saxena return revents; 1522d1d418eSSumit Saxena } 1532d1d418eSSumit Saxena 1542d1d418eSSumit Saxena /** 1552d1d418eSSumit Saxena * mpi3mr_app_get_adp_instancs - Get Adapter instance 1562d1d418eSSumit Saxena * @mrioc_id: Adapter ID 1572d1d418eSSumit Saxena * 1582d1d418eSSumit Saxena * This fucnction searches the Adapter reference with mrioc_id 1592d1d418eSSumit Saxena * upon found, returns the adapter reference otherwise returns 1602d1d418eSSumit Saxena * the NULL 1612d1d418eSSumit Saxena * 1622d1d418eSSumit Saxena * Return: Adapter reference on success and NULL on failure 1632d1d418eSSumit Saxena */ 1642d1d418eSSumit Saxena static struct mpi3mr_softc * 1652d1d418eSSumit Saxena mpi3mr_app_get_adp_instance(U8 mrioc_id) 1662d1d418eSSumit Saxena { 1672d1d418eSSumit Saxena struct mpi3mr_softc *sc = NULL; 1682d1d418eSSumit Saxena 1692d1d418eSSumit Saxena if (mrioc_id >= mpi3mr_mgmt_info.max_index) 1702d1d418eSSumit Saxena return NULL; 1712d1d418eSSumit Saxena 1722d1d418eSSumit Saxena sc = mpi3mr_mgmt_info.sc_ptr[mrioc_id]; 1732d1d418eSSumit Saxena return sc; 1742d1d418eSSumit Saxena } 1752d1d418eSSumit Saxena 1762d1d418eSSumit Saxena static int 1772d1d418eSSumit Saxena mpi3mr_app_construct_nvme_sgl(struct mpi3mr_softc *sc, 1782d1d418eSSumit Saxena Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request, 1792d1d418eSSumit Saxena struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, U8 bufcnt) 1802d1d418eSSumit Saxena { 1812d1d418eSSumit Saxena struct mpi3mr_nvme_pt_sge *nvme_sgl; 1822d1d418eSSumit Saxena U64 sgl_dma; 1832d1d418eSSumit Saxena U8 count; 1842d1d418eSSumit Saxena U16 available_sges = 0, i; 1852d1d418eSSumit Saxena U32 sge_element_size = sizeof(struct mpi3mr_nvme_pt_sge); 1862d1d418eSSumit Saxena size_t length = 0; 1872d1d418eSSumit Saxena struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; 1882d1d418eSSumit Saxena U64 sgemod_mask = ((U64)((sc->facts.sge_mod_mask) << 1892d1d418eSSumit Saxena sc->facts.sge_mod_shift) << 32); 1902d1d418eSSumit Saxena U64 sgemod_val = ((U64)(sc->facts.sge_mod_value) << 1912d1d418eSSumit Saxena sc->facts.sge_mod_shift) << 32; 1922d1d418eSSumit Saxena 1932d1d418eSSumit Saxena U32 size; 1942d1d418eSSumit Saxena 1952d1d418eSSumit Saxena nvme_sgl = (struct mpi3mr_nvme_pt_sge *) 1962d1d418eSSumit Saxena ((U8 *)(nvme_encap_request->Command) + MPI3MR_NVME_CMD_SGL_OFFSET); 1972d1d418eSSumit Saxena 1982d1d418eSSumit Saxena /* 1992d1d418eSSumit Saxena * Not all commands require a data transfer. If no data, just return 2002d1d418eSSumit Saxena * without constructing any SGL. 2012d1d418eSSumit Saxena */ 2022d1d418eSSumit Saxena for (count = 0; count < bufcnt; count++, dma_buff++) { 2032d1d418eSSumit Saxena if ((dma_buff->data_dir == MPI3MR_APP_DDI) || 2042d1d418eSSumit Saxena (dma_buff->data_dir == MPI3MR_APP_DDO)) { 2052d1d418eSSumit Saxena length = dma_buff->kern_buf_len; 2062d1d418eSSumit Saxena break; 2072d1d418eSSumit Saxena } 2082d1d418eSSumit Saxena } 2092d1d418eSSumit Saxena if (!length || !dma_buff->num_dma_desc) 2102d1d418eSSumit Saxena return 0; 2112d1d418eSSumit Saxena 2122d1d418eSSumit Saxena if (dma_buff->num_dma_desc == 1) { 2132d1d418eSSumit Saxena available_sges = 1; 2142d1d418eSSumit Saxena goto build_sges; 2152d1d418eSSumit Saxena } 2162d1d418eSSumit Saxena sgl_dma = (U64)sc->ioctl_chain_sge.dma_addr; 2172d1d418eSSumit Saxena 2182d1d418eSSumit Saxena if (sgl_dma & sgemod_mask) { 2192d1d418eSSumit Saxena printf(IOCNAME "NVMe SGL address collides with SGEModifier\n",sc->name); 2202d1d418eSSumit Saxena return -1; 2212d1d418eSSumit Saxena } 2222d1d418eSSumit Saxena 2232d1d418eSSumit Saxena sgl_dma &= ~sgemod_mask; 2242d1d418eSSumit Saxena sgl_dma |= sgemod_val; 2252d1d418eSSumit Saxena 2262d1d418eSSumit Saxena memset(sc->ioctl_chain_sge.addr, 0, sc->ioctl_chain_sge.size); 2272d1d418eSSumit Saxena available_sges = sc->ioctl_chain_sge.size / sge_element_size; 2282d1d418eSSumit Saxena if (available_sges < dma_buff->num_dma_desc) 2292d1d418eSSumit Saxena return -1; 2302d1d418eSSumit Saxena memset(nvme_sgl, 0, sizeof(struct mpi3mr_nvme_pt_sge)); 2312d1d418eSSumit Saxena nvme_sgl->base_addr = sgl_dma; 2322d1d418eSSumit Saxena size = dma_buff->num_dma_desc * sizeof(struct mpi3mr_nvme_pt_sge); 2332d1d418eSSumit Saxena nvme_sgl->length = htole32(size); 2342d1d418eSSumit Saxena nvme_sgl->type = MPI3MR_NVMESGL_LAST_SEGMENT; 2352d1d418eSSumit Saxena 2362d1d418eSSumit Saxena nvme_sgl = (struct mpi3mr_nvme_pt_sge *) sc->ioctl_chain_sge.addr; 2372d1d418eSSumit Saxena 2382d1d418eSSumit Saxena build_sges: 2392d1d418eSSumit Saxena for (i = 0; i < dma_buff->num_dma_desc; i++) { 2402d1d418eSSumit Saxena sgl_dma = htole64(dma_buff->dma_desc[i].dma_addr); 2412d1d418eSSumit Saxena if (sgl_dma & sgemod_mask) { 2422d1d418eSSumit Saxena printf("%s: SGL address collides with SGE modifier\n", 2432d1d418eSSumit Saxena __func__); 2442d1d418eSSumit Saxena return -1; 2452d1d418eSSumit Saxena } 2462d1d418eSSumit Saxena 2472d1d418eSSumit Saxena sgl_dma &= ~sgemod_mask; 2482d1d418eSSumit Saxena sgl_dma |= sgemod_val; 2492d1d418eSSumit Saxena 2502d1d418eSSumit Saxena nvme_sgl->base_addr = sgl_dma; 2512d1d418eSSumit Saxena nvme_sgl->length = htole32(dma_buff->dma_desc[i].size); 2522d1d418eSSumit Saxena nvme_sgl->type = MPI3MR_NVMESGL_DATA_SEGMENT; 2532d1d418eSSumit Saxena nvme_sgl++; 2542d1d418eSSumit Saxena available_sges--; 2552d1d418eSSumit Saxena } 2562d1d418eSSumit Saxena 2572d1d418eSSumit Saxena return 0; 2582d1d418eSSumit Saxena } 2592d1d418eSSumit Saxena 2602d1d418eSSumit Saxena static int 2612d1d418eSSumit Saxena mpi3mr_app_build_nvme_prp(struct mpi3mr_softc *sc, 2622d1d418eSSumit Saxena Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request, 2632d1d418eSSumit Saxena struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, U8 bufcnt) 2642d1d418eSSumit Saxena { 2652d1d418eSSumit Saxena int prp_size = MPI3MR_NVME_PRP_SIZE; 2662d1d418eSSumit Saxena U64 *prp_entry, *prp1_entry, *prp2_entry; 2672d1d418eSSumit Saxena U64 *prp_page; 2682d1d418eSSumit Saxena bus_addr_t prp_entry_dma, prp_page_dma, dma_addr; 2692d1d418eSSumit Saxena U32 offset, entry_len, dev_pgsz; 2702d1d418eSSumit Saxena U32 page_mask_result, page_mask; 2712d1d418eSSumit Saxena size_t length = 0, desc_len; 2722d1d418eSSumit Saxena U8 count; 2732d1d418eSSumit Saxena struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; 2742d1d418eSSumit Saxena U64 sgemod_mask = ((U64)((sc->facts.sge_mod_mask) << 2752d1d418eSSumit Saxena sc->facts.sge_mod_shift) << 32); 2762d1d418eSSumit Saxena U64 sgemod_val = ((U64)(sc->facts.sge_mod_value) << 2772d1d418eSSumit Saxena sc->facts.sge_mod_shift) << 32; 2782d1d418eSSumit Saxena U16 dev_handle = nvme_encap_request->DevHandle; 2792d1d418eSSumit Saxena struct mpi3mr_target *tgtdev; 2802d1d418eSSumit Saxena U16 desc_count = 0; 2812d1d418eSSumit Saxena 2822d1d418eSSumit Saxena tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, dev_handle); 2832d1d418eSSumit Saxena if (!tgtdev) { 2842d1d418eSSumit Saxena printf(IOCNAME "EncapNVMe Error: Invalid DevHandle 0x%02x\n", sc->name, 2852d1d418eSSumit Saxena dev_handle); 2862d1d418eSSumit Saxena return -1; 2872d1d418eSSumit Saxena } 2882d1d418eSSumit Saxena if (tgtdev->dev_spec.pcie_inf.pgsz == 0) { 2892d1d418eSSumit Saxena printf(IOCNAME "%s: NVME device page size is zero for handle 0x%04x\n", 2902d1d418eSSumit Saxena sc->name, __func__, dev_handle); 2912d1d418eSSumit Saxena return -1; 2922d1d418eSSumit Saxena } 2932d1d418eSSumit Saxena dev_pgsz = 1 << (tgtdev->dev_spec.pcie_inf.pgsz); 2942d1d418eSSumit Saxena 2952d1d418eSSumit Saxena page_mask = dev_pgsz - 1; 2962d1d418eSSumit Saxena 2972d1d418eSSumit Saxena if (dev_pgsz > MPI3MR_IOCTL_SGE_SIZE){ 2982d1d418eSSumit Saxena printf("%s: NVMe device page size(%d) is greater than ioctl data sge size(%d) for handle 0x%04x\n", 2992d1d418eSSumit Saxena __func__, dev_pgsz, MPI3MR_IOCTL_SGE_SIZE, dev_handle); 3002d1d418eSSumit Saxena return -1; 3012d1d418eSSumit Saxena } 3022d1d418eSSumit Saxena 3032d1d418eSSumit Saxena if (MPI3MR_IOCTL_SGE_SIZE % dev_pgsz){ 3042d1d418eSSumit Saxena printf("%s: ioctl data sge size(%d) is not a multiple of NVMe device page size(%d) for handle 0x%04x\n", 3052d1d418eSSumit Saxena __func__, MPI3MR_IOCTL_SGE_SIZE, dev_pgsz, dev_handle); 3062d1d418eSSumit Saxena return -1; 3072d1d418eSSumit Saxena } 3082d1d418eSSumit Saxena 3092d1d418eSSumit Saxena /* 3102d1d418eSSumit Saxena * Not all commands require a data transfer. If no data, just return 3112d1d418eSSumit Saxena * without constructing any PRP. 3122d1d418eSSumit Saxena */ 3132d1d418eSSumit Saxena for (count = 0; count < bufcnt; count++, dma_buff++) { 3142d1d418eSSumit Saxena if ((dma_buff->data_dir == MPI3MR_APP_DDI) || 3152d1d418eSSumit Saxena (dma_buff->data_dir == MPI3MR_APP_DDO)) { 3162d1d418eSSumit Saxena length = dma_buff->kern_buf_len; 3172d1d418eSSumit Saxena break; 3182d1d418eSSumit Saxena } 3192d1d418eSSumit Saxena } 3202d1d418eSSumit Saxena if (!length || !dma_buff->num_dma_desc) 3212d1d418eSSumit Saxena return 0; 3222d1d418eSSumit Saxena 3232d1d418eSSumit Saxena for (count = 0; count < dma_buff->num_dma_desc; count++) { 3242d1d418eSSumit Saxena dma_addr = dma_buff->dma_desc[count].dma_addr; 3252d1d418eSSumit Saxena if (dma_addr & page_mask) { 3262d1d418eSSumit Saxena printf("%s:dma_addr 0x%lu is not aligned with page size 0x%x\n", 3272d1d418eSSumit Saxena __func__, dma_addr, dev_pgsz); 3282d1d418eSSumit Saxena return -1; 3292d1d418eSSumit Saxena } 3302d1d418eSSumit Saxena } 3312d1d418eSSumit Saxena 3322d1d418eSSumit Saxena dma_addr = dma_buff->dma_desc[0].dma_addr; 3332d1d418eSSumit Saxena desc_len = dma_buff->dma_desc[0].size; 3342d1d418eSSumit Saxena 3352d1d418eSSumit Saxena sc->nvme_encap_prp_sz = 0; 3362d1d418eSSumit Saxena if (bus_dma_tag_create(sc->mpi3mr_parent_dmat, /* parent */ 3372d1d418eSSumit Saxena 4, 0, /* algnmnt, boundary */ 338ee7c431cSWarner Losh sc->dma_loaddr, /* lowaddr */ 3391ec7c672SWarner Losh BUS_SPACE_MAXADDR, /* highaddr */ 3402d1d418eSSumit Saxena NULL, NULL, /* filter, filterarg */ 3412d1d418eSSumit Saxena dev_pgsz, /* maxsize */ 3422d1d418eSSumit Saxena 1, /* nsegments */ 3432d1d418eSSumit Saxena dev_pgsz, /* maxsegsize */ 3442d1d418eSSumit Saxena 0, /* flags */ 3452d1d418eSSumit Saxena NULL, NULL, /* lockfunc, lockarg */ 3462d1d418eSSumit Saxena &sc->nvme_encap_prp_list_dmatag)) { 3472d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot create ioctl NVME kernel buffer dma tag\n"); 3482d1d418eSSumit Saxena return (ENOMEM); 3492d1d418eSSumit Saxena } 3502d1d418eSSumit Saxena 3512d1d418eSSumit Saxena if (bus_dmamem_alloc(sc->nvme_encap_prp_list_dmatag, (void **)&sc->nvme_encap_prp_list, 3522d1d418eSSumit Saxena BUS_DMA_NOWAIT, &sc->nvme_encap_prp_list_dma_dmamap)) { 3532d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "Cannot allocate ioctl NVME dma memory\n"); 3542d1d418eSSumit Saxena return (ENOMEM); 3552d1d418eSSumit Saxena } 3562d1d418eSSumit Saxena 3572d1d418eSSumit Saxena bzero(sc->nvme_encap_prp_list, dev_pgsz); 3582d1d418eSSumit Saxena bus_dmamap_load(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap, 3592d1d418eSSumit Saxena sc->nvme_encap_prp_list, dev_pgsz, mpi3mr_memaddr_cb, &sc->nvme_encap_prp_list_dma, 36039a3e6a8SAlexander Motin BUS_DMA_NOWAIT); 3612d1d418eSSumit Saxena 3622d1d418eSSumit Saxena if (!sc->nvme_encap_prp_list) { 3632d1d418eSSumit Saxena printf(IOCNAME "%s:%d Cannot load ioctl NVME dma memory for size: %d\n", sc->name, 3642d1d418eSSumit Saxena __func__, __LINE__, dev_pgsz); 3652d1d418eSSumit Saxena goto err_out; 3662d1d418eSSumit Saxena } 3672d1d418eSSumit Saxena sc->nvme_encap_prp_sz = dev_pgsz; 3682d1d418eSSumit Saxena 3692d1d418eSSumit Saxena /* 3702d1d418eSSumit Saxena * Set pointers to PRP1 and PRP2, which are in the NVMe command. 3712d1d418eSSumit Saxena * PRP1 is located at a 24 byte offset from the start of the NVMe 3722d1d418eSSumit Saxena * command. Then set the current PRP entry pointer to PRP1. 3732d1d418eSSumit Saxena */ 3742d1d418eSSumit Saxena prp1_entry = (U64 *)((U8 *)(nvme_encap_request->Command) + MPI3MR_NVME_CMD_PRP1_OFFSET); 3752d1d418eSSumit Saxena prp2_entry = (U64 *)((U8 *)(nvme_encap_request->Command) + MPI3MR_NVME_CMD_PRP2_OFFSET); 3762d1d418eSSumit Saxena prp_entry = prp1_entry; 3772d1d418eSSumit Saxena /* 3782d1d418eSSumit Saxena * For the PRP entries, use the specially allocated buffer of 3792d1d418eSSumit Saxena * contiguous memory. 3802d1d418eSSumit Saxena */ 3812d1d418eSSumit Saxena prp_page = sc->nvme_encap_prp_list; 3822d1d418eSSumit Saxena prp_page_dma = sc->nvme_encap_prp_list_dma; 3832d1d418eSSumit Saxena 3842d1d418eSSumit Saxena /* 3852d1d418eSSumit Saxena * Check if we are within 1 entry of a page boundary we don't 3862d1d418eSSumit Saxena * want our first entry to be a PRP List entry. 3872d1d418eSSumit Saxena */ 3882d1d418eSSumit Saxena page_mask_result = (uintptr_t)((U8 *)prp_page + prp_size) & page_mask; 3892d1d418eSSumit Saxena if (!page_mask_result) { 3902d1d418eSSumit Saxena printf(IOCNAME "PRP Page is not page aligned\n", sc->name); 3912d1d418eSSumit Saxena goto err_out; 3922d1d418eSSumit Saxena } 3932d1d418eSSumit Saxena 3942d1d418eSSumit Saxena /* 3952d1d418eSSumit Saxena * Set PRP physical pointer, which initially points to the current PRP 3962d1d418eSSumit Saxena * DMA memory page. 3972d1d418eSSumit Saxena */ 3982d1d418eSSumit Saxena prp_entry_dma = prp_page_dma; 3992d1d418eSSumit Saxena 4002d1d418eSSumit Saxena 4012d1d418eSSumit Saxena /* Loop while the length is not zero. */ 4022d1d418eSSumit Saxena while (length) { 4032d1d418eSSumit Saxena page_mask_result = (prp_entry_dma + prp_size) & page_mask; 4042d1d418eSSumit Saxena if (!page_mask_result && (length > dev_pgsz)) { 4052d1d418eSSumit Saxena printf(IOCNAME "Single PRP page is not sufficient\n", sc->name); 4062d1d418eSSumit Saxena goto err_out; 4072d1d418eSSumit Saxena } 4082d1d418eSSumit Saxena 4092d1d418eSSumit Saxena /* Need to handle if entry will be part of a page. */ 4102d1d418eSSumit Saxena offset = dma_addr & page_mask; 4112d1d418eSSumit Saxena entry_len = dev_pgsz - offset; 4122d1d418eSSumit Saxena 4132d1d418eSSumit Saxena if (prp_entry == prp1_entry) { 4142d1d418eSSumit Saxena /* 4152d1d418eSSumit Saxena * Must fill in the first PRP pointer (PRP1) before 4162d1d418eSSumit Saxena * moving on. 4172d1d418eSSumit Saxena */ 4182d1d418eSSumit Saxena *prp1_entry = dma_addr; 4192d1d418eSSumit Saxena if (*prp1_entry & sgemod_mask) { 4202d1d418eSSumit Saxena printf(IOCNAME "PRP1 address collides with SGEModifier\n", sc->name); 4212d1d418eSSumit Saxena goto err_out; 4222d1d418eSSumit Saxena } 4232d1d418eSSumit Saxena *prp1_entry &= ~sgemod_mask; 4242d1d418eSSumit Saxena *prp1_entry |= sgemod_val; 4252d1d418eSSumit Saxena 4262d1d418eSSumit Saxena /* 4272d1d418eSSumit Saxena * Now point to the second PRP entry within the 4282d1d418eSSumit Saxena * command (PRP2). 4292d1d418eSSumit Saxena */ 4302d1d418eSSumit Saxena prp_entry = prp2_entry; 4312d1d418eSSumit Saxena } else if (prp_entry == prp2_entry) { 4322d1d418eSSumit Saxena /* 4332d1d418eSSumit Saxena * Should the PRP2 entry be a PRP List pointer or just 4342d1d418eSSumit Saxena * a regular PRP pointer? If there is more than one 4352d1d418eSSumit Saxena * more page of data, must use a PRP List pointer. 4362d1d418eSSumit Saxena */ 4372d1d418eSSumit Saxena if (length > dev_pgsz) { 4382d1d418eSSumit Saxena /* 4392d1d418eSSumit Saxena * PRP2 will contain a PRP List pointer because 4402d1d418eSSumit Saxena * more PRP's are needed with this command. The 4412d1d418eSSumit Saxena * list will start at the beginning of the 4422d1d418eSSumit Saxena * contiguous buffer. 4432d1d418eSSumit Saxena */ 4442d1d418eSSumit Saxena *prp2_entry = prp_entry_dma; 4452d1d418eSSumit Saxena if (*prp2_entry & sgemod_mask) { 4462d1d418eSSumit Saxena printf(IOCNAME "PRP list address collides with SGEModifier\n", sc->name); 4472d1d418eSSumit Saxena goto err_out; 4482d1d418eSSumit Saxena } 4492d1d418eSSumit Saxena *prp2_entry &= ~sgemod_mask; 4502d1d418eSSumit Saxena *prp2_entry |= sgemod_val; 4512d1d418eSSumit Saxena 4522d1d418eSSumit Saxena /* 4532d1d418eSSumit Saxena * The next PRP Entry will be the start of the 4542d1d418eSSumit Saxena * first PRP List. 4552d1d418eSSumit Saxena */ 4562d1d418eSSumit Saxena prp_entry = prp_page; 4572d1d418eSSumit Saxena continue; 4582d1d418eSSumit Saxena } else { 4592d1d418eSSumit Saxena /* 4602d1d418eSSumit Saxena * After this, the PRP Entries are complete. 4612d1d418eSSumit Saxena * This command uses 2 PRP's and no PRP list. 4622d1d418eSSumit Saxena */ 4632d1d418eSSumit Saxena *prp2_entry = dma_addr; 4642d1d418eSSumit Saxena if (*prp2_entry & sgemod_mask) { 4652d1d418eSSumit Saxena printf(IOCNAME "PRP2 address collides with SGEModifier\n", sc->name); 4662d1d418eSSumit Saxena goto err_out; 4672d1d418eSSumit Saxena } 4682d1d418eSSumit Saxena *prp2_entry &= ~sgemod_mask; 4692d1d418eSSumit Saxena *prp2_entry |= sgemod_val; 4702d1d418eSSumit Saxena } 4712d1d418eSSumit Saxena } else { 4722d1d418eSSumit Saxena /* 4732d1d418eSSumit Saxena * Put entry in list and bump the addresses. 4742d1d418eSSumit Saxena * 4752d1d418eSSumit Saxena * After PRP1 and PRP2 are filled in, this will fill in 4762d1d418eSSumit Saxena * all remaining PRP entries in a PRP List, one per 4772d1d418eSSumit Saxena * each time through the loop. 4782d1d418eSSumit Saxena */ 4792d1d418eSSumit Saxena *prp_entry = dma_addr; 4802d1d418eSSumit Saxena if (*prp_entry & sgemod_mask) { 4812d1d418eSSumit Saxena printf(IOCNAME "PRP address collides with SGEModifier\n", sc->name); 4822d1d418eSSumit Saxena goto err_out; 4832d1d418eSSumit Saxena } 4842d1d418eSSumit Saxena *prp_entry &= ~sgemod_mask; 4852d1d418eSSumit Saxena *prp_entry |= sgemod_val; 4862d1d418eSSumit Saxena prp_entry++; 4872d1d418eSSumit Saxena prp_entry_dma += prp_size; 4882d1d418eSSumit Saxena } 4892d1d418eSSumit Saxena 4902d1d418eSSumit Saxena /* Decrement length accounting for last partial page. */ 4912d1d418eSSumit Saxena if (entry_len >= length) 4922d1d418eSSumit Saxena length = 0; 4932d1d418eSSumit Saxena else { 4942d1d418eSSumit Saxena if (entry_len <= desc_len) { 4952d1d418eSSumit Saxena dma_addr += entry_len; 4962d1d418eSSumit Saxena desc_len -= entry_len; 4972d1d418eSSumit Saxena } 4982d1d418eSSumit Saxena if (!desc_len) { 4992d1d418eSSumit Saxena if ((++desc_count) >= 5002d1d418eSSumit Saxena dma_buff->num_dma_desc) { 5012d1d418eSSumit Saxena printf("%s: Invalid len %ld while building PRP\n", 5022d1d418eSSumit Saxena __func__, length); 5032d1d418eSSumit Saxena goto err_out; 5042d1d418eSSumit Saxena } 5052d1d418eSSumit Saxena dma_addr = 5062d1d418eSSumit Saxena dma_buff->dma_desc[desc_count].dma_addr; 5072d1d418eSSumit Saxena desc_len = 5082d1d418eSSumit Saxena dma_buff->dma_desc[desc_count].size; 5092d1d418eSSumit Saxena } 5102d1d418eSSumit Saxena length -= entry_len; 5112d1d418eSSumit Saxena } 5122d1d418eSSumit Saxena } 5132d1d418eSSumit Saxena return 0; 5142d1d418eSSumit Saxena err_out: 5152d1d418eSSumit Saxena if (sc->nvme_encap_prp_list && sc->nvme_encap_prp_list_dma) { 5162d1d418eSSumit Saxena bus_dmamap_unload(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap); 5172d1d418eSSumit Saxena bus_dmamem_free(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list, sc->nvme_encap_prp_list_dma_dmamap); 5182d1d418eSSumit Saxena bus_dma_tag_destroy(sc->nvme_encap_prp_list_dmatag); 5192d1d418eSSumit Saxena sc->nvme_encap_prp_list = NULL; 5202d1d418eSSumit Saxena } 5212d1d418eSSumit Saxena return -1; 5222d1d418eSSumit Saxena } 5232d1d418eSSumit Saxena 5242d1d418eSSumit Saxena /** 5252d1d418eSSumit Saxena + * mpi3mr_map_data_buffer_dma - build dma descriptors for data 5262d1d418eSSumit Saxena + * buffers 5272d1d418eSSumit Saxena + * @sc: Adapter instance reference 5282d1d418eSSumit Saxena + * @dma_buff: buffer map descriptor 5292d1d418eSSumit Saxena + * @desc_count: Number of already consumed dma descriptors 5302d1d418eSSumit Saxena + * 5312d1d418eSSumit Saxena + * This function computes how many pre-allocated DMA descriptors 5322d1d418eSSumit Saxena + * are required for the given data buffer and if those number of 5332d1d418eSSumit Saxena + * descriptors are free, then setup the mapping of the scattered 5342d1d418eSSumit Saxena + * DMA address to the given data buffer, if the data direction 5352d1d418eSSumit Saxena + * of the buffer is DATA_OUT then the actual data is copied to 5362d1d418eSSumit Saxena + * the DMA buffers 5372d1d418eSSumit Saxena + * 5382d1d418eSSumit Saxena + * Return: 0 on success, -1 on failure 5392d1d418eSSumit Saxena + */ 5402d1d418eSSumit Saxena static int mpi3mr_map_data_buffer_dma(struct mpi3mr_softc *sc, 5412d1d418eSSumit Saxena struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, 5422d1d418eSSumit Saxena U8 desc_count) 5432d1d418eSSumit Saxena { 5442d1d418eSSumit Saxena U16 i, needed_desc = (dma_buffers->kern_buf_len / MPI3MR_IOCTL_SGE_SIZE); 5452d1d418eSSumit Saxena U32 buf_len = dma_buffers->kern_buf_len, copied_len = 0; 5466bfb7306SMark Johnston int error; 5472d1d418eSSumit Saxena 5482d1d418eSSumit Saxena if (dma_buffers->kern_buf_len % MPI3MR_IOCTL_SGE_SIZE) 5492d1d418eSSumit Saxena needed_desc++; 5502d1d418eSSumit Saxena 5512d1d418eSSumit Saxena if ((needed_desc + desc_count) > MPI3MR_NUM_IOCTL_SGE) { 5522d1d418eSSumit Saxena printf("%s: DMA descriptor mapping error %d:%d:%d\n", 5532d1d418eSSumit Saxena __func__, needed_desc, desc_count, MPI3MR_NUM_IOCTL_SGE); 5542d1d418eSSumit Saxena return -1; 5552d1d418eSSumit Saxena } 5562d1d418eSSumit Saxena 5572d1d418eSSumit Saxena dma_buffers->dma_desc = malloc(sizeof(*dma_buffers->dma_desc) * needed_desc, 5582d1d418eSSumit Saxena M_MPI3MR, M_NOWAIT | M_ZERO); 5592d1d418eSSumit Saxena if (!dma_buffers->dma_desc) 5602d1d418eSSumit Saxena return -1; 5612d1d418eSSumit Saxena 5626bfb7306SMark Johnston error = 0; 5632d1d418eSSumit Saxena for (i = 0; i < needed_desc; i++, desc_count++) { 5642d1d418eSSumit Saxena 5652d1d418eSSumit Saxena dma_buffers->dma_desc[i].addr = sc->ioctl_sge[desc_count].addr; 5662d1d418eSSumit Saxena dma_buffers->dma_desc[i].dma_addr = sc->ioctl_sge[desc_count].dma_addr; 5672d1d418eSSumit Saxena 5682d1d418eSSumit Saxena if (buf_len < sc->ioctl_sge[desc_count].size) 5692d1d418eSSumit Saxena dma_buffers->dma_desc[i].size = buf_len; 5702d1d418eSSumit Saxena else 5712d1d418eSSumit Saxena dma_buffers->dma_desc[i].size = sc->ioctl_sge[desc_count].size; 5722d1d418eSSumit Saxena 5732d1d418eSSumit Saxena buf_len -= dma_buffers->dma_desc[i].size; 5742d1d418eSSumit Saxena memset(dma_buffers->dma_desc[i].addr, 0, sc->ioctl_sge[desc_count].size); 5752d1d418eSSumit Saxena 5762d1d418eSSumit Saxena if (dma_buffers->data_dir == MPI3MR_APP_DDO) { 5776bfb7306SMark Johnston error = copyin(((U8 *)dma_buffers->user_buf + copied_len), 5782d1d418eSSumit Saxena dma_buffers->dma_desc[i].addr, 5792d1d418eSSumit Saxena dma_buffers->dma_desc[i].size); 5806bfb7306SMark Johnston if (error != 0) 5816bfb7306SMark Johnston break; 5822d1d418eSSumit Saxena copied_len += dma_buffers->dma_desc[i].size; 5832d1d418eSSumit Saxena } 5842d1d418eSSumit Saxena } 5856bfb7306SMark Johnston if (error != 0) { 5866bfb7306SMark Johnston printf("%s: DMA copyin error %d\n", __func__, error); 5876bfb7306SMark Johnston free(dma_buffers->dma_desc, M_MPI3MR); 5886bfb7306SMark Johnston return -1; 5896bfb7306SMark Johnston } 5902d1d418eSSumit Saxena 5912d1d418eSSumit Saxena dma_buffers->num_dma_desc = needed_desc; 5922d1d418eSSumit Saxena 5932d1d418eSSumit Saxena return 0; 5942d1d418eSSumit Saxena } 5952d1d418eSSumit Saxena 5962d1d418eSSumit Saxena static unsigned int 5972d1d418eSSumit Saxena mpi3mr_app_get_nvme_data_fmt(Mpi3NVMeEncapsulatedRequest_t *nvme_encap_request) 5982d1d418eSSumit Saxena { 5992d1d418eSSumit Saxena U8 format = 0; 6002d1d418eSSumit Saxena 6012d1d418eSSumit Saxena format = ((nvme_encap_request->Command[0] & 0xc000) >> 14); 6022d1d418eSSumit Saxena return format; 6032d1d418eSSumit Saxena } 6042d1d418eSSumit Saxena 6052d1d418eSSumit Saxena static inline U16 mpi3mr_total_num_ioctl_sges(struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, 6062d1d418eSSumit Saxena U8 bufcnt) 6072d1d418eSSumit Saxena { 6082d1d418eSSumit Saxena U16 i, sge_count = 0; 6092d1d418eSSumit Saxena for (i=0; i < bufcnt; i++, dma_buffers++) { 6102d1d418eSSumit Saxena if ((dma_buffers->data_dir == MPI3MR_APP_DDN) || 6112d1d418eSSumit Saxena dma_buffers->kern_buf) 6122d1d418eSSumit Saxena continue; 6132d1d418eSSumit Saxena sge_count += dma_buffers->num_dma_desc; 6142d1d418eSSumit Saxena if (!dma_buffers->num_dma_desc) 6152d1d418eSSumit Saxena sge_count++; 6162d1d418eSSumit Saxena } 6172d1d418eSSumit Saxena return sge_count; 6182d1d418eSSumit Saxena } 6192d1d418eSSumit Saxena 6202d1d418eSSumit Saxena static int 6212d1d418eSSumit Saxena mpi3mr_app_construct_sgl(struct mpi3mr_softc *sc, U8 *mpi_request, U32 sgl_offset, 6222d1d418eSSumit Saxena struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers, 6232d1d418eSSumit Saxena U8 bufcnt, U8 is_rmc, U8 is_rmr, U8 num_datasges) 6242d1d418eSSumit Saxena { 6252d1d418eSSumit Saxena U8 *sgl = (mpi_request + sgl_offset), count = 0; 6262d1d418eSSumit Saxena Mpi3RequestHeader_t *mpi_header = (Mpi3RequestHeader_t *)mpi_request; 6272d1d418eSSumit Saxena Mpi3MgmtPassthroughRequest_t *rmgmt_req = 6282d1d418eSSumit Saxena (Mpi3MgmtPassthroughRequest_t *)mpi_request; 6292d1d418eSSumit Saxena struct mpi3mr_ioctl_mpt_dma_buffer *dma_buff = dma_buffers; 6302d1d418eSSumit Saxena U8 flag, sgl_flags, sgl_flags_eob, sgl_flags_last, last_chain_sgl_flags; 6312d1d418eSSumit Saxena U16 available_sges, i, sges_needed; 6322d1d418eSSumit Saxena U32 sge_element_size = sizeof(struct _MPI3_SGE_COMMON); 6332d1d418eSSumit Saxena bool chain_used = false; 6342d1d418eSSumit Saxena 6352d1d418eSSumit Saxena sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | 6362d1d418eSSumit Saxena MPI3_SGE_FLAGS_DLAS_SYSTEM ; 6372d1d418eSSumit Saxena sgl_flags_eob = sgl_flags | MPI3_SGE_FLAGS_END_OF_BUFFER; 6382d1d418eSSumit Saxena sgl_flags_last = sgl_flags_eob | MPI3_SGE_FLAGS_END_OF_LIST; 6392d1d418eSSumit Saxena last_chain_sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | 6402d1d418eSSumit Saxena MPI3_SGE_FLAGS_DLAS_SYSTEM; 6412d1d418eSSumit Saxena 6422d1d418eSSumit Saxena sges_needed = mpi3mr_total_num_ioctl_sges(dma_buffers, bufcnt); 6432d1d418eSSumit Saxena 6442d1d418eSSumit Saxena if (is_rmc) { 6452d1d418eSSumit Saxena mpi3mr_add_sg_single(&rmgmt_req->CommandSGL, 6462d1d418eSSumit Saxena sgl_flags_last, dma_buff->kern_buf_len, 6472d1d418eSSumit Saxena dma_buff->kern_buf_dma); 6482d1d418eSSumit Saxena sgl = (U8 *) dma_buff->kern_buf + dma_buff->user_buf_len; 6492d1d418eSSumit Saxena available_sges = (dma_buff->kern_buf_len - 6502d1d418eSSumit Saxena dma_buff->user_buf_len) / sge_element_size; 6512d1d418eSSumit Saxena if (sges_needed > available_sges) 6522d1d418eSSumit Saxena return -1; 6532d1d418eSSumit Saxena chain_used = true; 6542d1d418eSSumit Saxena dma_buff++; 6552d1d418eSSumit Saxena count++; 6562d1d418eSSumit Saxena if (is_rmr) { 6572d1d418eSSumit Saxena mpi3mr_add_sg_single(&rmgmt_req->ResponseSGL, 6582d1d418eSSumit Saxena sgl_flags_last, dma_buff->kern_buf_len, 6592d1d418eSSumit Saxena dma_buff->kern_buf_dma); 6602d1d418eSSumit Saxena dma_buff++; 6612d1d418eSSumit Saxena count++; 6622d1d418eSSumit Saxena } else 6632d1d418eSSumit Saxena mpi3mr_build_zero_len_sge( 6642d1d418eSSumit Saxena &rmgmt_req->ResponseSGL); 6652d1d418eSSumit Saxena if (num_datasges) { 6662d1d418eSSumit Saxena i = 0; 6672d1d418eSSumit Saxena goto build_sges; 6682d1d418eSSumit Saxena } 6692d1d418eSSumit Saxena } else { 6702d1d418eSSumit Saxena if (sgl_offset >= MPI3MR_AREQ_FRAME_SZ) 6712d1d418eSSumit Saxena return -1; 6722d1d418eSSumit Saxena available_sges = (MPI3MR_AREQ_FRAME_SZ - sgl_offset) / 6732d1d418eSSumit Saxena sge_element_size; 6742d1d418eSSumit Saxena if (!available_sges) 6752d1d418eSSumit Saxena return -1; 6762d1d418eSSumit Saxena } 6772d1d418eSSumit Saxena 6782d1d418eSSumit Saxena if (!num_datasges) { 6792d1d418eSSumit Saxena mpi3mr_build_zero_len_sge(sgl); 6802d1d418eSSumit Saxena return 0; 6812d1d418eSSumit Saxena } 6822d1d418eSSumit Saxena 6832d1d418eSSumit Saxena if (mpi_header->Function == MPI3_FUNCTION_SMP_PASSTHROUGH) { 6842d1d418eSSumit Saxena if ((sges_needed > 2) || (sges_needed > available_sges)) 6852d1d418eSSumit Saxena return -1; 6862d1d418eSSumit Saxena for (; count < bufcnt; count++, dma_buff++) { 6872d1d418eSSumit Saxena if ((dma_buff->data_dir == MPI3MR_APP_DDN) || 6882d1d418eSSumit Saxena !dma_buff->num_dma_desc) 6892d1d418eSSumit Saxena continue; 6902d1d418eSSumit Saxena mpi3mr_add_sg_single(sgl, sgl_flags_last, 6912d1d418eSSumit Saxena dma_buff->dma_desc[0].size, 6922d1d418eSSumit Saxena dma_buff->dma_desc[0].dma_addr); 6932d1d418eSSumit Saxena sgl += sge_element_size; 6942d1d418eSSumit Saxena } 6952d1d418eSSumit Saxena return 0; 6962d1d418eSSumit Saxena } 6972d1d418eSSumit Saxena i = 0; 6982d1d418eSSumit Saxena 6992d1d418eSSumit Saxena build_sges: 7002d1d418eSSumit Saxena for (; count < bufcnt; count++, dma_buff++) { 7012d1d418eSSumit Saxena if (dma_buff->data_dir == MPI3MR_APP_DDN) 7022d1d418eSSumit Saxena continue; 7032d1d418eSSumit Saxena if (!dma_buff->num_dma_desc) { 7042d1d418eSSumit Saxena if (chain_used && !available_sges) 7052d1d418eSSumit Saxena return -1; 7062d1d418eSSumit Saxena if (!chain_used && (available_sges == 1) && 7072d1d418eSSumit Saxena (sges_needed > 1)) 7082d1d418eSSumit Saxena goto setup_chain; 7092d1d418eSSumit Saxena flag = sgl_flags_eob; 7102d1d418eSSumit Saxena if (num_datasges == 1) 7112d1d418eSSumit Saxena flag = sgl_flags_last; 7122d1d418eSSumit Saxena mpi3mr_add_sg_single(sgl, flag, 0, 0); 7132d1d418eSSumit Saxena sgl += sge_element_size; 7142d1d418eSSumit Saxena available_sges--; 7152d1d418eSSumit Saxena sges_needed--; 7162d1d418eSSumit Saxena num_datasges--; 7172d1d418eSSumit Saxena continue; 7182d1d418eSSumit Saxena } 7192d1d418eSSumit Saxena for (; i < dma_buff->num_dma_desc; i++) { 7202d1d418eSSumit Saxena if (chain_used && !available_sges) 7212d1d418eSSumit Saxena return -1; 7222d1d418eSSumit Saxena if (!chain_used && (available_sges == 1) && 7232d1d418eSSumit Saxena (sges_needed > 1)) 7242d1d418eSSumit Saxena goto setup_chain; 7252d1d418eSSumit Saxena flag = sgl_flags; 7262d1d418eSSumit Saxena if (i == (dma_buff->num_dma_desc - 1)) { 7272d1d418eSSumit Saxena if (num_datasges == 1) 7282d1d418eSSumit Saxena flag = sgl_flags_last; 7292d1d418eSSumit Saxena else 7302d1d418eSSumit Saxena flag = sgl_flags_eob; 7312d1d418eSSumit Saxena } 7322d1d418eSSumit Saxena 7332d1d418eSSumit Saxena mpi3mr_add_sg_single(sgl, flag, 7342d1d418eSSumit Saxena dma_buff->dma_desc[i].size, 7352d1d418eSSumit Saxena dma_buff->dma_desc[i].dma_addr); 7362d1d418eSSumit Saxena sgl += sge_element_size; 7372d1d418eSSumit Saxena available_sges--; 7382d1d418eSSumit Saxena sges_needed--; 7392d1d418eSSumit Saxena } 7402d1d418eSSumit Saxena num_datasges--; 7412d1d418eSSumit Saxena i = 0; 7422d1d418eSSumit Saxena } 7432d1d418eSSumit Saxena return 0; 7442d1d418eSSumit Saxena 7452d1d418eSSumit Saxena setup_chain: 7462d1d418eSSumit Saxena available_sges = sc->ioctl_chain_sge.size / sge_element_size; 7472d1d418eSSumit Saxena if (sges_needed > available_sges) 7482d1d418eSSumit Saxena return -1; 7492d1d418eSSumit Saxena mpi3mr_add_sg_single(sgl, last_chain_sgl_flags, 7502d1d418eSSumit Saxena (sges_needed * sge_element_size), sc->ioctl_chain_sge.dma_addr); 7512d1d418eSSumit Saxena memset(sc->ioctl_chain_sge.addr, 0, sc->ioctl_chain_sge.size); 7522d1d418eSSumit Saxena sgl = (U8 *)sc->ioctl_chain_sge.addr; 7532d1d418eSSumit Saxena chain_used = true; 7542d1d418eSSumit Saxena goto build_sges; 7552d1d418eSSumit Saxena } 7562d1d418eSSumit Saxena 7572d1d418eSSumit Saxena 7582d1d418eSSumit Saxena /** 7592d1d418eSSumit Saxena * mpi3mr_app_mptcmds - MPI Pass through IOCTL handler 7602d1d418eSSumit Saxena * @dev: char device 7612d1d418eSSumit Saxena * @cmd: IOCTL command 7622d1d418eSSumit Saxena * @arg: User data payload buffer for the IOCTL 7632d1d418eSSumit Saxena * @flag: flags 7642d1d418eSSumit Saxena * @thread: threads 7652d1d418eSSumit Saxena * 7662d1d418eSSumit Saxena * This function is the top level handler for MPI Pass through 7672d1d418eSSumit Saxena * IOCTL, this does basic validation of the input data buffers, 7682d1d418eSSumit Saxena * identifies the given buffer types and MPI command, allocates 7692d1d418eSSumit Saxena * DMAable memory for user given buffers, construstcs SGL 7702d1d418eSSumit Saxena * properly and passes the command to the firmware. 7712d1d418eSSumit Saxena * 7722d1d418eSSumit Saxena * Once the MPI command is completed the driver copies the data 7732d1d418eSSumit Saxena * if any and reply, sense information to user provided buffers. 7742d1d418eSSumit Saxena * If the command is timed out then issues controller reset 7752d1d418eSSumit Saxena * prior to returning. 7762d1d418eSSumit Saxena * 7772d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 7782d1d418eSSumit Saxena */ 7792d1d418eSSumit Saxena static long 7802d1d418eSSumit Saxena mpi3mr_app_mptcmds(struct cdev *dev, u_long cmd, void *uarg, 7812d1d418eSSumit Saxena int flag, struct thread *td) 7822d1d418eSSumit Saxena { 7832d1d418eSSumit Saxena long rval = EINVAL; 7842d1d418eSSumit Saxena U8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0, din_cnt = 0, dout_cnt = 0; 7852d1d418eSSumit Saxena U8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF; 7862d1d418eSSumit Saxena U16 desc_count = 0; 7872d1d418eSSumit Saxena U8 nvme_fmt = 0; 7882d1d418eSSumit Saxena U32 tmplen = 0, erbsz = MPI3MR_SENSEBUF_SZ, din_sz = 0, dout_sz = 0; 7892d1d418eSSumit Saxena U8 *kern_erb = NULL; 7902d1d418eSSumit Saxena U8 *mpi_request = NULL; 7912d1d418eSSumit Saxena Mpi3RequestHeader_t *mpi_header = NULL; 7922d1d418eSSumit Saxena Mpi3PELReqActionGetCount_t *pel = NULL; 7932d1d418eSSumit Saxena Mpi3StatusReplyDescriptor_t *status_desc = NULL; 7942d1d418eSSumit Saxena struct mpi3mr_softc *sc = NULL; 7952d1d418eSSumit Saxena struct mpi3mr_ioctl_buf_entry_list *buffer_list = NULL; 7962d1d418eSSumit Saxena struct mpi3mr_buf_entry *buf_entries = NULL; 7972d1d418eSSumit Saxena struct mpi3mr_ioctl_mpt_dma_buffer *dma_buffers = NULL, *dma_buff = NULL; 7982d1d418eSSumit Saxena struct mpi3mr_ioctl_mpirepbuf *mpirepbuf = NULL; 7992d1d418eSSumit Saxena struct mpi3mr_ioctl_mptcmd *karg = (struct mpi3mr_ioctl_mptcmd *)uarg; 8002d1d418eSSumit Saxena 8012d1d418eSSumit Saxena 8022d1d418eSSumit Saxena sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); 8032d1d418eSSumit Saxena if (!sc) 8042d1d418eSSumit Saxena return ENODEV; 8052d1d418eSSumit Saxena 8062d1d418eSSumit Saxena if (!sc->ioctl_sges_allocated) { 8072d1d418eSSumit Saxena printf("%s: DMA memory was not allocated\n", __func__); 8082d1d418eSSumit Saxena return ENOMEM; 8092d1d418eSSumit Saxena } 8102d1d418eSSumit Saxena 8112d1d418eSSumit Saxena if (karg->timeout < MPI3MR_IOCTL_DEFAULT_TIMEOUT) 8122d1d418eSSumit Saxena karg->timeout = MPI3MR_IOCTL_DEFAULT_TIMEOUT; 8132d1d418eSSumit Saxena 8142d1d418eSSumit Saxena if (!karg->mpi_msg_size || !karg->buf_entry_list_size) { 8152d1d418eSSumit Saxena printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 8162d1d418eSSumit Saxena __func__, __LINE__); 8172d1d418eSSumit Saxena return rval; 8182d1d418eSSumit Saxena } 8192d1d418eSSumit Saxena if ((karg->mpi_msg_size * 4) > MPI3MR_AREQ_FRAME_SZ) { 8202d1d418eSSumit Saxena printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 8212d1d418eSSumit Saxena __func__, __LINE__); 8222d1d418eSSumit Saxena return rval; 8232d1d418eSSumit Saxena } 8242d1d418eSSumit Saxena 8252d1d418eSSumit Saxena mpi_request = malloc(MPI3MR_AREQ_FRAME_SZ, M_MPI3MR, M_NOWAIT | M_ZERO); 8262d1d418eSSumit Saxena if (!mpi_request) { 8272d1d418eSSumit Saxena printf(IOCNAME "%s: memory allocation failed for mpi_request\n", sc->name, 8282d1d418eSSumit Saxena __func__); 8292d1d418eSSumit Saxena return ENOMEM; 8302d1d418eSSumit Saxena } 8312d1d418eSSumit Saxena 8322d1d418eSSumit Saxena mpi_header = (Mpi3RequestHeader_t *)mpi_request; 8332d1d418eSSumit Saxena pel = (Mpi3PELReqActionGetCount_t *)mpi_request; 8342d1d418eSSumit Saxena if (copyin(karg->mpi_msg_buf, mpi_request, (karg->mpi_msg_size * 4))) { 8352d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 8362d1d418eSSumit Saxena __FILE__, __LINE__, __func__); 8372d1d418eSSumit Saxena rval = EFAULT; 8382d1d418eSSumit Saxena goto out; 8392d1d418eSSumit Saxena } 8402d1d418eSSumit Saxena 8412d1d418eSSumit Saxena buffer_list = malloc(karg->buf_entry_list_size, M_MPI3MR, M_NOWAIT | M_ZERO); 8422d1d418eSSumit Saxena if (!buffer_list) { 8432d1d418eSSumit Saxena printf(IOCNAME "%s: memory allocation failed for buffer_list\n", sc->name, 8442d1d418eSSumit Saxena __func__); 8452d1d418eSSumit Saxena rval = ENOMEM; 8462d1d418eSSumit Saxena goto out; 8472d1d418eSSumit Saxena } 8482d1d418eSSumit Saxena if (copyin(karg->buf_entry_list, buffer_list, karg->buf_entry_list_size)) { 8492d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 8502d1d418eSSumit Saxena __FILE__, __LINE__, __func__); 8512d1d418eSSumit Saxena rval = EFAULT; 8522d1d418eSSumit Saxena goto out; 8532d1d418eSSumit Saxena } 8542d1d418eSSumit Saxena if (!buffer_list->num_of_buf_entries) { 8552d1d418eSSumit Saxena printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 8562d1d418eSSumit Saxena __func__, __LINE__); 8572d1d418eSSumit Saxena rval = EINVAL; 8582d1d418eSSumit Saxena goto out; 8592d1d418eSSumit Saxena } 8602d1d418eSSumit Saxena bufcnt = buffer_list->num_of_buf_entries; 8612d1d418eSSumit Saxena dma_buffers = malloc((sizeof(*dma_buffers) * bufcnt), M_MPI3MR, M_NOWAIT | M_ZERO); 8622d1d418eSSumit Saxena if (!dma_buffers) { 8632d1d418eSSumit Saxena printf(IOCNAME "%s: memory allocation failed for dma_buffers\n", sc->name, 8642d1d418eSSumit Saxena __func__); 8652d1d418eSSumit Saxena rval = ENOMEM; 8662d1d418eSSumit Saxena goto out; 8672d1d418eSSumit Saxena } 8682d1d418eSSumit Saxena buf_entries = buffer_list->buf_entry; 8692d1d418eSSumit Saxena dma_buff = dma_buffers; 8702d1d418eSSumit Saxena for (count = 0; count < bufcnt; count++, buf_entries++, dma_buff++) { 8712d1d418eSSumit Saxena memset(dma_buff, 0, sizeof(*dma_buff)); 8722d1d418eSSumit Saxena dma_buff->user_buf = buf_entries->buffer; 8732d1d418eSSumit Saxena dma_buff->user_buf_len = buf_entries->buf_len; 8742d1d418eSSumit Saxena 8752d1d418eSSumit Saxena switch (buf_entries->buf_type) { 8762d1d418eSSumit Saxena case MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_CMD: 8772d1d418eSSumit Saxena is_rmcb = 1; 8782d1d418eSSumit Saxena if ((count != 0) || !buf_entries->buf_len) 8792d1d418eSSumit Saxena invalid_be = 1; 8802d1d418eSSumit Saxena dma_buff->data_dir = MPI3MR_APP_DDO; 8812d1d418eSSumit Saxena break; 8822d1d418eSSumit Saxena case MPI3MR_IOCTL_BUFTYPE_RAIDMGMT_RESP: 8832d1d418eSSumit Saxena is_rmrb = 1; 8842d1d418eSSumit Saxena if (count != 1 || !is_rmcb || !buf_entries->buf_len) 8852d1d418eSSumit Saxena invalid_be = 1; 8862d1d418eSSumit Saxena dma_buff->data_dir = MPI3MR_APP_DDI; 8872d1d418eSSumit Saxena break; 8882d1d418eSSumit Saxena case MPI3MR_IOCTL_BUFTYPE_DATA_IN: 8892d1d418eSSumit Saxena din_sz = dma_buff->user_buf_len; 8902d1d418eSSumit Saxena din_cnt++; 8912d1d418eSSumit Saxena if ((din_cnt > 1) && !is_rmcb) 8922d1d418eSSumit Saxena invalid_be = 1; 8932d1d418eSSumit Saxena dma_buff->data_dir = MPI3MR_APP_DDI; 8942d1d418eSSumit Saxena break; 8952d1d418eSSumit Saxena case MPI3MR_IOCTL_BUFTYPE_DATA_OUT: 8962d1d418eSSumit Saxena dout_sz = dma_buff->user_buf_len; 8972d1d418eSSumit Saxena dout_cnt++; 8982d1d418eSSumit Saxena if ((dout_cnt > 1) && !is_rmcb) 8992d1d418eSSumit Saxena invalid_be = 1; 9002d1d418eSSumit Saxena dma_buff->data_dir = MPI3MR_APP_DDO; 9012d1d418eSSumit Saxena break; 9022d1d418eSSumit Saxena case MPI3MR_IOCTL_BUFTYPE_MPI_REPLY: 9032d1d418eSSumit Saxena mpirep_offset = count; 9042d1d418eSSumit Saxena dma_buff->data_dir = MPI3MR_APP_DDN; 9052d1d418eSSumit Saxena if (!buf_entries->buf_len) 9062d1d418eSSumit Saxena invalid_be = 1; 9072d1d418eSSumit Saxena break; 9082d1d418eSSumit Saxena case MPI3MR_IOCTL_BUFTYPE_ERR_RESPONSE: 9092d1d418eSSumit Saxena erb_offset = count; 9102d1d418eSSumit Saxena dma_buff->data_dir = MPI3MR_APP_DDN; 9112d1d418eSSumit Saxena if (!buf_entries->buf_len) 9122d1d418eSSumit Saxena invalid_be = 1; 9132d1d418eSSumit Saxena break; 9142d1d418eSSumit Saxena default: 9152d1d418eSSumit Saxena invalid_be = 1; 9162d1d418eSSumit Saxena break; 9172d1d418eSSumit Saxena } 9182d1d418eSSumit Saxena if (invalid_be) 9192d1d418eSSumit Saxena break; 9202d1d418eSSumit Saxena } 9212d1d418eSSumit Saxena if (invalid_be) { 9222d1d418eSSumit Saxena printf(IOCNAME "%s:%d Invalid IOCTL parameters passed\n", sc->name, 9232d1d418eSSumit Saxena __func__, __LINE__); 9242d1d418eSSumit Saxena rval = EINVAL; 9252d1d418eSSumit Saxena goto out; 9262d1d418eSSumit Saxena } 9272d1d418eSSumit Saxena 9282d1d418eSSumit Saxena if (is_rmcb && ((din_sz + dout_sz) > MPI3MR_MAX_IOCTL_TRANSFER_SIZE)) { 9292d1d418eSSumit Saxena printf("%s:%d: invalid data transfer size passed for function 0x%x" 9302d1d418eSSumit Saxena "din_sz = %d, dout_size = %d\n", __func__, __LINE__, 9312d1d418eSSumit Saxena mpi_header->Function, din_sz, dout_sz); 9322d1d418eSSumit Saxena rval = EINVAL; 9332d1d418eSSumit Saxena goto out; 9342d1d418eSSumit Saxena } 9352d1d418eSSumit Saxena 9362d1d418eSSumit Saxena if ((din_sz > MPI3MR_MAX_IOCTL_TRANSFER_SIZE) || 9372d1d418eSSumit Saxena (dout_sz > MPI3MR_MAX_IOCTL_TRANSFER_SIZE)) { 9382d1d418eSSumit Saxena printf("%s:%d: invalid data transfer size passed for function 0x%x" 9392d1d418eSSumit Saxena "din_size=%d dout_size=%d\n", __func__, __LINE__, 9402d1d418eSSumit Saxena mpi_header->Function, din_sz, dout_sz); 9412d1d418eSSumit Saxena rval = EINVAL; 9422d1d418eSSumit Saxena goto out; 9432d1d418eSSumit Saxena } 9442d1d418eSSumit Saxena 9452d1d418eSSumit Saxena if (mpi_header->Function == MPI3_FUNCTION_SMP_PASSTHROUGH) { 9462d1d418eSSumit Saxena if ((din_sz > MPI3MR_IOCTL_SGE_SIZE) || 9472d1d418eSSumit Saxena (dout_sz > MPI3MR_IOCTL_SGE_SIZE)) { 9482d1d418eSSumit Saxena printf("%s:%d: invalid message size passed:%d:%d:%d:%d\n", 9492d1d418eSSumit Saxena __func__, __LINE__, din_cnt, dout_cnt, din_sz, dout_sz); 9502d1d418eSSumit Saxena rval = EINVAL; 9512d1d418eSSumit Saxena goto out; 9522d1d418eSSumit Saxena } 9532d1d418eSSumit Saxena } 9542d1d418eSSumit Saxena 9552d1d418eSSumit Saxena dma_buff = dma_buffers; 9562d1d418eSSumit Saxena for (count = 0; count < bufcnt; count++, dma_buff++) { 9572d1d418eSSumit Saxena 9582d1d418eSSumit Saxena dma_buff->kern_buf_len = dma_buff->user_buf_len; 9592d1d418eSSumit Saxena 9602d1d418eSSumit Saxena if (is_rmcb && !count) { 9612d1d418eSSumit Saxena dma_buff->kern_buf = sc->ioctl_chain_sge.addr; 9622d1d418eSSumit Saxena dma_buff->kern_buf_len = sc->ioctl_chain_sge.size; 9632d1d418eSSumit Saxena dma_buff->kern_buf_dma = sc->ioctl_chain_sge.dma_addr; 9642d1d418eSSumit Saxena dma_buff->dma_desc = NULL; 9652d1d418eSSumit Saxena dma_buff->num_dma_desc = 0; 9662d1d418eSSumit Saxena memset(dma_buff->kern_buf, 0, dma_buff->kern_buf_len); 9672d1d418eSSumit Saxena tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); 9682d1d418eSSumit Saxena if (copyin(dma_buff->user_buf, dma_buff->kern_buf, tmplen)) { 9692d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "failure at %s() line: %d", 9702d1d418eSSumit Saxena __func__, __LINE__); 9712d1d418eSSumit Saxena rval = EFAULT; 9722d1d418eSSumit Saxena goto out; 9732d1d418eSSumit Saxena } 9742d1d418eSSumit Saxena } else if (is_rmrb && (count == 1)) { 9752d1d418eSSumit Saxena dma_buff->kern_buf = sc->ioctl_resp_sge.addr; 9762d1d418eSSumit Saxena dma_buff->kern_buf_len = sc->ioctl_resp_sge.size; 9772d1d418eSSumit Saxena dma_buff->kern_buf_dma = sc->ioctl_resp_sge.dma_addr; 9782d1d418eSSumit Saxena dma_buff->dma_desc = NULL; 9792d1d418eSSumit Saxena dma_buff->num_dma_desc = 0; 9802d1d418eSSumit Saxena memset(dma_buff->kern_buf, 0, dma_buff->kern_buf_len); 9812d1d418eSSumit Saxena tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); 9822d1d418eSSumit Saxena dma_buff->kern_buf_len = tmplen; 9832d1d418eSSumit Saxena } else { 9842d1d418eSSumit Saxena if (!dma_buff->kern_buf_len) 9852d1d418eSSumit Saxena continue; 9862d1d418eSSumit Saxena if (mpi3mr_map_data_buffer_dma(sc, dma_buff, desc_count)) { 9872d1d418eSSumit Saxena rval = ENOMEM; 9882d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_ERROR, "mapping data buffers failed" 9892d1d418eSSumit Saxena "at %s() line: %d\n", __func__, __LINE__); 9902d1d418eSSumit Saxena goto out; 9912d1d418eSSumit Saxena } 9922d1d418eSSumit Saxena desc_count += dma_buff->num_dma_desc; 9932d1d418eSSumit Saxena } 9942d1d418eSSumit Saxena } 9952d1d418eSSumit Saxena 9962d1d418eSSumit Saxena if (erb_offset != 0xFF) { 9972d1d418eSSumit Saxena kern_erb = malloc(erbsz, M_MPI3MR, M_NOWAIT | M_ZERO); 9982d1d418eSSumit Saxena if (!kern_erb) { 9992d1d418eSSumit Saxena printf(IOCNAME "%s:%d Cannot allocate memory for sense buffer\n", sc->name, 10002d1d418eSSumit Saxena __func__, __LINE__); 10012d1d418eSSumit Saxena rval = ENOMEM; 10022d1d418eSSumit Saxena goto out; 10032d1d418eSSumit Saxena } 10042d1d418eSSumit Saxena } 10052d1d418eSSumit Saxena 10062d1d418eSSumit Saxena if (sc->ioctl_cmds.state & MPI3MR_CMD_PENDING) { 10072d1d418eSSumit Saxena printf(IOCNAME "Issue IOCTL: Ioctl command is in use/previous command is pending\n", 10082d1d418eSSumit Saxena sc->name); 10092d1d418eSSumit Saxena rval = EAGAIN; 10102d1d418eSSumit Saxena goto out; 10112d1d418eSSumit Saxena } 10122d1d418eSSumit Saxena 10132d1d418eSSumit Saxena if (sc->unrecoverable) { 10142d1d418eSSumit Saxena printf(IOCNAME "Issue IOCTL: controller is in unrecoverable state\n", sc->name); 10152d1d418eSSumit Saxena rval = EFAULT; 10162d1d418eSSumit Saxena goto out; 10172d1d418eSSumit Saxena } 10182d1d418eSSumit Saxena 10192d1d418eSSumit Saxena if (sc->reset_in_progress) { 10202d1d418eSSumit Saxena printf(IOCNAME "Issue IOCTL: reset in progress\n", sc->name); 10212d1d418eSSumit Saxena rval = EAGAIN; 10222d1d418eSSumit Saxena goto out; 10232d1d418eSSumit Saxena } 10242d1d418eSSumit Saxena if (sc->block_ioctls) { 10252d1d418eSSumit Saxena printf(IOCNAME "Issue IOCTL: IOCTLs are blocked\n", sc->name); 10262d1d418eSSumit Saxena rval = EAGAIN; 10272d1d418eSSumit Saxena goto out; 10282d1d418eSSumit Saxena } 10292d1d418eSSumit Saxena 10302d1d418eSSumit Saxena if (mpi_header->Function != MPI3_FUNCTION_NVME_ENCAPSULATED) { 10312d1d418eSSumit Saxena if (mpi3mr_app_construct_sgl(sc, mpi_request, (karg->mpi_msg_size * 4), dma_buffers, 10322d1d418eSSumit Saxena bufcnt, is_rmcb, is_rmrb, (dout_cnt + din_cnt))) { 10332d1d418eSSumit Saxena printf(IOCNAME "Issue IOCTL: sgl build failed\n", sc->name); 10342d1d418eSSumit Saxena rval = EAGAIN; 10352d1d418eSSumit Saxena goto out; 10362d1d418eSSumit Saxena } 10372d1d418eSSumit Saxena 10382d1d418eSSumit Saxena } else { 10392d1d418eSSumit Saxena nvme_fmt = mpi3mr_app_get_nvme_data_fmt( 10402d1d418eSSumit Saxena (Mpi3NVMeEncapsulatedRequest_t *)mpi_request); 10412d1d418eSSumit Saxena if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_PRP) { 10422d1d418eSSumit Saxena if (mpi3mr_app_build_nvme_prp(sc, 10432d1d418eSSumit Saxena (Mpi3NVMeEncapsulatedRequest_t *) mpi_request, 10442d1d418eSSumit Saxena dma_buffers, bufcnt)) { 10452d1d418eSSumit Saxena rval = ENOMEM; 10462d1d418eSSumit Saxena goto out; 10472d1d418eSSumit Saxena } 10482d1d418eSSumit Saxena } else if (nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL1 || 10492d1d418eSSumit Saxena nvme_fmt == MPI3MR_NVME_DATA_FORMAT_SGL2) { 10502d1d418eSSumit Saxena if (mpi3mr_app_construct_nvme_sgl(sc, (Mpi3NVMeEncapsulatedRequest_t *) mpi_request, 10512d1d418eSSumit Saxena dma_buffers, bufcnt)) { 10522d1d418eSSumit Saxena rval = EINVAL; 10532d1d418eSSumit Saxena goto out; 10542d1d418eSSumit Saxena } 10552d1d418eSSumit Saxena } else { 10562d1d418eSSumit Saxena printf(IOCNAME "%s: Invalid NVMe Command Format\n", sc->name, 10572d1d418eSSumit Saxena __func__); 10582d1d418eSSumit Saxena rval = EINVAL; 10592d1d418eSSumit Saxena goto out; 10602d1d418eSSumit Saxena } 10612d1d418eSSumit Saxena } 10622d1d418eSSumit Saxena 10632d1d418eSSumit Saxena sc->ioctl_cmds.state = MPI3MR_CMD_PENDING; 10642d1d418eSSumit Saxena sc->ioctl_cmds.is_waiting = 1; 10652d1d418eSSumit Saxena sc->ioctl_cmds.callback = NULL; 10662d1d418eSSumit Saxena sc->ioctl_cmds.is_senseprst = 0; 10672d1d418eSSumit Saxena sc->ioctl_cmds.sensebuf = kern_erb; 10682d1d418eSSumit Saxena memset((sc->ioctl_cmds.reply), 0, sc->reply_sz); 10692d1d418eSSumit Saxena mpi_header->HostTag = MPI3MR_HOSTTAG_IOCTLCMDS; 10702d1d418eSSumit Saxena init_completion(&sc->ioctl_cmds.completion); 10712d1d418eSSumit Saxena rval = mpi3mr_submit_admin_cmd(sc, mpi_request, MPI3MR_AREQ_FRAME_SZ); 10722d1d418eSSumit Saxena if (rval) { 10732d1d418eSSumit Saxena printf(IOCNAME "Issue IOCTL: Admin Post failed\n", sc->name); 10742d1d418eSSumit Saxena goto out_failed; 10752d1d418eSSumit Saxena } 10762d1d418eSSumit Saxena wait_for_completion_timeout(&sc->ioctl_cmds.completion, karg->timeout); 10772d1d418eSSumit Saxena 10782d1d418eSSumit Saxena if (!(sc->ioctl_cmds.state & MPI3MR_CMD_COMPLETE)) { 10792d1d418eSSumit Saxena sc->ioctl_cmds.is_waiting = 0; 10802d1d418eSSumit Saxena printf(IOCNAME "Issue IOCTL: command timed out\n", sc->name); 10812d1d418eSSumit Saxena rval = EAGAIN; 10822d1d418eSSumit Saxena if (sc->ioctl_cmds.state & MPI3MR_CMD_RESET) 10832d1d418eSSumit Saxena goto out_failed; 10842d1d418eSSumit Saxena 10852d1d418eSSumit Saxena sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; 10862d1d418eSSumit Saxena sc->reset.reason = MPI3MR_RESET_FROM_IOCTL_TIMEOUT; 10872d1d418eSSumit Saxena goto out_failed; 10882d1d418eSSumit Saxena } 10892d1d418eSSumit Saxena 10902d1d418eSSumit Saxena if (sc->nvme_encap_prp_list && sc->nvme_encap_prp_list_dma) { 10912d1d418eSSumit Saxena bus_dmamap_unload(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list_dma_dmamap); 10922d1d418eSSumit Saxena bus_dmamem_free(sc->nvme_encap_prp_list_dmatag, sc->nvme_encap_prp_list, sc->nvme_encap_prp_list_dma_dmamap); 10932d1d418eSSumit Saxena bus_dma_tag_destroy(sc->nvme_encap_prp_list_dmatag); 10942d1d418eSSumit Saxena sc->nvme_encap_prp_list = NULL; 10952d1d418eSSumit Saxena } 10962d1d418eSSumit Saxena 10972d1d418eSSumit Saxena if (((sc->ioctl_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK) 10982d1d418eSSumit Saxena != MPI3_IOCSTATUS_SUCCESS) && 10992d1d418eSSumit Saxena (sc->mpi3mr_debug & MPI3MR_DEBUG_IOCTL)) { 11002d1d418eSSumit Saxena printf(IOCNAME "Issue IOCTL: Failed IOCStatus(0x%04x) Loginfo(0x%08x)\n", sc->name, 11012d1d418eSSumit Saxena (sc->ioctl_cmds.ioc_status & MPI3_IOCSTATUS_STATUS_MASK), 11022d1d418eSSumit Saxena sc->ioctl_cmds.ioc_loginfo); 11032d1d418eSSumit Saxena } 11042d1d418eSSumit Saxena 11052d1d418eSSumit Saxena if ((mpirep_offset != 0xFF) && 11062d1d418eSSumit Saxena dma_buffers[mpirep_offset].user_buf_len) { 11072d1d418eSSumit Saxena dma_buff = &dma_buffers[mpirep_offset]; 11082d1d418eSSumit Saxena dma_buff->kern_buf_len = (sizeof(*mpirepbuf) - 1 + 11092d1d418eSSumit Saxena sc->reply_sz); 11102d1d418eSSumit Saxena mpirepbuf = malloc(dma_buff->kern_buf_len, M_MPI3MR, M_NOWAIT | M_ZERO); 11112d1d418eSSumit Saxena 11122d1d418eSSumit Saxena if (!mpirepbuf) { 11132d1d418eSSumit Saxena printf(IOCNAME "%s: failed obtaining a memory for mpi reply\n", sc->name, 11142d1d418eSSumit Saxena __func__); 11152d1d418eSSumit Saxena rval = ENOMEM; 11162d1d418eSSumit Saxena goto out_failed; 11172d1d418eSSumit Saxena } 11182d1d418eSSumit Saxena if (sc->ioctl_cmds.state & MPI3MR_CMD_REPLYVALID) { 11192d1d418eSSumit Saxena mpirepbuf->mpirep_type = 11202d1d418eSSumit Saxena MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_ADDRESS; 11212d1d418eSSumit Saxena memcpy(mpirepbuf->repbuf, sc->ioctl_cmds.reply, sc->reply_sz); 11222d1d418eSSumit Saxena } else { 11232d1d418eSSumit Saxena mpirepbuf->mpirep_type = 11242d1d418eSSumit Saxena MPI3MR_IOCTL_MPI_REPLY_BUFTYPE_STATUS; 11252d1d418eSSumit Saxena status_desc = (Mpi3StatusReplyDescriptor_t *) 11262d1d418eSSumit Saxena mpirepbuf->repbuf; 11272d1d418eSSumit Saxena status_desc->IOCStatus = sc->ioctl_cmds.ioc_status; 11282d1d418eSSumit Saxena status_desc->IOCLogInfo = sc->ioctl_cmds.ioc_loginfo; 11292d1d418eSSumit Saxena } 11302d1d418eSSumit Saxena tmplen = min(dma_buff->kern_buf_len, dma_buff->user_buf_len); 11312d1d418eSSumit Saxena if (copyout(mpirepbuf, dma_buff->user_buf, tmplen)) { 11322d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 11332d1d418eSSumit Saxena __FILE__, __LINE__, __func__); 11342d1d418eSSumit Saxena rval = EFAULT; 11352d1d418eSSumit Saxena goto out_failed; 11362d1d418eSSumit Saxena } 11372d1d418eSSumit Saxena } 11382d1d418eSSumit Saxena 11392d1d418eSSumit Saxena if (erb_offset != 0xFF && sc->ioctl_cmds.sensebuf && 11402d1d418eSSumit Saxena sc->ioctl_cmds.is_senseprst) { 11412d1d418eSSumit Saxena dma_buff = &dma_buffers[erb_offset]; 11422d1d418eSSumit Saxena tmplen = min(erbsz, dma_buff->user_buf_len); 11432d1d418eSSumit Saxena if (copyout(kern_erb, dma_buff->user_buf, tmplen)) { 11442d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 11452d1d418eSSumit Saxena __FILE__, __LINE__, __func__); 11462d1d418eSSumit Saxena rval = EFAULT; 11472d1d418eSSumit Saxena goto out_failed; 11482d1d418eSSumit Saxena } 11492d1d418eSSumit Saxena } 11502d1d418eSSumit Saxena 11512d1d418eSSumit Saxena dma_buff = dma_buffers; 11522d1d418eSSumit Saxena for (count = 0; count < bufcnt; count++, dma_buff++) { 11532d1d418eSSumit Saxena if ((count == 1) && is_rmrb) { 11542d1d418eSSumit Saxena if (copyout(dma_buff->kern_buf, dma_buff->user_buf,dma_buff->kern_buf_len)) { 11552d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 11562d1d418eSSumit Saxena __FILE__, __LINE__, __func__); 11572d1d418eSSumit Saxena rval = EFAULT; 11582d1d418eSSumit Saxena goto out_failed; 11592d1d418eSSumit Saxena } 11602d1d418eSSumit Saxena } else if (dma_buff->data_dir == MPI3MR_APP_DDI) { 11612d1d418eSSumit Saxena tmplen = 0; 11622d1d418eSSumit Saxena for (desc_count = 0; desc_count < dma_buff->num_dma_desc; desc_count++) { 11632d1d418eSSumit Saxena if (copyout(dma_buff->dma_desc[desc_count].addr, 11642d1d418eSSumit Saxena (U8 *)dma_buff->user_buf+tmplen, 11652d1d418eSSumit Saxena dma_buff->dma_desc[desc_count].size)) { 11662d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 11672d1d418eSSumit Saxena __FILE__, __LINE__, __func__); 11682d1d418eSSumit Saxena rval = EFAULT; 11692d1d418eSSumit Saxena goto out_failed; 11702d1d418eSSumit Saxena } 11712d1d418eSSumit Saxena tmplen += dma_buff->dma_desc[desc_count].size; 11722d1d418eSSumit Saxena } 11732d1d418eSSumit Saxena } 11742d1d418eSSumit Saxena } 11752d1d418eSSumit Saxena 11762d1d418eSSumit Saxena if ((pel->Function == MPI3_FUNCTION_PERSISTENT_EVENT_LOG) && 11772d1d418eSSumit Saxena (pel->Action == MPI3_PEL_ACTION_GET_COUNT)) 11782d1d418eSSumit Saxena sc->mpi3mr_aen_triggered = 0; 11792d1d418eSSumit Saxena 11802d1d418eSSumit Saxena out_failed: 11812d1d418eSSumit Saxena sc->ioctl_cmds.is_senseprst = 0; 11822d1d418eSSumit Saxena sc->ioctl_cmds.sensebuf = NULL; 11832d1d418eSSumit Saxena sc->ioctl_cmds.state = MPI3MR_CMD_NOTUSED; 11842d1d418eSSumit Saxena out: 11852d1d418eSSumit Saxena if (kern_erb) 11862d1d418eSSumit Saxena free(kern_erb, M_MPI3MR); 11872d1d418eSSumit Saxena if (buffer_list) 11882d1d418eSSumit Saxena free(buffer_list, M_MPI3MR); 11892d1d418eSSumit Saxena if (mpi_request) 11902d1d418eSSumit Saxena free(mpi_request, M_MPI3MR); 11912d1d418eSSumit Saxena if (dma_buffers) { 11922d1d418eSSumit Saxena dma_buff = dma_buffers; 11932d1d418eSSumit Saxena for (count = 0; count < bufcnt; count++, dma_buff++) { 11942d1d418eSSumit Saxena free(dma_buff->dma_desc, M_MPI3MR); 11952d1d418eSSumit Saxena } 11962d1d418eSSumit Saxena free(dma_buffers, M_MPI3MR); 11972d1d418eSSumit Saxena } 11982d1d418eSSumit Saxena if (mpirepbuf) 11992d1d418eSSumit Saxena free(mpirepbuf, M_MPI3MR); 12002d1d418eSSumit Saxena return rval; 12012d1d418eSSumit Saxena } 12022d1d418eSSumit Saxena 12032d1d418eSSumit Saxena /** 12042d1d418eSSumit Saxena * mpi3mr_soft_reset_from_app - Trigger controller reset 12052d1d418eSSumit Saxena * @sc: Adapter instance reference 12062d1d418eSSumit Saxena * 12072d1d418eSSumit Saxena * This function triggers the controller reset from the 12082d1d418eSSumit Saxena * watchdog context and wait for it to complete. It will 12092d1d418eSSumit Saxena * come out of wait upon completion or timeout exaustion. 12102d1d418eSSumit Saxena * 12112d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 12122d1d418eSSumit Saxena */ 12132d1d418eSSumit Saxena static long 12142d1d418eSSumit Saxena mpi3mr_soft_reset_from_app(struct mpi3mr_softc *sc) 12152d1d418eSSumit Saxena { 12162d1d418eSSumit Saxena 12172d1d418eSSumit Saxena U32 timeout; 12182d1d418eSSumit Saxena 12192d1d418eSSumit Saxena /* if reset is not in progress, trigger soft reset from watchdog context */ 12202d1d418eSSumit Saxena if (!sc->reset_in_progress) { 12212d1d418eSSumit Saxena sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; 12222d1d418eSSumit Saxena sc->reset.reason = MPI3MR_RESET_FROM_IOCTL; 12232d1d418eSSumit Saxena 12242d1d418eSSumit Saxena /* Wait for soft reset to start */ 12252d1d418eSSumit Saxena timeout = 50; 12262d1d418eSSumit Saxena while (timeout--) { 12272d1d418eSSumit Saxena if (sc->reset_in_progress == 1) 12282d1d418eSSumit Saxena break; 12292d1d418eSSumit Saxena DELAY(100 * 1000); 12302d1d418eSSumit Saxena } 12312d1d418eSSumit Saxena if (!timeout) 12322d1d418eSSumit Saxena return EFAULT; 12332d1d418eSSumit Saxena } 12342d1d418eSSumit Saxena 12352d1d418eSSumit Saxena /* Wait for soft reset to complete */ 12362d1d418eSSumit Saxena int i = 0; 12372d1d418eSSumit Saxena timeout = sc->ready_timeout; 12382d1d418eSSumit Saxena while (timeout--) { 12392d1d418eSSumit Saxena if (sc->reset_in_progress == 0) 12402d1d418eSSumit Saxena break; 12412d1d418eSSumit Saxena i++; 12422d1d418eSSumit Saxena if (!(i % 5)) { 12432d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 12442d1d418eSSumit Saxena "[%2ds]waiting for controller reset to be finished from %s\n", i, __func__); 12452d1d418eSSumit Saxena } 12462d1d418eSSumit Saxena DELAY(1000 * 1000); 12472d1d418eSSumit Saxena } 12482d1d418eSSumit Saxena 12492d1d418eSSumit Saxena /* 12502d1d418eSSumit Saxena * In case of soft reset failure or not completed within stipulated time, 12512d1d418eSSumit Saxena * fail back to application. 12522d1d418eSSumit Saxena */ 12532d1d418eSSumit Saxena if ((!timeout || sc->reset.status)) 12542d1d418eSSumit Saxena return EFAULT; 12552d1d418eSSumit Saxena 12562d1d418eSSumit Saxena return 0; 12572d1d418eSSumit Saxena } 12582d1d418eSSumit Saxena 12592d1d418eSSumit Saxena 12602d1d418eSSumit Saxena /** 12612d1d418eSSumit Saxena * mpi3mr_adp_reset - Issue controller reset 12622d1d418eSSumit Saxena * @sc: Adapter instance reference 12632d1d418eSSumit Saxena * @data_out_buf: User buffer with reset type 12642d1d418eSSumit Saxena * @data_out_sz: length of the user buffer. 12652d1d418eSSumit Saxena * 12662d1d418eSSumit Saxena * This function identifies the user provided reset type and 12672d1d418eSSumit Saxena * issues approporiate reset to the controller and wait for that 12682d1d418eSSumit Saxena * to complete and reinitialize the controller and then returns. 12692d1d418eSSumit Saxena * 12702d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 12712d1d418eSSumit Saxena */ 12722d1d418eSSumit Saxena static long 12732d1d418eSSumit Saxena mpi3mr_adp_reset(struct mpi3mr_softc *sc, 12742d1d418eSSumit Saxena void *data_out_buf, U32 data_out_sz) 12752d1d418eSSumit Saxena { 12762d1d418eSSumit Saxena long rval = EINVAL; 12772d1d418eSSumit Saxena struct mpi3mr_ioctl_adpreset adpreset; 12782d1d418eSSumit Saxena 12792d1d418eSSumit Saxena memset(&adpreset, 0, sizeof(adpreset)); 12802d1d418eSSumit Saxena 12812d1d418eSSumit Saxena if (data_out_sz != sizeof(adpreset)) { 12822d1d418eSSumit Saxena printf(IOCNAME "Invalid user adpreset buffer size %s() line: %d\n", sc->name, 12832d1d418eSSumit Saxena __func__, __LINE__); 12842d1d418eSSumit Saxena goto out; 12852d1d418eSSumit Saxena } 12862d1d418eSSumit Saxena 12872d1d418eSSumit Saxena if (copyin(data_out_buf, &adpreset, sizeof(adpreset))) { 12882d1d418eSSumit Saxena printf(IOCNAME "failure at %s() line:%d\n", sc->name, 12892d1d418eSSumit Saxena __func__, __LINE__); 12902d1d418eSSumit Saxena rval = EFAULT; 12912d1d418eSSumit Saxena goto out; 12922d1d418eSSumit Saxena } 12932d1d418eSSumit Saxena 12942d1d418eSSumit Saxena switch (adpreset.reset_type) { 12952d1d418eSSumit Saxena case MPI3MR_IOCTL_ADPRESET_SOFT: 12962d1d418eSSumit Saxena sc->reset.ioctl_reset_snapdump = false; 12972d1d418eSSumit Saxena break; 12982d1d418eSSumit Saxena case MPI3MR_IOCTL_ADPRESET_DIAG_FAULT: 12992d1d418eSSumit Saxena sc->reset.ioctl_reset_snapdump = true; 13002d1d418eSSumit Saxena break; 13012d1d418eSSumit Saxena default: 13022d1d418eSSumit Saxena printf(IOCNAME "Unknown reset_type(0x%x) issued\n", sc->name, 13032d1d418eSSumit Saxena adpreset.reset_type); 13042d1d418eSSumit Saxena goto out; 13052d1d418eSSumit Saxena } 13062d1d418eSSumit Saxena rval = mpi3mr_soft_reset_from_app(sc); 13072d1d418eSSumit Saxena if (rval) 13082d1d418eSSumit Saxena printf(IOCNAME "reset handler returned error (0x%lx) for reset type 0x%x\n", 13092d1d418eSSumit Saxena sc->name, rval, adpreset.reset_type); 13102d1d418eSSumit Saxena 13112d1d418eSSumit Saxena out: 13122d1d418eSSumit Saxena return rval; 13132d1d418eSSumit Saxena } 13142d1d418eSSumit Saxena 13152d1d418eSSumit Saxena void 13162d1d418eSSumit Saxena mpi3mr_app_send_aen(struct mpi3mr_softc *sc) 13172d1d418eSSumit Saxena { 13182d1d418eSSumit Saxena sc->mpi3mr_aen_triggered = 1; 13192d1d418eSSumit Saxena if (sc->mpi3mr_poll_waiting) { 13202d1d418eSSumit Saxena selwakeup(&sc->mpi3mr_select); 13212d1d418eSSumit Saxena sc->mpi3mr_poll_waiting = 0; 13222d1d418eSSumit Saxena } 13232d1d418eSSumit Saxena return; 13242d1d418eSSumit Saxena } 13252d1d418eSSumit Saxena 13262d1d418eSSumit Saxena void 13272d1d418eSSumit Saxena mpi3mr_pel_wait_complete(struct mpi3mr_softc *sc, 13282d1d418eSSumit Saxena struct mpi3mr_drvr_cmd *drvr_cmd) 13292d1d418eSSumit Saxena { 13302d1d418eSSumit Saxena U8 retry = 0; 13312d1d418eSSumit Saxena Mpi3PELReply_t *pel_reply = NULL; 13322d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 13332d1d418eSSumit Saxena 13342d1d418eSSumit Saxena if (drvr_cmd->state & MPI3MR_CMD_RESET) 13352d1d418eSSumit Saxena goto cleanup_drvrcmd; 13362d1d418eSSumit Saxena 13372d1d418eSSumit Saxena if (!(drvr_cmd->state & MPI3MR_CMD_REPLYVALID)) { 13382d1d418eSSumit Saxena printf(IOCNAME "%s: PELGetSeqNum Failed, No Reply\n", sc->name, __func__); 13392d1d418eSSumit Saxena goto out_failed; 13402d1d418eSSumit Saxena } 13412d1d418eSSumit Saxena pel_reply = (Mpi3PELReply_t *)drvr_cmd->reply; 13422d1d418eSSumit Saxena 13432d1d418eSSumit Saxena if (((GET_IOC_STATUS(drvr_cmd->ioc_status)) != MPI3_IOCSTATUS_SUCCESS) 13442d1d418eSSumit Saxena || ((le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_SUCCESS) 13452d1d418eSSumit Saxena && (le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_ABORTED))){ 13462d1d418eSSumit Saxena printf(IOCNAME "%s: PELGetSeqNum Failed, IOCStatus(0x%04x) Loginfo(0x%08x) PEL_LogStatus(0x%04x)\n", 13472d1d418eSSumit Saxena sc->name, __func__, GET_IOC_STATUS(drvr_cmd->ioc_status), 13482d1d418eSSumit Saxena drvr_cmd->ioc_loginfo, le16toh(pel_reply->PELogStatus)); 13492d1d418eSSumit Saxena retry = 1; 13502d1d418eSSumit Saxena } 13512d1d418eSSumit Saxena 13522d1d418eSSumit Saxena if (retry) { 13532d1d418eSSumit Saxena if (drvr_cmd->retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 13542d1d418eSSumit Saxena drvr_cmd->retry_count++; 13552d1d418eSSumit Saxena printf(IOCNAME "%s : PELWaitretry=%d\n", sc->name, 13562d1d418eSSumit Saxena __func__, drvr_cmd->retry_count); 13572d1d418eSSumit Saxena mpi3mr_issue_pel_wait(sc, drvr_cmd); 13582d1d418eSSumit Saxena return; 13592d1d418eSSumit Saxena } 13602d1d418eSSumit Saxena 13612d1d418eSSumit Saxena printf(IOCNAME "%s :PELWait failed after all retries\n", sc->name, 13622d1d418eSSumit Saxena __func__); 13632d1d418eSSumit Saxena goto out_failed; 13642d1d418eSSumit Saxena } 13652d1d418eSSumit Saxena 13662d1d418eSSumit Saxena mpi3mr_app_send_aen(sc); 13672d1d418eSSumit Saxena 13682d1d418eSSumit Saxena if (!sc->pel_abort_requested) { 13692d1d418eSSumit Saxena sc->pel_cmds.retry_count = 0; 13702d1d418eSSumit Saxena mpi3mr_send_pel_getseq(sc, &sc->pel_cmds); 13712d1d418eSSumit Saxena } 13722d1d418eSSumit Saxena 13732d1d418eSSumit Saxena return; 13742d1d418eSSumit Saxena out_failed: 13752d1d418eSSumit Saxena sc->pel_wait_pend = 0; 13762d1d418eSSumit Saxena cleanup_drvrcmd: 13772d1d418eSSumit Saxena drvr_cmd->state = MPI3MR_CMD_NOTUSED; 13782d1d418eSSumit Saxena drvr_cmd->callback = NULL; 13792d1d418eSSumit Saxena drvr_cmd->retry_count = 0; 13802d1d418eSSumit Saxena } 13812d1d418eSSumit Saxena 13822d1d418eSSumit Saxena void 13832d1d418eSSumit Saxena mpi3mr_issue_pel_wait(struct mpi3mr_softc *sc, 13842d1d418eSSumit Saxena struct mpi3mr_drvr_cmd *drvr_cmd) 13852d1d418eSSumit Saxena { 13862d1d418eSSumit Saxena U8 retry_count = 0; 13872d1d418eSSumit Saxena Mpi3PELReqActionWait_t pel_wait; 13882d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 13892d1d418eSSumit Saxena 13902d1d418eSSumit Saxena sc->pel_abort_requested = 0; 13912d1d418eSSumit Saxena 13922d1d418eSSumit Saxena memset(&pel_wait, 0, sizeof(pel_wait)); 13932d1d418eSSumit Saxena drvr_cmd->state = MPI3MR_CMD_PENDING; 13942d1d418eSSumit Saxena drvr_cmd->is_waiting = 0; 13952d1d418eSSumit Saxena drvr_cmd->callback = mpi3mr_pel_wait_complete; 13962d1d418eSSumit Saxena drvr_cmd->ioc_status = 0; 13972d1d418eSSumit Saxena drvr_cmd->ioc_loginfo = 0; 13982d1d418eSSumit Saxena pel_wait.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 13992d1d418eSSumit Saxena pel_wait.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 14002d1d418eSSumit Saxena pel_wait.Action = MPI3_PEL_ACTION_WAIT; 14012d1d418eSSumit Saxena pel_wait.StartingSequenceNumber = htole32(sc->newest_seqnum); 14022d1d418eSSumit Saxena pel_wait.Locale = htole16(sc->pel_locale); 14032d1d418eSSumit Saxena pel_wait.Class = htole16(sc->pel_class); 14042d1d418eSSumit Saxena pel_wait.WaitTime = MPI3_PEL_WAITTIME_INFINITE_WAIT; 14052d1d418eSSumit Saxena printf(IOCNAME "Issuing PELWait: seqnum %u class %u locale 0x%08x\n", 14062d1d418eSSumit Saxena sc->name, sc->newest_seqnum, sc->pel_class, sc->pel_locale); 14072d1d418eSSumit Saxena retry_pel_wait: 14082d1d418eSSumit Saxena if (mpi3mr_submit_admin_cmd(sc, &pel_wait, sizeof(pel_wait))) { 14092d1d418eSSumit Saxena printf(IOCNAME "%s: Issue PELWait IOCTL: Admin Post failed\n", sc->name, __func__); 14102d1d418eSSumit Saxena if (retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 14112d1d418eSSumit Saxena retry_count++; 14122d1d418eSSumit Saxena goto retry_pel_wait; 14132d1d418eSSumit Saxena } 14142d1d418eSSumit Saxena goto out_failed; 14152d1d418eSSumit Saxena } 14162d1d418eSSumit Saxena return; 14172d1d418eSSumit Saxena out_failed: 14182d1d418eSSumit Saxena drvr_cmd->state = MPI3MR_CMD_NOTUSED; 14192d1d418eSSumit Saxena drvr_cmd->callback = NULL; 14202d1d418eSSumit Saxena drvr_cmd->retry_count = 0; 14212d1d418eSSumit Saxena sc->pel_wait_pend = 0; 14222d1d418eSSumit Saxena return; 14232d1d418eSSumit Saxena } 14242d1d418eSSumit Saxena 14252d1d418eSSumit Saxena void 14262d1d418eSSumit Saxena mpi3mr_send_pel_getseq(struct mpi3mr_softc *sc, 14272d1d418eSSumit Saxena struct mpi3mr_drvr_cmd *drvr_cmd) 14282d1d418eSSumit Saxena { 14292d1d418eSSumit Saxena U8 retry_count = 0; 14302d1d418eSSumit Saxena U8 sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 14312d1d418eSSumit Saxena Mpi3PELReqActionGetSequenceNumbers_t pel_getseq_req; 14322d1d418eSSumit Saxena 14332d1d418eSSumit Saxena memset(&pel_getseq_req, 0, sizeof(pel_getseq_req)); 14342d1d418eSSumit Saxena sc->pel_cmds.state = MPI3MR_CMD_PENDING; 14352d1d418eSSumit Saxena sc->pel_cmds.is_waiting = 0; 14362d1d418eSSumit Saxena sc->pel_cmds.ioc_status = 0; 14372d1d418eSSumit Saxena sc->pel_cmds.ioc_loginfo = 0; 14382d1d418eSSumit Saxena sc->pel_cmds.callback = mpi3mr_pel_getseq_complete; 14392d1d418eSSumit Saxena pel_getseq_req.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 14402d1d418eSSumit Saxena pel_getseq_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 14412d1d418eSSumit Saxena pel_getseq_req.Action = MPI3_PEL_ACTION_GET_SEQNUM; 14422d1d418eSSumit Saxena mpi3mr_add_sg_single(&pel_getseq_req.SGL, sgl_flags, 14432d1d418eSSumit Saxena sc->pel_seq_number_sz, sc->pel_seq_number_dma); 14442d1d418eSSumit Saxena 14452d1d418eSSumit Saxena retry_pel_getseq: 14462d1d418eSSumit Saxena if (mpi3mr_submit_admin_cmd(sc, &pel_getseq_req, sizeof(pel_getseq_req))) { 14472d1d418eSSumit Saxena printf(IOCNAME "%s: Issuing PEL GetSeq IOCTL: Admin Post failed\n", sc->name, __func__); 14482d1d418eSSumit Saxena if (retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 14492d1d418eSSumit Saxena retry_count++; 14502d1d418eSSumit Saxena goto retry_pel_getseq; 14512d1d418eSSumit Saxena } 14522d1d418eSSumit Saxena goto out_failed; 14532d1d418eSSumit Saxena } 14542d1d418eSSumit Saxena return; 14552d1d418eSSumit Saxena out_failed: 14562d1d418eSSumit Saxena drvr_cmd->state = MPI3MR_CMD_NOTUSED; 14572d1d418eSSumit Saxena drvr_cmd->callback = NULL; 14582d1d418eSSumit Saxena drvr_cmd->retry_count = 0; 14592d1d418eSSumit Saxena sc->pel_wait_pend = 0; 14602d1d418eSSumit Saxena } 14612d1d418eSSumit Saxena 14622d1d418eSSumit Saxena void 14632d1d418eSSumit Saxena mpi3mr_pel_getseq_complete(struct mpi3mr_softc *sc, 14642d1d418eSSumit Saxena struct mpi3mr_drvr_cmd *drvr_cmd) 14652d1d418eSSumit Saxena { 14662d1d418eSSumit Saxena U8 retry = 0; 14672d1d418eSSumit Saxena Mpi3PELReply_t *pel_reply = NULL; 14682d1d418eSSumit Saxena Mpi3PELSeq_t *pel_seq_num = (Mpi3PELSeq_t *)sc->pel_seq_number; 14692d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 14702d1d418eSSumit Saxena 14712d1d418eSSumit Saxena if (drvr_cmd->state & MPI3MR_CMD_RESET) 14722d1d418eSSumit Saxena goto cleanup_drvrcmd; 14732d1d418eSSumit Saxena 14742d1d418eSSumit Saxena if (!(drvr_cmd->state & MPI3MR_CMD_REPLYVALID)) { 14752d1d418eSSumit Saxena printf(IOCNAME "%s: PELGetSeqNum Failed, No Reply\n", sc->name, __func__); 14762d1d418eSSumit Saxena goto out_failed; 14772d1d418eSSumit Saxena } 14782d1d418eSSumit Saxena pel_reply = (Mpi3PELReply_t *)drvr_cmd->reply; 14792d1d418eSSumit Saxena 14802d1d418eSSumit Saxena if (((GET_IOC_STATUS(drvr_cmd->ioc_status)) != MPI3_IOCSTATUS_SUCCESS) 14812d1d418eSSumit Saxena || (le16toh(pel_reply->PELogStatus) != MPI3_PEL_STATUS_SUCCESS)){ 14822d1d418eSSumit Saxena printf(IOCNAME "%s: PELGetSeqNum Failed, IOCStatus(0x%04x) Loginfo(0x%08x) PEL_LogStatus(0x%04x)\n", 14832d1d418eSSumit Saxena sc->name, __func__, GET_IOC_STATUS(drvr_cmd->ioc_status), 14842d1d418eSSumit Saxena drvr_cmd->ioc_loginfo, le16toh(pel_reply->PELogStatus)); 14852d1d418eSSumit Saxena retry = 1; 14862d1d418eSSumit Saxena } 14872d1d418eSSumit Saxena 14882d1d418eSSumit Saxena if (retry) { 14892d1d418eSSumit Saxena if (drvr_cmd->retry_count < MPI3MR_PELCMDS_RETRYCOUNT) { 14902d1d418eSSumit Saxena drvr_cmd->retry_count++; 14912d1d418eSSumit Saxena printf(IOCNAME "%s : PELGetSeqNUM retry=%d\n", sc->name, 14922d1d418eSSumit Saxena __func__, drvr_cmd->retry_count); 14932d1d418eSSumit Saxena mpi3mr_send_pel_getseq(sc, drvr_cmd); 14942d1d418eSSumit Saxena return; 14952d1d418eSSumit Saxena } 14962d1d418eSSumit Saxena printf(IOCNAME "%s :PELGetSeqNUM failed after all retries\n", 14972d1d418eSSumit Saxena sc->name, __func__); 14982d1d418eSSumit Saxena goto out_failed; 14992d1d418eSSumit Saxena } 15002d1d418eSSumit Saxena 15012d1d418eSSumit Saxena sc->newest_seqnum = le32toh(pel_seq_num->Newest) + 1; 15022d1d418eSSumit Saxena drvr_cmd->retry_count = 0; 15032d1d418eSSumit Saxena mpi3mr_issue_pel_wait(sc, drvr_cmd); 15042d1d418eSSumit Saxena return; 15052d1d418eSSumit Saxena out_failed: 15062d1d418eSSumit Saxena sc->pel_wait_pend = 0; 15072d1d418eSSumit Saxena cleanup_drvrcmd: 15082d1d418eSSumit Saxena drvr_cmd->state = MPI3MR_CMD_NOTUSED; 15092d1d418eSSumit Saxena drvr_cmd->callback = NULL; 15102d1d418eSSumit Saxena drvr_cmd->retry_count = 0; 15112d1d418eSSumit Saxena } 15122d1d418eSSumit Saxena 15132d1d418eSSumit Saxena static int 15142d1d418eSSumit Saxena mpi3mr_pel_getseq(struct mpi3mr_softc *sc) 15152d1d418eSSumit Saxena { 15162d1d418eSSumit Saxena int rval = 0; 15172d1d418eSSumit Saxena U8 sgl_flags = 0; 15182d1d418eSSumit Saxena Mpi3PELReqActionGetSequenceNumbers_t pel_getseq_req; 15192d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 15202d1d418eSSumit Saxena 15212d1d418eSSumit Saxena if (sc->reset_in_progress || sc->block_ioctls) { 15222d1d418eSSumit Saxena printf(IOCNAME "%s: IOCTL failed: reset in progress: %u ioctls blocked: %u\n", 15232d1d418eSSumit Saxena sc->name, __func__, sc->reset_in_progress, sc->block_ioctls); 15242d1d418eSSumit Saxena return -1; 15252d1d418eSSumit Saxena } 15262d1d418eSSumit Saxena 15272d1d418eSSumit Saxena memset(&pel_getseq_req, 0, sizeof(pel_getseq_req)); 15282d1d418eSSumit Saxena sgl_flags = MPI3MR_SGEFLAGS_SYSTEM_SIMPLE_END_OF_LIST; 15292d1d418eSSumit Saxena sc->pel_cmds.state = MPI3MR_CMD_PENDING; 15302d1d418eSSumit Saxena sc->pel_cmds.is_waiting = 0; 15312d1d418eSSumit Saxena sc->pel_cmds.retry_count = 0; 15322d1d418eSSumit Saxena sc->pel_cmds.ioc_status = 0; 15332d1d418eSSumit Saxena sc->pel_cmds.ioc_loginfo = 0; 15342d1d418eSSumit Saxena sc->pel_cmds.callback = mpi3mr_pel_getseq_complete; 15352d1d418eSSumit Saxena pel_getseq_req.HostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 15362d1d418eSSumit Saxena pel_getseq_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 15372d1d418eSSumit Saxena pel_getseq_req.Action = MPI3_PEL_ACTION_GET_SEQNUM; 15382d1d418eSSumit Saxena mpi3mr_add_sg_single(&pel_getseq_req.SGL, sgl_flags, 15392d1d418eSSumit Saxena sc->pel_seq_number_sz, sc->pel_seq_number_dma); 15402d1d418eSSumit Saxena 15412d1d418eSSumit Saxena if ((rval = mpi3mr_submit_admin_cmd(sc, &pel_getseq_req, sizeof(pel_getseq_req)))) 15422d1d418eSSumit Saxena printf(IOCNAME "%s: Issue IOCTL: Admin Post failed\n", sc->name, __func__); 15432d1d418eSSumit Saxena 15442d1d418eSSumit Saxena return rval; 15452d1d418eSSumit Saxena } 15462d1d418eSSumit Saxena 15472d1d418eSSumit Saxena int 15482d1d418eSSumit Saxena mpi3mr_pel_abort(struct mpi3mr_softc *sc) 15492d1d418eSSumit Saxena { 15502d1d418eSSumit Saxena int retval = 0; 15512d1d418eSSumit Saxena U16 pel_log_status; 15522d1d418eSSumit Saxena Mpi3PELReqActionAbort_t pel_abort_req; 15532d1d418eSSumit Saxena Mpi3PELReply_t *pel_reply = NULL; 15542d1d418eSSumit Saxena 15552d1d418eSSumit Saxena if (sc->reset_in_progress || sc->block_ioctls) { 15562d1d418eSSumit Saxena printf(IOCNAME "%s: IOCTL failed: reset in progress: %u ioctls blocked: %u\n", 15572d1d418eSSumit Saxena sc->name, __func__, sc->reset_in_progress, sc->block_ioctls); 15582d1d418eSSumit Saxena return -1; 15592d1d418eSSumit Saxena } 15602d1d418eSSumit Saxena 15612d1d418eSSumit Saxena memset(&pel_abort_req, 0, sizeof(pel_abort_req)); 15622d1d418eSSumit Saxena 15632d1d418eSSumit Saxena mtx_lock(&sc->pel_abort_cmd.completion.lock); 15642d1d418eSSumit Saxena if (sc->pel_abort_cmd.state & MPI3MR_CMD_PENDING) { 15652d1d418eSSumit Saxena printf(IOCNAME "%s: PEL Abort command is in use\n", sc->name, __func__); 15662d1d418eSSumit Saxena mtx_unlock(&sc->pel_abort_cmd.completion.lock); 15672d1d418eSSumit Saxena return -1; 15682d1d418eSSumit Saxena } 15692d1d418eSSumit Saxena 15702d1d418eSSumit Saxena sc->pel_abort_cmd.state = MPI3MR_CMD_PENDING; 15712d1d418eSSumit Saxena sc->pel_abort_cmd.is_waiting = 1; 15722d1d418eSSumit Saxena sc->pel_abort_cmd.callback = NULL; 15732d1d418eSSumit Saxena pel_abort_req.HostTag = htole16(MPI3MR_HOSTTAG_PELABORT); 15742d1d418eSSumit Saxena pel_abort_req.Function = MPI3_FUNCTION_PERSISTENT_EVENT_LOG; 15752d1d418eSSumit Saxena pel_abort_req.Action = MPI3_PEL_ACTION_ABORT; 15762d1d418eSSumit Saxena pel_abort_req.AbortHostTag = htole16(MPI3MR_HOSTTAG_PELWAIT); 15772d1d418eSSumit Saxena 15782d1d418eSSumit Saxena sc->pel_abort_requested = 1; 15792d1d418eSSumit Saxena 15802d1d418eSSumit Saxena init_completion(&sc->pel_abort_cmd.completion); 15812d1d418eSSumit Saxena retval = mpi3mr_submit_admin_cmd(sc, &pel_abort_req, sizeof(pel_abort_req)); 15822d1d418eSSumit Saxena if (retval) { 15832d1d418eSSumit Saxena printf(IOCNAME "%s: Issue IOCTL: Admin Post failed\n", sc->name, __func__); 15842d1d418eSSumit Saxena sc->pel_abort_requested = 0; 15852d1d418eSSumit Saxena retval = -1; 15862d1d418eSSumit Saxena goto out_unlock; 15872d1d418eSSumit Saxena } 15882d1d418eSSumit Saxena wait_for_completion_timeout(&sc->pel_abort_cmd.completion, MPI3MR_INTADMCMD_TIMEOUT); 15892d1d418eSSumit Saxena 15902d1d418eSSumit Saxena if (!(sc->pel_abort_cmd.state & MPI3MR_CMD_COMPLETE)) { 15912d1d418eSSumit Saxena printf(IOCNAME "%s: PEL Abort command timedout\n",sc->name, __func__); 15922d1d418eSSumit Saxena sc->pel_abort_cmd.is_waiting = 0; 15932d1d418eSSumit Saxena retval = -1; 15942d1d418eSSumit Saxena sc->reset.type = MPI3MR_TRIGGER_SOFT_RESET; 15952d1d418eSSumit Saxena sc->reset.reason = MPI3MR_RESET_FROM_PELABORT_TIMEOUT; 15962d1d418eSSumit Saxena goto out_unlock; 15972d1d418eSSumit Saxena } 15982d1d418eSSumit Saxena if (((GET_IOC_STATUS(sc->pel_abort_cmd.ioc_status)) != MPI3_IOCSTATUS_SUCCESS) 15992d1d418eSSumit Saxena || (!(sc->pel_abort_cmd.state & MPI3MR_CMD_REPLYVALID))) { 16002d1d418eSSumit Saxena printf(IOCNAME "%s: PEL Abort command failed, ioc_status(0x%04x) log_info(0x%08x)\n", 16012d1d418eSSumit Saxena sc->name, __func__, GET_IOC_STATUS(sc->pel_abort_cmd.ioc_status), 16022d1d418eSSumit Saxena sc->pel_abort_cmd.ioc_loginfo); 16032d1d418eSSumit Saxena retval = -1; 16042d1d418eSSumit Saxena goto out_unlock; 16052d1d418eSSumit Saxena } 16062d1d418eSSumit Saxena 16072d1d418eSSumit Saxena pel_reply = (Mpi3PELReply_t *)sc->pel_abort_cmd.reply; 16082d1d418eSSumit Saxena pel_log_status = le16toh(pel_reply->PELogStatus); 16092d1d418eSSumit Saxena if (pel_log_status != MPI3_PEL_STATUS_SUCCESS) { 16102d1d418eSSumit Saxena printf(IOCNAME "%s: PEL abort command failed, pel_status(0x%04x)\n", 16112d1d418eSSumit Saxena sc->name, __func__, pel_log_status); 16122d1d418eSSumit Saxena retval = -1; 16132d1d418eSSumit Saxena } 16142d1d418eSSumit Saxena 16152d1d418eSSumit Saxena out_unlock: 16162d1d418eSSumit Saxena mtx_unlock(&sc->pel_abort_cmd.completion.lock); 16172d1d418eSSumit Saxena sc->pel_abort_cmd.state = MPI3MR_CMD_NOTUSED; 16182d1d418eSSumit Saxena return retval; 16192d1d418eSSumit Saxena } 16202d1d418eSSumit Saxena 16212d1d418eSSumit Saxena /** 16222d1d418eSSumit Saxena * mpi3mr_pel_enable - Handler for PEL enable 16232d1d418eSSumit Saxena * @sc: Adapter instance reference 16242d1d418eSSumit Saxena * @data_out_buf: User buffer containing PEL enable data 16252d1d418eSSumit Saxena * @data_out_sz: length of the user buffer. 16262d1d418eSSumit Saxena * 16272d1d418eSSumit Saxena * This function is the handler for PEL enable driver IOCTL. 16282d1d418eSSumit Saxena * Validates the application given class and locale and if 16292d1d418eSSumit Saxena * requires aborts the existing PEL wait request and/or issues 16302d1d418eSSumit Saxena * new PEL wait request to the firmware and returns. 16312d1d418eSSumit Saxena * 16322d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure. 16332d1d418eSSumit Saxena */ 16342d1d418eSSumit Saxena static long 16352d1d418eSSumit Saxena mpi3mr_pel_enable(struct mpi3mr_softc *sc, 16362d1d418eSSumit Saxena void *data_out_buf, U32 data_out_sz) 16372d1d418eSSumit Saxena { 16382d1d418eSSumit Saxena long rval = EINVAL; 16392d1d418eSSumit Saxena U8 tmp_class; 16402d1d418eSSumit Saxena U16 tmp_locale; 16412d1d418eSSumit Saxena struct mpi3mr_ioctl_pel_enable pel_enable; 16422d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_TRACE, "%s() line: %d\n", __func__, __LINE__); 16432d1d418eSSumit Saxena 1644042808f7SChandrakanth patil if (sc->unrecoverable) { 1645042808f7SChandrakanth patil device_printf(sc->mpi3mr_dev, "Issue IOCTL: controller is in unrecoverable state\n"); 1646042808f7SChandrakanth patil return EFAULT; 1647042808f7SChandrakanth patil } 1648042808f7SChandrakanth patil if (sc->reset_in_progress) { 1649042808f7SChandrakanth patil device_printf(sc->mpi3mr_dev, "Issue IOCTL: reset in progress\n"); 1650042808f7SChandrakanth patil return EAGAIN; 1651042808f7SChandrakanth patil } 1652042808f7SChandrakanth patil if (sc->block_ioctls) { 1653042808f7SChandrakanth patil device_printf(sc->mpi3mr_dev, "Issue IOCTL: IOCTLs are blocked\n"); 1654042808f7SChandrakanth patil return EAGAIN; 1655042808f7SChandrakanth patil } 16562d1d418eSSumit Saxena 16572d1d418eSSumit Saxena if ((data_out_sz != sizeof(pel_enable) || 16582d1d418eSSumit Saxena (pel_enable.pel_class > MPI3_PEL_CLASS_FAULT))) { 16592d1d418eSSumit Saxena printf(IOCNAME "%s: Invalid user pel_enable buffer size %u\n", 16602d1d418eSSumit Saxena sc->name, __func__, data_out_sz); 16612d1d418eSSumit Saxena goto out; 16622d1d418eSSumit Saxena } 16632d1d418eSSumit Saxena memset(&pel_enable, 0, sizeof(pel_enable)); 16642d1d418eSSumit Saxena if (copyin(data_out_buf, &pel_enable, sizeof(pel_enable))) { 16652d1d418eSSumit Saxena printf(IOCNAME "failure at %s() line:%d\n", sc->name, 16662d1d418eSSumit Saxena __func__, __LINE__); 16672d1d418eSSumit Saxena rval = EFAULT; 16682d1d418eSSumit Saxena goto out; 16692d1d418eSSumit Saxena } 16702d1d418eSSumit Saxena if (pel_enable.pel_class > MPI3_PEL_CLASS_FAULT) { 16712d1d418eSSumit Saxena printf(IOCNAME "%s: out of range class %d\n", 16722d1d418eSSumit Saxena sc->name, __func__, pel_enable.pel_class); 16732d1d418eSSumit Saxena goto out; 16742d1d418eSSumit Saxena } 16752d1d418eSSumit Saxena 16762d1d418eSSumit Saxena if (sc->pel_wait_pend) { 16772d1d418eSSumit Saxena if ((sc->pel_class <= pel_enable.pel_class) && 16782d1d418eSSumit Saxena !((sc->pel_locale & pel_enable.pel_locale) ^ 16792d1d418eSSumit Saxena pel_enable.pel_locale)) { 16802d1d418eSSumit Saxena rval = 0; 16812d1d418eSSumit Saxena goto out; 16822d1d418eSSumit Saxena } else { 16832d1d418eSSumit Saxena pel_enable.pel_locale |= sc->pel_locale; 16842d1d418eSSumit Saxena if (sc->pel_class < pel_enable.pel_class) 16852d1d418eSSumit Saxena pel_enable.pel_class = sc->pel_class; 16862d1d418eSSumit Saxena 16872d1d418eSSumit Saxena if (mpi3mr_pel_abort(sc)) { 16882d1d418eSSumit Saxena printf(IOCNAME "%s: pel_abort failed, status(%ld)\n", 16892d1d418eSSumit Saxena sc->name, __func__, rval); 16902d1d418eSSumit Saxena goto out; 16912d1d418eSSumit Saxena } 16922d1d418eSSumit Saxena } 16932d1d418eSSumit Saxena } 16942d1d418eSSumit Saxena 16952d1d418eSSumit Saxena tmp_class = sc->pel_class; 16962d1d418eSSumit Saxena tmp_locale = sc->pel_locale; 16972d1d418eSSumit Saxena sc->pel_class = pel_enable.pel_class; 16982d1d418eSSumit Saxena sc->pel_locale = pel_enable.pel_locale; 16992d1d418eSSumit Saxena sc->pel_wait_pend = 1; 17002d1d418eSSumit Saxena 17012d1d418eSSumit Saxena if ((rval = mpi3mr_pel_getseq(sc))) { 17022d1d418eSSumit Saxena sc->pel_class = tmp_class; 17032d1d418eSSumit Saxena sc->pel_locale = tmp_locale; 17042d1d418eSSumit Saxena sc->pel_wait_pend = 0; 17052d1d418eSSumit Saxena printf(IOCNAME "%s: pel get sequence number failed, status(%ld)\n", 17062d1d418eSSumit Saxena sc->name, __func__, rval); 17072d1d418eSSumit Saxena } 17082d1d418eSSumit Saxena 17092d1d418eSSumit Saxena out: 17102d1d418eSSumit Saxena return rval; 17112d1d418eSSumit Saxena } 17122d1d418eSSumit Saxena 17132d1d418eSSumit Saxena void 17142d1d418eSSumit Saxena mpi3mr_app_save_logdata(struct mpi3mr_softc *sc, char *event_data, 17152d1d418eSSumit Saxena U16 event_data_size) 17162d1d418eSSumit Saxena { 17172d1d418eSSumit Saxena struct mpi3mr_log_data_entry *entry; 17182d1d418eSSumit Saxena U32 index = sc->log_data_buffer_index, sz; 17192d1d418eSSumit Saxena 17202d1d418eSSumit Saxena if (!(sc->log_data_buffer)) 17212d1d418eSSumit Saxena return; 17222d1d418eSSumit Saxena 17232d1d418eSSumit Saxena entry = (struct mpi3mr_log_data_entry *) 17242d1d418eSSumit Saxena (sc->log_data_buffer + (index * sc->log_data_entry_size)); 17252d1d418eSSumit Saxena entry->valid_entry = 1; 17262d1d418eSSumit Saxena sz = min(sc->log_data_entry_size, event_data_size); 17272d1d418eSSumit Saxena memcpy(entry->data, event_data, sz); 17282d1d418eSSumit Saxena sc->log_data_buffer_index = 17292d1d418eSSumit Saxena ((++index) % MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES); 17302d1d418eSSumit Saxena mpi3mr_app_send_aen(sc); 17312d1d418eSSumit Saxena } 17322d1d418eSSumit Saxena 17332d1d418eSSumit Saxena /** 17342d1d418eSSumit Saxena * mpi3mr_get_logdata - Handler for get log data 17352d1d418eSSumit Saxena * @sc: Adapter instance reference 17362d1d418eSSumit Saxena * @data_in_buf: User buffer to copy the logdata entries 17372d1d418eSSumit Saxena * @data_in_sz: length of the user buffer. 17382d1d418eSSumit Saxena * 17392d1d418eSSumit Saxena * This function copies the log data entries to the user buffer 17402d1d418eSSumit Saxena * when log caching is enabled in the driver. 17412d1d418eSSumit Saxena * 17422d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 17432d1d418eSSumit Saxena */ 17442d1d418eSSumit Saxena static long 17452d1d418eSSumit Saxena mpi3mr_get_logdata(struct mpi3mr_softc *sc, 17462d1d418eSSumit Saxena void *data_in_buf, U32 data_in_sz) 17472d1d418eSSumit Saxena { 17482d1d418eSSumit Saxena long rval = EINVAL; 17492d1d418eSSumit Saxena U16 num_entries = 0; 17502d1d418eSSumit Saxena U16 entry_sz = sc->log_data_entry_size; 17512d1d418eSSumit Saxena 17522d1d418eSSumit Saxena if ((!sc->log_data_buffer) || (data_in_sz < entry_sz)) 17532d1d418eSSumit Saxena return rval; 17542d1d418eSSumit Saxena 17552d1d418eSSumit Saxena num_entries = data_in_sz / entry_sz; 17562d1d418eSSumit Saxena if (num_entries > MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES) 17572d1d418eSSumit Saxena num_entries = MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES; 17582d1d418eSSumit Saxena 17592d1d418eSSumit Saxena if ((rval = copyout(sc->log_data_buffer, data_in_buf, (num_entries * entry_sz)))) { 17602d1d418eSSumit Saxena printf(IOCNAME "%s: copy to user failed\n", sc->name, __func__); 17612d1d418eSSumit Saxena rval = EFAULT; 17622d1d418eSSumit Saxena } 17632d1d418eSSumit Saxena 17642d1d418eSSumit Saxena return rval; 17652d1d418eSSumit Saxena } 17662d1d418eSSumit Saxena 17672d1d418eSSumit Saxena /** 17682d1d418eSSumit Saxena * mpi3mr_logdata_enable - Handler for log data enable 17692d1d418eSSumit Saxena * @sc: Adapter instance reference 17702d1d418eSSumit Saxena * @data_in_buf: User buffer to copy the max logdata entry count 17712d1d418eSSumit Saxena * @data_in_sz: length of the user buffer. 17722d1d418eSSumit Saxena * 17732d1d418eSSumit Saxena * This function enables log data caching in the driver if not 17742d1d418eSSumit Saxena * already enabled and return the maximum number of log data 17752d1d418eSSumit Saxena * entries that can be cached in the driver. 17762d1d418eSSumit Saxena * 17772d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 17782d1d418eSSumit Saxena */ 17792d1d418eSSumit Saxena static long 17802d1d418eSSumit Saxena mpi3mr_logdata_enable(struct mpi3mr_softc *sc, 17812d1d418eSSumit Saxena void *data_in_buf, U32 data_in_sz) 17822d1d418eSSumit Saxena { 17832d1d418eSSumit Saxena long rval = EINVAL; 17842d1d418eSSumit Saxena struct mpi3mr_ioctl_logdata_enable logdata_enable; 17852d1d418eSSumit Saxena 17862d1d418eSSumit Saxena if (data_in_sz < sizeof(logdata_enable)) 17872d1d418eSSumit Saxena return rval; 17882d1d418eSSumit Saxena 17892d1d418eSSumit Saxena if (sc->log_data_buffer) 17902d1d418eSSumit Saxena goto copy_data; 17912d1d418eSSumit Saxena 17922d1d418eSSumit Saxena sc->log_data_entry_size = (sc->reply_sz - (sizeof(Mpi3EventNotificationReply_t) - 4)) 17932d1d418eSSumit Saxena + MPI3MR_IOCTL_LOGDATA_ENTRY_HEADER_SZ; 17942d1d418eSSumit Saxena 17952d1d418eSSumit Saxena sc->log_data_buffer = malloc((MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES * sc->log_data_entry_size), 17962d1d418eSSumit Saxena M_MPI3MR, M_NOWAIT | M_ZERO); 17972d1d418eSSumit Saxena if (!sc->log_data_buffer) { 17982d1d418eSSumit Saxena printf(IOCNAME "%s log data buffer memory allocation failed\n", sc->name, __func__); 17992d1d418eSSumit Saxena return ENOMEM; 18002d1d418eSSumit Saxena } 18012d1d418eSSumit Saxena 18022d1d418eSSumit Saxena sc->log_data_buffer_index = 0; 18032d1d418eSSumit Saxena 18042d1d418eSSumit Saxena copy_data: 18052d1d418eSSumit Saxena memset(&logdata_enable, 0, sizeof(logdata_enable)); 18062d1d418eSSumit Saxena logdata_enable.max_entries = MPI3MR_IOCTL_LOGDATA_MAX_ENTRIES; 18072d1d418eSSumit Saxena 18082d1d418eSSumit Saxena if ((rval = copyout(&logdata_enable, data_in_buf, sizeof(logdata_enable)))) { 18092d1d418eSSumit Saxena printf(IOCNAME "%s: copy to user failed\n", sc->name, __func__); 18102d1d418eSSumit Saxena rval = EFAULT; 18112d1d418eSSumit Saxena } 18122d1d418eSSumit Saxena 18132d1d418eSSumit Saxena return rval; 18142d1d418eSSumit Saxena } 18152d1d418eSSumit Saxena 18162d1d418eSSumit Saxena /** 18172d1d418eSSumit Saxena * mpi3mr_get_change_count - Get topology change count 18182d1d418eSSumit Saxena * @sc: Adapter instance reference 18192d1d418eSSumit Saxena * @data_in_buf: User buffer to copy the change count 18202d1d418eSSumit Saxena * @data_in_sz: length of the user buffer. 18212d1d418eSSumit Saxena * 18222d1d418eSSumit Saxena * This function copies the toplogy change count provided by the 18232d1d418eSSumit Saxena * driver in events and cached in the driver to the user 18242d1d418eSSumit Saxena * provided buffer for the specific controller. 18252d1d418eSSumit Saxena * 18262d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 18272d1d418eSSumit Saxena */ 18282d1d418eSSumit Saxena static long 18292d1d418eSSumit Saxena mpi3mr_get_change_count(struct mpi3mr_softc *sc, 18302d1d418eSSumit Saxena void *data_in_buf, U32 data_in_sz) 18312d1d418eSSumit Saxena { 18322d1d418eSSumit Saxena long rval = EINVAL; 18332d1d418eSSumit Saxena struct mpi3mr_ioctl_chgcnt chg_count; 18342d1d418eSSumit Saxena memset(&chg_count, 0, sizeof(chg_count)); 18352d1d418eSSumit Saxena 18362d1d418eSSumit Saxena chg_count.change_count = sc->change_count; 18372d1d418eSSumit Saxena if (data_in_sz >= sizeof(chg_count)) { 18382d1d418eSSumit Saxena if ((rval = copyout(&chg_count, data_in_buf, sizeof(chg_count)))) { 18392d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 18402d1d418eSSumit Saxena __LINE__, __func__); 18412d1d418eSSumit Saxena rval = EFAULT; 18422d1d418eSSumit Saxena } 18432d1d418eSSumit Saxena } 18442d1d418eSSumit Saxena return rval; 18452d1d418eSSumit Saxena } 18462d1d418eSSumit Saxena 18472d1d418eSSumit Saxena /** 18482d1d418eSSumit Saxena * mpi3mr_get_alltgtinfo - Get all targets information 18492d1d418eSSumit Saxena * @sc: Adapter instance reference 18502d1d418eSSumit Saxena * @data_in_buf: User buffer to copy the target information 18512d1d418eSSumit Saxena * @data_in_sz: length of the user buffer. 18522d1d418eSSumit Saxena * 18532d1d418eSSumit Saxena * This function copies the driver managed target devices device 18542d1d418eSSumit Saxena * handle, persistent ID, bus ID and taret ID to the user 18552d1d418eSSumit Saxena * provided buffer for the specific controller. This function 18562d1d418eSSumit Saxena * also provides the number of devices managed by the driver for 18572d1d418eSSumit Saxena * the specific controller. 18582d1d418eSSumit Saxena * 18592d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 18602d1d418eSSumit Saxena */ 18612d1d418eSSumit Saxena static long 18622d1d418eSSumit Saxena mpi3mr_get_alltgtinfo(struct mpi3mr_softc *sc, 18632d1d418eSSumit Saxena void *data_in_buf, U32 data_in_sz) 18642d1d418eSSumit Saxena { 18652d1d418eSSumit Saxena long rval = EINVAL; 18662d1d418eSSumit Saxena U8 get_count = 0; 18672d1d418eSSumit Saxena U16 i = 0, num_devices = 0; 18682d1d418eSSumit Saxena U32 min_entrylen = 0, kern_entrylen = 0, user_entrylen = 0; 18692d1d418eSSumit Saxena struct mpi3mr_target *tgtdev = NULL; 18702d1d418eSSumit Saxena struct mpi3mr_device_map_info *devmap_info = NULL; 18712d1d418eSSumit Saxena struct mpi3mr_cam_softc *cam_sc = sc->cam_sc; 18722d1d418eSSumit Saxena struct mpi3mr_ioctl_all_tgtinfo *all_tgtinfo = (struct mpi3mr_ioctl_all_tgtinfo *)data_in_buf; 18732d1d418eSSumit Saxena 18742d1d418eSSumit Saxena if (data_in_sz < sizeof(uint32_t)) { 18752d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 18762d1d418eSSumit Saxena __LINE__, __func__); 18772d1d418eSSumit Saxena goto out; 18782d1d418eSSumit Saxena } 18792d1d418eSSumit Saxena if (data_in_sz == sizeof(uint32_t)) 18802d1d418eSSumit Saxena get_count = 1; 18812d1d418eSSumit Saxena 18822d1d418eSSumit Saxena if (TAILQ_EMPTY(&cam_sc->tgt_list)) { 18832d1d418eSSumit Saxena get_count = 1; 18842d1d418eSSumit Saxena goto copy_usrbuf; 18852d1d418eSSumit Saxena } 18862d1d418eSSumit Saxena 18872d1d418eSSumit Saxena mtx_lock_spin(&cam_sc->sc->target_lock); 18882d1d418eSSumit Saxena TAILQ_FOREACH(tgtdev, &cam_sc->tgt_list, tgt_next) { 18892d1d418eSSumit Saxena num_devices++; 18902d1d418eSSumit Saxena } 18912d1d418eSSumit Saxena mtx_unlock_spin(&cam_sc->sc->target_lock); 18922d1d418eSSumit Saxena 18932d1d418eSSumit Saxena if (get_count) 18942d1d418eSSumit Saxena goto copy_usrbuf; 18952d1d418eSSumit Saxena 18962d1d418eSSumit Saxena kern_entrylen = num_devices * sizeof(*devmap_info); 18972d1d418eSSumit Saxena 18982d1d418eSSumit Saxena devmap_info = malloc(kern_entrylen, M_MPI3MR, M_NOWAIT | M_ZERO); 18992d1d418eSSumit Saxena if (!devmap_info) { 19002d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 19012d1d418eSSumit Saxena __LINE__, __func__); 19022d1d418eSSumit Saxena rval = ENOMEM; 19032d1d418eSSumit Saxena goto out; 19042d1d418eSSumit Saxena } 19052d1d418eSSumit Saxena memset((U8*)devmap_info, 0xFF, kern_entrylen); 19062d1d418eSSumit Saxena 19072d1d418eSSumit Saxena mtx_lock_spin(&cam_sc->sc->target_lock); 19082d1d418eSSumit Saxena TAILQ_FOREACH(tgtdev, &cam_sc->tgt_list, tgt_next) { 19092d1d418eSSumit Saxena if (i < num_devices) { 19102d1d418eSSumit Saxena devmap_info[i].handle = tgtdev->dev_handle; 19112d1d418eSSumit Saxena devmap_info[i].per_id = tgtdev->per_id; 19122d1d418eSSumit Saxena /*n 19132d1d418eSSumit Saxena * For hidden/ugood device the target_id and bus_id should be 0xFFFFFFFF and 0xFF 19142d1d418eSSumit Saxena */ 19152d1d418eSSumit Saxena if (!tgtdev->exposed_to_os) { 19162d1d418eSSumit Saxena devmap_info[i].target_id = 0xFFFFFFFF; 19172d1d418eSSumit Saxena devmap_info[i].bus_id = 0xFF; 19182d1d418eSSumit Saxena } else { 19192d1d418eSSumit Saxena devmap_info[i].target_id = tgtdev->tid; 19202d1d418eSSumit Saxena devmap_info[i].bus_id = 0; 19212d1d418eSSumit Saxena } 19222d1d418eSSumit Saxena i++; 19232d1d418eSSumit Saxena } 19242d1d418eSSumit Saxena } 19252d1d418eSSumit Saxena num_devices = i; 19262d1d418eSSumit Saxena mtx_unlock_spin(&cam_sc->sc->target_lock); 19272d1d418eSSumit Saxena 19282d1d418eSSumit Saxena copy_usrbuf: 19292d1d418eSSumit Saxena if (copyout(&num_devices, &all_tgtinfo->num_devices, sizeof(num_devices))) { 19302d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, __FILE__, 19312d1d418eSSumit Saxena __LINE__, __func__); 19322d1d418eSSumit Saxena rval = EFAULT; 19332d1d418eSSumit Saxena goto out; 19342d1d418eSSumit Saxena } 19352d1d418eSSumit Saxena user_entrylen = (data_in_sz - sizeof(uint32_t))/sizeof(*devmap_info); 19362d1d418eSSumit Saxena user_entrylen *= sizeof(*devmap_info); 19372d1d418eSSumit Saxena min_entrylen = min(user_entrylen, kern_entrylen); 19382d1d418eSSumit Saxena if (min_entrylen && (copyout(devmap_info, &all_tgtinfo->dmi, min_entrylen))) { 19392d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 19402d1d418eSSumit Saxena __FILE__, __LINE__, __func__); 19412d1d418eSSumit Saxena rval = EFAULT; 19422d1d418eSSumit Saxena goto out; 19432d1d418eSSumit Saxena } 19442d1d418eSSumit Saxena rval = 0; 19452d1d418eSSumit Saxena out: 19462d1d418eSSumit Saxena if (devmap_info) 19472d1d418eSSumit Saxena free(devmap_info, M_MPI3MR); 19482d1d418eSSumit Saxena 19492d1d418eSSumit Saxena return rval; 19502d1d418eSSumit Saxena } 19512d1d418eSSumit Saxena 19522d1d418eSSumit Saxena /** 19532d1d418eSSumit Saxena * mpi3mr_get_tgtinfo - Get specific target information 19542d1d418eSSumit Saxena * @sc: Adapter instance reference 19552d1d418eSSumit Saxena * @karg: driver ponter to users payload buffer 19562d1d418eSSumit Saxena * 19572d1d418eSSumit Saxena * This function copies the driver managed specific target device 19582d1d418eSSumit Saxena * info like handle, persistent ID, bus ID and taret ID to the user 19592d1d418eSSumit Saxena * provided buffer for the specific controller. 19602d1d418eSSumit Saxena * 19612d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 19622d1d418eSSumit Saxena */ 19632d1d418eSSumit Saxena static long 19642d1d418eSSumit Saxena mpi3mr_get_tgtinfo(struct mpi3mr_softc *sc, 19652d1d418eSSumit Saxena struct mpi3mr_ioctl_drvcmd *karg) 19662d1d418eSSumit Saxena { 19672d1d418eSSumit Saxena long rval = EINVAL; 19682d1d418eSSumit Saxena struct mpi3mr_target *tgtdev = NULL; 19692d1d418eSSumit Saxena struct mpi3mr_ioctl_tgtinfo tgtinfo; 19702d1d418eSSumit Saxena 19712d1d418eSSumit Saxena memset(&tgtinfo, 0, sizeof(tgtinfo)); 19722d1d418eSSumit Saxena 19732d1d418eSSumit Saxena if ((karg->data_out_size != sizeof(struct mpi3mr_ioctl_tgtinfo)) || 19742d1d418eSSumit Saxena (karg->data_in_size != sizeof(struct mpi3mr_ioctl_tgtinfo))) { 19752d1d418eSSumit Saxena printf(IOCNAME "Invalid user tgtinfo buffer size %s() line: %d\n", sc->name, 19762d1d418eSSumit Saxena __func__, __LINE__); 19772d1d418eSSumit Saxena goto out; 19782d1d418eSSumit Saxena } 19792d1d418eSSumit Saxena 19802d1d418eSSumit Saxena if (copyin(karg->data_out_buf, &tgtinfo, sizeof(tgtinfo))) { 19812d1d418eSSumit Saxena printf(IOCNAME "failure at %s() line:%d\n", sc->name, 19822d1d418eSSumit Saxena __func__, __LINE__); 19832d1d418eSSumit Saxena rval = EFAULT; 19842d1d418eSSumit Saxena goto out; 19852d1d418eSSumit Saxena } 19862d1d418eSSumit Saxena 19872d1d418eSSumit Saxena if ((tgtinfo.bus_id != 0xFF) && (tgtinfo.target_id != 0xFFFFFFFF)) { 19882d1d418eSSumit Saxena if ((tgtinfo.persistent_id != 0xFFFF) || 19892d1d418eSSumit Saxena (tgtinfo.dev_handle != 0xFFFF)) 19902d1d418eSSumit Saxena goto out; 19912d1d418eSSumit Saxena tgtdev = mpi3mr_find_target_by_per_id(sc->cam_sc, tgtinfo.target_id); 19922d1d418eSSumit Saxena } else if (tgtinfo.persistent_id != 0xFFFF) { 19932d1d418eSSumit Saxena if ((tgtinfo.bus_id != 0xFF) || 19942d1d418eSSumit Saxena (tgtinfo.dev_handle !=0xFFFF) || 19952d1d418eSSumit Saxena (tgtinfo.target_id != 0xFFFFFFFF)) 19962d1d418eSSumit Saxena goto out; 19972d1d418eSSumit Saxena tgtdev = mpi3mr_find_target_by_per_id(sc->cam_sc, tgtinfo.persistent_id); 19982d1d418eSSumit Saxena } else if (tgtinfo.dev_handle !=0xFFFF) { 19992d1d418eSSumit Saxena if ((tgtinfo.bus_id != 0xFF) || 20002d1d418eSSumit Saxena (tgtinfo.target_id != 0xFFFFFFFF) || 20012d1d418eSSumit Saxena (tgtinfo.persistent_id != 0xFFFF)) 20022d1d418eSSumit Saxena goto out; 20032d1d418eSSumit Saxena tgtdev = mpi3mr_find_target_by_dev_handle(sc->cam_sc, tgtinfo.dev_handle); 20042d1d418eSSumit Saxena } 20052d1d418eSSumit Saxena if (!tgtdev) 20062d1d418eSSumit Saxena goto out; 20072d1d418eSSumit Saxena 20082d1d418eSSumit Saxena tgtinfo.target_id = tgtdev->per_id; 20092d1d418eSSumit Saxena tgtinfo.bus_id = 0; 20102d1d418eSSumit Saxena tgtinfo.dev_handle = tgtdev->dev_handle; 20112d1d418eSSumit Saxena tgtinfo.persistent_id = tgtdev->per_id; 20122d1d418eSSumit Saxena tgtinfo.seq_num = 0; 20132d1d418eSSumit Saxena 20142d1d418eSSumit Saxena if (copyout(&tgtinfo, karg->data_in_buf, sizeof(tgtinfo))) { 20152d1d418eSSumit Saxena printf(IOCNAME "failure at %s() line:%d\n", sc->name, 20162d1d418eSSumit Saxena __func__, __LINE__); 20172d1d418eSSumit Saxena rval = EFAULT; 20182d1d418eSSumit Saxena } 20192d1d418eSSumit Saxena 20202d1d418eSSumit Saxena out: 20212d1d418eSSumit Saxena return rval; 20222d1d418eSSumit Saxena } 20232d1d418eSSumit Saxena 20242d1d418eSSumit Saxena /** 20252d1d418eSSumit Saxena * mpi3mr_get_pciinfo - Get PCI info IOCTL handler 20262d1d418eSSumit Saxena * @sc: Adapter instance reference 20272d1d418eSSumit Saxena * @data_in_buf: User buffer to hold adapter information 20282d1d418eSSumit Saxena * @data_in_sz: length of the user buffer. 20292d1d418eSSumit Saxena * 20302d1d418eSSumit Saxena * This function provides the PCI spec information for the 20312d1d418eSSumit Saxena * given controller 20322d1d418eSSumit Saxena * 20332d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 20342d1d418eSSumit Saxena */ 20352d1d418eSSumit Saxena static long 20362d1d418eSSumit Saxena mpi3mr_get_pciinfo(struct mpi3mr_softc *sc, 20372d1d418eSSumit Saxena void *data_in_buf, U32 data_in_sz) 20382d1d418eSSumit Saxena { 20392d1d418eSSumit Saxena long rval = EINVAL; 20402d1d418eSSumit Saxena U8 i; 20412d1d418eSSumit Saxena struct mpi3mr_ioctl_pciinfo pciinfo; 20422d1d418eSSumit Saxena memset(&pciinfo, 0, sizeof(pciinfo)); 20432d1d418eSSumit Saxena 20442d1d418eSSumit Saxena for (i = 0; i < 64; i++) 20452d1d418eSSumit Saxena pciinfo.config_space[i] = pci_read_config(sc->mpi3mr_dev, (i * 4), 4); 20462d1d418eSSumit Saxena 20472d1d418eSSumit Saxena if (data_in_sz >= sizeof(pciinfo)) { 20482d1d418eSSumit Saxena if ((rval = copyout(&pciinfo, data_in_buf, sizeof(pciinfo)))) { 20492d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 20502d1d418eSSumit Saxena __FILE__, __LINE__, __func__); 20512d1d418eSSumit Saxena rval = EFAULT; 20522d1d418eSSumit Saxena } 20532d1d418eSSumit Saxena } 20542d1d418eSSumit Saxena return rval; 20552d1d418eSSumit Saxena } 20562d1d418eSSumit Saxena 20572d1d418eSSumit Saxena /** 20582d1d418eSSumit Saxena * mpi3mr_get_adpinfo - Get adapter info IOCTL handler 20592d1d418eSSumit Saxena * @sc: Adapter instance reference 20602d1d418eSSumit Saxena * @data_in_buf: User buffer to hold adapter information 20612d1d418eSSumit Saxena * @data_in_sz: length of the user buffer. 20622d1d418eSSumit Saxena * 20632d1d418eSSumit Saxena * This function provides adapter information for the given 20642d1d418eSSumit Saxena * controller 20652d1d418eSSumit Saxena * 20662d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 20672d1d418eSSumit Saxena */ 20682d1d418eSSumit Saxena static long 20692d1d418eSSumit Saxena mpi3mr_get_adpinfo(struct mpi3mr_softc *sc, 20702d1d418eSSumit Saxena void *data_in_buf, U32 data_in_sz) 20712d1d418eSSumit Saxena { 20722d1d418eSSumit Saxena long rval = EINVAL; 20732d1d418eSSumit Saxena struct mpi3mr_ioctl_adpinfo adpinfo; 20742d1d418eSSumit Saxena enum mpi3mr_iocstate ioc_state; 20752d1d418eSSumit Saxena memset(&adpinfo, 0, sizeof(adpinfo)); 20762d1d418eSSumit Saxena 20772d1d418eSSumit Saxena adpinfo.adp_type = MPI3MR_IOCTL_ADPTYPE_AVGFAMILY; 20782d1d418eSSumit Saxena adpinfo.pci_dev_id = pci_get_device(sc->mpi3mr_dev); 20792d1d418eSSumit Saxena adpinfo.pci_dev_hw_rev = pci_read_config(sc->mpi3mr_dev, PCIR_REVID, 1); 20802d1d418eSSumit Saxena adpinfo.pci_subsys_dev_id = pci_get_subdevice(sc->mpi3mr_dev); 20812d1d418eSSumit Saxena adpinfo.pci_subsys_ven_id = pci_get_subvendor(sc->mpi3mr_dev); 2082*86a2c910SZhenlei Huang adpinfo.pci_bus = pci_get_bus(sc->mpi3mr_dev); 20832d1d418eSSumit Saxena adpinfo.pci_dev = pci_get_slot(sc->mpi3mr_dev); 20842d1d418eSSumit Saxena adpinfo.pci_func = pci_get_function(sc->mpi3mr_dev); 20852d1d418eSSumit Saxena adpinfo.pci_seg_id = pci_get_domain(sc->mpi3mr_dev); 20862d1d418eSSumit Saxena adpinfo.ioctl_ver = MPI3MR_IOCTL_VERSION; 20872d1d418eSSumit Saxena memcpy((U8 *)&adpinfo.driver_info, (U8 *)&sc->driver_info, sizeof(adpinfo.driver_info)); 20882d1d418eSSumit Saxena 20892d1d418eSSumit Saxena ioc_state = mpi3mr_get_iocstate(sc); 20902d1d418eSSumit Saxena 20912d1d418eSSumit Saxena if (ioc_state == MRIOC_STATE_UNRECOVERABLE) 20922d1d418eSSumit Saxena adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_UNRECOVERABLE; 20932d1d418eSSumit Saxena else if (sc->reset_in_progress || sc->block_ioctls) 20942d1d418eSSumit Saxena adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_IN_RESET; 20952d1d418eSSumit Saxena else if (ioc_state == MRIOC_STATE_FAULT) 20962d1d418eSSumit Saxena adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_FAULT; 20972d1d418eSSumit Saxena else 20982d1d418eSSumit Saxena adpinfo.adp_state = MPI3MR_IOCTL_ADP_STATE_OPERATIONAL; 20992d1d418eSSumit Saxena 21002d1d418eSSumit Saxena if (data_in_sz >= sizeof(adpinfo)) { 21012d1d418eSSumit Saxena if ((rval = copyout(&adpinfo, data_in_buf, sizeof(adpinfo)))) { 21022d1d418eSSumit Saxena printf(IOCNAME "failure at %s:%d/%s()!\n", sc->name, 21032d1d418eSSumit Saxena __FILE__, __LINE__, __func__); 21042d1d418eSSumit Saxena rval = EFAULT; 21052d1d418eSSumit Saxena } 21062d1d418eSSumit Saxena } 21072d1d418eSSumit Saxena return rval; 21082d1d418eSSumit Saxena } 21092d1d418eSSumit Saxena /** 21102d1d418eSSumit Saxena * mpi3mr_app_drvrcmds - Driver IOCTL handler 21112d1d418eSSumit Saxena * @dev: char device 21122d1d418eSSumit Saxena * @cmd: IOCTL command 21132d1d418eSSumit Saxena * @arg: User data payload buffer for the IOCTL 21142d1d418eSSumit Saxena * @flag: flags 21152d1d418eSSumit Saxena * @thread: threads 21162d1d418eSSumit Saxena * 21172d1d418eSSumit Saxena * This function is the top level handler for driver commands, 21182d1d418eSSumit Saxena * this does basic validation of the buffer and identifies the 21192d1d418eSSumit Saxena * opcode and switches to correct sub handler. 21202d1d418eSSumit Saxena * 21212d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 21222d1d418eSSumit Saxena */ 21232d1d418eSSumit Saxena 21242d1d418eSSumit Saxena static int 21252d1d418eSSumit Saxena mpi3mr_app_drvrcmds(struct cdev *dev, u_long cmd, 21262d1d418eSSumit Saxena void *uarg, int flag, struct thread *td) 21272d1d418eSSumit Saxena { 21282d1d418eSSumit Saxena long rval = EINVAL; 21292d1d418eSSumit Saxena struct mpi3mr_softc *sc = NULL; 21302d1d418eSSumit Saxena struct mpi3mr_ioctl_drvcmd *karg = (struct mpi3mr_ioctl_drvcmd *)uarg; 21312d1d418eSSumit Saxena 21322d1d418eSSumit Saxena sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); 21332d1d418eSSumit Saxena if (!sc) 21342d1d418eSSumit Saxena return ENODEV; 21352d1d418eSSumit Saxena 21362d1d418eSSumit Saxena mtx_lock(&sc->ioctl_cmds.completion.lock); 21372d1d418eSSumit Saxena switch (karg->opcode) { 21382d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_ADPINFO: 21392d1d418eSSumit Saxena rval = mpi3mr_get_adpinfo(sc, karg->data_in_buf, karg->data_in_size); 21402d1d418eSSumit Saxena break; 21412d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_GETPCIINFO: 21422d1d418eSSumit Saxena rval = mpi3mr_get_pciinfo(sc, karg->data_in_buf, karg->data_in_size); 21432d1d418eSSumit Saxena break; 21442d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_TGTDEVINFO: 21452d1d418eSSumit Saxena rval = mpi3mr_get_tgtinfo(sc, karg); 21462d1d418eSSumit Saxena break; 21472d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_ALLTGTDEVINFO: 21482d1d418eSSumit Saxena rval = mpi3mr_get_alltgtinfo(sc, karg->data_in_buf, karg->data_in_size); 21492d1d418eSSumit Saxena break; 21502d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_GETCHGCNT: 21512d1d418eSSumit Saxena rval = mpi3mr_get_change_count(sc, karg->data_in_buf, karg->data_in_size); 21522d1d418eSSumit Saxena break; 21532d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_LOGDATAENABLE: 21542d1d418eSSumit Saxena rval = mpi3mr_logdata_enable(sc, karg->data_in_buf, karg->data_in_size); 21552d1d418eSSumit Saxena break; 21562d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_GETLOGDATA: 21572d1d418eSSumit Saxena rval = mpi3mr_get_logdata(sc, karg->data_in_buf, karg->data_in_size); 21582d1d418eSSumit Saxena break; 21592d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_PELENABLE: 21602d1d418eSSumit Saxena rval = mpi3mr_pel_enable(sc, karg->data_out_buf, karg->data_out_size); 21612d1d418eSSumit Saxena break; 21622d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_ADPRESET: 21632d1d418eSSumit Saxena rval = mpi3mr_adp_reset(sc, karg->data_out_buf, karg->data_out_size); 21642d1d418eSSumit Saxena break; 21652d1d418eSSumit Saxena case MPI3MR_DRVRIOCTL_OPCODE_UNKNOWN: 21662d1d418eSSumit Saxena default: 21672d1d418eSSumit Saxena printf("Unsupported drvr ioctl opcode 0x%x\n", karg->opcode); 21682d1d418eSSumit Saxena break; 21692d1d418eSSumit Saxena } 21702d1d418eSSumit Saxena mtx_unlock(&sc->ioctl_cmds.completion.lock); 21712d1d418eSSumit Saxena return rval; 21722d1d418eSSumit Saxena } 21732d1d418eSSumit Saxena /** 21742d1d418eSSumit Saxena * mpi3mr_ioctl - IOCTL Handler 21752d1d418eSSumit Saxena * @dev: char device 21762d1d418eSSumit Saxena * @cmd: IOCTL command 21772d1d418eSSumit Saxena * @arg: User data payload buffer for the IOCTL 21782d1d418eSSumit Saxena * @flag: flags 21792d1d418eSSumit Saxena * @thread: threads 21802d1d418eSSumit Saxena * 21812d1d418eSSumit Saxena * This is the IOCTL entry point which checks the command type and 21822d1d418eSSumit Saxena * executes proper sub handler specific for the command. 21832d1d418eSSumit Saxena * 21842d1d418eSSumit Saxena * Return: 0 on success and proper error codes on failure 21852d1d418eSSumit Saxena */ 21862d1d418eSSumit Saxena static int 21872d1d418eSSumit Saxena mpi3mr_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 21882d1d418eSSumit Saxena { 21892d1d418eSSumit Saxena int rval = EINVAL; 21902d1d418eSSumit Saxena 21912d1d418eSSumit Saxena struct mpi3mr_softc *sc = NULL; 21922d1d418eSSumit Saxena struct mpi3mr_ioctl_drvcmd *karg = (struct mpi3mr_ioctl_drvcmd *)arg; 21932d1d418eSSumit Saxena 21942d1d418eSSumit Saxena sc = mpi3mr_app_get_adp_instance(karg->mrioc_id); 21952d1d418eSSumit Saxena 21962d1d418eSSumit Saxena if (!sc) 21972d1d418eSSumit Saxena return ENODEV; 21982d1d418eSSumit Saxena 21992d1d418eSSumit Saxena mpi3mr_atomic_inc(&sc->pend_ioctls); 22002d1d418eSSumit Saxena 22012d1d418eSSumit Saxena 22022d1d418eSSumit Saxena if (sc->mpi3mr_flags & MPI3MR_FLAGS_SHUTDOWN) { 22032d1d418eSSumit Saxena mpi3mr_dprint(sc, MPI3MR_INFO, 22042d1d418eSSumit Saxena "Return back IOCTL, shutdown is in progress\n"); 22052d1d418eSSumit Saxena mpi3mr_atomic_dec(&sc->pend_ioctls); 22062d1d418eSSumit Saxena return ENODEV; 22072d1d418eSSumit Saxena } 22082d1d418eSSumit Saxena 22092d1d418eSSumit Saxena switch (cmd) { 22102d1d418eSSumit Saxena case MPI3MRDRVCMD: 22112d1d418eSSumit Saxena rval = mpi3mr_app_drvrcmds(dev, cmd, arg, flag, td); 22122d1d418eSSumit Saxena break; 22132d1d418eSSumit Saxena case MPI3MRMPTCMD: 22142d1d418eSSumit Saxena mtx_lock(&sc->ioctl_cmds.completion.lock); 22152d1d418eSSumit Saxena rval = mpi3mr_app_mptcmds(dev, cmd, arg, flag, td); 22162d1d418eSSumit Saxena mtx_unlock(&sc->ioctl_cmds.completion.lock); 22172d1d418eSSumit Saxena break; 22182d1d418eSSumit Saxena default: 22192d1d418eSSumit Saxena printf("%s:Unsupported ioctl cmd (0x%08lx)\n", MPI3MR_DRIVER_NAME, cmd); 22202d1d418eSSumit Saxena break; 22212d1d418eSSumit Saxena } 22222d1d418eSSumit Saxena 22232d1d418eSSumit Saxena mpi3mr_atomic_dec(&sc->pend_ioctls); 22242d1d418eSSumit Saxena 22252d1d418eSSumit Saxena return rval; 22262d1d418eSSumit Saxena } 2227