📄 scsictrllib.c
字号:
return ((xferCount == pThread->statusLength) ? OK : ERROR); }/******************************************************************************** scsiCtrlMsgOutAction - respond to a request to send a SCSI message** This routine handles a SCSI message out transfer request. If there is no* message available to send to the target, a SCSI NO-OP message is sent.* If there is a message which has already been sent, ATN is asserted (this is* a requirement imposed by the SCSI specification).** Data is output from the message-out buffer in a single transfer. The* controller hardware must keep ATN asserted until just before ACK is* asserted during the last byte of the outgoing message, per SCSI 5.2.1.** Assuming the information transfer does not fail altogether, there are two* "successful" outcomes:** 1) the entire message is transferred - in this case the message state* is set to SENT. However, the target is not deemed to have accepted* the message until it requests a different phase - this is detected* and acted upon in "scsiCtrlNormalXfer()". (If the target continues* to request a MSG OUT transfer, it wants the current message to be* re-sent.)** 2) the message is only partially transferred - most likely because the* target has changed phase (e.g., to send a Reject message) before* all the message out bytes have been transferred. In this case the* message state remains PENDING. If the target is about to reject it,* the state will be reset then, otherwise we will try to send it again* when the target next requests a message out transfer.** Note: it is assumed that the length of the message never exceeds the* maximum byte count the controller can handle.** RETURNS: OK, or ERROR if information transfer phase fails.*/LOCAL STATUS scsiCtrlMsgOutAction ( SCSI_CTRL *pScsiCtrl, /* ptr to SCSI controller info */ SCSI_THREAD *pThread /* ptr to thread info */ ) { UINT xferCount; /* number of bytes transferred */ if ((pScsiCtrl->msgOutState == SCSI_MSG_OUT_SENT) && (pScsiCtrl->msgOutLength > 1)) { /* target is retrying: need to assert ATN (SCSI 5.1.9.2) */ if ((*pScsiCtrl->scsiBusControl) (pScsiCtrl, SCSI_BUS_ASSERT_ATN) != OK) { SCSI_ERROR_MSG ("scsiCtrlMsgOutAction: can't assert ATN.\n", 0, 0, 0, 0, 0, 0); return (ERROR); } } if (pScsiCtrl->msgOutState == SCSI_MSG_OUT_NONE) { pScsiCtrl->msgOutBuf[0] = SCSI_MSG_NO_OP; pScsiCtrl->msgOutLength = 1; } xferCount = (*pScsiCtrl->scsiInfoXfer) (pScsiCtrl, SCSI_MSG_OUT_PHASE, pScsiCtrl->msgOutBuf, pScsiCtrl->msgOutLength); if (xferCount == ERROR) return (ERROR); if (xferCount == pScsiCtrl->msgOutLength) pScsiCtrl->msgOutState = SCSI_MSG_OUT_SENT; return (OK); }/******************************************************************************** scsiCtrlMsgInAction - respond to an incoming SCSI message** Read and handle an incoming message from the target.** Note that if the incoming message is a SCSI Extended Message, it needs to* be read in three chunks (the message type, the additional length and the* extended message itself). This is achieved by using a finite state machine* which cycles through the chunks, returning to the phase sequencing code* until the message is complete.** RETURNS: OK, or ERROR if information transfer phase fails.*/LOCAL STATUS scsiCtrlMsgInAction ( SCSI_CTRL *pScsiCtrl, /* ptr to SCSI controller info */ SCSI_THREAD *pThread /* ptr to thread info */ ) { /* * Handle (possibly partial) message transfer */ if (pScsiCtrl->msgOutState == SCSI_MSG_OUT_PENDING) SCSI_DEBUG_MSG ("scsiCtrlMsgInAction: msg in while msg out pending\n", 0, 0, 0, 0, 0, 0); if (scsiCtrlMsgInXfer (pScsiCtrl) != OK) return (ERROR); /* * If we have a complete message, parse it and respond appropriately */ if (pScsiCtrl->msgInState == SCSI_MSG_IN_NONE) (void) scsiMsgInComplete (pScsiCtrl, pThread); /* * Negate ACK to allow target to continue; if rejecting message, * also assert ATN. */ if (scsiCtrlMsgInAck (pScsiCtrl) != OK) { SCSI_ERROR_MSG ("scsiCtrlMsgInAction: scsiCtrlMsgInAck failed.\n", 0, 0, 0, 0, 0, 0); return (ERROR); } return (OK); }/******************************************************************************** scsiCtrlMsgInXfer - handle MSG IN information transfer** Note: does not necessarily read a complete message.** Note: it is assumed that a message in transfer must be completed fully, i.e.* the target cannot disconnect. It is also assumed that the length of the* message (fragment) does not exceed the maximum byte count the controller* can handle.** RETURNS: OK, or ERROR if transfer fails.*/LOCAL STATUS scsiCtrlMsgInXfer ( SCSI_CTRL *pScsiCtrl /* ptr to SCSI controller info */ ) { UINT xferCount; /* number of bytes transferred */ UINT maxBytes; /* max number of bytes to read */ SCSI_MSG_IN_STATE state = pScsiCtrl->msgInState; switch (state) { case SCSI_MSG_IN_NONE: pScsiCtrl->msgInLength = 0; maxBytes = 1; break; case SCSI_MSG_IN_SECOND_BYTE: maxBytes = 1; break; case SCSI_MSG_IN_EXT_MSG_LEN: maxBytes = 1; break; case SCSI_MSG_IN_EXT_MSG_DATA: if ((maxBytes = pScsiCtrl->msgInBuf[SCSI_EXT_MSG_LENGTH_BYTE]) == 0) maxBytes = SCSI_EXT_MSG_MAX_LENGTH; break; default: SCSI_MSG ("scsiCtrlMsgInXfer: invalid state (%d)\n", state, 0, 0, 0, 0, 0); pScsiCtrl->msgInState = SCSI_MSG_IN_NONE; return (ERROR); } xferCount = (*pScsiCtrl->scsiInfoXfer) (pScsiCtrl, SCSI_MSG_IN_PHASE, pScsiCtrl->msgInBuf + pScsiCtrl->msgInLength, maxBytes); if (xferCount != maxBytes) { SCSI_ERROR_MSG ("scsiCtrlMsgInXfer: transfer failed\n", 0, 0, 0, 0, 0, 0); if (xferCount != ERROR) errnoSet (S_scsiLib_HARDWARE_ERROR); return (ERROR); } switch (state) { case SCSI_MSG_IN_NONE: if (pScsiCtrl->msgInBuf[0] == SCSI_MSG_EXTENDED_MESSAGE) state = SCSI_MSG_IN_EXT_MSG_LEN; else if (SCSI_IS_TWO_BYTE_MSG (pScsiCtrl->msgInBuf[0])) state = SCSI_MSG_IN_SECOND_BYTE; else state = SCSI_MSG_IN_NONE; break; case SCSI_MSG_IN_SECOND_BYTE: state = SCSI_MSG_IN_NONE; break; case SCSI_MSG_IN_EXT_MSG_LEN: state = SCSI_MSG_IN_EXT_MSG_DATA; break; case SCSI_MSG_IN_EXT_MSG_DATA: state = SCSI_MSG_IN_NONE; break; default: SCSI_MSG ("scsiCtrlMsgInXfer: invalid state (%d)\n", state, 0, 0, 0, 0, 0); pScsiCtrl->msgInState = SCSI_MSG_IN_NONE; return (ERROR); } pScsiCtrl->msgInState = state; pScsiCtrl->msgInLength += xferCount; return (OK); }/********************************************************************************* scsiCtrlThreadComplete - complete execution of a client thread** Set the thread status and errno appropriately, depending on whether or* not the thread has been aborted. Set the thread inactive, and notify* the SCSI manager of the completion.** RETURNS: N/A*/LOCAL void scsiCtrlThreadComplete ( SCSI_THREAD * pThread ) { SCSI_DEBUG_MSG ("scsiCtrlThreadComplete: thread 0x%08x completed\n", (int) pThread, 0, 0, 0, 0, 0); if (pThread->state == SCSI_THREAD_WAIT_ABORT) { pThread->status = ERROR; pThread->errNum = S_scsiLib_ABORTED; } else { pThread->status = OK; pThread->errNum = 0; } scsiCtrlThreadStateSet (pThread, SCSI_THREAD_INACTIVE); scsiCacheSynchronize (pThread, SCSI_CACHE_POST_COMMAND); scsiMgrThreadEvent (pThread, SCSI_THREAD_EVENT_COMPLETED); }/********************************************************************************* scsiCtrlThreadDefer - defer execution of a thread** Set the thread's state to INACTIVE and notify the SCSI manager of the* deferral event.** RETURNS: N/A*/LOCAL void scsiCtrlThreadDefer ( SCSI_THREAD * pThread ) { SCSI_DEBUG_MSG ("scsiCtrlThreadDefer: thread 0x%08x deferred\n", (int) pThread, 0, 0, 0, 0, 0); scsiCtrlThreadStateSet (pThread, SCSI_THREAD_INACTIVE); scsiMgrThreadEvent (pThread, SCSI_THREAD_EVENT_DEFERRED); } /********************************************************************************* scsiCtrlThreadFail - complete execution of a thread, with error status** Set the thread's status and errno according to the type of error. Set* the thread's state to INACTIVE, and notify the SCSI manager of the* completion event.** RETURNS: N/A*/LOCAL void scsiCtrlThreadFail ( SCSI_THREAD * pThread, int errNum ) { SCSI_DEBUG_MSG ("scsiCtrlThreadFail: thread 0x%08x failed (errno = %d)\n", (int) pThread, errNum, 0, 0, 0, 0); pThread->status = ERROR; if (pThread->state == SCSI_THREAD_WAIT_ABORT) pThread->errNum = S_scsiLib_ABORTED; else pThread->errNum = errNum; scsiCtrlThreadStateSet (pThread, SCSI_THREAD_INACTIVE); scsiMgrThreadEvent (pThread, SCSI_THREAD_EVENT_COMPLETED); } /********************************************************************************* scsiCtrlThreadStateSet - set the state of a thread** This is really just a place-holder for debugging and possible future* enhancements such as state-change logging.** RETURNS: N/A*/LOCAL void scsiCtrlThreadStateSet ( SCSI_THREAD * pThread, /* ptr to thread info */ SCSI_THREAD_STATE state ) { SCSI_DEBUG_MSG ("scsiCtrlThreadStateSet: thread 0x%08x: %d -> %d\n", (int) pThread, pThread->state, state, 0, 0, 0); pThread->state = state; }/********************************************************************************* scsiCtrlXferParamsSet - set transfer parameters for a thread** Call the controller-specific routine to set transfer parameters to the* values required by this thread's target device.** RETURNS: OK, or ERROR if transfer parameters cannot be set*/LOCAL STATUS scsiCtrlXferParamsSet ( SCSI_THREAD * pThread ) { SCSI_TARGET * pScsiTarget = pThread->pScsiTarget; SCSI_CTRL * pScsiCtrl = pThread->pScsiCtrl; /* * Set transfer parameters for thread's target device */ if ((*pScsiCtrl->scsiXferParamsSet) (pScsiCtrl, pScsiTarget->xferOffset, pScsiTarget->xferPeriod) != OK) { SCSI_ERROR_MSG ("scsiCtrlXferParamsSet: can't set transfer parameters.\n", 0, 0, 0, 0, 0, 0); return (ERROR); } return (OK); }/********************************************************************************* scsiCtrlMsgInAck - acknowledge an incoming message byte** Call the controller-specific routine to negate the SCSI ACK signal, and* assert the ATN signal if there is a pending message out. Note that the* controller driver must ensure that ATN is asserted, if necessary, before* ACK is negated.** RETURNS: OK, or ERROR if the signals could not be driven as required*/LOCAL STATUS scsiCtrlMsgInAck ( SCSI_CTRL * pScsiCtrl ) { UINT busCommand = SCSI_BUS_NEGATE_ACK; if (pScsiCtrl->msgOutState == SCSI_MSG_OUT_PENDING) { busCommand |= SCSI_BUS_ASSERT_ATN; } if ((*pScsiCtrl->scsiBusControl) (pScsiCtrl, busCommand) != OK) { SCSI_ERROR_MSG ("scsiCtrlMsgInAck: scsiBusControl failed.\n", 0, 0, 0, 0, 0, 0); return (ERROR); } return (OK); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -