|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1990 Microsoft Corporation
4:
5: Module Name:
6:
7: ncr53c9x.c
8:
9: Abstract:
10:
11: This module contains the NCR 53c9x specific functions for the NT SCSI port
12: driver.
13:
14: Author:
15:
16: Jeff Havens (jhavens) 28-Feb-1991
17:
18: Environment:
19:
20: Kernel Mode only
21:
22: Revision History:
23:
24: --*/
25:
26: #include "miniport.h"
27: #include "scsi.h"
28:
29: #include "ncr53c9x.h"
30: #include "mcadefs.h"
31: #include "string.h"
32:
33: #include "jazzdef.h"
34: #include "jazzdma.h"
35:
36: #undef ASSERT
37: #if DBG
38: VOID
39: RtlAssert(
40: PVOID FailedAssertion,
41: PVOID FileName,
42: ULONG LineNumber,
43: PCHAR Message
44: );
45:
46: #define ASSERT( exp ) \
47: if (!(exp)) \
48: RtlAssert( #exp, __FILE__, __LINE__, NULL )
49:
50: #define ASSERTMSG( msg, exp ) \
51: if (!(exp)) \
52: RtlAssert( #exp, __FILE__, __LINE__, msg )
53:
54: #else
55: #define ASSERT( exp )
56: #define ASSERTMSG( msg, exp )
57: #endif // DBG
58:
59: #if DBG
60: int NcrDebug;
61: #define NcrPrint(arg) ScsiDebugPrint arg
62: #else
63: #define NcrPrint(arg)
64: #endif
65:
66: //
67: // Define SCSI Protocol Chip configuration parameters.
68: //
69:
70: #define INITIATOR_BUS_ID 0x7
71: #define SELECT_TIMEOUT_FACTOR 33
72: #define SYNCHRONOUS_OFFSET 0x0f
73: #define ASYNCHRONOUS_OFFSET 0
74: #define ASYNCHRONOUS_PERIOD 0x05
75: #define RESET_STALL_TIME 25 // The minimum assertion time for
76: // a SCSI bus reset.
77: #define INTERRUPT_STALL_TIME 5 // Time to wait for the next interrupt.
78:
79:
80: //
81: // NCR 53c9x specific port driver device extension flags.
82: //
83:
84: #define PD_SYNCHRONOUS_RESPONSE_SENT 0x0001
85: #define PD_SYNCHRONOUS_TRANSFER_SENT 0x0002
86: #define PD_PENDING_START_IO 0x0004
87: #define PD_MESSAGE_OUT_VALID 0x0008
88: #define PD_DISCONNECT_EXPECTED 0x0010
89: #define PD_SEND_MESSAGE_REQUEST 0x0020
90: #define PD_POSSIBLE_EXTRA_MESSAGE_OUT 0x0040
91: #define PD_PENDING_DATA_TRANSFER 0x0080
92: #define PD_PARITY_ERROR_LOGGED 0x0100
93: #define PD_EXPECTING_RESET_INTERRUPT 0x0200
94: #define PD_EXPECTING_QUEUE_TAG 0x0400
95: #define PD_TAGGED_SELECT 0x0800
96: #define PD_NCR_ADAPTER 0x1000
97:
98: //
99: // The following defines specify masks which are used to clear flags when
100: // specific events occur, such as reset or disconnect.
101: //
102:
103: #define PD_ADAPTER_RESET_MASK ( PD_SYNCHRONOUS_TRANSFER_SENT | \
104: PD_PENDING_START_IO | \
105: PD_MESSAGE_OUT_VALID | \
106: PD_SEND_MESSAGE_REQUEST | \
107: PD_POSSIBLE_EXTRA_MESSAGE_OUT | \
108: PD_PENDING_DATA_TRANSFER | \
109: PD_PARITY_ERROR_LOGGED | \
110: PD_EXPECTING_QUEUE_TAG | \
111: PD_TAGGED_SELECT | \
112: PD_DISCONNECT_EXPECTED \
113: )
114:
115: #define PD_ADAPTER_DISCONNECT_MASK ( PD_SYNCHRONOUS_TRANSFER_SENT | \
116: PD_MESSAGE_OUT_VALID | \
117: PD_SEND_MESSAGE_REQUEST | \
118: PD_POSSIBLE_EXTRA_MESSAGE_OUT | \
119: PD_PENDING_DATA_TRANSFER | \
120: PD_PARITY_ERROR_LOGGED | \
121: PD_EXPECTING_QUEUE_TAG | \
122: PD_TAGGED_SELECT | \
123: PD_DISCONNECT_EXPECTED \
124: )
125:
126: //
127: // The largest SCSI bus message expected.
128: //
129:
130: #define MESSAGE_BUFFER_SIZE 8
131:
132: //
133: // Retry count limits.
134: //
135:
136: #define RETRY_SELECTION_LIMIT 1
137: #define RETRY_ERROR_LIMIT 2
138: #define MAX_INTERRUPT_COUNT 64
139:
140: //
141: // Bus and chip states.
142: //
143:
144: typedef enum _ADAPTER_STATE {
145: BusFree,
146: AttemptingSelect,
147: CommandComplete,
148: CommandOut,
149: DataTransfer,
150: DisconnectExpected,
151: MessageAccepted,
152: MessageIn,
153: MessageOut,
154: Reselected
155: } ADAPTER_STATE, *PADAPTER_STATE;
156:
157: //
158: // Define the types of chips this driver will support.
159: //
160:
161: typedef enum _CHIP_TYPES {
162: Ncr53c90,
163: Ncr53c94,
164: Fas216,
165: Fas216Fast
166: }CHIP_TYPES, *PCHIP_TYPES;
167:
168: //
169: // NCR 53c9x specific port driver logical unit flags.
170: //
171:
172: #define PD_STATUS_VALID 0x0004
173: #define PD_DO_NOT_CHECK_TRANSFER_LENGTH 0x0008
174: #define PD_INITIATE_RECOVERY 0x0010
175: #define PD_QUEUED_COMMANDS_EXECUTING 0x0020
176:
177: //
178: // The following defines specify masks which are used to clear flags when
179: // specific events occur, such as reset or command complete.
180: //
181:
182: #define PD_LU_COMPLETE_MASK ( PD_STATUS_VALID | \
183: PD_DO_NOT_CHECK_TRANSFER_LENGTH | \
184: PD_INITIATE_RECOVERY \
185: )
186:
187: #define PD_LU_RESET_MASK ( PD_STATUS_VALID | \
188: PD_DO_NOT_CHECK_TRANSFER_LENGTH | \
189: PD_QUEUED_COMMANDS_EXECUTING | \
190: PD_INITIATE_RECOVERY \
191: )
192:
193: //
194: // NCR 53c9x specific port driver SRB extension.
195: //
196:
197: typedef struct _SRB_EXTENSION {
198: ULONG SrbExtensionFlags;
199: ULONG SavedDataPointer;
200: ULONG SavedDataLength;
201: ULONG MaximumTransferLength;
202: }SRB_EXTENSION, *PSRB_EXTENSION;
203:
204: #define SRB_EXT(x) ((PSRB_EXTENSION)(x->SrbExtension))
205:
206: //
207: // NCR 53c9x specific port driver logical unit extension.
208: //
209:
210: typedef struct _SPECIFIC_LOGICAL_UNIT_EXTENSION {
211: USHORT LuFlags;
212: UCHAR RetryCount;
213: ULONG SavedDataPointer;
214: ULONG SavedDataLength;
215: PSCSI_REQUEST_BLOCK ActiveLuRequest;
216: PSCSI_REQUEST_BLOCK ActiveSendRequest;
217: }SPECIFIC_LOGICAL_UNIT_EXTENSION, *PSPECIFIC_LOGICAL_UNIT_EXTENSION;
218:
219: //
220: // NCR 53c9x specific per target controller information.
221: //
222:
223: typedef struct _SPECIFIC_TARGET_EXTENSION {
224: UCHAR TargetFlags;
225: UCHAR SynchronousPeriod;
226: UCHAR SynchronousOffset;
227: SCSI_CONFIGURATION3 Configuration3;
228: }SPECIFIC_TARGET_EXTENSION, *PSPECIFIC_TARGET_EXTENSION;
229:
230: //
231: // Define target controller specific flags.
232: //
233:
234: #define PD_SYNCHRONOUS_NEGOTIATION_DONE 0x0001
235: #define PD_DO_NOT_NEGOTIATE 0x0002
236:
237: //
238: // NCR 53c9x specific port driver device object extension.
239: //
240:
241: typedef struct _SPECIFIC_DEVICE_EXTENSION {
242: ULONG AdapterFlags;
243: ADAPTER_STATE AdapterState; // Current state of the adapter
244: PADAPTER_REGISTERS AdapterBase; // Address of the NCR 53c9x adapter
245: PSCSI_REGISTERS Adapter; // Address of the NCR 53c9x chip
246: PSCSI_REQUEST_BLOCK ActiveLuRequest;
247: PSPECIFIC_LOGICAL_UNIT_EXTENSION ActiveLogicalUnit;
248: // Pointer to the acitive request.
249: PSCSI_REQUEST_BLOCK NextSrbRequest; // Pointer to the next SRB to process.
250: ULONG ActiveDataPointer; // SCSI bus active data pointer
251: ULONG ActiveDataLength; // The amount of data to be transferred.
252: LONG InterruptCount; // Count of interrupts since connection.
253: SPECIFIC_TARGET_EXTENSION TargetState[SCSI_MAXIMUM_TARGETS];
254: CHIP_TYPES ChipType; // Type or version of the chip.
255: SCSI_STATUS AdapterStatus; // Saved status register value
256: SCSI_SEQUENCE_STEP SequenceStep; // Saved sequence step register value
257: SCSI_INTERRUPT AdapterInterrupt; // Saved interrupt status register
258: SCSI_CONFIGURATION3 Configuration3;
259: UCHAR AdapterBusId; // This adapter's SCSI bus ID
260: UCHAR AdapterBusIdMask; // This adapter's SCSI bus ID bit mask
261: UCHAR ClockSpeed; // Chip clock speed in megahetrz.
262: BOOLEAN InterruptPending; // Interrupt pending indicator
263: UCHAR MessageBuffer[MESSAGE_BUFFER_SIZE]; // SCSI bus message buffer
264: UCHAR MessageCount; // Count of bytes in message buffer
265: UCHAR MessageSent; // Count of bytes sent to target
266: UCHAR TargetId; // Saved target id.
267: UCHAR Lun; // Saved lun id.
268: UCHAR ErrorCount;
269: } SPECIFIC_DEVICE_EXTENSION, *PSPECIFIC_DEVICE_EXTENSION;
270:
271:
272: //
273: // Define the synchrouns data transfer parameters structure.
274: //
275:
276: typedef struct _SYNCHRONOUS_TYPE_PARAMETERS {
277: UCHAR MaximumPeriodCyles;
278: UCHAR SynchronousPeriodCyles;
279: UCHAR InitialRegisterValue;
280: }SYNCHRONOUS_TYPE_PARAMETERS, *PSYNCHRONOUS_TYPE_PARAMETERS;
281:
282: //
283: // Define the table of synchronous transfer types.
284: //
285:
286: const SYNCHRONOUS_TYPE_PARAMETERS SynchronousTransferTypes[] = {
287: { 0, 0, 5},
288: { 32, 5, 5},
289: { 32, 8, 7},
290: { 12, 4, 4}
291: };
292:
293: //
294: // SCSI Protocol Chip Control read and write macros.
295: //
296:
297: #ifdef SCSI_READ
298: #undef SCSI_READ
299: #undef SCSI_WRITE
300: #endif
301:
302: #if defined(DECSTATION)
303:
304: #define SCSI_READ(ChipAddr, Register) ScsiPortReadRegisterUchar(&((ChipAddr)->ReadRegisters.Register.Byte))
305:
306: #define SCSI_WRITE(ChipAddr, Register, Value) ScsiPortWriteRegisterUchar(&((ChipAddr)->WriteRegisters.Register.Byte), (Value))
307:
308: #else
309:
310: #define SCSI_READ(ChipAddr, Register) ScsiPortReadPortUchar(&((ChipAddr)->ReadRegisters.Register))
311: #define SCSI_WRITE(ChipAddr, Register, Value) (ScsiPortWritePortUchar(&((ChipAddr)->WriteRegisters.Register), (Value)))
312:
313: #endif
314:
315:
316: //
317: // Functions passed to the OS-specific port driver.
318: //
319:
320: ULONG
321: NcrEisaFindAdapter(
322: IN PVOID ServiceContext,
323: IN PVOID Context,
324: IN PVOID BusInformation,
325: IN PCHAR ArgumentString,
326: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
327: OUT PBOOLEAN Again
328: );
329:
330: ULONG
331: NcrMcaFindAdapter(
332: IN PVOID ServiceContext,
333: IN PVOID Context,
334: IN PVOID BusInformation,
335: IN PCHAR ArgumentString,
336: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
337: OUT PBOOLEAN Again
338: );
339:
340: ULONG
341: NcrMipsFindAdapter(
342: IN PVOID ServiceContext,
343: IN PVOID Context,
344: IN PVOID BusInformation,
345: IN PCHAR ArgumentString,
346: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
347: OUT PBOOLEAN Again
348: );
349:
350: BOOLEAN
351: NcrInitializeAdapter(
352: IN PVOID ServiceContext
353: );
354:
355: BOOLEAN
356: NcrInterruptServiceRoutine(
357: IN PVOID ServiceContext
358: );
359:
360: BOOLEAN
361: NcrResetScsiBus(
362: IN PVOID ServiceContext,
363: IN ULONG PathId
364: );
365:
366: BOOLEAN
367: NcrStartIo(
368: IN PVOID ServiceContext,
369: IN PSCSI_REQUEST_BLOCK Srb
370: );
371:
372: VOID
373: NcrStartDataTransfer(
374: IN PVOID ServiceContext
375: );
376:
377: //
378: // NCR 53c9x internal mini-port driver functions.
379: //
380:
381: VOID
382: NcrAcceptMessage(
383: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
384: IN BOOLEAN SetAttention,
385: IN BOOLEAN SetSynchronousParameters
386: );
387:
388: VOID
389: NcrCleanupAfterReset(
390: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
391: IN BOOLEAN ExternalReset
392: );
393:
394: VOID
395: NcrCompleteSendMessage(
396: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
397: IN UCHAR SrbStatus
398: );
399:
400: BOOLEAN
401: NcrDecodeSynchronousRequest(
402: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
403: IN PSPECIFIC_TARGET_EXTENSION TargetState,
404: IN BOOLEAN ResponseExpected
405: );
406:
407: VOID
408: NcrDumpState(
409: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
410: );
411:
412: BOOLEAN
413: NcrMessageDecode(
414: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
415: );
416:
417: VOID
418: NcrLogError(
419: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
420: IN ULONG ErrorCode,
421: IN ULONG UniqueCode
422: );
423:
424: VOID
425: NcrProcessRequestCompletion(
426: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
427: );
428:
429: VOID
430: NcrResetScsiBusInternal(
431: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
432: IN ULONG PathId
433: );
434:
435: VOID
436: NcrSelectTarget(
437: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
438: IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
439: );
440:
441: VOID
442: NcrSendMessage(
443: IN PSCSI_REQUEST_BLOCK Srb,
444: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
445: IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
446: );
447:
448: VOID
449: NcrStartExecution(
450: PSCSI_REQUEST_BLOCK Srb,
451: PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
452: PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
453: );
454:
455:
456: VOID
457: NcrAcceptMessage(
458: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
459: IN BOOLEAN SetAttention,
460: IN BOOLEAN SetSynchronousParameters
461: )
462: /*++
463:
464: Routine Description:
465:
466: This procedure tells the adapter to accept a pending message on the SCSI
467: bus. Optionally, it will set the synchronous transfer parameters and the
468: attention signal.
469:
470: Arguments:
471:
472: DeviceExtension - Supplies a pointer to the device extension.
473:
474: SetAttention - Indicates the attention line on the SCSI bus should be set.
475:
476: SetSynchronousParameters - Indicates the synchronous data transfer
477: parameters should be set.
478:
479: Return Value:
480:
481: None.
482:
483: --*/
484:
485: {
486:
487: PSPECIFIC_TARGET_EXTENSION targetState;
488:
489: //
490: // Check to see if the synchonous data transfer parameters need to be set.
491: //
492:
493: if (SetSynchronousParameters) {
494:
495: //
496: // These must be set before a data transfer is started.
497: //
498:
499: targetState = &DeviceExtension->TargetState[DeviceExtension->TargetId];
500:
501: SCSI_WRITE( DeviceExtension->Adapter,
502: SynchronousPeriod,
503: targetState->SynchronousPeriod
504: );
505: SCSI_WRITE( DeviceExtension->Adapter,
506: SynchronousOffset,
507: targetState->SynchronousOffset
508: );
509: SCSI_WRITE( DeviceExtension->Adapter,
510: Configuration3,
511: *((PUCHAR) &targetState->Configuration3)
512: );
513: }
514:
515: //
516: // Check to see if the attention signal needs to be set.
517: //
518:
519: if (SetAttention) {
520:
521: //
522: // This requests that the target enter the message-out phase.
523: //
524:
525: SCSI_WRITE( DeviceExtension->Adapter, Command, SET_ATTENTION );
526: }
527:
528: //
529: // Indicate to the adapter that the message-in phase may now be completed.
530: //
531:
532: SCSI_WRITE(DeviceExtension->Adapter, Command, MESSAGE_ACCEPTED);
533: }
534:
535:
536: VOID
537: NcrCleanupAfterReset(
538: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
539: IN BOOLEAN ExternalReset
540: )
541:
542: /*++
543:
544: Routine Description:
545:
546: This routine cleans up the adapter-specific
547: and logical-unit-specific data structures. Any active requests are
548: completed and the synchronous negotiation flags are cleared.
549:
550: Arguments:
551:
552: DeviceExtension - Supplies a pointer to device extension for the bus that
553: was reset.
554:
555: ExternalReset - When set, indicates that the reset was generated by a
556: SCSI device other than this host adapter.
557:
558: Return Value:
559:
560: None.
561:
562: --*/
563:
564: {
565: UCHAR pathId = 0;
566: UCHAR targetId;
567: UCHAR luId;
568: PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
569: PSPECIFIC_TARGET_EXTENSION targetState;
570:
571: //
572: // Check to see if a data transfer was in progress, if so, flush the DMA.
573: //
574:
575: if (DeviceExtension->AdapterState == DataTransfer) {
576:
577: SCSI_WRITE(DeviceExtension->Adapter, Command, FLUSH_FIFO);
578: ScsiPortFlushDma(DeviceExtension);
579:
580: }
581:
582: //
583: // if the current state is AttemptingSelect then SCSI port driver needs
584: // to be notified that new requests can be sent.
585: //
586:
587: if (DeviceExtension->AdapterFlags & PD_PENDING_START_IO) {
588:
589: //
590: // Ask for another request and clear the pending one. The pending
591: // request will be processed when the request of the active requests
592: // are returned.
593:
594: DeviceExtension->NextSrbRequest = NULL;
595: DeviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
596:
597: ScsiPortNotification( NextRequest, DeviceExtension, NULL );
598:
599: }
600:
601: //
602: // If there was an active request, then complete it with
603: // SRB_STATUS_PHASE_SEQUENCE_FAILURE so the class driver will know not
604: // to retry it too many times.
605: //
606:
607: if (DeviceExtension->ActiveLuRequest != NULL) {
608:
609: //
610: // Set the SrbStatus in the SRB, complete the request and
611: // clear the active pointers
612: //
613:
614: luExtension = DeviceExtension->ActiveLogicalUnit;
615:
616: DeviceExtension->ActiveLuRequest->SrbStatus =
617: SRB_STATUS_PHASE_SEQUENCE_FAILURE;
618:
619: targetState = &DeviceExtension->TargetState[DeviceExtension->TargetId];
620:
621: ScsiPortNotification(
622: RequestComplete,
623: DeviceExtension,
624: DeviceExtension->ActiveLuRequest
625: );
626:
627: //
628: // Check to see if there was a synchronous negotiation in progress. If
629: // there was then do not try to negotiate with this target again.
630: //
631:
632: if (DeviceExtension->AdapterFlags & (PD_SYNCHRONOUS_RESPONSE_SENT |
633: PD_SYNCHRONOUS_TRANSFER_SENT)) {
634:
635: //
636: // This target cannot negotiate properly. Set a flag to prevent
637: // further attempts and set the synchronous parameters to use
638: // asynchronous data transfer.
639: //
640:
641: targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE;
642: targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
643: targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
644: targetState->Configuration3.FastScsi = 0;
645:
646: }
647:
648: luExtension->ActiveLuRequest = NULL;
649: luExtension->RetryCount = 0;
650: DeviceExtension->ActiveLogicalUnit = NULL;
651: DeviceExtension->ActiveLuRequest = NULL;
652: }
653:
654: //
655: // Clear the appropriate state flags as well as the next request.
656: // The request will actually be cleared when the logical units are processed.
657: // Note that it is not necessary to fail the request waiting to be started
658: // since it will be processed properly by the target controller, but it
659: // is cleared anyway.
660: //
661:
662: for (targetId = 0; targetId < SCSI_MAXIMUM_TARGETS; targetId++) {
663:
664: //
665: // Loop through each of the possible logical units for this target.
666: //
667:
668: //
669: // Clear the synchronous negotiation flage for the target controller.
670: //
671:
672: DeviceExtension->TargetState[targetId].TargetFlags &=
673: ~PD_SYNCHRONOUS_NEGOTIATION_DONE;
674:
675: for (luId = 0; luId < SCSI_MAXIMUM_LOGICAL_UNITS; luId++) {
676:
677: luExtension = ScsiPortGetLogicalUnit( DeviceExtension,
678: pathId,
679: targetId,
680: luId
681: );
682:
683: if (luExtension == NULL) {
684: continue;
685: }
686:
687: ScsiPortCompleteRequest(
688: DeviceExtension,
689: pathId,
690: targetId,
691: luId,
692: SRB_STATUS_BUS_RESET
693: );
694:
695: luExtension->ActiveLuRequest = NULL;
696:
697: if (luExtension->ActiveSendRequest != NULL) {
698:
699: //
700: // Set the SrbStatus in the SRB, complete the request and
701: // clear the active pointers
702: //
703:
704: luExtension->ActiveSendRequest->SrbStatus =
705: SRB_STATUS_BUS_RESET;
706:
707: //
708: // Complete the request.
709: //
710:
711: ScsiPortNotification(
712: RequestComplete,
713: DeviceExtension,
714: luExtension->ActiveSendRequest
715: );
716:
717: luExtension->ActiveSendRequest = NULL;
718:
719: }
720:
721: //
722: // Clear the necessary logical unit flags.
723: //
724:
725: luExtension->LuFlags &= ~PD_LU_RESET_MASK;
726:
727: } /* for luId */
728: } /* for targetId */
729:
730: //
731: // Clear the adapter flags and set the bus state to free.
732: //
733:
734: DeviceExtension->AdapterState = BusFree;
735: DeviceExtension->AdapterFlags &= ~PD_ADAPTER_RESET_MASK;
736:
737: }
738:
739: VOID
740: NcrCompleteSendMessage(
741: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
742: IN UCHAR SrbStatus
743: )
744: /*++
745:
746: Routine Description:
747:
748: This function does the cleanup necessary to complete a send-message request.
749: This includes completing any affected execute-I/O requests and cleaning
750: up the device extension state.
751:
752: Arguments:
753:
754: DeviceExtension - Supplies a pointer to the device extension of the SCSI bus
755: adapter. The active logical unit is stored in ActiveLogicalUnit.
756:
757: SrbStatus - Indicates the status that the request should be completeted with
758: if the request did not complete normally, then any active execute
759: requests are not considered to have been affected.
760:
761: Return Value:
762:
763: None.
764:
765: --*/
766:
767: {
768: PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
769: PSCSI_REQUEST_BLOCK srb;
770: PSCSI_REQUEST_BLOCK srbAbort;
771: UCHAR pathId = 0;
772: UCHAR targetId;
773: UCHAR luId;
774:
775: luExtension = DeviceExtension->ActiveLogicalUnit;
776: srb = luExtension->ActiveSendRequest;
777:
778: //
779: // Clean up any EXECUTE requests which may have been affected by this
780: // message.
781: //
782:
783: if (SrbStatus == SRB_STATUS_SUCCESS) {
784: switch (srb->Function) {
785: case SRB_FUNCTION_ABORT_COMMAND:
786:
787: //
788: // Make sure there is still a request to complete. If so complete
789: // it with an SRB_STATUS_ABORTED status.
790: //
791:
792: srbAbort = ScsiPortGetSrb(
793: DeviceExtension,
794: srb->PathId,
795: srb->TargetId,
796: srb->Lun,
797: srb->QueueTag
798: );
799:
800: if (srbAbort != srb->NextSrb) {
801:
802: //
803: // If there is no request, then fail the abort.
804: //
805:
806: SrbStatus = SRB_STATUS_ABORT_FAILED;
807: break;
808: }
809:
810: srbAbort->SrbStatus = SRB_STATUS_ABORTED;
811:
812: ScsiPortNotification(
813: RequestComplete,
814: DeviceExtension,
815: srbAbort
816: );
817:
818: if (DeviceExtension->ActiveLuRequest == srbAbort) {
819:
820: DeviceExtension->ActiveLuRequest = NULL;
821: }
822:
823: luExtension->ActiveLuRequest = NULL;
824: luExtension->LuFlags &= ~PD_LU_COMPLETE_MASK;
825: luExtension->RetryCount = 0;
826:
827: break;
828:
829: case SRB_FUNCTION_RESET_DEVICE:
830:
831: //
832: // Cycle through each of the possible logical units looking
833: // for requests which have been cleared by the target reset.
834: //
835:
836: targetId = srb->TargetId;
837: DeviceExtension->TargetState[targetId].TargetFlags &=
838: ~PD_SYNCHRONOUS_NEGOTIATION_DONE;
839:
840: for (luId = 0; luId < SCSI_MAXIMUM_LOGICAL_UNITS; luId) {
841:
842: luExtension = ScsiPortGetLogicalUnit( DeviceExtension,
843: pathId,
844: targetId,
845: luId
846: );
847:
848: if (luExtension == NULL) {
849: continue;
850: }
851:
852: ScsiPortCompleteRequest(
853: DeviceExtension,
854: pathId,
855: targetId,
856: luId,
857: SRB_STATUS_BUS_RESET
858: );
859:
860: luExtension->ActiveLuRequest = NULL;
861: luExtension->RetryCount = 0;
862:
863: //
864: // Clear the necessary logical unit flags.
865: //
866:
867: luExtension->LuFlags &= ~PD_LU_RESET_MASK;
868:
869: } /* for luId */
870:
871: /* TODO: Handle CLEAR QUEUE */
872: }
873: } else {
874:
875: //
876: // If an abort request fails then complete target of the abort;
877: // otherwise the target of the ABORT may never be compileted.
878: //
879:
880: if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
881:
882: //
883: // Make sure there is still a request to complete. If so
884: // it with an SRB_STATUS_ABORTED status.
885: //
886:
887: srbAbort = ScsiPortGetSrb(
888: DeviceExtension,
889: srb->PathId,
890: srb->TargetId,
891: srb->Lun,
892: srb->QueueTag
893: );
894:
895: if (srbAbort == srb->NextSrb) {
896:
897: srbAbort->SrbStatus = SRB_STATUS_ABORTED;
898:
899: ScsiPortNotification(
900: RequestComplete,
901: DeviceExtension,
902: srbAbort
903: );
904:
905: luExtension->ActiveLuRequest = NULL;
906: luExtension->LuFlags &= ~PD_LU_COMPLETE_MASK;
907: luExtension->RetryCount = 0;
908:
909: }
910: }
911:
912: }
913:
914: //
915: // Complete the actual send-message request.
916: //
917:
918: srb->SrbStatus = SrbStatus;
919: ScsiPortNotification(
920: RequestComplete,
921: DeviceExtension,
922: srb
923: );
924:
925: //
926: // Clear the active send request and PD_SEND_MESSAGE_REQUEST flag.
927: //
928:
929: luExtension->RetryCount = 0;
930: luExtension->ActiveSendRequest = NULL;
931: DeviceExtension->AdapterFlags &= ~PD_SEND_MESSAGE_REQUEST;
932: }
933:
934: BOOLEAN
935: NcrMessageDecode(
936: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
937: )
938: /*++
939:
940: Routine Description:
941:
942: This function decodes the SCSI bus message-in the device extension message
943: buffer. After the message is decoded it decides what action to take in
944: response to the message. If an outgoing message needs to be sent, then
945: it is placed in the message buffer and TRUE is returned. If the message
946: is acceptable, then the device state is set either to DisconnectExpected or
947: MessageAccepted and the MessageCount is reset to 0.
948:
949: Some messages are made up of several bytes. This funtion will simply
950: return false when an incomplete message is detected, allowing the target
951: to send the rest of the message. The message count is left unchanged.
952:
953: Arguments:
954:
955: DeviceExtension - Supplies a pointer to the specific device extension.
956:
957: Return Value:
958:
959: TRUE - Returns true if there is a reponse message to be sent.
960:
961: FALSE - If there is no response message.
962:
963: --*/
964:
965: {
966: PSCSI_REQUEST_BLOCK srb;
967: PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
968: LONG offset;
969: PSPECIFIC_TARGET_EXTENSION targetState;
970: LONG i;
971: ULONG savedAdapterFlags;
972: PSCSI_EXTENDED_MESSAGE extendedMessage;
973:
974: //
975: // NOTE: The ActivelogicalUnit field could be invalid if the
976: // PD_DISCONNECT_EXPECTED flag is set, so luExtension cannot
977: // be used until this flag has been checked.
978: //
979:
980: luExtension = DeviceExtension->ActiveLogicalUnit;
981: savedAdapterFlags = DeviceExtension->AdapterFlags;
982: srb = DeviceExtension->ActiveLuRequest;
983: targetState = &DeviceExtension->TargetState[DeviceExtension->TargetId];
984:
985: //
986: // If a queue message is expected then it must be the first message byte.
987: //
988:
989: if (DeviceExtension->AdapterFlags & PD_EXPECTING_QUEUE_TAG &&
990: DeviceExtension->MessageBuffer[0] != SRB_SIMPLE_TAG_REQUEST) {
991:
992: NcrPrint((1, "NcrMessageDecode: Unexpected message recieved when que tag expected.\n"));
993:
994: //
995: // The target did not reselect correctly Send a
996: // message reject of this message.
997: //
998:
999: DeviceExtension->MessageCount = 1;
1000: DeviceExtension->MessageSent = 0;
1001: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1002: DeviceExtension->AdapterState = MessageOut;
1003:
1004: return(TRUE);
1005: }
1006:
1007: //
1008: // A number of special cases must be handled if a special message has
1009: // just been sent. These special messages are synchronous negotiations
1010: // or a messages which implie a disconnect. The special cases are:
1011: //
1012: // If a disconnect is expected because of a send-message request,
1013: // then the only valid message-in is a MESSAGE REJECT; other messages
1014: // are a protocol error and are rejected.
1015: //
1016: // If a synchronous negotiation response was just sent and the message
1017: // in was not a MESSAGE REJECT, then the negotiation has been accepted.
1018: //
1019: // If a synchronous negotiation request was just sent, then valid responses
1020: // are a MESSAGE REJECT or an extended synchronous message back.
1021: //
1022:
1023: if (DeviceExtension->AdapterFlags & (PD_SYNCHRONOUS_RESPONSE_SENT |
1024: PD_DISCONNECT_EXPECTED | PD_SYNCHRONOUS_TRANSFER_SENT)) {
1025:
1026: if (DeviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED &&
1027: DeviceExtension->MessageBuffer[0] != SCSIMESS_MESSAGE_REJECT) {
1028:
1029: //
1030: // The target is not responding correctly to the message. Send a
1031: // message reject of this message.
1032: //
1033:
1034: DeviceExtension->MessageCount = 1;
1035: DeviceExtension->MessageSent = 0;
1036: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1037: DeviceExtension->AdapterState = MessageOut;
1038:
1039: return(TRUE);
1040: }
1041:
1042: if (DeviceExtension->AdapterFlags & PD_SYNCHRONOUS_RESPONSE_SENT &&
1043: DeviceExtension->MessageBuffer[0] != SCSIMESS_MESSAGE_REJECT) {
1044:
1045: //
1046: // The target did not reject our response so the synchronous
1047: // transfer negotiation is done. Clear the adapter flags and
1048: // set the logical unit flags indicating this. Continue processing
1049: // the message which is unrelated to negotiation.
1050: //
1051:
1052: DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_RESPONSE_SENT;
1053: targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
1054: }
1055:
1056: //
1057: // Save the adapter flags for later use.
1058: //
1059:
1060: savedAdapterFlags = DeviceExtension->AdapterFlags;
1061:
1062: if (DeviceExtension->AdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT ) {
1063:
1064: //
1065: // The target is sending a message after a synchronous transfer
1066: // request was sent. Valid responses are a MESSAGE REJECT or an
1067: // extended synchronous message; any other message negates the
1068: // fact that a negotiation was started. However, since extended
1069: // messages are multi-byte, it is difficult to determine what the
1070: // incoming message is. So at this point, the fact that a
1071: // sychronous transfer was sent will be saved and cleared from the
1072: // AdapterFlags. If the message looks like a synchronous transfer
1073: // request, then restore this fact back into the AdapterFlags. If
1074: // the complete message is not the one expected, then opening
1075: // negotiation will be forgotten. This is an error by the target,
1076: // but minor so nothing will be done about it. Finally, to prevent
1077: // this cycle from reoccurring on the next request indicate that
1078: // the negotiation is done.
1079: //
1080:
1081: DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
1082: targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
1083: }
1084:
1085: }
1086:
1087: switch (DeviceExtension->MessageBuffer[0]) {
1088: case SCSIMESS_COMMAND_COMPLETE:
1089:
1090: //
1091: // For better or worse the command is complete. Process request which
1092: // set the SrbStatus and clean up the device and logical unit states.
1093: //
1094:
1095: NcrProcessRequestCompletion(DeviceExtension);
1096:
1097: //
1098: // Complete the request.
1099: //
1100:
1101: ScsiPortNotification(
1102: RequestComplete,
1103: DeviceExtension,
1104: srb
1105: );
1106:
1107: //
1108: // Everything is ok with the message so do not send one and set the
1109: // state to DisconnectExpected.
1110: //
1111:
1112: DeviceExtension->AdapterState = DisconnectExpected;
1113: DeviceExtension->MessageCount = 0;
1114: return(FALSE);
1115:
1116: case SCSIMESS_DISCONNECT:
1117:
1118: //
1119: // The target wants to disconnect. Set the state to DisconnectExpected,
1120: // and do not request a message-out.
1121: //
1122:
1123: DeviceExtension->AdapterState = DisconnectExpected;
1124: DeviceExtension->MessageCount = 0;
1125: return(FALSE);
1126:
1127: case SCSIMESS_EXTENDED_MESSAGE:
1128:
1129: //
1130: // The format of an extended message is:
1131: // Extended Message Code
1132: // Length of Message
1133: // Extended Message Type
1134: // .
1135: // .
1136: //
1137: // Until the entire message has been read in, just keep getting bytes
1138: // from the target, making sure that the message buffer is not
1139: // overrun.
1140: //
1141:
1142: extendedMessage = (PSCSI_EXTENDED_MESSAGE)
1143: DeviceExtension->MessageBuffer;
1144:
1145: if (DeviceExtension->MessageCount < 2 ||
1146: (DeviceExtension->MessageCount < MESSAGE_BUFFER_SIZE &&
1147: DeviceExtension->MessageCount < extendedMessage->MessageLength + 2)
1148: ) {
1149:
1150: //
1151: // Update the state and return; also restore the AdapterFlags.
1152: //
1153:
1154: DeviceExtension->AdapterFlags = savedAdapterFlags;
1155: DeviceExtension->AdapterState = MessageAccepted;
1156: return(FALSE);
1157:
1158: }
1159:
1160: //
1161: // Make sure the length includes an extended op-code.
1162: //
1163:
1164: if (DeviceExtension->MessageCount < 3) {
1165:
1166: //
1167: // This is an illegal extended message. Send a MESSAGE_REJECT.
1168: //
1169:
1170: DeviceExtension->MessageCount = 1;
1171: DeviceExtension->MessageSent = 0;
1172: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1173: DeviceExtension->AdapterState = MessageOut;
1174:
1175: return(TRUE);
1176: }
1177:
1178: //
1179: // Determine the extended message type.
1180: //
1181:
1182: switch (extendedMessage->MessageType) {
1183: case SCSIMESS_MODIFY_DATA_POINTER:
1184:
1185: //
1186: // Verify the message length.
1187: //
1188:
1189: if (extendedMessage->MessageLength != SCSIMESS_MODIFY_DATA_LENGTH) {
1190:
1191: //
1192: // Reject the message.
1193: //
1194:
1195: DeviceExtension->MessageCount = 1;
1196: DeviceExtension->MessageSent = 0;
1197: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1198: DeviceExtension->AdapterState = MessageOut;
1199:
1200: return(TRUE);
1201: }
1202:
1203: //
1204: // Calculate the modification to be added to the data pointer.
1205: //
1206:
1207: offset = 0;
1208: for (i = 0; i < 4; i++) {
1209: offset << 8;
1210: offset += extendedMessage->ExtendedArguments.Modify.Modifier[i];
1211: }
1212:
1213: //
1214: // Verify that the new data pointer is still within the range
1215: // of the buffer.
1216: //
1217:
1218: if (DeviceExtension->ActiveDataLength - offset >
1219: srb->DataTransferLength ||
1220: ((LONG) DeviceExtension->ActiveDataLength - offset) < 0 ) {
1221:
1222: //
1223: // The new pointer is not valid, so reject the message.
1224: //
1225:
1226: DeviceExtension->MessageCount = 1;
1227: DeviceExtension->MessageSent = 0;
1228: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1229: DeviceExtension->AdapterState = MessageOut;
1230:
1231: return(TRUE);
1232: }
1233:
1234: //
1235: // Everything has checked out, so update the pointer.
1236: //
1237:
1238: DeviceExtension->ActiveDataPointer += offset;
1239: DeviceExtension->ActiveDataLength -= offset;
1240:
1241: //
1242: // Everything is ok, so accept the message as is.
1243: //
1244:
1245: DeviceExtension->MessageCount = 0;
1246: DeviceExtension->AdapterState = MessageAccepted;
1247: return(FALSE);
1248:
1249: case SCSIMESS_SYNCHRONOUS_DATA_REQ:
1250:
1251: //
1252: // A SYNCHRONOUS DATA TRANSFER REQUEST message was received.
1253: // Make sure the length is correct.
1254: //
1255:
1256: if ( extendedMessage->MessageLength !=
1257: SCSIMESS_SYNCH_DATA_LENGTH) {
1258:
1259: //
1260: // The length is invalid, so reject the message.
1261: //
1262:
1263: DeviceExtension->MessageCount = 1;
1264: DeviceExtension->MessageSent = 0;
1265: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1266: DeviceExtension->AdapterState = MessageOut;
1267: return(TRUE);
1268: }
1269:
1270: //
1271: // If synchrouns negotiation has been disabled for this request,
1272: // then reject any synchronous messages; however, when synchronous
1273: // transfers are allowed then a new attempt can be made.
1274: //
1275:
1276: if (srb != NULL &&
1277: !(savedAdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT) &&
1278: srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) {
1279:
1280: //
1281: // Reject the synchronous transfer message since synchonrous
1282: // transfers are not desired at this time.
1283: //
1284:
1285: DeviceExtension->MessageCount = 1;
1286: DeviceExtension->MessageSent = 0;
1287: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1288: DeviceExtension->AdapterState = MessageOut;
1289: return(TRUE);
1290:
1291: }
1292:
1293: //
1294: // Call NcrDecodeSynchronousMessage to decode the message and
1295: // formulate a response if necessary.
1296: // NcrDecodeSynchronousRequest will return FALSE if the
1297: // message is not accepable and should be rejected.
1298: //
1299:
1300: if (!NcrDecodeSynchronousRequest(
1301: DeviceExtension,
1302: targetState,
1303: !(savedAdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT)
1304: )) {
1305:
1306: //
1307: // Indicate that a negotiation has been done in the logical
1308: // unit and clear the negotiation flags.
1309: //
1310:
1311: targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
1312:
1313: DeviceExtension->AdapterFlags &=
1314: ~(PD_SYNCHRONOUS_RESPONSE_SENT|
1315: PD_SYNCHRONOUS_TRANSFER_SENT);
1316:
1317: //
1318: // The message was not acceptable so send a MESSAGE_REJECT.
1319: //
1320:
1321: DeviceExtension->MessageCount = 1;
1322: DeviceExtension->MessageSent = 0;
1323: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1324: DeviceExtension->AdapterState = MessageOut;
1325: return(TRUE);
1326: }
1327:
1328: //
1329: // If a reponse was expected, then set the state for a message-out.
1330: // Otherwise, NcrDecodeSynchronousRequest has put a reponse
1331: // in the message buffer to be returned to the target.
1332: //
1333:
1334: if (savedAdapterFlags & PD_SYNCHRONOUS_TRANSFER_SENT){
1335:
1336: //
1337: // We initiated the negotiation, so no response is necessary.
1338: //
1339:
1340: DeviceExtension->AdapterState = MessageAccepted;
1341: DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
1342: targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
1343: DeviceExtension->MessageCount = 0;
1344: return(FALSE);
1345: }
1346:
1347: //
1348: // Set up the state to send the reponse. The message count is
1349: // still correct.
1350: //
1351:
1352: DeviceExtension->MessageSent = 0;
1353: DeviceExtension->AdapterState = MessageOut;
1354: DeviceExtension->AdapterFlags &= ~PD_SYNCHRONOUS_TRANSFER_SENT;
1355: DeviceExtension->AdapterFlags |= PD_SYNCHRONOUS_RESPONSE_SENT;
1356: return(TRUE);
1357:
1358: case SCSIMESS_WIDE_DATA_REQUEST:
1359:
1360: //
1361: // A WIDE DATA TRANSFER REQUEST message was received.
1362: // Make sure the length is correct.
1363: //
1364:
1365: if ( extendedMessage->MessageLength !=
1366: SCSIMESS_WIDE_DATA_LENGTH) {
1367:
1368: //
1369: // The length is invalid reject the message.
1370: //
1371:
1372: DeviceExtension->MessageCount = 1;
1373: DeviceExtension->MessageSent = 0;
1374: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1375: DeviceExtension->AdapterState = MessageOut;
1376: return(TRUE);
1377: }
1378:
1379: //
1380: // Since this SCSI protocol chip only supports 8-bits return
1381: // a width of 0 which indicates an 8-bit-wide transfers. The
1382: // MessageCount is still correct for the message.
1383: //
1384:
1385: extendedMessage->ExtendedArguments.Wide.Width = 0;
1386: DeviceExtension->MessageSent = 0;
1387: DeviceExtension->AdapterState = MessageOut;
1388: return(TRUE);
1389:
1390: default:
1391:
1392: //
1393: // This is an unknown or illegal message, so send-message REJECT.
1394: //
1395:
1396: DeviceExtension->MessageCount = 1;
1397: DeviceExtension->MessageSent = 0;
1398: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1399: DeviceExtension->AdapterState = MessageOut;
1400: return(TRUE);
1401: }
1402:
1403: case SCSIMESS_INITIATE_RECOVERY:
1404:
1405: //
1406: // Save the fact that a INITIATE RECOVERY message was received.
1407: //
1408:
1409: SRB_EXT(srb)->SrbExtensionFlags |= PD_INITIATE_RECOVERY;
1410: DeviceExtension->MessageCount = 0;
1411: return(FALSE);
1412:
1413: case SCSIMESS_LINK_CMD_COMP:
1414:
1415: //
1416: // A link command completed. Process the completion. Since the link
1417: // FLAG was not set, do not call ScsiPortNotification. Get the next
1418: // segment of the request and accept the message.
1419: //
1420:
1421: //
1422: // Make sure that this is a linked command.
1423: // Linked commands are not supported.
1424: //
1425:
1426: if (TRUE) {
1427:
1428: //
1429: // Something is messed up. Reject the message.
1430: //
1431:
1432: DeviceExtension->MessageCount = 1;
1433: DeviceExtension->MessageSent = 0;
1434: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1435: DeviceExtension->AdapterState = MessageOut;
1436: return(TRUE);
1437: }
1438:
1439: NcrProcessRequestCompletion(DeviceExtension);
1440:
1441: DeviceExtension->ActiveLuRequest = srb->NextSrb;
1442:
1443: //
1444: // Everything is ok with the message, so do not send one and set the
1445: // state to MessageAccepted.
1446: //
1447:
1448: DeviceExtension->AdapterState = MessageAccepted;
1449: DeviceExtension->MessageCount = 0;
1450: return(FALSE);
1451:
1452: case SCSIMESS_LINK_CMD_COMP_W_FLAG:
1453:
1454: //
1455: // A link command completed. Process the completion and get the next
1456: // segment of the request. Since the link FLAG was set, call
1457: // ScsiPortNotification to notify the class driver.
1458: //
1459:
1460: //
1461: // Make sure that this is a linked command.
1462: // Linked commands are not supported.
1463: //
1464:
1465: if (TRUE) {
1466:
1467: //
1468: // Something is messed up. Reject the message.
1469: //
1470:
1471: DeviceExtension->MessageCount = 1;
1472: DeviceExtension->MessageSent = 0;
1473: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1474: DeviceExtension->AdapterState = MessageOut;
1475: return(TRUE);
1476: }
1477:
1478: NcrProcessRequestCompletion(DeviceExtension);
1479:
1480: DeviceExtension->ActiveLuRequest = srb->NextSrb;
1481:
1482: //
1483: // Complete the request.
1484: //
1485:
1486: ScsiPortNotification(
1487: RequestComplete,
1488: DeviceExtension,
1489: srb
1490: );
1491:
1492: //
1493: // Everything is ok with the message, so do not send one and set the
1494: // state to MessageAccepted.
1495: //
1496:
1497: DeviceExtension->AdapterState = MessageAccepted;
1498: DeviceExtension->MessageCount = 0;
1499: return(FALSE);
1500:
1501: case SCSIMESS_MESSAGE_REJECT:
1502:
1503: //
1504: // The last message we sent was rejected. If this was a send
1505: // message request, then set the proper status and complete the
1506: // request. Set the state to message accepted.
1507: //
1508:
1509: /* TODO: Handle message reject correctly. */
1510: if (DeviceExtension->AdapterFlags & PD_SEND_MESSAGE_REQUEST) {
1511:
1512: //
1513: // Complete the request with message rejected status.
1514: //
1515:
1516: NcrCompleteSendMessage(
1517: DeviceExtension,
1518: SRB_STATUS_MESSAGE_REJECTED
1519: );
1520: }
1521:
1522: //
1523: // Check to see if a synchronous negotiation is in progress.
1524: //
1525:
1526: if (savedAdapterFlags & (PD_SYNCHRONOUS_RESPONSE_SENT|
1527: PD_SYNCHRONOUS_TRANSFER_SENT)) {
1528:
1529: //
1530: // The negotiation failed so use asynchronous data transfers.
1531: // Indicate that the negotiation has been attempted and set
1532: // the transfer for asynchronous. Clear the negotiation flags.
1533: //
1534:
1535: targetState->TargetFlags |= PD_SYNCHRONOUS_NEGOTIATION_DONE;
1536: targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
1537: targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
1538: targetState->Configuration3.FastScsi = 0;
1539: DeviceExtension->AdapterFlags &= ~(PD_SYNCHRONOUS_RESPONSE_SENT|
1540: PD_SYNCHRONOUS_TRANSFER_SENT);
1541:
1542: //
1543: // Even though the negotiation appeared to go ok, there is no reason
1544: // to try again, and some targets get messed up later, so do not try
1545: // synchronous negotiation again.
1546: //
1547:
1548: targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE;
1549:
1550: }
1551:
1552: DeviceExtension->AdapterState = MessageAccepted;
1553: DeviceExtension->MessageCount = 0;
1554: return(FALSE);
1555:
1556: case SCSIMESS_SIMPLE_QUEUE_TAG:
1557: case SCSIMESS_ORDERED_QUEUE_TAG:
1558: case SCSIMESS_HEAD_OF_QUEUE_TAG:
1559:
1560: //
1561: // A queue tag message was recieve. If this is the first byte just
1562: // accept the message and wait for the next one.
1563: //
1564:
1565: if (DeviceExtension->MessageCount < 2) {
1566:
1567: DeviceExtension->AdapterState = MessageAccepted;
1568: return(FALSE);
1569:
1570: }
1571:
1572: //
1573: // Make sure that a queue tag message is expected.
1574: //
1575:
1576: if (!(DeviceExtension->AdapterFlags & PD_EXPECTING_QUEUE_TAG) ||
1577: luExtension == NULL) {
1578:
1579: NcrPrint((1, "NcrMessageDecode: Unexpected queue tag message recieved\n"));
1580:
1581: //
1582: // Something is messed up. Reject the message.
1583: //
1584:
1585: DeviceExtension->MessageCount = 1;
1586: DeviceExtension->MessageSent = 0;
1587: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1588: DeviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
1589: DeviceExtension->AdapterState = MessageOut;
1590: NcrLogError( DeviceExtension, SP_PROTOCOL_ERROR, 17);
1591: return(TRUE);
1592:
1593: }
1594:
1595: //
1596: // The second byte contains the tag used to locate the srb.
1597: //
1598:
1599: srb = ScsiPortGetSrb(
1600: DeviceExtension,
1601: 0,
1602: DeviceExtension->TargetId,
1603: DeviceExtension->Lun,
1604: DeviceExtension->MessageBuffer[1]
1605: );
1606:
1607: if (srb == NULL) {
1608:
1609: NcrPrint((1, "NcrMessageDecode: Invalid queue tag recieved\n"));
1610:
1611: //
1612: // Something is messed up. Reject the message.
1613: //
1614:
1615: DeviceExtension->AdapterFlags &= ~PD_EXPECTING_QUEUE_TAG;
1616: DeviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
1617: DeviceExtension->MessageCount = 1;
1618: DeviceExtension->MessageSent = 0;
1619: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1620: DeviceExtension->AdapterState = MessageOut;
1621:
1622: NcrLogError( DeviceExtension, SP_PROTOCOL_ERROR, 16);
1623:
1624: return(TRUE);
1625:
1626: }
1627:
1628: //
1629: // Everthing is ok. Set up the device extension and accept the message.
1630: // Restore the data pointers.
1631: //
1632:
1633: DeviceExtension->ActiveLuRequest = srb;
1634: DeviceExtension->ActiveDataPointer = SRB_EXT(srb)->SavedDataPointer;
1635: DeviceExtension->ActiveDataLength = SRB_EXT(srb)->SavedDataLength;
1636: DeviceExtension->AdapterFlags &= ~PD_EXPECTING_QUEUE_TAG;
1637: DeviceExtension->AdapterState = MessageAccepted;
1638: DeviceExtension->MessageCount = 0;
1639: return(FALSE);
1640:
1641: case SCSIMESS_RESTORE_POINTERS:
1642:
1643: //
1644: // Restore data pointer message. Just copy the saved data pointer
1645: // and the length to the active data pointers.
1646: //
1647:
1648: DeviceExtension->ActiveDataPointer = SRB_EXT(srb)->SavedDataPointer;
1649: DeviceExtension->ActiveDataLength = SRB_EXT(srb)->SavedDataLength;
1650: DeviceExtension->AdapterState = MessageAccepted;
1651: DeviceExtension->MessageCount = 0;
1652: return(FALSE);
1653:
1654: case SCSIMESS_SAVE_DATA_POINTER:
1655:
1656: //
1657: // SAVE DATA POINTER message request that the active data pointer and
1658: // length be copied to the saved location.
1659: //
1660:
1661: SRB_EXT(srb)->SavedDataPointer = DeviceExtension->ActiveDataPointer;
1662: SRB_EXT(srb)->SavedDataLength = DeviceExtension->ActiveDataLength;
1663: DeviceExtension->AdapterState = MessageAccepted;
1664: DeviceExtension->MessageCount = 0;
1665: return(FALSE);
1666:
1667: default:
1668:
1669: //
1670: // An unrecognized or unsupported message. send-message reject.
1671: //
1672:
1673: DeviceExtension->MessageCount = 1;
1674: DeviceExtension->MessageSent = 0;
1675: DeviceExtension->MessageBuffer[0] = SCSIMESS_MESSAGE_REJECT;
1676: DeviceExtension->AdapterState = MessageOut;
1677: return(TRUE);
1678: }
1679: }
1680:
1681: BOOLEAN
1682: NcrDecodeSynchronousRequest(
1683: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
1684: PSPECIFIC_TARGET_EXTENSION TargetState,
1685: IN BOOLEAN ResponseExpected
1686: )
1687: /*++
1688:
1689: Routine Description:
1690:
1691: This function decodes the synchronous data transfer request message from
1692: the target. It will update the synchronous message-in the buffer and the
1693: synchronous transfer parameters in the logical unit extension. These
1694: parameters are specific for the NCR 53C9X protocol chip. The updated
1695: message-in the device extension message buffer might be returned to the
1696: target.
1697:
1698: This function should be called before the final byte of the message is
1699: accepted from the SCSI bus.
1700:
1701: Arguments:
1702:
1703: DeviceExtension - Supplies a pointer to the adapter specific device
1704: extension.
1705:
1706: TargetState - Supplies a pointer to the target controller's state.
1707: The synchronous transfer fields are updated in this structure to
1708: reflect the new parameter in the message.
1709:
1710: ResponseExpected - When set, indicates that the target initiated the
1711: negotiation and that it expects a response.
1712:
1713: Return Value:
1714:
1715: TRUE - Returned if the request is acceptable.
1716:
1717: FALSE - Returned if the request should be rejected and asynchronous
1718: transfer should be used.
1719:
1720: --*/
1721:
1722: {
1723: PSCSI_EXTENDED_MESSAGE extendedMessage;
1724: CHIP_TYPES chipType;
1725: LONG period;
1726: ULONG localPeriod;
1727: ULONG step;
1728: LONG i;
1729:
1730: extendedMessage = (PSCSI_EXTENDED_MESSAGE) DeviceExtension->MessageBuffer;
1731:
1732: //
1733: // Determine the transfer offset. It is the minimum of the SCSI protocol
1734: // chip's maximum offset and the requested offset.
1735: //
1736:
1737: if (extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset >
1738: SYNCHRONOUS_OFFSET) {
1739:
1740: if (!ResponseExpected) {
1741:
1742: //
1743: // The negotiation failed for some reason; fall back to
1744: // asynchronous data transfer.
1745: //
1746:
1747: TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
1748: TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
1749: TargetState->Configuration3.FastScsi = 0;
1750: return(FALSE);
1751: }
1752:
1753: extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset = SYNCHRONOUS_OFFSET;
1754: TargetState->SynchronousOffset = SYNCHRONOUS_OFFSET;
1755:
1756: } else {
1757:
1758: TargetState->SynchronousOffset =
1759: extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset;
1760:
1761: }
1762:
1763: //
1764: // If the offset requests asynchronous transfers then set the default
1765: // period and return.
1766: //
1767:
1768: if (extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset ==
1769: ASYNCHRONOUS_OFFSET) {
1770: TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
1771: TargetState->Configuration3.FastScsi = 0;
1772: return(TRUE);
1773: }
1774:
1775: //
1776: // Calculate the period in nanoseconds from the message.
1777: //
1778:
1779: period = extendedMessage->ExtendedArguments.Synchronous.TransferPeriod;
1780:
1781: NcrPrint((1, "NcrDecodeSynchronousRequest: Requested period %d, ", period));
1782:
1783: //
1784: // If the chip supports fast SCSI and the requested period is faster than
1785: // 200 ns then assume fast SCSI.
1786: //
1787:
1788: if (DeviceExtension->ChipType == Fas216 && period < 200 / 4) {
1789:
1790: chipType = Fas216Fast;
1791:
1792: //
1793: // Set the fast SCSI bit in the configuration register.
1794: //
1795:
1796: TargetState->Configuration3.FastScsi = 1;
1797:
1798: } else {
1799: chipType = DeviceExtension->ChipType;
1800: }
1801:
1802: //
1803: // The initial sychronous transfer period is:
1804: //
1805: // SynchronousPeriodCyles * 1000
1806: // -----------------------------
1807: // ClockSpeed * 4
1808: //
1809: // Note the result of the divide by four must be rounded up.
1810: //
1811:
1812: localPeriod = ((SynchronousTransferTypes[chipType].SynchronousPeriodCyles
1813: * 1000) / DeviceExtension->ClockSpeed + 3) / 4;
1814:
1815: //
1816: // Check to see if the period is less than the SCSI protocol chip can
1817: // use. If it is then update the message with our minimum and return.
1818: //
1819:
1820: if ((ULONG) period < localPeriod ) {
1821:
1822: if (!ResponseExpected) {
1823:
1824: //
1825: // The negotiation failed for some reason; fall back to
1826: // asynchronous data transfer.
1827: //
1828:
1829: TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
1830: TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
1831: TargetState->Configuration3.FastScsi = 0;
1832: NcrPrint((1, "Too fast. Local period %d\n", localPeriod));
1833: return(FALSE);
1834: }
1835:
1836: extendedMessage->ExtendedArguments.Synchronous.TransferPeriod =
1837: (UCHAR) localPeriod;
1838: period = localPeriod;
1839: }
1840:
1841: //
1842: // The synchronous transfer cycle count is calculated by:
1843: //
1844: // (RequestedPeriod - BasePeriod) * 1000
1845: // ------------------------------------- + InitialRegisterValue
1846: // ClockSpeed * 4
1847: //
1848: // Note the divide must be rounded up.
1849: //
1850:
1851: step = (1000 / 4) / DeviceExtension->ClockSpeed;
1852: period -= localPeriod;
1853: for (i = SynchronousTransferTypes[chipType].InitialRegisterValue;
1854: i < SynchronousTransferTypes[chipType].MaximumPeriodCyles;
1855: i++) {
1856:
1857: if (period <= 0) {
1858: break;
1859: }
1860:
1861: period -= step;
1862: localPeriod += step;
1863: }
1864:
1865: NcrPrint((1, "Local period: %d, Register value: %d\n", localPeriod, i));
1866:
1867: if (i >= SynchronousTransferTypes[chipType].MaximumPeriodCyles) {
1868:
1869: //
1870: // The requested transfer period is too long for the SCSI protocol
1871: // chip. Fall back to synchronous and reject the request.
1872: //
1873:
1874: TargetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
1875: TargetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
1876: TargetState->Configuration3.FastScsi = 0;
1877:
1878: return(FALSE);
1879: }
1880:
1881: TargetState->SynchronousPeriod = (UCHAR) i;
1882:
1883: //
1884: // If no response was expected then the negotation has completed
1885: // successfully. Set the synchronous data transfer parameter registers
1886: // to the new values. These must be set before a data transfer
1887: // is started.
1888: //
1889:
1890: SCSI_WRITE( DeviceExtension->Adapter,
1891: SynchronousPeriod,
1892: TargetState->SynchronousPeriod
1893: );
1894: SCSI_WRITE( DeviceExtension->Adapter,
1895: SynchronousOffset,
1896: TargetState->SynchronousOffset
1897: );
1898: SCSI_WRITE( DeviceExtension->Adapter,
1899: Configuration3,
1900: *((PUCHAR) &TargetState->Configuration3)
1901: );
1902:
1903: return(TRUE);
1904:
1905: }
1906:
1907: VOID
1908: NcrDumpState(
1909: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
1910: )
1911:
1912: /*++
1913:
1914: Routine Description:
1915:
1916: This function prints the interesting state information about the requested
1917: SCSI bus adapter.
1918:
1919: Arguments:
1920:
1921: DeviceExtension - Supplies a pointer to device extension for the SCSI
1922: bus adapter that should be displayed.
1923:
1924: Return Value:
1925:
1926: None.
1927:
1928: --*/
1929:
1930: {
1931: NcrPrint((0, "NcrDumpState: Specific device extension: %8x; Active Logical Unit: %8x;\n",
1932: DeviceExtension,
1933: DeviceExtension->ActiveLogicalUnit
1934: ));
1935: NcrPrint((0, "NcrDumpState: Adapter Status: %2x; Adapter Interrupt: %2x; Adapter Step: %2x;\n",
1936: *((PUCHAR) &DeviceExtension->AdapterStatus),
1937: *((PUCHAR) &DeviceExtension->AdapterInterrupt),
1938: *((PUCHAR) &DeviceExtension->SequenceStep)
1939: ));
1940: NcrPrint((0, "NcrDumpState: Adapter flags: %4x; Adapter state: %d;\n",
1941: DeviceExtension->AdapterFlags,
1942: DeviceExtension->AdapterState
1943: ));
1944:
1945: }
1946:
1947:
1948: BOOLEAN
1949: NcrInitializeAdapter(
1950: IN PVOID ServiceContext
1951: )
1952: /*++
1953:
1954: Routine Description:
1955:
1956: This function initializes the NCR 53c9x SCSI host adpater and protocol
1957: chip. This function must be called before any other operations are
1958: performed. It should also be called after a power failure. This
1959: function does not cause any interrupts; however, after it completes
1960: interrupts can occur.
1961:
1962: Arguments:
1963:
1964: ServiceContext - Pointer to the specific device extension for this SCSI
1965: bus.
1966:
1967: Return Value:
1968:
1969: TRUE - Returns true indicating that the initialization of the chip is
1970: complete.
1971:
1972: --*/
1973:
1974: {
1975: PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
1976: UCHAR dataByte;
1977:
1978: //
1979: // Clear the adapter flags, but preserve the NCR adapter flag.
1980: //
1981:
1982: deviceExtension->AdapterFlags =
1983: deviceExtension->AdapterFlags & PD_NCR_ADAPTER;
1984:
1985: //
1986: // Initialize the NCR 53c9x SCSI protocol chip.
1987: //
1988:
1989: SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
1990: SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
1991:
1992: //
1993: // Set the configuration register for slow cable mode, parity enable,
1994: // and allow reset interrupts, also set the host adapter SCSI bus id.
1995: // Configuration registers 2 and 3 are cleared by the chip reset and
1996: // do not need to be changed.
1997: //
1998:
1999: dataByte = deviceExtension->AdapterBusId;
2000: ((PSCSI_CONFIGURATION1)(&dataByte))->ParityEnable = 1;
2001:
2002: SCSI_WRITE(deviceExtension->Adapter, Configuration1, dataByte);
2003:
2004: //
2005: // Configuration registers 2 and 3 are cleared by a chip reset and do
2006: // need to be initialized. Note these registers do not exist on the
2007: // Ncr53c90, but the writes will do no harm. Set configuration register 3
2008: // with the value determined by the find adapter routine.
2009: //
2010:
2011: SCSI_WRITE(
2012: deviceExtension->Adapter,
2013: Configuration3,
2014: *((PUCHAR)&deviceExtension->Configuration3)
2015: );
2016:
2017: //
2018: // Enable the SCSI-2 features.
2019: //
2020:
2021: dataByte = 0;
2022: ((PSCSI_CONFIGURATION2)(&dataByte))->Scsi2 = 1;
2023: ((PSCSI_CONFIGURATION2)(&dataByte))->EnablePhaseLatch = 1;
2024:
2025: SCSI_WRITE(deviceExtension->Adapter, Configuration2, dataByte);
2026:
2027: //
2028: // Set the clock conversion register. The clock convertion factor is the
2029: // clock speed divided by 5 rounded up. Only the low three bits are used.
2030: //
2031:
2032: dataByte = (deviceExtension->ClockSpeed + 4) / 5;
2033: SCSI_WRITE(
2034: deviceExtension->Adapter,
2035: ClockConversionFactor,
2036: (dataByte & 0x07)
2037: );
2038:
2039: //
2040: // Set the SelectTimeOut Register to 250ms. This value is based on the
2041: // clock conversion factor and the clock speed.
2042: //
2043:
2044: dataByte = SELECT_TIMEOUT_FACTOR * deviceExtension->ClockSpeed / dataByte;
2045:
2046: SCSI_WRITE( deviceExtension->Adapter, SelectTimeOut, dataByte);
2047:
2048: //
2049: // NOTE: Reselection does not need to be enabled until a request is sent
2050: // to a target. The process of sending a target a request will cause a
2051: // disconnect interrupt so that an ENABLE_SELECTION_RESELECTION request
2052: // will be performed.
2053: //
2054:
2055: if (deviceExtension->AdapterFlags & PD_NCR_ADAPTER) {
2056:
2057: //
2058: // Enable Adapter Interrupts
2059: //
2060:
2061: dataByte = SCSI_READ(deviceExtension->AdapterBase, OptionSelect1);
2062: ((PPOS_DATA_1)(&dataByte))->InterruptEnable = 1;
2063: SCSI_WRITE(deviceExtension->AdapterBase, OptionSelect1, dataByte);
2064:
2065: }
2066:
2067: return( TRUE );
2068: }
2069:
2070: BOOLEAN
2071: NcrInterruptServiceRoutine(
2072: PVOID ServiceContext
2073: )
2074: /*++
2075:
2076: Routine Description:
2077:
2078: This routine is the interrupt service routine for the NCR 53c9x SCSI
2079: host adapter. It is the main SCSI protocol engine of the driver and
2080: is driven by service requests from targets on the SCSI bus. This routine
2081: also detects errors and performs error recovery. Generally, this routine
2082: handles one interrupt per invokation.
2083:
2084: The general flow of this routine is as follows:
2085:
2086: Check for an interrupt.
2087:
2088: Determine if there are any pending errors.
2089:
2090: Check to see if the bus disconnected.
2091:
2092: Check that the previous function completed normally.
2093:
2094: Determine what the target wants to do next and program the chip
2095: appropriately.
2096:
2097: Check for the next interrupt.
2098:
2099: Arguments:
2100:
2101: ServiceContext - Supplies a pointer to the device extension for the
2102: interrupting adapter.
2103:
2104: Return Value:
2105:
2106: TRUE - Indicates that an interrupt was found.
2107:
2108: FALSE - Indicates the device was not interrupting.
2109:
2110: --*/
2111:
2112: {
2113: PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
2114: PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
2115: PSCSI_REQUEST_BLOCK srb;
2116: LONG i;
2117: SCSI_DMA_STATUS DmaStatus;
2118: BOOLEAN setAttention;
2119:
2120: /* POWERFAIL */
2121:
2122: //
2123: // Make sure there is really an interrupt before reading the other
2124: // registers, particularly, the interrupt register.
2125: //
2126:
2127: if (deviceExtension->AdapterFlags & PD_NCR_ADAPTER) {
2128:
2129: *((PUCHAR) &DmaStatus) = SCSI_READ( deviceExtension->AdapterBase, DmaStatus );
2130: if (DmaStatus.Interrupt != deviceExtension->InterruptPending ) {
2131: return(FALSE);
2132: }
2133:
2134: *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ ( deviceExtension->Adapter, ScsiStatus );
2135:
2136: } else {
2137:
2138: *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ ( deviceExtension->Adapter, ScsiStatus );
2139: if (!deviceExtension->AdapterStatus.Interrupt) {
2140: return(FALSE);
2141: }
2142: }
2143:
2144: NextInterrupt:
2145:
2146: //
2147: // Get the current chip state which includes the status register, the
2148: // sequence step register and the interrupt register. These registers are
2149: // frozen until the interrupt register is read.
2150: //
2151:
2152: *((PUCHAR) &deviceExtension->SequenceStep) = SCSI_READ(
2153: deviceExtension->Adapter,
2154: SequenceStep
2155: );
2156: //
2157: // This read will dismiss the interrupt.
2158: //
2159:
2160: *((PUCHAR) &deviceExtension->AdapterInterrupt) = SCSI_READ(
2161: deviceExtension->Adapter,
2162: ScsiInterrupt
2163: );
2164:
2165: #if DBG
2166: if (!deviceExtension->AdapterInterrupt.Disconnect && NcrDebug) {
2167: NcrPrint((0, "NcrInterrupt: Adapter Status: %2x; Adapter Interrupt: %2x; Adapter Step: %2x;\n",
2168: *((PUCHAR) &deviceExtension->AdapterStatus),
2169: *((PUCHAR) &deviceExtension->AdapterInterrupt),
2170: *((PUCHAR) &deviceExtension->SequenceStep)
2171: ));
2172: }
2173: #endif
2174:
2175: deviceExtension->InterruptCount++;
2176:
2177: if (deviceExtension->AdapterInterrupt.IllegalCommand) {
2178: NcrPrint((1, "NcrInterrupt: IllegalCommand\n" ));
2179:
2180: #if DBG
2181: if ( NcrDebug != 0) {
2182: NcrDumpState(deviceExtension);
2183: }
2184: #endif
2185:
2186: if (deviceExtension->AdapterState == AttemptingSelect ||
2187: deviceExtension->AdapterState == Reselected) {
2188:
2189: //
2190: // If an IllegalCommand interrupt has occurred and a select
2191: // is being attempted, flush the FIFO and exit. This occurs
2192: // when the fifo is being filled for a new command at the
2193: // same time time a reselection occurs.
2194: //
2195:
2196: SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
2197:
2198: } else {
2199:
2200: //
2201: // An illegal command occured at an unexpected time. Reset the
2202: // bus and log an error.
2203: //
2204:
2205: NcrResetScsiBusInternal(deviceExtension, 0);
2206: NcrInitializeAdapter(deviceExtension);
2207:
2208: #ifdef MIPS
2209: //
2210: // There is a chip bug with the Emulex 216 part which causes
2211: // illegal commands interrupts to be generated. This problem
2212: // can be prevented on the mips systems by setting a bit in the
2213: // DMA controller to provide better DMA service to the adapter.
2214: //
2215:
2216: if (deviceExtension->ErrorCount++ == 1) {
2217:
2218: //
2219: // Clear on board DMA
2220: //
2221:
2222: i = ScsiPortReadRegisterUlong(
2223: (PULONG) &DMA_CONTROL->Channel[SCSI_CHANNEL].Enable.Long
2224: );
2225:
2226: ((PDMA_CHANNEL_ENABLE) &i)->ChannelEnable = 0;
2227: ScsiPortWriteRegisterUlong(
2228: (PULONG) &DMA_CONTROL->Channel[SCSI_CHANNEL].Enable.Long,
2229: i
2230: );
2231:
2232:
2233: //
2234: // Enable brust mode in the DMA controller.
2235: //
2236:
2237: i = ScsiPortReadRegisterUlong(
2238: (PULONG) &DMA_CONTROL->Channel[SCSI_CHANNEL].Mode.Long
2239: );
2240:
2241:
2242: ((PDMA_CHANNEL_MODE) &i)->BurstMode = 1;
2243:
2244: ScsiPortWriteRegisterUlong(
2245: (PULONG) &DMA_CONTROL->Channel[SCSI_CHANNEL].Mode.Long,
2246: i
2247: );
2248:
2249: NcrLogError(deviceExtension, SP_BAD_FW_WARNING, 15);
2250:
2251: }
2252: #endif
2253: NcrLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 14);
2254:
2255: }
2256:
2257: return(TRUE);
2258: }
2259:
2260: //
2261: // Check for major errors these should never occur.
2262: //
2263:
2264: if ( deviceExtension->AdapterInterrupt.Selected ||
2265: deviceExtension->AdapterInterrupt.SelectedWithAttention ||
2266: deviceExtension->AdapterStatus.GrossError ||
2267: deviceExtension->InterruptCount > MAX_INTERRUPT_COUNT) {
2268:
2269: //
2270: // Things are really messed up. Reset the bus, the chip and
2271: // bail out.
2272: //
2273:
2274: NcrPrint((0,
2275: "NcrInterruptServiceRoutine: Unexpected error. Interrupt Count=%d\n",
2276: deviceExtension->InterruptCount
2277: ));
2278:
2279: NcrDumpState(deviceExtension);
2280:
2281: NcrResetScsiBusInternal(deviceExtension, 0);
2282: NcrInitializeAdapter(deviceExtension);
2283:
2284: NcrLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 1);
2285: return(TRUE);
2286: }
2287:
2288: //
2289: // Check for a bus reset.
2290: //
2291:
2292: if (deviceExtension->AdapterInterrupt.ScsiReset) {
2293:
2294: //
2295: // Check if this was an expected reset.
2296: //
2297:
2298: if (!(deviceExtension->AdapterFlags & PD_EXPECTING_RESET_INTERRUPT)) {
2299:
2300: NcrPrint((0, "NcrInterruptServiceRoutine: SCSI bus reset detected\n"));
2301:
2302: //
2303: // Cleanup the logical units and notify the port driver,
2304: // then return.
2305: //
2306:
2307: NcrCleanupAfterReset(deviceExtension, TRUE);
2308: ScsiPortNotification(
2309: ResetDetected,
2310: deviceExtension,
2311: NULL
2312: );
2313:
2314: } else {
2315: deviceExtension->AdapterFlags &= ~PD_EXPECTING_RESET_INTERRUPT;
2316: }
2317:
2318: //
2319: // Stall for a short time. This allows interrupt to clear.
2320: //
2321:
2322: ScsiPortStallExecution(INTERRUPT_STALL_TIME);
2323:
2324: SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
2325:
2326: //
2327: // Note that this should only happen in firmware where the interrupts
2328: // are polled.
2329: //
2330:
2331: if (deviceExtension->AdapterFlags & PD_PENDING_START_IO) {
2332:
2333: //
2334: // Call NcrStartIo to start the pending request.
2335: // Note that NcrStartIo is idempotent when called with
2336: // the same arguments.
2337: //
2338:
2339: NcrStartIo(
2340: deviceExtension,
2341: deviceExtension->NextSrbRequest
2342: );
2343:
2344: }
2345:
2346: return(TRUE);
2347: }
2348:
2349: //
2350: // Check for parity errors.
2351: //
2352:
2353: if (deviceExtension->AdapterStatus.ParityError) {
2354:
2355: //
2356: // The SCSI protocol chip has set ATN: we expect the target to
2357: // go into message-out so that a error message can be sent and the
2358: // operation retried. After the error has been noted, continue
2359: // processing the interrupt. The message sent depends on whether a
2360: // message was being received or something else. If the status
2361: // is currently message-in then send-message PARITY ERROR;
2362: // otherwise, send INITIATOR DETECTED ERROR.
2363: //
2364:
2365: NcrPrint((0, "NcrInterruptServiceRoutine: Parity error detected.\n"));
2366: NcrDumpState(deviceExtension);
2367:
2368: //
2369: // If the current phase is MESSAGE_IN then special handling is requred.
2370: //
2371:
2372: if (deviceExtension->AdapterStatus.Phase == MESSAGE_IN) {
2373:
2374: //
2375: // If the current state is CommandComplete, then the fifo contains
2376: // a good status byte. Save the status byte before handling the
2377: // message parity error.
2378: //
2379:
2380: if (deviceExtension->AdapterState == CommandComplete) {
2381:
2382: srb = deviceExtension->ActiveLuRequest;
2383:
2384: srb->ScsiStatus = SCSI_READ(
2385: deviceExtension->Adapter,
2386: Fifo
2387: );
2388:
2389: SRB_EXT(srb)->SrbExtensionFlags |= PD_STATUS_VALID;
2390:
2391: }
2392:
2393: //
2394: // Set the message to indicate a message parity error, flush the
2395: // fifo and accept the message.
2396: //
2397:
2398: deviceExtension->MessageBuffer[0] = SCSIMESS_MESS_PARITY_ERROR;
2399: SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
2400: NcrAcceptMessage(deviceExtension, TRUE, TRUE);
2401:
2402: //
2403: // Since the message which was in the fifo is no good. Clear the
2404: // function complete interrupt which indicates that a message byte
2405: // has been recieved. If this is a reselection, then this will
2406: // a bus reset to occur. This cause is not handled well in this
2407: // code, because it is not setup to deal with a target id and no
2408: // logical unit.
2409: //
2410:
2411: deviceExtension->AdapterInterrupt.FunctionComplete = FALSE;
2412:
2413: } else {
2414:
2415: deviceExtension->MessageBuffer[0] = SCSIMESS_INIT_DETECTED_ERROR;
2416:
2417: }
2418:
2419: deviceExtension->MessageCount = 1;
2420: deviceExtension->MessageSent = 0;
2421: deviceExtension->AdapterState = MessageOut;
2422: deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
2423:
2424: if (!(deviceExtension->AdapterFlags & PD_PARITY_ERROR_LOGGED)) {
2425: NcrLogError(deviceExtension, SP_BUS_PARITY_ERROR, 2);
2426: deviceExtension->AdapterFlags |= PD_PARITY_ERROR_LOGGED;
2427: }
2428:
2429: }
2430:
2431:
2432: //
2433: // Check for bus disconnection. If this was expected, then the next request
2434: // can be processed. If a selection was being attempted, then perhaps the
2435: // logical unit is not there or has gone away. Otherwise, this is an
2436: // unexpected disconnect and should be reported as an error.
2437: //
2438:
2439: if (deviceExtension->AdapterInterrupt.Disconnect) {
2440:
2441: srb = deviceExtension->NextSrbRequest;
2442:
2443: //
2444: // Check for an unexpected disconnect. This occurs if the state is
2445: // not ExpectingDisconnect and a selection did not fail. A selection
2446: // failure is indicated by state of AttemptingSelect and a sequence
2447: // step of 0.
2448: //
2449:
2450: if (deviceExtension->AdapterState == AttemptingSelect &&
2451: deviceExtension->SequenceStep.Step == 0) {
2452:
2453: //
2454: // The target selection failed. Log the error. If the retry
2455: // count is not exceeded then retry the selection; otherwise
2456: // fail the request.
2457: //
2458:
2459: luExtension = ScsiPortGetLogicalUnit(
2460: deviceExtension,
2461: srb->PathId,
2462: srb->TargetId,
2463: srb->Lun
2464: );
2465:
2466: if (luExtension->RetryCount++ >= RETRY_SELECTION_LIMIT) {
2467:
2468: //
2469: // Clear the Active request in the logical unit.
2470: //
2471:
2472: luExtension->RetryCount = 0;
2473:
2474: if (deviceExtension->AdapterFlags & PD_SEND_MESSAGE_REQUEST) {
2475:
2476: //
2477: // Process the completion of the send message request.
2478: // Set the ActiveLogicalUnit for NcrCompleteSendMessage.
2479: // ActiveLogicalUnit is cleared after it returns.
2480: //
2481:
2482: deviceExtension->ActiveLogicalUnit = luExtension;
2483:
2484: NcrCompleteSendMessage(
2485: deviceExtension,
2486: SRB_STATUS_SELECTION_TIMEOUT
2487: );
2488:
2489: deviceExtension->ActiveLogicalUnit = NULL;
2490:
2491: } else {
2492:
2493: srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT;
2494:
2495: ScsiPortNotification(
2496: RequestComplete,
2497: deviceExtension,
2498: srb
2499: );
2500:
2501: luExtension->ActiveLuRequest = NULL;
2502: }
2503:
2504: deviceExtension->NextSrbRequest = NULL;
2505: deviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
2506:
2507: ScsiPortNotification(
2508: NextRequest,
2509: deviceExtension,
2510: NULL
2511: );
2512:
2513: }
2514:
2515: //
2516: // If the request needs to be retried, it will be automatically
2517: // because the PD_PENDING_START_IO flag is still set, and the
2518: // following code will cause it to be restarted.
2519: //
2520:
2521: //
2522: // The chip leaves some of the command in the FIFO, so clear the
2523: // FIFO so there is no garbage left in it.
2524: //
2525:
2526: SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
2527:
2528: } else if ( deviceExtension->AdapterState == DisconnectExpected ||
2529: deviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED) {
2530:
2531: //
2532: // Check to see if this was a send-message request which is
2533: // completed when the disconnect occurs.
2534: //
2535:
2536: if (deviceExtension->AdapterFlags & PD_SEND_MESSAGE_REQUEST) {
2537:
2538: //
2539: // Complete the request.
2540: //
2541:
2542: NcrCompleteSendMessage( deviceExtension,
2543: SRB_STATUS_SUCCESS
2544: );
2545: }
2546:
2547: } else {
2548:
2549: //
2550: // The disconnect was unexpected treat it as an error.
2551: // Check to see if a data transfer was in progress, if so flush
2552: // the DMA.
2553: //
2554:
2555: if (deviceExtension->AdapterState == DataTransfer) {
2556: ScsiPortFlushDma(deviceExtension);
2557: }
2558:
2559: //
2560: // NOTE: If the state is AttemptingSelect, then ActiveLogicalUnit
2561: // is NULL!
2562: //
2563:
2564: //
2565: // The chip leaves some of the command in the FIFO, so clear the
2566: // FIFO so there is not garbage left in it.
2567: //
2568:
2569: SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
2570:
2571: //
2572: // An unexpected disconnect has occurred. Log the error. It is
2573: // not clear if the device will respond again, so let the time-out
2574: // code clean up the request if necessary.
2575: //
2576:
2577: NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected bus disconnect\n"));
2578:
2579: NcrLogError(deviceExtension, SP_UNEXPECTED_DISCONNECT, 3);
2580: }
2581:
2582: //
2583: // Clean up the adapter state to indicate the bus is now free, enable
2584: // reselection, and start any pending request.
2585: //
2586:
2587: deviceExtension->AdapterState = BusFree;
2588: deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
2589: deviceExtension->ActiveLuRequest = NULL;
2590: SCSI_WRITE(deviceExtension->Adapter, Command, ENABLE_SELECTION_RESELECTION);
2591:
2592: #if DBG
2593: if (NcrDebug) {
2594: NcrPrint((0, "NcrInterruptServiceRoutine: DisconnectComplete.\n"));
2595: }
2596: #endif
2597:
2598: if (deviceExtension->AdapterFlags & PD_PENDING_START_IO) {
2599:
2600: ASSERT(deviceExtension->NextSrbRequest->SrbExtension != NULL);
2601:
2602: //
2603: // Check that the next request is still active. This should not
2604: // be necessary, but it appears there is a hole somewhere.
2605: //
2606:
2607: srb = deviceExtension->NextSrbRequest;
2608: srb = ScsiPortGetSrb(
2609: deviceExtension,
2610: srb->PathId,
2611: srb->TargetId,
2612: srb->Lun,
2613: srb->QueueTag
2614: );
2615:
2616: ASSERT(srb == deviceExtension->NextSrbRequest ||
2617: deviceExtension->NextSrbRequest->Function != SRB_FUNCTION_EXECUTE_SCSI);
2618:
2619: if (srb != deviceExtension->NextSrbRequest &&
2620: deviceExtension->NextSrbRequest->Function == SRB_FUNCTION_EXECUTE_SCSI) {
2621:
2622: NcrPrint((1, "NcrInterruptServiceRoutine: Found in active SRB in next request field.\n"));
2623: NcrDumpState(deviceExtension);
2624:
2625: //
2626: // Dump it on the floor.
2627: //
2628:
2629: deviceExtension->NextSrbRequest = NULL;
2630: deviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
2631:
2632: NcrLogError(deviceExtension, SP_INTERNAL_ADAPTER_ERROR, 18);
2633:
2634: ScsiPortNotification(
2635: NextRequest,
2636: deviceExtension,
2637: NULL
2638: );
2639:
2640: } else {
2641:
2642: //
2643: // Call NcrStartIo to start the pending request.
2644: // Note that NcrStartIo is idempotent when called with
2645: // the same arguments.
2646: //
2647:
2648: NcrStartIo(
2649: deviceExtension,
2650: deviceExtension->NextSrbRequest
2651: );
2652:
2653: }
2654: }
2655: }
2656:
2657:
2658: //
2659: // Check for a reselection interrupt.
2660: //
2661:
2662: if (deviceExtension->AdapterInterrupt.Reselected) {
2663: UCHAR targetId;
2664: UCHAR luId;
2665:
2666: //
2667: // The usual case is not to set attention so initialize the
2668: // varible to FALSE.
2669: //
2670:
2671: setAttention = FALSE;
2672:
2673: //
2674: // If the FunctionComplete interrupt is not set then the target did
2675: // not send an IDENTFY message. This is a fatal protocol violation.
2676: // Reset the bus to get rid of this target.
2677: //
2678:
2679: if (!deviceExtension->AdapterInterrupt.FunctionComplete) {
2680:
2681: NcrPrint((0, "NcrInterruptServiceRoutine: Reselection Failed.\n"));
2682: NcrDumpState(deviceExtension);
2683:
2684: NcrResetScsiBusInternal(deviceExtension, 0);
2685: NcrInitializeAdapter(deviceExtension);
2686:
2687: NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 4);
2688:
2689: return(TRUE);
2690: }
2691:
2692: //
2693: // The target Id and the logical unit id are in the FIFO. Use them to
2694: // get the connected active logical unit.
2695: //
2696:
2697: luId = SCSI_READ(deviceExtension->Adapter, Fifo);
2698:
2699: //
2700: // The select id has two bits set. One is the SCSI bus id of the
2701: // initiator and the other is the reselecting target id. The initiator
2702: // id must be stripped and the remaining bit converted to a bit number
2703: // to get the target id.
2704: //
2705:
2706: luId &= ~deviceExtension->AdapterBusIdMask;
2707: WHICH_BIT(luId, targetId);
2708:
2709: luId = SCSI_READ(deviceExtension->Adapter, Fifo);
2710:
2711: //
2712: // The logical unit id is stored in the low-order 3 bits of the
2713: // IDENTIFY message, so the upper bits must be stripped off the
2714: // byte read from the FIFO to get the logical unit number.
2715: //
2716:
2717: luId &= SCSI_MAXIMUM_LOGICAL_UNITS - 1;
2718:
2719: luExtension = ScsiPortGetLogicalUnit( deviceExtension,
2720: 0,
2721: targetId,
2722: luId
2723: );
2724:
2725: //
2726: // Check to that this is a valid logical unit.
2727: //
2728:
2729: if (luExtension == NULL) {
2730:
2731: NcrPrint((0, "NcrInterruptServiceRoutine: Reselection Failed.\n"));
2732: NcrDumpState(deviceExtension);
2733:
2734:
2735: ScsiPortLogError(
2736: deviceExtension, // HwDeviceExtension,
2737: NULL, // Srb
2738: 0, // PathId,
2739: targetId, // TargetId,
2740: luId, // Lun,
2741: SP_INVALID_RESELECTION, // ErrorCode,
2742: 4 // UniqueId
2743: );
2744:
2745: //
2746: // Send an abort message. Put the message in the buffer, set the
2747: // state, indicate that a disconnect is expected after this, and
2748: // set the attention signal.
2749: //
2750:
2751: deviceExtension->MessageBuffer[0] = SCSIMESS_ABORT;
2752: deviceExtension->MessageCount = 1;
2753: deviceExtension->MessageSent = 0;
2754: deviceExtension->AdapterState = MessageOut;
2755: deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
2756: deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID |
2757: PD_DISCONNECT_EXPECTED;
2758:
2759: setAttention = TRUE;
2760:
2761: } else {
2762:
2763: //
2764: // Everything looks ok.
2765: //
2766:
2767: //
2768: // A reselection has been completed. Set the active logical
2769: // unit, restore the active data pointer, and set the state.
2770: // In addition, any adpater flags set by a pending select
2771: // must be cleared using the disconnect mask.
2772: //
2773:
2774: deviceExtension->AdapterFlags &= ~PD_ADAPTER_DISCONNECT_MASK;
2775: deviceExtension->ActiveLogicalUnit = luExtension;
2776: deviceExtension->AdapterState = Reselected;
2777: deviceExtension->MessageCount = 0;
2778:
2779: srb = luExtension->ActiveLuRequest;
2780: deviceExtension->ActiveLuRequest = srb;
2781:
2782: if (srb == NULL) {
2783:
2784: //
2785: // This must be a reconnect for a tagged request.
2786: // Indicate a queue tag message is expected next and save
2787: // the target and logical unit ids.
2788: //
2789:
2790: deviceExtension->AdapterFlags |= PD_EXPECTING_QUEUE_TAG;
2791: deviceExtension->Lun = luId;
2792: } else {
2793:
2794: deviceExtension->ActiveDataPointer = SRB_EXT(srb)->SavedDataPointer;
2795: deviceExtension->ActiveDataLength = SRB_EXT(srb)->SavedDataLength;
2796:
2797: }
2798: }
2799:
2800: //
2801: // The bus is waiting for the message to be accepted. The attention
2802: // signal will be set if this is not a valid reselection. Finally,
2803: // the synchronous data tranfer parameters need to be set in case a
2804: // data transfer is done.
2805: //
2806:
2807: deviceExtension->TargetId = targetId;
2808: NcrAcceptMessage(deviceExtension, setAttention, TRUE);
2809: deviceExtension->InterruptCount = 0;
2810:
2811: } else if (deviceExtension->AdapterInterrupt.FunctionComplete) {
2812:
2813: //
2814: // Check for function complete interrupt if there was not a reselected
2815: // interrupt. The function complete interrupt has already been checked
2816: // in the previous case.
2817: //
2818: // The function complete interrupt occurs after the following cases:
2819: // A select succeeded
2820: // A message byte has been read
2821: // A status byte and message byte have been read when in the
2822: // command complete state.
2823: // A reselection (handled above)
2824: //
2825: // Switch on the state current state of the bus to determine what
2826: // action should be taken now the function has completed.
2827: //
2828:
2829: switch (deviceExtension->AdapterState) {
2830: case AttemptingSelect:
2831:
2832: //
2833: // The target was successfully selected. Set the active
2834: // logical unit field, clear the next logical unit, and
2835: // notify the OS-dependent driver that a new request can
2836: // be accepted. The state is set to MessageOut since is
2837: // the next thing done after a selection.
2838: //
2839:
2840: deviceExtension->ActiveLogicalUnit = ScsiPortGetLogicalUnit(
2841: deviceExtension,
2842: deviceExtension->NextSrbRequest->PathId,
2843: deviceExtension->NextSrbRequest->TargetId,
2844: deviceExtension->NextSrbRequest->Lun
2845: );
2846:
2847: srb = deviceExtension->NextSrbRequest;
2848: deviceExtension->ActiveLuRequest = srb;
2849:
2850: //
2851: // Restore the data pointers.
2852: //
2853:
2854: deviceExtension->ActiveDataPointer = SRB_EXT(srb)->SavedDataPointer;
2855: deviceExtension->ActiveDataLength = SRB_EXT(srb)->SavedDataLength;
2856:
2857: //
2858: // The next request has now become the active request.
2859: // Clear the state associated with the next request and ask for
2860: // another one to start.
2861: //
2862:
2863: deviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
2864: deviceExtension->NextSrbRequest = NULL;
2865: deviceExtension->AdapterState = MessageOut;
2866:
2867: //
2868: // If this was a tagged request then indicate that the next
2869: // request for this lu may be sent.
2870: //
2871:
2872: if (deviceExtension->AdapterFlags & PD_TAGGED_SELECT) {
2873:
2874: ScsiPortNotification(
2875: NextLuRequest,
2876: deviceExtension,
2877: srb->PathId,
2878: srb->TargetId,
2879: srb->Lun
2880: );
2881:
2882: } else {
2883:
2884: ScsiPortNotification(
2885: NextRequest,
2886: deviceExtension,
2887: NULL
2888: );
2889:
2890: }
2891:
2892: break;
2893:
2894: case CommandComplete:
2895:
2896: //
2897: // The FIFO contains the status byte and a message byte. Save the
2898: // status byte and set the state to look like MessageIn, then fall
2899: // through to the message-in state.
2900: //
2901:
2902: srb = deviceExtension->ActiveLuRequest;
2903:
2904: ASSERT(deviceExtension->NextSrbRequest != srb);
2905:
2906: srb->ScsiStatus = SCSI_READ(
2907: deviceExtension->Adapter,
2908: Fifo
2909: );
2910:
2911: SRB_EXT(srb)->SrbExtensionFlags |= PD_STATUS_VALID;
2912:
2913: deviceExtension->AdapterState = MessageIn;
2914: deviceExtension->MessageCount = 0;
2915: deviceExtension->AdapterFlags &= ~PD_MESSAGE_OUT_VALID;
2916:
2917: //
2918: // Fall through and process the message byte in the FIFO.
2919: //
2920:
2921: case MessageIn:
2922:
2923: //
2924: // A message byte has been received. Store it in the message buffer
2925: // and call message decode to determine what to do. The message
2926: // byte will either be accepted, or cause a message to be sent.
2927: // A message-out is indicated to the target by setting the ATN
2928: // line before sending the SCSI protocol chip the MESSAGE_ACCEPTED
2929: // command.
2930: //
2931:
2932: deviceExtension->MessageBuffer[deviceExtension->MessageCount++] =
2933: SCSI_READ( deviceExtension->Adapter, Fifo );
2934:
2935: if (NcrMessageDecode( deviceExtension )) {
2936:
2937: //
2938: // NcrMessageDecode returns TRUE if there is a message to be
2939: // sent out. This message will normally be a MESSAGE REJECT
2940: // or a SYNCHRONOUS DATA TRANSFER REQUEST. In any case, the
2941: // message has been set by NcrMessageDecode. All that needs
2942: // to be done here is set the ATN signal and set
2943: // PD_MESSAGE_OUT_VALID in the adapter flags.
2944: //
2945:
2946: deviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
2947: setAttention = TRUE;
2948: } else {
2949: setAttention = FALSE;
2950: }
2951:
2952: //
2953: // In either case, tell the SCSI protocol chip to acknowlege or
2954: // accept the message. The synchronous data transfer parameters
2955: // do not need to be set.
2956: //
2957:
2958: NcrAcceptMessage( deviceExtension, setAttention, FALSE);
2959: break;
2960:
2961: default:
2962:
2963: //
2964: // A function complete should not occur while in any other states.
2965: //
2966:
2967: NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected function complete interrupt.\n"));
2968: NcrDumpState(deviceExtension);
2969:
2970: }
2971: }
2972:
2973:
2974: //
2975: // Check for a bus service interrupt. This interrupt indicates the target
2976: // is requesting some form of bus transfer. The bus transfer type is
2977: // determined by the bus phase.
2978: //
2979:
2980: if (deviceExtension->AdapterInterrupt.BusService) {
2981:
2982: luExtension = deviceExtension->ActiveLogicalUnit;
2983:
2984: if (luExtension == NULL) {
2985:
2986: //
2987: // There should never be an bus service interrupt without an
2988: // active locgial unit. The bus or the chip is really messed up.
2989: // Reset the bus and return.
2990: //
2991:
2992: NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected Bus service interrupt.\n"));
2993: NcrDumpState(deviceExtension);
2994:
2995: NcrResetScsiBusInternal(deviceExtension, 0);
2996: NcrInitializeAdapter(deviceExtension);
2997:
2998: NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 6);
2999:
3000: return(TRUE);
3001: }
3002:
3003: srb = deviceExtension->ActiveLuRequest;
3004:
3005: //
3006: // If there is no current srb request then the bus service interrupt
3007: // must be a message in with a tag.
3008: //
3009:
3010: if (deviceExtension->AdapterFlags & PD_EXPECTING_QUEUE_TAG &&
3011: deviceExtension->AdapterStatus.Phase != MESSAGE_IN ) {
3012:
3013: //
3014: // A bus service interrupt occured when a queue tag message
3015: // was exepected. Is a protocol error by the target reset the
3016: // bus.
3017: //
3018:
3019: NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected Bus service interrupt when queue tag expected.\n"));
3020: NcrDumpState(deviceExtension);
3021:
3022: NcrResetScsiBusInternal(deviceExtension, 0);
3023: NcrInitializeAdapter(deviceExtension);
3024:
3025: NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 13);
3026:
3027: return(TRUE);
3028:
3029: }
3030:
3031: //
3032: // The bus is changing phases or needs more data. Generally, the target
3033: // can change bus phase at any time: in particular, in the middle of
3034: // a data transfer. The initiator must be able to restart a transfer
3035: // where it left off. To do this it must know how much data was
3036: // transferred. If the previous state was a data transfer, then the
3037: // amount of data transferred needs to be determined, saved and
3038: // the DMA flushed.
3039: //
3040:
3041: if (deviceExtension->AdapterState == DataTransfer) {
3042: SCSI_FIFO_FLAGS fifoFlags;
3043:
3044: //
3045: // Figure out how many bytes have been transferred based on the
3046: // original transfer count stored in the ActiveLengthField,
3047: // SCSI protocol chip transfer counters, and
3048: // the number of bytes in the FIFO. The normal case is when all
3049: // the bytes have been transferred so check for that using the
3050: // TerminalCount bit in the status field.
3051: //
3052:
3053: i = 0;
3054:
3055: if (!deviceExtension->AdapterStatus.TerminalCount) {
3056:
3057: //
3058: // Read bits 23-16 if this chip has that register.
3059: //
3060:
3061: if (deviceExtension->ChipType == Fas216) {
3062:
3063: i = (SCSI_READ(deviceExtension->Adapter,
3064: TransferCountPage
3065: )) << 16;
3066:
3067: }
3068:
3069: //
3070: // Read the current value of the tranfer count registers;
3071: //
3072:
3073: i |= (SCSI_READ(deviceExtension->Adapter, TransferCountHigh)) << 8;
3074: i |= SCSI_READ(deviceExtension->Adapter, TransferCountLow );
3075:
3076: //
3077: // A value of zero in i and TerminalCount clear indicates
3078: // that the transfer length was 64K and that no bytes were
3079: // transferred. Set i to 64K.
3080: //
3081:
3082: if (i == 0) {
3083: i = 0x10000;
3084: }
3085:
3086: }
3087:
3088: //
3089: // If this is a write then there may still be some bytes in the
3090: // FIFO which have yet to be transferred to the target.
3091: //
3092:
3093: if (srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
3094: *((PUCHAR) &fifoFlags) = SCSI_READ(deviceExtension->Adapter,
3095: FifoFlags
3096: );
3097: i += fifoFlags.ByteCount;
3098:
3099:
3100: if (i == 1 && deviceExtension->ChipType == Fas216) {
3101:
3102: //
3103: // This is a chip bug. If the bus state is still data
3104: // out then tell the chip to transfer one more byte.
3105: //
3106:
3107: NcrPrint((1, "NcrInterruptServiceRoutine: One byte left!\n"));
3108:
3109: //
3110: // Set the transfer count.
3111: //
3112:
3113: SCSI_WRITE( deviceExtension->Adapter,
3114: TransferCountLow,
3115: 1
3116: );
3117: SCSI_WRITE( deviceExtension->Adapter,
3118: TransferCountHigh,
3119: 0
3120: );
3121:
3122: SCSI_WRITE(deviceExtension->Adapter,
3123: TransferCountPage,
3124: 0
3125: );
3126:
3127: SCSI_WRITE(deviceExtension->Adapter, Command, TRANSFER_INFORMATION);
3128:
3129: return(TRUE);
3130: }
3131:
3132: //
3133: // The chip leaves some data in the FIFO, so clear the
3134: // FIFO so there is not garbage left in it.
3135: //
3136:
3137: SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
3138: }
3139:
3140: //
3141: // i now contains the number of bytes to be transferred.
3142: // Check to see if this the maximum that has be transferred so far,
3143: // and update the active data pointer and the active length.
3144: //
3145:
3146: if (srb->DataTransferLength - i >
3147: SRB_EXT(srb)->MaximumTransferLength) {
3148: SRB_EXT(srb)->MaximumTransferLength = srb->DataTransferLength -
3149: i;
3150: }
3151:
3152: deviceExtension->ActiveDataPointer +=
3153: deviceExtension->ActiveDataLength - i;
3154: deviceExtension->ActiveDataLength = i;
3155:
3156: //
3157: // Flush the DMA to ensure all the bytes are transferred.
3158: //
3159:
3160: deviceExtension->AdapterFlags &= ~PD_PENDING_DATA_TRANSFER;
3161: ScsiPortFlushDma(deviceExtension);
3162:
3163: } else if (deviceExtension->AdapterState == DisconnectExpected) {
3164:
3165: //
3166: // This is an error; however, some contollers attempt to read more
3167: // message bytes even after a message indicating a disconnect.
3168: // If the request is for a message transfer and extra bytes
3169: // are expected, then allow the transfer; otherwise, reset the bus.
3170: //
3171:
3172: if (!(deviceExtension->AdapterFlags & PD_POSSIBLE_EXTRA_MESSAGE_OUT)
3173: || (deviceExtension->AdapterStatus.Phase != MESSAGE_OUT &&
3174: deviceExtension->AdapterStatus.Phase != MESSAGE_IN)) {
3175:
3176: //
3177: // If a disconnect was expected and a bus service interrupt was
3178: // detected, then a SCSI protocol error has been detected and the
3179: // SCSI bus should be reset to clear the condition.
3180: //
3181:
3182: NcrPrint((0, "NcrInterruptServiceRoutine: Bus request while disconnect expected.\n"));
3183: NcrDumpState(deviceExtension);
3184:
3185: NcrResetScsiBusInternal(deviceExtension, 0);
3186: NcrInitializeAdapter(deviceExtension);
3187:
3188: NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 7);
3189:
3190: return(TRUE);
3191: } else {
3192:
3193: //
3194: // Make sure the disconnect-expected flag is set.
3195: //
3196:
3197: deviceExtension->AdapterFlags |= PD_DISCONNECT_EXPECTED;
3198: }
3199: } else if (deviceExtension->AdapterState == MessageOut) {
3200:
3201: //
3202: // The SCSI protocol chip indicates that the message has been sent;
3203: // however, the target may need to reread the message or there
3204: // may be more messages to send. This condition is indicated by a
3205: // message-out bus phase; otherwise, the message has been accepted
3206: // by the target. If message has been accepted then check to see
3207: // if any special processing is necessary. Note that the driver
3208: // state is set to MessageOut after the PD_DISCONNECT_EXPECTED is
3209: // set, or after a selection. So it is only necessary to check for
3210: // PD_DISCONNECT_EXPECTED when the driver state is currently in
3211: // MessageOut.
3212: //
3213:
3214: if (deviceExtension->AdapterFlags & (PD_DISCONNECT_EXPECTED |
3215: PD_SYNCHRONOUS_TRANSFER_SENT | PD_SYNCHRONOUS_RESPONSE_SENT) &&
3216: deviceExtension->AdapterStatus.Phase != MESSAGE_OUT &&
3217: deviceExtension->AdapterStatus.Phase != MESSAGE_IN) {
3218:
3219: if (deviceExtension->AdapterFlags & PD_DISCONNECT_EXPECTED) {
3220:
3221: //
3222: // If a disconnect was expected and a bus service interrupt was
3223: // detected, then a SCSI protocol error has been detected and the
3224: // SCSI bus should be reset to clear the condition.
3225: //
3226:
3227: NcrPrint((0, "NcrInterruptServiceRoutine: Bus request while disconnect expected after message-out.\n"));
3228: NcrDumpState(deviceExtension);
3229:
3230: NcrResetScsiBusInternal(deviceExtension, 0);
3231: NcrInitializeAdapter(deviceExtension);
3232:
3233: NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 8);
3234:
3235: return(TRUE);
3236:
3237: } else if (deviceExtension->AdapterFlags &
3238: PD_SYNCHRONOUS_TRANSFER_SENT) {
3239:
3240: //
3241: // The controller ignored the synchronous transfer message.
3242: // Treat it as a rejection and clear the necessary state.
3243: //
3244:
3245: deviceExtension->TargetState[deviceExtension->TargetId]
3246: .TargetFlags |=
3247: PD_SYNCHRONOUS_NEGOTIATION_DONE | PD_DO_NOT_NEGOTIATE;
3248: deviceExtension->AdapterFlags &=
3249: ~(PD_SYNCHRONOUS_RESPONSE_SENT |
3250: PD_SYNCHRONOUS_TRANSFER_SENT);
3251: } else if (deviceExtension->AdapterFlags &
3252: PD_SYNCHRONOUS_RESPONSE_SENT) {
3253:
3254: //
3255: // The target controller accepted the negotiation. Set
3256: // the done flag in the logical unit and clear the
3257: // negotiation flags in the adapter.
3258: //
3259:
3260: deviceExtension->TargetState[deviceExtension->TargetId].TargetFlags |=
3261: PD_SYNCHRONOUS_NEGOTIATION_DONE | PD_DO_NOT_NEGOTIATE;
3262: deviceExtension->AdapterFlags &=
3263: ~(PD_SYNCHRONOUS_RESPONSE_SENT |
3264: PD_SYNCHRONOUS_TRANSFER_SENT);
3265:
3266: }
3267: }
3268: }
3269:
3270: //
3271: // If the bus phase is not DATA_IN then the FIFO may need to be
3272: // flushed. The FIFO cannot be flushed while the bus is in the
3273: // DATA_IN phase because the FIFO already has data bytes in it.
3274: // The only case where a target can legally switch phases while
3275: // there are message bytes in the FIFO to the MESSAGE_OUT bus
3276: // phase. If the target leaves message bytes and attempts to
3277: // goto a DATA_IN phase, then the transfer will appear to overrun
3278: // and be detected as an error.
3279: //
3280:
3281: if (deviceExtension->AdapterStatus.Phase != DATA_IN) {
3282: SCSI_WRITE(deviceExtension->Adapter, Command, FLUSH_FIFO);
3283: }
3284:
3285: //
3286: // Decode the current bus phase.
3287: //
3288:
3289: switch (deviceExtension->AdapterStatus.Phase) {
3290:
3291: case COMMAND_OUT:
3292:
3293: //
3294: // Fill the FIFO with the commnad and tell the SCSI protocol chip
3295: // to go.
3296: //
3297:
3298: for (i = 0; i < srb->CdbLength; i++) {
3299: SCSI_WRITE( deviceExtension->Adapter,
3300: Fifo,
3301: srb->Cdb[i]
3302: );
3303: }
3304:
3305: SCSI_WRITE( deviceExtension->Adapter,
3306: Command,
3307: TRANSFER_INFORMATION
3308: );
3309:
3310: deviceExtension->AdapterState = CommandOut;
3311:
3312: break;
3313:
3314: case STATUS_IN:
3315:
3316: //
3317: // Setup of the SCSI protocol chip to read in the status and the
3318: // following message byte, and set the adapter state.
3319: //
3320:
3321: SCSI_WRITE( deviceExtension->Adapter, Command, COMMAND_COMPLETE );
3322: deviceExtension->AdapterState = CommandComplete;
3323:
3324: break;
3325:
3326: case MESSAGE_OUT:
3327:
3328: //
3329: // The target is requesting a message-out. There are three
3330: // possible cases. First, the target is improperly requesting
3331: // a message. Second, a message has been sent, but the target
3332: // could not read it properly. Third, a message has been
3333: // partially sent and the target is requesting the remainder
3334: // of the message.
3335: //
3336: // The first case is indicated when the MessageCount is zero or
3337: // the message-out flag is not set.
3338: //
3339:
3340: if ( deviceExtension->MessageCount == 0 ||
3341: !(deviceExtension->AdapterFlags & PD_MESSAGE_OUT_VALID)) {
3342:
3343: //
3344: // If extra message-outs are possible then just send a NOP
3345: // message.
3346:
3347: if (deviceExtension->AdapterFlags &
3348: PD_POSSIBLE_EXTRA_MESSAGE_OUT) {
3349:
3350: //
3351: // Set the message to NOP and clear the extra message
3352: // flag. This is a hack for controllers that do not
3353: // properly read the entire message.
3354: //
3355:
3356: deviceExtension->MessageBuffer[0] = SCSIMESS_NO_OPERATION;
3357: deviceExtension->AdapterFlags &=
3358: ~PD_POSSIBLE_EXTRA_MESSAGE_OUT;
3359: } else {
3360:
3361: //
3362: // Send an INITIATOR DETECTED ERROR message.
3363: //
3364:
3365: deviceExtension->MessageBuffer[0] =
3366: SCSIMESS_INIT_DETECTED_ERROR;
3367: NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 9);
3368: NcrPrint((0, "NcrInterruptServiceRoutine: Unexpected message-out request\n"));
3369: NcrDumpState(deviceExtension);
3370:
3371: }
3372:
3373: deviceExtension->MessageCount = 1;
3374: deviceExtension->MessageSent = 0;
3375: deviceExtension->AdapterState = MessageOut;
3376:
3377: }
3378:
3379: //
3380: // The second case is indicated when MessageCount and MessageSent
3381: // are equal and nonzero.
3382: //
3383:
3384: if (deviceExtension->MessageCount == deviceExtension->MessageSent){
3385:
3386: //
3387: // The message needs to be resent, so set ATN, clear MessageSent
3388: // and fall through to the next case.
3389: //
3390:
3391: SCSI_WRITE(deviceExtension->Adapter, Command, SET_ATTENTION);
3392: deviceExtension->MessageSent = 0;
3393: }
3394:
3395: if (deviceExtension->MessageCount != deviceExtension->MessageSent){
3396:
3397: //
3398: // The ATTENTION signal needs to be set if the current state
3399: // is not MessageOut.
3400: //
3401:
3402: if (deviceExtension->AdapterState != MessageOut) {
3403:
3404: SCSI_WRITE(
3405: deviceExtension->Adapter,
3406: Command,
3407: SET_ATTENTION
3408: );
3409: }
3410:
3411: //
3412: // There is more message to send. Fill the FIFO with the
3413: // message and tell the SCSI protocol chip to transfer the
3414: // message.
3415: //
3416:
3417: for (;
3418: deviceExtension->MessageSent <
3419: deviceExtension->MessageCount;
3420: deviceExtension->MessageSent++ ) {
3421:
3422: SCSI_WRITE(deviceExtension->Adapter,
3423: Fifo,
3424: deviceExtension->
3425: MessageBuffer[deviceExtension->MessageSent]
3426: );
3427:
3428: }
3429:
3430: SCSI_WRITE(deviceExtension->Adapter,
3431: Command,
3432: TRANSFER_INFORMATION
3433: );
3434:
3435: }
3436:
3437: break;
3438:
3439: case MESSAGE_IN:
3440:
3441: //
3442: // If this is the first byte of the message then initialize
3443: // MessageCount and the adapter state. The message buffer
3444: // cannot overflow because the message decode function will
3445: // take care of the message before the buffer is full.
3446: // The SCSI protocol chip will interrupt for each message
3447: // byte.
3448: //
3449:
3450: if ( deviceExtension->AdapterState != MessageIn &&
3451: deviceExtension->AdapterState != MessageAccepted ) {
3452:
3453: deviceExtension->AdapterFlags &= ~PD_MESSAGE_OUT_VALID;
3454: deviceExtension->MessageCount = 0;
3455: }
3456:
3457: deviceExtension->AdapterState = MessageIn;
3458:
3459: SCSI_WRITE( deviceExtension->Adapter,
3460: Command,
3461: TRANSFER_INFORMATION
3462: );
3463:
3464: break;
3465:
3466: case DATA_OUT:
3467: case DATA_IN:
3468:
3469: //
3470: // Check that the transfer direction is ok, setup the DMA, set
3471: // the synchronous transfer parameter, and tell the chip to go.
3472: // Also check that there is still data to be transferred.
3473: //
3474:
3475: if ((!(srb->SrbFlags & SRB_FLAGS_DATA_IN) &&
3476: deviceExtension->AdapterStatus.Phase == DATA_IN) ||
3477:
3478: (!(srb->SrbFlags & SRB_FLAGS_DATA_OUT) &&
3479: deviceExtension->AdapterStatus.Phase == DATA_OUT) ||
3480:
3481: deviceExtension->ActiveDataLength == 0 ) {
3482:
3483: //
3484: // The data direction is incorrect. Reset the bus to clear
3485: // things up.
3486: //
3487:
3488: NcrPrint((0, "NcrInterruptServiceRoutine: Illegal transfer direction.\n"));
3489: NcrDumpState(deviceExtension);
3490:
3491: NcrResetScsiBusInternal(deviceExtension, 0);
3492: NcrInitializeAdapter(deviceExtension);
3493:
3494: NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 10);
3495:
3496: return(TRUE);
3497: }
3498:
3499: //
3500: // Set the transfer count.
3501: //
3502:
3503: SCSI_WRITE( deviceExtension->Adapter,
3504: TransferCountLow,
3505: (UCHAR) deviceExtension->ActiveDataLength
3506: );
3507: SCSI_WRITE( deviceExtension->Adapter,
3508: TransferCountHigh,
3509: (UCHAR) (deviceExtension->ActiveDataLength >> 8)
3510: );
3511:
3512: //
3513: // Write bits 23-16 if this chip has that register.
3514: //
3515:
3516: if (deviceExtension->ChipType == Fas216) {
3517:
3518: SCSI_WRITE(deviceExtension->Adapter,
3519: TransferCountPage,
3520: (UCHAR) (deviceExtension->ActiveDataLength >> 16)
3521: );
3522:
3523: }
3524:
3525: //
3526: // Clear the extra data transfer flags correctly.
3527: //
3528:
3529: if (deviceExtension->AdapterStatus.Phase == DATA_IN) {
3530: srb->SrbFlags &= ~SRB_FLAGS_DATA_OUT;
3531: } else {
3532: srb->SrbFlags &= ~SRB_FLAGS_DATA_IN;
3533: }
3534:
3535: //
3536: // Set up the DMA controller.
3537: //
3538:
3539: deviceExtension->AdapterState = DataTransfer;
3540: deviceExtension->AdapterFlags |= PD_PENDING_DATA_TRANSFER;
3541:
3542: ScsiPortIoMapTransfer( deviceExtension,
3543: srb,
3544: (PVOID) deviceExtension->ActiveDataPointer,
3545: deviceExtension->ActiveDataLength
3546: );
3547:
3548: break;
3549:
3550: default:
3551:
3552: //
3553: // This phase is illegal and indicates a serious error. Reset the
3554: // bus to clear the problem.
3555: //
3556:
3557: NcrPrint((0, "NcrInterruptServiceRoutine: Illegal bus state detected.\n"));
3558: NcrDumpState(deviceExtension);
3559:
3560: NcrResetScsiBusInternal(deviceExtension, 0);
3561: NcrInitializeAdapter(deviceExtension);
3562:
3563: NcrLogError(deviceExtension, SP_PROTOCOL_ERROR, 11);
3564:
3565: return(TRUE);
3566: }
3567: }
3568:
3569: //
3570: // Stall for a short time. This allows interrupt to clear and gives new
3571: // interrupts a chance to fire.
3572: //
3573:
3574: ScsiPortStallExecution(INTERRUPT_STALL_TIME);
3575:
3576: //
3577: // Make sure there is really an interrupt before reading the other
3578: // registers, particularly, the interrupt register.
3579: //
3580:
3581: if (deviceExtension->AdapterFlags & PD_NCR_ADAPTER) {
3582:
3583: *((PUCHAR) &DmaStatus) = SCSI_READ( deviceExtension->AdapterBase, DmaStatus );
3584:
3585: if (DmaStatus.Interrupt == deviceExtension->InterruptPending) {
3586: *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ( deviceExtension->Adapter, ScsiStatus );
3587: deviceExtension->InterruptCount++;
3588: goto NextInterrupt;
3589:
3590: }
3591: } else {
3592:
3593: *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ ( deviceExtension->Adapter, ScsiStatus );
3594:
3595: if (deviceExtension->AdapterStatus.Interrupt) {
3596: deviceExtension->InterruptCount++;
3597: goto NextInterrupt;
3598:
3599: }
3600: }
3601:
3602: return(TRUE);
3603: }
3604:
3605: VOID
3606: NcrLogError(
3607: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
3608: IN ULONG ErrorCode,
3609: IN ULONG UniqueId
3610: )
3611: /*++
3612:
3613: Routine Description:
3614:
3615: This routine logs an error.
3616:
3617: Arguments:
3618:
3619: DeviceExtension - Supplies a pointer to the device extension for the
3620: port adapter to which the completing target controller is connected.
3621:
3622: ErrorCode - Supplies the error code to log with the error.
3623:
3624: UniqueId - Supplies the unique error identifier.
3625:
3626: Return Value:
3627:
3628: None.
3629:
3630: --*/
3631: {
3632:
3633: PSCSI_REQUEST_BLOCK srb;
3634:
3635: //
3636: // Look for a current request in the device extension.
3637: //
3638:
3639: if (DeviceExtension->ActiveLogicalUnit != NULL) {
3640:
3641: if (DeviceExtension->ActiveLuRequest != NULL) {
3642:
3643: srb = DeviceExtension->ActiveLuRequest;
3644:
3645: } else {
3646:
3647: srb = DeviceExtension->ActiveLogicalUnit->ActiveSendRequest;
3648:
3649: }
3650:
3651: } else {
3652:
3653: srb = DeviceExtension->NextSrbRequest;
3654:
3655: }
3656:
3657: //
3658: // If the srb is NULL, then log the error against the host adapter address.
3659: //
3660:
3661: if (srb == NULL) {
3662:
3663: ScsiPortLogError(
3664: DeviceExtension, // HwDeviceExtension,
3665: NULL, // Srb
3666: 0, // PathId,
3667: DeviceExtension->AdapterBusId, // TargetId,
3668: 0, // Lun,
3669: ErrorCode, // ErrorCode,
3670: UniqueId // UniqueId
3671: );
3672:
3673: } else {
3674:
3675: ScsiPortLogError(
3676: DeviceExtension, // HwDeviceExtension,
3677: srb, // Srb
3678: srb->PathId, // PathId,
3679: srb->TargetId, // TargetId,
3680: srb->Lun, // Lun,
3681: ErrorCode, // ErrorCode,
3682: UniqueId // UniqueId
3683: );
3684:
3685: }
3686:
3687: }
3688:
3689:
3690: VOID
3691: NcrProcessRequestCompletion(
3692: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension
3693: )
3694: /*++
3695:
3696: Routine Description:
3697:
3698: This routine does all of checking and state updating necessary when a
3699: request terminates normally. It determines what the SrbStatus
3700: should be and updates the state in the DeviceExtension, the
3701: logicalUnitExtension and the srb.
3702:
3703: Arguments:
3704:
3705: DeviceExtension - Supplies a pointer to the device extension for the
3706: port adapter on to which the completing target controller is connected.
3707:
3708: Return Value:
3709:
3710: None.
3711:
3712: --*/
3713:
3714: {
3715: PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
3716: PSCSI_REQUEST_BLOCK srb;
3717:
3718: luExtension = DeviceExtension->ActiveLogicalUnit;
3719: srb = DeviceExtension->ActiveLuRequest;
3720:
3721: ASSERT(DeviceExtension->NextSrbRequest != srb);
3722:
3723: if ( srb->ScsiStatus != SCSISTAT_GOOD &&
3724: srb->ScsiStatus != SCSISTAT_CONDITION_MET &&
3725: srb->ScsiStatus != SCSISTAT_INTERMEDIATE &&
3726: srb->ScsiStatus != SCSISTAT_INTERMEDIATE_COND_MET ) {
3727:
3728: //
3729: // Indicate an abnormal status code.
3730: //
3731:
3732: srb->SrbStatus = SRB_STATUS_ERROR;
3733:
3734: //
3735: // Indicate that a INITIATE RECOVERY message was received. This
3736: // indicates to the class driver that it must send a TERMINATE
3737: // RECOVERY message before the logical unit will resume normal
3738: // operation.
3739: //
3740:
3741: if (SRB_EXT(srb)->SrbExtensionFlags & PD_INITIATE_RECOVERY) {
3742:
3743: //
3744: // Modify the SrbStatus.
3745: //
3746:
3747: srb->SrbStatus = SRB_STATUS_ERROR_RECOVERY;
3748: }
3749:
3750: //
3751: // If this is a check condition, then clear the synchronous negotiation
3752: // done flag. This is done in case the controller was power cycled.
3753: //
3754:
3755: if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION) {
3756:
3757: DeviceExtension->TargetState[srb->TargetId].TargetFlags
3758: &= ~PD_SYNCHRONOUS_NEGOTIATION_DONE;
3759:
3760: }
3761:
3762: //
3763: // If there is a pending request for this logical unit then return
3764: // that request with a busy status. This situation only occurs when
3765: // command queuing is enabled an a command pending for a logical unit
3766: // at the same time that an error has occured. This may be a BUSY,
3767: // QUEUE FULL or CHECK CONDITION. The important case is CHECK CONDITION
3768: // because a contingatent aligance condition has be established and the
3769: // port driver needs a chance to send a Reqeust Sense before the
3770: // pending command is started.
3771: //
3772:
3773: if (DeviceExtension->AdapterFlags & PD_PENDING_START_IO &&
3774: DeviceExtension->NextSrbRequest->PathId == srb->PathId &&
3775: DeviceExtension->NextSrbRequest->TargetId == srb->TargetId &&
3776: DeviceExtension->NextSrbRequest->Lun == srb->Lun) {
3777:
3778: NcrPrint((1, "NcrProcessRequestCompletion: Failing request with busy status due to check condition\n"));
3779: DeviceExtension->NextSrbRequest->SrbStatus =
3780: SCSISTAT_CHECK_CONDITION;
3781:
3782: DeviceExtension->NextSrbRequest->ScsiStatus = SCSISTAT_BUSY;
3783:
3784: ScsiPortNotification(
3785: RequestComplete,
3786: DeviceExtension,
3787: DeviceExtension->NextSrbRequest
3788: );
3789:
3790: //
3791: // Make sure the request is not sitting in the logical unit.
3792: //
3793:
3794: if (DeviceExtension->NextSrbRequest == luExtension->ActiveLuRequest) {
3795:
3796: luExtension->ActiveLuRequest = NULL;
3797:
3798: } else if (DeviceExtension->NextSrbRequest ==
3799: luExtension->ActiveSendRequest) {
3800:
3801: luExtension->ActiveSendRequest = NULL;
3802: }
3803:
3804: DeviceExtension->NextSrbRequest = NULL;
3805: DeviceExtension->AdapterFlags &= ~PD_PENDING_START_IO;
3806:
3807: ScsiPortNotification(
3808: NextRequest,
3809: DeviceExtension,
3810: NULL
3811: );
3812:
3813: }
3814:
3815: } else {
3816:
3817: //
3818: // Everything looks correct so far.
3819: //
3820:
3821: srb->SrbStatus = SRB_STATUS_SUCCESS;
3822:
3823: //
3824: // Make sure that status is valid.
3825: //
3826:
3827: if (!(SRB_EXT(srb)->SrbExtensionFlags & PD_STATUS_VALID)) {
3828:
3829: //
3830: // The status byte is not valid.
3831: //
3832:
3833: srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
3834:
3835: //
3836: // Log the error.
3837: //
3838:
3839: NcrLogError(DeviceExtension, SP_PROTOCOL_ERROR, 12);
3840:
3841: }
3842:
3843:
3844: }
3845:
3846: //
3847: // Check that data was transferred to the end of the buffer.
3848: //
3849:
3850: if ( SRB_EXT(srb)->MaximumTransferLength != srb->DataTransferLength ){
3851:
3852: //
3853: // The entire buffer was not transferred. Update the length
3854: // and update the status code.
3855: //
3856:
3857: if (srb->SrbStatus == SRB_STATUS_SUCCESS) {
3858:
3859: NcrPrint((1, "NcrProcessRequestCompletion: Short transfer, Actual: %x; Expected: %x;\n",
3860: SRB_EXT(srb)->MaximumTransferLength,
3861: srb->DataTransferLength
3862: ));
3863:
3864: //
3865: // If no data was transferred then indicated this was a
3866: // protocol error rather than a data under/over run.
3867: //
3868:
3869: if (srb->DataTransferLength == 0) {
3870: srb->SrbStatus = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
3871: } else {
3872: srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
3873: }
3874:
3875: srb->DataTransferLength = SRB_EXT(srb)->MaximumTransferLength;
3876: } else {
3877:
3878: //
3879: // Update the length if a check condition was returned.
3880: //
3881:
3882: if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION) {
3883: srb->DataTransferLength = SRB_EXT(srb)->MaximumTransferLength;
3884: }
3885: }
3886: }
3887:
3888: if (srb->SrbStatus != SRB_STATUS_SUCCESS) {
3889: NcrPrint((1, "NcrProcessRequestCompletion: Request failed. ScsiStatus: %x, SrbStatus: %x\n",
3890: srb->ScsiStatus,
3891: srb->SrbStatus
3892: ));
3893: }
3894:
3895: //
3896: // Clear the request but not the ActiveLogicalUnit since the target has
3897: // not disconnected from the SCSI bus yet.
3898: //
3899:
3900: DeviceExtension->ActiveLuRequest = NULL;
3901: luExtension->ActiveLuRequest = NULL;
3902: luExtension->RetryCount = 0;
3903: luExtension->LuFlags &= ~PD_LU_COMPLETE_MASK;
3904: }
3905:
3906: BOOLEAN
3907: NcrResetScsiBus(
3908: IN PVOID ServiceContext,
3909: IN ULONG PathId
3910: )
3911:
3912: /*++
3913:
3914: Routine Description:
3915:
3916: This function resets the SCSI bus and calls the reset cleanup function.
3917:
3918: Arguments:
3919:
3920: ServiceContext - Supplies a pointer to the specific device extension.
3921:
3922: PathId - Supplies the path id of the bus.
3923:
3924: Return Value:
3925:
3926: TRUE - Indicating the reset is complete.
3927:
3928: --*/
3929:
3930: {
3931: PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
3932:
3933: NcrPrint((1, "NcrResetScsiBus: Resetting the SCSI bus.\n"));
3934:
3935: //
3936: // The bus should be reset regardless of what is occurring on the bus or in
3937: // the chip. The reset SCSI bus command executes immediately.
3938: //
3939:
3940: SCSI_WRITE(deviceExtension->Adapter, Command, RESET_SCSI_BUS);
3941:
3942: //
3943: // Delay the minimum assertion time for a SCSI bus reset to make sure a
3944: // valid reset signal is sent.
3945: //
3946:
3947: ScsiPortStallExecution( RESET_STALL_TIME );
3948:
3949: NcrCleanupAfterReset(deviceExtension, FALSE);
3950: deviceExtension->AdapterFlags |= PD_EXPECTING_RESET_INTERRUPT;
3951:
3952: return(TRUE);
3953: }
3954:
3955: VOID
3956: NcrResetScsiBusInternal(
3957: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
3958: IN ULONG PathId
3959: )
3960: /*++
3961:
3962: Routine Description:
3963:
3964: This function resets the SCSI bus and notifies the port driver.
3965:
3966: Arguments:
3967:
3968: DeviceExtension - Supplies a pointer to the specific device extension.
3969:
3970: PathId - Supplies the path id of the bus.
3971:
3972: Return Value:
3973:
3974: None
3975:
3976: --*/
3977: {
3978:
3979: ScsiPortNotification(
3980: ResetDetected,
3981: DeviceExtension,
3982: NULL
3983: );
3984:
3985: NcrResetScsiBus(DeviceExtension, 0);
3986: }
3987:
3988: VOID
3989: NcrSelectTarget(
3990: IN PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
3991: IN PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
3992: )
3993: /*++
3994:
3995: Routine Description:
3996:
3997: This routine sets up the hardware to select a target. If a valid message
3998: is in the message buffer, it will be sent to the target. If the request
3999: includes a SCSI command descriptor block, it will also be passed to the
4000: target.
4001:
4002: Arguments:
4003:
4004: DeviceExtension - Supplies the device extension for this HBA adapter.
4005:
4006: LuExtension - Supplies the logical unit extension for the target being
4007: selected.
4008:
4009: Return Value:
4010:
4011: None
4012:
4013: --*/
4014:
4015: {
4016: PSCSI_REQUEST_BLOCK srb;
4017: PSPECIFIC_TARGET_EXTENSION targetState;
4018: SCSI_DMA_STATUS DmaStatus;
4019: LONG i;
4020:
4021: srb = DeviceExtension->NextSrbRequest;
4022:
4023: targetState = &DeviceExtension->TargetState[srb->TargetId];
4024:
4025: #if DBG
4026: if (NcrDebug) {
4027: NcrPrint((0, "NcrSelectTarget: Attempting target select.\n"));
4028: }
4029: #endif
4030: /* Powerfail Start */
4031:
4032: //
4033: // Set up the SCSI protocol chip to select the target, transfer the
4034: // IDENTIFY message and the CDB. This can be done by following steps:
4035: //
4036: // setting the destination register,
4037: // filling the FIFO with the IDENTIFY message and the CDB
4038: // setting the command register
4039: //
4040: // If the chip is not interrupting, then set up for selection. If the
4041: // chip is interrupting then return. The interrupt will process the
4042: // request. Note that if we get reselected after this point the chip
4043: // will ignore the bytes written until the interrupt register is read.
4044: // The commands that handle a message and a CDB can only be used if the
4045: // message is one byte or 3 bytes long; otherwise only a one-byte message
4046: // is transferred on the select and the remaining bytes are handled in the
4047: // interrupt routine.
4048: //
4049:
4050: if (DeviceExtension->AdapterFlags & PD_NCR_ADAPTER) {
4051:
4052: *((PUCHAR) &DmaStatus) = SCSI_READ( DeviceExtension->AdapterBase, DmaStatus );
4053: if (DmaStatus.Interrupt == DeviceExtension->InterruptPending) {
4054: return;
4055: }
4056:
4057: } else {
4058:
4059: *((PUCHAR) &DeviceExtension->AdapterStatus) = SCSI_READ( DeviceExtension->Adapter, ScsiStatus );
4060: if (DeviceExtension->AdapterStatus.Interrupt) {
4061: return;
4062: }
4063:
4064: }
4065:
4066: //
4067: // Set the destination ID. Put the first byte of the message-in
4068: // the fifo and set the command to select with ATN. This command
4069: // selects the target, sends one message byte and interrupts. The
4070: // ATN line remains set. The succeeding bytes are loaded into the
4071: // FIFO and sent to the target by the interrupt service routine.
4072: //
4073:
4074: SCSI_WRITE(DeviceExtension->Adapter, DestinationId, srb->TargetId);
4075: SCSI_WRITE( DeviceExtension->Adapter,
4076: Fifo,
4077: DeviceExtension->MessageBuffer[DeviceExtension->MessageSent++]
4078: );
4079:
4080: //
4081: // Set the synchronous data transfer parameter registers in case a
4082: // data transfer is done. These must be set before a data transfer
4083: // is started.
4084: //
4085:
4086: SCSI_WRITE( DeviceExtension->Adapter,
4087: SynchronousPeriod,
4088: targetState->SynchronousPeriod
4089: );
4090: SCSI_WRITE( DeviceExtension->Adapter,
4091: SynchronousOffset,
4092: targetState->SynchronousOffset
4093: );
4094:
4095: SCSI_WRITE( DeviceExtension->Adapter,
4096: Configuration3,
4097: *((PCHAR) &targetState->Configuration3)
4098: );
4099:
4100:
4101: //
4102: // Determine if this srb has a Cdb with it and whether the message is such that
4103: // the message and the Cdb can be loaded into the fifo; otherwise, just
4104: // load the first byte of the message.
4105: //
4106:
4107: if (srb->Function == SRB_FUNCTION_EXECUTE_SCSI &&
4108: (DeviceExtension->MessageCount == 1 ||
4109: DeviceExtension->MessageCount == 3)) {
4110:
4111: //
4112: // Copy the entire message and Cdb into the fifo.
4113: //
4114:
4115: for (;
4116: DeviceExtension->MessageSent <
4117: DeviceExtension->MessageCount;
4118: DeviceExtension->MessageSent++ ) {
4119:
4120: SCSI_WRITE( DeviceExtension->Adapter,
4121: Fifo,
4122: DeviceExtension->
4123: MessageBuffer[DeviceExtension->MessageSent]
4124: );
4125:
4126: }
4127:
4128: for (i = 0; i < srb->CdbLength; i++) {
4129: SCSI_WRITE(DeviceExtension->Adapter,
4130: Fifo,
4131: srb->Cdb[i]
4132: );
4133: }
4134:
4135: if (DeviceExtension->MessageCount == 1) {
4136:
4137: //
4138: // One message byte so use select with attention which uses one
4139: // message byte.
4140: //
4141:
4142: SCSI_WRITE(
4143: DeviceExtension->Adapter,
4144: Command,
4145: SELECT_WITH_ATTENTION
4146: );
4147:
4148: } else {
4149:
4150: //
4151: // Three byte message, so use the select with attention which uses
4152: // three byte messages.
4153: //
4154:
4155: SCSI_WRITE(
4156: DeviceExtension->Adapter,
4157: Command,
4158: SELECT_WITH_ATTENTION3
4159: );
4160:
4161: }
4162:
4163: } else {
4164:
4165: //
4166: // Only the first byte of the message can be sent so select with
4167: // ATTENTION and the target will request the rest.
4168: //
4169:
4170: SCSI_WRITE(
4171: DeviceExtension->Adapter,
4172: Command,
4173: SELECT_WITH_ATTENTION_STOP
4174: );
4175:
4176: }
4177:
4178: /* Powerfail release */
4179:
4180: //
4181: // Set the device state to message-out and indicate that a message
4182: // is being sent.
4183: //
4184:
4185: DeviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
4186: DeviceExtension->AdapterState = AttemptingSelect;
4187: DeviceExtension->InterruptCount = 0;
4188:
4189: }
4190:
4191:
4192: VOID
4193: NcrSendMessage(
4194: PSCSI_REQUEST_BLOCK Srb,
4195: PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
4196: PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
4197: )
4198:
4199: /*++
4200:
4201: Routine Description:
4202:
4203: This routine attempts to send the indicated message to the target
4204: controller. There are three classes of messages:
4205: Those which terminate a specific request and end in bus free.
4206: Those which apply to a specific request and then proceed.
4207: Those which end in bus free.
4208:
4209: For those messages that apply to a specific request, check to see that
4210: the request is currently being processed and an INDENTIFY message prefixed
4211: to the message.
4212:
4213: It is possible that the destination logical unit is the active logical unit;
4214: however, it would difficult to jump in and send the requested message, so
4215: just wait for the bus to become free.
4216:
4217: In the case where the target is not currently active, then set up the SCSI
4218: protocol chip to select the target controller and send the message.
4219:
4220: Arguments:
4221:
4222: Srb - Supplies the request to be started.
4223:
4224: DeviceExtension - Supplies the extended device extension for this SCSI bus.
4225:
4226: LuExtension - Supplies the logical unit extension for this request.
4227:
4228: Notes:
4229:
4230: This routine must be synchronized with the interrupt routine.
4231:
4232: Return Value:
4233:
4234: None
4235:
4236: --*/
4237: {
4238: PSCSI_REQUEST_BLOCK linkedSrb;
4239: BOOLEAN impliesDisconnect;
4240: BOOLEAN useTag;
4241: UCHAR message;
4242:
4243: impliesDisconnect = FALSE;
4244: useTag = FALSE;
4245:
4246: //
4247: // Decode the type of message.
4248: //
4249:
4250: switch (Srb->Function) {
4251:
4252: case SRB_FUNCTION_TERMINATE_IO:
4253: case SRB_FUNCTION_ABORT_COMMAND:
4254:
4255: //
4256: // Verify that the request is being processed by the logical unit.
4257: //
4258:
4259: linkedSrb = ScsiPortGetSrb(
4260: DeviceExtension,
4261: Srb->PathId,
4262: Srb->TargetId,
4263: Srb->Lun,
4264: Srb->QueueTag
4265: );
4266:
4267: if (linkedSrb != Srb->NextSrb) {
4268:
4269: //
4270: // The specified request is not here. Complete the request
4271: // without error.
4272: //
4273:
4274: Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
4275: ScsiPortNotification(
4276: RequestComplete,
4277: DeviceExtension,
4278: Srb
4279: );
4280:
4281: ScsiPortNotification(
4282: NextRequest,
4283: DeviceExtension,
4284: NULL
4285: );
4286:
4287: return;
4288: }
4289:
4290: if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
4291: impliesDisconnect = TRUE;
4292: message = SCSIMESS_ABORT;
4293: } else {
4294: message = SCSIMESS_TERMINATE_IO_PROCESS;
4295: impliesDisconnect = FALSE;
4296: }
4297:
4298: //
4299: // Use a tagged message if the original request was tagged.
4300: //
4301:
4302: useTag = linkedSrb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE ?
4303: TRUE : FALSE;
4304:
4305: break;
4306:
4307: case SRB_FUNCTION_RESET_DEVICE:
4308:
4309: //
4310: // Because of the way the chip works it is easiest to send an IDENTIFY
4311: // message along with the BUS DEVICE RESET message. That is because
4312: // there is no way to select a target with ATN and send one message
4313: // byte. This IDENTIFY message is not necessary for the SCSI protocol,
4314: // but it is legal and should not cause any problem.
4315: //
4316:
4317: message = SCSIMESS_BUS_DEVICE_RESET;
4318: impliesDisconnect = TRUE;
4319: break;
4320:
4321: case SRB_FUNCTION_RELEASE_RECOVERY:
4322:
4323: //
4324: // These messages require an IDENTIFY message and imply a disconnect.
4325: //
4326:
4327: impliesDisconnect = TRUE;
4328: message = SCSIMESS_RELEASE_RECOVERY;
4329: break;
4330:
4331: case SCSIMESS_CLEAR_QUEUE:
4332:
4333: //
4334: // These messages require an IDENTIFY message and imply a disconnect.
4335: //
4336:
4337: message = SCSIMESS_CLEAR_QUEUE;
4338: impliesDisconnect = TRUE;
4339: break;
4340:
4341: default:
4342:
4343: //
4344: // This is an unsupported message request. Fail the request.
4345: //
4346:
4347: Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
4348: ScsiPortNotification(
4349: RequestComplete,
4350: DeviceExtension,
4351: Srb
4352: );
4353:
4354: ScsiPortNotification(
4355: NextRequest,
4356: DeviceExtension,
4357: NULL
4358: );
4359:
4360: return;
4361: }
4362:
4363: //
4364: // Save away the parameters in case nothing can be done now.
4365: //
4366:
4367: DeviceExtension->NextSrbRequest = Srb;
4368: DeviceExtension->AdapterFlags |= PD_PENDING_START_IO;
4369: LuExtension->ActiveSendRequest = Srb;
4370:
4371: //
4372: // Check to see if the bus is free. If it is not, then return. Since
4373: // the request parameters have been saved, indicate that the request has
4374: // been accepted. The request will be processed when the bus becomes free.
4375: //
4376:
4377: if (DeviceExtension->AdapterState != BusFree) {
4378: return;
4379: }
4380:
4381: //
4382: // Create the identify command and copy the message to the buffer.
4383: //
4384:
4385: DeviceExtension->MessageBuffer[0] = SCSIMESS_IDENTIFY_WITH_DISCON |
4386: Srb->Lun;
4387: DeviceExtension->MessageCount = 1;
4388: DeviceExtension->MessageSent = 0;
4389:
4390: if (useTag && Srb->QueueTag != SP_UNTAGGED) {
4391: DeviceExtension->MessageBuffer[DeviceExtension->MessageCount++] = SCSIMESS_SIMPLE_QUEUE_TAG;
4392: DeviceExtension->MessageBuffer[DeviceExtension->MessageCount++] = Srb->QueueTag;
4393:
4394: if (message == SCSIMESS_ABORT) {
4395: message = SCSIMESS_ABORT_WITH_TAG;
4396: }
4397: }
4398:
4399: DeviceExtension->MessageBuffer[DeviceExtension->MessageCount++] = message;
4400:
4401: //
4402: // Attempt to select the target and update the adapter flags.
4403: //
4404:
4405: NcrSelectTarget( DeviceExtension, LuExtension );
4406:
4407: DeviceExtension->AdapterFlags |= impliesDisconnect ?
4408: PD_DISCONNECT_EXPECTED | PD_SEND_MESSAGE_REQUEST
4409: : PD_SEND_MESSAGE_REQUEST;
4410:
4411: }
4412:
4413: VOID
4414: NcrStartExecution(
4415: PSCSI_REQUEST_BLOCK Srb,
4416: PSPECIFIC_DEVICE_EXTENSION DeviceExtension,
4417: PSPECIFIC_LOGICAL_UNIT_EXTENSION LuExtension
4418: )
4419:
4420: /*++
4421:
4422: Routine Description:
4423:
4424: This procedure sets up the chip to select the target and notify it that
4425: a request is available. For the NCR chip, the chip is set up to select,
4426: send the IDENTIFY message and send the command data block. A check is
4427: made to determine if synchronous negotiation is necessary.
4428:
4429: Arguments:
4430:
4431: Srb - Supplies the request to be started.
4432:
4433: DeviceExtension - Supplies the extended device extension for this SCSI bus.
4434:
4435: LuExtension - Supplies the logical unit extension for this requst.
4436:
4437: Notes:
4438:
4439: This routine must be synchronized with the interrupt routine.
4440:
4441: Return Value:
4442:
4443: None
4444:
4445: --*/
4446:
4447: {
4448:
4449: PSCSI_EXTENDED_MESSAGE extendedMessage;
4450: CHIP_TYPES chipType;
4451: PSPECIFIC_TARGET_EXTENSION targetState;
4452:
4453: //
4454: // Save away the parameters in case nothing can be done now.
4455: //
4456:
4457: SRB_EXT(Srb)->SavedDataPointer = (ULONG) Srb->DataBuffer;
4458: SRB_EXT(Srb)->SavedDataLength = Srb->DataTransferLength;
4459: SRB_EXT(Srb)->SrbExtensionFlags = 0;
4460: SRB_EXT(Srb)->MaximumTransferLength = 0;
4461: DeviceExtension->NextSrbRequest = Srb;
4462: DeviceExtension->AdapterFlags |= PD_PENDING_START_IO;
4463:
4464: //
4465: // Check to see if the bus is free. If it is not, then return. Since
4466: // the request parameters have been saved, indicate that the request has
4467: // been accepted. The request will be processed when the bus becomes free.
4468: //
4469:
4470: if (DeviceExtension->AdapterState != BusFree) {
4471: return;
4472: }
4473:
4474: //
4475: // Create the identify command.
4476: //
4477:
4478: DeviceExtension->MessageCount = 1;
4479: DeviceExtension->MessageSent = 0;
4480: DeviceExtension->AdapterFlags |= PD_MESSAGE_OUT_VALID;
4481:
4482: DeviceExtension->MessageBuffer[0] = SCSIMESS_IDENTIFY | Srb->Lun;
4483:
4484: DeviceExtension->TargetId = Srb->TargetId;
4485: targetState = &DeviceExtension->TargetState[Srb->TargetId];
4486:
4487: //
4488: // Check to see if disconnect is allowed. If not then don't do tagged
4489: // queuing either.
4490: //
4491:
4492: if (!(Srb->SrbFlags & SRB_FLAGS_DISABLE_DISCONNECT)) {
4493:
4494: //
4495: // Enable disconnects in the message.
4496: //
4497:
4498: DeviceExtension->MessageBuffer[0] |= SCSIMESS_IDENTIFY_WITH_DISCON;
4499:
4500: //
4501: // If this is a tagged command then create a tagged message.
4502: //
4503:
4504: if (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) {
4505:
4506: //
4507: // The queue tag message is two bytes the first is the queue action
4508: // and the second is the queue tag.
4509: //
4510:
4511: DeviceExtension->MessageBuffer[1] = Srb->QueueAction;
4512: DeviceExtension->MessageBuffer[2] = Srb->QueueTag;
4513: DeviceExtension->MessageCount += 2;
4514: DeviceExtension->AdapterFlags |= PD_TAGGED_SELECT;
4515:
4516: } else {
4517: LuExtension->ActiveLuRequest = Srb;
4518: }
4519:
4520: } else {
4521: LuExtension->ActiveLuRequest = Srb;
4522: }
4523:
4524: //
4525: // Check to see if synchronous negotiation is necessary.
4526: //
4527:
4528: if (!(targetState->TargetFlags &
4529: (PD_SYNCHRONOUS_NEGOTIATION_DONE | PD_DO_NOT_NEGOTIATE))) {
4530:
4531: //
4532: // Initialize the synchronous transfer register values to an
4533: // asynchronous transfer, which is what will be used if anything
4534: // goes wrong with the negotiation.
4535: //
4536:
4537: targetState->SynchronousOffset = ASYNCHRONOUS_OFFSET;
4538: targetState->SynchronousPeriod = ASYNCHRONOUS_PERIOD;
4539: targetState->Configuration3 = DeviceExtension->Configuration3;
4540:
4541: if (Srb->SrbFlags & SRB_FLAGS_DISABLE_SYNCH_TRANSFER) {
4542:
4543: //
4544: // Synchronous transfers are disabled by the SRB.
4545: //
4546:
4547: NcrSelectTarget( DeviceExtension, LuExtension );
4548: return;
4549: }
4550:
4551: if (DeviceExtension->ChipType == Fas216) {
4552:
4553: //
4554: // The Fas216 supports fast synchronous transfers.
4555: //
4556:
4557: chipType = Fas216Fast;
4558:
4559: } else if (DeviceExtension->ChipType == Ncr53c90) {
4560:
4561: //
4562: // The 53c90 does not support synchronous transfers.
4563: // Set the do not negotate flag in the logical unit structure.
4564: //
4565:
4566: targetState->TargetFlags |= PD_DO_NOT_NEGOTIATE;
4567: NcrSelectTarget( DeviceExtension, LuExtension );
4568: return;
4569:
4570: } else {
4571:
4572: chipType = DeviceExtension->ChipType;
4573:
4574: }
4575:
4576: //
4577: // Create the synchronous data transfer request message.
4578: // The format of the message is:
4579: //
4580: // EXTENDED_MESSAGE op-code
4581: // Length of message
4582: // Synchronous transfer data request op-code
4583: // Our Transfer period
4584: // Our REQ/ACK offset
4585: //
4586: // The message is placed after the IDENTIFY message.
4587: //
4588:
4589: extendedMessage = (PSCSI_EXTENDED_MESSAGE)
4590: &DeviceExtension->MessageBuffer[DeviceExtension->MessageCount];
4591: DeviceExtension->MessageCount += 2 + SCSIMESS_SYNCH_DATA_LENGTH;
4592:
4593: extendedMessage->InitialMessageCode = SCSIMESS_EXTENDED_MESSAGE;
4594: extendedMessage->MessageLength = SCSIMESS_SYNCH_DATA_LENGTH;
4595: extendedMessage->MessageType = SCSIMESS_SYNCHRONOUS_DATA_REQ;
4596:
4597: //
4598: // If this chips does not suport fast SCSI, just calculate the normal
4599: // minimum transfer period; otherwise use the fast value.
4600: //
4601:
4602: //
4603: // The initial sychronous transfer period is:
4604: //
4605: // SynchronousPeriodCyles * 1000
4606: // -----------------------------
4607: // ClockSpeed * 4
4608: //
4609: // Note the result of the divide by four must be rounded up.
4610: //
4611:
4612: extendedMessage->ExtendedArguments.Synchronous.TransferPeriod =
4613: ((SynchronousTransferTypes[chipType].SynchronousPeriodCyles * 1000) /
4614: DeviceExtension->ClockSpeed + 3) / 4;
4615: extendedMessage->ExtendedArguments.Synchronous.ReqAckOffset = SYNCHRONOUS_OFFSET;
4616:
4617: //
4618: // Attempt to select the target and update the adapter flags.
4619: //
4620:
4621: NcrSelectTarget( DeviceExtension, LuExtension );
4622:
4623: //
4624: // Many controllers reject the first byte of a synchronous
4625: // negotiation message. Since this is a multibyte message the
4626: // ATN signal remains set after the first byte is sent. Some
4627: // controllers remember this attempt to do a message-out
4628: // later. Setting the PD_POSSIBLE_EXTRA_MESSAGE_OUT flag allows
4629: // this extra message transfer to occur without error.
4630: //
4631:
4632: DeviceExtension->AdapterFlags |= PD_POSSIBLE_EXTRA_MESSAGE_OUT |
4633: PD_SYNCHRONOUS_TRANSFER_SENT;
4634:
4635: return;
4636: }
4637:
4638: NcrSelectTarget( DeviceExtension, LuExtension );
4639:
4640: }
4641:
4642: BOOLEAN
4643: NcrStartIo(
4644: IN PVOID ServiceContext,
4645: IN PSCSI_REQUEST_BLOCK Srb
4646: )
4647: /*++
4648:
4649: Routine Description:
4650:
4651: This function is used by the OS dependent port driver to pass requests to
4652: the dependent driver. This function begins the execution of the request.
4653: Requests to reset the SCSI bus are handled immediately. Requests to send
4654: a message or start a SCSI command are handled when the bus is free.
4655:
4656: Arguments:
4657:
4658: ServiceContext - Supplies the device Extension for the SCSI bus adapter.
4659:
4660: Srb - Supplies the SCSI request block to be started.
4661:
4662: Return Value:
4663:
4664: TRUE - If the request can be accepted at this time.
4665:
4666: FALSE - If the request must be submitted later.
4667:
4668: --*/
4669:
4670: {
4671: PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
4672: PSPECIFIC_LOGICAL_UNIT_EXTENSION luExtension;
4673:
4674: switch (Srb->Function) {
4675: case SRB_FUNCTION_EXECUTE_SCSI:
4676:
4677: //
4678: // Determine the logical unit that this request is for.
4679: //
4680:
4681: luExtension = ScsiPortGetLogicalUnit(
4682: deviceExtension,
4683: Srb->PathId,
4684: Srb->TargetId,
4685: Srb->Lun
4686: );
4687:
4688: NcrStartExecution(
4689: Srb,
4690: deviceExtension,
4691: luExtension
4692: );
4693:
4694: return(TRUE);
4695:
4696: case SRB_FUNCTION_ABORT_COMMAND:
4697: case SRB_FUNCTION_RESET_DEVICE:
4698: case SRB_FUNCTION_TERMINATE_IO:
4699:
4700: //
4701: // Determine the logical unit that this request is for.
4702: //
4703:
4704: luExtension = ScsiPortGetLogicalUnit(
4705: deviceExtension,
4706: Srb->PathId,
4707: Srb->TargetId,
4708: Srb->Lun
4709: );
4710:
4711: NcrSendMessage(
4712: Srb,
4713: deviceExtension,
4714: luExtension
4715: );
4716:
4717: return(TRUE);
4718:
4719: case SRB_FUNCTION_RESET_BUS:
4720:
4721: //
4722: // There is no logical unit so just reset the bus.
4723: //
4724:
4725: NcrResetScsiBusInternal( deviceExtension, 0 );
4726: return(TRUE);
4727:
4728: default:
4729:
4730: //
4731: // Unknown function code in the request. Complete the request with
4732: // an error and ask for the next request.
4733: //
4734:
4735: Srb->SrbStatus = SRB_STATUS_BAD_FUNCTION;
4736: ScsiPortNotification(
4737: RequestComplete,
4738: deviceExtension,
4739: Srb
4740: );
4741:
4742: ScsiPortNotification(
4743: NextRequest,
4744: deviceExtension,
4745: NULL
4746: );
4747:
4748: return(TRUE);
4749: }
4750:
4751: }
4752:
4753: VOID
4754: NcrStartDataTransfer(
4755: IN PVOID ServiceContext
4756: )
4757: /*++
4758:
4759: Routine Description:
4760:
4761: This routine sets up the scsi bus protocol chip to perform a data transfer.
4762: It is called after the DMA has been initialized.
4763:
4764: Arguments:
4765:
4766: ServiceContext - Supplies a pointer to the specific device extension.
4767:
4768: Return Value:
4769:
4770: None.
4771:
4772: --*/
4773:
4774: {
4775: PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
4776:
4777: //
4778: // If the data tranfer is no longer expected then ignore the notification.
4779: //
4780:
4781: if (!(deviceExtension->AdapterFlags & PD_PENDING_DATA_TRANSFER)) {
4782:
4783: return;
4784:
4785: }
4786:
4787: //
4788: // Set up the SCSI protocol chip for the data transfer with the
4789: // command to start.
4790: //
4791:
4792: SCSI_WRITE( deviceExtension->Adapter,
4793: Command,
4794: TRANSFER_INFORMATION_DMA
4795: );
4796:
4797: deviceExtension->AdapterFlags &= ~PD_PENDING_DATA_TRANSFER;
4798:
4799: }
4800:
4801: ULONG
4802: DriverEntry(
4803: IN PVOID DriverObject,
4804: IN PVOID Argument2
4805: )
4806:
4807: /*++
4808:
4809: Routine Description:
4810:
4811: Arguments:
4812:
4813: Driver Object is passed to ScsiPortInitialize()
4814:
4815: Return Value:
4816:
4817: Status from ScsiPortInitialize()
4818:
4819: --*/
4820:
4821: {
4822: HW_INITIALIZATION_DATA hwInitializationData;
4823: ULONG i;
4824: ULONG Status1;
4825: ULONG Status2;
4826: INIT_DATA InitData;
4827:
4828: ScsiDebugPrint(1,"\n\nNCR 53c9x SCSI MiniPort Driver\n");
4829:
4830: //
4831: // Zero out hardware initialization data structure.
4832: //
4833:
4834: for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
4835: ((PUCHAR)&hwInitializationData)[i] = 0;
4836: }
4837:
4838: //
4839: // Fill in the hardware initialization data structure.
4840: //
4841:
4842: hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
4843: hwInitializationData.HwInitialize = NcrInitializeAdapter;
4844: hwInitializationData.HwStartIo = NcrStartIo;
4845: hwInitializationData.HwInterrupt = NcrInterruptServiceRoutine;
4846: hwInitializationData.HwFindAdapter = NcrMcaFindAdapter;
4847: hwInitializationData.HwResetBus = NcrResetScsiBus;
4848: hwInitializationData.HwDmaStarted = NcrStartDataTransfer;
4849: hwInitializationData.NumberOfAccessRanges = 1;
4850: hwInitializationData.AdapterInterfaceType = MicroChannel;
4851: hwInitializationData.DeviceExtensionSize = sizeof(SPECIFIC_DEVICE_EXTENSION);
4852: hwInitializationData.SpecificLuExtensionSize =
4853: sizeof(SPECIFIC_LOGICAL_UNIT_EXTENSION);
4854: hwInitializationData.SrbExtensionSize = sizeof(SRB_EXTENSION);
4855:
4856: //
4857: // Initialize configuration information.
4858: //
4859: // The following adapter search order should be observed:
4860: // 1. Onboard 53c94 scsi host adapter
4861: // 2. Onboard 53c90 scsi host adapter
4862: // 3. Plug-in 53c90 scsi host adapter
4863: //
4864:
4865: InitData.AdapterId = 0;
4866: InitData.CardSlot = 7;
4867:
4868: Status1 = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &InitData);
4869:
4870: //
4871: // Look for internal mips adapter.
4872: //
4873:
4874: hwInitializationData.AdapterInterfaceType = Internal;
4875: hwInitializationData.HwFindAdapter = NcrMipsFindAdapter;
4876:
4877: Status2 = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &InitData);
4878:
4879: Status1 = Status2 < Status1 ? Status2 : Status1;
4880:
4881: //
4882: // Look for an Eisa adapter.
4883: //
4884:
4885: InitData.AdapterId = 0;
4886: hwInitializationData.AdapterInterfaceType = Eisa;
4887: hwInitializationData.HwFindAdapter = NcrEisaFindAdapter;
4888:
4889: Status2 = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &InitData);
4890:
4891: return(Status2 < Status1 ? Status2 : Status1);
4892:
4893: } // end PortInitialize()
4894:
4895: ULONG
4896: NcrMcaFindAdapter(
4897: IN PVOID ServiceContext,
4898: IN PVOID Context,
4899: IN PVOID BusInformation,
4900: IN PCHAR ArgumentString,
4901: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
4902: OUT PBOOLEAN Again
4903: )
4904: /*++
4905:
4906: Routine Description:
4907:
4908: This function fills in the configuration information structure. This
4909: routine is temporary until the configuration manager supplies similar
4910: informtion. It also fills in the capabilities structure.
4911:
4912: Arguments:
4913:
4914: ServiceContext - Supplies a pointer to the device extension.
4915:
4916: Context - Unused.
4917:
4918: BusInformation - Unused.
4919:
4920: ArgumentString - Unused.
4921:
4922: ConfigInfo - Pointer to the configuration information structure to be
4923: filled in.
4924:
4925: Again - Returns back a request to call this function again.
4926:
4927: Return Value:
4928:
4929: Returns a status value for the initialazitaition.
4930:
4931: --*/
4932:
4933: {
4934:
4935: PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
4936: PINIT_DATA InitData = Context;
4937: LONG Slot;
4938: LONG i;
4939: ULONG Status = SP_RETURN_NOT_FOUND;
4940:
4941: //
4942: // Determine if bus information array needs to be filled in.
4943: //
4944:
4945: if ( InitData->AdapterId == 0 ) {
4946:
4947: //
4948: // Fill in the POS data structure.
4949: //
4950:
4951: for ( Slot = 0; Slot < 8; Slot++ ) {
4952:
4953: i = ScsiPortGetBusData ( deviceExtension,
4954: Pos,
4955: 0,
4956: Slot,
4957: &InitData->PosData[Slot],
4958: sizeof( POS_DATA )
4959: );
4960:
4961: //
4962: // If less that the requested amount of data is returned, then
4963: // insure that this adapter is ignored.
4964: //
4965:
4966: if ( i < (sizeof( POS_DATA ))) {
4967: InitData->PosData[Slot].AdapterId = 0xffff;
4968: }
4969:
4970: }
4971:
4972: }
4973:
4974: for ( Slot = InitData->CardSlot; Slot >= 0; Slot-- ) {
4975: if (( InitData->PosData[Slot].AdapterId == ONBOARD_C94_ADAPTER_ID ||
4976: InitData->PosData[Slot].AdapterId == ONBOARD_C90_ADAPTER_ID ||
4977: InitData->PosData[Slot].AdapterId == PLUGIN_C90_ADAPTER_ID ) &&
4978: (*(PPOS_DATA_1)&InitData->PosData[Slot].OptionData1).AdapterEnable) {
4979: InitData->CardSlot = Slot - 1;
4980: Status = SP_RETURN_FOUND;
4981: break;
4982: }
4983: }
4984:
4985: if ( Status == SP_RETURN_FOUND ) {
4986:
4987: *Again = TRUE;
4988:
4989: deviceExtension->AdapterBase = (PVOID) AdapterBaseAddress[
4990: (*(PPOS_DATA_1) &InitData->PosData[Slot].OptionData1).IoAddressSelects];
4991: deviceExtension->Adapter = (PSCSI_REGISTERS)
4992: ((PCHAR) deviceExtension->AdapterBase + sizeof(ADAPTER_REGISTERS));
4993: if ( InitData->PosData[Slot].AdapterId == ONBOARD_C94_ADAPTER_ID ) {
4994: deviceExtension->ChipType = Ncr53c94;
4995: deviceExtension->AdapterBusId = AdapterScsiIdC94[
4996: (*(PPOS_DATA_3) &InitData->PosData[Slot].OptionData3).HostIdSelects];
4997: deviceExtension->InterruptPending = FALSE;
4998: } else {
4999: deviceExtension->ChipType = Ncr53c90;
5000: deviceExtension->AdapterBusId = AdapterScsiIdC90[
5001: (*(PPOS_DATA_4) &InitData->PosData[Slot].OptionData4).HostIdSelects];
5002: deviceExtension->InterruptPending = TRUE;
5003: }
5004:
5005: deviceExtension->AdapterBusIdMask = 1 << deviceExtension->AdapterBusId;
5006:
5007: //
5008: // Set configuration information
5009: //
5010:
5011: ConfigInfo->NumberOfPhysicalBreaks = 16;
5012: ConfigInfo->BusInterruptLevel = AdapterInterruptLevel[
5013: (*(PPOS_DATA_1) &InitData->PosData[Slot].OptionData1).InterruptSelects];
5014: ConfigInfo->InitiatorBusId[0] = deviceExtension->AdapterBusId;
5015: ConfigInfo->DmaChannel = AdapterDmaLevel[
5016: (*(PPOS_DATA_2) &InitData->PosData[Slot].OptionData2).DmaSelects];
5017: ConfigInfo->DmaPort = (ULONG) deviceExtension->AdapterBase + (ULONG)
5018: &((PADAPTER_WRITE_REGISTERS) 0)->DmaDecode;
5019: if ( InitData->PosData[Slot].AdapterId == ONBOARD_C94_ADAPTER_ID ) {
5020: ConfigInfo->DmaWidth = Width16Bits;
5021: ConfigInfo->AlignmentMask = 1;
5022: ConfigInfo->AdapterScansDown = TRUE;
5023: ConfigInfo->TaggedQueuing = 1;
5024: } else {
5025: ConfigInfo->DmaWidth = Width8Bits;
5026: }
5027:
5028: ConfigInfo->DmaSpeed = Compatible;
5029: ConfigInfo->MaximumTransferLength = 0xf000;
5030: ConfigInfo->NumberOfBuses = 1;
5031:
5032: //
5033: // Fill in the access array information.
5034: //
5035:
5036: (*ConfigInfo->AccessRanges)[0].RangeStart =
5037: ScsiPortConvertUlongToPhysicalAddress((ULONG) deviceExtension->AdapterBase);
5038: (*ConfigInfo->AccessRanges)[0].RangeLength = sizeof(ADAPTER_REGISTERS) +
5039: sizeof(SCSI_REGISTERS);
5040: (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
5041:
5042: //
5043: // Initialize hardware.
5044: //
5045:
5046: SCSI_WRITE(deviceExtension->Adapter, Command, RESET_SCSI_CHIP);
5047: SCSI_WRITE(deviceExtension->Adapter, Command, NO_OPERATION_DMA);
5048:
5049: deviceExtension->ClockSpeed = 14; // set clock speed at 14 Mhz.
5050: deviceExtension->AdapterFlags |= PD_NCR_ADAPTER;
5051:
5052: ScsiDebugPrint(1, " ScsiId = %x\n", ConfigInfo->InitiatorBusId[0]);
5053: ScsiDebugPrint(1, " IoBase = %2x\n", deviceExtension->Adapter);
5054: ScsiDebugPrint(1, " Irq = %x\n", ConfigInfo->BusInterruptLevel);
5055: ScsiDebugPrint(1, " Dma = %x\n", ConfigInfo->DmaChannel);
5056:
5057: } else {
5058:
5059: *Again = FALSE;
5060:
5061: }
5062:
5063: return(Status);
5064:
5065: }
5066:
5067: ULONG
5068: NcrEisaFindAdapter(
5069: IN PVOID ServiceContext,
5070: IN PVOID Context,
5071: IN PVOID BusInformation,
5072: IN PCHAR ArgumentString,
5073: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5074: OUT PBOOLEAN Again
5075: )
5076: /*++
5077:
5078: Routine Description:
5079:
5080: This function fills in the configuration information structure. This
5081: routine is temporary until the configuration manager supplies similar
5082: informtion. It also fills in the capabilities structure.
5083:
5084: Arguments:
5085:
5086: ServiceContext - Supplies a pointer to the device extension.
5087:
5088: Context - Unused.
5089:
5090: BusInformation - Unused.
5091:
5092: ArgumentString - Unused.
5093:
5094: ConfigInfo - Pointer to the configuration information structure to be
5095: filled in.
5096:
5097: Again - Returns back a request to call this function again.
5098:
5099: Return Value:
5100:
5101: Returns a status value for the initialazitaition.
5102:
5103: --*/
5104:
5105: {
5106:
5107: PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
5108: PCM_EISA_FUNCTION_INFORMATION functionInformation;
5109: PCM_EISA_SLOT_INFORMATION slotInformation;
5110: UCHAR dataByte;
5111: PUCHAR configurationRegister;
5112: ULONG boardId;
5113: ULONG numberOfFunctions;
5114: ULONG slotNumber;
5115:
5116: *Again = FALSE;
5117:
5118: for (slotNumber = 0; slotNumber < 16; slotNumber++) {
5119:
5120: boardId = ScsiPortGetBusData( deviceExtension,
5121: EisaConfiguration,
5122: ConfigInfo->SystemIoBusNumber,
5123: slotNumber,
5124: &slotInformation,
5125: 0);
5126:
5127: if (boardId == 0 || slotInformation == NULL) {
5128: continue;
5129: }
5130:
5131: //
5132: // Calculate the actual number of functions returned.
5133: //
5134:
5135: numberOfFunctions = (boardId - sizeof(CM_EISA_SLOT_INFORMATION)) /
5136: sizeof(CM_EISA_FUNCTION_INFORMATION);
5137:
5138: if (numberOfFunctions > (ULONG) slotInformation->NumberFunctions) {
5139: numberOfFunctions = slotInformation->NumberFunctions;
5140: }
5141:
5142: functionInformation = (PCM_EISA_FUNCTION_INFORMATION) (slotInformation + 1);
5143: for (; 0 < numberOfFunctions; numberOfFunctions--, functionInformation++) {
5144:
5145: if (!(functionInformation->FunctionFlags & EISA_FUNCTION_ENABLED) &&
5146: !strcmp(functionInformation->TypeString, "MSD,CDROM1")) {
5147:
5148: DebugPrint((1, "NcrEisaFindAdapter: Found type string. Function information: %lx\n", functionInformation));
5149: ConfigInfo->DmaWidth = Width8Bits;
5150: ConfigInfo->DmaSpeed = Compatible;
5151: deviceExtension->ChipType = Ncr53c90;
5152: goto found;
5153:
5154: } else if (!(functionInformation->FunctionFlags & EISA_FUNCTION_ENABLED) &&
5155: !strcmp(functionInformation->TypeString, "MSD,SCSI,C94")) {
5156:
5157: DebugPrint((1, "NcrEisaFindAdapter: Found type string. Function information: %lx\n", functionInformation));
5158: ConfigInfo->DmaWidth = Width16Bits;
5159: ConfigInfo->AlignmentMask = 1;
5160: ConfigInfo->DmaSpeed = TypeB;
5161: ConfigInfo->MaximumTransferLength = 0x10000;
5162: deviceExtension->ChipType = Ncr53c94;
5163: goto found;
5164: }
5165: }
5166: }
5167:
5168: //
5169: // Determine if this is the correct Eisa board.
5170: //
5171:
5172: if (slotNumber >= 16) {
5173:
5174: //
5175: // The device was not found.
5176: //
5177:
5178: return(SP_RETURN_NOT_FOUND);
5179: }
5180:
5181: found:
5182:
5183: ConfigInfo->BusInterruptVector = 0;
5184: ConfigInfo->NumberOfBuses = 1;
5185:
5186: //
5187: // Get the SCSI bus Id from the configuration information if there
5188: // is any.
5189: //
5190:
5191: if (ConfigInfo->InitiatorBusId[0] == (CCHAR) SP_UNINITIALIZED_VALUE) {
5192: deviceExtension->AdapterBusId = INITIATOR_BUS_ID;
5193: deviceExtension->AdapterBusIdMask = 1 << INITIATOR_BUS_ID;
5194: ConfigInfo->InitiatorBusId[0] = INITIATOR_BUS_ID;
5195: } else {
5196: deviceExtension->AdapterBusId = ConfigInfo->InitiatorBusId[0];
5197: deviceExtension->AdapterBusIdMask = 1 << ConfigInfo->InitiatorBusId[0];
5198: }
5199:
5200: configurationRegister = ScsiPortGetDeviceBase(
5201: deviceExtension, // HwDeviceExtension
5202: ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
5203: ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
5204: ScsiPortConvertUlongToPhysicalAddress(functionInformation->EisaPort->PortAddress),
5205: functionInformation->EisaPort->Configuration.NumberPorts, // NumberOfBytes
5206: TRUE // InIoSpace
5207: );
5208:
5209: if (configurationRegister == (PUCHAR) SP_UNINITIALIZED_VALUE) {
5210: return(SP_RETURN_ERROR);
5211: }
5212:
5213: deviceExtension->ClockSpeed = 25; // Assume a 25 Mhz clock speed.
5214: deviceExtension->Adapter = (PSCSI_REGISTERS) configurationRegister;
5215:
5216: //
5217: // The Emulex chip loads the TransferCountPage register with the chip id,
5218: // if the EnablePhaseLatch is set and a NOP DMA command has been loaded.
5219: //
5220:
5221: if (deviceExtension->ChipType == Ncr53c94) {
5222:
5223: //
5224: // Now write to the command register with a reset.
5225: //
5226:
5227: SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
5228:
5229: //
5230: // A NOP command is required by the FAS218 to
5231: // load the TransferCountPage register with the chip Id.
5232: //
5233:
5234: SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
5235:
5236: dataByte = SCSI_READ( deviceExtension->Adapter, TransferCountPage);
5237:
5238: if (((PNCR_PART_CODE) &dataByte)->ChipFamily == EMULEX_FAS_216) {
5239:
5240: deviceExtension->ChipType = Fas216;
5241: } else if (((PNCR_PART_CODE) &dataByte)->ChipFamily == NCR_53c96) {
5242:
5243: NcrPrint((1, "NcrFindAdapter: NCR 53c96 chip detected.\n"));
5244: deviceExtension->ChipType = Fas216;
5245: }
5246: }
5247:
5248: //
5249: // Set the parameters according to the chip type.
5250: //
5251:
5252: switch (deviceExtension->ChipType) {
5253: case Ncr53c94:
5254:
5255: NcrPrint((1, "NcrFindAdapter: Ncr 53C94 chip detected.\n"));
5256: ConfigInfo->TaggedQueuing = 1;
5257: ConfigInfo->MaximumTransferLength = 0x10000;
5258: break;
5259:
5260: case Fas216:
5261: NcrPrint((1, "NcrFindAdapter: Emulex FAS 216 chip detected.\n"));
5262: deviceExtension->ClockSpeed = EMULEX_SCSI_CLOCK_SPEED;
5263: ConfigInfo->TaggedQueuing = 1;
5264: ConfigInfo->MaximumTransferLength = 0x1000000-0x1000;
5265: deviceExtension->Configuration3.CheckIdMessage = 1;
5266: break;
5267:
5268: case Ncr53c90:
5269:
5270: NcrPrint((1, "NcrFindAdapter: Ncr 53C90 chip detected.\n"));
5271: ConfigInfo->MaximumTransferLength = 0x10000 - 0x1000;
5272: break;
5273:
5274: default:
5275: *Again = FALSE;
5276: return(SP_RETURN_BAD_CONFIG);
5277: }
5278:
5279: //
5280: // If the clock speed is greater than 25 Mhz then set the fast clock
5281: // bit in configuration register.
5282: //
5283:
5284: if (deviceExtension->ClockSpeed > 25) {
5285: deviceExtension->Configuration3.FastClock = 1;
5286: }
5287:
5288: ConfigInfo->DmaChannel =
5289: functionInformation->EisaDma->ConfigurationByte0.Channel;
5290: ConfigInfo->BusInterruptLevel =
5291: functionInformation->EisaIrq->ConfigurationByte.Interrupt;
5292: ConfigInfo->InterruptMode =
5293: functionInformation->EisaIrq->ConfigurationByte.LevelTriggered ?
5294: LevelSensitive : Latched;
5295:
5296: //
5297: // Fill in the access array information.
5298: //
5299:
5300: (*ConfigInfo->AccessRanges)[0].RangeStart =
5301: ScsiPortConvertUlongToPhysicalAddress(
5302: functionInformation->EisaPort->PortAddress);
5303: (*ConfigInfo->AccessRanges)[0].RangeLength =
5304: functionInformation->EisaPort->Configuration.NumberPorts;
5305: (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
5306:
5307: //
5308: // Make sure the interrupt and DMA channel are properly configured.
5309: //
5310:
5311: if (ConfigInfo->DmaChannel == (UCHAR) ~0 ||
5312: ConfigInfo->BusInterruptLevel == (UCHAR) ~0) {
5313:
5314: return(SP_RETURN_BAD_CONFIG);
5315: }
5316:
5317: //
5318: // Test for the interrupt bit in the status register. Some chips do not
5319: // implement this bit; however, this driver assumes that it exists.
5320: // The itnerrupt bit is tested for by reseting the chip, giving an
5321: // illegal command, and checking for an gross error interrupt.
5322: //
5323:
5324: SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
5325: SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
5326:
5327: SCSI_WRITE( deviceExtension->Adapter, Command, COMMAND_COMPLETE );
5328:
5329: *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ(
5330: deviceExtension->Adapter,
5331: ScsiStatus
5332: );
5333:
5334: dataByte = SCSI_READ( deviceExtension->Adapter, ScsiInterrupt );
5335:
5336: //
5337: // Test for the interrupt.
5338: //
5339:
5340: if (!deviceExtension->AdapterStatus.Interrupt) {
5341:
5342: NcrPrint((0, "\nNcrEisaFindAdapter: Ncr53c90 chip without status register interrupt detected.\n"));
5343: NcrPrint((0, "NcrInterrupt: Adapter Status: %2x; Adapter Interrupt: %2x\n",
5344: *((PUCHAR) &deviceExtension->AdapterStatus),
5345: dataByte
5346: ));
5347:
5348: ScsiPortFreeDeviceBase(deviceExtension, deviceExtension->Adapter);
5349: return(SP_RETURN_BAD_CONFIG);
5350: }
5351:
5352: //
5353: // Now write to the command register with a reset and a DMA nop.
5354: //
5355:
5356: SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
5357: SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
5358:
5359: return(SP_RETURN_FOUND);
5360:
5361: }
5362:
5363: ULONG
5364: NcrMipsFindAdapter(
5365: IN PVOID ServiceContext,
5366: IN PVOID Context,
5367: IN PVOID BusInformation,
5368: IN PCHAR ArgumentString,
5369: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
5370: OUT PBOOLEAN Again
5371: )
5372: /*++
5373:
5374: Routine Description:
5375:
5376: This function fills in the configuration information structure and mapes
5377: the SCSI protocol chip for access. This routine is temporary until
5378: the configuration manager supplies similar informtion.
5379:
5380: Arguments:
5381:
5382: ServiceContext - Supplies a pointer to the device extension.
5383:
5384: Context - Unused.
5385:
5386: BusInformation - Unused.
5387:
5388: ArgumentString - Unused.
5389:
5390: ConfigInfo - Pointer to the configuration information structure to be
5391: filled in.
5392:
5393: Again - Returns back a request to call this function again.
5394:
5395: Return Value:
5396:
5397: Returns a status value for the initialazitaition.
5398:
5399: --*/
5400:
5401: {
5402: PSPECIFIC_DEVICE_EXTENSION deviceExtension = ServiceContext;
5403: UCHAR dataByte;
5404: UCHAR commandSave;
5405:
5406: if (ConfigInfo->DmaChannel == SP_UNINITIALIZED_VALUE
5407: || ConfigInfo->BusInterruptLevel == 0 ||
5408: (*ConfigInfo->AccessRanges)[0].RangeLength == 0) {
5409: return(SP_RETURN_NOT_FOUND);
5410: }
5411:
5412: ConfigInfo->NumberOfBuses = 1;
5413:
5414: //
5415: // Get the SCSI bus Id from the configuration information if there
5416: // is any.
5417: //
5418:
5419: if (ConfigInfo->InitiatorBusId[0] == (CCHAR) SP_UNINITIALIZED_VALUE) {
5420: deviceExtension->AdapterBusId = INITIATOR_BUS_ID;
5421: deviceExtension->AdapterBusIdMask = 1 << INITIATOR_BUS_ID;
5422: ConfigInfo->InitiatorBusId[0] = INITIATOR_BUS_ID;
5423: } else {
5424: deviceExtension->AdapterBusId = ConfigInfo->InitiatorBusId[0];
5425: deviceExtension->AdapterBusIdMask = 1 << ConfigInfo->InitiatorBusId[0];
5426: }
5427:
5428: //
5429: // Map the SCSI protocol chip into the virtual address space.
5430: //
5431:
5432: deviceExtension->Adapter = ScsiPortGetDeviceBase(
5433: deviceExtension, // HwDeviceExtension
5434: ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
5435: ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
5436: (*ConfigInfo->AccessRanges)[0].RangeStart,
5437: (*ConfigInfo->AccessRanges)[0].RangeLength, // NumberOfBytes
5438: FALSE // InIoSpace
5439: );
5440:
5441: if (deviceExtension->Adapter == NULL) {
5442: NcrPrint((0, "\nScsiPortInitialize: Failed to map SCSI device registers into system space.\n"));
5443: return(SP_RETURN_ERROR);
5444: }
5445:
5446: //
5447: // Check the iterrupt register. If it is not equal zero then read it
5448: // agian it should now be zero.
5449: //
5450:
5451: dataByte = SCSI_READ( deviceExtension->Adapter, ScsiInterrupt );
5452:
5453: if (dataByte != 0) {
5454:
5455: ScsiPortStallExecution(INTERRUPT_STALL_TIME);
5456: dataByte = SCSI_READ( deviceExtension->Adapter, ScsiInterrupt );
5457:
5458: if (dataByte != 0 ) {
5459: NcrPrint((1, "NcrMipsFindAdapter: No Ncr53c9x chip found! Interrupt will not clear.\n"));
5460: ScsiPortFreeDeviceBase(deviceExtension, deviceExtension->Adapter);
5461: return(SP_RETURN_NOT_FOUND);
5462: }
5463: }
5464:
5465: //
5466: // Test for the interrupt bit in the status register. Some chips do not
5467: // implement this bit; however, this driver assumes that it exists.
5468: // The itnerrupt bit is tested for by reseting the chip, giving an
5469: // illegal command, and checking for an gross error interrupt.
5470: //
5471:
5472: commandSave = SCSI_READ(deviceExtension->Adapter, Command);
5473:
5474: SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
5475: ScsiPortStallExecution(1);
5476: SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
5477: ScsiPortStallExecution(1);
5478:
5479: SCSI_WRITE( deviceExtension->Adapter, Command, COMMAND_COMPLETE );
5480: ScsiPortStallExecution(1);
5481:
5482: *((PUCHAR) &deviceExtension->AdapterStatus) = SCSI_READ(
5483: deviceExtension->Adapter,
5484: ScsiStatus
5485: );
5486:
5487: dataByte = SCSI_READ( deviceExtension->Adapter, ScsiInterrupt );
5488:
5489: //
5490: // Test for the interrupt.
5491: //
5492:
5493: if (!deviceExtension->AdapterStatus.Interrupt) {
5494:
5495: NcrPrint((0, "\nNcrMipsFindAdapter: Ncr53c90 chip without status register interrupt detected.\n"));
5496: NcrPrint((0, "NcrMipsFindAdapter: Adapter Status: %2x; Adapter Interrupt: %2x\n",
5497: *((PUCHAR) &deviceExtension->AdapterStatus),
5498: dataByte
5499: ));
5500:
5501: //
5502: // Restore the command register.
5503: //
5504:
5505: SCSI_WRITE( deviceExtension->Adapter, Command, commandSave );
5506:
5507: ScsiPortFreeDeviceBase(deviceExtension, deviceExtension->Adapter);
5508: return(SP_RETURN_NOT_FOUND);
5509: }
5510:
5511: //
5512: // Initialize the NCR SCSI Chip.
5513: //
5514:
5515: SCSI_WRITE( deviceExtension->Adapter, Command, RESET_SCSI_CHIP );
5516:
5517: //
5518: // A NOP command is required to clear the chip reset command.
5519: //
5520:
5521: SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
5522:
5523: //
5524: // Determine the chip type.
5525: //
5526:
5527: //
5528: // The Ncr53c90 is detected by the absense of configuration register 3.
5529: // On the other to chips this register is zero after a reset and is read
5530: // writable.
5531: //
5532:
5533: dataByte = SCSI_READ( deviceExtension->Adapter, Configuration2);
5534:
5535: if (dataByte != 0) {
5536:
5537: deviceExtension->ChipType = Ncr53c90;
5538:
5539: } else {
5540:
5541: //
5542: // Set the Scsi2 and EnablePhaseLatch of the configuration regisiter.
5543: //
5544:
5545: ((PSCSI_CONFIGURATION2)(&dataByte))->Scsi2 = 1;
5546: ((PSCSI_CONFIGURATION2)(&dataByte))->EnablePhaseLatch = 1;
5547:
5548: SCSI_WRITE( deviceExtension->Adapter, Configuration2, dataByte);
5549:
5550: //
5551: // Read the register back if the value is not the same as was written,
5552: // then this an Ncr53c90.
5553: //
5554:
5555: if (dataByte != SCSI_READ( deviceExtension->Adapter, Configuration2)) {
5556:
5557: deviceExtension->ChipType = Ncr53c90;
5558:
5559: } else {
5560:
5561: deviceExtension->ChipType = Ncr53c94;
5562:
5563: }
5564: }
5565:
5566: //
5567: // The Emulex chip loads the TransferCountPage register with the chip id,
5568: // if the EnablePhaseLatch is set and a NOP DMA command has been loaded.
5569: //
5570:
5571: if (deviceExtension->ChipType == Ncr53c94) {
5572:
5573: //
5574: // A NOP command is required by the FAS218 to
5575: // load the TransferCountPage register with the chip Id.
5576: //
5577:
5578: SCSI_WRITE( deviceExtension->Adapter, Command, NO_OPERATION_DMA );
5579:
5580: dataByte = SCSI_READ( deviceExtension->Adapter, TransferCountPage);
5581:
5582: if (((PNCR_PART_CODE) &dataByte)->ChipFamily == EMULEX_FAS_216) {
5583:
5584: deviceExtension->ChipType = Fas216;
5585:
5586: } else if (((PNCR_PART_CODE) &dataByte)->ChipFamily == NCR_53c96) {
5587:
5588: NcrPrint((1, "NcrFindAdapter: NCR 53c96 chip detected.\n"));
5589: deviceExtension->ChipType = Fas216;
5590: }
5591: }
5592:
5593: //
5594: // Set the parameters according to the chip type.
5595: //
5596:
5597: switch (deviceExtension->ChipType) {
5598: case Ncr53c94:
5599:
5600: NcrPrint((1, "NcrFindAdapter: Ncr 53C94 chip detected.\n"));
5601: deviceExtension->ClockSpeed = NCR_SCSI_CLOCK_SPEED;
5602: ConfigInfo->TaggedQueuing = 1;
5603: ConfigInfo->MaximumTransferLength = 0x10000;
5604: break;
5605:
5606: case Fas216:
5607: NcrPrint((1, "NcrFindAdapter: Emulex FAS 216 chip detected.\n"));
5608: deviceExtension->ClockSpeed = EMULEX_SCSI_CLOCK_SPEED;
5609: ConfigInfo->TaggedQueuing = 1;
5610: ConfigInfo->MaximumTransferLength = 0x1000000-0x1000;
5611: deviceExtension->Configuration3.CheckIdMessage = 1;
5612: break;
5613:
5614: case Ncr53c90:
5615:
5616: NcrPrint((1, "NcrFindAdapter: Ncr 53C90 chip detected.\n"));
5617:
5618: default:
5619: *Again = FALSE;
5620: return(SP_RETURN_BAD_CONFIG);
5621: }
5622:
5623: //
5624: // If the clock speed is greater than 25 Mhz then set the fast clock
5625: // bit in configuration register.
5626: //
5627:
5628: if (deviceExtension->ClockSpeed > 25) {
5629: deviceExtension->Configuration3.FastClock = 1;
5630: }
5631:
5632: *Again = FALSE;
5633: return(SP_RETURN_FOUND);
5634:
5635: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.