|
|
1.1 root 1: /*++
2:
3: Copyright (c) 1990 Microsoft Corporation
4:
5: Module Name:
6:
7: aha154x.c
8:
9: Abstract:
10:
11: This is the port driver for the Adaptec 1540B SCSI Adapter.
12:
13: Author:
14:
15: Mike Glass
16: Tuong Hoang (Adaptec)
17:
18: Environment:
19:
20: kernel mode only
21:
22: Notes:
23:
24: Revision History:
25:
26: --*/
27:
28: #include "miniport.h"
29: #include "aha154x.h" // includes scsi.h
30:
31: //
32: // This conditionally compiles in the code to force the DMA transfer speed
33: // to 5.0.
34: //
35:
36: #define FORCE_DMA_SPEED 1
37:
38: //
39: // The following structure is allocated
40: // from noncached memory as data will be DMA'd to
41: // and from it.
42: //
43:
44: typedef struct _NONCACHED_EXTENSION {
45:
46: //
47: // Physical base address of mailboxes
48: //
49:
50: ULONG MailboxPA;
51:
52: //
53: // Mailboxes
54: //
55:
56: MBO Mbo[MB_COUNT];
57: MBI Mbi[MB_COUNT];
58:
59: } NONCACHED_EXTENSION, *PNONCACHED_EXTENSION;
60:
61: //
62: // Device extension
63: //
64:
65: typedef struct _HW_DEVICE_EXTENSION {
66:
67: //
68: // NonCached extension
69: //
70:
71: PNONCACHED_EXTENSION NoncachedExtension;
72:
73: //
74: // Adapter parameters
75: //
76:
77: PBASE_REGISTER BaseIoAddress;
78:
79: //
80: // Host Target id.
81: //
82:
83: UCHAR HostTargetId;
84:
85: //
86: // Old in\out box indexes.
87: //
88:
89: UCHAR MboIndex;
90:
91: UCHAR MbiIndex;
92:
93: //
94: // Pending request.
95: //
96:
97: BOOLEAN PendingRequest;
98:
99: //
100: // Bus on time to use.
101: //
102:
103: UCHAR BusOnTime;
104:
105: } HW_DEVICE_EXTENSION, *PHW_DEVICE_EXTENSION;
106:
107: //
108: // Logical unit extension
109: //
110:
111: typedef struct _HW_LU_EXTENSION {
112: PSCSI_REQUEST_BLOCK CurrentSrb;
113: } HW_LU_EXTENSION, *PHW_LU_EXTENSION;
114:
115:
116: //
117: // Function declarations
118: //
119: // Functions that start with 'A154x' are entry points
120: // for the OS port driver.
121: //
122:
123: ULONG
124: DriverEntry(
125: IN PVOID DriverObject,
126: IN PVOID Argument2
127: );
128:
129: ULONG
130: A154xDetermineInstalled(
131: IN PHW_DEVICE_EXTENSION HwDeviceExtension,
132: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
133: IN OUT PULONG AdapterCount,
134: OUT PBOOLEAN Again
135: );
136:
137: ULONG
138: A154xFindAdapter(
139: IN PVOID HwDeviceExtension,
140: IN PVOID Context,
141: IN PVOID BusInformation,
142: IN PCHAR ArgumentString,
143: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
144: OUT PBOOLEAN Again
145: );
146:
147: BOOLEAN
148: A154xHwInitialize(
149: IN PVOID DeviceExtension
150: );
151:
152: BOOLEAN
153: A154xStartIo(
154: IN PVOID DeviceExtension,
155: IN PSCSI_REQUEST_BLOCK Srb
156: );
157:
158: BOOLEAN
159: A154xInterrupt(
160: IN PVOID DeviceExtension
161: );
162:
163: BOOLEAN
164: A154xResetBus(
165: IN PVOID HwDeviceExtension,
166: IN ULONG PathId
167: );
168:
169: VOID
170: GetHostAdapterBoardId (
171: IN PVOID HwDeviceExtension,
172: OUT PUCHAR BoardId
173: );
174:
175: //
176: // This function is called from A154xStartIo.
177: //
178:
179: VOID
180: BuildCcb(
181: IN PHW_DEVICE_EXTENSION DeviceExtension,
182: IN PSCSI_REQUEST_BLOCK Srb
183: );
184:
185: //
186: // This function is called from BuildCcb.
187: //
188:
189: VOID
190: BuildSdl(
191: IN PHW_DEVICE_EXTENSION DeviceExtension,
192: IN PSCSI_REQUEST_BLOCK Srb
193: );
194:
195: //
196: // This function is called from A154xInitialize.
197: //
198:
199: BOOLEAN
200: AdapterPresent(
201: IN PVOID HwDeviceExtension
202: );
203:
204: //
205: // This function is called from A154xInterrupt.
206: //
207:
208: UCHAR
209: MapError(
210: IN PVOID HwDeviceExtension,
211: IN PSCSI_REQUEST_BLOCK Srb,
212: IN PCCB Ccb
213: );
214:
215: BOOLEAN
216: ReadCommandRegister(
217: IN PHW_DEVICE_EXTENSION DeviceExtension,
218: OUT PUCHAR DataByte,
219: IN BOOLEAN TimeOutFlag
220: );
221:
222: BOOLEAN
223: WriteCommandRegister(
224: IN PHW_DEVICE_EXTENSION DeviceExtension,
225: IN UCHAR AdapterCommand,
226: IN BOOLEAN LogError
227: );
228:
229: BOOLEAN
230: WriteDataRegister(
231: IN PHW_DEVICE_EXTENSION DeviceExtension,
232: IN UCHAR DataByte
233: );
234:
235: BOOLEAN
236: ScatterGatherSupported (
237: IN PHW_DEVICE_EXTENSION HwDeviceExtension
238: );
239:
240: BOOLEAN
241: FinishHBACmd(
242: IN PHW_DEVICE_EXTENSION HwDeviceExtension
243: );
244:
245: BOOLEAN
246: SpinForInterrupt(
247: IN PHW_DEVICE_EXTENSION DeviceExtension,
248: IN BOOLEAN TimeOutFlag
249: );
250:
251: BOOLEAN SendUnlockCommand(
252: IN PVOID HwDeviceExtension,
253: IN UCHAR locktype
254: );
255:
256: BOOLEAN UnlockMailBoxes(
257: IN PVOID HwDeviceExtension
258: );
259:
260: ULONG
261: AhaParseArgumentString(
262: IN PCHAR String,
263: IN PCHAR KeyWord
264: );
265:
266: ULONG
267: DriverEntry(
268: IN PVOID DriverObject,
269: IN PVOID Argument2
270: )
271:
272: /*++
273:
274: Routine Description:
275:
276: Installable driver initialization entry point for system.
277:
278: Arguments:
279:
280: Driver Object
281:
282: Return Value:
283:
284: Status from ScsiPortInitialize()
285:
286: --*/
287:
288: {
289: HW_INITIALIZATION_DATA hwInitializationData;
290: ULONG adapterCount;
291: ULONG isaStatus;
292: ULONG mcaStatus;
293: ULONG i;
294:
295: DebugPrint((1,"\n\nSCSI Adaptec 154X MiniPort Driver\n"));
296:
297: //
298: // Zero out structure.
299: //
300:
301: for (i=0; i<sizeof(HW_INITIALIZATION_DATA); i++) {
302: ((PUCHAR)&hwInitializationData)[i] = 0;
303: }
304:
305: //
306: // Set size of hwInitializationData.
307: //
308:
309: hwInitializationData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA);
310:
311: //
312: // Set entry points.
313: //
314:
315: hwInitializationData.HwInitialize = A154xHwInitialize;
316: hwInitializationData.HwResetBus = A154xResetBus;
317: hwInitializationData.HwStartIo = A154xStartIo;
318: hwInitializationData.HwInterrupt = A154xInterrupt;
319: hwInitializationData.HwFindAdapter = A154xFindAdapter;
320:
321: //
322: // Indicate no buffer mapping but will need physical addresses.
323: //
324:
325: hwInitializationData.NeedPhysicalAddresses = TRUE;
326:
327: //
328: // Specify size of extensions.
329: //
330:
331: hwInitializationData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION);
332: hwInitializationData.SpecificLuExtensionSize = sizeof(HW_LU_EXTENSION);
333:
334: //
335: // Specifiy the bus type.
336: //
337:
338: hwInitializationData.AdapterInterfaceType = Isa;
339: hwInitializationData.NumberOfAccessRanges = 1;
340:
341: //
342: // Ask for SRB extensions for CCBs.
343: //
344:
345: hwInitializationData.SrbExtensionSize = sizeof(CCB);
346:
347: //
348: // The adapter count is used by the find adapter routine to track how
349: // which adapter addresses have been tested.
350: //
351:
352: adapterCount = 0;
353:
354: isaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &adapterCount);
355:
356: //
357: // Now try to configure for the Mca bus.
358: // Specifiy the bus type.
359: //
360:
361: hwInitializationData.AdapterInterfaceType = MicroChannel;
362: adapterCount = 0;
363: mcaStatus = ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, &adapterCount);
364:
365: //
366: // Return the smaller status.
367: //
368:
369: return(mcaStatus < isaStatus ? mcaStatus : isaStatus);
370:
371: } // end A154xEntry()
372:
373:
374: ULONG
375: A154xFindAdapter(
376: IN PVOID HwDeviceExtension,
377: IN PVOID Context,
378: IN PVOID BusInformation,
379: IN PCHAR ArgumentString,
380: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
381: OUT PBOOLEAN Again
382: )
383: /*++
384:
385: Routine Description:
386:
387: This function is called by the OS-specific port driver after
388: the necessary storage has been allocated, to gather information
389: about the adapter's configuration.
390:
391: Arguments:
392:
393: HwDeviceExtension - HBA miniport driver's adapter data storage
394: Context - Register base address
395: ConfigInfo - Configuration information structure describing HBA
396: This structure is defined in PORT.H.
397:
398: Return Value:
399:
400: ULONG
401:
402: --*/
403:
404: {
405: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
406: ULONG length;
407: ULONG status;
408: UCHAR adapterTid;
409: UCHAR dmaChannel;
410: UCHAR irq;
411: UCHAR bit;
412:
413: //
414: // Determine if there are any adapters installed. Determine installed
415: // will initialize the BaseIoAddress if an adapter is found.
416: //
417:
418: status = A154xDetermineInstalled(deviceExtension,
419: ConfigInfo,
420: Context,
421: Again);
422:
423: //
424: // If there are not adapter's found then return.
425: //
426:
427: if (status != SP_RETURN_FOUND) {
428: return(status);
429: }
430:
431: //
432: // Issue adapter command to get IRQ.
433: //
434: // Returns 3 data bytes:
435: //
436: // Byte 0 Dma Channel
437: //
438: // Byte 1 Interrupt Channel
439: //
440: // Byte 2 Adapter SCSI ID
441: //
442:
443: if (!WriteCommandRegister(deviceExtension, AC_RET_CONFIGURATION_DATA, TRUE)) {
444: DebugPrint((1,"A154xFindAdapter: Get configuration data command failed\n"));
445: return SP_RETURN_ERROR;
446: }
447:
448: //
449: // Determine DMA channel.
450: //
451:
452: if (!ReadCommandRegister(deviceExtension,&dmaChannel,TRUE)) {
453: DebugPrint((1,"A154xFindAdapter: Couldn't read dma channel\n"));
454: return SP_RETURN_ERROR;
455: }
456:
457: if (ConfigInfo->AdapterInterfaceType != MicroChannel) {
458:
459: WHICH_BIT(dmaChannel,bit);
460:
461: ConfigInfo->DmaChannel = bit;
462:
463: DebugPrint((2,"A154xFindAdapter: DMA channel is %x\n",
464: ConfigInfo->DmaChannel));
465:
466: } else {
467: ConfigInfo->InterruptMode = LevelSensitive;
468: }
469:
470: //
471: // Determine hardware interrupt vector.
472: //
473:
474: if (!ReadCommandRegister(deviceExtension,&irq,TRUE)) {
475: DebugPrint((1,"A154xFindAdapter: Couldn't read adapter irq\n"));
476: return SP_RETURN_ERROR;
477: }
478:
479: WHICH_BIT(irq, bit);
480:
481: ConfigInfo->BusInterruptLevel = (UCHAR) 9 + bit;
482:
483: //
484: // Determine what SCSI bus id the adapter is on.
485: //
486:
487: if (!ReadCommandRegister(deviceExtension,&adapterTid,TRUE)) {
488: DebugPrint((1,"A154xFindAdapter: Couldn't read adapter SCSI id\n"));
489: return SP_RETURN_ERROR;
490: }
491:
492: //
493: // Set number of buses.
494: //
495:
496: ConfigInfo->NumberOfBuses = 1;
497: ConfigInfo->InitiatorBusId[0] = adapterTid;
498: deviceExtension->HostTargetId = adapterTid;
499:
500: ConfigInfo->MaximumTransferLength = MAX_TRANSFER_SIZE;
501: ConfigInfo->NumberOfPhysicalBreaks = MAX_SG_DESCRIPTORS - 1;
502: ConfigInfo->ScatterGather = ScatterGatherSupported(HwDeviceExtension);
503:
504: if (!ConfigInfo->ScatterGather) {
505: //ConfigInfo->NumberOfPhysicalBreaks = 1;
506: DebugPrint((1,"Aha154x: Scatter/Gather not supported!"));
507: }
508:
509: ConfigInfo->Master = TRUE;
510:
511: //
512: // Allocate a Noncached Extension to use for mail boxes.
513: //
514:
515: deviceExtension->NoncachedExtension = ScsiPortGetUncachedExtension(
516: deviceExtension,
517: ConfigInfo,
518: sizeof(NONCACHED_EXTENSION));
519:
520: if (deviceExtension->NoncachedExtension == NULL) {
521:
522: //
523: // Log error.
524: //
525:
526: ScsiPortLogError(
527: deviceExtension,
528: NULL,
529: 0,
530: 0,
531: 0,
532: SP_INTERNAL_ADAPTER_ERROR,
533: 7 << 8
534: );
535:
536: return(SP_RETURN_ERROR);
537: }
538:
539: //
540: // Convert virtual to physical mailbox address.
541: //
542:
543: deviceExtension->NoncachedExtension->MailboxPA =
544: ScsiPortConvertPhysicalAddressToUlong(
545: ScsiPortGetPhysicalAddress(deviceExtension,
546: NULL,
547: deviceExtension->NoncachedExtension->Mbo,
548: &length));
549:
550: //
551: // Set default bus on time. Then check for an override parameter.
552: //
553:
554: deviceExtension->BusOnTime = 0x07;
555: if (ArgumentString != NULL) {
556:
557: length = AhaParseArgumentString(ArgumentString, "BUSONTIME");
558:
559: //
560: // Validate that the new bus on time is reasonable before attempting
561: // to set it.
562: //
563:
564: if (length >= 2 && length <= 15) {
565:
566: deviceExtension->BusOnTime = (UCHAR) length;
567: DebugPrint((1,"A154xFindAdapter: Setting bus on time: %ld\n", length));
568: }
569: }
570:
571: DebugPrint((3,"A154xFindAdapter: Configuration completed\n"));
572: return SP_RETURN_FOUND;
573: } // end A154xFindAdapter()
574:
575:
576: BOOLEAN
577: AdaptecAdapter(
578: IN PHW_DEVICE_EXTENSION HwDeviceExtension,
579: IN ULONG IoPort,
580: IN BOOLEAN Mca
581: )
582:
583: /*++
584:
585: Routine Description:
586:
587: This routine checks the Special Options byte of the Adapter Inquiry
588: command to see if it is one of the two values returned by Adaptec
589: Adapters. This avoids claiming adapters from BusLogic and DTC.
590:
591: Arguments:
592:
593: HwDeviceExtension - miniport driver's adapter extension.
594:
595: Return Values:
596:
597: TRUE if the adapter looks like an Adaptec.
598: FALSE if not.
599:
600: --*/
601:
602: {
603: ULONG i;
604: UCHAR byte;
605: UCHAR specialOptions;
606: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
607: PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
608:
609: if (Mca == TRUE) {
610: INIT_DATA initData;
611: LONG slot;
612: LONG i;
613:
614: for (slot = 0; slot < NUMBER_POS_SLOTS; slot++) {
615: i = ScsiPortGetBusData(HwDeviceExtension,
616: Pos,
617: 0,
618: slot,
619: &initData.PosData[slot],
620: sizeof(POS_DATA));
621: if (i < (sizeof(POS_DATA))) {
622: initData.PosData[slot].AdapterId = 0xffff;
623: }
624: }
625:
626: for (slot = 0; slot < NUMBER_POS_SLOTS; slot++) {
627: if (initData.PosData[slot].AdapterId == POS_IDENTIFIER) {
628: switch (initData.PosData[slot].IoPortInformation & POS_PORT_MASK) {
629: case POS_PORT_130:
630: if (IoPort == 0x0130) {
631: return TRUE;
632: }
633: break;
634: case POS_PORT_134:
635: if (IoPort == 0x0134) {
636: return TRUE;
637: }
638: break;
639: case POS_PORT_230:
640: if (IoPort == 0x0230) {
641: return TRUE;
642: }
643: break;
644: case POS_PORT_234:
645: if (IoPort == 0x234) {
646: return TRUE;
647: }
648: break;
649: case POS_PORT_330:
650: if (IoPort == 0x330) {
651: return TRUE;
652: }
653: break;
654: case POS_PORT_334:
655: if (IoPort == 0x334) {
656: return TRUE;
657: }
658: break;
659: }
660: }
661: }
662: return FALSE;
663: }
664:
665: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
666: IOP_INTERRUPT_RESET);
667:
668: if (!WriteCommandRegister(HwDeviceExtension,AC_ADAPTER_INQUIRY,FALSE)) {
669: return FALSE;
670: }
671:
672: //
673: // Byte 0.
674: //
675:
676: if ((ReadCommandRegister(HwDeviceExtension,&byte,TRUE)) == FALSE) {
677: return FALSE;
678: }
679:
680: //
681: // Get the special options byte.
682: //
683:
684: if ((ReadCommandRegister(HwDeviceExtension,&specialOptions,TRUE)) == FALSE) {
685: return FALSE;
686: }
687:
688: //
689: // Get the last two bytes and clear the interrupt.
690: //
691:
692: if ((ReadCommandRegister(HwDeviceExtension,&byte,TRUE)) == FALSE) {
693: return FALSE;
694: }
695:
696: if ((ReadCommandRegister(HwDeviceExtension,&byte,TRUE)) == FALSE) {
697: return FALSE;
698: }
699:
700: //
701: // Interrupt handler is not yet installed so wait for HACC by hand.
702: //
703:
704: for (i = 0; i<5000; i++) {
705: if (ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister) ==
706: (IOP_ANY_INTERRUPT | IOP_COMMAND_COMPLETE) ) {
707: break;
708: }
709: ScsiPortStallExecution(1);
710: }
711:
712: if ((specialOptions == 0x30) || (specialOptions == 0x42)) {
713: return TRUE;
714: }
715:
716: return FALSE;
717: }
718:
719: ULONG
720: A154xDetermineInstalled(
721: IN PHW_DEVICE_EXTENSION HwDeviceExtension,
722: IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
723: IN OUT PULONG AdapterCount,
724: OUT PBOOLEAN Again
725: )
726:
727: /*++
728:
729: Routine Description:
730:
731: Determine if Adaptec 154X SCSI adapter is installed in system
732: by reading the status register as each base I/O address
733: and looking for a pattern. If an adapter is found, the BaseIoAddres is
734: initialized.
735:
736: Arguments:
737:
738: HwDeviceExtension - HBA miniport driver's adapter data storage
739:
740: ConfigInfo - Supplies the known configuraiton information.
741:
742: AdapterCount - Supplies the count of adapter slots which have been tested.
743:
744: Again - Returns whehter the OS specific driver should call again.
745:
746: Return Value:
747:
748: Returns a status indicating whether a driver is present or not.
749:
750: --*/
751:
752: {
753: PBASE_REGISTER baseIoAddress;
754: PUCHAR ioSpace;
755: UCHAR portValue;
756:
757: //
758: // The following table specifies the ports to be checked when searching for
759: // an adapter. A zero entry terminates the search.
760: //
761:
762: CONST ULONG AdapterAddresses[7] = {0X330, 0X334, 0X234, 0X134, 0X130, 0X230, 0};
763:
764:
765: //
766: // Get the system physical address for this card. The card uses I/O space.
767: //
768:
769: ioSpace = ScsiPortGetDeviceBase(
770: HwDeviceExtension, // HwDeviceExtension
771: ConfigInfo->AdapterInterfaceType, // AdapterInterfaceType
772: ConfigInfo->SystemIoBusNumber, // SystemIoBusNumber
773: ScsiPortConvertUlongToPhysicalAddress(0),
774: 0x400, // NumberOfBytes
775: TRUE // InIoSpace
776: );
777:
778: //
779: // Scan though the adapter address looking for adapters.
780: //
781:
782: while (AdapterAddresses[*AdapterCount] != 0) {
783:
784: //
785: // Check to see if adapter present in system.
786: //
787:
788: baseIoAddress = (PBASE_REGISTER)(ioSpace + AdapterAddresses[*AdapterCount]);
789: HwDeviceExtension->BaseIoAddress = baseIoAddress;
790:
791: //
792: // Update the adapter count.
793: //
794:
795: (*AdapterCount)++;
796:
797: portValue = ScsiPortReadPortUchar((PUCHAR)baseIoAddress);
798:
799: //
800: // Check for Adaptec adapter.
801: // The mask (0x29) are bits that may or may not be set.
802: // The bit 0x10 (IOP_SCSI_HBA_IDLE) should be set.
803: //
804:
805: if ((portValue & ~0x29) == IOP_SCSI_HBA_IDLE) {
806:
807: if (!AdaptecAdapter(HwDeviceExtension, AdapterAddresses[(*AdapterCount) - 1],
808: (BOOLEAN)(ConfigInfo->AdapterInterfaceType == MicroChannel ? TRUE : FALSE))) {
809: DebugPrint((1,"A154xDetermineInstalled: Clone command completed successfully - \n not our board;"));
810: continue;
811: }
812:
813: //
814: // An adapter has been found. Set the base address in the device
815: // extension, and request another call.
816: //
817:
818: HwDeviceExtension->BaseIoAddress = baseIoAddress;
819: *Again = TRUE;
820:
821: //
822: // Fill in the access array information.
823: //
824:
825: (*ConfigInfo->AccessRanges)[0].RangeStart =
826: ScsiPortConvertUlongToPhysicalAddress(
827: AdapterAddresses[*AdapterCount - 1]);
828: (*ConfigInfo->AccessRanges)[0].RangeLength = 4;
829: (*ConfigInfo->AccessRanges)[0].RangeInMemory = FALSE;
830:
831: return(SP_RETURN_FOUND);
832: }
833: }
834:
835: //
836: // The entire table has been searched and no adapters have been found.
837: // There is no need to call again and the device base can now be freed.
838: // Clear the adapter count for the next bus.
839: //
840:
841: *Again = FALSE;
842: *(AdapterCount) = 0;
843:
844: ScsiPortFreeDeviceBase(
845: HwDeviceExtension,
846: ioSpace
847: );
848:
849: return(SP_RETURN_NOT_FOUND);
850:
851: } // end A154xDetermineInstalled()
852:
853:
854: BOOLEAN
855: A154xHwInitialize(
856: IN PVOID HwDeviceExtension
857: )
858:
859: /*++
860:
861: Routine Description:
862:
863: This routine is called from ScsiPortInitialize
864: to set up the adapter so that it is ready to service requests.
865:
866: Arguments:
867:
868: HwDeviceExtension - HBA miniport driver's adapter data storage
869:
870: Return Value:
871:
872: TRUE - if initialization successful.
873: FALSE - if initialization unsuccessful.
874:
875: --*/
876:
877: {
878: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
879: PNONCACHED_EXTENSION noncachedExtension =
880: deviceExtension->NoncachedExtension;
881: PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
882: UCHAR status;
883: ULONG i;
884:
885: DebugPrint((2,"A154xHwInitialize: Reset aha154X and SCSI bus\n"));
886:
887: //
888: // Reset SCSI chip.
889: //
890:
891: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
892:
893: //
894: // Inform the port driver that the bus has been reset.
895: //
896:
897: ScsiPortNotification(ResetDetected, HwDeviceExtension, 0);
898:
899: ScsiPortStallExecution(500*1000);
900:
901: //
902: // Wait up to 5000 microseconds for adapter to initialize.
903: //
904:
905: for (i = 0; i < 5000; i++) {
906:
907: ScsiPortStallExecution(1);
908:
909: status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
910:
911: if (status & IOP_SCSI_HBA_IDLE) {
912: break;
913: }
914: }
915:
916: //
917: // Check if reset failed or succeeded.
918: //
919:
920: if (!(status & IOP_SCSI_HBA_IDLE) || !(status & IOP_MAILBOX_INIT_REQUIRED)) {
921: DebugPrint((1,"A154xInitialize: Reset SCSI bus failed\n"));
922: return FALSE;
923: }
924:
925: //
926: // Unlock mailboxes in case the adapter is a 1540B with 1Gb support
927: // or 1540C with extended translation enabled.
928: //
929:
930: status = UnlockMailBoxes(deviceExtension);
931: (VOID) SpinForInterrupt(deviceExtension,FALSE);
932:
933: //
934: // Zero out mailboxes.
935: //
936:
937: for (i=0; i<MB_COUNT; i++) {
938:
939: PMBO mailboxOut;
940: PMBI mailboxIn;
941:
942: mailboxIn = &noncachedExtension->Mbi[i];
943: mailboxOut = &noncachedExtension->Mbo[i];
944:
945: mailboxOut->Command = mailboxIn->Status = 0;
946: }
947:
948: //
949: // Zero preivous indexes.
950: //
951:
952: deviceExtension->MboIndex = 0;
953: deviceExtension->MbiIndex = 0;
954:
955: DebugPrint((3,"A154xHwInitialize: Initialize mailbox\n"));
956:
957: if (!WriteCommandRegister(deviceExtension,AC_MAILBOX_INITIALIZATION, TRUE)) {
958: DebugPrint((1,"A154xHwInitialize: Couldn't initialize mailboxes\n"));
959: return FALSE;
960: }
961:
962: //
963: // Send Adapter number of mailbox locations.
964: //
965:
966: if (!WriteDataRegister(deviceExtension, MB_COUNT)) {
967: return FALSE;
968: }
969:
970: //
971: // Send the most significant byte of the mailbox physical address.
972: //
973:
974: if (!WriteDataRegister(deviceExtension,
975: ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
976: return FALSE;
977: }
978:
979: //
980: // Send the middle byte of the mailbox physical address.
981: //
982:
983: if (!WriteDataRegister(deviceExtension,
984: ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
985: return FALSE;
986: }
987:
988: //
989: // Send the least significant byte of the mailbox physical address.
990: //
991:
992: if (!WriteDataRegister(deviceExtension,
993: ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
994: return FALSE;
995: }
996:
997: #ifdef FORCE_DMA_SPEED
998: //
999: // Set the DMA transfer speed to 5.0 MB/second. This is because
1000: // faster transfer speeds cause data corruption on 486/33 machines.
1001: // This overrides the card jumper setting.
1002: //
1003:
1004: if (!WriteCommandRegister(deviceExtension, AC_SET_TRANSFER_SPEED, TRUE)) {
1005:
1006: DebugPrint((1,"Can't set dma transfer speed\n"));
1007:
1008: } else if (!WriteDataRegister(deviceExtension, DMA_SPEED_50_MBS)) {
1009:
1010: DebugPrint((1,"Can't set dma transfer speed\n"));
1011: }
1012:
1013: //
1014: // Wait for interrupt.
1015: //
1016:
1017: if (!SpinForInterrupt(deviceExtension,TRUE)) {
1018:
1019: DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
1020: return TRUE;
1021: }
1022: #endif
1023:
1024: //
1025: // Override default setting for bus on time. This makes floppy
1026: // drives work better with this adapter.
1027: //
1028:
1029: if (!WriteCommandRegister(deviceExtension, AC_SET_BUS_ON_TIME, TRUE)) {
1030:
1031: DebugPrint((1,"Can't set bus on time\n"));
1032:
1033: } else if (!WriteDataRegister(deviceExtension, deviceExtension->BusOnTime)) {
1034:
1035: DebugPrint((1,"Can't set bus on time\n"));
1036: }
1037:
1038: //
1039: // Wait for interrupt.
1040: //
1041:
1042: if (!SpinForInterrupt(deviceExtension,TRUE)) {
1043:
1044: DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
1045: return TRUE;
1046: }
1047:
1048:
1049: //
1050: // Override the default CCB timeout of 250 mseconds to 500 (0x1F4).
1051: //
1052:
1053: if (!WriteCommandRegister(deviceExtension, AC_SET_SELECTION_TIMEOUT, TRUE)) {
1054: DebugPrint((1,"A154xHwInitialize: Can't set CCB timeout\n"));
1055: }
1056: else {
1057: if (!WriteDataRegister(deviceExtension,0x01)) {
1058: DebugPrint((1,"A154xHwInitialize: Can't set timeout selection enable\n"));
1059: }
1060:
1061: if (!WriteDataRegister(deviceExtension,0x00)) {
1062: DebugPrint((1,"A154xHwInitialize: Can't set second byte\n"));
1063: }
1064:
1065: if (!WriteDataRegister(deviceExtension,0x01)) {
1066: DebugPrint((1,"A154xHwInitialize: Can't set MSB\n"));
1067: }
1068:
1069: if (!WriteDataRegister(deviceExtension,0xF4)) {
1070: DebugPrint((1,"A154xHwInitialize: Can't set LSB\n"));
1071: }
1072: }
1073:
1074:
1075: //
1076: // Wait for interrupt.
1077: //
1078:
1079: if (!SpinForInterrupt(deviceExtension,TRUE)) {
1080:
1081: DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
1082: return TRUE;
1083: }
1084:
1085:
1086: return TRUE;
1087:
1088: } // end A154xHwInitialize()
1089:
1090:
1091: BOOLEAN
1092: A154xStartIo(
1093: IN PVOID HwDeviceExtension,
1094: IN PSCSI_REQUEST_BLOCK Srb
1095: )
1096:
1097: /*++
1098:
1099: Routine Description:
1100:
1101: This routine is called from the SCSI port driver synchronized
1102: with the kernel. The mailboxes are scanned for an empty one and
1103: the CCB is written to it. Then the doorbell is rung and the
1104: OS port driver is notified that the adapter can take
1105: another request, if any are available.
1106:
1107: Arguments:
1108:
1109: HwDeviceExtension - HBA miniport driver's adapter data storage
1110: Srb - IO request packet
1111:
1112: Return Value:
1113:
1114: TRUE
1115:
1116: --*/
1117:
1118: {
1119: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
1120: PNONCACHED_EXTENSION noncachedExtension =
1121: deviceExtension->NoncachedExtension;
1122: PMBO mailboxOut;
1123: PCCB ccb;
1124: PHW_LU_EXTENSION luExtension;
1125:
1126: ULONG i = deviceExtension->MboIndex;
1127: ULONG physicalCcb;
1128: ULONG length;
1129:
1130: DebugPrint((3,"A154xStartIo: Enter routine\n"));
1131:
1132: //
1133: // Check if command is an ABORT request.
1134: //
1135:
1136: if (Srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
1137:
1138: //
1139: // Verify that SRB to abort is still outstanding.
1140: //
1141:
1142: luExtension =
1143: ScsiPortGetLogicalUnit(deviceExtension,
1144: Srb->PathId,
1145: Srb->TargetId,
1146: Srb->Lun);
1147:
1148: if (!luExtension->CurrentSrb) {
1149:
1150: DebugPrint((1, "A154xStartIo: SRB to abort already completed\n"));
1151:
1152: //
1153: // Complete abort SRB.
1154: //
1155:
1156: Srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
1157:
1158: ScsiPortNotification(RequestComplete,
1159: deviceExtension,
1160: Srb);
1161: //
1162: // Adapter ready for next request.
1163: //
1164:
1165: ScsiPortNotification(NextRequest,
1166: deviceExtension,
1167: NULL);
1168:
1169: return TRUE;
1170: }
1171:
1172: //
1173: // Get CCB to abort.
1174: //
1175:
1176: ccb = Srb->NextSrb->SrbExtension;
1177:
1178: //
1179: // Set abort SRB for completion.
1180: //
1181:
1182: ccb->AbortSrb = Srb;
1183:
1184: } else {
1185:
1186: ccb = Srb->SrbExtension;
1187:
1188: //
1189: // Save SRB back pointer in CCB.
1190: //
1191:
1192: ccb->SrbAddress = Srb;
1193: }
1194:
1195: //
1196: // Get CCB physical address.
1197: //
1198:
1199: physicalCcb = ScsiPortConvertPhysicalAddressToUlong(
1200: ScsiPortGetPhysicalAddress(deviceExtension, NULL, ccb, &length));
1201:
1202: //
1203: // Find free mailboxOut.
1204: //
1205:
1206: do {
1207:
1208: mailboxOut = &noncachedExtension->Mbo[i % MB_COUNT];
1209: i++;
1210:
1211: } while (mailboxOut->Command != MBO_FREE);
1212:
1213: //
1214: // Save the next free location.
1215: //
1216:
1217: deviceExtension->MboIndex = (UCHAR) (i % MB_COUNT);
1218:
1219: DebugPrint((3,"A154xStartIo: MBO address %lx, Loop count = %d\n", mailboxOut, i));
1220:
1221: //
1222: // Write CCB to mailbox.
1223: //
1224:
1225: FOUR_TO_THREE(&mailboxOut->Address,
1226: (PFOUR_BYTE)&physicalCcb);
1227:
1228: switch (Srb->Function) {
1229:
1230: case SRB_FUNCTION_ABORT_COMMAND:
1231:
1232: DebugPrint((1, "A154xStartIo: Abort request received\n"));
1233:
1234: //
1235: // BUGBUG: Race condition (what if CCB to be aborted
1236: // completes after setting new SrbAddress?)
1237: //
1238:
1239: mailboxOut->Command = MBO_ABORT;
1240:
1241: break;
1242:
1243: case SRB_FUNCTION_RESET_BUS:
1244:
1245: //
1246: // Reset aha154x and SCSI bus.
1247: //
1248:
1249: DebugPrint((1, "A154xStartIo: Reset bus request received\n"));
1250:
1251: if (!A154xResetBus(
1252: deviceExtension,
1253: Srb->PathId
1254: )) {
1255:
1256: DebugPrint((1,"A154xStartIo: Reset bus failed\n"));
1257:
1258: Srb->SrbStatus = SRB_STATUS_ERROR;
1259:
1260: } else {
1261:
1262: Srb->SrbStatus = SRB_STATUS_SUCCESS;
1263: }
1264:
1265:
1266: ScsiPortNotification(RequestComplete,
1267: deviceExtension,
1268: Srb);
1269:
1270: ScsiPortNotification(NextRequest,
1271: deviceExtension,
1272: NULL);
1273:
1274: return TRUE;
1275:
1276: case SRB_FUNCTION_EXECUTE_SCSI:
1277:
1278: //
1279: // Get logical unit extension.
1280: //
1281:
1282: luExtension =
1283: ScsiPortGetLogicalUnit(deviceExtension,
1284: Srb->PathId,
1285: Srb->TargetId,
1286: Srb->Lun);
1287:
1288: //
1289: // Move SRB to logical unit extension.
1290: //
1291:
1292: luExtension->CurrentSrb = Srb;
1293:
1294: //
1295: // Build CCB.
1296: //
1297:
1298: BuildCcb(deviceExtension, Srb);
1299:
1300: mailboxOut->Command = MBO_START;
1301:
1302: break;
1303:
1304: case SRB_FUNCTION_RESET_DEVICE:
1305:
1306: DebugPrint((1,"A154xStartIo: Reset device not supported\n"));
1307:
1308: //
1309: // Drop through to default.
1310: //
1311:
1312: default:
1313:
1314: //
1315: // Set error, complete request
1316: // and signal ready for next request.
1317: //
1318:
1319: Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;
1320:
1321: ScsiPortNotification(RequestComplete,
1322: deviceExtension,
1323: Srb);
1324:
1325: ScsiPortNotification(NextRequest,
1326: deviceExtension,
1327: NULL);
1328:
1329: return TRUE;
1330:
1331: } // end switch
1332:
1333: //
1334: // Tell 154xb a CCB is available now.
1335: //
1336:
1337: if (!WriteCommandRegister(deviceExtension,AC_START_SCSI_COMMAND, FALSE)) {
1338:
1339: //
1340: // Let request time out and fail.
1341: //
1342:
1343: DebugPrint((1,"A154xStartIo: Can't write command to adapter\n"));
1344:
1345: deviceExtension->PendingRequest = TRUE;
1346:
1347: } else {
1348:
1349: //
1350: // Command(s) submitted. Clear pending request flag.
1351: //
1352:
1353: deviceExtension->PendingRequest = FALSE;
1354:
1355: //
1356: // Adapter ready for next request.
1357: //
1358:
1359: ScsiPortNotification(NextRequest,
1360: deviceExtension,
1361: NULL);
1362: }
1363:
1364: return TRUE;
1365:
1366: } // end A154xStartIo()
1367:
1368:
1369: BOOLEAN
1370: A154xInterrupt(
1371: IN PVOID HwDeviceExtension
1372: )
1373:
1374: /*++
1375:
1376: Routine Description:
1377:
1378: This is the interrupt service routine for the adaptec 154x SCSI adapter.
1379: It reads the interrupt register to determine if the adapter is indeed
1380: the source of the interrupt and clears the interrupt at the device.
1381: If the adapter is interrupting because a mailbox is full, the CCB is
1382: retrieved to complete the request.
1383:
1384: Arguments:
1385:
1386: HwDeviceExtension - HBA miniport driver's adapter data storage
1387:
1388: Return Value:
1389:
1390: TRUE if MailboxIn full
1391:
1392: --*/
1393:
1394: {
1395: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
1396: PNONCACHED_EXTENSION noncachedExtension =
1397: deviceExtension->NoncachedExtension;
1398: PCCB ccb;
1399: PSCSI_REQUEST_BLOCK srb;
1400: PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
1401: PMBI mailboxIn;
1402: ULONG physicalCcb;
1403: PHW_LU_EXTENSION luExtension;
1404: ULONG residualBytes;
1405: ULONG i;
1406:
1407: UCHAR InterruptFlags;
1408:
1409: InterruptFlags = ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister);
1410:
1411: //
1412: // Determine cause of interrupt.
1413: //
1414:
1415: if (InterruptFlags & IOP_COMMAND_COMPLETE) {
1416:
1417: //
1418: // Adapter command completed.
1419: //
1420:
1421: DebugPrint((2,"A154xInterrupt: Adapter Command complete\n"));
1422: DebugPrint((3,"A154xInterrupt: Interrupt flags %x\n", InterruptFlags));
1423: DebugPrint((3,"A154xInterrupt: Status %x\n",
1424: ScsiPortReadPortUchar(&baseIoAddress->StatusRegister)));
1425:
1426: //
1427: // Clear interrupt on adapter.
1428: //
1429:
1430: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
1431:
1432: return TRUE;
1433:
1434: } else if (InterruptFlags & IOP_MBI_FULL) {
1435:
1436: DebugPrint((3,"A154xInterrupt: MBI Full\n"));
1437:
1438: //
1439: // Clear interrupt on adapter.
1440: //
1441:
1442: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
1443:
1444: } else if (InterruptFlags & IOP_SCSI_RESET_DETECTED) {
1445:
1446: DebugPrint((1,"A154xInterrupt: SCSI Reset detected\n"));
1447:
1448: //
1449: // Clear interrupt on adapter.
1450: //
1451:
1452: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
1453:
1454: //
1455: // Notify of reset.
1456: //
1457:
1458: ScsiPortNotification(ResetDetected,
1459: deviceExtension,
1460: NULL);
1461:
1462: return TRUE;
1463:
1464: } else {
1465:
1466: DebugPrint((4,"A154xInterrupt: Spurious interrupt\n"));
1467:
1468: return FALSE;
1469: }
1470:
1471: //
1472: // Determine which MailboxIn location contains the CCB.
1473: //
1474:
1475: for (i=0; i<MB_COUNT; i++) {
1476:
1477: mailboxIn = &noncachedExtension->Mbi[deviceExtension->MbiIndex];
1478:
1479: //
1480: // Look for a mailbox entry with a legitimate status.
1481: //
1482:
1483: if (mailboxIn->Status != MBI_FREE) {
1484:
1485: //
1486: // Point to the next in box.
1487: //
1488:
1489: deviceExtension->MbiIndex = (deviceExtension->MbiIndex + 1) % MB_COUNT;
1490:
1491: //
1492: // MBI found. Convert CCB to big endian.
1493: //
1494:
1495: THREE_TO_FOUR((PFOUR_BYTE)&physicalCcb,
1496: &mailboxIn->Address);
1497:
1498: DebugPrint((3, "A154xInterrupt: Physical CCB %lx\n", physicalCcb));
1499:
1500: //
1501: // Check if physical CCB is zero.
1502: // This is done to cover for hardware errors.
1503: //
1504:
1505: if (!physicalCcb) {
1506:
1507: DebugPrint((1,"A154xInterrupt: Physical CCB address is 0\n"));
1508:
1509: //
1510: // Indicate MBI is available.
1511: //
1512:
1513: mailboxIn->Status = MBI_FREE;
1514:
1515: continue;
1516: }
1517:
1518: //
1519: // Convert Physical CCB to Virtual.
1520: //
1521:
1522: ccb = ScsiPortGetVirtualAddress(deviceExtension, ScsiPortConvertUlongToPhysicalAddress(physicalCcb));
1523:
1524:
1525: DebugPrint((3, "A154xInterrupt: Virtual CCB %lx\n", ccb));
1526:
1527: //
1528: // Make sure the virtual address was found.
1529: //
1530:
1531: if (ccb == NULL) {
1532:
1533: //
1534: // A bad physcial address was return by the adapter.
1535: // Log it as an error.
1536: //
1537:
1538: ScsiPortLogError(
1539: HwDeviceExtension,
1540: NULL,
1541: 0,
1542: deviceExtension->HostTargetId,
1543: 0,
1544: SP_INTERNAL_ADAPTER_ERROR,
1545: 5 << 8
1546: );
1547:
1548: //
1549: // Indicate MBI is available.
1550: //
1551:
1552: mailboxIn->Status = MBI_FREE;
1553:
1554: continue;
1555: }
1556:
1557: //
1558: // Get SRB from CCB.
1559: //
1560:
1561: srb = ccb->SrbAddress;
1562:
1563: //
1564: // Get logical unit extension.
1565: //
1566:
1567: luExtension =
1568: ScsiPortGetLogicalUnit(deviceExtension,
1569: srb->PathId,
1570: srb->TargetId,
1571: srb->Lun);
1572:
1573: //
1574: // Make sure the luExtension was found and it has a current request.
1575: //
1576:
1577: if (luExtension == NULL || (luExtension->CurrentSrb == NULL &&
1578: mailboxIn->Status != MBI_NOT_FOUND)) {
1579:
1580: //
1581: // A bad physcial address was return by the adapter.
1582: // Log it as an error.
1583: //
1584:
1585: ScsiPortLogError(
1586: HwDeviceExtension,
1587: NULL,
1588: 0,
1589: deviceExtension->HostTargetId,
1590: 0,
1591: SP_INTERNAL_ADAPTER_ERROR,
1592: (6 << 8) | mailboxIn->Status
1593: );
1594:
1595: //
1596: // Indicate MBI is available.
1597: //
1598:
1599: mailboxIn->Status = MBI_FREE;
1600:
1601: continue;
1602: }
1603:
1604: //
1605: // Check MBI status.
1606: //
1607:
1608: switch (mailboxIn->Status) {
1609:
1610: case MBI_SUCCESS:
1611:
1612: //
1613: // Update SRB with number of bytes transferred.
1614: //
1615:
1616: THREE_TO_FOUR((PFOUR_BYTE)&residualBytes,
1617: &ccb->DataLength);
1618:
1619: if (residualBytes != 0) {
1620:
1621: DebugPrint((1, "A154xInterrupt: Underrun occured. Request length = %lx, Residual length = %lx\n", srb->DataTransferLength, residualBytes));
1622: srb->DataTransferLength -= residualBytes;
1623: srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;
1624:
1625: } else {
1626:
1627: srb->SrbStatus = SRB_STATUS_SUCCESS;
1628:
1629: }
1630:
1631: luExtension->CurrentSrb = NULL;
1632:
1633: break;
1634:
1635: case MBI_NOT_FOUND:
1636:
1637: DebugPrint((1, "A154xInterrupt: CCB abort failed %lx\n", ccb));
1638:
1639: srb = ccb->AbortSrb;
1640:
1641: srb->SrbStatus = SRB_STATUS_ABORT_FAILED;
1642:
1643: //
1644: // Check if SRB still outstanding.
1645: //
1646:
1647: if (luExtension->CurrentSrb) {
1648:
1649: //
1650: // Complete this SRB.
1651: //
1652:
1653: luExtension->CurrentSrb->SrbStatus = SRB_STATUS_TIMEOUT;
1654:
1655: ScsiPortNotification(RequestComplete,
1656: deviceExtension,
1657: luExtension->CurrentSrb);
1658:
1659: luExtension->CurrentSrb = NULL;
1660: }
1661:
1662: break;
1663:
1664: case MBI_ABORT:
1665:
1666: DebugPrint((1, "A154xInterrupt: CCB aborted\n"));
1667:
1668: //
1669: // Update target status in aborted SRB.
1670: //
1671:
1672: srb->SrbStatus = SRB_STATUS_ABORTED;
1673:
1674: //
1675: // Call notification routine for the aborted SRB.
1676: //
1677:
1678: ScsiPortNotification(RequestComplete,
1679: deviceExtension,
1680: srb);
1681:
1682: luExtension->CurrentSrb = NULL;
1683:
1684: //
1685: // Get the abort SRB from CCB.
1686: //
1687:
1688: srb = ccb->AbortSrb;
1689:
1690: //
1691: // Set status for completing abort request.
1692: //
1693:
1694: srb->SrbStatus = SRB_STATUS_SUCCESS;
1695:
1696: break;
1697:
1698: case MBI_ERROR:
1699:
1700: DebugPrint((2, "A154xInterrupt: Error occurred\n"));
1701:
1702: srb->SrbStatus = MapError(deviceExtension, srb, ccb);
1703:
1704: //
1705: // Check if ABORT command.
1706: //
1707:
1708: if (srb->Function == SRB_FUNCTION_ABORT_COMMAND) {
1709:
1710: //
1711: // Check if SRB still outstanding.
1712: //
1713:
1714: if (luExtension->CurrentSrb) {
1715:
1716: //
1717: // Complete this SRB.
1718: //
1719:
1720: luExtension->CurrentSrb->SrbStatus = SRB_STATUS_TIMEOUT;
1721:
1722: ScsiPortNotification(RequestComplete,
1723: deviceExtension,
1724: luExtension->CurrentSrb);
1725:
1726: }
1727:
1728: DebugPrint((1,"A154xInterrupt: Abort command failed\n"));
1729: }
1730:
1731: luExtension->CurrentSrb = NULL;
1732:
1733: break;
1734:
1735: default:
1736:
1737: //
1738: // Log the error.
1739: //
1740:
1741: ScsiPortLogError(
1742: HwDeviceExtension,
1743: NULL,
1744: 0,
1745: deviceExtension->HostTargetId,
1746: 0,
1747: SP_INTERNAL_ADAPTER_ERROR,
1748: (1 << 8) | mailboxIn->Status
1749: );
1750:
1751: DebugPrint((1, "A154xInterrupt: Unrecognized mailbox status\n"));
1752:
1753: mailboxIn->Status = MBI_FREE;
1754:
1755: continue;
1756:
1757: } // end switch
1758:
1759: //
1760: // Indicate MBI is available.
1761: //
1762:
1763: mailboxIn->Status = MBI_FREE;
1764:
1765: DebugPrint((2, "A154xInterrupt: SCSI Status %x\n", srb->ScsiStatus));
1766:
1767: DebugPrint((2, "A154xInterrupt: Adapter Status %x\n", ccb->HostStatus));
1768:
1769: //
1770: // Update target status in SRB.
1771: //
1772:
1773: srb->ScsiStatus = ccb->TargetStatus;
1774:
1775: //
1776: // Signal request completion.
1777: //
1778:
1779: ScsiPortNotification(RequestComplete,
1780: (PVOID)deviceExtension,
1781: srb);
1782:
1783: } else {
1784:
1785: break;
1786:
1787: } // end if ((mailboxIn->Status == MBI_SUCCESS ...
1788:
1789: } // end for (i=0; i<MB_COUNT; i++) {
1790:
1791: if (deviceExtension->PendingRequest) {
1792:
1793: //
1794: // The last write command to the adapter failed. Try and start it now.
1795: //
1796:
1797: deviceExtension->PendingRequest = FALSE;
1798:
1799: //
1800: // Tell 154xb a CCB is available now.
1801: //
1802:
1803: if (!WriteCommandRegister(deviceExtension,AC_START_SCSI_COMMAND, FALSE)) {
1804:
1805: //
1806: // Let request time out and fail.
1807: //
1808:
1809: DebugPrint((1,"A154xInterrupt: Can't write command to adapter\n"));
1810:
1811: deviceExtension->PendingRequest = TRUE;
1812:
1813: } else {
1814:
1815: //
1816: // Adapter ready for next request.
1817: //
1818:
1819: ScsiPortNotification(NextRequest,
1820: deviceExtension,
1821: NULL);
1822: }
1823: }
1824:
1825: return TRUE;
1826:
1827: } // end A154xInterrupt()
1828:
1829:
1830: VOID
1831: BuildCcb(
1832: IN PHW_DEVICE_EXTENSION DeviceExtension,
1833: IN PSCSI_REQUEST_BLOCK Srb
1834: )
1835:
1836: /*++
1837:
1838: Routine Description:
1839:
1840: Build CCB for 154x.
1841:
1842: Arguments:
1843:
1844: DeviceExtenson
1845: SRB
1846:
1847: Return Value:
1848:
1849: Nothing.
1850:
1851: --*/
1852:
1853: {
1854: PCCB ccb = Srb->SrbExtension;
1855:
1856: DebugPrint((3,"BuildCcb: Enter routine\n"));
1857:
1858: //
1859: // Set target id and LUN.
1860: //
1861:
1862: ccb->ControlByte = (UCHAR)(Srb->TargetId << 5) | Srb->Lun;
1863:
1864: //
1865: // Set CCB Operation Code.
1866: //
1867:
1868:
1869: ccb->OperationCode = SCATTER_GATHER_COMMAND;
1870:
1871: //
1872: // Set transfer direction bit.
1873: //
1874:
1875: if (Srb->SrbFlags & SRB_FLAGS_DATA_OUT) {
1876:
1877: //
1878: // Check if both direction bits are set. This is an
1879: // indication that the direction has not been specified.
1880: //
1881:
1882: if (!(Srb->SrbFlags & SRB_FLAGS_DATA_IN)) {
1883: ccb->ControlByte |= CCB_DATA_XFER_OUT;
1884: }
1885:
1886: } else if (Srb->SrbFlags & SRB_FLAGS_DATA_IN) {
1887: ccb->ControlByte |= CCB_DATA_XFER_IN;
1888: } else {
1889:
1890: //
1891: // if no data transfer, we must set ccb command to to INITIATOR
1892: // instead of SCATTER_GATHER and zero ccb data pointer and length.
1893: //
1894:
1895: ccb->OperationCode = SCSI_INITIATOR_COMMAND;
1896: ccb->DataPointer.Msb = 0;
1897: ccb->DataPointer.Mid = 0;
1898: ccb->DataPointer.Lsb = 0;
1899: ccb->DataLength.Msb = 0;
1900: ccb->DataLength.Mid = 0;
1901: ccb->DataLength.Lsb = 0;
1902: }
1903:
1904: //
1905: // 01h disables auto request sense.
1906: //
1907:
1908: ccb->RequestSenseLength = 1;
1909:
1910: //
1911: // Set CDB length and copy to CCB.
1912: //
1913:
1914: ccb->CdbLength = (UCHAR)Srb->CdbLength;
1915:
1916: ScsiPortMoveMemory(ccb->Cdb, Srb->Cdb, ccb->CdbLength);
1917:
1918: //
1919: // Set reserved bytes to zero.
1920: //
1921:
1922: ccb->Reserved[0] = 0;
1923: ccb->Reserved[1] = 0;
1924:
1925: ccb->LinkIdentifier = 0;
1926:
1927: //
1928: // Zero link pointer.
1929: //
1930:
1931: ccb->LinkPointer.Msb = 0;
1932: ccb->LinkPointer.Lsb = 0;
1933: ccb->LinkPointer.Mid = 0;
1934:
1935: //
1936: // Build SDL in CCB if data transfer.
1937: //
1938:
1939: if (Srb->DataTransferLength > 0) {
1940: BuildSdl(DeviceExtension, Srb);
1941: }
1942:
1943: //
1944: // Move 0xff to Target Status to indicate
1945: // CCB has not completed.
1946: //
1947:
1948: ccb->TargetStatus = 0xFF;
1949:
1950: return;
1951:
1952: } // end BuildCcb()
1953:
1954:
1955: VOID
1956: BuildSdl(
1957: IN PHW_DEVICE_EXTENSION DeviceExtension,
1958: IN PSCSI_REQUEST_BLOCK Srb
1959: )
1960:
1961: /*++
1962:
1963: Routine Description:
1964:
1965: This routine builds a scatter/gather descriptor list for the CCB.
1966:
1967: Arguments:
1968:
1969: DeviceExtension
1970: Srb
1971:
1972: Return Value:
1973:
1974: None
1975:
1976: --*/
1977:
1978: {
1979: PVOID dataPointer = Srb->DataBuffer;
1980: ULONG bytesLeft = Srb->DataTransferLength;
1981: PCCB ccb = Srb->SrbExtension;
1982: PSDL sdl = &ccb->Sdl;
1983: ULONG physicalSdl;
1984: ULONG physicalAddress;
1985: ULONG length;
1986: ULONG four;
1987: PTHREE_BYTE three;
1988: ULONG i = 0;
1989:
1990: DebugPrint((3,"BuildSdl: Enter routine\n"));
1991:
1992: //
1993: // Get physical SDL address.
1994: //
1995:
1996: physicalSdl = ScsiPortConvertPhysicalAddressToUlong(
1997: ScsiPortGetPhysicalAddress(DeviceExtension, NULL,
1998: sdl, &length));
1999:
2000: //
2001: // Create SDL segment descriptors.
2002: //
2003:
2004: do {
2005:
2006: DebugPrint((3, "BuildSdl: Data buffer %lx\n", dataPointer));
2007:
2008: //
2009: // Get physical address and length of contiguous
2010: // physical buffer.
2011: //
2012:
2013: physicalAddress =
2014: ScsiPortConvertPhysicalAddressToUlong(
2015: ScsiPortGetPhysicalAddress(DeviceExtension,
2016: Srb,
2017: dataPointer,
2018: &length));
2019:
2020: DebugPrint((3, "BuildSdl: Physical address %lx\n", physicalAddress));
2021: DebugPrint((3, "BuildSdl: Data length %lx\n", length));
2022: DebugPrint((3, "BuildSdl: Bytes left %lx\n", bytesLeft));
2023:
2024: //
2025: // If length of physical memory is more
2026: // than bytes left in transfer, use bytes
2027: // left as final length.
2028: //
2029:
2030: if (length > bytesLeft) {
2031: length = bytesLeft;
2032: }
2033:
2034: //
2035: // Convert length to 3-byte big endian format.
2036: //
2037:
2038: four = length;
2039: three = &sdl->Sgd[i].Length;
2040: FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
2041:
2042: //
2043: // Convert physical address to 3-byte big endian format.
2044: //
2045:
2046: four = (ULONG)physicalAddress;
2047: three = &sdl->Sgd[i].Address;
2048: FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
2049: i++;
2050:
2051: //
2052: // Adjust counts.
2053: //
2054:
2055: dataPointer = (PUCHAR)dataPointer + length;
2056: bytesLeft -= length;
2057:
2058: } while (bytesLeft);
2059:
2060: //
2061: // Write SDL length to CCB.
2062: //
2063:
2064: four = i * sizeof(SGD);
2065: three = &ccb->DataLength;
2066: FOUR_TO_THREE(three, (PFOUR_BYTE)&four);
2067:
2068: DebugPrint((3,"BuildSdl: SDL length is %d\n", four));
2069:
2070: //
2071: // Write SDL address to CCB.
2072: //
2073:
2074: FOUR_TO_THREE(&ccb->DataPointer,
2075: (PFOUR_BYTE)&physicalSdl);
2076:
2077: DebugPrint((3,"BuildSdl: SDL address is %lx\n", sdl));
2078:
2079: DebugPrint((3,"BuildSdl: CCB address is %lx\n", ccb));
2080:
2081: return;
2082:
2083: } // end BuildSdl()
2084:
2085:
2086: BOOLEAN
2087: A154xResetBus(
2088: IN PVOID HwDeviceExtension,
2089: IN ULONG PathId
2090: )
2091:
2092: /*++
2093:
2094: Routine Description:
2095:
2096: Reset Adaptec 154X SCSI adapter and SCSI bus.
2097: Initialize adapter mailbox.
2098:
2099: Arguments:
2100:
2101: HwDeviceExtension - HBA miniport driver's adapter data storage
2102:
2103: Return Value:
2104:
2105: Nothing.
2106:
2107:
2108: --*/
2109:
2110: {
2111: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
2112: PNONCACHED_EXTENSION noncachedExtension =
2113: deviceExtension->NoncachedExtension;
2114: PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
2115: UCHAR status;
2116: ULONG i;
2117:
2118: DebugPrint((2,"ResetBus: Reset aha154X and SCSI bus\n"));
2119:
2120: //
2121: // Complete all outstanding requests with SRB_STATUS_BUS_RESET.
2122: //
2123:
2124: ScsiPortCompleteRequest(deviceExtension,
2125: (UCHAR) PathId,
2126: 0xFF,
2127: 0xFF,
2128: (ULONG) SRB_STATUS_BUS_RESET);
2129:
2130: //
2131: // Reset SCSI chip.
2132: //
2133:
2134: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_HARD_RESET);
2135:
2136: ScsiPortStallExecution(500 * 1000);
2137:
2138: //
2139: // Wait up to 5000 microseconds for adapter to initialize.
2140: //
2141:
2142: for (i = 0; i < 5000; i++) {
2143:
2144: ScsiPortStallExecution(1);
2145:
2146: status = ScsiPortReadPortUchar(&deviceExtension->BaseIoAddress->StatusRegister);
2147:
2148: if (status & IOP_SCSI_HBA_IDLE) {
2149: break;
2150: }
2151: }
2152:
2153: //
2154: // Zero out mailboxes.
2155: //
2156:
2157: for (i=0; i<MB_COUNT; i++) {
2158:
2159: PMBO mailboxOut;
2160: PMBI mailboxIn;
2161:
2162: mailboxIn = &noncachedExtension->Mbi[i];
2163: mailboxOut = &noncachedExtension->Mbo[i];
2164:
2165: mailboxOut->Command = mailboxIn->Status = 0;
2166: }
2167:
2168: //
2169: // Zero previous indexes.
2170: //
2171:
2172: deviceExtension->MboIndex = 0;
2173: deviceExtension->MbiIndex = 0;
2174:
2175: if (deviceExtension->PendingRequest) {
2176:
2177: deviceExtension->PendingRequest = FALSE;
2178:
2179: //
2180: // Adapter ready for next request.
2181: //
2182:
2183: ScsiPortNotification(NextRequest,
2184: deviceExtension,
2185: NULL);
2186: }
2187:
2188: if (!(status & IOP_SCSI_HBA_IDLE)) {
2189: return(FALSE);
2190: }
2191:
2192: //
2193: // Unlock mailboxes in case the adapter is a 1540B with 1Gb support
2194: // or 1540C with extended translation enabled. Maiboxes cannot be
2195: // initialized until unlock code is sent.
2196:
2197: status = UnlockMailBoxes(deviceExtension);
2198:
2199: if (!SpinForInterrupt(deviceExtension,FALSE)) {
2200: DebugPrint((1,"A154xResetBus: Failed to unlock mailboxes\n"));
2201: return FALSE;
2202: }
2203:
2204:
2205: DebugPrint((3,"ResetBus: Initialize mailbox\n"));
2206:
2207: if (!WriteCommandRegister(deviceExtension,AC_MAILBOX_INITIALIZATION, TRUE)) {
2208: DebugPrint((1,"A154xResetBus: Couldn't initialize mailboxes\n"));
2209: return FALSE;
2210: }
2211:
2212: //
2213: // Send Adapter number of mailbox locations.
2214: //
2215:
2216: if (!WriteDataRegister(deviceExtension,MB_COUNT)) {
2217: return FALSE;
2218: }
2219:
2220: //
2221: // Send the most significant byte of the mailbox physical address.
2222: //
2223:
2224: if (!WriteDataRegister(deviceExtension,
2225: ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte2)) {
2226: return FALSE;
2227: }
2228:
2229: //
2230: // Send the middle byte of the mailbox physical address.
2231: //
2232:
2233: if (!WriteDataRegister(deviceExtension,
2234: ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte1)) {
2235: return FALSE;
2236: }
2237:
2238: //
2239: // Send the least significant byte of the mailbox physical address.
2240: //
2241:
2242: if (!WriteDataRegister(deviceExtension,
2243: ((PFOUR_BYTE)&noncachedExtension->MailboxPA)->Byte0)) {
2244: return FALSE;
2245: }
2246:
2247: #ifdef FORCE_DMA_SPEED
2248: //
2249: // Set the DMA transfer speed to 5.0 MB/second. This is because
2250: // faster transfer speeds cause data corruption on 486/33 machines.
2251: // This overrides the card jumper setting.
2252: //
2253:
2254: if (!WriteCommandRegister(deviceExtension, AC_SET_TRANSFER_SPEED, TRUE)) {
2255:
2256: DebugPrint((1,"Can't set dma transfer speed\n"));
2257:
2258: } else if (!WriteDataRegister(deviceExtension, DMA_SPEED_50_MBS)) {
2259:
2260: DebugPrint((1,"Can't set dma transfer speed\n"));
2261: }
2262:
2263: //
2264: // Wait for interrupt.
2265: //
2266:
2267: if (!SpinForInterrupt(deviceExtension,TRUE)) {
2268:
2269: DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
2270: }
2271: #endif
2272:
2273: //
2274: // Override default setting for bus on time. This makes floppy
2275: // drives work better with this adapter.
2276: //
2277:
2278: if (!WriteCommandRegister(deviceExtension, AC_SET_BUS_ON_TIME, TRUE)) {
2279:
2280: DebugPrint((1,"Can't set bus on time\n"));
2281:
2282: } else if (!WriteDataRegister(deviceExtension, 0x07)) {
2283:
2284: DebugPrint((1,"Can't set bus on time\n"));
2285: }
2286:
2287: //
2288: // Wait for interrupt.
2289: //
2290:
2291: if (!SpinForInterrupt(deviceExtension,TRUE)) {
2292:
2293: DebugPrint((1,"Timed out waiting for adapter command to complete\n"));
2294: }
2295:
2296: return TRUE;
2297:
2298: } // end A154xResetBus()
2299:
2300:
2301: UCHAR
2302: MapError(
2303: IN PVOID HwDeviceExtension,
2304: IN PSCSI_REQUEST_BLOCK Srb,
2305: IN PCCB Ccb
2306: )
2307:
2308: /*++
2309:
2310: Routine Description:
2311:
2312: Translate A154x error to SRB error, and log an error if necessary.
2313:
2314: Arguments:
2315:
2316: HwDeviceExtension - The hardware device extension.
2317:
2318: Srb - The failing Srb.
2319:
2320: Ccb - Command Control Block contains error.
2321:
2322: Return Value:
2323:
2324: SRB Error
2325:
2326: --*/
2327:
2328: {
2329: UCHAR status;
2330: ULONG logError;
2331: ULONG residualBytes;
2332:
2333: switch (Ccb->HostStatus) {
2334:
2335: case CCB_COMPLETE:
2336: case CCB_SELECTION_TIMEOUT:
2337:
2338: if (Ccb->TargetStatus == SCSISTAT_CHECK_CONDITION) {
2339:
2340: //
2341: // Update SRB with number of bytes transferred.
2342: //
2343:
2344: THREE_TO_FOUR((PFOUR_BYTE)&residualBytes,
2345: &Ccb->DataLength);
2346:
2347: DebugPrint((1, "Aha154x MapError: Underrun occured. Request length = %lx, Residual length = %lx\n", Srb->DataTransferLength, residualBytes));
2348: Srb->DataTransferLength -= residualBytes;
2349: }
2350:
2351: return SRB_STATUS_ERROR;
2352:
2353: case CCB_DATA_OVER_UNDER_RUN:
2354: THREE_TO_FOUR((PFOUR_BYTE)&residualBytes,
2355: &Ccb->DataLength);
2356: if (residualBytes) {
2357: Srb->DataTransferLength -= residualBytes;
2358: } else {
2359: logError = SP_PROTOCOL_ERROR;
2360: }
2361: status = SRB_STATUS_DATA_OVERRUN;
2362: break;
2363:
2364: case CCB_UNEXPECTED_BUS_FREE:
2365: status = SRB_STATUS_UNEXPECTED_BUS_FREE;
2366: logError = SP_UNEXPECTED_DISCONNECT;
2367: break;
2368:
2369: case CCB_PHASE_SEQUENCE_FAIL:
2370: case CCB_INVALID_DIRECTION:
2371: status = SRB_STATUS_PHASE_SEQUENCE_FAILURE;
2372: logError = SP_PROTOCOL_ERROR;
2373: break;
2374:
2375: case CCB_BAD_MBO_COMMAND:
2376: case CCB_INVALID_OP_CODE:
2377: case CCB_BAD_LINKED_LUN:
2378: case CCB_DUPLICATE_CCB:
2379: case CCB_INVALID_CCB:
2380: status = SRB_STATUS_INVALID_REQUEST;
2381: logError = SP_INTERNAL_ADAPTER_ERROR;
2382: break;
2383:
2384: default:
2385: status = SRB_STATUS_ERROR;
2386: logError = SP_INTERNAL_ADAPTER_ERROR;
2387: break;
2388: }
2389:
2390: ScsiPortLogError(
2391: HwDeviceExtension,
2392: Srb,
2393: Srb->PathId,
2394: Srb->TargetId,
2395: Srb->Lun,
2396: logError,
2397: (2 << 8) | Ccb->HostStatus
2398: );
2399:
2400: return(status);
2401:
2402: } // end MapError()
2403:
2404:
2405: BOOLEAN
2406: ReadCommandRegister(
2407: IN PHW_DEVICE_EXTENSION DeviceExtension,
2408: OUT PUCHAR DataByte,
2409: IN BOOLEAN TimeOutFlag
2410: )
2411:
2412: /*++
2413:
2414: Routine Description:
2415:
2416: Read command register.
2417:
2418: Arguments:
2419:
2420: DeviceExtesion - Pointer to adapder extension
2421: DataByte - Byte read from register
2422:
2423: Return Value:
2424:
2425: TRUE if command register read.
2426: FALSE if timed out waiting for adapter.
2427:
2428: --*/
2429:
2430: {
2431: PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
2432: ULONG i;
2433:
2434: //
2435: // Wait up to 5000 microseconds for adapter to be ready.
2436: //
2437:
2438: for (i=0; i<5000; i++) {
2439:
2440: if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
2441: IOP_DATA_IN_PORT_FULL) {
2442:
2443: //
2444: // Adapter ready. Break out of loop.
2445: //
2446:
2447: break;
2448:
2449: } else {
2450:
2451: //
2452: // Stall 1 microsecond before
2453: // trying again.
2454: //
2455:
2456: ScsiPortStallExecution(1);
2457: }
2458: }
2459:
2460: if ( (i==5000) && (TimeOutFlag == TRUE)) {
2461:
2462: ScsiPortLogError(
2463: DeviceExtension,
2464: NULL,
2465: 0,
2466: DeviceExtension->HostTargetId,
2467: 0,
2468: SP_INTERNAL_ADAPTER_ERROR,
2469: 3 << 8
2470: );
2471:
2472: DebugPrint((1, "Aha154x:ReadCommandRegister: Read command timed out\n"));
2473: return FALSE;
2474: }
2475:
2476: *DataByte = ScsiPortReadPortUchar(&baseIoAddress->CommandRegister);
2477:
2478: return TRUE;
2479:
2480: } // end ReadCommandRegister()
2481:
2482:
2483: BOOLEAN
2484: WriteCommandRegister(
2485: IN PHW_DEVICE_EXTENSION DeviceExtension,
2486: IN UCHAR AdapterCommand,
2487: IN BOOLEAN WaitForIdle
2488: )
2489:
2490: /*++
2491:
2492: Routine Description:
2493:
2494: Write operation code to command register.
2495:
2496: Arguments:
2497:
2498: DeviceExtension - Pointer to adapter extension
2499: AdapterCommand - Value to be written to register
2500: WaitForIdle - Indicates if the idle bit needs to be checked
2501:
2502: Return Value:
2503:
2504: TRUE if command sent.
2505: FALSE if timed out waiting for adapter.
2506:
2507: --*/
2508:
2509: {
2510: PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
2511: ULONG i;
2512: UCHAR status;
2513:
2514: //
2515: // Wait up to 500 microseconds for adapter to be ready.
2516: //
2517:
2518: for (i=0; i<5000; i++) {
2519:
2520: status = ScsiPortReadPortUchar(&baseIoAddress->StatusRegister);
2521:
2522: if ((status & IOP_COMMAND_DATA_OUT_FULL) ||
2523: ( WaitForIdle && !(status & IOP_SCSI_HBA_IDLE))) {
2524:
2525: //
2526: // Stall 1 microsecond before
2527: // trying again.
2528: //
2529:
2530: ScsiPortStallExecution(1);
2531:
2532: } else {
2533:
2534: //
2535: // Adapter ready. Break out of loop.
2536: //
2537:
2538: break;
2539: }
2540: }
2541:
2542: if (i==5000) {
2543:
2544: ScsiPortLogError(
2545: DeviceExtension,
2546: NULL,
2547: 0,
2548: DeviceExtension->HostTargetId,
2549: 0,
2550: SP_INTERNAL_ADAPTER_ERROR,
2551: (4 << 8) | status);
2552:
2553: DebugPrint((1, "Aha154x:WriteCommandRegister: Write command timed out\n"));
2554: return FALSE;
2555: }
2556:
2557: ScsiPortWritePortUchar(&baseIoAddress->CommandRegister, AdapterCommand);
2558:
2559: return TRUE;
2560:
2561: } // end WriteCommandRegister()
2562:
2563:
2564: BOOLEAN
2565: WriteDataRegister(
2566: IN PHW_DEVICE_EXTENSION DeviceExtension,
2567: IN UCHAR DataByte
2568: )
2569:
2570: /*++
2571:
2572: Routine Description:
2573:
2574: Write data byte to data register.
2575:
2576: Arguments:
2577:
2578: DeviceExtension - Pointer to adapter extension
2579: DataByte - Value to be written to register
2580:
2581: Return Value:
2582:
2583: TRUE if byte sent.
2584: FALSE if timed out waiting for adapter.
2585:
2586: --*/
2587:
2588: {
2589: PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
2590: ULONG i;
2591:
2592: //
2593: // Wait up to 500 microseconds for adapter to be idle
2594: // and ready for next byte.
2595: //
2596:
2597: for (i=0; i<500; i++) {
2598:
2599: if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
2600: IOP_COMMAND_DATA_OUT_FULL) {
2601:
2602: //
2603: // Stall 1 microsecond before
2604: // trying again.
2605: //
2606:
2607: ScsiPortStallExecution(1);
2608:
2609: } else {
2610:
2611: //
2612: // Adapter ready. Break out of loop.
2613: //
2614:
2615: break;
2616: }
2617: }
2618:
2619: if (i==500) {
2620:
2621: ScsiPortLogError(
2622: DeviceExtension,
2623: NULL,
2624: 0,
2625: DeviceExtension->HostTargetId,
2626: 0,
2627: SP_INTERNAL_ADAPTER_ERROR,
2628: 8 << 8);
2629:
2630: DebugPrint((1, "Aha154x:WriteDataRegister: Write data timed out\n"));
2631: return FALSE;
2632: }
2633:
2634: ScsiPortWritePortUchar(&baseIoAddress->CommandRegister, DataByte);
2635:
2636: return TRUE;
2637:
2638: } // end WriteDataRegister()
2639:
2640:
2641: BOOLEAN
2642: FirmwareBug (
2643: IN PVOID HwDeviceExtension
2644: )
2645:
2646: /*++
2647:
2648: Routine Description:
2649:
2650: Check to see if the host adapter firmware has the scatter/gather
2651: bug.
2652:
2653: Arguments:
2654:
2655: HwDeviceExtension - HBA miniport driver's adapter data storage
2656:
2657: Return Value:
2658:
2659: Return FALSE if there is no firmware bug.
2660: Return TRUE if firmware has scatter/gather bug.
2661:
2662: --*/
2663:
2664: {
2665: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
2666: PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
2667: UCHAR ch;
2668: int i;
2669:
2670: //
2671: // Issue a RETURN SETUP DATA command
2672: // If timeout then return TRUE to indicate that there is a firmware bug.
2673: //
2674:
2675: if ((WriteCommandRegister(HwDeviceExtension,
2676: AC_RETURN_SETUP_DATA,FALSE)) == FALSE) {
2677: return TRUE;
2678: }
2679:
2680:
2681: //
2682: // Tell the adapter we want to read in 0x11 bytes.
2683: //
2684:
2685: if (WriteDataRegister(HwDeviceExtension,0x11) == FALSE) {
2686: return TRUE;
2687: }
2688:
2689: //
2690: // Now try to read in 0x11 bytes.
2691: //
2692:
2693: for (i = 0; i< 0x11; i++) {
2694: if (ReadCommandRegister(HwDeviceExtension,&ch,TRUE) == FALSE) {
2695: return TRUE;
2696: }
2697: }
2698:
2699: //
2700: // Clear adapter interrupt.
2701: //
2702:
2703: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
2704: IOP_INTERRUPT_RESET);
2705:
2706: //
2707: // Issue SET HA OPTION command.
2708: //
2709:
2710: if (WriteCommandRegister(HwDeviceExtension,
2711: AC_SET_HA_OPTION,FALSE) == FALSE) {
2712: return TRUE;
2713: }
2714:
2715: //
2716: // Delay 500 microseconds.
2717: //
2718:
2719: ScsiPortStallExecution(500);
2720:
2721: //
2722: // Check for invalid command.
2723: //
2724:
2725: if ( (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) &
2726: IOP_INVALID_COMMAND) ) {
2727: //
2728: // Clear adapter interrupt.
2729: //
2730:
2731: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
2732: IOP_INTERRUPT_RESET);
2733: return TRUE;
2734: }
2735:
2736: //
2737: // send 01h
2738: //
2739:
2740: if (WriteDataRegister(HwDeviceExtension,0x01) == FALSE) {
2741: return TRUE;
2742: }
2743:
2744: //
2745: // Send same byte as was last received.
2746: //
2747:
2748: if (WriteDataRegister(HwDeviceExtension,ch) == FALSE) {
2749: return TRUE;
2750: }
2751:
2752: //
2753: // Clear adapter interrupt.
2754: //
2755:
2756: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
2757: IOP_INTERRUPT_RESET);
2758: return FALSE;
2759: } // end of FirmwareBug ()
2760:
2761:
2762: VOID
2763: GetHostAdapterBoardId (
2764: IN PVOID HwDeviceExtension,
2765: OUT PUCHAR BoardId
2766: )
2767:
2768: /*++
2769:
2770: Routine Description:
2771:
2772: Get board id, firmware id and hardware id from the host adapter.
2773: These info are used to determine if the host adapter supports
2774: scatter/gather.
2775:
2776: Arguments:
2777:
2778: HwDeviceExtension - HBA miniport driver's adapter data storage
2779:
2780: Return Value:
2781:
2782: Board id, hardware id and firmware id (in that order) by modyfing *BoardId
2783: If there is any error, it will just return with *BoardId unmodified
2784:
2785: --*/
2786:
2787: {
2788: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
2789: PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
2790: UCHAR firmwareId;
2791: UCHAR board_Id;
2792: UCHAR hardwareId;
2793: ULONG i;
2794:
2795: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,
2796: IOP_INTERRUPT_RESET);
2797:
2798: if (!WriteCommandRegister(HwDeviceExtension,AC_ADAPTER_INQUIRY,FALSE)) {
2799: return;
2800: }
2801:
2802: //
2803: // Save byte 0 as board ID.
2804: //
2805:
2806: if ((ReadCommandRegister(HwDeviceExtension,&board_Id,TRUE)) == FALSE) {
2807: return;
2808: }
2809:
2810: //
2811: // Ignore byte 1. Use hardwareId as scrap storage.
2812: //
2813:
2814: if ((ReadCommandRegister(HwDeviceExtension,&hardwareId,TRUE)) == FALSE) {
2815: return;
2816: }
2817:
2818: //
2819: // Save byte 2 as hardware revision in hardwareId.
2820: //
2821:
2822: if ((ReadCommandRegister(HwDeviceExtension,&hardwareId,TRUE)) == FALSE) {
2823: return;
2824: }
2825:
2826: if ((ReadCommandRegister(HwDeviceExtension,&firmwareId,TRUE)) == FALSE) {
2827: return;
2828: }
2829:
2830: //
2831: // Interrupt handler is not yet installed so wait for HACC by hand.
2832: //
2833:
2834: for (i = 0; i<5000; i++) {
2835: if (ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister) ==
2836: (IOP_ANY_INTERRUPT | IOP_COMMAND_COMPLETE) ) {
2837: break;
2838: }
2839: ScsiPortStallExecution(1);
2840: }
2841:
2842: //
2843: // If timeout then return with *BoardId unmodified. This means that
2844: // scatter/gather won't be supported.
2845: //
2846:
2847: if (i == 5000) {
2848: return;
2849: }
2850:
2851: //
2852: // Clear adapter interrupt.
2853: //
2854:
2855: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,IOP_INTERRUPT_RESET);
2856:
2857: //
2858: // Return with appropriate ID's.
2859: //
2860:
2861: *BoardId++ = board_Id;
2862: *BoardId++ = hardwareId;
2863: *BoardId++ = firmwareId;
2864:
2865: DebugPrint((1,"board_id = %d\n",board_Id));
2866: DebugPrint((1,"hardwareid = %d\n",hardwareId));
2867: DebugPrint((1,"fid = %d\n",firmwareId));
2868:
2869: } // end of GetHostAdapterBoardId ()
2870:
2871:
2872: BOOLEAN
2873: ScatterGatherSupported (
2874: IN PHW_DEVICE_EXTENSION HwDeviceExtension
2875: )
2876:
2877: /*++
2878:
2879: Routine Description:
2880: Determine if the host adapter supports scatter/gather. On older
2881: boards, scatter/gather is not supported. On some boards, there is
2882: a bug that causes data corruption on multi-segment WRITE commands.
2883: The algorithm to determine whether the board has the scatter/gather
2884: bug is not "clean" but there is no other way since the firmware revision
2885: levels returned by the host adapter are inconsistent with previous
2886: releases.
2887:
2888: Arguments:
2889:
2890: HwDeviceExtension - HBA miniport driver's adapter data storage
2891:
2892: Return Value:
2893:
2894: Return TRUE if the algorithm determines that there is no scatter/gather
2895: firmware bug.
2896:
2897: Return FALSE if the algorithm determines that the adapter is an older
2898: board or that the firmware contains the scatter gather bug
2899:
2900: --*/
2901: {
2902: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
2903: PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
2904: UCHAR HostAdapterId[3];
2905:
2906: GetHostAdapterBoardId(HwDeviceExtension,&HostAdapterId[0]);
2907:
2908: //
2909: // If it's an older board then scatter/gather is not supported.
2910: //
2911:
2912: if ( (HostAdapterId[BOARD_ID] == OLD_BOARD_ID1) ||
2913: (HostAdapterId[BOARD_ID] == OLD_BOARD_ID2) ) {
2914: return FALSE;
2915: }
2916:
2917: //
2918: // If 1540A/B then check for firmware bug.
2919: //
2920:
2921: if (HostAdapterId[BOARD_ID] == A154X_BOARD) {
2922: if (FirmwareBug(HwDeviceExtension)) {
2923: return FALSE;
2924: }
2925: }
2926:
2927: //
2928: // Now check hardware ID and firmware ID.
2929: //
2930:
2931: if (HostAdapterId[HARDWARE_ID] != A154X_BAD_HARDWARE_ID) {
2932: return TRUE;
2933: }
2934:
2935: if (HostAdapterId[FIRMWARE_ID] != A154X_BAD_FIRMWARE_ID) {
2936: return TRUE;
2937: }
2938:
2939: //
2940: // Host adapter has scatter/gather bug.
2941: // Clear interrupt on adapter.
2942: //
2943:
2944: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,IOP_INTERRUPT_RESET);
2945:
2946: return FALSE;
2947:
2948: } // end of ScatterGatherSupported ()
2949:
2950:
2951: BOOLEAN
2952: SpinForInterrupt(
2953: IN PHW_DEVICE_EXTENSION DeviceExtension,
2954: IN BOOLEAN TimeOutFlag
2955: )
2956:
2957: /*++
2958:
2959: Routine Description:
2960:
2961: Wait for interrupt.
2962:
2963: Arguments:
2964:
2965: DeviceExtension - Pointer to adapter extension
2966:
2967: Return Value:
2968:
2969: TRUE if interrupt occurred.
2970: FALSE if timed out waiting for interrupt.
2971:
2972: --*/
2973:
2974: {
2975: PBASE_REGISTER baseIoAddress = DeviceExtension->BaseIoAddress;
2976: ULONG i;
2977:
2978: //
2979: // Wait up to 1 millisecond for interrupt to occur.
2980: //
2981:
2982: for (i=0; i<1000; i++) {
2983:
2984: if (ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister) & IOP_COMMAND_COMPLETE) {
2985:
2986: //
2987: // Interrupt occurred. Break out of wait loop.
2988: //
2989:
2990: break;
2991:
2992: } else {
2993:
2994: //
2995: // Stall one microsecond.
2996: //
2997:
2998: ScsiPortStallExecution(1);
2999: }
3000: }
3001:
3002: if ( (i==1000) && (TimeOutFlag == TRUE)) {
3003:
3004: ScsiPortLogError(DeviceExtension,
3005: NULL,
3006: 0,
3007: DeviceExtension->HostTargetId,
3008: 0,
3009: SP_INTERNAL_ADAPTER_ERROR,
3010: 9 << 8);
3011:
3012: DebugPrint((1, "Aha154x:SpinForInterrupt: Timed out waiting for interrupt\n"));
3013:
3014: return FALSE;
3015:
3016: } else {
3017:
3018: //
3019: // Clear interrupt on adapter.
3020: //
3021:
3022: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
3023:
3024: return TRUE;
3025: }
3026:
3027: } // end SpinForInterrupt()
3028:
3029:
3030: BOOLEAN UnlockMailBoxes (
3031: IN PVOID HwDeviceExtension
3032: )
3033:
3034: /*++
3035:
3036: Routine Description:
3037:
3038: Unlock 1542B+ or 1542C mailboxes so that the driver
3039: can zero out mailboxes when it's initializing the adapter.
3040:
3041: The mailboxes are locked if:
3042: 1. >1Gb option is enabled (this option is available for 154xB+ and
3043: 154xC).
3044:
3045: 2. Dynamic scan lock option is enabled (154xC board only)
3046:
3047: The reason the mailboxes are locked by the adapter's firmware is
3048: because the BIOS is now reporting 255/63 translation instead of 64/32.
3049: As such, if a user inadvertently enabled the >1Gb option (enabling
3050: 255/63 translation) and still uses an old driver, hard disk data
3051: will be corrupted. Therefore, the firmware will not allow mailboxes
3052: to be initialized unless the user knows what he is doing and updates
3053: his driver so that his disk won't be trashed.
3054:
3055: Arguments:
3056:
3057: DeviceExtension - Pointer to adapter extension
3058:
3059: Return Value:
3060:
3061: TRUE if mailboxes are unlocked.
3062: FALSE if mailboxes are not unlocked.
3063: Note that if the adapter is just a 154xB board (without the >1Gb
3064: option), this routine will return FALSE.
3065:
3066: --*/
3067:
3068: {
3069: UCHAR locktype;
3070:
3071: //
3072: // Request information.
3073: //
3074:
3075: if (WriteCommandRegister(HwDeviceExtension, AC_GET_BIOS_INFO, TRUE) == FALSE) {
3076: return FALSE;
3077: }
3078:
3079:
3080: //
3081: // Retrieve first byte.
3082: //
3083:
3084: if (ReadCommandRegister(HwDeviceExtension,&locktype,FALSE) == FALSE) {
3085: return FALSE;
3086: }
3087:
3088: //
3089: // Check for extended bios translation enabled option on 1540C and
3090: // 1540B with 1GB support.
3091: //
3092:
3093: if (locktype != TRANSLATION_ENABLED) {
3094:
3095: //
3096: // Extended translation is disabled. Retrieve lock status.
3097: //
3098:
3099: if (ReadCommandRegister(HwDeviceExtension,&locktype,FALSE) == FALSE) {
3100: return FALSE;
3101: }
3102:
3103: if (locktype == DYNAMIC_SCAN_LOCK) {
3104: return(SendUnlockCommand(HwDeviceExtension,locktype));
3105: }
3106: return FALSE;
3107: }
3108:
3109: //
3110: // Extended BIOS translation (255/63) is enabled.
3111: //
3112:
3113:
3114: if (ReadCommandRegister(HwDeviceExtension,&locktype,FALSE) == FALSE) {
3115: return FALSE;
3116: }
3117:
3118: if ((locktype == TRANSLATION_LOCK) || (locktype == DYNAMIC_SCAN_LOCK)) {
3119: return(SendUnlockCommand(HwDeviceExtension,locktype));
3120: }
3121:
3122: return FALSE;
3123: } // end of UnlockMailBoxes ()
3124:
3125:
3126: BOOLEAN
3127: SendUnlockCommand(
3128: IN PVOID HwDeviceExtension,
3129: IN UCHAR locktype
3130: )
3131:
3132: /*++
3133:
3134: Routine Description:
3135:
3136: Send unlock command to 1542B+ or 1542C board so that the driver
3137: can zero out mailboxes when it's initializing the adapter.
3138:
3139:
3140: Arguments:
3141:
3142: DeviceExtension - Pointer to adapter extension
3143:
3144: Return Value:
3145:
3146: TRUE if commands are sent successfully.
3147: FALSE if not.
3148:
3149: --*/
3150:
3151: {
3152: PHW_DEVICE_EXTENSION deviceExtension = HwDeviceExtension;
3153: PBASE_REGISTER baseIoAddress = deviceExtension->BaseIoAddress;
3154:
3155: if (WriteCommandRegister(deviceExtension,
3156: AC_SET_MAILBOX_INTERFACE,TRUE) == FALSE) {
3157: return FALSE;
3158: }
3159:
3160: if (WriteDataRegister(deviceExtension,MAILBOX_UNLOCK) == FALSE) {
3161: return FALSE;
3162: }
3163:
3164: if (WriteDataRegister(deviceExtension,locktype) == FALSE) {
3165: return FALSE;
3166: }
3167:
3168: //
3169: // Clear interrupt on adapter.
3170: //
3171:
3172:
3173: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister, IOP_INTERRUPT_RESET);
3174:
3175: return TRUE;
3176: } // end of SendUnlockCommand ()
3177:
3178:
3179: BOOLEAN
3180: FinishHBACmd(
3181: IN PHW_DEVICE_EXTENSION HwDeviceExtension
3182: )
3183:
3184: /*++
3185:
3186: Routine Description:
3187:
3188: Wait for command complete interrupt, clear interrupt, chk cmd status.
3189: This is done because the driver has not registered our interrupt handler
3190: (which would normally do this work).
3191:
3192: Arguments:
3193:
3194: HwDeviceExtension - Pointer to adapter extension
3195:
3196: Return Value:
3197:
3198: TRUE if command completed successfully.
3199: FALSE if timed out waiting for adapter or invalid command.
3200:
3201: --*/
3202:
3203: {
3204: PBASE_REGISTER baseIoAddress = HwDeviceExtension->BaseIoAddress;
3205: ULONG i;
3206:
3207: for (i=0; i<500; i++) {
3208:
3209: if (!((ScsiPortReadPortUchar(&baseIoAddress->InterruptRegister) &
3210: (IOP_COMMAND_COMPLETE | IOP_ANY_INTERRUPT))==
3211: (IOP_COMMAND_COMPLETE | IOP_ANY_INTERRUPT))) {
3212:
3213: //
3214: // Stall 1 microsecond before
3215: // trying again.
3216: //
3217:
3218: ScsiPortStallExecution(1);
3219:
3220: } else {
3221:
3222: //
3223: // Adapter ready. Break out of loop.
3224: //
3225:
3226: break;
3227: }
3228: }
3229:
3230: if (i==500) {
3231:
3232: ScsiPortLogError(HwDeviceExtension,
3233: NULL,
3234: 0,
3235: HwDeviceExtension->HostTargetId,
3236: 0,
3237: SP_INTERNAL_ADAPTER_ERROR,
3238: 4 << 8);
3239:
3240: DebugPrint((1, "A154x:FinishHBACmd: Wait for CmdCmplt & AnyIntr failed\n"));
3241: return FALSE;
3242: }
3243:
3244: ScsiPortWritePortUchar(&baseIoAddress->StatusRegister,IOP_INTERRUPT_RESET);
3245:
3246: if (ScsiPortReadPortUchar(&baseIoAddress->StatusRegister) & (IOP_INVALID_COMMAND)) {
3247: return FALSE;
3248: }
3249:
3250: return TRUE;
3251: } // end FinishHBACmd()
3252:
3253:
3254: ULONG
3255: AhaParseArgumentString(
3256: IN PCHAR String,
3257: IN PCHAR KeyWord
3258: )
3259:
3260: /*++
3261:
3262: Routine Description:
3263:
3264: This routine will parse the string for a match on the keyword, then
3265: calculate the value for the keyword and return it to the caller.
3266:
3267: Arguments:
3268:
3269: String - The ASCII string to parse.
3270: KeyWord - The keyword for the value desired.
3271:
3272: Return Values:
3273:
3274: Zero if value not found
3275: Value converted from ASCII to binary.
3276:
3277: --*/
3278:
3279: {
3280: PCHAR cptr;
3281: PCHAR kptr;
3282: ULONG value;
3283: ULONG stringLength = 0;
3284: ULONG keyWordLength = 0;
3285: ULONG index;
3286:
3287: //
3288: // Calculate the string length and lower case all characters.
3289: //
3290: cptr = String;
3291: while (*cptr) {
3292:
3293: if (*cptr >= 'A' && *cptr <= 'Z') {
3294: *cptr = *cptr + ('a' - 'A');
3295: }
3296: cptr++;
3297: stringLength++;
3298: }
3299:
3300: //
3301: // Calculate the keyword length and lower case all characters.
3302: //
3303: cptr = KeyWord;
3304: while (*cptr) {
3305:
3306: if (*cptr >= 'A' && *cptr <= 'Z') {
3307: *cptr = *cptr + ('a' - 'A');
3308: }
3309: cptr++;
3310: keyWordLength++;
3311: }
3312:
3313: if (keyWordLength > stringLength) {
3314:
3315: //
3316: // Can't possibly have a match.
3317: //
3318: return 0;
3319: }
3320:
3321: //
3322: // Now setup and start the compare.
3323: //
3324: cptr = String;
3325:
3326: ContinueSearch:
3327: //
3328: // The input string may start with white space. Skip it.
3329: //
3330: while (*cptr == ' ' || *cptr == '\t') {
3331: cptr++;
3332: }
3333:
3334: if (*cptr == '\0') {
3335:
3336: //
3337: // end of string.
3338: //
3339: return 0;
3340: }
3341:
3342: kptr = KeyWord;
3343: while (*cptr++ == *kptr++) {
3344:
3345: if (*(cptr - 1) == '\0') {
3346:
3347: //
3348: // end of string
3349: //
3350: return 0;
3351: }
3352: }
3353:
3354: if (*(kptr - 1) == '\0') {
3355:
3356: //
3357: // May have a match backup and check for blank or equals.
3358: //
3359:
3360: cptr--;
3361: while (*cptr == ' ' || *cptr == '\t') {
3362: cptr++;
3363: }
3364:
3365: //
3366: // Found a match. Make sure there is an equals.
3367: //
3368: if (*cptr != '=') {
3369:
3370: //
3371: // Not a match so move to the next semicolon.
3372: //
3373: while (*cptr) {
3374: if (*cptr++ == ';') {
3375: goto ContinueSearch;
3376: }
3377: }
3378: return 0;
3379: }
3380:
3381: //
3382: // Skip the equals sign.
3383: //
3384: cptr++;
3385:
3386: //
3387: // Skip white space.
3388: //
3389: while ((*cptr == ' ') || (*cptr == '\t')) {
3390: cptr++;
3391: }
3392:
3393: if (*cptr == '\0') {
3394:
3395: //
3396: // Early end of string, return not found
3397: //
3398: return 0;
3399: }
3400:
3401: if (*cptr == ';') {
3402:
3403: //
3404: // This isn't it either.
3405: //
3406: cptr++;
3407: goto ContinueSearch;
3408: }
3409:
3410: value = 0;
3411: if ((*cptr == '0') && (*(cptr + 1) == 'x')) {
3412:
3413: //
3414: // Value is in Hex. Skip the "0x"
3415: //
3416: cptr += 2;
3417: for (index = 0; *(cptr + index); index++) {
3418:
3419: if (*(cptr + index) == ' ' ||
3420: *(cptr + index) == '\t' ||
3421: *(cptr + index) == ';') {
3422: break;
3423: }
3424:
3425: if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
3426: value = (16 * value) + (*(cptr + index) - '0');
3427: } else {
3428: if ((*(cptr + index) >= 'a') && (*(cptr + index) <= 'f')) {
3429: value = (16 * value) + (*(cptr + index) - 'a' + 10);
3430: } else {
3431:
3432: //
3433: // Syntax error, return not found.
3434: //
3435: return 0;
3436: }
3437: }
3438: }
3439: } else {
3440:
3441: //
3442: // Value is in Decimal.
3443: //
3444: for (index = 0; *(cptr + index); index++) {
3445:
3446: if (*(cptr + index) == ' ' ||
3447: *(cptr + index) == '\t' ||
3448: *(cptr + index) == ';') {
3449: break;
3450: }
3451:
3452: if ((*(cptr + index) >= '0') && (*(cptr + index) <= '9')) {
3453: value = (10 * value) + (*(cptr + index) - '0');
3454: } else {
3455:
3456: //
3457: // Syntax error return not found.
3458: //
3459: return 0;
3460: }
3461: }
3462: }
3463:
3464: return value;
3465: } else {
3466:
3467: //
3468: // Not a match check for ';' to continue search.
3469: //
3470: while (*cptr) {
3471: if (*cptr++ == ';') {
3472: goto ContinueSearch;
3473: }
3474: }
3475:
3476: return 0;
3477: }
3478: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.