11e66f787SSean Bruno /*- 21e66f787SSean Bruno * Copyright (c) 2018 Microsemi Corporation. 31e66f787SSean Bruno * All rights reserved. 41e66f787SSean Bruno * 51e66f787SSean Bruno * Redistribution and use in source and binary forms, with or without 61e66f787SSean Bruno * modification, are permitted provided that the following conditions 71e66f787SSean Bruno * are met: 81e66f787SSean Bruno * 1. Redistributions of source code must retain the above copyright 91e66f787SSean Bruno * notice, this list of conditions and the following disclaimer. 101e66f787SSean Bruno * 2. Redistributions in binary form must reproduce the above copyright 111e66f787SSean Bruno * notice, this list of conditions and the following disclaimer in the 121e66f787SSean Bruno * documentation and/or other materials provided with the distribution. 131e66f787SSean Bruno * 141e66f787SSean Bruno * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 151e66f787SSean Bruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 161e66f787SSean Bruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 171e66f787SSean Bruno * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 181e66f787SSean Bruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 191e66f787SSean Bruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 201e66f787SSean Bruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 211e66f787SSean Bruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 221e66f787SSean Bruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 231e66f787SSean Bruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 241e66f787SSean Bruno * SUCH DAMAGE. 251e66f787SSean Bruno */ 261e66f787SSean Bruno 271e66f787SSean Bruno /* $FreeBSD$ */ 281e66f787SSean Bruno 291e66f787SSean Bruno /* 301e66f787SSean Bruno * Management interface for smartpqi driver 311e66f787SSean Bruno */ 321e66f787SSean Bruno 331e66f787SSean Bruno #include "smartpqi_includes.h" 341e66f787SSean Bruno 351e66f787SSean Bruno /* 361e66f787SSean Bruno * Wrapper function to copy to user from kernel 371e66f787SSean Bruno */ 381e66f787SSean Bruno int os_copy_to_user(struct pqisrc_softstate *softs, void *dest_buf, 391e66f787SSean Bruno void *src_buf, int size, int mode) 401e66f787SSean Bruno { 411e66f787SSean Bruno return(copyout(src_buf, dest_buf, size)); 421e66f787SSean Bruno } 431e66f787SSean Bruno 441e66f787SSean Bruno /* 451e66f787SSean Bruno * Wrapper function to copy from user to kernel 461e66f787SSean Bruno */ 471e66f787SSean Bruno int os_copy_from_user(struct pqisrc_softstate *softs, void *dest_buf, 481e66f787SSean Bruno void *src_buf, int size, int mode) 491e66f787SSean Bruno { 501e66f787SSean Bruno return(copyin(src_buf, dest_buf, size)); 511e66f787SSean Bruno } 521e66f787SSean Bruno 531e66f787SSean Bruno /* 541e66f787SSean Bruno * Device open function for ioctl entry 551e66f787SSean Bruno */ 561e66f787SSean Bruno static int smartpqi_open(struct cdev *cdev, int flags, int devtype, 571e66f787SSean Bruno struct thread *td) 581e66f787SSean Bruno { 591e66f787SSean Bruno int error = PQI_STATUS_SUCCESS; 601e66f787SSean Bruno 611e66f787SSean Bruno return error; 621e66f787SSean Bruno } 631e66f787SSean Bruno 641e66f787SSean Bruno /* 651e66f787SSean Bruno * Device close function for ioctl entry 661e66f787SSean Bruno */ 671e66f787SSean Bruno static int smartpqi_close(struct cdev *cdev, int flags, int devtype, 681e66f787SSean Bruno struct thread *td) 691e66f787SSean Bruno { 701e66f787SSean Bruno int error = PQI_STATUS_SUCCESS; 711e66f787SSean Bruno 721e66f787SSean Bruno return error; 731e66f787SSean Bruno } 741e66f787SSean Bruno 751e66f787SSean Bruno /* 761e66f787SSean Bruno * ioctl for getting driver info 771e66f787SSean Bruno */ 781e66f787SSean Bruno static void smartpqi_get_driver_info_ioctl(caddr_t udata, struct cdev *cdev) 791e66f787SSean Bruno { 801e66f787SSean Bruno struct pqisrc_softstate *softs = cdev->si_drv1; 811e66f787SSean Bruno pdriver_info driver_info = (pdriver_info)udata; 821e66f787SSean Bruno 831e66f787SSean Bruno DBG_FUNC("IN udata = %p cdev = %p\n", udata, cdev); 841e66f787SSean Bruno 851e66f787SSean Bruno driver_info->major_version = PQISRC_DRIVER_MAJOR; 861e66f787SSean Bruno driver_info->minor_version = PQISRC_DRIVER_MINOR; 871e66f787SSean Bruno driver_info->release_version = PQISRC_DRIVER_RELEASE; 881e66f787SSean Bruno driver_info->build_revision = PQISRC_DRIVER_REVISION; 891e66f787SSean Bruno driver_info->max_targets = PQI_MAX_DEVICES - 1; 901e66f787SSean Bruno driver_info->max_io = softs->max_io_for_scsi_ml; 911e66f787SSean Bruno driver_info->max_transfer_length = softs->pqi_cap.max_transfer_size; 921e66f787SSean Bruno 931e66f787SSean Bruno DBG_FUNC("OUT\n"); 941e66f787SSean Bruno } 951e66f787SSean Bruno 961e66f787SSean Bruno /* 971e66f787SSean Bruno * ioctl for getting controller info 981e66f787SSean Bruno */ 991e66f787SSean Bruno static void smartpqi_get_pci_info_ioctl(caddr_t udata, struct cdev *cdev) 1001e66f787SSean Bruno { 1011e66f787SSean Bruno struct pqisrc_softstate *softs = cdev->si_drv1; 1021e66f787SSean Bruno device_t dev = softs->os_specific.pqi_dev; 1031e66f787SSean Bruno pqi_pci_info_t *pci_info = (pqi_pci_info_t *)udata; 1041e66f787SSean Bruno uint32_t sub_vendor = 0; 1051e66f787SSean Bruno uint32_t sub_device = 0; 1061e66f787SSean Bruno uint32_t vendor = 0; 1071e66f787SSean Bruno uint32_t device = 0; 1081e66f787SSean Bruno 1091e66f787SSean Bruno DBG_FUNC("IN udata = %p cdev = %p\n", udata, cdev); 1101e66f787SSean Bruno 1111e66f787SSean Bruno pci_info->bus = pci_get_bus(dev); 1121e66f787SSean Bruno pci_info->dev_fn = pci_get_function(dev); 1131e66f787SSean Bruno pci_info->domain = pci_get_domain(dev); 1141e66f787SSean Bruno sub_vendor = pci_read_config(dev, PCIR_SUBVEND_0, 2); 1151e66f787SSean Bruno sub_device = pci_read_config(dev, PCIR_SUBDEV_0, 2); 1161e66f787SSean Bruno pci_info->board_id = ((sub_device << 16) & 0xffff0000) | sub_vendor; 1171e66f787SSean Bruno vendor = pci_get_vendor(dev); 1181e66f787SSean Bruno device = pci_get_device(dev); 1191e66f787SSean Bruno pci_info->chip_id = ((device << 16) & 0xffff0000) | vendor; 1201e66f787SSean Bruno DBG_FUNC("OUT\n"); 1211e66f787SSean Bruno } 1221e66f787SSean Bruno 1231e66f787SSean Bruno 1241e66f787SSean Bruno /* 1251e66f787SSean Bruno * ioctl entry point for user 1261e66f787SSean Bruno */ 1271e66f787SSean Bruno static int smartpqi_ioctl(struct cdev *cdev, u_long cmd, caddr_t udata, 1281e66f787SSean Bruno int flags, struct thread *td) 1291e66f787SSean Bruno { 1301e66f787SSean Bruno int error = PQI_STATUS_SUCCESS; 1311e66f787SSean Bruno struct pqisrc_softstate *softs = cdev->si_drv1; 1321e66f787SSean Bruno 1331e66f787SSean Bruno DBG_FUNC("IN cmd = 0x%lx udata = %p cdev = %p\n", cmd, udata, cdev); 1341e66f787SSean Bruno 1351e66f787SSean Bruno if (!udata) { 1361e66f787SSean Bruno DBG_ERR("udata is null !!\n"); 1371e66f787SSean Bruno } 1381e66f787SSean Bruno 1391e66f787SSean Bruno if (pqisrc_ctrl_offline(softs)){ 1401e66f787SSean Bruno DBG_ERR("Controller s offline !!\n"); 1411e66f787SSean Bruno return ENOTTY; 1421e66f787SSean Bruno } 1431e66f787SSean Bruno 1441e66f787SSean Bruno switch (cmd) { 1451e66f787SSean Bruno case CCISS_GETDRIVVER: 1461e66f787SSean Bruno smartpqi_get_driver_info_ioctl(udata, cdev); 1471e66f787SSean Bruno break; 1481e66f787SSean Bruno case CCISS_GETPCIINFO: 1491e66f787SSean Bruno smartpqi_get_pci_info_ioctl(udata, cdev); 1501e66f787SSean Bruno break; 1511e66f787SSean Bruno case SMARTPQI_PASS_THRU: 1521e66f787SSean Bruno case CCISS_PASSTHRU: 1531e66f787SSean Bruno error = pqisrc_passthru_ioctl(softs, udata, 0); 1541e66f787SSean Bruno error = PQI_STATUS_SUCCESS; 1551e66f787SSean Bruno break; 1561e66f787SSean Bruno case CCISS_REGNEWD: 1571e66f787SSean Bruno error = pqisrc_scan_devices(softs); 1581e66f787SSean Bruno break; 1591e66f787SSean Bruno default: 1601e66f787SSean Bruno DBG_WARN( "!IOCTL cmd 0x%lx not supported", cmd); 1611e66f787SSean Bruno error = ENOTTY; 1621e66f787SSean Bruno break; 1631e66f787SSean Bruno } 1641e66f787SSean Bruno 1651e66f787SSean Bruno DBG_FUNC("OUT error = %d\n", error); 1661e66f787SSean Bruno return error; 1671e66f787SSean Bruno } 1681e66f787SSean Bruno 1691e66f787SSean Bruno static d_open_t smartpqi_open; 1701e66f787SSean Bruno static d_ioctl_t smartpqi_ioctl; 1711e66f787SSean Bruno static d_close_t smartpqi_close; 1721e66f787SSean Bruno 1731e66f787SSean Bruno static struct cdevsw smartpqi_cdevsw = 1741e66f787SSean Bruno { 1751e66f787SSean Bruno .d_version = D_VERSION, 1761e66f787SSean Bruno .d_open = smartpqi_open, 1771e66f787SSean Bruno .d_close = smartpqi_close, 1781e66f787SSean Bruno .d_ioctl = smartpqi_ioctl, 1791e66f787SSean Bruno .d_name = "smartpqi", 1801e66f787SSean Bruno }; 1811e66f787SSean Bruno 1821e66f787SSean Bruno /* 1831e66f787SSean Bruno * Function to create device node for ioctl 1841e66f787SSean Bruno */ 1851e66f787SSean Bruno int create_char_dev(struct pqisrc_softstate *softs, int card_index) 1861e66f787SSean Bruno { 1871e66f787SSean Bruno int error = PQI_STATUS_SUCCESS; 1881e66f787SSean Bruno 1891e66f787SSean Bruno DBG_FUNC("IN idx = %d\n", card_index); 1901e66f787SSean Bruno 1911e66f787SSean Bruno softs->os_specific.cdev = make_dev(&smartpqi_cdevsw, card_index, 1921e66f787SSean Bruno UID_ROOT, GID_OPERATOR, 0640, 1931e66f787SSean Bruno "smartpqi%u", card_index); 1941e66f787SSean Bruno if(softs->os_specific.cdev) { 1951e66f787SSean Bruno softs->os_specific.cdev->si_drv1 = softs; 1961e66f787SSean Bruno } else { 1971e66f787SSean Bruno error = PQI_STATUS_FAILURE; 1981e66f787SSean Bruno } 1991e66f787SSean Bruno 2001e66f787SSean Bruno DBG_FUNC("OUT error = %d\n", error); 2011e66f787SSean Bruno return error; 2021e66f787SSean Bruno } 2031e66f787SSean Bruno 2041e66f787SSean Bruno /* 2051e66f787SSean Bruno * Function to destroy device node for ioctl 2061e66f787SSean Bruno */ 2071e66f787SSean Bruno void destroy_char_dev(struct pqisrc_softstate *softs) 2081e66f787SSean Bruno { 2091e66f787SSean Bruno DBG_FUNC("IN\n"); 2101e66f787SSean Bruno if (softs->os_specific.cdev) { 2111e66f787SSean Bruno destroy_dev(softs->os_specific.cdev); 2121e66f787SSean Bruno softs->os_specific.cdev = NULL; 2131e66f787SSean Bruno } 2141e66f787SSean Bruno DBG_FUNC("OUT\n"); 2151e66f787SSean Bruno } 2161e66f787SSean Bruno 2171e66f787SSean Bruno /* 2181e66f787SSean Bruno * Function used to send passthru commands to adapter 2191e66f787SSean Bruno * to support management tools. For eg. ssacli, sscon. 2201e66f787SSean Bruno */ 2211e66f787SSean Bruno int 2221e66f787SSean Bruno pqisrc_passthru_ioctl(struct pqisrc_softstate *softs, void *arg, int mode) 2231e66f787SSean Bruno { 2241e66f787SSean Bruno int ret = PQI_STATUS_SUCCESS; 2251e66f787SSean Bruno char *drv_buf = NULL; 2261e66f787SSean Bruno uint32_t tag = 0; 2271e66f787SSean Bruno IOCTL_Command_struct *iocommand = (IOCTL_Command_struct *)arg; 2281e66f787SSean Bruno dma_mem_t ioctl_dma_buf; 2291e66f787SSean Bruno pqisrc_raid_req_t request; 2301e66f787SSean Bruno raid_path_error_info_elem_t error_info; 2311e66f787SSean Bruno ib_queue_t *ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE]; 2321e66f787SSean Bruno ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE]; 2331e66f787SSean Bruno rcb_t *rcb = NULL; 2341e66f787SSean Bruno 2351e66f787SSean Bruno memset(&request, 0, sizeof(request)); 2361e66f787SSean Bruno memset(&error_info, 0, sizeof(error_info)); 2371e66f787SSean Bruno 2381e66f787SSean Bruno DBG_FUNC("IN"); 2391e66f787SSean Bruno 2401e66f787SSean Bruno if (pqisrc_ctrl_offline(softs)) 2411e66f787SSean Bruno return PQI_STATUS_FAILURE; 2421e66f787SSean Bruno 2431e66f787SSean Bruno if (!arg) 2441e66f787SSean Bruno return (PQI_STATUS_FAILURE); 2451e66f787SSean Bruno 2461e66f787SSean Bruno if (iocommand->buf_size < 1 && 2471e66f787SSean Bruno iocommand->Request.Type.Direction != PQIIOCTL_NONE) 2481e66f787SSean Bruno return PQI_STATUS_FAILURE; 2491e66f787SSean Bruno if (iocommand->Request.CDBLen > sizeof(request.cdb)) 2501e66f787SSean Bruno return PQI_STATUS_FAILURE; 2511e66f787SSean Bruno 2521e66f787SSean Bruno switch (iocommand->Request.Type.Direction) { 2531e66f787SSean Bruno case PQIIOCTL_NONE: 2541e66f787SSean Bruno case PQIIOCTL_WRITE: 2551e66f787SSean Bruno case PQIIOCTL_READ: 2561e66f787SSean Bruno case PQIIOCTL_BIDIRECTIONAL: 2571e66f787SSean Bruno break; 2581e66f787SSean Bruno default: 2591e66f787SSean Bruno return PQI_STATUS_FAILURE; 2601e66f787SSean Bruno } 2611e66f787SSean Bruno 2621e66f787SSean Bruno if (iocommand->buf_size > 0) { 2631e66f787SSean Bruno memset(&ioctl_dma_buf, 0, sizeof(struct dma_mem)); 2641e66f787SSean Bruno ioctl_dma_buf.tag = "Ioctl_PassthruCmd_Buffer"; 2651e66f787SSean Bruno ioctl_dma_buf.size = iocommand->buf_size; 2661e66f787SSean Bruno ioctl_dma_buf.align = PQISRC_DEFAULT_DMA_ALIGN; 2671e66f787SSean Bruno /* allocate memory */ 2681e66f787SSean Bruno ret = os_dma_mem_alloc(softs, &ioctl_dma_buf); 2691e66f787SSean Bruno if (ret) { 2701e66f787SSean Bruno DBG_ERR("Failed to Allocate dma mem for Ioctl PassthruCmd Buffer : %d\n", ret); 2711e66f787SSean Bruno ret = PQI_STATUS_FAILURE; 2721e66f787SSean Bruno goto out; 2731e66f787SSean Bruno } 2741e66f787SSean Bruno 2751e66f787SSean Bruno DBG_INFO("ioctl_dma_buf.dma_addr = %p\n",(void*)ioctl_dma_buf.dma_addr); 2761e66f787SSean Bruno DBG_INFO("ioctl_dma_buf.virt_addr = %p\n",(void*)ioctl_dma_buf.virt_addr); 2771e66f787SSean Bruno 2781e66f787SSean Bruno drv_buf = (char *)ioctl_dma_buf.virt_addr; 2791e66f787SSean Bruno if (iocommand->Request.Type.Direction & PQIIOCTL_WRITE) { 2801e66f787SSean Bruno if ((ret = os_copy_from_user(softs, (void *)drv_buf, (void *)iocommand->buf, 2811e66f787SSean Bruno iocommand->buf_size, mode)) != 0) { 2821e66f787SSean Bruno ret = PQI_STATUS_FAILURE; 2831e66f787SSean Bruno goto free_mem; 2841e66f787SSean Bruno } 2851e66f787SSean Bruno } 2861e66f787SSean Bruno } 2871e66f787SSean Bruno 2881e66f787SSean Bruno request.header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST; 2891e66f787SSean Bruno request.header.iu_length = offsetof(pqisrc_raid_req_t, sg_descriptors[1]) - 2901e66f787SSean Bruno PQI_REQUEST_HEADER_LENGTH; 2911e66f787SSean Bruno memcpy(request.lun_number, iocommand->LUN_info.LunAddrBytes, 2921e66f787SSean Bruno sizeof(request.lun_number)); 2931e66f787SSean Bruno memcpy(request.cdb, iocommand->Request.CDB, iocommand->Request.CDBLen); 2941e66f787SSean Bruno request.additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0; 2951e66f787SSean Bruno 2961e66f787SSean Bruno switch (iocommand->Request.Type.Direction) { 2971e66f787SSean Bruno case PQIIOCTL_NONE: 2981e66f787SSean Bruno request.data_direction = SOP_DATA_DIR_NONE; 2991e66f787SSean Bruno break; 3001e66f787SSean Bruno case PQIIOCTL_WRITE: 3011e66f787SSean Bruno request.data_direction = SOP_DATA_DIR_FROM_DEVICE; 3021e66f787SSean Bruno break; 3031e66f787SSean Bruno case PQIIOCTL_READ: 3041e66f787SSean Bruno request.data_direction = SOP_DATA_DIR_TO_DEVICE; 3051e66f787SSean Bruno break; 3061e66f787SSean Bruno case PQIIOCTL_BIDIRECTIONAL: 3071e66f787SSean Bruno request.data_direction = SOP_DATA_DIR_BIDIRECTIONAL; 3081e66f787SSean Bruno break; 3091e66f787SSean Bruno } 3101e66f787SSean Bruno 3111e66f787SSean Bruno request.task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE; 3121e66f787SSean Bruno if (iocommand->buf_size > 0) { 3131e66f787SSean Bruno request.buffer_length = iocommand->buf_size; 3141e66f787SSean Bruno request.sg_descriptors[0].addr = ioctl_dma_buf.dma_addr; 3151e66f787SSean Bruno request.sg_descriptors[0].len = iocommand->buf_size; 3161e66f787SSean Bruno request.sg_descriptors[0].flags = SG_FLAG_LAST; 3171e66f787SSean Bruno } 3181e66f787SSean Bruno tag = pqisrc_get_tag(&softs->taglist); 3191e66f787SSean Bruno request.request_id = tag; 3201e66f787SSean Bruno request.response_queue_id = ob_q->q_id; 3211e66f787SSean Bruno request.error_index = request.request_id; 3221e66f787SSean Bruno rcb = &softs->rcb[tag]; 3231e66f787SSean Bruno 3241e66f787SSean Bruno rcb->success_cmp_callback = pqisrc_process_internal_raid_response_success; 3251e66f787SSean Bruno rcb->error_cmp_callback = pqisrc_process_internal_raid_response_error; 3261e66f787SSean Bruno rcb->tag = tag; 3271e66f787SSean Bruno rcb->req_pending = true; 3281e66f787SSean Bruno /* Submit Command */ 3291e66f787SSean Bruno ret = pqisrc_submit_cmnd(softs, ib_q, &request); 3301e66f787SSean Bruno if (ret != PQI_STATUS_SUCCESS) { 3311e66f787SSean Bruno DBG_ERR("Unable to submit command\n"); 3321e66f787SSean Bruno goto err_out; 3331e66f787SSean Bruno } 3341e66f787SSean Bruno 3351e66f787SSean Bruno ret = pqisrc_wait_on_condition(softs, rcb); 3361e66f787SSean Bruno if (ret != PQI_STATUS_SUCCESS) { 3371e66f787SSean Bruno DBG_ERR("Passthru IOCTL cmd timed out !!\n"); 3381e66f787SSean Bruno goto err_out; 3391e66f787SSean Bruno } 3401e66f787SSean Bruno 3411e66f787SSean Bruno memset(&iocommand->error_info, 0, sizeof(iocommand->error_info)); 3421e66f787SSean Bruno 3431e66f787SSean Bruno 3441e66f787SSean Bruno if (rcb->status) { 3451e66f787SSean Bruno size_t sense_data_length; 3461e66f787SSean Bruno 3471e66f787SSean Bruno memcpy(&error_info, rcb->error_info, sizeof(error_info)); 3481e66f787SSean Bruno iocommand->error_info.ScsiStatus = error_info.status; 3491e66f787SSean Bruno sense_data_length = error_info.sense_data_len; 3501e66f787SSean Bruno 3511e66f787SSean Bruno if (!sense_data_length) 3521e66f787SSean Bruno sense_data_length = error_info.resp_data_len; 3531e66f787SSean Bruno 3541e66f787SSean Bruno if (sense_data_length && 3551e66f787SSean Bruno (sense_data_length > sizeof(error_info.data))) 3561e66f787SSean Bruno sense_data_length = sizeof(error_info.data); 3571e66f787SSean Bruno 3581e66f787SSean Bruno if (sense_data_length) { 3591e66f787SSean Bruno if (sense_data_length > 3601e66f787SSean Bruno sizeof(iocommand->error_info.SenseInfo)) 3611e66f787SSean Bruno sense_data_length = 3621e66f787SSean Bruno sizeof(iocommand->error_info.SenseInfo); 3631e66f787SSean Bruno memcpy (iocommand->error_info.SenseInfo, 3641e66f787SSean Bruno error_info.data, sense_data_length); 3651e66f787SSean Bruno iocommand->error_info.SenseLen = sense_data_length; 3661e66f787SSean Bruno } 3671e66f787SSean Bruno 3681e66f787SSean Bruno if (error_info.data_out_result == 3691e66f787SSean Bruno PQI_RAID_DATA_IN_OUT_UNDERFLOW){ 3701e66f787SSean Bruno rcb->status = REQUEST_SUCCESS; 3711e66f787SSean Bruno } 3721e66f787SSean Bruno } 3731e66f787SSean Bruno 3741e66f787SSean Bruno if (rcb->status == REQUEST_SUCCESS && iocommand->buf_size > 0 && 3751e66f787SSean Bruno (iocommand->Request.Type.Direction & PQIIOCTL_READ)) { 3761e66f787SSean Bruno 3771e66f787SSean Bruno if ((ret = os_copy_to_user(softs, (void*)iocommand->buf, 3781e66f787SSean Bruno (void*)drv_buf, iocommand->buf_size, mode)) != 0) { 3791e66f787SSean Bruno DBG_ERR("Failed to copy the response\n"); 3801e66f787SSean Bruno goto err_out; 3811e66f787SSean Bruno } 3821e66f787SSean Bruno } 3831e66f787SSean Bruno 3841e66f787SSean Bruno os_reset_rcb(rcb); 3851e66f787SSean Bruno pqisrc_put_tag(&softs->taglist, request.request_id); 3861e66f787SSean Bruno if (iocommand->buf_size > 0) 3871e66f787SSean Bruno os_dma_mem_free(softs,&ioctl_dma_buf); 3881e66f787SSean Bruno 3891e66f787SSean Bruno DBG_FUNC("OUT\n"); 3901e66f787SSean Bruno return ret; 3911e66f787SSean Bruno err_out: 3921e66f787SSean Bruno os_reset_rcb(rcb); 3931e66f787SSean Bruno pqisrc_put_tag(&softs->taglist, request.request_id); 3941e66f787SSean Bruno 3951e66f787SSean Bruno free_mem: 3961e66f787SSean Bruno if (iocommand->buf_size > 0) 3971e66f787SSean Bruno os_dma_mem_free(softs, &ioctl_dma_buf); 3981e66f787SSean Bruno 3991e66f787SSean Bruno out: 4001e66f787SSean Bruno DBG_FUNC("Failed OUT\n"); 4011e66f787SSean Bruno return PQI_STATUS_FAILURE; 4021e66f787SSean Bruno } 403