📄 mptctl.c
字号:
int sgSize = 0; /* Num SG elements */ int this_alloc; int iocnum, flagsLength; int sz, rc = 0; int msgContext; int tm_flags_set = 0; u16 req_idx; dctlprintk(("mptctl_do_mpt_command called.\n")); 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->id)) == 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. */ if (local) { /* Request frame in kernel space */ memcpy((char *)mf, (char *) mfPtr, karg.dataSgeOffset * 4); } else { /* Request frame in user space */ if (copy_from_user((char *)mf, (char *) 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__, (void*)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: 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: 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; 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; 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; default: /* * MPI_FUNCTION_IOC_INIT * 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_FC_PRIMITIVE_SEND 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) { /* Allocate memory for the SGL. * Used to free kernel memory once * the MF is freed. */ sglbuf = pci_alloc_consistent (ioc->pcidev, sgSize*sizeof(MptSge_t), &sglbuf_dma); if (sglbuf == NULL) { rc = -ENOMEM; goto done_free_mem; } this_sge = sglbuf; /* Set up the dataOut memory allocation */ if (karg.dataOutSize > 0) { dir = PCI_DMA_TODEVICE; if (karg.dataInSize > 0 ) { flagsLength = ( MPI_SGE_FLAGS_SIMPLE_ELEMENT | MPI_SGE_FLAGS_DIRECTION | mpt_addr_size() ) << MPI_SGE_FLAGS_SHIFT; } else { flagsLength = MPT_SGE_FLAGS_SSIMPLE_WRITE; } flagsLength |= karg.dataOutSize; this_alloc = karg.dataOutSize; bufOut.len = this_alloc; bufOut.kptr = pci_alloc_consistent( ioc->pcidev, this_alloc, &dma_addr); if (bufOut.kptr == NULL) { rc = -ENOMEM; goto done_free_mem; } else { /* 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__,(void*)karg.dataOutBufPtr); rc = -EFAULT; goto done_free_mem; } /* Set up this SGE. * Copy to MF and to sglbuf */ mpt_add_sge(psge, flagsLength, dma_addr); psge += (sizeof(u32) + sizeof(dma_addr_t)); this_sge->FlagsLength = flagsLength; this_sge->Address = dma_addr; this_sge++; } } if (karg.dataInSize > 0) { dir = PCI_DMA_FROMDEVICE; flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; flagsLength |= karg.dataInSize; this_alloc = karg.dataInSize; bufIn.len = this_alloc; bufIn.kptr = pci_alloc_consistent(ioc->pcidev, this_alloc, &dma_addr); 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); this_sge->FlagsLength = flagsLength; this_sge->Address = dma_addr; this_sge++; } } } 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) { rc = mpt_send_handshake_request(mptctl_id, ioc->id, sizeof(SCSITaskMgmt_t), (u32*)mf, NO_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; } } else { mpt_put_msg_frame(mptctl_id, ioc->id, mf); wait_event(mptctl_wait, ioc->ioctl->wait_done); } /* The command is complete. * Return data to the user. * * If command completed, mf has been freed so cannot * use this memory. * * If timeout, a recovery mechanism has been called. * Need to free the mf. */ if (ioc->ioctl->status & MPT_IOCTL_STATUS_DID_IOCRESET) { /* A timeout - there is no data to return to the * the user other than an error. * 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; /* Free memory and return to the calling function */ goto done_free_mem; } else if (ioc->ioctl->status & MPT_IOCTL_STATUS_TM_FAILED) { /* User TM request failed! */ rc = -ENODATA; } else { /* Callback freed request frame. */ mf = NULL; /* 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((char *)karg.replyFrameBufPtr, &ioc->ioctl->ReplyFrame, sz)){ printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " "Unable to write out reply frame %p\n", __FILE__, __LINE__, (void*)karg.replyFrameBufPtr); rc = -ENODATA; goto done_free_mem; } } } /* If valid sense data, copy to user. */ if (ioc->ioctl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -