aic7880Lib.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:51k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* aic7880Lib.c - Adaptec 7880 SCSI Host Adapter Library File */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01i,09nov01,pai  added memPartLib header file for Veloce KMEM_ALLOC
  7.                  definition.
  8. 01h,12oct01,dat  merge from ae 1.1
  9. 01g,21nov00,jkf  SPR#62266 T3 doc update
  10. 01f,20jul00,jkf  use KMEM_ALLOC, added a AIC_7880_VIRT_TO_PHYS macro, stop
  11.  logging shared INTs as spurious,log valid INT only.
  12.  SPR#31810, 32101,32102.
  13. 01e,08feb99,fle  doc : removed some .IPs that were wrong here
  14. 01d,19aug98,fle  doc : removed the routine word from the aic7880ReadConfig
  15.                  title line
  16. 01c,14oct97,dds  changed aic7880dFif0ThresholdSet to aic7880dFifoThresholdSet.
  17. 01b,11jul97,dds  added aic7880.h header file.
  18. 01a,10jul97,dds  written.
  19. */
  20. /*
  21. DESCRIPTION:
  22. This is the I/O driver for the Adaptec AIC 7880 PCI Bus Master Single 
  23. Chip SCSI Host Adapter. It is designed to work with scsi2Lib. This driver 
  24. runs in conjunction with the HIM (Hardware Interface Module) supplied by 
  25. Adaptec. The AIC 7880 SCSI Host Adapter driver supports the following features
  26. .iP
  27. Fast, Double Speed 20 MHz data transfers.
  28. .iP
  29. 16 bit Wide Synchronous Data transfers.
  30. .iP
  31. Tagged Command Queueing.
  32. .iP
  33. Data FIFO threshold selection.
  34. .iP
  35. Disconnect / Reconnect support.
  36. .iP
  37. Multiple Initiator support.
  38. .iP
  39. Multiple Controller support.
  40. .lE
  41. In general, the SCSI system and this driver will automatically choose 
  42. the best combination of these features to suit the target devices used. 
  43. However, the default choices may be over-ridden by using the function 
  44. "scsiTargetOptionsSet()" (see scsiLib).
  45. To use this driver, enable the INCLUDE_AIC7880_SCSI component. (VxAE)
  46. OPERATIONS OVERVIEW
  47. The host processor initiates a SCSI I/O operation by programming a data
  48. structure called SCB (SCSI Command Block). The SCB contains all the
  49. relevant information needed by the Host Adapter to carry out the requested
  50. SCSI operation. SCSI SCB's are passed to the HIM by this module which are
  51. then sent to the AIC-7880 for execution. The AIC-7880 Sequencer or PhaseEngine
  52. comprises the on-chip intelligence that allows the AIC-7880 to execute SCB
  53. commands. The Sequencer is programmable and uses its own microcode program 
  54. which is downloaded to AIC-7880 by the host at initialization.
  55. The following is an example of how an SCB is delivered to the AIC-7880
  56. .iP
  57. Memory is allocated for the SCB structure and it is programmed 
  58. with the necessary information required to execute a SCSI 
  59. transaction.
  60. .iP
  61. The SCB is then sent to HIM.
  62. .iP
  63. The HIM pauses the Sequencer.
  64. .iP
  65. The Sequencer has internal registers that point to the area in 
  66. system memory where the SCB resides.
  67. .iP
  68. The HIM unpauses the Sequencer.
  69. .iP
  70. The AIC-7880 Sequencer uses DMA to transfer the SCB into its 
  71. internal memory.
  72. .iP
  73. The AIC-7880 executes the SCB.
  74. .iP
  75. Upon completion of the SCB command, the AIC-7880 Sequencer posts 
  76. the pointer of the completed SCB into system memory.
  77. .iP
  78. The AIC-7880 generates an interupt.
  79. .iP
  80. The status of the completed SCB is then read by the host.
  81. SCB PROCESSING
  82. The AIC-7880 Sequencer uses DMA to transfer the SCB into its internal memory.
  83. The Sequencer processes SCB's in the order they are received with new SCB's 
  84. being started when older SCB operations are idle due to wait for selection 
  85. or a SCSI bus disconnect. When operations for an Idle SCB reactivate, the 
  86. sequencer scans the SCB array for the SCB corresponding to the Target/LUN 
  87. reactivating. The Sequencer then restarts the SCB found until the next 
  88. disconnect or SCB completion.
  89. .SS "MAXIMUM NUMBER OF TAGGED SCB's"
  90. The number of tagged SCB's per SCSI target that is handled by the Sequencer,
  91. range from 1-32. The HIM supports only the External SCB Access mode. The
  92. default number of tags handled by the Sequencer in this mode is 32. Changing
  93. the field "Cf_MaxTagScbs" in the cfp_struct changes the maximum number of 
  94. tagged SCB's.
  95. .SS "MAXIMUM NUMBER OF  SCB's"
  96. The number of SCB's that can be queued to the Sequencer, range from 1-254.
  97. This value can be changed before calling the HIM routine "PH_GetConfig ()".
  98. Changing the field "Cf_NumberScbs" in "cfp_struct" changes the maximum number
  99. of SCB's to be used. The default max number of SCB's is 254. 
  100. SYNCHRONOUS TRANSFER SUPPORT
  101. If double speed SCSI mode is enabled, this driver supports transfer periods
  102. of 50, 64 and 76 ns. In standard fast SCSI mode transfer periods of 100, 125,
  103. 150, 175, 200, 225, 250 and 275 are supported. Synchronous transfer parameters
  104. for a target can be set using the SCSI library function "scsiTargetOptionsSet".
  105. DOUBLE SPEED SCSI MODE
  106. To enable/disable double speed SCSI mode the routine 
  107. "aic7880EnableFast20" needs to be invoked with the following
  108. two parameters:
  109. .IP "(1)" 4
  110. A pointer to the appropriate SCSI Controller structure 
  111. .IP "(2)"
  112. A BOOLEAN value which enables or disable double speed SCSI mode.
  113. .LP
  114. With double speed SCSI mode enabled the host adapter may be capable of 
  115. transferring data at theoritcal transfer rates of 20 MB/s for an 8-bit 
  116. device and 40 MB/s for a 16-bit device. Double Speed SCSI is disabled
  117. by default.
  118. DATA FIFO THRESHOLD
  119. To set the data FIFO threshold the routine "aic7880dFifoThresholdSet"
  120. needs to be invoked with the following two parameters:
  121. .IP "(1)" 4
  122. A pointer to the appropriate SCSI Controller structure
  123. .IP "(2)"
  124. The data FIFO threhold value.
  125. .LP
  126. For more information about the data FIFO threshold value refer the 
  127. aic7880dFifoThresholdSet() routine
  128. In order to initialize the driver from the BSP the following needs to
  129. be done in the BSP specific routine sysScsiInit() in file sysScsi.c.
  130. .iP
  131. Find the SCSI Host Adapter.
  132. .iP
  133. Create the SCSI Controller Structure.
  134. .iP
  135. Connect the interrupt to Interupt Service Routine (ISR).
  136. .iP
  137. Enable the SCSI interupt
  138. .LP
  139. The following example shows the SCSI initialization sequence that need
  140. to be done in the BSP.
  141. .CS
  142. STATUS sysScsiInit ()
  143.     {
  144.     int   busNo;          /@ PCI bus number          @/
  145.     int   devNo;          /@ PCI device number       @/
  146.     UWORD found = FALSE;  /@ host adapter found      @/
  147.     int   numHa = 0;      /@ number of host adapters @/
  148.     for (busNo=0; busNo < MAX_NO_OF_PCI_BUSES && !found; busNo++)
  149.         for (devNo = 0; devNo < MAX_NO_OF_PCI_DEVICES; devNo++)
  150.         {
  151.         if ((found = sysScsiHostAdapterFind (busNo, devNo)) == HA_FOUND)
  152.             {
  153.             numHa++;
  154.             /@ Create the SCSI controller @/
  155.             if ((pSysScsiCtrl = (SCSI_CTRL *) aic7880CtrlCreate
  156.                  (busNo, devNo, SCSI_DEF_CTRL_BUS_ID)) == NULL)
  157.                 {
  158.                 logMsg ("Could not create SCSI controllern",
  159.                          0, 0, 0, 0, 0, 0);
  160.                 return (ERROR);
  161.                 }
  162.             /@ connect the SCSI controller's interrupt service routine @/
  163.             if ((pciIntConnect (INUM_TO_IVEC (SCSI_INT_VEC), aic7880Intr,
  164.                              (int) pSysScsiCtrl)) == ERROR)
  165.                 return (ERROR);
  166.             /@ enable SCSI interupts @/
  167.             sysIntEnablePIC (SCSI_INT_LVL);
  168.             }
  169.     return (OK);
  170.     }
  171. .CE
  172. SEE ALSO: scsiLib, scsi2Lib, cacheLib,
  173. .I "AIC-7880 Design In Handbook,"
  174. .I "AIC-7880 Data Book,"
  175. .I "Adaptec Hardware Interface Module (HIM) Specification,"
  176. .pG "I/O System"
  177. */
  178. #include "vxWorks.h"
  179. #include "memLib.h"
  180. #include "memPartLib.h"
  181. #include "ctype.h"
  182. #include "stdlib.h"
  183. #include "string.h"
  184. #include "stdio.h"
  185. #include "logLib.h"
  186. #include "semLib.h"
  187. #include "intLib.h"
  188. #include "errnoLib.h"
  189. #include "cacheLib.h"
  190. #include "taskLib.h"
  191. #include "drv/scsi/him/him_scb.h"
  192. #include "drv/scsi/aic7880.h"
  193. #include "drv/scsi/him/him_equ.h"
  194. #include "drv/scsi/him/seq_off.h"
  195. #include "drv/scsi/him/sequence.h"
  196. #include "drv/scsi/him/him_rel.h"
  197. #include "him/him_init.c"
  198. #include "him/him.c"
  199. #include "him/himd.c"
  200. #include "him/himdinit.c"
  201. #include "him/himdiopt.c"
  202. #include "him/himdopt.c"
  203. #define SIOP_MAX_XFER_LENGTH    ((UINT) (0x00ffffff))
  204. #define AIC_7880_VIRT_TO_PHYS(x) 
  205. ((UINT)CACHE_DMA_VIRT_TO_PHYS(x))
  206. typedef AIC_7880_SCSI_CTRL SIOP;
  207. int himDebug = 0;
  208. /* globals */
  209. AIC_7880_SCSI_CTRL * sysScsiCtrl;
  210. char * aic7880ScsiTaskName      = SCSI_DEF_TASK_NAME;
  211. int    aic7880ScsiTaskOptions   = SCSI_DEF_TASK_OPTIONS;
  212. int    aic7880ScsiTaskPriority  = SCSI_DEF_TASK_PRIORITY;
  213. int    aic7880ScsiTaskStackSize = SCSI_DEF_TASK_STACK_SIZE;
  214. IMPORT void PH_ScbSend (sp_struct *);
  215. IMPORT VOIDFUNCPTR intEOI;            /* pointer to function sysIntEOI() */
  216. /* function declarations */
  217. VOID   aic7880EnableFast20         (SCSI_CTRL * pScsiCtrl, BOOL enable);
  218. VOID   aic7880ScbCompleted         (sp_struct * pScb);
  219. STATUS aic7880dFifoThresholdSet    (SCSI_CTRL * pScsiCtrl, UBYTE threshHold);
  220. DWORD  aic7880ReadConfig           (cfp_struct * configPtr, UBYTE busNo,
  221.     UBYTE devNo, UBYTE regNo);
  222. DWORD  aic7880WriteConfig          (cfp_struct * configPtr, UBYTE busNo, 
  223.     UBYTE devNo, UBYTE regNo, DWORD regVal);
  224. DWORD aic7880GetNumOfBuses         ();
  225. LOCAL STATUS aic7880ThreadInit     (SIOP * pSiop, AIC_7880_THREAD * pThread);
  226. LOCAL BOOL aic7880ThreadAbort      (SIOP * pSiop, AIC_7880_THREAD * pThread);
  227. LOCAL STATUS aic7880ThreadActivate (SIOP *pSiop, AIC_7880_THREAD * pThread);
  228. LOCAL VOID   aic7880ThreadUpdate   (SIOP *pSiop, AIC_7880_THREAD * pThread);
  229. LOCAL VOID   aic7880Activate       (AIC_7880_THREAD * pThread);
  230. LOCAL VOID   aic7880ThreadComplete (AIC_7880_THREAD * pThread);
  231. LOCAL VOID   aic7880ThreadFail     (AIC_7880_THREAD * pThread, int errNum);
  232. LOCAL VOID   aic7880Event          (SIOP * pSiop, SCSI_EVENT * pScsiEvent);
  233. LOCAL VOID   aic7880InitEvent      (AIC_7880_THREAD * pThread,
  234.                                     SCSI_EVENT * pScsiEvent);
  235. LOCAL VOID   aic7880ThreadEvent    (AIC_7880_THREAD * pThread,
  236.     SCSI_EVENT * pScsiEvent);
  237. LOCAL VOID   aic7880ThreadStateSet (AIC_7880_THREAD * pThread,
  238.     SCSI_THREAD_STATE state);
  239. LOCAL VOID   aic7880DummyHandler ();
  240. LOCAL STATUS aic7880ScsiBusControl (SIOP * pSiop, int operation);
  241. LOCAL VOID   aic7880XferParamsCvt  (SIOP * pSiop, UINT8 * pOffset,
  242.     UINT8 * pPeriod, UINT8 * pXferRate);
  243. LOCAL STATUS aic7880XferParamsSet  (SCSI_CTRL * pScsiCtrl, UINT8 offset,
  244.     UINT8  period);
  245. LOCAL STATUS aic7880ThreadParamsSet   (AIC_7880_THREAD * pThread, UINT8 offset,
  246.        UINT8 period);
  247. LOCAL STATUS aic7880WideXferParamsSet (SCSI_CTRL * pScsiCtrl, UINT8 xferWidth);
  248. LOCAL STATUS aic7880XferParamsQuery   (SCSI_CTRL * pScsiCtrl, UINT8 * pOffset, 
  249.        UINT8 *pPeriod);
  250. /*******************************************************************************
  251. *
  252. * aic7880CtrlCreate - create a control structure for the AIC 7880
  253. *
  254. * This routine creates an AIC_7880_SCSI_CTRL structure and must be called 
  255. * before using the SCSI Host Adapter chip. It must be called exactly once for 
  256. * a specified Host Adapter. 
  257. *
  258. * RETURNS: A pointer to the AIC_7880_SCSI_CTRL structure, or NULL if memory
  259. * is unavailable or there are invalid parameters.
  260. */
  261. AIC_7880_SCSI_CTRL * aic7880CtrlCreate 
  262.     (
  263.     int busNo,        /* PCI bus Number */
  264.     int devNo,        /* PCI device Number */
  265.     int scsiBusId     /* SCSI Host Adapter Bus Id */
  266.     )
  267.     {
  268.     cfp_struct         * pCfpStruct;   /* ptr to HA confiuration struct    */
  269.     AIC_7880_SCSI_CTRL * aic7880Ctrl;  /* ptr to aic7880 Controller struct */
  270.     SCSI_CTRL          * pScsiCtrl;    /* ptr to generic SCSI Controller   */
  271.     int                  nBytes;       /* number of bytes                  */
  272.     int                  status;       /* status information               */
  273.     int                  i;
  274.     /* create the generic SCSI controller structure */
  275.     if ((aic7880Ctrl = (AIC_7880_SCSI_CTRL *) 
  276. KMEM_ALLOC((sizeof (AIC_7880_SCSI_CTRL)))) == NULL)
  277. {
  278. SCSI_DEBUG_MSG ("Could not allocate memory for SCSI controllen",
  279.        0, 0, 0, 0, 0, 0);
  280. return (NULL);
  281. }
  282.     
  283.     /* create the host adapter configuration structure */
  284.     if ((pCfpStruct = (cfp_struct *)KMEM_ALLOC(sizeof (cfp_struct))) == NULL)
  285.         {
  286. SCSI_DEBUG_MSG ("Could not allocate HIM configuration structuren",
  287.        0, 0, 0, 0, 0, 0);
  288.         return (NULL);
  289.         }
  290.     nBytes = sizeof (cfp_struct);
  291.     bzero ((char *) pCfpStruct, nBytes);
  292.     /* 
  293.      * the bus number and the device number are required by the
  294.      * HIM before the call to "PH_GetConfig".
  295.      */
  296.     pCfpStruct->Cf_BusNumber    = busNo;
  297.     pCfpStruct->Cf_DeviceNumber = devNo;
  298.     /* 
  299.      * Get host adapter configuration information for cfp struct.
  300.      * Upon return the pCfpStruct contains the AIC-7880 host adapter
  301.      * configuration information. (e.g. base address, Id, rev level etc.)
  302.      */
  303.     PH_GetConfig (pCfpStruct);
  304.     aic7880Ctrl->aic7880CfpStruct = pCfpStruct;
  305.     sysScsiCtrl = aic7880Ctrl;
  306.     /* allocate memory for the host adapter data structure */
  307.     nBytes = pCfpStruct->Cf_HimDataSize;
  308.     if ((pCfpStruct->CFP_HaDataPtr = 
  309. (hsp_struct *) KMEM_ALLOC(nBytes * sizeof (char))) == NULL)
  310. SCSI_DEBUG_MSG ("Could not allocate memory HIM data structuren",
  311.        0, 0, 0, 0, 0, 0);
  312.     /* 
  313.      * virtual and physical pointers to the host adapter data structure
  314.      * are the same. 
  315.      */
  316.     pCfpStruct->Cf_HaDataPhy = 
  317. AIC_7880_VIRT_TO_PHYS (pCfpStruct->CFP_HaDataPtr);
  318.     /* 
  319.      * Initialize the SCSI Host adapter, by reseting the SCSI bus and
  320.      * suppressing wide/sync data transfer negotiations initially.
  321.      */
  322.     pCfpStruct->CFP_InitNeeded = TRUE;
  323.     pCfpStruct->CFP_ResetBus = TRUE;
  324.     pCfpStruct->CFP_SuppressNego = TRUE;
  325.     pCfpStruct->Cf_ScsiId = scsiBusId;
  326.     /* 
  327.      * "PH_InitHA" initializes the SCSI Host Adapter, pauses the sequencer
  328.      * and  downloads the sequencer code to sequencer RAM which resides on 
  329.      * the AIC-7880. The sequencer code is then un-paused and the AIC-7880
  330.      * Host Adapter interupt is enabled.
  331.      */
  332.     if ((status = PH_InitHA (pCfpStruct)) == 0)
  333. SCSI_DEBUG_MSG ("Host Adapter Initialization Successfuln",
  334.        0, 0, 0, 0, 0, 0);
  335.     /* initialize the negotiation options for each target */
  336.     for (i = 0; i < pCfpStruct->Cf_MaxTargets; i++)
  337.         pCfpStruct->Cf_ScsiOption [i] = 0;
  338.     pScsiCtrl = (SCSI_CTRL *) aic7880Ctrl;
  339.     /* validate and set bus ID */    
  340.     pScsiCtrl->scsiCtrlBusId = pCfpStruct->Cf_ScsiId;
  341.     pScsiCtrl->eventSize  = sizeof (SCSI_EVENT);
  342.     pScsiCtrl->threadSize = sizeof (AIC_7880_THREAD);
  343.     pScsiCtrl->maxBytesPerXfer = SIOP_MAX_XFER_LENGTH;
  344.     /* fill in virtual functions used by SCSI library */
  345.     pScsiCtrl->scsiEventProc       = (VOIDFUNCPTR) aic7880Event;
  346.     pScsiCtrl->scsiTransact        = (FUNCPTR)     scsiTransact;
  347.     pScsiCtrl->scsiThreadInit      = (FUNCPTR)     aic7880ThreadInit;
  348.     pScsiCtrl->scsiThreadAbort     = (FUNCPTR)     aic7880ThreadAbort;
  349.     pScsiCtrl->scsiThreadActivate  = (FUNCPTR)     aic7880ThreadActivate;
  350.     pScsiCtrl->scsiBusControl      = (FUNCPTR)     aic7880ScsiBusControl;
  351.     pScsiCtrl->scsiSpecialHandler  = (FUNCPTR)     aic7880DummyHandler;
  352.     pScsiCtrl->scsiXferParamsQuery = (FUNCPTR)     aic7880XferParamsQuery;
  353.     pScsiCtrl->scsiXferParamsSet   = (FUNCPTR)     aic7880XferParamsSet;
  354.     pScsiCtrl->scsiWideXferParamsSet   = (FUNCPTR) aic7880WideXferParamsSet;
  355.     /* SCSI Host Adapter supports 16 bit wide bus */
  356.     pScsiCtrl->wideXfer = TRUE;
  357.     /* fill in the generic SCSI info for this controller */
  358.     scsiCtrlInit (&aic7880Ctrl->scsiCtrl); 
  359.     pScsiCtrl->scsiMgrId = taskSpawn (aic7880ScsiTaskName,
  360.                                       aic7880ScsiTaskPriority,
  361.                                       aic7880ScsiTaskOptions,
  362.                                       aic7880ScsiTaskStackSize,
  363.                                       (FUNCPTR) scsiMgr,
  364.                                       (int) aic7880Ctrl,
  365.       0, 0, 0, 0, 0, 0, 0, 0, 0); 
  366.     return (aic7880Ctrl);
  367.     }
  368. /*******************************************************************************
  369. *
  370. * aic7880ThreadInit - initialize a client thread structure
  371. *
  372. * Initialize the fixed data for a thread. Memory for the SCB (SCSI Command
  373. * Block) structure within the thread is allocated and initialized. Memory
  374. * for the scatter / gather  list structure is also allocated in this routine.
  375. * This routine is called once when a thread structure is first created. Memory
  376. * for a thread structure is allocated in function scsiThreadArrayCreate in 
  377. * scsi2Lib.c
  378. *
  379. * RETURNS: OK, or ERROR if memory is unavailable.
  380. */
  381. LOCAL STATUS aic7880ThreadInit
  382.     (
  383.     SIOP            * pSiop,   /* ptr to aic7880 Controller struct */
  384.     AIC_7880_THREAD * pThread  /* ptr to an aic7880 thread structure */
  385.     )
  386.     {
  387.     sp_struct * pScb;
  388.     SEG_PTR   * segPtr;
  389.     int nBytes;
  390.     if (scsiThreadInit (&pThread->scsiThread) != OK)
  391.         return (ERROR);
  392.     /* allocate a SCSI Command Block structure */
  393.     if ((pScb = (sp_struct *) KMEM_ALLOC(sizeof (sp_struct))) == NULL)
  394.         {
  395.         SCSI_DEBUG_MSG ("Could not allocate memory for sp_structn",
  396.        0, 0, 0, 0, 0, 0);
  397.         return (ERROR);
  398.         }
  399.     nBytes = sizeof (sp_struct);
  400.     bzero ((char *) pScb, nBytes);
  401.     /* driver can determine which SCSI thread belongs to the SCB */
  402.  
  403.     pScb->pThread = pThread;
  404.     /* allocate memory for the scatter/gather list */
  405.     if ((segPtr = (SEG_PTR *) KMEM_ALLOC(sizeof (SEG_PTR))) == NULL)
  406. {
  407. SCSI_DEBUG_MSG ("Could not allocate memory for Scatter/Gather listn",
  408.                        0, 0, 0, 0, 0, 0);
  409.         return (ERROR);
  410.         }
  411.     /* initialize the thread pointers to the SCB and the scatter/gather list */
  412.     pThread->pScb = pScb;
  413.     pThread->segPtr = segPtr;
  414.     return (OK);
  415.     }
  416. /*******************************************************************************
  417. *
  418. * aic7880ThreadActivate - activate a SCSI connection for an initiator thread
  419. *
  420. * This routine activates the client thread after updating the contents of the
  421. * SCB with information needed to execute a SCSI transaction. Cache Coherency
  422. * is ensured prior to thread execution. Sync/Wide Xfer parameters are 
  423. * re-negotiated if neccessary prior to the activation of each thread. 
  424. * After the SCSI thread has been activated the state of the thread is set to 
  425. * reflect the current status.
  426. *
  427. * RETURNS: OK or ERROR if unable to activate thread.
  428. */
  429. LOCAL STATUS aic7880ThreadActivate
  430.     (
  431.     SIOP            * pSiop,            /* ptr to controller info */
  432.     AIC_7880_THREAD * pThread           /* ptr to thread info     */
  433.     )
  434.     {
  435.     SCSI_CTRL   * pScsiCtrl   = (SCSI_CTRL *)   pSiop;
  436.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  437.     SCSI_TARGET * pScsiTarget  = pScsiThread->pScsiTarget;
  438.     SCSI_DEBUG_MSG ("aic7880ThreadActivate: thread 0x%08x: activatingn",
  439.                     (int) pThread, 0, 0, 0, 0, 0);
  440.     scsiCacheSynchronize (pScsiThread, SCSI_CACHE_PRE_COMMAND);
  441.     aic7880ThreadUpdate (pSiop, pThread);
  442.     /* 
  443.      * set the thread pointer in the generic SCSI Controller to 
  444.      * point to the thread being activated.
  445.      */
  446.     pScsiCtrl->pThread = pScsiThread;
  447.     pSiop->pHwThread   = pThread;
  448.     scsiWideXferNegotiate (pScsiCtrl, pScsiTarget, WIDE_XFER_NEW_THREAD);
  449.     scsiSyncXferNegotiate (pScsiCtrl, pScsiTarget, SYNC_XFER_NEW_THREAD); 
  450.     aic7880Activate (pThread);
  451.     aic7880ThreadStateSet (pThread, SCSI_THREAD_ESTABLISHED);
  452.     return (OK);
  453.     }
  454. /*******************************************************************************
  455. *
  456. * aic7880ThreadUpdate - update the thread structure for a current SCSI command
  457. *
  458. * This routine fills up the SCB (SCSI Command Block) with the information 
  459. * needed by the Sequencer to execute a SCSI transaction.
  460. *
  461. * RETURNS: N/A
  462. */
  463. LOCAL VOID aic7880ThreadUpdate 
  464.     (
  465.     SIOP            * pSiop,     /* ptr to controller info */
  466.     AIC_7880_THREAD * pThread    /* thread info */
  467.     )
  468.     {
  469.     SCSI_THREAD   * pScsiThread  = (SCSI_THREAD *) pThread;
  470.     SCSI_PHYS_DEV * pScsiPhysDev = pScsiThread->pScsiPhysDev;
  471.     SCSI_TARGET   * pScsiTarget  = pScsiThread->pScsiTarget;
  472.     UINT            busId        = pScsiTarget->scsiDevBusId;
  473.     UINT            devLun       = pScsiPhysDev->scsiDevLUN;
  474.     sp_struct * pScb;   /* pointer to the SCSI Command Block */
  475.     pScb = pThread->pScb; 
  476.     /*
  477.      * fill in the Scatter/Gather list Segment pointer with 
  478.      * the address of the first byte to be transferred and
  479.      * the length of the data to be transferred during the
  480.      * data phase of the SCSI command.
  481.      */
  482.     pThread->segPtr->dataPtr = 
  483. AIC_7880_VIRT_TO_PHYS(pScsiThread->dataAddress);
  484.     pThread->segPtr->dataLen = pScsiThread->dataLength;
  485.     /* 
  486.      * virtual pointer to the config data structure associated
  487.      * with the AIC 7880 to which the SCB is loaded.
  488.      */
  489.     
  490.     pScb->Sp_config.ConfigPtr = (struct cfp *) 
  491. AIC_7880_VIRT_TO_PHYS(pSiop->aic7880CfpStruct);
  492.     /* internal SCB Access SCSI command */
  493.     pScb->Sp_control.Cmd = EXEC_SCB; 
  494.     pScb->SP_Next     = 0;
  495.     pScb->SP_ResCnt   = 0;
  496.     pScb->SP_HaStat   = 0;
  497.     pScb->SP_TargStat = 0;
  498.     /* disable automatic Req Sense */
  499.     pScb->Sp_control.AutoSense = 0;
  500.     /* do not report underrun as an error */
  501.     pScb->Sp_control.NoUnderrun = 1;
  502.     /*
  503.      * indicate the specific target/Logical unit for which
  504.      * the SCB is to be executed.
  505.      */
  506.     pScb->SP_Tarlun = (busId << 4) | devLun;
  507.     /* 
  508.      * enable or disable disconnects and command queue 
  509.      * tagging. Also set the appropriate tag type 
  510.      */
  511.     if ((pScsiThread->tagType == SCSI_TAG_SIMPLE) ||
  512. (pScsiThread->tagType == SCSI_TAG_ORDERED) ||
  513. (pScsiThread->tagType == SCSI_TAG_HEAD_OF_Q))
  514. {
  515. if (pScsiThread->tagType == SCSI_TAG_SIMPLE)
  516.     pScb->SP_TagType = SIMPLE_QUEUE_TAG;
  517. else if (pScsiThread->tagType == SCSI_TAG_ORDERED)
  518.     pScb->SP_TagType = ORDERED_QUEUE_TAG;
  519. else if (pScsiThread->tagType == SCSI_TAG_HEAD_OF_Q)
  520.     pScb->SP_TagType = HEAD_OF_QUEUE_TAG;
  521. pScb->SP_TagEnable = 1;
  522. if (pScsiTarget->disconnect)
  523.     pScb->SP_DisEnable = 1;
  524. else
  525.     pScb->SP_DisEnable = 0;
  526. }
  527.     else
  528. {
  529. pScb->SP_TagEnable = 0;
  530.         pScb->SP_DisEnable = 0;
  531. }
  532.     /* 
  533.      * A value of 1 indicates that the data to be transferred from
  534.      * host memory is contiguous. In VxWorks since there is a one 
  535.      * to one correspondence between virtual and physical memory and
  536.      * this field is set to one for all data transfers.
  537.      */
  538.     if (pScsiThread->dataLength)
  539. pScb->SP_SegCnt = 1;
  540.     else
  541. pScb->SP_SegCnt = 0;
  542.     /* 
  543.      * This field indicates to the sequencer whether the data to be
  544.      * transferred to or from host memory is contiguous. This bit
  545.      * should be set to one if the SegCnt field is greater than one
  546.      */
  547.     if (pScb->SP_SegCnt > 1)
  548. pScb->SP_RejectMDP = 1;
  549.     else
  550. pScb->SP_RejectMDP = 0;
  551.     pScb->SP_SegPtr = 
  552. AIC_7880_VIRT_TO_PHYS(pThread->segPtr);
  553.     /* fill in the command descriptor block */
  554.     bcopy (pScsiThread->cmdAddress, pScb->Sp_CDB, pScsiThread->cmdLength);
  555.     /* 
  556.      * set the command length and the command pointer fields to 
  557.      * point to the appropriate SCSI command.
  558.      */
  559.     pScb->SP_CDBLen = (DWORD) pScsiThread->cmdLength;
  560.     pScb->SP_CDBPtr = AIC_7880_VIRT_TO_PHYS(pScb->Sp_CDB);
  561.     }
  562. /******************************************************************************
  563. *
  564. * aic7880Activate - activate an SCB corresponding to a new thread
  565. *
  566. * This routine activates the SCB corresponding to the new thread and then 
  567. * calls the HIM function PH_ScbSend with a pointer to the SCB. If the HIM is 
  568. * busy the SCB is queued for later execution, otherwise it begins execution
  569. * of the SCB immediately.
  570. *
  571. * RETURNS: N/A
  572. */
  573. LOCAL VOID aic7880Activate
  574.     (
  575.     AIC_7880_THREAD * pThread  /* ptr to thread info */
  576.     )
  577.     {
  578.     sp_struct * pScb;   /* pointer to the SCSI Command Block */
  579.     pScb = pThread->pScb;
  580.     /* send the thread for execution to the Sequencer */
  581.     PH_ScbSend (pScb);
  582.     }
  583. /******************************************************************************
  584. *
  585. * aic7880ThreadStateSet - set the state of a thread
  586. *
  587. * This routine sets the state of the current thread. The SCSI Thread
  588. * maintains only four states for this driver SCSI_THREAD_WAITING, 
  589. * SCSI_THREAD_ESTABLISHED, SCSI_THREAD_INACTIVE and SCSI_THREAD_ABORTING. 
  590. * Disconnects / Reconnects are handled by the Sequencer.
  591. *
  592. * RETURNS: N/A
  593. */
  594. LOCAL VOID aic7880ThreadStateSet
  595.     (
  596.     AIC_7880_THREAD   *  pThread,          /* ptr to thread info */
  597.     SCSI_THREAD_STATE    state             /* thread state */
  598.     )
  599.     {
  600.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  601.     SCSI_DEBUG_MSG ("aic78800ThreadStateSet: thread 0x%08x: %d -> %dn",
  602.                     (int) pThread, pScsiThread->state, state, 0, 0, 0);
  603.     pScsiThread->state = state;
  604.     }
  605. /*******************************************************************************
  606. *
  607. * aic7880Intr - interrupt service routine for the SIOP
  608. *
  609. * This routine is invoked when an aic7880 Host Adapter interrupt occurs.
  610. * Although most interrupts are due to a Command Completed interrupt, the
  611. * Sequencer code could also interrupt the host to handle abnormal SCSI phases
  612. * and errors. This routine calls the HIM "PH_IntHandler" routine with the 
  613. * cfp_struct pointer associated with appropriate AIC-7880 passed in. The HIM
  614. * handles the interrupt and returns with a status. The function then issues
  615. * an EOI if the returned status from "PH_IntHandler" indicates that it handled
  616. * the interrupt. In case of shared IRQ's the returned status may indicate that
  617. * no interupt was handled for this host adapter.
  618. *
  619. * RETURNS: N/A.
  620. *
  621. * NOMANUAL
  622. */
  623. VOID aic7880Intr 
  624.     (
  625.     SIOP * pSiop    /* ptr to controller info */
  626.     )
  627.     {
  628.     cfp_struct      * pCfpStruct;
  629.     UBYTE             intrStatus;
  630.     pCfpStruct = pSiop->aic7880CfpStruct;
  631.     intrStatus = PH_IntHandler (pCfpStruct);
  632.     intrStatus &= INTMASK;
  633.     /* send  EOI (End of Interrupt) signal. */
  634.      if (intrStatus)
  635. SCSI_DEBUG_MSG ("aic7880Intr pSiop = 0x%lxn",(int) pSiop, 
  636. 0, 0, 0, 0, 0);
  637.     }    
  638. /*******************************************************************************
  639. *
  640. * aic7880ScbCompleted - successfully completed execution of a client thread
  641. *
  642. * This routine is called from within the context of the ISR. The HIM calls
  643. * this routine passing in the pointer of the of the completed SCB. This
  644. * routine sets the thread status, handles the completed SCB and returns
  645. * program control back to the HIM which then returns from the PH_IntHandler 
  646. * routine.
  647. *
  648. * This routine could be called more than once from the same PH_IntHandler
  649. * call. Each call to this routine indicates the completion of an SCB. For
  650. * each SCB completed, this routine sets the event type and calls the 
  651. * appropriate AIC-7880 event handler routines which sets the SCSI Controller,
  652. * SCSI Physical Device and SCSI Thread, state variables appropriately.
  653. * This routine also handles synchronization with the SCSI Manager so that
  654. * the next runnable thread can be scheduled for execution.
  655. *
  656. * RETURNS: N/A
  657. *
  658. */
  659. VOID aic7880ScbCompleted 
  660.     (
  661.     sp_struct * pScb  /* ptr to completed SCSI Command Block */
  662.     )
  663.     {
  664.     AIC_7880_THREAD * pThread = pScb->pThread;
  665.     SCSI_THREAD     * pScsiThread = (SCSI_THREAD *) pThread;
  666.     SCSI_THREAD     * pSavedThread;
  667.     SCSI_CTRL       * pScsiCtrl = pScsiThread->pScsiCtrl;
  668.     SIOP            * pSiop = (SIOP *) pScsiCtrl;
  669.     SCSI_EVENT        pScsiEvent;
  670.     BOOL              notify    = TRUE;
  671.     DWORD             cmdStatus;         /* SCB command status */
  672.     DWORD             haStatus;          /* host adapter status */
  673.     /* update the status of the SCSI thread */
  674.     pScsiThread->status = (STATUS) pScb->SP_TargStat;
  675.     *pScsiThread->statusAddress = pScsiThread->status;
  676.     /* save the current H/W thread that may have been activated */
  677.     
  678.     pSavedThread = (SCSI_THREAD *) pSiop->pHwThread;
  679.     /* 
  680.      * set the generic SCSI C0ntrollers thread to point to the
  681.      * thread that has just compeleted execution. 
  682.      */
  683.     pScsiCtrl->pThread = pScsiThread;
  684.     
  685.     /* check the SCB command status */
  686.     
  687.     cmdStatus = pScb->SP_Stat;
  688.     switch (cmdStatus) 
  689. {
  690. case AIC_7880_CMD_COMPLETE:
  691.     pScsiEvent.type = AIC_7880_CMD_COMPLETE;
  692.             break;
  693.     
  694.         case AIC_7880_CMD_COMP_WITH_ERROR:
  695.     haStatus = pScb->SP_HaStat;
  696.     switch (haStatus)
  697. {
  698. case AIC_7880_NO_STATUS:
  699.     SCSI_DEBUG_MSG ("No Statusn", 0, 0, 0, 0, 0, 0);
  700.     pScsiEvent.type = AIC_7880_CMD_COMPLETE;
  701.     break;
  702. case AIC_7880_CMD_ABORT:
  703. case AIC_7880_CMD_ABORT_BY_HA:
  704.     SCSI_DEBUG_MSG ("SCSI Command Abortn", 0,0,0,0,0,0);
  705.     pScsiEvent.type = AIC_7880_CMD_COMPLETE;
  706.     break;
  707. case AIC_7880_UNEXPECTED_BUS_FREE:
  708.     SCSI_DEBUG_MSG ("Unexpected Bus Freen", 0,0,0,0,0,0);
  709.     pScsiEvent.type = AIC_7880_SCSI_BUS_RESET;
  710.     break;
  711. case AIC_7880_PHASE_MISMATCH:
  712.     SCSI_DEBUG_MSG ("Phase Mismatch occuredn", 0,0,0,0,0,0);
  713.     pScsiEvent.type = AIC_7880_SCSI_BUS_RESET;
  714.     break;
  715. case AIC_7880_HA_HW_ERROR:
  716.     SCSI_DEBUG_MSG ("Host Adapter H/W errorn", 0,0,0,0,0,0);
  717.     pScsiEvent.type = AIC_7880_SCSI_BUS_RESET;
  718.     break;
  719.   
  720. case AIC_7880_BUS_RESET:
  721. case AIC_7880_BUS_RESET_OTHER_DEV:
  722.     SCSI_DEBUG_MSG ("SCSI Bus Resetn", 0,0,0,0,0,0);
  723.     pScsiEvent.type = AIC_7880_SCSI_BUS_RESET;
  724.     break;
  725. case AIC_7880_SELECT_TIMEOUT:
  726.     SCSI_DEBUG_MSG ("Device Selction Timeoutn", 0,0,0,0,0,0);
  727.     pScsiEvent.type = AIC_7880_SELECT_TIMEOUT;
  728.     break;
  729. case AIC_7880_REQ_SENSE_FAILED:
  730.     SCSI_DEBUG_MSG ("Request Sense Failedn",0,0,0,0,0,0);
  731.     notify = FALSE;
  732.     break;
  733. default:
  734.     SCSI_DEBUG_MSG ("aic7880Intr: unexpt'd host adap'r intrn",
  735.    0,0,0,0,0,0);
  736.     break;
  737. }
  738.     break;
  739.     
  740. default:
  741.     notify = FALSE;
  742.             SCSI_DEBUG_MSG ("aic7880ScbCompleted: unexpected interuptn", 
  743.     0, 0, 0, 0, 0, 0); 
  744.             break; 
  745.         }
  746.     if (notify)
  747. {
  748. aic7880Event (pSiop, &pScsiEvent);
  749. semGive (pScsiCtrl->actionSem);
  750. }
  751.     
  752.     /* restore the current H/W thread */
  753.     pScsiCtrl->pThread = pSavedThread;
  754.     }
  755. /*******************************************************************************
  756. *
  757. * aic7880Event - AIC 788 SCSI controller event processing routine
  758. *
  759. * Parse the event type and act accordingly.  Controller-level events are
  760. * handled within this function, and the event is then passed to the completed
  761. * thread for thread-level processing. The SCSI Controllers state variables
  762. * are set to indicate if the controller is connected or disconnected. When
  763. * a thread is activated the Controllers state is set to CONNECTED and when
  764. * the thread has completed execution or if a SCSI Bus Reset has occured the
  765. * Controllers state is set to DISCONNECTED.
  766. *
  767. * RETURNS: N/A
  768. */
  769. LOCAL VOID aic7880Event
  770.     (
  771.     SIOP       * pSiop,         /* ptr to controller info */
  772.     SCSI_EVENT * pScsiEvent     /* ptr to SCSI EVENT      */
  773.     )
  774.     {
  775.     SCSI_CTRL       * pScsiCtrl  = (SCSI_CTRL *)  pSiop;
  776.     AIC_7880_THREAD * pThread    = (AIC_7880_THREAD *) pScsiCtrl->pThread;
  777.     SCSI_DEBUG_MSG ("aic7880Event: received event %d (thread = 0x%08x)n",
  778.                      pScsiEvent->type, (int) pThread, 0, 0, 0, 0);
  779.     switch (pScsiEvent->type)
  780. {
  781. case AIC_7880_CMD_COMPLETE:
  782. case AIC_7880_SELECT_TIMEOUT:
  783.             pScsiCtrl->peerBusId = NONE;
  784.             pScsiCtrl->pThread   = 0;
  785.             scsiMgrCtrlEvent (pScsiCtrl, SCSI_EVENT_DISCONNECTED);
  786.             break;
  787.         case AIC_7880_SCSI_BUS_RESET:
  788.             pScsiCtrl->peerBusId = NONE;
  789.             pScsiCtrl->pThread   = 0;
  790.             scsiMgrBusReset (pScsiCtrl);
  791.             break;
  792.     
  793.         default:
  794.     logMsg ("aic7880Event: invalid event type.n", 0, 0, 0, 0, 0, 0);
  795.             break;
  796. }
  797.     /* If there's a thread on the controller, forward the event to it */
  798.     if (pThread != 0)
  799.         aic7880ThreadEvent (pThread, pScsiEvent);
  800.     }
  801. /*******************************************************************************
  802. *
  803. * aic7880ThreadEvent - AIC 7880 thread event processing routine
  804. *
  805. * Forward the event to the proper handler for the thread's current role.
  806. *
  807. * RETURNS: N/A
  808. */
  809. LOCAL VOID aic7880ThreadEvent
  810.     (
  811.     AIC_7880_THREAD * pThread,    /* ptr to aci7880 thread info */
  812.     SCSI_EVENT      * pScsiEvent  /* ptr to SCSI EVENT */
  813.     )
  814.     {
  815.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  816.     switch (pScsiThread->role)
  817.         {
  818.         case SCSI_ROLE_INITIATOR:
  819.             aic7880InitEvent (pThread, pScsiEvent);
  820.             break;
  821.         default:
  822.             logMsg ("aic7880ThreadEvent: thread 0x%08x: invalid role (%d)n",
  823.                     (int) pThread, pScsiThread->role, 0, 0, 0, 0);
  824.             break;
  825. }
  826.     }
  827. /*******************************************************************************
  828. *
  829. * aic7880InitEvent - AIC 7880 initiator thread event processing routine
  830. *
  831. * Parse the event type and handle it accordingly.  This may result in state
  832. * changes for the thread, state variables being updated, etc.
  833. *
  834. * RETURNS: N/A
  835. */
  836. LOCAL VOID aic7880InitEvent
  837.     (
  838.     AIC_7880_THREAD * pThread,    /* ptr to aci7880 thread info */
  839.     SCSI_EVENT      * pScsiEvent  /* ptr to SCSI EVENT */
  840.     )
  841.     {
  842.     switch (pScsiEvent->type)
  843. {
  844.         case AIC_7880_CMD_COMPLETE:
  845.             aic7880ThreadComplete (pThread);
  846.             break;
  847. case AIC_7880_SELECT_TIMEOUT:
  848.             SCSI_ERROR_MSG ("aic7880InitEvent: thread 0x%08x: timeout.n",
  849.                             (int) pThread, 0, 0, 0, 0, 0);
  850.     
  851.     aic7880ThreadFail (pThread, S_scsiLib_SELECT_TIMEOUT);
  852.     break;
  853.         default:
  854.             logMsg ("aic7880InitEvent: invalid event type (%d)n",
  855.                      pScsiEvent->type, 0, 0, 0, 0, 0);
  856.             break;
  857. }
  858.     }
  859. /*******************************************************************************
  860. *
  861. * aic7880DummyHandler - used by scsi2Lib.c to do special handling 
  862. *
  863. * This routine is used by scsiMgrLib.c and scsi2Lib.c to perform certain
  864. * functions specific to the AIC-7880 driver. Wide / Synchronous transfer
  865. * negotiations and thread activation are handled differently by scsi2Lib for 
  866. * this driver.
  867. *
  868. * RETURNS N/A
  869. */
  870. LOCAL VOID aic7880DummyHandler
  871.     (
  872.     )
  873.     {
  874.     }
  875. /*******************************************************************************
  876. *
  877. * aic7880ThreadComplete - successfully complete execution of a client thread
  878. *
  879. * Set the thread status and errno appropriately, depending on whether or
  880. * not the thread has been aborted.  Set the thread inactive, and notify
  881. * the SCSI manager of the completion.
  882. *
  883. * RETURNS: N/A
  884. */
  885. LOCAL VOID aic7880ThreadComplete
  886.     (
  887.     AIC_7880_THREAD * pThread    /* ptr to aci7880 thread info */
  888.     )
  889.     {
  890.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  891.     if (pScsiThread->state == SCSI_THREAD_ABORTING)
  892.         {
  893.         pScsiThread->status = ERROR;
  894.         pScsiThread->errNum = S_scsiLib_ABORTED;
  895.         }
  896.     else
  897.         {
  898.         pScsiThread->status = OK;
  899.         pScsiThread->errNum = 0;
  900.         }
  901.     aic7880ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  902.     scsiCacheSynchronize (pScsiThread, SCSI_CACHE_POST_COMMAND);
  903.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_COMPLETED);
  904.     }
  905. /*******************************************************************************
  906. *
  907. * aic7880ThreadFail - complete execution of a thread, with error status
  908. *
  909. * Set the thread's status and errno according to the type of error.  Set
  910. * the thread's state to INACTIVE, and notify the SCSI manager of the
  911. * completion event.
  912. *
  913. * RETURNS: N/A
  914. */
  915. LOCAL VOID aic7880ThreadFail
  916.     (
  917.     AIC_7880_THREAD * pThread,   /* ptr to aci7880 thread info */
  918.     int               errNum     /* error number */
  919.     )
  920.     {
  921.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  922.     SCSI_DEBUG_MSG ("aic7880ThreadFail: thread 0x%08x failed (errno = %d)n",
  923.                     (int) pThread, errNum, 0, 0, 0, 0);
  924.     pScsiThread->status = ERROR;
  925.     if (pScsiThread->state == SCSI_THREAD_ABORTING)
  926.         pScsiThread->errNum = S_scsiLib_ABORTED;
  927.     else
  928.         pScsiThread->errNum = errNum;
  929.     aic7880ThreadStateSet (pThread, SCSI_THREAD_INACTIVE);
  930.     scsiMgrThreadEvent (pScsiThread, SCSI_THREAD_EVENT_COMPLETED);
  931.     }
  932. /*******************************************************************************
  933. *
  934. * aic7880ScsiBusControl - low-level SCSI bus control operations
  935. *
  936. * Currently supports only the SCSI_BUS_RESET operation. After a SCSI Bus
  937. * Reset has occured the transfer parameters are re negotiated when a
  938. * new SCSI thread begins execution.
  939. *
  940. * RETURNS: OK, or ERROR if an invalid operation is requested.
  941. */
  942. LOCAL STATUS aic7880ScsiBusControl
  943.     (
  944.     SIOP * pSiop,           /* ptr to controller info                   */
  945.     int    operation        /* bitmask for operation(s) to be performed */
  946.     )
  947.     {
  948.     SCSI_CTRL       * pScsiCtrl  = (SCSI_CTRL *)  pSiop;
  949.     cfp_struct      * configPtr;
  950.     int               status;
  951.     int               i;
  952.     if ((operation & ~SCSI_BUS_RESET) != 0)
  953.         return (ERROR);
  954.     
  955.     configPtr = pSiop->aic7880CfpStruct;
  956.     if (operation & SCSI_BUS_RESET)
  957.         if ((status = PH_Special (HARD_HA_RESET, configPtr, NULL))
  958.     != OK)
  959.     return (ERROR);
  960.     for (i = 0; i < configPtr->Cf_MaxTargets; i++)
  961. configPtr->Cf_ScsiOption [i] = 0;
  962.     
  963.     scsiMgrBusReset (pScsiCtrl);
  964.     return (OK);
  965.     }
  966. /*******************************************************************************
  967. *
  968. * aic7880XferParamsQuery - get synchronous transfer parameters
  969. *
  970. * Query the AIC 7880 and see if it is capable of handling the specified
  971. * transfer parameters. If the AIC 7880 does not support the specified 
  972. * period and offset this routine returns the offset and period values
  973. * the AIC 7880 is capable of handling.
  974. *
  975. * RETURNS: OK
  976. */
  977. LOCAL STATUS aic7880XferParamsQuery
  978.     (
  979.     SCSI_CTRL * pScsiCtrl,               /* ptr to controller info       */
  980.     UINT8     * pOffset,                 /* max REQ/ACK offset  [in/out] */
  981.     UINT8     * pPeriod                  /* min transfer period [in/out] */
  982.     )
  983.     {
  984.     UINT8 unused;
  985.     
  986.     (VOID) aic7880XferParamsCvt ((SIOP *) pScsiCtrl, pOffset, pPeriod,
  987.  &unused);
  988.     return (OK);
  989.     }
  990. /*******************************************************************************
  991. *
  992. * aic7880XferParamsCvt - convert transfer period from SCSI to AIC 7880 units.
  993. *
  994. * Given a "suggested" REQ/ACK offset and transfer period (in SCSI units of
  995. * 4 ns), return the nearest offset and transfer period the AIC 7880 is
  996. * capable of using.
  997. *
  998. * An offset of zero specifies asynchronous transfer, in which case the period
  999. * is irrelevant.  Otherwise, the offset specified is used if it lies within
  1000. * the permissible range allowed by the AIC 7880.
  1001. *
  1002. * The transfer period is normally rounded towards longer periods if the AIC
  1003. * 7880 is not capable of using the exact specified value.
  1004. *
  1005. * RETURNS: N/A.
  1006. *
  1007. * NOMANUAL
  1008. */
  1009. LOCAL VOID aic7880XferParamsCvt
  1010.     (
  1011.     FAST SIOP  * pSiop,            /* ptr to controller info            */
  1012.     FAST UINT8 * pOffset,          /* REQ/ACK offset                    */
  1013.     FAST UINT8 * pPeriod,          /* xfer period, SCSI units (x 4 ns)  */
  1014.     FAST UINT8 * pXferRate         /* corresponding Sync Xfer Reg value */
  1015.     )
  1016.     {
  1017.     cfp_struct * configPtr = pSiop->aic7880CfpStruct;
  1018.     UINT  offset  = (UINT) * pOffset;
  1019.     UINT  period  = (UINT) * pPeriod;
  1020.     /* asynchronous xfer requested */
  1021.     if (offset == SCSI_SYNC_XFER_ASYNC_OFFSET)
  1022.         period = 0;
  1023.     else
  1024.         {
  1025.         SCSI_DEBUG_MSG ("aic7880XferParamsCvt: requested: "
  1026. "offset = %d, period = %dn",
  1027.  offset, period, 0, 0, 0, 0);
  1028. /* convert to nano seconds */
  1029. period *= 4;
  1030. if (configPtr->CFP_EnableFast20)
  1031.     {
  1032.     if (period <= 50)
  1033. {
  1034. period = AIC_7880_DBLSPD_50;
  1035. *pXferRate = 0x00;
  1036. }
  1037.     else if ((period > 50) && (period <= 64))
  1038. {
  1039. period = AIC_7880_DBLSPD_64;
  1040. *pXferRate = 0x10;
  1041. }
  1042.     else if (period > 65)
  1043. {
  1044. period = AIC_7880_DBLSPD_75;
  1045. *pXferRate = 0x20;
  1046. }
  1047.     }
  1048. else
  1049.     {
  1050.     /* standard fast SCSI mode */
  1051.           
  1052.     if (period <= 100)
  1053. {
  1054. period    = AIC_7880_PERIOD_100;
  1055. *pXferRate = 0x00;
  1056. }
  1057.     else if ((period > 100) && (period <= 125))
  1058. {
  1059. period = AIC_7880_PERIOD_125;
  1060. *pXferRate = 0x10;
  1061. }
  1062.     else if ((period > 125) && (period <= 150))
  1063. {
  1064. period = AIC_7880_PERIOD_150;
  1065. *pXferRate = 0x20;
  1066. }
  1067.     else if ((period > 150) && (period <= 175))
  1068. {
  1069. period = AIC_7880_PERIOD_175;
  1070. *pXferRate = 0x30;
  1071. }
  1072.     
  1073.     else if ((period > 175) && (period <= 200))
  1074. {
  1075. period = AIC_7880_PERIOD_200;
  1076. *pXferRate = 0x40;
  1077. }
  1078.     else if ((period > 200) && (period <= 225))
  1079. {
  1080. period = AIC_7880_PERIOD_225;
  1081. *pXferRate = 0x50;
  1082. }
  1083.     
  1084.     else if ((period > 225) && (period <= 250))
  1085. {
  1086. period = AIC_7880_PERIOD_250;
  1087. *pXferRate = 0x60;
  1088. }
  1089.     
  1090.     else if (period > 250)
  1091. {
  1092. period = AIC_7880_PERIOD_275;
  1093. *pXferRate = 0x70;
  1094. }
  1095.     }
  1096. /* adjust the synchronous offset to fit the allowable range */
  1097.     
  1098. if (offset < AIC_7880_MIN_REQ_ACK_OFFSET)
  1099.     offset = AIC_7880_MIN_REQ_ACK_OFFSET;
  1100. else if (offset > AIC_7880_MAX_REQ_ACK_OFFSET)
  1101.     offset = AIC_7880_MAX_REQ_ACK_OFFSET;
  1102. }
  1103.     SCSI_DEBUG_MSG ("aic7880XferParamsCvt: converted to: "
  1104.     "offset = %d, period = %dn",
  1105.         offset, period, 0,0, 0, 0);
  1106.     
  1107.     *pOffset   = offset;
  1108.     *pPeriod   = period;
  1109.     }
  1110. /*******************************************************************************
  1111. *
  1112. * aic7880XferParamsSet - set transfer parameters
  1113. *
  1114. * Set the transfer parameters specific to a thread.
  1115. *
  1116. * Transfer period is specified in SCSI units (multiples of 4 ns).  An offset
  1117. * of zero specifies asynchronous transfer.
  1118. *
  1119. * RETURNS: OK or ERROR.
  1120. */
  1121. LOCAL STATUS aic7880XferParamsSet
  1122.     (
  1123.     SCSI_CTRL * pScsiCtrl, /* ptr to controller info */
  1124.     UINT8       offset, /* max REQ/ACK offset     */
  1125.     UINT8       period /* min transfer period    */
  1126.     )
  1127.     {
  1128.     AIC_7880_THREAD * pThread = (AIC_7880_THREAD *) pScsiCtrl->pThread;
  1129.     return (aic7880ThreadParamsSet (pThread, offset, period));
  1130.     }
  1131. /*******************************************************************************
  1132. *
  1133. * aic7880ThreadParamsSet - set various parameters for a thread
  1134. *
  1135. * Parameters include transfer offset and period, as well as the ID of the
  1136. * target device.  All of these end up as encoded values stored either in
  1137. * the thread's register context or its associated shared memory area.
  1138. *
  1139. * Transfer period is specified in SCSI units (multiples of 4 ns).  An offset
  1140. * of zero specifies asynchronous transfer.
  1141. *
  1142. * RETURNS: OK or ERROR if it failed negotiation.
  1143. */
  1144. LOCAL STATUS aic7880ThreadParamsSet
  1145.     (
  1146.     AIC_7880_THREAD * pThread,      /* thread to be affected  */
  1147.     UINT8            offset, /* max REQ/ACK offset     */
  1148.     UINT8            period /* min transfer period    */
  1149.     )
  1150.     {
  1151.     SCSI_THREAD   * pScsiThread  = (SCSI_THREAD *) pThread;
  1152.     SIOP          * pSiop        = (SIOP *) pScsiThread->pScsiCtrl;
  1153.     cfp_struct    * pCfpStruct;
  1154.     sp_struct     * pScb;
  1155.     UINT8           xferRate;
  1156.     UINT8           devBusId;
  1157.     STATUS          status;
  1158.     pScb = pThread->pScb;
  1159.     devBusId = (pScb->SP_Tarlun >> 4) & 0x0f;
  1160.     pCfpStruct = pSiop->aic7880CfpStruct;
  1161.     
  1162.     aic7880XferParamsCvt (pSiop, &offset, &period, &xferRate);
  1163.     offset = (offset - 1) << 1;
  1164.     offset &= SOFS;
  1165.     pCfpStruct->Cf_ScsiOption [devBusId] &= 0x80;
  1166.     pCfpStruct->Cf_ScsiOption [devBusId] |= (xferRate | offset | SYNC_MODE);
  1167.     pCfpStruct->CFP_SuppressNego = 0;
  1168.     if ((status = (PH_Special (FORCE_RENEGOTIATE, pCfpStruct, pScb))) != OK)
  1169. {
  1170. SCSI_DEBUG_MSG ("aic7880ThreadParamsSet: Sync Negotiation Failed.n",
  1171.  0, 0, 0, 0, 0, 0);
  1172. return (ERROR);
  1173. }
  1174.     return (OK);
  1175.     }
  1176. /*******************************************************************************
  1177. *
  1178. * aic7880WideXferParamsSet - set wide transfer parameters
  1179. *
  1180. * Assume valid parameters and set the AIC 7880's thread parameters to the
  1181. * appropriate values.
  1182. *
  1183. * RETURNS: OK or ERROR if it failed wide negotiation.
  1184. */
  1185. LOCAL STATUS aic7880WideXferParamsSet
  1186.     (
  1187.     SCSI_CTRL * pScsiCtrl, /* ptr to controller info */
  1188.     UINT8       xferWidth               /* wide data transfer width */
  1189.     )
  1190.     {
  1191.     AIC_7880_THREAD * pThread = (AIC_7880_THREAD *) pScsiCtrl->pThread;
  1192.     SCSI_THREAD   * pScsiThread  = (SCSI_THREAD *) pThread;
  1193.     SIOP          * pSiop        = (SIOP *) pScsiThread->pScsiCtrl;
  1194.     cfp_struct    * pCfpStruct;
  1195.     sp_struct     * pScb;
  1196.     UINT8           devBusId;
  1197.     STATUS          status;
  1198.     pScb = pThread->pScb;
  1199.     devBusId = (pScb->SP_Tarlun >> 4) & 0x0f;
  1200.     pCfpStruct = pSiop->aic7880CfpStruct;
  1201.     if (xferWidth != SCSI_WIDE_XFER_SIZE_NARROW)
  1202. {
  1203. pCfpStruct->Cf_ScsiOption [devBusId] |= WIDE_MODE;
  1204. SCSI_DEBUG_MSG ("aic7880WideXferParamsSet: %x %xn", devBusId, 
  1205. pCfpStruct->Cf_ScsiOption [devBusId], 0, 0, 0, 0);
  1206. pCfpStruct->CFP_SuppressNego = 0;
  1207. if ((status = (PH_Special (FORCE_RENEGOTIATE, pCfpStruct, pScb))) != OK)
  1208.     {
  1209.     SCSI_DEBUG_MSG ("aic7880WideParamsSet: Wide Negotiation Failed.n",
  1210.     0, 0, 0, 0, 0, 0);
  1211.     return (ERROR);
  1212.     }   
  1213. }
  1214.     else
  1215. pCfpStruct->Cf_ScsiOption [devBusId] = NARROW_MODE;    
  1216.     return (OK);
  1217.     }
  1218. /*******************************************************************************
  1219. *
  1220. * aic7880EnableFast20 - enable double speed SCSI data transfers
  1221. *
  1222. * This routine enables double speed SCSI data transfers for the SCSI host
  1223. * adapter. This allows the host adapter to transfer data upto 20 MB/s for
  1224. * an 8 bit device and upto 40 MB/s for a 16 bit device.
  1225. *
  1226. * RETURNS: N/A
  1227. */
  1228. VOID aic7880EnableFast20
  1229.     (
  1230.     SCSI_CTRL * pScsiCtrl,  /* ptr to SCSI controller */
  1231.     BOOL        enable      /* enable = 1 / disable = 0 */
  1232.     )
  1233.     {
  1234.     SIOP        * pSiop  = (SIOP *) pScsiCtrl;
  1235.     cfp_struct  * configPtr = pSiop->aic7880CfpStruct;
  1236.     if (enable)
  1237. configPtr->CFP_EnableFast20 = 1;
  1238.     else
  1239. configPtr->CFP_EnableFast20 = 0;
  1240.     }
  1241. /*******************************************************************************
  1242. *
  1243. * aic7880dFifoThresholdSet - set the data FIFO threshold.
  1244. *
  1245. * This routine specifies to the AIC-7880 host adapter how to manage its
  1246. * data FIFO. Below is a description of the threshold  values for SCSI
  1247. * reads and writes.
  1248. *
  1249. * SCSI READS
  1250. * .iP
  1251. * 0 Xfer data from FIFO as soon as it is available.
  1252. * .iP
  1253. * 1 Xfer data from FIFO as soon as the FIFO is half full.
  1254. * .iP
  1255. * 2 Xfer data from FIFO as soon as the FIFO is 75%  full.
  1256. * .iP
  1257. * 3 Xfer data from FIFO as soon as the FIFO is 100% full.
  1258. *
  1259. * SCSI WRITES
  1260. * .iP
  1261. * 0 Xfer data as soon as there is room in the FIFO.
  1262. * .iP
  1263. * 1 Xfer data to FIFO as soon as it is 50% empty. 
  1264. * .iP
  1265. * 2 Xfer data to FIFO as soon as it is 75% empty.
  1266. * .iP
  1267. * 3 Xfer data to FIFO as soon as the FIFO is empty.
  1268. *
  1269. * RETURNS: OK or ERROR if the threshold value is not within the valid range.
  1270. */
  1271. STATUS aic7880dFifoThresholdSet 
  1272.     (
  1273.     SCSI_CTRL * pScsiCtrl,   /* ptr to SCSI controller */
  1274.     UBYTE       threshHold   /* data FIFO threshold value */
  1275.     )
  1276.     {
  1277.     SIOP        * pSiop  = (SIOP *) pScsiCtrl;
  1278.     cfp_struct  * configPtr = pSiop->aic7880CfpStruct;
  1279.     if (threshHold > 3)
  1280. return (ERROR);
  1281.     configPtr->Cf_Threshold = threshHold;
  1282.     return (OK);
  1283.     }
  1284. /*******************************************************************************
  1285. *
  1286. * aic7880ThreadAbort - abort a thread
  1287. *
  1288. * If the thread is not currently connected, do nothing and return FALSE to
  1289. * indicate that the SCSI manager should abort the thread. Otherwise the
  1290. * thread is active on the controller. Invoke the PH_Special routine with the 
  1291. * Abort SCB opcode passing in the address of the SCB to be aborted. The HIM 
  1292. * reacts as follows:
  1293. *
  1294. * If the SCB has not become active, the status is set to aborted and
  1295. * it is  returned. If the SCB has already completed, it returns completion 
  1296. * status. If the SCB is active and connected, the abort is issued and the SCB
  1297. * is returned with an aborted status. If the target fails to transition to
  1298. * the Message out or Bus Free phase, a SCSI Reset is issued. If the SCB is
  1299. * active but disconnected, the HIM selects the target and issues an abort 
  1300. * message. If the target does not respond correctly to the selection and
  1301. * abort sequence a SCSI Bus Reset is issued. If the HIM does not find a 
  1302. * valid SCB at the specified address, the abort command is simply ignored.
  1303. *
  1304. * RETURNS: TRUE if the thread is being aborted by this driver (i.e. it is
  1305. * currently active on the controller) else FALSE.
  1306. */
  1307. LOCAL BOOL aic7880ThreadAbort
  1308.     (
  1309.     SIOP            * pSiop,      /* ptr to controller info */
  1310.     AIC_7880_THREAD * pThread     /* ptr to SCSI controller thread */
  1311.     )
  1312.     {
  1313.     SCSI_CTRL   * pScsiCtrl   = (SCSI_CTRL *)   pSiop;
  1314.     SCSI_THREAD * pScsiThread = (SCSI_THREAD *) pThread;
  1315.     sp_struct   * pScb = pThread->pScb;
  1316.     cfp_struct  * configPtr = pSiop->aic7880CfpStruct;    
  1317.     SCSI_DEBUG_MSG ("aic7880ThreadAbort: thread 0x%08x state = %d abortingn",
  1318.     (int) pThread, pScsiThread->state, 0, 0, 0, 0);
  1319.     if (pScsiThread != pScsiCtrl->pThread)
  1320.         return (FALSE);
  1321.     switch (pScsiThread->state)
  1322.         {
  1323.         case SCSI_THREAD_INACTIVE:
  1324.             return (FALSE);
  1325.             break;
  1326. default:
  1327.     PH_Special (ABORT_SCB, configPtr, pScb);
  1328.     aic7880ThreadStateSet (pThread, SCSI_THREAD_ABORTING);
  1329.     break;
  1330. }
  1331.     return (TRUE);
  1332.     }
  1333. /*******************************************************************************
  1334. *
  1335. * aic7880GetNumOfBuses - perform a PCI bus scan
  1336. *
  1337. * This routine provides a callback mechanism from the HIM to the OSM
  1338. * It allows the OSM to scan the PCI bus, before the HIM is allowed 
  1339. * to perform the bus scan.
  1340. *
  1341. * RETURNS: 0x55555555 if the OSM is not able to conduct its own bus scan
  1342. */
  1343. DWORD aic7880GetNumOfBuses ()
  1344.     {
  1345.     return (0x55555555);
  1346.     }
  1347. /*******************************************************************************
  1348. *
  1349. * aic7880ReadConfig  - read from PCI config space
  1350. *
  1351. * This routine provides a callback mechanism from the HIM to the OSM.
  1352. * The purpose of this routine is to allow the OSM to do its own Read
  1353. * access of the PCI configuration space. If the OSM cannot successfully
  1354. * complete the Read access, the OSM returns 0x55555555. If this happens
  1355. * the HIM attempts to conduct the configuration space Read access.
  1356. *
  1357. * RETURNS: value read or 0x55555555, if the OSM is not able to conduct 
  1358. * read access to the PCI configuration space.
  1359. */
  1360. DWORD aic7880ReadConfig 
  1361.     (
  1362.     cfp_struct * configPtr, /* ptr to cf_struct */
  1363.     UBYTE        busNo,     /* PCI bus number */
  1364.     UBYTE        devNo,     /* PCI device number */
  1365.     UBYTE        regNo      /* register */
  1366.     )
  1367.     {
  1368.     int          funcNo = 0;
  1369.     DWORD        regVal;
  1370.     if ((pciConfigInLong  (busNo, devNo, funcNo, (int) regNo,
  1371.    &regVal)) != OK)
  1372.         {
  1373.         logMsg ("aic7880ReadConfig: PCI read failedn",
  1374.                  0, 0, 0, 0, 0, 0);
  1375. return (0x55555555);
  1376.         }
  1377.     else
  1378. return (regVal);
  1379.     }
  1380. /*******************************************************************************
  1381. *
  1382. * aic7880WriteConfig - read to PCI config space
  1383. *
  1384. * This routine provides a callback mechanism from the HIM to the OSM.
  1385. * The purpose of this routine is to allow the OSM to do its own write
  1386. * access of the PCI configuration space. If the OSM cannot successfully
  1387. * complete the write access, the OSM returns 0x55555555. If this happens
  1388. * the HIM attempts to conduct the configuration space write access.
  1389. *
  1390. * RETURNS: OK or 0x55555555, if the OSM is not able to conduct write access 
  1391. * to the PCI configuration space.
  1392. */
  1393. DWORD aic7880WriteConfig 
  1394.     (
  1395.     cfp_struct * config_ptr,  /* ptr to cf_struct */
  1396.     UBYTE        busNo,       /* PCI bus number */
  1397.     UBYTE        devNo,       /* PCI device number */
  1398.     UBYTE        regNo,       /* register */
  1399.     DWORD        regVal       /* register value */
  1400.     )
  1401.     {
  1402.     int funcNo = 0;
  1403.     if ((pciConfigOutLong  (busNo, devNo, funcNo, (int) regNo,
  1404.     regVal)) != OK)
  1405.         {
  1406.         logMsg ("aic7880WriteConfig: PCI read failedn",
  1407.                  0, 0, 0, 0, 0, 0);
  1408. return (0x55555555);
  1409.         }
  1410.     else
  1411. return (OK);
  1412.     }