|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1991, 1992 Microsoft Corporation
4: Copyright (c) 1992 Future Domain Corporation
5:
6: Module Name:
7:
8: fd8xx.c
9:
10: Abstract:
11:
12: This is the miniport driver for the Future Domain TMC-8XX SCSI Adapters.
13:
14: Environment:
15:
16: kernel mode only
17:
18: Notes:
19:
20: --*/
21:
22: #include "miniport.h"
23: #include "stdarg.h"
24: #include <string.h>
25: #include <math.h>
26: #include <stdlib.h>
27: #include "fd8xx.h" // includes scsi.h
28:
29: //
30: // Logical Unit states.
31: //
32: typedef enum _LU_STATE {
33:
34: LS_UNDETERMINED,
35: LS_ARBITRATE,
36: LS_SELECT,
37: LS_IDENTIFY,
38: LS_MSG_SPECIAL,
39: LS_COMMAND,
40: LS_DATA,
41: LS_DISCONNECTED,
42: LS_ABORT,
43: LS_STATUS,
44: LS_MSG_IN,
45: LS_COMPLETE
46:
47: } LU_STATE, *PLU_STATE;
48:
49: //
50: // Logical Unit extension. The BOOLEANS in this structure will be initialized
51: // to FALSE by the port driver. It will zero the structure when allocated.
52: // Therefore there is no explicit initialization of these fields.
53: //
54: typedef struct _SPECIFIC_LU_EXTENSION {
55:
56: LU_STATE LuState; // State information.
57: ULONG SavedDataPointer; // Current data pointer.
58: ULONG SavedDataLength; // Current data lenght.
59: PSCSI_REQUEST_BLOCK ActiveLuRequest; // Active Srb for this LUN.
60: USHORT OverRunCount; // Initialized to zero, counts up
61: UCHAR AbortBeingAttempted;// Abort active on this LU.
62: BOOLEAN NoDisconnectActive; // No disconnect flag on SRB.
63: BOOLEAN HandShakeAllData; // Dribbling drive fix.
64: BOOLEAN SixByteCDBActive; // Potential tape access.
65:
66: } SPECIFIC_LU_EXTENSION, *PSPECIFIC_LU_EXTENSION;
67:
68: //
69: // Device extension
70: //
71: typedef struct _SPECIFIC_DEVICE_EXTENSION {
72:
73: PUCHAR BaseAddress; // Memory map address of adapter.
74: ULONG CurDataPointer; // Current pointer for active LUN.
75: ULONG CurDataLength; // Bytes left to xfer to this LUN.
76: PSPECIFIC_LU_EXTENSION SavedLu; // Saved LUN during interrupts.
77: PSPECIFIC_LU_EXTENSION ActiveLu; // Currently active LUN.
78: UCHAR PathId; // Relates to SCSI bus.
79: UCHAR ControlRegister; // Current val of fd8xx control reg.
80: BOOLEAN ExpectingInterrupt; // Bookkeeping for IRQ configuration.
81: BOOLEAN NotifiedConfigurationError; // Event is logged.
82: USHORT ContinueTimer; // Indicator to continue polling
83: USHORT TimerCaughtInterrupt; // Number times timer caught IRQ
84: UCHAR InitiatorId; // target id for host adapter
85: BOOLEAN ConfiguredWithoutInterrupts; // Intentially configured w/o IRQ
86:
87: } SPECIFIC_DEVICE_EXTENSION, *PSPECIFIC_DEVICE_EXTENSION;
88:
89:
90: //
91: // Function declarations
92: //
93:
94: ULONG
95: DriverEntry(
96: IN PVOID DriverObject,
97: IN PVOID Argument2
98: );
99:
100: ULONG
101: Fd8xxFindAdapter(
102: IN PVOID Context,
103: IN PVOID AdaptersFound,
104: IN PVOID BusInformation,
105: IN PCHAR ArgumentString,
106: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
107: OUT PBOOLEAN Again
108: );
109:
110: BOOLEAN
111: Fd8xxInitialize(
112: IN PVOID Context
113: );
114:
115: BOOLEAN
116: Fd8xxStartIo(
117: IN PVOID Context,
118: IN PSCSI_REQUEST_BLOCK Srb
119: );
120:
121: VOID
122: Fd8xxDoReconnect(
123: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
124: );
125:
126: VOID
127: Fd8xxDpcRunPhase(
128: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
129: );
130:
131: VOID
132: Fd8xxTimer(
133: IN PVOID Context
134: );
135:
136: BOOLEAN
137: Fd8xxInterrupt(
138: IN PVOID Context
139: );
140:
141: BOOLEAN
142: Fd8xxResetBus(
143: IN PVOID Context,
144: IN ULONG PathId
145: );
146:
147: VOID
148: Fd8xxMoveMemoryUchar(
149: PUCHAR Source,
150: PUCHAR Dest,
151: ULONG Length
152: );
153:
154:
155: #if DBG
156:
157: //
158: // Globals and externals used for debugging.
159: //
160:
161: //
162: // Fd8xxDebug affects which debug prints are enabled:
163: //
164: // 0x001 Arbitration and selection
165: // 0x002 Command, message out, and status
166: // 0x004 Data transfer
167: // 0x008 Message in and status
168: // 0x010 Miniport entry points and completion
169: // 0x020 Initialization and interrupt
170: // 0x040 StatusCheck and WaitForRequest
171: // 0x080 Control register manipulation
172: // 0x100 Completion
173: // 0x200 Handshake all bytes set.
174: //
175: ULONG Fd8xxDebug = 0x0000;
176:
177: #define FdDebugPrint(MASK, ARGS) \
178: if (MASK & Fd8xxDebug) { \
179: ScsiDebugPrint ARGS; \
180: }
181:
182: #else
183:
184: #define FdDebugPrint(MASK, ARGS)
185:
186: #endif
187:
188:
189: VOID
190: Fd8xxWriteControl(
191: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
192: IN UCHAR Value
193: )
194:
195: /*++
196:
197: Routine Description:
198:
199: This routine sets the control register on the adapter and remembers
200: the value set in the device extension.
201:
202: Arguments:
203:
204: DeviceExtension - Device adapter context pointer.
205: Value - New value for the control register.
206:
207: Return Value:
208:
209: None
210:
211: --*/
212:
213: {
214: FdDebugPrint(0x80,
215: (0, "WriteControl: Device = %x, NewVal = %x\n",
216: DeviceExtension,
217: Value));
218:
219: DeviceExtension->ControlRegister = Value;
220:
221: FD8XX_SET_CONTROL(DeviceExtension->BaseAddress,
222: Value);
223: } // end Fd8xxWriteControl()
224:
225:
226: VOID
227: Fd8xxSetControl(
228: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
229: IN UCHAR Value
230: )
231:
232: /*++
233:
234: Routine Description:
235:
236: This routine adds the control lines indicated to the current value
237: for the adapter control register.
238:
239: Arguments:
240:
241: DeviceExtension - Device adapter context pointer.
242: Value - The bits that are to be added (or'd in) to the
243: control register.
244:
245: Return Value:
246:
247: None
248:
249: --*/
250:
251: {
252: FdDebugPrint(0x80,
253: (0, "SetControl: Device = %x, Value = %x, NewVal = %x\n",
254: DeviceExtension,
255: Value,
256: DeviceExtension->ControlRegister | Value));
257:
258: DeviceExtension->ControlRegister |= Value;
259:
260: FD8XX_SET_CONTROL(DeviceExtension->BaseAddress,
261: DeviceExtension->ControlRegister);
262: } // end Fd8xxSetControl()
263:
264:
265: VOID
266: Fd8xxClearControl(
267: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
268: IN UCHAR Mask
269: )
270:
271: /*++
272:
273: Routine Description:
274:
275: This routine masks out the bits for the control register that are
276: passed in Mask and sets the adapter control register to the new value.
277:
278: Arguments:
279:
280: DeviceExtension - Device adapter context pointer.
281: Mask - The bits that are to be reset to zero in the control
282: register.
283:
284: Return Value:
285:
286: None
287:
288: --*/
289:
290: {
291: FdDebugPrint(0x80,
292: (0, "ClearControl: Device = %x, Mask = %x, NewVal = %x\n",
293: DeviceExtension,
294: Mask,
295: DeviceExtension->ControlRegister & (~(Mask))));
296:
297: //
298: // Negate Value to get a zero based mask.
299: //
300: Mask = ~(Mask);
301:
302: //
303: // AND against the current contents of the control register.
304: //
305: DeviceExtension->ControlRegister &= Mask;
306:
307: FD8XX_SET_CONTROL(DeviceExtension->BaseAddress,
308: DeviceExtension->ControlRegister);
309: } // end Fd8xxClearControl()
310:
311:
312: BOOLEAN
313: Fd8xxWaitForRequestLine(
314: PSPECIFIC_DEVICE_EXTENSION DeviceExtension
315: )
316:
317: /*++
318:
319: Routine Description:
320:
321: Spin checking the status of the FD8XX adapter until it indicates that
322: the SCSI REQUEST line is high.
323:
324: Arguments:
325:
326: DeviceExtension - Device adapter context pointer.
327:
328: Return Value:
329:
330: TRUE - indicates that the SCSI REQUEST line was asserted in time.
331: FALSE - indicates timeout occurred while waiting for the SCSI REQUEST
332: line.
333:
334: --*/
335:
336: {
337: PUCHAR baseAddress = DeviceExtension->BaseAddress;
338: ULONG spinCount = REQUEST_SPIN_WAIT;
339:
340: FdDebugPrint(0x40, (0, "FdWaitForReq: "));
341:
342: do {
343:
344: //
345: // Check if TWO of the status register reads are identical. This is
346: // to validate that there was no "glitch" that caused some line to
347: // temporarily go high.
348: //
349: while (FD8XX_READ_STATUS(baseAddress) !=
350: FD8XX_READ_ALTERNATE_STATUS(baseAddress, 1)) {
351:
352: ScsiPortStallExecution(1);
353: }
354:
355: if (FD8XX_READ_STATUS(baseAddress) & S_REQUEST) {
356:
357: FdDebugPrint(0x40, (0, "Got REQUEST\n"));
358: return TRUE;
359: }
360:
361: ScsiPortStallExecution(1);
362:
363: } while (spinCount--);
364:
365: FdDebugPrint(0x40, (0, "TIMEOUT\n"));
366:
367: if (DeviceExtension->ActiveLu) {
368:
369: ScsiPortLogError(DeviceExtension,
370: DeviceExtension->ActiveLu->ActiveLuRequest,
371: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
372: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
373: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
374: SP_REQUEST_TIMEOUT,
375: 1);
376: }
377:
378: return FALSE;
379: } // end Fd8xxWaitForRequestLine()
380:
381:
382: BOOLEAN
383: Fd8xxStatusCheck(
384: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
385: IN UCHAR Mask,
386: IN UCHAR Compare,
387: IN ULONG SpinMax
388: )
389:
390: /*++
391:
392: Routine Description:
393:
394: Spin checking the status of the FD8XX adapter until it matches
395: the desired value.
396:
397: Arguments:
398:
399: DeviceExtension - Device adapter context pointer.
400: Mask - Bits to mask out of the value returned by adapter
401: status register.
402: Compare - Desired result of status register after is is "Mask"ed.
403: SpinMax - Number of times to test adapter's status register.
404:
405: Return Value:
406:
407: TRUE indicates desired value was returned by the adapter status register.
408: FALSE indicates timeout occurred and desired value was not returned.
409:
410: --*/
411:
412: {
413: PUCHAR baseAddress = DeviceExtension->BaseAddress;
414:
415: FdDebugPrint(0x40, (0, "FdStatusCheck: "));
416:
417: FdDebugPrint(0x40,
418: (0, "Dev=%x Status=%x Mask=%x Compare=%x ",
419: DeviceExtension,
420: FD8XX_READ_STATUS(baseAddress),
421: Mask,
422: Compare));
423:
424: do {
425:
426: //
427: // Check if TWO of the status register reads are identical. This is
428: // to validate that there was no "glitch" that caused some line to
429: // temporarily go high.
430: //
431: while (FD8XX_READ_STATUS(baseAddress) !=
432: FD8XX_READ_ALTERNATE_STATUS(baseAddress, 1)) {
433:
434: ScsiPortStallExecution(1);
435: }
436:
437: if ((UCHAR)(FD8XX_READ_STATUS(baseAddress) & Mask) == Compare) {
438:
439: FdDebugPrint(0x40, (0, "Got Compare\n"));
440: return TRUE;
441: }
442:
443: ScsiPortStallExecution(1);
444:
445: } while (SpinMax--);
446:
447: FdDebugPrint(0x40,
448: (0, "TIMEOUT Status=%x\n",
449: FD8XX_READ_STATUS(baseAddress)));
450:
451: return FALSE;
452: } // end Fd8xxStatusCheck()
453:
454:
455: VOID
456: Fd8xxDetermineNextState(
457: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
458: )
459:
460: /*++
461:
462: Routine Description:
463:
464: This routine determines the next logical state of this state machine
465: based on the current SCSI bus phase. It is typically called because
466: from the current state, the next state can be one of a number of other
467: states. For example, after issuing the last command byte of COMMAND
468: phase, the device may want to drive us into DATA_IN, DATA_OUT, STATUS,
469: or MSG_IN (i.e., transfer data, report an error, or disconnect).
470:
471: Arguments:
472:
473: DeviceExtension - Device adapter context pointer.
474:
475: Return Value:
476:
477: None
478:
479: --*/
480:
481: {
482: FdDebugPrint(0x01,
483: (0, "FdNextPhase: phase = %x ",
484: FD8XX_READ_PHASE(DeviceExtension->BaseAddress)));
485:
486: switch (FD8XX_READ_PHASE(DeviceExtension->BaseAddress)) {
487:
488: case BP_COMMAND:
489:
490: FdDebugPrint(0x01, (0, "LS_COMMAND\n"));
491: DeviceExtension->ActiveLu->LuState = LS_COMMAND;
492: break;
493:
494: case BP_DATA_IN:
495: case BP_DATA_OUT:
496:
497: FdDebugPrint(0x01, (0, "LS_DATA\n"));
498: DeviceExtension->ActiveLu->LuState = LS_DATA;
499: break;
500:
501: case BP_MESSAGE_IN:
502:
503: FdDebugPrint(0x01, (0, "LS_MSG_IN\n"));
504: DeviceExtension->ActiveLu->LuState = LS_MSG_IN;
505: break;
506:
507: case BP_STATUS:
508:
509: FdDebugPrint(0x01, (0, "LS_STATUS\n"));
510: DeviceExtension->ActiveLu->LuState = LS_STATUS;
511: break;
512:
513: case BP_BUS_FREE:
514:
515: FdDebugPrint(0x01, (0, "LS_BUS_FREE\n"));
516:
517: if (DeviceExtension->ActiveLu->AbortBeingAttempted) {
518:
519: DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
520: SRB_STATUS_SUCCESS;
521: } else {
522:
523: DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
524: SRB_STATUS_UNEXPECTED_BUS_FREE;
525: }
526:
527: DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
528: break;
529:
530: case BP_MESSAGE_OUT:
531: case BP_RESELECT:
532: default:
533:
534: //
535: // This will get handled in RunPhase.
536: //
537: FdDebugPrint(0x01, (0, "N/A\n"));
538: break;
539: }
540: } // end Fd8xxDetermineNextState()
541:
542:
543: VOID
544: Fd8xxArbitrate(
545: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
546: )
547:
548: /*++
549:
550: Routine Description:
551:
552: Attempt to arbitrate for the SCSI bus.
553:
554: Arguments:
555:
556: DeviceExtension - Device adapter context pointer.
557:
558: Return Value:
559:
560: None
561:
562: --*/
563:
564: {
565: PUCHAR baseAddress = DeviceExtension->BaseAddress;
566: ULONG attemptsRemaining = MAX_ARB_ATTEMPTS;
567:
568: FdDebugPrint(0x01, (0, "FdArbitrate: baseaddr = %x ", baseAddress));
569:
570: while (DeviceExtension->ActiveLu->LuState == LS_ARBITRATE) {
571:
572: if (FD8XX_READ_PHASE(baseAddress) == BP_BUS_FREE) {
573:
574: //
575: // Tell the adapter to initiate arbitration for the SCSI bus
576: // since it ia available.
577: //
578: Fd8xxClearControl(DeviceExtension,
579: C_BUS_ENABLE);
580: Fd8xxSetControl(DeviceExtension,
581: C_PARITY_ENABLE);
582: FD8XX_WRITE_DATA(baseAddress,
583: (1 << DeviceExtension->InitiatorId));
584: Fd8xxSetControl(DeviceExtension,
585: C_ARBITRATION);
586: }
587:
588: if (Fd8xxStatusCheck(DeviceExtension,
589: S_ARB_COMPLETE,
590: S_ARB_COMPLETE,
591: ARBITRATION_DELAY)) {
592:
593: FdDebugPrint(0x01,
594: (0, "SUCCESS on attempt #%x!\n",
595: (MAX_ARB_ATTEMPTS - attemptsRemaining)));
596:
597: //
598: // Disable adapter interrupts so selection doesn't cause an
599: // interrupt. Then go to selection phase.
600: //
601: Fd8xxClearControl(DeviceExtension,
602: C_INT_ENABLE);
603: DeviceExtension->ActiveLu->LuState = LS_SELECT;
604:
605: } else {
606:
607: FdDebugPrint(0x01,
608: (0, "FAILED! Status=%x ",
609: FD8XX_READ_STATUS(baseAddress)));
610:
611: Fd8xxClearControl(DeviceExtension,
612: C_ARBITRATION);
613:
614: if (FD8XX_READ_PHASE(baseAddress) & S_SELECT) {
615:
616: FdDebugPrint(0x01, (0, "Being re-selected!\n"));
617:
618: //
619: // This will cause the interrupt routine to be called TWICE
620: // for the same reason. The first call will be from here.
621: // The second call will be from the NT OS since it will
622: // remember to call the interrupt routine due to the
623: // adapter IRQ line (which is tied to the SCSI SELECT line)
624: // going high. The second call will be seen by the interrupt
625: // routine as SPURRIOUS!
626: //
627: DeviceExtension->SavedLu = DeviceExtension->ActiveLu;
628: DeviceExtension->ActiveLu = NULL;
629:
630: Fd8xxDoReconnect(DeviceExtension);
631:
632: if (DeviceExtension->SavedLu == NULL) {
633:
634: //
635: // The bus was reset during the reconnect.
636: //
637: return;
638: }
639:
640: DeviceExtension->ActiveLu = DeviceExtension->SavedLu;
641: DeviceExtension->SavedLu = NULL;
642:
643: FdDebugPrint(0x01, (0, "Back to Arbitration "));
644:
645: } else if (!(attemptsRemaining--)) {
646:
647: FdDebugPrint(0x01, (0, "aborted.\n"));
648:
649: DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
650: DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
651: SRB_STATUS_TIMEOUT;
652: }
653: }
654: }
655: } // end Fd8xxArbitrate()
656:
657:
658: VOID
659: Fd8xxSelect(
660: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
661: )
662:
663: /*++
664:
665: Routine Description:
666:
667: Perform selection process on SCSI bus.
668:
669: Arguments:
670:
671: DeviceExtension - Device adapter context pointer.
672:
673: Return Value:
674:
675: None
676:
677: --*/
678:
679: {
680: FdDebugPrint(0x01,
681: (0, "FdSelect: Device = %x, Target = %x ",
682: DeviceExtension,
683: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId));
684:
685: //
686: // Raise Select line, keeping the BUSY line high. Also, enable parity
687: // and tell the adapter to drive the SCSI data lines to prepare for
688: // outgoing ID bits. Keep in mind that this also clears the
689: // C_ARBITRATION bit.
690: //
691: Fd8xxWriteControl(DeviceExtension,
692: (C_SELECT | C_BUSY | C_BUS_ENABLE));
693: Fd8xxSetControl(DeviceExtension,
694: C_PARITY_ENABLE);
695:
696: ScsiPortStallExecution(2); // Delay 1200 nanoseconds (Bus-Settle + Bus-Clear).
697:
698: FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
699: (1 << DeviceExtension->InitiatorId) |
700: (1 << (DeviceExtension->ActiveLu->ActiveLuRequest->TargetId)));
701:
702: //
703: // Raise attention to get to message out phase.
704: //
705: Fd8xxSetControl(DeviceExtension,
706: C_ATTENTION);
707:
708: ScsiPortStallExecution(1); // Delay 90 nanoseconds (2 * Bus-Deskew).
709:
710: //
711: // Clear BUSY
712: //
713: Fd8xxClearControl(DeviceExtension,
714: C_BUSY);
715:
716: ScsiPortStallExecution(1); // Delay 400 nanoseconds (Bus-Settle).
717:
718: if (Fd8xxStatusCheck(DeviceExtension,
719: S_BUSY,
720: S_BUSY,
721: SELECTION_DELAY)) {
722:
723: ScsiPortStallExecution(1); // Delay 90 nanoseconds (2 * Bus-Deskew).
724:
725: //
726: // Selection is Ok. Clear SELECT line.
727: //
728: Fd8xxClearControl(DeviceExtension,
729: C_SELECT);
730:
731: DeviceExtension->ActiveLu->LuState = LS_IDENTIFY;
732: FdDebugPrint(0x01,
733: (0, "SELECT OK %x\n",
734: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId));
735: return;
736: }
737:
738: //
739: // Selection failed. Force SCSI bus back to Bus-Free.
740: //
741: Fd8xxWriteControl(DeviceExtension,
742: C_PARITY_ENABLE);
743:
744: FdDebugPrint(0x01,
745: (0, "SELECT FAILED %x\n",
746: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId));
747:
748: DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
749: DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
750: SRB_STATUS_SELECTION_TIMEOUT;
751: } // end Fd8xxSelect()
752:
753:
754: VOID
755: Fd8xxSendIdentify(
756: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
757: )
758:
759: /*++
760:
761: Routine Description:
762:
763: Send an identify message on the SCSI bus if the target will accept it.
764:
765: Arguments:
766:
767: DeviceExtension - Device adapter context pointer.
768:
769: Return Value:
770:
771: None
772:
773: --*/
774:
775: {
776: PUCHAR baseAddress = DeviceExtension->BaseAddress;
777: PSCSI_REQUEST_BLOCK srb = DeviceExtension->ActiveLu->ActiveLuRequest;
778:
779: FdDebugPrint(0x02,
780: (0, "FdSendIdentify: Device = %x, Lun = %x ",
781: DeviceExtension,
782: srb->Lun));
783:
784: if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
785:
786: ScsiPortLogError(DeviceExtension,
787: DeviceExtension->ActiveLu->ActiveLuRequest,
788: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
789: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
790: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
791: SP_REQUEST_TIMEOUT,
792: 12);
793: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
794: return;
795: }
796:
797: if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
798:
799: Fd8xxWriteControl(DeviceExtension,
800: (C_PARITY_ENABLE | C_BUS_ENABLE));
801:
802: ScsiPortStallExecution(1); // Delay 90 nanoseconds (2 * Bus-Deskew).
803:
804: //
805: // The target may wish to negotiate synchronous with us, in which
806: // case we will reject the message and go on to COMMAND phase.
807: //
808: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
809:
810: } else {
811:
812: //
813: // We still have an ABORT or RESET message to send, so keep the
814: // ATTENTION line high.
815: //
816: Fd8xxWriteControl(DeviceExtension,
817: (C_PARITY_ENABLE | C_BUS_ENABLE | C_ATTENTION));
818:
819: DeviceExtension->ActiveLu->LuState = LS_MSG_SPECIAL;
820: }
821:
822: //
823: // Some old SCSI-I devices want to skip MESSAGE OUT phase and go
824: // directly to COMMAND phase. We'll just let them do what they want.
825: // If the drive is really stupid, the error should get picked up in
826: // the phase to which it transitions, so just return and get on with
827: // life.
828: //
829: if (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_OUT) {
830:
831: FdDebugPrint(0x02, (0, "IDENTIFY sent.\n"));
832:
833: if (srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT) {
834:
835: DeviceExtension->ActiveLu->NoDisconnectActive = TRUE;
836: FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
837: (SCSIMESS_IDENTIFY |
838: srb->Lun));
839: } else {
840:
841: FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
842: (SCSIMESS_IDENTIFY_WITH_DISCON |
843: srb->Lun));
844: }
845:
846: } else {
847:
848: FdDebugPrint(0x02,
849: (0, "IDENTIFY not sent %x\n",
850: FD8XX_READ_STATUS(DeviceExtension->BaseAddress)));
851:
852: Fd8xxClearControl(DeviceExtension, C_ATTENTION);
853: ScsiPortStallExecution(1); // Delay 90 nanoseconds (2 * Bus-Deskew).
854:
855: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
856: }
857: } // end Fd8xxSendIdentify()
858:
859:
860: VOID
861: Fd8xxSendSpecialMessage(
862: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
863: )
864:
865: /*++
866:
867: Routine Description:
868:
869: Send an ABORT or RESET message on the SCSI bus if the target will accept
870: it.
871:
872: Arguments:
873:
874: DeviceExtension - Device adapter context pointer.
875:
876: Return Value:
877:
878: None
879:
880: --*/
881:
882: {
883: PUCHAR baseAddress = DeviceExtension->BaseAddress;
884: PSCSI_REQUEST_BLOCK srb = DeviceExtension->ActiveLu->ActiveLuRequest;
885:
886: FdDebugPrint(0x02,
887: (0, "FdSendSpecialMessage: Device = %x, Lun = %x ",
888: DeviceExtension,
889: srb->Lun));
890:
891: if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
892:
893: ScsiPortLogError(DeviceExtension,
894: DeviceExtension->ActiveLu->ActiveLuRequest,
895: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
896: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
897: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
898: SP_REQUEST_TIMEOUT,
899: 13);
900: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
901: return;
902: }
903:
904: Fd8xxClearControl(DeviceExtension,
905: C_ATTENTION);
906: ScsiPortStallExecution(1); // Delay 90 nanoseconds (2 * Bus-Deskew).
907:
908: if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
909:
910: FdDebugPrint(0x02, (0, "ABORT\n"));
911: FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
912: SCSIMESS_ABORT);
913: } else if (srb->Function == SRB_FUNCTION_RESET_DEVICE) {
914:
915: FdDebugPrint(0x02, (0, "BDR\n"));
916: FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
917: SCSIMESS_BUS_DEVICE_RESET);
918: } else {
919:
920: ScsiPortLogError(DeviceExtension,
921: srb,
922: srb->PathId,
923: srb->TargetId,
924: srb->Lun,
925: SP_PROTOCOL_ERROR,
926: 2);
927:
928: FdDebugPrint(0x02, (0, "NO-OP\n"));
929: FD8XX_WRITE_DATA(DeviceExtension->BaseAddress,
930: SCSIMESS_NO_OPERATION);
931: }
932:
933: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
934: } // end Fd8xxSendSpecialMessage()
935:
936:
937: VOID
938: Fd8xxSendCDB(
939: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
940: )
941:
942: /*++
943:
944: Routine Description:
945:
946: Send the SCSI Command Descriptor Block (CDB) to the indicated target/lun.
947:
948: Arguments:
949:
950: DeviceExtension - Device adapter context pointer.
951:
952: Return Value:
953:
954: None
955:
956: --*/
957:
958: {
959: UCHAR cdbLength = DeviceExtension->ActiveLu->ActiveLuRequest->CdbLength;
960: PUCHAR cdb = DeviceExtension->ActiveLu->ActiveLuRequest->Cdb;
961: PUCHAR baseAddress = DeviceExtension->BaseAddress;
962:
963: FdDebugPrint(0x02, (0, "SendCommand: "));
964:
965: Fd8xxSetControl(DeviceExtension, C_BUS_ENABLE);
966:
967: while ((cdbLength-- != 0) &&
968: Fd8xxWaitForRequestLine(DeviceExtension) &&
969: (FD8XX_READ_PHASE(baseAddress) == BP_COMMAND)) {
970:
971: FdDebugPrint(0x02, (0, "%x ", *cdb));
972:
973: FD8XX_WRITE_DATA(baseAddress,
974: *cdb++);
975: }
976:
977: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
978:
979: //
980: // Set up the running data pointer info for a possible data transfer.
981: //
982: DeviceExtension->CurDataPointer = DeviceExtension->ActiveLu->SavedDataPointer;
983: DeviceExtension->CurDataLength = DeviceExtension->ActiveLu->SavedDataLength;
984:
985: FdDebugPrint(0x02, (0, "New phase=%x\n", FD8XX_READ_PHASE(baseAddress)));
986: } // end Fd8xxSendCDB()
987:
988:
989: VOID
990: Fd8xxCopyData(
991: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
992: )
993:
994: /*++
995:
996: Routine Description:
997:
998: Copy data byte-for-byte to and from adapter. This is used to copy data
999: from the FD8XX controller to system memory and vice-versa. Each
1000: iteration of the outer-most "while" loop will transfer MAX_BUFFER_LENGTH
1001: bytes (i.e., 512 bytes - this is the size of the TMC-950 memory-mapped
1002: SCSI data register), or any fraction thereof.
1003:
1004: In theory, one should be able to use the x86 REP MOVB instruction (or
1005: other equivalent) to "blast" 512 bytes of data to this register. The
1006: REQ/ACK handshaking is done by the TMC-950 chip. In practice, there is
1007: one problem. The SCSI data register is "locked in" with the host bus
1008: (ISA). This host bus cannot be tied up for longer than a memory refresh
1009: cycle (15 useconds, I think). After completing a REQ/ACK cycle, the
1010: 950 chip frees the bus, then locks it again waiting for the assertion
1011: SCSI REQ line by the target. If REQ is not asserted within a memory
1012: refresh cycle, the 950 chip times out and frees the host bus so that a
1013: memory refresh can take place. This puts the 950 chip one byte "ahead"
1014: of the target, thus screwing up the rest of the block transfer.
1015:
1016: Future Domain refers to this problem as the "dribbling drive" because
1017: the target delays the assertion of the SCSI REQ line for longer than
1018: usual (probably because the firmware did some maintenance task between
1019: bytes like filling or draining its internal FIFO). SCSI places no
1020: limit on how long a target has to re-assert the SCSI REQ line, so we must
1021: provide a work-around.
1022:
1023: After a fair amount of research and experimentation, we have learned that
1024: "manually" handshaking the first x number of bytes, the last x number of
1025: bytes, or a combination of the two, solves the problem. The determination
1026: of x in either case is purely trial-and-error and is based on device
1027: characteristics.
1028:
1029: Arguments:
1030:
1031: DeviceExtension - Device adapter context pointer.
1032:
1033: Return Value:
1034:
1035: None
1036:
1037: --*/
1038:
1039: {
1040: PUCHAR baseAddress = DeviceExtension->BaseAddress;
1041: UCHAR byteBucket = 0;
1042: UCHAR wantedState;
1043:
1044: register ULONG moveCount;
1045: register ULONG headCount;
1046: register ULONG tailCount;
1047:
1048: if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
1049:
1050: ScsiPortLogError(DeviceExtension,
1051: DeviceExtension->ActiveLu->ActiveLuRequest,
1052: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
1053: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
1054: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
1055: SP_REQUEST_TIMEOUT,
1056: 14);
1057: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
1058: return;
1059: }
1060:
1061: wantedState = FD8XX_READ_PHASE(baseAddress);
1062:
1063: FdDebugPrint(0x04,
1064: (0, "CopyData: from %s for %x ",
1065: (wantedState == BP_DATA_IN) ? "Target" : "Memory",
1066: DeviceExtension->CurDataLength));
1067:
1068: if (wantedState == BP_DATA_IN) {
1069:
1070: //
1071: // The target will drive the SCSI data lines in DATA_IN phase.
1072: //
1073: Fd8xxClearControl(DeviceExtension, C_BUS_ENABLE);
1074: } else {
1075:
1076: //
1077: // We will drive the SCSI data lines in DATA_OUT phase.
1078: //
1079: Fd8xxSetControl(DeviceExtension, C_BUS_ENABLE);
1080: }
1081:
1082: while (FD8XX_READ_PHASE(baseAddress) == wantedState) {
1083:
1084: if (DeviceExtension->CurDataLength == 0) {
1085:
1086: //
1087: // Overrun condition. Read (or write) bytes until
1088: // out of DATA phase.
1089: //
1090: FdDebugPrint(0x04, (0, "overrun "));
1091:
1092: while ((FD8XX_READ_PHASE(baseAddress) == wantedState) &&
1093: Fd8xxWaitForRequestLine(DeviceExtension)) {
1094:
1095: FdDebugPrint(0x04, (0, "."));
1096:
1097: if (wantedState == BP_DATA_IN) {
1098:
1099: //
1100: // Throw the byte away since there's nowhere to put it.
1101: //
1102: byteBucket = FD8XX_READ_DATA(baseAddress);
1103: } else {
1104:
1105: //
1106: // Write a zero to the device.
1107: //
1108: FD8XX_WRITE_DATA(baseAddress, byteBucket);
1109: }
1110: }
1111:
1112: DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
1113: SRB_STATUS_DATA_OVERRUN;
1114: DeviceExtension->ActiveLu->OverRunCount++;
1115: if (DeviceExtension->ActiveLu->OverRunCount >= 5) {
1116: FdDebugPrint(0x200, (0, "Fd8xx: Turned on handshake\n"));
1117: DeviceExtension->ActiveLu->HandShakeAllData = TRUE;
1118: }
1119: continue;
1120: }
1121:
1122: //
1123: // First, copy the first bytes (if any) with REQ/ACK handshaking...
1124: //
1125: // NOTE: Some devices are REALLY slow when transferring inquiry
1126: // data. So, we'll treat any transfer less than a block
1127: // as a SLOW transfer. Also, all transfers performed when
1128: // the DISABLE_DISCONNECT bit was on in the SRB are done in
1129: // the slower, handshake per byte way. Finally some devices
1130: // tend to "dribble" bytes and need to have a handshake all
1131: // the time. These are found by a threshold of overruns being
1132: // encountered above. The single OR on the HandShake and SixByte
1133: // booleans is on purpose. This generates an or and conditional
1134: // jump where a double OR generates more code.
1135: //
1136: if (((DeviceExtension->ActiveLu->NoDisconnectActive) &&
1137: (DeviceExtension->ActiveLu->OverRunCount != 0)) ||
1138: (DeviceExtension->ActiveLu->HandShakeAllData |
1139: DeviceExtension->ActiveLu->SixByteCDBActive)) {
1140:
1141: headCount = DeviceExtension->CurDataLength;
1142: } else {
1143: if (MAX_BUFFER_LENGTH > DeviceExtension->CurDataLength) {
1144:
1145: headCount = DeviceExtension->CurDataLength;
1146: } else {
1147:
1148: if (DeviceExtension->CurDataLength & (MAX_BUFFER_LENGTH - 1)) {
1149:
1150: //
1151: // If the expected transfer is not a block multiple, do it
1152: // all the slow way. This will correct problems with NEC
1153: // CD drives when doing NEC CD audio commands.
1154: //
1155: headCount = DeviceExtension->CurDataLength;
1156: } else {
1157: headCount = min(MAX_HEAD_LENGTH,
1158: DeviceExtension->CurDataLength);
1159: }
1160: }
1161: }
1162:
1163: moveCount = 0;
1164:
1165: while (moveCount != headCount) {
1166:
1167: if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
1168: ScsiPortLogError(DeviceExtension,
1169: DeviceExtension->ActiveLu->ActiveLuRequest,
1170: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
1171: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
1172: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
1173: SP_REQUEST_TIMEOUT,
1174: 11);
1175: break;
1176: }
1177:
1178: if (FD8XX_READ_PHASE(baseAddress) == BP_DATA_IN) {
1179:
1180: *((PUCHAR) DeviceExtension->CurDataPointer++) =
1181: FD8XX_READ_DATA(baseAddress);
1182: } else if (FD8XX_READ_PHASE(baseAddress) == BP_DATA_OUT) {
1183:
1184: FD8XX_WRITE_DATA(baseAddress,
1185: *((PUCHAR) DeviceExtension->CurDataPointer++));
1186: } else {
1187:
1188: //
1189: // Account for the number of bytes moved.
1190: //
1191: DeviceExtension->CurDataLength -= moveCount;
1192: goto Fd8xxCopyData_CheckNextPhase;
1193: }
1194: moveCount++;
1195: }
1196:
1197: DeviceExtension->CurDataLength -= moveCount;
1198:
1199: if (DeviceExtension->CurDataLength == 0) {
1200: goto Fd8xxCopyData_CheckNextPhase;
1201: }
1202:
1203: //
1204: // Now, calculate the the middle chunk for transfer without hanshaking...
1205: //
1206: moveCount = min(
1207: (DeviceExtension->CurDataLength & (MAX_BUFFER_LENGTH - 1)),
1208: MAX_BUFFER_LENGTH);
1209:
1210: if (moveCount >= MAX_TAIL_LENGTH) {
1211:
1212: moveCount -= MAX_TAIL_LENGTH;
1213: }
1214:
1215: if (wantedState == BP_DATA_IN) {
1216:
1217: ScsiPortReadRegisterBufferUchar((baseAddress + READ_SCSI),
1218: ((PUCHAR) DeviceExtension->CurDataPointer),
1219: moveCount);
1220: } else {
1221:
1222: ScsiPortWriteRegisterBufferUchar((baseAddress + WRITE_SCSI),
1223: ((PUCHAR) DeviceExtension->CurDataPointer),
1224: moveCount);
1225: }
1226:
1227: DeviceExtension->CurDataPointer += moveCount;
1228: DeviceExtension->CurDataLength -= moveCount;
1229:
1230: //
1231: // Finally, copy the last bytes (if any) with REQ/ACK handshaking...
1232: //
1233: tailCount = min(MAX_TAIL_LENGTH, DeviceExtension->CurDataLength);
1234: moveCount = 0;
1235:
1236: while ((moveCount != tailCount) &&
1237: (FD8XX_READ_PHASE(baseAddress) != BP_BUS_FREE) &&
1238: Fd8xxWaitForRequestLine(DeviceExtension)) {
1239:
1240: if (FD8XX_READ_PHASE(baseAddress) == BP_DATA_IN) {
1241:
1242: *((PUCHAR) DeviceExtension->CurDataPointer++) =
1243: FD8XX_READ_DATA(baseAddress);
1244: } else if (FD8XX_READ_PHASE(baseAddress) == BP_DATA_OUT) {
1245:
1246: FD8XX_WRITE_DATA(baseAddress,
1247: *((PUCHAR) DeviceExtension->CurDataPointer++));
1248: } else {
1249:
1250: DeviceExtension->CurDataLength -= moveCount;
1251: goto Fd8xxCopyData_CheckNextPhase;
1252: }
1253: moveCount++;
1254: }
1255:
1256: DeviceExtension->CurDataLength -= moveCount;
1257:
1258: if ((FD8XX_READ_PHASE(baseAddress) == BP_BUS_FREE) ||
1259: (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE)) {
1260:
1261: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
1262: FdDebugPrint(0x04, (0, "NO REQUEST\n"));
1263: return;
1264: }
1265: }
1266:
1267: Fd8xxCopyData_CheckNextPhase:
1268:
1269: if (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_IN) {
1270:
1271: //
1272: // The device most likely wants to disconnect.
1273: //
1274: DeviceExtension->ActiveLu->LuState = LS_MSG_IN;
1275:
1276: } else if (FD8XX_READ_PHASE(baseAddress) == BP_STATUS) {
1277:
1278: if (DeviceExtension->CurDataLength != 0) {
1279:
1280: //
1281: // We have an underrun condition. Update the count of bytes transferred.
1282: //
1283: FdDebugPrint(0x04, (0, "underrun "));
1284: DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
1285: SRB_STATUS_DATA_OVERRUN;
1286: DeviceExtension->ActiveLu->ActiveLuRequest->DataTransferLength -=
1287: DeviceExtension->CurDataLength;
1288: } else if (FD8XX_READ_STATUS(baseAddress) & S_PARITY) {
1289:
1290: //
1291: // We have a parity error.
1292: //
1293: FdDebugPrint(0x04, (0, "Parity Error! "));
1294: DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
1295: SRB_STATUS_PARITY_ERROR;
1296: ScsiPortLogError(DeviceExtension,
1297: DeviceExtension->ActiveLu->ActiveLuRequest,
1298: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
1299: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
1300: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
1301: SP_BUS_PARITY_ERROR,
1302: 3);
1303: }
1304:
1305: DeviceExtension->ActiveLu->LuState = LS_STATUS;
1306:
1307: } else {
1308:
1309: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
1310: FdDebugPrint(0x04, (0, "OTHER\n"));
1311: return;
1312: }
1313:
1314: FdDebugPrint(0x04, (0, "Done\n"));
1315: } // end Fd8xxCopyData()
1316:
1317:
1318: VOID
1319: Fd8xxStatus(
1320: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
1321: )
1322:
1323: /*++
1324:
1325: Routine Description:
1326:
1327: This routine will obtain the status from the target.
1328:
1329: Arguments:
1330:
1331: DeviceExtension - Device adapter context pointer.
1332:
1333: Return Value:
1334:
1335: None
1336:
1337: --*/
1338:
1339: {
1340: UCHAR status;
1341: UCHAR srbStatus;
1342: PSCSI_REQUEST_BLOCK srb = DeviceExtension->ActiveLu->ActiveLuRequest;
1343:
1344: Fd8xxClearControl(DeviceExtension, C_BUS_ENABLE);
1345:
1346: if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
1347:
1348: DeviceExtension->ActiveLu->LuState = LS_UNDETERMINED;
1349: ScsiPortLogError(DeviceExtension,
1350: DeviceExtension->ActiveLu->ActiveLuRequest,
1351: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
1352: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
1353: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
1354: SP_REQUEST_TIMEOUT,
1355: 17);
1356: return;
1357: }
1358:
1359: status = FD8XX_READ_DATA(DeviceExtension->BaseAddress);
1360:
1361: //
1362: // Save this away for the driver above.
1363: //
1364: srb->ScsiStatus = status;
1365:
1366: FdDebugPrint(0x02, (0, "FdStatus: Returned status byte=%x\n", status));
1367:
1368: switch (status) {
1369:
1370: case SCSISTAT_GOOD:
1371: case SCSISTAT_CONDITION_MET:
1372: case SCSISTAT_INTERMEDIATE:
1373: case SCSISTAT_INTERMEDIATE_COND_MET:
1374:
1375: srbStatus = SRB_STATUS_SUCCESS;
1376: break;
1377:
1378: case SCSISTAT_CHECK_CONDITION:
1379: case SCSISTAT_COMMAND_TERMINATED:
1380:
1381: srbStatus = SRB_STATUS_ERROR;
1382: break;
1383:
1384: case SCSISTAT_BUSY:
1385: case SCSISTAT_RESERVATION_CONFLICT:
1386: case SCSISTAT_QUEUE_FULL:
1387: default:
1388:
1389: srbStatus = SRB_STATUS_BUSY;
1390: break;
1391: }
1392:
1393: //
1394: // If some error condition already occurred (e.g., parity error), we'll
1395: // let that one take priority.
1396: //
1397: if (srb->SrbStatus == SRB_STATUS_PENDING)
1398: srb->SrbStatus = srbStatus;
1399:
1400: DeviceExtension->ActiveLu->LuState = LS_MSG_IN;
1401: } // end Fd8xxStatus()
1402:
1403:
1404: VOID
1405: Fd8xxMessageIn(
1406: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
1407: )
1408:
1409: /*++
1410:
1411: Routine Description:
1412:
1413: This routine will receive the message from the target.
1414:
1415: Arguments:
1416:
1417: DeviceExtension - Device adapter context pointer.
1418:
1419: Return Value:
1420:
1421: None
1422:
1423: --*/
1424:
1425: {
1426: PSPECIFIC_LU_EXTENSION luExtension = DeviceExtension->ActiveLu;
1427: PSCSI_REQUEST_BLOCK srb = luExtension->ActiveLuRequest;
1428: PUCHAR baseAddress = DeviceExtension->BaseAddress;
1429: UCHAR msg;
1430:
1431: Fd8xxClearControl(DeviceExtension,
1432: C_BUS_ENABLE);
1433:
1434: luExtension->LuState = LS_UNDETERMINED;
1435:
1436: if (Fd8xxWaitForRequestLine(DeviceExtension) == FALSE) {
1437:
1438: ScsiPortLogError(DeviceExtension,
1439: DeviceExtension->ActiveLu->ActiveLuRequest,
1440: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
1441: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
1442: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
1443: SP_REQUEST_TIMEOUT,
1444: 15);
1445: return;
1446: }
1447:
1448: msg = FD8XX_READ_DATA(baseAddress);
1449:
1450: FdDebugPrint(0x08, (0, "FdMessageIn: message=%x -- ", msg));
1451:
1452: if (msg == SCSIMESS_DISCONNECT) {
1453:
1454: FdDebugPrint(0x08, (0, "DISCONNECT\n"));
1455:
1456: luExtension->LuState = LS_DISCONNECTED;
1457: luExtension->SavedDataPointer = DeviceExtension->CurDataPointer;
1458: luExtension->SavedDataLength = DeviceExtension->CurDataLength;
1459:
1460: DeviceExtension->ActiveLu = NULL;
1461:
1462: if (DeviceExtension->ContinueTimer) {
1463:
1464: //
1465: // Still need the timer to insure interrupts.
1466: //
1467: DeviceExtension->ExpectingInterrupt = TRUE;
1468: ScsiPortNotification(RequestTimerCall,
1469: DeviceExtension,
1470: Fd8xxTimer,
1471: FD8xx_TIMER_VALUE);
1472: }
1473:
1474: } else if (msg == SCSIMESS_SAVE_DATA_POINTER) {
1475:
1476: FdDebugPrint(0x08, (0, "SAVE POINTERS\n"));
1477:
1478: luExtension->SavedDataPointer = DeviceExtension->CurDataPointer;
1479: luExtension->SavedDataLength = DeviceExtension->CurDataLength;
1480:
1481: } else if ((msg == SCSIMESS_COMMAND_COMPLETE) ||
1482: (msg == SCSIMESS_LINK_CMD_COMP) ||
1483: (msg == SCSIMESS_LINK_CMD_COMP_W_FLAG)) {
1484:
1485: FdDebugPrint(0x08, (0, "COMPLETION\n"));
1486:
1487: luExtension->LuState = LS_COMPLETE;
1488:
1489: } else if (msg == SCSIMESS_RESTORE_POINTERS) {
1490:
1491: FdDebugPrint(0x08, (0, "RESTORE POINTERS\n"));
1492:
1493: //
1494: // The Srb is already correct; just restore the adapter context
1495: // pointers.
1496: //
1497: DeviceExtension->CurDataPointer = luExtension->SavedDataPointer;
1498: DeviceExtension->CurDataLength = luExtension->SavedDataLength;
1499:
1500: } else if ((msg == SCSIMESS_NO_OPERATION) ||
1501: (msg == SCSIMESS_MESSAGE_REJECT)) {
1502:
1503: if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {
1504:
1505: //
1506: // We may be talking to a stupid device that cannot handle an
1507: // identify message. If this is the case, there's no telling
1508: // what it'll do next. Just let it take us where it wants and
1509: // hope we can recover.
1510: //
1511: FdDebugPrint(0x08, (0, "Identify "));
1512:
1513: } else {
1514:
1515: //
1516: // We were trying to tell the device to abort or reset and it
1517: // puked on the message. It's probably some old device that
1518: // cannot support these messages. So, just let the device take
1519: // us where it wants. If it's to cammand phase, we'll error this
1520: // out since there are no command bytes are associated w/ these
1521: // messages. Hopefully, it'll at least take us back to bus free.
1522: //
1523: srb->SrbStatus = SRB_STATUS_MESSAGE_REJECTED;
1524: FdDebugPrint(0x08, (0, "Abort/Reset "));
1525: }
1526:
1527: FdDebugPrint(0x08, (0, "REJECT\n"));
1528:
1529: } else if (msg == SCSIMESS_EXTENDED_MESSAGE) {
1530:
1531: UCHAR xMsgType;
1532: UCHAR xMsgLength;
1533:
1534: FdDebugPrint(0x08, (0, "EXTENDED "));
1535:
1536: if (Fd8xxStatusCheck(DeviceExtension,
1537: BP_MESSAGE_IN,
1538: BP_MESSAGE_IN,
1539: REQUEST_SPIN_WAIT)) {
1540:
1541: xMsgLength = FD8XX_READ_DATA(baseAddress);
1542: FdDebugPrint(0x08, (0, "length=%x ", xMsgLength));
1543:
1544: } else {
1545:
1546: //
1547: // This better NEVER happen! If it does, this device is
1548: // BRAINDEAD!!
1549: //
1550: goto Fd8xxMessageIn_PhaseSequenceFailure;
1551: }
1552:
1553: if (Fd8xxStatusCheck(DeviceExtension,
1554: BP_MESSAGE_IN,
1555: BP_MESSAGE_IN,
1556: REQUEST_SPIN_WAIT)) {
1557:
1558: xMsgType = FD8XX_READ_DATA(baseAddress);
1559: } else {
1560:
1561: goto Fd8xxMessageIn_PhaseSequenceFailure;
1562: }
1563:
1564: xMsgLength--; // Received one of the bytes.
1565:
1566: if (xMsgType == SCSIMESS_MODIFY_DATA_POINTER) {
1567:
1568: LONG offset = 0;
1569:
1570: FdDebugPrint(0x08, (0, "MODIFY "));
1571: while (xMsgLength-- != 0) {
1572:
1573: if (Fd8xxStatusCheck(DeviceExtension,
1574: BP_MESSAGE_IN,
1575: BP_MESSAGE_IN,
1576: REQUEST_SPIN_WAIT)) {
1577:
1578: *(((PUCHAR) &(offset)) + (3 - xMsgLength)) =
1579: FD8XX_READ_DATA(baseAddress);
1580: } else {
1581:
1582: goto Fd8xxMessageIn_PhaseSequenceFailure;
1583: }
1584: }
1585:
1586: //
1587: // All message bytes for this message were read. We can now
1588: // go and update our pointers as indicated by the juse-read
1589: // message. Keep in mind that the value of offset is a twos-
1590: // compliment value (i.e., negative).
1591: //
1592: FdDebugPrint(0x08, (0, "offset=%x\n", offset));
1593: DeviceExtension->CurDataPointer += offset;
1594: DeviceExtension->CurDataLength -= offset;
1595:
1596: } else {
1597:
1598: goto Fd8xxMessageIn_NotImplemented;
1599: }
1600:
1601: } else {
1602:
1603: Fd8xxMessageIn_NotImplemented:
1604:
1605: FdDebugPrint(0x08, (0, "NOT IMPLEMENTED\n"));
1606:
1607: Fd8xxSetControl(DeviceExtension, C_ATTENTION);
1608: ScsiPortStallExecution(1); // Delay 90 nanoseconds (2 * Bus-Deskew).
1609:
1610: while (Fd8xxWaitForRequestLine(DeviceExtension) &&
1611: (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_IN)) {
1612:
1613: //
1614: // Ignore the rest of this message.
1615: //
1616: msg = FD8XX_READ_DATA(baseAddress);
1617: }
1618:
1619: if (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_OUT) {
1620:
1621: Fd8xxSetControl(DeviceExtension, C_BUS_ENABLE);
1622: Fd8xxClearControl(DeviceExtension, C_ATTENTION);
1623: ScsiPortStallExecution(1); // Delay 90 nanoseconds.
1624: FD8XX_WRITE_DATA(baseAddress, SCSIMESS_MESSAGE_REJECT);
1625: }
1626:
1627: Fd8xxClearControl(DeviceExtension, C_ATTENTION);
1628: }
1629:
1630: return;
1631:
1632: Fd8xxMessageIn_PhaseSequenceFailure:
1633:
1634: srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
1635: ScsiPortLogError(DeviceExtension,
1636: srb,
1637: srb->PathId,
1638: srb->TargetId,
1639: srb->Lun,
1640: SP_PROTOCOL_ERROR,
1641: 4);
1642:
1643: FdDebugPrint(0x08,
1644: (0,
1645: "PHS SEQ ERROR=%x\n",
1646: FD8XX_READ_DATA(baseAddress)));
1647: return;
1648:
1649: } // end Fd8xxMessageIn()
1650:
1651:
1652: VOID
1653: Fd8xxNotifyCompletion(
1654: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
1655: )
1656:
1657: /*++
1658:
1659: Routine Description:
1660:
1661: This routine will perform any clean up operations for the Srb
1662: and notify the ScsiPort driver of completion.
1663:
1664: Arguments:
1665:
1666: DeviceExtension - Device adapter context pointer.
1667:
1668: Return Value:
1669:
1670: None
1671:
1672: --*/
1673:
1674: {
1675: PSPECIFIC_LU_EXTENSION luExtension = DeviceExtension->ActiveLu;
1676: PSCSI_REQUEST_BLOCK srb = luExtension->ActiveLuRequest;
1677:
1678: FdDebugPrint(0x110,
1679: (0, "FdComplete Dev = %x, Srb = %x, Srbstat = %x, Scsistat = %x\n",
1680: DeviceExtension,
1681: srb,
1682: srb->SrbStatus,
1683: srb->ScsiStatus));
1684:
1685: if (srb != NULL) {
1686: if (srb->SrbStatus == SRB_STATUS_PENDING) {
1687:
1688: srb->SrbStatus = SRB_STATUS_ERROR;
1689: ScsiPortLogError(DeviceExtension,
1690: luExtension->ActiveLuRequest,
1691: luExtension->ActiveLuRequest->PathId,
1692: luExtension->ActiveLuRequest->TargetId,
1693: luExtension->ActiveLuRequest->Lun,
1694: SP_INTERNAL_ADAPTER_ERROR,
1695: 5);
1696: }
1697: }
1698:
1699: luExtension->ActiveLuRequest = NULL;
1700: luExtension->NoDisconnectActive = FALSE;
1701: DeviceExtension->ActiveLu = NULL;
1702:
1703: //
1704: // Call notification routine.
1705: //
1706: if (srb != NULL) {
1707: ScsiPortNotification(RequestComplete,
1708: (PVOID) DeviceExtension,
1709: srb);
1710: }
1711:
1712: if (!(luExtension->AbortBeingAttempted)) {
1713:
1714: //
1715: // Adapter ready for next request.
1716: //
1717: ScsiPortNotification(NextRequest,
1718: DeviceExtension,
1719: NULL);
1720: }
1721:
1722: } // end Fd8xxNotifyCompletion()
1723:
1724:
1725: VOID
1726: Fd8xxRunPhase(
1727: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
1728: )
1729:
1730: /*++
1731:
1732: Routine Description:
1733:
1734: This routine runs through the bus phases until some type of completion
1735: indication is received. This can be when a message informing the host
1736: that the target will be disconnecting is received or when the SCSI bus
1737: goes to a free state.
1738:
1739: Arguments:
1740:
1741: DeviceExtension - Device adapter context pointer.
1742:
1743: Return Value:
1744:
1745: None.
1746:
1747: --*/
1748:
1749: {
1750: PUCHAR baseAddress = DeviceExtension->BaseAddress;
1751: ULONG undetermined = 0;
1752:
1753: while (DeviceExtension->ActiveLu != NULL) {
1754:
1755: switch (DeviceExtension->ActiveLu->LuState) {
1756:
1757: case LS_UNDETERMINED:
1758: Fd8xxDetermineNextState(DeviceExtension);
1759:
1760: if (undetermined++ == REQUEST_SPIN_WAIT) {
1761:
1762: //
1763: // Some CD-ROM drives like to be SCSI bus hogs
1764: // and hold the SCSI bus in COMMAND phase while feching
1765: // data (they also conveniently skip message out phase
1766: // so you can't tell it that you allow disconnect)!! So,
1767: // we better not time out if this happens.
1768: //
1769: if ((FD8XX_READ_PHASE(baseAddress) | S_REQUEST) !=
1770: BP_COMMAND) {
1771: FdDebugPrint(0x01, (0, "NO REQUEST\n"));
1772:
1773: DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
1774: DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
1775: SRB_STATUS_PHASE_SEQUENCE_FAILURE;
1776:
1777: ScsiPortLogError(DeviceExtension,
1778: DeviceExtension->ActiveLu->ActiveLuRequest,
1779: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
1780: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
1781: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
1782: SP_PROTOCOL_ERROR,
1783: 16);
1784: }
1785: }
1786: break;
1787:
1788: case LS_ARBITRATE:
1789: Fd8xxArbitrate(DeviceExtension);
1790: break;
1791:
1792: case LS_SELECT:
1793: Fd8xxSelect(DeviceExtension);
1794: break;
1795:
1796: case LS_IDENTIFY:
1797: Fd8xxSendIdentify(DeviceExtension);
1798: break;
1799:
1800: case LS_MSG_SPECIAL:
1801: Fd8xxSendSpecialMessage(DeviceExtension);
1802: break;
1803:
1804: case LS_COMMAND:
1805: Fd8xxSendCDB(DeviceExtension);
1806: break;
1807:
1808: case LS_DATA:
1809: Fd8xxCopyData(DeviceExtension);
1810: break;
1811:
1812: case LS_STATUS:
1813: Fd8xxStatus(DeviceExtension);
1814: break;
1815:
1816: case LS_MSG_IN:
1817: Fd8xxMessageIn(DeviceExtension);
1818: break;
1819:
1820: case LS_COMPLETE:
1821: Fd8xxNotifyCompletion(DeviceExtension);
1822: break;
1823:
1824: default:
1825:
1826: DeviceExtension->ActiveLu->LuState = LS_COMPLETE;
1827: DeviceExtension->ActiveLu->ActiveLuRequest->SrbStatus =
1828: SRB_STATUS_PHASE_SEQUENCE_FAILURE;
1829:
1830: ScsiPortLogError(DeviceExtension,
1831: DeviceExtension->ActiveLu->ActiveLuRequest,
1832: DeviceExtension->ActiveLu->ActiveLuRequest->PathId,
1833: DeviceExtension->ActiveLu->ActiveLuRequest->TargetId,
1834: DeviceExtension->ActiveLu->ActiveLuRequest->Lun,
1835: SP_PROTOCOL_ERROR,
1836: 6);
1837: break;
1838: }
1839: }
1840: } // end Fd8xxRunPhase()
1841:
1842:
1843: VOID
1844: Fd8xxReenableAdapterInterrupts(
1845: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
1846: )
1847: /*++
1848:
1849: Routine Description:
1850:
1851: This routine doesn't really do anything. It is here to keep the
1852: SCSI port driver happy about what it can do with interrupts.
1853: The only time we should enable interrupts on selection is when we
1854: get a disconnect from a target.
1855:
1856: Arguments:
1857:
1858: DeviceExtension - Device adapter context pointer.
1859:
1860: Return Value:
1861:
1862: None.
1863:
1864: --*/
1865:
1866: {
1867: //
1868: // Re-enable interrupts on selection.
1869: //
1870: Fd8xxSetControl(DeviceExtension, C_INT_ENABLE);
1871:
1872: } // end Fd8xxReenableAdapterInterrupts()
1873:
1874:
1875: VOID
1876: Fd8xxDoReconnect(
1877: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
1878: )
1879:
1880: /*++
1881:
1882: Routine Description:
1883:
1884: This routine handles reconnecting devices. It basically plucks the
1885: target ID out of reselection phase, followed by the LUN out of
1886: message in phase (from the IDENTIFY message). Then, after validating
1887: the target/lun combination, starts up the state machine again for
1888: the reconnecting device.
1889:
1890: This routine should be called with interrupts enabled.
1891:
1892: Arguments:
1893:
1894: DeviceExtension - Device adapter context pointer.
1895:
1896: Return Value:
1897:
1898: None.
1899:
1900: --*/
1901:
1902: {
1903: PUCHAR baseAddress = DeviceExtension->BaseAddress;
1904: PSPECIFIC_LU_EXTENSION luExtension;
1905: USHORT busFreeTimeout;
1906: UCHAR target; // bit value returned from target
1907: UCHAR targetID; // numeric value of target ID.
1908: UCHAR lunID; // numeric value of LUN ID.
1909:
1910: //
1911: // Wait for the target to drop busy, which is the TRUE beginning of
1912: // reselection phase. If BUSY is not dropped within the indicated time,
1913: // abort the interrupt (and the reselect).
1914: //
1915: if (Fd8xxStatusCheck(DeviceExtension,
1916: BP_RESELECT,
1917: BP_RESELECT,
1918: RESELECTION_WAIT) == FALSE) {
1919:
1920: FdDebugPrint(0x20,
1921: (0, "BUSY not dropped: Status=%x\n",
1922: FD8XX_READ_STATUS(baseAddress)));
1923:
1924: goto Fd8xxDoReconnect_InvalidReselection;
1925: }
1926:
1927: //
1928: // Delay a bit to allow for something close to a bus settle time
1929: // before reading the target id bits.
1930: //
1931: ScsiPortStallExecution(1);
1932:
1933: //
1934: // Try to figure out who is reselecting.
1935: //
1936: target = (FD8XX_READ_DATA(baseAddress) & ~(1 << DeviceExtension->InitiatorId));
1937:
1938: FdDebugPrint(0x20, (0, "Target data=%x ", target));
1939:
1940: //
1941: // Convert the bit oriented target into a number.
1942: //
1943: for (targetID = ((UCHAR) -1); target != 0; target >>= 1) {
1944:
1945: targetID++;
1946: }
1947: FdDebugPrint(0x20, (0, "Target Id=%x ", targetID));
1948:
1949: //
1950: // Answer the reselection by raising busy. This should cause the target
1951: // to transition to MESSAGE IN phase so that we cen figure out which LUN
1952: // is associated with the reselecting target.
1953: //
1954: ScsiPortStallExecution(1); // Delay 400 nanoseconds (Bus-Settle).
1955: Fd8xxSetControl(DeviceExtension, C_BUSY);
1956:
1957: if (Fd8xxStatusCheck(DeviceExtension,
1958: BP_MESSAGE_IN,
1959: BP_MESSAGE_IN,
1960: REQUEST_SPIN_WAIT) == FALSE) {
1961:
1962: FdDebugPrint(0x20,
1963: (0, "REQ not raised: Status=%x\n",
1964: FD8XX_READ_STATUS(baseAddress)));
1965:
1966: goto Fd8xxDoReconnect_InvalidReselection;
1967: }
1968:
1969: //
1970: // The target should be driving BUSY now, so we should de-assert it in
1971: // control register (keep in mind that BUSY is or-tied).
1972: //
1973: Fd8xxClearControl(DeviceExtension, C_BUSY);
1974:
1975: lunID = FD8XX_READ_DATA(baseAddress) & (SCSI_MAXIMUM_LOGICAL_UNITS - 1);
1976: FdDebugPrint(0x20, (0, "Lun Id=%x ", lunID));
1977:
1978: if ((targetID >= SCSI_MAXIMUM_TARGETS) ||
1979: (lunID >= SCSI_MAXIMUM_LOGICAL_UNITS)) {
1980:
1981: FdDebugPrint(0x20,
1982: (0, "BAD Target/Lun: %x/%x\n",
1983: targetID, lunID));
1984:
1985: goto Fd8xxDoReconnect_InvalidReselection;
1986: }
1987:
1988: //
1989: // Re-enable adapter interrupts. Don't do this if we're being called
1990: // by the arbitration routine, because they will never have been turned
1991: // off in the first place, and we'll only confuse the port driver.
1992: //
1993: if (DeviceExtension->SavedLu == NULL) {
1994:
1995: ScsiPortNotification(CallDisableInterrupts,
1996: DeviceExtension,
1997: Fd8xxReenableAdapterInterrupts);
1998: }
1999:
2000: luExtension = ScsiPortGetLogicalUnit(DeviceExtension,
2001: DeviceExtension->PathId,
2002: targetID,
2003: lunID);
2004:
2005: if (luExtension == NULL) {
2006:
2007: //
2008: // This is the pathological case. This would indicate that when
2009: // the target ID bits were read there was a parity error or some
2010: // other problem that made it look like a reselection from a phantom
2011: // device.
2012: //
2013:
2014: ScsiPortLogError(DeviceExtension,
2015: NULL,
2016: 0,
2017: 0,
2018: 0,
2019: SP_INVALID_RESELECTION,
2020: (0x07 << 16) | (targetID << 8) | lunID);
2021: Fd8xxResetBus(DeviceExtension, DeviceExtension->PathId);
2022: ScsiPortNotification(ResetDetected, DeviceExtension, NULL);
2023: return;
2024: }
2025:
2026: if (luExtension->ActiveLuRequest == NULL) {
2027:
2028: //
2029: // This reconnect is not expected. There is no request for the
2030: // device.
2031: //
2032: ScsiPortLogError(DeviceExtension,
2033: NULL,
2034: 0,
2035: 0,
2036: 0,
2037: SP_INVALID_RESELECTION,
2038: (0x17 << 16) | (targetID << 8) | lunID);
2039: Fd8xxResetBus(DeviceExtension, DeviceExtension->PathId);
2040: ScsiPortNotification(ResetDetected, DeviceExtension, NULL);
2041: return;
2042: }
2043:
2044: if ((luExtension->AbortBeingAttempted) &&
2045: (DeviceExtension->SavedLu != NULL)) {
2046:
2047: //
2048: // We're being called while trying to arbitrate for an abort.
2049: // The LUN we're trying to abort is reconnecting, so complete the
2050: // abort from here, and force the arbitration routine to exit.
2051: //
2052: DeviceExtension->SavedLu->LuState = LS_COMPLETE;
2053: DeviceExtension->SavedLu->ActiveLuRequest->SrbStatus = SRB_STATUS_SUCCESS;
2054: goto Fd8xxDoReconnect_AbortReconnect;
2055: }
2056:
2057: DeviceExtension->CurDataPointer = luExtension->SavedDataPointer;
2058: DeviceExtension->CurDataLength = luExtension->SavedDataLength;
2059: DeviceExtension->ActiveLu = luExtension;
2060:
2061: luExtension->LuState = LS_UNDETERMINED;
2062:
2063: Fd8xxRunPhase(DeviceExtension);
2064:
2065: return;
2066:
2067: Fd8xxDoReconnect_InvalidReselection:
2068:
2069: ScsiPortLogError(DeviceExtension,
2070: NULL,
2071: 0,
2072: 0,
2073: 0,
2074: SP_INVALID_RESELECTION,
2075: (0x27 << 16) | (targetID << 8) | lunID);
2076:
2077: if (DeviceExtension->SavedLu == NULL) {
2078:
2079: ScsiPortNotification(CallDisableInterrupts,
2080: DeviceExtension,
2081: Fd8xxReenableAdapterInterrupts);
2082: }
2083:
2084: Fd8xxDoReconnect_AbortReconnect:
2085:
2086: //
2087: // Attempt to send an abort message to the target.
2088: //
2089: Fd8xxSetControl(DeviceExtension, C_ATTENTION);
2090: ScsiPortStallExecution(1); // Delay 90 nanoseconds (2 * Bus-Deskew).
2091:
2092: while (Fd8xxWaitForRequestLine(DeviceExtension) &&
2093: (FD8XX_READ_PHASE(baseAddress) != BP_MESSAGE_OUT)) {
2094:
2095: FD8XX_READ_DATA(baseAddress);
2096: }
2097:
2098: Fd8xxSetControl(DeviceExtension, C_BUS_ENABLE);
2099: Fd8xxClearControl(DeviceExtension, C_ATTENTION);
2100: ScsiPortStallExecution(1); // Delay 90 nanoseconds.
2101:
2102: if (FD8XX_READ_PHASE(baseAddress) == BP_MESSAGE_OUT) {
2103:
2104: FD8XX_WRITE_DATA(baseAddress, SCSIMESS_ABORT);
2105: }
2106:
2107: Fd8xxClearControl(DeviceExtension, C_BUS_ENABLE);
2108:
2109: busFreeTimeout = 2048;
2110: while ((FD8XX_READ_PHASE(baseAddress) & S_BUSY) && (busFreeTimeout--)) {
2111:
2112: if (FD8XX_READ_PHASE(baseAddress) & S_REQUEST) {
2113:
2114: FD8XX_READ_DATA(baseAddress);
2115: } else {
2116:
2117: ScsiPortStallExecution(100);
2118: }
2119: }
2120:
2121: if (FD8XX_READ_PHASE(baseAddress) != BP_BUS_FREE) {
2122:
2123: //
2124: // Reset SCSI bus. Drastic measures for drastic times...
2125: //
2126: Fd8xxResetBus(DeviceExtension, DeviceExtension->PathId);
2127: ScsiPortNotification(ResetDetected, DeviceExtension, NULL);
2128: }
2129: } // end Fd8xxDoReconnect()
2130:
2131:
2132: VOID
2133: Fd8xxTimer(
2134: IN PVOID Context
2135: )
2136:
2137: /*++
2138:
2139: Routine Description:
2140:
2141: This routine is used to monitor interrupts from the Fd8xx adapter.
2142: The ScsiPort support for a timer is used when a disconnect message is
2143: received to schedule this routine as a timer for later execution. If
2144: this routine is invoked before the interrupt and the adapter is attempting
2145: to select, then it is assumed that the adapter is on a different IRQ then
2146: expected and operation will continue in a "polling" mode. If the actual
2147: interrupt occurs before this routine is called, then everything is ok
2148: and this routine need not reschedule itself.
2149:
2150: Operation when called is to see if the actual interrupt routine serviced
2151: the interrupt. If so, then mark the device extension such that this
2152: routine is not rescheduled and return. If the actual interrupt routine
2153: has not serviced the interrupt and the adapter is indicating that a
2154: reselection is being attempted, then call the interrupt routine to service
2155: the interrupt and continue scheduling this routine. Lastly, if the
2156: interrupt routine has not serviced the interrupt and the adapter is not
2157: indicating a reselection, schedule another timer.
2158:
2159: Arguments:
2160:
2161: Context - Device adapter context pointer.
2162:
2163: Return Value
2164:
2165: TRUE indicates that the interrupt was from this Fd8xx adapter,
2166: FALSE indicates that this interrupt was NOT from us.
2167:
2168: --*/
2169:
2170: {
2171: PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
2172: BOOLEAN restartTimer = TRUE;
2173:
2174: if (deviceExtension->ExpectingInterrupt == FALSE) {
2175:
2176: //
2177: // The interrupt routine got the interrupt. Decrement the number
2178: // of times to continue scheduling a timer routine.
2179: //
2180: deviceExtension->ContinueTimer--;
2181: return;
2182: }
2183:
2184: if (Fd8xxStatusCheck(deviceExtension, S_SELECT, S_SELECT, 1)) {
2185:
2186: //
2187: // If the interrupt routine does not claim this interrupt for some
2188: // reason, restart the timer. If it does claim the interrupt, shut
2189: // off the timer.
2190: //
2191: restartTimer = Fd8xxInterrupt(Context) == FALSE ? TRUE : FALSE;
2192:
2193: //
2194: // Now determine if an event log entry should be made to inform
2195: // the system administrator that there is a possible configuration
2196: // error on this driver.
2197: //
2198: if ((restartTimer == FALSE) &&
2199: (deviceExtension->NotifiedConfigurationError == FALSE)) {
2200: deviceExtension->TimerCaughtInterrupt--;
2201: if ((deviceExtension->TimerCaughtInterrupt == 0) &&
2202: (deviceExtension->ConfiguredWithoutInterrupts == FALSE)) {
2203: ScsiPortLogError(deviceExtension,
2204: NULL,
2205: 0,
2206: 0,
2207: 0,
2208: SP_IRQ_NOT_RESPONDING,
2209: 8);
2210: deviceExtension->NotifiedConfigurationError = TRUE;
2211: }
2212: }
2213: }
2214:
2215: if (restartTimer) {
2216:
2217: //
2218: // Not selected. Set timer for another call.
2219: //
2220: ScsiPortNotification(RequestTimerCall,
2221: deviceExtension,
2222: Fd8xxTimer,
2223: FD8xx_TIMER_VALUE);
2224: }
2225: }
2226:
2227:
2228: BOOLEAN
2229: Fd8xxInterrupt(
2230: IN PVOID Context
2231: )
2232:
2233: /*++
2234:
2235: Routine Description:
2236:
2237: This routine handles the interrupts for the FD8XX. The intention is to
2238: quickly determine the cause of the interrupt, clear the interrupt, and
2239: setup to process any SCSI command that may have been affected by the
2240: interrupt.
2241:
2242: Arguments:
2243:
2244: Context - Device adapter context pointer.
2245:
2246: Return Value:
2247:
2248: TRUE indicates that the interrupt was from this Fd8xx< adapter,
2249: FALSE indicates that this interrupt was NOT from us.
2250:
2251: --*/
2252:
2253: {
2254: PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
2255:
2256: FdDebugPrint(0x20,
2257: (0, "\nFdInterrupt: Device = %x ",
2258: deviceExtension));
2259:
2260: if (Fd8xxStatusCheck(deviceExtension,
2261: S_SELECT,
2262: S_SELECT,
2263: 1) == FALSE) {
2264:
2265: //
2266: // Spurious interrupt or for some other device.
2267: //
2268: FdDebugPrint(0x20,
2269: (0, "NOT Selected: Status = %x, Last CtrlReg = %x\n",
2270: FD8XX_READ_STATUS(deviceExtension->BaseAddress),
2271: deviceExtension->ControlRegister));
2272: return FALSE;
2273:
2274: } else {
2275:
2276: //
2277: // We are being reselected by a target.
2278: //
2279: FdDebugPrint(0x20,
2280: (0, "Selected: Status = %x, Last CtrlReg = %x",
2281: FD8XX_READ_STATUS(deviceExtension->BaseAddress),
2282: deviceExtension->ControlRegister));
2283:
2284: deviceExtension->ExpectingInterrupt = FALSE;
2285: Fd8xxClearControl(deviceExtension, C_INT_ENABLE);
2286:
2287: //
2288: // Here's where the fun starts. We tell the OS to call DoReconnect
2289: // with system interrupts enabled. This way we're not transferring
2290: // gobs of data with the rest of the world blocked out. We can be
2291: // friendly neighbors and do that sort of CPU hungry stuff while
2292: // letting others grab it when necessary.
2293: //
2294: ScsiPortNotification(CallEnableInterrupts,
2295: deviceExtension,
2296: Fd8xxDoReconnect);
2297:
2298: return TRUE;
2299: }
2300: } // end Fd8xxInterrupt()
2301:
2302:
2303: VOID
2304: Fd8xxDpcRunPhase(
2305: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
2306: )
2307:
2308: /*++
2309:
2310: Routine Description:
2311:
2312: This routine is called by the port driver with interrupts enabled.
2313: It calls the normal run phase routine of the 8xx driver to process
2314: the request.
2315:
2316: Arguments:
2317:
2318: DeviceExtension - context pointer for the start or run phase.
2319:
2320: Return Value:
2321:
2322: None.
2323:
2324: --*/
2325:
2326: {
2327:
2328: Fd8xxRunPhase(DeviceExtension);
2329:
2330: ScsiPortNotification(CallDisableInterrupts,
2331: DeviceExtension,
2332: Fd8xxReenableAdapterInterrupts);
2333:
2334: //
2335: // Adapter ready for next request.
2336: //
2337: ScsiPortNotification(NextRequest,
2338: DeviceExtension,
2339: NULL);
2340: }
2341:
2342:
2343: VOID
2344: Fd8xxStartExecution(
2345: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
2346: IN PSPECIFIC_LU_EXTENSION LuExtension,
2347: IN PSCSI_REQUEST_BLOCK Srb
2348: )
2349:
2350: /*++
2351:
2352: Routine Description:
2353:
2354: This routine will start (and possibley complete) the execution of
2355: a SCSI request.
2356:
2357: Arguments:
2358:
2359: DeviceExtension - Device adapter context pointer.
2360: LuExtension - The logical unit specific information.
2361: Srb - The Srb command to execute.
2362:
2363: Return Value:
2364:
2365: None.
2366:
2367: --*/
2368:
2369: {
2370: FdDebugPrint(0x10,
2371: (0, "FdStartExecution Device = %x, LuExt = %x, Srb = %x ",
2372: DeviceExtension,
2373: LuExtension,
2374: Srb));
2375: FdDebugPrint(0x10,
2376: (0, "Target = %x, Lun = %x.\n",
2377: Srb->TargetId,
2378: Srb->Lun));
2379:
2380: //
2381: // Setup the context for this adapter.
2382: //
2383: DeviceExtension->ActiveLu = LuExtension;
2384:
2385: //
2386: // Turn off selection interrupt.
2387: //
2388: Fd8xxClearControl(DeviceExtension, C_INT_ENABLE);
2389:
2390: //
2391: // Check for potential tape access to insure handshake data transfer.
2392: // This is done here instead of in the deferred routine to save
2393: // two pointer loads (Srb and LuExtension).
2394: //
2395: if (Srb->CdbLength == 6) {
2396: LuExtension->SixByteCDBActive = TRUE;
2397: } else {
2398: LuExtension->SixByteCDBActive = FALSE;
2399: }
2400:
2401: //
2402: // Run the bus phase with other interrupts in the system enabled.
2403: //
2404: ScsiPortNotification(CallEnableInterrupts,
2405: DeviceExtension,
2406: Fd8xxDpcRunPhase);
2407: } // end Fd8xxStartExecution()
2408:
2409:
2410: VOID
2411: Fd8xxAbort(
2412: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
2413: IN PSPECIFIC_LU_EXTENSION LuExtension,
2414: IN PSCSI_REQUEST_BLOCK Srb
2415: )
2416:
2417: /*++
2418:
2419: Routine Description:
2420:
2421: Attempt to abort a command on a SCSI target.
2422:
2423: Arguments:
2424:
2425: DeviceExtension - The adapter specific information.
2426: LuExtension - The specific target/logical unit information.
2427: Srb - The Srb command to execute.
2428:
2429: Return Value:
2430:
2431: None.
2432:
2433: --*/
2434:
2435: {
2436: PUCHAR baseAddress = DeviceExtension->BaseAddress;
2437: PSCSI_REQUEST_BLOCK srbBeingAborted = LuExtension->ActiveLuRequest;
2438:
2439: FdDebugPrint(0x10, (0, "FdAbort: "));
2440:
2441: //
2442: // Make sure there is still a request to complete. If so complete
2443: // it with an SRB_STATUS_ABORTED status.
2444: //
2445: if (srbBeingAborted == NULL) {
2446:
2447: //
2448: // If there is no request, then fail the abort.
2449: //
2450: Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
2451:
2452: FdDebugPrint(0x10, (0, "failed.\n"));
2453:
2454: } else {
2455:
2456: if (LuExtension->LuState == LS_DISCONNECTED) {
2457:
2458: FdDebugPrint(0x10, (0, "sending...\n"));
2459:
2460: //
2461: // Attempt to send an abort message SRB into the state machine.
2462: //
2463: LuExtension->LuState = LS_ARBITRATE;
2464: LuExtension->AbortBeingAttempted = TRUE;
2465: DeviceExtension->ActiveLu = LuExtension;
2466: Fd8xxArbitrate(DeviceExtension);
2467:
2468: if ((LuExtension->LuState == LS_SELECT) ||
2469: (LuExtension->LuState == LS_COMPLETE)) {
2470:
2471: //
2472: // Finish off the abort.
2473: //
2474: Fd8xxRunPhase(DeviceExtension);
2475: LuExtension->AbortBeingAttempted = FALSE;
2476:
2477: //
2478: // Now force a completion on the SRB that is being aborted.
2479: //
2480: LuExtension->LuState = LS_COMPLETE;
2481: srbBeingAborted->SrbStatus = SRB_STATUS_ABORTED;
2482:
2483: LuExtension->ActiveLuRequest = srbBeingAborted;
2484: DeviceExtension->ActiveLu = LuExtension;
2485: Fd8xxNotifyCompletion(DeviceExtension);
2486:
2487: } else {
2488:
2489: LuExtension->AbortBeingAttempted = FALSE;
2490: Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
2491:
2492: FdDebugPrint(0x10, (0, "FdAbort failed.\n"));
2493: }
2494:
2495: } else if (LuExtension->LuState != LS_COMPLETE) {
2496:
2497: //
2498: // The SCSI bus is most likely hung by this LUN, so reset it.
2499: //
2500: FdDebugPrint(0x10, (0, "still connected to SCSI bus.\n"));
2501: Fd8xxResetBus(DeviceExtension, Srb->PathId);
2502: ScsiPortNotification(ResetDetected, DeviceExtension, NULL);
2503: }
2504: }
2505: } // end Fd8xxAbort()
2506:
2507:
2508: BOOLEAN
2509: Fd8xxResetBus(
2510: IN PVOID Context,
2511: IN ULONG PathId
2512: )
2513:
2514: /*++
2515:
2516: Routine Description:
2517:
2518: Reset Future Domain 8XX SCSI adapter (there is no action for this)
2519: and SCSI bus.
2520:
2521: Arguments:
2522:
2523: Context - pointer to the device extension for the reset.
2524: PathId - The bus for telling the port driver where the reset occurred.
2525:
2526: Return Value:
2527:
2528: Nothing.
2529:
2530: --*/
2531:
2532: {
2533: PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
2534:
2535: FdDebugPrint(0x10, (0, "FdResetBus: Reset Fd8xx and SCSI bus\n"));
2536:
2537: //
2538: // RESET SCSI bus.
2539: //
2540: Fd8xxSetControl(deviceExtension,
2541: C_RESET);
2542: ScsiPortStallExecution(RESET_HOLD_TIME);
2543: Fd8xxClearControl(deviceExtension,
2544: C_RESET);
2545:
2546: //
2547: // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
2548: //
2549: ScsiPortCompleteRequest(deviceExtension,
2550: (UCHAR) PathId,
2551: (UCHAR) -1,
2552: (UCHAR) -1,
2553: SRB_STATUS_BUS_RESET);
2554:
2555: //
2556: // Find all luExtensions and zero them out.
2557: //
2558: if (deviceExtension->ActiveLu != NULL) {
2559: deviceExtension->ActiveLu->LuState = LS_COMPLETE;
2560: deviceExtension->ActiveLu->ActiveLuRequest = NULL;
2561: deviceExtension->ActiveLu->NoDisconnectActive = FALSE;
2562: deviceExtension->ActiveLu->AbortBeingAttempted = FALSE;
2563: deviceExtension->ActiveLu = NULL;
2564: }
2565:
2566: if (deviceExtension->SavedLu != NULL) {
2567: deviceExtension->SavedLu->LuState = LS_COMPLETE;
2568: deviceExtension->SavedLu->ActiveLuRequest = NULL;
2569: deviceExtension->SavedLu->NoDisconnectActive = FALSE;
2570: deviceExtension->SavedLu->AbortBeingAttempted = FALSE;
2571: deviceExtension->SavedLu = NULL;
2572: }
2573:
2574: return TRUE;
2575: } // end Fd8xxResetBus()
2576:
2577:
2578: BOOLEAN
2579: Fd8xxStartIo(
2580: IN PVOID Context,
2581: IN PSCSI_REQUEST_BLOCK Srb
2582: )
2583:
2584: /*++
2585:
2586: Routine Description:
2587:
2588: This routine is called from the SCSI port driver synchronized
2589: with the kernel with a request to be executed.
2590:
2591: Arguments:
2592: Context - The adapter specific information.
2593: Srb - The Srb command to execute.
2594:
2595: Return Value:
2596:
2597: TRUE
2598:
2599: --*/
2600:
2601: {
2602: PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
2603: PSPECIFIC_LU_EXTENSION luExtension;
2604:
2605: FdDebugPrint(0x10,
2606: (0, "\nFdStartIo: Device = %x, Srb = %x\n",
2607: deviceExtension,
2608: Srb));
2609:
2610: //
2611: // Determine the logical unit that this request is for.
2612: //
2613: deviceExtension->PathId = Srb->PathId;
2614: luExtension = ScsiPortGetLogicalUnit(deviceExtension,
2615: deviceExtension->PathId,
2616: Srb->TargetId,
2617: Srb->Lun);
2618: Srb->SrbStatus = SRB_STATUS_PENDING;
2619:
2620: switch (Srb->Function) {
2621:
2622: case SRB_FUNCTION_ABORT_COMMAND:
2623:
2624: FdDebugPrint(0x10, (0, "ABORT COMMAND.\n"));
2625:
2626: //
2627: // Abort request in progress.
2628: //
2629: // Fd8xxResetBus(deviceExtension, Srb->PathId);
2630: Fd8xxAbort(deviceExtension, luExtension, Srb);
2631: break;
2632:
2633: case SRB_FUNCTION_RESET_BUS:
2634:
2635: FdDebugPrint(0x10, (0, "RESET BUS.\n"));
2636:
2637: //
2638: // Reset Fd8xx and SCSI bus.
2639: //
2640: Fd8xxResetBus(deviceExtension, Srb->PathId);
2641: Srb->SrbStatus = SRB_STATUS_SUCCESS;
2642: break;
2643:
2644: case SRB_FUNCTION_EXECUTE_SCSI:
2645:
2646: FdDebugPrint(0x10, (0, "EXECUTE SCSI.\n"));
2647:
2648: //
2649: // Setup the context for this target/lun.
2650: //
2651: luExtension->ActiveLuRequest = Srb;
2652: luExtension->LuState = LS_ARBITRATE;
2653: luExtension->SavedDataPointer = (ULONG) Srb->DataBuffer;
2654: luExtension->SavedDataLength = Srb->DataTransferLength;
2655:
2656: //
2657: // Initiate a SCSI request.
2658: //
2659: Fd8xxStartExecution(deviceExtension, luExtension, Srb);
2660: return TRUE;
2661:
2662: default:
2663:
2664: Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
2665: ScsiPortNotification(RequestComplete,
2666: (PVOID) deviceExtension,
2667: Srb);
2668: break;
2669:
2670: }
2671:
2672: //
2673: // Adapter ready for next request.
2674: //
2675: ScsiPortNotification(NextRequest,
2676: deviceExtension,
2677: NULL);
2678: return TRUE;
2679: } // end Fd8xxStartIo()
2680:
2681:
2682: BOOLEAN
2683: Fd8xxInitialize(
2684: IN PVOID Context
2685: )
2686:
2687: /*++
2688:
2689: Routine Description:
2690:
2691: Inititialize Fd8xx adapter.
2692:
2693: Arguments:
2694:
2695: Context - Adapter object device extension.
2696:
2697: Return Value:
2698:
2699: Status.
2700:
2701: --*/
2702:
2703: {
2704: PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
2705:
2706: //
2707: // Reset Fd8xx and SCSI bus.
2708: //
2709: Fd8xxWriteControl(deviceExtension, C_RESET);
2710: ScsiPortStallExecution(RESET_HOLD_TIME);
2711: Fd8xxClearControl(deviceExtension, C_RESET);
2712:
2713: ScsiPortNotification(ResetDetected,
2714: (PVOID) deviceExtension);
2715:
2716: Fd8xxClearControl(deviceExtension, C_INT_ENABLE);
2717: deviceExtension->ExpectingInterrupt = FALSE;
2718: deviceExtension->NotifiedConfigurationError = FALSE;
2719: deviceExtension->ContinueTimer = 5;
2720: deviceExtension->TimerCaughtInterrupt = 10;
2721: deviceExtension->ConfiguredWithoutInterrupts = FALSE;
2722:
2723: return TRUE;
2724: } // end Fd8xx<Initialize()
2725:
2726:
2727: BOOLEAN
2728: Fd8xxCheckBaseAddress(
2729: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
2730: IN PUCHAR BaseAddress
2731: )
2732:
2733: /*++
2734:
2735: Routine Description:
2736:
2737: This routine will check to see if there is an adapter at the
2738: provided base address. It does this by first reading and comparing
2739: all of the data area bytes on the adapter. If these are all equal
2740: it then changes the first value and performs the compare again.
2741: All other data area values should change to be equal to the first
2742: value when the change is made. If they are not equal any changes
2743: are restored.
2744:
2745: Arguments:
2746:
2747: DeviceExtension - Necessary to attempt the reads.
2748: BaseAddress - The address to attempt to use for the base of the
2749: memory area
2750:
2751: Return Value:
2752:
2753: TRUE - There is an adapter present at the base address provided.
2754: FALSE - There is no adapter present at the base address provided.
2755:
2756: --*/
2757:
2758: {
2759: UCHAR testValue;
2760: UCHAR oldValue;
2761: USHORT offset;
2762:
2763: oldValue = FD8XX_READ_DATA(BaseAddress);
2764:
2765: //
2766: // Perform a read test of the memory area of the adapter.
2767: //
2768: for (offset = 254; offset > 0; offset--) {
2769:
2770: testValue = FD8XX_READ_ALTERNATE_DATA(BaseAddress, offset);
2771: if (oldValue != testValue) {
2772:
2773: FdDebugPrint(0x20, (0, "Read test failed. "));
2774: return FALSE;
2775: }
2776: }
2777:
2778: FdDebugPrint(0x20, (0, "Read test passed. "));
2779:
2780: //
2781: // Card may be present in the system. Perform a write test.
2782: // The write value is insured to be different than the previous
2783: // value by adding 1
2784: //
2785: oldValue++;
2786: Fd8xxWriteControl(DeviceExtension,
2787: (C_BUS_ENABLE | C_PARITY_ENABLE));
2788:
2789: FD8XX_WRITE_DATA(BaseAddress, oldValue);
2790:
2791: for (offset = 254; offset > 0; offset--) {
2792:
2793: testValue = FD8XX_READ_ALTERNATE_DATA(BaseAddress, offset);
2794:
2795: if (oldValue != testValue) {
2796:
2797: oldValue--; // Get the original value and restore it.
2798: FD8XX_WRITE_DATA(BaseAddress, oldValue);
2799: FdDebugPrint(0x20, (0, "Write test failed. "));
2800: return FALSE;
2801: }
2802: }
2803:
2804: FdDebugPrint(0x20, (0, "Write test passed. "));
2805:
2806: return TRUE;
2807: } // end Fd8xxCheckBaseAddress()
2808:
2809:
2810: ULONG
2811: Fd8xxParseArgumentString(
2812: IN PCHAR String,
2813: IN PCHAR KeyWord
2814: )
2815:
2816: /*++
2817:
2818: Routine Description:
2819:
2820: This routine will parse the string for a match on the keyword, then
2821: calculate the value for the keyword and return it to the caller.
2822:
2823: Arguments:
2824:
2825: String - The ASCII string to parse.
2826: KeyWord - The keyword for the value desired.
2827:
2828: Return Values:
2829:
2830: Zero if value not found
2831: Value converted from ASCII to binary.
2832:
2833: --*/
2834:
2835: {
2836: PCHAR cptr;
2837: PCHAR kptr;
2838: ULONG value;
2839: ULONG stringLength = 0;
2840: ULONG keyWordLength = 0;
2841: ULONG index;
2842:
2843: //
2844: // Calculate the string length and lower case all characters.
2845: //
2846: cptr = String;
2847: while (*cptr) {
2848:
2849: if (*cptr >= 'A' && *cptr <= 'Z') {
2850: *cptr = *cptr + ('a' - 'A');
2851: }
2852: cptr++;
2853: stringLength++;
2854: }
2855:
2856: //
2857: // Calculate the keyword length and lower case all characters.
2858: //
2859: cptr = KeyWord;
2860: while (*cptr) {
2861:
2862: if (*cptr >= 'A' && *cptr <= 'Z') {
2863: *cptr = *cptr + ('a' - 'A');
2864: }
2865: cptr++;
2866: keyWordLength++;
2867: }
2868:
2869: if (keyWordLength > stringLength) {
2870:
2871: //
2872: // Can't possibly have a match.
2873: //
2874: return 0;
2875: }
2876:
2877: //
2878: // Now setup and start the compare.
2879: //
2880: cptr = String;
2881:
2882: ContinueSearch:
2883: //
2884: // The input string may start with white space. Skip it.
2885: //
2886: while (*cptr == ' ' || *cptr == '\t') {
2887: cptr++;
2888: }
2889:
2890: if (*cptr == '\0') {
2891:
2892: //
2893: // end of string.
2894: //
2895: return 0;
2896: }
2897:
2898: kptr = KeyWord;
2899: while (*cptr++ == *kptr++) {
2900:
2901: if (*(cptr - 1) == '\0') {
2902:
2903: //
2904: // end of string
2905: //
2906: return 0;
2907: }
2908: }
2909:
2910: if (*(kptr - 1) == '\0') {
2911:
2912: //
2913: // May have a match backup and check for blank or equals.
2914: //
2915:
2916: cptr--;
2917: while (*cptr == ' ' || *cptr == '\t') {
2918: cptr++;
2919: }
2920:
2921: //
2922: // Found a match. Make sure there is an equals.
2923: //
2924: if (*cptr != '=') {
2925:
2926: //
2927: // Not a match so move to the next semicolon.
2928: //
2929: while (*cptr) {
2930: if (*cptr++ == ';') {
2931: goto ContinueSearch;
2932: }
2933: }
2934: return 0;
2935: }
2936:
2937: //
2938: // Skip the equals sign.
2939: //
2940: cptr++;
2941:
2942: //
2943: // Skip white space.
2944: //
2945: while ((*cptr == ' ') || (*cptr == '\t')) {
2946: cptr++;
2947: }
2948:
2949: if (*cptr == '\0') {
2950:
2951: //
2952: // Early end of string, return not found
2953: //
2954: return 0;
2955: }
2956:
2957: if (*cptr == ';') {
2958:
2959: //
2960: // This isn't it either.
2961: //
2962: cptr++;
2963: goto ContinueSearch;
2964: }
2965:
2966: value = 0;
2967: if ((*cptr == '0') && (*(cptr + 1) == 'x')) {
2968:
2969: //
2970: // Value is in Hex. Skip the "0x"
2971: //
2972: cptr += 2;
2973: for (index = 0; *(cptr + index); index++) {
2974:
2975: if (*(cptr + index) == ' ' ||
2976: *(cptr + index) == '\t' ||
2977: *(cptr + index) == ';') {
2978: break;
2979: }
2980:
2981: if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
2982: value = (16 * value) + (*(cptr + index) - '0');
2983: } else {
2984: if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) {
2985: value = (16 * value) + (*(cptr + index) - 'a' + 10);
2986: } else {
2987:
2988: //
2989: // Syntax error, return not found.
2990: //
2991: return 0;
2992: }
2993: }
2994: }
2995: } else {
2996:
2997: //
2998: // Value is in Decimal.
2999: //
3000: for (index = 0; *(cptr + index); index++) {
3001:
3002: if (*(cptr + index) == ' ' ||
3003: *(cptr + index) == '\t' ||
3004: *(cptr + index) == ';') {
3005: break;
3006: }
3007:
3008: if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
3009: value = (10 * value) + (*(cptr + index) - '0');
3010: } else {
3011:
3012: //
3013: // Syntax error return not found.
3014: //
3015: return 0;
3016: }
3017: }
3018: }
3019:
3020: return value;
3021: } else {
3022:
3023: //
3024: // Not a match check for ';' to continue search.
3025: //
3026: while (*cptr) {
3027: if (*cptr++ == ';') {
3028: goto ContinueSearch;
3029: }
3030: }
3031:
3032: return 0;
3033: }
3034: }
3035:
3036:
3037: BOOLEAN
3038: Fd8xxFindSignature(
3039: PUCHAR romAddress,
3040: PUCHAR p1RomBiosId)
3041:
3042: /*++
3043:
3044: Routine Description:
3045:
3046: This routine searches for a P2 ROM BIOS signature within the rom address
3047: provided.
3048:
3049: Arguments:
3050:
3051: romAddress - Location to search
3052: p1RomBiosId - BIOS string to match
3053:
3054: Return Values:
3055:
3056: TRUE if found
3057: FALSE otherwise
3058:
3059: --*/
3060:
3061: {
3062: USHORT count = 64; // Check first 64 bytes of ROM space.
3063: PUCHAR ptr1 = romAddress;
3064:
3065: while (count--) {
3066:
3067: PUCHAR ptr2 = ptr1++;
3068: PUCHAR ptr3 = p1RomBiosId;
3069: UCHAR c = ScsiPortReadRegisterUchar(ptr2);
3070:
3071: while (c == *ptr3++) {
3072:
3073: ptr2++;
3074: c = ScsiPortReadRegisterUchar(ptr2);
3075:
3076: if (*ptr3 == '\0')
3077: return TRUE;
3078:
3079: if (c == '\0')
3080: return FALSE;
3081: }
3082: }
3083:
3084: return FALSE;
3085: }
3086:
3087:
3088: BOOLEAN
3089: Fd8xxVerifyPatriot1(
3090: PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
3091: PPORT_CONFIGURATION_INFORMATION ConfigInfo
3092: )
3093:
3094: /*++
3095:
3096: Routine Descriptions:
3097:
3098: This routine verifies the presence of a P2 ROM based adapter.
3099:
3100: Arguments:
3101:
3102: DeviceExtension - call context.
3103: ConfigInfo - system provided configuration information.
3104:
3105: Return Value:
3106:
3107: TRUE if found
3108: FALSE otherwise
3109:
3110: --*/
3111:
3112: {
3113: UCHAR p1RomBiosId[] = "IBM F1 BIOS";
3114: BOOLEAN retval;
3115:
3116: if (Fd8xxFindSignature(DeviceExtension->BaseAddress, p1RomBiosId)) {
3117:
3118: //
3119: // We have a patriot-1 adapter installed.
3120: //
3121: retval = TRUE;
3122:
3123: } else {
3124:
3125: retval = FALSE;
3126: }
3127:
3128: return retval;
3129: }
3130:
3131:
3132: ULONG
3133: Fd8xxFindAdapter(
3134: IN PVOID Context,
3135: IN PVOID AdaptersFound,
3136: IN PVOID BusInformation,
3137: IN PCHAR ArgumentString,
3138: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
3139: OUT PBOOLEAN Again
3140: )
3141:
3142: /*++
3143:
3144: Routine Description:
3145:
3146: This routine maps the memory area for the FD8XX adapter into
3147: the virtual address space for the system. It then attempts to
3148: find the adapter and set the configuration information. If
3149: the adapter is not present in the system (or cannot be found)
3150: this routine returnes an indication as such (i.e. FALSE).
3151:
3152: Arguments:
3153:
3154: Context - The device specific context for the call.
3155: AdaptersFound - Passed through from the driver entry as additional
3156: context for the call.
3157: BusInformation - Unused.
3158: ArgumentString - Points to the potential IRQ for this adapter.
3159: ConfigInfo - Pointer to the configuration information structure to
3160: be filled in.
3161: Again - Returns back a request to call this function again.
3162:
3163: Return Value:
3164:
3165: SP_RETURN_FOUND - if an adapter is found.
3166: SP_RETURN_NOT_FOUND - if no adapter is found.
3167:
3168: --*/
3169:
3170: {
3171: USHORT curBaseAddress;
3172: USHORT adaptersFound;
3173: ULONG returnStatus = SP_RETURN_NOT_FOUND;
3174: PSPECIFIC_DEVICE_EXTENSION deviceExtension = Context;
3175: ULONG baseAddresses[] =
3176: {
3177: 0x000c8000,
3178: 0x000ca000,
3179: 0x000ce000,
3180: 0x000de000,
3181: 0x000e8000,
3182: 0x000ea000,
3183: 0
3184: };
3185:
3186: //
3187: // This must never be set to TRUE for this controller. If we return
3188: // TRUE for this parameter, the SCSI port driver will not move to the
3189: // next entry in the registry for the next controller of this type.
3190: // Instead, it will call this routine again with the SAME registry
3191: // information (i.e., IRQ vector) causing the next adapter with a
3192: // DIFFERENT IRQ to fail to install.
3193: //
3194: *Again = FALSE;
3195:
3196: curBaseAddress = (USHORT) (*((PULONG) AdaptersFound) >> 16);
3197: adaptersFound = (USHORT) (*((PULONG) AdaptersFound));
3198:
3199: if ((baseAddresses[curBaseAddress] == 0) ||
3200: (adaptersFound == MAX_ADAPTERS)) {
3201:
3202: return SP_RETURN_NOT_FOUND;
3203: }
3204:
3205: while ((baseAddresses[curBaseAddress] != 0) &&
3206: (adaptersFound != MAX_ADAPTERS) &&
3207: (returnStatus == SP_RETURN_NOT_FOUND)) {
3208:
3209: PUCHAR baseAddress;
3210:
3211: FdDebugPrint(0x20,
3212: (0, "Fd8xxFindAdapter: baseAddresses[%x] = %x, ",
3213: curBaseAddress,
3214: baseAddresses[curBaseAddress]));
3215: FdDebugPrint(0x20,
3216: (0, "%x adapters found so far.\n",
3217: adaptersFound));
3218:
3219: //
3220: // Map the TMC-950 chip into the virtual memory address space.
3221: // If ConfigInfo already has default information about this
3222: // controller, use it. If not, then we derive our own. This
3223: // is for Chicago compatibility.
3224: //
3225: if (ScsiPortConvertPhysicalAddressToUlong(
3226: (*ConfigInfo->AccessRanges)[0].RangeStart) != 0) {
3227:
3228: deviceExtension->BaseAddress = baseAddress =
3229: ScsiPortGetDeviceBase(
3230: deviceExtension,
3231: ConfigInfo->AdapterInterfaceType,
3232: ConfigInfo->SystemIoBusNumber,
3233: (*ConfigInfo->AccessRanges)[0].RangeStart,
3234: (*ConfigInfo->AccessRanges)[0].RangeLength,
3235: (BOOLEAN) !((*ConfigInfo->AccessRanges)[0].RangeInMemory));
3236: } else {
3237:
3238: deviceExtension->BaseAddress = baseAddress =
3239: ScsiPortGetDeviceBase(
3240: deviceExtension,
3241: ConfigInfo->AdapterInterfaceType,
3242: ConfigInfo->SystemIoBusNumber,
3243: ScsiPortConvertUlongToPhysicalAddress(baseAddresses[curBaseAddress]),
3244: (FD8XX_ADDRESS_SIZE), // NumberOfBytes
3245: (BOOLEAN) FALSE); // InIoSpace
3246: }
3247: FdDebugPrint(0x20,
3248: (0, "MmMapIoSpace address = %x ",
3249: baseAddress));
3250:
3251: //
3252: // Determine if the card is really installed in the system.
3253: //
3254: if (Fd8xxCheckBaseAddress(deviceExtension, baseAddress) == FALSE) {
3255:
3256: //
3257: // We did not find an adapter at this baseAddress. Free the
3258: // mapped memory space and continue with the next address if
3259: // there is one.
3260: //
3261: returnStatus = SP_RETURN_NOT_FOUND;
3262: ScsiPortFreeDeviceBase(deviceExtension,
3263: (PVOID) baseAddress);
3264:
3265: } else {
3266:
3267: returnStatus = SP_RETURN_FOUND;
3268:
3269: //
3270: // If there was no previously configured value for the IRQ,
3271: // look at the other way to configure the value or use a default.
3272: //
3273: if (ConfigInfo->BusInterruptLevel == 0) {
3274:
3275: ConfigInfo->BusInterruptLevel = FD8XX_IDT_VECTOR;
3276:
3277: if (ArgumentString != NULL) {
3278: ULONG irq = Fd8xxParseArgumentString(ArgumentString, "irq");
3279:
3280: if (irq == 0) {
3281:
3282: //
3283: // Check for the old way.
3284: //
3285: irq = *((PULONG)ArgumentString);
3286: if (irq > 15) {
3287:
3288: //
3289: // really was intended to be zero.
3290: //
3291: irq = 0;
3292: deviceExtension->ConfiguredWithoutInterrupts = TRUE;
3293: } else {
3294: irq = FD8XX_IDT_VECTOR;
3295: }
3296: }
3297:
3298: FdDebugPrint(0x20,
3299: (0,
3300: "IRQ %d passed in. ",
3301: irq));
3302: ConfigInfo->BusInterruptLevel = irq;
3303: } else {
3304:
3305: FdDebugPrint(0x20, (0, "default IRQ. "));
3306: }
3307: } else {
3308:
3309: FdDebugPrint(0x20,
3310: (0,
3311: "IRQ previously set to %d. ",
3312: ConfigInfo->BusInterruptLevel));
3313: }
3314:
3315: //
3316: // If the user has not specified a target ID, fill in a default.
3317: //
3318: if (ConfigInfo->InitiatorBusId[0] == (UCHAR)SP_UNINITIALIZED_VALUE) {
3319:
3320: deviceExtension->InitiatorId = SCSI_INITIATOR_ID;
3321: ConfigInfo->InitiatorBusId[0] = SCSI_INITIATOR_ID;
3322: } else {
3323:
3324: deviceExtension->InitiatorId = ConfigInfo->InitiatorBusId[0];
3325: FdDebugPrint(0x20,
3326: (0,
3327: "Initiator ID set to %d ",
3328: ConfigInfo->InitiatorBusId[0]));
3329: }
3330:
3331: //
3332: // Fill in the access array information only if there are no
3333: // default parameters already there.
3334: //
3335: if (ScsiPortConvertPhysicalAddressToUlong(
3336: (*ConfigInfo->AccessRanges)[0].RangeStart) == 0) {
3337:
3338: //
3339: // There is no pre-assigned information in the ConfigInfo
3340: // structure derived by Chicago. Thus, we can fill
3341: // our own derived information into the ConfigInfo structure.
3342: // Otherwise WE MUST NOT change the ConfigInfo structure, as
3343: // this will overwrite the Chicago-prestored information.
3344: //
3345: (*ConfigInfo->AccessRanges)[0].RangeStart =
3346: ScsiPortConvertUlongToPhysicalAddress(baseAddresses[curBaseAddress]);
3347: (*ConfigInfo->AccessRanges)[0].RangeLength = FD8XX_ADDRESS_SIZE;
3348: (*ConfigInfo->AccessRanges)[0].RangeInMemory = TRUE;
3349:
3350: ConfigInfo->ScatterGather = FALSE;
3351: ConfigInfo->Master = FALSE;
3352: ConfigInfo->MaximumTransferLength = MAX_TRANSFER_LENGTH;
3353: ConfigInfo->NumberOfBuses = 1;
3354:
3355: if (Fd8xxVerifyPatriot1(deviceExtension, ConfigInfo)) {
3356:
3357: //
3358: // We have a Patriot-I adapter installed in the system
3359: // which scans from Target ID 7 to Target ID 0.
3360: //
3361: ConfigInfo->AdapterScansDown = TRUE;
3362: }
3363: }
3364:
3365: adaptersFound++;
3366: }
3367:
3368: curBaseAddress++;
3369:
3370: FdDebugPrint(0x20, (0, "\n"));
3371: }
3372:
3373: *((PULONG) AdaptersFound) = ((ULONG) curBaseAddress) << 16;
3374: *((PULONG) AdaptersFound) += (ULONG) adaptersFound;
3375:
3376: return returnStatus;
3377: } // end Fd8xxFindAdapter()
3378:
3379:
3380: BOOLEAN
3381: Fd8xxAdapterState(
3382: IN PVOID DeviceExtension,
3383: IN PVOID AdaptersFound,
3384: IN BOOLEAN SaveState
3385: )
3386:
3387: /*++
3388:
3389: Routine Description:
3390:
3391: Saves/restores adapter's real-mode configuration state.
3392:
3393: Arguments:
3394:
3395: DeviceExtension - Adapter object device extension.
3396: AdaptersFound - Passed through from DriverEntry as additional
3397: context for the call.
3398: SaveState - TRUE = Save adapter state, FALSE = restore state.
3399:
3400: Return Value:
3401:
3402: The spec did not intend for this routine to have a return value.
3403: Whoever did the header file just forgot to change the BOOLEAN to
3404: a VOID. We will just return FALSE to shot the compiler up.
3405:
3406: --*/
3407:
3408: {
3409: return FALSE;
3410: }
3411:
3412:
3413: ULONG
3414: DriverEntry(
3415: IN PVOID DriverObject,
3416: IN PVOID Argument2
3417: )
3418:
3419: /*++
3420:
3421: Routine Description:
3422:
3423: Driver initialization entry point for system.
3424:
3425: Arguments:
3426:
3427: DriverObject - The driver specific object pointer
3428: Argument2 - not used.
3429:
3430: Return Value:
3431:
3432: Status from ScsiPortInitialize()
3433:
3434: --*/
3435:
3436: {
3437: HW_INITIALIZATION_DATA hwInitializationData;
3438: ULONG i;
3439:
3440: FdDebugPrint(0x20, (0, "\nSCSI Future Domain 8XX Miniport Driver\n"));
3441:
3442: //
3443: // Zero out the hwInitializationData structure.
3444: //
3445: for (i = 0; i < sizeof(HW_INITIALIZATION_DATA); i++) {
3446:
3447: *(((PUCHAR)&hwInitializationData + i)) = 0;
3448: }
3449:
3450: hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
3451:
3452: //
3453: // Set entry points.
3454: //
3455: hwInitializationData.HwInitialize = Fd8xxInitialize;
3456: hwInitializationData.HwStartIo = Fd8xxStartIo;
3457: hwInitializationData.HwInterrupt = Fd8xxInterrupt;
3458: hwInitializationData.HwFindAdapter = Fd8xxFindAdapter;
3459: hwInitializationData.HwResetBus = Fd8xxResetBus;
3460: hwInitializationData.HwAdapterState = Fd8xxAdapterState;
3461:
3462: //
3463: // Indicate need buffer mapping but not physical addresses.
3464: //
3465: hwInitializationData.MapBuffers = TRUE;
3466: hwInitializationData.NeedPhysicalAddresses = FALSE;
3467: hwInitializationData.NumberOfAccessRanges = 1;
3468:
3469: //
3470: // Specify size of device extension.
3471: //
3472: hwInitializationData.DeviceExtensionSize = sizeof(SPECIFIC_DEVICE_EXTENSION);
3473:
3474: //
3475: // Specify size of logical unit extension.
3476: //
3477: hwInitializationData.SpecificLuExtensionSize = sizeof(SPECIFIC_LU_EXTENSION);
3478:
3479: //
3480: // The fourth parameter below (i.e., "i") will show up as the
3481: // "AdaptersFound" parameter when FindAdapter() is called.
3482: //
3483:
3484: FdDebugPrint(0x20, (0, "Trying ISA...\n"));
3485: hwInitializationData.AdapterInterfaceType = Isa;
3486:
3487: i = 0;
3488: return ScsiPortInitialize(DriverObject,
3489: Argument2,
3490: &hwInitializationData,
3491: &(i));
3492:
3493: } // end DriverEntry()
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.