Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

586 lines
15 KiB

4 years ago
  1. //---------------------------------------------------------------------
  2. //
  3. // File: SCSIFNC.C
  4. //
  5. // N5380 Scsi Functions file. Contains higher level scsi functions.
  6. //
  7. // Revisions:
  8. // 09-01-92 KJB First.
  9. // 03-02-93 KJB/JAP Wait for phase change before doing i/o.
  10. // 03-11-93 JAP Changed retcode equates to reflect new names.
  11. // 03-12-93 KJB FinishCommandInterrupt now calls CardDisableInterrupt
  12. // 03-19-93 JAP Implemented condition build FAR and NEAR pointers
  13. // 03-23-93 KJB Changed for new functional interface.
  14. // 03-24-93 KJB ScsiStartCommandInterrupt can now return
  15. // RET_STATUS_MISSED_INTERRUPT, in which case caller
  16. // should pretend interrupt happened and call
  17. // FinishCommandInterrupt.
  18. // 03-25-93 JAP Fixed up typedef and prototype inconsistencies
  19. // 03-31-93 JAP/KJB Added code to handle data overflow:
  20. // DATAIN: target sends more bytes than we have
  21. // been asked to receive
  22. // DATAOUT: target requests more bytes than we have
  23. // been asked to send
  24. // 04-05-93 KJB DEBUG_LEVEL used by DebugPrint for NT.
  25. // 04-05-93 KJB Changed DoIo, now it will not return
  26. // DATA_OVERRUN when there is no data to transfer.
  27. // 04-09-93 KJB Check for phase mismatch before returning that
  28. // we missed an interrupt.
  29. // 05-13-93 KJB Added CardParseCommandString for card specific
  30. // standard string parsing across platforms.
  31. // Changed CardCheckAdapter to accept an
  32. // Initialization info from command line, ie
  33. // force bi-directional ports, etc.
  34. // All functions that used to take an PBASE_REGISTER
  35. // parameter now take PWORKSPACE. CardCheckAdapter
  36. // takes the both the PBASE_REGISTER and the
  37. // PWORKSPACE parameters. Auto Request Sense is
  38. // now supported.
  39. // 05-13-93 KJB Added RequestSenseValid field to TSRB.
  40. // 05-16-93 KJB Fixed bug: finishcommandinterrupt was returning
  41. // RET_STATUS_PENDING when length of xfer was 0.
  42. // Now return RET_STATUS_ERROR when Status != 0.
  43. //
  44. //---------------------------------------------------------------------
  45. #include CARDTXXX_H
  46. //
  47. // Local functions
  48. //
  49. void ScsiDoRequestSense(PTSRB t);
  50. //
  51. // ScsiSendCommand
  52. //
  53. // Selects a target and sends a scsi command during command phase.
  54. //
  55. USHORT ScsiSendCommand (PADAPTER_INFO g, UCHAR target,
  56. UCHAR lun, PUCHAR pcmd, UCHAR cmdlen)
  57. {
  58. USHORT rval;
  59. ULONG tmp;
  60. // select the target
  61. if (rval = N5380Select (g, target, lun)) {
  62. if (rval != RET_STATUS_SELECTION_TIMEOUT) {
  63. DebugPrint((DEBUG_LEVEL,"ScsiSendCommand-0 Error: %x\n",rval));
  64. }
  65. return rval;
  66. }
  67. // set the phase to Command
  68. if (rval = N5380SetPhase (g, PHASE_COMMAND)) {
  69. DebugPrint((DEBUG_LEVEL,"ScsiSendCommand-1 Error: %x\n",rval));
  70. return rval;
  71. }
  72. // send the command bytes
  73. if (rval = CardWriteBytesCommand (g, pcmd, (ULONG)cmdlen,
  74. &tmp, PHASE_COMMAND)) {
  75. DebugPrint((DEBUG_LEVEL,"ScsiSendCommand-2 Error: %x\n",rval));
  76. return rval;
  77. }
  78. return 0;
  79. }
  80. //
  81. // ScsiDoCommand
  82. //
  83. // Executes a complete scsi command: all phase sequences without using
  84. // interrupts.
  85. //
  86. USHORT ScsiDoCommand (PTSRB t)
  87. {
  88. USHORT rval;
  89. PADAPTER_INFO g = t->pWorkspace;
  90. // select the target and send the command bytes
  91. if (rval = ScsiSendCommand (g, t->Target, t->Lun, t->pCommand,
  92. t->CommandLen)) {
  93. DebugPrint((DEBUG_LEVEL,"ScsiDoCommand-0 Error: %x\n",rval));
  94. goto done;
  95. }
  96. if (rval = ScsiFinishCommandInterrupt (t)) {
  97. if (rval!=RET_STATUS_SUCCESS) {
  98. DebugPrint((DEBUG_LEVEL,"ScsiDoCommand-1 Error: %x\n",rval));
  99. }
  100. }
  101. done:
  102. t->ReturnCode = rval;
  103. return rval;
  104. }
  105. //
  106. // ScsiStartCommandInterrupt
  107. //
  108. // Executes a scsi command up to the end of command phase. After this, the
  109. // interrupt will come in and ScsiFinishCommandInterrupt should be called to
  110. // complete the data, status, and message phases.
  111. //
  112. USHORT ScsiStartCommandInterrupt (PTSRB t)
  113. {
  114. USHORT rval;
  115. PADAPTER_INFO g = t->pWorkspace;
  116. // select the target and send the command bytes
  117. if (rval = ScsiSendCommand (g, t->Target, t->Lun, t->pCommand,
  118. t->CommandLen)) {
  119. DebugPrint((DEBUG_LEVEL,"ScsiStartCommandInterrupt-0 Error: %x\n",rval));
  120. goto done;
  121. }
  122. // enable the interrupt
  123. CardEnableInterrupt (g);
  124. // if request is already up, we may have missed the interrupt, it is done
  125. if (N5380PortTest (g, N5380_CURRENT_STATUS, CS_REQ)) {
  126. // and we are not still in command phase
  127. if (!N5380PortTest(g, N5380_DMA_STATUS, DS_PHASE_MATCH)) {
  128. rval = RET_STATUS_MISSED_INTERRUPT;
  129. goto done;
  130. }
  131. }
  132. rval = RET_STATUS_PENDING;
  133. done:
  134. t->ReturnCode = rval;
  135. return rval;
  136. }
  137. //
  138. // ScsiFinishComamndInterrupt
  139. //
  140. // Called to finish a command that has been started by ScsiStartCommandInterupt.
  141. // This function completes the data, status, and message phases.
  142. //
  143. USHORT ScsiFinishCommandInterrupt (PTSRB t)
  144. {
  145. USHORT rval = 0;
  146. USHORT rval_stat = 0;
  147. PADAPTER_INFO g = t->pWorkspace;
  148. // set actual transfer length to 0
  149. t->ActualDataLen = 0;
  150. // set request sense valid flag to FALSE
  151. t->Flags.RequestSenseValid = FALSE;
  152. // is there a data phase??
  153. if (t->DataLen) {
  154. // read/write the data if there is a data phase
  155. rval = ScsiDoIo (t);
  156. }
  157. // if no errors, return RET_STATUS_SUCCESS.
  158. if (!rval) {
  159. rval = RET_STATUS_SUCCESS;
  160. }
  161. // get the stat and message bytes
  162. if (rval_stat = ScsiGetStat (g, &t->Status)) {
  163. DebugPrint((DEBUG_LEVEL,"ScsiFinishCommandInterrupt-0 Error: %x\n",rval_stat));
  164. rval = rval_stat;
  165. goto done;
  166. }
  167. // if not any other error, return a general status error to indicate
  168. // that the status byte was bad.
  169. if (!rval_stat) {
  170. // no errors get status, was there a status check condition?
  171. if (t->Status == 0x02) {
  172. if (t->Flags.DoRequestSense) {
  173. ScsiDoRequestSense(t);
  174. }
  175. }
  176. if (t->Status) {
  177. // return with error when there was a non-zero status
  178. rval = RET_STATUS_ERROR;
  179. }
  180. }
  181. if (rval!=RET_STATUS_SUCCESS) {
  182. DebugPrint((DEBUG_LEVEL,"ScsiFinishCommandInterrupt-1 Error: %x\n",rval));
  183. }
  184. done:
  185. // disable the interrupt
  186. CardDisableInterrupt(g);
  187. // for now, we never return pending
  188. t->ReturnCode = rval;
  189. return rval;
  190. }
  191. //
  192. // ScsiDoRequestSense
  193. //
  194. // Do a request sense and store the information in the current tsrb.
  195. // Works on the stack, does not harm the current tsrb.
  196. //
  197. VOID ScsiDoRequestSense(PTSRB t)
  198. {
  199. PADAPTER_INFO g = t->pWorkspace;
  200. // allocate on stack ok, since we don't use interrupt for the sense cmd
  201. TSRB tsrb;
  202. PTSRB t0 = &tsrb;
  203. UCHAR pSenseCmd[6];
  204. USHORT rval;
  205. pSenseCmd[0] = 0x03;
  206. pSenseCmd[1] = 0x00;
  207. pSenseCmd[2] = 0x00;
  208. pSenseCmd[3] = 0x00;
  209. pSenseCmd[4] = t->SenseDataLen;
  210. pSenseCmd[5] = 0x00;
  211. // copy most of the tsrb information from the current tsrb
  212. *t0 = *t;
  213. // get the sense information
  214. t0->Flags.DoRequestSense = FALSE; // don't request sense info here
  215. t0->pCommand = pSenseCmd;
  216. t0->CommandLen = 6;
  217. t0->Dir = TSRB_DIR_IN;
  218. t0->pData = t->pSenseData;
  219. t0->DataLen = t->SenseDataLen;
  220. rval = CardDoCommand(t0); // don't use interrupts
  221. if (rval == RET_STATUS_SUCCESS) {
  222. t->Flags.RequestSenseValid = TRUE;
  223. }
  224. }
  225. //
  226. // ScsiWriteBytesSlow
  227. //
  228. // This functions writes bytes to the scsi bus using the slow req/ack
  229. // handshake. Faster methods are generally avaiable, but they are dependent
  230. // on how the card inplements the dma capabilities of the 5380. This
  231. // is a sure-fire slow method that works. It is great to bring up new cards.
  232. //
  233. USHORT ScsiWriteBytesSlow (PADAPTER_INFO g, PUCHAR pbytes,
  234. ULONG len, PULONG pActualLen, UCHAR phase)
  235. {
  236. ULONG i;
  237. USHORT rval = 0;
  238. UCHAR tmp;
  239. for (i=0;i<len;i++) {
  240. // wait for request to be asserted
  241. if (rval = N5380GetPhase (g, &tmp)) {
  242. DebugPrint((DEBUG_LEVEL,"ScsiWriteBytesSlow-0 Error: %x\n",rval));
  243. goto done;
  244. }
  245. // see if phase match
  246. if (phase != tmp) {
  247. rval = RET_STATUS_DATA_OVERRUN;
  248. goto done;
  249. }
  250. if (rval = N5380PutByte (g, TIMEOUT_REQUEST, pbytes[i])) {
  251. DebugPrint((DEBUG_LEVEL,"ScsiWriteBytesSlow-1 Error: %x\n",rval));
  252. goto done;
  253. }
  254. }
  255. done:
  256. *pActualLen = i;
  257. return rval;
  258. }
  259. //
  260. // ScsiReadBytesSlow
  261. //
  262. // This functions reads bytes to the scsi bus using the slow req/ack
  263. // handshake. Faster methods are generally avaiable, but they are dependent
  264. // on how the card inplements the dma capabilities of the 5380. This
  265. // is a sure-fire slow method that works. It is great to bring up new cards.
  266. //
  267. USHORT ScsiReadBytesSlow (PADAPTER_INFO g, PUCHAR pbytes,
  268. ULONG len, PULONG pActualLen, UCHAR phase)
  269. {
  270. ULONG i;
  271. USHORT rval = 0;
  272. UCHAR tmp;
  273. for (i = 0; i < len; i++) {
  274. // wait for request to be asserted
  275. if (rval = N5380GetPhase (g, &tmp)) {
  276. DebugPrint((DEBUG_LEVEL,"ScsiReadBytesSlow-0 Error: %x\n",rval));
  277. goto done;
  278. }
  279. // see if phase match
  280. if (phase != tmp) {
  281. rval = RET_STATUS_DATA_OVERRUN;
  282. goto done;
  283. }
  284. if (rval = N5380GetByte (g, TIMEOUT_REQUEST, &pbytes[i])) {
  285. DebugPrint((DEBUG_LEVEL,"ScsiReadBytesSlow-1 Error: %x\n",rval));
  286. goto done;
  287. }
  288. }
  289. done:
  290. *pActualLen = i;
  291. return rval;
  292. }
  293. //
  294. // ScsiDoIo
  295. //
  296. // This function does the I/O during a data phase.
  297. //
  298. USHORT ScsiDoIo (PTSRB t)
  299. {
  300. USHORT rval;
  301. UCHAR tmp;
  302. UCHAR phase;
  303. PADAPTER_INFO g = t->pWorkspace;
  304. // wait for next phase, errors in phase will be caught below
  305. if (rval = N5380GetPhase (g, &tmp)) {
  306. goto done;
  307. }
  308. if (t->DataLen && tmp != PHASE_DATAIN && tmp != PHASE_DATAOUT) {
  309. // phase is not data in/out and we were expecting data, len !=0
  310. rval = RET_STATUS_DATA_OVERRUN;
  311. goto done;
  312. }
  313. // phase is now either data in or data out
  314. if (t->Dir == TSRB_DIR_UNKNOWN) {
  315. // must be read/write, use phase bits to determine it
  316. if (tmp == PHASE_DATAOUT) {
  317. t->Dir = TSRB_DIR_OUT;
  318. }
  319. else if (tmp == PHASE_DATAIN) {
  320. t->Dir = TSRB_DIR_IN;
  321. }
  322. // else: pass thru, don't transfer any data, must be in status phase
  323. }
  324. if (t->Dir == TSRB_DIR_OUT) {
  325. // data write
  326. // set the phase to data out
  327. if (rval = N5380SetPhase (g, PHASE_DATAOUT)) {
  328. return RET_STATUS_ERROR;
  329. }
  330. // send the bytes
  331. if (rval = CardWriteBytesFast (g, t->pData, t->DataLen,
  332. &t->ActualDataLen, PHASE_DATAOUT)) {
  333. DebugPrint((DEBUG_LEVEL,"ScsiDoIo-0 Error: %x\n",rval));
  334. return rval;
  335. }
  336. // Check for Data Overflow.
  337. while ((N5380GetPhase (g,&phase) == 0) &&
  338. (phase == PHASE_DATAOUT)) {
  339. // DATA OVERFLOW:
  340. // Target requests more bytes than we have been asked to send.
  341. // Send a dummy byte of 0 until we are out of DATAOUT phase.
  342. ULONG tmpDataLen;
  343. UCHAR dummy = 0;
  344. if (rval = ScsiWriteBytesSlow (g, &dummy, 1,
  345. &tmpDataLen, PHASE_DATAOUT)) {
  346. DebugPrint((DEBUG_LEVEL,"ScsiDoIo-2 Error: %x\n",rval));
  347. return rval;
  348. }
  349. }
  350. }
  351. else if (t->Dir == TSRB_DIR_IN) {
  352. // data read
  353. // set the phase to data in
  354. if (rval = N5380SetPhase (g, PHASE_DATAIN)) {
  355. return RET_STATUS_ERROR;
  356. }
  357. // read the bytes
  358. if (rval = CardReadBytesFast (g, t->pData, t->DataLen,
  359. &t->ActualDataLen, PHASE_DATAIN)) {
  360. DebugPrint((DEBUG_LEVEL,"ScsiDoIo-1 Error: %x\n",rval));
  361. return rval;
  362. }
  363. // Check for Data Overflow.
  364. while ((N5380GetPhase(g,&phase) == 0) &&
  365. phase == PHASE_DATAIN) {
  366. // DATA OVERFLOW:
  367. // Target sends more bytes than we have been asked to receive.
  368. // Swallow up extra bytes until we are out of DATAIN phase.
  369. ULONG tmpDataLen;
  370. UCHAR dummy;
  371. if (rval = ScsiReadBytesSlow (g, &dummy, 1,
  372. &tmpDataLen, PHASE_DATAIN)) {
  373. DebugPrint((DEBUG_LEVEL,"ScsiDoIo-3 Error: %x\n",rval));
  374. return rval;
  375. }
  376. }
  377. }
  378. done:
  379. return rval;
  380. }
  381. //
  382. // ScsiGetStat
  383. //
  384. // This function gets the status and message bytes.
  385. //
  386. USHORT ScsiGetStat (PADAPTER_INFO g, PUCHAR pstatus)
  387. {
  388. UCHAR tmp;
  389. USHORT rval;
  390. // set the phase to Status Phase
  391. if (rval = N5380SetPhase (g, PHASE_STATUS)) {
  392. DebugPrint((DEBUG_LEVEL,"ScsiGetStat-0 Error: %x\n",rval));
  393. return rval;
  394. }
  395. // wait for request to be asserted
  396. if (rval = N5380GetPhase (g,&tmp)) {
  397. DebugPrint((DEBUG_LEVEL,"ScsiGetStat-1 Error: %x\n",rval));
  398. return rval;
  399. }
  400. // see if phase match
  401. if (PHASE_STATUS != tmp) {
  402. return RET_STATUS_PHASE_SEQ_FAILURE;
  403. }
  404. // get the status byte
  405. if (rval = N5380GetByte (g, TIMEOUT_REQUEST, pstatus)) {
  406. DebugPrint((DEBUG_LEVEL,"ScsiGetStat-2 Error: %x\n",rval));
  407. return rval;
  408. }
  409. // set the phase to Message In Phase
  410. if (rval = N5380SetPhase (g, PHASE_MSGIN)) {
  411. DebugPrint((DEBUG_LEVEL,"ScsiGetStat-3 Error: %x\n",rval));
  412. return rval;
  413. }
  414. // wait for request to be asserted
  415. if (rval = N5380GetPhase (g,&tmp)) {
  416. DebugPrint((DEBUG_LEVEL,"ScsiGetStat-4 Error: %x\n",rval));
  417. return rval;
  418. }
  419. // see if phase match
  420. if (PHASE_MSGIN != tmp) {
  421. return RET_STATUS_PHASE_SEQ_FAILURE;
  422. }
  423. // get the msg byte, throw it away
  424. if (rval = N5380GetByte (g, TIMEOUT_REQUEST, &tmp)) {
  425. DebugPrint((DEBUG_LEVEL,"ScsiGetStat-5 Error: %x\n",rval));
  426. return rval;
  427. }
  428. // set the phase to NULL to up N5380 back to normal
  429. if (rval = N5380SetPhase (g, PHASE_NULL)) {
  430. DebugPrint((DEBUG_LEVEL,"ScsiGetStat-6 Error: %x\n",rval));
  431. return rval;
  432. }
  433. return rval;
  434. }