xref: /freebsd/sys/dev/smartpqi/smartpqi_ioctl.c (revision 7ea28254)
11e66f787SSean Bruno /*-
27ea28254SJohn Hall  * Copyright 2016-2023 Microchip Technology, Inc. and/or its subsidiaries.
31e66f787SSean Bruno  *
41e66f787SSean Bruno  * Redistribution and use in source and binary forms, with or without
51e66f787SSean Bruno  * modification, are permitted provided that the following conditions
61e66f787SSean Bruno  * are met:
71e66f787SSean Bruno  * 1. Redistributions of source code must retain the above copyright
81e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer.
91e66f787SSean Bruno  * 2. Redistributions in binary form must reproduce the above copyright
101e66f787SSean Bruno  *    notice, this list of conditions and the following disclaimer in the
111e66f787SSean Bruno  *    documentation and/or other materials provided with the distribution.
121e66f787SSean Bruno  *
131e66f787SSean Bruno  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
141e66f787SSean Bruno  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
151e66f787SSean Bruno  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
161e66f787SSean Bruno  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
171e66f787SSean Bruno  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
181e66f787SSean Bruno  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
191e66f787SSean Bruno  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
201e66f787SSean Bruno  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
211e66f787SSean Bruno  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
221e66f787SSean Bruno  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
231e66f787SSean Bruno  * SUCH DAMAGE.
241e66f787SSean Bruno  */
251e66f787SSean Bruno 
261e66f787SSean Bruno 
271e66f787SSean Bruno /*
281e66f787SSean Bruno  * Management interface for smartpqi driver
291e66f787SSean Bruno  */
301e66f787SSean Bruno 
311e66f787SSean Bruno #include "smartpqi_includes.h"
321e66f787SSean Bruno 
331e66f787SSean Bruno /*
341e66f787SSean Bruno  * Wrapper function to copy to user from kernel
351e66f787SSean Bruno  */
369fac68fcSPAPANI SRIKANTH int
os_copy_to_user(struct pqisrc_softstate * softs,void * dest_buf,void * src_buf,int size,int mode)379fac68fcSPAPANI SRIKANTH os_copy_to_user(struct pqisrc_softstate *softs, void *dest_buf,
381e66f787SSean Bruno 		void *src_buf, int size, int mode)
391e66f787SSean Bruno {
401e66f787SSean Bruno 	return(copyout(src_buf, dest_buf, size));
411e66f787SSean Bruno }
421e66f787SSean Bruno 
431e66f787SSean Bruno /*
441e66f787SSean Bruno  * Wrapper function to copy from user to kernel
451e66f787SSean Bruno  */
469fac68fcSPAPANI SRIKANTH int
os_copy_from_user(struct pqisrc_softstate * softs,void * dest_buf,void * src_buf,int size,int mode)479fac68fcSPAPANI SRIKANTH 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  */
569fac68fcSPAPANI SRIKANTH static int
smartpqi_open(struct cdev * cdev,int flags,int devtype,struct thread * td)579fac68fcSPAPANI SRIKANTH smartpqi_open(struct cdev *cdev, int flags, int devtype,
581e66f787SSean Bruno 		struct thread *td)
591e66f787SSean Bruno {
609fac68fcSPAPANI SRIKANTH 	return BSD_SUCCESS;
611e66f787SSean Bruno }
621e66f787SSean Bruno 
631e66f787SSean Bruno /*
641e66f787SSean Bruno  * Device close function for ioctl entry
651e66f787SSean Bruno  */
669fac68fcSPAPANI SRIKANTH static int
smartpqi_close(struct cdev * cdev,int flags,int devtype,struct thread * td)679fac68fcSPAPANI SRIKANTH smartpqi_close(struct cdev *cdev, int flags, int devtype,
681e66f787SSean Bruno 		struct thread *td)
691e66f787SSean Bruno {
709fac68fcSPAPANI SRIKANTH 	return BSD_SUCCESS;
711e66f787SSean Bruno }
721e66f787SSean Bruno 
731e66f787SSean Bruno /*
741e66f787SSean Bruno  * ioctl for getting driver info
751e66f787SSean Bruno  */
769fac68fcSPAPANI SRIKANTH static void
smartpqi_get_driver_info_ioctl(caddr_t udata,struct cdev * cdev)779fac68fcSPAPANI SRIKANTH smartpqi_get_driver_info_ioctl(caddr_t udata, struct cdev *cdev)
781e66f787SSean Bruno {
791e66f787SSean Bruno 	struct pqisrc_softstate *softs = cdev->si_drv1;
801e66f787SSean Bruno 	pdriver_info driver_info = (pdriver_info)udata;
811e66f787SSean Bruno 
821e66f787SSean Bruno 	DBG_FUNC("IN udata = %p cdev = %p\n", udata, cdev);
831e66f787SSean Bruno 
847ea28254SJohn Hall 	driver_info->major_version = PQISRC_DRIVER_MAJOR;
857ea28254SJohn Hall 	driver_info->minor_version = PQISRC_DRIVER_MINOR;
867ea28254SJohn Hall 	driver_info->release_version = PQISRC_DRIVER_RELEASE;
877ea28254SJohn Hall 	driver_info->build_revision = PQISRC_DRIVER_REVISION;
881e66f787SSean Bruno 	driver_info->max_targets = PQI_MAX_DEVICES - 1;
891e66f787SSean Bruno 	driver_info->max_io = softs->max_io_for_scsi_ml;
901e66f787SSean Bruno 	driver_info->max_transfer_length = softs->pqi_cap.max_transfer_size;
911e66f787SSean Bruno 
921e66f787SSean Bruno 	DBG_FUNC("OUT\n");
931e66f787SSean Bruno }
941e66f787SSean Bruno 
951e66f787SSean Bruno /*
961e66f787SSean Bruno  * ioctl for getting controller info
971e66f787SSean Bruno  */
989fac68fcSPAPANI SRIKANTH static void
smartpqi_get_pci_info_ioctl(caddr_t udata,struct cdev * cdev)999fac68fcSPAPANI SRIKANTH 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;
1207ea28254SJohn Hall 
1211e66f787SSean Bruno 	DBG_FUNC("OUT\n");
1221e66f787SSean Bruno }
1231e66f787SSean Bruno 
1249fac68fcSPAPANI SRIKANTH static inline int
pqi_status_to_bsd_ioctl_status(int pqi_status)1259fac68fcSPAPANI SRIKANTH pqi_status_to_bsd_ioctl_status(int pqi_status)
1269fac68fcSPAPANI SRIKANTH {
1279fac68fcSPAPANI SRIKANTH 	if (PQI_STATUS_SUCCESS == pqi_status)
1289fac68fcSPAPANI SRIKANTH 		return BSD_SUCCESS;
1299fac68fcSPAPANI SRIKANTH 	else
1309fac68fcSPAPANI SRIKANTH 		return EIO;
1319fac68fcSPAPANI SRIKANTH }
1329fac68fcSPAPANI SRIKANTH 
1331e66f787SSean Bruno /*
1341e66f787SSean Bruno  * ioctl entry point for user
1351e66f787SSean Bruno  */
1369fac68fcSPAPANI SRIKANTH static int
smartpqi_ioctl(struct cdev * cdev,u_long cmd,caddr_t udata,int flags,struct thread * td)1379fac68fcSPAPANI SRIKANTH smartpqi_ioctl(struct cdev *cdev, u_long cmd, caddr_t udata,
1381e66f787SSean Bruno 		int flags, struct thread *td)
1391e66f787SSean Bruno {
1409fac68fcSPAPANI SRIKANTH 	int bsd_status, pqi_status;
1411e66f787SSean Bruno 	struct pqisrc_softstate *softs = cdev->si_drv1;
1421e66f787SSean Bruno 
1431e66f787SSean Bruno 	DBG_FUNC("IN cmd = 0x%lx udata = %p cdev = %p\n", cmd, udata, cdev);
1441e66f787SSean Bruno 
1451e66f787SSean Bruno 	if (!udata) {
1461e66f787SSean Bruno 		DBG_ERR("udata is null !!\n");
1479fac68fcSPAPANI SRIKANTH 		return EINVAL;
1481e66f787SSean Bruno 	}
1491e66f787SSean Bruno 
1501e66f787SSean Bruno 	if (pqisrc_ctrl_offline(softs)){
1511e66f787SSean Bruno 		return ENOTTY;
1521e66f787SSean Bruno 	}
1531e66f787SSean Bruno 
1541e66f787SSean Bruno 	switch (cmd) {
1551e66f787SSean Bruno 		case CCISS_GETDRIVVER:
1561e66f787SSean Bruno 			smartpqi_get_driver_info_ioctl(udata, cdev);
1579fac68fcSPAPANI SRIKANTH 			bsd_status = BSD_SUCCESS;
1581e66f787SSean Bruno 			break;
1591e66f787SSean Bruno 		case CCISS_GETPCIINFO:
1601e66f787SSean Bruno 			smartpqi_get_pci_info_ioctl(udata, cdev);
1619fac68fcSPAPANI SRIKANTH 			bsd_status = BSD_SUCCESS;
1621e66f787SSean Bruno 			break;
1631e66f787SSean Bruno 		case SMARTPQI_PASS_THRU:
1641e66f787SSean Bruno 		case CCISS_PASSTHRU:
1659fac68fcSPAPANI SRIKANTH 			pqi_status = pqisrc_passthru_ioctl(softs, udata, 0);
1669fac68fcSPAPANI SRIKANTH 			bsd_status = pqi_status_to_bsd_ioctl_status(pqi_status);
1671e66f787SSean Bruno 			break;
1681e66f787SSean Bruno 		case CCISS_REGNEWD:
1699fac68fcSPAPANI SRIKANTH 			pqi_status = pqisrc_scan_devices(softs);
1709fac68fcSPAPANI SRIKANTH 			bsd_status = pqi_status_to_bsd_ioctl_status(pqi_status);
1711e66f787SSean Bruno 			break;
1721e66f787SSean Bruno 		default:
1739fac68fcSPAPANI SRIKANTH 			DBG_WARN( "!IOCTL cmd 0x%lx not supported\n", cmd);
1749fac68fcSPAPANI SRIKANTH 			bsd_status = ENOTTY;
1751e66f787SSean Bruno 			break;
1761e66f787SSean Bruno 	}
1771e66f787SSean Bruno 
1789fac68fcSPAPANI SRIKANTH 	DBG_FUNC("OUT error = %d\n", bsd_status);
1797ea28254SJohn Hall 
1809fac68fcSPAPANI SRIKANTH 	return bsd_status;
1811e66f787SSean Bruno }
1821e66f787SSean Bruno 
1831e66f787SSean Bruno static struct cdevsw smartpqi_cdevsw =
1841e66f787SSean Bruno {
1851e66f787SSean Bruno 	.d_version = D_VERSION,
1861e66f787SSean Bruno 	.d_open    = smartpqi_open,
1871e66f787SSean Bruno 	.d_close   = smartpqi_close,
1881e66f787SSean Bruno 	.d_ioctl   = smartpqi_ioctl,
1891e66f787SSean Bruno 	.d_name    = "smartpqi",
1901e66f787SSean Bruno };
1911e66f787SSean Bruno 
1921e66f787SSean Bruno /*
1931e66f787SSean Bruno  * Function to create device node for ioctl
1941e66f787SSean Bruno  */
1959fac68fcSPAPANI SRIKANTH int
create_char_dev(struct pqisrc_softstate * softs,int card_index)1969fac68fcSPAPANI SRIKANTH create_char_dev(struct pqisrc_softstate *softs, int card_index)
1971e66f787SSean Bruno {
1989fac68fcSPAPANI SRIKANTH 	int error = BSD_SUCCESS;
1991e66f787SSean Bruno 
2001e66f787SSean Bruno 	DBG_FUNC("IN idx = %d\n", card_index);
2011e66f787SSean Bruno 
2021e66f787SSean Bruno 	softs->os_specific.cdev = make_dev(&smartpqi_cdevsw, card_index,
2031e66f787SSean Bruno 				UID_ROOT, GID_OPERATOR, 0640,
2041e66f787SSean Bruno 				"smartpqi%u", card_index);
2051e66f787SSean Bruno 	if(softs->os_specific.cdev) {
2061e66f787SSean Bruno 		softs->os_specific.cdev->si_drv1 = softs;
2071e66f787SSean Bruno 	} else {
2089fac68fcSPAPANI SRIKANTH 		error = ENXIO;
2091e66f787SSean Bruno 	}
2101e66f787SSean Bruno 
2111e66f787SSean Bruno 	DBG_FUNC("OUT error = %d\n", error);
2129fac68fcSPAPANI SRIKANTH 
2131e66f787SSean Bruno 	return error;
2141e66f787SSean Bruno }
2151e66f787SSean Bruno 
2161e66f787SSean Bruno /*
2171e66f787SSean Bruno  * Function to destroy device node for ioctl
2181e66f787SSean Bruno  */
2199fac68fcSPAPANI SRIKANTH void
destroy_char_dev(struct pqisrc_softstate * softs)2209fac68fcSPAPANI SRIKANTH destroy_char_dev(struct pqisrc_softstate *softs)
2211e66f787SSean Bruno {
2221e66f787SSean Bruno 	DBG_FUNC("IN\n");
2231e66f787SSean Bruno 	if (softs->os_specific.cdev) {
2241e66f787SSean Bruno 		destroy_dev(softs->os_specific.cdev);
2251e66f787SSean Bruno 		softs->os_specific.cdev = NULL;
2261e66f787SSean Bruno 	}
2271e66f787SSean Bruno 	DBG_FUNC("OUT\n");
2281e66f787SSean Bruno }
2291e66f787SSean Bruno 
2301e66f787SSean Bruno /*
2311e66f787SSean Bruno  * Function used to send passthru commands to adapter
2321e66f787SSean Bruno  * to support management tools. For eg. ssacli, sscon.
2331e66f787SSean Bruno  */
2341e66f787SSean Bruno int
pqisrc_passthru_ioctl(struct pqisrc_softstate * softs,void * arg,int mode)2351e66f787SSean Bruno pqisrc_passthru_ioctl(struct pqisrc_softstate *softs, void *arg, int mode)
2361e66f787SSean Bruno {
2377ea28254SJohn Hall 	int ret;
2381e66f787SSean Bruno 	char *drv_buf = NULL;
2391e66f787SSean Bruno 	uint32_t tag = 0;
2401e66f787SSean Bruno 	IOCTL_Command_struct *iocommand = (IOCTL_Command_struct *)arg;
2411e66f787SSean Bruno 	dma_mem_t ioctl_dma_buf;
2421e66f787SSean Bruno 	pqisrc_raid_req_t request;
2431e66f787SSean Bruno 	raid_path_error_info_elem_t error_info;
2441e66f787SSean Bruno 	ib_queue_t *ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE];
2451e66f787SSean Bruno 	ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE];
2461e66f787SSean Bruno 	rcb_t *rcb = NULL;
2471e66f787SSean Bruno 
2481e66f787SSean Bruno 	memset(&request, 0, sizeof(request));
2491e66f787SSean Bruno 	memset(&error_info, 0, sizeof(error_info));
2501e66f787SSean Bruno 
2517ea28254SJohn Hall 	DBG_FUNC("IN\n");
2521e66f787SSean Bruno 
2531e66f787SSean Bruno 	if (pqisrc_ctrl_offline(softs))
2541e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
2551e66f787SSean Bruno 
2561e66f787SSean Bruno 	if (!arg)
2577ea28254SJohn Hall 		return PQI_STATUS_FAILURE;
2581e66f787SSean Bruno 
2591e66f787SSean Bruno 	if (iocommand->buf_size < 1 &&
2601e66f787SSean Bruno 		iocommand->Request.Type.Direction != PQIIOCTL_NONE)
2611e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
2627ea28254SJohn Hall 	if (iocommand->Request.CDBLen > sizeof(request.cmd.cdb))
2631e66f787SSean Bruno 		return PQI_STATUS_FAILURE;
2641e66f787SSean Bruno 
2651e66f787SSean Bruno 	switch (iocommand->Request.Type.Direction) {
2661e66f787SSean Bruno 		case PQIIOCTL_NONE:
2671e66f787SSean Bruno 		case PQIIOCTL_WRITE:
2681e66f787SSean Bruno 		case PQIIOCTL_READ:
2691e66f787SSean Bruno 		case PQIIOCTL_BIDIRECTIONAL:
2701e66f787SSean Bruno 			break;
2711e66f787SSean Bruno 		default:
2721e66f787SSean Bruno 			return PQI_STATUS_FAILURE;
2731e66f787SSean Bruno 	}
2741e66f787SSean Bruno 
2751e66f787SSean Bruno 	if (iocommand->buf_size > 0) {
2761e66f787SSean Bruno 		memset(&ioctl_dma_buf, 0, sizeof(struct dma_mem));
2777ea28254SJohn Hall 		os_strlcpy(ioctl_dma_buf.tag, "Ioctl_PassthruCmd_Buffer", sizeof(ioctl_dma_buf.tag));
2781e66f787SSean Bruno 		ioctl_dma_buf.size = iocommand->buf_size;
2791e66f787SSean Bruno 		ioctl_dma_buf.align = PQISRC_DEFAULT_DMA_ALIGN;
2801e66f787SSean Bruno 		/* allocate memory */
2811e66f787SSean Bruno 		ret = os_dma_mem_alloc(softs, &ioctl_dma_buf);
2821e66f787SSean Bruno 		if (ret) {
2831e66f787SSean Bruno 			DBG_ERR("Failed to Allocate dma mem for Ioctl PassthruCmd Buffer : %d\n", ret);
2841e66f787SSean Bruno 			goto out;
2851e66f787SSean Bruno 		}
2861e66f787SSean Bruno 
2877ea28254SJohn Hall 		DBG_IO("ioctl_dma_buf.dma_addr  = %p\n",(void*)ioctl_dma_buf.dma_addr);
2887ea28254SJohn Hall 		DBG_IO("ioctl_dma_buf.virt_addr = %p\n",(void*)ioctl_dma_buf.virt_addr);
2891e66f787SSean Bruno 
2901e66f787SSean Bruno 		drv_buf = (char *)ioctl_dma_buf.virt_addr;
2911e66f787SSean Bruno 		if (iocommand->Request.Type.Direction & PQIIOCTL_WRITE) {
2927ea28254SJohn Hall 			ret = os_copy_from_user(softs, (void *)drv_buf, (void *)iocommand->buf, iocommand->buf_size, mode);
2937ea28254SJohn Hall 			if (ret != 0) {
2941e66f787SSean Bruno 				goto free_mem;
2951e66f787SSean Bruno 			}
2961e66f787SSean Bruno 		}
2971e66f787SSean Bruno 	}
2981e66f787SSean Bruno 
2991e66f787SSean Bruno 	request.header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST;
3001e66f787SSean Bruno 	request.header.iu_length = offsetof(pqisrc_raid_req_t, sg_descriptors[1]) -
3011e66f787SSean Bruno 									PQI_REQUEST_HEADER_LENGTH;
3021e66f787SSean Bruno 	memcpy(request.lun_number, iocommand->LUN_info.LunAddrBytes,
3031e66f787SSean Bruno 		sizeof(request.lun_number));
3047ea28254SJohn Hall 	memcpy(request.cmd.cdb, iocommand->Request.CDB, iocommand->Request.CDBLen);
3051e66f787SSean Bruno 	request.additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0;
3061e66f787SSean Bruno 
3071e66f787SSean Bruno 	switch (iocommand->Request.Type.Direction) {
3081e66f787SSean Bruno 	case PQIIOCTL_NONE:
3091e66f787SSean Bruno 		request.data_direction = SOP_DATA_DIR_NONE;
3101e66f787SSean Bruno 		break;
3111e66f787SSean Bruno 	case PQIIOCTL_WRITE:
3121e66f787SSean Bruno 		request.data_direction = SOP_DATA_DIR_FROM_DEVICE;
3131e66f787SSean Bruno 		break;
3141e66f787SSean Bruno 	case PQIIOCTL_READ:
3151e66f787SSean Bruno 		request.data_direction = SOP_DATA_DIR_TO_DEVICE;
3161e66f787SSean Bruno 		break;
3171e66f787SSean Bruno 	case PQIIOCTL_BIDIRECTIONAL:
3181e66f787SSean Bruno 		request.data_direction = SOP_DATA_DIR_BIDIRECTIONAL;
3191e66f787SSean Bruno 		break;
3201e66f787SSean Bruno 	}
3211e66f787SSean Bruno 
3221e66f787SSean Bruno 	request.task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE;
3231e66f787SSean Bruno 	if (iocommand->buf_size > 0) {
3241e66f787SSean Bruno 		request.buffer_length = iocommand->buf_size;
3251e66f787SSean Bruno 		request.sg_descriptors[0].addr = ioctl_dma_buf.dma_addr;
3261e66f787SSean Bruno 		request.sg_descriptors[0].len = iocommand->buf_size;
3271e66f787SSean Bruno 		request.sg_descriptors[0].flags =  SG_FLAG_LAST;
3281e66f787SSean Bruno 	}
3291e66f787SSean Bruno 	tag = pqisrc_get_tag(&softs->taglist);
330b17f4335SSean Bruno 	if (INVALID_ELEM == tag) {
331b17f4335SSean Bruno 		DBG_ERR("Tag not available\n");
332b17f4335SSean Bruno 		goto free_mem;
333b17f4335SSean Bruno 	}
3341e66f787SSean Bruno 	request.request_id = tag;
3351e66f787SSean Bruno 	request.response_queue_id = ob_q->q_id;
3361e66f787SSean Bruno 	request.error_index = request.request_id;
3379fac68fcSPAPANI SRIKANTH 	if (softs->timeout_in_passthrough) {
3389fac68fcSPAPANI SRIKANTH 		request.timeout_in_sec = iocommand->Request.Timeout;
3399fac68fcSPAPANI SRIKANTH 	}
3401e66f787SSean Bruno 
3419fac68fcSPAPANI SRIKANTH 	rcb = &softs->rcb[tag];
3421e66f787SSean Bruno 	rcb->success_cmp_callback = pqisrc_process_internal_raid_response_success;
3431e66f787SSean Bruno 	rcb->error_cmp_callback = pqisrc_process_internal_raid_response_error;
3441e66f787SSean Bruno 	rcb->tag = tag;
3451e66f787SSean Bruno 	rcb->req_pending = true;
3461e66f787SSean Bruno 	/* Submit Command */
3471e66f787SSean Bruno 	ret = pqisrc_submit_cmnd(softs, ib_q, &request);
3481e66f787SSean Bruno 	if (ret != PQI_STATUS_SUCCESS) {
3491e66f787SSean Bruno 		DBG_ERR("Unable to submit command\n");
3501e66f787SSean Bruno 		goto err_out;
3511e66f787SSean Bruno 	}
3521e66f787SSean Bruno 
3537ea28254SJohn Hall 	ret = pqisrc_wait_on_condition(softs, rcb, PQISRC_PASSTHROUGH_CMD_TIMEOUT);
3541e66f787SSean Bruno 	if (ret != PQI_STATUS_SUCCESS) {
3551e66f787SSean Bruno 		DBG_ERR("Passthru IOCTL cmd timed out !!\n");
3561e66f787SSean Bruno 		goto err_out;
3571e66f787SSean Bruno 	}
3581e66f787SSean Bruno 
3591e66f787SSean Bruno 	memset(&iocommand->error_info, 0, sizeof(iocommand->error_info));
3601e66f787SSean Bruno 
3619fac68fcSPAPANI SRIKANTH 
3621e66f787SSean Bruno 	if (rcb->status) {
3631e66f787SSean Bruno 		size_t sense_data_length;
3641e66f787SSean Bruno 
3651e66f787SSean Bruno 		memcpy(&error_info, rcb->error_info, sizeof(error_info));
3661e66f787SSean Bruno 		iocommand->error_info.ScsiStatus = error_info.status;
3671e66f787SSean Bruno 		sense_data_length = error_info.sense_data_len;
3681e66f787SSean Bruno 
3691e66f787SSean Bruno 		if (!sense_data_length)
3701e66f787SSean Bruno 			sense_data_length = error_info.resp_data_len;
3711e66f787SSean Bruno 
3721e66f787SSean Bruno 		if (sense_data_length &&
3731e66f787SSean Bruno 			(sense_data_length > sizeof(error_info.data)))
3741e66f787SSean Bruno 				sense_data_length = sizeof(error_info.data);
3751e66f787SSean Bruno 
3761e66f787SSean Bruno 		if (sense_data_length) {
3771e66f787SSean Bruno 			if (sense_data_length >
3781e66f787SSean Bruno 				sizeof(iocommand->error_info.SenseInfo))
3791e66f787SSean Bruno 				sense_data_length =
3801e66f787SSean Bruno 					sizeof(iocommand->error_info.SenseInfo);
3811e66f787SSean Bruno 			memcpy (iocommand->error_info.SenseInfo,
3821e66f787SSean Bruno 					error_info.data, sense_data_length);
3831e66f787SSean Bruno 			iocommand->error_info.SenseLen = sense_data_length;
3841e66f787SSean Bruno 		}
3851e66f787SSean Bruno 
3867ea28254SJohn Hall 		if (error_info.data_out_result == PQI_RAID_DATA_IN_OUT_UNDERFLOW) {
3877ea28254SJohn Hall 			rcb->status = PQI_STATUS_SUCCESS;
3881e66f787SSean Bruno 		}
3891e66f787SSean Bruno 	}
3901e66f787SSean Bruno 
3917ea28254SJohn Hall 	if (rcb->status == PQI_STATUS_SUCCESS && iocommand->buf_size > 0 &&
3921e66f787SSean Bruno 		(iocommand->Request.Type.Direction & PQIIOCTL_READ)) {
3939fac68fcSPAPANI SRIKANTH 
3947ea28254SJohn Hall 		ret = os_copy_to_user(softs, (void*)iocommand->buf, (void*)drv_buf, iocommand->buf_size, mode);
3957ea28254SJohn Hall 		if (ret != 0) {
3961e66f787SSean Bruno 			DBG_ERR("Failed to copy the response\n");
3971e66f787SSean Bruno 			goto err_out;
3981e66f787SSean Bruno 		}
3991e66f787SSean Bruno 	}
4001e66f787SSean Bruno 
4011e66f787SSean Bruno 	os_reset_rcb(rcb);
4021e66f787SSean Bruno 	pqisrc_put_tag(&softs->taglist, request.request_id);
4031e66f787SSean Bruno 	if (iocommand->buf_size > 0)
4041e66f787SSean Bruno 		os_dma_mem_free(softs,&ioctl_dma_buf);
4051e66f787SSean Bruno 
4061e66f787SSean Bruno 	DBG_FUNC("OUT\n");
4077ea28254SJohn Hall 	return PQI_STATUS_SUCCESS;
4087ea28254SJohn Hall 
4091e66f787SSean Bruno err_out:
4101e66f787SSean Bruno 	os_reset_rcb(rcb);
4111e66f787SSean Bruno 	pqisrc_put_tag(&softs->taglist, request.request_id);
4121e66f787SSean Bruno 
4131e66f787SSean Bruno free_mem:
4141e66f787SSean Bruno 	if (iocommand->buf_size > 0)
4151e66f787SSean Bruno 		os_dma_mem_free(softs, &ioctl_dma_buf);
4161e66f787SSean Bruno 
4171e66f787SSean Bruno out:
4181e66f787SSean Bruno 	DBG_FUNC("Failed OUT\n");
4191e66f787SSean Bruno 	return PQI_STATUS_FAILURE;
4201e66f787SSean Bruno }
421