📄 aic7880lib.c
字号:
pScsiCtrl->scsiEventProc = (VOIDFUNCPTR) aic7880Event; pScsiCtrl->scsiTransact = (FUNCPTR) scsiTransact; pScsiCtrl->scsiThreadInit = (FUNCPTR) aic7880ThreadInit; pScsiCtrl->scsiThreadAbort = (FUNCPTR) aic7880ThreadAbort; pScsiCtrl->scsiThreadActivate = (FUNCPTR) aic7880ThreadActivate; pScsiCtrl->scsiBusControl = (FUNCPTR) aic7880ScsiBusControl; pScsiCtrl->scsiSpecialHandler = (FUNCPTR) aic7880DummyHandler; pScsiCtrl->scsiXferParamsQuery = (FUNCPTR) aic7880XferParamsQuery; pScsiCtrl->scsiXferParamsSet = (FUNCPTR) aic7880XferParamsSet; pScsiCtrl->scsiWideXferParamsSet = (FUNCPTR) aic7880WideXferParamsSet; /* SCSI Host Adapter supports 16 bit wide bus */ pScsiCtrl->wideXfer = TRUE; /* fill in the generic SCSI info for this controller */ scsiCtrlInit (&aic7880Ctrl->scsiCtrl); pScsiCtrl->scsiMgrId = taskSpawn (aic7880ScsiTaskName, aic7880ScsiTaskPriority, aic7880ScsiTaskOptions, aic7880ScsiTaskStackSize, (FUNCPTR) scsiMgr, (int) aic7880Ctrl, 0, 0, 0, 0, 0, 0, 0, 0, 0); return (aic7880Ctrl); }/********************************************************************************* aic7880ThreadInit - initialize a client thread structure** Initialize the fixed data for a thread. Memory for the SCB (SCSI Command* Block) structure within the thread is allocated and initialized. Memory* for the scatter / gather list structure is also allocated in this routine.* This routine is called once when a thread structure is first created. Memory* for a thread structure is allocated in function scsiThreadArrayCreate in * scsi2Lib.c** RETURNS: OK, or ERROR if memory is unavailable.*/LOCAL STATUS aic7880ThreadInit ( SIOP * pSiop, /* ptr to aic7880 Controller struct */ AIC_7880_THREAD * pThread /* ptr to an aic7880 thread structure */ ) { sp_struct * pScb; SEG_PTR * segPtr; int nBytes; if (scsiThreadInit (&pThread->scsiThread) != OK) return (ERROR); /* allocate a SCSI Command Block structure */ if ((pScb = (sp_struct *) KMEM_ALLOC(sizeof (sp_struct))) == NULL) { SCSI_DEBUG_MSG ("Could not allocate memory for sp_struct\n", 0, 0, 0, 0, 0, 0); return (ERROR); } nBytes = sizeof (sp_struct); bzero ((char *) pScb, nBytes); /* driver can determine which SCSI thread belongs to the SCB */ pScb->pThread = pThread; /* allocate memory for the scatter/gather list */ if ((segPtr = (SEG_PTR *) KMEM_ALLOC(sizeof (SEG_PTR))) == NULL) { SCSI_DEBUG_MSG ("Could not allocate memory for Scatter/Gather list\n", 0, 0, 0, 0, 0, 0); return (ERROR); } /* initialize the thread pointers to the SCB and the scatter/gather list */ pThread->pScb = pScb; pThread->segPtr = segPtr; return (OK); }/********************************************************************************* aic7880ThreadActivate - activate a SCSI connection for an initiator thread** This routine activates the client thread after updating the contents of the* SCB with information needed to execute a SCSI transaction. Cache Coherency* is ensured prior to thread execution. Sync/Wide Xfer parameters are * re-negotiated if neccessary prior to the activation of each thread. * After the SCSI thread has been activated the state of the thread is set to * reflect the current status.** RETURNS: OK or ERROR if unable to activate thread.*/LOCAL STATUS aic7880ThreadActivate ( SIOP * pSiop, /* ptr to controller info */ AIC_7880_THREAD * pThread /* ptr to thread info */ ) { SCSI_CTRL * pScsiCtrl = (SCSI_CTRL *) pSiop; SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_TARGET * pScsiTarget = pScsiThread->pScsiTarget; SCSI_DEBUG_MSG ("aic7880ThreadActivate: thread 0x%08x: activating\n", (int) pThread, 0, 0, 0, 0, 0); scsiCacheSynchronize (pScsiThread, SCSI_CACHE_PRE_COMMAND); aic7880ThreadUpdate (pSiop, pThread); /* * set the thread pointer in the generic SCSI Controller to * point to the thread being activated. */ pScsiCtrl->pThread = pScsiThread; pSiop->pHwThread = pThread; scsiWideXferNegotiate (pScsiCtrl, pScsiTarget, WIDE_XFER_NEW_THREAD); scsiSyncXferNegotiate (pScsiCtrl, pScsiTarget, SYNC_XFER_NEW_THREAD); aic7880Activate (pThread); aic7880ThreadStateSet (pThread, SCSI_THREAD_ESTABLISHED); return (OK); }/********************************************************************************* aic7880ThreadUpdate - update the thread structure for a current SCSI command** This routine fills up the SCB (SCSI Command Block) with the information * needed by the Sequencer to execute a SCSI transaction.** RETURNS: N/A*/LOCAL VOID aic7880ThreadUpdate ( SIOP * pSiop, /* ptr to controller info */ AIC_7880_THREAD * pThread /* thread info */ ) { SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_PHYS_DEV * pScsiPhysDev = pScsiThread->pScsiPhysDev; SCSI_TARGET * pScsiTarget = pScsiThread->pScsiTarget; UINT busId = pScsiTarget->scsiDevBusId; UINT devLun = pScsiPhysDev->scsiDevLUN; sp_struct * pScb; /* pointer to the SCSI Command Block */ pScb = pThread->pScb; /* * fill in the Scatter/Gather list Segment pointer with * the address of the first byte to be transferred and * the length of the data to be transferred during the * data phase of the SCSI command. */ pThread->segPtr->dataPtr = \ AIC_7880_VIRT_TO_PHYS(pScsiThread->dataAddress); pThread->segPtr->dataLen = pScsiThread->dataLength; /* * virtual pointer to the config data structure associated * with the AIC 7880 to which the SCB is loaded. */ pScb->Sp_config.ConfigPtr = (struct cfp *) \ AIC_7880_VIRT_TO_PHYS(pSiop->aic7880CfpStruct); /* internal SCB Access SCSI command */ pScb->Sp_control.Cmd = EXEC_SCB; pScb->SP_Next = 0; pScb->SP_ResCnt = 0; pScb->SP_HaStat = 0; pScb->SP_TargStat = 0; /* disable automatic Req Sense */ pScb->Sp_control.AutoSense = 0; /* do not report underrun as an error */ pScb->Sp_control.NoUnderrun = 1; /* * indicate the specific target/Logical unit for which * the SCB is to be executed. */ pScb->SP_Tarlun = (busId << 4) | devLun; /* * enable or disable disconnects and command queue * tagging. Also set the appropriate tag type */ if ((pScsiThread->tagType == SCSI_TAG_SIMPLE) || (pScsiThread->tagType == SCSI_TAG_ORDERED) || (pScsiThread->tagType == SCSI_TAG_HEAD_OF_Q)) { if (pScsiThread->tagType == SCSI_TAG_SIMPLE) pScb->SP_TagType = SIMPLE_QUEUE_TAG; else if (pScsiThread->tagType == SCSI_TAG_ORDERED) pScb->SP_TagType = ORDERED_QUEUE_TAG; else if (pScsiThread->tagType == SCSI_TAG_HEAD_OF_Q) pScb->SP_TagType = HEAD_OF_QUEUE_TAG; pScb->SP_TagEnable = 1; if (pScsiTarget->disconnect) pScb->SP_DisEnable = 1; else pScb->SP_DisEnable = 0; } else { pScb->SP_TagEnable = 0; pScb->SP_DisEnable = 0; } /* * A value of 1 indicates that the data to be transferred from * host memory is contiguous. In VxWorks since there is a one * to one correspondence between virtual and physical memory and * this field is set to one for all data transfers. */ if (pScsiThread->dataLength) pScb->SP_SegCnt = 1; else pScb->SP_SegCnt = 0; /* * This field indicates to the sequencer whether the data to be * transferred to or from host memory is contiguous. This bit * should be set to one if the SegCnt field is greater than one */ if (pScb->SP_SegCnt > 1) pScb->SP_RejectMDP = 1; else pScb->SP_RejectMDP = 0; pScb->SP_SegPtr = \ AIC_7880_VIRT_TO_PHYS(pThread->segPtr); /* fill in the command descriptor block */ bcopy (pScsiThread->cmdAddress, pScb->Sp_CDB, pScsiThread->cmdLength); /* * set the command length and the command pointer fields to * point to the appropriate SCSI command. */ pScb->SP_CDBLen = (DWORD) pScsiThread->cmdLength; pScb->SP_CDBPtr = AIC_7880_VIRT_TO_PHYS(pScb->Sp_CDB); }/******************************************************************************** aic7880Activate - activate an SCB corresponding to a new thread** This routine activates the SCB corresponding to the new thread and then * calls the HIM function PH_ScbSend with a pointer to the SCB. If the HIM is * busy the SCB is queued for later execution, otherwise it begins execution* of the SCB immediately.** RETURNS: N/A*/LOCAL VOID aic7880Activate ( AIC_7880_THREAD * pThread /* ptr to thread info */ ) { sp_struct * pScb; /* pointer to the SCSI Command Block */ pScb = pThread->pScb; /* send the thread for execution to the Sequencer */ PH_ScbSend (pScb); }/******************************************************************************** aic7880ThreadStateSet - set the state of a thread** This routine sets the state of the current thread. The SCSI Thread* maintains only four states for this driver SCSI_THREAD_WAITING, * SCSI_THREAD_ESTABLISHED, SCSI_THREAD_INACTIVE and SCSI_THREAD_ABORTING. * Disconnects / Reconnects are handled by the Sequencer.** RETURNS: N/A*/LOCAL VOID aic7880ThreadStateSet ( AIC_7880_THREAD * pThread, /* ptr to thread info */ SCSI_THREAD_STATE state /* thread state */ ) { SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_DEBUG_MSG ("aic78800ThreadStateSet: thread 0x%08x: %d -> %d\n", (int) pThread, pScsiThread->state, state, 0, 0, 0); pScsiThread->state = state; }/********************************************************************************* aic7880Intr - interrupt service routine for the SIOP** This routine is invoked when an aic7880 Host Adapter interrupt occurs.* Although most interrupts are due to a Command Completed interrupt, the* Sequencer code could also interrupt the host to handle abnormal SCSI phases* and errors. This routine calls the HIM "PH_IntHandler" routine with the * cfp_struct pointer associated with appropriate AIC-7880 passed in. The HIM* handles the interrupt and returns with a status. The function then issues* an EOI if the returned status from "PH_IntHandler" indicates that it handled* the interrupt. In case of shared IRQ's the returned status may indicate that* no interupt was handled for this host adapter.** RETURNS: N/A.** NOMANUAL*/VOID aic7880Intr ( SIOP * pSiop /* ptr to controller info */ ) { cfp_struct * pCfpStruct; UBYTE intrStatus; pCfpStruct = pSiop->aic7880CfpStruct; intrStatus = PH_IntHandler (pCfpStruct); intrStatus &= INTMASK; /* send EOI (End of Interrupt) signal. */ if (intrStatus) SCSI_DEBUG_MSG ("aic7880Intr pSiop = 0x%lx\n",(int) pSiop, 0, 0, 0, 0, 0); } /********************************************************************************* aic7880ScbCompleted - successfully completed execution of a client thread** This routine is called from within the context of the ISR. The HIM calls* this routine passing in the pointer of the of the completed SCB. This* routine sets the thread status, handles the completed SCB and returns* program control back to the HIM which then returns from the PH_IntHandler * routine.** This routine could be called more than once from the same PH_IntHandler* call. Each call to this routine indicates the completion of an SCB. For* each SCB completed, this routine sets the event type and calls the * appropriate AIC-7880 event handler routines which sets the SCSI Controller,* SCSI Physical Device and SCSI Thread, state variables appropriately.* This routine also handles synchronization with the SCSI Manager so that* the next runnable thread can be scheduled for execution.** RETURNS: N/A**/VOID aic7880ScbCompleted ( sp_struct * pScb /* ptr to completed SCSI Command Block */ ) { AIC_7880_THREAD * pThread = pScb->pThread; SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread; SCSI_THREAD * pSavedThread; SCSI_CTRL * pScsiCtrl = pScsiThread->pScsiCtrl; SIOP * pSiop = (SIOP *) pScsiCtrl; SCSI_EVENT pScsiEvent; BOOL notify = TRUE; DWORD cmdStatus; /* SCB command status */ DWORD haStatus; /* host adapter status */ /* update the status of the SCSI thread */ pScsiThread->status = (STATUS) pScb->SP_TargStat; *pScsiThread->statusAddress = pScsiThread->status; /* save the current H/W thread that may have been activated */ pSavedThread = (SCSI_THREAD *) pSiop->pHwThread; /* * set the generic SCSI C0ntrollers thread to point to the * thread that has just compeleted execution. */ pScsiCtrl->pThread = pScsiThread; /* check the SCB command status */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -