📄 mptctl.c
字号:
dma_addr_t dma_addr_in; dma_addr_t dma_addr_out; int sgSize = 0; /* Num SG elements */ int iocnum, flagsLength; int sz, rc = 0; int msgContext; int tm_flags_set = 0; u16 req_idx; dctlprintk(("mptctl_do_mpt_command called.\n")); bufIn.kptr = bufOut.kptr = NULL; if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { dctlprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } if (!ioc->ioctl) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "No memory available during driver init.\n", __FILE__, __LINE__); return -ENOMEM; } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Busy with IOC Reset \n", __FILE__, __LINE__); return -EBUSY; } /* Verify that the final request frame will not be too large. */ sz = karg.dataSgeOffset * 4; if (karg.dataInSize > 0) sz += sizeof(dma_addr_t) + sizeof(u32); if (karg.dataOutSize > 0) sz += sizeof(dma_addr_t) + sizeof(u32); if (sz > ioc->req_sz) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Request frame too large (%d) maximum (%d)\n", __FILE__, __LINE__, sz, ioc->req_sz); return -EFAULT; } /* Get a free request frame and save the message context. */ if ((mf = mpt_get_msg_frame(mptctl_id, ioc)) == NULL) return -EAGAIN; hdr = (MPIHeader_t *) mf; msgContext = le32_to_cpu(hdr->MsgContext); req_idx = le16_to_cpu(mf->u.frame.hwhdr.msgctxu.fld.req_idx); /* Copy the request frame * Reset the saved message context. * Request frame in user space */ if (copy_from_user(mf, mfPtr, karg.dataSgeOffset * 4)) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Unable to read MF from mpt_ioctl_command struct @ %p\n", __FILE__, __LINE__, mfPtr); rc = -EFAULT; goto done_free_mem; } hdr->MsgContext = cpu_to_le32(msgContext); /* Verify that this request is allowed. */ switch (hdr->Function) { case MPI_FUNCTION_IOC_FACTS: case MPI_FUNCTION_PORT_FACTS: karg.dataOutSize = karg.dataInSize = 0; break; case MPI_FUNCTION_CONFIG: case MPI_FUNCTION_FC_COMMON_TRANSPORT_SEND: case MPI_FUNCTION_FC_EX_LINK_SRVC_SEND: case MPI_FUNCTION_FW_UPLOAD: case MPI_FUNCTION_SCSI_ENCLOSURE_PROCESSOR: case MPI_FUNCTION_FW_DOWNLOAD: case MPI_FUNCTION_FC_PRIMITIVE_SEND: break; case MPI_FUNCTION_SCSI_IO_REQUEST: if (ioc->sh) { SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf; VirtDevice *pTarget = NULL; MPT_SCSI_HOST *hd = NULL; int qtag = MPI_SCSIIO_CONTROL_UNTAGGED; int scsidir = 0; int target = (int) pScsiReq->TargetID; int dataSize; if ((target < 0) || (target >= ioc->sh->max_id)) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Target ID out of bounds. \n", __FILE__, __LINE__); rc = -ENODEV; goto done_free_mem; } pScsiReq->MsgFlags = mpt_msg_flags(); /* verify that app has not requested * more sense data than driver * can provide, if so, reset this parameter * set the sense buffer pointer low address * update the control field to specify Q type */ if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; else pScsiReq->SenseBufferLength = karg.maxSenseBytes; pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (req_idx * MPT_SENSE_BUFFER_ALLOC)); if ((hd = (MPT_SCSI_HOST *) ioc->sh->hostdata)) { if (hd->Targets) pTarget = hd->Targets[target]; } if (pTarget &&(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; /* Have the IOCTL driver set the direction based * on the dataOutSize (ordering issue with Sparc). */ if (karg.dataOutSize > 0) { scsidir = MPI_SCSIIO_CONTROL_WRITE; dataSize = karg.dataOutSize; } else { scsidir = MPI_SCSIIO_CONTROL_READ; dataSize = karg.dataInSize; } pScsiReq->Control = cpu_to_le32(scsidir | qtag); pScsiReq->DataLength = cpu_to_le32(dataSize); ioc->ioctl->reset = MPTCTL_RESET_OK; ioc->ioctl->target = target; } else { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } break; case MPI_FUNCTION_RAID_ACTION: /* Just add a SGE */ break; case MPI_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: if (ioc->sh) { SCSIIORequest_t *pScsiReq = (SCSIIORequest_t *) mf; int qtag = MPI_SCSIIO_CONTROL_SIMPLEQ; int scsidir = MPI_SCSIIO_CONTROL_READ; int dataSize; pScsiReq->MsgFlags = mpt_msg_flags(); /* verify that app has not requested * more sense data than driver * can provide, if so, reset this parameter * set the sense buffer pointer low address * update the control field to specify Q type */ if (karg.maxSenseBytes > MPT_SENSE_BUFFER_SIZE) pScsiReq->SenseBufferLength = MPT_SENSE_BUFFER_SIZE; else pScsiReq->SenseBufferLength = karg.maxSenseBytes; pScsiReq->SenseBufferLowAddr = cpu_to_le32(ioc->sense_buf_low_dma + (req_idx * MPT_SENSE_BUFFER_ALLOC)); /* All commands to physical devices are tagged */ /* Have the IOCTL driver set the direction based * on the dataOutSize (ordering issue with Sparc). */ if (karg.dataOutSize > 0) { scsidir = MPI_SCSIIO_CONTROL_WRITE; dataSize = karg.dataOutSize; } else { scsidir = MPI_SCSIIO_CONTROL_READ; dataSize = karg.dataInSize; } pScsiReq->Control = cpu_to_le32(scsidir | qtag); pScsiReq->DataLength = cpu_to_le32(dataSize); ioc->ioctl->reset = MPTCTL_RESET_OK; ioc->ioctl->target = pScsiReq->TargetID; } else { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "SCSI driver is not loaded. \n", __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } break; case MPI_FUNCTION_SCSI_TASK_MGMT: { MPT_SCSI_HOST *hd = NULL; if ((ioc->sh == NULL) || ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "SCSI driver not loaded or SCSI host not found. \n", __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } else if (mptctl_set_tm_flags(hd) != 0) { rc = -EPERM; goto done_free_mem; } tm_flags_set = 1; } break; case MPI_FUNCTION_IOC_INIT: { IOCInit_t *pInit = (IOCInit_t *) mf; u32 high_addr, sense_high; /* Verify that all entries in the IOC INIT match * existing setup (and in LE format). */ if (sizeof(dma_addr_t) == sizeof(u64)) { high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32)); sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); } else { high_addr = 0; sense_high= 0; } if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) || (pInit->MaxBuses != ioc->facts.MaxBuses) || (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) || (pInit->HostMfaHighAddr != high_addr) || (pInit->SenseBufferHighAddr != sense_high)) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n", __FILE__, __LINE__); rc = -EFAULT; goto done_free_mem; } } break; default: /* * MPI_FUNCTION_PORT_ENABLE * MPI_FUNCTION_TARGET_CMD_BUFFER_POST * MPI_FUNCTION_TARGET_ASSIST * MPI_FUNCTION_TARGET_STATUS_SEND * MPI_FUNCTION_TARGET_MODE_ABORT * MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET * MPI_FUNCTION_IO_UNIT_RESET * MPI_FUNCTION_HANDSHAKE * MPI_FUNCTION_REPLY_FRAME_REMOVAL * MPI_FUNCTION_EVENT_NOTIFICATION * (driver handles event notification) * MPI_FUNCTION_EVENT_ACK */ /* What to do with these??? CHECK ME!!! MPI_FUNCTION_FC_LINK_SRVC_BUF_POST MPI_FUNCTION_FC_LINK_SRVC_RSP MPI_FUNCTION_FC_ABORT MPI_FUNCTION_LAN_SEND MPI_FUNCTION_LAN_RECEIVE MPI_FUNCTION_LAN_RESET */ printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Illegal request (function 0x%x) \n", __FILE__, __LINE__, hdr->Function); rc = -EFAULT; goto done_free_mem; } /* Add the SGL ( at most one data in SGE and one data out SGE ) * In the case of two SGE's - the data out (write) will always * preceede the data in (read) SGE. psgList is used to free the * allocated memory. */ psge = (char *) (((int *) mf) + karg.dataSgeOffset); flagsLength = 0; /* bufIn and bufOut are used for user to kernel space transfers */ bufIn.kptr = bufOut.kptr = NULL; bufIn.len = bufOut.len = 0; if (karg.dataOutSize > 0) sgSize ++; if (karg.dataInSize > 0) sgSize ++; if (sgSize > 0) { /* Set up the dataOut memory allocation */ if (karg.dataOutSize > 0) { if (karg.dataInSize > 0) { flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_END_OF_BUFFER | MPI_SGE_FLAGS_DIRECTION | mpt_addr_size() ) << MPI_SGE_FLAGS_SHIFT; } else { flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; } flagsLength |= karg.dataOutSize; bufOut.len = karg.dataOutSize; bufOut.kptr = pci_alloc_consistent( ioc->pcidev, bufOut.len, &dma_addr_out); if (bufOut.kptr == NULL) { rc = -ENOMEM; goto done_free_mem; } else { /* Set up this SGE. * Copy to MF and to sglbuf */ mpt_add_sge(psge, flagsLength, dma_addr_out); psge += (sizeof(u32) + sizeof(dma_addr_t)); /* Copy user data to kernel space. */ if (copy_from_user(bufOut.kptr, karg.dataOutBufPtr, bufOut.len)) { printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - Unable " "to read user data " "struct @ %p\n", __FILE__, __LINE__,karg.dataOutBufPtr); rc = -EFAULT; goto done_free_mem; } } } if (karg.dataInSize > 0) { flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; flagsLength |= karg.dataInSize; bufIn.len = karg.dataInSize; bufIn.kptr = pci_alloc_consistent(ioc->pcidev, bufIn.len, &dma_addr_in); if (bufIn.kptr == NULL) { rc = -ENOMEM; goto done_free_mem; } else { /* Set up this SGE * Copy to MF and to sglbuf */ mpt_add_sge(psge, flagsLength, dma_addr_in); } } } else { /* Add a NULL SGE */ mpt_add_sge(psge, flagsLength, (dma_addr_t) -1); } /* The request is complete. Set the timer parameters * and issue the request. */ if (karg.timeout > 0) { ioc->ioctl->timer.expires = jiffies + HZ*karg.timeout; } else { ioc->ioctl->timer.expires = jiffies + HZ*MPT_IOCTL_DEFAULT_TIMEOUT; } ioc->ioctl->wait_done = 0; ioc->ioctl->status |= MPT_IOCTL_STATUS_TIMER_ACTIVE; add_timer(&ioc->ioctl->timer); if (hdr->Function == MPI_FUNCTION_SCSI_TASK_MGMT) { DBG_DUMP_TM_REQUEST_FRAME((u32 *)mf); rc = mpt_send_handshake_request(mptctl_id, ioc, sizeof(SCSITaskMgmt_t), (u32*)mf, CAN_SLEEP); if (rc == 0) { wait_event(mptctl_wait, ioc->ioctl->wait_done); } else { mptctl_free_tm_flags(ioc); tm_flags_set= 0; del_timer(&ioc->ioctl->timer); ioc->ioctl->status &= ~MPT_IOCTL_STATUS_TIMER_ACTIVE; ioc->ioctl->status |= MPT_IOCTL_STATUS_TM_FAILED; mpt_free_msg_frame(ioc, mf); } } else { mpt_put_msg_frame(mptctl_id, ioc, mf); wait_event(mptctl_wait, ioc->ioctl->wait_done); } mf = NULL; /* MF Cleanup: * If command failed and failure triggered a diagnostic reset * OR a diagnostic reset happens during command processing, * no data, messaging queues are reset (mf cannot be accessed), * and status is DID_IOCRESET * * If a user-requested bus reset fails to be handshaked, then * mf is returned to free queue and status is TM_FAILED. * * Otherise, the command completed and the mf was freed # by ISR (mf cannot be touched). */ if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { /* The timer callback deleted the * timer and reset the adapter queues. */ printk(KERN_WARNING "%s@%d::mptctl_do_mpt_command - " "Timeout Occurred on IOCTL! Reset IOC.\n", __FILE__, __LINE__); tm_flags_set= 0; rc = -ETIME; } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TM_FAILED) { /* User TM request failed! mf has not been freed. */ rc = -ENODATA; } else { /* If a valid reply frame, copy to the user. * Offset 2: reply length in U32's */ if (ioc->ioctl->status & MPT_IOCTL_STATUS_RF_VALID) { if (karg.maxReplyBytes < ioc->reply_sz) { sz = min(karg.maxReplyBytes, 4*ioc->ioctl->ReplyFrame[2]); } else { sz = min(ioc->reply_sz, 4*ioc->ioctl->ReplyFrame[2]); } if (sz > 0) { if (copy_to_user(karg.replyFrameBufPtr, &ioc->ioctl->ReplyFrame, sz)){ printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Unable to write out rep
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -