Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/smartpqi/smartpqi_ioctl.c
/*- | /*- | ||||
* Copyright (c) 2018 Microsemi Corporation. | * Copyright (c) 2016-2019 Microsemi Corporation. | ||||
* Copyright (c) 2020 Microchip Technology Inc. and it's subsidiaries. | |||||
* | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
Show All 19 Lines | |||||
* Management interface for smartpqi driver | * Management interface for smartpqi driver | ||||
*/ | */ | ||||
#include "smartpqi_includes.h" | #include "smartpqi_includes.h" | ||||
/* | /* | ||||
* Wrapper function to copy to user from kernel | * Wrapper function to copy to user from kernel | ||||
*/ | */ | ||||
int os_copy_to_user(struct pqisrc_softstate *softs, void *dest_buf, | int | ||||
os_copy_to_user(struct pqisrc_softstate *softs, void *dest_buf, | |||||
void *src_buf, int size, int mode) | void *src_buf, int size, int mode) | ||||
{ | { | ||||
return(copyout(src_buf, dest_buf, size)); | return(copyout(src_buf, dest_buf, size)); | ||||
} | } | ||||
/* | /* | ||||
* Wrapper function to copy from user to kernel | * Wrapper function to copy from user to kernel | ||||
*/ | */ | ||||
int os_copy_from_user(struct pqisrc_softstate *softs, void *dest_buf, | int | ||||
os_copy_from_user(struct pqisrc_softstate *softs, void *dest_buf, | |||||
void *src_buf, int size, int mode) | void *src_buf, int size, int mode) | ||||
{ | { | ||||
return(copyin(src_buf, dest_buf, size)); | return(copyin(src_buf, dest_buf, size)); | ||||
} | } | ||||
/* | /* | ||||
* Device open function for ioctl entry | * Device open function for ioctl entry | ||||
*/ | */ | ||||
static int smartpqi_open(struct cdev *cdev, int flags, int devtype, | static int | ||||
smartpqi_open(struct cdev *cdev, int flags, int devtype, | |||||
struct thread *td) | struct thread *td) | ||||
{ | { | ||||
int error = PQI_STATUS_SUCCESS; | return BSD_SUCCESS; | ||||
return error; | |||||
} | } | ||||
/* | /* | ||||
* Device close function for ioctl entry | * Device close function for ioctl entry | ||||
*/ | */ | ||||
static int smartpqi_close(struct cdev *cdev, int flags, int devtype, | static int | ||||
smartpqi_close(struct cdev *cdev, int flags, int devtype, | |||||
struct thread *td) | struct thread *td) | ||||
{ | { | ||||
int error = PQI_STATUS_SUCCESS; | return BSD_SUCCESS; | ||||
return error; | |||||
} | } | ||||
/* | /* | ||||
* ioctl for getting driver info | * ioctl for getting driver info | ||||
*/ | */ | ||||
static void smartpqi_get_driver_info_ioctl(caddr_t udata, struct cdev *cdev) | static void | ||||
smartpqi_get_driver_info_ioctl(caddr_t udata, struct cdev *cdev) | |||||
{ | { | ||||
struct pqisrc_softstate *softs = cdev->si_drv1; | struct pqisrc_softstate *softs = cdev->si_drv1; | ||||
pdriver_info driver_info = (pdriver_info)udata; | pdriver_info driver_info = (pdriver_info)udata; | ||||
DBG_FUNC("IN udata = %p cdev = %p\n", udata, cdev); | DBG_FUNC("IN udata = %p cdev = %p\n", udata, cdev); | ||||
driver_info->major_version = PQISRC_DRIVER_MAJOR; | driver_info->major_version = PQISRC_OS_VERSION; | ||||
driver_info->minor_version = PQISRC_DRIVER_MINOR; | driver_info->minor_version = PQISRC_FEATURE_VERSION; | ||||
driver_info->release_version = PQISRC_DRIVER_RELEASE; | driver_info->release_version = PQISRC_PATCH_VERSION; | ||||
driver_info->build_revision = PQISRC_DRIVER_REVISION; | driver_info->build_revision = PQISRC_BUILD_VERSION; | ||||
driver_info->max_targets = PQI_MAX_DEVICES - 1; | driver_info->max_targets = PQI_MAX_DEVICES - 1; | ||||
driver_info->max_io = softs->max_io_for_scsi_ml; | driver_info->max_io = softs->max_io_for_scsi_ml; | ||||
driver_info->max_transfer_length = softs->pqi_cap.max_transfer_size; | driver_info->max_transfer_length = softs->pqi_cap.max_transfer_size; | ||||
DBG_FUNC("OUT\n"); | DBG_FUNC("OUT\n"); | ||||
} | } | ||||
/* | /* | ||||
* ioctl for getting controller info | * ioctl for getting controller info | ||||
*/ | */ | ||||
static void smartpqi_get_pci_info_ioctl(caddr_t udata, struct cdev *cdev) | static void | ||||
smartpqi_get_pci_info_ioctl(caddr_t udata, struct cdev *cdev) | |||||
{ | { | ||||
struct pqisrc_softstate *softs = cdev->si_drv1; | struct pqisrc_softstate *softs = cdev->si_drv1; | ||||
device_t dev = softs->os_specific.pqi_dev; | device_t dev = softs->os_specific.pqi_dev; | ||||
pqi_pci_info_t *pci_info = (pqi_pci_info_t *)udata; | pqi_pci_info_t *pci_info = (pqi_pci_info_t *)udata; | ||||
uint32_t sub_vendor = 0; | uint32_t sub_vendor = 0; | ||||
uint32_t sub_device = 0; | uint32_t sub_device = 0; | ||||
uint32_t vendor = 0; | uint32_t vendor = 0; | ||||
uint32_t device = 0; | uint32_t device = 0; | ||||
DBG_FUNC("IN udata = %p cdev = %p\n", udata, cdev); | DBG_FUNC("IN udata = %p cdev = %p\n", udata, cdev); | ||||
pci_info->bus = pci_get_bus(dev); | pci_info->bus = pci_get_bus(dev); | ||||
pci_info->dev_fn = pci_get_function(dev); | pci_info->dev_fn = pci_get_function(dev); | ||||
pci_info->domain = pci_get_domain(dev); | pci_info->domain = pci_get_domain(dev); | ||||
sub_vendor = pci_read_config(dev, PCIR_SUBVEND_0, 2); | sub_vendor = pci_read_config(dev, PCIR_SUBVEND_0, 2); | ||||
sub_device = pci_read_config(dev, PCIR_SUBDEV_0, 2); | sub_device = pci_read_config(dev, PCIR_SUBDEV_0, 2); | ||||
pci_info->board_id = ((sub_device << 16) & 0xffff0000) | sub_vendor; | pci_info->board_id = ((sub_device << 16) & 0xffff0000) | sub_vendor; | ||||
vendor = pci_get_vendor(dev); | vendor = pci_get_vendor(dev); | ||||
device = pci_get_device(dev); | device = pci_get_device(dev); | ||||
pci_info->chip_id = ((device << 16) & 0xffff0000) | vendor; | pci_info->chip_id = ((device << 16) & 0xffff0000) | vendor; | ||||
DBG_FUNC("OUT\n"); | DBG_FUNC("OUT\n"); | ||||
} | } | ||||
static inline int | |||||
pqi_status_to_bsd_ioctl_status(int pqi_status) | |||||
{ | |||||
if (PQI_STATUS_SUCCESS == pqi_status) | |||||
return BSD_SUCCESS; | |||||
else | |||||
return EIO; | |||||
} | |||||
/* | /* | ||||
* ioctl entry point for user | * ioctl entry point for user | ||||
*/ | */ | ||||
static int smartpqi_ioctl(struct cdev *cdev, u_long cmd, caddr_t udata, | static int | ||||
smartpqi_ioctl(struct cdev *cdev, u_long cmd, caddr_t udata, | |||||
int flags, struct thread *td) | int flags, struct thread *td) | ||||
{ | { | ||||
int error = PQI_STATUS_SUCCESS; | int bsd_status, pqi_status; | ||||
struct pqisrc_softstate *softs = cdev->si_drv1; | struct pqisrc_softstate *softs = cdev->si_drv1; | ||||
DBG_FUNC("IN cmd = 0x%lx udata = %p cdev = %p\n", cmd, udata, cdev); | DBG_FUNC("IN cmd = 0x%lx udata = %p cdev = %p\n", cmd, udata, cdev); | ||||
if (!udata) { | if (!udata) { | ||||
DBG_ERR("udata is null !!\n"); | DBG_ERR("udata is null !!\n"); | ||||
return EINVAL; | |||||
} | } | ||||
if (pqisrc_ctrl_offline(softs)){ | if (pqisrc_ctrl_offline(softs)){ | ||||
DBG_ERR("Controller s offline !!\n"); | |||||
return ENOTTY; | return ENOTTY; | ||||
} | } | ||||
switch (cmd) { | switch (cmd) { | ||||
case CCISS_GETDRIVVER: | case CCISS_GETDRIVVER: | ||||
smartpqi_get_driver_info_ioctl(udata, cdev); | smartpqi_get_driver_info_ioctl(udata, cdev); | ||||
bsd_status = BSD_SUCCESS; | |||||
break; | break; | ||||
case CCISS_GETPCIINFO: | case CCISS_GETPCIINFO: | ||||
smartpqi_get_pci_info_ioctl(udata, cdev); | smartpqi_get_pci_info_ioctl(udata, cdev); | ||||
bsd_status = BSD_SUCCESS; | |||||
break; | break; | ||||
case SMARTPQI_PASS_THRU: | case SMARTPQI_PASS_THRU: | ||||
case CCISS_PASSTHRU: | case CCISS_PASSTHRU: | ||||
error = pqisrc_passthru_ioctl(softs, udata, 0); | pqi_status = pqisrc_passthru_ioctl(softs, udata, 0); | ||||
error = PQI_STATUS_SUCCESS; | bsd_status = pqi_status_to_bsd_ioctl_status(pqi_status); | ||||
break; | break; | ||||
case CCISS_REGNEWD: | case CCISS_REGNEWD: | ||||
error = pqisrc_scan_devices(softs); | pqi_status = pqisrc_scan_devices(softs); | ||||
bsd_status = pqi_status_to_bsd_ioctl_status(pqi_status); | |||||
break; | break; | ||||
default: | default: | ||||
DBG_WARN( "!IOCTL cmd 0x%lx not supported", cmd); | DBG_WARN( "!IOCTL cmd 0x%lx not supported\n", cmd); | ||||
error = ENOTTY; | bsd_status = ENOTTY; | ||||
break; | break; | ||||
} | } | ||||
DBG_FUNC("OUT error = %d\n", error); | DBG_FUNC("OUT error = %d\n", bsd_status); | ||||
return error; | return bsd_status; | ||||
} | } | ||||
static struct cdevsw smartpqi_cdevsw = | static struct cdevsw smartpqi_cdevsw = | ||||
{ | { | ||||
.d_version = D_VERSION, | .d_version = D_VERSION, | ||||
.d_open = smartpqi_open, | .d_open = smartpqi_open, | ||||
.d_close = smartpqi_close, | .d_close = smartpqi_close, | ||||
.d_ioctl = smartpqi_ioctl, | .d_ioctl = smartpqi_ioctl, | ||||
.d_name = "smartpqi", | .d_name = "smartpqi", | ||||
}; | }; | ||||
/* | /* | ||||
* Function to create device node for ioctl | * Function to create device node for ioctl | ||||
*/ | */ | ||||
int create_char_dev(struct pqisrc_softstate *softs, int card_index) | int | ||||
create_char_dev(struct pqisrc_softstate *softs, int card_index) | |||||
{ | { | ||||
int error = PQI_STATUS_SUCCESS; | int error = BSD_SUCCESS; | ||||
DBG_FUNC("IN idx = %d\n", card_index); | DBG_FUNC("IN idx = %d\n", card_index); | ||||
softs->os_specific.cdev = make_dev(&smartpqi_cdevsw, card_index, | softs->os_specific.cdev = make_dev(&smartpqi_cdevsw, card_index, | ||||
UID_ROOT, GID_OPERATOR, 0640, | UID_ROOT, GID_OPERATOR, 0640, | ||||
"smartpqi%u", card_index); | "smartpqi%u", card_index); | ||||
if(softs->os_specific.cdev) { | if(softs->os_specific.cdev) { | ||||
softs->os_specific.cdev->si_drv1 = softs; | softs->os_specific.cdev->si_drv1 = softs; | ||||
} else { | } else { | ||||
error = PQI_STATUS_FAILURE; | error = ENXIO; | ||||
} | } | ||||
DBG_FUNC("OUT error = %d\n", error); | DBG_FUNC("OUT error = %d\n", error); | ||||
return error; | return error; | ||||
} | } | ||||
/* | /* | ||||
* Function to destroy device node for ioctl | * Function to destroy device node for ioctl | ||||
*/ | */ | ||||
void destroy_char_dev(struct pqisrc_softstate *softs) | void | ||||
destroy_char_dev(struct pqisrc_softstate *softs) | |||||
{ | { | ||||
DBG_FUNC("IN\n"); | DBG_FUNC("IN\n"); | ||||
if (softs->os_specific.cdev) { | if (softs->os_specific.cdev) { | ||||
destroy_dev(softs->os_specific.cdev); | destroy_dev(softs->os_specific.cdev); | ||||
softs->os_specific.cdev = NULL; | softs->os_specific.cdev = NULL; | ||||
} | } | ||||
DBG_FUNC("OUT\n"); | DBG_FUNC("OUT\n"); | ||||
} | } | ||||
Show All 13 Lines | pqisrc_passthru_ioctl(struct pqisrc_softstate *softs, void *arg, int mode) | ||||
pqisrc_raid_req_t request; | pqisrc_raid_req_t request; | ||||
raid_path_error_info_elem_t error_info; | raid_path_error_info_elem_t error_info; | ||||
ib_queue_t *ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE]; | ib_queue_t *ib_q = &softs->op_raid_ib_q[PQI_DEFAULT_IB_QUEUE]; | ||||
ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE]; | ob_queue_t *ob_q = &softs->op_ob_q[PQI_DEFAULT_IB_QUEUE]; | ||||
rcb_t *rcb = NULL; | rcb_t *rcb = NULL; | ||||
memset(&request, 0, sizeof(request)); | memset(&request, 0, sizeof(request)); | ||||
memset(&error_info, 0, sizeof(error_info)); | memset(&error_info, 0, sizeof(error_info)); | ||||
DBG_FUNC("IN"); | DBG_FUNC("IN"); | ||||
if (pqisrc_ctrl_offline(softs)) | if (pqisrc_ctrl_offline(softs)) | ||||
return PQI_STATUS_FAILURE; | return PQI_STATUS_FAILURE; | ||||
if (!arg) | if (!arg) | ||||
return (PQI_STATUS_FAILURE); | return (PQI_STATUS_FAILURE); | ||||
if (iocommand->buf_size < 1 && | if (iocommand->buf_size < 1 && | ||||
iocommand->Request.Type.Direction != PQIIOCTL_NONE) | iocommand->Request.Type.Direction != PQIIOCTL_NONE) | ||||
return PQI_STATUS_FAILURE; | return PQI_STATUS_FAILURE; | ||||
if (iocommand->Request.CDBLen > sizeof(request.cdb)) | if (iocommand->Request.CDBLen > sizeof(request.cdb)) | ||||
return PQI_STATUS_FAILURE; | return PQI_STATUS_FAILURE; | ||||
switch (iocommand->Request.Type.Direction) { | switch (iocommand->Request.Type.Direction) { | ||||
case PQIIOCTL_NONE: | case PQIIOCTL_NONE: | ||||
case PQIIOCTL_WRITE: | case PQIIOCTL_WRITE: | ||||
Show All 11 Lines | if (iocommand->buf_size > 0) { | ||||
ioctl_dma_buf.align = PQISRC_DEFAULT_DMA_ALIGN; | ioctl_dma_buf.align = PQISRC_DEFAULT_DMA_ALIGN; | ||||
/* allocate memory */ | /* allocate memory */ | ||||
ret = os_dma_mem_alloc(softs, &ioctl_dma_buf); | ret = os_dma_mem_alloc(softs, &ioctl_dma_buf); | ||||
if (ret) { | if (ret) { | ||||
DBG_ERR("Failed to Allocate dma mem for Ioctl PassthruCmd Buffer : %d\n", ret); | DBG_ERR("Failed to Allocate dma mem for Ioctl PassthruCmd Buffer : %d\n", ret); | ||||
ret = PQI_STATUS_FAILURE; | ret = PQI_STATUS_FAILURE; | ||||
goto out; | goto out; | ||||
} | } | ||||
DBG_INFO("ioctl_dma_buf.dma_addr = %p\n",(void*)ioctl_dma_buf.dma_addr); | DBG_INFO("ioctl_dma_buf.dma_addr = %p\n",(void*)ioctl_dma_buf.dma_addr); | ||||
DBG_INFO("ioctl_dma_buf.virt_addr = %p\n",(void*)ioctl_dma_buf.virt_addr); | DBG_INFO("ioctl_dma_buf.virt_addr = %p\n",(void*)ioctl_dma_buf.virt_addr); | ||||
drv_buf = (char *)ioctl_dma_buf.virt_addr; | drv_buf = (char *)ioctl_dma_buf.virt_addr; | ||||
if (iocommand->Request.Type.Direction & PQIIOCTL_WRITE) { | if (iocommand->Request.Type.Direction & PQIIOCTL_WRITE) { | ||||
if ((ret = os_copy_from_user(softs, (void *)drv_buf, (void *)iocommand->buf, | if ((ret = os_copy_from_user(softs, (void *)drv_buf, (void *)iocommand->buf, | ||||
iocommand->buf_size, mode)) != 0) { | iocommand->buf_size, mode)) != 0) { | ||||
ret = PQI_STATUS_FAILURE; | ret = PQI_STATUS_FAILURE; | ||||
goto free_mem; | goto free_mem; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
request.header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST; | request.header.iu_type = PQI_IU_TYPE_RAID_PATH_IO_REQUEST; | ||||
request.header.iu_length = offsetof(pqisrc_raid_req_t, sg_descriptors[1]) - | request.header.iu_length = offsetof(pqisrc_raid_req_t, sg_descriptors[1]) - | ||||
PQI_REQUEST_HEADER_LENGTH; | PQI_REQUEST_HEADER_LENGTH; | ||||
memcpy(request.lun_number, iocommand->LUN_info.LunAddrBytes, | memcpy(request.lun_number, iocommand->LUN_info.LunAddrBytes, | ||||
sizeof(request.lun_number)); | sizeof(request.lun_number)); | ||||
memcpy(request.cdb, iocommand->Request.CDB, iocommand->Request.CDBLen); | memcpy(request.cdb, iocommand->Request.CDB, iocommand->Request.CDBLen); | ||||
request.additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0; | request.additional_cdb_bytes_usage = PQI_ADDITIONAL_CDB_BYTES_0; | ||||
switch (iocommand->Request.Type.Direction) { | switch (iocommand->Request.Type.Direction) { | ||||
case PQIIOCTL_NONE: | case PQIIOCTL_NONE: | ||||
request.data_direction = SOP_DATA_DIR_NONE; | request.data_direction = SOP_DATA_DIR_NONE; | ||||
break; | break; | ||||
case PQIIOCTL_WRITE: | case PQIIOCTL_WRITE: | ||||
request.data_direction = SOP_DATA_DIR_FROM_DEVICE; | request.data_direction = SOP_DATA_DIR_FROM_DEVICE; | ||||
break; | break; | ||||
case PQIIOCTL_READ: | case PQIIOCTL_READ: | ||||
Show All 15 Lines | pqisrc_passthru_ioctl(struct pqisrc_softstate *softs, void *arg, int mode) | ||||
if (INVALID_ELEM == tag) { | if (INVALID_ELEM == tag) { | ||||
DBG_ERR("Tag not available\n"); | DBG_ERR("Tag not available\n"); | ||||
ret = PQI_STATUS_FAILURE; | ret = PQI_STATUS_FAILURE; | ||||
goto free_mem; | goto free_mem; | ||||
} | } | ||||
request.request_id = tag; | request.request_id = tag; | ||||
request.response_queue_id = ob_q->q_id; | request.response_queue_id = ob_q->q_id; | ||||
request.error_index = request.request_id; | request.error_index = request.request_id; | ||||
rcb = &softs->rcb[tag]; | if (softs->timeout_in_passthrough) { | ||||
request.timeout_in_sec = iocommand->Request.Timeout; | |||||
} | |||||
rcb = &softs->rcb[tag]; | |||||
rcb->success_cmp_callback = pqisrc_process_internal_raid_response_success; | rcb->success_cmp_callback = pqisrc_process_internal_raid_response_success; | ||||
rcb->error_cmp_callback = pqisrc_process_internal_raid_response_error; | rcb->error_cmp_callback = pqisrc_process_internal_raid_response_error; | ||||
rcb->tag = tag; | rcb->tag = tag; | ||||
rcb->req_pending = true; | rcb->req_pending = true; | ||||
/* Submit Command */ | /* Submit Command */ | ||||
ret = pqisrc_submit_cmnd(softs, ib_q, &request); | ret = pqisrc_submit_cmnd(softs, ib_q, &request); | ||||
if (ret != PQI_STATUS_SUCCESS) { | if (ret != PQI_STATUS_SUCCESS) { | ||||
DBG_ERR("Unable to submit command\n"); | DBG_ERR("Unable to submit command\n"); | ||||
goto err_out; | goto err_out; | ||||
} | } | ||||
ret = pqisrc_wait_on_condition(softs, rcb); | ret = pqisrc_wait_on_condition(softs, rcb, | ||||
PQISRC_PASSTHROUGH_CMD_TIMEOUT); | |||||
if (ret != PQI_STATUS_SUCCESS) { | if (ret != PQI_STATUS_SUCCESS) { | ||||
DBG_ERR("Passthru IOCTL cmd timed out !!\n"); | DBG_ERR("Passthru IOCTL cmd timed out !!\n"); | ||||
goto err_out; | goto err_out; | ||||
} | } | ||||
memset(&iocommand->error_info, 0, sizeof(iocommand->error_info)); | memset(&iocommand->error_info, 0, sizeof(iocommand->error_info)); | ||||
if (rcb->status) { | if (rcb->status) { | ||||
size_t sense_data_length; | size_t sense_data_length; | ||||
memcpy(&error_info, rcb->error_info, sizeof(error_info)); | memcpy(&error_info, rcb->error_info, sizeof(error_info)); | ||||
iocommand->error_info.ScsiStatus = error_info.status; | iocommand->error_info.ScsiStatus = error_info.status; | ||||
sense_data_length = error_info.sense_data_len; | sense_data_length = error_info.sense_data_len; | ||||
if (!sense_data_length) | if (!sense_data_length) | ||||
sense_data_length = error_info.resp_data_len; | sense_data_length = error_info.resp_data_len; | ||||
if (sense_data_length && | if (sense_data_length && | ||||
(sense_data_length > sizeof(error_info.data))) | (sense_data_length > sizeof(error_info.data))) | ||||
sense_data_length = sizeof(error_info.data); | sense_data_length = sizeof(error_info.data); | ||||
if (sense_data_length) { | if (sense_data_length) { | ||||
if (sense_data_length > | if (sense_data_length > | ||||
sizeof(iocommand->error_info.SenseInfo)) | sizeof(iocommand->error_info.SenseInfo)) | ||||
sense_data_length = | sense_data_length = | ||||
sizeof(iocommand->error_info.SenseInfo); | sizeof(iocommand->error_info.SenseInfo); | ||||
memcpy (iocommand->error_info.SenseInfo, | memcpy (iocommand->error_info.SenseInfo, | ||||
error_info.data, sense_data_length); | error_info.data, sense_data_length); | ||||
iocommand->error_info.SenseLen = sense_data_length; | iocommand->error_info.SenseLen = sense_data_length; | ||||
} | } | ||||
if (error_info.data_out_result == | if (error_info.data_out_result == | ||||
PQI_RAID_DATA_IN_OUT_UNDERFLOW){ | PQI_RAID_DATA_IN_OUT_UNDERFLOW){ | ||||
rcb->status = REQUEST_SUCCESS; | rcb->status = REQUEST_SUCCESS; | ||||
} | } | ||||
} | } | ||||
if (rcb->status == REQUEST_SUCCESS && iocommand->buf_size > 0 && | if (rcb->status == REQUEST_SUCCESS && iocommand->buf_size > 0 && | ||||
(iocommand->Request.Type.Direction & PQIIOCTL_READ)) { | (iocommand->Request.Type.Direction & PQIIOCTL_READ)) { | ||||
if ((ret = os_copy_to_user(softs, (void*)iocommand->buf, | if ((ret = os_copy_to_user(softs, (void*)iocommand->buf, | ||||
(void*)drv_buf, iocommand->buf_size, mode)) != 0) { | (void*)drv_buf, iocommand->buf_size, mode)) != 0) { | ||||
DBG_ERR("Failed to copy the response\n"); | DBG_ERR("Failed to copy the response\n"); | ||||
goto err_out; | goto err_out; | ||||
} | } | ||||
} | } | ||||
os_reset_rcb(rcb); | os_reset_rcb(rcb); | ||||
pqisrc_put_tag(&softs->taglist, request.request_id); | pqisrc_put_tag(&softs->taglist, request.request_id); | ||||
if (iocommand->buf_size > 0) | if (iocommand->buf_size > 0) | ||||
os_dma_mem_free(softs,&ioctl_dma_buf); | os_dma_mem_free(softs,&ioctl_dma_buf); | ||||
DBG_FUNC("OUT\n"); | DBG_FUNC("OUT\n"); | ||||
return ret; | return ret; | ||||
err_out: | err_out: | ||||
os_reset_rcb(rcb); | os_reset_rcb(rcb); | ||||
pqisrc_put_tag(&softs->taglist, request.request_id); | pqisrc_put_tag(&softs->taglist, request.request_id); | ||||
free_mem: | free_mem: | ||||
if (iocommand->buf_size > 0) | if (iocommand->buf_size > 0) | ||||
os_dma_mem_free(softs, &ioctl_dma_buf); | os_dma_mem_free(softs, &ioctl_dma_buf); | ||||
out: | out: | ||||
DBG_FUNC("Failed OUT\n"); | DBG_FUNC("Failed OUT\n"); | ||||
return PQI_STATUS_FAILURE; | return PQI_STATUS_FAILURE; | ||||
} | } |